@heyramzi/ui 2.1.0 → 2.2.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 (312) hide show
  1. package/package.json +7 -8
  2. package/scripts/sync-shadcn.mjs +3 -4
  3. package/src/agents/agent-avatar.svelte +604 -575
  4. package/src/agents/agent-cast.svelte +179 -183
  5. package/src/agents/demo.svelte +125 -113
  6. package/src/agents/helpers.ts +23 -17
  7. package/src/agents/index.ts +4 -4
  8. package/src/agents/page-state.ts +6 -6
  9. package/src/agents/types.ts +6 -6
  10. package/src/ai/ai-button/AiButton.svelte +4 -12
  11. package/src/ai/generation-progress/GenerationProgress.svelte +10 -3
  12. package/src/ai/prompt-input/PromptInputTextarea.svelte +1 -2
  13. package/src/ai/response/Response.css +2 -3
  14. package/src/animations/avatar-group-hover.css +2 -16
  15. package/src/animations/card-tilt.css +3 -6
  16. package/src/animations/digit-pop-in.css +2 -15
  17. package/src/animations/dropdown.css +4 -17
  18. package/src/animations/input-clear-dissolve.css +5 -18
  19. package/src/animations/input-shake.css +9 -41
  20. package/src/animations/learn-more-hover.css +17 -9
  21. package/src/animations/like-button.css +2 -4
  22. package/src/animations/page-side-by-side.css +2 -10
  23. package/src/animations/plus-menu-morph.css +2 -5
  24. package/src/animations/shimmer-text.css +5 -18
  25. package/src/animations/spinning-counter.css +2 -6
  26. package/src/animations/success-check.css +2 -15
  27. package/src/animations/thinking-states.css +2 -7
  28. package/src/brand/brand.test.ts +21 -5
  29. package/src/brand/index.ts +4 -10
  30. package/src/canvas/card/card-frame.svelte +43 -39
  31. package/src/canvas/card/resize-handles.svelte +89 -80
  32. package/src/canvas/chrome/chrome-zoom.svelte +101 -100
  33. package/src/canvas/chrome/lock-badge.svelte +8 -8
  34. package/src/canvas/chrome/side-handles.svelte +24 -19
  35. package/src/canvas/chrome/size-chip.svelte +30 -30
  36. package/src/canvas/chrome/snap-guides.svelte +20 -20
  37. package/src/canvas/components/icons/ToolIcon.svelte +8 -8
  38. package/src/canvas/components/shared/svg/PreviewSvg.svelte +19 -19
  39. package/src/canvas/components/shared/svg/ShapeOutline.svelte +71 -48
  40. package/src/canvas/components/shared/svg/StrokeNode.svelte +21 -27
  41. package/src/canvas/components/shared/svg/TextRule.svelte +25 -17
  42. package/src/canvas/edges/bend-handle.svelte +46 -46
  43. package/src/canvas/edges/edge-gradient.svelte +10 -10
  44. package/src/canvas/edges/gradient-edge.svelte +45 -29
  45. package/src/canvas/editor/lock.test.ts +6 -1
  46. package/src/canvas/editor/style.ts +7 -1
  47. package/src/canvas/headless/svg-figure.test.ts +5 -1
  48. package/src/canvas/lod/lod-switch.svelte +111 -106
  49. package/src/canvas/pen/PenField.svelte +87 -81
  50. package/src/canvas/pen/PenOverlay.svelte +127 -127
  51. package/src/canvas/pen/ShapeNode.svelte +31 -32
  52. package/src/canvas/pen/TextNode.svelte +54 -53
  53. package/src/canvas/pen/host-field.test.svelte +7 -7
  54. package/src/canvas/pen/shapes.ts +7 -1
  55. package/src/canvas/screen/GlyphIcon.svelte +22 -17
  56. package/src/canvas/screen/PartView.svelte +138 -72
  57. package/src/canvas/screen/ScreenBody.svelte +81 -60
  58. package/src/canvas/screen/ScreenCard.svelte +20 -20
  59. package/src/canvas/ui/CanvasToolbar.svelte +173 -85
  60. package/src/canvas/ui/FrameLayer.svelte +59 -59
  61. package/src/canvas/ui/PenLayer.svelte +39 -30
  62. package/src/canvas/ui/StylePanel.svelte +119 -102
  63. package/src/canvas/ui/canvas-grid.svelte +137 -129
  64. package/src/charts/animated-value.svelte +1 -1
  65. package/src/charts/area-chart.css +2 -5
  66. package/src/charts/area-chart.svelte +1 -1
  67. package/src/charts/bar-chart.css +2 -3
  68. package/src/charts/bar-chart.svelte +1 -1
  69. package/src/charts/charts.css +5 -17
  70. package/src/charts/crosshair.svelte +1 -1
  71. package/src/charts/dashboard/dashboard-empty.svelte +25 -25
  72. package/src/charts/dashboard/dashboard-section.svelte +24 -24
  73. package/src/charts/dashboard/data-panel.svelte +50 -50
  74. package/src/charts/dashboard/data-sort-head.svelte +56 -56
  75. package/src/charts/dashboard/data-table.svelte +138 -138
  76. package/src/charts/dashboard/panel-grid.svelte +30 -30
  77. package/src/charts/dashboard/period-filter.svelte +25 -25
  78. package/src/charts/dashboard/rating-chip.svelte +19 -19
  79. package/src/charts/dashboard/stat-band.svelte +32 -32
  80. package/src/charts/dashboard/stat-tile.svelte +106 -99
  81. package/src/charts/donut-chart.svelte +1 -1
  82. package/src/charts/edge-fade.svelte +1 -1
  83. package/src/charts/figure.svelte +1 -1
  84. package/src/charts/gauge-chart.css +4 -7
  85. package/src/charts/gauge-chart.svelte +1 -1
  86. package/src/charts/hover-focus.svelte +1 -1
  87. package/src/charts/legend.css +1 -3
  88. package/src/charts/legend.svelte +1 -1
  89. package/src/charts/line-chart.svelte +1 -1
  90. package/src/charts/number-chart.css +6 -9
  91. package/src/charts/number-chart.svelte +1 -1
  92. package/src/charts/reference-line.svelte +19 -19
  93. package/src/charts/reveal.svelte +1 -1
  94. package/src/charts/ring-chart.css +2 -4
  95. package/src/charts/ring-chart.svelte +1 -1
  96. package/src/charts/sparkline.svelte +5 -2
  97. package/src/charts/stat-card.svelte +1 -1
  98. package/src/charts/time-series-chart.css +2 -5
  99. package/src/charts/trend-pill.css +2 -4
  100. package/src/charts/trend-pill.svelte +1 -1
  101. package/src/components/copy/copy-button.svelte +93 -98
  102. package/src/components/copy/copy-button.test.ts +10 -2
  103. package/src/components/data-table/infinite-scroll.svelte +42 -42
  104. package/src/components/data-table/pagination.svelte +34 -22
  105. package/src/components/data-table/row-arrow.svelte +19 -16
  106. package/src/components/data-table/row-context-menu.svelte +52 -52
  107. package/src/components/data-table/sortable-head.svelte +25 -25
  108. package/src/components/data-table/table-skeleton.svelte +41 -36
  109. package/src/components/docs/doc-page.svelte +18 -9
  110. package/src/components/docs/on-this-page.svelte +16 -3
  111. package/src/components/docs/scroll-spy.svelte.ts +2 -3
  112. package/src/components/field-row/field-row.svelte +10 -8
  113. package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
  114. package/src/components/icon/icon.svelte +14 -14
  115. package/src/components/language-flag/language-flag.svelte +3 -1
  116. package/src/components/list-page/detail-empty.svelte +34 -34
  117. package/src/components/list-page/detail-header.svelte +55 -47
  118. package/src/components/list-page/detail-panel.svelte +51 -59
  119. package/src/components/list-page/detail-row.svelte +19 -19
  120. package/src/components/list-page/detail-stack.svelte +21 -21
  121. package/src/components/list-page/empty-state.svelte +30 -30
  122. package/src/components/list-page/filter-item.svelte +20 -20
  123. package/src/components/list-page/filter-popover.svelte +60 -55
  124. package/src/components/list-page/grouped-list.svelte +4 -2
  125. package/src/components/list-page/index.ts +5 -1
  126. package/src/components/list-page/list-page-shell.svelte +2 -5
  127. package/src/components/list-page/master-detail.svelte +87 -88
  128. package/src/components/list-page/notice-bar.svelte +38 -38
  129. package/src/components/list-page/prev-next.svelte +63 -63
  130. package/src/components/list-page/rail-body.svelte +18 -18
  131. package/src/components/list-page/rail-empty.svelte +23 -30
  132. package/src/components/list-page/rail-head.svelte +24 -24
  133. package/src/components/list-page/rail-row.svelte +77 -73
  134. package/src/components/list-page/section-host.ts +2 -3
  135. package/src/components/locale-switch/locale-switch.svelte +41 -41
  136. package/src/components/mark/mark.svelte +34 -38
  137. package/src/components/open-in/index.ts +1 -5
  138. package/src/components/open-in/open-in.svelte +40 -40
  139. package/src/components/picker/mark-picker.svelte +49 -49
  140. package/src/components/picker/picker.svelte +5 -3
  141. package/src/components/section-header/section-header.test.ts +7 -1
  142. package/src/components/section-header/section-label.svelte +20 -20
  143. package/src/components/segmented/animated-tabs.svelte +31 -2
  144. package/src/components/segmented/collapse.test.ts +2 -1
  145. package/src/components/segmented/index.ts +2 -0
  146. package/src/components/segmented/segment.svelte +52 -49
  147. package/src/components/segmented/segmented-filter.svelte +79 -80
  148. package/src/components/segmented/segmented-nav.svelte +34 -40
  149. package/src/components/segmented/segmented-overflow.svelte +53 -50
  150. package/src/components/segmented/segmented-track.svelte +62 -46
  151. package/src/components/segmented/segmented.ts +2 -3
  152. package/src/components/star-rating-input/star-rating-input.svelte +103 -103
  153. package/src/components/svg/svg.svelte +4 -4
  154. package/src/components/table-view/table-view.svelte +17 -2
  155. package/src/components/table-view/table-view.test.ts +7 -1
  156. package/src/components/table-view/types.ts +11 -11
  157. package/src/components/tags-input/index.ts +13 -0
  158. package/src/components/tags-input/tags-input.svelte +305 -0
  159. package/src/components/tags-input/tags.test.ts +64 -0
  160. package/src/components/tags-input/tags.ts +142 -0
  161. package/src/components/theme/index.ts +2 -4
  162. package/src/components/theme/theme-provider.svelte +1 -3
  163. package/src/components/toolbar/toolbar-search.svelte +25 -25
  164. package/src/components/toolbar/toolbar.svelte +11 -7
  165. package/src/components/toolbar/toolbar.test.ts +10 -1
  166. package/src/design/index.css +21 -78
  167. package/src/design/polish.css +26 -35
  168. package/src/editor/editor-toolbar.svelte +104 -99
  169. package/src/editor/editor.svelte +296 -266
  170. package/src/editor/image-toolbar.svelte +20 -22
  171. package/src/editor/index.ts +1 -4
  172. package/src/editor/inline-editor.svelte +280 -238
  173. package/src/editor/markdown.ts +15 -15
  174. package/src/editor/renderer.svelte +71 -71
  175. package/src/editor/slash-menu.svelte +24 -27
  176. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +1 -1
  177. package/src/effects/image-comparison/ImageComparison.svelte +11 -1
  178. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +59 -46
  179. package/src/effects/magic-card/MagicCard.css +14 -7
  180. package/src/effects/marquee/Marquee.svelte +3 -5
  181. package/src/effects/reveal/observe.ts +0 -3
  182. package/src/effects/spotlight/Spotlight.svelte +1 -1
  183. package/src/effects/theme-toggle/ThemeToggle.css +25 -22
  184. package/src/effects/theme-toggle/ThemeToggle.svelte +6 -7
  185. package/src/gallery.test.ts +14 -4
  186. package/src/inbox/README.md +1 -3
  187. package/src/inbox/inbox.test.ts +181 -138
  188. package/src/inbox/index.ts +20 -20
  189. package/src/inbox/logic.ts +114 -111
  190. package/src/inbox/thread-inbox.svelte +227 -151
  191. package/src/inbox/types.ts +130 -108
  192. package/src/lib/theme-transition.ts +2 -4
  193. package/src/lib/tone.ts +2 -4
  194. package/src/lib/utils.ts +2 -2
  195. package/src/modules.test.ts +79 -69
  196. package/src/onboarding/define-tours.test.ts +55 -40
  197. package/src/onboarding/define-tours.ts +23 -23
  198. package/src/onboarding/demo.svelte +24 -5
  199. package/src/onboarding/index.ts +1 -8
  200. package/src/onboarding/onboarding-provider.svelte +19 -7
  201. package/src/onboarding/onboarding.svelte.ts +16 -16
  202. package/src/onboarding/pick.test.ts +61 -52
  203. package/src/onboarding/pick.ts +16 -13
  204. package/src/onboarding/stores.test.ts +80 -80
  205. package/src/onboarding/stores.ts +41 -39
  206. package/src/onboarding/tour-card.svelte +30 -5
  207. package/src/onboarding/tour-runner.svelte +12 -3
  208. package/src/onboarding/types.ts +20 -12
  209. package/src/onboarding/wait.ts +22 -22
  210. package/src/panel/side-panel.svelte +94 -93
  211. package/src/record/demo-data.ts +291 -225
  212. package/src/record/field-section.svelte +38 -34
  213. package/src/record/fields.ts +148 -96
  214. package/src/record/format.ts +63 -56
  215. package/src/record/index.ts +49 -35
  216. package/src/record/info-list.svelte +145 -114
  217. package/src/record/kinds.ts +31 -31
  218. package/src/record/logic.ts +216 -214
  219. package/src/record/next-up.svelte +45 -34
  220. package/src/record/project-list.svelte +56 -50
  221. package/src/record/record-demo.svelte +130 -110
  222. package/src/record/record-header.svelte +37 -28
  223. package/src/record/record-shell.svelte +54 -54
  224. package/src/record/record-stats.svelte +25 -25
  225. package/src/record/record-timeline.svelte +134 -114
  226. package/src/record/record.test.ts +430 -309
  227. package/src/record/steps-rail.svelte +225 -216
  228. package/src/record/types.ts +234 -215
  229. package/src/record/where-we-are.svelte +62 -58
  230. package/src/shadcn/button/button.svelte +1 -1
  231. package/src/shadcn/card/card-title.svelte +1 -5
  232. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
  233. package/src/shadcn/sheet/sheet-content.svelte +2 -4
  234. package/src/shadcn/table/table-cell.svelte +2 -3
  235. package/src/shadcn/utilities.css +3 -8
  236. package/src/slides/Controls.svelte +150 -124
  237. package/src/slides/Deck.svelte +243 -238
  238. package/src/slides/Fragment.svelte +64 -57
  239. package/src/slides/Overview.svelte +106 -101
  240. package/src/slides/Presenter.svelte +300 -266
  241. package/src/slides/Slide.svelte +185 -170
  242. package/src/slides/SlideList.svelte +16 -12
  243. package/src/slides/ambient.d.ts +1 -1
  244. package/src/slides/bridges.ts +42 -23
  245. package/src/slides/deck-controller.svelte.ts +47 -35
  246. package/src/slides/demo-slides.svelte +330 -306
  247. package/src/slides/demo.svelte +164 -160
  248. package/src/slides/export/capture.ts +20 -16
  249. package/src/slides/export/ffmpeg.ts +43 -38
  250. package/src/slides/export/index.ts +5 -5
  251. package/src/slides/export/launch.ts +3 -1
  252. package/src/slides/export/pdf.ts +30 -27
  253. package/src/slides/export/types.ts +10 -8
  254. package/src/slides/index.ts +11 -11
  255. package/src/slides/labels.ts +22 -19
  256. package/src/slides/layout.ts +9 -2
  257. package/src/slides/model.ts +4 -4
  258. package/src/slides/navigation.ts +43 -31
  259. package/src/slides/theme.css +5 -7
  260. package/src/slides/types.ts +9 -10
  261. package/src/status/define-statuses.ts +17 -24
  262. package/src/status/index.ts +5 -5
  263. package/src/status/status-badge.svelte +3 -1
  264. package/src/status/status-dot.svelte +1 -3
  265. package/src/status/status-icon.svelte +1 -1
  266. package/src/status/status-types.ts +21 -21
  267. package/src/tasks/board-order.ts +2 -4
  268. package/src/tasks/demo.svelte +189 -31
  269. package/src/tasks/detail/detail-demo.svelte +73 -13
  270. package/src/tasks/detail/detail-types.ts +45 -45
  271. package/src/tasks/detail/task-detail.svelte +40 -10
  272. package/src/tasks/detail/task-property.svelte +8 -2
  273. package/src/tasks/detail/task-thread.svelte +53 -12
  274. package/src/tasks/gantt/gantt-bar.svelte +17 -6
  275. package/src/tasks/gantt/gantt-grid.svelte +40 -9
  276. package/src/tasks/gantt/gantt-group-row.svelte +8 -2
  277. package/src/tasks/gantt/gantt-header.svelte +9 -3
  278. package/src/tasks/gantt/gantt-task-row.svelte +26 -6
  279. package/src/tasks/gantt/gantt.css +2 -1
  280. package/src/tasks/gantt/gantt.test.ts +3 -1
  281. package/src/tasks/gantt/logic.test.ts +110 -20
  282. package/src/tasks/gantt/logic.ts +42 -6
  283. package/src/tasks/inbox/inbox-card.svelte +13 -5
  284. package/src/tasks/inbox/inbox-draft.svelte +1 -1
  285. package/src/tasks/inbox/inbox-logic.ts +6 -40
  286. package/src/tasks/inbox/inbox-statuses.ts +23 -23
  287. package/src/tasks/inbox/inbox-trace.svelte +9 -3
  288. package/src/tasks/inbox/inbox-types.ts +54 -58
  289. package/src/tasks/inbox/index.ts +22 -21
  290. package/src/tasks/index.ts +49 -52
  291. package/src/tasks/kanban-board.svelte +16 -12
  292. package/src/tasks/kanban-types.ts +2 -3
  293. package/src/tasks/presets/sales.ts +6 -6
  294. package/src/tasks/task-gantt.svelte +28 -8
  295. package/src/tasks/task-list.svelte +41 -17
  296. package/src/tasks/time/duration.ts +40 -40
  297. package/src/tasks/time/time-chip.svelte +9 -2
  298. package/src/tasks/time/time-dot.svelte +1 -1
  299. package/src/tasks/time/time-ring.svelte +11 -3
  300. package/src/tasks/time/time-tracker.svelte +57 -15
  301. package/src/tasks/time/time-types.ts +57 -57
  302. package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
  303. package/src/thread/index.ts +7 -7
  304. package/src/thread/logic.ts +36 -33
  305. package/src/thread/thread.svelte +82 -16
  306. package/src/thread/thread.test.ts +58 -47
  307. package/src/thread/types.ts +68 -68
  308. package/src/tokens/craft.css +17 -53
  309. package/src/tokens/index.css +3 -13
  310. package/src/tokens/palette.css +13 -11
  311. package/src/tokens/primitives.css +10 -23
  312. package/src/tasks/inbox/inbox.svelte +0 -203
@@ -1,145 +1,145 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import "./pen.css";
6
- import PreviewSvg from "../components/shared/svg/PreviewSvg.svelte";
7
- import type { ErasableNode } from "./eraser.js";
8
- import type { PenOp } from "./ops.js";
9
- import { createPenSession, type PenPreview } from "./pen-session.js";
10
- import type { PenColor, PenTool } from "./types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import "./pen.css";
6
+ import PreviewSvg from "../components/shared/svg/PreviewSvg.svelte";
7
+ import type { ErasableNode } from "./eraser.js";
8
+ import type { PenOp } from "./ops.js";
9
+ import { createPenSession, type PenPreview } from "./pen-session.js";
10
+ import type { PenColor, PenTool } from "./types.js";
11
11
 
12
- // =========================
13
- // TYPES
14
- // =========================
15
- interface Props {
16
- tool: PenTool;
17
- color?: PenColor;
18
- /** Brush width in flow units. Unset takes the tool's default. */
19
- size?: number;
20
- /** The xyflow viewport, so screen pixels map to flow units. */
21
- viewport: { x: number; y: number; zoom: number };
22
- nodes: readonly ErasableNode[];
23
- commit: (ops: PenOp[]) => void;
24
- startGesture: () => () => void;
25
- onTextPlaced?: (nodeId: string) => void;
26
- }
12
+ // =========================
13
+ // TYPES
14
+ // =========================
15
+ interface Props {
16
+ tool: PenTool;
17
+ color?: PenColor;
18
+ /** Brush width in flow units. Unset takes the tool's default. */
19
+ size?: number;
20
+ /** The xyflow viewport, so screen pixels map to flow units. */
21
+ viewport: { x: number; y: number; zoom: number };
22
+ nodes: readonly ErasableNode[];
23
+ commit: (ops: PenOp[]) => void;
24
+ startGesture: () => () => void;
25
+ onTextPlaced?: (nodeId: string) => void;
26
+ }
27
27
 
28
- // =========================
29
- // PROPS
30
- // =========================
31
- let {
32
- tool,
33
- color = "ink",
34
- size,
35
- viewport,
36
- nodes,
37
- commit,
38
- startGesture,
39
- onTextPlaced,
40
- }: Props = $props();
28
+ // =========================
29
+ // PROPS
30
+ // =========================
31
+ let {
32
+ tool,
33
+ color = "ink",
34
+ size,
35
+ viewport,
36
+ nodes,
37
+ commit,
38
+ startGesture,
39
+ onTextPlaced,
40
+ }: Props = $props();
41
41
 
42
- // =========================
43
- // STATE
44
- // =========================
45
- let layer = $state<HTMLDivElement | null>(null);
46
- let preview = $state<PenPreview | null>(null);
47
- const session = createPenSession(
48
- {
49
- getNodes: () => nodes,
50
- commit: (ops) => commit(ops),
51
- startGesture: () => startGesture(),
52
- onTextPlaced: (id) => onTextPlaced?.(id),
53
- onPreview: (next) => {
54
- preview = next;
42
+ // =========================
43
+ // STATE
44
+ // =========================
45
+ let layer = $state<HTMLDivElement | null>(null);
46
+ let preview = $state<PenPreview | null>(null);
47
+ const session = createPenSession(
48
+ {
49
+ getNodes: () => nodes,
50
+ commit: (ops) => commit(ops),
51
+ startGesture: () => startGesture(),
52
+ onTextPlaced: (id) => onTextPlaced?.(id),
53
+ onPreview: (next) => {
54
+ preview = next;
55
+ },
55
56
  },
56
- },
57
- () => ({ tool, color, size, zoom: viewport.zoom }),
58
- );
57
+ () => ({ tool, color, size, zoom: viewport.zoom }),
58
+ );
59
59
 
60
- // =========================
61
- // EFFECTS
62
- // =========================
63
- // Switching tool mid-stroke unmounts the overlay, and an open gesture would block undo for good.
64
- $effect(() => () => session.cancel());
60
+ // =========================
61
+ // EFFECTS
62
+ // =========================
63
+ // Switching tool mid-stroke unmounts the overlay, and an open gesture would block undo for good.
64
+ $effect(() => () => session.cancel());
65
65
 
66
- // =========================
67
- // FUNCTIONS
68
- // =========================
69
- function toFlow(event: { clientX: number; clientY: number }) {
70
- const rect = layer?.getBoundingClientRect();
71
- const left = rect?.left ?? 0;
72
- const top = rect?.top ?? 0;
73
- return {
74
- x: (event.clientX - left - viewport.x) / viewport.zoom,
75
- y: (event.clientY - top - viewport.y) / viewport.zoom,
76
- };
77
- }
66
+ // =========================
67
+ // FUNCTIONS
68
+ // =========================
69
+ function toFlow(event: { clientX: number; clientY: number }) {
70
+ const rect = layer?.getBoundingClientRect();
71
+ const left = rect?.left ?? 0;
72
+ const top = rect?.top ?? 0;
73
+ return {
74
+ x: (event.clientX - left - viewport.x) / viewport.zoom,
75
+ y: (event.clientY - top - viewport.y) / viewport.zoom,
76
+ };
77
+ }
78
78
 
79
- function pressureOf(event: PointerEvent): number | undefined {
80
- return event.pointerType === "pen" ? event.pressure : undefined;
81
- }
79
+ function pressureOf(event: PointerEvent): number | undefined {
80
+ return event.pointerType === "pen" ? event.pressure : undefined;
81
+ }
82
82
 
83
- function onpointerdown(event: PointerEvent) {
84
- // A second finger or a right click mustn't start a stroke.
85
- if (event.button !== 0 || !event.isPrimary) return;
86
- layer?.setPointerCapture(event.pointerId);
87
- session.down(toFlow(event), pressureOf(event));
88
- }
83
+ function onpointerdown(event: PointerEvent) {
84
+ // A second finger or a right click mustn't start a stroke.
85
+ if (event.button !== 0 || !event.isPrimary) return;
86
+ layer?.setPointerCapture(event.pointerId);
87
+ session.down(toFlow(event), pressureOf(event));
88
+ }
89
89
 
90
- function onpointermove(event: PointerEvent) {
91
- if (!session.active) return;
92
- // Coalesced events keep a fast pen stroke smooth between animation frames.
93
- const batch = event.getCoalescedEvents?.() ?? [];
94
- for (const sample of batch.length > 0 ? batch : [event]) {
95
- session.move(toFlow(sample), pressureOf(sample));
90
+ function onpointermove(event: PointerEvent) {
91
+ if (!session.active) return;
92
+ // Coalesced events keep a fast pen stroke smooth between animation frames.
93
+ const batch = event.getCoalescedEvents?.() ?? [];
94
+ for (const sample of batch.length > 0 ? batch : [event]) {
95
+ session.move(toFlow(sample), pressureOf(sample));
96
+ }
96
97
  }
97
- }
98
98
 
99
- function onpointerup(event: PointerEvent) {
100
- if (!session.active) return;
101
- layer?.releasePointerCapture(event.pointerId);
102
- session.up(toFlow(event), { square: event.shiftKey });
103
- }
99
+ function onpointerup(event: PointerEvent) {
100
+ if (!session.active) return;
101
+ layer?.releasePointerCapture(event.pointerId);
102
+ session.up(toFlow(event), { square: event.shiftKey });
103
+ }
104
104
 
105
- function onkeydown(event: KeyboardEvent) {
106
- if (event.key === "Escape") session.cancel();
107
- }
105
+ function onkeydown(event: KeyboardEvent) {
106
+ if (event.key === "Escape") session.cancel();
107
+ }
108
108
 
109
- // The overlay sits above xyflow's zoom pane, so a wheel or a trackpad pinch would
110
- // never reach it. Hand those to the pane so you can zoom and pan mid-drawing.
111
- function forwardWheel(node: HTMLElement) {
112
- const handler = (event: WheelEvent) => {
113
- const zoomPane = node.closest(".svelte-flow")?.querySelector(".svelte-flow__zoom");
114
- if (!zoomPane) return;
115
- event.preventDefault();
116
- zoomPane.dispatchEvent(
117
- new WheelEvent("wheel", {
118
- deltaX: event.deltaX,
119
- deltaY: event.deltaY,
120
- deltaZ: event.deltaZ,
121
- deltaMode: event.deltaMode,
122
- clientX: event.clientX,
123
- clientY: event.clientY,
124
- screenX: event.screenX,
125
- screenY: event.screenY,
126
- ctrlKey: event.ctrlKey,
127
- shiftKey: event.shiftKey,
128
- altKey: event.altKey,
129
- metaKey: event.metaKey,
130
- bubbles: true,
131
- cancelable: true,
132
- }),
133
- );
134
- };
135
- node.addEventListener("wheel", handler, { passive: false });
136
- return () => node.removeEventListener("wheel", handler);
137
- }
109
+ // The overlay sits above xyflow's zoom pane, so a wheel or a trackpad pinch would
110
+ // never reach it. Hand those to the pane so you can zoom and pan mid-drawing.
111
+ function forwardWheel(node: HTMLElement) {
112
+ const handler = (event: WheelEvent) => {
113
+ const zoomPane = node.closest(".svelte-flow")?.querySelector(".svelte-flow__zoom");
114
+ if (!zoomPane) return;
115
+ event.preventDefault();
116
+ zoomPane.dispatchEvent(
117
+ new WheelEvent("wheel", {
118
+ deltaX: event.deltaX,
119
+ deltaY: event.deltaY,
120
+ deltaZ: event.deltaZ,
121
+ deltaMode: event.deltaMode,
122
+ clientX: event.clientX,
123
+ clientY: event.clientY,
124
+ screenX: event.screenX,
125
+ screenY: event.screenY,
126
+ ctrlKey: event.ctrlKey,
127
+ shiftKey: event.shiftKey,
128
+ altKey: event.altKey,
129
+ metaKey: event.metaKey,
130
+ bubbles: true,
131
+ cancelable: true,
132
+ }),
133
+ );
134
+ };
135
+ node.addEventListener("wheel", handler, { passive: false });
136
+ return () => node.removeEventListener("wheel", handler);
137
+ }
138
138
 
139
- function cursorFor(current: PenTool): string {
140
- if (current === "text") return "text";
141
- return "crosshair";
142
- }
139
+ function cursorFor(current: PenTool): string {
140
+ if (current === "text") return "text";
141
+ return "crosshair";
142
+ }
143
143
  </script>
144
144
 
145
145
  <!-- =========================== -->
@@ -1,38 +1,36 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { NodeResizer, type NodeProps } from "@xyflow/svelte";
6
- import ShapeOutline from "../components/shared/svg/ShapeOutline.svelte";
7
- import PenField from "./PenField.svelte";
8
- import { getDiagramEditorContext } from "../editor/editor-context.js";
9
- import { useHandDrawn } from "../editor/hand-context.js";
10
- import { isLocked } from "../editor/lock.js";
11
- import "./pen.css";
12
- import { penColorVar } from "./colors.js";
13
- import { shapeOutline } from "./shapes.js";
14
- import type { ShapeData } from "./types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { NodeResizer, type NodeProps } from "@xyflow/svelte";
6
+ import ShapeOutline from "../components/shared/svg/ShapeOutline.svelte";
7
+ import PenField from "./PenField.svelte";
8
+ import { getDiagramEditorContext } from "../editor/editor-context.js";
9
+ import { useHandDrawn } from "../editor/hand-context.js";
10
+ import { isLocked } from "../editor/lock.js";
11
+ import "./pen.css";
12
+ import { penColorVar } from "./colors.js";
13
+ import { shapeOutline } from "./shapes.js";
14
+ import type { ShapeData } from "./types.js";
15
15
 
16
- // =========================
17
- // PROPS
18
- // =========================
19
- let { id, data, selected, width, height }: NodeProps = $props();
16
+ // =========================
17
+ // PROPS
18
+ // =========================
19
+ let { id, data, selected, width, height }: NodeProps = $props();
20
20
 
21
- // =========================
22
- // STATE
23
- // =========================
24
- const editor = getDiagramEditorContext();
25
- const handDrawn = useHandDrawn();
26
- let endResize: (() => void) | null = null;
21
+ // =========================
22
+ // STATE
23
+ // =========================
24
+ const editor = getDiagramEditorContext();
25
+ const handDrawn = useHandDrawn();
26
+ let endResize: (() => void) | null = null;
27
27
 
28
- // =========================
29
- // DERIVED
30
- // =========================
31
- let shape = $derived(data as ShapeData);
32
- let outline = $derived(
33
- shapeOutline(shape.shape, width ?? 0, height ?? 0, shape.strokeWidth / 2),
34
- );
35
- let ink = $derived(penColorVar(shape.color));
28
+ // =========================
29
+ // DERIVED
30
+ // =========================
31
+ let shape = $derived(data as ShapeData);
32
+ let outline = $derived(shapeOutline(shape.shape, width ?? 0, height ?? 0, shape.strokeWidth / 2));
33
+ let ink = $derived(penColorVar(shape.color));
36
34
  </script>
37
35
 
38
36
  <!-- =========================== -->
@@ -58,7 +56,8 @@ let ink = $derived(penColorVar(shape.color));
58
56
  readonly={!editor || isLocked({ data })}
59
57
  ariaLabel="Shape label"
60
58
  color={ink}
61
- onCommit={(next, live) => editor?.patchNodeData(id, { label: next }, live ? { coalesce: true } : undefined)}
59
+ onCommit={(next, live) =>
60
+ editor?.patchNodeData(id, { label: next }, live ? { coalesce: true } : undefined)}
62
61
  onExit={() => editor?.endTextEdit()}
63
62
  />
64
63
  {/if}
@@ -1,61 +1,61 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { Handle, Position, type NodeProps } from "@xyflow/svelte";
6
- import { onMount } from "svelte";
7
- import TextRule from "../components/shared/svg/TextRule.svelte";
8
- import PenField from "./PenField.svelte";
9
- import { getDiagramEditorContext } from "../editor/editor-context.js";
10
- import { useHandDrawn } from "../editor/hand-context.js";
11
- import { isLocked } from "../editor/lock.js";
12
- import { roughUnderline, seedFrom, sketchColors } from "../headless/sketch.js";
13
- import "./pen.css";
14
- import { penColorVar } from "./colors.js";
15
- import type { TextData } from "./types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { Handle, Position, type NodeProps } from "@xyflow/svelte";
6
+ import { onMount } from "svelte";
7
+ import TextRule from "../components/shared/svg/TextRule.svelte";
8
+ import PenField from "./PenField.svelte";
9
+ import { getDiagramEditorContext } from "../editor/editor-context.js";
10
+ import { useHandDrawn } from "../editor/hand-context.js";
11
+ import { isLocked } from "../editor/lock.js";
12
+ import { roughUnderline, seedFrom, sketchColors } from "../headless/sketch.js";
13
+ import "./pen.css";
14
+ import { penColorVar } from "./colors.js";
15
+ import type { TextData } from "./types.js";
16
16
 
17
- // =========================
18
- // PROPS
19
- // =========================
20
- let { id, data, selected }: NodeProps = $props();
17
+ // =========================
18
+ // PROPS
19
+ // =========================
20
+ let { id, data, selected }: NodeProps = $props();
21
21
 
22
- // =========================
23
- // STATE
24
- // =========================
25
- const editor = getDiagramEditorContext();
26
- const handDrawn = useHandDrawn();
27
- let field = $state<ReturnType<typeof PenField>>();
28
- let boxWidth = $state(0);
22
+ // =========================
23
+ // STATE
24
+ // =========================
25
+ const editor = getDiagramEditorContext();
26
+ const handDrawn = useHandDrawn();
27
+ let field = $state<ReturnType<typeof PenField>>();
28
+ let boxWidth = $state(0);
29
29
 
30
- // =========================
31
- // DERIVED
32
- // =========================
33
- let text = $derived(data as TextData);
34
- let ink = $derived(penColorVar(text.color));
35
- let rule = $derived(
36
- text.underline && boxWidth > 2
37
- ? roughUnderline(
38
- boxWidth,
39
- { seed: seedFrom(id) + 7, colors: { ...sketchColors("ink", false), stroke: ink } },
40
- { formal: !handDrawn() },
41
- )
42
- : [],
43
- );
30
+ // =========================
31
+ // DERIVED
32
+ // =========================
33
+ let text = $derived(data as TextData);
34
+ let ink = $derived(penColorVar(text.color));
35
+ let rule = $derived(
36
+ text.underline && boxWidth > 2
37
+ ? roughUnderline(
38
+ boxWidth,
39
+ { seed: seedFrom(id) + 7, colors: { ...sketchColors("ink", false), stroke: ink } },
40
+ { formal: !handDrawn() },
41
+ )
42
+ : [],
43
+ );
44
44
 
45
- // =========================
46
- // EFFECTS
47
- // =========================
48
- // The editor asks a freshly dropped text to open, so the first thing typed lands in it.
49
- onMount(() => editor?.registerStartEdit(id, () => void field?.edit()));
45
+ // =========================
46
+ // EFFECTS
47
+ // =========================
48
+ // The editor asks a freshly dropped text to open, so the first thing typed lands in it.
49
+ onMount(() => editor?.registerStartEdit(id, () => void field?.edit()));
50
50
 
51
- // =========================
52
- // FUNCTIONS
53
- // =========================
54
- function onExit() {
55
- editor?.endTextEdit();
56
- // A click that typed nothing leaves no empty node behind.
57
- if (editor && text.text.trim() === "") editor.removeNode(id);
58
- }
51
+ // =========================
52
+ // FUNCTIONS
53
+ // =========================
54
+ function onExit() {
55
+ editor?.endTextEdit();
56
+ // A click that typed nothing leaves no empty node behind.
57
+ if (editor && text.text.trim() === "") editor.removeNode(id);
58
+ }
59
59
  </script>
60
60
 
61
61
  <!-- =========================== -->
@@ -81,7 +81,8 @@ function onExit() {
81
81
  fontWeight={text.fontWeight === "bold" ? 700 : undefined}
82
82
  center={text.align === "center"}
83
83
  column={text.fixedWidth}
84
- onCommit={(next, live) => editor?.patchNodeData(id, { text: next }, live ? { coalesce: true } : undefined)}
84
+ onCommit={(next, live) =>
85
+ editor?.patchNodeData(id, { text: next }, live ? { coalesce: true } : undefined)}
85
86
  {onExit}
86
87
  />
87
88
  {#if rule.length > 0}
@@ -1,13 +1,13 @@
1
1
  <script lang="ts">
2
- // A host's text field for the PenField test: shows its value, records that it was opened.
3
- import type { TextFieldProps } from "../editor/text-field-context.js";
2
+ // A host's text field for the PenField test: shows its value, records that it was opened.
3
+ import type { TextFieldProps } from "../editor/text-field-context.js";
4
4
 
5
- let { value, readonly = false, class: klass = "" }: TextFieldProps = $props();
6
- let opened = $state(0);
5
+ let { value, readonly = false, class: klass = "" }: TextFieldProps = $props();
6
+ let opened = $state(0);
7
7
 
8
- export function edit() {
9
- opened++;
10
- }
8
+ export function edit() {
9
+ opened++;
10
+ }
11
11
  </script>
12
12
 
13
13
  <div data-host-field class={klass} data-readonly={readonly} data-opened={opened}>{value}</div>
@@ -1,7 +1,13 @@
1
1
  // Shape and text nodes from a drag or a click. Pure, so the CLI can reuse it.
2
2
 
3
3
  import type { Box, Pt } from "./geometry.js";
4
- import type { PenColor, PenNodeInput, ShapeData, ShapeKind, TextData } from "./types.js";
4
+ import type {
5
+ PenColor,
6
+ PenNodeInput,
7
+ ShapeData,
8
+ ShapeKind,
9
+ TextData,
10
+ } from "./types.js";
5
11
  import { PEN_DEFAULTS, SHAPE_NODE, TEXT_NODE } from "./types.js";
6
12
 
7
13
  /** A shape smaller than this on both sides was a click, so it gets the default size. */
@@ -1,25 +1,30 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { GLYPHS, type GlyphName } from "./glyphs.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { GLYPHS, type GlyphName } from "./glyphs.js";
6
6
 
7
- // =========================
8
- // TYPES
9
- // =========================
10
- interface Props {
11
- name: GlyphName;
12
- size?: number;
13
- class?: string;
14
- }
7
+ // =========================
8
+ // TYPES
9
+ // =========================
10
+ interface Props {
11
+ name: GlyphName;
12
+ size?: number;
13
+ class?: string;
14
+ }
15
15
 
16
- // =========================
17
- // PROPS
18
- // =========================
19
- let { name, size = 12, class: klass = "" }: Props = $props();
16
+ // =========================
17
+ // PROPS
18
+ // =========================
19
+ let { name, size = 12, class: klass = "" }: Props = $props();
20
20
  </script>
21
21
 
22
22
  <!-- =========================== -->
23
23
  <!-- MARKUP -->
24
24
  <!-- =========================== -->
25
- <span class="cv-glyph {klass}" style:--glyph={`url("${GLYPHS[name]}")`} style:--size="{size}px" aria-hidden="true"></span>
25
+ <span
26
+ class="cv-glyph {klass}"
27
+ style:--glyph={`url("${GLYPHS[name]}")`}
28
+ style:--size="{size}px"
29
+ aria-hidden="true"
30
+ ></span>