@sigx/lynx-daisyui 0.4.0 → 0.4.2
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 +38 -0
- package/dist/buttons/Button.js +53 -0
- package/dist/data/Avatar.js +46 -0
- package/dist/feedback/Alert.js +13 -0
- package/dist/feedback/Badge.js +17 -0
- package/dist/feedback/Loading.js +16 -0
- package/dist/feedback/Modal.js +23 -0
- package/dist/feedback/Progress.js +17 -0
- package/dist/feedback/Skeleton.js +18 -0
- package/dist/feedback/Steps.js +16 -0
- package/dist/forms/Checkbox.js +32 -0
- package/dist/forms/FormField.js +5 -0
- package/dist/forms/Input.js +25 -0
- package/dist/forms/Radio.js +28 -0
- package/dist/forms/Select.js +33 -0
- package/dist/forms/Textarea.js +31 -0
- package/dist/forms/Toggle.js +32 -0
- package/dist/index.d.ts +66 -58
- package/dist/index.js +41 -678
- package/dist/layout/Card.js +39 -0
- package/dist/layout/Center.d.ts +2 -1
- package/dist/layout/Center.js +24 -0
- package/dist/layout/Col.d.ts +2 -2
- package/dist/layout/Col.js +33 -0
- package/dist/layout/Divider.js +27 -0
- package/dist/layout/Row.d.ts +2 -2
- package/dist/layout/Row.js +33 -0
- package/dist/layout/ScrollView.js +18 -0
- package/dist/layout/Spacer.js +11 -0
- package/dist/navigation/NavDrawer.d.ts +62 -0
- package/dist/navigation/NavDrawer.js +205 -0
- package/dist/navigation/NavHeader.d.ts +12 -1
- package/dist/navigation/NavHeader.js +74 -0
- package/dist/navigation/NavTabBar.js +90 -0
- package/dist/navigation/SwiperIndicator.d.ts +59 -0
- package/dist/navigation/SwiperIndicator.js +232 -0
- package/dist/navigation/Tabs.js +18 -0
- package/dist/preset/index.js +66 -40
- package/dist/shared/press.d.ts +2 -0
- package/dist/shared/press.js +6 -0
- package/dist/shared/styles.d.ts +29 -1
- package/dist/shared/styles.js +90 -0
- package/dist/styles/components/typography.css +36 -2
- package/dist/styles/index.css +8 -4
- package/dist/styles/themes/shapes.css +2 -1
- package/dist/styles/themes/{dark.css → tokens.css} +9 -33
- package/dist/theme/StatusBarSync.d.ts +41 -0
- package/dist/theme/StatusBarSync.js +85 -0
- package/dist/theme/ThemeProvider.d.ts +91 -35
- package/dist/theme/ThemeProvider.js +183 -0
- package/dist/theme/registry.d.ts +101 -0
- package/dist/theme/registry.js +185 -0
- package/dist/typography/Heading.js +19 -0
- package/dist/typography/Text.d.ts +11 -1
- package/dist/typography/Text.js +25 -0
- package/package.json +12 -10
- package/dist/index.js.map +0 -1
- package/dist/preset/index.js.map +0 -1
- package/dist/styles/themes/light.css +0 -95
|
@@ -1,5 +1,30 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/*
|
|
2
|
+
* Daisy semantic color utilities.
|
|
3
|
+
*
|
|
4
|
+
* bg-<token>: every token in DAISY_COLOR_TOKEN_LIST (semantics +
|
|
5
|
+
* their -content variants, plus the three base surfaces
|
|
6
|
+
* and base-content).
|
|
7
|
+
* text-<token>: semantic tokens + their -content variants, plus
|
|
8
|
+
* base-content. The three base surface tokens
|
|
9
|
+
* (base-100/200/300) are deliberately omitted — text the
|
|
10
|
+
* colour of the surface it sits on is never useful, and
|
|
11
|
+
* keeping the class out prevents accidental "invisible
|
|
12
|
+
* text" footguns.
|
|
13
|
+
*
|
|
14
|
+
* Hand-written rules rather than Tailwind-generated utilities, so they
|
|
15
|
+
* survive purge regardless of whether a consumer's source statically
|
|
16
|
+
* references the class. This matters for daisy components that compose
|
|
17
|
+
* the class dynamically — e.g. `class={`bg-${props.background}`}` in
|
|
18
|
+
* `<NavDrawer>` — which Tailwind's source scanner can't see. Without
|
|
19
|
+
* these always-on rules, `<NavDrawer background="primary">` paints
|
|
20
|
+
* transparent because `bg-primary` got purged.
|
|
21
|
+
*
|
|
22
|
+
* Lynx specifics: `var(--color-*)` resolves only from CSS-pipeline rules
|
|
23
|
+
* (this file, daisy themes), never from inline `style.backgroundColor`.
|
|
24
|
+
* Keep daisy surface tokens flowing through a class.
|
|
25
|
+
*/
|
|
2
26
|
|
|
27
|
+
/* Text */
|
|
3
28
|
.text-primary { color: var(--color-primary); }
|
|
4
29
|
.text-primary-content { color: var(--color-primary-content); }
|
|
5
30
|
.text-secondary { color: var(--color-secondary); }
|
|
@@ -18,15 +43,24 @@
|
|
|
18
43
|
.text-error { color: var(--color-error); }
|
|
19
44
|
.text-error-content { color: var(--color-error-content); }
|
|
20
45
|
|
|
21
|
-
/* Background
|
|
46
|
+
/* Background */
|
|
22
47
|
.bg-primary { background-color: var(--color-primary); }
|
|
48
|
+
.bg-primary-content { background-color: var(--color-primary-content); }
|
|
23
49
|
.bg-secondary { background-color: var(--color-secondary); }
|
|
50
|
+
.bg-secondary-content { background-color: var(--color-secondary-content); }
|
|
24
51
|
.bg-accent { background-color: var(--color-accent); }
|
|
52
|
+
.bg-accent-content { background-color: var(--color-accent-content); }
|
|
25
53
|
.bg-neutral { background-color: var(--color-neutral); }
|
|
54
|
+
.bg-neutral-content { background-color: var(--color-neutral-content); }
|
|
26
55
|
.bg-base-100 { background-color: var(--color-base-100); }
|
|
27
56
|
.bg-base-200 { background-color: var(--color-base-200); }
|
|
28
57
|
.bg-base-300 { background-color: var(--color-base-300); }
|
|
58
|
+
.bg-base-content { background-color: var(--color-base-content); }
|
|
29
59
|
.bg-info { background-color: var(--color-info); }
|
|
60
|
+
.bg-info-content { background-color: var(--color-info-content); }
|
|
30
61
|
.bg-success { background-color: var(--color-success); }
|
|
62
|
+
.bg-success-content { background-color: var(--color-success-content); }
|
|
31
63
|
.bg-warning { background-color: var(--color-warning); }
|
|
64
|
+
.bg-warning-content { background-color: var(--color-warning-content); }
|
|
32
65
|
.bg-error { background-color: var(--color-error); }
|
|
66
|
+
.bg-error-content { background-color: var(--color-error-content); }
|
package/dist/styles/index.css
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
/* @sigx/lynx-daisyui —
|
|
1
|
+
/* @sigx/lynx-daisyui — base tokens + component styles.
|
|
2
|
+
*
|
|
3
|
+
* Theme COLORS live in the theme registry (src/theme/registry.ts) and are
|
|
4
|
+
* applied as inline CSS custom properties by <ThemeProvider>; only the
|
|
5
|
+
* theme-agnostic structural tokens ship as CSS, under the `.daisy` base
|
|
6
|
+
* class. */
|
|
2
7
|
|
|
3
|
-
/*
|
|
4
|
-
@import './themes/
|
|
5
|
-
@import './themes/dark.css';
|
|
8
|
+
/* Structural design tokens (.daisy) + composable shape modifiers */
|
|
9
|
+
@import './themes/tokens.css';
|
|
6
10
|
@import './themes/shapes.css';
|
|
7
11
|
|
|
8
12
|
/* Base reset */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* Shape variants — override roundness tokens */
|
|
2
|
-
/*
|
|
2
|
+
/* Compose with the base via ThemeProvider's `class` prop, e.g.
|
|
3
|
+
<ThemeProvider class="daisy-rounded"> → host class="daisy daisy-rounded" */
|
|
3
4
|
|
|
4
5
|
.daisy-flat {
|
|
5
6
|
--rounded-box: 0px;
|
|
@@ -1,37 +1,13 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/* Semantic colors */
|
|
10
|
-
--color-primary: #7582ff;
|
|
11
|
-
--color-primary-content: #050617;
|
|
12
|
-
--color-secondary: #ff71cf;
|
|
13
|
-
--color-secondary-content: #190211;
|
|
14
|
-
--color-accent: #00e7d0;
|
|
15
|
-
--color-accent-content: #001210;
|
|
16
|
-
--color-neutral: #2a323c;
|
|
17
|
-
--color-neutral-content: #a6adbb;
|
|
18
|
-
|
|
19
|
-
/* Base colors */
|
|
20
|
-
--color-base-100: #1d232a;
|
|
21
|
-
--color-base-200: #191e24;
|
|
22
|
-
--color-base-300: #343b46;
|
|
23
|
-
--color-base-content: #a6adbb;
|
|
24
|
-
|
|
25
|
-
/* Status colors */
|
|
26
|
-
--color-info: #00b4fa;
|
|
27
|
-
--color-info-content: #000000;
|
|
28
|
-
--color-success: #00a96e;
|
|
29
|
-
--color-success-content: #000000;
|
|
30
|
-
--color-warning: #ffc100;
|
|
31
|
-
--color-warning-content: #000000;
|
|
32
|
-
--color-error: #ff676a;
|
|
33
|
-
--color-error-content: #000000;
|
|
1
|
+
/* Theme-agnostic structural design tokens.
|
|
2
|
+
*
|
|
3
|
+
* Theme COLORS come from the theme registry (src/theme/registry.ts) and are
|
|
4
|
+
* applied as inline CSS custom properties by <ThemeProvider>. These
|
|
5
|
+
* radius / sizing / component tokens are identical across themes, so they
|
|
6
|
+
* ship once here under the `.daisy` base class that <ThemeProvider> puts on
|
|
7
|
+
* its host view; CSS inheritance propagates them to every descendant. A theme
|
|
8
|
+
* may still override roundness via its `radius` field. */
|
|
34
9
|
|
|
10
|
+
.daisy {
|
|
35
11
|
/* ── Roundness ── */
|
|
36
12
|
--rounded-box: 16px;
|
|
37
13
|
--rounded-btn: 8px;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<StatusBarSync />` — keeps the device status-bar (and Android's
|
|
3
|
+
* navigation-bar) tint legible against the active daisyui 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, {}>;
|
|
@@ -0,0 +1,85 @@
|
|
|
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 daisyui 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 { useTheme } from './ThemeProvider.js';
|
|
32
|
+
import { variantOf } from './registry.js';
|
|
33
|
+
export const StatusBarSync = component(({ props }) => {
|
|
34
|
+
const theme = useTheme();
|
|
35
|
+
let lastApplied = null;
|
|
36
|
+
let runner;
|
|
37
|
+
function apply(name) {
|
|
38
|
+
if (name === lastApplied)
|
|
39
|
+
return;
|
|
40
|
+
lastApplied = name;
|
|
41
|
+
const variant = variantOf(name);
|
|
42
|
+
// For unregistered themes we can't infer a variant — leave the
|
|
43
|
+
// system bars alone. Consumers can register their custom theme via
|
|
44
|
+
// `registerTheme()` to opt in.
|
|
45
|
+
if (!variant)
|
|
46
|
+
return;
|
|
47
|
+
const style = variant === 'dark' ? 'light' : 'dark';
|
|
48
|
+
// Fire-and-forget: `setSystemBarsStyle` is non-throwing (it
|
|
49
|
+
// resolves `{ ok: false, reason: 'unsupported' }` when the native
|
|
50
|
+
// module isn't registered, and silently filters per-leg
|
|
51
|
+
// `unsupported` results — e.g. nav-bar on iOS — so an aggregate
|
|
52
|
+
// `ok: true` is still reachable on partial platforms). Either way,
|
|
53
|
+
// void-discarding the promise here can't surface as an unhandled
|
|
54
|
+
// rejection.
|
|
55
|
+
void setSystemBarsStyle({
|
|
56
|
+
statusBar: style,
|
|
57
|
+
navigationBar: { style },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
onMounted(() => {
|
|
61
|
+
if (!isAvailable())
|
|
62
|
+
return;
|
|
63
|
+
// A reactive effect that reads `theme.name` so the effect re-runs
|
|
64
|
+
// whenever the theme controller's underlying signal changes —
|
|
65
|
+
// including the live system-flip path inside ThemeProvider. No
|
|
66
|
+
// side effects in render; nothing to subscribe/unsubscribe by
|
|
67
|
+
// hand.
|
|
68
|
+
runner = effect(() => {
|
|
69
|
+
apply(theme.name);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
onUnmounted(() => {
|
|
73
|
+
runner?.stop();
|
|
74
|
+
runner = undefined;
|
|
75
|
+
});
|
|
76
|
+
// Reference the prop so the type checker doesn't flag it as unused
|
|
77
|
+
// while it's still reserved. Drop this when the matchBackground
|
|
78
|
+
// implementation lands.
|
|
79
|
+
void props.matchBackground;
|
|
80
|
+
// Zero-size, out-of-flow placeholder. Avoids `display: none` —
|
|
81
|
+
// Lynx can leak unstyled text paint through display:none overlays in
|
|
82
|
+
// some builds (see lynx-display-none caveat); zero-size + absolute is
|
|
83
|
+
// the safer shape.
|
|
84
|
+
return () => (_jsx("view", { style: { position: 'absolute', width: '0px', height: '0px', opacity: 0 } }));
|
|
85
|
+
});
|
|
@@ -2,54 +2,92 @@
|
|
|
2
2
|
* `<ThemeProvider>` and `useTheme()` — daisyui theme switching for
|
|
3
3
|
* `@sigx/lynx-daisyui`.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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 the daisyui components are built to read
|
|
9
|
+
* those vars directly.
|
|
10
|
+
*
|
|
11
|
+
* Six color themes ship in the box (`daisy-light`, `daisy-dark`,
|
|
12
|
+
* `daisy-cupcake`, `daisy-emerald`, `daisy-synthwave`, `daisy-dracula`)
|
|
13
|
+
* plus style modifier themes (`daisy-rounded`, `daisy-flat`). Custom themes
|
|
14
|
+
* register their light/dark variant via `registerTheme()` in
|
|
15
|
+
* `./registry.ts` so `followSystem` and `toggle()` know what to pick.
|
|
12
16
|
*
|
|
13
17
|
* Usage:
|
|
14
18
|
*
|
|
15
19
|
* ```tsx
|
|
16
20
|
* import { ThemeProvider, useTheme } from '@sigx/lynx-daisyui';
|
|
17
21
|
*
|
|
22
|
+
* // System-aware (default): picks daisy-light or daisy-dark from the OS,
|
|
23
|
+
* // live-flips when the user toggles dark mode.
|
|
18
24
|
* defineApp(() => () => (
|
|
19
|
-
* <ThemeProvider
|
|
25
|
+
* <ThemeProvider>
|
|
20
26
|
* <App />
|
|
21
27
|
* </ThemeProvider>
|
|
22
28
|
* ));
|
|
23
29
|
*
|
|
24
|
-
* //
|
|
25
|
-
*
|
|
26
|
-
* theme.toggle(); // daisy-light ↔ daisy-dark
|
|
27
|
-
* theme.set('daisy-dark'); // explicit
|
|
28
|
-
* theme.name; // 'daisy-light' | 'daisy-dark' | custom string
|
|
29
|
-
* ```
|
|
30
|
+
* // Pin a specific theme — ignores system appearance.
|
|
31
|
+
* <ThemeProvider initial="daisy-light">…</ThemeProvider>
|
|
30
32
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
+
* // Custom light/dark pair under followSystem.
|
|
34
|
+
* <ThemeProvider light="daisy-cupcake" dark="daisy-synthwave">…</ThemeProvider>
|
|
35
|
+
* ```
|
|
33
36
|
*/
|
|
34
37
|
import { type Define } from '@sigx/lynx';
|
|
38
|
+
import type { DaisyColor } from '../shared/styles.js';
|
|
39
|
+
/**
|
|
40
|
+
* Declaration-merge extension: add a typed `variant` prop to `<Icon>`,
|
|
41
|
+
* `<FaSolidIcon>`, `<LucideIcon>`, etc. Daisy owns the entire concept
|
|
42
|
+
* — `@sigx/lynx-icons` has no notion of variants. Without this merge
|
|
43
|
+
* being in scope (i.e. an app that doesn't depend on daisy), `<Icon
|
|
44
|
+
* variant="…">` is a compile error: the property doesn't exist.
|
|
45
|
+
*
|
|
46
|
+
* The merge fires the moment any consumer imports anything from
|
|
47
|
+
* `@sigx/lynx-daisyui`. No subpath, no extra import dance.
|
|
48
|
+
*/
|
|
49
|
+
declare module '@sigx/lynx-icons' {
|
|
50
|
+
interface IconPropsExtensions {
|
|
51
|
+
/**
|
|
52
|
+
* Daisy color token applied as the icon's `fill`. Resolved at
|
|
53
|
+
* runtime through `useIconColorResolver` (provided by
|
|
54
|
+
* `<ThemeProvider>`) to the current theme's hex value.
|
|
55
|
+
*/
|
|
56
|
+
variant?: DaisyColor;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
35
59
|
/**
|
|
36
|
-
* Theme class applied to the provider's host view. The
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* `'daisy-light daisy-rounded'`.
|
|
60
|
+
* Theme class applied to the provider's host view. The six color themes
|
|
61
|
+
* get autocomplete; arbitrary strings are accepted for custom themes or
|
|
62
|
+
* multi-class compositions like `'daisy-light daisy-rounded'`.
|
|
40
63
|
*/
|
|
41
|
-
export type DaisyTheme = 'daisy-light' | 'daisy-dark' | (string & {});
|
|
64
|
+
export type DaisyTheme = 'daisy-light' | 'daisy-dark' | 'daisy-cupcake' | 'daisy-emerald' | 'daisy-synthwave' | 'daisy-dracula' | (string & {});
|
|
42
65
|
export interface ThemeController {
|
|
43
66
|
/** Current theme class. Reactive — read inside render/effect to track. */
|
|
44
67
|
readonly name: DaisyTheme;
|
|
45
|
-
/**
|
|
68
|
+
/**
|
|
69
|
+
* Whether the theme is currently being driven by the system color
|
|
70
|
+
* scheme (true when no `initial` was passed and `set()` hasn't been
|
|
71
|
+
* called since mount). UI like a settings screen can read this to show
|
|
72
|
+
* a "Follow system" indicator.
|
|
73
|
+
*/
|
|
74
|
+
readonly followingSystem: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Replace the active theme. Pins the choice — subsequent system
|
|
77
|
+
* appearance changes won't override it (until `followSystem()` is called).
|
|
78
|
+
*/
|
|
46
79
|
set(name: DaisyTheme): void;
|
|
47
80
|
/**
|
|
48
|
-
* Flip
|
|
49
|
-
*
|
|
50
|
-
*
|
|
81
|
+
* Flip to the paired theme — for built-ins, light ↔ dark; for custom
|
|
82
|
+
* themes, follows the `pair` declared in `registerTheme()`, or the
|
|
83
|
+
* first theme of the opposite variant.
|
|
51
84
|
*/
|
|
52
85
|
toggle(): void;
|
|
86
|
+
/**
|
|
87
|
+
* Resume following system appearance. Equivalent to mounting fresh
|
|
88
|
+
* with no `initial` prop. Useful for a "Reset to system" button.
|
|
89
|
+
*/
|
|
90
|
+
followSystem(): void;
|
|
53
91
|
}
|
|
54
92
|
/**
|
|
55
93
|
* Access the enclosing daisyui theme controller. Throws when used
|
|
@@ -57,26 +95,44 @@ export interface ThemeController {
|
|
|
57
95
|
*/
|
|
58
96
|
export declare const useTheme: import("@sigx/runtime-core").InjectableFunction<ThemeController>;
|
|
59
97
|
export type ThemeProviderProps =
|
|
60
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* Pin the initial theme. When set, the provider ignores system
|
|
100
|
+
* appearance until `controller.followSystem()` is called. When
|
|
101
|
+
* omitted, the provider follows the OS color scheme and live-flips
|
|
102
|
+
* with it.
|
|
103
|
+
*/
|
|
61
104
|
Define.Prop<'initial', DaisyTheme, false>
|
|
105
|
+
/**
|
|
106
|
+
* Theme to use when the system color scheme is `'light'`. Defaults to
|
|
107
|
+
* the first registered light theme (`daisy-light`). Only consulted
|
|
108
|
+
* while `followingSystem` is true.
|
|
109
|
+
*/
|
|
110
|
+
& Define.Prop<'light', DaisyTheme, false>
|
|
111
|
+
/**
|
|
112
|
+
* Theme to use when the system color scheme is `'dark'`. Defaults to
|
|
113
|
+
* the first registered dark theme (`daisy-dark`). Only consulted
|
|
114
|
+
* while `followingSystem` is true.
|
|
115
|
+
*/
|
|
116
|
+
& Define.Prop<'dark', DaisyTheme, false>
|
|
62
117
|
/** Extra classes appended to the theme class on the host view. */
|
|
63
118
|
& Define.Prop<'class', string, false>
|
|
64
119
|
/** Extra inline style on the host view. Merged after the base flex-fill defaults. */
|
|
65
120
|
& Define.Prop<'style', Record<string, string | number>, false> & Define.Slot<'default'>;
|
|
66
121
|
/**
|
|
67
|
-
* Wraps children in a `<view class={theme}>` so the daisyui CSS
|
|
68
|
-
*
|
|
69
|
-
* down to every descendant.
|
|
122
|
+
* Wraps children in a `<view class={theme}>` so the daisyui CSS variables
|
|
123
|
+
* defined inside the theme class inherit down to every descendant.
|
|
70
124
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
125
|
+
* Layout: defaults to flex-fill long-form so the wrapper doesn't collapse
|
|
126
|
+
* between ancestors that flex (e.g. `<SafeAreaProvider>`) and descendants
|
|
127
|
+
* that need a sized parent (`<SafeAreaView>`). Consumers override via
|
|
128
|
+
* `style`.
|
|
75
129
|
*
|
|
76
130
|
* Theme name is held in an *object* signal (not a primitive) so the
|
|
77
|
-
* literal-union type survives — `signal<T>` widens primitive literals
|
|
78
|
-
*
|
|
131
|
+
* literal-union type survives — `signal<T>` widens primitive literals to
|
|
132
|
+
* plain `string` via `Widen<T>`.
|
|
79
133
|
*/
|
|
80
134
|
export declare const ThemeProvider: import("@sigx/runtime-core").ComponentFactory<ThemeProviderProps, void, {
|
|
81
135
|
default: () => import("@sigx/runtime-core").JSXElement | import("@sigx/runtime-core").JSXElement[] | null;
|
|
82
136
|
}>;
|
|
137
|
+
export { listThemes, registerTheme, extendTheme, pickThemeFor, pairOf, variantOf, colorsOf, radiusOf, } from './registry.js';
|
|
138
|
+
export type { Theme, ThemePalette, ThemeRadius, ThemeVariant } from './registry.js';
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* `<ThemeProvider>` and `useTheme()` — daisyui theme switching for
|
|
4
|
+
* `@sigx/lynx-daisyui`.
|
|
5
|
+
*
|
|
6
|
+
* Themes are CSS classes containing scoped `--color-*` / `--radius-*`
|
|
7
|
+
* variable definitions; descendants of an element with the class inherit
|
|
8
|
+
* those variables (Lynx has `enableCSSInheritance: true` in its
|
|
9
|
+
* layout-pipeline defaults), and the daisyui components are built to read
|
|
10
|
+
* those vars directly.
|
|
11
|
+
*
|
|
12
|
+
* Six color themes ship in the box (`daisy-light`, `daisy-dark`,
|
|
13
|
+
* `daisy-cupcake`, `daisy-emerald`, `daisy-synthwave`, `daisy-dracula`)
|
|
14
|
+
* plus style modifier themes (`daisy-rounded`, `daisy-flat`). Custom themes
|
|
15
|
+
* register their light/dark variant via `registerTheme()` in
|
|
16
|
+
* `./registry.ts` so `followSystem` and `toggle()` know what to pick.
|
|
17
|
+
*
|
|
18
|
+
* Usage:
|
|
19
|
+
*
|
|
20
|
+
* ```tsx
|
|
21
|
+
* import { ThemeProvider, useTheme } from '@sigx/lynx-daisyui';
|
|
22
|
+
*
|
|
23
|
+
* // System-aware (default): picks daisy-light or daisy-dark from the OS,
|
|
24
|
+
* // live-flips when the user toggles dark mode.
|
|
25
|
+
* defineApp(() => () => (
|
|
26
|
+
* <ThemeProvider>
|
|
27
|
+
* <App />
|
|
28
|
+
* </ThemeProvider>
|
|
29
|
+
* ));
|
|
30
|
+
*
|
|
31
|
+
* // Pin a specific theme — ignores system appearance.
|
|
32
|
+
* <ThemeProvider initial="daisy-light">…</ThemeProvider>
|
|
33
|
+
*
|
|
34
|
+
* // Custom light/dark pair under followSystem.
|
|
35
|
+
* <ThemeProvider light="daisy-cupcake" dark="daisy-synthwave">…</ThemeProvider>
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
import { component, defineInjectable, defineProvide, onMounted, onUnmounted, signal, } from '@sigx/lynx';
|
|
39
|
+
import { useIconColorResolver } from '@sigx/lynx-icons';
|
|
40
|
+
import { useSystemColorScheme } from '@sigx/lynx-appearance';
|
|
41
|
+
import { colorsOf, pairOf, pickThemeFor, radiusOf } from './registry.js';
|
|
42
|
+
/**
|
|
43
|
+
* Access the enclosing daisyui theme controller. Throws when used
|
|
44
|
+
* outside `<ThemeProvider>` — install a provider at your app root.
|
|
45
|
+
*/
|
|
46
|
+
export const useTheme = defineInjectable(() => {
|
|
47
|
+
throw new Error('[lynx-daisyui] useTheme() called outside <ThemeProvider>. Wrap your app root with `<ThemeProvider>…</ThemeProvider>`.');
|
|
48
|
+
});
|
|
49
|
+
/**
|
|
50
|
+
* Wraps children in a `<view class={theme}>` so the daisyui CSS variables
|
|
51
|
+
* defined inside the theme class inherit down to every descendant.
|
|
52
|
+
*
|
|
53
|
+
* Layout: defaults to flex-fill long-form so the wrapper doesn't collapse
|
|
54
|
+
* between ancestors that flex (e.g. `<SafeAreaProvider>`) and descendants
|
|
55
|
+
* that need a sized parent (`<SafeAreaView>`). Consumers override via
|
|
56
|
+
* `style`.
|
|
57
|
+
*
|
|
58
|
+
* Theme name is held in an *object* signal (not a primitive) so the
|
|
59
|
+
* literal-union type survives — `signal<T>` widens primitive literals to
|
|
60
|
+
* plain `string` via `Widen<T>`.
|
|
61
|
+
*/
|
|
62
|
+
export const ThemeProvider = component(({ props, slots }) => {
|
|
63
|
+
const systemScheme = useSystemColorScheme();
|
|
64
|
+
// The underlying signal widens to PrimitiveSignal<string> via Widen<T>;
|
|
65
|
+
// cast at read sites to keep the narrow union throughout the component.
|
|
66
|
+
const readScheme = () => systemScheme.value;
|
|
67
|
+
// Seed: pin to `initial` if set, otherwise follow system.
|
|
68
|
+
const initialState = props.initial
|
|
69
|
+
? { name: props.initial, following: false }
|
|
70
|
+
: {
|
|
71
|
+
name: readScheme() === 'dark'
|
|
72
|
+
? (props.dark ?? pickThemeFor('dark'))
|
|
73
|
+
: (props.light ?? pickThemeFor('light')),
|
|
74
|
+
following: true,
|
|
75
|
+
};
|
|
76
|
+
const state = signal(initialState);
|
|
77
|
+
// Guard against re-applying the same theme on stray re-fires.
|
|
78
|
+
let lastApplied = state.following ? readScheme() : null;
|
|
79
|
+
function applySystem(scheme, force = false) {
|
|
80
|
+
if (!state.following)
|
|
81
|
+
return;
|
|
82
|
+
if (!force && lastApplied === scheme)
|
|
83
|
+
return;
|
|
84
|
+
lastApplied = scheme;
|
|
85
|
+
state.name = scheme === 'dark'
|
|
86
|
+
? (props.dark ?? pickThemeFor('dark'))
|
|
87
|
+
: (props.light ?? pickThemeFor('light'));
|
|
88
|
+
}
|
|
89
|
+
const controller = {
|
|
90
|
+
get name() { return state.name; },
|
|
91
|
+
get followingSystem() { return state.following; },
|
|
92
|
+
set(next) {
|
|
93
|
+
state.name = next;
|
|
94
|
+
state.following = false;
|
|
95
|
+
},
|
|
96
|
+
toggle() {
|
|
97
|
+
state.name = pairOf(state.name);
|
|
98
|
+
state.following = false;
|
|
99
|
+
},
|
|
100
|
+
followSystem() {
|
|
101
|
+
state.following = true;
|
|
102
|
+
applySystem(readScheme(), /* force */ true);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
defineProvide(useTheme, () => controller);
|
|
106
|
+
// Wire the daisy color resolver into `@sigx/lynx-icons`'s injectable
|
|
107
|
+
// so any `<Icon variant="primary">` rendered inside this subtree gets
|
|
108
|
+
// the daisy primary hex automatically. Reading `state.name` inside
|
|
109
|
+
// the resolver makes every icon's render re-run when the theme flips.
|
|
110
|
+
const resolver = (iconProps) => {
|
|
111
|
+
const variant = iconProps.variant;
|
|
112
|
+
if (!variant)
|
|
113
|
+
return undefined;
|
|
114
|
+
// Every theme's palette lives in the registry; fall back to daisy-light
|
|
115
|
+
// if the active theme isn't registered. SVG fills can't read CSS vars,
|
|
116
|
+
// so the resolved hex/rgb is substituted into the fill at render time.
|
|
117
|
+
const palette = colorsOf(state.name) ?? colorsOf('daisy-light');
|
|
118
|
+
return palette?.[variant];
|
|
119
|
+
};
|
|
120
|
+
defineProvide(useIconColorResolver, () => resolver);
|
|
121
|
+
// Subscribe to system color-scheme changes. Both PrimitiveSignal and
|
|
122
|
+
// Computed expose `.subscribe(fn)` returning an unsubscribe handle —
|
|
123
|
+
// we lean on the structural shape so this file doesn't pull
|
|
124
|
+
// @sigx/reactivity into its imports.
|
|
125
|
+
let unsubscribe;
|
|
126
|
+
onMounted(() => {
|
|
127
|
+
// Re-seed once mounted — covers the case where the native publisher
|
|
128
|
+
// populated `__globalProps` between setup and mount.
|
|
129
|
+
applySystem(readScheme());
|
|
130
|
+
const sig = systemScheme;
|
|
131
|
+
if (typeof sig.subscribe === 'function') {
|
|
132
|
+
unsubscribe = sig.subscribe(() => applySystem(readScheme()));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
onUnmounted(() => {
|
|
136
|
+
unsubscribe?.();
|
|
137
|
+
unsubscribe = undefined;
|
|
138
|
+
});
|
|
139
|
+
return () => {
|
|
140
|
+
// Every theme is data. Apply its color tokens as inline CSS custom
|
|
141
|
+
// properties — Lynx inherits custom properties to descendants, so
|
|
142
|
+
// component classes resolve `var(--color-*)` against these (the same
|
|
143
|
+
// mechanism SafeAreaProvider uses for `--sat`/`--sal`). The `daisy`
|
|
144
|
+
// base class supplies theme-agnostic structural tokens (radius,
|
|
145
|
+
// sizing); a theme may override roundness via `radius`. The root
|
|
146
|
+
// background/text are painted from the palette literals (inline
|
|
147
|
+
// `var()` values don't resolve in Lynx).
|
|
148
|
+
const palette = colorsOf(state.name) ?? colorsOf('daisy-light');
|
|
149
|
+
const radius = radiusOf(state.name);
|
|
150
|
+
const style = {
|
|
151
|
+
flexGrow: 1,
|
|
152
|
+
flexShrink: 1,
|
|
153
|
+
flexBasis: 0,
|
|
154
|
+
minHeight: 0,
|
|
155
|
+
display: 'flex',
|
|
156
|
+
flexDirection: 'column',
|
|
157
|
+
backgroundColor: palette['base-100'],
|
|
158
|
+
color: palette['base-content'],
|
|
159
|
+
};
|
|
160
|
+
for (const key in palette) {
|
|
161
|
+
style[`--color-${key}`] = palette[key];
|
|
162
|
+
}
|
|
163
|
+
if (radius) {
|
|
164
|
+
if (radius.box)
|
|
165
|
+
style['--rounded-box'] = radius.box;
|
|
166
|
+
if (radius.btn)
|
|
167
|
+
style['--rounded-btn'] = radius.btn;
|
|
168
|
+
if (radius.badge)
|
|
169
|
+
style['--rounded-badge'] = radius.badge;
|
|
170
|
+
if (radius.tab)
|
|
171
|
+
style['--rounded-tab'] = radius.tab;
|
|
172
|
+
if (radius.selector)
|
|
173
|
+
style['--rounded-selector'] = radius.selector;
|
|
174
|
+
if (radius.toggle)
|
|
175
|
+
style['--rounded-toggle'] = radius.toggle;
|
|
176
|
+
}
|
|
177
|
+
if (props.style)
|
|
178
|
+
Object.assign(style, props.style);
|
|
179
|
+
return (_jsx("view", { class: `daisy${props.class ? ' ' + props.class : ''}`, style: style, children: slots.default?.() }));
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
// Re-export registry helpers so consumers only need `@sigx/lynx-daisyui`.
|
|
183
|
+
export { listThemes, registerTheme, extendTheme, pickThemeFor, pairOf, variantOf, colorsOf, radiusOf, } from './registry.js';
|