@sigx/lynx-daisyui 0.1.3 → 0.4.1

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 (48) hide show
  1. package/README.md +109 -0
  2. package/dist/buttons/Button.js +53 -0
  3. package/dist/data/Avatar.js +46 -0
  4. package/dist/feedback/Alert.js +13 -0
  5. package/dist/feedback/Badge.js +17 -0
  6. package/dist/feedback/Loading.js +16 -0
  7. package/dist/feedback/Modal.js +23 -0
  8. package/dist/feedback/Progress.js +17 -0
  9. package/dist/feedback/Skeleton.js +18 -0
  10. package/dist/feedback/Steps.js +16 -0
  11. package/dist/forms/Checkbox.js +32 -0
  12. package/dist/forms/FormField.js +5 -0
  13. package/dist/forms/Input.js +25 -0
  14. package/dist/forms/Radio.js +28 -0
  15. package/dist/forms/Select.js +33 -0
  16. package/dist/forms/Textarea.js +31 -0
  17. package/dist/forms/Toggle.js +32 -0
  18. package/dist/index.d.ts +8 -0
  19. package/dist/index.js +38 -552
  20. package/dist/layout/Card.js +39 -0
  21. package/dist/layout/Center.d.ts +2 -1
  22. package/dist/layout/Center.js +24 -0
  23. package/dist/layout/Col.d.ts +2 -2
  24. package/dist/layout/Col.js +33 -0
  25. package/dist/layout/Divider.js +27 -0
  26. package/dist/layout/Row.d.ts +2 -2
  27. package/dist/layout/Row.js +33 -0
  28. package/dist/layout/ScrollView.js +18 -0
  29. package/dist/layout/Spacer.js +11 -0
  30. package/dist/navigation/NavHeader.d.ts +32 -0
  31. package/dist/navigation/NavHeader.js +62 -0
  32. package/dist/navigation/NavTabBar.d.ts +36 -0
  33. package/dist/navigation/NavTabBar.js +58 -0
  34. package/dist/navigation/Tabs.js +18 -0
  35. package/dist/preset/index.js +66 -26
  36. package/dist/shared/press.d.ts +2 -0
  37. package/dist/shared/press.js +6 -0
  38. package/dist/shared/styles.d.ts +29 -1
  39. package/dist/shared/styles.js +90 -0
  40. package/dist/styles/index.css.d.ts +7 -0
  41. package/dist/theme/ThemeProvider.d.ts +82 -0
  42. package/dist/theme/ThemeProvider.js +83 -0
  43. package/dist/typography/Heading.js +19 -0
  44. package/dist/typography/Text.d.ts +11 -1
  45. package/dist/typography/Text.js +25 -0
  46. package/package.json +18 -9
  47. package/dist/index.js.map +0 -1
  48. package/dist/preset/index.js.map +0 -1
package/README.md CHANGED
@@ -42,6 +42,115 @@ import { daisyuiPreset } from '@sigx/lynx-daisyui/preset';
42
42
  export default { presets: [daisyuiPreset], /* … */ };
43
43
  ```
44
44
 
45
+ The preset also publishes a `.flex-fill` utility class (long-form
46
+ `flex-grow/shrink/basis: 0` + `display: flex; flexDirection: column`).
47
+ Use it instead of `flex-1` when a Lynx parent's height comes from
48
+ flex rather than an explicit percentage — `flex-1` expands to
49
+ `flex: 1 1 auto`, which sizes to content and collapses the chain.
50
+
51
+ ## Theme switching
52
+
53
+ The stylesheet ships two color themes (`daisy-light`, `daisy-dark`)
54
+ plus style-modifier themes (`daisy-rounded`, `daisy-flat`). Each is a
55
+ CSS class containing scoped `--color-*` / `--radius-*` variables; Lynx
56
+ has `enableCSSInheritance: true` in its layout-pipeline defaults so
57
+ the variables propagate to every descendant of an element with the
58
+ theme class.
59
+
60
+ `<ThemeProvider>` is a small wrapper that applies the active theme
61
+ class to a host view and exposes a controller via `useTheme()`:
62
+
63
+ ```tsx
64
+ import { ThemeProvider, useTheme } from '@sigx/lynx-daisyui';
65
+
66
+ defineApp(() => () => (
67
+ <ThemeProvider initial="daisy-light">
68
+ <App />
69
+ </ThemeProvider>
70
+ ));
71
+
72
+ // Anywhere inside:
73
+ const theme = useTheme();
74
+ theme.toggle(); // daisy-light ↔ daisy-dark
75
+ theme.set('daisy-dark'); // explicit
76
+ theme.name; // 'daisy-light' | 'daisy-dark' | custom string
77
+ ```
78
+
79
+ The provider's host view defaults to flex-fill long-form so it doesn't
80
+ collapse between a flex parent (`<SafeAreaProvider>`) and a flex child
81
+ (`<SafeAreaView>`). Override via `style={…}` if you want a different
82
+ layout role. For multi-class compositions (color + modifier),
83
+ `theme.set('daisy-light daisy-rounded')` works — the class string is
84
+ applied verbatim to the host view.
85
+
86
+ ## Navigation chrome
87
+
88
+ Two daisy-themed components that pair with
89
+ [`@sigx/lynx-navigation`](../lynx-navigation). Both read state via the
90
+ navigation package's hooks (no internal-module imports), so swapping
91
+ in custom designs later is a one-component change.
92
+
93
+ ### `<NavTabBar />`
94
+
95
+ Themed bottom tab bar. Drop it inside `<Tabs>` and it picks up the
96
+ active tab + tab list via `useTabs()`.
97
+
98
+ ```tsx
99
+ import { Tabs } from '@sigx/lynx-navigation';
100
+ import { NavTabBar } from '@sigx/lynx-daisyui';
101
+
102
+ <Tabs initialTab="trips">
103
+ <Tabs.Screen name="trips" label="Trips">…</Tabs.Screen>
104
+ <Tabs.Screen name="map" label="Map">…</Tabs.Screen>
105
+ <NavTabBar />
106
+ </Tabs>
107
+ ```
108
+
109
+ | Prop | Default | Notes |
110
+ |---|---|---|
111
+ | `position` | `'bottom'` | `'top'` flips the separator border to the bottom edge. |
112
+ | `background` | `'base-200'` | `'base-100' / 'base-200' / 'base-300' / 'transparent'`. |
113
+ | `bordered` | `true` | Show a 1px separator on the edge opposite `position`. |
114
+ | `renderTab` | — | `(info, ctx) => JSX` — replace per-tab rendering entirely. |
115
+
116
+ ### `<NavHeader />`
117
+
118
+ Themed header bar. Drop it inside a `<Stack>` (uses the Stack's
119
+ default slot, introduced in `@sigx/lynx-navigation` 1.0) so its
120
+ `useNav()` resolves to the per-stack nav:
121
+
122
+ ```tsx
123
+ import { Stack } from '@sigx/lynx-navigation';
124
+ import { NavHeader } from '@sigx/lynx-daisyui';
125
+
126
+ <Stack initialRoute="tripsHome">
127
+ <NavHeader />
128
+ </Stack>
129
+ ```
130
+
131
+ Reads everything it needs via `useScreenChrome()` — title, header-
132
+ shown, back-button visibility, and the screen's left/right slot fills.
133
+ Renders an ~48dp horizontal bar with the title centred, a "‹ Back"
134
+ button on the left when `canGoBack`, and the right slot flush-right.
135
+
136
+ | Prop | Default | Notes |
137
+ |---|---|---|
138
+ | `background` | `'base-200'` | Same colour tokens as `NavTabBar`. |
139
+ | `bordered` | `true` | Bottom separator line. |
140
+ | `renderBack` | — | `({ pop }) => JSX` — replace the default back button. |
141
+
142
+ For a fully-custom design, build directly on
143
+ `useScreenChrome()` from `@sigx/lynx-navigation` — `NavHeader` is just
144
+ one consumer of that hook.
145
+
146
+ ## Layout primitives
147
+
148
+ Daisy's flex primitives (`Center`, `Col`, `Row`) accept a `flex={n}`
149
+ prop. The preset rewrites that into the long-form `flex-grow/shrink/
150
+ basis: 0` triple, so `flex={1}` actually fills available space instead
151
+ of collapsing to content size — the standard Lynx `flex: 1` shorthand
152
+ expands to `flex: 1 1 auto` which doesn't do what most people expect.
153
+
45
154
  ## Status
46
155
 
47
156
  Initial release — APIs may shift as the Lynx styling story evolves.
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ import { Pressable } from '@sigx/lynx-gestures';
4
+ import { Loading } from '../feedback/Loading.js';
5
+ import { PRESSED_SCALE, PRESSED_OPACITY } from '../shared/press.js';
6
+ const variantClasses = {
7
+ primary: 'btn-primary', secondary: 'btn-secondary', accent: 'btn-accent',
8
+ info: 'btn-info', success: 'btn-success', warning: 'btn-warning',
9
+ error: 'btn-error', ghost: 'btn-ghost', link: 'btn-link', neutral: 'btn-neutral',
10
+ };
11
+ const sizeClasses = {
12
+ xs: 'btn-xs', sm: 'btn-sm', md: '', lg: 'btn-lg', xl: 'btn-xl',
13
+ };
14
+ export const Button = component(({ props, slots, emit }) => {
15
+ const getClasses = () => {
16
+ const c = ['btn'];
17
+ if (props.variant)
18
+ c.push(variantClasses[props.variant]);
19
+ if (props.size) {
20
+ const s = sizeClasses[props.size];
21
+ if (s)
22
+ c.push(s);
23
+ }
24
+ if (props.outline)
25
+ c.push('btn-outline');
26
+ if (props.soft)
27
+ c.push('btn-soft');
28
+ if (props.wide)
29
+ c.push('btn-wide');
30
+ if (props.loading)
31
+ c.push('btn-loading');
32
+ if (props.block)
33
+ c.push('btn-block');
34
+ if (props.circle)
35
+ c.push('btn-circle');
36
+ if (props.square)
37
+ c.push('btn-square');
38
+ if (props.active)
39
+ c.push('btn-active');
40
+ if (props.disabled)
41
+ c.push('btn-disabled');
42
+ if (props.class)
43
+ c.push(props.class);
44
+ return c.join(' ');
45
+ };
46
+ return () => {
47
+ const inert = !!(props.disabled || props.loading);
48
+ return (_jsx(Pressable, { class: getClasses(), disabled: inert, pressedScale: PRESSED_SCALE, pressedOpacity: PRESSED_OPACITY, longPressDuration: 0, onPress: () => { if (!inert)
49
+ emit('press'); }, children: props.loading
50
+ ? _jsx(Loading, { type: "spinner", size: "sm" })
51
+ : slots.default?.() }));
52
+ };
53
+ });
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ const sizeMap = {
4
+ xs: 24,
5
+ sm: 32,
6
+ md: 48,
7
+ lg: 64,
8
+ xl: 96,
9
+ };
10
+ const fontSizeMap = {
11
+ xs: 10,
12
+ sm: 12,
13
+ md: 18,
14
+ lg: 24,
15
+ xl: 36,
16
+ };
17
+ export const Avatar = component(({ props }) => {
18
+ return () => {
19
+ const size = props.size || 'md';
20
+ const dim = sizeMap[size];
21
+ const classes = ['avatar'];
22
+ if (props.online)
23
+ classes.push('online');
24
+ if (props.offline)
25
+ classes.push('offline');
26
+ if (props.placeholder && !props.src)
27
+ classes.push('placeholder');
28
+ if (props.class)
29
+ classes.push(props.class);
30
+ const rounded = props.rounded;
31
+ const borderRadius = rounded === 'full' || rounded === true ? dim / 2 : 8;
32
+ const innerStyle = {
33
+ width: dim,
34
+ height: dim,
35
+ borderRadius,
36
+ overflow: 'hidden',
37
+ alignItems: 'center',
38
+ justifyContent: 'center',
39
+ display: 'flex',
40
+ };
41
+ if (props.src) {
42
+ return (_jsx("view", { class: classes.join(' '), children: _jsx("view", { style: innerStyle, children: _jsx("image", { src: props.src, style: { width: dim, height: dim, borderRadius } }) }) }));
43
+ }
44
+ return (_jsx("view", { class: classes.join(' '), children: _jsx("view", { class: "avatar-placeholder", style: innerStyle, children: _jsx("text", { style: { fontSize: fontSizeMap[size] }, children: props.placeholder || '?' }) }) }));
45
+ };
46
+ });
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ export const Alert = component(({ props, slots }) => {
4
+ const getClasses = () => {
5
+ const c = ['alert'];
6
+ if (props.variant)
7
+ c.push(`alert-${props.variant}`);
8
+ if (props.class)
9
+ c.push(props.class);
10
+ return c.join(' ');
11
+ };
12
+ return () => _jsx("view", { class: getClasses(), children: slots.default?.() });
13
+ });
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ export const Badge = component(({ props, slots }) => {
4
+ const getClasses = () => {
5
+ const c = ['badge'];
6
+ if (props.variant)
7
+ c.push(`badge-${props.variant}`);
8
+ if (props.size)
9
+ c.push(`badge-${props.size}`);
10
+ if (props.outline)
11
+ c.push('badge-outline');
12
+ if (props.class)
13
+ c.push(props.class);
14
+ return c.join(' ');
15
+ };
16
+ return () => _jsx("view", { class: getClasses(), children: slots.default?.() });
17
+ });
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ export const Loading = component(({ props }) => {
4
+ const getClasses = () => {
5
+ const c = ['loading'];
6
+ c.push(`loading-${props.type ?? 'spinner'}`);
7
+ if (props.size)
8
+ c.push(`loading-${props.size}`);
9
+ if (props.color)
10
+ c.push(`text-${props.color}`);
11
+ if (props.class)
12
+ c.push(props.class);
13
+ return c.join(' ');
14
+ };
15
+ return () => _jsx("view", { class: getClasses() });
16
+ });
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component, compound } from '@sigx/lynx';
3
+ const _Modal = component(({ props, slots }) => {
4
+ return () => {
5
+ if (!props.open)
6
+ return _jsx("view", { style: { display: 'none' } });
7
+ return (_jsx("view", { class: "modal-overlay", bindtap: () => { props.onClose?.(); }, children: _jsx("view", { class: `modal-box${props.class ? ' ' + props.class : ''}`, bindtap: (e) => { e?.stopPropagation?.(); }, children: slots.default?.() }) }));
8
+ };
9
+ });
10
+ const ModalHeader = component(({ props, slots }) => {
11
+ return () => (_jsx("view", { class: `modal-header${props.class ? ' ' + props.class : ''}`, children: slots.default?.() }));
12
+ });
13
+ const ModalBody = component(({ props, slots }) => {
14
+ return () => (_jsx("view", { class: `modal-body${props.class ? ' ' + props.class : ''}`, children: slots.default?.() }));
15
+ });
16
+ const ModalActions = component(({ props, slots }) => {
17
+ return () => (_jsx("view", { class: `modal-action${props.class ? ' ' + props.class : ''}`, children: slots.default?.() }));
18
+ });
19
+ export const Modal = compound(_Modal, {
20
+ Header: ModalHeader,
21
+ Body: ModalBody,
22
+ Actions: ModalActions,
23
+ });
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ export const Progress = component(({ props }) => {
4
+ const getClasses = () => {
5
+ const c = ['progress'];
6
+ if (props.color)
7
+ c.push(`progress-${props.color}`);
8
+ if (props.class)
9
+ c.push(props.class);
10
+ return c.join(' ');
11
+ };
12
+ return () => {
13
+ const max = props.max ?? 100;
14
+ const pct = Math.min(Math.max((props.value ?? 0) / max, 0), 1) * 100;
15
+ return (_jsx("view", { class: getClasses(), children: _jsx("view", { class: "progress-bar", style: { width: `${pct}%` } }) }));
16
+ };
17
+ });
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ export const Skeleton = component(({ props }) => {
4
+ return () => {
5
+ const style = {};
6
+ if (props.width != null)
7
+ style.width = props.width;
8
+ if (props.height != null)
9
+ style.height = props.height;
10
+ if (props.circle) {
11
+ const size = props.width ?? props.height ?? 48;
12
+ style.width = size;
13
+ style.height = size;
14
+ style.borderRadius = typeof size === 'number' ? size / 2 : '50%';
15
+ }
16
+ return (_jsx("view", { class: `skeleton${props.class ? ' ' + props.class : ''}`, style: style }));
17
+ };
18
+ });
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@sigx/lynx/jsx-runtime";
2
+ import { component, compound } from '@sigx/lynx';
3
+ const _Steps = component(({ props, slots }) => {
4
+ return () => {
5
+ const isVertical = props.vertical ?? false;
6
+ return (_jsx("view", { class: `steps${isVertical ? ' steps-vertical' : ' steps-horizontal'}${props.class ? ' ' + props.class : ''}`, children: slots.default?.() }));
7
+ };
8
+ });
9
+ const Step = component(({ props, slots }) => {
10
+ return () => {
11
+ const color = props.color;
12
+ const colorClass = color ? ` step-${color}` : '';
13
+ return (_jsxs("view", { class: `step${colorClass}${props.class ? ' ' + props.class : ''}`, children: [_jsx("view", { class: `step-indicator${colorClass}`, children: props.content ? _jsx("text", { style: { fontSize: 14 }, children: props.content }) : null }), slots.default?.()] }));
14
+ };
15
+ });
16
+ export const Steps = compound(_Steps, { Step });
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ import { Pressable } from '@sigx/lynx-gestures';
4
+ import { PRESSED_SCALE, PRESSED_OPACITY } from '../shared/press.js';
5
+ const checkmarkSizeMap = {
6
+ xs: 10, sm: 12, md: 14, lg: 19,
7
+ };
8
+ export const Checkbox = component(({ props, emit }) => {
9
+ const getClasses = () => {
10
+ const c = ['checkbox'];
11
+ const size = props.size ?? 'md';
12
+ if (size !== 'md')
13
+ c.push(`checkbox-${size}`);
14
+ if (props.color)
15
+ c.push(`checkbox-${props.color}`);
16
+ if (props.checked)
17
+ c.push('checkbox-checked');
18
+ if (props.disabled)
19
+ c.push('checkbox-disabled');
20
+ if (props.class)
21
+ c.push(props.class);
22
+ return c.join(' ');
23
+ };
24
+ return () => {
25
+ const checked = !!props.checked;
26
+ const size = props.size ?? 'md';
27
+ return (_jsx(Pressable, { class: getClasses(), disabled: !!props.disabled, pressedScale: PRESSED_SCALE, pressedOpacity: PRESSED_OPACITY, longPressDuration: 0, onPress: () => {
28
+ if (!props.disabled)
29
+ emit('change', !checked);
30
+ }, children: checked ? (_jsx("text", { class: "checkbox-mark", style: { fontSize: checkmarkSizeMap[size] }, children: "\u2713" })) : null }));
31
+ };
32
+ });
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ export const FormField = component(({ props, slots }) => {
4
+ return () => (_jsxs("view", { class: ['form-control', props.class].filter(Boolean).join(' '), style: { gap: 4 }, children: [props.label && (_jsx("view", { class: "label", children: _jsx("text", { class: "label-text", children: props.required ? `${props.label} *` : props.label }) })), slots.default?.(), props.error && (_jsx("view", { class: "label", children: _jsx("text", { class: "label-text-error", children: props.error }) }))] }));
5
+ });
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ const sizeClasses = {
4
+ xs: 'input-xs', sm: 'input-sm', md: '', lg: 'input-lg',
5
+ };
6
+ export const Input = component(({ props }) => {
7
+ const getClasses = () => {
8
+ const c = ['input'];
9
+ if (props.variant === 'bordered')
10
+ c.push('input-bordered');
11
+ if (props.variant === 'ghost')
12
+ c.push('input-ghost');
13
+ if (props.color)
14
+ c.push(`input-${props.color}`);
15
+ if (props.size) {
16
+ const s = sizeClasses[props.size];
17
+ if (s)
18
+ c.push(s);
19
+ }
20
+ if (props.class)
21
+ c.push(props.class);
22
+ return c.join(' ');
23
+ };
24
+ return () => (_jsx("input", { class: getClasses(), placeholder: props.placeholder, type: props.type ?? 'text', disabled: props.disabled, model: props.model }));
25
+ });
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@sigx/lynx/jsx-runtime";
2
+ import { component, compound } from '@sigx/lynx';
3
+ import { Pressable } from '@sigx/lynx-gestures';
4
+ import { PRESSED_SCALE, PRESSED_OPACITY } from '../shared/press.js';
5
+ const RadioItem = component(({ props, emit }) => {
6
+ const getClasses = () => {
7
+ const c = ['radio'];
8
+ if (props.color)
9
+ c.push(`radio-${props.color}`);
10
+ if (props.size)
11
+ c.push(`radio-${props.size}`);
12
+ if (props.checked)
13
+ c.push('radio-checked');
14
+ if (props.class)
15
+ c.push(props.class);
16
+ return c.join(' ');
17
+ };
18
+ return () => (_jsxs(Pressable, { style: { flexDirection: 'row', alignItems: 'center', gap: 8, opacity: props.disabled ? 0.5 : 1 }, disabled: !!props.disabled, pressedScale: PRESSED_SCALE, pressedOpacity: PRESSED_OPACITY, longPressDuration: 0, onPress: () => {
19
+ if (!props.disabled && props.value != null)
20
+ emit('select', props.value);
21
+ }, children: [_jsx("view", { class: getClasses(), children: props.checked && _jsx("view", { class: "radio-mark" }) }), props.label && _jsx("text", { children: props.label })] }));
22
+ });
23
+ const _RadioGroup = component(({ props, slots }) => {
24
+ return () => (_jsx("view", { class: props.class ?? '', style: { gap: 8 }, children: slots.default?.() }));
25
+ });
26
+ export const Radio = compound(_RadioGroup, {
27
+ Item: RadioItem,
28
+ });
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@sigx/lynx/jsx-runtime";
2
+ import { component, signal } from '@sigx/lynx';
3
+ import { Pressable } from '@sigx/lynx-gestures';
4
+ import { PRESSED_SCALE, PRESSED_OPACITY } from '../shared/press.js';
5
+ export const Select = component(({ props, emit }) => {
6
+ const state = signal({ open: false });
7
+ const getClasses = () => {
8
+ const c = ['select'];
9
+ if (props.variant === 'bordered')
10
+ c.push('select-bordered');
11
+ if (props.variant === 'ghost')
12
+ c.push('select-ghost');
13
+ if (props.color)
14
+ c.push(`select-${props.color}`);
15
+ if (props.size)
16
+ c.push(`select-${props.size}`);
17
+ if (props.class)
18
+ c.push(props.class);
19
+ return c.join(' ');
20
+ };
21
+ const getSelectedLabel = () => {
22
+ const opts = props.options ?? [];
23
+ const found = opts.find((o) => o.value === props.value);
24
+ return found ? found.label : (props.placeholder ?? 'Select...');
25
+ };
26
+ return () => (_jsxs("view", { style: { position: 'relative', opacity: props.disabled ? 0.5 : 1 }, children: [_jsxs(Pressable, { class: getClasses(), disabled: !!props.disabled, pressedScale: PRESSED_SCALE, pressedOpacity: PRESSED_OPACITY, longPressDuration: 0, onPress: () => {
27
+ if (!props.disabled)
28
+ state.open = !state.open;
29
+ }, children: [_jsx("text", { children: getSelectedLabel() }), _jsx("view", { style: { marginLeft: 'auto' }, children: _jsx("text", { children: state.open ? '▲' : '▼' }) })] }), state.open && !props.disabled && (_jsx("view", { class: "select-dropdown", style: { position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 10 }, children: (props.options ?? []).map((option) => (_jsx(Pressable, { class: `select-option${option.value === props.value ? ' select-option-active' : ''}`, pressedScale: PRESSED_SCALE, pressedOpacity: PRESSED_OPACITY, longPressDuration: 0, onPress: () => {
30
+ emit('change', option.value);
31
+ state.open = false;
32
+ }, children: _jsx("text", { children: option.label }) }))) }))] }));
33
+ });
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ const sizeClasses = {
4
+ xs: 'textarea-xs', sm: 'textarea-sm', md: '', lg: 'textarea-lg',
5
+ };
6
+ export const Textarea = component(({ props }) => {
7
+ const getClasses = () => {
8
+ const c = ['textarea'];
9
+ if (props.variant === 'bordered')
10
+ c.push('textarea-bordered');
11
+ if (props.variant === 'ghost')
12
+ c.push('textarea-ghost');
13
+ if (props.color)
14
+ c.push(`textarea-${props.color}`);
15
+ if (props.size) {
16
+ const s = sizeClasses[props.size];
17
+ if (s)
18
+ c.push(s);
19
+ }
20
+ if (props.class)
21
+ c.push(props.class);
22
+ return c.join(' ');
23
+ };
24
+ const getHeight = () => {
25
+ const rows = props.rows ?? 3;
26
+ const lineHeight = 20;
27
+ const padding = 16;
28
+ return rows * lineHeight + padding;
29
+ };
30
+ return () => (_jsx("textarea", { class: getClasses(), placeholder: props.placeholder, disabled: props.disabled, model: props.model, style: { height: getHeight() } }));
31
+ });
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx } from "@sigx/lynx/jsx-runtime";
2
+ import { component } from '@sigx/lynx';
3
+ import { Pressable } from '@sigx/lynx-gestures';
4
+ import { PRESSED_SCALE, PRESSED_OPACITY } from '../shared/press.js';
5
+ const thumbOffsetMap = {
6
+ xs: 10, sm: 16, md: 20, lg: 24,
7
+ };
8
+ export const Toggle = component(({ props, emit }) => {
9
+ const getClasses = () => {
10
+ const c = ['toggle'];
11
+ const size = props.size ?? 'md';
12
+ c.push(`toggle-${size}`);
13
+ if (props.color)
14
+ c.push(`toggle-${props.color}`);
15
+ if (props.checked)
16
+ c.push('toggle-checked');
17
+ if (props.disabled)
18
+ c.push('toggle-disabled');
19
+ if (props.class)
20
+ c.push(props.class);
21
+ return c.join(' ');
22
+ };
23
+ return () => {
24
+ const checked = !!props.checked;
25
+ const size = props.size ?? 'md';
26
+ const offset = checked ? thumbOffsetMap[size] : 0;
27
+ return (_jsx(Pressable, { class: getClasses(), disabled: !!props.disabled, pressedScale: PRESSED_SCALE, pressedOpacity: PRESSED_OPACITY, longPressDuration: 0, onPress: () => {
28
+ if (!props.disabled)
29
+ emit('change', !checked);
30
+ }, children: _jsx("view", { class: "toggle-thumb", style: { transform: `translateX(${offset}px)` } }) }));
31
+ };
32
+ });
package/dist/index.d.ts CHANGED
@@ -14,6 +14,8 @@ export { ScrollView } from './layout/ScrollView.js';
14
14
  export type { ScrollViewProps } from './layout/ScrollView.js';
15
15
  export { Divider } from './layout/Divider.js';
16
16
  export type { DividerProps } from './layout/Divider.js';
17
+ export type { DaisyColor, BackgroundValue, SpacingValue, BoxProps } from './shared/styles.js';
18
+ export { resolveDaisyColor } from './shared/styles.js';
17
19
  export { Input } from './forms/Input.js';
18
20
  export type { InputProps, InputSize, InputVariant, InputColor } from './forms/Input.js';
19
21
  export { Toggle } from './forms/Toggle.js';
@@ -44,6 +46,12 @@ export { Steps } from './feedback/Steps.js';
44
46
  export type { StepsProps, StepProps, StepColor } from './feedback/Steps.js';
45
47
  export { Tabs } from './navigation/Tabs.js';
46
48
  export type { TabsProps, TabProps } from './navigation/Tabs.js';
49
+ export { NavTabBar } from './navigation/NavTabBar.js';
50
+ export type { NavTabBarProps, NavTabBarPosition, NavTabBarBackground, NavTabRenderContext, } from './navigation/NavTabBar.js';
51
+ export { NavHeader } from './navigation/NavHeader.js';
52
+ export type { NavHeaderProps, NavHeaderBackground, } from './navigation/NavHeader.js';
53
+ export { ThemeProvider, useTheme } from './theme/ThemeProvider.js';
54
+ export type { DaisyTheme, ThemeController, ThemeProviderProps, } from './theme/ThemeProvider.js';
47
55
  export { Avatar } from './data/Avatar.js';
48
56
  export type { AvatarProps, AvatarSize } from './data/Avatar.js';
49
57
  export { Text } from './typography/Text.js';