@fusion.dev/helix-headless 0.143.0 → 0.144.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 +8551 -375
- package/dist/area-chart/root/area-chart-root.d.ts +12 -4
- package/dist/area-chart/root/area-chart-root.js +24 -7
- package/dist/avatar/root/avatar-root.d.ts +14 -0
- package/dist/avatar/root/avatar-root.js +23 -9
- package/dist/badge/root/badge-root.d.ts +11 -7
- package/dist/badge/root/badge-root.js +1 -1
- package/dist/bar-chart/root/bar-chart-root.d.ts +12 -3
- package/dist/bar-chart/root/bar-chart-root.js +17 -10
- package/dist/button/root/button-root.d.ts +47 -1
- package/dist/button/root/button-root.js +38 -4
- package/dist/callout/root/callout-root.d.ts +18 -1
- package/dist/callout/root/callout-root.js +15 -4
- package/dist/card/root/card-root.d.ts +30 -1
- package/dist/card/root/card-root.js +38 -5
- package/dist/checkbox/root/checkbox-root.js +2 -0
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +53 -3
- package/dist/checkbox-group/root/checkbox-group-root.js +71 -22
- package/dist/code-block/lines.d.ts +13 -0
- package/dist/code-block/lines.js +2 -0
- package/dist/code-block/root/code-block-root.d.ts +30 -0
- package/dist/code-block/root/code-block-root.js +23 -2
- package/dist/color-input/root/color-input-root.d.ts +34 -1
- package/dist/color-input/root/color-input-root.js +23 -4
- package/dist/color-picker/channels.d.ts +26 -0
- package/dist/color-picker/channels.js +84 -0
- package/dist/color-picker/root/color-picker-root.d.ts +81 -5
- package/dist/color-picker/root/color-picker-root.js +103 -10
- package/dist/combobox/root/combobox-root.d.ts +38 -3
- package/dist/combobox/root/combobox-root.js +64 -2
- package/dist/command/root/command-root.d.ts +30 -4
- package/dist/command/root/command-root.js +33 -3
- package/dist/copy-button/from.d.ts +22 -0
- package/dist/copy-button/from.js +28 -0
- package/dist/copy-button/root/copy-button-root.d.ts +27 -1
- package/dist/copy-button/root/copy-button-root.js +43 -7
- package/dist/date-input/root/date-input-root.d.ts +73 -4
- package/dist/date-input/root/date-input-root.js +93 -43
- package/dist/date-picker/root/date-picker-root.d.ts +145 -1
- package/dist/date-picker/root/date-picker-root.js +239 -48
- package/dist/dialog/description.d.ts +9 -0
- package/dist/dialog/description.js +14 -0
- package/dist/dialog/root/dialog-root.d.ts +64 -1
- package/dist/dialog/root/dialog-root.js +49 -23
- package/dist/donut-chart/root/donut-chart-root.d.ts +25 -4
- package/dist/donut-chart/root/donut-chart-root.js +21 -6
- package/dist/drawer/root/drawer-root.d.ts +63 -2
- package/dist/drawer/root/drawer-root.js +95 -19
- package/dist/drawer/swipe-start.d.ts +9 -0
- package/dist/drawer/swipe-start.js +12 -0
- package/dist/element-events.generated.js +8 -5
- package/dist/empty/root/empty-root.d.ts +1 -1
- package/dist/file-input/root/file-input-root.d.ts +47 -0
- package/dist/file-input/root/file-input-root.js +60 -22
- package/dist/file-input/screen.d.ts +35 -0
- package/dist/file-input/screen.js +49 -0
- package/dist/filter-input/root/filter-input-root.d.ts +38 -4
- package/dist/filter-input/root/filter-input-root.js +67 -3
- package/dist/filter-input/suggest.d.ts +17 -0
- package/dist/filter-input/suggest.js +23 -0
- package/dist/format-date/options.d.ts +33 -0
- package/dist/format-date/options.js +42 -0
- package/dist/format-date/root/format-date-root.d.ts +51 -0
- package/dist/format-date/root/format-date-root.js +58 -38
- package/dist/heatmap/root/heatmap-root.d.ts +23 -6
- package/dist/heatmap/root/heatmap-root.js +24 -13
- package/dist/icon/index.d.ts +2 -0
- package/dist/icon/index.js +2 -0
- package/dist/icon/registry.d.ts +37 -0
- package/dist/icon/registry.js +83 -0
- package/dist/icon/root/icon-root.d.ts +30 -4
- package/dist/icon/root/icon-root.js +41 -6
- package/dist/icon/root/index.d.ts +2 -0
- package/dist/icon/root/index.js +2 -0
- package/dist/icon/set.d.ts +1 -0
- package/dist/icon/set.js +3 -0
- package/dist/image/root/image-root.d.ts +14 -0
- package/dist/image/root/image-root.js +15 -2
- package/dist/input/root/input-root.d.ts +11 -0
- package/dist/input/root/input-root.js +15 -0
- package/dist/kbd/root/kbd-root.d.ts +20 -13
- package/dist/kbd/root/kbd-root.js +35 -37
- package/dist/kbd/shortcut.d.ts +18 -0
- package/dist/kbd/shortcut.js +35 -0
- package/dist/legend/hidden-series.d.ts +8 -0
- package/dist/legend/hidden-series.js +13 -0
- package/dist/legend/root/legend-root.d.ts +56 -0
- package/dist/legend/root/legend-root.js +54 -5
- package/dist/lightbox/item/lightbox-item.d.ts +15 -0
- package/dist/lightbox/item/lightbox-item.js +10 -1
- package/dist/lightbox/root/lightbox-root.d.ts +61 -1
- package/dist/lightbox/root/lightbox-root.js +94 -4
- package/dist/line-chart/root/line-chart-root.d.ts +11 -3
- package/dist/line-chart/root/line-chart-root.js +19 -5
- package/dist/listbox/range.d.ts +17 -0
- package/dist/listbox/range.js +5 -0
- package/dist/listbox/root/listbox-root.d.ts +74 -3
- package/dist/listbox/root/listbox-root.js +87 -9
- package/dist/loader/busy.d.ts +17 -0
- package/dist/loader/busy.js +24 -0
- package/dist/loader/root/loader-root.d.ts +37 -0
- package/dist/loader/root/loader-root.js +52 -3
- package/dist/meter/root/meter-root.d.ts +7 -0
- package/dist/meter/root/meter-root.js +6 -3
- package/dist/notifications/feed-keys.d.ts +10 -0
- package/dist/notifications/feed-keys.js +14 -0
- package/dist/notifications/notification/notification.d.ts +17 -0
- package/dist/notifications/notification/notification.js +21 -2
- package/dist/notifications/root/notifications-root.d.ts +42 -0
- package/dist/notifications/root/notifications-root.js +60 -1
- package/dist/number-input/root/number-input-root.d.ts +47 -0
- package/dist/number-input/root/number-input-root.js +58 -22
- package/dist/object-inspector/root/object-inspector-root.d.ts +1 -0
- package/dist/object-inspector/root/object-inspector-root.js +1 -1
- package/dist/option/root/option-root.d.ts +54 -5
- package/dist/option/root/option-root.js +34 -5
- package/dist/pin-input/format.d.ts +7 -0
- package/dist/pin-input/format.js +16 -0
- package/dist/pin-input/root/pin-input-root.d.ts +21 -0
- package/dist/pin-input/root/pin-input-root.js +29 -2
- package/dist/popover/root/popover-root.d.ts +62 -4
- package/dist/popover/root/popover-root.js +53 -5
- package/dist/progress/root/progress-root.d.ts +7 -0
- package/dist/progress/root/progress-root.js +9 -3
- package/dist/qr-code/export.d.ts +31 -0
- package/dist/qr-code/export.js +10 -0
- package/dist/qr-code/root/qr-code-root.d.ts +26 -0
- package/dist/qr-code/root/qr-code-root.js +49 -2
- package/dist/radio/group/radio-group.d.ts +23 -0
- package/dist/radio/group/radio-group.js +18 -0
- package/dist/rating/root/rating-root.d.ts +25 -0
- package/dist/rating/root/rating-root.js +45 -3
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
- package/dist/scatter-chart/root/scatter-chart-root.js +25 -7
- package/dist/select/root/select-root.d.ts +24 -0
- package/dist/select/root/select-root.js +20 -6
- package/dist/skeleton/root/skeleton-root.d.ts +25 -0
- package/dist/skeleton/root/skeleton-root.js +17 -2
- package/dist/slider/root/slider-root.d.ts +39 -0
- package/dist/slider/root/slider-root.js +45 -9
- package/dist/stat/root/stat-root.d.ts +2 -0
- package/dist/stat/root/stat-root.js +1 -1
- package/dist/steps/step/step.d.ts +1 -0
- package/dist/steps/step/step.js +1 -1
- package/dist/switch/root/switch-root.d.ts +12 -2
- package/dist/switch/root/switch-root.js +6 -1
- package/dist/tag/group/tag-group.d.ts +107 -0
- package/dist/tag/group/tag-group.js +157 -0
- package/dist/tag/index.d.ts +1 -0
- package/dist/tag/index.js +1 -0
- package/dist/tag/root/tag-root.d.ts +60 -0
- package/dist/tag/root/tag-root.js +74 -18
- package/dist/tag/selection.d.ts +10 -0
- package/dist/tag/selection.js +12 -0
- package/dist/textarea/grow.d.ts +22 -0
- package/dist/textarea/grow.js +20 -0
- package/dist/textarea/root/textarea-root.d.ts +9 -0
- package/dist/textarea/root/textarea-root.js +9 -1
- package/dist/time-input/root/time-input-root.d.ts +44 -5
- package/dist/time-input/root/time-input-root.js +69 -39
- package/dist/time-picker/root/time-picker-root.d.ts +54 -8
- package/dist/time-picker/root/time-picker-root.js +121 -91
- package/dist/toast/hotkey.d.ts +22 -0
- package/dist/toast/hotkey.js +23 -0
- package/dist/toast/item/toast-item.d.ts +16 -1
- package/dist/toast/item/toast-item.js +41 -13
- package/dist/toast/root/toast-root.d.ts +42 -8
- package/dist/toast/root/toast-root.js +64 -4
- package/dist/toggle/group/toggle-group.d.ts +57 -15
- package/dist/toggle/group/toggle-group.js +69 -9
- package/dist/toggle/root/toggle-root.d.ts +12 -1
- package/dist/toggle/root/toggle-root.js +11 -3
- package/dist/tooltip/focus-target.d.ts +6 -0
- package/dist/tooltip/focus-target.js +9 -0
- package/dist/tooltip/root/tooltip-root.d.ts +42 -17
- package/dist/tooltip/root/tooltip-root.js +50 -9
- package/dist/tour/naming.d.ts +30 -0
- package/dist/tour/naming.js +10 -0
- package/dist/tour/root/tour-root.d.ts +35 -0
- package/dist/tour/root/tour-root.js +56 -5
- package/dist/tour/stop/tour-stop.d.ts +53 -8
- package/dist/tour/stop/tour-stop.js +45 -15
- package/dist/tour/wait.d.ts +11 -0
- package/dist/tour/wait.js +19 -0
- package/dist/trend/root/trend-root.d.ts +13 -0
- package/dist/trend/root/trend-root.js +14 -9
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +4862 -254
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +1149 -67
|
@@ -4,10 +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, rgbOf } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing, svg, } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { encode } from 'uqr';
|
|
11
|
+
import { qrSvg } from '../export.js';
|
|
12
|
+
const QUIET = 4;
|
|
11
13
|
const isFinder = (x, y, size) => {
|
|
12
14
|
const near = (a, b) => a < 8 && b < 8;
|
|
13
15
|
return near(x, y) || near(size - 1 - x, y) || near(x, size - 1 - y);
|
|
@@ -104,6 +106,51 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
104
106
|
this.overflowed = '';
|
|
105
107
|
}
|
|
106
108
|
}
|
|
109
|
+
toSvg(size = 512) {
|
|
110
|
+
const code = this.renderRoot?.querySelector('svg[part="code"]');
|
|
111
|
+
const modules = code?.querySelector('[part="modules"]');
|
|
112
|
+
const finders = code?.querySelector('[part="finders"]');
|
|
113
|
+
if (!code || !modules || !finders) {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
const ground = getComputedStyle(this).backgroundColor;
|
|
117
|
+
const clear = ground === '' || ground === 'transparent' || /^rgba\(.*,\s*0\)$/.test(ground);
|
|
118
|
+
return qrSvg({
|
|
119
|
+
background: clear ? '#ffffff' : rgbOf(ground),
|
|
120
|
+
box: Number(code.getAttribute('viewBox')?.split(' ')[2] ?? 0),
|
|
121
|
+
finderColor: rgbOf(getComputedStyle(finders).fill || '#000000'),
|
|
122
|
+
finders: finders.getAttribute('d') ?? '',
|
|
123
|
+
moduleColor: rgbOf(getComputedStyle(modules).fill || '#000000'),
|
|
124
|
+
modules: modules.getAttribute('d') ?? '',
|
|
125
|
+
quiet: QUIET,
|
|
126
|
+
}, size);
|
|
127
|
+
}
|
|
128
|
+
async toPng(size = 512) {
|
|
129
|
+
const markup = this.toSvg(size);
|
|
130
|
+
if (markup === '') {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const image = new Image();
|
|
134
|
+
image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(markup)}`;
|
|
135
|
+
await image.decode();
|
|
136
|
+
const canvas = document.createElement('canvas');
|
|
137
|
+
canvas.width = size;
|
|
138
|
+
canvas.height = size;
|
|
139
|
+
canvas.getContext('2d')?.drawImage(image, 0, 0, size, size);
|
|
140
|
+
return new Promise((resolve) => canvas.toBlob(resolve, 'image/png'));
|
|
141
|
+
}
|
|
142
|
+
async download(filename = 'qr-code.png', size = 512) {
|
|
143
|
+
const png = await this.toPng(size);
|
|
144
|
+
if (!png) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const url = URL.createObjectURL(png);
|
|
148
|
+
const link = document.createElement('a');
|
|
149
|
+
link.href = url;
|
|
150
|
+
link.download = filename;
|
|
151
|
+
link.click();
|
|
152
|
+
setTimeout(() => URL.revokeObjectURL(url));
|
|
153
|
+
}
|
|
107
154
|
renderCode() {
|
|
108
155
|
if (this.value === '') {
|
|
109
156
|
return nothing;
|
|
@@ -113,7 +160,7 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
113
160
|
return nothing;
|
|
114
161
|
}
|
|
115
162
|
const size = result.size;
|
|
116
|
-
const quiet =
|
|
163
|
+
const quiet = QUIET;
|
|
117
164
|
const box = size + quiet * 2;
|
|
118
165
|
const finders = pathFor(result.data, 'square', 'finders');
|
|
119
166
|
return svg `<svg
|
|
@@ -23,6 +23,13 @@ declare const HelixHeadlessRadioGroup_base: (new (...args: any[]) => import("@fu
|
|
|
23
23
|
* the value until something is chosen, and where a reset returns. The two work
|
|
24
24
|
* like `checked` and `defaultChecked`.
|
|
25
25
|
*
|
|
26
|
+
* A choice sends its events in this order: `helix-select` from the radio, then,
|
|
27
|
+
* a microtask later and only if nobody refused it, `helix-before-change` from
|
|
28
|
+
* the group, and once the value has moved, `input` and `change`. The microtask
|
|
29
|
+
* is what lets a listener you add to the group after it connected refuse the
|
|
30
|
+
* `helix-select`. A native radio sends `input` and `change` in the same task as
|
|
31
|
+
* the click.
|
|
32
|
+
*
|
|
26
33
|
* @since 0.1.0
|
|
27
34
|
* @status stable
|
|
28
35
|
* @aliases RadioButtons, Choice group
|
|
@@ -69,6 +76,22 @@ export declare class HelixHeadlessRadioGroup extends HelixHeadlessRadioGroup_bas
|
|
|
69
76
|
* only `horizontal` has to be named.
|
|
70
77
|
*/
|
|
71
78
|
orientation?: 'horizontal' | 'vertical';
|
|
79
|
+
/**
|
|
80
|
+
* Whether a reader can see and focus the answer and cannot change it. A
|
|
81
|
+
* read-only group still submits its value.
|
|
82
|
+
*
|
|
83
|
+
* React Aria's `isReadOnly`. A press on a radio is refused, and the arrow
|
|
84
|
+
* keys, Home and End leave focus on the answer, so Tab still reaches it and
|
|
85
|
+
* a reader hears it with the group's name. The group says `aria-readonly`.
|
|
86
|
+
* A script can still set `value`.
|
|
87
|
+
*/
|
|
88
|
+
readOnly: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Keeps the keys that would move the answer from the keyboard controller
|
|
91
|
+
* while the group is read-only. A capture listener on the host runs ahead of
|
|
92
|
+
* the controller's own on the same target.
|
|
93
|
+
*/
|
|
94
|
+
private readonly holdKeys;
|
|
72
95
|
protected readonly keys: KeyboardNavigationController;
|
|
73
96
|
protected readonly cascade: DisabledCascadeController;
|
|
74
97
|
/** The radios, in light-DOM order. Client only: the server has no tree. */
|
|
@@ -8,16 +8,28 @@ import { customElement, DisabledCascadeController, HelixFormElement, hostAria, K
|
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessRadio } from '../root/radio-root.js';
|
|
11
|
+
const MOVING_KEYS = new Set(['ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'End', 'Home']);
|
|
11
12
|
let HelixHeadlessRadioGroup = class HelixHeadlessRadioGroup extends MixinControllerValue(MixinField(HelixFormElement)) {
|
|
12
13
|
constructor() {
|
|
13
14
|
super(...arguments);
|
|
14
15
|
this.focusable = true;
|
|
16
|
+
this.readOnly = false;
|
|
17
|
+
this.holdKeys = (event) => {
|
|
18
|
+
if (this.readOnly && MOVING_KEYS.has(event.key)) {
|
|
19
|
+
event.stopImmediatePropagation();
|
|
20
|
+
event.preventDefault();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
15
23
|
this.keys = new KeyboardNavigationController(this, { items: () => this.items });
|
|
16
24
|
this.cascade = new DisabledCascadeController(this, {
|
|
17
25
|
items: () => this.items,
|
|
18
26
|
});
|
|
19
27
|
this.handleSelection = (event) => {
|
|
20
28
|
event.stopPropagation();
|
|
29
|
+
if (this.readOnly) {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
21
33
|
queueMicrotask(() => {
|
|
22
34
|
if (event.defaultPrevented) {
|
|
23
35
|
return;
|
|
@@ -80,16 +92,19 @@ let HelixHeadlessRadioGroup = class HelixHeadlessRadioGroup extends MixinControl
|
|
|
80
92
|
connectedCallback() {
|
|
81
93
|
super.connectedCallback();
|
|
82
94
|
this.addEventListener('helix-select', this.handleSelection);
|
|
95
|
+
this.addEventListener('keydown', this.holdKeys, { capture: true });
|
|
83
96
|
}
|
|
84
97
|
disconnectedCallback() {
|
|
85
98
|
super.disconnectedCallback();
|
|
86
99
|
this.removeEventListener('helix-select', this.handleSelection);
|
|
100
|
+
this.removeEventListener('keydown', this.holdKeys, { capture: true });
|
|
87
101
|
}
|
|
88
102
|
willUpdate(changed) {
|
|
89
103
|
super.willUpdate(changed);
|
|
90
104
|
this.adopt();
|
|
91
105
|
hostAria(this.internals, { label: this.label, role: 'radiogroup' });
|
|
92
106
|
this.internals.ariaRequired = this.required ? 'true' : null;
|
|
107
|
+
this.internals.ariaReadOnly = this.readOnly ? 'true' : null;
|
|
93
108
|
}
|
|
94
109
|
updated(changed) {
|
|
95
110
|
super.updated(changed);
|
|
@@ -111,6 +126,9 @@ __decorate([
|
|
|
111
126
|
__decorate([
|
|
112
127
|
property({ reflect: true })
|
|
113
128
|
], HelixHeadlessRadioGroup.prototype, "orientation", void 0);
|
|
129
|
+
__decorate([
|
|
130
|
+
property({ attribute: 'readonly', reflect: true, type: Boolean })
|
|
131
|
+
], HelixHeadlessRadioGroup.prototype, "readOnly", void 0);
|
|
114
132
|
HelixHeadlessRadioGroup = __decorate([
|
|
115
133
|
customElement('helix-headless-radio-group')
|
|
116
134
|
], HelixHeadlessRadioGroup);
|
|
@@ -15,6 +15,9 @@ declare const HelixHeadlessRating_base: (new (...args: any[]) => import("@fusion
|
|
|
15
15
|
* A read-only rating displays a score, which is the most common use. It is
|
|
16
16
|
* announced as a displayed value and does not look disabled.
|
|
17
17
|
*
|
|
18
|
+
* With `clearable`, pressing the chosen score again, or Backspace or Delete on
|
|
19
|
+
* the marks, takes the rating back to unrated and sends `helix-clear`.
|
|
20
|
+
*
|
|
18
21
|
* @since 0.1.0
|
|
19
22
|
* @status stable
|
|
20
23
|
* @category forms
|
|
@@ -28,6 +31,7 @@ declare const HelixHeadlessRating_base: (new (...args: any[]) => import("@fusion
|
|
|
28
31
|
*
|
|
29
32
|
* @event {Event} change - The score was chosen. Sent together with `input`, because each choice commits the score.
|
|
30
33
|
* @event {HelixBeforeChangeEvent} helix-before-change - The score is about to change. Cancelable: cancel it to keep the current score.
|
|
34
|
+
* @event {Event} helix-clear - The rating went back to unrated, under `clearable`. Sent after `input` and `change`.
|
|
31
35
|
* @event {Event} input - The score changed.
|
|
32
36
|
*
|
|
33
37
|
* @csspart feedback - The message that says what is wrong.
|
|
@@ -50,6 +54,12 @@ declare const HelixHeadlessRating_base: (new (...args: any[]) => import("@fusion
|
|
|
50
54
|
*/
|
|
51
55
|
export declare class HelixHeadlessRating extends HelixHeadlessRating_base {
|
|
52
56
|
protected readonly announcesInput = false;
|
|
57
|
+
/**
|
|
58
|
+
* Whether a reader can take the rating back to unrated: by pressing the
|
|
59
|
+
* chosen score again, or with Backspace or Delete. Zag's rating group
|
|
60
|
+
* clears the same way.
|
|
61
|
+
*/
|
|
62
|
+
clearable: boolean;
|
|
53
63
|
/**
|
|
54
64
|
* How many marks there are.
|
|
55
65
|
*/
|
|
@@ -142,6 +152,8 @@ export declare class HelixHeadlessRating extends HelixHeadlessRating_base {
|
|
|
142
152
|
*/
|
|
143
153
|
valueText: string;
|
|
144
154
|
protected readonly aria: AriaForwardController;
|
|
155
|
+
/** @internal The element a missing name is checked on: the set of stars, so the name of one star does not count as the name of the rating. */
|
|
156
|
+
protected get namedControl(): HTMLElement | null;
|
|
145
157
|
/**
|
|
146
158
|
* The shape a consumer slotted, if they slotted one.
|
|
147
159
|
*
|
|
@@ -236,8 +248,17 @@ export declare class HelixHeadlessRating extends HelixHeadlessRating_base {
|
|
|
236
248
|
* or off the element entirely, has asked for nothing.
|
|
237
249
|
*/
|
|
238
250
|
private readonly handleDragStart;
|
|
251
|
+
/** The score a press began on, so releasing on the chosen one can clear it. */
|
|
252
|
+
private pressedOn;
|
|
253
|
+
/**
|
|
254
|
+
* Whether a drag has just chosen, so the click a browser may send after it
|
|
255
|
+
* does not choose again. Cleared a task later, since the click may not come.
|
|
256
|
+
*/
|
|
257
|
+
private dragChose;
|
|
239
258
|
private readonly handleDragMove;
|
|
240
259
|
private readonly handleDragEnd;
|
|
260
|
+
/** Whether a press on `score` takes a clearable rating back to unrated. */
|
|
261
|
+
private clearsAt;
|
|
241
262
|
private readonly handleDragCancel;
|
|
242
263
|
/**
|
|
243
264
|
* Reports the value, and whether the form may go without one.
|
|
@@ -260,6 +281,10 @@ export declare class HelixHeadlessRating extends HelixHeadlessRating_base {
|
|
|
260
281
|
*/
|
|
261
282
|
private sync;
|
|
262
283
|
private readonly handleOptionClick;
|
|
284
|
+
/** Backspace and Delete take a clearable rating back to unrated. */
|
|
285
|
+
private readonly handleClearKey;
|
|
286
|
+
/** Back to unrated, through the same cancelable request as a score, and said. */
|
|
287
|
+
private clear;
|
|
263
288
|
private readonly handleOptionEnter;
|
|
264
289
|
private readonly handleLeave;
|
|
265
290
|
connectedCallback(): void;
|
|
@@ -11,6 +11,7 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.announcesInput = false;
|
|
14
|
+
this.clearable = false;
|
|
14
15
|
this.max = 5;
|
|
15
16
|
this.min = 0;
|
|
16
17
|
this.optionLabel = '{score} out of {max}';
|
|
@@ -50,8 +51,11 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
50
51
|
catch {
|
|
51
52
|
}
|
|
52
53
|
this.dragging = event.pointerId;
|
|
54
|
+
this.pressedOn = score;
|
|
53
55
|
this.previewing = Number.parseFloat(score);
|
|
54
56
|
};
|
|
57
|
+
this.pressedOn = undefined;
|
|
58
|
+
this.dragChose = false;
|
|
55
59
|
this.handleDragMove = (event) => {
|
|
56
60
|
if (this.dragging !== event.pointerId) {
|
|
57
61
|
return;
|
|
@@ -68,9 +72,18 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
68
72
|
this.dragging = undefined;
|
|
69
73
|
this.previewing = undefined;
|
|
70
74
|
const score = this.scoreAt(event.clientX);
|
|
71
|
-
if (score
|
|
72
|
-
|
|
75
|
+
if (score === undefined) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.dragChose = true;
|
|
79
|
+
setTimeout(() => {
|
|
80
|
+
this.dragChose = false;
|
|
81
|
+
}, 0);
|
|
82
|
+
if (this.clearsAt(score) && score === this.pressedOn) {
|
|
83
|
+
this.clear();
|
|
84
|
+
return;
|
|
73
85
|
}
|
|
86
|
+
this.requestValue(score);
|
|
74
87
|
};
|
|
75
88
|
this.handleDragCancel = (event) => {
|
|
76
89
|
if (this.dragging !== event.pointerId) {
|
|
@@ -80,8 +93,22 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
80
93
|
this.previewing = undefined;
|
|
81
94
|
};
|
|
82
95
|
this.handleOptionClick = (event) => {
|
|
96
|
+
if (this.dragChose) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
83
99
|
const option = event.currentTarget;
|
|
84
|
-
|
|
100
|
+
const score = option.dataset.score ?? '';
|
|
101
|
+
if (this.clearsAt(score)) {
|
|
102
|
+
this.clear();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
this.requestValue(score);
|
|
106
|
+
};
|
|
107
|
+
this.handleClearKey = (event) => {
|
|
108
|
+
if (this.clearable && (event.key === 'Backspace' || event.key === 'Delete')) {
|
|
109
|
+
event.preventDefault();
|
|
110
|
+
this.clear();
|
|
111
|
+
}
|
|
85
112
|
};
|
|
86
113
|
this.handleOptionEnter = (event) => {
|
|
87
114
|
if (this.isDisabled) {
|
|
@@ -95,6 +122,9 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
95
122
|
};
|
|
96
123
|
this.warned = false;
|
|
97
124
|
}
|
|
125
|
+
get namedControl() {
|
|
126
|
+
return this.partNamed('marks');
|
|
127
|
+
}
|
|
98
128
|
get floor() {
|
|
99
129
|
if (!Number.isFinite(this.min)) {
|
|
100
130
|
return 0;
|
|
@@ -156,10 +186,18 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
156
186
|
}
|
|
157
187
|
return nearest;
|
|
158
188
|
}
|
|
189
|
+
clearsAt(score) {
|
|
190
|
+
return this.clearable && this.value !== '' && Number(score) === Number(this.value);
|
|
191
|
+
}
|
|
159
192
|
sync() {
|
|
160
193
|
this.internals.setFormValue(this.value === '' ? null : this.value);
|
|
161
194
|
this.reportRequired(this.value === '', 'Choose a rating to continue.', 'marks');
|
|
162
195
|
}
|
|
196
|
+
clear() {
|
|
197
|
+
if (this.value !== '' && !this.readOnly && !this.isDisabled && this.requestValue('')) {
|
|
198
|
+
this.dispatchEvent(new Event('helix-clear', { bubbles: true, composed: true }));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
163
201
|
connectedCallback() {
|
|
164
202
|
super.connectedCallback();
|
|
165
203
|
this.addEventListener('pointerleave', this.handleLeave);
|
|
@@ -226,6 +264,7 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
226
264
|
data-slotted=${this.markSource ? '' : nothing}
|
|
227
265
|
style=${`--rating-full: ${Math.floor(showing)}; --rating-part: ${showing - Math.floor(showing)}; --rating-steps: ${this.positions.length}`}
|
|
228
266
|
@pointercancel=${this.handleDragCancel}
|
|
267
|
+
@keydown=${this.handleClearKey}
|
|
229
268
|
@pointerdown=${this.handleDragStart}
|
|
230
269
|
@pointermove=${this.handleDragMove}
|
|
231
270
|
@pointerup=${this.handleDragEnd}
|
|
@@ -283,6 +322,9 @@ let HelixHeadlessRating = class HelixHeadlessRating extends MixinControllerValue
|
|
|
283
322
|
this.value = fromNumber(count);
|
|
284
323
|
}
|
|
285
324
|
};
|
|
325
|
+
__decorate([
|
|
326
|
+
property({ type: Boolean })
|
|
327
|
+
], HelixHeadlessRating.prototype, "clearable", void 0);
|
|
286
328
|
__decorate([
|
|
287
329
|
property({ type: Number })
|
|
288
330
|
], HelixHeadlessRating.prototype, "max", void 0);
|
|
@@ -33,7 +33,14 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
33
33
|
* round numbers, and the range extends to them.
|
|
34
34
|
*
|
|
35
35
|
* The summary gives each series' correlation coefficient and its number of
|
|
36
|
-
* points. The table has every number, and the drawing is
|
|
36
|
+
* points. The table has every number, and the drawing is hidden from screen
|
|
37
|
+
* readers.
|
|
38
|
+
*
|
|
39
|
+
* **The plot is read by key.** It takes focus, named by `label` or the caption.
|
|
40
|
+
* The left and right arrows move from row to row in the table's order, Home
|
|
41
|
+
* and End go to the first and the last, and the up and down arrows move among
|
|
42
|
+
* the series of a row. The tooltip sits on that point, the `live` part says the
|
|
43
|
+
* row in words, and Escape puts the tooltip away.
|
|
37
44
|
*
|
|
38
45
|
* Each point is a `<span>` placed by percentage over the drawing, as
|
|
39
46
|
* `LineChart` places its end points, so points stay round when the drawing
|
|
@@ -52,9 +59,10 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
52
59
|
* @documentation https://fusion.dev/helix/components/scatter-chart
|
|
53
60
|
*
|
|
54
61
|
* @csspart gridline - One line across the plot, drawn when `gridlines` is set.
|
|
62
|
+
* @csspart live - The readout: a polite live region that says the row the keys moved to. Hide it visually.
|
|
55
63
|
* @csspart mark - The invisible point the tooltip is anchored to.
|
|
56
64
|
* @csspart plane - The grid that holds the plot, both axes, and their names. It runs left to right on every page.
|
|
57
|
-
* @csspart plot - The drawing.
|
|
65
|
+
* @csspart plot - The drawing, which takes focus to be read by key.
|
|
58
66
|
* @csspart point - One row, as a point.
|
|
59
67
|
* @csspart point-active - A point in the row under the pointer. Set alongside `point`.
|
|
60
68
|
* @csspart summary - The text that says how strongly the measures relate, for people who cannot see the points.
|
|
@@ -68,6 +76,7 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
68
76
|
* @csspart tooltip-arrow-top - The point while the bubble is above the reading, on its bottom edge. Set alongside `tooltip-arrow`.
|
|
69
77
|
* @csspart tooltip-bottom - The bubble while it is below the reading. Set alongside `tooltip`.
|
|
70
78
|
* @csspart tooltip-cell - One column's name and value inside the tooltip.
|
|
79
|
+
* @csspart tooltip-cell-current - The cell the up and down arrows rest on, while they rest there. Set alongside `tooltip-cell`.
|
|
71
80
|
* @csspart tooltip-label - The row's own name inside the tooltip.
|
|
72
81
|
* @csspart tooltip-left - The bubble while it is left of the reading. Set alongside `tooltip`.
|
|
73
82
|
* @csspart tooltip-name - A column's name inside the tooltip.
|
|
@@ -149,7 +158,12 @@ export declare class HelixHeadlessScatterChart extends HelixHeadlessScatterChart
|
|
|
149
158
|
* absent where there are fewer than three points or no spread to measure.
|
|
150
159
|
*/
|
|
151
160
|
protected renderSummary(field: ScatterField): TemplateResult;
|
|
152
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* The row a pointer is resting on, over the point it is nearest.
|
|
163
|
+
*
|
|
164
|
+
* A row reached by key has no nearest point, so the bubble sits on the
|
|
165
|
+
* point of the series the keys rest on, or on the row's first point.
|
|
166
|
+
*/
|
|
153
167
|
protected renderTooltip(): TemplateResult | typeof nothing;
|
|
154
168
|
/**
|
|
155
169
|
* The point a pointer is nearest, within reach.
|
|
@@ -116,14 +116,17 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
116
116
|
const y = row.cells[column]?.value;
|
|
117
117
|
return x === undefined || y === undefined ? [] : [[x, y, index]];
|
|
118
118
|
}));
|
|
119
|
-
const
|
|
119
|
+
const shown = ups.map((column) => this.showsSeries(name(column)));
|
|
120
|
+
const all = pairs.filter((_, depth) => shown[depth]).flat();
|
|
120
121
|
const x = nice(extent(all.length > 0 ? all.map(([one]) => one) : [0]));
|
|
121
122
|
const y = nice(extent(all.length > 0 ? all.map(([, one]) => one) : [0]));
|
|
122
123
|
const along = linear(x, [0, PLOT_WIDTH]);
|
|
123
124
|
const up = linear(y, [PLOT_HEIGHT, 0]);
|
|
124
125
|
return {
|
|
125
126
|
pairs: pairs.map((series) => series.map(([one, two]) => [one, two])),
|
|
126
|
-
points: pairs.flatMap((series, depth) =>
|
|
127
|
+
points: pairs.flatMap((series, depth) => shown[depth]
|
|
128
|
+
? series.map(([one, two, row]) => ({ depth, row, x: along(one), y: up(two) }))
|
|
129
|
+
: []),
|
|
127
130
|
x,
|
|
128
131
|
xName: name(across),
|
|
129
132
|
y,
|
|
@@ -156,8 +159,17 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
156
159
|
}
|
|
157
160
|
renderPlot(field, along, up) {
|
|
158
161
|
const at = this.pointer.at;
|
|
159
|
-
return html `<div
|
|
162
|
+
return html `<div
|
|
163
|
+
aria-describedby=${this.named ? 'helix-chart-summary' : nothing}
|
|
164
|
+
aria-label=${this.named || nothing}
|
|
165
|
+
aria-labelledby=${this.named ? nothing : 'helix-chart-summary'}
|
|
166
|
+
id=${CHART_PLOT}
|
|
167
|
+
part="plot"
|
|
168
|
+
role="application"
|
|
169
|
+
tabindex="0"
|
|
170
|
+
>
|
|
160
171
|
<svg part="svg"
|
|
172
|
+
aria-hidden="true"
|
|
161
173
|
preserveAspectRatio="none"
|
|
162
174
|
viewBox="0 0 ${PLOT_WIDTH} ${PLOT_HEIGHT}"
|
|
163
175
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -172,6 +184,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
172
184
|
${field.points.map((point) => {
|
|
173
185
|
const index = seriesIndex(point.depth);
|
|
174
186
|
return html `<span
|
|
187
|
+
aria-hidden="true"
|
|
175
188
|
data-series=${index}
|
|
176
189
|
?data-active=${point.row === at}
|
|
177
190
|
part="point${point.row === at ? ' point-active' : ''}"
|
|
@@ -189,13 +202,18 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
189
202
|
return `${name} / ${field.xName}: ${pairs.length} ${this.pointsLabel}${strength}`;
|
|
190
203
|
});
|
|
191
204
|
const named = this.named ? `${this.named}. ` : '';
|
|
192
|
-
return html `<p part="summary">${named}${clauses.join('; ')}.</p>`;
|
|
205
|
+
return html `<p id="helix-chart-summary" part="summary">${named}${clauses.join('; ')}.</p>`;
|
|
193
206
|
}
|
|
194
207
|
renderTooltip() {
|
|
195
208
|
const at = this.pointer.at;
|
|
196
|
-
const
|
|
209
|
+
const column = this.pointer.column;
|
|
210
|
+
const depth = column === undefined ? -1 : this.plottedColumns.indexOf(column) - 1;
|
|
211
|
+
const point = this.nearest?.row === at && !this.pointer.keyed
|
|
212
|
+
? this.nearest
|
|
213
|
+
: (this.drawn.find((one) => one.row === at && one.depth === depth) ??
|
|
214
|
+
this.drawn.find((one) => one.row === at));
|
|
197
215
|
if (at < 0 || !point) {
|
|
198
|
-
return drawTooltip(this.sourceRows, -1, this.tag('tooltip'));
|
|
216
|
+
return drawTooltip(this.sourceRows, -1, this.tag('tooltip'), undefined, undefined, this.pointer);
|
|
199
217
|
}
|
|
200
218
|
return drawTooltip(this.sourceRows, at, this.tag('tooltip'), {
|
|
201
219
|
dir: isRtl(this) ? 'rtl' : 'ltr',
|
|
@@ -203,7 +221,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
203
221
|
placement: 'top',
|
|
204
222
|
x: `${point.x}%`,
|
|
205
223
|
y: `${point.y}%`,
|
|
206
|
-
}, (cell) => this.seriesOf(cell));
|
|
224
|
+
}, (cell) => this.seriesOf(cell), this.pointer);
|
|
207
225
|
}
|
|
208
226
|
};
|
|
209
227
|
__decorate([
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AriaForwardController, HelixFormElement, PopoverController } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import { type HelixHeadlessOption } from '../../option/root/option-root.js';
|
|
3
4
|
import '../../listbox/index.js';
|
|
4
5
|
declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
5
6
|
/**
|
|
@@ -17,6 +18,9 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
17
18
|
* `Select` owns the value, passes it down to the listbox, and takes changes
|
|
18
19
|
* back, so the value lives in one place.
|
|
19
20
|
*
|
|
21
|
+
* Set `valueContent` to draw the trigger's content from the chosen options,
|
|
22
|
+
* and several chosen options are written as a list in the reader's language.
|
|
23
|
+
*
|
|
20
24
|
* In the open list the arrow keys, Home, End, PageUp, PageDown and typed
|
|
21
25
|
* letters move the highlight, and Enter, Space or a click chooses it and
|
|
22
26
|
* closes the list. Tab closes the list and moves on. On the closed trigger,
|
|
@@ -103,6 +107,17 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
103
107
|
* Shown on the trigger while nothing is chosen.
|
|
104
108
|
*/
|
|
105
109
|
placeholder: string;
|
|
110
|
+
/**
|
|
111
|
+
* What the trigger shows for the chosen options: a function given them, in
|
|
112
|
+
* the order they appear, that returns text, an element or a Lit template.
|
|
113
|
+
*
|
|
114
|
+
* For a trigger that shows more than the words, an avatar beside a name or a
|
|
115
|
+
* count of a long set, as React Aria's `SelectValue` takes children. The
|
|
116
|
+
* trigger is named by what this draws, so keep the words in it. Nothing
|
|
117
|
+
* chosen still shows `placeholder`. A property only, there being no way to
|
|
118
|
+
* write a function in markup.
|
|
119
|
+
*/
|
|
120
|
+
valueContent?: ((chosen: readonly HelixHeadlessOption[]) => unknown) | undefined;
|
|
106
121
|
/**
|
|
107
122
|
* Which option is chosen, as an index, or `-1` where none is.
|
|
108
123
|
*
|
|
@@ -168,6 +183,13 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
168
183
|
* the commit creates the text node it needs.
|
|
169
184
|
*/
|
|
170
185
|
private get display();
|
|
186
|
+
/** The chosen options, in the order they appear. None on a server or while hydrating. */
|
|
187
|
+
private get chosenOptions();
|
|
188
|
+
/**
|
|
189
|
+
* What the trigger shows, behind a seam: what `value-content` draws for the
|
|
190
|
+
* chosen options, or their words, or the placeholder.
|
|
191
|
+
*/
|
|
192
|
+
protected renderValue(): unknown;
|
|
171
193
|
/** Where the highlight goes when the list opens, set by the key that opened it. */
|
|
172
194
|
private opening;
|
|
173
195
|
/**
|
|
@@ -187,6 +209,8 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
187
209
|
* Made on connection, there being no `MutationObserver` on a server.
|
|
188
210
|
*/
|
|
189
211
|
private watchers;
|
|
212
|
+
/** A link option, once followed, closes the panel as a choice does. */
|
|
213
|
+
private readonly handleLinkFollowed;
|
|
190
214
|
connectedCallback(): void;
|
|
191
215
|
disconnectedCallback(): void;
|
|
192
216
|
/** Opens the list with the highlight where the opening key says. */
|
|
@@ -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, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, reportValues, typesCharacter, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, afterLinkFollowed, customElement, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, reportValues, typesCharacter, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { caretDown } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
@@ -43,6 +43,9 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
43
43
|
this.opening = 'selected';
|
|
44
44
|
this.seen = new Set();
|
|
45
45
|
this.watchers = [];
|
|
46
|
+
this.handleLinkFollowed = (event) => {
|
|
47
|
+
afterLinkFollowed(event, () => this.requestOpen(false));
|
|
48
|
+
};
|
|
46
49
|
this.handleChange = (event) => {
|
|
47
50
|
const next = event.detail.value;
|
|
48
51
|
if (!this.requestValue(next)) {
|
|
@@ -105,16 +108,23 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
105
108
|
}
|
|
106
109
|
get display() {
|
|
107
110
|
const chosen = new Set(this.value === '' ? [] : this.value.split(','));
|
|
108
|
-
const words =
|
|
109
|
-
.filter((option) => chosen.has(option.value))
|
|
110
|
-
.map((option) => option.text);
|
|
111
|
+
const words = this.chosenOptions.map((option) => option.text);
|
|
111
112
|
if (words.length > 0) {
|
|
112
|
-
return
|
|
113
|
+
return new Intl.ListFormat(this.lang || undefined, { style: 'short', type: 'unit' }).format(words);
|
|
113
114
|
}
|
|
114
115
|
return chosen.size > 0 && !this.childrenKnown ? nothing : this.placeholder;
|
|
115
116
|
}
|
|
117
|
+
get chosenOptions() {
|
|
118
|
+
const chosen = new Set(this.value === '' ? [] : this.value.split(','));
|
|
119
|
+
return optionsAmong(this.knownChildren).filter((option) => chosen.has(option.value));
|
|
120
|
+
}
|
|
121
|
+
renderValue() {
|
|
122
|
+
const chosen = this.chosenOptions;
|
|
123
|
+
return this.valueContent && chosen.length > 0 ? this.valueContent(chosen) : this.display;
|
|
124
|
+
}
|
|
116
125
|
connectedCallback() {
|
|
117
126
|
super.connectedCallback();
|
|
127
|
+
this.addEventListener('helix-select', this.handleLinkFollowed);
|
|
118
128
|
const words = new MutationObserver(() => this.requestUpdate());
|
|
119
129
|
words.observe(this, {
|
|
120
130
|
attributeFilter: ['label', 'value'],
|
|
@@ -128,6 +138,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
128
138
|
}
|
|
129
139
|
disconnectedCallback() {
|
|
130
140
|
super.disconnectedCallback();
|
|
141
|
+
this.removeEventListener('helix-select', this.handleLinkFollowed);
|
|
131
142
|
for (const watcher of this.watchers) {
|
|
132
143
|
watcher.disconnect();
|
|
133
144
|
}
|
|
@@ -252,7 +263,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
252
263
|
@keydown=${this.handleTriggerKeydown}
|
|
253
264
|
>
|
|
254
265
|
<slot name="start"></slot>
|
|
255
|
-
<span part="value" id="value">${this.
|
|
266
|
+
<span part="value" id="value">${this.renderValue()}</span>
|
|
256
267
|
${''}
|
|
257
268
|
<slot name="end"></slot>
|
|
258
269
|
${''}
|
|
@@ -283,6 +294,9 @@ __decorate([
|
|
|
283
294
|
__decorate([
|
|
284
295
|
property()
|
|
285
296
|
], HelixHeadlessSelect.prototype, "placeholder", void 0);
|
|
297
|
+
__decorate([
|
|
298
|
+
property({ attribute: false })
|
|
299
|
+
], HelixHeadlessSelect.prototype, "valueContent", void 0);
|
|
286
300
|
HelixHeadlessSelect = __decorate([
|
|
287
301
|
customElement('helix-headless-select')
|
|
288
302
|
], HelixHeadlessSelect);
|
|
@@ -15,12 +15,22 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
15
15
|
* There is no `shape` property. Whether a placeholder is a line, a block, or a
|
|
16
16
|
* circle is presentation, which belongs to the styled tier.
|
|
17
17
|
*
|
|
18
|
+
* **Put the real content inside and set `loading`, and the skeleton takes its
|
|
19
|
+
* size.** While `loading` is set the content is inert, the host is
|
|
20
|
+
* `aria-busy`, and the styled tier hides the content and paints the
|
|
21
|
+
* placeholder over its box, so nothing moves when the content arrives. Take
|
|
22
|
+
* `loading` off and the content is shown as it is. An empty skeleton is a
|
|
23
|
+
* placeholder of its own size, as before.
|
|
24
|
+
*
|
|
18
25
|
* @since 0.1.0
|
|
19
26
|
* @status stable
|
|
20
27
|
* @category feedback
|
|
21
28
|
* @aliases Placeholder, Shimmer, Ghost
|
|
22
29
|
* @documentation https://fusion.dev/helix/components/skeleton
|
|
23
30
|
*
|
|
31
|
+
* @slot - The content the skeleton stands in for, which sizes it. Optional.
|
|
32
|
+
*
|
|
33
|
+
* @csspart content - The box around the content, inert while `loading`.
|
|
24
34
|
* @csspart skeleton - The placeholder shape.
|
|
25
35
|
*/
|
|
26
36
|
export declare class HelixHeadlessSkeleton extends HelixElement {
|
|
@@ -31,7 +41,22 @@ export declare class HelixHeadlessSkeleton extends HelixElement {
|
|
|
31
41
|
* Absent hides the placeholder from screen readers.
|
|
32
42
|
*/
|
|
33
43
|
label: string;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the content inside is still loading, which keeps it inert and
|
|
46
|
+
* draws the placeholder over it.
|
|
47
|
+
*
|
|
48
|
+
* Absent shows the content. An empty skeleton is a placeholder whatever
|
|
49
|
+
* this says. Reflected, because the styled tier hides the content on it.
|
|
50
|
+
*/
|
|
51
|
+
loading: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Whether the skeleton holds content, read off its children where they can
|
|
54
|
+
* be known. Not on a server, where an unlabeled skeleton is taken for an
|
|
55
|
+
* empty one until the page has its children.
|
|
56
|
+
*/
|
|
57
|
+
private get wraps();
|
|
34
58
|
protected willUpdate(changed: PropertyValues): void;
|
|
59
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
35
60
|
protected render(): TemplateResult;
|
|
36
61
|
}
|
|
37
62
|
declare global {
|