@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,43 +1,59 @@
1
1
  <svelte:options namespace="svg" />
2
2
 
3
3
  <script lang="ts">
4
- // =========================
5
- // IMPORTS
6
- // =========================
7
- import { BaseEdge } from "@xyflow/svelte";
8
- import EdgeGradient from "./edge-gradient.svelte";
4
+ // =========================
5
+ // IMPORTS
6
+ // =========================
7
+ import { BaseEdge } from "@xyflow/svelte";
8
+ import EdgeGradient from "./edge-gradient.svelte";
9
9
 
10
- // =========================
11
- // TYPES
12
- // =========================
13
- interface Props {
14
- id: string;
15
- path: string;
16
- from: { x: number; y: number };
17
- to: { x: number; y: number };
18
- fromColor: string;
19
- toColor?: string;
20
- markerEnd?: string;
21
- /** The edge's own style. A stroke set here beats the gradient. */
22
- style?: string;
23
- class?: string;
24
- }
10
+ // =========================
11
+ // TYPES
12
+ // =========================
13
+ interface Props {
14
+ id: string;
15
+ path: string;
16
+ from: { x: number; y: number };
17
+ to: { x: number; y: number };
18
+ fromColor: string;
19
+ toColor?: string;
20
+ markerEnd?: string;
21
+ /** The edge's own style. A stroke set here beats the gradient. */
22
+ style?: string;
23
+ class?: string;
24
+ }
25
25
 
26
- // =========================
27
- // PROPS
28
- // =========================
29
- let { id, path, from, to, fromColor, toColor = fromColor, markerEnd, style = "", class: className = "" }: Props = $props();
26
+ // =========================
27
+ // PROPS
28
+ // =========================
29
+ let {
30
+ id,
31
+ path,
32
+ from,
33
+ to,
34
+ fromColor,
35
+ toColor = fromColor,
36
+ markerEnd,
37
+ style = "",
38
+ class: className = "",
39
+ }: Props = $props();
30
40
 
31
- // =========================
32
- // DERIVED
33
- // =========================
34
- let gradientId = $derived(`canvas-gradient-${id.replace(/[^\w-]/g, "_")}`);
41
+ // =========================
42
+ // DERIVED
43
+ // =========================
44
+ let gradientId = $derived(`canvas-gradient-${id.replace(/[^\w-]/g, "_")}`);
35
45
  </script>
36
46
 
37
47
  <!-- =========================== -->
38
48
  <!-- MARKUP -->
39
49
  <!-- =========================== -->
40
50
  <EdgeGradient id={gradientId} {from} {to} {fromColor} {toColor} />
41
- <BaseEdge {id} {path} {markerEnd} class="canvas-edge {className}" style="stroke: url(#{gradientId}); {style}" />
51
+ <BaseEdge
52
+ {id}
53
+ {path}
54
+ {markerEnd}
55
+ class="canvas-edge {className}"
56
+ style="stroke: url(#{gradientId}); {style}"
57
+ />
42
58
  <!-- Hidden until a test run crosses this link; the canvas stylesheet draws the moving dashes. -->
43
59
  <path d={path} class="canvas-edge-flow" fill="none" aria-hidden="true" />
@@ -1,6 +1,11 @@
1
1
  import { describe, expect, it } from "vite-plus/test";
2
2
  import type { Node } from "@xyflow/svelte";
3
- import { deletableIds, refuseLockedOps, toggleLock, withLockFlags } from "./lock.js";
3
+ import {
4
+ deletableIds,
5
+ refuseLockedOps,
6
+ toggleLock,
7
+ withLockFlags,
8
+ } from "./lock.js";
4
9
 
5
10
  function card(id: string, data: Record<string, unknown> = {}, extra: Partial<Node> = {}): Node {
6
11
  return { id, type: "note", position: { x: 0, y: 0 }, data, ...extra };
@@ -2,7 +2,13 @@
2
2
  // A change is one patchNode per card, so it is one undo step.
3
3
 
4
4
  import type { CanvasOp } from "../ops/ops.js";
5
- import { PEN_COLORS, SHAPE_NODE, STROKE_NODE, TEXT_NODE, type PenColor } from "../pen/types.js";
5
+ import {
6
+ PEN_COLORS,
7
+ SHAPE_NODE,
8
+ STROKE_NODE,
9
+ TEXT_NODE,
10
+ type PenColor,
11
+ } from "../pen/types.js";
6
12
 
7
13
  export type FillValue = PenColor | "none";
8
14
  export type FontWeight = "regular" | "bold";
@@ -1,5 +1,9 @@
1
1
  import { describe, expect, it } from "vite-plus/test";
2
- import { figureBoxHeight, figureRatio, sanitizeFigureSvg } from "./svg-figure.js";
2
+ import {
3
+ figureBoxHeight,
4
+ figureRatio,
5
+ sanitizeFigureSvg,
6
+ } from "./svg-figure.js";
3
7
 
4
8
  describe("sanitizeFigureSvg", () => {
5
9
  it("keeps the shapes, the text and the geometry", () => {
@@ -1,81 +1,82 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import { useStore } from "@xyflow/svelte";
7
- import SideHandles from "../chrome/side-handles.svelte";
8
- import { lodMode } from "./lod-mode.svelte.js";
9
- import { renderAll } from "./render-all.svelte.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import { useStore } from "@xyflow/svelte";
7
+ import SideHandles from "../chrome/side-handles.svelte";
8
+ import { lodMode } from "./lod-mode.svelte.js";
9
+ import { renderAll } from "./render-all.svelte.js";
10
10
 
11
- // Zoomed out, a card is a box at its measured size, so no arrow moves.
12
- // Never measured, selected, dragged or exported: full.
11
+ // Zoomed out, a card is a box at its measured size, so no arrow moves.
12
+ // Never measured, selected, dragged or exported: full.
13
13
 
14
- // =========================
15
- // TYPES
16
- // =========================
17
- interface Props {
18
- id: string;
19
- selected?: boolean;
20
- dragging?: boolean;
21
- /** A CSS colour: the card's own, for the box's border and icon well. */
22
- tone: string;
23
- title: string;
24
- /** The full card. */
25
- children: Snippet;
26
- }
14
+ // =========================
15
+ // TYPES
16
+ // =========================
17
+ interface Props {
18
+ id: string;
19
+ selected?: boolean;
20
+ dragging?: boolean;
21
+ /** A CSS colour: the card's own, for the box's border and icon well. */
22
+ tone: string;
23
+ title: string;
24
+ /** The full card. */
25
+ children: Snippet;
26
+ }
27
27
 
28
- // =========================
29
- // PROPS
30
- // =========================
31
- let { id, selected = false, dragging = false, tone, title, children }: Props = $props();
28
+ // =========================
29
+ // PROPS
30
+ // =========================
31
+ let { id, selected = false, dragging = false, tone, title, children }: Props = $props();
32
32
 
33
- // =========================
34
- // STATE
35
- // =========================
36
- const store = useStore();
37
- const mode = lodMode(store);
38
- let probe = $state<HTMLElement>();
39
- // xyflow keeps the size of a card that scrolled away, so it comes back as a box.
40
- let size = $state<{ width: number; height: number } | null>(measured());
41
- // Plain on purpose: only the observer below reads it.
42
- let boxed = false;
33
+ // =========================
34
+ // STATE
35
+ // =========================
36
+ const store = useStore();
37
+ const mode = lodMode(store);
38
+ let probe = $state<HTMLElement>();
39
+ // xyflow keeps the size of a card that scrolled away, so it comes back as a box.
40
+ let size = $state<{ width: number; height: number } | null>(measured());
41
+ // Plain on purpose: only the observer below reads it.
42
+ let boxed = false;
43
43
 
44
- // =========================
45
- // DERIVED
46
- // =========================
47
- let simple = $derived(mode.low && size !== null && !selected && !dragging && !renderAll.on);
44
+ // =========================
45
+ // DERIVED
46
+ // =========================
47
+ let simple = $derived(mode.low && size !== null && !selected && !dragging && !renderAll.on);
48
48
 
49
- // =========================
50
- // EFFECTS
51
- // =========================
52
- // Sizes the simple box from the full card. The observer's first call carries it, so a mount forces no layout.
53
- $effect(() => {
54
- const node = probe?.closest<HTMLElement>(".svelte-flow__node");
55
- if (!node) return;
56
- const observer = new ResizeObserver(([entry]) => {
57
- if (boxed) return;
58
- const box = entry.borderBoxSize[0];
59
- const width = Math.round(box.inlineSize);
60
- const height = Math.round(box.blockSize);
61
- if (width && height && (width !== size?.width || height !== size?.height)) size = { width, height };
49
+ // =========================
50
+ // EFFECTS
51
+ // =========================
52
+ // Sizes the simple box from the full card. The observer's first call carries it, so a mount forces no layout.
53
+ $effect(() => {
54
+ const node = probe?.closest<HTMLElement>(".svelte-flow__node");
55
+ if (!node) return;
56
+ const observer = new ResizeObserver(([entry]) => {
57
+ if (boxed) return;
58
+ const box = entry.borderBoxSize[0];
59
+ const width = Math.round(box.inlineSize);
60
+ const height = Math.round(box.blockSize);
61
+ if (width && height && (width !== size?.width || height !== size?.height))
62
+ size = { width, height };
63
+ });
64
+ observer.observe(node);
65
+ return () => observer.disconnect();
62
66
  });
63
- observer.observe(node);
64
- return () => observer.disconnect();
65
- });
66
67
 
67
- // Set after the render that swaps the box in, so the read above never sees the box's own size.
68
- $effect(() => {
69
- boxed = simple;
70
- });
68
+ // Set after the render that swaps the box in, so the read above never sees the box's own size.
69
+ $effect(() => {
70
+ boxed = simple;
71
+ });
71
72
 
72
- // =========================
73
- // FUNCTIONS
74
- // =========================
75
- function measured(): { width: number; height: number } | null {
76
- const known = store.nodeLookup.get(id)?.measured;
77
- return known?.width && known.height ? { width: known.width, height: known.height } : null;
78
- }
73
+ // =========================
74
+ // FUNCTIONS
75
+ // =========================
76
+ function measured(): { width: number; height: number } | null {
77
+ const known = store.nodeLookup.get(id)?.measured;
78
+ return known?.width && known.height ? { width: known.width, height: known.height } : null;
79
+ }
79
80
  </script>
80
81
 
81
82
  <!-- =========================== -->
@@ -83,7 +84,11 @@ function measured(): { width: number; height: number } | null {
83
84
  <!-- =========================== -->
84
85
  <span class="cv-lod-probe" bind:this={probe} hidden></span>
85
86
  {#if simple && size}
86
- <div class="cv-lod-box" style="width: {size.width}px; height: {size.height}px; --cv-lod-tone: {tone}" data-lod="simple">
87
+ <div
88
+ class="cv-lod-box"
89
+ style="width: {size.width}px; height: {size.height}px; --cv-lod-tone: {tone}"
90
+ data-lod="simple"
91
+ >
87
92
  <span class="cv-lod-well"></span>
88
93
  <span class="cv-lod-title">{title}</span>
89
94
  </div>
@@ -96,45 +101,45 @@ function measured(): { width: number; height: number } | null {
96
101
  <!-- STYLES -->
97
102
  <!-- =========================== -->
98
103
  <style>
99
- :global([data-cv-every-card] .svelte-flow__node) {
100
- animation: none;
101
- }
104
+ :global([data-cv-every-card] .svelte-flow__node) {
105
+ animation: none;
106
+ }
102
107
 
103
- /* A dot on a zoomed-out box is too small to link from; unpainted, it keeps its place for the links. */
104
- :global(.cv-lod-handle) {
105
- visibility: hidden;
106
- }
108
+ /* A dot on a zoomed-out box is too small to link from; unpainted, it keeps its place for the links. */
109
+ :global(.cv-lod-handle) {
110
+ visibility: hidden;
111
+ }
107
112
 
108
- /* The architecture card's own frame and layout (architecture-node.svelte), so selecting a card doesn't change how it looks. */
109
- .cv-lod-box {
110
- position: relative;
111
- box-sizing: border-box;
112
- display: flex;
113
- align-items: flex-start;
114
- gap: 10px;
115
- overflow: hidden;
116
- padding: var(--card-pad, 12px);
117
- border: 1px solid color-mix(in oklab, var(--cv-lod-tone) 20%, transparent);
118
- border-radius: var(--card-radius, 12px);
119
- background: var(--card, var(--cv-chrome-surface, #fff));
120
- color: var(--cv-ink, var(--foreground, #1a1a1f));
121
- contain: strict;
122
- }
113
+ /* The architecture card's own frame and layout (architecture-node.svelte), so selecting a card doesn't change how it looks. */
114
+ .cv-lod-box {
115
+ position: relative;
116
+ box-sizing: border-box;
117
+ display: flex;
118
+ align-items: flex-start;
119
+ gap: 10px;
120
+ overflow: hidden;
121
+ padding: var(--card-pad, 12px);
122
+ border: 1px solid color-mix(in oklab, var(--cv-lod-tone) 20%, transparent);
123
+ border-radius: var(--card-radius, 12px);
124
+ background: var(--card, var(--cv-chrome-surface, #fff));
125
+ color: var(--cv-ink, var(--foreground, #1a1a1f));
126
+ contain: strict;
127
+ }
123
128
 
124
- /* The icon well, without the icon. */
125
- .cv-lod-well {
126
- flex: none;
127
- width: 32px;
128
- height: 32px;
129
- border-radius: 9999px;
130
- background: color-mix(in oklab, var(--cv-lod-tone) 10%, transparent);
131
- }
129
+ /* The icon well, without the icon. */
130
+ .cv-lod-well {
131
+ flex: none;
132
+ width: 32px;
133
+ height: 32px;
134
+ border-radius: 9999px;
135
+ background: color-mix(in oklab, var(--cv-lod-tone) 10%, transparent);
136
+ }
132
137
 
133
- .cv-lod-title {
134
- overflow: hidden;
135
- font-size: 14px;
136
- font-weight: 500;
137
- line-height: 1.25;
138
- overflow-wrap: anywhere;
139
- }
138
+ .cv-lod-title {
139
+ overflow: hidden;
140
+ font-size: 14px;
141
+ font-weight: 500;
142
+ line-height: 1.25;
143
+ overflow-wrap: anywhere;
144
+ }
140
145
  </style>
@@ -1,90 +1,95 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { useTextField, type TextFieldHandle } from "../editor/text-field-context.js";
6
- import { useHandDrawn } from "../editor/hand-context.js";
7
- import "./pen.css";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { useTextField, type TextFieldHandle } from "../editor/text-field-context.js";
6
+ import { useHandDrawn } from "../editor/hand-context.js";
7
+ import "./pen.css";
8
8
 
9
- // The words of a pen text or a shape label: the host's field when it gave one (formatted text,
10
- // its own bar and undo), else a plain textarea.
9
+ // The words of a pen text or a shape label: the host's field when it gave one (formatted text,
10
+ // its own bar and undo), else a plain textarea.
11
11
 
12
- // =========================
13
- // TYPES
14
- // =========================
15
- interface Props {
16
- value: string;
17
- /** Which pen element it sits in. Sets the size and the box it keeps. */
18
- variant: "text" | "label";
19
- onCommit: (next: string, live: boolean) => void;
20
- ariaLabel: string;
21
- /** Typing needs the canvas editor; without one the words are shown, not changed. */
22
- readonly?: boolean;
23
- selected?: boolean;
24
- color?: string;
25
- fontSize?: number;
26
- fontWeight?: number;
27
- center?: boolean;
28
- column?: boolean;
29
- /** Called when the field closes. */
30
- onExit?: () => void;
31
- }
12
+ // =========================
13
+ // TYPES
14
+ // =========================
15
+ interface Props {
16
+ value: string;
17
+ /** Which pen element it sits in. Sets the size and the box it keeps. */
18
+ variant: "text" | "label";
19
+ onCommit: (next: string, live: boolean) => void;
20
+ ariaLabel: string;
21
+ /** Typing needs the canvas editor; without one the words are shown, not changed. */
22
+ readonly?: boolean;
23
+ selected?: boolean;
24
+ color?: string;
25
+ fontSize?: number;
26
+ fontWeight?: number;
27
+ center?: boolean;
28
+ column?: boolean;
29
+ /** Called when the field closes. */
30
+ onExit?: () => void;
31
+ }
32
32
 
33
- // =========================
34
- // PROPS
35
- // =========================
36
- let {
37
- value,
38
- variant,
39
- onCommit,
40
- ariaLabel,
41
- readonly = false,
42
- selected = false,
43
- color,
44
- fontSize,
45
- fontWeight,
46
- center = false,
47
- column = false,
48
- onExit,
49
- }: Props = $props();
33
+ // =========================
34
+ // PROPS
35
+ // =========================
36
+ let {
37
+ value,
38
+ variant,
39
+ onCommit,
40
+ ariaLabel,
41
+ readonly = false,
42
+ selected = false,
43
+ color,
44
+ fontSize,
45
+ fontWeight,
46
+ center = false,
47
+ column = false,
48
+ onExit,
49
+ }: Props = $props();
50
50
 
51
- // =========================
52
- // STATE
53
- // =========================
54
- const Field = useTextField();
55
- const handDrawn = useHandDrawn();
56
- let textarea = $state<HTMLTextAreaElement>();
57
- let field = $state<TextFieldHandle>();
58
- let editing = $state(false);
51
+ // =========================
52
+ // STATE
53
+ // =========================
54
+ const Field = useTextField();
55
+ const handDrawn = useHandDrawn();
56
+ let textarea = $state<HTMLTextAreaElement>();
57
+ let field = $state<TextFieldHandle>();
58
+ let editing = $state(false);
59
59
 
60
- // =========================
61
- // DERIVED
62
- // =========================
63
- let style = $derived(
64
- [color && `color: ${color}`, fontSize && `font-size: ${fontSize}px`, fontWeight && `font-weight: ${fontWeight}`, center && "text-align: center"]
65
- .filter(Boolean)
66
- .join("; "),
67
- );
60
+ // =========================
61
+ // DERIVED
62
+ // =========================
63
+ let style = $derived(
64
+ [
65
+ color && `color: ${color}`,
66
+ fontSize && `font-size: ${fontSize}px`,
67
+ fontWeight && `font-weight: ${fontWeight}`,
68
+ center && "text-align: center",
69
+ ]
70
+ .filter(Boolean)
71
+ .join("; "),
72
+ );
68
73
 
69
- // =========================
70
- // FUNCTIONS
71
- // =========================
72
- /** Open the field for typing. A host field opens where `point` landed, else at the end. */
73
- export function edit(point?: { x: number; y: number }) {
74
- if (readonly) return;
75
- if (field) return field.edit(point);
76
- textarea?.focus();
77
- }
74
+ // =========================
75
+ // FUNCTIONS
76
+ // =========================
77
+ /** Open the field for typing. A host field opens where `point` landed, else at the end. */
78
+ export function edit(point?: { x: number; y: number }) {
79
+ if (readonly) return;
80
+ if (field) return field.edit(point);
81
+ textarea?.focus();
82
+ }
78
83
 
79
- function close() {
80
- editing = false;
81
- onExit?.();
82
- }
84
+ function close() {
85
+ editing = false;
86
+ onExit?.();
87
+ }
83
88
 
84
- // A text you aren't typing in drags like any card, so a first press must not focus it.
85
- function press(event: MouseEvent) {
86
- if (variant === "text" && !editing) event.preventDefault();
87
- }
89
+ // A text you aren't typing in drags like any card, so a first press must not focus it.
90
+ function press(event: MouseEvent) {
91
+ if (variant === "text" && !editing) event.preventDefault();
92
+ }
88
93
  </script>
89
94
 
90
95
  <!-- =========================== -->
@@ -98,7 +103,9 @@ function press(event: MouseEvent) {
98
103
  {ariaLabel}
99
104
  {readonly}
100
105
  {style}
101
- class="pen-field is-{variant} is-rich {handDrawn() ? 'hand' : ''} {selected ? 'selected' : ''} {column ? 'column' : ''}"
106
+ class="pen-field is-{variant} is-rich {handDrawn() ? 'hand' : ''} {selected
107
+ ? 'selected'
108
+ : ''} {column ? 'column' : ''}"
102
109
  clickToEdit={variant === "label"}
103
110
  onExit={close}
104
111
  />
@@ -123,6 +130,5 @@ function press(event: MouseEvent) {
123
130
  // Typing must never reach the canvas shortcuts, where Delete would remove the node.
124
131
  event.stopPropagation();
125
132
  if (event.key === "Escape") event.currentTarget.blur();
126
- }}
127
- ></textarea>
133
+ }}></textarea>
128
134
  {/if}