panelui-native 0.4.0 → 0.5.3

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 (51) hide show
  1. package/README.md +16 -8
  2. package/lib/module/components/accordion/index.js +312 -0
  3. package/lib/module/components/accordion/index.js.map +1 -0
  4. package/lib/module/components/avatar/index.js +58 -17
  5. package/lib/module/components/avatar/index.js.map +1 -1
  6. package/lib/module/components/badge/index.js +26 -5
  7. package/lib/module/components/badge/index.js.map +1 -1
  8. package/lib/module/components/button/index.js +51 -19
  9. package/lib/module/components/button/index.js.map +1 -1
  10. package/lib/module/components/checkbox/index.js +42 -14
  11. package/lib/module/components/checkbox/index.js.map +1 -1
  12. package/lib/module/components/frame/index.js +64 -13
  13. package/lib/module/components/frame/index.js.map +1 -1
  14. package/lib/module/components/timeline/index.js +658 -0
  15. package/lib/module/components/timeline/index.js.map +1 -0
  16. package/lib/module/components/toast/index.js +145 -55
  17. package/lib/module/components/toast/index.js.map +1 -1
  18. package/lib/module/icons/index.js +388 -27
  19. package/lib/module/icons/index.js.map +1 -1
  20. package/lib/module/index.js +3 -1
  21. package/lib/module/index.js.map +1 -1
  22. package/lib/typescript/src/components/accordion/index.d.ts +56 -0
  23. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -0
  24. package/lib/typescript/src/components/avatar/index.d.ts +8 -1
  25. package/lib/typescript/src/components/avatar/index.d.ts.map +1 -1
  26. package/lib/typescript/src/components/badge/index.d.ts +38 -0
  27. package/lib/typescript/src/components/badge/index.d.ts.map +1 -1
  28. package/lib/typescript/src/components/button/index.d.ts +18 -0
  29. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  30. package/lib/typescript/src/components/checkbox/index.d.ts +42 -0
  31. package/lib/typescript/src/components/checkbox/index.d.ts.map +1 -1
  32. package/lib/typescript/src/components/frame/index.d.ts +39 -5
  33. package/lib/typescript/src/components/frame/index.d.ts.map +1 -1
  34. package/lib/typescript/src/components/timeline/index.d.ts +96 -0
  35. package/lib/typescript/src/components/timeline/index.d.ts.map +1 -0
  36. package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
  37. package/lib/typescript/src/icons/index.d.ts +38 -3
  38. package/lib/typescript/src/icons/index.d.ts.map +1 -1
  39. package/lib/typescript/src/index.d.ts +4 -2
  40. package/lib/typescript/src/index.d.ts.map +1 -1
  41. package/package.json +1 -1
  42. package/src/components/accordion/index.tsx +344 -0
  43. package/src/components/avatar/index.tsx +68 -20
  44. package/src/components/badge/index.tsx +35 -6
  45. package/src/components/button/index.tsx +63 -20
  46. package/src/components/checkbox/index.tsx +49 -11
  47. package/src/components/frame/index.tsx +101 -31
  48. package/src/components/timeline/index.tsx +482 -0
  49. package/src/components/toast/index.tsx +166 -45
  50. package/src/icons/index.tsx +292 -27
  51. package/src/index.ts +38 -1
@@ -21,10 +21,34 @@ const checkboxVariants = tv({
21
21
  description: 'text-sm text-muted-foreground',
22
22
  },
23
23
  variants: {
24
+ variant: {
25
+ default: {},
26
+ /**
27
+ * The whole surface is the target — for pickable options where the
28
+ * checkbox is a confirmation rather than the affordance itself.
29
+ */
30
+ card: {
31
+ row: 'w-full items-start gap-3 rounded-xl border border-border bg-card p-4',
32
+ label: 'text-base font-medium',
33
+ },
34
+ },
35
+ checked: {
36
+ true: {},
37
+ },
24
38
  disabled: {
25
39
  true: { row: 'opacity-50' },
26
40
  },
27
41
  },
42
+ compoundVariants: [
43
+ {
44
+ variant: 'card',
45
+ checked: true,
46
+ class: { row: 'border-primary bg-accent' },
47
+ },
48
+ ],
49
+ defaultVariants: {
50
+ variant: 'default',
51
+ },
28
52
  });
29
53
 
30
54
  export interface CheckboxProps extends VariantProps<typeof checkboxVariants> {
@@ -39,9 +63,12 @@ export interface CheckboxProps extends VariantProps<typeof checkboxVariants> {
39
63
  }
40
64
 
41
65
  export const Checkbox = forwardRef<View, CheckboxProps>(
42
- ({ className, checked, onCheckedChange, disabled, label, description }, ref) => {
66
+ (
67
+ { className, checked, onCheckedChange, disabled, label, description, variant },
68
+ ref
69
+ ) => {
43
70
  const progress = useSharedValue(checked ? 1 : 0);
44
- const slots = checkboxVariants({ disabled: !!disabled });
71
+ const slots = checkboxVariants({ variant, checked, disabled: !!disabled });
45
72
  const checkColor = useCSSVariable('--color-primary-foreground');
46
73
 
47
74
  useEffect(() => {
@@ -55,6 +82,17 @@ export const Checkbox = forwardRef<View, CheckboxProps>(
55
82
  transform: [{ scale: 0.6 + progress.value * 0.4 }],
56
83
  }));
57
84
 
85
+ const box = (
86
+ <View className={slots.box()}>
87
+ <Animated.View style={fillStyle} className={slots.fill()}>
88
+ <CheckIcon
89
+ size={12}
90
+ color={typeof checkColor === 'string' ? checkColor : '#fff'}
91
+ />
92
+ </Animated.View>
93
+ </View>
94
+ );
95
+
58
96
  return (
59
97
  <Pressable
60
98
  ref={ref}
@@ -67,16 +105,15 @@ export const Checkbox = forwardRef<View, CheckboxProps>(
67
105
  hitSlop={8}
68
106
  // A description makes the row two lines tall — align the box to the
69
107
  // label rather than centring it against the whole block.
70
- className={slots.row({ className: description ? `items-start ${className ?? ''}` : className })}
108
+ className={slots.row({
109
+ className:
110
+ description && variant !== 'card'
111
+ ? `items-start ${className ?? ''}`
112
+ : className,
113
+ })}
71
114
  >
72
- <View className={slots.box()}>
73
- <Animated.View style={fillStyle} className={slots.fill()}>
74
- <CheckIcon
75
- size={12}
76
- color={typeof checkColor === 'string' ? checkColor : '#fff'}
77
- />
78
- </Animated.View>
79
- </View>
115
+ {/* The card lays out content first so the box sits top-right. */}
116
+ {variant === 'card' ? null : box}
80
117
  {label || description ? (
81
118
  <View className={slots.content()}>
82
119
  {label ? <Text className={slots.label()}>{label}</Text> : null}
@@ -85,6 +122,7 @@ export const Checkbox = forwardRef<View, CheckboxProps>(
85
122
  ) : null}
86
123
  </View>
87
124
  ) : null}
125
+ {variant === 'card' ? box : null}
88
126
  </Pressable>
89
127
  );
90
128
  }
@@ -1,5 +1,28 @@
1
- import { forwardRef } from 'react';
2
- import { View, type ViewProps } from 'react-native';
1
+ /**
2
+ * Frame — a widget shell: a titled surface wrapping an inset panel of rows,
3
+ * with an optional action on the header row and a caption underneath.
4
+ *
5
+ * Layout follows the nested-radius rule (inner radius = outer radius minus the
6
+ * gap between them), which is why the panel is `rounded-xl` inside a
7
+ * `rounded-2xl` shell. Since v0.4.0 the radius scale is theme-scoped, so this
8
+ * relationship holds while the absolute values change per theme.
9
+ *
10
+ * ```tsx
11
+ * <Frame>
12
+ * <Frame.Header>
13
+ * <Frame.Title>Usage Type</Frame.Title>
14
+ * <Frame.Action>Amount</Frame.Action>
15
+ * </Frame.Header>
16
+ * <Frame.Panel>
17
+ * <Frame.Row>…</Frame.Row>
18
+ * <Frame.Row divided>…</Frame.Row>
19
+ * </Frame.Panel>
20
+ * <Frame.Footer>Updated 2 minutes ago</Frame.Footer>
21
+ * </Frame>
22
+ * ```
23
+ */
24
+ import { forwardRef, type ReactNode } from 'react';
25
+ import { View, type Text as RNText, type ViewProps } from 'react-native';
3
26
  import { Text, type TextProps } from '../../primitives/text';
4
27
  import { cn } from '../../utils/cn';
5
28
 
@@ -7,39 +30,73 @@ export interface FrameProps extends ViewProps {
7
30
  className?: string;
8
31
  }
9
32
 
10
- /**
11
- * Grouping container (Coss UI's CardFrame): a tinted, rounded surface that
12
- * holds a header, one or more inset panels, and a footer. Use it to group
13
- * related settings or list sections under a single title.
14
- */
15
33
  const FrameRoot = forwardRef<View, FrameProps>(({ className, ...props }, ref) => (
16
34
  <View
17
35
  ref={ref}
18
- className={cn('gap-2 rounded-2xl border border-border bg-surface py-2', className)}
36
+ className={cn('rounded-2xl border border-border bg-surface p-1.5', className)}
19
37
  {...props}
20
38
  />
21
39
  ));
22
40
  FrameRoot.displayName = 'Frame';
23
41
 
24
- const FrameHeader = forwardRef<View, FrameProps>(({ className, ...props }, ref) => (
25
- <View ref={ref} className={cn('gap-1 px-5 py-2', className)} {...props} />
26
- ));
27
- FrameHeader.displayName = 'Frame.Header';
42
+ export interface FrameHeaderProps extends FrameProps {
43
+ children?: ReactNode;
44
+ }
28
45
 
29
- const FrameTitle = forwardRef<React.ElementRef<typeof Text>, TextProps>(
46
+ /**
47
+ * The header row: title on the left, `Frame.Action` on the right. Add
48
+ * `className="flex-col items-start"` when you want a description underneath.
49
+ */
50
+ const FrameHeader = forwardRef<View, FrameHeaderProps>(
30
51
  ({ className, ...props }, ref) => (
31
- <Text
52
+ <View
32
53
  ref={ref}
33
- size="base"
34
- weight="semibold"
35
- className={cn('text-foreground', className)}
54
+ className={cn(
55
+ 'flex-row items-center justify-between gap-3 px-3 pb-2.5 pt-2',
56
+ className
57
+ )}
36
58
  {...props}
37
59
  />
38
60
  )
39
61
  );
62
+ FrameHeader.displayName = 'Frame.Header';
63
+
64
+ const FrameTitle = forwardRef<RNText, TextProps>(({ className, ...props }, ref) => (
65
+ <Text
66
+ ref={ref}
67
+ size="base"
68
+ weight="medium"
69
+ className={cn('text-foreground', className)}
70
+ {...props}
71
+ />
72
+ ));
40
73
  FrameTitle.displayName = 'Frame.Title';
41
74
 
42
- const FrameDescription = forwardRef<React.ElementRef<typeof Text>, TextProps>(
75
+ export interface FrameActionProps extends FrameProps {
76
+ children?: ReactNode;
77
+ }
78
+
79
+ /**
80
+ * Trailing slot on the header row — a column label, a count, a button, a badge.
81
+ * Plain strings render as muted text; anything else renders as-is.
82
+ */
83
+ const FrameAction = forwardRef<View, FrameActionProps>(
84
+ ({ className, children, ...props }, ref) => (
85
+ <View ref={ref} className={cn('flex-row items-center gap-2', className)} {...props}>
86
+ {typeof children === 'string' ? (
87
+ <Text size="base" muted>
88
+ {children}
89
+ </Text>
90
+ ) : (
91
+ children
92
+ )}
93
+ </View>
94
+ )
95
+ );
96
+ FrameAction.displayName = 'Frame.Action';
97
+
98
+ /** Secondary line under the title, inside a column-wrapped header. */
99
+ const FrameDescription = forwardRef<RNText, TextProps>(
43
100
  ({ className, ...props }, ref) => (
44
101
  <Text ref={ref} size="sm" muted className={className} {...props} />
45
102
  )
@@ -47,16 +104,13 @@ const FrameDescription = forwardRef<React.ElementRef<typeof Text>, TextProps>(
47
104
  FrameDescription.displayName = 'Frame.Description';
48
105
 
49
106
  /**
50
- * An inset card surface inside a Frame — the raised panel that holds the
51
- * frame's actual content, sitting slightly in from the frame's edges.
107
+ * The inset card holding the frame's content — the raised surface sitting in
108
+ * from the shell's edges, with its own smaller radius.
52
109
  */
53
110
  const FramePanel = forwardRef<View, FrameProps>(({ className, ...props }, ref) => (
54
111
  <View
55
112
  ref={ref}
56
- className={cn(
57
- 'mx-1.5 overflow-hidden rounded-xl border border-border bg-card',
58
- className
59
- )}
113
+ className={cn('overflow-hidden rounded-xl border border-border bg-card', className)}
60
114
  {...props}
61
115
  />
62
116
  ));
@@ -85,18 +139,34 @@ const FrameRow = forwardRef<View, FrameRowProps>(
85
139
  );
86
140
  FrameRow.displayName = 'Frame.Row';
87
141
 
88
- const FrameFooter = forwardRef<View, FrameProps>(({ className, ...props }, ref) => (
89
- <View
90
- ref={ref}
91
- className={cn('flex-row items-center gap-2 px-5 py-2', className)}
92
- {...props}
93
- />
94
- ));
142
+ export interface FrameFooterProps extends FrameProps {
143
+ children?: ReactNode;
144
+ }
145
+
146
+ /** Muted caption under the panel. Strings are wrapped for you. */
147
+ const FrameFooter = forwardRef<View, FrameFooterProps>(
148
+ ({ className, children, ...props }, ref) => (
149
+ <View
150
+ ref={ref}
151
+ className={cn('flex-row items-center gap-2 px-3 pb-1.5 pt-2.5', className)}
152
+ {...props}
153
+ >
154
+ {typeof children === 'string' ? (
155
+ <Text size="sm" muted>
156
+ {children}
157
+ </Text>
158
+ ) : (
159
+ children
160
+ )}
161
+ </View>
162
+ )
163
+ );
95
164
  FrameFooter.displayName = 'Frame.Footer';
96
165
 
97
166
  export const Frame = Object.assign(FrameRoot, {
98
167
  Header: FrameHeader,
99
168
  Title: FrameTitle,
169
+ Action: FrameAction,
100
170
  Description: FrameDescription,
101
171
  Panel: FramePanel,
102
172
  Row: FrameRow,