@kerusiweb/core 2.1.0 → 2.2.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.
@@ -0,0 +1,45 @@
1
+ import { KerusiSeatmapColors } from './kerusi-seatmap-colors.js';
2
+ /**
3
+ * The words on the zoom and maximize controls, for a translator to replace.
4
+ *
5
+ * Kept apart from `SeatAriaStrings` on purpose: that type is an object callers
6
+ * build in full, so a new required field there would break every one of them.
7
+ */
8
+ export interface KerusiControlStrings {
9
+ /** The accessible name of the zoomable map's focusable viewport. */
10
+ viewport: string;
11
+ /** The accessible name of the group of zoom and maximize buttons. */
12
+ toolbar: string;
13
+ zoomIn: string;
14
+ zoomOut: string;
15
+ /** Back to fit-to-container. */
16
+ zoomReset: string;
17
+ /** The maximize button when the map is not maximized. */
18
+ maximize: string;
19
+ /** The maximize button when the map is maximized. */
20
+ restore: string;
21
+ }
22
+ export declare const DEFAULT_KERUSI_CONTROL_STRINGS: KerusiControlStrings;
23
+ /** Fills the gaps in a partial set of strings with the English defaults. */
24
+ export declare function resolveControlStrings(strings?: Partial<KerusiControlStrings>): KerusiControlStrings;
25
+ /**
26
+ * Colours for the controls and the maximized backdrop, as CSS values.
27
+ *
28
+ * Nothing new for a theme to learn: the buttons borrow the fixture tokens
29
+ * (`elementBg`, `elementFg`, `elementMutedFg`) and go through {@link cssVar}
30
+ * like every other colour, so a `--kerusi-*` property in the consumer's
31
+ * stylesheet still beats the `[colors]` input, which still beats the default.
32
+ * The focus ring is the one exception, and is not here: a pseudo-class cannot
33
+ * be set inline, so it reads `--kerusi-focus-ring-input` from the stylesheet,
34
+ * the same way a seat's does.
35
+ */
36
+ export interface KerusiControlStyle {
37
+ buttonBackground: string;
38
+ buttonColor: string;
39
+ buttonBorder: string;
40
+ /** Behind a maximized map. `backdrop`, or the page's own canvas if that is transparent. */
41
+ maximizedBackground: string;
42
+ maximizedColor: string;
43
+ }
44
+ export declare function controlStyle(colors?: KerusiSeatmapColors): KerusiControlStyle;
45
+ //# sourceMappingURL=control-strings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-strings.d.ts","sourceRoot":"","sources":["../../src/view/control-strings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,mBAAmB,EAAiB,MAAM,4BAA4B,CAAC;AAExF;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,8BAA8B,EAAE,oBAQ5C,CAAC;AAEF,4EAA4E;AAC5E,wBAAgB,qBAAqB,CACnC,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GACtC,oBAAoB,CAEtB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,2FAA2F;IAC3F,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,kBAAkB,CAe7E"}
@@ -0,0 +1,28 @@
1
+ import { cssVar, resolveColors } from './kerusi-seatmap-colors.js';
2
+ export const DEFAULT_KERUSI_CONTROL_STRINGS = {
3
+ viewport: 'Zoomable seat map. Plus and minus zoom, zero resets, arrow keys pan.',
4
+ toolbar: 'Map controls',
5
+ zoomIn: 'Zoom in',
6
+ zoomOut: 'Zoom out',
7
+ zoomReset: 'Reset zoom',
8
+ maximize: 'Enter full screen',
9
+ restore: 'Exit full screen',
10
+ };
11
+ /** Fills the gaps in a partial set of strings with the English defaults. */
12
+ export function resolveControlStrings(strings) {
13
+ return { ...DEFAULT_KERUSI_CONTROL_STRINGS, ...strings };
14
+ }
15
+ export function controlStyle(colors) {
16
+ const resolved = resolveColors(colors);
17
+ return {
18
+ buttonBackground: cssVar('elementBg', resolved.elementBg),
19
+ buttonColor: cssVar('elementFg', resolved.elementFg),
20
+ buttonBorder: cssVar('elementMutedFg', resolved.elementMutedFg),
21
+ // A maximized map covers the page, so a transparent backdrop would show it
22
+ // through. `Canvas` / `CanvasText` are the page's own background and text
23
+ // colours, which keeps the pair legible in whichever scheme the host uses.
24
+ maximizedBackground: cssVar('backdrop', resolved.backdrop === 'transparent' ? 'Canvas' : resolved.backdrop),
25
+ maximizedColor: 'CanvasText',
26
+ };
27
+ }
28
+ //# sourceMappingURL=control-strings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-strings.js","sourceRoot":"","sources":["../../src/view/control-strings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAuB,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAuBxF,MAAM,CAAC,MAAM,8BAA8B,GAAyB;IAClE,QAAQ,EAAE,sEAAsE;IAChF,OAAO,EAAE,cAAc;IACvB,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,YAAY;IACvB,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,kBAAkB;CAC5B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,UAAU,qBAAqB,CACnC,OAAuC;IAEvC,OAAO,EAAE,GAAG,8BAA8B,EAAE,GAAG,OAAO,EAAE,CAAC;AAC3D,CAAC;AAsBD,MAAM,UAAU,YAAY,CAAC,MAA4B;IACvD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO;QACL,gBAAgB,EAAE,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC;QACzD,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,SAAS,CAAC;QACpD,YAAY,EAAE,MAAM,CAAC,gBAAgB,EAAE,QAAQ,CAAC,cAAc,CAAC;QAC/D,2EAA2E;QAC3E,0EAA0E;QAC1E,2EAA2E;QAC3E,mBAAmB,EAAE,MAAM,CACzB,UAAU,EACV,QAAQ,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CACnE;QACD,cAAc,EAAE,YAAY;KAC7B,CAAC;AACJ,CAAC"}
@@ -1,12 +1,16 @@
1
1
  /**
2
2
  * Presentation policy that is still framework-free: the colour system a
3
- * renderer resolves seat fills from, the ARIA strings it announces, and the
4
- * selection rules that decide whether a seat may be toggled.
3
+ * renderer resolves seat fills from, the ARIA strings it announces, the
4
+ * selection rules that decide whether a seat may be toggled, and the zoom, pan
5
+ * and gesture arithmetic behind a zoomable map.
5
6
  *
6
7
  * A binding turns these into markup; none of them know how.
7
8
  */
9
+ export * from './control-strings.js';
8
10
  export * from './kerusi-seatmap-colors.js';
9
11
  export * from './rtl.js';
10
12
  export * from './seat-aria.js';
11
13
  export * from './selection.js';
14
+ export * from './viewport.js';
15
+ export * from './viewport-gesture.js';
12
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/view/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/view/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC"}
@@ -1,12 +1,16 @@
1
1
  /**
2
2
  * Presentation policy that is still framework-free: the colour system a
3
- * renderer resolves seat fills from, the ARIA strings it announces, and the
4
- * selection rules that decide whether a seat may be toggled.
3
+ * renderer resolves seat fills from, the ARIA strings it announces, the
4
+ * selection rules that decide whether a seat may be toggled, and the zoom, pan
5
+ * and gesture arithmetic behind a zoomable map.
5
6
  *
6
7
  * A binding turns these into markup; none of them know how.
7
8
  */
9
+ export * from './control-strings.js';
8
10
  export * from './kerusi-seatmap-colors.js';
9
11
  export * from './rtl.js';
10
12
  export * from './seat-aria.js';
11
13
  export * from './selection.js';
14
+ export * from './viewport.js';
15
+ export * from './viewport-gesture.js';
12
16
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/view/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/view/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { KerusiViewport, ViewportLimits, ViewportPoint, ViewportSize } from './viewport.js';
2
+ /**
3
+ * Pointer gestures on a zoomable map, as a reducer.
4
+ *
5
+ * One pointer pans, two pinch. The rule that matters most is the one that keeps
6
+ * seat selection intact: a touch that never leaves a small circle around where
7
+ * it landed is a *tap* and changes nothing, so the `click` that follows still
8
+ * reaches the seat. A binding feeds `down` / `move` / `up` / `cancel` in
9
+ * container coordinates and applies what comes back; it never has to know what
10
+ * a pinch is.
11
+ */
12
+ /** How far a pointer may travel, in CSS pixels, and still be a tap. */
13
+ export declare const TAP_SLOP_PX = 8;
14
+ export type GestureEvent = {
15
+ type: 'down' | 'move';
16
+ id: number;
17
+ point: ViewportPoint;
18
+ } | {
19
+ type: 'up' | 'cancel';
20
+ id: number;
21
+ };
22
+ /** Where the gesture stands. Opaque to callers: pass it back in. */
23
+ export interface GestureState {
24
+ /** Tracked pointer ids, oldest first. A pinch uses the first two. */
25
+ readonly ids: readonly number[];
26
+ /** Where each tracked pointer is now. */
27
+ readonly points: Readonly<Record<number, ViewportPoint>>;
28
+ /** The viewport and pointer positions the current movement is measured from. */
29
+ readonly origin: {
30
+ readonly viewport: KerusiViewport;
31
+ readonly points: Readonly<Record<number, ViewportPoint>>;
32
+ } | null;
33
+ /** True once the gesture is a pan or a pinch rather than a possible tap. */
34
+ readonly moved: boolean;
35
+ }
36
+ export declare const IDLE_GESTURE: GestureState;
37
+ export interface GestureContext {
38
+ /** The live viewport. */
39
+ viewport: KerusiViewport;
40
+ /** The map's laid-out size, unscaled. */
41
+ content: ViewportSize;
42
+ /** The visible area. */
43
+ container: ViewportSize;
44
+ limits?: ViewportLimits;
45
+ /** Overrides {@link TAP_SLOP_PX}. */
46
+ slop?: number;
47
+ }
48
+ export interface GestureResult {
49
+ state: GestureState;
50
+ /** The viewport after this event; the very same object when nothing changed. */
51
+ viewport: KerusiViewport;
52
+ /**
53
+ * True on the event that turns a possible tap into a gesture. A binding
54
+ * captures the pointers then, not earlier: capturing on `down` would
55
+ * retarget the tap's `click` away from the seat.
56
+ */
57
+ capture: boolean;
58
+ /**
59
+ * True on the `up` that ends a gesture. The browser still fires a `click`
60
+ * after a drag, and it must not select the seat under the finger.
61
+ */
62
+ suppressClick: boolean;
63
+ }
64
+ export declare function reduceGesture(state: GestureState, event: GestureEvent, context: GestureContext): GestureResult;
65
+ //# sourceMappingURL=viewport-gesture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-gesture.d.ts","sourceRoot":"","sources":["../../src/view/viewport-gesture.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACd,cAAc,EACd,aAAa,EACb,YAAY,EAEb,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;GASG;AAEH,uEAAuE;AACvE,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,IAAI,GAAG,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,oEAAoE;AACpE,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IACzD,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;QAClC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;KAC1D,GAAG,IAAI,CAAC;IACT,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,YAAY,EAAE,YAKzB,CAAC;AAEH,MAAM,WAAW,cAAc;IAC7B,yBAAyB;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,yCAAyC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,wBAAwB;IACxB,SAAS,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,gFAAgF;IAChF,QAAQ,EAAE,cAAc,CAAC;IACzB;;;;OAIG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,cAAc,GACtB,aAAa,CAUf"}
@@ -0,0 +1,145 @@
1
+ import { clampViewport, zoomLimits, } from './viewport.js';
2
+ /**
3
+ * Pointer gestures on a zoomable map, as a reducer.
4
+ *
5
+ * One pointer pans, two pinch. The rule that matters most is the one that keeps
6
+ * seat selection intact: a touch that never leaves a small circle around where
7
+ * it landed is a *tap* and changes nothing, so the `click` that follows still
8
+ * reaches the seat. A binding feeds `down` / `move` / `up` / `cancel` in
9
+ * container coordinates and applies what comes back; it never has to know what
10
+ * a pinch is.
11
+ */
12
+ /** How far a pointer may travel, in CSS pixels, and still be a tap. */
13
+ export const TAP_SLOP_PX = 8;
14
+ export const IDLE_GESTURE = Object.freeze({
15
+ ids: [],
16
+ points: {},
17
+ origin: null,
18
+ moved: false,
19
+ });
20
+ export function reduceGesture(state, event, context) {
21
+ switch (event.type) {
22
+ case 'down':
23
+ return onDown(state, event.id, event.point, context);
24
+ case 'move':
25
+ return onMove(state, event.id, event.point, context);
26
+ case 'up':
27
+ case 'cancel':
28
+ return onEnd(state, event.id, event.type === 'up', context);
29
+ }
30
+ }
31
+ function onDown(state, id, point, context) {
32
+ const ids = state.ids.includes(id) ? state.ids : [...state.ids, id];
33
+ const points = { ...state.points, [id]: point };
34
+ // A second finger makes it a pinch at once; there is no tap with two fingers.
35
+ const moved = state.moved || ids.length > 1;
36
+ return {
37
+ // Re-baselined on every change to the pointer set, so nothing jumps.
38
+ state: { ids, points, origin: { viewport: context.viewport, points }, moved },
39
+ viewport: context.viewport,
40
+ capture: moved && !state.moved,
41
+ suppressClick: false,
42
+ };
43
+ }
44
+ function onMove(state, id, point, context) {
45
+ if (!state.ids.includes(id) || !state.origin) {
46
+ return unchanged(state, context);
47
+ }
48
+ const points = { ...state.points, [id]: point };
49
+ let moved = state.moved;
50
+ let capture = false;
51
+ if (!moved) {
52
+ const slop = context.slop ?? TAP_SLOP_PX;
53
+ const start = state.origin.points[id] ?? point;
54
+ if (distance(start, point) <= slop) {
55
+ return {
56
+ state: { ...state, points },
57
+ viewport: context.viewport,
58
+ capture: false,
59
+ suppressClick: false,
60
+ };
61
+ }
62
+ moved = true;
63
+ capture = true;
64
+ }
65
+ const next = transformFromOrigin(state, points, context);
66
+ return {
67
+ state: { ...state, points, moved },
68
+ viewport: next,
69
+ capture,
70
+ suppressClick: false,
71
+ };
72
+ }
73
+ function onEnd(state, id, isUp, context) {
74
+ if (!state.ids.includes(id)) {
75
+ return unchanged(state, context);
76
+ }
77
+ const ids = state.ids.filter((other) => other !== id);
78
+ const points = { ...state.points };
79
+ delete points[id];
80
+ if (ids.length === 0) {
81
+ return {
82
+ state: IDLE_GESTURE,
83
+ viewport: context.viewport,
84
+ capture: false,
85
+ // A cancel means the browser took the gesture (a page scroll), and no
86
+ // click follows it.
87
+ suppressClick: isUp && state.moved,
88
+ };
89
+ }
90
+ // One finger of a pinch lifted: the other carries on as a pan from here.
91
+ return {
92
+ state: {
93
+ ids,
94
+ points,
95
+ origin: { viewport: context.viewport, points },
96
+ moved: state.moved,
97
+ },
98
+ viewport: context.viewport,
99
+ capture: false,
100
+ suppressClick: false,
101
+ };
102
+ }
103
+ /** Pan for one pointer; pan and zoom about the midpoint for two. */
104
+ function transformFromOrigin(state, points, context) {
105
+ const origin = state.origin;
106
+ const limits = context.limits ?? zoomLimits();
107
+ const [first, second] = state.ids;
108
+ const from = [origin.points[first]];
109
+ const to = [points[first]];
110
+ if (second !== undefined) {
111
+ from.push(origin.points[second]);
112
+ to.push(points[second]);
113
+ }
114
+ const fromCentre = centroid(from);
115
+ const toCentre = centroid(to);
116
+ const base = origin.viewport;
117
+ let zoom = base.zoom;
118
+ if (from.length === 2) {
119
+ const fromSpan = distance(from[0], from[1]);
120
+ if (fromSpan > 0) {
121
+ zoom = clampZoom(base.zoom * (distance(to[0], to[1]) / fromSpan), limits);
122
+ }
123
+ }
124
+ // The map point that sat under the gesture's start stays under its midpoint.
125
+ const ratio = zoom / base.zoom;
126
+ return clampViewport({
127
+ zoom,
128
+ x: toCentre.x - (fromCentre.x - base.x) * ratio,
129
+ y: toCentre.y - (fromCentre.y - base.y) * ratio,
130
+ }, context.content, context.container, limits);
131
+ }
132
+ function unchanged(state, context) {
133
+ return { state, viewport: context.viewport, capture: false, suppressClick: false };
134
+ }
135
+ function distance(a, b) {
136
+ return Math.hypot(a.x - b.x, a.y - b.y);
137
+ }
138
+ function centroid(points) {
139
+ const sum = points.reduce((acc, p) => ({ x: acc.x + p.x, y: acc.y + p.y }), { x: 0, y: 0 });
140
+ return { x: sum.x / points.length, y: sum.y / points.length };
141
+ }
142
+ function clampZoom(zoom, limits) {
143
+ return Math.min(limits.maxZoom, Math.max(limits.minZoom, zoom));
144
+ }
145
+ //# sourceMappingURL=viewport-gesture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-gesture.js","sourceRoot":"","sources":["../../src/view/viewport-gesture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * The zoom-and-pan model behind a `zoomable` seat map.
3
+ *
4
+ * A viewport is a CSS transform applied to the whole map: `translate(x, y)
5
+ * scale(zoom)` about the map's top-left corner. Everything here is arithmetic on
6
+ * numbers the caller measured, so it holds no DOM and every function is pure.
7
+ * The bindings own the measuring and the event listeners; this owns what a
8
+ * wheel tick, a key press or a pinch *means*.
9
+ *
10
+ * Zoom 1 is "fit": the map exactly as it lays out without zooming. It is also
11
+ * the minimum, so the map can never be shrunk below the container.
12
+ */
13
+ /** Zoom and pan of the map, as a CSS transform about its top-left corner. */
14
+ export interface KerusiViewport {
15
+ /** Scale relative to fit. 1 is fit-to-container. */
16
+ zoom: number;
17
+ /** Translation in CSS pixels, applied before the scale. */
18
+ x: number;
19
+ y: number;
20
+ }
21
+ export interface ViewportPoint {
22
+ x: number;
23
+ y: number;
24
+ }
25
+ export interface ViewportSize {
26
+ width: number;
27
+ height: number;
28
+ }
29
+ export interface ViewportRect extends ViewportPoint, ViewportSize {
30
+ }
31
+ export interface ViewportLimits {
32
+ minZoom: number;
33
+ maxZoom: number;
34
+ }
35
+ /** The map exactly as laid out: no zoom, no pan. */
36
+ export declare const FIT_VIEWPORT: KerusiViewport;
37
+ /** Zoom is relative to fit, so the floor is always 1. */
38
+ export declare const MIN_ZOOM = 1;
39
+ /** The default ceiling: enough to make a seat on a 375px phone comfortably tappable. */
40
+ export declare const DEFAULT_MAX_ZOOM = 4;
41
+ /** What one press of a zoom button or the `+` / `-` key multiplies the zoom by. */
42
+ export declare const ZOOM_STEP = 1.5;
43
+ /** How far an arrow key pans, in CSS pixels. */
44
+ export declare const KEYBOARD_PAN_STEP = 48;
45
+ /** The gap kept between a revealed seat and the container's edge, in CSS pixels. */
46
+ export declare const REVEAL_MARGIN = 16;
47
+ /** Wheel zoom: the exponent per pixel of `deltaY`, so a pinch's small deltas stay smooth. */
48
+ export declare const WHEEL_ZOOM_SENSITIVITY = 0.01;
49
+ /** A single wheel event never moves further than this, so a mouse notch is one step. */
50
+ export declare const WHEEL_MAX_DELTA = 50;
51
+ /** The limits for a given ceiling. A ceiling below fit still leaves fit reachable. */
52
+ export declare function zoomLimits(maxZoom?: number): ViewportLimits;
53
+ /**
54
+ * Brings a viewport back inside its limits.
55
+ *
56
+ * Zoom is clamped to the limits. Pan is clamped so the scaled map never leaves
57
+ * the container, and on an axis where the scaled map is *smaller* than the
58
+ * container (a maximized map on a large screen) it is centred instead.
59
+ */
60
+ export declare function clampViewport(viewport: KerusiViewport, content: ViewportSize, container: ViewportSize, limits?: ViewportLimits): KerusiViewport;
61
+ /** Fit, centred where the map is smaller than its container. */
62
+ export declare function fitViewport(content: ViewportSize, container: ViewportSize, limits?: ViewportLimits): KerusiViewport;
63
+ /**
64
+ * Zooms to an absolute level, keeping the map point under `anchor` where it is.
65
+ * `anchor` is in container coordinates — the pointer, the midpoint of a pinch,
66
+ * or the container's centre for a button.
67
+ */
68
+ export declare function zoomViewportTo(viewport: KerusiViewport, zoom: number, anchor: ViewportPoint, content: ViewportSize, container: ViewportSize, limits?: ViewportLimits): KerusiViewport;
69
+ /** Zooms by a factor about `anchor`. See {@link zoomViewportTo}. */
70
+ export declare function zoomViewportBy(viewport: KerusiViewport, factor: number, anchor: ViewportPoint, content: ViewportSize, container: ViewportSize, limits?: ViewportLimits): KerusiViewport;
71
+ /** One zoom-button step about the container's centre: `1` in, `-1` out. */
72
+ export declare function stepViewport(viewport: KerusiViewport, direction: 1 | -1, content: ViewportSize, container: ViewportSize, limits?: ViewportLimits): KerusiViewport;
73
+ /** Pans by a delta in CSS pixels, held inside the map's bounds. */
74
+ export declare function panViewportBy(viewport: KerusiViewport, dx: number, dy: number, content: ViewportSize, container: ViewportSize, limits?: ViewportLimits): KerusiViewport;
75
+ /**
76
+ * Pans just far enough to bring `rect` inside the container, with a margin.
77
+ *
78
+ * `rect` is where the thing is on screen *now*, in container coordinates — a
79
+ * seat's bounding box minus the container's. Measuring the result of the
80
+ * current transform, rather than computing a position from the layout, is what
81
+ * keeps this correct whatever the section widths and unit scale are. A rect
82
+ * bigger than the container is aligned by its leading edge.
83
+ */
84
+ export declare function revealRect(viewport: KerusiViewport, rect: ViewportRect, content: ViewportSize, container: ViewportSize, margin?: number, limits?: ViewportLimits): KerusiViewport;
85
+ /**
86
+ * The zoom factor a wheel event asks for, or `null` if it is not a zoom
87
+ * gesture.
88
+ *
89
+ * Only Ctrl/Cmd + wheel zooms. Browsers report a trackpad pinch as a wheel
90
+ * event with `ctrlKey` set, so one rule covers both. A plain wheel returns
91
+ * `null`, which is the cue for a binding to leave it alone so the page still
92
+ * scrolls — and only a non-null result should be `preventDefault`ed.
93
+ */
94
+ export declare function wheelZoomFactor(event: {
95
+ deltaY: number;
96
+ deltaMode?: number;
97
+ ctrlKey: boolean;
98
+ metaKey: boolean;
99
+ }): number | null;
100
+ /** The keys {@link keyboardViewport} understands, for a binding's own filtering. */
101
+ export interface ViewportKeyInput {
102
+ key: string;
103
+ ctrlKey?: boolean;
104
+ metaKey?: boolean;
105
+ altKey?: boolean;
106
+ /**
107
+ * Whether the viewport itself, rather than a seat inside it, has focus.
108
+ * Arrow keys pan only then: on a seat they keep moving seat focus.
109
+ */
110
+ viewportFocused?: boolean;
111
+ }
112
+ /**
113
+ * What a key press does to the viewport, or `null` if it does nothing.
114
+ *
115
+ * `+` / `=` zoom in, `-` zoom out, `0` resets to fit, and — only when the
116
+ * viewport itself has focus — the arrow keys pan. Ctrl, Cmd and Alt
117
+ * combinations are the browser's own zoom shortcuts and are left alone.
118
+ */
119
+ export declare function keyboardViewport(viewport: KerusiViewport, input: ViewportKeyInput, content: ViewportSize, container: ViewportSize, limits?: ViewportLimits): KerusiViewport | null;
120
+ /**
121
+ * Whether a key event came from somewhere text is typed.
122
+ *
123
+ * A host can put its own controls inside the map, and `+`, `-` and `0` are
124
+ * characters before they are shortcuts. Takes the target structurally so core
125
+ * never has to name a DOM type.
126
+ */
127
+ export declare function isTextEntryTarget(target: {
128
+ tagName?: string;
129
+ isContentEditable?: boolean;
130
+ } | null | undefined): boolean;
131
+ /** Whether two viewports are the same view, ignoring sub-pixel noise. */
132
+ export declare function viewportsEqual(a: KerusiViewport, b: KerusiViewport): boolean;
133
+ /** The CSS `transform` for a viewport. Apply with `transform-origin: 0 0`. */
134
+ export declare function viewportTransform(viewport: KerusiViewport): string;
135
+ /**
136
+ * The `touch-action` a zoomable map sets on its viewport.
137
+ *
138
+ * At fit there is nothing to pan, so a one-finger vertical swipe stays the
139
+ * page's: `pan-y` leaves vertical scrolling to the browser while still handing
140
+ * us pinch. Once zoomed in, one finger means pan, and a maximized map covers
141
+ * the page, so both take every gesture with `none`.
142
+ */
143
+ export declare function viewportTouchAction(viewport: KerusiViewport, maximized: boolean): string;
144
+ //# sourceMappingURL=viewport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport.d.ts","sourceRoot":"","sources":["../../src/view/viewport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * The zoom-and-pan model behind a `zoomable` seat map.
3
+ *
4
+ * A viewport is a CSS transform applied to the whole map: `translate(x, y)
5
+ * scale(zoom)` about the map's top-left corner. Everything here is arithmetic on
6
+ * numbers the caller measured, so it holds no DOM and every function is pure.
7
+ * The bindings own the measuring and the event listeners; this owns what a
8
+ * wheel tick, a key press or a pinch *means*.
9
+ *
10
+ * Zoom 1 is "fit": the map exactly as it lays out without zooming. It is also
11
+ * the minimum, so the map can never be shrunk below the container.
12
+ */
13
+ /** The map exactly as laid out: no zoom, no pan. */
14
+ export const FIT_VIEWPORT = Object.freeze({ zoom: 1, x: 0, y: 0 });
15
+ /** Zoom is relative to fit, so the floor is always 1. */
16
+ export const MIN_ZOOM = 1;
17
+ /** The default ceiling: enough to make a seat on a 375px phone comfortably tappable. */
18
+ export const DEFAULT_MAX_ZOOM = 4;
19
+ /** What one press of a zoom button or the `+` / `-` key multiplies the zoom by. */
20
+ export const ZOOM_STEP = 1.5;
21
+ /** How far an arrow key pans, in CSS pixels. */
22
+ export const KEYBOARD_PAN_STEP = 48;
23
+ /** The gap kept between a revealed seat and the container's edge, in CSS pixels. */
24
+ export const REVEAL_MARGIN = 16;
25
+ /** Wheel zoom: the exponent per pixel of `deltaY`, so a pinch's small deltas stay smooth. */
26
+ export const WHEEL_ZOOM_SENSITIVITY = 0.01;
27
+ /** A single wheel event never moves further than this, so a mouse notch is one step. */
28
+ export const WHEEL_MAX_DELTA = 50;
29
+ /** The limits for a given ceiling. A ceiling below fit still leaves fit reachable. */
30
+ export function zoomLimits(maxZoom = DEFAULT_MAX_ZOOM) {
31
+ return { minZoom: MIN_ZOOM, maxZoom: Math.max(MIN_ZOOM, finiteOr(maxZoom, DEFAULT_MAX_ZOOM)) };
32
+ }
33
+ /**
34
+ * Brings a viewport back inside its limits.
35
+ *
36
+ * Zoom is clamped to the limits. Pan is clamped so the scaled map never leaves
37
+ * the container, and on an axis where the scaled map is *smaller* than the
38
+ * container (a maximized map on a large screen) it is centred instead.
39
+ */
40
+ export function clampViewport(viewport, content, container, limits = zoomLimits()) {
41
+ const zoom = clamp(finiteOr(viewport.zoom, 1), limits.minZoom, limits.maxZoom);
42
+ return {
43
+ zoom,
44
+ x: clampAxis(finiteOr(viewport.x, 0), content.width * zoom, container.width),
45
+ y: clampAxis(finiteOr(viewport.y, 0), content.height * zoom, container.height),
46
+ };
47
+ }
48
+ /** Fit, centred where the map is smaller than its container. */
49
+ export function fitViewport(content, container, limits = zoomLimits()) {
50
+ return clampViewport(FIT_VIEWPORT, content, container, limits);
51
+ }
52
+ /**
53
+ * Zooms to an absolute level, keeping the map point under `anchor` where it is.
54
+ * `anchor` is in container coordinates — the pointer, the midpoint of a pinch,
55
+ * or the container's centre for a button.
56
+ */
57
+ export function zoomViewportTo(viewport, zoom, anchor, content, container, limits = zoomLimits()) {
58
+ const current = finiteOr(viewport.zoom, 1) || 1;
59
+ const next = clamp(finiteOr(zoom, current), limits.minZoom, limits.maxZoom);
60
+ const ratio = next / current;
61
+ return clampViewport({
62
+ zoom: next,
63
+ x: anchor.x - (anchor.x - viewport.x) * ratio,
64
+ y: anchor.y - (anchor.y - viewport.y) * ratio,
65
+ }, content, container, limits);
66
+ }
67
+ /** Zooms by a factor about `anchor`. See {@link zoomViewportTo}. */
68
+ export function zoomViewportBy(viewport, factor, anchor, content, container, limits = zoomLimits()) {
69
+ return zoomViewportTo(viewport, viewport.zoom * factor, anchor, content, container, limits);
70
+ }
71
+ /** One zoom-button step about the container's centre: `1` in, `-1` out. */
72
+ export function stepViewport(viewport, direction, content, container, limits = zoomLimits()) {
73
+ const centre = { x: container.width / 2, y: container.height / 2 };
74
+ const factor = direction === 1 ? ZOOM_STEP : 1 / ZOOM_STEP;
75
+ return zoomViewportBy(viewport, factor, centre, content, container, limits);
76
+ }
77
+ /** Pans by a delta in CSS pixels, held inside the map's bounds. */
78
+ export function panViewportBy(viewport, dx, dy, content, container, limits = zoomLimits()) {
79
+ return clampViewport({ zoom: viewport.zoom, x: viewport.x + dx, y: viewport.y + dy }, content, container, limits);
80
+ }
81
+ /**
82
+ * Pans just far enough to bring `rect` inside the container, with a margin.
83
+ *
84
+ * `rect` is where the thing is on screen *now*, in container coordinates — a
85
+ * seat's bounding box minus the container's. Measuring the result of the
86
+ * current transform, rather than computing a position from the layout, is what
87
+ * keeps this correct whatever the section widths and unit scale are. A rect
88
+ * bigger than the container is aligned by its leading edge.
89
+ */
90
+ export function revealRect(viewport, rect, content, container, margin = REVEAL_MARGIN, limits = zoomLimits()) {
91
+ const dx = revealAxis(rect.x, rect.width, container.width, margin);
92
+ const dy = revealAxis(rect.y, rect.height, container.height, margin);
93
+ return panViewportBy(viewport, dx, dy, content, container, limits);
94
+ }
95
+ /**
96
+ * The zoom factor a wheel event asks for, or `null` if it is not a zoom
97
+ * gesture.
98
+ *
99
+ * Only Ctrl/Cmd + wheel zooms. Browsers report a trackpad pinch as a wheel
100
+ * event with `ctrlKey` set, so one rule covers both. A plain wheel returns
101
+ * `null`, which is the cue for a binding to leave it alone so the page still
102
+ * scrolls — and only a non-null result should be `preventDefault`ed.
103
+ */
104
+ export function wheelZoomFactor(event) {
105
+ if (!event.ctrlKey && !event.metaKey) {
106
+ return null;
107
+ }
108
+ // deltaMode: 0 pixels, 1 lines, 2 pages.
109
+ const unit = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? 100 : 1;
110
+ const delta = clamp(finiteOr(event.deltaY, 0) * unit, -WHEEL_MAX_DELTA, WHEEL_MAX_DELTA);
111
+ return Math.exp(-delta * WHEEL_ZOOM_SENSITIVITY);
112
+ }
113
+ /**
114
+ * What a key press does to the viewport, or `null` if it does nothing.
115
+ *
116
+ * `+` / `=` zoom in, `-` zoom out, `0` resets to fit, and — only when the
117
+ * viewport itself has focus — the arrow keys pan. Ctrl, Cmd and Alt
118
+ * combinations are the browser's own zoom shortcuts and are left alone.
119
+ */
120
+ export function keyboardViewport(viewport, input, content, container, limits = zoomLimits()) {
121
+ if (input.ctrlKey || input.metaKey || input.altKey) {
122
+ return null;
123
+ }
124
+ switch (input.key) {
125
+ case '+':
126
+ case '=':
127
+ return stepViewport(viewport, 1, content, container, limits);
128
+ case '-':
129
+ case '_':
130
+ return stepViewport(viewport, -1, content, container, limits);
131
+ case '0':
132
+ return fitViewport(content, container, limits);
133
+ }
134
+ if (!input.viewportFocused) {
135
+ return null;
136
+ }
137
+ // The arrow names the direction the *view* moves, so the map moves the other way.
138
+ switch (input.key) {
139
+ case 'ArrowLeft':
140
+ return panViewportBy(viewport, KEYBOARD_PAN_STEP, 0, content, container, limits);
141
+ case 'ArrowRight':
142
+ return panViewportBy(viewport, -KEYBOARD_PAN_STEP, 0, content, container, limits);
143
+ case 'ArrowUp':
144
+ return panViewportBy(viewport, 0, KEYBOARD_PAN_STEP, content, container, limits);
145
+ case 'ArrowDown':
146
+ return panViewportBy(viewport, 0, -KEYBOARD_PAN_STEP, content, container, limits);
147
+ default:
148
+ return null;
149
+ }
150
+ }
151
+ /**
152
+ * Whether a key event came from somewhere text is typed.
153
+ *
154
+ * A host can put its own controls inside the map, and `+`, `-` and `0` are
155
+ * characters before they are shortcuts. Takes the target structurally so core
156
+ * never has to name a DOM type.
157
+ */
158
+ export function isTextEntryTarget(target) {
159
+ if (!target) {
160
+ return false;
161
+ }
162
+ const tag = target.tagName?.toUpperCase();
163
+ return (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || target.isContentEditable === true);
164
+ }
165
+ /** Whether two viewports are the same view, ignoring sub-pixel noise. */
166
+ export function viewportsEqual(a, b) {
167
+ return (Math.abs(a.zoom - b.zoom) < 1e-4 && Math.abs(a.x - b.x) < 1e-2 && Math.abs(a.y - b.y) < 1e-2);
168
+ }
169
+ /** The CSS `transform` for a viewport. Apply with `transform-origin: 0 0`. */
170
+ export function viewportTransform(viewport) {
171
+ return `translate(${round(viewport.x)}px, ${round(viewport.y)}px) scale(${round(viewport.zoom)})`;
172
+ }
173
+ /**
174
+ * The `touch-action` a zoomable map sets on its viewport.
175
+ *
176
+ * At fit there is nothing to pan, so a one-finger vertical swipe stays the
177
+ * page's: `pan-y` leaves vertical scrolling to the browser while still handing
178
+ * us pinch. Once zoomed in, one finger means pan, and a maximized map covers
179
+ * the page, so both take every gesture with `none`.
180
+ */
181
+ export function viewportTouchAction(viewport, maximized) {
182
+ return maximized || viewport.zoom > 1 + 1e-4 ? 'none' : 'pan-y';
183
+ }
184
+ // --- internals ------------------------------------------------------------
185
+ function clamp(value, min, max) {
186
+ return Math.min(max, Math.max(min, value));
187
+ }
188
+ function finiteOr(value, fallback) {
189
+ return Number.isFinite(value) ? value : fallback;
190
+ }
191
+ /** Holds a translation so a scaled span covers the container, or centres it if smaller. */
192
+ function clampAxis(offset, scaled, container) {
193
+ if (scaled <= container) {
194
+ return (container - scaled) / 2;
195
+ }
196
+ return clamp(offset, container - scaled, 0);
197
+ }
198
+ /** How far to shift a span of `size` at `start` to sit inside `[margin, container - margin]`. */
199
+ function revealAxis(start, size, container, margin) {
200
+ const edge = Math.min(Math.max(0, margin), container / 2);
201
+ const low = edge;
202
+ const high = container - edge;
203
+ if (size >= high - low) {
204
+ return low - start;
205
+ }
206
+ if (start < low) {
207
+ return low - start;
208
+ }
209
+ if (start + size > high) {
210
+ return high - (start + size);
211
+ }
212
+ return 0;
213
+ }
214
+ /** Trims float noise out of a CSS number, and `-0` out of a translation. */
215
+ function round(value) {
216
+ return Math.round(value * 1000) / 1000 + 0;
217
+ }
218
+ //# sourceMappingURL=viewport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport.js","sourceRoot":"","sources":["../../src/view/viewport.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerusiweb/core",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Framework-agnostic core for the Kerusi Seat Map & Availability Format: document types, a conformance validator, and the render model and geometry a seat-map renderer consumes.",
5
5
  "keywords": [
6
6
  "kerusi",