panelui-native 0.6.0 → 0.9.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.
Files changed (181) hide show
  1. package/README.md +1 -1
  2. package/lib/module/components/accordion/index.js +7 -5
  3. package/lib/module/components/accordion/index.js.map +1 -1
  4. package/lib/module/components/alert/index.js +3 -6
  5. package/lib/module/components/alert/index.js.map +1 -1
  6. package/lib/module/components/attachment/index.js +219 -0
  7. package/lib/module/components/attachment/index.js.map +1 -0
  8. package/lib/module/components/bottom-sheet/index.js +82 -4
  9. package/lib/module/components/bottom-sheet/index.js.map +1 -1
  10. package/lib/module/components/button/index.js +36 -1
  11. package/lib/module/components/button/index.js.map +1 -1
  12. package/lib/module/components/dialog/index.js +6 -2
  13. package/lib/module/components/dialog/index.js.map +1 -1
  14. package/lib/module/components/empty-state/index.js +98 -22
  15. package/lib/module/components/empty-state/index.js.map +1 -1
  16. package/lib/module/components/inline-select/index.js +171 -46
  17. package/lib/module/components/inline-select/index.js.map +1 -1
  18. package/lib/module/components/input/index.js +28 -5
  19. package/lib/module/components/input/index.js.map +1 -1
  20. package/lib/module/components/input-group/index.js +0 -1
  21. package/lib/module/components/input-group/index.js.map +1 -1
  22. package/lib/module/components/item/index.js +359 -0
  23. package/lib/module/components/item/index.js.map +1 -0
  24. package/lib/module/components/label/index.js +5 -3
  25. package/lib/module/components/label/index.js.map +1 -1
  26. package/lib/module/components/line-chart/index.js +1024 -0
  27. package/lib/module/components/line-chart/index.js.map +1 -0
  28. package/lib/module/components/marker/index.js +190 -0
  29. package/lib/module/components/marker/index.js.map +1 -0
  30. package/lib/module/components/message/index.js +334 -0
  31. package/lib/module/components/message/index.js.map +1 -0
  32. package/lib/module/components/message-scroller/index.js +451 -0
  33. package/lib/module/components/message-scroller/index.js.map +1 -0
  34. package/lib/module/components/popover/index.js +500 -0
  35. package/lib/module/components/popover/index.js.map +1 -0
  36. package/lib/module/components/radio-group/index.js +104 -16
  37. package/lib/module/components/radio-group/index.js.map +1 -1
  38. package/lib/module/components/scroll-fade/index.js +119 -71
  39. package/lib/module/components/scroll-fade/index.js.map +1 -1
  40. package/lib/module/components/select/index.js +35 -6
  41. package/lib/module/components/select/index.js.map +1 -1
  42. package/lib/module/components/separator/index.js +91 -0
  43. package/lib/module/components/separator/index.js.map +1 -0
  44. package/lib/module/components/shimmer/index.js +111 -64
  45. package/lib/module/components/shimmer/index.js.map +1 -1
  46. package/lib/module/components/surface/index.js +24 -4
  47. package/lib/module/components/surface/index.js.map +1 -1
  48. package/lib/module/components/switch/index.js +20 -1
  49. package/lib/module/components/switch/index.js.map +1 -1
  50. package/lib/module/components/toast/index.js +7 -8
  51. package/lib/module/components/toast/index.js.map +1 -1
  52. package/lib/module/components/typography/index.js +3 -3
  53. package/lib/module/hooks/index.js +1 -0
  54. package/lib/module/hooks/index.js.map +1 -1
  55. package/lib/module/hooks/use-breakpoint.js +2 -2
  56. package/lib/module/hooks/use-copy-to-clipboard.js +0 -2
  57. package/lib/module/hooks/use-copy-to-clipboard.js.map +1 -1
  58. package/lib/module/hooks/use-keyboard-avoidance.js +120 -0
  59. package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -0
  60. package/lib/module/icons/index.js +73 -4
  61. package/lib/module/icons/index.js.map +1 -1
  62. package/lib/module/index.js +13 -1
  63. package/lib/module/index.js.map +1 -1
  64. package/lib/module/native/index.js +53 -0
  65. package/lib/module/native/index.js.map +1 -0
  66. package/lib/module/primitives/keyboard-avoider.js +40 -0
  67. package/lib/module/primitives/keyboard-avoider.js.map +1 -0
  68. package/lib/module/primitives/scrim.js +72 -0
  69. package/lib/module/primitives/scrim.js.map +1 -0
  70. package/lib/module/providers/panel-ui-provider.js +24 -4
  71. package/lib/module/providers/panel-ui-provider.js.map +1 -1
  72. package/lib/module/theme/use-theme.js +1 -1
  73. package/lib/typescript/src/components/accordion/index.d.ts +7 -5
  74. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
  75. package/lib/typescript/src/components/alert/index.d.ts +3 -6
  76. package/lib/typescript/src/components/alert/index.d.ts.map +1 -1
  77. package/lib/typescript/src/components/attachment/index.d.ts +93 -0
  78. package/lib/typescript/src/components/attachment/index.d.ts.map +1 -0
  79. package/lib/typescript/src/components/bottom-sheet/index.d.ts +27 -2
  80. package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
  81. package/lib/typescript/src/components/button/index.d.ts +11 -0
  82. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  83. package/lib/typescript/src/components/dialog/index.d.ts +7 -1
  84. package/lib/typescript/src/components/dialog/index.d.ts.map +1 -1
  85. package/lib/typescript/src/components/empty-state/index.d.ts +156 -7
  86. package/lib/typescript/src/components/empty-state/index.d.ts.map +1 -1
  87. package/lib/typescript/src/components/inline-select/index.d.ts +29 -6
  88. package/lib/typescript/src/components/inline-select/index.d.ts.map +1 -1
  89. package/lib/typescript/src/components/input/index.d.ts +13 -0
  90. package/lib/typescript/src/components/input/index.d.ts.map +1 -1
  91. package/lib/typescript/src/components/input-group/index.d.ts +0 -1
  92. package/lib/typescript/src/components/input-group/index.d.ts.map +1 -1
  93. package/lib/typescript/src/components/item/index.d.ts +286 -0
  94. package/lib/typescript/src/components/item/index.d.ts.map +1 -0
  95. package/lib/typescript/src/components/label/index.d.ts +5 -3
  96. package/lib/typescript/src/components/label/index.d.ts.map +1 -1
  97. package/lib/typescript/src/components/line-chart/index.d.ts +247 -0
  98. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -0
  99. package/lib/typescript/src/components/marker/index.d.ts +137 -0
  100. package/lib/typescript/src/components/marker/index.d.ts.map +1 -0
  101. package/lib/typescript/src/components/message/index.d.ts +177 -0
  102. package/lib/typescript/src/components/message/index.d.ts.map +1 -0
  103. package/lib/typescript/src/components/message-scroller/index.d.ts +150 -0
  104. package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -0
  105. package/lib/typescript/src/components/popover/index.d.ts +130 -0
  106. package/lib/typescript/src/components/popover/index.d.ts.map +1 -0
  107. package/lib/typescript/src/components/radio-group/index.d.ts +32 -0
  108. package/lib/typescript/src/components/radio-group/index.d.ts.map +1 -1
  109. package/lib/typescript/src/components/scroll-fade/index.d.ts +18 -9
  110. package/lib/typescript/src/components/scroll-fade/index.d.ts.map +1 -1
  111. package/lib/typescript/src/components/select/index.d.ts +16 -1
  112. package/lib/typescript/src/components/select/index.d.ts.map +1 -1
  113. package/lib/typescript/src/components/separator/index.d.ts +47 -0
  114. package/lib/typescript/src/components/separator/index.d.ts.map +1 -0
  115. package/lib/typescript/src/components/shimmer/index.d.ts +38 -20
  116. package/lib/typescript/src/components/shimmer/index.d.ts.map +1 -1
  117. package/lib/typescript/src/components/surface/index.d.ts +51 -2
  118. package/lib/typescript/src/components/surface/index.d.ts.map +1 -1
  119. package/lib/typescript/src/components/switch/index.d.ts +10 -0
  120. package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
  121. package/lib/typescript/src/components/toast/index.d.ts +4 -4
  122. package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
  123. package/lib/typescript/src/hooks/index.d.ts +1 -0
  124. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  125. package/lib/typescript/src/hooks/use-breakpoint.d.ts +2 -2
  126. package/lib/typescript/src/hooks/use-copy-to-clipboard.d.ts +0 -2
  127. package/lib/typescript/src/hooks/use-copy-to-clipboard.d.ts.map +1 -1
  128. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts +20 -0
  129. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -0
  130. package/lib/typescript/src/icons/index.d.ts +10 -4
  131. package/lib/typescript/src/icons/index.d.ts.map +1 -1
  132. package/lib/typescript/src/index.d.ts +11 -1
  133. package/lib/typescript/src/index.d.ts.map +1 -1
  134. package/lib/typescript/src/native/index.d.ts +35 -0
  135. package/lib/typescript/src/native/index.d.ts.map +1 -0
  136. package/lib/typescript/src/primitives/keyboard-avoider.d.ts +22 -0
  137. package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -0
  138. package/lib/typescript/src/primitives/scrim.d.ts +21 -0
  139. package/lib/typescript/src/primitives/scrim.d.ts.map +1 -0
  140. package/lib/typescript/src/providers/panel-ui-provider.d.ts +1 -1
  141. package/lib/typescript/src/providers/panel-ui-provider.d.ts.map +1 -1
  142. package/lib/typescript/src/theme/use-theme.d.ts +1 -1
  143. package/package.json +16 -3
  144. package/src/components/accordion/index.tsx +7 -5
  145. package/src/components/alert/index.tsx +3 -6
  146. package/src/components/attachment/index.tsx +279 -0
  147. package/src/components/bottom-sheet/index.tsx +102 -2
  148. package/src/components/button/index.tsx +52 -0
  149. package/src/components/dialog/index.tsx +10 -1
  150. package/src/components/empty-state/index.tsx +64 -19
  151. package/src/components/inline-select/index.tsx +191 -44
  152. package/src/components/input/index.tsx +39 -3
  153. package/src/components/input-group/index.tsx +0 -1
  154. package/src/components/item/index.tsx +387 -0
  155. package/src/components/label/index.tsx +5 -3
  156. package/src/components/line-chart/index.tsx +1224 -0
  157. package/src/components/marker/index.tsx +194 -0
  158. package/src/components/message/index.tsx +336 -0
  159. package/src/components/message-scroller/index.tsx +574 -0
  160. package/src/components/popover/index.tsx +599 -0
  161. package/src/components/radio-group/index.tsx +108 -17
  162. package/src/components/scroll-fade/index.tsx +163 -51
  163. package/src/components/select/index.tsx +54 -9
  164. package/src/components/separator/index.tsx +97 -0
  165. package/src/components/shimmer/index.tsx +151 -58
  166. package/src/components/surface/index.tsx +32 -5
  167. package/src/components/switch/index.tsx +27 -1
  168. package/src/components/toast/index.tsx +7 -8
  169. package/src/components/typography/index.tsx +3 -3
  170. package/src/hooks/index.ts +5 -0
  171. package/src/hooks/use-breakpoint.ts +2 -2
  172. package/src/hooks/use-copy-to-clipboard.ts +0 -2
  173. package/src/hooks/use-keyboard-avoidance.ts +140 -0
  174. package/src/icons/index.tsx +52 -4
  175. package/src/index.ts +92 -0
  176. package/src/native/index.ts +79 -0
  177. package/src/primitives/keyboard-avoider.tsx +49 -0
  178. package/src/primitives/scrim.tsx +95 -0
  179. package/src/providers/panel-ui-provider.tsx +30 -9
  180. package/src/theme/use-theme.ts +1 -1
  181. package/theme.css +63 -3
@@ -0,0 +1,387 @@
1
+ /**
2
+ * Item — a row of content: media on one side, a title and description in the
3
+ * middle, actions on the other side.
4
+ *
5
+ * It is the shape almost every list in an app already has — a settings row, a
6
+ * file in a picker, a member in a team list, a tool call in a transcript — so
7
+ * it exists as one composable primitive rather than being rebuilt per screen
8
+ * with slightly different padding each time.
9
+ *
10
+ * ```tsx
11
+ * <Item variant="outline">
12
+ * <Item.Media variant="icon"><ReceiptIcon /></Item.Media>
13
+ * <Item.Content>
14
+ * <Item.Title>Invoice.pdf</Item.Title>
15
+ * <Item.Description>2.4 MB · Updated yesterday</Item.Description>
16
+ * </Item.Content>
17
+ * <Item.Actions><Button size="sm">Open</Button></Item.Actions>
18
+ * </Item>
19
+ * ```
20
+ *
21
+ * Two axes, and they are independent. `orientation` on the item decides
22
+ * whether its own parts sit side by side or stack into a card; `orientation`
23
+ * on `Item.Group` decides whether the items themselves run down the screen or
24
+ * across it. A carousel wants both set to the non-default: a horizontal group
25
+ * of vertical items.
26
+ */
27
+ import { createContext, forwardRef, useContext, type ReactNode } from 'react';
28
+ import { View, type ViewProps } from 'react-native';
29
+ import { tv, type VariantProps } from 'tailwind-variants';
30
+ import { AnimatedPressable, type AnimatedPressableProps } from '../../primitives/animated-pressable';
31
+ import { Text, type TextProps } from '../../primitives/text';
32
+ import { cn } from '../../utils/cn';
33
+
34
+ type ItemSize = 'default' | 'sm' | 'xs';
35
+ type ItemOrientation = 'horizontal' | 'vertical';
36
+
37
+ const itemVariants = tv({
38
+ slots: {
39
+ root: 'gap-3 rounded-xl',
40
+ title: 'font-medium text-foreground',
41
+ description: 'text-muted-foreground',
42
+ },
43
+ variants: {
44
+ variant: {
45
+ default: {},
46
+ outline: { root: 'border border-border' },
47
+ muted: { root: 'bg-muted' },
48
+ },
49
+ size: {
50
+ default: { root: 'p-4', title: 'text-base', description: 'text-sm' },
51
+ sm: { root: 'p-3', title: 'text-sm', description: 'text-xs' },
52
+ xs: { root: 'gap-2 p-2', title: 'text-sm', description: 'text-xs' },
53
+ },
54
+ orientation: {
55
+ /** Media, text and actions side by side — the list-row shape. */
56
+ horizontal: { root: 'w-full flex-row items-center' },
57
+ /** Stacked into a card — the shape a horizontal carousel wants. */
58
+ vertical: { root: 'flex-col items-start' },
59
+ },
60
+ disabled: {
61
+ true: { root: 'opacity-[0.64]' },
62
+ },
63
+ },
64
+ defaultVariants: {
65
+ variant: 'default',
66
+ size: 'default',
67
+ orientation: 'horizontal',
68
+ },
69
+ });
70
+
71
+ /** Sub-components inherit the row's density and axis rather than repeating them. */
72
+ const ItemContext = createContext<{ size: ItemSize; orientation: ItemOrientation }>({
73
+ size: 'default',
74
+ orientation: 'horizontal',
75
+ });
76
+
77
+ const mediaVariants = tv({
78
+ base: 'shrink-0 items-center justify-center',
79
+ variants: {
80
+ variant: {
81
+ /** No box — for an Avatar or anything that styles itself. */
82
+ default: '',
83
+ /** Rounded square tile sized for an icon. */
84
+ icon: 'rounded-lg border border-border bg-muted',
85
+ /** Clipped frame for an image or thumbnail. */
86
+ image: 'overflow-hidden rounded-lg bg-muted',
87
+ },
88
+ size: {
89
+ default: '',
90
+ sm: '',
91
+ xs: '',
92
+ },
93
+ },
94
+ compoundVariants: [
95
+ { variant: 'icon', size: 'default', class: 'h-10 w-10' },
96
+ { variant: 'icon', size: 'sm', class: 'h-8 w-8' },
97
+ { variant: 'icon', size: 'xs', class: 'h-6 w-6' },
98
+ { variant: 'image', size: 'default', class: 'h-12 w-12' },
99
+ { variant: 'image', size: 'sm', class: 'h-10 w-10' },
100
+ { variant: 'image', size: 'xs', class: 'h-8 w-8' },
101
+ ],
102
+ defaultVariants: {
103
+ variant: 'default',
104
+ size: 'default',
105
+ },
106
+ });
107
+
108
+ export interface ItemProps
109
+ extends Omit<AnimatedPressableProps, 'children' | 'disabled'>,
110
+ Omit<VariantProps<typeof itemVariants>, 'disabled'> {
111
+ className?: string;
112
+ disabled?: boolean;
113
+ /**
114
+ * Row density. `Item.Media`, `Item.Title` and `Item.Description` follow it,
115
+ * so it only needs setting here.
116
+ */
117
+ size?: ItemSize;
118
+ /**
119
+ * `horizontal` is the list row: media, text and actions side by side.
120
+ * `vertical` stacks them into a card, which is what a horizontal carousel
121
+ * wants — and it is also what `Item.Header` and `Item.Footer` need, since
122
+ * both are full-width strips.
123
+ */
124
+ orientation?: ItemOrientation;
125
+ children?: ReactNode;
126
+ }
127
+
128
+ /**
129
+ * Renders as a pressable when given `onPress`, and as a plain view otherwise,
130
+ * so a static row does not announce itself as a button.
131
+ */
132
+ const ItemRoot = forwardRef<View, ItemProps>(
133
+ (
134
+ {
135
+ className,
136
+ variant,
137
+ size = 'default',
138
+ orientation = 'horizontal',
139
+ disabled,
140
+ children,
141
+ onPress,
142
+ ...props
143
+ },
144
+ ref
145
+ ) => {
146
+ const { root } = itemVariants({ variant, size, orientation, disabled: !!disabled });
147
+
148
+ const body = !onPress ? (
149
+ <View
150
+ ref={ref}
151
+ accessibilityState={{ disabled: !!disabled }}
152
+ className={root({ className })}
153
+ {...(props as ViewProps)}
154
+ >
155
+ {children}
156
+ </View>
157
+ ) : (
158
+ <AnimatedPressable
159
+ ref={ref}
160
+ accessibilityRole="button"
161
+ accessibilityState={{ disabled: !!disabled }}
162
+ disabled={disabled}
163
+ onPress={onPress}
164
+ className={root({ className })}
165
+ {...props}
166
+ >
167
+ {children}
168
+ </AnimatedPressable>
169
+ );
170
+
171
+ return (
172
+ <ItemContext.Provider value={{ size, orientation }}>{body}</ItemContext.Provider>
173
+ );
174
+ }
175
+ );
176
+ ItemRoot.displayName = 'Item';
177
+
178
+ export interface ItemGroupProps extends ViewProps {
179
+ className?: string;
180
+ /**
181
+ * `vertical` stacks the items — the settings-list shape. `horizontal` runs
182
+ * them across instead, for a carousel; pair it with a scrollable and
183
+ * `orientation="vertical"` on each item so every entry reads as a card.
184
+ */
185
+ orientation?: ItemOrientation;
186
+ children?: ReactNode;
187
+ }
188
+
189
+ /** Stack of items. Pair with `Item.Separator` between them. */
190
+ const ItemGroup = forwardRef<View, ItemGroupProps>(
191
+ ({ className, orientation = 'vertical', children, ...props }, ref) => (
192
+ <View
193
+ ref={ref}
194
+ accessibilityRole="list"
195
+ className={cn(
196
+ orientation === 'horizontal'
197
+ ? 'flex-row items-stretch gap-3'
198
+ : 'w-full',
199
+ className
200
+ )}
201
+ {...props}
202
+ >
203
+ {children}
204
+ </View>
205
+ )
206
+ );
207
+ ItemGroup.displayName = 'Item.Group';
208
+
209
+ export interface ItemSeparatorProps extends ViewProps {
210
+ className?: string;
211
+ /** Match the group's axis: a horizontal group needs vertical hairlines. */
212
+ orientation?: ItemOrientation;
213
+ }
214
+
215
+ /** Hairline between rows in a group. */
216
+ const ItemSeparator = forwardRef<View, ItemSeparatorProps>(
217
+ ({ className, orientation = 'vertical', ...props }, ref) => (
218
+ <View
219
+ ref={ref}
220
+ className={cn(
221
+ orientation === 'horizontal' ? 'h-full w-px' : 'h-px w-full',
222
+ 'bg-border',
223
+ className
224
+ )}
225
+ {...props}
226
+ />
227
+ )
228
+ );
229
+ ItemSeparator.displayName = 'Item.Separator';
230
+
231
+ export interface ItemMediaProps
232
+ extends ViewProps,
233
+ VariantProps<typeof mediaVariants> {
234
+ className?: string;
235
+ children?: ReactNode;
236
+ }
237
+
238
+ /** Leading slot: an icon tile, a thumbnail, or an avatar passed through. */
239
+ const ItemMedia = forwardRef<View, ItemMediaProps>(
240
+ ({ className, variant, size, children, ...props }, ref) => {
241
+ const item = useContext(ItemContext);
242
+
243
+ return (
244
+ <View
245
+ ref={ref}
246
+ className={mediaVariants({ variant, size: size ?? item.size, className })}
247
+ {...props}
248
+ >
249
+ {children}
250
+ </View>
251
+ );
252
+ }
253
+ );
254
+ ItemMedia.displayName = 'Item.Media';
255
+
256
+ export interface ItemContentProps extends ViewProps {
257
+ className?: string;
258
+ children?: ReactNode;
259
+ }
260
+
261
+ /**
262
+ * The text column. In a horizontal item it takes the remaining width so the
263
+ * actions stay pinned to the trailing edge; in a vertical one it just fills
264
+ * the width, because there is nothing beside it to push against.
265
+ */
266
+ const ItemContent = forwardRef<View, ItemContentProps>(
267
+ ({ className, children, ...props }, ref) => {
268
+ const { orientation } = useContext(ItemContext);
269
+
270
+ return (
271
+ <View
272
+ ref={ref}
273
+ className={cn(
274
+ orientation === 'horizontal' ? 'flex-1' : 'w-full',
275
+ 'gap-0.5',
276
+ className
277
+ )}
278
+ {...props}
279
+ >
280
+ {children}
281
+ </View>
282
+ );
283
+ }
284
+ );
285
+ ItemContent.displayName = 'Item.Content';
286
+
287
+ export interface ItemTitleProps extends TextProps {
288
+ className?: string;
289
+ }
290
+
291
+ const ItemTitle = forwardRef<React.ElementRef<typeof Text>, ItemTitleProps>(
292
+ ({ className, ...props }, ref) => {
293
+ const { size } = useContext(ItemContext);
294
+ const { title } = itemVariants({ size });
295
+
296
+ return <Text ref={ref} className={title({ className })} {...props} />;
297
+ }
298
+ );
299
+ ItemTitle.displayName = 'Item.Title';
300
+
301
+ export interface ItemDescriptionProps extends TextProps {
302
+ className?: string;
303
+ }
304
+
305
+ const ItemDescription = forwardRef<
306
+ React.ElementRef<typeof Text>,
307
+ ItemDescriptionProps
308
+ >(({ className, ...props }, ref) => {
309
+ const { size } = useContext(ItemContext);
310
+ const { description } = itemVariants({ size });
311
+
312
+ return <Text ref={ref} className={description({ className })} {...props} />;
313
+ });
314
+ ItemDescription.displayName = 'Item.Description';
315
+
316
+ export interface ItemActionsProps extends ViewProps {
317
+ className?: string;
318
+ children?: ReactNode;
319
+ }
320
+
321
+ /** Trailing slot: buttons, a chevron, a switch. */
322
+ const ItemActions = forwardRef<View, ItemActionsProps>(
323
+ ({ className, children, ...props }, ref) => (
324
+ <View
325
+ ref={ref}
326
+ className={cn('shrink-0 flex-row items-center gap-1.5', className)}
327
+ {...props}
328
+ >
329
+ {children}
330
+ </View>
331
+ )
332
+ );
333
+ ItemActions.displayName = 'Item.Actions';
334
+
335
+ export interface ItemHeaderProps extends ViewProps {
336
+ className?: string;
337
+ children?: ReactNode;
338
+ }
339
+
340
+ /**
341
+ * Full-width strip above the item's main content — an eyebrow label, a badge
342
+ * row. Needs `orientation="vertical"` on the item, since a strip only makes
343
+ * sense once the item stacks.
344
+ */
345
+ const ItemHeader = forwardRef<View, ItemHeaderProps>(
346
+ ({ className, children, ...props }, ref) => (
347
+ <View
348
+ ref={ref}
349
+ className={cn('w-full flex-row items-center justify-between gap-2', className)}
350
+ {...props}
351
+ >
352
+ {children}
353
+ </View>
354
+ )
355
+ );
356
+ ItemHeader.displayName = 'Item.Header';
357
+
358
+ export interface ItemFooterProps extends ViewProps {
359
+ className?: string;
360
+ children?: ReactNode;
361
+ }
362
+
363
+ /** Full-width strip below the row's main content. */
364
+ const ItemFooter = forwardRef<View, ItemFooterProps>(
365
+ ({ className, children, ...props }, ref) => (
366
+ <View
367
+ ref={ref}
368
+ className={cn('w-full flex-row items-center gap-2', className)}
369
+ {...props}
370
+ >
371
+ {children}
372
+ </View>
373
+ )
374
+ );
375
+ ItemFooter.displayName = 'Item.Footer';
376
+
377
+ export const Item = Object.assign(ItemRoot, {
378
+ Group: ItemGroup,
379
+ Separator: ItemSeparator,
380
+ Media: ItemMedia,
381
+ Content: ItemContent,
382
+ Title: ItemTitle,
383
+ Description: ItemDescription,
384
+ Actions: ItemActions,
385
+ Header: ItemHeader,
386
+ Footer: ItemFooter,
387
+ });
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * Label — text that names a form field.
3
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).
4
+ * A string child is wrapped in `Label.Text` automatically, so the common case
5
+ * stays one line; pass the parts explicitly when the label needs more than
6
+ * text. `isRequired`, `isInvalid` and `isDisabled` are visual *and* semantic —
7
+ * they recolour and they set the accessibility state, so the two cannot drift
8
+ * apart.
7
9
  */
8
10
  import {
9
11
  createContext,