@sigx/lynx-safe-area 0.4.3 → 0.4.4
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/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +51 -8
- package/dist/provider.js.map +1 -1
- package/package.json +6 -6
- package/src/provider.tsx +53 -8
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAWL,KAAK,MAAM,EAEX,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAKpB;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAwBjD,MAAM,MAAM,qBAAqB,GAC7B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,GACnC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,GAC5D,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,gBAAgB;;EAiI3B,CAAC;AAiDH,YAAY,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/provider.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
|
|
2
|
-
import { component, defineProvide, computed, signal, onMounted, onUnmounted, useSharedValue, useMainThreadRef, runOnMainThread, } from '@sigx/lynx';
|
|
2
|
+
import { component, effect, defineProvide, computed, signal, onMounted, onUnmounted, useSharedValue, useMainThreadRef, runOnMainThread, } from '@sigx/lynx';
|
|
3
3
|
import { useSafeAreaContext } from './injectable.js';
|
|
4
4
|
import { readGlobalSafeArea } from './globals.js';
|
|
5
5
|
/**
|
|
@@ -13,6 +13,9 @@ import { readGlobalSafeArea } from './globals.js';
|
|
|
13
13
|
* churned across Lynx releases).
|
|
14
14
|
*/
|
|
15
15
|
export const SAFE_AREA_EVENT = 'safeAreaChanged';
|
|
16
|
+
// Unique host id per provider instance so the runtime `setProperty` call can
|
|
17
|
+
// target this provider's own view.
|
|
18
|
+
let safeAreaIdSeq = 0;
|
|
16
19
|
/**
|
|
17
20
|
* Mount once at the root of an app. Responsibilities:
|
|
18
21
|
*
|
|
@@ -85,8 +88,12 @@ export const SafeAreaProvider = component(({ props, slots }) => {
|
|
|
85
88
|
// Hold the elRef purely so consumers can extend the provider's host view
|
|
86
89
|
// via the published CSS variables. Not used internally for any MT writes.
|
|
87
90
|
const elRef = useMainThreadRef(null);
|
|
91
|
+
// Host id for the runtime `setProperty` CSS-variable application (below).
|
|
92
|
+
const hostId = `safe-area-${++safeAreaIdSeq}`;
|
|
88
93
|
let listener;
|
|
89
94
|
let emitter;
|
|
95
|
+
let varsEffect;
|
|
96
|
+
let insetsGen = 0;
|
|
90
97
|
onMounted(() => {
|
|
91
98
|
// `lynx` is a closure-injected identifier (provided by
|
|
92
99
|
// `@lynx-js/runtime-wrapper-webpack-plugin`'s `__init_card_bundle__`
|
|
@@ -95,6 +102,39 @@ export const SafeAreaProvider = component(({ props, slots }) => {
|
|
|
95
102
|
const lynxObj = typeof lynx !== 'undefined'
|
|
96
103
|
? lynx
|
|
97
104
|
: undefined;
|
|
105
|
+
// Publish insets as real, inheritable CSS custom properties via the runtime
|
|
106
|
+
// `setProperty` API. Lynx does NOT honor custom properties declared through
|
|
107
|
+
// the inline `style` attribute, so `class="pt-[var(--sat)]"` consumers rely
|
|
108
|
+
// on this. On cold start the host view isn't queryable from the background
|
|
109
|
+
// thread the instant this runs, so retry on a short timer until it resolves
|
|
110
|
+
// (`insetsGen` drops a superseded retry). Reactive on `insets.value`.
|
|
111
|
+
const pushInsets = () => {
|
|
112
|
+
const i = insets.value;
|
|
113
|
+
if (!lynxObj?.getElementById)
|
|
114
|
+
return;
|
|
115
|
+
const vars = {
|
|
116
|
+
'--sat': `${i.top}px`,
|
|
117
|
+
'--sar': `${i.right}px`,
|
|
118
|
+
'--sab': `${i.bottom}px`,
|
|
119
|
+
'--sal': `${i.left}px`,
|
|
120
|
+
'--safe-area-keyboard': `${i.keyboard}px`,
|
|
121
|
+
};
|
|
122
|
+
const gen = ++insetsGen;
|
|
123
|
+
let tries = 0;
|
|
124
|
+
const attempt = () => {
|
|
125
|
+
if (gen !== insetsGen)
|
|
126
|
+
return;
|
|
127
|
+
const el = lynxObj.getElementById(hostId);
|
|
128
|
+
if (el) {
|
|
129
|
+
el.setProperty(vars);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (tries++ < 30)
|
|
133
|
+
setTimeout(attempt, 16);
|
|
134
|
+
};
|
|
135
|
+
attempt();
|
|
136
|
+
};
|
|
137
|
+
varsEffect = effect(() => { pushInsets(); });
|
|
98
138
|
emitter = lynxObj?.getJSModule?.('GlobalEventEmitter');
|
|
99
139
|
if (!emitter)
|
|
100
140
|
return;
|
|
@@ -112,8 +152,11 @@ export const SafeAreaProvider = component(({ props, slots }) => {
|
|
|
112
152
|
onUnmounted(() => {
|
|
113
153
|
if (emitter && listener)
|
|
114
154
|
emitter.removeListener(SAFE_AREA_EVENT, listener);
|
|
155
|
+
varsEffect?.stop();
|
|
156
|
+
varsEffect = undefined;
|
|
157
|
+
++insetsGen; // cancel any pending setProperty retry
|
|
115
158
|
});
|
|
116
|
-
return () => (_jsx("view", { class: props.class, "main-thread:ref": elRef, style:
|
|
159
|
+
return () => (_jsx("view", { id: hostId, class: props.class, "main-thread:ref": elRef, style: rootStyle(props.style), children: slots.default?.() }));
|
|
117
160
|
});
|
|
118
161
|
function normaliseInsets(raw, fallback) {
|
|
119
162
|
if (!raw || typeof raw !== 'object')
|
|
@@ -132,22 +175,22 @@ function normaliseInsets(raw, fallback) {
|
|
|
132
175
|
function numOr(v, fallback) {
|
|
133
176
|
return typeof v === 'number' && Number.isFinite(v) ? v : fallback;
|
|
134
177
|
}
|
|
135
|
-
function
|
|
178
|
+
function rootStyle(user) {
|
|
136
179
|
// Defaults make the provider fill the device viewport and act as a
|
|
137
180
|
// flex-column ancestor. Without these, every Lynx app re-rolls inline
|
|
138
181
|
// `style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}`
|
|
139
182
|
// because `<view>` defaults to auto height and the lynx-tailwind
|
|
140
183
|
// preset (as of 0.4.0) doesn't ship an `h-screen` rule. Consumers can
|
|
141
184
|
// override any of these via `props.style`.
|
|
185
|
+
//
|
|
186
|
+
// The safe-area CSS variables (`--sat`/`--sar`/`--sab`/`--sal`/
|
|
187
|
+
// `--safe-area-keyboard`) are NOT set here: Lynx ignores custom properties
|
|
188
|
+
// declared via inline `style`. They're published via the runtime
|
|
189
|
+
// `setProperty` API in the provider's mount effect instead.
|
|
142
190
|
const base = {
|
|
143
191
|
height: '100vh',
|
|
144
192
|
display: 'flex',
|
|
145
193
|
flexDirection: 'column',
|
|
146
|
-
'--sat': `${i.top}px`,
|
|
147
|
-
'--sar': `${i.right}px`,
|
|
148
|
-
'--sab': `${i.bottom}px`,
|
|
149
|
-
'--sal': `${i.left}px`,
|
|
150
|
-
'--safe-area-keyboard': `${i.keyboard}px`,
|
|
151
194
|
};
|
|
152
195
|
return user ? { ...base, ...user } : base;
|
|
153
196
|
}
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,SAAS,EACT,aAAa,EACb,QAAQ,EACR,MAAM,EACN,SAAS,EACT,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,eAAe,GAIhB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGlD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigx/lynx-safe-area",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Safe area insets (notch, home indicator, status bar, keyboard) for sigx-lynx",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@sigx/reactivity": "^0.4.8",
|
|
34
|
-
"@sigx/lynx": "^0.4.
|
|
35
|
-
"@sigx/lynx-runtime-internal": "^0.4.
|
|
34
|
+
"@sigx/lynx": "^0.4.4",
|
|
35
|
+
"@sigx/lynx-runtime-internal": "^0.4.4"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@typescript/native-preview": "7.0.0-dev.20260521.1",
|
|
39
39
|
"typescript": "^6.0.3",
|
|
40
|
-
"@sigx/lynx-runtime-main": "^0.4.
|
|
41
|
-
"@sigx/lynx-
|
|
42
|
-
"@sigx/lynx-
|
|
40
|
+
"@sigx/lynx-runtime-main": "^0.4.4",
|
|
41
|
+
"@sigx/lynx-testing": "^0.4.4",
|
|
42
|
+
"@sigx/lynx-plugin": "^0.4.4"
|
|
43
43
|
},
|
|
44
44
|
"repository": {
|
|
45
45
|
"type": "git",
|
package/src/provider.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
component,
|
|
3
|
+
effect,
|
|
3
4
|
defineProvide,
|
|
4
5
|
computed,
|
|
5
6
|
signal,
|
|
@@ -35,6 +36,9 @@ interface GlobalEventEmitterLike {
|
|
|
35
36
|
|
|
36
37
|
interface LynxLike {
|
|
37
38
|
getJSModule?: (name: string) => GlobalEventEmitterLike | undefined;
|
|
39
|
+
getElementById?: (
|
|
40
|
+
id: string,
|
|
41
|
+
) => { setProperty(props: Record<string, string>): void } | null;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
// Closure-injected identifier provided by
|
|
@@ -43,6 +47,10 @@ interface LynxLike {
|
|
|
43
47
|
// have to depend on lynx-runtime-internal just for the ambient.
|
|
44
48
|
declare const lynx: unknown | undefined;
|
|
45
49
|
|
|
50
|
+
// Unique host id per provider instance so the runtime `setProperty` call can
|
|
51
|
+
// target this provider's own view.
|
|
52
|
+
let safeAreaIdSeq = 0;
|
|
53
|
+
|
|
46
54
|
export type SafeAreaProviderProps =
|
|
47
55
|
& Define.Prop<'class', string, false>
|
|
48
56
|
& Define.Prop<'style', Record<string, string | number>, false>
|
|
@@ -127,8 +135,13 @@ export const SafeAreaProvider = component<SafeAreaProviderProps>(({ props, slots
|
|
|
127
135
|
// via the published CSS variables. Not used internally for any MT writes.
|
|
128
136
|
const elRef = useMainThreadRef<MainThread.Element | null>(null);
|
|
129
137
|
|
|
138
|
+
// Host id for the runtime `setProperty` CSS-variable application (below).
|
|
139
|
+
const hostId = `safe-area-${++safeAreaIdSeq}`;
|
|
140
|
+
|
|
130
141
|
let listener: ((...a: unknown[]) => void) | undefined;
|
|
131
142
|
let emitter: GlobalEventEmitterLike | undefined;
|
|
143
|
+
let varsEffect: { stop: () => void } | undefined;
|
|
144
|
+
let insetsGen = 0;
|
|
132
145
|
|
|
133
146
|
onMounted(() => {
|
|
134
147
|
// `lynx` is a closure-injected identifier (provided by
|
|
@@ -138,6 +151,35 @@ export const SafeAreaProvider = component<SafeAreaProviderProps>(({ props, slots
|
|
|
138
151
|
const lynxObj: LynxLike | undefined = typeof lynx !== 'undefined'
|
|
139
152
|
? (lynx as unknown as LynxLike)
|
|
140
153
|
: undefined;
|
|
154
|
+
|
|
155
|
+
// Publish insets as real, inheritable CSS custom properties via the runtime
|
|
156
|
+
// `setProperty` API. Lynx does NOT honor custom properties declared through
|
|
157
|
+
// the inline `style` attribute, so `class="pt-[var(--sat)]"` consumers rely
|
|
158
|
+
// on this. On cold start the host view isn't queryable from the background
|
|
159
|
+
// thread the instant this runs, so retry on a short timer until it resolves
|
|
160
|
+
// (`insetsGen` drops a superseded retry). Reactive on `insets.value`.
|
|
161
|
+
const pushInsets = (): void => {
|
|
162
|
+
const i = insets.value;
|
|
163
|
+
if (!lynxObj?.getElementById) return;
|
|
164
|
+
const vars: Record<string, string> = {
|
|
165
|
+
'--sat': `${i.top}px`,
|
|
166
|
+
'--sar': `${i.right}px`,
|
|
167
|
+
'--sab': `${i.bottom}px`,
|
|
168
|
+
'--sal': `${i.left}px`,
|
|
169
|
+
'--safe-area-keyboard': `${i.keyboard}px`,
|
|
170
|
+
};
|
|
171
|
+
const gen = ++insetsGen;
|
|
172
|
+
let tries = 0;
|
|
173
|
+
const attempt = (): void => {
|
|
174
|
+
if (gen !== insetsGen) return;
|
|
175
|
+
const el = lynxObj!.getElementById!(hostId);
|
|
176
|
+
if (el) { el.setProperty(vars); return; }
|
|
177
|
+
if (tries++ < 30) setTimeout(attempt, 16);
|
|
178
|
+
};
|
|
179
|
+
attempt();
|
|
180
|
+
};
|
|
181
|
+
varsEffect = effect(() => { pushInsets(); });
|
|
182
|
+
|
|
141
183
|
emitter = lynxObj?.getJSModule?.('GlobalEventEmitter');
|
|
142
184
|
if (!emitter) return;
|
|
143
185
|
listener = (raw: unknown) => {
|
|
@@ -154,13 +196,17 @@ export const SafeAreaProvider = component<SafeAreaProviderProps>(({ props, slots
|
|
|
154
196
|
|
|
155
197
|
onUnmounted(() => {
|
|
156
198
|
if (emitter && listener) emitter.removeListener(SAFE_AREA_EVENT, listener);
|
|
199
|
+
varsEffect?.stop();
|
|
200
|
+
varsEffect = undefined;
|
|
201
|
+
++insetsGen; // cancel any pending setProperty retry
|
|
157
202
|
});
|
|
158
203
|
|
|
159
204
|
return () => (
|
|
160
205
|
<view
|
|
206
|
+
id={hostId}
|
|
161
207
|
class={props.class}
|
|
162
208
|
main-thread:ref={elRef}
|
|
163
|
-
style={
|
|
209
|
+
style={rootStyle(props.style)}
|
|
164
210
|
>
|
|
165
211
|
{slots.default?.()}
|
|
166
212
|
</view>
|
|
@@ -191,8 +237,7 @@ function numOr(v: unknown, fallback: number): number {
|
|
|
191
237
|
return typeof v === 'number' && Number.isFinite(v) ? v : fallback;
|
|
192
238
|
}
|
|
193
239
|
|
|
194
|
-
function
|
|
195
|
-
i: EdgeInsets,
|
|
240
|
+
function rootStyle(
|
|
196
241
|
user: Record<string, string | number> | undefined,
|
|
197
242
|
): Record<string, string | number> {
|
|
198
243
|
// Defaults make the provider fill the device viewport and act as a
|
|
@@ -201,15 +246,15 @@ function cssVarStyle(
|
|
|
201
246
|
// because `<view>` defaults to auto height and the lynx-tailwind
|
|
202
247
|
// preset (as of 0.4.0) doesn't ship an `h-screen` rule. Consumers can
|
|
203
248
|
// override any of these via `props.style`.
|
|
249
|
+
//
|
|
250
|
+
// The safe-area CSS variables (`--sat`/`--sar`/`--sab`/`--sal`/
|
|
251
|
+
// `--safe-area-keyboard`) are NOT set here: Lynx ignores custom properties
|
|
252
|
+
// declared via inline `style`. They're published via the runtime
|
|
253
|
+
// `setProperty` API in the provider's mount effect instead.
|
|
204
254
|
const base: Record<string, string | number> = {
|
|
205
255
|
height: '100vh',
|
|
206
256
|
display: 'flex',
|
|
207
257
|
flexDirection: 'column',
|
|
208
|
-
'--sat': `${i.top}px`,
|
|
209
|
-
'--sar': `${i.right}px`,
|
|
210
|
-
'--sab': `${i.bottom}px`,
|
|
211
|
-
'--sal': `${i.left}px`,
|
|
212
|
-
'--safe-area-keyboard': `${i.keyboard}px`,
|
|
213
258
|
};
|
|
214
259
|
return user ? { ...base, ...user } : base;
|
|
215
260
|
}
|