@fusion.dev/helix-core 0.144.0 → 0.146.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/custom-elements.json +5724 -1404
- package/dist/controllers/aria-forward-controller/aria-forward-controller.d.ts +3 -2
- package/dist/controllers/aria-forward-controller/aria-forward-controller.js +4 -14
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.d.ts +65 -3
- package/dist/controllers/chart-pointer-controller/chart-pointer-controller.js +37 -9
- package/dist/controllers/chart-pointer-controller/reading-step.d.ts +7 -1
- package/dist/controllers/chart-pointer-controller/reading-step.js +5 -0
- package/dist/controllers/countdown-controller/countdown-controller.d.ts +55 -0
- package/dist/controllers/countdown-controller/countdown-controller.js +57 -0
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.d.ts +20 -57
- package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.js +11 -40
- package/dist/controllers/relative-clock-controller/relative-clock-controller.d.ts +44 -0
- package/dist/controllers/relative-clock-controller/relative-clock-controller.js +31 -0
- package/dist/controllers/source-controller/source-controller.d.ts +10 -3
- package/dist/controllers/source-controller/source-controller.js +7 -4
- package/dist/controllers/virtualize-controller/virtualize-controller.d.ts +116 -36
- package/dist/controllers/virtualize-controller/virtualize-controller.js +122 -12
- package/dist/events/action.d.ts +12 -0
- package/dist/events/action.js +6 -0
- package/dist/events/activate.d.ts +22 -0
- package/dist/events/activate.js +11 -0
- package/dist/events/aura-fallback.d.ts +12 -0
- package/dist/events/aura-fallback.js +11 -0
- package/dist/events/before-activate.d.ts +24 -0
- package/dist/events/before-activate.js +11 -0
- package/dist/events/before-change.d.ts +26 -0
- package/dist/events/before-change.js +11 -0
- package/dist/events/before-close.d.ts +6 -0
- package/dist/events/before-close.js +11 -0
- package/dist/events/before-collapse.d.ts +6 -0
- package/dist/events/before-collapse.js +11 -0
- package/dist/events/before-edit.d.ts +6 -0
- package/dist/events/before-edit.js +11 -0
- package/dist/events/before-move.d.ts +17 -0
- package/dist/events/before-move.js +11 -0
- package/dist/events/before-open.d.ts +17 -0
- package/dist/events/before-open.js +11 -0
- package/dist/events/before-panel-resize.d.ts +13 -0
- package/dist/events/before-panel-resize.js +11 -0
- package/dist/events/before-pin.d.ts +6 -0
- package/dist/events/before-pin.js +11 -0
- package/dist/events/before-reconnect.d.ts +14 -0
- package/dist/events/before-reconnect.js +11 -0
- package/dist/events/before-relabel.d.ts +15 -0
- package/dist/events/before-relabel.js +11 -0
- package/dist/events/before-resize.d.ts +6 -0
- package/dist/events/before-resize.js +11 -0
- package/dist/events/before-split.d.ts +12 -0
- package/dist/events/before-split.js +11 -0
- package/dist/events/before-toggle.d.ts +23 -0
- package/dist/events/before-toggle.js +11 -0
- package/dist/events/canvas-edit.d.ts +16 -0
- package/dist/events/canvas-edit.js +11 -0
- package/dist/events/canvas-pan.d.ts +13 -0
- package/dist/events/canvas-pan.js +11 -0
- package/dist/events/canvas-view.d.ts +14 -0
- package/dist/events/canvas-view.js +11 -0
- package/dist/events/canvas-zoom.d.ts +6 -0
- package/dist/events/canvas-zoom.js +11 -0
- package/dist/events/caret.d.ts +17 -0
- package/dist/events/caret.js +11 -0
- package/dist/events/clear.d.ts +11 -0
- package/dist/events/clear.js +6 -0
- package/dist/events/collapse.d.ts +12 -0
- package/dist/events/collapse.js +11 -0
- package/dist/events/complete.d.ts +26 -0
- package/dist/events/complete.js +11 -0
- package/dist/events/connect.d.ts +14 -0
- package/dist/events/connect.js +11 -0
- package/dist/events/console.d.ts +13 -0
- package/dist/events/console.js +11 -0
- package/dist/events/copy-error.d.ts +9 -0
- package/dist/events/copy-error.js +6 -0
- package/dist/events/copy.d.ts +12 -0
- package/dist/events/copy.js +10 -0
- package/dist/events/create.d.ts +18 -0
- package/dist/events/create.js +11 -0
- package/dist/events/details.d.ts +454 -0
- package/dist/events/details.js +1 -0
- package/dist/events/dismiss.d.ts +16 -0
- package/dist/events/dismiss.js +11 -0
- package/dist/events/edit.d.ts +12 -0
- package/dist/events/edit.js +11 -0
- package/dist/events/end.d.ts +9 -0
- package/dist/events/end.js +6 -0
- package/dist/events/events.d.ts +125 -1306
- package/dist/events/events.js +105 -739
- package/dist/events/expand.d.ts +10 -0
- package/dist/events/expand.js +11 -0
- package/dist/events/facet.d.ts +17 -0
- package/dist/events/facet.js +11 -0
- package/dist/events/filter.d.ts +12 -0
- package/dist/events/filter.js +11 -0
- package/dist/events/filtered.d.ts +12 -0
- package/dist/events/filtered.js +11 -0
- package/dist/events/graph-filter.d.ts +10 -0
- package/dist/events/graph-filter.js +11 -0
- package/dist/events/graph-layout.d.ts +10 -0
- package/dist/events/graph-layout.js +11 -0
- package/dist/events/graph-pan.d.ts +9 -0
- package/dist/events/graph-pan.js +11 -0
- package/dist/events/graph-part-change.d.ts +10 -0
- package/dist/events/graph-part-change.js +11 -0
- package/dist/events/graph-ready.d.ts +8 -0
- package/dist/events/graph-ready.js +6 -0
- package/dist/events/graph-signal.d.ts +11 -0
- package/dist/events/graph-signal.js +11 -0
- package/dist/events/graph-zoom.d.ts +6 -0
- package/dist/events/graph-zoom.js +11 -0
- package/dist/events/history.d.ts +16 -0
- package/dist/events/history.js +11 -0
- package/dist/events/load-more.d.ts +12 -0
- package/dist/events/load-more.js +6 -0
- package/dist/events/load.d.ts +12 -0
- package/dist/events/load.js +6 -0
- package/dist/events/map-cluster.d.ts +15 -0
- package/dist/events/map-cluster.js +11 -0
- package/dist/events/map-pan.d.ts +18 -0
- package/dist/events/map-pan.js +11 -0
- package/dist/events/map-part-change.d.ts +16 -0
- package/dist/events/map-part-change.js +11 -0
- package/dist/events/map-ready.d.ts +15 -0
- package/dist/events/map-ready.js +6 -0
- package/dist/events/map-rotate.d.ts +9 -0
- package/dist/events/map-rotate.js +11 -0
- package/dist/events/map-tilt.d.ts +9 -0
- package/dist/events/map-tilt.js +11 -0
- package/dist/events/map-zoom.d.ts +13 -0
- package/dist/events/map-zoom.js +11 -0
- package/dist/events/move.d.ts +11 -0
- package/dist/events/move.js +11 -0
- package/dist/events/names.d.ts +15 -0
- package/dist/events/names.js +88 -0
- package/dist/events/navigate.d.ts +13 -0
- package/dist/events/navigate.js +11 -0
- package/dist/events/next.d.ts +23 -0
- package/dist/events/next.js +11 -0
- package/dist/events/panel-resize.d.ts +12 -0
- package/dist/events/panel-resize.js +11 -0
- package/dist/events/pin.d.ts +12 -0
- package/dist/events/pin.js +11 -0
- package/dist/events/press.d.ts +19 -0
- package/dist/events/press.js +11 -0
- package/dist/events/preview.d.ts +14 -0
- package/dist/events/preview.js +11 -0
- package/dist/events/previous.d.ts +6 -0
- package/dist/events/previous.js +11 -0
- package/dist/events/range-change.d.ts +10 -0
- package/dist/events/range-change.js +11 -0
- package/dist/events/read.d.ts +19 -0
- package/dist/events/read.js +11 -0
- package/dist/events/reconnect.d.ts +6 -0
- package/dist/events/reconnect.js +11 -0
- package/dist/events/reject.d.ts +13 -0
- package/dist/events/reject.js +11 -0
- package/dist/events/relabel.d.ts +6 -0
- package/dist/events/relabel.js +11 -0
- package/dist/events/remove.d.ts +12 -0
- package/dist/events/remove.js +11 -0
- package/dist/events/reorder.d.ts +18 -0
- package/dist/events/reorder.js +11 -0
- package/dist/events/reordered.d.ts +12 -0
- package/dist/events/reordered.js +11 -0
- package/dist/events/resize.d.ts +19 -0
- package/dist/events/resize.js +11 -0
- package/dist/events/resized.d.ts +16 -0
- package/dist/events/resized.js +11 -0
- package/dist/events/sample-end.d.ts +5 -0
- package/dist/events/sample-end.js +6 -0
- package/dist/events/sample-start.d.ts +18 -0
- package/dist/events/sample-start.js +6 -0
- package/dist/events/scrolled.d.ts +32 -0
- package/dist/events/scrolled.js +11 -0
- package/dist/events/select.d.ts +12 -0
- package/dist/events/select.js +11 -0
- package/dist/events/selected.d.ts +12 -0
- package/dist/events/selected.js +11 -0
- package/dist/events/send.d.ts +18 -0
- package/dist/events/send.js +11 -0
- package/dist/events/shortcut.d.ts +13 -0
- package/dist/events/shortcut.js +11 -0
- package/dist/events/sort.d.ts +17 -0
- package/dist/events/sort.js +11 -0
- package/dist/events/sorted.d.ts +15 -0
- package/dist/events/sorted.js +11 -0
- package/dist/events/split.d.ts +12 -0
- package/dist/events/split.js +11 -0
- package/dist/events/toggle.d.ts +15 -0
- package/dist/events/toggle.js +11 -0
- package/dist/events/tour-ask.d.ts +16 -0
- package/dist/events/tour-ask.js +11 -0
- package/dist/events/tour-status.d.ts +14 -0
- package/dist/events/tour-status.js +11 -0
- package/dist/events/typing.d.ts +10 -0
- package/dist/events/typing.js +11 -0
- package/dist/helix-element/helix-element.js +14 -1
- package/dist/helix-element/react-bridge.d.ts +19 -4
- package/dist/helix-element/react-bridge.js +15 -2
- package/dist/helix-form-element/helix-form-element.d.ts +5 -20
- package/dist/helix-form-element/helix-form-element.js +4 -56
- package/dist/index.d.ts +17 -3
- package/dist/index.js +17 -3
- package/dist/mixins/mixin-chart-source/mixin-chart-source.d.ts +17 -2
- package/dist/mixins/mixin-chart-source/mixin-chart-source.js +22 -1
- package/dist/mixins/mixin-controller-active/mixin-controller-active.js +4 -3
- package/dist/mixins/mixin-controller-checked/mixin-controller-checked.d.ts +5 -2
- package/dist/mixins/mixin-controller-checked/mixin-controller-checked.js +2 -1
- package/dist/mixins/mixin-controller-value/mixin-controller-value.d.ts +4 -2
- package/dist/mixins/mixin-controller-value/mixin-controller-value.js +7 -2
- package/dist/mixins/mixin-dismissible/mixin-dismissible.js +20 -4
- package/dist/mixins/mixin-field/mixin-field.js +2 -2
- package/dist/mixins/mixin-picker-field/mixin-picker-field.d.ts +15 -3
- package/dist/mixins/mixin-picker-field/mixin-picker-field.js +11 -4
- package/dist/mixins/mixin-segmented-field/mixin-segmented-field.d.ts +1 -1
- package/dist/mixins/mixin-segmented-field/mixin-segmented-field.js +10 -4
- package/dist/utils/audit-name/audit-name-off.d.ts +10 -0
- package/dist/utils/audit-name/audit-name-off.js +1 -0
- package/dist/utils/audit-name/audit-name.d.ts +19 -6
- package/dist/utils/audit-name/audit-name.js +10 -27
- package/dist/utils/calendar/calendar.js +7 -7
- package/dist/utils/draw-icon/draw-icon.d.ts +7 -6
- package/dist/utils/draw-tooltip/draw-tooltip.d.ts +1 -1
- package/dist/utils/draw-tooltip/draw-tooltip.js +3 -1
- package/dist/utils/draw-tooltip/spoken-reading.d.ts +6 -2
- package/dist/utils/draw-tooltip/spoken-reading.js +5 -4
- package/dist/utils/heading-level/heading-level.d.ts +8 -0
- package/dist/utils/heading-level/heading-level.js +4 -0
- package/dist/utils/implicit-submit/implicit-submit.d.ts +25 -0
- package/dist/utils/implicit-submit/implicit-submit.js +52 -0
- package/dist/utils/name-text/name-text.d.ts +12 -0
- package/dist/utils/name-text/name-text.js +25 -0
- package/dist/utils/number-format/number-format.d.ts +2 -1
- package/dist/utils/number-format/number-format.js +13 -5
- package/dist/utils/plain-click/plain-click.d.ts +10 -0
- package/dist/utils/plain-click/plain-click.js +1 -0
- package/dist/utils/press-type/press-type.d.ts +20 -0
- package/dist/utils/press-type/press-type.js +15 -0
- package/dist/utils/range-add/range-add.d.ts +19 -0
- package/dist/utils/range-add/range-add.js +5 -0
- package/dist/utils/reflect-elements/reflect-elements.d.ts +3 -3
- package/dist/utils/report-runtime/report-runtime.d.ts +9 -4
- package/dist/utils/row-data/row-data.d.ts +15 -0
- package/dist/utils/row-data/row-data.js +17 -0
- package/dist/utils/row-order/row-order.d.ts +141 -0
- package/dist/utils/row-order/row-order.js +76 -0
- package/dist/utils/tell-disclosure/tell-disclosure.d.ts +4 -0
- package/dist/utils/tree-arrow/tree-arrow.d.ts +23 -0
- package/dist/utils/tree-arrow/tree-arrow.js +9 -0
- package/dist/utils/typeahead/typeahead.d.ts +67 -0
- package/dist/utils/typeahead/typeahead.js +36 -0
- package/dist/utils/value-as/value-as.d.ts +9 -0
- package/dist/utils/value-as/value-as.js +9 -1
- package/dist/utils/watch-labels/watch-labels.d.ts +16 -0
- package/dist/utils/watch-labels/watch-labels.js +34 -0
- package/dist/utils/words-converter/words-converter.d.ts +14 -0
- package/dist/utils/words-converter/words-converter.js +15 -0
- package/dist/utils/write-time/write-time.d.ts +4 -4
- package/dist/utils/written-list/written-list.d.ts +29 -0
- package/dist/utils/written-list/written-list.js +30 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +18 -5
|
@@ -84,7 +84,8 @@ export interface AriaForwardOptions {
|
|
|
84
84
|
* and the host is a generic the reader never lands on, so a `<label for>` or a
|
|
85
85
|
* wrapping `<label>` left the textbox unnamed. The labels travel the same way a
|
|
86
86
|
* forwarded `aria-labelledby` does, as element references, and are read again
|
|
87
|
-
*
|
|
87
|
+
* on every update, which a form control asks for whenever a label in its tree
|
|
88
|
+
* changes (`watchLabels`), and as focus arrives.
|
|
88
89
|
*/
|
|
89
90
|
export declare class AriaForwardController implements ReactiveController {
|
|
90
91
|
private readonly host;
|
|
@@ -128,7 +129,7 @@ export declare class AriaForwardController implements ReactiveController {
|
|
|
128
129
|
forward(): void;
|
|
129
130
|
hostConnected(): void;
|
|
130
131
|
hostDisconnected(): void;
|
|
131
|
-
/** Forwards again as focus arrives
|
|
132
|
+
/** Forwards again as focus arrives. */
|
|
132
133
|
private readonly refresh;
|
|
133
134
|
hostUpdated(): void;
|
|
134
135
|
}
|
|
@@ -1,22 +1,12 @@
|
|
|
1
|
-
import { auditName } from '
|
|
1
|
+
import { auditName } from '#audit-name';
|
|
2
2
|
import { elementById } from '../../utils/element-by-id/element-by-id.js';
|
|
3
|
-
|
|
4
|
-
if (node instanceof HTMLSlotElement) {
|
|
5
|
-
return node.assignedNodes({ flatten: true }).map(shownText).join('');
|
|
6
|
-
}
|
|
7
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
8
|
-
return node.textContent ?? '';
|
|
9
|
-
}
|
|
10
|
-
if (node instanceof HTMLElement && node.hidden) {
|
|
11
|
-
return '';
|
|
12
|
-
}
|
|
13
|
-
return [...node.childNodes].map(shownText).join('');
|
|
14
|
-
};
|
|
3
|
+
import { nameText } from '../../utils/name-text/name-text.js';
|
|
15
4
|
const RELATIONSHIPS = [
|
|
16
5
|
['aria-describedby', 'ariaDescribedByElements'],
|
|
17
6
|
['aria-labelledby', 'ariaLabelledByElements'],
|
|
18
7
|
];
|
|
19
8
|
const STATES = [
|
|
9
|
+
'aria-current',
|
|
20
10
|
'aria-expanded',
|
|
21
11
|
'aria-haspopup',
|
|
22
12
|
'aria-controls',
|
|
@@ -48,7 +38,7 @@ export class AriaForwardController {
|
|
|
48
38
|
return true;
|
|
49
39
|
}
|
|
50
40
|
const own = target.labels;
|
|
51
|
-
return [...(own ?? [])].some((label) =>
|
|
41
|
+
return [...(own ?? [])].some((label) => nameText(label).trim() !== '');
|
|
52
42
|
}
|
|
53
43
|
hostLabels(target) {
|
|
54
44
|
const labels = this.host.labels;
|
|
@@ -34,6 +34,31 @@ export interface ChartPointerHost extends ReactiveControllerHost, HTMLElement {
|
|
|
34
34
|
* drawn from, such as a scatter's measure across.
|
|
35
35
|
*/
|
|
36
36
|
seriesOf?(cell: number): number | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Whether the series drawn from the cell at this place in a row is shown,
|
|
39
|
+
* which it is unless a legend hid it. Absent, every series is shown.
|
|
40
|
+
*
|
|
41
|
+
* The series keys pass over a hidden one, and the readout leaves it out.
|
|
42
|
+
*/
|
|
43
|
+
showsColumn?(cell: number): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the reading at this place is shown, for a chart whose readings
|
|
46
|
+
* a legend can hide: a ring's slices are its rows. Absent, every reading is
|
|
47
|
+
* shown.
|
|
48
|
+
*
|
|
49
|
+
* The keys pass over a hidden reading, as they pass over a hidden series.
|
|
50
|
+
*/
|
|
51
|
+
showsReading?(at: number): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* The words for where a reading stands among them, with `{position}` and
|
|
54
|
+
* `{count}` to fill. Absent or empty, no position is said.
|
|
55
|
+
*/
|
|
56
|
+
readonly positionLabel?: string;
|
|
57
|
+
/**
|
|
58
|
+
* The locale the position's numbers are written in. Absent or empty is the
|
|
59
|
+
* runtime's own.
|
|
60
|
+
*/
|
|
61
|
+
readonly locale?: string;
|
|
37
62
|
}
|
|
38
63
|
/**
|
|
39
64
|
* Which reading a pointer is nearest, for a chart that draws no markers.
|
|
@@ -62,8 +87,9 @@ export interface ChartPointerHost extends ReactiveControllerHost, HTMLElement {
|
|
|
62
87
|
* **The keyboard moves the same reading, which is what makes it the reading
|
|
63
88
|
* and not the pointer's.** A chart's plot takes focus (`tabindex="0"` on the
|
|
64
89
|
* element carrying `CHART_PLOT`), and while it has it the arrow keys walk the
|
|
65
|
-
* readings, Home and End go to the first and the last, and
|
|
66
|
-
*
|
|
90
|
+
* readings, Home and End go to the first and the last, PageUp and PageDown
|
|
91
|
+
* move a page of readings, and the other pair of arrows walks the series
|
|
92
|
+
* within a reading. Escape puts the bubble away, as it
|
|
67
93
|
* does a tooltip. The tooltip follows because it already follows `at`, and the
|
|
68
94
|
* chart's readout, a polite live region `drawTooltip` renders, says the
|
|
69
95
|
* reading in words. It speaks only for a key: a pointer crossing a chart is a
|
|
@@ -125,8 +151,41 @@ export declare class ChartPointerController implements ReactiveController {
|
|
|
125
151
|
* from, and the bubble lists every one of them.
|
|
126
152
|
*/
|
|
127
153
|
get column(): number | undefined;
|
|
128
|
-
/**
|
|
154
|
+
/**
|
|
155
|
+
* Whether the series drawn from the cell at this place in a row is shown.
|
|
156
|
+
*
|
|
157
|
+
* The readout asks, so a reading said whole leaves out what a legend hid,
|
|
158
|
+
* as the drawing does.
|
|
159
|
+
*/
|
|
160
|
+
shows(cell: number): boolean;
|
|
161
|
+
/**
|
|
162
|
+
* How far PageUp and PageDown move: four columns of a grid, which is four
|
|
163
|
+
* weeks of a calendar heatmap, a month near enough; and a tenth of the
|
|
164
|
+
* readings otherwise, at least one.
|
|
165
|
+
*/
|
|
166
|
+
private page;
|
|
167
|
+
/**
|
|
168
|
+
* Where the reading stands among the shown readings, in the host's
|
|
169
|
+
* `positionLabel`, such as "2 of 12". Empty with no reading, and where the
|
|
170
|
+
* host gives no words.
|
|
171
|
+
*
|
|
172
|
+
* Counted among the shown readings, so a slice a legend hid is not one of
|
|
173
|
+
* the count.
|
|
174
|
+
*/
|
|
175
|
+
get position(): string;
|
|
176
|
+
/**
|
|
177
|
+
* The cells a series key can rest on: every column a series was drawn
|
|
178
|
+
* from, and is still drawn from.
|
|
179
|
+
*/
|
|
129
180
|
private columns;
|
|
181
|
+
/**
|
|
182
|
+
* The readings the keys walk, by place: every one, less those a legend hid.
|
|
183
|
+
*
|
|
184
|
+
* The keys step through this list, so a hidden
|
|
185
|
+
* slice is passed over as if it were not in the table, which is how the
|
|
186
|
+
* ring draws it.
|
|
187
|
+
*/
|
|
188
|
+
private shown;
|
|
130
189
|
/**
|
|
131
190
|
* Tells the tooltip its anchor moved, which nothing else would.
|
|
132
191
|
*
|
|
@@ -145,6 +204,9 @@ export declare class ChartPointerController implements ReactiveController {
|
|
|
145
204
|
/**
|
|
146
205
|
* The box the readings are laid out in, which is the plot and not the host.
|
|
147
206
|
*
|
|
207
|
+
* Found by its part, or by the id every chart gives its plot, which is how
|
|
208
|
+
* a sparkline's drawing, whose part is `svg`, is found.
|
|
209
|
+
*
|
|
148
210
|
* The host also holds the row of labels, so measuring against it would map
|
|
149
211
|
* the pointer over a box taller than the drawing. That mattered the moment a
|
|
150
212
|
* chart started measuring down the box rather than across it, which is what
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { fillTemplate } from '../../utils/fill-template/fill-template.js';
|
|
2
|
+
import { formatNumbers } from '../../utils/format-numbers/format-numbers.js';
|
|
1
3
|
import { isRtl } from '../../utils/is-rtl/is-rtl.js';
|
|
2
4
|
import { stepReading } from './reading-step.js';
|
|
3
5
|
export const CHART_PLOT = 'helix-chart-plot';
|
|
@@ -13,7 +15,8 @@ export class ChartPointerController {
|
|
|
13
15
|
if (!this.fromPlot(event) || event.altKey || event.ctrlKey || event.metaKey) {
|
|
14
16
|
return;
|
|
15
17
|
}
|
|
16
|
-
const
|
|
18
|
+
const shown = this.shown();
|
|
19
|
+
const count = shown.length;
|
|
17
20
|
if (count === 0) {
|
|
18
21
|
return;
|
|
19
22
|
}
|
|
@@ -24,17 +27,19 @@ export class ChartPointerController {
|
|
|
24
27
|
}
|
|
25
28
|
return;
|
|
26
29
|
}
|
|
27
|
-
const next = stepReading(event.key, { at: this.at, series: this.series }, {
|
|
30
|
+
const next = stepReading(event.key, { at: shown.indexOf(this.at), series: this.series }, {
|
|
28
31
|
axis: this.axis,
|
|
29
32
|
count,
|
|
30
33
|
grid: this.grid,
|
|
34
|
+
page: this.page(count),
|
|
31
35
|
rtl: isRtl(this.host),
|
|
32
36
|
series: this.columns().length,
|
|
33
37
|
});
|
|
34
38
|
if (next === undefined) {
|
|
35
39
|
return;
|
|
36
40
|
}
|
|
37
|
-
const
|
|
41
|
+
const at = shown[next.at] ?? -1;
|
|
42
|
+
const { series } = next;
|
|
38
43
|
event.preventDefault();
|
|
39
44
|
if (at === this.at && series === this.series && this.keyed) {
|
|
40
45
|
return;
|
|
@@ -56,10 +61,11 @@ export class ChartPointerController {
|
|
|
56
61
|
}
|
|
57
62
|
catch {
|
|
58
63
|
}
|
|
59
|
-
|
|
64
|
+
const first = this.shown()[0];
|
|
65
|
+
if (!visible || first === undefined) {
|
|
60
66
|
return;
|
|
61
67
|
}
|
|
62
|
-
this.at =
|
|
68
|
+
this.at = first;
|
|
63
69
|
this.keyed = true;
|
|
64
70
|
this.moved = true;
|
|
65
71
|
this.host.requestUpdate();
|
|
@@ -123,12 +129,32 @@ export class ChartPointerController {
|
|
|
123
129
|
get column() {
|
|
124
130
|
return this.series < 0 ? undefined : this.columns()[this.series];
|
|
125
131
|
}
|
|
132
|
+
shows(cell) {
|
|
133
|
+
return this.host.showsColumn?.(cell) !== false;
|
|
134
|
+
}
|
|
135
|
+
page(count) {
|
|
136
|
+
return this.grid > 1 ? this.grid * 4 : Math.max(1, Math.round(count / 10));
|
|
137
|
+
}
|
|
138
|
+
get position() {
|
|
139
|
+
const words = this.host.positionLabel ?? '';
|
|
140
|
+
const shown = this.shown();
|
|
141
|
+
const place = shown.indexOf(this.at);
|
|
142
|
+
if (words === '' || place < 0) {
|
|
143
|
+
return '';
|
|
144
|
+
}
|
|
145
|
+
const format = formatNumbers(this.host.locale ?? '');
|
|
146
|
+
return fillTemplate(words, { count: format(shown.length), position: format(place + 1) });
|
|
147
|
+
}
|
|
126
148
|
columns() {
|
|
127
149
|
const host = this.host;
|
|
128
|
-
|
|
129
|
-
|
|
150
|
+
return (host.plottedColumns ?? []).filter((one) => (host.seriesOf === undefined || host.seriesOf(one) !== undefined) && this.shows(one));
|
|
151
|
+
}
|
|
152
|
+
shown() {
|
|
153
|
+
const host = this.host;
|
|
154
|
+
const all = Array.from({ length: host.readings }, (_, at) => at);
|
|
155
|
+
return host.showsReading === undefined
|
|
130
156
|
? all
|
|
131
|
-
: all.filter((
|
|
157
|
+
: all.filter((at) => host.showsReading?.(at) !== false);
|
|
132
158
|
}
|
|
133
159
|
hostUpdated() {
|
|
134
160
|
if (!this.moved) {
|
|
@@ -141,7 +167,9 @@ export class ChartPointerController {
|
|
|
141
167
|
}
|
|
142
168
|
box() {
|
|
143
169
|
if (!this.plot?.isConnected) {
|
|
144
|
-
this.plot =
|
|
170
|
+
this.plot =
|
|
171
|
+
this.host.renderRoot.querySelector(`[part="plot"], #${CHART_PLOT}`) ??
|
|
172
|
+
undefined;
|
|
145
173
|
}
|
|
146
174
|
return this.plot?.getBoundingClientRect();
|
|
147
175
|
}
|
|
@@ -18,6 +18,11 @@ export interface ReadingLayout {
|
|
|
18
18
|
count: number;
|
|
19
19
|
/** How many readings stand in one column, for a grid. `1` is a row of them. */
|
|
20
20
|
grid: number;
|
|
21
|
+
/**
|
|
22
|
+
* How far PageUp and PageDown move, in readings. Absent, they move nothing
|
|
23
|
+
* and the page keeps them.
|
|
24
|
+
*/
|
|
25
|
+
page?: number;
|
|
21
26
|
/** Whether the line of text runs right to left, which turns the inline arrows. */
|
|
22
27
|
rtl: boolean;
|
|
23
28
|
/** How many series a reading holds, which the cross pair of arrows walks. */
|
|
@@ -49,7 +54,8 @@ export declare const amongSeries: (key: string, layout: ReadingLayout) => number
|
|
|
49
54
|
* Where a key moves the reading, or `undefined` for a key that moves nothing,
|
|
50
55
|
* which the page keeps.
|
|
51
56
|
*
|
|
52
|
-
* Home and End go to the first and the last
|
|
57
|
+
* Home and End go to the first and the last, and PageUp and PageDown move a
|
|
58
|
+
* `page` of readings where the layout gives one. From no reading, an arrow moving
|
|
53
59
|
* on starts at the first and one moving back at the last, so either arrow
|
|
54
60
|
* starts somewhere a reader expects. A series key on no reading starts on the
|
|
55
61
|
* first. Nothing walks off either end.
|
|
@@ -29,6 +29,11 @@ export const stepReading = (key, from, layout) => {
|
|
|
29
29
|
if (key === 'End') {
|
|
30
30
|
return { at: last, series: from.series };
|
|
31
31
|
}
|
|
32
|
+
if ((key === 'PageDown' || key === 'PageUp') && layout.page !== undefined) {
|
|
33
|
+
const step = Math.max(1, layout.page) * (key === 'PageDown' ? 1 : -1);
|
|
34
|
+
const at = from.at < 0 ? (step > 0 ? 0 : last) : Math.min(Math.max(from.at + step, 0), last);
|
|
35
|
+
return { at, series: from.series };
|
|
36
|
+
}
|
|
32
37
|
const along = alongReadings(key, layout);
|
|
33
38
|
if (along !== 0) {
|
|
34
39
|
const at = from.at < 0 ? (along > 0 ? 0 : last) : Math.min(Math.max(from.at + along, 0), last);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
|
2
|
+
/** What a `CountdownController` does when its time runs out, and when it stops and starts. */
|
|
3
|
+
export interface CountdownOptions {
|
|
4
|
+
/** Runs once the time is spent. */
|
|
5
|
+
done: () => void;
|
|
6
|
+
/** Runs with `true` when the clock stops partway and `false` when it runs again. */
|
|
7
|
+
paused?: (paused: boolean) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A lifetime that pauses: a message that dismisses itself after a time, and
|
|
11
|
+
* holds that time while a reader is on it.
|
|
12
|
+
*
|
|
13
|
+
* Toast's items and Announcement each dismiss themselves after `duration`,
|
|
14
|
+
* and each stops the clock while the pointer or focus is on the message, so a
|
|
15
|
+
* reader partway through is not cut off. Resuming continues from what was
|
|
16
|
+
* left rather than starting over.
|
|
17
|
+
*
|
|
18
|
+
* **Holds are counted, not flagged.** Hover and focus stop the same clock and
|
|
19
|
+
* are independent: a pointer can leave while focus stays. Uncounted, a reader
|
|
20
|
+
* who tabs into a message and then moves the pointer off it has the clock
|
|
21
|
+
* restarted underneath them. Only the last one out starts it again.
|
|
22
|
+
*
|
|
23
|
+
* **Leaving the page pauses it**, keeping the time already spent, and drops
|
|
24
|
+
* the holds, since a pointer or focus on a detached element never leaves it.
|
|
25
|
+
* Coming back does not resume on its own: the host says whether it should,
|
|
26
|
+
* such as only while it is still showing. `DelayController` is the other wait
|
|
27
|
+
* in core, for a wait that starts over and forgets itself on leaving.
|
|
28
|
+
*/
|
|
29
|
+
export declare class CountdownController implements ReactiveController {
|
|
30
|
+
private readonly options;
|
|
31
|
+
/** When the current run began, or nothing while the clock is stopped. */
|
|
32
|
+
private startedAt;
|
|
33
|
+
/** What is left of the time, so resuming continues rather than restarts. */
|
|
34
|
+
private remaining;
|
|
35
|
+
private timer;
|
|
36
|
+
/** How many reasons there are to hold the clock. */
|
|
37
|
+
private holds;
|
|
38
|
+
constructor(host: ReactiveControllerHost, options: CountdownOptions);
|
|
39
|
+
/** Whether the clock is running now. */
|
|
40
|
+
get running(): boolean;
|
|
41
|
+
hostConnected(): void;
|
|
42
|
+
hostDisconnected(): void;
|
|
43
|
+
/** Starts the clock at `ms`. Nothing, zero or less starts nothing. */
|
|
44
|
+
start(ms: number | undefined): void;
|
|
45
|
+
/** Stops the clock and keeps the time that is left. */
|
|
46
|
+
pause(): void;
|
|
47
|
+
/** Runs the clock again from where it stopped. */
|
|
48
|
+
resume(): void;
|
|
49
|
+
/** Stops the clock where it is, as a dismissal does. */
|
|
50
|
+
cancel(): void;
|
|
51
|
+
/** One more reason to hold the clock, such as a pointer arriving. */
|
|
52
|
+
hold(): void;
|
|
53
|
+
/** One reason fewer, and the clock runs again once none is left. */
|
|
54
|
+
release(): void;
|
|
55
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export class CountdownController {
|
|
2
|
+
constructor(host, options) {
|
|
3
|
+
this.options = options;
|
|
4
|
+
this.holds = 0;
|
|
5
|
+
host.addController(this);
|
|
6
|
+
}
|
|
7
|
+
get running() {
|
|
8
|
+
return this.timer !== undefined;
|
|
9
|
+
}
|
|
10
|
+
hostConnected() { }
|
|
11
|
+
hostDisconnected() {
|
|
12
|
+
this.pause();
|
|
13
|
+
this.holds = 0;
|
|
14
|
+
}
|
|
15
|
+
start(ms) {
|
|
16
|
+
if (ms === undefined || !(ms > 0)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
this.remaining = ms;
|
|
20
|
+
this.resume();
|
|
21
|
+
}
|
|
22
|
+
pause() {
|
|
23
|
+
if (this.timer === undefined || this.startedAt === undefined) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
clearTimeout(this.timer);
|
|
27
|
+
this.timer = undefined;
|
|
28
|
+
this.remaining = Math.max((this.remaining ?? 0) - (Date.now() - this.startedAt), 0);
|
|
29
|
+
this.startedAt = undefined;
|
|
30
|
+
this.options.paused?.(true);
|
|
31
|
+
}
|
|
32
|
+
resume() {
|
|
33
|
+
if (this.timer !== undefined || this.remaining === undefined || this.remaining <= 0) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.startedAt = Date.now();
|
|
37
|
+
this.options.paused?.(false);
|
|
38
|
+
this.timer = setTimeout(() => {
|
|
39
|
+
this.timer = undefined;
|
|
40
|
+
this.options.done();
|
|
41
|
+
}, this.remaining);
|
|
42
|
+
}
|
|
43
|
+
cancel() {
|
|
44
|
+
clearTimeout(this.timer);
|
|
45
|
+
this.timer = undefined;
|
|
46
|
+
}
|
|
47
|
+
hold() {
|
|
48
|
+
this.holds += 1;
|
|
49
|
+
this.pause();
|
|
50
|
+
}
|
|
51
|
+
release() {
|
|
52
|
+
this.holds = Math.max(this.holds - 1, 0);
|
|
53
|
+
if (this.holds === 0) {
|
|
54
|
+
this.resume();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
|
2
|
+
import { type TypeaheadBy } from '../../utils/typeahead/typeahead.js';
|
|
2
3
|
/** What a controller needs of an item to move to it and choose it. */
|
|
3
4
|
export interface NavigableItem {
|
|
4
5
|
/**
|
|
@@ -19,6 +20,8 @@ export interface NavigableItem {
|
|
|
19
20
|
/** Whether the item is the current one, which is where movement starts. */
|
|
20
21
|
selected: boolean;
|
|
21
22
|
}
|
|
23
|
+
/** Where a move starts from: the item that has focus, or the chosen item. */
|
|
24
|
+
export type KeyboardOrigin = 'focus' | 'selection';
|
|
22
25
|
/** How the controller is told what it is moving through. */
|
|
23
26
|
export interface KeyboardNavigationOptions {
|
|
24
27
|
/** The items, in the order a reader moves through them. */
|
|
@@ -35,8 +38,13 @@ export interface KeyboardNavigationOptions {
|
|
|
35
38
|
* every time. It is also the only reading that can tell a press on a tab from
|
|
36
39
|
* a press somewhere else in the component, which matters wherever the host
|
|
37
40
|
* holds more than the set (a tab panel is a tab stop of its own).
|
|
41
|
+
*
|
|
42
|
+
* A function where the answer changes with the element's state, read on every
|
|
43
|
+
* press. A read-only radio group is the case: while it is read-only the arrows
|
|
44
|
+
* move focus between radios without choosing, so the move has to start where
|
|
45
|
+
* focus is, and once it is editable again the selection is the start.
|
|
38
46
|
*/
|
|
39
|
-
origin?:
|
|
47
|
+
origin?: KeyboardOrigin | (() => KeyboardOrigin);
|
|
40
48
|
/**
|
|
41
49
|
* Whether arriving also chooses.
|
|
42
50
|
*
|
|
@@ -63,14 +71,15 @@ export interface KeyboardNavigationOptions {
|
|
|
63
71
|
*/
|
|
64
72
|
reserved?: () => string[];
|
|
65
73
|
/**
|
|
66
|
-
* The
|
|
67
|
-
*
|
|
74
|
+
* The search that turns on typeahead, built with `typeaheadBy` from the
|
|
75
|
+
* words of an item: a printable key moves to the next item whose words
|
|
76
|
+
* start with what was typed.
|
|
68
77
|
*
|
|
69
78
|
* Off unless given. A set whose items have no words a reader would type, or
|
|
70
79
|
* that holds a text field of its own, leaves it out. See `Typeahead` for how
|
|
71
80
|
* the letters are matched.
|
|
72
81
|
*/
|
|
73
|
-
typeahead?:
|
|
82
|
+
typeahead?: TypeaheadBy<NavigableItem>;
|
|
74
83
|
/**
|
|
75
84
|
* Whether the ends join up, which they do unless a set says otherwise.
|
|
76
85
|
*
|
|
@@ -91,54 +100,6 @@ export interface KeyboardNavigationOptions {
|
|
|
91
100
|
*/
|
|
92
101
|
wrap?: boolean;
|
|
93
102
|
}
|
|
94
|
-
/**
|
|
95
|
-
* Whether a press types a character, which is what typeahead reads.
|
|
96
|
-
*
|
|
97
|
-
* One character with no Control, Command or Alt held, so a shortcut such as
|
|
98
|
-
* Control+A is never taken for the letter A. Shift is allowed, because a
|
|
99
|
-
* capital is still a letter.
|
|
100
|
-
*/
|
|
101
|
-
export declare const typesCharacter: (event: KeyboardEvent) => boolean;
|
|
102
|
-
/**
|
|
103
|
-
* Finds an item by the letters a reader types at a set, the way a native
|
|
104
|
-
* `<select>` does.
|
|
105
|
-
*
|
|
106
|
-
* Letters typed within `timeout` milliseconds of each other build one search,
|
|
107
|
-
* so typing "ca" moves to "Canada" past "Cambodia". The same letter typed again
|
|
108
|
-
* moves to the next item that starts with it, so pressing "c" three times visits
|
|
109
|
-
* the first three. A pause starts a new search.
|
|
110
|
-
*
|
|
111
|
-
* Matching ignores case and leading spaces, and searches from the reader's
|
|
112
|
-
* position, wrapping at the end. A search that matches nothing moves nothing.
|
|
113
|
-
*
|
|
114
|
-
* Holds only the letters, so one instance serves any set: the caller passes the
|
|
115
|
-
* words of the items and where the reader is on every key.
|
|
116
|
-
*/
|
|
117
|
-
export declare class Typeahead {
|
|
118
|
-
private letters;
|
|
119
|
-
private last;
|
|
120
|
-
private readonly timeout;
|
|
121
|
-
constructor({ timeout }?: {
|
|
122
|
-
timeout?: number;
|
|
123
|
-
});
|
|
124
|
-
/**
|
|
125
|
-
* Whether a search is under way.
|
|
126
|
-
*
|
|
127
|
-
* A set that chooses on Space asks this first, because a Space typed in the
|
|
128
|
-
* middle of a search is part of the words, as in "New York".
|
|
129
|
-
*/
|
|
130
|
-
typing(now?: number): boolean;
|
|
131
|
-
/**
|
|
132
|
-
* Adds a character to the search, and returns the index of the item it
|
|
133
|
-
* matches, or `-1` where none does.
|
|
134
|
-
*
|
|
135
|
-
* `texts` are the words of the items a reader can reach, in order, and
|
|
136
|
-
* `from` is the index of the item the reader is on, or `-1`.
|
|
137
|
-
*/
|
|
138
|
-
match(key: string, texts: readonly string[], from: number, now?: number): number;
|
|
139
|
-
/** Ends the search, so the next letter starts a new one. */
|
|
140
|
-
reset(): void;
|
|
141
|
-
}
|
|
142
103
|
/**
|
|
143
104
|
* Moves through a set of items with the arrow keys, and chooses as it goes.
|
|
144
105
|
*
|
|
@@ -164,9 +125,10 @@ export declare class Typeahead {
|
|
|
164
125
|
* Disabled items are skipped rather than stopped at, so a set with a gap in it
|
|
165
126
|
* still moves in one press.
|
|
166
127
|
*
|
|
167
|
-
* **Typeahead is opt-in.** Pass `typeahead
|
|
168
|
-
* item's words, and a printable key moves to the next
|
|
169
|
-
* with the letters typed, choosing it where arriving
|
|
128
|
+
* **Typeahead is opt-in.** Pass `typeahead`, built by `typeaheadBy` from a
|
|
129
|
+
* function that returns an item's words, and a printable key moves to the next
|
|
130
|
+
* item whose words start with the letters typed, choosing it where arriving
|
|
131
|
+
* chooses. A key that a text
|
|
170
132
|
* field inside the set is typing into is left to the field.
|
|
171
133
|
*
|
|
172
134
|
* A set that starts from focus rather than from the selection, or that moves
|
|
@@ -176,13 +138,14 @@ export declare class Typeahead {
|
|
|
176
138
|
export declare class KeyboardNavigationController implements ReactiveController {
|
|
177
139
|
private readonly host;
|
|
178
140
|
private readonly items;
|
|
179
|
-
private readonly
|
|
141
|
+
private readonly originOf;
|
|
180
142
|
private readonly selects;
|
|
181
143
|
private readonly reserved;
|
|
182
144
|
private readonly wrap;
|
|
183
|
-
private readonly words;
|
|
184
145
|
private readonly typeahead;
|
|
185
146
|
constructor(host: ReactiveControllerHost & HTMLElement, { items, origin, reserved, selects, typeahead, wrap, }: KeyboardNavigationOptions);
|
|
147
|
+
/** Where this press starts from, read again on every press. */
|
|
148
|
+
private get origin();
|
|
186
149
|
/** Moves to an item, and chooses it where arriving is choosing. */
|
|
187
150
|
private arrive;
|
|
188
151
|
/**
|
|
@@ -1,41 +1,9 @@
|
|
|
1
1
|
import { inlineStep } from '../../utils/inline-step/inline-step.js';
|
|
2
2
|
import { keyClaimed } from '../../utils/key-claimed/key-claimed.js';
|
|
3
|
+
import { typesCharacter } from '../../utils/typeahead/typeahead.js';
|
|
3
4
|
const KEYS = new Set(['ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'End', 'Home']);
|
|
4
|
-
export const typesCharacter = (event) => event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
5
|
-
export class Typeahead {
|
|
6
|
-
constructor({ timeout = 500 } = {}) {
|
|
7
|
-
this.letters = '';
|
|
8
|
-
this.last = 0;
|
|
9
|
-
this.timeout = timeout;
|
|
10
|
-
}
|
|
11
|
-
typing(now = Date.now()) {
|
|
12
|
-
return this.letters !== '' && now - this.last <= this.timeout;
|
|
13
|
-
}
|
|
14
|
-
match(key, texts, from, now = Date.now()) {
|
|
15
|
-
if (!this.typing(now)) {
|
|
16
|
-
this.letters = '';
|
|
17
|
-
}
|
|
18
|
-
this.last = now;
|
|
19
|
-
this.letters += key.toLowerCase();
|
|
20
|
-
const words = texts.map((text) => text.trim().toLowerCase());
|
|
21
|
-
const repeated = [...this.letters].every((letter) => letter === this.letters[0]);
|
|
22
|
-
const needle = repeated ? (this.letters[0] ?? '') : this.letters;
|
|
23
|
-
const start = repeated ? from + 1 : Math.max(from, 0);
|
|
24
|
-
for (let step = 0; step < words.length; step += 1) {
|
|
25
|
-
const at = (start + step) % words.length;
|
|
26
|
-
if (words[at]?.startsWith(needle)) {
|
|
27
|
-
return at;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return -1;
|
|
31
|
-
}
|
|
32
|
-
reset() {
|
|
33
|
-
this.letters = '';
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
5
|
export class KeyboardNavigationController {
|
|
37
6
|
constructor(host, { items, origin = 'selection', reserved = () => [], selects = () => true, typeahead, wrap = true, }) {
|
|
38
|
-
this.typeahead = new Typeahead();
|
|
39
7
|
this.handleKeydown = (event) => {
|
|
40
8
|
if (!KEYS.has(event.key)) {
|
|
41
9
|
this.handleTypeahead(event);
|
|
@@ -76,18 +44,21 @@ export class KeyboardNavigationController {
|
|
|
76
44
|
next = last;
|
|
77
45
|
}
|
|
78
46
|
event.preventDefault();
|
|
79
|
-
this.typeahead.reset();
|
|
47
|
+
this.typeahead?.search.reset();
|
|
80
48
|
this.arrive(items[next]);
|
|
81
49
|
};
|
|
82
50
|
this.host = host;
|
|
83
51
|
this.items = items;
|
|
84
|
-
this.
|
|
52
|
+
this.originOf = typeof origin === 'function' ? origin : () => origin;
|
|
85
53
|
this.reserved = reserved;
|
|
86
54
|
this.selects = selects;
|
|
87
|
-
this.
|
|
55
|
+
this.typeahead = typeahead;
|
|
88
56
|
this.wrap = wrap;
|
|
89
57
|
host.addController(this);
|
|
90
58
|
}
|
|
59
|
+
get origin() {
|
|
60
|
+
return this.originOf();
|
|
61
|
+
}
|
|
91
62
|
arrive(target) {
|
|
92
63
|
target?.focusItem();
|
|
93
64
|
if (this.selects()) {
|
|
@@ -104,11 +75,11 @@ export class KeyboardNavigationController {
|
|
|
104
75
|
return selected < 0 ? focused : selected;
|
|
105
76
|
}
|
|
106
77
|
handleTypeahead(event) {
|
|
107
|
-
const
|
|
108
|
-
if (!
|
|
78
|
+
const typeahead = this.typeahead;
|
|
79
|
+
if (!typeahead || !typesCharacter(event) || keyClaimed(event)) {
|
|
109
80
|
return;
|
|
110
81
|
}
|
|
111
|
-
if (event.key === ' ' && !
|
|
82
|
+
if (event.key === ' ' && !typeahead.search.typing()) {
|
|
112
83
|
return;
|
|
113
84
|
}
|
|
114
85
|
const items = this.items().filter((item) => !item.disabled);
|
|
@@ -119,7 +90,7 @@ export class KeyboardNavigationController {
|
|
|
119
90
|
if (this.origin === 'focus' && from === -1) {
|
|
120
91
|
return;
|
|
121
92
|
}
|
|
122
|
-
const at =
|
|
93
|
+
const at = typeahead.search.match(event.key, items.map(typeahead.words), from);
|
|
123
94
|
event.preventDefault();
|
|
124
95
|
if (at >= 0 && at !== from) {
|
|
125
96
|
this.arrive(items[at]);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
|
2
|
+
/** What the clock reads from its host. */
|
|
3
|
+
export interface RelativeClockOptions {
|
|
4
|
+
/**
|
|
5
|
+
* When the reading drawn at `now` stops being true, as `relativeTime` and
|
|
6
|
+
* `elapsedTime` say in `next`, in milliseconds from `now`; or `undefined`
|
|
7
|
+
* where the host shows no reading, which reads nothing and schedules
|
|
8
|
+
* nothing.
|
|
9
|
+
*/
|
|
10
|
+
expires: (now: Date) => number | undefined;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The time a relative reading is drawn against, moved on when the reading
|
|
14
|
+
* would change: "3 minutes ago" becoming "4 minutes ago".
|
|
15
|
+
*
|
|
16
|
+
* **One wakeup when the words go stale, and none in between.** The reading
|
|
17
|
+
* says how long it holds, so the clock asks core's shared ticker for exactly
|
|
18
|
+
* that moment: a reading a minute old wakes once a minute, an hour old once an
|
|
19
|
+
* hour, and a date never. Every reading on the page shares the ticker's one
|
|
20
|
+
* timer. Chat Message and Format Date draw against it.
|
|
21
|
+
*
|
|
22
|
+
* **Only on a page.** A server has nobody to update a reading for, and a
|
|
23
|
+
* subscription there holds the element after its markup is sent, so off the
|
|
24
|
+
* page `tick()` reads the time and schedules nothing.
|
|
25
|
+
*/
|
|
26
|
+
export declare class RelativeClockController implements ReactiveController {
|
|
27
|
+
private readonly host;
|
|
28
|
+
private readonly options;
|
|
29
|
+
/** The time the host last drew against, in milliseconds. */
|
|
30
|
+
now: number;
|
|
31
|
+
private stop;
|
|
32
|
+
constructor(host: ReactiveControllerHost & HTMLElement, options: RelativeClockOptions);
|
|
33
|
+
hostConnected(): void;
|
|
34
|
+
hostDisconnected(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Reads the clock again, asks the host to draw against it, and schedules
|
|
37
|
+
* the next reading.
|
|
38
|
+
*
|
|
39
|
+
* The host calls it when what it reads changes, the instant or the locale,
|
|
40
|
+
* and the ticker calls it when the words go stale. A host with no reading
|
|
41
|
+
* is left as it is.
|
|
42
|
+
*/
|
|
43
|
+
tick(): void;
|
|
44
|
+
}
|