@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,49 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { View, Text } from "react-native";
3
+ import { sizeStyle, textStyle, typeStyle } from "../controlStyles";
4
+ import { useScheme } from "../useScheme";
5
+ import { relaxedSizeStyle } from "./relaxedSizeStyle";
6
+
7
+ /**
8
+ * One labelled control in a `SettingsSection` body, the web stacked
9
+ * `SettingsField`: label `text-sm` medium (14 / 20 / 500) above the control,
10
+ * help text `text-xs leading-relaxed` (12 / 19.5), muted, below it.
11
+ */
12
+ export function SettingsField(t0) {
13
+ const $ = _c(10);
14
+ const {
15
+ label,
16
+ description,
17
+ children
18
+ } = t0;
19
+ const scheme = useScheme();
20
+ let t1;
21
+ if ($[0] !== label || $[1] !== scheme) {
22
+ t1 = typeof label === "string" ? <Text className="mb-2 text-sm font-instrument-sans-medium" style={[textStyle("foreground", scheme), sizeStyle("text-sm"), typeStyle("medium")]}>{label}</Text> : label;
23
+ $[0] = label;
24
+ $[1] = scheme;
25
+ $[2] = t1;
26
+ } else {
27
+ t1 = $[2];
28
+ }
29
+ let t2;
30
+ if ($[3] !== description || $[4] !== scheme) {
31
+ t2 = description != null ? typeof description === "string" ? <Text className="mt-1.5 text-xs leading-relaxed font-instrument-sans" style={[textStyle("muted", scheme), relaxedSizeStyle("text-xs")]}>{description}</Text> : description : null;
32
+ $[3] = description;
33
+ $[4] = scheme;
34
+ $[5] = t2;
35
+ } else {
36
+ t2 = $[5];
37
+ }
38
+ let t3;
39
+ if ($[6] !== children || $[7] !== t1 || $[8] !== t2) {
40
+ t3 = <View>{t1}{children}{t2}</View>;
41
+ $[6] = children;
42
+ $[7] = t1;
43
+ $[8] = t2;
44
+ $[9] = t3;
45
+ } else {
46
+ t3 = $[9];
47
+ }
48
+ return t3;
49
+ }
@@ -0,0 +1,101 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { View, Text } from "react-native";
3
+ import { cn } from "../cn";
4
+ import { cardStyle, sizeStyle, textStyle, typeStyle } from "../controlStyles";
5
+ import { tokens } from "../tokens";
6
+ import { useScheme } from "../useScheme";
7
+ import { relaxedSizeStyle } from "./relaxedSizeStyle";
8
+ export function SettingsSection(t0) {
9
+ const $ = _c(27);
10
+ const {
11
+ title,
12
+ description,
13
+ action,
14
+ footer,
15
+ children,
16
+ bodyVariant: t1,
17
+ className
18
+ } = t0;
19
+ const bodyVariant = t1 === undefined ? "form" : t1;
20
+ const scheme = useScheme();
21
+ const hasBody = children != null;
22
+ const hasCard = hasBody || footer != null;
23
+ let t2;
24
+ if ($[0] !== className) {
25
+ t2 = cn("flex-col gap-2", className);
26
+ $[0] = className;
27
+ $[1] = t2;
28
+ } else {
29
+ t2 = $[1];
30
+ }
31
+ let t3;
32
+ if ($[2] !== scheme || $[3] !== title) {
33
+ t3 = typeof title === "string" ? <Text accessibilityRole="header" className="text-sm font-instrument-sans-semibold" style={[textStyle("foreground", scheme), sizeStyle("text-sm"), typeStyle("semibold")]}>{title}</Text> : title;
34
+ $[2] = scheme;
35
+ $[3] = title;
36
+ $[4] = t3;
37
+ } else {
38
+ t3 = $[4];
39
+ }
40
+ let t4;
41
+ if ($[5] !== description || $[6] !== scheme) {
42
+ t4 = description != null ? typeof description === "string" ? <Text className="mt-0.5 text-sm leading-relaxed font-instrument-sans" style={[textStyle("muted", scheme), relaxedSizeStyle("text-sm")]}>{description}</Text> : description : null;
43
+ $[5] = description;
44
+ $[6] = scheme;
45
+ $[7] = t4;
46
+ } else {
47
+ t4 = $[7];
48
+ }
49
+ let t5;
50
+ if ($[8] !== t3 || $[9] !== t4) {
51
+ t5 = <View className="min-w-0 flex-1">{t3}{t4}</View>;
52
+ $[8] = t3;
53
+ $[9] = t4;
54
+ $[10] = t5;
55
+ } else {
56
+ t5 = $[10];
57
+ }
58
+ let t6;
59
+ if ($[11] !== action) {
60
+ t6 = action != null ? <View className="shrink-0">{action}</View> : null;
61
+ $[11] = action;
62
+ $[12] = t6;
63
+ } else {
64
+ t6 = $[12];
65
+ }
66
+ let t7;
67
+ if ($[13] !== t5 || $[14] !== t6) {
68
+ t7 = <View className="flex-row items-start justify-between gap-4 px-4">{t5}{t6}</View>;
69
+ $[13] = t5;
70
+ $[14] = t6;
71
+ $[15] = t7;
72
+ } else {
73
+ t7 = $[15];
74
+ }
75
+ let t8;
76
+ if ($[16] !== bodyVariant || $[17] !== children || $[18] !== footer || $[19] !== hasBody || $[20] !== hasCard || $[21] !== scheme) {
77
+ t8 = hasCard ? <View className="overflow-hidden" style={cardStyle(scheme)}>{hasBody ? <View className={bodyVariant === "list" ? "flex-col" : bodyVariant === "compact" ? "px-4 py-3" : "px-4 py-5"}>{children}</View> : null}{footer != null ? <View className="flex-row items-center justify-end gap-2 px-4 py-3" style={{
78
+ backgroundColor: tokens.color.surfaceSecondary[scheme]
79
+ }}>{footer}</View> : null}</View> : null;
80
+ $[16] = bodyVariant;
81
+ $[17] = children;
82
+ $[18] = footer;
83
+ $[19] = hasBody;
84
+ $[20] = hasCard;
85
+ $[21] = scheme;
86
+ $[22] = t8;
87
+ } else {
88
+ t8 = $[22];
89
+ }
90
+ let t9;
91
+ if ($[23] !== t2 || $[24] !== t7 || $[25] !== t8) {
92
+ t9 = <View className={t2}>{t7}{t8}</View>;
93
+ $[23] = t2;
94
+ $[24] = t7;
95
+ $[25] = t8;
96
+ $[26] = t9;
97
+ } else {
98
+ t9 = $[26];
99
+ }
100
+ return t9;
101
+ }
@@ -0,0 +1,17 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { View } from "react-native";
3
+ export function SettingsStack(t0) {
4
+ const $ = _c(2);
5
+ const {
6
+ children
7
+ } = t0;
8
+ let t1;
9
+ if ($[0] !== children) {
10
+ t1 = <View className="flex-col gap-8 px-4 pt-2 pb-8">{children}</View>;
11
+ $[0] = children;
12
+ $[1] = t1;
13
+ } else {
14
+ t1 = $[1];
15
+ }
16
+ return t1;
17
+ }
@@ -0,0 +1,163 @@
1
+ import { c as _c } from "react/compiler-runtime";
2
+ import { Pressable, View, Text } from "react-native";
3
+ import { cn } from "../cn";
4
+ import { MIN_TOUCH_TARGET, sizeStyle, textStyle, typeStyle } from "../controlStyles";
5
+ import { useLargerText } from "../theme";
6
+ import { useScheme } from "../useScheme";
7
+ import { relaxedSizeStyle } from "./relaxedSizeStyle";
8
+
9
+ /**
10
+ * One row in a `SettingsSection` list, the web `SettingsToggleRow`: title
11
+ * `text-sm` medium (14 / 20 / 500), description `text-xs leading-relaxed`
12
+ * (12 / 19.5), muted; one step up each with larger text. The web action column
13
+ * is `min-h-10` (40); this one keeps the 44 touch target.
14
+ *
15
+ * With `onCheckedChange` the whole row is the switch, as `LabeledSwitchRow`
16
+ * (the web `<label htmlFor>`): at least 56 high, one `switch` for TalkBack
17
+ * named by the title, with the `action` switch hidden from it.
18
+ */
19
+ export function SettingsToggleRow(t0) {
20
+ const $ = _c(40);
21
+ const {
22
+ title,
23
+ description,
24
+ action,
25
+ checked,
26
+ onCheckedChange,
27
+ disabled: t1,
28
+ accessibilityLabel,
29
+ className
30
+ } = t0;
31
+ const disabled = t1 === undefined ? false : t1;
32
+ const largerText = useLargerText();
33
+ const scheme = useScheme();
34
+ const titleSize = largerText ? "text-base" : "text-sm";
35
+ const descriptionSize = largerText ? "text-sm" : "text-xs";
36
+ let t2;
37
+ if ($[0] !== scheme || $[1] !== title || $[2] !== titleSize) {
38
+ t2 = typeof title === "string" ? <Text className={cn("font-instrument-sans-medium", titleSize)} style={[textStyle("foreground", scheme), sizeStyle(titleSize), typeStyle("medium")]}>{title}</Text> : title;
39
+ $[0] = scheme;
40
+ $[1] = title;
41
+ $[2] = titleSize;
42
+ $[3] = t2;
43
+ } else {
44
+ t2 = $[3];
45
+ }
46
+ let t3;
47
+ if ($[4] !== description || $[5] !== descriptionSize || $[6] !== scheme) {
48
+ t3 = description != null ? typeof description === "string" ? <Text className={cn("mt-1 font-instrument-sans", descriptionSize, "leading-relaxed")} style={[textStyle("muted", scheme), relaxedSizeStyle(descriptionSize)]}>{description}</Text> : description : null;
49
+ $[4] = description;
50
+ $[5] = descriptionSize;
51
+ $[6] = scheme;
52
+ $[7] = t3;
53
+ } else {
54
+ t3 = $[7];
55
+ }
56
+ let t4;
57
+ if ($[8] !== t2 || $[9] !== t3) {
58
+ t4 = <View className="min-w-0 flex-1">{t2}{t3}</View>;
59
+ $[8] = t2;
60
+ $[9] = t3;
61
+ $[10] = t4;
62
+ } else {
63
+ t4 = $[10];
64
+ }
65
+ let t5;
66
+ if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
67
+ t5 = {
68
+ minHeight: MIN_TOUCH_TARGET
69
+ };
70
+ $[11] = t5;
71
+ } else {
72
+ t5 = $[11];
73
+ }
74
+ const t6 = onCheckedChange != null;
75
+ const t7 = onCheckedChange ? "no-hide-descendants" : "auto";
76
+ let t8;
77
+ if ($[12] !== action || $[13] !== t6 || $[14] !== t7) {
78
+ t8 = <View className="shrink-0 items-center justify-center" style={t5} accessibilityElementsHidden={t6} importantForAccessibility={t7}>{action}</View>;
79
+ $[12] = action;
80
+ $[13] = t6;
81
+ $[14] = t7;
82
+ $[15] = t8;
83
+ } else {
84
+ t8 = $[15];
85
+ }
86
+ let t9;
87
+ if ($[16] !== t4 || $[17] !== t8) {
88
+ t9 = <>{t4}{t8}</>;
89
+ $[16] = t4;
90
+ $[17] = t8;
91
+ $[18] = t9;
92
+ } else {
93
+ t9 = $[18];
94
+ }
95
+ const content = t9;
96
+ if (!onCheckedChange) {
97
+ let t10;
98
+ if ($[19] !== className) {
99
+ t10 = cn("flex-row items-center justify-between gap-4 px-4 py-3", className);
100
+ $[19] = className;
101
+ $[20] = t10;
102
+ } else {
103
+ t10 = $[20];
104
+ }
105
+ let t11;
106
+ if ($[21] !== content || $[22] !== t10) {
107
+ t11 = <View className={t10}>{content}</View>;
108
+ $[21] = content;
109
+ $[22] = t10;
110
+ $[23] = t11;
111
+ } else {
112
+ t11 = $[23];
113
+ }
114
+ return t11;
115
+ }
116
+ const t10 = typeof title === "string" ? title : accessibilityLabel;
117
+ const t11 = typeof description === "string" ? description : undefined;
118
+ const t12 = Boolean(checked);
119
+ let t13;
120
+ if ($[24] !== disabled || $[25] !== t12) {
121
+ t13 = {
122
+ checked: t12,
123
+ disabled
124
+ };
125
+ $[24] = disabled;
126
+ $[25] = t12;
127
+ $[26] = t13;
128
+ } else {
129
+ t13 = $[26];
130
+ }
131
+ let t14;
132
+ if ($[27] !== checked || $[28] !== onCheckedChange) {
133
+ t14 = () => onCheckedChange(!checked);
134
+ $[27] = checked;
135
+ $[28] = onCheckedChange;
136
+ $[29] = t14;
137
+ } else {
138
+ t14 = $[29];
139
+ }
140
+ let t15;
141
+ if ($[30] !== className) {
142
+ t15 = cn("flex-row items-center justify-between gap-4 px-4 py-3", "min-h-14", className);
143
+ $[30] = className;
144
+ $[31] = t15;
145
+ } else {
146
+ t15 = $[31];
147
+ }
148
+ let t16;
149
+ if ($[32] !== content || $[33] !== disabled || $[34] !== t10 || $[35] !== t11 || $[36] !== t13 || $[37] !== t14 || $[38] !== t15) {
150
+ t16 = <Pressable accessibilityRole="switch" accessibilityLabel={t10} accessibilityHint={t11} accessibilityState={t13} disabled={disabled} onPress={t14} className={t15}>{content}</Pressable>;
151
+ $[32] = content;
152
+ $[33] = disabled;
153
+ $[34] = t10;
154
+ $[35] = t11;
155
+ $[36] = t13;
156
+ $[37] = t14;
157
+ $[38] = t15;
158
+ $[39] = t16;
159
+ } else {
160
+ t16 = $[39];
161
+ }
162
+ return t16;
163
+ }
@@ -0,0 +1,126 @@
1
+ import { familyApp } from "../brand/familyApps";
2
+
3
+ /** The Project V phone apps, in display order. */
4
+
5
+ /**
6
+ * V Store's home screen. V Store's `app/[id]` route takes the app's Convex
7
+ * document `_id`, not its catalog id or Android package, and native-ui cannot
8
+ * know live Convex ids. So the store step opens V Store's home, not the app's page.
9
+ */
10
+ export const VSTORE_HOME_URL = "vstore://";
11
+
12
+ // Names and sites come from `FAMILY_APPS` where it has the app. V Store is not
13
+ // a family app there (that file is a byte-identical copy of `@vvedantb/ui`).
14
+ const vibot = familyApp("vibot");
15
+ const verve = familyApp("verve");
16
+ const velth = familyApp("velth");
17
+ const vmem = familyApp("vmem");
18
+
19
+ /** The five Project V phone apps, in display order. */
20
+ export const PROJECT_V_MOBILE_APPS = [{
21
+ id: "vibot",
22
+ name: vibot.name,
23
+ description: "AI chat, agents and tools",
24
+ androidPackage: "com.projectvdotuk.vibot",
25
+ scheme: "vibot",
26
+ website: vibot.url
27
+ }, {
28
+ id: "verve",
29
+ name: verve.name,
30
+ description: "Notes, pages and writing",
31
+ androidPackage: "com.projectvdotuk.verve",
32
+ scheme: "verve",
33
+ website: verve.url
34
+ }, {
35
+ id: "velth",
36
+ name: velth.name,
37
+ description: "Health insights and camera scans",
38
+ androidPackage: "com.projectvdotuk.velth",
39
+ scheme: "velth",
40
+ website: velth.url
41
+ }, {
42
+ id: "vmem",
43
+ name: vmem.name,
44
+ description: "Your personal memory",
45
+ androidPackage: "com.projectvdotuk.vmem",
46
+ scheme: "vmem",
47
+ website: vmem.url
48
+ }, {
49
+ id: "vstore",
50
+ name: "V Store",
51
+ description: "Install Project V apps",
52
+ androidPackage: "com.projectvdotuk.vstore",
53
+ scheme: "vstore",
54
+ website: "https://v-store-chi.vercel.app"
55
+ }];
56
+
57
+ /** Entry of `PROJECT_V_MOBILE_APPS` for an app. */
58
+ export function projectVMobileApp(id) {
59
+ return PROJECT_V_MOBILE_APPS.find(app => app.id === id);
60
+ }
61
+
62
+ /** The phone apps other than `current`, in display order. */
63
+ export function otherProjectVMobileApps(current) {
64
+ return PROJECT_V_MOBILE_APPS.filter(app => app.id !== current);
65
+ }
66
+
67
+ /** Android intent URL that opens the installed app with this package. */
68
+ export function androidIntentUrl(app) {
69
+ return `intent://#Intent;scheme=${app.scheme};package=${app.androidPackage};end`;
70
+ }
71
+
72
+ /** How `openProjectVApp` opened an app. */
73
+
74
+ /** One URL to try, in order. `check`: ask `canOpenURL` first; otherwise try `openURL` and move on if it fails. */
75
+
76
+ /**
77
+ * The URLs `openProjectVApp` tries, in order: the app's scheme; on Android an
78
+ * intent to its package; V Store's home (`VSTORE_HOME_URL`); the website.
79
+ */
80
+ export function projectVAppOpenSteps(id, os) {
81
+ const app = projectVMobileApp(id);
82
+ const steps = [{
83
+ target: "app",
84
+ url: `${app.scheme}://`,
85
+ check: true
86
+ }];
87
+ if (os === "android") steps.push({
88
+ target: "app",
89
+ url: androidIntentUrl(app),
90
+ check: false
91
+ });
92
+ if (id !== "vstore") steps.push({
93
+ target: "store",
94
+ url: VSTORE_HOME_URL,
95
+ check: true
96
+ });
97
+ steps.push({
98
+ target: "website",
99
+ url: app.website,
100
+ check: false
101
+ });
102
+ return steps;
103
+ }
104
+
105
+ /** The part of React Native `Linking` that `openProjectVApp` uses. */
106
+
107
+ /**
108
+ * Opens a Project V app: the app if installed, else V Store's home if V Store
109
+ * is installed, else its website. Resolves to what it opened, or
110
+ * `null` when every URL failed. Pass React Native `Linking` and `Platform.OS`.
111
+ *
112
+ * `canOpenURL` needs the schemes declared by the calling app:
113
+ * `LSApplicationQueriesSchemes` on iOS and `<queries>` on Android 11+.
114
+ */
115
+ export async function openProjectVApp(id, linking, os) {
116
+ for (const step of projectVAppOpenSteps(id, os)) {
117
+ try {
118
+ if (step.check && !(await linking.canOpenURL(step.url))) continue;
119
+ await linking.openURL(step.url);
120
+ return step.target;
121
+ } catch {
122
+ // Not installed, or no handler: try the next URL.
123
+ }
124
+ }
125
+ return null;
126
+ }
@@ -0,0 +1,11 @@
1
+ import { sizeStyle } from "../controlStyles";
2
+
3
+ /**
4
+ * `sizeStyle(size)` with the Tailwind `leading-relaxed` line height (1.625 ×
5
+ * the size), for the web settings descriptions (`text-xs leading-relaxed` is
6
+ * 12 / 19.5). Set beside the `leading-relaxed` class. Kept for the settings
7
+ * files; the number lives in `sizeStyle`.
8
+ */
9
+ export function relaxedSizeStyle(size) {
10
+ return sizeStyle(size, "relaxed");
11
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The rules of a bottom sheet's drag to dismiss, as plain numbers, so they
3
+ * stay testable apart from the gesture. Distances are in points, `vy` in
4
+ * points per millisecond (the React Native `PanResponder` unit). Each is a
5
+ * worklet, so the Gesture Handler drag runs them on the UI thread.
6
+ */
7
+
8
+ /** How far ahead (ms) the release velocity carries the sheet when deciding to close. */
9
+ const PROJECTION_MS = 200;
10
+
11
+ /** A flick down at this speed (pt/ms, so 1000 pt/s) closes the sheet however short the drag. */
12
+ const FLICK_VELOCITY = 1;
13
+
14
+ /** How far an upward pull may lift the sheet: less than the corner radius hidden below the screen. */
15
+ export const SHEET_OVERPULL = 12;
16
+
17
+ /** A drag that starts the sheet gesture: down, more vertical than sideways, past a small slop. */
18
+ export function isSheetDragDown(dx, dy) {
19
+ "worklet";
20
+
21
+ return dy > 4 && Math.abs(dy) > Math.abs(dx);
22
+ }
23
+
24
+ /**
25
+ * Where the sheet sits for a drag that would put it `dy` below rest (where
26
+ * the drag started plus the finger's travel): it follows the finger down, and
27
+ * past rest upward it meets growing resistance, up to `SHEET_OVERPULL`.
28
+ */
29
+ export function sheetDragOffset(dy) {
30
+ "worklet";
31
+
32
+ if (dy >= 0) return dy;
33
+ return -SHEET_OVERPULL * (1 - 1 / (1 - dy / (SHEET_OVERPULL * 4)));
34
+ }
35
+
36
+ /**
37
+ * The finger position (window `y`) a drag's travel counts from, so the point
38
+ * the finger holds stays under it: where it touched down, moved down by any
39
+ * scroll the same touch spent bringing the body back to its top before the
40
+ * sheet took over (`scrollAtDown` to `scrollNow`). Without that, the sheet
41
+ * would jump by the scroll when it takes over.
42
+ */
43
+ export function sheetDragAnchor(downY, scrollAtDown, scrollNow) {
44
+ "worklet";
45
+
46
+ return downY + Math.max(0, scrollAtDown - scrollNow);
47
+ }
48
+
49
+ /**
50
+ * Whether a released drag closes the sheet: a quick flick down, or a drag
51
+ * whose position (`dy` below rest), carried on by its speed, passes half the
52
+ * sheet. A slow, short drag springs back.
53
+ */
54
+ export function sheetDragDismisses({
55
+ dy,
56
+ vy,
57
+ height
58
+ }) {
59
+ "worklet";
60
+
61
+ if (dy <= 0) return false;
62
+ if (vy >= FLICK_VELOCITY) return true;
63
+ return dy + Math.max(0, vy) * PROJECTION_MS > height / 2;
64
+ }
65
+
66
+ /**
67
+ * The velocity (pt/s) a sheet springs home with after a release at
68
+ * `position` (its offset from rest, up negative). Speed toward rest carries
69
+ * on; speed away from rest above the top is dropped, so a flick up does not
70
+ * lift the sheet off the bottom edge.
71
+ */
72
+ export function sheetSnapVelocity(position, velocity) {
73
+ "worklet";
74
+
75
+ return position < 0 ? Math.max(0, velocity) : velocity;
76
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Accessibility and test props for a `react-native-svg` `Svg`. React Native
3
+ * Web maps `accessible`, the `accessibility*` props and `testID` on `View`
4
+ * and `Text`, but on web `Svg` is a DOM `<svg>` that takes its props as they
5
+ * are, so React logs each one as an unknown DOM prop. Web gets ARIA and
6
+ * `data-testid`; iOS and Android keep the native props. No React Native
7
+ * import, so the tests can load this file.
8
+ */
9
+
10
+ /**
11
+ * Spread on the `Svg`. With `title` it is an image with that name; without it,
12
+ * it is hidden from assistive tech. Pass `Platform.OS` as `os`. Without
13
+ * `testID` the result has no test id key, not one set to `undefined`.
14
+ */
15
+ export function svgA11yProps({
16
+ title,
17
+ testID
18
+ }, os) {
19
+ if (os === "web") {
20
+ const id = testID === undefined ? {} : {
21
+ "data-testid": testID
22
+ };
23
+ return title ? {
24
+ role: "img",
25
+ "aria-label": title,
26
+ ...id
27
+ } : {
28
+ "aria-hidden": true,
29
+ ...id
30
+ };
31
+ }
32
+ const id = testID === undefined ? {} : {
33
+ testID
34
+ };
35
+ return title ? {
36
+ accessible: true,
37
+ accessibilityRole: "image",
38
+ accessibilityLabel: title,
39
+ ...id
40
+ } : {
41
+ accessible: false,
42
+ accessibilityElementsHidden: true,
43
+ importantForAccessibility: "no-hide-descendants",
44
+ ...id
45
+ };
46
+ }