@fusion.dev/helix-headless 0.103.2 → 0.103.3
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/custom-elements.json +254 -80
- package/dist/map/root/map-root.d.ts +15 -126
- package/dist/map/root/map-root.js +6 -140
- package/package.json +5 -5
- package/types/jsx.d.ts +226 -252
- package/types/vue.d.ts +67 -75
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { HelixElement } from '@fusion.dev/helix-core';
|
|
1
|
+
import { HelixElement, type ViewportControlsPlacement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
/**
|
|
4
|
+
* What `ViewportControlsPlacement` is called for a map.
|
|
5
|
+
*
|
|
6
|
+
* The corners are the surface's and the name is the family's, so a consumer who
|
|
7
|
+
* imported this before the surface was shared still has it.
|
|
8
|
+
*/
|
|
9
|
+
export type MapControlsPlacement = ViewportControlsPlacement;
|
|
10
|
+
declare const HelixHeadlessMap_base: (new (...args: any[]) => import("@fusion.dev/helix-core").ViewportElement) & typeof HelixElement;
|
|
7
11
|
/**
|
|
8
12
|
* @summary A frame around somebody else's map.
|
|
9
13
|
*
|
|
@@ -63,57 +67,7 @@ export type MapControlsPlacement = 'top-start' | 'top-end' | 'bottom-start' | 'b
|
|
|
63
67
|
* @cssstate fullscreen - While the frame fills the screen.
|
|
64
68
|
* @cssstate idle - While the reader has been still long enough to hide the chrome.
|
|
65
69
|
*/
|
|
66
|
-
export declare class HelixHeadlessMap extends
|
|
67
|
-
/**
|
|
68
|
-
* Which of the controls this frame draws, as a list of what to keep.
|
|
69
|
-
*
|
|
70
|
-
* **A list rather than a switch, because the overlap is not symmetric.**
|
|
71
|
-
* Every map library draws zoom controls and none of them draws pan buttons:
|
|
72
|
-
* MapLibre's navigation control is zoom and a compass, Leaflet's is zoom,
|
|
73
|
-
* Google's is zoom. So a consumer slotting one of those has our zoom twice
|
|
74
|
-
* over and our pan pad not at all, and a single switch would make them choose
|
|
75
|
-
* between a duplicate and nothing.
|
|
76
|
-
*
|
|
77
|
-
* `none` draws none of them, which is the right answer where the slotted map
|
|
78
|
-
* already has controls a reader can find: what this family argues for is that
|
|
79
|
-
* *a* findable control exists, never that it is ours. The methods stay public
|
|
80
|
-
* either way, so a consumer drawing their own chrome can still drive the
|
|
81
|
-
* frame.
|
|
82
|
-
*
|
|
83
|
-
* Absent is all three, which is this library's rule that a resting value is an
|
|
84
|
-
* attribute's absence, and it is what the stylesheet asks about: the layout
|
|
85
|
-
* rules are written against `[controls]:not([controls~="zoom"])` rather than
|
|
86
|
-
* the bare negation, or a frame that named no list at all would be laid out as
|
|
87
|
-
* though it had dropped everything.
|
|
88
|
-
*/
|
|
89
|
-
controls?: string;
|
|
90
|
-
/**
|
|
91
|
-
* Which corner the controls sit in.
|
|
92
|
-
*
|
|
93
|
-
* **Configurable because there is no safe default**, and this is a collision
|
|
94
|
-
* rather than a taste: MapLibre puts its own controls at the top end, Leaflet
|
|
95
|
-
* and OpenLayers at the top start, Google's zoom at the bottom end. Whichever
|
|
96
|
-
* corner this took would land on somebody's, which is why every one of those
|
|
97
|
-
* libraries made it a setting too.
|
|
98
|
-
*
|
|
99
|
-
* Logical corners rather than left and right, so a right-to-left page moves
|
|
100
|
-
* them without a consumer writing a second rule.
|
|
101
|
-
*
|
|
102
|
-
* Absent is the top end, which is this library's rule that a resting value is
|
|
103
|
-
* an attribute's absence: a default that reflected would write an attribute
|
|
104
|
-
* onto every host that no server sent and nobody asked for.
|
|
105
|
-
*/
|
|
106
|
-
controlsPlacement?: MapControlsPlacement;
|
|
107
|
-
/** What the control that fills the screen is called. */
|
|
108
|
-
fullscreenLabel: string;
|
|
109
|
-
/**
|
|
110
|
-
* How long the reader may be still before the chrome hides, in milliseconds.
|
|
111
|
-
*
|
|
112
|
-
* Zero keeps it up, which is the default: a map's controls are how a keyboard
|
|
113
|
-
* reader operates it, and chrome that hides itself by default would be this
|
|
114
|
-
* component undoing its own argument. Set it for a display map nobody drives.
|
|
115
|
-
*/
|
|
116
|
-
idleDelay: number;
|
|
70
|
+
export declare class HelixHeadlessMap extends HelixHeadlessMap_base {
|
|
117
71
|
/**
|
|
118
72
|
* Accessible name for the map, which is the one thing a consumer must write.
|
|
119
73
|
*
|
|
@@ -130,79 +84,14 @@ export declare class HelixHeadlessMap extends HelixElement {
|
|
|
130
84
|
*/
|
|
131
85
|
label: string;
|
|
132
86
|
/**
|
|
133
|
-
* What the controls
|
|
134
|
-
*/
|
|
135
|
-
panLabel: string;
|
|
136
|
-
/**
|
|
137
|
-
* How far one press moves the map, as a fraction of what is on screen.
|
|
138
|
-
*
|
|
139
|
-
* A fraction rather than a distance, because this frame does not know the
|
|
140
|
-
* scale of what is inside it: a quarter of the viewport is the same gesture at
|
|
141
|
-
* street level and at country level, and a consumer who wants metres can
|
|
142
|
-
* multiply by their own.
|
|
143
|
-
*/
|
|
144
|
-
panStep: number;
|
|
145
|
-
/** What the zoom controls are called. */
|
|
146
|
-
zoomInLabel: string;
|
|
147
|
-
/** What the zoom control that goes the other way is called. */
|
|
148
|
-
zoomOutLabel: string;
|
|
149
|
-
/** Whether the reader has been still long enough to hide the chrome. */
|
|
150
|
-
private resting;
|
|
151
|
-
/** Whether the frame is filling the screen. */
|
|
152
|
-
private filled;
|
|
153
|
-
private readonly fullscreen;
|
|
154
|
-
private readonly idle;
|
|
155
|
-
/** Whether a named group of controls is one this frame draws. */
|
|
156
|
-
private draws;
|
|
157
|
-
/** Fills the screen with the frame, or comes back. */
|
|
158
|
-
toggleFullscreen(): void;
|
|
159
|
-
/** Asks for the map to move, which the consumer answers. */
|
|
160
|
-
pan(to: Way): void;
|
|
161
|
-
/** Asks for the map to zoom, `1` in and `-1` out. */
|
|
162
|
-
zoom(by: number): void;
|
|
163
|
-
/**
|
|
164
|
-
* The arrow keys, which are the second way rather than the only one.
|
|
165
|
-
*
|
|
166
|
-
* `inlineStep` rather than a test against `ArrowLeft`, so the reader on a
|
|
167
|
-
* right-to-left page gets `end` from the key that points the way their text
|
|
168
|
-
* runs, which is what the pan buttons say too.
|
|
87
|
+
* What the group of controls is called.
|
|
169
88
|
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* the event this would have sent: every press moving twice, and the consumer
|
|
174
|
-
* with no way to tell which half to turn off. A press that started in the
|
|
175
|
-
* shadow root is this frame's to relay; anything from the map belongs to the
|
|
176
|
-
* map.
|
|
89
|
+
* The surface is shared and this is the half that is a map: a reader meeting
|
|
90
|
+
* the group hears what it drives rather than "view controls", which names the
|
|
91
|
+
* mechanism.
|
|
177
92
|
*/
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Starts the wait, so a map nobody has touched counts as still.
|
|
181
|
-
*
|
|
182
|
-
* Without this the timer only ever starts on a pointer or a focus, and a frame
|
|
183
|
-
* rendered on a page the reader never reaches stays awake for as long as the
|
|
184
|
-
* page is open: the chrome a consumer asked to hide would hide only after
|
|
185
|
-
* being used once, which is the opposite of what an idle delay is for.
|
|
186
|
-
*/
|
|
187
|
-
protected firstUpdated(changed: PropertyValues): void;
|
|
93
|
+
protected get controlsLabel(): string;
|
|
188
94
|
protected willUpdate(changed: PropertyValues): void;
|
|
189
|
-
/**
|
|
190
|
-
* What one pan button is called, with the way it goes filled in.
|
|
191
|
-
*
|
|
192
|
-
* Left and right rather than start and end, because the label is read aloud
|
|
193
|
-
* and a reader knows which way left is. The event keeps the reading-order
|
|
194
|
-
* name, which is the one a right-to-left page needs.
|
|
195
|
-
*/
|
|
196
|
-
private named;
|
|
197
|
-
/**
|
|
198
|
-
* The controls, or nothing where a consumer kept none of them.
|
|
199
|
-
*
|
|
200
|
-
* **Written out rather than generated**, because a part name behind an
|
|
201
|
-
* interpolation is a part the manifest cannot see: it would publish `pan-`
|
|
202
|
-
* and a consumer's `::part(pan-up)` would match nothing. The same cost
|
|
203
|
-
* `drawIcon` names for `Trend`.
|
|
204
|
-
*/
|
|
205
|
-
private renderControls;
|
|
206
95
|
/**
|
|
207
96
|
* The frame, with each region in a box of its own.
|
|
208
97
|
*
|
|
@@ -4,73 +4,16 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement,
|
|
8
|
-
import { html
|
|
9
|
-
import { property
|
|
10
|
-
let HelixHeadlessMap = class HelixHeadlessMap extends HelixElement {
|
|
7
|
+
import { customElement, HelixElement, hostAria, MixinViewport, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html } from 'lit';
|
|
9
|
+
import { property } from 'lit/decorators.js';
|
|
10
|
+
let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement) {
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
|
-
this.fullscreenLabel = 'Fill the screen';
|
|
14
|
-
this.idleDelay = 0;
|
|
15
13
|
this.label = '';
|
|
16
|
-
this.panLabel = 'Pan {way}';
|
|
17
|
-
this.panStep = 0.25;
|
|
18
|
-
this.zoomInLabel = 'Zoom in';
|
|
19
|
-
this.zoomOutLabel = 'Zoom out';
|
|
20
|
-
this.resting = false;
|
|
21
|
-
this.filled = false;
|
|
22
|
-
this.fullscreen = new FullscreenController(this, (full) => {
|
|
23
|
-
this.filled = full;
|
|
24
|
-
});
|
|
25
|
-
this.idle = new IdleController(this, () => this.idleDelay, (resting) => {
|
|
26
|
-
this.resting = resting;
|
|
27
|
-
});
|
|
28
|
-
this.handleKeydown = (event) => {
|
|
29
|
-
if (!this.renderRoot.contains(event.target)) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
const along = inlineStep(this, event.key);
|
|
33
|
-
if (along === 1) {
|
|
34
|
-
event.preventDefault();
|
|
35
|
-
this.pan('end');
|
|
36
|
-
}
|
|
37
|
-
else if (along === -1) {
|
|
38
|
-
event.preventDefault();
|
|
39
|
-
this.pan('start');
|
|
40
|
-
}
|
|
41
|
-
else if (event.key === 'ArrowUp') {
|
|
42
|
-
event.preventDefault();
|
|
43
|
-
this.pan('up');
|
|
44
|
-
}
|
|
45
|
-
else if (event.key === 'ArrowDown') {
|
|
46
|
-
event.preventDefault();
|
|
47
|
-
this.pan('down');
|
|
48
|
-
}
|
|
49
|
-
else if (event.key === '+' || event.key === '=') {
|
|
50
|
-
event.preventDefault();
|
|
51
|
-
this.zoom(1);
|
|
52
|
-
}
|
|
53
|
-
else if (event.key === '-' || event.key === '_') {
|
|
54
|
-
event.preventDefault();
|
|
55
|
-
this.zoom(-1);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
14
|
}
|
|
59
|
-
|
|
60
|
-
return
|
|
61
|
-
}
|
|
62
|
-
toggleFullscreen() {
|
|
63
|
-
void this.fullscreen.toggle();
|
|
64
|
-
}
|
|
65
|
-
pan(to) {
|
|
66
|
-
this.dispatchEvent(new HelixMapPanEvent({ by: this.panStep, to }));
|
|
67
|
-
}
|
|
68
|
-
zoom(by) {
|
|
69
|
-
this.dispatchEvent(new HelixMapZoomEvent({ by }));
|
|
70
|
-
}
|
|
71
|
-
firstUpdated(changed) {
|
|
72
|
-
super.firstUpdated(changed);
|
|
73
|
-
this.idle.stir();
|
|
15
|
+
get controlsLabel() {
|
|
16
|
+
return 'Map controls';
|
|
74
17
|
}
|
|
75
18
|
willUpdate(changed) {
|
|
76
19
|
super.willUpdate(changed);
|
|
@@ -78,53 +21,6 @@ let HelixHeadlessMap = class HelixHeadlessMap extends HelixElement {
|
|
|
78
21
|
this.toggleState('fullscreen', this.filled);
|
|
79
22
|
this.toggleState('idle', this.resting);
|
|
80
23
|
}
|
|
81
|
-
named(way) {
|
|
82
|
-
const spoken = way === 'start' ? 'left' : way === 'end' ? 'right' : way;
|
|
83
|
-
return this.panLabel.replace('{way}', spoken);
|
|
84
|
-
}
|
|
85
|
-
renderControls() {
|
|
86
|
-
const pan = this.draws('pan');
|
|
87
|
-
const zoom = this.draws('zoom');
|
|
88
|
-
const fullscreen = this.draws('fullscreen');
|
|
89
|
-
if (!pan && !zoom && !fullscreen) {
|
|
90
|
-
return nothing;
|
|
91
|
-
}
|
|
92
|
-
return html `<div part="controls" role="group" aria-label="Map controls">
|
|
93
|
-
${pan
|
|
94
|
-
? html `<button part="pan-up" aria-label=${this.named('up')} type="button" @click=${() => this.pan('up')}>
|
|
95
|
-
↑
|
|
96
|
-
</button>
|
|
97
|
-
<button part="pan-start" aria-label=${this.named('start')} type="button" @click=${() => this.pan('start')}>
|
|
98
|
-
←
|
|
99
|
-
</button>
|
|
100
|
-
<button part="pan-end" aria-label=${this.named('end')} type="button" @click=${() => this.pan('end')}>
|
|
101
|
-
→
|
|
102
|
-
</button>
|
|
103
|
-
<button part="pan-down" aria-label=${this.named('down')} type="button" @click=${() => this.pan('down')}>
|
|
104
|
-
↓
|
|
105
|
-
</button>`
|
|
106
|
-
: nothing}
|
|
107
|
-
${zoom
|
|
108
|
-
? html `<button part="zoom-in" aria-label=${this.zoomInLabel} type="button" @click=${() => this.zoom(1)}>
|
|
109
|
-
+
|
|
110
|
-
</button>
|
|
111
|
-
<button part="zoom-out" aria-label=${this.zoomOutLabel} type="button" @click=${() => this.zoom(-1)}>
|
|
112
|
-
−
|
|
113
|
-
</button>`
|
|
114
|
-
: nothing}
|
|
115
|
-
${fullscreen
|
|
116
|
-
? html `<button
|
|
117
|
-
part="fullscreen"
|
|
118
|
-
aria-label=${this.fullscreenLabel}
|
|
119
|
-
aria-pressed=${this.filled ? 'true' : 'false'}
|
|
120
|
-
type="button"
|
|
121
|
-
@click=${this.toggleFullscreen}
|
|
122
|
-
>
|
|
123
|
-
⤢
|
|
124
|
-
</button>`
|
|
125
|
-
: nothing}
|
|
126
|
-
</div>`;
|
|
127
|
-
}
|
|
128
24
|
render() {
|
|
129
25
|
return html `<div
|
|
130
26
|
part="region"
|
|
@@ -153,39 +49,9 @@ let HelixHeadlessMap = class HelixHeadlessMap extends HelixElement {
|
|
|
153
49
|
</div>`;
|
|
154
50
|
}
|
|
155
51
|
};
|
|
156
|
-
__decorate([
|
|
157
|
-
property({ reflect: true })
|
|
158
|
-
], HelixHeadlessMap.prototype, "controls", void 0);
|
|
159
|
-
__decorate([
|
|
160
|
-
property({ attribute: 'controls-placement', reflect: true })
|
|
161
|
-
], HelixHeadlessMap.prototype, "controlsPlacement", void 0);
|
|
162
|
-
__decorate([
|
|
163
|
-
property({ attribute: 'fullscreen-label' })
|
|
164
|
-
], HelixHeadlessMap.prototype, "fullscreenLabel", void 0);
|
|
165
|
-
__decorate([
|
|
166
|
-
property({ attribute: 'idle-delay', type: Number })
|
|
167
|
-
], HelixHeadlessMap.prototype, "idleDelay", void 0);
|
|
168
52
|
__decorate([
|
|
169
53
|
property()
|
|
170
54
|
], HelixHeadlessMap.prototype, "label", void 0);
|
|
171
|
-
__decorate([
|
|
172
|
-
property({ attribute: 'pan-label' })
|
|
173
|
-
], HelixHeadlessMap.prototype, "panLabel", void 0);
|
|
174
|
-
__decorate([
|
|
175
|
-
property({ attribute: 'pan-step', type: Number })
|
|
176
|
-
], HelixHeadlessMap.prototype, "panStep", void 0);
|
|
177
|
-
__decorate([
|
|
178
|
-
property({ attribute: 'zoom-in-label' })
|
|
179
|
-
], HelixHeadlessMap.prototype, "zoomInLabel", void 0);
|
|
180
|
-
__decorate([
|
|
181
|
-
property({ attribute: 'zoom-out-label' })
|
|
182
|
-
], HelixHeadlessMap.prototype, "zoomOutLabel", void 0);
|
|
183
|
-
__decorate([
|
|
184
|
-
state()
|
|
185
|
-
], HelixHeadlessMap.prototype, "resting", void 0);
|
|
186
|
-
__decorate([
|
|
187
|
-
state()
|
|
188
|
-
], HelixHeadlessMap.prototype, "filled", void 0);
|
|
189
55
|
HelixHeadlessMap = __decorate([
|
|
190
56
|
customElement('helix-headless-map')
|
|
191
57
|
], HelixHeadlessMap);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-headless",
|
|
3
3
|
"description": "Headless component tier. Structure, accessibility, state, and form participation. No styling.",
|
|
4
|
-
"version": "0.103.
|
|
4
|
+
"version": "0.103.3",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
},
|
|
47
47
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@fusion.dev/helix-core": "0.103.
|
|
50
|
-
"@fusion.dev/helix-icons": "0.103.
|
|
49
|
+
"@fusion.dev/helix-core": "0.103.3",
|
|
50
|
+
"@fusion.dev/helix-icons": "0.103.3",
|
|
51
51
|
"uqr": "^0.1.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@fusion.dev/helix-cem": "0.103.
|
|
55
|
-
"@fusion.dev/helix-testing": "0.103.
|
|
54
|
+
"@fusion.dev/helix-cem": "0.103.3",
|
|
55
|
+
"@fusion.dev/helix-testing": "0.103.3",
|
|
56
56
|
"@fusion.dev/scripts": "0.0.0-dev",
|
|
57
57
|
"@happy-dom/global-registrator": "^20.0.0",
|
|
58
58
|
"@lit-labs/ssr": "^4.1.0",
|