@agent-native/core 0.41.1 → 0.43.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 (181) hide show
  1. package/README.md +17 -56
  2. package/dist/action.d.ts +13 -1
  3. package/dist/action.d.ts.map +1 -1
  4. package/dist/action.js.map +1 -1
  5. package/dist/agent/production-agent.d.ts +8 -0
  6. package/dist/agent/production-agent.d.ts.map +1 -1
  7. package/dist/agent/production-agent.js +93 -0
  8. package/dist/agent/production-agent.js.map +1 -1
  9. package/dist/cli/app-skill.d.ts +16 -0
  10. package/dist/cli/app-skill.d.ts.map +1 -1
  11. package/dist/cli/app-skill.js +33 -3
  12. package/dist/cli/app-skill.js.map +1 -1
  13. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  14. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  15. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  16. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  17. package/dist/cli/recap.d.ts.map +1 -1
  18. package/dist/cli/recap.js +38 -16
  19. package/dist/cli/recap.js.map +1 -1
  20. package/dist/cli/skills.d.ts +30 -3
  21. package/dist/cli/skills.d.ts.map +1 -1
  22. package/dist/cli/skills.js +180 -114
  23. package/dist/cli/skills.js.map +1 -1
  24. package/dist/client/AssistantChat.d.ts.map +1 -1
  25. package/dist/client/AssistantChat.js +2 -2
  26. package/dist/client/AssistantChat.js.map +1 -1
  27. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  28. package/dist/client/agent-chat-adapter.js +172 -5
  29. package/dist/client/agent-chat-adapter.js.map +1 -1
  30. package/dist/client/blocks/index.d.ts +11 -0
  31. package/dist/client/blocks/index.d.ts.map +1 -1
  32. package/dist/client/blocks/index.js +11 -0
  33. package/dist/client/blocks/index.js.map +1 -1
  34. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts +19 -0
  35. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  36. package/dist/client/blocks/library/AnnotatedCodeBlock.js +6 -58
  37. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  38. package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
  39. package/dist/client/blocks/library/ApiEndpointBlock.js +116 -7
  40. package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
  41. package/dist/client/blocks/library/DataModelBlock.d.ts.map +1 -1
  42. package/dist/client/blocks/library/DataModelBlock.js +75 -9
  43. package/dist/client/blocks/library/DataModelBlock.js.map +1 -1
  44. package/dist/client/blocks/library/DiffBlock.d.ts +1 -1
  45. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  46. package/dist/client/blocks/library/DiffBlock.js +265 -39
  47. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  48. package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
  49. package/dist/client/blocks/library/FileTreeBlock.js +27 -4
  50. package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
  51. package/dist/client/blocks/library/HighlightedCode.d.ts +1 -1
  52. package/dist/client/blocks/library/HighlightedCode.js +1 -1
  53. package/dist/client/blocks/library/HighlightedCode.js.map +1 -1
  54. package/dist/client/blocks/library/JsonExplorerBlock.js +1 -1
  55. package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
  56. package/dist/client/blocks/library/MermaidBlock.js +1 -1
  57. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  58. package/dist/client/blocks/library/annotation-rail.d.ts +115 -0
  59. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -0
  60. package/dist/client/blocks/library/annotation-rail.js +139 -0
  61. package/dist/client/blocks/library/annotation-rail.js.map +1 -0
  62. package/dist/client/blocks/library/api-endpoint.config.d.ts +31 -6
  63. package/dist/client/blocks/library/api-endpoint.config.d.ts.map +1 -1
  64. package/dist/client/blocks/library/api-endpoint.config.js +30 -6
  65. package/dist/client/blocks/library/api-endpoint.config.js.map +1 -1
  66. package/dist/client/blocks/library/callout.config.d.ts +29 -0
  67. package/dist/client/blocks/library/callout.config.d.ts.map +1 -0
  68. package/dist/client/blocks/library/callout.config.js +33 -0
  69. package/dist/client/blocks/library/callout.config.js.map +1 -0
  70. package/dist/client/blocks/library/callout.d.ts +20 -0
  71. package/dist/client/blocks/library/callout.d.ts.map +1 -0
  72. package/dist/client/blocks/library/callout.js +61 -0
  73. package/dist/client/blocks/library/callout.js.map +1 -0
  74. package/dist/client/blocks/library/checklist.d.ts.map +1 -1
  75. package/dist/client/blocks/library/checklist.js +3 -3
  76. package/dist/client/blocks/library/checklist.js.map +1 -1
  77. package/dist/client/blocks/library/code.d.ts.map +1 -1
  78. package/dist/client/blocks/library/code.js +32 -15
  79. package/dist/client/blocks/library/code.js.map +1 -1
  80. package/dist/client/blocks/library/columns.d.ts.map +1 -1
  81. package/dist/client/blocks/library/columns.js +56 -35
  82. package/dist/client/blocks/library/columns.js.map +1 -1
  83. package/dist/client/blocks/library/data-model.config.d.ts +17 -0
  84. package/dist/client/blocks/library/data-model.config.d.ts.map +1 -1
  85. package/dist/client/blocks/library/data-model.config.js +15 -0
  86. package/dist/client/blocks/library/data-model.config.js.map +1 -1
  87. package/dist/client/blocks/library/decision.config.d.ts +37 -0
  88. package/dist/client/blocks/library/decision.config.d.ts.map +1 -0
  89. package/dist/client/blocks/library/decision.config.js +32 -0
  90. package/dist/client/blocks/library/decision.config.js.map +1 -0
  91. package/dist/client/blocks/library/decision.d.ts +19 -0
  92. package/dist/client/blocks/library/decision.d.ts.map +1 -0
  93. package/dist/client/blocks/library/decision.js +119 -0
  94. package/dist/client/blocks/library/decision.js.map +1 -0
  95. package/dist/client/blocks/library/diagram.config.d.ts +64 -0
  96. package/dist/client/blocks/library/diagram.config.d.ts.map +1 -0
  97. package/dist/client/blocks/library/diagram.config.js +111 -0
  98. package/dist/client/blocks/library/diagram.config.js.map +1 -0
  99. package/dist/client/blocks/library/diagram.d.ts +16 -0
  100. package/dist/client/blocks/library/diagram.d.ts.map +1 -0
  101. package/dist/client/blocks/library/diagram.js +261 -0
  102. package/dist/client/blocks/library/diagram.js.map +1 -0
  103. package/dist/client/blocks/library/diff.config.d.ts +28 -6
  104. package/dist/client/blocks/library/diff.config.d.ts.map +1 -1
  105. package/dist/client/blocks/library/diff.config.js +30 -6
  106. package/dist/client/blocks/library/diff.config.js.map +1 -1
  107. package/dist/client/blocks/library/question-form.config.d.ts +69 -0
  108. package/dist/client/blocks/library/question-form.config.d.ts.map +1 -0
  109. package/dist/client/blocks/library/question-form.config.js +58 -0
  110. package/dist/client/blocks/library/question-form.config.js.map +1 -0
  111. package/dist/client/blocks/library/question-form.d.ts +20 -0
  112. package/dist/client/blocks/library/question-form.d.ts.map +1 -0
  113. package/dist/client/blocks/library/question-form.js +286 -0
  114. package/dist/client/blocks/library/question-form.js.map +1 -0
  115. package/dist/client/blocks/library/sanitize-html.d.ts +5 -0
  116. package/dist/client/blocks/library/sanitize-html.d.ts.map +1 -0
  117. package/dist/client/blocks/library/sanitize-html.js +240 -0
  118. package/dist/client/blocks/library/sanitize-html.js.map +1 -0
  119. package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
  120. package/dist/client/blocks/library/server-specs.js +59 -0
  121. package/dist/client/blocks/library/server-specs.js.map +1 -1
  122. package/dist/client/blocks/library/specs.d.ts.map +1 -1
  123. package/dist/client/blocks/library/specs.js +11 -0
  124. package/dist/client/blocks/library/specs.js.map +1 -1
  125. package/dist/client/blocks/library/tabs.d.ts.map +1 -1
  126. package/dist/client/blocks/library/tabs.js +12 -12
  127. package/dist/client/blocks/library/tabs.js.map +1 -1
  128. package/dist/client/blocks/library/wireframe-kit.d.ts +260 -0
  129. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -0
  130. package/dist/client/blocks/library/wireframe-kit.js +920 -0
  131. package/dist/client/blocks/library/wireframe-kit.js.map +1 -0
  132. package/dist/client/blocks/library/wireframe.config.d.ts +123 -0
  133. package/dist/client/blocks/library/wireframe.config.d.ts.map +1 -0
  134. package/dist/client/blocks/library/wireframe.config.js +294 -0
  135. package/dist/client/blocks/library/wireframe.config.js.map +1 -0
  136. package/dist/client/blocks/library/wireframe.d.ts +15 -0
  137. package/dist/client/blocks/library/wireframe.d.ts.map +1 -0
  138. package/dist/client/blocks/library/wireframe.js +206 -0
  139. package/dist/client/blocks/library/wireframe.js.map +1 -0
  140. package/dist/client/blocks/registry.d.ts +9 -0
  141. package/dist/client/blocks/registry.d.ts.map +1 -1
  142. package/dist/client/blocks/registry.js +12 -5
  143. package/dist/client/blocks/registry.js.map +1 -1
  144. package/dist/client/blocks/server.d.ts +1 -0
  145. package/dist/client/blocks/server.d.ts.map +1 -1
  146. package/dist/client/blocks/server.js +1 -0
  147. package/dist/client/blocks/server.js.map +1 -1
  148. package/dist/client/blocks/types.d.ts +10 -2
  149. package/dist/client/blocks/types.d.ts.map +1 -1
  150. package/dist/client/blocks/types.js.map +1 -1
  151. package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
  152. package/dist/client/rich-markdown-editor/DragHandle.js +152 -21
  153. package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
  154. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +25 -1
  155. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
  156. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +29 -6
  157. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  158. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +8 -1
  159. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
  160. package/dist/client/rich-markdown-editor/SharedRichEditor.js +5 -1
  161. package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
  162. package/dist/extensions/actions.d.ts.map +1 -1
  163. package/dist/extensions/actions.js +159 -12
  164. package/dist/extensions/actions.js.map +1 -1
  165. package/dist/extensions/store.d.ts +21 -0
  166. package/dist/extensions/store.d.ts.map +1 -1
  167. package/dist/extensions/store.js +33 -1
  168. package/dist/extensions/store.js.map +1 -1
  169. package/dist/server/recap-image-route.d.ts.map +1 -1
  170. package/dist/server/recap-image-route.js +12 -3
  171. package/dist/server/recap-image-route.js.map +1 -1
  172. package/dist/styles/agent-native.css +1 -0
  173. package/dist/styles/blocks.css +1380 -0
  174. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +30 -5
  175. package/docs/content/plan-plugin.md +107 -0
  176. package/docs/content/pr-visual-recap.md +2 -2
  177. package/docs/content/skills-guide.md +8 -0
  178. package/docs/content/template-plan.md +94 -17
  179. package/package.json +2 -1
  180. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +30 -5
  181. package/docs/content/visual-plans.md +0 -80
@@ -0,0 +1,920 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, } from "react";
3
+ import rough from "roughjs";
4
+ const STYLE_STORAGE_KEY = "plan-wireframe-style";
5
+ const styleListeners = new Set();
6
+ function readStoredStyle() {
7
+ if (typeof localStorage === "undefined")
8
+ return "sketchy";
9
+ try {
10
+ return localStorage.getItem(STYLE_STORAGE_KEY) === "clean"
11
+ ? "clean"
12
+ : "sketchy";
13
+ }
14
+ catch {
15
+ return "sketchy";
16
+ }
17
+ }
18
+ let currentStyle = readStoredStyle();
19
+ export function setWireframeStyle(style) {
20
+ if (style === currentStyle)
21
+ return;
22
+ currentStyle = style;
23
+ try {
24
+ localStorage.setItem(STYLE_STORAGE_KEY, style);
25
+ }
26
+ catch {
27
+ // ignore (private mode / disabled storage)
28
+ }
29
+ for (const listener of styleListeners)
30
+ listener();
31
+ }
32
+ export function toggleWireframeStyle() {
33
+ setWireframeStyle(currentStyle === "sketchy" ? "clean" : "sketchy");
34
+ }
35
+ function subscribeStyle(callback) {
36
+ styleListeners.add(callback);
37
+ const onStorage = (event) => {
38
+ if (event.key === STYLE_STORAGE_KEY) {
39
+ currentStyle = readStoredStyle();
40
+ callback();
41
+ }
42
+ };
43
+ if (typeof window !== "undefined") {
44
+ window.addEventListener("storage", onStorage);
45
+ }
46
+ return () => {
47
+ styleListeners.delete(callback);
48
+ if (typeof window !== "undefined") {
49
+ window.removeEventListener("storage", onStorage);
50
+ }
51
+ };
52
+ }
53
+ export function useWireframeStyle() {
54
+ return useSyncExternalStore(subscribeStyle, () => currentStyle, () => "sketchy");
55
+ }
56
+ /** Read the live dark-mode flag from the document root (next-themes-free). */
57
+ export function useIsDark() {
58
+ const [isDark, setIsDark] = useState(false);
59
+ useEffect(() => {
60
+ if (typeof document === "undefined")
61
+ return;
62
+ const root = document.documentElement;
63
+ const read = () => setIsDark(root.classList.contains("dark"));
64
+ read();
65
+ const observer = new MutationObserver(read);
66
+ observer.observe(root, { attributes: true, attributeFilter: ["class"] });
67
+ return () => observer.disconnect();
68
+ }, []);
69
+ return isDark;
70
+ }
71
+ /* ========================================================================== */
72
+ /* Primitives (ported from kit/primitives.tsx) */
73
+ /* ========================================================================== */
74
+ /**
75
+ * Frame-level config threaded to every Screen so skeleton / theme / sketch-vs-
76
+ * clean reach the kit no matter which path renders the root Screen.
77
+ */
78
+ export const KitConfigContext = createContext({});
79
+ const V = {
80
+ ink: "var(--ink)",
81
+ soft: "var(--ink-soft)",
82
+ line: "var(--line)",
83
+ paper: "var(--paper)",
84
+ card: "var(--card)",
85
+ accent: "var(--accent)",
86
+ accentSoft: "var(--accent-soft)",
87
+ warn: "var(--warn)",
88
+ warnSoft: "var(--warn-soft)",
89
+ ok: "var(--ok)",
90
+ okSoft: "var(--ok-soft)",
91
+ stroke: "var(--stroke)",
92
+ radius: "var(--radius)",
93
+ gap: "var(--gap)",
94
+ pad: "var(--pad)",
95
+ fs: "var(--fs)",
96
+ hand: "var(--font-hand)",
97
+ script: "var(--font-script)",
98
+ };
99
+ function toneColors(tone = "default") {
100
+ switch (tone) {
101
+ case "accent":
102
+ return { fg: V.accent, bg: V.accentSoft, bd: V.accent };
103
+ case "warn":
104
+ return { fg: V.warn, bg: V.warnSoft, bd: V.warn };
105
+ case "ok":
106
+ return { fg: V.ok, bg: V.okSoft, bd: V.ok };
107
+ case "muted":
108
+ return { fg: V.soft, bg: "transparent", bd: V.soft };
109
+ default:
110
+ return { fg: V.ink, bg: "transparent", bd: V.ink };
111
+ }
112
+ }
113
+ function toneInk(tone) {
114
+ return toneColors(tone).fg;
115
+ }
116
+ function fontWeight(weight) {
117
+ if (weight === "bold")
118
+ return 700;
119
+ if (weight === "medium")
120
+ return 600;
121
+ return 400;
122
+ }
123
+ export function Screen({ children, pad = 0, sketch, density, theme, skeleton = false, style = {}, }) {
124
+ const cfg = useContext(KitConfigContext);
125
+ const isSkeleton = skeleton || Boolean(cfg.skeleton);
126
+ const wfStyle = cfg.style ?? "sketchy";
127
+ const wfTheme = theme ?? cfg.theme ?? "light";
128
+ void sketch;
129
+ return (_jsx("div", { className: "plan-wf", "data-density": density ?? "regular", "data-theme": wfTheme, "data-skeleton": isSkeleton ? "true" : undefined, "data-style": wfStyle, style: {
130
+ position: "relative",
131
+ width: "100%",
132
+ // `minHeight` (not a fixed `height: 100%`) so the screen fills an
133
+ // auto-height artboard's floor yet grows with its content instead of
134
+ // clipping. The frame shell (`ArtboardFrame`) owns the height policy; a
135
+ // caller can still override via `style.height` for a fixed canvas.
136
+ minHeight: "100%",
137
+ background: V.paper,
138
+ color: V.ink,
139
+ fontFamily: V.hand,
140
+ fontSize: V.fs,
141
+ lineHeight: 1.25,
142
+ display: "flex",
143
+ flexDirection: "column",
144
+ padding: pad,
145
+ boxSizing: "border-box",
146
+ overflow: "hidden",
147
+ ...style,
148
+ }, children: children }));
149
+ }
150
+ export function Hand({ children, size, weight = 400, color = V.ink, script = false, style = {}, }) {
151
+ return (_jsx("span", { style: {
152
+ fontFamily: script ? V.script : V.hand,
153
+ fontSize: size ?? V.fs,
154
+ fontWeight: weight,
155
+ color,
156
+ minWidth: 0,
157
+ overflowWrap: "break-word",
158
+ ...style,
159
+ }, children: children }));
160
+ }
161
+ export function Bar({ w = 80, h, color = V.line, r = 4, style = {}, }) {
162
+ return (_jsx("div", { style: {
163
+ width: w,
164
+ height: h ?? "calc(var(--fs) * 0.72)",
165
+ background: color,
166
+ borderRadius: r,
167
+ flex: "0 0 auto",
168
+ ...style,
169
+ } }));
170
+ }
171
+ export function Lines({ n = 2, gap = 6, widths, color = V.line, style = {}, }) {
172
+ const ws = widths ??
173
+ Array.from({ length: n }, (_, i) => (i === n - 1 ? "55%" : "100%"));
174
+ return (_jsx("div", { style: { display: "flex", flexDirection: "column", gap, ...style }, children: ws.map((w, i) => (_jsx(Bar, { w: typeof w === "number" ? `${w}%` : w, color: color }, i))) }));
175
+ }
176
+ export function Box({ children, pad = V.pad, fill = V.card, dashed = false, style = {}, }) {
177
+ return (_jsx("div", { "data-rough": "rect", style: {
178
+ ["--rough-stroke"]: V.ink,
179
+ border: `${V.stroke} ${dashed ? "dashed" : "solid"} ${V.ink}`,
180
+ borderRadius: V.radius,
181
+ background: fill,
182
+ padding: pad,
183
+ boxSizing: "border-box",
184
+ minWidth: 0,
185
+ ...style,
186
+ }, children: children }));
187
+ }
188
+ export function Check({ done = false, shape = "square", size = 18, }) {
189
+ const r = shape === "circle" ? "50%" : "calc(var(--radius) * 0.5)";
190
+ return (_jsx("div", { "data-rough": shape === "circle" ? "ellipse" : "rect", style: {
191
+ ["--rough-stroke"]: done ? V.accent : V.ink,
192
+ width: size,
193
+ height: size,
194
+ flex: "0 0 auto",
195
+ borderRadius: r,
196
+ border: `${V.stroke} solid ${done ? V.accent : V.ink}`,
197
+ background: done ? V.accent : "transparent",
198
+ display: "flex",
199
+ alignItems: "center",
200
+ justifyContent: "center",
201
+ }, children: done && (_jsx("svg", { width: size * 0.6, height: size * 0.6, viewBox: "0 0 12 12", fill: "none", stroke: "#fff", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("path", { d: "M2 6.5l2.5 2.5L10 3" }) })) }));
202
+ }
203
+ export function Pill({ children, tone = "default", style = {}, }) {
204
+ const c = toneColors(tone);
205
+ return (_jsx("span", { style: {
206
+ display: "inline-flex",
207
+ alignItems: "center",
208
+ gap: 4,
209
+ border: `${V.stroke} solid ${c.bd}`,
210
+ background: c.bg,
211
+ color: c.fg,
212
+ borderRadius: 999,
213
+ padding: "2px 9px",
214
+ fontSize: "calc(var(--fs) * 0.82)",
215
+ fontFamily: V.hand,
216
+ maxWidth: "100%",
217
+ minWidth: 0,
218
+ whiteSpace: "normal",
219
+ overflowWrap: "anywhere",
220
+ lineHeight: 1.3,
221
+ ...style,
222
+ }, children: children }));
223
+ }
224
+ export function Prio({ level = 2, label }) {
225
+ const fill = level === 1 ? V.warn : level === 2 ? V.soft : "transparent";
226
+ const bd = level === 3 ? V.soft : "transparent";
227
+ return (_jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 5 }, children: [_jsx("span", { style: {
228
+ width: 9,
229
+ height: 9,
230
+ borderRadius: "50%",
231
+ background: fill,
232
+ border: `${V.stroke} solid ${bd}`,
233
+ flex: "0 0 auto",
234
+ } }), label && (_jsx(Hand, { size: "calc(var(--fs) * 0.82)", color: V.soft, children: label }))] }));
235
+ }
236
+ export function Btn({ children, solid = false, full = false, size = "md", tone = "default", style = {}, }) {
237
+ const pad = size === "sm" ? "4px 10px" : size === "lg" ? "10px 18px" : "7px 14px";
238
+ const c = toneColors(tone === "default" ? "accent" : tone);
239
+ return (_jsx("div", { "data-rough": "rect", style: {
240
+ ["--rough-stroke"]: solid ? c.bd : V.ink,
241
+ display: full ? "flex" : "inline-flex",
242
+ alignItems: "center",
243
+ justifyContent: "center",
244
+ gap: 6,
245
+ border: `${V.stroke} solid ${solid ? c.bd : V.ink}`,
246
+ background: solid ? c.bd : "transparent",
247
+ color: solid ? "#fff" : V.ink,
248
+ borderRadius: V.radius,
249
+ padding: pad,
250
+ fontFamily: V.hand,
251
+ fontSize: V.fs,
252
+ fontWeight: 700,
253
+ width: full ? "100%" : "auto",
254
+ maxWidth: "100%",
255
+ minWidth: 0,
256
+ boxSizing: "border-box",
257
+ whiteSpace: "normal",
258
+ overflowWrap: "anywhere",
259
+ textAlign: "center",
260
+ ...style,
261
+ }, children: children }));
262
+ }
263
+ export function Chip({ children, active = false, style = {}, }) {
264
+ return (_jsx("span", { style: {
265
+ display: "inline-flex",
266
+ alignItems: "center",
267
+ gap: 5,
268
+ border: `${V.stroke} solid ${active ? V.accent : V.ink}`,
269
+ background: active ? V.accentSoft : "transparent",
270
+ color: active ? V.accent : V.ink,
271
+ borderRadius: 999,
272
+ padding: "4px 12px",
273
+ fontSize: "calc(var(--fs) * 0.88)",
274
+ fontFamily: V.hand,
275
+ fontWeight: active ? 700 : 400,
276
+ maxWidth: "100%",
277
+ minWidth: 0,
278
+ whiteSpace: "normal",
279
+ overflowWrap: "anywhere",
280
+ ...style,
281
+ }, children: children }));
282
+ }
283
+ export function Field({ label, value, placeholder, h, area = false, right, style = {}, }) {
284
+ return (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 5, ...style }, children: [label && (_jsx(Hand, { size: "calc(var(--fs) * 0.86)", color: V.soft, weight: 700, children: label })), _jsxs("div", { "data-rough": "rect", style: {
285
+ ["--rough-stroke"]: V.ink,
286
+ border: `${V.stroke} solid ${V.ink}`,
287
+ borderRadius: V.radius,
288
+ background: V.card,
289
+ padding: "calc(var(--pad) * 0.8)",
290
+ minHeight: h ?? (area ? 64 : "auto"),
291
+ display: "flex",
292
+ alignItems: area ? "flex-start" : "center",
293
+ justifyContent: "space-between",
294
+ minWidth: 0,
295
+ gap: 8,
296
+ }, children: [value ? (_jsx(Hand, { style: { minWidth: 0, overflowWrap: "anywhere" }, children: value })) : area ? (_jsx(Lines, { n: 2, widths: ["85%", "60%"] })) : (_jsx(Bar, { w: placeholder ?? 110 })), right] })] }));
297
+ }
298
+ export function StatusBar() {
299
+ return (_jsxs("div", { style: {
300
+ display: "flex",
301
+ alignItems: "center",
302
+ justifyContent: "space-between",
303
+ padding: "9px 18px 2px",
304
+ flex: "0 0 auto",
305
+ }, children: [_jsx(Hand, { size: "calc(var(--fs) * 0.82)", weight: 700, children: "9:41" }), _jsxs("div", { style: { display: "flex", gap: 5, alignItems: "center" }, children: [_jsx(Bar, { w: 16, h: 8, color: V.soft, r: 2 }), _jsx(Bar, { w: 12, h: 8, color: V.soft, r: 2 }), _jsx(Bar, { w: 20, h: 9, color: V.soft, r: 2 })] })] }));
306
+ }
307
+ export function Fab({ icon = "+" }) {
308
+ return (_jsx("div", { "data-rough": "ellipse", style: {
309
+ ["--rough-stroke"]: V.accent,
310
+ position: "absolute",
311
+ right: 18,
312
+ bottom: 22,
313
+ width: 52,
314
+ height: 52,
315
+ borderRadius: "50%",
316
+ border: `${V.stroke} solid ${V.accent}`,
317
+ background: V.accent,
318
+ color: "#fff",
319
+ display: "flex",
320
+ alignItems: "center",
321
+ justifyContent: "center",
322
+ fontFamily: V.hand,
323
+ fontSize: 28,
324
+ fontWeight: 700,
325
+ lineHeight: 1,
326
+ boxShadow: "0 4px 12px rgba(0,0,0,0.16)",
327
+ zIndex: 4,
328
+ }, children: icon }));
329
+ }
330
+ export function BrowserBar({ title = "todo", children, }) {
331
+ return (_jsxs("div", { "data-rough": "line:bottom", style: {
332
+ ["--rough-stroke"]: V.ink,
333
+ display: "flex",
334
+ alignItems: "center",
335
+ gap: 10,
336
+ padding: "9px 14px",
337
+ borderBottom: `${V.stroke} solid ${V.ink}`,
338
+ flex: "0 0 auto",
339
+ background: V.card,
340
+ }, children: [_jsx("div", { style: { display: "flex", gap: 6 }, children: [0, 1, 2].map((i) => (_jsx("span", { "data-rough": "ellipse", style: {
341
+ ["--rough-stroke"]: V.ink,
342
+ width: 11,
343
+ height: 11,
344
+ borderRadius: "50%",
345
+ border: `${V.stroke} solid ${V.ink}`,
346
+ } }, i))) }), _jsxs("div", { style: {
347
+ flex: 1,
348
+ border: `${V.stroke} solid ${V.soft}`,
349
+ borderRadius: 999,
350
+ padding: "3px 12px",
351
+ display: "flex",
352
+ alignItems: "center",
353
+ gap: 6,
354
+ }, children: [_jsx(Bar, { w: 12, h: 10, color: V.soft, r: 3 }), _jsxs(Hand, { size: "calc(var(--fs) * 0.82)", color: V.soft, children: [title, ".app"] })] }), children] }));
355
+ }
356
+ export function SectionLabel({ children, right, tone = "muted", }) {
357
+ return (_jsxs("div", { style: {
358
+ display: "flex",
359
+ alignItems: "baseline",
360
+ justifyContent: "space-between",
361
+ minWidth: 0,
362
+ gap: 8,
363
+ }, children: [_jsx(Hand, { size: "calc(var(--fs) * 0.9)", weight: 700, color: toneInk(tone), style: {
364
+ letterSpacing: 0.3,
365
+ minWidth: 0,
366
+ overflowWrap: "anywhere",
367
+ }, children: children }), right] }));
368
+ }
369
+ export function Avatar({ size = 26 }) {
370
+ return (_jsx("div", { "data-rough": "ellipse", style: {
371
+ ["--rough-stroke"]: V.ink,
372
+ width: size,
373
+ height: size,
374
+ borderRadius: "50%",
375
+ border: `${V.stroke} solid ${V.ink}`,
376
+ background: V.accentSoft,
377
+ flex: "0 0 auto",
378
+ } }));
379
+ }
380
+ export function IconSquare({ size = 18, active = false, }) {
381
+ return (_jsx("div", { "data-rough": "rect", style: {
382
+ ["--rough-stroke"]: active ? V.accent : V.soft,
383
+ width: size,
384
+ height: size,
385
+ flex: "0 0 auto",
386
+ borderRadius: "calc(var(--radius) * 0.5)",
387
+ border: `${V.stroke} solid ${active ? V.accent : V.soft}`,
388
+ display: "flex",
389
+ alignItems: "center",
390
+ justifyContent: "center",
391
+ }, children: _jsx("div", { style: {
392
+ width: "55%",
393
+ height: "55%",
394
+ borderRadius: 2,
395
+ background: active ? V.accent : V.line,
396
+ } }) }));
397
+ }
398
+ export function NavItem({ label, count, active = false, dot = false, tone = "accent", }) {
399
+ const dotColor = toneInk(tone);
400
+ return (_jsxs("div", { style: {
401
+ display: "flex",
402
+ alignItems: "center",
403
+ gap: 9,
404
+ padding: "5px 8px",
405
+ borderRadius: V.radius,
406
+ background: active ? V.accentSoft : "transparent",
407
+ minWidth: 0,
408
+ }, children: [dot ? (_jsx("span", { style: {
409
+ width: 10,
410
+ height: 10,
411
+ borderRadius: "50%",
412
+ border: `${V.stroke} solid ${dotColor}`,
413
+ background: dotColor,
414
+ flex: "0 0 auto",
415
+ } })) : (_jsx(IconSquare, { size: 15, active: active })), _jsx(Hand, { color: active ? V.accent : V.ink, weight: active ? 700 : 400, style: { flex: 1, minWidth: 0 }, children: label }), count != null && (_jsx(Hand, { size: "calc(var(--fs) * 0.82)", color: V.soft, children: count }))] }));
416
+ }
417
+ export function Sidebar({ children, width = 196, style = {}, }) {
418
+ return (_jsx("div", { "data-rough": "line:right", style: {
419
+ ["--rough-stroke"]: V.ink,
420
+ width,
421
+ flex: "0 0 auto",
422
+ borderRight: `${V.stroke} solid ${V.ink}`,
423
+ background: V.card,
424
+ padding: V.pad,
425
+ display: "flex",
426
+ flexDirection: "column",
427
+ gap: V.gap,
428
+ minHeight: 0,
429
+ minWidth: 0,
430
+ alignSelf: "stretch",
431
+ overflow: "hidden",
432
+ ...style,
433
+ }, children: children }));
434
+ }
435
+ export function Main({ children, style = {}, }) {
436
+ return (_jsx("div", { style: {
437
+ flex: 1,
438
+ minWidth: 0,
439
+ minHeight: 0,
440
+ padding: "18px 24px",
441
+ display: "flex",
442
+ flexDirection: "column",
443
+ gap: V.gap,
444
+ overflow: "hidden",
445
+ ...style,
446
+ }, children: children }));
447
+ }
448
+ export function Row({ children, full = false, style = {}, }) {
449
+ return (_jsx("div", { style: {
450
+ display: "flex",
451
+ flexDirection: "row",
452
+ alignItems: "stretch",
453
+ gap: V.gap,
454
+ minWidth: 0,
455
+ minHeight: 0,
456
+ maxWidth: "100%",
457
+ flex: full ? 1 : undefined,
458
+ ...style,
459
+ }, children: children }));
460
+ }
461
+ export function Col({ children, full = false, style = {}, }) {
462
+ return (_jsx("div", { style: {
463
+ display: "flex",
464
+ flexDirection: "column",
465
+ gap: V.gap,
466
+ minWidth: 0,
467
+ minHeight: 0,
468
+ flex: full ? 1 : undefined,
469
+ ...style,
470
+ }, children: children }));
471
+ }
472
+ export function TaskRow({ title, note, due, dueTone = "default", prio, done = false, }) {
473
+ return (_jsxs("div", { style: {
474
+ display: "flex",
475
+ alignItems: "flex-start",
476
+ gap: V.gap,
477
+ padding: "calc(var(--pad) * 0.55) 0",
478
+ minWidth: 0,
479
+ }, children: [_jsx("div", { style: { marginTop: 1 }, children: _jsx(Check, { done: done }) }), _jsxs("div", { style: {
480
+ flex: 1,
481
+ minWidth: 0,
482
+ display: "flex",
483
+ flexDirection: "column",
484
+ gap: 4,
485
+ }, children: [_jsx(Hand, { color: done ? V.soft : V.ink, style: done ? { textDecoration: "line-through" } : undefined, children: title }), note && (_jsx(Hand, { size: "calc(var(--fs) * 0.85)", color: V.soft, children: note }))] }), _jsxs("div", { style: {
486
+ display: "flex",
487
+ alignItems: "center",
488
+ flexWrap: "wrap",
489
+ justifyContent: "flex-end",
490
+ gap: 8,
491
+ flex: "0 0 auto",
492
+ }, children: [due && _jsx(Pill, { tone: dueTone, children: due }), prio ? _jsx(Prio, { level: prio }) : null] })] }));
493
+ }
494
+ export function Card({ children, style = {}, }) {
495
+ return (_jsx(Box, { pad: "calc(var(--pad) * 0.9)", style: {
496
+ display: "flex",
497
+ flexDirection: "column",
498
+ gap: 8,
499
+ background: V.card,
500
+ minWidth: 0,
501
+ maxWidth: "100%",
502
+ ...style,
503
+ }, children: children }));
504
+ }
505
+ export function Column({ title, count, tone = "muted", width = 232, children, }) {
506
+ return (_jsxs("div", { style: {
507
+ width,
508
+ flex: "0 0 auto",
509
+ display: "flex",
510
+ flexDirection: "column",
511
+ gap: V.gap,
512
+ }, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [_jsx("span", { style: {
513
+ width: 9,
514
+ height: 9,
515
+ borderRadius: "50%",
516
+ background: toneInk(tone),
517
+ flex: "0 0 auto",
518
+ } }), _jsx(Hand, { weight: 700, style: { whiteSpace: "nowrap" }, children: title }), count != null && (_jsx(Hand, { size: "calc(var(--fs) * 0.82)", color: V.soft, children: count })), _jsx("div", { style: { flex: 1 } }), _jsx(Hand, { color: V.soft, weight: 700, children: "+" })] }), children] }));
519
+ }
520
+ export function Toolbar({ children, style = {}, }) {
521
+ return (_jsx("div", { "data-rough": "line:bottom", style: {
522
+ ["--rough-stroke"]: V.ink,
523
+ display: "flex",
524
+ alignItems: "center",
525
+ justifyContent: "space-between",
526
+ gap: V.gap,
527
+ padding: "12px 22px",
528
+ borderBottom: `${V.stroke} solid ${V.ink}`,
529
+ background: V.card,
530
+ flex: "0 0 auto",
531
+ minWidth: 0,
532
+ flexWrap: "wrap",
533
+ ...style,
534
+ }, children: children }));
535
+ }
536
+ export function Tabs({ items = [], }) {
537
+ return (_jsx("div", { style: { display: "flex", gap: 7, flexWrap: "wrap" }, children: items.map((item, i) => (_jsx(Chip, { active: item.active, children: item.label }, i))) }));
538
+ }
539
+ export function KV({ rows = [] }) {
540
+ return (_jsx("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: rows.map((row, i) => (_jsxs("div", { style: {
541
+ display: "flex",
542
+ alignItems: "baseline",
543
+ justifyContent: "space-between",
544
+ gap: 12,
545
+ }, children: [_jsx(Hand, { size: "calc(var(--fs) * 0.88)", color: V.soft, children: row.k }), _jsx(Hand, { style: { textAlign: "right", minWidth: 0, wordBreak: "break-word" }, children: row.v })] }, i))) }));
546
+ }
547
+ export function SearchBar({ placeholder = "Search", }) {
548
+ return (_jsxs("div", { style: {
549
+ display: "flex",
550
+ alignItems: "center",
551
+ gap: 6,
552
+ border: `${V.stroke} solid ${V.soft}`,
553
+ borderRadius: 999,
554
+ padding: "5px 11px",
555
+ background: V.card,
556
+ }, children: [_jsx(Bar, { w: 11, h: 11, color: V.soft, r: 3 }), _jsx(Hand, { size: "calc(var(--fs) * 0.85)", color: V.soft, children: placeholder })] }));
557
+ }
558
+ export function Divider({ style = {} }) {
559
+ return (_jsx("div", { style: {
560
+ height: V.stroke,
561
+ background: V.line,
562
+ flex: "0 0 auto",
563
+ margin: "3px 0",
564
+ ...style,
565
+ } }));
566
+ }
567
+ export function Title({ text, script = false, size = "calc(var(--fs) * 2)", color = V.ink, }) {
568
+ return (_jsx(Hand, { script: script, size: size, weight: 700, color: color, children: text }));
569
+ }
570
+ export function Text({ value, color, weight, script = false, }) {
571
+ return (_jsx(Hand, { color: toneInk(color), weight: fontWeight(weight), script: script, children: value }));
572
+ }
573
+ const REGISTRY = {
574
+ // --- Frame / structure -------------------------------------------------
575
+ screen: (n) => {
576
+ const kids = n.children ?? [];
577
+ const lead = kids[0]?.el;
578
+ if (lead === "browserBar") {
579
+ return (_jsxs(Screen, { pad: 0, children: [renderNode(kids[0], kids[0].id ?? "browserbar"), renderScreenBodyNodes(kids.slice(1))] }));
580
+ }
581
+ if (lead === "statusBar") {
582
+ return (_jsxs(Screen, { pad: 0, children: [renderNode(kids[0], kids[0].id ?? "statusbar"), _jsx("div", { style: {
583
+ flex: 1,
584
+ minHeight: 0,
585
+ display: "flex",
586
+ flexDirection: "column",
587
+ gap: "var(--gap)",
588
+ padding: "calc(var(--pad) * 1.1)",
589
+ }, children: renderScreenBodyNodes(kids.slice(1)) })] }));
590
+ }
591
+ return (_jsx(Screen, { pad: "calc(var(--pad) * 1.35)", children: renderScreenBodyNodes(kids) }));
592
+ },
593
+ browserBar: (n, children) => (_jsx(BrowserBar, { title: n.title ?? n.text, children: children })),
594
+ statusBar: () => _jsx(StatusBar, {}),
595
+ toolbar: (_n, children) => _jsx(Toolbar, { children: children }),
596
+ row: (n, children) => _jsx(Row, { full: n.full, children: children }),
597
+ col: (n, children) => _jsx(Col, { full: n.full, children: children }),
598
+ sidebar: (_n, children) => _jsx(Sidebar, { children: children }),
599
+ main: (_n, children) => _jsx(Main, { children: children }),
600
+ box: (n, children) => _jsx(Box, { dashed: n.dashed, children: children }),
601
+ card: (_n, children) => _jsx(Card, { children: children }),
602
+ column: (n, children) => (_jsx(Column, { title: n.title ?? n.text, count: n.count, tone: n.tone, children: children })),
603
+ divider: () => _jsx(Divider, {}),
604
+ // --- Text --------------------------------------------------------------
605
+ title: (n) => _jsx(Title, { text: n.text, script: n.script }),
606
+ text: (n) => (_jsx(Text, { value: n.value ?? n.text, color: n.color, weight: n.weight, script: n.script })),
607
+ lines: (n) => _jsx(Lines, { n: n.n, widths: n.widths }),
608
+ section: (n) => (_jsx(SectionLabel, { tone: n.tone, children: n.label ?? n.text })),
609
+ // --- List / task -------------------------------------------------------
610
+ navItem: (n) => (_jsx(NavItem, { label: n.label ?? n.text, count: n.count, active: n.active, dot: n.dot, tone: n.tone })),
611
+ taskRow: (n) => (_jsx(TaskRow, { title: n.title ?? n.text, note: n.note, due: n.due, dueTone: n.dueTone, prio: n.prio, done: n.done })),
612
+ // --- Controls ----------------------------------------------------------
613
+ chips: (n) => _jsx(Tabs, { items: n.items ?? [] }),
614
+ chip: (n) => _jsx(Chip, { active: n.active, children: n.label ?? n.text }),
615
+ pill: (n) => _jsx(Pill, { tone: n.tone, children: n.label ?? n.text }),
616
+ check: (n) => _jsx(Check, { done: n.done, shape: n.shape }),
617
+ field: (n) => (_jsx(Field, { label: n.label, value: n.value, placeholder: n.placeholder, area: n.area })),
618
+ btn: (n) => (_jsx(Btn, { solid: n.solid, full: n.full, tone: n.tone, children: n.label ?? n.text })),
619
+ fab: (n) => _jsx(Fab, { icon: n.icon }),
620
+ searchBar: (n) => _jsx(SearchBar, { placeholder: n.placeholder }),
621
+ // --- Atoms -------------------------------------------------------------
622
+ avatar: () => _jsx(Avatar, {}),
623
+ iconSquare: (n) => _jsx(IconSquare, { active: n.active }),
624
+ kv: (n) => _jsx(KV, { rows: n.rows ?? [] }),
625
+ };
626
+ function renderScreenBodyNode(node, key) {
627
+ const shouldFill = node.full !== false &&
628
+ (node.el === "row" || node.el === "col" || node.el === "main");
629
+ return renderNode(shouldFill ? { ...node, full: true } : node, key);
630
+ }
631
+ function renderScreenBodyNodes(nodes) {
632
+ return nodes.map((node, i) => renderScreenBodyNode(node, node.id ?? `screen-body-${i}`));
633
+ }
634
+ /** Render a single kit-tree node (and its children, recursively). */
635
+ export function renderNode(node, key) {
636
+ const renderer = REGISTRY[node.el];
637
+ const children = node.children?.length ? renderNodes(node.children) : null;
638
+ if (!renderer) {
639
+ return children ? _jsx("div", { children: children }, key) : null;
640
+ }
641
+ const rendered = renderer(node, children);
642
+ return _jsx(KeyedNode, { children: rendered }, key ?? node.id);
643
+ }
644
+ /** Render an array of nodes. */
645
+ export function renderNodes(nodes) {
646
+ return nodes.map((node, i) => renderNode(node, node.id ?? i));
647
+ }
648
+ /** Lightweight keyed wrapper that does not introduce extra DOM. */
649
+ function KeyedNode({ children }) {
650
+ return _jsx(_Fragment, { children: children });
651
+ }
652
+ /** Whether an `el` name has a registered renderer. */
653
+ export function hasRenderer(el) {
654
+ return el in REGISTRY;
655
+ }
656
+ export { REGISTRY as NODE_REGISTRY, V as WFV, toneColors, toneInk, fontWeight };
657
+ /* ========================================================================== */
658
+ /* Rough overlay (ported from kit/rough.tsx) */
659
+ /* ========================================================================== */
660
+ const gen = rough.generator();
661
+ /** The default selector used for HTML mockups: bordered/box-like elements. */
662
+ export const HTML_ROUGH_SELECTOR = "[data-rough],button,input,textarea,select,.wf-card,.wf-box,hr,.wf-frame-target";
663
+ /** Stable per-element seed so a frame doesn't re-wobble on every measure. */
664
+ function seedFrom(...parts) {
665
+ const value = parts.join(":");
666
+ let hash = 2166136261;
667
+ for (let i = 0; i < value.length; i++) {
668
+ hash ^= value.charCodeAt(i);
669
+ hash = Math.imul(hash, 16777619);
670
+ }
671
+ return ((hash >>> 0) % 2147483646) + 1;
672
+ }
673
+ /** Map the 0–100 sketch slider to a rough.js roughness (calm + legible). */
674
+ export function sketchRoughness(sketch) {
675
+ const s = Math.max(0, Math.min(100, Number.isFinite(sketch) ? sketch : 0));
676
+ return Number((0.32 + (s / 100) * 1.15).toFixed(2));
677
+ }
678
+ function sketchBowing(sketch) {
679
+ const s = Math.max(0, Math.min(100, Number.isFinite(sketch) ? sketch : 0));
680
+ return Number((0.4 + (s / 100) * 0.5).toFixed(2));
681
+ }
682
+ function readVar(el, name) {
683
+ return getComputedStyle(el).getPropertyValue(name).trim();
684
+ }
685
+ /** Normalize a CSS color (hex or rgb[a]) to "r,g,b" for equality comparison. */
686
+ function toRgbKey(color) {
687
+ const c = color.trim();
688
+ const hex = c.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
689
+ if (hex) {
690
+ const h = hex[1];
691
+ const full = h.length === 3
692
+ ? h
693
+ .split("")
694
+ .map((d) => d + d)
695
+ .join("")
696
+ : h;
697
+ const n = parseInt(full, 16);
698
+ return `${(n >> 16) & 255},${(n >> 8) & 255},${n & 255}`;
699
+ }
700
+ const rgb = c.match(/rgba?\(([^)]+)\)/i);
701
+ if (rgb) {
702
+ const [r, g, b] = rgb[1].split(",").map((v) => parseInt(v.trim(), 10));
703
+ return `${r},${g},${b}`;
704
+ }
705
+ return null;
706
+ }
707
+ /** True when two CSS colors resolve to the same RGB (hex vs rgb tolerant). */
708
+ function sameColor(a, b) {
709
+ const ka = toRgbKey(a);
710
+ const kb = toRgbKey(b);
711
+ return ka !== null && ka === kb;
712
+ }
713
+ /** A rounded-rect SVG path (so the frame stroke follows the artboard radius). */
714
+ function roundedRectPath(x, y, w, h, r) {
715
+ const rad = Math.max(0, Math.min(r, w / 2, h / 2));
716
+ return [
717
+ `M${x + rad},${y}`,
718
+ `H${x + w - rad}`,
719
+ `A${rad},${rad} 0 0 1 ${x + w},${y + rad}`,
720
+ `V${y + h - rad}`,
721
+ `A${rad},${rad} 0 0 1 ${x + w - rad},${y + h}`,
722
+ `H${x + rad}`,
723
+ `A${rad},${rad} 0 0 1 ${x},${y + h - rad}`,
724
+ `V${y + rad}`,
725
+ `A${rad},${rad} 0 0 1 ${x + rad},${y}`,
726
+ "Z",
727
+ ].join(" ");
728
+ }
729
+ function elementStroke(node, fallback) {
730
+ const explicit = readVar(node, "--rough-stroke");
731
+ if (explicit)
732
+ return explicit;
733
+ const cs = getComputedStyle(node);
734
+ for (const side of [
735
+ "borderTopColor",
736
+ "borderLeftColor",
737
+ "borderBottomColor",
738
+ "borderRightColor",
739
+ ]) {
740
+ const width = parseFloat(cs.getPropertyValue(side.replace("Color", "Width")));
741
+ const color = cs[side];
742
+ if (width > 0 && color && color !== "rgba(0, 0, 0, 0)")
743
+ return color;
744
+ }
745
+ return fallback;
746
+ }
747
+ function build(scope, opts) {
748
+ const base = scope.getBoundingClientRect();
749
+ const layoutW = scope.offsetWidth;
750
+ const layoutH = scope.offsetHeight;
751
+ if (!layoutW || !layoutH)
752
+ return { paths: [], w: 0, h: 0 };
753
+ const zoom = base.width / layoutW || 1;
754
+ const themed = (scope.matches(".plan-wf, .plan-html-frame, .plan-diagram-frame")
755
+ ? scope
756
+ : scope.querySelector(".plan-wf, .plan-html-frame, .plan-diagram-frame")) ?? scope;
757
+ const ink = readVar(themed, "--ink") || readVar(themed, "--wf-ink") || "#34322e";
758
+ const sketch = readVar(themed, "--wf-sketch") || ink;
759
+ const line = readVar(themed, "--wf-line") || readVar(themed, "--line") || "";
760
+ const paths = [];
761
+ let index = 0;
762
+ const push = (drawable, stroke, sw) => {
763
+ for (const p of gen.toPaths(drawable)) {
764
+ paths.push({
765
+ d: p.d,
766
+ stroke: p.stroke && p.stroke !== "none" ? p.stroke : stroke,
767
+ strokeWidth: p.strokeWidth || sw,
768
+ });
769
+ }
770
+ };
771
+ const makeOpts = (stroke, sw, seed) => ({
772
+ seed,
773
+ roughness: opts.roughness,
774
+ bowing: opts.bowing,
775
+ stroke,
776
+ strokeWidth: sw,
777
+ preserveVertices: true,
778
+ });
779
+ if (opts.drawFrame) {
780
+ const sw = 2;
781
+ push(gen.path(roundedRectPath(2, 2, layoutW - 4, layoutH - 4, opts.frameRadius), {
782
+ ...makeOpts(sketch, sw, seedFrom("frame", layoutW, layoutH)),
783
+ roughness: opts.roughness + 0.35,
784
+ bowing: opts.bowing + 0.18,
785
+ }), sketch, sw);
786
+ }
787
+ scope.querySelectorAll(opts.selector).forEach((node) => {
788
+ const r = node.getBoundingClientRect();
789
+ const x = (r.left - base.left) / zoom;
790
+ const y = (r.top - base.top) / zoom;
791
+ const w = r.width / zoom;
792
+ const h = r.height / zoom;
793
+ if (w < 2 || h < 2)
794
+ return;
795
+ const kind = node.getAttribute("data-rough") || "rect";
796
+ const rawStroke = elementStroke(node, sketch);
797
+ const stroke = sameColor(rawStroke, ink) || (line !== "" && sameColor(rawStroke, line))
798
+ ? sketch
799
+ : rawStroke;
800
+ const sw = Number(readVar(node, "--rough-w")) || 1.4;
801
+ const seed = seedFrom(kind, Math.round(x), Math.round(y), Math.round(w), Math.round(h), index++);
802
+ const o = makeOpts(stroke, sw, seed);
803
+ let drawable;
804
+ if (kind === "ellipse") {
805
+ drawable = gen.ellipse(x + w / 2, y + h / 2, w, h, o);
806
+ }
807
+ else if (kind === "line:right") {
808
+ drawable = gen.line(x + w, y, x + w, y + h, o);
809
+ }
810
+ else if (kind === "line:bottom") {
811
+ drawable = gen.line(x, y + h, x + w, y + h, o);
812
+ }
813
+ else if (kind === "line:top" || node.tagName === "HR") {
814
+ drawable = gen.line(x, y + h / 2, x + w, y + h / 2, o);
815
+ }
816
+ else {
817
+ const cr = parseFloat(getComputedStyle(node).borderTopLeftRadius) || 0;
818
+ const radius = Math.min(cr / zoom, w / 2, h / 2);
819
+ drawable =
820
+ radius > 1
821
+ ? gen.path(roundedRectPath(x + 1, y + 1, w - 2, h - 2, radius), o)
822
+ : gen.rectangle(x + 1, y + 1, w - 2, h - 2, o);
823
+ }
824
+ push(drawable, stroke, sw);
825
+ });
826
+ return { paths, w: layoutW, h: layoutH };
827
+ }
828
+ /**
829
+ * Renders the rough overlay for a frame. `scopeRef` points at the frame root.
830
+ * When `enabled` is false (skeleton / clean register) it renders nothing and the
831
+ * crisp CSS borders stay visible.
832
+ */
833
+ export function RoughOverlay({ scopeRef, sketch = 52, enabled = true, drawFrame = true, frameRadius = 14, selector = "[data-rough]", }) {
834
+ const [state, setState] = useState({ paths: [], w: 0, h: 0 });
835
+ const rafRef = useRef(0);
836
+ useEffect(() => {
837
+ const el = scopeRef.current;
838
+ if (!el || !enabled) {
839
+ el?.removeAttribute("data-rough-ready");
840
+ el?.querySelector(".plan-wf, .plan-html-frame, .plan-diagram-frame")?.removeAttribute("data-rough-ready");
841
+ setState({ paths: [], w: 0, h: 0 });
842
+ return;
843
+ }
844
+ const roughness = sketchRoughness(sketch);
845
+ const bowing = sketchBowing(sketch);
846
+ const measure = () => {
847
+ clearTimeout(rafRef.current);
848
+ rafRef.current = window.setTimeout(() => {
849
+ const next = build(el, {
850
+ roughness,
851
+ bowing,
852
+ frameRadius,
853
+ drawFrame,
854
+ selector,
855
+ });
856
+ if (next.w && next.h) {
857
+ el.setAttribute("data-rough-ready", "true");
858
+ (el.querySelector(".plan-wf, .plan-html-frame, .plan-diagram-frame") ?? el).setAttribute("data-rough-ready", "true");
859
+ setState(next);
860
+ }
861
+ }, 0);
862
+ };
863
+ measure();
864
+ const ro = new ResizeObserver(measure);
865
+ ro.observe(el);
866
+ el.querySelectorAll(selector).forEach((node) => ro.observe(node));
867
+ const mo = new MutationObserver((mutations) => {
868
+ if (mutations.every(isRoughOverlayMutation))
869
+ return;
870
+ measure();
871
+ });
872
+ mo.observe(el, {
873
+ attributes: true,
874
+ childList: true,
875
+ characterData: true,
876
+ subtree: true,
877
+ });
878
+ el.addEventListener("plan-prototype-runtime:rendered", measure);
879
+ let cancelled = false;
880
+ if (typeof document !== "undefined" && "fonts" in document) {
881
+ void document.fonts.ready.then(() => {
882
+ if (!cancelled)
883
+ measure();
884
+ });
885
+ }
886
+ return () => {
887
+ cancelled = true;
888
+ ro.disconnect();
889
+ mo.disconnect();
890
+ el.removeEventListener("plan-prototype-runtime:rendered", measure);
891
+ clearTimeout(rafRef.current);
892
+ el.removeAttribute("data-rough-ready");
893
+ el.querySelector(".plan-wf, .plan-html-frame, .plan-diagram-frame")?.removeAttribute("data-rough-ready");
894
+ };
895
+ }, [scopeRef, sketch, enabled, drawFrame, frameRadius, selector]);
896
+ if (!enabled || !state.paths.length)
897
+ return null;
898
+ return (_jsx("svg", { "aria-hidden": true, className: "plan-rough-overlay", width: "100%", height: "100%", viewBox: `0 0 ${state.w} ${state.h}`, preserveAspectRatio: "none", style: {
899
+ position: "absolute",
900
+ inset: 0,
901
+ pointerEvents: "none",
902
+ overflow: "hidden",
903
+ zIndex: 3,
904
+ }, children: state.paths.map((p, i) => (_jsx("path", { d: p.d, fill: "none", stroke: p.stroke, strokeWidth: p.strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }, i))) }));
905
+ }
906
+ function isRoughOverlayMutation(mutation) {
907
+ if (nodeIsRoughOverlay(mutation.target))
908
+ return true;
909
+ const changedNodes = [
910
+ ...Array.from(mutation.addedNodes),
911
+ ...Array.from(mutation.removedNodes),
912
+ ];
913
+ return changedNodes.length > 0 && changedNodes.every(nodeIsRoughOverlay);
914
+ }
915
+ function nodeIsRoughOverlay(node) {
916
+ const element = node instanceof Element ? node : node.parentElement;
917
+ return Boolean(element?.classList.contains("plan-rough-overlay") ||
918
+ element?.closest(".plan-rough-overlay"));
919
+ }
920
+ //# sourceMappingURL=wireframe-kit.js.map