@cgi-learning-hub/ui 1.14.0 → 1.15.0

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.
@@ -0,0 +1,2843 @@
1
+ import { H as IconButton, It as Tooltip, Lt as Typography, Nt as ToggleButton, W as InputBase, Zt as DeleteRounded_default, et as Menu, hn as clsx, j as Divider, ln as SvgIcon_default, mt as Stack, ot as Popover, tt as MenuItem, u as Badge } from "../src-jE7nLe9k.js";
2
+ import { Fragment, forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
+ import { styled } from "@mui/material/styles";
5
+ import { createSvgIcon } from "@mui/material/utils";
6
+ import { AllSelection, NodeSelection, TextSelection } from "@tiptap/pm/state";
7
+ import { useCurrentEditor, useEditorState } from "@tiptap/react";
8
+ import "@tiptap/pm/tables";
9
+ //#region src/tiptap/components/icons/text-snippet-icon.tsx
10
+ var TextSnippetIcon = createSvgIcon(/* @__PURE__ */ jsx("path", { d: "M14.17,5L19,9.83V19H5V5L14.17,5L14.17,5 M14.17,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V9.83 c0-0.53-0.21-1.04-0.59-1.41l-4.83-4.83C15.21,3.21,14.7,3,14.17,3L14.17,3z M7,15h10v2H7V15z M7,11h10v2H7V11z M7,7h7v2H7V7z" }), "TextSnippet");
11
+ //#endregion
12
+ //#region src/tiptap/hooks/use-tiptap-editor.ts
13
+ function getActivePageEditor(editor) {
14
+ const pages = editor.storage.pages;
15
+ if (!pages || !("activeEditor" in pages)) return null;
16
+ return pages.activeEditor ?? null;
17
+ }
18
+ function useTiptapEditor(providedEditor) {
19
+ const { editor: coreEditor } = useCurrentEditor();
20
+ const mainEditor = providedEditor ?? coreEditor;
21
+ const [storageEditor, setStorageEditor] = useState(null);
22
+ useEffect(() => {
23
+ if (!mainEditor) {
24
+ setStorageEditor(null);
25
+ return;
26
+ }
27
+ const updateHandler = () => setStorageEditor(getActivePageEditor(mainEditor));
28
+ updateHandler();
29
+ mainEditor.on("update", updateHandler);
30
+ mainEditor.on("selectionUpdate", updateHandler);
31
+ return () => {
32
+ mainEditor.off("update", updateHandler);
33
+ mainEditor.off("selectionUpdate", updateHandler);
34
+ };
35
+ }, [mainEditor]);
36
+ useEffect(() => {
37
+ if (!storageEditor) return;
38
+ const handleDestroy = () => setStorageEditor(null);
39
+ storageEditor.on("destroy", handleDestroy);
40
+ return () => {
41
+ storageEditor.off("destroy", handleDestroy);
42
+ };
43
+ }, [storageEditor]);
44
+ return useEditorState({
45
+ editor: storageEditor ?? mainEditor,
46
+ selector(context) {
47
+ if (!context.editor) return {
48
+ editor: null,
49
+ editorState: void 0,
50
+ canCommand: void 0
51
+ };
52
+ return {
53
+ editor: context.editor,
54
+ editorState: context.editor.state,
55
+ canCommand: context.editor.can
56
+ };
57
+ }
58
+ }) ?? { editor: null };
59
+ }
60
+ //#endregion
61
+ //#region src/tiptap/lib/tiptap-utils.ts
62
+ var MAC_SYMBOLS = {
63
+ mod: "⌘",
64
+ command: "⌘",
65
+ meta: "⌘",
66
+ ctrl: "⌃",
67
+ control: "⌃",
68
+ alt: "⌥",
69
+ option: "⌥",
70
+ shift: "⇧",
71
+ backspace: "Del",
72
+ delete: "⌦",
73
+ enter: "⏎",
74
+ escape: "⎋",
75
+ capslock: "⇪"
76
+ };
77
+ function cn(...inputs) {
78
+ return clsx(inputs);
79
+ }
80
+ /**
81
+ * Determines if the current platform is macOS
82
+ * @returns boolean indicating if the current platform is Mac
83
+ */
84
+ function isMac() {
85
+ return typeof navigator !== "undefined" && navigator.platform.toLowerCase().includes("mac");
86
+ }
87
+ /**
88
+ * Formats a shortcut key based on the platform (Mac or non-Mac)
89
+ * @param key - The key to format (e.g., "ctrl", "alt", "shift")
90
+ * @param isMac - Boolean indicating if the platform is Mac
91
+ * @param capitalize - Whether to capitalize the key (default: true)
92
+ * @returns Formatted shortcut key symbol
93
+ */
94
+ var formatShortcutKey = (key, isMac, capitalize = true) => {
95
+ if (isMac) return MAC_SYMBOLS[key.toLowerCase()] || (capitalize ? key.toUpperCase() : key);
96
+ return capitalize ? key.charAt(0).toUpperCase() + key.slice(1) : key;
97
+ };
98
+ /**
99
+ * Parses a shortcut key string into an array of formatted key symbols
100
+ * @param shortcutKeys - The string of shortcut keys (e.g., "ctrl-alt-shift")
101
+ * @param delimiter - The delimiter used to split the keys (default: "-")
102
+ * @param capitalize - Whether to capitalize the keys (default: true)
103
+ * @returns Array of formatted shortcut key symbols
104
+ */
105
+ var parseShortcutKeys = (props) => {
106
+ const { shortcutKeys, delimiter = "+", capitalize = true } = props;
107
+ if (!shortcutKeys) return [];
108
+ return shortcutKeys.split(delimiter).map((key) => key.trim()).map((key) => formatShortcutKey(key, isMac(), capitalize));
109
+ };
110
+ /**
111
+ * Checks if a mark exists in the editor schema
112
+ * @param markName - The name of the mark to check
113
+ * @param editor - The editor instance
114
+ * @returns boolean indicating if the mark exists in the schema
115
+ */
116
+ var isMarkInSchema = (markName, editor) => {
117
+ if (!editor?.schema) return false;
118
+ return editor.schema.spec.marks.get(markName) !== void 0;
119
+ };
120
+ /**
121
+ * Checks if a node exists in the editor schema
122
+ * @param nodeName - The name of the node to check
123
+ * @param editor - The editor instance
124
+ * @returns boolean indicating if the node exists in the schema
125
+ */
126
+ var isNodeInSchema = (nodeName, editor) => {
127
+ if (!editor?.schema) return false;
128
+ return editor.schema.spec.nodes.get(nodeName) !== void 0;
129
+ };
130
+ /**
131
+ * Checks if a value is a valid number (not null, undefined, or NaN)
132
+ * @param value - The value to check
133
+ * @returns boolean indicating if the value is a valid number
134
+ */
135
+ function isValidPosition(pos) {
136
+ return typeof pos === "number" && pos >= 0;
137
+ }
138
+ /**
139
+ * Checks if one or more extensions are registered in the Tiptap editor.
140
+ * @param editor - The Tiptap editor instance
141
+ * @param extensionNames - A single extension name or an array of names to check
142
+ * @returns True if at least one of the extensions is available, false otherwise
143
+ */
144
+ var warnedMissingExtensions = /* @__PURE__ */ new Set();
145
+ function isExtensionAvailable(editor, extensionNames) {
146
+ if (!editor || editor.isDestroyed) return false;
147
+ const names = Array.isArray(extensionNames) ? extensionNames : [extensionNames];
148
+ const extensions = editor.extensionManager?.extensions;
149
+ if (!extensions) return false;
150
+ const found = names.some((name) => extensions.some((ext) => ext.name === name));
151
+ if (!found) {
152
+ const key = names.join(", ");
153
+ if (!warnedMissingExtensions.has(key)) {
154
+ warnedMissingExtensions.add(key);
155
+ console.warn(`None of the extensions [${key}] were found in the editor schema. Ensure they are included in the editor configuration.`);
156
+ }
157
+ }
158
+ return found;
159
+ }
160
+ /**
161
+ * Finds a node at the specified position with error handling
162
+ * @param editor The Tiptap editor instance
163
+ * @param position The position in the document to find the node
164
+ * @returns The node at the specified position, or null if not found
165
+ */
166
+ function findNodeAtPosition(editor, position) {
167
+ try {
168
+ const node = editor.state.doc.nodeAt(position);
169
+ if (!node) {
170
+ console.warn(`No node found at position ${position}`);
171
+ return null;
172
+ }
173
+ return node;
174
+ } catch (error) {
175
+ console.error(`Error getting node at position ${position}:`, error);
176
+ return null;
177
+ }
178
+ }
179
+ /**
180
+ * Finds the position and instance of a node in the document
181
+ * @param props Object containing editor, node (optional), and nodePos (optional)
182
+ * @param props.editor The Tiptap editor instance
183
+ * @param props.node The node to find (optional if nodePos is provided)
184
+ * @param props.nodePos The position of the node to find (optional if node is provided)
185
+ * @returns An object with the position and node, or null if not found
186
+ */
187
+ function findNodePosition(props) {
188
+ const { editor, node, nodePos } = props;
189
+ if (!editor || !editor.state?.doc) return null;
190
+ const hasValidNode = node !== void 0 && node !== null;
191
+ const hasValidPos = isValidPosition(nodePos);
192
+ if (!hasValidNode && !hasValidPos) return null;
193
+ if (hasValidNode) {
194
+ let foundPos = -1;
195
+ let foundNode = null;
196
+ editor.state.doc.descendants((currentNode, pos) => {
197
+ if (currentNode === node) {
198
+ foundPos = pos;
199
+ foundNode = currentNode;
200
+ return false;
201
+ }
202
+ return true;
203
+ });
204
+ if (foundPos !== -1 && foundNode !== null) return {
205
+ pos: foundPos,
206
+ node: foundNode
207
+ };
208
+ }
209
+ if (hasValidPos) {
210
+ const nodeAtPos = findNodeAtPosition(editor, nodePos);
211
+ if (nodeAtPos) return {
212
+ pos: nodePos,
213
+ node: nodeAtPos
214
+ };
215
+ }
216
+ return null;
217
+ }
218
+ /**
219
+ * Determines whether the current selection contains a node whose type matches
220
+ * any of the provided node type names.
221
+ * @param editor Tiptap editor instance
222
+ * @param nodeTypeNames List of node type names to match against
223
+ * @param checkAncestorNodes Whether to check ancestor node types up the depth chain
224
+ */
225
+ function isNodeTypeSelected(editor, nodeTypeNames = [], checkAncestorNodes = false) {
226
+ if (!editor || !editor.state.selection) return false;
227
+ const { selection } = editor.state;
228
+ if (selection.empty) return false;
229
+ if (selection instanceof NodeSelection) {
230
+ const selectedNode = selection.node;
231
+ return selectedNode ? nodeTypeNames.includes(selectedNode.type.name) : false;
232
+ }
233
+ if (checkAncestorNodes) {
234
+ const { $from } = selection;
235
+ for (let depth = $from.depth; depth > 0; depth--) {
236
+ const ancestorNode = $from.node(depth);
237
+ if (nodeTypeNames.includes(ancestorNode.type.name)) return true;
238
+ }
239
+ }
240
+ return false;
241
+ }
242
+ /**
243
+ * Check whether the current selection is fully within nodes
244
+ * whose type names are in the provided `types` list.
245
+ *
246
+ * - NodeSelection → checks the selected node.
247
+ * - Text/AllSelection → ensures all textblocks within [from, to) are allowed.
248
+ */
249
+ function selectionWithinConvertibleTypes(editor, types = []) {
250
+ if (!editor || types.length === 0) return false;
251
+ const { state } = editor;
252
+ const { selection } = state;
253
+ const allowed = new Set(types);
254
+ if (selection instanceof NodeSelection) {
255
+ const nodeType = selection.node?.type?.name;
256
+ return !!nodeType && allowed.has(nodeType);
257
+ }
258
+ if (selection instanceof TextSelection || selection instanceof AllSelection) {
259
+ let valid = true;
260
+ state.doc.nodesBetween(selection.from, selection.to, (node) => {
261
+ if (node.isTextblock && !allowed.has(node.type.name)) {
262
+ valid = false;
263
+ return false;
264
+ }
265
+ return valid;
266
+ });
267
+ return valid;
268
+ }
269
+ return false;
270
+ }
271
+ var ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
272
+ function isAllowedUri(uri, protocols) {
273
+ const allowedProtocols = [
274
+ "http",
275
+ "https",
276
+ "ftp",
277
+ "ftps",
278
+ "mailto",
279
+ "tel",
280
+ "callto",
281
+ "sms",
282
+ "cid",
283
+ "xmpp"
284
+ ];
285
+ if (protocols) protocols.forEach((protocol) => {
286
+ const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
287
+ if (nextProtocol) allowedProtocols.push(nextProtocol);
288
+ });
289
+ return !uri || uri.replace(ATTR_WHITESPACE, "").match(new RegExp(`^(?:(?:${allowedProtocols.join("|")}):|[^a-z]|[a-z0-9+.\-]+(?:[^a-z+.\-:]|$))`, "i"));
290
+ }
291
+ function sanitizeUrl(inputUrl, baseUrl, protocols) {
292
+ try {
293
+ const url = new URL(inputUrl, baseUrl);
294
+ if (isAllowedUri(url.href, protocols)) return url.href;
295
+ } catch {}
296
+ return "#";
297
+ }
298
+ function getSelectedBlockNodes(editor) {
299
+ const { doc } = editor.state;
300
+ const { from, to } = editor.state.selection;
301
+ const blocks = [];
302
+ const seen = /* @__PURE__ */ new Set();
303
+ doc.nodesBetween(from, to, (node, pos) => {
304
+ if (!node.isBlock) return;
305
+ if (!seen.has(pos)) {
306
+ seen.add(pos);
307
+ blocks.push(node);
308
+ }
309
+ return false;
310
+ });
311
+ return blocks;
312
+ }
313
+ //#endregion
314
+ //#region src/tiptap/components/ui/blockquote-button/use-blockquote.ts
315
+ var BLOCKQUOTE_SHORTCUT_KEY = "mod+shift+b";
316
+ /**
317
+ * Checks if blockquote can be toggled in the current editor state
318
+ */
319
+ function canToggleBlockquote(editor, turnInto = true) {
320
+ if (!editor || !editor.isEditable) return false;
321
+ if (!isNodeInSchema("blockquote", editor) || isNodeTypeSelected(editor, ["image"])) return false;
322
+ if (!turnInto) return editor.can().toggleWrap("blockquote");
323
+ if (!selectionWithinConvertibleTypes(editor, [
324
+ "paragraph",
325
+ "heading",
326
+ "bulletList",
327
+ "orderedList",
328
+ "taskList",
329
+ "blockquote",
330
+ "codeBlock"
331
+ ])) return false;
332
+ return editor.can().toggleWrap("blockquote") || editor.can().clearNodes();
333
+ }
334
+ /**
335
+ * Toggles blockquote formatting for a specific node or the current selection
336
+ */
337
+ function toggleBlockquote(editor) {
338
+ if (!editor || !editor.isEditable) return false;
339
+ if (!canToggleBlockquote(editor)) return false;
340
+ try {
341
+ const view = editor.view;
342
+ let state = view.state;
343
+ let tr = state.tr;
344
+ const blocks = getSelectedBlockNodes(editor);
345
+ const isPossibleToTurnInto = selectionWithinConvertibleTypes(editor, [
346
+ "paragraph",
347
+ "heading",
348
+ "bulletList",
349
+ "orderedList",
350
+ "taskList",
351
+ "blockquote",
352
+ "codeBlock"
353
+ ]) && blocks.length === 1;
354
+ if ((state.selection.empty || state.selection instanceof TextSelection) && isPossibleToTurnInto) {
355
+ const pos = findNodePosition({
356
+ editor,
357
+ node: state.selection.$anchor.node(1)
358
+ })?.pos;
359
+ if (!isValidPosition(pos)) return false;
360
+ tr = tr.setSelection(NodeSelection.create(state.doc, pos));
361
+ view.dispatch(tr);
362
+ state = view.state;
363
+ }
364
+ const selection = state.selection;
365
+ let chain = editor.chain().focus();
366
+ if (selection instanceof NodeSelection) {
367
+ const firstChild = selection.node.firstChild?.firstChild;
368
+ const lastChild = selection.node.lastChild?.lastChild;
369
+ const from = firstChild ? selection.from + firstChild.nodeSize : selection.from + 1;
370
+ const to = lastChild ? selection.to - lastChild.nodeSize : selection.to - 1;
371
+ const resolvedFrom = state.doc.resolve(from);
372
+ const resolvedTo = state.doc.resolve(to);
373
+ chain = chain.setTextSelection(TextSelection.between(resolvedFrom, resolvedTo)).clearNodes();
374
+ }
375
+ (editor.isActive("blockquote") ? chain.lift("blockquote") : chain.wrapIn("blockquote")).run();
376
+ editor.chain().focus().selectTextblockEnd().run();
377
+ return true;
378
+ } catch {
379
+ return false;
380
+ }
381
+ }
382
+ /**
383
+ * Determines if the blockquote button should be shown
384
+ */
385
+ function shouldShowButton$5(props) {
386
+ const { editor, hideWhenUnavailable } = props;
387
+ if (!editor) return false;
388
+ if (!hideWhenUnavailable) return true;
389
+ if (!editor.isEditable) return false;
390
+ if (!isNodeInSchema("blockquote", editor)) return false;
391
+ if (!editor.isActive("code")) return canToggleBlockquote(editor);
392
+ return true;
393
+ }
394
+ /**
395
+ * Custom hook that provides blockquote functionality for Tiptap editor
396
+ *
397
+ * @example
398
+ * ```tsx
399
+ * // Simple usage - no params needed
400
+ * function MySimpleBlockquoteButton() {
401
+ * const { isVisible, handleToggle, isActive } = useBlockquote()
402
+ *
403
+ * if (!isVisible) return null
404
+ *
405
+ * return <button onClick={handleToggle}>Blockquote</button>
406
+ * }
407
+ *
408
+ * // Advanced usage with configuration
409
+ * function MyAdvancedBlockquoteButton() {
410
+ * const { isVisible, handleToggle, label, isActive } = useBlockquote({
411
+ * editor: myEditor,
412
+ * hideWhenUnavailable: true,
413
+ * onToggled: () => console.log('Blockquote toggled!')
414
+ * })
415
+ *
416
+ * if (!isVisible) return null
417
+ *
418
+ * return (
419
+ * <MyButton
420
+ * onClick={handleToggle}
421
+ * aria-label={label}
422
+ * aria-pressed={isActive}
423
+ * >
424
+ * Toggle Blockquote
425
+ * </MyButton>
426
+ * )
427
+ * }
428
+ * ```
429
+ */
430
+ function useBlockquote(config) {
431
+ const { editor: providedEditor, hideWhenUnavailable = false, onToggled } = config || {};
432
+ const { editor } = useTiptapEditor(providedEditor);
433
+ const [isVisible, setIsVisible] = useState(true);
434
+ const canToggle = canToggleBlockquote(editor);
435
+ const isActive = editor?.isActive("blockquote") || false;
436
+ useEffect(() => {
437
+ if (!editor) return;
438
+ const handleSelectionUpdate = () => {
439
+ setIsVisible(shouldShowButton$5({
440
+ editor,
441
+ hideWhenUnavailable
442
+ }));
443
+ };
444
+ handleSelectionUpdate();
445
+ editor.on("selectionUpdate", handleSelectionUpdate);
446
+ return () => {
447
+ editor.off("selectionUpdate", handleSelectionUpdate);
448
+ };
449
+ }, [editor, hideWhenUnavailable]);
450
+ return {
451
+ isVisible,
452
+ isActive,
453
+ handleToggle: useCallback(() => {
454
+ if (!editor) return false;
455
+ const success = toggleBlockquote(editor);
456
+ if (success) onToggled?.();
457
+ return success;
458
+ }, [editor, onToggled]),
459
+ canToggle,
460
+ label: "Citation en bloc",
461
+ shortcutKeys: BLOCKQUOTE_SHORTCUT_KEY,
462
+ Icon: TextSnippetIcon
463
+ };
464
+ }
465
+ //#endregion
466
+ //#region src/tiptap/components/ui-primitive/button/button.tsx
467
+ var ShortcutDisplay = ({ shortcuts }) => {
468
+ if (shortcuts.length === 0) return null;
469
+ return /* @__PURE__ */ jsx("div", { children: shortcuts.map((key, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && /* @__PURE__ */ jsx("kbd", { children: "+" }), /* @__PURE__ */ jsx("kbd", { children: key })] }, index)) });
470
+ };
471
+ var Button = forwardRef(({ className, children, tooltip, showTooltip = true, shortcutKeys, ...props }, ref) => {
472
+ const shortcuts = useMemo(() => parseShortcutKeys({ shortcutKeys }), [shortcutKeys]);
473
+ if (!tooltip || !showTooltip) return /* @__PURE__ */ jsx(ToggleButton, {
474
+ size: "small",
475
+ color: "primary",
476
+ ref,
477
+ sx: {
478
+ border: "none",
479
+ "&:disabled": { border: "none" }
480
+ },
481
+ ...props,
482
+ children
483
+ });
484
+ return /* @__PURE__ */ jsx(Tooltip, {
485
+ enterDelay: 200,
486
+ title: /* @__PURE__ */ jsxs(Fragment$1, { children: [tooltip, /* @__PURE__ */ jsx(ShortcutDisplay, { shortcuts })] }),
487
+ slotProps: { popper: { modifiers: [{
488
+ name: "offset",
489
+ options: { offset: [0, -8] }
490
+ }] } },
491
+ children: /* @__PURE__ */ jsx(ToggleButton, {
492
+ size: "small",
493
+ color: "primary",
494
+ ref,
495
+ sx: {
496
+ border: "none",
497
+ "&:disabled": { border: "none" }
498
+ },
499
+ ...props,
500
+ children
501
+ })
502
+ });
503
+ });
504
+ Button.displayName = "Button";
505
+ //#endregion
506
+ //#region src/tiptap/components/ui/blockquote-button/blockquote-button.tsx
507
+ function BlockquoteShortcutBadge({ shortcutKeys = BLOCKQUOTE_SHORTCUT_KEY }) {
508
+ return /* @__PURE__ */ jsx(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
509
+ }
510
+ /**
511
+ * Button component for toggling blockquote in a Tiptap editor.
512
+ *
513
+ * For custom button implementations, use the `useBlockquote` hook instead.
514
+ */
515
+ var BlockquoteButton = forwardRef(({ editor: providedEditor, text, hideWhenUnavailable = false, onToggled, showShortcut = false, onClick, children, ...buttonProps }, ref) => {
516
+ const { editor } = useTiptapEditor(providedEditor);
517
+ const { isVisible, canToggle, isActive, handleToggle, label, shortcutKeys, Icon } = useBlockquote({
518
+ editor,
519
+ hideWhenUnavailable,
520
+ onToggled
521
+ });
522
+ const handleClick = useCallback((event) => {
523
+ onClick?.(event, !isActive);
524
+ if (event.defaultPrevented) return;
525
+ handleToggle();
526
+ }, [handleToggle, onClick]);
527
+ if (!isVisible) return null;
528
+ return /* @__PURE__ */ jsx(Button, {
529
+ value: "blockquote",
530
+ type: "button",
531
+ selected: isActive,
532
+ role: "button",
533
+ tabIndex: -1,
534
+ disabled: !canToggle,
535
+ "data-disabled": !canToggle,
536
+ "aria-label": label,
537
+ tooltip: label,
538
+ onClick: handleClick,
539
+ ...buttonProps,
540
+ ref,
541
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
542
+ /* @__PURE__ */ jsx(Icon, { fontSize: "small" }),
543
+ text && /* @__PURE__ */ jsx("span", {
544
+ className: "tiptap-button-text",
545
+ children: text
546
+ }),
547
+ showShortcut && /* @__PURE__ */ jsx(BlockquoteShortcutBadge, { shortcutKeys })
548
+ ] })
549
+ });
550
+ });
551
+ BlockquoteButton.displayName = "BlockquoteButton";
552
+ //#endregion
553
+ //#region src/tiptap/components/icons/integration-instructions-icon.tsx
554
+ var IntegrationInstructionIcon = createSvgIcon(/* @__PURE__ */ jsxs("g", { children: [
555
+ /* @__PURE__ */ jsx("rect", {
556
+ fill: "none",
557
+ height: "24",
558
+ width: "24"
559
+ }),
560
+ /* @__PURE__ */ jsx("circle", {
561
+ cx: "12",
562
+ cy: "3.5",
563
+ fill: "none",
564
+ r: ".75"
565
+ }),
566
+ /* @__PURE__ */ jsx("circle", {
567
+ cx: "12",
568
+ cy: "3.5",
569
+ fill: "none",
570
+ r: ".75"
571
+ }),
572
+ /* @__PURE__ */ jsx("polygon", {
573
+ fill: "none",
574
+ points: "5,15 5,16 5,19 19,19 19,16 19,15 19,5 5,5"
575
+ }),
576
+ /* @__PURE__ */ jsxs("g", { children: [
577
+ /* @__PURE__ */ jsx("polygon", { points: "11,14.17 8.83,12 11,9.83 9.59,8.41 6,12 9.59,15.59" }),
578
+ /* @__PURE__ */ jsx("polygon", { points: "14.41,15.59 18,12 14.41,8.41 13,9.83 15.17,12 13,14.17" }),
579
+ /* @__PURE__ */ jsx("path", { d: "M19,3h-4.18C14.4,1.84,13.3,1,12,1S9.6,1.84,9.18,3H5C4.86,3,4.73,3.01,4.6,3.04C4.21,3.12,3.86,3.32,3.59,3.59 c-0.18,0.18-0.33,0.4-0.43,0.64C3.06,4.46,3,4.72,3,5v10v1v3c0,0.27,0.06,0.54,0.16,0.78c0.1,0.24,0.25,0.45,0.43,0.64 c0.27,0.27,0.62,0.47,1.01,0.55C4.73,20.99,4.86,21,5,21h14c1.1,0,2-0.9,2-2v-3v-1V5C21,3.9,20.1,3,19,3z M12,2.75 c0.41,0,0.75,0.34,0.75,0.75S12.41,4.25,12,4.25s-0.75-0.34-0.75-0.75S11.59,2.75,12,2.75z M19,15v1v3H5v-3v-1V5h14V15z" })
580
+ ] })
581
+ ] }), "IntegrationInstruction");
582
+ //#endregion
583
+ //#region src/tiptap/components/ui/code-block-button/use-code-block.ts
584
+ var CODE_BLOCK_SHORTCUT_KEY = "mod+alt+c";
585
+ /**
586
+ * Checks if code block can be toggled in the current editor state
587
+ */
588
+ function canToggle$1(editor, turnInto = true) {
589
+ if (!editor || !editor.isEditable) return false;
590
+ if (!isNodeInSchema("codeBlock", editor) || isNodeTypeSelected(editor, ["image"])) return false;
591
+ if (!turnInto) return editor.can().toggleNode("codeBlock", "paragraph");
592
+ if (!selectionWithinConvertibleTypes(editor, [
593
+ "paragraph",
594
+ "heading",
595
+ "bulletList",
596
+ "orderedList",
597
+ "taskList",
598
+ "blockquote",
599
+ "codeBlock"
600
+ ])) return false;
601
+ return editor.can().toggleNode("codeBlock", "paragraph") || editor.can().clearNodes();
602
+ }
603
+ /**
604
+ * Toggles code block in the editor
605
+ */
606
+ function toggleCodeBlock(editor) {
607
+ if (!editor || !editor.isEditable) return false;
608
+ if (!canToggle$1(editor)) return false;
609
+ try {
610
+ const view = editor.view;
611
+ let state = view.state;
612
+ let tr = state.tr;
613
+ const blocks = getSelectedBlockNodes(editor);
614
+ const isPossibleToTurnInto = selectionWithinConvertibleTypes(editor, [
615
+ "paragraph",
616
+ "heading",
617
+ "bulletList",
618
+ "orderedList",
619
+ "taskList",
620
+ "blockquote",
621
+ "codeBlock"
622
+ ]) && blocks.length === 1;
623
+ if ((state.selection.empty || state.selection instanceof TextSelection) && isPossibleToTurnInto) {
624
+ const pos = findNodePosition({
625
+ editor,
626
+ node: state.selection.$anchor.node(1)
627
+ })?.pos;
628
+ if (!isValidPosition(pos)) return false;
629
+ tr = tr.setSelection(NodeSelection.create(state.doc, pos));
630
+ view.dispatch(tr);
631
+ state = view.state;
632
+ }
633
+ const selection = state.selection;
634
+ let chain = editor.chain().focus();
635
+ if (selection instanceof NodeSelection) {
636
+ const firstChild = selection.node.firstChild?.firstChild;
637
+ const lastChild = selection.node.lastChild?.lastChild;
638
+ const from = firstChild ? selection.from + firstChild.nodeSize : selection.from + 1;
639
+ const to = lastChild ? selection.to - lastChild.nodeSize : selection.to - 1;
640
+ const resolvedFrom = state.doc.resolve(from);
641
+ const resolvedTo = state.doc.resolve(to);
642
+ chain = chain.setTextSelection(TextSelection.between(resolvedFrom, resolvedTo)).clearNodes();
643
+ }
644
+ (editor.isActive("codeBlock") ? chain.setNode("paragraph") : chain.toggleNode("codeBlock", "paragraph")).run();
645
+ editor.chain().focus().selectTextblockEnd().run();
646
+ return true;
647
+ } catch {
648
+ return false;
649
+ }
650
+ }
651
+ /**
652
+ * Determines if the code block button should be shown
653
+ */
654
+ function shouldShowButton$4(props) {
655
+ const { editor, hideWhenUnavailable } = props;
656
+ if (!editor) return false;
657
+ if (!hideWhenUnavailable) return true;
658
+ if (!editor.isEditable) return false;
659
+ if (!isNodeInSchema("codeBlock", editor)) return false;
660
+ if (!editor.isActive("code")) return canToggle$1(editor);
661
+ return true;
662
+ }
663
+ /**
664
+ * Custom hook that provides code block functionality for Tiptap editor
665
+ *
666
+ * @example
667
+ * ```tsx
668
+ * // Simple usage - no params needed
669
+ * function MySimpleCodeBlockButton() {
670
+ * const { isVisible, isActive, handleToggle } = useCodeBlock()
671
+ *
672
+ * if (!isVisible) return null
673
+ *
674
+ * return (
675
+ * <button
676
+ * onClick={handleToggle}
677
+ * aria-pressed={isActive}
678
+ * >
679
+ * Code Block
680
+ * </button>
681
+ * )
682
+ * }
683
+ *
684
+ * // Advanced usage with configuration
685
+ * function MyAdvancedCodeBlockButton() {
686
+ * const { isVisible, isActive, handleToggle, label } = useCodeBlock({
687
+ * editor: myEditor,
688
+ * hideWhenUnavailable: true,
689
+ * onToggled: (isActive) => console.log('Code block toggled:', isActive)
690
+ * })
691
+ *
692
+ * if (!isVisible) return null
693
+ *
694
+ * return (
695
+ * <MyButton
696
+ * onClick={handleToggle}
697
+ * aria-label={label}
698
+ * aria-pressed={isActive}
699
+ * >
700
+ * Toggle Code Block
701
+ * </MyButton>
702
+ * )
703
+ * }
704
+ * ```
705
+ */
706
+ function useCodeBlock(config) {
707
+ const { editor: providedEditor, hideWhenUnavailable = false, onToggled } = config || {};
708
+ const { editor } = useTiptapEditor(providedEditor);
709
+ const [isVisible, setIsVisible] = useState(true);
710
+ const canToggleState = canToggle$1(editor);
711
+ const isActive = editor?.isActive("codeBlock") || false;
712
+ useEffect(() => {
713
+ if (!editor) return;
714
+ const handleSelectionUpdate = () => {
715
+ setIsVisible(shouldShowButton$4({
716
+ editor,
717
+ hideWhenUnavailable
718
+ }));
719
+ };
720
+ handleSelectionUpdate();
721
+ editor.on("selectionUpdate", handleSelectionUpdate);
722
+ return () => {
723
+ editor.off("selectionUpdate", handleSelectionUpdate);
724
+ };
725
+ }, [editor, hideWhenUnavailable]);
726
+ return {
727
+ isVisible,
728
+ isActive,
729
+ handleToggle: useCallback(() => {
730
+ if (!editor) return false;
731
+ const success = toggleCodeBlock(editor);
732
+ if (success) onToggled?.();
733
+ return success;
734
+ }, [editor, onToggled]),
735
+ canToggle: canToggleState,
736
+ label: "Bloc de code",
737
+ shortcutKeys: CODE_BLOCK_SHORTCUT_KEY,
738
+ Icon: IntegrationInstructionIcon
739
+ };
740
+ }
741
+ //#endregion
742
+ //#region src/tiptap/components/ui/code-block-button/code-block-button.tsx
743
+ function CodeBlockShortcutBadge({ shortcutKeys = CODE_BLOCK_SHORTCUT_KEY }) {
744
+ return /* @__PURE__ */ jsx(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
745
+ }
746
+ /**
747
+ * Button component for toggling code block in a Tiptap editor.
748
+ *
749
+ * For custom button implementations, use the `useCodeBlock` hook instead.
750
+ */
751
+ var CodeBlockButton = forwardRef(({ editor: providedEditor, text, hideWhenUnavailable = false, onToggled, showShortcut = false, onClick, children, ...buttonProps }, ref) => {
752
+ const { editor } = useTiptapEditor(providedEditor);
753
+ const { isVisible, canToggle, isActive, handleToggle, label, shortcutKeys, Icon } = useCodeBlock({
754
+ editor,
755
+ hideWhenUnavailable,
756
+ onToggled
757
+ });
758
+ const handleClick = useCallback((event) => {
759
+ onClick?.(event, !isActive);
760
+ if (event.defaultPrevented) return;
761
+ handleToggle();
762
+ }, [handleToggle, onClick]);
763
+ if (!isVisible) return null;
764
+ return /* @__PURE__ */ jsx(Button, {
765
+ value: "codeBlock",
766
+ type: "button",
767
+ selected: isActive,
768
+ role: "button",
769
+ disabled: !canToggle,
770
+ "data-disabled": !canToggle,
771
+ tabIndex: -1,
772
+ "aria-label": label,
773
+ tooltip: label,
774
+ onClick: handleClick,
775
+ ...buttonProps,
776
+ ref,
777
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
778
+ /* @__PURE__ */ jsx(Icon, { fontSize: "small" }),
779
+ text && /* @__PURE__ */ jsx("span", {
780
+ className: "tiptap-button-text",
781
+ children: text
782
+ }),
783
+ showShortcut && /* @__PURE__ */ jsx(CodeBlockShortcutBadge, { shortcutKeys })
784
+ ] })
785
+ });
786
+ });
787
+ CodeBlockButton.displayName = "CodeBlockButton";
788
+ //#endregion
789
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/ExpandMoreRounded.mjs
790
+ var ExpandMoreRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M15.88 9.29 12 13.17 8.12 9.29a.996.996 0 0 0-1.41 0c-.39.39-.39 1.02 0 1.41l4.59 4.59c.39.39 1.02.39 1.41 0l4.59-4.59c.39-.39.39-1.02 0-1.41-.39-.38-1.03-.39-1.42 0" }), "ExpandMoreRounded");
791
+ //#endregion
792
+ //#region src/tiptap/components/icons/heading-five-icon.tsx
793
+ var HeadingFiveIcon = createSvgIcon(/* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("path", {
794
+ d: "M5 6C5 5.44772 4.55228 5 4 5C3.44772 5 3 5.44772 3 6V18C3 18.5523 3.44772 19 4 19C4.55228 19 5 18.5523 5 18V13H11V18C11 18.5523 11.4477 19 12 19C12.5523 19 13 18.5523 13 18V6C13 5.44772 12.5523 5 12 5C11.4477 5 11 5.44772 11 6V11H5V6Z",
795
+ fill: "currentColor"
796
+ }), /* @__PURE__ */ jsx("path", {
797
+ d: "M16 10C16 9.44772 16.4477 9 17 9H21C21.5523 9 22 9.44772 22 10C22 10.5523 21.5523 11 21 11H18V12H18.3C20.2754 12 22 13.4739 22 15.5C22 17.5261 20.2754 19 18.3 19C17.6457 19 17.0925 18.8643 16.5528 18.5944C16.0588 18.3474 15.8586 17.7468 16.1055 17.2528C16.3525 16.7588 16.9532 16.5586 17.4472 16.8056C17.7074 16.9357 17.9542 17 18.3 17C19.3246 17 20 16.2739 20 15.5C20 14.7261 19.3246 14 18.3 14H17C16.4477 14 16 13.5523 16 13L16 12.9928V10Z",
798
+ fill: "currentColor"
799
+ })] }), "HeadingFiveIcon");
800
+ //#endregion
801
+ //#region src/tiptap/components/icons/heading-four-icon.tsx
802
+ var HeadingFourIcon = createSvgIcon(/* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("path", {
803
+ d: "M4 5C4.55228 5 5 5.44772 5 6V11H11V6C11 5.44772 11.4477 5 12 5C12.5523 5 13 5.44772 13 6V18C13 18.5523 12.5523 19 12 19C11.4477 19 11 18.5523 11 18V13H5V18C5 18.5523 4.55228 19 4 19C3.44772 19 3 18.5523 3 18V6C3 5.44772 3.44772 5 4 5Z",
804
+ fill: "currentColor"
805
+ }), /* @__PURE__ */ jsx("path", {
806
+ d: "M17 9C17.5523 9 18 9.44772 18 10V13H20V10C20 9.44772 20.4477 9 21 9C21.5523 9 22 9.44772 22 10V18C22 18.5523 21.5523 19 21 19C20.4477 19 20 18.5523 20 18V15H17C16.4477 15 16 14.5523 16 14V10C16 9.44772 16.4477 9 17 9Z",
807
+ fill: "currentColor"
808
+ })] }), "HeadingFour");
809
+ //#endregion
810
+ //#region src/tiptap/components/icons/heading-one-icon.tsx
811
+ var HeadingOneIcon = createSvgIcon(/* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("path", {
812
+ d: "M5 6C5 5.44772 4.55228 5 4 5C3.44772 5 3 5.44772 3 6V18C3 18.5523 3.44772 19 4 19C4.55228 19 5 18.5523 5 18V13H11V18C11 18.5523 11.4477 19 12 19C12.5523 19 13 18.5523 13 18V6C13 5.44772 12.5523 5 12 5C11.4477 5 11 5.44772 11 6V11H5V6Z",
813
+ fill: "currentColor"
814
+ }), /* @__PURE__ */ jsx("path", {
815
+ d: "M21.0001 10C21.0001 9.63121 20.7971 9.29235 20.472 9.11833C20.1468 8.94431 19.7523 8.96338 19.4454 9.16795L16.4454 11.168C15.9859 11.4743 15.8617 12.0952 16.1681 12.5547C16.4744 13.0142 17.0953 13.1384 17.5548 12.8321L19.0001 11.8685V18C19.0001 18.5523 19.4478 19 20.0001 19C20.5524 19 21.0001 18.5523 21.0001 18V10Z",
816
+ fill: "currentColor"
817
+ })] }), "HeadingOne");
818
+ //#endregion
819
+ //#region src/tiptap/components/icons/heading-six-icon.tsx
820
+ var HeadingSixIcon = createSvgIcon(/* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("path", {
821
+ d: "M5 6C5 5.44772 4.55228 5 4 5C3.44772 5 3 5.44772 3 6V18C3 18.5523 3.44772 19 4 19C4.55228 19 5 18.5523 5 18V13H11V18C11 18.5523 11.4477 19 12 19C12.5523 19 13 18.5523 13 18V6C13 5.44772 12.5523 5 12 5C11.4477 5 11 5.44772 11 6V11H5V6Z",
822
+ fill: "currentColor"
823
+ }), /* @__PURE__ */ jsx("path", {
824
+ fillRule: "evenodd",
825
+ clipRule: "evenodd",
826
+ d: "M20.7071 9.29289C21.0976 9.68342 21.0976 10.3166 20.7071 10.7071C19.8392 11.575 19.2179 12.2949 18.7889 13.0073C18.8587 13.0025 18.929 13 19 13C20.6569 13 22 14.3431 22 16C22 17.6569 20.6569 19 19 19C17.3431 19 16 17.6569 16 16C16 14.6007 16.2837 13.4368 16.8676 12.3419C17.4384 11.2717 18.2728 10.3129 19.2929 9.29289C19.6834 8.90237 20.3166 8.90237 20.7071 9.29289ZM19 17C18.4477 17 18 16.5523 18 16C18 15.4477 18.4477 15 19 15C19.5523 15 20 15.4477 20 16C20 16.5523 19.5523 17 19 17Z",
827
+ fill: "currentColor"
828
+ })] }), "HeadingSix");
829
+ //#endregion
830
+ //#region src/tiptap/components/icons/heading-three-icon.tsx
831
+ var HeadingThreeIcon = createSvgIcon(/* @__PURE__ */ jsxs("g", { children: [
832
+ /* @__PURE__ */ jsx("path", {
833
+ d: "M4 5C4.55228 5 5 5.44772 5 6V11H11V6C11 5.44772 11.4477 5 12 5C12.5523 5 13 5.44772 13 6V18C13 18.5523 12.5523 19 12 19C11.4477 19 11 18.5523 11 18V13H5V18C5 18.5523 4.55228 19 4 19C3.44772 19 3 18.5523 3 18V6C3 5.44772 3.44772 5 4 5Z",
834
+ fill: "currentColor"
835
+ }),
836
+ /* @__PURE__ */ jsx("path", {
837
+ fillRule: "evenodd",
838
+ clipRule: "evenodd",
839
+ d: "M19.4608 11.2169C19.1135 11.0531 18.5876 11.0204 18.0069 11.3619C17.5309 11.642 16.918 11.4831 16.638 11.007C16.358 10.531 16.5169 9.91809 16.9929 9.63807C18.1123 8.97962 19.3364 8.94691 20.314 9.40808C21.2839 9.86558 21.9999 10.818 21.9999 12C21.9999 12.7957 21.6838 13.5587 21.1212 14.1213C20.5586 14.6839 19.7956 15 18.9999 15C18.4476 15 17.9999 14.5523 17.9999 14C17.9999 13.4477 18.4476 13 18.9999 13C19.2651 13 19.5195 12.8947 19.707 12.7071C19.8946 12.5196 19.9999 12.2652 19.9999 12C19.9999 11.6821 19.8159 11.3844 19.4608 11.2169Z",
840
+ fill: "currentColor"
841
+ }),
842
+ /* @__PURE__ */ jsx("path", {
843
+ fillRule: "evenodd",
844
+ clipRule: "evenodd",
845
+ d: "M18.0001 14C18.0001 13.4477 18.4478 13 19.0001 13C19.7957 13 20.5588 13.3161 21.1214 13.8787C21.684 14.4413 22.0001 15.2043 22.0001 16C22.0001 17.2853 21.2767 18.3971 20.1604 18.8994C19.0257 19.41 17.642 19.2315 16.4001 18.3C15.9582 17.9686 15.8687 17.3418 16.2001 16.9C16.5314 16.4582 17.1582 16.3686 17.6001 16.7C18.3581 17.2685 18.9744 17.24 19.3397 17.0756C19.7234 16.9029 20.0001 16.5147 20.0001 16C20.0001 15.7348 19.8947 15.4804 19.7072 15.2929C19.5196 15.1054 19.2653 15 19.0001 15C18.4478 15 18.0001 14.5523 18.0001 14Z",
846
+ fill: "currentColor"
847
+ })
848
+ ] }), "HeadingThree");
849
+ //#endregion
850
+ //#region src/tiptap/components/ui/heading-menu-item/use-heading.ts
851
+ var headingIcons = {
852
+ 1: HeadingOneIcon,
853
+ 2: createSvgIcon(/* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("path", {
854
+ d: "M5 6C5 5.44772 4.55228 5 4 5C3.44772 5 3 5.44772 3 6V18C3 18.5523 3.44772 19 4 19C4.55228 19 5 18.5523 5 18V13H11V18C11 18.5523 11.4477 19 12 19C12.5523 19 13 18.5523 13 18V6C13 5.44772 12.5523 5 12 5C11.4477 5 11 5.44772 11 6V11H5V6Z",
855
+ fill: "currentColor"
856
+ }), /* @__PURE__ */ jsx("path", {
857
+ d: "M22.0001 12C22.0001 10.7611 21.1663 9.79297 20.0663 9.42632C18.9547 9.05578 17.6171 9.28724 16.4001 10.2C15.9582 10.5314 15.8687 11.1582 16.2001 11.6C16.5314 12.0418 17.1582 12.1314 17.6001 11.8C18.383 11.2128 19.0455 11.1942 19.4338 11.3237C19.8339 11.457 20.0001 11.7389 20.0001 12C20.0001 12.4839 19.8554 12.7379 19.6537 12.9481C19.4275 13.1837 19.1378 13.363 18.7055 13.6307C18.6313 13.6767 18.553 13.7252 18.4701 13.777C17.9572 14.0975 17.3128 14.5261 16.8163 15.2087C16.3007 15.9177 16.0001 16.8183 16.0001 18C16.0001 18.5523 16.4478 19 17.0001 19H21.0001C21.5523 19 22.0001 18.5523 22.0001 18C22.0001 17.4477 21.5523 17 21.0001 17H18.131C18.21 16.742 18.3176 16.5448 18.4338 16.385C18.6873 16.0364 19.0429 15.7775 19.5301 15.473C19.5898 15.4357 19.6536 15.3966 19.7205 15.3556C20.139 15.0992 20.6783 14.7687 21.0964 14.3332C21.6447 13.7621 22.0001 13.0161 22.0001 12Z",
858
+ fill: "currentColor"
859
+ })] }), "HeadingTwo"),
860
+ 3: HeadingThreeIcon,
861
+ 4: HeadingFourIcon,
862
+ 5: HeadingFiveIcon,
863
+ 6: HeadingSixIcon
864
+ };
865
+ var HEADING_SHORTCUT_KEYS = {
866
+ 1: "ctrl+alt+1",
867
+ 2: "ctrl+alt+2",
868
+ 3: "ctrl+alt+3",
869
+ 4: "ctrl+alt+4",
870
+ 5: "ctrl+alt+5",
871
+ 6: "ctrl+alt+6"
872
+ };
873
+ /**
874
+ * Checks if heading can be toggled in the current editor state
875
+ */
876
+ function canToggle(editor, level, turnInto = true) {
877
+ if (!editor || !editor.isEditable) return false;
878
+ if (!isNodeInSchema("heading", editor) || isNodeTypeSelected(editor, ["image"])) return false;
879
+ if (!turnInto) return level ? editor.can().setNode("heading", { level }) : editor.can().setNode("heading");
880
+ if (!selectionWithinConvertibleTypes(editor, [
881
+ "paragraph",
882
+ "heading",
883
+ "bulletList",
884
+ "orderedList",
885
+ "taskList",
886
+ "blockquote",
887
+ "codeBlock"
888
+ ])) return false;
889
+ return level ? editor.can().setNode("heading", { level }) || editor.can().clearNodes() : editor.can().setNode("heading") || editor.can().clearNodes();
890
+ }
891
+ /**
892
+ * Checks if heading is currently active
893
+ */
894
+ function isHeadingActive(editor, level) {
895
+ if (!editor || !editor.isEditable) return false;
896
+ if (Array.isArray(level)) return level.some((l) => editor.isActive("heading", { level: l }));
897
+ return level ? editor.isActive("heading", { level }) : editor.isActive("heading");
898
+ }
899
+ /**
900
+ * Toggles heading in the editor
901
+ */
902
+ function toggleHeading(editor, level) {
903
+ if (!editor || !editor.isEditable) return false;
904
+ const levels = Array.isArray(level) ? level : [level];
905
+ const toggleLevel = levels.find((l) => canToggle(editor, l));
906
+ if (!toggleLevel) return false;
907
+ try {
908
+ const view = editor.view;
909
+ let state = view.state;
910
+ let tr = state.tr;
911
+ const blocks = getSelectedBlockNodes(editor);
912
+ const isPossibleToTurnInto = selectionWithinConvertibleTypes(editor, [
913
+ "paragraph",
914
+ "heading",
915
+ "bulletList",
916
+ "orderedList",
917
+ "taskList",
918
+ "blockquote",
919
+ "codeBlock"
920
+ ]) && blocks.length === 1;
921
+ if ((state.selection.empty || state.selection instanceof TextSelection) && isPossibleToTurnInto) {
922
+ const pos = findNodePosition({
923
+ editor,
924
+ node: state.selection.$anchor.node(1)
925
+ })?.pos;
926
+ if (!isValidPosition(pos)) return false;
927
+ tr = tr.setSelection(NodeSelection.create(state.doc, pos));
928
+ view.dispatch(tr);
929
+ state = view.state;
930
+ }
931
+ const selection = state.selection;
932
+ let chain = editor.chain().focus();
933
+ if (selection instanceof NodeSelection) {
934
+ const firstChild = selection.node.firstChild?.firstChild;
935
+ const lastChild = selection.node.lastChild?.lastChild;
936
+ const from = firstChild ? selection.from + firstChild.nodeSize : selection.from + 1;
937
+ const to = lastChild ? selection.to - lastChild.nodeSize : selection.to - 1;
938
+ const resolvedFrom = state.doc.resolve(from);
939
+ const resolvedTo = state.doc.resolve(to);
940
+ chain = chain.setTextSelection(TextSelection.between(resolvedFrom, resolvedTo)).clearNodes();
941
+ }
942
+ (levels.some((l) => editor.isActive("heading", { level: l })) ? chain.setNode("paragraph") : chain.setNode("heading", { level: toggleLevel })).run();
943
+ editor.chain().focus().selectTextblockEnd().run();
944
+ return true;
945
+ } catch {
946
+ return false;
947
+ }
948
+ }
949
+ /**
950
+ * Determines if the heading menu item should be shown
951
+ */
952
+ function shouldShowItem(props) {
953
+ const { editor, level, hideWhenUnavailable } = props;
954
+ if (!editor) return false;
955
+ if (!hideWhenUnavailable) return true;
956
+ if (!editor.isEditable) return false;
957
+ if (!isNodeInSchema("heading", editor)) return false;
958
+ if (!editor.isActive("code")) {
959
+ if (Array.isArray(level)) return level.some((l) => canToggle(editor, l));
960
+ return canToggle(editor, level);
961
+ }
962
+ return true;
963
+ }
964
+ /**
965
+ * Custom hook that provides heading functionality for Tiptap editor
966
+ *
967
+ * @example
968
+ * ```tsx
969
+ * // Simple usage
970
+ * function MySimpleHeadingItem() {
971
+ * const { isVisible, isActive, handleToggle, Icon } = useHeading({ level: 1 })
972
+ *
973
+ * if (!isVisible) return null
974
+ *
975
+ * return (
976
+ * <button
977
+ * onClick={handleToggle}
978
+ * aria-pressed={isActive}
979
+ * >
980
+ * <Icon />
981
+ * Heading 1
982
+ * </button>
983
+ * )
984
+ * }
985
+ *
986
+ * // Advanced usage with configuration
987
+ * function MyAdvancedHeadingItem() {
988
+ * const { isVisible, isActive, handleToggle, label, Icon } = useHeading({
989
+ * level: 2,
990
+ * editor: myEditor,
991
+ * hideWhenUnavailable: true,
992
+ * onToggled: (isActive) => console.log('Heading toggled:', isActive)
993
+ * })
994
+ *
995
+ * if (!isVisible) return null
996
+ *
997
+ * return (
998
+ * <MyButton
999
+ * onClick={handleToggle}
1000
+ * aria-label={label}
1001
+ * aria-pressed={isActive}
1002
+ * >
1003
+ * <Icon />
1004
+ * Toggle Heading 2
1005
+ * </MyButton>
1006
+ * )
1007
+ * }
1008
+ * ```
1009
+ */
1010
+ function useHeading(config) {
1011
+ const { editor: providedEditor, level, hideWhenUnavailable = false, onToggled } = config;
1012
+ const { editor } = useTiptapEditor(providedEditor);
1013
+ const [isVisible, setIsVisible] = useState(true);
1014
+ const canToggleState = canToggle(editor, level);
1015
+ const isActive = isHeadingActive(editor, level);
1016
+ useEffect(() => {
1017
+ if (!editor) return;
1018
+ const handleSelectionUpdate = () => {
1019
+ setIsVisible(shouldShowItem({
1020
+ editor,
1021
+ level,
1022
+ hideWhenUnavailable
1023
+ }));
1024
+ };
1025
+ handleSelectionUpdate();
1026
+ editor.on("selectionUpdate", handleSelectionUpdate);
1027
+ return () => {
1028
+ editor.off("selectionUpdate", handleSelectionUpdate);
1029
+ };
1030
+ }, [
1031
+ editor,
1032
+ level,
1033
+ hideWhenUnavailable
1034
+ ]);
1035
+ return {
1036
+ isVisible,
1037
+ isActive,
1038
+ handleToggle: useCallback(() => {
1039
+ if (!editor) return false;
1040
+ const success = toggleHeading(editor, level);
1041
+ if (success) onToggled?.();
1042
+ return success;
1043
+ }, [
1044
+ editor,
1045
+ level,
1046
+ onToggled
1047
+ ]),
1048
+ canToggle: canToggleState,
1049
+ label: `Titre ${level}`,
1050
+ shortcutKeys: HEADING_SHORTCUT_KEYS[level],
1051
+ Icon: headingIcons[level]
1052
+ };
1053
+ }
1054
+ //#endregion
1055
+ //#region src/tiptap/components/ui/heading-menu-item/heading-menu-item.tsx
1056
+ function HeadingShortcutBadge({ level, shortcutKeys = HEADING_SHORTCUT_KEYS[level] }) {
1057
+ return /* @__PURE__ */ jsx(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
1058
+ }
1059
+ /**
1060
+ * Menu item component for toggling heading in a Tiptap editor.
1061
+ *
1062
+ * For custom menu item implementations, use the `useHeading` hook instead.
1063
+ */
1064
+ var HeadingMenuItem = forwardRef(({ editor: providedEditor, level, text, hideWhenUnavailable = false, onToggled, showShortcut = false, onClick, children, ...menuItemProps }, ref) => {
1065
+ const { editor } = useTiptapEditor(providedEditor);
1066
+ const { isVisible, canToggle, isActive, handleToggle, label, Icon, shortcutKeys } = useHeading({
1067
+ editor,
1068
+ level,
1069
+ hideWhenUnavailable,
1070
+ onToggled
1071
+ });
1072
+ const handleClick = useCallback((event) => {
1073
+ onClick?.(event);
1074
+ if (event.defaultPrevented) return;
1075
+ handleToggle();
1076
+ }, [handleToggle, onClick]);
1077
+ if (!isVisible) return null;
1078
+ return /* @__PURE__ */ jsx(MenuItem, {
1079
+ component: "li",
1080
+ role: "button",
1081
+ tabIndex: -1,
1082
+ disabled: !canToggle,
1083
+ "data-disabled": !canToggle,
1084
+ "aria-label": label,
1085
+ "aria-pressed": isActive,
1086
+ tooltip: label,
1087
+ selected: isActive,
1088
+ onClick: handleClick,
1089
+ ...menuItemProps,
1090
+ ref,
1091
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
1092
+ /* @__PURE__ */ jsx(Icon, { fontSize: "small" }),
1093
+ text && /* @__PURE__ */ jsx(Typography, {
1094
+ component: "span",
1095
+ variant: "body2",
1096
+ sx: { ml: 1 },
1097
+ children: label
1098
+ }),
1099
+ showShortcut && /* @__PURE__ */ jsx(HeadingShortcutBadge, {
1100
+ level,
1101
+ shortcutKeys
1102
+ })
1103
+ ] })
1104
+ });
1105
+ });
1106
+ HeadingMenuItem.displayName = "HeadingMenuItem";
1107
+ //#endregion
1108
+ //#region src/tiptap/components/icons/heading-icon.tsx
1109
+ var HeadingIcon = createSvgIcon(/* @__PURE__ */ jsx("path", {
1110
+ d: "M6 3C6.55228 3 7 3.44772 7 4V11H17V4C17 3.44772 17.4477 3 18 3C18.5523 3 19 3.44772 19 4V20C19 20.5523 18.5523 21 18 21C17.4477 21 17 20.5523 17 20V13H7V20C7 20.5523 6.55228 21 6 21C5.44772 21 5 20.5523 5 20V4C5 3.44772 5.44772 3 6 3Z",
1111
+ fill: "currentColor"
1112
+ }), "Heading");
1113
+ //#endregion
1114
+ //#region src/tiptap/components/ui/heading-menu/use-heading-menu.ts
1115
+ /**
1116
+ * Gets the currently active heading level from the available levels
1117
+ */
1118
+ function getActiveHeadingLevel(editor, levels = [
1119
+ 1,
1120
+ 2,
1121
+ 3,
1122
+ 4,
1123
+ 5,
1124
+ 6
1125
+ ]) {
1126
+ if (!editor || !editor.isEditable) return void 0;
1127
+ return levels.find((level) => isHeadingActive(editor, level));
1128
+ }
1129
+ /**
1130
+ * Custom hook that provides heading menu functionality for Tiptap editor
1131
+ *
1132
+ * @example
1133
+ * ```tsx
1134
+ * // Simple usage
1135
+ * function MyHeading() {
1136
+ * const {
1137
+ * isVisible,
1138
+ * activeLevel,
1139
+ * isAnyHeadingActive,
1140
+ * canToggle,
1141
+ * levels,
1142
+ * } = useHeadingMenu()
1143
+ *
1144
+ * if (!isVisible) return null
1145
+ *
1146
+ * return (
1147
+ * <Menu>
1148
+ * // content
1149
+ * </Menu>
1150
+ * )
1151
+ * }
1152
+ *
1153
+ * // Advanced usage with configuration
1154
+ * function MyAdvancedHeading() {
1155
+ * const {
1156
+ * isVisible,
1157
+ * activeLevel,
1158
+ * } = useHeadingMenu({
1159
+ * editor: myEditor,
1160
+ * levels: [1, 2, 3],
1161
+ * hideWhenUnavailable: true,
1162
+ * })
1163
+ *
1164
+ * // component implementation
1165
+ * }
1166
+ * ```
1167
+ */
1168
+ function useHeadingMenu(config) {
1169
+ const { editor: providedEditor, levels = [
1170
+ 1,
1171
+ 2,
1172
+ 3,
1173
+ 4,
1174
+ 5,
1175
+ 6
1176
+ ], hideWhenUnavailable = false } = config || {};
1177
+ const { editor } = useTiptapEditor(providedEditor);
1178
+ const [isVisible, setIsVisible] = useState(true);
1179
+ const activeLevel = getActiveHeadingLevel(editor, levels);
1180
+ const isActive = isHeadingActive(editor);
1181
+ const canToggleState = canToggle(editor);
1182
+ useEffect(() => {
1183
+ if (!editor) return;
1184
+ const handleSelectionUpdate = () => {
1185
+ setIsVisible(shouldShowItem({
1186
+ editor,
1187
+ hideWhenUnavailable,
1188
+ level: levels
1189
+ }));
1190
+ };
1191
+ handleSelectionUpdate();
1192
+ editor.on("selectionUpdate", handleSelectionUpdate);
1193
+ return () => {
1194
+ editor.off("selectionUpdate", handleSelectionUpdate);
1195
+ };
1196
+ }, [
1197
+ editor,
1198
+ hideWhenUnavailable,
1199
+ levels
1200
+ ]);
1201
+ return {
1202
+ isVisible,
1203
+ activeLevel,
1204
+ isActive,
1205
+ canToggle: canToggleState,
1206
+ levels,
1207
+ label: "Titre",
1208
+ Icon: activeLevel ? headingIcons[activeLevel] : HeadingIcon
1209
+ };
1210
+ }
1211
+ //#endregion
1212
+ //#region src/tiptap/components/ui/heading-menu/heading-menu.tsx
1213
+ /**
1214
+ * Menu component for selecting heading levels in a Tiptap editor.
1215
+ *
1216
+ * For custom menu implementations, use the `useHeadingMenu` hook instead.
1217
+ */
1218
+ var HeadingMenu = forwardRef(({ editor: providedEditor, levels = [
1219
+ 1,
1220
+ 2,
1221
+ 3,
1222
+ 4,
1223
+ 5,
1224
+ 6
1225
+ ], hideWhenUnavailable = false, onOpenChange, children, modal = true, ...buttonProps }, ref) => {
1226
+ const { editor } = useTiptapEditor(providedEditor);
1227
+ const [anchorEl, setAnchorEl] = useState(null);
1228
+ const open = Boolean(anchorEl);
1229
+ const { isVisible, isActive, canToggle, Icon, label } = useHeadingMenu({
1230
+ editor,
1231
+ levels,
1232
+ hideWhenUnavailable
1233
+ });
1234
+ const handleClick = (event) => {
1235
+ setAnchorEl(event.currentTarget);
1236
+ };
1237
+ const handleClose = useCallback(() => {
1238
+ if (!editor || !canToggle) return;
1239
+ setAnchorEl(null);
1240
+ onOpenChange?.(false);
1241
+ }, [
1242
+ canToggle,
1243
+ editor,
1244
+ onOpenChange
1245
+ ]);
1246
+ if (!isVisible) return null;
1247
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Button, {
1248
+ id: "heading-button",
1249
+ value: "heading",
1250
+ type: "button",
1251
+ selected: isActive || open,
1252
+ role: "button",
1253
+ tabIndex: -1,
1254
+ disabled: !canToggle,
1255
+ "data-disabled": !canToggle,
1256
+ "aria-haspopup": "listbox",
1257
+ "aria-controls": "heading-menu",
1258
+ "aria-label": "Format text as heading",
1259
+ "aria-expanded": open,
1260
+ tooltip: label,
1261
+ onClick: handleClick,
1262
+ ...buttonProps,
1263
+ ref,
1264
+ children: children ? children : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Icon, { fontSize: "small" }), /* @__PURE__ */ jsx(ExpandMoreRounded_default, { sx: { fontSize: "0.75rem" } })] })
1265
+ }), /* @__PURE__ */ jsx(Menu, {
1266
+ id: "heading-menu",
1267
+ anchorEl,
1268
+ open,
1269
+ onClose: handleClose,
1270
+ slotProps: { list: {
1271
+ "aria-labelledby": "heading-button",
1272
+ role: "listbox"
1273
+ } },
1274
+ children: levels.map((level) => /* @__PURE__ */ jsx(HeadingMenuItem, {
1275
+ editor,
1276
+ level,
1277
+ text: `Heading ${level}`,
1278
+ onClick: handleClose
1279
+ }, `heading-${level}`))
1280
+ })] });
1281
+ });
1282
+ HeadingMenu.displayName = "HeadingMenu";
1283
+ //#endregion
1284
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/KeyboardReturnRounded.mjs
1285
+ var KeyboardReturnRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M19 8v3H5.83l2.88-2.88c.39-.39.39-1.02 0-1.41a.996.996 0 0 0-1.41 0L2.71 11.3c-.39.39-.39 1.02 0 1.41L7.3 17.3c.39.39 1.02.39 1.41 0s.39-1.02 0-1.41L5.83 13H20c.55 0 1-.45 1-1V8c0-.55-.45-1-1-1s-1 .45-1 1" }), "KeyboardReturnRounded");
1286
+ //#endregion
1287
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/LinkRounded.mjs
1288
+ var LinkRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M17 7h-3c-.55 0-1 .45-1 1s.45 1 1 1h3c1.65 0 3 1.35 3 3s-1.35 3-3 3h-3c-.55 0-1 .45-1 1s.45 1 1 1h3c2.76 0 5-2.24 5-5s-2.24-5-5-5m-9 5c0 .55.45 1 1 1h6c.55 0 1-.45 1-1s-.45-1-1-1H9c-.55 0-1 .45-1 1m2 3H7c-1.65 0-3-1.35-3-3s1.35-3 3-3h3c.55 0 1-.45 1-1s-.45-1-1-1H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h3c.55 0 1-.45 1-1s-.45-1-1-1" }), "LinkRounded");
1289
+ //#endregion
1290
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/OpenInNewRounded.mjs
1291
+ var OpenInNewRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M18 19H6c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h5c.55 0 1-.45 1-1s-.45-1-1-1H5c-1.11 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-6c0-.55-.45-1-1-1s-1 .45-1 1v5c0 .55-.45 1-1 1M14 4c0 .55.45 1 1 1h2.59l-9.13 9.13c-.39.39-.39 1.02 0 1.41s1.02.39 1.41 0L19 6.41V9c0 .55.45 1 1 1s1-.45 1-1V4c0-.55-.45-1-1-1h-5c-.55 0-1 .45-1 1" }), "OpenInNewRounded");
1292
+ //#endregion
1293
+ //#region src/tiptap/components/ui/link-popover/use-link-popover.ts
1294
+ /**
1295
+ * Checks if a link can be set in the current editor state
1296
+ */
1297
+ function canSetLink(editor) {
1298
+ if (!editor || !editor.isEditable) return false;
1299
+ if (isNodeTypeSelected(editor, ["image"], true)) return false;
1300
+ try {
1301
+ return editor.can().setMark("link");
1302
+ } catch {
1303
+ return false;
1304
+ }
1305
+ }
1306
+ /**
1307
+ * Checks if a link is currently active in the editor
1308
+ */
1309
+ function isLinkActive(editor) {
1310
+ if (!editor || !editor.isEditable) return false;
1311
+ return editor.isActive("link");
1312
+ }
1313
+ /**
1314
+ * Determines if the link button should be shown
1315
+ */
1316
+ function shouldShowLinkButton(props) {
1317
+ const { editor, hideWhenUnavailable } = props;
1318
+ if (!editor || !editor.isEditable) return false;
1319
+ const linkInSchema = isMarkInSchema("link", editor);
1320
+ if (!hideWhenUnavailable) return true;
1321
+ if (!linkInSchema) return false;
1322
+ if (!editor.isActive("code")) return canSetLink(editor);
1323
+ return true;
1324
+ }
1325
+ /**
1326
+ * Custom hook for handling link operations in a Tiptap editor
1327
+ */
1328
+ function useLinkHandler(props) {
1329
+ const { editor, onSetLink } = props;
1330
+ const [url, setUrl] = useState(null);
1331
+ useEffect(() => {
1332
+ if (!editor) return;
1333
+ const { href } = editor.getAttributes("link");
1334
+ if (isLinkActive(editor) && url === null) setUrl(href || "");
1335
+ }, [editor, url]);
1336
+ useEffect(() => {
1337
+ if (!editor) return;
1338
+ const updateLinkState = () => {
1339
+ const { href } = editor.getAttributes("link");
1340
+ setUrl(href || "");
1341
+ };
1342
+ editor.on("selectionUpdate", updateLinkState);
1343
+ return () => {
1344
+ editor.off("selectionUpdate", updateLinkState);
1345
+ };
1346
+ }, [editor]);
1347
+ const setLink = useCallback(() => {
1348
+ if (!url || !editor) return;
1349
+ const { selection } = editor.state;
1350
+ const isEmpty = selection.empty;
1351
+ let chain = editor.chain().focus();
1352
+ chain = chain.extendMarkRange("link").setLink({ href: url });
1353
+ if (isEmpty) chain = chain.insertContent({
1354
+ type: "text",
1355
+ text: url
1356
+ });
1357
+ chain.run();
1358
+ setUrl(null);
1359
+ onSetLink?.();
1360
+ }, [
1361
+ editor,
1362
+ onSetLink,
1363
+ url
1364
+ ]);
1365
+ const removeLink = useCallback(() => {
1366
+ if (!editor) return;
1367
+ editor.chain().focus().extendMarkRange("link").unsetLink().setMeta("preventAutolink", true).run();
1368
+ setUrl("");
1369
+ }, [editor]);
1370
+ const openLink = useCallback((target = "_blank", features = "noopener,noreferrer") => {
1371
+ if (!url) return;
1372
+ const safeUrl = sanitizeUrl(url, window.location.href);
1373
+ if (safeUrl !== "#") window.open(safeUrl, target, features);
1374
+ }, [url]);
1375
+ return {
1376
+ url: url || "",
1377
+ setUrl,
1378
+ setLink,
1379
+ removeLink,
1380
+ openLink
1381
+ };
1382
+ }
1383
+ /**
1384
+ * Custom hook for link popover state management
1385
+ */
1386
+ function useLinkState(props) {
1387
+ const { editor, hideWhenUnavailable = false } = props;
1388
+ const canSet = canSetLink(editor);
1389
+ const isActive = isLinkActive(editor);
1390
+ const [isVisible, setIsVisible] = useState(true);
1391
+ useEffect(() => {
1392
+ if (!editor) return;
1393
+ const handleSelectionUpdate = () => {
1394
+ setIsVisible(shouldShowLinkButton({
1395
+ editor,
1396
+ hideWhenUnavailable
1397
+ }));
1398
+ };
1399
+ handleSelectionUpdate();
1400
+ editor.on("selectionUpdate", handleSelectionUpdate);
1401
+ return () => {
1402
+ editor.off("selectionUpdate", handleSelectionUpdate);
1403
+ };
1404
+ }, [editor, hideWhenUnavailable]);
1405
+ return {
1406
+ isVisible,
1407
+ canSet,
1408
+ isActive
1409
+ };
1410
+ }
1411
+ /**
1412
+ * Main hook that provides link popover functionality for Tiptap editor
1413
+ *
1414
+ * @example
1415
+ * ```tsx
1416
+ * // Simple usage
1417
+ * function MyLinkButton() {
1418
+ * const { isVisible, canSet, isActive, Icon, label } = useLinkPopover()
1419
+ *
1420
+ * if (!isVisible) return null
1421
+ *
1422
+ * return <button disabled={!canSet}>Link</button>
1423
+ * }
1424
+ *
1425
+ * // Advanced usage with configuration
1426
+ * function MyAdvancedLinkButton() {
1427
+ * const { isVisible, canSet, isActive, Icon, label } = useLinkPopover({
1428
+ * editor: myEditor,
1429
+ * hideWhenUnavailable: true,
1430
+ * onSetLink: () => console.log('Link set!')
1431
+ * })
1432
+ *
1433
+ * if (!isVisible) return null
1434
+ *
1435
+ * return (
1436
+ * <MyButton
1437
+ * disabled={!canSet}
1438
+ * aria-label={label}
1439
+ * aria-pressed={isActive}
1440
+ * >
1441
+ * <Icon />
1442
+ * {label}
1443
+ * </MyButton>
1444
+ * )
1445
+ * }
1446
+ * ```
1447
+ */
1448
+ function useLinkPopover(config) {
1449
+ const { editor: providedEditor, hideWhenUnavailable = false, onSetLink } = config || {};
1450
+ const { editor } = useTiptapEditor(providedEditor);
1451
+ const { isVisible, canSet, isActive } = useLinkState({
1452
+ editor,
1453
+ hideWhenUnavailable
1454
+ });
1455
+ return {
1456
+ isVisible,
1457
+ canSet,
1458
+ isActive,
1459
+ label: "Lien",
1460
+ Icon: LinkRounded_default,
1461
+ ...useLinkHandler({
1462
+ editor,
1463
+ onSetLink
1464
+ })
1465
+ };
1466
+ }
1467
+ //#endregion
1468
+ //#region src/tiptap/components/ui/link-popover/link-popover.tsx
1469
+ /**
1470
+ * Link button component for triggering the link popover
1471
+ */
1472
+ var LinkButton = forwardRef(({ className, children, ...props }, ref) => {
1473
+ return /* @__PURE__ */ jsx(Button, {
1474
+ type: "button",
1475
+ className,
1476
+ role: "button",
1477
+ tabIndex: -1,
1478
+ ref,
1479
+ ...props,
1480
+ children: children || /* @__PURE__ */ jsx(LinkRounded_default, { fontSize: "small" })
1481
+ });
1482
+ });
1483
+ LinkButton.displayName = "LinkButton";
1484
+ var StyledIconButton = styled(IconButton)(({ theme }) => ({
1485
+ borderRadius: theme.shape.borderRadius,
1486
+ "& .MuiTouchRipple-root .MuiTouchRipple-child": { borderRadius: theme.shape.borderRadius }
1487
+ }));
1488
+ /**
1489
+ * Main content component for the link popover
1490
+ */
1491
+ var LinkMain = ({ url, setUrl, setLink, removeLink, openLink, isActive }) => {
1492
+ const handleKeyDown = (event) => {
1493
+ if (event.key === "Enter") {
1494
+ event.preventDefault();
1495
+ setLink();
1496
+ }
1497
+ };
1498
+ return /* @__PURE__ */ jsxs(Stack, {
1499
+ direction: "row",
1500
+ spacing: .5,
1501
+ sx: {
1502
+ alignItems: "center",
1503
+ p: 1
1504
+ },
1505
+ children: [
1506
+ /* @__PURE__ */ jsx(InputBase, {
1507
+ type: "url",
1508
+ placeholder: "Coller un lien...",
1509
+ value: url,
1510
+ onChange: (e) => setUrl(e.target.value),
1511
+ onKeyDown: handleKeyDown,
1512
+ autoFocus: true,
1513
+ autoComplete: "off",
1514
+ autoCorrect: "off",
1515
+ autoCapitalize: "off",
1516
+ sx: {
1517
+ padding: ".25rem .625rem",
1518
+ fontSize: "0.875rem",
1519
+ minWidth: "12rem"
1520
+ }
1521
+ }),
1522
+ /* @__PURE__ */ jsx(StyledIconButton, {
1523
+ size: "small",
1524
+ type: "button",
1525
+ onClick: setLink,
1526
+ title: "Appliquer le lien",
1527
+ disabled: !url && !isActive,
1528
+ children: /* @__PURE__ */ jsx(KeyboardReturnRounded_default, { fontSize: "small" })
1529
+ }),
1530
+ /* @__PURE__ */ jsx(Divider, {
1531
+ orientation: "vertical",
1532
+ flexItem: true,
1533
+ sx: { my: .5 }
1534
+ }),
1535
+ /* @__PURE__ */ jsx(StyledIconButton, {
1536
+ size: "small",
1537
+ type: "button",
1538
+ onClick: openLink,
1539
+ title: "Ouvrir dans une nouvelle fenêtre",
1540
+ disabled: !url && !isActive,
1541
+ children: /* @__PURE__ */ jsx(OpenInNewRounded_default, { fontSize: "small" })
1542
+ }),
1543
+ /* @__PURE__ */ jsx(StyledIconButton, {
1544
+ size: "small",
1545
+ type: "button",
1546
+ onClick: removeLink,
1547
+ title: "Supprimer le lien",
1548
+ disabled: !url && !isActive,
1549
+ children: /* @__PURE__ */ jsx(DeleteRounded_default, { fontSize: "small" })
1550
+ })
1551
+ ]
1552
+ });
1553
+ };
1554
+ /**
1555
+ * Link popover component for Tiptap editors.
1556
+ *
1557
+ * For custom popover implementations, use the `useLinkPopover` hook instead.
1558
+ */
1559
+ var LinkPopover = forwardRef(({ editor: providedEditor, hideWhenUnavailable = false, onSetLink, onOpenChange, autoOpenOnLinkActive = true, onClick, children, ...buttonProps }, ref) => {
1560
+ const { editor } = useTiptapEditor(providedEditor);
1561
+ const [anchorEl, setAnchorEl] = useState(null);
1562
+ const internalRef = useRef(null);
1563
+ const justSubmittedRef = useRef(false);
1564
+ const { isVisible, canSet, isActive, url, setUrl, setLink, removeLink, openLink, label, Icon } = useLinkPopover({
1565
+ editor,
1566
+ hideWhenUnavailable,
1567
+ onSetLink
1568
+ });
1569
+ const setRefs = useCallback((node) => {
1570
+ internalRef.current = node;
1571
+ if (typeof ref === "function") ref(node);
1572
+ else if (ref) ref.current = node;
1573
+ }, [ref]);
1574
+ const handleClose = useCallback(() => {
1575
+ setAnchorEl(null);
1576
+ onOpenChange?.(false);
1577
+ }, [onOpenChange]);
1578
+ const handleSetLink = useCallback(() => {
1579
+ justSubmittedRef.current = true;
1580
+ setLink();
1581
+ setAnchorEl(null);
1582
+ queueMicrotask(() => {
1583
+ justSubmittedRef.current = false;
1584
+ });
1585
+ }, [setLink]);
1586
+ const handleClick = useCallback((event) => {
1587
+ onClick?.(event, !isActive);
1588
+ if (event.defaultPrevented) return;
1589
+ setAnchorEl(event.currentTarget);
1590
+ }, [onClick, anchorEl]);
1591
+ useEffect(() => {
1592
+ if (autoOpenOnLinkActive && isActive && !justSubmittedRef.current) setAnchorEl(internalRef.current);
1593
+ }, [autoOpenOnLinkActive, isActive]);
1594
+ if (!isVisible) return null;
1595
+ const open = Boolean(anchorEl);
1596
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(LinkButton, {
1597
+ value: "link",
1598
+ disabled: !canSet,
1599
+ selected: isActive || open,
1600
+ "data-disabled": !canSet,
1601
+ "aria-label": label,
1602
+ tooltip: label,
1603
+ onClick: handleClick,
1604
+ ...buttonProps,
1605
+ ref: setRefs,
1606
+ children: children ?? /* @__PURE__ */ jsx(Icon, { fontSize: "small" })
1607
+ }), /* @__PURE__ */ jsx(Popover, {
1608
+ open,
1609
+ anchorEl,
1610
+ onClose: handleClose,
1611
+ anchorOrigin: {
1612
+ vertical: "bottom",
1613
+ horizontal: "center"
1614
+ },
1615
+ transformOrigin: {
1616
+ vertical: -4,
1617
+ horizontal: "center"
1618
+ },
1619
+ children: /* @__PURE__ */ jsx(LinkMain, {
1620
+ url,
1621
+ setUrl,
1622
+ setLink: handleSetLink,
1623
+ removeLink,
1624
+ openLink,
1625
+ isActive
1626
+ })
1627
+ })] });
1628
+ });
1629
+ LinkPopover.displayName = "LinkPopover";
1630
+ //#endregion
1631
+ //#region src/tiptap/components/ui/list-button/use-list.ts
1632
+ var listIcons = {
1633
+ bulletList: SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5m0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5m0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5M8 19h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1s.45 1 1 1m0-6h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1s.45 1 1 1M7 6c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1" }), "FormatListBulletedRounded"),
1634
+ orderedList: SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M8 7h12c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1s.45 1 1 1m12 10H8c-.55 0-1 .45-1 1s.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1m0-6H8c-.55 0-1 .45-1 1s.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1M4.5 16h-2c-.28 0-.5.22-.5.5s.22.5.5.5H4v.5h-.5c-.28 0-.5.22-.5.5s.22.5.5.5H4v.5H2.5c-.28 0-.5.22-.5.5s.22.5.5.5h2c.28 0 .5-.22.5-.5v-3c0-.28-.22-.5-.5-.5m-2-11H3v2.5c0 .28.22.5.5.5s.5-.22.5-.5v-3c0-.28-.22-.5-.5-.5h-1c-.28 0-.5.22-.5.5s.22.5.5.5m2 5h-2c-.28 0-.5.22-.5.5s.22.5.5.5h1.3l-1.68 1.96c-.08.09-.12.21-.12.32v.22c0 .28.22.5.5.5h2c.28 0 .5-.22.5-.5s-.22-.5-.5-.5H3.2l1.68-1.96c.08-.09.12-.21.12-.32v-.22c0-.28-.22-.5-.5-.5" }), "FormatListNumberedRounded"),
1635
+ taskList: createSvgIcon(/* @__PURE__ */ jsxs("g", { children: [
1636
+ /* @__PURE__ */ jsx("path", {
1637
+ fillRule: "evenodd",
1638
+ clipRule: "evenodd",
1639
+ d: "M2 6C2 4.89543 2.89543 4 4 4H8C9.10457 4 10 4.89543 10 6V10C10 11.1046 9.10457 12 8 12H4C2.89543 12 2 11.1046 2 10V6ZM8 6H4V10H8V6Z",
1640
+ fill: "currentColor"
1641
+ }),
1642
+ /* @__PURE__ */ jsx("path", {
1643
+ fillRule: "evenodd",
1644
+ clipRule: "evenodd",
1645
+ d: "M9.70711 14.2929C10.0976 14.6834 10.0976 15.3166 9.70711 15.7071L5.70711 19.7071C5.31658 20.0976 4.68342 20.0976 4.29289 19.7071L2.29289 17.7071C1.90237 17.3166 1.90237 16.6834 2.29289 16.2929C2.68342 15.9024 3.31658 15.9024 3.70711 16.2929L5 17.5858L8.29289 14.2929C8.68342 13.9024 9.31658 13.9024 9.70711 14.2929Z",
1646
+ fill: "currentColor"
1647
+ }),
1648
+ /* @__PURE__ */ jsx("path", {
1649
+ fillRule: "evenodd",
1650
+ clipRule: "evenodd",
1651
+ d: "M12 6C12 5.44772 12.4477 5 13 5H21C21.5523 5 22 5.44772 22 6C22 6.55228 21.5523 7 21 7H13C12.4477 7 12 6.55228 12 6Z",
1652
+ fill: "currentColor"
1653
+ }),
1654
+ /* @__PURE__ */ jsx("path", {
1655
+ fillRule: "evenodd",
1656
+ clipRule: "evenodd",
1657
+ d: "M12 12C12 11.4477 12.4477 11 13 11H21C21.5523 11 22 11.4477 22 12C22 12.5523 21.5523 13 21 13H13C12.4477 13 12 12.5523 12 12Z",
1658
+ fill: "currentColor"
1659
+ }),
1660
+ /* @__PURE__ */ jsx("path", {
1661
+ fillRule: "evenodd",
1662
+ clipRule: "evenodd",
1663
+ d: "M12 18C12 17.4477 12.4477 17 13 17H21C21.5523 17 22 17.4477 22 18C22 18.5523 21.5523 19 21 19H13C12.4477 19 12 18.5523 12 18Z",
1664
+ fill: "currentColor"
1665
+ })
1666
+ ] }), "ListTodo")
1667
+ };
1668
+ var listLabels = {
1669
+ bulletList: "Liste à puces",
1670
+ orderedList: "Liste numérotée",
1671
+ taskList: "Liste de tâches"
1672
+ };
1673
+ var LIST_SHORTCUT_KEYS = {
1674
+ bulletList: "mod+shift+8",
1675
+ orderedList: "mod+shift+7",
1676
+ taskList: "mod+shift+9"
1677
+ };
1678
+ /**
1679
+ * Checks if a list can be toggled in the current editor state
1680
+ */
1681
+ function canToggleList(editor, type, turnInto = true) {
1682
+ if (!editor || !editor.isEditable) return false;
1683
+ if (!isNodeInSchema(type, editor) || isNodeTypeSelected(editor, ["image"])) return false;
1684
+ if (!turnInto) switch (type) {
1685
+ case "bulletList": return editor.can().toggleBulletList();
1686
+ case "orderedList": return editor.can().toggleOrderedList();
1687
+ case "taskList": return editor.can().toggleList("taskList", "taskItem");
1688
+ default: return false;
1689
+ }
1690
+ if (!selectionWithinConvertibleTypes(editor, [
1691
+ "paragraph",
1692
+ "heading",
1693
+ "bulletList",
1694
+ "orderedList",
1695
+ "taskList",
1696
+ "blockquote",
1697
+ "codeBlock"
1698
+ ])) return false;
1699
+ switch (type) {
1700
+ case "bulletList": return editor.can().toggleBulletList() || editor.can().clearNodes();
1701
+ case "orderedList": return editor.can().toggleOrderedList() || editor.can().clearNodes();
1702
+ case "taskList": return editor.can().toggleList("taskList", "taskItem") || editor.can().clearNodes();
1703
+ default: return false;
1704
+ }
1705
+ }
1706
+ /**
1707
+ * Checks if list is currently active
1708
+ */
1709
+ function isListActive(editor, type) {
1710
+ if (!editor || !editor.isEditable) return false;
1711
+ switch (type) {
1712
+ case "bulletList": return editor.isActive("bulletList");
1713
+ case "orderedList": return editor.isActive("orderedList");
1714
+ case "taskList": return editor.isActive("taskList");
1715
+ default: return false;
1716
+ }
1717
+ }
1718
+ /**
1719
+ * Toggles list in the editor
1720
+ */
1721
+ function toggleList(editor, type) {
1722
+ if (!editor || !editor.isEditable) return false;
1723
+ if (!canToggleList(editor, type)) return false;
1724
+ try {
1725
+ const view = editor.view;
1726
+ let state = view.state;
1727
+ let tr = state.tr;
1728
+ const blocks = getSelectedBlockNodes(editor);
1729
+ const isPossibleToTurnInto = selectionWithinConvertibleTypes(editor, [
1730
+ "paragraph",
1731
+ "heading",
1732
+ "bulletList",
1733
+ "orderedList",
1734
+ "taskList",
1735
+ "blockquote",
1736
+ "codeBlock"
1737
+ ]) && blocks.length === 1;
1738
+ if ((state.selection.empty || state.selection instanceof TextSelection) && isPossibleToTurnInto) {
1739
+ const pos = findNodePosition({
1740
+ editor,
1741
+ node: state.selection.$anchor.node(1)
1742
+ })?.pos;
1743
+ if (!isValidPosition(pos)) return false;
1744
+ tr = tr.setSelection(NodeSelection.create(state.doc, pos));
1745
+ view.dispatch(tr);
1746
+ state = view.state;
1747
+ }
1748
+ const selection = state.selection;
1749
+ let chain = editor.chain().focus();
1750
+ if (selection instanceof NodeSelection) {
1751
+ const firstChild = selection.node.firstChild?.firstChild;
1752
+ const lastChild = selection.node.lastChild?.lastChild;
1753
+ const from = firstChild ? selection.from + firstChild.nodeSize : selection.from + 1;
1754
+ const to = lastChild ? selection.to - lastChild.nodeSize : selection.to - 1;
1755
+ const resolvedFrom = state.doc.resolve(from);
1756
+ const resolvedTo = state.doc.resolve(to);
1757
+ chain = chain.setTextSelection(TextSelection.between(resolvedFrom, resolvedTo)).clearNodes();
1758
+ }
1759
+ if (editor.isActive(type)) chain.liftListItem("listItem").lift("bulletList").lift("orderedList").run();
1760
+ else {
1761
+ const toggle = {
1762
+ bulletList: () => chain.toggleBulletList(),
1763
+ orderedList: () => chain.toggleOrderedList(),
1764
+ taskList: () => chain.toggleList("taskList", "taskItem")
1765
+ }[type];
1766
+ if (!toggle) return false;
1767
+ toggle().run();
1768
+ }
1769
+ editor.chain().focus().selectTextblockEnd().run();
1770
+ return true;
1771
+ } catch {
1772
+ return false;
1773
+ }
1774
+ }
1775
+ /**
1776
+ * Determines if the list button should be shown
1777
+ */
1778
+ function shouldShowButton$3(props) {
1779
+ const { editor, type, hideWhenUnavailable } = props;
1780
+ if (!editor) return false;
1781
+ if (!hideWhenUnavailable) return true;
1782
+ if (!editor.isEditable) return false;
1783
+ if (!isNodeInSchema(type, editor)) return false;
1784
+ if (!editor.isActive("code")) return canToggleList(editor, type);
1785
+ return true;
1786
+ }
1787
+ /**
1788
+ * Custom hook that provides list functionality for Tiptap editor
1789
+ *
1790
+ * @example
1791
+ * ```tsx
1792
+ * // Simple usage
1793
+ * function MySimpleListButton() {
1794
+ * const { isVisible, handleToggle, isActive } = useList({ type: "bulletList" })
1795
+ *
1796
+ * if (!isVisible) return null
1797
+ *
1798
+ * return <button onClick={handleToggle}>Bullet List</button>
1799
+ * }
1800
+ *
1801
+ * // Advanced usage with configuration
1802
+ * function MyAdvancedListButton() {
1803
+ * const { isVisible, handleToggle, label, isActive } = useList({
1804
+ * type: "orderedList",
1805
+ * editor: myEditor,
1806
+ * hideWhenUnavailable: true,
1807
+ * onToggled: () => console.log('List toggled!')
1808
+ * })
1809
+ *
1810
+ * if (!isVisible) return null
1811
+ *
1812
+ * return (
1813
+ * <MyButton
1814
+ * onClick={handleToggle}
1815
+ * aria-label={label}
1816
+ * aria-pressed={isActive}
1817
+ * >
1818
+ * Toggle List
1819
+ * </MyButton>
1820
+ * )
1821
+ * }
1822
+ * ```
1823
+ */
1824
+ function useList(config) {
1825
+ const { editor: providedEditor, type, hideWhenUnavailable = false, onToggled } = config;
1826
+ const { editor } = useTiptapEditor(providedEditor);
1827
+ const [isVisible, setIsVisible] = useState(true);
1828
+ const canToggle = canToggleList(editor, type);
1829
+ const isActive = isListActive(editor, type);
1830
+ useEffect(() => {
1831
+ if (!editor) return;
1832
+ const handleSelectionUpdate = () => {
1833
+ setIsVisible(shouldShowButton$3({
1834
+ editor,
1835
+ type,
1836
+ hideWhenUnavailable
1837
+ }));
1838
+ };
1839
+ handleSelectionUpdate();
1840
+ editor.on("selectionUpdate", handleSelectionUpdate);
1841
+ return () => {
1842
+ editor.off("selectionUpdate", handleSelectionUpdate);
1843
+ };
1844
+ }, [
1845
+ editor,
1846
+ type,
1847
+ hideWhenUnavailable
1848
+ ]);
1849
+ return {
1850
+ isVisible,
1851
+ isActive,
1852
+ handleToggle: useCallback(() => {
1853
+ if (!editor) return false;
1854
+ const success = toggleList(editor, type);
1855
+ if (success) onToggled?.();
1856
+ return success;
1857
+ }, [
1858
+ editor,
1859
+ type,
1860
+ onToggled
1861
+ ]),
1862
+ canToggle,
1863
+ label: listLabels[type],
1864
+ shortcutKeys: LIST_SHORTCUT_KEYS[type],
1865
+ Icon: listIcons[type]
1866
+ };
1867
+ }
1868
+ //#endregion
1869
+ //#region src/tiptap/components/ui/list-button/list-button.tsx
1870
+ function ListShortcutBadge({ type, shortcutKeys = LIST_SHORTCUT_KEYS[type] }) {
1871
+ return /* @__PURE__ */ jsx(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
1872
+ }
1873
+ /**
1874
+ * Button component for toggling lists in a Tiptap editor.
1875
+ *
1876
+ * For custom button implementations, use the `useList` hook instead.
1877
+ */
1878
+ var ListButton = forwardRef(({ editor: providedEditor, type, text, hideWhenUnavailable = false, onToggled, showShortcut = false, onClick, children, ...buttonProps }, ref) => {
1879
+ const { editor } = useTiptapEditor(providedEditor);
1880
+ const { isVisible, canToggle, isActive, handleToggle, label, shortcutKeys, Icon } = useList({
1881
+ editor,
1882
+ type,
1883
+ hideWhenUnavailable,
1884
+ onToggled
1885
+ });
1886
+ const handleClick = useCallback((event) => {
1887
+ onClick?.(event, !isActive);
1888
+ if (event.defaultPrevented) return;
1889
+ handleToggle();
1890
+ }, [handleToggle, onClick]);
1891
+ if (!isVisible) return null;
1892
+ return /* @__PURE__ */ jsx(Button, {
1893
+ value: type,
1894
+ type: "button",
1895
+ selected: isActive,
1896
+ role: "button",
1897
+ tabIndex: -1,
1898
+ disabled: !canToggle,
1899
+ "data-disabled": !canToggle,
1900
+ "aria-label": label,
1901
+ tooltip: label,
1902
+ onClick: handleClick,
1903
+ ...buttonProps,
1904
+ ref,
1905
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
1906
+ /* @__PURE__ */ jsx(Icon, { fontSize: "small" }),
1907
+ text && /* @__PURE__ */ jsx("span", {
1908
+ className: "tiptap-button-text",
1909
+ children: text
1910
+ }),
1911
+ showShortcut && /* @__PURE__ */ jsx(ListShortcutBadge, {
1912
+ type,
1913
+ shortcutKeys
1914
+ })
1915
+ ] })
1916
+ });
1917
+ });
1918
+ ListButton.displayName = "ListButton";
1919
+ //#endregion
1920
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/CodeRounded.mjs
1921
+ var CodeRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M8.7 15.9 4.8 12l3.9-3.9c.39-.39.39-1.01 0-1.4a.984.984 0 0 0-1.4 0l-4.59 4.59c-.39.39-.39 1.02 0 1.41l4.59 4.6c.39.39 1.01.39 1.4 0s.39-1.01 0-1.4m6.6 0 3.9-3.9-3.9-3.9a.984.984 0 0 1 0-1.4c.39-.39 1.01-.39 1.4 0l4.59 4.59c.39.39.39 1.02 0 1.41l-4.59 4.6c-.39.39-1.01.39-1.4 0a.984.984 0 0 1 0-1.4" }), "CodeRounded");
1922
+ //#endregion
1923
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/FormatBoldRounded.mjs
1924
+ var FormatBoldRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H8c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h5.78c2.07 0 3.96-1.69 3.97-3.77.01-1.53-.85-2.84-2.15-3.44M10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5" }), "FormatBoldRounded");
1925
+ //#endregion
1926
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/FormatItalicRounded.mjs
1927
+ var FormatItalicRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M10 5.5c0 .83.67 1.5 1.5 1.5h.71l-3.42 8H7.5c-.83 0-1.5.67-1.5 1.5S6.67 18 7.5 18h5c.83 0 1.5-.67 1.5-1.5s-.67-1.5-1.5-1.5h-.71l3.42-8h1.29c.83 0 1.5-.67 1.5-1.5S17.33 4 16.5 4h-5c-.83 0-1.5.67-1.5 1.5" }), "FormatItalicRounded");
1928
+ //#endregion
1929
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/FormatUnderlinedRounded.mjs
1930
+ var FormatUnderlinedRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M12.79 16.95c3.03-.39 5.21-3.11 5.21-6.16V4.25C18 3.56 17.44 3 16.75 3s-1.25.56-1.25 1.25v6.65c0 1.67-1.13 3.19-2.77 3.52-2.25.47-4.23-1.25-4.23-3.42V4.25C8.5 3.56 7.94 3 7.25 3S6 3.56 6 4.25V11c0 3.57 3.13 6.42 6.79 5.95M5 20c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H6c-.55 0-1 .45-1 1" }), "FormatUnderlinedRounded");
1931
+ //#endregion
1932
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/StrikethroughSRounded.mjs
1933
+ var StrikethroughSRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M14.59 7.52c0-.31-.05-.59-.15-.85-.09-.27-.24-.49-.44-.68s-.45-.33-.75-.44c-.3-.1-.66-.16-1.06-.16-.39 0-.74.04-1.03.13s-.53.21-.72.36c-.19.16-.34.34-.44.55q-.15.315-.15.66c0 .48.25.88.74 1.21.38.25.77.48 1.41.7H7.39c-.05-.08-.11-.17-.15-.25-.26-.48-.39-1.03-.39-1.67 0-.61.13-1.16.4-1.67q.39-.75 1.11-1.29c.48-.35 1.05-.63 1.7-.83.66-.19 1.39-.29 2.18-.29.81 0 1.54.11 2.21.34.66.22 1.23.54 1.69.94.47.4.83.88 1.08 1.43s.38 1.15.38 1.81zM20 10H4c-.55 0-1 .45-1 1s.45 1 1 1h8.62c.18.07.4.14.55.2q.555.255.87.51c.315.255.35.36.43.57.07.2.11.43.11.69 0 .23-.05.45-.14.66-.09.2-.23.38-.42.53s-.42.26-.71.35c-.29.08-.63.13-1.01.13-.43 0-.83-.04-1.18-.13s-.66-.23-.91-.42-.45-.44-.59-.75-.25-.76-.25-1.21H6.4c0 .55.08 1.13.24 1.58s.37.85.65 1.21c.28.35.6.66.98.92.37.26.78.48 1.22.65q.66.255 1.38.39c.48.08.96.13 1.44.13.8 0 1.53-.09 2.18-.28s1.21-.45 1.67-.79.82-.77 1.07-1.27.38-1.07.38-1.71c0-.6-.1-1.14-.31-1.61-.05-.11-.11-.23-.17-.33H20c.55 0 1-.45 1-1V11c0-.55-.45-1-1-1" }), "StrikethroughSRounded");
1934
+ //#endregion
1935
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/SubscriptRounded.mjs
1936
+ var SubscriptRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M10.52 10.73 7.3 5.72C6.82 4.97 7.35 4 8.23 4c.39 0 .74.2.95.53l2.76 4.46h.12l2.74-4.45c.21-.34.57-.54.96-.54.88 0 1.42.98.94 1.72l-3.23 5 3.55 5.55c.48.75-.06 1.73-.94 1.73-.38 0-.74-.2-.95-.52l-3.07-4.89h-.12l-3.07 4.89c-.2.32-.56.52-.95.52-.88 0-1.42-.97-.94-1.72zM23 19.5c0-.28-.22-.5-.5-.5H20v-1h2c.55 0 1-.45 1-1v-1c0-.55-.45-1-1-1h-2.5c-.28 0-.5.22-.5.5s.22.5.5.5H22v1h-2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1h2.5c.28 0 .5-.22.5-.5" }), "SubscriptRounded");
1937
+ //#endregion
1938
+ //#region src/tiptap/components/ui/mark-button/use-mark.ts
1939
+ var markIcons = {
1940
+ bold: FormatBoldRounded_default,
1941
+ italic: FormatItalicRounded_default,
1942
+ underline: FormatUnderlinedRounded_default,
1943
+ strike: StrikethroughSRounded_default,
1944
+ code: CodeRounded_default,
1945
+ superscript: SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M10.51 12.73 7.3 7.72C6.82 6.97 7.35 6 8.23 6c.39 0 .74.2.95.53l2.76 4.46h.12l2.74-4.45c.2-.34.56-.54.95-.54.88 0 1.42.98.94 1.72l-3.23 5 3.55 5.55c.49.75-.05 1.73-.93 1.73-.38 0-.74-.2-.95-.52l-3.07-4.89h-.12l-3.07 4.89c-.21.32-.56.52-.95.52-.88 0-1.42-.97-.94-1.72zM23 8.5c0-.28-.22-.5-.5-.5H20V7h2c.55 0 1-.45 1-1V5c0-.55-.45-1-1-1h-2.5c-.28 0-.5.22-.5.5s.22.5.5.5H22v1h-2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1h2.5c.28 0 .5-.22.5-.5" }), "SuperscriptRounded"),
1946
+ subscript: SubscriptRounded_default
1947
+ };
1948
+ var MARK_SHORTCUT_KEYS = {
1949
+ bold: "mod+b",
1950
+ italic: "mod+i",
1951
+ underline: "mod+u",
1952
+ strike: "mod+shift+s",
1953
+ code: "mod+e",
1954
+ superscript: "mod+.",
1955
+ subscript: "mod+,"
1956
+ };
1957
+ /**
1958
+ * Checks if a mark can be toggled in the current editor state
1959
+ */
1960
+ function canToggleMark(editor, type) {
1961
+ if (!editor || !editor.isEditable) return false;
1962
+ if (!isMarkInSchema(type, editor) || isNodeTypeSelected(editor, ["image"])) return false;
1963
+ return editor.can().toggleMark(type);
1964
+ }
1965
+ /**
1966
+ * Checks if a mark is currently active
1967
+ */
1968
+ function isMarkActive(editor, type) {
1969
+ if (!editor || !editor.isEditable) return false;
1970
+ return editor.isActive(type);
1971
+ }
1972
+ /**
1973
+ * Toggles a mark in the editor
1974
+ */
1975
+ function toggleMark(editor, type) {
1976
+ if (!editor || !editor.isEditable) return false;
1977
+ if (!canToggleMark(editor, type)) return false;
1978
+ return editor.chain().focus().toggleMark(type).run();
1979
+ }
1980
+ /**
1981
+ * Determines if the mark button should be shown
1982
+ */
1983
+ function shouldShowButton$2(props) {
1984
+ const { editor, type, hideWhenUnavailable } = props;
1985
+ if (!editor) return false;
1986
+ if (!hideWhenUnavailable) return true;
1987
+ if (!editor.isEditable) return false;
1988
+ if (!isMarkInSchema(type, editor)) return false;
1989
+ if (!editor.isActive("code")) return canToggleMark(editor, type);
1990
+ return true;
1991
+ }
1992
+ /**
1993
+ * Gets the formatted mark name
1994
+ */
1995
+ function getFormattedMarkName(type) {
1996
+ switch (type) {
1997
+ case "bold": return "Gras";
1998
+ case "italic": return "Italique";
1999
+ case "strike": return "Barré";
2000
+ case "code": return "Code";
2001
+ case "underline": return "Souligné";
2002
+ case "superscript": return "Exposant";
2003
+ case "subscript": return "Indice";
2004
+ }
2005
+ }
2006
+ /**
2007
+ * Custom hook that provides mark functionality for Tiptap editor
2008
+ *
2009
+ * @example
2010
+ * ```tsx
2011
+ * // Simple usage
2012
+ * function MySimpleBoldButton() {
2013
+ * const { isVisible, handleMark } = useMark({ type: "bold" })
2014
+ *
2015
+ * if (!isVisible) return null
2016
+ *
2017
+ * return <button onClick={handleMark}>Bold</button>
2018
+ * }
2019
+ *
2020
+ * // Advanced usage with configuration
2021
+ * function MyAdvancedItalicButton() {
2022
+ * const { isVisible, handleMark, label, isActive } = useMark({
2023
+ * editor: myEditor,
2024
+ * type: "italic",
2025
+ * hideWhenUnavailable: true,
2026
+ * onToggled: () => console.log('Mark toggled!')
2027
+ * })
2028
+ *
2029
+ * if (!isVisible) return null
2030
+ *
2031
+ * return (
2032
+ * <MyButton
2033
+ * onClick={handleMark}
2034
+ * aria-pressed={isActive}
2035
+ * aria-label={label}
2036
+ * >
2037
+ * Italic
2038
+ * </MyButton>
2039
+ * )
2040
+ * }
2041
+ * ```
2042
+ */
2043
+ function useMark(config) {
2044
+ const { editor: providedEditor, type, hideWhenUnavailable = false, onToggled } = config;
2045
+ const { editor } = useTiptapEditor(providedEditor);
2046
+ const [isVisible, setIsVisible] = useState(true);
2047
+ const canToggle = canToggleMark(editor, type);
2048
+ const isActive = isMarkActive(editor, type);
2049
+ useEffect(() => {
2050
+ if (!editor) return;
2051
+ const handleSelectionUpdate = () => {
2052
+ setIsVisible(shouldShowButton$2({
2053
+ editor,
2054
+ type,
2055
+ hideWhenUnavailable
2056
+ }));
2057
+ };
2058
+ handleSelectionUpdate();
2059
+ editor.on("selectionUpdate", handleSelectionUpdate);
2060
+ return () => {
2061
+ editor.off("selectionUpdate", handleSelectionUpdate);
2062
+ };
2063
+ }, [
2064
+ editor,
2065
+ type,
2066
+ hideWhenUnavailable
2067
+ ]);
2068
+ return {
2069
+ isVisible,
2070
+ isActive,
2071
+ handleMark: useCallback(() => {
2072
+ if (!editor) return false;
2073
+ const success = toggleMark(editor, type);
2074
+ if (success) onToggled?.();
2075
+ return success;
2076
+ }, [
2077
+ editor,
2078
+ type,
2079
+ onToggled
2080
+ ]),
2081
+ canToggle,
2082
+ label: getFormattedMarkName(type),
2083
+ shortcutKeys: MARK_SHORTCUT_KEYS[type],
2084
+ Icon: markIcons[type]
2085
+ };
2086
+ }
2087
+ //#endregion
2088
+ //#region src/tiptap/components/ui/mark-button/mark-button.tsx
2089
+ function MarkShortcutBadge({ type, shortcutKeys = MARK_SHORTCUT_KEYS[type] }) {
2090
+ return /* @__PURE__ */ jsx(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
2091
+ }
2092
+ /**
2093
+ * Button component for toggling marks in a Tiptap editor.
2094
+ *
2095
+ * For custom button implementations, use the `useMark` hook instead.
2096
+ */
2097
+ var MarkButton = forwardRef(({ editor: providedEditor, type, text, hideWhenUnavailable = false, onToggled, showShortcut = false, onClick, children, ...buttonProps }, ref) => {
2098
+ const { editor } = useTiptapEditor(providedEditor);
2099
+ const { isVisible, handleMark, label, canToggle, isActive, Icon, shortcutKeys } = useMark({
2100
+ editor,
2101
+ type,
2102
+ hideWhenUnavailable,
2103
+ onToggled
2104
+ });
2105
+ const handleClick = useCallback((event) => {
2106
+ onClick?.(event, !isActive);
2107
+ if (event.defaultPrevented) return;
2108
+ handleMark();
2109
+ }, [handleMark, onClick]);
2110
+ if (!isVisible) return null;
2111
+ return /* @__PURE__ */ jsx(Button, {
2112
+ value: type,
2113
+ type: "button",
2114
+ disabled: !canToggle,
2115
+ selected: isActive,
2116
+ "data-disabled": !canToggle,
2117
+ role: "button",
2118
+ tabIndex: -1,
2119
+ "aria-label": label,
2120
+ tooltip: label,
2121
+ onClick: handleClick,
2122
+ ...buttonProps,
2123
+ ref,
2124
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
2125
+ /* @__PURE__ */ jsx(Icon, { fontSize: "small" }),
2126
+ text && /* @__PURE__ */ jsx("span", {
2127
+ className: "tiptap-button-text",
2128
+ children: text
2129
+ }),
2130
+ showShortcut && /* @__PURE__ */ jsx(MarkShortcutBadge, {
2131
+ type,
2132
+ shortcutKeys
2133
+ })
2134
+ ] })
2135
+ });
2136
+ });
2137
+ MarkButton.displayName = "MarkButton";
2138
+ //#endregion
2139
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/FormatAlignCenterRounded.mjs
2140
+ var FormatAlignCenterRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M7 16c0 .55.45 1 1 1h8c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1m-3 5h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1m0-8h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1m3-5c0 .55.45 1 1 1h8c.55 0 1-.45 1-1s-.45-1-1-1H8c-.55 0-1 .45-1 1M3 4c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1" }), "FormatAlignCenterRounded");
2141
+ //#endregion
2142
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/FormatAlignJustifyRounded.mjs
2143
+ var FormatAlignJustifyRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M4 21h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1m0-4h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1m0-4h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1m0-4h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1M3 4c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1" }), "FormatAlignJustifyRounded");
2144
+ //#endregion
2145
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/FormatAlignLeftRounded.mjs
2146
+ var FormatAlignLeftRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M14 15H4c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1m0-8H4c-.55 0-1 .45-1 1s.45 1 1 1h10c.55 0 1-.45 1-1s-.45-1-1-1M4 13h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1m0 8h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1M3 4c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1" }), "FormatAlignLeftRounded");
2147
+ //#endregion
2148
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/FormatAlignRightRounded.mjs
2149
+ var FormatAlignRightRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M4 21h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1m6-4h10c.55 0 1-.45 1-1s-.45-1-1-1H10c-.55 0-1 .45-1 1s.45 1 1 1m-6-4h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1m6-4h10c.55 0 1-.45 1-1s-.45-1-1-1H10c-.55 0-1 .45-1 1s.45 1 1 1M3 4c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1" }), "FormatAlignRightRounded");
2150
+ //#endregion
2151
+ //#region src/tiptap/components/ui/text-align-button/use-text-align.ts
2152
+ var TEXT_ALIGN_SHORTCUT_KEYS = {
2153
+ left: "mod+shift+l",
2154
+ center: "mod+shift+e",
2155
+ right: "mod+shift+r",
2156
+ justify: "mod+shift+j"
2157
+ };
2158
+ var textAlignIcons = {
2159
+ left: FormatAlignLeftRounded_default,
2160
+ center: FormatAlignCenterRounded_default,
2161
+ right: FormatAlignRightRounded_default,
2162
+ justify: FormatAlignJustifyRounded_default
2163
+ };
2164
+ var textAlignLabels = {
2165
+ left: "Aligner à gauche",
2166
+ center: "Aligner au centre",
2167
+ right: "Aligner à droite",
2168
+ justify: "Justifier"
2169
+ };
2170
+ /**
2171
+ * Checks if text alignment can be performed in the current editor state
2172
+ */
2173
+ function canSetTextAlign(editor, align) {
2174
+ if (!editor || editor.isDestroyed || !editor.isEditable) return false;
2175
+ if (!isExtensionAvailable(editor, "textAlign") || isNodeTypeSelected(editor, ["image", "horizontalRule"])) return false;
2176
+ try {
2177
+ return editor.can().setTextAlign(align);
2178
+ } catch {
2179
+ return false;
2180
+ }
2181
+ }
2182
+ function hasSetTextAlign(commands) {
2183
+ return "setTextAlign" in commands;
2184
+ }
2185
+ /**
2186
+ * Checks if the text alignment is currently active
2187
+ */
2188
+ function isTextAlignActive(editor, align) {
2189
+ if (!editor || !editor.isEditable) return false;
2190
+ return editor.isActive({ textAlign: align });
2191
+ }
2192
+ /**
2193
+ * Sets text alignment in the editor
2194
+ */
2195
+ function setTextAlign(editor, align) {
2196
+ if (!editor || editor.isDestroyed || !editor.isEditable) return false;
2197
+ if (!canSetTextAlign(editor, align)) return false;
2198
+ try {
2199
+ const chain = editor.chain().focus();
2200
+ if (hasSetTextAlign(chain)) return chain.setTextAlign(align).run();
2201
+ } catch {
2202
+ return false;
2203
+ }
2204
+ return false;
2205
+ }
2206
+ /**
2207
+ * Determines if the text align button should be shown
2208
+ */
2209
+ function shouldShowButton$1(props) {
2210
+ const { editor, hideWhenUnavailable, align } = props;
2211
+ if (!editor) return false;
2212
+ if (!hideWhenUnavailable) return true;
2213
+ if (!editor.isEditable) return false;
2214
+ if (!isExtensionAvailable(editor, "textAlign")) return false;
2215
+ if (!editor.isActive("code")) return canSetTextAlign(editor, align);
2216
+ return true;
2217
+ }
2218
+ /**
2219
+ * Custom hook that provides text align functionality for Tiptap editor
2220
+ *
2221
+ * @example
2222
+ * ```tsx
2223
+ * // Simple usage
2224
+ * function MySimpleAlignButton() {
2225
+ * const { isVisible, handleTextAlign } = useTextAlign({ align: "center" })
2226
+ *
2227
+ * if (!isVisible) return null
2228
+ *
2229
+ * return <button onClick={handleTextAlign}>Align Center</button>
2230
+ * }
2231
+ *
2232
+ * // Advanced usage with configuration
2233
+ * function MyAdvancedAlignButton() {
2234
+ * const { isVisible, handleTextAlign, label, isActive } = useTextAlign({
2235
+ * editor: myEditor,
2236
+ * align: "right",
2237
+ * hideWhenUnavailable: true,
2238
+ * onAligned: () => console.log('Text aligned!')
2239
+ * })
2240
+ *
2241
+ * if (!isVisible) return null
2242
+ *
2243
+ * return (
2244
+ * <MyButton
2245
+ * onClick={handleTextAlign}
2246
+ * aria-pressed={isActive}
2247
+ * aria-label={label}
2248
+ * >
2249
+ * Align Right
2250
+ * </MyButton>
2251
+ * )
2252
+ * }
2253
+ * ```
2254
+ */
2255
+ function useTextAlign(config) {
2256
+ const { editor: providedEditor, align, hideWhenUnavailable = false, onAligned } = config;
2257
+ const { editor } = useTiptapEditor(providedEditor);
2258
+ const [isVisible, setIsVisible] = useState(true);
2259
+ const canAlign = canSetTextAlign(editor, align);
2260
+ const isActive = isTextAlignActive(editor, align);
2261
+ useEffect(() => {
2262
+ if (!editor) return;
2263
+ const handleSelectionUpdate = () => {
2264
+ setIsVisible(shouldShowButton$1({
2265
+ editor,
2266
+ align,
2267
+ hideWhenUnavailable
2268
+ }));
2269
+ };
2270
+ handleSelectionUpdate();
2271
+ editor.on("selectionUpdate", handleSelectionUpdate);
2272
+ return () => {
2273
+ editor.off("selectionUpdate", handleSelectionUpdate);
2274
+ };
2275
+ }, [
2276
+ editor,
2277
+ hideWhenUnavailable,
2278
+ align
2279
+ ]);
2280
+ return {
2281
+ isVisible,
2282
+ isActive,
2283
+ handleTextAlign: useCallback(() => {
2284
+ if (!editor) return false;
2285
+ const success = setTextAlign(editor, align);
2286
+ if (success) onAligned?.();
2287
+ return success;
2288
+ }, [
2289
+ editor,
2290
+ align,
2291
+ onAligned
2292
+ ]),
2293
+ canAlign,
2294
+ label: textAlignLabels[align],
2295
+ shortcutKeys: TEXT_ALIGN_SHORTCUT_KEYS[align],
2296
+ Icon: textAlignIcons[align]
2297
+ };
2298
+ }
2299
+ //#endregion
2300
+ //#region src/tiptap/components/ui/text-align-button/text-align-button.tsx
2301
+ function TextAlignShortcutBadge({ align, shortcutKeys = TEXT_ALIGN_SHORTCUT_KEYS[align] }) {
2302
+ return /* @__PURE__ */ jsx(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
2303
+ }
2304
+ /**
2305
+ * Button component for setting text alignment in a Tiptap editor.
2306
+ *
2307
+ * For custom button implementations, use the `useTextAlign` hook instead.
2308
+ */
2309
+ var TextAlignButton = forwardRef(({ editor: providedEditor, align, text, hideWhenUnavailable = false, onAligned, showShortcut = false, onClick, icon: CustomIcon, children, ...buttonProps }, ref) => {
2310
+ const { editor } = useTiptapEditor(providedEditor);
2311
+ const { isVisible, handleTextAlign, label, canAlign, isActive, Icon, shortcutKeys } = useTextAlign({
2312
+ editor,
2313
+ align,
2314
+ hideWhenUnavailable,
2315
+ onAligned
2316
+ });
2317
+ const handleClick = useCallback((event) => {
2318
+ onClick?.(event, !isActive);
2319
+ if (event.defaultPrevented) return;
2320
+ handleTextAlign();
2321
+ }, [handleTextAlign, onClick]);
2322
+ if (!isVisible) return null;
2323
+ const RenderIcon = CustomIcon ?? Icon;
2324
+ return /* @__PURE__ */ jsx(Button, {
2325
+ value: align,
2326
+ type: "button",
2327
+ disabled: !canAlign,
2328
+ selected: isActive,
2329
+ "data-disabled": !canAlign,
2330
+ role: "button",
2331
+ tabIndex: -1,
2332
+ "aria-label": label,
2333
+ tooltip: label,
2334
+ onClick: handleClick,
2335
+ ...buttonProps,
2336
+ ref,
2337
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
2338
+ /* @__PURE__ */ jsx(RenderIcon, { fontSize: "small" }),
2339
+ text && /* @__PURE__ */ jsx("span", {
2340
+ className: "tiptap-button-text",
2341
+ children: text
2342
+ }),
2343
+ showShortcut && /* @__PURE__ */ jsx(TextAlignShortcutBadge, {
2344
+ align,
2345
+ shortcutKeys
2346
+ })
2347
+ ] })
2348
+ });
2349
+ });
2350
+ TextAlignButton.displayName = "TextAlignButton";
2351
+ //#endregion
2352
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/RedoRounded.mjs
2353
+ var RedoRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M18.4 10.6C16.55 8.99 14.15 8 11.5 8c-4.16 0-7.74 2.42-9.44 5.93-.32.67.04 1.47.75 1.71.59.2 1.23-.08 1.5-.64 1.3-2.66 4.03-4.5 7.19-4.5 1.95 0 3.73.72 5.12 1.88l-1.91 1.91c-.63.63-.19 1.71.7 1.71H21c.55 0 1-.45 1-1V9.41c0-.89-1.08-1.34-1.71-.71z" }), "RedoRounded");
2354
+ //#endregion
2355
+ //#region ../../node_modules/.pnpm/@mui+icons-material@9.4.0_@mui+material@9.4.0_@emotion+react@11.14.0_@types+react@19.2._02cb1dd638d2ccdea7d16c50ea4ea174/node_modules/@mui/icons-material/UndoRounded.mjs
2356
+ var UndoRounded_default = SvgIcon_default(/*#__PURE__*/ jsx("path", { d: "M12.5 8c-2.65 0-5.05.99-6.9 2.6L3.71 8.71C3.08 8.08 2 8.52 2 9.41V15c0 .55.45 1 1 1h5.59c.89 0 1.34-1.08.71-1.71l-1.91-1.91c1.39-1.16 3.16-1.88 5.12-1.88 3.16 0 5.89 1.84 7.19 4.5.27.56.91.84 1.5.64.71-.23 1.07-1.04.75-1.72C20.23 10.42 16.65 8 12.5 8" }), "UndoRounded");
2357
+ //#endregion
2358
+ //#region src/tiptap/components/ui/undo-redo-button/use-undo-redo.ts
2359
+ var UNDO_REDO_SHORTCUT_KEYS = {
2360
+ undo: "mod+z",
2361
+ redo: "mod+shift+z"
2362
+ };
2363
+ var historyActionLabels = {
2364
+ undo: "Annuler",
2365
+ redo: "Rétablir"
2366
+ };
2367
+ var historyIcons = {
2368
+ undo: UndoRounded_default,
2369
+ redo: RedoRounded_default
2370
+ };
2371
+ /**
2372
+ * Checks if a history action can be executed
2373
+ */
2374
+ function canExecuteUndoRedoAction(editor, action) {
2375
+ if (!editor || editor.isDestroyed || !editor.isEditable) return false;
2376
+ try {
2377
+ if (isNodeTypeSelected(editor, ["image"])) return false;
2378
+ const commands = editor.can();
2379
+ const command = action === "undo" ? commands.undo : commands.redo;
2380
+ return typeof command === "function" ? command() : false;
2381
+ } catch {
2382
+ return false;
2383
+ }
2384
+ }
2385
+ /**
2386
+ * Executes a history action on the editor
2387
+ */
2388
+ function executeUndoRedoAction(editor, action) {
2389
+ if (!editor || editor.isDestroyed || !editor.isEditable) return false;
2390
+ if (!canExecuteUndoRedoAction(editor, action)) return false;
2391
+ try {
2392
+ const chain = editor.chain().focus();
2393
+ return action === "undo" ? chain.undo().run() : chain.redo().run();
2394
+ } catch {
2395
+ return false;
2396
+ }
2397
+ }
2398
+ /**
2399
+ * Determines if the history button should be shown
2400
+ */
2401
+ function shouldShowButton(props) {
2402
+ const { editor, hideWhenUnavailable, action } = props;
2403
+ if (!editor) return false;
2404
+ if (!hideWhenUnavailable) return true;
2405
+ if (!editor.isEditable) return false;
2406
+ if (!editor.isActive("code")) return canExecuteUndoRedoAction(editor, action);
2407
+ return true;
2408
+ }
2409
+ /**
2410
+ * Custom hook that provides history functionality for Tiptap editor
2411
+ *
2412
+ * @example
2413
+ * ```tsx
2414
+ * // Simple usage
2415
+ * function MySimpleUndoButton() {
2416
+ * const { isVisible, handleAction } = useHistory({ action: "undo" })
2417
+ *
2418
+ * if (!isVisible) return null
2419
+ *
2420
+ * return <button onClick={handleAction}>Undo</button>
2421
+ * }
2422
+ *
2423
+ * // Advanced usage with configuration
2424
+ * function MyAdvancedRedoButton() {
2425
+ * const { isVisible, handleAction, label } = useHistory({
2426
+ * editor: myEditor,
2427
+ * action: "redo",
2428
+ * hideWhenUnavailable: true,
2429
+ * onExecuted: () => console.log('Action executed!')
2430
+ * })
2431
+ *
2432
+ * if (!isVisible) return null
2433
+ *
2434
+ * return (
2435
+ * <MyButton
2436
+ * onClick={handleAction}
2437
+ * aria-label={label}
2438
+ * >
2439
+ * Redo
2440
+ * </MyButton>
2441
+ * )
2442
+ * }
2443
+ * ```
2444
+ */
2445
+ function useUndoRedo(config) {
2446
+ const { editor: providedEditor, action, hideWhenUnavailable = false, onExecuted } = config;
2447
+ const { editor } = useTiptapEditor(providedEditor);
2448
+ const [isVisible, setIsVisible] = useState(true);
2449
+ const canExecute = canExecuteUndoRedoAction(editor, action);
2450
+ useEffect(() => {
2451
+ if (!editor) return;
2452
+ const handleUpdate = () => {
2453
+ setIsVisible(shouldShowButton({
2454
+ editor,
2455
+ hideWhenUnavailable,
2456
+ action
2457
+ }));
2458
+ };
2459
+ handleUpdate();
2460
+ editor.on("transaction", handleUpdate);
2461
+ return () => {
2462
+ editor.off("transaction", handleUpdate);
2463
+ };
2464
+ }, [
2465
+ editor,
2466
+ hideWhenUnavailable,
2467
+ action
2468
+ ]);
2469
+ return {
2470
+ isVisible,
2471
+ handleAction: useCallback(() => {
2472
+ if (!editor) return false;
2473
+ const success = executeUndoRedoAction(editor, action);
2474
+ if (success) onExecuted?.();
2475
+ return success;
2476
+ }, [
2477
+ editor,
2478
+ action,
2479
+ onExecuted
2480
+ ]),
2481
+ canExecute,
2482
+ label: historyActionLabels[action],
2483
+ shortcutKeys: UNDO_REDO_SHORTCUT_KEYS[action],
2484
+ Icon: historyIcons[action]
2485
+ };
2486
+ }
2487
+ //#endregion
2488
+ //#region src/tiptap/components/ui/undo-redo-button/undo-redo-button.tsx
2489
+ function HistoryShortcutBadge({ action, shortcutKeys = UNDO_REDO_SHORTCUT_KEYS[action] }) {
2490
+ return /* @__PURE__ */ jsx(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
2491
+ }
2492
+ /**
2493
+ * Button component for triggering undo/redo actions in a Tiptap editor.
2494
+ *
2495
+ * For custom button implementations, use the `useHistory` hook instead.
2496
+ */
2497
+ var UndoRedoButton = forwardRef(({ editor: providedEditor, action, text, hideWhenUnavailable = false, onExecuted, showShortcut = false, onClick, children, ...buttonProps }, ref) => {
2498
+ const { editor } = useTiptapEditor(providedEditor);
2499
+ const { isVisible, handleAction, label, canExecute, Icon, shortcutKeys } = useUndoRedo({
2500
+ editor,
2501
+ action,
2502
+ hideWhenUnavailable,
2503
+ onExecuted
2504
+ });
2505
+ const handleClick = useCallback((event) => {
2506
+ onClick?.(event, true);
2507
+ if (event.defaultPrevented) return;
2508
+ handleAction();
2509
+ }, [handleAction, onClick]);
2510
+ if (!isVisible) return null;
2511
+ return /* @__PURE__ */ jsx(Button, {
2512
+ value: action,
2513
+ type: "button",
2514
+ disabled: !canExecute,
2515
+ "data-disabled": !canExecute,
2516
+ role: "button",
2517
+ tabIndex: -1,
2518
+ "aria-label": label,
2519
+ tooltip: label,
2520
+ onClick: handleClick,
2521
+ ...buttonProps,
2522
+ ref,
2523
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
2524
+ /* @__PURE__ */ jsx(Icon, { fontSize: "small" }),
2525
+ text && /* @__PURE__ */ jsx("span", {
2526
+ className: "tiptap-button-text",
2527
+ children: text
2528
+ }),
2529
+ showShortcut && /* @__PURE__ */ jsx(HistoryShortcutBadge, {
2530
+ action,
2531
+ shortcutKeys
2532
+ })
2533
+ ] })
2534
+ });
2535
+ });
2536
+ UndoRedoButton.displayName = "UndoRedoButton";
2537
+ //#endregion
2538
+ //#region src/tiptap/hooks/use-composed-ref.ts
2539
+ var updateRef = (ref, value) => {
2540
+ if (typeof ref === "function") ref(value);
2541
+ else if (ref && typeof ref === "object" && "current" in ref) {
2542
+ const mutableRef = ref;
2543
+ mutableRef.current = value;
2544
+ }
2545
+ };
2546
+ var useComposedRef = (libRef, userRef) => {
2547
+ const prevUserRef = useRef(null);
2548
+ return useCallback((instance) => {
2549
+ if (libRef && "current" in libRef) {
2550
+ const mutableLibRef = libRef;
2551
+ mutableLibRef.current = instance;
2552
+ }
2553
+ if (prevUserRef.current) updateRef(prevUserRef.current, null);
2554
+ prevUserRef.current = userRef;
2555
+ if (userRef) updateRef(userRef, instance);
2556
+ }, [libRef, userRef]);
2557
+ };
2558
+ //#endregion
2559
+ //#region src/tiptap/hooks/use-menu-navigation.ts
2560
+ /**
2561
+ * Hook that implements keyboard navigation for dropdown menus and command palettes.
2562
+ *
2563
+ * Handles arrow keys, tab, home/end, enter for selection, and escape to close.
2564
+ * Works with both Tiptap editors and regular DOM elements.
2565
+ *
2566
+ * @param options - Configuration options for the menu navigation
2567
+ * @returns Object containing the selected index and a setter function
2568
+ */
2569
+ function useMenuNavigation({ editor, containerRef, query, items, onSelect, onClose, orientation = "vertical", autoSelectFirstItem = true, loopOnTab = true }) {
2570
+ const [selectedIndex, setSelectedIndex] = useState(autoSelectFirstItem ? 0 : -1);
2571
+ useEffect(() => {
2572
+ const handleKeyboardNavigation = (event) => {
2573
+ if (!items.length) return false;
2574
+ const moveNext = () => setSelectedIndex((currentIndex) => {
2575
+ if (currentIndex === -1) return 0;
2576
+ return (currentIndex + 1) % items.length;
2577
+ });
2578
+ const movePrev = () => setSelectedIndex((currentIndex) => {
2579
+ if (currentIndex === -1) return items.length - 1;
2580
+ return (currentIndex - 1 + items.length) % items.length;
2581
+ });
2582
+ switch (event.key) {
2583
+ case "ArrowUp":
2584
+ if (orientation === "horizontal") return false;
2585
+ event.preventDefault();
2586
+ movePrev();
2587
+ return true;
2588
+ case "ArrowDown":
2589
+ if (orientation === "horizontal") return false;
2590
+ event.preventDefault();
2591
+ moveNext();
2592
+ return true;
2593
+ case "ArrowLeft":
2594
+ if (orientation === "vertical") return false;
2595
+ event.preventDefault();
2596
+ movePrev();
2597
+ return true;
2598
+ case "ArrowRight":
2599
+ if (orientation === "vertical") return false;
2600
+ event.preventDefault();
2601
+ moveNext();
2602
+ return true;
2603
+ case "Tab":
2604
+ if (!loopOnTab) return false;
2605
+ event.preventDefault();
2606
+ if (event.shiftKey) movePrev();
2607
+ else moveNext();
2608
+ return true;
2609
+ case "Home":
2610
+ event.preventDefault();
2611
+ setSelectedIndex(0);
2612
+ return true;
2613
+ case "End":
2614
+ event.preventDefault();
2615
+ setSelectedIndex(items.length - 1);
2616
+ return true;
2617
+ case "Enter":
2618
+ if (event.isComposing) return false;
2619
+ event.preventDefault();
2620
+ if (selectedIndex !== -1 && items[selectedIndex]) onSelect?.(items[selectedIndex]);
2621
+ return true;
2622
+ case "Escape":
2623
+ if (!onClose) return false;
2624
+ event.preventDefault();
2625
+ onClose?.();
2626
+ return true;
2627
+ default: return false;
2628
+ }
2629
+ };
2630
+ let targetElement = null;
2631
+ if (editor) targetElement = editor.view.dom;
2632
+ else if (containerRef?.current) targetElement = containerRef.current;
2633
+ if (targetElement) {
2634
+ targetElement.addEventListener("keydown", handleKeyboardNavigation, true);
2635
+ return () => {
2636
+ targetElement?.removeEventListener("keydown", handleKeyboardNavigation, true);
2637
+ };
2638
+ }
2639
+ }, [
2640
+ editor,
2641
+ containerRef,
2642
+ items,
2643
+ selectedIndex,
2644
+ onSelect,
2645
+ onClose,
2646
+ orientation,
2647
+ loopOnTab
2648
+ ]);
2649
+ useEffect(() => {
2650
+ if (query) setSelectedIndex(autoSelectFirstItem ? 0 : -1);
2651
+ }, [query, autoSelectFirstItem]);
2652
+ return {
2653
+ selectedIndex: items.length ? selectedIndex : void 0,
2654
+ setSelectedIndex
2655
+ };
2656
+ }
2657
+ //#endregion
2658
+ //#region src/tiptap/components/ui-primitive/toolbar/toolbar.tsx
2659
+ var useToolbarNavigation = (toolbarRef) => {
2660
+ const [items, setItems] = useState([]);
2661
+ const initialContainerTabIndexRef = useRef(void 0);
2662
+ const collectItems = useCallback(() => {
2663
+ if (!toolbarRef.current) return [];
2664
+ return Array.from(toolbarRef.current.querySelectorAll("button:not([disabled]), [role=\"button\"]:not([disabled]), [tabindex=\"0\"]:not([disabled])"));
2665
+ }, [toolbarRef]);
2666
+ useEffect(() => {
2667
+ const toolbar = toolbarRef.current;
2668
+ if (!toolbar) return;
2669
+ if (initialContainerTabIndexRef.current === void 0) initialContainerTabIndexRef.current = toolbar.hasAttribute("tabindex") && toolbar.tabIndex >= 0 ? toolbar.tabIndex : null;
2670
+ const updateItems = () => setItems(collectItems());
2671
+ updateItems();
2672
+ const observer = new MutationObserver(updateItems);
2673
+ observer.observe(toolbar, {
2674
+ childList: true,
2675
+ subtree: true,
2676
+ attributes: true,
2677
+ attributeFilter: ["disabled"]
2678
+ });
2679
+ return () => observer.disconnect();
2680
+ }, [collectItems, toolbarRef]);
2681
+ const { selectedIndex, setSelectedIndex } = useMenuNavigation({
2682
+ containerRef: toolbarRef,
2683
+ items,
2684
+ orientation: "horizontal",
2685
+ onSelect: (el) => el.click(),
2686
+ autoSelectFirstItem: false,
2687
+ loopOnTab: false
2688
+ });
2689
+ useEffect(() => {
2690
+ const toolbar = toolbarRef.current;
2691
+ if (!toolbar) return;
2692
+ const handleFocus = (e) => {
2693
+ const target = e.target;
2694
+ if (toolbar.contains(target)) {
2695
+ target.setAttribute("data-focus-visible", "true");
2696
+ const itemIndex = items.indexOf(target);
2697
+ if (itemIndex >= 0) setSelectedIndex(itemIndex);
2698
+ }
2699
+ };
2700
+ const handleBlur = (e) => {
2701
+ const target = e.target;
2702
+ if (toolbar.contains(target)) target.removeAttribute("data-focus-visible");
2703
+ const nextTarget = e.relatedTarget;
2704
+ const NodeConstructor = toolbar.ownerDocument.defaultView?.Node;
2705
+ if ((!nextTarget || !NodeConstructor || !(nextTarget instanceof NodeConstructor) || !toolbar.contains(nextTarget)) && initialContainerTabIndexRef.current != null) queueMicrotask(() => {
2706
+ if (toolbar.isConnected && !toolbar.contains(toolbar.ownerDocument.activeElement)) {
2707
+ toolbar.tabIndex = initialContainerTabIndexRef.current;
2708
+ setSelectedIndex(-1);
2709
+ }
2710
+ });
2711
+ };
2712
+ toolbar.addEventListener("focus", handleFocus, true);
2713
+ toolbar.addEventListener("blur", handleBlur, true);
2714
+ return () => {
2715
+ toolbar.removeEventListener("focus", handleFocus, true);
2716
+ toolbar.removeEventListener("blur", handleBlur, true);
2717
+ };
2718
+ }, [
2719
+ items,
2720
+ setSelectedIndex,
2721
+ toolbarRef
2722
+ ]);
2723
+ useEffect(() => {
2724
+ if (!items.length) return;
2725
+ const toolbar = toolbarRef.current;
2726
+ if (!toolbar) return;
2727
+ const activeEl = toolbar.ownerDocument.activeElement;
2728
+ if (activeEl && !toolbar.contains(activeEl)) return;
2729
+ const initialContainerTabIndex = initialContainerTabIndexRef.current;
2730
+ const currentIndex = selectedIndex ?? -1;
2731
+ if (initialContainerTabIndex != null) {
2732
+ items.forEach((item) => {
2733
+ item.tabIndex = -1;
2734
+ });
2735
+ if (currentIndex >= 0 && items[currentIndex]) {
2736
+ toolbar.tabIndex = -1;
2737
+ items[currentIndex].focus();
2738
+ } else toolbar.tabIndex = initialContainerTabIndex;
2739
+ return;
2740
+ }
2741
+ const existingTabStop = items.findIndex((item) => item.tabIndex === 0);
2742
+ const activeIndex = currentIndex >= 0 && items[currentIndex] ? currentIndex : existingTabStop >= 0 ? existingTabStop : 0;
2743
+ items.forEach((item, index) => {
2744
+ item.tabIndex = index === activeIndex ? 0 : -1;
2745
+ });
2746
+ if (currentIndex >= 0) items[activeIndex]?.focus();
2747
+ }, [
2748
+ selectedIndex,
2749
+ items,
2750
+ toolbarRef
2751
+ ]);
2752
+ };
2753
+ var Toolbar = forwardRef(({ children, className, variant = "fixed", ...props }, ref) => {
2754
+ const toolbarRef = useRef(null);
2755
+ const composedRef = useComposedRef(toolbarRef, ref);
2756
+ useToolbarNavigation(toolbarRef);
2757
+ return /* @__PURE__ */ jsx("div", {
2758
+ ref: composedRef,
2759
+ role: "toolbar",
2760
+ "aria-label": "toolbar",
2761
+ "data-variant": variant,
2762
+ className: cn("tiptap-toolbar", className),
2763
+ ...props,
2764
+ children
2765
+ });
2766
+ });
2767
+ Toolbar.displayName = "Toolbar";
2768
+ var ToolbarGroup = forwardRef(({ children, className, ...props }, ref) => /* @__PURE__ */ jsx("div", {
2769
+ ref,
2770
+ role: "group",
2771
+ className: cn("tiptap-toolbar-group", className),
2772
+ ...props,
2773
+ children
2774
+ }));
2775
+ ToolbarGroup.displayName = "ToolbarGroup";
2776
+ var ToolbarSeparator = () => /* @__PURE__ */ jsx(Divider, {
2777
+ orientation: "vertical",
2778
+ flexItem: true,
2779
+ sx: { my: 1 }
2780
+ });
2781
+ ToolbarSeparator.displayName = "ToolbarSeparator";
2782
+ //#endregion
2783
+ //#region src/tiptap/components/ui-primitive/formatting-controls/formatting-controls.tsx
2784
+ var FormattingControls = ({ editor }) => {
2785
+ const hasSuperscriptSubscript = editor.extensionManager.extensions.map((e) => e.name).some((name) => name === "subscript" || name === "superscript");
2786
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
2787
+ /* @__PURE__ */ jsxs(ToolbarGroup, { children: [/* @__PURE__ */ jsx(UndoRedoButton, { action: "undo" }), /* @__PURE__ */ jsx(UndoRedoButton, { action: "redo" })] }),
2788
+ /* @__PURE__ */ jsx(ToolbarSeparator, {}),
2789
+ /* @__PURE__ */ jsxs(ToolbarGroup, { children: [
2790
+ /* @__PURE__ */ jsx(HeadingMenu, {
2791
+ modal: false,
2792
+ levels: [
2793
+ 1,
2794
+ 2,
2795
+ 3,
2796
+ 4
2797
+ ]
2798
+ }),
2799
+ /* @__PURE__ */ jsx(ListButton, { type: "bulletList" }),
2800
+ /* @__PURE__ */ jsx(ListButton, { type: "orderedList" }),
2801
+ /* @__PURE__ */ jsx(BlockquoteButton, {}),
2802
+ /* @__PURE__ */ jsx(CodeBlockButton, {})
2803
+ ] }),
2804
+ /* @__PURE__ */ jsx(ToolbarSeparator, {}),
2805
+ /* @__PURE__ */ jsxs(ToolbarGroup, { children: [
2806
+ /* @__PURE__ */ jsx(MarkButton, { type: "bold" }),
2807
+ /* @__PURE__ */ jsx(MarkButton, { type: "italic" }),
2808
+ /* @__PURE__ */ jsx(MarkButton, { type: "strike" }),
2809
+ /* @__PURE__ */ jsx(MarkButton, { type: "code" }),
2810
+ /* @__PURE__ */ jsx(MarkButton, { type: "underline" }),
2811
+ /* @__PURE__ */ jsx(LinkPopover, {})
2812
+ ] }),
2813
+ hasSuperscriptSubscript ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ToolbarSeparator, {}), /* @__PURE__ */ jsxs(ToolbarGroup, { children: [/* @__PURE__ */ jsx(MarkButton, { type: "superscript" }), /* @__PURE__ */ jsx(MarkButton, { type: "subscript" })] })] }) : null,
2814
+ /* @__PURE__ */ jsx(ToolbarSeparator, {}),
2815
+ /* @__PURE__ */ jsxs(ToolbarGroup, { children: [
2816
+ /* @__PURE__ */ jsx(TextAlignButton, { align: "left" }),
2817
+ /* @__PURE__ */ jsx(TextAlignButton, { align: "center" }),
2818
+ /* @__PURE__ */ jsx(TextAlignButton, { align: "right" }),
2819
+ /* @__PURE__ */ jsx(TextAlignButton, { align: "justify" })
2820
+ ] })
2821
+ ] });
2822
+ };
2823
+ FormattingControls.displayName = "FormattingControls";
2824
+ //#endregion
2825
+ //#region src/tiptap/components/ui-primitive/spacer/spacer.tsx
2826
+ function Spacer({ orientation = "horizontal", size, style = {}, ...props }) {
2827
+ const computedStyle = {
2828
+ ...style,
2829
+ ...orientation === "horizontal" && !size && { flex: 1 },
2830
+ ...size && {
2831
+ width: orientation === "vertical" ? "1px" : size,
2832
+ height: orientation === "horizontal" ? "1px" : size
2833
+ }
2834
+ };
2835
+ return /* @__PURE__ */ jsx("div", {
2836
+ ...props,
2837
+ style: computedStyle
2838
+ });
2839
+ }
2840
+ //#endregion
2841
+ export { FormattingControls, Spacer, Toolbar, ToolbarGroup, ToolbarSeparator };
2842
+
2843
+ //# sourceMappingURL=index.es.js.map