@farcaster/snap 1.18.0 → 1.20.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.
- package/dist/react/components/slider.js +2 -1
- package/dist/react/index.d.ts +3 -1
- package/dist/react/index.js +3 -3
- package/dist/react/v1/snap-view.d.ts +2 -1
- package/dist/react/v1/snap-view.js +77 -2
- package/dist/react/v2/snap-view.d.ts +2 -1
- package/dist/react/v2/snap-view.js +11 -3
- package/dist/react-native/components/snap-action-button.js +2 -2
- package/dist/react-native/components/snap-badge.js +2 -1
- package/dist/react-native/components/snap-bar-chart.js +3 -3
- package/dist/react-native/components/snap-cell-grid.js +1 -1
- package/dist/react-native/components/snap-image.js +0 -1
- package/dist/react-native/components/snap-input.js +2 -1
- package/dist/react-native/components/snap-item.js +4 -3
- package/dist/react-native/components/snap-progress.js +2 -2
- package/dist/react-native/components/snap-slider.js +6 -5
- package/dist/react-native/components/snap-switch.js +1 -0
- package/dist/react-native/components/snap-text.js +2 -2
- package/dist/react-native/components/snap-toggle-group.js +2 -1
- package/dist/react-native/index.d.ts +3 -1
- package/dist/react-native/index.js +3 -3
- package/dist/react-native/theme.js +16 -16
- package/dist/react-native/v1/snap-view.d.ts +2 -1
- package/dist/react-native/v1/snap-view.js +68 -11
- package/dist/react-native/v2/snap-view.d.ts +2 -1
- package/dist/react-native/v2/snap-view.js +25 -21
- package/dist/ui/catalog.d.ts +1 -1
- package/dist/ui/catalog.js +1 -2
- package/dist/ui/slider.d.ts +1 -0
- package/dist/ui/slider.js +2 -0
- package/llms.txt +1 -0
- package/package.json +1 -1
- package/src/react/components/slider.tsx +11 -1
- package/src/react/index.tsx +5 -0
- package/src/react/v1/snap-view.tsx +117 -7
- package/src/react/v2/snap-view.tsx +13 -1
- package/src/react-native/components/snap-action-button.tsx +2 -2
- package/src/react-native/components/snap-badge.tsx +2 -1
- package/src/react-native/components/snap-bar-chart.tsx +3 -3
- package/src/react-native/components/snap-cell-grid.tsx +1 -1
- package/src/react-native/components/snap-image.tsx +0 -1
- package/src/react-native/components/snap-input.tsx +2 -1
- package/src/react-native/components/snap-item.tsx +4 -3
- package/src/react-native/components/snap-progress.tsx +2 -2
- package/src/react-native/components/snap-slider.tsx +10 -7
- package/src/react-native/components/snap-switch.tsx +1 -0
- package/src/react-native/components/snap-text.tsx +2 -2
- package/src/react-native/components/snap-toggle-group.tsx +2 -1
- package/src/react-native/index.tsx +5 -0
- package/src/react-native/theme.tsx +16 -16
- package/src/react-native/v1/snap-view.tsx +102 -7
- package/src/react-native/v2/snap-view.tsx +52 -40
- package/src/ui/catalog.ts +1 -2
- package/src/ui/slider.ts +2 -0
|
@@ -50,32 +50,36 @@ export function SnapViewV2({ snap, handlers, loading = false, appearance = "dark
|
|
|
50
50
|
return (_jsx(SnapThemeProvider, { appearance: appearance, colors: colors, children: _jsx(SnapViewV2Inner, { snap: snap, handlers: handlers, loading: loading, onValidationError: onValidationError, validationErrorFallback: validationErrorFallback }) }));
|
|
51
51
|
}
|
|
52
52
|
// ─── SnapCardV2 (card frame + height limits) ─────────
|
|
53
|
-
function SnapCardV2Inner({ snap, handlers, loading, borderRadius, showOverflowWarning, onValidationError, validationErrorFallback, actionError, appearance, }) {
|
|
53
|
+
function SnapCardV2Inner({ snap, handlers, loading, borderRadius, showOverflowWarning, onValidationError, validationErrorFallback, actionError, appearance, plain, }) {
|
|
54
54
|
const { colors } = useSnapTheme();
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
55
|
+
const clipHeight = showOverflowWarning ? undefined : SNAP_MAX_HEIGHT;
|
|
56
|
+
const content = (_jsx(SnapViewV2Inner, { snap: snap, handlers: handlers, loading: loading, onValidationError: onValidationError, validationErrorFallback: validationErrorFallback }));
|
|
57
|
+
if (plain) {
|
|
58
|
+
return content;
|
|
59
|
+
}
|
|
60
|
+
return (_jsxs(_Fragment, { children: [_jsxs(View, { style: {
|
|
61
|
+
borderRadius,
|
|
62
|
+
borderWidth: 1,
|
|
63
|
+
borderColor: colors.border,
|
|
64
|
+
backgroundColor: colors.surface,
|
|
65
|
+
maxHeight: clipHeight,
|
|
66
|
+
overflow: "hidden",
|
|
67
|
+
minHeight: 120,
|
|
68
|
+
}, children: [_jsx(View, { style: { paddingHorizontal: 16, paddingVertical: 16 }, children: content }), showOverflowWarning && (_jsxs(View, { style: { position: "absolute", top: SNAP_MAX_HEIGHT, left: 0, right: 0, bottom: 0, zIndex: 10, pointerEvents: "none" }, children: [_jsx(View, { style: { height: 1, borderTopWidth: 1, borderStyle: "dashed", borderColor: "rgba(255,100,100,0.6)" } }), _jsx(View, { style: { position: "absolute", top: -10, right: 4, backgroundColor: "rgba(0,0,0,0.7)", paddingHorizontal: 4, paddingVertical: 1, borderRadius: 3 }, children: _jsxs(Text, { style: { fontSize: 10, color: "rgba(255,100,100,0.7)", fontFamily: Platform.select({ ios: "Menlo", default: "monospace" }) }, children: [SNAP_MAX_HEIGHT, "px"] }) }), _jsx(View, { style: { flex: 1, backgroundColor: "rgba(255,50,50,0.15)" } })] }))] }), actionError && (_jsx(Text, { style: {
|
|
69
|
+
paddingHorizontal: 12,
|
|
70
|
+
paddingVertical: 8,
|
|
71
|
+
fontSize: 13,
|
|
72
|
+
color: appearance === "dark"
|
|
73
|
+
? "rgba(255,100,100,0.9)"
|
|
74
|
+
: "rgba(200,0,0,0.8)",
|
|
75
|
+
}, children: actionError }))] }));
|
|
72
76
|
}
|
|
73
|
-
export function SnapCardV2({ snap, handlers, loading = false, appearance = "dark", colors, borderRadius = 16, showOverflowWarning = false, onValidationError, validationErrorFallback, actionError, }) {
|
|
74
|
-
return (_jsx(SnapThemeProvider, { appearance: appearance, colors: colors, children: _jsx(SnapCardV2Inner, { snap: snap, handlers: handlers, loading: loading, borderRadius: borderRadius, showOverflowWarning: showOverflowWarning, onValidationError: onValidationError, validationErrorFallback: validationErrorFallback, actionError: actionError, appearance: appearance }) }));
|
|
77
|
+
export function SnapCardV2({ snap, handlers, loading = false, appearance = "dark", colors, borderRadius = 16, showOverflowWarning = false, onValidationError, validationErrorFallback, actionError, plain = false, }) {
|
|
78
|
+
return (_jsx(SnapThemeProvider, { appearance: appearance, colors: colors, children: _jsx(SnapCardV2Inner, { snap: snap, handlers: handlers, loading: loading, borderRadius: borderRadius, showOverflowWarning: showOverflowWarning, onValidationError: onValidationError, validationErrorFallback: validationErrorFallback, actionError: actionError, appearance: appearance, plain: plain }) }));
|
|
75
79
|
}
|
|
76
80
|
const cardStyles = StyleSheet.create({
|
|
77
81
|
frameRing: { alignSelf: "stretch" },
|
|
78
|
-
card: {
|
|
82
|
+
card: { borderWidth: 1, minHeight: 120, overflow: "hidden" },
|
|
79
83
|
body: { paddingHorizontal: 16, paddingVertical: 16 },
|
|
80
84
|
actionError: { paddingHorizontal: 12, paddingVertical: 8, fontSize: 13 },
|
|
81
85
|
warningOverlay: {
|
package/dist/ui/catalog.d.ts
CHANGED
|
@@ -295,6 +295,7 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
295
295
|
step: z.ZodOptional<z.ZodNumber>;
|
|
296
296
|
defaultValue: z.ZodOptional<z.ZodNumber>;
|
|
297
297
|
label: z.ZodOptional<z.ZodString>;
|
|
298
|
+
showValue: z.ZodOptional<z.ZodBoolean>;
|
|
298
299
|
}, z.core.$strip>;
|
|
299
300
|
description: string;
|
|
300
301
|
};
|
|
@@ -417,7 +418,6 @@ export declare const snapJsonRenderCatalog: import("@json-render/core").Catalog<
|
|
|
417
418
|
description: string;
|
|
418
419
|
params: z.ZodObject<{
|
|
419
420
|
target: z.ZodString;
|
|
420
|
-
isSnap: z.ZodOptional<z.ZodBoolean>;
|
|
421
421
|
}, z.core.$strip>;
|
|
422
422
|
};
|
|
423
423
|
open_mini_app: {
|
package/dist/ui/catalog.js
CHANGED
|
@@ -99,10 +99,9 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
99
99
|
params: z.object({ target: z.string() }),
|
|
100
100
|
},
|
|
101
101
|
open_url: {
|
|
102
|
-
description: "Open
|
|
102
|
+
description: "Open URL in browser.",
|
|
103
103
|
params: z.object({
|
|
104
104
|
target: z.string(),
|
|
105
|
-
isSnap: z.boolean().optional(),
|
|
106
105
|
}),
|
|
107
106
|
},
|
|
108
107
|
open_mini_app: {
|
package/dist/ui/slider.d.ts
CHANGED
|
@@ -9,5 +9,6 @@ export declare const sliderProps: z.ZodObject<{
|
|
|
9
9
|
step: z.ZodOptional<z.ZodNumber>;
|
|
10
10
|
defaultValue: z.ZodOptional<z.ZodNumber>;
|
|
11
11
|
label: z.ZodOptional<z.ZodString>;
|
|
12
|
+
showValue: z.ZodOptional<z.ZodBoolean>;
|
|
12
13
|
}, z.core.$strip>;
|
|
13
14
|
export type SliderProps = z.infer<typeof sliderProps>;
|
package/dist/ui/slider.js
CHANGED
|
@@ -10,6 +10,8 @@ export const sliderProps = z
|
|
|
10
10
|
step: z.number().optional(),
|
|
11
11
|
defaultValue: z.number().optional(),
|
|
12
12
|
label: z.string().max(SLIDER_MAX_LABEL_CHARS).optional(),
|
|
13
|
+
/** When true, display the current value next to the label. */
|
|
14
|
+
showValue: z.boolean().optional(),
|
|
13
15
|
})
|
|
14
16
|
.superRefine((val, ctx) => {
|
|
15
17
|
if (val.min > val.max) {
|
package/llms.txt
CHANGED
|
@@ -134,6 +134,7 @@ Field values are sent in POST `inputs[name]` when a `submit` action fires.
|
|
|
134
134
|
- `step` (number, optional, > 0. Default: 1)
|
|
135
135
|
- `defaultValue` (number, optional, between min and max)
|
|
136
136
|
- `label` (string, optional, max 60)
|
|
137
|
+
- `showValue` (boolean, optional): display the current value next to the label
|
|
137
138
|
- POST value: number
|
|
138
139
|
|
|
139
140
|
**switch** — Boolean toggle.
|
package/package.json
CHANGED
|
@@ -16,6 +16,7 @@ export function SnapSlider({
|
|
|
16
16
|
const max = Number(props.max ?? 100);
|
|
17
17
|
const step = Number(props.step ?? 1);
|
|
18
18
|
const label = props.label ? String(props.label) : undefined;
|
|
19
|
+
const showValue = props.showValue === true;
|
|
19
20
|
const path = `/inputs/${name}`;
|
|
20
21
|
const raw = get(path);
|
|
21
22
|
const value =
|
|
@@ -27,7 +28,16 @@ export function SnapSlider({
|
|
|
27
28
|
|
|
28
29
|
return (
|
|
29
30
|
<div className="flex w-full flex-col gap-1.5">
|
|
30
|
-
{label &&
|
|
31
|
+
{label && (
|
|
32
|
+
<div className="flex items-center justify-between">
|
|
33
|
+
<Label style={{ color: colors.text }}>{label}</Label>
|
|
34
|
+
{showValue && (
|
|
35
|
+
<span style={{ color: colors.textMuted, fontSize: 13, lineHeight: "18px" }}>
|
|
36
|
+
{Math.round(value)}
|
|
37
|
+
</span>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
)}
|
|
31
41
|
<input
|
|
32
42
|
type="range"
|
|
33
43
|
min={min}
|
package/src/react/index.tsx
CHANGED
|
@@ -57,6 +57,7 @@ export function SnapCard({
|
|
|
57
57
|
onValidationError,
|
|
58
58
|
validationErrorFallback,
|
|
59
59
|
actionError,
|
|
60
|
+
plain = false,
|
|
60
61
|
}: {
|
|
61
62
|
snap: SnapPage;
|
|
62
63
|
handlers: SnapActionHandlers;
|
|
@@ -69,6 +70,8 @@ export function SnapCard({
|
|
|
69
70
|
validationErrorFallback?: ReactNode;
|
|
70
71
|
/** Server-side action error message to display inline. */
|
|
71
72
|
actionError?: string | null;
|
|
73
|
+
/** When true, renders without card frame (no border, background, or padding). */
|
|
74
|
+
plain?: boolean;
|
|
72
75
|
}) {
|
|
73
76
|
if (snap.version === SPEC_VERSION_2) {
|
|
74
77
|
return (
|
|
@@ -82,6 +85,7 @@ export function SnapCard({
|
|
|
82
85
|
onValidationError={onValidationError}
|
|
83
86
|
validationErrorFallback={validationErrorFallback}
|
|
84
87
|
actionError={actionError}
|
|
88
|
+
plain={plain}
|
|
85
89
|
/>
|
|
86
90
|
);
|
|
87
91
|
}
|
|
@@ -94,6 +98,7 @@ export function SnapCard({
|
|
|
94
98
|
appearance={appearance}
|
|
95
99
|
maxWidth={maxWidth}
|
|
96
100
|
actionError={actionError}
|
|
101
|
+
plain={plain}
|
|
97
102
|
/>
|
|
98
103
|
);
|
|
99
104
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
4
|
import { SnapViewCore } from "../snap-view-core";
|
|
4
5
|
import type { SnapPage, SnapActionHandlers } from "../index";
|
|
5
6
|
|
|
7
|
+
const SNAP_MAX_HEIGHT = 500;
|
|
8
|
+
|
|
6
9
|
export function SnapViewV1({
|
|
7
10
|
snap,
|
|
8
11
|
handlers,
|
|
@@ -31,6 +34,7 @@ export function SnapCardV1({
|
|
|
31
34
|
appearance = "dark",
|
|
32
35
|
maxWidth = 480,
|
|
33
36
|
actionError,
|
|
37
|
+
plain = false,
|
|
34
38
|
}: {
|
|
35
39
|
snap: SnapPage;
|
|
36
40
|
handlers: SnapActionHandlers;
|
|
@@ -38,15 +42,121 @@ export function SnapCardV1({
|
|
|
38
42
|
appearance?: "light" | "dark";
|
|
39
43
|
maxWidth?: number;
|
|
40
44
|
actionError?: string | null;
|
|
45
|
+
plain?: boolean;
|
|
41
46
|
}) {
|
|
47
|
+
const isDark = appearance === "dark";
|
|
48
|
+
const borderColor = isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)";
|
|
49
|
+
const surfaceBg = isDark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.02)";
|
|
50
|
+
const toggleBg = isDark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.05)";
|
|
51
|
+
const toggleBgHover = isDark
|
|
52
|
+
? "rgba(255,255,255,0.1)"
|
|
53
|
+
: "rgba(0,0,0,0.08)";
|
|
54
|
+
const toggleText = isDark ? "rgba(255,255,255,0.82)" : "rgba(0,0,0,0.72)";
|
|
55
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
56
|
+
const [isExpandable, setIsExpandable] = useState(false);
|
|
57
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setIsExpanded(false);
|
|
61
|
+
}, [snap]);
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
const node = contentRef.current;
|
|
65
|
+
if (!node) return;
|
|
66
|
+
|
|
67
|
+
const measure = () => {
|
|
68
|
+
setIsExpandable(node.scrollHeight > SNAP_MAX_HEIGHT + 1);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
measure();
|
|
72
|
+
|
|
73
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
74
|
+
const observer = new ResizeObserver(() => {
|
|
75
|
+
measure();
|
|
76
|
+
});
|
|
77
|
+
observer.observe(node);
|
|
78
|
+
return () => observer.disconnect();
|
|
79
|
+
}, [snap, plain]);
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!isExpandable) {
|
|
83
|
+
setIsExpanded(false);
|
|
84
|
+
}
|
|
85
|
+
}, [isExpandable]);
|
|
86
|
+
|
|
87
|
+
const isClipped = isExpandable && !isExpanded;
|
|
88
|
+
|
|
42
89
|
return (
|
|
43
|
-
<div
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
90
|
+
<div
|
|
91
|
+
style={{
|
|
92
|
+
position: "relative",
|
|
93
|
+
width: "100%",
|
|
94
|
+
maxWidth,
|
|
95
|
+
overflow: "hidden",
|
|
96
|
+
...(plain ? {} : {
|
|
97
|
+
borderRadius: 16,
|
|
98
|
+
border: `1px solid ${borderColor}`,
|
|
99
|
+
backgroundColor: surfaceBg,
|
|
100
|
+
}),
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
<div
|
|
104
|
+
style={
|
|
105
|
+
isClipped
|
|
106
|
+
? {
|
|
107
|
+
maxHeight: SNAP_MAX_HEIGHT,
|
|
108
|
+
overflow: "hidden",
|
|
109
|
+
}
|
|
110
|
+
: undefined
|
|
111
|
+
}
|
|
112
|
+
>
|
|
113
|
+
<div ref={contentRef} style={plain ? undefined : { padding: 16 }}>
|
|
114
|
+
<SnapViewV1
|
|
115
|
+
snap={snap}
|
|
116
|
+
handlers={handlers}
|
|
117
|
+
loading={loading}
|
|
118
|
+
appearance={appearance}
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
{isExpandable ? (
|
|
123
|
+
<div
|
|
124
|
+
style={{
|
|
125
|
+
display: "flex",
|
|
126
|
+
justifyContent: "center",
|
|
127
|
+
padding: plain ? "8px 0 0" : "10px 16px 12px",
|
|
128
|
+
...(plain
|
|
129
|
+
? {}
|
|
130
|
+
: { borderTop: `1px solid ${borderColor}` }),
|
|
131
|
+
}}
|
|
132
|
+
>
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
aria-expanded={isExpanded}
|
|
136
|
+
onClick={() => setIsExpanded((value) => !value)}
|
|
137
|
+
style={{
|
|
138
|
+
appearance: "none",
|
|
139
|
+
border: "none",
|
|
140
|
+
borderRadius: 9999,
|
|
141
|
+
backgroundColor: toggleBg,
|
|
142
|
+
color: toggleText,
|
|
143
|
+
padding: "6px 10px",
|
|
144
|
+
fontSize: 13,
|
|
145
|
+
lineHeight: "18px",
|
|
146
|
+
fontWeight: 600,
|
|
147
|
+
cursor: "pointer",
|
|
148
|
+
}}
|
|
149
|
+
onMouseEnter={(event) => {
|
|
150
|
+
event.currentTarget.style.backgroundColor = toggleBgHover;
|
|
151
|
+
}}
|
|
152
|
+
onMouseLeave={(event) => {
|
|
153
|
+
event.currentTarget.style.backgroundColor = toggleBg;
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
{isExpanded ? "Show less" : "Show more"}
|
|
157
|
+
</button>
|
|
158
|
+
</div>
|
|
159
|
+
) : null}
|
|
50
160
|
{actionError && (
|
|
51
161
|
<div
|
|
52
162
|
style={{
|
|
@@ -95,6 +95,7 @@ export function SnapCardV2({
|
|
|
95
95
|
onValidationError,
|
|
96
96
|
validationErrorFallback,
|
|
97
97
|
actionError,
|
|
98
|
+
plain = false,
|
|
98
99
|
}: {
|
|
99
100
|
snap: SnapPage;
|
|
100
101
|
handlers: SnapActionHandlers;
|
|
@@ -105,9 +106,13 @@ export function SnapCardV2({
|
|
|
105
106
|
onValidationError?: (result: ValidationResult) => void;
|
|
106
107
|
validationErrorFallback?: ReactNode;
|
|
107
108
|
actionError?: string | null;
|
|
109
|
+
plain?: boolean;
|
|
108
110
|
}) {
|
|
109
111
|
const maxHeight = showOverflowWarning ? SNAP_WARNING_HEIGHT : SNAP_MAX_HEIGHT;
|
|
110
|
-
const
|
|
112
|
+
const isDark = appearance === "dark";
|
|
113
|
+
const bg = isDark ? "rgba(0,0,0,0.85)" : "rgba(255,255,255,0.9)";
|
|
114
|
+
const borderColor = isDark ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)";
|
|
115
|
+
const surfaceBg = isDark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.02)";
|
|
111
116
|
|
|
112
117
|
return (
|
|
113
118
|
<>
|
|
@@ -118,8 +123,14 @@ export function SnapCardV2({
|
|
|
118
123
|
maxWidth,
|
|
119
124
|
maxHeight,
|
|
120
125
|
overflow: "hidden",
|
|
126
|
+
...(plain ? {} : {
|
|
127
|
+
borderRadius: 16,
|
|
128
|
+
border: `1px solid ${borderColor}`,
|
|
129
|
+
backgroundColor: surfaceBg,
|
|
130
|
+
}),
|
|
121
131
|
}}
|
|
122
132
|
>
|
|
133
|
+
<div style={plain ? undefined : { padding: 16 }}>
|
|
123
134
|
<SnapViewV2
|
|
124
135
|
snap={snap}
|
|
125
136
|
handlers={handlers}
|
|
@@ -128,6 +139,7 @@ export function SnapCardV2({
|
|
|
128
139
|
onValidationError={onValidationError}
|
|
129
140
|
validationErrorFallback={validationErrorFallback}
|
|
130
141
|
/>
|
|
142
|
+
</div>
|
|
131
143
|
{showOverflowWarning && (
|
|
132
144
|
<div
|
|
133
145
|
style={{
|
|
@@ -65,7 +65,7 @@ export function SnapActionButton({
|
|
|
65
65
|
return <I size={16} color={iconColor} />;
|
|
66
66
|
})()
|
|
67
67
|
: null}
|
|
68
|
-
<Text style={{ color: textColor, fontSize: 14, fontWeight: "600" }}>
|
|
68
|
+
<Text style={{ color: textColor, fontSize: 14, lineHeight: 18, fontWeight: "600" }}>
|
|
69
69
|
{label}
|
|
70
70
|
</Text>
|
|
71
71
|
{showExternalIcon ? (
|
|
@@ -77,7 +77,7 @@ export function SnapActionButton({
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const styles = StyleSheet.create({
|
|
80
|
-
outer: {
|
|
80
|
+
outer: { minWidth: 0 },
|
|
81
81
|
btn: {
|
|
82
82
|
paddingHorizontal: 16,
|
|
83
83
|
borderRadius: 10,
|
|
@@ -13,7 +13,7 @@ export function SnapBadge({
|
|
|
13
13
|
const iconName = props.icon ? String(props.icon) : undefined;
|
|
14
14
|
const isAccent = !color || color === "accent";
|
|
15
15
|
const resolvedColor = isAccent ? accentHex : hex(color);
|
|
16
|
-
const isFilled = variant
|
|
16
|
+
const isFilled = variant !== "outline";
|
|
17
17
|
|
|
18
18
|
const Icon = iconName ? ICON_MAP[iconName] : undefined;
|
|
19
19
|
|
|
@@ -54,6 +54,7 @@ const styles = StyleSheet.create({
|
|
|
54
54
|
},
|
|
55
55
|
label: {
|
|
56
56
|
fontSize: 12,
|
|
57
|
+
lineHeight: 16,
|
|
57
58
|
fontWeight: "500",
|
|
58
59
|
},
|
|
59
60
|
});
|
|
@@ -64,10 +64,10 @@ export function SnapBarChart({
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
const styles = StyleSheet.create({
|
|
67
|
-
wrap: {
|
|
67
|
+
wrap: { width: "100%", gap: 8 },
|
|
68
68
|
row: { flexDirection: "row", alignItems: "center", gap: 8 },
|
|
69
|
-
label: { width: 80, fontSize: 12, textAlign: "right" },
|
|
69
|
+
label: { width: 80, fontSize: 12, lineHeight: 16, textAlign: "right" },
|
|
70
70
|
track: { flex: 1, height: 10, borderRadius: 9999, overflow: "hidden" },
|
|
71
71
|
fill: { height: "100%", borderRadius: 9999 },
|
|
72
|
-
value: { width: 32, fontSize: 12, fontVariant: ["tabular-nums"] },
|
|
72
|
+
value: { width: 32, fontSize: 12, lineHeight: 16, fontVariant: ["tabular-nums"] },
|
|
73
73
|
});
|
|
@@ -147,6 +147,6 @@ const styles = StyleSheet.create({
|
|
|
147
147
|
alignItems: "center",
|
|
148
148
|
justifyContent: "center",
|
|
149
149
|
},
|
|
150
|
-
cellText: { fontSize: 12, fontWeight: "600" },
|
|
150
|
+
cellText: { fontSize: 12, lineHeight: 16, fontWeight: "600" },
|
|
151
151
|
selectionText: { fontSize: 11, fontFamily: "monospace", marginTop: 6 },
|
|
152
152
|
});
|
|
@@ -46,12 +46,13 @@ export function SnapInput({
|
|
|
46
46
|
|
|
47
47
|
const styles = StyleSheet.create({
|
|
48
48
|
wrap: { width: "100%", gap: 4 },
|
|
49
|
-
label: { fontSize: 13, fontWeight: "500" },
|
|
49
|
+
label: { fontSize: 13, lineHeight: 18, fontWeight: "500" },
|
|
50
50
|
input: {
|
|
51
51
|
borderWidth: 1,
|
|
52
52
|
borderRadius: 8,
|
|
53
53
|
paddingHorizontal: 12,
|
|
54
54
|
paddingVertical: 10,
|
|
55
55
|
fontSize: 14,
|
|
56
|
+
lineHeight: 18,
|
|
56
57
|
},
|
|
57
58
|
});
|
|
@@ -14,12 +14,12 @@ export function SnapItem({
|
|
|
14
14
|
: undefined;
|
|
15
15
|
const variant = String(props.variant ?? "default");
|
|
16
16
|
|
|
17
|
-
const containerVariant = { paddingVertical:
|
|
17
|
+
const containerVariant = { paddingVertical: 6, paddingHorizontal: 10 };
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
20
|
<View style={[styles.container, containerVariant]}>
|
|
21
21
|
<View style={styles.content}>
|
|
22
|
-
<Text style={[styles.title, { color: colors.text }]}>{title}</Text>
|
|
22
|
+
{title ? <Text style={[styles.title, { color: colors.text }]}>{title}</Text> : null}
|
|
23
23
|
{description ? (
|
|
24
24
|
<Text style={[styles.description, { color: colors.textSecondary }]}>
|
|
25
25
|
{description}
|
|
@@ -37,7 +37,6 @@ export function SnapItem({
|
|
|
37
37
|
|
|
38
38
|
const styles = StyleSheet.create({
|
|
39
39
|
container: {
|
|
40
|
-
flex: 1,
|
|
41
40
|
flexDirection: "row",
|
|
42
41
|
alignItems: "center",
|
|
43
42
|
},
|
|
@@ -46,10 +45,12 @@ const styles = StyleSheet.create({
|
|
|
46
45
|
},
|
|
47
46
|
title: {
|
|
48
47
|
fontSize: 15,
|
|
48
|
+
lineHeight: 20,
|
|
49
49
|
fontWeight: "500",
|
|
50
50
|
},
|
|
51
51
|
description: {
|
|
52
52
|
fontSize: 13,
|
|
53
|
+
lineHeight: 18,
|
|
53
54
|
marginTop: 1,
|
|
54
55
|
},
|
|
55
56
|
actions: {
|
|
@@ -26,8 +26,8 @@ export function SnapProgress({
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const styles = StyleSheet.create({
|
|
29
|
-
wrap: {
|
|
30
|
-
label: { fontSize: 13 },
|
|
29
|
+
wrap: { width: "100%", gap: 4 },
|
|
30
|
+
label: { fontSize: 13, lineHeight: 18 },
|
|
31
31
|
track: {
|
|
32
32
|
height: 10,
|
|
33
33
|
borderRadius: 9999,
|
|
@@ -26,6 +26,7 @@ export function SnapSlider({
|
|
|
26
26
|
: fallback;
|
|
27
27
|
|
|
28
28
|
const label = props.label != null ? String(props.label) : null;
|
|
29
|
+
const showValue = props.showValue === true;
|
|
29
30
|
const minLabel = props.minLabel != null ? String(props.minLabel) : null;
|
|
30
31
|
const maxLabel = props.maxLabel != null ? String(props.maxLabel) : null;
|
|
31
32
|
|
|
@@ -34,9 +35,11 @@ export function SnapSlider({
|
|
|
34
35
|
{label ? (
|
|
35
36
|
<View style={styles.labelRow}>
|
|
36
37
|
<Text style={[styles.label, { color: colors.text }]}>{label}</Text>
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
|
|
38
|
+
{showValue && (
|
|
39
|
+
<Text style={[styles.valueText, { color: colors.textSecondary }]}>
|
|
40
|
+
{String(Math.round(clamped))}
|
|
41
|
+
</Text>
|
|
42
|
+
)}
|
|
40
43
|
</View>
|
|
41
44
|
) : null}
|
|
42
45
|
<Slider
|
|
@@ -65,18 +68,18 @@ export function SnapSlider({
|
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
const styles = StyleSheet.create({
|
|
68
|
-
wrap: { width: "100%", gap:
|
|
71
|
+
wrap: { width: "100%", gap: 2 },
|
|
69
72
|
labelRow: {
|
|
70
73
|
flexDirection: "row",
|
|
71
74
|
justifyContent: "space-between",
|
|
72
75
|
alignItems: "center",
|
|
73
76
|
},
|
|
74
|
-
label: { fontSize: 13, fontWeight: "500", flex: 1 },
|
|
75
|
-
valueText: { fontSize: 13 },
|
|
77
|
+
label: { fontSize: 13, lineHeight: 18, fontWeight: "500", flex: 1 },
|
|
78
|
+
valueText: { fontSize: 13, lineHeight: 18 },
|
|
76
79
|
slider: { width: "100%", height: 40 },
|
|
77
80
|
minMaxRow: {
|
|
78
81
|
flexDirection: "row",
|
|
79
82
|
justifyContent: "space-between",
|
|
80
83
|
},
|
|
81
|
-
minMax: { fontSize: 12 },
|
|
84
|
+
minMax: { fontSize: 12, lineHeight: 16 },
|
|
82
85
|
});
|
|
@@ -4,7 +4,7 @@ import { useSnapTheme } from "../theme";
|
|
|
4
4
|
|
|
5
5
|
const SIZE_STYLES: Record<string, { fontSize: number; lineHeight?: number; fontWeight?: "400" | "500" | "600" | "700" }> = {
|
|
6
6
|
md: { fontSize: 16, lineHeight: 24 },
|
|
7
|
-
sm: { fontSize: 13 },
|
|
7
|
+
sm: { fontSize: 13, lineHeight: 18 },
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
const WEIGHT_MAP: Record<string, "400" | "500" | "600" | "700"> = {
|
|
@@ -46,6 +46,6 @@ export function SnapText({
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const styles = StyleSheet.create({
|
|
49
|
-
wrap: {
|
|
49
|
+
wrap: { width: "100%" },
|
|
50
50
|
base: {},
|
|
51
51
|
});
|
|
@@ -97,7 +97,7 @@ export function SnapToggleGroup({
|
|
|
97
97
|
|
|
98
98
|
const styles = StyleSheet.create({
|
|
99
99
|
wrap: { width: "100%", gap: 6 },
|
|
100
|
-
label: { fontSize: 13, fontWeight: "500" },
|
|
100
|
+
label: { fontSize: 13, lineHeight: 18, fontWeight: "500" },
|
|
101
101
|
group: {
|
|
102
102
|
padding: 4,
|
|
103
103
|
borderRadius: 8,
|
|
@@ -121,6 +121,7 @@ const styles = StyleSheet.create({
|
|
|
121
121
|
},
|
|
122
122
|
optionText: {
|
|
123
123
|
fontSize: 13,
|
|
124
|
+
lineHeight: 18,
|
|
124
125
|
fontWeight: "500",
|
|
125
126
|
},
|
|
126
127
|
});
|
|
@@ -30,6 +30,7 @@ export function SnapCard({
|
|
|
30
30
|
onValidationError,
|
|
31
31
|
validationErrorFallback,
|
|
32
32
|
actionError,
|
|
33
|
+
plain = false,
|
|
33
34
|
}: {
|
|
34
35
|
snap: SnapPage;
|
|
35
36
|
handlers: SnapActionHandlers;
|
|
@@ -46,6 +47,8 @@ export function SnapCard({
|
|
|
46
47
|
validationErrorFallback?: ReactNode;
|
|
47
48
|
/** Server-side action error message to display inline. */
|
|
48
49
|
actionError?: string | null;
|
|
50
|
+
/** When true, renders without card frame (no border, background, or padding). */
|
|
51
|
+
plain?: boolean;
|
|
49
52
|
}) {
|
|
50
53
|
if (snap.version === SPEC_VERSION_2) {
|
|
51
54
|
return (
|
|
@@ -60,6 +63,7 @@ export function SnapCard({
|
|
|
60
63
|
onValidationError={onValidationError}
|
|
61
64
|
validationErrorFallback={validationErrorFallback}
|
|
62
65
|
actionError={actionError}
|
|
66
|
+
plain={plain}
|
|
63
67
|
/>
|
|
64
68
|
);
|
|
65
69
|
}
|
|
@@ -73,6 +77,7 @@ export function SnapCard({
|
|
|
73
77
|
colors={colors}
|
|
74
78
|
borderRadius={borderRadius}
|
|
75
79
|
actionError={actionError}
|
|
80
|
+
plain={plain}
|
|
76
81
|
/>
|
|
77
82
|
);
|
|
78
83
|
}
|