@vvedantb/native-ui 0.17.2 → 0.18.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 (220) hide show
  1. package/dist/AlertDialog.jsx +123 -0
  2. package/dist/AmbientBackground.jsx +73 -0
  3. package/dist/ArtifactList.jsx +59 -0
  4. package/dist/Avatar.jsx +285 -0
  5. package/dist/Badge.jsx +154 -0
  6. package/dist/BottomSheetContainer.jsx +208 -0
  7. package/dist/BulkActionBar.jsx +717 -0
  8. package/dist/Button.jsx +344 -0
  9. package/dist/CaptureButton.jsx +104 -0
  10. package/dist/Card.jsx +371 -0
  11. package/dist/Checkbox.jsx +177 -0
  12. package/dist/Chip.jsx +79 -0
  13. package/dist/ColorSwatches.jsx +159 -0
  14. package/dist/ConfirmDialog.jsx +157 -0
  15. package/dist/DateTimeField.jsx +204 -0
  16. package/dist/Dialog.jsx +614 -0
  17. package/dist/DividedList.jsx +120 -0
  18. package/dist/DropdownMenu.jsx +849 -0
  19. package/dist/EmptyState.jsx +434 -0
  20. package/dist/ExpoWebRoot.jsx +134 -0
  21. package/dist/FloatingFAB.jsx +95 -0
  22. package/dist/FloatingSurface.jsx +226 -0
  23. package/dist/FloatingTabBar.jsx +403 -0
  24. package/dist/HeaderIconButton.jsx +53 -0
  25. package/dist/IconButton.jsx +157 -0
  26. package/dist/Input.jsx +96 -0
  27. package/dist/Label.jsx +96 -0
  28. package/dist/LabeledSwitchRow.jsx +170 -0
  29. package/dist/LiquidGlass.jsx +2 -0
  30. package/dist/ListRow.jsx +281 -0
  31. package/dist/LoadingState.jsx +205 -0
  32. package/dist/PageIndicator.jsx +128 -0
  33. package/dist/PageTitle.jsx +205 -0
  34. package/dist/Pager.jsx +105 -0
  35. package/dist/PasswordInput.jsx +120 -0
  36. package/dist/PillTabs.jsx +300 -0
  37. package/dist/PinnedBotTile.jsx +212 -0
  38. package/dist/Progress.jsx +147 -0
  39. package/dist/SafeAreaContainer.jsx +38 -0
  40. package/dist/ScreenContainer.jsx +117 -0
  41. package/dist/SearchInput.jsx +150 -0
  42. package/dist/SectionLabel.jsx +128 -0
  43. package/dist/Select.jsx +223 -0
  44. package/dist/Separator.jsx +95 -0
  45. package/dist/Sheet.jsx +343 -0
  46. package/dist/SheetRow.jsx +198 -0
  47. package/dist/Skeleton.jsx +311 -0
  48. package/dist/Spinner.jsx +195 -0
  49. package/dist/StackPageHeader.jsx +160 -0
  50. package/dist/StatGrid.jsx +74 -0
  51. package/dist/StatusDot.jsx +129 -0
  52. package/dist/SurfaceRow.jsx +143 -0
  53. package/dist/SwipeableRow.jsx +50 -0
  54. package/dist/Switch.jsx +130 -0
  55. package/dist/Tabs.jsx +385 -0
  56. package/dist/Textarea.jsx +103 -0
  57. package/dist/ThemeToggle.jsx +78 -0
  58. package/dist/Toast.jsx +396 -0
  59. package/dist/ai/activity-step-detail.jsx +179 -0
  60. package/dist/ai/activity-step-label.js +816 -0
  61. package/dist/ai/activity-step-types.js +14 -0
  62. package/dist/ai/activity-step.jsx +98 -0
  63. package/dist/ai/activity-tasks-utils.js +172 -0
  64. package/dist/ai/activity-timeline.js +47 -0
  65. package/dist/ai/attachments.jsx +258 -0
  66. package/dist/ai/card-button.jsx +188 -0
  67. package/dist/ai/chain-of-thought.jsx +459 -0
  68. package/dist/ai/chat-jump-rail.jsx +57 -0
  69. package/dist/ai/chat-text.js +44 -0
  70. package/dist/ai/chat-thread.jsx +135 -0
  71. package/dist/ai/choice-question.jsx +925 -0
  72. package/dist/ai/code-block.jsx +574 -0
  73. package/dist/ai/collapsible.jsx +275 -0
  74. package/dist/ai/conversation.jsx +723 -0
  75. package/dist/ai/file-chip.jsx +198 -0
  76. package/dist/ai/icon-button.jsx +179 -0
  77. package/dist/ai/index.js +37 -0
  78. package/dist/ai/message-action-sheet.jsx +408 -0
  79. package/dist/ai/message-quote.jsx +241 -0
  80. package/dist/ai/message.jsx +739 -0
  81. package/dist/ai/prompt-input-menu.jsx +365 -0
  82. package/dist/ai/prompt-input.jsx +626 -0
  83. package/dist/ai/reasoning.jsx +446 -0
  84. package/dist/ai/reply-quote-chip.jsx +278 -0
  85. package/dist/ai/response-text.jsx +130 -0
  86. package/dist/ai/shimmer.jsx +149 -0
  87. package/dist/ai/sources.jsx +260 -0
  88. package/dist/ai/subagent-cards.jsx +645 -0
  89. package/dist/ai/suggestion.jsx +186 -0
  90. package/dist/ai/tool-approval-card.jsx +359 -0
  91. package/dist/ai/trace.jsx +728 -0
  92. package/dist/ai/unified-diff.jsx +280 -0
  93. package/dist/ai/use-streaming-disclosure.js +70 -0
  94. package/dist/auth/AuthProviders.jsx +27 -0
  95. package/dist/auth/AuthScreen.jsx +292 -0
  96. package/dist/auth/GoogleSignInButton.jsx +188 -0
  97. package/dist/auth/SecondFactorScreen.jsx +133 -0
  98. package/dist/auth/SignInScreen.jsx +482 -0
  99. package/dist/auth/authErrors.js +131 -0
  100. package/dist/auth/index.js +11 -0
  101. package/dist/auth/totp.js +378 -0
  102. package/dist/blur.js +36 -0
  103. package/dist/brand/AppIcons.jsx +118 -0
  104. package/dist/brand/AppMark.jsx +128 -0
  105. package/dist/brand/AppWordmark.jsx +138 -0
  106. package/dist/brand/GoogleMark.jsx +71 -0
  107. package/dist/brand/ProviderIcon.jsx +192 -0
  108. package/dist/brand/familyApps.js +33 -0
  109. package/dist/brand/index.js +11 -0
  110. package/dist/brand/svg.js +252 -0
  111. package/dist/brand/vProAppBenefits.js +19 -0
  112. package/dist/cn.js +5 -0
  113. package/dist/colors.js +15 -0
  114. package/dist/configureTheme.js +72 -0
  115. package/dist/controlStyles.js +520 -0
  116. package/dist/definiteSize.js +12 -0
  117. package/dist/dialogLayout.js +18 -0
  118. package/dist/entries/ai.js +4 -0
  119. package/dist/entries/ambient.js +3 -0
  120. package/dist/entries/auth.js +5 -0
  121. package/dist/entries/bottom-sheet.js +2 -0
  122. package/dist/entries/brand.js +2 -0
  123. package/dist/entries/button.js +2 -0
  124. package/dist/entries/date-time.js +3 -0
  125. package/dist/entries/expo-router.js +4 -0
  126. package/dist/entries/expo-web-root.js +3 -0
  127. package/dist/entries/floating.js +7 -0
  128. package/dist/entries/gesture-handler.js +4 -0
  129. package/dist/entries/keyboard-controller.js +4 -0
  130. package/dist/entries/layout.js +16 -0
  131. package/dist/entries/markdown.js +4 -0
  132. package/dist/entries/marketing.js +3 -0
  133. package/dist/entries/page-title.js +7 -0
  134. package/dist/entries/password-input.js +3 -0
  135. package/dist/entries/primitives.js +57 -0
  136. package/dist/entries/search-input.js +3 -0
  137. package/dist/entries/tab-bar.js +4 -0
  138. package/dist/entries/theme.js +7 -0
  139. package/dist/entries/toast.js +5 -0
  140. package/dist/entries/video.js +3 -0
  141. package/dist/entries/webview.js +4 -0
  142. package/dist/examples/AiChatGallery.jsx +509 -0
  143. package/dist/examples/ParityGallery.jsx +1307 -0
  144. package/dist/floating.js +62 -0
  145. package/dist/glassBlur.jsx +145 -0
  146. package/dist/gradient.js +17 -0
  147. package/dist/haptics.js +44 -0
  148. package/dist/highlight.js +382 -0
  149. package/dist/index.js +85 -0
  150. package/dist/initials.js +4 -0
  151. package/dist/loadingGrid.js +81 -0
  152. package/dist/markdown/Markdown.jsx +515 -0
  153. package/dist/markdown/MarkdownTable.jsx +443 -0
  154. package/dist/markdown/tableText.js +68 -0
  155. package/dist/marketing/PricingModal.jsx +608 -0
  156. package/dist/marketing/UpgradeToProCard.jsx +164 -0
  157. package/dist/marketing/pricing.js +34 -0
  158. package/dist/media/ImageGallery.jsx +580 -0
  159. package/dist/media/MediaCard.jsx +162 -0
  160. package/dist/media/imageGrid.js +54 -0
  161. package/dist/motion.js +33 -0
  162. package/dist/pagerSwipe.js +104 -0
  163. package/dist/palette.js +104 -0
  164. package/dist/primitives/button.jsx +127 -0
  165. package/dist/primitives/card.jsx +249 -0
  166. package/dist/primitives/icon.jsx +37 -0
  167. package/dist/primitives/input.jsx +56 -0
  168. package/dist/primitives/keyboard-controller.jsx +207 -0
  169. package/dist/primitives/keyboard-parts.jsx +75 -0
  170. package/dist/primitives/native-only-animated-view.jsx +68 -0
  171. package/dist/primitives/overlay.jsx +391 -0
  172. package/dist/primitives/pager-gesture.jsx +131 -0
  173. package/dist/primitives/select-host.jsx +103 -0
  174. package/dist/primitives/select.jsx +555 -0
  175. package/dist/primitives/sheet-drag.jsx +420 -0
  176. package/dist/primitives/sheet-gesture.jsx +219 -0
  177. package/dist/primitives/swipe-row-gesture.jsx +341 -0
  178. package/dist/primitives/switch.jsx +105 -0
  179. package/dist/primitives/text.jsx +145 -0
  180. package/dist/primitives/toast-drag-gesture.jsx +94 -0
  181. package/dist/primitives/use-controllable-state.js +40 -0
  182. package/dist/primitives/web-click-guard.js +69 -0
  183. package/dist/push.js +166 -0
  184. package/dist/relativeTime.js +70 -0
  185. package/dist/router/RouterStackPageHeader.jsx +53 -0
  186. package/dist/selectA11y.js +32 -0
  187. package/dist/settings/MoreFromProjectV.jsx +168 -0
  188. package/dist/settings/SettingsEmptyState.jsx +102 -0
  189. package/dist/settings/SettingsField.jsx +49 -0
  190. package/dist/settings/SettingsSection.jsx +101 -0
  191. package/dist/settings/SettingsStack.jsx +17 -0
  192. package/dist/settings/SettingsToggleRow.jsx +163 -0
  193. package/dist/settings/projectVMobileApps.js +126 -0
  194. package/dist/settings/relaxedSizeStyle.js +11 -0
  195. package/dist/sheetDrag.js +76 -0
  196. package/dist/svgA11y.js +46 -0
  197. package/dist/swipeRow.js +161 -0
  198. package/dist/tabBarRoutes.js +41 -0
  199. package/dist/tabIndicator.js +139 -0
  200. package/dist/tailwind-preset.cjs +255 -0
  201. package/dist/tailwind-preset.d.cts +55 -0
  202. package/dist/theme.jsx +62 -0
  203. package/dist/toastChrome.js +110 -0
  204. package/dist/toastDrag.js +51 -0
  205. package/dist/toastStore.js +54 -0
  206. package/dist/tokens.js +70 -0
  207. package/dist/typography.js +40 -0
  208. package/dist/useReduceMotion.js +32 -0
  209. package/dist/useReduceTransparency.js +27 -0
  210. package/dist/useScheme.js +15 -0
  211. package/dist/video/InlineVideo.jsx +115 -0
  212. package/dist/webview/HtmlView.jsx +169 -0
  213. package/dist/webview/HtmlView.web.jsx +63 -0
  214. package/dist/webview/htmlView.js +43 -0
  215. package/package.json +70 -33
  216. package/src/DropdownMenu.tsx +28 -16
  217. package/src/FloatingTabBar.tsx +78 -41
  218. package/src/ai/conversation.tsx +12 -8
  219. package/src/glassBlur.tsx +47 -22
  220. package/src/primitives/swipe-row-gesture.tsx +11 -2
@@ -0,0 +1,341 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { useContext, useRef, useState } from "react";
3
+ import { Pressable, StyleSheet, View } from "react-native";
4
+ import { Gesture, GestureDetector } from "react-native-gesture-handler";
5
+ import Animated, { cancelAnimation, ReduceMotion, runOnJS, useAnimatedReaction, useAnimatedStyle, useSharedValue, withSpring, withTiming } from "react-native-reanimated";
6
+ import { impactHaptic } from "../haptics";
7
+ import { InsidePagerContext } from "../Pager";
8
+ import { EASE_OUT } from "../motion";
9
+ import { palette } from "../palette";
10
+ import { closeSwipeRows, isSwipeRowOpen, markSwipeRowClosed, markSwipeRowOpen, SWIPE_ACTION_WIDTH, SWIPE_FAIL_OFFSET_Y, swipeRowActivation, swipeRowArmed, swipeRowOffset, swipeRowSettle } from "../swipeRow";
11
+ import { tokens } from "../tokens";
12
+ import { useScheme } from "../useScheme";
13
+ import { useWebClickGuard } from "./web-click-guard";
14
+
15
+ // The swipeable row on Gesture Handler: the track phase and the release run
16
+ // as worklets on the UI thread, so the row never lags the finger. The rules
17
+ // are plain worklets in `swipeRow`.
18
+
19
+ /** The release: springs on at the finger's speed, no bounce (a row overshooting rest would flash the other side). */
20
+ const ROW_SPRING = {
21
+ duration: 250,
22
+ dampingRatio: 1,
23
+ reduceMotion: ReduceMotion.System
24
+ };
25
+
26
+ /** The armed full swipe: the first action's icon grows a little, with the haptic, so the commit shows without it. */
27
+ const ARMED_SCALE = 1.15;
28
+ const ARMED_TIMING = {
29
+ duration: 150,
30
+ easing: EASE_OUT,
31
+ reduceMotion: ReduceMotion.System
32
+ };
33
+ const ICON_SIZE = 20;
34
+
35
+ /** Each tone's fill and the icon colour on it. */
36
+ const TONES = {
37
+ default: {
38
+ fill: palette.primary,
39
+ icon: palette.primaryForeground
40
+ },
41
+ warning: {
42
+ fill: palette.warning,
43
+ icon: palette.warningForeground
44
+ },
45
+ danger: {
46
+ fill: palette.danger,
47
+ icon: palette.dangerForeground
48
+ }
49
+ };
50
+ export function GestureSwipeableRow({
51
+ leadingActions = [],
52
+ trailingActions = [],
53
+ enabled = true,
54
+ backgroundColor,
55
+ children
56
+ }) {
57
+ const scheme = useScheme();
58
+ const x = useSharedValue(0);
59
+ const width = useSharedValue(0);
60
+ // Where the row was when the finger caught it.
61
+ const start = useSharedValue(0);
62
+ const dragging = useSharedValue(false);
63
+ const armed = useSharedValue(null);
64
+ const armedScale = useSharedValue(1);
65
+ // Plain values for the worklets: they must not capture the actions' functions.
66
+ const leading = leadingActions.length * SWIPE_ACTION_WIDTH;
67
+ const trailing = trailingActions.length * SWIPE_ACTION_WIDTH;
68
+ const leadingExits = leadingActions[0]?.exits === true;
69
+ const trailingExits = trailingActions[0]?.exits === true;
70
+ const [handle] = useState(() => ({
71
+ close: () => x.set(withSpring(0, ROW_SPRING))
72
+ }));
73
+
74
+ // Whether this touch began while a row was open, so its release only closes that row. Nothing renders from it.
75
+ const closesOnRelease = useRef(false);
76
+ // The action strips mount on the row's first touch, not with the row: a
77
+ // list of a hundred rows then mounts no hidden buttons and icons up front.
78
+ // A touch lands a few frames before a swipe can move the row, so the strip
79
+ // is there before any of it shows.
80
+ const [revealed, setRevealed] = useState(false);
81
+ const reveal = () => setRevealed(true);
82
+ const webClicks = useWebClickGuard(isSwipeRowOpen);
83
+ const insidePager = useContext(InsidePagerContext);
84
+ const opened = () => {
85
+ closesOnRelease.current = false;
86
+ webClicks.swallowNext();
87
+ markSwipeRowOpen(handle);
88
+ };
89
+ const closed = () => markSwipeRowClosed(handle);
90
+ const firstOf = side => side === "leading" ? leadingActions[0] : trailingActions[0];
91
+ /** Runs an action once the row slid out: if it fails, the row comes back. */
92
+ const runExited = action => {
93
+ const result = action?.onPress();
94
+ if (result instanceof Promise) result.catch(() => x.set(withSpring(0, ROW_SPRING)));
95
+ };
96
+ // The worklets take sides, never the actions (their functions stay on the JavaScript thread).
97
+ const runFirstExited = side_0 => runExited(firstOf(side_0));
98
+ const runFirstInPlace = side_1 => void firstOf(side_1)?.onPress();
99
+ /** A tapped button: the row closes, or slides out for an action that exits, then the action runs. */
100
+ const press = (action_0, side_2) => {
101
+ closed();
102
+ if (!action_0.exits) {
103
+ x.set(withSpring(0, ROW_SPRING));
104
+ void action_0.onPress();
105
+ return;
106
+ }
107
+ const run = () => runExited(action_0);
108
+ x.set(withSpring(side_2 === "leading" ? width.get() : -width.get(), {
109
+ ...ROW_SPRING,
110
+ overshootClamping: true
111
+ }, finished => {
112
+ "worklet";
113
+
114
+ if (finished) runOnJS(run)();
115
+ }));
116
+ };
117
+
118
+ // The full swipe arms and disarms as the row crosses the point: the icon
119
+ // grows, and a light haptic fires as it arms under the finger.
120
+ useAnimatedReaction(() => swipeRowArmed(x.get(), {
121
+ leading,
122
+ trailing,
123
+ width: width.get()
124
+ }), (side_3, previous) => {
125
+ if (side_3 === previous) return;
126
+ armed.set(side_3);
127
+ armedScale.set(withTiming(side_3 ? ARMED_SCALE : 1, ARMED_TIMING));
128
+ if (side_3 && dragging.get()) runOnJS(impactHaptic)("light");
129
+ }, [leading, trailing]);
130
+
131
+ // Built on each render (for `enabled` and the actions): the detector keeps
132
+ // the same handler, and a drag in flight, and only takes the new config.
133
+ const activation = swipeRowActivation({
134
+ leading,
135
+ trailing
136
+ }, insidePager);
137
+ const pan = Gesture.Pan().enabled(enabled && leading + trailing > 0)
138
+ // Sideways intent first; a drag that goes vertical first is the list's scroll.
139
+ .activeOffsetX(activation.activeOffsetX).failOffsetY([-SWIPE_FAIL_OFFSET_Y, SWIPE_FAIL_OFFSET_Y]);
140
+ if (activation.failOffsetX !== undefined) pan.failOffsetX(activation.failOffsetX);
141
+ pan.onBegin(() => {
142
+ runOnJS(reveal)();
143
+ }).onStart(() => {
144
+ cancelAnimation(x);
145
+ start.set(x.get());
146
+ dragging.set(true);
147
+ runOnJS(opened)();
148
+ })
149
+ // Track phase: one shared value write per frame, on the UI thread.
150
+ .onUpdate(event => {
151
+ x.set(swipeRowOffset(start.get() + event.translationX, {
152
+ leading,
153
+ trailing,
154
+ width: width.get()
155
+ }));
156
+ }).onEnd((event_0, success) => {
157
+ dragging.set(false);
158
+ const rowWidth = width.get();
159
+ const settle = swipeRowSettle(x.get(), event_0.velocityX, {
160
+ leading,
161
+ trailing,
162
+ width: rowWidth
163
+ });
164
+ const velocity = event_0.velocityX;
165
+ if (success && settle.kind === "commit") {
166
+ // Armed by the fling rather than the position: the haptic fires now, with the commit.
167
+ if (armed.get() === null) runOnJS(impactHaptic)("light");
168
+ runOnJS(closed)();
169
+ const side_4 = settle.side;
170
+ if (side_4 === "leading" ? leadingExits : trailingExits) {
171
+ x.set(withSpring(side_4 === "leading" ? rowWidth : -rowWidth, {
172
+ ...ROW_SPRING,
173
+ velocity,
174
+ overshootClamping: true
175
+ }, finished_0 => {
176
+ "worklet";
177
+
178
+ if (finished_0) runOnJS(runFirstExited)(side_4);
179
+ }));
180
+ } else {
181
+ x.set(withSpring(0, {
182
+ ...ROW_SPRING,
183
+ velocity
184
+ }));
185
+ runOnJS(runFirstInPlace)(side_4);
186
+ }
187
+ return;
188
+ }
189
+ if (settle.kind === "open") {
190
+ x.set(withSpring(settle.side === "leading" ? leading : -trailing, {
191
+ ...ROW_SPRING,
192
+ velocity
193
+ }));
194
+ return;
195
+ }
196
+ x.set(withSpring(0, {
197
+ ...ROW_SPRING,
198
+ velocity
199
+ }));
200
+ runOnJS(closed)();
201
+ }).onFinalize(() => {
202
+ dragging.set(false);
203
+ });
204
+ const rowStyle = useAnimatedStyle(() => ({
205
+ transform: [{
206
+ translateX: x.get()
207
+ }]
208
+ }));
209
+ return <View onLayout={event_1 => width.set(event_1.nativeEvent.layout.width)} style={styles.clip}>
210
+ {revealed && leadingActions.length > 0 ? <ActionStrip side="leading" actions={leadingActions} x={x} armedScale={armedScale} onPress={press} /> : null}
211
+ {revealed && trailingActions.length > 0 ? <ActionStrip side="trailing" actions={trailingActions} x={x} armedScale={armedScale} onPress={press} /> : null}
212
+ <GestureDetector gesture={pan}>
213
+ <Animated.View style={[{
214
+ backgroundColor: backgroundColor ?? tokens.color.background[scheme]
215
+ }, rowStyle]}>
216
+ <View ref={webClicks.ref}
217
+ // While a row is open, a tap on any row only closes it: the row
218
+ // takes the touch from the pressables inside.
219
+ onStartShouldSetResponderCapture={() => {
220
+ closesOnRelease.current = isSwipeRowOpen();
221
+ return closesOnRelease.current;
222
+ }} onResponderRelease={() => {
223
+ if (closesOnRelease.current) closeSwipeRows();
224
+ }}>
225
+ {children}
226
+ </View>
227
+ </Animated.View>
228
+ </GestureDetector>
229
+ </View>;
230
+ }
231
+
232
+ /**
233
+ * One side's actions behind the row, the first at the screen edge, on the
234
+ * first action's fill (which stretches with a full swipe). Shown only while
235
+ * the row moves toward that side. Hidden from screen readers: they reach the
236
+ * actions on the row itself (`swipeActionsAccessibility`).
237
+ */
238
+ function ActionStrip(t0) {
239
+ const $ = _c(22);
240
+ const {
241
+ side,
242
+ actions,
243
+ x,
244
+ armedScale,
245
+ onPress
246
+ } = t0;
247
+ const scheme = useScheme();
248
+ const reveal = actions.length * SWIPE_ACTION_WIDTH;
249
+ const direction = side === "leading" ? 1 : -1;
250
+ const stripStyle = useAnimatedStyle(() => ({
251
+ opacity: x.get() * direction > 0 ? 1 : 0
252
+ }));
253
+ const firstIconStyle = useAnimatedStyle(() => ({
254
+ transform: [{
255
+ translateX: direction * Math.max(0, Math.abs(x.get()) - reveal)
256
+ }, {
257
+ scale: armedScale.get()
258
+ }]
259
+ }));
260
+ const t1 = side === "leading" ? "row" : "row-reverse";
261
+ let t2;
262
+ if ($[0] !== t1) {
263
+ t2 = {
264
+ flexDirection: t1
265
+ };
266
+ $[0] = t1;
267
+ $[1] = t2;
268
+ } else {
269
+ t2 = $[1];
270
+ }
271
+ const t3 = TONES[actions[0]?.tone ?? "default"].fill[scheme];
272
+ let t4;
273
+ if ($[2] !== t3) {
274
+ t4 = {
275
+ backgroundColor: t3
276
+ };
277
+ $[2] = t3;
278
+ $[3] = t4;
279
+ } else {
280
+ t4 = $[3];
281
+ }
282
+ let t5;
283
+ if ($[4] !== stripStyle || $[5] !== t2 || $[6] !== t4) {
284
+ t5 = [StyleSheet.absoluteFill, t2, t4, stripStyle];
285
+ $[4] = stripStyle;
286
+ $[5] = t2;
287
+ $[6] = t4;
288
+ $[7] = t5;
289
+ } else {
290
+ t5 = $[7];
291
+ }
292
+ let t6;
293
+ if ($[8] !== actions || $[9] !== firstIconStyle || $[10] !== onPress || $[11] !== scheme || $[12] !== side) {
294
+ let t7;
295
+ if ($[14] !== firstIconStyle || $[15] !== onPress || $[16] !== scheme || $[17] !== side) {
296
+ t7 = (action, index) => {
297
+ const tone = TONES[action.tone ?? "default"];
298
+ const Icon = action.icon;
299
+ return <Pressable key={action.key} accessibilityRole="button" accessibilityLabel={action.label} onPress={() => onPress(action, side)} style={[styles.action, {
300
+ backgroundColor: tone.fill[scheme]
301
+ }]}>{index === 0 ? <Animated.View style={firstIconStyle}><Icon size={ICON_SIZE} color={tone.icon[scheme]} /></Animated.View> : <Icon size={ICON_SIZE} color={tone.icon[scheme]} />}</Pressable>;
302
+ };
303
+ $[14] = firstIconStyle;
304
+ $[15] = onPress;
305
+ $[16] = scheme;
306
+ $[17] = side;
307
+ $[18] = t7;
308
+ } else {
309
+ t7 = $[18];
310
+ }
311
+ t6 = actions.map(t7);
312
+ $[8] = actions;
313
+ $[9] = firstIconStyle;
314
+ $[10] = onPress;
315
+ $[11] = scheme;
316
+ $[12] = side;
317
+ $[13] = t6;
318
+ } else {
319
+ t6 = $[13];
320
+ }
321
+ let t7;
322
+ if ($[19] !== t5 || $[20] !== t6) {
323
+ t7 = <Animated.View aria-hidden={true} importantForAccessibility="no-hide-descendants" style={t5}>{t6}</Animated.View>;
324
+ $[19] = t5;
325
+ $[20] = t6;
326
+ $[21] = t7;
327
+ } else {
328
+ t7 = $[21];
329
+ }
330
+ return t7;
331
+ }
332
+ const styles = StyleSheet.create({
333
+ clip: {
334
+ overflow: "hidden"
335
+ },
336
+ action: {
337
+ width: SWIPE_ACTION_WIDTH,
338
+ alignItems: "center",
339
+ justifyContent: "center"
340
+ }
341
+ });
@@ -0,0 +1,105 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import * as SwitchPrimitives from "@rn-primitives/switch";
3
+ import * as React from "react";
4
+ import { Platform } from "react-native";
5
+ import { cn } from "../cn";
6
+ const Switch = React.forwardRef((t0, ref) => {
7
+ const $ = _c(30);
8
+ let checked;
9
+ let className;
10
+ let disabled;
11
+ let props;
12
+ let style;
13
+ let thumbClassName;
14
+ let thumbStyle;
15
+ let trackStyle;
16
+ if ($[0] !== t0) {
17
+ ({
18
+ className,
19
+ thumbClassName,
20
+ trackStyle,
21
+ thumbStyle,
22
+ checked,
23
+ style,
24
+ disabled,
25
+ ...props
26
+ } = t0);
27
+ $[0] = t0;
28
+ $[1] = checked;
29
+ $[2] = className;
30
+ $[3] = disabled;
31
+ $[4] = props;
32
+ $[5] = style;
33
+ $[6] = thumbClassName;
34
+ $[7] = thumbStyle;
35
+ $[8] = trackStyle;
36
+ } else {
37
+ checked = $[1];
38
+ className = $[2];
39
+ disabled = $[3];
40
+ props = $[4];
41
+ style = $[5];
42
+ thumbClassName = $[6];
43
+ thumbStyle = $[7];
44
+ trackStyle = $[8];
45
+ }
46
+ const isChecked = Boolean(checked);
47
+ let t1;
48
+ if ($[9] !== style || $[10] !== trackStyle) {
49
+ t1 = Platform.OS === "web" || typeof style === "function" ? trackStyle : [trackStyle, style];
50
+ $[9] = style;
51
+ $[10] = trackStyle;
52
+ $[11] = t1;
53
+ } else {
54
+ t1 = $[11];
55
+ }
56
+ const resolvedStyle = t1;
57
+ let t2;
58
+ if ($[12] !== className || $[13] !== disabled || $[14] !== isChecked) {
59
+ t2 = cn("h-[1.15rem] w-8 shrink-0 rounded-full border border-transparent", Platform.select({
60
+ web: "outline-none transition-all"
61
+ }), isChecked ? "bg-primary" : "bg-input dark:bg-input/80", disabled && "opacity-50", className);
62
+ $[12] = className;
63
+ $[13] = disabled;
64
+ $[14] = isChecked;
65
+ $[15] = t2;
66
+ } else {
67
+ t2 = $[15];
68
+ }
69
+ const t3 = isChecked ? "translate-x-3.5 dark:bg-primary-foreground" : "translate-x-0 dark:bg-foreground";
70
+ let t4;
71
+ if ($[16] !== t3 || $[17] !== thumbClassName) {
72
+ t4 = cn("h-4 w-4 rounded-full bg-background transition-transform", t3, thumbClassName);
73
+ $[16] = t3;
74
+ $[17] = thumbClassName;
75
+ $[18] = t4;
76
+ } else {
77
+ t4 = $[18];
78
+ }
79
+ let t5;
80
+ if ($[19] !== t4 || $[20] !== thumbStyle) {
81
+ t5 = <SwitchPrimitives.Thumb style={thumbStyle} className={t4} />;
82
+ $[19] = t4;
83
+ $[20] = thumbStyle;
84
+ $[21] = t5;
85
+ } else {
86
+ t5 = $[21];
87
+ }
88
+ let t6;
89
+ if ($[22] !== checked || $[23] !== disabled || $[24] !== props || $[25] !== ref || $[26] !== resolvedStyle || $[27] !== t2 || $[28] !== t5) {
90
+ t6 = <SwitchPrimitives.Root ref={ref} checked={checked} disabled={disabled} style={resolvedStyle} className={t2} {...props}>{t5}</SwitchPrimitives.Root>;
91
+ $[22] = checked;
92
+ $[23] = disabled;
93
+ $[24] = props;
94
+ $[25] = ref;
95
+ $[26] = resolvedStyle;
96
+ $[27] = t2;
97
+ $[28] = t5;
98
+ $[29] = t6;
99
+ } else {
100
+ t6 = $[29];
101
+ }
102
+ return t6;
103
+ });
104
+ Switch.displayName = "Switch";
105
+ export { Switch };
@@ -0,0 +1,145 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import * as Slot from "@rn-primitives/slot";
3
+ import { cva } from "class-variance-authority";
4
+ import * as React from "react";
5
+ import { Platform, Text as RNText } from "react-native";
6
+ import { cn } from "../cn";
7
+ import { typeStyle } from "../controlStyles";
8
+ const textVariants = cva(cn("text-foreground text-base", Platform.select({
9
+ web: "select-text"
10
+ })), {
11
+ variants: {
12
+ variant: {
13
+ default: "",
14
+ h1: cn("text-4xl font-instrument-sans-semibold tracking-tight", Platform.select({
15
+ web: "scroll-m-20"
16
+ })),
17
+ h2: cn("text-3xl font-instrument-sans-semibold tracking-tight border-border border-b pb-2", Platform.select({
18
+ web: "scroll-m-20"
19
+ })),
20
+ h3: cn("text-2xl font-instrument-sans-semibold tracking-tight", Platform.select({
21
+ web: "scroll-m-20"
22
+ })),
23
+ h4: cn("text-xl font-instrument-sans-semibold tracking-tight", Platform.select({
24
+ web: "scroll-m-20"
25
+ })),
26
+ p: "leading-7",
27
+ blockquote: "border-l-2 border-border pl-4 italic",
28
+ code: "bg-muted rounded px-[0.3rem] py-[0.2rem] text-sm font-instrument-sans-semibold",
29
+ lead: "text-xl text-muted-foreground",
30
+ large: "text-lg font-instrument-sans-semibold",
31
+ small: "text-sm font-instrument-sans-medium",
32
+ muted: "text-sm text-muted-foreground"
33
+ }
34
+ },
35
+ defaultVariants: {
36
+ variant: "default"
37
+ }
38
+ });
39
+ const ROLE = {
40
+ h1: "heading",
41
+ h2: "heading",
42
+ h3: "heading",
43
+ h4: "heading",
44
+ blockquote: Platform.select({
45
+ web: "blockquote"
46
+ }),
47
+ code: Platform.select({
48
+ web: "code"
49
+ })
50
+ };
51
+ const ARIA_LEVEL = {
52
+ h1: "1",
53
+ h2: "2",
54
+ h3: "3",
55
+ h4: "4"
56
+ };
57
+
58
+ // The weight of each variant's `font-instrument-sans-*` class, set as a style
59
+ // beside it (`typeStyle`): where an app maps every one of those classes to one
60
+ // family, the class alone draws Regular. Headings are semibold, as the web
61
+ // titles; `h1` was `font-extrabold` before 0.3.13.
62
+ const WEIGHT = {
63
+ h1: typeStyle("semibold"),
64
+ h2: typeStyle("semibold"),
65
+ h3: typeStyle("semibold"),
66
+ h4: typeStyle("semibold"),
67
+ code: typeStyle("semibold"),
68
+ large: typeStyle("semibold"),
69
+ small: typeStyle("medium")
70
+ };
71
+ const TextClassContext = React.createContext(undefined);
72
+ const Text = React.forwardRef((t0, ref) => {
73
+ const $ = _c(21);
74
+ let className;
75
+ let props;
76
+ let style;
77
+ let t1;
78
+ let t2;
79
+ if ($[0] !== t0) {
80
+ ({
81
+ className,
82
+ asChild: t1,
83
+ variant: t2,
84
+ style,
85
+ ...props
86
+ } = t0);
87
+ $[0] = t0;
88
+ $[1] = className;
89
+ $[2] = props;
90
+ $[3] = style;
91
+ $[4] = t1;
92
+ $[5] = t2;
93
+ } else {
94
+ className = $[1];
95
+ props = $[2];
96
+ style = $[3];
97
+ t1 = $[4];
98
+ t2 = $[5];
99
+ }
100
+ const asChild = t1 === undefined ? false : t1;
101
+ const variant = t2 === undefined ? "default" : t2;
102
+ const textClass = React.useContext(TextClassContext);
103
+ const Component = asChild ? Slot.Text : RNText;
104
+ const weight = variant ? WEIGHT[variant] : undefined;
105
+ let t3;
106
+ if ($[6] !== className || $[7] !== textClass || $[8] !== variant) {
107
+ t3 = cn(textVariants({
108
+ variant
109
+ }), textClass, className);
110
+ $[6] = className;
111
+ $[7] = textClass;
112
+ $[8] = variant;
113
+ $[9] = t3;
114
+ } else {
115
+ t3 = $[9];
116
+ }
117
+ const t4 = variant ? ROLE[variant] : undefined;
118
+ const t5 = variant ? ARIA_LEVEL[variant] : undefined;
119
+ let t6;
120
+ if ($[10] !== style || $[11] !== weight) {
121
+ t6 = weight ? [weight, style] : style;
122
+ $[10] = style;
123
+ $[11] = weight;
124
+ $[12] = t6;
125
+ } else {
126
+ t6 = $[12];
127
+ }
128
+ let t7;
129
+ if ($[13] !== Component || $[14] !== props || $[15] !== ref || $[16] !== t3 || $[17] !== t4 || $[18] !== t5 || $[19] !== t6) {
130
+ t7 = <Component ref={ref} className={t3} role={t4} aria-level={t5} style={t6} {...props} />;
131
+ $[13] = Component;
132
+ $[14] = props;
133
+ $[15] = ref;
134
+ $[16] = t3;
135
+ $[17] = t4;
136
+ $[18] = t5;
137
+ $[19] = t6;
138
+ $[20] = t7;
139
+ } else {
140
+ t7 = $[20];
141
+ }
142
+ return t7;
143
+ });
144
+ Text.displayName = "Text";
145
+ export { Text, TextClassContext };
@@ -0,0 +1,94 @@
1
+ import { View } from "react-native";
2
+ import { Gesture, GestureDetector, GestureHandlerRootView } from "react-native-gesture-handler";
3
+ import Animated, { cancelAnimation, interpolate, ReduceMotion, runOnJS, useAnimatedStyle, useSharedValue, withSpring } from "react-native-reanimated";
4
+ import { impactHaptic } from "../haptics";
5
+ import { TOAST_DRAG_ACTIVE_OFFSET_Y, toastDragDismisses, toastDragOffset } from "../toastDrag";
6
+ import { useWebClickGuard } from "./web-click-guard";
7
+
8
+ // The toast drag on Gesture Handler: the track phase and the release run as
9
+ // worklets on the UI thread. The rules are plain worklets in `toastDrag`.
10
+
11
+ /** Back home after a short drag: a little bounce, as the finger applied force. */
12
+ const HOME_SPRING = {
13
+ duration: 250,
14
+ dampingRatio: 0.8,
15
+ reduceMotion: ReduceMotion.System
16
+ };
17
+ /** Away up the screen: no overshoot back into view. */
18
+ const AWAY_SPRING = {
19
+ duration: 250,
20
+ dampingRatio: 1,
21
+ overshootClamping: true,
22
+ reduceMotion: ReduceMotion.System
23
+ };
24
+ export function GestureToastDrag({
25
+ onDismiss,
26
+ onHoldChange,
27
+ children
28
+ }) {
29
+ const y = useSharedValue(0);
30
+ const height = useSharedValue(0);
31
+ // Where the toast was when the finger caught it, and the finger's travel then.
32
+ const start = useSharedValue(0);
33
+ const startY = useSharedValue(0);
34
+ const webClicks = useWebClickGuard();
35
+ const dismissed = () => {
36
+ impactHaptic("light");
37
+ onDismiss();
38
+ };
39
+
40
+ // Built on each render: the detector keeps the same handler, and a drag in flight.
41
+ const pan = Gesture.Pan().activeOffsetY([-TOAST_DRAG_ACTIVE_OFFSET_Y, TOAST_DRAG_ACTIVE_OFFSET_Y])
42
+ // The timer holds from the touch, a tap included (a tap closes the toast anyway).
43
+ .onBegin(() => {
44
+ runOnJS(onHoldChange)(true);
45
+ }).onStart(event => {
46
+ cancelAnimation(y);
47
+ start.set(y.get());
48
+ // Count from here, so the toast does not jump by the slop the drag needed to start.
49
+ startY.set(event.translationY);
50
+ runOnJS(webClicks.swallowNext)();
51
+ })
52
+ // Track phase: one shared value write per frame, on the UI thread.
53
+ .onUpdate(event_0 => {
54
+ y.set(toastDragOffset(start.get() + event_0.translationY - startY.get()));
55
+ }).onEnd(event_1 => {
56
+ const position = y.get();
57
+ if (toastDragDismisses(position, event_1.velocityY, height.get())) {
58
+ // Up past its own height, fading on the way (`toastStyle`), at the finger's speed.
59
+ y.set(withSpring(-height.get() * 1.5, {
60
+ ...AWAY_SPRING,
61
+ velocity: event_1.velocityY
62
+ }, finished => {
63
+ "worklet";
64
+
65
+ if (finished) runOnJS(dismissed)();
66
+ }));
67
+ return;
68
+ }
69
+ y.set(withSpring(0, {
70
+ ...HOME_SPRING,
71
+ velocity: event_1.velocityY
72
+ }));
73
+ }).onFinalize(() => {
74
+ runOnJS(onHoldChange)(false);
75
+ });
76
+
77
+ // Linked to the same value: the toast fades as it rises, gone one height up.
78
+ const toastStyle = useAnimatedStyle(() => ({
79
+ opacity: height.get() > 0 ? interpolate(y.get(), [-height.get(), 0], [0, 1], "clamp") : 1,
80
+ transform: [{
81
+ translateY: y.get()
82
+ }]
83
+ }));
84
+ return (
85
+ // Its own root: on iOS the toasts draw in a separate window (`FullWindowOverlay`).
86
+ <GestureHandlerRootView>
87
+ <GestureDetector gesture={pan}>
88
+ <Animated.View style={toastStyle} onLayout={event_2 => height.set(event_2.nativeEvent.layout.height)}>
89
+ <View ref={webClicks.ref}>{children}</View>
90
+ </Animated.View>
91
+ </GestureDetector>
92
+ </GestureHandlerRootView>
93
+ );
94
+ }