@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,42 @@
|
|
|
1
|
+
import { catalog } from "../../tuning/catalog.gen.js";
|
|
2
|
+
import { effectiveTokens, normalize } from "../../tuning/model.js";
|
|
3
|
+
import { toNativeVariables } from "../../tuning/native.js";
|
|
4
|
+
import { useActiveScheme } from "./theme.js";
|
|
5
|
+
import { TuningTokensContext } from "./tuning-context.js";
|
|
6
|
+
import { useMemo } from "react";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
import { VariableContextProvider } from "react-native-css";
|
|
9
|
+
|
|
10
|
+
//#region src/native/lib/tuning.tsx
|
|
11
|
+
/**
|
|
12
|
+
* The root that applies tuning (runtime overrides of tokens) to descendant components. Place it **inside `ThemeRoot`** (to receive the effective theme and the dark variables).
|
|
13
|
+
*
|
|
14
|
+
* - Distributes the changed colors, radius, and typefaces as CSS variables with `VariableContextProvider` from `react-native-css`. On device, what takes effect is
|
|
15
|
+
* classes that use color tokens whose values differ between light and dark (such as `bg-card`) and typefaces. Classes folded into literals at build time, such as `bg-action`,
|
|
16
|
+
* plus radius, body text size, and the targets of semantic references, **do not take effect on device** (`nativeLimits` returns an explanation.
|
|
17
|
+
* On react-native-web they are CSS variables, so everything takes effect)
|
|
18
|
+
* - Components that look up colors from TS (`useTokenColor`) read the effective values (references resolved) from `TuningTokensContext`, so **all of them follow**
|
|
19
|
+
* - With no tuning (same as the defaults), nothing changes (empty `tuning` restores the original look)
|
|
20
|
+
*
|
|
21
|
+
* Not yet verified on a real device (Expo). The README lists what was verified in react-native-web browser tests.
|
|
22
|
+
*/
|
|
23
|
+
function TuningRoot({ tuning, catalog: catalog$1 = catalog, children }) {
|
|
24
|
+
const scheme = useActiveScheme();
|
|
25
|
+
const normalized = useMemo(() => normalize(tuning, catalog$1), [tuning, catalog$1]);
|
|
26
|
+
const variables = useMemo(() => toNativeVariables(normalized, catalog$1, scheme), [
|
|
27
|
+
normalized,
|
|
28
|
+
catalog$1,
|
|
29
|
+
scheme
|
|
30
|
+
]);
|
|
31
|
+
const tokens = useMemo(() => effectiveTokens(normalized, catalog$1), [normalized, catalog$1]);
|
|
32
|
+
return /* @__PURE__ */ jsx(TuningTokensContext.Provider, {
|
|
33
|
+
value: tokens,
|
|
34
|
+
children: /* @__PURE__ */ jsx(VariableContextProvider, {
|
|
35
|
+
value: variables,
|
|
36
|
+
children
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { TuningRoot };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TextStyle } from "react-native";
|
|
2
|
+
//#region src/native/lib/typography.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A style that aligns digits with equal widths (tabular).
|
|
5
|
+
*
|
|
6
|
+
* Tailwind's `tabular-nums` (`font-variant-numeric`) cannot be expressed in className because
|
|
7
|
+
* react-native-css does not support it. For numeric displays, pass this via `style`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const tabularNums: TextStyle;
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/native/lib/typography.ts
|
|
2
|
+
/**
|
|
3
|
+
* A style that aligns digits with equal widths (tabular).
|
|
4
|
+
*
|
|
5
|
+
* Tailwind's `tabular-nums` (`font-variant-numeric`) cannot be expressed in className because
|
|
6
|
+
* react-native-css does not support it. For numeric displays, pass this via `style`.
|
|
7
|
+
*/
|
|
8
|
+
const tabularNums = { fontVariant: ["tabular-nums"] };
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { tabularNums };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { ClassValue } from "clsx";
|
|
3
|
+
//#region src/native/lib/utils.d.ts
|
|
4
|
+
export declare function cn(...inputs: ClassValue[]): string;
|
|
5
|
+
/**
|
|
6
|
+
* A `ReactNode` that renders nothing (`null`, `undefined`, booleans, the empty string, and arrays or `<></>` containing only those).
|
|
7
|
+
* Used to decide whether a heading or label "exists" (an empty heading such as `""` or `<></>` does not count as a name).
|
|
8
|
+
* An element (such as `<Text />`) counts as existing even if its content is empty (it is drawn). Only a Fragment is decided by its content.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isBlankNode(node: ReactNode): boolean;
|
|
11
|
+
//#endregion
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Fragment, isValidElement } from "react";
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
|
|
5
|
+
//#region src/native/lib/utils.ts
|
|
6
|
+
function cn(...inputs) {
|
|
7
|
+
return twMerge(clsx(inputs));
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A `ReactNode` that renders nothing (`null`, `undefined`, booleans, the empty string, and arrays or `<></>` containing only those).
|
|
11
|
+
* Used to decide whether a heading or label "exists" (an empty heading such as `""` or `<></>` does not count as a name).
|
|
12
|
+
* An element (such as `<Text />`) counts as existing even if its content is empty (it is drawn). Only a Fragment is decided by its content.
|
|
13
|
+
*/
|
|
14
|
+
function isBlankNode(node) {
|
|
15
|
+
if (node === null || node === void 0 || typeof node === "boolean" || node === "") return true;
|
|
16
|
+
if (Array.isArray(node)) return node.every(isBlankNode);
|
|
17
|
+
return isValidElement(node) && node.type === Fragment && isBlankNode(node.props.children);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { cn, isBlankNode };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/native/once/confirm.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The confirmation dialog invoked by `confirm()` (`lib/confirm.ts`). Place exactly one at the app root.
|
|
4
|
+
* It reads from an external store (`confirmDialogStore`).
|
|
5
|
+
*/
|
|
6
|
+
export declare function ConfirmDialog(): import("react").JSX.Element;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
2
|
+
import { Button } from "../atom/button.js";
|
|
3
|
+
import { closeConfirmDialog, confirmDialogStore, registerConfirmDialog } from "../lib/confirm.js";
|
|
4
|
+
import { useEffect } from "react";
|
|
5
|
+
import { Modal, Pressable, View } from "react-native";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/native/once/confirm.tsx
|
|
9
|
+
/**
|
|
10
|
+
* The confirmation dialog invoked by `confirm()` (`lib/confirm.ts`). Place exactly one at the app root.
|
|
11
|
+
* It reads from an external store (`confirmDialogStore`).
|
|
12
|
+
*/
|
|
13
|
+
function ConfirmDialog() {
|
|
14
|
+
const dialog = confirmDialogStore.use();
|
|
15
|
+
useEffect(() => registerConfirmDialog(), []);
|
|
16
|
+
const dismiss = () => {
|
|
17
|
+
dialog.onDismiss?.();
|
|
18
|
+
closeConfirmDialog();
|
|
19
|
+
};
|
|
20
|
+
return /* @__PURE__ */ jsx(Modal, {
|
|
21
|
+
visible: dialog.isOpen,
|
|
22
|
+
transparent: true,
|
|
23
|
+
animationType: "fade",
|
|
24
|
+
onRequestClose: dismiss,
|
|
25
|
+
"aria-label": dialog.title,
|
|
26
|
+
children: /* @__PURE__ */ jsx(Pressable, {
|
|
27
|
+
accessible: false,
|
|
28
|
+
className: "flex-1 items-center justify-center bg-scrim p-6",
|
|
29
|
+
onPress: dialog.onOutsideClick ? () => dialog.onOutsideClick?.(closeConfirmDialog) : void 0,
|
|
30
|
+
children: /* @__PURE__ */ jsxs(Pressable, {
|
|
31
|
+
accessible: false,
|
|
32
|
+
className: "w-full max-w-[400px] self-center rounded-surface bg-popover p-5 shadow-lg",
|
|
33
|
+
onPress: () => {},
|
|
34
|
+
children: [/* @__PURE__ */ jsxs(View, {
|
|
35
|
+
className: "gap-1.5",
|
|
36
|
+
children: [dialog.title ? /* @__PURE__ */ jsx(Text$1, {
|
|
37
|
+
className: "text-base leading-6 font-semibold",
|
|
38
|
+
children: dialog.title
|
|
39
|
+
}) : null, dialog.description ? /* @__PURE__ */ jsx(Text$1, {
|
|
40
|
+
className: "text-muted-foreground text-[13px] leading-5",
|
|
41
|
+
children: dialog.description
|
|
42
|
+
}) : null]
|
|
43
|
+
}), /* @__PURE__ */ jsx(View, {
|
|
44
|
+
className: "mt-4 flex-row justify-end gap-2",
|
|
45
|
+
children: dialog.buttons?.map(({ text, onClick, variant }) => /* @__PURE__ */ jsx(Button, {
|
|
46
|
+
variant,
|
|
47
|
+
onPress: () => {
|
|
48
|
+
onClick();
|
|
49
|
+
closeConfirmDialog();
|
|
50
|
+
},
|
|
51
|
+
children: text
|
|
52
|
+
}, text))
|
|
53
|
+
})]
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
export { ConfirmDialog };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Component, ReactNode } from "react";
|
|
2
|
+
//#region src/native/once/error-boundary.d.ts
|
|
3
|
+
export type ErrorBoundaryLabels = {
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
retry: string;
|
|
7
|
+
};
|
|
8
|
+
export type ErrorBoundaryProps = {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
/** Text for the fallback screen. The app resolves i18n and passes it in. */
|
|
11
|
+
labels: ErrorBoundaryLabels;
|
|
12
|
+
};
|
|
13
|
+
type State = {
|
|
14
|
+
hasError: boolean;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* An error boundary wrapping the whole app. It catches rendering exceptions in the child tree and,
|
|
18
|
+
* instead of a blank-screen crash, shows a fallback with a way to recover.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ErrorBoundary extends Component<ErrorBoundaryProps, State> {
|
|
21
|
+
state: State;
|
|
22
|
+
static getDerivedStateFromError(): State;
|
|
23
|
+
componentDidCatch(error: unknown): void;
|
|
24
|
+
reset: () => void;
|
|
25
|
+
render(): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
2
|
+
import { Button } from "../atom/button.js";
|
|
3
|
+
import { Component } from "react";
|
|
4
|
+
import { View } from "react-native";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/native/once/error-boundary.tsx
|
|
8
|
+
function ErrorFallback({ title, description, retry, onRetry }) {
|
|
9
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
10
|
+
role: "alert",
|
|
11
|
+
className: "flex-1 items-center justify-center gap-4 bg-background p-8",
|
|
12
|
+
children: [
|
|
13
|
+
/* @__PURE__ */ jsx(Text$1, {
|
|
14
|
+
className: "text-lg font-bold text-foreground",
|
|
15
|
+
children: title
|
|
16
|
+
}),
|
|
17
|
+
/* @__PURE__ */ jsx(Text$1, {
|
|
18
|
+
variant: "muted",
|
|
19
|
+
className: "text-center leading-5",
|
|
20
|
+
children: description
|
|
21
|
+
}),
|
|
22
|
+
/* @__PURE__ */ jsx(Button, {
|
|
23
|
+
onPress: onRetry,
|
|
24
|
+
children: retry
|
|
25
|
+
})
|
|
26
|
+
]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* An error boundary wrapping the whole app. It catches rendering exceptions in the child tree and,
|
|
31
|
+
* instead of a blank-screen crash, shows a fallback with a way to recover.
|
|
32
|
+
*/
|
|
33
|
+
var ErrorBoundary = class extends Component {
|
|
34
|
+
constructor(..._args) {
|
|
35
|
+
super(..._args);
|
|
36
|
+
this.state = { hasError: false };
|
|
37
|
+
this.reset = () => this.setState({ hasError: false });
|
|
38
|
+
}
|
|
39
|
+
static getDerivedStateFromError() {
|
|
40
|
+
return { hasError: true };
|
|
41
|
+
}
|
|
42
|
+
componentDidCatch(error) {
|
|
43
|
+
console.error("Uncaught render error:", error);
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
if (this.state.hasError) return /* @__PURE__ */ jsx(ErrorFallback, {
|
|
47
|
+
...this.props.labels,
|
|
48
|
+
onRetry: this.reset
|
|
49
|
+
});
|
|
50
|
+
return this.props.children;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { ErrorBoundary };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/native/once/loading-lock.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* An overlay that blocks interaction during global loading. Place exactly one at the app root.
|
|
4
|
+
* It appears on `globalLoading(true)` (`lib/loading.ts`) and disappears on `false`.
|
|
5
|
+
* It reads from an external store (`loadingStore`).
|
|
6
|
+
*/
|
|
7
|
+
export declare function LoadingLock(): import("react").JSX.Element;
|
|
8
|
+
//#endregion
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LOADING_LABEL } from "../lib/labels.js";
|
|
2
|
+
import { Spinner } from "../atom/spinner.js";
|
|
3
|
+
import { loadingStore } from "../lib/loading.js";
|
|
4
|
+
import { Modal, View } from "react-native";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
//#region src/native/once/loading-lock.tsx
|
|
8
|
+
/**
|
|
9
|
+
* An overlay that blocks interaction during global loading. Place exactly one at the app root.
|
|
10
|
+
* It appears on `globalLoading(true)` (`lib/loading.ts`) and disappears on `false`.
|
|
11
|
+
* It reads from an external store (`loadingStore`).
|
|
12
|
+
*/
|
|
13
|
+
function LoadingLock() {
|
|
14
|
+
const loading = loadingStore.use();
|
|
15
|
+
return /* @__PURE__ */ jsx(Modal, {
|
|
16
|
+
visible: loading,
|
|
17
|
+
transparent: true,
|
|
18
|
+
animationType: "fade",
|
|
19
|
+
"aria-label": LOADING_LABEL,
|
|
20
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
21
|
+
className: "flex-1 items-center justify-center bg-scrim",
|
|
22
|
+
children: /* @__PURE__ */ jsx(Spinner, { size: "large" })
|
|
23
|
+
})
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { LoadingLock };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/native/once/offline-banner.d.ts
|
|
2
|
+
export type OfflineBannerProps = {
|
|
3
|
+
/** The text to show. love3 does not depend on i18n, so the app resolves it and passes it in. */
|
|
4
|
+
message: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* A banner permanently shown at the top of the screen while the connection is down. It disappears automatically when the connection returns.
|
|
8
|
+
* The root needs `react-native-safe-area-context`'s `SafeAreaProvider` (Expo Router includes it by default).
|
|
9
|
+
*
|
|
10
|
+
* The colors are the `destructive` surface and the text on it (`paper`; the same pair as `atom/button`'s destructive).
|
|
11
|
+
* love3 has no color literals (it uses tokens), so the banner follows the theme.
|
|
12
|
+
* The state comes from `useIsOnline` in `lib/network.ts` (NetInfo; `navigator.onLine` on web). When the connection drops it is announced with `role="alert"`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function OfflineBanner({ message }: OfflineBannerProps): import("react").JSX.Element | null;
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
2
|
+
import { useIsOnline } from "../lib/network.js";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
6
|
+
|
|
7
|
+
//#region src/native/once/offline-banner.tsx
|
|
8
|
+
/**
|
|
9
|
+
* A banner permanently shown at the top of the screen while the connection is down. It disappears automatically when the connection returns.
|
|
10
|
+
* The root needs `react-native-safe-area-context`'s `SafeAreaProvider` (Expo Router includes it by default).
|
|
11
|
+
*
|
|
12
|
+
* The colors are the `destructive` surface and the text on it (`paper`; the same pair as `atom/button`'s destructive).
|
|
13
|
+
* love3 has no color literals (it uses tokens), so the banner follows the theme.
|
|
14
|
+
* The state comes from `useIsOnline` in `lib/network.ts` (NetInfo; `navigator.onLine` on web). When the connection drops it is announced with `role="alert"`.
|
|
15
|
+
*/
|
|
16
|
+
function OfflineBanner({ message }) {
|
|
17
|
+
const online = useIsOnline();
|
|
18
|
+
const insets = useSafeAreaInsets();
|
|
19
|
+
if (online) return null;
|
|
20
|
+
return /* @__PURE__ */ jsx(View, {
|
|
21
|
+
role: "alert",
|
|
22
|
+
className: "bg-destructive",
|
|
23
|
+
style: { paddingTop: insets.top },
|
|
24
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
25
|
+
className: "items-center py-1.5",
|
|
26
|
+
children: /* @__PURE__ */ jsx(Text$1, {
|
|
27
|
+
className: "text-paper text-[13px] font-semibold",
|
|
28
|
+
children: message
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { OfflineBanner };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/native/once/snackbar.d.ts
|
|
2
|
+
export type SnackbarProps = {
|
|
3
|
+
/** Whether toasts appear from the top edge (default) or the bottom edge. */
|
|
4
|
+
position?: "top" | "bottom";
|
|
5
|
+
/** Spoken name of each toast's close button (default "閉じる", i.e. "Close"). */
|
|
6
|
+
closeLabel?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The home for toasts. Place exactly one at the app root (make the parent a full-screen View; the position is the top or bottom edge of that parent).
|
|
10
|
+
* Corresponds to the web `once/snackbar` (sonner's Toaster).
|
|
11
|
+
* The root needs `react-native-safe-area-context`'s `SafeAreaProvider` (Expo Router includes it by default).
|
|
12
|
+
*
|
|
13
|
+
* Show toasts with `snackbar()` from `lib/snackbar.ts`. **Nothing appears unless this is mounted** (in development `snackbar()` warns).
|
|
14
|
+
* Errors use `role="alert"` and everything else `role="status"` (read out by assistive technology). iOS has no live region, so `announceForAccessibility` reads it out when a toast appears.
|
|
15
|
+
*/
|
|
16
|
+
export declare function Snackbar({ position, closeLabel }: SnackbarProps): import("react").JSX.Element | null;
|
|
17
|
+
//#endregion
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
3
|
+
import { CLOSE_LABEL } from "../lib/labels.js";
|
|
4
|
+
import { dismissSnackbar, registerSnackbarHost, snackbarStore } from "../lib/snackbar.js";
|
|
5
|
+
import { useEffect } from "react";
|
|
6
|
+
import { AccessibilityInfo, Platform, Pressable, View } from "react-native";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import Feather from "@expo/vector-icons/Feather";
|
|
9
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
10
|
+
|
|
11
|
+
//#region src/native/once/snackbar.tsx
|
|
12
|
+
const ICON = {
|
|
13
|
+
success: "check-circle",
|
|
14
|
+
error: "alert-octagon",
|
|
15
|
+
info: "info",
|
|
16
|
+
warning: "alert-triangle"
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The home for toasts. Place exactly one at the app root (make the parent a full-screen View; the position is the top or bottom edge of that parent).
|
|
20
|
+
* Corresponds to the web `once/snackbar` (sonner's Toaster).
|
|
21
|
+
* The root needs `react-native-safe-area-context`'s `SafeAreaProvider` (Expo Router includes it by default).
|
|
22
|
+
*
|
|
23
|
+
* Show toasts with `snackbar()` from `lib/snackbar.ts`. **Nothing appears unless this is mounted** (in development `snackbar()` warns).
|
|
24
|
+
* Errors use `role="alert"` and everything else `role="status"` (read out by assistive technology). iOS has no live region, so `announceForAccessibility` reads it out when a toast appears.
|
|
25
|
+
*/
|
|
26
|
+
function Snackbar({ position = "top", closeLabel = CLOSE_LABEL }) {
|
|
27
|
+
const items = snackbarStore.use();
|
|
28
|
+
const insets = useSafeAreaInsets();
|
|
29
|
+
useEffect(() => registerSnackbarHost(), []);
|
|
30
|
+
if (items.length === 0) return null;
|
|
31
|
+
return /* @__PURE__ */ jsx(View, {
|
|
32
|
+
pointerEvents: "box-none",
|
|
33
|
+
style: {
|
|
34
|
+
position: "absolute",
|
|
35
|
+
left: 0,
|
|
36
|
+
right: 0,
|
|
37
|
+
...position === "top" ? { top: insets.top } : { bottom: insets.bottom }
|
|
38
|
+
},
|
|
39
|
+
className: "gap-2 p-4",
|
|
40
|
+
children: items.map((item) => /* @__PURE__ */ jsx(Toast, {
|
|
41
|
+
item,
|
|
42
|
+
closeLabel
|
|
43
|
+
}, item.id))
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function Toast({ item, closeLabel }) {
|
|
47
|
+
const ink = useTokenColor("--ink-1000");
|
|
48
|
+
const iconColor = {
|
|
49
|
+
success: useTokenColor("--state-success"),
|
|
50
|
+
error: useTokenColor("--state-error"),
|
|
51
|
+
warning: useTokenColor("--state-warning"),
|
|
52
|
+
info: ink
|
|
53
|
+
}[item.icon];
|
|
54
|
+
const { id, title, description, action } = item;
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (Platform.OS === "ios") AccessibilityInfo.announceForAccessibility(description ? `${title}。${description}` : title);
|
|
57
|
+
}, [title, description]);
|
|
58
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
59
|
+
role: item.icon === "error" ? "alert" : "status",
|
|
60
|
+
"aria-live": item.icon === "error" ? "assertive" : "polite",
|
|
61
|
+
className: "flex-row items-start gap-3 rounded-surface border border-line bg-popover p-3 shadow-md",
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ jsx(Feather, {
|
|
64
|
+
name: ICON[item.icon],
|
|
65
|
+
size: 16,
|
|
66
|
+
color: iconColor
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ jsxs(View, {
|
|
69
|
+
className: "shrink grow gap-1",
|
|
70
|
+
children: [/* @__PURE__ */ jsx(Text$1, {
|
|
71
|
+
className: "text-sm font-medium",
|
|
72
|
+
children: title
|
|
73
|
+
}), description ? /* @__PURE__ */ jsx(Text$1, {
|
|
74
|
+
className: "text-muted-foreground text-xs",
|
|
75
|
+
children: description
|
|
76
|
+
}) : null]
|
|
77
|
+
}),
|
|
78
|
+
action ? /* @__PURE__ */ jsx(Pressable, {
|
|
79
|
+
accessibilityRole: "button",
|
|
80
|
+
hitSlop: 8,
|
|
81
|
+
onPress: () => {
|
|
82
|
+
dismissSnackbar(id);
|
|
83
|
+
action.onPress();
|
|
84
|
+
},
|
|
85
|
+
children: /* @__PURE__ */ jsx(Text$1, {
|
|
86
|
+
className: "text-action-ink text-xs font-medium underline",
|
|
87
|
+
children: action.label
|
|
88
|
+
})
|
|
89
|
+
}) : null,
|
|
90
|
+
/* @__PURE__ */ jsx(Pressable, {
|
|
91
|
+
accessibilityRole: "button",
|
|
92
|
+
accessibilityLabel: closeLabel,
|
|
93
|
+
hitSlop: 8,
|
|
94
|
+
onPress: () => dismissSnackbar(id),
|
|
95
|
+
children: /* @__PURE__ */ jsx(Feather, {
|
|
96
|
+
name: "x",
|
|
97
|
+
size: 14,
|
|
98
|
+
color: ink
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
]
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
//#endregion
|
|
106
|
+
export { Snackbar };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* love3's native styles (`@lt-three/love3/native/styles.css`). **The CSS entry point for Metro (real devices)**.
|
|
3
|
+
* Import it exactly once in the app's `global.css` (NativeWind v5 / react-native-css compiles it as Tailwind v4).
|
|
4
|
+
*
|
|
5
|
+
* @import "@lt-three/love3/native/styles.css";
|
|
6
|
+
*
|
|
7
|
+
* **Not the same as `native/web/styles.css`.** That one is the entry point used when preview and vitest draw with react-native-web
|
|
8
|
+
* (it rides on web Tailwind, so `nativewind/theme` is not needed, and dark is `<html class="dark">`). It is not used on real devices.
|
|
9
|
+
*
|
|
10
|
+
* Contents: the Tailwind v4 core, the NativeWind theme, the tokens (`@lt-three/love3/styles.css`), and detection of component classes.
|
|
11
|
+
* Token values live in `src/tokens/definition.ts` (the single source of truth). No tokens are written here.
|
|
12
|
+
*/
|
|
13
|
+
@import "tailwindcss/theme.css" layer(theme);
|
|
14
|
+
@import "tailwindcss/preflight.css" layer(base);
|
|
15
|
+
@import "tailwindcss/utilities.css";
|
|
16
|
+
|
|
17
|
+
@import "nativewind/theme";
|
|
18
|
+
|
|
19
|
+
/* The token body (@theme, light, dark). It is generated, so to change values, edit definition.ts */
|
|
20
|
+
@import "@lt-three/love3/styles.css";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Pick up the Tailwind classes used by love3's native components. node_modules (through the workspace symlink) is
|
|
24
|
+
* outside automatic detection, so it is listed explicitly here. The `@source` paths are relative to this CSS file's location.
|
|
25
|
+
* In the published package (`dist/`) components are `*.js`, so both `tsx` and `js` are picked up (the same files exist in both src and dist).
|
|
26
|
+
* `web/` is a helper for react-native-web (it has no classes), so it is excluded.
|
|
27
|
+
*/
|
|
28
|
+
@source "./**/*.{tsx,js}";
|
|
29
|
+
@source not "./**/*.test.tsx";
|
|
30
|
+
@source not "./web/**";
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* On native, `dark:` is resolved **by the OS color scheme setting, not by a class**.
|
|
34
|
+
*
|
|
35
|
+
* The default of `@lt-three/love3/styles.css` is `&:is(.dark *)` (it assumes web's `<html class="dark">`).
|
|
36
|
+
* Using that on native too would make `.dark` appear as an ancestor selector of rules that have `dark:`,
|
|
37
|
+
* so react-native-css would treat a view with `.dark` as a **container**
|
|
38
|
+
* and attach hover/active/focus tracking handlers. Then **a ScrollView among that view's descendants
|
|
39
|
+
* can no longer receive pan, and the whole app becomes unscrollable**
|
|
40
|
+
* (taps still go through, so it is easy to miss; confirmed on a real device).
|
|
41
|
+
*
|
|
42
|
+
* The OS color scheme can be switched with `Appearance.setColorScheme()` (`ThemeRoot` does this), so
|
|
43
|
+
* the app's in-app theme setting keeps working as before. `.dark` goes back to being a class that **only distributes variables**.
|
|
44
|
+
* `lib/tokens-check.ts` (`tokens.test.ts`) guards that no class creates a container.
|
|
45
|
+
*/
|
|
46
|
+
@custom-variant dark (@media (prefers-color-scheme: dark));
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//#region src/shared/analytics.d.ts
|
|
2
|
+
export type LinePoint = {
|
|
3
|
+
/** The heading shown in the readout (a date, for example). */
|
|
4
|
+
x: string | number;
|
|
5
|
+
y: number;
|
|
6
|
+
/**
|
|
7
|
+
* The value used for the horizontal position (a continuous quantity such as Unix seconds).
|
|
8
|
+
*
|
|
9
|
+
* **Always set it when overlaying multiple series.** When omitted, points are spaced evenly by order,
|
|
10
|
+
* so when series with different intervals (a daily balance and irregularly spaced equity) are overlaid,
|
|
11
|
+
* the same horizontal position would point to different times.
|
|
12
|
+
*/
|
|
13
|
+
t?: number;
|
|
14
|
+
};
|
|
15
|
+
/** One line of a multi-series line chart. */
|
|
16
|
+
export type LineSeries = {
|
|
17
|
+
/** The React key and the identifier of the series. */
|
|
18
|
+
key: string;
|
|
19
|
+
/** The name shown in the legend. */
|
|
20
|
+
label: string;
|
|
21
|
+
points: LinePoint[];
|
|
22
|
+
/** The line color. A CSS color (a token reference such as `var(--chart-1)` is recommended). */
|
|
23
|
+
color: string;
|
|
24
|
+
/** Draw the line dashed (to tell a secondary series from the primary one). */
|
|
25
|
+
dashed?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/** The line chart props for visual dimensions and the spoken summary (shared by web and native). */
|
|
28
|
+
export type ChartCommonProps = {
|
|
29
|
+
height?: number;
|
|
30
|
+
/**
|
|
31
|
+
* A summary of the chart for screen readers (for example: "The balance rose from $1,000 on January 1 to $1,210 on the 7th"). When passed, it becomes the
|
|
32
|
+
* name of `role="img"`. **The graphic (svg) itself has no name**, so this is how the values reach users who cannot read them
|
|
33
|
+
* (screen reader and keyboard users). This is a shared package, so the wording is left to the consumer.
|
|
34
|
+
*/
|
|
35
|
+
accessibilityLabel?: string;
|
|
36
|
+
};
|
|
37
|
+
/** A single-series line chart (`LineChart`). */
|
|
38
|
+
export type LineChartSharedProps = {
|
|
39
|
+
data: LinePoint[];
|
|
40
|
+
color?: string;
|
|
41
|
+
};
|
|
42
|
+
/** A multi-series line chart (`MultiLineChart`). */
|
|
43
|
+
export type MultiLineChartSharedProps = {
|
|
44
|
+
series: LineSeries[];
|
|
45
|
+
/** Formats the vertical axis ticks. Currency symbols and the like are decided by the consumer. */
|
|
46
|
+
formatValue?: (value: number) => string;
|
|
47
|
+
/** The text shown when every series is empty. */
|
|
48
|
+
emptyText?: string;
|
|
49
|
+
};
|
|
50
|
+
/** A single metric on a surface (`MetricCard`). */
|
|
51
|
+
export type MetricCardSharedProps = {
|
|
52
|
+
label: string;
|
|
53
|
+
value: string;
|
|
54
|
+
subValue?: string;
|
|
55
|
+
/** The sign of the change. The value is colored state-success when positive and state-error when negative (token colors; they follow dark mode too). */
|
|
56
|
+
trend?: number;
|
|
57
|
+
className?: string;
|
|
58
|
+
};
|
|
59
|
+
/** A number whose color changes with its sign (`ColoredValue`). */
|
|
60
|
+
export interface ColoredValueSharedProps<TValue> {
|
|
61
|
+
value: TValue;
|
|
62
|
+
format?: (value: TValue) => string;
|
|
63
|
+
isPositive?: (value: TValue) => boolean;
|
|
64
|
+
isNegative?: (value: TValue) => boolean;
|
|
65
|
+
/** The class for an increase. Defaults to `text-state-success` (a token; follows dark mode). */
|
|
66
|
+
positiveColor?: string;
|
|
67
|
+
/** The class for a decrease. Defaults to `text-state-error`. */
|
|
68
|
+
negativeColor?: string;
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
File without changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/shared/button.d.ts
|
|
2
|
+
export declare const BUTTON_VARIANTS: readonly ["default", "destructive", "outline", "secondary", "ghost", "link", "plate", "<3"];
|
|
3
|
+
/** `"<3"` is the Less Than Three brand color (pink fill). Meant for a confirming action, placed only once per screen */
|
|
4
|
+
export type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
|
|
5
|
+
export declare const BUTTON_SIZES: readonly ["default", "xs", "sm", "lg", "xl", "icon", "icon-xs"];
|
|
6
|
+
export type ButtonSize = (typeof BUTTON_SIZES)[number];
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/shared/button.ts
|
|
2
|
+
const BUTTON_VARIANTS = [
|
|
3
|
+
"default",
|
|
4
|
+
"destructive",
|
|
5
|
+
"outline",
|
|
6
|
+
"secondary",
|
|
7
|
+
"ghost",
|
|
8
|
+
"link",
|
|
9
|
+
"plate",
|
|
10
|
+
"<3"
|
|
11
|
+
];
|
|
12
|
+
const BUTTON_SIZES = [
|
|
13
|
+
"default",
|
|
14
|
+
"xs",
|
|
15
|
+
"sm",
|
|
16
|
+
"lg",
|
|
17
|
+
"xl",
|
|
18
|
+
"icon",
|
|
19
|
+
"icon-xs"
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { BUTTON_SIZES, BUTTON_VARIANTS };
|