@setsquare/ui 0.12.0 → 0.13.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.
@@ -1,9 +1,17 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { GripVertical } from 'lucide-react';
4
- import { Button as RACButton, GridList as RACGridList, GridListItem as RACGridListItem, } from 'react-aria-components';
3
+ import { useContext, useRef, useState } from 'react';
4
+ import { EllipsisVertical, GripVertical } from 'lucide-react';
5
+ import { Button as RACButton, GridList as RACGridList, GridListItem as RACGridListItem, useDragAndDrop, DragAndDropContext, } from 'react-aria-components';
6
+ import { announce } from '../lib/announce.js';
7
+ import { moveTarget } from '../lib/card-order.js';
5
8
  import { cn } from '../lib/cn.js';
9
+ import { useLabels } from '../lib/locale.js';
10
+ import { withoutSoftHyphens } from '../lib/soft-hyphen.js';
11
+ import { useHyphenated } from '../lib/use-hyphenated.js';
6
12
  import { SelectionCheckbox } from './checkbox.js';
13
+ import { DropIndicator, DropLayoutContext } from './drop-indicator.js';
14
+ import { Menu, MenuItem, MenuSection, MenuTrigger, Popover } from './menu.js';
7
15
  /**
8
16
  * A list of items people act on — members, files, integrations — where each row can hold its own buttons.
9
17
  * ↑ ↓ move between rows and → through a row's own controls; Tab leaves the list. With
@@ -15,7 +23,14 @@ import { SelectionCheckbox } from './checkbox.js';
15
23
  * button, which is how a keyboard or screen reader drag starts.
16
24
  */
17
25
  export function GridList({ className, ...props }) {
18
- return (_jsx(RACGridList, { ...props, className: cn('relative flex max-h-[inherit] flex-col overflow-auto rounded-lg border border-border bg-card text-sm outline-none data-focus-visible:focus-ring', 'data-drop-target:bg-brand-subtle data-drop-target:outline-2 data-drop-target:outline-solid data-drop-target:outline-brand data-drop-target:-outline-offset-2', className) }));
26
+ const layout = props.layout ?? 'stack';
27
+ return (_jsx(DropLayoutContext.Provider, { value: layout, children: _jsx(RACGridList, { ...props, className: cn(layout === 'grid'
28
+ ? // Cards in a wrapping row, as many as fit, `--card-gap` apart. A wrapping row rather than a CSS grid:
29
+ // while a drag is on, React Aria puts a drop indicator beside every card, and in a grid each would
30
+ // take a cell; in a row they take no room. No box of its own: the cards are boxes. Padding leaves
31
+ // room for a card's focus ring inside the scroller.
32
+ 'relative flex max-h-[inherit] flex-wrap content-start gap-(--card-gap) overflow-auto p-2 text-sm outline-none data-focus-visible:focus-ring'
33
+ : 'relative flex max-h-[inherit] flex-col overflow-auto rounded-lg border border-border bg-card text-sm outline-none data-focus-visible:focus-ring', 'data-drop-target:bg-brand-subtle data-drop-target:outline-2 data-drop-target:outline-solid data-drop-target:outline-brand data-drop-target:-outline-offset-2', className) }) }));
19
34
  }
20
35
  /** Selected: brand-subtle, the 3px sidebar-primary marker and a ticked box — the same signals as a table row. */
21
36
  export function GridListItem({ children, description, actions, dragLabel, className, ...props }) {
@@ -29,4 +44,101 @@ export function GridListItem({ children, description, actions, dragLabel, classN
29
44
  // Forced colours drop the selected ground and the inset marker: draw the marker in Highlight instead.
30
45
  "forced-colors:data-selected:before:absolute forced-colors:data-selected:before:inset-y-1 forced-colors:data-selected:before:start-0 forced-colors:data-selected:before:w-[3px] forced-colors:data-selected:before:bg-[Highlight] forced-colors:data-selected:before:forced-color-adjust-none forced-colors:data-selected:before:content-['']", className), children: ({ selectionMode, selectionBehavior, allowsDragging }) => (_jsxs(_Fragment, { children: [allowsDragging && (_jsx(RACButton, { slot: "drag", "aria-label": dragLabel, className: "group/grid-drag relative flex min-h-target min-w-target shrink-0 cursor-grab items-center justify-center outline-none", children: _jsx("span", { className: "flex size-control-sm items-center justify-center rounded-md text-muted-foreground group-data-focus-visible/grid-drag:focus-ring group-data-hovered/grid-drag:bg-muted group-data-hovered/grid-drag:text-foreground", children: _jsx(GripVertical, { "aria-hidden": "true", className: "size-4" }) }) })), selectionMode !== 'none' && selectionBehavior === 'toggle' && (_jsx(SelectionCheckbox, { className: "-ml-1" })), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "leading-5 font-medium text-foreground", children: children }), description && (_jsx("span", { className: "text-[13px] leading-5 text-muted-foreground", children: description }))] }), actions && _jsx("span", { className: "flex shrink-0 items-center gap-1", children: actions })] })) }));
31
46
  }
47
+ export const gridListCardLabels = {
48
+ options: 'Options for {title}',
49
+ moveSection: 'Move',
50
+ moveFirst: 'Move to start',
51
+ moveEarlier: 'Move earlier',
52
+ moveLater: 'Move later',
53
+ moveLast: 'Move to end',
54
+ moved: '{title} moved to position {position} of {count}',
55
+ movedSeveral: '{moved, plural, one {# card} other {# cards}} moved, starting at position {position} of {count}',
56
+ };
57
+ /**
58
+ * Reordering cards in a GridList, by drag and without: give `dragAndDropHooks` to the GridList and `order` to each
59
+ * GridListCard. Dragging a selected card drags the selected ones; a card's menu moves it (or the selection it's in)
60
+ * to the start, a place earlier, a place later or the end, which is the single-pointer way to reorder that 2.5.7
61
+ * asks for. Both call `onReorder` once per move.
62
+ */
63
+ export function useCardOrder({ onReorder }) {
64
+ const { dragAndDropHooks } = useDragAndDrop({
65
+ getItems: (dragged) => [...dragged].map((key) => ({ 'text/plain': String(key) })),
66
+ onReorder: (e) => onReorder({
67
+ keys: [...e.keys],
68
+ target: e.target.key,
69
+ position: e.target.dropPosition === 'after' ? 'after' : 'before',
70
+ }),
71
+ renderDropIndicator: (target) => _jsx(DropIndicator, { target: target }),
72
+ });
73
+ return { dragAndDropHooks, reorder: onReorder };
74
+ }
75
+ const MOVES = ['first', 'earlier', 'later', 'last'];
76
+ const MOVE_LABEL = {
77
+ first: 'moveFirst',
78
+ earlier: 'moveEarlier',
79
+ later: 'moveLater',
80
+ last: 'moveLast',
81
+ };
82
+ /**
83
+ * A card in a GridList with `layout="grid"`: a picture, a title, a line and a status, then a footer with its drag
84
+ * button, its selection checkbox and its menu, in that order, each a target of its own, none over the picture. The
85
+ * card is the row: arrow keys move between cards, Tab through a card's own controls. Selected: the `brand-subtle`
86
+ * ground and a 2px `brand` ring, and a ticked box; in forced colours a `Highlight` ring.
87
+ */
88
+ export function GridListCard({ id, title, media, description, status, menu, order, dragLabel, labels, className, ...props }) {
89
+ const t = useLabels('gridListCard', gridListCardLabels, labels);
90
+ const card = useRef(null);
91
+ const [shownTitle, titleRef] = useHyphenated(title);
92
+ const name = withoutSoftHyphens(title);
93
+ const hasMenu = !!menu || !!order;
94
+ return (_jsx(RACGridListItem, { ...props, id: id, ref: card, textValue: name, className: cn(
95
+ // Layer 1: the card is the target. Its width is the grid's, `--card-width`.
96
+ 'group/card relative flex w-(--card-width) min-w-0 cursor-default flex-col overflow-hidden rounded-lg border border-border bg-card text-card-foreground outline-none', 'data-hovered:cursor-pointer data-disabled:cursor-not-allowed data-disabled:opacity-60', 'data-selected:border-brand data-selected:bg-brand-subtle data-selected:shadow-[0_0_0_1px_var(--brand)]', 'data-focus-visible:focus-ring data-dragging:opacity-50',
97
+ // Forced colours drop the ground and the shadow: a Highlight ring inside its edge instead.
98
+ "forced-colors:data-selected:after:pointer-events-none forced-colors:data-selected:after:absolute forced-colors:data-selected:after:inset-0 forced-colors:data-selected:after:rounded-lg forced-colors:data-selected:after:border-2 forced-colors:data-selected:after:border-[Highlight] forced-colors:data-selected:after:forced-color-adjust-none forced-colors:data-selected:after:content-['']", className), children: ({ selectionMode, selectionBehavior, allowsDragging }) => (_jsxs(_Fragment, { children: [media && (_jsx("span", { "aria-hidden": "true", className: "block aspect-video overflow-hidden bg-muted", children: media })), _jsxs("span", { className: "flex min-w-0 flex-col gap-0.5 px-3 pt-2", children: [_jsx("span", { className: "min-w-0 leading-5 font-semibold hyphens-auto text-foreground", children: _jsx("span", { ref: titleRef, className: "inline-block max-w-full", children: shownTitle }) }), description && (_jsx("span", { className: "text-[13px] leading-5 text-muted-foreground", children: description })), status && _jsx("span", { className: "flex flex-wrap items-center gap-1", children: status })] }), _jsxs("span", { className: "mt-auto flex items-center gap-1 px-1 pt-1 pb-1", children: [allowsDragging && (_jsx(RACButton, { slot: "drag", "aria-label": dragLabel, className: "group/card-drag relative flex min-h-target min-w-target shrink-0 cursor-grab items-center justify-center outline-none", children: _jsx("span", { className: "flex size-control-sm items-center justify-center rounded-md text-muted-foreground group-data-focus-visible/card-drag:focus-ring group-data-hovered/card-drag:bg-muted group-data-hovered/card-drag:text-foreground", children: _jsx(GripVertical, { "aria-hidden": "true", className: "size-4" }) }) })), selectionMode !== 'none' && selectionBehavior === 'toggle' && _jsx(SelectionCheckbox, {}), _jsx("span", { className: "flex-1" }), hasMenu && (_jsx(CardMenuButton, { id: id, name: name, menu: menu, order: order, card: card, t: t }))] })] })) }));
99
+ }
100
+ /**
101
+ * The card's menu button. Rendered inside the card as the list draws it, which is where the list can be read: a
102
+ * card's own body runs in React Aria's first, hidden pass, and React Aria gives an item no list state of its own (it
103
+ * clears ListStateContext there). Its drag state has the list's collection and selection, and is there whenever the
104
+ * cards can be reordered, which `useCardOrder` makes so.
105
+ */
106
+ function CardMenuButton(props) {
107
+ const { dragState } = useContext(DragAndDropContext);
108
+ const state = dragState ?? null;
109
+ const [open, setOpen] = useState(false);
110
+ return (_jsxs(MenuTrigger, { isOpen: open, onOpenChange: setOpen, children: [_jsx(RACButton, { "aria-label": props.t('options', { title: props.name }), className: "group/card-menu relative flex min-h-target min-w-target shrink-0 cursor-pointer items-center justify-center outline-none", children: _jsx("span", { className: "flex size-control-sm items-center justify-center rounded-md text-muted-foreground group-data-focus-visible/card-menu:focus-ring group-data-hovered/card-menu:bg-muted group-data-hovered/card-menu:text-foreground group-data-pressed/card-menu:bg-muted", children: _jsx(EllipsisVertical, { "aria-hidden": "true", className: "size-4" }) }) }), _jsx(Popover, { placement: "bottom end", children: _jsx(CardMenu, { ...props, state: state }) })] }));
111
+ }
112
+ function CardMenu({ id, name, menu, order, card, t, state, }) {
113
+ const keys = state
114
+ ? [...state.collection.getKeys()].filter((k) => state.collection.getItem(k)?.type === 'item')
115
+ : [id];
116
+ const selection = state?.selectionManager;
117
+ // The cards a move takes: the selection, when this card is in it, or this card alone.
118
+ const moving = !selection?.isSelected(id)
119
+ ? [id]
120
+ : selection.isSelectAll
121
+ ? keys
122
+ : keys.filter((k) => selection.selectedKeys.has(k));
123
+ const targets = Object.fromEntries(MOVES.map((m) => [m, order ? moveTarget(keys, moving, m) : null]));
124
+ const doMove = (move) => {
125
+ const reorder = targets[move];
126
+ if (!order || !reorder)
127
+ return;
128
+ order.reorder(reorder);
129
+ // Where the first moved card ends up, counted from 1.
130
+ const rest = keys.filter((k) => !reorder.keys.includes(k));
131
+ const at = rest.indexOf(reorder.target) + (reorder.position === 'after' ? 1 : 0);
132
+ announce(reorder.keys.length === 1
133
+ ? t('moved', { title: name, position: at + 1, count: keys.length })
134
+ : t('movedSeveral', { moved: reorder.keys.length, position: at + 1, count: keys.length }));
135
+ // The card moved in the page: keep focus on it, after the menu has handed focus back.
136
+ requestAnimationFrame(() => requestAnimationFrame(() => card.current?.focus()));
137
+ };
138
+ return (_jsxs(Menu, { "aria-label": t('options', { title: name }), disabledKeys: MOVES.filter((m) => !targets[m]).map((m) => `move-${m}`), onAction: (key) => {
139
+ const move = String(key).replace(/^move-/, '');
140
+ if (MOVES.includes(move))
141
+ doMove(move);
142
+ }, children: [menu, order && (_jsx(MenuSection, { title: t('moveSection'), children: MOVES.map((m) => (_jsx(MenuItem, { id: `move-${m}`, children: t(MOVE_LABEL[m]) }, m))) }))] }));
143
+ }
32
144
  //# sourceMappingURL=grid-list.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"grid-list.js","sourceRoot":"","sources":["../../src/ui/grid-list.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EACL,MAAM,IAAI,SAAS,EACnB,QAAQ,IAAI,WAAW,EACvB,YAAY,IAAI,eAAe,GAGhC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAQlD;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CAAmB,EAAE,SAAS,EAAE,GAAG,KAAK,EAAoB;IAClF,OAAO,CACL,KAAC,WAAW,OACN,KAAK,EACT,SAAS,EAAE,EAAE,CACX,iJAAiJ,EACjJ,8JAA8J,EAC9J,SAAS,CACV,GACD,CACH,CAAC;AACJ,CAAC;AAaD,iHAAiH;AACjH,MAAM,UAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,WAAW,EACX,OAAO,EACP,SAAS,EACT,SAAS,EACT,GAAG,KAAK,EACU;IAClB,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC3F,OAAO,CACL,KAAC,eAAe,OACV,KAAK,EACT,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,CAChC,EAAE;QACA,sGAAsG;QACtG,qKAAqK;QACrK,sGAAsG;QACtG,6DAA6D;QAC7D,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAChC,4OAA4O,EAC5O,uLAAuL;QACvL,sGAAsG;QACtG,8UAA8U,EAC9U,SAAS,CACV,YAGF,CAAC,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,CACzD,8BACG,cAAc,IAAI,CACjB,KAAC,SAAS,IACR,IAAI,EAAC,MAAM,gBACC,SAAS,EACrB,SAAS,EAAC,uHAAuH,YAEjI,eAAM,SAAS,EAAC,oNAAoN,YAClO,KAAC,YAAY,mBAAa,MAAM,EAAC,SAAS,EAAC,QAAQ,GAAG,GACjD,GACG,CACb,EACA,aAAa,KAAK,MAAM,IAAI,iBAAiB,KAAK,QAAQ,IAAI,CAC7D,KAAC,iBAAiB,IAAC,SAAS,EAAC,OAAO,GAAG,CACxC,EACD,gBAAM,SAAS,EAAC,8BAA8B,aAC5C,eAAM,SAAS,EAAC,uCAAuC,YAAE,QAAQ,GAAQ,EACxE,WAAW,IAAI,CACd,eAAM,SAAS,EAAC,6CAA6C,YAAE,WAAW,GAAQ,CACnF,IACI,EACN,OAAO,IAAI,eAAM,SAAS,EAAC,kCAAkC,YAAE,OAAO,GAAQ,IAC9E,CACJ,GACe,CACnB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"grid-list.js","sourceRoot":"","sources":["../../src/ui/grid-list.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../src/ui/timeline.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../src/ui/timeline.tsx"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Children, createContext, isValidElement, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
3
+ import { Children, createContext, isValidElement, memo, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from 'react';
4
4
  import { ChevronRight, EllipsisVertical } from 'lucide-react';
5
5
  import { Button as RACButton, Focusable, ToggleButton, Tree as RACTree, TreeItem as RACTreeItem, TreeItemContent, TooltipTrigger, useLocale, } from 'react-aria-components';
6
6
  import { cn } from '../lib/cn.js';
@@ -29,6 +29,13 @@ export const timelineLabels = {
29
29
  wasReset: '{label} reset to {time}',
30
30
  };
31
31
  const TimelineContext = createContext(null);
32
+ /**
33
+ * The playhead's time, on its own: it changes every frame while media plays, and only the playhead and its line
34
+ * read it, so lanes, items and markers don't render again with it.
35
+ */
36
+ const TimeContext = createContext(undefined);
37
+ /** The part in view, for the ruler's ticks and the slots: it changes as the timeline scrolls. */
38
+ const ViewContext = createContext({ start: 0, end: 0 });
32
39
  function useTimeline(part) {
33
40
  const value = useContext(TimelineContext);
34
41
  if (!value)
@@ -46,16 +53,21 @@ export function useTimelineMove() {
46
53
  function useControlled(value, initial, onChange) {
47
54
  const [own, setOwn] = useState(initial);
48
55
  const controlled = value !== undefined;
49
- return [
50
- controlled ? value : own,
51
- (next) => {
52
- if (!controlled)
53
- setOwn(next);
54
- onChange?.(next);
55
- },
56
- ];
56
+ // The setter keeps its identity across renders, so the context it goes in can too.
57
+ const latest = useRef(onChange);
58
+ useEffect(() => {
59
+ latest.current = onChange;
60
+ });
61
+ const set = useCallback((next) => {
62
+ if (!controlled)
63
+ setOwn(next);
64
+ latest.current?.(next);
65
+ }, [controlled]);
66
+ return [controlled ? value : own, set];
57
67
  }
58
68
  const defaultStep = (format, fps) => format === 'frames' || format === 'timecode' ? 1 / fps : format === 'date' ? 900 : 0.1;
69
+ /** One empty list for every timeline without snap points: a new `[]` each render would change the context. */
70
+ const NO_POINTS = [];
59
71
  /** AAA as products mark it and as the design-system artifact does. */
60
72
  const AAA = '[data-conformance="aaa"], [data-theme$="-aaa"]';
61
73
  /**
@@ -69,7 +81,7 @@ const AAA = '[data-conformance="aaa"], [data-theme$="-aaa"]';
69
81
  * axis runs left to right; right-to-left layouts aren't supported yet. Under it, a line says what moving a marker
70
82
  * did (snapped, picked up, put down), and is read out as it changes.
71
83
  */
72
- export function Timeline({ duration, start = 0, format = 'seconds', fps = 25, timeZone, pxPerSecond: pps = 100, step: givenStep, time: givenTime, defaultTime, onTimeChange, snapPoints = [], selectedItem: givenItem, defaultSelectedItem = null, onSelectedItemChange, labelWidth = 160, maxHeight, followPlayhead = true, labels, className, children, ...name }) {
84
+ export function Timeline({ duration, start = 0, format = 'seconds', fps = 25, timeZone, pxPerSecond: pps = 100, step: givenStep, time: givenTime, defaultTime, onTimeChange, snapPoints = NO_POINTS, selectedItem: givenItem, defaultSelectedItem = null, onSelectedItemChange, labelWidth = 160, maxHeight, followPlayhead = true, labels, className, children, ...name }) {
73
85
  const t = useLabels('timeline', timelineLabels, labels);
74
86
  const { locale } = useLocale();
75
87
  const end = start + duration;
@@ -85,37 +97,56 @@ export function Timeline({ duration, start = 0, format = 'seconds', fps = 25, ti
85
97
  // Before the scroller is measured (and on the server), assume a wide screen's worth is in view.
86
98
  const [scroll, setScroll] = useState({ left: 0, width: 1600 });
87
99
  const scroller = useRef(null);
88
- const toX = (s) => (s - start) * pps;
89
- const value = {
100
+ const seek = useCallback((s) => setTime(clampTime(s, start, end)), [setTime, start, end]);
101
+ // Everything but the playhead's time and the part in view, kept as one value while none of it changes: playback
102
+ // and scrolling don't render lanes, items and markers again.
103
+ const value = useMemo(() => {
104
+ const toX = (s) => (s - start) * pps;
105
+ return {
106
+ start,
107
+ end,
108
+ pps,
109
+ step,
110
+ trackWidth,
111
+ scale,
112
+ toX,
113
+ timeAt: (clientX, track) => clampTime(start + (clientX - track.getBoundingClientRect().left) / pps, start, end),
114
+ show: (s, shownStep = step) => formatTime(s, scale, shownStep),
115
+ speak: (s) => speakTime(s, scale, {
116
+ frames: (count) => t('frames', { count }),
117
+ frame: (frame) => t('frame', { frame }),
118
+ }),
119
+ t,
120
+ hasPlayhead,
121
+ seek,
122
+ snapPoints,
123
+ selectedItem,
124
+ selectItem,
125
+ announce: setStatus,
126
+ picked,
127
+ pick,
128
+ moving,
129
+ setMoving,
130
+ };
131
+ }, [
90
132
  start,
91
133
  end,
92
134
  pps,
93
135
  step,
94
136
  trackWidth,
95
137
  scale,
96
- toX,
97
- timeAt: (clientX, track) => clampTime(start + (clientX - track.getBoundingClientRect().left) / pps, start, end),
98
- show: (s, shownStep = step) => formatTime(s, scale, shownStep),
99
- speak: (s) => speakTime(s, scale, {
100
- frames: (count) => t('frames', { count }),
101
- frame: (frame) => t('frame', { frame }),
102
- }),
103
138
  t,
104
- time: hasPlayhead ? time : undefined,
105
- seek: (s) => setTime(clampTime(s, start, end)),
139
+ hasPlayhead,
140
+ seek,
106
141
  snapPoints,
107
142
  selectedItem,
108
143
  selectItem,
109
- announce: setStatus,
110
144
  picked,
111
- pick,
112
145
  moving,
113
- setMoving,
114
- view: {
115
- start: clampTime(start + scroll.left / pps, start, end),
116
- end: clampTime(start + (scroll.left + scroll.width) / pps, start, end),
117
- },
118
- };
146
+ ]);
147
+ const viewStart = clampTime(start + scroll.left / pps, start, end);
148
+ const viewEnd = clampTime(start + (scroll.left + scroll.width) / pps, start, end);
149
+ const view = useMemo(() => ({ start: viewStart, end: viewEnd }), [viewStart, viewEnd]);
119
150
  // Track what's in view, for the ruler's ticks and the slots: on scroll, and as the scroller resizes.
120
151
  useEffect(() => {
121
152
  const el = scroller.current;
@@ -158,9 +189,9 @@ export function Timeline({ duration, start = 0, format = 'seconds', fps = 25, ti
158
189
  picked.cancel();
159
190
  }
160
191
  };
161
- return (_jsx(TimelineContext.Provider, { value: value, children: _jsxs("div", { role: "group", ...name, onKeyDownCapture: onKeyDownCapture, style: {
162
- '--timeline-label-width': `${labelWidth}px`,
163
- }, className: cn('relative flex flex-col overflow-hidden rounded-lg border border-border bg-background text-sm', className), children: [_jsx("div", { ref: scroller, "data-timeline-scroller": "", style: { maxHeight }, className: "relative overflow-auto overscroll-contain [scroll-padding-block-start:var(--lane-height)] [scroll-padding-inline-start:var(--timeline-label-width)]", children: _jsxs("div", { className: "relative", style: { width: `calc(var(--timeline-label-width) + ${trackWidth}px)` }, children: [children, playheadX !== null && (_jsx("div", { "aria-hidden": "true", "data-timeline-playhead-line": "", className: "pointer-events-none absolute inset-y-0 z-10 w-0.5 -translate-x-1/2 bg-primary forced-colors:bg-[Highlight] forced-colors:forced-color-adjust-none", style: { left: `calc(var(--timeline-label-width) + ${playheadX}px)` } }))] }) }), _jsx("p", { "aria-live": "polite", "aria-atomic": "true", "data-timeline-status": "", className: "border-t border-border px-3 py-1 text-[13px] leading-5 text-muted-foreground empty:border-0 empty:p-0", children: status })] }) }));
192
+ return (_jsx(TimelineContext.Provider, { value: value, children: _jsx(ViewContext.Provider, { value: view, children: _jsx(TimeContext.Provider, { value: hasPlayhead ? time : undefined, children: _jsxs("div", { role: "group", ...name, onKeyDownCapture: onKeyDownCapture, style: {
193
+ '--timeline-label-width': `${labelWidth}px`,
194
+ }, className: cn('relative flex flex-col overflow-hidden rounded-lg border border-border bg-background text-sm', className), children: [_jsx("div", { ref: scroller, "data-timeline-scroller": "", style: { maxHeight }, className: "relative overflow-auto overscroll-contain [scroll-padding-block-start:var(--lane-height)] [scroll-padding-inline-start:var(--timeline-label-width)]", children: _jsxs("div", { className: "relative", style: { width: `calc(var(--timeline-label-width) + ${trackWidth}px)` }, children: [children, playheadX !== null && (_jsx("div", { "aria-hidden": "true", "data-timeline-playhead-line": "", className: "pointer-events-none absolute inset-y-0 z-10 w-0.5 -translate-x-1/2 bg-primary forced-colors:bg-[Highlight] forced-colors:forced-color-adjust-none", style: { left: `calc(var(--timeline-label-width) + ${playheadX}px)` } }))] }) }), _jsx("p", { "aria-live": "polite", "aria-atomic": "true", "data-timeline-status": "", className: "border-t border-border px-3 py-1 text-[13px] leading-5 text-muted-foreground empty:border-0 empty:p-0", children: status })] }) }) }) }));
164
195
  }
165
196
  /** The label column's cell at the start of a row: it stays put while the track scrolls under it. */
166
197
  function LabelCell({ className, style, children, }) {
@@ -177,7 +208,8 @@ function LabelCell({ className, style, children, }) {
177
208
  */
178
209
  export function TimeRuler({ corner, className }) {
179
210
  const tl = useTimeline('TimeRuler');
180
- const { start, end, pps, scale, time, view, toX, show } = tl;
211
+ const view = useContext(ViewContext);
212
+ const { start, end, pps, scale, toX, show } = tl;
181
213
  const [dragging, setDragging] = useState(false);
182
214
  const thumb = useRef(null);
183
215
  // A label is about as wide as its widest text at this step: 8.5px a character, and room either side.
@@ -193,7 +225,7 @@ export function TimeRuler({ corner, className }) {
193
225
  tl.picked.put(at, e.altKey);
194
226
  return;
195
227
  }
196
- if (time === undefined)
228
+ if (!tl.hasPlayhead)
197
229
  return;
198
230
  e.preventDefault();
199
231
  e.currentTarget.setPointerCapture(e.pointerId);
@@ -208,16 +240,7 @@ export function TimeRuler({ corner, className }) {
208
240
  tl.seek(place(at, { step: tl.step, origin: start, pxPerSecond: pps, free: e.altKey }).time);
209
241
  };
210
242
  const stop = () => setDragging(false);
211
- const onKeyDown = (e) => {
212
- if (time === undefined)
213
- return;
214
- const next = keyTime(e, time, tl);
215
- if (next === null)
216
- return;
217
- e.preventDefault();
218
- tl.seek(next);
219
- };
220
- return (_jsxs("div", { "data-timeline-ruler": "", className: cn('sticky top-0 z-30 flex h-lane min-h-target bg-background', className), children: [_jsx(LabelCell, { className: "justify-end shadow-[inset_0_-1px_0_var(--border)]", children: _jsx("span", { "aria-hidden": "true", className: "leading-5 font-semibold text-foreground tabular-nums", children: corner ?? (time !== undefined ? show(time) : null) }) }), _jsxs("div", { "data-timeline-ruler-track": "", onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: stop, onPointerCancel: stop, className: cn('relative shrink-0 touch-none shadow-[inset_0_-1px_0_var(--border)] select-none', time !== undefined || tl.picked ? 'cursor-pointer' : 'cursor-default'), style: { width: tl.trackWidth }, children: [marks.map((mark) => (_jsx("span", { "aria-hidden": "true", className: cn('absolute bottom-0 w-px bg-muted-foreground', mark.major ? 'h-2.5' : 'h-1.5'), style: { left: toX(mark.t) } }, mark.t))), marks
243
+ return (_jsxs("div", { "data-timeline-ruler": "", className: cn('sticky top-0 z-30 flex h-lane min-h-target bg-background', className), children: [_jsx(LabelCell, { className: "justify-end shadow-[inset_0_-1px_0_var(--border)]", children: _jsx("span", { "aria-hidden": "true", className: "leading-5 font-semibold text-foreground tabular-nums", children: corner ?? _jsx(PlayheadTime, {}) }) }), _jsxs("div", { "data-timeline-ruler-track": "", onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: stop, onPointerCancel: stop, className: cn('relative shrink-0 touch-none shadow-[inset_0_-1px_0_var(--border)] select-none', tl.hasPlayhead || tl.picked ? 'cursor-pointer' : 'cursor-default'), style: { width: tl.trackWidth }, children: [marks.map((mark) => (_jsx("span", { "aria-hidden": "true", className: cn('absolute bottom-0 w-px bg-muted-foreground', mark.major ? 'h-2.5' : 'h-1.5'), style: { left: toX(mark.t) } }, mark.t))), marks
221
244
  .filter((mark) => mark.major)
222
245
  .map((mark) => {
223
246
  const x = toX(mark.t);
@@ -228,9 +251,30 @@ export function TimeRuler({ corner, className }) {
228
251
  if (last && mark.t - major >= start && x - toX(mark.t - major) < labelPx * 2)
229
252
  return null;
230
253
  return (_jsx("span", { "aria-hidden": "true", className: "absolute top-0 text-sm leading-5 whitespace-nowrap text-muted-foreground tabular-nums", style: last ? { right: tl.trackWidth - x + 4 } : { left: x + 4 }, children: show(mark.t, major) }, mark.t));
231
- }), time !== undefined && (_jsx("div", { ref: thumb, role: "slider", tabIndex: 0, "aria-label": tl.t('playhead'), "aria-orientation": "horizontal", "aria-valuemin": start, "aria-valuemax": end, "aria-valuenow": Math.round(time * 1000) / 1000, "aria-valuetext": tl.speak(time), "data-dragging": dragging || undefined, onKeyDown: onKeyDown,
232
- // Layer 1: one target square, centred on the time. Dragged, so grab.
233
- className: "group/playhead absolute top-0 z-10 flex h-full w-target -translate-x-1/2 cursor-grab justify-center outline-none data-dragging:cursor-grabbing", style: { left: toX(time) }, children: _jsx("span", { "aria-hidden": "true", className: "mt-0.5 h-[calc(100%-4px)] w-2.5 rounded-sm bg-primary group-focus-visible/playhead:focus-ring forced-colors:bg-[Highlight] forced-colors:forced-color-adjust-none" }) }))] })] }));
254
+ }), tl.hasPlayhead && _jsx(Playhead, { thumb: thumb, dragging: dragging })] })] }));
255
+ }
256
+ /** The playhead's time as the ruler shows it, for the corner: one of the few things that follows the time. */
257
+ function PlayheadTime() {
258
+ const tl = useTimeline('TimeRuler');
259
+ const time = useContext(TimeContext);
260
+ return time === undefined ? null : tl.show(time);
261
+ }
262
+ /** The playhead's slider. Its own component, so the ticks and labels don't render again as the time moves. */
263
+ function Playhead({ thumb, dragging, }) {
264
+ const tl = useTimeline('TimeRuler');
265
+ const time = useContext(TimeContext);
266
+ if (time === undefined)
267
+ return null;
268
+ const onKeyDown = (e) => {
269
+ const next = keyTime(e, time, tl);
270
+ if (next === null)
271
+ return;
272
+ e.preventDefault();
273
+ tl.seek(next);
274
+ };
275
+ return (_jsx("div", { ref: thumb, role: "slider", tabIndex: 0, "aria-label": tl.t('playhead'), "aria-orientation": "horizontal", "aria-valuemin": tl.start, "aria-valuemax": tl.end, "aria-valuenow": Math.round(time * 1000) / 1000, "aria-valuetext": tl.speak(time), "data-dragging": dragging || undefined, onKeyDown: onKeyDown,
276
+ // Layer 1: one target square, centred on the time. Dragged, so grab.
277
+ className: "group/playhead absolute top-0 z-10 flex h-full w-target -translate-x-1/2 cursor-grab justify-center outline-none data-dragging:cursor-grabbing", style: { left: tl.toX(time) }, children: _jsx("span", { "aria-hidden": "true", className: "mt-0.5 h-[calc(100%-4px)] w-2.5 rounded-sm bg-primary group-focus-visible/playhead:focus-ring forced-colors:bg-[Highlight] forced-colors:forced-color-adjust-none" }) }));
234
278
  }
235
279
  /** The time a key moves a slider on the timeline to, or null for a key it doesn't use. */
236
280
  function keyTime(e, from, tl) {
@@ -254,11 +298,12 @@ function keyTime(e, from, tl) {
254
298
  */
255
299
  export function TimelineSlot({ label, height = 48, 'aria-label': named, children, className, }) {
256
300
  const tl = useTimeline('TimelineSlot');
301
+ const inView = useContext(ViewContext);
257
302
  const view = {
258
303
  start: tl.start,
259
304
  end: tl.end,
260
- visibleStart: tl.view.start,
261
- visibleEnd: tl.view.end,
305
+ visibleStart: inView.start,
306
+ visibleEnd: inView.end,
262
307
  pxPerSecond: tl.pps,
263
308
  width: tl.trackWidth,
264
309
  toX: tl.toX,
@@ -286,16 +331,26 @@ const itemTimes = (node) => {
286
331
  * chevron to open it. Selected, it takes the `brand-subtle` ground and, in forced colours, a Highlight bar.
287
332
  */
288
333
  export function TimelineLane({ id, label, items, children, className }) {
334
+ return (_jsxs(RACTreeItem, { id: id, textValue: label, className: cn('group/lane relative flex h-lane min-h-target cursor-default outline-none', 'data-hovered:cursor-pointer data-hovered:bg-accent data-selected:bg-brand-subtle data-focus-visible:focus-ring-inset', className), children: [_jsx(TreeItemContent, { children: ({ hasChildItems, level }) => (_jsxs(_Fragment, { children: [_jsxs(LabelCell, { style: { '--lane-indent': level - 1 }, className: cn('gap-0.5 ps-[calc(var(--lane-indent)*12px)] shadow-[inset_0_-1px_0_var(--border)] group-data-hovered/lane:bg-accent group-data-selected/lane:bg-brand-subtle',
335
+ // Forced colours drop the selected ground: a Highlight bar instead, on the cell that stays in view.
336
+ "forced-colors:group-data-selected/lane:before:absolute forced-colors:group-data-selected/lane:before:inset-y-0.5 forced-colors:group-data-selected/lane:before:start-0 forced-colors:group-data-selected/lane:before:w-[3px] forced-colors:group-data-selected/lane:before:bg-[Highlight] forced-colors:group-data-selected/lane:before:forced-color-adjust-none forced-colors:group-data-selected/lane:before:content-['']"), children: [hasChildItems ? (_jsx(RACButton, { slot: "chevron", className: "group/lane-chevron relative flex size-target shrink-0 cursor-pointer items-center justify-center outline-none", children: _jsx("span", { className: "flex size-5 items-center justify-center rounded-sm text-muted-foreground group-data-focus-visible/lane-chevron:focus-ring group-data-hovered/lane-chevron:bg-muted group-data-hovered/lane-chevron:text-foreground", children: _jsx(ChevronRight, { "aria-hidden": "true", className: "size-4 group-data-expanded/lane:rotate-90" }) }) })) : (_jsx("span", { "aria-hidden": "true", className: "w-target shrink-0" })), _jsx("span", { className: "min-w-0 truncate leading-5 font-medium text-foreground group-data-selected/lane:font-semibold", children: label })] }), _jsx(LaneTrack, { items: items })] })) }), children] }));
337
+ }
338
+ /**
339
+ * A lane's track and its items, in time order. A component of its own, and memoised on `items`: React Aria renders a
340
+ * row again as its focus and hover change, and this keeps that from reaching the items, which render again only when
341
+ * the lane's items, the zoom, the selection or a move changes.
342
+ */
343
+ const LaneTrack = memo(function LaneTrack({ items }) {
289
344
  const tl = useTimeline('TimelineLane');
290
345
  const sorted = Children.toArray(items)
291
346
  .filter(isValidElement)
292
347
  .sort((a, b) => itemTimes(a)[0] - itemTimes(b)[0]);
293
- return (_jsxs(RACTreeItem, { id: id, textValue: label, className: cn('group/lane relative flex h-lane min-h-target cursor-default outline-none', 'data-hovered:cursor-pointer data-hovered:bg-accent data-selected:bg-brand-subtle data-focus-visible:focus-ring-inset', className), children: [_jsx(TreeItemContent, { children: ({ hasChildItems, level }) => (_jsxs(_Fragment, { children: [_jsxs(LabelCell, { style: { '--lane-indent': level - 1 }, className: cn('gap-0.5 ps-[calc(var(--lane-indent)*12px)] shadow-[inset_0_-1px_0_var(--border)] group-data-hovered/lane:bg-accent group-data-selected/lane:bg-brand-subtle',
294
- // Forced colours drop the selected ground: a Highlight bar instead, on the cell that stays in view.
295
- "forced-colors:group-data-selected/lane:before:absolute forced-colors:group-data-selected/lane:before:inset-y-0.5 forced-colors:group-data-selected/lane:before:start-0 forced-colors:group-data-selected/lane:before:w-[3px] forced-colors:group-data-selected/lane:before:bg-[Highlight] forced-colors:group-data-selected/lane:before:forced-color-adjust-none forced-colors:group-data-selected/lane:before:content-['']"), children: [hasChildItems ? (_jsx(RACButton, { slot: "chevron", className: "group/lane-chevron relative flex size-target shrink-0 cursor-pointer items-center justify-center outline-none", children: _jsx("span", { className: "flex size-5 items-center justify-center rounded-sm text-muted-foreground group-data-focus-visible/lane-chevron:focus-ring group-data-hovered/lane-chevron:bg-muted group-data-hovered/lane-chevron:text-foreground", children: _jsx(ChevronRight, { "aria-hidden": "true", className: "size-4 group-data-expanded/lane:rotate-90" }) }) })) : (_jsx("span", { "aria-hidden": "true", className: "w-target shrink-0" })), _jsx("span", { className: "min-w-0 truncate leading-5 font-medium text-foreground group-data-selected/lane:font-semibold", children: label })] }), _jsx("div", { className: "relative shrink-0 shadow-[inset_0_-1px_0_var(--border)]", style: { width: tl.trackWidth }, children: sorted.map((item, i) => (_jsx(ItemRoomContext.Provider, { value: {
296
- before: i > 0 ? tl.toX(itemTimes(sorted[i - 1])[1]) : -Infinity,
297
- after: i < sorted.length - 1 ? tl.toX(itemTimes(sorted[i + 1])[0]) : Infinity,
298
- }, children: item }, item.key ?? i))) })] })) }), children] }));
348
+ return (_jsx("div", { className: "relative shrink-0 shadow-[inset_0_-1px_0_var(--border)]", style: { width: tl.trackWidth }, children: sorted.map((item, i) => (_jsx(Neighbours, { before: i > 0 ? tl.toX(itemTimes(sorted[i - 1])[1]) : -Infinity, after: i < sorted.length - 1 ? tl.toX(itemTimes(sorted[i + 1])[0]) : Infinity, children: item }, item.key ?? i))) }));
349
+ });
350
+ /** Where an item's neighbours are, kept as one value while they don't move. */
351
+ function Neighbours({ before, after, children }) {
352
+ const room = useMemo(() => ({ before, after }), [before, after]);
353
+ return _jsx(ItemRoomContext.Provider, { value: room, children: children });
299
354
  }
300
355
  // The badge's pairs, whose text the contrast audit promises against their ground; the edge is the text colour.
301
356
  const tones = {