@fusion.dev/helix-headless 0.143.0 → 0.145.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 +16990 -1383
- package/dist/accordion/item/accordion-item.d.ts +48 -12
- package/dist/accordion/item/accordion-item.js +26 -5
- package/dist/accordion/root/accordion-root.d.ts +6 -0
- package/dist/accordion/root/accordion-root.js +7 -1
- package/dist/announcement/root/announcement-root.d.ts +21 -1
- package/dist/announcement/root/announcement-root.js +36 -1
- package/dist/app-header/root/app-header-root.d.ts +7 -0
- package/dist/app-header/root/app-header-root.js +5 -1
- package/dist/app-header/sectioning.d.ts +7 -0
- package/dist/app-header/sectioning.js +26 -0
- package/dist/area-chart/root/area-chart-root.d.ts +12 -4
- package/dist/area-chart/root/area-chart-root.js +24 -7
- package/dist/avatar/root/avatar-root.d.ts +14 -0
- package/dist/avatar/root/avatar-root.js +23 -9
- package/dist/badge/root/badge-root.d.ts +11 -7
- package/dist/badge/root/badge-root.js +1 -1
- package/dist/bar-chart/root/bar-chart-root.d.ts +12 -3
- package/dist/bar-chart/root/bar-chart-root.js +17 -10
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +32 -1
- package/dist/breadcrumbs/root/breadcrumbs-root.js +25 -2
- package/dist/button/root/button-root.d.ts +47 -1
- package/dist/button/root/button-root.js +38 -4
- package/dist/callout/root/callout-root.d.ts +18 -1
- package/dist/callout/root/callout-root.js +15 -4
- package/dist/canvas/root/canvas-root.d.ts +38 -3
- package/dist/canvas/root/canvas-root.js +121 -40
- package/dist/card/root/card-root.d.ts +30 -1
- package/dist/card/root/card-root.js +38 -5
- package/dist/carousel/root/carousel-root.d.ts +90 -0
- package/dist/carousel/root/carousel-root.js +134 -12
- 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 +25 -9
- package/dist/chat/naming.d.ts +22 -0
- package/dist/chat/naming.js +12 -0
- package/dist/chat/relative-clock.d.ts +39 -0
- package/dist/chat/relative-clock.js +31 -0
- package/dist/chat/root/chat-root.d.ts +36 -0
- package/dist/chat/root/chat-root.js +24 -1
- package/dist/checkbox/root/checkbox-root.js +2 -0
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +53 -3
- package/dist/checkbox-group/root/checkbox-group-root.js +71 -22
- package/dist/code-block/lines.d.ts +13 -0
- package/dist/code-block/lines.js +2 -0
- package/dist/code-block/root/code-block-root.d.ts +38 -1
- package/dist/code-block/root/code-block-root.js +28 -7
- package/dist/color-input/root/color-input-root.d.ts +34 -1
- package/dist/color-input/root/color-input-root.js +23 -4
- package/dist/color-picker/channels.d.ts +26 -0
- package/dist/color-picker/channels.js +84 -0
- package/dist/color-picker/root/color-picker-root.d.ts +81 -5
- package/dist/color-picker/root/color-picker-root.js +103 -10
- package/dist/combobox/root/combobox-root.d.ts +38 -3
- package/dist/combobox/root/combobox-root.js +64 -2
- package/dist/command/root/command-root.d.ts +30 -4
- package/dist/command/root/command-root.js +33 -3
- package/dist/copy-button/from.d.ts +22 -0
- package/dist/copy-button/from.js +28 -0
- package/dist/copy-button/root/copy-button-root.d.ts +47 -1
- package/dist/copy-button/root/copy-button-root.js +44 -8
- package/dist/data-table/root/data-table-root.d.ts +150 -2
- package/dist/data-table/root/data-table-root.js +303 -29
- package/dist/data-table/tree.d.ts +40 -0
- package/dist/data-table/tree.js +55 -0
- package/dist/date-input/root/date-input-root.d.ts +73 -4
- package/dist/date-input/root/date-input-root.js +93 -43
- package/dist/date-picker/root/date-picker-root.d.ts +145 -1
- package/dist/date-picker/root/date-picker-root.js +239 -48
- package/dist/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.d.ts +9 -0
- package/dist/dialog/description.js +14 -0
- package/dist/dialog/root/dialog-root.d.ts +64 -1
- package/dist/dialog/root/dialog-root.js +49 -23
- package/dist/donut-chart/root/donut-chart-root.d.ts +25 -4
- package/dist/donut-chart/root/donut-chart-root.js +21 -6
- package/dist/drawer/root/drawer-root.d.ts +63 -2
- package/dist/drawer/root/drawer-root.js +95 -19
- package/dist/drawer/swipe-start.d.ts +9 -0
- package/dist/drawer/swipe-start.js +12 -0
- package/dist/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 +11 -0
- package/dist/drilldown/root/drilldown-root.js +8 -3
- package/dist/element-events.generated.js +61 -13
- package/dist/empty/root/empty-root.d.ts +1 -1
- package/dist/file-input/root/file-input-root.d.ts +47 -0
- package/dist/file-input/root/file-input-root.js +60 -22
- package/dist/file-input/screen.d.ts +35 -0
- package/dist/file-input/screen.js +49 -0
- package/dist/filter-input/menu/filter-menu.d.ts +3 -0
- package/dist/filter-input/menu/filter-menu.js +8 -4
- package/dist/filter-input/root/filter-input-root.d.ts +38 -4
- package/dist/filter-input/root/filter-input-root.js +67 -3
- package/dist/filter-input/suggest.d.ts +17 -0
- package/dist/filter-input/suggest.js +23 -0
- package/dist/format-date/options.d.ts +33 -0
- package/dist/format-date/options.js +42 -0
- package/dist/format-date/root/format-date-root.d.ts +51 -0
- package/dist/format-date/root/format-date-root.js +58 -38
- package/dist/heatmap/root/heatmap-root.d.ts +23 -6
- package/dist/heatmap/root/heatmap-root.js +24 -13
- package/dist/icon/index.d.ts +2 -0
- package/dist/icon/index.js +2 -0
- package/dist/icon/registry.d.ts +37 -0
- package/dist/icon/registry.js +83 -0
- package/dist/icon/root/icon-root.d.ts +30 -4
- package/dist/icon/root/icon-root.js +41 -6
- package/dist/icon/root/index.d.ts +2 -0
- package/dist/icon/root/index.js +2 -0
- package/dist/icon/set.d.ts +1 -0
- package/dist/icon/set.js +3 -0
- package/dist/image/root/image-root.d.ts +14 -0
- package/dist/image/root/image-root.js +23 -2
- package/dist/input/root/input-root.d.ts +11 -0
- package/dist/input/root/input-root.js +16 -1
- package/dist/kbd/root/kbd-root.d.ts +20 -13
- package/dist/kbd/root/kbd-root.js +35 -37
- package/dist/kbd/shortcut.d.ts +18 -0
- package/dist/kbd/shortcut.js +35 -0
- package/dist/legend/hidden-series.d.ts +8 -0
- package/dist/legend/hidden-series.js +13 -0
- package/dist/legend/root/legend-root.d.ts +56 -0
- package/dist/legend/root/legend-root.js +54 -5
- package/dist/lightbox/item/lightbox-item.d.ts +15 -0
- package/dist/lightbox/item/lightbox-item.js +10 -1
- package/dist/lightbox/root/lightbox-root.d.ts +61 -1
- package/dist/lightbox/root/lightbox-root.js +94 -4
- package/dist/line-chart/root/line-chart-root.d.ts +11 -3
- package/dist/line-chart/root/line-chart-root.js +19 -5
- package/dist/list/item/list-item.d.ts +68 -1
- package/dist/list/item/list-item.js +66 -4
- package/dist/list/numbering.d.ts +14 -0
- package/dist/list/numbering.js +8 -0
- package/dist/list/root/list-root.d.ts +106 -9
- package/dist/list/root/list-root.js +189 -4
- package/dist/list/selection.d.ts +19 -0
- package/dist/list/selection.js +21 -0
- package/dist/listbox/root/listbox-root.d.ts +74 -3
- package/dist/listbox/root/listbox-root.js +86 -9
- package/dist/loader/busy.d.ts +17 -0
- package/dist/loader/busy.js +24 -0
- package/dist/loader/root/loader-root.d.ts +37 -0
- package/dist/loader/root/loader-root.js +52 -3
- package/dist/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 +21 -0
- package/dist/megamenu/root/megamenu-root.js +16 -2
- package/dist/menu/index.d.ts +1 -0
- package/dist/menu/index.js +1 -0
- package/dist/menu/item/menu-item.d.ts +38 -11
- package/dist/menu/item/menu-item.js +33 -1
- package/dist/menu/root/menu-root.d.ts +25 -1
- package/dist/menu/root/menu-root.js +63 -6
- 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 +7 -0
- package/dist/meter/root/meter-root.js +6 -3
- package/dist/navigation/root/navigation-root.d.ts +16 -1
- package/dist/navigation/root/navigation-root.js +27 -1
- package/dist/notifications/feed-keys.d.ts +10 -0
- package/dist/notifications/feed-keys.js +14 -0
- package/dist/notifications/notification/notification.d.ts +17 -0
- package/dist/notifications/notification/notification.js +21 -2
- package/dist/notifications/root/notifications-root.d.ts +60 -0
- package/dist/notifications/root/notifications-root.js +76 -1
- package/dist/number-input/root/number-input-root.d.ts +47 -0
- package/dist/number-input/root/number-input-root.js +58 -22
- package/dist/object-inspector/root/object-inspector-root.d.ts +98 -16
- package/dist/object-inspector/root/object-inspector-root.js +180 -80
- package/dist/object-inspector/rows.d.ts +57 -0
- package/dist/object-inspector/rows.js +86 -0
- package/dist/option/root/option-root.d.ts +54 -5
- package/dist/option/root/option-root.js +34 -5
- package/dist/outline/levels.d.ts +31 -0
- package/dist/outline/levels.js +23 -0
- package/dist/outline/root/outline-root.d.ts +68 -3
- package/dist/outline/root/outline-root.js +73 -8
- package/dist/pagination/size/pagination-size.d.ts +11 -2
- package/dist/pagination/size/pagination-size.js +19 -4
- package/dist/pin-input/format.d.ts +7 -0
- package/dist/pin-input/format.js +16 -0
- package/dist/pin-input/root/pin-input-root.d.ts +21 -0
- package/dist/pin-input/root/pin-input-root.js +29 -2
- package/dist/popover/root/popover-root.d.ts +62 -4
- package/dist/popover/root/popover-root.js +53 -5
- package/dist/progress/root/progress-root.d.ts +7 -0
- package/dist/progress/root/progress-root.js +9 -3
- package/dist/qr-code/export.d.ts +31 -0
- package/dist/qr-code/export.js +10 -0
- package/dist/qr-code/root/qr-code-root.d.ts +26 -0
- package/dist/qr-code/root/qr-code-root.js +49 -2
- package/dist/radio/group/radio-group.d.ts +17 -0
- package/dist/radio/group/radio-group.js +14 -1
- package/dist/rating/root/rating-root.d.ts +25 -0
- package/dist/rating/root/rating-root.js +46 -4
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
- package/dist/scatter-chart/root/scatter-chart-root.js +25 -7
- package/dist/scroll-area/root/scroll-area-root.d.ts +113 -0
- package/dist/scroll-area/root/scroll-area-root.js +218 -3
- package/dist/scroll-area/scrollbar.d.ts +65 -0
- package/dist/scroll-area/scrollbar.js +24 -0
- package/dist/select/root/select-root.d.ts +24 -0
- package/dist/select/root/select-root.js +21 -7
- package/dist/skeleton/root/skeleton-root.d.ts +25 -0
- package/dist/skeleton/root/skeleton-root.js +17 -2
- package/dist/slider/root/slider-root.d.ts +39 -0
- package/dist/slider/root/slider-root.js +45 -9
- package/dist/splitter/root/splitter-root.d.ts +13 -0
- package/dist/splitter/root/splitter-root.js +20 -2
- package/dist/splitter/snap.d.ts +9 -0
- package/dist/splitter/snap.js +12 -0
- package/dist/stat/root/stat-root.d.ts +2 -0
- package/dist/stat/root/stat-root.js +1 -1
- package/dist/steps/reach.d.ts +15 -0
- package/dist/steps/reach.js +12 -0
- package/dist/steps/root/steps-root.d.ts +30 -0
- package/dist/steps/root/steps-root.js +53 -0
- package/dist/steps/step/step.d.ts +39 -2
- package/dist/steps/step/step.js +29 -7
- package/dist/switch/root/switch-root.d.ts +12 -2
- package/dist/switch/root/switch-root.js +6 -1
- package/dist/table/column/table-column.d.ts +11 -0
- package/dist/table/column/table-column.js +6 -1
- package/dist/table/root/table-root.d.ts +101 -0
- package/dist/table/root/table-root.js +166 -5
- 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 +9 -5
- package/dist/tabs/panel/tab-panel.js +3 -4
- package/dist/tabs/root/tabs-root.d.ts +25 -1
- package/dist/tabs/root/tabs-root.js +21 -3
- package/dist/tabs/tab/tab.d.ts +36 -4
- package/dist/tabs/tab/tab.js +46 -3
- package/dist/tag/group/tag-group.d.ts +107 -0
- package/dist/tag/group/tag-group.js +157 -0
- package/dist/tag/index.d.ts +1 -0
- package/dist/tag/index.js +1 -0
- package/dist/tag/root/tag-root.d.ts +60 -0
- package/dist/tag/root/tag-root.js +74 -18
- package/dist/tag/selection.d.ts +10 -0
- package/dist/tag/selection.js +12 -0
- package/dist/textarea/grow.d.ts +22 -0
- package/dist/textarea/grow.js +20 -0
- package/dist/textarea/root/textarea-root.d.ts +9 -0
- package/dist/textarea/root/textarea-root.js +9 -1
- package/dist/time-input/root/time-input-root.d.ts +44 -5
- package/dist/time-input/root/time-input-root.js +69 -39
- package/dist/time-picker/root/time-picker-root.d.ts +54 -8
- package/dist/time-picker/root/time-picker-root.js +121 -91
- package/dist/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/hotkey.d.ts +22 -0
- package/dist/toast/hotkey.js +23 -0
- package/dist/toast/item/toast-item.d.ts +26 -18
- package/dist/toast/item/toast-item.js +55 -48
- package/dist/toast/root/toast-root.d.ts +42 -8
- package/dist/toast/root/toast-root.js +64 -4
- package/dist/toggle/group/toggle-group.d.ts +57 -15
- package/dist/toggle/group/toggle-group.js +69 -9
- package/dist/toggle/root/toggle-root.d.ts +12 -1
- package/dist/toggle/root/toggle-root.js +11 -3
- package/dist/toolbar/root/toolbar-root.d.ts +13 -0
- package/dist/toolbar/root/toolbar-root.js +15 -5
- package/dist/tooltip/focus-target.d.ts +6 -0
- package/dist/tooltip/focus-target.js +9 -0
- package/dist/tooltip/root/tooltip-root.d.ts +42 -17
- package/dist/tooltip/root/tooltip-root.js +50 -9
- package/dist/tour/naming.d.ts +30 -0
- package/dist/tour/naming.js +10 -0
- package/dist/tour/root/tour-root.d.ts +35 -0
- package/dist/tour/root/tour-root.js +56 -5
- package/dist/tour/stop/tour-stop.d.ts +53 -8
- package/dist/tour/stop/tour-stop.js +45 -15
- package/dist/tour/wait.d.ts +11 -0
- package/dist/tour/wait.js +19 -0
- package/dist/tree/item/tree-item.d.ts +54 -1
- package/dist/tree/item/tree-item.js +89 -20
- package/dist/tree/root/tree-root.d.ts +37 -0
- package/dist/tree/root/tree-root.js +51 -6
- package/dist/tree/selection.d.ts +24 -0
- package/dist/tree/selection.js +26 -0
- package/dist/trend/root/trend-root.d.ts +13 -0
- package/dist/trend/root/trend-root.js +14 -9
- package/dist/video/media-events.d.ts +49 -0
- package/dist/video/media-events.js +39 -0
- package/dist/video/root/video-root.d.ts +99 -13
- package/dist/video/root/video-root.js +84 -47
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +3 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +2 -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 +70 -2
- 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 +30 -0
- package/dist/virtual-list/fill.js +39 -0
- package/dist/virtual-list/keys.d.ts +15 -0
- package/dist/virtual-list/keys.js +24 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +155 -23
- package/dist/virtual-list/root/virtual-list-root.js +175 -34
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +8871 -1286
- package/types/svelte.d.ts +3 -0
- package/types/vue.d.ts +1918 -269
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** One visible line of the tree: a value, where it sits, and whether it is open. */
|
|
2
|
+
export interface Row {
|
|
3
|
+
branch: boolean;
|
|
4
|
+
depth: number;
|
|
5
|
+
/** The property name or array index this value is under; absent for the root. */
|
|
6
|
+
key?: string;
|
|
7
|
+
/** Whether its key or its value holds what the tree is filtered by. */
|
|
8
|
+
match: boolean;
|
|
9
|
+
open: boolean;
|
|
10
|
+
path: string;
|
|
11
|
+
position: number;
|
|
12
|
+
siblings: number;
|
|
13
|
+
value: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** Whether a value has entries of its own, an object or an array. */
|
|
16
|
+
export declare const branchy: (value: unknown) => value is object;
|
|
17
|
+
/** A branch's entries, an array's under its indexes. */
|
|
18
|
+
export declare const entries: (value: object) => [string, unknown][];
|
|
19
|
+
/** A child's path under its parent's, escaped the way a JSON Pointer escapes one. */
|
|
20
|
+
export declare const child: (path: string, key: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Every branch a path sits inside, from the root down, and not the path itself.
|
|
23
|
+
*
|
|
24
|
+
* The root's path is the empty string, so every other path has it first. A
|
|
25
|
+
* key's own `/` is escaped as `~1`, so cutting at each `/` cuts between keys.
|
|
26
|
+
*/
|
|
27
|
+
export declare const ancestorsOf: (path: string) => string[];
|
|
28
|
+
/**
|
|
29
|
+
* The paths of every entry whose key or value holds `query`, ignoring case,
|
|
30
|
+
* across the whole value and not only the open branches.
|
|
31
|
+
*
|
|
32
|
+
* A branch is matched by its key alone: its brackets and its count are drawn,
|
|
33
|
+
* and they are not what a reader is looking for.
|
|
34
|
+
*/
|
|
35
|
+
export declare const search: (root: unknown, query: string) => Set<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Every visible row, in order, for a value with `opened` branches open.
|
|
38
|
+
*
|
|
39
|
+
* With `found`, the paths a filter matched, a branch shows only the entries
|
|
40
|
+
* that matched or lead to one, and a matched entry shows everything under it.
|
|
41
|
+
* Position and set size count the entries shown, which is the set a reader
|
|
42
|
+
* hears.
|
|
43
|
+
*/
|
|
44
|
+
export declare const flatten: (root: unknown, opened: Set<string>, found?: Set<string>) => Row[];
|
|
45
|
+
/**
|
|
46
|
+
* Which branches are open for a value, by path.
|
|
47
|
+
*
|
|
48
|
+
* Every branch shallower than `depth` opens. A branch in `known`, the
|
|
49
|
+
* branches of the last value, keeps whether it was in `opened`, so a new value
|
|
50
|
+
* keeps the branches a reader opened or closed and only a new one takes the
|
|
51
|
+
* default. Returns the open branches and every branch, for the next value to
|
|
52
|
+
* be told apart from this one.
|
|
53
|
+
*/
|
|
54
|
+
export declare const seed: (root: unknown, depth: number, known?: Set<string>, opened?: Set<string>) => {
|
|
55
|
+
branches: Set<string>;
|
|
56
|
+
opened: Set<string>;
|
|
57
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HelixElement } from '@fusion.dev/helix-core';
|
|
1
|
+
import { HelixElement, type LinkModifiers } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
/**
|
|
4
4
|
* The options among some elements, reaching one level into a group.
|
|
@@ -34,6 +34,9 @@ export declare const optionsAmong: (elements: readonly Element[]) => HelixHeadle
|
|
|
34
34
|
* Filtering belongs to the owner, which hides an option with `hidden`. What
|
|
35
35
|
* counts as a match differs between a select and a command palette.
|
|
36
36
|
*
|
|
37
|
+
* An option with `href` is a link: choosing it follows the link and selects
|
|
38
|
+
* nothing, as an entry in a command palette that goes to a page does.
|
|
39
|
+
*
|
|
37
40
|
* @since 0.1.0
|
|
38
41
|
* @status stable
|
|
39
42
|
* @category forms
|
|
@@ -44,7 +47,7 @@ export declare const optionsAmong: (elements: readonly Element[]) => HelixHeadle
|
|
|
44
47
|
* @slot end - Content after the label, such as a shortcut or a count.
|
|
45
48
|
* @slot start - Content before the label, such as an icon or an avatar.
|
|
46
49
|
*
|
|
47
|
-
* @event {HelixSelectEvent} helix-select - The option was chosen. Cancelable: canceling it leaves the selection as it was
|
|
50
|
+
* @event {HelixSelectEvent} helix-select - The option was chosen. Cancelable: canceling it leaves the selection as it was, and keeps the browser from following an option's `href`.
|
|
48
51
|
*
|
|
49
52
|
* @csspart description - The description under the label, when there is one.
|
|
50
53
|
* @csspart item - The row.
|
|
@@ -148,6 +151,28 @@ export declare class HelixHeadlessOption extends HelixElement {
|
|
|
148
151
|
* Prevents the option from being chosen.
|
|
149
152
|
*/
|
|
150
153
|
disabled: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Whether following the link downloads what it names. Only meaningful
|
|
156
|
+
* beside an `href`.
|
|
157
|
+
*/
|
|
158
|
+
download: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* The URL the option links to. Setting it makes the option a link: choosing
|
|
161
|
+
* it, with a press, Enter or a click, follows the link and selects nothing,
|
|
162
|
+
* as React Aria's items with `href` do. Command, Control and Shift open it
|
|
163
|
+
* where they open a link, in a new tab or a new window.
|
|
164
|
+
*
|
|
165
|
+
* `helix-select` is said first with the `href` in it, and canceling it keeps
|
|
166
|
+
* the browser from following, so a client-side router follows it instead.
|
|
167
|
+
*
|
|
168
|
+
* **The option stays an option**, and an anchor is never drawn inside it:
|
|
169
|
+
* `role="option"` sits on the host, where a listbox's
|
|
170
|
+
* `aria-activedescendant` can name it, and an `<a>` inside would be exposed
|
|
171
|
+
* as a link within the option and take its name (Menu Item's `href` records
|
|
172
|
+
* the measurement). The link is followed through an anchor made for the
|
|
173
|
+
* moment, which `followLink` describes.
|
|
174
|
+
*/
|
|
175
|
+
href: string;
|
|
151
176
|
/**
|
|
152
177
|
* A shorter name for this choice, for where the row does not fit.
|
|
153
178
|
*
|
|
@@ -161,12 +186,30 @@ export declare class HelixHeadlessOption extends HelixElement {
|
|
|
161
186
|
* nothing for every choice.
|
|
162
187
|
*/
|
|
163
188
|
label: string;
|
|
189
|
+
/**
|
|
190
|
+
* The link's `rel`. Set it whenever you set `target="_blank"`.
|
|
191
|
+
*/
|
|
192
|
+
rel: string;
|
|
164
193
|
/**
|
|
165
194
|
* Whether this choice is currently chosen.
|
|
166
195
|
*
|
|
167
196
|
* Written by the listbox.
|
|
168
197
|
*/
|
|
169
198
|
selected: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* Where the link opens, such as `_blank`, for an option with an `href`.
|
|
201
|
+
*/
|
|
202
|
+
target: string;
|
|
203
|
+
/**
|
|
204
|
+
* The words a reader types to reach this choice, where the row's own words
|
|
205
|
+
* are not them: typeahead, a filter and a combobox match against it, and a
|
|
206
|
+
* select's trigger shows it.
|
|
207
|
+
*
|
|
208
|
+
* For a row whose content is a picture, an avatar beside a name and a role,
|
|
209
|
+
* or a name written in another script, as React Aria's `textValue`. Empty
|
|
210
|
+
* reads the row's words, then `label`.
|
|
211
|
+
*/
|
|
212
|
+
textValue: string;
|
|
170
213
|
/**
|
|
171
214
|
* The value that identifies the option, and that a form submits.
|
|
172
215
|
*/
|
|
@@ -210,11 +253,17 @@ export declare class HelixHeadlessOption extends HelixElement {
|
|
|
210
253
|
* it is in every comparison too.
|
|
211
254
|
*
|
|
212
255
|
* **The `label` where the slot holds nothing**, which is what the row shows
|
|
213
|
-
* then, so the six read the words a reader sees.
|
|
256
|
+
* then, so the six read the words a reader sees. `text-value` wins over both,
|
|
257
|
+
* being the consumer saying outright what the words are.
|
|
214
258
|
*/
|
|
215
259
|
get text(): string;
|
|
216
|
-
/**
|
|
217
|
-
|
|
260
|
+
/**
|
|
261
|
+
* Sends `helix-select` for this option. Does nothing when it is disabled.
|
|
262
|
+
*
|
|
263
|
+
* An option with an `href` then follows its link, unless the event was
|
|
264
|
+
* canceled, with the keys `modifiers` names held.
|
|
265
|
+
*/
|
|
266
|
+
select(modifiers?: LinkModifiers): void;
|
|
218
267
|
/**
|
|
219
268
|
* Mirrors the chosen state where a stylesheet can select on it.
|
|
220
269
|
*
|
|
@@ -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, HelixSelectEvent } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, followLink, HelixElement, HelixSelectEvent, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
export const optionsAmong = (elements) => {
|
|
@@ -18,8 +18,13 @@ let HelixHeadlessOption = class HelixHeadlessOption extends HelixElement {
|
|
|
18
18
|
this.alternate = '';
|
|
19
19
|
this.alternateLabel = '';
|
|
20
20
|
this.disabled = false;
|
|
21
|
+
this.download = false;
|
|
22
|
+
this.href = '';
|
|
21
23
|
this.label = '';
|
|
24
|
+
this.rel = '';
|
|
22
25
|
this.selected = false;
|
|
26
|
+
this.target = '';
|
|
27
|
+
this.textValue = '';
|
|
23
28
|
this.value = '';
|
|
24
29
|
}
|
|
25
30
|
get defaultSelected() {
|
|
@@ -29,17 +34,26 @@ let HelixHeadlessOption = class HelixHeadlessOption extends HelixElement {
|
|
|
29
34
|
this.toggleAttribute('selected', next);
|
|
30
35
|
}
|
|
31
36
|
get text() {
|
|
37
|
+
if (this.textValue !== '') {
|
|
38
|
+
return this.textValue;
|
|
39
|
+
}
|
|
32
40
|
return ([...this.childNodes]
|
|
33
41
|
.filter((node) => node.nodeType === Node.TEXT_NODE || (node instanceof Element && node.slot === ''))
|
|
34
42
|
.map((node) => node.textContent ?? '')
|
|
35
43
|
.join('')
|
|
36
44
|
.trim() || this.label);
|
|
37
45
|
}
|
|
38
|
-
select() {
|
|
46
|
+
select(modifiers) {
|
|
39
47
|
if (this.disabled) {
|
|
40
48
|
return;
|
|
41
49
|
}
|
|
42
|
-
|
|
50
|
+
if (this.href === '') {
|
|
51
|
+
this.dispatchEvent(new HelixSelectEvent({ value: this.value }));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (this.dispatchEvent(new HelixSelectEvent({ href: this.href, value: this.value }))) {
|
|
55
|
+
followLink(this.ownerDocument, this, modifiers);
|
|
56
|
+
}
|
|
43
57
|
}
|
|
44
58
|
willUpdate(changed) {
|
|
45
59
|
super.willUpdate(changed);
|
|
@@ -48,13 +62,13 @@ let HelixHeadlessOption = class HelixHeadlessOption extends HelixElement {
|
|
|
48
62
|
}
|
|
49
63
|
render() {
|
|
50
64
|
this.internals.role = 'option';
|
|
51
|
-
this.internals.ariaSelected = String(this.selected);
|
|
65
|
+
this.internals.ariaSelected = this.href === '' ? String(this.selected) : null;
|
|
52
66
|
this.internals.ariaDisabled = this.disabled ? 'true' : null;
|
|
53
67
|
this.internals.ariaDescription =
|
|
54
68
|
this.alternate !== '' && this.alternateLabel !== '' ? this.alternateLabel : null;
|
|
55
69
|
return html `<div
|
|
56
70
|
part="item${this.selected ? ' item-selected' : ''}${this.active ? ' item-active' : ''}"
|
|
57
|
-
@click=${() => this.select()}
|
|
71
|
+
@click=${(event) => this.select(event)}
|
|
58
72
|
>
|
|
59
73
|
<slot name="start"></slot>
|
|
60
74
|
<span part="text">
|
|
@@ -80,12 +94,27 @@ __decorate([
|
|
|
80
94
|
__decorate([
|
|
81
95
|
property({ reflect: true, type: Boolean })
|
|
82
96
|
], HelixHeadlessOption.prototype, "disabled", void 0);
|
|
97
|
+
__decorate([
|
|
98
|
+
property({ type: Boolean })
|
|
99
|
+
], HelixHeadlessOption.prototype, "download", void 0);
|
|
100
|
+
__decorate([
|
|
101
|
+
property()
|
|
102
|
+
], HelixHeadlessOption.prototype, "href", void 0);
|
|
83
103
|
__decorate([
|
|
84
104
|
property()
|
|
85
105
|
], HelixHeadlessOption.prototype, "label", void 0);
|
|
106
|
+
__decorate([
|
|
107
|
+
property()
|
|
108
|
+
], HelixHeadlessOption.prototype, "rel", void 0);
|
|
86
109
|
__decorate([
|
|
87
110
|
property({ type: Boolean })
|
|
88
111
|
], HelixHeadlessOption.prototype, "selected", void 0);
|
|
112
|
+
__decorate([
|
|
113
|
+
property()
|
|
114
|
+
], HelixHeadlessOption.prototype, "target", void 0);
|
|
115
|
+
__decorate([
|
|
116
|
+
property({ attribute: 'text-value' })
|
|
117
|
+
], HelixHeadlessOption.prototype, "textValue", void 0);
|
|
89
118
|
__decorate([
|
|
90
119
|
property()
|
|
91
120
|
], HelixHeadlessOption.prototype, "value", void 0);
|
|
@@ -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,12 @@ 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`.
|
|
17
22
|
*
|
|
18
23
|
* The current section is decided by the headings' positions. An
|
|
19
24
|
* `IntersectionObserver` with a band near the top fails both ways: when
|
|
@@ -27,13 +32,24 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
27
32
|
* @documentation https://fusion.dev/helix/components/outline
|
|
28
33
|
*
|
|
29
34
|
* @slot - The links, as anchors with fragment hrefs, or lists holding them.
|
|
35
|
+
* @slot heading - A heading above the links, such as "On this page". It names the navigation.
|
|
30
36
|
*
|
|
31
37
|
* @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
38
|
*
|
|
39
|
+
* @csspart heading - The box holding the `heading` slot, above the navigation.
|
|
33
40
|
* @csspart indicator - The mark that moves to the section in view.
|
|
34
41
|
* @csspart nav - The navigation landmark.
|
|
35
42
|
*/
|
|
36
43
|
export declare class HelixHeadlessOutline extends HelixElement {
|
|
44
|
+
/**
|
|
45
|
+
* Manual, so each link in a flat run can be put in a list item of its own.
|
|
46
|
+
*
|
|
47
|
+
* The list items are slots, which lay out as nothing at all, so each link is
|
|
48
|
+
* still laid out as a child of the navigation exactly where it was, and the
|
|
49
|
+
* consumer's markup is not touched. A run holding anything but links, a
|
|
50
|
+
* `<ul>` among them, goes to one plain slot as before.
|
|
51
|
+
*/
|
|
52
|
+
static shadowRootOptions: ShadowRootInit;
|
|
37
53
|
private readonly indicator;
|
|
38
54
|
/**
|
|
39
55
|
* How the page scrolls to a section when its link is clicked.
|
|
@@ -58,7 +74,8 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
58
74
|
*/
|
|
59
75
|
behavior: ScrollBehavior;
|
|
60
76
|
/**
|
|
61
|
-
* The navigation's name, read by screen readers.
|
|
77
|
+
* The navigation's name, read by screen readers. A heading in the `heading`
|
|
78
|
+
* slot names it in place of this.
|
|
62
79
|
*/
|
|
63
80
|
label: string;
|
|
64
81
|
/**
|
|
@@ -92,6 +109,11 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
92
109
|
*/
|
|
93
110
|
private reading;
|
|
94
111
|
private observer;
|
|
112
|
+
/**
|
|
113
|
+
* Watches the children, which a manual root is not told about: a link
|
|
114
|
+
* arriving, leaving or changing its level changes the lists drawn for them.
|
|
115
|
+
*/
|
|
116
|
+
private childWatch;
|
|
95
117
|
/**
|
|
96
118
|
* The links, in document order. Empty on the server, which has no tree.
|
|
97
119
|
*
|
|
@@ -101,6 +123,18 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
101
123
|
* nothing was announced, and nothing said why.
|
|
102
124
|
*/
|
|
103
125
|
private get links();
|
|
126
|
+
/** The children that are the content, which is all of them but the heading. */
|
|
127
|
+
private get content();
|
|
128
|
+
/**
|
|
129
|
+
* The links of a flat run, which the render puts into lists, or `undefined`
|
|
130
|
+
* where the content is anything else.
|
|
131
|
+
*
|
|
132
|
+
* Anything else is a list a consumer wrote, which already has its levels, a
|
|
133
|
+
* slot forwarded from a component around this one, or a server's render and
|
|
134
|
+
* the hydration of one, which cannot know the children. A root a server sent
|
|
135
|
+
* routes by name, so it keeps the plain slot after hydration too.
|
|
136
|
+
*/
|
|
137
|
+
private get run();
|
|
104
138
|
/**
|
|
105
139
|
* What each link points at, paired with the link, skipping anything missing.
|
|
106
140
|
*
|
|
@@ -250,8 +284,39 @@ export declare class HelixHeadlessOutline extends HelixElement {
|
|
|
250
284
|
private unland;
|
|
251
285
|
connectedCallback(): void;
|
|
252
286
|
protected firstUpdated(changed: PropertyValues): void;
|
|
287
|
+
/**
|
|
288
|
+
* Puts each child in its slot, on a root this element made.
|
|
289
|
+
*
|
|
290
|
+
* A link of a flat run goes to the slot inside its list item, and anything
|
|
291
|
+
* else, with the text between, to the plain slot. A root a server sent
|
|
292
|
+
* routes by name and needs none of it.
|
|
293
|
+
*/
|
|
294
|
+
private assign;
|
|
295
|
+
/** Whether the heading is what names the navigation. */
|
|
296
|
+
private namedByHeading;
|
|
297
|
+
/**
|
|
298
|
+
* Names the navigation by what is in the `heading` slot, in place of `label`.
|
|
299
|
+
*
|
|
300
|
+
* An element reference, because the heading is in the light DOM and the
|
|
301
|
+
* `<nav>` in this shadow root, which an IDREF cannot cross. A browser without
|
|
302
|
+
* element reflection keeps `label`.
|
|
303
|
+
*/
|
|
304
|
+
private readonly nameByHeading;
|
|
253
305
|
protected updated(changed: PropertyValues): void;
|
|
254
306
|
protected render(): TemplateResult;
|
|
307
|
+
/**
|
|
308
|
+
* A list for a run of links, with a list item for each, nested by level.
|
|
309
|
+
*
|
|
310
|
+
* **Slots, because a slot lays out as nothing.** A list and its items drawn
|
|
311
|
+
* as boxes would put each link inside an item, out of the navigation's own
|
|
312
|
+
* flex column, and every outline styled against that column would move. A
|
|
313
|
+
* slot is `display: contents`, keeps a role it is given, and shows its
|
|
314
|
+
* children while nothing is assigned to it, so the items nest in the
|
|
315
|
+
* accessibility tree and nowhere else. Measured in Chromium: every link at the
|
|
316
|
+
* same box with and without the lists, and each item at the level its
|
|
317
|
+
* nesting gives it.
|
|
318
|
+
*/
|
|
319
|
+
protected renderList(branches: Branch[]): TemplateResult;
|
|
255
320
|
}
|
|
256
321
|
declare global {
|
|
257
322
|
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, reflectElements, } 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);
|
|
@@ -72,16 +74,38 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
72
74
|
this.watch();
|
|
73
75
|
this.indicator.place();
|
|
74
76
|
};
|
|
77
|
+
this.namedByHeading = false;
|
|
78
|
+
this.nameByHeading = () => {
|
|
79
|
+
const slot = this.renderRoot?.querySelector?.('slot[name="heading"]');
|
|
80
|
+
this.namedByHeading = reflectElements(this.partNamed('nav'), 'ariaLabelledByElements', slot?.assignedElements({ flatten: true }) ?? [], this.namedByHeading);
|
|
81
|
+
};
|
|
75
82
|
}
|
|
83
|
+
static { this.shadowRootOptions = {
|
|
84
|
+
...HelixElement.shadowRootOptions,
|
|
85
|
+
slotAssignment: 'manual',
|
|
86
|
+
}; }
|
|
76
87
|
get current() {
|
|
77
88
|
return this.reading;
|
|
78
89
|
}
|
|
79
90
|
get links() {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
const slots = [
|
|
92
|
+
...(this.renderRoot?.querySelectorAll?.('slot[data-link], nav > slot:not([role])') ?? []),
|
|
93
|
+
];
|
|
94
|
+
return slots
|
|
95
|
+
.flatMap((slot) => slot.assignedElements({ flatten: true }))
|
|
96
|
+
.flatMap((element) => isFragment(element)
|
|
83
97
|
? [element]
|
|
84
|
-
: [...element.querySelectorAll('a[href^="#"]')].filter(
|
|
98
|
+
: [...element.querySelectorAll('a[href^="#"]')].filter(isFragment));
|
|
99
|
+
}
|
|
100
|
+
get content() {
|
|
101
|
+
return this.knownChildren.filter((child) => child.slot !== 'heading');
|
|
102
|
+
}
|
|
103
|
+
get run() {
|
|
104
|
+
const content = this.content;
|
|
105
|
+
if (this.assignsByName || content.length === 0 || !content.every(isFragment)) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
return content;
|
|
85
109
|
}
|
|
86
110
|
get sections() {
|
|
87
111
|
return this.links.flatMap((link) => {
|
|
@@ -163,6 +187,8 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
163
187
|
}
|
|
164
188
|
disconnectedCallback() {
|
|
165
189
|
super.disconnectedCallback();
|
|
190
|
+
this.childWatch?.disconnect();
|
|
191
|
+
this.childWatch = undefined;
|
|
166
192
|
this.removeEventListener('click', this.handleClick);
|
|
167
193
|
document.removeEventListener('scroll', this.handleScroll, true);
|
|
168
194
|
if (this.frame !== 0) {
|
|
@@ -183,6 +209,12 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
183
209
|
}
|
|
184
210
|
connectedCallback() {
|
|
185
211
|
super.connectedCallback();
|
|
212
|
+
this.childWatch = new MutationObserver(() => this.requestUpdate());
|
|
213
|
+
this.childWatch.observe(this, {
|
|
214
|
+
attributeFilter: ['data-level', 'href', 'slot'],
|
|
215
|
+
childList: true,
|
|
216
|
+
subtree: true,
|
|
217
|
+
});
|
|
186
218
|
this.addEventListener('click', this.handleClick);
|
|
187
219
|
document.addEventListener('scroll', this.handleScroll, {
|
|
188
220
|
capture: true,
|
|
@@ -195,9 +227,32 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
195
227
|
firstUpdated(changed) {
|
|
196
228
|
super.firstUpdated(changed);
|
|
197
229
|
this.watch();
|
|
230
|
+
this.finishHydration();
|
|
231
|
+
}
|
|
232
|
+
assign() {
|
|
233
|
+
if (this.assignsByName) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const root = this.renderRoot;
|
|
237
|
+
const heading = root?.querySelector?.('slot[name="heading"]');
|
|
238
|
+
heading?.assign?.(...this.knownChildren.filter((child) => child.slot === 'heading'));
|
|
239
|
+
const run = this.run;
|
|
240
|
+
if (run) {
|
|
241
|
+
for (const slot of root?.querySelectorAll?.('slot[data-link]') ?? []) {
|
|
242
|
+
const link = run[Number(slot.dataset.link)];
|
|
243
|
+
if (link) {
|
|
244
|
+
slot.assign(link);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const plain = root?.querySelector?.('nav > slot:not([role])');
|
|
250
|
+
plain?.assign?.(...[...this.childNodes].filter((node) => node instanceof Element ? node.slot !== 'heading' : node instanceof Text));
|
|
198
251
|
}
|
|
199
252
|
updated(changed) {
|
|
200
253
|
super.updated(changed);
|
|
254
|
+
this.assign();
|
|
255
|
+
this.nameByHeading();
|
|
201
256
|
if (changed.has('offset')) {
|
|
202
257
|
this.reach();
|
|
203
258
|
this.mark();
|
|
@@ -208,11 +263,21 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
208
263
|
this.indicator.place();
|
|
209
264
|
}
|
|
210
265
|
render() {
|
|
211
|
-
|
|
212
|
-
|
|
266
|
+
const run = this.run;
|
|
267
|
+
return html `<div part="heading"><slot name="heading" @slotchange=${this.nameByHeading}></slot></div>
|
|
268
|
+
<nav part="nav" aria-label=${this.label} @slotchange=${this.handleSlotChange}>
|
|
269
|
+
${run ? this.renderList(nest(run.map((link) => levelOf(link.getAttribute('data-level'))))) : html `<slot></slot>`}
|
|
213
270
|
<span part="indicator" aria-hidden="true"></span>
|
|
214
271
|
</nav>`;
|
|
215
272
|
}
|
|
273
|
+
renderList(branches) {
|
|
274
|
+
return html `<slot role="list"
|
|
275
|
+
>${branches.map((branch) => html `<slot role="listitem"
|
|
276
|
+
><slot data-link=${branch.index}></slot
|
|
277
|
+
>${branch.children.length > 0 ? this.renderList(branch.children) : nothing}</slot
|
|
278
|
+
>`)}</slot
|
|
279
|
+
>`;
|
|
280
|
+
}
|
|
216
281
|
};
|
|
217
282
|
__decorate([
|
|
218
283
|
property()
|