@sigx/lynx-zero 0.4.9

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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/dist/components/SwiperIndicator.d.ts +43 -0
  4. package/dist/components/SwiperIndicator.d.ts.map +1 -0
  5. package/dist/components/SwiperIndicator.js +272 -0
  6. package/dist/components/SwiperIndicator.js.map +1 -0
  7. package/dist/contract.d.ts +95 -0
  8. package/dist/contract.d.ts.map +1 -0
  9. package/dist/contract.js +30 -0
  10. package/dist/contract.js.map +1 -0
  11. package/dist/index.d.ts +30 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +41 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/layout/Center.d.ts +7 -0
  16. package/dist/layout/Center.d.ts.map +1 -0
  17. package/dist/layout/Center.js +25 -0
  18. package/dist/layout/Center.js.map +1 -0
  19. package/dist/layout/Col.d.ts +8 -0
  20. package/dist/layout/Col.d.ts.map +1 -0
  21. package/dist/layout/Col.js +34 -0
  22. package/dist/layout/Col.js.map +1 -0
  23. package/dist/layout/Row.d.ts +8 -0
  24. package/dist/layout/Row.d.ts.map +1 -0
  25. package/dist/layout/Row.js +34 -0
  26. package/dist/layout/Row.js.map +1 -0
  27. package/dist/layout/ScrollView.d.ts +6 -0
  28. package/dist/layout/ScrollView.d.ts.map +1 -0
  29. package/dist/layout/ScrollView.js +19 -0
  30. package/dist/layout/ScrollView.js.map +1 -0
  31. package/dist/layout/Spacer.d.ts +4 -0
  32. package/dist/layout/Spacer.d.ts.map +1 -0
  33. package/dist/layout/Spacer.js +12 -0
  34. package/dist/layout/Spacer.js.map +1 -0
  35. package/dist/preset/index.d.ts +31 -0
  36. package/dist/preset/index.d.ts.map +1 -0
  37. package/dist/preset/index.js +72 -0
  38. package/dist/preset/index.js.map +1 -0
  39. package/dist/shared/press.d.ts +3 -0
  40. package/dist/shared/press.d.ts.map +1 -0
  41. package/dist/shared/press.js +7 -0
  42. package/dist/shared/press.js.map +1 -0
  43. package/dist/shared/styles.d.ts +27 -0
  44. package/dist/shared/styles.d.ts.map +1 -0
  45. package/dist/shared/styles.js +62 -0
  46. package/dist/shared/styles.js.map +1 -0
  47. package/dist/shared/tabs-selection.d.ts +25 -0
  48. package/dist/shared/tabs-selection.d.ts.map +1 -0
  49. package/dist/shared/tabs-selection.js +45 -0
  50. package/dist/shared/tabs-selection.js.map +1 -0
  51. package/dist/styles/tokens.css +98 -0
  52. package/dist/theme/StatusBarSync.d.ts +42 -0
  53. package/dist/theme/StatusBarSync.d.ts.map +1 -0
  54. package/dist/theme/StatusBarSync.js +89 -0
  55. package/dist/theme/StatusBarSync.js.map +1 -0
  56. package/dist/theme/ThemeProvider.d.ts +144 -0
  57. package/dist/theme/ThemeProvider.d.ts.map +1 -0
  58. package/dist/theme/ThemeProvider.js +328 -0
  59. package/dist/theme/ThemeProvider.js.map +1 -0
  60. package/dist/theme/color-mix.d.ts +21 -0
  61. package/dist/theme/color-mix.d.ts.map +1 -0
  62. package/dist/theme/color-mix.js +65 -0
  63. package/dist/theme/color-mix.js.map +1 -0
  64. package/dist/theme/registry.d.ts +182 -0
  65. package/dist/theme/registry.d.ts.map +1 -0
  66. package/dist/theme/registry.js +182 -0
  67. package/dist/theme/registry.js.map +1 -0
  68. package/dist/theme/theme-state.d.ts +43 -0
  69. package/dist/theme/theme-state.d.ts.map +1 -0
  70. package/dist/theme/theme-state.js +94 -0
  71. package/dist/theme/theme-state.js.map +1 -0
  72. package/dist/theme/use-screen-theme.d.ts +4 -0
  73. package/dist/theme/use-screen-theme.d.ts.map +1 -0
  74. package/dist/theme/use-screen-theme.js +43 -0
  75. package/dist/theme/use-screen-theme.js.map +1 -0
  76. package/dist/theme/use-theme-colors.d.ts +48 -0
  77. package/dist/theme/use-theme-colors.d.ts.map +1 -0
  78. package/dist/theme/use-theme-colors.js +69 -0
  79. package/dist/theme/use-theme-colors.js.map +1 -0
  80. package/package.json +80 -0
  81. package/src/components/SwiperIndicator.tsx +519 -0
  82. package/src/contract.ts +136 -0
  83. package/src/index.ts +101 -0
  84. package/src/layout/Center.tsx +41 -0
  85. package/src/layout/Col.tsx +53 -0
  86. package/src/layout/Row.tsx +53 -0
  87. package/src/layout/ScrollView.tsx +38 -0
  88. package/src/layout/Spacer.tsx +18 -0
  89. package/src/preset/index.ts +77 -0
  90. package/src/shared/press.ts +6 -0
  91. package/src/shared/styles.ts +82 -0
  92. package/src/shared/tabs-selection.ts +57 -0
  93. package/src/styles/tokens.css +98 -0
  94. package/src/theme/StatusBarSync.tsx +104 -0
  95. package/src/theme/ThemeProvider.tsx +492 -0
  96. package/src/theme/color-mix.ts +68 -0
  97. package/src/theme/registry.ts +290 -0
  98. package/src/theme/theme-state.ts +112 -0
  99. package/src/theme/use-screen-theme.ts +42 -0
  100. package/src/theme/use-theme-colors.ts +99 -0
@@ -0,0 +1,42 @@
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 { type Define } from '@sigx/lynx';
29
+ export type StatusBarSyncProps =
30
+ /**
31
+ * Reserved — will (in a follow-up) push the active theme's
32
+ * `--color-base-100` as the Android status- and navigation-bar
33
+ * background. Currently a no-op; the prop ships so consumers can opt
34
+ * in without an API break later. iOS and Android 15+ ignore the
35
+ * background regardless (no equivalent on iOS; edge-to-edge on
36
+ * Android 15+).
37
+ */
38
+ Define.Prop<'matchBackground', boolean, false>;
39
+ export declare const StatusBarSync: import("@sigx/runtime-core").ComponentFactory<{
40
+ matchBackground?: boolean | undefined;
41
+ }, void, {}>;
42
+ //# sourceMappingURL=StatusBarSync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBarSync.d.ts","sourceRoot":"","sources":["../../src/theme/StatusBarSync.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAA6C,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAMpF,MAAM,MAAM,kBAAkB;AAC1B;;;;;;;GAOG;AACD,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;AAErD,eAAO,MAAM,aAAa;;YA2DxB,CAAC"}
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ /**
3
+ * `<StatusBarSync />` — keeps the device status-bar (and Android's
4
+ * navigation-bar) tint legible against the active theme.
5
+ *
6
+ * Reads the current theme via `useTheme()`, looks up its variant in the
7
+ * theme registry, and pushes the appropriate tint to the OS via
8
+ * `@sigx/lynx-appearance`:
9
+ *
10
+ * light theme → dark status-bar icons (legible against light bg)
11
+ * dark theme → light status-bar icons (legible against dark bg)
12
+ *
13
+ * Mount once, inside `<ThemeProvider>`:
14
+ *
15
+ * ```tsx
16
+ * <ThemeProvider>
17
+ * <StatusBarSync />
18
+ * <App />
19
+ * </ThemeProvider>
20
+ * ```
21
+ *
22
+ * Renders nothing — it's a side-effect-only component that drives a
23
+ * reactive `effect()` reading `theme.name`. The `matchBackground` prop is
24
+ * reserved for a follow-up that pushes the active theme's
25
+ * `--color-base-100` as the Android system-bar background; today it's a
26
+ * declared no-op so the API surface is stable across the rev that wires
27
+ * CSS-var resolution.
28
+ */
29
+ import { component, effect, onMounted, onUnmounted } from '@sigx/lynx';
30
+ import { isAvailable, setSystemBarsStyle } from '@sigx/lynx-appearance';
31
+ import { themeController } from './theme-state.js';
32
+ import { variantOf } from './registry.js';
33
+ export const StatusBarSync = component(({ props }) => {
34
+ // Bind to the *global* theme — not `useTheme()` — so the OS bars always
35
+ // track the app/screen theme and can't be hijacked by a content sub-scope
36
+ // (a nested `<ThemeProvider>` recolors its subtree but leaves the bars put).
37
+ const theme = themeController;
38
+ let lastApplied = null;
39
+ let runner;
40
+ function apply(name) {
41
+ if (name === lastApplied)
42
+ return;
43
+ lastApplied = name;
44
+ const variant = variantOf(name);
45
+ // For unregistered themes we can't infer a variant — leave the
46
+ // system bars alone. Consumers can register their custom theme via
47
+ // `registerTheme()` to opt in.
48
+ if (!variant)
49
+ return;
50
+ const style = variant === 'dark' ? 'light' : 'dark';
51
+ // Fire-and-forget: `setSystemBarsStyle` is non-throwing (it
52
+ // resolves `{ ok: false, reason: 'unsupported' }` when the native
53
+ // module isn't registered, and silently filters per-leg
54
+ // `unsupported` results — e.g. nav-bar on iOS — so an aggregate
55
+ // `ok: true` is still reachable on partial platforms). Either way,
56
+ // void-discarding the promise here can't surface as an unhandled
57
+ // rejection.
58
+ void setSystemBarsStyle({
59
+ statusBar: style,
60
+ navigationBar: { style },
61
+ });
62
+ }
63
+ onMounted(() => {
64
+ if (!isAvailable())
65
+ return;
66
+ // A reactive effect that reads `theme.name` so the effect re-runs
67
+ // whenever the theme controller's underlying signal changes —
68
+ // including the live system-flip path inside ThemeProvider. No
69
+ // side effects in render; nothing to subscribe/unsubscribe by
70
+ // hand.
71
+ runner = effect(() => {
72
+ apply(theme.name);
73
+ });
74
+ });
75
+ onUnmounted(() => {
76
+ runner?.stop();
77
+ runner = undefined;
78
+ });
79
+ // Reference the prop so the type checker doesn't flag it as unused
80
+ // while it's still reserved. Drop this when the matchBackground
81
+ // implementation lands.
82
+ void props.matchBackground;
83
+ // Zero-size, out-of-flow placeholder. Avoids `display: none` —
84
+ // Lynx can leak unstyled text paint through display:none overlays in
85
+ // some builds (see lynx-display-none caveat); zero-size + absolute is
86
+ // the safer shape.
87
+ return () => (_jsx("view", { style: { position: 'absolute', width: '0px', height: '0px', opacity: 0 } }));
88
+ });
89
+ //# sourceMappingURL=StatusBarSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBarSync.js","sourceRoot":"","sources":["../../src/theme/StatusBarSync.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAe,MAAM,YAAY,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAa1C,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAqB,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACrE,wEAAwE;IACxE,0EAA0E;IAC1E,6EAA6E;IAC7E,MAAM,KAAK,GAAG,eAAe,CAAC;IAC9B,IAAI,WAAW,GAAkB,IAAI,CAAC;IACtC,IAAI,MAAwC,CAAC;IAE7C,SAAS,KAAK,CAAC,IAAY;QACvB,IAAI,IAAI,KAAK,WAAW;YAAE,OAAO;QACjC,WAAW,GAAG,IAAI,CAAC;QACnB,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,+DAA+D;QAC/D,mEAAmE;QACnE,+BAA+B;QAC/B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,KAAK,GAAmB,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QACpE,4DAA4D;QAC5D,kEAAkE;QAClE,wDAAwD;QACxD,gEAAgE;QAChE,mEAAmE;QACnE,iEAAiE;QACjE,aAAa;QACb,KAAK,kBAAkB,CAAC;YACpB,SAAS,EAAE,KAAK;YAChB,aAAa,EAAE,EAAE,KAAK,EAAE;SAC3B,CAAC,CAAC;IACP,CAAC;IAED,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,CAAC,WAAW,EAAE;YAAE,OAAO;QAC3B,kEAAkE;QAClE,8DAA8D;QAC9D,+DAA+D;QAC/D,8DAA8D;QAC9D,QAAQ;QACR,MAAM,GAAG,MAAM,CAAC,GAAG,EAAE;YACjB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,WAAW,CAAC,GAAG,EAAE;QACb,MAAM,EAAE,IAAI,EAAE,CAAC;QACf,MAAM,GAAG,SAAS,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,mEAAmE;IACnE,gEAAgE;IAChE,wBAAwB;IACxB,KAAK,KAAK,CAAC,eAAe,CAAC;IAE3B,+DAA+D;IAC/D,qEAAqE;IACrE,sEAAsE;IACtE,mBAAmB;IACnB,OAAO,GAAG,EAAE,CAAC,CACT,eAAM,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,GAAI,CACrF,CAAC;AACN,CAAC,CAAC,CAAC"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * `<ThemeProvider>` and `useTheme()` — the design-system-neutral theme engine.
3
+ *
4
+ * Themes are CSS classes containing scoped `--color-*` / `--radius-*`
5
+ * variable definitions; descendants of an element with the class inherit
6
+ * those variables (Lynx has `enableCSSInheritance: true` in its
7
+ * layout-pipeline defaults), and design-system components are built to read
8
+ * those vars directly.
9
+ *
10
+ * Theme *data* comes from the design-system package: it seeds the registry at
11
+ * module load (`registerTheme()` in `./registry.ts`) and ships a generated CSS
12
+ * class per static theme so the first frame paints correctly. Custom themes —
13
+ * including tenant themes fetched at runtime — register the same way so
14
+ * `followSystem` and `toggle()` know what to pick.
15
+ *
16
+ * Usage (here with `@sigx/lynx-daisyui`'s themes):
17
+ *
18
+ * ```tsx
19
+ * import { ThemeProvider, useTheme } from '@sigx/lynx-daisyui';
20
+ *
21
+ * // System-aware (default): picks the first registered light/dark theme from
22
+ * // the OS scheme, live-flips when the user toggles dark mode.
23
+ * defineApp(() => () => (
24
+ * <ThemeProvider>
25
+ * <App />
26
+ * </ThemeProvider>
27
+ * ));
28
+ *
29
+ * // Pin a specific theme — ignores system appearance.
30
+ * <ThemeProvider initial="daisy-light">…</ThemeProvider>
31
+ *
32
+ * // Custom light/dark pair under followSystem.
33
+ * <ThemeProvider light="daisy-cupcake" dark="daisy-synthwave">…</ThemeProvider>
34
+ * ```
35
+ */
36
+ import { type Define } from '@sigx/lynx';
37
+ /**
38
+ * Theme class applied to the provider's host view. Plain string — a design
39
+ * system layers a literal union on top for autocomplete (e.g. daisyui's
40
+ * `DaisyTheme`). Multi-class compositions like `'daisy-light daisy-rounded'`
41
+ * are accepted.
42
+ */
43
+ export type ThemeName = string & {};
44
+ export interface ThemeController {
45
+ /** Current theme class. Reactive — read inside render/effect to track. */
46
+ readonly name: ThemeName;
47
+ /**
48
+ * Whether the theme is currently being driven by the system color
49
+ * scheme (true when no `initial` was passed and `set()` hasn't been
50
+ * called since mount). UI like a settings screen can read this to show
51
+ * a "Follow system" indicator.
52
+ */
53
+ readonly followingSystem: boolean;
54
+ /**
55
+ * Replace the active theme. Pins the choice — subsequent system
56
+ * appearance changes won't override it (until `followSystem()` is called).
57
+ */
58
+ set(name: ThemeName): void;
59
+ /**
60
+ * Flip to the paired theme — light ↔ dark by default; follows the `pair`
61
+ * declared in `registerTheme()`, or the first theme of the opposite
62
+ * variant.
63
+ */
64
+ toggle(): void;
65
+ /**
66
+ * Resume following system appearance. Equivalent to mounting fresh
67
+ * with no `initial` prop. Useful for a "Reset to system" button.
68
+ */
69
+ followSystem(): void;
70
+ /**
71
+ * Current global text-scale multiplier (`1` = the theme's default ramp).
72
+ * Reactive — read inside render/effect to track. Orthogonal to the theme:
73
+ * `set()` / `toggle()` leave it untouched.
74
+ */
75
+ readonly fontScale: number;
76
+ /**
77
+ * Set the global text-scale multiplier — the `--text-*` ramp is re-emitted
78
+ * at `defaultPx × scale`. Persists across theme switches, so it's the place
79
+ * to wire a user accessibility preference or a backend-driven setting (e.g.
80
+ * `setFontScale(1.25)`). Inherits into nested `<ThemeProvider>` subtrees.
81
+ */
82
+ setFontScale(scale: number): void;
83
+ }
84
+ /**
85
+ * Access the active theme controller. Resolves to the nearest
86
+ * `<ThemeProvider>`'s controller (a content sub-scope), or — at the app root
87
+ * and in *headless* code with no provider mounted — the global controller
88
+ * (`themeController`). Never throws: theme control is reachable from anywhere.
89
+ * For control that must always target the app/OS theme regardless of scope
90
+ * (e.g. a status-bar sync), import `themeController`.
91
+ */
92
+ export declare const useTheme: import("@sigx/runtime-core").InjectableFunction<ThemeController>;
93
+ export type ThemeProviderProps =
94
+ /**
95
+ * Pin the initial theme. When set, the provider ignores system
96
+ * appearance until `controller.followSystem()` is called. When
97
+ * omitted, the provider follows the OS color scheme and live-flips
98
+ * with it.
99
+ */
100
+ Define.Prop<'initial', ThemeName, false>
101
+ /**
102
+ * Theme to use when the system color scheme is `'light'`. Defaults to
103
+ * the first registered light theme. Only consulted while
104
+ * `followingSystem` is true.
105
+ */
106
+ & Define.Prop<'light', ThemeName, false>
107
+ /**
108
+ * Theme to use when the system color scheme is `'dark'`. Defaults to
109
+ * the first registered dark theme. Only consulted while
110
+ * `followingSystem` is true.
111
+ */
112
+ & Define.Prop<'dark', ThemeName, false>
113
+ /**
114
+ * Initial global text-scale multiplier (`1` = default ramp). Seeds the
115
+ * controller's `fontScale`; change it later via `controller.setFontScale()`.
116
+ * On the root provider an explicit value wins over any scale a headless
117
+ * caller set before mount.
118
+ */
119
+ & Define.Prop<'fontScale', number, false>
120
+ /** Extra classes appended to the theme class on the host view. */
121
+ & Define.Prop<'class', string, false>
122
+ /** Extra inline style on the host view. Merged after the base flex-fill defaults. */
123
+ & Define.Prop<'style', Record<string, string | number>, false> & Define.Slot<'default'>;
124
+ /**
125
+ * Wraps children in a `<view class={theme}>` so the CSS variables defined
126
+ * inside the theme class inherit down to every descendant.
127
+ *
128
+ * Layout: the root provider defaults to flex-fill long-form so the wrapper
129
+ * doesn't collapse between ancestors that flex (e.g. `<SafeAreaProvider>`)
130
+ * and descendants that need a sized parent (`<SafeAreaView>`). A nested
131
+ * provider is a content island and sizes to its content instead — flex-fill's
132
+ * `flexBasis: 0` computes to height 0 inside scroll-view content, where
133
+ * nothing grows it back (#269). Consumers override via `style`.
134
+ *
135
+ * Theme name is held in an *object* signal (not a primitive) so literal-union
136
+ * types a DS layers on survive — `signal<T>` widens primitive literals to
137
+ * plain `string` via `Widen<T>`.
138
+ */
139
+ export declare const ThemeProvider: import("@sigx/runtime-core").ComponentFactory<ThemeProviderProps, void, {
140
+ default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
141
+ }>;
142
+ export { listThemes, registerTheme, extendTheme, pickThemeFor, pairOf, variantOf, colorsOf, radiusOf, sizesOf, } from './registry.js';
143
+ export type { Theme, ThemePalette, ThemeRadius, ThemeSizes, ThemeVariant, } from './registry.js';
144
+ //# sourceMappingURL=ThemeProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../src/theme/ThemeProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EASH,KAAK,MAAM,EACd,MAAM,YAAY,CAAC;AA8HpB;;;;;GAKG;AAEH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC;AAEpC,MAAM,WAAW,eAAe;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC;;;OAGG;IACH,GAAG,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,MAAM,IAAI,IAAI,CAAC;IACf;;;OAGG;IACH,YAAY,IAAI,IAAI,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,kEAA2D,CAAC;AAmBjF,MAAM,MAAM,kBAAkB;AAC1B;;;;;GAKG;AACD,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC;AAC1C;;;;GAIG;GACD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC;AACxC;;;;GAIG;GACD,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC;AACvC;;;;;GAKG;GACD,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC;AACzC,kEAAkE;GAChE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC;AACrC,qFAAqF;GACnF,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;AAE7B;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa;;EA+KxB,CAAC;AAGH,OAAO,EACH,UAAU,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,MAAM,EACN,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,OAAO,GACV,MAAM,eAAe,CAAC;AACvB,YAAY,EACR,KAAK,EACL,YAAY,EACZ,WAAW,EACX,UAAU,EACV,YAAY,GACf,MAAM,eAAe,CAAC"}
@@ -0,0 +1,328 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ /**
3
+ * `<ThemeProvider>` and `useTheme()` — the design-system-neutral theme engine.
4
+ *
5
+ * Themes are CSS classes containing scoped `--color-*` / `--radius-*`
6
+ * variable definitions; descendants of an element with the class inherit
7
+ * those variables (Lynx has `enableCSSInheritance: true` in its
8
+ * layout-pipeline defaults), and design-system components are built to read
9
+ * those vars directly.
10
+ *
11
+ * Theme *data* comes from the design-system package: it seeds the registry at
12
+ * module load (`registerTheme()` in `./registry.ts`) and ships a generated CSS
13
+ * class per static theme so the first frame paints correctly. Custom themes —
14
+ * including tenant themes fetched at runtime — register the same way so
15
+ * `followSystem` and `toggle()` know what to pick.
16
+ *
17
+ * Usage (here with `@sigx/lynx-daisyui`'s themes):
18
+ *
19
+ * ```tsx
20
+ * import { ThemeProvider, useTheme } from '@sigx/lynx-daisyui';
21
+ *
22
+ * // System-aware (default): picks the first registered light/dark theme from
23
+ * // the OS scheme, live-flips when the user toggles dark mode.
24
+ * defineApp(() => () => (
25
+ * <ThemeProvider>
26
+ * <App />
27
+ * </ThemeProvider>
28
+ * ));
29
+ *
30
+ * // Pin a specific theme — ignores system appearance.
31
+ * <ThemeProvider initial="daisy-light">…</ThemeProvider>
32
+ *
33
+ * // Custom light/dark pair under followSystem.
34
+ * <ThemeProvider light="daisy-cupcake" dark="daisy-synthwave">…</ThemeProvider>
35
+ * ```
36
+ */
37
+ import { component, defineInjectable, defineProvide, effect, onMounted, onUnmounted, signal, untrack, } from '@sigx/lynx';
38
+ import { useSystemColorScheme } from '@sigx/lynx-appearance';
39
+ import { colorsOf, fallbackPalette, hasStaticCss, pickThemeFor, radiusOf, sizesOf, variantOf, } from './registry.js';
40
+ import { globalThemeState, makeThemeController, normalizeFontScale, themeController, } from './theme-state.js';
41
+ // Control dimensions are expressed as multiples of two base units
42
+ // (`--size-field`, `--size-selector`). Lynx's runtime CSS engine is unproven
43
+ // for `calc(var() * n)`, so when a theme overrides a base unit we do the
44
+ // multiplication here and emit literal px. Bases must be px (engine-safe, like
45
+ // colors); a non-px base sets only the base var and leaves the `.lynx-zero`
46
+ // defaults in place. Multiples mirror the defaults in `styles/tokens.css`.
47
+ const FIELD_STEPS = { xs: 6, sm: 8, md: 12, lg: 16 };
48
+ const SELECTOR_STEPS = {
49
+ 'checkbox-xs': 4, 'checkbox-sm': 5, 'checkbox-md': 6, 'checkbox-lg': 8,
50
+ 'toggle-width-xs': 8, 'toggle-width-sm': 10, 'toggle-width-md': 12, 'toggle-width-lg': 14,
51
+ 'toggle-height-xs': 6, 'toggle-height-sm': 6, 'toggle-height-md': 7, 'toggle-height-lg': 8,
52
+ 'toggle-thumb-xs': 4, 'toggle-thumb-sm': 4, 'toggle-thumb-md': 5, 'toggle-thumb-lg': 6,
53
+ 'badge-xs': 4, 'badge-sm': 5, 'badge-md': 6, 'badge-lg': 8,
54
+ };
55
+ // Default text ramp (px) — MUST mirror `--text-*` in `styles/tokens.css`
56
+ // (iOS-aligned, 17px base). The global `fontScale` multiplies these and emits
57
+ // literal px (no `calc(var() * n)` — unproven in Lynx).
58
+ const FONT_DEFAULTS = {
59
+ 'xs': 12, 'sm': 14, 'base': 17, 'lg': 20, 'xl': 24, '2xl': 28, '3xl': 34,
60
+ };
61
+ const pxValue = (v) => {
62
+ const m = /^\s*(\d+(?:\.\d+)?)px\s*$/.exec(v);
63
+ return m ? Number(m[1]) : undefined;
64
+ };
65
+ /** Emit a theme's `sizes` overrides as literal-px CSS custom properties. */
66
+ function applySizeVars(style, sizes) {
67
+ if (sizes.field) {
68
+ style['--size-field'] = sizes.field;
69
+ const base = pxValue(sizes.field);
70
+ if (base !== undefined) {
71
+ for (const k in FIELD_STEPS)
72
+ style[`--size-${k}`] = `${base * FIELD_STEPS[k]}px`;
73
+ }
74
+ }
75
+ if (sizes.selector) {
76
+ style['--size-selector'] = sizes.selector;
77
+ const base = pxValue(sizes.selector);
78
+ if (base !== undefined) {
79
+ for (const k in SELECTOR_STEPS)
80
+ style[`--${k}`] = `${base * SELECTOR_STEPS[k]}px`;
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Emit the text ramp scaled by `fontScale` as `--text-*` literal px. Always
86
+ * emits every step — even at `1` (the literal defaults) — because Lynx's
87
+ * `setProperty` only merges and never clears: skipping at `1` would leave a
88
+ * previously-emitted larger ramp stuck after a reset. A nested provider seeds
89
+ * its scale from the inherited ambient value, so emitting here re-states the
90
+ * same ramp rather than clobbering the root's scaled one.
91
+ */
92
+ function applyFontScale(style, fontScale) {
93
+ for (const k in FONT_DEFAULTS) {
94
+ style[`--text-${k}`] = `${Math.round(FONT_DEFAULTS[k] * fontScale)}px`;
95
+ }
96
+ }
97
+ /**
98
+ * The full custom-property set for a theme — colors, any radius/size overrides,
99
+ * and the `fontScale`-adjusted text ramp. Applied at runtime via the Lynx
100
+ * `setProperty` API (see
101
+ * `<ThemeProvider>`), NOT the inline `style` attribute: Lynx does not honor
102
+ * custom properties declared inline in this toolchain, but `setProperty`
103
+ * registers real, inheritable ones — the documented way to theme via CSS
104
+ * variables (https://lynxjs.org/guide/styling/custom-theming).
105
+ */
106
+ function buildThemeVars(name, fontScale) {
107
+ const palette = colorsOf(name) ?? fallbackPalette();
108
+ const radius = radiusOf(name);
109
+ const sizes = sizesOf(name);
110
+ const vars = {};
111
+ if (palette) {
112
+ for (const key in palette)
113
+ vars[`--color-${key}`] = palette[key];
114
+ }
115
+ if (radius) {
116
+ if (radius.selector)
117
+ vars['--radius-selector'] = radius.selector;
118
+ if (radius.field)
119
+ vars['--radius-field'] = radius.field;
120
+ if (radius.box)
121
+ vars['--radius-box'] = radius.box;
122
+ }
123
+ if (sizes)
124
+ applySizeVars(vars, sizes);
125
+ applyFontScale(vars, fontScale);
126
+ return vars;
127
+ }
128
+ /** Unique host id per provider instance so `getElementById` targets its own subtree. */
129
+ let themeIdSeq = 0;
130
+ /**
131
+ * Access the active theme controller. Resolves to the nearest
132
+ * `<ThemeProvider>`'s controller (a content sub-scope), or — at the app root
133
+ * and in *headless* code with no provider mounted — the global controller
134
+ * (`themeController`). Never throws: theme control is reachable from anywhere.
135
+ * For control that must always target the app/OS theme regardless of scope
136
+ * (e.g. a status-bar sync), import `themeController`.
137
+ */
138
+ export const useTheme = defineInjectable(() => themeController);
139
+ /**
140
+ * Nesting-depth marker. The outermost `<ThemeProvider>` sees depth 0 and binds
141
+ * the global singleton (so headless `themeController` mutations render and the
142
+ * OS bars track it); a nested provider sees >= 1 and creates its own local
143
+ * state — a content sub-scope that recolors its subtree without touching the
144
+ * global theme or the system bars.
145
+ */
146
+ const useThemeDepth = defineInjectable(() => 0);
147
+ /**
148
+ * Ambient text scale inherited by nested providers. A nested `<ThemeProvider>`
149
+ * with no explicit `fontScale` prop seeds from this (the enclosing scale,
150
+ * default 1) instead of resetting to 1 — so the root's scale flows down through
151
+ * color sub-scopes. Each provider re-provides its own current scale.
152
+ */
153
+ const useAmbientFontScale = defineInjectable(() => 1);
154
+ /**
155
+ * Wraps children in a `<view class={theme}>` so the CSS variables defined
156
+ * inside the theme class inherit down to every descendant.
157
+ *
158
+ * Layout: the root provider defaults to flex-fill long-form so the wrapper
159
+ * doesn't collapse between ancestors that flex (e.g. `<SafeAreaProvider>`)
160
+ * and descendants that need a sized parent (`<SafeAreaView>`). A nested
161
+ * provider is a content island and sizes to its content instead — flex-fill's
162
+ * `flexBasis: 0` computes to height 0 inside scroll-view content, where
163
+ * nothing grows it back (#269). Consumers override via `style`.
164
+ *
165
+ * Theme name is held in an *object* signal (not a primitive) so literal-union
166
+ * types a DS layers on survive — `signal<T>` widens primitive literals to
167
+ * plain `string` via `Widen<T>`.
168
+ */
169
+ export const ThemeProvider = component(({ props, slots }) => {
170
+ const systemScheme = useSystemColorScheme();
171
+ // The underlying signal widens to PrimitiveSignal<string> via Widen<T>;
172
+ // cast at read sites to keep the narrow union throughout the component.
173
+ const readScheme = () => systemScheme.value;
174
+ // Root vs. nested. The outermost provider (depth 0) binds the global
175
+ // singleton — so headless `themeController` mutations render here and the OS
176
+ // bars (via StatusBarSync) follow this theme. A nested provider gets its own
177
+ // local state: a content sub-scope that overrides its subtree only.
178
+ const depth = useThemeDepth();
179
+ const isRoot = depth === 0;
180
+ defineProvide(useThemeDepth, () => depth + 1);
181
+ // Stable id for the host view so the runtime `setProperty` call (below) can
182
+ // target it. Unique per instance so nested providers theme their own subtree.
183
+ const hostId = `zero-theme-${++themeIdSeq}`;
184
+ // A nested provider with no explicit `fontScale` inherits the enclosing
185
+ // scale (default 1 at the root), so the root's scale flows down through
186
+ // color sub-scopes rather than resetting. An explicit prop overrides it.
187
+ const ambientFontScale = useAmbientFontScale();
188
+ const seedScale = normalizeFontScale(props.fontScale, ambientFontScale);
189
+ const state = isRoot
190
+ ? globalThemeState
191
+ : signal(props.initial
192
+ ? { name: props.initial, following: false, fontScale: seedScale }
193
+ : {
194
+ name: readScheme() === 'dark'
195
+ ? (props.dark ?? pickThemeFor('dark'))
196
+ : (props.light ?? pickThemeFor('light')),
197
+ following: true,
198
+ fontScale: seedScale,
199
+ });
200
+ // Seed the root from props/system. An explicit `initial` pin is author
201
+ // intent and wins. With no `initial`, reflect the current system scheme into
202
+ // the first render — but only while `following`, so a theme a headless
203
+ // caller set before this mounted is respected, not clobbered. The follow
204
+ // effect below keeps it in sync afterwards.
205
+ if (isRoot) {
206
+ if (props.initial) {
207
+ state.name = props.initial;
208
+ state.following = false;
209
+ }
210
+ else if (state.following) {
211
+ state.name = readScheme() === 'dark'
212
+ ? (props.dark ?? pickThemeFor('dark'))
213
+ : (props.light ?? pickThemeFor('light'));
214
+ }
215
+ // Explicit author intent wins; otherwise keep whatever scale a headless
216
+ // caller may have set before this mounted (default 1).
217
+ if (props.fontScale !== undefined) {
218
+ state.fontScale = normalizeFontScale(props.fontScale, state.fontScale);
219
+ }
220
+ }
221
+ const controller = isRoot
222
+ ? themeController
223
+ : makeThemeController(state);
224
+ defineProvide(useTheme, () => controller);
225
+ // Re-provide this scope's current scale so nested providers inherit it.
226
+ defineProvide(useAmbientFontScale, () => state.fontScale);
227
+ // Follow the system color scheme while `following`. Reactive: re-runs when
228
+ // `following` flips true (e.g. `controller.followSystem()`, including the
229
+ // headless `themeController`) or when the OS scheme changes, and writes the
230
+ // matching theme. Reading `state.following` and `systemScheme.value` tracks
231
+ // them; the `name` write is `untrack`ed so it can't re-trigger the effect.
232
+ // Created on mount (the native publisher may populate the scheme between
233
+ // setup and mount) and torn down on unmount.
234
+ let follow;
235
+ let applyVars;
236
+ onMounted(() => {
237
+ follow = effect(() => {
238
+ const following = state.following;
239
+ const scheme = readScheme();
240
+ if (!following)
241
+ return;
242
+ const next = scheme === 'dark'
243
+ ? (props.dark ?? pickThemeFor('dark'))
244
+ : (props.light ?? pickThemeFor('light'));
245
+ untrack(() => {
246
+ if (state.name !== next)
247
+ state.name = next;
248
+ });
249
+ });
250
+ // Static themes are themed by their generated CSS class (applied on
251
+ // the host below), which resolves on the very first frame. This
252
+ // `setProperty` path additionally serves runtime-registered themes
253
+ // (`registerTheme`, no shipped CSS class) — applied once they're
254
+ // selected post-mount, where it lands reliably. Reading `state.name`
255
+ // and `state.fontScale` (via buildThemeVars) tracks them, so this
256
+ // re-runs on every theme change and every `setFontScale`.
257
+ applyVars = effect(() => {
258
+ const vars = buildThemeVars(state.name, state.fontScale);
259
+ if (typeof lynx !== 'undefined') {
260
+ // `setProperty` isn't implemented for every element on every
261
+ // host — notably web (`@lynx-js/web-core`), where it throws on
262
+ // the background thread and aborts the whole card render.
263
+ // Degrade gracefully: apply runtime-registered theme vars where
264
+ // supported; static themes still resolve via their generated
265
+ // CSS class (applied on the host element).
266
+ const el = lynx.getElementById(hostId);
267
+ if (el && typeof el.setProperty === 'function') {
268
+ try {
269
+ el.setProperty(vars);
270
+ }
271
+ catch {
272
+ /* host rejected runtime setProperty (e.g. web) */
273
+ }
274
+ }
275
+ }
276
+ });
277
+ });
278
+ onUnmounted(() => {
279
+ follow?.stop();
280
+ follow = undefined;
281
+ applyVars?.stop();
282
+ applyVars = undefined;
283
+ });
284
+ return () => {
285
+ // Theme COLORS and any radius/size overrides are applied as real,
286
+ // inheritable CSS custom properties via the Lynx `setProperty` runtime
287
+ // API (see the `applyVars` effect above) — Lynx does NOT honor custom
288
+ // properties declared through the inline `style` attribute in this
289
+ // toolchain. The root background/text are painted here from palette
290
+ // literals (real properties, not custom props) so the surface is themed
291
+ // on first paint; descendants resolve `var(--color-*)` once setProperty
292
+ // has run. The `lynx-zero` base class supplies structural token defaults.
293
+ const palette = colorsOf(state.name) ?? fallbackPalette();
294
+ // Static themes ship a generated CSS class, so `state.name` alone
295
+ // paints on the first frame. A runtime-registered theme has no class —
296
+ // fall back to its variant's static class for the first frame; the
297
+ // `setProperty` effect above then swaps in its exact palette post-mount.
298
+ const themeClass = hasStaticCss(state.name)
299
+ ? state.name
300
+ : `${pickThemeFor(variantOf(state.name) ?? 'light')} ${state.name}`;
301
+ // Root: flex-fill long-form (see the component doc comment). Nested:
302
+ // content-sized — a sub-scope inside scroll content would otherwise
303
+ // collapse to zero height via `flexBasis: 0` (#269).
304
+ const style = isRoot
305
+ ? {
306
+ flexGrow: 1,
307
+ flexShrink: 1,
308
+ flexBasis: 0,
309
+ minHeight: 0,
310
+ display: 'flex',
311
+ flexDirection: 'column',
312
+ }
313
+ : {
314
+ display: 'flex',
315
+ flexDirection: 'column',
316
+ };
317
+ if (palette) {
318
+ style.backgroundColor = palette['base-100'];
319
+ style.color = palette['base-content'];
320
+ }
321
+ if (props.style)
322
+ Object.assign(style, props.style);
323
+ return (_jsx("view", { id: hostId, class: `lynx-zero ${themeClass}${props.class ? ' ' + props.class : ''}`, style: style, children: slots.default?.() }));
324
+ };
325
+ });
326
+ // Re-export registry helpers so consumers only need one import source.
327
+ export { listThemes, registerTheme, extendTheme, pickThemeFor, pairOf, variantOf, colorsOf, radiusOf, sizesOf, } from './registry.js';
328
+ //# sourceMappingURL=ThemeProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemeProvider.js","sourceRoot":"","sources":["../../src/theme/ThemeProvider.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Engine-side color mixing.
3
+ *
4
+ * Lynx's CSS engine has no `color-mix()` and can't alpha-compose `var()`
5
+ * colors — but theme palettes are plain JS data, so tints can be computed
6
+ * where the palette lives instead of in CSS. `registerTheme()` uses this to
7
+ * materialize the `*-soft` tokens (see `./registry.ts`).
8
+ *
9
+ * Accepted inputs are the same "engine-safe" color strings themes already
10
+ * use: `#rgb`, `#rrggbb`, `#rrggbbaa`, `rgb(r, g, b)`, `rgba(r, g, b, a)`.
11
+ * Anything else (named colors, `oklch()`, `var()`) is not parseable here —
12
+ * `mixColors` then falls back to the base color unchanged, which degrades to
13
+ * a neutral surface rather than a wrong tint.
14
+ */
15
+ /**
16
+ * Mix `ratio` of `color` into `base` (linear sRGB per-channel, like
17
+ * `color-mix(in srgb, color ratio, base)`), returning a hex string. If either
18
+ * input can't be parsed, returns `base` unchanged.
19
+ */
20
+ export declare function mixColors(color: string, base: string, ratio: number): string;
21
+ //# sourceMappingURL=color-mix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-mix.d.ts","sourceRoot":"","sources":["../../src/theme/color-mix.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAwCH;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS5E"}