@farcaster/snap 1.5.1 → 2.0.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/constants.d.ts +0 -107
- package/dist/constants.js +0 -148
- package/dist/dataStore.d.ts +12 -0
- package/dist/dataStore.js +35 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +5 -3
- package/dist/middleware.d.ts +3 -0
- package/dist/middleware.js +3 -0
- package/dist/react/accent-context.d.ts +6 -0
- package/dist/react/accent-context.js +10 -0
- package/dist/react/catalog-renderer.d.ts +5 -0
- package/dist/react/catalog-renderer.js +37 -0
- package/dist/react/components/action-button.d.ts +6 -0
- package/dist/react/components/action-button.js +22 -0
- package/dist/react/components/badge.d.ts +5 -0
- package/dist/react/components/badge.js +18 -0
- package/dist/react/components/icon.d.ts +7 -0
- package/dist/react/components/icon.js +60 -0
- package/dist/react/components/image.d.ts +5 -0
- package/dist/react/components/image.js +15 -0
- package/dist/react/components/input.d.ts +5 -0
- package/dist/react/components/input.js +18 -0
- package/dist/react/components/item-group.d.ts +7 -0
- package/dist/react/components/item-group.js +17 -0
- package/dist/react/components/item.d.ts +7 -0
- package/dist/react/components/item.js +9 -0
- package/dist/react/components/progress.d.ts +5 -0
- package/dist/react/components/progress.js +11 -0
- package/dist/react/components/separator.d.ts +5 -0
- package/dist/react/components/separator.js +7 -0
- package/dist/react/components/slider.d.ts +5 -0
- package/dist/react/components/slider.js +21 -0
- package/dist/react/components/stack.d.ts +7 -0
- package/dist/react/components/stack.js +32 -0
- package/dist/react/components/switch.d.ts +5 -0
- package/dist/react/components/switch.js +23 -0
- package/dist/react/components/text.d.ts +5 -0
- package/dist/react/components/text.js +25 -0
- package/dist/react/components/toggle-group.d.ts +5 -0
- package/dist/react/components/toggle-group.js +52 -0
- package/dist/react/hooks/use-snap-accent.d.ts +13 -0
- package/dist/react/hooks/use-snap-accent.js +32 -0
- package/dist/react/index.d.ts +47 -0
- package/dist/react/index.js +191 -0
- package/dist/react/lib/preview-primary-css.d.ts +6 -0
- package/dist/react/lib/preview-primary-css.js +43 -0
- package/dist/react/lib/resolve-palette-hex.d.ts +2 -0
- package/dist/react/lib/resolve-palette-hex.js +10 -0
- package/dist/schemas.d.ts +14 -1629
- package/dist/schemas.js +14 -526
- package/dist/ui/badge.d.ts +52 -0
- package/dist/ui/badge.js +9 -0
- package/dist/ui/button.d.ts +42 -28
- package/dist/ui/button.js +7 -9
- package/dist/ui/catalog.d.ts +280 -155
- package/dist/ui/catalog.js +102 -83
- package/dist/ui/icon.d.ts +56 -0
- package/dist/ui/icon.js +51 -0
- package/dist/ui/image.d.ts +1 -0
- package/dist/ui/image.js +2 -2
- package/dist/ui/index.d.ts +20 -22
- package/dist/ui/index.js +10 -11
- package/dist/ui/input.d.ts +17 -0
- package/dist/ui/input.js +13 -0
- package/dist/ui/item-group.d.ts +12 -0
- package/dist/ui/item-group.js +7 -0
- package/dist/ui/item.d.ts +14 -0
- package/dist/ui/item.js +9 -0
- package/dist/ui/progress.d.ts +1 -11
- package/dist/ui/progress.js +21 -4
- package/dist/ui/schema.js +3 -3
- package/dist/ui/separator.d.ts +9 -0
- package/dist/ui/separator.js +5 -0
- package/dist/ui/slider.d.ts +4 -3
- package/dist/ui/slider.js +34 -5
- package/dist/ui/stack.d.ts +22 -1
- package/dist/ui/stack.js +8 -1
- package/dist/ui/switch.d.ts +8 -0
- package/dist/ui/switch.js +7 -0
- package/dist/ui/text.d.ts +15 -7
- package/dist/ui/text.js +8 -4
- package/dist/ui/toggle-group.d.ts +23 -0
- package/dist/ui/toggle-group.js +19 -0
- package/dist/validator.d.ts +5 -1
- package/dist/validator.js +6 -136
- package/package.json +72 -52
- package/src/constants.ts +0 -179
- package/src/dataStore.ts +62 -0
- package/src/index.ts +11 -20
- package/src/middleware.ts +7 -0
- package/src/react/accent-context.tsx +29 -0
- package/src/react/catalog-renderer.tsx +39 -0
- package/src/react/components/action-button.tsx +48 -0
- package/src/react/components/badge.tsx +37 -0
- package/src/react/components/icon.tsx +115 -0
- package/src/react/components/image.tsx +33 -0
- package/src/react/components/input.tsx +36 -0
- package/src/react/components/item-group.tsx +43 -0
- package/src/react/components/item.tsx +33 -0
- package/src/react/components/progress.tsx +29 -0
- package/src/react/components/separator.tsx +14 -0
- package/src/react/components/slider.tsx +43 -0
- package/src/react/components/stack.tsx +55 -0
- package/src/react/components/switch.tsx +46 -0
- package/src/react/components/text.tsx +43 -0
- package/src/react/components/toggle-group.tsx +85 -0
- package/src/react/hooks/use-snap-accent.ts +45 -0
- package/src/react/index.tsx +321 -0
- package/src/react/lib/preview-primary-css.ts +57 -0
- package/src/react/lib/resolve-palette-hex.ts +20 -0
- package/src/schemas.ts +18 -644
- package/src/ui/badge.ts +13 -0
- package/src/ui/button.ts +9 -12
- package/src/ui/catalog.ts +106 -86
- package/src/ui/icon.ts +56 -0
- package/src/ui/image.ts +3 -2
- package/src/ui/index.ts +26 -29
- package/src/ui/input.ts +17 -0
- package/src/ui/item-group.ts +11 -0
- package/src/ui/item.ts +13 -0
- package/src/ui/progress.ts +25 -7
- package/src/ui/schema.ts +3 -3
- package/src/ui/separator.ts +9 -0
- package/src/ui/slider.ts +40 -10
- package/src/ui/stack.ts +9 -1
- package/src/ui/switch.ts +11 -0
- package/src/ui/text.ts +9 -4
- package/src/ui/toggle-group.ts +23 -0
- package/src/validator.ts +6 -176
- package/dist/ui/bar-chart.d.ts +0 -30
- package/dist/ui/bar-chart.js +0 -15
- package/dist/ui/button-group.d.ts +0 -19
- package/dist/ui/button-group.js +0 -18
- package/dist/ui/divider.d.ts +0 -3
- package/dist/ui/divider.js +0 -2
- package/dist/ui/grid.d.ts +0 -22
- package/dist/ui/grid.js +0 -16
- package/dist/ui/group.d.ts +0 -7
- package/dist/ui/group.js +0 -5
- package/dist/ui/list.d.ts +0 -13
- package/dist/ui/list.js +0 -13
- package/dist/ui/spacer.d.ts +0 -9
- package/dist/ui/spacer.js +0 -5
- package/dist/ui/text-input.d.ts +0 -7
- package/dist/ui/text-input.js +0 -12
- package/dist/ui/toggle.d.ts +0 -7
- package/dist/ui/toggle.js +0 -6
- package/src/ui/bar-chart.ts +0 -20
- package/src/ui/button-group.ts +0 -26
- package/src/ui/divider.ts +0 -5
- package/src/ui/grid.ts +0 -25
- package/src/ui/group.ts +0 -8
- package/src/ui/list.ts +0 -17
- package/src/ui/spacer.ts +0 -8
- package/src/ui/text-input.ts +0 -15
- package/src/ui/toggle.ts +0 -9
package/dist/ui/slider.js
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export const
|
|
2
|
+
export const SLIDER_MAX_LABEL_CHARS = 60;
|
|
3
|
+
export const SLIDER_DEFAULT_STEP = 1;
|
|
4
|
+
export const SLIDER_STEP_ALIGN_EPS = 1e-6;
|
|
5
|
+
export const sliderProps = z
|
|
6
|
+
.object({
|
|
3
7
|
name: z.string().min(1),
|
|
4
8
|
min: z.number(),
|
|
5
9
|
max: z.number(),
|
|
6
10
|
step: z.number().optional(),
|
|
7
|
-
|
|
8
|
-
label: z.string().optional(),
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
defaultValue: z.number().optional(),
|
|
12
|
+
label: z.string().max(SLIDER_MAX_LABEL_CHARS).optional(),
|
|
13
|
+
})
|
|
14
|
+
.superRefine((val, ctx) => {
|
|
15
|
+
if (val.min > val.max) {
|
|
16
|
+
ctx.addIssue({
|
|
17
|
+
code: "custom",
|
|
18
|
+
message: `slider min (${val.min}) must be <= max (${val.max})`,
|
|
19
|
+
path: ["min"],
|
|
20
|
+
});
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (val.step !== undefined && (val.step <= 0 || !Number.isFinite(val.step))) {
|
|
24
|
+
ctx.addIssue({
|
|
25
|
+
code: "custom",
|
|
26
|
+
message: "slider step must be a finite number > 0",
|
|
27
|
+
path: ["step"],
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (val.defaultValue !== undefined) {
|
|
32
|
+
if (val.defaultValue < val.min || val.defaultValue > val.max) {
|
|
33
|
+
ctx.addIssue({
|
|
34
|
+
code: "custom",
|
|
35
|
+
message: `slider defaultValue (${val.defaultValue}) must be between min (${val.min}) and max (${val.max})`,
|
|
36
|
+
path: ["defaultValue"],
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
11
40
|
});
|
package/dist/ui/stack.d.ts
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const STACK_DIRECTIONS: readonly ["vertical", "horizontal"];
|
|
3
|
+
export declare const STACK_GAPS: readonly ["none", "sm", "md", "lg"];
|
|
4
|
+
export declare const STACK_JUSTIFY: readonly ["start", "center", "end", "between", "around"];
|
|
5
|
+
export declare const stackProps: z.ZodObject<{
|
|
6
|
+
direction: z.ZodOptional<z.ZodEnum<{
|
|
7
|
+
horizontal: "horizontal";
|
|
8
|
+
vertical: "vertical";
|
|
9
|
+
}>>;
|
|
10
|
+
gap: z.ZodOptional<z.ZodEnum<{
|
|
11
|
+
sm: "sm";
|
|
12
|
+
md: "md";
|
|
13
|
+
none: "none";
|
|
14
|
+
lg: "lg";
|
|
15
|
+
}>>;
|
|
16
|
+
justify: z.ZodOptional<z.ZodEnum<{
|
|
17
|
+
start: "start";
|
|
18
|
+
center: "center";
|
|
19
|
+
end: "end";
|
|
20
|
+
between: "between";
|
|
21
|
+
around: "around";
|
|
22
|
+
}>>;
|
|
23
|
+
}, z.core.$strip>;
|
|
3
24
|
export type StackProps = z.infer<typeof stackProps>;
|
package/dist/ui/stack.js
CHANGED
|
@@ -1,2 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export const
|
|
2
|
+
export const STACK_DIRECTIONS = ["vertical", "horizontal"];
|
|
3
|
+
export const STACK_GAPS = ["none", "sm", "md", "lg"];
|
|
4
|
+
export const STACK_JUSTIFY = ["start", "center", "end", "between", "around"];
|
|
5
|
+
export const stackProps = z.object({
|
|
6
|
+
direction: z.enum(STACK_DIRECTIONS).optional(),
|
|
7
|
+
gap: z.enum(STACK_GAPS).optional(),
|
|
8
|
+
justify: z.enum(STACK_JUSTIFY).optional(),
|
|
9
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const SWITCH_MAX_LABEL_CHARS = 60;
|
|
3
|
+
export declare const switchProps: z.ZodObject<{
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
label: z.ZodOptional<z.ZodString>;
|
|
6
|
+
defaultChecked: z.ZodOptional<z.ZodBoolean>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export type SwitchProps = z.infer<typeof switchProps>;
|
package/dist/ui/text.d.ts
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
export declare const TEXT_SIZES: readonly ["lg", "md", "sm"];
|
|
3
|
+
export declare const TEXT_WEIGHTS: readonly ["bold", "medium", "normal"];
|
|
4
|
+
export declare const TEXT_ALIGNS: readonly ["left", "center", "right"];
|
|
5
|
+
export declare const TEXT_MAX_CONTENT_CHARS = 320;
|
|
2
6
|
export declare const textProps: z.ZodObject<{
|
|
3
|
-
style: z.ZodEnum<{
|
|
4
|
-
title: "title";
|
|
5
|
-
body: "body";
|
|
6
|
-
caption: "caption";
|
|
7
|
-
label: "label";
|
|
8
|
-
}>;
|
|
9
7
|
content: z.ZodString;
|
|
8
|
+
size: z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
sm: "sm";
|
|
10
|
+
md: "md";
|
|
11
|
+
lg: "lg";
|
|
12
|
+
}>>;
|
|
13
|
+
weight: z.ZodOptional<z.ZodEnum<{
|
|
14
|
+
bold: "bold";
|
|
15
|
+
medium: "medium";
|
|
16
|
+
normal: "normal";
|
|
17
|
+
}>>;
|
|
10
18
|
align: z.ZodOptional<z.ZodEnum<{
|
|
11
|
-
left: "left";
|
|
12
19
|
center: "center";
|
|
20
|
+
left: "left";
|
|
13
21
|
right: "right";
|
|
14
22
|
}>>;
|
|
15
23
|
}, z.core.$strip>;
|
package/dist/ui/text.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
|
|
2
|
+
export const TEXT_SIZES = ["lg", "md", "sm"];
|
|
3
|
+
export const TEXT_WEIGHTS = ["bold", "medium", "normal"];
|
|
4
|
+
export const TEXT_ALIGNS = ["left", "center", "right"];
|
|
5
|
+
export const TEXT_MAX_CONTENT_CHARS = 320;
|
|
3
6
|
export const textProps = z.object({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
content: z.string().min(1).max(TEXT_MAX_CONTENT_CHARS),
|
|
8
|
+
size: z.enum(TEXT_SIZES).optional(),
|
|
9
|
+
weight: z.enum(TEXT_WEIGHTS).optional(),
|
|
10
|
+
align: z.enum(TEXT_ALIGNS).optional(),
|
|
7
11
|
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const TOGGLE_GROUP_VARIANTS: readonly ["default", "outline"];
|
|
3
|
+
export declare const TOGGLE_GROUP_ORIENTATIONS: readonly ["horizontal", "vertical"];
|
|
4
|
+
export declare const TOGGLE_GROUP_MIN_OPTIONS = 2;
|
|
5
|
+
export declare const TOGGLE_GROUP_MAX_OPTIONS = 6;
|
|
6
|
+
export declare const TOGGLE_GROUP_MAX_OPTION_CHARS = 30;
|
|
7
|
+
export declare const TOGGLE_GROUP_MAX_LABEL_CHARS = 60;
|
|
8
|
+
export declare const toggleGroupProps: z.ZodObject<{
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
label: z.ZodOptional<z.ZodString>;
|
|
11
|
+
multiple: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
+
orientation: z.ZodOptional<z.ZodEnum<{
|
|
13
|
+
horizontal: "horizontal";
|
|
14
|
+
vertical: "vertical";
|
|
15
|
+
}>>;
|
|
16
|
+
defaultValue: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
17
|
+
options: z.ZodArray<z.ZodString>;
|
|
18
|
+
variant: z.ZodOptional<z.ZodEnum<{
|
|
19
|
+
default: "default";
|
|
20
|
+
outline: "outline";
|
|
21
|
+
}>>;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
export type ToggleGroupProps = z.infer<typeof toggleGroupProps>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const TOGGLE_GROUP_VARIANTS = ["default", "outline"];
|
|
3
|
+
export const TOGGLE_GROUP_ORIENTATIONS = ["horizontal", "vertical"];
|
|
4
|
+
export const TOGGLE_GROUP_MIN_OPTIONS = 2;
|
|
5
|
+
export const TOGGLE_GROUP_MAX_OPTIONS = 6;
|
|
6
|
+
export const TOGGLE_GROUP_MAX_OPTION_CHARS = 30;
|
|
7
|
+
export const TOGGLE_GROUP_MAX_LABEL_CHARS = 60;
|
|
8
|
+
export const toggleGroupProps = z.object({
|
|
9
|
+
name: z.string().min(1),
|
|
10
|
+
label: z.string().max(TOGGLE_GROUP_MAX_LABEL_CHARS).optional(),
|
|
11
|
+
multiple: z.boolean().optional(),
|
|
12
|
+
orientation: z.enum(TOGGLE_GROUP_ORIENTATIONS).optional(),
|
|
13
|
+
defaultValue: z.union([z.string(), z.array(z.string())]).optional(),
|
|
14
|
+
options: z
|
|
15
|
+
.array(z.string().min(1).max(TOGGLE_GROUP_MAX_OPTION_CHARS))
|
|
16
|
+
.min(TOGGLE_GROUP_MIN_OPTIONS)
|
|
17
|
+
.max(TOGGLE_GROUP_MAX_OPTIONS),
|
|
18
|
+
variant: z.enum(TOGGLE_GROUP_VARIANTS).optional(),
|
|
19
|
+
});
|
package/dist/validator.d.ts
CHANGED
|
@@ -3,5 +3,9 @@ export type ValidationResult = {
|
|
|
3
3
|
valid: boolean;
|
|
4
4
|
issues: z.core.$ZodIssue[];
|
|
5
5
|
};
|
|
6
|
+
/**
|
|
7
|
+
* Validates a snap response against the schema.
|
|
8
|
+
* Element-level prop validation is handled by the json-render catalog.
|
|
9
|
+
* This validates the snap envelope (version, theme, effects, spec shape).
|
|
10
|
+
*/
|
|
6
11
|
export declare function validateSnapResponse(json: unknown): ValidationResult;
|
|
7
|
-
export declare function validateFirstPageResponse(json: unknown): ValidationResult;
|
package/dist/validator.js
CHANGED
|
@@ -1,121 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
buttonRowPx: 48,
|
|
8
|
-
};
|
|
9
|
-
function estimateElementHeight(el) {
|
|
10
|
-
switch (el.type) {
|
|
11
|
-
case ELEMENT_TYPE.text: {
|
|
12
|
-
const style = el.style;
|
|
13
|
-
if (style === TEXT_STYLE.title)
|
|
14
|
-
return 48;
|
|
15
|
-
if (style === TEXT_STYLE.body)
|
|
16
|
-
return 80;
|
|
17
|
-
if (style === TEXT_STYLE.caption)
|
|
18
|
-
return 36;
|
|
19
|
-
if (style === TEXT_STYLE.label)
|
|
20
|
-
return 24;
|
|
21
|
-
return 48;
|
|
22
|
-
}
|
|
23
|
-
case ELEMENT_TYPE.image:
|
|
24
|
-
return 180;
|
|
25
|
-
case ELEMENT_TYPE.grid:
|
|
26
|
-
return 180;
|
|
27
|
-
case ELEMENT_TYPE.progress:
|
|
28
|
-
return 32;
|
|
29
|
-
case ELEMENT_TYPE.list: {
|
|
30
|
-
const items = el.items;
|
|
31
|
-
const n = Array.isArray(items) ? items.length : 0;
|
|
32
|
-
return Math.min(n, LIMITS.maxListItems) * 30;
|
|
33
|
-
}
|
|
34
|
-
case ELEMENT_TYPE.slider:
|
|
35
|
-
return 56;
|
|
36
|
-
case ELEMENT_TYPE.button_group: {
|
|
37
|
-
const options = Array.isArray(el.options) ? el.options : [];
|
|
38
|
-
const style = el.style ??
|
|
39
|
-
(options.length <= 3
|
|
40
|
-
? BUTTON_GROUP_STYLE.row
|
|
41
|
-
: BUTTON_GROUP_STYLE.stack);
|
|
42
|
-
if (style === BUTTON_GROUP_STYLE.row)
|
|
43
|
-
return PAGE_HEIGHT_HEURISTIC.buttonRowPx;
|
|
44
|
-
if (style === BUTTON_GROUP_STYLE.grid) {
|
|
45
|
-
return (Math.ceil(options.length / 2) * PAGE_HEIGHT_HEURISTIC.buttonRowPx);
|
|
46
|
-
}
|
|
47
|
-
return options.length * PAGE_HEIGHT_HEURISTIC.buttonRowPx;
|
|
48
|
-
}
|
|
49
|
-
case ELEMENT_TYPE.text_input:
|
|
50
|
-
return 44;
|
|
51
|
-
case ELEMENT_TYPE.toggle:
|
|
52
|
-
return 40;
|
|
53
|
-
case ELEMENT_TYPE.divider:
|
|
54
|
-
return 16;
|
|
55
|
-
case ELEMENT_TYPE.spacer: {
|
|
56
|
-
const size = el.size ?? SPACER_SIZE.medium;
|
|
57
|
-
if (size === SPACER_SIZE.small)
|
|
58
|
-
return 8;
|
|
59
|
-
if (size === SPACER_SIZE.large)
|
|
60
|
-
return 24;
|
|
61
|
-
return 16;
|
|
62
|
-
}
|
|
63
|
-
case ELEMENT_TYPE.bar_chart:
|
|
64
|
-
return 140; // fixed: 120px bars + 20px labels
|
|
65
|
-
case ELEMENT_TYPE.group: {
|
|
66
|
-
let maxH = 0;
|
|
67
|
-
for (const child of el.children) {
|
|
68
|
-
const h = estimateElementHeight(child);
|
|
69
|
-
if (h > maxH)
|
|
70
|
-
maxH = h;
|
|
71
|
-
}
|
|
72
|
-
return maxH || 56;
|
|
73
|
-
}
|
|
74
|
-
default: {
|
|
75
|
-
const _exhaustive = el;
|
|
76
|
-
return _exhaustive;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function estimateButtonsHeight(buttons, buttonLayout) {
|
|
81
|
-
const rowPx = PAGE_HEIGHT_HEURISTIC.buttonRowPx;
|
|
82
|
-
if (buttons.length === 0)
|
|
83
|
-
return 0;
|
|
84
|
-
if (buttonLayout === BUTTON_GROUP_STYLE.row)
|
|
85
|
-
return rowPx;
|
|
86
|
-
if (buttonLayout === BUTTON_GROUP_STYLE.grid) {
|
|
87
|
-
return Math.ceil(buttons.length / 2) * rowPx;
|
|
88
|
-
}
|
|
89
|
-
return buttons.length * rowPx;
|
|
90
|
-
}
|
|
91
|
-
function measureHeightBudget(elements, buttons, buttonLayout) {
|
|
92
|
-
let totalHeight = PAGE_HEIGHT_HEURISTIC.baseChromePx;
|
|
93
|
-
for (const el of elements) {
|
|
94
|
-
totalHeight += estimateElementHeight(el);
|
|
95
|
-
}
|
|
96
|
-
if (elements.length > 1) {
|
|
97
|
-
totalHeight += (elements.length - 1) * PAGE_HEIGHT_HEURISTIC.elementGapPx;
|
|
98
|
-
}
|
|
99
|
-
totalHeight += estimateButtonsHeight(buttons, buttonLayout);
|
|
100
|
-
return totalHeight;
|
|
101
|
-
}
|
|
102
|
-
function heightBudgetValidationError(elements, buttons, buttonLayout) {
|
|
103
|
-
const totalHeight = measureHeightBudget(elements, buttons, buttonLayout);
|
|
104
|
-
if (totalHeight <= LIMITS.maxEstimatedPageHeightPx) {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
return {
|
|
108
|
-
code: "custom",
|
|
109
|
-
message: `estimated page height is ~${totalHeight}px, which exceeds the ${LIMITS.maxEstimatedPageHeightPx}px feed card limit (expected max ~${LIMITS.maxEstimatedPageHeightPx}px). Reduce elements or buttons to fit.`,
|
|
110
|
-
path: ["page"],
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
function heightBudgetValidationErrorForRoot(root) {
|
|
114
|
-
const layout = typeof root.page.button_layout === "string"
|
|
115
|
-
? root.page.button_layout
|
|
116
|
-
: DEFAULT_BUTTON_LAYOUT;
|
|
117
|
-
return heightBudgetValidationError(root.page.elements.children, root.page.buttons ?? [], layout);
|
|
118
|
-
}
|
|
1
|
+
import { snapResponseSchema } from "./schemas.js";
|
|
2
|
+
/**
|
|
3
|
+
* Validates a snap response against the schema.
|
|
4
|
+
* Element-level prop validation is handled by the json-render catalog.
|
|
5
|
+
* This validates the snap envelope (version, theme, effects, spec shape).
|
|
6
|
+
*/
|
|
119
7
|
export function validateSnapResponse(json) {
|
|
120
8
|
const parsed = snapResponseSchema.safeParse(json);
|
|
121
9
|
if (!parsed.success) {
|
|
@@ -124,23 +12,5 @@ export function validateSnapResponse(json) {
|
|
|
124
12
|
issues: parsed.error.issues,
|
|
125
13
|
};
|
|
126
14
|
}
|
|
127
|
-
const heightErr = heightBudgetValidationErrorForRoot(parsed.data);
|
|
128
|
-
if (heightErr) {
|
|
129
|
-
return { valid: false, issues: [heightErr] };
|
|
130
|
-
}
|
|
131
|
-
return { valid: true, issues: [] };
|
|
132
|
-
}
|
|
133
|
-
export function validateFirstPageResponse(json) {
|
|
134
|
-
const parsed = firstPageResponseSchema.safeParse(json);
|
|
135
|
-
if (!parsed.success) {
|
|
136
|
-
return {
|
|
137
|
-
valid: false,
|
|
138
|
-
issues: parsed.error.issues,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
const heightErr = heightBudgetValidationErrorForRoot(parsed.data);
|
|
142
|
-
if (heightErr) {
|
|
143
|
-
return { valid: false, issues: [heightErr] };
|
|
144
|
-
}
|
|
145
15
|
return { valid: true, issues: [] };
|
|
146
16
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farcaster/snap",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Farcaster Snaps 🫰",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,80 +26,80 @@
|
|
|
26
26
|
"import": "./dist/ui/index.js",
|
|
27
27
|
"default": "./dist/ui/index.js"
|
|
28
28
|
},
|
|
29
|
-
"./ui/
|
|
30
|
-
"types": "./dist/ui/
|
|
31
|
-
"import": "./dist/ui/
|
|
32
|
-
"default": "./dist/ui/
|
|
29
|
+
"./ui/badge": {
|
|
30
|
+
"types": "./dist/ui/badge.d.ts",
|
|
31
|
+
"import": "./dist/ui/badge.js",
|
|
32
|
+
"default": "./dist/ui/badge.js"
|
|
33
|
+
},
|
|
34
|
+
"./ui/button": {
|
|
35
|
+
"types": "./dist/ui/button.d.ts",
|
|
36
|
+
"import": "./dist/ui/button.js",
|
|
37
|
+
"default": "./dist/ui/button.js"
|
|
38
|
+
},
|
|
39
|
+
"./ui/icon": {
|
|
40
|
+
"types": "./dist/ui/icon.d.ts",
|
|
41
|
+
"import": "./dist/ui/icon.js",
|
|
42
|
+
"default": "./dist/ui/icon.js"
|
|
33
43
|
},
|
|
34
44
|
"./ui/image": {
|
|
35
45
|
"types": "./dist/ui/image.d.ts",
|
|
36
46
|
"import": "./dist/ui/image.js",
|
|
37
47
|
"default": "./dist/ui/image.js"
|
|
38
48
|
},
|
|
39
|
-
"./ui/
|
|
40
|
-
"types": "./dist/ui/
|
|
41
|
-
"import": "./dist/ui/
|
|
42
|
-
"default": "./dist/ui/
|
|
49
|
+
"./ui/input": {
|
|
50
|
+
"types": "./dist/ui/input.d.ts",
|
|
51
|
+
"import": "./dist/ui/input.js",
|
|
52
|
+
"default": "./dist/ui/input.js"
|
|
53
|
+
},
|
|
54
|
+
"./ui/item": {
|
|
55
|
+
"types": "./dist/ui/item.d.ts",
|
|
56
|
+
"import": "./dist/ui/item.js",
|
|
57
|
+
"default": "./dist/ui/item.js"
|
|
43
58
|
},
|
|
44
|
-
"./ui/
|
|
45
|
-
"types": "./dist/ui/
|
|
46
|
-
"import": "./dist/ui/
|
|
47
|
-
"default": "./dist/ui/
|
|
59
|
+
"./ui/item-group": {
|
|
60
|
+
"types": "./dist/ui/item-group.d.ts",
|
|
61
|
+
"import": "./dist/ui/item-group.js",
|
|
62
|
+
"default": "./dist/ui/item-group.js"
|
|
48
63
|
},
|
|
49
64
|
"./ui/progress": {
|
|
50
65
|
"types": "./dist/ui/progress.d.ts",
|
|
51
66
|
"import": "./dist/ui/progress.js",
|
|
52
67
|
"default": "./dist/ui/progress.js"
|
|
53
68
|
},
|
|
54
|
-
"./ui/
|
|
55
|
-
"types": "./dist/ui/
|
|
56
|
-
"import": "./dist/ui/
|
|
57
|
-
"default": "./dist/ui/
|
|
58
|
-
},
|
|
59
|
-
"./ui/grid": {
|
|
60
|
-
"types": "./dist/ui/grid.d.ts",
|
|
61
|
-
"import": "./dist/ui/grid.js",
|
|
62
|
-
"default": "./dist/ui/grid.js"
|
|
63
|
-
},
|
|
64
|
-
"./ui/text-input": {
|
|
65
|
-
"types": "./dist/ui/text-input.d.ts",
|
|
66
|
-
"import": "./dist/ui/text-input.js",
|
|
67
|
-
"default": "./dist/ui/text-input.js"
|
|
69
|
+
"./ui/separator": {
|
|
70
|
+
"types": "./dist/ui/separator.d.ts",
|
|
71
|
+
"import": "./dist/ui/separator.js",
|
|
72
|
+
"default": "./dist/ui/separator.js"
|
|
68
73
|
},
|
|
69
74
|
"./ui/slider": {
|
|
70
75
|
"types": "./dist/ui/slider.d.ts",
|
|
71
76
|
"import": "./dist/ui/slider.js",
|
|
72
77
|
"default": "./dist/ui/slider.js"
|
|
73
78
|
},
|
|
74
|
-
"./ui/button-group": {
|
|
75
|
-
"types": "./dist/ui/button-group.d.ts",
|
|
76
|
-
"import": "./dist/ui/button-group.js",
|
|
77
|
-
"default": "./dist/ui/button-group.js"
|
|
78
|
-
},
|
|
79
|
-
"./ui/toggle": {
|
|
80
|
-
"types": "./dist/ui/toggle.d.ts",
|
|
81
|
-
"import": "./dist/ui/toggle.js",
|
|
82
|
-
"default": "./dist/ui/toggle.js"
|
|
83
|
-
},
|
|
84
|
-
"./ui/bar-chart": {
|
|
85
|
-
"types": "./dist/ui/bar-chart.d.ts",
|
|
86
|
-
"import": "./dist/ui/bar-chart.js",
|
|
87
|
-
"default": "./dist/ui/bar-chart.js"
|
|
88
|
-
},
|
|
89
|
-
"./ui/group": {
|
|
90
|
-
"types": "./dist/ui/group.d.ts",
|
|
91
|
-
"import": "./dist/ui/group.js",
|
|
92
|
-
"default": "./dist/ui/group.js"
|
|
93
|
-
},
|
|
94
79
|
"./ui/stack": {
|
|
95
80
|
"types": "./dist/ui/stack.d.ts",
|
|
96
81
|
"import": "./dist/ui/stack.js",
|
|
97
82
|
"default": "./dist/ui/stack.js"
|
|
98
83
|
},
|
|
99
|
-
"./ui/
|
|
100
|
-
"types": "./dist/ui/
|
|
101
|
-
"import": "./dist/ui/
|
|
102
|
-
"default": "./dist/ui/
|
|
84
|
+
"./ui/switch": {
|
|
85
|
+
"types": "./dist/ui/switch.d.ts",
|
|
86
|
+
"import": "./dist/ui/switch.js",
|
|
87
|
+
"default": "./dist/ui/switch.js"
|
|
88
|
+
},
|
|
89
|
+
"./ui/text": {
|
|
90
|
+
"types": "./dist/ui/text.d.ts",
|
|
91
|
+
"import": "./dist/ui/text.js",
|
|
92
|
+
"default": "./dist/ui/text.js"
|
|
93
|
+
},
|
|
94
|
+
"./ui/toggle-group": {
|
|
95
|
+
"types": "./dist/ui/toggle-group.d.ts",
|
|
96
|
+
"import": "./dist/ui/toggle-group.js",
|
|
97
|
+
"default": "./dist/ui/toggle-group.js"
|
|
98
|
+
},
|
|
99
|
+
"./react": {
|
|
100
|
+
"types": "./dist/react/index.d.ts",
|
|
101
|
+
"import": "./dist/react/index.js",
|
|
102
|
+
"default": "./dist/react/index.js"
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
105
|
"files": [
|
|
@@ -116,10 +116,30 @@
|
|
|
116
116
|
"viem": "^2.21.0"
|
|
117
117
|
},
|
|
118
118
|
"peerDependencies": {
|
|
119
|
-
"zod": "^4.0.0"
|
|
119
|
+
"zod": "^4.0.0",
|
|
120
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
121
|
+
"@json-render/react": "*",
|
|
122
|
+
"@neynar/ui": "*",
|
|
123
|
+
"lucide-react": "*"
|
|
124
|
+
},
|
|
125
|
+
"peerDependenciesMeta": {
|
|
126
|
+
"react": {
|
|
127
|
+
"optional": true
|
|
128
|
+
},
|
|
129
|
+
"@json-render/react": {
|
|
130
|
+
"optional": true
|
|
131
|
+
},
|
|
132
|
+
"@neynar/ui": {
|
|
133
|
+
"optional": true
|
|
134
|
+
},
|
|
135
|
+
"lucide-react": {
|
|
136
|
+
"optional": true
|
|
137
|
+
}
|
|
120
138
|
},
|
|
121
139
|
"devDependencies": {
|
|
122
140
|
"@types/node": "^25.5.0",
|
|
141
|
+
"@types/react": "^19.0.0",
|
|
142
|
+
"react": "^19.0.0",
|
|
123
143
|
"tsc-alias": "^1.8.16",
|
|
124
144
|
"tsx": "^4.0.0",
|
|
125
145
|
"typescript": "^5.4.0",
|