@fusion.dev/helix-headless 0.145.0 → 0.146.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +7373 -3849
- package/dist/accordion/item/accordion-item.d.ts +14 -0
- package/dist/accordion/item/accordion-item.js +16 -6
- package/dist/accordion/root/accordion-root.d.ts +8 -5
- package/dist/announcement/root/announcement-root.d.ts +3 -2
- package/dist/announcement/root/announcement-root.js +3 -1
- package/dist/app-header/root/app-header-root.d.ts +7 -2
- package/dist/app-header/root/app-header-root.js +9 -1
- package/dist/app-header/sectioning.d.ts +3 -1
- package/dist/app-header/sectioning.js +3 -2
- package/dist/avatar/group/avatar-group.d.ts +20 -14
- package/dist/avatar/group/avatar-group.js +17 -19
- package/dist/badge/root/badge-root.d.ts +3 -1
- package/dist/badge/root/badge-root.js +2 -2
- package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
- package/dist/bar-chart/root/bar-chart-root.js +52 -15
- package/dist/bar-chart/stack.d.ts +15 -0
- package/dist/bar-chart/stack.js +19 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +25 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.js +50 -3
- package/dist/button/root/button-root.d.ts +26 -0
- package/dist/button/root/button-root.js +38 -18
- package/dist/button-group/root/button-group-root.d.ts +2 -1
- package/dist/button-group/root/button-group-root.js +5 -1
- package/dist/canvas/node/canvas-node.d.ts +4 -3
- package/dist/canvas/node/canvas-node.js +3 -2
- package/dist/canvas/root/canvas-root.js +2 -2
- package/dist/card/root/card-root.d.ts +24 -3
- package/dist/card/root/card-root.js +20 -8
- package/dist/carousel/root/carousel-root.d.ts +43 -4
- package/dist/carousel/root/carousel-root.js +40 -12
- package/dist/carousel/stops.d.ts +20 -0
- package/dist/carousel/stops.js +30 -0
- package/dist/chat/message/chat-message.js +5 -4
- package/dist/chat/naming.d.ts +5 -1
- package/dist/chat/naming.js +4 -2
- package/dist/chat/root/chat-root.d.ts +25 -3
- package/dist/chat/root/chat-root.js +22 -5
- package/dist/checkbox/root/checkbox-root.d.ts +20 -0
- package/dist/checkbox/root/checkbox-root.js +14 -1
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
- package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
- package/dist/checkbox-group/select-all.d.ts +27 -0
- package/dist/checkbox-group/select-all.js +12 -0
- package/dist/code-block/highlight.d.ts +15 -0
- package/dist/code-block/highlight.js +4 -0
- package/dist/code-block/root/code-block-root.d.ts +49 -1
- package/dist/code-block/root/code-block-root.js +58 -3
- package/dist/color-input/root/color-input-root.d.ts +3 -0
- package/dist/color-input/root/color-input-root.js +6 -3
- package/dist/color-picker/root/color-picker-root.d.ts +33 -4
- package/dist/color-picker/root/color-picker-root.js +80 -21
- package/dist/color-picker/swatches.d.ts +12 -0
- package/dist/color-picker/swatches.js +26 -0
- package/dist/combobox/root/combobox-root.d.ts +43 -0
- package/dist/combobox/root/combobox-root.js +79 -15
- package/dist/command/root/command-root.d.ts +16 -1
- package/dist/command/root/command-root.js +22 -4
- package/dist/copy-button/root/copy-button-root.d.ts +5 -0
- package/dist/copy-button/root/copy-button-root.js +10 -3
- package/dist/data-table/index.d.ts +1 -1
- package/dist/data-table/index.js +1 -1
- package/dist/data-table/keys.d.ts +24 -0
- package/dist/data-table/keys.js +24 -0
- package/dist/data-table/root/data-table-root.d.ts +27 -18
- package/dist/data-table/root/data-table-root.js +20 -52
- package/dist/data-table/tree.d.ts +16 -1
- package/dist/data-table/tree.js +2 -3
- package/dist/date-input/root/date-input-root.d.ts +3 -1
- package/dist/date-input/root/date-input-root.js +18 -7
- package/dist/date-picker/root/date-picker-root.js +12 -6
- package/dist/dialog/description.js +15 -1
- package/dist/dialog/root/dialog-root.d.ts +8 -2
- package/dist/dialog/root/dialog-root.js +16 -1
- package/dist/divider/root/divider-root.d.ts +3 -0
- package/dist/divider/root/divider-root.js +2 -1
- package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
- package/dist/donut-chart/root/donut-chart-root.js +48 -1
- package/dist/drawer/reveal.d.ts +8 -0
- package/dist/drawer/reveal.js +1 -0
- package/dist/drawer/root/drawer-root.d.ts +59 -0
- package/dist/drawer/root/drawer-root.js +63 -4
- package/dist/drilldown/item/drilldown-item.js +1 -1
- package/dist/drilldown/root/drilldown-root.d.ts +21 -3
- package/dist/drilldown/root/drilldown-root.js +21 -3
- package/dist/element-events.generated.js +31 -5
- package/dist/empty/root/empty-root.d.ts +3 -1
- package/dist/empty/root/empty-root.js +3 -2
- package/dist/file-input/root/file-input-root.d.ts +69 -6
- package/dist/file-input/root/file-input-root.js +82 -19
- package/dist/file-input/screen.d.ts +2 -1
- package/dist/filter-input/menu/filter-menu.d.ts +2 -0
- package/dist/filter-input/menu/filter-menu.js +12 -4
- package/dist/filter-input/root/filter-input-root.d.ts +30 -6
- package/dist/filter-input/root/filter-input-root.js +1 -1
- package/dist/filter-input/suggest.d.ts +28 -3
- package/dist/filter-input/suggest.js +18 -8
- package/dist/format-date/root/format-date-root.d.ts +9 -16
- package/dist/format-date/root/format-date-root.js +10 -27
- package/dist/heatmap/root/heatmap-root.d.ts +24 -13
- package/dist/heatmap/root/heatmap-root.js +34 -12
- package/dist/icon/root/icon-root.d.ts +12 -1
- package/dist/icon/root/icon-root.js +21 -10
- package/dist/icon/settle.d.ts +7 -0
- package/dist/icon/settle.js +10 -0
- package/dist/icon-button/root/icon-button-root.d.ts +2 -0
- package/dist/image/root/image-root.d.ts +5 -1
- package/dist/image/root/image-root.js +1 -1
- package/dist/input/root/input-root.d.ts +12 -2
- package/dist/input/root/input-root.js +11 -2
- package/dist/kbd/root/kbd-root.d.ts +35 -1
- package/dist/kbd/root/kbd-root.js +23 -4
- package/dist/legend/root/legend-root.d.ts +55 -8
- package/dist/legend/root/legend-root.js +55 -13
- package/dist/lightbox/root/lightbox-root.d.ts +49 -6
- package/dist/lightbox/root/lightbox-root.js +86 -19
- package/dist/lightbox/zoom-controller.d.ts +59 -0
- package/dist/lightbox/zoom-controller.js +128 -0
- package/dist/lightbox/zoom.d.ts +22 -0
- package/dist/lightbox/zoom.js +16 -0
- package/dist/line-chart/root/line-chart-root.d.ts +22 -1
- package/dist/line-chart/root/line-chart-root.js +21 -1
- package/dist/list/item/list-item.d.ts +2 -0
- package/dist/list/item/list-item.js +11 -2
- package/dist/list/root/list-root.d.ts +62 -13
- package/dist/list/root/list-root.js +70 -13
- package/dist/list/selection.d.ts +37 -7
- package/dist/list/selection.js +16 -7
- package/dist/listbox/root/listbox-root.d.ts +37 -1
- package/dist/listbox/root/listbox-root.js +49 -3
- package/dist/loader/busy.d.ts +10 -0
- package/dist/loader/busy.js +11 -0
- package/dist/loader/root/loader-root.d.ts +9 -2
- package/dist/loader/root/loader-root.js +23 -3
- package/dist/megamenu/root/megamenu-root.d.ts +51 -10
- package/dist/megamenu/root/megamenu-root.js +76 -5
- package/dist/menu/item/menu-item.d.ts +51 -2
- package/dist/menu/item/menu-item.js +47 -23
- package/dist/menu/root/menu-root.d.ts +14 -0
- package/dist/menu/root/menu-root.js +2 -2
- package/dist/meter/root/meter-root.d.ts +20 -1
- package/dist/meter/root/meter-root.js +11 -15
- package/dist/navigation/root/navigation-root.d.ts +2 -1
- package/dist/navigation/root/navigation-root.js +2 -2
- package/dist/notifications/root/notifications-root.d.ts +10 -3
- package/dist/notifications/root/notifications-root.js +19 -7
- package/dist/number-input/root/number-input-root.d.ts +17 -8
- package/dist/number-input/root/number-input-root.js +2 -7
- package/dist/object-inspector/root/object-inspector-root.d.ts +75 -27
- package/dist/object-inspector/root/object-inspector-root.js +117 -76
- package/dist/object-inspector/rows.d.ts +18 -0
- package/dist/object-inspector/rows.js +33 -0
- package/dist/option/root/option-root.d.ts +5 -3
- package/dist/outline/root/outline-root.d.ts +18 -0
- package/dist/outline/root/outline-root.js +23 -5
- package/dist/pagination/size/pagination-size.d.ts +1 -0
- package/dist/pagination/size/pagination-size.js +1 -1
- package/dist/pin-input/code.d.ts +10 -0
- package/dist/pin-input/code.js +13 -0
- package/dist/pin-input/root/pin-input-root.d.ts +25 -1
- package/dist/pin-input/root/pin-input-root.js +10 -11
- package/dist/popover/hide-outside.d.ts +14 -0
- package/dist/popover/hide-outside.js +41 -0
- package/dist/popover/root/popover-root.d.ts +57 -7
- package/dist/popover/root/popover-root.js +58 -3
- package/dist/progress/root/progress-root.d.ts +20 -0
- package/dist/progress/root/progress-root.js +15 -15
- package/dist/qr-code/export.d.ts +26 -1
- package/dist/qr-code/export.js +14 -0
- package/dist/qr-code/root/qr-code-root.d.ts +19 -5
- package/dist/qr-code/root/qr-code-root.js +58 -9
- package/dist/quote/marks.d.ts +8 -0
- package/dist/quote/marks.js +5 -0
- package/dist/quote/root/quote-root.d.ts +14 -2
- package/dist/quote/root/quote-root.js +23 -1
- package/dist/radio/root/radio-root.d.ts +6 -2
- package/dist/radio/root/radio-root.js +6 -1
- package/dist/rating/root/rating-root.d.ts +9 -4
- package/dist/rating/root/rating-root.js +31 -7
- package/dist/rating/steps.d.ts +7 -0
- package/dist/rating/steps.js +9 -0
- package/dist/scatter-chart/fit.d.ts +15 -0
- package/dist/scatter-chart/fit.js +35 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
- package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
- package/dist/scroll-area/root/scroll-area-root.d.ts +22 -51
- package/dist/scroll-area/root/scroll-area-root.js +57 -173
- package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
- package/dist/scroll-area/scrollbar-controller.js +172 -0
- package/dist/scroll-area/scrollbar.d.ts +27 -0
- package/dist/scroll-area/scrollbar.js +9 -0
- package/dist/select/root/select-root.d.ts +15 -0
- package/dist/select/root/select-root.js +18 -6
- package/dist/skeleton/root/skeleton-root.d.ts +3 -0
- package/dist/skeleton/root/skeleton-root.js +4 -2
- package/dist/skip-link/root/skip-link-root.js +2 -2
- package/dist/slider/root/slider-root.d.ts +41 -4
- package/dist/slider/root/slider-root.js +23 -3
- package/dist/sparkline/readings.d.ts +18 -0
- package/dist/sparkline/readings.js +19 -0
- package/dist/sparkline/root/sparkline-root.d.ts +78 -7
- package/dist/sparkline/root/sparkline-root.js +118 -23
- package/dist/speed-dial/root/speed-dial-root.js +2 -2
- package/dist/splitter/root/splitter-root.d.ts +7 -12
- package/dist/splitter/root/splitter-root.js +209 -204
- package/dist/stat/root/stat-root.d.ts +14 -5
- package/dist/stat/root/stat-root.js +21 -5
- package/dist/steps/reach.d.ts +5 -0
- package/dist/steps/reach.js +3 -0
- package/dist/steps/root/steps-root.d.ts +49 -3
- package/dist/steps/root/steps-root.js +44 -5
- package/dist/steps/step/step.d.ts +7 -0
- package/dist/steps/step/step.js +7 -2
- package/dist/switch/root/switch-root.d.ts +10 -0
- package/dist/table/column/table-column.d.ts +0 -10
- package/dist/table/column/table-column.js +3 -19
- package/dist/table/root/table-root.d.ts +31 -10
- package/dist/table/root/table-root.js +2 -13
- package/dist/tabs/panel/tab-panel.d.ts +16 -3
- package/dist/tabs/panel/tab-panel.js +34 -5
- package/dist/tabs/root/tabs-root.d.ts +12 -0
- package/dist/tabs/root/tabs-root.js +1 -1
- package/dist/tabs/tab/tab.d.ts +5 -0
- package/dist/tabs/tab/tab.js +5 -2
- package/dist/tag/group/tag-group.d.ts +31 -4
- package/dist/tag/group/tag-group.js +46 -7
- package/dist/tag/root/tag-root.js +9 -2
- package/dist/textarea/root/textarea-root.d.ts +28 -1
- package/dist/textarea/root/textarea-root.js +40 -1
- package/dist/time-input/root/time-input-root.d.ts +5 -1
- package/dist/time-input/root/time-input-root.js +16 -8
- package/dist/time-picker/root/time-picker-root.d.ts +18 -4
- package/dist/time-picker/root/time-picker-root.js +7 -10
- package/dist/time-picker/wheel-name.d.ts +9 -0
- package/dist/time-picker/wheel-name.js +15 -0
- package/dist/timeline/group/timeline-group.js +2 -2
- package/dist/toast/item/toast-item.d.ts +14 -1
- package/dist/toast/item/toast-item.js +22 -5
- package/dist/toast/root/toast-root.d.ts +6 -0
- package/dist/toast/root/toast-root.js +16 -1
- package/dist/toggle/group/toggle-group.d.ts +24 -3
- package/dist/toggle/group/toggle-group.js +34 -5
- package/dist/tooltip/root/tooltip-root.d.ts +13 -2
- package/dist/tooltip/root/tooltip-root.js +9 -1
- package/dist/tour/back.d.ts +10 -0
- package/dist/tour/back.js +8 -0
- package/dist/tour/root/tour-root.d.ts +30 -2
- package/dist/tour/root/tour-root.js +34 -8
- package/dist/tree/item/tree-item.d.ts +7 -3
- package/dist/tree/item/tree-item.js +3 -0
- package/dist/tree/root/tree-root.d.ts +24 -3
- package/dist/tree/root/tree-root.js +32 -13
- package/dist/tree/selection.js +2 -15
- package/dist/trend/root/trend-root.d.ts +43 -18
- package/dist/trend/root/trend-root.js +31 -6
- package/dist/video/media-events.d.ts +13 -18
- package/dist/video/media-events.js +1 -5
- package/dist/video/root/video-root.d.ts +18 -5
- package/dist/video/root/video-root.js +19 -10
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +2 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
- package/dist/video-playlist/root/video-playlist-root.d.ts +7 -1
- package/dist/virtual-list/fill.d.ts +0 -8
- package/dist/virtual-list/fill.js +1 -17
- package/dist/virtual-list/plan.d.ts +49 -0
- package/dist/virtual-list/plan.js +16 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +114 -13
- package/dist/virtual-list/root/virtual-list-root.js +183 -40
- package/lint.json +1 -1
- package/package.json +8 -8
- package/types/jsx.d.ts +4577 -835
- package/types/vue.d.ts +926 -168
- package/dist/chat/relative-clock.d.ts +0 -39
- package/dist/chat/relative-clock.js +0 -31
- package/dist/data-table/root/order.d.ts +0 -141
- package/dist/data-table/root/order.js +0 -76
- package/dist/tag/selection.d.ts +0 -10
- package/dist/tag/selection.js +0 -12
|
@@ -9,6 +9,7 @@ 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';
|
|
11
11
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
|
+
import { stepStop, stopFor, stopsOf } from '../stops.js';
|
|
12
13
|
const COUNT_OR_AUTO = {
|
|
13
14
|
fromAttribute: (value) => {
|
|
14
15
|
if (value === null) {
|
|
@@ -59,7 +60,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
59
60
|
? -1
|
|
60
61
|
: 0
|
|
61
62
|
: inlineStep(this, event.key);
|
|
62
|
-
let to
|
|
63
|
+
let to;
|
|
63
64
|
if (event.key === 'Home') {
|
|
64
65
|
to = 0;
|
|
65
66
|
}
|
|
@@ -69,6 +70,9 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
69
70
|
else if (step === 0) {
|
|
70
71
|
return;
|
|
71
72
|
}
|
|
73
|
+
else {
|
|
74
|
+
to = this.move(step);
|
|
75
|
+
}
|
|
72
76
|
event.preventDefault();
|
|
73
77
|
this.goTo(to);
|
|
74
78
|
this.updateComplete.then(() => {
|
|
@@ -213,6 +217,9 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
213
217
|
get positions() {
|
|
214
218
|
return Math.max(1, this.slides.length - (this.across ?? 1) + 1);
|
|
215
219
|
}
|
|
220
|
+
get stops() {
|
|
221
|
+
return stopsOf(this.positions, this.slidesPerMove);
|
|
222
|
+
}
|
|
216
223
|
measure() {
|
|
217
224
|
const track = this.partNamed('track');
|
|
218
225
|
const pane = this.panes[0]?.getBoundingClientRect().width;
|
|
@@ -281,6 +288,9 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
281
288
|
this.requestUpdate('index', previous);
|
|
282
289
|
this.dispatchEvent(new HelixActivateEvent({ value: String(value) }));
|
|
283
290
|
}
|
|
291
|
+
move(step) {
|
|
292
|
+
return stepStop(this.stops, this.index, step < 0 ? -1 : 1, this.loop);
|
|
293
|
+
}
|
|
284
294
|
goTo(index) {
|
|
285
295
|
if (this.slides.length === 0) {
|
|
286
296
|
return;
|
|
@@ -357,7 +367,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
357
367
|
if (!this.rotating || this.slides.length < 2) {
|
|
358
368
|
return;
|
|
359
369
|
}
|
|
360
|
-
this.timer = setInterval(() => this.goTo(this.index >= this.positions - 1 ? 0 : this.
|
|
370
|
+
this.timer = setInterval(() => this.goTo(this.index >= this.positions - 1 ? 0 : this.move(1)), this.interval);
|
|
361
371
|
}
|
|
362
372
|
nearest() {
|
|
363
373
|
const track = this.partNamed('track');
|
|
@@ -366,8 +376,11 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
366
376
|
}
|
|
367
377
|
const bleed = this.bleed(track);
|
|
368
378
|
const at = this.orientation === 'vertical' ? track.scrollTop : track.scrollLeft;
|
|
369
|
-
return this.
|
|
370
|
-
const
|
|
379
|
+
return this.stops.reduce((best, index) => {
|
|
380
|
+
const slide = this.panes[index];
|
|
381
|
+
const distance = slide
|
|
382
|
+
? Math.abs(this.edgeOf(slide, track, bleed) - at)
|
|
383
|
+
: Number.POSITIVE_INFINITY;
|
|
371
384
|
return distance < best.distance ? { distance, index } : best;
|
|
372
385
|
}, { distance: Number.POSITIVE_INFINITY, index: this.index }).index;
|
|
373
386
|
}
|
|
@@ -484,9 +497,21 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
484
497
|
</svg></slot
|
|
485
498
|
>`;
|
|
486
499
|
}
|
|
500
|
+
paneStyle(index, last, stops) {
|
|
501
|
+
const declared = [
|
|
502
|
+
index === last ? this.runEnd() : nothing,
|
|
503
|
+
(this.slidesPerMove ?? 1) > 1 && !stops.includes(index)
|
|
504
|
+
? 'scroll-snap-align: none !important'
|
|
505
|
+
: nothing,
|
|
506
|
+
].filter((one) => one !== nothing);
|
|
507
|
+
return declared.length > 0 ? declared.join('; ') : nothing;
|
|
508
|
+
}
|
|
487
509
|
render() {
|
|
488
510
|
const rotating = this.rotating;
|
|
489
511
|
const last = this.slides.length - 1;
|
|
512
|
+
const stops = this.stops;
|
|
513
|
+
const place = stopFor(stops, this.index);
|
|
514
|
+
const showing = stopFor(stops, this.showing ?? this.index);
|
|
490
515
|
return html `<div part="controls">
|
|
491
516
|
${this.autoplay
|
|
492
517
|
? html `<button
|
|
@@ -511,7 +536,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
511
536
|
type="button"
|
|
512
537
|
aria-label=${this.previousLabel}
|
|
513
538
|
aria-disabled=${this.atEnd('start') ? 'true' : nothing}
|
|
514
|
-
@click=${() => this.goTo(this.
|
|
539
|
+
@click=${() => this.goTo(this.move(-1))}
|
|
515
540
|
>
|
|
516
541
|
${this.renderPreviousMark()}
|
|
517
542
|
</button>
|
|
@@ -520,7 +545,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
520
545
|
type="button"
|
|
521
546
|
aria-label=${this.nextLabel}
|
|
522
547
|
aria-disabled=${this.atEnd('end') ? 'true' : nothing}
|
|
523
|
-
@click=${() => this.goTo(this.
|
|
548
|
+
@click=${() => this.goTo(this.move(1))}
|
|
524
549
|
>
|
|
525
550
|
${this.renderNextMark()}
|
|
526
551
|
</button>`}
|
|
@@ -545,7 +570,7 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
545
570
|
role="group"
|
|
546
571
|
aria-roledescription=${this.slideRoleLabel || nothing}
|
|
547
572
|
aria-label=${fillTemplate(this.slideLabel, { count: this.slides.length, index: index + 1 })}
|
|
548
|
-
style=${index
|
|
573
|
+
style=${this.paneStyle(index, last, stops)}
|
|
549
574
|
>
|
|
550
575
|
<slot
|
|
551
576
|
name=${this.assignsByName ? `slide-${index + 1}` : nothing}
|
|
@@ -557,17 +582,17 @@ let HelixHeadlessCarousel = class HelixHeadlessCarousel extends HelixElement {
|
|
|
557
582
|
${this.slides.length > 1 && this.across !== undefined
|
|
558
583
|
? html `<div part="indicators" role="group" aria-label=${fillTemplate(this.indicatorsLabel, { label: this.label })}>
|
|
559
584
|
${''}
|
|
560
|
-
${
|
|
561
|
-
const current = at ===
|
|
585
|
+
${stops.map((stop, at) => {
|
|
586
|
+
const current = at === showing;
|
|
562
587
|
return html `<button
|
|
563
588
|
part="indicator${current ? ' indicator-current' : ''}"
|
|
564
589
|
type="button"
|
|
565
590
|
aria-label=${fillTemplate(this.indicatorLabel, { index: at + 1 })}
|
|
566
|
-
aria-current=${at ===
|
|
567
|
-
tabindex=${at ===
|
|
591
|
+
aria-current=${at === place ? 'true' : nothing}
|
|
592
|
+
tabindex=${at === place ? '0' : '-1'}
|
|
568
593
|
?data-current=${current}
|
|
569
594
|
@keydown=${this.handleIndicatorKeydown}
|
|
570
|
-
@click=${() => this.goTo(
|
|
595
|
+
@click=${() => this.goTo(stop)}
|
|
571
596
|
></button>`;
|
|
572
597
|
})}
|
|
573
598
|
</div>`
|
|
@@ -628,6 +653,9 @@ __decorate([
|
|
|
628
653
|
__decorate([
|
|
629
654
|
property({ attribute: 'slide-role-label' })
|
|
630
655
|
], HelixHeadlessCarousel.prototype, "slideRoleLabel", void 0);
|
|
656
|
+
__decorate([
|
|
657
|
+
property({ attribute: 'slides-per-move', type: Number })
|
|
658
|
+
], HelixHeadlessCarousel.prototype, "slidesPerMove", void 0);
|
|
631
659
|
__decorate([
|
|
632
660
|
property({ attribute: 'start-label' })
|
|
633
661
|
], HelixHeadlessCarousel.prototype, "startLabel", void 0);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a carousel's track stops when it moves several slides at a time, as
|
|
3
|
+
* arithmetic over its positions.
|
|
4
|
+
*
|
|
5
|
+
* A position is a slide the track can start at: six slides four across have
|
|
6
|
+
* three, 0, 1 and 2. Moving `perMove` slides at a time stops at every
|
|
7
|
+
* `perMove`th of them from the first, and always at the last, so the end of
|
|
8
|
+
* the run is reachable whatever the count.
|
|
9
|
+
*/
|
|
10
|
+
/** The positions the track stops at, in order: every `perMove`th from 0, and the last. */
|
|
11
|
+
export declare const stopsOf: (positions: number, perMove?: number) => number[];
|
|
12
|
+
/** Which stop a position is at or past: the last stop at or before it, as an index into `stops`. */
|
|
13
|
+
export declare const stopFor: (stops: readonly number[], position: number) => number;
|
|
14
|
+
/**
|
|
15
|
+
* The position a move of one stop forward (`1`) or back (`-1`) lands on.
|
|
16
|
+
*
|
|
17
|
+
* From a position between two stops, back goes to the stop before it. Past
|
|
18
|
+
* either end it wraps where `loop` says so, and stays at the end otherwise.
|
|
19
|
+
*/
|
|
20
|
+
export declare const stepStop: (stops: readonly number[], position: number, step: -1 | 1, loop: boolean) => number;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const stopsOf = (positions, perMove = 1) => {
|
|
2
|
+
const step = Number.isFinite(perMove) ? Math.max(1, Math.floor(perMove)) : 1;
|
|
3
|
+
const last = Math.max(0, positions - 1);
|
|
4
|
+
const stops = [];
|
|
5
|
+
for (let at = 0; at < last; at += step) {
|
|
6
|
+
stops.push(at);
|
|
7
|
+
}
|
|
8
|
+
stops.push(last);
|
|
9
|
+
return stops;
|
|
10
|
+
};
|
|
11
|
+
export const stopFor = (stops, position) => {
|
|
12
|
+
let found = 0;
|
|
13
|
+
stops.forEach((stop, at) => {
|
|
14
|
+
if (stop <= position) {
|
|
15
|
+
found = at;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return found;
|
|
19
|
+
};
|
|
20
|
+
export const stepStop = (stops, position, step, loop) => {
|
|
21
|
+
const at = stopFor(stops, position);
|
|
22
|
+
let next = step < 0 && stops[at] !== position ? at : at + step;
|
|
23
|
+
if (loop) {
|
|
24
|
+
next = (next + stops.length) % stops.length;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
next = Math.min(Math.max(next, 0), stops.length - 1);
|
|
28
|
+
}
|
|
29
|
+
return stops[next] ?? 0;
|
|
30
|
+
};
|
|
@@ -4,12 +4,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, HelixElement, HelixSendEvent, hostAria, markRegion, relativeTime, requestChange, TONE_MARKS, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, HelixSendEvent, hostAria, markRegion, RelativeClockController, relativeTime, requestChange, TONE_MARKS, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
11
11
|
import { authorWords, TURN_WORDS, turnName } from '../naming.js';
|
|
12
|
-
import { RelativeClockController } from '../relative-clock.js';
|
|
13
12
|
export const FAILED_LABEL = 'Not sent';
|
|
14
13
|
let HelixHeadlessChatMessage = class HelixHeadlessChatMessage extends HelixElement {
|
|
15
14
|
constructor() {
|
|
@@ -23,8 +22,10 @@ let HelixHeadlessChatMessage = class HelixHeadlessChatMessage extends HelixEleme
|
|
|
23
22
|
this.turnWords = TURN_WORDS;
|
|
24
23
|
this.isChatMessage = true;
|
|
25
24
|
this.clock = new RelativeClockController(this, {
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
expires: (now) => {
|
|
26
|
+
const moment = this.moment;
|
|
27
|
+
return moment ? relativeTime(this.locale)(moment, now).next : undefined;
|
|
28
|
+
},
|
|
28
29
|
});
|
|
29
30
|
this.handleFill = () => {
|
|
30
31
|
this.markEmpty();
|
package/dist/chat/naming.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export interface TurnWords {
|
|
|
4
4
|
me: string;
|
|
5
5
|
/** The sentence for a turn with an author and a time, with `{author}` and `{time}`. */
|
|
6
6
|
sentence: string;
|
|
7
|
+
/** The name of a turn with neither an author a reader can be told nor a time. */
|
|
8
|
+
turn: string;
|
|
7
9
|
}
|
|
8
10
|
/** The words a chat says its turns with, where nobody said otherwise. */
|
|
9
11
|
export declare const TURN_WORDS: TurnWords;
|
|
@@ -17,6 +19,8 @@ export declare const TURN_WORDS: TurnWords;
|
|
|
17
19
|
export declare const authorWords: (author: string | undefined, authorLabel: string, words: TurnWords) => string;
|
|
18
20
|
/**
|
|
19
21
|
* The turn's accessible name: the sentence where it has an author and a time,
|
|
20
|
-
* and whichever of the two it has otherwise.
|
|
22
|
+
* and whichever of the two it has otherwise. Where it has neither, a turn by
|
|
23
|
+
* `them` with no `author-label` and no time, the chat's word for a turn, so
|
|
24
|
+
* no turn is an `article` with no name.
|
|
21
25
|
*/
|
|
22
26
|
export declare const turnName: (author: string, time: string, words: TurnWords) => string;
|
package/dist/chat/naming.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fillTemplate } from '@fusion.dev/helix-core';
|
|
2
|
-
export const TURN_WORDS = { me: 'You', sentence: '{author}, {time}' };
|
|
2
|
+
export const TURN_WORDS = { me: 'You', sentence: '{author}, {time}', turn: 'Message' };
|
|
3
3
|
export const authorWords = (author, authorLabel, words) => {
|
|
4
4
|
if (authorLabel !== '') {
|
|
5
5
|
return authorLabel;
|
|
@@ -9,4 +9,6 @@ export const authorWords = (author, authorLabel, words) => {
|
|
|
9
9
|
}
|
|
10
10
|
return author === undefined || author === 'them' ? '' : author;
|
|
11
11
|
};
|
|
12
|
-
export const turnName = (author, time, words) => author !== '' && time !== ''
|
|
12
|
+
export const turnName = (author, time, words) => author !== '' && time !== ''
|
|
13
|
+
? fillTemplate(words.sentence, { author, time })
|
|
14
|
+
: author || time || words.turn;
|
|
@@ -53,12 +53,15 @@ declare const HelixHeadlessChat_base: (new (...args: any[]) => import("@fusion.d
|
|
|
53
53
|
* `sent` or `failed` when your server answers. Add the reply as a turn with
|
|
54
54
|
* `state="streaming"`, write its text as it arrives, and set `state` to `sent`
|
|
55
55
|
* when it is complete. While the user types, the composer sends
|
|
56
|
-
* `helix-typing`, which you can pass on to the other side.
|
|
57
|
-
*
|
|
56
|
+
* `helix-typing`, which you can pass on to the other side. When the other side
|
|
57
|
+
* types, set `typing` to their name: the status band draws three dots and
|
|
58
|
+
* "Ada is typing" (`typing-label`), which a screen reader hears, and clearing
|
|
59
|
+
* it takes them away. Anything slotted into `status` is drawn first.
|
|
58
60
|
*
|
|
59
61
|
* A screen reader names each turn by its author and its time, such as "You, 2
|
|
60
62
|
* minutes ago". Set `me-label` and `message-label` to say it in your language,
|
|
61
|
-
* and give each turn by `them` an `author-label`.
|
|
63
|
+
* and give each turn by `them` an `author-label`. A turn with neither an author
|
|
64
|
+
* label nor a time is named by `turn-label`, "Message".
|
|
62
65
|
*
|
|
63
66
|
* A turn from `turns` is drawn in the chat's shadow root, so style it through
|
|
64
67
|
* the forwarded `message-*` parts. A turn by `me` also gets each part with
|
|
@@ -91,6 +94,7 @@ declare const HelixHeadlessChat_base: (new (...args: any[]) => import("@fusion.d
|
|
|
91
94
|
* @csspart empty - Shown when the conversation has no turns.
|
|
92
95
|
* @csspart header - The region above the transcript.
|
|
93
96
|
* @csspart history - Shown at the top of the transcript while older turns load.
|
|
97
|
+
* @csspart indicator - The three dots before the words that say who is typing, which the styled tier animates as a message's are. Hidden from screen readers.
|
|
94
98
|
* @csspart live - The region where screen readers announce each turn once it has arrived.
|
|
95
99
|
* @csspart loading - Shown while the history loads.
|
|
96
100
|
* @csspart log - The transcript, which scrolls.
|
|
@@ -117,6 +121,7 @@ declare const HelixHeadlessChat_base: (new (...args: any[]) => import("@fusion.d
|
|
|
117
121
|
* @csspart resume - The control shown while the user is scrolled away from the bottom.
|
|
118
122
|
* @csspart status - The status region, outside the log.
|
|
119
123
|
* @csspart turn - The wrapper around the message drawn for one turn from `turns`.
|
|
124
|
+
* @csspart typing - The words that say who is typing, in the status band, while `typing` names someone.
|
|
120
125
|
*/
|
|
121
126
|
export declare class HelixHeadlessChat extends HelixHeadlessChat_base {
|
|
122
127
|
/**
|
|
@@ -197,6 +202,11 @@ export declare class HelixHeadlessChat extends HelixHeadlessChat_base {
|
|
|
197
202
|
* history.
|
|
198
203
|
*/
|
|
199
204
|
threshold: number;
|
|
205
|
+
/**
|
|
206
|
+
* The name a screen reader gives a turn with neither an author it can say
|
|
207
|
+
* nor a time: a turn by `them` with no `author-label`, say.
|
|
208
|
+
*/
|
|
209
|
+
turnLabel: string;
|
|
200
210
|
/**
|
|
201
211
|
* The turns as data, for a transcript too long to hold as elements.
|
|
202
212
|
*
|
|
@@ -208,6 +218,18 @@ export declare class HelixHeadlessChat extends HelixHeadlessChat_base {
|
|
|
208
218
|
* element to look again.
|
|
209
219
|
*/
|
|
210
220
|
turns: readonly ChatTurn[];
|
|
221
|
+
/**
|
|
222
|
+
* Who on the other side is typing, by name, or empty while nobody is.
|
|
223
|
+
*
|
|
224
|
+
* Set it from your connection, and clear it when they stop or send. The
|
|
225
|
+
* status band says it with `typing-label`.
|
|
226
|
+
*/
|
|
227
|
+
typing: string;
|
|
228
|
+
/**
|
|
229
|
+
* What the status band says while someone is typing. `{author}` is the
|
|
230
|
+
* name in `typing`.
|
|
231
|
+
*/
|
|
232
|
+
typingLabel: string;
|
|
211
233
|
private pinnedState;
|
|
212
234
|
/** The last thing said, and how many times something has been. */
|
|
213
235
|
private announcement;
|
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
var HelixHeadlessChat_1;
|
|
8
|
-
import { customElement, HelixBeforePinEvent, HelixElement, HelixHistoryEvent, HelixPinEvent, hostAria, MixinCollection, onUnlessFalse, requestChange, VirtualizeController, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { customElement, fillTemplate, HelixBeforePinEvent, HelixElement, HelixHistoryEvent, HelixPinEvent, hostAria, MixinCollection, onUnlessFalse, requestChange, VirtualizeController, whenHydrated, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { keyed } from 'lit/directives/keyed.js';
|
|
@@ -43,7 +43,10 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
43
43
|
this.meLabel = 'You';
|
|
44
44
|
this.messageLabel = '{author}, {time}';
|
|
45
45
|
this.threshold = 48;
|
|
46
|
+
this.turnLabel = 'Message';
|
|
46
47
|
this.turns = [];
|
|
48
|
+
this.typing = '';
|
|
49
|
+
this.typingLabel = '{author} is typing';
|
|
47
50
|
this.pinnedState = undefined;
|
|
48
51
|
this.announcement = '';
|
|
49
52
|
this.said = 0;
|
|
@@ -365,8 +368,8 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
365
368
|
willUpdate(changed) {
|
|
366
369
|
super.willUpdate(changed);
|
|
367
370
|
hostAria(this.internals, { label: this.label || 'Conversation', role: 'region' });
|
|
368
|
-
if (changed.has('meLabel') || changed.has('messageLabel')) {
|
|
369
|
-
this.words = { me: this.meLabel, sentence: this.messageLabel };
|
|
371
|
+
if (changed.has('meLabel') || changed.has('messageLabel') || changed.has('turnLabel')) {
|
|
372
|
+
this.words = { me: this.meLabel, sentence: this.messageLabel, turn: this.turnLabel };
|
|
370
373
|
}
|
|
371
374
|
this.countRegions();
|
|
372
375
|
if (changed.has('history')) {
|
|
@@ -466,8 +469,13 @@ let HelixHeadlessChat = class HelixHeadlessChat extends MixinCollection(HelixEle
|
|
|
466
469
|
<div part="resume" ?hidden=${!away || !this.has('resume')} @click=${this.handleResume}>
|
|
467
470
|
<slot name="resume"></slot>
|
|
468
471
|
</div>
|
|
469
|
-
<div part="status" role="status" ?data-empty=${!this.has('status')}>
|
|
470
|
-
<slot name="status"></slot
|
|
472
|
+
<div part="status" role="status" ?data-empty=${!this.has('status') && this.typing === ''}>
|
|
473
|
+
<slot name="status"></slot>${this.typing === ''
|
|
474
|
+
? nothing
|
|
475
|
+
: html `<span part="typing"
|
|
476
|
+
><span part="indicator" aria-hidden="true"></span
|
|
477
|
+
>${fillTemplate(this.typingLabel, { author: this.typing })}</span
|
|
478
|
+
>`}
|
|
471
479
|
</div>
|
|
472
480
|
<div part="composer" ?hidden=${!this.has('composer')}>
|
|
473
481
|
<slot name="composer"></slot>
|
|
@@ -498,9 +506,18 @@ __decorate([
|
|
|
498
506
|
__decorate([
|
|
499
507
|
property({ type: Number })
|
|
500
508
|
], HelixHeadlessChat.prototype, "threshold", void 0);
|
|
509
|
+
__decorate([
|
|
510
|
+
property({ attribute: 'turn-label' })
|
|
511
|
+
], HelixHeadlessChat.prototype, "turnLabel", void 0);
|
|
501
512
|
__decorate([
|
|
502
513
|
property({ attribute: false })
|
|
503
514
|
], HelixHeadlessChat.prototype, "turns", void 0);
|
|
515
|
+
__decorate([
|
|
516
|
+
property()
|
|
517
|
+
], HelixHeadlessChat.prototype, "typing", void 0);
|
|
518
|
+
__decorate([
|
|
519
|
+
property({ attribute: 'typing-label' })
|
|
520
|
+
], HelixHeadlessChat.prototype, "typingLabel", void 0);
|
|
504
521
|
__decorate([
|
|
505
522
|
state()
|
|
506
523
|
], HelixHeadlessChat.prototype, "pinnedState", void 0);
|
|
@@ -21,6 +21,16 @@ declare const HelixHeadlessCheckbox_base: (new (...args: any[]) => import("@fusi
|
|
|
21
21
|
* it as neither checked nor unchecked, it never submits, and the first click
|
|
22
22
|
* resolves it.
|
|
23
23
|
*
|
|
24
|
+
* **Keyboard.** The box is one tab stop.
|
|
25
|
+
*
|
|
26
|
+
* | Key | What it does |
|
|
27
|
+
* |---|---|
|
|
28
|
+
* | Space | Checks or unchecks the box, and resolves `indeterminate`. |
|
|
29
|
+
*
|
|
30
|
+
* The native input reports checked, unchecked, or mixed. `aria-readonly` is set
|
|
31
|
+
* under `readonly`, and `aria-invalid` and `aria-describedby` point at the
|
|
32
|
+
* message while one shows.
|
|
33
|
+
*
|
|
24
34
|
* @since 0.1.0
|
|
25
35
|
* @status stable
|
|
26
36
|
* @category forms
|
|
@@ -28,6 +38,8 @@ declare const HelixHeadlessCheckbox_base: (new (...args: any[]) => import("@fusi
|
|
|
28
38
|
* @documentation https://fusion.dev/helix/components/checkbox
|
|
29
39
|
*
|
|
30
40
|
* @slot - The label.
|
|
41
|
+
* @slot check - An icon drawn as the mark while the box is checked, in place of the tick.
|
|
42
|
+
* @slot dash - An icon drawn as the mark while the box is indeterminate, in place of the dash.
|
|
31
43
|
* @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
|
|
32
44
|
* @slot hint - Help under the control, for content richer than the `hint` text.
|
|
33
45
|
*
|
|
@@ -47,6 +59,8 @@ declare const HelixHeadlessCheckbox_base: (new (...args: any[]) => import("@fusi
|
|
|
47
59
|
* @csspart mark-indeterminate - Added to `mark` while the box is indeterminate.
|
|
48
60
|
*
|
|
49
61
|
* @cssstate checked - While the box is checked.
|
|
62
|
+
* @cssstate has-check - An icon is slotted into `check`.
|
|
63
|
+
* @cssstate has-dash - An icon is slotted into `dash`.
|
|
50
64
|
* @cssstate has-label - The label slot has content, so the label is drawn.
|
|
51
65
|
* @cssstate indeterminate - While the box shows the dash, neither checked nor unchecked.
|
|
52
66
|
* @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
|
|
@@ -107,6 +121,12 @@ export declare class HelixHeadlessCheckbox extends HelixHeadlessCheckbox_base {
|
|
|
107
121
|
* worse problem than its spacing.
|
|
108
122
|
*/
|
|
109
123
|
private readonly handleLabelChange;
|
|
124
|
+
/**
|
|
125
|
+
* Records which of the mark's slots hold an icon, as `:state(has-check)` and
|
|
126
|
+
* `:state(has-dash)`, so a stylesheet drops its own drawing of that shape.
|
|
127
|
+
* A state, for the reason `:state(has-label)` is one.
|
|
128
|
+
*/
|
|
129
|
+
private readonly handleMarkChange;
|
|
110
130
|
/**
|
|
111
131
|
* Asks the slot, and records the answer as a state.
|
|
112
132
|
*
|
|
@@ -32,6 +32,16 @@ let HelixHeadlessCheckbox = class HelixHeadlessCheckbox extends MixinControllerC
|
|
|
32
32
|
this.handleLabelChange = () => {
|
|
33
33
|
this.syncLabelPresence();
|
|
34
34
|
};
|
|
35
|
+
this.handleMarkChange = (event) => {
|
|
36
|
+
const slot = event.target;
|
|
37
|
+
const filled = slot.assignedNodes().length > 0;
|
|
38
|
+
if (slot.name === 'dash') {
|
|
39
|
+
this.toggleState('has-dash', filled);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.toggleState('has-check', filled);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
35
45
|
}
|
|
36
46
|
static { this.shadowRootOptions = {
|
|
37
47
|
...HelixFormElement.shadowRootOptions,
|
|
@@ -94,7 +104,10 @@ let HelixHeadlessCheckbox = class HelixHeadlessCheckbox extends MixinControllerC
|
|
|
94
104
|
<span
|
|
95
105
|
part="mark${this.checked ? ' mark-checked' : ''}${this.indeterminate ? ' mark-indeterminate' : ''}${this.dashed ? ' mark-dash' : ''}"
|
|
96
106
|
aria-hidden="true"
|
|
97
|
-
|
|
107
|
+
>${this.dashed
|
|
108
|
+
? html `<slot name="dash" @slotchange=${this.handleMarkChange}></slot>`
|
|
109
|
+
: html `<slot name="check" @slotchange=${this.handleMarkChange}></slot>`}</span
|
|
110
|
+
>
|
|
98
111
|
</span>
|
|
99
112
|
<span part="label" ?data-hidden=${named !== null}
|
|
100
113
|
><slot @slotchange=${this.handleLabelChange}>${this.label || named}</slot></span
|
|
@@ -34,6 +34,9 @@ declare const HelixHeadlessCheckboxGroup_base: (new (...args: any[]) => import("
|
|
|
34
34
|
* only for validity and never calls `setFormValue`, so the browser does not
|
|
35
35
|
* generate a message for it.
|
|
36
36
|
*
|
|
37
|
+
* **Keyboard.** Each box is its own tab stop, as a set of native checkboxes
|
|
38
|
+
* is, and Space checks the focused one. The select-all box comes first.
|
|
39
|
+
*
|
|
37
40
|
* @since 0.1.0
|
|
38
41
|
* @status stable
|
|
39
42
|
* @category forms
|
|
@@ -221,12 +224,15 @@ export declare class HelixHeadlessCheckboxGroup extends HelixHeadlessCheckboxGro
|
|
|
221
224
|
* for the whole set, as a box moves it.
|
|
222
225
|
*/
|
|
223
226
|
private readonly handleSelectAll;
|
|
227
|
+
/** The set as the select-all helper reads it. */
|
|
228
|
+
private setBoxes;
|
|
224
229
|
/**
|
|
225
230
|
* The box above the set that checks or unchecks every box, under
|
|
226
231
|
* `select-all`, behind a seam a tier can move.
|
|
227
232
|
*
|
|
228
|
-
* Checked while every box is, and showing a dash while only some
|
|
229
|
-
*
|
|
233
|
+
* Checked while every enabled box is, and showing a dash while only some
|
|
234
|
+
* are, so its state says what a press does. It is in this shadow root, so
|
|
235
|
+
* it is no member of the set and submits nothing.
|
|
230
236
|
*/
|
|
231
237
|
protected renderSelectAll(): TemplateResult | typeof nothing;
|
|
232
238
|
protected render(): TemplateResult;
|
|
@@ -11,6 +11,7 @@ import { property } from 'lit/decorators.js';
|
|
|
11
11
|
import { html } from 'lit/static-html.js';
|
|
12
12
|
import { HelixHeadlessCheckbox } from '../../checkbox/root/checkbox-root.js';
|
|
13
13
|
import '../../checkbox/index.js';
|
|
14
|
+
import { selectAllPress, selectAllState } from '../select-all.js';
|
|
14
15
|
let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadlessCheckboxGroup extends MixinField(HelixFormElement) {
|
|
15
16
|
constructor() {
|
|
16
17
|
super(...arguments);
|
|
@@ -59,11 +60,7 @@ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadl
|
|
|
59
60
|
this.handleSelectAll = (event) => {
|
|
60
61
|
event.preventDefault();
|
|
61
62
|
event.stopPropagation();
|
|
62
|
-
const
|
|
63
|
-
const every = enabled.length > 0 && enabled.every((box) => box.checked);
|
|
64
|
-
const next = this.boxes
|
|
65
|
-
.filter((box) => (enabled.includes(box) ? !every : box.checked))
|
|
66
|
-
.map((box) => box.value);
|
|
63
|
+
const next = selectAllPress(this.setBoxes());
|
|
67
64
|
if (!this.dispatchEvent(new HelixBeforeChangeEvent({ value: next.join(',') }))) {
|
|
68
65
|
return;
|
|
69
66
|
}
|
|
@@ -177,13 +174,18 @@ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadl
|
|
|
177
174
|
this.validate();
|
|
178
175
|
this.linkHost();
|
|
179
176
|
}
|
|
177
|
+
setBoxes() {
|
|
178
|
+
return this.boxes.map((box) => ({
|
|
179
|
+
checked: box.checked,
|
|
180
|
+
disabled: box.isDisabled,
|
|
181
|
+
value: box.value,
|
|
182
|
+
}));
|
|
183
|
+
}
|
|
180
184
|
renderSelectAll() {
|
|
181
185
|
if (!this.selectAll) {
|
|
182
186
|
return nothing;
|
|
183
187
|
}
|
|
184
|
-
const
|
|
185
|
-
const ticked = boxes.filter((box) => box.checked).length;
|
|
186
|
-
const every = boxes.length > 0 && ticked === boxes.length;
|
|
188
|
+
const { checked, indeterminate } = selectAllState(this.childrenKnown ? this.setBoxes() : []);
|
|
187
189
|
const box = this.tag('checkbox');
|
|
188
190
|
return html `<${box}
|
|
189
191
|
part="select-all"
|
|
@@ -191,8 +193,8 @@ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadl
|
|
|
191
193
|
feedback: select-all-feedback, field: select-all-field, hint: select-all-hint,
|
|
192
194
|
label: select-all-label, mark: select-all-mark, mark-checked: select-all-mark-checked,
|
|
193
195
|
mark-dash: select-all-mark-dash, mark-indeterminate: select-all-mark-indeterminate"
|
|
194
|
-
.checked=${
|
|
195
|
-
.indeterminate=${
|
|
196
|
+
.checked=${checked}
|
|
197
|
+
.indeterminate=${indeterminate}
|
|
196
198
|
?disabled=${this.isDisabled}
|
|
197
199
|
label=${this.selectAllLabel}
|
|
198
200
|
@helix-before-toggle=${this.handleSelectAll}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** What the select-all helper reads from one box in the set. */
|
|
2
|
+
export interface SetBox {
|
|
3
|
+
/** Whether the box is checked. */
|
|
4
|
+
readonly checked: boolean;
|
|
5
|
+
/** Whether the box refuses a press, so select-all leaves it as it is. */
|
|
6
|
+
readonly disabled: boolean;
|
|
7
|
+
/** What the box submits when checked. */
|
|
8
|
+
readonly value: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* What the select-all box shows: checked while every enabled box is checked,
|
|
12
|
+
* mixed while only some are, and clear while none is.
|
|
13
|
+
*
|
|
14
|
+
* A disabled box counts for nothing, because a press leaves it as it is. A
|
|
15
|
+
* set whose every box is disabled reads every box, so the select-all box still
|
|
16
|
+
* shows what the set holds.
|
|
17
|
+
*/
|
|
18
|
+
export declare const selectAllState: (boxes: readonly SetBox[]) => {
|
|
19
|
+
checked: boolean;
|
|
20
|
+
indeterminate: boolean;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The values a press on the select-all box leaves, in the set's order: every
|
|
24
|
+
* enabled box checked, or every enabled box clear once all of them are
|
|
25
|
+
* checked. A disabled box keeps its state either way.
|
|
26
|
+
*/
|
|
27
|
+
export declare const selectAllPress: (boxes: readonly SetBox[]) => string[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const selectAllState = (boxes) => {
|
|
2
|
+
const enabled = boxes.filter((box) => !box.disabled);
|
|
3
|
+
const counted = enabled.length > 0 ? enabled : boxes;
|
|
4
|
+
const ticked = counted.filter((box) => box.checked).length;
|
|
5
|
+
const checked = counted.length > 0 && ticked === counted.length;
|
|
6
|
+
return { checked, indeterminate: ticked > 0 && !checked };
|
|
7
|
+
};
|
|
8
|
+
export const selectAllPress = (boxes) => {
|
|
9
|
+
const enabled = boxes.filter((box) => !box.disabled);
|
|
10
|
+
const every = enabled.length > 0 && enabled.every((box) => box.checked);
|
|
11
|
+
return boxes.filter((box) => (box.disabled ? box.checked : !every)).map((box) => box.value);
|
|
12
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The highlighted lines out of what a highlighter returned, without the
|
|
3
|
+
* `<pre>` and `<code>` around them that some highlighters write.
|
|
4
|
+
*
|
|
5
|
+
* Shiki's `codeToHtml` returns a whole block, `<pre class="shiki" tabindex="0"
|
|
6
|
+
* style="…"><code>…</code></pre>`. Drawn as given inside the block's own
|
|
7
|
+
* `<pre>`, that second `<pre>` sat 13px below the gutter's first number, and
|
|
8
|
+
* its `tabindex` was a second tab stop inside the block's scroller. Prism's
|
|
9
|
+
* `highlight` and highlight.js return the lines alone, which pass through
|
|
10
|
+
* unchanged.
|
|
11
|
+
*
|
|
12
|
+
* Only a wrapper around the whole markup is taken off, and only one. The block draws its own
|
|
13
|
+
* box and colors, so the wrapper's `style` and `class` go with it.
|
|
14
|
+
*/
|
|
15
|
+
export declare const highlightedLines: (markup: string) => string;
|