@charcuterie/ui 4.5.1 → 4.7.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 (58) hide show
  1. package/README.md +12 -0
  2. package/dist/LaneTimeline/LaneTimeline.d.ts +132 -0
  3. package/dist/LaneTimeline/LaneTimeline.d.ts.map +1 -0
  4. package/dist/LaneTimeline/LaneTimeline.js +165 -0
  5. package/dist/LaneTimeline/LaneTimeline.js.map +1 -0
  6. package/dist/LaneTimeline/LaneTimelineBar.d.ts +97 -0
  7. package/dist/LaneTimeline/LaneTimelineBar.d.ts.map +1 -0
  8. package/dist/LaneTimeline/LaneTimelineBar.js +69 -0
  9. package/dist/LaneTimeline/LaneTimelineBar.js.map +1 -0
  10. package/dist/LaneTimeline/LaneTimelineLane.d.ts +84 -0
  11. package/dist/LaneTimeline/LaneTimelineLane.d.ts.map +1 -0
  12. package/dist/LaneTimeline/LaneTimelineLane.js +109 -0
  13. package/dist/LaneTimeline/LaneTimelineLane.js.map +1 -0
  14. package/dist/LaneTimeline/laneTimelineGeometry.d.ts +268 -0
  15. package/dist/LaneTimeline/laneTimelineGeometry.d.ts.map +1 -0
  16. package/dist/LaneTimeline/laneTimelineGeometry.js +277 -0
  17. package/dist/LaneTimeline/laneTimelineGeometry.js.map +1 -0
  18. package/dist/LaneTimeline/useTrackMeasurements.d.ts +69 -0
  19. package/dist/LaneTimeline/useTrackMeasurements.d.ts.map +1 -0
  20. package/dist/LaneTimeline/useTrackMeasurements.js +134 -0
  21. package/dist/LaneTimeline/useTrackMeasurements.js.map +1 -0
  22. package/dist/Overlay/OverlayPanel.d.ts.map +1 -1
  23. package/dist/Overlay/OverlayPanel.js +54 -2
  24. package/dist/Overlay/OverlayPanel.js.map +1 -1
  25. package/dist/Overlay/OverlayStack.d.ts +5 -0
  26. package/dist/Overlay/OverlayStack.d.ts.map +1 -1
  27. package/dist/Overlay/OverlayStack.js +2 -0
  28. package/dist/Overlay/OverlayStack.js.map +1 -1
  29. package/dist/Toast/ToastRegion.d.ts +61 -0
  30. package/dist/Toast/ToastRegion.d.ts.map +1 -1
  31. package/dist/Toast/ToastRegion.js +80 -3
  32. package/dist/Toast/ToastRegion.js.map +1 -1
  33. package/dist/Toolbar/useToolbarOverflow.d.ts.map +1 -1
  34. package/dist/Toolbar/useToolbarOverflow.js +39 -0
  35. package/dist/Toolbar/useToolbarOverflow.js.map +1 -1
  36. package/dist/index.d.ts +6 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -0
  39. package/dist/index.js.map +1 -1
  40. package/package.json +3 -3
  41. package/src/LaneTimeline/LaneTimeline.mdx +191 -0
  42. package/src/LaneTimeline/LaneTimeline.stories.tsx +561 -0
  43. package/src/LaneTimeline/LaneTimeline.test.tsx +330 -0
  44. package/src/LaneTimeline/LaneTimeline.tsx +381 -0
  45. package/src/LaneTimeline/LaneTimelineBar.tsx +237 -0
  46. package/src/LaneTimeline/LaneTimelineLane.tsx +332 -0
  47. package/src/LaneTimeline/laneTimelineGeometry.test.ts +429 -0
  48. package/src/LaneTimeline/laneTimelineGeometry.ts +476 -0
  49. package/src/LaneTimeline/useTrackMeasurements.ts +165 -0
  50. package/src/Overlay/OverlayPanel.tsx +63 -2
  51. package/src/Overlay/OverlayStack.tsx +7 -1
  52. package/src/Toast/Toast.stories.tsx +154 -0
  53. package/src/Toast/ToastRegion.test.tsx +172 -0
  54. package/src/Toast/ToastRegion.tsx +120 -32
  55. package/src/Toolbar/Toolbar.test.tsx +84 -0
  56. package/src/Toolbar/useToolbarOverflow.ts +43 -0
  57. package/src/index.ts +13 -0
  58. package/src/sourceRules.test.ts +22 -1
package/README.md CHANGED
@@ -51,6 +51,18 @@ Moving a card takes **no drag-and-drop dependency**: one handle per card, a `Men
51
51
  other lanes as the primary path, Pointer-Event dragging at 1.4 KB gzip beside it
52
52
  ([decision](../../docs/decisions/2026-08-19-the-board-owns-the-move-and-takes-no-drag-and-drop-dependency.md)).
53
53
 
54
+ **`LaneTimeline` is the first component that folds on a measurement of its own box.**
55
+ One horizontal lane per group across a date axis, with anything lasting more than a day drawn
56
+ as a **bar** — the shape a month grid cannot show, and the only one that makes load asymmetry
57
+ visible, because overlapping items pack into stacked rows and a busy lane is literally taller.
58
+ `end` is **inclusive**, said four times over, because an off-by-one on a date range is
59
+ invisible in both directions. The Narrow View **abandons** the axis rather than panning or
60
+ squeezing it. And the fold is measured rather than queried for a reason no other component
61
+ here has: the question is not how wide the box is but how wide one *day* is, which is the
62
+ width divided by a number that lives in the data — 30 columns in 900px is a readable month
63
+ and 365 columns in the same 900px is a smear
64
+ ([decision](../../docs/decisions/2026-09-18-a-timeline-span-ends-on-its-last-day-and-the-axis-folds-on-measurement.md)).
65
+
54
66
  **`DropRail` is the move control for a page `Board`'s `Menu` cannot serve.** A menu of the
55
67
  other lanes is right at three lanes; it is wrong at thirty-four groups, where it becomes a
56
68
  scrolling list inside a popup and a drag becomes a scroll with the button held down. The
@@ -0,0 +1,132 @@
1
+ import type { ReactNode } from "react";
2
+ import type { TimelineLane } from "./LaneTimelineLane.tsx";
3
+ import type { TimelineSpan } from "./laneTimelineGeometry.ts";
4
+ export type LaneTimelineProps = {
5
+ className?: string;
6
+ /**
7
+ * Shown when there are no lanes, or when `range` is not a pair of
8
+ * calendar dates. Defaults to a real `EmptyState` — *"real empty
9
+ * states"* is a standing requirement, and an empty timeline is
10
+ * what a household sees on a good week.
11
+ */
12
+ emptyState?: ReactNode;
13
+ /**
14
+ * What level the lane headings are. The caller's, because only
15
+ * the caller knows what the timeline sits under: one directly
16
+ * below a page `<h1>` wants `2`. Getting it wrong is an axe
17
+ * `heading-order` failure and a hole in the screen-reader
18
+ * outline.
19
+ */
20
+ headingLevel?: 2 | 3 | 4 | 5;
21
+ /** The timeline's accessible name. Required — it is a landmark. */
22
+ label: string;
23
+ lanes: readonly TimelineLane[];
24
+ /**
25
+ * BCP-47, for the dates only. Omitted, `Intl` uses the runtime's
26
+ * own — which is right on a personal machine and wrong on a
27
+ * server, so a server render should pass one rather than let two
28
+ * environments disagree about what "6 Apr" looks like.
29
+ */
30
+ locale?: string;
31
+ /** How many bars one lane may stack. Default 6. */
32
+ maxRowCount?: number;
33
+ /**
34
+ * The narrowest a day column may get before the axis is abandoned
35
+ * for the Narrow View, as a multiple of the timeline's **own font
36
+ * size**. Default 1.75.
37
+ *
38
+ * In em rather than pixels because every length in this token set
39
+ * moves with the density axis: a floor pinned at 20px is generous
40
+ * on a desktop and clips a two-digit date on the kiosk. Same
41
+ * argument `Avatar` makes about a chip that stays 20px while the
42
+ * prose around it scales.
43
+ */
44
+ minColumnSize?: number;
45
+ /**
46
+ * The days on screen. **Both ends inclusive**, like every other
47
+ * span in this component — a Monday-to-Sunday week is
48
+ * `2026-04-06` to `2026-04-12`, which is seven columns, not eight.
49
+ */
50
+ range: TimelineSpan;
51
+ };
52
+ /**
53
+ * One horizontal lane per group, across a date axis, with anything
54
+ * that lasts more than a day drawn as a **bar**.
55
+ *
56
+ * ## What it is for
57
+ *
58
+ * A month grid gives every day the same box, so a thing that runs
59
+ * Tuesday to Friday is four separate entries and the fact that it is
60
+ * *one* thing is lost. Worse, every cell is the same size no matter
61
+ * how much is in it, so a grid cannot show that one person is
62
+ * carrying most of the week. A lane can: bars keep their real
63
+ * shape, and a lane with overlapping work stacks into rows and gets
64
+ * **taller**. The asymmetry then reads from across the room, before
65
+ * anybody counts anything.
66
+ *
67
+ * It is not a calendar. There is no event, no attendee and no
68
+ * recurrence in this API, because Docket wants the same shape for
69
+ * phases and Horizon wants it for a household — the library owns the
70
+ * **shape** and the app owns the **data**. What a lane holds is a
71
+ * `key`, a `label` and items with a `start`, an `end` and a `title`.
72
+ *
73
+ * ## `end` is INCLUSIVE, and that is the decision to know
74
+ *
75
+ * An off-by-one on a date range is invisible in both directions: a
76
+ * bar one day short and a bar one day long are both bars. So it is
77
+ * stated loudly here and again on the type — **`end` is the last day
78
+ * the item covers**. `2026-04-06` to `2026-04-06` is one day, and a
79
+ * seven-day week ends on its seventh day, not on the eighth. The
80
+ * alternative (a half-open interval, the way `Date` ranges and
81
+ * iCalendar's `DTEND` work) is the better model for *instants* and
82
+ * the wrong one for a human writing down when the roofers are
83
+ * coming: nobody says "Monday to Saturday" about a working week, so
84
+ * an exclusive end would make every consumer add a day on the way in
85
+ * and forget to on one of the paths.
86
+ * [Decision](../../../docs/decisions/2026-09-18-a-timeline-span-ends-on-its-last-day-and-the-axis-folds-on-measurement.md).
87
+ *
88
+ * ## The Narrow View is a LIST, not a pan surface
89
+ *
90
+ * Thirty columns have no narrow layout, and the two obvious answers
91
+ * are both wrong. Horizontal scrolling hides lanes behind a gesture
92
+ * with no affordance and fights the trackpad's own back-navigation
93
+ * — the same objection `Board` settled with *"no horizontal scroll,
94
+ * ever"*. Squeezing thirty columns into 390px gives each day 13
95
+ * pixels, which is not a timeline, it is a texture.
96
+ *
97
+ * So below the threshold the axis is **abandoned** rather than
98
+ * shrunk: each lane becomes a one-column list of its items, each one
99
+ * a line of text with its span written out in words. Nothing is
100
+ * hidden, nothing overflows, and the reading order is the one the
101
+ * fleet's text-heavy lists already use.
102
+ *
103
+ * ## It folds on a MEASUREMENT, not a breakpoint
104
+ *
105
+ * There is no `@media` and no `cq-` in this component, and neither
106
+ * could do the job: the question is not *how wide is the box* but
107
+ * **how wide is one day**, which is the width divided by a number
108
+ * that lives in the data. Thirty columns in 900px is a readable
109
+ * month and three hundred and sixty five columns in the same 900px
110
+ * is a grey smear, and no query can tell those apart. `Nav` folds
111
+ * its bar on a measured width for the weaker version of this
112
+ * reason; `useToolbarOverflow` writes the argument down.
113
+ *
114
+ * ⚠️ **It must not be sized by its own contents.** The component
115
+ * reads its own box to decide what to draw in it, so a shrink-
116
+ * wrapping parent makes the answer its own input. The root declares
117
+ * `container-type: inline-size` — not to query it, the same reason
118
+ * `Main` declares one — which forbids the element from being sized
119
+ * by what is inside it and makes that loop unformable. In a story
120
+ * this is what `align="stretch"` on the `StoryCell` is for.
121
+ *
122
+ * ## What it deliberately does not do
123
+ *
124
+ * No time of day: this is a **calendar-date** axis, so two things on
125
+ * one Tuesday stack rather than sit at 09:00 and 14:00. No "now"
126
+ * marker, no zoom, no drag to reschedule, no data. A range control
127
+ * belongs to the page — `DatePicker` already is one — and a bar you
128
+ * can drag is a write operation, which is a different component with
129
+ * a different decision behind it.
130
+ */
131
+ export declare const LaneTimeline: ({ className, emptyState, headingLevel, label, lanes, locale, maxRowCount, minColumnSize, range, }: LaneTimelineProps) => ReactNode;
132
+ //# sourceMappingURL=LaneTimeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LaneTimeline.d.ts","sourceRoot":"","sources":["../../src/LaneTimeline/LaneTimeline.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AA+C7D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,SAAS,CAAA;IACtB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IAC9B;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,KAAK,EAAE,YAAY,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,eAAO,MAAM,YAAY,GAAI,mGAU1B,iBAAiB,KAAG,SA4LtB,CAAA"}
@@ -0,0 +1,165 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { getPlainDateFromDayNumber } from "../DatePicker/plainDate.js";
3
+ import { EmptyState } from "../EmptyState/EmptyState.js";
4
+ import { toClassName } from "../toClassName.js";
5
+ import { LaneTimelineLane } from "./LaneTimelineLane.js";
6
+ import { chooseAxisTickStep, formatAxisDate, getIsAxisReadable, toTimelineAxis, } from "./laneTimelineGeometry.js";
7
+ import { useTrackMeasurements } from "./useTrackMeasurements.js";
8
+ /**
9
+ * Room one tick label needs, as a multiple of the timeline's own
10
+ * font size.
11
+ *
12
+ * `Mon 12 Apr` is about 4.5 of them, and the number is bigger than
13
+ * the label looks because the two are measured against **different**
14
+ * sizes: the label renders at `text-xs` while this multiplies the
15
+ * container's own font size, which is the one the probe can read. A
16
+ * constant rather than a prop, because it is a fact about the label
17
+ * this component prints rather than a preference anybody has.
18
+ */
19
+ const TICK_LABEL_SIZE = 4.5;
20
+ /**
21
+ * The narrowest a day column may get before the axis stops being
22
+ * worth drawing, in em.
23
+ *
24
+ * ⚠️ **The one number in here that is a taste call**, and it was
25
+ * moved once already. 1.25em drew a seven-day axis into a 24rem
26
+ * sidebar, which is 25 pixels a day: the bars were real shapes and
27
+ * every one of their titles was `Mi…`, so the picture was worse than
28
+ * the list it was chosen over. 1.75em is roughly the narrowest
29
+ * column that still holds a short word, which puts a month at about
30
+ * 1030px of component and a week in anything past a phone.
31
+ *
32
+ * The case still worth arguing about is a quarter. Ninety days wants
33
+ * more than 2500px and therefore falls to the Narrow View on every
34
+ * screen here — and 6px a day does still show a *shape*, so somebody
35
+ * may prefer the smear to the list. It is a prop for that reason.
36
+ */
37
+ const DEFAULT_MIN_COLUMN_SIZE = 1.75;
38
+ /**
39
+ * How many bars a lane may stack before the rest are counted rather
40
+ * than drawn. Six is roughly a screen's worth of one lane.
41
+ */
42
+ const DEFAULT_MAX_ROW_COUNT = 6;
43
+ /**
44
+ * One horizontal lane per group, across a date axis, with anything
45
+ * that lasts more than a day drawn as a **bar**.
46
+ *
47
+ * ## What it is for
48
+ *
49
+ * A month grid gives every day the same box, so a thing that runs
50
+ * Tuesday to Friday is four separate entries and the fact that it is
51
+ * *one* thing is lost. Worse, every cell is the same size no matter
52
+ * how much is in it, so a grid cannot show that one person is
53
+ * carrying most of the week. A lane can: bars keep their real
54
+ * shape, and a lane with overlapping work stacks into rows and gets
55
+ * **taller**. The asymmetry then reads from across the room, before
56
+ * anybody counts anything.
57
+ *
58
+ * It is not a calendar. There is no event, no attendee and no
59
+ * recurrence in this API, because Docket wants the same shape for
60
+ * phases and Horizon wants it for a household — the library owns the
61
+ * **shape** and the app owns the **data**. What a lane holds is a
62
+ * `key`, a `label` and items with a `start`, an `end` and a `title`.
63
+ *
64
+ * ## `end` is INCLUSIVE, and that is the decision to know
65
+ *
66
+ * An off-by-one on a date range is invisible in both directions: a
67
+ * bar one day short and a bar one day long are both bars. So it is
68
+ * stated loudly here and again on the type — **`end` is the last day
69
+ * the item covers**. `2026-04-06` to `2026-04-06` is one day, and a
70
+ * seven-day week ends on its seventh day, not on the eighth. The
71
+ * alternative (a half-open interval, the way `Date` ranges and
72
+ * iCalendar's `DTEND` work) is the better model for *instants* and
73
+ * the wrong one for a human writing down when the roofers are
74
+ * coming: nobody says "Monday to Saturday" about a working week, so
75
+ * an exclusive end would make every consumer add a day on the way in
76
+ * and forget to on one of the paths.
77
+ * [Decision](../../../docs/decisions/2026-09-18-a-timeline-span-ends-on-its-last-day-and-the-axis-folds-on-measurement.md).
78
+ *
79
+ * ## The Narrow View is a LIST, not a pan surface
80
+ *
81
+ * Thirty columns have no narrow layout, and the two obvious answers
82
+ * are both wrong. Horizontal scrolling hides lanes behind a gesture
83
+ * with no affordance and fights the trackpad's own back-navigation
84
+ * — the same objection `Board` settled with *"no horizontal scroll,
85
+ * ever"*. Squeezing thirty columns into 390px gives each day 13
86
+ * pixels, which is not a timeline, it is a texture.
87
+ *
88
+ * So below the threshold the axis is **abandoned** rather than
89
+ * shrunk: each lane becomes a one-column list of its items, each one
90
+ * a line of text with its span written out in words. Nothing is
91
+ * hidden, nothing overflows, and the reading order is the one the
92
+ * fleet's text-heavy lists already use.
93
+ *
94
+ * ## It folds on a MEASUREMENT, not a breakpoint
95
+ *
96
+ * There is no `@media` and no `cq-` in this component, and neither
97
+ * could do the job: the question is not *how wide is the box* but
98
+ * **how wide is one day**, which is the width divided by a number
99
+ * that lives in the data. Thirty columns in 900px is a readable
100
+ * month and three hundred and sixty five columns in the same 900px
101
+ * is a grey smear, and no query can tell those apart. `Nav` folds
102
+ * its bar on a measured width for the weaker version of this
103
+ * reason; `useToolbarOverflow` writes the argument down.
104
+ *
105
+ * ⚠️ **It must not be sized by its own contents.** The component
106
+ * reads its own box to decide what to draw in it, so a shrink-
107
+ * wrapping parent makes the answer its own input. The root declares
108
+ * `container-type: inline-size` — not to query it, the same reason
109
+ * `Main` declares one — which forbids the element from being sized
110
+ * by what is inside it and makes that loop unformable. In a story
111
+ * this is what `align="stretch"` on the `StoryCell` is for.
112
+ *
113
+ * ## What it deliberately does not do
114
+ *
115
+ * No time of day: this is a **calendar-date** axis, so two things on
116
+ * one Tuesday stack rather than sit at 09:00 and 14:00. No "now"
117
+ * marker, no zoom, no drag to reschedule, no data. A range control
118
+ * belongs to the page — `DatePicker` already is one — and a bar you
119
+ * can drag is a write operation, which is a different component with
120
+ * a different decision behind it.
121
+ */
122
+ export const LaneTimeline = ({ className, emptyState, headingLevel = 3, label, lanes, locale, maxRowCount = DEFAULT_MAX_ROW_COUNT, minColumnSize = DEFAULT_MIN_COLUMN_SIZE, range, }) => {
123
+ const { fontSize, inlineSize, isMeasured, trackRef } = useTrackMeasurements();
124
+ const axis = toTimelineAxis(range);
125
+ const columnCount = axis?.columnCount ?? 0;
126
+ const isAxisReadable = getIsAxisReadable({
127
+ columnCount,
128
+ inlineSize,
129
+ isMeasured,
130
+ minColumnInlineSize: minColumnSize * fontSize,
131
+ });
132
+ const tickStep = chooseAxisTickStep({
133
+ columnCount,
134
+ inlineSize,
135
+ minTickInlineSize: TICK_LABEL_SIZE * fontSize,
136
+ });
137
+ /*
138
+ * An inline style, not a class. Tailwind scans source text for
139
+ * complete class strings, so a `grid-cols-[repeat(${n},…)]` is
140
+ * generated **never** — the grid silently falls back to one column
141
+ * and every bar lands on top of every other one, with nothing
142
+ * failing. `AdaptiveGrid` carries the same note about the same
143
+ * trap.
144
+ */
145
+ const columnTemplate = `repeat(${Math.max(columnCount, 1)}, minmax(0, 1fr))`;
146
+ const rangeCaption = axis &&
147
+ `${formatAxisDate({
148
+ date: getPlainDateFromDayNumber(axis.startDay),
149
+ locale,
150
+ })} to ${formatAxisDate({
151
+ date: getPlainDateFromDayNumber(axis.endDay),
152
+ locale,
153
+ })}`;
154
+ return (_jsxs("section", { "aria-label": label, className: toClassName("@container flex flex-col", className), children: [_jsxs("div", { "aria-hidden": "true", className: "grid grid-cols-[12rem_minmax(0,1fr)] gap-x-3 overflow-hidden", children: [_jsx("div", {}), _jsx("div", { className: "h-0", ref: trackRef })] }), axis === null ? ((emptyState ?? (_jsx(EmptyState, { description: "This timeline has no visible date range.", heading: "Nothing to show", headingLevel: headingLevel, size: "sm" })))) : lanes.length === 0 ? ((emptyState ?? (_jsx(EmptyState, { description: "Nothing has been added to this timeline yet.", heading: "No lanes yet", headingLevel: headingLevel, size: "sm" })))) : isAxisReadable ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid grid-cols-[12rem_minmax(0,1fr)] items-end gap-x-3 pb-1", children: [_jsx("span", { className: "min-w-0 truncate text-content-muted text-xs", title: rangeCaption ?? undefined, children: rangeCaption }), _jsx("div", { "aria-hidden": "true", className: "grid", style: {
155
+ gridTemplateColumns: columnTemplate,
156
+ }, children: Array.from({ length: columnCount }, (_unused, index) => index)
157
+ .filter((index) => index % tickStep === 0)
158
+ .map((index) => (_jsx("span", { className: "min-w-0 truncate text-content-muted text-xs", style: {
159
+ gridColumn: `${index + 1} / span ${Math.min(tickStep, columnCount - index)}`,
160
+ }, children: formatAxisDate({
161
+ date: getPlainDateFromDayNumber(axis.startDay + index),
162
+ locale,
163
+ }) }, axis.startDay + index))) })] }), lanes.map((lane, position) => (_jsx(LaneTimelineLane, { axis: axis, columnTemplate: columnTemplate, headingLevel: headingLevel, lane: lane, locale: locale, maxRowCount: maxRowCount, position: position, shape: "axis", tickStep: tickStep }, lane.key)))] })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "pb-1 text-content-muted text-xs", children: rangeCaption }), lanes.map((lane, position) => (_jsx(LaneTimelineLane, { axis: axis, columnTemplate: columnTemplate, headingLevel: headingLevel, lane: lane, locale: locale, maxRowCount: maxRowCount, position: position, shape: "list", tickStep: tickStep }, lane.key)))] }))] }));
164
+ };
165
+ //# sourceMappingURL=LaneTimeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LaneTimeline.js","sourceRoot":"","sources":["../../src/LaneTimeline/LaneTimeline.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ import type { CategoricalIndex } from "@charcuterie/tokens";
2
+ import type { ReactNode } from "react";
3
+ import type { TimelineSpan } from "./laneTimelineGeometry.ts";
4
+ /**
5
+ * Who owns the item's activation — nobody, a router, or a handler.
6
+ *
7
+ * A union rather than two loose optionals, the same call
8
+ * `BoardItemTitleLink` makes and for the same reason: `href` renders
9
+ * an `<a>` and `onSelect` renders a `<button>`, so a bar carrying
10
+ * both is one of them with the other silently dropped. On screen the
11
+ * two are identical.
12
+ */
13
+ type TimelineItemAction = {
14
+ /**
15
+ * Where the bar navigates. Routed through
16
+ * `RouterLinkProvider` like every other `href` in this
17
+ * library.
18
+ */
19
+ href?: string;
20
+ onSelect?: never;
21
+ } | {
22
+ href?: never;
23
+ /** For a timeline that opens a panel rather than a route. */
24
+ onSelect?: () => void;
25
+ };
26
+ export type TimelineItem = TimelineSpan & {
27
+ /**
28
+ * The bar's colour, when somebody has chosen one. Omitted, it is
29
+ * the **lane's**, because on this component colour means *which
30
+ * lane* — an item that picked its own hue out of the ten would
31
+ * read as belonging somewhere else. Pass this only when the item
32
+ * genuinely carries its own identity, and then put that identity
33
+ * in words too.
34
+ */
35
+ categorical?: CategoricalIndex;
36
+ key: string;
37
+ /**
38
+ * The words. A **string**, not a `ReactNode`, for the reason
39
+ * `BoardLane.label` is one: the same value goes into the bar's
40
+ * accessible name, the `title` a hovering reader gets, and the
41
+ * Narrow View's row — none of which can hold a node.
42
+ */
43
+ title: string;
44
+ } & TimelineItemAction;
45
+ export type LaneTimelineBarProps = {
46
+ className?: string;
47
+ item: TimelineItem;
48
+ /** The lane's hue, used when the item picked none. */
49
+ laneCategorical: CategoricalIndex;
50
+ /** What the bar says out loud: title, then the span in words. */
51
+ description: string;
52
+ /** Square the leading edge — the item began before this range. */
53
+ hasEarlierStart: boolean;
54
+ /** Square the trailing edge — it runs past this range. */
55
+ hasLaterEnd: boolean;
56
+ /**
57
+ * `bar` is the block on the axis. `row` is the Narrow View's
58
+ * full-width line, where the same item has room for two lines of
59
+ * text and no position to carry meaning.
60
+ */
61
+ shape: "bar" | "row";
62
+ };
63
+ /**
64
+ * One item, in either of the two shapes this component draws it in.
65
+ *
66
+ * ### The name is the whole of the accessibility argument
67
+ *
68
+ * A bar means something by **where it sits and how long it is**, and
69
+ * neither of those reaches a screen reader. Nor does the hue: ten
70
+ * categorical colours carry *which lane*, and colour alone failing
71
+ * WCAG 1.4.1 is the least of it — the lane is already a named group,
72
+ * so the colour is reinforcement rather than information.
73
+ *
74
+ * What is genuinely only in the geometry is the **span**, so every
75
+ * bar carries it as text: `description` is appended to the title in
76
+ * a `VisuallyHidden` and repeated in the `title` attribute. That
77
+ * second one is not an accessibility feature, it is for the sighted
78
+ * reader: a one-day bar is about twenty pixels wide and cannot show
79
+ * its own name at all.
80
+ *
81
+ * A native `title` rather than `Tooltip`, deliberately. A household
82
+ * week is two hundred bars, and two hundred floating-ui instances to
83
+ * describe boxes that are already described is a cost with nothing
84
+ * on the other side of it.
85
+ *
86
+ * ### The clipped edge is square, and it is also in words
87
+ *
88
+ * An item running out of the visible range loses the radius on that
89
+ * edge, which is the convention every Gantt chart uses. It is **not**
90
+ * the only signal:
91
+ * `description` already says "starts before this range", because a
92
+ * missing corner is not something anybody perceives without the
93
+ * unclipped bar beside it to compare against.
94
+ */
95
+ export declare const LaneTimelineBar: ({ className, description, hasEarlierStart, hasLaterEnd, item, laneCategorical, shape, }: LaneTimelineBarProps) => ReactNode;
96
+ export {};
97
+ //# sourceMappingURL=LaneTimelineBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LaneTimelineBar.d.ts","sourceRoot":"","sources":["../../src/LaneTimeline/LaneTimelineBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAUtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE7D;;;;;;;;GAQG;AACH,KAAK,kBAAkB,GACnB;IACE;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,KAAK,CAAA;CACjB,GACD;IACE,IAAI,CAAC,EAAE,KAAK,CAAA;IACZ,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA;AAEL,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG;IACxC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAA;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAA;CACd,GAAG,kBAAkB,CAAA;AAEtB,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,YAAY,CAAA;IAClB,sDAAsD;IACtD,eAAe,EAAE,gBAAgB,CAAA;IACjC,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAA;IACnB,kEAAkE;IAClE,eAAe,EAAE,OAAO,CAAA;IACxB,0DAA0D;IAC1D,WAAW,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,KAAK,EAAE,KAAK,GAAG,KAAK,CAAA;CACrB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,eAAe,GAAI,yFAQ7B,oBAAoB,KAAG,SAuHzB,CAAA"}
@@ -0,0 +1,69 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { CATEGORICAL_APPEARANCE_CLASS, CATEGORICAL_HOVER_CLASS, } from "../categoricalStyles.js";
3
+ import { FOCUS_RING_CLASS } from "../intentStyles.js";
4
+ import { UnstyledLink } from "../RouterLink/UnstyledLink.js";
5
+ import { toClassName } from "../toClassName.js";
6
+ import { VisuallyHidden } from "../VisuallyHidden/VisuallyHidden.js";
7
+ /**
8
+ * One item, in either of the two shapes this component draws it in.
9
+ *
10
+ * ### The name is the whole of the accessibility argument
11
+ *
12
+ * A bar means something by **where it sits and how long it is**, and
13
+ * neither of those reaches a screen reader. Nor does the hue: ten
14
+ * categorical colours carry *which lane*, and colour alone failing
15
+ * WCAG 1.4.1 is the least of it — the lane is already a named group,
16
+ * so the colour is reinforcement rather than information.
17
+ *
18
+ * What is genuinely only in the geometry is the **span**, so every
19
+ * bar carries it as text: `description` is appended to the title in
20
+ * a `VisuallyHidden` and repeated in the `title` attribute. That
21
+ * second one is not an accessibility feature, it is for the sighted
22
+ * reader: a one-day bar is about twenty pixels wide and cannot show
23
+ * its own name at all.
24
+ *
25
+ * A native `title` rather than `Tooltip`, deliberately. A household
26
+ * week is two hundred bars, and two hundred floating-ui instances to
27
+ * describe boxes that are already described is a cost with nothing
28
+ * on the other side of it.
29
+ *
30
+ * ### The clipped edge is square, and it is also in words
31
+ *
32
+ * An item running out of the visible range loses the radius on that
33
+ * edge, which is the convention every Gantt chart uses. It is **not**
34
+ * the only signal:
35
+ * `description` already says "starts before this range", because a
36
+ * missing corner is not something anybody perceives without the
37
+ * unclipped bar beside it to compare against.
38
+ */
39
+ export const LaneTimelineBar = ({ className, description, hasEarlierStart, hasLaterEnd, item, laneCategorical, shape, }) => {
40
+ const categorical = item.categorical ?? laneCategorical;
41
+ const isInteractive = Boolean(item.href ?? item.onSelect);
42
+ const content = (_jsxs(_Fragment, { children: [_jsx("span", { className: toClassName("min-w-0 flex-1", shape === "bar"
43
+ ? "truncate"
44
+ : "wrap-anywhere text-sm"), children: item.title }), shape === "row" ? (_jsx("span", { className: "text-content-muted text-xs", children: description })) : isInteractive ? null : (_jsx(VisuallyHidden, { children: description }))] }));
45
+ /**
46
+ * Only the bar shape gets one, and it carries the **title** as
47
+ * well as the span. The Narrow View prints both already, and a
48
+ * tooltip repeating text that is on screen is noise a pointer
49
+ * user cannot dismiss.
50
+ */
51
+ const sentence = `${item.title}, ${description}`;
52
+ const hoverText = shape === "bar" ? sentence : undefined;
53
+ const shellClassName = toClassName("w-full min-w-0 border px-1.5 text-xs leading-tight", shape === "bar"
54
+ ? "flex min-h-5 items-center rounded-sm"
55
+ : "flex flex-col gap-0.5 rounded-md py-1", CATEGORICAL_APPEARANCE_CLASS[categorical].soft,
56
+ // A square edge where the item leaves the range. `rounded-*-none`
57
+ // rather than a different component, so a clipped bar and a whole
58
+ // one are the same box with one corner rule changed.
59
+ hasEarlierStart && shape === "bar" && "rounded-s-none", hasLaterEnd && shape === "bar" && "rounded-e-none", isInteractive && "cursor-pointer", isInteractive &&
60
+ CATEGORICAL_HOVER_CLASS[categorical].soft, isInteractive && FOCUS_RING_CLASS, className);
61
+ if (item.href) {
62
+ return (_jsx(UnstyledLink, { "aria-label": sentence, className: shellClassName, href: item.href, title: hoverText, children: content }));
63
+ }
64
+ if (item.onSelect) {
65
+ return (_jsx("button", { "aria-label": sentence, className: toClassName(shellClassName, "text-start"), onClick: item.onSelect, title: hoverText, type: "button", children: content }));
66
+ }
67
+ return (_jsx("span", { className: shellClassName, title: hoverText, children: content }));
68
+ };
69
+ //# sourceMappingURL=LaneTimelineBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LaneTimelineBar.js","sourceRoot":"","sources":["../../src/LaneTimeline/LaneTimelineBar.tsx"],"names":[],"mappings":";AAGA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,GACxB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAAgC,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAsC,CAAA;AAmErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAC9B,SAAS,EACT,WAAW,EACX,eAAe,EACf,WAAW,EACX,IAAI,EACJ,eAAe,EACf,KAAK,GACgB,EAAa,EAAE;IACpC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,eAAe,CAAA;IAEvD,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAA;IAEzD,MAAM,OAAO,GAAG,CACd,8BASE,eACE,SAAS,EAAE,WAAW,CACpB,gBAAgB,EAChB,KAAK,KAAK,KAAK;oBACb,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,uBAAuB,CAC5B,YAEA,IAAI,CAAC,KAAK,GACN,EAsBN,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,CACjB,eAAM,SAAS,EAAC,4BAA4B,YACzC,WAAW,GACP,CACR,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACzB,KAAC,cAAc,cAAE,WAAW,GAAkB,CAC/C,IACA,CACJ,CAAA;IAED;;;;;OAKG;IACH,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,KAAK,KAAK,WAAW,EAAE,CAAA;IAEhD,MAAM,SAAS,GAAG,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAExD,MAAM,cAAc,GAAG,WAAW,CAChC,oDAAoD,EACpD,KAAK,KAAK,KAAK;QACb,CAAC,CAAC,sCAAsC;QACxC,CAAC,CAAC,uCAAuC,EAC3C,4BAA4B,CAAC,WAAW,CAAC,CAAC,IAAI;IAC9C,kEAAkE;IAClE,kEAAkE;IAClE,qDAAqD;IACrD,eAAe,IAAI,KAAK,KAAK,KAAK,IAAI,gBAAgB,EACtD,WAAW,IAAI,KAAK,KAAK,KAAK,IAAI,gBAAgB,EAClD,aAAa,IAAI,gBAAgB,EACjC,aAAa;QACX,uBAAuB,CAAC,WAAW,CAAC,CAAC,IAAI,EAC3C,aAAa,IAAI,gBAAgB,EACjC,SAAS,CACV,CAAA;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CACL,KAAC,YAAY,kBACC,QAAQ,EACpB,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,IAAI,CAAC,IAAI,EACf,KAAK,EAAE,SAAS,YAEf,OAAO,GACK,CAChB,CAAA;IACH,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,CACL,+BACc,QAAQ,EACpB,SAAS,EAAE,WAAW,CACpB,cAAc,EACd,YAAY,CACb,EACD,OAAO,EAAE,IAAI,CAAC,QAAQ,EACtB,KAAK,EAAE,SAAS,EAChB,IAAI,EAAC,QAAQ,YAEZ,OAAO,GACD,CACV,CAAA;IACH,CAAC;IAED,OAAO,CACL,eAAM,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,YAC9C,OAAO,GACH,CACR,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,84 @@
1
+ import type { CategoricalIndex } from "@charcuterie/tokens";
2
+ import type { ReactNode } from "react";
3
+ import type { TimelineItem } from "./LaneTimelineBar.tsx";
4
+ import type { TimelineAxis } from "./laneTimelineGeometry.ts";
5
+ export type TimelineLane = {
6
+ /**
7
+ * Which of the ten hues this lane wears, overriding the one its
8
+ * **position** would have given it.
9
+ *
10
+ * Reach for it when a lane's colour means something outside this
11
+ * set — a person who is the same colour on every screen of the
12
+ * app, a pair that must not drift apart when a third lane is
13
+ * inserted between them. An overridden lane keeps its hue and the
14
+ * rest go on walking `CATEGORICAL_SEQUENCE` from their own
15
+ * positions, so naming one does not force naming all of them.
16
+ */
17
+ categorical?: CategoricalIndex;
18
+ /**
19
+ * Where the lane's heading navigates — the "show me only this
20
+ * lane" route. A link **inside** the heading, never a heading
21
+ * replaced by a link, exactly as `BoardLane.href` is: the heading
22
+ * keeps its level, its id, and its job of naming the group.
23
+ */
24
+ href?: string;
25
+ items: readonly TimelineItem[];
26
+ key: string;
27
+ /**
28
+ * The lane's name. A **string**: it names the group, and a group
29
+ * with a `ReactNode` name is a group with no name.
30
+ */
31
+ label: string;
32
+ };
33
+ export type LaneTimelineLaneProps = {
34
+ axis: TimelineAxis;
35
+ /** The CSS track list, built once by the parent and shared. */
36
+ columnTemplate: string;
37
+ headingLevel: 2 | 3 | 4 | 5;
38
+ lane: TimelineLane;
39
+ locale?: string;
40
+ maxRowCount: number;
41
+ /** Where this lane sits in the set, for its default hue. */
42
+ position: number;
43
+ /**
44
+ * `axis` is the bars across the date axis. `list` is the Narrow
45
+ * View, where there is no axis and each item is a line of text.
46
+ */
47
+ shape: "axis" | "list";
48
+ /** Draw a separator every this many columns. */
49
+ tickStep: number;
50
+ };
51
+ /**
52
+ * One lane: its name, how much it is carrying, and either a track of
53
+ * bars or a list of lines.
54
+ *
55
+ * ### A lane is a `group`, not a landmark
56
+ *
57
+ * The same call `BoardLaneList` makes, and it was a real axe failure
58
+ * there before it changed. A named `<section>` is a `region`, so a
59
+ * timeline of eight lanes would put eight landmarks on a page that
60
+ * has one job, and two timelines on one page would put two landmarks
61
+ * with the same name in the document — which is `landmark-unique`.
62
+ * It is a `<div role="group">` rather than a `<section role="group">`
63
+ * because axe matches `section[aria-labelledby]` on the **element**
64
+ * and audits it as a landmark even after the role is overridden.
65
+ *
66
+ * ### The count is what the lane carries IN THIS RANGE
67
+ *
68
+ * Not `items.length`. A consumer hands over a month and shows a
69
+ * week; counting the array would print "31" beside a lane with two
70
+ * bars on it. `inRangeCount` includes anything the row limit hid, so
71
+ * a lane cannot look lighter by being more loaded.
72
+ *
73
+ * ### A lane gets TALLER when it is busy, and that is the design
74
+ *
75
+ * Overlapping items stack into rows (`toPackedLane`), so a lane
76
+ * carrying three things at once is three bars tall while one
77
+ * carrying them in sequence is one. Load asymmetry then reads as
78
+ * height from across the room, before anybody counts anything —
79
+ * which is the whole reason this component exists rather than a
80
+ * month grid, where every cell is the same size no matter what is
81
+ * in it.
82
+ */
83
+ export declare const LaneTimelineLane: ({ axis, columnTemplate, headingLevel, lane, locale, maxRowCount, position, shape, tickStep, }: LaneTimelineLaneProps) => ReactNode;
84
+ //# sourceMappingURL=LaneTimelineLane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LaneTimelineLane.d.ts","sourceRoot":"","sources":["../../src/LaneTimeline/LaneTimelineLane.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAK3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAM7D,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAA;IAC9B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,SAAS,YAAY,EAAE,CAAA;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,YAAY,CAAA;IAClB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3B,IAAI,EAAE,YAAY,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,gBAAgB,GAAI,+FAU9B,qBAAqB,KAAG,SA6N1B,CAAA"}