@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,16 @@
|
|
|
1
|
+
//#region src/native/lib/external-store.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A small external store that bridges the imperative APIs (`confirm()`, `globalLoading()`) and the components placed at the root (`ConfirmDialog`, `LoadingLock`).
|
|
4
|
+
* love3 does not depend on jotai, so it is read with React's `useSyncExternalStore`. Treat values as immutable (`set` takes a new value).
|
|
5
|
+
*/
|
|
6
|
+
export type ExternalStore<T> = {
|
|
7
|
+
get: () => T;
|
|
8
|
+
set: (next: T) => void;
|
|
9
|
+
/** Builds the next value from the previous one. */
|
|
10
|
+
update: (updater: (prev: T) => T) => void;
|
|
11
|
+
subscribe: (listener: () => void) => () => void;
|
|
12
|
+
/** Read from components. Re-renders when the value changes. */
|
|
13
|
+
use: () => T;
|
|
14
|
+
};
|
|
15
|
+
export declare function createExternalStore<T>(initial: T): ExternalStore<T>;
|
|
16
|
+
//#endregion
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/native/lib/external-store.ts
|
|
4
|
+
function createExternalStore(initial) {
|
|
5
|
+
let state = initial;
|
|
6
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
7
|
+
const get = () => state;
|
|
8
|
+
const subscribe = (listener) => {
|
|
9
|
+
listeners.add(listener);
|
|
10
|
+
return () => {
|
|
11
|
+
listeners.delete(listener);
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
const set = (next) => {
|
|
15
|
+
if (Object.is(next, state)) return;
|
|
16
|
+
state = next;
|
|
17
|
+
for (const listener of listeners) listener();
|
|
18
|
+
};
|
|
19
|
+
const update = (updater) => set(updater(state));
|
|
20
|
+
return {
|
|
21
|
+
get,
|
|
22
|
+
set,
|
|
23
|
+
update,
|
|
24
|
+
subscribe,
|
|
25
|
+
use: () => useSyncExternalStore(subscribe, get, get)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { createExternalStore };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { KeyDownEvent } from "react-native";
|
|
2
|
+
//#region src/native/lib/keyboard.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* An `onKeyDown` that calls `activate` on Space (pass it to `Pressable`).
|
|
5
|
+
*
|
|
6
|
+
* react-native-web's `Pressable` treats Enter as a press, but treats Space as a press **only for `<button>` or `role="button"`**
|
|
7
|
+
* (`isValidKeyPress` in `PressResponder`). `role="radio"` / `"checkbox"` / `"switch"` do not respond to Space.
|
|
8
|
+
* The WAI-ARIA APG decides these three with Space (without it, people using only a keyboard cannot select them; WCAG 2.1.1).
|
|
9
|
+
* **Enter is already handled as a press by react-native-web**, so only Space is handled here (handling Enter too would call it twice).
|
|
10
|
+
*
|
|
11
|
+
* Real-device React Native only delivers keys listed in `keyDownEvents` to `onKeyDown`, so with this usage, which passes none, it is
|
|
12
|
+
* never called (behavior on device does not change). Presses with modifier keys (Ctrl, Alt, Meta, Shift) and held-key repeats are ignored.
|
|
13
|
+
*/
|
|
14
|
+
export declare function activateOnSpace(activate: () => void, disabled?: boolean | null): (event: KeyDownEvent) => void;
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/native/lib/keyboard.ts
|
|
2
|
+
/**
|
|
3
|
+
* An `onKeyDown` that calls `activate` on Space (pass it to `Pressable`).
|
|
4
|
+
*
|
|
5
|
+
* react-native-web's `Pressable` treats Enter as a press, but treats Space as a press **only for `<button>` or `role="button"`**
|
|
6
|
+
* (`isValidKeyPress` in `PressResponder`). `role="radio"` / `"checkbox"` / `"switch"` do not respond to Space.
|
|
7
|
+
* The WAI-ARIA APG decides these three with Space (without it, people using only a keyboard cannot select them; WCAG 2.1.1).
|
|
8
|
+
* **Enter is already handled as a press by react-native-web**, so only Space is handled here (handling Enter too would call it twice).
|
|
9
|
+
*
|
|
10
|
+
* Real-device React Native only delivers keys listed in `keyDownEvents` to `onKeyDown`, so with this usage, which passes none, it is
|
|
11
|
+
* never called (behavior on device does not change). Presses with modifier keys (Ctrl, Alt, Meta, Shift) and held-key repeats are ignored.
|
|
12
|
+
*/
|
|
13
|
+
function activateOnSpace(activate, disabled) {
|
|
14
|
+
return (event) => {
|
|
15
|
+
const { key, repeat, altKey, ctrlKey, metaKey, shiftKey } = event.nativeEvent;
|
|
16
|
+
if (key !== " " || repeat === true || altKey || ctrlKey || metaKey || shiftKey) return;
|
|
17
|
+
event.preventDefault();
|
|
18
|
+
if (disabled === true) return;
|
|
19
|
+
activate();
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { activateOnSpace };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/native/lib/labels.d.ts
|
|
2
|
+
/** Loading indicator (Spinner) */
|
|
3
|
+
export declare const LOADING_LABEL = "読み込み中";
|
|
4
|
+
/** Default buttons of the confirm dialog (`confirm()`). Callers override them with `yes` / `no` */
|
|
5
|
+
export declare const YES_LABEL = "はい";
|
|
6
|
+
export declare const NO_LABEL = "いいえ";
|
|
7
|
+
/** When the input of a number field (`type="number"` of `form/text-input`) cannot be read as a number */
|
|
8
|
+
export declare const NUMBER_INVALID_LABEL = "数値で入力してください";
|
|
9
|
+
/** Close button (Sheet, Modal, Snackbar). Callers override it with `closeLabel` */
|
|
10
|
+
export declare const CLOSE_LABEL = "閉じる";
|
|
11
|
+
/** Last resort for when no heading or name was passed for the options of `atom/select` (so it never becomes an unnamed dialog) */
|
|
12
|
+
export declare const SELECT_LABEL = "選択肢";
|
|
13
|
+
/** Default placeholder of `form/select` (same wording as the web `form/select`) */
|
|
14
|
+
export declare const SELECT_PLACEHOLDER_LABEL = "選択してください";
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/native/lib/labels.ts
|
|
2
|
+
/** Loading indicator (Spinner) */
|
|
3
|
+
const LOADING_LABEL = "読み込み中";
|
|
4
|
+
/** Default buttons of the confirm dialog (`confirm()`). Callers override them with `yes` / `no` */
|
|
5
|
+
const YES_LABEL = "はい";
|
|
6
|
+
const NO_LABEL = "いいえ";
|
|
7
|
+
/** When the input of a number field (`type="number"` of `form/text-input`) cannot be read as a number */
|
|
8
|
+
const NUMBER_INVALID_LABEL = "数値で入力してください";
|
|
9
|
+
/** Close button (Sheet, Modal, Snackbar). Callers override it with `closeLabel` */
|
|
10
|
+
const CLOSE_LABEL = "閉じる";
|
|
11
|
+
/** Last resort for when no heading or name was passed for the options of `atom/select` (so it never becomes an unnamed dialog) */
|
|
12
|
+
const SELECT_LABEL = "選択肢";
|
|
13
|
+
/** Default placeholder of `form/select` (same wording as the web `form/select`) */
|
|
14
|
+
const SELECT_PLACEHOLDER_LABEL = "選択してください";
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { CLOSE_LABEL, LOADING_LABEL, NO_LABEL, NUMBER_INVALID_LABEL, SELECT_LABEL, SELECT_PLACEHOLDER_LABEL, YES_LABEL };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ExternalStore } from "./external-store.js";
|
|
2
|
+
//#region src/native/lib/loading.d.ts
|
|
3
|
+
/** State read by `LoadingLock`. The imperative API (`globalLoading()`) writes here. */
|
|
4
|
+
export declare const loadingStore: ExternalStore<boolean>;
|
|
5
|
+
/**
|
|
6
|
+
* Shows or hides a loading overlay that blocks interaction across the whole app. Place one `LoadingLock` from `once/loading-lock` at the app root.
|
|
7
|
+
* Holds a single boolean (repeated calls are not counted; the overlay goes away as soon as `false` is passed).
|
|
8
|
+
*/
|
|
9
|
+
export declare function globalLoading(loading: boolean): void;
|
|
10
|
+
//#endregion
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createExternalStore } from "./external-store.js";
|
|
2
|
+
|
|
3
|
+
//#region src/native/lib/loading.ts
|
|
4
|
+
/** State read by `LoadingLock`. The imperative API (`globalLoading()`) writes here. */
|
|
5
|
+
const loadingStore = createExternalStore(false);
|
|
6
|
+
/**
|
|
7
|
+
* Shows or hides a loading overlay that blocks interaction across the whole app. Place one `LoadingLock` from `once/loading-lock` at the app root.
|
|
8
|
+
* Holds a single boolean (repeated calls are not counted; the overlay goes away as soon as `false` is passed).
|
|
9
|
+
*/
|
|
10
|
+
function globalLoading(loading) {
|
|
11
|
+
loadingStore.set(loading);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { globalLoading, loadingStore };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/native/lib/network.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Subscribes to whether the device is currently online. Used to control the display of `once/offline-banner`.
|
|
4
|
+
* It watches NetInfo only and does not depend on TanStack Query (an app that wants to tie fetch pausing and refetch on reconnect to NetInfo
|
|
5
|
+
* wires `onlineManager.setEventListener` to NetInfo itself).
|
|
6
|
+
*
|
|
7
|
+
* On device it uses NetInfo's `isConnected` (a `null` while determining is treated as online to avoid false positives).
|
|
8
|
+
* On web (react-native-web) NetInfo also works, watching `navigator.onLine` and the `online` / `offline` events.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useIsOnline(): boolean;
|
|
11
|
+
//#endregion
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { addEventListener } from "@react-native-community/netinfo";
|
|
3
|
+
|
|
4
|
+
//#region src/native/lib/network.ts
|
|
5
|
+
/**
|
|
6
|
+
* Subscribes to whether the device is currently online. Used to control the display of `once/offline-banner`.
|
|
7
|
+
* It watches NetInfo only and does not depend on TanStack Query (an app that wants to tie fetch pausing and refetch on reconnect to NetInfo
|
|
8
|
+
* wires `onlineManager.setEventListener` to NetInfo itself).
|
|
9
|
+
*
|
|
10
|
+
* On device it uses NetInfo's `isConnected` (a `null` while determining is treated as online to avoid false positives).
|
|
11
|
+
* On web (react-native-web) NetInfo also works, watching `navigator.onLine` and the `online` / `offline` events.
|
|
12
|
+
*/
|
|
13
|
+
function useIsOnline() {
|
|
14
|
+
const [online, setOnline] = useState(true);
|
|
15
|
+
useEffect(() => addEventListener((state) => setOnline(state.isConnected !== false)), []);
|
|
16
|
+
return online;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { useIsOnline };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TokenName } from "../../tokens/tokens.gen.js";
|
|
2
|
+
//#region src/native/lib/scheme.d.ts
|
|
3
|
+
/** Theme selection. `system` follows the device setting. Where it is stored (AsyncStorage, a settings screen) is the app's responsibility and is not handled here. */
|
|
4
|
+
export type ThemePreference = "system" | "light" | "dark";
|
|
5
|
+
/** The theme actually used for rendering. */
|
|
6
|
+
export type ActiveScheme = "light" | "dark";
|
|
7
|
+
/** Decides the theme to actually use from the selection and the device color scheme. */
|
|
8
|
+
export declare function resolveScheme(preference: ThemePreference, system: "light" | "dark" | "unspecified" | null | undefined): ActiveScheme;
|
|
9
|
+
/** Names of color tokens (excluding the `font-*` typefaces and `radius`). These are the only ones `useTokenColor` accepts. */
|
|
10
|
+
export type ColorTokenName = Exclude<TokenName, `font-${string}` | "radius">;
|
|
11
|
+
/**
|
|
12
|
+
* The actual value of a color token. The DS owns the values (`@lt-three/love3/tokens`), and components look them up through here.
|
|
13
|
+
* The name may be in CSS variable form (`--ink-500`) or token name form (`ink-500`). Non-color tokens (typefaces, radius) are not accepted.
|
|
14
|
+
*/
|
|
15
|
+
export declare function tokenColor(scheme: ActiveScheme, name: `--${ColorTokenName}` | ColorTokenName,
|
|
16
|
+
/** Effective values distributed by tuning (`TuningRoot`). If present, they take priority (following runtime overrides). */
|
|
17
|
+
overlay?: Readonly<Record<ActiveScheme, Readonly<Record<string, string>>>> | null): string;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { tokenNames, tokens } from "../../tokens/tokens.gen.js";
|
|
2
|
+
|
|
3
|
+
//#region src/native/lib/scheme.ts
|
|
4
|
+
/** Decides the theme to actually use from the selection and the device color scheme. */
|
|
5
|
+
function resolveScheme(preference, system) {
|
|
6
|
+
if (preference === "system") return system === "dark" ? "dark" : "light";
|
|
7
|
+
return preference;
|
|
8
|
+
}
|
|
9
|
+
const isColorToken = (name) => !name.startsWith("font-") && name !== "radius";
|
|
10
|
+
/**
|
|
11
|
+
* The actual value of a color token. The DS owns the values (`@lt-three/love3/tokens`), and components look them up through here.
|
|
12
|
+
* The name may be in CSS variable form (`--ink-500`) or token name form (`ink-500`). Non-color tokens (typefaces, radius) are not accepted.
|
|
13
|
+
*/
|
|
14
|
+
function tokenColor(scheme, name, overlay) {
|
|
15
|
+
const key = name.startsWith("--") ? name.slice(2) : name;
|
|
16
|
+
const token = tokenNames.find((candidate) => candidate === key);
|
|
17
|
+
if (token === void 0 || !isColorToken(token)) throw new Error(`色のトークンではない: ${name}`);
|
|
18
|
+
return overlay?.[scheme][token] ?? tokens[scheme][token];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { resolveScheme, tokenColor };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ExternalStore } from "./external-store.js";
|
|
2
|
+
//#region src/native/lib/snackbar.d.ts
|
|
3
|
+
export type SnackbarIcon = "success" | "error" | "info" | "warning";
|
|
4
|
+
export type SnackbarAction = {
|
|
5
|
+
label: string;
|
|
6
|
+
/** Called when pressed; the toast closes afterward (same as the sonner action on web). */
|
|
7
|
+
onPress: () => void;
|
|
8
|
+
};
|
|
9
|
+
export type SnackbarItem = {
|
|
10
|
+
id: string | number;
|
|
11
|
+
icon: SnackbarIcon;
|
|
12
|
+
title: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
action?: SnackbarAction;
|
|
15
|
+
persistent?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type SnackbarOptions = {
|
|
18
|
+
id?: string | number;
|
|
19
|
+
icon?: SnackbarIcon;
|
|
20
|
+
description?: string;
|
|
21
|
+
action?: SnackbarAction;
|
|
22
|
+
/**
|
|
23
|
+
* If true, the toast does not dismiss itself (dismiss it with `dismissSnackbar` or the close button).
|
|
24
|
+
* **Defaults to true when `action` is set** (if it disappeared before being pressed, people using a keyboard or assistive technology could not reach it in time; WCAG 2.2.1).
|
|
25
|
+
* Even with `action`, passing `duration` or an explicit `persistent: false` makes it dismiss itself.
|
|
26
|
+
*/
|
|
27
|
+
persistent?: boolean;
|
|
28
|
+
/** Milliseconds until it dismisses itself (default 4000). Ignored when `persistent`. */
|
|
29
|
+
duration?: number;
|
|
30
|
+
};
|
|
31
|
+
/** The queue read by `Snackbar`. The imperative API (`snackbar()`) writes here. */
|
|
32
|
+
export declare const snackbarStore: ExternalStore<readonly SnackbarItem[]>;
|
|
33
|
+
/** Call only while a `Snackbar` is mounted (`once/snackbar` calls it in an effect). Returns an unsubscribe function. Used for the not-mounted warning. */
|
|
34
|
+
export declare function registerSnackbarHost(): () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Shows a toast. The returned id can be passed to `dismissSnackbar`.
|
|
37
|
+
* Place one `Snackbar` from `once/snackbar` at the app root (**nothing is shown without it**; a warning is logged in development.
|
|
38
|
+
* The auto-dismiss timer runs even before it is placed).
|
|
39
|
+
*/
|
|
40
|
+
export declare function snackbar(title: string, options?: SnackbarOptions): string | number;
|
|
41
|
+
/** Dismisses the given toast. */
|
|
42
|
+
export declare function dismissSnackbar(id: string | number): void;
|
|
43
|
+
/** Dismisses all visible toasts (and cancels all pending auto-dismiss timers). */
|
|
44
|
+
export declare function dismissAllSnackbars(): void;
|
|
45
|
+
//#endregion
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createExternalStore } from "./external-store.js";
|
|
2
|
+
|
|
3
|
+
//#region src/native/lib/snackbar.ts
|
|
4
|
+
/** The queue read by `Snackbar`. The imperative API (`snackbar()`) writes here. */
|
|
5
|
+
const snackbarStore = createExternalStore([]);
|
|
6
|
+
const DEFAULT_DURATION = 4e3;
|
|
7
|
+
let sequence = 0;
|
|
8
|
+
const timers = /* @__PURE__ */ new Map();
|
|
9
|
+
let mountedHosts = 0;
|
|
10
|
+
/** Call only while a `Snackbar` is mounted (`once/snackbar` calls it in an effect). Returns an unsubscribe function. Used for the not-mounted warning. */
|
|
11
|
+
function registerSnackbarHost() {
|
|
12
|
+
mountedHosts += 1;
|
|
13
|
+
return () => {
|
|
14
|
+
mountedHosts -= 1;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Shows a toast. The returned id can be passed to `dismissSnackbar`.
|
|
19
|
+
* Place one `Snackbar` from `once/snackbar` at the app root (**nothing is shown without it**; a warning is logged in development.
|
|
20
|
+
* The auto-dismiss timer runs even before it is placed).
|
|
21
|
+
*/
|
|
22
|
+
function snackbar(title, options) {
|
|
23
|
+
if (__DEV__ && mountedHosts === 0) console.warn("snackbar(): Snackbar がマウントされていない。アプリのルートに <Snackbar /> を 1 つ置くまで、このトーストは出ない。");
|
|
24
|
+
sequence += 1;
|
|
25
|
+
const id = options?.id ?? sequence;
|
|
26
|
+
const persistent = options?.persistent ?? (options?.action !== void 0 && options.duration === void 0);
|
|
27
|
+
const item = {
|
|
28
|
+
id,
|
|
29
|
+
icon: options?.icon ?? "info",
|
|
30
|
+
title,
|
|
31
|
+
description: options?.description,
|
|
32
|
+
action: options?.action,
|
|
33
|
+
persistent
|
|
34
|
+
};
|
|
35
|
+
snackbarStore.update((items) => [...items.filter((candidate) => candidate.id !== id), item]);
|
|
36
|
+
clearTimer(id);
|
|
37
|
+
if (!persistent) timers.set(id, setTimeout(() => dismissSnackbar(id), options?.duration ?? DEFAULT_DURATION));
|
|
38
|
+
return id;
|
|
39
|
+
}
|
|
40
|
+
/** Dismisses the given toast. */
|
|
41
|
+
function dismissSnackbar(id) {
|
|
42
|
+
clearTimer(id);
|
|
43
|
+
snackbarStore.update((items) => items.filter((candidate) => candidate.id !== id));
|
|
44
|
+
}
|
|
45
|
+
/** Dismisses all visible toasts (and cancels all pending auto-dismiss timers). */
|
|
46
|
+
function dismissAllSnackbars() {
|
|
47
|
+
for (const timer of timers.values()) clearTimeout(timer);
|
|
48
|
+
timers.clear();
|
|
49
|
+
snackbarStore.set([]);
|
|
50
|
+
}
|
|
51
|
+
function clearTimer(id) {
|
|
52
|
+
const timer = timers.get(id);
|
|
53
|
+
if (timer === void 0) return;
|
|
54
|
+
clearTimeout(timer);
|
|
55
|
+
timers.delete(id);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { dismissAllSnackbars, dismissSnackbar, registerSnackbarHost, snackbar, snackbarStore };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ActiveScheme, ThemePreference } from "./scheme.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/native/lib/theme.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The current effective theme.
|
|
6
|
+
*
|
|
7
|
+
* It does not return the colors themselves. Colors come from NativeWind's semantic classes
|
|
8
|
+
* (`bg-background` / `text-foreground`, etc.). Use this hook only where
|
|
9
|
+
* a native-side API (react-navigation theme, StatusBar, SF Symbols tint, chart colors, etc.)
|
|
10
|
+
* needs light/dark passed to it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function useActiveScheme(): ActiveScheme;
|
|
13
|
+
export type ThemeRootProps = {
|
|
14
|
+
/** Theme selection. Where it is stored (AsyncStorage, jotai, etc.) is up to the app; only the value is passed here. */
|
|
15
|
+
preference: ThemePreference;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The root that applies the theme to actual rendering.
|
|
20
|
+
*
|
|
21
|
+
* `@lt-three/love3/styles.css` defines dark tokens of the form `.dark { --paper: ...; ... }`,
|
|
22
|
+
* which are **class-based**. react-native-css compiles this class rule as is,
|
|
23
|
+
* so placing `className="dark"` on the root distributes the dark CSS variables to every descendant.
|
|
24
|
+
* This works the same way as `<html class="dark">` on web, so the tokens need not be duplicated in TS.
|
|
25
|
+
*
|
|
26
|
+
* It also syncs React Native's `Appearance`. Native UI outside NativeWind, such as the navigation theme and StatusBar,
|
|
27
|
+
* reads it.
|
|
28
|
+
*
|
|
29
|
+
* **Not used on web (react-native-web).** The web theme is owned by `<html class="dark">`
|
|
30
|
+
* (preview and vitest switch it directly).
|
|
31
|
+
*/
|
|
32
|
+
export declare function ThemeRoot({ preference, children }: ThemeRootProps): import("react").JSX.Element;
|
|
33
|
+
//#endregion
|
|
34
|
+
export type { ActiveScheme, ThemePreference };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { resolveScheme } from "./scheme.js";
|
|
2
|
+
import { createContext, useContext, useEffect } from "react";
|
|
3
|
+
import { Appearance, View, useColorScheme } from "react-native";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/native/lib/theme.tsx
|
|
7
|
+
/** The effective theme distributed by `ThemeRoot`. Outside `ThemeRoot` it follows the device color scheme. */
|
|
8
|
+
const SchemeContext = createContext(null);
|
|
9
|
+
/**
|
|
10
|
+
* The current effective theme.
|
|
11
|
+
*
|
|
12
|
+
* It does not return the colors themselves. Colors come from NativeWind's semantic classes
|
|
13
|
+
* (`bg-background` / `text-foreground`, etc.). Use this hook only where
|
|
14
|
+
* a native-side API (react-navigation theme, StatusBar, SF Symbols tint, chart colors, etc.)
|
|
15
|
+
* needs light/dark passed to it.
|
|
16
|
+
*/
|
|
17
|
+
function useActiveScheme() {
|
|
18
|
+
const fromRoot = useContext(SchemeContext);
|
|
19
|
+
const system = useColorScheme();
|
|
20
|
+
return fromRoot ?? resolveScheme("system", system);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The root that applies the theme to actual rendering.
|
|
24
|
+
*
|
|
25
|
+
* `@lt-three/love3/styles.css` defines dark tokens of the form `.dark { --paper: ...; ... }`,
|
|
26
|
+
* which are **class-based**. react-native-css compiles this class rule as is,
|
|
27
|
+
* so placing `className="dark"` on the root distributes the dark CSS variables to every descendant.
|
|
28
|
+
* This works the same way as `<html class="dark">` on web, so the tokens need not be duplicated in TS.
|
|
29
|
+
*
|
|
30
|
+
* It also syncs React Native's `Appearance`. Native UI outside NativeWind, such as the navigation theme and StatusBar,
|
|
31
|
+
* reads it.
|
|
32
|
+
*
|
|
33
|
+
* **Not used on web (react-native-web).** The web theme is owned by `<html class="dark">`
|
|
34
|
+
* (preview and vitest switch it directly).
|
|
35
|
+
*/
|
|
36
|
+
function ThemeRoot({ preference, children }) {
|
|
37
|
+
const system = useColorScheme();
|
|
38
|
+
const scheme = resolveScheme(preference, system);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
Appearance.setColorScheme(preference === "system" ? "unspecified" : preference);
|
|
41
|
+
}, [preference]);
|
|
42
|
+
return /* @__PURE__ */ jsx(SchemeContext.Provider, {
|
|
43
|
+
value: scheme,
|
|
44
|
+
children: /* @__PURE__ */ jsx(View, {
|
|
45
|
+
accessible: false,
|
|
46
|
+
className: scheme === "dark" ? "dark flex-1" : "flex-1",
|
|
47
|
+
children
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
export { ThemeRoot, useActiveScheme };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/native/lib/timezone.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Utilities for time zones (IANA strings). Used by `atom/timezone-select`.
|
|
4
|
+
* love3 has no dependency on a shared core package, so this lives in native `lib/`
|
|
5
|
+
* (if a timezone-select is added to the web side of love3, move this to `shared/` and share it).
|
|
6
|
+
*
|
|
7
|
+
* The options are not built from `Intl.supportedValuesOf("timeZone")` because the native JS engine
|
|
8
|
+
* Hermes does not have it (confirmed that the string is absent from the hermesvm binary of Hermes 250829098.0.16.
|
|
9
|
+
* `resolvedOptions().timeZone` of `Intl.DateTimeFormat` exists on both iOS and Android).
|
|
10
|
+
* Listing every zone (about 420) is unusable in a select list without search, so a fixed list is used.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Major IANA time zones. Representative cities of each region, chosen from the IANA tz database.
|
|
14
|
+
* Even for values not listed here, `timeZoneOptions` always adds the device time zone and the saved value.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAJOR_TIME_ZONES: readonly string[];
|
|
17
|
+
/** This device's time zone (IANA string). An empty string if it cannot be obtained. */
|
|
18
|
+
export declare function getDeviceTimeZone(): string;
|
|
19
|
+
/**
|
|
20
|
+
* The list of time zone options. Adds `extra` (the device value, the saved value) to the fixed list,
|
|
21
|
+
* and returns it with duplicates and the empty string removed. Prevents a selected value not in the list from vanishing from the options and showing as empty.
|
|
22
|
+
*/
|
|
23
|
+
export declare function timeZoneOptions(...extra: string[]): string[];
|
|
24
|
+
/** Display name. The IANA `_` is hard to read, so it is turned into a space (`America/New_York` → `America/New York`). */
|
|
25
|
+
export declare function formatTimeZoneLabel(zone: string): string;
|
|
26
|
+
//#endregion
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
//#region src/native/lib/timezone.ts
|
|
2
|
+
/**
|
|
3
|
+
* Utilities for time zones (IANA strings). Used by `atom/timezone-select`.
|
|
4
|
+
* love3 has no dependency on a shared core package, so this lives in native `lib/`
|
|
5
|
+
* (if a timezone-select is added to the web side of love3, move this to `shared/` and share it).
|
|
6
|
+
*
|
|
7
|
+
* The options are not built from `Intl.supportedValuesOf("timeZone")` because the native JS engine
|
|
8
|
+
* Hermes does not have it (confirmed that the string is absent from the hermesvm binary of Hermes 250829098.0.16.
|
|
9
|
+
* `resolvedOptions().timeZone` of `Intl.DateTimeFormat` exists on both iOS and Android).
|
|
10
|
+
* Listing every zone (about 420) is unusable in a select list without search, so a fixed list is used.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Major IANA time zones. Representative cities of each region, chosen from the IANA tz database.
|
|
14
|
+
* Even for values not listed here, `timeZoneOptions` always adds the device time zone and the saved value.
|
|
15
|
+
*/
|
|
16
|
+
const MAJOR_TIME_ZONES = [
|
|
17
|
+
"UTC",
|
|
18
|
+
"Pacific/Honolulu",
|
|
19
|
+
"America/Anchorage",
|
|
20
|
+
"America/Los_Angeles",
|
|
21
|
+
"America/Vancouver",
|
|
22
|
+
"America/Phoenix",
|
|
23
|
+
"America/Denver",
|
|
24
|
+
"America/Chicago",
|
|
25
|
+
"America/Mexico_City",
|
|
26
|
+
"America/New_York",
|
|
27
|
+
"America/Toronto",
|
|
28
|
+
"America/Halifax",
|
|
29
|
+
"America/Sao_Paulo",
|
|
30
|
+
"America/Argentina/Buenos_Aires",
|
|
31
|
+
"Atlantic/Reykjavik",
|
|
32
|
+
"Europe/London",
|
|
33
|
+
"Europe/Dublin",
|
|
34
|
+
"Europe/Lisbon",
|
|
35
|
+
"Europe/Madrid",
|
|
36
|
+
"Europe/Paris",
|
|
37
|
+
"Europe/Amsterdam",
|
|
38
|
+
"Europe/Berlin",
|
|
39
|
+
"Europe/Zurich",
|
|
40
|
+
"Europe/Rome",
|
|
41
|
+
"Europe/Stockholm",
|
|
42
|
+
"Europe/Athens",
|
|
43
|
+
"Europe/Helsinki",
|
|
44
|
+
"Europe/Istanbul",
|
|
45
|
+
"Europe/Moscow",
|
|
46
|
+
"Africa/Lagos",
|
|
47
|
+
"Africa/Cairo",
|
|
48
|
+
"Africa/Nairobi",
|
|
49
|
+
"Africa/Johannesburg",
|
|
50
|
+
"Asia/Jerusalem",
|
|
51
|
+
"Asia/Dubai",
|
|
52
|
+
"Asia/Karachi",
|
|
53
|
+
"Asia/Kolkata",
|
|
54
|
+
"Asia/Dhaka",
|
|
55
|
+
"Asia/Bangkok",
|
|
56
|
+
"Asia/Jakarta",
|
|
57
|
+
"Asia/Ho_Chi_Minh",
|
|
58
|
+
"Asia/Singapore",
|
|
59
|
+
"Asia/Kuala_Lumpur",
|
|
60
|
+
"Asia/Hong_Kong",
|
|
61
|
+
"Asia/Shanghai",
|
|
62
|
+
"Asia/Taipei",
|
|
63
|
+
"Asia/Manila",
|
|
64
|
+
"Asia/Seoul",
|
|
65
|
+
"Asia/Tokyo",
|
|
66
|
+
"Australia/Perth",
|
|
67
|
+
"Australia/Adelaide",
|
|
68
|
+
"Australia/Sydney",
|
|
69
|
+
"Australia/Melbourne",
|
|
70
|
+
"Pacific/Auckland"
|
|
71
|
+
];
|
|
72
|
+
/** This device's time zone (IANA string). An empty string if it cannot be obtained. */
|
|
73
|
+
function getDeviceTimeZone() {
|
|
74
|
+
try {
|
|
75
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone ?? "";
|
|
76
|
+
} catch {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The list of time zone options. Adds `extra` (the device value, the saved value) to the fixed list,
|
|
82
|
+
* and returns it with duplicates and the empty string removed. Prevents a selected value not in the list from vanishing from the options and showing as empty.
|
|
83
|
+
*/
|
|
84
|
+
function timeZoneOptions(...extra) {
|
|
85
|
+
const set = new Set(MAJOR_TIME_ZONES);
|
|
86
|
+
for (const zone of extra) if (zone) set.add(zone);
|
|
87
|
+
return [...set].sort((a, b) => a.localeCompare(b));
|
|
88
|
+
}
|
|
89
|
+
/** Display name. The IANA `_` is hard to read, so it is turned into a space (`America/New_York` → `America/New York`). */
|
|
90
|
+
function formatTimeZoneLabel(zone) {
|
|
91
|
+
return zone.replaceAll("_", " ");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//#endregion
|
|
95
|
+
export { MAJOR_TIME_ZONES, formatTimeZoneLabel, getDeviceTimeZone, timeZoneOptions };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ColorTokenName } from "./scheme.js";
|
|
2
|
+
//#region src/native/lib/token-color.d.ts
|
|
3
|
+
/** The argument is a color token in CSS variable form (`--ink-500`). Semantic names (`--muted-foreground`) can also be looked up. Typefaces and radius are not accepted. */
|
|
4
|
+
export declare function useTokenColor(name: `--${ColorTokenName}`): string;
|
|
5
|
+
//#endregion
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { tokenColor } from "./scheme.js";
|
|
2
|
+
import { useActiveScheme } from "./theme.js";
|
|
3
|
+
import { TuningTokensContext } from "./tuning-context.js";
|
|
4
|
+
import { useContext } from "react";
|
|
5
|
+
|
|
6
|
+
//#region src/native/lib/token-color.ts
|
|
7
|
+
/** The argument is a color token in CSS variable form (`--ink-500`). Semantic names (`--muted-foreground`) can also be looked up. Typefaces and radius are not accepted. */
|
|
8
|
+
function useTokenColor(name) {
|
|
9
|
+
return tokenColor(useActiveScheme(), name, useContext(TuningTokensContext));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
export { useTokenColor };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Mode } from "../../tuning/types.js";
|
|
2
|
+
//#region src/native/lib/tuning-context.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The effective token values (separate for light and dark; references resolved) distributed by tuning (`TuningRoot`). If absent (outside `TuningRoot`), there is no tuning.
|
|
5
|
+
* `useTokenColor`, which looks up colors from TS, reads this to follow runtime overrides.
|
|
6
|
+
*/
|
|
7
|
+
export type TuningTokens = Readonly<Record<Mode, Readonly<Record<string, string>>>>;
|
|
8
|
+
export declare const TuningTokensContext: import("react").Context<Readonly<Record<Mode, Readonly<Record<string, string>>>> | null>;
|
|
9
|
+
//#endregion
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Tuning, TuningCatalog } from "../../tuning/types.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/native/lib/tuning.d.ts
|
|
4
|
+
export type TuningRootProps = {
|
|
5
|
+
/** The tuning content (the diff from the defaults; `Tuning` of `@lt-three/love3/tuning`. Where it is stored is up to the app). */
|
|
6
|
+
tuning: Tuning;
|
|
7
|
+
/** The tuning target. Defaults to love3's generated output (`tuning/catalog.gen.ts`). */
|
|
8
|
+
catalog?: TuningCatalog;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
};
|
|
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
|
+
export declare function TuningRoot({ tuning, catalog, children }: TuningRootProps): import("react").JSX.Element;
|
|
24
|
+
//#endregion
|