@joewinke/jatui 0.37.0 → 0.38.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 (266) hide show
  1. package/dist/artifact-blocks/AttachmentChip.svelte +66 -0
  2. package/dist/artifact-blocks/AttachmentChip.svelte.d.ts +7 -0
  3. package/dist/artifact-blocks/BlockComments.svelte +309 -0
  4. package/dist/artifact-blocks/BlockComments.svelte.d.ts +33 -0
  5. package/dist/artifact-blocks/BlockRenderer.svelte +674 -0
  6. package/dist/artifact-blocks/BlockRenderer.svelte.d.ts +55 -0
  7. package/dist/artifact-blocks/BlockVerdict.svelte +151 -0
  8. package/dist/artifact-blocks/BlockVerdict.svelte.d.ts +13 -0
  9. package/dist/artifact-blocks/BlocksArtifactView.svelte +1616 -0
  10. package/dist/artifact-blocks/BlocksArtifactView.svelte.d.ts +113 -0
  11. package/dist/artifact-blocks/CONTRACT.md +225 -0
  12. package/dist/artifact-blocks/CommentPill.svelte +49 -0
  13. package/dist/artifact-blocks/CommentPill.svelte.d.ts +16 -0
  14. package/dist/artifact-blocks/FoldedRounds.svelte +95 -0
  15. package/dist/artifact-blocks/FoldedRounds.svelte.d.ts +9 -0
  16. package/dist/artifact-blocks/Glyph.svelte +54 -0
  17. package/dist/artifact-blocks/Glyph.svelte.d.ts +10 -0
  18. package/dist/artifact-blocks/HistoryScrubber.svelte +500 -0
  19. package/dist/artifact-blocks/HistoryScrubber.svelte.d.ts +15 -0
  20. package/dist/artifact-blocks/Markdown.svelte +186 -0
  21. package/dist/artifact-blocks/Markdown.svelte.d.ts +30 -0
  22. package/dist/artifact-blocks/NoteComposer.svelte +31 -0
  23. package/dist/artifact-blocks/NoteComposer.svelte.d.ts +8 -0
  24. package/dist/artifact-blocks/PlainComposer.svelte +200 -0
  25. package/dist/artifact-blocks/PlainComposer.svelte.d.ts +15 -0
  26. package/dist/artifact-blocks/SectionTools.svelte +102 -0
  27. package/dist/artifact-blocks/SectionTools.svelte.d.ts +19 -0
  28. package/dist/artifact-blocks/adapter.d.ts +13 -0
  29. package/dist/artifact-blocks/adapter.js +31 -0
  30. package/dist/artifact-blocks/autoSend.d.ts +49 -0
  31. package/dist/artifact-blocks/autoSend.js +103 -0
  32. package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte +557 -0
  33. package/dist/artifact-blocks/blocks/actions/ActionsBlock.svelte.d.ts +48 -0
  34. package/dist/artifact-blocks/blocks/actions/block.d.ts +8 -0
  35. package/dist/artifact-blocks/blocks/actions/block.js +74 -0
  36. package/dist/artifact-blocks/blocks/actions/requests.d.ts +62 -0
  37. package/dist/artifact-blocks/blocks/actions/requests.js +26 -0
  38. package/dist/artifact-blocks/blocks/actions/schema.d.ts +168 -0
  39. package/dist/artifact-blocks/blocks/actions/schema.js +253 -0
  40. package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte +779 -0
  41. package/dist/artifact-blocks/blocks/callout/CalloutBlock.svelte.d.ts +40 -0
  42. package/dist/artifact-blocks/blocks/callout/block.d.ts +7 -0
  43. package/dist/artifact-blocks/blocks/callout/block.js +39 -0
  44. package/dist/artifact-blocks/blocks/callout/schema.d.ts +72 -0
  45. package/dist/artifact-blocks/blocks/callout/schema.js +115 -0
  46. package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte +875 -0
  47. package/dist/artifact-blocks/blocks/chart/ChartBlock.svelte.d.ts +59 -0
  48. package/dist/artifact-blocks/blocks/chart/block.d.ts +9 -0
  49. package/dist/artifact-blocks/blocks/chart/block.js +70 -0
  50. package/dist/artifact-blocks/blocks/chart/schema.d.ts +171 -0
  51. package/dist/artifact-blocks/blocks/chart/schema.js +498 -0
  52. package/dist/artifact-blocks/blocks/chart/thumb.d.ts +2 -0
  53. package/dist/artifact-blocks/blocks/chart/thumb.js +201 -0
  54. package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte +1048 -0
  55. package/dist/artifact-blocks/blocks/checklist/ChecklistBlock.svelte.d.ts +16 -0
  56. package/dist/artifact-blocks/blocks/checklist/Icon.svelte +105 -0
  57. package/dist/artifact-blocks/blocks/checklist/Icon.svelte.d.ts +17 -0
  58. package/dist/artifact-blocks/blocks/checklist/block.d.ts +10 -0
  59. package/dist/artifact-blocks/blocks/checklist/block.js +63 -0
  60. package/dist/artifact-blocks/blocks/checklist/itemReview.d.ts +16 -0
  61. package/dist/artifact-blocks/blocks/checklist/itemReview.js +63 -0
  62. package/dist/artifact-blocks/blocks/checklist/labels.d.ts +62 -0
  63. package/dist/artifact-blocks/blocks/checklist/labels.js +96 -0
  64. package/dist/artifact-blocks/blocks/checklist/retest.d.ts +43 -0
  65. package/dist/artifact-blocks/blocks/checklist/retest.js +68 -0
  66. package/dist/artifact-blocks/blocks/checklist/schema.d.ts +84 -0
  67. package/dist/artifact-blocks/blocks/checklist/schema.js +91 -0
  68. package/dist/artifact-blocks/blocks/code/CodeBlock.svelte +128 -0
  69. package/dist/artifact-blocks/blocks/code/CodeBlock.svelte.d.ts +12 -0
  70. package/dist/artifact-blocks/blocks/code/block.d.ts +8 -0
  71. package/dist/artifact-blocks/blocks/code/block.js +31 -0
  72. package/dist/artifact-blocks/blocks/code/highlight.d.ts +34 -0
  73. package/dist/artifact-blocks/blocks/code/highlight.js +280 -0
  74. package/dist/artifact-blocks/blocks/code/schema.d.ts +32 -0
  75. package/dist/artifact-blocks/blocks/code/schema.js +39 -0
  76. package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte +290 -0
  77. package/dist/artifact-blocks/blocks/collage/CollageBlock.svelte.d.ts +29 -0
  78. package/dist/artifact-blocks/blocks/collage/block.d.ts +9 -0
  79. package/dist/artifact-blocks/blocks/collage/block.js +29 -0
  80. package/dist/artifact-blocks/blocks/collage/schema.d.ts +52 -0
  81. package/dist/artifact-blocks/blocks/collage/schema.js +86 -0
  82. package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte +484 -0
  83. package/dist/artifact-blocks/blocks/compare/CompareBlock.svelte.d.ts +25 -0
  84. package/dist/artifact-blocks/blocks/compare/block.d.ts +9 -0
  85. package/dist/artifact-blocks/blocks/compare/block.js +32 -0
  86. package/dist/artifact-blocks/blocks/compare/schema.d.ts +74 -0
  87. package/dist/artifact-blocks/blocks/compare/schema.js +148 -0
  88. package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte +392 -0
  89. package/dist/artifact-blocks/blocks/diagram/DiagramBlock.svelte.d.ts +30 -0
  90. package/dist/artifact-blocks/blocks/diagram/block.d.ts +9 -0
  91. package/dist/artifact-blocks/blocks/diagram/block.js +50 -0
  92. package/dist/artifact-blocks/blocks/diagram/constants.d.ts +48 -0
  93. package/dist/artifact-blocks/blocks/diagram/constants.js +53 -0
  94. package/dist/artifact-blocks/blocks/diagram/schema.d.ts +161 -0
  95. package/dist/artifact-blocks/blocks/diagram/schema.js +621 -0
  96. package/dist/artifact-blocks/blocks/diagram/thumb.d.ts +2 -0
  97. package/dist/artifact-blocks/blocks/diagram/thumb.js +157 -0
  98. package/dist/artifact-blocks/blocks/diagram/types.d.ts +74 -0
  99. package/dist/artifact-blocks/blocks/diagram/types.js +1 -0
  100. package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte +81 -0
  101. package/dist/artifact-blocks/blocks/diff/DiffBlock.svelte.d.ts +10 -0
  102. package/dist/artifact-blocks/blocks/diff/block.d.ts +7 -0
  103. package/dist/artifact-blocks/blocks/diff/block.js +36 -0
  104. package/dist/artifact-blocks/blocks/diff/schema.d.ts +18 -0
  105. package/dist/artifact-blocks/blocks/diff/schema.js +35 -0
  106. package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte +1055 -0
  107. package/dist/artifact-blocks/blocks/diff-review/DiffReviewBlock.svelte.d.ts +5 -0
  108. package/dist/artifact-blocks/blocks/diff-review/block.d.ts +15 -0
  109. package/dist/artifact-blocks/blocks/diff-review/block.js +64 -0
  110. package/dist/artifact-blocks/blocks/diff-review/decisions.d.ts +57 -0
  111. package/dist/artifact-blocks/blocks/diff-review/decisions.js +80 -0
  112. package/dist/artifact-blocks/blocks/diff-review/schema.d.ts +13 -0
  113. package/dist/artifact-blocks/blocks/diff-review/schema.js +84 -0
  114. package/dist/artifact-blocks/blocks/diff-review/types.d.ts +35 -0
  115. package/dist/artifact-blocks/blocks/diff-review/types.js +1 -0
  116. package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte +145 -0
  117. package/dist/artifact-blocks/blocks/explainer/ExplainerBlock.svelte.d.ts +5 -0
  118. package/dist/artifact-blocks/blocks/explainer/block.d.ts +8 -0
  119. package/dist/artifact-blocks/blocks/explainer/block.js +21 -0
  120. package/dist/artifact-blocks/blocks/explainer/schema.d.ts +26 -0
  121. package/dist/artifact-blocks/blocks/explainer/schema.js +69 -0
  122. package/dist/artifact-blocks/blocks/group-content.d.ts +10 -0
  123. package/dist/artifact-blocks/blocks/group-content.js +16 -0
  124. package/dist/artifact-blocks/blocks/group-data.d.ts +10 -0
  125. package/dist/artifact-blocks/blocks/group-data.js +7 -0
  126. package/dist/artifact-blocks/blocks/group-review.d.ts +10 -0
  127. package/dist/artifact-blocks/blocks/group-review.js +12 -0
  128. package/dist/artifact-blocks/blocks/group-visual.d.ts +17 -0
  129. package/dist/artifact-blocks/blocks/group-visual.js +14 -0
  130. package/dist/artifact-blocks/blocks/map/MapBlock.svelte +413 -0
  131. package/dist/artifact-blocks/blocks/map/MapBlock.svelte.d.ts +53 -0
  132. package/dist/artifact-blocks/blocks/map/block.d.ts +9 -0
  133. package/dist/artifact-blocks/blocks/map/block.js +62 -0
  134. package/dist/artifact-blocks/blocks/map/schema.d.ts +123 -0
  135. package/dist/artifact-blocks/blocks/map/schema.js +113 -0
  136. package/dist/artifact-blocks/blocks/map/thumb.d.ts +2 -0
  137. package/dist/artifact-blocks/blocks/map/thumb.js +69 -0
  138. package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte +33 -0
  139. package/dist/artifact-blocks/blocks/markdown/MarkdownBlock.svelte.d.ts +15 -0
  140. package/dist/artifact-blocks/blocks/markdown/block.d.ts +7 -0
  141. package/dist/artifact-blocks/blocks/markdown/block.js +28 -0
  142. package/dist/artifact-blocks/blocks/markdown/render.d.ts +17 -0
  143. package/dist/artifact-blocks/blocks/markdown/render.js +115 -0
  144. package/dist/artifact-blocks/blocks/markdown/schema.d.ts +10 -0
  145. package/dist/artifact-blocks/blocks/markdown/schema.js +23 -0
  146. package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte +2112 -0
  147. package/dist/artifact-blocks/blocks/media-picker/MediaPickerBlock.svelte.d.ts +5 -0
  148. package/dist/artifact-blocks/blocks/media-picker/block.d.ts +24 -0
  149. package/dist/artifact-blocks/blocks/media-picker/block.js +137 -0
  150. package/dist/artifact-blocks/blocks/media-picker/choices.d.ts +28 -0
  151. package/dist/artifact-blocks/blocks/media-picker/choices.js +35 -0
  152. package/dist/artifact-blocks/blocks/media-picker/decisions.d.ts +51 -0
  153. package/dist/artifact-blocks/blocks/media-picker/decisions.js +75 -0
  154. package/dist/artifact-blocks/blocks/media-picker/schema.d.ts +7 -0
  155. package/dist/artifact-blocks/blocks/media-picker/schema.js +199 -0
  156. package/dist/artifact-blocks/blocks/media-picker/types.d.ts +92 -0
  157. package/dist/artifact-blocks/blocks/media-picker/types.js +1 -0
  158. package/dist/artifact-blocks/blocks/media-picker/versions.d.ts +51 -0
  159. package/dist/artifact-blocks/blocks/media-picker/versions.js +118 -0
  160. package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte +213 -0
  161. package/dist/artifact-blocks/blocks/mockup/MockupBlock.svelte.d.ts +5 -0
  162. package/dist/artifact-blocks/blocks/mockup/block.d.ts +26 -0
  163. package/dist/artifact-blocks/blocks/mockup/block.js +52 -0
  164. package/dist/artifact-blocks/blocks/mockup/doc.d.ts +24 -0
  165. package/dist/artifact-blocks/blocks/mockup/doc.js +44 -0
  166. package/dist/artifact-blocks/blocks/mockup/sandbox.d.ts +21 -0
  167. package/dist/artifact-blocks/blocks/mockup/sandbox.js +27 -0
  168. package/dist/artifact-blocks/blocks/mockup/schema.d.ts +7 -0
  169. package/dist/artifact-blocks/blocks/mockup/schema.js +90 -0
  170. package/dist/artifact-blocks/blocks/mockup/types.d.ts +36 -0
  171. package/dist/artifact-blocks/blocks/mockup/types.js +17 -0
  172. package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte +359 -0
  173. package/dist/artifact-blocks/blocks/program/ProgramBlock.svelte.d.ts +32 -0
  174. package/dist/artifact-blocks/blocks/program/block.d.ts +35 -0
  175. package/dist/artifact-blocks/blocks/program/block.js +68 -0
  176. package/dist/artifact-blocks/blocks/program/schema.d.ts +132 -0
  177. package/dist/artifact-blocks/blocks/program/schema.js +268 -0
  178. package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte +315 -0
  179. package/dist/artifact-blocks/blocks/stats/StatsBlock.svelte.d.ts +24 -0
  180. package/dist/artifact-blocks/blocks/stats/block.d.ts +7 -0
  181. package/dist/artifact-blocks/blocks/stats/block.js +49 -0
  182. package/dist/artifact-blocks/blocks/stats/schema.d.ts +82 -0
  183. package/dist/artifact-blocks/blocks/stats/schema.js +43 -0
  184. package/dist/artifact-blocks/blocks/stats/thumb.d.ts +2 -0
  185. package/dist/artifact-blocks/blocks/stats/thumb.js +102 -0
  186. package/dist/artifact-blocks/blocks/table/TableBlock.svelte +490 -0
  187. package/dist/artifact-blocks/blocks/table/TableBlock.svelte.d.ts +28 -0
  188. package/dist/artifact-blocks/blocks/table/block.d.ts +9 -0
  189. package/dist/artifact-blocks/blocks/table/block.js +100 -0
  190. package/dist/artifact-blocks/blocks/table/schema.d.ts +143 -0
  191. package/dist/artifact-blocks/blocks/table/schema.js +278 -0
  192. package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte +347 -0
  193. package/dist/artifact-blocks/blocks/timeline/TimelineBlock.svelte.d.ts +42 -0
  194. package/dist/artifact-blocks/blocks/timeline/block.d.ts +9 -0
  195. package/dist/artifact-blocks/blocks/timeline/block.js +96 -0
  196. package/dist/artifact-blocks/blocks/timeline/constants.d.ts +26 -0
  197. package/dist/artifact-blocks/blocks/timeline/constants.js +27 -0
  198. package/dist/artifact-blocks/blocks/timeline/schema.d.ts +102 -0
  199. package/dist/artifact-blocks/blocks/timeline/schema.js +405 -0
  200. package/dist/artifact-blocks/blocks/timeline/thumb.d.ts +2 -0
  201. package/dist/artifact-blocks/blocks/timeline/thumb.js +117 -0
  202. package/dist/artifact-blocks/blocks/timeline/types.d.ts +66 -0
  203. package/dist/artifact-blocks/blocks/timeline/types.js +1 -0
  204. package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte +169 -0
  205. package/dist/artifact-blocks/blocks/transcript/TranscriptBlock.svelte.d.ts +26 -0
  206. package/dist/artifact-blocks/blocks/transcript/block.d.ts +9 -0
  207. package/dist/artifact-blocks/blocks/transcript/block.js +86 -0
  208. package/dist/artifact-blocks/blocks/transcript/schema.d.ts +114 -0
  209. package/dist/artifact-blocks/blocks/transcript/schema.js +126 -0
  210. package/dist/artifact-blocks/builtins.d.ts +40 -0
  211. package/dist/artifact-blocks/builtins.js +22 -0
  212. package/dist/artifact-blocks/contractBlocks.d.ts +92 -0
  213. package/dist/artifact-blocks/contractBlocks.js +279 -0
  214. package/dist/artifact-blocks/history.d.ts +140 -0
  215. package/dist/artifact-blocks/history.js +363 -0
  216. package/dist/artifact-blocks/index.d.ts +40 -0
  217. package/dist/artifact-blocks/index.js +46 -0
  218. package/dist/artifact-blocks/listen/context.d.ts +30 -0
  219. package/dist/artifact-blocks/listen/context.js +30 -0
  220. package/dist/artifact-blocks/liveData.d.ts +78 -0
  221. package/dist/artifact-blocks/liveData.js +137 -0
  222. package/dist/artifact-blocks/liveDataPoller.d.ts +41 -0
  223. package/dist/artifact-blocks/liveDataPoller.js +140 -0
  224. package/dist/artifact-blocks/openNav.d.ts +46 -0
  225. package/dist/artifact-blocks/openNav.js +106 -0
  226. package/dist/artifact-blocks/pageReviewKeys.d.ts +17 -0
  227. package/dist/artifact-blocks/pageReviewKeys.js +115 -0
  228. package/dist/artifact-blocks/params.d.ts +98 -0
  229. package/dist/artifact-blocks/params.js +159 -0
  230. package/dist/artifact-blocks/registry.d.ts +27 -0
  231. package/dist/artifact-blocks/registry.js +83 -0
  232. package/dist/artifact-blocks/review/BlockIcon.svelte +99 -0
  233. package/dist/artifact-blocks/review/BlockIcon.svelte.d.ts +17 -0
  234. package/dist/artifact-blocks/review/BulkRejectForm.svelte +94 -0
  235. package/dist/artifact-blocks/review/BulkRejectForm.svelte.d.ts +11 -0
  236. package/dist/artifact-blocks/review/BulkUndoBar.svelte +40 -0
  237. package/dist/artifact-blocks/review/BulkUndoBar.svelte.d.ts +9 -0
  238. package/dist/artifact-blocks/review/ItemNote.svelte +193 -0
  239. package/dist/artifact-blocks/review/ItemNote.svelte.d.ts +33 -0
  240. package/dist/artifact-blocks/review/NoteToggle.svelte +52 -0
  241. package/dist/artifact-blocks/review/NoteToggle.svelte.d.ts +12 -0
  242. package/dist/artifact-blocks/review/TeamChip.svelte +71 -0
  243. package/dist/artifact-blocks/review/TeamChip.svelte.d.ts +8 -0
  244. package/dist/artifact-blocks/review/attachments.d.ts +10 -0
  245. package/dist/artifact-blocks/review/attachments.js +37 -0
  246. package/dist/artifact-blocks/review/bulk.d.ts +52 -0
  247. package/dist/artifact-blocks/review/bulk.js +61 -0
  248. package/dist/artifact-blocks/review/itemReview.d.ts +33 -0
  249. package/dist/artifact-blocks/review/itemReview.js +112 -0
  250. package/dist/artifact-blocks/review/roundLines.d.ts +14 -0
  251. package/dist/artifact-blocks/review/roundLines.js +20 -0
  252. package/dist/artifact-blocks/review/rounds.d.ts +86 -0
  253. package/dist/artifact-blocks/review/rounds.js +302 -0
  254. package/dist/artifact-blocks/review/saver.d.ts +23 -0
  255. package/dist/artifact-blocks/review/saver.js +48 -0
  256. package/dist/artifact-blocks/review/team.d.ts +31 -0
  257. package/dist/artifact-blocks/review/team.js +42 -0
  258. package/dist/artifact-blocks/review/visualOrder.d.ts +29 -0
  259. package/dist/artifact-blocks/review/visualOrder.js +66 -0
  260. package/dist/artifact-blocks/review.d.ts +180 -0
  261. package/dist/artifact-blocks/review.js +716 -0
  262. package/dist/artifact-blocks/thumb-kit.d.ts +80 -0
  263. package/dist/artifact-blocks/thumb-kit.js +149 -0
  264. package/dist/artifact-blocks/types.d.ts +513 -0
  265. package/dist/artifact-blocks/types.js +1 -0
  266. package/package.json +11 -2
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Timeline block — params schema, validation, date scale and layout
3
+ * (mos-d70v4).
4
+ *
5
+ * Pure functions only (no DOM): dates parse to UTC-midnight epoch ms (a
6
+ * date-only ISO string parses identically in every timezone), the domain,
7
+ * ticks, lane rows and dependency elbows are computed here, and colors
8
+ * NEVER appear — the renderer maps tones to theme-token classes.
9
+ *
10
+ * Untrusted-input rules (CONTRACT.md): text params are length-capped
11
+ * strings, dates are ISO-validated (impossible calendar dates are refused
12
+ * at publish), arrays are capped (50 milestones / 80 bars / 120 deps).
13
+ */
14
+ import { z } from "zod";
15
+ import { toneSchema, isoDateSchema } from "../../params.js";
16
+ import { MAX_MILESTONES, MAX_BARS, MAX_DEPS, MAX_LANES, BAR_TEXT_MAX, ID_MAX, LANE_MAX, } from "./constants.js";
17
+ // ── Schemas ───────────────────────────────────────────────────────────────
18
+ const timelineIdSchema = z
19
+ .string()
20
+ .min(1)
21
+ .max(ID_MAX)
22
+ .regex(/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/);
23
+ const milestoneSchema = z.object({
24
+ id: timelineIdSchema.optional(),
25
+ label: z.string().min(1).max(BAR_TEXT_MAX),
26
+ date: isoDateSchema,
27
+ tone: toneSchema.optional(),
28
+ lane: z.string().min(1).max(LANE_MAX).optional(),
29
+ });
30
+ const barSchema = z.object({
31
+ id: timelineIdSchema,
32
+ label: z.string().min(1).max(BAR_TEXT_MAX),
33
+ start: isoDateSchema,
34
+ end: isoDateSchema,
35
+ lane: z.string().min(1).max(LANE_MAX).optional(),
36
+ tone: toneSchema.optional(),
37
+ /** Completion percentage 0-100 (int) — renders a darker fill portion. */
38
+ progress: z.number().int().min(0).max(100).optional(),
39
+ });
40
+ const dependencySchema = z.object({
41
+ from: timelineIdSchema,
42
+ to: timelineIdSchema,
43
+ });
44
+ export const timelineParamsSchema = z
45
+ .object({
46
+ title: z.string().max(200).optional(),
47
+ subtitle: z.string().max(300).optional(),
48
+ /** Axis granularity: day / week / month ticks. */
49
+ zoom: z.enum(["day", "week", "month"]).default("month"),
50
+ /** Dashed "today" line at the current date (when it falls in range). */
51
+ showToday: z.boolean().default(true),
52
+ milestones: z.array(milestoneSchema).max(MAX_MILESTONES).default([]),
53
+ bars: z.array(barSchema).max(MAX_BARS).default([]),
54
+ dependencies: z.array(dependencySchema).max(MAX_DEPS).default([]),
55
+ /** Explicit lane order; lanes discovered from bars/milestones append. */
56
+ lanes: z.array(z.string().min(1).max(LANE_MAX)).max(MAX_LANES).optional(),
57
+ })
58
+ .superRefine((p, ctx) => {
59
+ // bar ids unique; end >= start
60
+ const barIds = new Set();
61
+ for (const [i, b] of p.bars.entries()) {
62
+ if (barIds.has(b.id)) {
63
+ ctx.addIssue({
64
+ code: "custom",
65
+ message: `Duplicate bar id "${b.id}" (bar ${i})`,
66
+ path: ["bars", i, "id"],
67
+ });
68
+ }
69
+ barIds.add(b.id);
70
+ if (Date.parse(b.start) > Date.parse(b.end)) {
71
+ ctx.addIssue({
72
+ code: "custom",
73
+ message: `Bar "${b.id}" ends before it starts`,
74
+ path: ["bars", i, "end"],
75
+ });
76
+ }
77
+ }
78
+ // milestone ids unique (when given)
79
+ const msIds = new Set();
80
+ for (const [i, m] of p.milestones.entries()) {
81
+ if (!m.id)
82
+ continue;
83
+ if (msIds.has(m.id)) {
84
+ ctx.addIssue({
85
+ code: "custom",
86
+ message: `Duplicate milestone id "${m.id}" (milestone ${i})`,
87
+ path: ["milestones", i, "id"],
88
+ });
89
+ }
90
+ msIds.add(m.id);
91
+ }
92
+ // dependencies reference bars, no self-deps, no duplicates
93
+ p.dependencies.forEach((d, i) => {
94
+ for (const key of ["from", "to"]) {
95
+ if (!barIds.has(d[key])) {
96
+ ctx.addIssue({
97
+ code: "custom",
98
+ message: `Dependency ${i} ${key} "${d[key]}" has no bar`,
99
+ path: ["dependencies", i, key],
100
+ });
101
+ }
102
+ }
103
+ if (d.from === d.to) {
104
+ ctx.addIssue({
105
+ code: "custom",
106
+ message: `Dependency ${i} is a self-dependency`,
107
+ path: ["dependencies", i],
108
+ });
109
+ }
110
+ for (let j = 0; j < i; j++) {
111
+ const o = p.dependencies[j];
112
+ if (o.from === d.from && o.to === d.to) {
113
+ ctx.addIssue({
114
+ code: "custom",
115
+ message: `Dependency ${i} duplicates dependency ${j}`,
116
+ path: ["dependencies", i],
117
+ });
118
+ }
119
+ }
120
+ });
121
+ });
122
+ // ── Date scale (UTC-day anchored, deterministic) ──────────────────────────
123
+ export const DAY_MS = 86_400_000;
124
+ /** ISO date(-time) → epoch ms. Date-only strings are UTC midnight. */
125
+ export function parseDay(v) {
126
+ const ms = Date.parse(v);
127
+ return Number.isFinite(ms) ? ms : Number.NaN;
128
+ }
129
+ function startOfUtcDay(ms) {
130
+ return Math.floor(ms / DAY_MS) * DAY_MS;
131
+ }
132
+ export function addDays(ms, days) {
133
+ return ms + days * DAY_MS;
134
+ }
135
+ /** UTC Monday 00:00 of the week containing ms. */
136
+ function startOfUtcWeek(ms) {
137
+ const d = new Date(ms);
138
+ const day = (d.getUTCDay() + 6) % 7; // Mon=0 … Sun=6
139
+ return startOfUtcDay(ms) - day * DAY_MS;
140
+ }
141
+ /** UTC 1st of the month 00:00 containing ms. */
142
+ function startOfUtcMonth(ms) {
143
+ const d = new Date(ms);
144
+ return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);
145
+ }
146
+ /** Tick steps (in units) that keep the tick count honest. */
147
+ const STEP_LADDER = [1, 2, 3, 6, 12];
148
+ /** Calendar-aware ticks for the domain at the chosen zoom, snapped to real
149
+ * day/week/month boundaries (never "Mar 34"). Returns ≤ ~48 ticks; the step
150
+ * widens when the span is too long for the zoom. */
151
+ export function timeTicks(d0, d1, zoom) {
152
+ if (!Number.isFinite(d0) || !Number.isFinite(d1) || d1 <= d0)
153
+ return [];
154
+ const spanDays = (d1 - d0) / DAY_MS;
155
+ const out = [];
156
+ if (zoom === "day") {
157
+ const stepDays = STEP_LADDER.concat([14]).find((s) => spanDays / s <= 46) ?? 14;
158
+ let t = startOfUtcDay(d0);
159
+ while (t <= d1) {
160
+ if (t >= d0)
161
+ out.push({
162
+ ms: t,
163
+ label: new Intl.DateTimeFormat("en-US", {
164
+ month: "short",
165
+ day: "numeric",
166
+ }).format(t),
167
+ });
168
+ t = addDays(t, stepDays);
169
+ }
170
+ return out;
171
+ }
172
+ if (zoom === "week") {
173
+ const stepWeeks = STEP_LADDER.find((s) => spanDays / (7 * s) <= 46) ?? 12;
174
+ let t = startOfUtcWeek(d0);
175
+ while (t <= d1) {
176
+ if (t >= d0)
177
+ out.push({
178
+ ms: t,
179
+ label: new Intl.DateTimeFormat("en-US", {
180
+ month: "short",
181
+ day: "numeric",
182
+ }).format(t),
183
+ });
184
+ t = addDays(t, 7 * stepWeeks);
185
+ }
186
+ return out;
187
+ }
188
+ const stepMonths = STEP_LADDER.find((s) => spanDays / (30.4 * s) <= 46) ?? 12;
189
+ let t = startOfUtcMonth(d0);
190
+ while (t <= d1 && out.length < 60) {
191
+ if (t >= d0) {
192
+ const d = new Date(t);
193
+ const jan = d.getUTCMonth() === 0;
194
+ out.push({
195
+ ms: t,
196
+ label: jan
197
+ ? new Intl.DateTimeFormat("en-US", {
198
+ month: "short",
199
+ year: "numeric",
200
+ }).format(t)
201
+ : new Intl.DateTimeFormat("en-US", { month: "short" }).format(t),
202
+ });
203
+ }
204
+ const d = new Date(t);
205
+ t = Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + stepMonths, 1);
206
+ }
207
+ return out;
208
+ }
209
+ /** Domain pad per zoom (days each side) so marks aren't glued to the edge. */
210
+ function padDays(zoom) {
211
+ return zoom === "day" ? 1 : zoom === "week" ? 3 : 10;
212
+ }
213
+ /** Date domain over milestones + bars, padded per zoom. */
214
+ function timeDomain(p) {
215
+ let min = Number.POSITIVE_INFINITY;
216
+ let max = Number.NEGATIVE_INFINITY;
217
+ for (const m of p.milestones) {
218
+ const t = parseDay(m.date);
219
+ if (Number.isFinite(t)) {
220
+ min = Math.min(min, t);
221
+ max = Math.max(max, t);
222
+ }
223
+ }
224
+ for (const b of p.bars) {
225
+ const s = parseDay(b.start);
226
+ const e = parseDay(b.end);
227
+ if (Number.isFinite(s))
228
+ min = Math.min(min, s);
229
+ if (Number.isFinite(e))
230
+ max = Math.max(max, e);
231
+ }
232
+ if (!Number.isFinite(min) || !Number.isFinite(max)) {
233
+ // no data: a one-week window around today keeps the axis honest
234
+ const today = startOfUtcDay(Date.now());
235
+ return { d0: addDays(today, -2), d1: addDays(today, 5) };
236
+ }
237
+ min = startOfUtcDay(min);
238
+ max = startOfUtcDay(max);
239
+ if (min === max)
240
+ max = addDays(max, 1);
241
+ const pad = padDays(p.zoom);
242
+ return { d0: addDays(min, -pad), d1: addDays(max, pad) };
243
+ }
244
+ // ── Lanes ─────────────────────────────────────────────────────────────────
245
+ const MILESTONE_LANE = "__milestones";
246
+ /** Lane order: explicit `lanes` first (only those with items), then lanes
247
+ * discovered from bars/milestones in first-seen order. Lane-less milestones
248
+ * land on the dedicated top lane; lane-less bars on a trailing "—"-labeled
249
+ * lane. Returns lane ids with display labels. */
250
+ function laneOrder(p) {
251
+ const out = [];
252
+ const seen = new Set();
253
+ const push = (id, label) => {
254
+ if (!seen.has(id)) {
255
+ seen.add(id);
256
+ out.push({ id, label });
257
+ }
258
+ };
259
+ const msLaneless = p.milestones.some((m) => !m.lane);
260
+ if (msLaneless)
261
+ push(MILESTONE_LANE, "Milestones");
262
+ for (const l of p.lanes ?? [])
263
+ push(l, l);
264
+ for (const m of p.milestones)
265
+ if (m.lane)
266
+ push(m.lane, m.lane);
267
+ for (const b of p.bars)
268
+ if (b.lane)
269
+ push(b.lane, b.lane);
270
+ if (p.bars.some((b) => !b.lane))
271
+ push("", "Tasks");
272
+ return out;
273
+ }
274
+ // ── Layout ────────────────────────────────────────────────────────────────
275
+ const TICK_H = 22;
276
+ const ROW_PAD = 9;
277
+ const BAR_H = 16;
278
+ const SUB_ROW_H = BAR_H + 7;
279
+ /** Full layout for the renderer. `nowMs` (client-only) adds the today line
280
+ * when it falls inside the domain; SSR passes null and the line is skipped
281
+ * — no hydration mismatch. */
282
+ export function layoutTimeline(p, opts = {
283
+ plotW: 700,
284
+ laneW: 120,
285
+ nowMs: null,
286
+ }) {
287
+ const { d0, d1 } = timeDomain(p);
288
+ const span = Math.max(1, d1 - d0);
289
+ const xFor = (ms) => opts.laneW + ((ms - d0) / span) * Math.max(40, opts.plotW);
290
+ const rows = [];
291
+ let y = TICK_H + ROW_PAD;
292
+ const laneDefs = laneOrder(p);
293
+ for (const lane of laneDefs) {
294
+ const bars = p.bars
295
+ .filter((b) => (b.lane ?? "") === lane.id)
296
+ .sort((a, b) => Date.parse(a.start) - Date.parse(b.start));
297
+ const milestones = p.milestones.filter((m) => (m.lane ?? "") === lane.id || (!m.lane && lane.id === MILESTONE_LANE));
298
+ // greedy sub-rows so overlapping bars in one lane stack
299
+ const subEnds = [];
300
+ const placed = bars.map((b) => {
301
+ const s = parseDay(b.start);
302
+ const e = parseDay(b.end);
303
+ let sub = subEnds.findIndex((end) => end <= s);
304
+ if (sub === -1) {
305
+ subEnds.push(e);
306
+ sub = subEnds.length - 1;
307
+ }
308
+ else
309
+ subEnds[sub] = e;
310
+ return { bar: b, sub, x: xFor(s), w: Math.max(2, xFor(e) - xFor(s)) };
311
+ });
312
+ const subCount = Math.max(subEnds.length, milestones.length ? 1 : 0, 1);
313
+ const height = subCount * SUB_ROW_H + ROW_PAD;
314
+ const rowY = y;
315
+ y += height;
316
+ rows.push({
317
+ id: lane.id,
318
+ label: lane.label,
319
+ y: rowY,
320
+ height,
321
+ bars: placed.map((pl) => ({
322
+ id: pl.bar.id,
323
+ label: pl.bar.label,
324
+ tone: pl.bar.tone,
325
+ progress: pl.bar.progress,
326
+ start: pl.bar.start,
327
+ end: pl.bar.end,
328
+ x: pl.x,
329
+ w: pl.w,
330
+ y: rowY + ROW_PAD / 2 + pl.sub * SUB_ROW_H + (SUB_ROW_H - BAR_H) / 2,
331
+ xStartMs: parseDay(pl.bar.start),
332
+ xEndMs: parseDay(pl.bar.end),
333
+ })),
334
+ milestones: milestones.map((m) => ({
335
+ id: m.id ?? `ms-${m.label}`,
336
+ label: m.label,
337
+ tone: m.tone,
338
+ date: m.date,
339
+ x: xFor(parseDay(m.date)),
340
+ y: rowY + height / 2,
341
+ })),
342
+ });
343
+ }
344
+ const height = y + ROW_PAD;
345
+ const today = opts.nowMs != null &&
346
+ Number.isFinite(opts.nowMs) &&
347
+ opts.nowMs >= d0 &&
348
+ opts.nowMs <= d1
349
+ ? { x: xFor(startOfUtcDay(opts.nowMs)) }
350
+ : null;
351
+ return {
352
+ d0,
353
+ d1,
354
+ ticks: timeTicks(d0, d1, p.zoom).map((t) => ({
355
+ ...t,
356
+ x: xFor(t.ms),
357
+ })),
358
+ rows,
359
+ today,
360
+ width: opts.laneW + Math.max(40, opts.plotW) + 12,
361
+ height,
362
+ laneW: opts.laneW,
363
+ };
364
+ }
365
+ /** Dependency elbow path: from the END of bar A to the START of bar B,
366
+ * routed through the row gap. Points (not a path string) so the renderer
367
+ * draws + head-triangles it like every other polyline here. */
368
+ export function dependencyPoints(from, to) {
369
+ const dir = to.xStart >= from.xEnd ? 1 : -1;
370
+ const gap = 8 * dir;
371
+ if (Math.abs(to.y - from.y) < 2)
372
+ return [
373
+ { x: from.xEnd, y: from.y },
374
+ { x: to.xStart, y: to.y },
375
+ ];
376
+ return [
377
+ { x: from.xEnd, y: from.y },
378
+ { x: from.xEnd + gap, y: from.y },
379
+ { x: from.xEnd + gap, y: to.y },
380
+ { x: to.xStart, y: to.y },
381
+ ];
382
+ }
383
+ const dayFmt = new Intl.DateTimeFormat("en-US", { dateStyle: "medium" });
384
+ /** Flat rows for the accessible data fallback (sr-only table). */
385
+ export function timelineRows(p) {
386
+ const rows = [];
387
+ for (const m of p.milestones)
388
+ rows.push({
389
+ kind: "milestone",
390
+ label: m.label,
391
+ detail: `${dayFmt.format(Date.parse(m.date))}${m.lane ? ` · ${m.lane}` : ""}`,
392
+ });
393
+ for (const b of p.bars)
394
+ rows.push({
395
+ kind: "bar",
396
+ label: b.label,
397
+ detail: `${b.start} → ${b.end}${b.lane ? ` · ${b.lane}` : ""}${b.progress != null ? ` · ${b.progress}%` : ""}`,
398
+ });
399
+ for (const d of p.dependencies) {
400
+ const f = p.bars.find((b) => b.id === d.from)?.label ?? d.from;
401
+ const t = p.bars.find((b) => b.id === d.to)?.label ?? d.to;
402
+ rows.push({ kind: "bar", label: `${f} → ${t}`, detail: "dependency" });
403
+ }
404
+ return rows;
405
+ }
@@ -0,0 +1,2 @@
1
+ import { type ThumbPalette } from "../../thumb-kit.js";
2
+ export declare function drawTimelineThumb(raw: unknown, palette: ThumbPalette): string | null;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Timeline block thumbnail composer (mos-qkpva).
3
+ *
4
+ * The same layoutTimeline geometry the component draws (./schema.ts, pure and
5
+ * unit-tested) as a simplified silhouette: tick header, lane-labeled bar rows
6
+ * (tone fills at the component's opacities), progress overlays and milestone
7
+ * diamonds. The today line is client-only in the component (nowMs=null on
8
+ * SSR); the thumb passes null too, so a thumbnail never lies about "today".
9
+ *
10
+ * A timeline can be very tall (24 lanes); the thumb keeps rows only while
11
+ * they fit a ~2:1 box and clips the viewBox to what it drew — a tall timeline
12
+ * shows its first rows, not a dust-scale whole.
13
+ */
14
+ import { timelineParamsSchema, layoutTimeline, } from "./schema.js";
15
+ import { LANE_W, BAR_H, MS_R } from "./constants.js";
16
+ import { r1, thumbText, thumbTruncate, toneColor, } from "../../thumb-kit.js";
17
+ const PLOT_W = 480;
18
+ const MAX_ROWS_HEIGHT = 300;
19
+ /** The components' static tone maps, resolved to concrete color+opacity. */
20
+ function barFill(palette, tone) {
21
+ switch (tone) {
22
+ case "success":
23
+ case "warning":
24
+ return { fill: toneColor(palette, tone), opacity: 0.3 };
25
+ case "neutral":
26
+ return { fill: palette.ink, opacity: 0.15 };
27
+ case undefined:
28
+ return { fill: palette.primary, opacity: 0.25 };
29
+ default:
30
+ return { fill: toneColor(palette, tone), opacity: 0.25 };
31
+ }
32
+ }
33
+ function barStroke(palette, tone) {
34
+ switch (tone) {
35
+ case "warning":
36
+ return { stroke: palette.warning, opacity: 0.8 };
37
+ case "neutral":
38
+ return { stroke: palette.ink, opacity: 0.35 };
39
+ case undefined:
40
+ return { stroke: palette.primary, opacity: 0.7 };
41
+ default:
42
+ return { stroke: toneColor(palette, tone), opacity: 0.7 };
43
+ }
44
+ }
45
+ function progressFill(palette, tone) {
46
+ switch (tone) {
47
+ case "neutral":
48
+ return { fill: palette.ink, opacity: 0.4 };
49
+ case undefined:
50
+ return { fill: palette.primary, opacity: 0.6 };
51
+ default:
52
+ return { fill: toneColor(palette, tone), opacity: 0.6 };
53
+ }
54
+ }
55
+ export function drawTimelineThumb(raw, palette) {
56
+ const parsed = timelineParamsSchema.safeParse(raw);
57
+ if (!parsed.success)
58
+ return null;
59
+ const params = parsed.data;
60
+ if (params.bars.length === 0 && params.milestones.length === 0)
61
+ return null;
62
+ const layout = layoutTimeline(params, {
63
+ plotW: PLOT_W,
64
+ laneW: LANE_W,
65
+ nowMs: null,
66
+ });
67
+ // Keep rows until they no longer fit the ~2:1 silhouette box; the drawn
68
+ // height becomes the viewBox height.
69
+ const rows = [];
70
+ let drawnH = layout.rows.length ? layout.rows[0].y : 0;
71
+ for (const row of layout.rows) {
72
+ rows.push(row);
73
+ drawnH = row.y + row.height;
74
+ if (drawnH > MAX_ROWS_HEIGHT && rows.length > 1) {
75
+ rows.pop();
76
+ drawnH = (rows.at(-1)?.y ?? 0) + (rows.at(-1)?.height ?? 0);
77
+ break;
78
+ }
79
+ }
80
+ if (rows.length === 0)
81
+ return null;
82
+ const W = Math.max(240, layout.width);
83
+ const H = Math.max(60, drawnH + 6);
84
+ const out = [];
85
+ // tick header (position + faint line only — labels are dust at cell size)
86
+ for (const t of layout.ticks) {
87
+ out.push(`<line x1="${r1(t.x)}" x2="${r1(t.x)}" y1="0" y2="${r1(H)}" stroke="${palette.ink}" stroke-opacity="0.08" stroke-width="1"/>`);
88
+ }
89
+ for (const row of rows) {
90
+ // lane label
91
+ if (row.label)
92
+ out.push(thumbText(8, row.y + row.height / 2 + 3, thumbTruncate(row.label, 14), {
93
+ size: 10,
94
+ fill: palette.ink,
95
+ opacity: 0.55,
96
+ }));
97
+ // row hairline separator (alternate, like the component)
98
+ out.push(`<line x1="${r1(LANE_W)}" x2="${r1(W)}" y1="${r1(row.y + row.height)}" y2="${r1(row.y + row.height)}" stroke="${palette.ink}" stroke-opacity="0.08" stroke-width="1"/>`);
99
+ for (const b of row.bars) {
100
+ const f = barFill(palette, b.tone);
101
+ const s = barStroke(palette, b.tone);
102
+ out.push(`<rect x="${r1(b.x)}" y="${r1(b.y)}" width="${r1(Math.max(2, b.w))}" height="${BAR_H}" rx="4" fill="${f.fill}" fill-opacity="${f.opacity}" stroke="${s.stroke}" stroke-opacity="${s.opacity}" stroke-width="1"/>`);
103
+ if (b.progress != null) {
104
+ const pf = progressFill(palette, b.tone);
105
+ out.push(`<rect x="${r1(b.x)}" y="${r1(b.y)}" width="${r1(Math.max(2, (b.w * b.progress) / 100))}" height="${BAR_H}" rx="4" fill="${pf.fill}" fill-opacity="${pf.opacity}"/>`);
106
+ }
107
+ }
108
+ for (const m of row.milestones) {
109
+ const tone = m.tone ?? "accent";
110
+ const color = toneColor(palette, tone === "neutral" ? "accent" : tone);
111
+ const cx = r1(m.x);
112
+ const cy = r1(m.y);
113
+ out.push(`<polygon points="${cx},${cy - MS_R} ${cx + MS_R},${cy} ${cx},${cy + MS_R} ${cx - MS_R},${cy}" fill="${color}"/>`);
114
+ }
115
+ }
116
+ return `<svg viewBox="0 0 ${r1(W)} ${r1(H)}">${out.join("")}</svg>`;
117
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Timeline block — shared types. schema.ts owns the zod schema and infers
3
+ * TimelineParams from it; this file carries the layout vocabulary so
4
+ * schema.ts and TimelineBlock.svelte agree without a cycle.
5
+ */
6
+ import type { z } from "zod";
7
+ import type { ToneTokenT } from "./constants.js";
8
+ import type { timelineParamsSchema } from "./schema.js";
9
+ export type ToneToken = ToneTokenT;
10
+ export type TimelineParams = z.infer<typeof timelineParamsSchema>;
11
+ export interface Point {
12
+ x: number;
13
+ y: number;
14
+ }
15
+ export interface Tick {
16
+ ms: number;
17
+ label: string;
18
+ /** x pixel position (layout fills this in). */
19
+ x: number;
20
+ }
21
+ export interface TimelineBar {
22
+ id: string;
23
+ label: string;
24
+ tone?: ToneToken;
25
+ progress?: number;
26
+ start: string;
27
+ end: string;
28
+ /** Pixel geometry (layout fills these in). */
29
+ x: number;
30
+ w: number;
31
+ y: number;
32
+ /** Parsed epoch ms of start/end (for dependency routing). */
33
+ xStartMs: number;
34
+ xEndMs: number;
35
+ }
36
+ export interface TimelineMilestone {
37
+ id: string;
38
+ label: string;
39
+ tone?: ToneToken;
40
+ date: string;
41
+ /** Pixel center of the diamond (layout fills these in). */
42
+ x: number;
43
+ y: number;
44
+ }
45
+ export interface LaneRow {
46
+ id: string;
47
+ label: string;
48
+ y: number;
49
+ height: number;
50
+ bars: TimelineBar[];
51
+ milestones: TimelineMilestone[];
52
+ }
53
+ export interface TimelineLayout {
54
+ /** UTC-day-anchored domain (epoch ms). */
55
+ d0: number;
56
+ d1: number;
57
+ ticks: Tick[];
58
+ rows: LaneRow[];
59
+ /** Today line when it falls inside the domain (client-only). */
60
+ today: {
61
+ x: number;
62
+ } | null;
63
+ width: number;
64
+ height: number;
65
+ laneW: number;
66
+ }
@@ -0,0 +1 @@
1
+ export {};