@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,592 @@
|
|
|
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, valueAsNumber as asNumber, customElement, numberAsValue as fromNumber, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { minus, plus } from '@fusion.dev/helix-icons';
|
|
9
|
+
import { html, nothing } from 'lit';
|
|
10
|
+
import { property } from 'lit/decorators.js';
|
|
11
|
+
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
|
+
/**
|
|
13
|
+
* How far a pointer travels for one step of the value, in pixels.
|
|
14
|
+
*
|
|
15
|
+
* Four, measured against the alternatives rather than picked: at one the value
|
|
16
|
+
* runs away from the pointer and a field with `step="1"` crosses a hundred in
|
|
17
|
+
* the width of a word, and at ten a reader has to cross the viewport to reach
|
|
18
|
+
* a useful number. Four is roughly a character's width at the sizes this is set
|
|
19
|
+
* in, so a step reads as "about one glyph of travel".
|
|
20
|
+
*/
|
|
21
|
+
const SCRUB_PITCH = 4;
|
|
22
|
+
/**
|
|
23
|
+
* And the same step over four times the travel, which is what fine means here.
|
|
24
|
+
*
|
|
25
|
+
* Fine lengthens the distance rather than shrinking the increment. A drag that
|
|
26
|
+
* produced values between the steps would be the one input in the library that
|
|
27
|
+
* can reach a number its own arrow keys cannot, and `step` would stop being the
|
|
28
|
+
* grid the control is on.
|
|
29
|
+
*/
|
|
30
|
+
const SCRUB_FINE = 16;
|
|
31
|
+
/**
|
|
32
|
+
* @summary A number a reader types or steps to.
|
|
33
|
+
*
|
|
34
|
+
* @description
|
|
35
|
+
* **A family rather than `Input`'s `type="number"`, and rather than a part of
|
|
36
|
+
* it.** `Input` already takes that type and will keep it: a bare numeric field
|
|
37
|
+
* in a form is a text field with a different keyboard, and that is all it needs
|
|
38
|
+
* to be. This is a different control. It renders two buttons, binds four keys
|
|
39
|
+
* that `Input` does not, and owns clamping and stepping, so it is an alternative
|
|
40
|
+
* and not a variant. Namespacing it under `Input` would say it is contained by
|
|
41
|
+
* one, which is what `IconButton` is top-level for.
|
|
42
|
+
*
|
|
43
|
+
* **The field is `type="text"` with `inputmode="decimal"`, and that is a
|
|
44
|
+
* measurement rather than a preference.** Asked of a real browser, `type=number`
|
|
45
|
+
* fails three ways this control cannot live with:
|
|
46
|
+
*
|
|
47
|
+
* ```
|
|
48
|
+
* typed "12e" into type=number → .value === ""
|
|
49
|
+
* focused, wheeled over it → 5 became 4
|
|
50
|
+
* selectionStart on type=number → null
|
|
51
|
+
* same keystrokes into type=text → .value === "12e"
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* The first is fatal on its own: the element cannot see what the reader typed,
|
|
55
|
+
* so a controlled value is destroyed by a keystroke and there is nothing left to
|
|
56
|
+
* correct or to report. The second changes a value because a page scrolled past.
|
|
57
|
+
* The third means the caret cannot be managed at all, which any correcting or
|
|
58
|
+
* formatting field needs. `inputmode` is what keeps the phone keypad, which is
|
|
59
|
+
* the one thing `type=number` was giving.
|
|
60
|
+
*
|
|
61
|
+
* Validity is still the platform's, through `min`, `max` and `step` mirrored
|
|
62
|
+
* onto the host's own `setValidity`. What is not mirrored is the field's
|
|
63
|
+
* `type`, because a text field has no opinion about numbers.
|
|
64
|
+
*
|
|
65
|
+
* **Stepping is separate from typing.** A reader mid-way through "1" of "12"
|
|
66
|
+
* has not asked for anything to be clamped, so the value is only pulled into
|
|
67
|
+
* range when they step, blur, or the form asks. Clamping on every keystroke is
|
|
68
|
+
* what makes a field that cannot be typed backwards into.
|
|
69
|
+
*
|
|
70
|
+
* @since 0.1.0
|
|
71
|
+
* @status experimental
|
|
72
|
+
* @category forms
|
|
73
|
+
* @aliases NumberField, Stepper, InputNumber
|
|
74
|
+
* @documentation https://helix.fusion.dev/components/number-input
|
|
75
|
+
*
|
|
76
|
+
* @slot end - After it.
|
|
77
|
+
* @slot start - Before the number, for a unit or an icon.
|
|
78
|
+
*
|
|
79
|
+
* @event {Event} change - Relayed from the field once the reader has finished.
|
|
80
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - Fired as the value changes, and cancelable.
|
|
81
|
+
* @event {Event} input - Announced once the value has moved.
|
|
82
|
+
*
|
|
83
|
+
* @csspart control - The field itself.
|
|
84
|
+
* @csspart decrement - The control that steps down.
|
|
85
|
+
* @csspart decrement-mark - The glyph on the step down control.
|
|
86
|
+
* @csspart feedback - What is wrong with it.
|
|
87
|
+
* @csspart field - The box holding everything.
|
|
88
|
+
* @csspart hint - Help under the field, while nothing is wrong.
|
|
89
|
+
* @csspart increment - The control that steps up.
|
|
90
|
+
* @csspart increment-mark - The glyph on the step up control.
|
|
91
|
+
* @csspart label - The name over the field, which is also the scrub grip.
|
|
92
|
+
*/
|
|
93
|
+
let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinControllerValue(MixinField(HelixFormElement)) {
|
|
94
|
+
constructor() {
|
|
95
|
+
super(...arguments);
|
|
96
|
+
/* A consumer's `aria-describedby` names ids in their own tree and the control
|
|
97
|
+
is in this shadow root, so the reference has to be carried down as an
|
|
98
|
+
element rather than copied as an id. See `AriaForwardController`: measured
|
|
99
|
+
in Chrome's own tree, the host held the description and the control the
|
|
100
|
+
reader is actually on was exposed without it. */
|
|
101
|
+
this.aria = new AriaForwardController(this, {
|
|
102
|
+
target: () => this.renderRoot?.querySelector('[part="control"]') ?? null,
|
|
103
|
+
});
|
|
104
|
+
/** Typed or dragged, so every edit is announced. See `announcesInput`. */
|
|
105
|
+
this.announcesInput = true;
|
|
106
|
+
/**
|
|
107
|
+
* What the browser may autofill here, as one of the platform's own tokens.
|
|
108
|
+
*
|
|
109
|
+
* Empty leaves the attribute off, which is the browser's default and is what
|
|
110
|
+
* lets autofill work at all. This used to be hardcoded `off`, so a reader
|
|
111
|
+
* could never have a birthday or a postal code filled in for them and a
|
|
112
|
+
* consumer had no way to ask for it. See 295.
|
|
113
|
+
*/
|
|
114
|
+
this.autocomplete = '';
|
|
115
|
+
/**
|
|
116
|
+
* How far one step moves.
|
|
117
|
+
*/
|
|
118
|
+
this.step = 1;
|
|
119
|
+
/**
|
|
120
|
+
* Shown while the field is empty.
|
|
121
|
+
*
|
|
122
|
+
* Not a label: it goes when typing starts.
|
|
123
|
+
*/
|
|
124
|
+
this.placeholder = '';
|
|
125
|
+
/**
|
|
126
|
+
* Whether the field refuses input while still submitting its value.
|
|
127
|
+
*/
|
|
128
|
+
this.readOnly = false;
|
|
129
|
+
/**
|
|
130
|
+
* Whether a grip is shown that changes the value when it is dragged.
|
|
131
|
+
*
|
|
132
|
+
* The label is what is dragged, so this adds no chrome at all. Still opt-in,
|
|
133
|
+
* because it changes what a press on the label does and a reader who drags
|
|
134
|
+
* across a word expecting to select it should get that everywhere it has not
|
|
135
|
+
* been asked for. Where it earns its place is a value a reader tunes rather
|
|
136
|
+
* than states: a duration, a weight, a count they are looking for rather than
|
|
137
|
+
* one they already know.
|
|
138
|
+
*/
|
|
139
|
+
this.scrub = false;
|
|
140
|
+
/**
|
|
141
|
+
* Accessible name for the control that steps down.
|
|
142
|
+
*/
|
|
143
|
+
this.decrementLabel = 'Decrease';
|
|
144
|
+
/**
|
|
145
|
+
* Accessible name for the control that steps up.
|
|
146
|
+
*/
|
|
147
|
+
this.incrementLabel = 'Increase';
|
|
148
|
+
/** Where the pointer went down, and what the value was there. */
|
|
149
|
+
this.scrubFrom = 0;
|
|
150
|
+
this.scrubValue = 0;
|
|
151
|
+
/**
|
|
152
|
+
* Press, and the value follows the pointer.
|
|
153
|
+
*
|
|
154
|
+
* Captured, so a drag that leaves the grip keeps going: a reader tuning a
|
|
155
|
+
* number moves further than a 20 pixel handle and the gesture ending because
|
|
156
|
+
* they overshot it would be the control refusing the very thing it offered.
|
|
157
|
+
* `preventDefault` because a press inside a field otherwise starts a text
|
|
158
|
+
* selection, which drags a blue wash across the label at the same time.
|
|
159
|
+
*/
|
|
160
|
+
this.handleScrubDown = (event) => {
|
|
161
|
+
if (this.isDisabled || this.readOnly) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
;
|
|
165
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
166
|
+
this.scrubFrom = event.clientX;
|
|
167
|
+
this.scrubValue = this.numeric ?? this.min ?? 0;
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Read from where the press began, never from the last frame.
|
|
172
|
+
*
|
|
173
|
+
* Accumulating a delta per move drifts: every rounding to a step throws away
|
|
174
|
+
* the remainder, and a slow drag across a hundred events throws it away a
|
|
175
|
+
* hundred times, so the value and the pointer disagree by more the longer
|
|
176
|
+
* anyone holds. From the origin the arithmetic is the same on every frame and
|
|
177
|
+
* the value can only be where the pointer says it is.
|
|
178
|
+
*/
|
|
179
|
+
this.handleScrubMove = (event) => {
|
|
180
|
+
const grip = event.currentTarget;
|
|
181
|
+
if (!grip.hasPointerCapture(event.pointerId)) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const step = Math.abs(this.step) || 1;
|
|
185
|
+
const unit = event.shiftKey ? (this.largeStep ?? 10) * step : step;
|
|
186
|
+
const pitch = event.altKey ? SCRUB_FINE : SCRUB_PITCH;
|
|
187
|
+
const steps = Math.round((event.clientX - this.scrubFrom) / pitch);
|
|
188
|
+
const next = String(this.clamp(this.scrubValue + steps * unit));
|
|
189
|
+
/* Compared before it is sent. A drag produces a move event per frame and
|
|
190
|
+
most of them land on the step the value is already on, and announcing
|
|
191
|
+
those would be `helix-input` firing sixty times a second saying nothing
|
|
192
|
+
changed. */
|
|
193
|
+
if (next === this.value) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
this.requestValue(next);
|
|
197
|
+
const control = this.control;
|
|
198
|
+
if (control) {
|
|
199
|
+
restoreValue(control, this.value);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
/** Let go, and the capture goes with it. */
|
|
203
|
+
this.handleScrubEnd = (event) => {
|
|
204
|
+
const grip = event.currentTarget;
|
|
205
|
+
if (grip.hasPointerCapture(event.pointerId)) {
|
|
206
|
+
grip.releasePointerCapture(event.pointerId);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* Every keystroke, cancelable, and put back where it is refused.
|
|
211
|
+
*
|
|
212
|
+
* Not clamped here. A reader typing "12" is at "1" for one keystroke, and a
|
|
213
|
+
* field with `min="10"` that corrected them at that moment could never be
|
|
214
|
+
* typed into at all. Range is settled on blur, on a step, and at submit.
|
|
215
|
+
*/
|
|
216
|
+
this.handleInput = (event) => {
|
|
217
|
+
// Stopped for the reason `Input.handleInput` gives: the inner control's own
|
|
218
|
+
// `input` is composed and would reach a consumer beside this element's.
|
|
219
|
+
event.stopPropagation();
|
|
220
|
+
const control = event.target;
|
|
221
|
+
this.requestValue(control.value);
|
|
222
|
+
restoreValue(control, this.value);
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Leaving the field is where a half-typed number becomes a number.
|
|
226
|
+
*
|
|
227
|
+
* Blank is left blank, because an empty optional field is a legitimate answer
|
|
228
|
+
* and filling it with `min` would put a number in a form the reader never
|
|
229
|
+
* gave.
|
|
230
|
+
*
|
|
231
|
+
* **And text that is not a number is left alone, which this cleared at
|
|
232
|
+
* first.** Typing `2.7e` and tabbing away emptied the field: the reader looks
|
|
233
|
+
* back and their entry is gone with nothing saying why, and the likeliest
|
|
234
|
+
* cause is a fat finger on a number they had almost finished. Nothing is lost
|
|
235
|
+
* by keeping it, because `sync` has already marked it `badInput`, so the field
|
|
236
|
+
* shows as wrong and the form refuses to submit. Destroying the evidence of a
|
|
237
|
+
* mistake is not the same as preventing one.
|
|
238
|
+
*/
|
|
239
|
+
this.handleBlur = () => {
|
|
240
|
+
const control = this.control;
|
|
241
|
+
const parsed = this.numeric;
|
|
242
|
+
if (!control || parsed === null) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.requestValue(String(this.clamp(parsed)));
|
|
246
|
+
restoreValue(control, this.value);
|
|
247
|
+
};
|
|
248
|
+
/** Relayed, because `change` does not cross a shadow boundary on its own. */
|
|
249
|
+
this.handleChange = (event) => {
|
|
250
|
+
event.stopPropagation();
|
|
251
|
+
this.dispatchEvent(new Event('change', { bubbles: true, composed: false }));
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* The four keys a spinner answers, which `Input` does not bind.
|
|
255
|
+
*
|
|
256
|
+
* `Home` and `End` only where there is a bound to go to: without one they are
|
|
257
|
+
* the text field's own keys and moving the caret to the start of the number is
|
|
258
|
+
* what a reader pressing them meant.
|
|
259
|
+
*/
|
|
260
|
+
this.handleKeydown = (event) => {
|
|
261
|
+
if (event.key === 'ArrowUp') {
|
|
262
|
+
this.stepUp();
|
|
263
|
+
}
|
|
264
|
+
else if (event.key === 'ArrowDown') {
|
|
265
|
+
this.stepDown();
|
|
266
|
+
}
|
|
267
|
+
else if (event.key === 'PageUp') {
|
|
268
|
+
this.stepUp(true);
|
|
269
|
+
}
|
|
270
|
+
else if (event.key === 'PageDown') {
|
|
271
|
+
this.stepDown(true);
|
|
272
|
+
/* Guarded the way `nudge` is. A read-only field still receives keydown,
|
|
273
|
+
so Home on one with a `min` silently rewrote the value that the arrows
|
|
274
|
+
beside it correctly refused to touch. */
|
|
275
|
+
}
|
|
276
|
+
else if (event.key === 'Home' &&
|
|
277
|
+
this.min !== undefined &&
|
|
278
|
+
!this.isDisabled &&
|
|
279
|
+
!this.readOnly) {
|
|
280
|
+
this.requestValue(String(this.min));
|
|
281
|
+
}
|
|
282
|
+
else if (event.key === 'End' &&
|
|
283
|
+
this.max !== undefined &&
|
|
284
|
+
!this.isDisabled &&
|
|
285
|
+
!this.readOnly) {
|
|
286
|
+
this.requestValue(String(this.max));
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// Or the arrows scroll the page and Home jumps to the top of it.
|
|
292
|
+
event.preventDefault();
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/** Focus is delegated to the field, so the host is never the focus target. */
|
|
296
|
+
static { this.shadowRootOptions = {
|
|
297
|
+
...HelixFormElement.shadowRootOptions,
|
|
298
|
+
delegatesFocus: true,
|
|
299
|
+
}; }
|
|
300
|
+
get control() {
|
|
301
|
+
return this.renderRoot.querySelector('[part="control"]');
|
|
302
|
+
}
|
|
303
|
+
/** The value as a number, or `null` where the field holds nothing usable. */
|
|
304
|
+
get numeric() {
|
|
305
|
+
if (this.value.trim() === '') {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
const parsed = Number(this.value);
|
|
309
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* A value pulled into range and onto the step grid.
|
|
313
|
+
*
|
|
314
|
+
* The grid is anchored at `min` where there is one, so `min="1" step="2"`
|
|
315
|
+
* gives 1, 3, 5 rather than 0, 2, 4. Rounded to the step's own precision,
|
|
316
|
+
* because stepping 0.1 in binary floating point otherwise produces
|
|
317
|
+
* `0.30000000000000004` and puts it in the field.
|
|
318
|
+
*/
|
|
319
|
+
clamp(value) {
|
|
320
|
+
const step = Math.abs(this.step) || 1;
|
|
321
|
+
const anchor = this.min ?? 0;
|
|
322
|
+
const stepped = anchor + Math.round((value - anchor) / step) * step;
|
|
323
|
+
const floored = this.min === undefined ? stepped : Math.max(this.min, stepped);
|
|
324
|
+
const capped = this.max === undefined ? floored : Math.min(this.max, floored);
|
|
325
|
+
/* Decimal places from the step and the anchor together: a step of 0.25 from
|
|
326
|
+
an anchor of 0.1 lands on 0.35, which needs two rather than the two the
|
|
327
|
+
step alone would give by luck. */
|
|
328
|
+
const places = Math.max(decimals(step), decimals(anchor));
|
|
329
|
+
return Number(capped.toFixed(places));
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Moves by whole steps, from where the reader is.
|
|
333
|
+
*
|
|
334
|
+
* From `min` when the field is empty, so the first press of an arrow lands
|
|
335
|
+
* somewhere meaningful rather than on zero: an empty field with `min="1"`
|
|
336
|
+
* stepping to 0 would be out of range before the reader had typed anything.
|
|
337
|
+
*/
|
|
338
|
+
nudge(steps) {
|
|
339
|
+
if (this.isDisabled || this.readOnly) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const step = Math.abs(this.step) || 1;
|
|
343
|
+
const from = this.numeric ?? this.min ?? 0;
|
|
344
|
+
const next = this.clamp(this.numeric === null ? from : from + steps * step);
|
|
345
|
+
this.requestValue(String(next));
|
|
346
|
+
const control = this.control;
|
|
347
|
+
if (control) {
|
|
348
|
+
restoreValue(control, this.value);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/** One step up, or `PageUp`'s larger one. */
|
|
352
|
+
stepUp(large = false) {
|
|
353
|
+
this.nudge(large ? (this.largeStep ?? 10) : 1);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Steps the value down, by `largeStep` when `large` is set.
|
|
357
|
+
*
|
|
358
|
+
* The same path a press of the down arrow takes, so a consumer driving this
|
|
359
|
+
* from their own control gets the clamping and the announcement rather than
|
|
360
|
+
* having to repeat both.
|
|
361
|
+
*/
|
|
362
|
+
stepDown(large = false) {
|
|
363
|
+
this.nudge(large ? -(this.largeStep ?? 10) : -1);
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* The label is the surface, which is where the convention already is.
|
|
367
|
+
*
|
|
368
|
+
* A grip was drawn first, an icon of its own at the leading edge, and it was
|
|
369
|
+
* a second control in a field that already has three. Every tool that does
|
|
370
|
+
* this well drags the *name* of the value: the label is present on every
|
|
371
|
+
* field, costs no chrome, and a reader who wants to know what they are
|
|
372
|
+
* dragging is already looking at it.
|
|
373
|
+
*
|
|
374
|
+
* Overridden rather than handled on the host, because the handlers have to
|
|
375
|
+
* sit on the element that takes the capture. The markup is the mixin's, said
|
|
376
|
+
* again here, which is the duplication #76 exists to remove: when base
|
|
377
|
+
* renders break into methods a styled tier can extend, this becomes a call to
|
|
378
|
+
* `super` with three listeners added.
|
|
379
|
+
*
|
|
380
|
+
* A label with nothing in it is still nothing. `scrub` on a field whose label
|
|
381
|
+
* is empty leaves no surface, which is honest: there is nowhere to put the
|
|
382
|
+
* gesture and inventing somewhere is how the grip happened.
|
|
383
|
+
*/
|
|
384
|
+
renderLabel() {
|
|
385
|
+
if (!this.scrub) {
|
|
386
|
+
return super.renderLabel();
|
|
387
|
+
}
|
|
388
|
+
const hidden = this.label === '' ? this.getAttribute('aria-label') : null;
|
|
389
|
+
if (this.label === '' && !hidden) {
|
|
390
|
+
return nothing;
|
|
391
|
+
}
|
|
392
|
+
return html `<label
|
|
393
|
+
part="label"
|
|
394
|
+
for="control"
|
|
395
|
+
?data-hidden=${hidden !== null}
|
|
396
|
+
@pointercancel=${this.handleScrubEnd}
|
|
397
|
+
@pointerdown=${this.handleScrubDown}
|
|
398
|
+
@pointermove=${this.handleScrubMove}
|
|
399
|
+
@pointerup=${this.handleScrubEnd}
|
|
400
|
+
><slot name="label">${this.label || hidden}</slot></label
|
|
401
|
+
>`;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Reports the value and a verdict on it.
|
|
405
|
+
*
|
|
406
|
+
* Computed here rather than copied off the field, which is the one place this
|
|
407
|
+
* differs from `Input`: the field is text, so the browser has no opinion about
|
|
408
|
+
* whether it is a number in range. The flags are the platform's own names, so
|
|
409
|
+
* a consumer reading `validity.rangeOverflow` finds what they expect and the
|
|
410
|
+
* message is what a native spinner would have said.
|
|
411
|
+
*/
|
|
412
|
+
sync() {
|
|
413
|
+
const control = this.control;
|
|
414
|
+
this.internals.setFormValue(this.value);
|
|
415
|
+
if (!control) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const parsed = this.numeric;
|
|
419
|
+
if (this.required && this.value.trim() === '') {
|
|
420
|
+
this.internals.setValidity({ valueMissing: true }, 'Please fill in this field.', control);
|
|
421
|
+
}
|
|
422
|
+
else if (this.value.trim() !== '' && parsed === null) {
|
|
423
|
+
this.internals.setValidity({ badInput: true }, 'Please enter a number.', control);
|
|
424
|
+
}
|
|
425
|
+
else if (parsed !== null && this.min !== undefined && parsed < this.min) {
|
|
426
|
+
this.internals.setValidity({ rangeUnderflow: true }, `Value must be ${this.min} or more.`, control);
|
|
427
|
+
}
|
|
428
|
+
else if (parsed !== null && this.max !== undefined && parsed > this.max) {
|
|
429
|
+
this.internals.setValidity({ rangeOverflow: true }, `Value must be ${this.max} or less.`, control);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
this.internals.setValidity({}, '', control);
|
|
433
|
+
}
|
|
434
|
+
// Straight after, because validity moved without any property moving.
|
|
435
|
+
this.refreshFeedback();
|
|
436
|
+
}
|
|
437
|
+
/** Puts the caret in the field, the way a label pointing at one would. */
|
|
438
|
+
focus(options) {
|
|
439
|
+
this.control?.focus(options);
|
|
440
|
+
}
|
|
441
|
+
/** Selects the number, so typing replaces it. */
|
|
442
|
+
select() {
|
|
443
|
+
this.control?.select();
|
|
444
|
+
}
|
|
445
|
+
willUpdate(changed) {
|
|
446
|
+
super.willUpdate(changed);
|
|
447
|
+
/* Never before the first update, which is the one the server does: there is
|
|
448
|
+
no render root to query there, and `querySelector` is not merely empty on
|
|
449
|
+
Lit's element shim, it is undefined. There is also no caret to keep before
|
|
450
|
+
anything has rendered. */
|
|
451
|
+
if (!this.hasUpdated) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const control = this.control;
|
|
455
|
+
if (changed.has('value') && control && this.shadowRoot?.activeElement === control) {
|
|
456
|
+
this.releaseCaret = holdCaret(control);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
updated(changed) {
|
|
460
|
+
super.updated(changed);
|
|
461
|
+
this.releaseCaret?.();
|
|
462
|
+
this.releaseCaret = undefined;
|
|
463
|
+
this.sync();
|
|
464
|
+
}
|
|
465
|
+
render() {
|
|
466
|
+
const parsed = this.numeric;
|
|
467
|
+
const atMin = parsed !== null && this.min !== undefined && parsed <= this.min;
|
|
468
|
+
const atMax = parsed !== null && this.max !== undefined && parsed >= this.max;
|
|
469
|
+
return html `${this.renderLabel()}
|
|
470
|
+
<div part="field">
|
|
471
|
+
<button
|
|
472
|
+
part="decrement"
|
|
473
|
+
type="button"
|
|
474
|
+
aria-label=${this.decrementLabel}
|
|
475
|
+
tabindex="-1"
|
|
476
|
+
?disabled=${this.isDisabled || this.readOnly || atMin}
|
|
477
|
+
@click=${() => this.stepDown()}
|
|
478
|
+
>
|
|
479
|
+
<svg part="decrement-mark" fill="currentColor" viewBox=${minus.viewBox} aria-hidden="true">
|
|
480
|
+
${unsafeSVG(minus.content)}
|
|
481
|
+
</svg>
|
|
482
|
+
</button>
|
|
483
|
+
<slot name="start"></slot>
|
|
484
|
+
${
|
|
485
|
+
/* `role="spinbutton"` with the range on it, which is what tells a
|
|
486
|
+
screen reader this is a number in a range rather than a line of
|
|
487
|
+
text. The three `aria-value*` attributes are what the native
|
|
488
|
+
`type=number` would have carried, and they have to be written here
|
|
489
|
+
because the field is text. */
|
|
490
|
+
''}
|
|
491
|
+
<input
|
|
492
|
+
part="control"
|
|
493
|
+
id="control"
|
|
494
|
+
.value=${this.value}
|
|
495
|
+
type="text"
|
|
496
|
+
role="spinbutton"
|
|
497
|
+
inputmode="decimal"
|
|
498
|
+
autocomplete=${this.autocomplete || nothing}
|
|
499
|
+
name=${this.name || nothing}
|
|
500
|
+
placeholder=${this.placeholder || nothing}
|
|
501
|
+
aria-describedby=${this.describedBy ?? nothing}
|
|
502
|
+
aria-valuemin=${this.min ?? nothing}
|
|
503
|
+
aria-valuemax=${this.max ?? nothing}
|
|
504
|
+
aria-valuenow=${parsed ?? nothing}
|
|
505
|
+
?disabled=${this.isDisabled}
|
|
506
|
+
?readonly=${this.readOnly}
|
|
507
|
+
?required=${this.required}
|
|
508
|
+
@blur=${this.handleBlur}
|
|
509
|
+
@change=${this.handleChange}
|
|
510
|
+
@input=${this.handleInput}
|
|
511
|
+
@keydown=${this.handleKeydown}
|
|
512
|
+
/>
|
|
513
|
+
<slot name="end"></slot>
|
|
514
|
+
<button
|
|
515
|
+
part="increment"
|
|
516
|
+
type="button"
|
|
517
|
+
aria-label=${this.incrementLabel}
|
|
518
|
+
tabindex="-1"
|
|
519
|
+
?disabled=${this.isDisabled || this.readOnly || atMax}
|
|
520
|
+
@click=${() => this.stepUp()}
|
|
521
|
+
>
|
|
522
|
+
<svg part="increment-mark" fill="currentColor" viewBox=${plus.viewBox} aria-hidden="true">
|
|
523
|
+
${unsafeSVG(plus.content)}
|
|
524
|
+
</svg>
|
|
525
|
+
</button>
|
|
526
|
+
</div>
|
|
527
|
+
${this.renderHint()}${this.renderFeedback()}`;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* The value as a number, or `NaN` while the control is empty.
|
|
531
|
+
*
|
|
532
|
+
* `NaN` and not zero, which is the trap the platform already avoids: `Number('')`
|
|
533
|
+
* is zero, so an empty control would report a number it does not hold and a
|
|
534
|
+
* form would submit it.
|
|
535
|
+
*/
|
|
536
|
+
get valueAsNumber() {
|
|
537
|
+
return asNumber(this.value);
|
|
538
|
+
}
|
|
539
|
+
set valueAsNumber(count) {
|
|
540
|
+
this.value = fromNumber(count);
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
__decorate([
|
|
544
|
+
property()
|
|
545
|
+
], HelixHeadlessNumberInput.prototype, "autocomplete", void 0);
|
|
546
|
+
__decorate([
|
|
547
|
+
property({ type: Number })
|
|
548
|
+
], HelixHeadlessNumberInput.prototype, "min", void 0);
|
|
549
|
+
__decorate([
|
|
550
|
+
property({ type: Number })
|
|
551
|
+
], HelixHeadlessNumberInput.prototype, "max", void 0);
|
|
552
|
+
__decorate([
|
|
553
|
+
property({ type: Number })
|
|
554
|
+
], HelixHeadlessNumberInput.prototype, "step", void 0);
|
|
555
|
+
__decorate([
|
|
556
|
+
property({ attribute: 'large-step', type: Number })
|
|
557
|
+
], HelixHeadlessNumberInput.prototype, "largeStep", void 0);
|
|
558
|
+
__decorate([
|
|
559
|
+
property()
|
|
560
|
+
], HelixHeadlessNumberInput.prototype, "placeholder", void 0);
|
|
561
|
+
__decorate([
|
|
562
|
+
property({ attribute: 'readonly', reflect: true, type: Boolean })
|
|
563
|
+
], HelixHeadlessNumberInput.prototype, "readOnly", void 0);
|
|
564
|
+
__decorate([
|
|
565
|
+
property({ reflect: true, type: Boolean })
|
|
566
|
+
], HelixHeadlessNumberInput.prototype, "scrub", void 0);
|
|
567
|
+
__decorate([
|
|
568
|
+
property({ attribute: 'decrement-label' })
|
|
569
|
+
], HelixHeadlessNumberInput.prototype, "decrementLabel", void 0);
|
|
570
|
+
__decorate([
|
|
571
|
+
property({ attribute: 'increment-label' })
|
|
572
|
+
], HelixHeadlessNumberInput.prototype, "incrementLabel", void 0);
|
|
573
|
+
HelixHeadlessNumberInput = __decorate([
|
|
574
|
+
customElement('helix-headless-number-input')
|
|
575
|
+
], HelixHeadlessNumberInput);
|
|
576
|
+
export { HelixHeadlessNumberInput };
|
|
577
|
+
/**
|
|
578
|
+
* How many decimal places a number is written with.
|
|
579
|
+
*
|
|
580
|
+
* Read off the string rather than computed, because the question is about how
|
|
581
|
+
* the consumer wrote the step and not about what the binary can represent.
|
|
582
|
+
* `1e-7` is handled separately: its string form has no dot at all, so counting
|
|
583
|
+
* after one would say zero and round every result to a whole number.
|
|
584
|
+
*/
|
|
585
|
+
const decimals = (value) => {
|
|
586
|
+
const text = String(value);
|
|
587
|
+
const exponent = /e-(\d+)$/.exec(text);
|
|
588
|
+
if (exponent) {
|
|
589
|
+
return Number(exponent[1]);
|
|
590
|
+
}
|
|
591
|
+
return (text.split('.')[1] ?? '').length;
|
|
592
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
+
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
/**
|
|
4
|
+
* @summary A named run of options inside a listbox.
|
|
5
|
+
*
|
|
6
|
+
* @description
|
|
7
|
+
* A heading over a set, and nothing else: it holds no selection and no value,
|
|
8
|
+
* because grouping is presentation over a list whose owner is the listbox. Its
|
|
9
|
+
* options are still the listbox's options, which is what keeps the keyboard
|
|
10
|
+
* moving through a grouped list exactly as it moves through a flat one.
|
|
11
|
+
*
|
|
12
|
+
* `role="group"` named by the heading, so a screen reader announces which run
|
|
13
|
+
* an option is in without the heading becoming something to land on.
|
|
14
|
+
*
|
|
15
|
+
* @since 0.1.0
|
|
16
|
+
* @status experimental
|
|
17
|
+
* @aliases OptGroup, Section
|
|
18
|
+
* @documentation https://helix.fusion.dev/components/option-group
|
|
19
|
+
*
|
|
20
|
+
* @slot - The options in this run.
|
|
21
|
+
* @slot label - Richer than a string.
|
|
22
|
+
*
|
|
23
|
+
* @csspart items - The run itself.
|
|
24
|
+
* @csspart label - The heading.
|
|
25
|
+
*/
|
|
26
|
+
export declare class HelixHeadlessOptionGroup extends HelixElement {
|
|
27
|
+
/**
|
|
28
|
+
* The heading over the run.
|
|
29
|
+
*/
|
|
30
|
+
label: string;
|
|
31
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
32
|
+
protected render(): TemplateResult;
|
|
33
|
+
}
|
|
34
|
+
declare global {
|
|
35
|
+
interface HTMLElementTagNameMap {
|
|
36
|
+
'helix-headless-option-group': HelixHeadlessOptionGroup;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
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 { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html } from 'lit';
|
|
9
|
+
import { property } from 'lit/decorators.js';
|
|
10
|
+
/**
|
|
11
|
+
* @summary A named run of options inside a listbox.
|
|
12
|
+
*
|
|
13
|
+
* @description
|
|
14
|
+
* A heading over a set, and nothing else: it holds no selection and no value,
|
|
15
|
+
* because grouping is presentation over a list whose owner is the listbox. Its
|
|
16
|
+
* options are still the listbox's options, which is what keeps the keyboard
|
|
17
|
+
* moving through a grouped list exactly as it moves through a flat one.
|
|
18
|
+
*
|
|
19
|
+
* `role="group"` named by the heading, so a screen reader announces which run
|
|
20
|
+
* an option is in without the heading becoming something to land on.
|
|
21
|
+
*
|
|
22
|
+
* @since 0.1.0
|
|
23
|
+
* @status experimental
|
|
24
|
+
* @aliases OptGroup, Section
|
|
25
|
+
* @documentation https://helix.fusion.dev/components/option-group
|
|
26
|
+
*
|
|
27
|
+
* @slot - The options in this run.
|
|
28
|
+
* @slot label - Richer than a string.
|
|
29
|
+
*
|
|
30
|
+
* @csspart items - The run itself.
|
|
31
|
+
* @csspart label - The heading.
|
|
32
|
+
*/
|
|
33
|
+
let HelixHeadlessOptionGroup = class HelixHeadlessOptionGroup extends HelixElement {
|
|
34
|
+
constructor() {
|
|
35
|
+
super(...arguments);
|
|
36
|
+
/**
|
|
37
|
+
* The heading over the run.
|
|
38
|
+
*/
|
|
39
|
+
this.label = '';
|
|
40
|
+
}
|
|
41
|
+
willUpdate(changed) {
|
|
42
|
+
super.willUpdate(changed);
|
|
43
|
+
hostAria(this.internals, { label: this.label, role: 'group' });
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
return html `<span part="label" aria-hidden="true">
|
|
47
|
+
<slot name="label">${this.label}</slot>
|
|
48
|
+
</span>
|
|
49
|
+
<div part="items"><slot></slot></div>`;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
__decorate([
|
|
53
|
+
property()
|
|
54
|
+
], HelixHeadlessOptionGroup.prototype, "label", void 0);
|
|
55
|
+
HelixHeadlessOptionGroup = __decorate([
|
|
56
|
+
customElement('helix-headless-option-group')
|
|
57
|
+
], HelixHeadlessOptionGroup);
|
|
58
|
+
export { HelixHeadlessOptionGroup };
|