@clevertask/scribe 0.0.14 → 0.1.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 (68) hide show
  1. package/README.md +26 -25
  2. package/dist/BarMenu-BDtEfu-R.js +327 -0
  3. package/dist/assets/index.css +1 -1
  4. package/dist/components/Menu/BarMenu.d.ts +0 -1
  5. package/dist/components/Menu/BarMenu.d.ts.map +1 -1
  6. package/dist/components/Menu/BarMenu.js +8 -119
  7. package/dist/components/Menu/BubbleMenu.d.ts.map +1 -1
  8. package/dist/components/Menu/BubbleMenu.js +2070 -159
  9. package/dist/components/Menu/Mobile/ListOptionBar.d.ts.map +1 -1
  10. package/dist/components/Menu/Mobile/ListOptionBar.js +42 -34
  11. package/dist/components/Scribe/extension/emoji/EmojiList.d.ts +19 -1
  12. package/dist/components/Scribe/extension/emoji/EmojiList.d.ts.map +1 -1
  13. package/dist/components/Scribe/extension/emoji/EmojiList.js +38 -27
  14. package/dist/components/Scribe/extension/emoji/suggest.d.ts +2 -4
  15. package/dist/components/Scribe/extension/emoji/suggest.d.ts.map +1 -1
  16. package/dist/components/Scribe/extension/emoji/suggest.js +20 -15
  17. package/dist/components/Scribe/extension/extension-link.d.ts.map +1 -1
  18. package/dist/components/Scribe/extension/extension-link.js +2 -986
  19. package/dist/components/Scribe/extension/extension-markdown-paste.d.ts +4 -0
  20. package/dist/components/Scribe/extension/extension-markdown-paste.d.ts.map +1 -0
  21. package/dist/components/Scribe/extension/extension-markdown-paste.js +46 -0
  22. package/dist/components/Scribe/extension/extension-selectedText.js +1 -1
  23. package/dist/components/Scribe/extension/getPopupMountTarget.d.ts +3 -0
  24. package/dist/components/Scribe/extension/getPopupMountTarget.d.ts.map +1 -0
  25. package/dist/components/Scribe/extension/getPopupMountTarget.js +16 -0
  26. package/dist/components/Scribe/extension/index.d.ts +1 -1
  27. package/dist/components/Scribe/extension/index.d.ts.map +1 -1
  28. package/dist/components/Scribe/extension/index.js +37047 -32
  29. package/dist/components/Scribe/extension/slashCommand/SlashCommandList.d.ts +4 -1
  30. package/dist/components/Scribe/extension/slashCommand/SlashCommandList.d.ts.map +1 -1
  31. package/dist/components/Scribe/extension/slashCommand/SlashCommandList.js +3732 -13
  32. package/dist/components/Scribe/extension/slashCommand/index.js +2 -2
  33. package/dist/components/Scribe/extension/slashCommand/items.d.ts.map +1 -1
  34. package/dist/components/Scribe/extension/slashCommand/renderItems.d.ts +1 -1
  35. package/dist/components/Scribe/extension/slashCommand/renderItems.d.ts.map +1 -1
  36. package/dist/components/Scribe/extension/slashCommand/renderItems.js +21 -16
  37. package/dist/components/Scribe/index.d.ts +0 -1
  38. package/dist/components/Scribe/index.d.ts.map +1 -1
  39. package/dist/components/Scribe/index.js +83 -90
  40. package/dist/extension-link-D3eyOFkn.js +1030 -0
  41. package/dist/icons/ToolbarIcons.d.ts +19 -0
  42. package/dist/icons/ToolbarIcons.d.ts.map +1 -0
  43. package/dist/icons/ToolbarIcons.js +135 -0
  44. package/dist/index-DZylq4Bc.js +232 -0
  45. package/dist/index-FY_iYS6i.js +1410 -0
  46. package/dist/index-PJNQPLn5.js +841 -0
  47. package/dist/{index-flsxByQS.js → index-hHvpW2H6.js} +6552 -5417
  48. package/dist/main.css +200 -1120
  49. package/dist/main.js +1 -1
  50. package/dist/markdown-to-html-BwS08CTi.js +1135 -0
  51. package/dist/{purify.es-BRDuGiV2.js → purify.es-BPDBzHtc.js} +1 -1
  52. package/dist/tippy.esm-DLHdsnfG.js +1711 -0
  53. package/dist/utils/convert-legacy-math-delimiters.d.ts.map +1 -1
  54. package/dist/utils/create-scribe-editor.d.ts +3 -3
  55. package/dist/utils/create-scribe-editor.d.ts.map +1 -1
  56. package/dist/utils/create-scribe-editor.js +8 -4
  57. package/dist/utils/html-to-markdown.d.ts.map +1 -1
  58. package/dist/utils/html-to-markdown.js +663 -18
  59. package/dist/utils/index.d.ts +1 -1
  60. package/dist/utils/index.js +3 -3
  61. package/dist/utils/markdown-to-html.js +3 -4
  62. package/package.json +59 -62
  63. package/dist/clsx-OuTLNxxd.js +0 -16
  64. package/dist/index-BfaHEr44.js +0 -159
  65. package/dist/index-Bvgjhwaj.js +0 -2349
  66. package/dist/index-DAuPG8ME.js +0 -50919
  67. package/dist/marked.esm-H7n4rMcO.js +0 -1554
  68. package/dist/turndown.browser.es-RmA_HBaI.js +0 -649
package/README.md CHANGED
@@ -6,6 +6,7 @@ A versatile, block-based rich text editor for diverse applications, built with T
6
6
 
7
7
  - **Block-based Editing:** Enjoy a familiar and intuitive Notion-style editing experience.
8
8
  - **Markdown Support:** Parse and render Markdown content effortlessly.
9
+ - **Markdown Paste:** Paste plain-text markdown into the editor and have it converted into rich content automatically.
9
10
  - **Versatile Integration:** Easily integrate `@clevertask/scribe` into any project requiring rich text editing.
10
11
  - **View and Edit:** Seamlessly switch between viewing and editing modes.
11
12
 
@@ -36,7 +37,9 @@ npm install @clevertask/scribe
36
37
  ### Basic usage
37
38
 
38
39
  ```tsx
40
+ import "@radix-ui/themes/styles.css";
39
41
  import "@clevertask/scribe/dist/main.css";
42
+ import { Theme } from "@radix-ui/themes";
40
43
  import { Scribe, ScribeOnChangeContents } from "@clevertask/scribe";
41
44
 
42
45
  function App() {
@@ -47,14 +50,20 @@ function App() {
47
50
  [],
48
51
  );
49
52
 
50
- return <Scribe onContentChange={onContentChange} />;
53
+ return (
54
+ <Theme>
55
+ <Scribe onContentChange={onContentChange} />
56
+ </Theme>
57
+ );
51
58
  }
52
59
  ```
53
60
 
54
61
  ### With ref
55
62
 
56
63
  ```tsx
64
+ import "@radix-ui/themes/styles.css";
57
65
  import "@clevertask/scribe/dist/main.css";
66
+ import { Theme } from "@radix-ui/themes";
58
67
  import { Scribe, ScribeOnChangeContents } from "@clevertask/scribe";
59
68
 
60
69
  function App() {
@@ -66,37 +75,36 @@ function App() {
66
75
 
67
76
  return (
68
77
  <>
69
- <Scribe ref={editor} />
78
+ <Theme>
79
+ <Scribe ref={editor} />
80
+ </Theme>
70
81
  <button onClick={resetContent}>Reset content</button>
71
82
  </>
72
83
  );
73
84
  }
74
85
  ```
75
86
 
76
- ### With Dark Mode
87
+ ### Using Your App Theme
77
88
 
78
89
  ```tsx
90
+ import "@radix-ui/themes/styles.css";
79
91
  import "@clevertask/scribe/dist/main.css";
80
- import { Scribe, ScribeOnChangeContents } from "@clevertask/scribe";
92
+ import { Theme } from "@radix-ui/themes";
93
+ import { Scribe } from "@clevertask/scribe";
81
94
 
82
95
  function App() {
83
- const editor = useRef<ScribeRef>(null);
84
-
85
- const resetContent = useCallback(() => {
86
- editor.current.resetContent();
87
- }, []);
88
-
89
96
  return (
90
- <>
91
- <Scribe darkMode />
92
- <button onClick={resetContent}>Reset content</button>
93
- </>
97
+ <Theme appearance="dark">
98
+ <Scribe />
99
+ </Theme>
94
100
  );
95
101
  }
96
102
  ```
97
103
 
98
104
  ## Math Expressions
99
105
 
106
+ Scribe's default UI is styled with Radix Themes components. Load `@radix-ui/themes/styles.css` once in your app alongside `@clevertask/scribe/dist/main.css`, and render Scribe somewhere inside a Radix `<Theme>`.
107
+
100
108
  Scribe ships with `@tiptap/extension-mathematics`. The extension renders math when it receives math nodes in the HTML:
101
109
 
102
110
  ```html
@@ -141,7 +149,6 @@ If your content arrives as HTML (for example from a server), use the helper belo
141
149
  | `mainContainerStyle` | `React.CSSProperties` | `undefined` | You can send a CSS object to style the main editor container |
142
150
  | `mainContainerClassName` | `string` | `undefined` | The same idea of `mainContainerStyle` but with classes. |
143
151
  | `onKeyDown` | `KeyboardEventHandler` | `undefined` | A callback function that is triggered when a key is pressed within the editor. This allows you to handle custom keyboard shortcuts. For example, you can use this prop to implement a "send message" functionality when `Ctrl + Enter` is pressed. |
144
- | `darkMode` | `boolean` | `false` | You can switch the darkMode value to change the text editor's theme |
145
152
 
146
153
  ## Helper Functions
147
154
 
@@ -153,6 +160,8 @@ export declare function md2html(md: string): string;
153
160
 
154
161
  Convert markdown to html. Useful if you're rendering an AI-based response, or if you were storing content on markdown in your database and want to show it on the text editor. This function sanitizes the content to prevent XSS attacks.
155
162
 
163
+ Editable Scribe instances also use this conversion internally when you paste plain-text markdown into the editor.
164
+
156
165
  **Usage Example**:
157
166
 
158
167
  ```tsx
@@ -168,11 +177,7 @@ const ChatMessages = () => {
168
177
  return messages.map((message) => (
169
178
  <Flex key={message.id} direction="column" mb="4">
170
179
  <Heading size="4">{`${message.role}: `}</Heading>
171
- <Scribe
172
- editable={false}
173
- showBarMenu={false}
174
- content={md2html(message.content)}
175
- />
180
+ <Scribe editable={false} showBarMenu={false} content={md2html(message.content)} />
176
181
  </Flex>
177
182
  ));
178
183
  };
@@ -219,11 +224,7 @@ This helper is primarily for consumers upgrading from older Scribe versions who
219
224
  **Usage Example**:
220
225
 
221
226
  ```tsx
222
- import {
223
- convertLegacyMathDelimiters,
224
- md2html,
225
- Scribe,
226
- } from "@clevertask/scribe";
227
+ import { convertLegacyMathDelimiters, md2html, Scribe } from "@clevertask/scribe";
227
228
 
228
229
  const html = md2html(convertLegacyMathDelimiters(rawMarkdown));
229
230
 
@@ -0,0 +1,327 @@
1
+ import { jsx as i, jsxs as l } from "react/jsx-runtime";
2
+ import { Box as A, Flex as r, Popover as g, IconButton as B, Text as m, TextField as R, Button as f, Separator as F } from "@radix-ui/themes";
3
+ import { u as H } from "./index-PJNQPLn5.js";
4
+ import { useState as v, useCallback as u, Fragment as U } from "react";
5
+ import { getPopupMountTarget as V } from "./components/Scribe/extension/getPopupMountTarget.js";
6
+ import { BoldIcon as q, ItalicIcon as E, StrikeIcon as W, InlineCodeIcon as Q, HighlightIcon as G, UnorderedListIcon as J, OrderedListIcon as K, LinkIcon as X, ImageIcon as Y, CodeBlockIcon as Z, BlockQuoteIcon as _, HorizontalLineIcon as ee } from "./icons/ToolbarIcons.js";
7
+ function O(e) {
8
+ var s, a, t = "";
9
+ if (typeof e == "string" || typeof e == "number") t += e;
10
+ else if (typeof e == "object") if (Array.isArray(e)) {
11
+ var h = e.length;
12
+ for (s = 0; s < h; s++) e[s] && (a = O(e[s])) && (t && (t += " "), t += a);
13
+ } else for (a in e) e[a] && (t && (t += " "), t += a);
14
+ return t;
15
+ }
16
+ function I() {
17
+ for (var e, s, a = 0, t = "", h = arguments.length; a < h; a++) (e = arguments[a]) && (s = O(e)) && (t && (t += " "), t += s);
18
+ return t;
19
+ }
20
+ const ce = ({ editor: e }) => {
21
+ const [s, a] = v(!1), [t, h] = v(!1), [p, y] = v(""), [b, L] = v(""), C = V(e), c = H({
22
+ editor: e,
23
+ selector: ({ editor: n }) => n ? {
24
+ isBold: n.isActive("bold"),
25
+ isItalic: n.isActive("italic"),
26
+ isStrike: n.isActive("strike"),
27
+ isCode: n.isActive("code"),
28
+ isHighlight: n.isActive("highlight"),
29
+ isBulletList: n.isActive("bulletList"),
30
+ isOrderedList: n.isActive("orderedList"),
31
+ isLink: n.isActive("link"),
32
+ isImage: n.isActive("image"),
33
+ isCodeBlock: n.isActive("codeBlock"),
34
+ isBlockquote: n.isActive("blockquote")
35
+ } : null
36
+ }), z = u(
37
+ (n) => {
38
+ if (n) {
39
+ const d = e.getAttributes("link").href ?? "";
40
+ y(d), h(!1);
41
+ }
42
+ a(n);
43
+ },
44
+ [e]
45
+ ), M = u(
46
+ (n) => {
47
+ if (n) {
48
+ const d = e.getAttributes("image").src ?? "";
49
+ L(d), a(!1);
50
+ }
51
+ h(n);
52
+ },
53
+ [e]
54
+ ), S = u(() => {
55
+ const n = p.trim();
56
+ if (n.length === 0) {
57
+ e.chain().focus().extendMarkRange("link").unsetLink().run(), a(!1);
58
+ return;
59
+ }
60
+ e.chain().focus().extendMarkRange("link").setLink({ href: n }).selectTextblockEnd().run(), a(!1);
61
+ }, [e, p]), P = u(() => {
62
+ e.chain().focus().extendMarkRange("link").unsetLink().run(), a(!1);
63
+ }, [e]), T = u(() => {
64
+ const n = b.trim();
65
+ n && (e.chain().focus().setImage({ src: n }).run(), h(!1));
66
+ }, [e, b]), D = u(
67
+ (n, d) => {
68
+ n.preventDefault(), d();
69
+ },
70
+ []
71
+ ), w = u((n) => {
72
+ n.preventDefault();
73
+ }, []), N = u(
74
+ ({ target: { value: n } }) => {
75
+ y(n);
76
+ },
77
+ []
78
+ ), $ = u(
79
+ ({ target: { value: n } }) => {
80
+ L(n);
81
+ },
82
+ []
83
+ ), x = [
84
+ [
85
+ {
86
+ name: "bold",
87
+ icon: q,
88
+ command: () => e.chain().focus().toggleBold().run(),
89
+ isActive: () => !!c?.isBold
90
+ },
91
+ {
92
+ name: "italic",
93
+ icon: E,
94
+ command: () => e.chain().focus().toggleItalic().run(),
95
+ isActive: () => !!c?.isItalic
96
+ },
97
+ {
98
+ name: "strike",
99
+ icon: W,
100
+ command: () => e.chain().focus().toggleStrike().run(),
101
+ isActive: () => !!c?.isStrike
102
+ }
103
+ ],
104
+ [
105
+ {
106
+ name: "inline-code",
107
+ icon: Q,
108
+ command: () => e.chain().focus().toggleCode().run(),
109
+ isActive: () => !!c?.isCode
110
+ },
111
+ {
112
+ name: "highlight",
113
+ icon: G,
114
+ command: () => e.chain().focus().toggleHighlight().run(),
115
+ isActive: () => !!c?.isHighlight
116
+ }
117
+ ],
118
+ [
119
+ {
120
+ name: "unordered-list",
121
+ icon: J,
122
+ command: () => e.chain().focus().toggleBulletList().run(),
123
+ isActive: () => !!c?.isBulletList
124
+ },
125
+ {
126
+ name: "ordered-list",
127
+ icon: K,
128
+ command: () => e.chain().focus().toggleOrderedList().run(),
129
+ isActive: () => !!c?.isOrderedList
130
+ }
131
+ ],
132
+ [
133
+ {
134
+ name: "link",
135
+ icon: X,
136
+ isActive: () => !!c?.isLink,
137
+ popover: "link"
138
+ },
139
+ {
140
+ name: "image",
141
+ icon: Y,
142
+ isActive: () => !!c?.isImage,
143
+ disabled: !1,
144
+ popover: "image"
145
+ },
146
+ {
147
+ name: "code-block",
148
+ icon: Z,
149
+ command: () => e.chain().focus().toggleCodeBlock().run(),
150
+ isActive: () => !!c?.isCodeBlock
151
+ },
152
+ {
153
+ name: "block-quote",
154
+ icon: _,
155
+ command: () => e.chain().focus().toggleBlockquote().run(),
156
+ isActive: () => !!c?.isBlockquote
157
+ },
158
+ {
159
+ name: "horizontal-line",
160
+ icon: ee,
161
+ command: () => e.chain().focus().setHorizontalRule().run(),
162
+ isActive: () => !1
163
+ }
164
+ ]
165
+ ];
166
+ return /* @__PURE__ */ i(A, { className: "scribe-toolbar", children: /* @__PURE__ */ i(r, { align: "center", gap: "3", wrap: "wrap", children: x.map((n, d) => /* @__PURE__ */ l(U, { children: [
167
+ /* @__PURE__ */ i(r, { align: "center", gap: "2", wrap: "wrap", children: n.map((o, k) => o.popover === "link" ? /* @__PURE__ */ l(
168
+ g.Root,
169
+ {
170
+ open: s,
171
+ onOpenChange: z,
172
+ children: [
173
+ /* @__PURE__ */ i(g.Trigger, { children: /* @__PURE__ */ i(
174
+ B,
175
+ {
176
+ type: "button",
177
+ radius: "medium",
178
+ color: "gray",
179
+ variant: o.isActive() ? "soft" : "ghost",
180
+ disabled: o.disabled || !e.isEditable,
181
+ title: o.name,
182
+ onMouseDown: w,
183
+ className: I(o.disabled && "scribe-toolbar-button--disabled"),
184
+ children: /* @__PURE__ */ i(o.icon, { className: "scribe-toolbar-icon" })
185
+ }
186
+ ) }),
187
+ /* @__PURE__ */ i(
188
+ g.Content,
189
+ {
190
+ container: C,
191
+ size: "2",
192
+ side: "bottom",
193
+ align: "start",
194
+ style: { maxWidth: "calc(100vw - 32px)", width: 320 },
195
+ children: /* @__PURE__ */ l(r, { direction: "column", gap: "4", children: [
196
+ /* @__PURE__ */ l(A, { children: [
197
+ /* @__PURE__ */ i(m, { as: "p", size: "3", weight: "medium", children: "Link" }),
198
+ /* @__PURE__ */ i(m, { as: "p", size: "2", color: "gray", children: "Add or update a link for the current selection." })
199
+ ] }),
200
+ /* @__PURE__ */ i("label", { children: /* @__PURE__ */ l(r, { direction: "column", gap: "2", children: [
201
+ /* @__PURE__ */ i(m, { as: "span", size: "2", weight: "medium", children: "URL" }),
202
+ /* @__PURE__ */ i(
203
+ R.Root,
204
+ {
205
+ autoFocus: !0,
206
+ placeholder: "https://example.com",
207
+ value: p,
208
+ onChange: N
209
+ }
210
+ )
211
+ ] }) }),
212
+ /* @__PURE__ */ l(r, { justify: "between", gap: "3", wrap: "wrap", children: [
213
+ /* @__PURE__ */ i(
214
+ f,
215
+ {
216
+ type: "button",
217
+ color: "red",
218
+ variant: "soft",
219
+ disabled: !((e.getAttributes("link").href ?? "").trim() || p.trim()),
220
+ onClick: P,
221
+ children: "Remove link"
222
+ }
223
+ ),
224
+ /* @__PURE__ */ l(r, { gap: "2", justify: "end", style: { marginLeft: "auto" }, children: [
225
+ /* @__PURE__ */ i(g.Close, { children: /* @__PURE__ */ i(f, { type: "button", variant: "soft", color: "gray", children: "Cancel" }) }),
226
+ /* @__PURE__ */ i(
227
+ f,
228
+ {
229
+ type: "button",
230
+ disabled: p.trim().length === 0,
231
+ onClick: S,
232
+ children: "Save"
233
+ }
234
+ )
235
+ ] })
236
+ ] })
237
+ ] })
238
+ }
239
+ )
240
+ ]
241
+ },
242
+ `${o.name}-${k}`
243
+ ) : o.popover === "image" ? /* @__PURE__ */ l(
244
+ g.Root,
245
+ {
246
+ open: t,
247
+ onOpenChange: M,
248
+ children: [
249
+ /* @__PURE__ */ i(g.Trigger, { children: /* @__PURE__ */ i(
250
+ B,
251
+ {
252
+ type: "button",
253
+ radius: "medium",
254
+ color: "gray",
255
+ variant: o.isActive() ? "soft" : "ghost",
256
+ disabled: o.disabled || !e.isEditable,
257
+ title: o.name,
258
+ onMouseDown: w,
259
+ className: I(o.disabled && "scribe-toolbar-button--disabled"),
260
+ children: /* @__PURE__ */ i(o.icon, { className: "scribe-toolbar-icon" })
261
+ }
262
+ ) }),
263
+ /* @__PURE__ */ i(
264
+ g.Content,
265
+ {
266
+ container: C,
267
+ size: "2",
268
+ side: "bottom",
269
+ align: "start",
270
+ style: { maxWidth: "calc(100vw - 32px)", width: 320 },
271
+ children: /* @__PURE__ */ l(r, { direction: "column", gap: "4", children: [
272
+ /* @__PURE__ */ l(A, { children: [
273
+ /* @__PURE__ */ i(m, { as: "p", size: "3", weight: "medium", children: "Image" }),
274
+ /* @__PURE__ */ i(m, { as: "p", size: "2", color: "gray", children: "Insert an image from a URL." })
275
+ ] }),
276
+ /* @__PURE__ */ i("label", { children: /* @__PURE__ */ l(r, { direction: "column", gap: "2", children: [
277
+ /* @__PURE__ */ i(m, { as: "span", size: "2", weight: "medium", children: "Image URL" }),
278
+ /* @__PURE__ */ i(
279
+ R.Root,
280
+ {
281
+ autoFocus: !0,
282
+ placeholder: "https://example.com/image.png",
283
+ value: b,
284
+ onChange: $
285
+ }
286
+ )
287
+ ] }) }),
288
+ /* @__PURE__ */ l(r, { justify: "end", gap: "2", children: [
289
+ /* @__PURE__ */ i(g.Close, { children: /* @__PURE__ */ i(f, { type: "button", variant: "soft", color: "gray", children: "Cancel" }) }),
290
+ /* @__PURE__ */ i(
291
+ f,
292
+ {
293
+ type: "button",
294
+ disabled: b.trim().length === 0,
295
+ onClick: T,
296
+ children: "Save"
297
+ }
298
+ )
299
+ ] })
300
+ ] })
301
+ }
302
+ )
303
+ ]
304
+ },
305
+ `${o.name}-${k}`
306
+ ) : /* @__PURE__ */ i(
307
+ B,
308
+ {
309
+ type: "button",
310
+ radius: "medium",
311
+ color: "gray",
312
+ variant: o.isActive() ? "soft" : "ghost",
313
+ disabled: o.disabled || !e.isEditable,
314
+ title: o.name,
315
+ onMouseDown: (j) => D(j, o.command),
316
+ className: I(o.disabled && "scribe-toolbar-button--disabled"),
317
+ children: /* @__PURE__ */ i(o.icon, { className: "scribe-toolbar-icon" })
318
+ },
319
+ `${o.name}-${k}`
320
+ )) }),
321
+ d !== x.length - 1 ? /* @__PURE__ */ i(F, { orientation: "vertical", decorative: !0, style: { height: 20 } }) : null
322
+ ] }, `format-group-${d}`)) }) });
323
+ };
324
+ export {
325
+ ce as B,
326
+ I as c
327
+ };