dishui 0.0.83 → 0.0.89

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 (100) hide show
  1. package/dist/components/Demo/index.js +2 -2
  2. package/dist/components/Demo/index.js.map +1 -1
  3. package/dist/components/Input/index.js +52 -62
  4. package/dist/components/Input/index.js.map +1 -1
  5. package/dist/components/LayoutSuite/index.d.ts +10 -0
  6. package/dist/components/LayoutSuite/index.js +27 -18
  7. package/dist/components/LayoutSuite/index.js.map +1 -1
  8. package/dist/components/Markdown/markdownComponents.js +1 -0
  9. package/dist/components/Markdown/markdownComponents.js.map +1 -1
  10. package/dist/components/Markdown/useMarkdownSource.js +46 -31
  11. package/dist/components/Markdown/useMarkdownSource.js.map +1 -1
  12. package/dist/components/Markdown/useMarkmapRenderer.js +44 -31
  13. package/dist/components/Markdown/useMarkmapRenderer.js.map +1 -1
  14. package/dist/components/Markdown/useMermaidRenderer.js +49 -31
  15. package/dist/components/Markdown/useMermaidRenderer.js.map +1 -1
  16. package/dist/components/Page/index.d.ts +18 -4
  17. package/dist/components/Page/index.js +47 -35
  18. package/dist/components/Page/index.js.map +1 -1
  19. package/dist/components/ProtectedRoute/index.d.ts +2 -1
  20. package/dist/components/ProtectedRoute/index.js +16 -6
  21. package/dist/components/ProtectedRoute/index.js.map +1 -1
  22. package/dist/components/Select/index.d.ts +6 -0
  23. package/dist/components/Select/index.js +166 -136
  24. package/dist/components/Select/index.js.map +1 -1
  25. package/dist/components/Tabs/index.d.ts +12 -1
  26. package/dist/components/Tabs/index.js +42 -17
  27. package/dist/components/Tabs/index.js.map +1 -1
  28. package/dist/components/Text/index.d.ts +1 -1
  29. package/dist/components/Text/index.js +2 -2
  30. package/dist/components/Text/index.js.map +1 -1
  31. package/dist/components/pro/ArticleContextMenu/index.js +7 -7
  32. package/dist/components/pro/CodeEditor/editors/CodeEditor.js +200 -189
  33. package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
  34. package/dist/components/pro/CodeEditor/types.d.ts +3 -0
  35. package/dist/components/pro/DataTable/DataTable.d.ts +1 -1
  36. package/dist/components/pro/DataTable/DataTable.js +98 -240
  37. package/dist/components/pro/DataTable/DataTable.js.map +1 -1
  38. package/dist/components/pro/DataTable/components/TableBody.js +14 -16
  39. package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
  40. package/dist/components/pro/DataTable/components/TablePagination.d.ts +3 -9
  41. package/dist/components/pro/DataTable/components/TablePagination.js +29 -25
  42. package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
  43. package/dist/components/pro/DataTable/tanstack-table.d.ts +2 -2
  44. package/dist/components/pro/DataTable/tanstack-table.js +29 -21
  45. package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
  46. package/dist/components/pro/DataTable/treeDataUtils.d.ts +2 -0
  47. package/dist/components/pro/DataTable/treeDataUtils.js +18 -19
  48. package/dist/components/pro/DataTable/treeDataUtils.js.map +1 -1
  49. package/dist/components/pro/DataTable/types.d.ts +24 -0
  50. package/dist/components/pro/DataTable/useDataTableModel.d.ts +16 -0
  51. package/dist/components/pro/DataTable/useDataTableModel.js +148 -0
  52. package/dist/components/pro/DataTable/useDataTableModel.js.map +1 -0
  53. package/dist/components/pro/FileExplorer/Breadcrumb.js +12 -12
  54. package/dist/components/pro/Flow/nodes/DataNodeView.js +87 -82
  55. package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
  56. package/dist/components/pro/Flow/nodes/MediaContent.js +1 -1
  57. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  58. package/dist/components/pro/Flow/nodes/MediaOverlay.js +1 -1
  59. package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
  60. package/dist/components/pro/Flow/nodes/Model3DView.js +69 -63
  61. package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
  62. package/dist/components/pro/Flow/nodes/chartGeometryBudget.d.ts +14 -0
  63. package/dist/components/pro/Flow/nodes/chartGeometryBudget.js +76 -0
  64. package/dist/components/pro/Flow/nodes/chartGeometryBudget.js.map +1 -0
  65. package/dist/components/pro/Flow/nodes/demandRender.d.ts +11 -0
  66. package/dist/components/pro/Flow/nodes/demandRender.js +26 -0
  67. package/dist/components/pro/Flow/nodes/demandRender.js.map +1 -0
  68. package/dist/components/pro/RichTextEditor/SlashMenu.js +68 -58
  69. package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
  70. package/dist/contexts/AppContext.d.ts +1 -0
  71. package/dist/contexts/AppContext.js +144 -145
  72. package/dist/contexts/AppContext.js.map +1 -1
  73. package/dist/contexts/authentication.d.ts +7 -0
  74. package/dist/contexts/authentication.js +22 -0
  75. package/dist/contexts/authentication.js.map +1 -0
  76. package/dist/dishui.css +1 -1
  77. package/dist/hooks/useControllableState.d.ts +6 -14
  78. package/dist/hooks/useControllableState.js +21 -15
  79. package/dist/hooks/useControllableState.js.map +1 -1
  80. package/dist/hooks/useTableColumns.d.ts +3 -3
  81. package/dist/hooks/useTableColumns.js +2 -2
  82. package/dist/hooks/useTableColumns.js.map +1 -1
  83. package/dist/hooks/useTableData.d.ts +11 -4
  84. package/dist/hooks/useTableData.js +44 -26
  85. package/dist/hooks/useTableData.js.map +1 -1
  86. package/dist/index-nostyled.d.ts +2 -2
  87. package/dist/index.d.ts +2 -2
  88. package/dist/index.js +97 -97
  89. package/dist/layouts/Sidebar.d.ts +3 -1
  90. package/dist/layouts/Sidebar.js +131 -122
  91. package/dist/layouts/Sidebar.js.map +1 -1
  92. package/dist/utils/i18n.js +1 -1
  93. package/dist/utils/i18n.js.map +1 -1
  94. package/dist/utils/routerBuilder.d.ts +7 -5
  95. package/dist/utils/routerBuilder.js +11 -15
  96. package/dist/utils/routerBuilder.js.map +1 -1
  97. package/dist/utils/safeStorage.d.ts +8 -0
  98. package/dist/utils/safeStorage.js +45 -0
  99. package/dist/utils/safeStorage.js.map +1 -0
  100. package/package.json +22 -5
@@ -121,11 +121,11 @@ var c = [
121
121
  action: (e) => e
122
122
  }
123
123
  ], l = ({ editor: l }) => {
124
- let [u, d] = i(!1), [f, p] = i(""), [m, h] = i({
124
+ let [u, d] = i(!1), [f, p] = i(null), m = f?.query ?? "", [h, g] = i({
125
125
  x: 0,
126
126
  y: 0
127
- }), [g, _] = i(0), v = r(null), y = r(null), b = r(null), x = r(!1), S = e(() => {
128
- if (l.isDestroyed || !l.isEditable || l.view.composing || x.current) return null;
127
+ }), [_, v] = i(0), y = r(null), b = r(null), x = r(null), S = r(!1), C = e(() => {
128
+ if (l.isDestroyed || !l.isEditable || l.view.composing || S.current) return null;
129
129
  let e = l.state.selection;
130
130
  if (!(e instanceof s) || !e.empty || e.$from.parent.type.spec.code || e.$from.marks().some((e) => e.type.spec.code)) return null;
131
131
  let { $from: t } = e, n = t.parent.textBetween(0, t.parentOffset, "\n", (e) => e.type.name === "hardBreak" ? "\n" : ""), r = /(?:^|\s)\/([^\s/]*)$/.exec(n);
@@ -134,70 +134,80 @@ var c = [
134
134
  to: t.pos,
135
135
  query: r[1]
136
136
  } : null;
137
- }, [l]), C = f ? c.filter((e) => {
138
- let t = f.toLowerCase();
137
+ }, [l]), w = m ? c.filter((e) => {
138
+ let t = m.toLowerCase();
139
139
  return e.label.toLowerCase().includes(t) || e.description.toLowerCase().includes(t) || e.keywords?.some((e) => e.includes(t));
140
- }) : c, w = e(() => {
141
- d(!1), p("");
142
- let e = y.current;
143
- e && (b.current = `${e.from}:${e.to}:${e.query}`), y.current = null, _(0);
144
- }, []), T = e((e) => {
145
- let t = S(), n = y.current;
146
- if (!t || !n || t.from !== n.from || t.to !== n.to || t.query !== n.query) {
147
- w();
140
+ }) : c, T = e(() => {
141
+ d(!1), p(null);
142
+ let e = b.current;
143
+ e && (x.current = `${e.from}:${e.to}:${e.query}`), b.current = null, v(0);
144
+ }, []), E = e((e) => {
145
+ let t = C(), n = b.current;
146
+ if (!t || !n || !f || t.from !== f.from || t.to !== f.to || t.query !== f.query || t.from !== n.from || t.to !== n.to || t.query !== n.query) {
147
+ T();
148
148
  return;
149
149
  }
150
150
  let r = e.label === "Image" ? window.prompt("Image URL:")?.trim() : void 0;
151
151
  if (e.label === "Image" && !r) {
152
- w();
152
+ T();
153
153
  return;
154
154
  }
155
- w();
155
+ T();
156
156
  let i = l.chain().focus().deleteRange(t);
157
157
  (r ? i.setImage({ src: r }) : e.action(i)).run();
158
158
  }, [
159
159
  l,
160
- S,
161
- w
160
+ C,
161
+ T,
162
+ f
162
163
  ]);
163
164
  return t(() => {
164
165
  let e, t = () => {
165
- let e = l.isFocused ? S() : null;
166
+ let e = l.isFocused ? C() : null;
166
167
  if (!e) {
167
- y.current = null, b.current = null, d(!1);
168
+ b.current = null, x.current = null, d(!1);
168
169
  return;
169
170
  }
170
- b.current !== `${e.from}:${e.to}:${e.query}` && ((y.current?.query !== e.query || y.current?.from !== e.from) && _(0), y.current = e, p(e.query), d(!0));
171
+ x.current !== `${e.from}:${e.to}:${e.query}` && ((b.current?.query !== e.query || b.current?.from !== e.from) && v(0), b.current = e, p(e), d(!0));
171
172
  }, n = () => {
172
- x.current = !0, w();
173
+ S.current = !0, T();
173
174
  }, r = () => {
174
- x.current = !1, b.current = null, e = setTimeout(t, 0);
175
+ S.current = !1, x.current = null, e = setTimeout(t, 0);
175
176
  }, i = l.view.dom;
176
- return l.on("transaction", t), l.on("blur", w), i.addEventListener("compositionstart", n), i.addEventListener("compositionend", r), () => {
177
- clearTimeout(e), l.off("transaction", t), l.off("blur", w), i.removeEventListener("compositionstart", n), i.removeEventListener("compositionend", r);
177
+ return l.on("transaction", t), l.on("blur", T), i.addEventListener("compositionstart", n), i.addEventListener("compositionend", r), () => {
178
+ clearTimeout(e), l.off("transaction", t), l.off("blur", T), i.removeEventListener("compositionstart", n), i.removeEventListener("compositionend", r);
178
179
  };
179
180
  }, [
180
181
  l,
181
- S,
182
- w
182
+ C,
183
+ T
183
184
  ]), n(() => {
184
- if (!u || !C.length) return;
185
- let e = l.view.dom.closest(".rte-editor-wrapper"), t = v.current;
185
+ if (!u || !w.length) return;
186
+ let e = l.view.dom.closest(".rte-editor-wrapper"), t = y.current;
186
187
  if (!e || !t) return;
187
188
  let n = () => {
188
- let n = S();
189
+ let n = C();
189
190
  if (!n) {
190
- w();
191
+ T();
192
+ return;
193
+ }
194
+ let r = l.view.coordsAtPos(n.to), i = e.getBoundingClientRect(), a = Math.max(8, i.left + e.clientLeft), o = Math.min(window.innerWidth - 8, i.right), s = Math.max(8, i.top + e.clientTop), c = Math.min(window.innerHeight - 8, i.bottom);
195
+ if (o <= a || c <= s || r.bottom < s || r.top > c) {
196
+ T();
191
197
  return;
192
198
  }
193
- let r = l.view.coordsAtPos(n.to), i = e.getBoundingClientRect(), a = Math.max(8, i.left + e.clientLeft), o = Math.min(window.innerWidth - 8, i.right), s = Math.max(8, i.top + e.clientTop), c = Math.min(window.innerHeight - 8, i.bottom), u = Math.min(Math.max(r.top, s), c), d = Math.min(Math.max(r.bottom, s), c);
194
- t.style.minWidth = "0", t.style.width = `${Math.min(280, Math.max(120, o - a))}px`;
195
- let f = c - d - 4, p = u - s - 4, m = f < Math.min(300, t.scrollHeight) && p > f;
196
- t.style.maxHeight = `${Math.max(120, Math.min(300, m ? p : f))}px`;
197
- let g = Math.max(a, Math.min(r.left, o - t.offsetWidth)), _ = m ? u - t.offsetHeight - 4 : d + 4;
198
- h({
199
- x: g - i.left - e.clientLeft + e.scrollLeft,
200
- y: _ - i.top - e.clientTop + e.scrollTop
199
+ let u = Math.min(Math.max(r.top, s), c), d = Math.min(Math.max(r.bottom, s), c);
200
+ t.style.boxSizing = "border-box", t.style.minWidth = "0", t.style.width = `${Math.min(280, o - a)}px`;
201
+ let f = c - d - 4, p = u - s - 4, m = f < Math.min(300, t.scrollHeight) && p > f, h = m ? p : f;
202
+ if (h <= 0) {
203
+ T();
204
+ return;
205
+ }
206
+ t.style.maxHeight = `${Math.min(300, h)}px`;
207
+ let _ = Math.max(a, Math.min(r.left, o - t.offsetWidth)), v = m ? u - t.offsetHeight - 4 : d + 4;
208
+ g({
209
+ x: _ - i.left - e.clientLeft + e.scrollLeft,
210
+ y: v - i.top - e.clientTop + e.scrollTop
201
211
  });
202
212
  };
203
213
  return n(), window.addEventListener("scroll", n, !0), window.addEventListener("resize", n), l.on("transaction", n), () => {
@@ -206,54 +216,54 @@ var c = [
206
216
  }, [
207
217
  l,
208
218
  u,
209
- C.length,
210
- S,
211
- w
219
+ w.length,
220
+ C,
221
+ T
212
222
  ]), t(() => {
213
223
  if (!u) return;
214
- let e = v.current, t = e?.children[g];
224
+ let e = y.current, t = e?.children[_];
215
225
  e && t && (t.offsetTop < e.scrollTop ? e.scrollTop = t.offsetTop : t.offsetTop + t.offsetHeight > e.scrollTop + e.clientHeight && (e.scrollTop = t.offsetTop + t.offsetHeight - e.clientHeight));
216
- }, [g, u]), t(() => {
226
+ }, [_, u]), t(() => {
217
227
  if (!u) return;
218
228
  let e = (e) => {
219
- !l.view.dom.contains(e.target) || !l.isFocused || e.isComposing || e.keyCode === 229 || l.view.composing || x.current || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || (C.length || e.key === "Escape") && ([
229
+ !l.view.dom.contains(e.target) || !l.isFocused || e.isComposing || e.keyCode === 229 || l.view.composing || S.current || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || (w.length || e.key === "Escape") && ([
220
230
  "ArrowDown",
221
231
  "ArrowUp",
222
232
  "Enter",
223
233
  "Escape"
224
- ].includes(e.key) && e.stopImmediatePropagation(), e.key === "ArrowDown" ? (e.preventDefault(), _((e) => (e + 1) % C.length)) : e.key === "ArrowUp" ? (e.preventDefault(), _((e) => (e - 1 + C.length) % C.length)) : e.key === "Enter" ? (e.preventDefault(), C[g] && T(C[g])) : e.key === "Escape" && (e.preventDefault(), w()));
234
+ ].includes(e.key) && e.stopImmediatePropagation(), e.key === "ArrowDown" ? (e.preventDefault(), v((e) => (e + 1) % w.length)) : e.key === "ArrowUp" ? (e.preventDefault(), v((e) => (e - 1 + w.length) % w.length)) : e.key === "Enter" ? (e.preventDefault(), w[_] && E(w[_])) : e.key === "Escape" && (e.preventDefault(), T()));
225
235
  };
226
236
  return document.addEventListener("keydown", e, !0), () => document.removeEventListener("keydown", e, !0);
227
237
  }, [
228
238
  l,
229
239
  u,
230
- C,
231
- g,
232
- T,
233
- w
240
+ w,
241
+ _,
242
+ E,
243
+ T
234
244
  ]), t(() => {
235
245
  if (!u) return;
236
246
  let e = (e) => {
237
- v.current && !v.current.contains(e.target) && w();
247
+ y.current && !y.current.contains(e.target) && T();
238
248
  };
239
249
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
240
- }, [u, w]), !u || C.length === 0 ? null : /* @__PURE__ */ a("div", {
241
- ref: v,
250
+ }, [u, T]), !u || w.length === 0 ? null : /* @__PURE__ */ a("div", {
251
+ ref: y,
242
252
  className: "rte-slash-menu",
243
253
  role: "menu",
244
254
  "aria-label": "Insert block",
245
255
  style: {
246
- left: m.x,
247
- top: m.y
256
+ left: h.x,
257
+ top: h.y
248
258
  },
249
259
  onMouseDown: (e) => e.preventDefault(),
250
- children: C.map((e, t) => /* @__PURE__ */ o("button", {
260
+ children: w.map((e, t) => /* @__PURE__ */ o("button", {
251
261
  type: "button",
252
262
  role: "menuitem",
253
263
  tabIndex: -1,
254
- className: `rte-slash-menu__item ${t === g ? "rte-slash-menu__item--active" : ""}`,
255
- onClick: () => T(e),
256
- onMouseEnter: () => _(t),
264
+ className: `rte-slash-menu__item ${t === _ ? "rte-slash-menu__item--active" : ""}`,
265
+ onClick: () => E(e),
266
+ onMouseEnter: () => v(t),
257
267
  children: [/* @__PURE__ */ a("span", {
258
268
  className: "rte-slash-menu__icon",
259
269
  children: e.icon
@@ -1 +1 @@
1
- {"version":3,"file":"SlashMenu.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/SlashMenu.tsx"],"sourcesContent":["import React, { useState, useEffect, useLayoutEffect, useRef, useCallback } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { ChainedCommands } from '@tiptap/core';\nimport { TextSelection } from '@tiptap/pm/state';\n\ninterface SlashMenuItem {\n label: string;\n icon: string;\n description: string;\n action: (chain: ChainedCommands) => ChainedCommands;\n keywords?: string[];\n}\n\nconst SLASH_ITEMS: SlashMenuItem[] = [\n { label: 'Text', icon: 'Aa', description: 'Plain text', keywords: ['paragraph', 'text', 'plain'],\n action: (e) => e.setParagraph() },\n { label: 'Heading 1', icon: 'H1', description: 'Large heading', keywords: ['h1', 'title'],\n action: (e) => e.setHeading({ level: 1 }) },\n { label: 'Heading 2', icon: 'H2', description: 'Medium heading', keywords: ['h2', 'subtitle'],\n action: (e) => e.setHeading({ level: 2 }) },\n { label: 'Heading 3', icon: 'H3', description: 'Small heading', keywords: ['h3'],\n action: (e) => e.setHeading({ level: 3 }) },\n { label: 'Bullet List', icon: '•', description: 'Unordered list', keywords: ['ul', 'bullet', 'unordered'],\n action: (e) => e.toggleBulletList() },\n { label: 'Numbered List', icon: '1.', description: 'Ordered list', keywords: ['ol', 'ordered', 'number'],\n action: (e) => e.toggleOrderedList() },\n { label: 'Task List', icon: '☑', description: 'To-do list', keywords: ['todo', 'checkbox', 'task'],\n action: (e) => e.toggleTaskList() },\n { label: 'Blockquote', icon: '\"', description: 'Quote block', keywords: ['quote', 'blockquote'],\n action: (e) => e.toggleBlockquote() },\n { label: 'Code Block', icon: '</>', description: 'Code snippet', keywords: ['code', 'pre', 'snippet'],\n action: (e) => e.setNode('codeBlock') },\n { label: 'Divider', icon: '—', description: 'Horizontal rule', keywords: ['hr', 'divider', 'separator', 'line'],\n action: (e) => e.setHorizontalRule() },\n { label: 'Table', icon: '⊞', description: 'Insert 3×3 table', keywords: ['table', 'grid'],\n action: (e) => e.insertTable({ rows: 3, cols: 3, withHeaderRow: true }) },\n { label: 'Image', icon: '🖼', description: 'Insert image by URL', keywords: ['image', 'picture', 'photo'],\n action: (e) => e},\n];\n\ninterface SlashMenuProps {\n editor: Editor;\n}\n\nconst SlashMenu: React.FC<SlashMenuProps> = ({ editor }) => {\n const [visible, setVisible] = useState(false);\n const [query, setQuery] = useState('');\n const [pos, setPos] = useState({ x: 0, y: 0 });\n const [selected, setSelected] = useState(0);\n const menuRef = useRef<HTMLDivElement>(null);\n const activeRange = useRef<{ from: number; to: number; query: string } | null>(null);\n const dismissed = useRef<string | null>(null);\n const composing = useRef(false);\n\n const getRange = useCallback(() => {\n if (editor.isDestroyed || !editor.isEditable || editor.view.composing || composing.current) return null;\n const selection = editor.state.selection;\n if (!(selection instanceof TextSelection) || !selection.empty || selection.$from.parent.type.spec.code || selection.$from.marks().some((mark) => mark.type.spec.code)) return null;\n const { $from } = selection;\n // textContent drops inline atoms and hard breaks, so its offsets are not document offsets.\n const text = $from.parent.textBetween(0, $from.parentOffset, '\\n', (node) => node.type.name === 'hardBreak' ? '\\n' : '\\ufffc');\n const match = /(?:^|\\s)\\/([^\\s/]*)$/.exec(text);\n if (!match) return null;\n return { from: $from.pos - match[1].length - 1, to: $from.pos, query: match[1] };\n }, [editor]);\n\n const filtered = query\n ? SLASH_ITEMS.filter((item) => {\n const q = query.toLowerCase();\n return item.label.toLowerCase().includes(q)\n || item.description.toLowerCase().includes(q)\n || item.keywords?.some((k) => k.includes(q));\n })\n : SLASH_ITEMS;\n\n const close = useCallback(() => {\n setVisible(false);\n setQuery('');\n const range = activeRange.current;\n if (range) dismissed.current = `${range.from}:${range.to}:${range.query}`;\n activeRange.current = null;\n setSelected(0);\n }, []);\n\n const executeItem = useCallback((item: SlashMenuItem) => {\n const range = getRange();\n const active = activeRange.current;\n if (!range || !active || range.from !== active.from || range.to !== active.to || range.query !== active.query) {\n close();\n return;\n }\n const url = item.label === 'Image' ? window.prompt('Image URL:')?.trim() : undefined;\n if (item.label === 'Image' && !url) { close(); return; }\n close();\n // Delete the trigger and insert/convert in one transaction (one undo step).\n const chain = editor.chain().focus().deleteRange(range);\n (url ? chain.setImage({ src: url }) : item.action(chain)).run();\n }, [editor, getRange, close]);\n\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const handleUpdate = () => {\n const range = editor.isFocused ? getRange() : null;\n if (!range) {\n activeRange.current = null;\n dismissed.current = null;\n setVisible(false);\n return;\n }\n if (dismissed.current === `${range.from}:${range.to}:${range.query}`) return;\n if (activeRange.current?.query !== range.query || activeRange.current?.from !== range.from) setSelected(0);\n activeRange.current = range;\n setQuery(range.query);\n setVisible(true);\n };\n const start = () => { composing.current = true; close(); };\n const end = () => {\n composing.current = false;\n dismissed.current = null;\n timer = setTimeout(handleUpdate, 0);\n };\n const dom = editor.view.dom;\n editor.on('transaction', handleUpdate);\n editor.on('blur', close);\n dom.addEventListener('compositionstart', start);\n dom.addEventListener('compositionend', end);\n return () => {\n clearTimeout(timer);\n editor.off('transaction', handleUpdate);\n editor.off('blur', close);\n dom.removeEventListener('compositionstart', start);\n dom.removeEventListener('compositionend', end);\n };\n }, [editor, getRange, close]);\n\n useLayoutEffect(() => {\n if (!visible || !filtered.length) return;\n const wrapper = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n const menu = menuRef.current;\n if (!wrapper || !menu) return;\n const place = () => {\n const range = getRange();\n if (!range) { close(); return; }\n const coords = editor.view.coordsAtPos(range.to);\n const rect = wrapper.getBoundingClientRect();\n const left = Math.max(8, rect.left + wrapper.clientLeft);\n const right = Math.min(window.innerWidth - 8, rect.right);\n const top = Math.max(8, rect.top + wrapper.clientTop);\n const bottom = Math.min(window.innerHeight - 8, rect.bottom);\n // Clamp the anchor into the visible area instead of closing: on small /\n // scrollable (phone) containers the cursor can sit at the very edge, and\n // closing the menu makes block insertion feel broken (\" stuck \").\n const anchorTop = Math.min(Math.max(coords.top, top), bottom);\n const anchorBottom = Math.min(Math.max(coords.bottom, top), bottom);\n menu.style.minWidth = '0';\n menu.style.width = `${Math.min(280, Math.max(120, right - left))}px`;\n const below = bottom - anchorBottom - 4;\n const above = anchorTop - top - 4;\n const flip = below < Math.min(300, menu.scrollHeight) && above > below;\n // Keep a minimum visible height: a 0-height menu still hijacks Enter and\n // arrow keys, which looks like a frozen editor.\n menu.style.maxHeight = `${Math.max(120, Math.min(300, flip ? above : below))}px`;\n const x = Math.max(left, Math.min(coords.left, right - menu.offsetWidth));\n const y = flip ? anchorTop - menu.offsetHeight - 4 : anchorBottom + 4;\n setPos({ x: x - rect.left - wrapper.clientLeft + wrapper.scrollLeft,\n y: y - rect.top - wrapper.clientTop + wrapper.scrollTop });\n };\n place();\n window.addEventListener('scroll', place, true);\n window.addEventListener('resize', place);\n editor.on('transaction', place);\n return () => {\n window.removeEventListener('scroll', place, true);\n window.removeEventListener('resize', place);\n editor.off('transaction', place);\n };\n }, [editor, visible, filtered.length, getRange, close]);\n\n useEffect(() => {\n if (!visible) return;\n const menu = menuRef.current;\n const item = menu?.children[selected] as HTMLElement | undefined;\n if (!menu || !item) return;\n if (item.offsetTop < menu.scrollTop) menu.scrollTop = item.offsetTop;\n else if (item.offsetTop + item.offsetHeight > menu.scrollTop + menu.clientHeight) {\n menu.scrollTop = item.offsetTop + item.offsetHeight - menu.clientHeight;\n }\n }, [selected, visible]);\n\n useEffect(() => {\n if (!visible) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (!editor.view.dom.contains(e.target as Node) || !editor.isFocused || e.isComposing || e.keyCode === 229 || editor.view.composing || composing.current || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return;\n if (!filtered.length && e.key !== 'Escape') return;\n if (['ArrowDown', 'ArrowUp', 'Enter', 'Escape'].includes(e.key)) e.stopImmediatePropagation();\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n setSelected((s) => (s + 1) % filtered.length);\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setSelected((s) => (s - 1 + filtered.length) % filtered.length);\n } else if (e.key === 'Enter') {\n e.preventDefault();\n if (filtered[selected]) executeItem(filtered[selected]);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n close();\n }\n };\n document.addEventListener('keydown', handleKeyDown, true);\n return () => document.removeEventListener('keydown', handleKeyDown, true);\n }, [editor, visible, filtered, selected, executeItem, close]);\n\n useEffect(() => {\n if (!visible) return;\n const handler = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) close();\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [visible, close]);\n\n if (!visible || filtered.length === 0) return null;\n\n return (\n <div ref={menuRef} className=\"rte-slash-menu\" role=\"menu\" aria-label=\"Insert block\" style={{ left: pos.x, top: pos.y }} onMouseDown={(e) => e.preventDefault()}>\n {filtered.map((item, i) => (\n <button\n key={item.label}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n className={`rte-slash-menu__item ${i === selected ? 'rte-slash-menu__item--active' : ''}`}\n onClick={() => executeItem(item)}\n onMouseEnter={() => setSelected(i)}\n >\n <span className=\"rte-slash-menu__icon\">{item.icon}</span>\n <div className=\"rte-slash-menu__text\">\n <span className=\"rte-slash-menu__label\">{item.label}</span>\n <span className=\"rte-slash-menu__desc\">{item.description}</span>\n </div>\n </button>\n ))}\n </div>\n );\n};\n\nexport default SlashMenu;\n"],"mappings":"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"}
1
+ {"version":3,"file":"SlashMenu.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/SlashMenu.tsx"],"sourcesContent":["import React, { useState, useEffect, useLayoutEffect, useRef, useCallback } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { ChainedCommands } from '@tiptap/core';\nimport { TextSelection } from '@tiptap/pm/state';\n\ninterface SlashMenuItem {\n label: string;\n icon: string;\n description: string;\n action: (chain: ChainedCommands) => ChainedCommands;\n keywords?: string[];\n}\n\nconst SLASH_ITEMS: SlashMenuItem[] = [\n { label: 'Text', icon: 'Aa', description: 'Plain text', keywords: ['paragraph', 'text', 'plain'],\n action: (e) => e.setParagraph() },\n { label: 'Heading 1', icon: 'H1', description: 'Large heading', keywords: ['h1', 'title'],\n action: (e) => e.setHeading({ level: 1 }) },\n { label: 'Heading 2', icon: 'H2', description: 'Medium heading', keywords: ['h2', 'subtitle'],\n action: (e) => e.setHeading({ level: 2 }) },\n { label: 'Heading 3', icon: 'H3', description: 'Small heading', keywords: ['h3'],\n action: (e) => e.setHeading({ level: 3 }) },\n { label: 'Bullet List', icon: '•', description: 'Unordered list', keywords: ['ul', 'bullet', 'unordered'],\n action: (e) => e.toggleBulletList() },\n { label: 'Numbered List', icon: '1.', description: 'Ordered list', keywords: ['ol', 'ordered', 'number'],\n action: (e) => e.toggleOrderedList() },\n { label: 'Task List', icon: '☑', description: 'To-do list', keywords: ['todo', 'checkbox', 'task'],\n action: (e) => e.toggleTaskList() },\n { label: 'Blockquote', icon: '\"', description: 'Quote block', keywords: ['quote', 'blockquote'],\n action: (e) => e.toggleBlockquote() },\n { label: 'Code Block', icon: '</>', description: 'Code snippet', keywords: ['code', 'pre', 'snippet'],\n action: (e) => e.setNode('codeBlock') },\n { label: 'Divider', icon: '—', description: 'Horizontal rule', keywords: ['hr', 'divider', 'separator', 'line'],\n action: (e) => e.setHorizontalRule() },\n { label: 'Table', icon: '⊞', description: 'Insert 3×3 table', keywords: ['table', 'grid'],\n action: (e) => e.insertTable({ rows: 3, cols: 3, withHeaderRow: true }) },\n { label: 'Image', icon: '🖼', description: 'Insert image by URL', keywords: ['image', 'picture', 'photo'],\n action: (e) => e},\n];\n\ninterface SlashRange {\n from: number;\n to: number;\n query: string;\n}\n\ninterface SlashMenuProps {\n editor: Editor;\n}\n\nconst SlashMenu: React.FC<SlashMenuProps> = ({ editor }) => {\n const [visible, setVisible] = useState(false);\n const [renderedRange, setRenderedRange] = useState<SlashRange | null>(null);\n const query = renderedRange?.query ?? '';\n const [pos, setPos] = useState({ x: 0, y: 0 });\n const [selected, setSelected] = useState(0);\n const menuRef = useRef<HTMLDivElement>(null);\n const activeRange = useRef<SlashRange | null>(null);\n const dismissed = useRef<string | null>(null);\n const composing = useRef(false);\n\n const getRange = useCallback(() => {\n if (editor.isDestroyed || !editor.isEditable || editor.view.composing || composing.current) return null;\n const selection = editor.state.selection;\n if (!(selection instanceof TextSelection) || !selection.empty || selection.$from.parent.type.spec.code || selection.$from.marks().some((mark) => mark.type.spec.code)) return null;\n const { $from } = selection;\n // textContent drops inline atoms and hard breaks, so its offsets are not document offsets.\n const text = $from.parent.textBetween(0, $from.parentOffset, '\\n', (node) => node.type.name === 'hardBreak' ? '\\n' : '\\ufffc');\n const match = /(?:^|\\s)\\/([^\\s/]*)$/.exec(text);\n if (!match) return null;\n return { from: $from.pos - match[1].length - 1, to: $from.pos, query: match[1] };\n }, [editor]);\n\n const filtered = query\n ? SLASH_ITEMS.filter((item) => {\n const q = query.toLowerCase();\n return item.label.toLowerCase().includes(q)\n || item.description.toLowerCase().includes(q)\n || item.keywords?.some((k) => k.includes(q));\n })\n : SLASH_ITEMS;\n\n const close = useCallback(() => {\n setVisible(false);\n setRenderedRange(null);\n const range = activeRange.current;\n if (range) dismissed.current = `${range.from}:${range.to}:${range.query}`;\n activeRange.current = null;\n setSelected(0);\n }, []);\n\n const executeItem = useCallback((item: SlashMenuItem) => {\n const range = getRange();\n const active = activeRange.current;\n // Transactions update the ref before React commits the new menu. An old\n // rendered action must not operate on that newer trigger/selection.\n if (!range || !active || !renderedRange\n || range.from !== renderedRange.from || range.to !== renderedRange.to || range.query !== renderedRange.query\n || range.from !== active.from || range.to !== active.to || range.query !== active.query) {\n close();\n return;\n }\n const url = item.label === 'Image' ? window.prompt('Image URL:')?.trim() : undefined;\n if (item.label === 'Image' && !url) { close(); return; }\n close();\n // Delete the trigger and insert/convert in one transaction (one undo step).\n const chain = editor.chain().focus().deleteRange(range);\n (url ? chain.setImage({ src: url }) : item.action(chain)).run();\n }, [editor, getRange, close, renderedRange]);\n\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const handleUpdate = () => {\n const range = editor.isFocused ? getRange() : null;\n if (!range) {\n activeRange.current = null;\n dismissed.current = null;\n setVisible(false);\n return;\n }\n if (dismissed.current === `${range.from}:${range.to}:${range.query}`) return;\n if (activeRange.current?.query !== range.query || activeRange.current?.from !== range.from) setSelected(0);\n activeRange.current = range;\n setRenderedRange(range);\n setVisible(true);\n };\n const start = () => { composing.current = true; close(); };\n const end = () => {\n composing.current = false;\n dismissed.current = null;\n timer = setTimeout(handleUpdate, 0);\n };\n const dom = editor.view.dom;\n editor.on('transaction', handleUpdate);\n editor.on('blur', close);\n dom.addEventListener('compositionstart', start);\n dom.addEventListener('compositionend', end);\n return () => {\n clearTimeout(timer);\n editor.off('transaction', handleUpdate);\n editor.off('blur', close);\n dom.removeEventListener('compositionstart', start);\n dom.removeEventListener('compositionend', end);\n };\n }, [editor, getRange, close]);\n\n useLayoutEffect(() => {\n if (!visible || !filtered.length) return;\n const wrapper = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n const menu = menuRef.current;\n if (!wrapper || !menu) return;\n const place = () => {\n const range = getRange();\n if (!range) { close(); return; }\n const coords = editor.view.coordsAtPos(range.to);\n const rect = wrapper.getBoundingClientRect();\n const left = Math.max(8, rect.left + wrapper.clientLeft);\n const right = Math.min(window.innerWidth - 8, rect.right);\n const top = Math.max(8, rect.top + wrapper.clientTop);\n const bottom = Math.min(window.innerHeight - 8, rect.bottom);\n // Keep partially visible edge anchors usable, but never leave an\n // offscreen menu intercepting the editor's Enter/arrow keys.\n if (right <= left || bottom <= top || coords.bottom < top || coords.top > bottom) {\n close();\n return;\n }\n const anchorTop = Math.min(Math.max(coords.top, top), bottom);\n const anchorBottom = Math.min(Math.max(coords.bottom, top), bottom);\n menu.style.boxSizing = 'border-box';\n menu.style.minWidth = '0';\n menu.style.width = `${Math.min(280, right - left)}px`;\n const below = bottom - anchorBottom - 4;\n const above = anchorTop - top - 4;\n const flip = below < Math.min(300, menu.scrollHeight) && above > below;\n const availableHeight = flip ? above : below;\n if (availableHeight <= 0) { close(); return; }\n menu.style.maxHeight = `${Math.min(300, availableHeight)}px`;\n const x = Math.max(left, Math.min(coords.left, right - menu.offsetWidth));\n const y = flip ? anchorTop - menu.offsetHeight - 4 : anchorBottom + 4;\n setPos({ x: x - rect.left - wrapper.clientLeft + wrapper.scrollLeft,\n y: y - rect.top - wrapper.clientTop + wrapper.scrollTop });\n };\n place();\n window.addEventListener('scroll', place, true);\n window.addEventListener('resize', place);\n editor.on('transaction', place);\n return () => {\n window.removeEventListener('scroll', place, true);\n window.removeEventListener('resize', place);\n editor.off('transaction', place);\n };\n }, [editor, visible, filtered.length, getRange, close]);\n\n useEffect(() => {\n if (!visible) return;\n const menu = menuRef.current;\n const item = menu?.children[selected] as HTMLElement | undefined;\n if (!menu || !item) return;\n if (item.offsetTop < menu.scrollTop) menu.scrollTop = item.offsetTop;\n else if (item.offsetTop + item.offsetHeight > menu.scrollTop + menu.clientHeight) {\n menu.scrollTop = item.offsetTop + item.offsetHeight - menu.clientHeight;\n }\n }, [selected, visible]);\n\n useEffect(() => {\n if (!visible) return;\n const handleKeyDown = (e: KeyboardEvent) => {\n if (!editor.view.dom.contains(e.target as Node) || !editor.isFocused || e.isComposing || e.keyCode === 229 || editor.view.composing || composing.current || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return;\n if (!filtered.length && e.key !== 'Escape') return;\n if (['ArrowDown', 'ArrowUp', 'Enter', 'Escape'].includes(e.key)) e.stopImmediatePropagation();\n if (e.key === 'ArrowDown') {\n e.preventDefault();\n setSelected((s) => (s + 1) % filtered.length);\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setSelected((s) => (s - 1 + filtered.length) % filtered.length);\n } else if (e.key === 'Enter') {\n e.preventDefault();\n if (filtered[selected]) executeItem(filtered[selected]);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n close();\n }\n };\n document.addEventListener('keydown', handleKeyDown, true);\n return () => document.removeEventListener('keydown', handleKeyDown, true);\n }, [editor, visible, filtered, selected, executeItem, close]);\n\n useEffect(() => {\n if (!visible) return;\n const handler = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) close();\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [visible, close]);\n\n if (!visible || filtered.length === 0) return null;\n\n return (\n <div ref={menuRef} className=\"rte-slash-menu\" role=\"menu\" aria-label=\"Insert block\" style={{ left: pos.x, top: pos.y }} onMouseDown={(e) => e.preventDefault()}>\n {filtered.map((item, i) => (\n <button\n key={item.label}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n className={`rte-slash-menu__item ${i === selected ? 'rte-slash-menu__item--active' : ''}`}\n onClick={() => executeItem(item)}\n onMouseEnter={() => setSelected(i)}\n >\n <span className=\"rte-slash-menu__icon\">{item.icon}</span>\n <div className=\"rte-slash-menu__text\">\n <span className=\"rte-slash-menu__label\">{item.label}</span>\n <span className=\"rte-slash-menu__desc\">{item.description}</span>\n </div>\n </button>\n ))}\n </div>\n );\n};\n\nexport default SlashMenu;\n"],"mappings":"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"}
@@ -41,6 +41,7 @@ export type AppShellConfig = {
41
41
  menuItems?: MenuItem[];
42
42
  getMenuItems?: (language: 'zh' | 'en') => MenuItem[];
43
43
  themes?: ThemeConfig[];
44
+ /** Enables client auth state and navigation notifications, not loader protection. Use route beforeLoad for loaders. */
44
45
  enableAuth?: boolean;
45
46
  onAuthRequired?: () => boolean | void;
46
47
  protectedRoutes?: string[];