@fusion.dev/helix-headless 0.144.0 → 0.146.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 +15195 -4240
- package/dist/accordion/item/accordion-item.d.ts +62 -12
- package/dist/accordion/item/accordion-item.js +41 -10
- package/dist/accordion/root/accordion-root.d.ts +14 -5
- package/dist/accordion/root/accordion-root.js +7 -1
- package/dist/announcement/root/announcement-root.d.ts +24 -3
- package/dist/announcement/root/announcement-root.js +39 -2
- package/dist/app-header/root/app-header-root.d.ts +12 -0
- package/dist/app-header/root/app-header-root.js +13 -1
- package/dist/app-header/sectioning.d.ts +9 -0
- package/dist/app-header/sectioning.js +27 -0
- package/dist/avatar/group/avatar-group.d.ts +20 -14
- package/dist/avatar/group/avatar-group.js +17 -19
- package/dist/badge/root/badge-root.d.ts +3 -1
- package/dist/badge/root/badge-root.js +2 -2
- package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
- package/dist/bar-chart/root/bar-chart-root.js +52 -15
- package/dist/bar-chart/stack.d.ts +15 -0
- package/dist/bar-chart/stack.js +19 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +57 -1
- package/dist/breadcrumbs/root/breadcrumbs-root.js +73 -3
- package/dist/button/root/button-root.d.ts +26 -0
- package/dist/button/root/button-root.js +38 -18
- package/dist/button-group/root/button-group-root.d.ts +2 -1
- package/dist/button-group/root/button-group-root.js +5 -1
- package/dist/canvas/node/canvas-node.d.ts +4 -3
- package/dist/canvas/node/canvas-node.js +3 -2
- package/dist/canvas/root/canvas-root.d.ts +38 -3
- package/dist/canvas/root/canvas-root.js +123 -42
- package/dist/card/root/card-root.d.ts +24 -3
- package/dist/card/root/card-root.js +20 -8
- package/dist/carousel/root/carousel-root.d.ts +133 -4
- package/dist/carousel/root/carousel-root.js +174 -24
- package/dist/carousel/stops.d.ts +20 -0
- package/dist/carousel/stops.js +30 -0
- package/dist/chat/composer/chat-composer.d.ts +38 -6
- package/dist/chat/composer/chat-composer.js +42 -9
- package/dist/chat/message/chat-message.d.ts +32 -1
- package/dist/chat/message/chat-message.js +27 -10
- package/dist/chat/naming.d.ts +26 -0
- package/dist/chat/naming.js +14 -0
- package/dist/chat/root/chat-root.d.ts +58 -0
- package/dist/chat/root/chat-root.js +43 -3
- package/dist/checkbox/root/checkbox-root.d.ts +20 -0
- package/dist/checkbox/root/checkbox-root.js +14 -1
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
- package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
- package/dist/checkbox-group/select-all.d.ts +27 -0
- package/dist/checkbox-group/select-all.js +12 -0
- package/dist/code-block/highlight.d.ts +15 -0
- package/dist/code-block/highlight.js +4 -0
- package/dist/code-block/root/code-block-root.d.ts +57 -2
- package/dist/code-block/root/code-block-root.js +63 -8
- package/dist/color-input/root/color-input-root.d.ts +3 -0
- package/dist/color-input/root/color-input-root.js +6 -3
- package/dist/color-picker/root/color-picker-root.d.ts +33 -4
- package/dist/color-picker/root/color-picker-root.js +80 -21
- package/dist/color-picker/swatches.d.ts +12 -0
- package/dist/color-picker/swatches.js +26 -0
- package/dist/combobox/root/combobox-root.d.ts +43 -0
- package/dist/combobox/root/combobox-root.js +79 -15
- package/dist/command/root/command-root.d.ts +16 -1
- package/dist/command/root/command-root.js +22 -4
- package/dist/copy-button/root/copy-button-root.d.ts +26 -1
- package/dist/copy-button/root/copy-button-root.js +12 -5
- package/dist/data-table/index.d.ts +1 -1
- package/dist/data-table/index.js +1 -1
- package/dist/data-table/keys.d.ts +24 -0
- package/dist/data-table/keys.js +24 -0
- package/dist/data-table/root/data-table-root.d.ts +170 -13
- package/dist/data-table/root/data-table-root.js +294 -52
- package/dist/data-table/tree.d.ts +55 -0
- package/dist/data-table/tree.js +54 -0
- package/dist/date-input/root/date-input-root.d.ts +3 -1
- package/dist/date-input/root/date-input-root.js +18 -7
- package/dist/date-picker/root/date-picker-root.js +12 -6
- package/dist/description-list/item/description-list-item.d.ts +17 -2
- package/dist/description-list/item/description-list-item.js +15 -2
- package/dist/description-list/root/description-list-root.d.ts +27 -1
- package/dist/description-list/root/description-list-root.js +26 -1
- package/dist/dialog/description.js +15 -1
- package/dist/dialog/root/dialog-root.d.ts +8 -2
- package/dist/dialog/root/dialog-root.js +16 -1
- package/dist/divider/root/divider-root.d.ts +3 -0
- package/dist/divider/root/divider-root.js +2 -1
- package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
- package/dist/donut-chart/root/donut-chart-root.js +48 -1
- package/dist/drawer/reveal.d.ts +8 -0
- package/dist/drawer/reveal.js +1 -0
- package/dist/drawer/root/drawer-root.d.ts +59 -0
- package/dist/drawer/root/drawer-root.js +63 -4
- package/dist/drilldown/item/drilldown-item.d.ts +11 -6
- package/dist/drilldown/item/drilldown-item.js +8 -5
- package/dist/drilldown/root/drilldown-root.d.ts +29 -0
- package/dist/drilldown/root/drilldown-root.js +28 -5
- package/dist/element-events.generated.js +83 -12
- package/dist/empty/root/empty-root.d.ts +3 -1
- package/dist/empty/root/empty-root.js +3 -2
- package/dist/file-input/root/file-input-root.d.ts +69 -6
- package/dist/file-input/root/file-input-root.js +82 -19
- package/dist/file-input/screen.d.ts +2 -1
- package/dist/filter-input/menu/filter-menu.d.ts +5 -0
- package/dist/filter-input/menu/filter-menu.js +16 -4
- package/dist/filter-input/root/filter-input-root.d.ts +30 -6
- package/dist/filter-input/root/filter-input-root.js +1 -1
- package/dist/filter-input/suggest.d.ts +28 -3
- package/dist/filter-input/suggest.js +18 -8
- package/dist/format-date/root/format-date-root.d.ts +9 -16
- package/dist/format-date/root/format-date-root.js +10 -27
- package/dist/heatmap/root/heatmap-root.d.ts +24 -13
- package/dist/heatmap/root/heatmap-root.js +34 -12
- package/dist/icon/root/icon-root.d.ts +12 -1
- package/dist/icon/root/icon-root.js +21 -10
- package/dist/icon/settle.d.ts +7 -0
- package/dist/icon/settle.js +10 -0
- package/dist/icon-button/root/icon-button-root.d.ts +2 -0
- package/dist/image/root/image-root.d.ts +5 -1
- package/dist/image/root/image-root.js +10 -2
- package/dist/input/root/input-root.d.ts +13 -3
- package/dist/input/root/input-root.js +12 -3
- package/dist/kbd/root/kbd-root.d.ts +35 -1
- package/dist/kbd/root/kbd-root.js +23 -4
- package/dist/legend/root/legend-root.d.ts +55 -8
- package/dist/legend/root/legend-root.js +55 -13
- package/dist/lightbox/root/lightbox-root.d.ts +49 -6
- package/dist/lightbox/root/lightbox-root.js +86 -19
- package/dist/lightbox/zoom-controller.d.ts +59 -0
- package/dist/lightbox/zoom-controller.js +128 -0
- package/dist/lightbox/zoom.d.ts +22 -0
- package/dist/lightbox/zoom.js +16 -0
- package/dist/line-chart/root/line-chart-root.d.ts +22 -1
- package/dist/line-chart/root/line-chart-root.js +21 -1
- package/dist/list/item/list-item.d.ts +70 -1
- package/dist/list/item/list-item.js +77 -6
- package/dist/list/numbering.d.ts +14 -0
- package/dist/list/numbering.js +8 -0
- package/dist/list/root/list-root.d.ts +155 -9
- package/dist/list/root/list-root.js +246 -4
- package/dist/list/selection.d.ts +49 -0
- package/dist/list/selection.js +30 -0
- package/dist/listbox/root/listbox-root.d.ts +37 -1
- package/dist/listbox/root/listbox-root.js +49 -4
- package/dist/loader/busy.d.ts +10 -0
- package/dist/loader/busy.js +11 -0
- package/dist/loader/root/loader-root.d.ts +9 -2
- package/dist/loader/root/loader-root.js +23 -3
- package/dist/map/root/map-root.d.ts +6 -2
- package/dist/map/root/map-root.js +5 -2
- package/dist/megamenu/root/megamenu-root.d.ts +62 -0
- package/dist/megamenu/root/megamenu-root.js +90 -5
- package/dist/menu/index.d.ts +1 -0
- package/dist/menu/index.js +1 -0
- package/dist/menu/item/menu-item.d.ts +87 -11
- package/dist/menu/item/menu-item.js +78 -22
- package/dist/menu/root/menu-root.d.ts +39 -1
- package/dist/menu/root/menu-root.js +65 -8
- package/dist/menu/section/menu-section.d.ts +55 -0
- package/dist/menu/section/menu-section.js +60 -0
- package/dist/meter/root/meter-root.d.ts +20 -1
- package/dist/meter/root/meter-root.js +11 -15
- package/dist/navigation/root/navigation-root.d.ts +18 -2
- package/dist/navigation/root/navigation-root.js +29 -3
- package/dist/notifications/root/notifications-root.d.ts +25 -0
- package/dist/notifications/root/notifications-root.js +33 -5
- package/dist/number-input/root/number-input-root.d.ts +17 -8
- package/dist/number-input/root/number-input-root.js +2 -7
- package/dist/object-inspector/root/object-inspector-root.d.ts +161 -32
- package/dist/object-inspector/root/object-inspector-root.js +264 -123
- package/dist/object-inspector/rows.d.ts +75 -0
- package/dist/object-inspector/rows.js +119 -0
- package/dist/option/root/option-root.d.ts +5 -3
- package/dist/outline/levels.d.ts +31 -0
- package/dist/outline/levels.js +23 -0
- package/dist/outline/root/outline-root.d.ts +86 -3
- package/dist/outline/root/outline-root.js +95 -12
- package/dist/pagination/size/pagination-size.d.ts +12 -2
- package/dist/pagination/size/pagination-size.js +20 -5
- package/dist/pin-input/code.d.ts +10 -0
- package/dist/pin-input/code.js +13 -0
- package/dist/pin-input/root/pin-input-root.d.ts +25 -1
- package/dist/pin-input/root/pin-input-root.js +10 -11
- package/dist/popover/hide-outside.d.ts +14 -0
- package/dist/popover/hide-outside.js +41 -0
- package/dist/popover/root/popover-root.d.ts +57 -7
- package/dist/popover/root/popover-root.js +58 -3
- package/dist/progress/root/progress-root.d.ts +20 -0
- package/dist/progress/root/progress-root.js +15 -15
- package/dist/qr-code/export.d.ts +26 -1
- package/dist/qr-code/export.js +14 -0
- package/dist/qr-code/root/qr-code-root.d.ts +19 -5
- package/dist/qr-code/root/qr-code-root.js +58 -9
- package/dist/quote/marks.d.ts +8 -0
- package/dist/quote/marks.js +5 -0
- package/dist/quote/root/quote-root.d.ts +14 -2
- package/dist/quote/root/quote-root.js +23 -1
- package/dist/radio/group/radio-group.d.ts +4 -10
- package/dist/radio/group/radio-group.js +5 -10
- package/dist/radio/root/radio-root.d.ts +6 -2
- package/dist/radio/root/radio-root.js +6 -1
- package/dist/rating/root/rating-root.d.ts +10 -5
- package/dist/rating/root/rating-root.js +32 -8
- package/dist/rating/steps.d.ts +7 -0
- package/dist/rating/steps.js +9 -0
- package/dist/scatter-chart/fit.d.ts +15 -0
- package/dist/scatter-chart/fit.js +35 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
- package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
- package/dist/scroll-area/root/scroll-area-root.d.ts +84 -0
- package/dist/scroll-area/root/scroll-area-root.js +106 -7
- package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
- package/dist/scroll-area/scrollbar-controller.js +172 -0
- package/dist/scroll-area/scrollbar.d.ts +92 -0
- package/dist/scroll-area/scrollbar.js +33 -0
- package/dist/select/root/select-root.d.ts +15 -0
- package/dist/select/root/select-root.js +18 -6
- package/dist/skeleton/root/skeleton-root.d.ts +3 -0
- package/dist/skeleton/root/skeleton-root.js +4 -2
- package/dist/skip-link/root/skip-link-root.js +2 -2
- package/dist/slider/root/slider-root.d.ts +41 -4
- package/dist/slider/root/slider-root.js +23 -3
- package/dist/sparkline/readings.d.ts +18 -0
- package/dist/sparkline/readings.js +19 -0
- package/dist/sparkline/root/sparkline-root.d.ts +78 -7
- package/dist/sparkline/root/sparkline-root.js +118 -23
- package/dist/speed-dial/root/speed-dial-root.js +2 -2
- package/dist/splitter/root/splitter-root.d.ts +20 -12
- package/dist/splitter/root/splitter-root.js +226 -203
- package/dist/splitter/snap.d.ts +9 -0
- package/dist/splitter/snap.js +12 -0
- package/dist/stat/root/stat-root.d.ts +14 -5
- package/dist/stat/root/stat-root.js +21 -5
- package/dist/steps/reach.d.ts +20 -0
- package/dist/steps/reach.js +15 -0
- package/dist/steps/root/steps-root.d.ts +76 -0
- package/dist/steps/root/steps-root.js +93 -1
- package/dist/steps/step/step.d.ts +45 -2
- package/dist/steps/step/step.js +33 -6
- package/dist/switch/root/switch-root.d.ts +10 -0
- package/dist/table/column/table-column.d.ts +11 -10
- package/dist/table/column/table-column.js +8 -19
- package/dist/table/root/table-root.d.ts +126 -4
- package/dist/table/root/table-root.js +156 -6
- package/dist/table/row/table-row.d.ts +47 -1
- package/dist/table/row/table-row.js +39 -2
- package/dist/tabs/panel/tab-panel.d.ts +22 -5
- package/dist/tabs/panel/tab-panel.js +34 -6
- package/dist/tabs/root/tabs-root.d.ts +37 -1
- package/dist/tabs/root/tabs-root.js +22 -4
- package/dist/tabs/tab/tab.d.ts +41 -4
- package/dist/tabs/tab/tab.js +49 -3
- package/dist/tag/group/tag-group.d.ts +31 -4
- package/dist/tag/group/tag-group.js +46 -7
- package/dist/tag/root/tag-root.js +9 -2
- package/dist/textarea/root/textarea-root.d.ts +28 -1
- package/dist/textarea/root/textarea-root.js +40 -1
- package/dist/time-input/root/time-input-root.d.ts +5 -1
- package/dist/time-input/root/time-input-root.js +16 -8
- package/dist/time-picker/root/time-picker-root.d.ts +18 -4
- package/dist/time-picker/root/time-picker-root.js +7 -10
- package/dist/time-picker/wheel-name.d.ts +9 -0
- package/dist/time-picker/wheel-name.js +15 -0
- package/dist/timeline/group/timeline-group.d.ts +46 -0
- package/dist/timeline/group/timeline-group.js +37 -0
- package/dist/timeline/index.d.ts +1 -0
- package/dist/timeline/index.js +1 -0
- package/dist/timeline/root/timeline-root.d.ts +10 -3
- package/dist/toast/item/toast-item.d.ts +24 -18
- package/dist/toast/item/toast-item.js +36 -40
- package/dist/toast/root/toast-root.d.ts +6 -0
- package/dist/toast/root/toast-root.js +16 -1
- package/dist/toggle/group/toggle-group.d.ts +24 -3
- package/dist/toggle/group/toggle-group.js +34 -5
- package/dist/toolbar/root/toolbar-root.d.ts +13 -0
- package/dist/toolbar/root/toolbar-root.js +15 -5
- package/dist/tooltip/root/tooltip-root.d.ts +13 -2
- package/dist/tooltip/root/tooltip-root.js +9 -1
- package/dist/tour/back.d.ts +10 -0
- package/dist/tour/back.js +8 -0
- package/dist/tour/root/tour-root.d.ts +30 -2
- package/dist/tour/root/tour-root.js +34 -8
- package/dist/tree/item/tree-item.d.ts +61 -4
- package/dist/tree/item/tree-item.js +92 -20
- package/dist/tree/root/tree-root.d.ts +58 -0
- package/dist/tree/root/tree-root.js +80 -16
- package/dist/tree/selection.d.ts +24 -0
- package/dist/tree/selection.js +13 -0
- package/dist/trend/root/trend-root.d.ts +43 -18
- package/dist/trend/root/trend-root.js +31 -6
- package/dist/video/media-events.d.ts +44 -0
- package/dist/video/media-events.js +35 -0
- package/dist/video/root/video-root.d.ts +117 -18
- package/dist/video/root/video-root.js +93 -47
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
- package/dist/video-playlist/order.d.ts +41 -0
- package/dist/video-playlist/order.js +34 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +77 -3
- package/dist/video-playlist/root/video-playlist-root.js +60 -16
- package/dist/virtual-list/controls.d.ts +4 -0
- package/dist/virtual-list/controls.js +30 -0
- package/dist/virtual-list/fill.d.ts +22 -0
- package/dist/virtual-list/fill.js +23 -0
- package/dist/virtual-list/keys.d.ts +15 -0
- package/dist/virtual-list/keys.js +24 -0
- package/dist/virtual-list/plan.d.ts +49 -0
- package/dist/virtual-list/plan.js +16 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +259 -26
- package/dist/virtual-list/root/virtual-list-root.js +333 -49
- package/lint.json +1 -1
- package/package.json +8 -8
- package/types/jsx.d.ts +8113 -1394
- package/types/svelte.d.ts +2 -0
- package/types/vue.d.ts +1678 -353
- package/dist/data-table/root/order.d.ts +0 -141
- package/dist/data-table/root/order.js +0 -76
- package/dist/listbox/range.d.ts +0 -17
- package/dist/listbox/range.js +0 -5
- package/dist/tag/selection.d.ts +0 -10
- package/dist/tag/selection.js +0 -12
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export const branchy = (value) => value !== null && typeof value === 'object';
|
|
2
|
+
export const entries = (value) => Array.isArray(value) ? value.map((item, at) => [String(at), item]) : Object.entries(value);
|
|
3
|
+
export const child = (path, key) => `${path}/${key.replaceAll('~', '~0').replaceAll('/', '~1')}`;
|
|
4
|
+
export const ancestorsOf = (path) => {
|
|
5
|
+
const cuts = [];
|
|
6
|
+
for (let at = path.indexOf('/'); at !== -1; at = path.indexOf('/', at + 1)) {
|
|
7
|
+
cuts.push(path.slice(0, at));
|
|
8
|
+
}
|
|
9
|
+
return cuts;
|
|
10
|
+
};
|
|
11
|
+
const words = (value) => (branchy(value) ? '' : String(value));
|
|
12
|
+
export const search = (root, query) => {
|
|
13
|
+
const found = new Set();
|
|
14
|
+
const wanted = query.trim().toLocaleLowerCase();
|
|
15
|
+
if (wanted === '' || root === undefined) {
|
|
16
|
+
return found;
|
|
17
|
+
}
|
|
18
|
+
const visit = (value, path, key) => {
|
|
19
|
+
if (key?.toLocaleLowerCase().includes(wanted) ||
|
|
20
|
+
words(value).toLocaleLowerCase().includes(wanted)) {
|
|
21
|
+
found.add(path);
|
|
22
|
+
}
|
|
23
|
+
if (branchy(value)) {
|
|
24
|
+
for (const [name, item] of entries(value)) {
|
|
25
|
+
visit(item, child(path, name), name);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
visit(root, '');
|
|
30
|
+
return found;
|
|
31
|
+
};
|
|
32
|
+
export const flatten = (root, opened, found) => {
|
|
33
|
+
const rows = [];
|
|
34
|
+
if (root === undefined) {
|
|
35
|
+
return rows;
|
|
36
|
+
}
|
|
37
|
+
const trail = new Set([...(found ?? [])].flatMap(ancestorsOf));
|
|
38
|
+
const visit = (value, path, depth, position, siblings, under, key) => {
|
|
39
|
+
const branch = branchy(value);
|
|
40
|
+
const open = branch && opened.has(path);
|
|
41
|
+
const match = found?.has(path) === true;
|
|
42
|
+
rows.push({
|
|
43
|
+
branch,
|
|
44
|
+
depth,
|
|
45
|
+
match,
|
|
46
|
+
open,
|
|
47
|
+
path,
|
|
48
|
+
position,
|
|
49
|
+
siblings,
|
|
50
|
+
value,
|
|
51
|
+
...(key === undefined ? {} : { key }),
|
|
52
|
+
});
|
|
53
|
+
if (!open) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const inside = under || match || !found;
|
|
57
|
+
const children = entries(value)
|
|
58
|
+
.map(([name, item]) => [name, item, child(path, name)])
|
|
59
|
+
.filter(([, , at]) => inside || found?.has(at) || trail.has(at));
|
|
60
|
+
children.forEach(([name, item, at], index) => {
|
|
61
|
+
visit(item, at, depth + 1, index + 1, children.length, inside && !!found, name);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
if (!found || found.has('') || trail.has('')) {
|
|
65
|
+
visit(root, '', 0, 1, 1, false);
|
|
66
|
+
}
|
|
67
|
+
return rows;
|
|
68
|
+
};
|
|
69
|
+
export const seed = (root, depth, known = new Set(), opened = new Set()) => {
|
|
70
|
+
const open = new Set();
|
|
71
|
+
const branches = new Set();
|
|
72
|
+
const visit = (value, path, level) => {
|
|
73
|
+
if (!branchy(value)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
branches.add(path);
|
|
77
|
+
if (known.has(path) ? opened.has(path) : level < depth) {
|
|
78
|
+
open.add(path);
|
|
79
|
+
}
|
|
80
|
+
for (const [name, item] of entries(value)) {
|
|
81
|
+
visit(item, child(path, name), level + 1);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
visit(root, '', 0);
|
|
85
|
+
return { branches, opened: open };
|
|
86
|
+
};
|
|
87
|
+
export const cursorFor = (rows, path, cursor, filtered) => {
|
|
88
|
+
const at = (one) => rows.findIndex((row) => row.path === one);
|
|
89
|
+
const own = path === undefined ? -1 : at(path);
|
|
90
|
+
if (own >= 0 || path === undefined) {
|
|
91
|
+
return own >= 0 ? own : Math.min(cursor, Math.max(0, rows.length - 1));
|
|
92
|
+
}
|
|
93
|
+
const match = filtered ? rows.findIndex((row) => row.match) : -1;
|
|
94
|
+
const around = ancestorsOf(path)
|
|
95
|
+
.reverse()
|
|
96
|
+
.map(at)
|
|
97
|
+
.find((one) => one >= 0);
|
|
98
|
+
return match >= 0 ? match : (around ?? 0);
|
|
99
|
+
};
|
|
100
|
+
export const withAncestors = (opened, branches, paths) => {
|
|
101
|
+
const next = new Set(opened);
|
|
102
|
+
for (const path of paths) {
|
|
103
|
+
for (const above of ancestorsOf(path)) {
|
|
104
|
+
if (branches.has(above)) {
|
|
105
|
+
next.add(above);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return next;
|
|
110
|
+
};
|
|
111
|
+
export const siblingBranches = (rows, row) => {
|
|
112
|
+
const parent = row.path.slice(0, row.path.lastIndexOf('/'));
|
|
113
|
+
return rows
|
|
114
|
+
.filter((one) => one.branch &&
|
|
115
|
+
!one.open &&
|
|
116
|
+
one.depth === row.depth &&
|
|
117
|
+
one.path.slice(0, one.path.lastIndexOf('/')) === parent)
|
|
118
|
+
.map((one) => one.path);
|
|
119
|
+
};
|
|
@@ -63,9 +63,11 @@ export declare class HelixHeadlessOption extends HelixElement {
|
|
|
63
63
|
/**
|
|
64
64
|
* Whether this is the option the keyboard is on.
|
|
65
65
|
*
|
|
66
|
-
* Written by the listbox
|
|
67
|
-
*
|
|
68
|
-
*
|
|
66
|
+
* Written by the listbox once a reader moves the highlight. Style it with
|
|
67
|
+
* `:state(active)`, or `::part(item-active)` for an option inside another
|
|
68
|
+
* component's shadow root. The `data-active` attribute sets it from markup;
|
|
69
|
+
* it is also written back for stylesheets from before the state, and no
|
|
70
|
+
* stylesheet of the library's own selects it.
|
|
69
71
|
*/
|
|
70
72
|
active: boolean;
|
|
71
73
|
/**
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The levels of a flat run of links, as the nested lists they describe.
|
|
3
|
+
*
|
|
4
|
+
* A contents list written flat, `<a data-level="2">`, says its depth in an
|
|
5
|
+
* attribute that only a stylesheet reads. The outline turns the run into lists
|
|
6
|
+
* inside list items in its shadow root, so a screen reader hears the levels a
|
|
7
|
+
* nested `<ul>` would have given it, with the links left where they are.
|
|
8
|
+
*/
|
|
9
|
+
/** One link in the tree: its place in the run, and the links nested under it. */
|
|
10
|
+
export interface Branch {
|
|
11
|
+
/** The link's position in the flat run, counted from zero. */
|
|
12
|
+
index: number;
|
|
13
|
+
/** The links one level or more deeper that follow it, before the next at its level. */
|
|
14
|
+
children: Branch[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The level a link's `data-level` asks for, a whole number from 1.
|
|
18
|
+
*
|
|
19
|
+
* Absent, empty, or not a number is the top level, which is how the outline
|
|
20
|
+
* has always read a link without one.
|
|
21
|
+
*/
|
|
22
|
+
export declare const levelOf: (value: string | null) => number;
|
|
23
|
+
/**
|
|
24
|
+
* Nests a run of levels.
|
|
25
|
+
*
|
|
26
|
+
* Each link goes under the nearest link before it with a lower level, and to
|
|
27
|
+
* the top where there is none. A jump of two levels nests one list deeper and
|
|
28
|
+
* not two, since a list item with no link of its own would be read as an empty
|
|
29
|
+
* entry. A run that starts deeper than 1 starts at the top all the same.
|
|
30
|
+
*/
|
|
31
|
+
export declare const nest: (levels: readonly number[]) => Branch[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const levelOf = (value) => {
|
|
2
|
+
const level = Number.parseInt(value ?? '', 10);
|
|
3
|
+
return Number.isFinite(level) && level >= 1 ? level : 1;
|
|
4
|
+
};
|
|
5
|
+
export const nest = (levels) => {
|
|
6
|
+
const top = [];
|
|
7
|
+
const open = [];
|
|
8
|
+
levels.forEach((level, index) => {
|
|
9
|
+
const branch = { children: [], index };
|
|
10
|
+
while (open.length > 0 && (open.at(-1)?.level ?? 0) >= level) {
|
|
11
|
+
open.pop();
|
|
12
|
+
}
|
|
13
|
+
const parent = open.at(-1);
|
|
14
|
+
if (parent) {
|
|
15
|
+
parent.branch.children.push(branch);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
top.push(branch);
|
|
19
|
+
}
|
|
20
|
+
open.push({ branch, level });
|
|
21
|
+
});
|
|
22
|
+
return top;
|
|
23
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import { type Branch } from '../levels.js';
|
|
3
4
|
/**
|
|
4
5
|
* @summary Links to the headings on the page, with the section in view marked.
|
|
5
6
|
*
|
|
@@ -12,8 +13,15 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
12
13
|
* the same page.
|
|
13
14
|
*
|
|
14
15
|
* Write the anchors flat, with `data-level` for their depth, or nested in
|
|
15
|
-
* lists, `<ul><li><a>`. A screen reader hears
|
|
16
|
-
*
|
|
16
|
+
* lists, `<ul><li><a>`. A screen reader hears the levels either way: the
|
|
17
|
+
* outline puts a flat run into lists inside list items of its own, nested by
|
|
18
|
+
* `data-level`, and leaves the links where they are. A link without
|
|
19
|
+
* `data-level` is at the top level.
|
|
20
|
+
*
|
|
21
|
+
* A heading slotted into `heading` names the navigation, in place of `label`.
|
|
22
|
+
*
|
|
23
|
+
* In a contents rail with a scrollbar of its own, `follow` keeps the link of
|
|
24
|
+
* the section in view showing as the reader scrolls the page.
|
|
17
25
|
*
|
|
18
26
|
* The current section is decided by the headings' positions. An
|
|
19
27
|
* `IntersectionObserver` with a band near the top fails both ways: when
|
|
@@ -27,13 +35,24 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
27
35
|
* @documentation https://fusion.dev/helix/components/outline
|
|
28
36
|
*
|
|
29
37
|
* @slot - The links, as anchors with fragment hrefs, or lists holding them.
|
|
38
|
+
* @slot heading - A heading above the links, such as "On this page". It names the navigation.
|
|
30
39
|
*
|
|
31
40
|
* @event {HelixActivateEvent} helix-activate - Fired when the section in view changes, with its id as the value. It reports the scroll position and cannot be prevented.
|
|
32
41
|
*
|
|
42
|
+
* @csspart heading - The box holding the `heading` slot, above the navigation.
|
|
33
43
|
* @csspart indicator - The mark that moves to the section in view.
|
|
34
44
|
* @csspart nav - The navigation landmark.
|
|
35
45
|
*/
|
|
36
46
|
export declare class HelixHeadlessOutline extends HelixElement {
|
|
47
|
+
/**
|
|
48
|
+
* Manual, so each link in a flat run can be put in a list item of its own.
|
|
49
|
+
*
|
|
50
|
+
* The list items are slots, which lay out as nothing at all, so each link is
|
|
51
|
+
* still laid out as a child of the navigation exactly where it was, and the
|
|
52
|
+
* consumer's markup is not touched. A run holding anything but links, a
|
|
53
|
+
* `<ul>` among them, goes to one plain slot as before.
|
|
54
|
+
*/
|
|
55
|
+
static shadowRootOptions: ShadowRootInit;
|
|
37
56
|
private readonly indicator;
|
|
38
57
|
/**
|
|
39
58
|
* How the page scrolls to a section when its link is clicked.
|
|
@@ -58,7 +77,15 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
58
77
|
*/
|
|
59
78
|
behavior: ScrollBehavior;
|
|
60
79
|
/**
|
|
61
|
-
*
|
|
80
|
+
* Keeps the link of the section in view in view itself, in an outline
|
|
81
|
+
* longer than the box it scrolls in, such as a contents rail with a
|
|
82
|
+
* scrollbar of its own. Only that box moves: never the page, and never the
|
|
83
|
+
* box the sections scroll in.
|
|
84
|
+
*/
|
|
85
|
+
follow: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The navigation's name, read by screen readers. A heading in the `heading`
|
|
88
|
+
* slot names it in place of this.
|
|
62
89
|
*/
|
|
63
90
|
label: string;
|
|
64
91
|
/**
|
|
@@ -92,6 +119,11 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
92
119
|
*/
|
|
93
120
|
private reading;
|
|
94
121
|
private observer;
|
|
122
|
+
/**
|
|
123
|
+
* Watches the children, which a manual root is not told about: a link
|
|
124
|
+
* arriving, leaving or changing its level changes the lists drawn for them.
|
|
125
|
+
*/
|
|
126
|
+
private childWatch;
|
|
95
127
|
/**
|
|
96
128
|
* The links, in document order. Empty on the server, which has no tree.
|
|
97
129
|
*
|
|
@@ -101,6 +133,18 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
101
133
|
* nothing was announced, and nothing said why.
|
|
102
134
|
*/
|
|
103
135
|
private get links();
|
|
136
|
+
/** The children that are the content, which is all of them but the heading. */
|
|
137
|
+
private get content();
|
|
138
|
+
/**
|
|
139
|
+
* The links of a flat run, which the render puts into lists, or `undefined`
|
|
140
|
+
* where the content is anything else.
|
|
141
|
+
*
|
|
142
|
+
* Anything else is a list a consumer wrote, which already has its levels, a
|
|
143
|
+
* slot forwarded from a component around this one, or a server's render and
|
|
144
|
+
* the hydration of one, which cannot know the children. A root a server sent
|
|
145
|
+
* routes by name, so it keeps the plain slot after hydration too.
|
|
146
|
+
*/
|
|
147
|
+
private get run();
|
|
104
148
|
/**
|
|
105
149
|
* What each link points at, paired with the link, skipping anything missing.
|
|
106
150
|
*
|
|
@@ -120,6 +164,14 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
120
164
|
private mark;
|
|
121
165
|
/** Where the destination is set, whether measured or asked for. */
|
|
122
166
|
private markTo;
|
|
167
|
+
/**
|
|
168
|
+
* Scrolls the box the links scroll in to show `link`, under `follow`.
|
|
169
|
+
*
|
|
170
|
+
* The nearest box above the link that scrolls, and only where it is the
|
|
171
|
+
* rail's own: the page, the box the sections scroll in, or a box holding it
|
|
172
|
+
* would move the reading under the reader, which is the scroll this marks.
|
|
173
|
+
*/
|
|
174
|
+
private reveal;
|
|
123
175
|
/**
|
|
124
176
|
* Whether the page has no more scroll left.
|
|
125
177
|
*
|
|
@@ -250,8 +302,39 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
250
302
|
private unland;
|
|
251
303
|
connectedCallback(): void;
|
|
252
304
|
protected firstUpdated(changed: PropertyValues): void;
|
|
305
|
+
/**
|
|
306
|
+
* Puts each child in its slot, on a root this element made.
|
|
307
|
+
*
|
|
308
|
+
* A link of a flat run goes to the slot inside its list item, and anything
|
|
309
|
+
* else, with the text between, to the plain slot. A root a server sent
|
|
310
|
+
* routes by name and needs none of it.
|
|
311
|
+
*/
|
|
312
|
+
private assign;
|
|
313
|
+
/** Whether the heading is what names the navigation. */
|
|
314
|
+
private namedByHeading;
|
|
315
|
+
/**
|
|
316
|
+
* Names the navigation by what is in the `heading` slot, in place of `label`.
|
|
317
|
+
*
|
|
318
|
+
* An element reference, because the heading is in the light DOM and the
|
|
319
|
+
* `<nav>` in this shadow root, which an IDREF cannot cross. A browser without
|
|
320
|
+
* element reflection keeps `label`.
|
|
321
|
+
*/
|
|
322
|
+
private readonly nameByHeading;
|
|
253
323
|
protected updated(changed: PropertyValues): void;
|
|
254
324
|
protected render(): TemplateResult;
|
|
325
|
+
/**
|
|
326
|
+
* A list for a run of links, with a list item for each, nested by level.
|
|
327
|
+
*
|
|
328
|
+
* **Slots, because a slot lays out as nothing.** A list and its items drawn
|
|
329
|
+
* as boxes would put each link inside an item, out of the navigation's own
|
|
330
|
+
* flex column, and every outline styled against that column would move. A
|
|
331
|
+
* slot is `display: contents`, keeps a role it is given, and shows its
|
|
332
|
+
* children while nothing is assigned to it, so the items nest in the
|
|
333
|
+
* accessibility tree and nowhere else. Measured in Chromium: every link at the
|
|
334
|
+
* same box with and without the lists, and each item at the level its
|
|
335
|
+
* nesting gives it.
|
|
336
|
+
*/
|
|
337
|
+
protected renderList(branches: Branch[]): TemplateResult;
|
|
255
338
|
}
|
|
256
339
|
declare global {
|
|
257
340
|
interface HTMLElementTagNameMap {
|
|
@@ -4,9 +4,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, elementById, HelixActivateEvent, HelixElement, IndicatorController, } from '@fusion.dev/helix-core';
|
|
8
|
-
import { html } from 'lit';
|
|
7
|
+
import { customElement, elementById, HelixActivateEvent, HelixElement, IndicatorController, plainClick, reflectElements, scrollItemIntoView, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { levelOf, nest } from '../levels.js';
|
|
11
|
+
const isFragment = (element) => element instanceof HTMLAnchorElement && element.getAttribute('href')?.startsWith('#') === true;
|
|
10
12
|
let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
11
13
|
constructor() {
|
|
12
14
|
super(...arguments);
|
|
@@ -16,6 +18,7 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
16
18
|
surface: () => this.partNamed('nav'),
|
|
17
19
|
});
|
|
18
20
|
this.behavior = 'auto';
|
|
21
|
+
this.follow = false;
|
|
19
22
|
this.label = 'On this page';
|
|
20
23
|
this.offset = 0;
|
|
21
24
|
this.reading = '';
|
|
@@ -30,10 +33,7 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
30
33
|
});
|
|
31
34
|
};
|
|
32
35
|
this.handleClick = (event) => {
|
|
33
|
-
if (event.defaultPrevented || event
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
|
36
|
+
if (event.defaultPrevented || !plainClick(event)) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
const link = event.target?.closest?.('a[href^="#"]');
|
|
@@ -72,16 +72,38 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
72
72
|
this.watch();
|
|
73
73
|
this.indicator.place();
|
|
74
74
|
};
|
|
75
|
+
this.namedByHeading = false;
|
|
76
|
+
this.nameByHeading = () => {
|
|
77
|
+
const slot = this.renderRoot?.querySelector?.('slot[name="heading"]');
|
|
78
|
+
this.namedByHeading = reflectElements(this.partNamed('nav'), 'ariaLabelledByElements', slot?.assignedElements({ flatten: true }) ?? [], this.namedByHeading);
|
|
79
|
+
};
|
|
75
80
|
}
|
|
81
|
+
static { this.shadowRootOptions = {
|
|
82
|
+
...HelixElement.shadowRootOptions,
|
|
83
|
+
slotAssignment: 'manual',
|
|
84
|
+
}; }
|
|
76
85
|
get current() {
|
|
77
86
|
return this.reading;
|
|
78
87
|
}
|
|
79
88
|
get links() {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
const slots = [
|
|
90
|
+
...(this.renderRoot?.querySelectorAll?.('slot[data-link], nav > slot:not([role])') ?? []),
|
|
91
|
+
];
|
|
92
|
+
return slots
|
|
93
|
+
.flatMap((slot) => slot.assignedElements({ flatten: true }))
|
|
94
|
+
.flatMap((element) => isFragment(element)
|
|
83
95
|
? [element]
|
|
84
|
-
: [...element.querySelectorAll('a[href^="#"]')].filter(
|
|
96
|
+
: [...element.querySelectorAll('a[href^="#"]')].filter(isFragment));
|
|
97
|
+
}
|
|
98
|
+
get content() {
|
|
99
|
+
return this.knownChildren.filter((child) => child.slot !== 'heading');
|
|
100
|
+
}
|
|
101
|
+
get run() {
|
|
102
|
+
const content = this.content;
|
|
103
|
+
if (this.assignsByName || content.length === 0 || !content.every(isFragment)) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
return content;
|
|
85
107
|
}
|
|
86
108
|
get sections() {
|
|
87
109
|
return this.links.flatMap((link) => {
|
|
@@ -118,9 +140,26 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
118
140
|
if (next !== this.reading) {
|
|
119
141
|
this.reading = next;
|
|
120
142
|
this.indicator.place();
|
|
143
|
+
if (this.follow && active) {
|
|
144
|
+
this.reveal(active.link);
|
|
145
|
+
}
|
|
121
146
|
this.dispatchEvent(new HelixActivateEvent({ value: next }));
|
|
122
147
|
}
|
|
123
148
|
}
|
|
149
|
+
reveal(link) {
|
|
150
|
+
const sections = this.scroller;
|
|
151
|
+
const page = this.page;
|
|
152
|
+
for (let node = link.parentElement; node && node !== page; node = node.parentElement) {
|
|
153
|
+
const { overflowY } = getComputedStyle(node);
|
|
154
|
+
if (!/auto|scroll|overlay/.test(overflowY) || node.scrollHeight <= node.clientHeight) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (node !== sections && !node.contains(sections)) {
|
|
158
|
+
scrollItemIntoView(link, { scroller: node });
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
124
163
|
get atEnd() {
|
|
125
164
|
const doc = this.scroller;
|
|
126
165
|
return Math.ceil(doc.scrollTop + doc.clientHeight) >= doc.scrollHeight - 1;
|
|
@@ -163,6 +202,8 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
163
202
|
}
|
|
164
203
|
disconnectedCallback() {
|
|
165
204
|
super.disconnectedCallback();
|
|
205
|
+
this.childWatch?.disconnect();
|
|
206
|
+
this.childWatch = undefined;
|
|
166
207
|
this.removeEventListener('click', this.handleClick);
|
|
167
208
|
document.removeEventListener('scroll', this.handleScroll, true);
|
|
168
209
|
if (this.frame !== 0) {
|
|
@@ -183,6 +224,12 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
183
224
|
}
|
|
184
225
|
connectedCallback() {
|
|
185
226
|
super.connectedCallback();
|
|
227
|
+
this.childWatch = new MutationObserver(() => this.requestUpdate());
|
|
228
|
+
this.childWatch.observe(this, {
|
|
229
|
+
attributeFilter: ['data-level', 'href', 'slot'],
|
|
230
|
+
childList: true,
|
|
231
|
+
subtree: true,
|
|
232
|
+
});
|
|
186
233
|
this.addEventListener('click', this.handleClick);
|
|
187
234
|
document.addEventListener('scroll', this.handleScroll, {
|
|
188
235
|
capture: true,
|
|
@@ -195,9 +242,32 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
195
242
|
firstUpdated(changed) {
|
|
196
243
|
super.firstUpdated(changed);
|
|
197
244
|
this.watch();
|
|
245
|
+
this.finishHydration();
|
|
246
|
+
}
|
|
247
|
+
assign() {
|
|
248
|
+
if (this.assignsByName) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const root = this.renderRoot;
|
|
252
|
+
const heading = root?.querySelector?.('slot[name="heading"]');
|
|
253
|
+
heading?.assign?.(...this.knownChildren.filter((child) => child.slot === 'heading'));
|
|
254
|
+
const run = this.run;
|
|
255
|
+
if (run) {
|
|
256
|
+
for (const slot of root?.querySelectorAll?.('slot[data-link]') ?? []) {
|
|
257
|
+
const link = run[Number(slot.dataset.link)];
|
|
258
|
+
if (link) {
|
|
259
|
+
slot.assign(link);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const plain = root?.querySelector?.('nav > slot:not([role])');
|
|
265
|
+
plain?.assign?.(...[...this.childNodes].filter((node) => node instanceof Element ? node.slot !== 'heading' : node instanceof Text));
|
|
198
266
|
}
|
|
199
267
|
updated(changed) {
|
|
200
268
|
super.updated(changed);
|
|
269
|
+
this.assign();
|
|
270
|
+
this.nameByHeading();
|
|
201
271
|
if (changed.has('offset')) {
|
|
202
272
|
this.reach();
|
|
203
273
|
this.mark();
|
|
@@ -208,15 +278,28 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
208
278
|
this.indicator.place();
|
|
209
279
|
}
|
|
210
280
|
render() {
|
|
211
|
-
|
|
212
|
-
|
|
281
|
+
const run = this.run;
|
|
282
|
+
return html `<div part="heading"><slot name="heading" @slotchange=${this.nameByHeading}></slot></div>
|
|
283
|
+
<nav part="nav" aria-label=${this.label} @slotchange=${this.handleSlotChange}>
|
|
284
|
+
${run ? this.renderList(nest(run.map((link) => levelOf(link.getAttribute('data-level'))))) : html `<slot></slot>`}
|
|
213
285
|
<span part="indicator" aria-hidden="true"></span>
|
|
214
286
|
</nav>`;
|
|
215
287
|
}
|
|
288
|
+
renderList(branches) {
|
|
289
|
+
return html `<slot role="list"
|
|
290
|
+
>${branches.map((branch) => html `<slot role="listitem"
|
|
291
|
+
><slot data-link=${branch.index}></slot
|
|
292
|
+
>${branch.children.length > 0 ? this.renderList(branch.children) : nothing}</slot
|
|
293
|
+
>`)}</slot
|
|
294
|
+
>`;
|
|
295
|
+
}
|
|
216
296
|
};
|
|
217
297
|
__decorate([
|
|
218
298
|
property()
|
|
219
299
|
], HelixHeadlessOutline.prototype, "behavior", void 0);
|
|
300
|
+
__decorate([
|
|
301
|
+
property({ type: Boolean })
|
|
302
|
+
], HelixHeadlessOutline.prototype, "follow", void 0);
|
|
220
303
|
__decorate([
|
|
221
304
|
property()
|
|
222
305
|
], HelixHeadlessOutline.prototype, "label", void 0);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HelixFormElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import '../../option/index.js';
|
|
4
4
|
import '../../select/index.js';
|
|
@@ -28,6 +28,11 @@ import '../../select/index.js';
|
|
|
28
28
|
* Re-querying and returning to page one is up to you, because only you know
|
|
29
29
|
* whether the current position should be kept.
|
|
30
30
|
*
|
|
31
|
+
* It takes part in a form. Give it a `name` and the size in force is submitted
|
|
32
|
+
* under that name, so a `GET` form carries it in the address beside the page.
|
|
33
|
+
* A form reset returns it to `default-value`, and `disabled`, or a disabled
|
|
34
|
+
* `<fieldset>` around it, turns the select off.
|
|
35
|
+
*
|
|
31
36
|
* @since 0.1.0
|
|
32
37
|
* @status stable
|
|
33
38
|
* @aliases Page size, Rows per page
|
|
@@ -44,6 +49,7 @@ import '../../select/index.js';
|
|
|
44
49
|
* @csspart control-label - The label beside the number.
|
|
45
50
|
* @csspart control-listbox - The list inside the panel.
|
|
46
51
|
* @csspart control-listbox-empty - The text shown when the filter hides every option.
|
|
52
|
+
* @csspart control-listbox-error - The inner list's `error` part, shown while its `load-error` is set.
|
|
47
53
|
* @csspart control-listbox-feedback - The inner list's message that says what is wrong with the value.
|
|
48
54
|
* @csspart control-listbox-filter-icon - The icon beside the filter field.
|
|
49
55
|
* @csspart control-listbox-filter-mark - The default icon beside the filter field, shown when none is slotted.
|
|
@@ -67,7 +73,7 @@ import '../../select/index.js';
|
|
|
67
73
|
*
|
|
68
74
|
* @cssstate empty - While there are no sizes to offer.
|
|
69
75
|
*/
|
|
70
|
-
export declare class HelixHeadlessPaginationSize extends
|
|
76
|
+
export declare class HelixHeadlessPaginationSize extends HelixFormElement {
|
|
71
77
|
/**
|
|
72
78
|
* The size to start on when `value` is not set.
|
|
73
79
|
*/
|
|
@@ -115,6 +121,10 @@ export declare class HelixHeadlessPaginationSize extends HelixElement {
|
|
|
115
121
|
* after it, and a refused size still sent it.
|
|
116
122
|
*/
|
|
117
123
|
private readonly stopNative;
|
|
124
|
+
/** Returns to the size the markup declared, as a native `<select>` does on a reset. */
|
|
125
|
+
formResetCallback(): void;
|
|
126
|
+
/** Takes back the size a browser restores with the form, or the declared one. */
|
|
127
|
+
formStateRestoreCallback(state: string | File | FormData | null): void;
|
|
118
128
|
protected willUpdate(changed: PropertyValues): void;
|
|
119
129
|
/**
|
|
120
130
|
* The control itself, which is the whole of this part, behind a seam the styled tier can move.
|
|
@@ -4,13 +4,13 @@ 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,
|
|
7
|
+
import { customElement, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, 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';
|
|
11
11
|
import '../../option/index.js';
|
|
12
12
|
import '../../select/index.js';
|
|
13
|
-
let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends
|
|
13
|
+
let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends HelixFormElement {
|
|
14
14
|
constructor() {
|
|
15
15
|
super(...arguments);
|
|
16
16
|
this.defaultValue = 0;
|
|
@@ -29,8 +29,8 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
29
29
|
const previous = this.value;
|
|
30
30
|
this.valueState = size;
|
|
31
31
|
this.requestUpdate('value', previous);
|
|
32
|
-
this.
|
|
33
|
-
this.
|
|
32
|
+
this.announceInput();
|
|
33
|
+
this.announceChange();
|
|
34
34
|
},
|
|
35
35
|
event: (size) => new HelixBeforeChangeEvent({ value: String(size) }),
|
|
36
36
|
host: this,
|
|
@@ -68,9 +68,23 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
68
68
|
const options = this.options;
|
|
69
69
|
return options.includes(this.value) ? this.value : (options[0] ?? 0);
|
|
70
70
|
}
|
|
71
|
+
formResetCallback() {
|
|
72
|
+
super.formResetCallback();
|
|
73
|
+
const previous = this.value;
|
|
74
|
+
this.valueState = undefined;
|
|
75
|
+
this.requestUpdate('value', previous);
|
|
76
|
+
}
|
|
77
|
+
formStateRestoreCallback(state) {
|
|
78
|
+
const size = typeof state === 'string' ? Number.parseInt(state, 10) : Number.NaN;
|
|
79
|
+
const previous = this.value;
|
|
80
|
+
this.valueState = Number.isFinite(size) && size > 0 ? size : undefined;
|
|
81
|
+
this.requestUpdate('value', previous);
|
|
82
|
+
}
|
|
71
83
|
willUpdate(changed) {
|
|
72
84
|
super.willUpdate(changed);
|
|
73
85
|
this.toggleState('empty', this.options.length === 0);
|
|
86
|
+
const current = this.current;
|
|
87
|
+
this.internals.setFormValue(current > 0 ? String(current) : null);
|
|
74
88
|
}
|
|
75
89
|
renderSelect() {
|
|
76
90
|
const select = this.tag('select');
|
|
@@ -79,13 +93,14 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
79
93
|
part="control"
|
|
80
94
|
exportparts="feedback: control-feedback, hint: control-hint, indicator: control-indicator,
|
|
81
95
|
label: control-label, listbox: control-listbox, listbox-empty: control-listbox-empty,
|
|
82
|
-
listbox-feedback: control-listbox-feedback, listbox-filter-icon: control-listbox-filter-icon,
|
|
96
|
+
listbox-error: control-listbox-error, listbox-feedback: control-listbox-feedback, listbox-filter-icon: control-listbox-filter-icon,
|
|
83
97
|
listbox-filter-mark: control-listbox-filter-mark, listbox-hint: control-listbox-hint,
|
|
84
98
|
listbox-items: control-listbox-items, listbox-label: control-listbox-label,
|
|
85
99
|
listbox-live: control-listbox-live, listbox-loading: control-listbox-loading, listbox-search: control-listbox-search,
|
|
86
100
|
listbox-search-field: control-listbox-search-field, surface: control-surface,
|
|
87
101
|
trigger: control-trigger, value: control-value"
|
|
88
102
|
label=${this.label}
|
|
103
|
+
?disabled=${this.isDisabled}
|
|
89
104
|
.value=${String(this.current)}
|
|
90
105
|
@helix-before-change=${this.handleChange}
|
|
91
106
|
@input=${this.stopNative}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PinCase, PinType } from './root/pin-input-root.js';
|
|
2
|
+
/**
|
|
3
|
+
* Typed or pasted text as the code's characters: trimmed, with what `type`
|
|
4
|
+
* refuses dropped, and its letters cased as `letterCase` asks. Web Awesome's
|
|
5
|
+
* OTP input takes the same `case`.
|
|
6
|
+
*
|
|
7
|
+
* `numeric` keeps digits, `alphanumeric` keeps ASCII letters and digits, and
|
|
8
|
+
* `text` keeps everything.
|
|
9
|
+
*/
|
|
10
|
+
export declare const cleanCode: (text: string, type: PinType, letterCase?: PinCase) => string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const cleanCode = (text, type, letterCase = 'preserve') => {
|
|
2
|
+
const trimmed = text.trim();
|
|
3
|
+
const kept = type === 'numeric'
|
|
4
|
+
? trimmed.replace(/\D/g, '')
|
|
5
|
+
: type === 'alphanumeric'
|
|
6
|
+
? trimmed.replace(/[^0-9A-Za-z]/g, '')
|
|
7
|
+
: trimmed;
|
|
8
|
+
return letterCase === 'upper'
|
|
9
|
+
? kept.toUpperCase()
|
|
10
|
+
: letterCase === 'lower'
|
|
11
|
+
? kept.toLowerCase()
|
|
12
|
+
: kept;
|
|
13
|
+
};
|