panelui-native 0.7.0 → 0.12.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 (161) hide show
  1. package/README.md +5 -3
  2. package/lib/module/components/attachment/index.js +219 -0
  3. package/lib/module/components/attachment/index.js.map +1 -0
  4. package/lib/module/components/bottom-sheet/index.js +53 -3
  5. package/lib/module/components/bottom-sheet/index.js.map +1 -1
  6. package/lib/module/components/button/index.js +19 -1
  7. package/lib/module/components/button/index.js.map +1 -1
  8. package/lib/module/components/dialog/index.js +6 -2
  9. package/lib/module/components/dialog/index.js.map +1 -1
  10. package/lib/module/components/empty-state/index.js +94 -17
  11. package/lib/module/components/empty-state/index.js.map +1 -1
  12. package/lib/module/components/frame/index.js +128 -15
  13. package/lib/module/components/frame/index.js.map +1 -1
  14. package/lib/module/components/input/index.js +107 -15
  15. package/lib/module/components/input/index.js.map +1 -1
  16. package/lib/module/components/line-chart/index.js +1024 -0
  17. package/lib/module/components/line-chart/index.js.map +1 -0
  18. package/lib/module/components/marker/index.js +190 -0
  19. package/lib/module/components/marker/index.js.map +1 -0
  20. package/lib/module/components/message/index.js +24 -8
  21. package/lib/module/components/message/index.js.map +1 -1
  22. package/lib/module/components/message-scroller/index.js +451 -0
  23. package/lib/module/components/message-scroller/index.js.map +1 -0
  24. package/lib/module/components/popover/index.js +511 -0
  25. package/lib/module/components/popover/index.js.map +1 -0
  26. package/lib/module/components/progress/index.js +52 -2
  27. package/lib/module/components/progress/index.js.map +1 -1
  28. package/lib/module/components/radio-group/index.js +132 -17
  29. package/lib/module/components/radio-group/index.js.map +1 -1
  30. package/lib/module/components/section-rail/index.js +355 -0
  31. package/lib/module/components/section-rail/index.js.map +1 -0
  32. package/lib/module/components/select/index.js +245 -56
  33. package/lib/module/components/select/index.js.map +1 -1
  34. package/lib/module/components/separator/index.js +91 -0
  35. package/lib/module/components/separator/index.js.map +1 -0
  36. package/lib/module/components/slider/index.js +355 -0
  37. package/lib/module/components/slider/index.js.map +1 -0
  38. package/lib/module/components/surface/index.js +21 -2
  39. package/lib/module/components/surface/index.js.map +1 -1
  40. package/lib/module/components/switch/index.js +10 -1
  41. package/lib/module/components/switch/index.js.map +1 -1
  42. package/lib/module/components/tabs/index.js +186 -16
  43. package/lib/module/components/tabs/index.js.map +1 -1
  44. package/lib/module/components/toggle-button/index.js +297 -0
  45. package/lib/module/components/toggle-button/index.js.map +1 -0
  46. package/lib/module/hooks/index.js +1 -0
  47. package/lib/module/hooks/index.js.map +1 -1
  48. package/lib/module/hooks/use-keyboard-avoidance.js +57 -8
  49. package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -1
  50. package/lib/module/hooks/use-scroll-sections.js +89 -0
  51. package/lib/module/hooks/use-scroll-sections.js.map +1 -0
  52. package/lib/module/icons/index.js +69 -0
  53. package/lib/module/icons/index.js.map +1 -1
  54. package/lib/module/index.js +11 -2
  55. package/lib/module/index.js.map +1 -1
  56. package/lib/module/native/index.js.map +1 -1
  57. package/lib/module/primitives/keyboard-avoider.js +2 -0
  58. package/lib/module/primitives/keyboard-avoider.js.map +1 -1
  59. package/lib/module/primitives/scrim.js +72 -0
  60. package/lib/module/primitives/scrim.js.map +1 -0
  61. package/lib/module/utils/haptics.js +57 -0
  62. package/lib/module/utils/haptics.js.map +1 -0
  63. package/lib/typescript/src/components/attachment/index.d.ts +93 -0
  64. package/lib/typescript/src/components/attachment/index.d.ts.map +1 -0
  65. package/lib/typescript/src/components/bottom-sheet/index.d.ts +6 -1
  66. package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
  67. package/lib/typescript/src/components/button/index.d.ts +9 -4
  68. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  69. package/lib/typescript/src/components/dialog/index.d.ts +7 -1
  70. package/lib/typescript/src/components/dialog/index.d.ts.map +1 -1
  71. package/lib/typescript/src/components/empty-state/index.d.ts +152 -2
  72. package/lib/typescript/src/components/empty-state/index.d.ts.map +1 -1
  73. package/lib/typescript/src/components/frame/index.d.ts +47 -7
  74. package/lib/typescript/src/components/frame/index.d.ts.map +1 -1
  75. package/lib/typescript/src/components/input/index.d.ts +113 -2
  76. package/lib/typescript/src/components/input/index.d.ts.map +1 -1
  77. package/lib/typescript/src/components/line-chart/index.d.ts +247 -0
  78. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -0
  79. package/lib/typescript/src/components/marker/index.d.ts +137 -0
  80. package/lib/typescript/src/components/marker/index.d.ts.map +1 -0
  81. package/lib/typescript/src/components/message/index.d.ts +8 -1
  82. package/lib/typescript/src/components/message/index.d.ts.map +1 -1
  83. package/lib/typescript/src/components/message-scroller/index.d.ts +150 -0
  84. package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -0
  85. package/lib/typescript/src/components/popover/index.d.ts +136 -0
  86. package/lib/typescript/src/components/popover/index.d.ts.map +1 -0
  87. package/lib/typescript/src/components/progress/index.d.ts +33 -0
  88. package/lib/typescript/src/components/progress/index.d.ts.map +1 -1
  89. package/lib/typescript/src/components/radio-group/index.d.ts +39 -0
  90. package/lib/typescript/src/components/radio-group/index.d.ts.map +1 -1
  91. package/lib/typescript/src/components/section-rail/index.d.ts +115 -0
  92. package/lib/typescript/src/components/section-rail/index.d.ts.map +1 -0
  93. package/lib/typescript/src/components/select/index.d.ts +46 -7
  94. package/lib/typescript/src/components/select/index.d.ts.map +1 -1
  95. package/lib/typescript/src/components/separator/index.d.ts +47 -0
  96. package/lib/typescript/src/components/separator/index.d.ts.map +1 -0
  97. package/lib/typescript/src/components/slider/index.d.ts +203 -0
  98. package/lib/typescript/src/components/slider/index.d.ts.map +1 -0
  99. package/lib/typescript/src/components/surface/index.d.ts +51 -2
  100. package/lib/typescript/src/components/surface/index.d.ts.map +1 -1
  101. package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
  102. package/lib/typescript/src/components/tabs/index.d.ts +46 -4
  103. package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
  104. package/lib/typescript/src/components/toggle-button/index.d.ts +244 -0
  105. package/lib/typescript/src/components/toggle-button/index.d.ts.map +1 -0
  106. package/lib/typescript/src/hooks/index.d.ts +1 -0
  107. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  108. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts +10 -1
  109. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -1
  110. package/lib/typescript/src/hooks/use-scroll-sections.d.ts +31 -0
  111. package/lib/typescript/src/hooks/use-scroll-sections.d.ts.map +1 -0
  112. package/lib/typescript/src/icons/index.d.ts +6 -0
  113. package/lib/typescript/src/icons/index.d.ts.map +1 -1
  114. package/lib/typescript/src/index.d.ts +13 -4
  115. package/lib/typescript/src/index.d.ts.map +1 -1
  116. package/lib/typescript/src/native/index.d.ts +16 -1
  117. package/lib/typescript/src/native/index.d.ts.map +1 -1
  118. package/lib/typescript/src/primitives/keyboard-avoider.d.ts +8 -1
  119. package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -1
  120. package/lib/typescript/src/primitives/scrim.d.ts +21 -0
  121. package/lib/typescript/src/primitives/scrim.d.ts.map +1 -0
  122. package/lib/typescript/src/utils/haptics.d.ts +12 -0
  123. package/lib/typescript/src/utils/haptics.d.ts.map +1 -0
  124. package/package.json +9 -1
  125. package/src/components/attachment/index.tsx +279 -0
  126. package/src/components/bottom-sheet/index.tsx +58 -2
  127. package/src/components/button/index.tsx +26 -5
  128. package/src/components/dialog/index.tsx +10 -1
  129. package/src/components/empty-state/index.tsx +60 -14
  130. package/src/components/frame/index.tsx +175 -29
  131. package/src/components/input/index.tsx +122 -16
  132. package/src/components/line-chart/index.tsx +1224 -0
  133. package/src/components/marker/index.tsx +194 -0
  134. package/src/components/message/index.tsx +29 -5
  135. package/src/components/message-scroller/index.tsx +574 -0
  136. package/src/components/popover/index.tsx +624 -0
  137. package/src/components/progress/index.tsx +81 -1
  138. package/src/components/radio-group/index.tsx +156 -18
  139. package/src/components/section-rail/index.tsx +459 -0
  140. package/src/components/select/index.tsx +265 -52
  141. package/src/components/separator/index.tsx +97 -0
  142. package/src/components/slider/index.tsx +371 -0
  143. package/src/components/surface/index.tsx +29 -3
  144. package/src/components/switch/index.tsx +8 -1
  145. package/src/components/tabs/index.tsx +208 -28
  146. package/src/components/toggle-button/index.tsx +374 -0
  147. package/src/hooks/index.ts +5 -0
  148. package/src/hooks/use-keyboard-avoidance.ts +73 -7
  149. package/src/hooks/use-scroll-sections.ts +127 -0
  150. package/src/icons/index.tsx +48 -0
  151. package/src/index.ts +97 -6
  152. package/src/native/index.ts +13 -1
  153. package/src/primitives/keyboard-avoider.tsx +9 -1
  154. package/src/primitives/scrim.tsx +95 -0
  155. package/src/utils/haptics.ts +63 -0
  156. package/theme.css +64 -2
  157. package/lib/module/components/inline-select/index.js +0 -284
  158. package/lib/module/components/inline-select/index.js.map +0 -1
  159. package/lib/typescript/src/components/inline-select/index.d.ts +0 -48
  160. package/lib/typescript/src/components/inline-select/index.d.ts.map +0 -1
  161. package/src/components/inline-select/index.tsx +0 -332
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Marker — an inline note in a conversation.
3
+ *
4
+ * Transcripts are not only messages. Between the turns sit things the
5
+ * conversation did rather than said: a tool that ran, a file that was read, a
6
+ * model that changed, the point where yesterday ended. Those are not messages
7
+ * and should not look like one — a bubble implies a speaker, and none of these
8
+ * have one. A marker is the quieter row that carries them: small, muted, and
9
+ * aligned to the transcript rather than to a side of it.
10
+ *
11
+ * ```tsx
12
+ * <Marker>
13
+ * <Marker.Icon><CheckIcon /></Marker.Icon>
14
+ * <Marker.Content>Explored 4 files</Marker.Content>
15
+ * </Marker>
16
+ * ```
17
+ *
18
+ * `shimmer` on the content is for the row that is still happening — the sweep
19
+ * runs through the glyphs while a step is in flight, and is dropped the moment
20
+ * it finishes.
21
+ */
22
+ import { createContext, forwardRef, useContext, type ReactNode } from 'react';
23
+ import { View, type Text as RNText, type ViewProps } from 'react-native';
24
+ import { tv, type VariantProps } from 'tailwind-variants';
25
+ import { useCSSVariable } from 'uniwind';
26
+ import { IconColorProvider } from '../../icons';
27
+ import { AnimatedPressable, type AnimatedPressableProps } from '../../primitives/animated-pressable';
28
+ import { Text, type TextProps } from '../../primitives/text';
29
+ import { cn } from '../../utils/cn';
30
+ import { Separator } from '../separator';
31
+ import { Shimmer } from '../shimmer';
32
+
33
+ type MarkerVariant = 'default' | 'border' | 'separator';
34
+
35
+ const markerVariants = tv({
36
+ slots: {
37
+ root: 'w-full flex-row items-center gap-2 py-1.5',
38
+ content: 'text-sm text-muted-foreground',
39
+ },
40
+ variants: {
41
+ variant: {
42
+ /** The plain row: an icon and a line of muted text. */
43
+ default: {},
44
+ /** Same row, closed by a hairline — for a step that ends a section. */
45
+ border: { root: 'border-b border-border pb-2.5' },
46
+ /**
47
+ * A centred label with a rule running out to each edge. The rules are
48
+ * `Separator`s rather than borders so they follow the same token and
49
+ * thickness as every other rule in the app.
50
+ */
51
+ separator: { root: 'gap-3 py-3', content: 'text-xs uppercase tracking-wider' },
52
+ },
53
+ disabled: {
54
+ true: { root: 'opacity-[0.64]' },
55
+ },
56
+ },
57
+ defaultVariants: {
58
+ variant: 'default',
59
+ },
60
+ });
61
+
62
+ /** The parts read the variant rather than being told it twice. */
63
+ const MarkerContext = createContext<MarkerVariant>('default');
64
+
65
+ export interface MarkerProps
66
+ extends Omit<AnimatedPressableProps, 'children' | 'disabled'>,
67
+ Omit<VariantProps<typeof markerVariants>, 'disabled'> {
68
+ className?: string;
69
+ disabled?: boolean;
70
+ /**
71
+ * `default` is the inline status row. `border` closes it with a hairline.
72
+ * `separator` centres the content between two rules — the "Yesterday"
73
+ * divider shape.
74
+ */
75
+ variant?: MarkerVariant;
76
+ children?: ReactNode;
77
+ }
78
+
79
+ /**
80
+ * Renders as a pressable when given `onPress` and as a plain view otherwise,
81
+ * so a marker that does nothing does not announce itself as a button.
82
+ */
83
+ const MarkerRoot = forwardRef<View, MarkerProps>(
84
+ ({ className, variant = 'default', disabled, children, onPress, ...props }, ref) => {
85
+ const { root } = markerVariants({ variant, disabled: !!disabled });
86
+
87
+ // The rules belong to the root, not the content: the content has to stay a
88
+ // single centred child for `flex-1` on either side to split the remainder.
89
+ const inner =
90
+ variant === 'separator' ? (
91
+ <>
92
+ <Separator className="flex-1" />
93
+ {children}
94
+ <Separator className="flex-1" />
95
+ </>
96
+ ) : (
97
+ children
98
+ );
99
+
100
+ const body = !onPress ? (
101
+ <View
102
+ ref={ref}
103
+ accessibilityState={{ disabled: !!disabled }}
104
+ className={root({ className })}
105
+ {...(props as ViewProps)}
106
+ >
107
+ {inner}
108
+ </View>
109
+ ) : (
110
+ <AnimatedPressable
111
+ ref={ref}
112
+ accessibilityRole="button"
113
+ accessibilityState={{ disabled: !!disabled }}
114
+ disabled={disabled}
115
+ onPress={onPress}
116
+ className={root({ className })}
117
+ {...props}
118
+ >
119
+ {inner}
120
+ </AnimatedPressable>
121
+ );
122
+
123
+ return <MarkerContext.Provider value={variant}>{body}</MarkerContext.Provider>;
124
+ }
125
+ );
126
+ MarkerRoot.displayName = 'Marker';
127
+
128
+ export interface MarkerIconProps extends ViewProps {
129
+ className?: string;
130
+ children?: ReactNode;
131
+ }
132
+
133
+ /**
134
+ * Decorative leading slot. Hidden from screen readers — the icon repeats what
135
+ * the content already says, and announcing it twice is noise.
136
+ */
137
+ const MarkerIcon = forwardRef<View, MarkerIconProps>(
138
+ ({ className, children, ...props }, ref) => {
139
+ // Icons here take the muted foreground, so a marker reads as chrome next to
140
+ // a message rather than competing with it.
141
+ const muted = useCSSVariable('--color-muted-foreground');
142
+
143
+ return (
144
+ <View
145
+ ref={ref}
146
+ accessibilityElementsHidden
147
+ importantForAccessibility="no-hide-descendants"
148
+ className={cn('h-4 w-4 shrink-0 items-center justify-center', className)}
149
+ {...props}
150
+ >
151
+ <IconColorProvider color={typeof muted === 'string' ? muted : undefined}>
152
+ {children}
153
+ </IconColorProvider>
154
+ </View>
155
+ );
156
+ }
157
+ );
158
+ MarkerIcon.displayName = 'Marker.Icon';
159
+
160
+ export interface MarkerContentProps extends TextProps {
161
+ className?: string;
162
+ /**
163
+ * Sweep a highlight through the text, for a step that is still running.
164
+ * Drop it when the step finishes — a marker that shimmers forever reads as
165
+ * a stuck one.
166
+ */
167
+ shimmer?: boolean;
168
+ children?: ReactNode;
169
+ }
170
+
171
+ const MarkerContent = forwardRef<RNText, MarkerContentProps>(
172
+ ({ className, shimmer, children, ...props }, ref) => {
173
+ const variant = useContext(MarkerContext);
174
+ const { content } = markerVariants({ variant });
175
+
176
+ if (shimmer) {
177
+ // Shimmer owns the text so it can mask the sweep to the glyphs; the
178
+ // class goes to the text inside it rather than to the wrapping view.
179
+ return <Shimmer textClassName={content({ className })}>{children}</Shimmer>;
180
+ }
181
+
182
+ return (
183
+ <Text ref={ref} className={content({ className })} {...props}>
184
+ {children}
185
+ </Text>
186
+ );
187
+ }
188
+ );
189
+ MarkerContent.displayName = 'Marker.Content';
190
+
191
+ export const Marker = Object.assign(MarkerRoot, {
192
+ Icon: MarkerIcon,
193
+ Content: MarkerContent,
194
+ });
@@ -29,8 +29,9 @@ import {
29
29
  useContext,
30
30
  type ReactNode,
31
31
  } from 'react';
32
- import { View, type ViewProps } from 'react-native';
32
+ import { View, type GestureResponderEvent, type ViewProps } from 'react-native';
33
33
  import { tv, type VariantProps } from 'tailwind-variants';
34
+ import { AnimatedPressable } from '../../primitives/animated-pressable';
34
35
  import { Text, type TextProps } from '../../primitives/text';
35
36
  import { cn } from '../../utils/cn';
36
37
 
@@ -107,20 +108,43 @@ export interface MessageProps
107
108
  * this for you.
108
109
  */
109
110
  stacked?: boolean;
111
+ /**
112
+ * Fires on a long press anywhere on the turn — the gesture a chat uses to
113
+ * surface per-message actions (copy, reply, react). Open a menu from it; the
114
+ * component only exposes the press. When set, the whole row gains press
115
+ * feedback. A plain tap should still do nothing, so there is no `onPress`.
116
+ */
117
+ onLongPress?: (event: GestureResponderEvent) => void;
110
118
  children?: ReactNode;
111
119
  }
112
120
 
113
121
  const MessageRoot = forwardRef<View, MessageProps>(
114
- ({ className, align, stacked = false, children, ...props }, ref) => {
122
+ ({ className, align, stacked = false, onLongPress, children, ...props }, ref) => {
115
123
  const group = useContext(GroupContext);
116
124
  const resolvedAlign = align ?? group?.align ?? 'start';
117
125
  const { root } = messageVariants({ align: resolvedAlign });
118
126
 
127
+ const body = onLongPress ? (
128
+ // A long-press target, not a button — a tap does nothing, so no role is
129
+ // announced. The feedback matches every other pressable in the library.
130
+ <AnimatedPressable
131
+ ref={ref}
132
+ onLongPress={onLongPress}
133
+ delayLongPress={300}
134
+ className={root({ className })}
135
+ {...props}
136
+ >
137
+ {children}
138
+ </AnimatedPressable>
139
+ ) : (
140
+ <View ref={ref} className={root({ className })} {...props}>
141
+ {children}
142
+ </View>
143
+ );
144
+
119
145
  return (
120
146
  <MessageContext.Provider value={{ align: resolvedAlign, stacked }}>
121
- <View ref={ref} className={root({ className })} {...props}>
122
- {children}
123
- </View>
147
+ {body}
124
148
  </MessageContext.Provider>
125
149
  );
126
150
  }