@handled-ai/design-system 0.20.17 → 0.20.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/pill.d.ts +1 -1
- package/dist/components/rich-text-toolbar.d.ts +2 -1
- package/dist/components/rich-text-toolbar.js +56 -47
- package/dist/components/rich-text-toolbar.js.map +1 -1
- package/dist/components/tabs.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/__tests__/rich-text-toolbar.test.tsx +10 -5
- package/src/components/rich-text-toolbar.tsx +54 -47
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const badgeVariants: (props?: ({
|
|
6
|
-
variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" |
|
|
6
|
+
variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
7
7
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
8
8
|
declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
|
|
9
9
|
asChild?: boolean;
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" |
|
|
6
|
+
variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
7
7
|
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
|
|
@@ -12,7 +12,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
12
12
|
*/
|
|
13
13
|
type PillStatus = "success" | "warning" | "error" | "neutral" | "info";
|
|
14
14
|
declare const pillVariants: (props?: ({
|
|
15
|
-
variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "
|
|
15
|
+
variant?: "error" | "default" | "secondary" | "destructive" | "outline" | "ghost" | "neutral" | "info" | "success" | "warning" | null | undefined;
|
|
16
16
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
17
17
|
interface PillProps extends React.ComponentProps<"span">, VariantProps<typeof pillVariants> {
|
|
18
18
|
}
|
|
@@ -10,7 +10,8 @@ interface RichTextToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
10
10
|
fontOptions?: RichTextFontOption[];
|
|
11
11
|
selectedFontFamily?: string;
|
|
12
12
|
onFontFamilyChange?: (fontFamily: string) => void;
|
|
13
|
+
showDelete?: boolean;
|
|
13
14
|
}
|
|
14
|
-
declare function RichTextToolbar({ onAction, className, fontOptions, selectedFontFamily, onFontFamilyChange, ...rest }: RichTextToolbarProps): React.JSX.Element;
|
|
15
|
+
declare function RichTextToolbar({ onAction, className, fontOptions, selectedFontFamily, onFontFamilyChange, showDelete, ...rest }: RichTextToolbarProps): React.JSX.Element;
|
|
15
16
|
|
|
16
17
|
export { type RichTextAction, type RichTextFontOption, RichTextToolbar, type RichTextToolbarProps };
|
|
@@ -33,9 +33,15 @@ var __objRest = (source, exclude) => {
|
|
|
33
33
|
return target;
|
|
34
34
|
};
|
|
35
35
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
36
|
-
import * as React from "react";
|
|
37
36
|
import { Undo2, Redo2, Bold, Italic, Underline, AlignLeft, List, Trash2, ChevronDown } from "lucide-react";
|
|
38
37
|
import { cn } from "../lib/utils.js";
|
|
38
|
+
import {
|
|
39
|
+
DropdownMenu,
|
|
40
|
+
DropdownMenuContent,
|
|
41
|
+
DropdownMenuRadioGroup,
|
|
42
|
+
DropdownMenuRadioItem,
|
|
43
|
+
DropdownMenuTrigger
|
|
44
|
+
} from "./dropdown-menu.js";
|
|
39
45
|
function ToolbarButton({
|
|
40
46
|
action,
|
|
41
47
|
icon: Icon,
|
|
@@ -61,30 +67,20 @@ function RichTextToolbar(_a) {
|
|
|
61
67
|
className,
|
|
62
68
|
fontOptions,
|
|
63
69
|
selectedFontFamily,
|
|
64
|
-
onFontFamilyChange
|
|
70
|
+
onFontFamilyChange,
|
|
71
|
+
showDelete = true
|
|
65
72
|
} = _b, rest = __objRest(_b, [
|
|
66
73
|
"onAction",
|
|
67
74
|
"className",
|
|
68
75
|
"fontOptions",
|
|
69
76
|
"selectedFontFamily",
|
|
70
|
-
"onFontFamilyChange"
|
|
77
|
+
"onFontFamilyChange",
|
|
78
|
+
"showDelete"
|
|
71
79
|
]);
|
|
72
|
-
var _a2, _b2;
|
|
73
|
-
const [fontMenuOpen, setFontMenuOpen] = React.useState(false);
|
|
74
|
-
const fontMenuRef = React.useRef(null);
|
|
80
|
+
var _a2, _b2, _c;
|
|
75
81
|
const selectedFontOption = (_a2 = fontOptions == null ? void 0 : fontOptions.find((option) => option.value === selectedFontFamily)) != null ? _a2 : fontOptions == null ? void 0 : fontOptions[0];
|
|
76
82
|
const fontLabel = (_b2 = selectedFontOption == null ? void 0 : selectedFontOption.label) != null ? _b2 : "Sans Serif";
|
|
77
83
|
const hasFontMenu = Boolean((fontOptions == null ? void 0 : fontOptions.length) && onFontFamilyChange);
|
|
78
|
-
React.useEffect(() => {
|
|
79
|
-
if (!fontMenuOpen) return;
|
|
80
|
-
function handleDocumentMouseDown(event) {
|
|
81
|
-
var _a3;
|
|
82
|
-
if ((_a3 = fontMenuRef.current) == null ? void 0 : _a3.contains(event.target)) return;
|
|
83
|
-
setFontMenuOpen(false);
|
|
84
|
-
}
|
|
85
|
-
document.addEventListener("mousedown", handleDocumentMouseDown);
|
|
86
|
-
return () => document.removeEventListener("mousedown", handleDocumentMouseDown);
|
|
87
|
-
}, [fontMenuOpen]);
|
|
88
84
|
return /* @__PURE__ */ jsxs(
|
|
89
85
|
"div",
|
|
90
86
|
__spreadProps(__spreadValues({
|
|
@@ -98,51 +94,64 @@ function RichTextToolbar(_a) {
|
|
|
98
94
|
/* @__PURE__ */ jsx(ToolbarButton, { action: "undo", icon: Undo2, label: "Undo", onAction }),
|
|
99
95
|
/* @__PURE__ */ jsx(ToolbarButton, { action: "redo", icon: Redo2, label: "Redo", onAction }),
|
|
100
96
|
/* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-border mx-1", "aria-hidden": "true" }),
|
|
101
|
-
/* @__PURE__ */ jsxs(
|
|
102
|
-
/* @__PURE__ */ jsxs(
|
|
97
|
+
hasFontMenu ? /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
98
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
103
99
|
"button",
|
|
104
100
|
{
|
|
105
101
|
type: "button",
|
|
106
102
|
"data-slot": "rich-text-toolbar-button",
|
|
107
|
-
onClick: () =>
|
|
108
|
-
onAction == null ? void 0 : onAction("font");
|
|
109
|
-
if (hasFontMenu) setFontMenuOpen((open) => !open);
|
|
110
|
-
},
|
|
103
|
+
onClick: () => onAction == null ? void 0 : onAction("font"),
|
|
111
104
|
"aria-label": "Font family",
|
|
112
105
|
"aria-haspopup": "menu",
|
|
113
|
-
"aria-expanded": hasFontMenu ? fontMenuOpen : void 0,
|
|
114
106
|
className: "text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1",
|
|
115
107
|
children: [
|
|
116
108
|
fontLabel,
|
|
117
109
|
/* @__PURE__ */ jsx(ChevronDown, { size: 10 })
|
|
118
110
|
]
|
|
119
111
|
}
|
|
120
|
-
),
|
|
121
|
-
|
|
122
|
-
|
|
112
|
+
) }),
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
DropdownMenuContent,
|
|
123
115
|
{
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
className: "
|
|
127
|
-
|
|
128
|
-
|
|
116
|
+
side: "top",
|
|
117
|
+
align: "start",
|
|
118
|
+
className: "min-w-32 pointer-events-auto",
|
|
119
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
120
|
+
children: /* @__PURE__ */ jsx(
|
|
121
|
+
DropdownMenuRadioGroup,
|
|
129
122
|
{
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
123
|
+
"aria-label": "Font family",
|
|
124
|
+
value: (_c = selectedFontOption == null ? void 0 : selectedFontOption.value) != null ? _c : "",
|
|
125
|
+
onValueChange: (value) => onFontFamilyChange == null ? void 0 : onFontFamilyChange(value),
|
|
126
|
+
children: fontOptions == null ? void 0 : fontOptions.map((option) => /* @__PURE__ */ jsx(
|
|
127
|
+
DropdownMenuRadioItem,
|
|
128
|
+
{
|
|
129
|
+
value: option.value,
|
|
130
|
+
className: "text-xs",
|
|
131
|
+
style: { fontFamily: option.value },
|
|
132
|
+
children: option.label
|
|
133
|
+
},
|
|
134
|
+
option.value
|
|
135
|
+
))
|
|
136
|
+
}
|
|
137
|
+
)
|
|
143
138
|
}
|
|
144
|
-
)
|
|
145
|
-
] })
|
|
139
|
+
)
|
|
140
|
+
] }) : /* @__PURE__ */ jsxs(
|
|
141
|
+
"button",
|
|
142
|
+
{
|
|
143
|
+
type: "button",
|
|
144
|
+
"data-slot": "rich-text-toolbar-button",
|
|
145
|
+
onClick: () => onAction == null ? void 0 : onAction("font"),
|
|
146
|
+
"aria-label": "Font family",
|
|
147
|
+
"aria-haspopup": "menu",
|
|
148
|
+
className: "text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1",
|
|
149
|
+
children: [
|
|
150
|
+
fontLabel,
|
|
151
|
+
/* @__PURE__ */ jsx(ChevronDown, { size: 10 })
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
),
|
|
146
155
|
/* @__PURE__ */ jsx("div", { className: "w-px h-4 bg-border mx-1", "aria-hidden": "true" }),
|
|
147
156
|
/* @__PURE__ */ jsx(ToolbarButton, { action: "bold", icon: Bold, label: "Bold", onAction }),
|
|
148
157
|
/* @__PURE__ */ jsx(ToolbarButton, { action: "italic", icon: Italic, label: "Italic", onAction }),
|
|
@@ -151,7 +160,7 @@ function RichTextToolbar(_a) {
|
|
|
151
160
|
/* @__PURE__ */ jsx(ToolbarButton, { action: "align", icon: AlignLeft, label: "Align left", onAction }),
|
|
152
161
|
/* @__PURE__ */ jsx(ToolbarButton, { action: "list", icon: List, label: "List", onAction })
|
|
153
162
|
] }),
|
|
154
|
-
/* @__PURE__ */ jsx(ToolbarButton, { action: "delete", icon: Trash2, label: "Delete", extraClassName: "hover:text-destructive", onAction })
|
|
163
|
+
showDelete ? /* @__PURE__ */ jsx(ToolbarButton, { action: "delete", icon: Trash2, label: "Delete", extraClassName: "hover:text-destructive", onAction }) : null
|
|
155
164
|
]
|
|
156
165
|
})
|
|
157
166
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/rich-text-toolbar.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport type { LucideIcon } from \"lucide-react\"\nimport { Undo2, Redo2, Bold, Italic, Underline, AlignLeft, List, Trash2, ChevronDown } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\n\ntype RichTextAction =\n | \"undo\" | \"redo\"\n | \"font\"\n | \"bold\" | \"italic\" | \"underline\"\n | \"align\" | \"list\"\n | \"delete\"\n\ninterface RichTextFontOption {\n label: string\n value: string\n}\n\ninterface RichTextToolbarProps extends React.HTMLAttributes<HTMLDivElement> {\n onAction?: (action: RichTextAction) => void\n fontOptions?: RichTextFontOption[]\n selectedFontFamily?: string\n onFontFamilyChange?: (fontFamily: string) => void\n}\n\nfunction ToolbarButton({\n action,\n icon: Icon,\n label,\n extraClassName,\n onAction,\n}: {\n action: RichTextAction\n icon: LucideIcon\n label: string\n extraClassName?: string\n onAction?: (action: RichTextAction) => void\n}) {\n return (\n <button\n type=\"button\"\n data-slot=\"rich-text-toolbar-button\"\n onClick={() => onAction?.(action)}\n aria-label={label}\n className={cn(\"p-1.5 rounded hover:bg-muted/50 cursor-pointer text-muted-foreground\", extraClassName)}\n >\n <Icon size={14} />\n </button>\n )\n}\n\nfunction RichTextToolbar({\n onAction,\n className,\n fontOptions,\n selectedFontFamily,\n onFontFamilyChange,\n ...rest\n}: RichTextToolbarProps) {\n const
|
|
1
|
+
{"version":3,"sources":["../../src/components/rich-text-toolbar.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport type { LucideIcon } from \"lucide-react\"\nimport { Undo2, Redo2, Bold, Italic, Underline, AlignLeft, List, Trash2, ChevronDown } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuTrigger,\n} from \"./dropdown-menu\"\n\ntype RichTextAction =\n | \"undo\" | \"redo\"\n | \"font\"\n | \"bold\" | \"italic\" | \"underline\"\n | \"align\" | \"list\"\n | \"delete\"\n\ninterface RichTextFontOption {\n label: string\n value: string\n}\n\ninterface RichTextToolbarProps extends React.HTMLAttributes<HTMLDivElement> {\n onAction?: (action: RichTextAction) => void\n fontOptions?: RichTextFontOption[]\n selectedFontFamily?: string\n onFontFamilyChange?: (fontFamily: string) => void\n showDelete?: boolean\n}\n\nfunction ToolbarButton({\n action,\n icon: Icon,\n label,\n extraClassName,\n onAction,\n}: {\n action: RichTextAction\n icon: LucideIcon\n label: string\n extraClassName?: string\n onAction?: (action: RichTextAction) => void\n}) {\n return (\n <button\n type=\"button\"\n data-slot=\"rich-text-toolbar-button\"\n onClick={() => onAction?.(action)}\n aria-label={label}\n className={cn(\"p-1.5 rounded hover:bg-muted/50 cursor-pointer text-muted-foreground\", extraClassName)}\n >\n <Icon size={14} />\n </button>\n )\n}\n\nfunction RichTextToolbar({\n onAction,\n className,\n fontOptions,\n selectedFontFamily,\n onFontFamilyChange,\n showDelete = true,\n ...rest\n}: RichTextToolbarProps) {\n const selectedFontOption = fontOptions?.find((option) => option.value === selectedFontFamily) ?? fontOptions?.[0]\n const fontLabel = selectedFontOption?.label ?? \"Sans Serif\"\n const hasFontMenu = Boolean(fontOptions?.length && onFontFamilyChange)\n\n return (\n <div\n data-slot=\"rich-text-toolbar\"\n role=\"toolbar\"\n aria-label=\"Rich text formatting\"\n className={cn(\"px-3 py-1.5 flex items-center justify-between\", className)}\n {...rest}\n >\n <div className=\"flex items-center gap-0.5\">\n <ToolbarButton action=\"undo\" icon={Undo2} label=\"Undo\" onAction={onAction} />\n <ToolbarButton action=\"redo\" icon={Redo2} label=\"Redo\" onAction={onAction} />\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n {hasFontMenu ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n data-slot=\"rich-text-toolbar-button\"\n onClick={() => onAction?.(\"font\")}\n aria-label=\"Font family\"\n aria-haspopup=\"menu\"\n className=\"text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1\"\n >\n {fontLabel}\n <ChevronDown size={10} />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side=\"top\"\n align=\"start\"\n className=\"min-w-32 pointer-events-auto\"\n onMouseDown={(event) => event.preventDefault()}\n >\n <DropdownMenuRadioGroup\n aria-label=\"Font family\"\n value={selectedFontOption?.value ?? \"\"}\n onValueChange={(value) => onFontFamilyChange?.(value)}\n >\n {fontOptions?.map((option) => (\n <DropdownMenuRadioItem\n key={option.value}\n value={option.value}\n className=\"text-xs\"\n style={{ fontFamily: option.value }}\n >\n {option.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n ) : (\n <button\n type=\"button\"\n data-slot=\"rich-text-toolbar-button\"\n onClick={() => onAction?.(\"font\")}\n aria-label=\"Font family\"\n aria-haspopup=\"menu\"\n className=\"text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1\"\n >\n {fontLabel}\n <ChevronDown size={10} />\n </button>\n )}\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n <ToolbarButton action=\"bold\" icon={Bold} label=\"Bold\" onAction={onAction} />\n <ToolbarButton action=\"italic\" icon={Italic} label=\"Italic\" onAction={onAction} />\n <ToolbarButton action=\"underline\" icon={Underline} label=\"Underline\" onAction={onAction} />\n\n <div className=\"w-px h-4 bg-border mx-1\" aria-hidden=\"true\" />\n\n <ToolbarButton action=\"align\" icon={AlignLeft} label=\"Align left\" onAction={onAction} />\n <ToolbarButton action=\"list\" icon={List} label=\"List\" onAction={onAction} />\n </div>\n\n {showDelete ? (\n <ToolbarButton action=\"delete\" icon={Trash2} label=\"Delete\" extraClassName=\"hover:text-destructive\" onAction={onAction} />\n ) : null}\n </div>\n )\n}\n\nexport { RichTextToolbar, type RichTextToolbarProps, type RichTextAction, type RichTextFontOption }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDM,cAmCQ,YAnCR;AApDN,SAAS,OAAO,OAAO,MAAM,QAAQ,WAAW,WAAW,MAAM,QAAQ,mBAAmB;AAE5F,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAsBP,SAAS,cAAc;AAAA,EACrB;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,aAAU;AAAA,MACV,SAAS,MAAM,qCAAW;AAAA,MAC1B,cAAY;AAAA,MACZ,WAAW,GAAG,wEAAwE,cAAc;AAAA,MAEpG,8BAAC,QAAK,MAAM,IAAI;AAAA;AAAA,EAClB;AAEJ;AAEA,SAAS,gBAAgB,IAQA;AARA,eACvB;AAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa;AAAA,EAnEf,IA6DyB,IAOpB,iBAPoB,IAOpB;AAAA,IANH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAnEF,MAAAA,KAAAC,KAAA;AAsEE,QAAM,sBAAqBD,MAAA,2CAAa,KAAK,CAAC,WAAW,OAAO,UAAU,wBAA/C,OAAAA,MAAsE,2CAAc;AAC/G,QAAM,aAAYC,MAAA,yDAAoB,UAApB,OAAAA,MAA6B;AAC/C,QAAM,cAAc,SAAQ,2CAAa,WAAU,kBAAkB;AAErE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,MAAK;AAAA,MACL,cAAW;AAAA,MACX,WAAW,GAAG,iDAAiD,SAAS;AAAA,OACpE,OALL;AAAA,MAOC;AAAA,6BAAC,SAAI,WAAU,6BACb;AAAA,8BAAC,iBAAc,QAAO,QAAO,MAAM,OAAO,OAAM,QAAO,UAAoB;AAAA,UAC3E,oBAAC,iBAAc,QAAO,QAAO,MAAM,OAAO,OAAM,QAAO,UAAoB;AAAA,UAE3E,oBAAC,SAAI,WAAU,2BAA0B,eAAY,QAAO;AAAA,UAE3D,cACC,qBAAC,gBACC;AAAA,gCAAC,uBAAoB,SAAO,MAC1B;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,aAAU;AAAA,gBACV,SAAS,MAAM,qCAAW;AAAA,gBAC1B,cAAW;AAAA,gBACX,iBAAc;AAAA,gBACd,WAAU;AAAA,gBAET;AAAA;AAAA,kBACD,oBAAC,eAAY,MAAM,IAAI;AAAA;AAAA;AAAA,YACzB,GACF;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,WAAU;AAAA,gBACV,aAAa,CAAC,UAAU,MAAM,eAAe;AAAA,gBAE7C;AAAA,kBAAC;AAAA;AAAA,oBACC,cAAW;AAAA,oBACX,QAAO,8DAAoB,UAApB,YAA6B;AAAA,oBACpC,eAAe,CAAC,UAAU,yDAAqB;AAAA,oBAE9C,qDAAa,IAAI,CAAC,WACjB;AAAA,sBAAC;AAAA;AAAA,wBAEC,OAAO,OAAO;AAAA,wBACd,WAAU;AAAA,wBACV,OAAO,EAAE,YAAY,OAAO,MAAM;AAAA,wBAEjC,iBAAO;AAAA;AAAA,sBALH,OAAO;AAAA,oBAMd;AAAA;AAAA,gBAEJ;AAAA;AAAA,YACF;AAAA,aACF,IAEA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,aAAU;AAAA,cACV,SAAS,MAAM,qCAAW;AAAA,cAC1B,cAAW;AAAA,cACX,iBAAc;AAAA,cACd,WAAU;AAAA,cAET;AAAA;AAAA,gBACD,oBAAC,eAAY,MAAM,IAAI;AAAA;AAAA;AAAA,UACzB;AAAA,UAGF,oBAAC,SAAI,WAAU,2BAA0B,eAAY,QAAO;AAAA,UAE5D,oBAAC,iBAAc,QAAO,QAAO,MAAM,MAAM,OAAM,QAAO,UAAoB;AAAA,UAC1E,oBAAC,iBAAc,QAAO,UAAS,MAAM,QAAQ,OAAM,UAAS,UAAoB;AAAA,UAChF,oBAAC,iBAAc,QAAO,aAAY,MAAM,WAAW,OAAM,aAAY,UAAoB;AAAA,UAEzF,oBAAC,SAAI,WAAU,2BAA0B,eAAY,QAAO;AAAA,UAE5D,oBAAC,iBAAc,QAAO,SAAQ,MAAM,WAAW,OAAM,cAAa,UAAoB;AAAA,UACtF,oBAAC,iBAAc,QAAO,QAAO,MAAM,MAAM,OAAM,QAAO,UAAoB;AAAA,WAC5E;AAAA,QAEC,aACC,oBAAC,iBAAc,QAAO,UAAS,MAAM,QAAQ,OAAM,UAAS,gBAAe,0BAAyB,UAAoB,IACtH;AAAA;AAAA;AAAA,EACN;AAEJ;","names":["_a","_b"]}
|
|
@@ -5,7 +5,7 @@ import { Tabs as Tabs$1 } from 'radix-ui';
|
|
|
5
5
|
|
|
6
6
|
declare function Tabs({ className, orientation, ...props }: React.ComponentProps<typeof Tabs$1.Root>): React.JSX.Element;
|
|
7
7
|
declare const tabsListVariants: (props?: ({
|
|
8
|
-
variant?: "
|
|
8
|
+
variant?: "line" | "default" | null | undefined;
|
|
9
9
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
10
|
declare function TabsList({ className, variant, ...props }: React.ComponentProps<typeof Tabs$1.List> & VariantProps<typeof tabsListVariants>): React.JSX.Element;
|
|
11
11
|
declare function TabsTrigger({ className, ...props }: React.ComponentProps<typeof Tabs$1.Trigger>): React.JSX.Element;
|
package/package.json
CHANGED
|
@@ -54,7 +54,7 @@ describe("RichTextToolbar", () => {
|
|
|
54
54
|
expect(handler).toHaveBeenCalledWith("font");
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
it("opens a font menu and emits the selected font family when options are provided", () => {
|
|
57
|
+
it("opens a font menu and emits the selected font family when options are provided", async () => {
|
|
58
58
|
const handler = vi.fn();
|
|
59
59
|
render(
|
|
60
60
|
<RichTextToolbar
|
|
@@ -67,18 +67,23 @@ describe("RichTextToolbar", () => {
|
|
|
67
67
|
/>,
|
|
68
68
|
);
|
|
69
69
|
|
|
70
|
-
fireEvent.
|
|
71
|
-
expect(screen.
|
|
70
|
+
fireEvent.pointerDown(screen.getByLabelText("Font family"), { button: 0, ctrlKey: false });
|
|
71
|
+
expect(await screen.findByRole("menu")).toBeDefined();
|
|
72
72
|
fireEvent.click(screen.getByRole("menuitemradio", { name: "Serif" }));
|
|
73
73
|
|
|
74
74
|
expect(handler).toHaveBeenCalledWith("Georgia, serif");
|
|
75
|
-
expect(screen.queryByRole("menu"
|
|
75
|
+
expect(screen.queryByRole("menu")).toBeNull();
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it("keeps the font button backward compatible when no menu options are supplied", () => {
|
|
79
79
|
render(<RichTextToolbar />);
|
|
80
80
|
fireEvent.click(screen.getByLabelText("Font family"));
|
|
81
|
-
expect(screen.queryByRole("menu"
|
|
81
|
+
expect(screen.queryByRole("menu")).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("can hide the delete action", () => {
|
|
85
|
+
render(<RichTextToolbar showDelete={false} />);
|
|
86
|
+
expect(screen.queryByLabelText("Delete")).toBeNull();
|
|
82
87
|
});
|
|
83
88
|
|
|
84
89
|
it("fires onAction with 'delete' when Delete button clicked", () => {
|
|
@@ -5,6 +5,13 @@ import type { LucideIcon } from "lucide-react"
|
|
|
5
5
|
import { Undo2, Redo2, Bold, Italic, Underline, AlignLeft, List, Trash2, ChevronDown } from "lucide-react"
|
|
6
6
|
|
|
7
7
|
import { cn } from "../lib/utils"
|
|
8
|
+
import {
|
|
9
|
+
DropdownMenu,
|
|
10
|
+
DropdownMenuContent,
|
|
11
|
+
DropdownMenuRadioGroup,
|
|
12
|
+
DropdownMenuRadioItem,
|
|
13
|
+
DropdownMenuTrigger,
|
|
14
|
+
} from "./dropdown-menu"
|
|
8
15
|
|
|
9
16
|
type RichTextAction =
|
|
10
17
|
| "undo" | "redo"
|
|
@@ -23,6 +30,7 @@ interface RichTextToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
23
30
|
fontOptions?: RichTextFontOption[]
|
|
24
31
|
selectedFontFamily?: string
|
|
25
32
|
onFontFamilyChange?: (fontFamily: string) => void
|
|
33
|
+
showDelete?: boolean
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
function ToolbarButton({
|
|
@@ -57,26 +65,13 @@ function RichTextToolbar({
|
|
|
57
65
|
fontOptions,
|
|
58
66
|
selectedFontFamily,
|
|
59
67
|
onFontFamilyChange,
|
|
68
|
+
showDelete = true,
|
|
60
69
|
...rest
|
|
61
70
|
}: RichTextToolbarProps) {
|
|
62
|
-
const [fontMenuOpen, setFontMenuOpen] = React.useState(false)
|
|
63
|
-
const fontMenuRef = React.useRef<HTMLDivElement | null>(null)
|
|
64
71
|
const selectedFontOption = fontOptions?.find((option) => option.value === selectedFontFamily) ?? fontOptions?.[0]
|
|
65
72
|
const fontLabel = selectedFontOption?.label ?? "Sans Serif"
|
|
66
73
|
const hasFontMenu = Boolean(fontOptions?.length && onFontFamilyChange)
|
|
67
74
|
|
|
68
|
-
React.useEffect(() => {
|
|
69
|
-
if (!fontMenuOpen) return
|
|
70
|
-
|
|
71
|
-
function handleDocumentMouseDown(event: MouseEvent) {
|
|
72
|
-
if (fontMenuRef.current?.contains(event.target as Node)) return
|
|
73
|
-
setFontMenuOpen(false)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
document.addEventListener("mousedown", handleDocumentMouseDown)
|
|
77
|
-
return () => document.removeEventListener("mousedown", handleDocumentMouseDown)
|
|
78
|
-
}, [fontMenuOpen])
|
|
79
|
-
|
|
80
75
|
return (
|
|
81
76
|
<div
|
|
82
77
|
data-slot="rich-text-toolbar"
|
|
@@ -91,48 +86,58 @@ function RichTextToolbar({
|
|
|
91
86
|
|
|
92
87
|
<div className="w-px h-4 bg-border mx-1" aria-hidden="true" />
|
|
93
88
|
|
|
94
|
-
|
|
89
|
+
{hasFontMenu ? (
|
|
90
|
+
<DropdownMenu>
|
|
91
|
+
<DropdownMenuTrigger asChild>
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
data-slot="rich-text-toolbar-button"
|
|
95
|
+
onClick={() => onAction?.("font")}
|
|
96
|
+
aria-label="Font family"
|
|
97
|
+
aria-haspopup="menu"
|
|
98
|
+
className="text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1"
|
|
99
|
+
>
|
|
100
|
+
{fontLabel}
|
|
101
|
+
<ChevronDown size={10} />
|
|
102
|
+
</button>
|
|
103
|
+
</DropdownMenuTrigger>
|
|
104
|
+
<DropdownMenuContent
|
|
105
|
+
side="top"
|
|
106
|
+
align="start"
|
|
107
|
+
className="min-w-32 pointer-events-auto"
|
|
108
|
+
onMouseDown={(event) => event.preventDefault()}
|
|
109
|
+
>
|
|
110
|
+
<DropdownMenuRadioGroup
|
|
111
|
+
aria-label="Font family"
|
|
112
|
+
value={selectedFontOption?.value ?? ""}
|
|
113
|
+
onValueChange={(value) => onFontFamilyChange?.(value)}
|
|
114
|
+
>
|
|
115
|
+
{fontOptions?.map((option) => (
|
|
116
|
+
<DropdownMenuRadioItem
|
|
117
|
+
key={option.value}
|
|
118
|
+
value={option.value}
|
|
119
|
+
className="text-xs"
|
|
120
|
+
style={{ fontFamily: option.value }}
|
|
121
|
+
>
|
|
122
|
+
{option.label}
|
|
123
|
+
</DropdownMenuRadioItem>
|
|
124
|
+
))}
|
|
125
|
+
</DropdownMenuRadioGroup>
|
|
126
|
+
</DropdownMenuContent>
|
|
127
|
+
</DropdownMenu>
|
|
128
|
+
) : (
|
|
95
129
|
<button
|
|
96
130
|
type="button"
|
|
97
131
|
data-slot="rich-text-toolbar-button"
|
|
98
|
-
onClick={() =>
|
|
99
|
-
onAction?.("font")
|
|
100
|
-
if (hasFontMenu) setFontMenuOpen((open) => !open)
|
|
101
|
-
}}
|
|
132
|
+
onClick={() => onAction?.("font")}
|
|
102
133
|
aria-label="Font family"
|
|
103
134
|
aria-haspopup="menu"
|
|
104
|
-
aria-expanded={hasFontMenu ? fontMenuOpen : undefined}
|
|
105
135
|
className="text-[11px] text-muted-foreground px-1.5 py-0.5 rounded hover:bg-muted/50 cursor-pointer flex items-center gap-1"
|
|
106
136
|
>
|
|
107
137
|
{fontLabel}
|
|
108
138
|
<ChevronDown size={10} />
|
|
109
139
|
</button>
|
|
110
|
-
|
|
111
|
-
{hasFontMenu && fontMenuOpen ? (
|
|
112
|
-
<div
|
|
113
|
-
role="menu"
|
|
114
|
-
aria-label="Font family"
|
|
115
|
-
className="absolute left-0 bottom-full z-50 mb-1 min-w-32 overflow-hidden rounded-md border border-border bg-background py-1 shadow-md"
|
|
116
|
-
>
|
|
117
|
-
{fontOptions!.map((option) => (
|
|
118
|
-
<button
|
|
119
|
-
key={option.value}
|
|
120
|
-
type="button"
|
|
121
|
-
role="menuitemradio"
|
|
122
|
-
aria-checked={option.value === selectedFontFamily}
|
|
123
|
-
className="block w-full px-2.5 py-1.5 text-left text-xs text-foreground hover:bg-muted/60"
|
|
124
|
-
style={{ fontFamily: option.value }}
|
|
125
|
-
onClick={() => {
|
|
126
|
-
onFontFamilyChange?.(option.value)
|
|
127
|
-
setFontMenuOpen(false)
|
|
128
|
-
}}
|
|
129
|
-
>
|
|
130
|
-
{option.label}
|
|
131
|
-
</button>
|
|
132
|
-
))}
|
|
133
|
-
</div>
|
|
134
|
-
) : null}
|
|
135
|
-
</div>
|
|
140
|
+
)}
|
|
136
141
|
|
|
137
142
|
<div className="w-px h-4 bg-border mx-1" aria-hidden="true" />
|
|
138
143
|
|
|
@@ -146,7 +151,9 @@ function RichTextToolbar({
|
|
|
146
151
|
<ToolbarButton action="list" icon={List} label="List" onAction={onAction} />
|
|
147
152
|
</div>
|
|
148
153
|
|
|
149
|
-
|
|
154
|
+
{showDelete ? (
|
|
155
|
+
<ToolbarButton action="delete" icon={Trash2} label="Delete" extraClassName="hover:text-destructive" onAction={onAction} />
|
|
156
|
+
) : null}
|
|
150
157
|
</div>
|
|
151
158
|
)
|
|
152
159
|
}
|