@tangle-network/ui 11.11.8 → 11.13.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 (279) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/_virtual/_rolldown/runtime.js +13 -0
  3. package/dist/auth/auth.d.ts +53 -0
  4. package/dist/{auth-DOETfnd9.js → auth/auth.js} +7 -37
  5. package/dist/auth/login-layout.d.ts +20 -0
  6. package/dist/auth/login-layout.js +36 -0
  7. package/dist/auth.d.ts +2 -1
  8. package/dist/auth.js +2 -1
  9. package/dist/chat/agent-timeline.d.ts +83 -0
  10. package/dist/chat/agent-timeline.js +236 -0
  11. package/dist/chat/chat-container.d.ts +51 -0
  12. package/dist/chat/chat-container.js +309 -0
  13. package/dist/chat/chat-message.d.ts +22 -0
  14. package/dist/chat/chat-message.js +38 -0
  15. package/dist/chat/message-list.d.ts +32 -0
  16. package/dist/chat/message-list.js +37 -0
  17. package/dist/chat/thinking-indicator.d.ts +6 -0
  18. package/dist/chat/thinking-indicator.js +38 -0
  19. package/dist/chat/user-message.d.ts +21 -0
  20. package/dist/chat/user-message.js +42 -0
  21. package/dist/chat.d.ts +6 -1
  22. package/dist/chat.js +6 -1
  23. package/dist/editor/document-editor-pane.d.ts +37 -0
  24. package/dist/editor/document-editor-pane.js +199 -0
  25. package/dist/editor/editor-lazy.js +37 -0
  26. package/dist/editor/editor-loading.js +21 -0
  27. package/dist/editor/editor-peers.d.ts +6 -0
  28. package/dist/editor/editor-peers.js +155 -0
  29. package/dist/{document-editor-pane-DHM8DDhb.d.ts → editor/editor-provider.d.ts} +10 -47
  30. package/dist/editor/editor-provider.js +253 -0
  31. package/dist/editor/editor-toolbar.d.ts +11 -0
  32. package/dist/editor/editor-toolbar.js +106 -0
  33. package/dist/editor/markdown-conversion.js +23 -0
  34. package/dist/editor/markdown-document-editor.js +103 -0
  35. package/dist/editor/tiptap-editor.d.ts +45 -0
  36. package/dist/editor/tiptap-editor.js +271 -0
  37. package/dist/editor/use-editor.d.ts +67 -0
  38. package/dist/editor/use-editor.js +158 -0
  39. package/dist/editor.d.ts +6 -119
  40. package/dist/editor.js +5 -1
  41. package/dist/files/file-artifact-pane.d.ts +47 -0
  42. package/dist/files/file-artifact-pane.js +114 -0
  43. package/dist/files/file-format.d.ts +51 -0
  44. package/dist/{file-format-BgXbr-Ib.js → files/file-format.js} +1 -1
  45. package/dist/files/file-preview.d.ts +27 -0
  46. package/dist/files/file-preview.js +359 -0
  47. package/dist/files/file-tabs.d.ts +19 -0
  48. package/dist/files/file-tabs.js +48 -0
  49. package/dist/files/file-tree.d.ts +31 -0
  50. package/dist/files/file-tree.js +135 -0
  51. package/dist/files/rich-file-tree.d.ts +62 -0
  52. package/dist/files/rich-file-tree.js +122 -0
  53. package/dist/files.d.ts +6 -1
  54. package/dist/files.js +6 -2
  55. package/dist/hooks/use-auth.d.ts +40 -0
  56. package/dist/hooks/use-auth.js +91 -0
  57. package/dist/hooks/use-auto-scroll.d.ts +11 -0
  58. package/dist/hooks/use-auto-scroll.js +48 -0
  59. package/dist/hooks/use-dropdown-menu.d.ts +12 -0
  60. package/dist/hooks/use-dropdown-menu.js +31 -0
  61. package/dist/hooks/use-live-time.d.ts +7 -0
  62. package/dist/hooks/use-live-time.js +22 -0
  63. package/dist/hooks/use-realtime-session.d.ts +32 -0
  64. package/dist/hooks/use-realtime-session.js +235 -0
  65. package/dist/hooks/use-run-collapse-state.d.ts +13 -0
  66. package/dist/hooks/use-run-collapse-state.js +24 -0
  67. package/dist/hooks/use-run-groups.d.ts +11 -0
  68. package/dist/hooks/use-run-groups.js +85 -0
  69. package/dist/hooks/use-sdk-session.d.ts +59 -0
  70. package/dist/hooks/use-sdk-session.js +322 -0
  71. package/dist/hooks/use-sse-stream.d.ts +124 -0
  72. package/dist/hooks/use-sse-stream.js +229 -0
  73. package/dist/hooks/use-tool-call-stream.d.ts +23 -0
  74. package/dist/hooks/use-tool-call-stream.js +75 -0
  75. package/dist/hooks.d.ts +11 -49
  76. package/dist/hooks.js +10 -110
  77. package/dist/index.d.ts +99 -25
  78. package/dist/index.js +86 -36
  79. package/dist/lib/focus.d.ts +55 -0
  80. package/dist/{focus-BcE_SHqz.js → lib/focus.js} +1 -1
  81. package/dist/lib/utils.d.ts +4 -0
  82. package/dist/{utils-C_uf36nf.js → lib/utils.js} +1 -1
  83. package/dist/{code-block-B9miUPht.d.ts → markdown/code-block.d.ts} +5 -6
  84. package/dist/{code-block-B36KVUSN.js → markdown/code-block.js} +22 -47
  85. package/dist/{markdown-C0atSabr.d.ts → markdown/markdown.d.ts} +4 -5
  86. package/dist/{markdown-Db08KAYF.js → markdown/markdown.js} +3 -3
  87. package/dist/markdown.d.ts +2 -2
  88. package/dist/markdown.js +2 -2
  89. package/dist/{openui-artifact-renderer-fkBQaoLO.d.ts → openui/openui-artifact-renderer.d.ts} +20 -21
  90. package/dist/{openui-artifact-renderer-DG_i2lOR.js → openui/openui-artifact-renderer.js} +9 -7
  91. package/dist/{schema-BpW9rSSG.js → openui/schema-compiled.js} +2 -354
  92. package/dist/{schema-DAstk-J4.d.ts → openui/schema-data.d.ts} +3 -24
  93. package/dist/openui/schema-data.js +206 -0
  94. package/dist/openui-schema.d.ts +22 -3
  95. package/dist/openui-schema.js +138 -1
  96. package/dist/openui.d.ts +3 -2
  97. package/dist/openui.js +3 -2
  98. package/dist/{artifact-pane-BL_DFWNl.d.ts → primitives/artifact-pane.d.ts} +3 -4
  99. package/dist/{artifact-pane-DMXT9a8U.js → primitives/artifact-pane.js} +2 -2
  100. package/dist/primitives/avatar.d.ts +8 -0
  101. package/dist/primitives/avatar.js +25 -0
  102. package/dist/primitives/badge.d.ts +22 -0
  103. package/dist/primitives/badge.js +47 -0
  104. package/dist/{button-yoIv77e2.d.ts → primitives/button.d.ts} +2 -2
  105. package/dist/primitives/button.js +113 -0
  106. package/dist/primitives/card.d.ts +18 -0
  107. package/dist/primitives/card.js +52 -0
  108. package/dist/primitives/code-block.d.ts +6 -0
  109. package/dist/primitives/code-block.js +13 -0
  110. package/dist/primitives/dialog.d.ts +23 -0
  111. package/dist/primitives/dialog.js +59 -0
  112. package/dist/primitives/drop-zone.d.ts +23 -0
  113. package/dist/primitives/drop-zone.js +104 -0
  114. package/dist/primitives/dropdown-menu.d.ts +29 -0
  115. package/dist/{dropdown-menu-BpcLa5vF.js → primitives/dropdown-menu.js} +2 -23
  116. package/dist/primitives/empty-state.d.ts +11 -0
  117. package/dist/primitives/empty-state.js +32 -0
  118. package/dist/primitives/heading.d.ts +23 -0
  119. package/dist/primitives/heading.js +38 -0
  120. package/dist/primitives/input.d.ts +23 -0
  121. package/dist/primitives/input.js +110 -0
  122. package/dist/primitives/label.d.ts +6 -0
  123. package/dist/primitives/label.js +16 -0
  124. package/dist/primitives/metric-strip.d.ts +48 -0
  125. package/dist/primitives/metric-strip.js +52 -0
  126. package/dist/primitives/page-header.d.ts +25 -0
  127. package/dist/primitives/page-header.js +47 -0
  128. package/dist/primitives/page-shell.d.ts +14 -0
  129. package/dist/primitives/page-shell.js +17 -0
  130. package/dist/primitives/progress.d.ts +9 -0
  131. package/dist/primitives/progress.js +29 -0
  132. package/dist/primitives/segmented-control.d.ts +40 -0
  133. package/dist/primitives/segmented-control.js +57 -0
  134. package/dist/primitives/select.d.ts +15 -0
  135. package/dist/primitives/select.js +74 -0
  136. package/dist/primitives/sidebar-drop-zone.d.ts +21 -0
  137. package/dist/primitives/sidebar-drop-zone.js +88 -0
  138. package/dist/primitives/skeleton.d.ts +10 -0
  139. package/dist/primitives/skeleton.js +50 -0
  140. package/dist/primitives/stat-card.d.ts +16 -0
  141. package/dist/primitives/stat-card.js +60 -0
  142. package/dist/primitives/status-pill.d.ts +44 -0
  143. package/dist/primitives/status-pill.js +119 -0
  144. package/dist/primitives/switch.d.ts +6 -0
  145. package/dist/primitives/switch.js +16 -0
  146. package/dist/primitives/table.d.ts +22 -0
  147. package/dist/primitives/table.js +63 -0
  148. package/dist/primitives/tabs.d.ts +13 -0
  149. package/dist/{tabs-BVHR6NkO.js → primitives/tabs.js} +3 -3
  150. package/dist/primitives/terminal-display.d.ts +25 -0
  151. package/dist/primitives/terminal-display.js +109 -0
  152. package/dist/primitives/text-shimmer.d.ts +16 -0
  153. package/dist/{text-shimmer-BUUo6I-g.js → primitives/text-shimmer.js} +2 -2
  154. package/dist/primitives/theme-toggle.d.ts +11 -0
  155. package/dist/primitives/theme-toggle.js +154 -0
  156. package/dist/primitives/toast.d.ts +29 -0
  157. package/dist/primitives/toast.js +142 -0
  158. package/dist/primitives/toolbar.d.ts +55 -0
  159. package/dist/primitives/toolbar.js +37 -0
  160. package/dist/primitives/upload-progress.d.ts +23 -0
  161. package/dist/primitives/upload-progress.js +72 -0
  162. package/dist/primitives.d.ts +35 -5
  163. package/dist/primitives.js +35 -9
  164. package/dist/{index-COgqsFAQ.d.ts → redaction/redacted-document.d.ts} +6 -7
  165. package/dist/{redaction-CGGB2ENG.js → redaction/redacted-document.js} +2 -2
  166. package/dist/redaction.d.ts +1 -1
  167. package/dist/redaction.js +1 -1
  168. package/dist/run/expandable-content.js +41 -0
  169. package/dist/run/expanded-tool-detail.d.ts +12 -0
  170. package/dist/run/expanded-tool-detail.js +163 -0
  171. package/dist/run/inline-thinking-item.d.ts +11 -0
  172. package/dist/run/inline-thinking-item.js +60 -0
  173. package/dist/run/inline-tool-item.d.ts +25 -0
  174. package/dist/run/inline-tool-item.js +63 -0
  175. package/dist/run/run-group.d.ts +26 -0
  176. package/dist/{run-group-BWGeesgs.js → run/run-group.js} +9 -60
  177. package/dist/run/run-item-primitives.d.ts +5 -0
  178. package/dist/{run-ZsIKPA6J.js → run/run-item-primitives.js} +2 -2
  179. package/dist/run/run-row-shell.d.ts +53 -0
  180. package/dist/run/run-row-shell.js +114 -0
  181. package/dist/{tool-call-feed-BeB1_4pX.d.ts → run/tool-call-feed.d.ts} +7 -12
  182. package/dist/{tool-call-feed-BpmMLpPX.js → run/tool-call-feed.js} +4 -4
  183. package/dist/run/tool-call-step.d.ts +5 -0
  184. package/dist/run/tool-call-step.js +82 -0
  185. package/dist/run.d.ts +8 -2
  186. package/dist/run.js +7 -4
  187. package/dist/sdk-hooks.d.ts +8 -1
  188. package/dist/sdk-hooks.js +8 -2
  189. package/dist/stores/active-sessions-store.d.ts +83 -0
  190. package/dist/{active-sessions-store-Gt1R0rFG.js → stores/active-sessions-store.js} +1 -1
  191. package/dist/stores/chat-store.d.ts +14 -0
  192. package/dist/stores/chat-store.js +33 -0
  193. package/dist/stores.d.ts +3 -16
  194. package/dist/stores.js +2 -33
  195. package/dist/tool-previews/command-preview.d.ts +11 -0
  196. package/dist/tool-previews/command-preview.js +91 -0
  197. package/dist/tool-previews/diff-preview.d.ts +7 -0
  198. package/dist/tool-previews/diff-preview.js +76 -0
  199. package/dist/tool-previews/glob-results-preview.d.ts +7 -0
  200. package/dist/tool-previews/glob-results-preview.js +53 -0
  201. package/dist/tool-previews/grep-results-preview.d.ts +7 -0
  202. package/dist/tool-previews/grep-results-preview.js +99 -0
  203. package/dist/tool-previews/preview-primitives.js +58 -0
  204. package/dist/tool-previews/question-preview.d.ts +7 -0
  205. package/dist/tool-previews/question-preview.js +63 -0
  206. package/dist/tool-previews/web-search-preview.d.ts +7 -0
  207. package/dist/tool-previews/web-search-preview.js +78 -0
  208. package/dist/tool-previews/write-file-preview.d.ts +11 -0
  209. package/dist/tool-previews/write-file-preview.js +52 -0
  210. package/dist/tool-previews.d.ts +7 -1
  211. package/dist/tool-previews.js +7 -1
  212. package/dist/{branding-26d5ARIr.d.ts → types/branding.d.ts} +2 -3
  213. package/dist/{message-vhUI0c5G.d.ts → types/message.d.ts} +2 -3
  214. package/dist/{parts-5mhy9yJ3.d.ts → types/parts.d.ts} +8 -9
  215. package/dist/{run-OyWmIDqu.d.ts → types/run.d.ts} +9 -10
  216. package/dist/{tool-display-DgmL5rIU.d.ts → types/tool-display.d.ts} +5 -6
  217. package/dist/types.d.ts +5 -5
  218. package/dist/utils/copy-text.d.ts +7 -0
  219. package/dist/{utils-Bl_CZ0Qp.js → utils/copy-text.js} +1 -11
  220. package/dist/utils/format.d.ts +22 -0
  221. package/dist/{format-DfcLWqMa.js → utils/format.js} +1 -1
  222. package/dist/utils/time-ago.d.ts +3 -0
  223. package/dist/utils/time-ago.js +11 -0
  224. package/dist/utils/tool-display.d.ts +16 -0
  225. package/dist/{tool-display-BAuAVa43.js → utils/tool-display.js} +1 -1
  226. package/dist/utils.d.ts +6 -1
  227. package/dist/utils.js +6 -5
  228. package/package.json +2 -2
  229. package/src/editor/document-editor-pane.tsx +4 -1
  230. package/src/files/file-artifact-pane.test.tsx +23 -0
  231. package/src/files/file-artifact-pane.tsx +3 -0
  232. package/src/files/rich-file-tree.stories.tsx +1 -1
  233. package/src/files/rich-file-tree.tsx +12 -9
  234. package/src/markdown/code-block.test.tsx +46 -2
  235. package/src/markdown/code-block.tsx +23 -60
  236. package/src/markdown/markdown.test.tsx +3 -2
  237. package/src/primitives/button.stories.tsx +37 -1
  238. package/src/primitives/button.test.tsx +230 -0
  239. package/src/primitives/button.tsx +62 -14
  240. package/src/primitives/card-anatomy.stories.tsx +51 -0
  241. package/src/primitives/card.test.tsx +71 -0
  242. package/src/primitives/card.tsx +25 -13
  243. package/src/primitives/heading.stories.tsx +35 -0
  244. package/src/primitives/heading.test.tsx +56 -0
  245. package/src/primitives/heading.tsx +76 -0
  246. package/src/primitives/index.ts +8 -0
  247. package/src/primitives/input.stories.tsx +28 -0
  248. package/src/primitives/input.test.tsx +161 -0
  249. package/src/primitives/input.tsx +34 -28
  250. package/src/primitives/page-header.stories.tsx +51 -0
  251. package/src/primitives/page-header.test.tsx +48 -0
  252. package/src/primitives/page-header.tsx +35 -35
  253. package/src/primitives/page-shell.stories.tsx +89 -0
  254. package/src/primitives/page-shell.test.tsx +24 -0
  255. package/src/primitives/page-shell.tsx +26 -0
  256. package/src/primitives/table-wrapper.stories.tsx +54 -0
  257. package/src/primitives/table.test.tsx +72 -0
  258. package/src/primitives/table.tsx +33 -12
  259. package/src/primitives/theme-toggle.test.tsx +167 -0
  260. package/src/primitives/theme-toggle.tsx +111 -39
  261. package/dist/active-sessions-store-nl70ZnMC.d.ts +0 -84
  262. package/dist/button-C87nEe2R.js +0 -78
  263. package/dist/chat-DDvF2oGQ.js +0 -672
  264. package/dist/diff-preview-BcK3nRXb.js +0 -533
  265. package/dist/document-editor-pane-CsFbH2qo.js +0 -1279
  266. package/dist/files--Unn___t.js +0 -752
  267. package/dist/index-2UntyjBb.d.ts +0 -52
  268. package/dist/index-BgUHilZm.d.ts +0 -108
  269. package/dist/index-CPDET_s1.d.ts +0 -549
  270. package/dist/index-Cg6gYAqh.d.ts +0 -73
  271. package/dist/index-Cs7j8V7l.d.ts +0 -203
  272. package/dist/index-CyGSLGVF.d.ts +0 -234
  273. package/dist/index-DjKxO357.d.ts +0 -128
  274. package/dist/primitives-Bx59fT-U.js +0 -1239
  275. package/dist/table-Bss73DhB.js +0 -146
  276. package/dist/tool-call-step-DNebqhmX.js +0 -434
  277. package/dist/use-auto-scroll-C5Pjeqon.js +0 -153
  278. package/dist/use-sse-stream-DjqRuDft.js +0 -884
  279. package/dist/use-sse-stream-Dm6R5YWz.d.ts +0 -282
@@ -0,0 +1,199 @@
1
+ "use client";
2
+ import { focusRing } from "../lib/focus.js";
3
+ import { cn } from "../lib/utils.js";
4
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "../primitives/tabs.js";
5
+ import { ArtifactPane } from "../primitives/artifact-pane.js";
6
+ import { Markdown } from "../markdown/markdown.js";
7
+ import { EditorProvider } from "./editor-provider.js";
8
+ import { CollaboratorsList, TiptapEditor } from "./tiptap-editor.js";
9
+ import { htmlToMarkdown, markdownToHtml, normalizeMarkdown } from "./markdown-conversion.js";
10
+ import { MarkdownDocumentEditor } from "./markdown-document-editor.js";
11
+ import { useCollaborators, useEditorConnection } from "./use-editor.js";
12
+ import { useEffect, useMemo, useState } from "react";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ import { PencilLine, Save, Users, Wifi, WifiOff } from "lucide-react";
15
+ //#region src/editor/document-editor-pane.tsx
16
+ function connectionTone(state) {
17
+ switch (state) {
18
+ case "synced": return "text-[var(--surface-success-text)] border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]";
19
+ case "connected":
20
+ case "connecting": return "text-[var(--surface-info-text)] border-[var(--surface-info-border)] bg-[var(--surface-info-bg)]";
21
+ default: return "text-[var(--surface-warning-text)] border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)]";
22
+ }
23
+ }
24
+ function connectionLabel(state) {
25
+ switch (state) {
26
+ case "synced": return "Live synced";
27
+ case "connected": return "Connected";
28
+ case "connecting": return "Connecting";
29
+ default: return "Offline";
30
+ }
31
+ }
32
+ function connectionDescription(state, collaborators, readOnly) {
33
+ if (readOnly) return state === "disconnected" ? "Live access is paused. You can keep reading while the editor reconnects." : "You are viewing the live document in read-only mode.";
34
+ switch (state) {
35
+ case "synced": return collaborators > 0 ? `You and ${collaborators} collaborator${collaborators === 1 ? "" : "s"} are editing the same document.` : "You are editing the live document. Changes sync automatically.";
36
+ case "connected":
37
+ case "connecting": return "Connecting the live document. Local edits stay in place while sync catches up.";
38
+ default: return "Live updates are paused. You can keep editing and reconnect when the transport is healthy again.";
39
+ }
40
+ }
41
+ function CollaborativeDocumentSurface({ markdown, placeholder, autoFocus, readOnly, className, onChange }) {
42
+ const { state } = useEditorConnection();
43
+ const { collaborators } = useCollaborators();
44
+ const initialContent = useMemo(() => markdownToHtml(markdown), [markdown]);
45
+ const collaboratorCount = collaborators.length + 1;
46
+ return /* @__PURE__ */ jsxs("div", {
47
+ className: cn("flex h-full min-h-0 flex-col gap-3", className),
48
+ children: [/* @__PURE__ */ jsxs("div", {
49
+ className: "flex flex-wrap items-center justify-between gap-3 rounded-[var(--radius-lg)] border border-border bg-card px-3 py-2",
50
+ children: [/* @__PURE__ */ jsxs("div", {
51
+ className: "min-w-0 space-y-2",
52
+ children: [/* @__PURE__ */ jsxs("div", {
53
+ className: "flex flex-wrap items-center gap-2 text-xs text-muted-foreground",
54
+ children: [/* @__PURE__ */ jsxs("span", {
55
+ className: cn("inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 font-medium", connectionTone(state)),
56
+ children: [state === "disconnected" ? /* @__PURE__ */ jsx(WifiOff, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Wifi, { className: "h-3.5 w-3.5" }), connectionLabel(state)]
57
+ }), /* @__PURE__ */ jsxs("span", {
58
+ className: "inline-flex items-center gap-1.5 rounded-full border border-border bg-background px-2.5 py-1",
59
+ children: [/* @__PURE__ */ jsx(Users, { className: "h-3.5 w-3.5" }), collaborators.length === 0 ? "Solo editing" : `${collaboratorCount} active`]
60
+ })]
61
+ }), /* @__PURE__ */ jsx("p", {
62
+ className: "text-xs text-muted-foreground",
63
+ children: connectionDescription(state, collaborators.length, readOnly)
64
+ })]
65
+ }), /* @__PURE__ */ jsx(CollaboratorsList, { collaborators })]
66
+ }), /* @__PURE__ */ jsx(TiptapEditor, {
67
+ initialContent,
68
+ placeholder,
69
+ autoFocus,
70
+ readOnly,
71
+ className: cn("h-full min-h-[16rem]", className),
72
+ onUpdate: (editor) => {
73
+ onChange?.(normalizeMarkdown(htmlToMarkdown(editor.getHTML())));
74
+ }
75
+ })]
76
+ });
77
+ }
78
+ /**
79
+ * DocumentEditorPane — reusable markdown document surface with preview/edit
80
+ * modes and optional collaborative editing backed by Yjs/Hocuspocus.
81
+ */
82
+ function DocumentEditorPane({ eyebrow, title, subtitle, meta, headerActions, footer, className, contentClassName, headerClassName, hideTitleBlock, tabs, toolbar, markdown = "", savedMarkdown, urlTransform, mode, defaultMode = "preview", onModeChange, backend = "local", placeholder = "Start writing...", autoFocus = false, readOnly = false, onChange, onSave, saving = false, saveLabel = "Save changes", previewClassName, editorClassName, collaboration }) {
83
+ const [draft, setDraft] = useState(markdown);
84
+ const [uncontrolledMode, setUncontrolledMode] = useState(defaultMode);
85
+ const activeMode = mode ?? uncontrolledMode;
86
+ const isCollaborative = backend === "collaborative" && Boolean(collaboration);
87
+ const isDirty = normalizeMarkdown(draft) !== normalizeMarkdown(savedMarkdown ?? markdown);
88
+ const saveStateLabel = readOnly ? "Read only" : isCollaborative ? isDirty ? "Snapshot pending" : "Live document current" : isDirty ? "Unsaved changes" : "Saved";
89
+ useEffect(() => {
90
+ setDraft(markdown);
91
+ }, [markdown]);
92
+ useEffect(() => {
93
+ if (mode === void 0) setUncontrolledMode(defaultMode);
94
+ }, [defaultMode, mode]);
95
+ const setMode = (nextMode) => {
96
+ if (mode === void 0) setUncontrolledMode(nextMode);
97
+ onModeChange?.(nextMode);
98
+ };
99
+ const handleChange = (nextMarkdown) => {
100
+ setDraft(nextMarkdown);
101
+ onChange?.(nextMarkdown);
102
+ };
103
+ const editorToolbar = /* @__PURE__ */ jsxs("div", {
104
+ className: "flex flex-wrap items-center justify-between gap-3",
105
+ children: [/* @__PURE__ */ jsxs(TabsList, {
106
+ variant: "underline",
107
+ className: "h-auto gap-4 border-0 bg-transparent p-0 text-muted-foreground",
108
+ children: [/* @__PURE__ */ jsx(TabsTrigger, {
109
+ value: "preview",
110
+ variant: "underline",
111
+ className: "pb-2 data-[state=active]:border-primary data-[state=active]:text-foreground",
112
+ children: "Preview"
113
+ }), /* @__PURE__ */ jsxs(TabsTrigger, {
114
+ value: "edit",
115
+ variant: "underline",
116
+ className: "flex items-center gap-2 pb-2 data-[state=active]:border-primary data-[state=active]:text-foreground",
117
+ children: [/* @__PURE__ */ jsx(PencilLine, { className: "h-3.5 w-3.5" }), isCollaborative ? "Live edit" : "Edit"]
118
+ })]
119
+ }), /* @__PURE__ */ jsxs("div", {
120
+ className: "flex flex-wrap items-center gap-2 text-xs text-muted-foreground",
121
+ children: [
122
+ toolbar,
123
+ /* @__PURE__ */ jsx("span", {
124
+ className: "rounded-full border border-border bg-card px-2.5 py-1 font-medium",
125
+ children: isCollaborative ? "Live document" : "Local draft"
126
+ }),
127
+ /* @__PURE__ */ jsx("span", {
128
+ className: "rounded-full border border-border bg-background px-2.5 py-1",
129
+ children: saveStateLabel
130
+ }),
131
+ onSave && !readOnly && /* @__PURE__ */ jsxs("button", {
132
+ type: "button",
133
+ onClick: () => void onSave(draft),
134
+ disabled: saving || !isDirty,
135
+ className: cn("inline-flex items-center gap-2 rounded-[var(--radius-full)] border border-border bg-card px-3 py-1.5 text-xs font-semibold text-foreground transition-colors hover:border-[var(--border-strong)] hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50", focusRing),
136
+ children: [/* @__PURE__ */ jsx(Save, { className: "h-3.5 w-3.5" }), saving ? "Saving..." : saveLabel]
137
+ })
138
+ ]
139
+ })]
140
+ });
141
+ const preview = /* @__PURE__ */ jsx("div", {
142
+ className: cn("m-4 rounded-[var(--radius-lg)] border border-border bg-card p-5", previewClassName),
143
+ children: /* @__PURE__ */ jsx(Markdown, {
144
+ urlTransform,
145
+ children: draft
146
+ })
147
+ });
148
+ const localEditor = /* @__PURE__ */ jsx(MarkdownDocumentEditor, {
149
+ value: draft,
150
+ placeholder,
151
+ autoFocus,
152
+ readOnly,
153
+ onChange: (nextMarkdown) => {
154
+ handleChange(nextMarkdown);
155
+ },
156
+ className: editorClassName
157
+ });
158
+ const collaborativeEditor = collaboration ? /* @__PURE__ */ jsx(EditorProvider, {
159
+ ...collaboration,
160
+ children: /* @__PURE__ */ jsx(CollaborativeDocumentSurface, {
161
+ markdown: draft,
162
+ placeholder,
163
+ autoFocus,
164
+ readOnly,
165
+ className: editorClassName,
166
+ onChange: handleChange
167
+ })
168
+ }, collaboration.documentName) : localEditor;
169
+ return /* @__PURE__ */ jsx(Tabs, {
170
+ value: activeMode,
171
+ onValueChange: (nextValue) => setMode(nextValue),
172
+ className: "h-full",
173
+ children: /* @__PURE__ */ jsxs(ArtifactPane, {
174
+ eyebrow,
175
+ title,
176
+ subtitle,
177
+ meta,
178
+ headerActions,
179
+ footer,
180
+ tabs,
181
+ className,
182
+ contentClassName,
183
+ headerClassName,
184
+ toolbar: editorToolbar,
185
+ hideTitleBlock,
186
+ children: [/* @__PURE__ */ jsx(TabsContent, {
187
+ value: "preview",
188
+ className: "mt-0 h-full",
189
+ children: preview
190
+ }), /* @__PURE__ */ jsx(TabsContent, {
191
+ value: "edit",
192
+ className: "mt-0 h-full px-4 py-4",
193
+ children: isCollaborative ? collaborativeEditor : localEditor
194
+ })]
195
+ })
196
+ });
197
+ }
198
+ //#endregion
199
+ export { DocumentEditorPane };
@@ -0,0 +1,37 @@
1
+ import { isMissingEditorPeersError } from "./editor-peers.js";
2
+ import { lazy } from "react";
3
+ //#region src/editor/editor-lazy.ts
4
+ /**
5
+ * Builds a `lazy` editor component that a remount can re-attempt.
6
+ *
7
+ * `lazy` caches its first rejection for the life of the component. That is
8
+ * right for a missing peer, which stays missing for the session, and wrong for
9
+ * a transient chunk fetch: one failed network request would otherwise hold the
10
+ * editor broken until a full page reload.
11
+ *
12
+ * The returned function gives the component to render, and a caller must call
13
+ * it on every render: a transient failure replaces the component, and a caller
14
+ * that holds the one it got earlier keeps replaying the cached rejection.
15
+ *
16
+ * A `MissingEditorPeersError` keeps the cached rejection, so the install list
17
+ * reaches the consumer's error boundary once and the loader does not run
18
+ * again. Any other rejection replaces the component, so the next mount — an
19
+ * error boundary that resets, or a remount by the parent — starts a fresh
20
+ * attempt.
21
+ */
22
+ function retryableLazyEditor(loadComponent) {
23
+ function build() {
24
+ return lazy(async () => {
25
+ try {
26
+ return { default: await loadComponent() };
27
+ } catch (error) {
28
+ if (!isMissingEditorPeersError(error)) current = build();
29
+ throw error;
30
+ }
31
+ });
32
+ }
33
+ let current = build();
34
+ return () => current;
35
+ }
36
+ //#endregion
37
+ export { retryableLazyEditor };
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { cn } from "../lib/utils.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/editor/editor-loading.tsx
5
+ /**
6
+ * Stands in for an editor while its optional peers load. The editors reach
7
+ * tiptap through a dynamic import, so an editor's first frame waits for that
8
+ * chunk. The live region announces the wait, which a screen reader has no
9
+ * other way to notice. Callers put their own minimum height first, so a
10
+ * caller-supplied className still wins.
11
+ */
12
+ function EditorLoadingPlaceholder({ className }) {
13
+ return /* @__PURE__ */ jsx("div", {
14
+ role: "status",
15
+ "aria-live": "polite",
16
+ className: cn("flex w-full items-center justify-center rounded-lg border border-border border-dashed bg-muted text-muted-foreground text-sm", className),
17
+ children: "Loading editor…"
18
+ });
19
+ }
20
+ //#endregion
21
+ export { EditorLoadingPlaceholder };
@@ -0,0 +1,6 @@
1
+ import "@hocuspocus/provider";
2
+ import "yjs";
3
+ import "@tiptap/extension-collaboration";
4
+ import "@tiptap/extension-collaboration-caret";
5
+ import "@tiptap/react";
6
+ import "@tiptap/starter-kit";
@@ -0,0 +1,155 @@
1
+ //#region src/editor/editor-peers.ts
2
+ const DOCUMENT_PEERS_MISSING = "@tangle-network/ui/editor needs its optional editor peers. Install @tiptap/react and @tiptap/starter-kit.";
3
+ const PROVIDER_PEERS_MISSING = "@tangle-network/ui/editor needs its optional collaboration transport peers. Install @hocuspocus/provider and yjs.";
4
+ const COLLABORATION_PEERS_MISSING = "@tangle-network/ui/editor needs its optional collaboration peers. Install @tiptap/react, @tiptap/starter-kit, @tiptap/extension-collaboration, @tiptap/extension-collaboration-caret, @hocuspocus/provider and yjs.";
5
+ /**
6
+ * A peer the editor needs is absent, or resolved to a stub that carries none
7
+ * of the members the editor calls. The condition holds for the rest of the
8
+ * session, because a package does not install itself mid-run.
9
+ */
10
+ var MissingEditorPeersError = class extends Error {
11
+ constructor(message, options) {
12
+ super(message, options);
13
+ this.name = "MissingEditorPeersError";
14
+ }
15
+ };
16
+ /**
17
+ * True for the error above. The name carries the answer, so a duplicated copy
18
+ * of this module in a consumer's bundle still reports its own error correctly.
19
+ */
20
+ function isMissingEditorPeersError(error) {
21
+ return error instanceof Error && error.name === "MissingEditorPeersError";
22
+ }
23
+ /** The messages a bundler or a runtime gives for a module it cannot resolve. */
24
+ const RESOLUTION_FAILURE = /could not resolve|cannot find (?:module|package)|can't resolve|failed to resolve|module not found/i;
25
+ /**
26
+ * True when the rejection says the package is not installed. Only such an
27
+ * error gets the install list: a transient chunk-fetch failure that reads as
28
+ * "install the peers" sends the reader to the wrong fix. An error this
29
+ * predicate does not match keeps its own message, so it can only
30
+ * under-report.
31
+ */
32
+ function isMissingPeerError(error) {
33
+ return error instanceof Error && RESOLUTION_FAILURE.test(error.message);
34
+ }
35
+ /**
36
+ * Hands an `import()` rejection on unchanged. esbuild reports an unresolvable
37
+ * literal `import()` as a build error and defers it to run time only when the
38
+ * call carries a `.catch()`, so every peer import attaches this handler. It
39
+ * changes nothing at run time.
40
+ */
41
+ function rethrow(error) {
42
+ throw error;
43
+ }
44
+ /**
45
+ * Every optional peer the `./editor` entry needs at run time. The loaders
46
+ * import all but `@tiptap/core`, which the tiptap packages need in turn: a
47
+ * consumer that resolves it to nothing breaks the same way, so a failure that
48
+ * names it is a missing peer too. `scripts/validate-dist.mjs` holds the same
49
+ * list and rejects a build where the two disagree.
50
+ */
51
+ const DEFERRED_PEERS = [
52
+ "@tiptap/core",
53
+ "@tiptap/react",
54
+ "@tiptap/starter-kit",
55
+ "@tiptap/extension-collaboration",
56
+ "@tiptap/extension-collaboration-caret",
57
+ "@hocuspocus/provider",
58
+ "yjs"
59
+ ];
60
+ /** Every deferred peer a resolution failure names. */
61
+ function unresolvedPeersFrom(error) {
62
+ if (!(error instanceof Error)) return [];
63
+ const named = DEFERRED_PEERS.filter((name) => error.message.includes(name));
64
+ return named.filter((name) => !named.some((other) => other !== name && other.includes(name)));
65
+ }
66
+ /**
67
+ * Turns a rejection that names an unresolved peer into the install-list error,
68
+ * and keeps the original as its cause. Any other rejection passes through, so
69
+ * a transient chunk fetch keeps its own message and stays retryable.
70
+ */
71
+ function asMissingEditorPeersError(error, missingMessage) {
72
+ if (!isMissingPeerError(error)) return error;
73
+ const unresolved = unresolvedPeersFrom(error);
74
+ if (unresolved.length === 0) return error;
75
+ return new MissingEditorPeersError(missingMessage + (unresolved.length === 1 ? ` ${unresolved[0]} did not resolve.` : ""), { cause: error });
76
+ }
77
+ async function loadPeers(load, missingMessage) {
78
+ try {
79
+ return await load();
80
+ } catch (error) {
81
+ throw asMissingEditorPeersError(error, missingMessage);
82
+ }
83
+ }
84
+ /**
85
+ * True for a tiptap extension the editor can configure. A bundler can stub a
86
+ * missing optional peer as a silent namespace whose default export is an empty
87
+ * object, which is defined but carries no `configure`. Reading the member the
88
+ * factories call separates that shape from a real extension.
89
+ */
90
+ function isConfigurableExtension(value) {
91
+ return typeof value?.configure === "function";
92
+ }
93
+ /**
94
+ * Reads the members the editor calls, so a stub namespace fails with the
95
+ * install list, and not as an undefined-property crash in the middle of a
96
+ * render.
97
+ */
98
+ function assertDocumentEditorPeers(peers, missingMessage) {
99
+ if (typeof peers.react.useEditor !== "function" || peers.react.EditorContent === void 0 || !isConfigurableExtension(peers.starterKit.default)) throw new MissingEditorPeersError(missingMessage);
100
+ }
101
+ function assertEditorProviderPeers(peers, missingMessage) {
102
+ if (typeof peers.hocuspocus.HocuspocusProvider !== "function" || typeof peers.yjs.Doc !== "function") throw new MissingEditorPeersError(missingMessage);
103
+ }
104
+ function assertCollaborationPeers(peers) {
105
+ assertDocumentEditorPeers(peers, COLLABORATION_PEERS_MISSING);
106
+ assertEditorProviderPeers(peers, COLLABORATION_PEERS_MISSING);
107
+ if (!isConfigurableExtension(peers.collaboration.default) || !isConfigurableExtension(peers.collaborationCaret.default)) throw new MissingEditorPeersError(COLLABORATION_PEERS_MISSING);
108
+ }
109
+ async function importDocumentEditorPeers() {
110
+ const [react, starterKit] = await Promise.all([import("@tiptap/react").catch(rethrow), import("@tiptap/starter-kit").catch(rethrow)]);
111
+ return {
112
+ react,
113
+ starterKit
114
+ };
115
+ }
116
+ async function importEditorProviderPeers() {
117
+ const [hocuspocus, yjs] = await Promise.all([import("@hocuspocus/provider").catch(rethrow), import("yjs").catch(rethrow)]);
118
+ return {
119
+ hocuspocus,
120
+ yjs
121
+ };
122
+ }
123
+ /** Resolve the collaboration transport's peers, or throw and name them. */
124
+ async function loadEditorProviderPeers() {
125
+ const peers = await loadPeers(importEditorProviderPeers, PROVIDER_PEERS_MISSING);
126
+ assertEditorProviderPeers(peers, PROVIDER_PEERS_MISSING);
127
+ return peers;
128
+ }
129
+ /** Resolve the local markdown editor's peers, or throw and name them. */
130
+ async function loadDocumentEditorPeers() {
131
+ const peers = await loadPeers(importDocumentEditorPeers, DOCUMENT_PEERS_MISSING);
132
+ assertDocumentEditorPeers(peers, DOCUMENT_PEERS_MISSING);
133
+ return peers;
134
+ }
135
+ /** Resolve the collaborative editor's peers, or throw and name them. */
136
+ async function loadCollaborationPeers() {
137
+ const peers = await loadPeers(async () => {
138
+ const [documentPeers, providerPeers, collaboration, collaborationCaret] = await Promise.all([
139
+ importDocumentEditorPeers(),
140
+ importEditorProviderPeers(),
141
+ import("@tiptap/extension-collaboration").catch(rethrow),
142
+ import("@tiptap/extension-collaboration-caret").catch(rethrow)
143
+ ]);
144
+ return {
145
+ ...documentPeers,
146
+ ...providerPeers,
147
+ collaboration,
148
+ collaborationCaret
149
+ };
150
+ }, COLLABORATION_PEERS_MISSING);
151
+ assertCollaborationPeers(peers);
152
+ return peers;
153
+ }
154
+ //#endregion
155
+ export { MissingEditorPeersError, asMissingEditorPeersError, isMissingEditorPeersError, isMissingPeerError, loadCollaborationPeers, loadDocumentEditorPeers, loadEditorProviderPeers };
@@ -1,21 +1,16 @@
1
- import { n as ArtifactPaneProps } from "./artifact-pane-BL_DFWNl.js";
1
+ import "./editor-peers.js";
2
2
  import { ReactNode } from "react";
3
- import { UrlTransform } from "react-markdown";
4
3
  import { HocuspocusProvider } from "@hocuspocus/provider";
5
4
  import * as Y from "yjs";
6
- import "@tiptap/extension-collaboration";
7
- import "@tiptap/extension-collaboration-caret";
8
- import "@tiptap/react";
9
- import "@tiptap/starter-kit";
10
5
  //#region src/editor/editor-provider.d.ts
11
6
  /**
12
7
  * Connection state for the Hocuspocus provider.
13
8
  */
14
- type ConnectionState = "disconnected" | "connecting" | "connected" | "synced";
9
+ export type ConnectionState = "disconnected" | "connecting" | "connected" | "synced";
15
10
  /**
16
11
  * Collaborator information from awareness.
17
12
  */
18
- interface Collaborator {
13
+ export interface Collaborator {
19
14
  clientId: number;
20
15
  user: {
21
16
  name: string;
@@ -26,7 +21,7 @@ interface Collaborator {
26
21
  /**
27
22
  * Editor context value exposed to children.
28
23
  */
29
- interface EditorContextValue {
24
+ export interface EditorContextValue {
30
25
  /** The Y.Doc instance for collaboration */
31
26
  doc: Y.Doc;
32
27
  /** The Hocuspocus provider instance */
@@ -45,19 +40,19 @@ interface EditorContextValue {
45
40
  /**
46
41
  * User information for presence/awareness.
47
42
  */
48
- interface EditorUser {
43
+ export interface EditorUser {
49
44
  name: string;
50
45
  color?: string;
51
46
  userId?: string;
52
47
  }
53
- interface EditorTokenRefreshResult {
48
+ export interface EditorTokenRefreshResult {
54
49
  token: string;
55
50
  expiresAt?: number;
56
51
  }
57
52
  /**
58
53
  * Props for EditorProvider.
59
54
  */
60
- interface EditorProviderProps {
55
+ export interface EditorProviderProps {
61
56
  /** WebSocket URL for the Hocuspocus server */
62
57
  websocketUrl: string;
63
58
  /** Document name (e.g., "doc:my-document") */
@@ -93,42 +88,10 @@ interface EditorProviderProps {
93
88
  * supply. A consumer that drives its own editor from that context therefore
94
89
  * needs those two peers alone.
95
90
  */
96
- declare function EditorProvider(props: EditorProviderProps): import("react").JSX.Element;
91
+ export declare function EditorProvider(props: EditorProviderProps): import("react").JSX.Element;
97
92
  /**
98
93
  * Hook to access the editor context.
99
94
  * Must be used within an EditorProvider.
100
95
  */
101
- declare function useEditorContext(): EditorContextValue;
102
- //#endregion
103
- //#region src/editor/document-editor-pane.d.ts
104
- type DocumentEditorMode = "preview" | "edit";
105
- type DocumentEditorBackend = "local" | "collaborative";
106
- interface DocumentEditorPaneCollaborationConfig extends Omit<EditorProviderProps, "children"> {}
107
- interface DocumentEditorPaneProps extends Omit<ArtifactPaneProps, "children" | "tabs" | "toolbar" | "emptyState"> {
108
- tabs?: ArtifactPaneProps["tabs"];
109
- toolbar?: ReactNode;
110
- markdown?: string;
111
- /** Transform Markdown links and images through the shared URL policy. */
112
- urlTransform?: UrlTransform;
113
- mode?: DocumentEditorMode;
114
- defaultMode?: DocumentEditorMode;
115
- onModeChange?: (mode: DocumentEditorMode) => void;
116
- backend?: DocumentEditorBackend;
117
- placeholder?: string;
118
- autoFocus?: boolean;
119
- readOnly?: boolean;
120
- onChange?: (markdown: string) => void;
121
- onSave?: (markdown: string) => Promise<void> | void;
122
- saving?: boolean;
123
- saveLabel?: string;
124
- previewClassName?: string;
125
- editorClassName?: string;
126
- collaboration?: DocumentEditorPaneCollaborationConfig;
127
- }
128
- /**
129
- * DocumentEditorPane — reusable markdown document surface with preview/edit
130
- * modes and optional collaborative editing backed by Yjs/Hocuspocus.
131
- */
132
- declare function DocumentEditorPane({ eyebrow, title, subtitle, meta, headerActions, footer, className, contentClassName, headerClassName, hideTitleBlock, tabs, toolbar, markdown, urlTransform, mode, defaultMode, onModeChange, backend, placeholder, autoFocus, readOnly, onChange, onSave, saving, saveLabel, previewClassName, editorClassName, collaboration }: DocumentEditorPaneProps): import("react").JSX.Element;
133
- //#endregion
134
- export { DocumentEditorPaneProps as a, EditorContextValue as c, EditorTokenRefreshResult as d, EditorUser as f, DocumentEditorPaneCollaborationConfig as i, EditorProvider as l, DocumentEditorMode as n, Collaborator as o, useEditorContext as p, DocumentEditorPane as r, ConnectionState as s, DocumentEditorBackend as t, EditorProviderProps as u };
96
+ export declare function useEditorContext(): EditorContextValue;
97
+ //#endregion