@heyramzi/ui 2.11.1 → 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 (266) 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/editor/markdown.ts +30 -35
@@ -1,89 +1,94 @@
1
- export const visibleIndexes = (slides)=>slides.flatMap((slide, index)=>slide.hidden ? [] : [
2
- index
3
- ]);
4
- const clamp = (value, min, max)=>Math.min(max, Math.max(min, value));
1
+ export const visibleIndexes = (slides) => slides.flatMap((slide, index) => slide.hidden ? [] : [index]);
2
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
3
+ /** Snaps a position onto a visible slide and a real step. Empty decks stay at 0, 0. */
5
4
  export function settle(slides, position) {
6
- const visible = visibleIndexes(slides);
7
- if (visible.length === 0) return {
8
- index: 0,
9
- step: 0
10
- };
11
- const index = visible.find((i)=>i >= position.index) ?? visible[visible.length - 1];
12
- return {
13
- index,
14
- step: clamp(position.step, 0, slides[index].steps)
15
- };
5
+ const visible = visibleIndexes(slides);
6
+ if (visible.length === 0) return {
7
+ index: 0,
8
+ step: 0
9
+ };
10
+ const index = visible.find((i) => i >= position.index) ?? visible[visible.length - 1];
11
+ return {
12
+ index,
13
+ step: clamp(position.step, 0, slides[index].steps)
14
+ };
16
15
  }
16
+ /** The position after one forward press, or null at the end of a deck that doesn't loop. */
17
17
  export function nextPosition(slides, from, loop = false) {
18
- const visible = visibleIndexes(slides);
19
- if (visible.length === 0) return null;
20
- if (from.step < slides[from.index].steps) return {
21
- index: from.index,
22
- step: from.step + 1
23
- };
24
- const next = visible.find((i)=>i > from.index);
25
- if (next !== undefined) return {
26
- index: next,
27
- step: 0
28
- };
29
- return loop ? {
30
- index: visible[0],
31
- step: 0
32
- } : null;
18
+ const visible = visibleIndexes(slides);
19
+ if (visible.length === 0) return null;
20
+ if (from.step < slides[from.index].steps) return {
21
+ index: from.index,
22
+ step: from.step + 1
23
+ };
24
+ const next = visible.find((i) => i > from.index);
25
+ if (next !== undefined) return {
26
+ index: next,
27
+ step: 0
28
+ };
29
+ return loop ? {
30
+ index: visible[0],
31
+ step: 0
32
+ } : null;
33
33
  }
34
+ /** The position after one back press. Landing on an earlier slide shows it fully revealed. */
34
35
  export function prevPosition(slides, from, loop = false) {
35
- const visible = visibleIndexes(slides);
36
- if (visible.length === 0) return null;
37
- if (from.step > 0) return {
38
- index: from.index,
39
- step: from.step - 1
40
- };
41
- const before = visible.filter((i)=>i < from.index);
42
- const index = before.length ? before[before.length - 1] : loop ? visible[visible.length - 1] : undefined;
43
- return index === undefined ? null : {
44
- index,
45
- step: slides[index].steps
46
- };
36
+ const visible = visibleIndexes(slides);
37
+ if (visible.length === 0) return null;
38
+ if (from.step > 0) return {
39
+ index: from.index,
40
+ step: from.step - 1
41
+ };
42
+ const before = visible.filter((i) => i < from.index);
43
+ const index = before.length ? before[before.length - 1] : loop ? visible[visible.length - 1] : undefined;
44
+ return index === undefined ? null : {
45
+ index,
46
+ step: slides[index].steps
47
+ };
47
48
  }
49
+ /** Where slide `index` sits among the visible ones, 1 based, for "3 of 12". */
48
50
  export function ordinalOf(slides, index) {
49
- const visible = visibleIndexes(slides);
50
- return {
51
- n: Math.max(0, visible.indexOf(index)) + 1,
52
- of: visible.length
53
- };
51
+ const visible = visibleIndexes(slides);
52
+ return {
53
+ n: Math.max(0, visible.indexOf(index)) + 1,
54
+ of: visible.length
55
+ };
54
56
  }
57
+ /** How far through the deck a position is, 0 to 1. A slide's fragments split its own share. */
55
58
  export function progressOf(slides, position) {
56
- const visible = visibleIndexes(slides);
57
- if (visible.length === 0) return 0;
58
- const at = Math.max(0, visible.indexOf(position.index));
59
- const steps = slides[position.index]?.steps ?? 0;
60
- const share = steps > 0 ? (position.step + 1) / (steps + 1) : 1;
61
- return (at + share) / visible.length;
59
+ const visible = visibleIndexes(slides);
60
+ if (visible.length === 0) return 0;
61
+ const at = Math.max(0, visible.indexOf(position.index));
62
+ const steps = slides[position.index]?.steps ?? 0;
63
+ const share = steps > 0 ? (position.step + 1) / (steps + 1) : 1;
64
+ return (at + share) / visible.length;
62
65
  }
66
+ /** Reads `?s=` as a zero based index. Anything that isn't a whole number in range is null. */
63
67
  export function parseSlideParam(raw, total) {
64
- if (!raw || !/^\d+$/.test(raw)) return null;
65
- const index = Number(raw) - 1;
66
- return index >= 0 && index < total ? index : null;
68
+ if (!raw || !/^\d+$/.test(raw)) return null;
69
+ const index = Number(raw) - 1;
70
+ return index >= 0 && index < total ? index : null;
67
71
  }
68
72
  const KEYS = {
69
- ArrowRight: "next",
70
- PageDown: "next",
71
- ArrowLeft: "prev",
72
- PageUp: "prev",
73
- ArrowUp: "up",
74
- ArrowDown: "down",
75
- Home: "first",
76
- End: "last",
77
- Enter: "select",
78
- Escape: "close",
79
- o: "overview",
80
- O: "overview",
81
- f: "fullscreen",
82
- F: "fullscreen",
83
- p: "presenter",
84
- P: "presenter"
73
+ ArrowRight: "next",
74
+ PageDown: "next",
75
+ ArrowLeft: "prev",
76
+ PageUp: "prev",
77
+ ArrowUp: "up",
78
+ ArrowDown: "down",
79
+ Home: "first",
80
+ End: "last",
81
+ Enter: "select",
82
+ Escape: "close",
83
+ o: "overview",
84
+ O: "overview",
85
+ f: "fullscreen",
86
+ F: "fullscreen",
87
+ p: "presenter",
88
+ P: "presenter"
85
89
  };
90
+ /** Maps a key to what the deck does with it. Space moves forward, Shift+Space back. */
86
91
  export function keyAction(key, shift = false) {
87
- if (key === " ") return shift ? "prev" : "next";
88
- return KEYS[key] ?? null;
92
+ if (key === " ") return shift ? "prev" : "next";
93
+ return KEYS[key] ?? null;
89
94
  }
@@ -1,6 +1,6 @@
1
1
  export const DECK_KEY = Symbol("heyramzi.deck");
2
2
  export const SLIDE_KEY = Symbol("heyramzi.slide");
3
3
  export const DEFAULT_CANVAS = {
4
- w: 960,
5
- h: 540
4
+ w: 960,
5
+ h: 540
6
6
  };
@@ -1,16 +1,20 @@
1
+ /**
2
+ * Builds a status registry from a map, keeping its keys as a union so lookups stay typed:
3
+ * `defineStatuses({ draft: { label: "Draft", tone: "neutral" } })`.
4
+ */
1
5
  export function defineStatuses(map) {
2
- const lookup = map;
3
- const find = (id)=>lookup[id];
4
- return {
5
- map,
6
- ids: Object.keys(map),
7
- has: (id)=>find(id) !== undefined,
8
- get: find,
9
- label: (id)=>find(id)?.label ?? id,
10
- tone: (id)=>find(id)?.tone ?? "neutral",
11
- icon: (id)=>find(id)?.icon,
12
- variant: (id)=>find(id)?.variant ?? "open",
13
- progress: (id)=>find(id)?.progress,
14
- color: (id)=>find(id)?.color
15
- };
6
+ const lookup = map;
7
+ const find = (id) => lookup[id];
8
+ return {
9
+ map,
10
+ ids: Object.keys(map),
11
+ has: (id) => find(id) !== undefined,
12
+ get: find,
13
+ label: (id) => find(id)?.label ?? id,
14
+ tone: (id) => find(id)?.tone ?? "neutral",
15
+ icon: (id) => find(id)?.icon,
16
+ variant: (id) => find(id)?.variant ?? "open",
17
+ progress: (id) => find(id)?.progress,
18
+ color: (id) => find(id)?.color
19
+ };
16
20
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,26 +1,30 @@
1
+ // WHY a setup file and not a beforeAll: layerchart and svelte/motion call
2
+ // matchMedia while their module evaluates, which happens on import, before any hook runs. jsdom ships none of these, and bits-ui and embla measure with them.
1
3
  class ObserverStub {
2
- observe() {}
3
- unobserve() {}
4
- disconnect() {}
5
- takeRecords() {
6
- return [];
7
- }
4
+ observe() {}
5
+ unobserve() {}
6
+ disconnect() {}
7
+ takeRecords() {
8
+ return [];
9
+ }
8
10
  }
9
11
  globalThis.ResizeObserver ??= ObserverStub;
10
12
  globalThis.IntersectionObserver ??= ObserverStub;
11
- globalThis.matchMedia ??= (query)=>({
12
- matches: false,
13
- media: query,
14
- onchange: null,
15
- addEventListener () {},
16
- removeEventListener () {},
17
- addListener () {},
18
- removeListener () {},
19
- dispatchEvent: ()=>false
20
- });
13
+ globalThis.matchMedia ??= ((query) => ({
14
+ matches: false,
15
+ media: query,
16
+ onchange: null,
17
+ addEventListener() {},
18
+ removeEventListener() {},
19
+ addListener() {},
20
+ removeListener() {},
21
+ dispatchEvent: () => false
22
+ }));
23
+ // jsdom lays out nothing, so an SVG path has no length to give. The success
24
+ // check reads one to set its dash offset.
21
25
  if (globalThis.SVGElement && !("getTotalLength" in globalThis.SVGElement.prototype)) {
22
- Object.defineProperty(globalThis.SVGElement.prototype, "getTotalLength", {
23
- value: ()=>100,
24
- configurable: true
25
- });
26
+ Object.defineProperty(globalThis.SVGElement.prototype, "getTotalLength", {
27
+ value: () => 100,
28
+ configurable: true
29
+ });
26
30
  }
@@ -1,94 +1,90 @@
1
1
  import { DEFAULT_THREAD_LABELS } from "./types.js";
2
+ /** A timestamp as a number, a malformed one last. */
2
3
  function at(iso) {
3
- const ms = Date.parse(iso);
4
- return Number.isNaN(ms) ? Number.POSITIVE_INFINITY : ms;
4
+ const ms = Date.parse(iso);
5
+ return Number.isNaN(ms) ? Number.POSITIVE_INFINITY : ms;
5
6
  }
6
7
  function time(comment) {
7
- return at(comment.createdAt);
8
+ return at(comment.createdAt);
8
9
  }
10
+ /** Oldest first, a malformed timestamp last, ties in the order they came. */
9
11
  function byTime(comments) {
10
- return comments.map((comment, index)=>({
11
- comment,
12
- index
13
- })).toSorted((a, b)=>time(a.comment) - time(b.comment) || a.index - b.index).map((row)=>row.comment);
12
+ return comments.map((comment, index) => ({
13
+ comment,
14
+ index
15
+ })).toSorted((a, b) => time(a.comment) - time(b.comment) || a.index - b.index).map((row) => row.comment);
14
16
  }
17
+ /**
18
+ * Roots in time order with their replies: a reply to a reply joins the root, an orphan becomes a
19
+ * root, and a parent loop can't hang the walk.
20
+ */
15
21
  export function buildThread(comments) {
16
- const byId = new Map(comments.map((comment)=>[
17
- comment.id,
18
- comment
19
- ]));
20
- function rootOf(comment) {
21
- const seen = new Set([
22
- comment.id
23
- ]);
24
- let current = comment;
25
- for(;;){
26
- const parent = current.parentId ? byId.get(current.parentId) : undefined;
27
- if (!parent) return current;
28
- if (seen.has(parent.id)) return comment;
29
- seen.add(parent.id);
30
- current = parent;
31
- }
32
- }
33
- const replies = new Map();
34
- const roots = [];
35
- for (const comment of comments){
36
- const root = rootOf(comment);
37
- if (root.id === comment.id) roots.push(comment);
38
- else replies.set(root.id, [
39
- ...replies.get(root.id) ?? [],
40
- comment
41
- ]);
42
- }
43
- return byTime(roots).map((comment)=>({
44
- comment,
45
- replies: byTime(replies.get(comment.id) ?? [])
46
- }));
22
+ const byId = new Map(comments.map((comment) => [comment.id, comment]));
23
+ function rootOf(comment) {
24
+ const seen = new Set([comment.id]);
25
+ let current = comment;
26
+ for (;;) {
27
+ const parent = current.parentId ? byId.get(current.parentId) : undefined;
28
+ if (!parent) return current;
29
+ if (seen.has(parent.id)) return comment;
30
+ seen.add(parent.id);
31
+ current = parent;
32
+ }
33
+ }
34
+ const replies = new Map();
35
+ const roots = [];
36
+ for (const comment of comments) {
37
+ const root = rootOf(comment);
38
+ if (root.id === comment.id) roots.push(comment);
39
+ else replies.set(root.id, [...replies.get(root.id) ?? [], comment]);
40
+ }
41
+ return byTime(roots).map((comment) => ({
42
+ comment,
43
+ replies: byTime(replies.get(comment.id) ?? [])
44
+ }));
47
45
  }
46
+ /** How many conversations are resolved. */
48
47
  export function resolvedCount(nodes) {
49
- return nodes.filter((node)=>node.comment.resolved).length;
48
+ return nodes.filter((node) => node.comment.resolved).length;
50
49
  }
51
50
  export function resolveThreadLabels(overrides) {
52
- return {
53
- ...DEFAULT_THREAD_LABELS,
54
- ...overrides
55
- };
51
+ return {
52
+ ...DEFAULT_THREAD_LABELS,
53
+ ...overrides
54
+ };
56
55
  }
56
+ /** Fills `{count}` in a label, so a French host writes its own sentence. */
57
57
  export function fillCount(label, count) {
58
- return label.replaceAll("{count}", String(count));
58
+ return label.replaceAll("{count}", String(count));
59
59
  }
60
+ /** Conversations and events in time order, each run of events between two conversations as one item. */
60
61
  export function interleave(nodes, events) {
61
- const timed = [
62
- ...nodes.map((node, index)=>({
63
- at: at(node.comment.createdAt),
64
- index,
65
- node
66
- })),
67
- ...events.map((event, index)=>({
68
- at: at(event.at),
69
- index: nodes.length + index,
70
- event
71
- }))
72
- ].toSorted((a, b)=>a.at - b.at || a.index - b.index);
73
- const items = [];
74
- for (const row of timed){
75
- if ("node" in row) {
76
- items.push({
77
- type: "node",
78
- key: row.node.comment.id,
79
- node: row.node
80
- });
81
- continue;
82
- }
83
- const last = items.at(-1);
84
- if (last?.type === "events") last.events.push(row.event);
85
- else items.push({
86
- type: "events",
87
- key: row.event.id,
88
- events: [
89
- row.event
90
- ]
91
- });
92
- }
93
- return items;
62
+ const timed = [...nodes.map((node, index) => ({
63
+ at: at(node.comment.createdAt),
64
+ index,
65
+ node
66
+ })), ...events.map((event, index) => ({
67
+ at: at(event.at),
68
+ index: nodes.length + index,
69
+ event
70
+ }))].toSorted((a, b) => a.at - b.at || a.index - b.index);
71
+ const items = [];
72
+ for (const row of timed) {
73
+ if ("node" in row) {
74
+ items.push({
75
+ type: "node",
76
+ key: row.node.comment.id,
77
+ node: row.node
78
+ });
79
+ continue;
80
+ }
81
+ const last = items.at(-1);
82
+ if (last?.type === "events") last.events.push(row.event);
83
+ else items.push({
84
+ type: "events",
85
+ key: row.event.id,
86
+ events: [row.event]
87
+ });
88
+ }
89
+ return items;
94
90
  }
@@ -1,23 +1,23 @@
1
1
  export const DEFAULT_THREAD_LABELS = {
2
- title: "Activity",
3
- empty: "No comments yet",
4
- placeholder: "Leave a comment",
5
- replyPlaceholder: "Reply",
6
- send: "Comment",
7
- sending: "Sending",
8
- reply: "Reply",
9
- edit: "Edit comment",
10
- delete: "Delete comment",
11
- edited: "edited",
12
- save: "Save",
13
- cancel: "Cancel",
14
- resolve: "Resolve",
15
- unresolve: "Reopen",
16
- resolved: "Resolved",
17
- showResolved: "Show {count} resolved",
18
- hideResolved: "Hide resolved",
19
- agent: "AI",
20
- pinned: "Pinned",
21
- showMore: "Show more",
22
- showLess: "Show less"
2
+ title: "Activity",
3
+ empty: "No comments yet",
4
+ placeholder: "Leave a comment",
5
+ replyPlaceholder: "Reply",
6
+ send: "Comment",
7
+ sending: "Sending",
8
+ reply: "Reply",
9
+ edit: "Edit comment",
10
+ delete: "Delete comment",
11
+ edited: "edited",
12
+ save: "Save",
13
+ cancel: "Cancel",
14
+ resolve: "Resolve",
15
+ unresolve: "Reopen",
16
+ resolved: "Resolved",
17
+ showResolved: "Show {count} resolved",
18
+ hideResolved: "Hide resolved",
19
+ agent: "AI",
20
+ pinned: "Pinned",
21
+ showMore: "Show more",
22
+ showLess: "Show less"
23
23
  };