@kerusiweb/angular 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 +311 -4
- package/fesm2022/kerusiweb-angular.mjs +500 -138
- package/fesm2022/kerusiweb-angular.mjs.map +1 -1
- package/package.json +2 -2
- package/types/kerusiweb-angular.d.ts +177 -60
|
@@ -1,7 +1,53 @@
|
|
|
1
1
|
import * as _kerusiweb_core from '@kerusiweb/core';
|
|
2
|
-
import { KerusiMap, KerusiState, KerusiSession, SeatAriaStrings, KerusiSeatmapColors, RenderSeat, DisallowedReason, KerusiViolation, RenderMap, SectionLayout, RenderSection, PlacedSeat,
|
|
2
|
+
import { KerusiSeatContext, KerusiMap, KerusiState, KerusiSession, SeatAriaStrings, KerusiSeatmapColors, SeatStyleFn, RenderSeat, KerusiControlStrings, DisallowedReason, KerusiViolation, KerusiViewport, RenderMap, SectionLayout, RenderSection, PlacedSeat, PlacedElement, RenderLegendEntry, SeatOccupantVariant, SequenceReader, HeldSeat, KerusiStateDelta, DeltaApplication } from '@kerusiweb/core';
|
|
3
3
|
import * as _angular_core from '@angular/core';
|
|
4
|
-
import { Signal } from '@angular/core';
|
|
4
|
+
import { TemplateRef, Signal } from '@angular/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* What a `kerusiSeat` template is handed for each seat (`let-seat`): the seat,
|
|
8
|
+
* whether it is selected, the stock glyph core resolved for it, and the stock
|
|
9
|
+
* drawing itself.
|
|
10
|
+
*/
|
|
11
|
+
interface SeatTemplateContext extends KerusiSeatContext {
|
|
12
|
+
/**
|
|
13
|
+
* The library's own drawing of this seat. Render it to keep the stock seat,
|
|
14
|
+
* or alongside your own marks to add to it:
|
|
15
|
+
*
|
|
16
|
+
* ```html
|
|
17
|
+
* <ng-container *ngTemplateOutlet="seat.defaultContent; context: { $implicit: seat }" />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
defaultContent: TemplateRef<SeatTemplateOutletContext>;
|
|
21
|
+
}
|
|
22
|
+
/** The context object a seat template is stamped with. */
|
|
23
|
+
interface SeatTemplateOutletContext {
|
|
24
|
+
$implicit: SeatTemplateContext;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Marks an `<ng-template>` inside `<kerusi-seatmap>` as the drawing for every
|
|
28
|
+
* seat. The library keeps each seat's `<g>`, with its role, ARIA state, tab
|
|
29
|
+
* stop, rotation and event handlers, and stamps this template inside it.
|
|
30
|
+
*
|
|
31
|
+
* The template is declared outside any `<svg>`, so Angular cannot tell its
|
|
32
|
+
* elements are SVG: prefix each one with `svg:` (`<svg:path>`, `<svg:image>`),
|
|
33
|
+
* or it is created as an unknown HTML element and draws nothing.
|
|
34
|
+
*
|
|
35
|
+
* ```html
|
|
36
|
+
* <kerusi-seatmap [map]="map">
|
|
37
|
+
* <ng-template kerusiSeat let-seat>
|
|
38
|
+
* <ng-container *ngTemplateOutlet="seat.defaultContent; context: { $implicit: seat }" />
|
|
39
|
+
* <svg:circle [attr.cx]="seat.glyph.box.x" [attr.cy]="seat.glyph.box.y" r="3" />
|
|
40
|
+
* </ng-template>
|
|
41
|
+
* </kerusi-seatmap>
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare class KerusiSeatTemplateDirective {
|
|
45
|
+
readonly template: TemplateRef<SeatTemplateOutletContext>;
|
|
46
|
+
/** Types `let-seat` as a {@link SeatTemplateContext}. */
|
|
47
|
+
static ngTemplateContextGuard(_dir: KerusiSeatTemplateDirective, ctx: unknown): ctx is SeatTemplateOutletContext;
|
|
48
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<KerusiSeatTemplateDirective, never>;
|
|
49
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<KerusiSeatTemplateDirective, "ng-template[kerusiSeat]", never, {}, {}, never, never, true, never>;
|
|
50
|
+
}
|
|
5
51
|
|
|
6
52
|
/** How a document with validation errors is handled. */
|
|
7
53
|
type ValidationMode =
|
|
@@ -46,6 +92,11 @@ interface SeatDisallowed {
|
|
|
46
92
|
* ```html
|
|
47
93
|
* <kerusi-seatmap [map]="map" [state]="state" [(selection)]="picked" />
|
|
48
94
|
* ```
|
|
95
|
+
*
|
|
96
|
+
* Two opt-in features sit on top, both off by default so an existing map is
|
|
97
|
+
* unchanged: `[zoomable]` (pinch, wheel and drag, keys `+` `-` `0`, buttons)
|
|
98
|
+
* and `[maximizable]` (a full-screen button). Their arithmetic is in
|
|
99
|
+
* `@kerusiweb/core`; this class supplies the listeners and the signals.
|
|
49
100
|
*/
|
|
50
101
|
declare class KerusiSeatmapComponent {
|
|
51
102
|
private readonly host;
|
|
@@ -64,6 +115,22 @@ declare class KerusiSeatmapComponent {
|
|
|
64
115
|
readonly colors: _angular_core.InputSignal<KerusiSeatmapColors>;
|
|
65
116
|
/** Let an available seat take its `SeatType.color` (§4.7). */
|
|
66
117
|
readonly typeColors: _angular_core.InputSignal<boolean>;
|
|
118
|
+
/**
|
|
119
|
+
* Styles for every seat of a type, keyed by `SeatType.id`: fill, label colour
|
|
120
|
+
* and classes. Never changes a selected or blocked seat's fill. Also shown in
|
|
121
|
+
* the legend.
|
|
122
|
+
*/
|
|
123
|
+
readonly seatTypeStyles: _angular_core.InputSignal<Readonly<Record<string, _kerusiweb_core.KerusiSeatStyle>> | undefined>;
|
|
124
|
+
/**
|
|
125
|
+
* A style for one seat, laid over its `seatTypeStyles` entry; return nothing
|
|
126
|
+
* to leave a seat be. Never changes a selected or blocked seat's fill.
|
|
127
|
+
*/
|
|
128
|
+
readonly seatStyle: _angular_core.InputSignal<SeatStyleFn | undefined>;
|
|
129
|
+
/**
|
|
130
|
+
* A `<ng-template kerusiSeat let-seat>` placed inside the map draws the inside
|
|
131
|
+
* of every seat in place of the stock glyph. See {@link KerusiSeatTemplateDirective}.
|
|
132
|
+
*/
|
|
133
|
+
protected readonly seatTemplate: _angular_core.Signal<KerusiSeatTemplateDirective | undefined>;
|
|
67
134
|
/** Grid cell edge, in viewBox units. */
|
|
68
135
|
readonly seatSize: _angular_core.InputSignal<number>;
|
|
69
136
|
/** Gap between grid cells, in viewBox units. */
|
|
@@ -82,7 +149,7 @@ declare class KerusiSeatmapComponent {
|
|
|
82
149
|
readonly sectionIds: _angular_core.InputSignal<readonly string[] | undefined>;
|
|
83
150
|
readonly sectionOverrides: _angular_core.InputSignal<Readonly<Record<string, SectionRenderOptions>>>;
|
|
84
151
|
/** Statuses in which a seat may be picked. Default: `['available']`. */
|
|
85
|
-
readonly selectableStatuses: _angular_core.InputSignal<readonly ("
|
|
152
|
+
readonly selectableStatuses: _angular_core.InputSignal<readonly ("available" | "blocked" | "held" | "booked")[]>;
|
|
86
153
|
/** `auto` selects a seat's companion closure together (§4.6). */
|
|
87
154
|
readonly companionMode: _angular_core.InputSignal<"auto" | "independent">;
|
|
88
155
|
readonly maxSelection: _angular_core.InputSignal<number | undefined>;
|
|
@@ -96,6 +163,22 @@ declare class KerusiSeatmapComponent {
|
|
|
96
163
|
*/
|
|
97
164
|
readonly expireHolds: _angular_core.InputSignal<boolean>;
|
|
98
165
|
readonly expiryIntervalMs: _angular_core.InputSignal<number>;
|
|
166
|
+
/**
|
|
167
|
+
* Pinch, Ctrl/Cmd + wheel and drag to zoom and pan, `+` `-` `0` on the keyboard,
|
|
168
|
+
* and on-screen buttons. A tap still selects at every zoom level.
|
|
169
|
+
*/
|
|
170
|
+
readonly zoomable: _angular_core.InputSignal<boolean>;
|
|
171
|
+
/** The zoom ceiling, relative to fit-to-container. The floor is always fit. */
|
|
172
|
+
readonly maxZoom: _angular_core.InputSignal<number>;
|
|
173
|
+
/**
|
|
174
|
+
* The built-in zoom buttons. Turn this off to supply your own, anywhere on the
|
|
175
|
+
* page, and call `zoomIn()`, `zoomOut()` and `resetZoom()` on the component.
|
|
176
|
+
*/
|
|
177
|
+
readonly showZoomControls: _angular_core.InputSignal<boolean>;
|
|
178
|
+
/** A button that maximizes the map to fill the screen. */
|
|
179
|
+
readonly maximizable: _angular_core.InputSignal<boolean>;
|
|
180
|
+
/** Overrides the built-in English names of the zoom and maximize controls. */
|
|
181
|
+
readonly controlStrings: _angular_core.InputSignal<Partial<KerusiControlStrings>>;
|
|
99
182
|
readonly validate: _angular_core.InputSignal<ValidationMode>;
|
|
100
183
|
readonly seatSelect: _angular_core.OutputEmitterRef<SeatInteraction>;
|
|
101
184
|
readonly seatDeselect: _angular_core.OutputEmitterRef<SeatInteraction>;
|
|
@@ -103,6 +186,9 @@ declare class KerusiSeatmapComponent {
|
|
|
103
186
|
readonly seatFocus: _angular_core.OutputEmitterRef<RenderSeat>;
|
|
104
187
|
/** Emitted whenever the documents change, in `collect` mode. */
|
|
105
188
|
readonly validationIssues: _angular_core.OutputEmitterRef<readonly KerusiViolation[]>;
|
|
189
|
+
/** The zoom and pan, whenever they change. For a host that persists or shows them. */
|
|
190
|
+
readonly viewportChange: _angular_core.OutputEmitterRef<KerusiViewport>;
|
|
191
|
+
readonly maximizedChange: _angular_core.OutputEmitterRef<boolean>;
|
|
106
192
|
/**
|
|
107
193
|
* The seat holding each section's tab stop, keyed by section id.
|
|
108
194
|
*
|
|
@@ -114,6 +200,20 @@ declare class KerusiSeatmapComponent {
|
|
|
114
200
|
private readonly announcement;
|
|
115
201
|
/** Bumped by the hold ticker to force the state to be re-derived. */
|
|
116
202
|
private readonly expiryTick;
|
|
203
|
+
private readonly viewportState;
|
|
204
|
+
private readonly maximizedState;
|
|
205
|
+
/** True for a discrete change (button, key, reveal), false while a finger or wheel drives. */
|
|
206
|
+
protected readonly animated: _angular_core.WritableSignal<boolean>;
|
|
207
|
+
private readonly viewportEl;
|
|
208
|
+
private readonly contentEl;
|
|
209
|
+
private gesture;
|
|
210
|
+
private suppressClick;
|
|
211
|
+
private gestureBase;
|
|
212
|
+
private nativeFullscreen;
|
|
213
|
+
/** The current zoom and pan. Read-only: drive it with the methods below. */
|
|
214
|
+
readonly viewport: _angular_core.Signal<KerusiViewport>;
|
|
215
|
+
/** Whether the map is currently maximized. */
|
|
216
|
+
readonly maximized: _angular_core.Signal<boolean>;
|
|
117
217
|
constructor();
|
|
118
218
|
protected readonly issues: _angular_core.Signal<readonly KerusiViolation[]>;
|
|
119
219
|
/** The state actually rendered — with lapsed holds reverted when asked. */
|
|
@@ -123,6 +223,14 @@ declare class KerusiSeatmapComponent {
|
|
|
123
223
|
protected readonly isRtl: _angular_core.Signal<boolean>;
|
|
124
224
|
protected readonly resolvedColors: _angular_core.Signal<Required<KerusiSeatmapColors>>;
|
|
125
225
|
protected readonly selectionSet: _angular_core.Signal<Set<string>>;
|
|
226
|
+
protected readonly limits: _angular_core.Signal<_kerusiweb_core.ViewportLimits>;
|
|
227
|
+
protected readonly strings: _angular_core.Signal<KerusiControlStrings>;
|
|
228
|
+
protected readonly controlColors: _angular_core.Signal<_kerusiweb_core.KerusiControlStyle>;
|
|
229
|
+
protected readonly transform: _angular_core.Signal<string>;
|
|
230
|
+
protected readonly touchAction: _angular_core.Signal<string>;
|
|
231
|
+
protected readonly showToolbar: _angular_core.Signal<boolean>;
|
|
232
|
+
protected readonly atMaxZoom: _angular_core.Signal<boolean>;
|
|
233
|
+
protected readonly atFit: _angular_core.Signal<boolean>;
|
|
126
234
|
/** Placed geometry per section, keyed by section id. */
|
|
127
235
|
protected readonly layouts: _angular_core.Signal<ReadonlyMap<string, SectionLayout>>;
|
|
128
236
|
/** Navigation graphs per section — arrows move within, Tab moves between. */
|
|
@@ -150,16 +258,58 @@ declare class KerusiSeatmapComponent {
|
|
|
150
258
|
/**
|
|
151
259
|
* Moves the roving tab stop, then the DOM focus that follows it.
|
|
152
260
|
*
|
|
261
|
+
* When zoomable, the browser's own scroll-into-view is suppressed: the map
|
|
262
|
+
* moves by transform, so `onSeatFocused` pans it into view instead.
|
|
263
|
+
*/
|
|
264
|
+
private moveFocusTo;
|
|
265
|
+
/**
|
|
153
266
|
* Seat ids come from the document, so they cannot be interpolated into a
|
|
154
267
|
* selector unescaped — and `CSS.escape` is absent in jsdom and under SSR.
|
|
155
268
|
* Scanning the rendered nodes avoids both problems.
|
|
156
269
|
*/
|
|
157
|
-
private
|
|
270
|
+
private seatNode;
|
|
271
|
+
/** Zooms in one step about the centre. No-op unless `zoomable`. */
|
|
272
|
+
zoomIn(): void;
|
|
273
|
+
/** Zooms out one step about the centre. No-op unless `zoomable`. */
|
|
274
|
+
zoomOut(): void;
|
|
275
|
+
/** Back to fit-to-container: the map's original view. No-op unless `zoomable`. */
|
|
276
|
+
resetZoom(): void;
|
|
277
|
+
private stepZoom;
|
|
278
|
+
/** Sizes in CSS pixels, read when needed: `offset*` ignores the zoom transform. */
|
|
279
|
+
private measure;
|
|
280
|
+
private commit;
|
|
281
|
+
private reclamp;
|
|
282
|
+
/** A point in the viewport's own coordinates, which is what the core functions take. */
|
|
283
|
+
private containerPoint;
|
|
284
|
+
/**
|
|
285
|
+
* Pans a seat that took keyboard focus into view. A click or tap also
|
|
286
|
+
* focuses the seat, but should not move the map under the finger, so only a
|
|
287
|
+
* `:focus-visible` focus counts.
|
|
288
|
+
*/
|
|
289
|
+
private revealSeat;
|
|
290
|
+
private onPointerDown;
|
|
291
|
+
private onPointerMove;
|
|
292
|
+
private onPointerEnd;
|
|
293
|
+
private feedGesture;
|
|
294
|
+
private onClickCapture;
|
|
295
|
+
private onWheel;
|
|
296
|
+
private onGestureStart;
|
|
297
|
+
private onGestureChange;
|
|
298
|
+
private onGestureEnd;
|
|
299
|
+
/**
|
|
300
|
+
* `+` `-` `0` zoom, and arrows pan when the viewport itself has focus; Esc
|
|
301
|
+
* leaves a maximized map. A seat's own handler runs first, so an Esc that
|
|
302
|
+
* cleared the selection is already `defaultPrevented` and stays at that.
|
|
303
|
+
*/
|
|
304
|
+
protected onRootKeydown(event: KeyboardEvent): void;
|
|
305
|
+
/** Maximizes or restores the map. Maximizing needs `maximizable`. */
|
|
306
|
+
toggleMaximized(): void;
|
|
307
|
+
setMaximized(next: boolean): void;
|
|
158
308
|
private announceSelection;
|
|
159
309
|
private announce;
|
|
160
310
|
private visibleSectionIds;
|
|
161
311
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<KerusiSeatmapComponent, never>;
|
|
162
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<KerusiSeatmapComponent, "kerusi-seatmap", never, { "map": { "alias": "map"; "required": true; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "session": { "alias": "session"; "required": false; "isSignal": true; }; "selection": { "alias": "selection"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "rtl": { "alias": "rtl"; "required": false; "isSignal": true; }; "ariaStrings": { "alias": "ariaStrings"; "required": false; "isSignal": true; }; "colors": { "alias": "colors"; "required": false; "isSignal": true; }; "typeColors": { "alias": "typeColors"; "required": false; "isSignal": true; }; "seatSize": { "alias": "seatSize"; "required": false; "isSignal": true; }; "seatGap": { "alias": "seatGap"; "required": false; "isSignal": true; }; "freeformBasis": { "alias": "freeformBasis"; "required": false; "isSignal": true; }; "unitScale": { "alias": "unitScale"; "required": false; "isSignal": true; }; "showSectionLabels": { "alias": "showSectionLabels"; "required": false; "isSignal": true; }; "showLegend": { "alias": "showLegend"; "required": false; "isSignal": true; }; "showLegendPrices": { "alias": "showLegendPrices"; "required": false; "isSignal": true; }; "sectionIds": { "alias": "sectionIds"; "required": false; "isSignal": true; }; "sectionOverrides": { "alias": "sectionOverrides"; "required": false; "isSignal": true; }; "selectableStatuses": { "alias": "selectableStatuses"; "required": false; "isSignal": true; }; "companionMode": { "alias": "companionMode"; "required": false; "isSignal": true; }; "maxSelection": { "alias": "maxSelection"; "required": false; "isSignal": true; }; "seatSelectable": { "alias": "seatSelectable"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; "expireHolds": { "alias": "expireHolds"; "required": false; "isSignal": true; }; "expiryIntervalMs": { "alias": "expiryIntervalMs"; "required": false; "isSignal": true; }; "validate": { "alias": "validate"; "required": false; "isSignal": true; }; }, { "selection": "selectionChange"; "seatSelect": "seatSelect"; "seatDeselect": "seatDeselect"; "seatDisallowed": "seatDisallowed"; "seatFocus": "seatFocus"; "validationIssues": "validationIssues"; },
|
|
312
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<KerusiSeatmapComponent, "kerusi-seatmap", never, { "map": { "alias": "map"; "required": true; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "session": { "alias": "session"; "required": false; "isSignal": true; }; "selection": { "alias": "selection"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "rtl": { "alias": "rtl"; "required": false; "isSignal": true; }; "ariaStrings": { "alias": "ariaStrings"; "required": false; "isSignal": true; }; "colors": { "alias": "colors"; "required": false; "isSignal": true; }; "typeColors": { "alias": "typeColors"; "required": false; "isSignal": true; }; "seatTypeStyles": { "alias": "seatTypeStyles"; "required": false; "isSignal": true; }; "seatStyle": { "alias": "seatStyle"; "required": false; "isSignal": true; }; "seatSize": { "alias": "seatSize"; "required": false; "isSignal": true; }; "seatGap": { "alias": "seatGap"; "required": false; "isSignal": true; }; "freeformBasis": { "alias": "freeformBasis"; "required": false; "isSignal": true; }; "unitScale": { "alias": "unitScale"; "required": false; "isSignal": true; }; "showSectionLabels": { "alias": "showSectionLabels"; "required": false; "isSignal": true; }; "showLegend": { "alias": "showLegend"; "required": false; "isSignal": true; }; "showLegendPrices": { "alias": "showLegendPrices"; "required": false; "isSignal": true; }; "sectionIds": { "alias": "sectionIds"; "required": false; "isSignal": true; }; "sectionOverrides": { "alias": "sectionOverrides"; "required": false; "isSignal": true; }; "selectableStatuses": { "alias": "selectableStatuses"; "required": false; "isSignal": true; }; "companionMode": { "alias": "companionMode"; "required": false; "isSignal": true; }; "maxSelection": { "alias": "maxSelection"; "required": false; "isSignal": true; }; "seatSelectable": { "alias": "seatSelectable"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; "expireHolds": { "alias": "expireHolds"; "required": false; "isSignal": true; }; "expiryIntervalMs": { "alias": "expiryIntervalMs"; "required": false; "isSignal": true; }; "zoomable": { "alias": "zoomable"; "required": false; "isSignal": true; }; "maxZoom": { "alias": "maxZoom"; "required": false; "isSignal": true; }; "showZoomControls": { "alias": "showZoomControls"; "required": false; "isSignal": true; }; "maximizable": { "alias": "maximizable"; "required": false; "isSignal": true; }; "controlStrings": { "alias": "controlStrings"; "required": false; "isSignal": true; }; "validate": { "alias": "validate"; "required": false; "isSignal": true; }; }, { "selection": "selectionChange"; "seatSelect": "seatSelect"; "seatDeselect": "seatDeselect"; "seatDisallowed": "seatDisallowed"; "seatFocus": "seatFocus"; "validationIssues": "validationIssues"; "viewportChange": "viewportChange"; "maximizedChange": "maximizedChange"; }, ["seatTemplate"], never, true, never>;
|
|
163
313
|
}
|
|
164
314
|
|
|
165
315
|
/**
|
|
@@ -185,6 +335,12 @@ declare class KerusiSectionComponent {
|
|
|
185
335
|
readonly colors: _angular_core.InputSignal<Required<KerusiSeatmapColors>>;
|
|
186
336
|
/** Whether an available seat may take its `SeatType.color` (§4.7). */
|
|
187
337
|
readonly typeColors: _angular_core.InputSignal<boolean>;
|
|
338
|
+
/** Styles for every seat of a type, keyed by `SeatType.id`. */
|
|
339
|
+
readonly seatTypeStyles: _angular_core.InputSignal<Readonly<Record<string, _kerusiweb_core.KerusiSeatStyle>> | undefined>;
|
|
340
|
+
/** A style for one seat, laid over its type's. */
|
|
341
|
+
readonly seatStyle: _angular_core.InputSignal<SeatStyleFn | undefined>;
|
|
342
|
+
/** Draws the inside of each seat in place of the stock glyph. */
|
|
343
|
+
readonly seatTemplate: _angular_core.InputSignal<TemplateRef<SeatTemplateOutletContext> | undefined>;
|
|
188
344
|
/** When false, seats render but do not respond to pointer or keyboard. */
|
|
189
345
|
readonly interactive: _angular_core.InputSignal<boolean>;
|
|
190
346
|
/**
|
|
@@ -203,62 +359,19 @@ declare class KerusiSectionComponent {
|
|
|
203
359
|
protected readonly viewBox: _angular_core.Signal<string>;
|
|
204
360
|
/** The section's natural width in CSS pixels; it never draws wider. */
|
|
205
361
|
protected readonly naturalWidth: _angular_core.Signal<number>;
|
|
206
|
-
protected isSelected(placed: PlacedSeat): boolean;
|
|
207
|
-
protected fill(placed: PlacedSeat): string;
|
|
208
|
-
protected textFill(placed: PlacedSeat): string;
|
|
209
|
-
protected backdrop(): string;
|
|
210
|
-
/** The seat's outline: square-ish front, tapered back — shape carries facing. */
|
|
211
|
-
protected bodyPath(placed: PlacedSeat): string;
|
|
212
|
-
/** `null` for an available or blocked seat — nothing to mark. */
|
|
213
|
-
protected occupantVariant(placed: PlacedSeat): SeatOccupantVariant | null;
|
|
214
|
-
/**
|
|
215
|
-
* The box a seat's decorative marks are drawn to: the seat's own, or — when
|
|
216
|
-
* it is selected — the core plate's, which is inset by the frame width.
|
|
217
|
-
*
|
|
218
|
-
* Everything over a selected seat sits on the core, so it all has to be
|
|
219
|
-
* measured from the core. Drawing to the seat's box instead leaves the
|
|
220
|
-
* occupant's hips crossing the frame, where a figure tinted `selectedBg`
|
|
221
|
-
* lands on a frame filled `selectedBg` and reads as a hard nub. Since the
|
|
222
|
-
* core is an exact scaled copy of the body (see {@link seatSelectedFrame}),
|
|
223
|
-
* routing through here reproduces every clearance the mark had against the
|
|
224
|
-
* body, scaled — so the frame width stays free to change.
|
|
225
|
-
*/
|
|
226
|
-
private markBox;
|
|
227
|
-
/** The bright plate inside a selected seat's frame. */
|
|
228
|
-
protected corePath(placed: PlacedSeat): string;
|
|
229
|
-
protected coreFill(): string;
|
|
230
|
-
/** The dimming wash over a held or booked seat's type colour. */
|
|
231
|
-
protected washFill(placed: PlacedSeat): string;
|
|
232
|
-
/** The occupant figure for a marked seat, sized to whatever it sits on. */
|
|
233
|
-
protected occupantPath(placed: PlacedSeat): string;
|
|
234
|
-
protected occupantStroke(placed: PlacedSeat): number;
|
|
235
|
-
protected wheelchairCx(placed: PlacedSeat): number;
|
|
236
|
-
protected wheelchairCy(placed: PlacedSeat): number;
|
|
237
|
-
protected wheelchairRadius(placed: PlacedSeat): number;
|
|
238
362
|
/**
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
* The label is centred on the occupant's shoulder line, so without this it is
|
|
243
|
-
* `selectedBg` over a `selectedBg` silhouette — the figure, not the plate, is
|
|
244
|
-
* what it actually has to contrast against. The halo also rescues a label too
|
|
245
|
-
* long for the core, which would otherwise run onto the frame and vanish into
|
|
246
|
-
* it.
|
|
247
|
-
*
|
|
248
|
-
* Bound here rather than in the stylesheet on purpose: a CSS
|
|
249
|
-
* `var(--kerusi-selected-fg, …)` rule would carry the library default as its
|
|
250
|
-
* fallback and silently skip the `[colors]` input tier, which only the
|
|
251
|
-
* TypeScript side can resolve.
|
|
363
|
+
* Every seat with its glyph resolved, once per change of layout, selection or
|
|
364
|
+
* theme rather than once per binding per change detection.
|
|
252
365
|
*/
|
|
253
|
-
protected
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
366
|
+
protected readonly seats: _angular_core.Signal<{
|
|
367
|
+
placed: PlacedSeat;
|
|
368
|
+
selected: boolean;
|
|
369
|
+
glyph: _kerusiweb_core.SeatGlyph;
|
|
370
|
+
}[]>;
|
|
371
|
+
protected backdrop(): string;
|
|
258
372
|
/** The section's single tab stop; every other seat is reachable by arrow key. */
|
|
259
373
|
protected tabIndex(placed: PlacedSeat): number;
|
|
260
374
|
protected ariaLabel(placed: PlacedSeat): string;
|
|
261
|
-
protected seatClasses(placed: PlacedSeat): string;
|
|
262
375
|
/** SVG rotate() about the item's center; null when it does not rotate. */
|
|
263
376
|
protected transform(item: PlacedSeat | PlacedElement): string | null;
|
|
264
377
|
/** Cancels the parent <g>'s rotation so the label stays upright and stays put. */
|
|
@@ -277,7 +390,7 @@ declare class KerusiSectionComponent {
|
|
|
277
390
|
protected onSeatFocus(placed: PlacedSeat): void;
|
|
278
391
|
protected onKeydown(event: KeyboardEvent): void;
|
|
279
392
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<KerusiSectionComponent, never>;
|
|
280
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<KerusiSectionComponent, "kerusi-section", never, { "section": { "alias": "section"; "required": true; "isSignal": true; }; "layout": { "alias": "layout"; "required": true; "isSignal": true; }; "selection": { "alias": "selection"; "required": false; "isSignal": true; }; "focusedSeatId": { "alias": "focusedSeatId"; "required": false; "isSignal": true; }; "ariaLabels": { "alias": "ariaLabels"; "required": false; "isSignal": true; }; "colors": { "alias": "colors"; "required": false; "isSignal": true; }; "typeColors": { "alias": "typeColors"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; "unitScale": { "alias": "unitScale"; "required": false; "isSignal": true; }; }, { "seatActivate": "seatActivate"; "seatFocused": "seatFocused"; "seatKeydown": "seatKeydown"; }, never, never, true, never>;
|
|
393
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<KerusiSectionComponent, "kerusi-section", never, { "section": { "alias": "section"; "required": true; "isSignal": true; }; "layout": { "alias": "layout"; "required": true; "isSignal": true; }; "selection": { "alias": "selection"; "required": false; "isSignal": true; }; "focusedSeatId": { "alias": "focusedSeatId"; "required": false; "isSignal": true; }; "ariaLabels": { "alias": "ariaLabels"; "required": false; "isSignal": true; }; "colors": { "alias": "colors"; "required": false; "isSignal": true; }; "typeColors": { "alias": "typeColors"; "required": false; "isSignal": true; }; "seatTypeStyles": { "alias": "seatTypeStyles"; "required": false; "isSignal": true; }; "seatStyle": { "alias": "seatStyle"; "required": false; "isSignal": true; }; "seatTemplate": { "alias": "seatTemplate"; "required": false; "isSignal": true; }; "interactive": { "alias": "interactive"; "required": false; "isSignal": true; }; "unitScale": { "alias": "unitScale"; "required": false; "isSignal": true; }; }, { "seatActivate": "seatActivate"; "seatFocused": "seatFocused"; "seatKeydown": "seatKeydown"; }, never, never, true, never>;
|
|
281
394
|
}
|
|
282
395
|
|
|
283
396
|
/** Which marks, beyond the body fill, a status swatch draws. */
|
|
@@ -310,6 +423,8 @@ declare class KerusiLegendComponent {
|
|
|
310
423
|
readonly colors: _angular_core.InputSignal<Required<KerusiSeatmapColors>>;
|
|
311
424
|
/** Whether an available seat takes its type color — mirrors the seatmap input. */
|
|
312
425
|
readonly typeColors: _angular_core.InputSignal<boolean>;
|
|
426
|
+
/** Mirrors the seatmap input: a type's style is what its swatch shows. */
|
|
427
|
+
readonly seatTypeStyles: _angular_core.InputSignal<Readonly<Record<string, _kerusiweb_core.KerusiSeatStyle>> | undefined>;
|
|
313
428
|
readonly showPrices: _angular_core.InputSignal<boolean>;
|
|
314
429
|
/** Hide types no seat in the rendered map actually uses. */
|
|
315
430
|
readonly hideUnusedTypes: _angular_core.InputSignal<boolean>;
|
|
@@ -318,6 +433,8 @@ declare class KerusiLegendComponent {
|
|
|
318
433
|
protected readonly types: _angular_core.Signal<RenderLegendEntry[]>;
|
|
319
434
|
protected readonly statuses: _angular_core.Signal<StatusEntry[]>;
|
|
320
435
|
protected swatch(entry: RenderLegendEntry): string;
|
|
436
|
+
/** The swatch outline for a type styled with its own shape; `undefined` keeps the square. */
|
|
437
|
+
protected typeShape(entry: RenderLegendEntry): string | undefined;
|
|
321
438
|
protected swatchText(entry: RenderLegendEntry): string;
|
|
322
439
|
/** The swatch's viewBox edge; the seat glyph is drawn to fill it. */
|
|
323
440
|
protected readonly glyphSize = 16;
|
|
@@ -341,7 +458,7 @@ declare class KerusiLegendComponent {
|
|
|
341
458
|
protected coreFill(): string;
|
|
342
459
|
protected price(entry: RenderLegendEntry): string;
|
|
343
460
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<KerusiLegendComponent, never>;
|
|
344
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<KerusiLegendComponent, "kerusi-legend", never, { "legend": { "alias": "legend"; "required": true; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "colors": { "alias": "colors"; "required": false; "isSignal": true; }; "typeColors": { "alias": "typeColors"; "required": false; "isSignal": true; }; "showPrices": { "alias": "showPrices"; "required": false; "isSignal": true; }; "hideUnusedTypes": { "alias": "hideUnusedTypes"; "required": false; "isSignal": true; }; "headingSeatTypes": { "alias": "headingSeatTypes"; "required": false; "isSignal": true; }; "headingAvailability": { "alias": "headingAvailability"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
461
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<KerusiLegendComponent, "kerusi-legend", never, { "legend": { "alias": "legend"; "required": true; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "colors": { "alias": "colors"; "required": false; "isSignal": true; }; "typeColors": { "alias": "typeColors"; "required": false; "isSignal": true; }; "seatTypeStyles": { "alias": "seatTypeStyles"; "required": false; "isSignal": true; }; "showPrices": { "alias": "showPrices"; "required": false; "isSignal": true; }; "hideUnusedTypes": { "alias": "hideUnusedTypes"; "required": false; "isSignal": true; }; "headingSeatTypes": { "alias": "headingSeatTypes"; "required": false; "isSignal": true; }; "headingAvailability": { "alias": "headingAvailability"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
345
462
|
}
|
|
346
463
|
|
|
347
464
|
/**
|
|
@@ -390,5 +507,5 @@ declare class KerusiStateStore {
|
|
|
390
507
|
startExpiryTicker(intervalMs?: number): () => void;
|
|
391
508
|
}
|
|
392
509
|
|
|
393
|
-
export { KerusiLegendComponent, KerusiSeatmapComponent, KerusiSectionComponent, KerusiStateStore };
|
|
394
|
-
export type { SeatDisallowed, SeatInteraction, SectionRenderOptions, ValidationMode };
|
|
510
|
+
export { KerusiLegendComponent, KerusiSeatTemplateDirective, KerusiSeatmapComponent, KerusiSectionComponent, KerusiStateStore };
|
|
511
|
+
export type { SeatDisallowed, SeatInteraction, SeatTemplateContext, SeatTemplateOutletContext, SectionRenderOptions, ValidationMode };
|