@fusion.dev/helix-headless 0.142.1 → 0.144.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +25381 -1202
- package/dist/accordion/item/accordion-item.d.ts +38 -2
- package/dist/accordion/item/accordion-item.js +38 -6
- package/dist/accordion/root/accordion-root.d.ts +23 -1
- package/dist/accordion/root/accordion-root.js +39 -3
- package/dist/announcement/root/announcement-root.d.ts +11 -7
- package/dist/announcement/root/announcement-root.js +1 -1
- package/dist/app-header/root/app-header-root.d.ts +21 -0
- package/dist/app-header/root/app-header-root.js +31 -5
- package/dist/area-chart/root/area-chart-root.d.ts +12 -4
- package/dist/area-chart/root/area-chart-root.js +39 -11
- package/dist/avatar/group/avatar-group.d.ts +24 -3
- package/dist/avatar/group/avatar-group.js +34 -2
- package/dist/avatar/root/avatar-root.d.ts +17 -1
- package/dist/avatar/root/avatar-root.js +31 -10
- package/dist/badge/root/badge-root.d.ts +12 -0
- package/dist/badge/root/badge-root.js +1 -1
- package/dist/bar-chart/root/bar-chart-root.d.ts +30 -5
- package/dist/bar-chart/root/bar-chart-root.js +58 -21
- package/dist/blockquote/root/blockquote-root.d.ts +12 -7
- package/dist/blockquote/root/blockquote-root.js +6 -4
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
- package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
- package/dist/button/root/button-root.d.ts +84 -1
- package/dist/button/root/button-root.js +81 -3
- package/dist/callout/root/callout-root.d.ts +32 -6
- package/dist/callout/root/callout-root.js +26 -7
- package/dist/canvas/root/canvas-root.d.ts +1 -0
- package/dist/canvas/root/canvas-root.js +10 -1
- 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 +47 -5
- package/dist/carousel/root/carousel-root.js +53 -21
- package/dist/chat/composer/chat-composer.d.ts +13 -11
- package/dist/chat/composer/chat-composer.js +6 -12
- package/dist/chat/message/chat-message.js +8 -1
- package/dist/chat/root/chat-root.d.ts +1 -0
- package/dist/chat/root/chat-root.js +2 -1
- package/dist/checkbox/root/checkbox-root.d.ts +7 -0
- package/dist/checkbox/root/checkbox-root.js +9 -3
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +116 -33
- package/dist/checkbox-group/root/checkbox-group-root.js +141 -44
- package/dist/code/root/code-root.d.ts +1 -1
- 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 +49 -0
- package/dist/code-block/root/code-block-root.js +44 -3
- package/dist/color-input/root/color-input-root.d.ts +60 -2
- package/dist/color-input/root/color-input-root.js +55 -7
- 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 +118 -12
- package/dist/color-picker/root/color-picker-root.js +183 -13
- package/dist/combobox/root/combobox-root.d.ts +126 -3
- package/dist/combobox/root/combobox-root.js +224 -21
- package/dist/command/root/command-root.d.ts +47 -10
- package/dist/command/root/command-root.js +45 -4
- 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 +48 -7
- package/dist/copy-button/root/copy-button-root.js +54 -8
- package/dist/data-table/root/data-table-root.d.ts +164 -10
- package/dist/data-table/root/data-table-root.js +488 -57
- package/dist/date-input/root/date-input-root.d.ts +123 -9
- package/dist/date-input/root/date-input-root.js +147 -45
- package/dist/date-picker/root/date-picker-root.d.ts +229 -18
- package/dist/date-picker/root/date-picker-root.js +342 -46
- package/dist/dialog/description.d.ts +9 -0
- package/dist/dialog/description.js +14 -0
- package/dist/dialog/root/dialog-root.d.ts +101 -10
- package/dist/dialog/root/dialog-root.js +83 -4
- package/dist/donut-chart/root/donut-chart-root.d.ts +61 -16
- package/dist/donut-chart/root/donut-chart-root.js +48 -13
- package/dist/drawer/root/drawer-root.d.ts +93 -7
- package/dist/drawer/root/drawer-root.js +126 -5
- 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 +16 -13
- package/dist/drilldown/item/drilldown-item.js +6 -2
- package/dist/drilldown/root/drilldown-root.d.ts +21 -5
- package/dist/drilldown/root/drilldown-root.js +26 -10
- package/dist/element-events.generated.js +42 -13
- package/dist/empty/root/empty-root.d.ts +1 -1
- package/dist/file-input/root/file-input-root.d.ts +65 -1
- package/dist/file-input/root/file-input-root.js +76 -12
- 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 +9 -0
- package/dist/filter-input/menu/filter-menu.js +8 -0
- package/dist/filter-input/root/filter-input-root.d.ts +43 -6
- package/dist/filter-input/root/filter-input-root.js +89 -10
- 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 +62 -3
- package/dist/format-date/root/format-date-root.js +78 -37
- package/dist/graph/root/graph-root.d.ts +24 -3
- package/dist/graph/root/graph-root.js +66 -12
- package/dist/heatmap/root/buckets.d.ts +2 -1
- package/dist/heatmap/root/buckets.js +5 -1
- package/dist/heatmap/root/heatmap-root.d.ts +47 -9
- package/dist/heatmap/root/heatmap-root.js +46 -18
- 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 +53 -6
- package/dist/icon/root/icon-root.js +72 -4
- 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/icon-button/root/icon-button-root.d.ts +1 -1
- package/dist/image/root/image-root.d.ts +23 -2
- package/dist/image/root/image-root.js +23 -4
- package/dist/input/root/input-root.d.ts +62 -9
- package/dist/input/root/input-root.js +61 -5
- package/dist/kbd/root/kbd-root.d.ts +26 -11
- package/dist/kbd/root/kbd-root.js +35 -38
- 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 +63 -0
- package/dist/legend/root/legend-root.js +61 -7
- package/dist/lightbox/item/lightbox-item.d.ts +17 -1
- package/dist/lightbox/item/lightbox-item.js +10 -1
- package/dist/lightbox/root/lightbox-root.d.ts +77 -6
- package/dist/lightbox/root/lightbox-root.js +116 -5
- package/dist/line-chart/root/line-chart-root.d.ts +29 -4
- package/dist/line-chart/root/line-chart-root.js +58 -17
- package/dist/list/item/list-item.d.ts +11 -5
- package/dist/list/item/list-item.js +5 -6
- package/dist/listbox/range.d.ts +17 -0
- package/dist/listbox/range.js +5 -0
- package/dist/listbox/root/listbox-root.d.ts +184 -4
- package/dist/listbox/root/listbox-root.js +229 -23
- 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 +19 -4
- package/dist/map/root/map-root.js +36 -7
- package/dist/megamenu/root/megamenu-root.d.ts +10 -1
- package/dist/megamenu/root/megamenu-root.js +10 -1
- package/dist/menu/item/menu-item.d.ts +41 -12
- package/dist/menu/item/menu-item.js +46 -3
- package/dist/menu/root/menu-root.d.ts +32 -2
- package/dist/menu/root/menu-root.js +48 -8
- package/dist/meter/root/meter-root.d.ts +13 -0
- package/dist/meter/root/meter-root.js +24 -5
- package/dist/navigation/root/navigation-root.d.ts +10 -2
- package/dist/navigation/root/navigation-root.js +13 -2
- package/dist/notifications/feed-keys.d.ts +10 -0
- package/dist/notifications/feed-keys.js +14 -0
- package/dist/notifications/group/notification-group.d.ts +1 -0
- package/dist/notifications/notification/notification.d.ts +29 -0
- package/dist/notifications/notification/notification.js +51 -3
- package/dist/notifications/root/notifications-root.d.ts +49 -0
- package/dist/notifications/root/notifications-root.js +76 -2
- package/dist/number-input/root/number-input-root.d.ts +109 -7
- package/dist/number-input/root/number-input-root.js +109 -21
- package/dist/object-inspector/root/object-inspector-root.d.ts +49 -5
- package/dist/object-inspector/root/object-inspector-root.js +92 -12
- package/dist/option/root/option-root.d.ts +58 -6
- package/dist/option/root/option-root.js +35 -5
- package/dist/outline/root/outline-root.d.ts +13 -2
- package/dist/outline/root/outline-root.js +4 -2
- package/dist/pagination/root/pagination-root.d.ts +19 -1
- package/dist/pagination/root/pagination-root.js +49 -9
- package/dist/pagination/size/pagination-size.d.ts +13 -3
- package/dist/pagination/size/pagination-size.js +7 -0
- 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 +37 -0
- package/dist/pin-input/root/pin-input-root.js +48 -7
- package/dist/popover/root/popover-root.d.ts +78 -3
- package/dist/popover/root/popover-root.js +74 -5
- package/dist/progress/root/progress-root.d.ts +23 -1
- package/dist/progress/root/progress-root.js +40 -10
- 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 +45 -0
- package/dist/qr-code/root/qr-code-root.js +78 -3
- package/dist/radio/group/radio-group.d.ts +64 -0
- package/dist/radio/group/radio-group.js +66 -12
- package/dist/radio/root/radio-root.d.ts +8 -5
- package/dist/radio/root/radio-root.js +1 -2
- package/dist/rating/root/rating-root.d.ts +49 -1
- package/dist/rating/root/rating-root.js +69 -10
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
- package/dist/scatter-chart/root/scatter-chart-root.js +40 -14
- package/dist/select/root/select-root.d.ts +93 -3
- package/dist/select/root/select-root.js +111 -13
- package/dist/skeleton/root/skeleton-root.d.ts +39 -3
- package/dist/skeleton/root/skeleton-root.js +33 -4
- package/dist/skip-link/root/skip-link-root.d.ts +10 -0
- package/dist/skip-link/root/skip-link-root.js +15 -1
- package/dist/slider/root/slider-root.d.ts +59 -2
- package/dist/slider/root/slider-root.js +82 -8
- package/dist/sparkline/root/sparkline-root.d.ts +9 -10
- package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
- package/dist/speed-dial/item/speed-dial-item.js +7 -2
- package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
- package/dist/speed-dial/root/speed-dial-root.js +19 -5
- package/dist/splitter/root/splitter-root.d.ts +28 -6
- package/dist/splitter/root/splitter-root.js +35 -1
- package/dist/stat/root/stat-root.d.ts +9 -1
- package/dist/stat/root/stat-root.js +15 -2
- package/dist/steps/root/steps-root.js +1 -1
- package/dist/steps/step/step.d.ts +1 -0
- package/dist/steps/step/step.js +1 -1
- package/dist/switch/root/switch-root.d.ts +14 -2
- package/dist/switch/root/switch-root.js +7 -1
- package/dist/table/cell/table-cell.d.ts +24 -4
- package/dist/table/cell/table-cell.js +21 -1
- package/dist/table/column/table-column.d.ts +32 -6
- package/dist/table/column/table-column.js +36 -6
- package/dist/table/root/table-root.d.ts +94 -3
- package/dist/table/root/table-root.js +128 -5
- package/dist/table/row/table-row.d.ts +7 -0
- package/dist/table/row/table-row.js +9 -1
- package/dist/tabs/root/tabs-root.d.ts +6 -1
- package/dist/tabs/root/tabs-root.js +6 -2
- 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 +83 -1
- package/dist/tag/root/tag-root.js +87 -17
- 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 +13 -0
- package/dist/textarea/root/textarea-root.js +10 -2
- package/dist/time-input/root/time-input-root.d.ts +71 -6
- package/dist/time-input/root/time-input-root.js +110 -44
- package/dist/time-picker/root/time-picker-root.d.ts +155 -26
- package/dist/time-picker/root/time-picker-root.js +192 -63
- package/dist/toast/hotkey.d.ts +22 -0
- package/dist/toast/hotkey.js +23 -0
- package/dist/toast/item/toast-item.d.ts +16 -1
- package/dist/toast/item/toast-item.js +41 -13
- package/dist/toast/root/toast-root.d.ts +105 -8
- package/dist/toast/root/toast-root.js +209 -4
- package/dist/toggle/group/toggle-group.d.ts +95 -16
- package/dist/toggle/group/toggle-group.js +99 -13
- package/dist/toggle/root/toggle-root.d.ts +26 -11
- package/dist/toggle/root/toggle-root.js +14 -6
- package/dist/toolbar/root/toolbar-root.d.ts +55 -15
- package/dist/toolbar/root/toolbar-root.js +99 -16
- 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 +73 -15
- package/dist/tooltip/root/tooltip-root.js +96 -7
- package/dist/tour/naming.d.ts +30 -0
- package/dist/tour/naming.js +10 -0
- package/dist/tour/root/tour-root.d.ts +67 -3
- package/dist/tour/root/tour-root.js +105 -17
- package/dist/tour/stop/tour-stop.d.ts +65 -3
- package/dist/tour/stop/tour-stop.js +61 -11
- package/dist/tour/wait.d.ts +11 -0
- package/dist/tour/wait.js +19 -0
- package/dist/tree/item/tree-item.d.ts +21 -5
- package/dist/tree/item/tree-item.js +14 -4
- package/dist/tree/root/tree-root.d.ts +29 -5
- package/dist/tree/root/tree-root.js +64 -8
- package/dist/trend/root/trend-root.d.ts +36 -1
- package/dist/trend/root/trend-root.js +41 -15
- package/dist/video/root/keys.d.ts +5 -0
- package/dist/video/root/keys.js +13 -1
- package/dist/video/root/video-root.d.ts +19 -0
- package/dist/video/root/video-root.js +48 -4
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
- package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
- package/dist/video-playlist/root/video-playlist-root.js +6 -3
- package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
- package/dist/virtual-list/root/virtual-list-root.js +103 -21
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +9140 -1149
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +2089 -267
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HelixElement } from '@fusion.dev/helix-core';
|
|
1
|
+
import { AriaForwardController, HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
declare const HelixHeadlessTree_base: (new (...args: any[]) => import("@fusion.dev/helix-core").CollectionElement) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerActiveInterface) & typeof HelixElement;
|
|
4
4
|
/**
|
|
@@ -13,6 +13,9 @@ declare const HelixHeadlessTree_base: (new (...args: any[]) => import("@fusion.d
|
|
|
13
13
|
* Items are found with `instanceof`, never by tag name, so the headless tier
|
|
14
14
|
* does not depend on the styled one.
|
|
15
15
|
*
|
|
16
|
+
* Typing a letter moves to the next visible item whose name starts with it,
|
|
17
|
+
* and `*` opens every branch beside the focused item.
|
|
18
|
+
*
|
|
16
19
|
* @since 0.1.0
|
|
17
20
|
* @status stable
|
|
18
21
|
* @category navigation
|
|
@@ -33,8 +36,15 @@ declare const HelixHeadlessTree_base: (new (...args: any[]) => import("@fusion.d
|
|
|
33
36
|
export declare class HelixHeadlessTree extends HelixHeadlessTree_base {
|
|
34
37
|
/**
|
|
35
38
|
* Accessible name for the tree.
|
|
39
|
+
*
|
|
40
|
+
* An `aria-label` or `aria-labelledby` on the host names the tree too, and
|
|
41
|
+
* wins over this.
|
|
36
42
|
*/
|
|
37
43
|
label: string;
|
|
44
|
+
/** Carries a host `aria-label` and `aria-labelledby` to the tree. */
|
|
45
|
+
protected readonly aria: AriaForwardController;
|
|
46
|
+
/** The letters typed so far, for moving to an item by its name. */
|
|
47
|
+
private readonly typeahead;
|
|
38
48
|
/**
|
|
39
49
|
* What a deeper level means: `peer` for no change, `subordinate` for a lower
|
|
40
50
|
* rank, or `heading` for a parent that heads the items under it.
|
|
@@ -98,16 +108,30 @@ export declare class HelixHeadlessTree extends HelixHeadlessTree_base {
|
|
|
98
108
|
* so an item moved in the tree gets the right indent without knowing it moved.
|
|
99
109
|
*/
|
|
100
110
|
private syncItems;
|
|
111
|
+
/** The nearest item around `item` that a reader can see, if any. */
|
|
112
|
+
private visibleAncestor;
|
|
113
|
+
/**
|
|
114
|
+
* Moves to the next visible item whose name starts with the letters typed,
|
|
115
|
+
* or opens every branch beside the focused item on `*`.
|
|
116
|
+
*
|
|
117
|
+
* Returns whether the press was one of those.
|
|
118
|
+
*/
|
|
119
|
+
private handleTyping;
|
|
101
120
|
private move;
|
|
102
121
|
private focusOn;
|
|
103
122
|
private readonly handleKeydown;
|
|
104
123
|
/**
|
|
105
124
|
* A branch opened or closed, whoever did it.
|
|
106
125
|
*
|
|
107
|
-
* Listening for the item's own
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
126
|
+
* Listening for the item's own `toggle` rather than calling `syncItems` from
|
|
127
|
+
* each keyboard path: that misses the pointer, and collapsing a branch by
|
|
128
|
+
* clicking its row then left the tree's one tab stop on a row inside the
|
|
129
|
+
* subtree just hidden, so Tab passed over the tree. It also covers a
|
|
130
|
+
* consumer setting `open` directly.
|
|
131
|
+
*
|
|
132
|
+
* **In capture**, because `toggle` does not bubble, which is the platform's
|
|
133
|
+
* shape for it. The `helix-before-*` pair this listened for does not bubble
|
|
134
|
+
* either, and is sent before the branch has moved.
|
|
111
135
|
*/
|
|
112
136
|
private readonly handleBranch;
|
|
113
137
|
connectedCallback(): void;
|
|
@@ -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 { closestInstance, customElement, HelixElement, inlineStep, MixinCollection, MixinControllerActive, scrollItemIntoView, whenHydrated, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, closestInstance, customElement, HelixElement, inlineStep, keyClaimed, MixinCollection, MixinControllerActive, scrollItemIntoView, slottedWords, Typeahead, typesCharacter, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessTreeItem } from '../item/tree-item.js';
|
|
@@ -22,7 +22,16 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
22
22
|
constructor() {
|
|
23
23
|
super(...arguments);
|
|
24
24
|
this.label = 'Tree';
|
|
25
|
+
this.aria = new AriaForwardController(this, {
|
|
26
|
+
label: true,
|
|
27
|
+
target: () => this.partNamed('tree'),
|
|
28
|
+
});
|
|
29
|
+
this.typeahead = new Typeahead();
|
|
25
30
|
this.handleSelection = (event) => {
|
|
31
|
+
const origin = event.target;
|
|
32
|
+
if (!(origin instanceof HelixHeadlessTreeItem) || !this.items.includes(origin)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
26
35
|
if (!event.defaultPrevented) {
|
|
27
36
|
this.requestActive(event.detail.value);
|
|
28
37
|
}
|
|
@@ -30,9 +39,17 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
30
39
|
};
|
|
31
40
|
this.handleKeydown = (event) => {
|
|
32
41
|
const current = closestInstance(event.target, HelixHeadlessTreeItem);
|
|
33
|
-
if (!current || !this.items.includes(current)
|
|
42
|
+
if (!current || !this.items.includes(current)) {
|
|
34
43
|
return;
|
|
35
44
|
}
|
|
45
|
+
if (this.handleTyping(current, event)) {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (!KEYS.has(event.key)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.typeahead.reset();
|
|
36
53
|
const along = inlineStep(this, event.key);
|
|
37
54
|
if (event.key === 'ArrowDown') {
|
|
38
55
|
this.move(current, 1);
|
|
@@ -67,6 +84,9 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
67
84
|
}
|
|
68
85
|
else {
|
|
69
86
|
if (current.isBranch) {
|
|
87
|
+
if (current.choosable) {
|
|
88
|
+
current.select();
|
|
89
|
+
}
|
|
70
90
|
current.toggleOpen();
|
|
71
91
|
this.syncItems();
|
|
72
92
|
}
|
|
@@ -98,8 +118,10 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
98
118
|
syncItems() {
|
|
99
119
|
const visible = this.visibleItems;
|
|
100
120
|
const chosen = this.resolveActive(visible);
|
|
101
|
-
const held = visible.find((item) => item.focusable)
|
|
121
|
+
const held = visible.find((item) => item.focusable) ??
|
|
122
|
+
this.visibleAncestor(this.items.find((item) => item.focusable));
|
|
102
123
|
const stop = held ?? chosen;
|
|
124
|
+
const heads = this.nesting === 'heading';
|
|
103
125
|
for (const item of this.items) {
|
|
104
126
|
const selected = item.value !== '' && item.value === this.active;
|
|
105
127
|
const focusable = item === stop;
|
|
@@ -115,9 +137,45 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
115
137
|
item.selected = selected;
|
|
116
138
|
item.focusable = focusable;
|
|
117
139
|
item.level = level;
|
|
140
|
+
item.heads = heads;
|
|
118
141
|
});
|
|
119
142
|
}
|
|
120
143
|
}
|
|
144
|
+
visibleAncestor(item) {
|
|
145
|
+
const visible = this.visibleItems;
|
|
146
|
+
let node = item?.parentElement ?? null;
|
|
147
|
+
while (node && node !== this) {
|
|
148
|
+
if (node instanceof HelixHeadlessTreeItem && visible.includes(node)) {
|
|
149
|
+
return node;
|
|
150
|
+
}
|
|
151
|
+
node = node.parentElement;
|
|
152
|
+
}
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
handleTyping(current, event) {
|
|
156
|
+
if (!typesCharacter(event) || keyClaimed(event)) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
if (event.key === ' ' && !this.typeahead.typing()) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
if (event.key === '*') {
|
|
163
|
+
const siblings = [...(current.parentElement?.children ?? [])].filter((node) => node instanceof HelixHeadlessTreeItem && node.slot === current.slot);
|
|
164
|
+
for (const sibling of siblings) {
|
|
165
|
+
if (sibling.isBranch && !sibling.open) {
|
|
166
|
+
sibling.requestOpen(true);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
this.syncItems();
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
const visible = this.visibleItems;
|
|
173
|
+
const at = this.typeahead.match(event.key, visible.map((item) => slottedWords(item, [''])), visible.indexOf(current));
|
|
174
|
+
if (at >= 0) {
|
|
175
|
+
this.focusOn(visible[at]);
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
121
179
|
move(from, delta) {
|
|
122
180
|
const visible = this.visibleItems;
|
|
123
181
|
const index = visible.indexOf(from);
|
|
@@ -137,8 +195,7 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
137
195
|
connectedCallback() {
|
|
138
196
|
super.connectedCallback();
|
|
139
197
|
this.addEventListener('helix-select', this.handleSelection);
|
|
140
|
-
this.addEventListener('
|
|
141
|
-
this.addEventListener('helix-before-close', this.handleBranch);
|
|
198
|
+
this.addEventListener('toggle', this.handleBranch, true);
|
|
142
199
|
this.addEventListener('keydown', this.handleKeydown);
|
|
143
200
|
this.watcher = new MutationObserver(() => this.syncItems());
|
|
144
201
|
this.watcher.observe(this, { childList: true, subtree: true });
|
|
@@ -146,8 +203,7 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
146
203
|
disconnectedCallback() {
|
|
147
204
|
super.disconnectedCallback();
|
|
148
205
|
this.removeEventListener('helix-select', this.handleSelection);
|
|
149
|
-
this.removeEventListener('
|
|
150
|
-
this.removeEventListener('helix-before-close', this.handleBranch);
|
|
206
|
+
this.removeEventListener('toggle', this.handleBranch, true);
|
|
151
207
|
this.removeEventListener('keydown', this.handleKeydown);
|
|
152
208
|
this.watcher?.disconnect();
|
|
153
209
|
this.watcher = undefined;
|
|
@@ -158,7 +214,7 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
158
214
|
}
|
|
159
215
|
updated(changed) {
|
|
160
216
|
super.updated(changed);
|
|
161
|
-
if (changed.has('active')) {
|
|
217
|
+
if (changed.has('active') || changed.has('nesting')) {
|
|
162
218
|
this.syncItems();
|
|
163
219
|
}
|
|
164
220
|
}
|
|
@@ -16,7 +16,8 @@ import { type TemplateResult } from 'lit';
|
|
|
16
16
|
*
|
|
17
17
|
* The direction is also written as a word, so a screen reader reads it. The
|
|
18
18
|
* styled tier hides `part="direction"` visually and keeps it in the
|
|
19
|
-
* accessibility tree.
|
|
19
|
+
* accessibility tree. The words are properties, `up-label` through
|
|
20
|
+
* `worse-label`, so a page in another language can set its own.
|
|
20
21
|
*
|
|
21
22
|
* The metric and the label are bare slots. An element that assigned its own
|
|
22
23
|
* slot on connect would add an attribute to its host after upgrade, which the
|
|
@@ -29,12 +30,17 @@ import { type TemplateResult } from 'lit';
|
|
|
29
30
|
* @documentation https://fusion.dev/helix/components/trend
|
|
30
31
|
*
|
|
31
32
|
* @slot - The metric that moved.
|
|
33
|
+
* @slot icon - Replaces the arrow, such as with a glyph of your own set. Slot the one for the current direction.
|
|
32
34
|
* @slot label - The period the metric moved over.
|
|
33
35
|
*
|
|
34
36
|
* @csspart direction - The direction as a word, for people who cannot see the arrow.
|
|
35
37
|
* @csspart icon - The arrow.
|
|
36
38
|
*/
|
|
37
39
|
export declare class HelixHeadlessTrend extends HelixElement {
|
|
40
|
+
/**
|
|
41
|
+
* The word read out after the direction when the move is an improvement.
|
|
42
|
+
*/
|
|
43
|
+
betterLabel: string;
|
|
38
44
|
/**
|
|
39
45
|
* Which way the measurement moved.
|
|
40
46
|
*
|
|
@@ -46,6 +52,10 @@ export declare class HelixHeadlessTrend extends HelixElement {
|
|
|
46
52
|
* and reports as a hydration mismatch.
|
|
47
53
|
*/
|
|
48
54
|
direction?: 'down' | 'neutral' | 'up';
|
|
55
|
+
/**
|
|
56
|
+
* The word read out for a move down.
|
|
57
|
+
*/
|
|
58
|
+
downLabel: string;
|
|
49
59
|
/**
|
|
50
60
|
* Which direction counts as an improvement for this metric.
|
|
51
61
|
*
|
|
@@ -55,6 +65,31 @@ export declare class HelixHeadlessTrend extends HelixElement {
|
|
|
55
65
|
* direction changes underneath.
|
|
56
66
|
*/
|
|
57
67
|
good?: 'down' | 'up';
|
|
68
|
+
/**
|
|
69
|
+
* The word read out for no move, or for a direction that is not one of the
|
|
70
|
+
* three.
|
|
71
|
+
*/
|
|
72
|
+
unchangedLabel: string;
|
|
73
|
+
/**
|
|
74
|
+
* The word read out for a move up.
|
|
75
|
+
*/
|
|
76
|
+
upLabel: string;
|
|
77
|
+
/**
|
|
78
|
+
* The word read out after the direction when the move is a setback.
|
|
79
|
+
*/
|
|
80
|
+
worseLabel: string;
|
|
81
|
+
/**
|
|
82
|
+
* The arrow for the direction, as the fallback of the `icon` slot.
|
|
83
|
+
*
|
|
84
|
+
* Slot fallback, so the page replaces it by slotting a glyph of its own and
|
|
85
|
+
* a trend with none draws the arrow it always did; and a method, so the tier
|
|
86
|
+
* above replaces it by overriding. The word beside it still says the
|
|
87
|
+
* direction either way.
|
|
88
|
+
*/
|
|
89
|
+
protected renderIcon(icon: {
|
|
90
|
+
content: string;
|
|
91
|
+
viewBox: string;
|
|
92
|
+
}): TemplateResult;
|
|
58
93
|
protected render(): TemplateResult;
|
|
59
94
|
}
|
|
60
95
|
declare global {
|
|
@@ -10,39 +10,65 @@ import { html } from 'lit';
|
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
11
11
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
12
|
const DIRECTIONS = {
|
|
13
|
-
down: { icon: arrowDown, word: '
|
|
14
|
-
neutral: { icon: minus, word: '
|
|
15
|
-
up: { icon: arrowUp, word: '
|
|
13
|
+
down: { icon: arrowDown, word: 'downLabel' },
|
|
14
|
+
neutral: { icon: minus, word: 'unchangedLabel' },
|
|
15
|
+
up: { icon: arrowUp, word: 'upLabel' },
|
|
16
16
|
};
|
|
17
17
|
const readDirection = (value) => DIRECTIONS[value] ?? DIRECTIONS.neutral;
|
|
18
18
|
let HelixHeadlessTrend = class HelixHeadlessTrend extends HelixElement {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this.betterLabel = 'better';
|
|
22
|
+
this.downLabel = 'Down';
|
|
23
|
+
this.unchangedLabel = 'Unchanged';
|
|
24
|
+
this.upLabel = 'Up';
|
|
25
|
+
this.worseLabel = 'worse';
|
|
26
|
+
}
|
|
27
|
+
renderIcon(icon) {
|
|
28
|
+
return html `<slot name="icon"
|
|
29
|
+
><svg
|
|
27
30
|
aria-hidden="true"
|
|
28
31
|
data-glyph
|
|
29
32
|
fill="currentColor"
|
|
30
33
|
part="icon"
|
|
31
|
-
viewBox=${
|
|
34
|
+
viewBox=${icon.viewBox}
|
|
32
35
|
>
|
|
33
|
-
${unsafeSVG(
|
|
34
|
-
</svg
|
|
35
|
-
|
|
36
|
+
${unsafeSVG(icon.content)}
|
|
37
|
+
</svg></slot
|
|
38
|
+
>`;
|
|
39
|
+
}
|
|
40
|
+
render() {
|
|
41
|
+
const direction = readDirection(this.direction);
|
|
42
|
+
const judgment = this.good && this.direction && this.direction !== 'neutral'
|
|
43
|
+
? `, ${this.good === this.direction ? this.betterLabel : this.worseLabel}`
|
|
44
|
+
: '';
|
|
45
|
+
return html `${this.renderIcon(direction.icon)}
|
|
46
|
+
<span part="direction">${`${this[direction.word]}${judgment}`}</span>
|
|
36
47
|
<slot></slot>
|
|
37
48
|
<slot name="label"></slot>`;
|
|
38
49
|
}
|
|
39
50
|
};
|
|
51
|
+
__decorate([
|
|
52
|
+
property({ attribute: 'better-label' })
|
|
53
|
+
], HelixHeadlessTrend.prototype, "betterLabel", void 0);
|
|
40
54
|
__decorate([
|
|
41
55
|
property({ reflect: true })
|
|
42
56
|
], HelixHeadlessTrend.prototype, "direction", void 0);
|
|
57
|
+
__decorate([
|
|
58
|
+
property({ attribute: 'down-label' })
|
|
59
|
+
], HelixHeadlessTrend.prototype, "downLabel", void 0);
|
|
43
60
|
__decorate([
|
|
44
61
|
property({ reflect: true })
|
|
45
62
|
], HelixHeadlessTrend.prototype, "good", void 0);
|
|
63
|
+
__decorate([
|
|
64
|
+
property({ attribute: 'unchanged-label' })
|
|
65
|
+
], HelixHeadlessTrend.prototype, "unchangedLabel", void 0);
|
|
66
|
+
__decorate([
|
|
67
|
+
property({ attribute: 'up-label' })
|
|
68
|
+
], HelixHeadlessTrend.prototype, "upLabel", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
property({ attribute: 'worse-label' })
|
|
71
|
+
], HelixHeadlessTrend.prototype, "worseLabel", void 0);
|
|
46
72
|
HelixHeadlessTrend = __decorate([
|
|
47
73
|
customElement('helix-headless-trend')
|
|
48
74
|
], HelixHeadlessTrend);
|
|
@@ -21,5 +21,10 @@ export interface KeyActions {
|
|
|
21
21
|
* Nothing is taken while focus is in a range. The scrubber and the volume are
|
|
22
22
|
* real inputs and the arrows are already theirs, so intercepting would mean
|
|
23
23
|
* seeking twice for one press.
|
|
24
|
+
*
|
|
25
|
+
* **Nor a press a control already handled, nor Space on a control.** Space is
|
|
26
|
+
* how a button is pressed, so Space on Mute played the video and left it
|
|
27
|
+
* unmuted, and a menu row chosen with Space also toggled playback. A key a
|
|
28
|
+
* menu or a control took for itself arrives here already refused.
|
|
24
29
|
*/
|
|
25
30
|
export declare const takeKey: (event: KeyboardEvent, video: HTMLVideoElement, actions: KeyActions) => boolean;
|
package/dist/video/root/keys.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { SKIP_SECONDS } from '@fusion.dev/helix-core';
|
|
2
|
+
const PRESSED_BY_SPACE = new Set(['a', 'button', 'select', 'summary', 'textarea']);
|
|
3
|
+
const PRESSED_ROLES = /^(button|checkbox|link|menuitem\w*|option|radio|switch|tab)$/;
|
|
2
4
|
export const takeKey = (event, video, actions) => {
|
|
3
|
-
if (event.
|
|
5
|
+
if (event.defaultPrevented) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const origin = (event.composedPath?.()[0] ?? event.target);
|
|
9
|
+
if (origin?.tagName === 'INPUT' || origin?.isContentEditable) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (event.key === ' ' &&
|
|
13
|
+
origin &&
|
|
14
|
+
(PRESSED_BY_SPACE.has(origin.localName) ||
|
|
15
|
+
PRESSED_ROLES.test(origin.getAttribute?.('role') ?? ''))) {
|
|
4
16
|
return false;
|
|
5
17
|
}
|
|
6
18
|
const step = event.shiftKey ? SKIP_SECONDS : 5;
|
|
@@ -383,6 +383,8 @@ export declare class HelixHeadlessVideo extends HelixElement {
|
|
|
383
383
|
private silent;
|
|
384
384
|
private full;
|
|
385
385
|
private captioned;
|
|
386
|
+
/** Which of the player's own menus is open, for its trigger to say so. */
|
|
387
|
+
private menuOpen;
|
|
386
388
|
/**
|
|
387
389
|
* Which caption track is showing, or `-1` for none.
|
|
388
390
|
*
|
|
@@ -582,6 +584,15 @@ export declare class HelixHeadlessVideo extends HelixElement {
|
|
|
582
584
|
* presses it twice expects twenty seconds rather than an accelerating jump.
|
|
583
585
|
*/
|
|
584
586
|
private skipBy;
|
|
587
|
+
/**
|
|
588
|
+
* Keeps each choice row's tick where this element puts it.
|
|
589
|
+
*
|
|
590
|
+
* A choice row checks itself after `helix-before-toggle`, and this element
|
|
591
|
+
* already sets `checked` on every row from its own state. The request is
|
|
592
|
+
* refused, so a tick moves only when the choice is applied, and stopped, so
|
|
593
|
+
* it does not reach a page that never placed the row.
|
|
594
|
+
*/
|
|
595
|
+
private readonly keepTick;
|
|
585
596
|
/** Shows one track and disables every other, or shows none at `-1`. */
|
|
586
597
|
private showCaption;
|
|
587
598
|
/** Turns captions on or off, which is what the button means with one track. */
|
|
@@ -695,6 +706,14 @@ export declare class HelixHeadlessVideo extends HelixElement {
|
|
|
695
706
|
* component's to paper over with "Track 2".
|
|
696
707
|
*/
|
|
697
708
|
protected renderCaptions(): TemplateResult | typeof nothing;
|
|
709
|
+
/**
|
|
710
|
+
* Notes which menu opened or closed, so its trigger says so.
|
|
711
|
+
*
|
|
712
|
+
* **The trigger is this element's own button**, so the state is written onto
|
|
713
|
+
* it here: a menu cannot write onto a plain button slotted into it, and the
|
|
714
|
+
* button said neither that it opens a menu nor whether that menu was open.
|
|
715
|
+
*/
|
|
716
|
+
private heardMenu;
|
|
698
717
|
protected renderOverflowItem(one: string): TemplateResult;
|
|
699
718
|
protected renderBar(): TemplateResult;
|
|
700
719
|
protected render(): TemplateResult;
|
|
@@ -10,6 +10,7 @@ import { nothing } from 'lit';
|
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { html } from 'lit/static-html.js';
|
|
12
12
|
import '../../menu/index.js';
|
|
13
|
+
import { HelixHeadlessMenu } from '../../menu/root/menu-root.js';
|
|
13
14
|
import { barControls, menuControls, ownFile } from './extra-controls.js';
|
|
14
15
|
import { takeKey } from './keys.js';
|
|
15
16
|
const clock = (seconds) => {
|
|
@@ -75,6 +76,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
|
|
|
75
76
|
this.silent = false;
|
|
76
77
|
this.full = false;
|
|
77
78
|
this.captioned = false;
|
|
79
|
+
this.menuOpen = undefined;
|
|
78
80
|
this.captionIndex = -1;
|
|
79
81
|
this.captionCount = 0;
|
|
80
82
|
this.rate = 1;
|
|
@@ -161,6 +163,12 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
|
|
|
161
163
|
const track = captionTracks(this.video)[this.captionIndex] ?? this.video?.textTracks[0];
|
|
162
164
|
this.cue = activeCue(track);
|
|
163
165
|
};
|
|
166
|
+
this.keepTick = (event) => {
|
|
167
|
+
if (event.target === event.currentTarget) {
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
event.stopPropagation();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
164
172
|
this.handlePicture = () => {
|
|
165
173
|
if (this.controls) {
|
|
166
174
|
return;
|
|
@@ -179,6 +187,9 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
|
|
|
179
187
|
if (!video) {
|
|
180
188
|
return;
|
|
181
189
|
}
|
|
190
|
+
if (event.composedPath().some((node) => node instanceof HelixHeadlessMenu)) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
182
193
|
const taken = takeKey(event, video, {
|
|
183
194
|
fullscreen: () => void this.fullscreen.toggle(),
|
|
184
195
|
seek: (seconds) => this.seek(seconds),
|
|
@@ -521,8 +532,16 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
|
|
|
521
532
|
return html `<${this.tag('menu')} part="captions-menu"
|
|
522
533
|
exportparts="back: captions-menu-back, back-mark: captions-menu-back-mark, empty: captions-menu-empty,
|
|
523
534
|
header: captions-menu-header, live: captions-menu-live, loading: captions-menu-loading, surface: captions-menu-surface,
|
|
524
|
-
title: captions-menu-title" label=${this.subtitlesLabel} placement="top-end"
|
|
525
|
-
|
|
535
|
+
title: captions-menu-title" label=${this.subtitlesLabel} placement="top-end"
|
|
536
|
+
@toggle=${(event) => this.heardMenu('captions', event)}>
|
|
537
|
+
<button
|
|
538
|
+
part="captions"
|
|
539
|
+
slot="trigger"
|
|
540
|
+
type="button"
|
|
541
|
+
aria-label=${this.subtitlesLabel}
|
|
542
|
+
aria-haspopup="menu"
|
|
543
|
+
aria-expanded=${this.menuOpen === 'captions' ? 'true' : 'false'}
|
|
544
|
+
>
|
|
526
545
|
${drawIcon(closedCaptioning)}
|
|
527
546
|
</button>
|
|
528
547
|
<${this.tag('menu-item')}
|
|
@@ -532,6 +551,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
|
|
|
532
551
|
checkable
|
|
533
552
|
exclusive
|
|
534
553
|
?checked=${this.captionIndex < 0}
|
|
554
|
+
@helix-before-toggle=${this.keepTick}
|
|
535
555
|
@helix-select=${() => this.showCaption(-1)}
|
|
536
556
|
>
|
|
537
557
|
${this.captionsOffLabel}
|
|
@@ -542,12 +562,25 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
|
|
|
542
562
|
checkable
|
|
543
563
|
exclusive
|
|
544
564
|
?checked=${this.captionIndex === at}
|
|
565
|
+
@helix-before-toggle=${this.keepTick}
|
|
545
566
|
@helix-select=${() => this.showCaption(at)}
|
|
546
567
|
>
|
|
547
568
|
${track.label || track.language}
|
|
548
569
|
</${this.tag('menu-item')}>`)}
|
|
549
570
|
</${this.tag('menu')}>`;
|
|
550
571
|
}
|
|
572
|
+
heardMenu(menu, event) {
|
|
573
|
+
if (event.target !== event.currentTarget) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
const open = event.newState === 'open';
|
|
577
|
+
if (open) {
|
|
578
|
+
this.menuOpen = menu;
|
|
579
|
+
}
|
|
580
|
+
else if (this.menuOpen === menu) {
|
|
581
|
+
this.menuOpen = undefined;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
551
584
|
renderOverflowItem(one) {
|
|
552
585
|
if (one === 'remote') {
|
|
553
586
|
return html `<${this.tag('menu-item')} part="entry"
|
|
@@ -682,8 +715,16 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
|
|
|
682
715
|
: html `<${this.tag('menu')} part="overflow"
|
|
683
716
|
exportparts="back: overflow-back, back-mark: overflow-back-mark, empty: overflow-empty,
|
|
684
717
|
header: overflow-header, live: overflow-live, loading: overflow-loading, surface: overflow-surface,
|
|
685
|
-
title: overflow-title" label=${this.moreLabel} placement="top-end"
|
|
686
|
-
|
|
718
|
+
title: overflow-title" label=${this.moreLabel} placement="top-end"
|
|
719
|
+
@toggle=${(event) => this.heardMenu('overflow', event)}>
|
|
720
|
+
<button
|
|
721
|
+
part="more"
|
|
722
|
+
slot="trigger"
|
|
723
|
+
type="button"
|
|
724
|
+
aria-label=${this.moreLabel}
|
|
725
|
+
aria-haspopup="menu"
|
|
726
|
+
aria-expanded=${this.menuOpen === 'overflow' ? 'true' : 'false'}
|
|
727
|
+
>
|
|
687
728
|
${drawIcon(dotsThreeVertical)}
|
|
688
729
|
</button>
|
|
689
730
|
${this.overflow.map((one) => this.renderOverflowItem(one))}
|
|
@@ -941,6 +982,9 @@ __decorate([
|
|
|
941
982
|
__decorate([
|
|
942
983
|
state()
|
|
943
984
|
], HelixHeadlessVideo.prototype, "captioned", void 0);
|
|
985
|
+
__decorate([
|
|
986
|
+
state()
|
|
987
|
+
], HelixHeadlessVideo.prototype, "menuOpen", void 0);
|
|
944
988
|
__decorate([
|
|
945
989
|
state()
|
|
946
990
|
], HelixHeadlessVideo.prototype, "captionIndex", void 0);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HelixElement } from '@fusion.dev/helix-core';
|
|
1
|
+
import { HelixElement, type Placement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type TemplateResult } from 'lit';
|
|
3
3
|
import '../../menu/index.js';
|
|
4
4
|
/**
|
|
@@ -51,7 +51,16 @@ export declare class HelixHeadlessVideoPlaylistMenu extends HelixElement {
|
|
|
51
51
|
* `top-end` because a control bar sits at the foot of the picture, and a menu
|
|
52
52
|
* opening downward from there opens off the player.
|
|
53
53
|
*/
|
|
54
|
-
placement:
|
|
54
|
+
placement: Placement;
|
|
55
|
+
/** Whether the menu is open, for the built-in trigger to say so. */
|
|
56
|
+
private open;
|
|
57
|
+
/**
|
|
58
|
+
* Notes the menu opening and closing, for the built-in trigger.
|
|
59
|
+
*
|
|
60
|
+
* The trigger is this element's own button, so the state is written onto it
|
|
61
|
+
* here. The menu cannot write onto a plain button slotted into it.
|
|
62
|
+
*/
|
|
63
|
+
private readonly heardToggle;
|
|
55
64
|
private observer;
|
|
56
65
|
connectedCallback(): void;
|
|
57
66
|
disconnectedCallback(): void;
|
|
@@ -88,6 +97,15 @@ export declare class HelixHeadlessVideoPlaylistMenu extends HelixElement {
|
|
|
88
97
|
*/
|
|
89
98
|
private watch;
|
|
90
99
|
private readonly reread;
|
|
100
|
+
/**
|
|
101
|
+
* Keeps each choice row's tick where this element puts it.
|
|
102
|
+
*
|
|
103
|
+
* A choice row checks itself after `helix-before-toggle`, and this element
|
|
104
|
+
* already sets `checked` on every row from its own state. The request is
|
|
105
|
+
* refused, so a tick moves only when the choice is applied, and stopped, so
|
|
106
|
+
* it does not reach a page that never placed the row.
|
|
107
|
+
*/
|
|
108
|
+
private readonly keepTick;
|
|
91
109
|
private readonly choose;
|
|
92
110
|
protected render(): TemplateResult;
|
|
93
111
|
/** The menu itself, behind a method so a styled tier can render another one. */
|
|
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { closestInstance, customElement, drawIcon, HelixElement, HelixSelectEvent, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { list } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
|
-
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { html } from 'lit/static-html.js';
|
|
12
12
|
import { HelixHeadlessVideoPlaylistItem } from '../item/video-playlist-item.js';
|
|
13
13
|
import { HelixHeadlessVideoPlaylist } from '../root/video-playlist-root.js';
|
|
@@ -17,9 +17,21 @@ let HelixHeadlessVideoPlaylistMenu = class HelixHeadlessVideoPlaylistMenu extend
|
|
|
17
17
|
super(...arguments);
|
|
18
18
|
this.label = 'Episodes';
|
|
19
19
|
this.placement = 'top-end';
|
|
20
|
+
this.open = false;
|
|
21
|
+
this.heardToggle = (event) => {
|
|
22
|
+
if (event.target === event.currentTarget) {
|
|
23
|
+
this.open = event.newState === 'open';
|
|
24
|
+
}
|
|
25
|
+
};
|
|
20
26
|
this.reread = () => {
|
|
21
27
|
this.requestUpdate();
|
|
22
28
|
};
|
|
29
|
+
this.keepTick = (event) => {
|
|
30
|
+
if (event.target === event.currentTarget) {
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
event.stopPropagation();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
23
35
|
this.choose = (value) => {
|
|
24
36
|
this.dispatchEvent(new HelixSelectEvent({ value }));
|
|
25
37
|
};
|
|
@@ -58,21 +70,28 @@ let HelixHeadlessVideoPlaylistMenu = class HelixHeadlessVideoPlaylistMenu extend
|
|
|
58
70
|
return this.renderMenu();
|
|
59
71
|
}
|
|
60
72
|
renderMenu() {
|
|
61
|
-
const active = this.playlist?.active;
|
|
62
73
|
return html `<${this.tag('menu')} part="menu"
|
|
63
74
|
exportparts="back: menu-back, back-mark: menu-back-mark, empty: menu-empty, header: menu-header,
|
|
64
|
-
live: menu-live, loading: menu-loading, surface: menu-surface, title: menu-title" label=${this.label} placement=${this.placement}
|
|
75
|
+
live: menu-live, loading: menu-loading, surface: menu-surface, title: menu-title" label=${this.label} placement=${this.placement}
|
|
76
|
+
@toggle=${this.heardToggle}>
|
|
65
77
|
<slot name="trigger" slot="trigger">
|
|
66
|
-
<button
|
|
78
|
+
<button
|
|
79
|
+
part="trigger"
|
|
80
|
+
type="button"
|
|
81
|
+
aria-label=${this.label}
|
|
82
|
+
aria-haspopup="menu"
|
|
83
|
+
aria-expanded=${this.open ? 'true' : 'false'}
|
|
84
|
+
>${drawIcon(list)}</button>
|
|
67
85
|
</slot>
|
|
68
86
|
${this.entries.map((entry) => html `<${this.tag('menu-item')}
|
|
69
87
|
part="entry"
|
|
70
88
|
exportparts="item: entry-item, mark: entry-mark, start: entry-start"
|
|
71
89
|
value=${entry.value}
|
|
72
90
|
checkable
|
|
73
|
-
?checked=${entry.
|
|
91
|
+
?checked=${entry.current}
|
|
74
92
|
?disabled=${entry.disabled}
|
|
75
93
|
exclusive
|
|
94
|
+
@helix-before-toggle=${this.keepTick}
|
|
76
95
|
@helix-select=${(event) => {
|
|
77
96
|
event.stopPropagation();
|
|
78
97
|
this.choose(entry.value);
|
|
@@ -92,6 +111,9 @@ __decorate([
|
|
|
92
111
|
__decorate([
|
|
93
112
|
property()
|
|
94
113
|
], HelixHeadlessVideoPlaylistMenu.prototype, "placement", void 0);
|
|
114
|
+
__decorate([
|
|
115
|
+
state()
|
|
116
|
+
], HelixHeadlessVideoPlaylistMenu.prototype, "open", void 0);
|
|
95
117
|
HelixHeadlessVideoPlaylistMenu = __decorate([
|
|
96
118
|
customElement('helix-headless-video-playlist-menu')
|
|
97
119
|
], HelixHeadlessVideoPlaylistMenu);
|