mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 18:26:17 +00:00
Two latent defects in the announcement path this branch adds. - lanesId was keyed by render row alone, so a second TimelineLanes on the page (a mini-timeline beside the main one) would mint the same timeline-lanes-track-0 and every caret's aria-controls would resolve to whichever instance mounted first. The prefix now comes from useId, with the colons stripped so the id stays a legal CSS selector. - trackDisplayNumber returned trackOrder.length + 1 for a key it could not find, which is indistinguishable from a real row: the label announced a row the user can see is wrong and nothing upstream could tell it had guessed. It returns null now, and trackDisplaySuffix drops the number from the label rather than inventing one.
39 lines
1.7 KiB
TypeScript
39 lines
1.7 KiB
TypeScript
/**
|
|
* The one owner of "what track number does the user see".
|
|
*
|
|
* `TimelineElement.track` is a z-order SORT key, not a row number: an expanded
|
|
* sub-composition child gets a synthesized fractional key (`host.track + n /
|
|
* (siblings + 2)`, see `useExpandedTimelineElements`), so putting it in a string
|
|
* announces "Hide track 0.16666666666666666". Every user-visible track number,
|
|
* whether it is rendered by a component or baked into an undo-history label,
|
|
* routes through here; the raw key stays in callbacks and lookups only.
|
|
*/
|
|
|
|
/** Ascending distinct track keys, the row order the timeline renders in. */
|
|
export function timelineTrackOrder(elements: readonly { track: number }[]): number[] {
|
|
return [...new Set(elements.map((element) => element.track))].sort((a, b) => a - b);
|
|
}
|
|
|
|
/**
|
|
* A track key's 1-based display row, or null when the key is not in
|
|
* `trackOrder` at all.
|
|
*
|
|
* Both callers build `trackOrder` from the same elements the key came from, so
|
|
* null is unreachable by construction today. It is null rather than a number
|
|
* because the only numbers available to return (the end row, the last row) are
|
|
* indistinguishable from a real answer: a label would announce a row the user
|
|
* can see is wrong, and nothing upstream would ever learn it had guessed.
|
|
*/
|
|
export function trackDisplayNumber(trackOrder: readonly number[], track: number): number | null {
|
|
const row = trackOrder.indexOf(track);
|
|
return row < 0 ? null : row + 1;
|
|
}
|
|
|
|
/**
|
|
* The `" 3"` in `Hide track 3`, empty when there is no display row to name.
|
|
* Announcing "Hide track" is thin; announcing an invented row is wrong.
|
|
*/
|
|
export function trackDisplaySuffix(displayNumber: number | null): string {
|
|
return displayNumber === null ? "" : ` ${displayNumber}`;
|
|
}
|