diff --git a/packages/lexical/src/action-declarations.tsx b/packages/lexical/src/action-declarations.tsx index a135c20..32ff40e 100644 --- a/packages/lexical/src/action-declarations.tsx +++ b/packages/lexical/src/action-declarations.tsx @@ -58,6 +58,7 @@ export type LexicalActionPlacement = export interface LexicalActionProps { children?: (props: LexicalControlRenderProps) => ReactNode + className?: string in?: LexicalActionPlacement } @@ -86,6 +87,7 @@ export type LexicalActionsProps = export interface CompiledLexicalAction { action: AnyLexicalActionDefinition + className?: string key: string kind: "action" render?: AnyLexicalActionProps["children"] @@ -229,6 +231,11 @@ function getPresetActions(preset: LexicalActionsPreset): ReactNode { <> + + + + + - - - - - ) @@ -277,6 +279,9 @@ function getPresetActions(preset: LexicalActionsPreset): ReactNode { + + + - - - - + ) } @@ -418,6 +420,7 @@ function compileItems( for (const area of new Set(areas)) { output[area].push({ action, + className: props.className, key, kind: "action", render: props.children, diff --git a/packages/lexical/src/actions-view.test.tsx b/packages/lexical/src/actions-view.test.tsx index 918106a..e18b42e 100644 --- a/packages/lexical/src/actions-view.test.tsx +++ b/packages/lexical/src/actions-view.test.tsx @@ -1,6 +1,6 @@ // @vitest-environment jsdom -import { cleanup, render, screen } from "@testing-library/react" +import { cleanup, fireEvent, render, screen } from "@testing-library/react" import { afterEach, describe, expect, it } from "vitest" import { @@ -54,6 +54,46 @@ describe("declarative Lexical actions", () => { expect(screen.getByRole("button", { name: "格式" })).not.toBeNull() }) + it("forwards an action className to its default control", () => { + render( + undefined}> + + + + + + + ) + + expect( + screen + .getByRole("button", { name: "Bold" }) + .classList.contains("text-destructive") + ).toBe(true) + }) + + it("forwards an action className to its default menu item", async () => { + render( + undefined}> + + + + + + + + + ) + + fireEvent.click(screen.getByRole("button", { name: "格式" })) + + expect( + ( + await screen.findByRole("menuitem", { name: "Bold" }) + ).classList.contains("text-destructive") + ).toBe(true) + }) + it("does not render optional regions without matching actions", () => { render( undefined}> diff --git a/packages/lexical/src/actions-view.tsx b/packages/lexical/src/actions-view.tsx index 59d5f70..39a5979 100644 --- a/packages/lexical/src/actions-view.tsx +++ b/packages/lexical/src/actions-view.tsx @@ -29,6 +29,7 @@ export function LexicalActionTree({ ) : item.type === "menu" ? ( @@ -102,13 +103,14 @@ function MenuItems({ items }: { items: readonly CompiledLexicalActionItem[] }) { } function ActionMenuItem({ item }: { item: CompiledLexicalAction }) { - const { action, render } = item + const { action, className: actionClassName, render } = item const Icon = action.icon if (render || action.control) { return ( @@ -118,10 +120,11 @@ function ActionMenuItem({ item }: { item: CompiledLexicalAction }) { return ( ( + className={actionClassName} + render={({ active, className, disabled, label, onClick }) => ( event.preventDefault()} onClick={onClick} > diff --git a/packages/lexical/src/control.test.tsx b/packages/lexical/src/control.test.tsx index c12efe5..c8f3942 100644 --- a/packages/lexical/src/control.test.tsx +++ b/packages/lexical/src/control.test.tsx @@ -19,8 +19,8 @@ describe("Lexical action rendering", () => { undefined}> - {({ active, label, onClick }) => ( - )} @@ -34,4 +34,28 @@ describe("Lexical action rendering", () => { const button = screen.getByRole("button", { name: "Bold:off" }) expect(() => fireEvent.click(button)).not.toThrow() }) + + it("passes an action className to custom renderers", () => { + render( + undefined}> + + + {({ className, label, onClick }) => ( + + )} + + + + + + ) + + expect( + screen + .getByRole("button", { name: "Bold" }) + .classList.contains("custom-bold") + ).toBe(true) + }) }) diff --git a/packages/lexical/src/control.tsx b/packages/lexical/src/control.tsx index eb0d493..d02d830 100644 --- a/packages/lexical/src/control.tsx +++ b/packages/lexical/src/control.tsx @@ -4,13 +4,13 @@ import { TooltipContent, TooltipTrigger, } from "@workspace/ui/components/tooltip" - import { useLexicalActionContext } from "./context" import { useLexicalMessage } from "./i18n" import type { LexicalControlProps } from "./types" export function LexicalControl({ action, + className, label, presentation = "control", render, @@ -25,6 +25,7 @@ export function LexicalControl({ const onClick = () => execute() const renderProps = { active, + className, disabled, execute, label: resolvedLabel, @@ -54,6 +55,7 @@ export function LexicalControl({