@fusion.dev/helix-headless 0.109.3 → 0.110.1
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 +553 -2
- package/dist/button/root/button-root.d.ts +10 -0
- package/dist/button/root/button-root.js +4 -0
- package/dist/color-picker/root/color-picker-root.js +4 -0
- package/dist/data-table/root/data-table-root.d.ts +32 -0
- package/dist/data-table/root/data-table-root.js +49 -1
- package/dist/map/root/map-root.d.ts +57 -0
- package/dist/map/root/map-root.js +97 -1
- package/dist/menu/root/menu-root.js +1 -1
- package/dist/select/root/select-root.d.ts +14 -0
- package/dist/select/root/select-root.js +8 -1
- package/dist/time-picker/root/time-picker-root.js +2 -0
- package/package.json +5 -5
- package/types/jsx.d.ts +298 -0
- package/types/vue.d.ts +94 -0
|
@@ -142,6 +142,16 @@ export declare class HelixHeadlessButton extends HelixFormElement {
|
|
|
142
142
|
* "button" and nothing else.
|
|
143
143
|
*/
|
|
144
144
|
label: string;
|
|
145
|
+
/**
|
|
146
|
+
* What kind of panel this button opens, where it opens one: `menu` for a
|
|
147
|
+
* `Menu`.
|
|
148
|
+
*
|
|
149
|
+
* Set by the component that owns the panel, as a property for the reason
|
|
150
|
+
* `expanded` gives above. It is what makes a reader say the button opens a
|
|
151
|
+
* menu. Read from Chromium's tree, a Menu's trigger was a plain button that
|
|
152
|
+
* reported collapsed and expanded and no popup.
|
|
153
|
+
*/
|
|
154
|
+
popup?: 'dialog' | 'grid' | 'listbox' | 'menu' | 'tree';
|
|
145
155
|
/** Moves focus to the inner control, so the host is never the focus target. */
|
|
146
156
|
static shadowRootOptions: ShadowRootInit;
|
|
147
157
|
private readonly handleClick;
|
|
@@ -123,6 +123,7 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
|
|
|
123
123
|
part="button"
|
|
124
124
|
type="button"
|
|
125
125
|
aria-expanded=${this.expanded === undefined ? nothing : String(this.expanded)}
|
|
126
|
+
aria-haspopup=${this.popup ?? nothing}
|
|
126
127
|
aria-label=${this.label || nothing}
|
|
127
128
|
command=${this.command || nothing}
|
|
128
129
|
tabindex=${stop}
|
|
@@ -163,6 +164,9 @@ __decorate([
|
|
|
163
164
|
__decorate([
|
|
164
165
|
property()
|
|
165
166
|
], HelixHeadlessButton.prototype, "label", void 0);
|
|
167
|
+
__decorate([
|
|
168
|
+
property({ attribute: false })
|
|
169
|
+
], HelixHeadlessButton.prototype, "popup", void 0);
|
|
166
170
|
__decorate([
|
|
167
171
|
property()
|
|
168
172
|
], HelixHeadlessButton.prototype, "type", void 0);
|
|
@@ -175,6 +175,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
175
175
|
hint: channel-hint, label: channel-label, marker: channel-marker,
|
|
176
176
|
marker-label: channel-marker-label, markers: channel-markers, output: channel-output"
|
|
177
177
|
data-channel=${channel}
|
|
178
|
+
aria-invalid=${this.invalid ? 'true' : nothing}
|
|
178
179
|
label=${label}
|
|
179
180
|
max=${max}
|
|
180
181
|
min="0"
|
|
@@ -254,6 +255,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
254
255
|
min="0"
|
|
255
256
|
max="100"
|
|
256
257
|
aria-label=${this.saturationLabel}
|
|
258
|
+
aria-invalid=${this.invalid ? 'true' : nothing}
|
|
257
259
|
.value=${String(color.saturation)}
|
|
258
260
|
?disabled=${this.isDisabled}
|
|
259
261
|
@input=${(event) => this.takeArea('saturation', event)}
|
|
@@ -264,6 +266,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
264
266
|
min="0"
|
|
265
267
|
max="100"
|
|
266
268
|
aria-label=${this.brightnessLabel}
|
|
269
|
+
aria-invalid=${this.invalid ? 'true' : nothing}
|
|
267
270
|
.value=${String(color.brightness)}
|
|
268
271
|
?disabled=${this.isDisabled}
|
|
269
272
|
@input=${(event) => this.takeArea('brightness', event)}
|
|
@@ -298,6 +301,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinContr
|
|
|
298
301
|
part="value"
|
|
299
302
|
type="text"
|
|
300
303
|
aria-label=${this.valueLabel}
|
|
304
|
+
aria-invalid=${this.invalid ? 'true' : nothing}
|
|
301
305
|
autocomplete=${this.autocomplete || nothing}
|
|
302
306
|
spellcheck="false"
|
|
303
307
|
.value=${this.value}
|
|
@@ -127,6 +127,8 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
127
127
|
* same reason.
|
|
128
128
|
*/
|
|
129
129
|
static shadowRootOptions: ShadowRootInit;
|
|
130
|
+
/** The word for an ascending sort, in `sorted-label`. */
|
|
131
|
+
ascendingLabel: string;
|
|
130
132
|
/**
|
|
131
133
|
* The starting search query, used until `filter` is set.
|
|
132
134
|
*/
|
|
@@ -152,6 +154,8 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
152
154
|
* The starting sort order, used until `sort` is set.
|
|
153
155
|
*/
|
|
154
156
|
defaultSort: string;
|
|
157
|
+
/** The word for a descending sort, in `sorted-label`. */
|
|
158
|
+
descendingLabel: string;
|
|
155
159
|
/**
|
|
156
160
|
* The estimated height of a row before it is drawn, in pixels.
|
|
157
161
|
*
|
|
@@ -280,6 +284,11 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
280
284
|
*/
|
|
281
285
|
get selected(): string;
|
|
282
286
|
set selected(next: string);
|
|
287
|
+
/**
|
|
288
|
+
* What screen readers hear when the chosen rows change. `{count}` is how many
|
|
289
|
+
* rows are chosen.
|
|
290
|
+
*/
|
|
291
|
+
selectedLabel: string;
|
|
283
292
|
/**
|
|
284
293
|
* The sort order, as `field:direction`.
|
|
285
294
|
*
|
|
@@ -289,6 +298,11 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
289
298
|
*/
|
|
290
299
|
get sort(): string;
|
|
291
300
|
set sort(next: string);
|
|
301
|
+
/**
|
|
302
|
+
* What screen readers hear when the table is sorted. `{column}` is the
|
|
303
|
+
* column's heading and `{order}` is `ascending-label` or `descending-label`.
|
|
304
|
+
*/
|
|
305
|
+
sortedLabel: string;
|
|
292
306
|
/**
|
|
293
307
|
* The number of rows in the whole result, for when the table cannot count
|
|
294
308
|
* them.
|
|
@@ -299,6 +313,8 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
299
313
|
* one that cannot be stale.
|
|
300
314
|
*/
|
|
301
315
|
total: number;
|
|
316
|
+
/** What screen readers hear when the table stops being sorted. */
|
|
317
|
+
unsortedLabel: string;
|
|
302
318
|
/**
|
|
303
319
|
* Draws only the rows in view, with empty space in place of the rest.
|
|
304
320
|
*
|
|
@@ -582,6 +598,22 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
582
598
|
* Manual assignment, so a consumer's own markup is never written to.
|
|
583
599
|
*/
|
|
584
600
|
private assign;
|
|
601
|
+
/** The sort last heard, so a render that changed nothing says nothing. */
|
|
602
|
+
private heardSort;
|
|
603
|
+
/** The selection last heard, for the same reason. */
|
|
604
|
+
private heardSelected;
|
|
605
|
+
/**
|
|
606
|
+
* What the table says after a sort or a change to the chosen rows.
|
|
607
|
+
*
|
|
608
|
+
* **The state changed and nothing said so.** A sort moved `aria-sort` on the
|
|
609
|
+
* heading, and a reader on the heading's button is not told its column's
|
|
610
|
+
* state changed; a chosen row ticked one box, and nothing gave the count. So
|
|
611
|
+
* each is said in the collection's live region, once, after it has happened.
|
|
612
|
+
* Whoever set it, a reader or a consumer answering `helix-sort`, since either
|
|
613
|
+
* way the rows under the reader have moved. Not on the first render, which
|
|
614
|
+
* is the table arriving rather than anything changing.
|
|
615
|
+
*/
|
|
616
|
+
private news;
|
|
585
617
|
protected willUpdate(changed: PropertyValues): void;
|
|
586
618
|
/**
|
|
587
619
|
* Says on the toolbar and the footer whether anything is in them.
|
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
var HelixHeadlessDataTable_1;
|
|
8
|
-
import { customElement, HelixElement, HelixFilterEvent, HelixNavigateEvent, HelixReorderEvent, HelixSelectEvent, HelixSortEvent, hostAria, inlineStep, isRtl, MixinCollection, markRegion, requestChange, VirtualizeController, writtenList, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { customElement, fillTemplate, formatNumbers, HelixElement, HelixFilterEvent, HelixNavigateEvent, HelixReorderEvent, HelixSelectEvent, HelixSortEvent, hostAria, inlineStep, isRtl, MixinCollection, markRegion, requestChange, VirtualizeController, writtenList, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { repeat } from 'lit/directives/repeat.js';
|
|
@@ -17,12 +17,14 @@ import { arranged, cycle, format, ordered, parse, window_, } from './order.js';
|
|
|
17
17
|
let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollection(HelixElement) {
|
|
18
18
|
constructor() {
|
|
19
19
|
super(...arguments);
|
|
20
|
+
this.ascendingLabel = 'ascending';
|
|
20
21
|
this.defaultFilter = '';
|
|
21
22
|
this.defaultOrder = '';
|
|
22
23
|
this.defaultPage = 1;
|
|
23
24
|
this.defaultPageSize = 0;
|
|
24
25
|
this.defaultSelected = '';
|
|
25
26
|
this.defaultSort = '';
|
|
27
|
+
this.descendingLabel = 'descending';
|
|
26
28
|
this.estimate = 32;
|
|
27
29
|
this.label = '';
|
|
28
30
|
this.mode = 'client';
|
|
@@ -30,7 +32,10 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
30
32
|
this.rowKey = '';
|
|
31
33
|
this.rows = [];
|
|
32
34
|
this.selectable = false;
|
|
35
|
+
this.selectedLabel = '{count} selected';
|
|
36
|
+
this.sortedLabel = 'Sorted by {column}, {order}';
|
|
33
37
|
this.total = 0;
|
|
38
|
+
this.unsortedLabel = 'Not sorted';
|
|
34
39
|
this.windowed = false;
|
|
35
40
|
this.sortState = undefined;
|
|
36
41
|
this.filterState = undefined;
|
|
@@ -76,6 +81,8 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
76
81
|
}
|
|
77
82
|
this.requestSelected(keys);
|
|
78
83
|
};
|
|
84
|
+
this.heardSort = undefined;
|
|
85
|
+
this.heardSelected = undefined;
|
|
79
86
|
this.handleSlotChange = () => {
|
|
80
87
|
this.requestUpdate();
|
|
81
88
|
};
|
|
@@ -508,8 +515,34 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
508
515
|
}
|
|
509
516
|
}
|
|
510
517
|
}
|
|
518
|
+
news() {
|
|
519
|
+
const sort = this.sort;
|
|
520
|
+
const selected = this.selectable ? this.selected : '';
|
|
521
|
+
let said = this.announced;
|
|
522
|
+
if (this.hasUpdated && sort !== this.heardSort) {
|
|
523
|
+
const parsed = parse(sort);
|
|
524
|
+
const column = parsed
|
|
525
|
+
? this.tableColumns.find((one) => one.field === parsed.field)
|
|
526
|
+
: undefined;
|
|
527
|
+
said = parsed
|
|
528
|
+
? fillTemplate(this.sortedLabel, {
|
|
529
|
+
column: column?.textContent?.trim() || parsed.field,
|
|
530
|
+
order: parsed.direction === 'asc' ? this.ascendingLabel : this.descendingLabel,
|
|
531
|
+
})
|
|
532
|
+
: this.unsortedLabel;
|
|
533
|
+
}
|
|
534
|
+
else if (this.hasUpdated && selected !== this.heardSelected) {
|
|
535
|
+
said = fillTemplate(this.selectedLabel, {
|
|
536
|
+
count: formatNumbers(this.lang)(this.chosen.size),
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
this.heardSort = sort;
|
|
540
|
+
this.heardSelected = selected;
|
|
541
|
+
return said;
|
|
542
|
+
}
|
|
511
543
|
willUpdate(changed) {
|
|
512
544
|
super.willUpdate(changed);
|
|
545
|
+
this.announced = this.news();
|
|
513
546
|
hostAria(this.internals, { label: this.label || 'Table', role: 'grid' });
|
|
514
547
|
this.internals.ariaMultiSelectable = this.selectable ? 'true' : null;
|
|
515
548
|
const placement = this.placement;
|
|
@@ -697,6 +730,9 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
697
730
|
return undefined;
|
|
698
731
|
}
|
|
699
732
|
};
|
|
733
|
+
__decorate([
|
|
734
|
+
property({ attribute: 'ascending-label' })
|
|
735
|
+
], HelixHeadlessDataTable.prototype, "ascendingLabel", void 0);
|
|
700
736
|
__decorate([
|
|
701
737
|
property({ attribute: 'default-filter' })
|
|
702
738
|
], HelixHeadlessDataTable.prototype, "defaultFilter", void 0);
|
|
@@ -715,6 +751,9 @@ __decorate([
|
|
|
715
751
|
__decorate([
|
|
716
752
|
property({ attribute: 'default-sort' })
|
|
717
753
|
], HelixHeadlessDataTable.prototype, "defaultSort", void 0);
|
|
754
|
+
__decorate([
|
|
755
|
+
property({ attribute: 'descending-label' })
|
|
756
|
+
], HelixHeadlessDataTable.prototype, "descendingLabel", void 0);
|
|
718
757
|
__decorate([
|
|
719
758
|
property({ type: Number })
|
|
720
759
|
], HelixHeadlessDataTable.prototype, "estimate", void 0);
|
|
@@ -754,12 +793,21 @@ __decorate([
|
|
|
754
793
|
__decorate([
|
|
755
794
|
property()
|
|
756
795
|
], HelixHeadlessDataTable.prototype, "selected", null);
|
|
796
|
+
__decorate([
|
|
797
|
+
property({ attribute: 'selected-label' })
|
|
798
|
+
], HelixHeadlessDataTable.prototype, "selectedLabel", void 0);
|
|
757
799
|
__decorate([
|
|
758
800
|
property()
|
|
759
801
|
], HelixHeadlessDataTable.prototype, "sort", null);
|
|
802
|
+
__decorate([
|
|
803
|
+
property({ attribute: 'sorted-label' })
|
|
804
|
+
], HelixHeadlessDataTable.prototype, "sortedLabel", void 0);
|
|
760
805
|
__decorate([
|
|
761
806
|
property({ type: Number })
|
|
762
807
|
], HelixHeadlessDataTable.prototype, "total", void 0);
|
|
808
|
+
__decorate([
|
|
809
|
+
property({ attribute: 'unsorted-label' })
|
|
810
|
+
], HelixHeadlessDataTable.prototype, "unsortedLabel", void 0);
|
|
763
811
|
__decorate([
|
|
764
812
|
property({ reflect: true, type: Boolean })
|
|
765
813
|
], HelixHeadlessDataTable.prototype, "windowed", void 0);
|
|
@@ -89,6 +89,7 @@ declare const HelixHeadlessMap_base: (new (...args: any[]) => import("@fusion.de
|
|
|
89
89
|
* @csspart layers - The list of the map's shown layers, such as routes, areas, and points, read by screen readers.
|
|
90
90
|
* @csspart layers-menu - The menu of the map's layers, which the layers button opens.
|
|
91
91
|
* @csspart layers-toggle - The button that opens and closes the layers menu.
|
|
92
|
+
* @csspart live - What screen readers hear after the map moves: the zoom level, the way it faces, its tilt, or the way it moved. Visually hidden in the styled tier.
|
|
92
93
|
* @csspart map-type - One map type's card in the layers menu: a radio button, its picture, and its name.
|
|
93
94
|
* @csspart map-type-name - The name on a map type's card.
|
|
94
95
|
* @csspart map-type-preview - The picture of the map on a map type's card.
|
|
@@ -124,6 +125,8 @@ export declare class HelixHeadlessMap extends HelixHeadlessMap_base {
|
|
|
124
125
|
cluster: boolean;
|
|
125
126
|
/** The Face north button's label. */
|
|
126
127
|
faceNorthLabel: string;
|
|
128
|
+
/** What screen readers hear when the map is tilted back to looking straight down. */
|
|
129
|
+
flatLabel: string;
|
|
127
130
|
/** The Hybrid map type's name. */
|
|
128
131
|
hybridLabel: string;
|
|
129
132
|
/**
|
|
@@ -149,6 +152,16 @@ export declare class HelixHeadlessMap extends HelixHeadlessMap_base {
|
|
|
149
152
|
mapType?: 'hybrid' | 'satellite' | undefined;
|
|
150
153
|
/** The name of the map types in the layers menu, read by screen readers. */
|
|
151
154
|
mapTypeLabel: string;
|
|
155
|
+
/** What screen readers hear when the map has moved down. */
|
|
156
|
+
movedDownLabel: string;
|
|
157
|
+
/** What screen readers hear when the map has moved left. */
|
|
158
|
+
movedLeftLabel: string;
|
|
159
|
+
/** What screen readers hear when the map has moved right. */
|
|
160
|
+
movedRightLabel: string;
|
|
161
|
+
/** What screen readers hear when the map has moved up. */
|
|
162
|
+
movedUpLabel: string;
|
|
163
|
+
/** What screen readers hear when the map is turned back to face north. */
|
|
164
|
+
northLabel: string;
|
|
152
165
|
/**
|
|
153
166
|
* How far the map is tilted, in degrees from looking straight down.
|
|
154
167
|
* `connectMap` keeps it current, and the 3D button is pressed while it is
|
|
@@ -163,8 +176,52 @@ export declare class HelixHeadlessMap extends HelixHeadlessMap_base {
|
|
|
163
176
|
satelliteLabel: string;
|
|
164
177
|
/** The Standard map type's name. */
|
|
165
178
|
standardLabel: string;
|
|
179
|
+
/**
|
|
180
|
+
* What screen readers hear when the map is tilted. `{degrees}` is the tilt
|
|
181
|
+
* from looking straight down.
|
|
182
|
+
*/
|
|
183
|
+
tiltedLabel: string;
|
|
166
184
|
/** The 3D button's label. */
|
|
167
185
|
tiltLabel: string;
|
|
186
|
+
/**
|
|
187
|
+
* What screen readers hear when the map is turned. `{degrees}` is the way the
|
|
188
|
+
* top of the map faces, clockwise from north.
|
|
189
|
+
*/
|
|
190
|
+
turnedLabel: string;
|
|
191
|
+
/**
|
|
192
|
+
* What screen readers hear after a zoom. `{level}` is the zoom level.
|
|
193
|
+
*/
|
|
194
|
+
zoomedLabel: string;
|
|
195
|
+
/**
|
|
196
|
+
* How far the map is zoomed, in its renderer's levels. `connectMap` keeps it
|
|
197
|
+
* current, and the map says it after a zoom.
|
|
198
|
+
*/
|
|
199
|
+
zoomLevel?: number | undefined;
|
|
200
|
+
/** What the live region says now. */
|
|
201
|
+
private said;
|
|
202
|
+
/** What a reader last asked of the map, until the map has answered it. */
|
|
203
|
+
private asked;
|
|
204
|
+
/** The wait for the view to settle before it is said. */
|
|
205
|
+
private settling;
|
|
206
|
+
/**
|
|
207
|
+
* Says the map has moved, where a reader asked it to.
|
|
208
|
+
*
|
|
209
|
+
* **Called by whatever moves the map**, as `connectMap` does on every frame
|
|
210
|
+
* the view moves. The frame's keys and buttons only ask, and nothing moves
|
|
211
|
+
* until something answers, so the frame says nothing until it is told the
|
|
212
|
+
* view moved: an announcement for a move that never happened is worse than
|
|
213
|
+
* none. A page moving its own map in answer to `helix-map-pan` calls this
|
|
214
|
+
* once it has.
|
|
215
|
+
*
|
|
216
|
+
* What is said waits for the view to settle, so a held key or a long
|
|
217
|
+
* animation is one sentence, and it is the view's state where there is one:
|
|
218
|
+
* the zoom level, the way the map faces, its tilt. A pan has no state to
|
|
219
|
+
* say, so it says which way the map moved.
|
|
220
|
+
*/
|
|
221
|
+
moved(): void;
|
|
222
|
+
private say;
|
|
223
|
+
/** Records what a reader asked, so the answer can be said. */
|
|
224
|
+
private ask;
|
|
168
225
|
/**
|
|
169
226
|
* The routes and areas among the frame's children, in the order they are
|
|
170
227
|
* written, which is the order the list names them in.
|
|
@@ -4,7 +4,7 @@ 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, HelixActivateEvent, HelixElement, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, hostAria, KeyboardNavigationController, MixinViewport, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, fillTemplate, formatNumbers, HelixActivateEvent, HelixElement, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, hostAria, KeyboardNavigationController, MixinViewport, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { buildings, cloudRain, dotsNine, leaf, mountains, path, polygon, stack, target, } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -35,23 +35,37 @@ const iconOf = (layer) => {
|
|
|
35
35
|
const ROTATE_STEP = 15;
|
|
36
36
|
const TILT_STEP = 10;
|
|
37
37
|
const TILTED = 50;
|
|
38
|
+
const ASK_LAPSES = 3000;
|
|
39
|
+
const SETTLES = 400;
|
|
38
40
|
let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement) {
|
|
39
41
|
constructor() {
|
|
40
42
|
super(...arguments);
|
|
41
43
|
this.bearing = 0;
|
|
42
44
|
this.cluster = false;
|
|
43
45
|
this.faceNorthLabel = 'Face north';
|
|
46
|
+
this.flatLabel = 'Looking straight down';
|
|
44
47
|
this.hybridLabel = 'Hybrid';
|
|
45
48
|
this.label = '';
|
|
46
49
|
this.layersLabel = 'Map layers';
|
|
47
50
|
this.mapPreviews = {};
|
|
48
51
|
this.mapTypeLabel = 'Map type';
|
|
52
|
+
this.movedDownLabel = 'Moved down';
|
|
53
|
+
this.movedLeftLabel = 'Moved left';
|
|
54
|
+
this.movedRightLabel = 'Moved right';
|
|
55
|
+
this.movedUpLabel = 'Moved up';
|
|
56
|
+
this.northLabel = 'Facing north';
|
|
49
57
|
this.pitch = 0;
|
|
50
58
|
this.rotateLeftLabel = 'Rotate left';
|
|
51
59
|
this.rotateRightLabel = 'Rotate right';
|
|
52
60
|
this.satelliteLabel = 'Satellite';
|
|
53
61
|
this.standardLabel = 'Standard';
|
|
62
|
+
this.tiltedLabel = 'Tilted {degrees} degrees';
|
|
54
63
|
this.tiltLabel = 'Show in 3D';
|
|
64
|
+
this.turnedLabel = 'Facing {degrees} degrees';
|
|
65
|
+
this.zoomedLabel = 'Zoom level {level}';
|
|
66
|
+
this.said = '';
|
|
67
|
+
this.asked = undefined;
|
|
68
|
+
this.settling = undefined;
|
|
55
69
|
this.layersOpen = false;
|
|
56
70
|
this.handleOutside = (event) => {
|
|
57
71
|
if (!event.composedPath().includes(this)) {
|
|
@@ -119,6 +133,46 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
|
|
|
119
133
|
this.requestUpdate();
|
|
120
134
|
};
|
|
121
135
|
}
|
|
136
|
+
moved() {
|
|
137
|
+
if (!this.asked || performance.now() - this.asked.at > ASK_LAPSES) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
clearTimeout(this.settling);
|
|
141
|
+
this.settling = setTimeout(() => this.say(), SETTLES);
|
|
142
|
+
}
|
|
143
|
+
say() {
|
|
144
|
+
const asked = this.asked;
|
|
145
|
+
this.asked = undefined;
|
|
146
|
+
if (!asked) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const numbers = formatNumbers(this.lang);
|
|
150
|
+
const degrees = (value) => numbers(Math.round(value));
|
|
151
|
+
const bearing = ((Math.round(this.bearing) % 360) + 360) % 360;
|
|
152
|
+
const words = {
|
|
153
|
+
down: this.movedDownLabel,
|
|
154
|
+
left: this.movedLeftLabel,
|
|
155
|
+
right: this.movedRightLabel,
|
|
156
|
+
up: this.movedUpLabel,
|
|
157
|
+
};
|
|
158
|
+
const next = asked.kind === 'pan'
|
|
159
|
+
? (words[asked.side ?? ''] ?? '')
|
|
160
|
+
: asked.kind === 'zoom'
|
|
161
|
+
? this.zoomLevel === undefined
|
|
162
|
+
? ''
|
|
163
|
+
: fillTemplate(this.zoomedLabel, { level: numbers(this.zoomLevel) })
|
|
164
|
+
: asked.kind === 'tilt'
|
|
165
|
+
? Math.round(this.pitch) === 0
|
|
166
|
+
? this.flatLabel
|
|
167
|
+
: fillTemplate(this.tiltedLabel, { degrees: degrees(this.pitch) })
|
|
168
|
+
: bearing === 0
|
|
169
|
+
? this.northLabel
|
|
170
|
+
: fillTemplate(this.turnedLabel, { degrees: degrees(bearing) });
|
|
171
|
+
this.said = next !== '' && next === this.said.trim() ? `${next}\u00a0` : next;
|
|
172
|
+
}
|
|
173
|
+
ask(kind, side) {
|
|
174
|
+
this.asked = { at: performance.now(), kind, ...(side ? { side } : {}) };
|
|
175
|
+
}
|
|
122
176
|
get layers() {
|
|
123
177
|
return this.knownChildren.filter((child) => child.isMapLayer === true);
|
|
124
178
|
}
|
|
@@ -183,6 +237,8 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
|
|
|
183
237
|
}
|
|
184
238
|
disconnectedCallback() {
|
|
185
239
|
super.disconnectedCallback();
|
|
240
|
+
clearTimeout(this.settling);
|
|
241
|
+
this.settling = undefined;
|
|
186
242
|
this.hiding?.disconnect();
|
|
187
243
|
document.removeEventListener('pointerdown', this.handleOutside);
|
|
188
244
|
this.removeEventListener(HelixMapPartChangeEvent.eventName, this.handlePartChange);
|
|
@@ -221,15 +277,19 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
|
|
|
221
277
|
}
|
|
222
278
|
}
|
|
223
279
|
rotate(by) {
|
|
280
|
+
this.ask('rotate');
|
|
224
281
|
this.dispatchEvent(new HelixMapRotateEvent({ by }));
|
|
225
282
|
}
|
|
226
283
|
faceNorth() {
|
|
284
|
+
this.ask('north');
|
|
227
285
|
this.dispatchEvent(new HelixMapRotateEvent({ to: 0 }));
|
|
228
286
|
}
|
|
229
287
|
tilt(by) {
|
|
288
|
+
this.ask('tilt');
|
|
230
289
|
this.dispatchEvent(new HelixMapTiltEvent({ by }));
|
|
231
290
|
}
|
|
232
291
|
tiltTo(to) {
|
|
292
|
+
this.ask('tilt');
|
|
233
293
|
this.dispatchEvent(new HelixMapTiltEvent({ to }));
|
|
234
294
|
}
|
|
235
295
|
renderLayersMenu() {
|
|
@@ -423,9 +483,11 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
|
|
|
423
483
|
return false;
|
|
424
484
|
}
|
|
425
485
|
panEvent(detail) {
|
|
486
|
+
this.ask('pan', this.sideOf(detail.to));
|
|
426
487
|
return new HelixMapPanEvent(detail);
|
|
427
488
|
}
|
|
428
489
|
zoomEvent(detail) {
|
|
490
|
+
this.ask('zoom');
|
|
429
491
|
return new HelixMapZoomEvent(detail);
|
|
430
492
|
}
|
|
431
493
|
get restingControlsLabel() {
|
|
@@ -472,6 +534,7 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
|
|
|
472
534
|
<div part="attribution">
|
|
473
535
|
<slot name="attribution"></slot>
|
|
474
536
|
</div>
|
|
537
|
+
<span part="live" role="status">${this.said}</span>
|
|
475
538
|
</div>`;
|
|
476
539
|
}
|
|
477
540
|
};
|
|
@@ -484,6 +547,9 @@ __decorate([
|
|
|
484
547
|
__decorate([
|
|
485
548
|
property({ attribute: 'face-north-label' })
|
|
486
549
|
], HelixHeadlessMap.prototype, "faceNorthLabel", void 0);
|
|
550
|
+
__decorate([
|
|
551
|
+
property({ attribute: 'flat-label' })
|
|
552
|
+
], HelixHeadlessMap.prototype, "flatLabel", void 0);
|
|
487
553
|
__decorate([
|
|
488
554
|
property({ attribute: 'hybrid-label' })
|
|
489
555
|
], HelixHeadlessMap.prototype, "hybridLabel", void 0);
|
|
@@ -502,6 +568,21 @@ __decorate([
|
|
|
502
568
|
__decorate([
|
|
503
569
|
property({ attribute: 'map-type-label' })
|
|
504
570
|
], HelixHeadlessMap.prototype, "mapTypeLabel", void 0);
|
|
571
|
+
__decorate([
|
|
572
|
+
property({ attribute: 'moved-down-label' })
|
|
573
|
+
], HelixHeadlessMap.prototype, "movedDownLabel", void 0);
|
|
574
|
+
__decorate([
|
|
575
|
+
property({ attribute: 'moved-left-label' })
|
|
576
|
+
], HelixHeadlessMap.prototype, "movedLeftLabel", void 0);
|
|
577
|
+
__decorate([
|
|
578
|
+
property({ attribute: 'moved-right-label' })
|
|
579
|
+
], HelixHeadlessMap.prototype, "movedRightLabel", void 0);
|
|
580
|
+
__decorate([
|
|
581
|
+
property({ attribute: 'moved-up-label' })
|
|
582
|
+
], HelixHeadlessMap.prototype, "movedUpLabel", void 0);
|
|
583
|
+
__decorate([
|
|
584
|
+
property({ attribute: 'north-label' })
|
|
585
|
+
], HelixHeadlessMap.prototype, "northLabel", void 0);
|
|
505
586
|
__decorate([
|
|
506
587
|
property({ type: Number })
|
|
507
588
|
], HelixHeadlessMap.prototype, "pitch", void 0);
|
|
@@ -517,9 +598,24 @@ __decorate([
|
|
|
517
598
|
__decorate([
|
|
518
599
|
property({ attribute: 'standard-label' })
|
|
519
600
|
], HelixHeadlessMap.prototype, "standardLabel", void 0);
|
|
601
|
+
__decorate([
|
|
602
|
+
property({ attribute: 'tilted-label' })
|
|
603
|
+
], HelixHeadlessMap.prototype, "tiltedLabel", void 0);
|
|
520
604
|
__decorate([
|
|
521
605
|
property({ attribute: 'tilt-label' })
|
|
522
606
|
], HelixHeadlessMap.prototype, "tiltLabel", void 0);
|
|
607
|
+
__decorate([
|
|
608
|
+
property({ attribute: 'turned-label' })
|
|
609
|
+
], HelixHeadlessMap.prototype, "turnedLabel", void 0);
|
|
610
|
+
__decorate([
|
|
611
|
+
property({ attribute: 'zoomed-label' })
|
|
612
|
+
], HelixHeadlessMap.prototype, "zoomedLabel", void 0);
|
|
613
|
+
__decorate([
|
|
614
|
+
property({ attribute: 'zoom-level', type: Number })
|
|
615
|
+
], HelixHeadlessMap.prototype, "zoomLevel", void 0);
|
|
616
|
+
__decorate([
|
|
617
|
+
state()
|
|
618
|
+
], HelixHeadlessMap.prototype, "said", void 0);
|
|
523
619
|
__decorate([
|
|
524
620
|
state()
|
|
525
621
|
], HelixHeadlessMap.prototype, "layersOpen", void 0);
|
|
@@ -94,7 +94,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
|
|
|
94
94
|
}
|
|
95
95
|
tellTrigger() {
|
|
96
96
|
const slot = this.renderRoot?.querySelector('slot[name="trigger"]');
|
|
97
|
-
tellDisclosure(slot?.assignedElements({ flatten: false })[0], this.open);
|
|
97
|
+
tellDisclosure(slot?.assignedElements({ flatten: false })[0], this.open, 'menu');
|
|
98
98
|
}
|
|
99
99
|
get trigger() {
|
|
100
100
|
return anchorElement(this.renderRoot?.querySelector('slot[name="trigger"]'), this);
|
|
@@ -188,6 +188,20 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
188
188
|
* cannot change.
|
|
189
189
|
*/
|
|
190
190
|
protected renderIndicator(): TemplateResult;
|
|
191
|
+
/**
|
|
192
|
+
* What names the trigger: the label, then the choice.
|
|
193
|
+
*
|
|
194
|
+
* **A button is named by its label alone**, and what it shows is not read:
|
|
195
|
+
* the `<label for>` wins over the button's own text. Read from Chromium's
|
|
196
|
+
* tree, a Select showing "Spanish" was a button named "Language", with the
|
|
197
|
+
* choice in no name or value, so a reader never heard what was chosen. A
|
|
198
|
+
* native `<select>` says both, and this names the trigger by both, the label
|
|
199
|
+
* and then the value, in that order.
|
|
200
|
+
*
|
|
201
|
+
* A consumer's own `aria-labelledby` on the host wins, carried to the trigger
|
|
202
|
+
* by `AriaForwardController`, so nothing is written here to fight it.
|
|
203
|
+
*/
|
|
204
|
+
private get triggerNames();
|
|
191
205
|
protected render(): TemplateResult;
|
|
192
206
|
}
|
|
193
207
|
declare global {
|
|
@@ -146,12 +146,19 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
146
146
|
</svg>
|
|
147
147
|
</slot>`;
|
|
148
148
|
}
|
|
149
|
+
get triggerNames() {
|
|
150
|
+
if (this.hasAttribute('aria-labelledby')) {
|
|
151
|
+
return nothing;
|
|
152
|
+
}
|
|
153
|
+
return this.labeled ? `${this.labelId} value` : 'value';
|
|
154
|
+
}
|
|
149
155
|
render() {
|
|
150
156
|
return html `${this.renderLabel()}
|
|
151
157
|
<button
|
|
152
158
|
part="trigger"
|
|
153
159
|
id=${this.controlId}
|
|
154
160
|
type="button"
|
|
161
|
+
aria-labelledby=${this.triggerNames}
|
|
155
162
|
aria-haspopup="listbox"
|
|
156
163
|
aria-expanded=${this.open ? 'true' : 'false'}
|
|
157
164
|
aria-describedby=${this.describedBy ?? nothing}
|
|
@@ -161,7 +168,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
161
168
|
@keydown=${this.handleTriggerKeydown}
|
|
162
169
|
>
|
|
163
170
|
<slot name="start"></slot>
|
|
164
|
-
<span part="value">${this.display}</span>
|
|
171
|
+
<span part="value" id="value">${this.display}</span>
|
|
165
172
|
${''}
|
|
166
173
|
<slot name="end"></slot>
|
|
167
174
|
${''}
|
|
@@ -202,6 +202,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
202
202
|
return html `<${this.tag('listbox')}
|
|
203
203
|
part="column"
|
|
204
204
|
data-column=${part}
|
|
205
|
+
aria-invalid=${this.invalid ? 'true' : nothing}
|
|
205
206
|
exportparts="empty: column-empty, feedback: column-feedback, filter-icon: column-filter-icon,
|
|
206
207
|
filter-mark: column-filter-mark, hint: column-hint, items: column-items, label: column-label,
|
|
207
208
|
live: column-live, loading: column-loading, search: column-search, search-field: column-search-field"
|
|
@@ -244,6 +245,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
244
245
|
renderList() {
|
|
245
246
|
return html `<${this.tag('listbox')}
|
|
246
247
|
part="list"
|
|
248
|
+
aria-invalid=${this.invalid ? 'true' : nothing}
|
|
247
249
|
exportparts="empty: list-empty, feedback: list-feedback, filter-icon: list-filter-icon,
|
|
248
250
|
filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
|
|
249
251
|
live: list-live, loading: list-loading, search: list-search, search-field: list-search-field"
|
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.
|
|
4
|
+
"version": "0.110.1",
|
|
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.
|
|
50
|
-
"@fusion.dev/helix-icons": "0.
|
|
49
|
+
"@fusion.dev/helix-core": "0.110.1",
|
|
50
|
+
"@fusion.dev/helix-icons": "0.110.1",
|
|
51
51
|
"uqr": "^0.1.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@fusion.dev/helix-cem": "0.
|
|
55
|
-
"@fusion.dev/helix-testing": "0.
|
|
54
|
+
"@fusion.dev/helix-cem": "0.110.1",
|
|
55
|
+
"@fusion.dev/helix-testing": "0.110.1",
|
|
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",
|