@delacour/react-native-ui 0.1.0-alpha.4 → 0.2.0-alpha.20261010061731
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/README.md +10 -6
- package/package.json +49 -5
- package/src/components/accordion/AGENTS.md +21 -9
- package/src/components/accordion/accordion-content.tsx +7 -4
- package/src/components/accordion/accordion-item.tsx +15 -13
- package/src/components/accordion/accordion.context.tsx +11 -5
- package/src/components/accordion/accordion.variants.test.ts +64 -3
- package/src/components/accordion/accordion.variants.ts +33 -9
- package/src/components/alert/AGENTS.md +102 -0
- package/src/components/alert/alert-action.tsx +17 -0
- package/src/components/alert/alert-close-button.tsx +50 -0
- package/src/components/alert/alert-content.tsx +15 -0
- package/src/components/alert/alert-description.tsx +16 -0
- package/src/components/alert/alert-glyphs.ts +25 -0
- package/src/components/alert/alert-indicator.tsx +40 -0
- package/src/components/alert/alert-title.tsx +18 -0
- package/src/components/alert/alert.context.tsx +69 -0
- package/src/components/alert/alert.tsx +160 -0
- package/src/components/alert/alert.types.ts +10 -0
- package/src/components/alert/alert.variants.test.ts +218 -0
- package/src/components/alert/alert.variants.ts +180 -0
- package/src/components/alert/index.ts +23 -0
- package/src/components/avatar/AGENTS.md +106 -0
- package/src/components/avatar/avatar-badge.tsx +51 -0
- package/src/components/avatar/avatar-group.tsx +139 -0
- package/src/components/avatar/avatar.context.tsx +93 -0
- package/src/components/avatar/avatar.tsx +201 -0
- package/src/components/avatar/avatar.utils.test.ts +174 -0
- package/src/components/avatar/avatar.utils.ts +141 -0
- package/src/components/avatar/avatar.variants.test.ts +251 -0
- package/src/components/avatar/avatar.variants.ts +270 -0
- package/src/components/avatar/index.ts +39 -0
- package/src/components/badge/AGENTS.md +10 -0
- package/src/components/badge/badge-close-button.tsx +2 -2
- package/src/components/badge/badge.context.tsx +2 -1
- package/src/components/badge/badge.tsx +13 -4
- package/src/components/badge/badge.variants.test.ts +26 -0
- package/src/components/badge/badge.variants.ts +21 -0
- package/src/components/bottom-sheet/AGENTS.md +186 -231
- package/src/components/bottom-sheet/bottom-sheet-background.tsx +31 -22
- package/src/components/bottom-sheet/bottom-sheet-close.tsx +23 -30
- package/src/components/bottom-sheet/bottom-sheet-container.tsx +54 -208
- package/src/components/bottom-sheet/bottom-sheet-content.tsx +25 -48
- package/src/components/bottom-sheet/bottom-sheet-description.tsx +8 -2
- package/src/components/bottom-sheet/bottom-sheet-flat-list.tsx +65 -0
- package/src/components/bottom-sheet/bottom-sheet-footer.tsx +53 -122
- package/src/components/bottom-sheet/bottom-sheet-handle.tsx +31 -26
- package/src/components/bottom-sheet/bottom-sheet-legend-list.tsx +69 -0
- package/src/components/bottom-sheet/bottom-sheet-overlay.tsx +25 -147
- package/src/components/bottom-sheet/bottom-sheet-provider.tsx +42 -0
- package/src/components/bottom-sheet/bottom-sheet-scroll-view.tsx +38 -62
- package/src/components/bottom-sheet/bottom-sheet-section-list.tsx +58 -0
- package/src/components/bottom-sheet/bottom-sheet-steps.tsx +88 -0
- package/src/components/bottom-sheet/bottom-sheet-text-input.tsx +44 -0
- package/src/components/bottom-sheet/bottom-sheet-title.tsx +12 -8
- package/src/components/bottom-sheet/bottom-sheet-trigger.tsx +19 -37
- package/src/components/bottom-sheet/bottom-sheet.tsx +113 -60
- package/src/components/bottom-sheet/bottom-sheet.variants.test.ts +47 -87
- package/src/components/bottom-sheet/bottom-sheet.variants.ts +50 -126
- package/src/components/bottom-sheet/index.ts +39 -17
- package/src/components/bottom-sheet/use-bottom-sheet-input.ts +16 -115
- package/src/components/button/AGENTS.md +51 -11
- package/src/components/button/button-group.tsx +44 -8
- package/src/components/button/button.context.tsx +10 -0
- package/src/components/button/button.tsx +7 -1
- package/src/components/button/button.variants.test.ts +190 -0
- package/src/components/button/button.variants.ts +87 -6
- package/src/components/button/index.ts +2 -0
- package/src/components/calendar/AGENTS.md +142 -0
- package/src/components/calendar/calendar-caption.tsx +116 -0
- package/src/components/calendar/calendar-day.tsx +103 -0
- package/src/components/calendar/calendar-grid.tsx +183 -0
- package/src/components/calendar/calendar-header.tsx +34 -0
- package/src/components/calendar/calendar-nav.tsx +51 -0
- package/src/components/calendar/calendar-picker.tsx +128 -0
- package/src/components/calendar/calendar-weekdays.tsx +48 -0
- package/src/components/calendar/calendar.context.tsx +108 -0
- package/src/components/calendar/calendar.date.test.ts +456 -0
- package/src/components/calendar/calendar.date.ts +584 -0
- package/src/components/calendar/calendar.tsx +389 -0
- package/src/components/calendar/calendar.types.ts +87 -0
- package/src/components/calendar/calendar.variants.test.ts +363 -0
- package/src/components/calendar/calendar.variants.ts +426 -0
- package/src/components/calendar/index.ts +96 -0
- package/src/components/card/AGENTS.md +92 -0
- package/src/components/card/card-action.tsx +16 -0
- package/src/components/card/card-content.tsx +12 -0
- package/src/components/card/card-description.tsx +12 -0
- package/src/components/card/card-footer.tsx +30 -0
- package/src/components/card/card-header.tsx +45 -0
- package/src/components/card/card-title.tsx +25 -0
- package/src/components/card/card.context.tsx +64 -0
- package/src/components/card/card.tsx +100 -0
- package/src/components/card/card.types.ts +13 -0
- package/src/components/card/card.variants.test.ts +240 -0
- package/src/components/card/card.variants.ts +177 -0
- package/src/components/card/index.ts +15 -0
- package/src/components/chart/AGENTS.md +8 -0
- package/src/components/chart/chart.tsx +8 -1
- package/src/components/chip/AGENTS.md +113 -0
- package/src/components/chip/chip-close-button.tsx +48 -0
- package/src/components/chip/chip-end-content.tsx +15 -0
- package/src/components/chip/chip-label.tsx +21 -0
- package/src/components/chip/chip-start-content.tsx +16 -0
- package/src/components/chip/chip.context.tsx +66 -0
- package/src/components/chip/chip.tsx +268 -0
- package/src/components/chip/chip.types.ts +10 -0
- package/src/components/chip/chip.variants.test.ts +335 -0
- package/src/components/chip/chip.variants.ts +321 -0
- package/src/components/chip/index.ts +24 -0
- package/src/components/collapsible/AGENTS.md +97 -0
- package/src/components/collapsible/collapsible-content.tsx +97 -0
- package/src/components/collapsible/collapsible-description.tsx +17 -0
- package/src/components/collapsible/collapsible-indicator.tsx +92 -0
- package/src/components/collapsible/collapsible-title.tsx +17 -0
- package/src/components/collapsible/collapsible-trigger.tsx +133 -0
- package/src/components/collapsible/collapsible.context.tsx +91 -0
- package/src/components/collapsible/collapsible.tsx +167 -0
- package/src/components/collapsible/collapsible.types.ts +9 -0
- package/src/components/collapsible/collapsible.variants.test.ts +338 -0
- package/src/components/collapsible/collapsible.variants.ts +228 -0
- package/src/components/collapsible/index.ts +32 -0
- package/src/components/context-menu/AGENTS.md +103 -0
- package/src/components/context-menu/context-menu-content.tsx +64 -0
- package/src/components/context-menu/context-menu-item.tsx +22 -0
- package/src/components/context-menu/context-menu-preview.tsx +60 -0
- package/src/components/context-menu/context-menu-trigger.tsx +160 -0
- package/src/components/context-menu/context-menu.context.tsx +91 -0
- package/src/components/context-menu/context-menu.tsx +90 -0
- package/src/components/context-menu/context-menu.variants.test.ts +266 -0
- package/src/components/context-menu/context-menu.variants.ts +147 -0
- package/src/components/context-menu/index.ts +18 -0
- package/src/components/dialog/AGENTS.md +97 -0
- package/src/components/dialog/dialog-body.tsx +21 -0
- package/src/components/dialog/dialog-close.tsx +82 -0
- package/src/components/dialog/dialog-content.tsx +153 -0
- package/src/components/dialog/dialog-description.tsx +23 -0
- package/src/components/dialog/dialog-footer.tsx +32 -0
- package/src/components/dialog/dialog-header.tsx +20 -0
- package/src/components/dialog/dialog-title.tsx +42 -0
- package/src/components/dialog/dialog-trigger.tsx +54 -0
- package/src/components/dialog/dialog.context.tsx +90 -0
- package/src/components/dialog/dialog.tsx +119 -0
- package/src/components/dialog/dialog.variants.test.ts +224 -0
- package/src/components/dialog/dialog.variants.ts +173 -0
- package/src/components/dialog/index.ts +30 -0
- package/src/components/drawer/AGENTS.md +123 -0
- package/src/components/drawer/drawer-body.tsx +46 -0
- package/src/components/drawer/drawer-close.tsx +76 -0
- package/src/components/drawer/drawer-content.tsx +186 -0
- package/src/components/drawer/drawer-description.tsx +23 -0
- package/src/components/drawer/drawer-footer.tsx +21 -0
- package/src/components/drawer/drawer-header.tsx +42 -0
- package/src/components/drawer/drawer-title.tsx +35 -0
- package/src/components/drawer/drawer-trigger.tsx +54 -0
- package/src/components/drawer/drawer.context.tsx +114 -0
- package/src/components/drawer/drawer.tsx +119 -0
- package/src/components/drawer/drawer.variants.test.ts +392 -0
- package/src/components/drawer/drawer.variants.ts +244 -0
- package/src/components/drawer/index.ts +41 -0
- package/src/components/drawer/use-drawer-pan.ts +108 -0
- package/src/components/empty-state/AGENTS.md +90 -0
- package/src/components/empty-state/empty-state-content.tsx +17 -0
- package/src/components/empty-state/empty-state-description.tsx +12 -0
- package/src/components/empty-state/empty-state-header.tsx +17 -0
- package/src/components/empty-state/empty-state-media.tsx +56 -0
- package/src/components/empty-state/empty-state-title.tsx +18 -0
- package/src/components/empty-state/empty-state.context.tsx +65 -0
- package/src/components/empty-state/empty-state.tsx +84 -0
- package/src/components/empty-state/empty-state.types.ts +14 -0
- package/src/components/empty-state/empty-state.variants.test.ts +245 -0
- package/src/components/empty-state/empty-state.variants.ts +132 -0
- package/src/components/empty-state/index.ts +20 -0
- package/src/components/fab/AGENTS.md +119 -0
- package/src/components/fab/fab-action.tsx +118 -0
- package/src/components/fab/fab-group.tsx +214 -0
- package/src/components/fab/fab-label.tsx +18 -0
- package/src/components/fab/fab.context.tsx +125 -0
- package/src/components/fab/fab.tsx +156 -0
- package/src/components/fab/fab.types.ts +17 -0
- package/src/components/fab/fab.variants.test.ts +274 -0
- package/src/components/fab/fab.variants.ts +234 -0
- package/src/components/fab/index.ts +37 -0
- package/src/components/feedback/AGENTS.md +95 -0
- package/src/components/feedback/feedback-action.tsx +16 -0
- package/src/components/feedback/feedback-cancel.tsx +34 -0
- package/src/components/feedback/feedback-close.tsx +21 -0
- package/src/components/feedback/feedback-content.tsx +24 -0
- package/src/components/feedback/feedback-field.tsx +70 -0
- package/src/components/feedback/feedback-footer.tsx +21 -0
- package/src/components/feedback/feedback-panel.tsx +54 -0
- package/src/components/feedback/feedback-submit.tsx +74 -0
- package/src/components/feedback/feedback-title.tsx +34 -0
- package/src/components/feedback/feedback-trigger.tsx +20 -0
- package/src/components/feedback/feedback.context.tsx +73 -0
- package/src/components/feedback/feedback.tsx +135 -0
- package/src/components/feedback/feedback.variants.test.ts +185 -0
- package/src/components/feedback/feedback.variants.ts +128 -0
- package/src/components/feedback/index.ts +24 -0
- package/src/components/field/AGENTS.md +19 -0
- package/src/components/field/field-label.tsx +19 -5
- package/src/components/field/field.context.tsx +17 -0
- package/src/components/field/field.tsx +15 -2
- package/src/components/field/field.variants.test.ts +24 -0
- package/src/components/field/field.variants.ts +20 -0
- package/src/components/field/index.ts +1 -0
- package/src/components/input/AGENTS.md +5 -0
- package/src/components/input/input.variants.test.ts +32 -0
- package/src/components/input/input.variants.ts +13 -1
- package/src/components/item/AGENTS.md +92 -0
- package/src/components/item/index.ts +25 -0
- package/src/components/item/item-actions.tsx +28 -0
- package/src/components/item/item-content.tsx +15 -0
- package/src/components/item/item-description.tsx +12 -0
- package/src/components/item/item-footer.tsx +13 -0
- package/src/components/item/item-group.tsx +32 -0
- package/src/components/item/item-header.tsx +13 -0
- package/src/components/item/item-media.tsx +37 -0
- package/src/components/item/item-separator.tsx +13 -0
- package/src/components/item/item-title.tsx +17 -0
- package/src/components/item/item.context.tsx +66 -0
- package/src/components/item/item.tsx +218 -0
- package/src/components/item/item.types.ts +12 -0
- package/src/components/item/item.variants.test.ts +263 -0
- package/src/components/item/item.variants.ts +200 -0
- package/src/components/kpi/AGENTS.md +125 -0
- package/src/components/kpi/index.ts +45 -0
- package/src/components/kpi/kpi-action.tsx +12 -0
- package/src/components/kpi/kpi-content.tsx +35 -0
- package/src/components/kpi/kpi-footer.tsx +52 -0
- package/src/components/kpi/kpi-group.tsx +70 -0
- package/src/components/kpi/kpi-header.tsx +25 -0
- package/src/components/kpi/kpi-icon.tsx +28 -0
- package/src/components/kpi/kpi-sparkline.tsx +145 -0
- package/src/components/kpi/kpi-stat.tsx +20 -0
- package/src/components/kpi/kpi-title.tsx +19 -0
- package/src/components/kpi/kpi-trend.tsx +105 -0
- package/src/components/kpi/kpi-value.tsx +32 -0
- package/src/components/kpi/kpi.context.tsx +111 -0
- package/src/components/kpi/kpi.tsx +154 -0
- package/src/components/kpi/kpi.types.ts +9 -0
- package/src/components/kpi/kpi.variants.test.ts +428 -0
- package/src/components/kpi/kpi.variants.ts +347 -0
- package/src/components/label/AGENTS.md +89 -0
- package/src/components/label/index.ts +10 -0
- package/src/components/label/label.tsx +97 -0
- package/src/components/label/label.variants.test.ts +176 -0
- package/src/components/label/label.variants.ts +123 -0
- package/src/components/menu/AGENTS.md +176 -0
- package/src/components/menu/index.ts +44 -0
- package/src/components/menu/menu-background.tsx +17 -0
- package/src/components/menu/menu-checkbox-item.tsx +57 -0
- package/src/components/menu/menu-content.tsx +303 -0
- package/src/components/menu/menu-item.tsx +162 -0
- package/src/components/menu/menu-label.tsx +14 -0
- package/src/components/menu/menu-radio-group.tsx +50 -0
- package/src/components/menu/menu-radio-item.tsx +57 -0
- package/src/components/menu/menu-separator.tsx +11 -0
- package/src/components/menu/menu-sub-content.tsx +72 -0
- package/src/components/menu/menu-sub-trigger.tsx +50 -0
- package/src/components/menu/menu-sub.tsx +75 -0
- package/src/components/menu/menu-trigger.tsx +57 -0
- package/src/components/menu/menu.context.tsx +214 -0
- package/src/components/menu/menu.tsx +88 -0
- package/src/components/menu/menu.types.ts +33 -0
- package/src/components/menu/menu.variants.test.ts +400 -0
- package/src/components/menu/menu.variants.ts +353 -0
- package/src/components/meter/AGENTS.md +135 -0
- package/src/components/meter/index.ts +43 -0
- package/src/components/meter/meter-fill.tsx +19 -0
- package/src/components/meter/meter-header.tsx +17 -0
- package/src/components/meter/meter-label.tsx +18 -0
- package/src/components/meter/meter-output.tsx +42 -0
- package/src/components/meter/meter-segments.tsx +83 -0
- package/src/components/meter/meter-track.tsx +16 -0
- package/src/components/meter/meter.context.tsx +62 -0
- package/src/components/meter/meter.tsx +286 -0
- package/src/components/meter/meter.types.ts +30 -0
- package/src/components/meter/meter.variants.test.ts +430 -0
- package/src/components/meter/meter.variants.ts +347 -0
- package/src/components/overlay/AGENTS.md +89 -0
- package/src/components/overlay/index.ts +27 -0
- package/src/components/overlay/overlay-portal.tsx +84 -0
- package/src/components/overlay/overlay-presence.test.ts +46 -0
- package/src/components/overlay/overlay-presence.ts +49 -0
- package/src/components/overlay/overlay-registry.test.ts +96 -0
- package/src/components/overlay/overlay-registry.ts +99 -0
- package/src/components/overlay/overlay-scrim.tsx +49 -0
- package/src/components/overlay/overlay.context.tsx +48 -0
- package/src/components/overlay/overlay.tsx +118 -0
- package/src/components/overlay/overlay.variants.test.ts +37 -0
- package/src/components/overlay/overlay.variants.ts +33 -0
- package/src/components/overlay/use-overlay-back-handler.ts +34 -0
- package/src/components/overlay/use-overlay-presence.ts +87 -0
- package/src/components/popover/AGENTS.md +138 -0
- package/src/components/popover/index.ts +48 -0
- package/src/components/popover/popover-anchor.tsx +49 -0
- package/src/components/popover/popover-arrow.tsx +89 -0
- package/src/components/popover/popover-close.tsx +73 -0
- package/src/components/popover/popover-content.tsx +235 -0
- package/src/components/popover/popover-description.tsx +18 -0
- package/src/components/popover/popover-title.tsx +33 -0
- package/src/components/popover/popover-trigger.tsx +56 -0
- package/src/components/popover/popover.context.tsx +71 -0
- package/src/components/popover/popover.position.test.ts +354 -0
- package/src/components/popover/popover.position.ts +286 -0
- package/src/components/popover/popover.tsx +123 -0
- package/src/components/popover/popover.variants.test.ts +135 -0
- package/src/components/popover/popover.variants.ts +85 -0
- package/src/components/popover/use-anchor-measure.ts +76 -0
- package/src/components/popover/use-anchored-content.ts +219 -0
- package/src/components/pressable/AGENTS.md +11 -1
- package/src/components/pressable/pressable.tsx +7 -2
- package/src/components/pressable/pressable.variants.test.ts +29 -0
- package/src/components/pressable/pressable.variants.ts +17 -0
- package/src/components/progress/AGENTS.md +120 -0
- package/src/components/progress/index.ts +40 -0
- package/src/components/progress/progress-fill.tsx +152 -0
- package/src/components/progress/progress-header.tsx +19 -0
- package/src/components/progress/progress-label.tsx +27 -0
- package/src/components/progress/progress-output.tsx +47 -0
- package/src/components/progress/progress-track.tsx +38 -0
- package/src/components/progress/progress.context.tsx +79 -0
- package/src/components/progress/progress.tsx +171 -0
- package/src/components/progress/progress.types.ts +23 -0
- package/src/components/progress/progress.variants.test.ts +335 -0
- package/src/components/progress/progress.variants.ts +284 -0
- package/src/components/progress-button/AGENTS.md +116 -0
- package/src/components/progress-button/index.ts +36 -0
- package/src/components/progress-button/progress-button-done.tsx +33 -0
- package/src/components/progress-button/progress-button-label.tsx +27 -0
- package/src/components/progress-button/progress-button.context.tsx +93 -0
- package/src/components/progress-button/progress-button.tsx +414 -0
- package/src/components/progress-button/progress-button.variants.test.ts +314 -0
- package/src/components/progress-button/progress-button.variants.ts +236 -0
- package/src/components/provider/AGENTS.md +38 -25
- package/src/components/provider/provider.tsx +38 -11
- package/src/components/radio/AGENTS.md +8 -10
- package/src/components/radio/radio.variants.test.ts +5 -6
- package/src/components/radio/radio.variants.ts +6 -7
- package/src/components/rating/AGENTS.md +143 -0
- package/src/components/rating/index.ts +43 -0
- package/src/components/rating/rating-output.tsx +39 -0
- package/src/components/rating/rating-star.tsx +70 -0
- package/src/components/rating/rating-stars.tsx +219 -0
- package/src/components/rating/rating.context.tsx +79 -0
- package/src/components/rating/rating.tsx +163 -0
- package/src/components/rating/rating.variants.test.ts +347 -0
- package/src/components/rating/rating.variants.ts +354 -0
- package/src/components/selection-mode/AGENTS.md +155 -0
- package/src/components/selection-mode/index.ts +43 -0
- package/src/components/selection-mode/selection-mode-action.tsx +65 -0
- package/src/components/selection-mode/selection-mode-bar.tsx +79 -0
- package/src/components/selection-mode/selection-mode-group.tsx +123 -0
- package/src/components/selection-mode/selection-mode-header.tsx +85 -0
- package/src/components/selection-mode/selection-mode-indicator.tsx +118 -0
- package/src/components/selection-mode/selection-mode-item.tsx +182 -0
- package/src/components/selection-mode/selection-mode.context.tsx +89 -0
- package/src/components/selection-mode/selection-mode.tsx +207 -0
- package/src/components/selection-mode/selection-mode.types.ts +36 -0
- package/src/components/selection-mode/selection-mode.variants.test.ts +292 -0
- package/src/components/selection-mode/selection-mode.variants.ts +329 -0
- package/src/components/skeleton/AGENTS.md +120 -0
- package/src/components/skeleton/index.ts +15 -0
- package/src/components/skeleton/skeleton-clock.ts +48 -0
- package/src/components/skeleton/skeleton-group.tsx +64 -0
- package/src/components/skeleton/skeleton-shimmer.tsx +80 -0
- package/src/components/skeleton/skeleton.context.tsx +45 -0
- package/src/components/skeleton/skeleton.tsx +227 -0
- package/src/components/skeleton/skeleton.variants.test.ts +245 -0
- package/src/components/skeleton/skeleton.variants.ts +222 -0
- package/src/components/slide-button/AGENTS.md +122 -0
- package/src/components/slide-button/index.ts +43 -0
- package/src/components/slide-button/slide-button-label.tsx +70 -0
- package/src/components/slide-button/slide-button-thumb.tsx +93 -0
- package/src/components/slide-button/slide-button.context.tsx +76 -0
- package/src/components/slide-button/slide-button.tsx +457 -0
- package/src/components/slide-button/slide-button.variants.test.ts +288 -0
- package/src/components/slide-button/slide-button.variants.ts +324 -0
- package/src/components/slider/index.ts +2 -0
- package/src/components/slider/slider-thumb.tsx +33 -1
- package/src/components/slider/slider.variants.test.ts +52 -0
- package/src/components/slider/slider.variants.ts +56 -2
- package/src/components/stack-card/AGENTS.md +169 -0
- package/src/components/stack-card/index.ts +37 -0
- package/src/components/stack-card/stack-card-action.tsx +66 -0
- package/src/components/stack-card/stack-card-actions.tsx +18 -0
- package/src/components/stack-card/stack-card-card.tsx +71 -0
- package/src/components/stack-card/stack-card-empty.tsx +30 -0
- package/src/components/stack-card/stack-card-slot.tsx +90 -0
- package/src/components/stack-card/stack-card-stamp.tsx +76 -0
- package/src/components/stack-card/stack-card.context.tsx +117 -0
- package/src/components/stack-card/stack-card.tsx +557 -0
- package/src/components/stack-card/stack-card.types.ts +26 -0
- package/src/components/stack-card/stack-card.variants.test.ts +355 -0
- package/src/components/stack-card/stack-card.variants.ts +360 -0
- package/src/components/steps/AGENTS.md +153 -0
- package/src/components/steps/index.ts +45 -0
- package/src/components/steps/steps-connector.tsx +31 -0
- package/src/components/steps/steps-description.tsx +26 -0
- package/src/components/steps/steps-indicator.tsx +106 -0
- package/src/components/steps/steps-item.tsx +225 -0
- package/src/components/steps/steps-panel.tsx +41 -0
- package/src/components/steps/steps-title.tsx +32 -0
- package/src/components/steps/steps-track.tsx +59 -0
- package/src/components/steps/steps.context.tsx +123 -0
- package/src/components/steps/steps.tsx +166 -0
- package/src/components/steps/steps.variants.test.ts +388 -0
- package/src/components/steps/steps.variants.ts +468 -0
- package/src/components/surface/AGENTS.md +82 -0
- package/src/components/surface/index.ts +15 -0
- package/src/components/surface/surface.context.tsx +56 -0
- package/src/components/surface/surface.tsx +87 -0
- package/src/components/surface/surface.variants.test.ts +227 -0
- package/src/components/surface/surface.variants.ts +165 -0
- package/src/components/swipe/AGENTS.md +140 -0
- package/src/components/swipe/index.ts +31 -0
- package/src/components/swipe/swipe-action.tsx +99 -0
- package/src/components/swipe/swipe-end.tsx +14 -0
- package/src/components/swipe/swipe-group.tsx +55 -0
- package/src/components/swipe/swipe-panel.tsx +55 -0
- package/src/components/swipe/swipe-start.tsx +15 -0
- package/src/components/swipe/swipe.context.tsx +135 -0
- package/src/components/swipe/swipe.tsx +393 -0
- package/src/components/swipe/swipe.types.ts +7 -0
- package/src/components/swipe/swipe.variants.test.ts +337 -0
- package/src/components/swipe/swipe.variants.ts +290 -0
- package/src/components/switch/switch.variants.ts +2 -2
- package/src/components/tabs/AGENTS.md +4 -3
- package/src/components/tabs/tabs.variants.test.ts +1 -1
- package/src/components/tabs/tabs.variants.ts +4 -6
- package/src/components/text/AGENTS.md +8 -2
- package/src/components/text/text.tsx +7 -0
- package/src/components/text/text.variants.test.ts +24 -1
- package/src/components/text/text.variants.ts +5 -0
- package/src/components/textarea/AGENTS.md +89 -0
- package/src/components/textarea/index.ts +16 -0
- package/src/components/textarea/textarea.tsx +157 -0
- package/src/components/textarea/textarea.variants.test.ts +219 -0
- package/src/components/textarea/textarea.variants.ts +171 -0
- package/src/components/toast/AGENTS.md +140 -0
- package/src/components/toast/index.ts +74 -0
- package/src/components/toast/toast-action.tsx +59 -0
- package/src/components/toast/toast-api.ts +32 -0
- package/src/components/toast/toast-close.tsx +44 -0
- package/src/components/toast/toast-content.tsx +11 -0
- package/src/components/toast/toast-description.tsx +11 -0
- package/src/components/toast/toast-indicator.tsx +34 -0
- package/src/components/toast/toast-item.tsx +308 -0
- package/src/components/toast/toast-title.tsx +13 -0
- package/src/components/toast/toast-viewport.tsx +135 -0
- package/src/components/toast/toast.context.tsx +69 -0
- package/src/components/toast/toast.store.test.ts +259 -0
- package/src/components/toast/toast.store.ts +338 -0
- package/src/components/toast/toast.timer.test.ts +64 -0
- package/src/components/toast/toast.timer.ts +51 -0
- package/src/components/toast/toast.tsx +132 -0
- package/src/components/toast/toast.variants.test.ts +393 -0
- package/src/components/toast/toast.variants.ts +304 -0
- package/src/components/toggle-button/AGENTS.md +106 -0
- package/src/components/toggle-button/index.ts +30 -0
- package/src/components/toggle-button/toggle-button-group.tsx +156 -0
- package/src/components/toggle-button/toggle-button-label.tsx +19 -0
- package/src/components/toggle-button/toggle-button.context.tsx +130 -0
- package/src/components/toggle-button/toggle-button.tsx +172 -0
- package/src/components/toggle-button/toggle-button.variants.test.ts +189 -0
- package/src/components/toggle-button/toggle-button.variants.ts +160 -0
- package/src/components/tooltip/AGENTS.md +133 -0
- package/src/components/tooltip/index.ts +28 -0
- package/src/components/tooltip/tooltip-arrow.tsx +40 -0
- package/src/components/tooltip/tooltip-content.tsx +179 -0
- package/src/components/tooltip/tooltip-description.tsx +19 -0
- package/src/components/tooltip/tooltip-text.tsx +21 -0
- package/src/components/tooltip/tooltip-title.tsx +20 -0
- package/src/components/tooltip/tooltip-trigger.tsx +103 -0
- package/src/components/tooltip/tooltip.context.tsx +68 -0
- package/src/components/tooltip/tooltip.tsx +213 -0
- package/src/components/tooltip/tooltip.variants.test.ts +231 -0
- package/src/components/tooltip/tooltip.variants.ts +177 -0
- package/src/hooks/use-calm-motion.tsx +31 -0
- package/src/lib/calm-motion.test.ts +17 -0
- package/src/lib/calm-motion.ts +23 -0
- package/src/lib/cn.parity.test.ts +62 -0
- package/src/lib/cn.test.ts +14 -0
- package/src/lib/cn.ts +11 -6
- package/src/no-gorhom.test.ts +54 -0
- package/src/styles/geometry.test.ts +1 -0
- package/src/styles/theme.css +4 -0
- package/src/styles/tokens.css +44 -0
- package/src/styles/tokens.test.ts +56 -0
- package/src/styles/tokens.ts +29 -1
- package/src/components/bottom-sheet/bottom-sheet-portal.tsx +0 -72
- package/src/components/bottom-sheet/bottom-sheet.context.tsx +0 -135
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { type ReactElement, useEffect } from "react";
|
|
2
|
+
import { View, type ViewProps } from "react-native";
|
|
3
|
+
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
|
|
4
|
+
import { useMeterPart } from "./meter.context";
|
|
5
|
+
import { METER_SEGMENT_FADE_MS, type MeterColor, type MeterSize, meterVariants } from "./meter.variants";
|
|
6
|
+
|
|
7
|
+
export type MeterSegmentsProps = Omit<ViewProps, "children"> & {
|
|
8
|
+
/** Extra classes for every block. */
|
|
9
|
+
segmentClassName?: string;
|
|
10
|
+
/** Extra classes for a lit block's painted layer. */
|
|
11
|
+
fillClassName?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type MeterSegmentProps = {
|
|
15
|
+
isLit: boolean;
|
|
16
|
+
color: MeterColor;
|
|
17
|
+
size: MeterSize;
|
|
18
|
+
className?: string;
|
|
19
|
+
fillClassName?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* One block: an unlit groove with its lit layer fading over it.
|
|
24
|
+
*
|
|
25
|
+
* The layer is seeded at its current state, so a meter mounting at three of
|
|
26
|
+
* four does not replay the lighting on every row that scrolls in. The timing
|
|
27
|
+
* takes Reanimated's default reduce-motion policy, so with the system setting on
|
|
28
|
+
* a block lights without a fade — nothing here needs to stay moving to be read.
|
|
29
|
+
*/
|
|
30
|
+
function MeterSegment({ isLit, color, size, className, fillClassName }: MeterSegmentProps): ReactElement {
|
|
31
|
+
const opacity = useSharedValue(isLit ? 1 : 0);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
opacity.value = withTiming(isLit ? 1 : 0, { duration: METER_SEGMENT_FADE_MS });
|
|
35
|
+
}, [isLit, opacity]);
|
|
36
|
+
|
|
37
|
+
const fillStyle = useAnimatedStyle(() => ({ opacity: opacity.value }));
|
|
38
|
+
const slots = meterVariants({ color, size });
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<View className={slots.segment({ className })}>
|
|
42
|
+
<Animated.View className={slots.segmentFill({ className: fillClassName })} style={fillStyle} />
|
|
43
|
+
</View>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
MeterSegment.displayName = "DelacourUI.Meter.Segments.Segment";
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The scale drawn as discrete blocks — the segmented meter's track and fill in one.
|
|
50
|
+
*
|
|
51
|
+
* Draws the count the root was given as `segments`, lighting whole blocks only:
|
|
52
|
+
* four blocks say "three out of four" where a bar says "about seventy percent".
|
|
53
|
+
* With no count on the root it draws nothing, because there is no scale to cut.
|
|
54
|
+
*/
|
|
55
|
+
export function MeterSegments({
|
|
56
|
+
className,
|
|
57
|
+
segmentClassName,
|
|
58
|
+
fillClassName,
|
|
59
|
+
...props
|
|
60
|
+
}: MeterSegmentsProps): ReactElement | null {
|
|
61
|
+
const { size, renderProps } = useMeterPart("Meter.Segments");
|
|
62
|
+
const { segments, litSegments, color } = renderProps;
|
|
63
|
+
|
|
64
|
+
if (segments === null) return null;
|
|
65
|
+
|
|
66
|
+
const blocks = Array.from({ length: segments }, (_, index) => index);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<View className={meterVariants({ color, size }).segments({ className })} {...props}>
|
|
70
|
+
{blocks.map((index) => (
|
|
71
|
+
<MeterSegment
|
|
72
|
+
className={segmentClassName}
|
|
73
|
+
color={color}
|
|
74
|
+
fillClassName={fillClassName}
|
|
75
|
+
isLit={index < litSegments}
|
|
76
|
+
key={index}
|
|
77
|
+
size={size}
|
|
78
|
+
/>
|
|
79
|
+
))}
|
|
80
|
+
</View>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
MeterSegments.displayName = "DelacourUI.Meter.Segments";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import { Progress, type ProgressTrackProps } from "../progress";
|
|
3
|
+
import { useMeterPart } from "./meter.context";
|
|
4
|
+
|
|
5
|
+
export type MeterTrackProps = ProgressTrackProps;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The continuous groove the fill slides along — the progress bar's own track.
|
|
9
|
+
*
|
|
10
|
+
* For a segmented meter write `Meter.Segments` instead.
|
|
11
|
+
*/
|
|
12
|
+
export function MeterTrack(props: MeterTrackProps): ReactElement {
|
|
13
|
+
useMeterPart("Meter.Track");
|
|
14
|
+
return <Progress.Track {...props} />;
|
|
15
|
+
}
|
|
16
|
+
MeterTrack.displayName = "DelacourUI.Meter.Track";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createContext, type ReactElement, type ReactNode, use } from "react";
|
|
2
|
+
import type { MeterRenderProps } from "./meter.types";
|
|
3
|
+
import type { MeterSize } from "./meter.variants";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* What a meter's own parts read.
|
|
7
|
+
*
|
|
8
|
+
* The continuous track and fill do not read this — the root also publishes the
|
|
9
|
+
* progress bar's context, and `Meter.Track` and `Meter.Fill` are the progress
|
|
10
|
+
* bar's parts reading that. This holds only what a meter adds: the judged colour,
|
|
11
|
+
* the region and the blocks.
|
|
12
|
+
*/
|
|
13
|
+
export type MeterContextValue = {
|
|
14
|
+
size: MeterSize;
|
|
15
|
+
/** The settled state `Meter.Output` formats and a render function is handed. */
|
|
16
|
+
renderProps: MeterRenderProps;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const MeterContext = createContext<MeterContextValue | null>(null);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Supplies one meter's state to its own parts.
|
|
23
|
+
*
|
|
24
|
+
* Its own module, importing nothing but React and types, so a part can read it
|
|
25
|
+
* without importing `./meter` and closing a cycle.
|
|
26
|
+
*/
|
|
27
|
+
export function MeterProvider({ value, children }: { value: MeterContextValue; children: ReactNode }): ReactElement {
|
|
28
|
+
return <MeterContext value={value}>{children}</MeterContext>;
|
|
29
|
+
}
|
|
30
|
+
MeterProvider.displayName = "DelacourUI.Meter.Provider";
|
|
31
|
+
|
|
32
|
+
/** The enclosing meter's state, or null outside a `<Meter>`. */
|
|
33
|
+
export function useMeterContext(): MeterContextValue | null {
|
|
34
|
+
return use(MeterContext);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Reads the enclosing meter's state.
|
|
39
|
+
*
|
|
40
|
+
* For a custom readout or legend that has to match the meter it sits in. Throws
|
|
41
|
+
* outside one — use {@link useMeterContext} where the meter is optional.
|
|
42
|
+
*/
|
|
43
|
+
export function useMeter(): MeterContextValue {
|
|
44
|
+
const context = useMeterContext();
|
|
45
|
+
if (!context) {
|
|
46
|
+
throw new Error("useMeter must be called inside a <Meter>.");
|
|
47
|
+
}
|
|
48
|
+
return context;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The enclosing meter's state, for a compound part that cannot work without one.
|
|
53
|
+
*
|
|
54
|
+
* Internal: deliberately not re-exported from `index.ts`.
|
|
55
|
+
*/
|
|
56
|
+
export function useMeterPart(component: string): MeterContextValue {
|
|
57
|
+
const context = useMeterContext();
|
|
58
|
+
if (!context) {
|
|
59
|
+
throw new Error(`${component} must be rendered inside a <Meter>.`);
|
|
60
|
+
}
|
|
61
|
+
return context;
|
|
62
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { type ReactElement, type ReactNode, useMemo } from "react";
|
|
2
|
+
import { View, type ViewProps } from "react-native";
|
|
3
|
+
import { useSharedValue } from "react-native-reanimated";
|
|
4
|
+
import { type ProgressContextValue, ProgressProvider, type ProgressRenderProps } from "../progress";
|
|
5
|
+
import {
|
|
6
|
+
formatProgressValue,
|
|
7
|
+
progressRatio,
|
|
8
|
+
progressVariants,
|
|
9
|
+
resolveProgressAccessibility,
|
|
10
|
+
} from "../progress/progress.variants";
|
|
11
|
+
import { type MeterContextValue, MeterProvider } from "./meter.context";
|
|
12
|
+
import type { MeterRenderProps } from "./meter.types";
|
|
13
|
+
import {
|
|
14
|
+
litSegments,
|
|
15
|
+
METER_MAX_VALUE,
|
|
16
|
+
METER_MIN_VALUE,
|
|
17
|
+
type MeterColor,
|
|
18
|
+
type MeterSize,
|
|
19
|
+
type MeterThreshold,
|
|
20
|
+
type MeterValueLabel,
|
|
21
|
+
meterRange,
|
|
22
|
+
meterSegmentCount,
|
|
23
|
+
meterValue,
|
|
24
|
+
resolveMeterAxes,
|
|
25
|
+
resolveMeterColor,
|
|
26
|
+
resolveMeterScale,
|
|
27
|
+
resolveMeterValueLabel,
|
|
28
|
+
} from "./meter.variants";
|
|
29
|
+
import { MeterFill } from "./meter-fill";
|
|
30
|
+
import { MeterHeader } from "./meter-header";
|
|
31
|
+
import { MeterLabel } from "./meter-label";
|
|
32
|
+
import { MeterOutput } from "./meter-output";
|
|
33
|
+
import { MeterSegments } from "./meter-segments";
|
|
34
|
+
import { MeterTrack } from "./meter-track";
|
|
35
|
+
|
|
36
|
+
type MeterBaseProps = Omit<ViewProps, "children"> & {
|
|
37
|
+
/** The reading. Outside the scale it clamps to the nearer end; `NaN` reads at the floor. */
|
|
38
|
+
value: number;
|
|
39
|
+
/** The bottom of the scale — where the meter reads empty. */
|
|
40
|
+
minValue?: number;
|
|
41
|
+
/** The top of the scale — where the meter reads full. */
|
|
42
|
+
maxValue?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Passed to `Intl.NumberFormat` by `Meter.Output` and the spoken value. With
|
|
45
|
+
* none, or a `percent` style, the readout is the share of the scale; any other
|
|
46
|
+
* style formats the reading itself — `168 GB`.
|
|
47
|
+
*/
|
|
48
|
+
formatOptions?: Intl.NumberFormatOptions;
|
|
49
|
+
/**
|
|
50
|
+
* Replaces the formatted readout, on screen and to assistive technology — `Strong`, `Almost full`.
|
|
51
|
+
* A function is handed the judged reading, which is how a region is put into words a screen reader hears.
|
|
52
|
+
*/
|
|
53
|
+
valueLabel?: MeterValueLabel;
|
|
54
|
+
/** The fill's colour on a plain scale, and below every threshold. Ignored when judging by regions. */
|
|
55
|
+
color?: MeterColor;
|
|
56
|
+
size?: MeterSize;
|
|
57
|
+
/** Draw the scale as this many whole blocks instead of one continuous bar. */
|
|
58
|
+
segments?: number;
|
|
59
|
+
/** The anatomy. With none, the meter draws a bare track and fill, or its blocks. */
|
|
60
|
+
children?: ReactNode;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Judge the reading by where it falls against a preferred end or band. */
|
|
64
|
+
type MeterRegionProps = {
|
|
65
|
+
/** Below this is the low part of the scale. Defaults to `minValue`. */
|
|
66
|
+
low?: number;
|
|
67
|
+
/** Above this is the high part of the scale. Defaults to `maxValue`. */
|
|
68
|
+
high?: number;
|
|
69
|
+
/** The best reading. Below `low` means low is good; above `high` means high is good; between, the band is. */
|
|
70
|
+
optimum?: number;
|
|
71
|
+
thresholds?: never;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** Judge the reading by explicit colour changes along the scale. */
|
|
75
|
+
type MeterThresholdProps = {
|
|
76
|
+
/** Points where the colour changes, `{ from, color }`, in the reading's own units. The highest reached wins. */
|
|
77
|
+
thresholds: readonly MeterThreshold[];
|
|
78
|
+
low?: never;
|
|
79
|
+
high?: never;
|
|
80
|
+
optimum?: never;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* A meter judges its reading one of two ways, never both: `low` / `high` /
|
|
85
|
+
* `optimum` regions, or a `thresholds` list. The union makes passing both a type
|
|
86
|
+
* error rather than a precedence rule to remember.
|
|
87
|
+
*/
|
|
88
|
+
export type MeterProps = MeterBaseProps & (MeterRegionProps | MeterThresholdProps);
|
|
89
|
+
|
|
90
|
+
function MeterRoot({
|
|
91
|
+
value: rawValue,
|
|
92
|
+
minValue: rawMinValue = METER_MIN_VALUE,
|
|
93
|
+
maxValue: rawMaxValue = METER_MAX_VALUE,
|
|
94
|
+
formatOptions,
|
|
95
|
+
valueLabel,
|
|
96
|
+
color,
|
|
97
|
+
size,
|
|
98
|
+
segments: rawSegments,
|
|
99
|
+
low,
|
|
100
|
+
high,
|
|
101
|
+
optimum,
|
|
102
|
+
thresholds,
|
|
103
|
+
className,
|
|
104
|
+
children,
|
|
105
|
+
...props
|
|
106
|
+
}: MeterProps): ReactElement {
|
|
107
|
+
const axes = resolveMeterAxes({ color, size });
|
|
108
|
+
const trackSize = useSharedValue(0);
|
|
109
|
+
|
|
110
|
+
const { minValue, maxValue } = meterRange(rawMinValue, rawMaxValue);
|
|
111
|
+
const value = meterValue(rawValue, minValue, maxValue);
|
|
112
|
+
const ratio = progressRatio(value, minValue, maxValue);
|
|
113
|
+
const segments = meterSegmentCount(rawSegments);
|
|
114
|
+
const lit = segments === null ? 0 : litSegments({ count: segments, ratio });
|
|
115
|
+
|
|
116
|
+
const judged = useMemo(
|
|
117
|
+
() =>
|
|
118
|
+
resolveMeterColor({
|
|
119
|
+
color: axes.color,
|
|
120
|
+
maxValue,
|
|
121
|
+
minValue,
|
|
122
|
+
scale: resolveMeterScale({ high, low, optimum, thresholds }),
|
|
123
|
+
value,
|
|
124
|
+
}),
|
|
125
|
+
[axes.color, high, low, maxValue, minValue, optimum, thresholds, value]
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const reading = useMemo(
|
|
129
|
+
() => formatProgressValue({ formatOptions, maxValue, minValue, value }),
|
|
130
|
+
[formatOptions, maxValue, minValue, value]
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const label = useMemo(
|
|
134
|
+
() =>
|
|
135
|
+
resolveMeterValueLabel(valueLabel, {
|
|
136
|
+
color: judged.color,
|
|
137
|
+
formatted: reading,
|
|
138
|
+
maxValue,
|
|
139
|
+
minValue,
|
|
140
|
+
ratio,
|
|
141
|
+
region: judged.region,
|
|
142
|
+
value,
|
|
143
|
+
}),
|
|
144
|
+
[judged.color, judged.region, maxValue, minValue, ratio, reading, value, valueLabel]
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const formatted = label ?? reading;
|
|
148
|
+
|
|
149
|
+
const accessibility = useMemo(
|
|
150
|
+
() =>
|
|
151
|
+
resolveProgressAccessibility({
|
|
152
|
+
formatOptions,
|
|
153
|
+
isIndeterminate: false,
|
|
154
|
+
maxValue,
|
|
155
|
+
minValue,
|
|
156
|
+
value,
|
|
157
|
+
valueLabel: label,
|
|
158
|
+
}),
|
|
159
|
+
[formatOptions, label, maxValue, minValue, value]
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
const renderProps = useMemo<MeterRenderProps>(
|
|
163
|
+
() => ({
|
|
164
|
+
color: judged.color,
|
|
165
|
+
formatted,
|
|
166
|
+
litSegments: lit,
|
|
167
|
+
maxValue,
|
|
168
|
+
minValue,
|
|
169
|
+
ratio,
|
|
170
|
+
region: judged.region,
|
|
171
|
+
segments,
|
|
172
|
+
value,
|
|
173
|
+
}),
|
|
174
|
+
[formatted, judged.color, judged.region, lit, maxValue, minValue, ratio, segments, value]
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const progressRenderProps = useMemo<ProgressRenderProps>(
|
|
178
|
+
() => ({ formatted, isIndeterminate: false, maxValue, minValue, ratio, value }),
|
|
179
|
+
[formatted, maxValue, minValue, ratio, value]
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// The progress bar's track and fill read this shape, so publishing it is what
|
|
183
|
+
// lets `Meter.Track` and `Meter.Fill` be those parts rather than copies.
|
|
184
|
+
const progressContext = useMemo<ProgressContextValue>(
|
|
185
|
+
() => ({
|
|
186
|
+
color: judged.color,
|
|
187
|
+
isIndeterminate: false,
|
|
188
|
+
ratio,
|
|
189
|
+
renderProps: progressRenderProps,
|
|
190
|
+
size: axes.size,
|
|
191
|
+
trackSize,
|
|
192
|
+
}),
|
|
193
|
+
[axes.size, judged.color, progressRenderProps, ratio, trackSize]
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const meterContext = useMemo<MeterContextValue>(() => ({ renderProps, size: axes.size }), [axes.size, renderProps]);
|
|
197
|
+
|
|
198
|
+
// A bare `<Meter value={68} />` draws the scale. A compound root with no
|
|
199
|
+
// default anatomy would draw nothing, which is a failure with no error.
|
|
200
|
+
const content =
|
|
201
|
+
children ??
|
|
202
|
+
(segments === null ? (
|
|
203
|
+
<MeterTrack>
|
|
204
|
+
<MeterFill />
|
|
205
|
+
</MeterTrack>
|
|
206
|
+
) : (
|
|
207
|
+
<MeterSegments />
|
|
208
|
+
));
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<ProgressProvider value={progressContext}>
|
|
212
|
+
<MeterProvider value={meterContext}>
|
|
213
|
+
<View
|
|
214
|
+
accessibilityRole="progressbar"
|
|
215
|
+
accessibilityValue={accessibility.value}
|
|
216
|
+
accessible
|
|
217
|
+
className={progressVariants({ size: axes.size }).root({ className })}
|
|
218
|
+
{...props}
|
|
219
|
+
>
|
|
220
|
+
{content}
|
|
221
|
+
</View>
|
|
222
|
+
</MeterProvider>
|
|
223
|
+
</ProgressProvider>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* A measurement on a fixed scale, coloured by where it falls — storage used, a
|
|
229
|
+
* battery's charge, a password's strength.
|
|
230
|
+
*
|
|
231
|
+
* A progress bar says how far a task has got; a meter says what a quantity *is*,
|
|
232
|
+
* and its colour is a judgement about that. Judge it one of two ways:
|
|
233
|
+
*
|
|
234
|
+
* - **`low`, `high` and `optimum`** split the scale into a good region, the one
|
|
235
|
+
* next to it and the far side of that, painted success, warning and
|
|
236
|
+
* destructive. `optimum` says which end is good — below `low` for a disk,
|
|
237
|
+
* above `high` for a battery, between them for a temperature.
|
|
238
|
+
* - **`thresholds`** name the colour outright at points along the scale.
|
|
239
|
+
*
|
|
240
|
+
* With neither, the fill is `color`. `segments` draws the scale as whole blocks.
|
|
241
|
+
*
|
|
242
|
+
* The anatomy is the progress bar's — `Meter.Header`, `Meter.Label`,
|
|
243
|
+
* `Meter.Output`, `Meter.Track`, `Meter.Fill` — plus `Meter.Segments`. A bare
|
|
244
|
+
* `<Meter value={68} />` draws the track and fill, or the blocks, on its own.
|
|
245
|
+
*
|
|
246
|
+
* **It is one accessible element with the `progressbar` role**, the scale and
|
|
247
|
+
* the reading published as `accessibilityValue` and a `Meter.Label` as its name.
|
|
248
|
+
* Colour is never the only signal: put the judgement into words with a
|
|
249
|
+
* `valueLabel` function reading `region` — it is spoken as well as drawn.
|
|
250
|
+
*
|
|
251
|
+
* It is not a control, so there is no disabled, invalid or loading state — a
|
|
252
|
+
* reading that is not known yet is a progress bar's indeterminate loop, not a
|
|
253
|
+
* meter.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* <Meter value={68} />
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* <Meter value={231} maxValue={256} low={192} high={240} optimum={0} formatOptions={{ style: "unit", unit: "gigabyte" }}>
|
|
260
|
+
* <Meter.Header>
|
|
261
|
+
* <Meter.Label>Storage</Meter.Label>
|
|
262
|
+
* <Meter.Output />
|
|
263
|
+
* </Meter.Header>
|
|
264
|
+
* <Meter.Track>
|
|
265
|
+
* <Meter.Fill />
|
|
266
|
+
* </Meter.Track>
|
|
267
|
+
* </Meter>
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* <Meter accessibilityLabel="Password strength" segments={4} value={3} maxValue={4} valueLabel="Good" />
|
|
271
|
+
*/
|
|
272
|
+
export const Meter = Object.assign(MeterRoot, {
|
|
273
|
+
/** The row above the scale: a label at the start, a readout at the end. */
|
|
274
|
+
Header: MeterHeader,
|
|
275
|
+
/** What is being measured. Read as the meter's accessible name. */
|
|
276
|
+
Label: MeterLabel,
|
|
277
|
+
/** The reading, formatted. Give it a function to word it — or its region — yourself. */
|
|
278
|
+
Output: MeterOutput,
|
|
279
|
+
/** The continuous groove the fill slides along. */
|
|
280
|
+
Track: MeterTrack,
|
|
281
|
+
/** The painted bar, in the judged colour. */
|
|
282
|
+
Fill: MeterFill,
|
|
283
|
+
/** The scale as whole blocks, for a meter given `segments`. */
|
|
284
|
+
Segments: MeterSegments,
|
|
285
|
+
displayName: "DelacourUI.Meter",
|
|
286
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { MeterColor, MeterRegion } from "./meter.variants";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* What a render function inside a meter is handed.
|
|
6
|
+
*
|
|
7
|
+
* Shared by the root's context and `Meter.Output`, which is what puts it here
|
|
8
|
+
* rather than in either one's own file. See AGENTS.md.
|
|
9
|
+
*/
|
|
10
|
+
export type MeterRenderProps = {
|
|
11
|
+
/** The reading, clamped to the scale. */
|
|
12
|
+
value: number;
|
|
13
|
+
minValue: number;
|
|
14
|
+
maxValue: number;
|
|
15
|
+
/** Where the reading sits on the scale, 0–1. */
|
|
16
|
+
ratio: number;
|
|
17
|
+
/** The readout's default text: `valueLabel`, or the formatted reading. */
|
|
18
|
+
formatted: string;
|
|
19
|
+
/** The colour the reading was judged to be. */
|
|
20
|
+
color: MeterColor;
|
|
21
|
+
/** The region the reading falls in, when the meter was given `low`, `high` or `optimum`. */
|
|
22
|
+
region: MeterRegion | null;
|
|
23
|
+
/** How many blocks a segmented meter draws, or `null` for the continuous bar. */
|
|
24
|
+
segments: number | null;
|
|
25
|
+
/** How many of those blocks are lit. `0` on the continuous bar. */
|
|
26
|
+
litSegments: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** A part whose children may be written out or computed from the meter's state. */
|
|
30
|
+
export type MeterRenderChildren = ReactNode | ((props: MeterRenderProps) => ReactNode);
|