@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,101 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
4
|
+
import { tabularNums } from "../lib/typography.js";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import Feather from "@expo/vector-icons/Feather";
|
|
8
|
+
|
|
9
|
+
//#region src/native/analytics/single-number.tsx
|
|
10
|
+
/**
|
|
11
|
+
* A metric showing a large number on a raised surface (surface corner radius, 1px hairline border).
|
|
12
|
+
* Mirrors the web analytics single-number. Increase/decrease uses the state colors (the surface does not invert, so the same theme values work).
|
|
13
|
+
*/
|
|
14
|
+
function SingleNumber({ title, subTitle, value, unit, compareValue, compareTitle, reverseColor, className }) {
|
|
15
|
+
const up = useTokenColor("--state-success");
|
|
16
|
+
const down = useTokenColor("--state-error");
|
|
17
|
+
const diff = typeof compareValue === "number" ? (value ?? 0) - compareValue : 0;
|
|
18
|
+
const diffPercent = (1 - (value ?? 0) / (compareValue ?? 0)) * -100;
|
|
19
|
+
const diffColor = reverseColor ? diff < 0 ? up : down : diff < 0 ? down : up;
|
|
20
|
+
const iconName = diff < 0 ? "chevron-down" : "chevron-up";
|
|
21
|
+
const showCompare = typeof value === "number" && typeof compareValue === "number";
|
|
22
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
23
|
+
className: cn("gap-3 rounded-surface border border-line bg-card p-3", className),
|
|
24
|
+
children: [
|
|
25
|
+
/* @__PURE__ */ jsxs(View, {
|
|
26
|
+
className: "flex-row items-end gap-2",
|
|
27
|
+
children: [/* @__PURE__ */ jsx(Text$1, {
|
|
28
|
+
className: "text-card-foreground text-lg font-bold",
|
|
29
|
+
children: title
|
|
30
|
+
}), subTitle ? /* @__PURE__ */ jsx(Text$1, {
|
|
31
|
+
className: "text-muted-foreground text-xs",
|
|
32
|
+
children: subTitle
|
|
33
|
+
}) : null]
|
|
34
|
+
}),
|
|
35
|
+
/* @__PURE__ */ jsxs(View, {
|
|
36
|
+
className: "flex-row items-end",
|
|
37
|
+
children: [/* @__PURE__ */ jsx(Text$1, {
|
|
38
|
+
style: tabularNums,
|
|
39
|
+
className: "text-card-foreground font-mono text-3xl leading-none",
|
|
40
|
+
children: value
|
|
41
|
+
}), unit ? /* @__PURE__ */ jsx(Text$1, {
|
|
42
|
+
className: "text-card-foreground ml-1 text-base",
|
|
43
|
+
children: unit
|
|
44
|
+
}) : null]
|
|
45
|
+
}),
|
|
46
|
+
showCompare ? /* @__PURE__ */ jsxs(View, {
|
|
47
|
+
className: "flex-row items-end gap-2",
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ jsxs(View, {
|
|
50
|
+
className: "flex-row items-center",
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsx(Feather, {
|
|
53
|
+
name: iconName,
|
|
54
|
+
size: 14,
|
|
55
|
+
color: diffColor
|
|
56
|
+
}),
|
|
57
|
+
/* @__PURE__ */ jsx(Text$1, {
|
|
58
|
+
style: [tabularNums, { color: diffColor }],
|
|
59
|
+
className: "font-mono text-lg leading-none",
|
|
60
|
+
children: diff
|
|
61
|
+
}),
|
|
62
|
+
unit ? /* @__PURE__ */ jsx(Text$1, {
|
|
63
|
+
style: { color: diffColor },
|
|
64
|
+
className: "ml-1 text-xs",
|
|
65
|
+
children: unit
|
|
66
|
+
}) : null
|
|
67
|
+
]
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ jsxs(View, {
|
|
70
|
+
className: "flex-row items-center",
|
|
71
|
+
children: [
|
|
72
|
+
/* @__PURE__ */ jsx(Feather, {
|
|
73
|
+
name: iconName,
|
|
74
|
+
size: 14,
|
|
75
|
+
color: diffColor
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ jsx(Text$1, {
|
|
78
|
+
style: [tabularNums, { color: diffColor }],
|
|
79
|
+
className: "font-mono text-lg leading-none",
|
|
80
|
+
children: Number.isNaN(diffPercent) ? 0 : !Number.isFinite(diffPercent) ? 100 : diffPercent.toFixed(2)
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ jsx(Text$1, {
|
|
83
|
+
style: { color: diffColor },
|
|
84
|
+
className: "ml-1 text-xs",
|
|
85
|
+
children: "%"
|
|
86
|
+
})
|
|
87
|
+
]
|
|
88
|
+
}),
|
|
89
|
+
compareTitle ? /* @__PURE__ */ jsx(Text$1, {
|
|
90
|
+
style: { color: diffColor },
|
|
91
|
+
className: "text-xs",
|
|
92
|
+
children: compareTitle
|
|
93
|
+
}) : null
|
|
94
|
+
]
|
|
95
|
+
}) : null
|
|
96
|
+
]
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
export { SingleNumber };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReactElement } from "react";
|
|
2
|
+
//#region src/native/atom/avatar.d.ts
|
|
3
|
+
export type AvatarProps = {
|
|
4
|
+
src?: string;
|
|
5
|
+
/** Alternative text for the image. Empty by default (decorative; assumes a name is shown next to it). For a standalone face with no name, pass the person's name (same as the web) */
|
|
6
|
+
alt?: string;
|
|
7
|
+
/**
|
|
8
|
+
* What to show when there is no image or loading failed (initials, etc.). A string is wrapped in Text. **Omitted or empty shows a person icon**
|
|
9
|
+
* (the web shows nothing for an empty string). Numbers are not accepted (RN cannot render text directly under a View; pass a string).
|
|
10
|
+
*/
|
|
11
|
+
fallback?: string | ReactElement;
|
|
12
|
+
/** Side length in px. Defaults to 24, the same as the web `size-6`. */
|
|
13
|
+
size?: number;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Same structure as the web atom/avatar (image + fallback).
|
|
18
|
+
* Drawn as a circle (`rounded-full`), like the web Avatar.
|
|
19
|
+
*/
|
|
20
|
+
export declare function Avatar({ src, alt, fallback, size, className }: AvatarProps): import("react").JSX.Element;
|
|
21
|
+
//#endregion
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import Feather from "@expo/vector-icons/Feather";
|
|
8
|
+
import { Image } from "expo-image";
|
|
9
|
+
|
|
10
|
+
//#region src/native/atom/avatar.tsx
|
|
11
|
+
/**
|
|
12
|
+
* Same structure as the web atom/avatar (image + fallback).
|
|
13
|
+
* Drawn as a circle (`rounded-full`), like the web Avatar.
|
|
14
|
+
*/
|
|
15
|
+
function Avatar({ src, alt = "", fallback, size = 24, className }) {
|
|
16
|
+
const [failed, setFailed] = useState(false);
|
|
17
|
+
const wash = useTokenColor("--wash");
|
|
18
|
+
const showImage = !!src && !failed;
|
|
19
|
+
return /* @__PURE__ */ jsx(View, {
|
|
20
|
+
style: {
|
|
21
|
+
width: size,
|
|
22
|
+
height: size
|
|
23
|
+
},
|
|
24
|
+
className: cn("items-center justify-center overflow-hidden rounded-full bg-ink-500", className),
|
|
25
|
+
children: showImage ? /* @__PURE__ */ jsx(Image, {
|
|
26
|
+
source: { uri: src },
|
|
27
|
+
accessibilityLabel: alt,
|
|
28
|
+
style: {
|
|
29
|
+
width: size,
|
|
30
|
+
height: size
|
|
31
|
+
},
|
|
32
|
+
onError: () => setFailed(true)
|
|
33
|
+
}) : fallback === void 0 || fallback === "" ? /* @__PURE__ */ jsx(Feather, {
|
|
34
|
+
name: "user",
|
|
35
|
+
size: size * .6,
|
|
36
|
+
color: wash
|
|
37
|
+
}) : typeof fallback === "string" ? /* @__PURE__ */ jsx(Text$1, {
|
|
38
|
+
style: { fontSize: size * .45 },
|
|
39
|
+
className: "text-wash font-medium",
|
|
40
|
+
children: fallback
|
|
41
|
+
}) : fallback
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { Avatar };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { VariantProps } from "class-variance-authority";
|
|
3
|
+
//#region src/native/atom/badge.d.ts
|
|
4
|
+
declare const badgeVariants: (props?: ({
|
|
5
|
+
variant?: "<3" | "default" | "destructive" | "outline" | "secondary" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
export type BadgeVariants = VariantProps<typeof badgeVariants>["variant"];
|
|
8
|
+
export type BadgeProps = {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
variant?: BadgeVariants;
|
|
11
|
+
/**
|
|
12
|
+
* Makes the badge tappable (filter chips, etc.). A native-only addition not present in the web Badge;
|
|
13
|
+
* it keeps the look unchanged and secures a tap area equivalent to 44pt via `hitSlop`.
|
|
14
|
+
*/
|
|
15
|
+
onPress?: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Name for screen readers and E2E. Always pass it when chips with the same text appear
|
|
18
|
+
* across different axes (to tell which axis a given "All" belongs to).
|
|
19
|
+
*/
|
|
20
|
+
accessibilityLabel?: string;
|
|
21
|
+
/** Tells screen readers and E2E that this chip is selected. */
|
|
22
|
+
selected?: boolean;
|
|
23
|
+
className?: string;
|
|
24
|
+
textClassName?: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function Badge({ children, variant, onPress, accessibilityLabel, selected, className, textClassName }: BadgeProps): import("react").JSX.Element;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { badgeVariants };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
3
|
+
import { tabularNums } from "../lib/typography.js";
|
|
4
|
+
import { Platform, Pressable, View } from "react-native";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { cva } from "class-variance-authority";
|
|
7
|
+
|
|
8
|
+
//#region src/native/atom/badge.tsx
|
|
9
|
+
const badgeVariants = cva("h-5 flex-row items-center justify-center gap-1 self-start rounded-control border px-1.5", {
|
|
10
|
+
variants: { variant: {
|
|
11
|
+
default: "border-transparent bg-action",
|
|
12
|
+
secondary: "border-transparent bg-secondary",
|
|
13
|
+
destructive: "border-state-error/30 bg-state-error/5",
|
|
14
|
+
outline: "border-line-strong",
|
|
15
|
+
"<3": "border-transparent bg-lt-three"
|
|
16
|
+
} },
|
|
17
|
+
defaultVariants: { variant: "default" }
|
|
18
|
+
});
|
|
19
|
+
const badgeTextVariants = cva("font-mono text-xs font-medium tracking-[0.01em]", {
|
|
20
|
+
variants: { variant: {
|
|
21
|
+
default: "text-action-foreground",
|
|
22
|
+
secondary: "text-secondary-foreground",
|
|
23
|
+
destructive: "text-state-error",
|
|
24
|
+
outline: "text-foreground",
|
|
25
|
+
"<3": "text-lt-three-foreground"
|
|
26
|
+
} },
|
|
27
|
+
defaultVariants: { variant: "default" }
|
|
28
|
+
});
|
|
29
|
+
function Badge({ children, variant, onPress, accessibilityLabel, selected, className, textClassName }) {
|
|
30
|
+
const badge = /* @__PURE__ */ jsx(View, {
|
|
31
|
+
className: cn(badgeVariants({ variant }), className),
|
|
32
|
+
children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx(Text$1, {
|
|
33
|
+
style: tabularNums,
|
|
34
|
+
className: cn(badgeTextVariants({ variant }), textClassName),
|
|
35
|
+
children
|
|
36
|
+
}) : children
|
|
37
|
+
});
|
|
38
|
+
if (!onPress) return badge;
|
|
39
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
40
|
+
accessibilityRole: "button",
|
|
41
|
+
accessibilityLabel,
|
|
42
|
+
...Platform.OS === "web" ? { "aria-pressed": selected } : { "aria-selected": selected },
|
|
43
|
+
onPress,
|
|
44
|
+
hitSlop: 12,
|
|
45
|
+
className: "self-start",
|
|
46
|
+
children: badge
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { Badge, badgeVariants };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { VariantProps } from "class-variance-authority";
|
|
3
|
+
//#region src/native/atom/button.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A button with the same variants and look as the web base/button (indigo primary action, raised surface + faint border, control corner radius).
|
|
6
|
+
* Only the height differs: it is larger than the web's (default 36) because it is pressed with a finger.
|
|
7
|
+
*
|
|
8
|
+
* Where `base/button` (`@expo/ui`) renders an OS-native button (iOS 26 Liquid Glass, etc.),
|
|
9
|
+
* this one is an RN `Pressable`, so it can be painted with tokens. **Use this one wherever it should look the same as the web.**
|
|
10
|
+
*
|
|
11
|
+
* The web's `hover:` does not exist in RN, so it is mapped to `pressed` while pressed.
|
|
12
|
+
*
|
|
13
|
+
* The web Button is `inline-flex`, so it shrinks to its content. An RN `Pressable` stretches across
|
|
14
|
+
* the parent's cross axis, so `self-start` gives it the same behavior. For a full-width CTA,
|
|
15
|
+
* pass `className="self-stretch"` from the consumer.
|
|
16
|
+
*/
|
|
17
|
+
declare const buttonVariants: (props?: ({
|
|
18
|
+
variant?: "<3" | "default" | "destructive" | "ghost" | "link" | "outline" | "plate" | "secondary" | null | undefined;
|
|
19
|
+
size?: "default" | "icon" | "icon-xs" | "lg" | "sm" | "xl" | "xs" | null | undefined;
|
|
20
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
21
|
+
declare const buttonTextVariants: (props?: ({
|
|
22
|
+
variant?: "<3" | "default" | "destructive" | "ghost" | "link" | "outline" | "plate" | "secondary" | null | undefined;
|
|
23
|
+
size?: "default" | "icon" | "icon-xs" | "lg" | "sm" | "xl" | "xs" | null | undefined;
|
|
24
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
25
|
+
export type ButtonVariants = VariantProps<typeof buttonVariants>;
|
|
26
|
+
export type ButtonProps = ButtonVariants & {
|
|
27
|
+
children?: ReactNode;
|
|
28
|
+
onPress?: () => void;
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Elements placed to the left and right of the label. The web takes a lucide component type, but native
|
|
32
|
+
* icon renderers vary (`@expo/vector-icons`, `expo-symbols`, etc.), so it takes already-rendered elements.
|
|
33
|
+
*/
|
|
34
|
+
iconLeft?: ReactNode;
|
|
35
|
+
iconRight?: ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* Name for screen readers and E2E. **Always pass it when buttons with the same text appear in a list
|
|
38
|
+
* (a per-row "Delete", etc.).** Without it VoiceOver cannot tell which row a button belongs to, and E2E cannot target them individually.
|
|
39
|
+
*/
|
|
40
|
+
accessibilityLabel?: string;
|
|
41
|
+
className?: string;
|
|
42
|
+
textClassName?: string;
|
|
43
|
+
};
|
|
44
|
+
export declare function Button({ children, onPress, disabled, variant, size, iconLeft, iconRight, accessibilityLabel, className, textClassName }: ButtonProps): import("react").JSX.Element;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { buttonTextVariants, buttonVariants };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Text as Text$1, TextClassContext } from "../base/text.js";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Pressable } from "react-native";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { cva } from "class-variance-authority";
|
|
7
|
+
|
|
8
|
+
//#region src/native/atom/button.tsx
|
|
9
|
+
/**
|
|
10
|
+
* A button with the same variants and look as the web base/button (indigo primary action, raised surface + faint border, control corner radius).
|
|
11
|
+
* Only the height differs: it is larger than the web's (default 36) because it is pressed with a finger.
|
|
12
|
+
*
|
|
13
|
+
* Where `base/button` (`@expo/ui`) renders an OS-native button (iOS 26 Liquid Glass, etc.),
|
|
14
|
+
* this one is an RN `Pressable`, so it can be painted with tokens. **Use this one wherever it should look the same as the web.**
|
|
15
|
+
*
|
|
16
|
+
* The web's `hover:` does not exist in RN, so it is mapped to `pressed` while pressed.
|
|
17
|
+
*
|
|
18
|
+
* The web Button is `inline-flex`, so it shrinks to its content. An RN `Pressable` stretches across
|
|
19
|
+
* the parent's cross axis, so `self-start` gives it the same behavior. For a full-width CTA,
|
|
20
|
+
* pass `className="self-stretch"` from the consumer.
|
|
21
|
+
*/
|
|
22
|
+
const buttonVariants = cva("flex-row items-center justify-center gap-2 self-start rounded-control border border-transparent", {
|
|
23
|
+
variants: {
|
|
24
|
+
variant: {
|
|
25
|
+
default: "bg-action",
|
|
26
|
+
destructive: "bg-destructive-solid",
|
|
27
|
+
outline: "border-line-strong bg-raised",
|
|
28
|
+
secondary: "border-line-strong bg-raised",
|
|
29
|
+
ghost: "",
|
|
30
|
+
link: "",
|
|
31
|
+
plate: "border-black bg-white",
|
|
32
|
+
"<3": "bg-lt-three"
|
|
33
|
+
},
|
|
34
|
+
size: {
|
|
35
|
+
default: "h-9 px-4",
|
|
36
|
+
xs: "h-7 gap-1 px-2",
|
|
37
|
+
sm: "h-8 gap-1.5 px-3",
|
|
38
|
+
lg: "h-10 px-6",
|
|
39
|
+
xl: "h-12 px-6",
|
|
40
|
+
icon: "h-8 w-8",
|
|
41
|
+
"icon-xs": "h-7 w-7"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
defaultVariants: {
|
|
45
|
+
variant: "default",
|
|
46
|
+
size: "default"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const buttonTextVariants = cva("font-medium", {
|
|
50
|
+
variants: {
|
|
51
|
+
variant: {
|
|
52
|
+
default: "text-action-foreground",
|
|
53
|
+
destructive: "text-destructive-solid-foreground",
|
|
54
|
+
outline: "text-foreground",
|
|
55
|
+
secondary: "text-secondary-foreground",
|
|
56
|
+
ghost: "text-foreground",
|
|
57
|
+
link: "text-action-ink underline",
|
|
58
|
+
plate: "font-normal text-black",
|
|
59
|
+
"<3": "text-lt-three-foreground"
|
|
60
|
+
},
|
|
61
|
+
size: {
|
|
62
|
+
default: "text-sm",
|
|
63
|
+
xs: "text-xs",
|
|
64
|
+
sm: "text-sm",
|
|
65
|
+
lg: "text-sm",
|
|
66
|
+
xl: "text-sm",
|
|
67
|
+
icon: "text-sm",
|
|
68
|
+
"icon-xs": "text-xs"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
defaultVariants: {
|
|
72
|
+
variant: "default",
|
|
73
|
+
size: "default"
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
function Button({ children, onPress, disabled, variant, size, iconLeft, iconRight, accessibilityLabel, className, textClassName }) {
|
|
77
|
+
const textClass = cn(buttonTextVariants({
|
|
78
|
+
variant,
|
|
79
|
+
size
|
|
80
|
+
}), textClassName);
|
|
81
|
+
const [pressed, setPressed] = useState(false);
|
|
82
|
+
return /* @__PURE__ */ jsx(Pressable, {
|
|
83
|
+
onPress,
|
|
84
|
+
onPressIn: () => setPressed(true),
|
|
85
|
+
onPressOut: () => setPressed(false),
|
|
86
|
+
disabled,
|
|
87
|
+
accessibilityRole: "button",
|
|
88
|
+
"aria-disabled": disabled,
|
|
89
|
+
accessibilityLabel,
|
|
90
|
+
className: cn(buttonVariants({
|
|
91
|
+
variant,
|
|
92
|
+
size
|
|
93
|
+
}), pressed && "opacity-70", disabled && "opacity-50", className),
|
|
94
|
+
children: /* @__PURE__ */ jsxs(TextClassContext.Provider, {
|
|
95
|
+
value: textClass,
|
|
96
|
+
children: [
|
|
97
|
+
iconLeft,
|
|
98
|
+
typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx(Text$1, {
|
|
99
|
+
className: textClass,
|
|
100
|
+
children
|
|
101
|
+
}) : children,
|
|
102
|
+
iconRight
|
|
103
|
+
]
|
|
104
|
+
})
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
export { Button, buttonTextVariants, buttonVariants };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NamedControlA11yProps } from "../lib/control.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/native/atom/checkbox.d.ts
|
|
4
|
+
export type CheckboxProps = NamedControlA11yProps & {
|
|
5
|
+
checked: boolean;
|
|
6
|
+
onCheckedChange: (checked: boolean) => void;
|
|
7
|
+
/** Label shown to the right of the checkbox. It is part of the tap area. */
|
|
8
|
+
label?: ReactNode;
|
|
9
|
+
/** Name for screen readers. A string label is used as-is, so pass this when there is no label or it is not a string. */
|
|
10
|
+
accessibilityLabel?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
invalid?: boolean;
|
|
13
|
+
className?: string;
|
|
14
|
+
wrapperClassName?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A 16px square with the control corner radius, identical to the web base/checkbox.
|
|
18
|
+
* Unchecked is a raised surface + a line-control border (3:1); checked is an indigo fill + a white check.
|
|
19
|
+
*/
|
|
20
|
+
export declare function Checkbox({ checked, onCheckedChange, label, accessibilityLabel, disabled, invalid, className, wrapperClassName, accessibilityHint, id, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid }: CheckboxProps): import("react").JSX.Element;
|
|
21
|
+
//#endregion
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { useTokenColor } from "../lib/token-color.js";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
4
|
+
import { activateOnSpace } from "../lib/keyboard.js";
|
|
5
|
+
import { Pressable, View } from "react-native";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import Feather from "@expo/vector-icons/Feather";
|
|
8
|
+
|
|
9
|
+
//#region src/native/atom/checkbox.tsx
|
|
10
|
+
/**
|
|
11
|
+
* A 16px square with the control corner radius, identical to the web base/checkbox.
|
|
12
|
+
* Unchecked is a raised surface + a line-control border (3:1); checked is an indigo fill + a white check.
|
|
13
|
+
*/
|
|
14
|
+
function Checkbox({ checked, onCheckedChange, label, accessibilityLabel, disabled, invalid, className, wrapperClassName, accessibilityHint, id, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid }) {
|
|
15
|
+
const isInvalid = invalid ?? ariaInvalid;
|
|
16
|
+
const checkColor = useTokenColor("--action-foreground");
|
|
17
|
+
const box = /* @__PURE__ */ jsx(View, {
|
|
18
|
+
className: cn("h-4 w-4 shrink-0 items-center justify-center rounded-control border", checked ? "border-action bg-action" : "border-line-control bg-raised", isInvalid && "border-destructive", disabled && "opacity-50", className),
|
|
19
|
+
children: checked ? /* @__PURE__ */ jsx(Feather, {
|
|
20
|
+
name: "check",
|
|
21
|
+
size: 12,
|
|
22
|
+
color: checkColor
|
|
23
|
+
}) : null
|
|
24
|
+
});
|
|
25
|
+
return /* @__PURE__ */ jsxs(Pressable, {
|
|
26
|
+
accessibilityRole: "checkbox",
|
|
27
|
+
accessibilityLabel: accessibilityLabel ?? (typeof label === "string" ? label : void 0),
|
|
28
|
+
"aria-checked": checked,
|
|
29
|
+
"aria-disabled": disabled,
|
|
30
|
+
"aria-invalid": isInvalid,
|
|
31
|
+
"aria-describedby": ariaDescribedBy,
|
|
32
|
+
accessibilityHint,
|
|
33
|
+
id,
|
|
34
|
+
onPress: () => onCheckedChange(!checked),
|
|
35
|
+
onKeyDown: activateOnSpace(() => onCheckedChange(!checked), disabled),
|
|
36
|
+
disabled,
|
|
37
|
+
hitSlop: 12,
|
|
38
|
+
className: cn("flex-row items-center gap-1.5 self-start", wrapperClassName),
|
|
39
|
+
children: [box, label === void 0 ? null : typeof label === "string" || typeof label === "number" ? /* @__PURE__ */ jsx(Text$1, {
|
|
40
|
+
className: "text-sm font-medium leading-none",
|
|
41
|
+
children: label
|
|
42
|
+
}) : label]
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { Checkbox };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ColoredValueSharedProps } from "../../shared/analytics.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/native/atom/colored-value.d.ts
|
|
4
|
+
export type ColoredValueProps<TValue> = ColoredValueSharedProps<TValue>;
|
|
5
|
+
/**
|
|
6
|
+
* A number whose color changes with its sign. Same API as the web atom/colored-value (`shared/analytics.ts`).
|
|
7
|
+
* The default colors are the tokens `state-success` / `state-error` rather than Tailwind's fixed palette (green-500 / red-500),
|
|
8
|
+
* and they keep 4.5:1 contrast in dark mode too.
|
|
9
|
+
* Being a number, it is drawn monospaced (tabular).
|
|
10
|
+
*/
|
|
11
|
+
export declare function ColoredValue<TValue>({ value, format, isPositive, isNegative, positiveColor, negativeColor, className }: ColoredValueProps<TValue>): ReactNode;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Text } from "../base/text.js";
|
|
3
|
+
import { tabularNums } from "../lib/typography.js";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/native/atom/colored-value.tsx
|
|
7
|
+
/**
|
|
8
|
+
* A number whose color changes with its sign. Same API as the web atom/colored-value (`shared/analytics.ts`).
|
|
9
|
+
* The default colors are the tokens `state-success` / `state-error` rather than Tailwind's fixed palette (green-500 / red-500),
|
|
10
|
+
* and they keep 4.5:1 contrast in dark mode too.
|
|
11
|
+
* Being a number, it is drawn monospaced (tabular).
|
|
12
|
+
*/
|
|
13
|
+
function ColoredValue({ value, format, isPositive, isNegative, positiveColor = "text-state-success", negativeColor = "text-state-error", className }) {
|
|
14
|
+
const formatted = format ? format(value) : String(value);
|
|
15
|
+
const toneClass = isPositive?.(value) ? positiveColor : isNegative?.(value) ? negativeColor : void 0;
|
|
16
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
17
|
+
style: tabularNums,
|
|
18
|
+
className: cn("font-mono", toneClass, className),
|
|
19
|
+
children: formatted
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { ColoredValue };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/native/atom/image.d.ts
|
|
2
|
+
export type ImageWithLoaderProps = {
|
|
3
|
+
src: string;
|
|
4
|
+
/** Description for screen readers. Corresponds to the web `alt`. */
|
|
5
|
+
alt: string;
|
|
6
|
+
/** Opens a full-screen view on tap (default true). */
|
|
7
|
+
expandable?: boolean;
|
|
8
|
+
/** Text shown when loading fails. This is a shared package, so consumers own the wording. */
|
|
9
|
+
errorText?: string;
|
|
10
|
+
/** Screen reader name of the expand button. */
|
|
11
|
+
expandLabel?: string;
|
|
12
|
+
/** Screen reader name of the button that closes the expanded view. */
|
|
13
|
+
closeLabel?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* An image that shows a skeleton while loading and a placeholder on failure.
|
|
18
|
+
* Mirrors the web atom/image (ImageWithLoader).
|
|
19
|
+
*/
|
|
20
|
+
export declare function ImageWithLoader({ src, alt, expandable, errorText, expandLabel, closeLabel, className }: ImageWithLoaderProps): import("react").JSX.Element;
|
|
21
|
+
//#endregion
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Text as Text$1 } from "../base/text.js";
|
|
3
|
+
import { Skeleton } from "./skeleton.js";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { Modal, Pressable, View } from "react-native";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Image } from "expo-image";
|
|
8
|
+
|
|
9
|
+
//#region src/native/atom/image.tsx
|
|
10
|
+
/**
|
|
11
|
+
* An image that shows a skeleton while loading and a placeholder on failure.
|
|
12
|
+
* Mirrors the web atom/image (ImageWithLoader).
|
|
13
|
+
*/
|
|
14
|
+
function ImageWithLoader({ src, alt, expandable = true, errorText = "画像の読み込みに失敗しました", expandLabel = "画像を拡大する", closeLabel = "閉じる", className }) {
|
|
15
|
+
const [status, setStatus] = useState("loading");
|
|
16
|
+
const [expanded, setExpanded] = useState(false);
|
|
17
|
+
if (status === "error") return /* @__PURE__ */ jsx(View, {
|
|
18
|
+
className: cn("items-center justify-center bg-muted p-5", className),
|
|
19
|
+
children: /* @__PURE__ */ jsx(Text$1, {
|
|
20
|
+
className: "text-muted-foreground text-sm",
|
|
21
|
+
children: errorText
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
const image = /* @__PURE__ */ jsx(Image, {
|
|
25
|
+
source: { uri: src },
|
|
26
|
+
accessibilityLabel: alt,
|
|
27
|
+
contentFit: "cover",
|
|
28
|
+
style: {
|
|
29
|
+
width: "100%",
|
|
30
|
+
height: "100%"
|
|
31
|
+
},
|
|
32
|
+
onLoad: () => setStatus("loaded"),
|
|
33
|
+
onError: () => setStatus("error")
|
|
34
|
+
});
|
|
35
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
36
|
+
className: cn("overflow-hidden", className),
|
|
37
|
+
children: [
|
|
38
|
+
status === "loading" ? /* @__PURE__ */ jsx(Skeleton, { className: "absolute inset-0" }) : null,
|
|
39
|
+
expandable ? /* @__PURE__ */ jsx(Pressable, {
|
|
40
|
+
accessibilityRole: "button",
|
|
41
|
+
accessibilityLabel: alt === "" ? expandLabel : `${alt}(${expandLabel})`,
|
|
42
|
+
className: "h-full w-full",
|
|
43
|
+
onPress: () => setExpanded(true),
|
|
44
|
+
children: image
|
|
45
|
+
}) : image,
|
|
46
|
+
/* @__PURE__ */ jsx(Modal, {
|
|
47
|
+
visible: expanded,
|
|
48
|
+
transparent: true,
|
|
49
|
+
animationType: "fade",
|
|
50
|
+
onRequestClose: () => setExpanded(false),
|
|
51
|
+
children: /* @__PURE__ */ jsx(Pressable, {
|
|
52
|
+
accessibilityRole: "button",
|
|
53
|
+
accessibilityLabel: closeLabel,
|
|
54
|
+
className: "flex-1 items-center justify-center bg-scrim p-4",
|
|
55
|
+
onPress: () => setExpanded(false),
|
|
56
|
+
children: /* @__PURE__ */ jsx(Image, {
|
|
57
|
+
source: { uri: src },
|
|
58
|
+
accessibilityLabel: alt,
|
|
59
|
+
contentFit: "contain",
|
|
60
|
+
style: {
|
|
61
|
+
flex: 1,
|
|
62
|
+
width: "100%"
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { ImageWithLoader };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/native/atom/label.d.ts
|
|
3
|
+
export type LabelProps = {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** Adds the required mark (`*`). */
|
|
6
|
+
required?: boolean;
|
|
7
|
+
/** Supplementary text placed to the right of the label. */
|
|
8
|
+
helpText?: ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
/** The `id` of the text part. Point to it from the input's `aria-labelledby` (the required `*` and the supplementary text are not part of the name). */
|
|
11
|
+
id?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* A label that looks the same as the web base/label.
|
|
15
|
+
* RN has no equivalent of the web's `htmlFor`, so tapping the label does not move focus to the input.
|
|
16
|
+
*/
|
|
17
|
+
export declare function Label({ children, required, helpText, className, id }: LabelProps): import("react").JSX.Element;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1,33 @@
|
|
|
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/label.tsx
|
|
7
|
+
/**
|
|
8
|
+
* A label that looks the same as the web base/label.
|
|
9
|
+
* RN has no equivalent of the web's `htmlFor`, so tapping the label does not move focus to the input.
|
|
10
|
+
*/
|
|
11
|
+
function Label({ children, required, helpText, className, id }) {
|
|
12
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
13
|
+
className: "flex-row items-center gap-2",
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ jsx(Text$1, {
|
|
16
|
+
id,
|
|
17
|
+
className: cn("text-sm font-medium leading-none", className),
|
|
18
|
+
children
|
|
19
|
+
}),
|
|
20
|
+
required ? /* @__PURE__ */ jsx(Text$1, {
|
|
21
|
+
className: "text-destructive text-sm",
|
|
22
|
+
children: "*"
|
|
23
|
+
}) : null,
|
|
24
|
+
helpText ? /* @__PURE__ */ jsx(Text$1, {
|
|
25
|
+
className: "text-muted-foreground text-xs font-normal",
|
|
26
|
+
children: helpText
|
|
27
|
+
}) : null
|
|
28
|
+
]
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { Label };
|