@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,52 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { activateOnSpace } from "../lib/keyboard.js";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { Animated, Platform, Pressable } from "react-native";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/native/atom/switch.tsx
|
|
8
|
+
const TRACK_PADDING = 1;
|
|
9
|
+
const KNOB_TRAVEL = 19;
|
|
10
|
+
/**
|
|
11
|
+
* A round switch identical to the web base/switch (on is filled indigo, off is a wash surface with a line-control border).
|
|
12
|
+
*
|
|
13
|
+
* When the OS-standard switch is needed, use the `@expo/ui` one in `base/`. This is
|
|
14
|
+
* an RN implementation that prioritizes looking the same as the web.
|
|
15
|
+
*/
|
|
16
|
+
function Switch({ checked, onCheckedChange, disabled, accessibilityLabel, accessibilityHint, className, id, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid }) {
|
|
17
|
+
const progress = useRef(new Animated.Value(checked ? 1 : 0)).current;
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
Animated.timing(progress, {
|
|
20
|
+
toValue: checked ? 1 : 0,
|
|
21
|
+
duration: 150,
|
|
22
|
+
useNativeDriver: Platform.OS !== "web"
|
|
23
|
+
}).start();
|
|
24
|
+
}, [checked, progress]);
|
|
25
|
+
const translateX = progress.interpolate({
|
|
26
|
+
inputRange: [0, 1],
|
|
27
|
+
outputRange: [TRACK_PADDING, KNOB_TRAVEL]
|
|
28
|
+
});
|
|
29
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
30
|
+
accessibilityRole: "switch",
|
|
31
|
+
accessibilityLabel,
|
|
32
|
+
accessibilityHint,
|
|
33
|
+
id,
|
|
34
|
+
"aria-labelledby": ariaLabelledBy,
|
|
35
|
+
"aria-describedby": ariaDescribedBy,
|
|
36
|
+
"aria-invalid": ariaInvalid,
|
|
37
|
+
"aria-checked": checked,
|
|
38
|
+
"aria-disabled": disabled,
|
|
39
|
+
onPress: () => onCheckedChange(!checked),
|
|
40
|
+
onKeyDown: activateOnSpace(() => onCheckedChange(!checked), disabled),
|
|
41
|
+
disabled,
|
|
42
|
+
hitSlop: 12,
|
|
43
|
+
className: cn("h-5 w-9 shrink-0 justify-center rounded-full border", checked ? "border-action bg-action" : "border-line-control bg-wash", disabled && "opacity-50", className),
|
|
44
|
+
children: /* @__PURE__ */ jsx(Animated.View, {
|
|
45
|
+
style: { transform: [{ translateX }] },
|
|
46
|
+
className: "h-3.5 w-3.5 rounded-full bg-white shadow-xs"
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
export { Switch };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SymbolProps } from "./symbol.types.js";
|
|
2
|
+
//#region src/native/atom/symbol.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* An icon. Drawn with SF Symbols on iOS and Material Symbols on Android.
|
|
5
|
+
*
|
|
6
|
+
* **Passing an SF name to `SymbolView` as a string draws nothing on Android.**
|
|
7
|
+
* No exception or warning is raised, so the icon silently disappears (for example the search magnifier,
|
|
8
|
+
* the settings gear, a row's `>` and empty-state icons all vanish). The Android implementation
|
|
9
|
+
* only runs when the name is passed as `{ ios, android }`, so **apps must always use this component**.
|
|
10
|
+
*
|
|
11
|
+
* The mapping table is in `symbol.types.ts`. SF names missing from the table are not drawn on Android,
|
|
12
|
+
* so `fallback` renders an empty box of the icon's size to keep the space where the icon should be (the layout does not collapse).
|
|
13
|
+
*/
|
|
14
|
+
export declare function Symbol({ name, size, tintColor, accessibilityLabel, className, style }: SymbolProps): import("react").JSX.Element;
|
|
15
|
+
//#endregion
|
|
16
|
+
export type { SymbolProps };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SF_TO_ANDROID } from "./symbol.types.js";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { SymbolView } from "expo-symbols";
|
|
5
|
+
|
|
6
|
+
//#region src/native/atom/symbol.tsx
|
|
7
|
+
/**
|
|
8
|
+
* An icon. Drawn with SF Symbols on iOS and Material Symbols on Android.
|
|
9
|
+
*
|
|
10
|
+
* **Passing an SF name to `SymbolView` as a string draws nothing on Android.**
|
|
11
|
+
* No exception or warning is raised, so the icon silently disappears (for example the search magnifier,
|
|
12
|
+
* the settings gear, a row's `>` and empty-state icons all vanish). The Android implementation
|
|
13
|
+
* only runs when the name is passed as `{ ios, android }`, so **apps must always use this component**.
|
|
14
|
+
*
|
|
15
|
+
* The mapping table is in `symbol.types.ts`. SF names missing from the table are not drawn on Android,
|
|
16
|
+
* so `fallback` renders an empty box of the icon's size to keep the space where the icon should be (the layout does not collapse).
|
|
17
|
+
*/
|
|
18
|
+
function Symbol({ name, size = 20, tintColor, accessibilityLabel, className, style }) {
|
|
19
|
+
const android = SF_TO_ANDROID[name];
|
|
20
|
+
return /* @__PURE__ */ jsx(SymbolView, {
|
|
21
|
+
name: android ? {
|
|
22
|
+
ios: name,
|
|
23
|
+
android
|
|
24
|
+
} : name,
|
|
25
|
+
size,
|
|
26
|
+
tintColor,
|
|
27
|
+
accessibilityLabel,
|
|
28
|
+
style,
|
|
29
|
+
className,
|
|
30
|
+
fallback: /* @__PURE__ */ jsx(View, { style: {
|
|
31
|
+
width: size,
|
|
32
|
+
height: size
|
|
33
|
+
} })
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { Symbol };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { StyleProp, ViewStyle } from "react-native";
|
|
2
|
+
import { AndroidSymbol, SFSymbol } from "expo-symbols";
|
|
3
|
+
//#region src/native/atom/symbol.types.d.ts
|
|
4
|
+
export type SymbolProps = {
|
|
5
|
+
/** The SF Symbol name. On Android it is mapped to Material Symbols via `SF_TO_ANDROID`. */
|
|
6
|
+
name: SFSymbol;
|
|
7
|
+
size?: number;
|
|
8
|
+
tintColor?: string;
|
|
9
|
+
accessibilityLabel?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
style?: StyleProp<ViewStyle>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Mapping table from SF Symbol to Material Symbols (Android).
|
|
15
|
+
*
|
|
16
|
+
* **`SymbolView` draws nothing on Android when `name` is passed as a string.**
|
|
17
|
+
* The Android implementation (the Material Symbols font) only runs when `name` is passed as `{ ios, android }`.
|
|
18
|
+
* Passing SF names as plain strings makes icons such as the search magnifier, the settings gear,
|
|
19
|
+
* a row's `>` and empty-state icons **disappear on Android without any exception or warning**.
|
|
20
|
+
*
|
|
21
|
+
* **Do not collapse the fill distinction.** SF sometimes expresses selected or
|
|
22
|
+
* checked state only through `circle` vs `circle.fill`, so the Android side maps them to different icons.
|
|
23
|
+
*/
|
|
24
|
+
export declare const SF_TO_ANDROID: Record<string, AndroidSymbol>;
|
|
25
|
+
//#endregion
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/native/atom/symbol.types.ts
|
|
2
|
+
/**
|
|
3
|
+
* Mapping table from SF Symbol to Material Symbols (Android).
|
|
4
|
+
*
|
|
5
|
+
* **`SymbolView` draws nothing on Android when `name` is passed as a string.**
|
|
6
|
+
* The Android implementation (the Material Symbols font) only runs when `name` is passed as `{ ios, android }`.
|
|
7
|
+
* Passing SF names as plain strings makes icons such as the search magnifier, the settings gear,
|
|
8
|
+
* a row's `>` and empty-state icons **disappear on Android without any exception or warning**.
|
|
9
|
+
*
|
|
10
|
+
* **Do not collapse the fill distinction.** SF sometimes expresses selected or
|
|
11
|
+
* checked state only through `circle` vs `circle.fill`, so the Android side maps them to different icons.
|
|
12
|
+
*/
|
|
13
|
+
const SF_TO_ANDROID = {
|
|
14
|
+
archivebox: "archive",
|
|
15
|
+
book: "book",
|
|
16
|
+
"book.fill": "menu_book",
|
|
17
|
+
calendar: "calendar_month",
|
|
18
|
+
"chart.bar": "bar_chart",
|
|
19
|
+
"chart.pie": "pie_chart_outline",
|
|
20
|
+
"chart.pie.fill": "pie_chart",
|
|
21
|
+
checkmark: "check",
|
|
22
|
+
"checkmark.circle.fill": "check_circle",
|
|
23
|
+
"chevron.left": "chevron_left",
|
|
24
|
+
"chevron.right": "chevron_right",
|
|
25
|
+
circle: "circle",
|
|
26
|
+
"circle.fill": "brightness_1",
|
|
27
|
+
"doc.on.doc": "content_copy",
|
|
28
|
+
gearshape: "settings",
|
|
29
|
+
"info.circle": "info",
|
|
30
|
+
"line.3.horizontal.decrease": "filter_list",
|
|
31
|
+
"line.3.horizontal.decrease.circle.fill": "filter_alt",
|
|
32
|
+
link: "link",
|
|
33
|
+
"link.badge.plus": "add_link",
|
|
34
|
+
lock: "lock_open",
|
|
35
|
+
"lock.fill": "lock",
|
|
36
|
+
magnifyingglass: "search",
|
|
37
|
+
"note.text": "note",
|
|
38
|
+
pencil: "edit",
|
|
39
|
+
"square.and.arrow.up": "ios_share",
|
|
40
|
+
"square.stack": "stack",
|
|
41
|
+
"square.stack.3d.up": "stack_group",
|
|
42
|
+
"square.stack.fill": "layers",
|
|
43
|
+
tray: "inbox",
|
|
44
|
+
"tray.and.arrow.up": "unarchive",
|
|
45
|
+
xmark: "close"
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
export { SF_TO_ANDROID };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ControlA11yProps } from "../lib/control.js";
|
|
2
|
+
import { AutoComplete } from "../lib/autocomplete.js";
|
|
3
|
+
//#region src/native/atom/text-field.d.ts
|
|
4
|
+
export type TextFieldType = "text" | "number" | "password" | "email" | "tel";
|
|
5
|
+
export type TextFieldProps = ControlA11yProps & {
|
|
6
|
+
value: string;
|
|
7
|
+
onChangeText: (text: string) => void;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
type?: TextFieldType;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
/** Error state. The border becomes destructive and `aria-invalid` is set (inside a form, `FormControl` passes it). */
|
|
12
|
+
invalid?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* The kind of autofill (the same terms as the web `TextInput.autoComplete`: `email`, `current-password`, `one-time-code`, etc.).
|
|
15
|
+
* Passed straight to RN's `autoComplete`, and on iOS also mapped to `textContentType` (`lib/autocomplete.ts`).
|
|
16
|
+
* The type is narrower than the web's (only the terms RN accepts).
|
|
17
|
+
*/
|
|
18
|
+
autoComplete?: AutoComplete;
|
|
19
|
+
autoCapitalize?: "none" | "sentences" | "words" | "characters";
|
|
20
|
+
/** `false` turns off autocorrection (such as smart-quote replacement). Use it for fields where JSON, code or IDs are typed. */
|
|
21
|
+
autoCorrect?: boolean;
|
|
22
|
+
/** Called when focus leaves the field (used to commit or discard the text being typed). */
|
|
23
|
+
onBlur?: () => void;
|
|
24
|
+
multiline?: boolean;
|
|
25
|
+
/** Approximate number of lines when multiline (use together with `multiline`). */
|
|
26
|
+
numberOfLines?: number;
|
|
27
|
+
onSubmitEditing?: () => void;
|
|
28
|
+
returnKeyType?: "done" | "go" | "next" | "search" | "send";
|
|
29
|
+
accessibilityLabel?: string;
|
|
30
|
+
/**
|
|
31
|
+
* An identifier for targeting the field uniquely from E2E (becomes accessibilityIdentifier on iOS).
|
|
32
|
+
*
|
|
33
|
+
* In a form where the label and the input share the same text, matching by text **hits the heading
|
|
34
|
+
* and the input gets cleared** (observed with Maestro). Set it on any input that must be targeted.
|
|
35
|
+
*/
|
|
36
|
+
testID?: string;
|
|
37
|
+
className?: string;
|
|
38
|
+
};
|
|
39
|
+
export declare const textFieldClass = "min-h-9 w-full rounded-control border border-line-strong bg-raised px-3 py-1.5 text-sm text-foreground";
|
|
40
|
+
/**
|
|
41
|
+
* A plain text input. The input frame corresponding to the web base/input,
|
|
42
|
+
* used directly on screens that do not use TanStack Form (login, settings, memo fields, etc.).
|
|
43
|
+
*
|
|
44
|
+
* `base/input` is the OS-native TextField from `@expo/ui`, so it **cannot be painted with tokens**.
|
|
45
|
+
* Use this one for inputs that should look the same as the web. When form integration is needed,
|
|
46
|
+
* use `form/text-input` (which uses this one internally).
|
|
47
|
+
*/
|
|
48
|
+
export declare function TextField({ value, onChangeText, placeholder, type, disabled, invalid, autoComplete, autoCapitalize, autoCorrect, onBlur, multiline, numberOfLines, onSubmitEditing, returnKeyType, accessibilityLabel, accessibilityHint, testID, className, id, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid }: TextFieldProps): import("react").JSX.Element;
|
|
49
|
+
//#endregion
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { textContentTypeOf } from "../lib/autocomplete.js";
|
|
4
|
+
import { TextInput } from "react-native";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/native/atom/text-field.tsx
|
|
8
|
+
const textFieldClass = "min-h-9 w-full rounded-control border border-line-strong bg-raised px-3 py-1.5 text-sm text-foreground";
|
|
9
|
+
const KEYBOARD = {
|
|
10
|
+
text: "default",
|
|
11
|
+
number: "decimal-pad",
|
|
12
|
+
password: "default",
|
|
13
|
+
email: "email-address",
|
|
14
|
+
tel: "phone-pad"
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A plain text input. The input frame corresponding to the web base/input,
|
|
18
|
+
* used directly on screens that do not use TanStack Form (login, settings, memo fields, etc.).
|
|
19
|
+
*
|
|
20
|
+
* `base/input` is the OS-native TextField from `@expo/ui`, so it **cannot be painted with tokens**.
|
|
21
|
+
* Use this one for inputs that should look the same as the web. When form integration is needed,
|
|
22
|
+
* use `form/text-input` (which uses this one internally).
|
|
23
|
+
*/
|
|
24
|
+
function TextField({ value, onChangeText, placeholder, type = "text", disabled, invalid, autoComplete, autoCapitalize, autoCorrect, onBlur, multiline, numberOfLines, onSubmitEditing, returnKeyType, accessibilityLabel, accessibilityHint, testID, className, id, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid }) {
|
|
25
|
+
const mutedInk = useTokenColor("--ink-500");
|
|
26
|
+
const isInvalid = invalid ?? ariaInvalid;
|
|
27
|
+
return /* @__PURE__ */ jsx(TextInput, {
|
|
28
|
+
value,
|
|
29
|
+
onChangeText,
|
|
30
|
+
placeholder,
|
|
31
|
+
placeholderTextColor: mutedInk,
|
|
32
|
+
editable: !disabled,
|
|
33
|
+
secureTextEntry: type === "password",
|
|
34
|
+
keyboardType: KEYBOARD[type],
|
|
35
|
+
autoComplete,
|
|
36
|
+
textContentType: textContentTypeOf(autoComplete),
|
|
37
|
+
autoCapitalize: autoCapitalize ?? (type === "email" ? "none" : void 0),
|
|
38
|
+
autoCorrect: autoCorrect ?? (type === "email" ? false : void 0),
|
|
39
|
+
onBlur,
|
|
40
|
+
multiline,
|
|
41
|
+
numberOfLines,
|
|
42
|
+
onSubmitEditing,
|
|
43
|
+
returnKeyType,
|
|
44
|
+
accessibilityLabel,
|
|
45
|
+
accessibilityHint,
|
|
46
|
+
id,
|
|
47
|
+
"aria-labelledby": ariaLabelledBy,
|
|
48
|
+
"aria-describedby": ariaDescribedBy,
|
|
49
|
+
"aria-invalid": isInvalid,
|
|
50
|
+
testID,
|
|
51
|
+
className: cn(textFieldClass, multiline && "min-h-[72px] py-2", isInvalid && "border-destructive", disabled && "opacity-50", className)
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { TextField, textFieldClass };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ActiveScheme } from "../lib/scheme.js";
|
|
2
|
+
import "../lib/theme.js";
|
|
3
|
+
//#region src/native/atom/theme-toggle.d.ts
|
|
4
|
+
export type ThemeToggleProps = {
|
|
5
|
+
/** Receives the theme to switch to (`light` / `dark`). Where it is stored (AsyncStorage, jotai, etc.) is up to the app. */
|
|
6
|
+
onSchemeChange: (scheme: ActiveScheme) => void;
|
|
7
|
+
/** The current theme. When omitted, follows `useActiveScheme()` (`ThemeRoot`, or the device setting if there is none). */
|
|
8
|
+
scheme?: ActiveScheme;
|
|
9
|
+
/** Label for screen readers. */
|
|
10
|
+
accessibilityLabel?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Switches between light and dark with a single tap.
|
|
15
|
+
* If a three-way choice including "follow system" is needed, the app owns the `ThemeRoot` `preference` directly.
|
|
16
|
+
*
|
|
17
|
+
* love3 has no place to store the theme (`ThemeRoot` receives
|
|
18
|
+
* `preference` via props), so the next theme is handed over through `onSchemeChange`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function ThemeToggle({ onSchemeChange, scheme: schemeProp, accessibilityLabel, className }: ThemeToggleProps): import("react").JSX.Element;
|
|
21
|
+
//#endregion
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useActiveScheme } from "../lib/theme.js";
|
|
2
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { Platform, Pressable } from "react-native";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import Feather from "@expo/vector-icons/Feather";
|
|
7
|
+
|
|
8
|
+
//#region src/native/atom/theme-toggle.tsx
|
|
9
|
+
/**
|
|
10
|
+
* Switches between light and dark with a single tap.
|
|
11
|
+
* If a three-way choice including "follow system" is needed, the app owns the `ThemeRoot` `preference` directly.
|
|
12
|
+
*
|
|
13
|
+
* love3 has no place to store the theme (`ThemeRoot` receives
|
|
14
|
+
* `preference` via props), so the next theme is handed over through `onSchemeChange`.
|
|
15
|
+
*/
|
|
16
|
+
function ThemeToggle({ onSchemeChange, scheme: schemeProp, accessibilityLabel = "テーマ切り替え", className }) {
|
|
17
|
+
const active = useActiveScheme();
|
|
18
|
+
const scheme = schemeProp ?? active;
|
|
19
|
+
const ink = useTokenColor("--ink-500");
|
|
20
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
21
|
+
accessibilityRole: "button",
|
|
22
|
+
accessibilityLabel,
|
|
23
|
+
onPress: () => onSchemeChange(scheme === "dark" ? "light" : "dark"),
|
|
24
|
+
...Platform.OS === "web" ? { "aria-pressed": scheme === "dark" } : { "aria-selected": scheme === "dark" },
|
|
25
|
+
hitSlop: 12,
|
|
26
|
+
className: cn("h-8 w-8 items-center justify-center rounded-control", className),
|
|
27
|
+
children: /* @__PURE__ */ jsx(Feather, {
|
|
28
|
+
name: scheme === "dark" ? "sun" : "moon",
|
|
29
|
+
size: 16,
|
|
30
|
+
color: ink
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { ThemeToggle };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SelectProps } from "./select.js";
|
|
2
|
+
//#region src/native/atom/timezone-select.d.ts
|
|
3
|
+
export type TimezoneSelectProps = Pick<SelectProps, "label" | "description" | "placeholder" | "disabled" | "size" | "className" | "wrapperClassName" | "sheetTitle" | "closeLabel" | "accessibilityLabel"> & {
|
|
4
|
+
/** The selected IANA time zone. An empty string means "not decided yet" (the placeholder is shown). */
|
|
5
|
+
value: string;
|
|
6
|
+
onValueChange: (zone: string) => void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A Select for choosing a time zone (IANA string). Same name and props as the web atom/timezone-select.
|
|
10
|
+
*
|
|
11
|
+
* The options are a fixed list of major cities plus this device's time zone and the selected value (`lib/timezone.ts`).
|
|
12
|
+
* The list is fixed because Hermes has no `Intl.supportedValuesOf`.
|
|
13
|
+
* It is chosen in a bottom sheet, so pass `closeLabel` in the caller's language (the default is Japanese).
|
|
14
|
+
*/
|
|
15
|
+
export declare function TimezoneSelect({ value, onValueChange, ...props }: TimezoneSelectProps): import("react").JSX.Element;
|
|
16
|
+
//#endregion
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Select } from "./select.js";
|
|
2
|
+
import { formatTimeZoneLabel, getDeviceTimeZone, timeZoneOptions } from "../lib/timezone.js";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/native/atom/timezone-select.tsx
|
|
7
|
+
/**
|
|
8
|
+
* A Select for choosing a time zone (IANA string). Same name and props as the web atom/timezone-select.
|
|
9
|
+
*
|
|
10
|
+
* The options are a fixed list of major cities plus this device's time zone and the selected value (`lib/timezone.ts`).
|
|
11
|
+
* The list is fixed because Hermes has no `Intl.supportedValuesOf`.
|
|
12
|
+
* It is chosen in a bottom sheet, so pass `closeLabel` in the caller's language (the default is Japanese).
|
|
13
|
+
*/
|
|
14
|
+
function TimezoneSelect({ value, onValueChange, ...props }) {
|
|
15
|
+
const options = useMemo(() => timeZoneOptions(getDeviceTimeZone(), value).map((zone) => ({
|
|
16
|
+
value: zone,
|
|
17
|
+
label: formatTimeZoneLabel(zone)
|
|
18
|
+
})), [value]);
|
|
19
|
+
return /* @__PURE__ */ jsx(Select, {
|
|
20
|
+
...props,
|
|
21
|
+
value,
|
|
22
|
+
onValueChange,
|
|
23
|
+
options
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { TimezoneSelect };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/native/atom/typography.d.ts
|
|
3
|
+
export type SectionTitleProps = {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
description?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A section heading. Mirrors SectionTitle of the web atom/typography.
|
|
10
|
+
* Same structure: a 2px indigo bar on the left edge + a bold heading + an optional description.
|
|
11
|
+
*/
|
|
12
|
+
export declare function SectionTitle({ children, description, className }: SectionTitleProps): import("react").JSX.Element;
|
|
13
|
+
//#endregion
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/native/atom/typography.tsx
|
|
7
|
+
/**
|
|
8
|
+
* A section heading. Mirrors SectionTitle of the web atom/typography.
|
|
9
|
+
* Same structure: a 2px indigo bar on the left edge + a bold heading + an optional description.
|
|
10
|
+
*/
|
|
11
|
+
function SectionTitle({ children, description, className }) {
|
|
12
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
13
|
+
className: "gap-0.5",
|
|
14
|
+
children: [/* @__PURE__ */ jsxs(View, {
|
|
15
|
+
className: "flex-row items-center py-2 pl-3",
|
|
16
|
+
children: [/* @__PURE__ */ jsx(View, { className: "absolute inset-y-2 left-1 w-0.5 bg-action/70" }), /* @__PURE__ */ jsx(Text$1, {
|
|
17
|
+
className: cn("text-sm font-semibold", className),
|
|
18
|
+
children
|
|
19
|
+
})]
|
|
20
|
+
}), description ? /* @__PURE__ */ jsx(Text$1, {
|
|
21
|
+
className: "text-muted-foreground text-sm",
|
|
22
|
+
children: description
|
|
23
|
+
}) : null]
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { SectionTitle };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ButtonVariant } from "../../shared/button.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { ViewStyle } from "react-native";
|
|
4
|
+
//#region src/native/base/button.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The button's appearance variants. **The same names as `atom/button` (and the web Button)** (`ButtonVariant` from `@lt-three/love3/shared`),
|
|
7
|
+
* plus `glass`, which exists only for iOS 26 Liquid Glass.
|
|
8
|
+
* - `glass`: the iOS 26 Liquid Glass button (for primary actions; falls back to a filled button below iOS 26 and on Android)
|
|
9
|
+
* - The others mean the same as in `atom/button`. They are mapped onto the three shapes the OS control has (filled, outlined, text only) (see the tables below)
|
|
10
|
+
*/
|
|
11
|
+
export type NativeButtonVariant = ButtonVariant | "glass";
|
|
12
|
+
declare const IOS_BUTTON_STYLE: {
|
|
13
|
+
readonly default: "borderedProminent";
|
|
14
|
+
readonly destructive: "borderedProminent";
|
|
15
|
+
readonly outline: "bordered";
|
|
16
|
+
readonly secondary: "bordered";
|
|
17
|
+
readonly ghost: "plain";
|
|
18
|
+
readonly link: "plain";
|
|
19
|
+
readonly plate: "bordered";
|
|
20
|
+
readonly "<3": "borderedProminent";
|
|
21
|
+
readonly glass: "glassProminent";
|
|
22
|
+
};
|
|
23
|
+
declare const UNIVERSAL_VARIANT: {
|
|
24
|
+
readonly default: "filled";
|
|
25
|
+
readonly destructive: "filled";
|
|
26
|
+
readonly outline: "outlined";
|
|
27
|
+
readonly secondary: "filled";
|
|
28
|
+
readonly ghost: "text";
|
|
29
|
+
readonly link: "text";
|
|
30
|
+
readonly plate: "outlined";
|
|
31
|
+
readonly "<3": "filled";
|
|
32
|
+
readonly glass: "filled";
|
|
33
|
+
};
|
|
34
|
+
type ButtonProps = {
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
onPress?: () => void;
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
variant?: NativeButtonVariant;
|
|
39
|
+
/**
|
|
40
|
+
* The accent color (SwiftUI `.tint()` on iOS). When omitted, the token color matching the variant
|
|
41
|
+
* (`default` is the primary action's indigo, `destructive` is destructive-solid, `<3` is the brand color).
|
|
42
|
+
*/
|
|
43
|
+
tintColor?: string;
|
|
44
|
+
/**
|
|
45
|
+
* The label text color (SwiftUI `.foregroundStyle()` on iOS). When omitted, the token color paired to be readable on the fill.
|
|
46
|
+
* Prominent styles default to a white label, so combining them with a light tint makes the label unreadable (the same applies on surfaces that invert).
|
|
47
|
+
*/
|
|
48
|
+
labelColor?: string;
|
|
49
|
+
/** Style applied to the Host container (an RN View). Used to adjust width and margins. */
|
|
50
|
+
style?: ViewStyle;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* The native button (the OS control layer). Renders SwiftUI's `Button` on iOS and Jetpack Compose's
|
|
54
|
+
* `Button` on Android (via `@expo/ui` universal). On iOS 26, `glass` becomes Liquid Glass.
|
|
55
|
+
*
|
|
56
|
+
* The **OS-native base layer** counterpart of `atom/button` (an RN `Pressable`, a button painted with tokens).
|
|
57
|
+
* Use `atom/button` where it should look the same as the web, and this one where the OS's standard look and feel is wanted.
|
|
58
|
+
*/
|
|
59
|
+
declare function Button({ children, onPress, disabled, variant, tintColor, labelColor, style }: ButtonProps): import("react").JSX.Element;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { Button, type ButtonProps, IOS_BUTTON_STYLE, UNIVERSAL_VARIANT };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { Platform } from "react-native";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { Button as Button$1, Host } from "@expo/ui";
|
|
5
|
+
import { buttonStyle, foregroundStyle, tint } from "@expo/ui/swift-ui/modifiers";
|
|
6
|
+
|
|
7
|
+
//#region src/native/base/button.tsx
|
|
8
|
+
const IOS_BUTTON_STYLE = {
|
|
9
|
+
default: "borderedProminent",
|
|
10
|
+
destructive: "borderedProminent",
|
|
11
|
+
outline: "bordered",
|
|
12
|
+
secondary: "bordered",
|
|
13
|
+
ghost: "plain",
|
|
14
|
+
link: "plain",
|
|
15
|
+
plate: "bordered",
|
|
16
|
+
"<3": "borderedProminent",
|
|
17
|
+
glass: "glassProminent"
|
|
18
|
+
};
|
|
19
|
+
const UNIVERSAL_VARIANT = {
|
|
20
|
+
default: "filled",
|
|
21
|
+
destructive: "filled",
|
|
22
|
+
outline: "outlined",
|
|
23
|
+
secondary: "filled",
|
|
24
|
+
ghost: "text",
|
|
25
|
+
link: "text",
|
|
26
|
+
plate: "outlined",
|
|
27
|
+
"<3": "filled",
|
|
28
|
+
glass: "filled"
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The native button (the OS control layer). Renders SwiftUI's `Button` on iOS and Jetpack Compose's
|
|
32
|
+
* `Button` on Android (via `@expo/ui` universal). On iOS 26, `glass` becomes Liquid Glass.
|
|
33
|
+
*
|
|
34
|
+
* The **OS-native base layer** counterpart of `atom/button` (an RN `Pressable`, a button painted with tokens).
|
|
35
|
+
* Use `atom/button` where it should look the same as the web, and this one where the OS's standard look and feel is wanted.
|
|
36
|
+
*/
|
|
37
|
+
function Button({ children, onPress, disabled, variant = "default", tintColor, labelColor, style }) {
|
|
38
|
+
const primary = useTokenColor("--primary");
|
|
39
|
+
const primaryForeground = useTokenColor("--primary-foreground");
|
|
40
|
+
const destructive = useTokenColor("--destructive-solid");
|
|
41
|
+
const destructiveForeground = useTokenColor("--destructive-solid-foreground");
|
|
42
|
+
const actionInk = useTokenColor("--action-ink");
|
|
43
|
+
const brand = useTokenColor("--lt-three");
|
|
44
|
+
const brandForeground = useTokenColor("--lt-three-foreground");
|
|
45
|
+
const foreground = useTokenColor("--foreground");
|
|
46
|
+
const defaults = {
|
|
47
|
+
default: {
|
|
48
|
+
tint: primary,
|
|
49
|
+
label: primaryForeground
|
|
50
|
+
},
|
|
51
|
+
destructive: {
|
|
52
|
+
tint: destructive,
|
|
53
|
+
label: destructiveForeground
|
|
54
|
+
},
|
|
55
|
+
outline: { tint: foreground },
|
|
56
|
+
secondary: { tint: foreground },
|
|
57
|
+
ghost: { tint: foreground },
|
|
58
|
+
link: { tint: actionInk },
|
|
59
|
+
plate: { tint: foreground },
|
|
60
|
+
"<3": {
|
|
61
|
+
tint: brand,
|
|
62
|
+
label: brandForeground
|
|
63
|
+
},
|
|
64
|
+
glass: {
|
|
65
|
+
tint: primary,
|
|
66
|
+
label: primaryForeground
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const label = typeof children === "string" ? children : void 0;
|
|
70
|
+
const tintValue = tintColor ?? defaults[variant].tint;
|
|
71
|
+
const labelValue = labelColor ?? defaults[variant].label;
|
|
72
|
+
const modifiers = Platform.OS === "ios" ? [
|
|
73
|
+
buttonStyle(IOS_BUTTON_STYLE[variant]),
|
|
74
|
+
...tintValue ? [tint(tintValue)] : [],
|
|
75
|
+
...labelValue ? [foregroundStyle(labelValue)] : []
|
|
76
|
+
] : void 0;
|
|
77
|
+
return /* @__PURE__ */ jsx(Host, {
|
|
78
|
+
matchContents: true,
|
|
79
|
+
style,
|
|
80
|
+
children: /* @__PURE__ */ jsx(Button$1, {
|
|
81
|
+
label,
|
|
82
|
+
onPress,
|
|
83
|
+
disabled,
|
|
84
|
+
variant: UNIVERSAL_VARIANT[variant],
|
|
85
|
+
modifiers,
|
|
86
|
+
children: label ? void 0 : children
|
|
87
|
+
})
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
//#endregion
|
|
92
|
+
export { Button, IOS_BUTTON_STYLE, UNIVERSAL_VARIANT };
|