@heyramzi/ui 2.11.0 → 2.11.2

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 (267) hide show
  1. package/dist/agents/helpers.js +38 -38
  2. package/dist/agents/page-state.js +49 -50
  3. package/dist/agents/vendor/color.js +146 -127
  4. package/dist/agents/vendor/draw.js +617 -508
  5. package/dist/agents/vendor/engine.js +698 -599
  6. package/dist/agents/vendor/mesh.js +653 -683
  7. package/dist/agents/vendor/plastic.js +3913 -3112
  8. package/dist/agents/vendor/presets.js +163 -164
  9. package/dist/agents/vendor/shapes.js +21 -20
  10. package/dist/agents/vendor/ticker.js +41 -42
  11. package/dist/agents/vendor/types.js +1 -0
  12. package/dist/agents/vendor/wear.js +1421 -1448
  13. package/dist/ai/confirmation/confirmation-context.svelte.js +6 -6
  14. package/dist/ai/confirmation/index.js +3 -1
  15. package/dist/ai/index.js +33 -0
  16. package/dist/ai/prompt-input/index.js +3 -1
  17. package/dist/ai/reasoning/index.js +3 -1
  18. package/dist/ai/reasoning/reasoning-context.svelte.js +6 -6
  19. package/dist/ai/suggestion/index.js +3 -1
  20. package/dist/ai/typing-dots/index.js +3 -1
  21. package/dist/animations/text-swap.js +24 -24
  22. package/dist/brand/index.js +54 -48
  23. package/dist/canvas/card/resize.js +5 -3
  24. package/dist/canvas/edges/edge-path.js +255 -242
  25. package/dist/canvas/editor/context-menu.js +39 -36
  26. package/dist/canvas/editor/dispatch.svelte.js +154 -151
  27. package/dist/canvas/editor/editor-context.js +7 -2
  28. package/dist/canvas/editor/editor-mode.js +1 -0
  29. package/dist/canvas/editor/frame.js +73 -76
  30. package/dist/canvas/editor/hand-context.js +5 -2
  31. package/dist/canvas/editor/history-core.js +163 -191
  32. package/dist/canvas/editor/keymap.js +95 -169
  33. package/dist/canvas/editor/layout-actions.js +143 -144
  34. package/dist/canvas/editor/lock.js +52 -51
  35. package/dist/canvas/editor/rebase.js +217 -240
  36. package/dist/canvas/editor/style.js +132 -137
  37. package/dist/canvas/editor/text-field-context.js +7 -2
  38. package/dist/canvas/editor/z-order.js +65 -70
  39. package/dist/canvas/headless/alignment.js +22 -16
  40. package/dist/canvas/headless/break-apart-find.js +286 -279
  41. package/dist/canvas/headless/break-apart-pieces.js +62 -58
  42. package/dist/canvas/headless/break-apart-plan.js +299 -325
  43. package/dist/canvas/headless/break-apart-style.js +75 -70
  44. package/dist/canvas/headless/break-apart.js +188 -181
  45. package/dist/canvas/headless/canvas-cleanup.js +78 -58
  46. package/dist/canvas/headless/edge-anchors.js +115 -116
  47. package/dist/canvas/headless/edge-memo.js +24 -22
  48. package/dist/canvas/headless/edge-serialization.js +17 -27
  49. package/dist/canvas/headless/figure-geometry.js +232 -264
  50. package/dist/canvas/headless/fit-viewport.js +84 -67
  51. package/dist/canvas/headless/grid.js +88 -86
  52. package/dist/canvas/headless/icon-node.js +44 -36
  53. package/dist/canvas/headless/index.js +1 -0
  54. package/dist/canvas/headless/linkify.js +17 -19
  55. package/dist/canvas/headless/pen-marks.js +101 -95
  56. package/dist/canvas/headless/sketch.js +231 -209
  57. package/dist/canvas/headless/snap-guides.js +99 -83
  58. package/dist/canvas/headless/svg-figure.js +133 -117
  59. package/dist/canvas/headless/table-layout.js +146 -107
  60. package/dist/canvas/index.js +2 -0
  61. package/dist/canvas/lod/lod-mode.svelte.js +20 -18
  62. package/dist/canvas/lod/render-all.svelte.js +36 -39
  63. package/dist/canvas/ops/arrange.js +78 -71
  64. package/dist/canvas/ops/ops.js +260 -255
  65. package/dist/canvas/pen/colors.js +37 -35
  66. package/dist/canvas/pen/eraser.js +28 -27
  67. package/dist/canvas/pen/geometry.js +120 -130
  68. package/dist/canvas/pen/index.js +1 -0
  69. package/dist/canvas/pen/ops.js +11 -11
  70. package/dist/canvas/pen/pen-session.js +150 -159
  71. package/dist/canvas/pen/plugin.js +107 -104
  72. package/dist/canvas/pen/shapes.js +73 -68
  73. package/dist/canvas/pen/stroke-path.js +32 -30
  74. package/dist/canvas/pen/types.js +21 -21
  75. package/dist/canvas/pen/ui.js +10 -8
  76. package/dist/canvas/plugin.js +46 -46
  77. package/dist/canvas/screen/glyphs.js +12 -11
  78. package/dist/canvas/screen/labels.js +22 -22
  79. package/dist/canvas/screen/parts.js +98 -111
  80. package/dist/canvas/screen/plugin.js +47 -56
  81. package/dist/canvas/screen/types.js +30 -35
  82. package/dist/canvas/screen/ui.js +7 -7
  83. package/dist/canvas/test-utils.js +14 -14
  84. package/dist/canvas/types.js +1 -0
  85. package/dist/canvas/ui/forward-wheel.js +24 -25
  86. package/dist/canvas/ui/icons.js +64 -131
  87. package/dist/canvas/ui/place-panel.js +58 -49
  88. package/dist/canvas/ui/shortcut-tip.js +14 -12
  89. package/dist/canvas/ui/tools.js +300 -385
  90. package/dist/charts/dashboard/chart.js +4 -0
  91. package/dist/charts/dashboard/data-table.js +11 -0
  92. package/dist/charts/dashboard/windows.js +8 -3
  93. package/dist/charts/edge-fade.js +10 -5
  94. package/dist/charts/hover-band.js +16 -11
  95. package/dist/charts/index.js +0 -1
  96. package/dist/charts/motion.js +11 -7
  97. package/dist/charts/primitives/chart-utils.js +12 -12
  98. package/dist/components/copy/clipboard.js +32 -32
  99. package/dist/components/copy/copied.svelte.js +31 -23
  100. package/dist/components/data-table/data-table.js +39 -39
  101. package/dist/components/docs/index.js +4 -0
  102. package/dist/components/docs/scroll-spy.svelte.js +73 -68
  103. package/dist/components/list-page/filter-section.js +4 -1
  104. package/dist/components/list-page/index.js +2 -0
  105. package/dist/components/list-page/list-table.js +7 -2
  106. package/dist/components/list-page/queue-rail.js +14 -0
  107. package/dist/components/list-page/section-host.js +4 -2
  108. package/dist/components/list-page/step.js +4 -3
  109. package/dist/components/list-page/types.js +1 -0
  110. package/dist/components/picker/trigger.js +48 -30
  111. package/dist/components/picker/types.js +1 -0
  112. package/dist/components/segmented/collapse.js +38 -27
  113. package/dist/components/segmented/index.js +8 -0
  114. package/dist/components/segmented/segmented.js +67 -42
  115. package/dist/components/star-rating-input/index.js +3 -1
  116. package/dist/components/table-view/types.js +1 -0
  117. package/dist/components/tags-input/tags.js +81 -69
  118. package/dist/components/theme/index.js +4 -0
  119. package/dist/components/toolbar/index.js +4 -0
  120. package/dist/components/toolbar/toolbar-trigger.js +14 -1
  121. package/dist/editor/anchors.js +17 -13
  122. package/dist/editor/block-id.js +52 -51
  123. package/dist/editor/block-ops.js +108 -80
  124. package/dist/editor/doc-blocks.js +155 -166
  125. package/dist/editor/extensions.js +139 -180
  126. package/dist/editor/index.js +4 -0
  127. package/dist/editor/markdown-test-helpers.js +4 -2
  128. package/dist/editor/markdown.js +420 -408
  129. package/dist/editor/serializer.js +204 -200
  130. package/dist/editor/slash-items.js +89 -101
  131. package/dist/editor/youtube-url.js +25 -20
  132. package/dist/effects/animated-beam/path-calculator.svelte.js +43 -38
  133. package/dist/effects/animated-beam/types.js +1 -0
  134. package/dist/effects/border-beam/css.js +92 -78
  135. package/dist/effects/border-beam/presets.js +1705 -1720
  136. package/dist/effects/border-beam/register-properties.js +43 -33
  137. package/dist/effects/border-beam/types.js +1 -0
  138. package/dist/effects/image-comparison/compare.js +3 -2
  139. package/dist/effects/image-reveal/types.js +1 -0
  140. package/dist/effects/magnetic/magnetic.js +58 -52
  141. package/dist/effects/reveal/observe.js +50 -40
  142. package/dist/effects/reveal/types.js +1 -0
  143. package/dist/effects/shader-gradient/color.js +36 -29
  144. package/dist/effects/shader-gradient/renderer.js +384 -295
  145. package/dist/effects/shader-gradient/shaders.js +31 -0
  146. package/dist/effects/shader-gradient/types.js +1 -0
  147. package/dist/icons/apple-symbol-exports.js +99 -124
  148. package/dist/icons/sf-symbols.js +357 -461
  149. package/dist/icons/trades.js +43 -28
  150. package/dist/inbox/index.js +1 -0
  151. package/dist/inbox/logic.js +126 -122
  152. package/dist/inbox/types.js +43 -43
  153. package/dist/lib/arrive.js +19 -12
  154. package/dist/lib/icon-types.js +1 -0
  155. package/dist/lib/initials.js +16 -10
  156. package/dist/lib/layout.js +5 -0
  157. package/dist/lib/panel.js +13 -0
  158. package/dist/lib/result.js +22 -22
  159. package/dist/lib/sliding-pill.js +59 -44
  160. package/dist/lib/theme-transition.js +43 -43
  161. package/dist/lib/tone.js +31 -24
  162. package/dist/lib/utils.js +3 -1
  163. package/dist/onboarding/define-tours.js +24 -23
  164. package/dist/onboarding/onboarding.svelte.js +16 -12
  165. package/dist/onboarding/pick.js +10 -6
  166. package/dist/onboarding/stores.js +40 -41
  167. package/dist/onboarding/wait.js +24 -23
  168. package/dist/panel/side-panel-types.js +1 -0
  169. package/dist/record/demo-data.js +459 -486
  170. package/dist/record/fields.js +129 -131
  171. package/dist/record/format.js +70 -82
  172. package/dist/record/gutter.js +1 -0
  173. package/dist/record/kinds.js +95 -105
  174. package/dist/record/logic.js +238 -219
  175. package/dist/record/types.js +49 -48
  176. package/dist/shadcn/accordion/index.js +3 -1
  177. package/dist/shadcn/alert/index.js +3 -1
  178. package/dist/shadcn/alert-dialog/index.js +3 -1
  179. package/dist/shadcn/attachment/index.js +3 -1
  180. package/dist/shadcn/avatar/index.js +3 -1
  181. package/dist/shadcn/breadcrumb/index.js +3 -1
  182. package/dist/shadcn/bubble/index.js +3 -1
  183. package/dist/shadcn/button/index.js +3 -1
  184. package/dist/shadcn/calendar/index.js +3 -1
  185. package/dist/shadcn/card/index.js +3 -1
  186. package/dist/shadcn/checkbox/index.js +3 -1
  187. package/dist/shadcn/code-block/index.js +3 -1
  188. package/dist/shadcn/collapsible/index.js +3 -1
  189. package/dist/shadcn/command/index.js +4 -1
  190. package/dist/shadcn/context-menu/index.js +3 -1
  191. package/dist/shadcn/dialog/index.js +3 -1
  192. package/dist/shadcn/dropdown-menu/menu-item.js +40 -20
  193. package/dist/shadcn/empty/index.js +3 -1
  194. package/dist/shadcn/field/index.js +3 -1
  195. package/dist/shadcn/hooks/highlighter.js +77 -75
  196. package/dist/shadcn/hooks/is-mobile.svelte.js +3 -3
  197. package/dist/shadcn/hooks/use-highlighted-code.svelte.js +62 -62
  198. package/dist/shadcn/input/index.js +3 -1
  199. package/dist/shadcn/kbd/index.js +3 -1
  200. package/dist/shadcn/label/index.js +3 -1
  201. package/dist/shadcn/marker/index.js +3 -1
  202. package/dist/shadcn/message/index.js +3 -1
  203. package/dist/shadcn/message-scroller/index.js +3 -1
  204. package/dist/shadcn/popover/index.js +3 -1
  205. package/dist/shadcn/progress/index.js +3 -1
  206. package/dist/shadcn/progress/tone.js +8 -7
  207. package/dist/shadcn/radio-group/index.js +3 -1
  208. package/dist/shadcn/scroll-area/index.js +3 -1
  209. package/dist/shadcn/select/index.js +3 -1
  210. package/dist/shadcn/separator/index.js +3 -1
  211. package/dist/shadcn/sheet/index.js +3 -1
  212. package/dist/shadcn/sidebar/context.svelte.js +42 -28
  213. package/dist/shadcn/sidebar/index.js +3 -1
  214. package/dist/shadcn/skeleton/index.js +3 -1
  215. package/dist/shadcn/slider/index.js +3 -1
  216. package/dist/shadcn/switch/index.js +3 -1
  217. package/dist/shadcn/table/index.js +3 -1
  218. package/dist/shadcn/tabs/index.js +3 -1
  219. package/dist/shadcn/textarea/index.js +3 -1
  220. package/dist/shadcn/toggle/index.js +3 -1
  221. package/dist/shadcn/toggle-group/index.js +3 -1
  222. package/dist/shadcn/tooltip/context.js +7 -2
  223. package/dist/shadcn/tooltip/index.js +3 -1
  224. package/dist/shadcn/trace/index.js +3 -1
  225. package/dist/slides/bridges.js +65 -59
  226. package/dist/slides/deck-controller.svelte.js +210 -207
  227. package/dist/slides/export/capture.js +66 -71
  228. package/dist/slides/export/ffmpeg.js +76 -72
  229. package/dist/slides/export/index.js +3 -0
  230. package/dist/slides/export/launch.js +9 -6
  231. package/dist/slides/export/pdf.js +60 -54
  232. package/dist/slides/export/types.js +1 -0
  233. package/dist/slides/labels.js +24 -24
  234. package/dist/slides/layout.js +39 -41
  235. package/dist/slides/model.js +9 -7
  236. package/dist/slides/navigation.js +78 -73
  237. package/dist/slides/types.js +2 -2
  238. package/dist/status/define-statuses.js +18 -14
  239. package/dist/status/status-types.js +1 -0
  240. package/dist/test-setup.js +24 -20
  241. package/dist/thread/logic.js +73 -77
  242. package/dist/thread/types.js +21 -21
  243. package/dist/work/board-order.js +94 -90
  244. package/dist/work/dates.js +16 -9
  245. package/dist/work/detail/detail-types.js +18 -18
  246. package/dist/work/docs/edited.js +32 -29
  247. package/dist/work/docs/index.js +4 -0
  248. package/dist/work/docs/labels.js +34 -34
  249. package/dist/work/docs/menu.js +113 -106
  250. package/dist/work/docs/outline.js +39 -29
  251. package/dist/work/gantt/logic.js +211 -235
  252. package/dist/work/inbox/inbox-logic.js +71 -75
  253. package/dist/work/inbox/inbox-statuses.js +75 -72
  254. package/dist/work/inbox/inbox-types.js +1 -0
  255. package/dist/work/kanban-drag.js +27 -22
  256. package/dist/work/kanban-types.js +1 -0
  257. package/dist/work/presets/sales.js +36 -32
  258. package/dist/work/reorder.js +9 -8
  259. package/dist/work/task-types.js +1 -0
  260. package/dist/work/time/duration.js +51 -46
  261. package/dist/work/time/time-types.js +23 -23
  262. package/dist/work/use-kanban-dnd.svelte.js +126 -125
  263. package/package.json +3 -1
  264. package/src/components/list-page/master-detail.svelte +3 -1
  265. package/src/components/list-page/rail-row.svelte +4 -4
  266. package/src/components/tags-input/tags-input.svelte +2 -0
  267. package/src/editor/markdown.ts +30 -35
@@ -1,174 +1,169 @@
1
1
  import { PEN_COLORS, SHAPE_NODE, STROKE_NODE, TEXT_NODE } from "../pen/types.js";
2
2
  export const FONT_SIZES = [
3
- 16,
4
- 20,
5
- 28,
6
- 40
3
+ 16,
4
+ 20,
5
+ 28,
6
+ 40
7
7
  ];
8
8
  const SHAPE_WIDTHS = [
9
- 2,
10
- 3,
11
- 5
9
+ 2,
10
+ 3,
11
+ 5
12
12
  ];
13
13
  const PEN_WIDTHS = [
14
- 2,
15
- 4,
16
- 8
14
+ 2,
15
+ 4,
16
+ 8
17
17
  ];
18
18
  const HIGHLIGHTER_WIDTHS = [
19
- 12,
20
- 20,
21
- 32
19
+ 12,
20
+ 20,
21
+ 32
22
22
  ];
23
23
  const FRAME_WIDTHS = [
24
- 1,
25
- 2,
26
- 4
24
+ 1,
25
+ 2,
26
+ 4
27
27
  ];
28
28
  const CONTROLS = {
29
- shape: [
30
- "fill",
31
- "stroke",
32
- "width"
33
- ],
34
- text: [
35
- "stroke",
36
- "fontSize",
37
- "fontWeight"
38
- ],
39
- stroke: [
40
- "stroke",
41
- "width"
42
- ],
43
- frame: [
44
- "fill",
45
- "stroke",
46
- "width"
47
- ]
29
+ shape: [
30
+ "fill",
31
+ "stroke",
32
+ "width"
33
+ ],
34
+ text: [
35
+ "stroke",
36
+ "fontSize",
37
+ "fontWeight"
38
+ ],
39
+ stroke: ["stroke", "width"],
40
+ frame: [
41
+ "fill",
42
+ "stroke",
43
+ "width"
44
+ ]
48
45
  };
49
46
  function kindOf(node, frameType) {
50
- if (node.type === SHAPE_NODE) return "shape";
51
- if (node.type === TEXT_NODE) return "text";
52
- if (node.type === STROKE_NODE) return "stroke";
53
- return node.type === frameType && node.data.frame === true ? "frame" : null;
47
+ if (node.type === SHAPE_NODE) return "shape";
48
+ if (node.type === TEXT_NODE) return "text";
49
+ if (node.type === STROKE_NODE) return "stroke";
50
+ // Only a frame from the F tool wears a fill and a line; a group draws its own colour.
51
+ return node.type === frameType && node.data.frame === true ? "frame" : null;
54
52
  }
55
53
  function widthsOf(kind, node) {
56
- if (kind === "shape") return SHAPE_WIDTHS;
57
- if (kind === "frame") return FRAME_WIDTHS;
58
- return node.data.tool === "highlighter" ? HIGHLIGHTER_WIDTHS : PEN_WIDTHS;
54
+ if (kind === "shape") return SHAPE_WIDTHS;
55
+ if (kind === "frame") return FRAME_WIDTHS;
56
+ return node.data.tool === "highlighter" ? HIGHLIGHTER_WIDTHS : PEN_WIDTHS;
59
57
  }
60
58
  function widthKey(kind) {
61
- if (kind === "stroke") return "size";
62
- return "strokeWidth";
59
+ if (kind === "stroke") return "size";
60
+ return "strokeWidth";
63
61
  }
64
62
  function colorOf(value) {
65
- return PEN_COLORS.find((color)=>color === value);
63
+ return PEN_COLORS.find((color) => color === value);
66
64
  }
67
65
  function levelOf(kind, node) {
68
- const widths = widthsOf(kind, node);
69
- const stored = Number(node.data[widthKey(kind)]);
70
- if (!Number.isFinite(stored)) return kind === "frame" ? 0 : 1;
71
- let nearest = 0;
72
- for(let at = 1; at < widths.length; at += 1){
73
- if (Math.abs(widths[at] - stored) < Math.abs(widths[nearest] - stored)) nearest = at;
74
- }
75
- return nearest;
66
+ const widths = widthsOf(kind, node);
67
+ // A frame nobody styled draws the thinnest line, and a pen mark its middle one.
68
+ const stored = Number(node.data[widthKey(kind)]);
69
+ if (!Number.isFinite(stored)) return kind === "frame" ? 0 : 1;
70
+ let nearest = 0;
71
+ for (let at = 1; at < widths.length; at += 1) {
72
+ if (Math.abs(widths[at] - stored) < Math.abs(widths[nearest] - stored)) nearest = at;
73
+ }
74
+ return nearest;
76
75
  }
76
+ /** What a card of each kind shows, given the colour it draws in. */
77
77
  const VALUES = {
78
- shape: (node, color)=>({
79
- fill: node.data.filled ? colorOf(node.data.fill) ?? color : "none",
80
- stroke: color,
81
- width: levelOf("shape", node)
82
- }),
83
- text: (node, color)=>({
84
- stroke: color,
85
- fontSize: Number(node.data.fontSize) || 20,
86
- fontWeight: node.data.fontWeight === "bold" ? "bold" : "regular"
87
- }),
88
- stroke: (node, color)=>({
89
- stroke: color,
90
- width: levelOf("stroke", node)
91
- }),
92
- frame: (node)=>({
93
- fill: colorOf(node.data.fill) ?? "none",
94
- stroke: colorOf(node.data.stroke) ?? "ink",
95
- width: levelOf("frame", node)
96
- })
78
+ shape: (node, color) => ({
79
+ fill: node.data.filled ? colorOf(node.data.fill) ?? color : "none",
80
+ stroke: color,
81
+ width: levelOf("shape", node)
82
+ }),
83
+ text: (node, color) => ({
84
+ stroke: color,
85
+ fontSize: Number(node.data.fontSize) || 20,
86
+ fontWeight: node.data.fontWeight === "bold" ? "bold" : "regular"
87
+ }),
88
+ stroke: (node, color) => ({
89
+ stroke: color,
90
+ width: levelOf("stroke", node)
91
+ }),
92
+ frame: (node) => ({
93
+ fill: colorOf(node.data.fill) ?? "none",
94
+ stroke: colorOf(node.data.stroke) ?? "ink",
95
+ width: levelOf("frame", node)
96
+ })
97
97
  };
98
98
  function valuesOf(kind, node) {
99
- return VALUES[kind](node, colorOf(node.data.color) ?? "ink");
99
+ return VALUES[kind](node, colorOf(node.data.color) ?? "ink");
100
100
  }
101
+ /** What the panel shows for a selection, or null when nothing in it takes a style. */
101
102
  export function summarizeStyle(nodes, frameType) {
102
- const controls = new Set();
103
- const seen = new Map();
104
- let widths = [];
105
- for (const node of nodes){
106
- const kind = kindOf(node, frameType);
107
- if (!kind) continue;
108
- const values = valuesOf(kind, node);
109
- for (const control of CONTROLS[kind]){
110
- controls.add(control);
111
- const set = seen.get(control) ?? new Set();
112
- set.add(values[control]);
113
- seen.set(control, set);
114
- }
115
- if (widths.length === 0 && CONTROLS[kind].includes("width")) widths = widthsOf(kind, node);
116
- }
117
- if (controls.size === 0) return null;
118
- const values = {};
119
- for (const [control, set] of seen){
120
- if (set.size === 1) Object.assign(values, {
121
- [control]: [
122
- ...set
123
- ][0]
124
- });
125
- }
126
- return {
127
- controls,
128
- values,
129
- widths
130
- };
103
+ const controls = new Set();
104
+ const seen = new Map();
105
+ let widths = [];
106
+ for (const node of nodes) {
107
+ const kind = kindOf(node, frameType);
108
+ if (!kind) continue;
109
+ const values = valuesOf(kind, node);
110
+ for (const control of CONTROLS[kind]) {
111
+ controls.add(control);
112
+ const set = seen.get(control) ?? new Set();
113
+ set.add(values[control]);
114
+ seen.set(control, set);
115
+ }
116
+ if (widths.length === 0 && CONTROLS[kind].includes("width")) widths = widthsOf(kind, node);
117
+ }
118
+ if (controls.size === 0) return null;
119
+ const values = {};
120
+ for (const [control, set] of seen) {
121
+ if (set.size === 1) Object.assign(values, { [control]: [...set][0] });
122
+ }
123
+ return {
124
+ controls,
125
+ values,
126
+ widths
127
+ };
131
128
  }
129
+ /** A frame keeps its fill as is; a shape's fill also says whether it is filled. */
132
130
  function fillData(kind, fill) {
133
- if (kind === "frame") return {
134
- fill
135
- };
136
- return fill === "none" ? {
137
- filled: false
138
- } : {
139
- filled: true,
140
- fill
141
- };
131
+ if (kind === "frame") return { fill };
132
+ return fill === "none" ? { filled: false } : {
133
+ filled: true,
134
+ fill
135
+ };
142
136
  }
143
137
  function textData(change) {
144
- const data = {};
145
- if (change.fontSize !== undefined) data.fontSize = change.fontSize;
146
- if (change.fontWeight !== undefined) data.fontWeight = change.fontWeight;
147
- return data;
138
+ const data = {};
139
+ if (change.fontSize !== undefined) data.fontSize = change.fontSize;
140
+ if (change.fontWeight !== undefined) data.fontWeight = change.fontWeight;
141
+ return data;
148
142
  }
149
143
  function dataFor(kind, node, change) {
150
- const data = {};
151
- if (change.stroke) data[kind === "frame" ? "stroke" : "color"] = change.stroke;
152
- if (change.fill !== undefined && (kind === "shape" || kind === "frame")) {
153
- Object.assign(data, fillData(kind, change.fill));
154
- }
155
- if (change.width !== undefined && kind !== "text") {
156
- data[widthKey(kind)] = widthsOf(kind, node)[change.width];
157
- }
158
- if (kind === "text") Object.assign(data, textData(change));
159
- return data;
144
+ const data = {};
145
+ if (change.stroke) data[kind === "frame" ? "stroke" : "color"] = change.stroke;
146
+ if (change.fill !== undefined && (kind === "shape" || kind === "frame")) {
147
+ Object.assign(data, fillData(kind, change.fill));
148
+ }
149
+ if (change.width !== undefined && kind !== "text") {
150
+ data[widthKey(kind)] = widthsOf(kind, node)[change.width];
151
+ }
152
+ if (kind === "text") Object.assign(data, textData(change));
153
+ return data;
160
154
  }
155
+ /** One patch per card the change applies to. All of them are one undo step when dispatched together. */
161
156
  export function styleOps(nodes, change, frameType) {
162
- const ops = [];
163
- for (const node of nodes){
164
- const kind = kindOf(node, frameType);
165
- if (!kind) continue;
166
- const data = dataFor(kind, node, change);
167
- if (Object.keys(data).length > 0) ops.push({
168
- kind: "patchNode",
169
- nodeId: node.id,
170
- data
171
- });
172
- }
173
- return ops;
157
+ const ops = [];
158
+ for (const node of nodes) {
159
+ const kind = kindOf(node, frameType);
160
+ if (!kind) continue;
161
+ const data = dataFor(kind, node, change);
162
+ if (Object.keys(data).length > 0) ops.push({
163
+ kind: "patchNode",
164
+ nodeId: node.id,
165
+ data
166
+ });
167
+ }
168
+ return ops;
174
169
  }
@@ -1,8 +1,13 @@
1
+ // The text field a host hands the pen. A plain textarea keeps the canvas MIT-clean; a host that
2
+ // formats text provides a component, set once with the page skin.
1
3
  import { getContext, setContext } from "svelte";
4
+ /** For a host that mounts a pen node with `mount(..., { context })`, as a test does. */
2
5
  export const TEXT_FIELD_KEY = Symbol("canvas-text-field");
6
+ /** Call during component init. */
3
7
  export function setTextField(component) {
4
- setContext(TEXT_FIELD_KEY, component);
8
+ setContext(TEXT_FIELD_KEY, component);
5
9
  }
10
+ /** The host's field, or null: the pen then draws its own textarea. */
6
11
  export function useTextField() {
7
- return getContext(TEXT_FIELD_KEY) ?? null;
12
+ return getContext(TEXT_FIELD_KEY) ?? null;
8
13
  }
@@ -1,82 +1,77 @@
1
+ /** Ink is an annotation layer pinned above every card by pen.css, so it has no place in a stack. */
1
2
  export const INK_TYPES = new Set([
2
- "stroke",
3
- "text",
4
- "shape"
3
+ "stroke",
4
+ "text",
5
+ "shape"
5
6
  ]);
6
7
  function layerOf(node) {
7
- return typeof node.zIndex === "number" ? node.zIndex : 0;
8
+ return typeof node.zIndex === "number" ? node.zIndex : 0;
8
9
  }
10
+ /** Cards stack among their siblings: a child never leaves its group's own stack. */
9
11
  function stacks(nodes) {
10
- const byParent = new Map();
11
- nodes.forEach((node, index)=>{
12
- if (INK_TYPES.has(node.type ?? "")) return;
13
- const key = node.parentId ?? "";
14
- const stack = byParent.get(key) ?? [];
15
- stack.push({
16
- node,
17
- index
18
- });
19
- byParent.set(key, stack);
20
- });
21
- for (const stack of byParent.values()){
22
- stack.sort((a, b)=>layerOf(a.node) - layerOf(b.node) || a.index - b.index);
23
- }
24
- return byParent;
12
+ const byParent = new Map();
13
+ nodes.forEach((node, index) => {
14
+ if (INK_TYPES.has(node.type ?? "")) return;
15
+ const key = node.parentId ?? "";
16
+ const stack = byParent.get(key) ?? [];
17
+ stack.push({
18
+ node,
19
+ index
20
+ });
21
+ byParent.set(key, stack);
22
+ });
23
+ for (const stack of byParent.values()) {
24
+ stack.sort((a, b) => layerOf(a.node) - layerOf(b.node) || a.index - b.index);
25
+ }
26
+ return byParent;
25
27
  }
28
+ /** One stack after a move, bottom first. Selected cards keep their order among themselves. */
26
29
  function moved(stack, picked, move) {
27
- const isPicked = (slot)=>picked.has(slot.node.id);
28
- if (move === "front") return [
29
- ...stack.filter((s)=>!isPicked(s)),
30
- ...stack.filter(isPicked)
31
- ];
32
- if (move === "back") return [
33
- ...stack.filter(isPicked),
34
- ...stack.filter((s)=>!isPicked(s))
35
- ];
36
- const next = [
37
- ...stack
38
- ];
39
- if (move === "forward") {
40
- for(let i = next.length - 2; i >= 0; i--){
41
- if (isPicked(next[i]) && !isPicked(next[i + 1])) [next[i], next[i + 1]] = [
42
- next[i + 1],
43
- next[i]
44
- ];
45
- }
46
- } else {
47
- for(let i = 1; i < next.length; i++){
48
- if (isPicked(next[i]) && !isPicked(next[i - 1])) [next[i], next[i - 1]] = [
49
- next[i - 1],
50
- next[i]
51
- ];
52
- }
53
- }
54
- return next;
30
+ const isPicked = (slot) => picked.has(slot.node.id);
31
+ if (move === "front") return [...stack.filter((s) => !isPicked(s)), ...stack.filter(isPicked)];
32
+ if (move === "back") return [...stack.filter(isPicked), ...stack.filter((s) => !isPicked(s))];
33
+ const next = [...stack];
34
+ // One step: each picked card trades places with the unpicked card beside it.
35
+ if (move === "forward") {
36
+ for (let i = next.length - 2; i >= 0; i--) {
37
+ if (isPicked(next[i]) && !isPicked(next[i + 1])) [next[i], next[i + 1]] = [next[i + 1], next[i]];
38
+ }
39
+ } else {
40
+ for (let i = 1; i < next.length; i++) {
41
+ if (isPicked(next[i]) && !isPicked(next[i - 1])) [next[i], next[i - 1]] = [next[i - 1], next[i]];
42
+ }
43
+ }
44
+ return next;
55
45
  }
46
+ /**
47
+ * The board after a stacking move, or null when nothing changes. Only a stack holding a
48
+ * picked card is touched, and only cards whose layer changed are rewritten.
49
+ */
56
50
  export function reorderStack(nodes, picked, move) {
57
- const layers = new Map();
58
- for (const stack of stacks(nodes).values()){
59
- if (!stack.some((slot)=>picked.has(slot.node.id))) continue;
60
- const next = moved(stack, picked, move);
61
- if (next.every((slot, i)=>slot === stack[i])) continue;
62
- next.forEach((slot, rank)=>{
63
- if (layerOf(slot.node) !== rank) layers.set(slot.node.id, rank);
64
- });
65
- }
66
- if (layers.size === 0) return null;
67
- return nodes.map((node)=>{
68
- const layer = layers.get(node.id);
69
- return layer === undefined ? node : {
70
- ...node,
71
- zIndex: layer
72
- };
73
- });
51
+ const layers = new Map();
52
+ for (const stack of stacks(nodes).values()) {
53
+ if (!stack.some((slot) => picked.has(slot.node.id))) continue;
54
+ const next = moved(stack, picked, move);
55
+ if (next.every((slot, i) => slot === stack[i])) continue;
56
+ next.forEach((slot, rank) => {
57
+ if (layerOf(slot.node) !== rank) layers.set(slot.node.id, rank);
58
+ });
59
+ }
60
+ if (layers.size === 0) return null;
61
+ return nodes.map((node) => {
62
+ const layer = layers.get(node.id);
63
+ return layer === undefined ? node : {
64
+ ...node,
65
+ zIndex: layer
66
+ };
67
+ });
74
68
  }
69
+ /** The layer a new card needs to land on top of its siblings, or undefined while no card has been raised. */
75
70
  export function topLayer(nodes, parentId) {
76
- let top = 0;
77
- for (const node of nodes){
78
- if (INK_TYPES.has(node.type ?? "") || (node.parentId ?? "") !== (parentId ?? "")) continue;
79
- top = Math.max(top, layerOf(node));
80
- }
81
- return top > 0 ? top + 1 : undefined;
71
+ let top = 0;
72
+ for (const node of nodes) {
73
+ if (INK_TYPES.has(node.type ?? "") || (node.parentId ?? "") !== (parentId ?? "")) continue;
74
+ top = Math.max(top, layerOf(node));
75
+ }
76
+ return top > 0 ? top + 1 : undefined;
82
77
  }
@@ -1,20 +1,26 @@
1
+ /**
2
+ * Align nodes horizontally (same row): set all to the topmost Y.
3
+ */
1
4
  export function alignNodesHorizontally(nodes) {
2
- if (nodes.length < 2) return;
3
- const targetY = Math.min(...nodes.map((n)=>n.position.y));
4
- for (const node of nodes){
5
- node.position = {
6
- ...node.position,
7
- y: targetY
8
- };
9
- }
5
+ if (nodes.length < 2) return;
6
+ const targetY = Math.min(...nodes.map((n) => n.position.y));
7
+ for (const node of nodes) {
8
+ node.position = {
9
+ ...node.position,
10
+ y: targetY
11
+ };
12
+ }
10
13
  }
14
+ /**
15
+ * Align nodes vertically (same column): set all to the leftmost X.
16
+ */
11
17
  export function alignNodesVertically(nodes) {
12
- if (nodes.length < 2) return;
13
- const targetX = Math.min(...nodes.map((n)=>n.position.x));
14
- for (const node of nodes){
15
- node.position = {
16
- ...node.position,
17
- x: targetX
18
- };
19
- }
18
+ if (nodes.length < 2) return;
19
+ const targetX = Math.min(...nodes.map((n) => n.position.x));
20
+ for (const node of nodes) {
21
+ node.position = {
22
+ ...node.position,
23
+ x: targetX
24
+ };
25
+ }
20
26
  }