@heyramzi/ui 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. package/package.json +7 -8
  2. package/scripts/sync-shadcn.mjs +3 -4
  3. package/src/agents/agent-avatar.svelte +604 -575
  4. package/src/agents/agent-cast.svelte +179 -183
  5. package/src/agents/demo.svelte +125 -113
  6. package/src/agents/helpers.ts +23 -17
  7. package/src/agents/index.ts +4 -4
  8. package/src/agents/page-state.ts +6 -6
  9. package/src/agents/types.ts +6 -6
  10. package/src/ai/ai-button/AiButton.svelte +4 -12
  11. package/src/ai/generation-progress/GenerationProgress.svelte +10 -3
  12. package/src/ai/prompt-input/PromptInputTextarea.svelte +1 -2
  13. package/src/ai/response/Response.css +2 -3
  14. package/src/animations/avatar-group-hover.css +2 -16
  15. package/src/animations/card-tilt.css +3 -6
  16. package/src/animations/digit-pop-in.css +2 -15
  17. package/src/animations/dropdown.css +4 -17
  18. package/src/animations/input-clear-dissolve.css +5 -18
  19. package/src/animations/input-shake.css +9 -41
  20. package/src/animations/learn-more-hover.css +17 -9
  21. package/src/animations/like-button.css +2 -4
  22. package/src/animations/page-side-by-side.css +2 -10
  23. package/src/animations/plus-menu-morph.css +2 -5
  24. package/src/animations/shimmer-text.css +5 -18
  25. package/src/animations/spinning-counter.css +2 -6
  26. package/src/animations/success-check.css +2 -15
  27. package/src/animations/thinking-states.css +2 -7
  28. package/src/brand/brand.test.ts +21 -5
  29. package/src/brand/index.ts +4 -10
  30. package/src/canvas/card/card-frame.svelte +43 -39
  31. package/src/canvas/card/resize-handles.svelte +89 -80
  32. package/src/canvas/chrome/chrome-zoom.svelte +101 -100
  33. package/src/canvas/chrome/lock-badge.svelte +8 -8
  34. package/src/canvas/chrome/side-handles.svelte +24 -19
  35. package/src/canvas/chrome/size-chip.svelte +30 -30
  36. package/src/canvas/chrome/snap-guides.svelte +20 -20
  37. package/src/canvas/components/icons/ToolIcon.svelte +8 -8
  38. package/src/canvas/components/shared/svg/PreviewSvg.svelte +19 -19
  39. package/src/canvas/components/shared/svg/ShapeOutline.svelte +71 -48
  40. package/src/canvas/components/shared/svg/StrokeNode.svelte +21 -27
  41. package/src/canvas/components/shared/svg/TextRule.svelte +25 -17
  42. package/src/canvas/edges/bend-handle.svelte +46 -46
  43. package/src/canvas/edges/edge-gradient.svelte +10 -10
  44. package/src/canvas/edges/gradient-edge.svelte +45 -29
  45. package/src/canvas/editor/lock.test.ts +6 -1
  46. package/src/canvas/editor/style.ts +7 -1
  47. package/src/canvas/headless/svg-figure.test.ts +5 -1
  48. package/src/canvas/lod/lod-switch.svelte +111 -106
  49. package/src/canvas/pen/PenField.svelte +87 -81
  50. package/src/canvas/pen/PenOverlay.svelte +127 -127
  51. package/src/canvas/pen/ShapeNode.svelte +31 -32
  52. package/src/canvas/pen/TextNode.svelte +54 -53
  53. package/src/canvas/pen/host-field.test.svelte +7 -7
  54. package/src/canvas/pen/shapes.ts +7 -1
  55. package/src/canvas/screen/GlyphIcon.svelte +22 -17
  56. package/src/canvas/screen/PartView.svelte +138 -72
  57. package/src/canvas/screen/ScreenBody.svelte +81 -60
  58. package/src/canvas/screen/ScreenCard.svelte +20 -20
  59. package/src/canvas/ui/CanvasToolbar.svelte +173 -85
  60. package/src/canvas/ui/FrameLayer.svelte +59 -59
  61. package/src/canvas/ui/PenLayer.svelte +39 -30
  62. package/src/canvas/ui/StylePanel.svelte +119 -102
  63. package/src/canvas/ui/canvas-grid.svelte +137 -129
  64. package/src/charts/animated-value.svelte +1 -1
  65. package/src/charts/area-chart.css +2 -5
  66. package/src/charts/area-chart.svelte +1 -1
  67. package/src/charts/bar-chart.css +2 -3
  68. package/src/charts/bar-chart.svelte +1 -1
  69. package/src/charts/charts.css +5 -17
  70. package/src/charts/crosshair.svelte +1 -1
  71. package/src/charts/dashboard/dashboard-empty.svelte +25 -25
  72. package/src/charts/dashboard/dashboard-section.svelte +24 -24
  73. package/src/charts/dashboard/data-panel.svelte +50 -50
  74. package/src/charts/dashboard/data-sort-head.svelte +56 -56
  75. package/src/charts/dashboard/data-table.svelte +138 -138
  76. package/src/charts/dashboard/panel-grid.svelte +30 -30
  77. package/src/charts/dashboard/period-filter.svelte +25 -25
  78. package/src/charts/dashboard/rating-chip.svelte +19 -19
  79. package/src/charts/dashboard/stat-band.svelte +32 -32
  80. package/src/charts/dashboard/stat-tile.svelte +106 -99
  81. package/src/charts/donut-chart.svelte +1 -1
  82. package/src/charts/edge-fade.svelte +1 -1
  83. package/src/charts/figure.svelte +1 -1
  84. package/src/charts/gauge-chart.css +4 -7
  85. package/src/charts/gauge-chart.svelte +1 -1
  86. package/src/charts/hover-focus.svelte +1 -1
  87. package/src/charts/legend.css +1 -3
  88. package/src/charts/legend.svelte +1 -1
  89. package/src/charts/line-chart.svelte +1 -1
  90. package/src/charts/number-chart.css +6 -9
  91. package/src/charts/number-chart.svelte +1 -1
  92. package/src/charts/reference-line.svelte +19 -19
  93. package/src/charts/reveal.svelte +1 -1
  94. package/src/charts/ring-chart.css +2 -4
  95. package/src/charts/ring-chart.svelte +1 -1
  96. package/src/charts/sparkline.svelte +5 -2
  97. package/src/charts/stat-card.svelte +1 -1
  98. package/src/charts/time-series-chart.css +2 -5
  99. package/src/charts/trend-pill.css +2 -4
  100. package/src/charts/trend-pill.svelte +1 -1
  101. package/src/components/copy/copy-button.svelte +93 -98
  102. package/src/components/copy/copy-button.test.ts +10 -2
  103. package/src/components/data-table/infinite-scroll.svelte +42 -42
  104. package/src/components/data-table/pagination.svelte +34 -22
  105. package/src/components/data-table/row-arrow.svelte +19 -16
  106. package/src/components/data-table/row-context-menu.svelte +52 -52
  107. package/src/components/data-table/sortable-head.svelte +25 -25
  108. package/src/components/data-table/table-skeleton.svelte +41 -36
  109. package/src/components/docs/doc-page.svelte +18 -9
  110. package/src/components/docs/on-this-page.svelte +16 -3
  111. package/src/components/docs/scroll-spy.svelte.ts +2 -3
  112. package/src/components/field-row/field-row.svelte +10 -8
  113. package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
  114. package/src/components/icon/icon.svelte +14 -14
  115. package/src/components/language-flag/language-flag.svelte +3 -1
  116. package/src/components/list-page/detail-empty.svelte +34 -34
  117. package/src/components/list-page/detail-header.svelte +55 -47
  118. package/src/components/list-page/detail-panel.svelte +51 -59
  119. package/src/components/list-page/detail-row.svelte +19 -19
  120. package/src/components/list-page/detail-stack.svelte +21 -21
  121. package/src/components/list-page/empty-state.svelte +30 -30
  122. package/src/components/list-page/filter-item.svelte +20 -20
  123. package/src/components/list-page/filter-popover.svelte +60 -55
  124. package/src/components/list-page/grouped-list.svelte +4 -2
  125. package/src/components/list-page/index.ts +5 -1
  126. package/src/components/list-page/list-page-shell.svelte +2 -5
  127. package/src/components/list-page/master-detail.svelte +87 -88
  128. package/src/components/list-page/notice-bar.svelte +38 -38
  129. package/src/components/list-page/prev-next.svelte +63 -63
  130. package/src/components/list-page/rail-body.svelte +18 -18
  131. package/src/components/list-page/rail-empty.svelte +23 -30
  132. package/src/components/list-page/rail-head.svelte +24 -24
  133. package/src/components/list-page/rail-row.svelte +77 -73
  134. package/src/components/list-page/section-host.ts +2 -3
  135. package/src/components/locale-switch/locale-switch.svelte +41 -41
  136. package/src/components/mark/mark.svelte +34 -38
  137. package/src/components/open-in/index.ts +1 -5
  138. package/src/components/open-in/open-in.svelte +40 -40
  139. package/src/components/picker/mark-picker.svelte +49 -49
  140. package/src/components/picker/picker.svelte +5 -3
  141. package/src/components/section-header/section-header.test.ts +7 -1
  142. package/src/components/section-header/section-label.svelte +20 -20
  143. package/src/components/segmented/animated-tabs.svelte +31 -2
  144. package/src/components/segmented/collapse.test.ts +2 -1
  145. package/src/components/segmented/index.ts +2 -0
  146. package/src/components/segmented/segment.svelte +52 -49
  147. package/src/components/segmented/segmented-filter.svelte +79 -80
  148. package/src/components/segmented/segmented-nav.svelte +34 -40
  149. package/src/components/segmented/segmented-overflow.svelte +53 -50
  150. package/src/components/segmented/segmented-track.svelte +62 -46
  151. package/src/components/segmented/segmented.ts +2 -3
  152. package/src/components/star-rating-input/star-rating-input.svelte +103 -103
  153. package/src/components/svg/svg.svelte +4 -4
  154. package/src/components/table-view/table-view.svelte +17 -2
  155. package/src/components/table-view/table-view.test.ts +7 -1
  156. package/src/components/table-view/types.ts +11 -11
  157. package/src/components/tags-input/index.ts +13 -0
  158. package/src/components/tags-input/tags-input.svelte +305 -0
  159. package/src/components/tags-input/tags.test.ts +64 -0
  160. package/src/components/tags-input/tags.ts +142 -0
  161. package/src/components/theme/index.ts +2 -4
  162. package/src/components/theme/theme-provider.svelte +1 -3
  163. package/src/components/toolbar/toolbar-search.svelte +25 -25
  164. package/src/components/toolbar/toolbar.svelte +11 -7
  165. package/src/components/toolbar/toolbar.test.ts +10 -1
  166. package/src/design/index.css +21 -78
  167. package/src/design/polish.css +26 -35
  168. package/src/editor/editor-toolbar.svelte +104 -99
  169. package/src/editor/editor.svelte +296 -266
  170. package/src/editor/image-toolbar.svelte +20 -22
  171. package/src/editor/index.ts +1 -4
  172. package/src/editor/inline-editor.svelte +280 -238
  173. package/src/editor/markdown.ts +15 -15
  174. package/src/editor/renderer.svelte +71 -71
  175. package/src/editor/slash-menu.svelte +24 -27
  176. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +1 -1
  177. package/src/effects/image-comparison/ImageComparison.svelte +11 -1
  178. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +59 -46
  179. package/src/effects/magic-card/MagicCard.css +14 -7
  180. package/src/effects/marquee/Marquee.svelte +3 -5
  181. package/src/effects/reveal/observe.ts +0 -3
  182. package/src/effects/spotlight/Spotlight.svelte +1 -1
  183. package/src/effects/theme-toggle/ThemeToggle.css +25 -22
  184. package/src/effects/theme-toggle/ThemeToggle.svelte +6 -7
  185. package/src/gallery.test.ts +14 -4
  186. package/src/inbox/README.md +1 -3
  187. package/src/inbox/inbox.test.ts +181 -138
  188. package/src/inbox/index.ts +20 -20
  189. package/src/inbox/logic.ts +114 -111
  190. package/src/inbox/thread-inbox.svelte +227 -151
  191. package/src/inbox/types.ts +130 -108
  192. package/src/lib/theme-transition.ts +2 -4
  193. package/src/lib/tone.ts +2 -4
  194. package/src/lib/utils.ts +2 -2
  195. package/src/modules.test.ts +79 -69
  196. package/src/onboarding/define-tours.test.ts +55 -40
  197. package/src/onboarding/define-tours.ts +23 -23
  198. package/src/onboarding/demo.svelte +24 -5
  199. package/src/onboarding/index.ts +1 -8
  200. package/src/onboarding/onboarding-provider.svelte +19 -7
  201. package/src/onboarding/onboarding.svelte.ts +16 -16
  202. package/src/onboarding/pick.test.ts +61 -52
  203. package/src/onboarding/pick.ts +16 -13
  204. package/src/onboarding/stores.test.ts +80 -80
  205. package/src/onboarding/stores.ts +41 -39
  206. package/src/onboarding/tour-card.svelte +30 -5
  207. package/src/onboarding/tour-runner.svelte +12 -3
  208. package/src/onboarding/types.ts +20 -12
  209. package/src/onboarding/wait.ts +22 -22
  210. package/src/panel/side-panel.svelte +94 -93
  211. package/src/record/demo-data.ts +291 -225
  212. package/src/record/field-section.svelte +38 -34
  213. package/src/record/fields.ts +148 -96
  214. package/src/record/format.ts +63 -56
  215. package/src/record/index.ts +49 -35
  216. package/src/record/info-list.svelte +145 -114
  217. package/src/record/kinds.ts +31 -31
  218. package/src/record/logic.ts +216 -214
  219. package/src/record/next-up.svelte +45 -34
  220. package/src/record/project-list.svelte +56 -50
  221. package/src/record/record-demo.svelte +130 -110
  222. package/src/record/record-header.svelte +37 -28
  223. package/src/record/record-shell.svelte +54 -54
  224. package/src/record/record-stats.svelte +25 -25
  225. package/src/record/record-timeline.svelte +134 -114
  226. package/src/record/record.test.ts +430 -309
  227. package/src/record/steps-rail.svelte +225 -216
  228. package/src/record/types.ts +234 -215
  229. package/src/record/where-we-are.svelte +62 -58
  230. package/src/shadcn/button/button.svelte +1 -1
  231. package/src/shadcn/card/card-title.svelte +1 -5
  232. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
  233. package/src/shadcn/sheet/sheet-content.svelte +2 -4
  234. package/src/shadcn/table/table-cell.svelte +2 -3
  235. package/src/shadcn/utilities.css +3 -8
  236. package/src/slides/Controls.svelte +150 -124
  237. package/src/slides/Deck.svelte +243 -238
  238. package/src/slides/Fragment.svelte +64 -57
  239. package/src/slides/Overview.svelte +106 -101
  240. package/src/slides/Presenter.svelte +300 -266
  241. package/src/slides/Slide.svelte +185 -170
  242. package/src/slides/SlideList.svelte +16 -12
  243. package/src/slides/ambient.d.ts +1 -1
  244. package/src/slides/bridges.ts +42 -23
  245. package/src/slides/deck-controller.svelte.ts +47 -35
  246. package/src/slides/demo-slides.svelte +330 -306
  247. package/src/slides/demo.svelte +164 -160
  248. package/src/slides/export/capture.ts +20 -16
  249. package/src/slides/export/ffmpeg.ts +43 -38
  250. package/src/slides/export/index.ts +5 -5
  251. package/src/slides/export/launch.ts +3 -1
  252. package/src/slides/export/pdf.ts +30 -27
  253. package/src/slides/export/types.ts +10 -8
  254. package/src/slides/index.ts +11 -11
  255. package/src/slides/labels.ts +22 -19
  256. package/src/slides/layout.ts +9 -2
  257. package/src/slides/model.ts +4 -4
  258. package/src/slides/navigation.ts +43 -31
  259. package/src/slides/theme.css +5 -7
  260. package/src/slides/types.ts +9 -10
  261. package/src/status/define-statuses.ts +17 -24
  262. package/src/status/index.ts +5 -5
  263. package/src/status/status-badge.svelte +3 -1
  264. package/src/status/status-dot.svelte +1 -3
  265. package/src/status/status-icon.svelte +1 -1
  266. package/src/status/status-types.ts +21 -21
  267. package/src/tasks/board-order.ts +2 -4
  268. package/src/tasks/demo.svelte +189 -31
  269. package/src/tasks/detail/detail-demo.svelte +73 -13
  270. package/src/tasks/detail/detail-types.ts +45 -45
  271. package/src/tasks/detail/task-detail.svelte +40 -10
  272. package/src/tasks/detail/task-property.svelte +8 -2
  273. package/src/tasks/detail/task-thread.svelte +53 -12
  274. package/src/tasks/gantt/gantt-bar.svelte +17 -6
  275. package/src/tasks/gantt/gantt-grid.svelte +40 -9
  276. package/src/tasks/gantt/gantt-group-row.svelte +8 -2
  277. package/src/tasks/gantt/gantt-header.svelte +9 -3
  278. package/src/tasks/gantt/gantt-task-row.svelte +26 -6
  279. package/src/tasks/gantt/gantt.css +2 -1
  280. package/src/tasks/gantt/gantt.test.ts +3 -1
  281. package/src/tasks/gantt/logic.test.ts +110 -20
  282. package/src/tasks/gantt/logic.ts +42 -6
  283. package/src/tasks/inbox/inbox-card.svelte +13 -5
  284. package/src/tasks/inbox/inbox-draft.svelte +1 -1
  285. package/src/tasks/inbox/inbox-logic.ts +6 -40
  286. package/src/tasks/inbox/inbox-statuses.ts +23 -23
  287. package/src/tasks/inbox/inbox-trace.svelte +9 -3
  288. package/src/tasks/inbox/inbox-types.ts +54 -58
  289. package/src/tasks/inbox/index.ts +22 -21
  290. package/src/tasks/index.ts +49 -52
  291. package/src/tasks/kanban-board.svelte +16 -12
  292. package/src/tasks/kanban-types.ts +2 -3
  293. package/src/tasks/presets/sales.ts +6 -6
  294. package/src/tasks/task-gantt.svelte +28 -8
  295. package/src/tasks/task-list.svelte +41 -17
  296. package/src/tasks/time/duration.ts +40 -40
  297. package/src/tasks/time/time-chip.svelte +9 -2
  298. package/src/tasks/time/time-dot.svelte +1 -1
  299. package/src/tasks/time/time-ring.svelte +11 -3
  300. package/src/tasks/time/time-tracker.svelte +57 -15
  301. package/src/tasks/time/time-types.ts +57 -57
  302. package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
  303. package/src/thread/index.ts +7 -7
  304. package/src/thread/logic.ts +36 -33
  305. package/src/thread/thread.svelte +82 -16
  306. package/src/thread/thread.test.ts +58 -47
  307. package/src/thread/types.ts +68 -68
  308. package/src/tokens/craft.css +17 -53
  309. package/src/tokens/index.css +3 -13
  310. package/src/tokens/palette.css +13 -11
  311. package/src/tokens/primitives.css +10 -23
  312. package/src/tasks/inbox/inbox.svelte +0 -203
@@ -3,137 +3,159 @@ import type { InboxItem } from "../tasks/inbox/inbox-types.js";
3
3
  export type InboxActorKind = "user" | "agent";
4
4
 
5
5
  export type InboxActor = {
6
- kind: InboxActorKind;
7
- name: string;
8
- /** Image URL for a person. The host's own portrait goes through the `avatar` snippet. */
9
- avatar?: string;
6
+ kind: InboxActorKind;
7
+ name: string;
8
+ /** Image URL for a person. The host's own portrait goes through the `avatar` snippet. */
9
+ avatar?: string;
10
10
  };
11
11
 
12
- export type InboxEntryKind = "comment" | "status" | "assigned" | "mention" | "agent_response" | "proposal";
12
+ export type InboxEntryKind =
13
+ | "comment"
14
+ | "status"
15
+ | "assigned"
16
+ | "mention"
17
+ | "agent_response"
18
+ | "proposal";
13
19
 
14
20
  /** What the thread is about: one task, project or doc. Entries with the same type and id share a thread. */
15
21
  export type InboxSubject = {
16
- /** "task", "project", "doc" or whatever the host calls it. */
17
- type: string;
18
- id: string;
19
- /** The short reference, such as "TSK-7". */
20
- ref?: string;
21
- title: string;
22
- /** A status id the host draws itself, for a badge in the thread header. */
23
- status?: string;
24
- href?: string;
22
+ /** "task", "project", "doc" or whatever the host calls it. */
23
+ type: string;
24
+ id: string;
25
+ /** The short reference, such as "TSK-7". */
26
+ ref?: string;
27
+ title: string;
28
+ /** A status id the host draws itself, for a badge in the thread header. */
29
+ status?: string;
30
+ href?: string;
25
31
  };
26
32
 
27
33
  export type InboxEntry = {
28
- id: string;
29
- kind: InboxEntryKind;
30
- /** An entry with no subject id belongs to no thread and is dropped. */
31
- subject?: InboxSubject;
32
- actor: InboxActor;
33
- /** ISO timestamp. A malformed one sorts last. */
34
- at: string;
35
- read?: boolean;
36
- /** Text of a comment, a mention or an agent response. */
37
- body?: string;
38
- /** A `status` entry: where the subject moved. */
39
- status?: { from?: string; to: string };
40
- /** An `assigned` entry: who got the work. */
41
- assignee?: string;
42
- /** A `proposal` entry: the agent's ask, drawn as an InboxCard while it waits. */
43
- proposal?: InboxItem;
34
+ id: string;
35
+ kind: InboxEntryKind;
36
+ /** An entry with no subject id belongs to no thread and is dropped. */
37
+ subject?: InboxSubject;
38
+ actor: InboxActor;
39
+ /** ISO timestamp. A malformed one sorts last. */
40
+ at: string;
41
+ read?: boolean;
42
+ /** Text of a comment, a mention or an agent response. */
43
+ body?: string;
44
+ /** A `status` entry: where the subject moved. */
45
+ status?: { from?: string; to: string };
46
+ /** An `assigned` entry: who got the work. */
47
+ assignee?: string;
48
+ /** A `proposal` entry: the agent's ask, drawn as an InboxCard while it waits. */
49
+ proposal?: InboxItem;
44
50
  };
45
51
 
46
52
  export type InboxThread = {
47
- /** `type:id`, unique across subjects. */
48
- key: string;
49
- subject: InboxSubject;
50
- /** Oldest first. */
51
- entries: InboxEntry[];
52
- unread: number;
53
- /** The newest valid timestamp, as written. The raw first one when none parses. */
54
- latestAt: string;
55
- /** Proposals still waiting for a verdict, newest first. */
56
- pending: InboxEntry[];
53
+ /** `type:id`, unique across subjects. */
54
+ key: string;
55
+ subject: InboxSubject;
56
+ /** Oldest first. */
57
+ entries: InboxEntry[];
58
+ unread: number;
59
+ /** The newest valid timestamp, as written. The raw first one when none parses. */
60
+ latestAt: string;
61
+ /** Proposals still waiting for a verdict, newest first. */
62
+ pending: InboxEntry[];
57
63
  };
58
64
 
59
65
  export type InboxFilter = {
60
- /** A subject type, or "all". */
61
- type: string;
62
- /** An actor name, or "all". */
63
- who: string;
64
- /** Only threads holding a pending proposal. */
65
- needsYou: boolean;
66
+ /** A subject type, or "all". */
67
+ type: string;
68
+ /** An actor name, or "all". */
69
+ who: string;
70
+ /** Only threads holding a pending proposal. */
71
+ needsYou: boolean;
66
72
  };
67
73
 
68
74
  export const ALL = "all";
69
75
 
70
- export type InboxKey = "next" | "previous" | "toggleRead" | "snooze" | "approve" | "decline" | "steer" | "edit";
76
+ export type InboxKey =
77
+ | "next"
78
+ | "previous"
79
+ | "toggleRead"
80
+ | "snooze"
81
+ | "approve"
82
+ | "decline"
83
+ | "steer"
84
+ | "edit";
71
85
 
72
86
  export type InboxSnooze = { thread: InboxThread; until: Date };
73
87
 
74
88
  export type InboxLabels = {
75
- title: string;
76
- all: string;
77
- anyone: string;
78
- needsYou: string;
79
- empty: string;
80
- emptyNeedsYou: string;
81
- emptyFiltered: string;
82
- clearFilters: string;
83
- unread: string;
84
- markRead: string;
85
- markUnread: string;
86
- snooze: string;
87
- snoozeLater: string;
88
- snoozeTomorrow: string;
89
- snoozeNextWeek: string;
90
- selectThread: string;
91
- filterType: string;
92
- filterWho: string;
93
- agent: string;
94
- statusMoved: string;
95
- statusSet: string;
96
- assigned: string;
97
- mentioned: string;
98
- commented: string;
99
- responded: string;
100
- proposed: string;
101
- /** Keyboard hint words. */
102
- hintMove: string;
103
- hintRead: string;
104
- hintSnooze: string;
105
- hintAct: string;
89
+ title: string;
90
+ all: string;
91
+ anyone: string;
92
+ needsYou: string;
93
+ empty: string;
94
+ emptyNeedsYou: string;
95
+ emptyFiltered: string;
96
+ clearFilters: string;
97
+ unread: string;
98
+ markRead: string;
99
+ markUnread: string;
100
+ snooze: string;
101
+ snoozeLater: string;
102
+ snoozeTomorrow: string;
103
+ snoozeNextWeek: string;
104
+ selectThread: string;
105
+ filterType: string;
106
+ filterWho: string;
107
+ filter: string;
108
+ kind: string;
109
+ from: string;
110
+ open: string;
111
+ agent: string;
112
+ statusMoved: string;
113
+ statusSet: string;
114
+ assigned: string;
115
+ mentioned: string;
116
+ commented: string;
117
+ responded: string;
118
+ proposed: string;
119
+ /** Keyboard hint words. */
120
+ hintMove: string;
121
+ hintRead: string;
122
+ hintSnooze: string;
123
+ hintAct: string;
106
124
  };
107
125
 
108
126
  export const DEFAULT_INBOX_LABELS: InboxLabels = {
109
- title: "Inbox",
110
- all: "All",
111
- anyone: "Anyone",
112
- needsYou: "Needs you",
113
- empty: "Nothing here",
114
- emptyNeedsYou: "Nothing is waiting on you",
115
- emptyFiltered: "No thread matches these filters",
116
- clearFilters: "Clear filters",
117
- unread: "unread",
118
- markRead: "Mark read",
119
- markUnread: "Mark unread",
120
- snooze: "Snooze",
121
- snoozeLater: "Later today",
122
- snoozeTomorrow: "Tomorrow",
123
- snoozeNextWeek: "Next week",
124
- selectThread: "Select a thread",
125
- filterType: "Filter by type",
126
- filterWho: "Filter by person or agent",
127
- agent: "AI",
128
- statusMoved: "moved this from {from} to {to}",
129
- statusSet: "set this to {to}",
130
- assigned: "assigned this to {assignee}",
131
- mentioned: "mentioned you",
132
- commented: "commented",
133
- responded: "replied",
134
- proposed: "asks for your call",
135
- hintMove: "move",
136
- hintRead: "read",
137
- hintSnooze: "snooze",
138
- hintAct: "approve, decline, steer, edit",
127
+ title: "Inbox",
128
+ all: "All",
129
+ anyone: "Anyone",
130
+ needsYou: "Needs you",
131
+ empty: "Nothing here",
132
+ emptyNeedsYou: "Nothing is waiting on you",
133
+ emptyFiltered: "No thread matches these filters",
134
+ clearFilters: "Clear filters",
135
+ unread: "unread",
136
+ markRead: "Mark read",
137
+ markUnread: "Mark unread",
138
+ snooze: "Snooze",
139
+ snoozeLater: "Later today",
140
+ snoozeTomorrow: "Tomorrow",
141
+ snoozeNextWeek: "Next week",
142
+ selectThread: "Select a thread",
143
+ filterType: "Filter by type",
144
+ filterWho: "Filter by person or agent",
145
+ filter: "Filter",
146
+ kind: "Type",
147
+ from: "From",
148
+ open: "Open",
149
+ agent: "AI",
150
+ statusMoved: "moved this from {from} to {to}",
151
+ statusSet: "set this to {to}",
152
+ assigned: "assigned this to {assignee}",
153
+ mentioned: "mentioned you",
154
+ commented: "commented",
155
+ responded: "replied",
156
+ proposed: "asks for your call",
157
+ hintMove: "move",
158
+ hintRead: "read",
159
+ hintSnooze: "snooze",
160
+ hintAct: "approve, decline, steer, edit",
139
161
  };
@@ -14,10 +14,8 @@ const DEFAULT_DURATION = 400;
14
14
  const STYLE_ID = "heyramzi-reveal-theme";
15
15
 
16
16
  /**
17
- * Run `apply` inside a circular wipe that grows from the centre of the clicked
18
- * element, the element, or a point. Falls back to a plain `apply()` when the
19
- * browser has no view transitions, the user prefers reduced motion, or `skip`
20
- * is set. It adds the `::view-transition-*(root)` reset itself.
17
+ * Run `apply` inside a circular wipe from the clicked element or a point, falling back to
18
+ * plain `apply()` without view transitions, under reduced motion, or with `skip`.
21
19
  */
22
20
  export function revealTheme(
23
21
  origin: RevealOrigin,
package/src/lib/tone.ts CHANGED
@@ -1,10 +1,8 @@
1
1
  export type Tone = "neutral" | "accent" | "info" | "success" | "warning" | "destructive";
2
2
 
3
3
  /**
4
- * The severity scale, as Tailwind classes for a chip and as CSS colors for the
5
- * dot. Tokens are plain CSS variables, so a host app can retheme them. The
6
- * accent tone reads `--tone-accent` and falls back to `--color-primary`, for a
7
- * host whose primary is a neutral and whose accent is a brand color.
4
+ * The severity scale as chip classes and dot colors. Accent reads `--tone-accent` before
5
+ * `--color-primary`, for a host whose primary is a neutral.
8
6
  */
9
7
 
10
8
  export const TONE_CLASS: Record<Tone, string> = {
package/src/lib/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
- // The class merge and prop types every shadcn primitive is written against. They live here, not in
2
- // a shared utils package, so this public package installs with nothing private behind it.
1
+ // The class merge and prop types every shadcn primitive uses, kept here, not in a shared utils
2
+ // package, so this public package installs with nothing private behind it.
3
3
  import { type ClassValue, clsx } from "clsx";
4
4
  import { twMerge } from "tailwind-merge";
5
5
 
@@ -5,91 +5,101 @@ import { describe, expect, it, vi } from "vite-plus/test";
5
5
  import * as status from "./status/index.js";
6
6
  import * as panel from "./panel/index.js";
7
7
  import * as record from "./record/index.js";
8
- import * as taskInbox from "./tasks/inbox/index.js";
9
8
  import * as inbox from "./inbox/index.js";
10
9
  import * as thread from "./thread/index.js";
11
10
  import type {
12
- PanelStat as FromTasksPanelStat,
13
- SidePanelWidth as FromTasksWidth,
14
- StatusDef as FromTasksStatusDef,
15
- StatusDotVariant as FromTasksVariant,
16
- StatusId as FromTasksId,
17
- StatusMap as FromTasksMap,
18
- Statuses as FromTasksStatuses,
11
+ PanelStat as FromTasksPanelStat,
12
+ SidePanelWidth as FromTasksWidth,
13
+ StatusDef as FromTasksStatusDef,
14
+ StatusDotVariant as FromTasksVariant,
15
+ StatusId as FromTasksId,
16
+ StatusMap as FromTasksMap,
17
+ Statuses as FromTasksStatuses,
19
18
  } from "./tasks/index.js";
20
19
  import type { PanelStat, SidePanelWidth } from "./panel/index.js";
21
- import type { StatusDef, StatusDotVariant, StatusId, StatusMap, Statuses } from "./status/index.js";
20
+ import type {
21
+ StatusDef,
22
+ StatusDotVariant,
23
+ StatusId,
24
+ StatusMap,
25
+ Statuses,
26
+ } from "./status/index.js";
22
27
 
23
28
  // Both spellings of every moved type have to be the same type.
24
29
  type Same<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
25
30
  const sameTypes: [
26
- Same<PanelStat, FromTasksPanelStat>,
27
- Same<SidePanelWidth, FromTasksWidth>,
28
- Same<StatusDef, FromTasksStatusDef>,
29
- Same<StatusDotVariant, FromTasksVariant>,
30
- Same<StatusId<{ a: StatusDef }>, FromTasksId<{ a: StatusDef }>>,
31
- Same<StatusMap, FromTasksMap>,
32
- Same<Statuses, FromTasksStatuses>,
31
+ Same<PanelStat, FromTasksPanelStat>,
32
+ Same<SidePanelWidth, FromTasksWidth>,
33
+ Same<StatusDef, FromTasksStatusDef>,
34
+ Same<StatusDotVariant, FromTasksVariant>,
35
+ Same<StatusId<{ a: StatusDef }>, FromTasksId<{ a: StatusDef }>>,
36
+ Same<StatusMap, FromTasksMap>,
37
+ Same<Statuses, FromTasksStatuses>,
33
38
  ] = [true, true, true, true, true, true, true];
34
39
 
35
- const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf8")) as {
36
- exports: Record<string, string | Record<string, string>>;
40
+ const pkg = JSON.parse(
41
+ readFileSync(join(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf8"),
42
+ ) as {
43
+ exports: Record<string, string | Record<string, string>>;
37
44
  };
38
45
 
39
46
  describe("module split", () => {
40
- it("keeps every moved name on tasks, the same object as on its new module", async () => {
41
- // The kanban board reads matchMedia on import, and jsdom has none.
42
- vi.stubGlobal("matchMedia", () => ({ matches: false, addEventListener() {}, removeEventListener() {} }));
43
- const tasks = await import("./tasks/index.js");
44
- expect(sameTypes).toHaveLength(7);
45
- expect(tasks.StatusBadge).toBe(status.StatusBadge);
46
- expect(tasks.StatusDot).toBe(status.StatusDot);
47
- expect(tasks.StatusIcon).toBe(status.StatusIcon);
48
- expect(tasks.defineStatuses).toBe(status.defineStatuses);
49
- expect(tasks.StatusBadge).toBeDefined();
50
- expect(tasks.SidePanel).toBe(panel.SidePanel);
51
- expect(Object.keys(taskInbox)).toContain("Inbox");
52
- });
47
+ it("keeps every moved name on tasks, the same object as on its new module", async () => {
48
+ // The kanban board reads matchMedia on import, and jsdom has none.
49
+ vi.stubGlobal("matchMedia", () => ({
50
+ matches: false,
51
+ addEventListener() {},
52
+ removeEventListener() {},
53
+ }));
54
+ const tasks = await import("./tasks/index.js");
55
+ expect(sameTypes).toHaveLength(7);
56
+ expect(tasks.StatusBadge).toBe(status.StatusBadge);
57
+ expect(tasks.StatusDot).toBe(status.StatusDot);
58
+ expect(tasks.StatusIcon).toBe(status.StatusIcon);
59
+ expect(tasks.defineStatuses).toBe(status.defineStatuses);
60
+ expect(tasks.StatusBadge).toBeDefined();
61
+ expect(tasks.SidePanel).toBe(panel.SidePanel);
62
+ });
53
63
 
54
- it("holds the record page's names", () => {
55
- expect(record.RecordShell).toBeDefined();
56
- expect(record.DEFAULT_RECORD_LABELS).toBeDefined();
57
- });
64
+ it("holds the record page's names", () => {
65
+ expect(record.RecordShell).toBeDefined();
66
+ expect(record.DEFAULT_RECORD_LABELS).toBeDefined();
67
+ });
58
68
 
59
- it("names what the new modules export", () => {
60
- expect(thread.Thread).toBeDefined();
61
- expect(inbox.ThreadInbox).toBeDefined();
62
- expect(inbox.InboxCard).toBeDefined();
63
- expect(inbox.threadsOf).toBeTypeOf("function");
64
- });
69
+ it("names what the new modules export", () => {
70
+ expect(thread.Thread).toBeDefined();
71
+ expect(inbox.ThreadInbox).toBeDefined();
72
+ expect(inbox.InboxCard).toBeDefined();
73
+ expect(inbox.threadsOf).toBeTypeOf("function");
74
+ });
65
75
 
66
- it("resolves every export path to a file", () => {
67
- const root = join(dirname(fileURLToPath(import.meta.url)), "..");
68
- const missing: string[] = [];
69
- for (const [name, target] of Object.entries(pkg.exports)) {
70
- const path = typeof target === "string" ? target : (target.default ?? target.svelte);
71
- if (path.includes("*") || path.endsWith(".css")) continue;
72
- if (!existsSync(join(root, path))) missing.push(`${name} -> ${path}`);
73
- }
74
- expect(missing).toEqual([]);
75
- });
76
+ it("resolves every export path to a file", () => {
77
+ const root = join(dirname(fileURLToPath(import.meta.url)), "..");
78
+ const missing: string[] = [];
79
+ for (const [name, target] of Object.entries(pkg.exports)) {
80
+ const path = typeof target === "string" ? target : (target.default ?? target.svelte);
81
+ if (path.includes("*") || path.endsWith(".css")) continue;
82
+ if (!existsSync(join(root, path))) missing.push(`${name} -> ${path}`);
83
+ }
84
+ expect(missing).toEqual([]);
85
+ });
76
86
 
77
- it("keeps the old subpaths and adds the new ones", () => {
78
- for (const name of [
79
- "./tasks",
80
- "./tasks/status",
81
- "./tasks/status-dot",
82
- "./tasks/statuses",
83
- "./tasks/side-panel",
84
- "./tasks/record",
85
- "./tasks/inbox",
86
- "./status",
87
- "./panel",
88
- "./record",
89
- "./thread",
90
- "./inbox",
91
- ]) {
92
- expect(pkg.exports[name], name).toBeDefined();
93
- }
94
- });
87
+ it("keeps the old subpaths and adds the new ones", () => {
88
+ for (const name of [
89
+ "./tasks",
90
+ "./tasks/status",
91
+ "./tasks/status-dot",
92
+ "./tasks/statuses",
93
+ "./tasks/side-panel",
94
+ "./tasks/record",
95
+ "./tasks/inbox",
96
+ "./status",
97
+ "./panel",
98
+ "./record",
99
+ "./thread",
100
+ "./inbox",
101
+ ]) {
102
+ expect(pkg.exports[name], name).toBeDefined();
103
+ }
104
+ });
95
105
  });
@@ -2,49 +2,64 @@ import { describe, expect, it } from "vite-plus/test";
2
2
  import { defineTours } from "./define-tours.js";
3
3
  import type { Step, Tour } from "./types.js";
4
4
 
5
- const step = (n: number): Step => ({ target: `[data-tour="s${n}"]`, title: `Title ${n}`, body: `Body ${n}` });
5
+ const step = (n: number): Step => ({
6
+ target: `[data-tour="s${n}"]`,
7
+ title: `Title ${n}`,
8
+ body: `Body ${n}`,
9
+ });
6
10
  const steps = (count: number) => Array.from({ length: count }, (_, i) => step(i + 1));
7
11
  const board = (over: Partial<Extract<Tour, { kind: "steps" }>> = {}): Tour => ({
8
- id: "board",
9
- route: "/(app)/projects",
10
- kind: "steps",
11
- steps: steps(3),
12
- ...over,
12
+ id: "board",
13
+ route: "/(app)/projects",
14
+ kind: "steps",
15
+ steps: steps(3),
16
+ ...over,
13
17
  });
14
18
 
15
19
  describe("defineTours", () => {
16
- it("returns the tours it was given", () => {
17
- const list = [board(), { id: "home", route: "/(app)", kind: "intro", title: "Hi", body: "Welcome." } as const];
18
- expect(defineTours(list)).toBe(list);
19
- });
20
-
21
- it("rejects a repeated id", () => {
22
- expect(() => defineTours([board(), board({ route: "/(app)/other" })])).toThrow(/"board".*used twice/);
23
- });
24
-
25
- it("takes 1 to 6 steps", () => {
26
- expect(() => defineTours([board({ steps: steps(1) })])).not.toThrow();
27
- expect(() => defineTours([board({ steps: steps(6) })])).not.toThrow();
28
- expect(() => defineTours([board({ steps: [] })])).toThrow(/0 steps/);
29
- expect(() => defineTours([board({ steps: steps(7) })])).toThrow(/7 steps/);
30
- });
31
-
32
- it("rejects a route that isn't a route id", () => {
33
- expect(() => defineTours([board({ route: "projects" })])).toThrow(/not a route id/);
34
- });
35
-
36
- it("rejects a bad version", () => {
37
- expect(() => defineTours([board({ version: 0 })])).toThrow(/version/);
38
- expect(() => defineTours([board({ version: 1.5 })])).toThrow(/version/);
39
- expect(() => defineTours([board({ version: 2 })])).not.toThrow();
40
- });
41
-
42
- it("rejects a step with no target or no words", () => {
43
- expect(() => defineTours([board({ steps: [{ ...step(1), target: " " }] })])).toThrow(/step 1 has no target/);
44
- expect(() => defineTours([board({ steps: [{ ...step(1), body: "" }] })])).toThrow(/title and a body/);
45
- });
46
-
47
- it("rejects an intro with no title", () => {
48
- expect(() => defineTours([{ id: "home", route: "/(app)", kind: "intro", title: "", body: "x" }])).toThrow(/intro/);
49
- });
20
+ it("returns the tours it was given", () => {
21
+ const list = [
22
+ board(),
23
+ { id: "home", route: "/(app)", kind: "intro", title: "Hi", body: "Welcome." } as const,
24
+ ];
25
+ expect(defineTours(list)).toBe(list);
26
+ });
27
+
28
+ it("rejects a repeated id", () => {
29
+ expect(() => defineTours([board(), board({ route: "/(app)/other" })])).toThrow(
30
+ /"board".*used twice/,
31
+ );
32
+ });
33
+
34
+ it("takes 1 to 6 steps", () => {
35
+ expect(() => defineTours([board({ steps: steps(1) })])).not.toThrow();
36
+ expect(() => defineTours([board({ steps: steps(6) })])).not.toThrow();
37
+ expect(() => defineTours([board({ steps: [] })])).toThrow(/0 steps/);
38
+ expect(() => defineTours([board({ steps: steps(7) })])).toThrow(/7 steps/);
39
+ });
40
+
41
+ it("rejects a route that isn't a route id", () => {
42
+ expect(() => defineTours([board({ route: "projects" })])).toThrow(/not a route id/);
43
+ });
44
+
45
+ it("rejects a bad version", () => {
46
+ expect(() => defineTours([board({ version: 0 })])).toThrow(/version/);
47
+ expect(() => defineTours([board({ version: 1.5 })])).toThrow(/version/);
48
+ expect(() => defineTours([board({ version: 2 })])).not.toThrow();
49
+ });
50
+
51
+ it("rejects a step with no target or no words", () => {
52
+ expect(() => defineTours([board({ steps: [{ ...step(1), target: " " }] })])).toThrow(
53
+ /step 1 has no target/,
54
+ );
55
+ expect(() => defineTours([board({ steps: [{ ...step(1), body: "" }] })])).toThrow(
56
+ /title and a body/,
57
+ );
58
+ });
59
+
60
+ it("rejects an intro with no title", () => {
61
+ expect(() =>
62
+ defineTours([{ id: "home", route: "/(app)", kind: "intro", title: "", body: "x" }]),
63
+ ).toThrow(/intro/);
64
+ });
50
65
  });
@@ -1,31 +1,31 @@
1
1
  import { MAX_STEPS, type Tour } from "./types.js";
2
2
 
3
3
  function fail(id: string, problem: string): never {
4
- throw new Error(`tour "${id}": ${problem}`);
4
+ throw new Error(`tour "${id}": ${problem}`);
5
5
  }
6
6
 
7
7
  /** Returns the tours as written, after checking what a typo would hide until a user hits it. */
8
8
  export function defineTours<const T extends readonly Tour[]>(tours: T): T {
9
- const ids = new Set<string>();
10
- for (const tour of tours) {
11
- const { id } = tour;
12
- if (!id || !id.trim()) throw new Error("a tour needs an id");
13
- if (ids.has(id)) fail(id, "its id is used twice");
14
- ids.add(id);
15
- if (!tour.route.startsWith("/")) fail(id, `route "${tour.route}" is not a route id`);
16
- const version = tour.version ?? 1;
17
- if (!Number.isInteger(version) || version < 1) fail(id, "version is a whole number from 1");
18
- if (tour.kind === "intro") {
19
- if (!tour.title || !tour.body) fail(id, "an intro needs a title and a body");
20
- continue;
21
- }
22
- if (tour.steps.length < 1 || tour.steps.length > MAX_STEPS) {
23
- fail(id, `has ${tour.steps.length} steps, and a tour takes 1 to ${MAX_STEPS}`);
24
- }
25
- tour.steps.forEach((step, i) => {
26
- if (!step.target.trim()) fail(id, `step ${i + 1} has no target`);
27
- if (!step.title || !step.body) fail(id, `step ${i + 1} needs a title and a body`);
28
- });
29
- }
30
- return tours;
9
+ const ids = new Set<string>();
10
+ for (const tour of tours) {
11
+ const { id } = tour;
12
+ if (!id || !id.trim()) throw new Error("a tour needs an id");
13
+ if (ids.has(id)) fail(id, "its id is used twice");
14
+ ids.add(id);
15
+ if (!tour.route.startsWith("/")) fail(id, `route "${tour.route}" is not a route id`);
16
+ const version = tour.version ?? 1;
17
+ if (!Number.isInteger(version) || version < 1) fail(id, "version is a whole number from 1");
18
+ if (tour.kind === "intro") {
19
+ if (!tour.title || !tour.body) fail(id, "an intro needs a title and a body");
20
+ continue;
21
+ }
22
+ if (tour.steps.length < 1 || tour.steps.length > MAX_STEPS) {
23
+ fail(id, `has ${tour.steps.length} steps, and a tour takes 1 to ${MAX_STEPS}`);
24
+ }
25
+ tour.steps.forEach((step, i) => {
26
+ if (!step.target.trim()) fail(id, `step ${i + 1} has no target`);
27
+ if (!step.title || !step.body) fail(id, `step ${i + 1} needs a title and a body`);
28
+ });
29
+ }
30
+ return tours;
31
31
  }