@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,580 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { useState } from "react";
3
+ import { FlatList, Image, Modal, Pressable, Text, View, useWindowDimensions } from "react-native";
4
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
5
+ import { IconExternalLink, IconX } from "@tabler/icons-react-native";
6
+ import { typeStyle } from "../controlStyles";
7
+ import { IconButton } from "../IconButton";
8
+ import { withAlpha } from "../palette";
9
+ import { tokens } from "../tokens";
10
+ import { useReduceMotion } from "../useReduceMotion";
11
+ import { useScheme } from "../useScheme";
12
+ import { imageAspect, imageGridTiles, imageViewerPage, MEDIA } from "./imageGrid";
13
+ /**
14
+ * The web `ImageGalleryPreview`: one image at its own shape (as wide as the
15
+ * column, at most 384 high), or up to a 2 x 2 grid of 4:3 tiles with "+N" on
16
+ * the fourth. A tap opens `ImageViewer` at that image. Images only; draw
17
+ * videos apart.
18
+ */
19
+ export function ImageGallery(t0) {
20
+ const $ = _c(12);
21
+ const {
22
+ images,
23
+ onOpenImage,
24
+ testID
25
+ } = t0;
26
+ const [viewerIndex, setViewerIndex] = useState(null);
27
+ const first = images[0];
28
+ if (!first) {
29
+ return null;
30
+ }
31
+ let t1;
32
+ if ($[0] !== first || $[1] !== images) {
33
+ t1 = images.length === 1 ? <SingleImage image={first} onOpen={() => setViewerIndex(0)} /> : <ImageGrid images={images} onOpen={setViewerIndex} />;
34
+ $[0] = first;
35
+ $[1] = images;
36
+ $[2] = t1;
37
+ } else {
38
+ t1 = $[2];
39
+ }
40
+ let t2;
41
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
42
+ t2 = () => setViewerIndex(null);
43
+ $[3] = t2;
44
+ } else {
45
+ t2 = $[3];
46
+ }
47
+ let t3;
48
+ if ($[4] !== images || $[5] !== onOpenImage || $[6] !== viewerIndex) {
49
+ t3 = <ImageViewer images={images} index={viewerIndex} onIndexChange={setViewerIndex} onClose={t2} onOpenImage={onOpenImage} />;
50
+ $[4] = images;
51
+ $[5] = onOpenImage;
52
+ $[6] = viewerIndex;
53
+ $[7] = t3;
54
+ } else {
55
+ t3 = $[7];
56
+ }
57
+ let t4;
58
+ if ($[8] !== t1 || $[9] !== t3 || $[10] !== testID) {
59
+ t4 = <View testID={testID} className="w-full">{t1}{t3}</View>;
60
+ $[8] = t1;
61
+ $[9] = t3;
62
+ $[10] = testID;
63
+ $[11] = t4;
64
+ } else {
65
+ t4 = $[11];
66
+ }
67
+ return t4;
68
+ }
69
+
70
+ /** The hairline-ringed, rounded frame of a gallery image or grid. */
71
+ function useMediaFrame() {
72
+ const $ = _c(3);
73
+ const scheme = useScheme();
74
+ const t0 = MEDIA.outline[scheme];
75
+ const t1 = tokens.color.surfaceSecondary[scheme];
76
+ let t2;
77
+ if ($[0] !== t0 || $[1] !== t1) {
78
+ t2 = {
79
+ borderRadius: MEDIA.radius,
80
+ borderWidth: 1,
81
+ borderColor: t0,
82
+ overflow: "hidden",
83
+ backgroundColor: t1
84
+ };
85
+ $[0] = t0;
86
+ $[1] = t1;
87
+ $[2] = t2;
88
+ } else {
89
+ t2 = $[2];
90
+ }
91
+ return t2;
92
+ }
93
+
94
+ /**
95
+ * A lone image, sized from the column and the image's own shape and capped
96
+ * at 384 high, so a tall capture keeps its shape instead of being cropped.
97
+ * Until both are known it holds a full-width 4:3 box.
98
+ */
99
+ function SingleImage(t0) {
100
+ const $ = _c(18);
101
+ const {
102
+ image,
103
+ onOpen
104
+ } = t0;
105
+ const frame = useMediaFrame();
106
+ const [columnWidth, setColumnWidth] = useState(0);
107
+ const [loadedSize, setLoadedSize] = useState(null);
108
+ const aspect = imageAspect(loadedSize);
109
+ const width = columnWidth > 0 ? Math.min(columnWidth, MEDIA.singleMaxHeight * aspect) : undefined;
110
+ let t1;
111
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
112
+ t1 = event => setColumnWidth(event.nativeEvent.layout.width);
113
+ $[0] = t1;
114
+ } else {
115
+ t1 = $[0];
116
+ }
117
+ const t2 = image.alt ?? "Image";
118
+ let t3;
119
+ if ($[1] !== aspect || $[2] !== width) {
120
+ t3 = width === undefined ? {
121
+ width: "100%",
122
+ aspectRatio: aspect
123
+ } : {
124
+ width,
125
+ height: width / aspect
126
+ };
127
+ $[1] = aspect;
128
+ $[2] = width;
129
+ $[3] = t3;
130
+ } else {
131
+ t3 = $[3];
132
+ }
133
+ let t4;
134
+ if ($[4] !== frame || $[5] !== t3) {
135
+ t4 = [frame, t3];
136
+ $[4] = frame;
137
+ $[5] = t3;
138
+ $[6] = t4;
139
+ } else {
140
+ t4 = $[6];
141
+ }
142
+ let t5;
143
+ if ($[7] !== image.url) {
144
+ t5 = {
145
+ uri: image.url
146
+ };
147
+ $[7] = image.url;
148
+ $[8] = t5;
149
+ } else {
150
+ t5 = $[8];
151
+ }
152
+ let t6;
153
+ let t7;
154
+ if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
155
+ t6 = {
156
+ width: "100%",
157
+ height: "100%"
158
+ };
159
+ t7 = event_0 => setLoadedSize(event_0.nativeEvent.source);
160
+ $[9] = t6;
161
+ $[10] = t7;
162
+ } else {
163
+ t6 = $[9];
164
+ t7 = $[10];
165
+ }
166
+ let t8;
167
+ if ($[11] !== t5) {
168
+ t8 = <Image source={t5} resizeMode="cover" style={t6} onLoad={t7} />;
169
+ $[11] = t5;
170
+ $[12] = t8;
171
+ } else {
172
+ t8 = $[12];
173
+ }
174
+ let t9;
175
+ if ($[13] !== onOpen || $[14] !== t2 || $[15] !== t4 || $[16] !== t8) {
176
+ t9 = <View className="w-full" onLayout={t1}><Pressable accessibilityRole="imagebutton" accessibilityLabel={t2} accessibilityHint="Opens full screen" onPress={onOpen} className="active:opacity-90" style={t4}>{t8}</Pressable></View>;
177
+ $[13] = onOpen;
178
+ $[14] = t2;
179
+ $[15] = t4;
180
+ $[16] = t8;
181
+ $[17] = t9;
182
+ } else {
183
+ t9 = $[17];
184
+ }
185
+ return t9;
186
+ }
187
+
188
+ /**
189
+ * Two columns of 4:3 tiles, filled as the web grid's rows are: tiles 0 and 2
190
+ * on the left, 1 and 3 on the right. With three, the first fills the left
191
+ * column, as tall as the two on the right.
192
+ */
193
+ function ImageGrid(t0) {
194
+ const $ = _c(27);
195
+ const {
196
+ images,
197
+ onOpen
198
+ } = t0;
199
+ const frame = useMediaFrame();
200
+ let T0;
201
+ let T1;
202
+ let t1;
203
+ let t2;
204
+ let t3;
205
+ let t4;
206
+ if ($[0] !== frame || $[1] !== images || $[2] !== onOpen) {
207
+ const tiles = imageGridTiles(images.length);
208
+ const spans = tiles[0]?.spansColumn === true;
209
+ const left = spans ? tiles.slice(0, 1) : tiles.filter(_temp);
210
+ const right = spans ? tiles.slice(1) : tiles.filter(_temp2);
211
+ let t5;
212
+ if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
213
+ t5 = {
214
+ width: "100%",
215
+ aspectRatio: MEDIA.tileAspect
216
+ };
217
+ $[9] = t5;
218
+ } else {
219
+ t5 = $[9];
220
+ }
221
+ const tileStyle = t5;
222
+ let t6;
223
+ if ($[10] !== images || $[11] !== onOpen) {
224
+ t6 = tile_1 => {
225
+ const image = images[tile_1.index];
226
+ if (!image) {
227
+ return null;
228
+ }
229
+ const name = image.alt ?? `Image ${tile_1.index + 1}`;
230
+ return <Pressable key={tile_1.index} accessibilityRole="imagebutton" accessibilityLabel={tile_1.overflow > 0 ? `${name}, ${tile_1.overflow} more` : name} accessibilityHint="Opens full screen" onPress={() => onOpen(tile_1.index)} className="active:opacity-90" style={tile_1.spansColumn ? {
231
+ width: "100%",
232
+ flex: 1
233
+ } : tileStyle}><Image source={{
234
+ uri: image.url
235
+ }} resizeMode="cover" style={{
236
+ width: "100%",
237
+ height: "100%"
238
+ }} />{tile_1.overflow > 0 ? <View className="absolute inset-0 items-center justify-center" style={{
239
+ backgroundColor: withAlpha(tokens.color.black, 0.6)
240
+ }}><Text className="font-instrument-sans-semibold text-xl" style={[{
241
+ color: tokens.color.white
242
+ }, typeStyle("semibold")]}>{`+${tile_1.overflow}`}</Text></View> : null}</Pressable>;
243
+ };
244
+ $[10] = images;
245
+ $[11] = onOpen;
246
+ $[12] = t6;
247
+ } else {
248
+ t6 = $[12];
249
+ }
250
+ const cell = t6;
251
+ T1 = View;
252
+ let t7;
253
+ if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
254
+ t7 = {
255
+ flexDirection: "row",
256
+ gap: MEDIA.gap
257
+ };
258
+ $[13] = t7;
259
+ } else {
260
+ t7 = $[13];
261
+ }
262
+ if ($[14] !== frame) {
263
+ t3 = [frame, t7];
264
+ $[14] = frame;
265
+ $[15] = t3;
266
+ } else {
267
+ t3 = $[15];
268
+ }
269
+ let t8;
270
+ if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
271
+ t8 = {
272
+ flex: 1,
273
+ gap: MEDIA.gap
274
+ };
275
+ $[16] = t8;
276
+ } else {
277
+ t8 = $[16];
278
+ }
279
+ t4 = <View style={t8}>{left.map(cell)}</View>;
280
+ T0 = View;
281
+ if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
282
+ t1 = {
283
+ flex: 1,
284
+ gap: MEDIA.gap
285
+ };
286
+ $[17] = t1;
287
+ } else {
288
+ t1 = $[17];
289
+ }
290
+ t2 = right.map(cell);
291
+ $[0] = frame;
292
+ $[1] = images;
293
+ $[2] = onOpen;
294
+ $[3] = T0;
295
+ $[4] = T1;
296
+ $[5] = t1;
297
+ $[6] = t2;
298
+ $[7] = t3;
299
+ $[8] = t4;
300
+ } else {
301
+ T0 = $[3];
302
+ T1 = $[4];
303
+ t1 = $[5];
304
+ t2 = $[6];
305
+ t3 = $[7];
306
+ t4 = $[8];
307
+ }
308
+ let t5;
309
+ if ($[18] !== T0 || $[19] !== t1 || $[20] !== t2) {
310
+ t5 = <T0 style={t1}>{t2}</T0>;
311
+ $[18] = T0;
312
+ $[19] = t1;
313
+ $[20] = t2;
314
+ $[21] = t5;
315
+ } else {
316
+ t5 = $[21];
317
+ }
318
+ let t6;
319
+ if ($[22] !== T1 || $[23] !== t3 || $[24] !== t4 || $[25] !== t5) {
320
+ t6 = <T1 style={t3}>{t4}{t5}</T1>;
321
+ $[22] = T1;
322
+ $[23] = t3;
323
+ $[24] = t4;
324
+ $[25] = t5;
325
+ $[26] = t6;
326
+ } else {
327
+ t6 = $[26];
328
+ }
329
+ return t6;
330
+ }
331
+ function _temp2(tile_0) {
332
+ return tile_0.index % 2 === 1;
333
+ }
334
+ function _temp(tile) {
335
+ return tile.index % 2 === 0;
336
+ }
337
+ /**
338
+ * The web `ImageLightbox` on a phone: the images full screen on black, one
339
+ * page each, swiped sideways (TalkBack and VoiceOver step with the adjustable
340
+ * actions). Close (X, or Android back) and "Open in browser" sit at the top,
341
+ * "2 / 5" at the bottom when there is more than one. No pinch zoom. It fades
342
+ * in, or appears at once with Reduce Motion.
343
+ */
344
+ export function ImageViewer(t0) {
345
+ const $ = _c(10);
346
+ const {
347
+ images,
348
+ index,
349
+ onIndexChange,
350
+ onClose,
351
+ onOpenImage
352
+ } = t0;
353
+ const reduceMotion = useReduceMotion();
354
+ if (index === null) {
355
+ return null;
356
+ }
357
+ const t1 = reduceMotion ? "none" : "fade";
358
+ let t2;
359
+ if ($[0] !== images || $[1] !== index || $[2] !== onClose || $[3] !== onIndexChange || $[4] !== onOpenImage) {
360
+ t2 = <ViewerPages images={images} index={index} onIndexChange={onIndexChange} onClose={onClose} onOpenImage={onOpenImage} />;
361
+ $[0] = images;
362
+ $[1] = index;
363
+ $[2] = onClose;
364
+ $[3] = onIndexChange;
365
+ $[4] = onOpenImage;
366
+ $[5] = t2;
367
+ } else {
368
+ t2 = $[5];
369
+ }
370
+ let t3;
371
+ if ($[6] !== onClose || $[7] !== t1 || $[8] !== t2) {
372
+ t3 = <Modal visible={true} transparent={true} statusBarTranslucent={true} animationType={t1} onRequestClose={onClose}>{t2}</Modal>;
373
+ $[6] = onClose;
374
+ $[7] = t1;
375
+ $[8] = t2;
376
+ $[9] = t3;
377
+ } else {
378
+ t3 = $[9];
379
+ }
380
+ return t3;
381
+ }
382
+ function ViewerPages(t0) {
383
+ const $ = _c(48);
384
+ const {
385
+ images,
386
+ index,
387
+ onIndexChange,
388
+ onClose,
389
+ onOpenImage
390
+ } = t0;
391
+ const {
392
+ width,
393
+ height
394
+ } = useWindowDimensions();
395
+ const insets = useSafeAreaInsets();
396
+ const count = images.length;
397
+ const current = images[index];
398
+ const white = tokens.color.white;
399
+ let t1;
400
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
401
+ t1 = {
402
+ backgroundColor: withAlpha(tokens.color.black, 0.92)
403
+ };
404
+ $[0] = t1;
405
+ } else {
406
+ t1 = $[0];
407
+ }
408
+ let t2;
409
+ if ($[1] !== width) {
410
+ t2 = (_, item) => ({
411
+ length: width,
412
+ offset: width * item,
413
+ index: item
414
+ });
415
+ $[1] = width;
416
+ $[2] = t2;
417
+ } else {
418
+ t2 = $[2];
419
+ }
420
+ let t3;
421
+ if ($[3] !== count || $[4] !== onIndexChange || $[5] !== width) {
422
+ t3 = event => onIndexChange(imageViewerPage(event.nativeEvent.contentOffset.x, width, count));
423
+ $[3] = count;
424
+ $[4] = onIndexChange;
425
+ $[5] = width;
426
+ $[6] = t3;
427
+ } else {
428
+ t3 = $[6];
429
+ }
430
+ let t4;
431
+ if ($[7] !== height || $[8] !== width) {
432
+ t4 = t5 => {
433
+ const {
434
+ item: item_1
435
+ } = t5;
436
+ return <View style={{
437
+ width,
438
+ height
439
+ }} className="items-center justify-center"><Image source={{
440
+ uri: item_1.url
441
+ }} resizeMode="contain" style={{
442
+ width: "100%",
443
+ height: "100%"
444
+ }} accessibilityLabel={item_1.alt ?? "Image"} /></View>;
445
+ };
446
+ $[7] = height;
447
+ $[8] = width;
448
+ $[9] = t4;
449
+ } else {
450
+ t4 = $[9];
451
+ }
452
+ const t5 = current?.alt ?? "Image";
453
+ let t6;
454
+ if ($[10] !== count || $[11] !== index) {
455
+ t6 = count > 1 ? {
456
+ text: `${index + 1} of ${count}`
457
+ } : undefined;
458
+ $[10] = count;
459
+ $[11] = index;
460
+ $[12] = t6;
461
+ } else {
462
+ t6 = $[12];
463
+ }
464
+ let t7;
465
+ if ($[13] !== count) {
466
+ t7 = count > 1 ? [{
467
+ name: "increment"
468
+ }, {
469
+ name: "decrement"
470
+ }] : undefined;
471
+ $[13] = count;
472
+ $[14] = t7;
473
+ } else {
474
+ t7 = $[14];
475
+ }
476
+ let t8;
477
+ if ($[15] !== count || $[16] !== index || $[17] !== onIndexChange) {
478
+ t8 = event_0 => {
479
+ const next = event_0.nativeEvent.actionName === "increment" ? index + 1 : index - 1;
480
+ if (next >= 0 && next < count) {
481
+ onIndexChange(next);
482
+ }
483
+ };
484
+ $[15] = count;
485
+ $[16] = index;
486
+ $[17] = onIndexChange;
487
+ $[18] = t8;
488
+ } else {
489
+ t8 = $[18];
490
+ }
491
+ let t9;
492
+ if ($[19] !== images || $[20] !== index || $[21] !== t2 || $[22] !== t3 || $[23] !== t4 || $[24] !== t5 || $[25] !== t6 || $[26] !== t7 || $[27] !== t8) {
493
+ t9 = <FlatList data={images} horizontal={true} pagingEnabled={true} showsHorizontalScrollIndicator={false} initialScrollIndex={index} getItemLayout={t2} keyExtractor={_temp3} onMomentumScrollEnd={t3} renderItem={t4} accessibilityRole="adjustable" accessibilityLabel={t5} accessibilityValue={t6} accessibilityActions={t7} onAccessibilityAction={t8} />;
494
+ $[19] = images;
495
+ $[20] = index;
496
+ $[21] = t2;
497
+ $[22] = t3;
498
+ $[23] = t4;
499
+ $[24] = t5;
500
+ $[25] = t6;
501
+ $[26] = t7;
502
+ $[27] = t8;
503
+ $[28] = t9;
504
+ } else {
505
+ t9 = $[28];
506
+ }
507
+ const t10 = insets.top + 8;
508
+ let t11;
509
+ if ($[29] !== t10) {
510
+ t11 = {
511
+ top: t10
512
+ };
513
+ $[29] = t10;
514
+ $[30] = t11;
515
+ } else {
516
+ t11 = $[30];
517
+ }
518
+ let t12;
519
+ if ($[31] !== current || $[32] !== onOpenImage) {
520
+ t12 = onOpenImage && current ? <Pressable accessibilityRole="link" onPress={() => onOpenImage(current.url)} className="min-h-11 flex-row items-center gap-1.5 rounded-full px-3 active:opacity-70" style={{
521
+ backgroundColor: withAlpha(tokens.color.black, 0.6)
522
+ }}><IconExternalLink size={16} color={white} /><Text className="font-instrument-sans text-sm" style={{
523
+ color: white
524
+ }}>Open in browser</Text></Pressable> : <View />;
525
+ $[31] = current;
526
+ $[32] = onOpenImage;
527
+ $[33] = t12;
528
+ } else {
529
+ t12 = $[33];
530
+ }
531
+ let t13;
532
+ if ($[34] !== onClose) {
533
+ t13 = <IconButton icon={IconX} label="Close" variant="overlay" size="lg" onPress={onClose} />;
534
+ $[34] = onClose;
535
+ $[35] = t13;
536
+ } else {
537
+ t13 = $[35];
538
+ }
539
+ let t14;
540
+ if ($[36] !== t11 || $[37] !== t12 || $[38] !== t13) {
541
+ t14 = <View className="absolute left-0 right-0 flex-row items-center justify-between px-3" style={t11}>{t12}{t13}</View>;
542
+ $[36] = t11;
543
+ $[37] = t12;
544
+ $[38] = t13;
545
+ $[39] = t14;
546
+ } else {
547
+ t14 = $[39];
548
+ }
549
+ let t15;
550
+ if ($[40] !== count || $[41] !== index || $[42] !== insets.bottom) {
551
+ t15 = count > 1 ? <View className="absolute left-0 right-0 items-center" style={{
552
+ bottom: insets.bottom + 16
553
+ }} pointerEvents="none"><View className="rounded-full px-3 py-1" style={{
554
+ backgroundColor: withAlpha(tokens.color.black, 0.6)
555
+ }}><Text className="font-instrument-sans text-sm" style={{
556
+ color: white,
557
+ fontVariant: ["tabular-nums"]
558
+ }}>{`${index + 1} / ${count}`}</Text></View></View> : null;
559
+ $[40] = count;
560
+ $[41] = index;
561
+ $[42] = insets.bottom;
562
+ $[43] = t15;
563
+ } else {
564
+ t15 = $[43];
565
+ }
566
+ let t16;
567
+ if ($[44] !== t14 || $[45] !== t15 || $[46] !== t9) {
568
+ t16 = <View className="flex-1" style={t1}>{t9}{t14}{t15}</View>;
569
+ $[44] = t14;
570
+ $[45] = t15;
571
+ $[46] = t9;
572
+ $[47] = t16;
573
+ } else {
574
+ t16 = $[47];
575
+ }
576
+ return t16;
577
+ }
578
+ function _temp3(image, item_0) {
579
+ return `${item_0}:${image.url}`;
580
+ }