@lt-three/love3 0.0.0 → 0.1.0
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 +17 -0
- package/dist/native/analytics/multi-line-chart.js +215 -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 +13 -0
- package/dist/native/atom/separator.js +17 -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 +23 -0
- package/dist/native/form/form.js +45 -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 +49 -0
- package/dist/native/lib/confirm.js +70 -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 +17 -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 +12 -0
- package/dist/native/lib/network.js +21 -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 +46 -0
- package/dist/native/lib/snackbar.js +60 -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 +40 -0
- package/dist/web/atom/segmented-control.js +43 -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 +22 -0
- package/dist/web/atom/text-area.js +26 -0
- package/dist/web/atom/text-field.d.ts +17 -0
- package/dist/web/atom/text-field.js +21 -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 +33 -0
- package/dist/web/layout/titled-modal.js +59 -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,17 @@
|
|
|
1
|
+
//#region src/native/lib/external-store.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* 命令的な API(`confirm()`・`globalLoading()`)と、ルートに置く部品(`ConfirmDialog`・`LoadingLock`)の橋渡しをする、
|
|
4
|
+
* 小さな外部ストア。`@lt-three/core` は jotai の atom と共有のストアでこれをやっていたが、love3 は jotai に依存しない
|
|
5
|
+
* ので、React の `useSyncExternalStore` で読む。値は不変で扱う(`set` は新しい値を渡す)。
|
|
6
|
+
*/
|
|
7
|
+
export type ExternalStore<T> = {
|
|
8
|
+
get: () => T;
|
|
9
|
+
set: (next: T) => void;
|
|
10
|
+
/** 前の値から次の値を作る。 */
|
|
11
|
+
update: (updater: (prev: T) => T) => void;
|
|
12
|
+
subscribe: (listener: () => void) => () => void;
|
|
13
|
+
/** 部品から読む。値が変わると描き直す。 */
|
|
14
|
+
use: () => T;
|
|
15
|
+
};
|
|
16
|
+
export declare function createExternalStore<T>(initial: T): ExternalStore<T>;
|
|
17
|
+
//#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
|
+
* Space で `activate` を呼ぶ `onKeyDown`(`Pressable` に渡す)。
|
|
5
|
+
*
|
|
6
|
+
* react-native-web の `Pressable` は、Enter では押したことになるが、Space は **`<button>` か `role="button"` のときだけ**
|
|
7
|
+
* 押したことになる(`PressResponder` の `isValidKeyPress`)。`role="radio"` / `"checkbox"` / `"switch"` は Space で動かない。
|
|
8
|
+
* WAI-ARIA の APG は、この 3 つを Space で決定する(キーボードだけの人が選べない = WCAG 2.1.1)。
|
|
9
|
+
* **Enter は react-native-web が押したことにする**ので、ここでは Space だけを扱う(Enter まで扱うと二重に呼ばれる)。
|
|
10
|
+
*
|
|
11
|
+
* 実機の React Native は、`onKeyDown` を受けるキーを `keyDownEvents` で挙げたものだけにするので、何も渡さないこの使い方では
|
|
12
|
+
* 呼ばれない(実機の挙動は変わらない)。修飾キー(Ctrl・Alt・Meta・Shift)つきと、押しっぱなしの繰り返しは無視する。
|
|
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
|
+
* Space で `activate` を呼ぶ `onKeyDown`(`Pressable` に渡す)。
|
|
4
|
+
*
|
|
5
|
+
* react-native-web の `Pressable` は、Enter では押したことになるが、Space は **`<button>` か `role="button"` のときだけ**
|
|
6
|
+
* 押したことになる(`PressResponder` の `isValidKeyPress`)。`role="radio"` / `"checkbox"` / `"switch"` は Space で動かない。
|
|
7
|
+
* WAI-ARIA の APG は、この 3 つを Space で決定する(キーボードだけの人が選べない = WCAG 2.1.1)。
|
|
8
|
+
* **Enter は react-native-web が押したことにする**ので、ここでは Space だけを扱う(Enter まで扱うと二重に呼ばれる)。
|
|
9
|
+
*
|
|
10
|
+
* 実機の React Native は、`onKeyDown` を受けるキーを `keyDownEvents` で挙げたものだけにするので、何も渡さないこの使い方では
|
|
11
|
+
* 呼ばれない(実機の挙動は変わらない)。修飾キー(Ctrl・Alt・Meta・Shift)つきと、押しっぱなしの繰り返しは無視する。
|
|
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
|
+
/** 読み込み中の表示(Spinner) */
|
|
3
|
+
export declare const LOADING_LABEL = "読み込み中";
|
|
4
|
+
/** 確認ダイアログ(`confirm()`)の既定のボタン。使う側は `yes` / `no` で上書きする */
|
|
5
|
+
export declare const YES_LABEL = "はい";
|
|
6
|
+
export declare const NO_LABEL = "いいえ";
|
|
7
|
+
/** 数値欄(`form/text-input` の `type="number"`)の入力が数として読めないとき */
|
|
8
|
+
export declare const NUMBER_INVALID_LABEL = "数値で入力してください";
|
|
9
|
+
/** 閉じるボタン(Sheet・Modal・Snackbar)。使う側は `closeLabel` で上書きする */
|
|
10
|
+
export declare const CLOSE_LABEL = "閉じる";
|
|
11
|
+
/** `atom/select` の選択肢の見出し・名前が何も渡されなかったときの、最後の砦(無名のダイアログにしない) */
|
|
12
|
+
export declare const SELECT_LABEL = "選択肢";
|
|
13
|
+
/** `form/select` の placeholder の既定(web の `form/select` と同じ文言) */
|
|
14
|
+
export declare const SELECT_PLACEHOLDER_LABEL = "選択してください";
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/native/lib/labels.ts
|
|
2
|
+
/** 読み込み中の表示(Spinner) */
|
|
3
|
+
const LOADING_LABEL = "読み込み中";
|
|
4
|
+
/** 確認ダイアログ(`confirm()`)の既定のボタン。使う側は `yes` / `no` で上書きする */
|
|
5
|
+
const YES_LABEL = "はい";
|
|
6
|
+
const NO_LABEL = "いいえ";
|
|
7
|
+
/** 数値欄(`form/text-input` の `type="number"`)の入力が数として読めないとき */
|
|
8
|
+
const NUMBER_INVALID_LABEL = "数値で入力してください";
|
|
9
|
+
/** 閉じるボタン(Sheet・Modal・Snackbar)。使う側は `closeLabel` で上書きする */
|
|
10
|
+
const CLOSE_LABEL = "閉じる";
|
|
11
|
+
/** `atom/select` の選択肢の見出し・名前が何も渡されなかったときの、最後の砦(無名のダイアログにしない) */
|
|
12
|
+
const SELECT_LABEL = "選択肢";
|
|
13
|
+
/** `form/select` の placeholder の既定(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
|
+
/** `LoadingLock` が読む状態。命令的な API(`globalLoading()`)がここへ書く。 */
|
|
4
|
+
export declare const loadingStore: ExternalStore<boolean>;
|
|
5
|
+
/**
|
|
6
|
+
* アプリ全体の操作を塞ぐローディングを出す・消す。アプリのルートに `once/loading-lock` の `LoadingLock` を 1 つ置いておく。
|
|
7
|
+
* 真偽の 1 つだけを持つ(重ねて呼んでも数えない。最後に `false` を渡した時点で消える。移植元と同じ)。
|
|
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
|
+
/** `LoadingLock` が読む状態。命令的な API(`globalLoading()`)がここへ書く。 */
|
|
5
|
+
const loadingStore = createExternalStore(false);
|
|
6
|
+
/**
|
|
7
|
+
* アプリ全体の操作を塞ぐローディングを出す・消す。アプリのルートに `once/loading-lock` の `LoadingLock` を 1 つ置いておく。
|
|
8
|
+
* 真偽の 1 つだけを持つ(重ねて呼んでも数えない。最後に `false` を渡した時点で消える。移植元と同じ)。
|
|
9
|
+
*/
|
|
10
|
+
function globalLoading(loading) {
|
|
11
|
+
loadingStore.set(loading);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { globalLoading, loadingStore };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/native/lib/network.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* 現在オンラインかどうかを購読する。`once/offline-banner` の表示制御に使う。
|
|
4
|
+
* 移植元(`@lt-three/native` の `hooks/network.ts`)は TanStack Query の `onlineManager` を NetInfo に委譲していたが、
|
|
5
|
+
* love3 は TanStack Query に依存しないので、ここは NetInfo だけを見る(fetch の保留・復帰時の再取得を NetInfo に連動させたいアプリは、
|
|
6
|
+
* 自分で `onlineManager.setEventListener` を NetInfo に繋ぐ)。
|
|
7
|
+
*
|
|
8
|
+
* 実機は NetInfo の `isConnected`(判定中の `null` はオンライン扱いにして誤検知を避ける)。
|
|
9
|
+
* web(react-native-web)でも NetInfo は動き、`navigator.onLine` と `online` / `offline` イベントを見る。
|
|
10
|
+
*/
|
|
11
|
+
export declare function useIsOnline(): boolean;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { addEventListener } from "@react-native-community/netinfo";
|
|
3
|
+
|
|
4
|
+
//#region src/native/lib/network.ts
|
|
5
|
+
/**
|
|
6
|
+
* 現在オンラインかどうかを購読する。`once/offline-banner` の表示制御に使う。
|
|
7
|
+
* 移植元(`@lt-three/native` の `hooks/network.ts`)は TanStack Query の `onlineManager` を NetInfo に委譲していたが、
|
|
8
|
+
* love3 は TanStack Query に依存しないので、ここは NetInfo だけを見る(fetch の保留・復帰時の再取得を NetInfo に連動させたいアプリは、
|
|
9
|
+
* 自分で `onlineManager.setEventListener` を NetInfo に繋ぐ)。
|
|
10
|
+
*
|
|
11
|
+
* 実機は NetInfo の `isConnected`(判定中の `null` はオンライン扱いにして誤検知を避ける)。
|
|
12
|
+
* web(react-native-web)でも NetInfo は動き、`navigator.onLine` と `online` / `offline` イベントを見る。
|
|
13
|
+
*/
|
|
14
|
+
function useIsOnline() {
|
|
15
|
+
const [online, setOnline] = useState(true);
|
|
16
|
+
useEffect(() => addEventListener((state) => setOnline(state.isConnected !== false)), []);
|
|
17
|
+
return online;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { useIsOnline };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TokenName } from "../../tokens/tokens.gen.js";
|
|
2
|
+
//#region src/native/lib/scheme.d.ts
|
|
3
|
+
/** テーマ選択。`system` は端末設定に追従する。保存先(AsyncStorage・設定画面)はアプリの責務で、ここでは持たない。 */
|
|
4
|
+
export type ThemePreference = "system" | "light" | "dark";
|
|
5
|
+
/** 実際に描画に使われるテーマ。 */
|
|
6
|
+
export type ActiveScheme = "light" | "dark";
|
|
7
|
+
/** 選択と端末のカラースキームから、実際に使うテーマを決める。 */
|
|
8
|
+
export declare function resolveScheme(preference: ThemePreference, system: "light" | "dark" | "unspecified" | null | undefined): ActiveScheme;
|
|
9
|
+
/** 色のトークンの名前(書体 `font-*` と角丸 `radius` を除く)。`useTokenColor` が受けるのはこれだけ。 */
|
|
10
|
+
export type ColorTokenName = Exclude<TokenName, `font-${string}` | "radius">;
|
|
11
|
+
/**
|
|
12
|
+
* トークンの色の実値。DS が値を持ち(`@lt-three/love3/tokens`)、部品はここを通して引く。
|
|
13
|
+
* 名前は CSS 変数の形(`--ink-500`)でも、トークン名(`ink-500`)でもよい。色でないトークン(書体・角丸)は受けない。
|
|
14
|
+
*/
|
|
15
|
+
export declare function tokenColor(scheme: ActiveScheme, name: `--${ColorTokenName}` | ColorTokenName,
|
|
16
|
+
/** 調整(`TuningRoot`)が配る実効値。あれば、その値を優先する(実行時の上書きに追従する)。 */
|
|
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
|
+
/** 選択と端末のカラースキームから、実際に使うテーマを決める。 */
|
|
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
|
+
* トークンの色の実値。DS が値を持ち(`@lt-three/love3/tokens`)、部品はここを通して引く。
|
|
12
|
+
* 名前は CSS 変数の形(`--ink-500`)でも、トークン名(`ink-500`)でもよい。色でないトークン(書体・角丸)は受けない。
|
|
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,46 @@
|
|
|
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
|
+
/** 押すと呼ばれ、そのあとトーストは閉じる(web の sonner の action と同じ)。 */
|
|
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
|
+
* true なら自動で消えない(`dismissSnackbar` か、閉じるボタンで消す)。
|
|
24
|
+
* **`action` があるときの既定は true**(押す前に消えると、キーボードや支援技術で操作する人が間に合わない。WCAG 2.2.1)。
|
|
25
|
+
* `action` つきでも、`duration` を渡すか `persistent: false` を明示すれば、自動で消える。
|
|
26
|
+
*/
|
|
27
|
+
persistent?: boolean;
|
|
28
|
+
/** 自動で消えるまでの ms(既定 4000)。`persistent` のときは無視される。 */
|
|
29
|
+
duration?: number;
|
|
30
|
+
};
|
|
31
|
+
/** `Snackbar` が読む待ち行列。命令的な API(`snackbar()`)がここへ書く。 */
|
|
32
|
+
export declare const snackbarStore: ExternalStore<readonly SnackbarItem[]>;
|
|
33
|
+
/** `Snackbar` がマウントされている間だけ呼ぶ(`once/snackbar` が effect で呼ぶ)。戻り値は解除。未マウントの警告に使う。 */
|
|
34
|
+
export declare function registerSnackbarHost(): () => void;
|
|
35
|
+
/**
|
|
36
|
+
* トーストを出す。戻り値の id は `dismissSnackbar` に渡せる。
|
|
37
|
+
* アプリのルートに `once/snackbar` の `Snackbar` を 1 つ置いておく(**置いていないと出ない**。開発時は警告を出す。
|
|
38
|
+
* 自動で消えるまでの時間は、置く前でも進む)。
|
|
39
|
+
* 移植元の `@lt-three/native/lib/snackbar`(jotai の atom)と同じ形の API を、外部ストアで作り直した。
|
|
40
|
+
*/
|
|
41
|
+
export declare function snackbar(title: string, options?: SnackbarOptions): string | number;
|
|
42
|
+
/** 指定したトーストを閉じる。 */
|
|
43
|
+
export declare function dismissSnackbar(id: string | number): void;
|
|
44
|
+
/** 出ているトーストを全部閉じる(自動で消える予約も全部取り消す)。 */
|
|
45
|
+
export declare function dismissAllSnackbars(): void;
|
|
46
|
+
//#endregion
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createExternalStore } from "./external-store.js";
|
|
2
|
+
|
|
3
|
+
//#region src/native/lib/snackbar.ts
|
|
4
|
+
/** `Snackbar` が読む待ち行列。命令的な API(`snackbar()`)がここへ書く。 */
|
|
5
|
+
const snackbarStore = createExternalStore([]);
|
|
6
|
+
const DEFAULT_DURATION = 4e3;
|
|
7
|
+
let sequence = 0;
|
|
8
|
+
const timers = /* @__PURE__ */ new Map();
|
|
9
|
+
let mountedHosts = 0;
|
|
10
|
+
/** `Snackbar` がマウントされている間だけ呼ぶ(`once/snackbar` が effect で呼ぶ)。戻り値は解除。未マウントの警告に使う。 */
|
|
11
|
+
function registerSnackbarHost() {
|
|
12
|
+
mountedHosts += 1;
|
|
13
|
+
return () => {
|
|
14
|
+
mountedHosts -= 1;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* トーストを出す。戻り値の id は `dismissSnackbar` に渡せる。
|
|
19
|
+
* アプリのルートに `once/snackbar` の `Snackbar` を 1 つ置いておく(**置いていないと出ない**。開発時は警告を出す。
|
|
20
|
+
* 自動で消えるまでの時間は、置く前でも進む)。
|
|
21
|
+
* 移植元の `@lt-three/native/lib/snackbar`(jotai の atom)と同じ形の API を、外部ストアで作り直した。
|
|
22
|
+
*/
|
|
23
|
+
function snackbar(title, options) {
|
|
24
|
+
if (__DEV__ && mountedHosts === 0) console.warn("snackbar(): Snackbar がマウントされていない。アプリのルートに <Snackbar /> を 1 つ置くまで、このトーストは出ない。");
|
|
25
|
+
sequence += 1;
|
|
26
|
+
const id = options?.id ?? sequence;
|
|
27
|
+
const persistent = options?.persistent ?? (options?.action !== void 0 && options.duration === void 0);
|
|
28
|
+
const item = {
|
|
29
|
+
id,
|
|
30
|
+
icon: options?.icon ?? "info",
|
|
31
|
+
title,
|
|
32
|
+
description: options?.description,
|
|
33
|
+
action: options?.action,
|
|
34
|
+
persistent
|
|
35
|
+
};
|
|
36
|
+
snackbarStore.update((items) => [...items.filter((candidate) => candidate.id !== id), item]);
|
|
37
|
+
clearTimer(id);
|
|
38
|
+
if (!persistent) timers.set(id, setTimeout(() => dismissSnackbar(id), options?.duration ?? DEFAULT_DURATION));
|
|
39
|
+
return id;
|
|
40
|
+
}
|
|
41
|
+
/** 指定したトーストを閉じる。 */
|
|
42
|
+
function dismissSnackbar(id) {
|
|
43
|
+
clearTimer(id);
|
|
44
|
+
snackbarStore.update((items) => items.filter((candidate) => candidate.id !== id));
|
|
45
|
+
}
|
|
46
|
+
/** 出ているトーストを全部閉じる(自動で消える予約も全部取り消す)。 */
|
|
47
|
+
function dismissAllSnackbars() {
|
|
48
|
+
for (const timer of timers.values()) clearTimeout(timer);
|
|
49
|
+
timers.clear();
|
|
50
|
+
snackbarStore.set([]);
|
|
51
|
+
}
|
|
52
|
+
function clearTimer(id) {
|
|
53
|
+
const timer = timers.get(id);
|
|
54
|
+
if (timer === void 0) return;
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
timers.delete(id);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
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
|
+
* 現在の有効テーマ。
|
|
6
|
+
*
|
|
7
|
+
* 配色そのものはここでは返さない。色は NativeWind のセマンティッククラス
|
|
8
|
+
* (`bg-background` / `text-foreground` 等)から取る。このフックは
|
|
9
|
+
* ネイティブ側 API(react-navigation のテーマ、StatusBar、SF Symbols の tint、チャートの色等)に
|
|
10
|
+
* ライト/ダークを渡す必要がある箇所だけで使う。
|
|
11
|
+
*/
|
|
12
|
+
export declare function useActiveScheme(): ActiveScheme;
|
|
13
|
+
export type ThemeRootProps = {
|
|
14
|
+
/** テーマ選択。保存先(AsyncStorage・jotai など)はアプリが持ち、ここへは値だけを渡す。 */
|
|
15
|
+
preference: ThemePreference;
|
|
16
|
+
children: ReactNode;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* テーマを実際の描画へ反映するルート。
|
|
20
|
+
*
|
|
21
|
+
* `@lt-three/love3/styles.css` は `.dark { --paper: ...; ... }` という
|
|
22
|
+
* **クラスベース**のダークトークンを定義している。react-native-css はこのクラス規則をそのまま
|
|
23
|
+
* コンパイルするため、ルートに `className="dark"` を置けば子孫すべてにダークの CSS 変数が配られる。
|
|
24
|
+
* web の `<html class="dark">` と同じ仕組みで、トークンを TS 側に複製しなくて済む。
|
|
25
|
+
*
|
|
26
|
+
* あわせて RN の `Appearance` も同期する。ナビゲーションのテーマや StatusBar など、
|
|
27
|
+
* NativeWind の外側にあるネイティブ UI がこれを見ている。
|
|
28
|
+
*
|
|
29
|
+
* **web(react-native-web)では使わない。** web のテーマは `<html class="dark">` が持つ
|
|
30
|
+
* (preview・vitest はそのまま切り替える)。
|
|
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
|
+
/** `ThemeRoot` が配る有効テーマ。`ThemeRoot` の外では端末のカラースキームに従う。 */
|
|
8
|
+
const SchemeContext = createContext(null);
|
|
9
|
+
/**
|
|
10
|
+
* 現在の有効テーマ。
|
|
11
|
+
*
|
|
12
|
+
* 配色そのものはここでは返さない。色は NativeWind のセマンティッククラス
|
|
13
|
+
* (`bg-background` / `text-foreground` 等)から取る。このフックは
|
|
14
|
+
* ネイティブ側 API(react-navigation のテーマ、StatusBar、SF Symbols の tint、チャートの色等)に
|
|
15
|
+
* ライト/ダークを渡す必要がある箇所だけで使う。
|
|
16
|
+
*/
|
|
17
|
+
function useActiveScheme() {
|
|
18
|
+
const fromRoot = useContext(SchemeContext);
|
|
19
|
+
const system = useColorScheme();
|
|
20
|
+
return fromRoot ?? resolveScheme("system", system);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* テーマを実際の描画へ反映するルート。
|
|
24
|
+
*
|
|
25
|
+
* `@lt-three/love3/styles.css` は `.dark { --paper: ...; ... }` という
|
|
26
|
+
* **クラスベース**のダークトークンを定義している。react-native-css はこのクラス規則をそのまま
|
|
27
|
+
* コンパイルするため、ルートに `className="dark"` を置けば子孫すべてにダークの CSS 変数が配られる。
|
|
28
|
+
* web の `<html class="dark">` と同じ仕組みで、トークンを TS 側に複製しなくて済む。
|
|
29
|
+
*
|
|
30
|
+
* あわせて RN の `Appearance` も同期する。ナビゲーションのテーマや StatusBar など、
|
|
31
|
+
* NativeWind の外側にあるネイティブ UI がこれを見ている。
|
|
32
|
+
*
|
|
33
|
+
* **web(react-native-web)では使わない。** web のテーマは `<html class="dark">` が持つ
|
|
34
|
+
* (preview・vitest はそのまま切り替える)。
|
|
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
|
+
* タイムゾーン(IANA 文字列)のユーティリティ。`atom/timezone-select` が使う。
|
|
4
|
+
* 移植元は `@lt-three/core/lib/timezone`。love3 は core に依存しないので、native の `lib/` に持つ
|
|
5
|
+
* (web の love3 に timezone-select が移ったら `shared/` へ移して共有する)。
|
|
6
|
+
*
|
|
7
|
+
* 選択肢を `Intl.supportedValuesOf("timeZone")` から作らないのは、native の JS エンジン
|
|
8
|
+
* Hermes にそれが無いため(Hermes 250829098.0.16 の hermesvm バイナリに文字列が無いことを確認した。
|
|
9
|
+
* `Intl.DateTimeFormat` の `resolvedOptions().timeZone` は iOS / Android とも持つ)。
|
|
10
|
+
* 全ゾーン(約 420)を出しても検索の無い選択リストでは使えないので、固定リストにしている。
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* 主要な IANA タイムゾーン。各地域の代表的な都市を IANA の tz database から選んだ。
|
|
14
|
+
* ここに無い値でも、デバイスのタイムゾーンと保存済みの値は `timeZoneOptions` が必ず足す。
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAJOR_TIME_ZONES: readonly string[];
|
|
17
|
+
/** この端末のタイムゾーン(IANA 文字列)。取れなければ空文字。 */
|
|
18
|
+
export declare function getDeviceTimeZone(): string;
|
|
19
|
+
/**
|
|
20
|
+
* 選択肢のタイムゾーン一覧。固定リストに `extra`(デバイスの値・保存済みの値)を足し、
|
|
21
|
+
* 重複と空文字を除いて返す。リストに無い値が選択済みのとき、選択肢から消えて空表示になるのを防ぐ。
|
|
22
|
+
*/
|
|
23
|
+
export declare function timeZoneOptions(...extra: string[]): string[];
|
|
24
|
+
/** 表示用の名前。IANA の `_` は読みにくいので空白に直す(`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
|
+
* タイムゾーン(IANA 文字列)のユーティリティ。`atom/timezone-select` が使う。
|
|
4
|
+
* 移植元は `@lt-three/core/lib/timezone`。love3 は core に依存しないので、native の `lib/` に持つ
|
|
5
|
+
* (web の love3 に timezone-select が移ったら `shared/` へ移して共有する)。
|
|
6
|
+
*
|
|
7
|
+
* 選択肢を `Intl.supportedValuesOf("timeZone")` から作らないのは、native の JS エンジン
|
|
8
|
+
* Hermes にそれが無いため(Hermes 250829098.0.16 の hermesvm バイナリに文字列が無いことを確認した。
|
|
9
|
+
* `Intl.DateTimeFormat` の `resolvedOptions().timeZone` は iOS / Android とも持つ)。
|
|
10
|
+
* 全ゾーン(約 420)を出しても検索の無い選択リストでは使えないので、固定リストにしている。
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* 主要な IANA タイムゾーン。各地域の代表的な都市を IANA の tz database から選んだ。
|
|
14
|
+
* ここに無い値でも、デバイスのタイムゾーンと保存済みの値は `timeZoneOptions` が必ず足す。
|
|
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
|
+
/** この端末のタイムゾーン(IANA 文字列)。取れなければ空文字。 */
|
|
73
|
+
function getDeviceTimeZone() {
|
|
74
|
+
try {
|
|
75
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone ?? "";
|
|
76
|
+
} catch {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 選択肢のタイムゾーン一覧。固定リストに `extra`(デバイスの値・保存済みの値)を足し、
|
|
82
|
+
* 重複と空文字を除いて返す。リストに無い値が選択済みのとき、選択肢から消えて空表示になるのを防ぐ。
|
|
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
|
+
/** 表示用の名前。IANA の `_` は読みにくいので空白に直す(`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
|
+
/** 引数は CSS 変数の形の色のトークン(`--ink-500`)。セマンティックな名前(`--muted-foreground`)も引ける。書体・角丸は受けない。 */
|
|
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
|
+
/** 引数は CSS 変数の形の色のトークン(`--ink-500`)。セマンティックな名前(`--muted-foreground`)も引ける。書体・角丸は受けない。 */
|
|
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
|
+
* 調整(`TuningRoot`)が配る、トークンの実効値(ライト・ダーク別。参照を解決した値)。無ければ(`TuningRoot` の外)調整なし。
|
|
5
|
+
* TS から色を引く `useTokenColor` が、これを見て実行時の上書きに追従する。
|
|
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
|
+
/** 調整の内容(既定との差分。`@lt-three/love3/tuning` の `Tuning`。保存先はアプリが持つ)。 */
|
|
6
|
+
tuning: Tuning;
|
|
7
|
+
/** 調整の対象。既定は love3 の生成物(`tuning/catalog.gen.ts`)。 */
|
|
8
|
+
catalog?: TuningCatalog;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* 調整(トークンの実行時の上書き)を、子孫の部品に反映するルート。**`ThemeRoot` の内側**に置く(有効テーマと、ダークの変数を受け取るため)。
|
|
13
|
+
*
|
|
14
|
+
* - `react-native-css` の `VariableContextProvider` で、変えた色・角丸・書体を CSS 変数として配る。実機で効くのは、
|
|
15
|
+
* ライト・ダークで値が違う色のトークンを使うクラス(`bg-card` など)と書体。`bg-action` などビルド時にリテラルへ
|
|
16
|
+
* 畳み込まれるクラス・角丸・本文サイズ・セマンティックの参照先は、**実機では効かない**(`nativeLimits` が説明を返す。
|
|
17
|
+
* react-native-web では CSS 変数なので全部効く)
|
|
18
|
+
* - TS から色を引く部品(`useTokenColor`)は、実効値(参照を解決した値)を `TuningTokensContext` から引くので、**全部追従する**
|
|
19
|
+
* - 調整が無い(既定と同じ)なら、何も変えない(`tuning` を空にすれば元の見た目)
|
|
20
|
+
*
|
|
21
|
+
* 実機(Expo)での確認は未実施。react-native-web の browser test で確かめた範囲を README に書いてある。
|
|
22
|
+
*/
|
|
23
|
+
export declare function TuningRoot({ tuning, catalog, children }: TuningRootProps): import("react").JSX.Element;
|
|
24
|
+
//#endregion
|