@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
|
@@ -4,14 +4,20 @@ 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 } from '@fusion.dev/helix-core';
|
|
7
|
+
import { capturePointer, customElement, DelayController, HelixElement, isRtl, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
|
+
import { hasScrollbar, offsetAt, scrollFraction, scrollPerPixel, showsScrollbar, thumbFraction, } from '../scrollbar.js';
|
|
10
11
|
const EDGES = ['block-start', 'block-end', 'inline-start', 'inline-end'];
|
|
11
12
|
let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement {
|
|
12
13
|
constructor() {
|
|
13
14
|
super(...arguments);
|
|
15
|
+
this.hideDelay = 600;
|
|
14
16
|
this.label = '';
|
|
17
|
+
this.active = false;
|
|
18
|
+
this.hovered = false;
|
|
19
|
+
this.over = false;
|
|
20
|
+
this.hide = new DelayController(this, { renders: false });
|
|
15
21
|
this.more = [];
|
|
16
22
|
this.scrolls = false;
|
|
17
23
|
this.measure = () => {
|
|
@@ -36,6 +42,56 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
|
|
|
36
42
|
}
|
|
37
43
|
this.more = found;
|
|
38
44
|
this.scrolls = box.scrollHeight > box.clientHeight || box.scrollWidth > box.clientWidth;
|
|
45
|
+
if (this.scrollbars) {
|
|
46
|
+
this.readBars(box);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
this.handleVerticalDown = (event) => {
|
|
50
|
+
this.grab(event, 'vertical');
|
|
51
|
+
};
|
|
52
|
+
this.handleHorizontalDown = (event) => {
|
|
53
|
+
this.grab(event, 'horizontal');
|
|
54
|
+
};
|
|
55
|
+
this.handleDragMove = (event) => {
|
|
56
|
+
const drag = this.drag;
|
|
57
|
+
const box = this.scroller;
|
|
58
|
+
if (!drag || !box) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const pointer = drag.axis === 'vertical' ? event.clientY : event.clientX;
|
|
62
|
+
this.scrollAlong(box, drag.axis, drag.from + (pointer - drag.pointer) * drag.sign * drag.perPixel);
|
|
63
|
+
};
|
|
64
|
+
this.handleDragEnd = () => {
|
|
65
|
+
if (!this.drag) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.drag = undefined;
|
|
69
|
+
this.wake();
|
|
70
|
+
this.requestUpdate();
|
|
71
|
+
};
|
|
72
|
+
this.handleBarEnter = () => {
|
|
73
|
+
this.over = true;
|
|
74
|
+
};
|
|
75
|
+
this.handleBarLeave = () => {
|
|
76
|
+
this.over = false;
|
|
77
|
+
this.wake();
|
|
78
|
+
};
|
|
79
|
+
this.handleEnter = () => {
|
|
80
|
+
this.hovered = true;
|
|
81
|
+
};
|
|
82
|
+
this.handleLeave = () => {
|
|
83
|
+
this.hovered = false;
|
|
84
|
+
if (this.scrollbars === 'hover') {
|
|
85
|
+
this.wake();
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
this.handleScroll = (event) => {
|
|
89
|
+
this.measure();
|
|
90
|
+
this.wake();
|
|
91
|
+
this.relayNativeEvent(event);
|
|
92
|
+
};
|
|
93
|
+
this.handleScrollEnd = (event) => {
|
|
94
|
+
this.relayNativeEvent(event);
|
|
39
95
|
};
|
|
40
96
|
this.handleSlotChange = (event) => {
|
|
41
97
|
const slot = event.target;
|
|
@@ -48,8 +104,84 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
|
|
|
48
104
|
get scroller() {
|
|
49
105
|
return this.partNamed('viewport');
|
|
50
106
|
}
|
|
107
|
+
extent(box, axis) {
|
|
108
|
+
return axis === 'vertical'
|
|
109
|
+
? { client: box.clientHeight, offset: box.scrollTop, scroll: box.scrollHeight }
|
|
110
|
+
: { client: box.clientWidth, offset: Math.abs(box.scrollLeft), scroll: box.scrollWidth };
|
|
111
|
+
}
|
|
112
|
+
readBars(box) {
|
|
113
|
+
const mode = this.scrollbars ?? 'auto';
|
|
114
|
+
const style = getComputedStyle(box);
|
|
115
|
+
const bar = (axis, overflow) => {
|
|
116
|
+
const extent = this.extent(box, axis);
|
|
117
|
+
return {
|
|
118
|
+
along: scrollFraction(extent),
|
|
119
|
+
drawn: hasScrollbar(mode, !['clip', 'hidden', 'visible'].includes(overflow), extent.offset > 1 || extent.client < extent.scroll - 1),
|
|
120
|
+
thumb: thumbFraction(extent),
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
const next = {
|
|
124
|
+
horizontal: bar('horizontal', style.overflowX),
|
|
125
|
+
vertical: bar('vertical', style.overflowY),
|
|
126
|
+
};
|
|
127
|
+
if (JSON.stringify(next) !== JSON.stringify(this.bars)) {
|
|
128
|
+
this.bars = next;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
wake() {
|
|
132
|
+
if (this.scrollbars !== 'scroll' && this.scrollbars !== 'hover') {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.active = true;
|
|
136
|
+
this.hide.start(this.hideDelay, () => {
|
|
137
|
+
this.active = false;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
scrollAlong(box, axis, offset) {
|
|
141
|
+
box.scrollTo(axis === 'vertical'
|
|
142
|
+
? { behavior: 'instant', top: offset }
|
|
143
|
+
: { behavior: 'instant', left: isRtl(box) ? -offset : offset });
|
|
144
|
+
}
|
|
145
|
+
grab(event, axis) {
|
|
146
|
+
const box = this.scroller;
|
|
147
|
+
const bar = event.currentTarget;
|
|
148
|
+
const thumb = bar.querySelector('[part~="thumb"]');
|
|
149
|
+
if (event.button !== 0 || !box || !thumb) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
event.preventDefault();
|
|
153
|
+
const vertical = axis === 'vertical';
|
|
154
|
+
const rtl = !vertical && isRtl(box);
|
|
155
|
+
const track = bar.getBoundingClientRect();
|
|
156
|
+
const held = thumb.getBoundingClientRect();
|
|
157
|
+
const length = vertical ? track.height : track.width;
|
|
158
|
+
const size = vertical ? held.height : held.width;
|
|
159
|
+
const extent = this.extent(box, axis);
|
|
160
|
+
const pointer = vertical ? event.clientY : event.clientX;
|
|
161
|
+
let from = extent.offset;
|
|
162
|
+
if (!thumb.contains(event.target)) {
|
|
163
|
+
const along = vertical
|
|
164
|
+
? pointer - track.top
|
|
165
|
+
: rtl
|
|
166
|
+
? track.right - pointer
|
|
167
|
+
: pointer - track.left;
|
|
168
|
+
from = offsetAt(extent, along, length, size);
|
|
169
|
+
this.scrollAlong(box, axis, from);
|
|
170
|
+
}
|
|
171
|
+
this.drag = {
|
|
172
|
+
axis,
|
|
173
|
+
from,
|
|
174
|
+
perPixel: scrollPerPixel(extent, length, size),
|
|
175
|
+
pointer,
|
|
176
|
+
sign: rtl ? -1 : 1,
|
|
177
|
+
};
|
|
178
|
+
capturePointer(bar, event.pointerId);
|
|
179
|
+
this.requestUpdate();
|
|
180
|
+
}
|
|
51
181
|
connectedCallback() {
|
|
52
182
|
super.connectedCallback();
|
|
183
|
+
this.addEventListener('pointerenter', this.handleEnter);
|
|
184
|
+
this.addEventListener('pointerleave', this.handleLeave);
|
|
53
185
|
this.watcher = new ResizeObserver(this.measure);
|
|
54
186
|
if (this.hasUpdated) {
|
|
55
187
|
this.watchContent();
|
|
@@ -57,8 +189,14 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
|
|
|
57
189
|
}
|
|
58
190
|
disconnectedCallback() {
|
|
59
191
|
super.disconnectedCallback();
|
|
192
|
+
this.removeEventListener('pointerenter', this.handleEnter);
|
|
193
|
+
this.removeEventListener('pointerleave', this.handleLeave);
|
|
60
194
|
this.watcher?.disconnect();
|
|
61
195
|
this.watcher = undefined;
|
|
196
|
+
this.drag = undefined;
|
|
197
|
+
this.active = false;
|
|
198
|
+
this.hovered = false;
|
|
199
|
+
this.over = false;
|
|
62
200
|
}
|
|
63
201
|
firstUpdated(changed) {
|
|
64
202
|
super.firstUpdated?.(changed);
|
|
@@ -79,11 +217,20 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
|
|
|
79
217
|
}
|
|
80
218
|
updated(changed) {
|
|
81
219
|
super.updated?.(changed);
|
|
220
|
+
if (changed.has('scrollbars') && this.hasUpdated && this.scrollbars) {
|
|
221
|
+
const box = this.scroller;
|
|
222
|
+
if (box) {
|
|
223
|
+
this.readBars(box);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
82
226
|
this.toggleState('scrolls', this.scrolls);
|
|
83
227
|
this.toggleState('more-block-start', this.more.includes('block-start'));
|
|
84
228
|
this.toggleState('more-block-end', this.more.includes('block-end'));
|
|
85
229
|
this.toggleState('more-inline-start', this.more.includes('inline-start'));
|
|
86
230
|
this.toggleState('more-inline-end', this.more.includes('inline-end'));
|
|
231
|
+
const drawn = this.scrollbars ? this.bars : undefined;
|
|
232
|
+
this.toggleState('scrollbar-horizontal', drawn?.horizontal.drawn === true);
|
|
233
|
+
this.toggleState('scrollbar-vertical', drawn?.vertical.drawn === true);
|
|
87
234
|
}
|
|
88
235
|
render() {
|
|
89
236
|
return html `<div
|
|
@@ -92,7 +239,8 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
|
|
|
92
239
|
role=${this.label ? 'region' : nothing}
|
|
93
240
|
aria-label=${this.label || nothing}
|
|
94
241
|
tabindex=${this.scrolls ? '0' : nothing}
|
|
95
|
-
@scroll=${this.
|
|
242
|
+
@scroll=${this.handleScroll}
|
|
243
|
+
@scrollend=${this.handleScrollEnd}
|
|
96
244
|
>
|
|
97
245
|
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
98
246
|
</div>
|
|
@@ -104,12 +252,79 @@ let HelixHeadlessScrollArea = class HelixHeadlessScrollArea extends HelixElement
|
|
|
104
252
|
<div
|
|
105
253
|
part="edges"
|
|
106
254
|
aria-hidden="true"
|
|
107
|
-
></div
|
|
255
|
+
></div>${this.scrollbars ? this.renderScrollbars(this.scrollbars) : nothing}`;
|
|
256
|
+
}
|
|
257
|
+
renderScrollbars(mode) {
|
|
258
|
+
const bars = this.bars;
|
|
259
|
+
const moment = {
|
|
260
|
+
active: this.active,
|
|
261
|
+
held: this.over || this.drag !== undefined,
|
|
262
|
+
hovered: this.hovered,
|
|
263
|
+
};
|
|
264
|
+
const shown = showsScrollbar(mode, moment);
|
|
265
|
+
const facts = (bar) => bar
|
|
266
|
+
? `--scroll-area-thumb-fraction: ${bar.thumb}; --scroll-area-scroll-fraction: ${bar.along}`
|
|
267
|
+
: nothing;
|
|
268
|
+
const vertical = bars?.vertical.drawn === true;
|
|
269
|
+
const horizontal = bars?.horizontal.drawn === true;
|
|
270
|
+
return html `<div
|
|
271
|
+
part="scrollbar scrollbar-vertical${vertical && shown ? ' scrollbar-visible' : ''}"
|
|
272
|
+
aria-hidden="true"
|
|
273
|
+
?hidden=${!vertical}
|
|
274
|
+
style=${facts(bars?.vertical)}
|
|
275
|
+
@pointerdown=${this.handleVerticalDown}
|
|
276
|
+
@pointermove=${this.handleDragMove}
|
|
277
|
+
@pointerup=${this.handleDragEnd}
|
|
278
|
+
@pointercancel=${this.handleDragEnd}
|
|
279
|
+
@lostpointercapture=${this.handleDragEnd}
|
|
280
|
+
@pointerenter=${this.handleBarEnter}
|
|
281
|
+
@pointerleave=${this.handleBarLeave}
|
|
282
|
+
>
|
|
283
|
+
<div part="thumb thumb-vertical"></div>
|
|
284
|
+
</div>
|
|
285
|
+
<div
|
|
286
|
+
part="scrollbar scrollbar-horizontal${horizontal && shown ? ' scrollbar-visible' : ''}"
|
|
287
|
+
aria-hidden="true"
|
|
288
|
+
?hidden=${!horizontal}
|
|
289
|
+
style=${facts(bars?.horizontal)}
|
|
290
|
+
@pointerdown=${this.handleHorizontalDown}
|
|
291
|
+
@pointermove=${this.handleDragMove}
|
|
292
|
+
@pointerup=${this.handleDragEnd}
|
|
293
|
+
@pointercancel=${this.handleDragEnd}
|
|
294
|
+
@lostpointercapture=${this.handleDragEnd}
|
|
295
|
+
@pointerenter=${this.handleBarEnter}
|
|
296
|
+
@pointerleave=${this.handleBarLeave}
|
|
297
|
+
>
|
|
298
|
+
<div part="thumb thumb-horizontal"></div>
|
|
299
|
+
</div>
|
|
300
|
+
<div
|
|
301
|
+
part="corner"
|
|
302
|
+
aria-hidden="true"
|
|
303
|
+
?hidden=${!(vertical && horizontal)}
|
|
304
|
+
></div>`;
|
|
108
305
|
}
|
|
109
306
|
};
|
|
307
|
+
__decorate([
|
|
308
|
+
property({ attribute: 'hide-delay', type: Number })
|
|
309
|
+
], HelixHeadlessScrollArea.prototype, "hideDelay", void 0);
|
|
110
310
|
__decorate([
|
|
111
311
|
property()
|
|
112
312
|
], HelixHeadlessScrollArea.prototype, "label", void 0);
|
|
313
|
+
__decorate([
|
|
314
|
+
property({ reflect: true })
|
|
315
|
+
], HelixHeadlessScrollArea.prototype, "scrollbars", void 0);
|
|
316
|
+
__decorate([
|
|
317
|
+
state()
|
|
318
|
+
], HelixHeadlessScrollArea.prototype, "bars", void 0);
|
|
319
|
+
__decorate([
|
|
320
|
+
state()
|
|
321
|
+
], HelixHeadlessScrollArea.prototype, "active", void 0);
|
|
322
|
+
__decorate([
|
|
323
|
+
state()
|
|
324
|
+
], HelixHeadlessScrollArea.prototype, "hovered", void 0);
|
|
325
|
+
__decorate([
|
|
326
|
+
state()
|
|
327
|
+
], HelixHeadlessScrollArea.prototype, "over", void 0);
|
|
113
328
|
__decorate([
|
|
114
329
|
state()
|
|
115
330
|
], HelixHeadlessScrollArea.prototype, "more", void 0);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The arithmetic behind the scrollbars a scroll area draws under `scrollbars`.
|
|
3
|
+
*
|
|
4
|
+
* Every length here is along one axis and counted from that axis' start, which
|
|
5
|
+
* is the right-hand edge on a right-to-left page for the horizontal one. The
|
|
6
|
+
* component turns a pointer and a `scrollLeft` into those counts, so nothing
|
|
7
|
+
* below has to know which way the line runs.
|
|
8
|
+
*/
|
|
9
|
+
/** Which scrollbars are drawn, and when. Absent keeps the browser's own. */
|
|
10
|
+
export type Scrollbars = 'always' | 'auto' | 'hover' | 'scroll';
|
|
11
|
+
/** One axis of the viewport, read off the box. */
|
|
12
|
+
export interface Extent {
|
|
13
|
+
/** How much of the content the viewport shows, `clientHeight` or `clientWidth`. */
|
|
14
|
+
client: number;
|
|
15
|
+
/** How far from its start the axis is scrolled, never negative. */
|
|
16
|
+
offset: number;
|
|
17
|
+
/** The whole length of the content, `scrollHeight` or `scrollWidth`. */
|
|
18
|
+
scroll: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The share of the track the thumb covers, from 0 to 1: how much of the content
|
|
22
|
+
* is in view. A box with no content, or one that shows all of it, is 1.
|
|
23
|
+
*/
|
|
24
|
+
export declare const thumbFraction: ({ client, scroll }: Extent) => number;
|
|
25
|
+
/**
|
|
26
|
+
* How far along the axis is scrolled, from 0 at the start to 1 at the end. An
|
|
27
|
+
* axis with nothing to scroll is 0.
|
|
28
|
+
*/
|
|
29
|
+
export declare const scrollFraction: ({ client, offset, scroll }: Extent) => number;
|
|
30
|
+
/**
|
|
31
|
+
* How far the content moves for each pixel the thumb is dragged.
|
|
32
|
+
*
|
|
33
|
+
* The thumb travels the track less its own length, and the content travels
|
|
34
|
+
* its length less the view, so the ratio of the two is the gearing. Zero where
|
|
35
|
+
* the thumb fills the track and cannot move.
|
|
36
|
+
*/
|
|
37
|
+
export declare const scrollPerPixel: (extent: Extent, track: number, thumb: number) => number;
|
|
38
|
+
/**
|
|
39
|
+
* The offset that puts the middle of the thumb under a press on the track.
|
|
40
|
+
*
|
|
41
|
+
* `along` is where the press landed, counted from the track's start. The thumb
|
|
42
|
+
* stops at either end of the track, so a press near an end scrolls to that end.
|
|
43
|
+
*/
|
|
44
|
+
export declare const offsetAt: (extent: Extent, along: number, track: number, thumb: number) => number;
|
|
45
|
+
/**
|
|
46
|
+
* Whether an axis has a scrollbar at all: it can scroll, and under every value
|
|
47
|
+
* but `always` it has something to scroll.
|
|
48
|
+
*
|
|
49
|
+
* An axis whose `overflow` is `hidden` or `clip` cannot be scrolled by a reader,
|
|
50
|
+
* so it gets no scrollbar whatever `scrollbars` says. That is how a consumer
|
|
51
|
+
* keeps a horizontal bar off a list that only scrolls down.
|
|
52
|
+
*/
|
|
53
|
+
export declare const hasScrollbar: (mode: Scrollbars, scrollable: boolean, overflows: boolean) => boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Whether a scrollbar that exists is showing at this moment.
|
|
56
|
+
*
|
|
57
|
+
* `auto` and `always` show it the whole time. `scroll` shows it while the
|
|
58
|
+
* content is moving and for the hide delay after, and while the pointer holds
|
|
59
|
+
* it. `hover` adds the time the pointer is over the scroll area.
|
|
60
|
+
*/
|
|
61
|
+
export declare const showsScrollbar: (mode: Scrollbars, moment: {
|
|
62
|
+
active: boolean;
|
|
63
|
+
held: boolean;
|
|
64
|
+
hovered: boolean;
|
|
65
|
+
}) => boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const clamp = (value, low, high) => Math.min(Math.max(value, low), high);
|
|
2
|
+
export const thumbFraction = ({ client, scroll }) => scroll <= 0 ? 1 : clamp(client / scroll, 0, 1);
|
|
3
|
+
export const scrollFraction = ({ client, offset, scroll }) => {
|
|
4
|
+
const room = scroll - client;
|
|
5
|
+
return room <= 0 ? 0 : clamp(offset / room, 0, 1);
|
|
6
|
+
};
|
|
7
|
+
export const scrollPerPixel = (extent, track, thumb) => {
|
|
8
|
+
const run = track - thumb;
|
|
9
|
+
return run <= 0 ? 0 : Math.max(0, extent.scroll - extent.client) / run;
|
|
10
|
+
};
|
|
11
|
+
export const offsetAt = (extent, along, track, thumb) => {
|
|
12
|
+
const run = track - thumb;
|
|
13
|
+
if (run <= 0) {
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
return clamp((along - thumb / 2) / run, 0, 1) * Math.max(0, extent.scroll - extent.client);
|
|
17
|
+
};
|
|
18
|
+
export const hasScrollbar = (mode, scrollable, overflows) => scrollable && (mode === 'always' || overflows);
|
|
19
|
+
export const showsScrollbar = (mode, moment) => {
|
|
20
|
+
if (mode === 'auto' || mode === 'always') {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return moment.active || moment.held || (mode === 'hover' && moment.hovered);
|
|
24
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AriaForwardController, HelixFormElement, PopoverController } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import { type HelixHeadlessOption } from '../../option/root/option-root.js';
|
|
3
4
|
import '../../listbox/index.js';
|
|
4
5
|
declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
5
6
|
/**
|
|
@@ -17,6 +18,9 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
17
18
|
* `Select` owns the value, passes it down to the listbox, and takes changes
|
|
18
19
|
* back, so the value lives in one place.
|
|
19
20
|
*
|
|
21
|
+
* Set `valueContent` to draw the trigger's content from the chosen options,
|
|
22
|
+
* and several chosen options are written as a list in the reader's language.
|
|
23
|
+
*
|
|
20
24
|
* In the open list the arrow keys, Home, End, PageUp, PageDown and typed
|
|
21
25
|
* letters move the highlight, and Enter, Space or a click chooses it and
|
|
22
26
|
* closes the list. Tab closes the list and moves on. On the closed trigger,
|
|
@@ -103,6 +107,17 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
103
107
|
* Shown on the trigger while nothing is chosen.
|
|
104
108
|
*/
|
|
105
109
|
placeholder: string;
|
|
110
|
+
/**
|
|
111
|
+
* What the trigger shows for the chosen options: a function given them, in
|
|
112
|
+
* the order they appear, that returns text, an element or a Lit template.
|
|
113
|
+
*
|
|
114
|
+
* For a trigger that shows more than the words, an avatar beside a name or a
|
|
115
|
+
* count of a long set, as React Aria's `SelectValue` takes children. The
|
|
116
|
+
* trigger is named by what this draws, so keep the words in it. Nothing
|
|
117
|
+
* chosen still shows `placeholder`. A property only, there being no way to
|
|
118
|
+
* write a function in markup.
|
|
119
|
+
*/
|
|
120
|
+
valueContent?: ((chosen: readonly HelixHeadlessOption[]) => unknown) | undefined;
|
|
106
121
|
/**
|
|
107
122
|
* Which option is chosen, as an index, or `-1` where none is.
|
|
108
123
|
*
|
|
@@ -168,6 +183,13 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
168
183
|
* the commit creates the text node it needs.
|
|
169
184
|
*/
|
|
170
185
|
private get display();
|
|
186
|
+
/** The chosen options, in the order they appear. None on a server or while hydrating. */
|
|
187
|
+
private get chosenOptions();
|
|
188
|
+
/**
|
|
189
|
+
* What the trigger shows, behind a seam: what `value-content` draws for the
|
|
190
|
+
* chosen options, or their words, or the placeholder.
|
|
191
|
+
*/
|
|
192
|
+
protected renderValue(): unknown;
|
|
171
193
|
/** Where the highlight goes when the list opens, set by the key that opened it. */
|
|
172
194
|
private opening;
|
|
173
195
|
/**
|
|
@@ -187,6 +209,8 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
187
209
|
* Made on connection, there being no `MutationObserver` on a server.
|
|
188
210
|
*/
|
|
189
211
|
private watchers;
|
|
212
|
+
/** A link option, once followed, closes the panel as a choice does. */
|
|
213
|
+
private readonly handleLinkFollowed;
|
|
190
214
|
connectedCallback(): void;
|
|
191
215
|
disconnectedCallback(): void;
|
|
192
216
|
/** Opens the list with the highlight where the opening key says. */
|
|
@@ -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 { AriaForwardController, customElement, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, reportValues, typesCharacter, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, afterLinkFollowed, customElement, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, reportValues, typesCharacter, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { caretDown } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
@@ -43,6 +43,9 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
43
43
|
this.opening = 'selected';
|
|
44
44
|
this.seen = new Set();
|
|
45
45
|
this.watchers = [];
|
|
46
|
+
this.handleLinkFollowed = (event) => {
|
|
47
|
+
afterLinkFollowed(event, () => this.requestOpen(false));
|
|
48
|
+
};
|
|
46
49
|
this.handleChange = (event) => {
|
|
47
50
|
const next = event.detail.value;
|
|
48
51
|
if (!this.requestValue(next)) {
|
|
@@ -105,16 +108,23 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
105
108
|
}
|
|
106
109
|
get display() {
|
|
107
110
|
const chosen = new Set(this.value === '' ? [] : this.value.split(','));
|
|
108
|
-
const words =
|
|
109
|
-
.filter((option) => chosen.has(option.value))
|
|
110
|
-
.map((option) => option.text);
|
|
111
|
+
const words = this.chosenOptions.map((option) => option.text);
|
|
111
112
|
if (words.length > 0) {
|
|
112
|
-
return
|
|
113
|
+
return new Intl.ListFormat(this.lang || undefined, { style: 'short', type: 'unit' }).format(words);
|
|
113
114
|
}
|
|
114
115
|
return chosen.size > 0 && !this.childrenKnown ? nothing : this.placeholder;
|
|
115
116
|
}
|
|
117
|
+
get chosenOptions() {
|
|
118
|
+
const chosen = new Set(this.value === '' ? [] : this.value.split(','));
|
|
119
|
+
return optionsAmong(this.knownChildren).filter((option) => chosen.has(option.value));
|
|
120
|
+
}
|
|
121
|
+
renderValue() {
|
|
122
|
+
const chosen = this.chosenOptions;
|
|
123
|
+
return this.valueContent && chosen.length > 0 ? this.valueContent(chosen) : this.display;
|
|
124
|
+
}
|
|
116
125
|
connectedCallback() {
|
|
117
126
|
super.connectedCallback();
|
|
127
|
+
this.addEventListener('helix-select', this.handleLinkFollowed);
|
|
118
128
|
const words = new MutationObserver(() => this.requestUpdate());
|
|
119
129
|
words.observe(this, {
|
|
120
130
|
attributeFilter: ['label', 'value'],
|
|
@@ -128,6 +138,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
128
138
|
}
|
|
129
139
|
disconnectedCallback() {
|
|
130
140
|
super.disconnectedCallback();
|
|
141
|
+
this.removeEventListener('helix-select', this.handleLinkFollowed);
|
|
131
142
|
for (const watcher of this.watchers) {
|
|
132
143
|
watcher.disconnect();
|
|
133
144
|
}
|
|
@@ -211,7 +222,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
211
222
|
?multiple=${this.multiple}
|
|
212
223
|
?filterable=${this.filterable}
|
|
213
224
|
manual
|
|
214
|
-
aria-label=${this.label || nothing}
|
|
225
|
+
aria-label=${this.label || this.getAttribute('aria-label') || nothing}
|
|
215
226
|
@keydown=${this.handleListKeydown}
|
|
216
227
|
@helix-before-change=${this.handleChange}
|
|
217
228
|
@change=${this.stopInner}
|
|
@@ -252,7 +263,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
252
263
|
@keydown=${this.handleTriggerKeydown}
|
|
253
264
|
>
|
|
254
265
|
<slot name="start"></slot>
|
|
255
|
-
<span part="value" id="value">${this.
|
|
266
|
+
<span part="value" id="value">${this.renderValue()}</span>
|
|
256
267
|
${''}
|
|
257
268
|
<slot name="end"></slot>
|
|
258
269
|
${''}
|
|
@@ -283,6 +294,9 @@ __decorate([
|
|
|
283
294
|
__decorate([
|
|
284
295
|
property()
|
|
285
296
|
], HelixHeadlessSelect.prototype, "placeholder", void 0);
|
|
297
|
+
__decorate([
|
|
298
|
+
property({ attribute: false })
|
|
299
|
+
], HelixHeadlessSelect.prototype, "valueContent", void 0);
|
|
286
300
|
HelixHeadlessSelect = __decorate([
|
|
287
301
|
customElement('helix-headless-select')
|
|
288
302
|
], HelixHeadlessSelect);
|
|
@@ -15,12 +15,22 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
15
15
|
* There is no `shape` property. Whether a placeholder is a line, a block, or a
|
|
16
16
|
* circle is presentation, which belongs to the styled tier.
|
|
17
17
|
*
|
|
18
|
+
* **Put the real content inside and set `loading`, and the skeleton takes its
|
|
19
|
+
* size.** While `loading` is set the content is inert, the host is
|
|
20
|
+
* `aria-busy`, and the styled tier hides the content and paints the
|
|
21
|
+
* placeholder over its box, so nothing moves when the content arrives. Take
|
|
22
|
+
* `loading` off and the content is shown as it is. An empty skeleton is a
|
|
23
|
+
* placeholder of its own size, as before.
|
|
24
|
+
*
|
|
18
25
|
* @since 0.1.0
|
|
19
26
|
* @status stable
|
|
20
27
|
* @category feedback
|
|
21
28
|
* @aliases Placeholder, Shimmer, Ghost
|
|
22
29
|
* @documentation https://fusion.dev/helix/components/skeleton
|
|
23
30
|
*
|
|
31
|
+
* @slot - The content the skeleton stands in for, which sizes it. Optional.
|
|
32
|
+
*
|
|
33
|
+
* @csspart content - The box around the content, inert while `loading`.
|
|
24
34
|
* @csspart skeleton - The placeholder shape.
|
|
25
35
|
*/
|
|
26
36
|
export declare class HelixHeadlessSkeleton extends HelixElement {
|
|
@@ -31,7 +41,22 @@ export declare class HelixHeadlessSkeleton extends HelixElement {
|
|
|
31
41
|
* Absent hides the placeholder from screen readers.
|
|
32
42
|
*/
|
|
33
43
|
label: string;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the content inside is still loading, which keeps it inert and
|
|
46
|
+
* draws the placeholder over it.
|
|
47
|
+
*
|
|
48
|
+
* Absent shows the content. An empty skeleton is a placeholder whatever
|
|
49
|
+
* this says. Reflected, because the styled tier hides the content on it.
|
|
50
|
+
*/
|
|
51
|
+
loading: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Whether the skeleton holds content, read off its children where they can
|
|
54
|
+
* be known. Not on a server, where an unlabeled skeleton is taken for an
|
|
55
|
+
* empty one until the page has its children.
|
|
56
|
+
*/
|
|
57
|
+
private get wraps();
|
|
34
58
|
protected willUpdate(changed: PropertyValues): void;
|
|
59
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
35
60
|
protected render(): TemplateResult;
|
|
36
61
|
}
|
|
37
62
|
declare global {
|
|
@@ -11,25 +11,40 @@ let HelixHeadlessSkeleton = class HelixHeadlessSkeleton extends HelixElement {
|
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.label = '';
|
|
14
|
+
this.loading = false;
|
|
15
|
+
}
|
|
16
|
+
get wraps() {
|
|
17
|
+
return (this.childrenKnown &&
|
|
18
|
+
[...this.childNodes].some((node) => node.nodeType === 1 || (node.textContent ?? '').trim() !== ''));
|
|
14
19
|
}
|
|
15
20
|
willUpdate(changed) {
|
|
16
21
|
super.willUpdate(changed);
|
|
22
|
+
this.internals.ariaBusy = this.loading ? 'true' : null;
|
|
17
23
|
if (this.label) {
|
|
18
24
|
hostAria(this.internals, { label: this.label, role: 'progressbar' });
|
|
19
25
|
this.internals.ariaHidden = null;
|
|
20
26
|
}
|
|
21
27
|
else {
|
|
22
28
|
hostAria(this.internals, { label: '', role: '' });
|
|
23
|
-
this.internals.ariaHidden = 'true';
|
|
29
|
+
this.internals.ariaHidden = this.wraps ? null : 'true';
|
|
24
30
|
}
|
|
25
31
|
}
|
|
32
|
+
firstUpdated(changed) {
|
|
33
|
+
super.firstUpdated(changed);
|
|
34
|
+
this.finishHydration();
|
|
35
|
+
}
|
|
26
36
|
render() {
|
|
27
|
-
return html `<span part="
|
|
37
|
+
return html `<span part="content" ?inert=${this.loading}
|
|
38
|
+
><slot @slotchange=${() => this.requestUpdate()}></slot></span
|
|
39
|
+
><span part="skeleton"></span>`;
|
|
28
40
|
}
|
|
29
41
|
};
|
|
30
42
|
__decorate([
|
|
31
43
|
property()
|
|
32
44
|
], HelixHeadlessSkeleton.prototype, "label", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
property({ reflect: true, type: Boolean })
|
|
47
|
+
], HelixHeadlessSkeleton.prototype, "loading", void 0);
|
|
33
48
|
HelixHeadlessSkeleton = __decorate([
|
|
34
49
|
customElement('helix-headless-skeleton')
|
|
35
50
|
], HelixHeadlessSkeleton);
|
|
@@ -20,6 +20,13 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
|
|
|
20
20
|
*
|
|
21
21
|
* A range with two thumbs is two inputs stacked on one track, because there is
|
|
22
22
|
* no native two-thumb range. Each thumb keeps its own value.
|
|
23
|
+
* `min-steps-between-thumbs` keeps them that many steps apart.
|
|
24
|
+
*
|
|
25
|
+
* `format-options` writes the value with `Intl.NumberFormat` in `locale`, as a
|
|
26
|
+
* currency, a percent or a unit, and `formatter` writes it with a function of
|
|
27
|
+
* your own, such as words for a scale. Either one is what a screen reader
|
|
28
|
+
* hears, what the readout shows and what the marker labels say. `value-text`
|
|
29
|
+
* still wraps it in a sentence, with the formatted value in its place.
|
|
23
30
|
*
|
|
24
31
|
* `required` comes with the field mixin and cannot fail. A range is never
|
|
25
32
|
* empty: the platform shows its midpoint when no value is set, and `willUpdate`
|
|
@@ -62,6 +69,27 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
|
|
|
62
69
|
protected readonly aria: AriaForwardController;
|
|
63
70
|
/** Typed or dragged, so every edit is announced. See `announcesInput`. */
|
|
64
71
|
protected readonly announcesInput = true;
|
|
72
|
+
/**
|
|
73
|
+
* `Intl.NumberFormat` options the value is written with: a currency, a
|
|
74
|
+
* percent, a unit, or a number of decimals. Written as JSON in the
|
|
75
|
+
* attribute.
|
|
76
|
+
*
|
|
77
|
+
* ```html
|
|
78
|
+
* <helix-slider format-options='{"style":"currency","currency":"USD"}'></helix-slider>
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
formatOptions?: Intl.NumberFormatOptions;
|
|
82
|
+
/**
|
|
83
|
+
* Writes a value as text, in place of `format-options`: words for a scale,
|
|
84
|
+
* or anything `Intl.NumberFormat` cannot say. A property, since a function
|
|
85
|
+
* cannot be written in an attribute.
|
|
86
|
+
*/
|
|
87
|
+
formatter?: (value: number) => string;
|
|
88
|
+
/**
|
|
89
|
+
* The locale `format-options` writes the value in, such as `de-DE`. Empty is
|
|
90
|
+
* the reader's own.
|
|
91
|
+
*/
|
|
92
|
+
locale: string;
|
|
65
93
|
/**
|
|
66
94
|
* Shows the value at each mark.
|
|
67
95
|
*/
|
|
@@ -102,6 +130,11 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
|
|
|
102
130
|
min: number;
|
|
103
131
|
/** The name of a range's lower thumb, read after the slider's label. */
|
|
104
132
|
minimumLabel: string;
|
|
133
|
+
/**
|
|
134
|
+
* How many steps a range's two thumbs stay apart, as Zag's
|
|
135
|
+
* `minStepsBetweenThumbs`. A thumb pushed closer stops there.
|
|
136
|
+
*/
|
|
137
|
+
minStepsBetweenThumbs: number;
|
|
105
138
|
/**
|
|
106
139
|
* The direction the track runs. `vertical` stands it on end.
|
|
107
140
|
*
|
|
@@ -223,6 +256,12 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
|
|
|
223
256
|
* step, or for a range, two of them in order.
|
|
224
257
|
*/
|
|
225
258
|
private sanitize;
|
|
259
|
+
/** How far apart a range's thumbs stay, in the slider's own units. */
|
|
260
|
+
private get gap();
|
|
261
|
+
/** Whether the value is written by `formatter` or `format-options`. */
|
|
262
|
+
private get formats();
|
|
263
|
+
/** A value as the reader sees it: formatted where asked, the number otherwise. */
|
|
264
|
+
private said;
|
|
226
265
|
/** What a screen reader says for one thumb, where `value-text` asks. */
|
|
227
266
|
private spoken;
|
|
228
267
|
protected updated(changed: PropertyValues): void;
|