@farcaster/snap 1.5.2 → 1.7.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 (208) hide show
  1. package/dist/constants.d.ts +0 -107
  2. package/dist/constants.js +0 -148
  3. package/dist/dataStore.d.ts +12 -0
  4. package/dist/dataStore.js +35 -0
  5. package/dist/index.d.ts +5 -3
  6. package/dist/index.js +4 -3
  7. package/dist/react/accent-context.d.ts +6 -0
  8. package/dist/react/accent-context.js +10 -0
  9. package/dist/react/catalog-renderer.d.ts +5 -0
  10. package/dist/react/catalog-renderer.js +37 -0
  11. package/dist/react/components/action-button.d.ts +6 -0
  12. package/dist/react/components/action-button.js +22 -0
  13. package/dist/react/components/badge.d.ts +5 -0
  14. package/dist/react/components/badge.js +18 -0
  15. package/dist/react/components/icon.d.ts +7 -0
  16. package/dist/react/components/icon.js +60 -0
  17. package/dist/react/components/image.d.ts +5 -0
  18. package/dist/react/components/image.js +15 -0
  19. package/dist/react/components/input.d.ts +5 -0
  20. package/dist/react/components/input.js +18 -0
  21. package/dist/react/components/item-group.d.ts +7 -0
  22. package/dist/react/components/item-group.js +17 -0
  23. package/dist/react/components/item.d.ts +7 -0
  24. package/dist/react/components/item.js +9 -0
  25. package/dist/react/components/progress.d.ts +5 -0
  26. package/dist/react/components/progress.js +11 -0
  27. package/dist/react/components/separator.d.ts +5 -0
  28. package/dist/react/components/separator.js +7 -0
  29. package/dist/react/components/slider.d.ts +5 -0
  30. package/dist/react/components/slider.js +21 -0
  31. package/dist/react/components/stack.d.ts +7 -0
  32. package/dist/react/components/stack.js +32 -0
  33. package/dist/react/components/switch.d.ts +5 -0
  34. package/dist/react/components/switch.js +23 -0
  35. package/dist/react/components/text.d.ts +5 -0
  36. package/dist/react/components/text.js +25 -0
  37. package/dist/react/components/toggle-group.d.ts +5 -0
  38. package/dist/react/components/toggle-group.js +52 -0
  39. package/dist/react/hooks/use-snap-accent.d.ts +13 -0
  40. package/dist/react/hooks/use-snap-accent.js +32 -0
  41. package/dist/react/index.d.ts +47 -0
  42. package/dist/react/index.js +191 -0
  43. package/dist/react/lib/preview-primary-css.d.ts +6 -0
  44. package/dist/react/lib/preview-primary-css.js +43 -0
  45. package/dist/react/lib/resolve-palette-hex.d.ts +2 -0
  46. package/dist/react/lib/resolve-palette-hex.js +10 -0
  47. package/dist/react-native/catalog-renderer.d.ts +5 -0
  48. package/dist/react-native/catalog-renderer.js +36 -0
  49. package/dist/react-native/components/snap-action-button.d.ts +2 -0
  50. package/dist/react-native/components/snap-action-button.js +68 -0
  51. package/dist/react-native/components/snap-badge.d.ts +2 -0
  52. package/dist/react-native/components/snap-badge.js +38 -0
  53. package/dist/react-native/components/snap-icon.d.ts +5 -0
  54. package/dist/react-native/components/snap-icon.js +56 -0
  55. package/dist/react-native/components/snap-image.d.ts +2 -0
  56. package/dist/react-native/components/snap-image.js +24 -0
  57. package/dist/react-native/components/snap-input.d.ts +2 -0
  58. package/dist/react-native/components/snap-input.js +36 -0
  59. package/dist/react-native/components/snap-item-group.d.ts +5 -0
  60. package/dist/react-native/components/snap-item-group.js +23 -0
  61. package/dist/react-native/components/snap-item.d.ts +5 -0
  62. package/dist/react-native/components/snap-item.js +45 -0
  63. package/dist/react-native/components/snap-progress.d.ts +2 -0
  64. package/dist/react-native/components/snap-progress.js +26 -0
  65. package/dist/react-native/components/snap-separator.d.ts +2 -0
  66. package/dist/react-native/components/snap-separator.js +23 -0
  67. package/dist/react-native/components/snap-slider.d.ts +2 -0
  68. package/dist/react-native/components/snap-slider.js +42 -0
  69. package/dist/react-native/components/snap-stack.d.ts +5 -0
  70. package/dist/react-native/components/snap-stack.js +49 -0
  71. package/dist/react-native/components/snap-switch.d.ts +2 -0
  72. package/dist/react-native/components/snap-switch.js +30 -0
  73. package/dist/react-native/components/snap-text.d.ts +2 -0
  74. package/dist/react-native/components/snap-text.js +37 -0
  75. package/dist/react-native/components/snap-toggle-group.d.ts +2 -0
  76. package/dist/react-native/components/snap-toggle-group.js +100 -0
  77. package/dist/react-native/index.d.ts +52 -0
  78. package/dist/react-native/index.js +155 -0
  79. package/dist/react-native/theme.d.ts +21 -0
  80. package/dist/react-native/theme.js +37 -0
  81. package/dist/react-native/use-snap-palette.d.ts +13 -0
  82. package/dist/react-native/use-snap-palette.js +48 -0
  83. package/dist/schemas.d.ts +14 -1629
  84. package/dist/schemas.js +14 -526
  85. package/dist/ui/badge.d.ts +52 -0
  86. package/dist/ui/badge.js +9 -0
  87. package/dist/ui/button.d.ts +42 -28
  88. package/dist/ui/button.js +7 -9
  89. package/dist/ui/catalog.d.ts +281 -156
  90. package/dist/ui/catalog.js +102 -83
  91. package/dist/ui/icon.d.ts +56 -0
  92. package/dist/ui/icon.js +51 -0
  93. package/dist/ui/image.d.ts +1 -0
  94. package/dist/ui/image.js +2 -2
  95. package/dist/ui/index.d.ts +20 -22
  96. package/dist/ui/index.js +10 -11
  97. package/dist/ui/input.d.ts +17 -0
  98. package/dist/ui/input.js +13 -0
  99. package/dist/ui/item-group.d.ts +12 -0
  100. package/dist/ui/item-group.js +7 -0
  101. package/dist/ui/item.d.ts +14 -0
  102. package/dist/ui/item.js +9 -0
  103. package/dist/ui/progress.d.ts +1 -11
  104. package/dist/ui/progress.js +21 -4
  105. package/dist/ui/schema.d.ts +1 -1
  106. package/dist/ui/schema.js +3 -3
  107. package/dist/ui/separator.d.ts +9 -0
  108. package/dist/ui/separator.js +5 -0
  109. package/dist/ui/slider.d.ts +4 -3
  110. package/dist/ui/slider.js +34 -5
  111. package/dist/ui/stack.d.ts +22 -1
  112. package/dist/ui/stack.js +8 -1
  113. package/dist/ui/switch.d.ts +8 -0
  114. package/dist/ui/switch.js +7 -0
  115. package/dist/ui/text.d.ts +15 -7
  116. package/dist/ui/text.js +8 -4
  117. package/dist/ui/toggle-group.d.ts +23 -0
  118. package/dist/ui/toggle-group.js +19 -0
  119. package/dist/validator.d.ts +5 -1
  120. package/dist/validator.js +6 -136
  121. package/package.json +78 -53
  122. package/src/constants.ts +0 -179
  123. package/src/dataStore.ts +62 -0
  124. package/src/index.ts +10 -20
  125. package/src/react/accent-context.tsx +29 -0
  126. package/src/react/catalog-renderer.tsx +39 -0
  127. package/src/react/components/action-button.tsx +48 -0
  128. package/src/react/components/badge.tsx +37 -0
  129. package/src/react/components/icon.tsx +115 -0
  130. package/src/react/components/image.tsx +33 -0
  131. package/src/react/components/input.tsx +36 -0
  132. package/src/react/components/item-group.tsx +43 -0
  133. package/src/react/components/item.tsx +33 -0
  134. package/src/react/components/progress.tsx +29 -0
  135. package/src/react/components/separator.tsx +14 -0
  136. package/src/react/components/slider.tsx +43 -0
  137. package/src/react/components/stack.tsx +55 -0
  138. package/src/react/components/switch.tsx +46 -0
  139. package/src/react/components/text.tsx +43 -0
  140. package/src/react/components/toggle-group.tsx +85 -0
  141. package/src/react/hooks/use-snap-accent.ts +45 -0
  142. package/src/react/index.tsx +321 -0
  143. package/src/react/lib/preview-primary-css.ts +57 -0
  144. package/src/react/lib/resolve-palette-hex.ts +20 -0
  145. package/src/react-native/catalog-renderer.tsx +37 -0
  146. package/src/react-native/components/snap-action-button.tsx +92 -0
  147. package/src/react-native/components/snap-badge.tsx +57 -0
  148. package/src/react-native/components/snap-icon.tsx +102 -0
  149. package/src/react-native/components/snap-image.tsx +38 -0
  150. package/src/react-native/components/snap-input.tsx +57 -0
  151. package/src/react-native/components/snap-item-group.tsx +43 -0
  152. package/src/react-native/components/snap-item.tsx +70 -0
  153. package/src/react-native/components/snap-progress.tsx +40 -0
  154. package/src/react-native/components/snap-separator.tsx +32 -0
  155. package/src/react-native/components/snap-slider.tsx +82 -0
  156. package/src/react-native/components/snap-stack.tsx +66 -0
  157. package/src/react-native/components/snap-switch.tsx +45 -0
  158. package/src/react-native/components/snap-text.tsx +53 -0
  159. package/src/react-native/components/snap-toggle-group.tsx +128 -0
  160. package/src/react-native/index.tsx +267 -0
  161. package/src/react-native/theme.tsx +73 -0
  162. package/src/react-native/use-snap-palette.ts +64 -0
  163. package/src/schemas.ts +18 -644
  164. package/src/ui/badge.ts +13 -0
  165. package/src/ui/button.ts +9 -12
  166. package/src/ui/catalog.ts +106 -86
  167. package/src/ui/icon.ts +56 -0
  168. package/src/ui/image.ts +3 -2
  169. package/src/ui/index.ts +26 -29
  170. package/src/ui/input.ts +17 -0
  171. package/src/ui/item-group.ts +11 -0
  172. package/src/ui/item.ts +13 -0
  173. package/src/ui/progress.ts +25 -7
  174. package/src/ui/schema.ts +3 -3
  175. package/src/ui/separator.ts +9 -0
  176. package/src/ui/slider.ts +40 -10
  177. package/src/ui/stack.ts +9 -1
  178. package/src/ui/switch.ts +11 -0
  179. package/src/ui/text.ts +9 -4
  180. package/src/ui/toggle-group.ts +23 -0
  181. package/src/validator.ts +6 -176
  182. package/dist/ui/bar-chart.d.ts +0 -30
  183. package/dist/ui/bar-chart.js +0 -15
  184. package/dist/ui/button-group.d.ts +0 -19
  185. package/dist/ui/button-group.js +0 -18
  186. package/dist/ui/divider.d.ts +0 -3
  187. package/dist/ui/divider.js +0 -2
  188. package/dist/ui/grid.d.ts +0 -22
  189. package/dist/ui/grid.js +0 -16
  190. package/dist/ui/group.d.ts +0 -7
  191. package/dist/ui/group.js +0 -5
  192. package/dist/ui/list.d.ts +0 -13
  193. package/dist/ui/list.js +0 -13
  194. package/dist/ui/spacer.d.ts +0 -9
  195. package/dist/ui/spacer.js +0 -5
  196. package/dist/ui/text-input.d.ts +0 -7
  197. package/dist/ui/text-input.js +0 -12
  198. package/dist/ui/toggle.d.ts +0 -7
  199. package/dist/ui/toggle.js +0 -6
  200. package/src/ui/bar-chart.ts +0 -20
  201. package/src/ui/button-group.ts +0 -26
  202. package/src/ui/divider.ts +0 -5
  203. package/src/ui/grid.ts +0 -25
  204. package/src/ui/group.ts +0 -8
  205. package/src/ui/list.ts +0 -17
  206. package/src/ui/spacer.ts +0 -8
  207. package/src/ui/text-input.ts +0 -15
  208. package/src/ui/toggle.ts +0 -9
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Pressable, StyleSheet, Text, View } from "react-native";
3
+ import { useSnapPalette } from "../use-snap-palette.js";
4
+ import { useSnapTheme } from "../theme.js";
5
+ import { ICON_MAP } from "./snap-icon.js";
6
+ const VARIANT_MAP = {
7
+ default: "default",
8
+ secondary: "secondary",
9
+ outline: "outline",
10
+ ghost: "ghost",
11
+ };
12
+ export function SnapActionButton({ element: { props }, emit, }) {
13
+ const { accentHex } = useSnapPalette();
14
+ const { colors } = useSnapTheme();
15
+ const label = String(props.label ?? "Action");
16
+ const variant = VARIANT_MAP[String(props.variant ?? "default")] ?? "default";
17
+ const iconName = props.icon ? String(props.icon) : undefined;
18
+ const variantStyle = (() => {
19
+ switch (variant) {
20
+ case "default":
21
+ return { backgroundColor: accentHex };
22
+ case "secondary":
23
+ return { backgroundColor: "transparent", borderWidth: 1.5, borderColor: accentHex };
24
+ case "outline":
25
+ return { backgroundColor: "rgba(255,255,255,0.04)", borderWidth: 1, borderColor: colors.border };
26
+ case "ghost":
27
+ return { backgroundColor: "transparent" };
28
+ }
29
+ })();
30
+ const textColor = variant === "default" ? "#fff" : variant === "secondary" ? accentHex : colors.text;
31
+ const iconColor = variant === "default" ? "#fff" : variant === "secondary" ? accentHex : colors.text;
32
+ return (_jsx(View, { style: styles.outer, children: _jsxs(Pressable, { style: ({ pressed }) => [
33
+ styles.btn,
34
+ variant === "default" ? styles.btnDefault : styles.btnOther,
35
+ variantStyle,
36
+ pressed && styles.pressed,
37
+ ], onPress: () => {
38
+ void (async () => {
39
+ try {
40
+ await emit("press");
41
+ }
42
+ catch (err) {
43
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
44
+ // eslint-disable-next-line no-console
45
+ console.error("[snap] action failed", err);
46
+ }
47
+ }
48
+ })();
49
+ }, children: [iconName && ICON_MAP[iconName] ? ((() => { const I = ICON_MAP[iconName]; return _jsx(I, { size: 16, color: iconColor }); })()) : null, _jsx(Text, { style: { color: textColor, fontSize: 14, fontWeight: "600" }, children: label })] }) }));
50
+ }
51
+ const styles = StyleSheet.create({
52
+ outer: { flex: 1, minWidth: 0 },
53
+ btn: {
54
+ paddingHorizontal: 16,
55
+ borderRadius: 10,
56
+ alignItems: "center",
57
+ justifyContent: "center",
58
+ flexDirection: "row",
59
+ gap: 8,
60
+ },
61
+ btnDefault: {
62
+ paddingVertical: 10,
63
+ },
64
+ btnOther: {
65
+ paddingVertical: 8,
66
+ },
67
+ pressed: { opacity: 0.88 },
68
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapBadge({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { StyleSheet, Text, View } from "react-native";
3
+ import { useSnapPalette } from "../use-snap-palette.js";
4
+ import { ICON_MAP } from "./snap-icon.js";
5
+ export function SnapBadge({ element: { props }, }) {
6
+ const { accentHex, hex } = useSnapPalette();
7
+ const label = String(props.label ?? "");
8
+ const color = props.color ? String(props.color) : undefined;
9
+ const iconName = props.icon ? String(props.icon) : undefined;
10
+ const isAccent = !color || color === "accent";
11
+ const resolvedColor = isAccent ? accentHex : hex(color);
12
+ const Icon = iconName ? ICON_MAP[iconName] : undefined;
13
+ return (_jsxs(View, { style: [
14
+ styles.badge,
15
+ isAccent
16
+ ? { backgroundColor: resolvedColor, borderColor: resolvedColor }
17
+ : { borderColor: resolvedColor },
18
+ ], children: [Icon && (_jsx(Icon, { size: 12, color: isAccent ? "#fff" : resolvedColor })), _jsx(Text, { style: [
19
+ styles.label,
20
+ { color: isAccent ? "#fff" : resolvedColor },
21
+ ], children: label })] }));
22
+ }
23
+ const styles = StyleSheet.create({
24
+ badge: {
25
+ alignSelf: "flex-start",
26
+ flexDirection: "row",
27
+ alignItems: "center",
28
+ gap: 4,
29
+ paddingHorizontal: 8,
30
+ paddingVertical: 2,
31
+ borderRadius: 9999,
32
+ borderWidth: 1,
33
+ },
34
+ label: {
35
+ fontSize: 12,
36
+ fontWeight: "500",
37
+ },
38
+ });
@@ -0,0 +1,5 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ import { type LucideIcon } from "lucide-react-native";
3
+ declare const ICON_MAP: Record<string, LucideIcon>;
4
+ export declare function SnapIcon({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
5
+ export { ICON_MAP };
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { View } from "react-native";
3
+ import { useSnapPalette } from "../use-snap-palette.js";
4
+ import { ArrowRight, ArrowLeft, ExternalLink, ChevronRight, Check, X, AlertTriangle, Info, Clock, Heart, MessageCircle, Repeat, Share, User, Users, Star, Trophy, Zap, Flame, Gift, ImageIcon, Play, Pause, Wallet, Coins, Plus, Minus, RefreshCw, Bookmark, ThumbsUp, ThumbsDown, TrendingUp, TrendingDown, } from "lucide-react-native";
5
+ const ICON_MAP = {
6
+ "arrow-right": ArrowRight,
7
+ "arrow-left": ArrowLeft,
8
+ "external-link": ExternalLink,
9
+ "chevron-right": ChevronRight,
10
+ check: Check,
11
+ x: X,
12
+ "alert-triangle": AlertTriangle,
13
+ info: Info,
14
+ clock: Clock,
15
+ heart: Heart,
16
+ "message-circle": MessageCircle,
17
+ repeat: Repeat,
18
+ share: Share,
19
+ user: User,
20
+ users: Users,
21
+ star: Star,
22
+ trophy: Trophy,
23
+ zap: Zap,
24
+ flame: Flame,
25
+ gift: Gift,
26
+ image: ImageIcon,
27
+ play: Play,
28
+ pause: Pause,
29
+ wallet: Wallet,
30
+ coins: Coins,
31
+ plus: Plus,
32
+ minus: Minus,
33
+ "refresh-cw": RefreshCw,
34
+ bookmark: Bookmark,
35
+ "thumbs-up": ThumbsUp,
36
+ "thumbs-down": ThumbsDown,
37
+ "trending-up": TrendingUp,
38
+ "trending-down": TrendingDown,
39
+ };
40
+ const SIZE_PX = {
41
+ sm: 16,
42
+ md: 20,
43
+ };
44
+ export function SnapIcon({ element: { props }, }) {
45
+ const { accentHex, hex } = useSnapPalette();
46
+ const name = String(props.name ?? "info");
47
+ const size = SIZE_PX[String(props.size ?? "md")] ?? 20;
48
+ const color = props.color ? String(props.color) : undefined;
49
+ const isAccent = !color || color === "accent";
50
+ const resolvedColor = isAccent ? accentHex : hex(color);
51
+ const Icon = ICON_MAP[name];
52
+ if (!Icon)
53
+ return null;
54
+ return (_jsx(View, { style: { alignItems: "center", justifyContent: "center" }, children: _jsx(Icon, { size: size, color: resolvedColor }) }));
55
+ }
56
+ export { ICON_MAP };
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapImage({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Image } from "expo-image";
3
+ import { StyleSheet, View } from "react-native";
4
+ function aspectToRatio(aspect) {
5
+ const [w, h] = aspect.split(":").map(Number);
6
+ if (!w || !h)
7
+ return 1;
8
+ return w / h;
9
+ }
10
+ export function SnapImage({ element: { props }, }) {
11
+ const url = String(props.url ?? "");
12
+ const alt = String(props.alt ?? "");
13
+ const ratio = aspectToRatio(String(props.aspect ?? "1:1"));
14
+ return (_jsx(View, { style: [styles.frame, { aspectRatio: ratio }], children: _jsx(Image, { source: { uri: url }, style: StyleSheet.absoluteFill, contentFit: "cover", accessibilityLabel: alt || undefined }) }));
15
+ }
16
+ const styles = StyleSheet.create({
17
+ frame: {
18
+ flex: 1,
19
+ width: "100%",
20
+ borderRadius: 8,
21
+ overflow: "hidden",
22
+ backgroundColor: "#f3f4f6",
23
+ },
24
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapInput({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useStateStore } from "@json-render/react-native";
3
+ import { StyleSheet, Text, TextInput, View } from "react-native";
4
+ import { useSnapTheme } from "../theme.js";
5
+ export function SnapInput({ element: { props }, }) {
6
+ const { get, set } = useStateStore();
7
+ const { colors } = useSnapTheme();
8
+ const name = String(props.name ?? "input");
9
+ const path = `/inputs/${name}`;
10
+ const label = props.label ? String(props.label) : undefined;
11
+ const placeholder = props.placeholder ? String(props.placeholder) : undefined;
12
+ const type = String(props.type ?? "text");
13
+ const maxLength = typeof props.maxLength === "number" ? props.maxLength : undefined;
14
+ const defaultValue = props.defaultValue != null ? String(props.defaultValue) : "";
15
+ const raw = get(path);
16
+ const value = raw !== undefined && raw !== null ? String(raw) : defaultValue;
17
+ return (_jsxs(View, { style: styles.wrap, children: [label ? _jsx(Text, { style: [styles.label, { color: colors.text }], children: label }) : null, _jsx(TextInput, { style: [
18
+ styles.input,
19
+ {
20
+ borderColor: colors.border,
21
+ backgroundColor: colors.inputBg,
22
+ color: colors.text,
23
+ },
24
+ ], value: value, onChangeText: (text) => set(path, type === "number" ? Number(text) || 0 : text), placeholder: placeholder, placeholderTextColor: colors.textSecondary, maxLength: maxLength, autoCapitalize: "none", autoCorrect: false, keyboardType: type === "number" ? "numeric" : "default" })] }));
25
+ }
26
+ const styles = StyleSheet.create({
27
+ wrap: { width: "100%", gap: 4 },
28
+ label: { fontSize: 13, fontWeight: "500" },
29
+ input: {
30
+ borderWidth: 1,
31
+ borderRadius: 8,
32
+ paddingHorizontal: 12,
33
+ paddingVertical: 10,
34
+ fontSize: 14,
35
+ },
36
+ });
@@ -0,0 +1,5 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ import { type ReactNode } from "react";
3
+ export declare function SnapItemGroup({ element: { props }, children, }: ComponentRenderProps<Record<string, unknown>> & {
4
+ children?: ReactNode;
5
+ }): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Children, Fragment } from "react";
3
+ import { StyleSheet, View } from "react-native";
4
+ import { useSnapTheme } from "../theme.js";
5
+ const GAP_MAP = { none: 0, sm: 4, md: 8, lg: 12 };
6
+ export function SnapItemGroup({ element: { props }, children, }) {
7
+ const { colors } = useSnapTheme();
8
+ const border = Boolean(props.border);
9
+ const separator = Boolean(props.separator);
10
+ const gap = GAP_MAP[String(props.gap ?? "sm")] ?? 4;
11
+ const items = Children.toArray(children);
12
+ return (_jsx(View, { style: [
13
+ styles.group,
14
+ border && { borderWidth: 1, borderColor: colors.border, borderRadius: 12 },
15
+ { gap },
16
+ ], children: items.map((child, i) => (_jsxs(Fragment, { children: [separator && i > 0 && (_jsx(View, { style: { height: 1, backgroundColor: colors.border + "80" } })), child] }, i))) }));
17
+ }
18
+ const styles = StyleSheet.create({
19
+ group: {
20
+ width: "100%",
21
+ overflow: "hidden",
22
+ },
23
+ });
@@ -0,0 +1,5 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ import type { ReactNode } from "react";
3
+ export declare function SnapItem({ element: { props }, children, }: ComponentRenderProps<Record<string, unknown>> & {
4
+ children?: ReactNode;
5
+ }): import("react").JSX.Element;
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { StyleSheet, Text, View } from "react-native";
3
+ import { useSnapTheme } from "../theme.js";
4
+ export function SnapItem({ element: { props }, children, }) {
5
+ const { colors } = useSnapTheme();
6
+ const title = String(props.title ?? "");
7
+ const description = props.description
8
+ ? String(props.description)
9
+ : undefined;
10
+ const variant = String(props.variant ?? "default");
11
+ const containerVariant = variant === "outline"
12
+ ? { borderWidth: 1, borderColor: colors.border + "80", borderRadius: 8, padding: 10 }
13
+ : variant === "muted"
14
+ ? { backgroundColor: "rgba(255,255,255,0.04)", borderRadius: 8, padding: 10 }
15
+ : { paddingVertical: 8, paddingHorizontal: 10 };
16
+ return (_jsxs(View, { style: [styles.container, containerVariant], children: [_jsxs(View, { style: styles.content, children: [_jsx(Text, { style: [styles.title, { color: colors.text }], children: title }), description ? (_jsx(Text, { style: [styles.description, { color: colors.textSecondary }], children: description })) : null] }), children ? (_jsx(View, { style: styles.actions, children: _jsx(View, { style: { flex: 0 }, children: children }) })) : null] }));
17
+ }
18
+ const styles = StyleSheet.create({
19
+ container: {
20
+ flex: 1,
21
+ flexDirection: "row",
22
+ alignItems: "center",
23
+ },
24
+ content: {
25
+ flex: 1,
26
+ },
27
+ title: {
28
+ fontSize: 15,
29
+ fontWeight: "500",
30
+ },
31
+ description: {
32
+ fontSize: 13,
33
+ marginTop: 1,
34
+ },
35
+ actions: {
36
+ marginLeft: "auto",
37
+ paddingLeft: 12,
38
+ flexDirection: "row",
39
+ alignItems: "center",
40
+ flexShrink: 0,
41
+ flexGrow: 0,
42
+ flexBasis: "auto",
43
+ gap: 4,
44
+ },
45
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapProgress({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { StyleSheet, Text, View } from "react-native";
3
+ import { useSnapPalette } from "../use-snap-palette.js";
4
+ import { useSnapTheme } from "../theme.js";
5
+ export function SnapProgress({ element: { props }, }) {
6
+ const { accentHex } = useSnapPalette();
7
+ const { colors } = useSnapTheme();
8
+ const value = Number(props.value ?? 0);
9
+ const max = Math.max(1, Number(props.max ?? 100));
10
+ const percent = Math.min(100, Math.max(0, (value / max) * 100));
11
+ const label = props.label != null ? String(props.label) : null;
12
+ return (_jsxs(View, { style: styles.wrap, children: [label ? (_jsx(Text, { style: [styles.label, { color: colors.textSecondary }], children: label })) : null, _jsx(View, { style: [styles.track, { backgroundColor: colors.muted }], children: _jsx(View, { style: [styles.fill, { width: `${percent}%`, backgroundColor: accentHex }] }) })] }));
13
+ }
14
+ const styles = StyleSheet.create({
15
+ wrap: { flex: 1, width: "100%", gap: 4 },
16
+ label: { fontSize: 13 },
17
+ track: {
18
+ height: 10,
19
+ borderRadius: 9999,
20
+ overflow: "hidden",
21
+ },
22
+ fill: {
23
+ height: "100%",
24
+ borderRadius: 9999,
25
+ },
26
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapSeparator({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { StyleSheet, View } from "react-native";
3
+ import { useSnapTheme } from "../theme.js";
4
+ export function SnapSeparator({ element: { props }, }) {
5
+ const { colors } = useSnapTheme();
6
+ const orientation = String(props.orientation ?? "horizontal");
7
+ const isVertical = orientation === "vertical";
8
+ return (_jsx(View, { style: [
9
+ isVertical ? styles.vertical : styles.horizontal,
10
+ { backgroundColor: colors.border + "80" },
11
+ ] }));
12
+ }
13
+ const styles = StyleSheet.create({
14
+ horizontal: {
15
+ width: "100%",
16
+ height: 1,
17
+ },
18
+ vertical: {
19
+ height: "100%",
20
+ width: 1,
21
+ alignSelf: "stretch",
22
+ },
23
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapSlider({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useStateStore } from "@json-render/react-native";
3
+ import Slider from "@react-native-community/slider";
4
+ import { StyleSheet, Text, View } from "react-native";
5
+ import { useSnapPalette } from "../use-snap-palette.js";
6
+ import { useSnapTheme } from "../theme.js";
7
+ export function SnapSlider({ element: { props }, }) {
8
+ const { get, set } = useStateStore();
9
+ const { accentHex } = useSnapPalette();
10
+ const { colors } = useSnapTheme();
11
+ const name = String(props.name ?? "slider");
12
+ const path = `/inputs/${name}`;
13
+ const min = Number(props.min ?? 0);
14
+ const max = Number(props.max ?? 100);
15
+ const step = props.step != null ? Number(props.step) : 1;
16
+ const fallback = props.defaultValue != null ? Number(props.defaultValue) : (min + max) / 2;
17
+ const raw = get(path);
18
+ const value = raw === undefined || raw === null ? fallback : Number(raw);
19
+ const clamped = Number.isFinite(value)
20
+ ? Math.min(max, Math.max(min, value))
21
+ : fallback;
22
+ const label = props.label != null ? String(props.label) : null;
23
+ const minLabel = props.minLabel != null ? String(props.minLabel) : null;
24
+ const maxLabel = props.maxLabel != null ? String(props.maxLabel) : null;
25
+ return (_jsxs(View, { style: styles.wrap, children: [label ? (_jsxs(View, { style: styles.labelRow, children: [_jsx(Text, { style: [styles.label, { color: colors.text }], children: label }), _jsx(Text, { style: [styles.valueText, { color: colors.textSecondary }], children: String(Math.round(clamped)) })] })) : null, _jsx(Slider, { style: styles.slider, minimumValue: min, maximumValue: max, step: step > 0 ? step : 1, value: clamped, onValueChange: (v) => set(path, v), minimumTrackTintColor: accentHex, maximumTrackTintColor: colors.muted, thumbTintColor: accentHex }), minLabel != null || maxLabel != null ? (_jsxs(View, { style: styles.minMaxRow, children: [_jsx(Text, { style: [styles.minMax, { color: colors.textSecondary }], children: minLabel ?? String(min) }), _jsx(Text, { style: [styles.minMax, { color: colors.textSecondary }], children: maxLabel ?? String(max) })] })) : null] }));
26
+ }
27
+ const styles = StyleSheet.create({
28
+ wrap: { width: "100%", gap: 6 },
29
+ labelRow: {
30
+ flexDirection: "row",
31
+ justifyContent: "space-between",
32
+ alignItems: "center",
33
+ },
34
+ label: { fontSize: 13, fontWeight: "500", flex: 1 },
35
+ valueText: { fontSize: 13 },
36
+ slider: { width: "100%", height: 40 },
37
+ minMaxRow: {
38
+ flexDirection: "row",
39
+ justifyContent: "space-between",
40
+ },
41
+ minMax: { fontSize: 12 },
42
+ });
@@ -0,0 +1,5 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ import type { ReactNode } from "react";
3
+ export declare function SnapStack({ element: { props }, children, }: ComponentRenderProps<Record<string, unknown>> & {
4
+ children?: ReactNode;
5
+ }): import("react").JSX.Element;
@@ -0,0 +1,49 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { StyleSheet, View } from "react-native";
3
+ const VGAP = {
4
+ none: 0,
5
+ sm: 8,
6
+ md: 16,
7
+ lg: 24,
8
+ };
9
+ const HGAP = {
10
+ none: 0,
11
+ sm: 4,
12
+ md: 8,
13
+ lg: 12,
14
+ };
15
+ const JUSTIFY = {
16
+ start: "flex-start",
17
+ center: "center",
18
+ end: "flex-end",
19
+ between: "space-between",
20
+ around: "space-around",
21
+ };
22
+ export function SnapStack({ element: { props }, children, }) {
23
+ const direction = String(props.direction ?? "vertical");
24
+ const rawGap = props.gap;
25
+ const isHorizontal = direction === "horizontal";
26
+ const gapMap = isHorizontal ? HGAP : VGAP;
27
+ const gap = typeof rawGap === "number"
28
+ ? rawGap
29
+ : typeof rawGap === "string" && rawGap in gapMap
30
+ ? gapMap[rawGap]
31
+ : isHorizontal ? HGAP.md : VGAP.md;
32
+ const justify = props.justify ? JUSTIFY[String(props.justify)] : undefined;
33
+ return (_jsx(View, { style: [
34
+ styles.stack,
35
+ isHorizontal ? styles.horizontal : undefined,
36
+ { gap },
37
+ justify ? { justifyContent: justify } : undefined,
38
+ ], children: children }));
39
+ }
40
+ const styles = StyleSheet.create({
41
+ stack: {
42
+ width: "100%",
43
+ },
44
+ horizontal: {
45
+ flexDirection: "row",
46
+ alignItems: "center",
47
+ flexWrap: "wrap",
48
+ },
49
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapSwitch({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useStateStore } from "@json-render/react-native";
3
+ import { StyleSheet, Switch, Text, View } from "react-native";
4
+ import { useSnapPalette } from "../use-snap-palette.js";
5
+ import { useSnapTheme } from "../theme.js";
6
+ export function SnapSwitch({ element: { props }, }) {
7
+ const { get, set } = useStateStore();
8
+ const { accentHex } = useSnapPalette();
9
+ const { colors } = useSnapTheme();
10
+ const name = String(props.name ?? "switch");
11
+ const path = `/inputs/${name}`;
12
+ const label = props.label ? String(props.label) : undefined;
13
+ const fallback = Boolean(props.defaultChecked ?? false);
14
+ const raw = get(path);
15
+ const checked = raw === undefined || raw === null ? fallback : Boolean(raw);
16
+ return (_jsxs(View, { style: styles.row, children: [label ? _jsx(Text, { style: [styles.label, { color: colors.text }], children: label }) : null, _jsx(Switch, { value: checked, onValueChange: (v) => set(path, v), trackColor: { false: colors.border, true: accentHex }, thumbColor: "#fff" })] }));
17
+ }
18
+ const styles = StyleSheet.create({
19
+ row: {
20
+ flexDirection: "row",
21
+ alignItems: "center",
22
+ justifyContent: "space-between",
23
+ gap: 12,
24
+ },
25
+ label: {
26
+ fontSize: 14,
27
+ fontWeight: "400",
28
+ flex: 1,
29
+ },
30
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapText({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { StyleSheet, Text, View } from "react-native";
3
+ import { useSnapTheme } from "../theme.js";
4
+ const SIZE_STYLES = {
5
+ lg: { fontSize: 20, fontWeight: "700" },
6
+ md: { fontSize: 16, lineHeight: 24 },
7
+ sm: { fontSize: 13 },
8
+ };
9
+ const WEIGHT_MAP = {
10
+ bold: "700",
11
+ medium: "500",
12
+ normal: "400",
13
+ };
14
+ export function SnapText({ element: { props }, }) {
15
+ const { colors } = useSnapTheme();
16
+ const content = String(props.content ?? "");
17
+ const size = String(props.size ?? "md");
18
+ const weight = props.weight ? String(props.weight) : undefined;
19
+ const align = props.align ?? undefined;
20
+ const sizeStyle = SIZE_STYLES[size] ?? SIZE_STYLES.md;
21
+ const resolvedWeight = weight ? WEIGHT_MAP[weight] : sizeStyle?.fontWeight;
22
+ const textAlign = align === "center" ? "center" : align === "right" ? "right" : "left";
23
+ return (_jsx(View, { style: styles.wrap, children: _jsx(Text, { style: [
24
+ styles.base,
25
+ {
26
+ color: colors.text,
27
+ fontSize: sizeStyle.fontSize,
28
+ lineHeight: sizeStyle.lineHeight,
29
+ fontWeight: resolvedWeight,
30
+ textAlign,
31
+ },
32
+ ], children: content }) }));
33
+ }
34
+ const styles = StyleSheet.create({
35
+ wrap: { flex: 1, width: "100%" },
36
+ base: {},
37
+ });
@@ -0,0 +1,2 @@
1
+ import type { ComponentRenderProps } from "@json-render/react-native";
2
+ export declare function SnapToggleGroup({ element: { props }, }: ComponentRenderProps<Record<string, unknown>>): import("react").JSX.Element;