@symbiote-native/localization 0.2.0 → 0.3.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 +54 -17
- package/build/angular/services/calendars.service/index.js +2 -2
- package/build/angular/services/locales.service/index.js +1 -1
- package/build/core/index.d.ts +1 -1
- package/build/core/index.js +1 -1
- package/build/react/hooks/use-calendars/index.js +1 -1
- package/build/solid/index.d.ts +3 -0
- package/build/solid/index.js +8 -0
- package/build/solid/primitives/create-calendars.d.ts +3 -0
- package/build/solid/primitives/create-calendars.js +14 -0
- package/build/solid/primitives/create-locales.d.ts +3 -0
- package/build/solid/primitives/create-locales.js +24 -0
- package/build/svelte/runes/use-locales.svelte.js +1 -1
- package/build/vue/composables/use-locales/index.js +1 -1
- package/build-ngc/angular/services/calendars.service/index.js +2 -2
- package/build-ngc/angular/services/calendars.service/index.js.map +1 -1
- package/build-ngc/angular/services/locales.service/index.js +1 -1
- package/build-ngc/angular/services/locales.service/index.js.map +1 -1
- package/build-ngc/core/index.d.ts +1 -1
- package/build-ngc/core/index.js +1 -1
- package/build-ngc/core/index.js.map +1 -1
- package/build-ngc/core/localization.js.map +1 -1
- package/build-ngc/core/native-module.js.map +1 -1
- package/package.json +22 -8
- package/src/angular/services/calendars.service/index.ts +16 -3
- package/src/angular/services/locales.service/index.ts +8 -1
- package/src/core/index.ts +6 -1
- package/src/core/localization.ts +2 -1
- package/src/core/native-module.ts +11 -3
- package/src/react/hooks/use-calendars/index.ts +5 -1
- package/src/solid/index.ts +9 -0
- package/src/solid/primitives/create-calendars.ts +23 -0
- package/src/solid/primitives/create-locales.ts +33 -0
- package/src/svelte/runes/use-locales.svelte.ts +6 -1
- package/src/vue/composables/use-locales/index.ts +6 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Port of [`expo-localization`](https://docs.expo.dev/versions/latest/sdk/localization/) for
|
|
4
4
|
[SymbioteNative](../../README.md) — the device's locale list and preferred calendar settings,
|
|
5
|
-
reachable from every adapter (React, Vue, Angular), not just React.
|
|
5
|
+
reachable from every adapter (React, Vue, Svelte, Solid, Angular), not just React.
|
|
6
6
|
|
|
7
7
|
Built the same way as [`@symbiote-native/battery`](../battery) and
|
|
8
8
|
[`@symbiote-native/device`](../device), an `expo-modules-core`-based wrapper (see the
|
|
@@ -29,12 +29,12 @@ Unlike a plain RN native module, `expo-localization`'s native code is discovered
|
|
|
29
29
|
into the native host app **once**, covering this package and every other `expo-modules-core`
|
|
30
30
|
package (`@symbiote-native/battery`, `@symbiote-native/device`, ...) with zero further changes:
|
|
31
31
|
|
|
32
|
-
| Platform | Touches
|
|
33
|
-
|
|
34
|
-
| iOS
|
|
35
|
-
| iOS
|
|
36
|
-
| Android
|
|
37
|
-
| Android
|
|
32
|
+
| Platform | Touches |
|
|
33
|
+
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
|
+
| iOS | `ios/Podfile` — add `use_expo_modules!` |
|
|
35
|
+
| iOS | `AppDelegate.swift` — Expo's runtime-bootstrap hook |
|
|
36
|
+
| Android | `settings.gradle` / `app/build.gradle` — resolve and include the Expo Gradle projects |
|
|
37
|
+
| Android | `MainApplication.kt` — Expo's bootstrap hook, plus a hand-written native-module name map (there's no `expo` meta-package here to auto-generate one) |
|
|
38
38
|
|
|
39
39
|
Full mechanics — the Podfile pieces that normally ship inside the `expo` package, the `expo`
|
|
40
40
|
peer-dependency exclusion list — live in the `symbiote-expo-native-module` skill. Reference
|
|
@@ -55,13 +55,18 @@ src/core/ types.ts — Locale, Weekday, CalendarIdentifier, Calend
|
|
|
55
55
|
native module.
|
|
56
56
|
src/react/hooks/ @symbiote-native/localization/react — useLocales, useCalendars
|
|
57
57
|
src/vue/composables/ @symbiote-native/localization/vue — same two names, Vue lifecycle
|
|
58
|
+
src/svelte/runes/ @symbiote-native/localization/svelte — same two names, read as `.current`
|
|
59
|
+
src/solid/primitives/ @symbiote-native/localization/solid — createLocales, createCalendars
|
|
60
|
+
(each returns an Accessor)
|
|
58
61
|
src/angular/services/ @symbiote-native/localization/angular — LocalesService, CalendarsService
|
|
59
62
|
(`.connect()` returns a Signal)
|
|
60
63
|
```
|
|
61
64
|
|
|
62
65
|
Two independent getters, each with its own native change listener and its own reactive hook per
|
|
63
66
|
adapter — mirroring `@symbiote-native/battery`'s shape of shipping several distinct hooks in one
|
|
64
|
-
package, not one combined hook.
|
|
67
|
+
package, not one combined hook. Solid's naming differs on purpose: `create*`, not `use*`, which
|
|
68
|
+
Solid reserves for consuming something that already exists. Each hook/composable/rune/primitive/
|
|
69
|
+
service seeds its return value from the
|
|
65
70
|
matching synchronous `get*()` call (no initial "loading" state needed — the native call is
|
|
66
71
|
sync, not async) and recomputes it whenever the matching listener fires.
|
|
67
72
|
|
|
@@ -72,8 +77,8 @@ sync, not async) and recomputes it whenever the matching listener fires.
|
|
|
72
77
|
import { useLocales, useCalendars } from '@symbiote-native/localization/react';
|
|
73
78
|
|
|
74
79
|
function LocalizationScreen() {
|
|
75
|
-
const locales = useLocales();
|
|
76
|
-
const calendars = useCalendars();
|
|
80
|
+
const locales = useLocales(); // Locale[], guaranteed at least 1 element
|
|
81
|
+
const calendars = useCalendars(); // Calendar[], guaranteed at least 1 element
|
|
77
82
|
|
|
78
83
|
return (
|
|
79
84
|
<>
|
|
@@ -89,7 +94,7 @@ function LocalizationScreen() {
|
|
|
89
94
|
<script setup lang="ts">
|
|
90
95
|
import { useLocales, useCalendars } from '@symbiote-native/localization/vue';
|
|
91
96
|
|
|
92
|
-
const locales = useLocales();
|
|
97
|
+
const locales = useLocales(); // Ref<Locale[]>
|
|
93
98
|
const calendars = useCalendars(); // Ref<Calendar[]>
|
|
94
99
|
</script>
|
|
95
100
|
<template>
|
|
@@ -98,15 +103,39 @@ const calendars = useCalendars(); // Ref<Calendar[]>
|
|
|
98
103
|
</template>
|
|
99
104
|
```
|
|
100
105
|
|
|
106
|
+
```tsx
|
|
107
|
+
// Solid — an accessor per getter; call it to read, so a component body that runs once still
|
|
108
|
+
// re-renders the leaf that reads it.
|
|
109
|
+
import {
|
|
110
|
+
createLocales,
|
|
111
|
+
createCalendars,
|
|
112
|
+
} from '@symbiote-native/localization/solid';
|
|
113
|
+
|
|
114
|
+
function LocalizationScreen() {
|
|
115
|
+
const locales = createLocales(); // Accessor<Locale[]>
|
|
116
|
+
const calendars = createCalendars(); // Accessor<Calendar[]>
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<>
|
|
120
|
+
<Text>{locales()[0].languageTag}</Text>
|
|
121
|
+
<Text>{calendars()[0].timeZone}</Text>
|
|
122
|
+
</>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
101
127
|
```ts
|
|
102
128
|
// Angular — examples/expo-angular/src/screens/LocalizationScreen.ts
|
|
103
129
|
import { Component, inject } from '@angular/core';
|
|
104
|
-
import {
|
|
130
|
+
import {
|
|
131
|
+
LocalesService,
|
|
132
|
+
CalendarsService,
|
|
133
|
+
} from '@symbiote-native/localization/angular';
|
|
105
134
|
|
|
106
|
-
@Component({
|
|
135
|
+
@Component({/* ... */})
|
|
107
136
|
export class LocalizationScreen {
|
|
108
|
-
readonly locales = inject(LocalesService).connect();
|
|
109
|
-
readonly calendars = inject(CalendarsService).connect();
|
|
137
|
+
readonly locales = inject(LocalesService).connect(); // Signal<Locale[]>
|
|
138
|
+
readonly calendars = inject(CalendarsService).connect(); // Signal<Calendar[]>
|
|
110
139
|
}
|
|
111
140
|
```
|
|
112
141
|
|
|
@@ -134,7 +163,15 @@ import { getLocales, getCalendars } from '@symbiote-native/localization';
|
|
|
134
163
|
// hook/composable/service per getter:
|
|
135
164
|
import { useLocales, useCalendars } from '@symbiote-native/localization/react';
|
|
136
165
|
import { useLocales, useCalendars } from '@symbiote-native/localization/vue';
|
|
137
|
-
import {
|
|
166
|
+
import { useLocales, useCalendars } from '@symbiote-native/localization/svelte';
|
|
167
|
+
import {
|
|
168
|
+
createLocales,
|
|
169
|
+
createCalendars,
|
|
170
|
+
} from '@symbiote-native/localization/solid';
|
|
171
|
+
import {
|
|
172
|
+
LocalesService,
|
|
173
|
+
CalendarsService,
|
|
174
|
+
} from '@symbiote-native/localization/angular';
|
|
138
175
|
```
|
|
139
176
|
|
|
140
177
|
Each hook/composable/service seeds its initial value from the matching synchronous `get*()`
|
|
@@ -146,7 +183,7 @@ mirroring upstream's own `useLocales`/`useCalendars`.
|
|
|
146
183
|
No Fabric/Descriptor angle at all — localization is a pure synchronous-function + `EventEmitter`
|
|
147
184
|
listener surface, never a view. Tests inject a fake native-module object in place of the real
|
|
148
185
|
`requireNativeModule` resolution (`src/core/localization.test.ts`,
|
|
149
|
-
`src/{react,vue,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
|
|
186
|
+
`src/{react,vue,svelte,solid,angular}/**/*.test.{ts,tsx}`, `vitest`), the same pattern
|
|
150
187
|
`@symbiote-native/battery` and `@symbiote-native/device` use — no `installFabric()`, no
|
|
151
188
|
ViewConfig for the core test; the adapter hook/composable/service tests do use `installFabric()`
|
|
152
189
|
purely to mount a host component, same as every other sibling package. Native rendering itself is
|
|
@@ -32,8 +32,8 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
32
32
|
}
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
|
-
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
36
|
-
import { addCalendarListener, getCalendars } from '../../../core/index.js';
|
|
35
|
+
import { effect, inject, Injectable, Injector, signal, } from '@angular/core';
|
|
36
|
+
import { addCalendarListener, getCalendars, } from '../../../core/index.js';
|
|
37
37
|
// Angular twin of React's `useCalendars` hook and Vue's `useCalendars` composable — mirrors
|
|
38
38
|
// LocalesService's shape exactly.
|
|
39
39
|
//
|
|
@@ -32,7 +32,7 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
32
32
|
}
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
|
-
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
35
|
+
import { effect, inject, Injectable, Injector, signal, } from '@angular/core';
|
|
36
36
|
import { addLocaleListener, getLocales } from '../../../core/index.js';
|
|
37
37
|
// Angular twin of React's `useLocales` hook and Vue's `useLocales` composable. See
|
|
38
38
|
// packages/battery's BatteryStateService for the `connect()` pattern rationale. getLocales() is
|
package/build/core/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { getLocales, getCalendars } from './localization';
|
|
2
2
|
export { addLocaleListener, addCalendarListener } from './native-module';
|
|
3
|
-
export { Weekday, CalendarIdentifier, type Locale, type Calendar } from './types';
|
|
3
|
+
export { Weekday, CalendarIdentifier, type Locale, type Calendar, } from './types';
|
|
4
4
|
export type { EventSubscription } from 'expo-modules-core';
|
package/build/core/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// React lifecycle wiring over the framework-agnostic core — mirrors use-locales' shape exactly.
|
|
2
2
|
// Ported from expo-localization's own useCalendars hook (sdk-57).
|
|
3
3
|
import { useEffect, useMemo, useReducer } from 'react';
|
|
4
|
-
import { addCalendarListener, getCalendars } from '../../../core/index.js';
|
|
4
|
+
import { addCalendarListener, getCalendars, } from '../../../core/index.js';
|
|
5
5
|
export function useCalendars() {
|
|
6
6
|
const [invalidationKey, invalidate] = useReducer((key) => key + 1, 0);
|
|
7
7
|
const calendars = useMemo(() => getCalendars(), [invalidationKey]);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// @symbiote-native/localization/solid: the Solid entry over the framework-agnostic core. Locales
|
|
2
|
+
// and calendars each get their own primitive, matching upstream's own useLocales/useCalendars
|
|
3
|
+
// being two separate hooks, not one combined hook — mirrors the lifecycle-bucket naming of
|
|
4
|
+
// adapters/solid/src/primitives (never `hooks/`/`composables/`/`runes/`, and `create*` rather
|
|
5
|
+
// than `use*`, which Solid reserves for consuming something that already exists).
|
|
6
|
+
export { createLocales } from './primitives/create-locales.js';
|
|
7
|
+
export { createCalendars } from './primitives/create-calendars.js';
|
|
8
|
+
export * from '../core/index.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Solid lifecycle wiring over the framework-agnostic core (core/localization.ts) — mirrors
|
|
2
|
+
// create-locales' shape exactly, including why no seed-vs-event guard is needed here.
|
|
3
|
+
import { createSignal, onCleanup } from 'solid-js';
|
|
4
|
+
import { addCalendarListener, getCalendars, } from '../../core/index.js';
|
|
5
|
+
export function createCalendars() {
|
|
6
|
+
const [calendars, setCalendars] = createSignal(getCalendars());
|
|
7
|
+
const subscription = addCalendarListener(() => {
|
|
8
|
+
setCalendars(getCalendars());
|
|
9
|
+
});
|
|
10
|
+
onCleanup(() => {
|
|
11
|
+
subscription.remove();
|
|
12
|
+
});
|
|
13
|
+
return calendars;
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Solid lifecycle wiring over the framework-agnostic core (core/localization.ts) — the twin of
|
|
2
|
+
// react/hooks/use-locales, vue/composables/use-locales and svelte/runes/use-locales.svelte. See
|
|
3
|
+
// adapters/solid/src/primitives/create-color-scheme.ts for why the bucket is `primitives/` and
|
|
4
|
+
// the name is `create*` rather than `use*`.
|
|
5
|
+
//
|
|
6
|
+
// Returns an ACCESSOR, never a snapshot: a Solid component body runs ONCE, so a returned array
|
|
7
|
+
// would pin the screen to the locale list the app booted with.
|
|
8
|
+
//
|
|
9
|
+
// getLocales() is a SYNCHRONOUS native read, so seed and subscribe both happen inline in the body
|
|
10
|
+
// and there is no seed-vs-event race to guard (unlike the battery primitives, whose seed is a
|
|
11
|
+
// promise) — and no re-read on mount either, which the Vue and Svelte twins need only because
|
|
12
|
+
// their subscription is deferred to an effect.
|
|
13
|
+
import { createSignal, onCleanup } from 'solid-js';
|
|
14
|
+
import { addLocaleListener, getLocales, } from '../../core/index.js';
|
|
15
|
+
export function createLocales() {
|
|
16
|
+
const [locales, setLocales] = createSignal(getLocales());
|
|
17
|
+
const subscription = addLocaleListener(() => {
|
|
18
|
+
setLocales(getLocales());
|
|
19
|
+
});
|
|
20
|
+
onCleanup(() => {
|
|
21
|
+
subscription.remove();
|
|
22
|
+
});
|
|
23
|
+
return locales;
|
|
24
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// Returns a boxed getter, not a bare `$state`: Svelte 5 reactivity is lexically scoped to the
|
|
8
8
|
// declaring module and doesn't survive being returned raw from a plain function, so the caller
|
|
9
9
|
// reads `.current` like unwrapping Vue's `Ref` via `.value`.
|
|
10
|
-
import { addLocaleListener, getLocales } from '../../core/index.js';
|
|
10
|
+
import { addLocaleListener, getLocales, } from '../../core/index.js';
|
|
11
11
|
export function useLocales() {
|
|
12
12
|
let locales = $state(getLocales());
|
|
13
13
|
$effect(() => {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// setup — onMounted only wires the change listener, mirroring use-network-state's
|
|
5
5
|
// onMounted/onUnmounted subscription shape otherwise.
|
|
6
6
|
import { onMounted, onUnmounted, ref } from '@vue/runtime-core';
|
|
7
|
-
import { addLocaleListener, getLocales } from '../../../core/index.js';
|
|
7
|
+
import { addLocaleListener, getLocales, } from '../../../core/index.js';
|
|
8
8
|
export function useLocales() {
|
|
9
9
|
const locales = ref(getLocales());
|
|
10
10
|
let subscription;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
2
|
-
import { addCalendarListener, getCalendars } from '../../../core';
|
|
1
|
+
import { effect, inject, Injectable, Injector, signal, } from '@angular/core';
|
|
2
|
+
import { addCalendarListener, getCalendars, } from '../../../core';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
// Angular twin of React's `useCalendars` hook and Vue's `useCalendars` composable — mirrors
|
|
5
5
|
// LocalesService's shape exactly.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/calendars.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/calendars.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,UAAU,EACV,QAAQ,EACR,MAAM,GAEP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,mBAAmB,EACnB,YAAY,GAEb,MAAM,eAAe,CAAC;;AAEvB,4FAA4F;AAC5F,kCAAkC;AAClC,EAAE;AACF,6DAA6D;AAC7D,mCAAmC;AAEnC,MAAM,OAAO,gBAAgB;IACV,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO;QACL,MAAM,SAAS,GAAG,MAAM,CAAa,YAAY,EAAE;sFAAC,CAAC;QAErD,MAAM,CACJ,SAAS,CAAC,EAAE;YACV,MAAM,YAAY,GAAG,mBAAmB,CAAC,GAAG,EAAE,CAC5C,SAAS,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAC9B,CAAC;YACF,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B,CAAC;QAEF,OAAO,SAAS,CAAC,UAAU,EAAE,CAAC;IAChC,CAAC;uGAjBU,gBAAgB;2GAAhB,gBAAgB,cADH,MAAM;;2FACnB,gBAAgB;kBAD5B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { effect, inject, Injectable, Injector, signal } from '@angular/core';
|
|
1
|
+
import { effect, inject, Injectable, Injector, signal, } from '@angular/core';
|
|
2
2
|
import { addLocaleListener, getLocales } from '../../../core';
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
// Angular twin of React's `useLocales` hook and Vue's `useLocales` composable. See
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/locales.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/angular/services/locales.service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,MAAM,EACN,UAAU,EACV,QAAQ,EACR,MAAM,GAEP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAe,MAAM,eAAe,CAAC;;AAE3E,mFAAmF;AACnF,gGAAgG;AAChG,0FAA0F;AAC1F,EAAE;AACF,yDAAyD;AACzD,iCAAiC;AAEjC,MAAM,OAAO,cAAc;IACR,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO;QACL,MAAM,OAAO,GAAG,MAAM,CAAW,UAAU,EAAE;oFAAC,CAAC;QAE/C,MAAM,CACJ,SAAS,CAAC,EAAE;YACV,MAAM,YAAY,GAAG,iBAAiB,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YACxE,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B,CAAC;QAEF,OAAO,OAAO,CAAC,UAAU,EAAE,CAAC;IAC9B,CAAC;uGAfU,cAAc;2GAAd,cAAc,cADD,MAAM;;2FACnB,cAAc;kBAD1B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { getLocales, getCalendars } from './localization';
|
|
2
2
|
export { addLocaleListener, addCalendarListener } from './native-module';
|
|
3
|
-
export { Weekday, CalendarIdentifier, type Locale, type Calendar } from './types';
|
|
3
|
+
export { Weekday, CalendarIdentifier, type Locale, type Calendar, } from './types';
|
|
4
4
|
export type { EventSubscription } from 'expo-modules-core';
|
package/build-ngc/core/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { getLocales, getCalendars } from './localization';
|
|
2
2
|
export { addLocaleListener, addCalendarListener } from './native-module';
|
|
3
|
-
export { Weekday, CalendarIdentifier } from './types';
|
|
3
|
+
export { Weekday, CalendarIdentifier, } from './types';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EACL,OAAO,EACP,kBAAkB,GAGnB,MAAM,SAAS,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localization.js","sourceRoot":"","sources":["../../src/core/localization.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,gGAAgG;AAChG,+BAA+B;AAC/B,OAAO,sBAAsB,MAAM,iBAAiB,CAAC;AAGrD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAmB,sBAAsB,CAAC,UAAU,CAAC;AAE5E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"localization.js","sourceRoot":"","sources":["../../src/core/localization.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,gGAAgG;AAChG,+BAA+B;AAC/B,OAAO,sBAAsB,MAAM,iBAAiB,CAAC;AAGrD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAmB,sBAAsB,CAAC,UAAU,CAAC;AAE5E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,YAAY,GACvB,sBAAsB,CAAC,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,+FAA+F;AAC/F,6EAA6E;AAC7E,gGAAgG;AAChG,4FAA4F;AAC5F,4EAA4E;AAC5E,OAAO,EAA0B,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGhF,MAAM,6BAA6B,GAAG,kBAAkB,CAAC;AAezD,MAAM,sBAAsB,GAAG,mBAAmB,CAChD,6BAA6B,CAC9B,CAAC;AAEF,MAAM,UAAU,iBAAiB;AAC/B,oFAAoF;AACpF,iFAAiF;AACjF,QAAmC;IAEnC,OAAO,sBAAsB,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"native-module.js","sourceRoot":"","sources":["../../src/core/native-module.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,+FAA+F;AAC/F,6EAA6E;AAC7E,gGAAgG;AAChG,4FAA4F;AAC5F,4EAA4E;AAC5E,OAAO,EAA0B,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGhF,MAAM,6BAA6B,GAAG,kBAAkB,CAAC;AAezD,MAAM,sBAAsB,GAAG,mBAAmB,CAChD,6BAA6B,CAC9B,CAAC;AAEF,MAAM,UAAU,iBAAiB;AAC/B,oFAAoF;AACpF,iFAAiF;AACjF,QAAmC;IAEnC,OAAO,sBAAsB,CAAC,WAAW,CACvC,yBAAyB,EACzB,QAAQ,CACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAmC;IAEnC,OAAO,sBAAsB,CAAC,WAAW,CACvC,2BAA2B,EAC3B,QAAQ,CACT,CAAC;AACJ,CAAC;AAED,eAAe,sBAAsB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/localization",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "expo-localization wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, and Angular adapters. Two independent synchronous getters (getLocales, getCalendars), each with its own native change listener and its own reactive hook per adapter.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "expo-localization wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Two independent synchronous getters (getLocales, getCalendars), each with its own native change listener and its own reactive hook per adapter.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"types": "./build/svelte/index.d.ts",
|
|
35
35
|
"default": "./build/svelte/index.js"
|
|
36
36
|
},
|
|
37
|
+
"./solid": {
|
|
38
|
+
"types": "./build/solid/index.d.ts",
|
|
39
|
+
"default": "./build/solid/index.js"
|
|
40
|
+
},
|
|
37
41
|
"./angular": {
|
|
38
42
|
"types": "./build-ngc/angular/index.d.ts",
|
|
39
43
|
"react-native": "./build-ngc/angular/index.js",
|
|
@@ -60,12 +64,14 @@
|
|
|
60
64
|
"@symbiote-native/angular": ">=0.6.2",
|
|
61
65
|
"@symbiote-native/engine": ">=0.1.7",
|
|
62
66
|
"@symbiote-native/react": ">=0.2.8",
|
|
67
|
+
"@symbiote-native/solid": ">=0.0.1",
|
|
63
68
|
"@symbiote-native/svelte": ">=0.1.0",
|
|
64
69
|
"@symbiote-native/vue": ">=0.3.8",
|
|
65
70
|
"@angular/core": ">=20",
|
|
66
71
|
"@vue/runtime-core": "^3.5.13",
|
|
67
72
|
"react": ">=19.0.0",
|
|
68
73
|
"react-native": ">=0.86",
|
|
74
|
+
"solid-js": ">=1.9.0",
|
|
69
75
|
"svelte": ">=5.56.0",
|
|
70
76
|
"vue": ">=3.5.0"
|
|
71
77
|
},
|
|
@@ -76,6 +82,9 @@
|
|
|
76
82
|
"@symbiote-native/react": {
|
|
77
83
|
"optional": true
|
|
78
84
|
},
|
|
85
|
+
"@symbiote-native/solid": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
79
88
|
"@symbiote-native/svelte": {
|
|
80
89
|
"optional": true
|
|
81
90
|
},
|
|
@@ -91,6 +100,9 @@
|
|
|
91
100
|
"react": {
|
|
92
101
|
"optional": true
|
|
93
102
|
},
|
|
103
|
+
"solid-js": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
94
106
|
"svelte": {
|
|
95
107
|
"optional": true
|
|
96
108
|
},
|
|
@@ -106,14 +118,16 @@
|
|
|
106
118
|
"@types/react": "^19.2.0",
|
|
107
119
|
"@vue/runtime-core": "^3.5.13",
|
|
108
120
|
"react": "19.2.3",
|
|
121
|
+
"solid-js": "^1.9.14",
|
|
109
122
|
"svelte": "^5.56.0",
|
|
110
123
|
"typescript": "~6.0.0",
|
|
111
|
-
"@symbiote-native/angular": "0.
|
|
112
|
-
"@symbiote-native/engine": "0.
|
|
113
|
-
"@symbiote-native/react": "0.
|
|
114
|
-
"@symbiote-native/
|
|
115
|
-
"@symbiote-native/
|
|
116
|
-
"@symbiote-native/
|
|
124
|
+
"@symbiote-native/angular": "0.8.0",
|
|
125
|
+
"@symbiote-native/engine": "0.3.0",
|
|
126
|
+
"@symbiote-native/react": "0.4.0",
|
|
127
|
+
"@symbiote-native/solid": "0.1.0",
|
|
128
|
+
"@symbiote-native/svelte": "0.3.0",
|
|
129
|
+
"@symbiote-native/test-utils": "0.2.0",
|
|
130
|
+
"@symbiote-native/vue": "0.5.0"
|
|
117
131
|
},
|
|
118
132
|
"scripts": {
|
|
119
133
|
"typecheck": "tsc --build",
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
effect,
|
|
3
|
+
inject,
|
|
4
|
+
Injectable,
|
|
5
|
+
Injector,
|
|
6
|
+
signal,
|
|
7
|
+
type Signal,
|
|
8
|
+
} from '@angular/core';
|
|
9
|
+
import {
|
|
10
|
+
addCalendarListener,
|
|
11
|
+
getCalendars,
|
|
12
|
+
type Calendar,
|
|
13
|
+
} from '../../../core';
|
|
3
14
|
|
|
4
15
|
// Angular twin of React's `useCalendars` hook and Vue's `useCalendars` composable — mirrors
|
|
5
16
|
// LocalesService's shape exactly.
|
|
@@ -15,7 +26,9 @@ export class CalendarsService {
|
|
|
15
26
|
|
|
16
27
|
effect(
|
|
17
28
|
onCleanup => {
|
|
18
|
-
const subscription = addCalendarListener(() =>
|
|
29
|
+
const subscription = addCalendarListener(() =>
|
|
30
|
+
calendars.set(getCalendars()),
|
|
31
|
+
);
|
|
19
32
|
onCleanup(() => subscription.remove());
|
|
20
33
|
},
|
|
21
34
|
{ injector: this.injector },
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
effect,
|
|
3
|
+
inject,
|
|
4
|
+
Injectable,
|
|
5
|
+
Injector,
|
|
6
|
+
signal,
|
|
7
|
+
type Signal,
|
|
8
|
+
} from '@angular/core';
|
|
2
9
|
import { addLocaleListener, getLocales, type Locale } from '../../../core';
|
|
3
10
|
|
|
4
11
|
// Angular twin of React's `useLocales` hook and Vue's `useLocales` composable. See
|
package/src/core/index.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export { getLocales, getCalendars } from './localization';
|
|
2
2
|
export { addLocaleListener, addCalendarListener } from './native-module';
|
|
3
|
-
export {
|
|
3
|
+
export {
|
|
4
|
+
Weekday,
|
|
5
|
+
CalendarIdentifier,
|
|
6
|
+
type Locale,
|
|
7
|
+
type Calendar,
|
|
8
|
+
} from './types';
|
|
4
9
|
export type { EventSubscription } from 'expo-modules-core';
|
package/src/core/localization.ts
CHANGED
|
@@ -42,4 +42,5 @@ export const getLocales: () => Locale[] = ExpoLocalizationModule.getLocales;
|
|
|
42
42
|
* }]
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
|
-
export const getCalendars: () => Calendar[] =
|
|
45
|
+
export const getCalendars: () => Calendar[] =
|
|
46
|
+
ExpoLocalizationModule.getCalendars;
|
|
@@ -31,11 +31,19 @@ export function addLocaleListener(
|
|
|
31
31
|
// invalidate signal for useLocales/the Vue composable/the Angular service below.
|
|
32
32
|
listener: (event?: unknown) => void,
|
|
33
33
|
): EventSubscription {
|
|
34
|
-
return ExpoLocalizationModule.addListener(
|
|
34
|
+
return ExpoLocalizationModule.addListener(
|
|
35
|
+
'onLocaleSettingsChanged',
|
|
36
|
+
listener,
|
|
37
|
+
);
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
export function addCalendarListener(
|
|
38
|
-
|
|
40
|
+
export function addCalendarListener(
|
|
41
|
+
listener: (event?: unknown) => void,
|
|
42
|
+
): EventSubscription {
|
|
43
|
+
return ExpoLocalizationModule.addListener(
|
|
44
|
+
'onCalendarSettingsChanged',
|
|
45
|
+
listener,
|
|
46
|
+
);
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
export default ExpoLocalizationModule;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
// React lifecycle wiring over the framework-agnostic core — mirrors use-locales' shape exactly.
|
|
2
2
|
// Ported from expo-localization's own useCalendars hook (sdk-57).
|
|
3
3
|
import { useEffect, useMemo, useReducer } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
addCalendarListener,
|
|
6
|
+
getCalendars,
|
|
7
|
+
type Calendar,
|
|
8
|
+
} from '../../../core';
|
|
5
9
|
|
|
6
10
|
export function useCalendars(): Calendar[] {
|
|
7
11
|
const [invalidationKey, invalidate] = useReducer((key: number) => key + 1, 0);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// @symbiote-native/localization/solid: the Solid entry over the framework-agnostic core. Locales
|
|
2
|
+
// and calendars each get their own primitive, matching upstream's own useLocales/useCalendars
|
|
3
|
+
// being two separate hooks, not one combined hook — mirrors the lifecycle-bucket naming of
|
|
4
|
+
// adapters/solid/src/primitives (never `hooks/`/`composables/`/`runes/`, and `create*` rather
|
|
5
|
+
// than `use*`, which Solid reserves for consuming something that already exists).
|
|
6
|
+
|
|
7
|
+
export { createLocales } from './primitives/create-locales';
|
|
8
|
+
export { createCalendars } from './primitives/create-calendars';
|
|
9
|
+
export * from '../core';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Solid lifecycle wiring over the framework-agnostic core (core/localization.ts) — mirrors
|
|
2
|
+
// create-locales' shape exactly, including why no seed-vs-event guard is needed here.
|
|
3
|
+
import { createSignal, onCleanup, type Accessor } from 'solid-js';
|
|
4
|
+
import {
|
|
5
|
+
addCalendarListener,
|
|
6
|
+
getCalendars,
|
|
7
|
+
type Calendar,
|
|
8
|
+
type EventSubscription,
|
|
9
|
+
} from '../../core';
|
|
10
|
+
|
|
11
|
+
export function createCalendars(): Accessor<Calendar[]> {
|
|
12
|
+
const [calendars, setCalendars] = createSignal<Calendar[]>(getCalendars());
|
|
13
|
+
|
|
14
|
+
const subscription: EventSubscription = addCalendarListener(() => {
|
|
15
|
+
setCalendars(getCalendars());
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
onCleanup(() => {
|
|
19
|
+
subscription.remove();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return calendars;
|
|
23
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Solid lifecycle wiring over the framework-agnostic core (core/localization.ts) — the twin of
|
|
2
|
+
// react/hooks/use-locales, vue/composables/use-locales and svelte/runes/use-locales.svelte. See
|
|
3
|
+
// adapters/solid/src/primitives/create-color-scheme.ts for why the bucket is `primitives/` and
|
|
4
|
+
// the name is `create*` rather than `use*`.
|
|
5
|
+
//
|
|
6
|
+
// Returns an ACCESSOR, never a snapshot: a Solid component body runs ONCE, so a returned array
|
|
7
|
+
// would pin the screen to the locale list the app booted with.
|
|
8
|
+
//
|
|
9
|
+
// getLocales() is a SYNCHRONOUS native read, so seed and subscribe both happen inline in the body
|
|
10
|
+
// and there is no seed-vs-event race to guard (unlike the battery primitives, whose seed is a
|
|
11
|
+
// promise) — and no re-read on mount either, which the Vue and Svelte twins need only because
|
|
12
|
+
// their subscription is deferred to an effect.
|
|
13
|
+
import { createSignal, onCleanup, type Accessor } from 'solid-js';
|
|
14
|
+
import {
|
|
15
|
+
addLocaleListener,
|
|
16
|
+
getLocales,
|
|
17
|
+
type EventSubscription,
|
|
18
|
+
type Locale,
|
|
19
|
+
} from '../../core';
|
|
20
|
+
|
|
21
|
+
export function createLocales(): Accessor<Locale[]> {
|
|
22
|
+
const [locales, setLocales] = createSignal<Locale[]>(getLocales());
|
|
23
|
+
|
|
24
|
+
const subscription: EventSubscription = addLocaleListener(() => {
|
|
25
|
+
setLocales(getLocales());
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
onCleanup(() => {
|
|
29
|
+
subscription.remove();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return locales;
|
|
33
|
+
}
|
|
@@ -7,7 +7,12 @@
|
|
|
7
7
|
// Returns a boxed getter, not a bare `$state`: Svelte 5 reactivity is lexically scoped to the
|
|
8
8
|
// declaring module and doesn't survive being returned raw from a plain function, so the caller
|
|
9
9
|
// reads `.current` like unwrapping Vue's `Ref` via `.value`.
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
addLocaleListener,
|
|
12
|
+
getLocales,
|
|
13
|
+
type EventSubscription,
|
|
14
|
+
type Locale,
|
|
15
|
+
} from '../../core';
|
|
11
16
|
|
|
12
17
|
export function useLocales(): { readonly current: Locale[] } {
|
|
13
18
|
let locales = $state<Locale[]>(getLocales());
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
// setup — onMounted only wires the change listener, mirroring use-network-state's
|
|
5
5
|
// onMounted/onUnmounted subscription shape otherwise.
|
|
6
6
|
import { onMounted, onUnmounted, ref, type Ref } from '@vue/runtime-core';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
addLocaleListener,
|
|
9
|
+
getLocales,
|
|
10
|
+
type EventSubscription,
|
|
11
|
+
type Locale,
|
|
12
|
+
} from '../../../core';
|
|
8
13
|
|
|
9
14
|
export function useLocales(): Ref<Locale[]> {
|
|
10
15
|
const locales = ref<Locale[]>(getLocales());
|