@fusion.dev/helix-headless 0.147.0 → 0.148.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 +4512 -790
- package/dist/accordion/item/accordion-item.d.ts +5 -2
- package/dist/accordion/item/accordion-item.js +11 -7
- package/dist/accordion/root/accordion-root.js +4 -6
- package/dist/announcement/root/announcement-root.d.ts +56 -5
- package/dist/announcement/root/announcement-root.js +124 -21
- package/dist/area-chart/root/area-chart-root.js +3 -4
- package/dist/badge/count.d.ts +14 -0
- package/dist/badge/count.js +20 -0
- package/dist/badge/root/badge-root.js +8 -22
- package/dist/blockquote/root/blockquote-root.d.ts +66 -8
- package/dist/blockquote/root/blockquote-root.js +85 -8
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +2 -2
- package/dist/button-group/arrows.d.ts +14 -0
- package/dist/button-group/arrows.js +10 -0
- package/dist/button-group/root/button-group-root.d.ts +141 -3
- package/dist/button-group/root/button-group-root.js +142 -2
- package/dist/canvas/edge-pan.d.ts +61 -0
- package/dist/canvas/edge-pan.js +63 -0
- package/dist/canvas/node/canvas-node.d.ts +12 -2
- package/dist/canvas/node/canvas-node.js +6 -2
- package/dist/canvas/root/canvas-document.d.ts +10 -0
- package/dist/canvas/root/canvas-document.js +1 -0
- package/dist/canvas/root/canvas-root.d.ts +107 -5
- package/dist/canvas/root/canvas-root.js +140 -36
- package/dist/canvas/snap.d.ts +42 -0
- package/dist/canvas/snap.js +32 -0
- package/dist/carousel/root/carousel-root.d.ts +4 -3
- package/dist/carousel/root/carousel-root.js +2 -6
- package/dist/chat/root/chat-root.d.ts +13 -3
- package/dist/chat/root/chat-root.js +2 -6
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +13 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +18 -10
- package/dist/checkbox-group/select-all.d.ts +11 -0
- package/dist/checkbox-group/select-all.js +5 -0
- package/dist/code-block/root/code-block-root.d.ts +8 -6
- package/dist/code-block/root/code-block-root.js +4 -3
- package/dist/color-picker/root/color-picker-root.js +6 -12
- package/dist/color-picker/wheel.d.ts +11 -0
- package/dist/color-picker/wheel.js +9 -0
- package/dist/combobox/root/combobox-root.d.ts +70 -11
- package/dist/combobox/root/combobox-root.js +68 -18
- package/dist/command/root/command-root.d.ts +4 -3
- package/dist/data-table/root/data-table-root.js +17 -44
- package/dist/description-list/item/description-list-item.d.ts +4 -0
- package/dist/description-list/item/description-list-item.js +7 -1
- package/dist/divider/root/divider-root.d.ts +45 -16
- package/dist/divider/root/divider-root.js +28 -4
- package/dist/drilldown/item/drilldown-item.js +3 -4
- package/dist/element-events.generated.js +1 -0
- package/dist/empty/root/empty-root.d.ts +17 -3
- package/dist/empty/root/empty-root.js +29 -5
- package/dist/file-input/root/file-input-root.js +3 -4
- package/dist/file-input/status.js +2 -1
- package/dist/filter-input/chip/filter-chip.js +2 -3
- package/dist/format-date/fields.d.ts +20 -0
- package/dist/format-date/fields.js +14 -0
- package/dist/format-date/options.d.ts +2 -1
- package/dist/format-date/options.js +9 -38
- package/dist/format-date/root/format-date-root.d.ts +35 -3
- package/dist/format-date/root/format-date-root.js +24 -32
- package/dist/graph/root/graph-root.d.ts +23 -5
- package/dist/graph/root/graph-root.js +17 -20
- package/dist/heatmap/root/heatmap-root.d.ts +12 -0
- package/dist/heatmap/root/heatmap-root.js +26 -11
- package/dist/image/root/image-root.d.ts +11 -0
- package/dist/kbd/root/kbd-root.js +1 -2
- package/dist/legend/root/legend-root.js +4 -17
- package/dist/list/root/list-root.js +8 -22
- package/dist/listbox/root/listbox-root.d.ts +119 -24
- package/dist/listbox/root/listbox-root.js +130 -132
- package/dist/map/marker/map-marker.d.ts +2 -1
- package/dist/map/root/map-root.d.ts +40 -2
- package/dist/map/root/map-root.js +64 -23
- package/dist/megamenu/root/megamenu-root.js +4 -11
- package/dist/menu/root/menu-root.d.ts +2 -2
- package/dist/navigation/root/navigation-root.js +5 -8
- package/dist/notifications/group/notification-group.d.ts +8 -1
- package/dist/notifications/group/notification-group.js +12 -6
- package/dist/notifications/notification/notification.d.ts +12 -1
- package/dist/notifications/notification/notification.js +3 -1
- package/dist/notifications/root/notifications-root.d.ts +41 -5
- package/dist/notifications/root/notifications-root.js +27 -7
- package/dist/object-inspector/root/object-inspector-root.d.ts +5 -1
- package/dist/object-inspector/root/object-inspector-root.js +21 -11
- package/dist/pagination/size/pagination-size.d.ts +1 -0
- package/dist/pagination/size/pagination-size.js +1 -1
- package/dist/pin-input/code.d.ts +23 -0
- package/dist/pin-input/code.js +25 -0
- package/dist/pin-input/root/pin-input-root.js +9 -23
- package/dist/qr-code/root/qr-code-root.d.ts +14 -3
- package/dist/qr-code/root/qr-code-root.js +19 -5
- package/dist/scatter-chart/measures.d.ts +22 -0
- package/dist/scatter-chart/measures.js +11 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +2 -6
- package/dist/scatter-chart/root/scatter-chart-root.js +6 -19
- package/dist/select/root/select-root.d.ts +56 -8
- package/dist/select/root/select-root.js +33 -9
- package/dist/speed-dial/group/speed-dial-group.d.ts +48 -0
- package/dist/speed-dial/group/speed-dial-group.js +43 -0
- package/dist/speed-dial/index.d.ts +1 -0
- package/dist/speed-dial/index.js +1 -0
- package/dist/speed-dial/item/speed-dial-item.d.ts +26 -1
- package/dist/speed-dial/item/speed-dial-item.js +41 -3
- package/dist/speed-dial/long-press.d.ts +50 -0
- package/dist/speed-dial/long-press.js +48 -0
- package/dist/speed-dial/root/speed-dial-root.d.ts +80 -1
- package/dist/speed-dial/root/speed-dial-root.js +114 -5
- package/dist/splitter/root/splitter-root.d.ts +7 -3
- package/dist/splitter/root/splitter-root.js +16 -3
- package/dist/table/cell/table-cell.d.ts +8 -1
- package/dist/table/cell/table-cell.js +6 -2
- package/dist/table/grid-controller.d.ts +117 -0
- package/dist/table/grid-controller.js +293 -0
- package/dist/table/root/table-root.d.ts +47 -3
- package/dist/table/root/table-root.js +81 -24
- package/dist/table/row/table-row.d.ts +13 -1
- package/dist/table/row/table-row.js +20 -6
- package/dist/tag/group/tag-group.js +6 -15
- package/dist/time-picker/root/time-picker-root.d.ts +1 -0
- package/dist/time-picker/root/time-picker-root.js +3 -0
- package/dist/toast/item/toast-item.d.ts +6 -3
- package/dist/toast/item/toast-item.js +1 -0
- package/dist/toast/root/toast-root.d.ts +13 -1
- package/dist/toast/root/toast-root.js +20 -14
- package/dist/toggle/group/toggle-group.js +3 -5
- package/dist/toolbar/root/toolbar-root.d.ts +31 -0
- package/dist/toolbar/root/toolbar-root.js +39 -8
- package/dist/tooltip/root/tooltip-root.js +1 -2
- package/dist/video/root/video-root.d.ts +11 -0
- package/dist/video/root/video-root.js +15 -1
- package/dist/virtual-list/root/virtual-list-root.js +6 -18
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +2005 -266
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +338 -62
- package/dist/kbd/keys.d.ts +0 -29
- package/dist/kbd/keys.js +0 -52
- package/dist/tooltip/focus-target.d.ts +0 -6
- package/dist/tooltip/focus-target.js +0 -9
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
var HelixHeadlessObjectInspector_1;
|
|
8
|
-
import { AriaForwardController, CopyController, countLabel, customElement, drawStatus, elementById, fillTemplate, formatNumbers, HelixActivateEvent, HelixBeforeActivateEvent, HelixBeforeCloseEvent, HelixBeforeOpenEvent, HelixElement, HelixFilterEvent, HelixFilteredEvent, inlineStep, requestChange, StatusController, scrollItemIntoView, searchableById, Typeahead, treeArrow, VirtualizeController, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { AriaForwardController, CopyController, countLabel, customElement, drawStatus, elementById, fillTemplate, formatNumbers, HelixActivateEvent, HelixBeforeActivateEvent, HelixBeforeCloseEvent, HelixBeforeOpenEvent, HelixElement, HelixFilterEvent, HelixFilteredEvent, inlineStep, pageRows, requestChange, StatusController, scrollItemIntoView, scrollRoom, searchableById, Typeahead, treeArrow, VirtualizeController, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { caretDown, caretRight } from '@fusion.dev/helix-icons';
|
|
10
10
|
import { html, nothing } from 'lit';
|
|
11
11
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -85,10 +85,10 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
85
85
|
this.move(rows.length - 1);
|
|
86
86
|
break;
|
|
87
87
|
case 'PageDown':
|
|
88
|
-
this.move(this.cursor + this.
|
|
88
|
+
this.move(this.cursor + this.pageStep());
|
|
89
89
|
break;
|
|
90
90
|
case 'PageUp':
|
|
91
|
-
this.move(this.cursor - this.
|
|
91
|
+
this.move(this.cursor - this.pageStep());
|
|
92
92
|
break;
|
|
93
93
|
case 'ArrowRight':
|
|
94
94
|
case 'ArrowLeft':
|
|
@@ -153,6 +153,11 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
153
153
|
this.requestUpdate();
|
|
154
154
|
}
|
|
155
155
|
};
|
|
156
|
+
this.handleTreeFocus = () => {
|
|
157
|
+
this.revealing = true;
|
|
158
|
+
this.focusing = true;
|
|
159
|
+
this.requestUpdate();
|
|
160
|
+
};
|
|
156
161
|
this.handleFocusIn = (event) => {
|
|
157
162
|
const index = Number(event.target.dataset?.index);
|
|
158
163
|
if (Number.isInteger(index) && index !== this.cursor) {
|
|
@@ -367,6 +372,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
367
372
|
}
|
|
368
373
|
this.revealing = true;
|
|
369
374
|
this.focusing = true;
|
|
375
|
+
this.requestUpdate();
|
|
370
376
|
return true;
|
|
371
377
|
}
|
|
372
378
|
typeahead(letter) {
|
|
@@ -375,11 +381,8 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
375
381
|
this.move(at);
|
|
376
382
|
}
|
|
377
383
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const room = tree && tree.scrollHeight > tree.clientHeight + 1 ? tree.clientHeight : window.innerHeight;
|
|
381
|
-
const tall = this.virtualize.sizeOf(this.cursor) || HelixHeadlessObjectInspector_1.ESTIMATE;
|
|
382
|
-
return Math.max(1, Math.floor(room / tall) - 1);
|
|
384
|
+
pageStep() {
|
|
385
|
+
return pageRows(scrollRoom(this.partNamed('tree')), this.virtualize.sizeOf(this.cursor) || HelixHeadlessObjectInspector_1.ESTIMATE);
|
|
383
386
|
}
|
|
384
387
|
handleRowClick(index, row) {
|
|
385
388
|
if (this.move(index) && row.branch) {
|
|
@@ -446,8 +449,11 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
446
449
|
</div>`;
|
|
447
450
|
}
|
|
448
451
|
hasFocusedRow() {
|
|
452
|
+
return this.focusedIndex() !== undefined;
|
|
453
|
+
}
|
|
454
|
+
focusedIndex() {
|
|
449
455
|
const focused = this.shadowRoot?.activeElement;
|
|
450
|
-
return focused?.getAttribute?.('role') === 'row';
|
|
456
|
+
return focused?.getAttribute?.('role') === 'row' ? Number(focused.dataset.index) : undefined;
|
|
451
457
|
}
|
|
452
458
|
renderCopyButton(row) {
|
|
453
459
|
return staticHtml `<${this.tag('copy-button')}
|
|
@@ -464,8 +470,9 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
464
470
|
render() {
|
|
465
471
|
const rows = this.rows;
|
|
466
472
|
const { first, last } = this.windowed ? this.virtualize.window : { first: 0, last: rows.length };
|
|
467
|
-
const
|
|
468
|
-
|
|
473
|
+
const focused = this.focusedIndex();
|
|
474
|
+
const kept = this.windowed && focused !== undefined && (focused < first || focused >= last)
|
|
475
|
+
? focused
|
|
469
476
|
: undefined;
|
|
470
477
|
const { after, before } = this.windowed
|
|
471
478
|
? this.virtualize.spacers(kept)
|
|
@@ -475,6 +482,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
475
482
|
if (kept !== undefined && keptRow) {
|
|
476
483
|
shown.splice(kept < first ? 0 : shown.length, 0, [keptRow, kept]);
|
|
477
484
|
}
|
|
485
|
+
const stopless = rows.length > 0 && !shown.some(([, at]) => at === this.cursor);
|
|
478
486
|
return html `${this.label ? html `<div part="header"><span part="label">${this.label}</span></div>` : nothing}${this.filterable
|
|
479
487
|
? html `<input
|
|
480
488
|
part="search-field"
|
|
@@ -494,8 +502,10 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
494
502
|
id="tree"
|
|
495
503
|
role="treegrid"
|
|
496
504
|
?data-scroller=${this.windowed}
|
|
505
|
+
tabindex=${stopless ? '0' : nothing}
|
|
497
506
|
aria-label=${this.label || this.treeLabel}
|
|
498
507
|
@keydown=${this.handleKeydown}
|
|
508
|
+
@focus=${this.handleTreeFocus}
|
|
499
509
|
@focusin=${this.handleFocusIn}
|
|
500
510
|
@focusout=${this.handleFocusOut}
|
|
501
511
|
@scroll=${() => this.virtualize.measure()}
|
|
@@ -65,6 +65,7 @@ import '../../select/index.js';
|
|
|
65
65
|
* @csspart control-listbox-loading - The text shown while the options load.
|
|
66
66
|
* @csspart control-listbox-search - The region that holds the filter field.
|
|
67
67
|
* @csspart control-listbox-search-field - The filter field.
|
|
68
|
+
* @csspart control-live - The select's `live` part, the region a screen reader hears a choice made on the closed trigger from.
|
|
68
69
|
* @csspart control-surface - The floating panel.
|
|
69
70
|
* @csspart control-trigger - The closed control, which shows the chosen size.
|
|
70
71
|
* @csspart control-value - The chosen size inside the trigger.
|
|
@@ -98,7 +98,7 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
98
98
|
listbox-filter-mark: control-listbox-filter-mark, listbox-hint: control-listbox-hint,
|
|
99
99
|
listbox-items: control-listbox-items, listbox-label: control-listbox-label,
|
|
100
100
|
listbox-live: control-listbox-live, listbox-loading: control-listbox-loading, listbox-search: control-listbox-search,
|
|
101
|
-
listbox-search-field: control-listbox-search-field, surface: control-surface,
|
|
101
|
+
listbox-search-field: control-listbox-search-field, live: control-live, surface: control-surface,
|
|
102
102
|
trigger: control-trigger, value: control-value"
|
|
103
103
|
label=${named ? '' : this.label}
|
|
104
104
|
aria-label=${named || nothing}
|
package/dist/pin-input/code.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PickerVerdict } from '@fusion.dev/helix-core';
|
|
1
2
|
/** What a box accepts, which decides the keyboard a phone offers. */
|
|
2
3
|
export type PinType = 'alphanumeric' | 'numeric' | 'text';
|
|
3
4
|
/** How typed letters are cased: as typed, or turned upper or lower case. */
|
|
@@ -35,3 +36,25 @@ export declare const readTyped: (raw: string, caret: number, type: PinType, lett
|
|
|
35
36
|
* holding two fill from box three.
|
|
36
37
|
*/
|
|
37
38
|
export declare const overwriteCode: (code: string, at: number, text: string, count: number) => CodeEdit;
|
|
39
|
+
/** The messages a code's verdict is written with, where the page set its own. */
|
|
40
|
+
export interface CodeMessages {
|
|
41
|
+
/** For a code with no characters in a required field. */
|
|
42
|
+
missing?: string | undefined;
|
|
43
|
+
/** For a code with fewer characters than boxes; `{length}` is how many. */
|
|
44
|
+
short?: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* What is wrong with a code, as a picker field reports it: a required field
|
|
48
|
+
* with nothing in it is missing, a code with fewer characters than boxes is
|
|
49
|
+
* too short, and anything else is fine (`''`). The platform's own words where
|
|
50
|
+
* the page set none.
|
|
51
|
+
*/
|
|
52
|
+
export declare const codeVerdict: (code: string, count: number, required: boolean, messages: CodeMessages) => PickerVerdict;
|
|
53
|
+
/**
|
|
54
|
+
* The box a caret key moves to from `caret`, kept within the boxes up to
|
|
55
|
+
* `end`, or `undefined` for a key that moves nothing.
|
|
56
|
+
*
|
|
57
|
+
* Not `inlineStep`: the row is left to right whatever the page, so the key
|
|
58
|
+
* pointing right is the one that moves on in every script.
|
|
59
|
+
*/
|
|
60
|
+
export declare const caretTo: (key: string, caret: number, end: number) => number | undefined;
|
package/dist/pin-input/code.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fillTemplate } from '@fusion.dev/helix-core';
|
|
1
2
|
export const cleanCode = (text, type, letterCase = 'preserve') => {
|
|
2
3
|
const trimmed = text.trim();
|
|
3
4
|
const kept = type === 'numeric'
|
|
@@ -23,3 +24,27 @@ export const overwriteCode = (code, at, text, count) => {
|
|
|
23
24
|
}
|
|
24
25
|
return { caret: Math.min(count - 1, start + text.length), code: characters.join('') };
|
|
25
26
|
};
|
|
27
|
+
export const codeVerdict = (code, count, required, messages) => {
|
|
28
|
+
if (required && code === '') {
|
|
29
|
+
return ['valueMissing', messages.missing || 'Please fill in this field.'];
|
|
30
|
+
}
|
|
31
|
+
if (code !== '' && code.length < count) {
|
|
32
|
+
return [
|
|
33
|
+
'tooShort',
|
|
34
|
+
fillTemplate(messages.short || 'Please enter all {length} characters.', { length: count }),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
return '';
|
|
38
|
+
};
|
|
39
|
+
export const caretTo = (key, caret, end) => {
|
|
40
|
+
const to = key === 'ArrowRight'
|
|
41
|
+
? caret + 1
|
|
42
|
+
: key === 'ArrowLeft'
|
|
43
|
+
? caret - 1
|
|
44
|
+
: key === 'Home'
|
|
45
|
+
? 0
|
|
46
|
+
: key === 'End'
|
|
47
|
+
? end
|
|
48
|
+
: undefined;
|
|
49
|
+
return to === undefined ? undefined : Math.max(0, Math.min(to, end));
|
|
50
|
+
};
|
|
@@ -4,10 +4,10 @@ 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,
|
|
7
|
+
import { AriaForwardController, customElement, HelixCompleteEvent, HelixFormElement, MixinControllerValue, MixinField, restoreValue, submitImplicitly, verdictFlags, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
|
-
import { cleanCode, overwriteCode, readTyped, } from '../code.js';
|
|
10
|
+
import { caretTo, cleanCode, codeVerdict, overwriteCode, readTyped, } from '../code.js';
|
|
11
11
|
import { separatorsAfter } from '../format.js';
|
|
12
12
|
const UNSEEN = 'position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;font-size:16px';
|
|
13
13
|
const keepFocus = (event) => event.preventDefault();
|
|
@@ -61,20 +61,12 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
|
|
|
61
61
|
}
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
const to = event.key
|
|
65
|
-
? this.caretBox + 1
|
|
66
|
-
: event.key === 'ArrowLeft'
|
|
67
|
-
? this.caretBox - 1
|
|
68
|
-
: event.key === 'Home'
|
|
69
|
-
? 0
|
|
70
|
-
: event.key === 'End'
|
|
71
|
-
? this.end
|
|
72
|
-
: undefined;
|
|
64
|
+
const to = caretTo(event.key, this.caretBox, this.end);
|
|
73
65
|
if (to === undefined) {
|
|
74
66
|
return;
|
|
75
67
|
}
|
|
76
68
|
event.preventDefault();
|
|
77
|
-
this.active =
|
|
69
|
+
this.active = to;
|
|
78
70
|
this.placeCaret(true);
|
|
79
71
|
};
|
|
80
72
|
this.handlePress = (event) => {
|
|
@@ -172,17 +164,11 @@ let HelixHeadlessPinInput = class HelixHeadlessPinInput extends MixinControllerV
|
|
|
172
164
|
if (!control) {
|
|
173
165
|
return;
|
|
174
166
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
length: this.count,
|
|
181
|
-
}), control);
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
this.internals.setValidity({}, '', control);
|
|
185
|
-
}
|
|
167
|
+
const found = verdictFlags(codeVerdict(this.value, this.count, this.required, {
|
|
168
|
+
missing: this.valueMissingMessage,
|
|
169
|
+
short: this.tooShortMessage,
|
|
170
|
+
}));
|
|
171
|
+
this.internals.setValidity(found?.[0] ?? {}, found?.[1] ?? '', control);
|
|
186
172
|
this.refreshFeedback();
|
|
187
173
|
}
|
|
188
174
|
focus(options) {
|
|
@@ -27,7 +27,8 @@ export type QrStyle = 'dots' | 'rounded' | 'square';
|
|
|
27
27
|
* `correction` sets how much of the code can be lost. At `H` a code can lose
|
|
28
28
|
* thirty percent and still scan, so a mark in the center slot is safe. At `L`
|
|
29
29
|
* the same mark makes the code unscannable. The default is `M`, and `H` when the
|
|
30
|
-
* `logo` slot is filled.
|
|
30
|
+
* `logo` slot is filled. A code that holds a logo at a `correction` below `H`
|
|
31
|
+
* warns once with the kind `unscannable-logo`.
|
|
31
32
|
*
|
|
32
33
|
* A higher level holds fewer characters, so a value that fits at `M` can be too
|
|
33
34
|
* long once a logo raises the level to `H`. A value too long for the level
|
|
@@ -37,7 +38,8 @@ export type QrStyle = 'dots' | 'rounded' | 'square';
|
|
|
37
38
|
* `toSvg()`, `toPng()` and `download()` give the drawn code as a file of its
|
|
38
39
|
* own, in the colors it is drawn in, with a slotted image or SVG logo where
|
|
39
40
|
* it sits, for a page that offers it to save or print, as Zag's download
|
|
40
|
-
* trigger does.
|
|
41
|
+
* trigger does. `download()` saves an SVG for a name ending in `.svg`, and a
|
|
42
|
+
* PNG for any other.
|
|
41
43
|
*
|
|
42
44
|
* @since 0.1.0
|
|
43
45
|
* @status stable
|
|
@@ -111,6 +113,14 @@ export declare class HelixHeadlessQrCode extends HelixElement {
|
|
|
111
113
|
protected firstUpdated(changed: PropertyValues): void;
|
|
112
114
|
/** The level actually used, which the slot can raise. */
|
|
113
115
|
private get level();
|
|
116
|
+
/** Whether this code has warned that its logo may keep it from scanning. */
|
|
117
|
+
private toldLogo;
|
|
118
|
+
/**
|
|
119
|
+
* Warns once when a logo covers a code whose level was set below `H`, where
|
|
120
|
+
* the cover can take more than the level can lose. A level the code chose
|
|
121
|
+
* itself is `H` already.
|
|
122
|
+
*/
|
|
123
|
+
private auditLogo;
|
|
114
124
|
/** The value and level that did not fit, so `error` fires once for each. */
|
|
115
125
|
private overflowed;
|
|
116
126
|
/**
|
|
@@ -148,7 +158,8 @@ export declare class HelixHeadlessQrCode extends HelixElement {
|
|
|
148
158
|
*/
|
|
149
159
|
toPng(size?: number): Promise<Blob | null>;
|
|
150
160
|
/**
|
|
151
|
-
* Saves the code as a
|
|
161
|
+
* Saves the code as a file named `filename`, `size` pixels square: an SVG
|
|
162
|
+
* where the name ends in `.svg`, and a PNG otherwise.
|
|
152
163
|
*
|
|
153
164
|
* Call it from a press, since a browser lets a page start a download only
|
|
154
165
|
* in answer to one. Does nothing where no code is drawn.
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, HelixElement, rgbOf } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, reportRuntime, rgbOf, slotFilled, } 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';
|
|
@@ -81,6 +81,7 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
81
81
|
this.label = '';
|
|
82
82
|
this.value = '';
|
|
83
83
|
this.logo = false;
|
|
84
|
+
this.toldLogo = false;
|
|
84
85
|
this.overflowed = '';
|
|
85
86
|
}
|
|
86
87
|
willUpdate(changed) {
|
|
@@ -96,6 +97,17 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
96
97
|
get level() {
|
|
97
98
|
return this.correction ?? (this.logo ? 'H' : 'M');
|
|
98
99
|
}
|
|
100
|
+
auditLogo() {
|
|
101
|
+
if (this.toldLogo || !this.logo || (this.correction ?? 'H') === 'H') {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this.toldLogo = true;
|
|
105
|
+
reportRuntime({
|
|
106
|
+
kind: 'unscannable-logo',
|
|
107
|
+
message: `<${this.localName}> holds a logo at correction "${this.correction}", which may keep it from scanning. Set \`correction\` to "H", or leave it unset.`,
|
|
108
|
+
tag: this.localName,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
99
111
|
encoded() {
|
|
100
112
|
try {
|
|
101
113
|
return encode(this.value, { border: 0, ecc: this.level });
|
|
@@ -109,6 +121,7 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
109
121
|
}
|
|
110
122
|
updated(changed) {
|
|
111
123
|
super.updated(changed);
|
|
124
|
+
this.auditLogo();
|
|
112
125
|
const key = `${this.level}:${this.value}`;
|
|
113
126
|
const overflow = this.value !== '' && this.encoded() === undefined;
|
|
114
127
|
this.toggleState('overflow', overflow);
|
|
@@ -186,11 +199,12 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
186
199
|
return new Promise((resolve) => canvas.toBlob(resolve, 'image/png'));
|
|
187
200
|
}
|
|
188
201
|
async download(filename = 'qr-code.png', size = 512) {
|
|
189
|
-
const
|
|
190
|
-
|
|
202
|
+
const svg = /\.svg$/i.test(filename) ? this.toSvg(size) : '';
|
|
203
|
+
const file = svg ? new Blob([svg], { type: 'image/svg+xml' }) : await this.toPng(size);
|
|
204
|
+
if (!file) {
|
|
191
205
|
return;
|
|
192
206
|
}
|
|
193
|
-
const url = URL.createObjectURL(
|
|
207
|
+
const url = URL.createObjectURL(file);
|
|
194
208
|
const link = document.createElement('a');
|
|
195
209
|
link.href = url;
|
|
196
210
|
link.download = filename;
|
|
@@ -235,7 +249,7 @@ let HelixHeadlessQrCode = class HelixHeadlessQrCode extends HelixElement {
|
|
|
235
249
|
<slot
|
|
236
250
|
name="logo"
|
|
237
251
|
@slotchange=${(event) => {
|
|
238
|
-
const next = event.target
|
|
252
|
+
const next = slotFilled(event.target);
|
|
239
253
|
if (next !== this.logo) {
|
|
240
254
|
this.logo = next;
|
|
241
255
|
this.requestUpdate();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** The numeric columns by what they measure. */
|
|
2
|
+
export interface Measures {
|
|
3
|
+
/** The column across, the first one that is not the size. */
|
|
4
|
+
across: number | undefined;
|
|
5
|
+
/** The column `size-by` names, which sizes the points. */
|
|
6
|
+
size: number | undefined;
|
|
7
|
+
/** Every other column, each a series up. */
|
|
8
|
+
ups: number[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The numeric columns by what they measure: the column whose heading
|
|
12
|
+
* `sizeBy` names as the size, by its series key, then the first of the rest
|
|
13
|
+
* across and every other one up.
|
|
14
|
+
*/
|
|
15
|
+
export declare const measuresOf: (columns: readonly number[], name: (column: number) => string, sizeBy: string) => Measures;
|
|
16
|
+
/**
|
|
17
|
+
* Each row's point size from its reading in the size column, by area, so a
|
|
18
|
+
* point twice the measure is twice the ink: the square root of its share of
|
|
19
|
+
* the largest. A size below zero is none, and a row with no size, or a column
|
|
20
|
+
* whose largest is not above zero, has no weight.
|
|
21
|
+
*/
|
|
22
|
+
export declare const bubbleWeights: (sizes: readonly (number | undefined)[]) => (number | undefined)[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { seriesKey } from '@fusion.dev/helix-core';
|
|
2
|
+
export const measuresOf = (columns, name, sizeBy) => {
|
|
3
|
+
const key = seriesKey(sizeBy);
|
|
4
|
+
const size = key === '' ? undefined : columns.find((column) => seriesKey(name(column)) === key);
|
|
5
|
+
const [across, ...ups] = columns.filter((column) => column !== size);
|
|
6
|
+
return { across, size, ups };
|
|
7
|
+
};
|
|
8
|
+
export const bubbleWeights = (sizes) => {
|
|
9
|
+
const largest = Math.max(0, ...sizes.map((one) => one ?? 0));
|
|
10
|
+
return sizes.map((one) => one === undefined || largest <= 0 ? undefined : Math.sqrt(Math.max(0, one) / largest));
|
|
11
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { nothing, type TemplateResult } from 'lit';
|
|
3
3
|
import '../../tooltip/index.js';
|
|
4
|
+
import { type Measures } from '../measures.js';
|
|
4
5
|
/** One row drawn as a point: which row, which series, and where, in percent of the plot. */
|
|
5
6
|
export interface ScatterPoint {
|
|
6
7
|
depth: number;
|
|
@@ -172,12 +173,7 @@ export declare class HelixHeadlessScatterChart extends HelixHeadlessScatterChart
|
|
|
172
173
|
* The numeric columns by what they measure: the first across, the column
|
|
173
174
|
* `size-by` names as the size, and every other one up, as a series.
|
|
174
175
|
*/
|
|
175
|
-
protected get measures():
|
|
176
|
-
across: number | undefined;
|
|
177
|
-
size: number | undefined;
|
|
178
|
-
ups: number[];
|
|
179
|
-
};
|
|
180
|
-
showsColumn(cell: number): boolean;
|
|
176
|
+
protected get measures(): Measures;
|
|
181
177
|
/** Whether the levels across are ruled. */
|
|
182
178
|
protected get rulesX(): boolean;
|
|
183
179
|
/** Whether the levels up are ruled. */
|
|
@@ -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 { CHART_PLOT, customElement, drawTooltip, extent, formatNumbers, HelixElement, isRtl, linear, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex,
|
|
7
|
+
import { CHART_PLOT, customElement, drawTooltip, extent, formatNumbers, HelixElement, isRtl, linear, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, ticks, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing, svg } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import '../../tooltip/index.js';
|
|
11
11
|
import { correlation, leastSquares } from '../fit.js';
|
|
12
|
+
import { bubbleWeights, measuresOf } from '../measures.js';
|
|
12
13
|
const REACH = 24;
|
|
13
14
|
const COEFFICIENTS = new Map();
|
|
14
15
|
const coefficientIn = (locale) => {
|
|
@@ -87,16 +88,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
87
88
|
return depth < 0 ? undefined : seriesIndex(depth);
|
|
88
89
|
}
|
|
89
90
|
get measures() {
|
|
90
|
-
|
|
91
|
-
const key = seriesKey(this.sizeBy);
|
|
92
|
-
const size = key === ''
|
|
93
|
-
? undefined
|
|
94
|
-
: this.plottedColumns.find((column) => seriesKey(rows.find((row) => row.cells[column])?.cells[column]?.name ?? '') === key);
|
|
95
|
-
const [across, ...ups] = this.plottedColumns.filter((column) => column !== size);
|
|
96
|
-
return { across, size, ups };
|
|
97
|
-
}
|
|
98
|
-
showsColumn(cell) {
|
|
99
|
-
return cell !== this.measures.size && super.showsColumn(cell);
|
|
91
|
+
return measuresOf(this.plottedColumns, (column) => this.columnName(column), this.sizeBy);
|
|
100
92
|
}
|
|
101
93
|
get rulesX() {
|
|
102
94
|
return this.gridlines !== undefined && this.gridlines !== 'y';
|
|
@@ -107,7 +99,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
107
99
|
get field() {
|
|
108
100
|
const rows = this.sourceRows;
|
|
109
101
|
const { across, size, ups } = this.measures;
|
|
110
|
-
const name = (column) => column === undefined ? '' :
|
|
102
|
+
const name = (column) => column === undefined ? '' : this.columnName(column);
|
|
111
103
|
const pairs = ups.map((column) => rows.flatMap((row, index) => {
|
|
112
104
|
const x = across === undefined ? undefined : row.cells[across]?.value;
|
|
113
105
|
const y = row.cells[column]?.value;
|
|
@@ -119,19 +111,14 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
119
111
|
const y = nice(extent(all.length > 0 ? all.map(([, one]) => one) : [0]));
|
|
120
112
|
const along = linear(x, [0, PLOT_WIDTH]);
|
|
121
113
|
const up = linear(y, [PLOT_HEIGHT, 0]);
|
|
122
|
-
const
|
|
123
|
-
const largest = Math.max(0, ...sizes.map((one) => one ?? 0));
|
|
124
|
-
const weight = (row) => {
|
|
125
|
-
const one = sizes[row];
|
|
126
|
-
return one === undefined || largest <= 0 ? undefined : Math.sqrt(Math.max(0, one) / largest);
|
|
127
|
-
};
|
|
114
|
+
const weights = bubbleWeights(rows.map((row) => (size === undefined ? undefined : row.cells[size]?.value)));
|
|
128
115
|
return {
|
|
129
116
|
pairs: pairs.map((series) => series.map(([one, two]) => [one, two])),
|
|
130
117
|
points: pairs.flatMap((series, depth) => shown[depth]
|
|
131
118
|
? series.map(([one, two, row]) => ({
|
|
132
119
|
depth,
|
|
133
120
|
row,
|
|
134
|
-
weight:
|
|
121
|
+
weight: weights[row],
|
|
135
122
|
x: along(one),
|
|
136
123
|
y: up(two),
|
|
137
124
|
}))
|
|
@@ -21,13 +21,36 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
21
21
|
* Set `valueContent` to draw the trigger's content from the chosen options,
|
|
22
22
|
* and several chosen options are written as a list in the reader's language.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
24
|
+
* **Keyboard.** On the closed trigger:
|
|
25
|
+
*
|
|
26
|
+
* | Key | What it does |
|
|
27
|
+
* |---|---|
|
|
28
|
+
* | Down, Enter, Space | Opens the list on the chosen option, or the first. |
|
|
29
|
+
* | Up | Opens the list on the chosen option, or the last. |
|
|
30
|
+
* | Home, End | Opens the list on the first or the last option. |
|
|
31
|
+
* | Left, Right | Chooses the option before or after the chosen one without opening, as React Aria's Select does, in either direction of text. |
|
|
32
|
+
* | A letter or a word | Chooses the option whose words start with what you typed, as a native `<select>` does. With `multiple`, opens the list on it. |
|
|
33
|
+
*
|
|
34
|
+
* In the open list, which is a `Listbox`:
|
|
35
|
+
*
|
|
36
|
+
* | Key | What it does |
|
|
37
|
+
* |---|---|
|
|
38
|
+
* | Down, Up, Home, End, Page Down, Page Up | Moves the highlight. |
|
|
39
|
+
* | A letter or a word | Moves the highlight to the next option whose words start with what you typed. |
|
|
40
|
+
* | Enter, Space | Chooses the highlighted option and closes the list. With `multiple`, toggles it and leaves the list open. |
|
|
41
|
+
* | Escape | Closes the list and puts focus back on the trigger. |
|
|
42
|
+
* | Tab | Closes the list and moves on. |
|
|
43
|
+
*
|
|
44
|
+
* A choice made on the closed trigger is said aloud on Apple devices, where
|
|
45
|
+
* VoiceOver does not read the trigger's new name.
|
|
46
|
+
*
|
|
47
|
+
* **ARIA.** The trigger is a `button` with `aria-haspopup="listbox"` and
|
|
48
|
+
* `aria-expanded`, named by the label and then the chosen words, as a native
|
|
49
|
+
* `<select>` is. The list is the listbox `Listbox` describes, named by the
|
|
50
|
+
* label, or by `list-label` where there is none.
|
|
51
|
+
*
|
|
52
|
+
* Set `autocomplete` to let a browser's autofill choose, as a native `<select>`
|
|
53
|
+
* with the same attribute would.
|
|
31
54
|
*
|
|
32
55
|
* @since 0.1.0
|
|
33
56
|
* @status stable
|
|
@@ -69,6 +92,7 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
69
92
|
* @csspart listbox-loading - The text shown while the options load.
|
|
70
93
|
* @csspart listbox-search - The region that holds the filter field.
|
|
71
94
|
* @csspart listbox-search-field - The filter field.
|
|
95
|
+
* @csspart live - The region a screen reader announces a choice made on the closed trigger from, drawn once there is one to say. Visually hidden in the styled tier.
|
|
72
96
|
* @csspart surface - The floating panel.
|
|
73
97
|
* @csspart trigger - The closed control, which shows the chosen value.
|
|
74
98
|
* @csspart value - The chosen option's text inside the trigger.
|
|
@@ -81,6 +105,18 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
81
105
|
*/
|
|
82
106
|
export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
83
107
|
protected readonly aria: AriaForwardController;
|
|
108
|
+
/** The region a choice made on the closed trigger is said from. */
|
|
109
|
+
private readonly status;
|
|
110
|
+
/**
|
|
111
|
+
* What a browser's autofill may fill in, as a platform token such as
|
|
112
|
+
* `country` or `cc-exp-month`, as on a native `<select>`.
|
|
113
|
+
*
|
|
114
|
+
* Set, the select keeps a hidden native `<select>` with the same options for
|
|
115
|
+
* the browser to fill, as React Aria's `HiddenSelect` does, and takes the
|
|
116
|
+
* option the browser picks, by its value or its words, as the value. Empty
|
|
117
|
+
* draws no hidden select, and a browser fills nothing.
|
|
118
|
+
*/
|
|
119
|
+
autocomplete: string;
|
|
84
120
|
/**
|
|
85
121
|
* The text shown when no options match the filter.
|
|
86
122
|
*/
|
|
@@ -283,9 +319,21 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
283
319
|
* Aria's Select do, so a reader who knows the answer types it. A Space in the
|
|
284
320
|
* middle of those letters is one of them. With `multiple`, a letter opens the
|
|
285
321
|
* list on the match instead, because adding to a set is a choice the reader
|
|
286
|
-
* makes in the list.
|
|
322
|
+
* makes in the list. ArrowLeft and ArrowRight choose the option before and
|
|
323
|
+
* after the chosen one.
|
|
287
324
|
*/
|
|
288
325
|
private readonly handleTriggerKeydown;
|
|
326
|
+
/**
|
|
327
|
+
* Chooses from the closed trigger, and says the choice on Apple devices.
|
|
328
|
+
*
|
|
329
|
+
* The trigger is named by the label and the chosen words, so a choice made
|
|
330
|
+
* on it renames the control in focus. VoiceOver does not read a name that
|
|
331
|
+
* changes under focus, so a reader there heard nothing as a letter or an
|
|
332
|
+
* arrow changed the answer. The words are said in a live region, as React
|
|
333
|
+
* Aria says a combobox's choice for VoiceOver alone, since other screen
|
|
334
|
+
* readers read the new name.
|
|
335
|
+
*/
|
|
336
|
+
private choose;
|
|
289
337
|
/**
|
|
290
338
|
* Tab closes the list and lets focus move on, as a native `<select>` does.
|
|
291
339
|
*
|