@heyramzi/ui 2.0.1 → 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 (341) hide show
  1. package/package.json +48 -24
  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/README.md +9 -12
  31. package/src/canvas/card/card-frame.svelte +43 -39
  32. package/src/canvas/card/resize-handles.svelte +89 -80
  33. package/src/canvas/chrome/chrome-zoom.svelte +101 -100
  34. package/src/canvas/chrome/lock-badge.svelte +8 -8
  35. package/src/canvas/chrome/side-handles.svelte +24 -19
  36. package/src/canvas/chrome/size-chip.svelte +30 -30
  37. package/src/canvas/chrome/snap-guides.svelte +20 -20
  38. package/src/canvas/components/icons/ToolIcon.svelte +8 -8
  39. package/src/canvas/components/shared/svg/PreviewSvg.svelte +19 -19
  40. package/src/canvas/components/shared/svg/ShapeOutline.svelte +71 -48
  41. package/src/canvas/components/shared/svg/StrokeNode.svelte +21 -27
  42. package/src/canvas/components/shared/svg/TextRule.svelte +25 -17
  43. package/src/canvas/edges/bend-handle.svelte +46 -46
  44. package/src/canvas/edges/edge-gradient.svelte +10 -10
  45. package/src/canvas/edges/gradient-edge.svelte +45 -29
  46. package/src/canvas/editor/lock.test.ts +6 -1
  47. package/src/canvas/editor/style.ts +7 -1
  48. package/src/canvas/headless/svg-figure.test.ts +5 -1
  49. package/src/canvas/lod/lod-switch.svelte +111 -106
  50. package/src/canvas/pen/PenField.svelte +87 -81
  51. package/src/canvas/pen/PenOverlay.svelte +127 -127
  52. package/src/canvas/pen/ShapeNode.svelte +31 -32
  53. package/src/canvas/pen/TextNode.svelte +54 -53
  54. package/src/canvas/pen/host-field.test.svelte +7 -7
  55. package/src/canvas/pen/shapes.ts +7 -1
  56. package/src/canvas/screen/GlyphIcon.svelte +22 -17
  57. package/src/canvas/screen/PartView.svelte +138 -72
  58. package/src/canvas/screen/ScreenBody.svelte +81 -60
  59. package/src/canvas/screen/ScreenCard.svelte +20 -20
  60. package/src/canvas/ui/CanvasToolbar.svelte +173 -85
  61. package/src/canvas/ui/FrameLayer.svelte +59 -59
  62. package/src/canvas/ui/PenLayer.svelte +39 -30
  63. package/src/canvas/ui/StylePanel.svelte +119 -102
  64. package/src/canvas/ui/canvas-grid.svelte +137 -129
  65. package/src/charts/animated-value.svelte +1 -1
  66. package/src/charts/area-chart.css +2 -5
  67. package/src/charts/area-chart.svelte +1 -1
  68. package/src/charts/bar-chart.css +2 -3
  69. package/src/charts/bar-chart.svelte +1 -1
  70. package/src/charts/charts.css +5 -17
  71. package/src/charts/crosshair.svelte +1 -1
  72. package/src/charts/dashboard/dashboard-empty.svelte +25 -25
  73. package/src/charts/dashboard/dashboard-section.svelte +24 -24
  74. package/src/charts/dashboard/data-panel.svelte +50 -50
  75. package/src/charts/dashboard/data-sort-head.svelte +56 -56
  76. package/src/charts/dashboard/data-table.svelte +138 -138
  77. package/src/charts/dashboard/panel-grid.svelte +30 -30
  78. package/src/charts/dashboard/period-filter.svelte +25 -25
  79. package/src/charts/dashboard/rating-chip.svelte +19 -19
  80. package/src/charts/dashboard/stat-band.svelte +32 -32
  81. package/src/charts/dashboard/stat-tile.svelte +106 -99
  82. package/src/charts/donut-chart.svelte +1 -1
  83. package/src/charts/edge-fade.svelte +1 -1
  84. package/src/charts/figure.svelte +1 -1
  85. package/src/charts/gauge-chart.css +4 -7
  86. package/src/charts/gauge-chart.svelte +1 -1
  87. package/src/charts/hover-focus.svelte +1 -1
  88. package/src/charts/legend.css +1 -3
  89. package/src/charts/legend.svelte +1 -1
  90. package/src/charts/line-chart.svelte +1 -1
  91. package/src/charts/number-chart.css +6 -9
  92. package/src/charts/number-chart.svelte +1 -1
  93. package/src/charts/reference-line.svelte +19 -19
  94. package/src/charts/reveal.svelte +1 -1
  95. package/src/charts/ring-chart.css +2 -4
  96. package/src/charts/ring-chart.svelte +1 -1
  97. package/src/charts/sparkline.svelte +5 -2
  98. package/src/charts/stat-card.svelte +1 -1
  99. package/src/charts/time-series-chart.css +2 -5
  100. package/src/charts/trend-pill.css +2 -4
  101. package/src/charts/trend-pill.svelte +1 -1
  102. package/src/components/copy/copy-button.svelte +93 -98
  103. package/src/components/copy/copy-button.test.ts +10 -2
  104. package/src/components/data-table/infinite-scroll.svelte +42 -42
  105. package/src/components/data-table/pagination.svelte +34 -22
  106. package/src/components/data-table/row-arrow.svelte +19 -16
  107. package/src/components/data-table/row-context-menu.svelte +52 -52
  108. package/src/components/data-table/sortable-head.svelte +25 -25
  109. package/src/components/data-table/table-skeleton.svelte +41 -36
  110. package/src/components/docs/doc-page.svelte +18 -9
  111. package/src/components/docs/on-this-page.svelte +16 -3
  112. package/src/components/docs/scroll-spy.svelte.ts +2 -3
  113. package/src/components/field-row/field-row.svelte +10 -8
  114. package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
  115. package/src/components/icon/icon.svelte +14 -14
  116. package/src/components/language-flag/language-flag.svelte +3 -1
  117. package/src/components/list-page/detail-empty.svelte +34 -34
  118. package/src/components/list-page/detail-header.svelte +55 -47
  119. package/src/components/list-page/detail-panel.svelte +51 -59
  120. package/src/components/list-page/detail-row.svelte +19 -19
  121. package/src/components/list-page/detail-stack.svelte +21 -21
  122. package/src/components/list-page/empty-state.svelte +30 -30
  123. package/src/components/list-page/filter-item.svelte +20 -20
  124. package/src/components/list-page/filter-popover.svelte +60 -55
  125. package/src/components/list-page/grouped-list.svelte +4 -2
  126. package/src/components/list-page/index.ts +8 -4
  127. package/src/components/list-page/list-page-shell.svelte +2 -5
  128. package/src/components/list-page/master-detail.svelte +87 -88
  129. package/src/components/list-page/notice-bar.svelte +38 -38
  130. package/src/components/list-page/prev-next.svelte +63 -63
  131. package/src/components/list-page/rail-body.svelte +18 -18
  132. package/src/components/list-page/rail-empty.svelte +23 -30
  133. package/src/components/list-page/rail-head.svelte +24 -24
  134. package/src/components/list-page/rail-row.svelte +77 -73
  135. package/src/components/list-page/section-host.ts +2 -3
  136. package/src/components/locale-switch/locale-switch.svelte +41 -41
  137. package/src/components/mark/mark.svelte +34 -38
  138. package/src/components/open-in/index.ts +1 -5
  139. package/src/components/open-in/open-in.svelte +40 -40
  140. package/src/components/picker/mark-picker.svelte +49 -49
  141. package/src/components/picker/picker.svelte +5 -3
  142. package/src/components/section-header/index.ts +1 -0
  143. package/src/components/section-header/section-header.svelte +1 -1
  144. package/src/components/section-header/section-header.test.ts +7 -1
  145. package/src/components/section-header/section-label.svelte +39 -0
  146. package/src/components/segmented/animated-tabs.svelte +31 -2
  147. package/src/components/segmented/collapse.test.ts +2 -1
  148. package/src/components/segmented/index.ts +2 -0
  149. package/src/components/segmented/segment.svelte +52 -49
  150. package/src/components/segmented/segmented-filter.svelte +79 -80
  151. package/src/components/segmented/segmented-nav.svelte +34 -40
  152. package/src/components/segmented/segmented-overflow.svelte +53 -50
  153. package/src/components/segmented/segmented-track.svelte +62 -46
  154. package/src/components/segmented/segmented.ts +2 -3
  155. package/src/components/star-rating-input/star-rating-input.svelte +103 -103
  156. package/src/components/svg/svg.svelte +4 -4
  157. package/src/components/table-view/table-view.svelte +17 -2
  158. package/src/components/table-view/table-view.test.ts +7 -1
  159. package/src/components/table-view/types.ts +11 -11
  160. package/src/components/tags-input/index.ts +13 -0
  161. package/src/components/tags-input/tags-input.svelte +305 -0
  162. package/src/components/tags-input/tags.test.ts +64 -0
  163. package/src/components/tags-input/tags.ts +142 -0
  164. package/src/components/theme/index.ts +2 -4
  165. package/src/components/theme/theme-provider.svelte +1 -3
  166. package/src/components/toolbar/index.ts +2 -0
  167. package/src/components/{list-page → toolbar}/toolbar-search.svelte +25 -25
  168. package/src/components/toolbar/toolbar.svelte +13 -9
  169. package/src/components/toolbar/toolbar.test.ts +10 -1
  170. package/src/design/index.css +21 -78
  171. package/src/design/polish.css +26 -35
  172. package/src/editor/editor-toolbar.svelte +104 -99
  173. package/src/editor/editor.svelte +296 -266
  174. package/src/editor/image-toolbar.svelte +20 -22
  175. package/src/editor/index.ts +1 -4
  176. package/src/editor/inline-editor.svelte +280 -238
  177. package/src/editor/markdown.ts +15 -15
  178. package/src/editor/renderer.svelte +71 -71
  179. package/src/editor/slash-menu.svelte +24 -27
  180. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +1 -1
  181. package/src/effects/image-comparison/ImageComparison.svelte +11 -1
  182. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +59 -46
  183. package/src/effects/magic-card/MagicCard.css +14 -7
  184. package/src/effects/marquee/Marquee.svelte +3 -5
  185. package/src/effects/reveal/observe.ts +0 -3
  186. package/src/effects/spotlight/Spotlight.svelte +1 -1
  187. package/src/effects/theme-toggle/ThemeToggle.css +25 -22
  188. package/src/effects/theme-toggle/ThemeToggle.svelte +6 -7
  189. package/src/gallery.test.ts +14 -4
  190. package/src/inbox/README.md +27 -0
  191. package/src/inbox/inbox.test.ts +214 -0
  192. package/src/inbox/index.ts +31 -0
  193. package/src/inbox/logic.ts +169 -0
  194. package/src/inbox/thread-inbox.svelte +439 -0
  195. package/src/inbox/types.ts +161 -0
  196. package/src/lib/theme-transition.ts +2 -4
  197. package/src/lib/tone.ts +2 -4
  198. package/src/lib/utils.ts +2 -2
  199. package/src/modules.test.ts +105 -0
  200. package/src/onboarding/define-tours.test.ts +55 -40
  201. package/src/onboarding/define-tours.ts +23 -23
  202. package/src/onboarding/demo.svelte +24 -5
  203. package/src/onboarding/index.ts +1 -8
  204. package/src/onboarding/onboarding-provider.svelte +19 -7
  205. package/src/onboarding/onboarding.svelte.ts +16 -16
  206. package/src/onboarding/pick.test.ts +61 -52
  207. package/src/onboarding/pick.ts +16 -13
  208. package/src/onboarding/stores.test.ts +80 -80
  209. package/src/onboarding/stores.ts +41 -39
  210. package/src/onboarding/tour-card.svelte +30 -5
  211. package/src/onboarding/tour-runner.svelte +12 -3
  212. package/src/onboarding/types.ts +20 -12
  213. package/src/onboarding/wait.ts +22 -22
  214. package/src/panel/README.md +5 -0
  215. package/src/panel/index.ts +2 -0
  216. package/src/panel/side-panel.svelte +194 -0
  217. package/src/record/README.md +3 -0
  218. package/src/record/demo-data.ts +352 -0
  219. package/src/record/field-section.svelte +57 -0
  220. package/src/record/fields.ts +194 -0
  221. package/src/record/format.ts +94 -0
  222. package/src/{tasks/record → record}/index.ts +49 -35
  223. package/src/{tasks/record → record}/info-list.svelte +145 -114
  224. package/src/record/kinds.ts +42 -0
  225. package/src/record/logic.ts +326 -0
  226. package/src/record/next-up.svelte +81 -0
  227. package/src/{tasks/record → record}/project-list.svelte +56 -50
  228. package/src/{tasks/record → record}/record-demo.svelte +130 -110
  229. package/src/{tasks/record → record}/record-header.svelte +37 -28
  230. package/src/{tasks/record → record}/record-shell.svelte +54 -54
  231. package/src/record/record-stats.svelte +48 -0
  232. package/src/record/record-timeline.svelte +251 -0
  233. package/src/record/record.test.ts +471 -0
  234. package/src/{tasks/record → record}/steps-rail.svelte +225 -216
  235. package/src/record/types.ts +299 -0
  236. package/src/record/where-we-are.svelte +125 -0
  237. package/src/shadcn/button/button.svelte +1 -1
  238. package/src/shadcn/card/card-title.svelte +1 -5
  239. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
  240. package/src/shadcn/sheet/sheet-content.svelte +2 -4
  241. package/src/shadcn/table/table-cell.svelte +2 -3
  242. package/src/shadcn/utilities.css +3 -8
  243. package/src/slides/Controls.svelte +150 -124
  244. package/src/slides/Deck.svelte +243 -238
  245. package/src/slides/Fragment.svelte +64 -57
  246. package/src/slides/Overview.svelte +106 -101
  247. package/src/slides/Presenter.svelte +300 -266
  248. package/src/slides/Slide.svelte +185 -170
  249. package/src/slides/SlideList.svelte +16 -12
  250. package/src/slides/ambient.d.ts +1 -1
  251. package/src/slides/bridges.ts +42 -23
  252. package/src/slides/deck-controller.svelte.ts +47 -35
  253. package/src/slides/demo-slides.svelte +330 -306
  254. package/src/slides/demo.svelte +164 -160
  255. package/src/slides/export/capture.ts +20 -16
  256. package/src/slides/export/ffmpeg.ts +43 -38
  257. package/src/slides/export/index.ts +5 -5
  258. package/src/slides/export/launch.ts +3 -1
  259. package/src/slides/export/pdf.ts +30 -27
  260. package/src/slides/export/types.ts +10 -8
  261. package/src/slides/index.ts +11 -11
  262. package/src/slides/labels.ts +22 -19
  263. package/src/slides/layout.ts +9 -2
  264. package/src/slides/model.ts +4 -4
  265. package/src/slides/navigation.ts +43 -31
  266. package/src/slides/theme.css +5 -7
  267. package/src/slides/types.ts +9 -10
  268. package/src/status/README.md +18 -0
  269. package/src/status/define-statuses.ts +25 -0
  270. package/src/status/index.ts +11 -0
  271. package/src/{tasks → status}/status-badge.svelte +3 -1
  272. package/src/{tasks → status}/status-dot.svelte +1 -3
  273. package/src/{tasks → status}/status-icon.svelte +1 -1
  274. package/src/status/status-types.ts +40 -0
  275. package/src/tasks/README.md +1 -1
  276. package/src/tasks/board-order.ts +2 -4
  277. package/src/tasks/demo.svelte +192 -34
  278. package/src/tasks/detail/detail-demo.svelte +75 -15
  279. package/src/tasks/detail/detail-types.ts +45 -45
  280. package/src/tasks/detail/task-detail.svelte +40 -10
  281. package/src/tasks/detail/task-property.svelte +8 -2
  282. package/src/tasks/detail/task-thread.svelte +53 -12
  283. package/src/tasks/gantt/gantt-bar.svelte +17 -6
  284. package/src/tasks/gantt/gantt-grid.svelte +40 -9
  285. package/src/tasks/gantt/gantt-group-row.svelte +8 -2
  286. package/src/tasks/gantt/gantt-header.svelte +9 -3
  287. package/src/tasks/gantt/gantt-task-row.svelte +26 -6
  288. package/src/tasks/gantt/gantt.css +2 -1
  289. package/src/tasks/gantt/gantt.test.ts +4 -2
  290. package/src/tasks/gantt/logic.test.ts +110 -20
  291. package/src/tasks/gantt/logic.ts +42 -6
  292. package/src/tasks/inbox/inbox-card.svelte +15 -7
  293. package/src/tasks/inbox/inbox-draft.svelte +1 -1
  294. package/src/tasks/inbox/inbox-logic.ts +6 -40
  295. package/src/tasks/inbox/inbox-statuses.ts +24 -24
  296. package/src/tasks/inbox/inbox-trace.svelte +9 -3
  297. package/src/tasks/inbox/inbox-types.ts +54 -58
  298. package/src/tasks/inbox/index.ts +22 -21
  299. package/src/tasks/index.ts +52 -53
  300. package/src/tasks/kanban-board.svelte +16 -12
  301. package/src/tasks/kanban-types.ts +2 -3
  302. package/src/tasks/presets/sales.ts +7 -7
  303. package/src/tasks/task-gantt.svelte +28 -8
  304. package/src/tasks/task-list.svelte +41 -17
  305. package/src/tasks/time/duration.ts +40 -40
  306. package/src/tasks/time/time-chip.svelte +9 -2
  307. package/src/tasks/time/time-dot.svelte +1 -1
  308. package/src/tasks/time/time-ring.svelte +11 -3
  309. package/src/tasks/time/time-tracker.svelte +57 -15
  310. package/src/tasks/time/time-types.ts +57 -57
  311. package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
  312. package/src/thread/README.md +31 -0
  313. package/src/thread/index.ts +12 -0
  314. package/src/thread/logic.ts +61 -0
  315. package/src/thread/thread.svelte +432 -0
  316. package/src/thread/thread.test.ts +73 -0
  317. package/src/thread/types.ts +93 -0
  318. package/src/tokens/craft.css +17 -53
  319. package/src/tokens/index.css +3 -13
  320. package/src/tokens/palette.css +13 -11
  321. package/src/tokens/primitives.css +10 -23
  322. package/src/components/list-page/section-label.svelte +0 -39
  323. package/src/tasks/define-statuses.ts +0 -32
  324. package/src/tasks/inbox/inbox.svelte +0 -203
  325. package/src/tasks/record/demo-data.ts +0 -286
  326. package/src/tasks/record/field-section.svelte +0 -53
  327. package/src/tasks/record/fields.ts +0 -142
  328. package/src/tasks/record/format.ts +0 -87
  329. package/src/tasks/record/kinds.ts +0 -42
  330. package/src/tasks/record/logic.ts +0 -324
  331. package/src/tasks/record/next-up.svelte +0 -70
  332. package/src/tasks/record/record-stats.svelte +0 -48
  333. package/src/tasks/record/record-timeline.svelte +0 -231
  334. package/src/tasks/record/record.test.ts +0 -350
  335. package/src/tasks/record/types.ts +0 -280
  336. package/src/tasks/record/where-we-are.svelte +0 -121
  337. package/src/tasks/side-panel.svelte +0 -193
  338. package/src/tasks/status-types.ts +0 -40
  339. /package/src/components/{list-page → toolbar}/toolbar-trigger.ts +0 -0
  340. /package/src/{tasks → panel}/side-panel-types.ts +0 -0
  341. /package/src/{tasks/record → record}/gutter.ts +0 -0
@@ -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>
@@ -1,78 +1,94 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { tick } from "svelte";
6
- import GlyphIcon from "./GlyphIcon.svelte";
7
- import { addItem, removeItem, setItem } from "./parts.js";
8
- import type { ScreenLabels } from "./labels.js";
9
- import type { ScreenMode, ScreenPart } from "./types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { tick } from "svelte";
6
+ import GlyphIcon from "./GlyphIcon.svelte";
7
+ import { addItem, removeItem, setItem } from "./parts.js";
8
+ import type { ScreenLabels } from "./labels.js";
9
+ import type { ScreenMode, ScreenPart } from "./types.js";
10
10
 
11
- // One kit part, drawn as grey boxes or in the board's tokens. Its words are inputs in both.
11
+ // One kit part, drawn as grey boxes or in the board's tokens. Its words are inputs in both.
12
12
 
13
- // =========================
14
- // TYPES
15
- // =========================
16
- interface Props {
17
- part: ScreenPart;
18
- mode: ScreenMode;
19
- index: number;
20
- count: number;
21
- labels: ScreenLabels;
22
- readonly?: boolean;
23
- oncommit: (patch: Partial<Omit<ScreenPart, "id" | "kind">>, live: boolean) => void;
24
- onmove: (step: -1 | 1) => void;
25
- onremove: () => void;
26
- onend: () => void;
27
- }
13
+ // =========================
14
+ // TYPES
15
+ // =========================
16
+ interface Props {
17
+ part: ScreenPart;
18
+ mode: ScreenMode;
19
+ index: number;
20
+ count: number;
21
+ labels: ScreenLabels;
22
+ readonly?: boolean;
23
+ oncommit: (patch: Partial<Omit<ScreenPart, "id" | "kind">>, live: boolean) => void;
24
+ onmove: (step: -1 | 1) => void;
25
+ onremove: () => void;
26
+ onend: () => void;
27
+ }
28
28
 
29
- // =========================
30
- // PROPS
31
- // =========================
32
- let { part, mode, index, count, labels, readonly = false, oncommit, onmove, onremove, onend }: Props = $props();
29
+ // =========================
30
+ // PROPS
31
+ // =========================
32
+ let {
33
+ part,
34
+ mode,
35
+ index,
36
+ count,
37
+ labels,
38
+ readonly = false,
39
+ oncommit,
40
+ onmove,
41
+ onremove,
42
+ onend,
43
+ }: Props = $props();
33
44
 
34
- // =========================
35
- // STATE
36
- // =========================
37
- let root = $state<HTMLElement>();
45
+ // =========================
46
+ // STATE
47
+ // =========================
48
+ let root = $state<HTMLElement>();
38
49
 
39
- // =========================
40
- // DERIVED
41
- // =========================
42
- let items = $derived(part.items ?? []);
50
+ // =========================
51
+ // DERIVED
52
+ // =========================
53
+ let items = $derived(part.items ?? []);
43
54
 
44
- // =========================
45
- // FUNCTIONS
46
- // =========================
47
- function keep(event: KeyboardEvent) {
48
- // A key typed into a part's words is the part's, so it never reaches the board's shortcuts.
49
- event.stopPropagation();
50
- if (event.key === "Escape") (event.currentTarget as HTMLElement).blur();
51
- }
55
+ // =========================
56
+ // FUNCTIONS
57
+ // =========================
58
+ function keep(event: KeyboardEvent) {
59
+ // A key typed into a part's words is the part's, so it never reaches the board's shortcuts.
60
+ event.stopPropagation();
61
+ if (event.key === "Escape") (event.currentTarget as HTMLElement).blur();
62
+ }
52
63
 
53
- async function focusItem(at: number) {
54
- await tick();
55
- root?.querySelector<HTMLInputElement>(`[data-item="${at}"]`)?.focus();
56
- }
64
+ async function focusItem(at: number) {
65
+ await tick();
66
+ root?.querySelector<HTMLInputElement>(`[data-item="${at}"]`)?.focus();
67
+ }
57
68
 
58
- function itemKey(event: KeyboardEvent, at: number) {
59
- keep(event);
60
- if (event.key === "Enter") {
61
- event.preventDefault();
62
- oncommit({ items: [...items.slice(0, at + 1), "Item", ...items.slice(at + 1)] }, false);
63
- focusItem(at + 1);
64
- } else if (event.key === "Backspace" && items[at] === "" && items.length > 1) {
65
- event.preventDefault();
66
- oncommit({ items: removeItem(items, at) }, false);
67
- focusItem(Math.max(0, at - 1));
69
+ function itemKey(event: KeyboardEvent, at: number) {
70
+ keep(event);
71
+ if (event.key === "Enter") {
72
+ event.preventDefault();
73
+ oncommit({ items: [...items.slice(0, at + 1), "Item", ...items.slice(at + 1)] }, false);
74
+ focusItem(at + 1);
75
+ } else if (event.key === "Backspace" && items[at] === "" && items.length > 1) {
76
+ event.preventDefault();
77
+ oncommit({ items: removeItem(items, at) }, false);
78
+ focusItem(Math.max(0, at - 1));
79
+ }
68
80
  }
69
- }
70
81
  </script>
71
82
 
72
83
  <!-- =========================== -->
73
84
  <!-- MARKUP -->
74
85
  <!-- =========================== -->
75
- {#snippet words(value: string, aria: string, commit: (next: string, live: boolean) => void, cls = "")}
86
+ {#snippet words(
87
+ value: string,
88
+ aria: string,
89
+ commit: (next: string, live: boolean) => void,
90
+ cls = "",
91
+ )}
76
92
  <input
77
93
  class="cv-field nodrag {cls}"
78
94
  {value}
@@ -88,18 +104,30 @@ function itemKey(event: KeyboardEvent, at: number) {
88
104
  {#if part.kind === "header"}
89
105
  <div class="cv-header">
90
106
  <span class="cv-brand" aria-hidden="true"></span>
91
- {@render words(part.label, labels.kinds.header, (next, live) => oncommit({ label: next }, live), "cv-header-title")}
107
+ {@render words(
108
+ part.label,
109
+ labels.kinds.header,
110
+ (next, live) => oncommit({ label: next }, live),
111
+ "cv-header-title",
112
+ )}
92
113
  <span class="cv-menu" aria-hidden="true"><i></i><i></i><i></i></span>
93
114
  </div>
94
115
  {:else if part.kind === "button"}
95
116
  <div class="cv-button-row">
96
117
  <div class="cv-button is-{part.variant ?? 'primary'}">
97
- {@render words(part.label, labels.kinds.button, (next, live) => oncommit({ label: next }, live))}
118
+ {@render words(part.label, labels.kinds.button, (next, live) =>
119
+ oncommit({ label: next }, live),
120
+ )}
98
121
  </div>
99
122
  </div>
100
123
  {:else if part.kind === "input"}
101
124
  <div class="cv-input">
102
- {@render words(part.label, labels.kinds.input, (next, live) => oncommit({ label: next }, live), "cv-input-label")}
125
+ {@render words(
126
+ part.label,
127
+ labels.kinds.input,
128
+ (next, live) => oncommit({ label: next }, live),
129
+ "cv-input-label",
130
+ )}
103
131
  <div class="cv-input-box" aria-hidden="true"><i></i></div>
104
132
  </div>
105
133
  {:else if part.kind === "image"}
@@ -107,7 +135,12 @@ function itemKey(event: KeyboardEvent, at: number) {
107
135
  <div class="cv-image-box" aria-hidden="true">
108
136
  <GlyphIcon name="hills" size={60} class="cv-hills" />
109
137
  </div>
110
- {@render words(part.label, labels.kinds.image, (next, live) => oncommit({ label: next }, live), "cv-caption")}
138
+ {@render words(
139
+ part.label,
140
+ labels.kinds.image,
141
+ (next, live) => oncommit({ label: next }, live),
142
+ "cv-caption",
143
+ )}
111
144
  </div>
112
145
  {:else if part.kind === "list"}
113
146
  <ul class="cv-list">
@@ -120,12 +153,18 @@ function itemKey(event: KeyboardEvent, at: number) {
120
153
  value={item}
121
154
  {readonly}
122
155
  aria-label={labels.kinds.list}
123
- oninput={(event) => oncommit({ items: setItem(items, at, event.currentTarget.value) }, true)}
156
+ oninput={(event) =>
157
+ oncommit({ items: setItem(items, at, event.currentTarget.value) }, true)}
124
158
  onblur={onend}
125
159
  onkeydown={(event) => itemKey(event, at)}
126
160
  />
127
161
  {#if !readonly && items.length > 1}
128
- <button type="button" class="cv-mini nodrag" aria-label={labels.removeItem} onclick={() => oncommit({ items: removeItem(items, at) }, false)}>
162
+ <button
163
+ type="button"
164
+ class="cv-mini nodrag"
165
+ aria-label={labels.removeItem}
166
+ onclick={() => oncommit({ items: removeItem(items, at) }, false)}
167
+ >
129
168
  <GlyphIcon name="close" size={10} />
130
169
  </button>
131
170
  {/if}
@@ -133,7 +172,11 @@ function itemKey(event: KeyboardEvent, at: number) {
133
172
  {/each}
134
173
  {#if !readonly}
135
174
  <li class="cv-list-row is-add">
136
- <button type="button" class="cv-add-item nodrag" onclick={() => oncommit({ items: addItem(items) }, false)}>
175
+ <button
176
+ type="button"
177
+ class="cv-add-item nodrag"
178
+ onclick={() => oncommit({ items: addItem(items) }, false)}
179
+ >
137
180
  <GlyphIcon name="plus" size={10} />
138
181
  {labels.addItem}
139
182
  </button>
@@ -143,10 +186,20 @@ function itemKey(event: KeyboardEvent, at: number) {
143
186
  {:else}
144
187
  <div class="cv-modal">
145
188
  <div class="cv-modal-head">
146
- {@render words(part.label, labels.kinds.modal, (next, live) => oncommit({ label: next }, live), "cv-modal-title")}
189
+ {@render words(
190
+ part.label,
191
+ labels.kinds.modal,
192
+ (next, live) => oncommit({ label: next }, live),
193
+ "cv-modal-title",
194
+ )}
147
195
  <GlyphIcon name="close" size={10} class="cv-x" />
148
196
  </div>
149
- {@render words(part.text ?? "", labels.kinds.modal, (next, live) => oncommit({ text: next }, live), "cv-modal-text")}
197
+ {@render words(
198
+ part.text ?? "",
199
+ labels.kinds.modal,
200
+ (next, live) => oncommit({ text: next }, live),
201
+ "cv-modal-text",
202
+ )}
150
203
  </div>
151
204
  {/if}
152
205
 
@@ -157,15 +210,28 @@ function itemKey(event: KeyboardEvent, at: number) {
157
210
  type="button"
158
211
  class="cv-tool is-text"
159
212
  aria-pressed={part.variant !== "secondary"}
160
- onclick={() => oncommit({ variant: part.variant === "secondary" ? "primary" : "secondary" }, false)}
213
+ onclick={() =>
214
+ oncommit({ variant: part.variant === "secondary" ? "primary" : "secondary" }, false)}
161
215
  >
162
216
  {part.variant === "secondary" ? labels.secondary : labels.primary}
163
217
  </button>
164
218
  {/if}
165
- <button type="button" class="cv-tool" aria-label={labels.moveUp} disabled={index === 0} onclick={() => onmove(-1)}>
219
+ <button
220
+ type="button"
221
+ class="cv-tool"
222
+ aria-label={labels.moveUp}
223
+ disabled={index === 0}
224
+ onclick={() => onmove(-1)}
225
+ >
166
226
  <GlyphIcon name="up" />
167
227
  </button>
168
- <button type="button" class="cv-tool" aria-label={labels.moveDown} disabled={index === count - 1} onclick={() => onmove(1)}>
228
+ <button
229
+ type="button"
230
+ class="cv-tool"
231
+ aria-label={labels.moveDown}
232
+ disabled={index === count - 1}
233
+ onclick={() => onmove(1)}
234
+ >
169
235
  <GlyphIcon name="down" />
170
236
  </button>
171
237
  <button type="button" class="cv-tool" aria-label={labels.remove} onclick={onremove}>
@@ -1,72 +1,88 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { getDiagramEditorContext } from "../editor/editor-context.js";
6
- import { isLocked } from "../editor/lock.js";
7
- import { DEFAULT_SCREEN_LABELS, type ScreenLabels } from "./labels.js";
8
- import { addPart, movePart, normalizeScreen, patchPart, removePart } from "./parts.js";
9
- import GlyphIcon from "./GlyphIcon.svelte";
10
- import PartView from "./PartView.svelte";
11
- import { PART_KINDS, SCREEN_MODES, type PartKind, type ScreenMode, type ScreenPart } from "./types.js";
12
- import "./screen.css";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { getDiagramEditorContext } from "../editor/editor-context.js";
6
+ import { isLocked } from "../editor/lock.js";
7
+ import { DEFAULT_SCREEN_LABELS, type ScreenLabels } from "./labels.js";
8
+ import {
9
+ addPart,
10
+ movePart,
11
+ normalizeScreen,
12
+ patchPart,
13
+ removePart,
14
+ } from "./parts.js";
15
+ import GlyphIcon from "./GlyphIcon.svelte";
16
+ import PartView from "./PartView.svelte";
17
+ import {
18
+ PART_KINDS,
19
+ SCREEN_MODES,
20
+ type PartKind,
21
+ type ScreenMode,
22
+ type ScreenPart,
23
+ } from "./types.js";
24
+ import "./screen.css";
13
25
 
14
- // What sits in a Screen card's frame. Every edit patches the node's `data`, so undo and
15
- // save come from the editor and nothing here keeps a copy.
26
+ // What sits in a Screen card's frame. Every edit patches the node's `data`, so undo and
27
+ // save come from the editor and nothing here keeps a copy.
16
28
 
17
- // =========================
18
- // TYPES
19
- // =========================
20
- interface Props {
21
- id: string;
22
- data: Record<string, unknown>;
23
- /** The host's translations. Missing keys fall back to English. */
24
- labels?: Partial<ScreenLabels>;
25
- }
29
+ // =========================
30
+ // TYPES
31
+ // =========================
32
+ interface Props {
33
+ id: string;
34
+ data: Record<string, unknown>;
35
+ /** The host's translations. Missing keys fall back to English. */
36
+ labels?: Partial<ScreenLabels>;
37
+ }
26
38
 
27
- // =========================
28
- // PROPS
29
- // =========================
30
- let { id, data, labels: given }: Props = $props();
39
+ // =========================
40
+ // PROPS
41
+ // =========================
42
+ let { id, data, labels: given }: Props = $props();
31
43
 
32
- // =========================
33
- // STATE
34
- // =========================
35
- const editor = getDiagramEditorContext();
36
- let tray = $state(false);
44
+ // =========================
45
+ // STATE
46
+ // =========================
47
+ const editor = getDiagramEditorContext();
48
+ let tray = $state(false);
37
49
 
38
- // =========================
39
- // DERIVED
40
- // =========================
41
- let screen = $derived(normalizeScreen(data));
42
- let labels = $derived<ScreenLabels>({
43
- ...DEFAULT_SCREEN_LABELS,
44
- ...given,
45
- modes: { ...DEFAULT_SCREEN_LABELS.modes, ...given?.modes },
46
- kinds: { ...DEFAULT_SCREEN_LABELS.kinds, ...given?.kinds },
47
- });
48
- let readonly = $derived(!editor || isLocked({ data }));
49
- let showTray = $derived(!readonly && (tray || screen.parts.length === 0));
50
+ // =========================
51
+ // DERIVED
52
+ // =========================
53
+ let screen = $derived(normalizeScreen(data));
54
+ let labels = $derived<ScreenLabels>({
55
+ ...DEFAULT_SCREEN_LABELS,
56
+ ...given,
57
+ modes: { ...DEFAULT_SCREEN_LABELS.modes, ...given?.modes },
58
+ kinds: { ...DEFAULT_SCREEN_LABELS.kinds, ...given?.kinds },
59
+ });
60
+ let readonly = $derived(!editor || isLocked({ data }));
61
+ let showTray = $derived(!readonly && (tray || screen.parts.length === 0));
50
62
 
51
- // =========================
52
- // FUNCTIONS
53
- // =========================
54
- function write(patch: Record<string, unknown>, live = false) {
55
- editor?.patchNodeData(id, patch, live ? { coalesce: true } : undefined);
56
- }
63
+ // =========================
64
+ // FUNCTIONS
65
+ // =========================
66
+ function write(patch: Record<string, unknown>, live = false) {
67
+ editor?.patchNodeData(id, patch, live ? { coalesce: true } : undefined);
68
+ }
57
69
 
58
- function setMode(mode: ScreenMode) {
59
- if (mode !== screen.mode) write({ mode });
60
- }
70
+ function setMode(mode: ScreenMode) {
71
+ if (mode !== screen.mode) write({ mode });
72
+ }
61
73
 
62
- function add(kind: PartKind) {
63
- write({ parts: addPart(screen.parts, kind) });
64
- tray = false;
65
- }
74
+ function add(kind: PartKind) {
75
+ write({ parts: addPart(screen.parts, kind) });
76
+ tray = false;
77
+ }
66
78
 
67
- function commitPart(part: ScreenPart, change: Partial<Omit<ScreenPart, "id" | "kind">>, live: boolean) {
68
- write({ parts: patchPart(screen.parts, part.id, change) }, live);
69
- }
79
+ function commitPart(
80
+ part: ScreenPart,
81
+ change: Partial<Omit<ScreenPart, "id" | "kind">>,
82
+ live: boolean,
83
+ ) {
84
+ write({ parts: patchPart(screen.parts, part.id, change) }, live);
85
+ }
70
86
  </script>
71
87
 
72
88
  <!-- =========================== -->
@@ -132,7 +148,12 @@ function commitPart(part: ScreenPart, change: Partial<Omit<ScreenPart, "id" | "k
132
148
  {/each}
133
149
  </div>
134
150
  {:else}
135
- <button type="button" class="cv-add nodrag" data-testid="screen-add" onclick={() => (tray = true)}>
151
+ <button
152
+ type="button"
153
+ class="cv-add nodrag"
154
+ data-testid="screen-add"
155
+ onclick={() => (tray = true)}
156
+ >
136
157
  <GlyphIcon name="plus" />
137
158
  {labels.addPart}
138
159
  </button>