@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,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, fillTemplate, HelixActivateEvent, HelixElement, HelixSelectEvent, hostAria, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { capturePointer, customElement, fillTemplate, HelixActivateEvent, HelixElement, HelixSelectEvent, hostAria, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { caretLeft, caretRight, play, stop } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -18,6 +18,8 @@ const COUNT_OR_AUTO = {
|
|
|
18
18
|
},
|
|
19
19
|
toAttribute: (value) => value === undefined ? null : String(value),
|
|
20
20
|
};
|
|
21
|
+
const ICON_SLOTS = ['previous-icon', 'next-icon'];
|
|
22
|
+
const DRAG_SLOP = 4;
|
|
21
23
|
let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
22
24
|
constructor() {
|
|
23
25
|
super(...arguments);
|
|
@@ -31,9 +33,11 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
31
33
|
this.said = '';
|
|
32
34
|
this.label = 'Carousel';
|
|
33
35
|
this.loop = false;
|
|
36
|
+
this.mouseDrag = false;
|
|
34
37
|
this.nextLabel = 'Next slide';
|
|
35
38
|
this.rotating = false;
|
|
36
39
|
this.previousLabel = 'Previous slide';
|
|
40
|
+
this.roleLabel = 'carousel';
|
|
37
41
|
this.slideLabel = '{index} of {count}';
|
|
38
42
|
this.slideRoleLabel = 'slide';
|
|
39
43
|
this.startLabel = 'Start slide rotation';
|
|
@@ -75,6 +79,68 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
75
79
|
this.handleTake = () => {
|
|
76
80
|
this.settling = false;
|
|
77
81
|
};
|
|
82
|
+
this.dragging = false;
|
|
83
|
+
this.handlePress = (event) => {
|
|
84
|
+
this.handleTake();
|
|
85
|
+
const track = this.partNamed('track');
|
|
86
|
+
if (!this.mouseDrag || event.pointerType !== 'mouse' || event.button !== 0 || !track) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.pull = { left: track.scrollLeft, top: track.scrollTop, x: event.clientX, y: event.clientY };
|
|
90
|
+
};
|
|
91
|
+
this.handlePull = (event) => {
|
|
92
|
+
const pull = this.pull;
|
|
93
|
+
const track = this.partNamed('track');
|
|
94
|
+
if (!pull || !track) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if ((event.buttons & 1) === 0) {
|
|
98
|
+
this.pull = undefined;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const across = event.clientX - pull.x;
|
|
102
|
+
const down = event.clientY - pull.y;
|
|
103
|
+
if (!this.dragging) {
|
|
104
|
+
if (Math.hypot(across, down) < DRAG_SLOP) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this.dragging = true;
|
|
108
|
+
track.style.setProperty('scroll-snap-type', 'none', 'important');
|
|
109
|
+
capturePointer(track, event.pointerId);
|
|
110
|
+
}
|
|
111
|
+
track.scrollTo(this.orientation === 'vertical'
|
|
112
|
+
? { behavior: 'instant', top: pull.top - down }
|
|
113
|
+
: { behavior: 'instant', left: pull.left - across });
|
|
114
|
+
};
|
|
115
|
+
this.handleLetGo = () => {
|
|
116
|
+
if (!this.pull) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.pull = undefined;
|
|
120
|
+
if (!this.dragging) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.swallowClick();
|
|
124
|
+
const nearest = this.nearest();
|
|
125
|
+
this.dragging = false;
|
|
126
|
+
this.showing = undefined;
|
|
127
|
+
const moved = nearest !== undefined &&
|
|
128
|
+
nearest !== this.index &&
|
|
129
|
+
requestChange({
|
|
130
|
+
apply: (value) => this.applyIndex(value),
|
|
131
|
+
event: (value) => new HelixSelectEvent({ value: String(value) }),
|
|
132
|
+
host: this,
|
|
133
|
+
next: nearest,
|
|
134
|
+
});
|
|
135
|
+
if (!moved) {
|
|
136
|
+
this.updateComplete.then(() => this.scrollToIndex());
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
this.handleDragStart = (event) => {
|
|
140
|
+
if (this.mouseDrag) {
|
|
141
|
+
event.preventDefault();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
78
144
|
this.handleTrackScroll = () => {
|
|
79
145
|
if (this.settling || this.scrollFrame) {
|
|
80
146
|
return;
|
|
@@ -92,6 +158,9 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
92
158
|
this.settling = false;
|
|
93
159
|
return;
|
|
94
160
|
}
|
|
161
|
+
if (this.dragging) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
95
164
|
this.showing = undefined;
|
|
96
165
|
const nearest = this.nearest();
|
|
97
166
|
if (nearest === undefined) {
|
|
@@ -169,6 +238,14 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
169
238
|
handed() {
|
|
170
239
|
return this.fits ? nothing : `--carousel-per-view: ${this.clamped}`;
|
|
171
240
|
}
|
|
241
|
+
trackStyle() {
|
|
242
|
+
const handed = this.handed();
|
|
243
|
+
if (!this.dragging) {
|
|
244
|
+
return handed;
|
|
245
|
+
}
|
|
246
|
+
const off = 'scroll-snap-type: none !important';
|
|
247
|
+
return handed === nothing ? off : `${handed}; ${off}`;
|
|
248
|
+
}
|
|
172
249
|
watchPane() {
|
|
173
250
|
if (!this.fits || typeof ResizeObserver === 'undefined') {
|
|
174
251
|
this.sizes?.disconnect();
|
|
@@ -193,7 +270,10 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
193
270
|
return [...(this.renderRoot?.querySelectorAll?.('[part="slide"]') ?? [])];
|
|
194
271
|
}
|
|
195
272
|
get slides() {
|
|
196
|
-
return this.knownChildren.filter((child) => child instanceof HTMLElement);
|
|
273
|
+
return this.knownChildren.filter((child) => child instanceof HTMLElement && !ICON_SLOTS.includes(child.slot));
|
|
274
|
+
}
|
|
275
|
+
iconsFor(name) {
|
|
276
|
+
return this.knownChildren.filter((child) => child.slot === name);
|
|
197
277
|
}
|
|
198
278
|
applyIndex(value) {
|
|
199
279
|
const previous = this.index;
|
|
@@ -251,6 +331,18 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
251
331
|
this.settling = true;
|
|
252
332
|
track.scrollTo({ behavior: still ? 'instant' : 'smooth', ...at });
|
|
253
333
|
}
|
|
334
|
+
swallowClick() {
|
|
335
|
+
const track = this.partNamed('track');
|
|
336
|
+
if (!track) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const swallow = (event) => {
|
|
340
|
+
event.preventDefault();
|
|
341
|
+
event.stopPropagation();
|
|
342
|
+
};
|
|
343
|
+
track.addEventListener('click', swallow, { capture: true, once: true });
|
|
344
|
+
setTimeout(() => track.removeEventListener('click', swallow, { capture: true }));
|
|
345
|
+
}
|
|
254
346
|
stop() {
|
|
255
347
|
this.stopped = true;
|
|
256
348
|
this.rotating = false;
|
|
@@ -324,7 +416,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
324
416
|
this.fitted = undefined;
|
|
325
417
|
}
|
|
326
418
|
hostAria(this.internals, { label: this.label, role: 'group' });
|
|
327
|
-
this.internals.ariaRoleDescription =
|
|
419
|
+
this.internals.ariaRoleDescription = this.roleLabel || null;
|
|
328
420
|
}
|
|
329
421
|
firstUpdated(changed) {
|
|
330
422
|
super.firstUpdated(changed);
|
|
@@ -342,6 +434,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
342
434
|
this.holdIndex();
|
|
343
435
|
this.watchPane();
|
|
344
436
|
this.assign();
|
|
437
|
+
this.toggleState('dragging', this.dragging);
|
|
345
438
|
}
|
|
346
439
|
assign() {
|
|
347
440
|
if (this.assignsByName) {
|
|
@@ -350,6 +443,11 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
350
443
|
});
|
|
351
444
|
return;
|
|
352
445
|
}
|
|
446
|
+
for (const name of ICON_SLOTS) {
|
|
447
|
+
this.renderRoot
|
|
448
|
+
?.querySelector?.(`slot[name="${name}"]`)
|
|
449
|
+
?.assign?.(...this.iconsFor(name));
|
|
450
|
+
}
|
|
353
451
|
const panes = this.renderRoot?.querySelectorAll?.('[part="slide"] slot');
|
|
354
452
|
if (!panes) {
|
|
355
453
|
return;
|
|
@@ -372,6 +470,20 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
372
470
|
}
|
|
373
471
|
return side === 'start' ? this.index <= 0 : this.index >= this.positions - 1;
|
|
374
472
|
}
|
|
473
|
+
renderPreviousMark() {
|
|
474
|
+
return html `<slot name="previous-icon"
|
|
475
|
+
><svg part="previous-mark" data-mirror fill="currentColor" viewBox=${caretLeft.viewBox} aria-hidden="true">
|
|
476
|
+
${unsafeSVG(caretLeft.content)}
|
|
477
|
+
</svg></slot
|
|
478
|
+
>`;
|
|
479
|
+
}
|
|
480
|
+
renderNextMark() {
|
|
481
|
+
return html `<slot name="next-icon"
|
|
482
|
+
><svg part="next-mark" data-mirror fill="currentColor" viewBox=${caretRight.viewBox} aria-hidden="true">
|
|
483
|
+
${unsafeSVG(caretRight.content)}
|
|
484
|
+
</svg></slot
|
|
485
|
+
>`;
|
|
486
|
+
}
|
|
375
487
|
render() {
|
|
376
488
|
const rotating = this.rotating;
|
|
377
489
|
const last = this.slides.length - 1;
|
|
@@ -401,9 +513,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
401
513
|
aria-disabled=${this.atEnd('start') ? 'true' : nothing}
|
|
402
514
|
@click=${() => this.goTo(this.index - 1)}
|
|
403
515
|
>
|
|
404
|
-
|
|
405
|
-
${unsafeSVG(caretLeft.content)}
|
|
406
|
-
</svg>
|
|
516
|
+
${this.renderPreviousMark()}
|
|
407
517
|
</button>
|
|
408
518
|
<button
|
|
409
519
|
part="next"
|
|
@@ -412,25 +522,28 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
412
522
|
aria-disabled=${this.atEnd('end') ? 'true' : nothing}
|
|
413
523
|
@click=${() => this.goTo(this.index + 1)}
|
|
414
524
|
>
|
|
415
|
-
|
|
416
|
-
${unsafeSVG(caretRight.content)}
|
|
417
|
-
</svg>
|
|
525
|
+
${this.renderNextMark()}
|
|
418
526
|
</button>`}
|
|
419
527
|
</div>
|
|
420
528
|
<div
|
|
421
529
|
data-scroller
|
|
422
530
|
part="track"
|
|
423
|
-
style=${this.
|
|
531
|
+
style=${this.trackStyle()}
|
|
424
532
|
@scroll=${this.handleTrackScroll}
|
|
425
533
|
@scrollend=${this.handleScroll}
|
|
426
|
-
@pointerdown=${this.
|
|
534
|
+
@pointerdown=${this.handlePress}
|
|
535
|
+
@pointermove=${this.handlePull}
|
|
536
|
+
@pointerup=${this.handleLetGo}
|
|
537
|
+
@pointercancel=${this.handleLetGo}
|
|
538
|
+
@lostpointercapture=${this.handleLetGo}
|
|
539
|
+
@dragstart=${this.handleDragStart}
|
|
427
540
|
@touchstart=${this.handleTake}
|
|
428
541
|
@wheel=${this.handleTake}
|
|
429
542
|
>
|
|
430
543
|
${this.slides.map((_, index) => html `<div
|
|
431
544
|
part="slide"
|
|
432
545
|
role="group"
|
|
433
|
-
aria-roledescription=${this.slideRoleLabel}
|
|
546
|
+
aria-roledescription=${this.slideRoleLabel || nothing}
|
|
434
547
|
aria-label=${fillTemplate(this.slideLabel, { count: this.slides.length, index: index + 1 })}
|
|
435
548
|
style=${index === last ? this.runEnd() : nothing}
|
|
436
549
|
>
|
|
@@ -488,6 +601,9 @@ __decorate([
|
|
|
488
601
|
__decorate([
|
|
489
602
|
property({ type: Boolean })
|
|
490
603
|
], HelixHeadlessCarousel.prototype, "loop", void 0);
|
|
604
|
+
__decorate([
|
|
605
|
+
property({ attribute: 'mouse-drag', reflect: true, type: Boolean })
|
|
606
|
+
], HelixHeadlessCarousel.prototype, "mouseDrag", void 0);
|
|
491
607
|
__decorate([
|
|
492
608
|
property({ attribute: 'next-label' })
|
|
493
609
|
], HelixHeadlessCarousel.prototype, "nextLabel", void 0);
|
|
@@ -503,6 +619,9 @@ __decorate([
|
|
|
503
619
|
__decorate([
|
|
504
620
|
property({ attribute: 'previous-label' })
|
|
505
621
|
], HelixHeadlessCarousel.prototype, "previousLabel", void 0);
|
|
622
|
+
__decorate([
|
|
623
|
+
property({ attribute: 'role-label' })
|
|
624
|
+
], HelixHeadlessCarousel.prototype, "roleLabel", void 0);
|
|
506
625
|
__decorate([
|
|
507
626
|
property({ attribute: 'slide-label' })
|
|
508
627
|
], HelixHeadlessCarousel.prototype, "slideLabel", void 0);
|
|
@@ -518,6 +637,9 @@ __decorate([
|
|
|
518
637
|
__decorate([
|
|
519
638
|
state()
|
|
520
639
|
], HelixHeadlessCarousel.prototype, "fitted", void 0);
|
|
640
|
+
__decorate([
|
|
641
|
+
state()
|
|
642
|
+
], HelixHeadlessCarousel.prototype, "dragging", void 0);
|
|
521
643
|
__decorate([
|
|
522
644
|
state()
|
|
523
645
|
], HelixHeadlessCarousel.prototype, "showing", void 0);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HelixFormElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
/**
|
|
4
4
|
* @summary A field for writing a turn in a conversation.
|
|
@@ -15,6 +15,16 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
15
15
|
* The composer clears only when no listener cancels the send, so the text is
|
|
16
16
|
* kept when you cancel a send that failed.
|
|
17
17
|
*
|
|
18
|
+
* **In a form, the draft is the composer's value**, submitted under `name`. A
|
|
19
|
+
* form reset puts back the `value` the markup declared, and a `<fieldset
|
|
20
|
+
* disabled>` turns the composer off. Sending is still `helix-send`, and it
|
|
21
|
+
* does not submit the form.
|
|
22
|
+
*
|
|
23
|
+
* **`typing` says whether the user is writing**, and `helix-typing` is sent
|
|
24
|
+
* each time it changes: when they start, and when they send or stop for
|
|
25
|
+
* `typing-timeout` milliseconds. Pass it on to show "is typing" to the other
|
|
26
|
+
* side.
|
|
27
|
+
*
|
|
18
28
|
* @since 0.1.0
|
|
19
29
|
* @status stable
|
|
20
30
|
* @category forms
|
|
@@ -25,6 +35,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
25
35
|
* @slot start - Content under the field at the leading edge, such as an attachment button or a model picker.
|
|
26
36
|
*
|
|
27
37
|
* @event {HelixSendEvent} helix-send - Fired when the user sends their turn, and cancelable.
|
|
38
|
+
* @event {HelixTypingEvent} helix-typing - The user started or stopped writing, with `typing` saying which, as the composer's `typing` does.
|
|
28
39
|
* @event {Event} input - The user changed the text. Read it from `value`, for a typing indicator or a saved draft. Sent on the composer and does not bubble.
|
|
29
40
|
*
|
|
30
41
|
* @csspart composer - The whole composer.
|
|
@@ -35,11 +46,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
35
46
|
* @csspart start - The box around the `start` slot.
|
|
36
47
|
* @csspart tools - The row under the field.
|
|
37
48
|
*/
|
|
38
|
-
export declare class HelixHeadlessChatComposer extends
|
|
39
|
-
/**
|
|
40
|
-
* Whether the composer blocks input, such as while a turn is being sent.
|
|
41
|
-
*/
|
|
42
|
-
disabled: boolean;
|
|
49
|
+
export declare class HelixHeadlessChatComposer extends HelixFormElement {
|
|
43
50
|
/**
|
|
44
51
|
* The field's name, read by screen readers.
|
|
45
52
|
*/
|
|
@@ -67,6 +74,11 @@ export declare class HelixHeadlessChatComposer extends HelixElement {
|
|
|
67
74
|
* has to mean a new line and nothing else.
|
|
68
75
|
*/
|
|
69
76
|
submitOn: 'button' | 'enter';
|
|
77
|
+
/**
|
|
78
|
+
* How long after the last keystroke the user still counts as typing, in
|
|
79
|
+
* milliseconds.
|
|
80
|
+
*/
|
|
81
|
+
typingTimeout: number;
|
|
70
82
|
/**
|
|
71
83
|
* The text the user has written.
|
|
72
84
|
*
|
|
@@ -78,6 +90,17 @@ export declare class HelixHeadlessChatComposer extends HelixElement {
|
|
|
78
90
|
* @internal Read by the transcript to find the composer among its children.
|
|
79
91
|
*/
|
|
80
92
|
readonly isChatComposer = true;
|
|
93
|
+
/** Whether the user is writing, which `helix-typing` announces. */
|
|
94
|
+
private writing;
|
|
95
|
+
/** The pause after which the user has stopped writing. */
|
|
96
|
+
private readonly pause;
|
|
97
|
+
/**
|
|
98
|
+
* Whether the user is writing: true from their first keystroke until they
|
|
99
|
+
* send, clear the field, or pause for `typing-timeout` milliseconds.
|
|
100
|
+
*/
|
|
101
|
+
get typing(): boolean;
|
|
102
|
+
/** Records whether the user is writing, and says so when that changed. */
|
|
103
|
+
private markTyping;
|
|
81
104
|
/**
|
|
82
105
|
* Sends what is written, and returns whether the send went through.
|
|
83
106
|
*
|
|
@@ -86,6 +109,15 @@ export declare class HelixHeadlessChatComposer extends HelixElement {
|
|
|
86
109
|
* a reasonable way to send.
|
|
87
110
|
*/
|
|
88
111
|
send(): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* The value the markup declared, which a form reset and an empty restore go
|
|
114
|
+
* back to. `value` does not reflect, so its attribute stays as written.
|
|
115
|
+
*/
|
|
116
|
+
private get declared();
|
|
117
|
+
/** Puts back the draft the markup declared when the form is reset. */
|
|
118
|
+
formResetCallback(): void;
|
|
119
|
+
/** Brings back the draft when the browser restores the form. */
|
|
120
|
+
formStateRestoreCallback(state: string | File | FormData | null): void;
|
|
89
121
|
/**
|
|
90
122
|
* Says on each tool box whether anything is in it.
|
|
91
123
|
*
|
|
@@ -4,27 +4,30 @@ 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,
|
|
7
|
+
import { customElement, DelayController, HelixFormElement, HelixSendEvent, HelixTypingEvent, hostAria, markRegion, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { arrowElbowDownLeft } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
11
11
|
import { live } from 'lit/directives/live.js';
|
|
12
12
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
13
|
-
let HelixHeadlessChatComposer = class HelixHeadlessChatComposer extends
|
|
13
|
+
let HelixHeadlessChatComposer = class HelixHeadlessChatComposer extends HelixFormElement {
|
|
14
14
|
constructor() {
|
|
15
15
|
super(...arguments);
|
|
16
|
-
this.disabled = false;
|
|
17
16
|
this.label = 'Message';
|
|
18
17
|
this.placeholder = '';
|
|
19
18
|
this.rows = 1;
|
|
20
19
|
this.sendLabel = 'Send';
|
|
21
20
|
this.submitOn = 'enter';
|
|
21
|
+
this.typingTimeout = 3000;
|
|
22
22
|
this.value = '';
|
|
23
23
|
this.isChatComposer = true;
|
|
24
|
+
this.writing = false;
|
|
25
|
+
this.pause = new DelayController(this, { renders: false });
|
|
24
26
|
this.handleInput = (event) => {
|
|
25
27
|
event.stopPropagation();
|
|
26
28
|
this.value = event.target.value;
|
|
27
29
|
this.dispatchEvent(new Event('input'));
|
|
30
|
+
this.markTyping(this.value !== '');
|
|
28
31
|
};
|
|
29
32
|
this.handleSend = () => {
|
|
30
33
|
this.send();
|
|
@@ -40,17 +43,44 @@ let HelixHeadlessChatComposer = class HelixHeadlessChatComposer extends HelixEle
|
|
|
40
43
|
this.send();
|
|
41
44
|
};
|
|
42
45
|
}
|
|
46
|
+
get typing() {
|
|
47
|
+
return this.writing;
|
|
48
|
+
}
|
|
49
|
+
markTyping(typing) {
|
|
50
|
+
if (typing) {
|
|
51
|
+
this.pause.start(Math.max(0, this.typingTimeout), () => this.markTyping(false));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.pause.cancel();
|
|
55
|
+
}
|
|
56
|
+
if (typing === this.writing) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.writing = typing;
|
|
60
|
+
this.dispatchEvent(new HelixTypingEvent({ typing }));
|
|
61
|
+
}
|
|
43
62
|
send() {
|
|
44
63
|
const value = this.value.trim();
|
|
45
|
-
if (value === '' || this.
|
|
64
|
+
if (value === '' || this.isDisabled) {
|
|
46
65
|
return false;
|
|
47
66
|
}
|
|
48
67
|
if (!this.dispatchEvent(new HelixSendEvent({ value }))) {
|
|
49
68
|
return false;
|
|
50
69
|
}
|
|
51
70
|
this.value = '';
|
|
71
|
+
this.markTyping(false);
|
|
52
72
|
return true;
|
|
53
73
|
}
|
|
74
|
+
get declared() {
|
|
75
|
+
return this.getAttribute('value') ?? '';
|
|
76
|
+
}
|
|
77
|
+
formResetCallback() {
|
|
78
|
+
super.formResetCallback();
|
|
79
|
+
this.value = this.declared;
|
|
80
|
+
}
|
|
81
|
+
formStateRestoreCallback(state) {
|
|
82
|
+
this.value = typeof state === 'string' ? state : this.declared;
|
|
83
|
+
}
|
|
54
84
|
markEmpty() {
|
|
55
85
|
for (const name of ['start', 'end']) {
|
|
56
86
|
markRegion(this.renderRoot, name, [name]);
|
|
@@ -59,6 +89,9 @@ let HelixHeadlessChatComposer = class HelixHeadlessChatComposer extends HelixEle
|
|
|
59
89
|
updated(changed) {
|
|
60
90
|
super.updated(changed);
|
|
61
91
|
this.markEmpty();
|
|
92
|
+
if (changed.has('value')) {
|
|
93
|
+
this.internals.setFormValue(this.value === '' ? null : this.value);
|
|
94
|
+
}
|
|
62
95
|
}
|
|
63
96
|
willUpdate(changed) {
|
|
64
97
|
super.willUpdate(changed);
|
|
@@ -69,7 +102,7 @@ let HelixHeadlessChatComposer = class HelixHeadlessChatComposer extends HelixEle
|
|
|
69
102
|
part="send"
|
|
70
103
|
type="button"
|
|
71
104
|
aria-label=${this.sendLabel}
|
|
72
|
-
?disabled=${this.
|
|
105
|
+
?disabled=${this.isDisabled}
|
|
73
106
|
@click=${this.handleSend}
|
|
74
107
|
>
|
|
75
108
|
<svg
|
|
@@ -90,7 +123,7 @@ let HelixHeadlessChatComposer = class HelixHeadlessChatComposer extends HelixEle
|
|
|
90
123
|
aria-label=${this.label}
|
|
91
124
|
placeholder=${this.placeholder}
|
|
92
125
|
rows=${this.rows}
|
|
93
|
-
?disabled=${this.
|
|
126
|
+
?disabled=${this.isDisabled}
|
|
94
127
|
@input=${this.handleInput}
|
|
95
128
|
@keydown=${this.handleKey}
|
|
96
129
|
></textarea>
|
|
@@ -102,9 +135,6 @@ let HelixHeadlessChatComposer = class HelixHeadlessChatComposer extends HelixEle
|
|
|
102
135
|
</div>`;
|
|
103
136
|
}
|
|
104
137
|
};
|
|
105
|
-
__decorate([
|
|
106
|
-
property({ reflect: true, type: Boolean })
|
|
107
|
-
], HelixHeadlessChatComposer.prototype, "disabled", void 0);
|
|
108
138
|
__decorate([
|
|
109
139
|
property()
|
|
110
140
|
], HelixHeadlessChatComposer.prototype, "label", void 0);
|
|
@@ -120,6 +150,9 @@ __decorate([
|
|
|
120
150
|
__decorate([
|
|
121
151
|
property({ attribute: 'submit-on' })
|
|
122
152
|
], HelixHeadlessChatComposer.prototype, "submitOn", void 0);
|
|
153
|
+
__decorate([
|
|
154
|
+
property({ attribute: 'typing-timeout', type: Number })
|
|
155
|
+
], HelixHeadlessChatComposer.prototype, "typingTimeout", void 0);
|
|
123
156
|
__decorate([
|
|
124
157
|
property()
|
|
125
158
|
], HelixHeadlessChatComposer.prototype, "value", void 0);
|
|
@@ -19,6 +19,13 @@ export declare const FAILED_LABEL = "Not sent";
|
|
|
19
19
|
* and announced once when it settles. A screen reader cannot follow a stream
|
|
20
20
|
* read out character by character.
|
|
21
21
|
*
|
|
22
|
+
* A screen reader names the turn by its author and its time, such as "You, 2
|
|
23
|
+
* minutes ago". The author is `author-label`, or "You" for `me`, or the
|
|
24
|
+
* `author` itself where it is a name; give a turn by `them` an `author-label`
|
|
25
|
+
* to name it. The chat it sits in holds the sentence and the word for `me`, so
|
|
26
|
+
* a page in another language sets them once there. The time moves on by
|
|
27
|
+
* itself, so "now" becomes "1 minute ago" while the page is open.
|
|
28
|
+
*
|
|
22
29
|
* @since 0.1.0
|
|
23
30
|
* @status stable
|
|
24
31
|
* @category feedback
|
|
@@ -62,6 +69,14 @@ export declare class HelixHeadlessChatMessage extends HelixElement {
|
|
|
62
69
|
* anything else is a name the consumer styles.
|
|
63
70
|
*/
|
|
64
71
|
author?: string;
|
|
72
|
+
/**
|
|
73
|
+
* The author's name, as a screen reader says it at the start of the turn,
|
|
74
|
+
* such as "Support" or "Ada Lovelace".
|
|
75
|
+
*
|
|
76
|
+
* Empty reads "You" for `me`, the `author` itself where it is a name, and
|
|
77
|
+
* nothing for `them`.
|
|
78
|
+
*/
|
|
79
|
+
authorLabel: string;
|
|
65
80
|
/**
|
|
66
81
|
* Label for a message that did not send.
|
|
67
82
|
*/
|
|
@@ -93,15 +108,31 @@ export declare class HelixHeadlessChatMessage extends HelixElement {
|
|
|
93
108
|
* holds the reason. Everything else that moves it is the consumer's.
|
|
94
109
|
*/
|
|
95
110
|
state?: 'failed' | 'sending' | 'sent' | 'streaming';
|
|
111
|
+
/**
|
|
112
|
+
* @internal Set by the chat: the word for `me` and the sentence that names a
|
|
113
|
+
* turn with both an author and a time, in the chat's language.
|
|
114
|
+
*/
|
|
115
|
+
turnWords: import("../naming.js").TurnWords;
|
|
96
116
|
/**
|
|
97
117
|
* @internal Read by the transcript to identify its children across the light
|
|
98
118
|
* DOM, which is cheaper than `instanceof`. Not a consumer's to read or set.
|
|
99
119
|
*/
|
|
100
120
|
readonly isChatMessage = true;
|
|
101
|
-
|
|
121
|
+
/** The time the reading is drawn against, moved on when the words go stale. */
|
|
122
|
+
private readonly clock;
|
|
102
123
|
/** The timestamp, or nothing where there is not one to read. */
|
|
103
124
|
private get moment();
|
|
104
125
|
protected willUpdate(changed: PropertyValues): void;
|
|
126
|
+
/** The time as it reads now, or nothing where the turn has none. */
|
|
127
|
+
private get reading();
|
|
128
|
+
/**
|
|
129
|
+
* What a screen reader calls the turn: who wrote it, and when.
|
|
130
|
+
*
|
|
131
|
+
* **The name of an `article` is never its content**, so without one a reader
|
|
132
|
+
* moving through a transcript heard "article" for every turn and had to read
|
|
133
|
+
* each to learn who wrote it.
|
|
134
|
+
*/
|
|
135
|
+
private get name();
|
|
105
136
|
private renderTime;
|
|
106
137
|
/**
|
|
107
138
|
* The status glyph, behind a seam so a tier can draw its own.
|
|
@@ -6,19 +6,26 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { customElement, HelixElement, HelixSendEvent, hostAria, markRegion, relativeTime, requestChange, TONE_MARKS, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
|
-
import { property
|
|
9
|
+
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
11
|
+
import { authorWords, TURN_WORDS, turnName } from '../naming.js';
|
|
12
|
+
import { RelativeClockController } from '../relative-clock.js';
|
|
11
13
|
export const FAILED_LABEL = 'Not sent';
|
|
12
14
|
let HelixHeadlessChatMessage = class HelixHeadlessChatMessage extends HelixElement {
|
|
13
15
|
constructor() {
|
|
14
16
|
super(...arguments);
|
|
15
17
|
this.at = '';
|
|
18
|
+
this.authorLabel = '';
|
|
16
19
|
this.failedLabel = FAILED_LABEL;
|
|
17
20
|
this.locale = '';
|
|
18
21
|
this.retryLabel = 'Try again';
|
|
19
22
|
this.sendingLabel = 'Sending';
|
|
23
|
+
this.turnWords = TURN_WORDS;
|
|
20
24
|
this.isChatMessage = true;
|
|
21
|
-
this.clock =
|
|
25
|
+
this.clock = new RelativeClockController(this, {
|
|
26
|
+
locale: () => this.locale,
|
|
27
|
+
moment: () => this.moment,
|
|
28
|
+
});
|
|
22
29
|
this.handleFill = () => {
|
|
23
30
|
this.markEmpty();
|
|
24
31
|
};
|
|
@@ -50,19 +57,25 @@ let HelixHeadlessChatMessage = class HelixHeadlessChatMessage extends HelixEleme
|
|
|
50
57
|
}
|
|
51
58
|
willUpdate(changed) {
|
|
52
59
|
super.willUpdate(changed);
|
|
53
|
-
if (changed.has('at')) {
|
|
54
|
-
this.clock
|
|
60
|
+
if (changed.has('at') || changed.has('locale')) {
|
|
61
|
+
this.clock.tick();
|
|
55
62
|
}
|
|
56
|
-
hostAria(this.internals, { role: 'article' });
|
|
63
|
+
hostAria(this.internals, { label: this.name, role: 'article' });
|
|
57
64
|
this.internals.ariaBusy = this.state === 'streaming' ? 'true' : null;
|
|
58
65
|
}
|
|
66
|
+
get reading() {
|
|
67
|
+
const moment = this.moment;
|
|
68
|
+
return moment ? relativeTime(this.locale)(moment, new Date(this.clock.now)).text : '';
|
|
69
|
+
}
|
|
70
|
+
get name() {
|
|
71
|
+
return turnName(authorWords(this.author, this.authorLabel, this.turnWords), this.reading, this.turnWords);
|
|
72
|
+
}
|
|
59
73
|
renderTime() {
|
|
60
74
|
const moment = this.moment;
|
|
61
75
|
if (!moment) {
|
|
62
76
|
return nothing;
|
|
63
77
|
}
|
|
64
|
-
|
|
65
|
-
return html `<time part="time" datetime=${moment.toISOString()}>${text}</time>`;
|
|
78
|
+
return html `<time part="time" datetime=${moment.toISOString()}>${this.reading}</time>`;
|
|
66
79
|
}
|
|
67
80
|
renderMark() {
|
|
68
81
|
const { icon, label } = TONE_MARKS.danger;
|
|
@@ -124,6 +137,9 @@ __decorate([
|
|
|
124
137
|
__decorate([
|
|
125
138
|
property({ reflect: true })
|
|
126
139
|
], HelixHeadlessChatMessage.prototype, "author", void 0);
|
|
140
|
+
__decorate([
|
|
141
|
+
property({ attribute: 'author-label' })
|
|
142
|
+
], HelixHeadlessChatMessage.prototype, "authorLabel", void 0);
|
|
127
143
|
__decorate([
|
|
128
144
|
property({ attribute: 'failed-label' })
|
|
129
145
|
], HelixHeadlessChatMessage.prototype, "failedLabel", void 0);
|
|
@@ -140,8 +156,8 @@ __decorate([
|
|
|
140
156
|
property({ reflect: true })
|
|
141
157
|
], HelixHeadlessChatMessage.prototype, "state", void 0);
|
|
142
158
|
__decorate([
|
|
143
|
-
|
|
144
|
-
], HelixHeadlessChatMessage.prototype, "
|
|
159
|
+
property({ attribute: false })
|
|
160
|
+
], HelixHeadlessChatMessage.prototype, "turnWords", void 0);
|
|
145
161
|
HelixHeadlessChatMessage = __decorate([
|
|
146
162
|
customElement('helix-headless-chat-message')
|
|
147
163
|
], HelixHeadlessChatMessage);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** What the chat names its turns with, which it hands to each of them. */
|
|
2
|
+
export interface TurnWords {
|
|
3
|
+
/** The word for `me`, such as "You". */
|
|
4
|
+
me: string;
|
|
5
|
+
/** The sentence for a turn with an author and a time, with `{author}` and `{time}`. */
|
|
6
|
+
sentence: string;
|
|
7
|
+
}
|
|
8
|
+
/** The words a chat says its turns with, where nobody said otherwise. */
|
|
9
|
+
export declare const TURN_WORDS: TurnWords;
|
|
10
|
+
/**
|
|
11
|
+
* Who wrote a turn, in words: its `author-label`, or else the chat's word for
|
|
12
|
+
* `me`, or else the `author` itself where it is a name.
|
|
13
|
+
*
|
|
14
|
+
* `them` is the other side of a two-sided conversation and not a name, so it
|
|
15
|
+
* says nothing until it is given an `author-label`.
|
|
16
|
+
*/
|
|
17
|
+
export declare const authorWords: (author: string | undefined, authorLabel: string, words: TurnWords) => string;
|
|
18
|
+
/**
|
|
19
|
+
* The turn's accessible name: the sentence where it has an author and a time,
|
|
20
|
+
* and whichever of the two it has otherwise. Empty where it has neither.
|
|
21
|
+
*/
|
|
22
|
+
export declare const turnName: (author: string, time: string, words: TurnWords) => string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { fillTemplate } from '@fusion.dev/helix-core';
|
|
2
|
+
export const TURN_WORDS = { me: 'You', sentence: '{author}, {time}' };
|
|
3
|
+
export const authorWords = (author, authorLabel, words) => {
|
|
4
|
+
if (authorLabel !== '') {
|
|
5
|
+
return authorLabel;
|
|
6
|
+
}
|
|
7
|
+
if (author === 'me') {
|
|
8
|
+
return words.me;
|
|
9
|
+
}
|
|
10
|
+
return author === undefined || author === 'them' ? '' : author;
|
|
11
|
+
};
|
|
12
|
+
export const turnName = (author, time, words) => author !== '' && time !== '' ? fillTemplate(words.sentence, { author, time }) : author || time;
|