@spatika/editor 1.5.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.
Files changed (142) hide show
  1. package/README.md +43 -0
  2. package/dist/composites/AiCommandDock.d.ts +13 -0
  3. package/dist/composites/AiCommandDock.d.ts.map +1 -0
  4. package/dist/composites/AiCommandDock.js +63 -0
  5. package/dist/composites/AiCommandMenu.d.ts +16 -0
  6. package/dist/composites/AiCommandMenu.d.ts.map +1 -0
  7. package/dist/composites/AiCommandMenu.js +51 -0
  8. package/dist/composites/AiCommandPanel.d.ts +12 -0
  9. package/dist/composites/AiCommandPanel.d.ts.map +1 -0
  10. package/dist/composites/AiCommandPanel.js +12 -0
  11. package/dist/composites/AiOverlay.d.ts +7 -0
  12. package/dist/composites/AiOverlay.d.ts.map +1 -0
  13. package/dist/composites/AiOverlay.js +8 -0
  14. package/dist/composites/EditorBubbleMenu.d.ts +10 -0
  15. package/dist/composites/EditorBubbleMenu.d.ts.map +1 -0
  16. package/dist/composites/EditorBubbleMenu.js +16 -0
  17. package/dist/composites/EditorToolbar.d.ts +20 -0
  18. package/dist/composites/EditorToolbar.d.ts.map +1 -0
  19. package/dist/composites/EditorToolbar.js +45 -0
  20. package/dist/composites/ImageBubbleMenu.d.ts +7 -0
  21. package/dist/composites/ImageBubbleMenu.d.ts.map +1 -0
  22. package/dist/composites/ImageBubbleMenu.js +15 -0
  23. package/dist/composites/MentionMenu.d.ts +11 -0
  24. package/dist/composites/MentionMenu.d.ts.map +1 -0
  25. package/dist/composites/MentionMenu.js +10 -0
  26. package/dist/composites/SlashCommandMenu.d.ts +13 -0
  27. package/dist/composites/SlashCommandMenu.d.ts.map +1 -0
  28. package/dist/composites/SlashCommandMenu.js +10 -0
  29. package/dist/composites/SpatikaEditor.d.ts +14 -0
  30. package/dist/composites/SpatikaEditor.d.ts.map +1 -0
  31. package/dist/composites/SpatikaEditor.js +159 -0
  32. package/dist/composites/TableGridPicker.d.ts +9 -0
  33. package/dist/composites/TableGridPicker.d.ts.map +1 -0
  34. package/dist/composites/TableGridPicker.js +54 -0
  35. package/dist/composites/ToolbarButton.d.ts +7 -0
  36. package/dist/composites/ToolbarButton.d.ts.map +1 -0
  37. package/dist/composites/ToolbarButton.js +7 -0
  38. package/dist/composites/ToolbarFormatPanels.d.ts +9 -0
  39. package/dist/composites/ToolbarFormatPanels.d.ts.map +1 -0
  40. package/dist/composites/ToolbarFormatPanels.js +35 -0
  41. package/dist/composites/ToolbarInsertPanels.d.ts +14 -0
  42. package/dist/composites/ToolbarInsertPanels.d.ts.map +1 -0
  43. package/dist/composites/ToolbarInsertPanels.js +96 -0
  44. package/dist/composites/ToolbarPopover.d.ts +14 -0
  45. package/dist/composites/ToolbarPopover.d.ts.map +1 -0
  46. package/dist/composites/ToolbarPopover.js +48 -0
  47. package/dist/extensions/ai-action.d.ts +24 -0
  48. package/dist/extensions/ai-action.d.ts.map +1 -0
  49. package/dist/extensions/ai-action.js +53 -0
  50. package/dist/extensions/mention.d.ts +17 -0
  51. package/dist/extensions/mention.d.ts.map +1 -0
  52. package/dist/extensions/mention.js +129 -0
  53. package/dist/extensions/resizable-image-view.d.ts +18 -0
  54. package/dist/extensions/resizable-image-view.d.ts.map +1 -0
  55. package/dist/extensions/resizable-image-view.js +70 -0
  56. package/dist/extensions/resizable-image.d.ts +4 -0
  57. package/dist/extensions/resizable-image.d.ts.map +1 -0
  58. package/dist/extensions/resizable-image.js +68 -0
  59. package/dist/extensions/slash-command.d.ts +18 -0
  60. package/dist/extensions/slash-command.d.ts.map +1 -0
  61. package/dist/extensions/slash-command.js +178 -0
  62. package/dist/index.d.ts +24 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +18 -0
  65. package/dist/lib/ai-command-menu.d.ts +9 -0
  66. package/dist/lib/ai-command-menu.d.ts.map +1 -0
  67. package/dist/lib/ai-command-menu.js +43 -0
  68. package/dist/lib/cn.d.ts +4 -0
  69. package/dist/lib/cn.d.ts.map +1 -0
  70. package/dist/lib/cn.js +6 -0
  71. package/dist/lib/editor-format-colors.d.ts +10 -0
  72. package/dist/lib/editor-format-colors.d.ts.map +1 -0
  73. package/dist/lib/editor-format-colors.js +24 -0
  74. package/dist/lib/image-upload.d.ts +14 -0
  75. package/dist/lib/image-upload.d.ts.map +1 -0
  76. package/dist/lib/image-upload.js +29 -0
  77. package/dist/lib/insert-editor-images.d.ts +5 -0
  78. package/dist/lib/insert-editor-images.d.ts.map +1 -0
  79. package/dist/lib/insert-editor-images.js +32 -0
  80. package/dist/lib/types.d.ts +131 -0
  81. package/dist/lib/types.d.ts.map +1 -0
  82. package/dist/lib/types.js +12 -0
  83. package/dist/lib/use-spatika-editor.d.ts +13 -0
  84. package/dist/lib/use-spatika-editor.d.ts.map +1 -0
  85. package/dist/lib/use-spatika-editor.js +171 -0
  86. package/dist/styles.css +1056 -0
  87. package/package.json +101 -0
  88. package/src/composites/AiCommandDock.test.tsx +48 -0
  89. package/src/composites/AiCommandDock.tsx +137 -0
  90. package/src/composites/AiCommandMenu.test.tsx +67 -0
  91. package/src/composites/AiCommandMenu.tsx +120 -0
  92. package/src/composites/AiCommandPanel.test.tsx +42 -0
  93. package/src/composites/AiCommandPanel.tsx +56 -0
  94. package/src/composites/AiOverlay.test.tsx +18 -0
  95. package/src/composites/AiOverlay.tsx +18 -0
  96. package/src/composites/EditorBubbleMenu.test.tsx +49 -0
  97. package/src/composites/EditorBubbleMenu.tsx +73 -0
  98. package/src/composites/EditorToolbar.test.tsx +146 -0
  99. package/src/composites/EditorToolbar.tsx +362 -0
  100. package/src/composites/ImageBubbleMenu.test.tsx +43 -0
  101. package/src/composites/ImageBubbleMenu.tsx +51 -0
  102. package/src/composites/MentionMenu.test.tsx +25 -0
  103. package/src/composites/MentionMenu.tsx +46 -0
  104. package/src/composites/SlashCommandMenu.test.tsx +33 -0
  105. package/src/composites/SlashCommandMenu.tsx +54 -0
  106. package/src/composites/SpatikaEditor.test.tsx +167 -0
  107. package/src/composites/SpatikaEditor.tsx +302 -0
  108. package/src/composites/TableGridPicker.test.tsx +26 -0
  109. package/src/composites/TableGridPicker.tsx +138 -0
  110. package/src/composites/ToolbarButton.test.tsx +21 -0
  111. package/src/composites/ToolbarButton.tsx +24 -0
  112. package/src/composites/ToolbarFormatPanels.test.tsx +46 -0
  113. package/src/composites/ToolbarFormatPanels.tsx +78 -0
  114. package/src/composites/ToolbarInsertPanels.test.tsx +60 -0
  115. package/src/composites/ToolbarInsertPanels.tsx +200 -0
  116. package/src/composites/ToolbarPopover.test.tsx +24 -0
  117. package/src/composites/ToolbarPopover.tsx +95 -0
  118. package/src/extensions/ai-action.test.ts +26 -0
  119. package/src/extensions/ai-action.ts +73 -0
  120. package/src/extensions/mention.test.ts +31 -0
  121. package/src/extensions/mention.ts +158 -0
  122. package/src/extensions/resizable-image-view.test.ts +26 -0
  123. package/src/extensions/resizable-image-view.ts +96 -0
  124. package/src/extensions/resizable-image.test.ts +28 -0
  125. package/src/extensions/resizable-image.ts +75 -0
  126. package/src/extensions/slash-command.test.ts +45 -0
  127. package/src/extensions/slash-command.ts +197 -0
  128. package/src/index.ts +49 -0
  129. package/src/lib/ai-command-menu.test.ts +48 -0
  130. package/src/lib/ai-command-menu.ts +57 -0
  131. package/src/lib/cn.ts +7 -0
  132. package/src/lib/editor-format-colors.test.ts +15 -0
  133. package/src/lib/editor-format-colors.ts +31 -0
  134. package/src/lib/image-upload.test.ts +19 -0
  135. package/src/lib/image-upload.ts +49 -0
  136. package/src/lib/insert-editor-images.test.ts +76 -0
  137. package/src/lib/insert-editor-images.ts +44 -0
  138. package/src/lib/types.ts +149 -0
  139. package/src/lib/use-spatika-editor.test.tsx +56 -0
  140. package/src/lib/use-spatika-editor.ts +191 -0
  141. package/src/styles/editor.css +1056 -0
  142. package/src/test/setup.ts +46 -0
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # @spatika/editor
2
+
3
+ Tiptap-powered rich text editor with Spatika glass theming, slash commands, @mentions, AI hooks, and an extensible toolbar.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @spatika/editor @spatika/tokens
9
+ ```
10
+
11
+ Peer dependencies: `react` and `react-dom` (^18 or ^19).
12
+
13
+ ## Bootstrap
14
+
15
+ ```tsx
16
+ import "@spatika/tokens/styles.css";
17
+ import "@spatika/editor/styles.css";
18
+ import { SpatikaThemeProvider } from "@spatika/react";
19
+ import { SpatikaEditor } from "@spatika/editor";
20
+ ```
21
+
22
+ `SpatikaEditor` is also re-exported from `@spatika/react`.
23
+
24
+ ## Usage
25
+
26
+ ```tsx
27
+ <SpatikaEditor
28
+ value={html}
29
+ onChange={setHtml}
30
+ placeholder="Start writing…"
31
+ mentions={[{ id: "1", label: "Asha Verma" }]}
32
+ onAiCommand={async (context) => rewrite(context.actionId, context.selectedText)}
33
+ toolbar={{ layout: "ribbon" }}
34
+ />
35
+ ```
36
+
37
+ ## Headless
38
+
39
+ Use `useSpatikaEditor` when you need full control over chrome while keeping Spatika's default extensions.
40
+
41
+ ## License
42
+
43
+ MIT — uses MIT-licensed Tiptap packages only.
@@ -0,0 +1,13 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ import type { AiActionDefinition, AiCommandMenuConfig } from "../lib/types";
3
+ import type { AiCommandRunRequest } from "./AiCommandMenu";
4
+ type AiCommandDockProps = {
5
+ editor: Editor | null;
6
+ config?: AiCommandMenuConfig;
7
+ actions?: AiActionDefinition[];
8
+ onRun: (request: AiCommandRunRequest) => void;
9
+ className?: string;
10
+ };
11
+ export declare function AiCommandDock({ editor, config, actions, onRun, className }: AiCommandDockProps): import("react").JSX.Element | null;
12
+ export {};
13
+ //# sourceMappingURL=AiCommandDock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiCommandDock.d.ts","sourceRoot":"","sources":["../../src/composites/AiCommandDock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAgB3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAI5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAoB3D,KAAK,kBAAkB,GAAG;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,kBAAkB,sCAwF9F"}
@@ -0,0 +1,63 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ArrowLeft, ArrowUp, MessageSquarePlus, PenLine, Plus, Search, Sparkles, Table2, } from "lucide-react";
3
+ import { useEffect, useId, useRef, useState } from "react";
4
+ import { resolveAiCommandActions, resolveAiPromptConfig, } from "../lib/ai-command-menu";
5
+ import { AI_PROMPT_ACTION_ID } from "../lib/types";
6
+ import { cn } from "../lib/cn";
7
+ import { AiCommandPanel } from "./AiCommandPanel";
8
+ const DEFAULT_ACTION_ICONS = {
9
+ proofread: _jsx(Search, { className: "size-4" }),
10
+ rewrite: _jsx(PenLine, { className: "size-4" }),
11
+ shorten: _jsx(ArrowLeft, { className: "size-4" }),
12
+ improve: _jsx(Sparkles, { className: "size-4" }),
13
+ expand: _jsx(Plus, { className: "size-4" }),
14
+ continue: _jsx(Plus, { className: "size-4" }),
15
+ table: _jsx(Table2, { className: "size-4" }),
16
+ comment: _jsx(MessageSquarePlus, { className: "size-4" }),
17
+ };
18
+ function withDefaultIcons(actions) {
19
+ return actions.map((action) => ({
20
+ ...action,
21
+ icon: action.icon ?? DEFAULT_ACTION_ICONS[action.id],
22
+ }));
23
+ }
24
+ export function AiCommandDock({ editor, config, actions, onRun, className }) {
25
+ const [open, setOpen] = useState(false);
26
+ const [prompt, setPrompt] = useState("");
27
+ const rootRef = useRef(null);
28
+ const panelId = useId();
29
+ const title = config?.title ?? "AI Toolkit examples";
30
+ const commandActions = withDefaultIcons(resolveAiCommandActions(config, actions));
31
+ const promptConfig = resolveAiPromptConfig(config?.prompt);
32
+ const hasSelection = Boolean(editor?.state?.selection && !editor.state.selection.empty);
33
+ useEffect(() => {
34
+ if (!open)
35
+ return;
36
+ const onPointerDown = (event) => {
37
+ if (!rootRef.current?.contains(event.target)) {
38
+ setOpen(false);
39
+ }
40
+ };
41
+ document.addEventListener("mousedown", onPointerDown);
42
+ return () => document.removeEventListener("mousedown", onPointerDown);
43
+ }, [open]);
44
+ const runAction = (actionId, userPrompt) => {
45
+ onRun({ actionId, prompt: userPrompt });
46
+ setOpen(false);
47
+ setPrompt("");
48
+ };
49
+ const submitPrompt = () => {
50
+ const trimmed = prompt.trim();
51
+ if (!trimmed)
52
+ return;
53
+ runAction(AI_PROMPT_ACTION_ID, trimmed);
54
+ };
55
+ if (!editor)
56
+ return null;
57
+ return (_jsxs("div", { ref: rootRef, className: cn("spk-editor-ai-dock", className), children: [open ? (_jsx(AiCommandPanel, { id: panelId, title: title, actions: commandActions, hasSelection: hasSelection, onSelect: (actionId) => runAction(actionId), className: "spk-editor-ai-dock-panel" })) : null, promptConfig.enabled ? (_jsxs("div", { className: "spk-editor-ai-dock-bar", role: "search", children: [_jsx("button", { type: "button", className: cn("spk-editor-ai-dock-trigger", open && "spk-editor-ai-dock-trigger--active"), "aria-label": "AI commands", "aria-expanded": open, "aria-controls": open ? panelId : undefined, onClick: () => setOpen((value) => !value), children: _jsx(Sparkles, { className: "size-4" }) }), _jsxs("label", { className: "spk-editor-ai-dock-field", children: [_jsx("span", { className: "sr-only", children: promptConfig.placeholder }), _jsx("input", { type: "text", className: "spk-editor-ai-dock-input", value: prompt, placeholder: promptConfig.placeholder, onFocus: () => setOpen(true), onChange: (event) => setPrompt(event.target.value), onKeyDown: (event) => {
58
+ if (event.key === "Enter")
59
+ submitPrompt();
60
+ if (event.key === "Escape")
61
+ setOpen(false);
62
+ } })] }), _jsx("button", { type: "button", className: "spk-editor-ai-dock-submit", "aria-label": promptConfig.submitLabel, disabled: !prompt.trim(), onClick: submitPrompt, children: _jsx(ArrowUp, { className: "size-4" }) })] })) : null] }));
63
+ }
@@ -0,0 +1,16 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ import type { AiActionDefinition, AiCommandMenuConfig } from "../lib/types";
3
+ export type AiCommandRunRequest = {
4
+ actionId: string;
5
+ prompt?: string;
6
+ };
7
+ type AiCommandMenuProps = {
8
+ editor: Editor | null;
9
+ config?: AiCommandMenuConfig;
10
+ actions?: AiActionDefinition[];
11
+ onRun: (request: AiCommandRunRequest) => void;
12
+ className?: string;
13
+ };
14
+ export declare function AiCommandMenu({ editor, config, actions, onRun, className }: AiCommandMenuProps): import("react").JSX.Element | null;
15
+ export {};
16
+ //# sourceMappingURL=AiCommandMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiCommandMenu.d.ts","sourceRoot":"","sources":["../../src/composites/AiCommandMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAO3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAM5E,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,kBAAkB,sCA6F9F"}
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ArrowUp, Sparkles } from "lucide-react";
3
+ import { useEffect, useId, useRef, useState } from "react";
4
+ import { resolveAiCommandActions, resolveAiPromptConfig, } from "../lib/ai-command-menu";
5
+ import { AI_PROMPT_ACTION_ID } from "../lib/types";
6
+ import { cn } from "../lib/cn";
7
+ import { AiCommandPanel } from "./AiCommandPanel";
8
+ import { ToolbarButton } from "./ToolbarButton";
9
+ export function AiCommandMenu({ editor, config, actions, onRun, className }) {
10
+ const [open, setOpen] = useState(false);
11
+ const [prompt, setPrompt] = useState("");
12
+ const rootRef = useRef(null);
13
+ const titleId = useId();
14
+ const title = config?.title ?? "AI Toolkit examples";
15
+ const commandActions = resolveAiCommandActions(config, actions);
16
+ const promptConfig = resolveAiPromptConfig(config?.prompt);
17
+ const hasSelection = Boolean(editor?.state?.selection && !editor.state.selection.empty);
18
+ useEffect(() => {
19
+ if (!open)
20
+ return;
21
+ const onPointerDown = (event) => {
22
+ if (!rootRef.current?.contains(event.target)) {
23
+ setOpen(false);
24
+ }
25
+ };
26
+ document.addEventListener("mousedown", onPointerDown);
27
+ return () => document.removeEventListener("mousedown", onPointerDown);
28
+ }, [open]);
29
+ const close = () => {
30
+ setOpen(false);
31
+ setPrompt("");
32
+ };
33
+ const runAction = (actionId, userPrompt) => {
34
+ onRun({ actionId, prompt: userPrompt });
35
+ close();
36
+ };
37
+ const submitPrompt = () => {
38
+ const trimmed = prompt.trim();
39
+ if (!trimmed)
40
+ return;
41
+ runAction(AI_PROMPT_ACTION_ID, trimmed);
42
+ };
43
+ if (!editor)
44
+ return null;
45
+ return (_jsxs("div", { ref: rootRef, className: cn("spk-editor-ai-menu", className), children: [_jsx(ToolbarButton, { "aria-label": "AI commands", "aria-expanded": open, "aria-haspopup": "dialog", "aria-controls": open ? titleId : undefined, active: open, onClick: () => setOpen((value) => !value), children: _jsx(Sparkles, { className: "size-4" }) }), open ? (_jsxs("div", { className: "spk-editor-ai-menu-shell", onMouseDown: (event) => event.stopPropagation(), children: [_jsx(AiCommandPanel, { id: titleId, title: title, actions: commandActions, hasSelection: hasSelection, onSelect: (actionId) => runAction(actionId) }), promptConfig.enabled ? (_jsxs("div", { className: "spk-editor-ai-menu-prompt", children: [_jsxs("label", { className: "spk-editor-ai-menu-prompt-field", children: [_jsx("span", { className: "sr-only", children: promptConfig.placeholder }), _jsx("input", { type: "text", className: "spk-editor-ai-menu-prompt-input", value: prompt, placeholder: promptConfig.placeholder, onChange: (event) => setPrompt(event.target.value), onKeyDown: (event) => {
46
+ if (event.key === "Enter")
47
+ submitPrompt();
48
+ if (event.key === "Escape")
49
+ close();
50
+ }, autoFocus: true })] }), _jsx("button", { type: "button", className: "spk-editor-ai-menu-prompt-submit", "aria-label": promptConfig.submitLabel, disabled: !prompt.trim(), onClick: submitPrompt, children: _jsx(ArrowUp, { className: "size-4" }) })] })) : null] })) : null] }));
51
+ }
@@ -0,0 +1,12 @@
1
+ import type { AiActionDefinition } from "../lib/types";
2
+ type AiCommandPanelProps = {
3
+ title: string;
4
+ actions: AiActionDefinition[];
5
+ hasSelection: boolean;
6
+ onSelect: (actionId: string) => void;
7
+ className?: string;
8
+ id?: string;
9
+ };
10
+ export declare function AiCommandPanel({ title, actions, hasSelection, onSelect, className, id, }: AiCommandPanelProps): import("react").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=AiCommandPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiCommandPanel.d.ts","sourceRoot":"","sources":["../../src/composites/AiCommandPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAIvD,KAAK,mBAAmB,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAMF,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,EAAE,GACH,EAAE,mBAAmB,+BA+BrB"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Sparkles } from "lucide-react";
3
+ import { cn } from "../lib/cn";
4
+ function actionDisabled(action, hasSelection) {
5
+ return Boolean(action.requiresSelection && !hasSelection);
6
+ }
7
+ export function AiCommandPanel({ title, actions, hasSelection, onSelect, className, id, }) {
8
+ return (_jsxs("div", { id: id, className: cn("spk-editor-ai-panel", className), role: "dialog", "aria-label": title, children: [_jsx("div", { className: "spk-editor-ai-panel-title", children: title }), _jsx("ul", { className: "spk-editor-ai-panel-list", "aria-label": title, children: actions.map((action) => {
9
+ const disabled = actionDisabled(action, hasSelection);
10
+ return (_jsx("li", { children: _jsxs("button", { type: "button", className: "spk-editor-ai-panel-item", disabled: disabled, onClick: () => onSelect(action.id), children: [_jsx("span", { className: "spk-editor-ai-panel-item-icon", "aria-hidden": "true", children: action.icon ?? _jsx(Sparkles, { className: "size-4" }) }), _jsxs("span", { className: "spk-editor-ai-panel-item-copy", children: [_jsx("span", { className: "spk-editor-ai-panel-item-label", children: action.label }), action.description ? (_jsx("span", { className: "spk-editor-ai-panel-item-desc", children: action.description })) : null] })] }) }, action.id));
11
+ }) })] }));
12
+ }
@@ -0,0 +1,7 @@
1
+ type AiOverlayProps = {
2
+ visible: boolean;
3
+ className?: string;
4
+ };
5
+ export declare function AiOverlay({ visible, className }: AiOverlayProps): import("react").JSX.Element | null;
6
+ export {};
7
+ //# sourceMappingURL=AiOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiOverlay.d.ts","sourceRoot":"","sources":["../../src/composites/AiOverlay.tsx"],"names":[],"mappings":"AAGA,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,cAAc,sCAS/D"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Sparkles } from "lucide-react";
3
+ import { cn } from "../lib/cn";
4
+ export function AiOverlay({ visible, className }) {
5
+ if (!visible)
6
+ return null;
7
+ return (_jsxs("div", { className: cn("spk-editor-ai-overlay", className), "aria-hidden": "true", children: [_jsx(Sparkles, { className: "spk-editor-ai-overlay-icon size-5" }), _jsx("span", { children: "AI is working\u2026" })] }));
8
+ }
@@ -0,0 +1,10 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ import type { AiActionDefinition } from "../lib/types";
3
+ type EditorBubbleMenuProps = {
4
+ editor: Editor | null;
5
+ aiActions?: AiActionDefinition[];
6
+ onAiAction?: (actionId: string) => void;
7
+ };
8
+ export declare function EditorBubbleMenu({ editor, aiActions, onAiAction }: EditorBubbleMenuProps): import("react").JSX.Element | null;
9
+ export {};
10
+ //# sourceMappingURL=EditorBubbleMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorBubbleMenu.d.ts","sourceRoot":"","sources":["../../src/composites/EditorBubbleMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGvD,KAAK,qBAAqB,GAAG;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,qBAAqB,sCA4DxF"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { BubbleMenu } from "@tiptap/react/menus";
3
+ import { Bold, Code, Italic, Sparkles, Strikethrough, Underline as UnderlineIcon } from "lucide-react";
4
+ import { ToolbarButton } from "./ToolbarButton";
5
+ export function EditorBubbleMenu({ editor, aiActions, onAiAction }) {
6
+ if (!editor)
7
+ return null;
8
+ return (_jsxs(BubbleMenu, { editor: editor, className: "spk-editor-bubble-menu", shouldShow: ({ editor: ed, state }) => {
9
+ const { selection } = state;
10
+ if (selection.empty)
11
+ return false;
12
+ if (ed.isActive("image"))
13
+ return false;
14
+ return true;
15
+ }, children: [_jsx(ToolbarButton, { "aria-label": "Bold", active: editor.isActive("bold"), onClick: () => editor.chain().focus().toggleBold().run(), children: _jsx(Bold, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Italic", active: editor.isActive("italic"), onClick: () => editor.chain().focus().toggleItalic().run(), children: _jsx(Italic, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Underline", active: editor.isActive("underline"), onClick: () => editor.chain().focus().toggleUnderline().run(), children: _jsx(UnderlineIcon, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Strikethrough", active: editor.isActive("strike"), onClick: () => editor.chain().focus().toggleStrike().run(), children: _jsx(Strikethrough, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Inline code", active: editor.isActive("code"), onClick: () => editor.chain().focus().toggleCode().run(), children: _jsx(Code, { className: "size-4" }) }), aiActions?.map((action) => (_jsx(ToolbarButton, { "aria-label": action.label, onClick: () => onAiAction?.(action.id), children: action.icon ?? _jsx(Sparkles, { className: "size-4" }) }, action.id)))] }));
16
+ }
@@ -0,0 +1,20 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ import type { ReactNode } from "react";
3
+ import type { AiActionDefinition, AiCommandMenuConfig, ImageInsertConfig, SpatikaEditorToolbarConfig } from "../lib/types";
4
+ import { type AiCommandRunRequest } from "./AiCommandMenu";
5
+ type EditorToolbarProps = {
6
+ editor: Editor | null;
7
+ config?: SpatikaEditorToolbarConfig;
8
+ toolbarActions?: ReactNode;
9
+ aiActions?: AiActionDefinition[];
10
+ aiCommandMenu?: AiCommandMenuConfig | false;
11
+ useAiCommandMenu?: boolean;
12
+ onAiCommand?: (request: AiCommandRunRequest) => void;
13
+ onAiAction?: (actionId: string) => void;
14
+ onInsertImage?: () => void;
15
+ imageInsert?: ImageInsertConfig;
16
+ className?: string;
17
+ };
18
+ export declare function EditorToolbar({ editor, config, toolbarActions, aiActions, aiCommandMenu, useAiCommandMenu, onAiCommand, onAiAction, onInsertImage, imageInsert, className, }: EditorToolbarProps): import("react").JSX.Element | null;
19
+ export {};
20
+ //# sourceMappingURL=EditorToolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditorToolbar.d.ts","sourceRoot":"","sources":["../../src/composites/EditorToolbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAgC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAG3H,OAAO,EAAiB,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAM1E,KAAK,kBAAkB,GAAG;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,0BAA0B,CAAC;IACpC,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACrD,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAMF,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,MAAM,EACN,cAAc,EACd,SAAS,EACT,aAAa,EACb,gBAAwB,EACxB,WAAW,EACX,UAAU,EACV,aAAa,EACb,WAAW,EACX,SAAS,GACV,EAAE,kBAAkB,sCAgSpB"}
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { AlignCenter, AlignJustify, AlignLeft, AlignRight, Bold, Code, Heading1, Heading2, Heading3, Highlighter, ImageIcon, Italic, Link2, List, ListOrdered, ListTodo, Minus, Palette, Pilcrow, Quote, Redo2, Sparkles, SquareCode, Strikethrough, Subscript, Superscript, Table2, Underline as UnderlineIcon, Undo2, } from "lucide-react";
3
+ import { useEffect, useState } from "react";
4
+ import { DEFAULT_TOOLBAR } from "../lib/types";
5
+ import { cn } from "../lib/cn";
6
+ import { AiCommandMenu } from "./AiCommandMenu";
7
+ import { ToolbarButton } from "./ToolbarButton";
8
+ import { ImageInsertPanel, LinkInsertPanel, TableInsertPanel } from "./ToolbarInsertPanels";
9
+ import { HighlightColorPanel, TextColorPanel } from "./ToolbarFormatPanels";
10
+ import { ToolbarPopover } from "./ToolbarPopover";
11
+ function ToolbarGroup({ children, className }) {
12
+ return _jsx("div", { className: cn("spk-editor-toolbar-group", className), children: children });
13
+ }
14
+ export function EditorToolbar({ editor, config, toolbarActions, aiActions, aiCommandMenu, useAiCommandMenu = false, onAiCommand, onAiAction, onInsertImage, imageInsert, className, }) {
15
+ const toolbar = { ...DEFAULT_TOOLBAR, ...config };
16
+ const [, setRevision] = useState(0);
17
+ useEffect(() => {
18
+ if (!editor)
19
+ return;
20
+ const refresh = () => setRevision((value) => value + 1);
21
+ editor.on("transaction", refresh);
22
+ return () => {
23
+ editor.off("transaction", refresh);
24
+ };
25
+ }, [editor]);
26
+ if (!editor)
27
+ return null;
28
+ const historyGroup = toolbar.history ? (_jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { "aria-label": "Undo", disabled: !editor.can().undo(), onClick: () => editor.chain().focus().undo().run(), children: _jsx(Undo2, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Redo", disabled: !editor.can().redo(), onClick: () => editor.chain().focus().redo().run(), children: _jsx(Redo2, { className: "size-4" }) })] })) : null;
29
+ const textStyleGroup = toolbar.textStyle ? (_jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { "aria-label": "Paragraph", active: editor.isActive("paragraph"), onClick: () => editor.chain().focus().setParagraph().run(), children: _jsx(Pilcrow, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Heading 1", active: editor.isActive("heading", { level: 1 }), onClick: () => editor.chain().focus().toggleHeading({ level: 1 }).run(), children: _jsx(Heading1, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Heading 2", active: editor.isActive("heading", { level: 2 }), onClick: () => editor.chain().focus().toggleHeading({ level: 2 }).run(), children: _jsx(Heading2, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Heading 3", active: editor.isActive("heading", { level: 3 }), onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(), children: _jsx(Heading3, { className: "size-4" }) })] })) : null;
30
+ const inlineGroup = toolbar.inlineFormat ? (_jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { "aria-label": "Bold", active: editor.isActive("bold"), onClick: () => editor.chain().focus().toggleBold().run(), children: _jsx(Bold, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Italic", active: editor.isActive("italic"), onClick: () => editor.chain().focus().toggleItalic().run(), children: _jsx(Italic, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Underline", active: editor.isActive("underline"), onClick: () => editor.chain().focus().toggleUnderline().run(), children: _jsx(UnderlineIcon, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Strikethrough", active: editor.isActive("strike"), onClick: () => editor.chain().focus().toggleStrike().run(), children: _jsx(Strikethrough, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Inline code", active: editor.isActive("code"), onClick: () => editor.chain().focus().toggleCode().run(), children: _jsx(Code, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Subscript", active: editor.isActive("subscript"), onClick: () => editor.chain().focus().toggleSubscript().run(), children: _jsx(Subscript, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Superscript", active: editor.isActive("superscript"), onClick: () => editor.chain().focus().toggleSuperscript().run(), children: _jsx(Superscript, { className: "size-4" }) }), _jsx(ToolbarPopover, { label: "Text color", title: "Text color", icon: _jsx(Palette, { className: "size-4" }), active: Boolean(editor.getAttributes("textStyle").color), children: ({ close }) => _jsx(TextColorPanel, { editor: editor, close: close }) }), _jsx(ToolbarPopover, { label: "Highlight", title: "Highlight color", icon: _jsx(Highlighter, { className: "size-4" }), active: editor.isActive("highlight"), children: ({ close }) => _jsx(HighlightColorPanel, { editor: editor, close: close }) }), _jsx(ToolbarButton, { "aria-label": "Blockquote", active: editor.isActive("blockquote"), onClick: () => editor.chain().focus().toggleBlockquote().run(), children: _jsx(Quote, { className: "size-4" }) })] })) : null;
31
+ const listGroup = toolbar.lists ? (_jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { "aria-label": "Bullet list", active: editor.isActive("bulletList"), onClick: () => editor.chain().focus().toggleBulletList().run(), children: _jsx(List, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Numbered list", active: editor.isActive("orderedList"), onClick: () => editor.chain().focus().toggleOrderedList().run(), children: _jsx(ListOrdered, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Task list", active: editor.isActive("taskList"), onClick: () => editor.chain().focus().toggleTaskList().run(), children: _jsx(ListTodo, { className: "size-4" }) })] })) : null;
32
+ const alignGroup = toolbar.alignment ? (_jsxs(ToolbarGroup, { children: [_jsx(ToolbarButton, { "aria-label": "Align left", active: editor.isActive({ textAlign: "left" }), onClick: () => editor.chain().focus().setTextAlign("left").run(), children: _jsx(AlignLeft, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Align center", active: editor.isActive({ textAlign: "center" }), onClick: () => editor.chain().focus().setTextAlign("center").run(), children: _jsx(AlignCenter, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Align right", active: editor.isActive({ textAlign: "right" }), onClick: () => editor.chain().focus().setTextAlign("right").run(), children: _jsx(AlignRight, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Justify", active: editor.isActive({ textAlign: "justify" }), onClick: () => editor.chain().focus().setTextAlign("justify").run(), children: _jsx(AlignJustify, { className: "size-4" }) })] })) : null;
33
+ const insertGroup = toolbar.insert ? (_jsxs(ToolbarGroup, { children: [_jsx(ToolbarPopover, { label: "Insert link", title: "Insert link", icon: _jsx(Link2, { className: "size-4" }), children: ({ close }) => _jsx(LinkInsertPanel, { editor: editor, close: close }) }), _jsx(ToolbarButton, { "aria-label": "Insert divider", onClick: () => editor.chain().focus().setHorizontalRule().run(), children: _jsx(Minus, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Code block", active: editor.isActive("codeBlock"), onClick: () => editor.chain().focus().toggleCodeBlock().run(), children: _jsx(SquareCode, { className: "size-4" }) }), _jsx(ToolbarPopover, { label: "Insert table", title: "Insert table", icon: _jsx(Table2, { className: "size-4" }), children: ({ close }) => _jsx(TableInsertPanel, { editor: editor, close: close }) }), onInsertImage ? (_jsx(ToolbarButton, { "aria-label": "Insert image", onClick: onInsertImage, children: _jsx(ImageIcon, { className: "size-4" }) })) : (_jsx(ToolbarPopover, { label: "Insert image", title: "Insert image", icon: _jsx(ImageIcon, { className: "size-4" }), children: ({ close }) => _jsx(ImageInsertPanel, { editor: editor, close: close, config: imageInsert }) }))] })) : null;
34
+ const aiGroup = toolbar.ai && useAiCommandMenu && onAiCommand ? (_jsx(ToolbarGroup, { children: _jsx(AiCommandMenu, { editor: editor, config: typeof aiCommandMenu === "object" ? aiCommandMenu : undefined, actions: aiActions, onRun: onAiCommand }) })) : toolbar.ai && aiActions?.length ? (_jsx(ToolbarGroup, { children: aiActions.map((action) => (_jsx(ToolbarButton, { "aria-label": action.label, onClick: () => onAiAction?.(action.id), children: action.icon ?? _jsx(Sparkles, { className: "size-4" }) }, action.id))) })) : null;
35
+ const groupNodes = [
36
+ { id: "history", node: historyGroup },
37
+ { id: "text-style", node: textStyleGroup },
38
+ { id: "inline", node: inlineGroup },
39
+ { id: "lists", node: listGroup },
40
+ { id: "align", node: alignGroup },
41
+ { id: "insert", node: insertGroup },
42
+ { id: "ai", node: aiGroup },
43
+ ].filter((entry) => entry.node);
44
+ return (_jsxs("div", { className: cn("spk-editor-toolbar", toolbar.layout === "compact" && "spk-editor-toolbar--compact", className), role: "toolbar", "aria-label": "Editor formatting", children: [_jsx("div", { className: "spk-editor-toolbar-row", children: groupNodes.map((entry) => (_jsx("div", { children: entry.node }, entry.id))) }), toolbarActions ? _jsx("div", { className: "spk-editor-toolbar-actions", children: toolbarActions }) : null] }));
45
+ }
@@ -0,0 +1,7 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ type ImageBubbleMenuProps = {
3
+ editor: Editor | null;
4
+ };
5
+ export declare function ImageBubbleMenu({ editor }: ImageBubbleMenuProps): import("react").JSX.Element | null;
6
+ export {};
7
+ //# sourceMappingURL=ImageBubbleMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageBubbleMenu.d.ts","sourceRoot":"","sources":["../../src/composites/ImageBubbleMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAM3C,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,EAAE,oBAAoB,sCAwC/D"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { BubbleMenu } from "@tiptap/react/menus";
3
+ import { AlignCenter, AlignLeft, AlignRight, Trash2 } from "lucide-react";
4
+ import { ToolbarButton } from "./ToolbarButton";
5
+ export function ImageBubbleMenu({ editor }) {
6
+ if (!editor)
7
+ return null;
8
+ const setAlign = (align) => {
9
+ editor.chain().focus().updateAttributes("image", { align }).run();
10
+ };
11
+ const setWidth = (width) => {
12
+ editor.chain().focus().updateAttributes("image", { width }).run();
13
+ };
14
+ return (_jsxs(BubbleMenu, { editor: editor, className: "spk-editor-bubble-menu", shouldShow: ({ editor: ed }) => ed.isActive("image"), children: [_jsx(ToolbarButton, { "aria-label": "Align image left", onClick: () => setAlign("left"), children: _jsx(AlignLeft, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Align image center", onClick: () => setAlign("center"), children: _jsx(AlignCenter, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Align image right", onClick: () => setAlign("right"), children: _jsx(AlignRight, { className: "size-4" }) }), _jsx(ToolbarButton, { "aria-label": "Image width 50%", onClick: () => setWidth("50%"), children: "50%" }), _jsx(ToolbarButton, { "aria-label": "Image width 100%", onClick: () => setWidth("100%"), children: "100%" }), _jsx(ToolbarButton, { "aria-label": "Delete image", onClick: () => editor.chain().focus().deleteSelection().run(), children: _jsx(Trash2, { className: "size-4" }) })] }));
15
+ }
@@ -0,0 +1,11 @@
1
+ import type { MentionContact } from "../lib/types";
2
+ type MentionMenuProps = {
3
+ contacts: MentionContact[];
4
+ query: string;
5
+ activeIndex: number;
6
+ open: boolean;
7
+ onSelect: (contact: MentionContact) => void;
8
+ };
9
+ export declare function MentionMenu({ contacts, query, activeIndex, open, onSelect }: MentionMenuProps): import("react").JSX.Element | null;
10
+ export {};
11
+ //# sourceMappingURL=MentionMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MentionMenu.d.ts","sourceRoot":"","sources":["../../src/composites/MentionMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,KAAK,gBAAgB,GAAG;IACtB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CAC7C,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,gBAAgB,sCAkC7F"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../lib/cn";
3
+ export function MentionMenu({ contacts, query, activeIndex, open, onSelect }) {
4
+ if (!open || contacts.length === 0)
5
+ return null;
6
+ return (_jsxs("div", { className: "spk-editor-suggestion", role: "listbox", "aria-label": "Mentions", children: [_jsx("div", { className: "spk-editor-suggestion-header", children: query ? `People matching “@${query}”` : "Mention someone" }), _jsx("ul", { className: "spk-editor-suggestion-list", children: contacts.map((contact, index) => (_jsx("li", { children: _jsxs("button", { type: "button", role: "option", "aria-selected": index === activeIndex, className: cn("spk-editor-suggestion-item", index === activeIndex && "spk-editor-suggestion-item--active"), onMouseDown: (event) => {
7
+ event.preventDefault();
8
+ onSelect(contact);
9
+ }, children: [_jsx("span", { className: "spk-editor-suggestion-title", children: contact.label }), contact.subtitle ? (_jsx("span", { className: "spk-editor-suggestion-desc", children: contact.subtitle })) : null] }) }, contact.id))) })] }));
10
+ }
@@ -0,0 +1,13 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ import type { SlashCommandItem } from "../lib/types";
3
+ type SlashCommandMenuProps = {
4
+ editor: Editor | null;
5
+ items: SlashCommandItem[];
6
+ query: string;
7
+ activeIndex: number;
8
+ open: boolean;
9
+ onSelect: (item: SlashCommandItem) => void;
10
+ };
11
+ export declare function SlashCommandMenu({ items, query, activeIndex, open, onSelect, }: SlashCommandMenuProps): import("react").JSX.Element | null;
12
+ export {};
13
+ //# sourceMappingURL=SlashCommandMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlashCommandMenu.d.ts","sourceRoot":"","sources":["../../src/composites/SlashCommandMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD,KAAK,qBAAqB,GAAG;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,KAAK,EACL,WAAW,EACX,IAAI,EACJ,QAAQ,GACT,EAAE,qBAAqB,sCAkCvB"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../lib/cn";
3
+ export function SlashCommandMenu({ items, query, activeIndex, open, onSelect, }) {
4
+ if (!open || items.length === 0)
5
+ return null;
6
+ return (_jsxs("div", { className: "spk-editor-suggestion", role: "listbox", "aria-label": "Slash commands", children: [_jsx("div", { className: "spk-editor-suggestion-header", children: query ? `Results for “/${query}”` : "Insert block" }), _jsx("ul", { className: "spk-editor-suggestion-list", children: items.map((item, index) => (_jsx("li", { children: _jsxs("button", { type: "button", role: "option", "aria-selected": index === activeIndex, className: cn("spk-editor-suggestion-item", index === activeIndex && "spk-editor-suggestion-item--active"), onMouseDown: (event) => {
7
+ event.preventDefault();
8
+ onSelect(item);
9
+ }, children: [_jsx("span", { className: "spk-editor-suggestion-title", children: item.title }), item.description ? (_jsx("span", { className: "spk-editor-suggestion-desc", children: item.description })) : null] }) }, item.id))) })] }));
10
+ }
@@ -0,0 +1,14 @@
1
+ import type { SpatikaEditorHandle } from "../lib/types";
2
+ export declare const SpatikaEditor: import("react").ForwardRefExoticComponent<import("..").UseSpatikaEditorOptions & {
3
+ className?: string;
4
+ heightClassName?: string;
5
+ toolbar?: import("..").SpatikaEditorToolbarConfig;
6
+ toolbarActions?: import("react").ReactNode;
7
+ isAiProcessing?: boolean;
8
+ aiActions?: import("..").AiActionDefinition[];
9
+ aiCommandMenu?: import("..").AiCommandMenuConfig | false;
10
+ imageInsert?: import("..").ImageInsertConfig;
11
+ onInsertImage?: () => void;
12
+ mobileFullscreen?: boolean;
13
+ } & import("react").RefAttributes<SpatikaEditorHandle>>;
14
+ //# sourceMappingURL=SpatikaEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpatikaEditor.d.ts","sourceRoot":"","sources":["../../src/composites/SpatikaEditor.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,mBAAmB,EAAsB,MAAM,cAAc,CAAC;AAmB5E,eAAO,MAAM,aAAa;;;;;;;;;;;uDA2QzB,CAAC"}