@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,151 @@
|
|
|
1
|
+
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
/**
|
|
4
|
+
* @summary A timestamp, written the way the reader's locale writes one.
|
|
5
|
+
*
|
|
6
|
+
* @description
|
|
7
|
+
* A date in a page is almost never wanted as an ISO string, and formatting one
|
|
8
|
+
* in the consumer's own code means every consumer ships a copy of the same
|
|
9
|
+
* `Intl` call and a different set of options. This is that call, as an element,
|
|
10
|
+
* so a date is written where it is shown.
|
|
11
|
+
*
|
|
12
|
+
* **`elapsed` is the mode a feed wants, and it stops being relative on
|
|
13
|
+
* purpose.** "42m", "3h", "1d" is what a row of activity reads as, and past a
|
|
14
|
+
* week the compact form is a lie: `Intl.NumberFormat` narrow renders both
|
|
15
|
+
* `minute` and `month` as `m` in en-US, so "3m" is three minutes at the top of a
|
|
16
|
+
* feed and three months further down it. Past six days this shows a date, which
|
|
17
|
+
* is shorter to read and impossible to misread. `elapsedTime` in `helix/core`
|
|
18
|
+
* carries the measurement.
|
|
19
|
+
*
|
|
20
|
+
* **The reading refreshes itself, from one timer the page shares.** A relative
|
|
21
|
+
* timestamp is correct for as long as its unit lasts and wrong afterwards, and a
|
|
22
|
+
* page left open is exactly where that shows. Each element asks to be woken when
|
|
23
|
+
* its own reading expires rather than polling, and an element showing a date
|
|
24
|
+
* asks for nothing at all: fifty rows and fifty intervals is fifty wakeups a
|
|
25
|
+
* second where one will do, and a feed of last month's notifications should cost
|
|
26
|
+
* nothing to leave open.
|
|
27
|
+
*
|
|
28
|
+
* **`<time datetime>` whatever the text says**, so a screen reader, a copy and
|
|
29
|
+
* paste, and anything parsing the page all get the real instant rather than
|
|
30
|
+
* "yesterday".
|
|
31
|
+
*
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
* @status experimental
|
|
34
|
+
* @category typography
|
|
35
|
+
* @aliases RelativeTime, Timestamp, TimeAgo
|
|
36
|
+
* @documentation https://helix.fusion.dev/components/format-date
|
|
37
|
+
*
|
|
38
|
+
* @csspart time - The `<time>` element carrying the reading.
|
|
39
|
+
*/
|
|
40
|
+
export declare class HelixHeadlessFormatDate extends HelixElement {
|
|
41
|
+
/**
|
|
42
|
+
* The timestamp, as anything `Date` parses.
|
|
43
|
+
*
|
|
44
|
+
* An ISO string is what an API sends and what `<time datetime>` takes, so it
|
|
45
|
+
* is the shape that needs no translation at either end. Left unset this
|
|
46
|
+
* renders nothing rather than the epoch, which is what parsing an empty string
|
|
47
|
+
* would give.
|
|
48
|
+
*
|
|
49
|
+
* **The element's own text is read as a fallback, and only in a browser.**
|
|
50
|
+
* `<helix-format-date elapsed>2026-08-27T01:00:00Z</helix-format-date>` is the
|
|
51
|
+
* spelling that reads best in markup, and it cannot be the only one: measured
|
|
52
|
+
* against Lit's server shim, `textContent`, `children`, `firstChild` and
|
|
53
|
+
* `querySelector` are all `undefined` there, so a server has no way to see it.
|
|
54
|
+
* An element rendered on a server needs the attribute; one rendered in a
|
|
55
|
+
* browser may use either.
|
|
56
|
+
*/
|
|
57
|
+
date: string;
|
|
58
|
+
/**
|
|
59
|
+
* How the day of the month is written, where a date is shown.
|
|
60
|
+
*/
|
|
61
|
+
day?: 'numeric' | '2-digit';
|
|
62
|
+
/**
|
|
63
|
+
* Show how long ago it was, compactly, instead of the date.
|
|
64
|
+
*
|
|
65
|
+
* Reflected, because it is the one property that decides which of two readings
|
|
66
|
+
* this is and a stylesheet has a reason to know: a compact reading is a fixed
|
|
67
|
+
* few characters and a date is not.
|
|
68
|
+
*/
|
|
69
|
+
elapsed: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* How the hour is written, where a time of day is shown.
|
|
72
|
+
*/
|
|
73
|
+
hour?: 'numeric' | '2-digit';
|
|
74
|
+
/**
|
|
75
|
+
* Locale for the reading.
|
|
76
|
+
*
|
|
77
|
+
* Empty is the runtime's own.
|
|
78
|
+
*/
|
|
79
|
+
locale: string;
|
|
80
|
+
/**
|
|
81
|
+
* How the minute is written, where a time of day is shown.
|
|
82
|
+
*/
|
|
83
|
+
minute?: 'numeric' | '2-digit';
|
|
84
|
+
/**
|
|
85
|
+
* How the month is written, where a date is shown.
|
|
86
|
+
*/
|
|
87
|
+
month?: 'numeric' | '2-digit' | 'long' | 'short' | 'narrow';
|
|
88
|
+
/**
|
|
89
|
+
* How the second is written, where a time of day is shown.
|
|
90
|
+
*/
|
|
91
|
+
second?: 'numeric' | '2-digit';
|
|
92
|
+
/**
|
|
93
|
+
* The time zone to read the timestamp in.
|
|
94
|
+
*
|
|
95
|
+
* Empty is the runtime's own.
|
|
96
|
+
*/
|
|
97
|
+
timeZone?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Whether to name the time zone, and how.
|
|
100
|
+
*/
|
|
101
|
+
timeZoneName?: 'long' | 'short';
|
|
102
|
+
/**
|
|
103
|
+
* How the weekday is written, where one is shown.
|
|
104
|
+
*/
|
|
105
|
+
weekday?: 'long' | 'short' | 'narrow';
|
|
106
|
+
/**
|
|
107
|
+
* How the year is written, where a date is shown.
|
|
108
|
+
*/
|
|
109
|
+
year?: 'numeric' | '2-digit';
|
|
110
|
+
/**
|
|
111
|
+
* The clock this element last drew against.
|
|
112
|
+
*
|
|
113
|
+
* A state field and not a read of `Date.now()` inside `render`, which would
|
|
114
|
+
* make the template a function of something Lit cannot see change: the element
|
|
115
|
+
* would draw the right text once and never notice it had gone stale.
|
|
116
|
+
*/
|
|
117
|
+
private clock;
|
|
118
|
+
/**
|
|
119
|
+
* The date read out of the light DOM, where no attribute carried one.
|
|
120
|
+
*/
|
|
121
|
+
private written;
|
|
122
|
+
private stopTicking;
|
|
123
|
+
private watching;
|
|
124
|
+
/** The timestamp, or nothing where there is not one to read. */
|
|
125
|
+
private get moment();
|
|
126
|
+
/** Every `Intl.DateTimeFormat` option a consumer set, and none they did not. */
|
|
127
|
+
private get options();
|
|
128
|
+
connectedCallback(): void;
|
|
129
|
+
disconnectedCallback(): void;
|
|
130
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
131
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
132
|
+
/** The light DOM's own text, which is the other way to write the value. */
|
|
133
|
+
private read;
|
|
134
|
+
private watch;
|
|
135
|
+
/**
|
|
136
|
+
* Schedules the next reading, and only the next one.
|
|
137
|
+
*
|
|
138
|
+
* The formatter says when its own answer expires, so this asks for exactly
|
|
139
|
+
* that moment rather than polling: an item minutes old wakes once a minute, an
|
|
140
|
+
* item hours old once an hour, and an item showing a date never, which is the
|
|
141
|
+
* difference between a feed that costs nothing to leave open and one that
|
|
142
|
+
* does.
|
|
143
|
+
*/
|
|
144
|
+
private tick;
|
|
145
|
+
protected render(): TemplateResult | typeof nothing;
|
|
146
|
+
}
|
|
147
|
+
declare global {
|
|
148
|
+
interface HTMLElementTagNameMap {
|
|
149
|
+
'helix-headless-format-date': HelixHeadlessFormatDate;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
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, elapsedTime, HelixElement, subscribe } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html, nothing } from 'lit';
|
|
9
|
+
import { property, state } from 'lit/decorators.js';
|
|
10
|
+
/**
|
|
11
|
+
* @summary A timestamp, written the way the reader's locale writes one.
|
|
12
|
+
*
|
|
13
|
+
* @description
|
|
14
|
+
* A date in a page is almost never wanted as an ISO string, and formatting one
|
|
15
|
+
* in the consumer's own code means every consumer ships a copy of the same
|
|
16
|
+
* `Intl` call and a different set of options. This is that call, as an element,
|
|
17
|
+
* so a date is written where it is shown.
|
|
18
|
+
*
|
|
19
|
+
* **`elapsed` is the mode a feed wants, and it stops being relative on
|
|
20
|
+
* purpose.** "42m", "3h", "1d" is what a row of activity reads as, and past a
|
|
21
|
+
* week the compact form is a lie: `Intl.NumberFormat` narrow renders both
|
|
22
|
+
* `minute` and `month` as `m` in en-US, so "3m" is three minutes at the top of a
|
|
23
|
+
* feed and three months further down it. Past six days this shows a date, which
|
|
24
|
+
* is shorter to read and impossible to misread. `elapsedTime` in `helix/core`
|
|
25
|
+
* carries the measurement.
|
|
26
|
+
*
|
|
27
|
+
* **The reading refreshes itself, from one timer the page shares.** A relative
|
|
28
|
+
* timestamp is correct for as long as its unit lasts and wrong afterwards, and a
|
|
29
|
+
* page left open is exactly where that shows. Each element asks to be woken when
|
|
30
|
+
* its own reading expires rather than polling, and an element showing a date
|
|
31
|
+
* asks for nothing at all: fifty rows and fifty intervals is fifty wakeups a
|
|
32
|
+
* second where one will do, and a feed of last month's notifications should cost
|
|
33
|
+
* nothing to leave open.
|
|
34
|
+
*
|
|
35
|
+
* **`<time datetime>` whatever the text says**, so a screen reader, a copy and
|
|
36
|
+
* paste, and anything parsing the page all get the real instant rather than
|
|
37
|
+
* "yesterday".
|
|
38
|
+
*
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
* @status experimental
|
|
41
|
+
* @category typography
|
|
42
|
+
* @aliases RelativeTime, Timestamp, TimeAgo
|
|
43
|
+
* @documentation https://helix.fusion.dev/components/format-date
|
|
44
|
+
*
|
|
45
|
+
* @csspart time - The `<time>` element carrying the reading.
|
|
46
|
+
*/
|
|
47
|
+
let HelixHeadlessFormatDate = class HelixHeadlessFormatDate extends HelixElement {
|
|
48
|
+
constructor() {
|
|
49
|
+
super(...arguments);
|
|
50
|
+
/**
|
|
51
|
+
* The timestamp, as anything `Date` parses.
|
|
52
|
+
*
|
|
53
|
+
* An ISO string is what an API sends and what `<time datetime>` takes, so it
|
|
54
|
+
* is the shape that needs no translation at either end. Left unset this
|
|
55
|
+
* renders nothing rather than the epoch, which is what parsing an empty string
|
|
56
|
+
* would give.
|
|
57
|
+
*
|
|
58
|
+
* **The element's own text is read as a fallback, and only in a browser.**
|
|
59
|
+
* `<helix-format-date elapsed>2026-08-27T01:00:00Z</helix-format-date>` is the
|
|
60
|
+
* spelling that reads best in markup, and it cannot be the only one: measured
|
|
61
|
+
* against Lit's server shim, `textContent`, `children`, `firstChild` and
|
|
62
|
+
* `querySelector` are all `undefined` there, so a server has no way to see it.
|
|
63
|
+
* An element rendered on a server needs the attribute; one rendered in a
|
|
64
|
+
* browser may use either.
|
|
65
|
+
*/
|
|
66
|
+
this.date = '';
|
|
67
|
+
/**
|
|
68
|
+
* Show how long ago it was, compactly, instead of the date.
|
|
69
|
+
*
|
|
70
|
+
* Reflected, because it is the one property that decides which of two readings
|
|
71
|
+
* this is and a stylesheet has a reason to know: a compact reading is a fixed
|
|
72
|
+
* few characters and a date is not.
|
|
73
|
+
*/
|
|
74
|
+
this.elapsed = false;
|
|
75
|
+
/**
|
|
76
|
+
* Locale for the reading.
|
|
77
|
+
*
|
|
78
|
+
* Empty is the runtime's own.
|
|
79
|
+
*/
|
|
80
|
+
this.locale = '';
|
|
81
|
+
/**
|
|
82
|
+
* The clock this element last drew against.
|
|
83
|
+
*
|
|
84
|
+
* A state field and not a read of `Date.now()` inside `render`, which would
|
|
85
|
+
* make the template a function of something Lit cannot see change: the element
|
|
86
|
+
* would draw the right text once and never notice it had gone stale.
|
|
87
|
+
*/
|
|
88
|
+
this.clock = undefined;
|
|
89
|
+
/**
|
|
90
|
+
* The date read out of the light DOM, where no attribute carried one.
|
|
91
|
+
*/
|
|
92
|
+
this.written = '';
|
|
93
|
+
this.stopTicking = undefined;
|
|
94
|
+
this.watching = undefined;
|
|
95
|
+
}
|
|
96
|
+
/** The timestamp, or nothing where there is not one to read. */
|
|
97
|
+
get moment() {
|
|
98
|
+
const source = this.date || this.written;
|
|
99
|
+
if (source === '') {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
const parsed = new Date(source);
|
|
103
|
+
return Number.isNaN(parsed.getTime()) ? undefined : parsed;
|
|
104
|
+
}
|
|
105
|
+
/** Every `Intl.DateTimeFormat` option a consumer set, and none they did not. */
|
|
106
|
+
get options() {
|
|
107
|
+
const asked = {};
|
|
108
|
+
if (this.day) {
|
|
109
|
+
asked.day = this.day;
|
|
110
|
+
}
|
|
111
|
+
if (this.hour) {
|
|
112
|
+
asked.hour = this.hour;
|
|
113
|
+
}
|
|
114
|
+
if (this.minute) {
|
|
115
|
+
asked.minute = this.minute;
|
|
116
|
+
}
|
|
117
|
+
if (this.month) {
|
|
118
|
+
asked.month = this.month;
|
|
119
|
+
}
|
|
120
|
+
if (this.second) {
|
|
121
|
+
asked.second = this.second;
|
|
122
|
+
}
|
|
123
|
+
if (this.timeZone) {
|
|
124
|
+
asked.timeZone = this.timeZone;
|
|
125
|
+
}
|
|
126
|
+
if (this.timeZoneName) {
|
|
127
|
+
asked.timeZoneName = this.timeZoneName;
|
|
128
|
+
}
|
|
129
|
+
if (this.weekday) {
|
|
130
|
+
asked.weekday = this.weekday;
|
|
131
|
+
}
|
|
132
|
+
if (this.year) {
|
|
133
|
+
asked.year = this.year;
|
|
134
|
+
}
|
|
135
|
+
return asked;
|
|
136
|
+
}
|
|
137
|
+
connectedCallback() {
|
|
138
|
+
super.connectedCallback();
|
|
139
|
+
this.tick();
|
|
140
|
+
/* Rebuilt on every connection rather than built once, because
|
|
141
|
+
`disconnectedCallback` takes it down and a framework moves nodes for
|
|
142
|
+
ordinary reasons: built in `firstUpdated` alone this comes back
|
|
143
|
+
permanently dead the first time a list is reordered. Guarded on
|
|
144
|
+
`hasUpdated` because the first connection happens before there is anything
|
|
145
|
+
to watch. See `check:observers`. */
|
|
146
|
+
if (this.hasUpdated) {
|
|
147
|
+
this.watch();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
disconnectedCallback() {
|
|
151
|
+
super.disconnectedCallback();
|
|
152
|
+
/* Both outlive the element otherwise, and a page that mounts and unmounts a
|
|
153
|
+
feed leaks one of each every time it opens. */
|
|
154
|
+
this.stopTicking?.();
|
|
155
|
+
this.stopTicking = undefined;
|
|
156
|
+
this.watching?.disconnect();
|
|
157
|
+
this.watching = undefined;
|
|
158
|
+
}
|
|
159
|
+
firstUpdated(changed) {
|
|
160
|
+
super.firstUpdated(changed);
|
|
161
|
+
this.read();
|
|
162
|
+
this.watch();
|
|
163
|
+
}
|
|
164
|
+
willUpdate(changed) {
|
|
165
|
+
super.willUpdate(changed);
|
|
166
|
+
if (changed.has('date') || changed.has('elapsed') || changed.has('locale')) {
|
|
167
|
+
this.tick();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/** The light DOM's own text, which is the other way to write the value. */
|
|
171
|
+
read() {
|
|
172
|
+
if (this.date !== '') {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const written = this.textContent?.trim() ?? '';
|
|
176
|
+
if (written !== this.written) {
|
|
177
|
+
this.written = written;
|
|
178
|
+
this.tick();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
watch() {
|
|
182
|
+
this.watching?.disconnect();
|
|
183
|
+
this.watching = new MutationObserver(() => this.read());
|
|
184
|
+
this.watching.observe(this, { characterData: true, childList: true, subtree: true });
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Schedules the next reading, and only the next one.
|
|
188
|
+
*
|
|
189
|
+
* The formatter says when its own answer expires, so this asks for exactly
|
|
190
|
+
* that moment rather than polling: an item minutes old wakes once a minute, an
|
|
191
|
+
* item hours old once an hour, and an item showing a date never, which is the
|
|
192
|
+
* difference between a feed that costs nothing to leave open and one that
|
|
193
|
+
* does.
|
|
194
|
+
*/
|
|
195
|
+
tick() {
|
|
196
|
+
this.stopTicking?.();
|
|
197
|
+
this.stopTicking = undefined;
|
|
198
|
+
const moment = this.moment;
|
|
199
|
+
if (!moment || !this.elapsed) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const now = new Date();
|
|
203
|
+
this.clock = now.getTime();
|
|
204
|
+
const { next } = elapsedTime(this.locale)(moment, now);
|
|
205
|
+
if (!Number.isFinite(next)) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
this.stopTicking = subscribe(next, () => this.tick());
|
|
209
|
+
}
|
|
210
|
+
render() {
|
|
211
|
+
const moment = this.moment;
|
|
212
|
+
if (!moment) {
|
|
213
|
+
return nothing;
|
|
214
|
+
}
|
|
215
|
+
const text = this.elapsed
|
|
216
|
+
? elapsedTime(this.locale)(moment, new Date(this.clock ?? Date.now())).text
|
|
217
|
+
: new Intl.DateTimeFormat(this.locale || undefined, this.options).format(moment);
|
|
218
|
+
return html `<time part="time" datetime=${moment.toISOString()}>${text}</time>`;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
__decorate([
|
|
222
|
+
property()
|
|
223
|
+
], HelixHeadlessFormatDate.prototype, "date", void 0);
|
|
224
|
+
__decorate([
|
|
225
|
+
property()
|
|
226
|
+
], HelixHeadlessFormatDate.prototype, "day", void 0);
|
|
227
|
+
__decorate([
|
|
228
|
+
property({ reflect: true, type: Boolean })
|
|
229
|
+
], HelixHeadlessFormatDate.prototype, "elapsed", void 0);
|
|
230
|
+
__decorate([
|
|
231
|
+
property()
|
|
232
|
+
], HelixHeadlessFormatDate.prototype, "hour", void 0);
|
|
233
|
+
__decorate([
|
|
234
|
+
property()
|
|
235
|
+
], HelixHeadlessFormatDate.prototype, "locale", void 0);
|
|
236
|
+
__decorate([
|
|
237
|
+
property()
|
|
238
|
+
], HelixHeadlessFormatDate.prototype, "minute", void 0);
|
|
239
|
+
__decorate([
|
|
240
|
+
property()
|
|
241
|
+
], HelixHeadlessFormatDate.prototype, "month", void 0);
|
|
242
|
+
__decorate([
|
|
243
|
+
property()
|
|
244
|
+
], HelixHeadlessFormatDate.prototype, "second", void 0);
|
|
245
|
+
__decorate([
|
|
246
|
+
property({ attribute: 'time-zone' })
|
|
247
|
+
], HelixHeadlessFormatDate.prototype, "timeZone", void 0);
|
|
248
|
+
__decorate([
|
|
249
|
+
property({ attribute: 'time-zone-name' })
|
|
250
|
+
], HelixHeadlessFormatDate.prototype, "timeZoneName", void 0);
|
|
251
|
+
__decorate([
|
|
252
|
+
property()
|
|
253
|
+
], HelixHeadlessFormatDate.prototype, "weekday", void 0);
|
|
254
|
+
__decorate([
|
|
255
|
+
property()
|
|
256
|
+
], HelixHeadlessFormatDate.prototype, "year", void 0);
|
|
257
|
+
__decorate([
|
|
258
|
+
state()
|
|
259
|
+
], HelixHeadlessFormatDate.prototype, "clock", void 0);
|
|
260
|
+
__decorate([
|
|
261
|
+
state()
|
|
262
|
+
], HelixHeadlessFormatDate.prototype, "written", void 0);
|
|
263
|
+
HelixHeadlessFormatDate = __decorate([
|
|
264
|
+
customElement('helix-headless-format-date')
|
|
265
|
+
], HelixHeadlessFormatDate);
|
|
266
|
+
export { HelixHeadlessFormatDate };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which tone a reading gets, and how many readings fit.
|
|
3
|
+
*
|
|
4
|
+
* Kept apart from the element because both answers are arithmetic and both are
|
|
5
|
+
* easy to get subtly wrong in ways a picture hides: a threshold comparison off
|
|
6
|
+
* by one boundary colours a handful of cells wrong out of ninety, and a fit
|
|
7
|
+
* calculation off by one drops a day silently. Neither is visible in a
|
|
8
|
+
* screenshot of a strip.
|
|
9
|
+
*/
|
|
10
|
+
/** A reading, reduced to what the bucketing needs. */
|
|
11
|
+
export interface Reading {
|
|
12
|
+
tone?: string | undefined;
|
|
13
|
+
value: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The tone for one reading, from its own `data-tone` or from the thresholds.
|
|
17
|
+
*
|
|
18
|
+
* **The cell's own tone wins**, and that ordering is the whole reason both
|
|
19
|
+
* exist. A status page already knows a day was degraded; making it encode that
|
|
20
|
+
* as a number so a component can decode it again is work for nothing, and the
|
|
21
|
+
* encoding would have to agree with the thresholds or the colours would drift
|
|
22
|
+
* from the truth. A contribution graph has only counts and wants the buckets.
|
|
23
|
+
*
|
|
24
|
+
* Thresholds are read as lower bounds, in the order given, and the last one that
|
|
25
|
+
* a value reaches wins. `thresholds="0,1,3,6"` with `tones="muted,info,accent,success"`
|
|
26
|
+
* puts 0 in `muted`, 1 and 2 in `info`, 3 to 5 in `accent`, and 6 upward in
|
|
27
|
+
* `success`. A value below the first bound gets no tone rather than the first
|
|
28
|
+
* one: an empty cell in a contribution graph is a day with nothing in it, and
|
|
29
|
+
* painting it as the lowest bucket claims a reading that does not exist.
|
|
30
|
+
*/
|
|
31
|
+
export declare const toneOf: (reading: Reading, thresholds: readonly number[], tones: readonly string[]) => string | undefined;
|
|
32
|
+
/** A comma or space separated list of numbers, in the order written. */
|
|
33
|
+
export declare const numbers: (source: string) => number[];
|
|
34
|
+
/** A comma or space separated list of names, in the order written. */
|
|
35
|
+
export declare const words: (source: string) => string[];
|
|
36
|
+
/**
|
|
37
|
+
* How many readings fit across a given width, and which ones they are.
|
|
38
|
+
*
|
|
39
|
+
* **Ninety cells in 320 pixels is three and a half pixels each**, which is not a
|
|
40
|
+
* strip, it is a smear. So a narrow container shows fewer cells rather than
|
|
41
|
+
* thinner ones, and it shows the *most recent* ones, because a status strip that
|
|
42
|
+
* drops the newest days to keep the oldest is answering a question nobody asked.
|
|
43
|
+
*
|
|
44
|
+
* **The count it returns is what the summary has to be recomputed against.** A
|
|
45
|
+
* strip labeled "99.2% over 90 days" that is drawing 45 of them is telling the
|
|
46
|
+
* reader something false about the picture in front of them, and nothing about
|
|
47
|
+
* the picture says so. That is the one fault in this component that a screenshot
|
|
48
|
+
* cannot show, which is why the element reflects the number and announces it.
|
|
49
|
+
*
|
|
50
|
+
* **What crosses the width is a column, and `rows` is how many cells are in
|
|
51
|
+
* one.** This counted cells until 27 Aug 2026, which is the same number only
|
|
52
|
+
* while `rows` is 1. At `rows="7"` a ten week graph came out at fifty-nine
|
|
53
|
+
* readings in a 592px box: eleven days dropped to fit a strip that wanted 156
|
|
54
|
+
* pixels, and the fifty-nine were not a multiple of seven, so every column after
|
|
55
|
+
* the cut was offset by a day and the day-of-week rows stopped meaning anything.
|
|
56
|
+
* A calendar heatmap that silently rotates its own weekdays is worse than one
|
|
57
|
+
* that drops a week, and both came from dividing by the wrong thing.
|
|
58
|
+
*
|
|
59
|
+
* The count is therefore always a whole number of columns, which is what keeps
|
|
60
|
+
* the tail slice aligned.
|
|
61
|
+
*/
|
|
62
|
+
export declare const fits: (total: number, width: number, minimum: number, gap: number, rows?: number) => number;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which tone a reading gets, and how many readings fit.
|
|
3
|
+
*
|
|
4
|
+
* Kept apart from the element because both answers are arithmetic and both are
|
|
5
|
+
* easy to get subtly wrong in ways a picture hides: a threshold comparison off
|
|
6
|
+
* by one boundary colours a handful of cells wrong out of ninety, and a fit
|
|
7
|
+
* calculation off by one drops a day silently. Neither is visible in a
|
|
8
|
+
* screenshot of a strip.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The tone for one reading, from its own `data-tone` or from the thresholds.
|
|
12
|
+
*
|
|
13
|
+
* **The cell's own tone wins**, and that ordering is the whole reason both
|
|
14
|
+
* exist. A status page already knows a day was degraded; making it encode that
|
|
15
|
+
* as a number so a component can decode it again is work for nothing, and the
|
|
16
|
+
* encoding would have to agree with the thresholds or the colours would drift
|
|
17
|
+
* from the truth. A contribution graph has only counts and wants the buckets.
|
|
18
|
+
*
|
|
19
|
+
* Thresholds are read as lower bounds, in the order given, and the last one that
|
|
20
|
+
* a value reaches wins. `thresholds="0,1,3,6"` with `tones="muted,info,accent,success"`
|
|
21
|
+
* puts 0 in `muted`, 1 and 2 in `info`, 3 to 5 in `accent`, and 6 upward in
|
|
22
|
+
* `success`. A value below the first bound gets no tone rather than the first
|
|
23
|
+
* one: an empty cell in a contribution graph is a day with nothing in it, and
|
|
24
|
+
* painting it as the lowest bucket claims a reading that does not exist.
|
|
25
|
+
*/
|
|
26
|
+
export const toneOf = (reading, thresholds, tones) => {
|
|
27
|
+
if (reading.tone) {
|
|
28
|
+
return reading.tone;
|
|
29
|
+
}
|
|
30
|
+
if (thresholds.length === 0) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
let chosen;
|
|
34
|
+
for (const [index, bound] of thresholds.entries()) {
|
|
35
|
+
if (reading.value >= bound) {
|
|
36
|
+
chosen = tones[index] ?? chosen;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return chosen;
|
|
40
|
+
};
|
|
41
|
+
/** A comma or space separated list of numbers, in the order written. */
|
|
42
|
+
export const numbers = (source) => source
|
|
43
|
+
.split(/[\s,]+/)
|
|
44
|
+
.filter((one) => one !== '')
|
|
45
|
+
.map(Number)
|
|
46
|
+
.filter((one) => Number.isFinite(one));
|
|
47
|
+
/** A comma or space separated list of names, in the order written. */
|
|
48
|
+
export const words = (source) => source.split(/[\s,]+/).filter((one) => one !== '');
|
|
49
|
+
/**
|
|
50
|
+
* How many readings fit across a given width, and which ones they are.
|
|
51
|
+
*
|
|
52
|
+
* **Ninety cells in 320 pixels is three and a half pixels each**, which is not a
|
|
53
|
+
* strip, it is a smear. So a narrow container shows fewer cells rather than
|
|
54
|
+
* thinner ones, and it shows the *most recent* ones, because a status strip that
|
|
55
|
+
* drops the newest days to keep the oldest is answering a question nobody asked.
|
|
56
|
+
*
|
|
57
|
+
* **The count it returns is what the summary has to be recomputed against.** A
|
|
58
|
+
* strip labeled "99.2% over 90 days" that is drawing 45 of them is telling the
|
|
59
|
+
* reader something false about the picture in front of them, and nothing about
|
|
60
|
+
* the picture says so. That is the one fault in this component that a screenshot
|
|
61
|
+
* cannot show, which is why the element reflects the number and announces it.
|
|
62
|
+
*
|
|
63
|
+
* **What crosses the width is a column, and `rows` is how many cells are in
|
|
64
|
+
* one.** This counted cells until 27 Aug 2026, which is the same number only
|
|
65
|
+
* while `rows` is 1. At `rows="7"` a ten week graph came out at fifty-nine
|
|
66
|
+
* readings in a 592px box: eleven days dropped to fit a strip that wanted 156
|
|
67
|
+
* pixels, and the fifty-nine were not a multiple of seven, so every column after
|
|
68
|
+
* the cut was offset by a day and the day-of-week rows stopped meaning anything.
|
|
69
|
+
* A calendar heatmap that silently rotates its own weekdays is worse than one
|
|
70
|
+
* that drops a week, and both came from dividing by the wrong thing.
|
|
71
|
+
*
|
|
72
|
+
* The count is therefore always a whole number of columns, which is what keeps
|
|
73
|
+
* the tail slice aligned.
|
|
74
|
+
*/
|
|
75
|
+
export const fits = (total, width, minimum, gap, rows = 1) => {
|
|
76
|
+
if (!Number.isFinite(width) || width <= 0 || minimum <= 0) {
|
|
77
|
+
return total;
|
|
78
|
+
}
|
|
79
|
+
/* n columns need n widths and n-1 gaps, so solving for n gives the +gap on
|
|
80
|
+
both sides. Written as `width / (minimum + gap)` it is short by one column
|
|
81
|
+
at every size, which is the off-by-one that reads as "the strip has a
|
|
82
|
+
margin". */
|
|
83
|
+
const columns = Math.max(1, Math.floor((width + gap) / (minimum + gap)));
|
|
84
|
+
return Math.min(total, columns * Math.max(1, rows));
|
|
85
|
+
};
|