@bizapps/design-system-testing 1.7.2 → 1.8.1
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/editor.cjs +87 -82
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.d.cts +49 -31
- package/dist/editor.d.ts +49 -31
- package/dist/editor.js +87 -82
- package/dist/editor.js.map +1 -1
- package/package.json +1 -1
package/dist/editor.d.cts
CHANGED
|
@@ -164,6 +164,36 @@ interface InsertImageDialogProps {
|
|
|
164
164
|
*/
|
|
165
165
|
declare function InsertImageDialog({ open, onOpenChange, labels, url, onUrlChange, alt, onAltChange, file, onFileChange, uploading, onApply, onCancel, removable, onRemove, maxSizeBytes, accept, }: InsertImageDialogProps): react.JSX.Element;
|
|
166
166
|
|
|
167
|
+
interface LinkBubbleMenuLabels {
|
|
168
|
+
open: string;
|
|
169
|
+
edit: string;
|
|
170
|
+
remove: string;
|
|
171
|
+
}
|
|
172
|
+
interface LinkBubbleMenuProps {
|
|
173
|
+
editor: Editor | null;
|
|
174
|
+
labels: LinkBubbleMenuLabels;
|
|
175
|
+
/** Opens the consumer's link dialog, pre-filled with the current href. */
|
|
176
|
+
onEdit: () => void;
|
|
177
|
+
/**
|
|
178
|
+
* Follows the link. Left to the consumer for the cases this package cannot
|
|
179
|
+
* judge — routing instead of navigating, or confirming first.
|
|
180
|
+
*
|
|
181
|
+
* Defaults to opening a new tab, which is also what Ctrl/Cmd-click does, so
|
|
182
|
+
* the author never loses unsaved work just by checking a URL.
|
|
183
|
+
*/
|
|
184
|
+
onOpen?: (href: string) => void;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* A floating bar that appears when the caret sits inside a link, offering to
|
|
188
|
+
* open, edit or unlink it.
|
|
189
|
+
*
|
|
190
|
+
* It exists because an editor cannot let a plain click navigate: clicking is how
|
|
191
|
+
* you place the caret to fix a typo, so `openOnClick` stays false and this gives
|
|
192
|
+
* the author a deliberate way out to the URL. Ctrl/Cmd-click is wired separately,
|
|
193
|
+
* on the editor itself, for people who expect the shortcut.
|
|
194
|
+
*/
|
|
195
|
+
declare function LinkBubbleMenu({ editor, labels, onEdit, onOpen }: LinkBubbleMenuProps): react.JSX.Element | null;
|
|
196
|
+
|
|
167
197
|
/**
|
|
168
198
|
* Whatever `useEditor` accepts in its `extensions` array.
|
|
169
199
|
*
|
|
@@ -190,6 +220,8 @@ interface RichTextEditorLabels {
|
|
|
190
220
|
bullet: string;
|
|
191
221
|
ordered: string;
|
|
192
222
|
};
|
|
223
|
+
/** The floating bar shown while the caret sits inside a link. */
|
|
224
|
+
link: LinkBubbleMenuLabels;
|
|
193
225
|
table: TableMenuLabels;
|
|
194
226
|
highlight: string;
|
|
195
227
|
}
|
|
@@ -217,6 +249,14 @@ interface UseRichTextEditorOptions {
|
|
|
217
249
|
after?: string;
|
|
218
250
|
items: ToolbarItem[];
|
|
219
251
|
}[];
|
|
252
|
+
/**
|
|
253
|
+
* Replaces a built-in entry, keyed by its id.
|
|
254
|
+
*
|
|
255
|
+
* For when a product needs a richer version of something the preset already
|
|
256
|
+
* provides — swapping the single highlight button for a palette of shades,
|
|
257
|
+
* say. Replacing rather than adding keeps the toolbar from carrying both.
|
|
258
|
+
*/
|
|
259
|
+
replaceToolbar?: Record<string, ToolbarItem>;
|
|
220
260
|
/** Merged on top of the built-in content styles. */
|
|
221
261
|
contentClassName?: string;
|
|
222
262
|
/** Allows data: URIs in images. Off by default: uploads belong in storage. */
|
|
@@ -233,6 +273,14 @@ interface UseRichTextEditorOptions {
|
|
|
233
273
|
}
|
|
234
274
|
interface UseRichTextEditorResult {
|
|
235
275
|
editor: Editor | null;
|
|
276
|
+
/**
|
|
277
|
+
* The floating link bar, ready to render beside `<RichTextEditor />`.
|
|
278
|
+
*
|
|
279
|
+
* Returned as an element rather than left to the consumer because it is easy
|
|
280
|
+
* to forget, and an editor without it gives the author no way to reach or
|
|
281
|
+
* remove a link they have already inserted.
|
|
282
|
+
*/
|
|
283
|
+
linkMenu: ReactNode;
|
|
236
284
|
/** Ready for `<RichTextEditor items={...} />`. */
|
|
237
285
|
toolbar: ToolbarItem[];
|
|
238
286
|
/** True when the caret has no selection, so a new link needs its own text. */
|
|
@@ -254,7 +302,7 @@ interface UseRichTextEditorResult {
|
|
|
254
302
|
* What stays with the consumer is what only it can know: the marks its document
|
|
255
303
|
* contract allows, and the copy. Both arrive as options.
|
|
256
304
|
*/
|
|
257
|
-
declare function useRichTextEditor({ labels, onUpdate, content, onInsertLink, onInsertImage, extraExtensions, extraToolbar, contentClassName, allowBase64Images, editorProps, }: UseRichTextEditorOptions): UseRichTextEditorResult;
|
|
305
|
+
declare function useRichTextEditor({ labels, onUpdate, content, onInsertLink, onInsertImage, extraExtensions, extraToolbar, replaceToolbar, contentClassName, allowBase64Images, editorProps, }: UseRichTextEditorOptions): UseRichTextEditorResult;
|
|
258
306
|
|
|
259
307
|
/**
|
|
260
308
|
* One entry in the palette.
|
|
@@ -363,36 +411,6 @@ interface InsertLinkDialogProps {
|
|
|
363
411
|
*/
|
|
364
412
|
declare function InsertLinkDialog({ open, onOpenChange, labels, url, onUrlChange, text, onTextChange, needsText, onApply, onCancel, }: InsertLinkDialogProps): react.JSX.Element;
|
|
365
413
|
|
|
366
|
-
interface LinkBubbleMenuLabels {
|
|
367
|
-
open: string;
|
|
368
|
-
edit: string;
|
|
369
|
-
remove: string;
|
|
370
|
-
}
|
|
371
|
-
interface LinkBubbleMenuProps {
|
|
372
|
-
editor: Editor | null;
|
|
373
|
-
labels: LinkBubbleMenuLabels;
|
|
374
|
-
/** Opens the consumer's link dialog, pre-filled with the current href. */
|
|
375
|
-
onEdit: () => void;
|
|
376
|
-
/**
|
|
377
|
-
* Follows the link. Left to the consumer for the cases this package cannot
|
|
378
|
-
* judge — routing instead of navigating, or confirming first.
|
|
379
|
-
*
|
|
380
|
-
* Defaults to opening a new tab, which is also what Ctrl/Cmd-click does, so
|
|
381
|
-
* the author never loses unsaved work just by checking a URL.
|
|
382
|
-
*/
|
|
383
|
-
onOpen?: (href: string) => void;
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* A floating bar that appears when the caret sits inside a link, offering to
|
|
387
|
-
* open, edit or unlink it.
|
|
388
|
-
*
|
|
389
|
-
* It exists because an editor cannot let a plain click navigate: clicking is how
|
|
390
|
-
* you place the caret to fix a typo, so `openOnClick` stays false and this gives
|
|
391
|
-
* the author a deliberate way out to the URL. Ctrl/Cmd-click is wired separately,
|
|
392
|
-
* on the editor itself, for people who expect the shortcut.
|
|
393
|
-
*/
|
|
394
|
-
declare function LinkBubbleMenu({ editor, labels, onEdit, onOpen }: LinkBubbleMenuProps): react.JSX.Element | null;
|
|
395
|
-
|
|
396
414
|
interface ResizableImageOptions {
|
|
397
415
|
/** Already translated: names the resize handle for assistive tech. */
|
|
398
416
|
resizeLabel: string;
|
package/dist/editor.d.ts
CHANGED
|
@@ -164,6 +164,36 @@ interface InsertImageDialogProps {
|
|
|
164
164
|
*/
|
|
165
165
|
declare function InsertImageDialog({ open, onOpenChange, labels, url, onUrlChange, alt, onAltChange, file, onFileChange, uploading, onApply, onCancel, removable, onRemove, maxSizeBytes, accept, }: InsertImageDialogProps): react.JSX.Element;
|
|
166
166
|
|
|
167
|
+
interface LinkBubbleMenuLabels {
|
|
168
|
+
open: string;
|
|
169
|
+
edit: string;
|
|
170
|
+
remove: string;
|
|
171
|
+
}
|
|
172
|
+
interface LinkBubbleMenuProps {
|
|
173
|
+
editor: Editor | null;
|
|
174
|
+
labels: LinkBubbleMenuLabels;
|
|
175
|
+
/** Opens the consumer's link dialog, pre-filled with the current href. */
|
|
176
|
+
onEdit: () => void;
|
|
177
|
+
/**
|
|
178
|
+
* Follows the link. Left to the consumer for the cases this package cannot
|
|
179
|
+
* judge — routing instead of navigating, or confirming first.
|
|
180
|
+
*
|
|
181
|
+
* Defaults to opening a new tab, which is also what Ctrl/Cmd-click does, so
|
|
182
|
+
* the author never loses unsaved work just by checking a URL.
|
|
183
|
+
*/
|
|
184
|
+
onOpen?: (href: string) => void;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* A floating bar that appears when the caret sits inside a link, offering to
|
|
188
|
+
* open, edit or unlink it.
|
|
189
|
+
*
|
|
190
|
+
* It exists because an editor cannot let a plain click navigate: clicking is how
|
|
191
|
+
* you place the caret to fix a typo, so `openOnClick` stays false and this gives
|
|
192
|
+
* the author a deliberate way out to the URL. Ctrl/Cmd-click is wired separately,
|
|
193
|
+
* on the editor itself, for people who expect the shortcut.
|
|
194
|
+
*/
|
|
195
|
+
declare function LinkBubbleMenu({ editor, labels, onEdit, onOpen }: LinkBubbleMenuProps): react.JSX.Element | null;
|
|
196
|
+
|
|
167
197
|
/**
|
|
168
198
|
* Whatever `useEditor` accepts in its `extensions` array.
|
|
169
199
|
*
|
|
@@ -190,6 +220,8 @@ interface RichTextEditorLabels {
|
|
|
190
220
|
bullet: string;
|
|
191
221
|
ordered: string;
|
|
192
222
|
};
|
|
223
|
+
/** The floating bar shown while the caret sits inside a link. */
|
|
224
|
+
link: LinkBubbleMenuLabels;
|
|
193
225
|
table: TableMenuLabels;
|
|
194
226
|
highlight: string;
|
|
195
227
|
}
|
|
@@ -217,6 +249,14 @@ interface UseRichTextEditorOptions {
|
|
|
217
249
|
after?: string;
|
|
218
250
|
items: ToolbarItem[];
|
|
219
251
|
}[];
|
|
252
|
+
/**
|
|
253
|
+
* Replaces a built-in entry, keyed by its id.
|
|
254
|
+
*
|
|
255
|
+
* For when a product needs a richer version of something the preset already
|
|
256
|
+
* provides — swapping the single highlight button for a palette of shades,
|
|
257
|
+
* say. Replacing rather than adding keeps the toolbar from carrying both.
|
|
258
|
+
*/
|
|
259
|
+
replaceToolbar?: Record<string, ToolbarItem>;
|
|
220
260
|
/** Merged on top of the built-in content styles. */
|
|
221
261
|
contentClassName?: string;
|
|
222
262
|
/** Allows data: URIs in images. Off by default: uploads belong in storage. */
|
|
@@ -233,6 +273,14 @@ interface UseRichTextEditorOptions {
|
|
|
233
273
|
}
|
|
234
274
|
interface UseRichTextEditorResult {
|
|
235
275
|
editor: Editor | null;
|
|
276
|
+
/**
|
|
277
|
+
* The floating link bar, ready to render beside `<RichTextEditor />`.
|
|
278
|
+
*
|
|
279
|
+
* Returned as an element rather than left to the consumer because it is easy
|
|
280
|
+
* to forget, and an editor without it gives the author no way to reach or
|
|
281
|
+
* remove a link they have already inserted.
|
|
282
|
+
*/
|
|
283
|
+
linkMenu: ReactNode;
|
|
236
284
|
/** Ready for `<RichTextEditor items={...} />`. */
|
|
237
285
|
toolbar: ToolbarItem[];
|
|
238
286
|
/** True when the caret has no selection, so a new link needs its own text. */
|
|
@@ -254,7 +302,7 @@ interface UseRichTextEditorResult {
|
|
|
254
302
|
* What stays with the consumer is what only it can know: the marks its document
|
|
255
303
|
* contract allows, and the copy. Both arrive as options.
|
|
256
304
|
*/
|
|
257
|
-
declare function useRichTextEditor({ labels, onUpdate, content, onInsertLink, onInsertImage, extraExtensions, extraToolbar, contentClassName, allowBase64Images, editorProps, }: UseRichTextEditorOptions): UseRichTextEditorResult;
|
|
305
|
+
declare function useRichTextEditor({ labels, onUpdate, content, onInsertLink, onInsertImage, extraExtensions, extraToolbar, replaceToolbar, contentClassName, allowBase64Images, editorProps, }: UseRichTextEditorOptions): UseRichTextEditorResult;
|
|
258
306
|
|
|
259
307
|
/**
|
|
260
308
|
* One entry in the palette.
|
|
@@ -363,36 +411,6 @@ interface InsertLinkDialogProps {
|
|
|
363
411
|
*/
|
|
364
412
|
declare function InsertLinkDialog({ open, onOpenChange, labels, url, onUrlChange, text, onTextChange, needsText, onApply, onCancel, }: InsertLinkDialogProps): react.JSX.Element;
|
|
365
413
|
|
|
366
|
-
interface LinkBubbleMenuLabels {
|
|
367
|
-
open: string;
|
|
368
|
-
edit: string;
|
|
369
|
-
remove: string;
|
|
370
|
-
}
|
|
371
|
-
interface LinkBubbleMenuProps {
|
|
372
|
-
editor: Editor | null;
|
|
373
|
-
labels: LinkBubbleMenuLabels;
|
|
374
|
-
/** Opens the consumer's link dialog, pre-filled with the current href. */
|
|
375
|
-
onEdit: () => void;
|
|
376
|
-
/**
|
|
377
|
-
* Follows the link. Left to the consumer for the cases this package cannot
|
|
378
|
-
* judge — routing instead of navigating, or confirming first.
|
|
379
|
-
*
|
|
380
|
-
* Defaults to opening a new tab, which is also what Ctrl/Cmd-click does, so
|
|
381
|
-
* the author never loses unsaved work just by checking a URL.
|
|
382
|
-
*/
|
|
383
|
-
onOpen?: (href: string) => void;
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* A floating bar that appears when the caret sits inside a link, offering to
|
|
387
|
-
* open, edit or unlink it.
|
|
388
|
-
*
|
|
389
|
-
* It exists because an editor cannot let a plain click navigate: clicking is how
|
|
390
|
-
* you place the caret to fix a typo, so `openOnClick` stays false and this gives
|
|
391
|
-
* the author a deliberate way out to the URL. Ctrl/Cmd-click is wired separately,
|
|
392
|
-
* on the editor itself, for people who expect the shortcut.
|
|
393
|
-
*/
|
|
394
|
-
declare function LinkBubbleMenu({ editor, labels, onEdit, onOpen }: LinkBubbleMenuProps): react.JSX.Element | null;
|
|
395
|
-
|
|
396
414
|
interface ResizableImageOptions {
|
|
397
415
|
/** Already translated: names the resize handle for assistive tech. */
|
|
398
416
|
resizeLabel: string;
|
package/dist/editor.js
CHANGED
|
@@ -861,20 +861,21 @@ function ResizableImageView({ node, updateAttributes, selected, extension }) {
|
|
|
861
861
|
if (sizeRef.current.width > 0 || fittedSrcRef.current === src) return;
|
|
862
862
|
const fit = () => {
|
|
863
863
|
const available = img.closest(".ProseMirror")?.clientWidth ?? 0;
|
|
864
|
-
if (!img.naturalWidth || !img.naturalHeight || available <= 0) return;
|
|
864
|
+
if (!img.naturalWidth || !img.naturalHeight || available <= 0) return false;
|
|
865
865
|
fittedSrcRef.current = src;
|
|
866
866
|
const nextWidth = Math.min(img.naturalWidth, available);
|
|
867
867
|
updateAttributes({
|
|
868
868
|
width: nextWidth,
|
|
869
869
|
height: Math.round(nextWidth / (img.naturalWidth / img.naturalHeight))
|
|
870
870
|
});
|
|
871
|
+
return true;
|
|
871
872
|
};
|
|
872
|
-
if (img.complete)
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
}
|
|
876
|
-
img.addEventListener("load",
|
|
877
|
-
return () => img.removeEventListener("load",
|
|
873
|
+
if (img.complete && fit()) return;
|
|
874
|
+
const onLoad = () => {
|
|
875
|
+
if (fit()) img.removeEventListener("load", onLoad);
|
|
876
|
+
};
|
|
877
|
+
img.addEventListener("load", onLoad);
|
|
878
|
+
return () => img.removeEventListener("load", onLoad);
|
|
878
879
|
}, [src, updateAttributes]);
|
|
879
880
|
const onPointerDown = useCallback(
|
|
880
881
|
(event) => {
|
|
@@ -974,6 +975,78 @@ function createResizableImage(options) {
|
|
|
974
975
|
}
|
|
975
976
|
});
|
|
976
977
|
}
|
|
978
|
+
function LinkActions({ editor, labels, onEdit, onOpen }) {
|
|
979
|
+
const href = useEditorState({
|
|
980
|
+
editor,
|
|
981
|
+
selector: ({ editor: current }) => current.getAttributes("link").href ?? ""
|
|
982
|
+
});
|
|
983
|
+
return /* @__PURE__ */ jsxs(
|
|
984
|
+
"div",
|
|
985
|
+
{
|
|
986
|
+
"data-slot": "link-bubble-menu",
|
|
987
|
+
className: "bg-popover text-popover-foreground flex items-center gap-1 rounded-md border p-1 shadow-md",
|
|
988
|
+
children: [
|
|
989
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground max-w-[16rem] truncate px-2 text-xs", children: href }),
|
|
990
|
+
/* @__PURE__ */ jsx(
|
|
991
|
+
Button,
|
|
992
|
+
{
|
|
993
|
+
type: "button",
|
|
994
|
+
size: "sm",
|
|
995
|
+
variant: "ghost",
|
|
996
|
+
title: labels.open,
|
|
997
|
+
"aria-label": labels.open,
|
|
998
|
+
disabled: !href,
|
|
999
|
+
onClick: () => {
|
|
1000
|
+
if (!href) return;
|
|
1001
|
+
if (onOpen) {
|
|
1002
|
+
onOpen(href);
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
window.open(href, "_blank", "noopener,noreferrer");
|
|
1006
|
+
},
|
|
1007
|
+
children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" })
|
|
1008
|
+
}
|
|
1009
|
+
),
|
|
1010
|
+
/* @__PURE__ */ jsx(
|
|
1011
|
+
Button,
|
|
1012
|
+
{
|
|
1013
|
+
type: "button",
|
|
1014
|
+
size: "sm",
|
|
1015
|
+
variant: "ghost",
|
|
1016
|
+
title: labels.edit,
|
|
1017
|
+
"aria-label": labels.edit,
|
|
1018
|
+
onClick: onEdit,
|
|
1019
|
+
children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
|
|
1020
|
+
}
|
|
1021
|
+
),
|
|
1022
|
+
/* @__PURE__ */ jsx(
|
|
1023
|
+
Button,
|
|
1024
|
+
{
|
|
1025
|
+
type: "button",
|
|
1026
|
+
size: "sm",
|
|
1027
|
+
variant: "ghost",
|
|
1028
|
+
className: "text-destructive",
|
|
1029
|
+
title: labels.remove,
|
|
1030
|
+
"aria-label": labels.remove,
|
|
1031
|
+
onClick: () => editor.chain().focus().extendMarkRange("link").unsetLink().run(),
|
|
1032
|
+
children: /* @__PURE__ */ jsx(Unlink, { className: "h-4 w-4" })
|
|
1033
|
+
}
|
|
1034
|
+
)
|
|
1035
|
+
]
|
|
1036
|
+
}
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
function LinkBubbleMenu({ editor, labels, onEdit, onOpen }) {
|
|
1040
|
+
const shouldShow = useCallback(
|
|
1041
|
+
// Only while the caret is actually in a link — otherwise this bar would
|
|
1042
|
+
// compete with any other bubble menu the consumer adds.
|
|
1043
|
+
({ editor: current }) => current.isActive("link"),
|
|
1044
|
+
[]
|
|
1045
|
+
);
|
|
1046
|
+
const options = useMemo(() => ({ placement: "bottom", offset: 8 }), []);
|
|
1047
|
+
if (!editor) return null;
|
|
1048
|
+
return /* @__PURE__ */ jsx(BubbleMenu, { editor, shouldShow, options, children: /* @__PURE__ */ jsx(LinkActions, { editor, labels, onEdit, onOpen }) });
|
|
1049
|
+
}
|
|
977
1050
|
function ListMenu({ editor, triggerLabel, icon, options }) {
|
|
978
1051
|
const active = options.find((option) => editor?.isActive(option.node));
|
|
979
1052
|
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
@@ -1026,6 +1099,7 @@ function useRichTextEditor({
|
|
|
1026
1099
|
onInsertImage,
|
|
1027
1100
|
extraExtensions = [],
|
|
1028
1101
|
extraToolbar = [],
|
|
1102
|
+
replaceToolbar,
|
|
1029
1103
|
contentClassName,
|
|
1030
1104
|
allowBase64Images = false,
|
|
1031
1105
|
editorProps
|
|
@@ -1221,7 +1295,9 @@ function useRichTextEditor({
|
|
|
1221
1295
|
)
|
|
1222
1296
|
}
|
|
1223
1297
|
];
|
|
1224
|
-
let items = builtIn
|
|
1298
|
+
let items = replaceToolbar ? builtIn.map(
|
|
1299
|
+
(item) => item.kind !== "separator" && replaceToolbar[item.id] ? replaceToolbar[item.id] : item
|
|
1300
|
+
) : builtIn;
|
|
1225
1301
|
const appended = [];
|
|
1226
1302
|
for (const group of extraToolbar) {
|
|
1227
1303
|
if (!group.after) {
|
|
@@ -1238,8 +1314,9 @@ function useRichTextEditor({
|
|
|
1238
1314
|
items = [...items.slice(0, at + 1), ...group.items, ...items.slice(at + 1)];
|
|
1239
1315
|
}
|
|
1240
1316
|
return [...items, ...appended];
|
|
1241
|
-
}, [labels, extraToolbar, onInsertImage, openLink]);
|
|
1242
|
-
|
|
1317
|
+
}, [labels, extraToolbar, replaceToolbar, onInsertImage, openLink]);
|
|
1318
|
+
const linkMenu = /* @__PURE__ */ jsx(LinkBubbleMenu, { editor, labels: labels.link, onEdit: openLink });
|
|
1319
|
+
return { editor, toolbar, linkMenu, linkNeedsText, currentLinkHref, applyLink };
|
|
1243
1320
|
}
|
|
1244
1321
|
function ColorMenu({ editor, labels, icon, swatches }) {
|
|
1245
1322
|
const active = swatches.find((swatch) => editor?.isActive(swatch.mark));
|
|
@@ -1379,78 +1456,6 @@ function InsertLinkDialog({
|
|
|
1379
1456
|
] })
|
|
1380
1457
|
] }) });
|
|
1381
1458
|
}
|
|
1382
|
-
function LinkActions({ editor, labels, onEdit, onOpen }) {
|
|
1383
|
-
const href = useEditorState({
|
|
1384
|
-
editor,
|
|
1385
|
-
selector: ({ editor: current }) => current.getAttributes("link").href ?? ""
|
|
1386
|
-
});
|
|
1387
|
-
return /* @__PURE__ */ jsxs(
|
|
1388
|
-
"div",
|
|
1389
|
-
{
|
|
1390
|
-
"data-slot": "link-bubble-menu",
|
|
1391
|
-
className: "bg-popover text-popover-foreground flex items-center gap-1 rounded-md border p-1 shadow-md",
|
|
1392
|
-
children: [
|
|
1393
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground max-w-[16rem] truncate px-2 text-xs", children: href }),
|
|
1394
|
-
/* @__PURE__ */ jsx(
|
|
1395
|
-
Button,
|
|
1396
|
-
{
|
|
1397
|
-
type: "button",
|
|
1398
|
-
size: "sm",
|
|
1399
|
-
variant: "ghost",
|
|
1400
|
-
title: labels.open,
|
|
1401
|
-
"aria-label": labels.open,
|
|
1402
|
-
disabled: !href,
|
|
1403
|
-
onClick: () => {
|
|
1404
|
-
if (!href) return;
|
|
1405
|
-
if (onOpen) {
|
|
1406
|
-
onOpen(href);
|
|
1407
|
-
return;
|
|
1408
|
-
}
|
|
1409
|
-
window.open(href, "_blank", "noopener,noreferrer");
|
|
1410
|
-
},
|
|
1411
|
-
children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" })
|
|
1412
|
-
}
|
|
1413
|
-
),
|
|
1414
|
-
/* @__PURE__ */ jsx(
|
|
1415
|
-
Button,
|
|
1416
|
-
{
|
|
1417
|
-
type: "button",
|
|
1418
|
-
size: "sm",
|
|
1419
|
-
variant: "ghost",
|
|
1420
|
-
title: labels.edit,
|
|
1421
|
-
"aria-label": labels.edit,
|
|
1422
|
-
onClick: onEdit,
|
|
1423
|
-
children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" })
|
|
1424
|
-
}
|
|
1425
|
-
),
|
|
1426
|
-
/* @__PURE__ */ jsx(
|
|
1427
|
-
Button,
|
|
1428
|
-
{
|
|
1429
|
-
type: "button",
|
|
1430
|
-
size: "sm",
|
|
1431
|
-
variant: "ghost",
|
|
1432
|
-
className: "text-destructive",
|
|
1433
|
-
title: labels.remove,
|
|
1434
|
-
"aria-label": labels.remove,
|
|
1435
|
-
onClick: () => editor.chain().focus().extendMarkRange("link").unsetLink().run(),
|
|
1436
|
-
children: /* @__PURE__ */ jsx(Unlink, { className: "h-4 w-4" })
|
|
1437
|
-
}
|
|
1438
|
-
)
|
|
1439
|
-
]
|
|
1440
|
-
}
|
|
1441
|
-
);
|
|
1442
|
-
}
|
|
1443
|
-
function LinkBubbleMenu({ editor, labels, onEdit, onOpen }) {
|
|
1444
|
-
const shouldShow = useCallback(
|
|
1445
|
-
// Only while the caret is actually in a link — otherwise this bar would
|
|
1446
|
-
// compete with any other bubble menu the consumer adds.
|
|
1447
|
-
({ editor: current }) => current.isActive("link"),
|
|
1448
|
-
[]
|
|
1449
|
-
);
|
|
1450
|
-
const options = useMemo(() => ({ placement: "bottom", offset: 8 }), []);
|
|
1451
|
-
if (!editor) return null;
|
|
1452
|
-
return /* @__PURE__ */ jsx(BubbleMenu, { editor, shouldShow, options, children: /* @__PURE__ */ jsx(LinkActions, { editor, labels, onEdit, onOpen }) });
|
|
1453
|
-
}
|
|
1454
1459
|
|
|
1455
1460
|
export { ColorMenu, EDITOR_CONTENT_STYLE, InsertImageDialog, InsertLinkDialog, LinkBubbleMenu, ListMenu, RichTextEditor, RichTextToolbar, TableMenu, createResizableImage, useRichTextEditor };
|
|
1456
1461
|
//# sourceMappingURL=editor.js.map
|