@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,791 @@
|
|
|
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 { AriaForwardController, valueAsDate as asDate, customElement, dateAsValue as fromDate, HelixFormElement, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { calendarBlank } from '@fusion.dev/helix-icons';
|
|
9
|
+
import { nothing } from 'lit';
|
|
10
|
+
import { property, state } from 'lit/decorators.js';
|
|
11
|
+
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
|
+
import { html } from 'lit/static-html.js';
|
|
13
|
+
import '../../date-picker/index.js';
|
|
14
|
+
import '../../tag/index.js';
|
|
15
|
+
/** Whether a string is a date the rest of this component can reason about. */
|
|
16
|
+
const isIso = (value) => /^\d{4}-\d{2}-\d{2}$/.test(value);
|
|
17
|
+
/**
|
|
18
|
+
* The dates in a value, which may hold more than one.
|
|
19
|
+
*
|
|
20
|
+
* A range is two and a multiple is any number, comma separated, which is what
|
|
21
|
+
* the calendar announces and what a form field can carry as one string. Empty
|
|
22
|
+
* entries are dropped so a trailing comma while typing is not a date.
|
|
23
|
+
*/
|
|
24
|
+
const dates = (value) =>
|
|
25
|
+
/* The en dash and the spaced hyphen both mean "to", because a range is shown
|
|
26
|
+
that way and what is shown is what gets typed back. An ISO date holds
|
|
27
|
+
hyphens of its own, so only a spaced one separates: `2026-08-04-2026-08-11`
|
|
28
|
+
is not a thing anybody writes, and treating a bare hyphen as a separator
|
|
29
|
+
would take `2026-08-04` apart into three numbers. */
|
|
30
|
+
value
|
|
31
|
+
.replace(/\s+[–-]\s+/g, ',')
|
|
32
|
+
.split(',')
|
|
33
|
+
.map((one) => one.trim())
|
|
34
|
+
.filter(Boolean);
|
|
35
|
+
/**
|
|
36
|
+
* @summary A date, typed or picked from a calendar.
|
|
37
|
+
*
|
|
38
|
+
* @description
|
|
39
|
+
* **The calendar is `helix-date-picker`, not a second one written here.** It
|
|
40
|
+
* already knows about months, ranges, disabled days, the first day of the week
|
|
41
|
+
* and every keyboard rule a grid owes a reader, and a picker that reimplemented
|
|
42
|
+
* a tenth of that would be a worse grid that also had to be maintained. This
|
|
43
|
+
* element is the field, the overlay, and the translation between them.
|
|
44
|
+
*
|
|
45
|
+
* **Typed as well as picked, and the typing is the reason it is not
|
|
46
|
+
* `<input type="date">`.** The native control gives a free picker and a free
|
|
47
|
+
* locale and takes almost all styling with it, which is a fair trade until a
|
|
48
|
+
* product needs the calendar to match everything around it. What is kept from
|
|
49
|
+
* the native one is the part worth keeping: a real text field, so a reader who
|
|
50
|
+
* knows the date types it and never opens anything.
|
|
51
|
+
*
|
|
52
|
+
* **The value is `YYYY-MM-DD`, always.** That is what a form submits, what
|
|
53
|
+
* `min` and `max` compare against, and what the calendar speaks. What the field
|
|
54
|
+
* *shows* is the same string: a locale-formatted display would have to be parsed
|
|
55
|
+
* back on every keystroke, and half-typed input does not survive a round trip
|
|
56
|
+
* through a formatter. The same reasoning the sandbox records for its two
|
|
57
|
+
* syntaxes, which is that a document being edited must not be a rendering of
|
|
58
|
+
* something else.
|
|
59
|
+
*
|
|
60
|
+
* **Opening does not commit.** The calendar announces a date, this element takes
|
|
61
|
+
* it, and the overlay shuts, because a single date has nothing more to say. A
|
|
62
|
+
* consumer who owns `value` answers the announcement the way they answer any
|
|
63
|
+
* other control here.
|
|
64
|
+
*
|
|
65
|
+
* @since 0.1.0
|
|
66
|
+
* @status experimental
|
|
67
|
+
* @category forms
|
|
68
|
+
* @aliases DatePicker, DateField, InputDate
|
|
69
|
+
* @documentation https://helix.fusion.dev/components/date-input
|
|
70
|
+
*
|
|
71
|
+
* @slot feedback - What is wrong with it.
|
|
72
|
+
* @slot hint - Help under the field.
|
|
73
|
+
* @slot trigger - The mark on the field saying a calendar opens.
|
|
74
|
+
*
|
|
75
|
+
* @event {Event} change - Announced once the value has moved.
|
|
76
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the date changes. Cancelable: refusing it takes the decision and nothing moves.
|
|
77
|
+
* @event {HelixBeforeCloseEvent} helix-before-close - Fired before it closes. Cancelable: refusing it takes the decision and nothing moves.
|
|
78
|
+
* @event {HelixBeforeOpenEvent} helix-before-open - Fired before the calendar opens. Cancelable: refusing it takes the decision and nothing moves.
|
|
79
|
+
* @event {Event} input - Announced once the value has moved.
|
|
80
|
+
* @event {Event} toggle - Says the state moved, carrying `newState` and `oldState`.
|
|
81
|
+
*
|
|
82
|
+
* @csspart control - The text input.
|
|
83
|
+
* @csspart date - One held date, as a tag, in `multiple`.
|
|
84
|
+
* @csspart date-dismiss - The remove button, when `dismissible`.
|
|
85
|
+
* @csspart date-dismiss-mark - The glyph on the dismiss control, where none is slotted.
|
|
86
|
+
* @csspart date-prefix - The category before the label.
|
|
87
|
+
* @csspart feedback - What is wrong with it.
|
|
88
|
+
* @csspart field - The box holding the text and the trigger.
|
|
89
|
+
* @csspart hint - Help under the field, while nothing is wrong.
|
|
90
|
+
* @csspart label - The question, over the field.
|
|
91
|
+
* @csspart picker - The date picker inside it.
|
|
92
|
+
* @csspart picker-cell - One column of a row, which is what a range paints.
|
|
93
|
+
* @csspart picker-day - The shape inside a cell, which is what a single date paints.
|
|
94
|
+
* @csspart picker-grid - The grid of days.
|
|
95
|
+
* @csspart picker-header - The month name and its controls.
|
|
96
|
+
* @csspart picker-heading - The month and year being shown.
|
|
97
|
+
* @csspart picker-month - One month, its header and its grid.
|
|
98
|
+
* @csspart picker-months - The run of months.
|
|
99
|
+
* @csspart picker-next - The control that moves to the next month.
|
|
100
|
+
* @csspart picker-next-mark - The glyph on the next month control.
|
|
101
|
+
* @csspart picker-previous - The control that moves to the previous month.
|
|
102
|
+
* @csspart picker-previous-mark - The glyph on the previous month control.
|
|
103
|
+
* @csspart picker-week - One row of days.
|
|
104
|
+
* @csspart picker-weekday - A column header naming a day of the week.
|
|
105
|
+
* @csspart rest - How many dates are held beyond the ones shown.
|
|
106
|
+
* @csspart surface - The floating panel.
|
|
107
|
+
* @csspart trigger - The control that opens the calendar.
|
|
108
|
+
* @csspart trigger-icon - The mark on the button that opens the calendar.
|
|
109
|
+
*/
|
|
110
|
+
let HelixHeadlessDateInput = class HelixHeadlessDateInput extends MixinControllerOpen(MixinControllerValue(MixinField(HelixFormElement))) {
|
|
111
|
+
constructor() {
|
|
112
|
+
super(...arguments);
|
|
113
|
+
/* A consumer's `aria-describedby` names ids in their own tree and the control
|
|
114
|
+
is in this shadow root, so the reference has to be carried down as an
|
|
115
|
+
element rather than copied as an id. See `AriaForwardController`: measured
|
|
116
|
+
in Chrome's own tree, the host held the description and the control the
|
|
117
|
+
reader is actually on was exposed without it. */
|
|
118
|
+
this.aria = new AriaForwardController(this, {
|
|
119
|
+
target: () => this.renderRoot?.querySelector('[part="control"]') ?? null,
|
|
120
|
+
});
|
|
121
|
+
/**
|
|
122
|
+
* What the browser may autofill here, as one of the platform's own tokens.
|
|
123
|
+
*
|
|
124
|
+
* Empty leaves the attribute off, which is the browser's default and is what
|
|
125
|
+
* lets autofill work at all. This used to be hardcoded `off`, so a reader
|
|
126
|
+
* could never have a birthday or a postal code filled in for them and a
|
|
127
|
+
* consumer had no way to ask for it. See 295.
|
|
128
|
+
*/
|
|
129
|
+
this.autocomplete = '';
|
|
130
|
+
/**
|
|
131
|
+
* How many months the calendar shows, side by side.
|
|
132
|
+
*
|
|
133
|
+
* Worth more than one mainly for a range, where picking a start in March and
|
|
134
|
+
* an end in April otherwise means paging between them and losing sight of the
|
|
135
|
+
* first. The panel is sized by its content, so this widens it.
|
|
136
|
+
*/
|
|
137
|
+
this.months = 1;
|
|
138
|
+
/**
|
|
139
|
+
* How many dates are shown as tags before the rest are counted, in `multiple`.
|
|
140
|
+
*
|
|
141
|
+
* `0` is all of them, and is the default: a cap that guesses is worse than no
|
|
142
|
+
* cap, because the number that fits depends on the width of the field and the
|
|
143
|
+
* length of what is in it, neither of which this element knows. What a cap is
|
|
144
|
+
* genuinely for is a field in a row or a table cell, where a set of twelve
|
|
145
|
+
* dates would push everything below it down a line at a time.
|
|
146
|
+
*
|
|
147
|
+
* The remainder is counted rather than hidden. "3 more" is a fact a reader can
|
|
148
|
+
* act on, where a row that silently stops is a field that appears to have lost
|
|
149
|
+
* what was put in it, and the count is what tells them there is more to see.
|
|
150
|
+
*/
|
|
151
|
+
this.maxTags = 0;
|
|
152
|
+
/**
|
|
153
|
+
* Earliest date that can be chosen, as `YYYY-MM-DD`.
|
|
154
|
+
*/
|
|
155
|
+
this.min = '';
|
|
156
|
+
/**
|
|
157
|
+
* How far apart the selectable dates are, in days.
|
|
158
|
+
*
|
|
159
|
+
* `<input type="date" step>`'s own unit, handed to the calendar this renders
|
|
160
|
+
* so the field and the grid agree about which dates exist. Counted from `min`
|
|
161
|
+
* where there is one and from 1 January 1970 where there is not, which is the
|
|
162
|
+
* platform's base.
|
|
163
|
+
*/
|
|
164
|
+
this.step = 1;
|
|
165
|
+
/**
|
|
166
|
+
* Latest date that can be chosen, as `YYYY-MM-DD`.
|
|
167
|
+
*/
|
|
168
|
+
this.max = '';
|
|
169
|
+
/**
|
|
170
|
+
* Dates that cannot be chosen, as a comma-separated `YYYY-MM-DD` list.
|
|
171
|
+
*/
|
|
172
|
+
this.disableDates = '';
|
|
173
|
+
/**
|
|
174
|
+
* Days of the week that cannot be chosen, `0` for Sunday through `6`.
|
|
175
|
+
*/
|
|
176
|
+
this.disableDays = '';
|
|
177
|
+
/**
|
|
178
|
+
* First column of the week in the calendar, `0` for Sunday through `6`.
|
|
179
|
+
*/
|
|
180
|
+
this.firstDayOfWeek = 0;
|
|
181
|
+
/**
|
|
182
|
+
* How a date is written in the field: `short` through `full`, or ISO.
|
|
183
|
+
*
|
|
184
|
+
* **The field renders when it is idle and holds the value when it is being
|
|
185
|
+
* edited.** A written date is a rendering, and a document being edited must
|
|
186
|
+
* not be a rendering of something else: `Intl.DateTimeFormat` formats and does
|
|
187
|
+
* not parse, so `4 August 2026` cannot be typed back, and writing a parser per
|
|
188
|
+
* locale is how a field ends up rejecting what it just displayed.
|
|
189
|
+
*
|
|
190
|
+
* The way out is not to choose between the two but to separate them in time.
|
|
191
|
+
* Idle, the field shows `4 August 2026`, which is what a date is for reading.
|
|
192
|
+
* Focused, it shows `2026-08-04`, which is what a date is for typing, and it
|
|
193
|
+
* goes back on the way out. Nothing parses a rendering, and nothing is
|
|
194
|
+
* read-only, which is what an earlier version of this settled for.
|
|
195
|
+
*
|
|
196
|
+
* A range is the exception that needs no swap: the dash between its two dates
|
|
197
|
+
* is a separator this element understands, so that much reads back either way.
|
|
198
|
+
*
|
|
199
|
+
* `iso` turns the rendering off, for a field whose reader is entering data
|
|
200
|
+
* rather than reading it, or where the ISO form is itself the point.
|
|
201
|
+
*
|
|
202
|
+
* The value is always `YYYY-MM-DD` regardless, because that is what a form
|
|
203
|
+
* submits and what `min` and `max` compare against.
|
|
204
|
+
*/
|
|
205
|
+
this.dateStyle = 'long';
|
|
206
|
+
/**
|
|
207
|
+
* Language tag the calendar names its months and days in.
|
|
208
|
+
*/
|
|
209
|
+
this.locale = '';
|
|
210
|
+
/**
|
|
211
|
+
* What the field says before a date is in it.
|
|
212
|
+
*/
|
|
213
|
+
this.placeholder = 'YYYY-MM-DD';
|
|
214
|
+
/**
|
|
215
|
+
* Accessible name for the control that opens the calendar.
|
|
216
|
+
*/
|
|
217
|
+
this.triggerLabel = 'Choose a date';
|
|
218
|
+
/**
|
|
219
|
+
* The overlay, placed against the field rather than the trigger.
|
|
220
|
+
*
|
|
221
|
+
* Against the field because that is the box a reader sees as the control: a
|
|
222
|
+
* calendar hung off a small button at one end of a wide field reads as
|
|
223
|
+
* belonging to the button. `Select` anchors to its trigger for the opposite
|
|
224
|
+
* reason, its trigger being the whole control.
|
|
225
|
+
*/
|
|
226
|
+
this.panel = new PopoverController(this, {
|
|
227
|
+
anchor: () => this.renderRoot?.querySelector('[part="field"]'),
|
|
228
|
+
/* The surface *and* the trigger.
|
|
229
|
+
*
|
|
230
|
+
* A control is not always one element: the button that opens this panel is
|
|
231
|
+
* part of it, and a press on it is not a press outside. Scoped to the
|
|
232
|
+
* surface alone, `pointerdown` on the trigger closed the panel and the
|
|
233
|
+
* trigger's own `toggleOpen` reopened it on the `click` that followed, so
|
|
234
|
+
* the panel could never be closed by the button that opened it. Measured
|
|
235
|
+
* across all five popover-bearing components: Menu, Popover and Tooltip
|
|
236
|
+
* already named their invoker; this one and its three siblings did not, and
|
|
237
|
+
* all four stayed open on a second press where Menu closed.
|
|
238
|
+
*
|
|
239
|
+
* `DismissController` documents this exact failure and takes a list for it.
|
|
240
|
+
* The list was the fix; using it was the part that did not happen here. */
|
|
241
|
+
boundary: () => [
|
|
242
|
+
this.renderRoot?.querySelector('[part="surface"]'),
|
|
243
|
+
this.renderRoot?.querySelector('[part="trigger"]'),
|
|
244
|
+
],
|
|
245
|
+
/* Wider than the four every other panel here takes. Those sit against a
|
|
246
|
+
control the same width as themselves and read as an extension of it; this
|
|
247
|
+
one is a calendar of its own size hanging off a field, so the gap is what
|
|
248
|
+
says the two are separate things rather than one control that grew. */
|
|
249
|
+
offset: () => 8,
|
|
250
|
+
onDismiss: () => this.requestOpen(false),
|
|
251
|
+
placement: 'bottom-start',
|
|
252
|
+
surface: () => this.renderRoot?.querySelector('[part="surface"]'),
|
|
253
|
+
});
|
|
254
|
+
/**
|
|
255
|
+
* Whether the caret is in the field, which is when it holds the value.
|
|
256
|
+
*/
|
|
257
|
+
this.editing = false;
|
|
258
|
+
/**
|
|
259
|
+
* What is being typed but not yet held, for `multiple` only.
|
|
260
|
+
*
|
|
261
|
+
* The other modes type into the value directly, because one date and a range
|
|
262
|
+
* are both a whole answer at the moment they are complete. A multiple is not:
|
|
263
|
+
* it is a set being added to, so the field needs somewhere to hold a date
|
|
264
|
+
* before it joins the set and somewhere to leave a half-typed one that is not
|
|
265
|
+
* a date yet.
|
|
266
|
+
*/
|
|
267
|
+
this.draft = '';
|
|
268
|
+
/** Relayed under this element's name, so a consumer hears one control. */
|
|
269
|
+
this.handleInput = (event) => {
|
|
270
|
+
event.stopPropagation();
|
|
271
|
+
// Typing is editing, whatever the focus did. The field has to hold the value
|
|
272
|
+
// while it is being changed, or a keystroke lands in a rendering.
|
|
273
|
+
this.editing = true;
|
|
274
|
+
const typed = event.target.value;
|
|
275
|
+
if (this.mode === 'multiple') {
|
|
276
|
+
this.draft = typed;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
/* Stored as commas once every date in it is whole, and kept exactly as typed
|
|
280
|
+
until then. A form should submit `2026-08-04,2026-08-11` however the dash
|
|
281
|
+
was written, and the dash is a reading of that rather than a second value
|
|
282
|
+
shape to support. Half-typed text stays verbatim, for the reason the class
|
|
283
|
+
gives about a document being edited: normalizing `2026-08-0` would take
|
|
284
|
+
the caret away mid-date. */
|
|
285
|
+
const held = dates(typed);
|
|
286
|
+
const whole = held.length > 0 && held.every(isIso);
|
|
287
|
+
this.requestValue(whole ? held.join(',') : typed);
|
|
288
|
+
this.restore();
|
|
289
|
+
};
|
|
290
|
+
/** Adds what was typed to the set, or takes the last one back out. */
|
|
291
|
+
this.handleDraftKey = (event) => {
|
|
292
|
+
if (this.mode !== 'multiple') {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const held = dates(this.value);
|
|
296
|
+
if (event.key === 'Enter' && isIso(this.draft)) {
|
|
297
|
+
event.preventDefault();
|
|
298
|
+
if (!held.includes(this.draft)) {
|
|
299
|
+
this.requestValue([...held, this.draft].join(','));
|
|
300
|
+
}
|
|
301
|
+
this.draft = '';
|
|
302
|
+
}
|
|
303
|
+
else if (event.key === 'Backspace' && this.draft === '' && held.length > 0) {
|
|
304
|
+
/* The convention every tag field has: an empty field and a backspace takes
|
|
305
|
+
the last one back, so a mistake costs one key rather than a hunt for a
|
|
306
|
+
small control. */
|
|
307
|
+
this.requestValue(held.slice(0, -1).join(','));
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
/** Takes one date back out of the set. */
|
|
311
|
+
this.removeDate = (date) => {
|
|
312
|
+
this.requestValue(dates(this.value)
|
|
313
|
+
.filter((one) => one !== date)
|
|
314
|
+
.join(','));
|
|
315
|
+
};
|
|
316
|
+
this.handleCalendarChange = (event) => {
|
|
317
|
+
event.stopPropagation();
|
|
318
|
+
const { value } = event.detail;
|
|
319
|
+
this.requestValue(value);
|
|
320
|
+
this.restore();
|
|
321
|
+
/* A single date has nothing more to say, so the panel gets out of the way.
|
|
322
|
+
A range or a multiple has: the reader is still choosing, and shutting the
|
|
323
|
+
calendar under them after the first date is taking the control away
|
|
324
|
+
mid-answer. */
|
|
325
|
+
if (this.mode === undefined) {
|
|
326
|
+
this.requestOpen(false);
|
|
327
|
+
this.updateComplete.then(() => this.returnFocus());
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
/** Escape shuts the calendar without moving the date. */
|
|
331
|
+
this.handleKeydown = (event) => {
|
|
332
|
+
if (event.key === 'Escape' && this.open) {
|
|
333
|
+
event.stopPropagation();
|
|
334
|
+
this.requestOpen(false);
|
|
335
|
+
this.returnFocus();
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Whether the control refuses changes while still submitting its value.
|
|
340
|
+
*
|
|
341
|
+
* **Enforced by refusing every request in one place**, which is the seam this
|
|
342
|
+
* component already has: `requestValue` is what every path here comes through,
|
|
343
|
+
* and gating it once is what stops the next call site from being written
|
|
344
|
+
* without the check.
|
|
345
|
+
*
|
|
346
|
+
* Not `disabled`, which is the confusion worth naming: a disabled control
|
|
347
|
+
* submits nothing and leaves the tab order, and a read-only one submits its
|
|
348
|
+
* value and stays reachable, which is what a form showing a value somebody
|
|
349
|
+
* else set needs.
|
|
350
|
+
*/
|
|
351
|
+
this.readOnly = false;
|
|
352
|
+
/*
|
|
353
|
+
* Focusing the field opens the calendar.
|
|
354
|
+
*
|
|
355
|
+
* A reader who reaches this control is choosing a date, and making them find
|
|
356
|
+
* the trigger afterwards is a second action for something they have already
|
|
357
|
+
* asked for. Typing still works with it up, because the calendar follows the
|
|
358
|
+
* field rather than the other way round.
|
|
359
|
+
*
|
|
360
|
+
* **Only where focus arrived from outside this element**, which is the whole
|
|
361
|
+
* of the difficulty. Picking a date shuts the panel and puts the caret back in
|
|
362
|
+
* the field, and the first version of this reopened it on the way: the reader
|
|
363
|
+
* chose a date and the calendar came straight back, which the existing spec
|
|
364
|
+
* caught. `relatedTarget` is where focus came from, so a hand-off from the
|
|
365
|
+
* calendar or the trigger is left alone and only a genuine arrival opens
|
|
366
|
+
* anything.
|
|
367
|
+
*
|
|
368
|
+
* On the input rather than on the field, too. Focus does not bubble, so a
|
|
369
|
+
* listener here covers the text and not the trigger, which is what keeps
|
|
370
|
+
* pressing the trigger from opening the panel on focus and then shutting it
|
|
371
|
+
* again on the click.
|
|
372
|
+
*/
|
|
373
|
+
/**
|
|
374
|
+
* Puts the caret back in the field without the field reopening the calendar.
|
|
375
|
+
*
|
|
376
|
+
* Focus opens the calendar, so handing focus back after a pick reopens the
|
|
377
|
+
* thing that was just answered. `relatedTarget` was the guard and it is not
|
|
378
|
+
* enough on its own: it catches a hand-off from the trigger, and it does not
|
|
379
|
+
* catch this, because the cell that had focus is gone by the time the caret
|
|
380
|
+
* moves and the document has fallen back to something outside this element.
|
|
381
|
+
*
|
|
382
|
+
* **Reasoned rather than measured, and worth saying which.** In a focused
|
|
383
|
+
* document: the reader presses a day, the cell has focus, the panel is hidden,
|
|
384
|
+
* the browser moves focus off the removed cell to the body, and the caret is
|
|
385
|
+
* then put back here with `relatedTarget` pointing at the body, which is
|
|
386
|
+
* outside this element and reads as an arrival. Every step is ordinary browser
|
|
387
|
+
* behavior and none of it can be exercised here: `focus()` dispatches no
|
|
388
|
+
* event in an unfocused document, which is what both the test runtime and the
|
|
389
|
+
* available browser pane are. A spec was written for it and passed with the
|
|
390
|
+
* guard removed, so it was covering nothing and has been taken out rather than
|
|
391
|
+
* left to look like proof.
|
|
392
|
+
*
|
|
393
|
+
* A flag rather than a better guess, because this element is the one moving
|
|
394
|
+
* the focus and is the only thing that can know so. Cleared synchronously,
|
|
395
|
+
* since `focus()` dispatches before it returns.
|
|
396
|
+
*/
|
|
397
|
+
this.returning = false;
|
|
398
|
+
this.handleBlur = () => {
|
|
399
|
+
this.editing = false;
|
|
400
|
+
};
|
|
401
|
+
this.handleFocus = (event) => {
|
|
402
|
+
/* Not while the caret is being handed back. Picking a date returns focus
|
|
403
|
+
to the field, and treating that as editing put the field into the shape it
|
|
404
|
+
takes for typing: a reader chose "10:00 PM" from a list and the field
|
|
405
|
+
answered "22:00". Focus is a good enough signal for editing everywhere
|
|
406
|
+
except the one moment this element moved the focus itself, and it already
|
|
407
|
+
knows when that is. */
|
|
408
|
+
this.editing = !this.returning;
|
|
409
|
+
const from = event.relatedTarget;
|
|
410
|
+
if (this.open || this.isDisabled || this.returning) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (from instanceof Node && this.renderRoot?.contains?.(from)) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
this.requestOpen(true);
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
get control() {
|
|
420
|
+
if (typeof this.renderRoot?.querySelector !== 'function') {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
return this.renderRoot.querySelector('[part="control"]');
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* What the calendar should show, which is only ever a whole date.
|
|
427
|
+
*
|
|
428
|
+
* Half-typed input reaches here on every keystroke, and `2026-08-1` is not a
|
|
429
|
+
* date: handing it to the calendar would move the month under a reader
|
|
430
|
+
* mid-word. So the grid follows the field only once the field says something
|
|
431
|
+
* complete.
|
|
432
|
+
*/
|
|
433
|
+
get picked() {
|
|
434
|
+
const held = dates(this.value);
|
|
435
|
+
return held.length > 0 && held.every(isIso) ? held.join(',') : '';
|
|
436
|
+
}
|
|
437
|
+
/*
|
|
438
|
+
* What the field shows, which is the value in every mode but one.
|
|
439
|
+
*
|
|
440
|
+
* A range reads `2026-08-04 – 2026-08-11`, because two dates separated by a
|
|
441
|
+
* comma is a list and a range is a span: the comma says "and these", the dash
|
|
442
|
+
* says "through". It is the one place this component shows something other
|
|
443
|
+
* than the value it holds, and it is safe because the dash reads back: `dates`
|
|
444
|
+
* takes a spaced dash as a separator, so what is shown is what can be typed.
|
|
445
|
+
*
|
|
446
|
+
* `multiple` shows nothing here at all. Its dates are tags beside the input
|
|
447
|
+
* and the input is a draft, which is the next thing down.
|
|
448
|
+
*/
|
|
449
|
+
/** One date, written the way `dateStyle` asks for. */
|
|
450
|
+
written(date) {
|
|
451
|
+
if (this.dateStyle === 'iso' || !isIso(date)) {
|
|
452
|
+
return date;
|
|
453
|
+
}
|
|
454
|
+
/* UTC, because the dates are UTC throughout: a date parsed in a zone behind
|
|
455
|
+
Greenwich renders as the day before, which is the classic off-by-one that
|
|
456
|
+
makes a calendar disagree with the field beside it. */
|
|
457
|
+
const at = new Date(`${date}T00:00:00Z`);
|
|
458
|
+
return Number.isNaN(at.getTime())
|
|
459
|
+
? date
|
|
460
|
+
: new Intl.DateTimeFormat(this.locale || undefined, {
|
|
461
|
+
dateStyle: this.dateStyle,
|
|
462
|
+
timeZone: 'UTC',
|
|
463
|
+
}).format(at);
|
|
464
|
+
}
|
|
465
|
+
get display() {
|
|
466
|
+
if (this.mode === 'multiple') {
|
|
467
|
+
return this.draft;
|
|
468
|
+
}
|
|
469
|
+
const held = dates(this.value);
|
|
470
|
+
/* Being edited, the field is the value. The rendering is what it shows when
|
|
471
|
+
nobody is in it, so there is never a moment where what is on screen is
|
|
472
|
+
something this element could not read back. */
|
|
473
|
+
if (this.editing || this.dateStyle === 'iso') {
|
|
474
|
+
return this.mode === 'range' && held.length === 2 ? held.join(' – ') : this.value;
|
|
475
|
+
}
|
|
476
|
+
const written = held.map((one) => this.written(one));
|
|
477
|
+
return this.mode === 'range' ? written.join(' – ') : written.join(', ');
|
|
478
|
+
}
|
|
479
|
+
/** The dates that get a tag, which is all of them until `maxTags` says not. */
|
|
480
|
+
get shownDates() {
|
|
481
|
+
const held = dates(this.value);
|
|
482
|
+
return this.maxTags > 0 ? held.slice(0, this.maxTags) : held;
|
|
483
|
+
}
|
|
484
|
+
/** How many are held beyond the ones shown. */
|
|
485
|
+
get restCount() {
|
|
486
|
+
return Math.max(0, dates(this.value).length - this.shownDates.length);
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Puts the field back where the answer differs from what was typed.
|
|
490
|
+
*
|
|
491
|
+
* `requestValue` is the mixin's, and it announces and decides; this is the
|
|
492
|
+
* other half, which `Input` needs for the same reason: the native control has
|
|
493
|
+
* already changed, so wherever the answer does not follow it, it has to be
|
|
494
|
+
* restored. A refusal and a consumer who owns `value` and has not given a new
|
|
495
|
+
* one are the same thing from here.
|
|
496
|
+
*/
|
|
497
|
+
restore() {
|
|
498
|
+
const control = this.control;
|
|
499
|
+
if (control && control.value !== this.display) {
|
|
500
|
+
control.value = this.display;
|
|
501
|
+
}
|
|
502
|
+
this.sync();
|
|
503
|
+
}
|
|
504
|
+
/** Reports the value and the validity the host stands behind. */
|
|
505
|
+
sync() {
|
|
506
|
+
this.internals.setFormValue(this.value);
|
|
507
|
+
const control = this.control;
|
|
508
|
+
if (!control) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
/* Bounds are checked here rather than left to the input, which is `text`
|
|
512
|
+
and has no idea what a date is: `min` and `max` on a text input do
|
|
513
|
+
nothing, and `type="date"` is what was given up to own the calendar.
|
|
514
|
+
String comparison is enough because ISO dates sort lexically, which is
|
|
515
|
+
the whole reason the value is that shape. */
|
|
516
|
+
/* Every date in the value, not the value itself: a range is two of them and
|
|
517
|
+
a multiple is any number, so a string comparison against `min` would be
|
|
518
|
+
comparing a bound to a list. */
|
|
519
|
+
const held = dates(this.value);
|
|
520
|
+
let message = '';
|
|
521
|
+
if (held.length > 0 && !held.every(isIso)) {
|
|
522
|
+
message =
|
|
523
|
+
this.mode === undefined
|
|
524
|
+
? 'Enter a date as YYYY-MM-DD.'
|
|
525
|
+
: 'Enter dates as YYYY-MM-DD, separated by commas.';
|
|
526
|
+
}
|
|
527
|
+
else if (this.min !== '' && held.some((one) => one < this.min)) {
|
|
528
|
+
message = `Choose a date on or after ${this.min}.`;
|
|
529
|
+
}
|
|
530
|
+
else if (this.max !== '' && held.some((one) => one > this.max)) {
|
|
531
|
+
message = `Choose a date on or before ${this.max}.`;
|
|
532
|
+
}
|
|
533
|
+
else if (this.mode === 'range' && held.length > 2) {
|
|
534
|
+
message = 'A range is two dates.';
|
|
535
|
+
}
|
|
536
|
+
if (message === '') {
|
|
537
|
+
this.internals.setValidity(control.validity, control.validationMessage, control);
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
this.internals.setValidity({ badInput: true }, message, control);
|
|
541
|
+
}
|
|
542
|
+
this.refreshFeedback();
|
|
543
|
+
}
|
|
544
|
+
/** Refuses every change while read-only. See `readOnly`. */
|
|
545
|
+
requestValue(next) {
|
|
546
|
+
if (this.readOnly) {
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
return super.requestValue(next);
|
|
550
|
+
}
|
|
551
|
+
firstUpdated(changed) {
|
|
552
|
+
super.firstUpdated(changed);
|
|
553
|
+
// Whatever the markup arrived with, so a form knows before anything is typed.
|
|
554
|
+
this.sync();
|
|
555
|
+
}
|
|
556
|
+
updated(changed) {
|
|
557
|
+
super.updated(changed);
|
|
558
|
+
// Every update, not only the ones that name `value`: see the note on
|
|
559
|
+
// `ColorInput.updated`, and the fifteen controls that already did this.
|
|
560
|
+
this.sync();
|
|
561
|
+
/* Driven from here rather than from the toggle, because `open` is a property
|
|
562
|
+
a consumer may set directly and the panel has to follow either way. The
|
|
563
|
+
controller is idempotent, so arriving twice for the same open costs
|
|
564
|
+
nothing. Select drives it the same way, and without this the surface stays
|
|
565
|
+
`display: none`: a `popover` element is hidden until something shows it,
|
|
566
|
+
so the calendar rendered its forty-two cells into a box of nothing. */
|
|
567
|
+
if (this.open) {
|
|
568
|
+
this.panel.show();
|
|
569
|
+
// Only on the update that opened it, or every keystroke while it is up
|
|
570
|
+
// would steal focus back into the grid.
|
|
571
|
+
if (changed.has('open')) {
|
|
572
|
+
this.renderRoot?.querySelector('[part="picker"]')?.focus();
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
this.panel.hide();
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
returnFocus() {
|
|
580
|
+
this.returning = true;
|
|
581
|
+
this.control?.focus();
|
|
582
|
+
this.returning = false;
|
|
583
|
+
}
|
|
584
|
+
/** Puts the caret in the field, the way a label pointing at one would. */
|
|
585
|
+
focus(options) {
|
|
586
|
+
this.control?.focus(options);
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* The calendar the field opens, behind a seam the styled tier can move.
|
|
590
|
+
*
|
|
591
|
+
* A method rather than a fragment inline, so a tier above can render its own,
|
|
592
|
+
* wrap this one, pass it a property the base does not know about, or leave it
|
|
593
|
+
* out, without reimplementing the whole template to do any of them. The tag is
|
|
594
|
+
* interpolated rather than written, so `tier` resolves it: this renders the
|
|
595
|
+
* headless element, and a styled subclass that sets `tier` renders the styled one
|
|
596
|
+
* from the same template.
|
|
597
|
+
*/
|
|
598
|
+
renderPicker() {
|
|
599
|
+
return html `<${this.tag('date-picker')}
|
|
600
|
+
part="picker"
|
|
601
|
+
exportparts="cell: picker-cell, day: picker-day, grid: picker-grid, header: picker-header,
|
|
602
|
+
heading: picker-heading, month: picker-month, months: picker-months, next: picker-next,
|
|
603
|
+
next-mark: picker-next-mark, previous: picker-previous, previous-mark: picker-previous-mark,
|
|
604
|
+
week: picker-week, weekday: picker-weekday"
|
|
605
|
+
?invalid=${this.resolvedFeedback !== ''}
|
|
606
|
+
mode=${this.mode ?? nothing}
|
|
607
|
+
months=${this.months}
|
|
608
|
+
.value=${this.picked}
|
|
609
|
+
disable-dates=${this.disableDates || nothing}
|
|
610
|
+
disable-days=${this.disableDays || nothing}
|
|
611
|
+
first-day-of-week=${this.firstDayOfWeek}
|
|
612
|
+
locale=${this.locale || nothing}
|
|
613
|
+
max=${this.max || nothing}
|
|
614
|
+
min=${this.min || nothing}
|
|
615
|
+
step=${this.step}
|
|
616
|
+
@helix-before-change=${this.handleCalendarChange}
|
|
617
|
+
@change=${this.stopInner}
|
|
618
|
+
@input=${this.stopInner}
|
|
619
|
+
></${this.tag('date-picker')}>`;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* One chosen date, as a tag, behind a seam the styled tier can move.
|
|
623
|
+
*
|
|
624
|
+
* A method rather than a fragment inline, so a tier above can render its own,
|
|
625
|
+
* wrap this one, pass it a property the base does not know about, or leave it
|
|
626
|
+
* out, without reimplementing the whole template to do any of them. The tag is
|
|
627
|
+
* interpolated rather than written, so `tier` resolves it: this renders the
|
|
628
|
+
* headless element, and a styled subclass that sets `tier` renders the styled one
|
|
629
|
+
* from the same template.
|
|
630
|
+
*/
|
|
631
|
+
renderTag(date) {
|
|
632
|
+
return html `<${this.tag('tag')}
|
|
633
|
+
part="date"
|
|
634
|
+
exportparts="dismiss: date-dismiss, dismiss-mark: date-dismiss-mark, prefix: date-prefix"
|
|
635
|
+
dismissible
|
|
636
|
+
dismiss-label=${`Remove ${date}`}
|
|
637
|
+
?disabled=${this.isDisabled}
|
|
638
|
+
@helix-dismiss=${(event) => {
|
|
639
|
+
event.stopPropagation();
|
|
640
|
+
this.removeDate(date);
|
|
641
|
+
}}
|
|
642
|
+
>${this.written(date)}</${this.tag('tag')}
|
|
643
|
+
>`;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* The mark on the button that opens the calendar, behind a seam.
|
|
647
|
+
*
|
|
648
|
+
* Slot fallback, so a consumer replaces it by slotting; and a method, so the
|
|
649
|
+
* tier above replaces it by overriding.
|
|
650
|
+
*
|
|
651
|
+
* **A named import rather than `<helix-icon>`, and that is a reversal.** The
|
|
652
|
+
* element looked like the tidier of the two and loses on three counts.
|
|
653
|
+
* `helix-icon` indexes the whole icon map at runtime, `icons[this.name]`, and
|
|
654
|
+
* no bundler can shake a runtime lookup, so every consumer of any component
|
|
655
|
+
* that renders one ships all 50kB of path data; a named import ships one
|
|
656
|
+
* path. The import is checked when the package compiles, where a `name`
|
|
657
|
+
* string is checked only when `check:icons` runs. And `helix-icon` is not
|
|
658
|
+
* registered on the headless tier at all, which registers `helix-headless-icon`,
|
|
659
|
+
* so a headless consumer got an inert unknown element and no mark whatsoever.
|
|
660
|
+
*/
|
|
661
|
+
renderTrigger() {
|
|
662
|
+
return html `<slot name="trigger"><svg aria-hidden="true" fill="currentColor" part="trigger-icon" viewBox=${calendarBlank.viewBox}>
|
|
663
|
+
${unsafeSVG(calendarBlank.content)}
|
|
664
|
+
</svg></slot>`;
|
|
665
|
+
}
|
|
666
|
+
render() {
|
|
667
|
+
return html `${this.renderLabel()}
|
|
668
|
+
<div part="field" @keydown=${this.handleKeydown}>
|
|
669
|
+
${this.mode === 'multiple' ? this.shownDates.map((date) => this.renderTag(date)) : nothing}
|
|
670
|
+
${this.restCount > 0 ? html `<span part="rest">${`+${this.restCount}`}</span>` : nothing}
|
|
671
|
+
<input
|
|
672
|
+
part="control"
|
|
673
|
+
id="control"
|
|
674
|
+
type="text"
|
|
675
|
+
.value=${this.display}
|
|
676
|
+
name=${this.name || nothing}
|
|
677
|
+
placeholder=${this.mode === 'multiple' && dates(this.value).length > 0
|
|
678
|
+
? nothing
|
|
679
|
+
: this.placeholder || nothing}
|
|
680
|
+
autocomplete=${this.autocomplete || nothing}
|
|
681
|
+
inputmode="numeric"
|
|
682
|
+
aria-describedby=${this.describedBy ?? nothing}
|
|
683
|
+
?disabled=${this.isDisabled}
|
|
684
|
+
?readonly=${this.readOnly}
|
|
685
|
+
?required=${this.required}
|
|
686
|
+
@blur=${this.handleBlur}
|
|
687
|
+
@focus=${this.handleFocus}
|
|
688
|
+
@input=${this.handleInput}
|
|
689
|
+
@keydown=${this.handleDraftKey}
|
|
690
|
+
/>
|
|
691
|
+
<button
|
|
692
|
+
part="trigger"
|
|
693
|
+
type="button"
|
|
694
|
+
aria-controls="surface"
|
|
695
|
+
aria-expanded=${this.open ? 'true' : 'false'}
|
|
696
|
+
aria-haspopup="dialog"
|
|
697
|
+
aria-label=${this.triggerLabel}
|
|
698
|
+
?disabled=${this.isDisabled}
|
|
699
|
+
@click=${() => this.toggleOpen()}
|
|
700
|
+
>
|
|
701
|
+
${this.renderTrigger()}
|
|
702
|
+
</button>
|
|
703
|
+
</div>
|
|
704
|
+
|
|
705
|
+
<div part="surface" id="surface" popover="manual" ?hidden=${!this.open}>
|
|
706
|
+
${this.renderPicker()}
|
|
707
|
+
</div>
|
|
708
|
+
${this.renderHint()}${this.renderFeedback()}`;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* The value as a `Date`, at midnight UTC, or `null` while there is no date.
|
|
712
|
+
*
|
|
713
|
+
* The platform's own pair on `<input type="date">`, and this control holds the
|
|
714
|
+
* same `YYYY-MM-DD` string, so a consumer moving from one to the other reads
|
|
715
|
+
* the same two properties. UTC because the platform chose UTC: a date that is
|
|
716
|
+
* the same date everywhere must not become a different one by crossing a
|
|
717
|
+
* timezone, and midnight local would do exactly that for anybody west of
|
|
718
|
+
* Greenwich.
|
|
719
|
+
*
|
|
720
|
+
* `null` while the value is half typed, which is most of the keystrokes a
|
|
721
|
+
* reader makes in one of these.
|
|
722
|
+
*/
|
|
723
|
+
get valueAsDate() {
|
|
724
|
+
return asDate(this.value);
|
|
725
|
+
}
|
|
726
|
+
set valueAsDate(date) {
|
|
727
|
+
this.value = fromDate(date);
|
|
728
|
+
}
|
|
729
|
+
/** The value as milliseconds since the epoch, or `NaN` while there is no date. */
|
|
730
|
+
get valueAsNumber() {
|
|
731
|
+
return asDate(this.value)?.getTime() ?? Number.NaN;
|
|
732
|
+
}
|
|
733
|
+
set valueAsNumber(ms) {
|
|
734
|
+
this.value = Number.isNaN(ms) ? '' : fromDate(new Date(ms));
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
__decorate([
|
|
738
|
+
property()
|
|
739
|
+
], HelixHeadlessDateInput.prototype, "autocomplete", void 0);
|
|
740
|
+
__decorate([
|
|
741
|
+
property({ reflect: true })
|
|
742
|
+
], HelixHeadlessDateInput.prototype, "mode", void 0);
|
|
743
|
+
__decorate([
|
|
744
|
+
property({ type: Number })
|
|
745
|
+
], HelixHeadlessDateInput.prototype, "months", void 0);
|
|
746
|
+
__decorate([
|
|
747
|
+
property({ attribute: 'max-tags', type: Number })
|
|
748
|
+
], HelixHeadlessDateInput.prototype, "maxTags", void 0);
|
|
749
|
+
__decorate([
|
|
750
|
+
property()
|
|
751
|
+
], HelixHeadlessDateInput.prototype, "min", void 0);
|
|
752
|
+
__decorate([
|
|
753
|
+
property({ type: Number })
|
|
754
|
+
], HelixHeadlessDateInput.prototype, "step", void 0);
|
|
755
|
+
__decorate([
|
|
756
|
+
property()
|
|
757
|
+
], HelixHeadlessDateInput.prototype, "max", void 0);
|
|
758
|
+
__decorate([
|
|
759
|
+
property({ attribute: 'disable-dates' })
|
|
760
|
+
], HelixHeadlessDateInput.prototype, "disableDates", void 0);
|
|
761
|
+
__decorate([
|
|
762
|
+
property({ attribute: 'disable-days' })
|
|
763
|
+
], HelixHeadlessDateInput.prototype, "disableDays", void 0);
|
|
764
|
+
__decorate([
|
|
765
|
+
property({ attribute: 'first-day-of-week', type: Number })
|
|
766
|
+
], HelixHeadlessDateInput.prototype, "firstDayOfWeek", void 0);
|
|
767
|
+
__decorate([
|
|
768
|
+
property({ attribute: 'date-style' })
|
|
769
|
+
], HelixHeadlessDateInput.prototype, "dateStyle", void 0);
|
|
770
|
+
__decorate([
|
|
771
|
+
property()
|
|
772
|
+
], HelixHeadlessDateInput.prototype, "locale", void 0);
|
|
773
|
+
__decorate([
|
|
774
|
+
property()
|
|
775
|
+
], HelixHeadlessDateInput.prototype, "placeholder", void 0);
|
|
776
|
+
__decorate([
|
|
777
|
+
property({ attribute: 'trigger-label' })
|
|
778
|
+
], HelixHeadlessDateInput.prototype, "triggerLabel", void 0);
|
|
779
|
+
__decorate([
|
|
780
|
+
state()
|
|
781
|
+
], HelixHeadlessDateInput.prototype, "editing", void 0);
|
|
782
|
+
__decorate([
|
|
783
|
+
state()
|
|
784
|
+
], HelixHeadlessDateInput.prototype, "draft", void 0);
|
|
785
|
+
__decorate([
|
|
786
|
+
property({ attribute: 'readonly', reflect: true, type: Boolean })
|
|
787
|
+
], HelixHeadlessDateInput.prototype, "readOnly", void 0);
|
|
788
|
+
HelixHeadlessDateInput = __decorate([
|
|
789
|
+
customElement('helix-headless-date-input')
|
|
790
|
+
], HelixHeadlessDateInput);
|
|
791
|
+
export { HelixHeadlessDateInput };
|