@elia-ori/editor 0.1.27 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,17 +30,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- Callout: () => Callout,
34
33
  EliaEditor: () => EliaEditor,
34
+ EliaEditorProvider: () => EliaEditorProvider,
35
35
  SimpleEditor: () => EliaEditor,
36
+ TocSidebar: () => TocSidebar,
36
37
  contentExtensions: () => contentExtensions,
37
- generateEditorHTML: () => generateEditorHTML
38
+ generateEditorHTML: () => generateEditorHTML,
39
+ useEliaEditor: () => useEliaEditor
38
40
  });
39
41
  module.exports = __toCommonJS(index_exports);
40
42
 
41
43
  // src/components/tiptap-templates/simple/simple-editor.tsx
42
- var import_react86 = require("react");
43
- var import_react87 = require("@tiptap/react");
44
+ var import_react101 = require("react");
45
+ var import_react102 = require("@tiptap/react");
44
46
  var import_starter_kit = require("@tiptap/starter-kit");
45
47
  var import_extension_list = require("@tiptap/extension-list");
46
48
  var import_extension_text_align = require("@tiptap/extension-text-align");
@@ -56,72 +58,9 @@ var import_extension_table = require("@tiptap/extension-table");
56
58
  var import_extension_table_row = require("@tiptap/extension-table-row");
57
59
  var import_extension_table_header = require("@tiptap/extension-table-header");
58
60
  var import_extension_table_cell = require("@tiptap/extension-table-cell");
61
+ var import_extension_unique_id = require("@tiptap/extension-unique-id");
59
62
  var import_tiptap_extension_resize_image = __toESM(require("tiptap-extension-resize-image"), 1);
60
63
 
61
- // src/extensions/callout.ts
62
- var import_core = require("@tiptap/core");
63
- var CALLOUT_ARIA_LABELS = {
64
- success: "\u6210\u529F\u63D0\u793A",
65
- warning: "\u8B66\u544A\u63D0\u793A",
66
- error: "\u932F\u8AA4\u63D0\u793A",
67
- info: "\u8CC7\u8A0A\u63D0\u793A"
68
- };
69
- var Callout = import_core.Node.create({
70
- name: "callout",
71
- group: "block",
72
- content: "block+",
73
- defining: true,
74
- addOptions() {
75
- return {
76
- HTMLAttributes: {}
77
- };
78
- },
79
- addAttributes() {
80
- return {
81
- type: {
82
- default: "info",
83
- parseHTML: (element) => element.getAttribute("data-type"),
84
- renderHTML: (attributes) => ({
85
- "data-type": attributes.type
86
- })
87
- }
88
- };
89
- },
90
- parseHTML() {
91
- return [
92
- {
93
- tag: "div[data-callout]"
94
- }
95
- ];
96
- },
97
- renderHTML({ node, HTMLAttributes }) {
98
- const type = node.attrs.type || "info";
99
- return [
100
- "div",
101
- (0, import_core.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, {
102
- "data-callout": "",
103
- "class": `callout callout-${type}`,
104
- "role": "note",
105
- "aria-label": CALLOUT_ARIA_LABELS[type]
106
- }),
107
- 0
108
- ];
109
- },
110
- addCommands() {
111
- return {
112
- setCallout: (attributes) => ({ commands }) => {
113
- return commands.wrapIn(this.name, attributes);
114
- },
115
- toggleCallout: (attributes) => ({ commands }) => {
116
- return commands.toggleWrap(this.name, attributes);
117
- },
118
- unsetCallout: () => ({ commands }) => {
119
- return commands.lift(this.name);
120
- }
121
- };
122
- }
123
- });
124
-
125
64
  // src/components/tiptap-ui-primitive/button/button.tsx
126
65
  var import_react4 = require("react");
127
66
 
@@ -232,7 +171,6 @@ var TooltipTrigger = (0, import_react.forwardRef)(
232
171
  "button",
233
172
  {
234
173
  ref,
235
- type: "button",
236
174
  "data-tooltip-state": context.open ? "open" : "closed",
237
175
  ...context.getReferenceProps(props),
238
176
  children
@@ -437,36 +375,22 @@ function selectionWithinConvertibleTypes(editor, types = []) {
437
375
  return false;
438
376
  }
439
377
  var handleImageUpload = async (file, onProgress, abortSignal) => {
440
- if (!file) throw new Error("No file provided");
441
- const formData = new FormData();
442
- formData.append("file", file);
443
- return new Promise((resolve, reject) => {
444
- const xhr = new XMLHttpRequest();
445
- if (onProgress) {
446
- xhr.upload.onprogress = (e) => {
447
- if (e.lengthComputable) {
448
- onProgress({ progress: Math.round(e.loaded / e.total * 100) });
449
- }
450
- };
378
+ if (!file) {
379
+ throw new Error("No file provided");
380
+ }
381
+ if (file.size > MAX_FILE_SIZE) {
382
+ throw new Error(
383
+ `File size exceeds maximum allowed (${MAX_FILE_SIZE / (1024 * 1024)}MB)`
384
+ );
385
+ }
386
+ for (let progress = 0; progress <= 100; progress += 10) {
387
+ if (abortSignal?.aborted) {
388
+ throw new Error("Upload cancelled");
451
389
  }
452
- xhr.onload = () => {
453
- if (xhr.status >= 200 && xhr.status < 300) {
454
- try {
455
- const { data } = JSON.parse(xhr.responseText);
456
- resolve(data.url);
457
- } catch {
458
- reject(new Error("Invalid response format"));
459
- }
460
- } else {
461
- reject(new Error(`Upload failed: ${xhr.status}`));
462
- }
463
- };
464
- xhr.onerror = () => reject(new Error("Network error"));
465
- xhr.onabort = () => reject(new Error("Upload cancelled"));
466
- abortSignal?.addEventListener("abort", () => xhr.abort());
467
- xhr.open("POST", "/api/upload");
468
- xhr.send(formData);
469
- });
390
+ await new Promise((resolve) => setTimeout(resolve, 500));
391
+ onProgress?.({ progress });
392
+ }
393
+ return "/images/tiptap-ui-placeholder-image.jpg";
470
394
  };
471
395
  var ATTR_WHITESPACE = (
472
396
  // eslint-disable-next-line no-control-regex
@@ -511,6 +435,34 @@ function sanitizeUrl(inputUrl, baseUrl, protocols) {
511
435
  }
512
436
  return "#";
513
437
  }
438
+ function selectCurrentBlockContent(editor) {
439
+ const { selection, doc } = editor.state;
440
+ if (!selection.empty) return;
441
+ const $pos = selection.$from;
442
+ let blockNode = null;
443
+ let blockPos = -1;
444
+ for (let depth = $pos.depth; depth >= 0; depth--) {
445
+ const node = $pos.node(depth);
446
+ const pos = $pos.start(depth);
447
+ if (node.isBlock && node.textContent.trim()) {
448
+ blockNode = node;
449
+ blockPos = pos;
450
+ break;
451
+ }
452
+ }
453
+ if (blockNode && blockPos >= 0) {
454
+ const from = blockPos;
455
+ const to = blockPos + blockNode.nodeSize - 2;
456
+ if (from < to) {
457
+ const $from = doc.resolve(from);
458
+ const $to = doc.resolve(to);
459
+ const newSelection = import_state.TextSelection.between($from, $to, 1);
460
+ if (newSelection && !selection.eq(newSelection)) {
461
+ editor.view.dispatch(editor.state.tr.setSelection(newSelection));
462
+ }
463
+ }
464
+ }
465
+ }
514
466
  function getSelectedBlockNodes(editor) {
515
467
  const { doc } = editor.state;
516
468
  const { from, to } = editor.state.selection;
@@ -1996,7 +1948,7 @@ function useHeading(config) {
1996
1948
  isActive,
1997
1949
  handleToggle,
1998
1950
  canToggle: canToggleState,
1999
- label: `\u6A19\u984C ${level}`,
1951
+ label: `Heading ${level}`,
2000
1952
  shortcutKeys: HEADING_SHORTCUT_KEYS[level],
2001
1953
  Icon: headingIcons[level]
2002
1954
  };
@@ -2031,7 +1983,7 @@ var DropdownMenuSubContent = (0, import_react27.forwardRef)(({ className, portal
2031
1983
  return portal ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DropdownMenuPortal, { ...typeof portal === "object" ? portal : {}, children: content }) : content;
2032
1984
  });
2033
1985
  DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
2034
- var DropdownMenuContent = (0, import_react27.forwardRef)(({ className, sideOffset = 4, portal = true, ...props }, ref) => {
1986
+ var DropdownMenuContent = (0, import_react27.forwardRef)(({ className, sideOffset = 4, portal = false, ...props }, ref) => {
2035
1987
  const content = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2036
1988
  DropdownMenuPrimitive.Content,
2037
1989
  {
@@ -2755,9 +2707,9 @@ var listIcons = {
2755
2707
  taskList: ListTodoIcon
2756
2708
  };
2757
2709
  var listLabels = {
2758
- bulletList: "\u9805\u76EE\u6E05\u55AE",
2759
- orderedList: "\u7DE8\u865F\u6E05\u55AE",
2760
- taskList: "\u5F85\u8FA6\u6E05\u55AE"
2710
+ bulletList: "Bullet List",
2711
+ orderedList: "Ordered List",
2712
+ taskList: "Task List"
2761
2713
  };
2762
2714
  var LIST_SHORTCUT_KEYS = {
2763
2715
  bulletList: "mod+shift+8",
@@ -3126,7 +3078,7 @@ var BlockquoteButton = (0, import_react43.forwardRef)(
3126
3078
  "data-disabled": !canToggle3,
3127
3079
  "aria-label": label,
3128
3080
  "aria-pressed": isActive,
3129
- tooltip: "\u5F15\u7528",
3081
+ tooltip: "Blockquote",
3130
3082
  onClick: handleClick,
3131
3083
  ...buttonProps,
3132
3084
  ref,
@@ -3312,7 +3264,7 @@ function useBlockquote(config) {
3312
3264
  isActive,
3313
3265
  handleToggle,
3314
3266
  canToggle: canToggle3,
3315
- label: "\u5F15\u7528",
3267
+ label: "Blockquote",
3316
3268
  shortcutKeys: BLOCKQUOTE_SHORTCUT_KEY,
3317
3269
  Icon: BlockquoteIcon
3318
3270
  };
@@ -3374,7 +3326,7 @@ var CodeBlockButton = (0, import_react46.forwardRef)(
3374
3326
  tabIndex: -1,
3375
3327
  "aria-label": label,
3376
3328
  "aria-pressed": isActive,
3377
- tooltip: "\u7A0B\u5F0F\u78BC",
3329
+ tooltip: "Code Block",
3378
3330
  onClick: handleClick,
3379
3331
  ...buttonProps,
3380
3332
  ref,
@@ -3551,7 +3503,7 @@ function useCodeBlock(config) {
3551
3503
  isActive,
3552
3504
  handleToggle,
3553
3505
  canToggle: canToggleState,
3554
- label: "\u7A0B\u5F0F\u78BC",
3506
+ label: "Code Block",
3555
3507
  shortcutKeys: CODE_BLOCK_SHORTCUT_KEY,
3556
3508
  Icon: CodeBlockIcon
3557
3509
  };
@@ -3742,52 +3694,52 @@ var import_react_hotkeys_hook2 = require("react-hotkeys-hook");
3742
3694
  var COLOR_HIGHLIGHT_SHORTCUT_KEY = "mod+shift+h";
3743
3695
  var HIGHLIGHT_COLORS = [
3744
3696
  {
3745
- label: "\u9810\u8A2D\u80CC\u666F",
3697
+ label: "Default background",
3746
3698
  value: "var(--tt-bg-color)",
3747
3699
  border: "var(--tt-bg-color-contrast)"
3748
3700
  },
3749
3701
  {
3750
- label: "\u7070\u8272\u80CC\u666F",
3702
+ label: "Gray background",
3751
3703
  value: "var(--tt-color-highlight-gray)",
3752
3704
  border: "var(--tt-color-highlight-gray-contrast)"
3753
3705
  },
3754
3706
  {
3755
- label: "\u68D5\u8272\u80CC\u666F",
3707
+ label: "Brown background",
3756
3708
  value: "var(--tt-color-highlight-brown)",
3757
3709
  border: "var(--tt-color-highlight-brown-contrast)"
3758
3710
  },
3759
3711
  {
3760
- label: "\u6A58\u8272\u80CC\u666F",
3712
+ label: "Orange background",
3761
3713
  value: "var(--tt-color-highlight-orange)",
3762
3714
  border: "var(--tt-color-highlight-orange-contrast)"
3763
3715
  },
3764
3716
  {
3765
- label: "\u9EC3\u8272\u80CC\u666F",
3717
+ label: "Yellow background",
3766
3718
  value: "var(--tt-color-highlight-yellow)",
3767
3719
  border: "var(--tt-color-highlight-yellow-contrast)"
3768
3720
  },
3769
3721
  {
3770
- label: "\u7DA0\u8272\u80CC\u666F",
3722
+ label: "Green background",
3771
3723
  value: "var(--tt-color-highlight-green)",
3772
3724
  border: "var(--tt-color-highlight-green-contrast)"
3773
3725
  },
3774
3726
  {
3775
- label: "\u85CD\u8272\u80CC\u666F",
3727
+ label: "Blue background",
3776
3728
  value: "var(--tt-color-highlight-blue)",
3777
3729
  border: "var(--tt-color-highlight-blue-contrast)"
3778
3730
  },
3779
3731
  {
3780
- label: "\u7D2B\u8272\u80CC\u666F",
3732
+ label: "Purple background",
3781
3733
  value: "var(--tt-color-highlight-purple)",
3782
3734
  border: "var(--tt-color-highlight-purple-contrast)"
3783
3735
  },
3784
3736
  {
3785
- label: "\u7C89\u7D05\u80CC\u666F",
3737
+ label: "Pink background",
3786
3738
  value: "var(--tt-color-highlight-pink)",
3787
3739
  border: "var(--tt-color-highlight-pink-contrast)"
3788
3740
  },
3789
3741
  {
3790
- label: "\u7D05\u8272\u80CC\u666F",
3742
+ label: "Red background",
3791
3743
  value: "var(--tt-color-highlight-red)",
3792
3744
  border: "var(--tt-color-highlight-red-contrast)"
3793
3745
  }
@@ -3913,7 +3865,7 @@ function useColorHighlight(config) {
3913
3865
  const handleRemoveHighlight = (0, import_react52.useCallback)(() => {
3914
3866
  const success = removeHighlight(editor, mode);
3915
3867
  if (success) {
3916
- onApplied?.({ color: "", label: "\u79FB\u9664\u87A2\u5149\u6A19\u8A18", mode });
3868
+ onApplied?.({ color: "", label: "Remove highlight", mode });
3917
3869
  }
3918
3870
  return success;
3919
3871
  }, [editor, onApplied, mode]);
@@ -3935,7 +3887,7 @@ function useColorHighlight(config) {
3935
3887
  handleColorHighlight,
3936
3888
  handleRemoveHighlight,
3937
3889
  canColorHighlight: canColorHighlightState,
3938
- label: label || `\u87A2\u5149\u6A19\u8A18`,
3890
+ label: label || `Highlight`,
3939
3891
  shortcutKeys: COLOR_HIGHLIGHT_SHORTCUT_KEY,
3940
3892
  Icon: HighlighterIcon,
3941
3893
  mode
@@ -5538,300 +5490,42 @@ function useUndoRedo(config) {
5538
5490
  };
5539
5491
  }
5540
5492
 
5541
- // src/components/tiptap-ui/callout-button/callout-button.tsx
5542
- var React = __toESM(require("react"), 1);
5493
+ // src/components/tiptap-node/table-node/ui/table-trigger-button/table-grid-selector.tsx
5494
+ var import_react81 = require("react");
5495
+
5496
+ // src/components/tiptap-icons/table-column-icon.tsx
5497
+ var import_react79 = require("react");
5543
5498
  var import_jsx_runtime59 = require("react/jsx-runtime");
5544
- var CALLOUT_OPTIONS = [
5545
- { type: "success", label: "\u6210\u529F\u63D0\u793A", className: "callout-option--success" },
5546
- { type: "warning", label: "\u8B66\u544A\u63D0\u793A", className: "callout-option--warning" },
5547
- { type: "error", label: "\u932F\u8AA4\u63D0\u793A", className: "callout-option--error" },
5548
- { type: "info", label: "\u8CC7\u8A0A\u63D0\u793A", className: "callout-option--info" }
5549
- ];
5550
- function CalloutButton({ portal = true }) {
5551
- const { editor } = useTiptapEditor();
5552
- const [isOpen, setIsOpen] = React.useState(false);
5553
- const [isVisible, setIsVisible] = React.useState(true);
5554
- React.useEffect(() => {
5555
- if (!editor) return;
5556
- setIsVisible(editor.isEditable);
5557
- }, [editor]);
5558
- const handleSelect = React.useCallback(
5559
- (type) => {
5560
- if (!editor) return;
5561
- editor.chain().focus().setCallout({ type }).run();
5562
- setIsOpen(false);
5563
- },
5564
- [editor]
5565
- );
5566
- if (!isVisible) return null;
5567
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
5568
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)(
5569
- Button,
5570
- {
5571
- "data-style": "ghost",
5572
- "data-active-state": isOpen ? "on" : "off",
5573
- disabled: !editor,
5574
- tooltip: "\u63D0\u793A\u6846",
5575
- "aria-label": "\u63D0\u793A\u6846",
5576
- children: [
5577
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(CalloutIcon, { className: "tiptap-button-icon" }),
5578
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(ChevronDownIcon, { className: "tiptap-button-icon" })
5579
- ]
5580
- }
5581
- ) }),
5582
- /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(DropdownMenuContent, { portal, children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(CardBody, { children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "callout-options", children: CALLOUT_OPTIONS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
5583
- "button",
5584
- {
5585
- type: "button",
5586
- className: `callout-option ${option.className}`,
5587
- onClick: () => handleSelect(option.type),
5588
- title: option.label,
5589
- "aria-label": option.label
5590
- },
5591
- option.type
5592
- )) }) }) }) })
5593
- ] });
5594
- }
5595
- function CalloutIcon({ className }) {
5499
+ var TableColumnIcon = (0, import_react79.memo)(({ className, ...props }) => {
5596
5500
  return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
5597
5501
  "svg",
5598
5502
  {
5599
- xmlns: "http://www.w3.org/2000/svg",
5600
- width: "18",
5601
- height: "18",
5602
- viewBox: "0 0 24 24",
5603
- fill: "none",
5604
- stroke: "currentColor",
5605
- strokeWidth: "2",
5606
- strokeLinecap: "round",
5607
- strokeLinejoin: "round",
5503
+ width: "24",
5504
+ height: "24",
5608
5505
  className,
5609
- children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
5610
- }
5611
- );
5612
- }
5613
-
5614
- // src/components/tiptap-ui/table-button/table-button.tsx
5615
- var React2 = __toESM(require("react"), 1);
5616
- var import_jsx_runtime60 = require("react/jsx-runtime");
5617
- var GRID_SIZE = 6;
5618
- var TOTAL_CELLS = GRID_SIZE * GRID_SIZE;
5619
- function TableButton({ portal = true }) {
5620
- const { editor } = useTiptapEditor();
5621
- const [isOpen, setIsOpen] = React2.useState(false);
5622
- const [isVisible, setIsVisible] = React2.useState(true);
5623
- const [hoveredCell, setHoveredCell] = React2.useState(null);
5624
- React2.useEffect(() => {
5625
- if (!editor) return;
5626
- setIsVisible(editor.isEditable);
5627
- }, [editor]);
5628
- const isInTable = editor?.isActive("table") ?? false;
5629
- const insertTable = React2.useCallback((rows, cols) => {
5630
- if (!editor) return;
5631
- editor.chain().focus().insertTable({ rows, cols, withHeaderRow: true }).run();
5632
- setIsOpen(false);
5633
- setHoveredCell(null);
5634
- }, [editor]);
5635
- const addRowBefore = React2.useCallback(() => {
5636
- if (!editor) return;
5637
- editor.chain().focus().addRowBefore().run();
5638
- setIsOpen(false);
5639
- }, [editor]);
5640
- const addRowAfter = React2.useCallback(() => {
5641
- if (!editor) return;
5642
- editor.chain().focus().addRowAfter().run();
5643
- setIsOpen(false);
5644
- }, [editor]);
5645
- const addColumnBefore = React2.useCallback(() => {
5646
- if (!editor) return;
5647
- editor.chain().focus().addColumnBefore().run();
5648
- setIsOpen(false);
5649
- }, [editor]);
5650
- const addColumnAfter = React2.useCallback(() => {
5651
- if (!editor) return;
5652
- editor.chain().focus().addColumnAfter().run();
5653
- setIsOpen(false);
5654
- }, [editor]);
5655
- const deleteRow = React2.useCallback(() => {
5656
- if (!editor) return;
5657
- editor.chain().focus().deleteRow().run();
5658
- setIsOpen(false);
5659
- }, [editor]);
5660
- const deleteColumn = React2.useCallback(() => {
5661
- if (!editor) return;
5662
- editor.chain().focus().deleteColumn().run();
5663
- setIsOpen(false);
5664
- }, [editor]);
5665
- const deleteTable = React2.useCallback(() => {
5666
- if (!editor) return;
5667
- editor.chain().focus().deleteTable().run();
5668
- setIsOpen(false);
5669
- }, [editor]);
5670
- const handleOpenChange = React2.useCallback((open) => {
5671
- setIsOpen(open);
5672
- if (!open) {
5673
- setHoveredCell(null);
5674
- }
5675
- }, []);
5676
- if (!isVisible) return null;
5677
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(DropdownMenu, { open: isOpen, onOpenChange: handleOpenChange, children: [
5678
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
5679
- Button,
5680
- {
5681
- "data-style": "ghost",
5682
- "data-active-state": isOpen || isInTable ? "on" : "off",
5683
- disabled: !editor,
5684
- tooltip: "\u8868\u683C",
5685
- "aria-label": "\u8868\u683C",
5686
- children: [
5687
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(TableIcon, { className: "tiptap-button-icon" }),
5688
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ChevronDownIcon, { className: "tiptap-button-icon" })
5689
- ]
5690
- }
5691
- ) }),
5692
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuContent, { portal, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(CardBody, { children: !isInTable ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "table-grid-picker", onMouseLeave: () => setHoveredCell(null), children: [
5693
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "table-grid", children: Array.from({ length: TOTAL_CELLS }).map((_, index) => {
5694
- const row = Math.floor(index / GRID_SIZE);
5695
- const col = index % GRID_SIZE;
5696
- const isSelected = hoveredCell && row <= hoveredCell.row && col <= hoveredCell.col;
5697
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
5698
- "div",
5699
- {
5700
- className: `table-grid-cell ${isSelected ? "is-selected" : ""}`,
5701
- onMouseEnter: () => setHoveredCell({ row, col }),
5702
- onClick: () => insertTable(row + 1, col + 1)
5703
- },
5704
- index
5705
- );
5706
- }) }),
5707
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "table-grid-size", children: hoveredCell ? `${hoveredCell.row + 1} x ${hoveredCell.col + 1}` : "" })
5708
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
5709
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuItem, { onSelect: addRowBefore, children: "\u4E0A\u65B9\u63D2\u5165\u5217" }),
5710
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuItem, { onSelect: addRowAfter, children: "\u4E0B\u65B9\u63D2\u5165\u5217" }),
5711
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuItem, { onSelect: addColumnBefore, children: "\u5DE6\u65B9\u63D2\u5165\u6B04" }),
5712
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuItem, { onSelect: addColumnAfter, children: "\u53F3\u65B9\u63D2\u5165\u6B04" }),
5713
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuItem, { onSelect: deleteRow, children: "\u522A\u9664\u5217" }),
5714
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuItem, { onSelect: deleteColumn, children: "\u522A\u9664\u6B04" }),
5715
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(DropdownMenuItem, { onSelect: deleteTable, children: "\u522A\u9664\u8868\u683C" })
5716
- ] }) }) }) })
5717
- ] });
5718
- }
5719
- TableButton.displayName = "TableButton";
5720
- function TableIcon({ className }) {
5721
- return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
5722
- "svg",
5723
- {
5724
- xmlns: "http://www.w3.org/2000/svg",
5725
- width: "18",
5726
- height: "18",
5727
5506
  viewBox: "0 0 24 24",
5728
- fill: "none",
5729
- stroke: "currentColor",
5730
- strokeWidth: "2",
5731
- strokeLinecap: "round",
5732
- strokeLinejoin: "round",
5733
- className,
5734
- children: [
5735
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("path", { d: "M12 3v18" }),
5736
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
5737
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("path", { d: "M3 9h18" }),
5738
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("path", { d: "M3 15h18" })
5739
- ]
5740
- }
5741
- );
5742
- }
5743
-
5744
- // src/components/tiptap-ui/text-color-button/text-color-button.tsx
5745
- var React3 = __toESM(require("react"), 1);
5746
- var import_jsx_runtime61 = require("react/jsx-runtime");
5747
- var TEXT_COLORS = [
5748
- { color: "inherit", label: "\u9810\u8A2D", className: "text-color--default" },
5749
- { color: "var(--tt-color-text-gray)", label: "\u7070\u8272", className: "text-color--gray" },
5750
- { color: "var(--tt-color-text-brown)", label: "\u68D5\u8272", className: "text-color--brown" },
5751
- { color: "var(--tt-color-text-orange)", label: "\u6A58\u8272", className: "text-color--orange" },
5752
- { color: "var(--tt-color-text-yellow)", label: "\u9EC3\u8272", className: "text-color--yellow" },
5753
- { color: "var(--tt-color-text-green)", label: "\u7DA0\u8272", className: "text-color--green" },
5754
- { color: "var(--tt-color-text-blue)", label: "\u85CD\u8272", className: "text-color--blue" },
5755
- { color: "var(--tt-color-text-purple)", label: "\u7D2B\u8272", className: "text-color--purple" },
5756
- { color: "var(--tt-color-text-pink)", label: "\u7C89\u7D05", className: "text-color--pink" },
5757
- { color: "var(--tt-color-text-red)", label: "\u7D05\u8272", className: "text-color--red" }
5758
- ];
5759
- function TextColorButton({ portal = true }) {
5760
- const { editor } = useTiptapEditor();
5761
- const [isOpen, setIsOpen] = React3.useState(false);
5762
- const [isVisible, setIsVisible] = React3.useState(true);
5763
- React3.useEffect(() => {
5764
- if (!editor) return;
5765
- setIsVisible(editor.isEditable);
5766
- }, [editor]);
5767
- const handleSelect = React3.useCallback(
5768
- (color) => {
5769
- if (!editor) return;
5770
- if (color === "inherit") {
5771
- editor.chain().focus().unsetColor().run();
5772
- } else {
5773
- editor.chain().focus().setColor(color).run();
5774
- }
5775
- setIsOpen(false);
5776
- },
5777
- [editor]
5778
- );
5779
- if (!isVisible) return null;
5780
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
5781
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
5782
- Button,
5783
- {
5784
- "data-style": "ghost",
5785
- "data-active-state": isOpen ? "on" : "off",
5786
- disabled: !editor,
5787
- children: [
5788
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(TextColorIcon, { className: "tiptap-button-icon" }),
5789
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(ChevronDownIcon, { className: "tiptap-button-icon" })
5790
- ]
5791
- }
5792
- ) }),
5793
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(DropdownMenuContent, { portal, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(CardBody, { children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "text-color-options", children: TEXT_COLORS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
5794
- "button",
5795
- {
5796
- type: "button",
5797
- className: `text-color-option ${option.className}`,
5798
- onClick: () => handleSelect(option.color),
5799
- title: option.label,
5800
- "aria-label": option.label,
5801
- children: "A"
5802
- },
5803
- option.color
5804
- )) }) }) }) })
5805
- ] });
5806
- }
5807
- function TextColorIcon({ className }) {
5808
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
5809
- "svg",
5810
- {
5507
+ fill: "currentColor",
5811
5508
  xmlns: "http://www.w3.org/2000/svg",
5812
- width: "18",
5813
- height: "18",
5814
- viewBox: "0 0 24 24",
5815
- fill: "none",
5816
- stroke: "currentColor",
5817
- strokeWidth: "2",
5818
- strokeLinecap: "round",
5819
- strokeLinejoin: "round",
5820
- className,
5821
- children: [
5822
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("path", { d: "M4 20h16" }),
5823
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("path", { d: "m6 16 6-12 6 12" }),
5824
- /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("path", { d: "M8 12h8" })
5825
- ]
5509
+ ...props,
5510
+ children: /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
5511
+ "path",
5512
+ {
5513
+ fillRule: "evenodd",
5514
+ clipRule: "evenodd",
5515
+ d: "M4 5C4 4.44772 4.44772 4 5 4H8V20H5C4.44772 20 4 19.5523 4 19V5ZM9 22H5C3.34315 22 2 20.6569 2 19V5C2 3.34315 3.34315 2 5 2H9H15H19C20.6569 2 22 3.34315 22 5V19C22 20.6569 20.6569 22 19 22H15H9ZM14 20H10V4H14V20ZM16 20H19C19.5523 20 20 19.5523 20 19V5C20 4.44772 19.5523 4 19 4H16V20Z",
5516
+ fill: "currentColor"
5517
+ }
5518
+ )
5826
5519
  }
5827
5520
  );
5828
- }
5521
+ });
5522
+ TableColumnIcon.displayName = "TableColumnIcon";
5829
5523
 
5830
- // src/components/tiptap-icons/arrow-left-icon.tsx
5831
- var import_react79 = require("react");
5832
- var import_jsx_runtime62 = require("react/jsx-runtime");
5833
- var ArrowLeftIcon = (0, import_react79.memo)(({ className, ...props }) => {
5834
- return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
5524
+ // src/components/tiptap-icons/table-row-icon.tsx
5525
+ var import_react80 = require("react");
5526
+ var import_jsx_runtime60 = require("react/jsx-runtime");
5527
+ var TableRowIcon = (0, import_react80.memo)(({ className, ...props }) => {
5528
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
5835
5529
  "svg",
5836
5530
  {
5837
5531
  width: "24",
@@ -5841,69 +5535,1322 @@ var ArrowLeftIcon = (0, import_react79.memo)(({ className, ...props }) => {
5841
5535
  fill: "currentColor",
5842
5536
  xmlns: "http://www.w3.org/2000/svg",
5843
5537
  ...props,
5844
- children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
5538
+ children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
5845
5539
  "path",
5846
5540
  {
5847
- d: "M12.7071 5.70711C13.0976 5.31658 13.0976 4.68342 12.7071 4.29289C12.3166 3.90237 11.6834 3.90237 11.2929 4.29289L4.29289 11.2929C3.90237 11.6834 3.90237 12.3166 4.29289 12.7071L11.2929 19.7071C11.6834 20.0976 12.3166 20.0976 12.7071 19.7071C13.0976 19.3166 13.0976 18.6834 12.7071 18.2929L7.41421 13L19 13C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11L7.41421 11L12.7071 5.70711Z",
5541
+ fillRule: "evenodd",
5542
+ clipRule: "evenodd",
5543
+ d: "M5 4C4.44772 4 4 4.44772 4 5V8H20V5C20 4.44772 19.5523 4 19 4H5ZM2 5V9V15V19C2 20.6569 3.34315 22 5 22H19C20.6569 22 22 20.6569 22 19V15V9V5C22 3.34315 20.6569 2 19 2H5C3.34315 2 2 3.34315 2 5ZM20 14V10H4V14H20ZM4 16H20V19C20 19.5523 19.5523 20 19 20H5C4.44772 20 4 19.5523 4 19V16Z",
5848
5544
  fill: "currentColor"
5849
5545
  }
5850
5546
  )
5851
5547
  }
5852
5548
  );
5853
5549
  });
5854
- ArrowLeftIcon.displayName = "ArrowLeftIcon";
5855
-
5856
- // src/hooks/use-window-size.ts
5857
- var import_react82 = require("react");
5550
+ TableRowIcon.displayName = "TableRowIcon";
5858
5551
 
5859
- // src/hooks/use-throttled-callback.ts
5860
- var import_lodash = __toESM(require("lodash.throttle"), 1);
5861
-
5862
- // src/hooks/use-unmount.ts
5863
- var import_react80 = require("react");
5864
- var useUnmount = (callback) => {
5865
- const ref = (0, import_react80.useRef)(callback);
5866
- ref.current = callback;
5867
- (0, import_react80.useEffect)(
5868
- () => () => {
5869
- ref.current();
5870
- },
5871
- []
5872
- );
5552
+ // src/components/tiptap-node/table-node/ui/table-trigger-button/table-grid-selector.tsx
5553
+ var import_jsx_runtime61 = require("react/jsx-runtime");
5554
+ var isCellSelected = (cell, hoveredCell) => {
5555
+ if (!hoveredCell) return false;
5556
+ return cell.row <= hoveredCell.row && cell.col <= hoveredCell.col;
5873
5557
  };
5874
-
5875
- // src/hooks/use-throttled-callback.ts
5876
- var import_react81 = require("react");
5877
- var defaultOptions = {
5878
- leading: false,
5879
- trailing: true
5558
+ var generateGridCells = (rows, cols) => {
5559
+ const totalCells = rows * cols;
5560
+ return Array.from({ length: totalCells }, (_, index) => ({
5561
+ row: Math.floor(index / cols),
5562
+ col: index % cols
5563
+ }));
5880
5564
  };
5881
- function useThrottledCallback(fn, wait = 250, dependencies = [], options = defaultOptions) {
5882
- const handler = (0, import_react81.useMemo)(
5883
- () => (0, import_lodash.default)(fn, wait, options),
5884
- // eslint-disable-next-line react-hooks/exhaustive-deps
5885
- dependencies
5886
- );
5887
- useUnmount(() => {
5888
- handler.cancel();
5889
- });
5890
- return handler;
5891
- }
5565
+ var GridCell = ({
5566
+ row,
5567
+ col,
5568
+ isSelected,
5569
+ disabled,
5570
+ onMouseEnter,
5571
+ onClick
5572
+ }) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
5573
+ Button,
5574
+ {
5575
+ "data-size": "small",
5576
+ type: "button",
5577
+ className: cn("tiptap-table-grid-cell", isSelected && "selected"),
5578
+ disabled,
5579
+ onMouseEnter,
5580
+ onClick,
5581
+ "aria-label": `Select ${row + 1}x${col + 1} table`
5582
+ }
5583
+ );
5584
+ var SizeIndicator = ({
5585
+ hoveredCell
5586
+ }) => {
5587
+ const columns = hoveredCell ? hoveredCell.col + 1 : 1;
5588
+ const rows = hoveredCell ? hoveredCell.row + 1 : 1;
5589
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "tiptap-table-size-indicator", children: [
5590
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "tiptap-table-size-indicator-item", children: [
5591
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(TableColumnIcon, { className: "tiptap-table-column-icon" }),
5592
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "tiptap-table-size-indicator-text", children: columns })
5593
+ ] }),
5594
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "tiptap-table-size-indicator-delimiter", children: "x" }),
5595
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "tiptap-table-size-indicator-item", children: [
5596
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(TableRowIcon, { className: "tiptap-table-row-icon" }),
5597
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "tiptap-table-size-indicator-text", children: rows })
5598
+ ] })
5599
+ ] });
5600
+ };
5601
+ var TableGridSelector = (0, import_react81.forwardRef)(
5602
+ ({
5603
+ maxRows = 8,
5604
+ maxCols = 8,
5605
+ hoveredCell,
5606
+ onCellHover,
5607
+ onCellClick,
5608
+ onMouseLeave,
5609
+ disabled = false,
5610
+ className,
5611
+ showSizeIndicator = true
5612
+ }, ref) => {
5613
+ const gridCells = (0, import_react81.useMemo)(
5614
+ () => generateGridCells(maxRows, maxCols),
5615
+ [maxRows, maxCols]
5616
+ );
5617
+ const gridStyle = (0, import_react81.useMemo)(
5618
+ () => ({
5619
+ "--tt-table-columns": maxCols,
5620
+ "--tt-table-rows": maxRows
5621
+ }),
5622
+ [maxCols, maxRows]
5623
+ );
5624
+ const handleCellHover = (0, import_react81.useCallback)(
5625
+ (row, col) => () => onCellHover(row, col),
5626
+ [onCellHover]
5627
+ );
5628
+ const handleCellClick = (0, import_react81.useCallback)(
5629
+ (row, col) => () => onCellClick(row, col),
5630
+ [onCellClick]
5631
+ );
5632
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
5633
+ /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
5634
+ "div",
5635
+ {
5636
+ ref,
5637
+ className: cn("tiptap-table-grid", className),
5638
+ onMouseLeave,
5639
+ style: gridStyle,
5640
+ children: gridCells.map((cell, index) => /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
5641
+ GridCell,
5642
+ {
5643
+ row: cell.row,
5644
+ col: cell.col,
5645
+ isSelected: isCellSelected(cell, hoveredCell),
5646
+ disabled,
5647
+ onMouseEnter: handleCellHover(cell.row, cell.col),
5648
+ onClick: handleCellClick(cell.row, cell.col)
5649
+ },
5650
+ index
5651
+ ))
5652
+ }
5653
+ ),
5654
+ showSizeIndicator && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(SizeIndicator, { hoveredCell })
5655
+ ] });
5656
+ }
5657
+ );
5658
+ TableGridSelector.displayName = "TableGridSelector";
5892
5659
 
5893
- // src/hooks/use-window-size.ts
5894
- function useWindowSize() {
5895
- const [windowSize, setWindowSize] = (0, import_react82.useState)({
5896
- width: 0,
5897
- height: 0,
5898
- offsetTop: 0,
5899
- offsetLeft: 0,
5900
- scale: 0
5901
- });
5902
- const handleViewportChange = useThrottledCallback(() => {
5903
- if (typeof window === "undefined") return;
5904
- const vp = window.visualViewport;
5905
- if (!vp) return;
5906
- const {
5660
+ // src/components/tiptap-node/table-node/ui/table-trigger-button/table-trigger-button.tsx
5661
+ var import_react82 = require("react");
5662
+ var import_jsx_runtime62 = require("react/jsx-runtime");
5663
+ var TableTriggerButton = (0, import_react82.forwardRef)(
5664
+ ({
5665
+ editor: providedEditor,
5666
+ hideWhenUnavailable = false,
5667
+ maxRows = 8,
5668
+ maxCols = 8,
5669
+ onInserted,
5670
+ text,
5671
+ children,
5672
+ ...buttonProps
5673
+ }, ref) => {
5674
+ const { editor } = useTiptapEditor(providedEditor);
5675
+ const {
5676
+ isVisible,
5677
+ canInsert,
5678
+ isOpen,
5679
+ setIsOpen,
5680
+ hoveredCell,
5681
+ handleCellHover,
5682
+ handleCellClick,
5683
+ resetHoveredCell,
5684
+ label,
5685
+ Icon
5686
+ } = useTableTriggerButton({
5687
+ editor,
5688
+ hideWhenUnavailable,
5689
+ maxRows,
5690
+ maxCols,
5691
+ onInserted
5692
+ });
5693
+ if (!isVisible) {
5694
+ return null;
5695
+ }
5696
+ return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
5697
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
5698
+ Button,
5699
+ {
5700
+ ref,
5701
+ type: "button",
5702
+ "data-style": "ghost",
5703
+ disabled: !canInsert,
5704
+ "data-disabled": !canInsert,
5705
+ "aria-label": label,
5706
+ tooltip: label,
5707
+ ...buttonProps,
5708
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(import_jsx_runtime62.Fragment, { children: [
5709
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Icon, { className: "tiptap-button-icon" }),
5710
+ text && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: "tiptap-button-text", children: text })
5711
+ ] })
5712
+ }
5713
+ ) }),
5714
+ /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(PopoverContent, { align: "start", side: "bottom", children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(CardBody, { children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
5715
+ TableGridSelector,
5716
+ {
5717
+ maxRows,
5718
+ maxCols,
5719
+ hoveredCell,
5720
+ onCellHover: handleCellHover,
5721
+ onCellClick: handleCellClick,
5722
+ onMouseLeave: resetHoveredCell,
5723
+ disabled: !canInsert
5724
+ }
5725
+ ) }) }) })
5726
+ ] });
5727
+ }
5728
+ );
5729
+ TableTriggerButton.displayName = "TableTriggerButton";
5730
+
5731
+ // src/components/tiptap-node/table-node/ui/table-trigger-button/use-table-trigger.ts
5732
+ var import_react84 = require("react");
5733
+
5734
+ // src/components/tiptap-icons/table-icon.tsx
5735
+ var import_react83 = require("react");
5736
+ var import_jsx_runtime63 = require("react/jsx-runtime");
5737
+ var TableIcon = (0, import_react83.memo)(({ className, ...props }) => {
5738
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5739
+ "svg",
5740
+ {
5741
+ width: "24",
5742
+ height: "24",
5743
+ className,
5744
+ viewBox: "0 0 24 24",
5745
+ fill: "currentColor",
5746
+ xmlns: "http://www.w3.org/2000/svg",
5747
+ ...props,
5748
+ children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
5749
+ "path",
5750
+ {
5751
+ fillRule: "evenodd",
5752
+ clipRule: "evenodd",
5753
+ d: "M2 5C2 3.34315 3.34315 2 5 2H19C20.6569 2 22 3.34315 22 5V19C22 20.6569 20.6569 22 19 22H5C3.34315 22 2 20.6569 2 19V5ZM4 5C4 4.44772 4.44772 4 5 4H11V8H4V5ZM4 10H11V14H4V10ZM20 14V10H13V14H20ZM13 16H20V19C20 19.5523 19.5523 20 19 20H13V16ZM11 16V20H5C4.44772 20 4 19.5523 4 19V16H11ZM13 8H20V5C20 4.44772 19.5523 4 19 4H13V8Z",
5754
+ fill: "currentColor"
5755
+ }
5756
+ )
5757
+ }
5758
+ );
5759
+ });
5760
+ TableIcon.displayName = "TableIcon";
5761
+
5762
+ // src/components/tiptap-node/table-node/ui/table-trigger-button/use-table-trigger.ts
5763
+ var REQUIRED_EXTENSIONS = ["table"];
5764
+ function canInsertTable(editor) {
5765
+ if (!editor || !editor.isEditable) return false;
5766
+ return isExtensionAvailable(editor, REQUIRED_EXTENSIONS);
5767
+ }
5768
+ function insertTable(editor, rows, cols) {
5769
+ if (!editor || !canInsertTable(editor)) return false;
5770
+ try {
5771
+ return editor.chain().focus().insertTable({
5772
+ rows,
5773
+ cols,
5774
+ withHeaderRow: false
5775
+ }).run();
5776
+ } catch (error) {
5777
+ console.error("Error inserting table:", error);
5778
+ return false;
5779
+ }
5780
+ }
5781
+ function shouldShowButton10(editor, hideWhenUnavailable) {
5782
+ if (!editor || !editor.isEditable) return false;
5783
+ const hasExtension = isExtensionAvailable(editor, REQUIRED_EXTENSIONS);
5784
+ if (!hasExtension) return false;
5785
+ return !hideWhenUnavailable || canInsertTable(editor);
5786
+ }
5787
+ function useTableTriggerButton(config) {
5788
+ const {
5789
+ editor: providedEditor,
5790
+ hideWhenUnavailable = false,
5791
+ onInserted
5792
+ } = config || {};
5793
+ const { editor } = useTiptapEditor(providedEditor);
5794
+ const [isOpen, setIsOpen] = (0, import_react84.useState)(false);
5795
+ const [hoveredCell, setHoveredCell] = (0, import_react84.useState)(null);
5796
+ const isVisible = shouldShowButton10(editor, hideWhenUnavailable);
5797
+ const canInsert = canInsertTable(editor);
5798
+ const handleCellHover = (0, import_react84.useCallback)((row, col) => {
5799
+ setHoveredCell({ row, col });
5800
+ }, []);
5801
+ const handleCellClick = (0, import_react84.useCallback)(
5802
+ (row, col) => {
5803
+ const success = insertTable(editor, row + 1, col + 1);
5804
+ if (success) {
5805
+ setIsOpen(false);
5806
+ onInserted?.(row + 1, col + 1);
5807
+ }
5808
+ },
5809
+ [editor, onInserted]
5810
+ );
5811
+ const resetHoveredCell = (0, import_react84.useCallback)(() => {
5812
+ setHoveredCell(null);
5813
+ }, []);
5814
+ return {
5815
+ isVisible,
5816
+ canInsert,
5817
+ isOpen,
5818
+ setIsOpen,
5819
+ hoveredCell,
5820
+ handleCellHover,
5821
+ handleCellClick,
5822
+ resetHoveredCell,
5823
+ label: "Insert table",
5824
+ Icon: TableIcon
5825
+ };
5826
+ }
5827
+
5828
+ // src/components/tiptap-ui/color-text-popover/color-text-popover.tsx
5829
+ var import_react88 = require("react");
5830
+
5831
+ // src/components/tiptap-ui/color-text-button/color-text-button.tsx
5832
+ var import_react85 = require("react");
5833
+ var import_jsx_runtime64 = require("react/jsx-runtime");
5834
+ function ColorTextShortcutBadge({
5835
+ shortcutKeys = COLOR_TEXT_SHORTCUT_KEY
5836
+ }) {
5837
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
5838
+ }
5839
+ var ColorTextButton = (0, import_react85.forwardRef)(
5840
+ ({
5841
+ editor: providedEditor,
5842
+ textColor,
5843
+ text,
5844
+ hideWhenUnavailable = false,
5845
+ onApplied,
5846
+ showShortcut = false,
5847
+ onClick,
5848
+ children,
5849
+ style,
5850
+ ...buttonProps
5851
+ }, ref) => {
5852
+ const { editor } = useTiptapEditor(providedEditor);
5853
+ const {
5854
+ isVisible,
5855
+ canColorText: canColorText2,
5856
+ isActive,
5857
+ handleColorText,
5858
+ label,
5859
+ shortcutKeys,
5860
+ Icon
5861
+ } = useColorText({
5862
+ editor,
5863
+ textColor,
5864
+ label: text || `Color text to ${textColor}`,
5865
+ hideWhenUnavailable,
5866
+ onApplied
5867
+ });
5868
+ const handleClick = (0, import_react85.useCallback)(
5869
+ (event) => {
5870
+ onClick?.(event);
5871
+ if (event.defaultPrevented) return;
5872
+ handleColorText();
5873
+ },
5874
+ [handleColorText, onClick]
5875
+ );
5876
+ const buttonStyle = (0, import_react85.useMemo)(
5877
+ () => ({
5878
+ ...style,
5879
+ "--color-text-button-color": textColor
5880
+ }),
5881
+ [textColor, style]
5882
+ );
5883
+ if (!isVisible) {
5884
+ return null;
5885
+ }
5886
+ return /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5887
+ Button,
5888
+ {
5889
+ type: "button",
5890
+ "data-style": "ghost",
5891
+ "data-active-state": isActive ? "on" : "off",
5892
+ role: "button",
5893
+ tabIndex: -1,
5894
+ disabled: !canColorText2,
5895
+ "data-disabled": !canColorText2,
5896
+ "aria-label": label,
5897
+ "aria-pressed": isActive,
5898
+ tooltip: label,
5899
+ onClick: handleClick,
5900
+ style: buttonStyle,
5901
+ ...buttonProps,
5902
+ ref,
5903
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime64.jsxs)(import_jsx_runtime64.Fragment, { children: [
5904
+ /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5905
+ "span",
5906
+ {
5907
+ className: "tiptap-button-color-text",
5908
+ style: { color: textColor },
5909
+ children: /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(
5910
+ Icon,
5911
+ {
5912
+ className: "tiptap-button-icon",
5913
+ style: { color: textColor, flexGrow: 1 }
5914
+ }
5915
+ )
5916
+ }
5917
+ ),
5918
+ text && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)("span", { className: "tiptap-button-text", children: text }),
5919
+ showShortcut && /* @__PURE__ */ (0, import_jsx_runtime64.jsx)(ColorTextShortcutBadge, { shortcutKeys })
5920
+ ] })
5921
+ }
5922
+ );
5923
+ }
5924
+ );
5925
+ ColorTextButton.displayName = "ColorTextButton";
5926
+
5927
+ // src/components/tiptap-ui/color-text-button/use-color-text.ts
5928
+ var import_react87 = require("react");
5929
+ var import_react_hotkeys_hook3 = require("react-hotkeys-hook");
5930
+
5931
+ // src/components/tiptap-icons/text-color-small-icon.tsx
5932
+ var import_react86 = require("react");
5933
+ var import_jsx_runtime65 = require("react/jsx-runtime");
5934
+ var TextColorSmallIcon = (0, import_react86.memo)(({ className, ...props }) => {
5935
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5936
+ "svg",
5937
+ {
5938
+ width: "24",
5939
+ height: "24",
5940
+ className,
5941
+ viewBox: "0 0 24 24",
5942
+ fill: "currentColor",
5943
+ xmlns: "http://www.w3.org/2000/svg",
5944
+ ...props,
5945
+ children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
5946
+ "path",
5947
+ {
5948
+ fillRule: "evenodd",
5949
+ clipRule: "evenodd",
5950
+ d: "M12.8944 5.55279C12.725 5.214 12.3787 5 12 5C11.6212 5 11.2749 5.214 11.1055 5.55279L5.10555 17.5528C4.85856 18.0468 5.05878 18.6474 5.55276 18.8944C6.04674 19.1414 6.64741 18.9412 6.8944 18.4472L8.64957 14.9369C8.75862 14.9777 8.87671 15 9 15H15C15.1233 15 15.2413 14.9777 15.3504 14.9369L17.1055 18.4472C17.3525 18.9412 17.9532 19.1414 18.4472 18.8944C18.9412 18.6474 19.1414 18.0468 18.8944 17.5528L12.8944 5.55279ZM14.3819 13L12 8.23607L9.61801 13H14.3819Z",
5951
+ fill: "currentColor"
5952
+ }
5953
+ )
5954
+ }
5955
+ );
5956
+ });
5957
+ TextColorSmallIcon.displayName = "TextColorSmallIcon";
5958
+
5959
+ // src/components/tiptap-ui/color-text-button/use-color-text.ts
5960
+ var COLOR_TEXT_SHORTCUT_KEY = "mod+shift+t";
5961
+ var TEXT_COLORS = [
5962
+ {
5963
+ label: "Default text",
5964
+ value: "var(--tt-color-text)",
5965
+ border: "var(--tt-color-text-contrast)"
5966
+ },
5967
+ {
5968
+ label: "Gray text",
5969
+ value: "var(--tt-color-text-gray)",
5970
+ border: "var(--tt-color-text-gray-contrast)"
5971
+ },
5972
+ {
5973
+ label: "Brown text",
5974
+ value: "var(--tt-color-text-brown)",
5975
+ border: "var(--tt-color-text-brown-contrast)"
5976
+ },
5977
+ {
5978
+ label: "Orange text",
5979
+ value: "var(--tt-color-text-orange)",
5980
+ border: "var(--tt-color-text-orange-contrast)"
5981
+ },
5982
+ {
5983
+ label: "Yellow text",
5984
+ value: "var(--tt-color-text-yellow)",
5985
+ border: "var(--tt-color-text-yellow-contrast)"
5986
+ },
5987
+ {
5988
+ label: "Green text",
5989
+ value: "var(--tt-color-text-green)",
5990
+ border: "var(--tt-color-text-green-contrast)"
5991
+ },
5992
+ {
5993
+ label: "Blue text",
5994
+ value: "var(--tt-color-text-blue)",
5995
+ border: "var(--tt-color-text-blue-contrast)"
5996
+ },
5997
+ {
5998
+ label: "Purple text",
5999
+ value: "var(--tt-color-text-purple)",
6000
+ border: "var(--tt-color-text-purple-contrast)"
6001
+ },
6002
+ {
6003
+ label: "Pink text",
6004
+ value: "var(--tt-color-text-pink)",
6005
+ border: "var(--tt-color-text-pink-contrast)"
6006
+ },
6007
+ {
6008
+ label: "Red text",
6009
+ value: "var(--tt-color-text-red)",
6010
+ border: "var(--tt-color-text-red-contrast)"
6011
+ }
6012
+ ];
6013
+ function canColorText(editor) {
6014
+ if (!editor || !editor.isEditable) return false;
6015
+ if (!isMarkInSchema("textStyle", editor) || isNodeTypeSelected(editor, ["image"]))
6016
+ return false;
6017
+ try {
6018
+ return editor.can().setMark("textStyle", { color: "currentColor" });
6019
+ } catch {
6020
+ return false;
6021
+ }
6022
+ }
6023
+ function isColorTextActive(editor, textColor) {
6024
+ if (!editor || !editor.isEditable) return false;
6025
+ return editor.isActive("textStyle", { color: textColor });
6026
+ }
6027
+ function shouldShowButton11(props) {
6028
+ const { editor, hideWhenUnavailable } = props;
6029
+ if (!editor || !editor.isEditable) return false;
6030
+ if (!isMarkInSchema("textStyle", editor)) return false;
6031
+ if (hideWhenUnavailable && !editor.isActive("code")) {
6032
+ return canColorText(editor);
6033
+ }
6034
+ return true;
6035
+ }
6036
+ function useColorText(config) {
6037
+ const {
6038
+ editor: providedEditor,
6039
+ label,
6040
+ textColor,
6041
+ hideWhenUnavailable = false,
6042
+ onApplied
6043
+ } = config;
6044
+ const { editor } = useTiptapEditor(providedEditor);
6045
+ const isMobile = useIsBreakpoint();
6046
+ const [isVisible, setIsVisible] = (0, import_react87.useState)(true);
6047
+ const canColorTextState = canColorText(editor);
6048
+ const isActive = isColorTextActive(editor, textColor);
6049
+ (0, import_react87.useEffect)(() => {
6050
+ if (!editor) return;
6051
+ const handleSelectionUpdate = () => {
6052
+ setIsVisible(shouldShowButton11({ editor, hideWhenUnavailable }));
6053
+ };
6054
+ handleSelectionUpdate();
6055
+ editor.on("selectionUpdate", handleSelectionUpdate);
6056
+ return () => {
6057
+ editor.off("selectionUpdate", handleSelectionUpdate);
6058
+ };
6059
+ }, [editor, hideWhenUnavailable]);
6060
+ const handleColorText = (0, import_react87.useCallback)(() => {
6061
+ if (!editor || !canColorTextState) return false;
6062
+ if (editor.state.storedMarks) {
6063
+ const textStyleMarkType = editor.schema.marks.textStyle;
6064
+ if (textStyleMarkType) {
6065
+ editor.view.dispatch(
6066
+ editor.state.tr.removeStoredMark(textStyleMarkType)
6067
+ );
6068
+ }
6069
+ }
6070
+ setTimeout(() => {
6071
+ selectCurrentBlockContent(editor);
6072
+ const success = editor.chain().focus().toggleMark("textStyle", { color: textColor }).run();
6073
+ if (success) {
6074
+ onApplied?.({ color: textColor, label });
6075
+ }
6076
+ return success;
6077
+ }, 0);
6078
+ }, [editor, canColorTextState, textColor, onApplied, label]);
6079
+ (0, import_react_hotkeys_hook3.useHotkeys)(
6080
+ COLOR_TEXT_SHORTCUT_KEY,
6081
+ (event) => {
6082
+ event.preventDefault();
6083
+ handleColorText();
6084
+ },
6085
+ {
6086
+ enabled: isVisible && canColorTextState,
6087
+ enableOnContentEditable: !isMobile,
6088
+ enableOnFormTags: true
6089
+ }
6090
+ );
6091
+ return {
6092
+ isVisible,
6093
+ isActive,
6094
+ handleColorText,
6095
+ canColorText: canColorTextState,
6096
+ label: label || `Color text to ${textColor}`,
6097
+ shortcutKeys: COLOR_TEXT_SHORTCUT_KEY,
6098
+ Icon: TextColorSmallIcon
6099
+ };
6100
+ }
6101
+
6102
+ // src/lib/tiptap-advanced-utils.ts
6103
+ var import_state6 = require("@tiptap/pm/state");
6104
+ function chunkArray(array, size) {
6105
+ return Array.from(
6106
+ { length: Math.ceil(array.length / size) },
6107
+ (_, index) => array.slice(index * size, index * size + size)
6108
+ );
6109
+ }
6110
+ function getActiveMarkAttrs(editor, markName) {
6111
+ if (!editor) return null;
6112
+ const { state } = editor;
6113
+ const { from, to, empty, $from } = state.selection;
6114
+ if (empty) {
6115
+ const mark = $from.marks().find((m) => m.type.name === markName);
6116
+ return mark?.attrs ?? null;
6117
+ }
6118
+ const seen = /* @__PURE__ */ new Set();
6119
+ let foundAttrs = null;
6120
+ state.doc.nodesBetween(from, to, (node) => {
6121
+ if (!node.isText) return;
6122
+ for (const mark of node.marks) {
6123
+ if (mark.type.name === markName && !seen.has(mark.type.name)) {
6124
+ seen.add(mark.type.name);
6125
+ foundAttrs = mark.attrs;
6126
+ }
6127
+ }
6128
+ });
6129
+ return foundAttrs;
6130
+ }
6131
+
6132
+ // src/components/tiptap-ui/color-text-popover/color-text-popover.tsx
6133
+ var import_jsx_runtime66 = require("react/jsx-runtime");
6134
+ var RecentColorButton = ({
6135
+ colorObj,
6136
+ withLabel = false,
6137
+ onColorChanged,
6138
+ ...props
6139
+ }) => {
6140
+ const colorSet = colorObj.type === "text" ? TEXT_COLORS : HIGHLIGHT_COLORS;
6141
+ const color = getColorByValue(colorObj.value, colorSet);
6142
+ const commonProps = {
6143
+ tooltip: color.label,
6144
+ text: withLabel ? color.label : void 0,
6145
+ onApplied: () => onColorChanged?.({
6146
+ type: colorObj.type,
6147
+ label: color.label,
6148
+ value: color.value
6149
+ }),
6150
+ ...props
6151
+ };
6152
+ return colorObj.type === "text" ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6153
+ ColorTextButton,
6154
+ {
6155
+ textColor: color.value,
6156
+ label: color.label,
6157
+ ...commonProps
6158
+ }
6159
+ ) : /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(ColorHighlightButton, { highlightColor: color.value, ...commonProps });
6160
+ };
6161
+ var ColorGroup = ({
6162
+ type,
6163
+ colors,
6164
+ onColorSelected,
6165
+ selectedIndex,
6166
+ startIndexOffset
6167
+ }) => {
6168
+ return colors.map((group, groupIndex) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(ButtonGroup, { orientation: "horizontal", children: group.map((color, colorIndex) => {
6169
+ const itemIndex = startIndexOffset + colors.slice(0, groupIndex).reduce((acc, g) => acc + g.length, 0) + colorIndex;
6170
+ const isHighlighted = selectedIndex === itemIndex;
6171
+ const commonProps = {
6172
+ tooltip: color.label,
6173
+ onApplied: () => onColorSelected({ type, label: color.label, value: color.value }),
6174
+ tabIndex: isHighlighted ? 0 : -1,
6175
+ "data-highlighted": isHighlighted,
6176
+ "aria-label": `${color.label} ${type === "text" ? "text" : "highlight"} color`
6177
+ };
6178
+ return type === "text" ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6179
+ ColorTextButton,
6180
+ {
6181
+ textColor: color.value,
6182
+ label: color.label,
6183
+ ...commonProps
6184
+ },
6185
+ `${type}-${color.value}-${colorIndex}`
6186
+ ) : /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6187
+ ColorHighlightButton,
6188
+ {
6189
+ highlightColor: color.value,
6190
+ ...commonProps
6191
+ },
6192
+ `${type}-${color.value}-${colorIndex}`
6193
+ );
6194
+ }) }, `${type}-group-${groupIndex}`));
6195
+ };
6196
+ var RecentColorsSection = ({
6197
+ recentColors,
6198
+ onColorSelected,
6199
+ selectedIndex
6200
+ }) => {
6201
+ if (recentColors.length === 0) return null;
6202
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(CardItemGroup, { children: [
6203
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(CardGroupLabel, { children: "Recently used" }),
6204
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(ButtonGroup, { orientation: "horizontal", children: recentColors.map((colorObj, index) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6205
+ RecentColorButton,
6206
+ {
6207
+ colorObj,
6208
+ onColorChanged: onColorSelected,
6209
+ tabIndex: selectedIndex === index ? 0 : -1,
6210
+ "data-highlighted": selectedIndex === index
6211
+ },
6212
+ `recent-${colorObj.type}-${colorObj.value}`
6213
+ )) })
6214
+ ] });
6215
+ };
6216
+ var TextStyleColorPanel = ({
6217
+ maxColorsPerGroup = 5,
6218
+ maxRecentColors = 3,
6219
+ onColorChanged
6220
+ }) => {
6221
+ const { recentColors, addRecentColor, isInitialized } = useRecentColors(maxRecentColors);
6222
+ const containerRef = (0, import_react88.useRef)(null);
6223
+ const textColorGroups = (0, import_react88.useMemo)(
6224
+ () => chunkArray(TEXT_COLORS, maxColorsPerGroup),
6225
+ [maxColorsPerGroup]
6226
+ );
6227
+ const highlightColorGroups = (0, import_react88.useMemo)(
6228
+ () => chunkArray(HIGHLIGHT_COLORS, maxColorsPerGroup),
6229
+ [maxColorsPerGroup]
6230
+ );
6231
+ const allTextColors = (0, import_react88.useMemo)(() => textColorGroups.flat(), [textColorGroups]);
6232
+ const allHighlightColors = (0, import_react88.useMemo)(
6233
+ () => highlightColorGroups.flat(),
6234
+ [highlightColorGroups]
6235
+ );
6236
+ const textColorStartIndex = (0, import_react88.useMemo)(
6237
+ () => isInitialized ? recentColors.length : 0,
6238
+ [isInitialized, recentColors.length]
6239
+ );
6240
+ const highlightColorStartIndex = (0, import_react88.useMemo)(
6241
+ () => textColorStartIndex + allTextColors.length,
6242
+ [textColorStartIndex, allTextColors.length]
6243
+ );
6244
+ const menuItems = (0, import_react88.useMemo)(() => {
6245
+ const items = [];
6246
+ if (isInitialized && recentColors.length > 0) {
6247
+ items.push(
6248
+ ...recentColors.map((color) => ({
6249
+ type: color.type,
6250
+ value: color.value,
6251
+ label: `Recent ${color.type === "text" ? "text" : "highlight"} color`,
6252
+ group: "recent"
6253
+ }))
6254
+ );
6255
+ }
6256
+ items.push(
6257
+ ...allTextColors.map((color) => ({
6258
+ type: "text",
6259
+ value: color.value,
6260
+ label: color.label,
6261
+ group: "text"
6262
+ }))
6263
+ );
6264
+ items.push(
6265
+ ...allHighlightColors.map((color) => ({
6266
+ type: "highlight",
6267
+ value: color.value,
6268
+ label: color.label,
6269
+ group: "highlight"
6270
+ }))
6271
+ );
6272
+ return items;
6273
+ }, [isInitialized, recentColors, allTextColors, allHighlightColors]);
6274
+ const handleColorSelected = (0, import_react88.useCallback)(
6275
+ ({
6276
+ type,
6277
+ label,
6278
+ value
6279
+ }) => {
6280
+ if (!containerRef.current) return false;
6281
+ const highlightedElement = containerRef.current.querySelector(
6282
+ '[data-highlighted="true"]'
6283
+ );
6284
+ if (highlightedElement) {
6285
+ highlightedElement.click();
6286
+ }
6287
+ addRecentColor({ type, label, value });
6288
+ onColorChanged?.({ type, label, value });
6289
+ },
6290
+ [addRecentColor, onColorChanged]
6291
+ );
6292
+ const { selectedIndex } = useMenuNavigation({
6293
+ containerRef,
6294
+ items: menuItems,
6295
+ onSelect: (item) => {
6296
+ if (item) {
6297
+ handleColorSelected({
6298
+ type: item.type,
6299
+ label: item.label,
6300
+ value: item.value
6301
+ });
6302
+ }
6303
+ },
6304
+ orientation: "both",
6305
+ autoSelectFirstItem: false
6306
+ });
6307
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(Card, { ref: containerRef, tabIndex: 0, role: "menu", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(CardBody, { children: [
6308
+ isInitialized && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6309
+ RecentColorsSection,
6310
+ {
6311
+ recentColors,
6312
+ onColorSelected: handleColorSelected,
6313
+ selectedIndex
6314
+ }
6315
+ ),
6316
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(CardItemGroup, { children: [
6317
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(CardGroupLabel, { children: "Text color" }),
6318
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6319
+ ColorGroup,
6320
+ {
6321
+ type: "text",
6322
+ colors: textColorGroups,
6323
+ onColorSelected: handleColorSelected,
6324
+ selectedIndex,
6325
+ startIndexOffset: textColorStartIndex
6326
+ }
6327
+ )
6328
+ ] }),
6329
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(CardItemGroup, { children: [
6330
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(CardGroupLabel, { children: "Highlight color" }),
6331
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6332
+ ColorGroup,
6333
+ {
6334
+ type: "highlight",
6335
+ colors: highlightColorGroups,
6336
+ onColorSelected: handleColorSelected,
6337
+ selectedIndex,
6338
+ startIndexOffset: highlightColorStartIndex
6339
+ }
6340
+ )
6341
+ ] })
6342
+ ] }) });
6343
+ };
6344
+ var ColorTextPopover = (0, import_react88.forwardRef)(
6345
+ ({
6346
+ editor: providedEditor,
6347
+ hideWhenUnavailable = false,
6348
+ onColorChanged,
6349
+ onClick,
6350
+ children,
6351
+ ...buttonProps
6352
+ }, ref) => {
6353
+ const { editor } = useTiptapEditor(providedEditor);
6354
+ const [isOpen, setIsOpen] = (0, import_react88.useState)(false);
6355
+ const {
6356
+ isVisible,
6357
+ canToggle: canToggle3,
6358
+ activeTextStyle,
6359
+ activeHighlight,
6360
+ handleColorChanged,
6361
+ label,
6362
+ Icon
6363
+ } = useColorTextPopover({
6364
+ editor,
6365
+ hideWhenUnavailable,
6366
+ onColorChanged
6367
+ });
6368
+ const handleClick = (0, import_react88.useCallback)(
6369
+ (event) => {
6370
+ onClick?.(event);
6371
+ if (event.defaultPrevented) return;
6372
+ setIsOpen(!isOpen);
6373
+ },
6374
+ [onClick, isOpen, setIsOpen]
6375
+ );
6376
+ if (!isVisible) {
6377
+ return null;
6378
+ }
6379
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
6380
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6381
+ Button,
6382
+ {
6383
+ type: "button",
6384
+ "data-style": "ghost",
6385
+ "data-appearance": "default",
6386
+ role: "button",
6387
+ "aria-label": label,
6388
+ tooltip: label,
6389
+ disabled: !canToggle3,
6390
+ "data-disabled": !canToggle3,
6391
+ onClick: handleClick,
6392
+ ...buttonProps,
6393
+ ref,
6394
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(import_jsx_runtime66.Fragment, { children: [
6395
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6396
+ "span",
6397
+ {
6398
+ className: "tiptap-button-color-text-popover",
6399
+ style: activeHighlight.color ? {
6400
+ "--active-highlight-color": activeHighlight.color
6401
+ } : {},
6402
+ children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6403
+ Icon,
6404
+ {
6405
+ className: "tiptap-button-icon",
6406
+ style: {
6407
+ color: activeTextStyle.color || void 0
6408
+ }
6409
+ }
6410
+ )
6411
+ }
6412
+ ),
6413
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(ChevronDownIcon, { className: "tiptap-button-dropdown-small" })
6414
+ ] })
6415
+ }
6416
+ ) }),
6417
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
6418
+ PopoverContent,
6419
+ {
6420
+ "aria-label": "Text color options",
6421
+ side: "bottom",
6422
+ align: "start",
6423
+ children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(TextStyleColorPanel, { onColorChanged: handleColorChanged })
6424
+ }
6425
+ )
6426
+ ] });
6427
+ }
6428
+ );
6429
+ ColorTextPopover.displayName = "ColorTextPopover";
6430
+
6431
+ // src/components/tiptap-ui/color-text-popover/use-color-text-popover.ts
6432
+ var import_react89 = require("react");
6433
+ function getColorByValue(value, colorArray) {
6434
+ return colorArray.find((color) => color.value === value) ?? {
6435
+ value,
6436
+ label: value
6437
+ };
6438
+ }
6439
+ function shouldShowColorTextPopover(params) {
6440
+ const { editor, hideWhenUnavailable } = params;
6441
+ if (!editor || !editor.isEditable) return false;
6442
+ if (hideWhenUnavailable && !editor.isActive("code")) {
6443
+ return canColorText(editor) || canColorHighlight(editor);
6444
+ }
6445
+ return true;
6446
+ }
6447
+ function useRecentColors(maxColors = 3) {
6448
+ const [recentColors, setRecentColors] = (0, import_react89.useState)([]);
6449
+ const [isInitialized, setIsInitialized] = (0, import_react89.useState)(false);
6450
+ (0, import_react89.useEffect)(() => {
6451
+ try {
6452
+ const storedColors = localStorage.getItem("tiptapRecentlyUsedColors");
6453
+ if (storedColors) {
6454
+ const colors = JSON.parse(storedColors);
6455
+ setRecentColors(colors.slice(0, maxColors));
6456
+ }
6457
+ } catch (e) {
6458
+ console.error("Failed to load stored colors:", e);
6459
+ } finally {
6460
+ setIsInitialized(true);
6461
+ }
6462
+ }, [maxColors]);
6463
+ const addRecentColor = (0, import_react89.useCallback)(
6464
+ ({
6465
+ type,
6466
+ label,
6467
+ value
6468
+ }) => {
6469
+ setRecentColors((prevColors) => {
6470
+ const filtered = prevColors.filter(
6471
+ (c) => !(c.type === type && c.value === value)
6472
+ );
6473
+ const updated = [{ type, label, value }, ...filtered].slice(
6474
+ 0,
6475
+ maxColors
6476
+ );
6477
+ try {
6478
+ localStorage.setItem(
6479
+ "tiptapRecentlyUsedColors",
6480
+ JSON.stringify(updated)
6481
+ );
6482
+ } catch (e) {
6483
+ console.error("Failed to store colors:", e);
6484
+ }
6485
+ return updated;
6486
+ });
6487
+ },
6488
+ [maxColors]
6489
+ );
6490
+ return { recentColors, addRecentColor, isInitialized };
6491
+ }
6492
+ function useColorTextPopover(config) {
6493
+ const {
6494
+ editor: providedEditor,
6495
+ hideWhenUnavailable = false,
6496
+ onColorChanged
6497
+ } = config || {};
6498
+ const { editor } = useTiptapEditor(providedEditor);
6499
+ const [isVisible, setIsVisible] = (0, import_react89.useState)(true);
6500
+ const textStyleInSchema = isMarkInSchema("textStyle", editor);
6501
+ const highlightInSchema = isMarkInSchema("highlight", editor);
6502
+ const activeTextStyle = getActiveMarkAttrs(editor, "textStyle") || {};
6503
+ const activeHighlight = getActiveMarkAttrs(editor, "highlight") || {};
6504
+ const canToggle3 = canColorText(editor) || canColorHighlight(editor);
6505
+ (0, import_react89.useEffect)(() => {
6506
+ if (!editor) return;
6507
+ const updateVisibility = () => {
6508
+ setIsVisible(
6509
+ shouldShowColorTextPopover({
6510
+ editor,
6511
+ hideWhenUnavailable
6512
+ })
6513
+ );
6514
+ };
6515
+ updateVisibility();
6516
+ editor.on("selectionUpdate", updateVisibility);
6517
+ return () => {
6518
+ editor.off("selectionUpdate", updateVisibility);
6519
+ };
6520
+ }, [editor, hideWhenUnavailable, highlightInSchema, textStyleInSchema]);
6521
+ const handleColorChanged = (0, import_react89.useCallback)(
6522
+ ({
6523
+ type,
6524
+ label,
6525
+ value
6526
+ }) => {
6527
+ onColorChanged?.({ type, label, value });
6528
+ },
6529
+ [onColorChanged]
6530
+ );
6531
+ return {
6532
+ isVisible,
6533
+ canToggle: canToggle3,
6534
+ activeTextStyle,
6535
+ activeHighlight,
6536
+ handleColorChanged,
6537
+ label: "Text color",
6538
+ Icon: TextColorSmallIcon
6539
+ };
6540
+ }
6541
+
6542
+ // src/components/tiptap-ui/text-button/text-button.tsx
6543
+ var import_react90 = require("react");
6544
+ var import_jsx_runtime67 = require("react/jsx-runtime");
6545
+ function TextShortcutBadge({
6546
+ shortcutKeys = TEXT_SHORTCUT_KEY
6547
+ }) {
6548
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(Badge, { children: parseShortcutKeys({ shortcutKeys }) });
6549
+ }
6550
+ var TextButton = (0, import_react90.forwardRef)(
6551
+ ({
6552
+ editor: providedEditor,
6553
+ text,
6554
+ hideWhenUnavailable = false,
6555
+ onToggled,
6556
+ showShortcut = false,
6557
+ onClick,
6558
+ children,
6559
+ ...buttonProps
6560
+ }, ref) => {
6561
+ const { editor } = useTiptapEditor(providedEditor);
6562
+ const {
6563
+ isVisible,
6564
+ canToggle: canToggle3,
6565
+ isActive,
6566
+ handleToggle,
6567
+ label,
6568
+ shortcutKeys,
6569
+ Icon
6570
+ } = useText({
6571
+ editor,
6572
+ hideWhenUnavailable,
6573
+ onToggled
6574
+ });
6575
+ const handleClick = (0, import_react90.useCallback)(
6576
+ (event) => {
6577
+ onClick?.(event);
6578
+ if (event.defaultPrevented) return;
6579
+ handleToggle();
6580
+ },
6581
+ [handleToggle, onClick]
6582
+ );
6583
+ if (!isVisible) {
6584
+ return null;
6585
+ }
6586
+ return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
6587
+ Button,
6588
+ {
6589
+ type: "button",
6590
+ "data-style": "ghost",
6591
+ "data-active-state": isActive ? "on" : "off",
6592
+ role: "button",
6593
+ tabIndex: -1,
6594
+ disabled: !canToggle3,
6595
+ "data-disabled": !canToggle3,
6596
+ "aria-label": label,
6597
+ "aria-pressed": isActive,
6598
+ tooltip: "Text",
6599
+ onClick: handleClick,
6600
+ ...buttonProps,
6601
+ ref,
6602
+ children: children ?? /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
6603
+ /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(Icon, { className: "tiptap-button-icon" }),
6604
+ text && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "tiptap-button-text", children: text }),
6605
+ showShortcut && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(TextShortcutBadge, { shortcutKeys })
6606
+ ] })
6607
+ }
6608
+ );
6609
+ }
6610
+ );
6611
+ TextButton.displayName = "TextButton";
6612
+
6613
+ // src/components/tiptap-ui/text-button/use-text.ts
6614
+ var import_react92 = require("react");
6615
+ var import_react_hotkeys_hook4 = require("react-hotkeys-hook");
6616
+ var import_state7 = require("@tiptap/pm/state");
6617
+
6618
+ // src/components/tiptap-icons/type-icon.tsx
6619
+ var import_react91 = require("react");
6620
+ var import_jsx_runtime68 = require("react/jsx-runtime");
6621
+ var TypeIcon = (0, import_react91.memo)(({ className, ...props }) => {
6622
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6623
+ "svg",
6624
+ {
6625
+ width: "24",
6626
+ height: "24",
6627
+ className,
6628
+ viewBox: "0 0 24 24",
6629
+ fill: "currentColor",
6630
+ xmlns: "http://www.w3.org/2000/svg",
6631
+ ...props,
6632
+ children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
6633
+ "path",
6634
+ {
6635
+ d: "M3 4C3 3.44772 3.44772 3 4 3H20C20.5523 3 21 3.44772 21 4V7C21 7.55228 20.5523 8 20 8C19.4477 8 19 7.55228 19 7V5H13V19H15C15.5523 19 16 19.4477 16 20C16 20.5523 15.5523 21 15 21H9C8.44772 21 8 20.5523 8 20C8 19.4477 8.44772 19 9 19H11V5H5V7C5 7.55228 4.55228 8 4 8C3.44772 8 3 7.55228 3 7V4Z",
6636
+ fill: "currentColor"
6637
+ }
6638
+ )
6639
+ }
6640
+ );
6641
+ });
6642
+ TypeIcon.displayName = "TypeIcon";
6643
+
6644
+ // src/components/tiptap-ui/text-button/use-text.ts
6645
+ var TEXT_SHORTCUT_KEY = "mod+alt+0";
6646
+ function canToggleText(editor, turnInto = true) {
6647
+ if (!editor) return false;
6648
+ if (!editor.schema.nodes.paragraph) return false;
6649
+ if (!turnInto) {
6650
+ return editor.can().setNode("paragraph");
6651
+ }
6652
+ if (!selectionWithinConvertibleTypes(editor, [
6653
+ "paragraph",
6654
+ "heading",
6655
+ "bulletList",
6656
+ "orderedList",
6657
+ "taskList",
6658
+ "blockquote",
6659
+ "codeBlock"
6660
+ ]))
6661
+ return false;
6662
+ return editor.can().setNode("paragraph") || editor.can().clearNodes();
6663
+ }
6664
+ function isParagraphActive(editor) {
6665
+ if (!editor) return false;
6666
+ return editor.isActive("paragraph");
6667
+ }
6668
+ function toggleParagraph(editor) {
6669
+ if (!editor || !editor.isEditable) return false;
6670
+ if (!canToggleText(editor)) return false;
6671
+ try {
6672
+ const view = editor.view;
6673
+ let state = view.state;
6674
+ let tr = state.tr;
6675
+ const blocks = getSelectedBlockNodes(editor);
6676
+ const isPossibleToTurnInto = selectionWithinConvertibleTypes(editor, [
6677
+ "paragraph",
6678
+ "heading",
6679
+ "bulletList",
6680
+ "orderedList",
6681
+ "taskList",
6682
+ "blockquote",
6683
+ "codeBlock"
6684
+ ]) && blocks.length === 1;
6685
+ if ((state.selection.empty || state.selection instanceof import_state7.TextSelection) && isPossibleToTurnInto) {
6686
+ const pos = findNodePosition({
6687
+ editor,
6688
+ node: state.selection.$anchor.node(1)
6689
+ })?.pos;
6690
+ if (!isValidPosition(pos)) return false;
6691
+ tr = tr.setSelection(import_state7.NodeSelection.create(state.doc, pos));
6692
+ view.dispatch(tr);
6693
+ state = view.state;
6694
+ }
6695
+ const selection = state.selection;
6696
+ let chain = editor.chain().focus();
6697
+ if (selection instanceof import_state7.NodeSelection) {
6698
+ const firstChild = selection.node.firstChild?.firstChild;
6699
+ const lastChild = selection.node.lastChild?.lastChild;
6700
+ const from = firstChild ? selection.from + firstChild.nodeSize : selection.from + 1;
6701
+ const to = lastChild ? selection.to - lastChild.nodeSize : selection.to - 1;
6702
+ const resolvedFrom = state.doc.resolve(from);
6703
+ const resolvedTo = state.doc.resolve(to);
6704
+ chain = chain.setTextSelection(import_state7.TextSelection.between(resolvedFrom, resolvedTo)).clearNodes();
6705
+ }
6706
+ if (!editor.isActive("paragraph")) {
6707
+ chain.setNode("paragraph").run();
6708
+ }
6709
+ editor.chain().focus().selectTextblockEnd().run();
6710
+ return true;
6711
+ } catch {
6712
+ return false;
6713
+ }
6714
+ }
6715
+ function shouldShowButton12(props) {
6716
+ const { editor, hideWhenUnavailable } = props;
6717
+ if (!editor || !editor.isEditable) return false;
6718
+ if (!isNodeInSchema("paragraph", editor)) return false;
6719
+ if (hideWhenUnavailable && !editor.isActive("code")) {
6720
+ return canToggleText(editor);
6721
+ }
6722
+ return true;
6723
+ }
6724
+ function useText(config) {
6725
+ const {
6726
+ editor: providedEditor,
6727
+ hideWhenUnavailable = false,
6728
+ onToggled
6729
+ } = config || {};
6730
+ const { editor } = useTiptapEditor(providedEditor);
6731
+ const isMobile = useIsBreakpoint();
6732
+ const [isVisible, setIsVisible] = (0, import_react92.useState)(true);
6733
+ const canToggle3 = canToggleText(editor);
6734
+ const isActive = isParagraphActive(editor);
6735
+ (0, import_react92.useEffect)(() => {
6736
+ if (!editor) return;
6737
+ const handleSelectionUpdate = () => {
6738
+ setIsVisible(shouldShowButton12({ editor, hideWhenUnavailable }));
6739
+ };
6740
+ handleSelectionUpdate();
6741
+ editor.on("selectionUpdate", handleSelectionUpdate);
6742
+ return () => {
6743
+ editor.off("selectionUpdate", handleSelectionUpdate);
6744
+ };
6745
+ }, [editor, hideWhenUnavailable]);
6746
+ const handleToggle = (0, import_react92.useCallback)(() => {
6747
+ if (!editor) return false;
6748
+ const success = toggleParagraph(editor);
6749
+ if (success) {
6750
+ onToggled?.();
6751
+ }
6752
+ return success;
6753
+ }, [editor, onToggled]);
6754
+ (0, import_react_hotkeys_hook4.useHotkeys)(
6755
+ TEXT_SHORTCUT_KEY,
6756
+ (event) => {
6757
+ event.preventDefault();
6758
+ handleToggle();
6759
+ },
6760
+ {
6761
+ enabled: isVisible && canToggle3,
6762
+ enableOnContentEditable: !isMobile,
6763
+ enableOnFormTags: true
6764
+ }
6765
+ );
6766
+ return {
6767
+ isVisible,
6768
+ isActive,
6769
+ handleToggle,
6770
+ canToggle: canToggle3,
6771
+ label: "Text",
6772
+ shortcutKeys: TEXT_SHORTCUT_KEY,
6773
+ Icon: TypeIcon
6774
+ };
6775
+ }
6776
+
6777
+ // src/components/tiptap-icons/arrow-left-icon.tsx
6778
+ var import_react93 = require("react");
6779
+ var import_jsx_runtime69 = require("react/jsx-runtime");
6780
+ var ArrowLeftIcon = (0, import_react93.memo)(({ className, ...props }) => {
6781
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
6782
+ "svg",
6783
+ {
6784
+ width: "24",
6785
+ height: "24",
6786
+ className,
6787
+ viewBox: "0 0 24 24",
6788
+ fill: "currentColor",
6789
+ xmlns: "http://www.w3.org/2000/svg",
6790
+ ...props,
6791
+ children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
6792
+ "path",
6793
+ {
6794
+ d: "M12.7071 5.70711C13.0976 5.31658 13.0976 4.68342 12.7071 4.29289C12.3166 3.90237 11.6834 3.90237 11.2929 4.29289L4.29289 11.2929C3.90237 11.6834 3.90237 12.3166 4.29289 12.7071L11.2929 19.7071C11.6834 20.0976 12.3166 20.0976 12.7071 19.7071C13.0976 19.3166 13.0976 18.6834 12.7071 18.2929L7.41421 13L19 13C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11L7.41421 11L12.7071 5.70711Z",
6795
+ fill: "currentColor"
6796
+ }
6797
+ )
6798
+ }
6799
+ );
6800
+ });
6801
+ ArrowLeftIcon.displayName = "ArrowLeftIcon";
6802
+
6803
+ // src/hooks/use-window-size.ts
6804
+ var import_react96 = require("react");
6805
+
6806
+ // src/hooks/use-throttled-callback.ts
6807
+ var import_lodash = __toESM(require("lodash.throttle"), 1);
6808
+
6809
+ // src/hooks/use-unmount.ts
6810
+ var import_react94 = require("react");
6811
+ var useUnmount = (callback) => {
6812
+ const ref = (0, import_react94.useRef)(callback);
6813
+ ref.current = callback;
6814
+ (0, import_react94.useEffect)(
6815
+ () => () => {
6816
+ ref.current();
6817
+ },
6818
+ []
6819
+ );
6820
+ };
6821
+
6822
+ // src/hooks/use-throttled-callback.ts
6823
+ var import_react95 = require("react");
6824
+ var defaultOptions = {
6825
+ leading: false,
6826
+ trailing: true
6827
+ };
6828
+ function useThrottledCallback(fn, wait = 250, dependencies = [], options = defaultOptions) {
6829
+ const handler = (0, import_react95.useMemo)(
6830
+ () => (0, import_lodash.default)(fn, wait, options),
6831
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6832
+ dependencies
6833
+ );
6834
+ useUnmount(() => {
6835
+ handler.cancel();
6836
+ });
6837
+ return handler;
6838
+ }
6839
+
6840
+ // src/hooks/use-window-size.ts
6841
+ function useWindowSize() {
6842
+ const [windowSize, setWindowSize] = (0, import_react96.useState)({
6843
+ width: 0,
6844
+ height: 0,
6845
+ offsetTop: 0,
6846
+ offsetLeft: 0,
6847
+ scale: 0
6848
+ });
6849
+ const handleViewportChange = useThrottledCallback(() => {
6850
+ if (typeof window === "undefined") return;
6851
+ const vp = window.visualViewport;
6852
+ if (!vp) return;
6853
+ const {
5907
6854
  width = 0,
5908
6855
  height = 0,
5909
6856
  offsetTop = 0,
@@ -5917,7 +6864,7 @@ function useWindowSize() {
5917
6864
  return { width, height, offsetTop, offsetLeft, scale };
5918
6865
  });
5919
6866
  }, 200);
5920
- (0, import_react82.useEffect)(() => {
6867
+ (0, import_react96.useEffect)(() => {
5921
6868
  const visualViewport = window.visualViewport;
5922
6869
  if (!visualViewport) return;
5923
6870
  visualViewport.addEventListener("resize", handleViewportChange);
@@ -5930,7 +6877,7 @@ function useWindowSize() {
5930
6877
  }
5931
6878
 
5932
6879
  // src/hooks/use-element-rect.ts
5933
- var import_react83 = require("react");
6880
+ var import_react97 = require("react");
5934
6881
  var initialRect = {
5935
6882
  x: 0,
5936
6883
  y: 0,
@@ -5950,8 +6897,8 @@ function useElementRect({
5950
6897
  throttleMs = 100,
5951
6898
  useResizeObserver = true
5952
6899
  } = {}) {
5953
- const [rect, setRect] = (0, import_react83.useState)(initialRect);
5954
- const getTargetElement = (0, import_react83.useCallback)(() => {
6900
+ const [rect, setRect] = (0, import_react97.useState)(initialRect);
6901
+ const getTargetElement = (0, import_react97.useCallback)(() => {
5955
6902
  if (!enabled || !isClientSide()) return null;
5956
6903
  if (!element) {
5957
6904
  return document.body;
@@ -5988,7 +6935,7 @@ function useElementRect({
5988
6935
  [enabled, getTargetElement],
5989
6936
  { leading: true, trailing: true }
5990
6937
  );
5991
- (0, import_react83.useEffect)(() => {
6938
+ (0, import_react97.useEffect)(() => {
5992
6939
  if (!enabled || !isClientSide()) {
5993
6940
  setRect(initialRect);
5994
6941
  return;
@@ -6026,7 +6973,7 @@ function useBodyRect(options = {}) {
6026
6973
  }
6027
6974
 
6028
6975
  // src/hooks/use-cursor-visibility.ts
6029
- var import_react84 = require("react");
6976
+ var import_react98 = require("react");
6030
6977
  function useCursorVisibility({
6031
6978
  editor,
6032
6979
  overlayHeight = 0
@@ -6037,7 +6984,7 @@ function useCursorVisibility({
6037
6984
  throttleMs: 100,
6038
6985
  useResizeObserver: true
6039
6986
  });
6040
- (0, import_react84.useEffect)(() => {
6987
+ (0, import_react98.useEffect)(() => {
6041
6988
  const ensureCursorVisibility = () => {
6042
6989
  if (!editor) return;
6043
6990
  const { state, view } = editor;
@@ -6064,11 +7011,11 @@ function useCursorVisibility({
6064
7011
  }
6065
7012
 
6066
7013
  // src/hooks/use-auto-height.ts
6067
- var import_react85 = require("react");
7014
+ var import_react99 = require("react");
6068
7015
  function useAutoHeight(containerRef, options) {
6069
7016
  const { enabled, bottomOffset = 24, minHeight = 200 } = options;
6070
- const [height, setHeight] = (0, import_react85.useState)(void 0);
6071
- const calculateHeight = (0, import_react85.useCallback)(() => {
7017
+ const [height, setHeight] = (0, import_react99.useState)(void 0);
7018
+ const calculateHeight = (0, import_react99.useCallback)(() => {
6072
7019
  if (!enabled || !containerRef.current) {
6073
7020
  setHeight(void 0);
6074
7021
  return;
@@ -6078,7 +7025,7 @@ function useAutoHeight(containerRef, options) {
6078
7025
  const finalHeight = Math.max(availableHeight, minHeight);
6079
7026
  setHeight(finalHeight);
6080
7027
  }, [enabled, bottomOffset, minHeight, containerRef]);
6081
- (0, import_react85.useEffect)(() => {
7028
+ (0, import_react99.useEffect)(() => {
6082
7029
  if (!enabled) {
6083
7030
  setHeight(void 0);
6084
7031
  return;
@@ -6092,15 +7039,32 @@ function useAutoHeight(containerRef, options) {
6092
7039
  return height;
6093
7040
  }
6094
7041
 
7042
+ // src/context/elia-editor-context.tsx
7043
+ var import_react100 = require("react");
7044
+ var import_jsx_runtime70 = require("react/jsx-runtime");
7045
+ var EliaEditorContext = (0, import_react100.createContext)(null);
7046
+ function EliaEditorProvider({ children }) {
7047
+ const [editor, setEditor] = (0, import_react100.useState)(null);
7048
+ const value = (0, import_react100.useMemo)(() => ({ editor, setEditor }), [editor]);
7049
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(EliaEditorContext.Provider, { value, children });
7050
+ }
7051
+ function useEliaEditor() {
7052
+ const context = (0, import_react100.useContext)(EliaEditorContext);
7053
+ return context?.editor ?? null;
7054
+ }
7055
+ function useEliaEditorContext() {
7056
+ return (0, import_react100.useContext)(EliaEditorContext);
7057
+ }
7058
+
6095
7059
  // src/components/tiptap-templates/simple/simple-editor.tsx
6096
- var import_jsx_runtime63 = require("react/jsx-runtime");
7060
+ var import_jsx_runtime71 = require("react/jsx-runtime");
6097
7061
  var DEFAULT_TOOLBAR = [
6098
7062
  "undo-redo",
7063
+ "text",
6099
7064
  "heading",
6100
7065
  "list",
6101
7066
  "blockquote",
6102
7067
  "code-block",
6103
- "callout",
6104
7068
  "table",
6105
7069
  "format",
6106
7070
  "text-color",
@@ -6118,66 +7082,66 @@ var MainToolbarContent = ({
6118
7082
  toolbar
6119
7083
  }) => {
6120
7084
  const has = (item) => toolbar.includes(item);
6121
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_jsx_runtime63.Fragment, { children: [
6122
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Spacer, {}),
6123
- has("undo-redo") && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(ToolbarGroup, { children: [
6124
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(UndoRedoButton, { action: "undo" }),
6125
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(UndoRedoButton, { action: "redo" })
7085
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_jsx_runtime71.Fragment, { children: [
7086
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(Spacer, {}),
7087
+ has("undo-redo") && /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(ToolbarGroup, { children: [
7088
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(UndoRedoButton, { action: "undo" }),
7089
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(UndoRedoButton, { action: "redo" })
6126
7090
  ] }),
6127
- has("undo-redo") && (has("heading") || has("list") || has("blockquote") || has("code-block") || has("callout") || has("table")) && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ToolbarSeparator, {}),
6128
- (has("heading") || has("list") || has("blockquote") || has("code-block") || has("callout") || has("table")) && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(ToolbarGroup, { children: [
6129
- has("heading") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(HeadingDropdownMenu, { levels: [1, 2, 3, 4] }),
6130
- has("list") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
7091
+ has("undo-redo") && (has("text") || has("heading") || has("list") || has("blockquote") || has("code-block") || has("table")) && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ToolbarSeparator, {}),
7092
+ (has("text") || has("heading") || has("list") || has("blockquote") || has("code-block") || has("table")) && /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(ToolbarGroup, { children: [
7093
+ has("text") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(TextButton, {}),
7094
+ has("heading") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(HeadingDropdownMenu, { levels: [1, 2, 3, 4] }),
7095
+ has("list") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
6131
7096
  ListDropdownMenu,
6132
7097
  {
6133
7098
  types: ["bulletList", "orderedList", "taskList"]
6134
7099
  }
6135
7100
  ),
6136
- has("blockquote") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(BlockquoteButton, {}),
6137
- has("code-block") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(CodeBlockButton, {}),
6138
- has("callout") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(CalloutButton, {}),
6139
- has("table") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TableButton, {})
7101
+ has("blockquote") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(BlockquoteButton, {}),
7102
+ has("code-block") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(CodeBlockButton, {}),
7103
+ has("table") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(TableTriggerButton, {})
6140
7104
  ] }),
6141
- (has("heading") || has("list") || has("blockquote") || has("code-block") || has("callout") || has("table")) && (has("format") || has("text-color") || has("highlight") || has("link")) && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ToolbarSeparator, {}),
6142
- (has("format") || has("text-color") || has("highlight") || has("link")) && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(ToolbarGroup, { children: [
6143
- has("format") && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_jsx_runtime63.Fragment, { children: [
6144
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(MarkButton, { type: "bold" }),
6145
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(MarkButton, { type: "italic" }),
6146
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(MarkButton, { type: "strike" }),
6147
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(MarkButton, { type: "code" }),
6148
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(MarkButton, { type: "underline" })
7105
+ (has("text") || has("heading") || has("list") || has("blockquote") || has("code-block") || has("table")) && (has("format") || has("text-color") || has("highlight") || has("link")) && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ToolbarSeparator, {}),
7106
+ (has("format") || has("text-color") || has("highlight") || has("link")) && /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(ToolbarGroup, { children: [
7107
+ has("format") && /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_jsx_runtime71.Fragment, { children: [
7108
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(MarkButton, { type: "bold" }),
7109
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(MarkButton, { type: "italic" }),
7110
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(MarkButton, { type: "strike" }),
7111
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(MarkButton, { type: "code" }),
7112
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(MarkButton, { type: "underline" })
6149
7113
  ] }),
6150
- has("text-color") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TextColorButton, {}),
6151
- has("highlight") && (!isMobile ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ColorHighlightPopover, {}) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ColorHighlightPopoverButton, { onClick: onHighlighterClick })),
6152
- has("link") && (!isMobile ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(LinkPopover, {}) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(LinkButton, { onClick: onLinkClick }))
7114
+ has("text-color") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ColorTextPopover, {}),
7115
+ has("highlight") && (!isMobile ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ColorHighlightPopover, {}) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ColorHighlightPopoverButton, { onClick: onHighlighterClick })),
7116
+ has("link") && (!isMobile ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(LinkPopover, {}) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(LinkButton, { onClick: onLinkClick }))
6153
7117
  ] }),
6154
- (has("format") || has("text-color") || has("highlight") || has("link")) && (has("superscript") || has("subscript")) && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ToolbarSeparator, {}),
6155
- (has("superscript") || has("subscript")) && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(ToolbarGroup, { children: [
6156
- has("superscript") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(MarkButton, { type: "superscript" }),
6157
- has("subscript") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(MarkButton, { type: "subscript" })
7118
+ (has("format") || has("text-color") || has("highlight") || has("link")) && (has("superscript") || has("subscript")) && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ToolbarSeparator, {}),
7119
+ (has("superscript") || has("subscript")) && /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(ToolbarGroup, { children: [
7120
+ has("superscript") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(MarkButton, { type: "superscript" }),
7121
+ has("subscript") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(MarkButton, { type: "subscript" })
6158
7122
  ] }),
6159
- (has("superscript") || has("subscript")) && has("align") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ToolbarSeparator, {}),
6160
- has("align") && /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(ToolbarGroup, { children: [
6161
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TextAlignButton, { align: "left" }),
6162
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TextAlignButton, { align: "center" }),
6163
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TextAlignButton, { align: "right" }),
6164
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(TextAlignButton, { align: "justify" })
7123
+ (has("superscript") || has("subscript")) && has("align") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ToolbarSeparator, {}),
7124
+ has("align") && /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(ToolbarGroup, { children: [
7125
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(TextAlignButton, { align: "left" }),
7126
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(TextAlignButton, { align: "center" }),
7127
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(TextAlignButton, { align: "right" }),
7128
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(TextAlignButton, { align: "justify" })
6165
7129
  ] }),
6166
- has("align") && has("image") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ToolbarSeparator, {}),
6167
- has("image") && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ToolbarGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ImageUploadButton, {}) }),
6168
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(Spacer, {})
7130
+ has("align") && has("image") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ToolbarSeparator, {}),
7131
+ has("image") && /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ToolbarGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ImageUploadButton, {}) }),
7132
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(Spacer, {})
6169
7133
  ] });
6170
7134
  };
6171
7135
  var MobileToolbarContent = ({
6172
7136
  type,
6173
7137
  onBack
6174
- }) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_jsx_runtime63.Fragment, { children: [
6175
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ToolbarGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(Button, { "data-style": "ghost", onClick: onBack, children: [
6176
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ArrowLeftIcon, { className: "tiptap-button-icon" }),
6177
- type === "highlighter" ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(HighlighterIcon, { className: "tiptap-button-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(LinkIcon, { className: "tiptap-button-icon" })
7138
+ }) => /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_jsx_runtime71.Fragment, { children: [
7139
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ToolbarGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(Button, { "data-style": "ghost", onClick: onBack, children: [
7140
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ArrowLeftIcon, { className: "tiptap-button-icon" }),
7141
+ type === "highlighter" ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(HighlighterIcon, { className: "tiptap-button-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(LinkIcon, { className: "tiptap-button-icon" })
6178
7142
  ] }) }),
6179
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ToolbarSeparator, {}),
6180
- type === "highlighter" ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(ColorHighlightPopoverContent, {}) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(LinkContent, {})
7143
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ToolbarSeparator, {}),
7144
+ type === "highlighter" ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(ColorHighlightPopoverContent, {}) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(LinkContent, {})
6181
7145
  ] });
6182
7146
  function EliaEditor({
6183
7147
  content = "",
@@ -6197,26 +7161,26 @@ function EliaEditor({
6197
7161
  }) {
6198
7162
  const isMobile = useIsBreakpoint();
6199
7163
  const { height } = useWindowSize();
6200
- const [mobileView, setMobileView] = (0, import_react86.useState)(
7164
+ const [mobileView, setMobileView] = (0, import_react101.useState)(
6201
7165
  "main"
6202
7166
  );
6203
- const toolbarRef = (0, import_react86.useRef)(null);
6204
- const containerRef = (0, import_react86.useRef)(null);
6205
- const isInternalUpdate = (0, import_react86.useRef)(false);
7167
+ const toolbarRef = (0, import_react101.useRef)(null);
7168
+ const containerRef = (0, import_react101.useRef)(null);
7169
+ const isInternalUpdate = (0, import_react101.useRef)(false);
6206
7170
  const computedHeight = useAutoHeight(containerRef, {
6207
7171
  enabled: embedded && autoHeight,
6208
7172
  bottomOffset,
6209
7173
  minHeight
6210
7174
  });
6211
7175
  const uploadFn = onImageUpload || handleImageUpload;
6212
- const handleUpdate = (0, import_react86.useCallback)(
7176
+ const handleUpdate = (0, import_react101.useCallback)(
6213
7177
  ({ editor: editor2 }) => {
6214
7178
  isInternalUpdate.current = true;
6215
7179
  onChange?.(editor2.getHTML(), editor2.getJSON());
6216
7180
  },
6217
7181
  [onChange]
6218
7182
  );
6219
- const editor = (0, import_react87.useEditor)({
7183
+ const editor = (0, import_react102.useEditor)({
6220
7184
  immediatelyRender: false,
6221
7185
  editorProps: {
6222
7186
  attributes: {
@@ -6258,7 +7222,6 @@ function EliaEditor({
6258
7222
  import_tiptap_extension_resize_image.default.configure({
6259
7223
  allowBase64: true
6260
7224
  }),
6261
- Callout,
6262
7225
  ImageUploadNode2.configure({
6263
7226
  type: "imageResize",
6264
7227
  accept: "image/*",
@@ -6266,6 +7229,10 @@ function EliaEditor({
6266
7229
  limit: 3,
6267
7230
  upload: uploadFn,
6268
7231
  onError: (error) => console.error("Upload failed:", error)
7232
+ }),
7233
+ import_extension_unique_id.UniqueID.configure({
7234
+ types: ["heading"],
7235
+ attributeName: "id"
6269
7236
  })
6270
7237
  ],
6271
7238
  content,
@@ -6273,27 +7240,38 @@ function EliaEditor({
6273
7240
  editable: !readOnly,
6274
7241
  onUpdate: handleUpdate
6275
7242
  });
7243
+ const eliaContext = useEliaEditorContext();
7244
+ (0, import_react101.useEffect)(() => {
7245
+ if (eliaContext && editor) {
7246
+ eliaContext.setEditor(editor);
7247
+ }
7248
+ return () => {
7249
+ if (eliaContext) {
7250
+ eliaContext.setEditor(null);
7251
+ }
7252
+ };
7253
+ }, [editor]);
6276
7254
  const rect = useCursorVisibility({
6277
7255
  editor,
6278
7256
  overlayHeight: toolbarRef.current?.getBoundingClientRect().height ?? 0
6279
7257
  });
6280
- (0, import_react86.useEffect)(() => {
7258
+ (0, import_react101.useEffect)(() => {
6281
7259
  if (!isMobile && mobileView !== "main") {
6282
7260
  setMobileView("main");
6283
7261
  }
6284
7262
  }, [isMobile, mobileView]);
6285
- (0, import_react86.useEffect)(() => {
7263
+ (0, import_react101.useEffect)(() => {
6286
7264
  if (editor && !isInternalUpdate.current && content !== editor.getHTML()) {
6287
7265
  editor.commands.setContent(content);
6288
7266
  }
6289
7267
  isInternalUpdate.current = false;
6290
7268
  }, [content, editor]);
6291
- (0, import_react86.useEffect)(() => {
7269
+ (0, import_react101.useEffect)(() => {
6292
7270
  if (editor) {
6293
7271
  editor.setEditable(!readOnly);
6294
7272
  }
6295
7273
  }, [readOnly, editor]);
6296
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
7274
+ return /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
6297
7275
  "div",
6298
7276
  {
6299
7277
  ref: containerRef,
@@ -6304,8 +7282,8 @@ function EliaEditor({
6304
7282
  className
6305
7283
  ),
6306
7284
  style: computedHeight ? { height: computedHeight } : void 0,
6307
- children: /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_react87.EditorContext.Provider, { value: { editor }, children: [
6308
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
7285
+ children: /* @__PURE__ */ (0, import_jsx_runtime71.jsxs)(import_react102.EditorContext.Provider, { value: { editor }, children: [
7286
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
6309
7287
  Toolbar,
6310
7288
  {
6311
7289
  ref: toolbarRef,
@@ -6314,7 +7292,7 @@ function EliaEditor({
6314
7292
  bottom: `calc(100% - ${height - rect.y}px)`
6315
7293
  } : {}
6316
7294
  },
6317
- children: mobileView === "main" ? /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
7295
+ children: mobileView === "main" ? /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
6318
7296
  MainToolbarContent,
6319
7297
  {
6320
7298
  onHighlighterClick: () => setMobileView("highlighter"),
@@ -6322,7 +7300,7 @@ function EliaEditor({
6322
7300
  isMobile,
6323
7301
  toolbar
6324
7302
  }
6325
- ) : /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
7303
+ ) : /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
6326
7304
  MobileToolbarContent,
6327
7305
  {
6328
7306
  type: mobileView === "highlighter" ? "highlighter" : "link",
@@ -6331,8 +7309,8 @@ function EliaEditor({
6331
7309
  )
6332
7310
  }
6333
7311
  ),
6334
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
6335
- import_react87.EditorContent,
7312
+ /* @__PURE__ */ (0, import_jsx_runtime71.jsx)(
7313
+ import_react102.EditorContent,
6336
7314
  {
6337
7315
  editor,
6338
7316
  role: "presentation",
@@ -6344,8 +7322,123 @@ function EliaEditor({
6344
7322
  );
6345
7323
  }
6346
7324
 
7325
+ // src/components/toc-sidebar/toc-sidebar.tsx
7326
+ var import_react105 = require("react");
7327
+
7328
+ // src/hooks/use-toc-items.ts
7329
+ var import_react103 = require("react");
7330
+ function useTocItems(editor) {
7331
+ const [items, setItems] = (0, import_react103.useState)([]);
7332
+ const updateToc = (0, import_react103.useCallback)(() => {
7333
+ if (!editor) {
7334
+ setItems([]);
7335
+ return;
7336
+ }
7337
+ const headings = [];
7338
+ const doc = editor.state.doc;
7339
+ doc.descendants((node, pos) => {
7340
+ if (node.type.name === "heading") {
7341
+ const level = node.attrs.level;
7342
+ if (level >= 1 && level <= 4) {
7343
+ const id = node.attrs.id || `heading-${pos}`;
7344
+ headings.push({
7345
+ id,
7346
+ level,
7347
+ text: node.textContent,
7348
+ pos
7349
+ });
7350
+ }
7351
+ }
7352
+ });
7353
+ setItems(headings);
7354
+ }, [editor]);
7355
+ (0, import_react103.useEffect)(() => {
7356
+ if (!editor) return;
7357
+ updateToc();
7358
+ editor.on("update", updateToc);
7359
+ return () => {
7360
+ editor.off("update", updateToc);
7361
+ };
7362
+ }, [editor, updateToc]);
7363
+ return items;
7364
+ }
7365
+
7366
+ // src/hooks/use-active-heading.ts
7367
+ var import_react104 = require("react");
7368
+ function useActiveHeading(items) {
7369
+ const [activeId, setActiveId] = (0, import_react104.useState)(items[0]?.id ?? null);
7370
+ const handleScroll = (0, import_react104.useCallback)(() => {
7371
+ if (items.length === 0) {
7372
+ setActiveId(null);
7373
+ return;
7374
+ }
7375
+ const headingElements = items.map((item) => ({
7376
+ id: item.id,
7377
+ element: document.getElementById(item.id)
7378
+ })).filter((item) => item.element !== null);
7379
+ if (headingElements.length === 0) {
7380
+ setActiveId(items[0]?.id ?? null);
7381
+ return;
7382
+ }
7383
+ const offset2 = 100;
7384
+ let currentId = null;
7385
+ for (const { id, element } of headingElements) {
7386
+ if (element) {
7387
+ const rect = element.getBoundingClientRect();
7388
+ if (rect.top <= offset2) {
7389
+ currentId = id;
7390
+ }
7391
+ }
7392
+ }
7393
+ setActiveId(currentId ?? items[0]?.id ?? null);
7394
+ }, [items]);
7395
+ (0, import_react104.useEffect)(() => {
7396
+ handleScroll();
7397
+ window.addEventListener("scroll", handleScroll, { passive: true });
7398
+ return () => window.removeEventListener("scroll", handleScroll);
7399
+ }, [handleScroll]);
7400
+ return activeId;
7401
+ }
7402
+
7403
+ // src/components/toc-sidebar/toc-sidebar.tsx
7404
+ var import_jsx_runtime72 = require("react/jsx-runtime");
7405
+ function TocSidebar({ className }) {
7406
+ const editor = useEliaEditor();
7407
+ const items = useTocItems(editor);
7408
+ const activeId = useActiveHeading(items);
7409
+ const handleClick = (0, import_react105.useCallback)((id) => {
7410
+ const element = document.getElementById(id);
7411
+ if (element) {
7412
+ element.scrollIntoView({ behavior: "smooth", block: "start" });
7413
+ }
7414
+ }, []);
7415
+ return /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("nav", { className: cn("toc-sidebar", className), children: [
7416
+ /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("div", { className: "toc-sidebar-title", children: "\u76EE\u9304" }),
7417
+ items.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime72.jsx)("ul", { className: "toc-sidebar-list", children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
7418
+ "li",
7419
+ {
7420
+ className: cn(
7421
+ "toc-sidebar-item",
7422
+ `toc-sidebar-item--level-${item.level}`,
7423
+ activeId === item.id && "toc-sidebar-item--active"
7424
+ ),
7425
+ children: /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
7426
+ "button",
7427
+ {
7428
+ type: "button",
7429
+ onClick: () => handleClick(item.id),
7430
+ className: "toc-sidebar-link",
7431
+ children: item.text
7432
+ }
7433
+ )
7434
+ },
7435
+ item.id
7436
+ )) })
7437
+ ] });
7438
+ }
7439
+
6347
7440
  // src/utils/content-renderer.ts
6348
- var import_core2 = require("@tiptap/core");
7441
+ var import_core = require("@tiptap/core");
6349
7442
  var import_starter_kit2 = __toESM(require("@tiptap/starter-kit"), 1);
6350
7443
  var import_extension_text_align2 = require("@tiptap/extension-text-align");
6351
7444
  var import_extension_list2 = require("@tiptap/extension-list");
@@ -6378,18 +7471,19 @@ var contentExtensions = [
6378
7471
  import_extension_table_row2.TableRow,
6379
7472
  import_extension_table_header2.TableHeader,
6380
7473
  import_extension_table_cell2.TableCell,
6381
- import_tiptap_extension_resize_image2.default.configure({ allowBase64: true }),
6382
- Callout
7474
+ import_tiptap_extension_resize_image2.default.configure({ allowBase64: true })
6383
7475
  ];
6384
7476
  function generateEditorHTML(content) {
6385
- return (0, import_core2.generateHTML)(content, contentExtensions);
7477
+ return (0, import_core.generateHTML)(content, contentExtensions);
6386
7478
  }
6387
7479
  // Annotate the CommonJS export names for ESM import in node:
6388
7480
  0 && (module.exports = {
6389
- Callout,
6390
7481
  EliaEditor,
7482
+ EliaEditorProvider,
6391
7483
  SimpleEditor,
7484
+ TocSidebar,
6392
7485
  contentExtensions,
6393
- generateEditorHTML
7486
+ generateEditorHTML,
7487
+ useEliaEditor
6394
7488
  });
6395
7489
  //# sourceMappingURL=index.cjs.map