@delacour/react-native-ui 0.1.0-alpha.4 → 0.1.0
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 +48 -4
- 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 +5 -0
- package/src/components/badge/badge.tsx +6 -1
- 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 +45 -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 +2 -1
- package/src/components/button/button.variants.test.ts +154 -0
- package/src/components/button/button.variants.ts +71 -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 +88 -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 +94 -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/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 +72 -0
- package/src/components/surface/index.ts +15 -0
- package/src/components/surface/surface.context.tsx +54 -0
- package/src/components/surface/surface.tsx +70 -0
- package/src/components/surface/surface.variants.test.ts +180 -0
- package/src/components/surface/surface.variants.ts +133 -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/textarea/AGENTS.md +86 -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.test.ts +14 -0
- package/src/lib/cn.ts +2 -2
- 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 +11 -0
- package/src/styles/tokens.test.ts +22 -0
- package/src/styles/tokens.ts +20 -0
- package/src/components/bottom-sheet/bottom-sheet-portal.tsx +0 -72
- package/src/components/bottom-sheet/bottom-sheet.context.tsx +0 -135
|
@@ -13,45 +13,23 @@ export const BOTTOM_SHEET_OVERLAY_TOKEN = "overlay";
|
|
|
13
13
|
/**
|
|
14
14
|
* The backdrop's opacity at full appearance.
|
|
15
15
|
*
|
|
16
|
-
* **1
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* **1.** The alpha lives in `--overlay`, so any other number here would multiply
|
|
17
|
+
* against it and land the scrim somewhere the theme did not ask for. One source
|
|
18
|
+
* for the alpha, and it is the token — which is also what lets the two theme
|
|
19
|
+
* variants differ.
|
|
20
20
|
*/
|
|
21
21
|
export const BOTTOM_SHEET_OVERLAY_OPACITY = 1;
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* The snap indices the scrim appears and disappears on.
|
|
24
|
+
* The snap point indices the scrim appears and disappears on.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* is only absent when the sheet is closed (`-1`).
|
|
26
|
+
* A modal sheet has no resting state: it is either presented or gone, so the
|
|
27
|
+
* scrim belongs from the FIRST snap point (`0`) and is only absent when the sheet
|
|
28
|
+
* is closed (`-1`). These are the engine's own defaults too; they are named
|
|
29
|
+
* here so the test that pins them has something to read.
|
|
31
30
|
*/
|
|
32
31
|
export const BOTTOM_SHEET_BACKDROP_INDICES = { appearsOnIndex: 0, disappearsOnIndex: -1 } as const;
|
|
33
32
|
|
|
34
|
-
/**
|
|
35
|
-
* Keyboard behaviour every `BottomSheet.Container` starts from.
|
|
36
|
-
*
|
|
37
|
-
* A const rather than three defaults spelled inline, so `bun test` pins them and
|
|
38
|
-
* a retune is one edit rather than three.
|
|
39
|
-
*
|
|
40
|
-
* - `interactive` — the sheet grows to keep its content above the keyboard,
|
|
41
|
-
* following it frame by frame rather than snapping once it has settled.
|
|
42
|
-
* - `restore` — blurring returns the sheet to the snap point it was on. Without
|
|
43
|
-
* it a sheet that grew for the keyboard stays grown over empty screen.
|
|
44
|
-
* - `adjustResize` — gorhom's own default is `adjustPan`, which leaves the
|
|
45
|
-
* Android window height alone and slides the whole view up, so a sheet's
|
|
46
|
-
* footer lands off-screen. `resize` is already what Expo configures and what
|
|
47
|
-
* `KeyboardProvider` requires, so this is the value that matches the window.
|
|
48
|
-
*/
|
|
49
|
-
export const BOTTOM_SHEET_KEYBOARD_DEFAULTS = {
|
|
50
|
-
keyboardBehavior: "interactive",
|
|
51
|
-
keyboardBlurBehavior: "restore",
|
|
52
|
-
android_keyboardInputMode: "adjustResize",
|
|
53
|
-
} as const;
|
|
54
|
-
|
|
55
33
|
/**
|
|
56
34
|
* Slop around `BottomSheet.Close`.
|
|
57
35
|
*
|
|
@@ -62,22 +40,23 @@ export const BOTTOM_SHEET_KEYBOARD_DEFAULTS = {
|
|
|
62
40
|
export const BOTTOM_SHEET_CLOSE_HIT_SLOP = 8;
|
|
63
41
|
|
|
64
42
|
/**
|
|
65
|
-
* The padding a pinned footer
|
|
43
|
+
* The padding a pinned footer's measured box carries.
|
|
66
44
|
*
|
|
67
|
-
* A number rather than a `p-4`,
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
45
|
+
* A number rather than a `p-4`, because it is handed to the engine's `padding`
|
|
46
|
+
* prop: the engine measures the footer's inner box into the dynamic snap point,
|
|
47
|
+
* and padding written there is counted where a class on the outer view would
|
|
48
|
+
* not be. The horizontal gutter still comes from the `stickyFooter` slot, which
|
|
49
|
+
* is merged after it.
|
|
71
50
|
*/
|
|
72
51
|
export const BOTTOM_SHEET_FOOTER_PADDING = 16;
|
|
73
52
|
|
|
74
53
|
/**
|
|
75
54
|
* The gap between the last of the content and a pinned footer.
|
|
76
55
|
*
|
|
77
|
-
* Also a number, because the
|
|
78
|
-
* the footer's measured height. Without it the last
|
|
79
|
-
* against the footer's hairline, which reads as content
|
|
80
|
-
* content ended.
|
|
56
|
+
* Also a number, because it is the engine's `footerGap` — added to the spacer it
|
|
57
|
+
* reserves under the body from the footer's measured height. Without it the last
|
|
58
|
+
* row of a list sits flush against the footer's hairline, which reads as content
|
|
59
|
+
* clipped rather than content ended.
|
|
81
60
|
*/
|
|
82
61
|
export const BOTTOM_SHEET_FOOTER_GAP = 16;
|
|
83
62
|
|
|
@@ -85,7 +64,7 @@ export const bottomSheetVariants = tv({
|
|
|
85
64
|
slots: {
|
|
86
65
|
/**
|
|
87
66
|
* The scrim. Carries the colour and nothing else — the fade is an animated
|
|
88
|
-
* opacity
|
|
67
|
+
* opacity the engine drives off the sheet's own index.
|
|
89
68
|
*/
|
|
90
69
|
overlay: "bg-overlay",
|
|
91
70
|
/**
|
|
@@ -94,7 +73,8 @@ export const bottomSheetVariants = tv({
|
|
|
94
73
|
* surface token nothing else in the package had claimed.
|
|
95
74
|
*
|
|
96
75
|
* Only the top corners round. The bottom edge runs off the screen, and a
|
|
97
|
-
* radius there shows as two notches of the app behind it.
|
|
76
|
+
* radius there shows as two notches of the app behind it. The `detached`
|
|
77
|
+
* variant is the exception — a floating card has a visible bottom edge.
|
|
98
78
|
*/
|
|
99
79
|
background: "rounded-t-2xl bg-popover",
|
|
100
80
|
handle: "items-center justify-center pt-3 pb-1",
|
|
@@ -102,6 +82,14 @@ export const bottomSheetVariants = tv({
|
|
|
102
82
|
content: "gap-4 px-screen-gutter pt-2",
|
|
103
83
|
/** A scrollable body's content container. Same treatment as `content`. */
|
|
104
84
|
scrollContent: "gap-4 px-screen-gutter pt-2",
|
|
85
|
+
/**
|
|
86
|
+
* A multi-step body. The gutter only: the engine measures each `Step`, not
|
|
87
|
+
* the box around the stack, so vertical padding here would be height the
|
|
88
|
+
* sheet never counts.
|
|
89
|
+
*/
|
|
90
|
+
steps: "px-screen-gutter",
|
|
91
|
+
/** One step of a multi-step body — `content` less the gutter `steps` already carries. */
|
|
92
|
+
step: "gap-4 pt-2",
|
|
105
93
|
footer: "gap-3 px-screen-gutter pt-4",
|
|
106
94
|
/**
|
|
107
95
|
* A pinned footer draws OVER the content, so unlike the inline one it has
|
|
@@ -110,9 +98,8 @@ export const bottomSheetVariants = tv({
|
|
|
110
98
|
* to overlap blank space. The same reason `Screen.Footer`'s backing lives
|
|
111
99
|
* inside its sticky view.
|
|
112
100
|
*
|
|
113
|
-
* It carries no vertical padding: that is
|
|
114
|
-
*
|
|
115
|
-
* {@link BOTTOM_SHEET_FOOTER_PADDING}.
|
|
101
|
+
* It carries no vertical padding: that is the engine's `padding` prop, so
|
|
102
|
+
* the measured box counts it. See {@link BOTTOM_SHEET_FOOTER_PADDING}.
|
|
116
103
|
*/
|
|
117
104
|
stickyFooter: "gap-3 border-border border-t bg-popover px-screen-gutter",
|
|
118
105
|
close: "absolute top-4 right-4 z-10",
|
|
@@ -131,90 +118,27 @@ export const bottomSheetVariants = tv({
|
|
|
131
118
|
*/
|
|
132
119
|
title: "pr-8",
|
|
133
120
|
},
|
|
121
|
+
variants: {
|
|
122
|
+
/**
|
|
123
|
+
* A floating card. Every corner is on screen, so every corner rounds;
|
|
124
|
+
* `rounded-2xl` replaces `rounded-t-2xl` through tailwind-merge rather
|
|
125
|
+
* than stacking beside it.
|
|
126
|
+
*/
|
|
127
|
+
detached: {
|
|
128
|
+
true: {
|
|
129
|
+
background: "rounded-2xl",
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
134
133
|
});
|
|
135
134
|
|
|
136
135
|
/**
|
|
137
|
-
* There is no `description` or `scrollView` slot.
|
|
136
|
+
* There is no `description`, `panel`, `portal` or `scrollView` slot.
|
|
138
137
|
*
|
|
139
|
-
*
|
|
140
|
-
* gap column
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* caller's `className` with `cn()` instead.
|
|
138
|
+
* None has any layout of its own — a description is a `Text.Paragraph` in a
|
|
139
|
+
* gap column, the panel is a transparent frame the engine positions, a scroll
|
|
140
|
+
* view fills whatever it is given — and `tv` emits `undefined` for a slot whose
|
|
141
|
+
* class string is empty, so a slot that says nothing is a slot no test can
|
|
142
|
+
* assert against. Those parts merge the caller's `className` with `cn()` instead.
|
|
144
143
|
*/
|
|
145
144
|
export type BottomSheetVariantProps = VariantProps<typeof bottomSheetVariants>;
|
|
146
|
-
|
|
147
|
-
/** Where a `BottomSheet.Footer` among a container's children has to be rendered. */
|
|
148
|
-
export type BottomSheetFooterPlacement = "sticky" | "inline" | "none";
|
|
149
|
-
|
|
150
|
-
/** One child of a `BottomSheet.Container`, reduced to what the placement turns on. */
|
|
151
|
-
export type BottomSheetFooterFlag = {
|
|
152
|
-
isFooter: boolean;
|
|
153
|
-
isSticky: boolean;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Whether a container's children hold a footer, and where it has to go.
|
|
158
|
-
*
|
|
159
|
-
* gorhom takes a footer as a `footerComponent` render prop rather than as a
|
|
160
|
-
* child, so a sticky one has to be lifted out of the tree it was written in and
|
|
161
|
-
* handed over; an inline one simply stays put. This is the decision, kept pure
|
|
162
|
-
* so `bun test` reaches the whole matrix — the walk over `Children.toArray` that
|
|
163
|
-
* produces the flags lives with its caller, the way `withIndicator` does in
|
|
164
|
-
* `radio.tsx`.
|
|
165
|
-
*
|
|
166
|
-
* A single sticky footer anywhere in the children wins, because two footers is
|
|
167
|
-
* not a state worth expressing and the pinned one is the one a caller meant.
|
|
168
|
-
*/
|
|
169
|
-
export function resolveFooterPlacement(flags: readonly BottomSheetFooterFlag[]): BottomSheetFooterPlacement {
|
|
170
|
-
let hasFooter = false;
|
|
171
|
-
|
|
172
|
-
for (const flag of flags) {
|
|
173
|
-
if (!flag.isFooter) continue;
|
|
174
|
-
if (flag.isSticky) return "sticky";
|
|
175
|
-
hasFooter = true;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return hasFooter ? "inline" : "none";
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* The safe-area band `BottomSheet.Content` and `BottomSheet.ScrollView` reserve.
|
|
183
|
-
*
|
|
184
|
-
* Exactly one thing in the sheet pays for the home indicator. A pinned footer is
|
|
185
|
-
* the bottom-most thing there is, and its own box carries the band so its surface
|
|
186
|
-
* reaches the bottom of the screen — gorhom then adds that whole measured height
|
|
187
|
-
* to the content's reserve, so the content asking for the band as well would
|
|
188
|
-
* count it twice and leave a gap the height of the indicator above the footer.
|
|
189
|
-
* With no pinned footer the content IS the bottom-most thing and takes it.
|
|
190
|
-
*/
|
|
191
|
-
export function resolveSheetBottomInset({
|
|
192
|
-
hasStickyFooter,
|
|
193
|
-
bottom,
|
|
194
|
-
}: {
|
|
195
|
-
hasStickyFooter: boolean;
|
|
196
|
-
bottom: number;
|
|
197
|
-
}): number {
|
|
198
|
-
return hasStickyFooter ? 0 : bottom;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* The padding at the end of `BottomSheet.ScrollView`'s content.
|
|
203
|
-
*
|
|
204
|
-
* A scroll view does not reserve a pinned footer the way `BottomSheet.Content`
|
|
205
|
-
* does — its FRAME stops at the footer's top edge instead, so the scroll
|
|
206
|
-
* indicator and the overscroll bounce end there too rather than running on
|
|
207
|
-
* underneath it. That leaves the content only the gap to hold it off the
|
|
208
|
-
* footer's hairline. With no pinned footer the content is the bottom-most thing
|
|
209
|
-
* in the sheet and takes the safe-area band, as {@link resolveSheetBottomInset}
|
|
210
|
-
* has it.
|
|
211
|
-
*/
|
|
212
|
-
export function resolveSheetScrollEndPadding({
|
|
213
|
-
hasStickyFooter,
|
|
214
|
-
bottom,
|
|
215
|
-
}: {
|
|
216
|
-
hasStickyFooter: boolean;
|
|
217
|
-
bottom: number;
|
|
218
|
-
}): number {
|
|
219
|
-
return hasStickyFooter ? BOTTOM_SHEET_FOOTER_GAP : resolveSheetBottomInset({ bottom, hasStickyFooter });
|
|
220
|
-
}
|
|
@@ -1,40 +1,62 @@
|
|
|
1
|
-
export { BottomSheet, type BottomSheetProps } from "./bottom-sheet";
|
|
2
1
|
export {
|
|
3
|
-
type
|
|
4
|
-
BottomSheetContainerProvider,
|
|
2
|
+
type BottomSheetAnimatedValue,
|
|
5
3
|
type BottomSheetContextValue,
|
|
6
|
-
type
|
|
7
|
-
type
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
type BottomSheetHostProps,
|
|
5
|
+
type BottomSheetPortalProps,
|
|
6
|
+
type BottomSheetRef,
|
|
7
|
+
type BottomSheetRegistryValue,
|
|
8
|
+
type BottomSheetTextInputHandlers,
|
|
9
|
+
defineSheetMachine,
|
|
10
|
+
type SheetEvent,
|
|
11
|
+
type SheetMachine,
|
|
12
|
+
type SheetMachineConfig,
|
|
13
|
+
type SheetMachineSnapshot,
|
|
14
|
+
type SheetStepController,
|
|
15
|
+
type SheetStepTransition,
|
|
10
16
|
useBottomSheet,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
useBottomSheetAnimated,
|
|
18
|
+
useBottomSheetRegistry,
|
|
19
|
+
useBottomSheetTextInput,
|
|
20
|
+
useOptionalBottomSheet,
|
|
21
|
+
useOptionalBottomSheet as useBottomSheetContext,
|
|
22
|
+
useSheetMachine,
|
|
23
|
+
useSheetStep,
|
|
24
|
+
} from "@delacour/react-native-bottom-sheet";
|
|
25
|
+
export { resolveSheetBottomInset, resolveSheetScrollEndPadding } from "@delacour/react-native-bottom-sheet/core";
|
|
26
|
+
export { BottomSheet, type BottomSheetProps } from "./bottom-sheet";
|
|
15
27
|
export {
|
|
16
28
|
BOTTOM_SHEET_BACKDROP_INDICES,
|
|
17
29
|
BOTTOM_SHEET_CLOSE_HIT_SLOP,
|
|
18
30
|
BOTTOM_SHEET_FOOTER_GAP,
|
|
19
31
|
BOTTOM_SHEET_FOOTER_PADDING,
|
|
20
|
-
BOTTOM_SHEET_KEYBOARD_DEFAULTS,
|
|
21
32
|
BOTTOM_SHEET_OVERLAY_OPACITY,
|
|
22
33
|
BOTTOM_SHEET_OVERLAY_TOKEN,
|
|
23
|
-
type BottomSheetFooterFlag,
|
|
24
|
-
type BottomSheetFooterPlacement,
|
|
25
34
|
type BottomSheetVariantProps,
|
|
26
35
|
bottomSheetVariants,
|
|
27
|
-
resolveFooterPlacement,
|
|
28
|
-
resolveSheetBottomInset,
|
|
29
36
|
} from "./bottom-sheet.variants";
|
|
37
|
+
export type { BottomSheetBackgroundProps } from "./bottom-sheet-background";
|
|
30
38
|
export type { BottomSheetCloseProps } from "./bottom-sheet-close";
|
|
31
39
|
export type { BottomSheetContainerProps } from "./bottom-sheet-container";
|
|
32
40
|
export type { BottomSheetContentProps } from "./bottom-sheet-content";
|
|
33
41
|
export type { BottomSheetDescriptionProps } from "./bottom-sheet-description";
|
|
42
|
+
export type { BottomSheetFlatListProps } from "./bottom-sheet-flat-list";
|
|
34
43
|
export type { BottomSheetFooterProps } from "./bottom-sheet-footer";
|
|
44
|
+
export type { BottomSheetHandleProps } from "./bottom-sheet-handle";
|
|
45
|
+
export type { BottomSheetLegendListProps } from "./bottom-sheet-legend-list";
|
|
35
46
|
export type { BottomSheetOverlayProps } from "./bottom-sheet-overlay";
|
|
36
|
-
export type
|
|
47
|
+
export { BottomSheetProvider, type BottomSheetProviderProps } from "./bottom-sheet-provider";
|
|
37
48
|
export type { BottomSheetScrollViewProps } from "./bottom-sheet-scroll-view";
|
|
49
|
+
export type { BottomSheetSectionListProps } from "./bottom-sheet-section-list";
|
|
50
|
+
export type { BottomSheetStepProps, BottomSheetStepsProps } from "./bottom-sheet-steps";
|
|
51
|
+
export type { BottomSheetTextInputProps } from "./bottom-sheet-text-input";
|
|
38
52
|
export type { BottomSheetTitleProps } from "./bottom-sheet-title";
|
|
39
53
|
export type { BottomSheetTriggerProps } from "./bottom-sheet-trigger";
|
|
40
54
|
export { type BottomSheetInputHandlers, useBottomSheetInput } from "./use-bottom-sheet-input";
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The imperative handle a `BottomSheet` ref exposes.
|
|
58
|
+
*
|
|
59
|
+
* @deprecated The engine's name is `BottomSheetRef`; this alias stays for the
|
|
60
|
+
* callers that typed the old name and goes with the next major.
|
|
61
|
+
*/
|
|
62
|
+
export type BottomSheetHandle = import("@delacour/react-native-bottom-sheet").BottomSheetRef;
|
|
@@ -1,125 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type RefCallback, useCallback, useRef } from "react";
|
|
3
|
-
import { type BlurEvent, type FocusEvent, findNodeHandle, TextInput } from "react-native";
|
|
1
|
+
import { type BottomSheetTextInputHandlers, useBottomSheetTextInput } from "@delacour/react-native-bottom-sheet";
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
* `findNodeHandle` for a value React Native's own types do not admit.
|
|
7
|
-
*
|
|
8
|
-
* `TextInput.State.currentlyFocusedInput()` returns a Fabric host instance, and
|
|
9
|
-
* the shipped signature still describes the pre-Fabric parameter — the runtime
|
|
10
|
-
* accepts it, which is what gorhom's own `BottomSheetTextInput` relies on. One
|
|
11
|
-
* cast, in one place, rather than at each call.
|
|
12
|
-
*/
|
|
13
|
-
function nodeHandleOf(instance: unknown): number | null {
|
|
14
|
-
return findNodeHandle(instance as Parameters<typeof findNodeHandle>[0]);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type BottomSheetInputHandlers = {
|
|
18
|
-
onFocus: (event: FocusEvent) => void;
|
|
19
|
-
onBlur: (event: BlurEvent) => void;
|
|
20
|
-
ref: RefCallback<TextInput | null>;
|
|
21
|
-
};
|
|
3
|
+
export type BottomSheetInputHandlers = BottomSheetTextInputHandlers;
|
|
22
4
|
|
|
23
5
|
/**
|
|
24
|
-
*
|
|
6
|
+
* Registers a text field as the sheet's own, so the keyboard it raises is the
|
|
7
|
+
* sheet's to lift for.
|
|
25
8
|
*
|
|
26
|
-
*
|
|
9
|
+
* The engine's `useBottomSheetTextInput()` under the name this library shipped
|
|
10
|
+
* it as. Spread the result onto any `Input` or `TextInput`:
|
|
27
11
|
*
|
|
28
12
|
* ```tsx
|
|
29
|
-
*
|
|
13
|
+
* const sheetInput = useBottomSheetInput();
|
|
14
|
+
* <Input {...sheetInput} placeholder="Name" />
|
|
30
15
|
* ```
|
|
31
16
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* sheet
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* Three props, and all three are load-bearing:
|
|
17
|
+
* All three handlers matter: `ref` puts the field's native node in the sheet's
|
|
18
|
+
* registry, `onFocus` claims the keyboard, and `onBlur` gives it up — unless
|
|
19
|
+
* focus moved to another registered field in the same sheet, which is what
|
|
20
|
+
* keeps a tap from one field to the next from reading as a close and a reopen.
|
|
21
|
+
* Outside a sheet the handlers are inert, so a form shared between a screen
|
|
22
|
+
* and a sheet needs no branch.
|
|
40
23
|
*
|
|
41
|
-
*
|
|
42
|
-
* focus from one field in the sheet to the next reads as the keyboard closing
|
|
43
|
-
* and reopening, and the sheet resizes twice on the way.
|
|
44
|
-
* - `onFocus` tells the sheet which field to keep clear of the keyboard.
|
|
45
|
-
* - `onBlur` gives that up again, unless focus went to another field in the same
|
|
46
|
-
* sheet.
|
|
47
|
-
*
|
|
48
|
-
* Called outside a sheet it returns inert handlers rather than throwing, so a
|
|
49
|
-
* form component shared between a screen and a sheet needs no branch.
|
|
50
|
-
*
|
|
51
|
-
* It covers the keyboard half only. A *drag* across a field can still be claimed
|
|
52
|
-
* by the sheet's content pan, because gorhom's input is built on Gesture
|
|
53
|
-
* Handler's `TextInput` and this one is not; if that ever bites, the fix is
|
|
54
|
-
* `enableContentPanningGesture={false}` on the `BottomSheet.Container`. The
|
|
55
|
-
* *tap* half — a scrim that used to swallow the press meant for the field — is
|
|
56
|
-
* solved in `BottomSheet.Overlay`, not here.
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* <Field>
|
|
60
|
-
* <Field.Label>Name</Field.Label>
|
|
61
|
-
* <Input {...useBottomSheetInput()} onChangeText={setName} value={name} />
|
|
62
|
-
* </Field>
|
|
24
|
+
* `BottomSheet.TextInput` is this over `Input`, for the plain case.
|
|
63
25
|
*/
|
|
64
|
-
export
|
|
65
|
-
const internal = useBottomSheetInternal(true);
|
|
66
|
-
// The node this field last registered, so the ref can withdraw exactly it.
|
|
67
|
-
// A JS ref rather than a shared value: nothing renders differently for it.
|
|
68
|
-
const registeredNodeRef = useRef<number | null>(null);
|
|
69
|
-
|
|
70
|
-
const ref = useCallback<RefCallback<TextInput | null>>(
|
|
71
|
-
(instance) => {
|
|
72
|
-
const nodes = internal?.textInputNodesRef.current;
|
|
73
|
-
const previous = registeredNodeRef.current;
|
|
74
|
-
|
|
75
|
-
if (previous !== null) {
|
|
76
|
-
nodes?.delete(previous);
|
|
77
|
-
registeredNodeRef.current = null;
|
|
78
|
-
if (internal !== null && internal.animatedKeyboardState.get().target === previous) {
|
|
79
|
-
internal.animatedKeyboardState.set((state) => ({ ...state, target: undefined }));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (instance === null || nodes === undefined) return;
|
|
84
|
-
|
|
85
|
-
const node = nodeHandleOf(instance);
|
|
86
|
-
if (node === null) return;
|
|
87
|
-
|
|
88
|
-
nodes.add(node);
|
|
89
|
-
registeredNodeRef.current = node;
|
|
90
|
-
},
|
|
91
|
-
[internal]
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const onFocus = useCallback(
|
|
95
|
-
(event: FocusEvent) => {
|
|
96
|
-
if (internal === null) return;
|
|
97
|
-
const target = event.nativeEvent.target;
|
|
98
|
-
internal.animatedKeyboardState.set((state) => ({ ...state, target }));
|
|
99
|
-
},
|
|
100
|
-
[internal]
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
const onBlur = useCallback(
|
|
104
|
-
(event: BlurEvent) => {
|
|
105
|
-
if (internal === null) return;
|
|
106
|
-
|
|
107
|
-
const target = event.nativeEvent.target;
|
|
108
|
-
const isThisFieldsTarget = internal.animatedKeyboardState.get().target === target;
|
|
109
|
-
if (!isThisFieldsTarget) return;
|
|
110
|
-
|
|
111
|
-
// React Native's own focus registry, not the sheet's: focus may already
|
|
112
|
-
// have moved to the next field in the same sheet, and giving the target
|
|
113
|
-
// up there would close and reopen the sheet's keyboard allowance between
|
|
114
|
-
// two taps that never dismissed the keyboard.
|
|
115
|
-
const focused = TextInput.State.currentlyFocusedInput();
|
|
116
|
-
const focusedNode = focused === null ? null : nodeHandleOf(focused);
|
|
117
|
-
if (focusedNode !== null && internal.textInputNodesRef.current.has(focusedNode)) return;
|
|
118
|
-
|
|
119
|
-
internal.animatedKeyboardState.set((state) => ({ ...state, target: undefined }));
|
|
120
|
-
},
|
|
121
|
-
[internal]
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
return { onBlur, onFocus, ref };
|
|
125
|
-
}
|
|
26
|
+
export const useBottomSheetInput: () => BottomSheetInputHandlers = useBottomSheetTextInput;
|
|
@@ -194,20 +194,54 @@ for a chunk that says something rather than doing something. An
|
|
|
194
194
|
- **The group paints nothing.** No background, no border, no disabled fade. A
|
|
195
195
|
disabled group publishes `isDisabled` and each member fades itself; a group
|
|
196
196
|
fading as well would compound the two down to a quarter opacity. It carries no
|
|
197
|
-
`gap`
|
|
198
|
-
`overflow-hidden`, which would square off the very corners the position
|
|
197
|
+
`gap` while attached — a gap is the seam this component exists to close — and
|
|
198
|
+
no `overflow-hidden`, which would square off the very corners the position
|
|
199
199
|
compounds just rounded.
|
|
200
200
|
- **No `accessibilityRole` on the group.** Announcing a control with no action
|
|
201
201
|
in front of every member helps nobody; the members are already buttons.
|
|
202
|
-
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
202
|
+
- **`isAttached={false}` shares the props and drops the shape.** A toolbar of
|
|
203
|
+
`Find · Export · Share` wants one `variant` and one `size` without becoming a
|
|
204
|
+
segmented control. Detached, `resolveGroupPositions` places every member
|
|
205
|
+
`only` — the lone member's existing position, which draws the lone button's
|
|
206
|
+
`rounded-button-*` — rather than minting a fourth sentinel, and
|
|
207
|
+
`resolveGroupSeams` returns no seams, so nothing overlaps into the gap. The gap
|
|
208
|
+
is `gap-2` on either axis, a `tv` variant on the `group` slot and never inline.
|
|
209
|
+
`Button.Group.Separator` still renders, as a rule between spaced members.
|
|
210
|
+
- **A detached member presses with `scale` again.** The fade exists only because
|
|
211
|
+
a scaling member tears its seam, and a detached run has none.
|
|
212
|
+
`resolveButtonFeedback` takes `isAttached` as a fourth argument, defaulting to
|
|
213
|
+
`true`, rather than turning into an options object: its positional signature
|
|
214
|
+
is public, `Input` and the existing tests call it, and the new rung is the only
|
|
215
|
+
thing that changed.
|
|
216
|
+
- **`isFullWidth` splits the parent equally, not by content.** A
|
|
217
|
+
`Monthly · Annual · One-off` picker sized to its labels moves its dividers when
|
|
218
|
+
the copy changes, and a wider segment reads as more important. The group trades
|
|
219
|
+
`self-start` for `w-full self-stretch` — declared after `orientation` in
|
|
220
|
+
`buttonVariants`, so tailwind-merge drops `self-start` rather than keeping it —
|
|
221
|
+
and every member of a horizontal run gets `flex-1 basis-0`. **`basis-0` is the
|
|
222
|
+
part that matters**: with `flex-1` alone Yoga shares out only the space left
|
|
223
|
+
after each member's content width, and the widths still follow the labels.
|
|
224
|
+
- **A member learns it stretches from context, as `isStretched`.**
|
|
225
|
+
`resolveGroupMemberStretch` decides it once per group, it rides on the
|
|
226
|
+
per-member context beside `position` and `isSeamed`, and `Button` feeds it to
|
|
227
|
+
an `isStretched` variant on its own `tv`. No `cloneElement`, for the reason
|
|
228
|
+
above. A caller's `className="flex-none"` on one member still wins — the
|
|
229
|
+
variant is merged before the caller's class. `Button.Group.Text` and the
|
|
230
|
+
separator do **not** stretch: a caption and a rule keep their content width
|
|
231
|
+
and the buttons share what is left. `Input` does not read it yet; a caller
|
|
232
|
+
sizes a joined field with its own `className`.
|
|
233
|
+
- **`isFullWidth` on a vertical group widens the group and does nothing else.**
|
|
234
|
+
Its members already stretch on the cross axis, and `basis-0` on the main axis
|
|
235
|
+
of a column with no definite height would collapse every member to nothing —
|
|
236
|
+
so `isStretched` is `false` there by construction.
|
|
237
|
+
- **Horizontal groups are content-width by default** (`self-start`), because
|
|
238
|
+
that is what a segmented control is. `isFullWidth` fills the parent — **and the
|
|
239
|
+
parent must have a definite width**. Yoga resolves a percentage against the
|
|
240
|
+
parent's content box, so `w-full` inside a container that is itself
|
|
241
|
+
content-sized resolves to nothing and falls back to the content width: the
|
|
242
|
+
group collapses onto its buttons and a `flex-1` field between them is squeezed
|
|
243
|
+
to a few points. It looks like the group ignored `isFullWidth`. It did not;
|
|
244
|
+
there was no width to take a percentage of.
|
|
211
245
|
- **`Button.Group.Text` draws the button's own chrome**, not chrome of its own,
|
|
212
246
|
which is what keeps its height, padding and corner identical to the buttons
|
|
213
247
|
beside it — those come off one axis, and restating any of them here is how a
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type ButtonSize,
|
|
14
14
|
type ButtonVariant,
|
|
15
15
|
buttonVariants,
|
|
16
|
+
resolveGroupMemberStretch,
|
|
16
17
|
resolveGroupPositions,
|
|
17
18
|
resolveGroupSeams,
|
|
18
19
|
} from "./button.variants";
|
|
@@ -30,6 +31,18 @@ export type ButtonGroupProps = ViewProps & {
|
|
|
30
31
|
isDisabled?: boolean;
|
|
31
32
|
/** Press treatment for every member. Unset, a joined member fades rather than scaling. */
|
|
32
33
|
feedback?: PressableFeedback;
|
|
34
|
+
/**
|
|
35
|
+
* Join the members into one shape. On by default, because that is what a group is. Off keeps the
|
|
36
|
+
* inherited `variant` / `size` / `isDisabled` / `feedback` and drops the joined shape: every
|
|
37
|
+
* member keeps its own corner, no seam overlap, and the run takes a `gap`.
|
|
38
|
+
*/
|
|
39
|
+
isAttached?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Span the parent and split it equally between members. Horizontal only — a vertical group
|
|
42
|
+
* already stretches its members, so there it only widens the group. The parent needs a
|
|
43
|
+
* definite width.
|
|
44
|
+
*/
|
|
45
|
+
isFullWidth?: boolean;
|
|
33
46
|
className?: string;
|
|
34
47
|
children?: ReactNode;
|
|
35
48
|
};
|
|
@@ -40,13 +53,15 @@ function ButtonGroupRoot({
|
|
|
40
53
|
variant,
|
|
41
54
|
isDisabled,
|
|
42
55
|
feedback,
|
|
56
|
+
isAttached = true,
|
|
57
|
+
isFullWidth = false,
|
|
43
58
|
className,
|
|
44
59
|
children,
|
|
45
60
|
...props
|
|
46
61
|
}: ButtonGroupProps): ReactElement {
|
|
47
62
|
const group = useMemo<ButtonGroupContextValue>(
|
|
48
|
-
() => ({ feedback, isDisabled, orientation, size, variant }),
|
|
49
|
-
[feedback, isDisabled, orientation, size, variant]
|
|
63
|
+
() => ({ feedback, isAttached, isDisabled, isFullWidth, orientation, size, variant }),
|
|
64
|
+
[feedback, isAttached, isDisabled, isFullWidth, orientation, size, variant]
|
|
50
65
|
);
|
|
51
66
|
|
|
52
67
|
const items = useMemo(() => Children.toArray(children), [children]);
|
|
@@ -56,17 +71,18 @@ function ButtonGroupRoot({
|
|
|
56
71
|
// the members' order actually change.
|
|
57
72
|
const values = useMemo(() => {
|
|
58
73
|
const isMember = items.map(isGroupMember);
|
|
59
|
-
const positions = resolveGroupPositions(isMember);
|
|
60
|
-
const seams = resolveGroupSeams(isMember);
|
|
74
|
+
const positions = resolveGroupPositions(isMember, group);
|
|
75
|
+
const seams = resolveGroupSeams(isMember, group);
|
|
76
|
+
const isStretched = resolveGroupMemberStretch(group);
|
|
61
77
|
|
|
62
78
|
return positions.map<ButtonGroupItemContextValue | null>((position, index) =>
|
|
63
|
-
position === null ? null : { ...group, isSeamed: seams[index] === true, position }
|
|
79
|
+
position === null ? null : { ...group, isSeamed: seams[index] === true, isStretched, position }
|
|
64
80
|
);
|
|
65
81
|
}, [items, group]);
|
|
66
82
|
|
|
67
83
|
return (
|
|
68
84
|
<ButtonGroupProvider value={group}>
|
|
69
|
-
<View className={buttonVariants({ orientation }).group({ className })} {...props}>
|
|
85
|
+
<View className={buttonVariants({ isAttached, isFullWidth, orientation }).group({ className })} {...props}>
|
|
70
86
|
{items.map((child, index) => {
|
|
71
87
|
const value = values[index];
|
|
72
88
|
if (!value) return child;
|
|
@@ -130,8 +146,14 @@ function keyOf(child: ReactNode, index: number): string {
|
|
|
130
146
|
* The group paints nothing itself — no background, no border, no disabled fade.
|
|
131
147
|
* A fade here would compound with the members' own down to a quarter opacity.
|
|
132
148
|
*
|
|
133
|
-
* Horizontal groups are content-width.
|
|
134
|
-
*
|
|
149
|
+
* Horizontal groups are content-width. `isFullWidth` spans the parent and
|
|
150
|
+
* splits it equally between members — `flex-1 basis-0` on each, published as
|
|
151
|
+
* `isStretched` on the member's context — whatever their labels say. The parent
|
|
152
|
+
* needs a definite width for there to be anything to split.
|
|
153
|
+
*
|
|
154
|
+
* `isAttached={false}` keeps the shared axes and drops the shape: every member
|
|
155
|
+
* draws its own corner, nothing overlaps, the run takes a gap, and an unset
|
|
156
|
+
* `feedback` goes back to the lone button's `scale`.
|
|
135
157
|
*
|
|
136
158
|
* @example
|
|
137
159
|
* <Button.Group variant="outline">
|
|
@@ -141,6 +163,20 @@ function keyOf(child: ReactNode, index: number): string {
|
|
|
141
163
|
* </Button.Group>
|
|
142
164
|
*
|
|
143
165
|
* @example
|
|
166
|
+
* <Button.Group isAttached={false} size="sm" variant="outline">
|
|
167
|
+
* <Button onPress={find}>Find</Button>
|
|
168
|
+
* <Button onPress={exportFile}>Export</Button>
|
|
169
|
+
* <Button onPress={share}>Share</Button>
|
|
170
|
+
* </Button.Group>
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* <Button.Group isFullWidth variant="outline">
|
|
174
|
+
* <Button onPress={monthly}>Monthly</Button>
|
|
175
|
+
* <Button onPress={annual}>Annual</Button>
|
|
176
|
+
* <Button onPress={once}>One-off</Button>
|
|
177
|
+
* </Button.Group>
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
144
180
|
* <Button.Group>
|
|
145
181
|
* <Button onPress={save}>Save</Button>
|
|
146
182
|
* <Button.Group.Separator />
|