@fusion.dev/helix-headless 0.0.0-dev
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/LICENSE +21 -0
- package/custom-elements.json +75202 -0
- package/dist/accordion/index.d.ts +2 -0
- package/dist/accordion/index.js +2 -0
- package/dist/accordion/item/accordion-item.d.ts +141 -0
- package/dist/accordion/item/accordion-item.js +214 -0
- package/dist/accordion/root/accordion-root.d.ts +57 -0
- package/dist/accordion/root/accordion-root.js +96 -0
- package/dist/announcement/index.d.ts +1 -0
- package/dist/announcement/index.js +1 -0
- package/dist/announcement/root/announcement-root.d.ts +106 -0
- package/dist/announcement/root/announcement-root.js +144 -0
- package/dist/app-header/index.d.ts +1 -0
- package/dist/app-header/index.js +1 -0
- package/dist/app-header/root/app-header-root.d.ts +113 -0
- package/dist/app-header/root/app-header-root.js +147 -0
- package/dist/avatar/group/avatar-group.d.ts +116 -0
- package/dist/avatar/group/avatar-group.js +136 -0
- package/dist/avatar/index.d.ts +2 -0
- package/dist/avatar/index.js +2 -0
- package/dist/avatar/root/avatar-root.d.ts +71 -0
- package/dist/avatar/root/avatar-root.js +147 -0
- package/dist/badge/index.d.ts +1 -0
- package/dist/badge/index.js +1 -0
- package/dist/badge/root/badge-root.d.ts +61 -0
- package/dist/badge/root/badge-root.js +121 -0
- package/dist/bar-chart/index.d.ts +1 -0
- package/dist/bar-chart/index.js +1 -0
- package/dist/bar-chart/root/bar-chart-root.d.ts +266 -0
- package/dist/bar-chart/root/bar-chart-root.js +515 -0
- package/dist/blockquote/index.d.ts +1 -0
- package/dist/blockquote/index.js +1 -0
- package/dist/blockquote/root/blockquote-root.d.ts +51 -0
- package/dist/blockquote/root/blockquote-root.js +84 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +104 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +137 -0
- package/dist/breadcrumbs/index.d.ts +2 -0
- package/dist/breadcrumbs/index.js +2 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +77 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.js +94 -0
- package/dist/button/index.d.ts +1 -0
- package/dist/button/index.js +1 -0
- package/dist/button/root/button-root.d.ts +251 -0
- package/dist/button/root/button-root.js +401 -0
- package/dist/button-group/index.d.ts +1 -0
- package/dist/button-group/index.js +1 -0
- package/dist/button-group/root/button-group-root.d.ts +62 -0
- package/dist/button-group/root/button-group-root.js +62 -0
- package/dist/callout/index.d.ts +1 -0
- package/dist/callout/index.js +1 -0
- package/dist/callout/root/callout-root.d.ts +72 -0
- package/dist/callout/root/callout-root.js +90 -0
- package/dist/card/index.d.ts +1 -0
- package/dist/card/index.js +1 -0
- package/dist/card/root/card-root.d.ts +54 -0
- package/dist/card/root/card-root.js +71 -0
- package/dist/carousel/index.d.ts +1 -0
- package/dist/carousel/index.js +1 -0
- package/dist/carousel/root/carousel-root.d.ts +399 -0
- package/dist/carousel/root/carousel-root.js +723 -0
- package/dist/chat/composer/chat-composer.d.ts +160 -0
- package/dist/chat/composer/chat-composer.js +273 -0
- package/dist/chat/index.d.ts +3 -0
- package/dist/chat/index.js +3 -0
- package/dist/chat/message/chat-message.d.ts +170 -0
- package/dist/chat/message/chat-message.js +271 -0
- package/dist/chat/root/chat-root.d.ts +216 -0
- package/dist/chat/root/chat-root.js +389 -0
- package/dist/checkbox/index.d.ts +1 -0
- package/dist/checkbox/index.js +1 -0
- package/dist/checkbox/root/checkbox-root.d.ts +108 -0
- package/dist/checkbox/root/checkbox-root.js +207 -0
- package/dist/checkbox-group/index.d.ts +1 -0
- package/dist/checkbox-group/index.js +1 -0
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +155 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +293 -0
- package/dist/code/index.d.ts +1 -0
- package/dist/code/index.js +1 -0
- package/dist/code/root/code-root.d.ts +36 -0
- package/dist/code/root/code-root.js +43 -0
- package/dist/code-block/index.d.ts +1 -0
- package/dist/code-block/index.js +1 -0
- package/dist/code-block/root/code-block-root.d.ts +112 -0
- package/dist/code-block/root/code-block-root.js +155 -0
- package/dist/color-input/index.d.ts +1 -0
- package/dist/color-input/index.js +1 -0
- package/dist/color-input/root/color-input-root.d.ts +227 -0
- package/dist/color-input/root/color-input-root.js +456 -0
- package/dist/color-picker/color.d.ts +74 -0
- package/dist/color-picker/color.js +238 -0
- package/dist/color-picker/index.d.ts +2 -0
- package/dist/color-picker/index.js +2 -0
- package/dist/color-picker/root/color-picker-root.d.ts +303 -0
- package/dist/color-picker/root/color-picker-root.js +576 -0
- package/dist/combobox/index.d.ts +1 -0
- package/dist/combobox/index.js +1 -0
- package/dist/combobox/root/combobox-root.d.ts +396 -0
- package/dist/combobox/root/combobox-root.js +808 -0
- package/dist/command/index.d.ts +1 -0
- package/dist/command/index.js +1 -0
- package/dist/command/root/command-root.d.ts +166 -0
- package/dist/command/root/command-root.js +353 -0
- package/dist/copy-button/index.d.ts +1 -0
- package/dist/copy-button/index.js +1 -0
- package/dist/copy-button/root/copy-button-root.d.ts +154 -0
- package/dist/copy-button/root/copy-button-root.js +225 -0
- package/dist/data-table/index.d.ts +2 -0
- package/dist/data-table/index.js +2 -0
- package/dist/data-table/root/data-table-root.d.ts +392 -0
- package/dist/data-table/root/data-table-root.js +729 -0
- package/dist/data-table/root/order.d.ts +116 -0
- package/dist/data-table/root/order.js +175 -0
- package/dist/date-input/index.d.ts +1 -0
- package/dist/date-input/index.js +1 -0
- package/dist/date-input/root/date-input-root.d.ts +361 -0
- package/dist/date-input/root/date-input-root.js +791 -0
- package/dist/date-picker/index.d.ts +1 -0
- package/dist/date-picker/index.js +1 -0
- package/dist/date-picker/root/date-picker-root.d.ts +361 -0
- package/dist/date-picker/root/date-picker-root.js +837 -0
- package/dist/dialog/index.d.ts +1 -0
- package/dist/dialog/index.js +1 -0
- package/dist/dialog/root/dialog-root.d.ts +185 -0
- package/dist/dialog/root/dialog-root.js +319 -0
- package/dist/divider/index.d.ts +1 -0
- package/dist/divider/index.js +1 -0
- package/dist/divider/root/divider-root.d.ts +68 -0
- package/dist/divider/root/divider-root.js +116 -0
- package/dist/donut-chart/index.d.ts +1 -0
- package/dist/donut-chart/index.js +1 -0
- package/dist/donut-chart/root/donut-chart-root.d.ts +209 -0
- package/dist/donut-chart/root/donut-chart-root.js +395 -0
- package/dist/drawer/index.d.ts +1 -0
- package/dist/drawer/index.js +1 -0
- package/dist/drawer/root/drawer-root.d.ts +144 -0
- package/dist/drawer/root/drawer-root.js +222 -0
- package/dist/drilldown/index.d.ts +2 -0
- package/dist/drilldown/index.js +2 -0
- package/dist/drilldown/item/drilldown-item.d.ts +87 -0
- package/dist/drilldown/item/drilldown-item.js +152 -0
- package/dist/drilldown/root/drilldown-root.d.ts +115 -0
- package/dist/drilldown/root/drilldown-root.js +263 -0
- package/dist/element-events.generated.d.ts +1 -0
- package/dist/element-events.generated.js +125 -0
- package/dist/empty/index.d.ts +1 -0
- package/dist/empty/index.js +1 -0
- package/dist/empty/root/empty-root.d.ts +47 -0
- package/dist/empty/root/empty-root.js +68 -0
- package/dist/file-input/index.d.ts +1 -0
- package/dist/file-input/index.js +1 -0
- package/dist/file-input/root/file-input-root.d.ts +196 -0
- package/dist/file-input/root/file-input-root.js +488 -0
- package/dist/format-date/index.d.ts +1 -0
- package/dist/format-date/index.js +1 -0
- package/dist/format-date/root/format-date-root.d.ts +151 -0
- package/dist/format-date/root/format-date-root.js +266 -0
- package/dist/heatmap/index.d.ts +2 -0
- package/dist/heatmap/index.js +2 -0
- package/dist/heatmap/root/buckets.d.ts +62 -0
- package/dist/heatmap/root/buckets.js +85 -0
- package/dist/heatmap/root/heatmap-root.d.ts +330 -0
- package/dist/heatmap/root/heatmap-root.js +526 -0
- package/dist/icon/index.d.ts +1 -0
- package/dist/icon/index.js +1 -0
- package/dist/icon/root/icon-root.d.ts +53 -0
- package/dist/icon/root/icon-root.js +93 -0
- package/dist/icon-button/index.d.ts +1 -0
- package/dist/icon-button/index.js +1 -0
- package/dist/icon-button/root/icon-button-root.d.ts +40 -0
- package/dist/icon-button/root/icon-button-root.js +46 -0
- package/dist/image/index.d.ts +1 -0
- package/dist/image/index.js +1 -0
- package/dist/image/root/image-root.d.ts +213 -0
- package/dist/image/root/image-root.js +335 -0
- package/dist/index.d.ts +99 -0
- package/dist/index.js +99 -0
- package/dist/input/index.d.ts +1 -0
- package/dist/input/index.js +1 -0
- package/dist/input/root/input-root.d.ts +281 -0
- package/dist/input/root/input-root.js +472 -0
- package/dist/kbd/index.d.ts +1 -0
- package/dist/kbd/index.js +1 -0
- package/dist/kbd/root/kbd-root.d.ts +98 -0
- package/dist/kbd/root/kbd-root.js +230 -0
- package/dist/legend/index.d.ts +1 -0
- package/dist/legend/index.js +1 -0
- package/dist/legend/root/legend-root.d.ts +83 -0
- package/dist/legend/root/legend-root.js +125 -0
- package/dist/line-chart/index.d.ts +1 -0
- package/dist/line-chart/index.js +1 -0
- package/dist/line-chart/root/line-chart-root.d.ts +238 -0
- package/dist/line-chart/root/line-chart-root.js +365 -0
- package/dist/list/index.d.ts +2 -0
- package/dist/list/index.js +2 -0
- package/dist/list/item/list-item.d.ts +95 -0
- package/dist/list/item/list-item.js +148 -0
- package/dist/list/root/list-root.d.ts +72 -0
- package/dist/list/root/list-root.js +61 -0
- package/dist/listbox/index.d.ts +1 -0
- package/dist/listbox/index.js +1 -0
- package/dist/listbox/root/listbox-root.d.ts +357 -0
- package/dist/listbox/root/listbox-root.js +890 -0
- package/dist/loader/index.d.ts +1 -0
- package/dist/loader/index.js +1 -0
- package/dist/loader/root/loader-root.d.ts +52 -0
- package/dist/loader/root/loader-root.js +74 -0
- package/dist/megamenu/index.d.ts +1 -0
- package/dist/megamenu/index.js +1 -0
- package/dist/megamenu/root/megamenu-root.d.ts +254 -0
- package/dist/megamenu/root/megamenu-root.js +526 -0
- package/dist/menu/index.d.ts +2 -0
- package/dist/menu/index.js +2 -0
- package/dist/menu/item/menu-item.d.ts +231 -0
- package/dist/menu/item/menu-item.js +405 -0
- package/dist/menu/root/menu-root.d.ts +158 -0
- package/dist/menu/root/menu-root.js +422 -0
- package/dist/meter/index.d.ts +1 -0
- package/dist/meter/index.js +1 -0
- package/dist/meter/root/meter-root.d.ts +234 -0
- package/dist/meter/root/meter-root.js +316 -0
- package/dist/navigation/index.d.ts +1 -0
- package/dist/navigation/index.js +1 -0
- package/dist/navigation/root/navigation-root.d.ts +55 -0
- package/dist/navigation/root/navigation-root.js +130 -0
- package/dist/notifications/index.d.ts +2 -0
- package/dist/notifications/index.js +2 -0
- package/dist/notifications/notification/notification.d.ts +181 -0
- package/dist/notifications/notification/notification.js +305 -0
- package/dist/notifications/root/notifications-root.d.ts +168 -0
- package/dist/notifications/root/notifications-root.js +291 -0
- package/dist/number-input/index.d.ts +1 -0
- package/dist/number-input/index.js +1 -0
- package/dist/number-input/root/number-input-root.d.ts +282 -0
- package/dist/number-input/root/number-input-root.js +592 -0
- package/dist/option/group/option-group.d.ts +38 -0
- package/dist/option/group/option-group.js +58 -0
- package/dist/option/index.d.ts +2 -0
- package/dist/option/index.js +2 -0
- package/dist/option/root/option-root.d.ts +194 -0
- package/dist/option/root/option-root.js +247 -0
- package/dist/outline/index.d.ts +1 -0
- package/dist/outline/index.js +1 -0
- package/dist/outline/root/outline-root.d.ts +237 -0
- package/dist/outline/root/outline-root.js +519 -0
- package/dist/pagination/index.d.ts +3 -0
- package/dist/pagination/index.js +3 -0
- package/dist/pagination/root/pagination-root.d.ts +390 -0
- package/dist/pagination/root/pagination-root.js +695 -0
- package/dist/pagination/size/pagination-size.d.ts +127 -0
- package/dist/pagination/size/pagination-size.js +232 -0
- package/dist/pagination/summary/pagination-summary.d.ts +90 -0
- package/dist/pagination/summary/pagination-summary.js +145 -0
- package/dist/pin-input/index.d.ts +1 -0
- package/dist/pin-input/index.js +1 -0
- package/dist/pin-input/root/pin-input-root.d.ts +292 -0
- package/dist/pin-input/root/pin-input-root.js +553 -0
- package/dist/popover/index.d.ts +1 -0
- package/dist/popover/index.js +1 -0
- package/dist/popover/root/popover-root.d.ts +108 -0
- package/dist/popover/root/popover-root.js +231 -0
- package/dist/progress/index.d.ts +1 -0
- package/dist/progress/index.js +1 -0
- package/dist/progress/root/progress-root.d.ts +125 -0
- package/dist/progress/root/progress-root.js +212 -0
- package/dist/qr-code/index.d.ts +1 -0
- package/dist/qr-code/index.js +1 -0
- package/dist/qr-code/root/qr-code-root.d.ts +93 -0
- package/dist/qr-code/root/qr-code-root.js +233 -0
- package/dist/quote/index.d.ts +1 -0
- package/dist/quote/index.js +1 -0
- package/dist/quote/root/quote-root.d.ts +36 -0
- package/dist/quote/root/quote-root.js +50 -0
- package/dist/radio/group/radio-group.d.ts +84 -0
- package/dist/radio/group/radio-group.js +170 -0
- package/dist/radio/index.d.ts +2 -0
- package/dist/radio/index.js +2 -0
- package/dist/radio/root/radio-root.d.ts +102 -0
- package/dist/radio/root/radio-root.js +151 -0
- package/dist/rating/index.d.ts +1 -0
- package/dist/rating/index.js +1 -0
- package/dist/rating/root/rating-root.d.ts +242 -0
- package/dist/rating/root/rating-root.js +484 -0
- package/dist/scroll-area/index.d.ts +1 -0
- package/dist/scroll-area/index.js +1 -0
- package/dist/scroll-area/root/scroll-area-root.d.ts +96 -0
- package/dist/scroll-area/root/scroll-area-root.js +215 -0
- package/dist/select/index.d.ts +1 -0
- package/dist/select/index.js +1 -0
- package/dist/select/root/select-root.d.ts +170 -0
- package/dist/select/root/select-root.js +419 -0
- package/dist/skeleton/index.d.ts +1 -0
- package/dist/skeleton/index.js +1 -0
- package/dist/skeleton/root/skeleton-root.d.ts +31 -0
- package/dist/skeleton/root/skeleton-root.js +42 -0
- package/dist/slider/index.d.ts +1 -0
- package/dist/slider/index.js +1 -0
- package/dist/slider/root/slider-root.d.ts +235 -0
- package/dist/slider/root/slider-root.js +488 -0
- package/dist/sparkline/index.d.ts +1 -0
- package/dist/sparkline/index.js +1 -0
- package/dist/sparkline/root/sparkline-root.d.ts +147 -0
- package/dist/sparkline/root/sparkline-root.js +278 -0
- package/dist/speed-dial/index.d.ts +2 -0
- package/dist/speed-dial/index.js +2 -0
- package/dist/speed-dial/item/speed-dial-item.d.ts +71 -0
- package/dist/speed-dial/item/speed-dial-item.js +113 -0
- package/dist/speed-dial/root/speed-dial-root.d.ts +122 -0
- package/dist/speed-dial/root/speed-dial-root.js +251 -0
- package/dist/splitter/index.d.ts +1 -0
- package/dist/splitter/index.js +1 -0
- package/dist/splitter/root/splitter-root.d.ts +491 -0
- package/dist/splitter/root/splitter-root.js +1030 -0
- package/dist/stat/group/stat-group.d.ts +30 -0
- package/dist/stat/group/stat-group.js +47 -0
- package/dist/stat/index.d.ts +2 -0
- package/dist/stat/index.js +2 -0
- package/dist/stat/root/stat-root.d.ts +62 -0
- package/dist/stat/root/stat-root.js +51 -0
- package/dist/steps/index.d.ts +2 -0
- package/dist/steps/index.js +2 -0
- package/dist/steps/root/steps-root.d.ts +110 -0
- package/dist/steps/root/steps-root.js +130 -0
- package/dist/steps/step/step.d.ts +139 -0
- package/dist/steps/step/step.js +215 -0
- package/dist/switch/index.d.ts +1 -0
- package/dist/switch/index.js +1 -0
- package/dist/switch/root/switch-root.d.ts +74 -0
- package/dist/switch/root/switch-root.js +153 -0
- package/dist/table/cell/table-cell.d.ts +34 -0
- package/dist/table/cell/table-cell.js +52 -0
- package/dist/table/column/table-column.d.ts +165 -0
- package/dist/table/column/table-column.js +222 -0
- package/dist/table/index.d.ts +4 -0
- package/dist/table/index.js +4 -0
- package/dist/table/root/table-root.d.ts +98 -0
- package/dist/table/root/table-root.js +161 -0
- package/dist/table/row/table-row.d.ts +27 -0
- package/dist/table/row/table-row.js +42 -0
- package/dist/tabs/index.d.ts +3 -0
- package/dist/tabs/index.js +3 -0
- package/dist/tabs/panel/tab-panel.d.ts +67 -0
- package/dist/tabs/panel/tab-panel.js +98 -0
- package/dist/tabs/root/tabs-root.d.ts +123 -0
- package/dist/tabs/root/tabs-root.js +217 -0
- package/dist/tabs/tab/tab.d.ts +64 -0
- package/dist/tabs/tab/tab.js +116 -0
- package/dist/tag/index.d.ts +1 -0
- package/dist/tag/index.js +1 -0
- package/dist/tag/root/tag-root.d.ts +41 -0
- package/dist/tag/root/tag-root.js +67 -0
- package/dist/textarea/index.d.ts +1 -0
- package/dist/textarea/index.js +1 -0
- package/dist/textarea/root/textarea-root.d.ts +215 -0
- package/dist/textarea/root/textarea-root.js +380 -0
- package/dist/time-input/index.d.ts +1 -0
- package/dist/time-input/index.js +1 -0
- package/dist/time-input/root/time-input-root.d.ts +322 -0
- package/dist/time-input/root/time-input-root.js +661 -0
- package/dist/time-picker/index.d.ts +1 -0
- package/dist/time-picker/index.js +1 -0
- package/dist/time-picker/root/time-picker-root.d.ts +380 -0
- package/dist/time-picker/root/time-picker-root.js +669 -0
- package/dist/timeline/index.d.ts +2 -0
- package/dist/timeline/index.js +2 -0
- package/dist/timeline/item/timeline-item.d.ts +81 -0
- package/dist/timeline/item/timeline-item.js +128 -0
- package/dist/timeline/root/timeline-root.d.ts +52 -0
- package/dist/timeline/root/timeline-root.js +72 -0
- package/dist/toast/index.d.ts +2 -0
- package/dist/toast/index.js +2 -0
- package/dist/toast/item/toast-item.d.ts +183 -0
- package/dist/toast/item/toast-item.js +345 -0
- package/dist/toast/root/toast-root.d.ts +72 -0
- package/dist/toast/root/toast-root.js +87 -0
- package/dist/toggle/group/toggle-group.d.ts +140 -0
- package/dist/toggle/group/toggle-group.js +278 -0
- package/dist/toggle/index.d.ts +2 -0
- package/dist/toggle/index.js +2 -0
- package/dist/toggle/root/toggle-root.d.ts +99 -0
- package/dist/toggle/root/toggle-root.js +146 -0
- package/dist/toolbar/index.d.ts +1 -0
- package/dist/toolbar/index.js +1 -0
- package/dist/toolbar/root/toolbar-root.d.ts +105 -0
- package/dist/toolbar/root/toolbar-root.js +260 -0
- package/dist/tooltip/index.d.ts +1 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/tooltip/root/tooltip-root.d.ts +388 -0
- package/dist/tooltip/root/tooltip-root.js +707 -0
- package/dist/tour/index.d.ts +2 -0
- package/dist/tour/index.js +2 -0
- package/dist/tour/root/tour-root.d.ts +161 -0
- package/dist/tour/root/tour-root.js +351 -0
- package/dist/tour/stop/tour-stop.d.ts +131 -0
- package/dist/tour/stop/tour-stop.js +249 -0
- package/dist/tree/index.d.ts +2 -0
- package/dist/tree/index.js +2 -0
- package/dist/tree/item/tree-item.d.ts +208 -0
- package/dist/tree/item/tree-item.js +381 -0
- package/dist/tree/root/tree-root.d.ts +88 -0
- package/dist/tree/root/tree-root.js +287 -0
- package/dist/trend/index.d.ts +1 -0
- package/dist/trend/index.js +1 -0
- package/dist/trend/root/trend-root.d.ts +67 -0
- package/dist/trend/root/trend-root.js +106 -0
- package/dist/video/index.d.ts +1 -0
- package/dist/video/index.js +1 -0
- package/dist/video/root/video-root.d.ts +711 -0
- package/dist/video/root/video-root.js +1821 -0
- package/dist/video-playlist/index.d.ts +3 -0
- package/dist/video-playlist/index.js +3 -0
- package/dist/video-playlist/item/video-playlist-item.d.ts +101 -0
- package/dist/video-playlist/item/video-playlist-item.js +162 -0
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +121 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +237 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +108 -0
- package/dist/video-playlist/root/video-playlist-root.js +218 -0
- package/dist/virtual-list/index.d.ts +1 -0
- package/dist/virtual-list/index.js +1 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +121 -0
- package/dist/virtual-list/root/virtual-list-root.js +221 -0
- package/jsx.d.ts +49767 -0
- package/package.json +77 -0
- package/svelte.d.ts +129 -0
- package/vue.d.ts +9242 -0
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { valueAsTime as asTime, customElement, timeAsValue as fromTime, HelixFormElement, MixinControllerValue, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { nothing } from 'lit';
|
|
9
|
+
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { html } from 'lit/static-html.js';
|
|
11
|
+
/* Side-effect imports, because this renders these in its own shadow root and a
|
|
12
|
+
custom element registers on import. The paths are relative, so this registers
|
|
13
|
+
the headless elements and the styled file's identical imports register the styled
|
|
14
|
+
ones; `tier` picks which names the template asks for. */
|
|
15
|
+
import '../../listbox/index.js';
|
|
16
|
+
import '../../option/index.js';
|
|
17
|
+
/** Whether a string is a time the rest of this component can reason about. */
|
|
18
|
+
export const isTime = (value) => /^([01]\d|2[0-3]):[0-5]\d$/.test(value);
|
|
19
|
+
/** Minutes since midnight, or `null` where it is not a time. */
|
|
20
|
+
export const toMinutes = (value) => {
|
|
21
|
+
if (!isTime(value)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const [hours = '0', minutes = '0'] = value.split(':');
|
|
25
|
+
return Number(hours) * 60 + Number(minutes);
|
|
26
|
+
};
|
|
27
|
+
/** Minutes since midnight back to `HH:mm`, which is the value shape throughout. */
|
|
28
|
+
export const fromMinutes = (minutes) => {
|
|
29
|
+
const whole = ((Math.round(minutes) % 1440) + 1440) % 1440;
|
|
30
|
+
return `${String(Math.floor(whole / 60)).padStart(2, '0')}:${String(whole % 60).padStart(2, '0')}`;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* A time written the way the reader's locale writes one.
|
|
34
|
+
*
|
|
35
|
+
* `Intl` decides between a twelve and a twenty-four hour clock, because that is
|
|
36
|
+
* a property of the locale rather than of this component: `en-US` gets
|
|
37
|
+
* `2:30 PM` and `en-GB` gets `14:30` without either being configured. There is
|
|
38
|
+
* no flag to force one, deliberately. A product that needs to override its
|
|
39
|
+
* reader's own convention has a locale problem rather than a component one, and
|
|
40
|
+
* the value is 24 hour regardless.
|
|
41
|
+
*/
|
|
42
|
+
export const writeTime = (value, locale) => {
|
|
43
|
+
const minutes = toMinutes(value);
|
|
44
|
+
if (minutes === null) {
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
const at = new Date(Date.UTC(2000, 0, 1, Math.floor(minutes / 60), minutes % 60));
|
|
48
|
+
/* `timeStyle` rather than `hour` and `minute` assembled by hand. Measured in
|
|
49
|
+
Chrome: `hour: 'numeric'` gives `9:00` for `en-GB`, unpadded, which is not
|
|
50
|
+
how a twenty-four hour clock is written, while `hour: '2-digit'` gives
|
|
51
|
+
`09:00 AM` for `en-US`, which is not how a twelve hour one is. `short` is
|
|
52
|
+
each locale's own answer: `09:00` and `9:00 AM`. */
|
|
53
|
+
return new Intl.DateTimeFormat(locale || undefined, {
|
|
54
|
+
timeStyle: 'short',
|
|
55
|
+
timeZone: 'UTC',
|
|
56
|
+
}).format(at);
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Whether the reader's locale writes times on a twelve hour clock.
|
|
60
|
+
*
|
|
61
|
+
* Asked of `Intl` rather than derived from a list of locales, because it is
|
|
62
|
+
* exactly the question `resolvedOptions` answers and the list is long and
|
|
63
|
+
* changes. `en-US` is true, `en-GB`, `fr-FR` and `ja-JP` are false, measured.
|
|
64
|
+
*/
|
|
65
|
+
const isTwelveHour = (locale) => new Intl.DateTimeFormat(locale || undefined, { timeStyle: 'short' }).resolvedOptions().hour12 ===
|
|
66
|
+
true;
|
|
67
|
+
/**
|
|
68
|
+
* @summary Picks a time, from a list of them.
|
|
69
|
+
*
|
|
70
|
+
* @description
|
|
71
|
+
* **A list rather than three wheels**, and the reason is what a list already
|
|
72
|
+
* is. `helix-listbox` brings the keyboard, the typeahead, the scroll into view
|
|
73
|
+
* and the announcement of a set of options, and a time at a step is a set of
|
|
74
|
+
* options. Three little wheels for hours, minutes and a meridiem are three
|
|
75
|
+
* controls to build, three to test, and a tab stop each for something a reader
|
|
76
|
+
* answers once.
|
|
77
|
+
*
|
|
78
|
+
* **A step is what makes it a list at all.** Fifteen minutes is ninety-six rows,
|
|
79
|
+
* which a reader scrolls or types into; one minute is one thousand four hundred
|
|
80
|
+
* and forty, which is a listbox in name only. So the list is for the times a
|
|
81
|
+
* product actually offers, and arbitrary times are the field's job in Input
|
|
82
|
+
* Time, the same division Date Input draws between typing a date and using the
|
|
83
|
+
* calendar.
|
|
84
|
+
*
|
|
85
|
+
* **The value is `HH:mm` on a twenty-four hour clock, always.** That is what a
|
|
86
|
+
* form submits and what `min` and `max` compare against, and it sorts as a
|
|
87
|
+
* string, which is the whole reason the shape is that one. What each row *says*
|
|
88
|
+
* is the reader's own convention, from `Intl`.
|
|
89
|
+
*
|
|
90
|
+
* @since 0.1.0
|
|
91
|
+
* @status experimental
|
|
92
|
+
* @category forms
|
|
93
|
+
* @aliases Time, TimeList
|
|
94
|
+
* @documentation https://helix.fusion.dev/components/time-picker
|
|
95
|
+
*
|
|
96
|
+
* @event {Event} change - Announced once the value has moved.
|
|
97
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the time changes. Cancelable: refusing it takes the decision and nothing moves.
|
|
98
|
+
* @event {Event} input - Announced once the value has moved.
|
|
99
|
+
*
|
|
100
|
+
* @csspart column - One of them.
|
|
101
|
+
* @csspart column-empty - Shown when a filter has hidden everything.
|
|
102
|
+
* @csspart column-feedback - What is wrong with it.
|
|
103
|
+
* @csspart column-filter-icon - The mark beside that field.
|
|
104
|
+
* @csspart column-filter-mark - The glyph beside the filter field, where none is slotted.
|
|
105
|
+
* @csspart column-hint - Help under the list.
|
|
106
|
+
* @csspart column-items - The list itself.
|
|
107
|
+
* @csspart column-label - The question, over the list.
|
|
108
|
+
* @csspart column-loading - Shown while the options are still on their way.
|
|
109
|
+
* @csspart column-search - The region holding the field that narrows the list.
|
|
110
|
+
* @csspart column-search-field - The field itself.
|
|
111
|
+
* @csspart columns - The row of columns, in `wheels`.
|
|
112
|
+
* @csspart list - The listbox holding the times, in `list`.
|
|
113
|
+
* @csspart list-empty - Shown when a filter has hidden everything.
|
|
114
|
+
* @csspart list-feedback - What is wrong with it.
|
|
115
|
+
* @csspart list-filter-icon - The mark beside that field.
|
|
116
|
+
* @csspart list-filter-mark - The glyph beside the filter field, where none is slotted.
|
|
117
|
+
* @csspart list-hint - Help under the list.
|
|
118
|
+
* @csspart list-items - The list itself.
|
|
119
|
+
* @csspart list-label - The question, over the list.
|
|
120
|
+
* @csspart list-loading - Shown while the options are still on their way.
|
|
121
|
+
* @csspart list-search - The region holding the field that narrows the list.
|
|
122
|
+
* @csspart list-search-field - The field itself.
|
|
123
|
+
* @csspart option - One time in it. Carries `data-between` inside a range.
|
|
124
|
+
* @csspart option-description - The caption under the words, when there is one.
|
|
125
|
+
* @csspart option-item - The row.
|
|
126
|
+
* @csspart option-label - The words.
|
|
127
|
+
* @csspart option-text - The words and the caption, as one column.
|
|
128
|
+
*/
|
|
129
|
+
let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControllerValue(HelixFormElement) {
|
|
130
|
+
constructor() {
|
|
131
|
+
super(...arguments);
|
|
132
|
+
/**
|
|
133
|
+
* Whether the current selection fails validation.
|
|
134
|
+
*
|
|
135
|
+
* A flag rather than a message, which is the split Date Picker already drew and
|
|
136
|
+
* these two now follow. A flat picker has no room of its own for a sentence:
|
|
137
|
+
* the field that wraps one owns the label, the hint and the feedback, and a
|
|
138
|
+
* second message inside the panel would be the same error said twice. What is
|
|
139
|
+
* left for the picker is the one thing the field cannot draw from outside, the
|
|
140
|
+
* mark on the answer itself.
|
|
141
|
+
*/
|
|
142
|
+
this.invalid = false;
|
|
143
|
+
/**
|
|
144
|
+
* How far apart the offered times are, in minutes.
|
|
145
|
+
*
|
|
146
|
+
* Fifteen, which is four rows an hour and ninety-six in a day: enough that a
|
|
147
|
+
* reader scrolls rather than hunts, and few enough that the list is a list.
|
|
148
|
+
* Anything under five is a thousand rows and wants a field instead.
|
|
149
|
+
*/
|
|
150
|
+
this.step = 15;
|
|
151
|
+
/**
|
|
152
|
+
* Earliest time offered, as `HH:mm`.
|
|
153
|
+
*/
|
|
154
|
+
this.min = '00:00';
|
|
155
|
+
/**
|
|
156
|
+
* Latest time offered, as `HH:mm`.
|
|
157
|
+
*/
|
|
158
|
+
this.max = '23:59';
|
|
159
|
+
/**
|
|
160
|
+
* Times that cannot be chosen, comma separated, as `HH:mm`.
|
|
161
|
+
*
|
|
162
|
+
* The counterpart to Date Picker's `disable-dates`, and it exists for the same
|
|
163
|
+
* shape of problem: `min` and `max` take away a span, and what a booking
|
|
164
|
+
* usually has to take away is a scatter. A morning with 09:30 and 11:00
|
|
165
|
+
* already gone is not two bounds.
|
|
166
|
+
*
|
|
167
|
+
* A time not on the step is simply never offered, so it is not an error to
|
|
168
|
+
* name one, and naming every time in the list is how the empty state is
|
|
169
|
+
* reached honestly rather than by handing over an empty range.
|
|
170
|
+
*/
|
|
171
|
+
this.disableTimes = '';
|
|
172
|
+
/**
|
|
173
|
+
* Language tag the times are written in.
|
|
174
|
+
*
|
|
175
|
+
* Absent uses the runtime's own.
|
|
176
|
+
*/
|
|
177
|
+
this.locale = '';
|
|
178
|
+
/**
|
|
179
|
+
* Accessible name for the list, which has no visible one of its own.
|
|
180
|
+
*/
|
|
181
|
+
this.label = 'Time';
|
|
182
|
+
/**
|
|
183
|
+
* Takes what the list announced and constrains it to what the mode allows.
|
|
184
|
+
*
|
|
185
|
+
* The listbox is put in `multiple` for both modes, because that is what marks
|
|
186
|
+
* more than one row and toggles on press. A range then differs only in what is
|
|
187
|
+
* kept: two, and a third pick starts again from that third one. Working out
|
|
188
|
+
* which is newest by difference rather than by position, since a toggle can
|
|
189
|
+
* remove as easily as add and the announced list is a set rather than a
|
|
190
|
+
* sequence.
|
|
191
|
+
*/
|
|
192
|
+
this.handleChange = (event) => {
|
|
193
|
+
event.stopPropagation();
|
|
194
|
+
/* `disabled` meant nothing here beyond dropping the value at submit time,
|
|
195
|
+
the same gap the calendar had: times still took a click, the keyboard
|
|
196
|
+
still moved through the list, and nothing said the control was off. The
|
|
197
|
+
listbox is told as well, which is what grays it and takes it out of the
|
|
198
|
+
tab order, and this refuses at the source so every path in is covered by
|
|
199
|
+
one check.
|
|
200
|
+
`isDisabled` rather than `disabled`, which is only the half a consumer
|
|
201
|
+
wrote: an ancestor `<fieldset disabled>` is the other half. */
|
|
202
|
+
if (this.isDisabled) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const announced = event.detail.value;
|
|
206
|
+
/* The listbox already skips a disabled option, so this is the second lock
|
|
207
|
+
rather than the first: it covers a value arriving from a consumer's own
|
|
208
|
+
dispatch, and it is what makes the refusal a fact about the component
|
|
209
|
+
rather than about the listbox it happens to render. */
|
|
210
|
+
if (announced.split(',').some((one) => this.barred(one.trim()))) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (this.mode !== 'range') {
|
|
214
|
+
this.requestValue(announced);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const next = announced
|
|
218
|
+
.split(',')
|
|
219
|
+
.map((one) => one.trim())
|
|
220
|
+
.filter(Boolean);
|
|
221
|
+
if (next.length <= 2) {
|
|
222
|
+
this.requestValue(next.sort().join(','));
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const before = new Set(this.held);
|
|
226
|
+
const added = next.find((one) => !before.has(one));
|
|
227
|
+
this.requestValue(added ?? '');
|
|
228
|
+
};
|
|
229
|
+
/** Puts a changed column back together into a whole time. */
|
|
230
|
+
this.moveColumn = (part, to) => {
|
|
231
|
+
if (this.isDisabled) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const { hour, meridiem, minute } = this.parts;
|
|
235
|
+
let next = hour * 60 + minute;
|
|
236
|
+
if (part === 'minute') {
|
|
237
|
+
next = hour * 60 + Number(to);
|
|
238
|
+
}
|
|
239
|
+
else if (part === 'hour') {
|
|
240
|
+
/* On a twelve hour clock the column says 1 to 12 and the meridiem says
|
|
241
|
+
which half, so the two have to be recombined rather than read straight:
|
|
242
|
+
12 AM is midnight and 12 PM is noon, which is the one pair that does not
|
|
243
|
+
follow the pattern. */
|
|
244
|
+
const shown = Number(to);
|
|
245
|
+
const whole = isTwelveHour(this.locale) ? (shown % 12) + (meridiem === 'PM' ? 12 : 0) : shown;
|
|
246
|
+
next = whole * 60 + minute;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
const half = hour % 12;
|
|
250
|
+
next = (half + (to === 'PM' ? 12 : 0)) * 60 + minute;
|
|
251
|
+
}
|
|
252
|
+
/* The wheels build a value from three columns and never reach
|
|
253
|
+
`handleChange`, so the refusal has to be repeated here. Disabling the
|
|
254
|
+
options is not enough on its own: a reader on 09:00 who moves the hour to
|
|
255
|
+
10 lands on 10:00, and 10:00 can be barred while nothing in the hour
|
|
256
|
+
column was. */
|
|
257
|
+
const whole = fromMinutes(next);
|
|
258
|
+
if (this.barred(whole)) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
this.requestValue(whole);
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Whether the control refuses changes while still submitting its value.
|
|
265
|
+
*
|
|
266
|
+
* **Enforced by refusing every request in one place**, which is the seam this
|
|
267
|
+
* component already has: `requestValue` is what every path here comes through,
|
|
268
|
+
* and gating it once is what stops the next call site from being written
|
|
269
|
+
* without the check.
|
|
270
|
+
*
|
|
271
|
+
* Not `disabled`, which is the confusion worth naming: a disabled control
|
|
272
|
+
* submits nothing and leaves the tab order, and a read-only one submits its
|
|
273
|
+
* value and stays reachable, which is what a form showing a value somebody
|
|
274
|
+
* else set needs.
|
|
275
|
+
*/
|
|
276
|
+
this.readOnly = false;
|
|
277
|
+
/**
|
|
278
|
+
* Whether the form refuses to submit while nothing is chosen.
|
|
279
|
+
*/
|
|
280
|
+
this.required = false;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Every time on offer, as minutes since midnight.
|
|
284
|
+
*
|
|
285
|
+
* Built from `min` upward rather than from midnight, so a list that starts at
|
|
286
|
+
* `09:00` steps from nine rather than offering `09:15` because that is where
|
|
287
|
+
* the quarter hours from midnight happen to land. A step that does not divide
|
|
288
|
+
* the hour is a real thing to want, twenty minutes being the obvious one, and
|
|
289
|
+
* this is the reading that makes it behave.
|
|
290
|
+
*/
|
|
291
|
+
get times() {
|
|
292
|
+
const from = toMinutes(this.min) ?? 0;
|
|
293
|
+
const to = toMinutes(this.max) ?? 1439;
|
|
294
|
+
const step = Math.max(1, Math.round(this.step));
|
|
295
|
+
const found = [];
|
|
296
|
+
for (let at = from; at <= to; at += step) {
|
|
297
|
+
found.push(at);
|
|
298
|
+
}
|
|
299
|
+
return found;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Whether a time is barred by name.
|
|
303
|
+
*
|
|
304
|
+
* `barred`, not `disabled`, for the reason Date Picker records: this is a form
|
|
305
|
+
* control and `HelixFormElement.disabled` is a boolean about the whole of it,
|
|
306
|
+
* so a method and a flag cannot share the name.
|
|
307
|
+
*
|
|
308
|
+
* Only the named list. `min` and `max` are not consulted here because they
|
|
309
|
+
* never produce a row to bar: `times` builds the list between them, so a time
|
|
310
|
+
* outside the bounds is absent rather than present and refused.
|
|
311
|
+
*/
|
|
312
|
+
barred(at) {
|
|
313
|
+
return this.disableTimes
|
|
314
|
+
.split(',')
|
|
315
|
+
.map((one) => one.trim())
|
|
316
|
+
.filter(Boolean)
|
|
317
|
+
.includes(at);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Whether every offered time in an hour is barred.
|
|
321
|
+
*
|
|
322
|
+
* `shown` is the meridiem the wheel is on, so `1` means 01:00 under AM and
|
|
323
|
+
* 13:00 under PM. Absent is a 24 hour clock, where the number is the hour.
|
|
324
|
+
*/
|
|
325
|
+
wholeHourBarred(shown, half) {
|
|
326
|
+
const whole = half === undefined ? shown : (shown % 12) + (half === 'PM' ? 12 : 0);
|
|
327
|
+
const within = this.times.filter((at) => Math.floor(at / 60) === whole);
|
|
328
|
+
return within.length > 0 && within.every((at) => this.barred(fromMinutes(at)));
|
|
329
|
+
}
|
|
330
|
+
/** Whether every offered time in a half of the clock is barred. */
|
|
331
|
+
halfBarred(half) {
|
|
332
|
+
const within = this.times.filter((at) => (half === 'PM') === at >= 720);
|
|
333
|
+
return within.length > 0 && within.every((at) => this.barred(fromMinutes(at)));
|
|
334
|
+
}
|
|
335
|
+
/** The times held, which is a list whether or not a mode is set. */
|
|
336
|
+
get held() {
|
|
337
|
+
return this.value
|
|
338
|
+
.split(',')
|
|
339
|
+
.map((one) => one.trim())
|
|
340
|
+
.filter(Boolean);
|
|
341
|
+
}
|
|
342
|
+
/** Whether a time falls inside a range, which is what gets banded. */
|
|
343
|
+
between(at) {
|
|
344
|
+
if (this.mode !== 'range') {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
const [from, to] = this.held;
|
|
348
|
+
return from !== undefined && to !== undefined && at > from && at < to;
|
|
349
|
+
}
|
|
350
|
+
/** The three readings a wheel shows, from the value or from `min`. */
|
|
351
|
+
get parts() {
|
|
352
|
+
const at = toMinutes(this.value) ?? toMinutes(this.min) ?? 0;
|
|
353
|
+
const hour = Math.floor(at / 60);
|
|
354
|
+
return { hour, meridiem: hour < 12 ? 'AM' : 'PM', minute: at % 60 };
|
|
355
|
+
}
|
|
356
|
+
/** Every whole hour that has at least one offered time in it. */
|
|
357
|
+
get hours() {
|
|
358
|
+
const found = new Set(this.times.map((at) => Math.floor(at / 60)));
|
|
359
|
+
return [...found];
|
|
360
|
+
}
|
|
361
|
+
/** Every minute offered within the hour currently shown. */
|
|
362
|
+
get minutes() {
|
|
363
|
+
const hour = this.parts.hour;
|
|
364
|
+
return this.times.filter((at) => Math.floor(at / 60) === hour).map((at) => at % 60);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Each wheel comes to rest on its own answer.
|
|
368
|
+
*
|
|
369
|
+
* A dial that opens at midnight when it holds ten in the evening is a dial
|
|
370
|
+
* showing the wrong thing, and CSS cannot fix it: `scroll-snap-type` chooses a
|
|
371
|
+
* snap point when something scrolls, and nothing has. Measured before this,
|
|
372
|
+
* with the value at 22:00, the hour wheel sat 288 pixels above its answer.
|
|
373
|
+
*
|
|
374
|
+
* On every update rather than on the first, because the columns re-render as
|
|
375
|
+
* the value moves and the minute column's contents change with the hour.
|
|
376
|
+
*
|
|
377
|
+
* **And it is public, because an update is not the only moment that matters.**
|
|
378
|
+
* Inside a panel this element renders while the panel is still
|
|
379
|
+
* `display: none`, so every box measures zero and there is nothing to center
|
|
380
|
+
* against: measured, the hour wheel stayed 288 pixels off its answer because
|
|
381
|
+
* the only call happened before anything had a size. Whatever shows the panel
|
|
382
|
+
* calls this again afterwards. The guard below makes the early call harmless
|
|
383
|
+
* rather than wrong, which is why it can be left in.
|
|
384
|
+
*/
|
|
385
|
+
reveal() {
|
|
386
|
+
if (this.variant !== 'wheels' || this.mode !== undefined) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
for (const column of this.renderRoot?.querySelectorAll('[part="column"]') ?? []) {
|
|
390
|
+
column.reveal?.();
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/** Refuses every change while read-only. See `readOnly`. */
|
|
394
|
+
requestValue(next) {
|
|
395
|
+
if (this.readOnly) {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
return super.requestValue(next);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Reports "required and empty", or clears it.
|
|
402
|
+
*
|
|
403
|
+
* Written out rather than taken from `MixinField`, which is where the seven
|
|
404
|
+
* form controls get this. That mixin brings a label, a hint and a feedback
|
|
405
|
+
* region with it, and this is a grid rather than a field: it is composed
|
|
406
|
+
* *into* the field that has those, so taking the mixin would give one control
|
|
407
|
+
* two of each. What is shared is five lines, and the anchor is what the
|
|
408
|
+
* browser points its bubble at.
|
|
409
|
+
*/
|
|
410
|
+
reportRequired() {
|
|
411
|
+
const anchor = this.renderRoot?.querySelector('[part="list"]') ?? undefined;
|
|
412
|
+
if (this.required && this.value === '') {
|
|
413
|
+
this.internals.setValidity({ valueMissing: true }, 'Choose a time.', anchor);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
/* A value the wheels cannot read is bad input, the same as on the calendar
|
|
417
|
+
and for the same measured reason: `value="not-a-time"` marked no row,
|
|
418
|
+
reported `:valid` and was handed to the form. `asTime` rejects the hours
|
|
419
|
+
and minutes that are shaped right and out of range as well as the ones
|
|
420
|
+
that are not shaped right at all. */
|
|
421
|
+
const held = this.held;
|
|
422
|
+
if (held.length > 0 && held.some((one) => asTime(one) === null)) {
|
|
423
|
+
this.internals.setValidity({ badInput: true }, this.mode === undefined
|
|
424
|
+
? 'Enter a time as HH:mm.'
|
|
425
|
+
: 'Enter times as HH:mm, separated by commas.', anchor);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
this.internals.setValidity({});
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Reports the times to the form, one entry each.
|
|
432
|
+
*
|
|
433
|
+
* **This element was form-associated, took a `name`, held a `value` and
|
|
434
|
+
* reported `valueMissing`, and never called `setFormValue` at all.** So
|
|
435
|
+
* `<helix-time-picker name="start" required>` refused the submit until a
|
|
436
|
+
* reader filled it and then submitted nothing, which is the worst shape the
|
|
437
|
+
* omission takes: every visible signal says the control is participating.
|
|
438
|
+
* Measured before the fix, one form holding both pickers, both named and
|
|
439
|
+
* both seeded: the entry list carried the date and no time.
|
|
440
|
+
*
|
|
441
|
+
* `FormData` and one entry per time, which is `DatePicker.report` exactly.
|
|
442
|
+
* `mode="multiple"` is genuinely several answers, and a server reading
|
|
443
|
+
* `times=09:00,17:00` would have to split it on a convention this library
|
|
444
|
+
* invented; `range` sends its two in order, so start and end arrive as the
|
|
445
|
+
* pair they already are.
|
|
446
|
+
*
|
|
447
|
+
* **Nothing at all without a `name`.** A `FormData` carries its own names and
|
|
448
|
+
* its entries are appended whatever the element is called, so an unnamed
|
|
449
|
+
* picker would submit empty-named times rather than being skipped the way a
|
|
450
|
+
* control reporting a plain string is. That is the same guard, for the same
|
|
451
|
+
* reason, that the calendar's own note spells out.
|
|
452
|
+
*/
|
|
453
|
+
report() {
|
|
454
|
+
const times = this.held;
|
|
455
|
+
if (this.name === '' || this.disabled || times.length === 0) {
|
|
456
|
+
this.internals.setFormValue(null);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const data = new FormData();
|
|
460
|
+
for (const time of times) {
|
|
461
|
+
data.append(this.name, time);
|
|
462
|
+
}
|
|
463
|
+
this.internals.setFormValue(data);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Reveals once the wheels have rendered themselves.
|
|
467
|
+
*
|
|
468
|
+
* `updated` is this element's own moment, and each wheel is a `helix-listbox`
|
|
469
|
+
* that was created during this very render: its first update has been
|
|
470
|
+
* scheduled and has not run, so it has no rows and no height and `reveal`
|
|
471
|
+
* measures zero and gives up. Measured on a standalone picker, every column
|
|
472
|
+
* sat at `scrollTop: 0` with the answer nine rows down, which reads as a wheel
|
|
473
|
+
* showing the wrong time rather than as one that failed to scroll.
|
|
474
|
+
*
|
|
475
|
+
* It survived because the case that was tested was the panel, and whatever
|
|
476
|
+
* opens a panel calls `reveal` again afterwards for the separate reason the
|
|
477
|
+
* method documents. Flat on a page there is no panel and no second call.
|
|
478
|
+
*
|
|
479
|
+
* Safe to run on every update: the listbox stops as soon as the chosen row is
|
|
480
|
+
* within a pixel of center, so a call with nothing to do costs two rect reads
|
|
481
|
+
* and changes nothing. It cannot fight a reader mid-scroll either, since
|
|
482
|
+
* scrolling a wheel changes no property and so schedules no update.
|
|
483
|
+
*/
|
|
484
|
+
async revealWhenSettled() {
|
|
485
|
+
const columns = [
|
|
486
|
+
...(this.renderRoot?.querySelectorAll('[part="column"]') ?? []),
|
|
487
|
+
];
|
|
488
|
+
await Promise.all(columns.map((column) => column.updateComplete));
|
|
489
|
+
this.reveal();
|
|
490
|
+
}
|
|
491
|
+
/* `ariaInvalid` on the host through `ElementInternals`, the same route
|
|
492
|
+
Date Picker takes and for the reason the whole library records: a `role` or a
|
|
493
|
+
state written onto the host as an attribute is one a React consumer's
|
|
494
|
+
server markup never had. */
|
|
495
|
+
willUpdate(changed) {
|
|
496
|
+
super.willUpdate(changed);
|
|
497
|
+
this.internals.ariaInvalid = this.invalid ? 'true' : null;
|
|
498
|
+
/* Here rather than in `updated`, which is where `DatePicker` reports from
|
|
499
|
+
too: the value is known before the render and a form read between the two
|
|
500
|
+
should not see the previous one. */
|
|
501
|
+
this.report();
|
|
502
|
+
}
|
|
503
|
+
updated(changed) {
|
|
504
|
+
super.updated(changed);
|
|
505
|
+
this.reportRequired();
|
|
506
|
+
this.reveal();
|
|
507
|
+
void this.revealWhenSettled();
|
|
508
|
+
}
|
|
509
|
+
/** Puts the keyboard on the list, which is the only control here. */
|
|
510
|
+
focus(options) {
|
|
511
|
+
this.renderRoot?.querySelector('[part="list"]')?.focus(options);
|
|
512
|
+
}
|
|
513
|
+
/* One wheel, which is a listbox like the whole list is. */
|
|
514
|
+
/**
|
|
515
|
+
* One wheel.
|
|
516
|
+
*
|
|
517
|
+
* `barred` is passed per column rather than read from `disableTimes` here,
|
|
518
|
+
* because a column holds a third of a time and only the caller knows the
|
|
519
|
+
* other two thirds. What that means differs by column and the difference is
|
|
520
|
+
* not a detail: a minute is barred when *this* hour plus it is, and an hour is
|
|
521
|
+
* barred only when every minute in it is, since one free minute is a reason to
|
|
522
|
+
* open the wheel rather than to close it.
|
|
523
|
+
*/
|
|
524
|
+
/* `protected` rather than `private`, which is the whole of what a seam is
|
|
525
|
+
here: the method already existed and a tier above could not reach it. */
|
|
526
|
+
renderColumn(part, label, values, written, value, barred = () => false) {
|
|
527
|
+
return html `<${this.tag('listbox')}
|
|
528
|
+
part="column"
|
|
529
|
+
data-column=${part}
|
|
530
|
+
exportparts="empty: column-empty, feedback: column-feedback, filter-icon: column-filter-icon,
|
|
531
|
+
filter-mark: column-filter-mark, hint: column-hint, items: column-items, label: column-label,
|
|
532
|
+
loading: column-loading, search: column-search, search-field: column-search-field"
|
|
533
|
+
aria-label=${label}
|
|
534
|
+
?disabled=${this.isDisabled}
|
|
535
|
+
.value=${value}
|
|
536
|
+
@helix-before-change=${(event) => {
|
|
537
|
+
event.stopPropagation();
|
|
538
|
+
this.moveColumn(part, event.detail.value);
|
|
539
|
+
}}
|
|
540
|
+
>
|
|
541
|
+
${values.map((one) => html `<${this.tag('option')} part="option"
|
|
542
|
+
exportparts="description: option-description, item: option-item, label: option-label, text: option-text" value=${one} ?disabled=${barred(one)}
|
|
543
|
+
>${written(one)}</${this.tag('option')}
|
|
544
|
+
>`)}
|
|
545
|
+
</${this.tag('listbox')}>`;
|
|
546
|
+
}
|
|
547
|
+
renderSpinner() {
|
|
548
|
+
const twelve = isTwelveHour(this.locale);
|
|
549
|
+
const { hour, meridiem, minute } = this.parts;
|
|
550
|
+
const shownHour = twelve ? String(hour % 12 === 0 ? 12 : hour % 12) : String(hour);
|
|
551
|
+
/* The hour column reads 1 to 12 on a twelve hour clock, so the whole hours
|
|
552
|
+
on offer are mapped into that half and de-duplicated: 13:00 and 01:00 are
|
|
553
|
+
both "1", and offering it twice is offering a choice that is not one. */
|
|
554
|
+
const hours = twelve
|
|
555
|
+
? [...new Set(this.hours.map((one) => (one % 12 === 0 ? 12 : one % 12)))].sort((a, b) => a - b)
|
|
556
|
+
: this.hours;
|
|
557
|
+
return html `<div part="columns" data-unset=${this.value === '' ? '' : nothing}>
|
|
558
|
+
${this.renderColumn('hour', 'Hour', hours.map(String), (one) => (twelve ? one : one.padStart(2, '0')), shownHour, (one) => this.wholeHourBarred(Number(one), twelve ? meridiem : undefined))}
|
|
559
|
+
${this.renderColumn('minute', 'Minute', this.minutes.map(String), (one) => one.padStart(2, '0'), String(minute), (one) => this.barred(fromMinutes(hour * 60 + Number(one))))}
|
|
560
|
+
${twelve
|
|
561
|
+
? this.renderColumn('meridiem', 'Before or after noon', ['AM', 'PM'], (one) => one, meridiem, (one) => this.halfBarred(one))
|
|
562
|
+
: nothing}
|
|
563
|
+
</div>`;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* The flat list of times, for the appearance that is not wheels, behind a seam the styled tier can move.
|
|
567
|
+
*
|
|
568
|
+
* A method rather than a fragment inline, so a tier above can render its own,
|
|
569
|
+
* wrap this one, pass it a property the base does not know about, or leave it
|
|
570
|
+
* out, without reimplementing the whole template to do any of them. The tag is
|
|
571
|
+
* interpolated rather than written, so `tier` resolves it: this renders the
|
|
572
|
+
* headless element, and a styled subclass that sets `tier` renders the styled one
|
|
573
|
+
* from the same template.
|
|
574
|
+
*/
|
|
575
|
+
renderList() {
|
|
576
|
+
return html `<${this.tag('listbox')}
|
|
577
|
+
part="list"
|
|
578
|
+
exportparts="empty: list-empty, feedback: list-feedback, filter-icon: list-filter-icon,
|
|
579
|
+
filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
|
|
580
|
+
loading: list-loading, search: list-search, search-field: list-search-field"
|
|
581
|
+
aria-label=${this.label}
|
|
582
|
+
data-unset=${this.value === '' ? '' : nothing}
|
|
583
|
+
?disabled=${this.isDisabled}
|
|
584
|
+
?multiple=${this.mode !== undefined}
|
|
585
|
+
.value=${this.value}
|
|
586
|
+
@helix-before-change=${this.handleChange}
|
|
587
|
+
>
|
|
588
|
+
${this.times.map((minutes) => {
|
|
589
|
+
const at = fromMinutes(minutes);
|
|
590
|
+
return html `<${this.tag('option')}
|
|
591
|
+
part="option"
|
|
592
|
+
exportparts="description: option-description, item: option-item, label: option-label, text: option-text"
|
|
593
|
+
value=${at}
|
|
594
|
+
?disabled=${this.barred(at)}
|
|
595
|
+
data-between=${this.between(at) ? '' : nothing}
|
|
596
|
+
>${writeTime(at, this.locale)}</${this.tag('option')}
|
|
597
|
+
>`;
|
|
598
|
+
})}
|
|
599
|
+
</${this.tag('listbox')}>`;
|
|
600
|
+
}
|
|
601
|
+
render() {
|
|
602
|
+
/* A mode falls back to the list, for the reason the property records: a
|
|
603
|
+
range on wheels is two sets of wheels and a multiple is a set, which a
|
|
604
|
+
wheel cannot hold. */
|
|
605
|
+
if (this.variant === 'wheels' && this.mode === undefined) {
|
|
606
|
+
return this.renderSpinner();
|
|
607
|
+
}
|
|
608
|
+
return html `${this.renderList()}`;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* The value as a `Date` on 1 January 1970 UTC, or `null` while there is no time.
|
|
612
|
+
*
|
|
613
|
+
* The platform's own pair on `<input type="time">`, epoch day included: a time
|
|
614
|
+
* is an offset into a day rather than an instant, and putting it on the epoch
|
|
615
|
+
* is what makes `valueAsNumber` come out as milliseconds since midnight rather
|
|
616
|
+
* than as a moment nobody meant. Assigning any date reads the clock off it, so
|
|
617
|
+
* a consumer handing over `new Date()` gets the time of day they expected.
|
|
618
|
+
*/
|
|
619
|
+
get valueAsDate() {
|
|
620
|
+
return asTime(this.value);
|
|
621
|
+
}
|
|
622
|
+
set valueAsDate(date) {
|
|
623
|
+
this.value = fromTime(date);
|
|
624
|
+
}
|
|
625
|
+
/** The value as milliseconds since midnight, or `NaN` while there is no time. */
|
|
626
|
+
get valueAsNumber() {
|
|
627
|
+
return asTime(this.value)?.getTime() ?? Number.NaN;
|
|
628
|
+
}
|
|
629
|
+
set valueAsNumber(ms) {
|
|
630
|
+
this.value = Number.isNaN(ms) ? '' : fromTime(new Date(ms));
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
__decorate([
|
|
634
|
+
property({ reflect: true, type: Boolean })
|
|
635
|
+
], HelixHeadlessTimePicker.prototype, "invalid", void 0);
|
|
636
|
+
__decorate([
|
|
637
|
+
property({ type: Number })
|
|
638
|
+
], HelixHeadlessTimePicker.prototype, "step", void 0);
|
|
639
|
+
__decorate([
|
|
640
|
+
property()
|
|
641
|
+
], HelixHeadlessTimePicker.prototype, "min", void 0);
|
|
642
|
+
__decorate([
|
|
643
|
+
property()
|
|
644
|
+
], HelixHeadlessTimePicker.prototype, "max", void 0);
|
|
645
|
+
__decorate([
|
|
646
|
+
property({ attribute: 'disable-times' })
|
|
647
|
+
], HelixHeadlessTimePicker.prototype, "disableTimes", void 0);
|
|
648
|
+
__decorate([
|
|
649
|
+
property()
|
|
650
|
+
], HelixHeadlessTimePicker.prototype, "locale", void 0);
|
|
651
|
+
__decorate([
|
|
652
|
+
property()
|
|
653
|
+
], HelixHeadlessTimePicker.prototype, "label", void 0);
|
|
654
|
+
__decorate([
|
|
655
|
+
property({ reflect: true })
|
|
656
|
+
], HelixHeadlessTimePicker.prototype, "mode", void 0);
|
|
657
|
+
__decorate([
|
|
658
|
+
property({ reflect: true })
|
|
659
|
+
], HelixHeadlessTimePicker.prototype, "variant", void 0);
|
|
660
|
+
__decorate([
|
|
661
|
+
property({ attribute: 'readonly', reflect: true, type: Boolean })
|
|
662
|
+
], HelixHeadlessTimePicker.prototype, "readOnly", void 0);
|
|
663
|
+
__decorate([
|
|
664
|
+
property({ reflect: true, type: Boolean })
|
|
665
|
+
], HelixHeadlessTimePicker.prototype, "required", void 0);
|
|
666
|
+
HelixHeadlessTimePicker = __decorate([
|
|
667
|
+
customElement('helix-headless-time-picker')
|
|
668
|
+
], HelixHeadlessTimePicker);
|
|
669
|
+
export { HelixHeadlessTimePicker };
|