panelui-native 0.1.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +251 -0
- package/lib/module/components/alert/index.js +107 -24
- package/lib/module/components/alert/index.js.map +1 -1
- package/lib/module/components/avatar/index.js +1 -1
- package/lib/module/components/avatar/index.js.map +1 -1
- package/lib/module/components/badge/index.js +3 -3
- package/lib/module/components/badge/index.js.map +1 -1
- package/lib/module/components/bottom-sheet/index.js +35 -31
- package/lib/module/components/bottom-sheet/index.js.map +1 -1
- package/lib/module/components/button/index.js +44 -15
- package/lib/module/components/button/index.js.map +1 -1
- package/lib/module/components/card/index.js +5 -5
- package/lib/module/components/card/index.js.map +1 -1
- package/lib/module/components/checkbox/index.js +21 -8
- package/lib/module/components/checkbox/index.js.map +1 -1
- package/lib/module/components/dialog/index.js +21 -17
- package/lib/module/components/dialog/index.js.map +1 -1
- package/lib/module/components/empty-state/index.js +178 -0
- package/lib/module/components/empty-state/index.js.map +1 -0
- package/lib/module/components/frame/index.js +100 -0
- package/lib/module/components/frame/index.js.map +1 -0
- package/lib/module/components/inline-select/index.js +159 -0
- package/lib/module/components/inline-select/index.js.map +1 -0
- package/lib/module/components/input/index.js +1 -1
- package/lib/module/components/input/index.js.map +1 -1
- package/lib/module/components/input-group/index.js +132 -0
- package/lib/module/components/input-group/index.js.map +1 -0
- package/lib/module/components/label/index.js +117 -0
- package/lib/module/components/label/index.js.map +1 -0
- package/lib/module/components/progress/index.js +138 -0
- package/lib/module/components/progress/index.js.map +1 -0
- package/lib/module/components/select/index.js +35 -28
- package/lib/module/components/select/index.js.map +1 -1
- package/lib/module/components/skeleton/index.js +1 -1
- package/lib/module/components/skeleton/index.js.map +1 -1
- package/lib/module/components/spinner/index.js +1 -1
- package/lib/module/components/spinner/index.js.map +1 -1
- package/lib/module/components/steps/index.js +354 -0
- package/lib/module/components/steps/index.js.map +1 -0
- package/lib/module/components/tabs/index.js +9 -3
- package/lib/module/components/tabs/index.js.map +1 -1
- package/lib/module/components/toast/index.js +479 -0
- package/lib/module/components/toast/index.js.map +1 -0
- package/lib/module/components/toast/toast-store.js +81 -0
- package/lib/module/components/toast/toast-store.js.map +1 -0
- package/lib/module/components/typography/index.js +126 -0
- package/lib/module/components/typography/index.js.map +1 -0
- package/lib/module/icons/index.js +223 -2
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +11 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/providers/panel-ui-provider.js +20 -8
- package/lib/module/providers/panel-ui-provider.js.map +1 -1
- package/lib/module/theme/use-theme.js +90 -3
- package/lib/module/theme/use-theme.js.map +1 -1
- package/lib/typescript/src/components/alert/index.d.ts +41 -19
- package/lib/typescript/src/components/alert/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/src/components/button/index.d.ts +39 -0
- package/lib/typescript/src/components/button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/checkbox/index.d.ts +8 -0
- package/lib/typescript/src/components/checkbox/index.d.ts.map +1 -1
- package/lib/typescript/src/components/dialog/index.d.ts.map +1 -1
- package/lib/typescript/src/components/empty-state/index.d.ts +73 -0
- package/lib/typescript/src/components/empty-state/index.d.ts.map +1 -0
- package/lib/typescript/src/components/frame/index.d.ts +21 -0
- package/lib/typescript/src/components/frame/index.d.ts.map +1 -0
- package/lib/typescript/src/components/inline-select/index.d.ts +25 -0
- package/lib/typescript/src/components/inline-select/index.d.ts.map +1 -0
- package/lib/typescript/src/components/input-group/index.d.ts +34 -0
- package/lib/typescript/src/components/input-group/index.d.ts.map +1 -0
- package/lib/typescript/src/components/label/index.d.ts +28 -0
- package/lib/typescript/src/components/label/index.d.ts.map +1 -0
- package/lib/typescript/src/components/progress/index.d.ts +132 -0
- package/lib/typescript/src/components/progress/index.d.ts.map +1 -0
- package/lib/typescript/src/components/select/index.d.ts.map +1 -1
- package/lib/typescript/src/components/spinner/index.d.ts +2 -2
- package/lib/typescript/src/components/spinner/index.d.ts.map +1 -1
- package/lib/typescript/src/components/steps/index.d.ts +62 -0
- package/lib/typescript/src/components/steps/index.d.ts.map +1 -0
- package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
- package/lib/typescript/src/components/toast/index.d.ts +176 -0
- package/lib/typescript/src/components/toast/index.d.ts.map +1 -0
- package/lib/typescript/src/components/toast/toast-store.d.ts +65 -0
- package/lib/typescript/src/components/toast/toast-store.d.ts.map +1 -0
- package/lib/typescript/src/components/typography/index.d.ts +77 -0
- package/lib/typescript/src/components/typography/index.d.ts.map +1 -0
- package/lib/typescript/src/icons/index.d.ts +25 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +12 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/providers/panel-ui-provider.d.ts +20 -5
- package/lib/typescript/src/providers/panel-ui-provider.d.ts.map +1 -1
- package/lib/typescript/src/theme/use-theme.d.ts +64 -4
- package/lib/typescript/src/theme/use-theme.d.ts.map +1 -1
- package/package.json +28 -5
- package/src/components/alert/index.tsx +104 -28
- package/src/components/avatar/index.tsx +1 -1
- package/src/components/badge/index.tsx +3 -3
- package/src/components/bottom-sheet/index.tsx +8 -3
- package/src/components/button/index.tsx +47 -7
- package/src/components/card/index.tsx +5 -5
- package/src/components/checkbox/index.tsx +18 -4
- package/src/components/dialog/index.tsx +10 -5
- package/src/components/empty-state/index.tsx +136 -0
- package/src/components/frame/index.tsx +104 -0
- package/src/components/inline-select/index.tsx +185 -0
- package/src/components/input/index.tsx +1 -1
- package/src/components/input-group/index.tsx +164 -0
- package/src/components/label/index.tsx +128 -0
- package/src/components/progress/index.tsx +147 -0
- package/src/components/select/index.tsx +30 -23
- package/src/components/skeleton/index.tsx +1 -1
- package/src/components/spinner/index.tsx +1 -1
- package/src/components/steps/index.tsx +343 -0
- package/src/components/tabs/index.tsx +10 -2
- package/src/components/toast/index.tsx +447 -0
- package/src/components/toast/toast-store.ts +120 -0
- package/src/components/typography/index.tsx +121 -0
- package/src/icons/index.tsx +152 -1
- package/src/index.ts +82 -3
- package/src/providers/panel-ui-provider.tsx +35 -10
- package/src/theme/use-theme.ts +119 -4
- package/theme.css +446 -108
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Label — text that names a form field.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from: heroui-inc/heroui-native src/components/label/ (root +
|
|
5
|
+
* Label.Text anatomy, string children auto-wrapping, the required asterisk,
|
|
6
|
+
* and the isInvalid / isDisabled recolouring).
|
|
7
|
+
*/
|
|
8
|
+
import {
|
|
9
|
+
createContext,
|
|
10
|
+
forwardRef,
|
|
11
|
+
useContext,
|
|
12
|
+
useMemo,
|
|
13
|
+
type ReactNode,
|
|
14
|
+
} from 'react';
|
|
15
|
+
import { View, type Text as RNText, type ViewProps } from 'react-native';
|
|
16
|
+
import { tv } from 'tailwind-variants';
|
|
17
|
+
import { Text, type TextProps } from '../../primitives/text';
|
|
18
|
+
|
|
19
|
+
const labelVariants = tv({
|
|
20
|
+
slots: {
|
|
21
|
+
root: 'flex-row items-center gap-1',
|
|
22
|
+
text: 'text-sm font-medium text-foreground',
|
|
23
|
+
asterisk: 'text-sm font-medium text-destructive',
|
|
24
|
+
},
|
|
25
|
+
variants: {
|
|
26
|
+
isDisabled: {
|
|
27
|
+
true: {
|
|
28
|
+
root: 'opacity-[0.64]',
|
|
29
|
+
asterisk: 'text-muted-foreground',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
isInvalid: {
|
|
33
|
+
true: { text: 'text-destructive' },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
interface LabelState {
|
|
39
|
+
isRequired: boolean;
|
|
40
|
+
isInvalid: boolean;
|
|
41
|
+
isDisabled: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const LabelContext = createContext<LabelState>({
|
|
45
|
+
isRequired: false,
|
|
46
|
+
isInvalid: false,
|
|
47
|
+
isDisabled: false,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export interface LabelProps extends ViewProps {
|
|
51
|
+
className?: string;
|
|
52
|
+
/** Appends an asterisk marking the field as required. */
|
|
53
|
+
isRequired?: boolean;
|
|
54
|
+
/** Recolours the label to signal a validation error. */
|
|
55
|
+
isInvalid?: boolean;
|
|
56
|
+
isDisabled?: boolean;
|
|
57
|
+
children?: ReactNode;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const LabelRoot = forwardRef<View, LabelProps>(
|
|
61
|
+
(
|
|
62
|
+
{
|
|
63
|
+
className,
|
|
64
|
+
isRequired = false,
|
|
65
|
+
isInvalid = false,
|
|
66
|
+
isDisabled = false,
|
|
67
|
+
children,
|
|
68
|
+
...props
|
|
69
|
+
},
|
|
70
|
+
ref
|
|
71
|
+
) => {
|
|
72
|
+
const { root } = labelVariants({ isDisabled, isInvalid });
|
|
73
|
+
const state = useMemo(
|
|
74
|
+
() => ({ isRequired, isInvalid, isDisabled }),
|
|
75
|
+
[isRequired, isInvalid, isDisabled]
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<LabelContext.Provider value={state}>
|
|
80
|
+
<View
|
|
81
|
+
ref={ref}
|
|
82
|
+
className={root({ className })}
|
|
83
|
+
accessibilityState={{ disabled: isDisabled }}
|
|
84
|
+
{...props}
|
|
85
|
+
>
|
|
86
|
+
{/* Bare strings are the common case — wrap them so callers don't have to. */}
|
|
87
|
+
{typeof children === 'string' ? <LabelText>{children}</LabelText> : children}
|
|
88
|
+
</View>
|
|
89
|
+
</LabelContext.Provider>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
LabelRoot.displayName = 'Label';
|
|
94
|
+
|
|
95
|
+
export interface LabelTextProps extends TextProps {
|
|
96
|
+
className?: string;
|
|
97
|
+
/** Classes for the required asterisk. */
|
|
98
|
+
asteriskClassName?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const LabelText = forwardRef<RNText, LabelTextProps>(
|
|
102
|
+
({ className, asteriskClassName, children, ...props }, ref) => {
|
|
103
|
+
const { isRequired, isInvalid, isDisabled } = useContext(LabelContext);
|
|
104
|
+
const { text, asterisk } = labelVariants({ isDisabled, isInvalid });
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<>
|
|
108
|
+
<Text ref={ref} className={text({ className })} {...props}>
|
|
109
|
+
{children}
|
|
110
|
+
</Text>
|
|
111
|
+
{isRequired ? (
|
|
112
|
+
<Text
|
|
113
|
+
accessibilityElementsHidden
|
|
114
|
+
importantForAccessibility="no-hide-descendants"
|
|
115
|
+
className={asterisk({ className: asteriskClassName })}
|
|
116
|
+
>
|
|
117
|
+
*
|
|
118
|
+
</Text>
|
|
119
|
+
) : null}
|
|
120
|
+
</>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
LabelText.displayName = 'Label.Text';
|
|
125
|
+
|
|
126
|
+
export const Label = Object.assign(LabelRoot, {
|
|
127
|
+
Text: LabelText,
|
|
128
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { forwardRef, useEffect } from 'react';
|
|
2
|
+
import { View, type LayoutChangeEvent, type ViewProps } from 'react-native';
|
|
3
|
+
import Animated, {
|
|
4
|
+
Easing,
|
|
5
|
+
cancelAnimation,
|
|
6
|
+
interpolate,
|
|
7
|
+
useAnimatedStyle,
|
|
8
|
+
useSharedValue,
|
|
9
|
+
withRepeat,
|
|
10
|
+
withSpring,
|
|
11
|
+
withTiming,
|
|
12
|
+
} from 'react-native-reanimated';
|
|
13
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
14
|
+
|
|
15
|
+
const SPRING = { damping: 20, stiffness: 180, mass: 0.6 } as const;
|
|
16
|
+
/** Fraction of the track covered by the sliding bar in indeterminate mode. */
|
|
17
|
+
const INDETERMINATE_WIDTH = 0.4;
|
|
18
|
+
|
|
19
|
+
const progressVariants = tv({
|
|
20
|
+
slots: {
|
|
21
|
+
track: 'w-full overflow-hidden rounded-full',
|
|
22
|
+
indicator: 'h-full rounded-full',
|
|
23
|
+
},
|
|
24
|
+
variants: {
|
|
25
|
+
color: {
|
|
26
|
+
primary: { track: 'bg-primary/16', indicator: 'bg-primary' },
|
|
27
|
+
success: { track: 'bg-success/16', indicator: 'bg-success' },
|
|
28
|
+
warning: { track: 'bg-warning/16', indicator: 'bg-warning' },
|
|
29
|
+
destructive: { track: 'bg-destructive/16', indicator: 'bg-destructive' },
|
|
30
|
+
info: { track: 'bg-info/16', indicator: 'bg-info' },
|
|
31
|
+
},
|
|
32
|
+
size: {
|
|
33
|
+
sm: { track: 'h-1.5' },
|
|
34
|
+
md: { track: 'h-2' },
|
|
35
|
+
lg: { track: 'h-3' },
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultVariants: {
|
|
39
|
+
color: 'primary',
|
|
40
|
+
size: 'md',
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
type ProgressVariantProps = VariantProps<typeof progressVariants>;
|
|
45
|
+
|
|
46
|
+
export interface ProgressProps
|
|
47
|
+
extends Omit<ViewProps, 'children'>,
|
|
48
|
+
ProgressVariantProps {
|
|
49
|
+
className?: string;
|
|
50
|
+
/** Progress value, 0–100. Ignored when `indeterminate` is set. */
|
|
51
|
+
value?: number;
|
|
52
|
+
/** Show a looping animation for unknown-duration work. */
|
|
53
|
+
indeterminate?: boolean;
|
|
54
|
+
/** Extra classes for the moving indicator. */
|
|
55
|
+
indicatorClassName?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function clamp(value: number) {
|
|
59
|
+
'worklet';
|
|
60
|
+
if (value < 0) return 0;
|
|
61
|
+
if (value > 100) return 100;
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Determinate or indeterminate progress bar. The fill width (determinate) and
|
|
67
|
+
* the sliding bar (indeterminate) are both driven on the UI thread, so updates
|
|
68
|
+
* never re-render past the value change itself.
|
|
69
|
+
*/
|
|
70
|
+
export const Progress = forwardRef<View, ProgressProps>(
|
|
71
|
+
(
|
|
72
|
+
{
|
|
73
|
+
className,
|
|
74
|
+
indicatorClassName,
|
|
75
|
+
value = 0,
|
|
76
|
+
indeterminate = false,
|
|
77
|
+
color,
|
|
78
|
+
size,
|
|
79
|
+
...props
|
|
80
|
+
},
|
|
81
|
+
ref
|
|
82
|
+
) => {
|
|
83
|
+
const slots = progressVariants({ color, size });
|
|
84
|
+
const trackWidth = useSharedValue(0);
|
|
85
|
+
const progress = useSharedValue(clamp(value) / 100);
|
|
86
|
+
const slide = useSharedValue(0);
|
|
87
|
+
|
|
88
|
+
const target = clamp(value) / 100;
|
|
89
|
+
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (indeterminate) {
|
|
92
|
+
slide.value = withRepeat(
|
|
93
|
+
withTiming(1, { duration: 1100, easing: Easing.inOut(Easing.ease) }),
|
|
94
|
+
-1,
|
|
95
|
+
false
|
|
96
|
+
);
|
|
97
|
+
return () => cancelAnimation(slide);
|
|
98
|
+
}
|
|
99
|
+
progress.value = withSpring(target, SPRING);
|
|
100
|
+
return undefined;
|
|
101
|
+
}, [indeterminate, target, progress, slide]);
|
|
102
|
+
|
|
103
|
+
const onLayout = (event: LayoutChangeEvent) => {
|
|
104
|
+
trackWidth.value = event.nativeEvent.layout.width;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const determinateStyle = useAnimatedStyle(() => ({
|
|
108
|
+
width: trackWidth.value * progress.value,
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
const indeterminateStyle = useAnimatedStyle(() => {
|
|
112
|
+
const barWidth = trackWidth.value * INDETERMINATE_WIDTH;
|
|
113
|
+
return {
|
|
114
|
+
width: barWidth,
|
|
115
|
+
transform: [
|
|
116
|
+
{
|
|
117
|
+
translateX: interpolate(
|
|
118
|
+
slide.value,
|
|
119
|
+
[0, 1],
|
|
120
|
+
[-barWidth, trackWidth.value]
|
|
121
|
+
),
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<View
|
|
129
|
+
ref={ref}
|
|
130
|
+
accessibilityRole="progressbar"
|
|
131
|
+
accessibilityValue={
|
|
132
|
+
indeterminate ? undefined : { min: 0, max: 100, now: clamp(value) }
|
|
133
|
+
}
|
|
134
|
+
className={slots.track({ className })}
|
|
135
|
+
onLayout={onLayout}
|
|
136
|
+
{...props}
|
|
137
|
+
>
|
|
138
|
+
<Animated.View
|
|
139
|
+
style={indeterminate ? indeterminateStyle : determinateStyle}
|
|
140
|
+
className={slots.indicator({ className: indicatorClassName })}
|
|
141
|
+
/>
|
|
142
|
+
</View>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
Progress.displayName = 'Progress';
|
|
@@ -18,15 +18,16 @@ import { BottomSheet } from '../bottom-sheet';
|
|
|
18
18
|
const selectVariants = tv({
|
|
19
19
|
slots: {
|
|
20
20
|
trigger:
|
|
21
|
-
'
|
|
22
|
-
triggerLabel: 'text-base text-foreground',
|
|
23
|
-
placeholder: 'text-base text-muted-foreground',
|
|
24
|
-
item: 'flex-row items-center
|
|
25
|
-
itemLabel: 'text-base text-foreground',
|
|
21
|
+
'w-full flex-row items-center justify-between gap-3 rounded-2xl border border-input bg-background px-4 py-3.5',
|
|
22
|
+
triggerLabel: 'flex-1 text-base font-medium text-foreground',
|
|
23
|
+
placeholder: 'flex-1 text-base text-muted-foreground',
|
|
24
|
+
item: 'flex-row items-center gap-2 rounded-xl px-3 py-3',
|
|
25
|
+
itemLabel: 'flex-1 text-base font-medium text-foreground',
|
|
26
|
+
itemIndicator: 'h-5 w-5 items-center justify-center',
|
|
26
27
|
},
|
|
27
28
|
variants: {
|
|
28
29
|
selected: {
|
|
29
|
-
true: { item: 'bg-accent'
|
|
30
|
+
true: { item: 'bg-accent' },
|
|
30
31
|
},
|
|
31
32
|
disabled: {
|
|
32
33
|
true: { trigger: 'opacity-50' },
|
|
@@ -54,8 +55,8 @@ function SelectItem({ value, label }: SelectItemProps) {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
const selected = context.value === value;
|
|
57
|
-
const { item, itemLabel } = selectVariants({ selected });
|
|
58
|
-
const checkColor = useCSSVariable('--muted-foreground');
|
|
58
|
+
const { item, itemLabel, itemIndicator } = selectVariants({ selected });
|
|
59
|
+
const checkColor = useCSSVariable('--color-muted-foreground');
|
|
59
60
|
|
|
60
61
|
return (
|
|
61
62
|
<Pressable
|
|
@@ -65,12 +66,14 @@ function SelectItem({ value, label }: SelectItemProps) {
|
|
|
65
66
|
className={item()}
|
|
66
67
|
>
|
|
67
68
|
<Text className={itemLabel()}>{label}</Text>
|
|
68
|
-
{
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
<View className={itemIndicator()}>
|
|
70
|
+
{selected ? (
|
|
71
|
+
<CheckIcon
|
|
72
|
+
size={16}
|
|
73
|
+
color={typeof checkColor === 'string' ? checkColor : '#737373'}
|
|
74
|
+
/>
|
|
75
|
+
) : null}
|
|
76
|
+
</View>
|
|
74
77
|
</Pressable>
|
|
75
78
|
);
|
|
76
79
|
}
|
|
@@ -124,7 +127,7 @@ function SelectRoot({
|
|
|
124
127
|
const { trigger, triggerLabel, placeholder: placeholderSlot } = selectVariants({
|
|
125
128
|
disabled: !!disabled,
|
|
126
129
|
});
|
|
127
|
-
const chevronColor = useCSSVariable('--muted-foreground');
|
|
130
|
+
const chevronColor = useCSSVariable('--color-muted-foreground');
|
|
128
131
|
|
|
129
132
|
return (
|
|
130
133
|
<SelectContext.Provider value={context}>
|
|
@@ -146,14 +149,18 @@ function SelectRoot({
|
|
|
146
149
|
</Pressable>
|
|
147
150
|
<BottomSheet open={open} onOpenChange={setOpen}>
|
|
148
151
|
<BottomSheet.Content>
|
|
149
|
-
{
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
152
|
+
{/* BottomSheet.Content portals its children out of this subtree —
|
|
153
|
+
re-provide the select context so Select.Item keeps working. */}
|
|
154
|
+
<SelectContext.Provider value={context}>
|
|
155
|
+
{title ? (
|
|
156
|
+
<Text size="lg" weight="semibold" className="mb-2 px-3">
|
|
157
|
+
{title}
|
|
158
|
+
</Text>
|
|
159
|
+
) : null}
|
|
160
|
+
<ScrollView bounces={false} className="max-h-96">
|
|
161
|
+
<View className="gap-1 pb-2">{children}</View>
|
|
162
|
+
</ScrollView>
|
|
163
|
+
</SelectContext.Provider>
|
|
157
164
|
</BottomSheet.Content>
|
|
158
165
|
</BottomSheet>
|
|
159
166
|
</SelectContext.Provider>
|
|
@@ -28,7 +28,7 @@ export const Skeleton = memo(function Skeleton({ className }: SkeletonProps) {
|
|
|
28
28
|
return (
|
|
29
29
|
<Animated.View
|
|
30
30
|
style={animatedStyle}
|
|
31
|
-
className={cn('rounded-md bg-
|
|
31
|
+
className={cn('rounded-md bg-skeleton', className)}
|
|
32
32
|
/>
|
|
33
33
|
);
|
|
34
34
|
});
|
|
@@ -10,7 +10,7 @@ import Animated, {
|
|
|
10
10
|
import { tv, type VariantProps } from 'tailwind-variants';
|
|
11
11
|
|
|
12
12
|
const spinnerVariants = tv({
|
|
13
|
-
base: 'rounded-full border-2 border-
|
|
13
|
+
base: 'rounded-full border-2 border-muted border-t-primary',
|
|
14
14
|
variants: {
|
|
15
15
|
size: {
|
|
16
16
|
sm: 'h-4 w-4',
|