@sigx/lynx-zero 0.4.9 → 0.5.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/LICENSE +21 -21
- package/README.md +25 -25
- package/dist/styles/tokens.css +98 -98
- package/dist/theme/ThemeProvider.d.ts +25 -1
- package/dist/theme/ThemeProvider.d.ts.map +1 -1
- package/dist/theme/ThemeProvider.js +17 -0
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/package.json +13 -8
- package/src/components/SwiperIndicator.tsx +519 -519
- package/src/contract.ts +136 -136
- package/src/index.ts +101 -101
- package/src/layout/Center.tsx +41 -41
- package/src/layout/Col.tsx +53 -53
- package/src/layout/Row.tsx +53 -53
- package/src/layout/ScrollView.tsx +38 -38
- package/src/layout/Spacer.tsx +18 -18
- package/src/preset/index.ts +77 -77
- package/src/shared/press.ts +6 -6
- package/src/shared/styles.ts +82 -82
- package/src/shared/tabs-selection.ts +57 -57
- package/src/styles/tokens.css +98 -98
- package/src/theme/StatusBarSync.tsx +104 -104
- package/src/theme/ThemeProvider.tsx +532 -492
- package/src/theme/color-mix.ts +68 -68
- package/src/theme/registry.ts +290 -290
- package/src/theme/theme-state.ts +112 -112
- package/src/theme/use-screen-theme.ts +42 -42
- package/src/theme/use-theme-colors.ts +99 -99
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `<StatusBarSync />` — keeps the device status-bar (and Android's
|
|
3
|
-
* navigation-bar) tint legible against the active theme.
|
|
4
|
-
*
|
|
5
|
-
* Reads the current theme via `useTheme()`, looks up its variant in the
|
|
6
|
-
* theme registry, and pushes the appropriate tint to the OS via
|
|
7
|
-
* `@sigx/lynx-appearance`:
|
|
8
|
-
*
|
|
9
|
-
* light theme → dark status-bar icons (legible against light bg)
|
|
10
|
-
* dark theme → light status-bar icons (legible against dark bg)
|
|
11
|
-
*
|
|
12
|
-
* Mount once, inside `<ThemeProvider>`:
|
|
13
|
-
*
|
|
14
|
-
* ```tsx
|
|
15
|
-
* <ThemeProvider>
|
|
16
|
-
* <StatusBarSync />
|
|
17
|
-
* <App />
|
|
18
|
-
* </ThemeProvider>
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* Renders nothing — it's a side-effect-only component that drives a
|
|
22
|
-
* reactive `effect()` reading `theme.name`. The `matchBackground` prop is
|
|
23
|
-
* reserved for a follow-up that pushes the active theme's
|
|
24
|
-
* `--color-base-100` as the Android system-bar background; today it's a
|
|
25
|
-
* declared no-op so the API surface is stable across the rev that wires
|
|
26
|
-
* CSS-var resolution.
|
|
27
|
-
*/
|
|
28
|
-
import { component, effect, onMounted, onUnmounted, type Define } from '@sigx/lynx';
|
|
29
|
-
import { isAvailable, setSystemBarsStyle } from '@sigx/lynx-appearance';
|
|
30
|
-
import type { SystemBarStyle } from '@sigx/lynx-appearance';
|
|
31
|
-
import { themeController } from './theme-state.js';
|
|
32
|
-
import { variantOf } from './registry.js';
|
|
33
|
-
|
|
34
|
-
export type StatusBarSyncProps =
|
|
35
|
-
/**
|
|
36
|
-
* Reserved — will (in a follow-up) push the active theme's
|
|
37
|
-
* `--color-base-100` as the Android status- and navigation-bar
|
|
38
|
-
* background. Currently a no-op; the prop ships so consumers can opt
|
|
39
|
-
* in without an API break later. iOS and Android 15+ ignore the
|
|
40
|
-
* background regardless (no equivalent on iOS; edge-to-edge on
|
|
41
|
-
* Android 15+).
|
|
42
|
-
*/
|
|
43
|
-
& Define.Prop<'matchBackground', boolean, false>;
|
|
44
|
-
|
|
45
|
-
export const StatusBarSync = component<StatusBarSyncProps>(({ props }) => {
|
|
46
|
-
// Bind to the *global* theme — not `useTheme()` — so the OS bars always
|
|
47
|
-
// track the app/screen theme and can't be hijacked by a content sub-scope
|
|
48
|
-
// (a nested `<ThemeProvider>` recolors its subtree but leaves the bars put).
|
|
49
|
-
const theme = themeController;
|
|
50
|
-
let lastApplied: string | null = null;
|
|
51
|
-
let runner: { stop: () => void } | undefined;
|
|
52
|
-
|
|
53
|
-
function apply(name: string): void {
|
|
54
|
-
if (name === lastApplied) return;
|
|
55
|
-
lastApplied = name;
|
|
56
|
-
const variant = variantOf(name);
|
|
57
|
-
// For unregistered themes we can't infer a variant — leave the
|
|
58
|
-
// system bars alone. Consumers can register their custom theme via
|
|
59
|
-
// `registerTheme()` to opt in.
|
|
60
|
-
if (!variant) return;
|
|
61
|
-
const style: SystemBarStyle = variant === 'dark' ? 'light' : 'dark';
|
|
62
|
-
// Fire-and-forget: `setSystemBarsStyle` is non-throwing (it
|
|
63
|
-
// resolves `{ ok: false, reason: 'unsupported' }` when the native
|
|
64
|
-
// module isn't registered, and silently filters per-leg
|
|
65
|
-
// `unsupported` results — e.g. nav-bar on iOS — so an aggregate
|
|
66
|
-
// `ok: true` is still reachable on partial platforms). Either way,
|
|
67
|
-
// void-discarding the promise here can't surface as an unhandled
|
|
68
|
-
// rejection.
|
|
69
|
-
void setSystemBarsStyle({
|
|
70
|
-
statusBar: style,
|
|
71
|
-
navigationBar: { style },
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
onMounted(() => {
|
|
76
|
-
if (!isAvailable()) return;
|
|
77
|
-
// A reactive effect that reads `theme.name` so the effect re-runs
|
|
78
|
-
// whenever the theme controller's underlying signal changes —
|
|
79
|
-
// including the live system-flip path inside ThemeProvider. No
|
|
80
|
-
// side effects in render; nothing to subscribe/unsubscribe by
|
|
81
|
-
// hand.
|
|
82
|
-
runner = effect(() => {
|
|
83
|
-
apply(theme.name);
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
onUnmounted(() => {
|
|
88
|
-
runner?.stop();
|
|
89
|
-
runner = undefined;
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// Reference the prop so the type checker doesn't flag it as unused
|
|
93
|
-
// while it's still reserved. Drop this when the matchBackground
|
|
94
|
-
// implementation lands.
|
|
95
|
-
void props.matchBackground;
|
|
96
|
-
|
|
97
|
-
// Zero-size, out-of-flow placeholder. Avoids `display: none` —
|
|
98
|
-
// Lynx can leak unstyled text paint through display:none overlays in
|
|
99
|
-
// some builds (see lynx-display-none caveat); zero-size + absolute is
|
|
100
|
-
// the safer shape.
|
|
101
|
-
return () => (
|
|
102
|
-
<view style={{ position: 'absolute', width: '0px', height: '0px', opacity: 0 }} />
|
|
103
|
-
);
|
|
104
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* `<StatusBarSync />` — keeps the device status-bar (and Android's
|
|
3
|
+
* navigation-bar) tint legible against the active theme.
|
|
4
|
+
*
|
|
5
|
+
* Reads the current theme via `useTheme()`, looks up its variant in the
|
|
6
|
+
* theme registry, and pushes the appropriate tint to the OS via
|
|
7
|
+
* `@sigx/lynx-appearance`:
|
|
8
|
+
*
|
|
9
|
+
* light theme → dark status-bar icons (legible against light bg)
|
|
10
|
+
* dark theme → light status-bar icons (legible against dark bg)
|
|
11
|
+
*
|
|
12
|
+
* Mount once, inside `<ThemeProvider>`:
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <ThemeProvider>
|
|
16
|
+
* <StatusBarSync />
|
|
17
|
+
* <App />
|
|
18
|
+
* </ThemeProvider>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Renders nothing — it's a side-effect-only component that drives a
|
|
22
|
+
* reactive `effect()` reading `theme.name`. The `matchBackground` prop is
|
|
23
|
+
* reserved for a follow-up that pushes the active theme's
|
|
24
|
+
* `--color-base-100` as the Android system-bar background; today it's a
|
|
25
|
+
* declared no-op so the API surface is stable across the rev that wires
|
|
26
|
+
* CSS-var resolution.
|
|
27
|
+
*/
|
|
28
|
+
import { component, effect, onMounted, onUnmounted, type Define } from '@sigx/lynx';
|
|
29
|
+
import { isAvailable, setSystemBarsStyle } from '@sigx/lynx-appearance';
|
|
30
|
+
import type { SystemBarStyle } from '@sigx/lynx-appearance';
|
|
31
|
+
import { themeController } from './theme-state.js';
|
|
32
|
+
import { variantOf } from './registry.js';
|
|
33
|
+
|
|
34
|
+
export type StatusBarSyncProps =
|
|
35
|
+
/**
|
|
36
|
+
* Reserved — will (in a follow-up) push the active theme's
|
|
37
|
+
* `--color-base-100` as the Android status- and navigation-bar
|
|
38
|
+
* background. Currently a no-op; the prop ships so consumers can opt
|
|
39
|
+
* in without an API break later. iOS and Android 15+ ignore the
|
|
40
|
+
* background regardless (no equivalent on iOS; edge-to-edge on
|
|
41
|
+
* Android 15+).
|
|
42
|
+
*/
|
|
43
|
+
& Define.Prop<'matchBackground', boolean, false>;
|
|
44
|
+
|
|
45
|
+
export const StatusBarSync = component<StatusBarSyncProps>(({ props }) => {
|
|
46
|
+
// Bind to the *global* theme — not `useTheme()` — so the OS bars always
|
|
47
|
+
// track the app/screen theme and can't be hijacked by a content sub-scope
|
|
48
|
+
// (a nested `<ThemeProvider>` recolors its subtree but leaves the bars put).
|
|
49
|
+
const theme = themeController;
|
|
50
|
+
let lastApplied: string | null = null;
|
|
51
|
+
let runner: { stop: () => void } | undefined;
|
|
52
|
+
|
|
53
|
+
function apply(name: string): void {
|
|
54
|
+
if (name === lastApplied) return;
|
|
55
|
+
lastApplied = name;
|
|
56
|
+
const variant = variantOf(name);
|
|
57
|
+
// For unregistered themes we can't infer a variant — leave the
|
|
58
|
+
// system bars alone. Consumers can register their custom theme via
|
|
59
|
+
// `registerTheme()` to opt in.
|
|
60
|
+
if (!variant) return;
|
|
61
|
+
const style: SystemBarStyle = variant === 'dark' ? 'light' : 'dark';
|
|
62
|
+
// Fire-and-forget: `setSystemBarsStyle` is non-throwing (it
|
|
63
|
+
// resolves `{ ok: false, reason: 'unsupported' }` when the native
|
|
64
|
+
// module isn't registered, and silently filters per-leg
|
|
65
|
+
// `unsupported` results — e.g. nav-bar on iOS — so an aggregate
|
|
66
|
+
// `ok: true` is still reachable on partial platforms). Either way,
|
|
67
|
+
// void-discarding the promise here can't surface as an unhandled
|
|
68
|
+
// rejection.
|
|
69
|
+
void setSystemBarsStyle({
|
|
70
|
+
statusBar: style,
|
|
71
|
+
navigationBar: { style },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
onMounted(() => {
|
|
76
|
+
if (!isAvailable()) return;
|
|
77
|
+
// A reactive effect that reads `theme.name` so the effect re-runs
|
|
78
|
+
// whenever the theme controller's underlying signal changes —
|
|
79
|
+
// including the live system-flip path inside ThemeProvider. No
|
|
80
|
+
// side effects in render; nothing to subscribe/unsubscribe by
|
|
81
|
+
// hand.
|
|
82
|
+
runner = effect(() => {
|
|
83
|
+
apply(theme.name);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
onUnmounted(() => {
|
|
88
|
+
runner?.stop();
|
|
89
|
+
runner = undefined;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Reference the prop so the type checker doesn't flag it as unused
|
|
93
|
+
// while it's still reserved. Drop this when the matchBackground
|
|
94
|
+
// implementation lands.
|
|
95
|
+
void props.matchBackground;
|
|
96
|
+
|
|
97
|
+
// Zero-size, out-of-flow placeholder. Avoids `display: none` —
|
|
98
|
+
// Lynx can leak unstyled text paint through display:none overlays in
|
|
99
|
+
// some builds (see lynx-display-none caveat); zero-size + absolute is
|
|
100
|
+
// the safer shape.
|
|
101
|
+
return () => (
|
|
102
|
+
<view style={{ position: 'absolute', width: '0px', height: '0px', opacity: 0 }} />
|
|
103
|
+
);
|
|
104
|
+
});
|