@lt-three/love3 0.0.0 → 0.1.1
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 +85 -1
- package/dist/native/analytics/animation.d.ts +4 -0
- package/dist/native/analytics/animation.js +6 -0
- package/dist/native/analytics/chart.types.d.ts +25 -0
- package/dist/native/analytics/chart.types.js +0 -0
- package/dist/native/analytics/line-chart.d.ts +4 -0
- package/dist/native/analytics/line-chart.ios.d.ts +4 -0
- package/dist/native/analytics/line-chart.ios.js +24 -0
- package/dist/native/analytics/line-chart.js +33 -0
- package/dist/native/analytics/metric-card.d.ts +10 -0
- package/dist/native/analytics/metric-card.js +29 -0
- package/dist/native/analytics/multi-line-chart.d.ts +18 -0
- package/dist/native/analytics/multi-line-chart.js +216 -0
- package/dist/native/analytics/pie-chart.d.ts +15 -0
- package/dist/native/analytics/pie-chart.ios.d.ts +4 -0
- package/dist/native/analytics/pie-chart.ios.js +24 -0
- package/dist/native/analytics/pie-chart.js +92 -0
- package/dist/native/analytics/single-number.d.ts +19 -0
- package/dist/native/analytics/single-number.js +101 -0
- package/dist/native/atom/avatar.d.ts +21 -0
- package/dist/native/atom/avatar.js +46 -0
- package/dist/native/atom/badge.d.ts +28 -0
- package/dist/native/atom/badge.js +51 -0
- package/dist/native/atom/button.d.ts +46 -0
- package/dist/native/atom/button.js +109 -0
- package/dist/native/atom/checkbox.d.ts +21 -0
- package/dist/native/atom/checkbox.js +47 -0
- package/dist/native/atom/colored-value.d.ts +12 -0
- package/dist/native/atom/colored-value.js +24 -0
- package/dist/native/atom/image.d.ts +21 -0
- package/dist/native/atom/image.js +72 -0
- package/dist/native/atom/label.d.ts +18 -0
- package/dist/native/atom/label.js +33 -0
- package/dist/native/atom/link.d.ts +18 -0
- package/dist/native/atom/link.js +25 -0
- package/dist/native/atom/readout.d.ts +22 -0
- package/dist/native/atom/readout.js +39 -0
- package/dist/native/atom/search-input.d.ts +12 -0
- package/dist/native/atom/search-input.js +36 -0
- package/dist/native/atom/select.d.ts +54 -0
- package/dist/native/atom/select.js +200 -0
- package/dist/native/atom/separator.d.ts +12 -0
- package/dist/native/atom/separator.js +16 -0
- package/dist/native/atom/skeleton.d.ts +12 -0
- package/dist/native/atom/skeleton.js +39 -0
- package/dist/native/atom/slider.d.ts +32 -0
- package/dist/native/atom/slider.js +75 -0
- package/dist/native/atom/spinner.d.ts +15 -0
- package/dist/native/atom/spinner.js +25 -0
- package/dist/native/atom/switch.d.ts +18 -0
- package/dist/native/atom/switch.js +52 -0
- package/dist/native/atom/symbol.d.ts +16 -0
- package/dist/native/atom/symbol.js +38 -0
- package/dist/native/atom/symbol.types.d.ts +25 -0
- package/dist/native/atom/symbol.types.js +49 -0
- package/dist/native/atom/text-field.d.ts +49 -0
- package/dist/native/atom/text-field.js +56 -0
- package/dist/native/atom/text.d.ts +2 -0
- package/dist/native/atom/text.js +3 -0
- package/dist/native/atom/theme-toggle.d.ts +21 -0
- package/dist/native/atom/theme-toggle.js +36 -0
- package/dist/native/atom/timezone-select.d.ts +16 -0
- package/dist/native/atom/timezone-select.js +28 -0
- package/dist/native/atom/typography.d.ts +13 -0
- package/dist/native/atom/typography.js +28 -0
- package/dist/native/base/button.d.ts +61 -0
- package/dist/native/base/button.js +92 -0
- package/dist/native/base/form.d.ts +72 -0
- package/dist/native/base/form.js +113 -0
- package/dist/native/base/glass-card.d.ts +15 -0
- package/dist/native/base/glass-card.js +38 -0
- package/dist/native/base/input.d.ts +29 -0
- package/dist/native/base/input.js +27 -0
- package/dist/native/base/sheet.d.ts +71 -0
- package/dist/native/base/sheet.js +187 -0
- package/dist/native/base/text.d.ts +14 -0
- package/dist/native/base/text.js +53 -0
- package/dist/native/form/checkbox.d.ts +13 -0
- package/dist/native/form/checkbox.js +55 -0
- package/dist/native/form/date-picker.d.ts +23 -0
- package/dist/native/form/date-picker.js +119 -0
- package/dist/native/form/form.d.ts +22 -0
- package/dist/native/form/form.js +44 -0
- package/dist/native/form/radio-group.d.ts +23 -0
- package/dist/native/form/radio-group.js +88 -0
- package/dist/native/form/select.d.ts +13 -0
- package/dist/native/form/select.js +45 -0
- package/dist/native/form/slider.d.ts +14 -0
- package/dist/native/form/slider.js +42 -0
- package/dist/native/form/switch.d.ts +9 -0
- package/dist/native/form/switch.js +59 -0
- package/dist/native/form/text-area.d.ts +11 -0
- package/dist/native/form/text-area.js +50 -0
- package/dist/native/form/text-input.d.ts +18 -0
- package/dist/native/form/text-input.js +90 -0
- package/dist/native/index.d.ts +1 -0
- package/dist/native/index.js +0 -0
- package/dist/native/layout/accordion.d.ts +25 -0
- package/dist/native/layout/accordion.js +54 -0
- package/dist/native/layout/card.d.ts +47 -0
- package/dist/native/layout/card.js +57 -0
- package/dist/native/layout/description.d.ts +16 -0
- package/dist/native/layout/description.js +32 -0
- package/dist/native/layout/error.d.ts +21 -0
- package/dist/native/layout/error.js +44 -0
- package/dist/native/layout/information.d.ts +25 -0
- package/dist/native/layout/information.js +35 -0
- package/dist/native/layout/locked.d.ts +38 -0
- package/dist/native/layout/locked.js +94 -0
- package/dist/native/layout/modal.d.ts +25 -0
- package/dist/native/layout/modal.js +93 -0
- package/dist/native/layout/not-found.d.ts +17 -0
- package/dist/native/layout/not-found.js +30 -0
- package/dist/native/layout/page-frame.d.ts +23 -0
- package/dist/native/layout/page-frame.js +46 -0
- package/dist/native/layout/panel.d.ts +18 -0
- package/dist/native/layout/panel.js +23 -0
- package/dist/native/layout/reorderable-list.d.ts +42 -0
- package/dist/native/layout/reorderable-list.js +52 -0
- package/dist/native/layout/sheet.d.ts +30 -0
- package/dist/native/layout/sheet.js +46 -0
- package/dist/native/layout/simple-dialog.d.ts +16 -0
- package/dist/native/layout/simple-dialog.js +20 -0
- package/dist/native/layout/simple-table.d.ts +50 -0
- package/dist/native/layout/simple-table.js +75 -0
- package/dist/native/layout/tab-bar.d.ts +33 -0
- package/dist/native/layout/tab-bar.js +48 -0
- package/dist/native/layout/tabs.d.ts +28 -0
- package/dist/native/layout/tabs.js +54 -0
- package/dist/native/layout/tuning-panel.d.ts +24 -0
- package/dist/native/layout/tuning-panel.js +246 -0
- package/dist/native/lib/autocomplete.d.ts +7 -0
- package/dist/native/lib/autocomplete.js +34 -0
- package/dist/native/lib/breakpoints.d.ts +14 -0
- package/dist/native/lib/breakpoints.js +17 -0
- package/dist/native/lib/chart-palette.d.ts +8 -0
- package/dist/native/lib/chart-palette.js +20 -0
- package/dist/native/lib/confirm.d.ts +48 -0
- package/dist/native/lib/confirm.js +69 -0
- package/dist/native/lib/control.d.ts +24 -0
- package/dist/native/lib/control.js +0 -0
- package/dist/native/lib/external-store.d.ts +16 -0
- package/dist/native/lib/external-store.js +30 -0
- package/dist/native/lib/keyboard.d.ts +15 -0
- package/dist/native/lib/keyboard.js +24 -0
- package/dist/native/lib/labels.d.ts +15 -0
- package/dist/native/lib/labels.js +17 -0
- package/dist/native/lib/loading.d.ts +10 -0
- package/dist/native/lib/loading.js +15 -0
- package/dist/native/lib/network.d.ts +11 -0
- package/dist/native/lib/network.js +20 -0
- package/dist/native/lib/scheme.d.ts +18 -0
- package/dist/native/lib/scheme.js +22 -0
- package/dist/native/lib/snackbar.d.ts +45 -0
- package/dist/native/lib/snackbar.js +59 -0
- package/dist/native/lib/theme.d.ts +34 -0
- package/dist/native/lib/theme.js +53 -0
- package/dist/native/lib/timezone.d.ts +26 -0
- package/dist/native/lib/timezone.js +95 -0
- package/dist/native/lib/token-color.d.ts +5 -0
- package/dist/native/lib/token-color.js +13 -0
- package/dist/native/lib/token-color.web.d.ts +4 -0
- package/dist/native/lib/token-color.web.js +7 -0
- package/dist/native/lib/tuning-context.d.ts +9 -0
- package/dist/native/lib/tuning-context.js +7 -0
- package/dist/native/lib/tuning.d.ts +24 -0
- package/dist/native/lib/tuning.js +42 -0
- package/dist/native/lib/typography.d.ts +10 -0
- package/dist/native/lib/typography.js +11 -0
- package/dist/native/lib/utils.d.ts +11 -0
- package/dist/native/lib/utils.js +21 -0
- package/dist/native/once/confirm.d.ts +7 -0
- package/dist/native/once/confirm.js +60 -0
- package/dist/native/once/error-boundary.d.ts +28 -0
- package/dist/native/once/error-boundary.js +55 -0
- package/dist/native/once/loading-lock.d.ts +8 -0
- package/dist/native/once/loading-lock.js +28 -0
- package/dist/native/once/offline-banner.d.ts +15 -0
- package/dist/native/once/offline-banner.js +35 -0
- package/dist/native/once/snackbar.d.ts +17 -0
- package/dist/native/once/snackbar.js +106 -0
- package/dist/native/styles.css +46 -0
- package/dist/shared/analytics.d.ts +71 -0
- package/dist/shared/analytics.js +0 -0
- package/dist/shared/button.d.ts +7 -0
- package/dist/shared/button.js +23 -0
- package/dist/shared/form.d.ts +45 -0
- package/dist/shared/form.js +46 -0
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.js +3 -0
- package/dist/tokens/contrast-pairs.d.ts +30 -0
- package/dist/tokens/contrast-pairs.js +404 -0
- package/dist/tokens/index.d.ts +6 -0
- package/dist/tokens/index.js +10 -0
- package/dist/tokens/styles.gen.css +250 -0
- package/dist/tokens/tokens.gen.d.ts +141 -0
- package/dist/tokens/tokens.gen.js +206 -0
- package/dist/tuning/catalog.d.ts +27 -0
- package/dist/tuning/catalog.gen.d.ts +4 -0
- package/dist/tuning/catalog.gen.js +397 -0
- package/dist/tuning/catalog.js +128 -0
- package/dist/tuning/color.d.ts +20 -0
- package/dist/tuning/color.js +80 -0
- package/dist/tuning/css.d.ts +35 -0
- package/dist/tuning/css.js +147 -0
- package/dist/tuning/index.d.ts +8 -0
- package/dist/tuning/index.js +9 -0
- package/dist/tuning/model.d.ts +33 -0
- package/dist/tuning/model.js +154 -0
- package/dist/tuning/native.d.ts +35 -0
- package/dist/tuning/native.js +80 -0
- package/dist/tuning/schema.d.ts +69 -0
- package/dist/tuning/schema.js +247 -0
- package/dist/tuning/types.d.ts +75 -0
- package/dist/tuning/types.js +39 -0
- package/dist/web/analytics/line-chart.d.ts +20 -0
- package/dist/web/analytics/line-chart.js +28 -0
- package/dist/web/analytics/metric-card.d.ts +18 -0
- package/dist/web/analytics/metric-card.js +40 -0
- package/dist/web/analytics/multi-line-chart.d.ts +39 -0
- package/dist/web/analytics/multi-line-chart.js +345 -0
- package/dist/web/atom/avatar.d.ts +11 -0
- package/dist/web/atom/avatar.js +24 -0
- package/dist/web/atom/badge.d.ts +2 -0
- package/dist/web/atom/badge.js +3 -0
- package/dist/web/atom/button.d.ts +23 -0
- package/dist/web/atom/button.js +35 -0
- package/dist/web/atom/checkbox.d.ts +19 -0
- package/dist/web/atom/checkbox.js +33 -0
- package/dist/web/atom/colored-value.d.ts +13 -0
- package/dist/web/atom/colored-value.js +24 -0
- package/dist/web/atom/help.d.ts +10 -0
- package/dist/web/atom/help.js +18 -0
- package/dist/web/atom/label.d.ts +2 -0
- package/dist/web/atom/label.js +3 -0
- package/dist/web/atom/segmented-control.d.ts +39 -0
- package/dist/web/atom/segmented-control.js +42 -0
- package/dist/web/atom/select.d.ts +43 -0
- package/dist/web/atom/select.js +93 -0
- package/dist/web/atom/separator.d.ts +2 -0
- package/dist/web/atom/separator.js +3 -0
- package/dist/web/atom/skeleton.d.ts +2 -0
- package/dist/web/atom/skeleton.js +3 -0
- package/dist/web/atom/slider.d.ts +33 -0
- package/dist/web/atom/slider.js +70 -0
- package/dist/web/atom/spinner.d.ts +8 -0
- package/dist/web/atom/spinner.js +14 -0
- package/dist/web/atom/switch.d.ts +11 -0
- package/dist/web/atom/switch.js +10 -0
- package/dist/web/atom/text-area.d.ts +23 -0
- package/dist/web/atom/text-area.js +27 -0
- package/dist/web/atom/text-field.d.ts +18 -0
- package/dist/web/atom/text-field.js +22 -0
- package/dist/web/atom/toggle-chip.d.ts +22 -0
- package/dist/web/atom/toggle-chip.js +28 -0
- package/dist/web/atom/tooltip.d.ts +23 -0
- package/dist/web/atom/tooltip.js +26 -0
- package/dist/web/atom/typography.d.ts +6 -0
- package/dist/web/atom/typography.js +23 -0
- package/dist/web/base/accordion.d.ts +9 -0
- package/dist/web/base/accordion.js +44 -0
- package/dist/web/base/alert.d.ts +11 -0
- package/dist/web/base/alert.js +37 -0
- package/dist/web/base/avatar.d.ts +8 -0
- package/dist/web/base/avatar.js +29 -0
- package/dist/web/base/badge.d.ts +12 -0
- package/dist/web/base/badge.js +26 -0
- package/dist/web/base/breadcrumb.d.ts +16 -0
- package/dist/web/base/breadcrumb.js +72 -0
- package/dist/web/base/button.d.ts +12 -0
- package/dist/web/base/button.js +47 -0
- package/dist/web/base/card.d.ts +19 -0
- package/dist/web/base/card.js +74 -0
- package/dist/web/base/checkbox.d.ts +6 -0
- package/dist/web/base/checkbox.js +21 -0
- package/dist/web/base/dialog.d.ts +20 -0
- package/dist/web/base/dialog.js +92 -0
- package/dist/web/base/dropdown-menu.d.ts +29 -0
- package/dist/web/base/dropdown-menu.js +125 -0
- package/dist/web/base/field.d.ts +27 -0
- package/dist/web/base/field.js +118 -0
- package/dist/web/base/form.d.ts +38 -0
- package/dist/web/base/form.js +110 -0
- package/dist/web/base/input.d.ts +9 -0
- package/dist/web/base/input.js +23 -0
- package/dist/web/base/label.d.ts +6 -0
- package/dist/web/base/label.js +15 -0
- package/dist/web/base/pagination.d.ts +34 -0
- package/dist/web/base/pagination.js +90 -0
- package/dist/web/base/popover.d.ts +11 -0
- package/dist/web/base/popover.js +37 -0
- package/dist/web/base/radio-group.d.ts +7 -0
- package/dist/web/base/radio-group.js +27 -0
- package/dist/web/base/scroll-area.d.ts +10 -0
- package/dist/web/base/scroll-area.js +41 -0
- package/dist/web/base/select.d.ts +17 -0
- package/dist/web/base/select.js +96 -0
- package/dist/web/base/separator.d.ts +6 -0
- package/dist/web/base/separator.js +17 -0
- package/dist/web/base/sheet.d.ts +19 -0
- package/dist/web/base/sheet.js +88 -0
- package/dist/web/base/skeleton.d.ts +5 -0
- package/dist/web/base/skeleton.js +14 -0
- package/dist/web/base/slider.d.ts +9 -0
- package/dist/web/base/slider.js +39 -0
- package/dist/web/base/sonner.d.ts +9 -0
- package/dist/web/base/sonner.js +25 -0
- package/dist/web/base/spinner.d.ts +5 -0
- package/dist/web/base/spinner.js +17 -0
- package/dist/web/base/switch.d.ts +6 -0
- package/dist/web/base/switch.js +19 -0
- package/dist/web/base/table.d.ts +14 -0
- package/dist/web/base/table.js +68 -0
- package/dist/web/base/tabs.d.ts +9 -0
- package/dist/web/base/tabs.js +36 -0
- package/dist/web/base/textarea.d.ts +9 -0
- package/dist/web/base/textarea.js +23 -0
- package/dist/web/base/tooltip.d.ts +9 -0
- package/dist/web/base/tooltip.js +36 -0
- package/dist/web/form/checkbox.d.ts +35 -0
- package/dist/web/form/checkbox.js +91 -0
- package/dist/web/form/radio-group.d.ts +24 -0
- package/dist/web/form/radio-group.js +75 -0
- package/dist/web/form/select.d.ts +16 -0
- package/dist/web/form/select.js +44 -0
- package/dist/web/form/slider.d.ts +19 -0
- package/dist/web/form/slider.js +51 -0
- package/dist/web/form/switch.d.ts +11 -0
- package/dist/web/form/switch.js +50 -0
- package/dist/web/form/text-area.d.ts +10 -0
- package/dist/web/form/text-area.js +31 -0
- package/dist/web/form/text-input.d.ts +10 -0
- package/dist/web/form/text-input.js +42 -0
- package/dist/web/index.d.ts +1 -0
- package/dist/web/index.js +0 -0
- package/dist/web/layout/accordion.d.ts +26 -0
- package/dist/web/layout/accordion.js +29 -0
- package/dist/web/layout/alert-modal.d.ts +41 -0
- package/dist/web/layout/alert-modal.js +71 -0
- package/dist/web/layout/card.d.ts +17 -0
- package/dist/web/layout/card.js +35 -0
- package/dist/web/layout/description.d.ts +12 -0
- package/dist/web/layout/description.js +20 -0
- package/dist/web/layout/information.d.ts +36 -0
- package/dist/web/layout/information.js +53 -0
- package/dist/web/layout/modal.d.ts +16 -0
- package/dist/web/layout/modal.js +37 -0
- package/dist/web/layout/page-frame.d.ts +37 -0
- package/dist/web/layout/page-frame.js +79 -0
- package/dist/web/layout/scroll-area.d.ts +10 -0
- package/dist/web/layout/scroll-area.js +13 -0
- package/dist/web/layout/sheet.d.ts +32 -0
- package/dist/web/layout/sheet.js +68 -0
- package/dist/web/layout/simple-dialog.d.ts +11 -0
- package/dist/web/layout/simple-dialog.js +24 -0
- package/dist/web/layout/simple-table.d.ts +49 -0
- package/dist/web/layout/simple-table.js +58 -0
- package/dist/web/layout/tabs.d.ts +26 -0
- package/dist/web/layout/tabs.js +42 -0
- package/dist/web/layout/titled-modal.d.ts +32 -0
- package/dist/web/layout/titled-modal.js +58 -0
- package/dist/web/lib/css-vars.d.ts +14 -0
- package/dist/web/lib/css-vars.js +18 -0
- package/dist/web/lib/dialog.d.ts +13 -0
- package/dist/web/lib/dialog.js +0 -0
- package/dist/web/lib/form.d.ts +2 -0
- package/dist/web/lib/form.js +3 -0
- package/dist/web/lib/labels.d.ts +27 -0
- package/dist/web/lib/labels.js +29 -0
- package/dist/web/lib/modal-open-focus.d.ts +17 -0
- package/dist/web/lib/modal-open-focus.js +44 -0
- package/dist/web/lib/restore-focus.d.ts +12 -0
- package/dist/web/lib/restore-focus.js +32 -0
- package/dist/web/lib/utils.d.ts +4 -0
- package/dist/web/lib/utils.js +10 -0
- package/dist/web/styles.css +162 -0
- package/package.json +203 -4
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/native/base/form.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The set of chrome ids and the errors. Use it inside `FormItem`. It does not crash outside a field (controlled mode) either.
|
|
5
|
+
*
|
|
6
|
+
* **The errors to display are decided in one place here** (the field's errors + the `errors` of `FormItem`). The `FormLabel` color, the `FormMessage` text and
|
|
7
|
+
* the `FormControl` `aria-invalid` / `aria-describedby` all read from it, so mismatches such as a message being shown without `aria-invalid` cannot occur.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useFormField(): {
|
|
10
|
+
id: string;
|
|
11
|
+
formItemId: string;
|
|
12
|
+
formLabelId: string;
|
|
13
|
+
formDescriptionId: string;
|
|
14
|
+
formMessageId: string;
|
|
15
|
+
errors: readonly unknown[];
|
|
16
|
+
};
|
|
17
|
+
export declare function FormItem({ children, className, errors }: {
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Errors **added to** the field's (TanStack Form) errors. Use it outside a field, or inside a field when you want to show an error
|
|
22
|
+
* owned by the input component itself (such as "not readable as a number" on a numeric field). It affects the input's `aria-invalid` and `aria-describedby`,
|
|
23
|
+
* the label color and the `FormMessage` display alike. Passing an empty array does not hide the field's errors.
|
|
24
|
+
*/
|
|
25
|
+
errors?: readonly unknown[];
|
|
26
|
+
}): import("react").JSX.Element;
|
|
27
|
+
export declare function FormLabel({ children, required, helpText, className }: {
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
required?: boolean;
|
|
30
|
+
helpText?: ReactNode;
|
|
31
|
+
className?: string;
|
|
32
|
+
}): import("react").JSX.Element;
|
|
33
|
+
/** The props `FormControl` passes to the input component (the same shape as the component's `ControlA11yProps`). */
|
|
34
|
+
export type FormControlProps = {
|
|
35
|
+
id: string;
|
|
36
|
+
"aria-labelledby": string | undefined;
|
|
37
|
+
"aria-describedby": string | undefined;
|
|
38
|
+
"aria-invalid": boolean;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Passes `id`, `aria-labelledby`, `aria-describedby` and `aria-invalid` to the input component. The child is received as a function.
|
|
42
|
+
*
|
|
43
|
+
* ```tsx
|
|
44
|
+
* <FormControl labelled={Boolean(label)} described={Boolean(description)}>
|
|
45
|
+
* {control => <TextField {...control} value={value} onChangeText={setValue} />}
|
|
46
|
+
* </FormControl>
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* - `labelled`: when a `FormLabel` is placed. Makes the label text the input's name (`aria-labelledby`). When none is placed,
|
|
50
|
+
* it is not set so it never points to a nonexistent id. Inputs that carry their own label on the right (checkbox, radio) do not set it, because their own text is the name
|
|
51
|
+
* - `described`: when a `FormDescription` is placed. Adds the description to `aria-describedby`. When there is an error, the error text is added too
|
|
52
|
+
* - `id`: defaults to `formItemId` (when a field has one input). **When a field has several inputs** (radio options),
|
|
53
|
+
* pass one per option so the same id does not collide
|
|
54
|
+
*/
|
|
55
|
+
export declare function FormControl({ children, id, labelled, described }: {
|
|
56
|
+
children: (control: FormControlProps) => ReactNode;
|
|
57
|
+
id?: string;
|
|
58
|
+
labelled?: boolean;
|
|
59
|
+
described?: boolean;
|
|
60
|
+
}): ReactNode;
|
|
61
|
+
export declare function FormDescription({ children, className }: {
|
|
62
|
+
children: ReactNode;
|
|
63
|
+
className?: string;
|
|
64
|
+
}): import("react").JSX.Element;
|
|
65
|
+
/**
|
|
66
|
+
* The error text. The only errors shown are the single set from `useFormField` (add more via the `errors` of `FormItem`).
|
|
67
|
+
* It does not have the web `FormMessage`'s "errors shown only in this message" (`errors`), because changing only the text would disagree with `aria-invalid`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function FormMessage({ className }: {
|
|
70
|
+
className?: string;
|
|
71
|
+
}): import("react").JSX.Element | null;
|
|
72
|
+
//#endregion
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useOptionalFieldContext } from "../../shared/form.js";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Text as Text$1 } from "./text.js";
|
|
4
|
+
import { createContext, useContext, useId } from "react";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/native/base/form.tsx
|
|
9
|
+
const FormItemContext = createContext({ id: "" });
|
|
10
|
+
/**
|
|
11
|
+
* The set of chrome ids and the errors. Use it inside `FormItem`. It does not crash outside a field (controlled mode) either.
|
|
12
|
+
*
|
|
13
|
+
* **The errors to display are decided in one place here** (the field's errors + the `errors` of `FormItem`). The `FormLabel` color, the `FormMessage` text and
|
|
14
|
+
* the `FormControl` `aria-invalid` / `aria-describedby` all read from it, so mismatches such as a message being shown without `aria-invalid` cannot occur.
|
|
15
|
+
*/
|
|
16
|
+
function useFormField() {
|
|
17
|
+
const itemContext = useContext(FormItemContext);
|
|
18
|
+
const errors = [...useOptionalFieldContext()?.state.meta.errors ?? [], ...itemContext.extraErrors ?? []];
|
|
19
|
+
const { id } = itemContext;
|
|
20
|
+
return {
|
|
21
|
+
id,
|
|
22
|
+
formItemId: `${id}-form-item`,
|
|
23
|
+
formLabelId: `${id}-form-item-label`,
|
|
24
|
+
formDescriptionId: `${id}-form-item-description`,
|
|
25
|
+
formMessageId: `${id}-form-item-message`,
|
|
26
|
+
errors
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function FormItem({ children, className, errors }) {
|
|
30
|
+
const id = useId();
|
|
31
|
+
return /* @__PURE__ */ jsx(FormItemContext.Provider, {
|
|
32
|
+
value: {
|
|
33
|
+
id,
|
|
34
|
+
extraErrors: errors
|
|
35
|
+
},
|
|
36
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
37
|
+
className: cn("gap-2", className),
|
|
38
|
+
children
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function FormLabel({ children, required, helpText, className }) {
|
|
43
|
+
const { errors, formLabelId } = useFormField();
|
|
44
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
45
|
+
className: "flex-row items-center gap-1",
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx(Text$1, {
|
|
48
|
+
id: formLabelId,
|
|
49
|
+
className: cn("text-xs font-semibold opacity-80", errors.length > 0 && "text-destructive opacity-100", className),
|
|
50
|
+
children
|
|
51
|
+
}),
|
|
52
|
+
required ? /* @__PURE__ */ jsx(Text$1, {
|
|
53
|
+
className: "text-destructive text-sm",
|
|
54
|
+
children: "*"
|
|
55
|
+
}) : null,
|
|
56
|
+
helpText ? /* @__PURE__ */ jsx(Text$1, {
|
|
57
|
+
className: "text-muted-foreground text-xs font-normal",
|
|
58
|
+
children: helpText
|
|
59
|
+
}) : null
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Passes `id`, `aria-labelledby`, `aria-describedby` and `aria-invalid` to the input component. The child is received as a function.
|
|
65
|
+
*
|
|
66
|
+
* ```tsx
|
|
67
|
+
* <FormControl labelled={Boolean(label)} described={Boolean(description)}>
|
|
68
|
+
* {control => <TextField {...control} value={value} onChangeText={setValue} />}
|
|
69
|
+
* </FormControl>
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* - `labelled`: when a `FormLabel` is placed. Makes the label text the input's name (`aria-labelledby`). When none is placed,
|
|
73
|
+
* it is not set so it never points to a nonexistent id. Inputs that carry their own label on the right (checkbox, radio) do not set it, because their own text is the name
|
|
74
|
+
* - `described`: when a `FormDescription` is placed. Adds the description to `aria-describedby`. When there is an error, the error text is added too
|
|
75
|
+
* - `id`: defaults to `formItemId` (when a field has one input). **When a field has several inputs** (radio options),
|
|
76
|
+
* pass one per option so the same id does not collide
|
|
77
|
+
*/
|
|
78
|
+
function FormControl({ children, id, labelled = false, described = false }) {
|
|
79
|
+
const { errors, formItemId, formLabelId, formDescriptionId, formMessageId } = useFormField();
|
|
80
|
+
const invalid = errors.length > 0;
|
|
81
|
+
const describedBy = [described ? formDescriptionId : void 0, invalid ? formMessageId : void 0].filter(Boolean).join(" ");
|
|
82
|
+
return children({
|
|
83
|
+
id: id ?? formItemId,
|
|
84
|
+
"aria-labelledby": labelled ? formLabelId : void 0,
|
|
85
|
+
"aria-describedby": describedBy === "" ? void 0 : describedBy,
|
|
86
|
+
"aria-invalid": invalid
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function FormDescription({ children, className }) {
|
|
90
|
+
const { formDescriptionId } = useFormField();
|
|
91
|
+
return /* @__PURE__ */ jsx(Text$1, {
|
|
92
|
+
id: formDescriptionId,
|
|
93
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
94
|
+
children
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The error text. The only errors shown are the single set from `useFormField` (add more via the `errors` of `FormItem`).
|
|
99
|
+
* It does not have the web `FormMessage`'s "errors shown only in this message" (`errors`), because changing only the text would disagree with `aria-invalid`.
|
|
100
|
+
*/
|
|
101
|
+
function FormMessage({ className }) {
|
|
102
|
+
const { errors: list, formMessageId } = useFormField();
|
|
103
|
+
if (list.length === 0) return null;
|
|
104
|
+
return /* @__PURE__ */ jsx(Text$1, {
|
|
105
|
+
id: formMessageId,
|
|
106
|
+
role: "alert",
|
|
107
|
+
className: cn("text-destructive text-sm", className),
|
|
108
|
+
children: list.map((error) => String(error)).join("\n")
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//#endregion
|
|
113
|
+
export { FormControl, FormDescription, FormItem, FormLabel, FormMessage, useFormField };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { ViewStyle } from "react-native";
|
|
3
|
+
//#region src/native/base/glass-card.d.ts
|
|
4
|
+
type GlassCardProps = {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
style?: ViewStyle;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A Liquid Glass card surface. On iOS 26 and later it uses `GlassView` (`UIGlassEffect`)
|
|
10
|
+
* for a glass look that blurs what is behind it; on unsupported environments (below iOS 26, Android, web) it falls back to a plain View with a border.
|
|
11
|
+
* The fallback border uses the token's line color (`--line`).
|
|
12
|
+
*/
|
|
13
|
+
declare function GlassCard({ children, style }: GlassCardProps): import("react").JSX.Element;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { GlassCard, type GlassCardProps };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { GlassView, isLiquidGlassAvailable } from "expo-glass-effect";
|
|
5
|
+
|
|
6
|
+
//#region src/native/base/glass-card.tsx
|
|
7
|
+
const BASE = {
|
|
8
|
+
borderRadius: 10,
|
|
9
|
+
padding: 16,
|
|
10
|
+
overflow: "hidden"
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A Liquid Glass card surface. On iOS 26 and later it uses `GlassView` (`UIGlassEffect`)
|
|
14
|
+
* for a glass look that blurs what is behind it; on unsupported environments (below iOS 26, Android, web) it falls back to a plain View with a border.
|
|
15
|
+
* The fallback border uses the token's line color (`--line`).
|
|
16
|
+
*/
|
|
17
|
+
function GlassCard({ children, style }) {
|
|
18
|
+
const line = useTokenColor("--line");
|
|
19
|
+
if (isLiquidGlassAvailable()) return /* @__PURE__ */ jsx(GlassView, {
|
|
20
|
+
glassEffectStyle: "regular",
|
|
21
|
+
style: [BASE, style],
|
|
22
|
+
children
|
|
23
|
+
});
|
|
24
|
+
return /* @__PURE__ */ jsx(View, {
|
|
25
|
+
style: [
|
|
26
|
+
BASE,
|
|
27
|
+
{
|
|
28
|
+
borderWidth: 1,
|
|
29
|
+
borderColor: line
|
|
30
|
+
},
|
|
31
|
+
style
|
|
32
|
+
],
|
|
33
|
+
children
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { GlassCard };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { KeyboardTypeOptions } from "react-native";
|
|
2
|
+
//#region src/native/base/input.d.ts
|
|
3
|
+
type InputProps = {
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
/** The value to display. Pass it when syncing with external state (internally it is driven uncontrolled). */
|
|
6
|
+
value?: string;
|
|
7
|
+
onChangeText?: (text: string) => void;
|
|
8
|
+
secureTextEntry?: boolean;
|
|
9
|
+
editable?: boolean;
|
|
10
|
+
autoFocus?: boolean;
|
|
11
|
+
autoCapitalize?: "none" | "sentences" | "words" | "characters";
|
|
12
|
+
keyboardType?: KeyboardTypeOptions;
|
|
13
|
+
returnKeyType?: "done" | "go" | "next" | "search" | "send";
|
|
14
|
+
onSubmitEditing?: (text: string) => void;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The native text input (the OS control layer). Renders SwiftUI's `TextField` / `SecureField` on iOS
|
|
18
|
+
* and Jetpack Compose's `TextField` on Android (via `@expo/ui` universal).
|
|
19
|
+
*
|
|
20
|
+
* The **OS-native base layer** counterpart of `atom/text-field` (an RN `TextInput`, an input frame painted with tokens).
|
|
21
|
+
* It **cannot be painted with tokens**, so for inputs that should look the same as the web use `atom/text-field` (or `form/text-input` in a form).
|
|
22
|
+
*
|
|
23
|
+
* The universal `value` is an `ObservableState` type, so to handle a plain string it is driven by
|
|
24
|
+
* `defaultValue` (uncontrolled) + `onChangeText`. External state is
|
|
25
|
+
* synced through `onChangeText`.
|
|
26
|
+
*/
|
|
27
|
+
declare function Input({ value, ...props }: InputProps): import("react").JSX.Element;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { Input, type InputProps };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Host, TextInput } from "@expo/ui";
|
|
3
|
+
|
|
4
|
+
//#region src/native/base/input.tsx
|
|
5
|
+
/**
|
|
6
|
+
* The native text input (the OS control layer). Renders SwiftUI's `TextField` / `SecureField` on iOS
|
|
7
|
+
* and Jetpack Compose's `TextField` on Android (via `@expo/ui` universal).
|
|
8
|
+
*
|
|
9
|
+
* The **OS-native base layer** counterpart of `atom/text-field` (an RN `TextInput`, an input frame painted with tokens).
|
|
10
|
+
* It **cannot be painted with tokens**, so for inputs that should look the same as the web use `atom/text-field` (or `form/text-input` in a form).
|
|
11
|
+
*
|
|
12
|
+
* The universal `value` is an `ObservableState` type, so to handle a plain string it is driven by
|
|
13
|
+
* `defaultValue` (uncontrolled) + `onChangeText`. External state is
|
|
14
|
+
* synced through `onChangeText`.
|
|
15
|
+
*/
|
|
16
|
+
function Input({ value, ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsx(Host, {
|
|
18
|
+
style: { minHeight: 44 },
|
|
19
|
+
children: /* @__PURE__ */ jsx(TextInput, {
|
|
20
|
+
defaultValue: value,
|
|
21
|
+
...props
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { Input };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/native/base/sheet.d.ts
|
|
3
|
+
export type SheetShellProps = {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
/** Whether tapping the backdrop closes it (default true). */
|
|
7
|
+
dismissOnBackdropPress?: boolean;
|
|
8
|
+
/** The maximum height as a ratio of the screen height (default 0.85). */
|
|
9
|
+
maxHeightRatio?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Called **exactly once** after it has fully closed and the `Modal` has been dismissed (not called if it was never opened, nor on every re-render).
|
|
12
|
+
* **Open the next sheet from here.**
|
|
13
|
+
* If another sheet is opened right after setting `open` to false, two `Modal`s coexist for the duration of the
|
|
14
|
+
* closing animation, and iOS does not present the later one (it looks like nothing happens).
|
|
15
|
+
*
|
|
16
|
+
* **A confirm dialog (`once/confirm`) is also a `Modal`.** When showing a confirmation from inside a sheet,
|
|
17
|
+
* use this for the same reason.
|
|
18
|
+
*/
|
|
19
|
+
onClosed?: () => void;
|
|
20
|
+
/**
|
|
21
|
+
* The `id` of the heading that names the dialog (the same value as `SheetHeader`'s `titleId`). Practically required when there is no `aria-label`
|
|
22
|
+
* (a dialog without a name is conveyed to assistive technology only as "dialog").
|
|
23
|
+
*/
|
|
24
|
+
"aria-labelledby"?: string;
|
|
25
|
+
/** The dialog's name when the heading is not a string or no heading is shown. */
|
|
26
|
+
"aria-label"?: string;
|
|
27
|
+
/** The `id` of the supplementary text (the same value as `SheetHeader`'s `descriptionId`). */
|
|
28
|
+
"aria-describedby"?: string;
|
|
29
|
+
children: ReactNode;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Do not use `Modal`'s `animationType="slide"`. It slides up **together with the scrim**,
|
|
33
|
+
* so the dark overlay appears to grow from the bottom and looks cheap. Here the scrim's fade and the panel's
|
|
34
|
+
* slide are driven by separate curves.
|
|
35
|
+
*
|
|
36
|
+
* The dialog role (`role="dialog"`, `aria-modal`), focus trapping and Esc (`onRequestClose`) are provided by `Modal`
|
|
37
|
+
* (react-native-web's `Modal` emits the role and the trap. It has no name of its own, so pass `aria-label(ledby)`).
|
|
38
|
+
*/
|
|
39
|
+
export declare function SheetShell({ open, onOpenChange, dismissOnBackdropPress, maxHeightRatio, onClosed, "aria-labelledby": ariaLabelledBy, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, children }: SheetShellProps): import("react").JSX.Element | null;
|
|
40
|
+
export type SheetHeaderProps = {
|
|
41
|
+
title?: ReactNode;
|
|
42
|
+
description?: ReactNode;
|
|
43
|
+
/** Screen reader name of the close button (the default is the Japanese "close" label). */
|
|
44
|
+
closeLabel?: string;
|
|
45
|
+
onClose: () => void;
|
|
46
|
+
/** The `id` of the heading. Pass the same value to `SheetShell`'s `aria-labelledby` and the heading becomes the dialog's name. */
|
|
47
|
+
titleId?: string;
|
|
48
|
+
/** The `id` of the supplementary text. Pass the same value to `SheetShell`'s `aria-describedby`. */
|
|
49
|
+
descriptionId?: string;
|
|
50
|
+
};
|
|
51
|
+
/** The grab cue (grabber), the heading and the close button. */
|
|
52
|
+
export declare function SheetHeader({ title, description, closeLabel, onClose, titleId, descriptionId }: SheetHeaderProps): import("react").JSX.Element;
|
|
53
|
+
export type SheetScrollProps = {
|
|
54
|
+
/** Whether to pad the content (default true). Use false for a row list that fills edge to edge. */
|
|
55
|
+
padded?: boolean;
|
|
56
|
+
/** Whether there is a footer. When there is none, the content's bottom edge absorbs the safe area. */
|
|
57
|
+
hasFooter?: boolean;
|
|
58
|
+
children: ReactNode;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* The sheet body.
|
|
62
|
+
*
|
|
63
|
+
* `contentContainerClassName` **does not work** with react-native-css (the padding silently disappears and
|
|
64
|
+
* text gets clipped at the edge). Always write padding in `contentContainerStyle`.
|
|
65
|
+
*/
|
|
66
|
+
export declare function SheetScroll({ padded, hasFooter, children }: SheetScrollProps): import("react").JSX.Element;
|
|
67
|
+
/** The sheet footer. Adds the safe area so it does not slip under the home indicator. */
|
|
68
|
+
export declare function SheetFooter({ children }: {
|
|
69
|
+
children: ReactNode;
|
|
70
|
+
}): import("react").JSX.Element;
|
|
71
|
+
//#endregion
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { isBlankNode } from "../lib/utils.js";
|
|
3
|
+
import { Text as Text$1 } from "./text.js";
|
|
4
|
+
import { CLOSE_LABEL } from "../lib/labels.js";
|
|
5
|
+
import { useEffect, useRef, useState } from "react";
|
|
6
|
+
import { KeyboardAvoidingView, Modal, Platform, Pressable, ScrollView, StyleSheet, View, useWindowDimensions } from "react-native";
|
|
7
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import Feather from "@expo/vector-icons/Feather";
|
|
9
|
+
import Animated$1, { Easing as Easing$1, useAnimatedStyle, useSharedValue, withSpring, withTiming } from "react-native-reanimated";
|
|
10
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
11
|
+
import { scheduleOnRN } from "react-native-worklets";
|
|
12
|
+
|
|
13
|
+
//#region src/native/base/sheet.tsx
|
|
14
|
+
/**
|
|
15
|
+
* The base for a bottom sheet. Mirrors the web base/sheet (a wrapper around Radix Dialog).
|
|
16
|
+
*
|
|
17
|
+
* This holds only "how the surface appears"; conventions for headings and body are decided by `layout/sheet`.
|
|
18
|
+
* Things that want their own content, such as the `atom/select` picker, cannot go through `layout/`
|
|
19
|
+
* (the dependency would run backwards), so, as on the web, the base lives in base and both use it.
|
|
20
|
+
*/
|
|
21
|
+
/** The content padding. Even when `padded` is false, the bottom safe area is always secured. */
|
|
22
|
+
const GUTTER = 16;
|
|
23
|
+
/**
|
|
24
|
+
* Do not use `Modal`'s `animationType="slide"`. It slides up **together with the scrim**,
|
|
25
|
+
* so the dark overlay appears to grow from the bottom and looks cheap. Here the scrim's fade and the panel's
|
|
26
|
+
* slide are driven by separate curves.
|
|
27
|
+
*
|
|
28
|
+
* The dialog role (`role="dialog"`, `aria-modal`), focus trapping and Esc (`onRequestClose`) are provided by `Modal`
|
|
29
|
+
* (react-native-web's `Modal` emits the role and the trap. It has no name of its own, so pass `aria-label(ledby)`).
|
|
30
|
+
*/
|
|
31
|
+
function SheetShell({ open, onOpenChange, dismissOnBackdropPress = true, maxHeightRatio = .85, onClosed, "aria-labelledby": ariaLabelledBy, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, children }) {
|
|
32
|
+
const { height: windowHeight } = useWindowDimensions();
|
|
33
|
+
const [mounted, setMounted] = useState(open);
|
|
34
|
+
const [panelHeight, setPanelHeight] = useState(0);
|
|
35
|
+
if (open && !mounted) setMounted(true);
|
|
36
|
+
if (!open && !mounted && panelHeight !== 0) setPanelHeight(0);
|
|
37
|
+
const progress = useSharedValue(0);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (open) return;
|
|
40
|
+
progress.set(withTiming(0, {
|
|
41
|
+
duration: 180,
|
|
42
|
+
easing: Easing$1.in(Easing$1.cubic)
|
|
43
|
+
}, (finished) => {
|
|
44
|
+
"worklet";
|
|
45
|
+
if (finished) scheduleOnRN(setMounted, false);
|
|
46
|
+
}));
|
|
47
|
+
}, [open, progress]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!open || panelHeight === 0) return;
|
|
50
|
+
progress.set(withSpring(1, {
|
|
51
|
+
damping: 26,
|
|
52
|
+
stiffness: 260,
|
|
53
|
+
mass: .9
|
|
54
|
+
}));
|
|
55
|
+
}, [
|
|
56
|
+
open,
|
|
57
|
+
panelHeight,
|
|
58
|
+
progress
|
|
59
|
+
]);
|
|
60
|
+
const wasMounted = useRef(false);
|
|
61
|
+
const onClosedRef = useRef(onClosed);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
onClosedRef.current = onClosed;
|
|
64
|
+
});
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (mounted) {
|
|
67
|
+
wasMounted.current = true;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!wasMounted.current) return;
|
|
71
|
+
wasMounted.current = false;
|
|
72
|
+
onClosedRef.current?.();
|
|
73
|
+
}, [mounted]);
|
|
74
|
+
const scrimStyle = useAnimatedStyle(() => ({ opacity: progress.get() }), [progress]);
|
|
75
|
+
const panelStyle = useAnimatedStyle(() => ({
|
|
76
|
+
opacity: panelHeight === 0 ? 0 : 1,
|
|
77
|
+
transform: [{ translateY: (1 - progress.get()) * panelHeight }]
|
|
78
|
+
}), [progress, panelHeight]);
|
|
79
|
+
if (!mounted) return null;
|
|
80
|
+
return /* @__PURE__ */ jsx(Modal, {
|
|
81
|
+
visible: true,
|
|
82
|
+
transparent: true,
|
|
83
|
+
statusBarTranslucent: true,
|
|
84
|
+
animationType: "none",
|
|
85
|
+
onRequestClose: () => onOpenChange(false),
|
|
86
|
+
"aria-labelledby": ariaLabelledBy,
|
|
87
|
+
"aria-label": ariaLabel,
|
|
88
|
+
"aria-describedby": ariaDescribedBy,
|
|
89
|
+
children: /* @__PURE__ */ jsxs(View, {
|
|
90
|
+
style: { flex: 1 },
|
|
91
|
+
children: [/* @__PURE__ */ jsx(Animated$1.View, {
|
|
92
|
+
style: [StyleSheet.absoluteFill, scrimStyle],
|
|
93
|
+
children: /* @__PURE__ */ jsx(Pressable, {
|
|
94
|
+
accessible: false,
|
|
95
|
+
style: StyleSheet.absoluteFill,
|
|
96
|
+
className: "bg-scrim",
|
|
97
|
+
onPress: dismissOnBackdropPress ? () => onOpenChange(false) : void 0
|
|
98
|
+
})
|
|
99
|
+
}), /* @__PURE__ */ jsx(KeyboardAvoidingView, {
|
|
100
|
+
style: {
|
|
101
|
+
flex: 1,
|
|
102
|
+
justifyContent: "flex-end"
|
|
103
|
+
},
|
|
104
|
+
pointerEvents: "box-none",
|
|
105
|
+
behavior: Platform.OS === "ios" ? "padding" : "height",
|
|
106
|
+
children: /* @__PURE__ */ jsx(Animated$1.View, {
|
|
107
|
+
style: panelStyle,
|
|
108
|
+
onLayout: (event) => setPanelHeight(event.nativeEvent.layout.height),
|
|
109
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
110
|
+
className: "rounded-t-surface bg-popover shadow-lg",
|
|
111
|
+
style: { maxHeight: windowHeight * maxHeightRatio },
|
|
112
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
113
|
+
className: "overflow-hidden rounded-t-surface",
|
|
114
|
+
style: { flexShrink: 1 },
|
|
115
|
+
children
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
})]
|
|
120
|
+
})
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/** The grab cue (grabber), the heading and the close button. */
|
|
124
|
+
function SheetHeader({ title, description, closeLabel = CLOSE_LABEL, onClose, titleId, descriptionId }) {
|
|
125
|
+
const ink = useTokenColor("--ink-500");
|
|
126
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(View, {
|
|
127
|
+
className: "items-center pt-2 pb-1",
|
|
128
|
+
children: /* @__PURE__ */ jsx(View, { className: "h-1 w-9 bg-line" })
|
|
129
|
+
}), /* @__PURE__ */ jsxs(View, {
|
|
130
|
+
className: "flex-row items-start justify-between gap-2 border-b border-line px-4 pt-1 pb-3",
|
|
131
|
+
children: [/* @__PURE__ */ jsxs(View, {
|
|
132
|
+
className: "shrink gap-1",
|
|
133
|
+
children: [!isBlankNode(title) ? /* @__PURE__ */ jsx(Text$1, {
|
|
134
|
+
id: titleId,
|
|
135
|
+
role: "heading",
|
|
136
|
+
"aria-level": "2",
|
|
137
|
+
className: "text-base font-semibold",
|
|
138
|
+
children: title
|
|
139
|
+
}) : null, !isBlankNode(description) ? /* @__PURE__ */ jsx(Text$1, {
|
|
140
|
+
id: descriptionId,
|
|
141
|
+
className: "text-muted-foreground text-sm",
|
|
142
|
+
children: description
|
|
143
|
+
}) : null]
|
|
144
|
+
}), /* @__PURE__ */ jsx(Pressable, {
|
|
145
|
+
accessibilityRole: "button",
|
|
146
|
+
accessibilityLabel: closeLabel,
|
|
147
|
+
hitSlop: 12,
|
|
148
|
+
onPress: onClose,
|
|
149
|
+
children: /* @__PURE__ */ jsx(Feather, {
|
|
150
|
+
name: "x",
|
|
151
|
+
size: 16,
|
|
152
|
+
color: ink
|
|
153
|
+
})
|
|
154
|
+
})]
|
|
155
|
+
})] });
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The sheet body.
|
|
159
|
+
*
|
|
160
|
+
* `contentContainerClassName` **does not work** with react-native-css (the padding silently disappears and
|
|
161
|
+
* text gets clipped at the edge). Always write padding in `contentContainerStyle`.
|
|
162
|
+
*/
|
|
163
|
+
function SheetScroll({ padded = true, hasFooter = false, children }) {
|
|
164
|
+
const insets = useSafeAreaInsets();
|
|
165
|
+
return /* @__PURE__ */ jsx(ScrollView, {
|
|
166
|
+
style: { flexShrink: 1 },
|
|
167
|
+
contentContainerStyle: {
|
|
168
|
+
gap: padded ? GUTTER : 0,
|
|
169
|
+
paddingHorizontal: padded ? GUTTER : 0,
|
|
170
|
+
paddingTop: padded ? GUTTER : 0,
|
|
171
|
+
paddingBottom: (padded ? GUTTER : 0) + (hasFooter ? 0 : insets.bottom)
|
|
172
|
+
},
|
|
173
|
+
children
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/** The sheet footer. Adds the safe area so it does not slip under the home indicator. */
|
|
177
|
+
function SheetFooter({ children }) {
|
|
178
|
+
const insets = useSafeAreaInsets();
|
|
179
|
+
return /* @__PURE__ */ jsx(View, {
|
|
180
|
+
className: "flex-row justify-end gap-2 border-t border-line px-4 pt-3",
|
|
181
|
+
style: { paddingBottom: 12 + insets.bottom },
|
|
182
|
+
children
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//#endregion
|
|
187
|
+
export { SheetFooter, SheetHeader, SheetScroll, SheetShell };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React$1 from "react";
|
|
2
|
+
import { Text as Text$1 } from "react-native";
|
|
3
|
+
import { VariantProps } from "class-variance-authority";
|
|
4
|
+
//#region src/native/base/text.d.ts
|
|
5
|
+
declare const textVariants: (props?: ({
|
|
6
|
+
variant?: "blockquote" | "code" | "default" | "h1" | "h2" | "h3" | "h4" | "large" | "lead" | "muted" | "p" | "small" | null | undefined;
|
|
7
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
|
+
type TextVariantProps = VariantProps<typeof textVariants>;
|
|
9
|
+
declare const TextClassContext: React$1.Context<string | undefined>;
|
|
10
|
+
declare function Text({ className, asChild, variant, ...props }: React$1.ComponentProps<typeof Text$1> & TextVariantProps & React$1.RefAttributes<Text$1> & {
|
|
11
|
+
asChild?: boolean;
|
|
12
|
+
}): React$1.JSX.Element;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { Text, TextClassContext };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import * as React$1 from "react";
|
|
3
|
+
import { Platform, Text as Text$1 } from "react-native";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import * as Slot from "@rn-primitives/slot";
|
|
6
|
+
import { cva } from "class-variance-authority";
|
|
7
|
+
|
|
8
|
+
//#region src/native/base/text.tsx
|
|
9
|
+
const textVariants = cva(cn("text-foreground font-sans text-base", Platform.select({ web: "select-text" })), {
|
|
10
|
+
variants: { variant: {
|
|
11
|
+
default: "",
|
|
12
|
+
h1: cn("text-center text-4xl font-extrabold tracking-tight", Platform.select({ web: "scroll-m-20 text-balance" })),
|
|
13
|
+
h2: cn("border-line border-b pb-2 text-3xl font-semibold tracking-tight", Platform.select({ web: "scroll-m-20 first:mt-0" })),
|
|
14
|
+
h3: cn("text-2xl font-semibold tracking-tight", Platform.select({ web: "scroll-m-20" })),
|
|
15
|
+
h4: cn("text-xl font-semibold tracking-tight", Platform.select({ web: "scroll-m-20" })),
|
|
16
|
+
p: "mt-3 leading-7 sm:mt-6",
|
|
17
|
+
blockquote: "mt-4 border-l-2 pl-3 italic sm:mt-6 sm:pl-6",
|
|
18
|
+
code: cn("bg-muted rounded-control relative px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold"),
|
|
19
|
+
lead: "text-muted-foreground text-xl",
|
|
20
|
+
large: "text-lg font-semibold",
|
|
21
|
+
small: "text-sm font-medium leading-none",
|
|
22
|
+
muted: "text-muted-foreground text-sm"
|
|
23
|
+
} },
|
|
24
|
+
defaultVariants: { variant: "default" }
|
|
25
|
+
});
|
|
26
|
+
const ROLE = {
|
|
27
|
+
h1: "heading",
|
|
28
|
+
h2: "heading",
|
|
29
|
+
h3: "heading",
|
|
30
|
+
h4: "heading",
|
|
31
|
+
blockquote: Platform.select({ web: "blockquote" }),
|
|
32
|
+
code: Platform.select({ web: "code" })
|
|
33
|
+
};
|
|
34
|
+
const ARIA_LEVEL = {
|
|
35
|
+
h1: "1",
|
|
36
|
+
h2: "2",
|
|
37
|
+
h3: "3",
|
|
38
|
+
h4: "4"
|
|
39
|
+
};
|
|
40
|
+
const TextClassContext = React$1.createContext(void 0);
|
|
41
|
+
function Text({ className, asChild = false, variant = "default", ...props }) {
|
|
42
|
+
const textClass = React$1.useContext(TextClassContext);
|
|
43
|
+
const Component = asChild ? Slot.Text : Text$1;
|
|
44
|
+
return /* @__PURE__ */ jsx(Component, {
|
|
45
|
+
className: cn(textVariants({ variant }), textClass, className),
|
|
46
|
+
role: variant ? ROLE[variant] : void 0,
|
|
47
|
+
"aria-level": variant ? ARIA_LEVEL[variant] : void 0,
|
|
48
|
+
...props
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
export { Text, TextClassContext };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseInputProps } from "../../shared/form.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/native/form/checkbox.d.ts
|
|
4
|
+
export type CheckboxProps = BaseInputProps<boolean> & {
|
|
5
|
+
/** Label placed to the right of the checkbox. Distinct from the field's `label` (this one becomes the checkbox's name). */
|
|
6
|
+
checkboxLabel: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Checkbox integrated with TanStack Form. Like the web `form/checkbox`,
|
|
10
|
+
* pass `value` / `onValueChange` for controlled mode (the field is not used); omit them to read from the field context.
|
|
11
|
+
*/
|
|
12
|
+
export declare function Checkbox(props: CheckboxProps): import("react").JSX.Element;
|
|
13
|
+
//#endregion
|