@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,88 +1,95 @@
1
1
  <script lang="ts" module>
2
- import type { PenColor } from "../pen/types.js";
3
- import type { CanvasTool } from "./tools.js";
2
+ import type { PenColor } from "../pen/types.js";
3
+ import type { CanvasTool } from "./tools.js";
4
4
 
5
- export interface ToolbarLabels {
6
- toolbar: string;
7
- style: string;
8
- tools: Record<CanvasTool, string> & { shapes: string; note: string };
9
- colors: Record<PenColor, string>;
10
- /** Small, medium, large. */
11
- sizes: readonly [string, string, string];
12
- }
5
+ export interface ToolbarLabels {
6
+ toolbar: string;
7
+ style: string;
8
+ tools: Record<CanvasTool, string> & { shapes: string; note: string };
9
+ colors: Record<PenColor, string>;
10
+ /** Small, medium, large. */
11
+ sizes: readonly [string, string, string];
12
+ }
13
13
  </script>
14
14
 
15
15
  <script lang="ts">
16
- // =========================
17
- // IMPORTS
18
- // =========================
19
- import { Panel } from "@xyflow/svelte";
20
- import type { Snippet } from "svelte";
21
- import "../pen/pen.css";
22
- import { PEN_COLORS } from "../pen/types.js";
23
- import "./canvas-ui.css";
24
- import ToolIcon from "../components/icons/ToolIcon.svelte";
25
- import {
26
- hasBrush,
27
- hasColor,
28
- isBrushTool,
29
- isShapeTool,
30
- keyForTool,
31
- type BrushLevel,
32
- type BrushTool,
33
- } from "./tools.js";
16
+ // =========================
17
+ // IMPORTS
18
+ // =========================
19
+ import { Panel } from "@xyflow/svelte";
20
+ import type { Snippet } from "svelte";
21
+ import "../pen/pen.css";
22
+ import { PEN_COLORS } from "../pen/types.js";
23
+ import "./canvas-ui.css";
24
+ import ToolIcon from "../components/icons/ToolIcon.svelte";
25
+ import {
26
+ hasBrush,
27
+ hasColor,
28
+ isBrushTool,
29
+ isShapeTool,
30
+ keyForTool,
31
+ type BrushLevel,
32
+ type BrushTool,
33
+ } from "./tools.js";
34
34
 
35
- // =========================
36
- // TYPES
37
- // =========================
38
- interface Props {
39
- tool: CanvasTool;
40
- color: PenColor;
41
- level: BrushLevel;
42
- labels: ToolbarLabels;
43
- /** The note button drops a note card, so the host owns what it does. Omit it to hide the button. */
44
- onNote?: () => void;
45
- /** Sits last on the rail, for what only the host knows, like the card palette. */
46
- extra?: Snippet;
47
- }
35
+ // =========================
36
+ // TYPES
37
+ // =========================
38
+ interface Props {
39
+ tool: CanvasTool;
40
+ color: PenColor;
41
+ level: BrushLevel;
42
+ labels: ToolbarLabels;
43
+ /** The note button drops a note card, so the host owns what it does. Omit it to hide the button. */
44
+ onNote?: () => void;
45
+ /** Sits last on the rail, for what only the host knows, like the card palette. */
46
+ extra?: Snippet;
47
+ }
48
48
 
49
- // =========================
50
- // PROPS
51
- // =========================
52
- let { tool = $bindable(), color = $bindable(), level = $bindable(), labels, onNote, extra }: Props = $props();
49
+ // =========================
50
+ // PROPS
51
+ // =========================
52
+ let {
53
+ tool = $bindable(),
54
+ color = $bindable(),
55
+ level = $bindable(),
56
+ labels,
57
+ onNote,
58
+ extra,
59
+ }: Props = $props();
53
60
 
54
- // =========================
55
- // STATE
56
- // =========================
57
- let lastShape = $state<"rectangle" | "ellipse" | "diamond">("rectangle");
58
- let lastBrush = $state<BrushTool>("pen");
61
+ // =========================
62
+ // STATE
63
+ // =========================
64
+ let lastShape = $state<"rectangle" | "ellipse" | "diamond">("rectangle");
65
+ let lastBrush = $state<BrushTool>("pen");
59
66
 
60
- // =========================
61
- // DERIVED
62
- // =========================
63
- const BRUSHES = ["pen", "highlighter", "eraser"] as const;
64
- const SHAPES = ["rectangle", "ellipse", "diamond"] as const;
65
- const BRUSH_DOT = [4, 7, 11] as const;
67
+ // =========================
68
+ // DERIVED
69
+ // =========================
70
+ const BRUSHES = ["pen", "highlighter", "eraser"] as const;
71
+ const SHAPES = ["rectangle", "ellipse", "diamond"] as const;
72
+ const BRUSH_DOT = [4, 7, 11] as const;
66
73
 
67
- let shapeActive = $derived(isShapeTool(tool));
68
- let brushActive = $derived(isBrushTool(tool));
69
- let showStyle = $derived(brushActive || shapeActive || hasColor(tool));
74
+ let shapeActive = $derived(isShapeTool(tool));
75
+ let brushActive = $derived(isBrushTool(tool));
76
+ let showStyle = $derived(brushActive || shapeActive || hasColor(tool));
70
77
 
71
- // =========================
72
- // EFFECTS
73
- // =========================
74
- $effect(() => {
75
- if (isShapeTool(tool)) lastShape = tool;
76
- if (isBrushTool(tool)) lastBrush = tool;
77
- });
78
+ // =========================
79
+ // EFFECTS
80
+ // =========================
81
+ $effect(() => {
82
+ if (isShapeTool(tool)) lastShape = tool;
83
+ if (isBrushTool(tool)) lastBrush = tool;
84
+ });
78
85
 
79
- // =========================
80
- // FUNCTIONS
81
- // =========================
82
- function tip(id: CanvasTool, label = labels.tools[id]): string {
83
- const key = keyForTool(id);
84
- return key ? `${label} ${key}` : label;
85
- }
86
+ // =========================
87
+ // FUNCTIONS
88
+ // =========================
89
+ function tip(id: CanvasTool, label = labels.tools[id]): string {
90
+ const key = keyForTool(id);
91
+ return key ? `${label} ${key}` : label;
92
+ }
86
93
  </script>
87
94
 
88
95
  <!-- =========================== -->
@@ -90,30 +97,90 @@ function tip(id: CanvasTool, label = labels.tools[id]): string {
90
97
  <!-- =========================== -->
91
98
  <Panel position="center-left" class="cv-dock">
92
99
  <div class="cv-row">
93
- <div class="cv-bar cv-rail" role="toolbar" aria-orientation="vertical" aria-label={labels.toolbar}>
94
- <button type="button" class="cv-btn" aria-pressed={tool === "select"} aria-label={labels.tools.select} data-tip={tip("select")} onclick={() => (tool = "select")}>
100
+ <div
101
+ class="cv-bar cv-rail"
102
+ role="toolbar"
103
+ aria-orientation="vertical"
104
+ aria-label={labels.toolbar}
105
+ >
106
+ <button
107
+ type="button"
108
+ class="cv-btn"
109
+ aria-pressed={tool === "select"}
110
+ aria-label={labels.tools.select}
111
+ data-tip={tip("select")}
112
+ onclick={() => (tool = "select")}
113
+ >
95
114
  <ToolIcon name="select" />
96
115
  </button>
97
- <button type="button" class="cv-btn" aria-pressed={tool === "hand"} aria-label={labels.tools.hand} data-tip={tip("hand")} onclick={() => (tool = "hand")}>
116
+ <button
117
+ type="button"
118
+ class="cv-btn"
119
+ aria-pressed={tool === "hand"}
120
+ aria-label={labels.tools.hand}
121
+ data-tip={tip("hand")}
122
+ onclick={() => (tool = "hand")}
123
+ >
98
124
  <ToolIcon name="hand" />
99
125
  </button>
100
- <button type="button" class="cv-btn" aria-pressed={tool === "connect"} aria-label={labels.tools.connect} data-tip={tip("connect")} onclick={() => (tool = "connect")}>
126
+ <button
127
+ type="button"
128
+ class="cv-btn"
129
+ aria-pressed={tool === "connect"}
130
+ aria-label={labels.tools.connect}
131
+ data-tip={tip("connect")}
132
+ onclick={() => (tool = "connect")}
133
+ >
101
134
  <ToolIcon name="connect" />
102
135
  </button>
103
- <button type="button" class="cv-btn" aria-pressed={brushActive} aria-label={labels.tools[lastBrush]} data-tip={tip(lastBrush)} onclick={() => (tool = lastBrush)}>
136
+ <button
137
+ type="button"
138
+ class="cv-btn"
139
+ aria-pressed={brushActive}
140
+ aria-label={labels.tools[lastBrush]}
141
+ data-tip={tip(lastBrush)}
142
+ onclick={() => (tool = lastBrush)}
143
+ >
104
144
  <ToolIcon name={brushActive ? (tool as BrushTool) : lastBrush} />
105
145
  </button>
106
- <button type="button" class="cv-btn" aria-pressed={tool === "text"} aria-label={labels.tools.text} data-tip={tip("text")} onclick={() => (tool = "text")}>
146
+ <button
147
+ type="button"
148
+ class="cv-btn"
149
+ aria-pressed={tool === "text"}
150
+ aria-label={labels.tools.text}
151
+ data-tip={tip("text")}
152
+ onclick={() => (tool = "text")}
153
+ >
107
154
  <ToolIcon name="text" />
108
155
  </button>
109
- <button type="button" class="cv-btn" aria-pressed={shapeActive} aria-label={labels.tools.shapes} data-tip={tip("rectangle", labels.tools.shapes)} onclick={() => (tool = lastShape)}>
156
+ <button
157
+ type="button"
158
+ class="cv-btn"
159
+ aria-pressed={shapeActive}
160
+ aria-label={labels.tools.shapes}
161
+ data-tip={tip("rectangle", labels.tools.shapes)}
162
+ onclick={() => (tool = lastShape)}
163
+ >
110
164
  <ToolIcon name={shapeActive ? (tool as typeof lastShape) : lastShape} />
111
165
  </button>
112
- <button type="button" class="cv-btn" aria-pressed={tool === "frame"} aria-label={labels.tools.frame} data-tip={tip("frame")} onclick={() => (tool = "frame")}>
166
+ <button
167
+ type="button"
168
+ class="cv-btn"
169
+ aria-pressed={tool === "frame"}
170
+ aria-label={labels.tools.frame}
171
+ data-tip={tip("frame")}
172
+ onclick={() => (tool = "frame")}
173
+ >
113
174
  <ToolIcon name="frame" />
114
175
  </button>
115
176
  {#if onNote}
116
- <button type="button" class="cv-btn" aria-label={labels.tools.note} data-tip="{labels.tools.note} N" onclick={onNote}>
177
+ <button
178
+ type="button"
179
+ class="cv-btn"
180
+ aria-label={labels.tools.note}
181
+ data-tip="{labels.tools.note} N"
182
+ onclick={onNote}
183
+ >
117
184
  <ToolIcon name="note" />
118
185
  </button>
119
186
  {/if}
@@ -128,13 +195,27 @@ function tip(id: CanvasTool, label = labels.tools[id]): string {
128
195
  <div class="cv-bar t-enter" role="toolbar" aria-label={labels.style}>
129
196
  {#if brushActive}
130
197
  {#each BRUSHES as brush (brush)}
131
- <button type="button" class="cv-btn" aria-pressed={tool === brush} aria-label={labels.tools[brush]} data-tip={tip(brush)} onclick={() => (tool = brush)}>
198
+ <button
199
+ type="button"
200
+ class="cv-btn"
201
+ aria-pressed={tool === brush}
202
+ aria-label={labels.tools[brush]}
203
+ data-tip={tip(brush)}
204
+ onclick={() => (tool = brush)}
205
+ >
132
206
  <ToolIcon name={brush} />
133
207
  </button>
134
208
  {/each}
135
209
  {:else if shapeActive}
136
210
  {#each SHAPES as shape (shape)}
137
- <button type="button" class="cv-btn" aria-pressed={tool === shape} aria-label={labels.tools[shape]} data-tip={tip(shape)} onclick={() => (tool = shape)}>
211
+ <button
212
+ type="button"
213
+ class="cv-btn"
214
+ aria-pressed={tool === shape}
215
+ aria-label={labels.tools[shape]}
216
+ data-tip={tip(shape)}
217
+ onclick={() => (tool = shape)}
218
+ >
138
219
  <ToolIcon name={shape} />
139
220
  </button>
140
221
  {/each}
@@ -158,7 +239,14 @@ function tip(id: CanvasTool, label = labels.tools[id]): string {
158
239
  {#if hasBrush(tool)}
159
240
  <span class="cv-gap" aria-hidden="true"></span>
160
241
  {#each BRUSH_DOT as dot, index (index)}
161
- <button type="button" class="cv-btn" aria-pressed={level === index} aria-label={labels.sizes[index]} data-tip={labels.sizes[index]} onclick={() => (level = index as BrushLevel)}>
242
+ <button
243
+ type="button"
244
+ class="cv-btn"
245
+ aria-pressed={level === index}
246
+ aria-label={labels.sizes[index]}
247
+ data-tip={labels.sizes[index]}
248
+ onclick={() => (level = index as BrushLevel)}
249
+ >
162
250
  <span class="cv-dot" style:--dot="{dot}px"></span>
163
251
  </button>
164
252
  {/each}
@@ -1,72 +1,72 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { useStore } from "@xyflow/svelte";
6
- import { frameRect, type FrameRect } from "../editor/frame.js";
7
- import "./canvas-ui.css";
8
- import { forwardWheel } from "./forward-wheel.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { useStore } from "@xyflow/svelte";
6
+ import { frameRect, type FrameRect } from "../editor/frame.js";
7
+ import "./canvas-ui.css";
8
+ import { forwardWheel } from "./forward-wheel.js";
9
9
 
10
- // =========================
11
- // TYPES
12
- // =========================
13
- interface Props {
14
- /** A drag ended, or a click: the box in flow units. */
15
- onFrame: (rect: FrameRect) => void;
16
- }
10
+ // =========================
11
+ // TYPES
12
+ // =========================
13
+ interface Props {
14
+ /** A drag ended, or a click: the box in flow units. */
15
+ onFrame: (rect: FrameRect) => void;
16
+ }
17
17
 
18
- // =========================
19
- // PROPS
20
- // =========================
21
- let { onFrame }: Props = $props();
18
+ // =========================
19
+ // PROPS
20
+ // =========================
21
+ let { onFrame }: Props = $props();
22
22
 
23
- // =========================
24
- // STATE
25
- // =========================
26
- // The layer maps screen pixels to flow units, so it reads the live xyflow viewport.
27
- const store = useStore();
28
- let layer = $state<HTMLDivElement | null>(null);
29
- let start = $state<{ x: number; y: number } | null>(null);
30
- let end = $state<{ x: number; y: number } | null>(null);
23
+ // =========================
24
+ // STATE
25
+ // =========================
26
+ // The layer maps screen pixels to flow units, so it reads the live xyflow viewport.
27
+ const store = useStore();
28
+ let layer = $state<HTMLDivElement | null>(null);
29
+ let start = $state<{ x: number; y: number } | null>(null);
30
+ let end = $state<{ x: number; y: number } | null>(null);
31
31
 
32
- // =========================
33
- // DERIVED
34
- // =========================
35
- let preview = $derived(start && end ? frameRect(start, end) : null);
32
+ // =========================
33
+ // DERIVED
34
+ // =========================
35
+ let preview = $derived(start && end ? frameRect(start, end) : null);
36
36
 
37
- // =========================
38
- // FUNCTIONS
39
- // =========================
40
- function toFlow(event: { clientX: number; clientY: number }) {
41
- const box = layer?.getBoundingClientRect();
42
- const { x, y, zoom } = store.viewport;
43
- return {
44
- x: (event.clientX - (box?.left ?? 0) - x) / zoom,
45
- y: (event.clientY - (box?.top ?? 0) - y) / zoom,
46
- };
47
- }
37
+ // =========================
38
+ // FUNCTIONS
39
+ // =========================
40
+ function toFlow(event: { clientX: number; clientY: number }) {
41
+ const box = layer?.getBoundingClientRect();
42
+ const { x, y, zoom } = store.viewport;
43
+ return {
44
+ x: (event.clientX - (box?.left ?? 0) - x) / zoom,
45
+ y: (event.clientY - (box?.top ?? 0) - y) / zoom,
46
+ };
47
+ }
48
48
 
49
- function onpointerdown(event: PointerEvent) {
50
- if (event.button !== 0 || !event.isPrimary) return;
51
- layer?.setPointerCapture(event.pointerId);
52
- start = end = toFlow(event);
53
- }
49
+ function onpointerdown(event: PointerEvent) {
50
+ if (event.button !== 0 || !event.isPrimary) return;
51
+ layer?.setPointerCapture(event.pointerId);
52
+ start = end = toFlow(event);
53
+ }
54
54
 
55
- function onpointermove(event: PointerEvent) {
56
- if (start) end = toFlow(event);
57
- }
55
+ function onpointermove(event: PointerEvent) {
56
+ if (start) end = toFlow(event);
57
+ }
58
58
 
59
- function onpointerup(event: PointerEvent) {
60
- if (!start) return;
61
- layer?.releasePointerCapture(event.pointerId);
62
- const rect = frameRect(start, toFlow(event));
63
- start = end = null;
64
- onFrame(rect);
65
- }
59
+ function onpointerup(event: PointerEvent) {
60
+ if (!start) return;
61
+ layer?.releasePointerCapture(event.pointerId);
62
+ const rect = frameRect(start, toFlow(event));
63
+ start = end = null;
64
+ onFrame(rect);
65
+ }
66
66
 
67
- function cancel() {
68
- start = end = null;
69
- }
67
+ function cancel() {
68
+ start = end = null;
69
+ }
70
70
  </script>
71
71
 
72
72
  <!-- =========================== -->
@@ -1,39 +1,48 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { useStore } from "@xyflow/svelte";
6
- import type { ErasableNode } from "../pen/eraser.js";
7
- import type { PenOp } from "../pen/ops.js";
8
- import PenOverlay from "../pen/PenOverlay.svelte";
9
- import type { PenColor, PenTool } from "../pen/types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { useStore } from "@xyflow/svelte";
6
+ import type { ErasableNode } from "../pen/eraser.js";
7
+ import type { PenOp } from "../pen/ops.js";
8
+ import PenOverlay from "../pen/PenOverlay.svelte";
9
+ import type { PenColor, PenTool } from "../pen/types.js";
10
10
 
11
- // =========================
12
- // TYPES
13
- // =========================
14
- interface Props {
15
- tool: PenTool;
16
- color: PenColor;
17
- size?: number;
18
- nodes: readonly ErasableNode[];
19
- commit: (ops: PenOp[]) => void;
20
- startGesture: () => () => void;
21
- onTextPlaced?: (nodeId: string) => void;
22
- }
11
+ // =========================
12
+ // TYPES
13
+ // =========================
14
+ interface Props {
15
+ tool: PenTool;
16
+ color: PenColor;
17
+ size?: number;
18
+ nodes: readonly ErasableNode[];
19
+ commit: (ops: PenOp[]) => void;
20
+ startGesture: () => () => void;
21
+ onTextPlaced?: (nodeId: string) => void;
22
+ }
23
23
 
24
- // =========================
25
- // PROPS
26
- // =========================
27
- let { tool, color, size, nodes, commit, startGesture, onTextPlaced }: Props = $props();
24
+ // =========================
25
+ // PROPS
26
+ // =========================
27
+ let { tool, color, size, nodes, commit, startGesture, onTextPlaced }: Props = $props();
28
28
 
29
- // =========================
30
- // STATE
31
- // =========================
32
- // The overlay maps screen pixels to flow units, so it reads the live xyflow viewport.
33
- const store = useStore();
29
+ // =========================
30
+ // STATE
31
+ // =========================
32
+ // The overlay maps screen pixels to flow units, so it reads the live xyflow viewport.
33
+ const store = useStore();
34
34
  </script>
35
35
 
36
36
  <!-- =========================== -->
37
37
  <!-- MARKUP -->
38
38
  <!-- =========================== -->
39
- <PenOverlay {tool} {color} {size} viewport={store.viewport} {nodes} {commit} {startGesture} {onTextPlaced} />
39
+ <PenOverlay
40
+ {tool}
41
+ {color}
42
+ {size}
43
+ viewport={store.viewport}
44
+ {nodes}
45
+ {commit}
46
+ {startGesture}
47
+ {onTextPlaced}
48
+ />