@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
|
@@ -4,11 +4,11 @@ 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, byRow, CHART_PLOT, customElement, drawTooltip, formatNumbers, HelixElement, HelixResizeEvent, MixinChartSource, markRegion, searchableById, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, byRow, CHART_PLOT, commaList, customElement, drawTooltip, fillTemplate, formatNumbers, HelixBeforeChangeEvent, HelixElement, HelixResizeEvent, MixinChartSource, markRegion, pressedValue, rangeAdd, requestChange, StatusController, searchableById, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
10
|
import '../../tooltip/index.js';
|
|
11
|
-
import { fits, toneOf } from './buckets.js';
|
|
11
|
+
import { fits, monthPage, overviewOf, toneOf } from './buckets.js';
|
|
12
12
|
let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(HelixElement) {
|
|
13
13
|
constructor() {
|
|
14
14
|
super(...arguments);
|
|
@@ -17,9 +17,11 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
17
17
|
this.gap = 2;
|
|
18
18
|
this.minCell = 8;
|
|
19
19
|
this.rows = 1;
|
|
20
|
+
this.selectionLabel = '{count} selected';
|
|
20
21
|
this.thresholds = '';
|
|
21
22
|
this.tones = '';
|
|
22
23
|
this.totalLabel = 'Total';
|
|
24
|
+
this.value = '';
|
|
23
25
|
this.width = undefined;
|
|
24
26
|
this.metrics = undefined;
|
|
25
27
|
this.aria = new AriaForwardController(this, {
|
|
@@ -27,6 +29,35 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
27
29
|
});
|
|
28
30
|
this.observer = undefined;
|
|
29
31
|
this.announced = undefined;
|
|
32
|
+
this.anchor = -1;
|
|
33
|
+
this.status = new StatusController(this);
|
|
34
|
+
this.onKeydown = (event) => {
|
|
35
|
+
const at = this.pointer.at;
|
|
36
|
+
if (!this.selectionMode || at < 0 || event.altKey || event.ctrlKey || event.metaKey) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (event.key === ' ' || event.key === 'Enter') {
|
|
40
|
+
event.preventDefault();
|
|
41
|
+
this.press(at);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const moves = /^(Arrow|Page|Home$|End$)/.test(event.key);
|
|
45
|
+
if (!event.shiftKey || !moves || this.selectionMode !== 'multiple') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const keys = this.keysOf(this.drawn);
|
|
49
|
+
const added = rangeAdd(commaList(this.value), keys, this.anchor < 0 ? at : this.anchor, at);
|
|
50
|
+
if (added) {
|
|
51
|
+
this.choose(added.join(', '));
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
this.onClick = (event) => {
|
|
55
|
+
const cell = event.target?.closest?.('[part~="cell"]');
|
|
56
|
+
const index = Number(cell?.getAttribute('data-index') ?? -1);
|
|
57
|
+
if (cell && Number.isInteger(index) && index >= 0) {
|
|
58
|
+
this.press(index);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
30
61
|
this.onPointerOver = (event) => {
|
|
31
62
|
if (!this.pointer.accepts(event)) {
|
|
32
63
|
return;
|
|
@@ -44,6 +75,35 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
44
75
|
get visible() {
|
|
45
76
|
return Math.min(this.points.length, this.room);
|
|
46
77
|
}
|
|
78
|
+
keysOf(cells) {
|
|
79
|
+
const offset = this.points.length - cells.length;
|
|
80
|
+
const rows = this.sourceRows;
|
|
81
|
+
return cells.map((_, index) => rows[offset + index]?.label ?? '');
|
|
82
|
+
}
|
|
83
|
+
choose(next) {
|
|
84
|
+
if (next === this.value) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
requestChange({
|
|
88
|
+
apply: (value) => {
|
|
89
|
+
this.value = value;
|
|
90
|
+
this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
|
91
|
+
this.status.say(fillTemplate(this.selectionLabel, { count: commaList(value).length }));
|
|
92
|
+
},
|
|
93
|
+
event: (value) => new HelixBeforeChangeEvent({ value }),
|
|
94
|
+
host: this,
|
|
95
|
+
next,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
press(index) {
|
|
99
|
+
const mode = this.selectionMode;
|
|
100
|
+
const key = this.keysOf(this.drawn)[index];
|
|
101
|
+
if (!mode || key === undefined || key === '') {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this.anchor = index;
|
|
105
|
+
this.choose(pressedValue(mode, this.value, key));
|
|
106
|
+
}
|
|
47
107
|
get points() {
|
|
48
108
|
const series = this.series[0];
|
|
49
109
|
if (!series) {
|
|
@@ -99,8 +159,13 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
99
159
|
super.willUpdate(changed);
|
|
100
160
|
this.pointer.grid = this.rowCount;
|
|
101
161
|
}
|
|
162
|
+
pageFrom(at, forward) {
|
|
163
|
+
const offset = this.points.length - this.drawn.length;
|
|
164
|
+
return monthPage(this.sourceRows.slice(offset).map((row) => row.when), at, forward);
|
|
165
|
+
}
|
|
102
166
|
connectedCallback() {
|
|
103
167
|
super.connectedCallback();
|
|
168
|
+
this.addEventListener('keydown', this.onKeydown);
|
|
104
169
|
if (typeof ResizeObserver !== 'undefined') {
|
|
105
170
|
this.observer = new ResizeObserver((entries) => {
|
|
106
171
|
const measured = entries[0]?.contentRect.width;
|
|
@@ -113,6 +178,7 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
113
178
|
}
|
|
114
179
|
disconnectedCallback() {
|
|
115
180
|
super.disconnectedCallback();
|
|
181
|
+
this.removeEventListener('keydown', this.onKeydown);
|
|
116
182
|
this.observer?.disconnect();
|
|
117
183
|
this.observer = undefined;
|
|
118
184
|
}
|
|
@@ -143,6 +209,8 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
143
209
|
const palette = writtenList(this.tones);
|
|
144
210
|
const cells = this.drawn;
|
|
145
211
|
const readable = cells.length > 0;
|
|
212
|
+
const keys = this.selectionMode ? this.keysOf(cells) : [];
|
|
213
|
+
const chosen = new Set(this.selectionMode ? commaList(this.value) : []);
|
|
146
214
|
return html `<div
|
|
147
215
|
aria-describedby=${readable ? 'helix-chart-summary' : nothing}
|
|
148
216
|
aria-label=${this.named || 'Heatmap'}
|
|
@@ -151,6 +219,7 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
151
219
|
role=${readable ? 'application' : 'img'}
|
|
152
220
|
style="--heatmap-rows: ${this.rowCount}"
|
|
153
221
|
tabindex=${readable ? '0' : nothing}
|
|
222
|
+
@click=${this.onClick}
|
|
154
223
|
@pointerover=${this.onPointerOver}
|
|
155
224
|
@pointerleave=${this.onPointerLeave}
|
|
156
225
|
>
|
|
@@ -159,13 +228,14 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
159
228
|
: cells.map((reading, index) => {
|
|
160
229
|
const tone = toneOf(reading, bounds, palette);
|
|
161
230
|
const active = this.pointer.at === index;
|
|
231
|
+
const picked = chosen.has(keys[index] ?? '');
|
|
162
232
|
return tone === undefined
|
|
163
233
|
? html `<span
|
|
164
|
-
part="cell${active ? ' cell-active' : ''}"
|
|
234
|
+
part="cell${active ? ' cell-active' : ''}${picked ? ' cell-selected' : ''}"
|
|
165
235
|
data-index=${index}
|
|
166
236
|
></span>`
|
|
167
237
|
: html `<span
|
|
168
|
-
part="cell${active ? ' cell-active' : ''}"
|
|
238
|
+
part="cell${active ? ' cell-active' : ''}${picked ? ' cell-selected' : ''}"
|
|
169
239
|
data-index=${index}
|
|
170
240
|
data-tone=${tone}
|
|
171
241
|
style="--heatmap-tone: var(--heatmap-tone-${tone})"
|
|
@@ -178,27 +248,18 @@ let HelixHeadlessHeatmap = class HelixHeadlessHeatmap extends MixinChartSource(H
|
|
|
178
248
|
<span part="start"><slot name="start"></slot></span>
|
|
179
249
|
<span part="summary"><slot name="summary"></slot></span>
|
|
180
250
|
<span part="end"><slot name="end"></slot></span>
|
|
181
|
-
</div>${readable ? this.renderOverview(cells) : nothing}
|
|
251
|
+
</div>${readable ? this.renderOverview(cells) : nothing}${this.status.spoken
|
|
252
|
+
? html `<span part="selection" role="status">${this.status.said}</span>`
|
|
253
|
+
: nothing}`;
|
|
182
254
|
}
|
|
183
255
|
renderOverview(cells) {
|
|
184
256
|
const rows = this.sourceRows;
|
|
185
257
|
const offset = this.points.length - cells.length;
|
|
186
258
|
const column = this.plottedColumns[0] ?? -1;
|
|
187
|
-
|
|
188
|
-
let total = 0;
|
|
189
|
-
cells.forEach((cell, index) => {
|
|
190
|
-
if (cell.value === undefined) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
total += cell.value;
|
|
194
|
-
if (busiest < 0 || cell.value > (cells[busiest]?.value ?? 0)) {
|
|
195
|
-
busiest = index;
|
|
196
|
-
}
|
|
197
|
-
});
|
|
259
|
+
const { busiest, total } = overviewOf(cells);
|
|
198
260
|
const row = rows[offset + busiest];
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
: '';
|
|
261
|
+
const text = row?.cells[column]?.text ?? '';
|
|
262
|
+
const most = row ? `${this.busiestLabel}: ${row.label}${text === '' ? '' : `, ${text}`}` : '';
|
|
202
263
|
const sum = `${this.totalLabel} ${formatNumbers(this.locale)(total)}`;
|
|
203
264
|
return html `<p id="helix-chart-summary" part="overview">${most ? `${most}; ${sum}` : sum}.</p>`;
|
|
204
265
|
}
|
|
@@ -234,6 +295,12 @@ __decorate([
|
|
|
234
295
|
__decorate([
|
|
235
296
|
property({ type: Number })
|
|
236
297
|
], HelixHeadlessHeatmap.prototype, "rows", void 0);
|
|
298
|
+
__decorate([
|
|
299
|
+
property({ attribute: 'selection-label' })
|
|
300
|
+
], HelixHeadlessHeatmap.prototype, "selectionLabel", void 0);
|
|
301
|
+
__decorate([
|
|
302
|
+
property({ attribute: 'selection-mode' })
|
|
303
|
+
], HelixHeadlessHeatmap.prototype, "selectionMode", void 0);
|
|
237
304
|
__decorate([
|
|
238
305
|
property()
|
|
239
306
|
], HelixHeadlessHeatmap.prototype, "thresholds", void 0);
|
|
@@ -243,6 +310,9 @@ __decorate([
|
|
|
243
310
|
__decorate([
|
|
244
311
|
property({ attribute: 'total-label' })
|
|
245
312
|
], HelixHeadlessHeatmap.prototype, "totalLabel", void 0);
|
|
313
|
+
__decorate([
|
|
314
|
+
property()
|
|
315
|
+
], HelixHeadlessHeatmap.prototype, "value", void 0);
|
|
246
316
|
__decorate([
|
|
247
317
|
state()
|
|
248
318
|
], HelixHeadlessHeatmap.prototype, "width", void 0);
|
package/dist/icon/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import './set.js';
|
|
2
|
-
export { type IconResolver, registerIconLibrary, registerIcons, resolveIcon } from './registry.js';
|
|
2
|
+
export { type IconLibraryOptions, type IconResolver, registerIconLibrary, registerIcons, resolveIcon, } from './registry.js';
|
|
3
3
|
export * from './root/icon-root.js';
|
package/dist/icon/index.js
CHANGED
package/dist/icon/registry.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { HelixIcon } from '@fusion.dev/helix-icons';
|
|
2
2
|
/** What a library gives for a name: a glyph, a glyph later, or nothing. */
|
|
3
3
|
export type IconResolver = (name: string) => HelixIcon | Promise<HelixIcon | undefined> | undefined;
|
|
4
|
+
/** How a library's glyphs are drawn, beside the names it resolves. */
|
|
5
|
+
export interface IconLibraryOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Changes each drawn `<svg>` of the library's glyphs, as Web Awesome's
|
|
8
|
+
* `mutator` does: a stroke width, a fill, an attribute the set leaves out.
|
|
9
|
+
* Called after every render that draws one of them.
|
|
10
|
+
*/
|
|
11
|
+
mutator?: (svg: SVGSVGElement) => void;
|
|
12
|
+
}
|
|
4
13
|
/**
|
|
5
14
|
* Makes glyphs resolvable by name: a record of names to glyphs, such as the
|
|
6
15
|
* whole set, or a list of glyphs, each under its own `name`.
|
|
@@ -15,14 +24,30 @@ export declare const registerIcons: (glyphs: Record<string, HelixIcon> | readonl
|
|
|
15
24
|
* The resolver may answer at once or with a promise; an element waiting on a
|
|
16
25
|
* promise draws the glyph when it arrives and fires `load`. Each written name
|
|
17
26
|
* is asked once, and a prefix registered again is asked afresh.
|
|
27
|
+
*
|
|
28
|
+
* A sprite sheet is a library whose glyphs point into it, so the sheet is
|
|
29
|
+
* fetched once and cached:
|
|
30
|
+
*
|
|
31
|
+
* ```js
|
|
32
|
+
* registerIconLibrary('sprite', (name) => ({
|
|
33
|
+
* content: `<use href="/icons.svg#${name}"></use>`,
|
|
34
|
+
* name,
|
|
35
|
+
* viewBox: '0 0 24 24',
|
|
36
|
+
* }))
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* `mutator` changes each drawn `<svg>` of the library, such as
|
|
40
|
+
* `(svg) => svg.setAttribute('stroke-width', '1.5')`.
|
|
18
41
|
*/
|
|
19
|
-
export declare const registerIconLibrary: (prefix: string, resolve: IconResolver) => void;
|
|
42
|
+
export declare const registerIconLibrary: (prefix: string, resolve: IconResolver, options?: IconLibraryOptions) => void;
|
|
20
43
|
/**
|
|
21
44
|
* Calls `watcher` whenever a glyph or a library is registered, so an element
|
|
22
45
|
* drawn before its glyph was registered can look again. Returns the function
|
|
23
46
|
* that stops it.
|
|
24
47
|
*/
|
|
25
48
|
export declare const watchIcons: (watcher: () => void) => (() => void);
|
|
49
|
+
/** The mutator of the library a written name asks, or `undefined`. */
|
|
50
|
+
export declare const iconMutator: (name: string) => ((svg: SVGSVGElement) => void) | undefined;
|
|
26
51
|
/** The registered glyph of this name, or `undefined`. */
|
|
27
52
|
export declare const registeredIcon: (name: string) => HelixIcon | undefined;
|
|
28
53
|
/**
|
package/dist/icon/registry.js
CHANGED
|
@@ -24,9 +24,16 @@ export const registerIcons = (glyphs) => {
|
|
|
24
24
|
}
|
|
25
25
|
changed(held);
|
|
26
26
|
};
|
|
27
|
-
export const registerIconLibrary = (prefix, resolve) => {
|
|
27
|
+
export const registerIconLibrary = (prefix, resolve, options = {}) => {
|
|
28
28
|
const held = registry();
|
|
29
29
|
held.libraries.set(prefix, resolve);
|
|
30
|
+
held.mutators ??= new Map();
|
|
31
|
+
if (options.mutator) {
|
|
32
|
+
held.mutators.set(prefix, options.mutator);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
held.mutators.delete(prefix);
|
|
36
|
+
}
|
|
30
37
|
for (const name of held.answers.keys()) {
|
|
31
38
|
if (name.startsWith(`${prefix}:`)) {
|
|
32
39
|
held.answers.delete(name);
|
|
@@ -41,6 +48,10 @@ export const watchIcons = (watcher) => {
|
|
|
41
48
|
held.watchers.delete(watcher);
|
|
42
49
|
};
|
|
43
50
|
};
|
|
51
|
+
export const iconMutator = (name) => {
|
|
52
|
+
const split = name.indexOf(':');
|
|
53
|
+
return split > 0 ? registry().mutators?.get(name.slice(0, split)) : undefined;
|
|
54
|
+
};
|
|
44
55
|
export const registeredIcon = (name) => registry().glyphs.get(name);
|
|
45
56
|
export const resolveIcon = (name) => {
|
|
46
57
|
const registered = registeredIcon(name);
|
|
@@ -36,6 +36,11 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
|
36
36
|
* button with no text. An `aria-label` on the element works too: the element
|
|
37
37
|
* is then an image with that name.
|
|
38
38
|
*
|
|
39
|
+
* **A decorative icon that is all a control holds is reported.** In a
|
|
40
|
+
* development build, a button or a link whose only content is an icon with no
|
|
41
|
+
* `label`, and which has no name of its own, warns `missing-name` once,
|
|
42
|
+
* through the runtime channel every Helix warning uses.
|
|
43
|
+
*
|
|
39
44
|
* @since 0.1.0
|
|
40
45
|
* @status stable
|
|
41
46
|
* @category media
|
|
@@ -121,6 +126,14 @@ export declare class HelixHeadlessIcon extends HelixElement {
|
|
|
121
126
|
private lookup;
|
|
122
127
|
protected willUpdate(changed: PropertyValues): void;
|
|
123
128
|
protected updated(changed: PropertyValues): void;
|
|
129
|
+
/** Hands the drawn `<svg>` to the mutator of the library `name` asks, where it has one. */
|
|
130
|
+
private mutate;
|
|
131
|
+
/**
|
|
132
|
+
* Asks the button or link a decorative icon sits in whether it has a name.
|
|
133
|
+
* Its content is this icon alone where it has none, and the audit says so
|
|
134
|
+
* once, in a development build only. A Helix button reports its own name.
|
|
135
|
+
*/
|
|
136
|
+
private auditControl;
|
|
124
137
|
/** The name a report is waiting on the page to settle for, so it is asked once. */
|
|
125
138
|
private pending;
|
|
126
139
|
/**
|
|
@@ -4,11 +4,11 @@ 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, hostAria, reportRuntime } from '@fusion.dev/helix-core';
|
|
7
|
+
import { auditName, customElement, HelixElement, hostAria, reportRuntime, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
11
|
-
import { resolveIcon, watchIcons } from '../registry.js';
|
|
11
|
+
import { iconMutator, resolveIcon, watchIcons } from '../registry.js';
|
|
12
12
|
import { afterPageSettles } from '../settle.js';
|
|
13
13
|
let HelixHeadlessIcon = class HelixHeadlessIcon extends HelixElement {
|
|
14
14
|
constructor() {
|
|
@@ -66,6 +66,10 @@ let HelixHeadlessIcon = class HelixHeadlessIcon extends HelixElement {
|
|
|
66
66
|
}
|
|
67
67
|
updated(changed) {
|
|
68
68
|
super.updated(changed);
|
|
69
|
+
if (this.drawn !== undefined) {
|
|
70
|
+
this.mutate();
|
|
71
|
+
this.auditControl();
|
|
72
|
+
}
|
|
69
73
|
if (this.arrived === this.name && this.drawn !== undefined) {
|
|
70
74
|
this.dispatchEvent(new Event('load', { bubbles: false, cancelable: false, composed: false }));
|
|
71
75
|
}
|
|
@@ -80,6 +84,23 @@ let HelixHeadlessIcon = class HelixHeadlessIcon extends HelixElement {
|
|
|
80
84
|
this.missed = '';
|
|
81
85
|
}
|
|
82
86
|
}
|
|
87
|
+
mutate() {
|
|
88
|
+
const svg = this.renderRoot.querySelector('svg');
|
|
89
|
+
const mutator = this.icon === undefined ? iconMutator(this.name) : undefined;
|
|
90
|
+
if (svg && mutator) {
|
|
91
|
+
mutator(svg);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
auditControl() {
|
|
95
|
+
if (this.label !== '' || this.hasAttribute('aria-label')) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const control = this.closest('a[href], button, summary, [role="button"], [role="link"]');
|
|
99
|
+
if (control) {
|
|
100
|
+
auditName(control, () => null, `Its only content is <${this.localName}>, which is decorative: give the icon a \`label\`, or the control an \`aria-label\`.`, () => (control.textContent ?? '').trim() !== '' ||
|
|
101
|
+
control.querySelector('[alt]:not([alt=""]), [aria-label]:not([aria-label=""])') !== null);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
83
104
|
reportMissing() {
|
|
84
105
|
const name = this.pending;
|
|
85
106
|
this.pending = '';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { type IconResolver, registerIconLibrary, registerIcons, resolveIcon } from '../registry.js';
|
|
1
|
+
export { type IconLibraryOptions, type IconResolver, registerIconLibrary, registerIcons, resolveIcon, } from '../registry.js';
|
|
2
2
|
export * from './icon-root.js';
|
package/dist/icon/root/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { registerIconLibrary, registerIcons, resolveIcon } from '../registry.js';
|
|
1
|
+
export { registerIconLibrary, registerIcons, resolveIcon, } from '../registry.js';
|
|
2
2
|
export * from './icon-root.js';
|
|
@@ -34,6 +34,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
34
34
|
*
|
|
35
35
|
* @cssstate error - The image failed to load, and the fallback shows.
|
|
36
36
|
* @cssstate loaded - The image loaded.
|
|
37
|
+
* @cssstate loading - The image is on its way, so neither `loaded` nor `error` is true yet.
|
|
38
|
+
* @cssstate waiting - The image is on its way and `placeholder-delay` still holds the placeholder back.
|
|
37
39
|
*/
|
|
38
40
|
export declare class HelixHeadlessImage extends HelixElement {
|
|
39
41
|
/**
|
|
@@ -121,6 +123,11 @@ export declare class HelixHeadlessImage extends HelixElement {
|
|
|
121
123
|
*
|
|
122
124
|
* `loading` writes nothing, because it is where every image starts and the
|
|
123
125
|
* resting state of a mirror is the attribute's absence.
|
|
126
|
+
*
|
|
127
|
+
* **Kept beside the custom states, and what the styled tier draws from.** An
|
|
128
|
+
* engine without `CustomStateSet`, Safari before 17.4 and Firefox before
|
|
129
|
+
* 126, records no state, and a picture faded in by `:state(loaded)` alone
|
|
130
|
+
* would stay transparent there for good. A sheet of your own can read either.
|
|
124
131
|
*/
|
|
125
132
|
status: 'error' | 'loaded' | 'loading';
|
|
126
133
|
/**
|
|
@@ -194,6 +201,8 @@ export declare class HelixHeadlessImage extends HelixElement {
|
|
|
194
201
|
private settle;
|
|
195
202
|
protected willUpdate(changed: PropertyValues): void;
|
|
196
203
|
protected updated(changed: PropertyValues): void;
|
|
204
|
+
/** Whether the picture is on its way and the wait still holds the placeholder back. */
|
|
205
|
+
private get waiting();
|
|
197
206
|
private startWait;
|
|
198
207
|
protected firstUpdated(changed: PropertyValues): void;
|
|
199
208
|
/**
|
|
@@ -92,7 +92,12 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
|
|
|
92
92
|
}
|
|
93
93
|
this.toggleState('loaded', this.status === 'loaded');
|
|
94
94
|
this.toggleState('error', this.status === 'error');
|
|
95
|
+
this.toggleState('loading', this.status === 'loading');
|
|
95
96
|
}
|
|
97
|
+
this.toggleState('waiting', this.waiting);
|
|
98
|
+
}
|
|
99
|
+
get waiting() {
|
|
100
|
+
return this.status === 'loading' && this.placeholderDelay > 0 && !this.wait.elapsed;
|
|
96
101
|
}
|
|
97
102
|
startWait() {
|
|
98
103
|
this.wait.start(this.placeholderDelay > 0 ? this.placeholderDelay : undefined);
|
|
@@ -142,7 +147,7 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
|
|
|
142
147
|
<span
|
|
143
148
|
part="placeholder"
|
|
144
149
|
aria-hidden="true"
|
|
145
|
-
?hidden=${this.status !== 'loading' ||
|
|
150
|
+
?hidden=${this.status !== 'loading' || this.waiting}
|
|
146
151
|
><slot name="placeholder"></slot
|
|
147
152
|
></span>
|
|
148
153
|
<span
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
|
|
1
|
+
import { AriaForwardController, HelixFormElement, type OwnRule } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
/** What the control accepts, which is text of one kind or another. */
|
|
4
4
|
export type InputType = 'email' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'url';
|
|
@@ -25,16 +25,30 @@ declare const HelixHeadlessInput_base: (new (...args: any[]) => import("@fusion.
|
|
|
25
25
|
* Aria's TextField `validate` does. What it returns is the message the field
|
|
26
26
|
* shows once the user has edited it, and the message a submit raises.
|
|
27
27
|
*
|
|
28
|
+
* **Keyboard.** The field's own keys are the platform's. Enter submits the
|
|
29
|
+
* form through its default button, as in a native field. The clear button
|
|
30
|
+
* under `clearable` and the reveal button under `reveal` are tab stops of
|
|
31
|
+
* their own after the field, so a keyboard reaches them.
|
|
32
|
+
*
|
|
33
|
+
* The inner input is named by `label`, or by a host `aria-label`,
|
|
34
|
+
* `aria-labelledby` or `<label for>`, and is described by the hint and the
|
|
35
|
+
* message, with `aria-invalid` while a message shows. The clear button is
|
|
36
|
+
* named `clear-label`, and the reveal button `reveal-label` with
|
|
37
|
+
* `aria-pressed` while the password shows.
|
|
38
|
+
*
|
|
28
39
|
* @since 0.1.0
|
|
29
40
|
* @status stable
|
|
30
41
|
* @category forms
|
|
31
42
|
* @aliases TextField, Field, TextInput
|
|
32
43
|
* @documentation https://fusion.dev/helix/components/input
|
|
33
44
|
*
|
|
45
|
+
* @slot clear-icon - Replaces the cross on the clear button, under `clearable`.
|
|
46
|
+
* @slot conceal-icon - Replaces the crossed-out eye on the reveal button while the password shows, under `reveal`.
|
|
34
47
|
* @slot end - After the text, for an icon or a unit.
|
|
35
48
|
* @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
|
|
36
49
|
* @slot hint - Help under the control, for content richer than the `hint` text.
|
|
37
50
|
* @slot label - The label, for content richer than the `label` text.
|
|
51
|
+
* @slot reveal-icon - Replaces the eye on the reveal button while the password is hidden, under `reveal`.
|
|
38
52
|
* @slot start - Before the text, for an icon or a prefix.
|
|
39
53
|
*
|
|
40
54
|
* @event {Event} change - Sent when the user finishes changing the value. Relayed from the native input.
|
|
@@ -290,7 +304,14 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
|
|
|
290
304
|
* nothing wrong. Return a message, or a list of them, to mark the field
|
|
291
305
|
* invalid, and `true`, `null`, or nothing to accept the value.
|
|
292
306
|
*/
|
|
293
|
-
validate?:
|
|
307
|
+
validate?: OwnRule;
|
|
308
|
+
/** The cross on the clear button, behind a seam a tier can move. */
|
|
309
|
+
protected renderClearIcon(): TemplateResult;
|
|
310
|
+
/**
|
|
311
|
+
* The eye on the reveal button, behind a seam a tier can move: open while
|
|
312
|
+
* the password is hidden, and crossed out while it shows.
|
|
313
|
+
*/
|
|
314
|
+
protected renderRevealIcon(): TemplateResult;
|
|
294
315
|
protected render(): TemplateResult;
|
|
295
316
|
}
|
|
296
317
|
declare global {
|
|
@@ -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, customElement, drawIcon, HelixClearEvent, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, submitImplicitly, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, applyOwnRule, customElement, drawIcon, HelixClearEvent, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, submitImplicitly, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { eye, eyeSlash, x } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -112,11 +112,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
|
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
114
|
this.copyValidity(control);
|
|
115
|
-
|
|
116
|
-
const message = Array.isArray(own) ? own.join(' ') : typeof own === 'string' ? own : '';
|
|
117
|
-
if (message !== '') {
|
|
118
|
-
this.internals.setValidity({ customError: true }, message, control);
|
|
119
|
-
}
|
|
115
|
+
applyOwnRule(this.internals, control, this.validate, this.value);
|
|
120
116
|
this.refreshFeedback();
|
|
121
117
|
}
|
|
122
118
|
focus(options) {
|
|
@@ -156,6 +152,14 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
|
|
|
156
152
|
this.releaseCaret = undefined;
|
|
157
153
|
this.sync();
|
|
158
154
|
}
|
|
155
|
+
renderClearIcon() {
|
|
156
|
+
return html `<slot name="clear-icon">${drawIcon(x)}</slot>`;
|
|
157
|
+
}
|
|
158
|
+
renderRevealIcon() {
|
|
159
|
+
return this.revealed
|
|
160
|
+
? html `<slot name="conceal-icon">${drawIcon(eyeSlash)}</slot>`
|
|
161
|
+
: html `<slot name="reveal-icon">${drawIcon(eye)}</slot>`;
|
|
162
|
+
}
|
|
159
163
|
render() {
|
|
160
164
|
return html `${this.renderLabel()}
|
|
161
165
|
<div part="field">
|
|
@@ -199,7 +203,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
|
|
|
199
203
|
aria-label=${this.clearLabel}
|
|
200
204
|
@click=${this.handleClear}
|
|
201
205
|
>
|
|
202
|
-
${
|
|
206
|
+
${this.renderClearIcon()}
|
|
203
207
|
</button>`
|
|
204
208
|
: nothing}
|
|
205
209
|
${this.reveal && this.type === 'password'
|
|
@@ -213,7 +217,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
|
|
|
213
217
|
this.revealed = !this.revealed;
|
|
214
218
|
}}
|
|
215
219
|
>
|
|
216
|
-
${
|
|
220
|
+
${this.renderRevealIcon()}
|
|
217
221
|
</button>`
|
|
218
222
|
: nothing}
|
|
219
223
|
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The words and glyphs a chord is drawn with, per platform.
|
|
3
|
+
*
|
|
4
|
+
* Beside the family's `index.ts`, because which label a key gets is a table
|
|
5
|
+
* and a rule, and not the key's template.
|
|
6
|
+
*/
|
|
7
|
+
/** A chord's keys as they are shown, and what is shown between two of them. */
|
|
8
|
+
export interface KeyNames {
|
|
9
|
+
/** Each key's label, in the order the chord names them. */
|
|
10
|
+
keys: string[];
|
|
11
|
+
/** What goes between two keys: `+`, a hyphen, or nothing. */
|
|
12
|
+
separator: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The labels of a chord's keys on a platform, with `own` labels in place of
|
|
16
|
+
* the platform's, and what goes between two keys.
|
|
17
|
+
*
|
|
18
|
+
* `parts` are the chord's names as `chordParts` splits them. A name `own`
|
|
19
|
+
* holds takes that label, a name the platform knows takes its glyph or word,
|
|
20
|
+
* and any other single character is shown in capitals.
|
|
21
|
+
*
|
|
22
|
+
* **On an Apple keyboard glyphs run together and words are joined with a
|
|
23
|
+
* hyphen**, as Apple writes `Command-K`. A label of more than one character
|
|
24
|
+
* from `own` is a word, so `{"mod": "Command"}` shows `Command-K` there, where
|
|
25
|
+
* nothing between the two ran them into `CommandK`. The platform's own `Esc`
|
|
26
|
+
* and `Space` keep running on from a glyph, as `⌘Esc` always has. Everywhere
|
|
27
|
+
* else keys are joined with `+`.
|
|
28
|
+
*/
|
|
29
|
+
export declare const keyNames: (parts: readonly string[], apple: boolean, own?: Readonly<Record<string, string>>) => KeyNames;
|
package/dist/kbd/keys.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const APPLE = {
|
|
2
|
+
alt: '⌥',
|
|
3
|
+
backspace: '⌫',
|
|
4
|
+
cmd: '⌘',
|
|
5
|
+
ctrl: '⌃',
|
|
6
|
+
del: '⌦',
|
|
7
|
+
down: '↓',
|
|
8
|
+
enter: '↵',
|
|
9
|
+
esc: 'Esc',
|
|
10
|
+
left: '←',
|
|
11
|
+
meta: '⌘',
|
|
12
|
+
mod: '⌘',
|
|
13
|
+
opt: '⌥',
|
|
14
|
+
right: '→',
|
|
15
|
+
shift: '⇧',
|
|
16
|
+
space: 'Space',
|
|
17
|
+
tab: '⇥',
|
|
18
|
+
up: '↑',
|
|
19
|
+
};
|
|
20
|
+
const ELSEWHERE = {
|
|
21
|
+
alt: 'Alt',
|
|
22
|
+
backspace: 'Backspace',
|
|
23
|
+
cmd: 'Win',
|
|
24
|
+
ctrl: 'Ctrl',
|
|
25
|
+
del: 'Del',
|
|
26
|
+
down: '↓',
|
|
27
|
+
enter: 'Enter',
|
|
28
|
+
esc: 'Esc',
|
|
29
|
+
left: '←',
|
|
30
|
+
meta: 'Win',
|
|
31
|
+
mod: 'Ctrl',
|
|
32
|
+
opt: 'Alt',
|
|
33
|
+
right: '→',
|
|
34
|
+
shift: 'Shift',
|
|
35
|
+
space: 'Space',
|
|
36
|
+
tab: 'Tab',
|
|
37
|
+
up: '↑',
|
|
38
|
+
};
|
|
39
|
+
export const keyNames = (parts, apple, own = {}) => {
|
|
40
|
+
const names = apple ? APPLE : ELSEWHERE;
|
|
41
|
+
let worded = false;
|
|
42
|
+
const keys = parts.map((part) => {
|
|
43
|
+
const name = part.toLowerCase();
|
|
44
|
+
const mine = own[name];
|
|
45
|
+
if (mine !== undefined) {
|
|
46
|
+
worded ||= [...mine].length > 1;
|
|
47
|
+
return mine;
|
|
48
|
+
}
|
|
49
|
+
return names[name] ?? (part.length === 1 ? part.toUpperCase() : part);
|
|
50
|
+
});
|
|
51
|
+
return { keys, separator: apple ? (worded ? '-' : '') : '+' };
|
|
52
|
+
};
|