@kerusiweb/react 2.1.0 → 2.3.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.
package/README.md CHANGED
@@ -88,17 +88,20 @@ usually a mistake.
88
88
 
89
89
  **Appearance**
90
90
 
91
- | Prop | Type | Default | |
92
- | --------------------------------- | --------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
93
- | `colors` | `KerusiSeatmapColors` | theme defaults | Per-status fills, element tones, focus ring, backdrop. See [Theming](#theming). |
94
- | `typeColors` | `boolean` | `true` | Let an available seat take its `SeatType.color` (§4.7). |
95
- | `seatSize` | `number` | `28` | Grid cell edge, in viewBox units. |
96
- | `seatGap` | `number` | `6` | Gap between grid cells. |
97
- | `freeformBasis` | `number` | `1000` | Freeform viewBox width; height follows the aspect ratio. |
98
- | `unitScale` | `number` | `1` | CSS pixels per viewBox unit. Caps each section at its natural size so a narrow section and a wide one draw seats the same size. |
99
- | `showSectionLabels` | `boolean` | `true` | |
100
- | `showLegend` / `showLegendPrices` | `boolean` | `false` / `true` | |
101
- | `className` / `style` | — | — | Applied to the root element, alongside `kerusi-seatmap`. |
91
+ | Prop | Type | Default | |
92
+ | --------------------------------- | --------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
93
+ | `colors` | `KerusiSeatmapColors` | theme defaults | Per-status fills, element tones, focus ring, backdrop. See [Theming](#theming). |
94
+ | `typeColors` | `boolean` | `true` | Let an available seat take its `SeatType.color` (§4.7). |
95
+ | `seatTypeStyles` | `SeatTypeStyles` | — | Styles for every seat of a type, keyed by `SeatType.id`. Also shown in the legend. See [From code](#from-code). |
96
+ | `seatStyle` | `SeatStyleFn` | — | A style for one seat, over its type's. Never recolours a selected or blocked seat. See [From code](#from-code). |
97
+ | `renderSeat` | `(ctx: SeatRenderContext) => ReactNode` | — | Draws the inside of every seat yourself. See [Custom seat content](#custom-seat-content). |
98
+ | `seatSize` | `number` | `28` | Grid cell edge, in viewBox units. |
99
+ | `seatGap` | `number` | `6` | Gap between grid cells. |
100
+ | `freeformBasis` | `number` | `1000` | Freeform viewBox width; height follows the aspect ratio. |
101
+ | `unitScale` | `number` | `1` | CSS pixels per viewBox unit. Caps each section at its natural size so a narrow section and a wide one draw seats the same size. |
102
+ | `showSectionLabels` | `boolean` | `true` | |
103
+ | `showLegend` / `showLegendPrices` | `boolean` | `false` / `true` | |
104
+ | `className` / `style` | — | — | Applied to the root element, alongside `kerusi-seatmap`. |
102
105
 
103
106
  **Sections**
104
107
 
@@ -121,6 +124,16 @@ usually a mistake.
121
124
  `validate="throw"` throws a `KerusiValidationError` **during render**, so an
122
125
  error boundary catches it. `collect` never throws.
123
126
 
127
+ **Zoom, pan and maximize** (both off by default; see [Zoom, pan and maximize](#zoom-pan-and-maximize))
128
+
129
+ | Prop | Type | Default | |
130
+ | ------------------ | ------------------------------- | ------- | -------------------------------------------------------------------------------------- |
131
+ | `zoomable` | `boolean` | `false` | Pinch, Ctrl/Cmd + wheel and drag to zoom and pan; `+` `-` `0` keys; on-screen buttons. |
132
+ | `maxZoom` | `number` | `4` | The zoom ceiling, relative to fit. The floor is always fit. |
133
+ | `showZoomControls` | `boolean` | `true` | The built-in zoom buttons. Turn off to supply your own. |
134
+ | `maximizable` | `boolean` | `false` | A button that fills the screen with the map. |
135
+ | `controlStrings` | `Partial<KerusiControlStrings>` | English | The names of the zoom and maximize buttons, for translation. |
136
+
124
137
  ### Callbacks
125
138
 
126
139
  | Prop | Payload | |
@@ -130,6 +143,8 @@ error boundary catches it. `collect` never throws.
130
143
  | `onSeatDisallowed` | `SeatDisallowed` | `reason` is `booked`, `held`, `blocked`, `not-selectable`, `max-selection` or `companion-unavailable`. |
131
144
  | `onSeatFocus` | `RenderSeat` | |
132
145
  | `onValidationIssues` | `readonly KerusiViolation[]` | Called whenever the documents change. |
146
+ | `onViewportChange` | `KerusiViewport` | `{ zoom, x, y }`, whenever the zoom or pan changes. Only with `zoomable`. |
147
+ | `onMaximizedChange` | `boolean` | When the map is maximized or restored. Only with `maximizable`. |
133
148
 
134
149
  ### The `ref`
135
150
 
@@ -137,6 +152,8 @@ error boundary catches it. `collect` never throws.
137
152
  const map = useRef<KerusiSeatmapHandle>(null);
138
153
  // map.current.summary -> { seats, total, unpriced }
139
154
  // map.current.focusSeat('A12')
155
+ // map.current.viewport -> { zoom, x, y }
156
+ // map.current.zoomIn() / zoomOut() / resetZoom() / toggleMaximized()
140
157
  ```
141
158
 
142
159
  ### Memoizing props
@@ -207,6 +224,290 @@ Every key of `KerusiSeatmapColors` has a property, kebab-cased:
207
224
  | `focusRing` | `--kerusi-focus-ring` |
208
225
  | `backdrop` | `--kerusi-backdrop` |
209
226
 
227
+ A `SeatType.color` from the document has **no theme token**, because it is the
228
+ map's own value under §4.7. It can be overridden only seat by seat (or type by
229
+ type) with `--kerusi-seat-fill`; see
230
+ [Styling individual seats](#styling-individual-seats). Turn it off wholesale
231
+ with `typeColors={false}` if you want the theme to own every fill.
232
+
233
+ For anything the palette does not cover, each seat group carries the same class
234
+ hooks as the Angular binding (`.kerusi-seat`, `--available` / `--held` /
235
+ `--booked` / `--blocked`, `--selected`, `--unselectable`, `--wheelchair`,
236
+ `--companion`), and inside a seat: `.kerusi-seat__box`, `__wash`, `__core`,
237
+ `__occupant` (`__occupant--selected` / `--held` / `--booked`), `__label`,
238
+ `__wheelchair`, and, only while `renderSeat` is set, `__focus`.
239
+
240
+ ### Styling individual seats
241
+
242
+ The palette themes every seat of a status at once. To pick out _some_ seats (a
243
+ VIP block, every aisle seat, one row), select them in CSS and set the per-seat
244
+ tokens. Each seat's `<g>` carries what the document says about it:
245
+
246
+ | Attribute | Value | Example selector |
247
+ | ---------------------- | ------------------------------------------------------ | --------------------------------- |
248
+ | `data-seat-id` | `Seat.id` | `[data-seat-id="12A"]` |
249
+ | `data-seat-type` | `Seat.type` | `[data-seat-type="recliner"]` |
250
+ | `data-seat-row` | `Seat.row`, when the seat has one | `[data-seat-row="A"]` |
251
+ | `data-seat-status` | `available`, `held`, `booked` or `blocked` | `[data-seat-status="held"]` |
252
+ | `data-seat-attributes` | `Seat.attributes`, space-separated, when there are any | `[data-seat-attributes~="aisle"]` |
253
+ | `data-section-id` | The seat's section | `[data-section-id="balcony"]` |
254
+
255
+ Two tokens then recolour the seats a selector picks out:
256
+
257
+ | Token | Replaces |
258
+ | --------------------- | -------------------------------------------------------------- |
259
+ | `--kerusi-seat-fill` | The seat's own colour: its `SeatType.color`, or `availableBg`. |
260
+ | `--kerusi-seat-label` | The colour of the number drawn on it. |
261
+
262
+ ```css
263
+ .kerusi-seatmap :is(.kerusi-seat, .kerusi-legend__item)[data-seat-type='vip'] {
264
+ --kerusi-seat-fill: #d4a017;
265
+ --kerusi-seat-label: #000000;
266
+ }
267
+
268
+ .kerusi-seatmap .kerusi-seat[data-seat-attributes~='aisle'] {
269
+ --kerusi-seat-fill: #2f6b45;
270
+ --kerusi-seat-label: #ffffff;
271
+ }
272
+ ```
273
+
274
+ - **Per seat, not global.** The library never sets these tokens and gives them
275
+ no map-wide default. They are meant for a selector that picks seats out;
276
+ setting one on the map itself would repaint every seat and hide the
277
+ document's type colours, which is what `typeColors={false}` and `availableBg` are for.
278
+ - **Status still shows.** They replace only the seat's own colour. A held or
279
+ booked seat keeps it under its wash and occupant figure, while a selected seat
280
+ keeps its selected frame and core, and a blocked seat its grey, whatever the
281
+ tokens say. Status is never carried by colour alone.
282
+ - **Set the label with the fill.** The library cannot read a colour set in CSS,
283
+ so it cannot choose a readable number colour for it.
284
+ - **Keep the legend in step.** Each type in the legend carries the same
285
+ `data-seat-type`, and its swatch reads `--kerusi-seat-fill`. Include
286
+ `.kerusi-legend__item` in a type selector, as above, and the key matches the
287
+ map.
288
+
289
+ #### From code
290
+
291
+ When the choice lives in TypeScript (a recommendation, a search result, the
292
+ document's own `Seat.metadata`), use `seatTypeStyles` for whole types and
293
+ `seatStyle` for single seats. Both take a `KerusiSeatStyle`:
294
+
295
+ | Field | Type | |
296
+ | ------------ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------ |
297
+ | `fill` | `string` | The seat's own colour, the same slot as `--kerusi-seat-fill`. Any CSS colour. |
298
+ | `labelColor` | `string` | The number's colour. Defaults to black or white for a hex `fill`; set it for any other kind of colour. |
299
+ | `className` | `string \| readonly string[]` | Extra classes on the seat's `<g>`, for CSS that needs more than colour. |
300
+ | `shape` | `KerusiSeatShape` | The seat's outline: `'seat'` (default), `'square'`, `'rounded'`, `'circle'`, or a function. See [Shapes](#shapes). |
301
+
302
+ ```tsx
303
+ import type { SeatStyleFn, SeatTypeStyles } from '@kerusiweb/core';
304
+
305
+ const typeStyles: SeatTypeStyles = { vip: { fill: '#d4a017', labelColor: '#000000' } };
306
+ const highlight: SeatStyleFn = (seat) =>
307
+ seat.source.metadata?.['bestView'] ? { fill: '#2f6b45', className: 'best-view' } : undefined;
308
+
309
+ <KerusiSeatmap map={map} seatTypeStyles={typeStyles} seatStyle={highlight} />;
310
+ ```
311
+
312
+ A seat's colour resolves in this order, first match wins:
313
+
314
+ | # | Source | |
315
+ | --- | ----------------------------------------- | ------------------------------------------------------ |
316
+ | 1 | Selected | `selectedBg` frame and `selectedFg` core, always. |
317
+ | 2 | Blocked | `blockedBg`, always. |
318
+ | 3 | `--kerusi-seat-fill` from your stylesheet | See above. |
319
+ | 4 | `seatStyle(seat)` | Its `fill`. |
320
+ | 5 | `seatTypeStyles[seat.type]` | Its `fill`. Applies whether or not `typeColors` is on. |
321
+ | 6 | `SeatType.color` | When `typeColors` is on. |
322
+ | 7 | `availableBg` | The theme. |
323
+
324
+ - **Status always reads.** Neither option can change a selected or blocked
325
+ seat's colour, and a held or booked seat keeps its wash and occupant figure
326
+ over whatever colour it has. A style that could recolour your own picks
327
+ would make them ambiguous. For anything beyond this, use a
328
+ [custom seat template](#custom-seat-content).
329
+ - **Per-seat over per-type, field by field.** A `seatStyle` result replaces only
330
+ the fields it sets, so a type's `fill` survives a per-seat `className`.
331
+ Classes from both are kept.
332
+ - **The legend shows `seatTypeStyles`**, because a type has one value to show.
333
+ A per-seat `seatStyle` has no single value a legend could draw.
334
+ - The function runs for every seat on every render of the map, so keep it
335
+ cheap. A new function or object each render is fine, since neither rebuilds the
336
+ render model, but declaring them once outside the component is simplest.
337
+
338
+ #### Shapes
339
+
340
+ A style's `shape` changes the seat's outline. It works in `seatTypeStyles` (a
341
+ sofa type drawn rounded, say) and in `seatStyle`; for every seat at once, use
342
+ `seatStyle={() => ({ shape: 'circle' })}`.
343
+
344
+ | `shape` | |
345
+ | -------------------------- | --------------------------------------------------------------------------- |
346
+ | `'seat'` | The default: square-ish at the front, tapered at the back. |
347
+ | `'square'` | A square with the same slight corners as the seat's front. |
348
+ | `'rounded'` | A square with soft corners. |
349
+ | `'circle'` | A circle filling the seat's box. |
350
+ | `(box: SeatBox) => string` | Your own closed path `d`, drawn inside `box` (`x`, `y`, `width`, `height`). |
351
+
352
+ - **Status marks follow the shape.** The wash, the selected frame and core, and
353
+ a seat template's focus outline are all drawn in it, and the occupant figure
354
+ and wheelchair marker sit inside every preset.
355
+ - **Only `'seat'` shows which way a seat faces.** The other presets are
356
+ symmetric, so on rotated seats (a fanned theatre, a stadium bowl) that cue is
357
+ lost.
358
+ - **A function shape must draw relative to the box it is given.** It is called
359
+ once for the seat and again for the selected core's smaller box. Leave room
360
+ for the occupant figure (the middle 44% of the width, from 15% to 86% of the
361
+ height) and keep the top-right corner filled for the wheelchair marker.
362
+ - **The legend draws a shaped type in its shape.** Types without a `shape`, and
363
+ every status swatch, keep their usual swatches.
364
+
365
+ ### Custom seat content
366
+
367
+ When the palette and the class hooks are not enough (an icon, a badge, a price
368
+ tag, a different shape), draw the inside of each seat yourself with
369
+ `renderSeat`. It returns SVG, in the section's viewBox units:
370
+
371
+ ```tsx
372
+ import { KerusiSeatmap } from '@kerusiweb/react';
373
+ import type { SeatRenderContext } from '@kerusiweb/react';
374
+
375
+ function drawSeat({ seat, glyph, defaultContent }: SeatRenderContext) {
376
+ return (
377
+ <>
378
+ {/* The stock seat, then a badge on top of it. */}
379
+ {defaultContent}
380
+ {seat.source.metadata?.['bestView'] ? (
381
+ <circle cx={glyph.box.x + glyph.box.width} cy={glyph.box.y} r={4} fill="gold" />
382
+ ) : null}
383
+ </>
384
+ );
385
+ }
386
+
387
+ <KerusiSeatmap map={map} state={state} renderSeat={drawSeat} />;
388
+ ```
389
+
390
+ `renderSeat` receives a `SeatRenderContext`:
391
+
392
+ | Field | Type | |
393
+ | ---------------- | ------------ | -------------------------------------------------------------------------------------------------- |
394
+ | `seat` | `RenderSeat` | Status, type, price, accessibility, and the document's own `source.metadata`. |
395
+ | `selected` | `boolean` | Whether the seat is in the current selection. |
396
+ | `placed` | `PlacedSeat` | The seat's box, centre, font size and rotation, in viewBox units. |
397
+ | `glyph` | `SeatGlyph` | The stock seat, resolved by `resolveSeatGlyph()` in core: every path, paint and position it draws. |
398
+ | `defaultContent` | `ReactNode` | The stock drawing, as a fragment. Return it to keep the stock seat, or place it beside your marks. |
399
+
400
+ It runs for every seat on every render of the map. A new function each render
401
+ is fine, since it does not rebuild the render model, but declaring it once
402
+ outside the component is simplest.
403
+
404
+ **What the library keeps.** Each seat's `<g>` stays the library's: its role,
405
+ `aria-label`, `aria-pressed`, `aria-disabled`, tab stop, `data-seat-id`, class
406
+ list, rotation and its click, focus and key handlers. Only what is drawn inside
407
+ it is yours. Keyboard navigation, selection, companions and announcements
408
+ therefore behave exactly as they do for the stock seat, and the accessible name
409
+ still comes from the library (and `ariaStrings`), whatever text you draw.
410
+
411
+ **Coordinates.** Draw in the section's viewBox units, using `glyph.box` (or
412
+ `placed`) for the seat's position and size. The `<g>` already carries the seat's
413
+ rotation, so draw it unrotated with the front at the top edge;
414
+ `glyph.label.transform` counter-rotates text so it stays upright.
415
+
416
+ **Status is yours to show.** A template replaces the stock marks, including the
417
+ occupant figure, the wash and the selected frame and core, which are what tell
418
+ held, booked and selected apart by shape rather than colour (WCAG 1.4.1). The
419
+ library's own styling options never alter those marks, so a template is the one
420
+ place that can, and it carries that responsibility. The simplest way to keep
421
+ them is to render `defaultContent` and add to it. Otherwise reuse `glyph.wash`,
422
+ `glyph.core` and `glyph.occupant`, and the `kerusi-seat__wash` and
423
+ `kerusi-seat__occupant--*` classes, which keep the stock opacity.
424
+
425
+ **Focus outline.** The stock focus ring strokes `.kerusi-seat__box`, which your
426
+ content may not have. So while a seat template is in use, the library draws one
427
+ more path in every seat, after your content: `.kerusi-seat__focus`, an outline
428
+ of the seat's body shown only on `:focus-visible`, so keyboard focus stays
429
+ visible whatever you draw (WCAG 2.4.7). It takes the same colour as the stock
430
+ ring (`--kerusi-focus-ring`, then `colors.focusRing`, then `currentColor`). It
431
+ follows the seat's outline (its [`shape`](#shapes), if a style gives one), not
432
+ your drawing; if you draw your own focus indicator, restyle or hide it with
433
+ `.kerusi-seat:focus-visible .kerusi-seat__focus`. Without a seat template it is
434
+ not rendered at all, and the markup is unchanged.
435
+
436
+ **Legend.** The legend keeps drawing the stock glyph. If your seats look very
437
+ different, turn it off and show your own key.
438
+
439
+ ### Zoom, pan and maximize
440
+
441
+ Two features, both **off by default**: with them off the markup and behaviour are
442
+ exactly what they were. They are independent; turn on either or both.
443
+
444
+ On a phone a map of several hundred seats is drawn at fit-to-width, so a seat is
445
+ too small to tap. `zoomable` lets the reader zoom in and pan; `maximizable` adds a button
446
+ that fills the screen.
447
+
448
+ **Zoom and pan.**
449
+
450
+ - **Pinch** with two fingers on a touch screen. **Ctrl/Cmd + wheel**, or a
451
+ trackpad pinch (Safari's included), on desktop. A plain wheel is left alone, so
452
+ the page still scrolls.
453
+ - **Drag** with one finger or the primary mouse button to pan.
454
+ - **A tap still selects**, at any zoom level. A touch or click that moves less
455
+ than 8 CSS pixels is a tap, and reaches the seat exactly as it does without
456
+ `zoomable`. Anything that moves further is a drag, and a drag never selects the
457
+ seat under it.
458
+ - **Limits.** The floor is fit-to-container, the ceiling is `maxZoom` (default
459
+ `4`), and panning stays inside the map. A map smaller than its container, which
460
+ happens when it is maximized on a large screen, is centred.
461
+ - **Gestures and the page.** `touch-action` is `pan-y` at fit, so a one-finger
462
+ vertical swipe still scrolls the page while a pinch is the map's; once zoomed in
463
+ or maximized it is `none`. With `zoomable` off, no `touch-action` is set.
464
+ - **Reduced motion.** The short transition on the zoom buttons, the keys and
465
+ reset is dropped under `prefers-reduced-motion: reduce`. A finger or wheel moves
466
+ the map directly and never eases.
467
+
468
+ | Key | |
469
+ | --------------- | ------------------------------------------------------------ |
470
+ | `+` / `=`, `-` | Zoom in / out, from anywhere inside the map |
471
+ | `0` | Reset to fit |
472
+ | `←` `→` `↑` `↓` | Pan, when the zoomable viewport itself has focus (Tab to it) |
473
+
474
+ On a seat, the arrow keys keep their usual job of moving seat focus, and a seat
475
+ that takes keyboard focus is scrolled into view. Ctrl, Cmd and Alt combinations
476
+ are left to the browser, and keys typed into a field you put inside the map are
477
+ ignored.
478
+
479
+ **Controls.** The zoom buttons (zoom in, zoom out, reset to fit) are real
480
+ `<button>`s with accessible names. At a limit they set `aria-disabled` rather than
481
+ `disabled`, so keyboard focus is not thrown away mid-press. Their names come from
482
+ `controlStrings`, for translation. They use the theme's existing tokens
483
+ (`--kerusi-element-bg`, `--kerusi-element-fg`, `--kerusi-element-muted-fg`,
484
+ `--kerusi-focus-ring`), so there is nothing new to theme.
485
+
486
+ To put the controls somewhere else, turn the built-in ones off
487
+ (`showZoomControls={false}`) and drive the map yourself:
488
+
489
+ ```tsx
490
+ const map = useRef<KerusiSeatmapHandle>(null);
491
+ // map.current.zoomIn(); map.current.zoomOut(); map.current.resetZoom(); map.current.toggleMaximized();
492
+ // map.current.viewport -> { zoom, x, y }
493
+ // map.current.maximized -> boolean
494
+ ```
495
+
496
+ `onViewportChange` reports `{ zoom, x, y }` whenever the view changes, for a host that wants
497
+ to display or persist it. (Restoring a saved view is not supported.)
498
+
499
+ **Maximize.** The button fills the screen with the map and its legend, freezes the
500
+ page behind it, and swaps to an "Exit full screen" button. The layout is a fixed
501
+ overlay, which is all iPhone Safari offers; where the browser has the Fullscreen
502
+ API it is requested on top, and leaving it with the browser's own Esc leaves the
503
+ map's maximized state too. `Escape` from the map also leaves, except that on a
504
+ seat with a non-empty selection the first `Escape` still clears the selection, as
505
+ it always has. The backdrop is `--kerusi-backdrop`, or the page's own canvas colour
506
+ while that is transparent; `--kerusi-maximized-z-index` (default `1000`) sets the
507
+ stacking. It is not a modal dialog: focus is not trapped, and an ancestor with a
508
+ `transform` or `filter` would anchor the fixed layout to itself instead of the
509
+ screen.
510
+
210
511
  ### Keyboard
211
512
 
212
513
  Tab moves between sections; each section keeps its own tab stop. Within a
@@ -227,6 +528,8 @@ Each seat is a `role="button"` announcing its position, type, price, status,
227
528
  every `Seat.accessibility` property and its attributes. A polite live region
228
529
  reports the running selection and any disallowed reason.
229
530
 
531
+ With `zoomable` on there are a few more keys: see [Zoom, pan and maximize](#zoom-pan-and-maximize).
532
+
230
533
  ---
231
534
 
232
535
  ## `<KerusiLegend>`
@@ -1,4 +1,4 @@
1
- import type { KerusiSeatmapColors, RenderLegendEntry } from '@kerusiweb/core';
1
+ import type { KerusiSeatmapColors, RenderLegendEntry, SeatTypeStyles } from '@kerusiweb/core';
2
2
  export interface KerusiLegendProps {
3
3
  /** From `RenderMap.legend`. */
4
4
  legend: readonly RenderLegendEntry[];
@@ -6,6 +6,8 @@ export interface KerusiLegendProps {
6
6
  colors?: Required<KerusiSeatmapColors>;
7
7
  /** Whether an available seat takes its type color — mirrors the seatmap prop. */
8
8
  typeColors?: boolean;
9
+ /** Mirrors the seatmap prop: a type's style is what its swatch shows. */
10
+ seatTypeStyles?: SeatTypeStyles;
9
11
  showPrices?: boolean;
10
12
  /** Hide types no seat in the rendered map actually uses. */
11
13
  hideUnusedTypes?: boolean;
@@ -25,5 +27,5 @@ export interface KerusiLegendProps {
25
27
  * It is opt-in: `<KerusiSeatmap showLegend />` renders it inline, or use
26
28
  * `<KerusiLegend>` directly to place it anywhere.
27
29
  */
28
- export declare function KerusiLegend({ legend, locale, colors, typeColors, showPrices, hideUnusedTypes, headingSeatTypes, headingAvailability, }: KerusiLegendProps): import("react").JSX.Element;
30
+ export declare function KerusiLegend({ legend, locale, colors, typeColors, seatTypeStyles, showPrices, hideUnusedTypes, headingSeatTypes, headingAvailability, }: KerusiLegendProps): import("react").JSX.Element;
29
31
  //# sourceMappingURL=kerusi-legend.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kerusi-legend.d.ts","sourceRoot":"","sources":["../src/kerusi-legend.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAuB,MAAM,iBAAiB,CAAC;AAcnG,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACvC,iFAAiF;IACjF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4DAA4D;IAC5D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,MAAa,EACb,MAA8B,EAC9B,UAAiB,EACjB,UAAiB,EACjB,eAAsB,EACtB,gBAA+B,EAC/B,mBAAoC,GACrC,EAAE,iBAAiB,+BAsFnB"}
1
+ {"version":3,"file":"kerusi-legend.d.ts","sourceRoot":"","sources":["../src/kerusi-legend.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EAEjB,cAAc,EACf,MAAM,iBAAiB,CAAC;AAczB,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACvC,iFAAiF;IACjF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4DAA4D;IAC5D,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAuBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,MAAa,EACb,MAA8B,EAC9B,UAAiB,EACjB,cAAc,EACd,UAAiB,EACjB,eAAsB,EACtB,gBAA+B,EAC/B,mBAAoC,GACrC,EAAE,iBAAiB,+BAmGnB"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cssVar, DEFAULT_KERUSI_COLORS, formatMoney, occupantFillFor, occupantStrokeFor, readableOn, seatBodyPath, seatCoreFill, seatOccupantPath, seatOccupantStroke, seatSelectedFrame, seatWashFill, } from '@kerusiweb/core';
2
+ import { cssVar, DEFAULT_KERUSI_COLORS, formatMoney, legendSwatchFill, legendSwatchPath, legendSwatchText, occupantFillFor, occupantStrokeFor, seatBodyPath, seatCoreFill, seatOccupantPath, seatOccupantStroke, seatSelectedFrame, seatWashFill, } from '@kerusiweb/core';
3
3
  /** The swatch's viewBox edge; the seat glyph is drawn to fill it. */
4
4
  const GLYPH_SIZE = 16;
5
5
  const GLYPH_BODY = seatBodyPath(0, 0, GLYPH_SIZE, GLYPH_SIZE);
@@ -25,20 +25,21 @@ const GLYPH_CORE_OCCUPANT_STROKE = seatOccupantStroke(GLYPH_CORE_SIZE, GLYPH_COR
25
25
  * It is opt-in: `<KerusiSeatmap showLegend />` renders it inline, or use
26
26
  * `<KerusiLegend>` directly to place it anywhere.
27
27
  */
28
- export function KerusiLegend({ legend, locale = 'en', colors = DEFAULT_KERUSI_COLORS, typeColors = true, showPrices = true, hideUnusedTypes = true, headingSeatTypes = 'Seat types', headingAvailability = 'Availability', }) {
28
+ export function KerusiLegend({ legend, locale = 'en', colors = DEFAULT_KERUSI_COLORS, typeColors = true, seatTypeStyles, showPrices = true, hideUnusedTypes = true, headingSeatTypes = 'Seat types', headingAvailability = 'Availability', }) {
29
29
  const types = legend.filter((entry) => !hideUnusedTypes || entry.seatCount > 0);
30
30
  const statuses = statusEntries(colors);
31
31
  return (_jsxs("div", { className: "kerusi-legend", children: [types.length > 0 && (_jsxs("div", { className: "kerusi-legend__block", children: [_jsx("h4", { className: "kerusi-legend__heading", children: headingSeatTypes }), _jsx("ul", { className: "kerusi-legend__list", children: types.map((entry) => {
32
- const typeColor = (typeColors && entry.color) || null;
33
32
  const price = entry.price ? formatMoney(entry.price, locale) : '';
34
- return (_jsxs("li", { className: "kerusi-legend__item", children: [_jsx("span", { className: "kerusi-legend__swatch", "aria-hidden": "true", style: {
35
- background: typeColor ?? cssVar('availableBg', colors.availableBg),
36
- // Mirrors `seatTextFill`: only a document-supplied color
37
- // needs guessing at.
38
- color: typeColor
39
- ? readableOn(typeColor)
40
- : cssVar('availableFg', colors.availableFg),
41
- } }), _jsx("span", { className: "kerusi-legend__label", children: entry.label }), showPrices && price && _jsx("span", { className: "kerusi-legend__price", children: price })] }, entry.id));
33
+ const typeStyle = seatTypeStyles?.[entry.id];
34
+ const shapePath = legendSwatchPath(typeStyle, GLYPH_SIZE);
35
+ const swatchFill = legendSwatchFill(entry, colors, typeColors, typeStyle);
36
+ return (_jsxs("li", { className: "kerusi-legend__item", "data-seat-type": entry.id, children: [shapePath ? (_jsx("svg", { className: "kerusi-legend__swatch kerusi-legend__swatch--glyph", "aria-hidden": "true", focusable: "false", viewBox: `0 0 ${GLYPH_SIZE} ${GLYPH_SIZE}`, children: _jsx("path", { d: shapePath, style: { fill: swatchFill } }) })) : (_jsx("span", { className: "kerusi-legend__swatch", "aria-hidden": "true", style: {
37
+ // Same token and fallback as an available seat of the
38
+ // type, so a rule that sets `--kerusi-seat-fill` on the
39
+ // seats and the legend items keeps them in step.
40
+ background: swatchFill,
41
+ color: legendSwatchText(entry, colors, typeColors, typeStyle),
42
+ } })), _jsx("span", { className: "kerusi-legend__label", children: entry.label }), showPrices && price && _jsx("span", { className: "kerusi-legend__price", children: price })] }, entry.id));
42
43
  }) })] })), _jsxs("div", { className: "kerusi-legend__block", children: [_jsx("h4", { className: "kerusi-legend__heading", children: headingAvailability }), _jsx("ul", { className: "kerusi-legend__list", children: statuses.map((status) => (_jsxs("li", { className: "kerusi-legend__item", children: [_jsxs("svg", { className: "kerusi-legend__swatch kerusi-legend__swatch--glyph", "aria-hidden": "true", focusable: "false", viewBox: `0 0 ${GLYPH_SIZE} ${GLYPH_SIZE}`, children: [_jsx("path", { d: GLYPH_BODY, style: { fill: status.fill } }), hasWash(status.kind) && (_jsx("path", { d: GLYPH_BODY, style: { fill: seatWashFill(status.kind, colors) }, opacity: "0.5" })), status.kind === 'selected' && (_jsx("path", { d: GLYPH_CORE, style: { fill: seatCoreFill(colors) } })), hasOccupant(status.kind) && (_jsx("path", { d: status.kind === 'selected' ? GLYPH_CORE_OCCUPANT : GLYPH_OCCUPANT, className: `kerusi-legend__occupant kerusi-legend__occupant--${status.kind}`, strokeWidth: status.kind === 'selected'
43
44
  ? GLYPH_CORE_OCCUPANT_STROKE
44
45
  : GLYPH_OCCUPANT_STROKE, style: {
@@ -1 +1 @@
1
- {"version":3,"file":"kerusi-legend.js","sourceRoot":"","sources":["../src/kerusi-legend.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kerusi-legend.js","sourceRoot":"","sources":["../src/kerusi-legend.tsx"],"names":[],"mappings":"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"}
@@ -15,6 +15,11 @@ import type { KerusiSeatmapHandle, KerusiSeatmapProps } from './types.js';
15
15
  *
16
16
  * Import the stylesheet once, anywhere in the app:
17
17
  * `import '@kerusiweb/react/styles.css'`.
18
+ *
19
+ * Two opt-in features sit on top, both off by default so an existing map is
20
+ * unchanged: `zoomable` (pinch, wheel and drag, keys `+` `-` `0`, buttons) and
21
+ * `maximizable` (a full-screen button). Their arithmetic is in
22
+ * `@kerusiweb/core`; this file supplies the listeners and the state.
18
23
  */
19
24
  export declare const KerusiSeatmap: import("react").ForwardRefExoticComponent<KerusiSeatmapProps & import("react").RefAttributes<KerusiSeatmapHandle>>;
20
25
  //# sourceMappingURL=kerusi-seatmap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kerusi-seatmap.d.ts","sourceRoot":"","sources":["../src/kerusi-seatmap.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAGnB,MAAM,YAAY,CAAC;AAOpB;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa,oHAmazB,CAAC"}
1
+ {"version":3,"file":"kerusi-seatmap.d.ts","sourceRoot":"","sources":["../src/kerusi-seatmap.tsx"],"names":[],"mappings":"AA6CA,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAGnB,MAAM,YAAY,CAAC;AASpB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,aAAa,oHAymBzB,CAAC"}