@kerusiweb/react 2.3.0 → 3.1.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.
@@ -5,7 +5,7 @@
5
5
  * there, not re-exported here: the document types (`KerusiMap`, `KerusiState`,
6
6
  * `KerusiSession`), the conformance validator, the render model
7
7
  * (`buildRenderModel`, `RenderMap`, `RenderSeat`), the geometry
8
- * (`computeSectionLayout`), and the view helpers (`summarizeSelection`,
8
+ * (`computeMapLayout`), and the view helpers (`summarizeSelection`,
9
9
  * `seatAriaLabel`, `DEFAULT_KERUSI_COLORS`). This package supplies only what is
10
10
  * React's: components, hooks, and their props.
11
11
  *
@@ -0,0 +1,36 @@
1
+ import type { RenderSeat, SeatCardAppearance, SeatCardPlacement } from '@kerusiweb/core';
2
+ import type { ReactNode, RefObject } from 'react';
3
+ export interface SeatCardProps {
4
+ kind: 'hover' | 'click';
5
+ /** The card's `id`: a hover card is named by the seat's `aria-describedby`. */
6
+ id: string;
7
+ seat: RenderSeat;
8
+ /** Names a click card's dialog. */
9
+ label: string;
10
+ placement: SeatCardPlacement;
11
+ appearance: SeatCardAppearance;
12
+ className?: string;
13
+ /** The map's root element: the card is positioned in it and kept inside it. */
14
+ rootRef: RefObject<HTMLElement | null>;
15
+ getSeatNode: (seatId: string) => SVGGElement | null;
16
+ /** Moves focus into the card on mount; a click card opened from the keyboard. */
17
+ focusOnOpen?: boolean;
18
+ /** A hover card is hoverable (WCAG 1.4.13): the pointer may enter it. */
19
+ onPointerEnter?: () => void;
20
+ onPointerLeave?: () => void;
21
+ children: ReactNode;
22
+ }
23
+ /**
24
+ * One seat card: a floating element anchored to a seat.
25
+ *
26
+ * It sits inside the map's root, outside the clipped viewport, so it shows in
27
+ * full screen and inherits the `--kerusi-*` properties set on the map. Where it
28
+ * goes is `placeSeatCard()`'s; this component measures the seat, the card and
29
+ * the root, and re-measures after every render and whenever the root or the card
30
+ * changes size, which is how it follows zoom, pan, maximize and full screen.
31
+ *
32
+ * It sets no colour, no padding and no font: that is the stylesheet's, and then
33
+ * the consumer's (D11).
34
+ */
35
+ export declare function SeatCard({ kind, id, seat, label, placement, appearance, className, rootRef, getSeatNode, focusOnOpen, onPointerEnter, onPointerLeave, children, }: SeatCardProps): import("react").JSX.Element;
36
+ //# sourceMappingURL=seat-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seat-card.d.ts","sourceRoot":"","sources":["../src/seat-card.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAiB,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,+EAA+E;IAC/E,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,iBAAiB,CAAC;IAC7B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACvC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,WAAW,GAAG,IAAI,CAAC;IACpD,iFAAiF;IACjF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,QAAQ,EAAE,SAAS,CAAC;CACrB;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,EAAE,EACF,IAAI,EACJ,KAAK,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACT,OAAO,EACP,WAAW,EACX,WAAmB,EACnB,cAAc,EACd,cAAc,EACd,QAAQ,GACT,EAAE,aAAa,+BAsHf"}
@@ -0,0 +1,99 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cssLengthToPx, placeSeatCard, seatCardClassName, seatCardDataAttributes, } from '@kerusiweb/core';
3
+ import { useLayoutEffect, useRef, useState } from 'react';
4
+ const DEFAULT_OFFSET = 8;
5
+ const DEFAULT_ARROW = 6;
6
+ /**
7
+ * One seat card: a floating element anchored to a seat.
8
+ *
9
+ * It sits inside the map's root, outside the clipped viewport, so it shows in
10
+ * full screen and inherits the `--kerusi-*` properties set on the map. Where it
11
+ * goes is `placeSeatCard()`'s; this component measures the seat, the card and
12
+ * the root, and re-measures after every render and whenever the root or the card
13
+ * changes size, which is how it follows zoom, pan, maximize and full screen.
14
+ *
15
+ * It sets no colour, no padding and no font: that is the stylesheet's, and then
16
+ * the consumer's (D11).
17
+ */
18
+ export function SeatCard({ kind, id, seat, label, placement, appearance, className, rootRef, getSeatNode, focusOnOpen = false, onPointerEnter, onPointerLeave, children, }) {
19
+ const cardRef = useRef(null);
20
+ const [position, setPosition] = useState(null);
21
+ /** False when the consumer set `--kerusi-seat-card-arrow-size: 0`. */
22
+ const [arrowShown, setArrowShown] = useState(true);
23
+ const measure = () => {
24
+ const root = rootRef.current;
25
+ const card = cardRef.current;
26
+ const seatNode = getSeatNode(seat.id);
27
+ if (!root || !card || !seatNode) {
28
+ return;
29
+ }
30
+ const rootBox = root.getBoundingClientRect();
31
+ const seatBox = seatNode.getBoundingClientRect();
32
+ // `position: absolute` is measured from the root's padding box.
33
+ const originX = rootBox.left + root.clientLeft;
34
+ const originY = rootBox.top + root.clientTop;
35
+ const styles = getComputedStyle(card);
36
+ const fontSizes = {
37
+ root: parseFloat(getComputedStyle(card.ownerDocument.documentElement).fontSize) || 16,
38
+ element: parseFloat(styles.fontSize) || 16,
39
+ };
40
+ const arrowSize = cssLengthToPx(styles.getPropertyValue('--kerusi-seat-card-arrow-size'), DEFAULT_ARROW, fontSizes);
41
+ setArrowShown(arrowSize > 0);
42
+ const next = placeSeatCard({
43
+ seat: {
44
+ x: seatBox.left - originX,
45
+ y: seatBox.top - originY,
46
+ width: seatBox.width,
47
+ height: seatBox.height,
48
+ },
49
+ card: { width: card.offsetWidth, height: card.offsetHeight },
50
+ container: { x: 0, y: 0, width: root.clientWidth, height: root.clientHeight },
51
+ placement,
52
+ offset: cssLengthToPx(styles.getPropertyValue('--kerusi-seat-card-offset'), DEFAULT_OFFSET, fontSizes),
53
+ arrowInset: Math.max(12, arrowSize * 2),
54
+ });
55
+ setPosition((current) => current &&
56
+ current.side === next.side &&
57
+ current.x === next.x &&
58
+ current.y === next.y &&
59
+ current.arrowOffset === next.arrowOffset
60
+ ? current
61
+ : next);
62
+ };
63
+ // After every render, before paint: the card is in place when it first shows,
64
+ // and a zoom or pan (which re-renders the map) moves it with the seat.
65
+ useLayoutEffect(measure);
66
+ // A change the render did not announce: the root resized (maximize, full
67
+ // screen, a rotated phone), or the card's own content did.
68
+ useLayoutEffect(() => {
69
+ const root = rootRef.current;
70
+ const card = cardRef.current;
71
+ if (!root || !card || typeof ResizeObserver === 'undefined') {
72
+ return;
73
+ }
74
+ const observer = new ResizeObserver(() => measure());
75
+ observer.observe(root);
76
+ observer.observe(card);
77
+ return () => observer.disconnect();
78
+ // `measure` closes over props that are stable for as long as the card is this seat's.
79
+ // eslint-disable-next-line react-hooks/exhaustive-deps
80
+ }, [seat.id, placement]);
81
+ useLayoutEffect(() => {
82
+ if (!focusOnOpen) {
83
+ return;
84
+ }
85
+ const card = cardRef.current;
86
+ if (!card) {
87
+ return;
88
+ }
89
+ const first = card.querySelector('a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])');
90
+ (first ?? card).focus({ preventScroll: true });
91
+ }, [focusOnOpen, seat.id]);
92
+ const style = {
93
+ left: position?.x ?? 0,
94
+ top: position?.y ?? 0,
95
+ '--kerusi-seat-card-arrow-shift': `${position?.arrowOffset ?? 0}px`,
96
+ };
97
+ return (_jsxs("div", { ref: cardRef, id: id, className: seatCardClassName(kind, appearance, className), role: kind === 'hover' ? 'tooltip' : 'dialog', "aria-label": kind === 'click' ? label : undefined, tabIndex: kind === 'click' ? -1 : undefined, "data-placement": position?.side ?? (placement === 'auto' ? 'top' : placement), ...seatCardDataAttributes(seat), style: style, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, children: [_jsx("div", { className: "kerusi-seat-card__body", children: children }), appearance === 'none' || !arrowShown ? null : (_jsx("span", { className: "kerusi-seat-card__arrow", "aria-hidden": "true" }))] }));
98
+ }
99
+ //# sourceMappingURL=seat-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seat-card.js","sourceRoot":"","sources":["../src/seat-card.tsx"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { DisallowedReason, KerusiControlStrings, KerusiMap, KerusiSeatContext, KerusiSeatmapColors, KerusiSession, KerusiState, KerusiViewport, KerusiViolation, RenderSeat, SeatAriaStrings, SeatRenderStatus, SeatStyleFn, SeatTypeStyles, SelectionSummary } from '@kerusiweb/core';
1
+ import type { DisallowedReason, HoverCardDelay, KerusiControlStrings, KerusiMap, KerusiSeatCardContext, KerusiSeatContext, KerusiSeatmapColors, KerusiSession, KerusiState, KerusiViewport, KerusiViolation, RenderSeat, SeatAriaStrings, SeatCardAppearance, SeatCardPlacement, SeatClick, SeatRenderStatus, SeatStyleFn, SeatTypeStyles, SelectionSummary } from '@kerusiweb/core';
2
2
  import type { CSSProperties, ReactNode } from 'react';
3
3
  /** How a document with validation errors is handled. */
4
4
  export type ValidationMode =
@@ -10,11 +10,8 @@ export type ValidationMode =
10
10
  | 'off';
11
11
  /** Per-section rendering overrides, keyed by `Section.id`. */
12
12
  export interface SectionRenderOptions {
13
+ /** Leaves the section out. Its space on the canvas stays empty (D4). */
13
14
  hidden?: boolean;
14
- /** Overrides `Section.aspectRatio`. */
15
- aspectRatio?: string;
16
- /** Overrides the seat size for this section only. */
17
- seatSize?: number;
18
15
  /** Overrides the localized `Section.label`. */
19
16
  label?: string;
20
17
  }
@@ -47,14 +44,29 @@ export interface KerusiSeatmapHandle {
47
44
  readonly summary: SelectionSummary;
48
45
  /** Moves DOM focus to a seat, if it is rendered. */
49
46
  focusSeat(seatId: string): void;
47
+ /**
48
+ * Opens the click card for a seat, for example from a search result. No-op
49
+ * without `renderClickCard`, or for a seat that is not rendered.
50
+ */
51
+ openSeatCard(seatId: string): void;
52
+ /** Closes the click card. */
53
+ closeSeatCard(): void;
54
+ /** The seat whose click card is showing, or `null`. */
55
+ readonly openSeatCardId: string | null;
50
56
  /** The current zoom and pan. Fit (`{ zoom: 1, x: 0, y: 0 }`) unless `zoomable`. */
51
57
  readonly viewport: KerusiViewport;
52
58
  /** Zooms in one step about the centre. No-op unless `zoomable`. */
53
59
  zoomIn(): void;
54
60
  /** Zooms out one step about the centre. No-op unless `zoomable`. */
55
61
  zoomOut(): void;
56
- /** Back to fit-to-container: the map's original view. No-op unless `zoomable`. */
62
+ /** Back to fit-to-container: the whole canvas. No-op unless `zoomable`. */
57
63
  resetZoom(): void;
64
+ /**
65
+ * Zooms to one section: its declared `bounds`, or the box around its seats
66
+ * and elements when it declares none. No-op unless `zoomable`, or for a
67
+ * section that is not rendered.
68
+ */
69
+ zoomToSection(sectionId: string): void;
58
70
  /** Whether the map is currently maximized. */
59
71
  readonly maximized: boolean;
60
72
  /** Maximizes or restores the map. Maximizing needs `maximizable`. */
@@ -97,23 +109,24 @@ export interface KerusiSeatmapProps {
97
109
  /**
98
110
  * Draws the inside of every seat yourself. The library keeps the seat's
99
111
  * `<g>`, with its role, ARIA state, tab stop, rotation and event handlers, and
100
- * renders whatever this returns inside it, in viewBox units. Return
112
+ * renders whatever this returns inside it, in canvas units. Return
101
113
  * `ctx.defaultContent` for the stock seat, or add to it. While this is set the
102
114
  * library also draws a focus outline over your content, so keyboard focus
103
115
  * stays visible whatever you draw.
104
116
  */
105
117
  renderSeat?: (ctx: SeatRenderContext) => ReactNode;
106
- /** Grid cell edge, in viewBox units. */
107
- seatSize?: number;
108
- /** Gap between grid cells, in viewBox units. */
109
- seatGap?: number;
110
- /** Freeform viewBox width; height follows the section's aspect ratio. */
111
- freeformBasis?: number;
112
118
  /**
113
- * CSS pixels per viewBox unit. Caps each section at its natural size so a
114
- * narrow section and a wide one in the same map draw seats the same size.
119
+ * CSS pixels per canvas unit, at most: the map never draws wider than
120
+ * `canvas.width × unitScale`, and scales down to a narrower container. The
121
+ * document fixes every seat's size and position (§4.5); this is the only
122
+ * sizing control. Default `1`.
115
123
  */
116
124
  unitScale?: number;
125
+ /**
126
+ * Draws each section's label inside the map, at the top-left of its `bounds`.
127
+ * Only sections that declare `bounds` get one; every section's label is its
128
+ * group's accessible name either way. Default `true`.
129
+ */
117
130
  showSectionLabels?: boolean;
118
131
  showLegend?: boolean;
119
132
  showLegendPrices?: boolean;
@@ -131,7 +144,11 @@ export interface KerusiSeatmapProps {
131
144
  * Memoize it — an inline arrow rebuilds the whole render model every render.
132
145
  */
133
146
  seatSelectable?: (seat: RenderSeat) => boolean;
134
- /** When false the map renders read-only: no pointer or keyboard interaction. */
147
+ /**
148
+ * `false` turns selection off. Seats still take clicks, and stay
149
+ * keyboard-reachable, while `onSeatClick` or `renderClickCard` is set (D14).
150
+ * With neither set, a read-only map has no pointer or keyboard interaction.
151
+ */
135
152
  interactive?: boolean;
136
153
  /**
137
154
  * Revert a lapsed `holdExpires` to available on a ticker (§5.1). Off by
@@ -159,11 +176,61 @@ export interface KerusiSeatmapProps {
159
176
  * Memoize it — a new object each render rebuilds the controls' strings.
160
177
  */
161
178
  controlStrings?: Partial<KerusiControlStrings>;
179
+ /**
180
+ * Shown while a seat is hovered, anchored to it. Return `null` for no card on
181
+ * this seat. Never shown for touch. With neither card function set, nothing is
182
+ * rendered and the markup is unchanged (D10).
183
+ *
184
+ * A hover card is pointer-only unless `hoverCardOnFocus` is set, so it must not
185
+ * be the only place important information lives.
186
+ */
187
+ renderHoverCard?: (ctx: KerusiSeatCardContext) => ReactNode;
188
+ /**
189
+ * Opened by a click, tap or Enter/Space on a seat, anchored to it. It stays
190
+ * open until dismissed: `Escape`, a press outside, a second click on the same
191
+ * seat, `ctx.close()`, or another seat's click card opening. Return `null` for
192
+ * no card on this seat.
193
+ *
194
+ * A click on a selectable seat still toggles it. To show details without
195
+ * selecting, turn selection off with `interactive={false}`,
196
+ * `selectableStatuses={[]}` or `seatSelectable`.
197
+ */
198
+ renderClickCard?: (ctx: KerusiSeatCardContext) => ReactNode;
199
+ /** The side a card prefers; it flips when it would overflow the map. Default `top`. */
200
+ seatCardPlacement?: SeatCardPlacement;
201
+ /** Extra classes on the card element, for Tailwind or a design-system class (D11). */
202
+ seatCardClassName?: string;
203
+ /**
204
+ * `none` drops the card's background, border, padding, shadow and arrow,
205
+ * leaving only positioning, so your content is the card (D11). Default `default`.
206
+ */
207
+ seatCardAppearance?: SeatCardAppearance;
208
+ /** Milliseconds before a hover card opens and closes. Default `{ open: 150, close: 100 }`. */
209
+ hoverCardDelay?: Partial<HoverCardDelay>;
210
+ /**
211
+ * Also show the hover card when a seat takes keyboard focus (D12). Default
212
+ * `false`. Setting it makes seats keyboard-reachable even on a read-only map.
213
+ */
214
+ hoverCardOnFocus?: boolean;
162
215
  validate?: ValidationMode;
163
216
  onSeatSelect?: (event: SeatInteraction) => void;
164
217
  onSeatDeselect?: (event: SeatInteraction) => void;
165
218
  onSeatDisallowed?: (event: SeatDisallowed) => void;
166
219
  onSeatFocus?: (seat: RenderSeat) => void;
220
+ /**
221
+ * The seat under the pointer when it enters a seat, and `null` when it leaves
222
+ * the seat or the map. Not repeated while the pointer moves within a seat.
223
+ * Pointer devices only (mouse and pen), never during a pan or zoom, and
224
+ * unaffected by `interactive` (D10).
225
+ */
226
+ onSeatHover?: (seat: RenderSeat | null) => void;
227
+ /**
228
+ * Every activation of any seat, whether or not it can be selected: booked,
229
+ * held and blocked seats included. Fires before the selection callbacks, with
230
+ * `selected` as it was before the click. A read-only notification: it cannot
231
+ * cancel or change what the click does (D13).
232
+ */
233
+ onSeatClick?: (event: SeatClick) => void;
167
234
  /** Called whenever the documents change, unless `validate` is `off`. */
168
235
  onValidationIssues?: (issues: readonly KerusiViolation[]) => void;
169
236
  /** The zoom and pan, whenever they change. For a host that persists or shows them. */
@@ -171,7 +238,7 @@ export interface KerusiSeatmapProps {
171
238
  onMaximizedChange?: (maximized: boolean) => void;
172
239
  className?: string;
173
240
  style?: CSSProperties;
174
- /** Rendered inside the map's root element, after the sections and legend. */
241
+ /** Rendered inside the map's root element, after the map and legend. */
175
242
  children?: ReactNode;
176
243
  }
177
244
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { HoverCardDelay, KerusiSeatCardContext, RenderMap, RenderSeat, SeatAriaStrings, SeatCardAppearance, SeatCardPlacement, SeatClickSource } from '@kerusiweb/core';
2
+ import type { ReactNode, RefObject } from 'react';
3
+ export interface UseSeatCardsOptions {
4
+ rootRef: RefObject<HTMLElement | null>;
5
+ renderMap: RenderMap;
6
+ selection: ReadonlySet<string>;
7
+ locale: string;
8
+ ariaStrings: SeatAriaStrings;
9
+ getSeatNode: (seatId: string) => SVGGElement | null;
10
+ focusSeat: (seatId: string) => void;
11
+ onSeatHover?: (seat: RenderSeat | null) => void;
12
+ renderHoverCard?: (ctx: KerusiSeatCardContext) => ReactNode;
13
+ renderClickCard?: (ctx: KerusiSeatCardContext) => ReactNode;
14
+ placement: SeatCardPlacement;
15
+ className?: string;
16
+ appearance: SeatCardAppearance;
17
+ hoverCardDelay?: Partial<HoverCardDelay>;
18
+ hoverCardOnFocus: boolean;
19
+ }
20
+ export interface SeatCards {
21
+ /** Whether seats need pointer listeners at all. */
22
+ tracksPointer: boolean;
23
+ /** Whether seats need focus and blur listeners for a hover card (D12). */
24
+ tracksFocus: boolean;
25
+ /** A click behaviour is configured: `onSeatClick` or a click card (D14). */
26
+ pointer(type: 'enter' | 'leave' | 'move', seatId: string, pointerType: string): void;
27
+ focus(seatId: string): void;
28
+ blur(seatId: string): void;
29
+ /** A pan, pinch or wheel zoom began. */
30
+ gesture(): void;
31
+ /** Opens or closes the click card for an activated seat. */
32
+ activate(seatId: string, source: SeatClickSource): void;
33
+ /** Closes what is open, hover card first. True if a card was showing. */
34
+ dismiss(): boolean;
35
+ openSeatCard(seatId: string): void;
36
+ closeSeatCard(): void;
37
+ /** The seat whose click card is showing. */
38
+ openSeatCardId: string | null;
39
+ /** The seat → card `id` link, for the seat showing a hover card. */
40
+ describedBy: {
41
+ seatId: string;
42
+ id: string;
43
+ } | null;
44
+ /** Both cards, as elements to render inside the map's root. */
45
+ elements: ReactNode;
46
+ }
47
+ /**
48
+ * Seat hover events and the two seat cards (D10).
49
+ *
50
+ * The rules are core's: `reduceSeatHover()` decides what a pointer, a key or a
51
+ * timer means, and `placeSeatCard()` where a card goes. This hook holds the
52
+ * state, runs the one timer the reducer asks for, and renders the cards.
53
+ */
54
+ export declare function useSeatCards(options: UseSeatCardsOptions): SeatCards;
55
+ //# sourceMappingURL=use-seat-cards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-seat-cards.d.ts","sourceRoot":"","sources":["../src/use-seat-cards.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,SAAS,EACT,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EAGhB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACvC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,eAAe,CAAC;IAC7B,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,WAAW,GAAG,IAAI,CAAC;IACpD,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,SAAS,CAAC;IAC5D,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,SAAS,CAAC;IAC5D,SAAS,EAAE,iBAAiB,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACzC,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,mDAAmD;IACnD,aAAa,EAAE,OAAO,CAAC;IACvB,0EAA0E;IAC1E,WAAW,EAAE,OAAO,CAAC;IACrB,4EAA4E;IAC5E,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACrF,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,wCAAwC;IACxC,OAAO,IAAI,IAAI,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IACxD,yEAAyE;IACzE,OAAO,IAAI,OAAO,CAAC;IACnB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,IAAI,IAAI,CAAC;IACtB,4CAA4C;IAC5C,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,oEAAoE;IACpE,WAAW,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACnD,+DAA+D;IAC/D,QAAQ,EAAE,SAAS,CAAC;CACrB;AAUD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,SAAS,CAiSpE"}
@@ -0,0 +1,202 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IDLE_SEAT_HOVER, reduceSeatHover, resolveHoverCardDelay, seatAriaLabel, seatCardId, } from '@kerusiweb/core';
3
+ import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
4
+ import { SeatCard } from './seat-card.js';
5
+ /** `null`, `undefined`, `false`, `true`, `''` and `[]` draw nothing. */
6
+ function isEmptyContent(node) {
7
+ if (node === null || node === undefined || typeof node === 'boolean' || node === '') {
8
+ return true;
9
+ }
10
+ return Array.isArray(node) && node.every(isEmptyContent);
11
+ }
12
+ /**
13
+ * Seat hover events and the two seat cards (D10).
14
+ *
15
+ * The rules are core's: `reduceSeatHover()` decides what a pointer, a key or a
16
+ * timer means, and `placeSeatCard()` where a card goes. This hook holds the
17
+ * state, runs the one timer the reducer asks for, and renders the cards.
18
+ */
19
+ export function useSeatCards(options) {
20
+ const { rootRef, renderMap, selection, locale, ariaStrings, getSeatNode, focusSeat, renderHoverCard, renderClickCard, placement, className, appearance, hoverCardOnFocus, } = options;
21
+ const prefix = useId();
22
+ const delayOpen = options.hoverCardDelay?.open;
23
+ const delayClose = options.hoverCardDelay?.close;
24
+ const delay = useMemo(() => resolveHoverCardDelay({ open: delayOpen, close: delayClose }), [delayOpen, delayClose]);
25
+ // The latest of everything the long-lived callbacks read.
26
+ const live = useRef({ renderMap, delay, onSeatHover: options.onSeatHover });
27
+ live.current = { renderMap, delay, onSeatHover: options.onSeatHover };
28
+ // --- hover ----------------------------------------------------------------
29
+ const [hover, setHover] = useState(IDLE_SEAT_HOVER);
30
+ const hoverRef = useRef(IDLE_SEAT_HOVER);
31
+ const timer = useRef(undefined);
32
+ const feed = useCallback((event) => {
33
+ const result = reduceSeatHover(hoverRef.current, event, live.current.delay);
34
+ hoverRef.current = result.state;
35
+ setHover(result.state);
36
+ if (result.timer) {
37
+ clearTimeout(timer.current);
38
+ timer.current = undefined;
39
+ if (result.timer.action === 'start') {
40
+ const { kind, ms } = result.timer;
41
+ timer.current = setTimeout(() => feed({ type: 'timer', kind }), ms);
42
+ }
43
+ }
44
+ if (result.report) {
45
+ const { seatId } = result.report;
46
+ const seat = seatId === null ? null : (live.current.renderMap.seatsById.get(seatId) ?? null);
47
+ if (seatId === null || seat) {
48
+ live.current.onSeatHover?.(seat);
49
+ }
50
+ }
51
+ }, []);
52
+ useEffect(() => () => clearTimeout(timer.current), []);
53
+ const tracksPointer = !!options.onSeatHover || !!renderHoverCard;
54
+ const tracksFocus = hoverCardOnFocus && !!renderHoverCard;
55
+ const pointer = useCallback((type, seatId, pointerType) => feed({ type, seatId, pointerType }), [feed]);
56
+ const focus = useCallback((seatId) => feed({ type: 'focus', seatId }), [feed]);
57
+ const blur = useCallback((seatId) => feed({ type: 'blur', seatId }), [feed]);
58
+ const gesture = useCallback(() => feed({ type: 'gesture' }), [feed]);
59
+ // --- click ----------------------------------------------------------------
60
+ const [clickId, setClickId] = useState(null);
61
+ const clickRef = useRef(null);
62
+ clickRef.current = clickId;
63
+ /** Set when the card is opened from the keyboard, so focus moves into it. */
64
+ const [clickFromKeyboard, setClickFromKeyboard] = useState(false);
65
+ /**
66
+ * Closes the click card. Focus goes back to the seat only when it was inside
67
+ * the card, so a press elsewhere on the page keeps the focus it just took.
68
+ */
69
+ const closeClick = useCallback((restoreFocus) => {
70
+ const current = clickRef.current;
71
+ if (current !== null && restoreFocus) {
72
+ const card = rootRef.current?.querySelector('.kerusi-seat-card--click');
73
+ if (card?.contains(card.ownerDocument.activeElement)) {
74
+ // After the card is gone, so nothing fights the focus move.
75
+ queueMicrotask(() => focusSeat(current));
76
+ }
77
+ }
78
+ setClickId(null);
79
+ setClickFromKeyboard(false);
80
+ }, [rootRef, focusSeat]);
81
+ const activate = useCallback((seatId, source) => {
82
+ if (!renderClickCard) {
83
+ return;
84
+ }
85
+ if (clickId === seatId) {
86
+ closeClick(true);
87
+ return;
88
+ }
89
+ setClickId(seatId);
90
+ setClickFromKeyboard(source === 'keyboard');
91
+ }, [renderClickCard, clickId, closeClick]);
92
+ const openSeatCard = useCallback((seatId) => {
93
+ if (renderClickCard && live.current.renderMap.seatsById.has(seatId)) {
94
+ setClickId(seatId);
95
+ setClickFromKeyboard(false);
96
+ }
97
+ }, [renderClickCard]);
98
+ const closeSeatCard = useCallback(() => closeClick(true), [closeClick]);
99
+ // --- what is showing ------------------------------------------------------
100
+ const clickSeat = clickId ? renderMap.seatsById.get(clickId) : undefined;
101
+ const hoverSeat = hover.cardId ? renderMap.seatsById.get(hover.cardId) : undefined;
102
+ const contextFor = (seat, trigger, close) => ({ seat, selected: selection.has(seat.id), trigger, close });
103
+ const clickContent = renderClickCard && clickSeat
104
+ ? renderClickCard(contextFor(clickSeat, 'click', () => closeClick(true)))
105
+ : null;
106
+ const clickShowing = clickSeat !== undefined && !isEmptyContent(clickContent);
107
+ // A click card open for a seat hides that seat's hover card.
108
+ const hoverContent = renderHoverCard && hoverSeat && hoverSeat.id !== clickId
109
+ ? renderHoverCard(contextFor(hoverSeat, hover.cardTrigger === 'focus' ? 'focus' : 'hover', () => feed({ type: 'escape' })))
110
+ : null;
111
+ const hoverShowing = hoverSeat !== undefined && !isEmptyContent(hoverContent);
112
+ // A seat that goes away (a hidden section, a new map) takes its cards with it.
113
+ useEffect(() => {
114
+ if (clickId !== null && !renderMap.seatsById.has(clickId)) {
115
+ closeClick(false);
116
+ }
117
+ if (hover.cardId !== null && !renderMap.seatsById.has(hover.cardId)) {
118
+ feed({ type: 'reset' });
119
+ }
120
+ }, [renderMap, clickId, hover.cardId, closeClick, feed]);
121
+ // A card whose render function is taken away has nothing to show.
122
+ useEffect(() => {
123
+ if (!renderClickCard && clickId !== null) {
124
+ closeClick(false);
125
+ }
126
+ }, [renderClickCard, clickId, closeClick]);
127
+ useEffect(() => {
128
+ if (!tracksPointer && hoverRef.current !== IDLE_SEAT_HOVER) {
129
+ feed({ type: 'reset' });
130
+ }
131
+ }, [tracksPointer, feed]);
132
+ const dismiss = useCallback(() => {
133
+ if (clickId !== null) {
134
+ closeClick(true);
135
+ return clickShowing;
136
+ }
137
+ if (hoverRef.current.cardId !== null || hoverRef.current.pendingId !== null) {
138
+ feed({ type: 'escape' });
139
+ return hoverShowing;
140
+ }
141
+ return false;
142
+ }, [clickId, clickShowing, hoverShowing, closeClick, feed]);
143
+ const anyOpen = clickId !== null || hover.cardId !== null;
144
+ // Escape anywhere dismisses a card, including with focus outside the map: a
145
+ // hover card the pointer opened must be dismissible without moving it (WCAG
146
+ // 1.4.13). The map's own key handling runs first and marks the event handled.
147
+ useEffect(() => {
148
+ if (!anyOpen) {
149
+ return;
150
+ }
151
+ const doc = rootRef.current?.ownerDocument ?? document;
152
+ const onKeyDown = (event) => {
153
+ if (event.key === 'Escape' && !event.defaultPrevented && dismiss()) {
154
+ event.preventDefault();
155
+ }
156
+ };
157
+ doc.addEventListener('keydown', onKeyDown);
158
+ return () => doc.removeEventListener('keydown', onKeyDown);
159
+ }, [anyOpen, dismiss, rootRef]);
160
+ // A press outside the click card and outside every seat closes it. A press on
161
+ // a seat is that seat's own click, which opens or closes a card by itself.
162
+ useEffect(() => {
163
+ if (clickId === null) {
164
+ return;
165
+ }
166
+ const doc = rootRef.current?.ownerDocument ?? document;
167
+ const onPointerDown = (event) => {
168
+ const target = event.target;
169
+ const root = rootRef.current;
170
+ if (!target || !root) {
171
+ return;
172
+ }
173
+ const inCard = target.closest?.('.kerusi-seat-card--click');
174
+ const onSeat = root.contains(target) && target.closest?.('[data-seat-id]');
175
+ if (!inCard && !onSeat) {
176
+ closeClick(false);
177
+ }
178
+ };
179
+ doc.addEventListener('pointerdown', onPointerDown, true);
180
+ return () => doc.removeEventListener('pointerdown', onPointerDown, true);
181
+ }, [clickId, closeClick, rootRef]);
182
+ // --- render ---------------------------------------------------------------
183
+ const hoverId = seatCardId(prefix, 'hover');
184
+ const clickCardId = seatCardId(prefix, 'click');
185
+ const elements = (_jsxs(_Fragment, { children: [hoverShowing && hoverSeat && (_jsx(SeatCard, { kind: "hover", id: hoverId, seat: hoverSeat, label: "", placement: placement, appearance: appearance, className: className, rootRef: rootRef, getSeatNode: getSeatNode, onPointerEnter: () => feed({ type: 'card-enter' }), onPointerLeave: () => feed({ type: 'card-leave' }), children: hoverContent }, `hover:${hoverSeat.id}`)), clickShowing && clickSeat && (_jsx(SeatCard, { kind: "click", id: clickCardId, seat: clickSeat, label: seatAriaLabel(clickSeat, locale, ariaStrings), placement: placement, appearance: appearance, className: className, rootRef: rootRef, getSeatNode: getSeatNode, focusOnOpen: clickFromKeyboard, children: clickContent }, `click:${clickSeat.id}`))] }));
186
+ return {
187
+ tracksPointer,
188
+ tracksFocus,
189
+ pointer,
190
+ focus,
191
+ blur,
192
+ gesture,
193
+ activate,
194
+ dismiss,
195
+ openSeatCard,
196
+ closeSeatCard,
197
+ openSeatCardId: clickShowing ? clickId : null,
198
+ describedBy: hoverShowing && hoverSeat ? { seatId: hoverSeat.id, id: hoverId } : null,
199
+ elements,
200
+ };
201
+ }
202
+ //# sourceMappingURL=use-seat-cards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-seat-cards.js","sourceRoot":"","sources":["../src/use-seat-cards.tsx"],"names":[],"mappings":"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"}