@4399ywkf/editor 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,12 @@
1
+ import { useTiptapEditor, isExtensionAvailable, isNodeInSchema, Button, cn, getSelectionBoundingRect, isSelectionValid, getSelectedNodesOfType, selectCurrentBlockContent, Popover, PopoverTrigger, PopoverContent, isValidPosition, updateNodesAttr, parseShortcutKeys, isMarkInSchema, isNodeTypeSelected, SR_ONLY, sanitizeUrl, selectionWithinConvertibleTypes, getSelectedBlockNodes, findNodePosition, Card, CardBody, CardItemGroup, Input, clamp, focusNextNode, getAvatar, getUrlParam, handleImageUpload, getNodeDisplayName, isTextSelectionValid, AIButton, CardGroupLabel, getElementOverflowPosition } from './chunk-GSBPP62I.js';
1
2
  import * as React from 'react';
2
- import { createContext, forwardRef, isValidElement, version, cloneElement, useMemo, memo, useState, useCallback, useRef, useEffect, useLayoutEffect, useContext, Fragment as Fragment$2, Children } from 'react';
3
+ import { createContext, memo, forwardRef, useState, useCallback, useRef, useEffect, useMemo, useLayoutEffect, useContext, Children, isValidElement, cloneElement } from 'react';
3
4
  import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
4
- import { Node, mergeAttributes, ReactNodeViewRenderer, Extension as Extension$1, NodeViewWrapper, NodeViewContent, useCurrentEditor, useEditorState, isNodeSelection, posToDOMRect, isTextSelection, findParentNodeClosestToPos, EditorContext, EditorContent, useEditor } from '@tiptap/react';
5
- import { PluginKey, Plugin, TextSelection, Selection, NodeSelection, AllSelection } from '@tiptap/pm/state';
6
- import { columnResizing, tableEditing, cellAround, CellSelection, TableView, moveTableRow, moveTableColumn, TableMap, findTable, mergeCells, splitCell, selectedRect, deleteCellSelection, selectionCell, isInTable, columnResizingPluginKey, deleteRow, deleteColumn, toggleHeader, addRowBefore, addRowAfter, addColumnBefore, addColumnAfter, rowIsHeader, columnIsHeader } from '@tiptap/pm/tables';
5
+ import { PluginKey, Plugin, TextSelection, Selection, NodeSelection } from '@tiptap/pm/state';
6
+ import { Node, mergeAttributes, ReactNodeViewRenderer, Extension as Extension$1, NodeViewWrapper, NodeViewContent, useEditorState, EditorContext, EditorContent, useEditor, isNodeSelection } from '@tiptap/react';
7
7
  import { Extension, Node as Node$1, mergeAttributes as mergeAttributes$1 } from '@tiptap/core';
8
- import { useMergeRefs, FloatingPortal, shift, flip, offset, FloatingDelayGroup, useFloating, autoUpdate, useTransitionStyles, useDismiss, useInteractions, useHover, useFocus, useRole, size } from '@floating-ui/react';
9
8
  import { Fragment, Slice } from '@tiptap/pm/model';
10
- import * as PopoverPrimitive from '@radix-ui/react-popover';
9
+ import { shift, flip, offset, useMergeRefs, useFloating, autoUpdate, useTransitionStyles, useDismiss, useInteractions, FloatingPortal, size } from '@floating-ui/react';
11
10
  import { Doc } from 'yjs';
12
11
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
13
12
  import throttle from 'lodash.throttle';
@@ -34,6 +33,7 @@ import TiptapHorizontalRule from '@tiptap/extension-horizontal-rule';
34
33
  import { Image as Image$1 } from '@tiptap/extension-image';
35
34
  import { Table } from '@tiptap/extension-table/table';
36
35
  import { TableCell, TableHeader, TableRow } from '@tiptap/extension-table';
36
+ import { columnResizing, tableEditing, cellAround, TableView, CellSelection, moveTableRow, moveTableColumn, TableMap, findTable, mergeCells, splitCell, selectedRect, deleteCellSelection, selectionCell, isInTable, columnResizingPluginKey, deleteRow, deleteColumn, toggleHeader, addRowBefore, addRowAfter, addColumnBefore, addColumnAfter, rowIsHeader, columnIsHeader } from '@tiptap/pm/tables';
37
37
  import { canJoin, Mapping } from '@tiptap/pm/transform';
38
38
  import { Decoration, DecorationSet } from '@tiptap/pm/view';
39
39
  import * as Ariakit2 from '@ariakit/react';
@@ -44,7 +44,6 @@ import { cva } from 'class-variance-authority';
44
44
  import { SuggestionPluginKey, Suggestion } from '@tiptap/suggestion';
45
45
  import { DragHandle } from '@tiptap/extension-drag-handle-react';
46
46
 
47
- // src/contexts/editor-config-context.tsx
48
47
  var DEFAULT_MAX_FILE_SIZES = {
49
48
  image: 5 * 1024 * 1024,
50
49
  video: 100 * 1024 * 1024,
@@ -74,391 +73,6 @@ function EditorConfigProvider({
74
73
  return /* @__PURE__ */ jsx(EditorConfigContext.Provider, { value, children });
75
74
  }
76
75
  var useEditorConfig = () => useContext(EditorConfigContext);
77
- function getActivePageEditor(editor) {
78
- const storage = editor.storage;
79
- const pages = storage.pages;
80
- if (!pages || !("activeEditor" in pages)) return null;
81
- return pages.activeEditor ?? null;
82
- }
83
- function useTiptapEditor(providedEditor) {
84
- const { editor: coreEditor } = useCurrentEditor();
85
- const mainEditor = providedEditor ?? coreEditor;
86
- const [storageEditor, setStorageEditor] = useState(null);
87
- useEffect(() => {
88
- if (!mainEditor) {
89
- setStorageEditor(null);
90
- return;
91
- }
92
- const updateHandler = () => setStorageEditor(getActivePageEditor(mainEditor));
93
- updateHandler();
94
- mainEditor.on("update", updateHandler);
95
- mainEditor.on("selectionUpdate", updateHandler);
96
- return () => {
97
- mainEditor.off("update", updateHandler);
98
- mainEditor.off("selectionUpdate", updateHandler);
99
- };
100
- }, [mainEditor]);
101
- useEffect(() => {
102
- if (!storageEditor) return;
103
- const handleDestroy = () => setStorageEditor(null);
104
- storageEditor.on("destroy", handleDestroy);
105
- return () => {
106
- storageEditor.off("destroy", handleDestroy);
107
- };
108
- }, [storageEditor]);
109
- const editorState = useEditorState({
110
- editor: storageEditor ?? mainEditor,
111
- selector(context) {
112
- if (!context.editor) {
113
- return { editor: null, editorState: void 0, canCommand: void 0 };
114
- }
115
- return {
116
- editor: context.editor,
117
- editorState: context.editor.state,
118
- canCommand: context.editor.can
119
- };
120
- }
121
- });
122
- return editorState ?? { editor: null };
123
- }
124
- var MAX_FILE_SIZE = 5 * 1024 * 1024;
125
- var MAC_SYMBOLS = {
126
- mod: "⌘",
127
- command: "⌘",
128
- meta: "⌘",
129
- ctrl: "⌃",
130
- control: "⌃",
131
- alt: "⌥",
132
- option: "⌥",
133
- shift: "⇧",
134
- backspace: "Del",
135
- delete: "⌦",
136
- enter: "⏎",
137
- escape: "⎋",
138
- capslock: "⇪"
139
- };
140
- var SR_ONLY = {
141
- position: "absolute",
142
- width: "1px",
143
- height: "1px",
144
- padding: 0,
145
- margin: "-1px",
146
- overflow: "hidden",
147
- clip: "rect(0, 0, 0, 0)",
148
- whiteSpace: "nowrap",
149
- borderWidth: 0
150
- };
151
- function cn(...classes) {
152
- return classes.filter(Boolean).join(" ");
153
- }
154
- function isMac() {
155
- return typeof navigator !== "undefined" && navigator.platform.toLowerCase().includes("mac");
156
- }
157
- var formatShortcutKey = (key, isMac2, capitalize = true) => {
158
- if (isMac2) {
159
- const lowerKey = key.toLowerCase();
160
- return MAC_SYMBOLS[lowerKey] || (capitalize ? key.toUpperCase() : key);
161
- }
162
- return capitalize ? key.charAt(0).toUpperCase() + key.slice(1) : key;
163
- };
164
- var parseShortcutKeys = (props) => {
165
- const { shortcutKeys, delimiter = "+", capitalize = true } = props;
166
- if (!shortcutKeys) return [];
167
- return shortcutKeys.split(delimiter).map((key) => key.trim()).map((key) => formatShortcutKey(key, isMac(), capitalize));
168
- };
169
- var isMarkInSchema = (markName, editor) => {
170
- if (!editor?.schema) return false;
171
- return editor.schema.spec.marks.get(markName) !== void 0;
172
- };
173
- var isNodeInSchema = (nodeName, editor) => {
174
- if (!editor?.schema) return false;
175
- return editor.schema.spec.nodes.get(nodeName) !== void 0;
176
- };
177
- function focusNextNode(editor) {
178
- const { state, view } = editor;
179
- const { doc, selection } = state;
180
- const nextSel = Selection.findFrom(selection.$to, 1, true);
181
- if (nextSel) {
182
- view.dispatch(state.tr.setSelection(nextSel).scrollIntoView());
183
- return true;
184
- }
185
- const paragraphType = state.schema.nodes.paragraph;
186
- if (!paragraphType) {
187
- console.warn("No paragraph node type found in schema.");
188
- return false;
189
- }
190
- const end = doc.content.size;
191
- const para = paragraphType.create();
192
- let tr = state.tr.insert(end, para);
193
- const $inside = tr.doc.resolve(end + 1);
194
- tr = tr.setSelection(TextSelection.near($inside)).scrollIntoView();
195
- view.dispatch(tr);
196
- return true;
197
- }
198
- function isValidPosition(pos) {
199
- return typeof pos === "number" && pos >= 0;
200
- }
201
- function isExtensionAvailable(editor, extensionNames) {
202
- if (!editor) return false;
203
- const names = Array.isArray(extensionNames) ? extensionNames : [extensionNames];
204
- const found = names.some(
205
- (name) => editor.extensionManager.extensions.some((ext) => ext.name === name)
206
- );
207
- if (!found) {
208
- console.warn(
209
- `None of the extensions [${names.join(", ")}] were found in the editor schema. Ensure they are included in the editor configuration.`
210
- );
211
- }
212
- return found;
213
- }
214
- function findNodeAtPosition(editor, position) {
215
- try {
216
- const node = editor.state.doc.nodeAt(position);
217
- if (!node) {
218
- console.warn(`No node found at position ${position}`);
219
- return null;
220
- }
221
- return node;
222
- } catch (error) {
223
- console.error(`Error getting node at position ${position}:`, error);
224
- return null;
225
- }
226
- }
227
- function findNodePosition(props) {
228
- const { editor, node, nodePos } = props;
229
- if (!editor || !editor.state?.doc) return null;
230
- const hasValidNode = node !== void 0 && node !== null;
231
- const hasValidPos = isValidPosition(nodePos);
232
- if (!hasValidNode && !hasValidPos) {
233
- return null;
234
- }
235
- if (hasValidNode) {
236
- let foundPos = -1;
237
- let foundNode = null;
238
- editor.state.doc.descendants((currentNode, pos) => {
239
- if (currentNode === node) {
240
- foundPos = pos;
241
- foundNode = currentNode;
242
- return false;
243
- }
244
- return true;
245
- });
246
- if (foundPos !== -1 && foundNode !== null) {
247
- return { pos: foundPos, node: foundNode };
248
- }
249
- }
250
- if (hasValidPos) {
251
- const nodeAtPos = findNodeAtPosition(editor, nodePos);
252
- if (nodeAtPos) {
253
- return { pos: nodePos, node: nodeAtPos };
254
- }
255
- }
256
- return null;
257
- }
258
- function isNodeTypeSelected(editor, nodeTypeNames = [], checkAncestorNodes = false) {
259
- if (!editor || !editor.state.selection) return false;
260
- const { selection } = editor.state;
261
- if (selection.empty) return false;
262
- if (selection instanceof NodeSelection) {
263
- const selectedNode = selection.node;
264
- return selectedNode ? nodeTypeNames.includes(selectedNode.type.name) : false;
265
- }
266
- if (checkAncestorNodes) {
267
- const { $from } = selection;
268
- for (let depth = $from.depth; depth > 0; depth--) {
269
- const ancestorNode = $from.node(depth);
270
- if (nodeTypeNames.includes(ancestorNode.type.name)) {
271
- return true;
272
- }
273
- }
274
- }
275
- return false;
276
- }
277
- function selectionWithinConvertibleTypes(editor, types = []) {
278
- if (!editor || types.length === 0) return false;
279
- const { state } = editor;
280
- const { selection } = state;
281
- const allowed = new Set(types);
282
- if (selection instanceof NodeSelection) {
283
- const nodeType = selection.node?.type?.name;
284
- return !!nodeType && allowed.has(nodeType);
285
- }
286
- if (selection instanceof TextSelection || selection instanceof AllSelection) {
287
- let valid = true;
288
- state.doc.nodesBetween(selection.from, selection.to, (node) => {
289
- if (node.isTextblock && !allowed.has(node.type.name)) {
290
- valid = false;
291
- return false;
292
- }
293
- return valid;
294
- });
295
- return valid;
296
- }
297
- return false;
298
- }
299
- var handleImageUpload = async (file, onProgress, abortSignal) => {
300
- if (!file) {
301
- throw new Error("No file provided");
302
- }
303
- if (file.size > MAX_FILE_SIZE) {
304
- throw new Error(
305
- `File size exceeds maximum allowed (${MAX_FILE_SIZE / (1024 * 1024)}MB)`
306
- );
307
- }
308
- for (let progress = 0; progress <= 100; progress += 10) {
309
- if (abortSignal?.aborted) {
310
- throw new Error("Upload cancelled");
311
- }
312
- await new Promise((resolve) => setTimeout(resolve, 500));
313
- onProgress?.({ progress });
314
- }
315
- return "/images/tiptap-ui-placeholder-image.jpg";
316
- };
317
- var ATTR_WHITESPACE = (
318
- // eslint-disable-next-line no-control-regex
319
- /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g
320
- );
321
- function isAllowedUri(uri, protocols) {
322
- const allowedProtocols = [
323
- "http",
324
- "https",
325
- "ftp",
326
- "ftps",
327
- "mailto",
328
- "tel",
329
- "callto",
330
- "sms",
331
- "cid",
332
- "xmpp"
333
- ];
334
- if (protocols) {
335
- protocols.forEach((protocol) => {
336
- const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
337
- if (nextProtocol) {
338
- allowedProtocols.push(nextProtocol);
339
- }
340
- });
341
- }
342
- return !uri || uri.replace(ATTR_WHITESPACE, "").match(
343
- new RegExp(
344
- // eslint-disable-next-line no-useless-escape
345
- `^(?:(?:${allowedProtocols.join("|")}):|[^a-z]|[a-z0-9+.-]+(?:[^a-z+.-:]|$))`,
346
- "i"
347
- )
348
- );
349
- }
350
- function sanitizeUrl(inputUrl, baseUrl, protocols) {
351
- try {
352
- const url = new URL(inputUrl, baseUrl);
353
- if (isAllowedUri(url.href, protocols)) {
354
- return url.href;
355
- }
356
- } catch {
357
- }
358
- return "#";
359
- }
360
- function updateNodesAttr(tr, targets, attrName, next) {
361
- if (!targets.length) return false;
362
- let changed = false;
363
- for (const { pos } of targets) {
364
- const currentNode = tr.doc.nodeAt(pos);
365
- if (!currentNode) continue;
366
- const prevValue = currentNode.attrs[attrName];
367
- const resolvedNext = typeof next === "function" ? next(prevValue) : next;
368
- if (prevValue === resolvedNext) continue;
369
- const nextAttrs = { ...currentNode.attrs };
370
- if (resolvedNext === void 0) {
371
- delete nextAttrs[attrName];
372
- } else {
373
- nextAttrs[attrName] = resolvedNext;
374
- }
375
- tr.setNodeMarkup(pos, void 0, nextAttrs);
376
- changed = true;
377
- }
378
- return changed;
379
- }
380
- function selectCurrentBlockContent(editor) {
381
- const { selection, doc } = editor.state;
382
- if (!selection.empty) return;
383
- const $pos = selection.$from;
384
- let blockNode = null;
385
- let blockPos = -1;
386
- for (let depth = $pos.depth; depth >= 0; depth--) {
387
- const node = $pos.node(depth);
388
- const pos = $pos.start(depth);
389
- if (node.isBlock && node.textContent.trim()) {
390
- blockNode = node;
391
- blockPos = pos;
392
- break;
393
- }
394
- }
395
- if (blockNode && blockPos >= 0) {
396
- const from = blockPos;
397
- const to = blockPos + blockNode.nodeSize - 2;
398
- if (from < to) {
399
- const $from = doc.resolve(from);
400
- const $to = doc.resolve(to);
401
- const newSelection = TextSelection.between($from, $to, 1);
402
- if (newSelection && !selection.eq(newSelection)) {
403
- editor.view.dispatch(editor.state.tr.setSelection(newSelection));
404
- }
405
- }
406
- }
407
- }
408
- function getSelectedNodesOfType(selection, allowedNodeTypes) {
409
- const results = [];
410
- const allowed = new Set(allowedNodeTypes);
411
- if (selection instanceof CellSelection) {
412
- selection.forEachCell((node, pos) => {
413
- if (allowed.has(node.type.name)) {
414
- results.push({ node, pos });
415
- }
416
- });
417
- return results;
418
- }
419
- if (selection instanceof NodeSelection) {
420
- const { node, from: pos } = selection;
421
- if (node && allowed.has(node.type.name)) {
422
- results.push({ node, pos });
423
- }
424
- return results;
425
- }
426
- const { $anchor } = selection;
427
- const cell = cellAround($anchor);
428
- if (cell) {
429
- const cellNode = selection.$anchor.doc.nodeAt(cell.pos);
430
- if (cellNode && allowed.has(cellNode.type.name)) {
431
- results.push({ node: cellNode, pos: cell.pos });
432
- return results;
433
- }
434
- }
435
- const parentNode = findParentNodeClosestToPos(
436
- $anchor,
437
- (node) => allowed.has(node.type.name)
438
- );
439
- if (parentNode) {
440
- results.push({ node: parentNode.node, pos: parentNode.pos });
441
- }
442
- return results;
443
- }
444
- function clamp(value, min, max) {
445
- return Math.max(min, Math.min(value, max));
446
- }
447
- function getSelectedBlockNodes(editor) {
448
- const { doc } = editor.state;
449
- const { from, to } = editor.state.selection;
450
- const blocks = [];
451
- const seen = /* @__PURE__ */ new Set();
452
- doc.nodesBetween(from, to, (node, pos) => {
453
- if (!node.isBlock) return;
454
- if (!seen.has(pos)) {
455
- seen.add(pos);
456
- blocks.push(node);
457
- }
458
- return false;
459
- });
460
- return blocks;
461
- }
462
76
  function chunkArray(array, size4) {
463
77
  return Array.from(
464
78
  { length: Math.ceil(array.length / size4) },
@@ -655,202 +269,6 @@ var UiState = Extension.create({
655
269
  this.storage = { ...defaultUiState };
656
270
  }
657
271
  });
658
- function useTooltip({
659
- initialOpen = false,
660
- placement = "top",
661
- open: controlledOpen,
662
- onOpenChange: setControlledOpen,
663
- delay = 600,
664
- closeDelay = 0
665
- } = {}) {
666
- const [uncontrolledOpen, setUncontrolledOpen] = useState(initialOpen);
667
- const open = controlledOpen ?? uncontrolledOpen;
668
- const setOpen = setControlledOpen ?? setUncontrolledOpen;
669
- const data = useFloating({
670
- placement,
671
- open,
672
- onOpenChange: setOpen,
673
- whileElementsMounted: autoUpdate,
674
- middleware: [
675
- offset(4),
676
- flip({
677
- crossAxis: placement.includes("-"),
678
- fallbackAxisSideDirection: "start",
679
- padding: 4
680
- }),
681
- shift({ padding: 4 })
682
- ]
683
- });
684
- const context = data.context;
685
- const hover = useHover(context, {
686
- mouseOnly: true,
687
- move: false,
688
- restMs: delay,
689
- enabled: controlledOpen == null,
690
- delay: {
691
- close: closeDelay
692
- }
693
- });
694
- const focus = useFocus(context, {
695
- enabled: controlledOpen == null
696
- });
697
- const dismiss = useDismiss(context);
698
- const role = useRole(context, { role: "tooltip" });
699
- const interactions = useInteractions([hover, focus, dismiss, role]);
700
- return useMemo(
701
- () => ({
702
- open,
703
- setOpen,
704
- ...interactions,
705
- ...data
706
- }),
707
- [open, setOpen, interactions, data]
708
- );
709
- }
710
- var TooltipContext = createContext(null);
711
- function useTooltipContext() {
712
- const context = useContext(TooltipContext);
713
- if (context == null) {
714
- throw new Error("Tooltip components must be wrapped in <TooltipProvider />");
715
- }
716
- return context;
717
- }
718
- function Tooltip({ children, ...props }) {
719
- const tooltip = useTooltip(props);
720
- if (!props.useDelayGroup) {
721
- return /* @__PURE__ */ jsx(TooltipContext.Provider, { value: tooltip, children });
722
- }
723
- return /* @__PURE__ */ jsx(
724
- FloatingDelayGroup,
725
- {
726
- delay: { open: props.delay ?? 0, close: props.closeDelay ?? 0 },
727
- timeoutMs: props.timeout,
728
- children: /* @__PURE__ */ jsx(TooltipContext.Provider, { value: tooltip, children })
729
- }
730
- );
731
- }
732
- var TooltipTrigger = forwardRef(
733
- function TooltipTrigger2({ children, asChild = false, ...props }, propRef) {
734
- const context = useTooltipContext();
735
- const childrenRef = isValidElement(children) ? parseInt(version, 10) >= 19 ? (
736
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
737
- children.props.ref
738
- ) : (
739
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
740
- children.ref
741
- ) : void 0;
742
- const ref = useMergeRefs([context.refs.setReference, propRef, childrenRef]);
743
- if (asChild && isValidElement(children)) {
744
- const dataAttributes = {
745
- "data-tooltip-state": context.open ? "open" : "closed"
746
- };
747
- return cloneElement(
748
- children,
749
- context.getReferenceProps({
750
- ref,
751
- ...props,
752
- ...typeof children.props === "object" ? children.props : {},
753
- ...dataAttributes
754
- })
755
- );
756
- }
757
- return /* @__PURE__ */ jsx(
758
- "button",
759
- {
760
- ref,
761
- "data-tooltip-state": context.open ? "open" : "closed",
762
- ...context.getReferenceProps(props),
763
- children
764
- }
765
- );
766
- }
767
- );
768
- var TooltipContent = forwardRef(
769
- function TooltipContent2({ style, children, portal = true, portalProps = {}, ...props }, propRef) {
770
- const context = useTooltipContext();
771
- const ref = useMergeRefs([context.refs.setFloating, propRef]);
772
- if (!context.open) return null;
773
- const content = /* @__PURE__ */ jsx(
774
- "div",
775
- {
776
- ref,
777
- style: {
778
- ...context.floatingStyles,
779
- ...style
780
- },
781
- ...context.getFloatingProps(props),
782
- className: "tiptap-tooltip",
783
- children
784
- }
785
- );
786
- if (portal) {
787
- return /* @__PURE__ */ jsx(FloatingPortal, { ...portalProps, children: content });
788
- }
789
- return content;
790
- }
791
- );
792
- Tooltip.displayName = "Tooltip";
793
- TooltipTrigger.displayName = "TooltipTrigger";
794
- TooltipContent.displayName = "TooltipContent";
795
- var ShortcutDisplay = ({
796
- shortcuts
797
- }) => {
798
- if (shortcuts.length === 0) return null;
799
- return /* @__PURE__ */ jsx("div", { children: shortcuts.map((key, index) => /* @__PURE__ */ jsxs(Fragment$2, { children: [
800
- index > 0 && /* @__PURE__ */ jsx("kbd", { children: "+" }),
801
- /* @__PURE__ */ jsx("kbd", { children: key })
802
- ] }, index)) });
803
- };
804
- var Button = forwardRef(
805
- ({
806
- className,
807
- children,
808
- tooltip,
809
- showTooltip = true,
810
- shortcutKeys,
811
- variant,
812
- size: size4,
813
- ...props
814
- }, ref) => {
815
- const shortcuts = useMemo(
816
- () => parseShortcutKeys({ shortcutKeys }),
817
- [shortcutKeys]
818
- );
819
- if (!tooltip || !showTooltip) {
820
- return /* @__PURE__ */ jsx(
821
- "button",
822
- {
823
- "data-slot": "tiptap-button",
824
- className: cn("tiptap-button", className),
825
- ref,
826
- "data-style": variant,
827
- "data-size": size4,
828
- ...props,
829
- children
830
- }
831
- );
832
- }
833
- return /* @__PURE__ */ jsxs(Tooltip, { delay: 200, children: [
834
- /* @__PURE__ */ jsx(
835
- TooltipTrigger,
836
- {
837
- "data-slot": "tiptap-button",
838
- className: cn("tiptap-button", className),
839
- ref,
840
- "data-style": variant,
841
- "data-size": size4,
842
- ...props,
843
- children
844
- }
845
- ),
846
- /* @__PURE__ */ jsxs(TooltipContent, { children: [
847
- tooltip,
848
- /* @__PURE__ */ jsx(ShortcutDisplay, { shortcuts })
849
- ] })
850
- ] });
851
- }
852
- );
853
- Button.displayName = "Button";
854
272
  var Video = Node.create({
855
273
  name: "video",
856
274
  group: "block",
@@ -2156,32 +1574,6 @@ function useMenuNavigation({
2156
1574
  setSelectedIndex
2157
1575
  };
2158
1576
  }
2159
- function Popover({
2160
- ...props
2161
- }) {
2162
- return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { ...props });
2163
- }
2164
- function PopoverTrigger({
2165
- ...props
2166
- }) {
2167
- return /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { ...props });
2168
- }
2169
- function PopoverContent({
2170
- className,
2171
- align = "center",
2172
- sideOffset = 4,
2173
- ...props
2174
- }) {
2175
- return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
2176
- PopoverPrimitive.Content,
2177
- {
2178
- align,
2179
- sideOffset,
2180
- className: cn("tiptap-popover", className),
2181
- ...props
2182
- }
2183
- ) });
2184
- }
2185
1577
  function useFloatingElement(show, reference, zIndex, options, autoUpdateOptions) {
2186
1578
  const { dismissOptions, ...floatingOptions } = options || {};
2187
1579
  const { refs, context, floatingStyles } = useFloating({
@@ -2240,97 +1632,6 @@ function useFloatingElement(show, reference, zIndex, options, autoUpdateOptions)
2240
1632
  ]
2241
1633
  );
2242
1634
  }
2243
- var NODE_TYPE_LABELS = {
2244
- paragraph: "Text",
2245
- heading: "Heading",
2246
- blockquote: "Blockquote",
2247
- listItem: "List Item",
2248
- codeBlock: "Code Block",
2249
- table: "Table",
2250
- tocNode: "Table of contents"
2251
- };
2252
- var getUrlParam = (param) => {
2253
- if (typeof window === "undefined") return null;
2254
- const params = new URLSearchParams(window.location.search);
2255
- return params.get(param);
2256
- };
2257
- var getNodeDisplayName = (editor) => {
2258
- if (!editor) return "Node";
2259
- const { selection } = editor.state;
2260
- if (selection instanceof NodeSelection) {
2261
- const nodeType2 = selection.node.type.name;
2262
- return NODE_TYPE_LABELS[nodeType2] || nodeType2.toLowerCase();
2263
- }
2264
- if (selection instanceof CellSelection) {
2265
- return "Table";
2266
- }
2267
- const { $anchor } = selection;
2268
- const nodeType = $anchor.parent.type.name;
2269
- return NODE_TYPE_LABELS[nodeType] || nodeType.toLowerCase();
2270
- };
2271
- var removeEmptyParagraphs = (content) => ({
2272
- ...content,
2273
- content: content.content?.filter(
2274
- (node) => node.type !== "paragraph" || node.content?.some((child) => child.text?.trim() || child.type !== "text")
2275
- )
2276
- });
2277
- function getElementOverflowPosition(targetElement, containerElement) {
2278
- const targetBounds = targetElement.getBoundingClientRect();
2279
- const containerBounds = containerElement.getBoundingClientRect();
2280
- const isOverflowingTop = targetBounds.top < containerBounds.top;
2281
- const isOverflowingBottom = targetBounds.bottom > containerBounds.bottom;
2282
- if (isOverflowingTop && isOverflowingBottom) return "both";
2283
- if (isOverflowingTop) return "top";
2284
- if (isOverflowingBottom) return "bottom";
2285
- return "none";
2286
- }
2287
- var isSelectionValid = (editor, selection, excludedNodeTypes = ["imageUpload", "horizontalRule"]) => {
2288
- if (!editor) return false;
2289
- if (!selection) selection = editor.state.selection;
2290
- const { state } = editor;
2291
- const { doc } = state;
2292
- const { empty, from, to } = selection;
2293
- const isEmptyTextBlock = !doc.textBetween(from, to).length && isTextSelection(selection);
2294
- const isCodeBlock = selection.$from.parent.type.spec.code || isNodeSelection(selection) && selection.node.type.spec.code;
2295
- const isExcludedNode = isNodeSelection(selection) && excludedNodeTypes.includes(selection.node.type.name);
2296
- const isTableCell = selection instanceof CellSelection;
2297
- return !empty && !isEmptyTextBlock && !isCodeBlock && !isExcludedNode && !isTableCell;
2298
- };
2299
- var isTextSelectionValid = (editor) => {
2300
- if (!editor) return false;
2301
- const { state } = editor;
2302
- const { selection } = state;
2303
- const isValid = isTextSelection(selection) && !selection.empty && !selection.$from.parent.type.spec.code && !isNodeSelection(selection);
2304
- return isValid;
2305
- };
2306
- var getSelectionBoundingRect = (editor) => {
2307
- const { state } = editor.view;
2308
- const { selection } = state;
2309
- const { ranges } = selection;
2310
- const from = Math.min(...ranges.map((range) => range.$from.pos));
2311
- const to = Math.max(...ranges.map((range) => range.$to.pos));
2312
- if (isNodeSelection(selection)) {
2313
- const node = editor.view.nodeDOM(from);
2314
- if (node) {
2315
- return node.getBoundingClientRect();
2316
- }
2317
- }
2318
- return posToDOMRect(editor.view, from, to);
2319
- };
2320
- var getAvatar = (name) => {
2321
- if (!name) {
2322
- return "/avatars/memoji_01.png";
2323
- }
2324
- let hash = 0;
2325
- for (let i = 0; i < name.length; i++) {
2326
- hash = name.charCodeAt(i) + ((hash << 5) - hash);
2327
- hash = hash & hash;
2328
- }
2329
- const randomFraction = Math.abs(hash) % 1e6 / 1e6;
2330
- const id = 1 + Math.floor(randomFraction * 20);
2331
- const idString = id.toString().padStart(2, "0");
2332
- return `/avatars/memoji_${idString}.png`;
2333
- };
2334
1635
 
2335
1636
  // src/lib/file-picker.ts
2336
1637
  function pickFile(accept, multiple = false) {
@@ -6293,9 +5594,9 @@ var tableDragStart = (orientation, event) => {
6293
5594
  const dragImage = createTableDragImage(editor, orientation, index, blockPos);
6294
5595
  if (event.dataTransfer) {
6295
5596
  const handleRect = event.currentTarget.getBoundingClientRect();
6296
- const offset7 = orientation === "col" ? { x: handleRect.width / 2, y: 0 } : { x: 0, y: handleRect.height / 2 };
5597
+ const offset6 = orientation === "col" ? { x: handleRect.width / 2, y: 0 } : { x: 0, y: handleRect.height / 2 };
6297
5598
  event.dataTransfer.effectAllowed = orientation === "col" ? "move" : "copyMove";
6298
- event.dataTransfer.setDragImage(dragImage, offset7.x, offset7.y);
5599
+ event.dataTransfer.setDragImage(dragImage, offset6.x, offset6.y);
6299
5600
  }
6300
5601
  const cleanup = () => dragImage.parentNode?.removeChild(dragImage);
6301
5602
  document.addEventListener("drop", cleanup, { once: true });
@@ -6579,17 +5880,6 @@ var MoreVerticalIcon = memo(({ className, ...props }) => {
6579
5880
  );
6580
5881
  });
6581
5882
  MoreVerticalIcon.displayName = "MoreVerticalIcon";
6582
- function Input({ className, type, ...props }) {
6583
- return /* @__PURE__ */ jsx(
6584
- "input",
6585
- {
6586
- type,
6587
- "data-slot": "tiptap-input",
6588
- className: cn("tiptap-input", className),
6589
- ...props
6590
- }
6591
- );
6592
- }
6593
5883
  function ComboboxProvider2({ ...props }) {
6594
5884
  return /* @__PURE__ */ jsx(
6595
5885
  Ariakit2.ComboboxProvider,
@@ -9293,69 +8583,6 @@ var ChevronDownIcon = memo(({ className, ...props }) => {
9293
8583
  );
9294
8584
  });
9295
8585
  ChevronDownIcon.displayName = "ChevronDownIcon";
9296
- var Card = forwardRef(
9297
- ({ className, ...props }, ref) => {
9298
- return /* @__PURE__ */ jsx("div", { ref, className: cn("tiptap-card", className), ...props });
9299
- }
9300
- );
9301
- Card.displayName = "Card";
9302
- var CardHeader = forwardRef(
9303
- ({ className, ...props }, ref) => {
9304
- return /* @__PURE__ */ jsx(
9305
- "div",
9306
- {
9307
- ref,
9308
- className: cn("tiptap-card-header", className),
9309
- ...props
9310
- }
9311
- );
9312
- }
9313
- );
9314
- CardHeader.displayName = "CardHeader";
9315
- var CardBody = forwardRef(
9316
- ({ className, ...props }, ref) => {
9317
- return /* @__PURE__ */ jsx("div", { ref, className: cn("tiptap-card-body", className), ...props });
9318
- }
9319
- );
9320
- CardBody.displayName = "CardBody";
9321
- var CardItemGroup = forwardRef(({ className, orientation = "vertical", ...props }, ref) => {
9322
- return /* @__PURE__ */ jsx(
9323
- "div",
9324
- {
9325
- ref,
9326
- "data-orientation": orientation,
9327
- className: cn("tiptap-card-item-group", className),
9328
- ...props
9329
- }
9330
- );
9331
- });
9332
- CardItemGroup.displayName = "CardItemGroup";
9333
- var CardGroupLabel = forwardRef(
9334
- ({ className, ...props }, ref) => {
9335
- return /* @__PURE__ */ jsx(
9336
- "div",
9337
- {
9338
- ref,
9339
- className: cn("tiptap-card-group-label", className),
9340
- ...props
9341
- }
9342
- );
9343
- }
9344
- );
9345
- CardGroupLabel.displayName = "CardGroupLabel";
9346
- var CardFooter = forwardRef(
9347
- ({ className, ...props }, ref) => {
9348
- return /* @__PURE__ */ jsx(
9349
- "div",
9350
- {
9351
- ref,
9352
- className: cn("tiptap-card-footer", className),
9353
- ...props
9354
- }
9355
- );
9356
- }
9357
- );
9358
- CardFooter.displayName = "CardFooter";
9359
8586
  var buttonGroupVariants = cva("tiptap-button-group", {
9360
8587
  variants: {
9361
8588
  orientation: {
@@ -13831,6 +13058,9 @@ function addEmojiTrigger(editor, trigger = ":", node, nodePos) {
13831
13058
  function canInsertMention(editor, node, nodePos) {
13832
13059
  if (!editor || !editor.isEditable) return false;
13833
13060
  if (isNodeTypeSelected(editor, ["image"])) return false;
13061
+ if (isValidPosition(nodePos)) {
13062
+ if (isValidPosition(nodePos) && nodePos >= 0) ;
13063
+ }
13834
13064
  return true;
13835
13065
  }
13836
13066
  function insertTriggerInBlockNode2(editor, trigger, node, nodePos) {
@@ -13888,7 +13118,7 @@ function insertTriggerInTextNode2(editor, trigger, node, nodePos) {
13888
13118
  }
13889
13119
  function addMentionTrigger(editor, trigger = "@", node, nodePos) {
13890
13120
  if (!editor || !editor.isEditable) return false;
13891
- if (!canInsertMention(editor)) return false;
13121
+ if (!canInsertMention(editor, node, nodePos)) return false;
13892
13122
  try {
13893
13123
  const { $from } = editor.state.selection;
13894
13124
  const currentNode = $from.node();
@@ -20278,10 +19508,10 @@ function setImageAlign(editor, align, extensionName = "image", attributeName = "
20278
19508
  }
20279
19509
  try {
20280
19510
  const { selection } = editor.state;
20281
- const isNodeSelection3 = selection instanceof NodeSelection;
20282
- const selectionPosition = isNodeSelection3 ? selection.from : selection.$anchor.pos;
19511
+ const isNodeSelection2 = selection instanceof NodeSelection;
19512
+ const selectionPosition = isNodeSelection2 ? selection.from : selection.$anchor.pos;
20283
19513
  const alignmentUpdated = editor.chain().focus().updateAttributes(extensionName, { [attributeName]: align }).run();
20284
- if (alignmentUpdated && isNodeSelection3) {
19514
+ if (alignmentUpdated && isNodeSelection2) {
20285
19515
  editor.commands.setNodeSelection(selectionPosition);
20286
19516
  }
20287
19517
  return alignmentUpdated;
@@ -21005,6 +20235,8 @@ function NotionToolbarFloating() {
21005
20235
  ),
21006
20236
  /* @__PURE__ */ jsx(ColorTextPopover, { hideWhenUnavailable: true })
21007
20237
  ] }),
20238
+ /* @__PURE__ */ jsx(ToolbarSeparator, {}),
20239
+ /* @__PURE__ */ jsx(ToolbarGroup, { children: /* @__PURE__ */ jsx(AIButton, { hideWhenUnavailable: true }) }),
21008
20240
  /* @__PURE__ */ jsx(MoreOptions, { hideWhenUnavailable: true })
21009
20241
  ] }) });
21010
20242
  }
@@ -21936,6 +21168,6 @@ function ArticleViewer({ content, placeholder = "" }) {
21936
21168
  ) }) });
21937
21169
  }
21938
21170
 
21939
- export { ArticleViewer, Audio, Button, CollabContext, CollabProvider, Column, Columns, DEFAULT_MAX_FILE_SIZES, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EditorConfigProvider, EditorContentArea, EditorProvider, FileAttachment, FloatingElement, HIDE_FLOATING_META, LoadingSpinner, MAC_SYMBOLS, MAX_FILE_SIZE, MediaUploadButton, MediaUploadPlaceholder, NotionEditor, NotionEditorContent, PasteDropMedia, Popover, PopoverContent, PopoverTrigger, SR_ONLY, Separator, Spacer, Toolbar, ToolbarGroup, ToolbarSeparator, UiState, UserContext, UserProvider, Video, clamp, cn, defaultUiState, detectMediaKind, findNodeAtPosition, findNodePosition, findSelectionPosition, focusNextNode, formatShortcutKey, getAvatar, getElementOverflowPosition, getNodeDisplayName, getSelectedBlockNodes, getSelectedNodesOfType, getSelectionBoundingRect, getUrlParam, handleImageUpload, hasContentAbove, isAllowedUri, isExtensionAvailable, isMac, isMarkInSchema, isNodeInSchema, isNodeTypeSelected, isSelectionValid, isTextSelectionValid, isValidPosition, markHideFloatingOnNext, parseShortcutKeys, pickFile, removeEmptyParagraphs, resolveMaxSize, runMediaUpload, sanitizeUrl, selectCurrentBlockContent, selectNodeAndHideFloating, selectionWithinConvertibleTypes, updateNodesAttr, useCollab, useCollaboration, useComposedRef, useCursorVisibility, useEditorConfig, useElementRect, useFloatingElement, useFloatingToolbarVisibility, useIsBreakpoint, useIsomorphicLayoutEffect, useMenuNavigation, useOnClickOutside, useThrottledCallback, useTiptapEditor, useUiEditorState, useUnmount, useUser, useWindowSize, use_ui_editor_state_default };
21940
- //# sourceMappingURL=chunk-ZRFOS52C.js.map
21941
- //# sourceMappingURL=chunk-ZRFOS52C.js.map
21171
+ export { ArticleViewer, Audio, CollabContext, CollabProvider, Column, Columns, DEFAULT_MAX_FILE_SIZES, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EditorConfigProvider, EditorContentArea, EditorProvider, FileAttachment, FloatingElement, HIDE_FLOATING_META, LoadingSpinner, MediaUploadButton, MediaUploadPlaceholder, NotionEditor, NotionEditorContent, PasteDropMedia, Separator, Spacer, Toolbar, ToolbarGroup, ToolbarSeparator, UiState, UserContext, UserProvider, Video, defaultUiState, detectMediaKind, findSelectionPosition, hasContentAbove, markHideFloatingOnNext, pickFile, resolveMaxSize, runMediaUpload, selectNodeAndHideFloating, useCollab, useCollaboration, useComposedRef, useCursorVisibility, useEditorConfig, useElementRect, useFloatingElement, useFloatingToolbarVisibility, useIsBreakpoint, useIsomorphicLayoutEffect, useMenuNavigation, useOnClickOutside, useThrottledCallback, useUiEditorState, useUnmount, useUser, useWindowSize, use_ui_editor_state_default };
21172
+ //# sourceMappingURL=chunk-BBZGFBWU.js.map
21173
+ //# sourceMappingURL=chunk-BBZGFBWU.js.map