@farcaster/snap 2.6.0 → 2.6.2
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/image.js +6 -1
- package/dist/react/components/item-group.js +3 -1
- package/dist/react/components/item.js +1 -1
- package/dist/react/components/text.js +5 -8
- package/dist/react-native/components/snap-image.js +18 -6
- package/dist/react-native/components/snap-item-group.js +3 -1
- package/dist/react-native/components/snap-item.js +2 -2
- package/dist/react-native/components/snap-text.js +2 -8
- package/dist/ui/catalog.js +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/src/react/components/image.tsx +17 -4
- package/src/react/components/item-group.tsx +4 -1
- package/src/react/components/item.tsx +6 -2
- package/src/react/components/text.tsx +6 -9
- package/src/react-native/components/snap-image.tsx +30 -16
- package/src/react-native/components/snap-item-group.tsx +4 -1
- package/src/react-native/components/snap-item.tsx +2 -2
- package/src/react-native/components/snap-text.tsx +14 -11
- package/src/ui/catalog.ts +1 -1
|
@@ -18,5 +18,10 @@ export function SnapImage({ element: { props }, }) {
|
|
|
18
18
|
const ratio = aspectToRatio(String(props.aspect ?? "1:1"));
|
|
19
19
|
const stackDir = useSnapStackDirection();
|
|
20
20
|
const inHorizontalStack = stackDir === "horizontal";
|
|
21
|
-
return (_jsxs(AspectRatio, { ratio: ratio, className: cn("relative overflow-hidden rounded-lg", inHorizontalStack ? "min-w-0 flex-1 basis-0" : "w-full"), children: [_jsx("img", { src: url, alt: alt, className: "absolute inset-0 size-full object-cover" }), hasOverlay && (_jsxs("div", { className: "absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/
|
|
21
|
+
return (_jsxs(AspectRatio, { ratio: ratio, className: cn("relative overflow-hidden rounded-lg", inHorizontalStack ? "min-w-0 flex-1 basis-0" : "w-full"), children: [_jsx("img", { src: url, alt: alt, className: "absolute inset-0 size-full object-cover" }), hasOverlay && (_jsxs("div", { className: "absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 via-black/35 to-transparent p-3 pt-10 text-white", children: [title && (_jsx("div", { className: "truncate text-sm font-semibold leading-5", style: {
|
|
22
|
+
textShadow: "0 1px 2px rgba(0,0,0,0.95), 0 0 3px rgba(0,0,0,0.9)",
|
|
23
|
+
WebkitTextStroke: "0.25px rgba(0,0,0,0.75)",
|
|
24
|
+
}, children: title })), subtitle && (_jsx("div", { className: "truncate text-xs font-medium leading-4 text-white/90", style: {
|
|
25
|
+
textShadow: "0 1px 2px rgba(0,0,0,0.95), 0 0 3px rgba(0,0,0,0.9)",
|
|
26
|
+
}, children: subtitle }))] }))] }));
|
|
22
27
|
}
|
|
@@ -13,7 +13,9 @@ const GAP_MAP = {
|
|
|
13
13
|
export function SnapItemGroup({ element: { props }, children, }) {
|
|
14
14
|
const border = Boolean(props.border);
|
|
15
15
|
const separator = Boolean(props.separator);
|
|
16
|
-
const
|
|
16
|
+
const explicitGap = typeof props.gap === "string" ? String(props.gap) : undefined;
|
|
17
|
+
const defaultGap = border || separator ? "sm" : "none";
|
|
18
|
+
const gap = GAP_MAP[explicitGap ?? defaultGap] ?? GAP_MAP[defaultGap];
|
|
17
19
|
const items = Children.toArray(children);
|
|
18
20
|
const colors = useSnapColors();
|
|
19
21
|
return (_jsx(SnapItemGroupBorderProvider, { value: border, children: _jsx("div", { className: cn("flex flex-col", border && "rounded-lg border", gap), style: border ? { borderColor: colors.border } : undefined, children: items.map((child, i) => (_jsxs(Fragment, { children: [separator && i > 0 && (_jsx("div", { className: "h-px", style: { backgroundColor: colors.border } })), child] }, i))) }) }));
|
|
@@ -44,7 +44,7 @@ export function SnapItem({ element: { props, children: childIds }, children, })
|
|
|
44
44
|
alignSelf: "center",
|
|
45
45
|
borderRadius: media.round ? "9999px" : undefined,
|
|
46
46
|
transform: "none",
|
|
47
|
-
}, children: _jsx("img", { src: media.url, alt: media.alt ?? "", className: "size-full object-cover" }) })), _jsxs(ItemContent, { className: "gap-0", children: [_jsx(ItemTitle, { style: { color: colors.text }, children: title }), description && (_jsx(ItemDescription, { className: "mt-0 text-xs leading-snug", style: {
|
|
47
|
+
}, children: _jsx("img", { src: media.url, alt: media.alt ?? "", className: "size-full object-cover" }) })), _jsxs(ItemContent, { className: "gap-0", children: [_jsx(ItemTitle, { style: { color: colors.text, fontSize: 14, lineHeight: "19px" }, children: title }), description && (_jsx(ItemDescription, { className: "mt-0 text-xs leading-snug", style: {
|
|
48
48
|
color: colors.textMuted,
|
|
49
49
|
fontSize: 12,
|
|
50
50
|
lineHeight: "16px",
|
|
@@ -4,7 +4,6 @@ import { Text } from "@neynar/ui/typography";
|
|
|
4
4
|
import { cn } from "@neynar/ui/utils";
|
|
5
5
|
import { useSnapColors } from "../hooks/use-snap-colors.js";
|
|
6
6
|
import { useSnapStackDirection } from "../stack-direction-context.js";
|
|
7
|
-
import { useSnapVersion } from "../snap-version-context.js";
|
|
8
7
|
const SIZE_MAP = {
|
|
9
8
|
md: { textSize: "base" },
|
|
10
9
|
sm: { textSize: "sm" },
|
|
@@ -12,18 +11,15 @@ const SIZE_MAP = {
|
|
|
12
11
|
export function SnapText({ element: { props }, }) {
|
|
13
12
|
const content = String(props.content ?? "");
|
|
14
13
|
const size = String(props.size ?? "md");
|
|
15
|
-
const weight = props.weight
|
|
14
|
+
const weight = props.weight
|
|
15
|
+
? String(props.weight)
|
|
16
|
+
: undefined;
|
|
16
17
|
const align = props.align ?? undefined;
|
|
17
18
|
const config = SIZE_MAP[size] ?? SIZE_MAP.md;
|
|
18
19
|
const colors = useSnapColors();
|
|
19
20
|
const stackDir = useSnapStackDirection();
|
|
20
|
-
const snapVersion = useSnapVersion();
|
|
21
21
|
const inHorizontalStack = stackDir === "horizontal";
|
|
22
|
-
const maxLines = typeof props.maxLines === "number"
|
|
23
|
-
? props.maxLines
|
|
24
|
-
: snapVersion === "2.0"
|
|
25
|
-
? 1
|
|
26
|
-
: undefined;
|
|
22
|
+
const maxLines = typeof props.maxLines === "number" ? props.maxLines : undefined;
|
|
27
23
|
return (_jsx(Text, { size: config.textSize, weight: weight, align: align, className: cn(
|
|
28
24
|
/**
|
|
29
25
|
* Row peers hug content like RN `wrapRow` — `min-w-0 shrink` lets text wrap
|
|
@@ -35,6 +31,7 @@ export function SnapText({ element: { props }, }) {
|
|
|
35
31
|
*/
|
|
36
32
|
inHorizontalStack ? "min-w-0 shrink" : "min-w-0"), style: {
|
|
37
33
|
color: colors.text,
|
|
34
|
+
fontSize: size === "md" ? 15 : undefined,
|
|
38
35
|
lineHeight: size === "sm" ? 1.35 : 1.4,
|
|
39
36
|
...(maxLines
|
|
40
37
|
? {
|
|
@@ -21,7 +21,7 @@ export function SnapImage({ element: { props }, }) {
|
|
|
21
21
|
styles.frame,
|
|
22
22
|
inHorizontalStack ? styles.frameInHorizontalRow : styles.frameFullWidth,
|
|
23
23
|
{ aspectRatio: ratio },
|
|
24
|
-
], children: [_jsx(Image, { source: { uri: url }, style: StyleSheet.absoluteFill, contentFit: "cover", accessibilityLabel: alt || undefined }), hasOverlay ? (
|
|
24
|
+
], children: [_jsx(Image, { source: { uri: url }, style: StyleSheet.absoluteFill, contentFit: "cover", accessibilityLabel: alt || undefined }), hasOverlay ? (_jsx(View, { style: styles.overlay, pointerEvents: "none", children: _jsxs(View, { style: styles.overlayContent, children: [title ? (_jsx(Text, { numberOfLines: 1, style: styles.title, children: title })) : null, subtitle ? (_jsx(Text, { numberOfLines: 1, style: styles.subtitle, children: subtitle })) : null] }) })) : null] }));
|
|
25
25
|
}
|
|
26
26
|
const styles = StyleSheet.create({
|
|
27
27
|
frame: {
|
|
@@ -41,21 +41,33 @@ const styles = StyleSheet.create({
|
|
|
41
41
|
left: 0,
|
|
42
42
|
right: 0,
|
|
43
43
|
bottom: 0,
|
|
44
|
-
paddingHorizontal:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
paddingHorizontal: 3,
|
|
45
|
+
paddingBottom: 3,
|
|
46
|
+
},
|
|
47
|
+
overlayContent: {
|
|
48
|
+
alignSelf: "flex-start",
|
|
49
|
+
maxWidth: "100%",
|
|
50
|
+
borderRadius: 5,
|
|
51
|
+
paddingHorizontal: 5,
|
|
52
|
+
paddingVertical: 3,
|
|
53
|
+
backgroundColor: "rgba(0, 0, 0, 0.22)",
|
|
48
54
|
},
|
|
49
55
|
title: {
|
|
50
56
|
color: "#fff",
|
|
51
57
|
fontSize: 14,
|
|
52
58
|
lineHeight: 18,
|
|
53
59
|
fontWeight: "700",
|
|
60
|
+
textShadowColor: "#000",
|
|
61
|
+
textShadowOffset: { width: 1.25, height: 1.25 },
|
|
62
|
+
textShadowRadius: 1,
|
|
54
63
|
},
|
|
55
64
|
subtitle: {
|
|
56
|
-
color: "
|
|
65
|
+
color: "#fff",
|
|
57
66
|
fontSize: 12,
|
|
58
67
|
lineHeight: 16,
|
|
59
68
|
fontWeight: "500",
|
|
69
|
+
textShadowColor: "#000",
|
|
70
|
+
textShadowOffset: { width: 1.25, height: 1.25 },
|
|
71
|
+
textShadowRadius: 1,
|
|
60
72
|
},
|
|
61
73
|
});
|
|
@@ -13,7 +13,9 @@ export function SnapItemGroup({ element: { props }, children, }) {
|
|
|
13
13
|
const { colors } = useSnapTheme();
|
|
14
14
|
const border = Boolean(props.border);
|
|
15
15
|
const separator = Boolean(props.separator);
|
|
16
|
-
const
|
|
16
|
+
const explicitGap = typeof props.gap === "string" ? String(props.gap) : undefined;
|
|
17
|
+
const defaultGap = border || separator ? "sm" : "none";
|
|
18
|
+
const gap = GAP_MAP[explicitGap ?? defaultGap] ?? GAP_MAP[defaultGap];
|
|
17
19
|
const items = Children.toArray(children);
|
|
18
20
|
return (_jsx(SnapItemGroupBorderProvider, { value: border, children: _jsx(View, { style: [
|
|
19
21
|
styles.group,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { StyleSheet, Text, View } from "react-native";
|
|
3
3
|
import { useSnapStackDirection } from "../stack-direction-context.js";
|
|
4
|
-
import { useSnapVersion } from "../snap-version-context.js";
|
|
5
4
|
import { useSnapTheme } from "../theme.js";
|
|
6
5
|
const SIZE_STYLES = {
|
|
7
|
-
md: { fontSize:
|
|
6
|
+
md: { fontSize: 15, lineHeight: 21 },
|
|
8
7
|
sm: { fontSize: 13, lineHeight: 16 },
|
|
9
8
|
};
|
|
10
9
|
const WEIGHT_MAP = {
|
|
@@ -17,16 +16,11 @@ export function SnapText({ element: { props }, }) {
|
|
|
17
16
|
const size = String(props.size ?? "md");
|
|
18
17
|
const weight = props.weight ? String(props.weight) : undefined;
|
|
19
18
|
const align = props.align ?? undefined;
|
|
20
|
-
const snapVersion = useSnapVersion();
|
|
21
19
|
const sizeStyle = SIZE_STYLES[size] ?? SIZE_STYLES.md;
|
|
22
20
|
const resolvedWeight = weight ? WEIGHT_MAP[weight] : sizeStyle?.fontWeight;
|
|
23
21
|
const textAlign = align === "center" ? "center" : align === "right" ? "right" : "left";
|
|
24
22
|
const inHorizontalStack = useSnapStackDirection() === "horizontal";
|
|
25
|
-
const maxLines = typeof props.maxLines === "number"
|
|
26
|
-
? props.maxLines
|
|
27
|
-
: snapVersion === "2.0"
|
|
28
|
-
? 1
|
|
29
|
-
: undefined;
|
|
23
|
+
const maxLines = typeof props.maxLines === "number" ? props.maxLines : undefined;
|
|
30
24
|
return (_jsx(View, { style: inHorizontalStack ? styles.wrapRow : styles.wrapCol, children: _jsx(Text, { style: [
|
|
31
25
|
styles.base,
|
|
32
26
|
{
|
package/dist/ui/catalog.js
CHANGED
|
@@ -87,7 +87,7 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
87
87
|
},
|
|
88
88
|
text: {
|
|
89
89
|
props: textProps,
|
|
90
|
-
description: "Text block — size: md (body, default), sm (caption). Optional weight, align, and maxLines.
|
|
90
|
+
description: "Text block — size: md (body, default), sm (caption). Optional weight, align, and maxLines. Text does not clamp by default; set maxLines to bound rendered lines.",
|
|
91
91
|
},
|
|
92
92
|
bar_chart: {
|
|
93
93
|
props: barChartProps,
|
package/llms.txt
CHANGED
|
@@ -85,7 +85,7 @@ Top-level fields: `version` (required, `"1.0"` or `"2.0"`), `theme` (optional, `
|
|
|
85
85
|
- `size` (optional): `"md"` (body) | `"sm"` (caption). Default: `"md"`
|
|
86
86
|
- `weight` (optional): `"bold"` | `"normal"`. Default: `"normal"`
|
|
87
87
|
- `align` (optional): `"left"` | `"center"` | `"right"`. Default: `"left"`
|
|
88
|
-
- `maxLines` (optional): integer 1–6. Default
|
|
88
|
+
- `maxLines` (optional): integer 1–6. Default: no clamp. Set this when body text should use a bounded number of visible lines.
|
|
89
89
|
|
|
90
90
|
### Data Components
|
|
91
91
|
|
package/package.json
CHANGED
|
@@ -29,7 +29,7 @@ export function SnapImage({
|
|
|
29
29
|
ratio={ratio}
|
|
30
30
|
className={cn(
|
|
31
31
|
"relative overflow-hidden rounded-lg",
|
|
32
|
-
inHorizontalStack ? "min-w-0 flex-1 basis-0" : "w-full"
|
|
32
|
+
inHorizontalStack ? "min-w-0 flex-1 basis-0" : "w-full"
|
|
33
33
|
)}
|
|
34
34
|
>
|
|
35
35
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
@@ -39,14 +39,27 @@ export function SnapImage({
|
|
|
39
39
|
className="absolute inset-0 size-full object-cover"
|
|
40
40
|
/>
|
|
41
41
|
{hasOverlay && (
|
|
42
|
-
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/
|
|
42
|
+
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/70 via-black/35 to-transparent p-3 pt-10 text-white">
|
|
43
43
|
{title && (
|
|
44
|
-
<div
|
|
44
|
+
<div
|
|
45
|
+
className="truncate text-sm font-semibold leading-5"
|
|
46
|
+
style={{
|
|
47
|
+
textShadow:
|
|
48
|
+
"0 1px 2px rgba(0,0,0,0.95), 0 0 3px rgba(0,0,0,0.9)",
|
|
49
|
+
WebkitTextStroke: "0.25px rgba(0,0,0,0.75)",
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
45
52
|
{title}
|
|
46
53
|
</div>
|
|
47
54
|
)}
|
|
48
55
|
{subtitle && (
|
|
49
|
-
<div
|
|
56
|
+
<div
|
|
57
|
+
className="truncate text-xs font-medium leading-4 text-white/90"
|
|
58
|
+
style={{
|
|
59
|
+
textShadow:
|
|
60
|
+
"0 1px 2px rgba(0,0,0,0.95), 0 0 3px rgba(0,0,0,0.9)",
|
|
61
|
+
}}
|
|
62
|
+
>
|
|
50
63
|
{subtitle}
|
|
51
64
|
</div>
|
|
52
65
|
)}
|
|
@@ -21,7 +21,10 @@ export function SnapItemGroup({
|
|
|
21
21
|
}) {
|
|
22
22
|
const border = Boolean(props.border);
|
|
23
23
|
const separator = Boolean(props.separator);
|
|
24
|
-
const
|
|
24
|
+
const explicitGap =
|
|
25
|
+
typeof props.gap === "string" ? String(props.gap) : undefined;
|
|
26
|
+
const defaultGap = border || separator ? "sm" : "none";
|
|
27
|
+
const gap = GAP_MAP[explicitGap ?? defaultGap] ?? GAP_MAP[defaultGap]!;
|
|
25
28
|
const items = Children.toArray(children);
|
|
26
29
|
const colors = useSnapColors();
|
|
27
30
|
|
|
@@ -73,7 +73,7 @@ export function SnapItem({
|
|
|
73
73
|
"gap-2 py-1.5",
|
|
74
74
|
inBorderedGroup ? "px-2" : "px-0",
|
|
75
75
|
/** Horizontal: share width with peers. Vertical: don't fill column height. */
|
|
76
|
-
inHorizontalStack && "flex-1"
|
|
76
|
+
inHorizontalStack && "flex-1"
|
|
77
77
|
)}
|
|
78
78
|
style={{
|
|
79
79
|
columnGap: 8,
|
|
@@ -111,7 +111,11 @@ export function SnapItem({
|
|
|
111
111
|
</ItemMedia>
|
|
112
112
|
)}
|
|
113
113
|
<ItemContent className="gap-0">
|
|
114
|
-
<ItemTitle
|
|
114
|
+
<ItemTitle
|
|
115
|
+
style={{ color: colors.text, fontSize: 14, lineHeight: "19px" }}
|
|
116
|
+
>
|
|
117
|
+
{title}
|
|
118
|
+
</ItemTitle>
|
|
115
119
|
{description && (
|
|
116
120
|
<ItemDescription
|
|
117
121
|
className="mt-0 text-xs leading-snug"
|
|
@@ -4,7 +4,6 @@ import { Text } from "@neynar/ui/typography";
|
|
|
4
4
|
import { cn } from "@neynar/ui/utils";
|
|
5
5
|
import { useSnapColors } from "../hooks/use-snap-colors";
|
|
6
6
|
import { useSnapStackDirection } from "../stack-direction-context";
|
|
7
|
-
import { useSnapVersion } from "../snap-version-context";
|
|
8
7
|
|
|
9
8
|
const SIZE_MAP = {
|
|
10
9
|
md: { textSize: "base" as const },
|
|
@@ -18,19 +17,16 @@ export function SnapText({
|
|
|
18
17
|
}) {
|
|
19
18
|
const content = String(props.content ?? "");
|
|
20
19
|
const size = String(props.size ?? "md") as "md" | "sm";
|
|
21
|
-
const weight = props.weight
|
|
20
|
+
const weight = props.weight
|
|
21
|
+
? (String(props.weight) as "bold" | "normal")
|
|
22
|
+
: undefined;
|
|
22
23
|
const align = (props.align as "left" | "center" | "right") ?? undefined;
|
|
23
24
|
const config = SIZE_MAP[size] ?? SIZE_MAP.md;
|
|
24
25
|
const colors = useSnapColors();
|
|
25
26
|
const stackDir = useSnapStackDirection();
|
|
26
|
-
const snapVersion = useSnapVersion();
|
|
27
27
|
const inHorizontalStack = stackDir === "horizontal";
|
|
28
28
|
const maxLines =
|
|
29
|
-
typeof props.maxLines === "number"
|
|
30
|
-
? props.maxLines
|
|
31
|
-
: snapVersion === "2.0"
|
|
32
|
-
? 1
|
|
33
|
-
: undefined;
|
|
29
|
+
typeof props.maxLines === "number" ? props.maxLines : undefined;
|
|
34
30
|
|
|
35
31
|
return (
|
|
36
32
|
<Text
|
|
@@ -46,10 +42,11 @@ export function SnapText({
|
|
|
46
42
|
* column's height, distributing siblings when the row is taller than its
|
|
47
43
|
* content (e.g. text next to a tall image).
|
|
48
44
|
*/
|
|
49
|
-
inHorizontalStack ? "min-w-0 shrink" : "min-w-0"
|
|
45
|
+
inHorizontalStack ? "min-w-0 shrink" : "min-w-0"
|
|
50
46
|
)}
|
|
51
47
|
style={{
|
|
52
48
|
color: colors.text,
|
|
49
|
+
fontSize: size === "md" ? 15 : undefined,
|
|
53
50
|
lineHeight: size === "sm" ? 1.35 : 1.4,
|
|
54
51
|
...(maxLines
|
|
55
52
|
? {
|
|
@@ -36,17 +36,19 @@ export function SnapImage({
|
|
|
36
36
|
accessibilityLabel={alt || undefined}
|
|
37
37
|
/>
|
|
38
38
|
{hasOverlay ? (
|
|
39
|
-
<View style={styles.overlay}>
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
{title}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
{subtitle}
|
|
48
|
-
|
|
49
|
-
|
|
39
|
+
<View style={styles.overlay} pointerEvents="none">
|
|
40
|
+
<View style={styles.overlayContent}>
|
|
41
|
+
{title ? (
|
|
42
|
+
<Text numberOfLines={1} style={styles.title}>
|
|
43
|
+
{title}
|
|
44
|
+
</Text>
|
|
45
|
+
) : null}
|
|
46
|
+
{subtitle ? (
|
|
47
|
+
<Text numberOfLines={1} style={styles.subtitle}>
|
|
48
|
+
{subtitle}
|
|
49
|
+
</Text>
|
|
50
|
+
) : null}
|
|
51
|
+
</View>
|
|
50
52
|
</View>
|
|
51
53
|
) : null}
|
|
52
54
|
</View>
|
|
@@ -71,21 +73,33 @@ const styles = StyleSheet.create({
|
|
|
71
73
|
left: 0,
|
|
72
74
|
right: 0,
|
|
73
75
|
bottom: 0,
|
|
74
|
-
paddingHorizontal:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
paddingHorizontal: 3,
|
|
77
|
+
paddingBottom: 3,
|
|
78
|
+
},
|
|
79
|
+
overlayContent: {
|
|
80
|
+
alignSelf: "flex-start",
|
|
81
|
+
maxWidth: "100%",
|
|
82
|
+
borderRadius: 5,
|
|
83
|
+
paddingHorizontal: 5,
|
|
84
|
+
paddingVertical: 3,
|
|
85
|
+
backgroundColor: "rgba(0, 0, 0, 0.22)",
|
|
78
86
|
},
|
|
79
87
|
title: {
|
|
80
88
|
color: "#fff",
|
|
81
89
|
fontSize: 14,
|
|
82
90
|
lineHeight: 18,
|
|
83
91
|
fontWeight: "700",
|
|
92
|
+
textShadowColor: "#000",
|
|
93
|
+
textShadowOffset: { width: 1.25, height: 1.25 },
|
|
94
|
+
textShadowRadius: 1,
|
|
84
95
|
},
|
|
85
96
|
subtitle: {
|
|
86
|
-
color: "
|
|
97
|
+
color: "#fff",
|
|
87
98
|
fontSize: 12,
|
|
88
99
|
lineHeight: 16,
|
|
89
100
|
fontWeight: "500",
|
|
101
|
+
textShadowColor: "#000",
|
|
102
|
+
textShadowOffset: { width: 1.25, height: 1.25 },
|
|
103
|
+
textShadowRadius: 1,
|
|
90
104
|
},
|
|
91
105
|
});
|
|
@@ -18,7 +18,10 @@ export function SnapItemGroup({
|
|
|
18
18
|
const { colors } = useSnapTheme();
|
|
19
19
|
const border = Boolean(props.border);
|
|
20
20
|
const separator = Boolean(props.separator);
|
|
21
|
-
const
|
|
21
|
+
const explicitGap =
|
|
22
|
+
typeof props.gap === "string" ? String(props.gap) : undefined;
|
|
23
|
+
const defaultGap = border || separator ? "sm" : "none";
|
|
24
|
+
const gap = GAP_MAP[explicitGap ?? defaultGap] ?? GAP_MAP[defaultGap]!;
|
|
22
25
|
const items = Children.toArray(children);
|
|
23
26
|
|
|
24
27
|
return (
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { ComponentRenderProps } from "@json-render/react-native";
|
|
2
2
|
import { StyleSheet, Text, View } from "react-native";
|
|
3
3
|
import { useSnapStackDirection } from "../stack-direction-context";
|
|
4
|
-
import { useSnapVersion } from "../snap-version-context";
|
|
5
4
|
import { useSnapTheme } from "../theme";
|
|
6
5
|
|
|
7
|
-
const SIZE_STYLES: Record<
|
|
8
|
-
|
|
6
|
+
const SIZE_STYLES: Record<
|
|
7
|
+
string,
|
|
8
|
+
{
|
|
9
|
+
fontSize: number;
|
|
10
|
+
lineHeight?: number;
|
|
11
|
+
fontWeight?: "400" | "500" | "600" | "700";
|
|
12
|
+
}
|
|
13
|
+
> = {
|
|
14
|
+
md: { fontSize: 15, lineHeight: 21 },
|
|
9
15
|
sm: { fontSize: 13, lineHeight: 16 },
|
|
10
16
|
};
|
|
11
17
|
|
|
@@ -21,19 +27,16 @@ export function SnapText({
|
|
|
21
27
|
const content = String(props.content ?? "");
|
|
22
28
|
const size = String(props.size ?? "md");
|
|
23
29
|
const weight = props.weight ? String(props.weight) : undefined;
|
|
24
|
-
const align =
|
|
25
|
-
|
|
30
|
+
const align =
|
|
31
|
+
(props.align as "left" | "center" | "right" | undefined) ?? undefined;
|
|
26
32
|
|
|
27
33
|
const sizeStyle = SIZE_STYLES[size] ?? SIZE_STYLES.md;
|
|
28
34
|
const resolvedWeight = weight ? WEIGHT_MAP[weight] : sizeStyle?.fontWeight;
|
|
29
|
-
const textAlign =
|
|
35
|
+
const textAlign =
|
|
36
|
+
align === "center" ? "center" : align === "right" ? "right" : "left";
|
|
30
37
|
const inHorizontalStack = useSnapStackDirection() === "horizontal";
|
|
31
38
|
const maxLines =
|
|
32
|
-
typeof props.maxLines === "number"
|
|
33
|
-
? props.maxLines
|
|
34
|
-
: snapVersion === "2.0"
|
|
35
|
-
? 1
|
|
36
|
-
: undefined;
|
|
39
|
+
typeof props.maxLines === "number" ? props.maxLines : undefined;
|
|
37
40
|
|
|
38
41
|
return (
|
|
39
42
|
<View style={inHorizontalStack ? styles.wrapRow : styles.wrapCol}>
|
package/src/ui/catalog.ts
CHANGED
|
@@ -104,7 +104,7 @@ export const snapJsonRenderCatalog = defineCatalog(snapJsonRenderSchema, {
|
|
|
104
104
|
text: {
|
|
105
105
|
props: textProps,
|
|
106
106
|
description:
|
|
107
|
-
"Text block — size: md (body, default), sm (caption). Optional weight, align, and maxLines.
|
|
107
|
+
"Text block — size: md (body, default), sm (caption). Optional weight, align, and maxLines. Text does not clamp by default; set maxLines to bound rendered lines.",
|
|
108
108
|
},
|
|
109
109
|
bar_chart: {
|
|
110
110
|
props: barChartProps,
|