@fusion.dev/helix-headless 0.146.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 +9287 -1084
- package/dist/accordion/item/accordion-item.d.ts +43 -21
- package/dist/accordion/item/accordion-item.js +37 -11
- package/dist/accordion/root/accordion-root.d.ts +8 -2
- package/dist/accordion/root/accordion-root.js +6 -8
- package/dist/announcement/root/announcement-root.d.ts +66 -6
- package/dist/announcement/root/announcement-root.js +144 -13
- package/dist/area-chart/root/area-chart-root.d.ts +18 -1
- package/dist/area-chart/root/area-chart-root.js +14 -7
- package/dist/avatar/root/avatar-root.d.ts +31 -1
- package/dist/avatar/root/avatar-root.js +11 -1
- package/dist/badge/count.d.ts +14 -0
- package/dist/badge/count.js +20 -0
- package/dist/badge/root/badge-root.d.ts +57 -6
- package/dist/badge/root/badge-root.js +77 -8
- 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/blockquote/root/blockquote-root.d.ts +66 -8
- package/dist/blockquote/root/blockquote-root.js +85 -8
- 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/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/card/root/card-root.d.ts +12 -1
- package/dist/card/root/card-root.js +11 -4
- 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 +28 -4
- package/dist/chat/root/chat-root.js +12 -7
- package/dist/checkbox/root/checkbox-root.js +5 -7
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +13 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +16 -7
- package/dist/checkbox-group/select-all.d.ts +9 -4
- package/dist/checkbox-group/select-all.js +1 -1
- package/dist/code-block/root/code-block-root.d.ts +41 -18
- package/dist/code-block/root/code-block-root.js +21 -6
- 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 +99 -55
- package/dist/color-picker/wheel.d.ts +28 -0
- package/dist/color-picker/wheel.js +15 -0
- package/dist/combobox/root/combobox-root.d.ts +83 -11
- package/dist/combobox/root/combobox-root.js +81 -18
- package/dist/command/root/command-root.d.ts +7 -4
- 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 +29 -50
- 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 +22 -4
- package/dist/description-list/item/description-list-item.js +14 -4
- package/dist/divider/root/divider-root.d.ts +45 -16
- package/dist/divider/root/divider-root.js +28 -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 +38 -4
- package/dist/drilldown/root/drilldown-root.js +3 -2
- package/dist/element-events.generated.js +5 -1
- package/dist/empty/root/empty-root.d.ts +46 -2
- package/dist/empty/root/empty-root.js +50 -5
- package/dist/file-input/root/file-input-root.d.ts +34 -6
- package/dist/file-input/root/file-input-root.js +55 -21
- package/dist/file-input/status.d.ts +24 -0
- package/dist/file-input/status.js +11 -0
- package/dist/filter-input/chip/filter-chip.d.ts +23 -0
- package/dist/filter-input/chip/filter-chip.js +10 -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/fields.d.ts +20 -0
- package/dist/format-date/fields.js +14 -0
- package/dist/format-date/options.d.ts +5 -5
- package/dist/format-date/options.js +10 -39
- package/dist/format-date/root/format-date-root.d.ts +53 -4
- package/dist/format-date/root/format-date-root.js +38 -50
- package/dist/graph/root/graph-root.d.ts +23 -5
- package/dist/graph/root/graph-root.js +17 -20
- 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 +76 -3
- package/dist/heatmap/root/heatmap-root.js +105 -20
- 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 +20 -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/root/kbd-root.d.ts +20 -3
- package/dist/kbd/root/kbd-root.js +23 -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 +25 -26
- 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 +31 -24
- package/dist/list/selection.d.ts +17 -0
- package/dist/list/selection.js +16 -0
- package/dist/listbox/root/listbox-root.d.ts +125 -26
- package/dist/listbox/root/listbox-root.js +156 -166
- 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/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 +29 -50
- package/dist/menu/item/menu-item.js +4 -4
- package/dist/menu/root/menu-root.d.ts +5 -2
- package/dist/meter/root/meter-root.d.ts +42 -0
- package/dist/meter/root/meter-root.js +33 -7
- 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 +48 -3
- package/dist/notifications/root/notifications-root.js +36 -6
- 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 +17 -6
- package/dist/object-inspector/root/object-inspector-root.js +31 -20
- 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 +6 -0
- package/dist/pagination/size/pagination-size.js +5 -3
- package/dist/pin-input/code.d.ts +51 -1
- package/dist/pin-input/code.js +37 -0
- package/dist/pin-input/root/pin-input-root.d.ts +98 -121
- package/dist/pin-input/root/pin-input-root.js +151 -156
- 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 +31 -9
- package/dist/qr-code/root/qr-code-root.js +29 -17
- 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/measures.d.ts +22 -0
- package/dist/scatter-chart/measures.js +11 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +26 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +21 -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 +115 -11
- package/dist/select/root/select-root.js +104 -20
- 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/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 +27 -2
- package/dist/speed-dial/item/speed-dial-item.js +43 -5
- 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 +86 -1
- package/dist/speed-dial/root/speed-dial-root.js +123 -6
- package/dist/splitter/root/splitter-root.d.ts +9 -2
- package/dist/splitter/root/splitter-root.js +18 -3
- 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/cell/table-cell.d.ts +8 -1
- package/dist/table/cell/table-cell.js +6 -2
- package/dist/table/column/table-column.d.ts +6 -0
- package/dist/table/column/table-column.js +5 -1
- 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 +93 -29
- package/dist/table/row/table-row.d.ts +36 -0
- package/dist/table/row/table-row.js +52 -2
- 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 +23 -20
- 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 +12 -14
- package/dist/time-picker/root/time-picker-root.js +18 -23
- package/dist/toast/item/toast-item.d.ts +9 -6
- package/dist/toast/item/toast-item.js +1 -1
- package/dist/toast/root/toast-root.d.ts +40 -4
- package/dist/toast/root/toast-root.js +68 -16
- 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 -43
- package/dist/toggle/root/toggle-root.js +2 -4
- package/dist/toolbar/root/toolbar-root.d.ts +52 -5
- package/dist/toolbar/root/toolbar-root.js +88 -13
- package/dist/tooltip/root/tooltip-root.d.ts +7 -1
- package/dist/tooltip/root/tooltip-root.js +10 -2
- 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 +16 -1
- package/dist/video/root/video-root.js +15 -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 +53 -41
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +4934 -954
- package/types/svelte.d.ts +2 -0
- package/types/vue.d.ts +946 -253
- 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
- package/dist/tooltip/focus-target.d.ts +0 -6
- package/dist/tooltip/focus-target.js +0 -9
|
@@ -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, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, requestChange, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, hostWords, requestChange, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { html } from 'lit/static-html.js';
|
|
@@ -89,6 +89,7 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
89
89
|
renderSelect() {
|
|
90
90
|
const select = this.tag('select');
|
|
91
91
|
const option = this.tag('option');
|
|
92
|
+
const named = this.isConnected ? hostWords(this) : '';
|
|
92
93
|
return html `<${select}
|
|
93
94
|
part="control"
|
|
94
95
|
exportparts="feedback: control-feedback, hint: control-hint, indicator: control-indicator,
|
|
@@ -97,9 +98,10 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
97
98
|
listbox-filter-mark: control-listbox-filter-mark, listbox-hint: control-listbox-hint,
|
|
98
99
|
listbox-items: control-listbox-items, listbox-label: control-listbox-label,
|
|
99
100
|
listbox-live: control-listbox-live, listbox-loading: control-listbox-loading, listbox-search: control-listbox-search,
|
|
100
|
-
listbox-search-field: control-listbox-search-field, surface: control-surface,
|
|
101
|
+
listbox-search-field: control-listbox-search-field, live: control-live, surface: control-surface,
|
|
101
102
|
trigger: control-trigger, value: control-value"
|
|
102
|
-
label=${this.label}
|
|
103
|
+
label=${named ? '' : this.label}
|
|
104
|
+
aria-label=${named || nothing}
|
|
103
105
|
?disabled=${this.isDisabled}
|
|
104
106
|
.value=${String(this.current)}
|
|
105
107
|
@helix-before-change=${this.handleChange}
|
package/dist/pin-input/code.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type PickerVerdict } from '@fusion.dev/helix-core';
|
|
2
|
+
/** What a box accepts, which decides the keyboard a phone offers. */
|
|
3
|
+
export type PinType = 'alphanumeric' | 'numeric' | 'text';
|
|
4
|
+
/** How typed letters are cased: as typed, or turned upper or lower case. */
|
|
5
|
+
export type PinCase = 'lower' | 'preserve' | 'upper';
|
|
2
6
|
/**
|
|
3
7
|
* Typed or pasted text as the code's characters: trimmed, with what `type`
|
|
4
8
|
* refuses dropped, and its letters cased as `letterCase` asks. Web Awesome's
|
|
@@ -8,3 +12,49 @@ import type { PinCase, PinType } from './root/pin-input-root.js';
|
|
|
8
12
|
* `text` keeps everything.
|
|
9
13
|
*/
|
|
10
14
|
export declare const cleanCode: (text: string, type: PinType, letterCase?: PinCase) => string;
|
|
15
|
+
/** A code after an edit, and the box the caret is in after it. */
|
|
16
|
+
export interface CodeEdit {
|
|
17
|
+
/** The box the caret is in, from 0, never past the last box. */
|
|
18
|
+
caret: number;
|
|
19
|
+
/** The code's characters, as many as there are boxes at most. */
|
|
20
|
+
code: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* What the one field holds after the platform edited it, as a code: `raw` is
|
|
24
|
+
* the field's text with the caret at `caret`, cleaned and cut at `count`, and
|
|
25
|
+
* the caret is moved past only the characters the code kept before it.
|
|
26
|
+
*/
|
|
27
|
+
export declare const readTyped: (raw: string, caret: number, type: PinType, letterCase: PinCase, count: number) => CodeEdit;
|
|
28
|
+
/**
|
|
29
|
+
* A run of characters written over `code` from box `at` onward, which is what a
|
|
30
|
+
* paste does: the boxes it reaches take its characters and the rest keep
|
|
31
|
+
* theirs, and anything past the last box is dropped.
|
|
32
|
+
*
|
|
33
|
+
* **A code has no holes in it**, so the run starts no later than the end of
|
|
34
|
+
* the code: a whole code pasted into an empty field fills from the first box
|
|
35
|
+
* wherever the caret was, and two characters pasted into box three of a field
|
|
36
|
+
* holding two fill from box three.
|
|
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'
|
|
@@ -11,3 +12,39 @@ export const cleanCode = (text, type, letterCase = 'preserve') => {
|
|
|
11
12
|
? kept.toLowerCase()
|
|
12
13
|
: kept;
|
|
13
14
|
};
|
|
15
|
+
export const readTyped = (raw, caret, type, letterCase, count) => ({
|
|
16
|
+
caret: Math.min(cleanCode(raw.slice(0, caret), type, letterCase).length, count - 1),
|
|
17
|
+
code: cleanCode(raw, type, letterCase).slice(0, count),
|
|
18
|
+
});
|
|
19
|
+
export const overwriteCode = (code, at, text, count) => {
|
|
20
|
+
const start = Math.min(at, code.length);
|
|
21
|
+
const characters = [...code.slice(0, count)];
|
|
22
|
+
for (let offset = 0; offset < text.length && start + offset < count; offset += 1) {
|
|
23
|
+
characters[start + offset] = text[offset];
|
|
24
|
+
}
|
|
25
|
+
return { caret: Math.min(count - 1, start + text.length), code: characters.join('') };
|
|
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
|
+
};
|
|
@@ -1,53 +1,56 @@
|
|
|
1
1
|
import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
-
|
|
4
|
-
export type
|
|
5
|
-
/** How typed letters are cased: as typed, or turned upper or lower case. */
|
|
6
|
-
export type PinCase = 'lower' | 'preserve' | 'upper';
|
|
3
|
+
import { type PinCase, type PinType } from '../code.js';
|
|
4
|
+
export type { PinCase, PinType } from '../code.js';
|
|
7
5
|
declare const HelixHeadlessPinInput_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
8
6
|
/**
|
|
9
7
|
* @summary A field for a short code, with one box for each character.
|
|
10
8
|
*
|
|
11
9
|
* @description
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* One real `<input>` holds the code, and the boxes are drawn from it, as Web
|
|
11
|
+
* Awesome's OTP input does. A screen reader meets one field, named by the
|
|
12
|
+
* label, and the code never sits in a row of separate fields. The boxes are
|
|
13
|
+
* hidden from it.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* arrives in cell three fills from cell three.
|
|
15
|
+
* The caret is drawn in the box it is in, and the box is marked with
|
|
16
|
+
* `cell-active` while the field has focus. A filled box selects its character,
|
|
17
|
+
* so typing replaces it and moves on.
|
|
19
18
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* Input longer than one character is treated as a paste. This covers pasting,
|
|
20
|
+
* a browser autofilling an SMS code, and a password manager. A six-character
|
|
21
|
+
* code pasted into an empty field fills from the first box.
|
|
23
22
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* The code is one value to a form. The field is in a shadow root and submits
|
|
24
|
+
* nothing. The host is form-associated and submits the code, which also
|
|
25
|
+
* carries validity and responds to a form reset. The field carries
|
|
26
|
+
* `autocomplete="one-time-code"`, which lets a phone offer the code from a
|
|
27
|
+
* message.
|
|
26
28
|
*
|
|
27
29
|
* `autosubmit` submits the form once the last box is filled, through the form's
|
|
28
30
|
* default button where there is one. `format` draws separators between the
|
|
29
|
-
* boxes, such as the dash in `###-###`, as text a screen reader skips.
|
|
30
|
-
*
|
|
31
|
-
*
|
|
31
|
+
* boxes, such as the dash in `###-###`, as text a screen reader skips. `mask`
|
|
32
|
+
* makes the field a password field and draws `mask-character` in each filled
|
|
33
|
+
* box, so the code is never drawn as text.
|
|
32
34
|
*
|
|
33
|
-
* The row of
|
|
35
|
+
* The row of boxes always runs left to right, with `dir="ltr"`, including in
|
|
34
36
|
* Arabic and Hebrew. The first box is the leftmost, a paste fills to the right,
|
|
35
37
|
* and the right arrow moves to the next box. The label, hint, and feedback
|
|
36
38
|
* follow the page's direction.
|
|
37
39
|
*
|
|
38
|
-
* **Keyboard.**
|
|
40
|
+
* **Keyboard.** The field is one tab stop.
|
|
39
41
|
*
|
|
40
42
|
* | Key | What it does |
|
|
41
43
|
* |---|---|
|
|
42
44
|
* | A character | Fills the box and moves to the next one. A longer run is read as a paste. |
|
|
43
45
|
* | Left, Right | Moves to the box before or after. |
|
|
44
46
|
* | Home, End | Moves to the first box, or to the box after the last character. |
|
|
45
|
-
* | Backspace |
|
|
47
|
+
* | Backspace | Removes the character in the box, or in an empty box the one before it, and moves there. |
|
|
46
48
|
* | Delete | Removes the character in the box and pulls the rest of the code back. |
|
|
47
49
|
* | Enter | Submits the form. |
|
|
48
50
|
*
|
|
49
|
-
* The
|
|
50
|
-
*
|
|
51
|
+
* The field is a text field, or a password field under `mask`, named by the
|
|
52
|
+
* label and described by the hint and the message, with `aria-invalid` while
|
|
53
|
+
* a message shows and `aria-required` under `required`. `helix-complete` is a
|
|
51
54
|
* `HelixCompleteEvent` sent once the last box is filled.
|
|
52
55
|
*
|
|
53
56
|
* @since 0.1.0
|
|
@@ -65,11 +68,16 @@ declare const HelixHeadlessPinInput_base: (new (...args: any[]) => import("@fusi
|
|
|
65
68
|
* @event {HelixCompleteEvent} helix-complete - The last box was filled.
|
|
66
69
|
* @event {Event} input - The code changed.
|
|
67
70
|
*
|
|
71
|
+
* @csspart caret - The caret, drawn in the empty box it is in while the field has focus.
|
|
68
72
|
* @csspart cell - One box.
|
|
73
|
+
* @csspart cell-active - The box the caret is in, while the field has focus. Set together with `cell`.
|
|
74
|
+
* @csspart cell-filled - A box that holds a character. Set together with `cell`.
|
|
75
|
+
* @csspart control - The one field that holds the code, out of sight: the boxes are drawn from it.
|
|
69
76
|
* @csspart feedback - The message that says what is wrong with the code.
|
|
70
77
|
* @csspart field - The row of boxes, ordered left to right in every language.
|
|
71
78
|
* @csspart hint - The help under the boxes, shown while there is no feedback.
|
|
72
79
|
* @csspart label - The label above the boxes.
|
|
80
|
+
* @csspart placeholder - The `placeholder` text in an empty box.
|
|
73
81
|
* @csspart separator - The text `format` draws between two boxes.
|
|
74
82
|
*
|
|
75
83
|
* @cssstate complete - Every box holds a character.
|
|
@@ -77,17 +85,12 @@ declare const HelixHeadlessPinInput_base: (new (...args: any[]) => import("@fusi
|
|
|
77
85
|
*/
|
|
78
86
|
export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
|
|
79
87
|
protected readonly aria: AriaForwardController;
|
|
80
|
-
/**
|
|
81
|
-
protected get namedControl(): HTMLElement | null;
|
|
82
|
-
/** Typed or dragged, so every edit is announced. See `announcesInput`. */
|
|
88
|
+
/** Typed or pasted, so every edit is announced. See `announcesInput`. */
|
|
83
89
|
protected readonly announcesInput = true;
|
|
84
90
|
/**
|
|
85
|
-
* The autofill hint for the browser
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* that lets a phone offer the code out of a message. Later cells stay `off`
|
|
89
|
-
* for the reason in the class comment above, that six cells each offering
|
|
90
|
-
* the same code is one offer made six times.
|
|
91
|
+
* The autofill hint for the browser. `one-time-code` is why this defaults to
|
|
92
|
+
* anything at all: it is the token that lets a phone offer the code out of a
|
|
93
|
+
* message.
|
|
91
94
|
*/
|
|
92
95
|
autocomplete: string;
|
|
93
96
|
/**
|
|
@@ -103,7 +106,11 @@ export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
|
|
|
103
106
|
*/
|
|
104
107
|
case: PinCase;
|
|
105
108
|
/**
|
|
106
|
-
*
|
|
109
|
+
* The name each box once had, with `{index}` and `{length}` filled in.
|
|
110
|
+
*
|
|
111
|
+
* @deprecated No longer read. The boxes are drawn from one field, which is
|
|
112
|
+
* named by `label`, and a screen reader does not meet the boxes. Removed in
|
|
113
|
+
* the next breaking release.
|
|
107
114
|
*/
|
|
108
115
|
cellLabel: string;
|
|
109
116
|
/**
|
|
@@ -117,23 +124,23 @@ export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
|
|
|
117
124
|
*/
|
|
118
125
|
length: number;
|
|
119
126
|
/**
|
|
120
|
-
* Whether the characters are hidden, the way a password is.
|
|
127
|
+
* Whether the characters are hidden, the way a password is. The field is a
|
|
128
|
+
* password field, and each filled box draws `mask-character`.
|
|
121
129
|
*/
|
|
122
130
|
mask: boolean;
|
|
123
131
|
/**
|
|
124
|
-
* What
|
|
125
|
-
*
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* Empty by default, because a row of boxes already reads as a row of boxes.
|
|
132
|
+
* What a filled box draws under `mask`, in place of its character, as Web
|
|
133
|
+
* Awesome's `--mask-char`.
|
|
134
|
+
*/
|
|
135
|
+
maskCharacter: string;
|
|
136
|
+
/**
|
|
137
|
+
* What an empty box shows, usually a single dot. It is not shown in the box
|
|
138
|
+
* the caret is in. Empty by default, because a row of boxes already reads as
|
|
139
|
+
* a row of boxes.
|
|
133
140
|
*/
|
|
134
141
|
placeholder: string;
|
|
135
142
|
/**
|
|
136
|
-
* Whether the
|
|
143
|
+
* Whether the field blocks input. A read-only code still submits its value.
|
|
137
144
|
*/
|
|
138
145
|
readOnly: boolean;
|
|
139
146
|
/**
|
|
@@ -159,51 +166,60 @@ export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
|
|
|
159
166
|
*
|
|
160
167
|
* **Not reflected**: nothing selects on it, so reflecting only writes
|
|
161
168
|
* `type="numeric"` onto every `<helix-headless-pin-input>` ever rendered, an
|
|
162
|
-
* attribute no consumer's markup had. The
|
|
163
|
-
* "reflect only what CSS selects on". The real inputs take it as a binding,
|
|
169
|
+
* attribute no consumer's markup had. The field takes it as `inputmode`,
|
|
164
170
|
* which is what makes the keyboard follow.
|
|
165
171
|
*/
|
|
166
172
|
type: PinType;
|
|
167
173
|
/** Focus is delegated, so the host is never the focus target. */
|
|
168
174
|
static shadowRootOptions: ShadowRootInit;
|
|
175
|
+
/**
|
|
176
|
+
* The box the caret is in while the field has focus, and -1 while it does
|
|
177
|
+
* not or while the field is read-only, where there is nothing to type into.
|
|
178
|
+
*/
|
|
179
|
+
private active;
|
|
180
|
+
/** The box a press asked for, taken when the focus it starts arrives. */
|
|
181
|
+
private pressedAt;
|
|
169
182
|
/** How many boxes there are, clamped once so every reader agrees. */
|
|
170
183
|
private get count();
|
|
171
|
-
private get
|
|
172
|
-
/** The
|
|
173
|
-
private get
|
|
174
|
-
/**
|
|
175
|
-
private
|
|
184
|
+
private get control();
|
|
185
|
+
/** The furthest box the caret can be in: after the code, and the last box at most. */
|
|
186
|
+
private get end();
|
|
187
|
+
/** The box the caret is drawn in, kept within the code a script may have shortened. */
|
|
188
|
+
private get caretBox();
|
|
176
189
|
/**
|
|
177
|
-
*
|
|
190
|
+
* Takes a code the field was edited to, and moves the caret to `caret`.
|
|
178
191
|
*
|
|
179
192
|
* The single path for typing, pasting and autofill alike, because they are
|
|
180
|
-
* the same act at different lengths
|
|
181
|
-
*
|
|
182
|
-
* end.
|
|
193
|
+
* the same act at different lengths. Through `requestValue`, so a consumer
|
|
194
|
+
* who owns the code can refuse it, and a refused edit puts the field back.
|
|
183
195
|
*/
|
|
184
|
-
private
|
|
196
|
+
private take;
|
|
185
197
|
/**
|
|
186
|
-
* Puts the
|
|
198
|
+
* Puts the field's selection on the box the caret is in: the character
|
|
199
|
+
* there, so typing replaces it, or the empty place after the code.
|
|
187
200
|
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* keystroke leaves the box holding a character the element rejected. This is
|
|
191
|
-
* the same put-back `Input` does with `restoreValue`, once per box.
|
|
201
|
+
* Left alone while the reader holds a wider selection of their own, such as
|
|
202
|
+
* everything after Control+A, unless `force` says the caret moved.
|
|
192
203
|
*/
|
|
193
|
-
private
|
|
204
|
+
private placeCaret;
|
|
194
205
|
private readonly handleInput;
|
|
206
|
+
/**
|
|
207
|
+
* A paste writes over the boxes from the caret on, rather than into the
|
|
208
|
+
* field's text, so a code pasted into box three of a full code replaces the
|
|
209
|
+
* characters there instead of pushing them along.
|
|
210
|
+
*/
|
|
195
211
|
private readonly handlePaste;
|
|
196
212
|
/**
|
|
197
|
-
* The keys that move between boxes
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* is what makes a code correctable without the reader hunting for the box
|
|
201
|
-
* they meant. In a full box it does what it always does and is left alone.
|
|
213
|
+
* The keys that move between boxes. Backspace and Delete are the field's
|
|
214
|
+
* own: the selection on a filled box makes them remove its character, and
|
|
215
|
+
* the empty place after the code makes Backspace remove the one before.
|
|
202
216
|
*
|
|
203
217
|
* Home goes to the first box and End to the end of the code, the box after
|
|
204
218
|
* its last character, which is where the caret goes in a single text field.
|
|
205
219
|
*/
|
|
206
220
|
private readonly handleKeydown;
|
|
221
|
+
/** A press on a box puts the caret there, or after the code where the box is past it. */
|
|
222
|
+
private readonly handlePress;
|
|
207
223
|
/**
|
|
208
224
|
* The code as it stood when focus arrived, so a visit that changed nothing
|
|
209
225
|
* says nothing.
|
|
@@ -220,72 +236,37 @@ export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
|
|
|
220
236
|
* | types a character and deletes it | silent | silent | silent |
|
|
221
237
|
*
|
|
222
238
|
* One row differed and it is the one that matters: a consumer who assigns
|
|
223
|
-
* `value` and then has a reader tab through the
|
|
239
|
+
* `value` and then has a reader tab through the field was told the reader had
|
|
224
240
|
* entered a code. `change` on a field means "the reader had a go at this",
|
|
225
241
|
* `MixinField` treats it as exactly that, and announcing a value the consumer
|
|
226
242
|
* set themselves is a false positive rather than the safe half of a trade.
|
|
227
243
|
*
|
|
228
|
-
* **The narrower divergence that is left** is a script assigning while the row
|
|
229
|
-
* is focused, where the platform stays silent because no user edit happened
|
|
230
|
-
* and this commits on the way out. Closing it needs a dirty flag set from real
|
|
231
|
-
* cell input rather than a baseline, which is more machinery than the case has
|
|
232
|
-
* earned: a consumer writing to a field the reader is inside is already in a
|
|
233
|
-
* fight with them.
|
|
234
|
-
*
|
|
235
244
|
* Seeded in `firstUpdated`, a code in the markup being committed by whoever
|
|
236
|
-
* wrote it, and re-taken on every arrival
|
|
245
|
+
* wrote it, and re-taken on every arrival.
|
|
237
246
|
*/
|
|
238
247
|
private committed;
|
|
239
|
-
/**
|
|
248
|
+
/** Takes the baseline, and puts the caret in the box pressed or after the code. */
|
|
240
249
|
private readonly handleFocus;
|
|
241
250
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* **The arrival is a transition, not a `relatedTarget` reading**, which is
|
|
245
|
-
* what the exit still does. `relatedTarget` does not work on the way in for
|
|
246
|
-
* two reasons and the second decides it. Every character moves focus to the
|
|
247
|
-
* next box, so an unguarded `focusin` re-baselines on each keystroke and the
|
|
248
|
-
* row can never report anything: measured, the three commit specs went silent
|
|
249
|
-
* at once. And `focusin` carries `relatedTarget` in a browser and not in
|
|
250
|
-
* happy-dom, so a guard written on it holds in production and not in the
|
|
251
|
-
* specs, which is the worse half. This flag needs neither: entering is
|
|
252
|
-
* `focusin` while it is `false`, and nothing else is.
|
|
253
|
-
*/
|
|
254
|
-
private within;
|
|
255
|
-
/**
|
|
256
|
-
* Takes the baseline when focus arrives from outside the row.
|
|
257
|
-
*
|
|
258
|
-
* The value at arrival is what the platform compares against, and the table
|
|
259
|
-
* on `committed` is why.
|
|
260
|
-
*/
|
|
261
|
-
private readonly handleFocusIn;
|
|
262
|
-
/**
|
|
263
|
-
* Commits when focus leaves the row.
|
|
251
|
+
* Commits when focus leaves the field.
|
|
264
252
|
*
|
|
265
253
|
* `change` is one of the two events `MixinField` reads as "the reader has had
|
|
266
254
|
* a go at this", so without this a code that was never completed is never
|
|
267
255
|
* `touched` and its own `tooShort` message cannot show: two boxes of four
|
|
268
|
-
* filled and tabbed away from is answered with nothing at all.
|
|
269
|
-
* this for free by relaying its control's own `change`; here the cells each
|
|
270
|
-
* fire one, none of them means the code is entered, and neither does any
|
|
271
|
-
* single one of them mean the reader has left.
|
|
272
|
-
*
|
|
273
|
-
* **Focus leaving the row, and not a cell.** Every character moves focus to
|
|
274
|
-
* the next box, so a per-cell blur would commit on every keystroke, which is
|
|
275
|
-
* the fault this exists to fix pointed the other way.
|
|
256
|
+
* filled and tabbed away from is answered with nothing at all.
|
|
276
257
|
*/
|
|
277
|
-
private readonly
|
|
258
|
+
private readonly handleBlur;
|
|
278
259
|
/**
|
|
279
260
|
* Announces the code as entered, from whichever moment reached it first.
|
|
280
261
|
*
|
|
281
262
|
* **One writer, because the fact has two moments and only one meaning.** A
|
|
282
|
-
* filled code and a
|
|
263
|
+
* filled code and a field being left are both "the reader is done with this".
|
|
283
264
|
* Dispatching from either site directly is how a moment gets added that fires
|
|
284
265
|
* without baselining.
|
|
285
266
|
*
|
|
286
267
|
* Silent when nothing moved since the baseline, which is what makes it safe
|
|
287
268
|
* to call from both: completing a code that is already the committed one, or
|
|
288
|
-
* leaving a
|
|
269
|
+
* leaving a field nobody edited, says nothing.
|
|
289
270
|
*
|
|
290
271
|
* `composed: false`, like the native event this stands in for. It is
|
|
291
272
|
* dispatched on the host, so a consumer hears it.
|
|
@@ -307,20 +288,15 @@ export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
|
|
|
307
288
|
* | typed `1234` | valid | valid |
|
|
308
289
|
*
|
|
309
290
|
* So `required` decides whether *nothing* is acceptable, and the length rule
|
|
310
|
-
* applies to anything that is not nothing.
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
* being told off before they have had a go.
|
|
315
|
-
*
|
|
316
|
-
* `execCommand('insertText')` is not enough to measure this: `tooShort`
|
|
317
|
-
* applies only to a value the user edited, and the first run of the probe
|
|
318
|
-
* reported every case valid because nothing had set that flag.
|
|
291
|
+
* applies to anything that is not nothing. Two of four characters is not an
|
|
292
|
+
* optional code omitted, it is a code got wrong, and submitting it would send
|
|
293
|
+
* a fragment. The gate on the message is `touched` rather than `required`,
|
|
294
|
+
* which is what stops a reader being told off before they have had a go.
|
|
319
295
|
*/
|
|
320
296
|
private sync;
|
|
321
297
|
/** Puts the caret in the first empty box. */
|
|
322
298
|
focus(options?: FocusOptions): void;
|
|
323
|
-
/** Empties every box and
|
|
299
|
+
/** Empties every box and puts the caret in the first. */
|
|
324
300
|
clear(): void;
|
|
325
301
|
protected firstUpdated(changed: PropertyValues): void;
|
|
326
302
|
protected updated(changed: PropertyValues): void;
|
|
@@ -333,6 +309,8 @@ export declare class HelixHeadlessPinInput extends HelixHeadlessPinInput_base {
|
|
|
333
309
|
private readonly handleKeypress;
|
|
334
310
|
/** @internal A single line of text counts against implicit submission. */
|
|
335
311
|
protected get blocksImplicitSubmission(): boolean;
|
|
312
|
+
/** What one box draws: its character, the mask, the caret, or the placeholder. */
|
|
313
|
+
private renderBox;
|
|
336
314
|
protected render(): TemplateResult;
|
|
337
315
|
}
|
|
338
316
|
declare global {
|
|
@@ -340,4 +318,3 @@ declare global {
|
|
|
340
318
|
'helix-headless-pin-input': HelixHeadlessPinInput;
|
|
341
319
|
}
|
|
342
320
|
}
|
|
343
|
-
export {};
|