@fusion.dev/helix-headless 0.146.0 → 0.147.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 +5266 -785
- package/dist/accordion/item/accordion-item.d.ts +38 -19
- package/dist/accordion/item/accordion-item.js +31 -9
- package/dist/accordion/root/accordion-root.d.ts +8 -2
- package/dist/accordion/root/accordion-root.js +3 -3
- package/dist/announcement/root/announcement-root.d.ts +13 -4
- package/dist/announcement/root/announcement-root.js +34 -6
- package/dist/area-chart/root/area-chart-root.d.ts +18 -1
- package/dist/area-chart/root/area-chart-root.js +11 -3
- package/dist/avatar/root/avatar-root.d.ts +31 -1
- package/dist/avatar/root/avatar-root.js +11 -1
- package/dist/badge/root/badge-root.d.ts +57 -6
- package/dist/badge/root/badge-root.js +88 -5
- package/dist/bar-chart/root/bar-chart-root.js +11 -20
- package/dist/bar-chart/stack.d.ts +10 -0
- package/dist/bar-chart/stack.js +8 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
- package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
- package/dist/button/root/button-root.d.ts +24 -38
- package/dist/button/root/button-root.js +6 -37
- package/dist/button/submitter.d.ts +27 -0
- package/dist/button/submitter.js +25 -0
- package/dist/card/root/card-root.d.ts +12 -1
- package/dist/card/root/card-root.js +11 -4
- package/dist/chat/root/chat-root.d.ts +15 -1
- package/dist/chat/root/chat-root.js +11 -2
- package/dist/checkbox/root/checkbox-root.js +5 -7
- package/dist/checkbox-group/root/checkbox-group-root.js +4 -3
- package/dist/checkbox-group/select-all.d.ts +0 -6
- package/dist/checkbox-group/select-all.js +0 -5
- package/dist/code-block/root/code-block-root.d.ts +35 -14
- package/dist/code-block/root/code-block-root.js +17 -3
- package/dist/color-input/root/color-input-root.d.ts +11 -0
- package/dist/color-input/root/color-input-root.js +12 -5
- package/dist/color-picker/channels.js +1 -2
- package/dist/color-picker/root/color-picker-root.d.ts +32 -24
- package/dist/color-picker/root/color-picker-root.js +101 -51
- package/dist/color-picker/wheel.d.ts +17 -0
- package/dist/color-picker/wheel.js +6 -0
- package/dist/combobox/root/combobox-root.d.ts +13 -0
- package/dist/combobox/root/combobox-root.js +14 -1
- package/dist/command/root/command-root.d.ts +3 -1
- package/dist/command/root/command-root.js +2 -19
- package/dist/copy-button/root/copy-button-root.d.ts +16 -1
- package/dist/copy-button/root/copy-button-root.js +7 -2
- package/dist/data-table/keys.d.ts +0 -18
- package/dist/data-table/keys.js +1 -11
- package/dist/data-table/root/data-table-root.js +13 -7
- package/dist/date-input/root/date-input-root.d.ts +8 -1
- package/dist/date-input/root/date-input-root.js +8 -5
- package/dist/date-picker/root/date-picker-root.d.ts +14 -9
- package/dist/date-picker/root/date-picker-root.js +21 -16
- package/dist/description-list/item/description-list-item.d.ts +18 -4
- package/dist/description-list/item/description-list-item.js +8 -4
- package/dist/donut-chart/root/donut-chart-root.js +13 -6
- package/dist/donut-chart/slice-label.d.ts +35 -0
- package/dist/donut-chart/slice-label.js +11 -0
- package/dist/drawer/root/drawer-root.d.ts +4 -2
- package/dist/drawer/root/drawer-root.js +15 -3
- package/dist/drilldown/item/drilldown-item.d.ts +21 -1
- package/dist/drilldown/item/drilldown-item.js +39 -4
- package/dist/drilldown/root/drilldown-root.js +3 -2
- package/dist/element-events.generated.js +4 -1
- package/dist/empty/root/empty-root.d.ts +31 -1
- package/dist/empty/root/empty-root.js +26 -5
- package/dist/file-input/root/file-input-root.d.ts +34 -6
- package/dist/file-input/root/file-input-root.js +54 -19
- package/dist/file-input/status.d.ts +24 -0
- package/dist/file-input/status.js +10 -0
- package/dist/filter-input/chip/filter-chip.d.ts +23 -0
- package/dist/filter-input/chip/filter-chip.js +11 -2
- package/dist/filter-input/root/filter-input-root.d.ts +8 -0
- package/dist/filter-input/root/filter-input-root.js +17 -27
- package/dist/format-date/options.d.ts +3 -4
- package/dist/format-date/options.js +2 -2
- package/dist/format-date/root/format-date-root.d.ts +18 -1
- package/dist/format-date/root/format-date-root.js +19 -23
- package/dist/heatmap/root/buckets.d.ts +21 -0
- package/dist/heatmap/root/buckets.js +34 -0
- package/dist/heatmap/root/heatmap-root.d.ts +64 -3
- package/dist/heatmap/root/heatmap-root.js +89 -19
- package/dist/icon/index.d.ts +1 -1
- package/dist/icon/index.js +1 -1
- package/dist/icon/registry.d.ts +26 -1
- package/dist/icon/registry.js +12 -1
- package/dist/icon/root/icon-root.d.ts +13 -0
- package/dist/icon/root/icon-root.js +23 -2
- package/dist/icon/root/index.d.ts +1 -1
- package/dist/icon/root/index.js +1 -1
- package/dist/image/root/image-root.d.ts +9 -0
- package/dist/image/root/image-root.js +6 -1
- package/dist/input/root/input-root.d.ts +23 -2
- package/dist/input/root/input-root.js +12 -8
- package/dist/kbd/keys.d.ts +29 -0
- package/dist/kbd/keys.js +52 -0
- package/dist/kbd/root/kbd-root.d.ts +20 -3
- package/dist/kbd/root/kbd-root.js +24 -50
- package/dist/legend/hidden-series.d.ts +10 -2
- package/dist/legend/hidden-series.js +5 -2
- package/dist/legend/root/legend-root.d.ts +25 -7
- package/dist/legend/root/legend-root.js +22 -10
- package/dist/lightbox/root/lightbox-root.d.ts +50 -5
- package/dist/lightbox/root/lightbox-root.js +76 -8
- package/dist/lightbox/zoom.d.ts +2 -0
- package/dist/lightbox/zoom.js +5 -3
- package/dist/line-chart/root/line-chart-root.d.ts +16 -0
- package/dist/line-chart/root/line-chart-root.js +10 -2
- package/dist/list/root/list-root.d.ts +10 -2
- package/dist/list/root/list-root.js +26 -5
- package/dist/list/selection.d.ts +17 -0
- package/dist/list/selection.js +16 -0
- package/dist/listbox/root/listbox-root.d.ts +9 -5
- package/dist/listbox/root/listbox-root.js +29 -37
- package/dist/megamenu/hand-over.d.ts +75 -0
- package/dist/megamenu/hand-over.js +67 -0
- package/dist/megamenu/root/megamenu-root.d.ts +38 -14
- package/dist/megamenu/root/megamenu-root.js +36 -50
- package/dist/menu/item/menu-item.js +4 -4
- package/dist/menu/root/menu-root.d.ts +3 -0
- package/dist/meter/root/meter-root.d.ts +42 -0
- package/dist/meter/root/meter-root.js +33 -7
- package/dist/notifications/root/notifications-root.d.ts +10 -1
- package/dist/notifications/root/notifications-root.js +11 -1
- package/dist/number-input/grain.d.ts +28 -0
- package/dist/number-input/grain.js +14 -0
- package/dist/number-input/root/number-input-root.d.ts +17 -1
- package/dist/number-input/root/number-input-root.js +29 -18
- package/dist/object-inspector/root/object-inspector-root.d.ts +13 -6
- package/dist/object-inspector/root/object-inspector-root.js +18 -17
- package/dist/option/index.d.ts +1 -0
- package/dist/option/index.js +1 -0
- package/dist/option/separator/option-separator.d.ts +30 -0
- package/dist/option/separator/option-separator.js +21 -0
- package/dist/outline/root/outline-root.d.ts +12 -0
- package/dist/outline/root/outline-root.js +5 -19
- package/dist/pagination/size/pagination-size.d.ts +5 -0
- package/dist/pagination/size/pagination-size.js +4 -2
- package/dist/pin-input/code.d.ts +28 -1
- package/dist/pin-input/code.js +12 -0
- package/dist/pin-input/root/pin-input-root.d.ts +98 -121
- package/dist/pin-input/root/pin-input-root.js +157 -148
- package/dist/popover/hide-outside.js +2 -9
- package/dist/popover/root/popover-root.d.ts +7 -1
- package/dist/popover/root/popover-root.js +9 -1
- package/dist/progress/root/progress-root.d.ts +27 -0
- package/dist/progress/root/progress-root.js +25 -7
- package/dist/qr-code/export.d.ts +19 -0
- package/dist/qr-code/export.js +14 -0
- package/dist/qr-code/name.d.ts +11 -0
- package/dist/qr-code/name.js +7 -0
- package/dist/qr-code/root/qr-code-root.d.ts +17 -6
- package/dist/qr-code/root/qr-code-root.js +10 -12
- package/dist/radio/group/radio-group.d.ts +15 -0
- package/dist/radio/root/radio-root.js +2 -2
- package/dist/rating/root/rating-root.d.ts +22 -9
- package/dist/rating/root/rating-root.js +15 -39
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +30 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +34 -7
- package/dist/scroll-area/scrollbar.d.ts +0 -8
- package/dist/scroll-area/scrollbar.js +1 -1
- package/dist/select/align.d.ts +47 -0
- package/dist/select/align.js +7 -0
- package/dist/select/root/select-root.d.ts +59 -3
- package/dist/select/root/select-root.js +72 -12
- package/dist/slider/root/slider-root.d.ts +18 -1
- package/dist/slider/root/slider-root.js +22 -0
- package/dist/sparkline/readings.d.ts +30 -12
- package/dist/sparkline/readings.js +32 -15
- package/dist/sparkline/root/sparkline-root.d.ts +46 -3
- package/dist/sparkline/root/sparkline-root.js +60 -21
- package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
- package/dist/speed-dial/item/speed-dial-item.js +2 -2
- package/dist/speed-dial/root/speed-dial-root.d.ts +6 -0
- package/dist/speed-dial/root/speed-dial-root.js +9 -1
- package/dist/splitter/root/splitter-root.d.ts +3 -0
- package/dist/splitter/root/splitter-root.js +2 -0
- package/dist/steps/root/steps-root.d.ts +8 -1
- package/dist/steps/root/steps-root.js +6 -1
- package/dist/steps/step/step.d.ts +1 -0
- package/dist/steps/step/step.js +1 -1
- package/dist/table/column/table-column.d.ts +6 -0
- package/dist/table/column/table-column.js +5 -1
- package/dist/table/root/table-root.js +13 -6
- package/dist/table/row/table-row.d.ts +24 -0
- package/dist/table/row/table-row.js +37 -1
- package/dist/tabs/root/tabs-root.d.ts +5 -3
- package/dist/tag/group/tag-group.d.ts +16 -4
- package/dist/tag/group/tag-group.js +19 -7
- package/dist/textarea/root/textarea-root.d.ts +14 -2
- package/dist/textarea/root/textarea-root.js +6 -7
- package/dist/time-input/root/time-input-root.d.ts +5 -1
- package/dist/time-input/root/time-input-root.js +10 -7
- package/dist/time-picker/root/time-picker-root.d.ts +11 -14
- package/dist/time-picker/root/time-picker-root.js +15 -23
- package/dist/toast/item/toast-item.d.ts +3 -3
- package/dist/toast/item/toast-item.js +0 -1
- package/dist/toast/root/toast-root.d.ts +28 -4
- package/dist/toast/root/toast-root.js +58 -12
- package/dist/toast/words.d.ts +12 -0
- package/dist/toast/words.js +25 -0
- package/dist/toggle/group/toggle-group.d.ts +29 -5
- package/dist/toggle/group/toggle-group.js +26 -41
- package/dist/toggle/root/toggle-root.js +2 -4
- package/dist/toolbar/root/toolbar-root.d.ts +21 -5
- package/dist/toolbar/root/toolbar-root.js +52 -8
- package/dist/tooltip/root/tooltip-root.d.ts +7 -1
- package/dist/tooltip/root/tooltip-root.js +10 -1
- package/dist/tour/root/tour-root.d.ts +15 -0
- package/dist/tour/root/tour-root.js +20 -1
- package/dist/tour/stop/tour-stop.d.ts +3 -0
- package/dist/tour/stop/tour-stop.js +3 -3
- package/dist/tree/root/tree-root.js +2 -2
- package/dist/trend/figure.d.ts +16 -0
- package/dist/trend/figure.js +8 -0
- package/dist/trend/root/trend-root.d.ts +41 -2
- package/dist/trend/root/trend-root.js +29 -3
- package/dist/video/root/extra-controls.d.ts +12 -0
- package/dist/video/root/extra-controls.js +6 -2
- package/dist/video/root/video-root.d.ts +5 -1
- package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
- package/dist/video-playlist/root/video-playlist-root.js +3 -0
- package/dist/virtual-list/fill.d.ts +11 -0
- package/dist/virtual-list/fill.js +9 -0
- package/dist/virtual-list/keys.d.ts +16 -7
- package/dist/virtual-list/keys.js +17 -6
- package/dist/virtual-list/plan.d.ts +17 -1
- package/dist/virtual-list/plan.js +13 -2
- package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
- package/dist/virtual-list/root/virtual-list-root.js +48 -24
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +2979 -738
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +619 -202
- package/dist/color-picker/swatches.d.ts +0 -12
- package/dist/color-picker/swatches.js +0 -26
- package/dist/rating/steps.d.ts +0 -7
- package/dist/rating/steps.js +0 -9
|
@@ -40,6 +40,12 @@ declare const HelixHeadlessTour_base: (new (...args: any[]) => import("@fusion.d
|
|
|
40
40
|
* you have moved it somewhere else on the page. A stop does not trap focus, so
|
|
41
41
|
* you can still `Tab` out to the element it describes.
|
|
42
42
|
*
|
|
43
|
+
* **The arrow keys move between stops** while focus is in one: the arrow that
|
|
44
|
+
* points the way the line runs goes on, and the other goes back, so on a
|
|
45
|
+
* right-to-left page `ArrowLeft` goes on. Neither finishes the tour at the last
|
|
46
|
+
* stop, and a text field in a stop keeps its own arrows. `Escape` skips the
|
|
47
|
+
* tour.
|
|
48
|
+
*
|
|
43
49
|
* @since 0.1.0
|
|
44
50
|
* @status stable
|
|
45
51
|
* @category overlays
|
|
@@ -159,6 +165,15 @@ export declare class HelixHeadlessTour extends HelixHeadlessTour_base {
|
|
|
159
165
|
private finish;
|
|
160
166
|
private move;
|
|
161
167
|
private readonly handleAsk;
|
|
168
|
+
/**
|
|
169
|
+
* The arrow along the line, from inside a stop: on, or back.
|
|
170
|
+
*
|
|
171
|
+
* A move and never a finish, so a reader walking the stops with the arrows
|
|
172
|
+
* cannot end the tour by going one too far; that is Next on the last stop.
|
|
173
|
+
*/
|
|
174
|
+
private readonly handleArrows;
|
|
175
|
+
/** Whether `back()` would move, there being a stop that shows before this one. */
|
|
176
|
+
private get canGoBack();
|
|
162
177
|
private readonly handleKeydown;
|
|
163
178
|
private readonly handleViewport;
|
|
164
179
|
connectedCallback(): void;
|
|
@@ -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 { controlsIn, customElement, deepActiveElement, deepContains, fillTemplate, HelixActivateEvent, HelixBeforeActivateEvent, HelixCompleteEvent, HelixElement, HelixTourStatusEvent, hostAria, MixinControllerOpen, requestChange, whenHydrated, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { controlsIn, customElement, deepActiveElement, deepContains, fillTemplate, HelixActivateEvent, HelixBeforeActivateEvent, HelixCompleteEvent, HelixElement, HelixTourStatusEvent, hostAria, inlineStep, keyClaimed, MixinControllerOpen, requestChange, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property, queryAssignedElements, state } from 'lit/decorators.js';
|
|
10
10
|
import { stopBefore } from '../back.js';
|
|
@@ -36,6 +36,20 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
|
|
|
36
36
|
this.skip();
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
|
+
this.handleArrows = (event) => {
|
|
40
|
+
if (!this.open || keyClaimed(event) || event.altKey || event.ctrlKey || event.metaKey) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const along = inlineStep(this, event.key);
|
|
44
|
+
if (along === 1 && this.index < this.length - 1) {
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
this.next();
|
|
47
|
+
}
|
|
48
|
+
else if (along === -1 && this.canGoBack) {
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
this.back();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
39
53
|
this.handleKeydown = (event) => {
|
|
40
54
|
if (this.open && event.key === 'Escape' && !event.defaultPrevented) {
|
|
41
55
|
event.preventDefault();
|
|
@@ -99,9 +113,13 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
|
|
|
99
113
|
this.dispatchEvent(new HelixActivateEvent({ value: String(this.index) }));
|
|
100
114
|
}
|
|
101
115
|
}
|
|
116
|
+
get canGoBack() {
|
|
117
|
+
return (stopBefore(this.stops.map((stop) => stop.type), this.index) !== undefined);
|
|
118
|
+
}
|
|
102
119
|
connectedCallback() {
|
|
103
120
|
super.connectedCallback();
|
|
104
121
|
this.addEventListener('helix-tour-ask', this.handleAsk);
|
|
122
|
+
this.addEventListener('keydown', this.handleArrows);
|
|
105
123
|
document.addEventListener('keydown', this.handleKeydown);
|
|
106
124
|
window.addEventListener('resize', this.handleViewport, { passive: true });
|
|
107
125
|
window.addEventListener('scroll', this.handleViewport, { capture: true, passive: true });
|
|
@@ -112,6 +130,7 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
|
|
|
112
130
|
disconnectedCallback() {
|
|
113
131
|
super.disconnectedCallback();
|
|
114
132
|
this.removeEventListener('helix-tour-ask', this.handleAsk);
|
|
133
|
+
this.removeEventListener('keydown', this.handleArrows);
|
|
115
134
|
document.removeEventListener('keydown', this.handleKeydown);
|
|
116
135
|
window.removeEventListener('resize', this.handleViewport);
|
|
117
136
|
window.removeEventListener('scroll', this.handleViewport, { capture: true });
|
|
@@ -62,6 +62,7 @@ import '../../button/index.js';
|
|
|
62
62
|
* @csspart back - The control that goes to the previous stop.
|
|
63
63
|
* @csspart back-button - The button inside `back`.
|
|
64
64
|
* @csspart back-live - The live region inside `back`.
|
|
65
|
+
* @csspart back-spinner - The ring `back` turns while it is pending.
|
|
65
66
|
* @csspart back-text - The words on that button, trimmed to their capitals and baseline.
|
|
66
67
|
* @csspart bubble - The panel that points at the target.
|
|
67
68
|
* @csspart content - The region holding the slotted content.
|
|
@@ -70,11 +71,13 @@ import '../../button/index.js';
|
|
|
70
71
|
* @csspart next - The control that goes to the next stop, and finishes the tour on the last stop.
|
|
71
72
|
* @csspart next-button - The button inside `next`.
|
|
72
73
|
* @csspart next-live - The live region inside `next`.
|
|
74
|
+
* @csspart next-spinner - The ring `next` turns while it is pending.
|
|
73
75
|
* @csspart next-text - The words on that button, trimmed to their capitals and baseline.
|
|
74
76
|
* @csspart progress - The stop's place in the tour, such as "2 of 5". It describes the panel, and is shown when the tour has `progress`.
|
|
75
77
|
* @csspart skip - The control that ends the tour early.
|
|
76
78
|
* @csspart skip-button - The button inside `skip`.
|
|
77
79
|
* @csspart skip-live - The live region inside `skip`.
|
|
80
|
+
* @csspart skip-spinner - The ring `skip` turns while it is pending.
|
|
78
81
|
* @csspart skip-text - The words on that button, trimmed to their capitals and baseline.
|
|
79
82
|
*
|
|
80
83
|
* @cssstate placed-bottom - The panel sits below its target.
|
|
@@ -86,14 +86,14 @@ let HelixHeadlessTourStop = class HelixHeadlessTourStop extends HelixElement {
|
|
|
86
86
|
return html `<slot name="actions">
|
|
87
87
|
<${this.tag('button')}
|
|
88
88
|
part="skip"
|
|
89
|
-
exportparts="button: skip-button, live: skip-live, text: skip-text" emphasis="ghost" @click=${() => this.ask('skip')}>
|
|
89
|
+
exportparts="button: skip-button, live: skip-live, spinner: skip-spinner, text: skip-text" emphasis="ghost" @click=${() => this.ask('skip')}>
|
|
90
90
|
${this.skipLabel}
|
|
91
91
|
</${this.tag('button')}>
|
|
92
92
|
${this.first
|
|
93
93
|
? ''
|
|
94
94
|
: html `<${this.tag('button')}
|
|
95
95
|
part="back"
|
|
96
|
-
exportparts="button: back-button, live: back-live, text: back-text"
|
|
96
|
+
exportparts="button: back-button, live: back-live, spinner: back-spinner, text: back-text"
|
|
97
97
|
emphasis="outlined"
|
|
98
98
|
@click=${() => this.ask('back')}
|
|
99
99
|
>
|
|
@@ -101,7 +101,7 @@ let HelixHeadlessTourStop = class HelixHeadlessTourStop extends HelixElement {
|
|
|
101
101
|
</${this.tag('button')}>`}
|
|
102
102
|
<${this.tag('button')}
|
|
103
103
|
part="next"
|
|
104
|
-
exportparts="button: next-button, live: next-live, text: next-text"
|
|
104
|
+
exportparts="button: next-button, live: next-live, spinner: next-spinner, text: next-text"
|
|
105
105
|
emphasis="solid"
|
|
106
106
|
tone="primary"
|
|
107
107
|
@click=${() => this.ask('next')}
|
|
@@ -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 { AriaForwardController, closestInstance, commaList, customElement, HelixElement, inlineStep, keyClaimed, MixinCollection, MixinControllerActive, scrollItemIntoView, slottedWords, Typeahead, treeArrow, typesCharacter, whenHydrated, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, closestInstance, commaList, customElement, HelixElement, inlineStep, keyClaimed, MixinCollection, MixinControllerActive, scrollItemIntoView, selectsAll, slottedWords, Typeahead, treeArrow, typesCharacter, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessTreeItem } from '../item/tree-item.js';
|
|
@@ -217,7 +217,7 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
217
217
|
return true;
|
|
218
218
|
}
|
|
219
219
|
handleMultiple(current, event) {
|
|
220
|
-
if ((event
|
|
220
|
+
if (selectsAll(event)) {
|
|
221
221
|
const leaves = this.items
|
|
222
222
|
.filter((item) => !this.holds(item) && !item.disabled && item.value !== '')
|
|
223
223
|
.map((item) => item.value);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The movement a signed change makes: `up` above zero, `down` below it and
|
|
3
|
+
* `neutral` at zero. Nothing for a value that is no number, so a trend with
|
|
4
|
+
* none falls back to what its attributes say.
|
|
5
|
+
*/
|
|
6
|
+
export declare const movementOf: (value: number | undefined) => 'down' | 'neutral' | 'up' | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* A change written in a locale with `Intl.NumberFormat` options, such as
|
|
9
|
+
* `12%` for 0.12 with `{ style: 'percent' }`.
|
|
10
|
+
*
|
|
11
|
+
* **The size of the change, with no sign**, because the movement is already
|
|
12
|
+
* said by the arrow and the word: "Down, worse 8%" rather than "Down, worse
|
|
13
|
+
* -8%". Options that set `signDisplay` ask for the sign, and get the value as
|
|
14
|
+
* it is.
|
|
15
|
+
*/
|
|
16
|
+
export declare const figureOf: (value: number, locale?: string, options?: Intl.NumberFormatOptions) => string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { formatNumber } from '@fusion.dev/helix-core';
|
|
2
|
+
export const movementOf = (value) => {
|
|
3
|
+
if (value === undefined || !Number.isFinite(value)) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
return value > 0 ? 'up' : value < 0 ? 'down' : 'neutral';
|
|
7
|
+
};
|
|
8
|
+
export const figureOf = (value, locale = '', options) => formatNumber(options?.signDisplay === undefined ? Math.abs(value) : value, locale, options);
|
|
@@ -21,6 +21,12 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
21
21
|
* `worse-label`, so a page in another language can set its own. The arrow and
|
|
22
22
|
* any glyph slotted in its place are hidden from screen readers.
|
|
23
23
|
*
|
|
24
|
+
* **Or give the change as a number.** `value` is the signed change, such as
|
|
25
|
+
* `0.12` or `-8`: its sign is the movement, and its size is written as the
|
|
26
|
+
* metric with `Intl.NumberFormat`, in `locale` and with `format-options`,
|
|
27
|
+
* such as `{"style":"percent"}` for `12%`. `movement` still wins when it is
|
|
28
|
+
* written. Without `value` the metric is what the page slots.
|
|
29
|
+
*
|
|
24
30
|
* Slot one glyph per movement into `up-icon`, `down-icon` and `neutral-icon`,
|
|
25
31
|
* and the trend shows the one that matches; a glyph in `icon` stands in for
|
|
26
32
|
* all three. Inside a `Stat`, put the trend in the stat's `trend` slot so it is
|
|
@@ -36,7 +42,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
36
42
|
* @aliases Delta, Change, Movement
|
|
37
43
|
* @documentation https://fusion.dev/helix/components/trend
|
|
38
44
|
*
|
|
39
|
-
* @slot - The metric that moved.
|
|
45
|
+
* @slot - The metric that moved. Not needed with `value`, which writes it.
|
|
40
46
|
* @slot down-icon - Replaces the arrow while `movement` is `down`. Hidden from screen readers.
|
|
41
47
|
* @slot icon - Replaces the arrow for every movement, such as with a glyph of your own set. Hidden from screen readers, since the movement is also a word.
|
|
42
48
|
* @slot label - The period the metric moved over.
|
|
@@ -45,6 +51,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
45
51
|
*
|
|
46
52
|
* @csspart direction - The movement as a word, for people who cannot see the arrow.
|
|
47
53
|
* @csspart icon - The arrow.
|
|
54
|
+
* @csspart value - The change written from `value`, hidden while `value` is no number.
|
|
48
55
|
*
|
|
49
56
|
* @cssstate better - The trend moved the way `good` names.
|
|
50
57
|
* @cssstate worse - The trend moved against the way `good` names.
|
|
@@ -66,6 +73,20 @@ export declare class HelixHeadlessTrend extends HelixElement {
|
|
|
66
73
|
* The word read out for a move down.
|
|
67
74
|
*/
|
|
68
75
|
downLabel: string;
|
|
76
|
+
/**
|
|
77
|
+
* `Intl.NumberFormat` options `value` is written with, as React Aria's
|
|
78
|
+
* NumberField takes them: a percent, a currency, a unit or a number of
|
|
79
|
+
* decimals. Written as JSON in the attribute.
|
|
80
|
+
*
|
|
81
|
+
* ```html
|
|
82
|
+
* <helix-trend value="-0.084" format-options='{"style":"percent","maximumFractionDigits":1}'></helix-trend>
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* The example says "Down 8.4%". The size is written without a sign, since
|
|
86
|
+
* the arrow and the word say which way; set `signDisplay` for one. Absent
|
|
87
|
+
* writes the number as the locale writes any number.
|
|
88
|
+
*/
|
|
89
|
+
formatOptions?: Intl.NumberFormatOptions;
|
|
69
90
|
/**
|
|
70
91
|
* Which movement counts as an improvement for this metric.
|
|
71
92
|
*
|
|
@@ -75,6 +96,13 @@ export declare class HelixHeadlessTrend extends HelixElement {
|
|
|
75
96
|
* movement changes underneath.
|
|
76
97
|
*/
|
|
77
98
|
good?: 'down' | 'up';
|
|
99
|
+
/**
|
|
100
|
+
* The locale `value` is written in, such as `de` for `1.234,5`.
|
|
101
|
+
*
|
|
102
|
+
* Absent uses the runtime's own. Set it on a page rendered on a server, so
|
|
103
|
+
* the server and the browser write the figure alike.
|
|
104
|
+
*/
|
|
105
|
+
locale: string;
|
|
78
106
|
/**
|
|
79
107
|
* Which way the measurement moved.
|
|
80
108
|
*
|
|
@@ -94,6 +122,16 @@ export declare class HelixHeadlessTrend extends HelixElement {
|
|
|
94
122
|
* The word read out for a move up.
|
|
95
123
|
*/
|
|
96
124
|
upLabel: string;
|
|
125
|
+
/**
|
|
126
|
+
* The change as a signed number, such as `0.12` or `-8`, which sets the
|
|
127
|
+
* movement by its sign and is written as the metric.
|
|
128
|
+
*
|
|
129
|
+
* Above zero is up, below is down, and zero is neutral; `movement` wins when
|
|
130
|
+
* both are written. The size is written in the `value` part with
|
|
131
|
+
* `format-options` and `locale`, in place of a slotted metric. Absent leaves
|
|
132
|
+
* the movement to `movement` and the metric to the slot.
|
|
133
|
+
*/
|
|
134
|
+
value?: number;
|
|
97
135
|
/**
|
|
98
136
|
* The word read out after the direction when the move is a setback.
|
|
99
137
|
*/
|
|
@@ -110,10 +148,11 @@ export declare class HelixHeadlessTrend extends HelixElement {
|
|
|
110
148
|
content: string;
|
|
111
149
|
viewBox: string;
|
|
112
150
|
}): TemplateResult;
|
|
113
|
-
/** The movement, read from `movement
|
|
151
|
+
/** The movement, read from `movement`, then from the old `direction`, then from the sign of `value`. */
|
|
114
152
|
private get moved();
|
|
115
153
|
/** Better or worse, or neither when `good` is unset or nothing moved. */
|
|
116
154
|
private get judged();
|
|
155
|
+
protected updated(changed: PropertyValues): void;
|
|
117
156
|
protected willUpdate(changed: PropertyValues): void;
|
|
118
157
|
protected render(): TemplateResult;
|
|
119
158
|
}
|
|
@@ -4,11 +4,12 @@ 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, HelixElement } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, reportRuntime } from '@fusion.dev/helix-core';
|
|
8
8
|
import { arrowDown, arrowUp, minus } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
11
11
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
|
+
import { figureOf, movementOf } from '../figure.js';
|
|
12
13
|
const DIRECTIONS = {
|
|
13
14
|
down: { icon: arrowDown, word: 'downLabel' },
|
|
14
15
|
neutral: { icon: minus, word: 'unchangedLabel' },
|
|
@@ -20,6 +21,7 @@ let HelixHeadlessTrend = class HelixHeadlessTrend extends HelixElement {
|
|
|
20
21
|
super(...arguments);
|
|
21
22
|
this.betterLabel = 'better';
|
|
22
23
|
this.downLabel = 'Down';
|
|
24
|
+
this.locale = '';
|
|
23
25
|
this.unchangedLabel = 'Unchanged';
|
|
24
26
|
this.upLabel = 'Up';
|
|
25
27
|
this.worseLabel = 'worse';
|
|
@@ -38,7 +40,7 @@ let HelixHeadlessTrend = class HelixHeadlessTrend extends HelixElement {
|
|
|
38
40
|
>`;
|
|
39
41
|
}
|
|
40
42
|
get moved() {
|
|
41
|
-
return this.movement ?? this.direction;
|
|
43
|
+
return this.movement ?? this.direction ?? movementOf(this.value);
|
|
42
44
|
}
|
|
43
45
|
get judged() {
|
|
44
46
|
const moved = this.moved;
|
|
@@ -47,6 +49,17 @@ let HelixHeadlessTrend = class HelixHeadlessTrend extends HelixElement {
|
|
|
47
49
|
}
|
|
48
50
|
return this.good === moved ? 'better' : 'worse';
|
|
49
51
|
}
|
|
52
|
+
updated(changed) {
|
|
53
|
+
super.updated(changed);
|
|
54
|
+
if (changed.has('direction') && this.direction && changed.get('direction') === undefined) {
|
|
55
|
+
reportRuntime({
|
|
56
|
+
kind: 'deprecated',
|
|
57
|
+
message: `<${this.localName} direction="${this.direction}"> is deprecated: write ` +
|
|
58
|
+
`movement="${this.direction}", which says the same. \`direction\` is a layout on Stat and Flex.`,
|
|
59
|
+
tag: this.localName,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
50
63
|
willUpdate(changed) {
|
|
51
64
|
super.willUpdate(changed);
|
|
52
65
|
const judged = this.judged;
|
|
@@ -64,9 +77,13 @@ let HelixHeadlessTrend = class HelixHeadlessTrend extends HelixElement {
|
|
|
64
77
|
: moved === 'down'
|
|
65
78
|
? html `<slot aria-hidden="true" name="down-icon">${icon}</slot>`
|
|
66
79
|
: html `<slot aria-hidden="true" name="neutral-icon">${icon}</slot>`;
|
|
80
|
+
const value = this.value;
|
|
81
|
+
const figure = value === undefined || !Number.isFinite(value)
|
|
82
|
+
? ''
|
|
83
|
+
: figureOf(value, this.locale, this.formatOptions);
|
|
67
84
|
return html `${glyph}
|
|
68
85
|
<span part="direction">${`${this[direction.word]}${judgment}`}</span>
|
|
69
|
-
<slot></slot>
|
|
86
|
+
<span part="value" ?hidden=${figure === ''}>${figure}</span><slot></slot>
|
|
70
87
|
<slot name="label"></slot>`;
|
|
71
88
|
}
|
|
72
89
|
};
|
|
@@ -79,9 +96,15 @@ __decorate([
|
|
|
79
96
|
__decorate([
|
|
80
97
|
property({ attribute: 'down-label' })
|
|
81
98
|
], HelixHeadlessTrend.prototype, "downLabel", void 0);
|
|
99
|
+
__decorate([
|
|
100
|
+
property({ attribute: 'format-options', type: Object })
|
|
101
|
+
], HelixHeadlessTrend.prototype, "formatOptions", void 0);
|
|
82
102
|
__decorate([
|
|
83
103
|
property({ reflect: true })
|
|
84
104
|
], HelixHeadlessTrend.prototype, "good", void 0);
|
|
105
|
+
__decorate([
|
|
106
|
+
property()
|
|
107
|
+
], HelixHeadlessTrend.prototype, "locale", void 0);
|
|
85
108
|
__decorate([
|
|
86
109
|
property({ reflect: true })
|
|
87
110
|
], HelixHeadlessTrend.prototype, "movement", void 0);
|
|
@@ -91,6 +114,9 @@ __decorate([
|
|
|
91
114
|
__decorate([
|
|
92
115
|
property({ attribute: 'up-label' })
|
|
93
116
|
], HelixHeadlessTrend.prototype, "upLabel", void 0);
|
|
117
|
+
__decorate([
|
|
118
|
+
property({ type: Number })
|
|
119
|
+
], HelixHeadlessTrend.prototype, "value", void 0);
|
|
94
120
|
__decorate([
|
|
95
121
|
property({ attribute: 'worse-label' })
|
|
96
122
|
], HelixHeadlessTrend.prototype, "worseLabel", void 0);
|
|
@@ -20,6 +20,18 @@ export interface Conditions {
|
|
|
20
20
|
}
|
|
21
21
|
/** Whether this platform can do a named control at all. */
|
|
22
22
|
export declare const offers: (one: string, player: Conditions) => boolean;
|
|
23
|
+
/**
|
|
24
|
+
* What `full` stands for in a list of controls: every control that does
|
|
25
|
+
* something to the video by itself, as Web Awesome's `full` preset adds speed
|
|
26
|
+
* and picture in picture to its standard bar.
|
|
27
|
+
*
|
|
28
|
+
* `download`, `previous` and `next` are left out. Offering the file is a
|
|
29
|
+
* decision about the content, and the other two move a set the player cannot
|
|
30
|
+
* see, so each is named where it is wanted.
|
|
31
|
+
*/
|
|
32
|
+
export declare const FULL_CONTROLS: readonly ['rewind', 'forward', 'speed', 'pip', 'remote'];
|
|
33
|
+
/** The names in a written list, with `full` read as the controls it stands for, each once. */
|
|
34
|
+
export declare const controlNames: (written: string) => string[];
|
|
23
35
|
/** The extras asked for, in order, and only the ones this platform can do. */
|
|
24
36
|
export declare const barControls: (written: string, player: Conditions) => string[];
|
|
25
37
|
/**
|
|
@@ -20,10 +20,14 @@ export const offers = (one, player) => {
|
|
|
20
20
|
}
|
|
21
21
|
return one === 'speed';
|
|
22
22
|
};
|
|
23
|
-
export const
|
|
23
|
+
export const FULL_CONTROLS = ['rewind', 'forward', 'speed', 'pip', 'remote'];
|
|
24
|
+
export const controlNames = (written) => [
|
|
25
|
+
...new Set(writtenList(written).flatMap((one) => one === 'full' ? FULL_CONTROLS : [one])),
|
|
26
|
+
];
|
|
27
|
+
export const barControls = (written, player) => controlNames(written).filter((one) => offers(one, player));
|
|
24
28
|
export const menuControls = (written, onBar, player) => {
|
|
25
29
|
const bar = new Set(onBar);
|
|
26
|
-
return
|
|
30
|
+
return controlNames(written).filter((one) => !bar.has(one) && offers(one, player));
|
|
27
31
|
};
|
|
28
32
|
export const ownFile = (src) => {
|
|
29
33
|
if (src === '') {
|
|
@@ -242,7 +242,11 @@ export declare class HelixHeadlessVideo extends HelixElement {
|
|
|
242
242
|
* that cannot work is worse than one that is not there.
|
|
243
243
|
*
|
|
244
244
|
* The names are `speed`, `pip`, `remote`, `download`, `rewind`, `forward`,
|
|
245
|
-
* `previous` and `next`.
|
|
245
|
+
* `previous` and `next`. `full` stands for `rewind`, `forward`, `speed`,
|
|
246
|
+
* `pip` and `remote` in that order, the controls that act on the video by
|
|
247
|
+
* themselves, as Web Awesome's `full` preset does, and a name it already
|
|
248
|
+
* holds is drawn once. `extra-controls="full"` is the whole bar, and
|
|
249
|
+
* `overflow-controls="full"` puts all of it behind one button.
|
|
246
250
|
*
|
|
247
251
|
* **`previous` and `next` do nothing to the video, and are offered anyway.**
|
|
248
252
|
* They announce `helix-previous` and `helix-next` and stop there, so what
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import { HelixHeadlessVideoPlaylistItem } from '../item/video-playlist-item.js';
|
|
3
4
|
import { type Repeat } from '../order.js';
|
|
4
5
|
declare const HelixHeadlessVideoPlaylist_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerActiveInterface) & typeof HelixElement;
|
|
5
6
|
/**
|
|
@@ -44,7 +45,7 @@ declare const HelixHeadlessVideoPlaylist_base: (new (...args: any[]) => import("
|
|
|
44
45
|
* @slot - The entries.
|
|
45
46
|
* @slot player - The player that plays the entries.
|
|
46
47
|
*
|
|
47
|
-
* @event {HelixActivateEvent} helix-activate - The current entry changed. The playlist already holds the new entry when this is sent, and `detail.previous` is the entry it left.
|
|
48
|
+
* @event {HelixActivateEvent} helix-activate - The current entry changed. The playlist already holds the new entry when this is sent, and `detail.previous` is the entry it left. `currentEntry` is the entry itself, with its `src`, `poster` and name.
|
|
48
49
|
* @event {HelixBeforeActivateEvent} helix-before-activate - The current entry is about to change. Cancelable: cancel it to keep the current entry.
|
|
49
50
|
* @event {HelixEndEvent} helix-end - The last entry finished playing, and the playlist stopped there. Not sent while `repeat` is set.
|
|
50
51
|
*
|
|
@@ -137,6 +138,15 @@ export declare class HelixHeadlessVideoPlaylist extends HelixHeadlessVideoPlayli
|
|
|
137
138
|
* under `repeat="one"` asks for, and a list of one under `repeat="all"`.
|
|
138
139
|
*/
|
|
139
140
|
private replay;
|
|
141
|
+
/**
|
|
142
|
+
* The entry that is current, with the `src`, `poster`, `value` and name the
|
|
143
|
+
* player was given, or `undefined` in an empty playlist.
|
|
144
|
+
*
|
|
145
|
+
* Read it in a `helix-activate` listener for the clip the playlist moved to,
|
|
146
|
+
* which Web Awesome's change event carries: the event says which entry by
|
|
147
|
+
* value, and this is the entry.
|
|
148
|
+
*/
|
|
149
|
+
get currentEntry(): HelixHeadlessVideoPlaylistItem | undefined;
|
|
140
150
|
/**
|
|
141
151
|
* Moves to the next entry and plays it, as the player's next control does.
|
|
142
152
|
* Follows `shuffle`, goes round under `repeat="all"`, and stays on the last
|
|
@@ -81,6 +81,9 @@ let HelixHeadlessVideoPlaylist = class HelixHeadlessVideoPlaylist extends MixinC
|
|
|
81
81
|
player.currentTime = 0;
|
|
82
82
|
void Promise.resolve(player.play()).catch(() => { });
|
|
83
83
|
}
|
|
84
|
+
get currentEntry() {
|
|
85
|
+
return this.resolveActive(this.items);
|
|
86
|
+
}
|
|
84
87
|
next() {
|
|
85
88
|
this.step(1);
|
|
86
89
|
}
|
|
@@ -20,3 +20,14 @@
|
|
|
20
20
|
export declare const textOf: (value: unknown) => string;
|
|
21
21
|
/** Fills one element's holes, its own and those below it, from an item. */
|
|
22
22
|
export declare const fillHoles: (root: Element, item: unknown) => void;
|
|
23
|
+
/**
|
|
24
|
+
* The key of item `at` in a selecting list's `value`: its `keyField` where it
|
|
25
|
+
* is an object and one is named, a string or a number item itself, and its
|
|
26
|
+
* place in the set otherwise.
|
|
27
|
+
*/
|
|
28
|
+
export declare const keyOf: (item: unknown, at: number, keyField: string) => string;
|
|
29
|
+
/**
|
|
30
|
+
* The text typing matches for each item: its `field`, or a string or number
|
|
31
|
+
* item itself, and nothing where an object has no `field` to read.
|
|
32
|
+
*/
|
|
33
|
+
export declare const textsOf: (data: readonly unknown[], field: string) => string[];
|
|
@@ -21,3 +21,12 @@ export const fillHoles = (root, item) => {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
|
+
export const keyOf = (item, at, keyField) => {
|
|
25
|
+
if (keyField !== '' && item !== null && typeof item === 'object') {
|
|
26
|
+
return textOf(valueAt(item, keyField));
|
|
27
|
+
}
|
|
28
|
+
return typeof item === 'string' || typeof item === 'number' ? String(item) : String(at);
|
|
29
|
+
};
|
|
30
|
+
export const textsOf = (data, field) => data.map((item) => field === '' || item === null || typeof item !== 'object'
|
|
31
|
+
? textOf(item)
|
|
32
|
+
: textOf(valueAt(item, field)));
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Which item a key moves to in a
|
|
2
|
+
* Which item a key moves to in a list of `count` items laid out `across`
|
|
3
|
+
* items to a line, from `at`.
|
|
3
4
|
*
|
|
4
5
|
* Index arithmetic, because most of the items are not drawn: the list moves to
|
|
5
6
|
* an index, scrolls it into view, and focuses the row once it is there. The
|
|
6
|
-
* keys are the ones a listbox answers
|
|
7
|
+
* keys are the ones a listbox answers, and in a grid the ones a grid of
|
|
8
|
+
* options answers:
|
|
7
9
|
*
|
|
8
|
-
* - Up and Down move one item.
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
* one
|
|
10
|
+
* - Up and Down move one line, to the item in the same column. Down from the
|
|
11
|
+
* line above a shorter last line goes to the last item.
|
|
12
|
+
* - Left and Right move one item, in a grid only, with `forward` naming the
|
|
13
|
+
* one that moves ahead along the line: Right, or Left on a right-to-left
|
|
14
|
+
* page. In a list they move nothing, and are left to the row.
|
|
15
|
+
* - Home and End move to the first and the last item.
|
|
16
|
+
* - Page Up and Page Down move by `page` lines, the number of lines on screen
|
|
17
|
+
* less one, so the line at one edge of the box lands at the other.
|
|
12
18
|
*
|
|
13
19
|
* `undefined` for a key the list does not take, and for an empty list.
|
|
14
20
|
*/
|
|
15
|
-
export declare const stepIndex: (key: string, at: number, count: number, page: number
|
|
21
|
+
export declare const stepIndex: (key: string, at: number, count: number, page: number, { across, forward }?: {
|
|
22
|
+
across?: number;
|
|
23
|
+
forward?: string;
|
|
24
|
+
}) => number | undefined;
|
|
@@ -1,23 +1,34 @@
|
|
|
1
|
-
export const stepIndex = (key, at, count, page) => {
|
|
1
|
+
export const stepIndex = (key, at, count, page, { across = 1, forward = 'ArrowRight' } = {}) => {
|
|
2
2
|
if (count <= 0) {
|
|
3
3
|
return undefined;
|
|
4
4
|
}
|
|
5
|
+
const width = Math.max(1, Math.trunc(across));
|
|
5
6
|
const last = count - 1;
|
|
6
7
|
const from = Math.max(0, Math.min(at, last));
|
|
7
|
-
const
|
|
8
|
+
const line = Math.floor(from / width);
|
|
9
|
+
const along = (lines) => {
|
|
10
|
+
const to = Math.max(0, Math.min(line + lines, Math.floor(last / width)));
|
|
11
|
+
return Math.min(last, to * width + (from % width));
|
|
12
|
+
};
|
|
8
13
|
switch (key) {
|
|
9
14
|
case 'ArrowDown':
|
|
10
|
-
return
|
|
15
|
+
return along(1);
|
|
11
16
|
case 'ArrowUp':
|
|
12
|
-
return
|
|
17
|
+
return along(-1);
|
|
18
|
+
case 'ArrowLeft':
|
|
19
|
+
case 'ArrowRight':
|
|
20
|
+
if (width === 1) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return Math.max(0, Math.min(last, from + (key === forward ? 1 : -1)));
|
|
13
24
|
case 'End':
|
|
14
25
|
return last;
|
|
15
26
|
case 'Home':
|
|
16
27
|
return 0;
|
|
17
28
|
case 'PageDown':
|
|
18
|
-
return Math.
|
|
29
|
+
return along(Math.max(1, page));
|
|
19
30
|
case 'PageUp':
|
|
20
|
-
return Math.max(
|
|
31
|
+
return along(-Math.max(1, page));
|
|
21
32
|
default:
|
|
22
33
|
return undefined;
|
|
23
34
|
}
|
|
@@ -27,6 +27,11 @@ export interface DrawInput {
|
|
|
27
27
|
drawn: readonly number[];
|
|
28
28
|
/** Whether every drawn row is drawn again from nothing, as for a new way of drawing. */
|
|
29
29
|
redraw?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* How many items a line holds, in a grid. The kept item brings its whole
|
|
32
|
+
* line, so the columns of the lines around it stay where they are.
|
|
33
|
+
*/
|
|
34
|
+
across?: number;
|
|
30
35
|
}
|
|
31
36
|
/**
|
|
32
37
|
* Which items a pass draws, and which drawn rows leave.
|
|
@@ -34,7 +39,7 @@ export interface DrawInput {
|
|
|
34
39
|
* A drawn row leaves when its item is not wanted, when it holds no item, or
|
|
35
40
|
* when everything is drawn again. A wanted item with no row left is drawn new.
|
|
36
41
|
*/
|
|
37
|
-
export declare const drawPlan: ({ count, drawn, first, kept, last, redraw, }: DrawInput) => DrawPlan;
|
|
42
|
+
export declare const drawPlan: ({ across, count, drawn, first, kept, last, redraw, }: DrawInput) => DrawPlan;
|
|
38
43
|
/**
|
|
39
44
|
* Which item holds the list's tab stop after a pass.
|
|
40
45
|
*
|
|
@@ -47,3 +52,14 @@ export declare const stopAfter: (active: number, wanted: readonly number[], { co
|
|
|
47
52
|
last: number;
|
|
48
53
|
onScreen: number;
|
|
49
54
|
}) => number;
|
|
55
|
+
/**
|
|
56
|
+
* The items a span of lines holds, `across` items to a line: what a window of
|
|
57
|
+
* lines draws, or which items a reader sees.
|
|
58
|
+
*/
|
|
59
|
+
export declare const itemsOf: (lines: {
|
|
60
|
+
first: number;
|
|
61
|
+
last: number;
|
|
62
|
+
}, across: number, count: number) => {
|
|
63
|
+
first: number;
|
|
64
|
+
last: number;
|
|
65
|
+
};
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
export const drawPlan = ({ count, drawn, first, kept, last, redraw = false, }) => {
|
|
1
|
+
export const drawPlan = ({ across = 1, count, drawn, first, kept, last, redraw = false, }) => {
|
|
2
2
|
const wanted = [];
|
|
3
3
|
for (let at = first; at < Math.min(last, count); at += 1) {
|
|
4
4
|
wanted.push(at);
|
|
5
5
|
}
|
|
6
6
|
if (kept !== undefined && !wanted.includes(kept)) {
|
|
7
|
-
|
|
7
|
+
const width = Math.max(1, across);
|
|
8
|
+
const start = kept - (kept % width);
|
|
9
|
+
for (let at = start; at < Math.min(start + width, count); at += 1) {
|
|
10
|
+
wanted.push(at);
|
|
11
|
+
}
|
|
8
12
|
wanted.sort((a, b) => a - b);
|
|
9
13
|
}
|
|
10
14
|
const keep = new Set(wanted);
|
|
@@ -14,3 +18,10 @@ export const drawPlan = ({ count, drawn, first, kept, last, redraw = false, }) =
|
|
|
14
18
|
export const stopAfter = (active, wanted, { count, first, last, onScreen, }) => wanted.includes(active)
|
|
15
19
|
? active
|
|
16
20
|
: Math.max(Math.min(onScreen, Math.min(last, count) - 1), first, 0);
|
|
21
|
+
export const itemsOf = (lines, across, count) => {
|
|
22
|
+
const width = Math.max(1, across);
|
|
23
|
+
return {
|
|
24
|
+
first: Math.min(lines.first * width, count),
|
|
25
|
+
last: Math.min(lines.last * width, count),
|
|
26
|
+
};
|
|
27
|
+
};
|