Skip to content

Commit 0594fbf

Browse files
committed
update the action schemas
1 parent 6901a0c commit 0594fbf

File tree

1 file changed

+320
-14
lines changed

1 file changed

+320
-14
lines changed

src/common/schema/flexMessage.ts

Lines changed: 320 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,328 @@
11
import { z } from "zod";
22

3+
const flexActionSchema = z.discriminatedUnion("type", [
4+
z.object({
5+
type: z.literal("postback"),
6+
data: z.string(),
7+
label: z.string(),
8+
displayText: z.string().optional(),
9+
inputOption: z
10+
.enum(["closeRichMenu", "openRichMenu", "openKeyboard", "openVoice"])
11+
.optional(),
12+
fillInText: z.string().optional(),
13+
}),
14+
z.object({
15+
type: z.literal("message"),
16+
label: z.string(),
17+
text: z.string(),
18+
}),
19+
z.object({
20+
type: z.literal("uri"),
21+
label: z.string(),
22+
uri: z.string(),
23+
altUri: z
24+
.object({
25+
desktop: z.string(),
26+
})
27+
.optional(),
28+
}),
29+
z.object({
30+
type: z.literal("datetimepicker"),
31+
label: z.string(),
32+
data: z.string(),
33+
mode: z.enum(["date", "time", "datetime"]),
34+
initial: z.string().optional(),
35+
max: z.string().optional(),
36+
min: z.string().optional(),
37+
}),
38+
z.object({
39+
type: z.literal("camera"),
40+
label: z.string(),
41+
}),
42+
z.object({
43+
type: z.literal("cameraRoll"),
44+
label: z.string(),
45+
}),
46+
z.object({
47+
type: z.literal("location"),
48+
label: z.string(),
49+
}),
50+
z.object({
51+
type: z.literal("richmenuswitch"),
52+
label: z.string(),
53+
richMenuAliasId: z.string(),
54+
data: z.string(),
55+
}),
56+
z.object({
57+
type: z.literal("clipboard"),
58+
label: z.string(),
59+
clipboardText: z.string(),
60+
}),
61+
]);
62+
63+
const flexSpanSchema = z.object({
64+
type: z.literal("span"),
65+
text: z.string(),
66+
color: z.string().optional(),
67+
size: z
68+
.enum(["xxs", "xs", "sm", "md", "lg", "xl", "xxl", "3xl", "4xl", "5xl"])
69+
.optional(),
70+
weight: z.enum(["regular", "bold"]).optional(),
71+
style: z.enum(["normal", "italic"]).optional(),
72+
decoration: z.enum(["none", "underline", "line-through"]).optional(),
73+
});
74+
75+
const flexComponentSchema: z.ZodType<any> = z.lazy(() =>
76+
z.discriminatedUnion("type", [
77+
z.object({
78+
type: z.literal("box"),
79+
layout: z.enum(["horizontal", "vertical", "baseline"]),
80+
contents: z.array(flexComponentSchema),
81+
backgroundColor: z.string().optional(),
82+
borderColor: z.string().optional(),
83+
borderWidth: z.string().optional(),
84+
cornerRadius: z.string().optional(),
85+
margin: z.enum(["none", "xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
86+
paddingAll: z.string().optional(),
87+
paddingTop: z.string().optional(),
88+
paddingBottom: z.string().optional(),
89+
paddingStart: z.string().optional(),
90+
paddingEnd: z.string().optional(),
91+
spacing: z.enum(["none", "xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
92+
width: z.string().optional(),
93+
height: z.string().optional(),
94+
flex: z.number().optional(),
95+
justifyContent: z
96+
.enum([
97+
"flex-start",
98+
"center",
99+
"flex-end",
100+
"space-between",
101+
"space-around",
102+
"space-evenly",
103+
])
104+
.optional(),
105+
alignItems: z.enum(["flex-start", "center", "flex-end"]).optional(),
106+
background: z
107+
.object({
108+
type: z.literal("linearGradient"),
109+
angle: z.string(),
110+
startColor: z.string(),
111+
endColor: z.string(),
112+
})
113+
.optional(),
114+
action: flexActionSchema.optional(),
115+
offsetTop: z.string().optional(),
116+
offsetBottom: z.string().optional(),
117+
offsetStart: z.string().optional(),
118+
offsetEnd: z.string().optional(),
119+
position: z.enum(["relative", "absolute"]).optional(),
120+
}),
121+
z.object({
122+
type: z.literal("button"),
123+
action: flexActionSchema,
124+
flex: z.number().optional(),
125+
margin: z.enum(["none", "xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
126+
position: z.enum(["relative", "absolute"]).optional(),
127+
offsetTop: z.string().optional(),
128+
offsetBottom: z.string().optional(),
129+
offsetStart: z.string().optional(),
130+
offsetEnd: z.string().optional(),
131+
height: z.enum(["sm", "md"]).optional(),
132+
style: z.enum(["link", "primary", "secondary"]).optional(),
133+
color: z.string().optional(),
134+
gravity: z.enum(["top", "bottom", "center"]).optional(),
135+
adjustMode: z.enum(["shrink-to-fit"]).optional(),
136+
scaling: z.boolean().optional(),
137+
}),
138+
z.object({
139+
type: z.literal("filler"),
140+
flex: z.number().optional(),
141+
}),
142+
z.object({
143+
type: z.literal("icon"),
144+
url: z.string(),
145+
margin: z.enum(["none", "xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
146+
position: z.enum(["relative", "absolute"]).optional(),
147+
offsetTop: z.string().optional(),
148+
offsetBottom: z.string().optional(),
149+
offsetStart: z.string().optional(),
150+
offsetEnd: z.string().optional(),
151+
size: z
152+
.enum(["xxs", "xs", "sm", "md", "lg", "xl", "xxl", "3xl", "4xl", "5xl"])
153+
.optional(),
154+
aspectRatio: z.string().optional(),
155+
scaling: z.boolean().optional(),
156+
}),
157+
z.object({
158+
type: z.literal("image"),
159+
url: z.string(),
160+
flex: z.number().optional(),
161+
margin: z.enum(["none", "xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
162+
position: z.enum(["relative", "absolute"]).optional(),
163+
offsetTop: z.string().optional(),
164+
offsetBottom: z.string().optional(),
165+
offsetStart: z.string().optional(),
166+
offsetEnd: z.string().optional(),
167+
align: z.enum(["start", "end", "center"]).optional(),
168+
gravity: z.enum(["top", "bottom", "center"]).optional(),
169+
size: z
170+
.enum([
171+
"xxs",
172+
"xs",
173+
"sm",
174+
"md",
175+
"lg",
176+
"xl",
177+
"xxl",
178+
"3xl",
179+
"4xl",
180+
"5xl",
181+
"full",
182+
])
183+
.optional(),
184+
aspectRatio: z.string().optional(),
185+
aspectMode: z.enum(["cover", "fit"]).optional(),
186+
backgroundColor: z.string().optional(),
187+
action: flexActionSchema.optional(),
188+
animated: z.boolean().optional(),
189+
scaling: z.boolean().optional(),
190+
}),
191+
z.object({
192+
type: z.literal("separator"),
193+
margin: z.enum(["none", "xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
194+
color: z.string().optional(),
195+
}),
196+
z.object({
197+
type: z.literal("spacer"),
198+
size: z.enum(["xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
199+
}),
200+
z.object({
201+
type: z.literal("text"),
202+
text: z.string(),
203+
contents: z.array(flexSpanSchema).optional(),
204+
adjustMode: z.enum(["shrink-to-fit"]).optional(),
205+
flex: z.number().optional(),
206+
margin: z.enum(["none", "xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
207+
position: z.enum(["relative", "absolute"]).optional(),
208+
offsetTop: z.string().optional(),
209+
offsetBottom: z.string().optional(),
210+
offsetStart: z.string().optional(),
211+
offsetEnd: z.string().optional(),
212+
size: z
213+
.enum(["xxs", "xs", "sm", "md", "lg", "xl", "xxl", "3xl", "4xl", "5xl"])
214+
.optional(),
215+
align: z.enum(["start", "end", "center"]).optional(),
216+
gravity: z.enum(["top", "bottom", "center"]).optional(),
217+
wrap: z.boolean().optional(),
218+
lineSpacing: z.enum(["xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
219+
weight: z.enum(["regular", "bold"]).optional(),
220+
color: z.string().optional(),
221+
action: flexActionSchema.optional(),
222+
style: z.enum(["normal", "italic"]).optional(),
223+
decoration: z.enum(["none", "underline", "line-through"]).optional(),
224+
maxLines: z.number().optional(),
225+
scaling: z.boolean().optional(),
226+
}),
227+
z.object({
228+
type: z.literal("video"),
229+
url: z.string(),
230+
previewUrl: z.string(),
231+
altContent: flexComponentSchema,
232+
flex: z.number().optional(),
233+
margin: z.enum(["none", "xs", "sm", "md", "lg", "xl", "xxl"]).optional(),
234+
position: z.enum(["relative", "absolute"]).optional(),
235+
offsetTop: z.string().optional(),
236+
offsetBottom: z.string().optional(),
237+
offsetStart: z.string().optional(),
238+
offsetEnd: z.string().optional(),
239+
align: z.enum(["start", "end", "center"]).optional(),
240+
gravity: z.enum(["top", "bottom", "center"]).optional(),
241+
size: z
242+
.enum([
243+
"xxs",
244+
"xs",
245+
"sm",
246+
"md",
247+
"lg",
248+
"xl",
249+
"xxl",
250+
"3xl",
251+
"4xl",
252+
"5xl",
253+
"full",
254+
])
255+
.optional(),
256+
aspectRatio: z.string().optional(),
257+
action: flexActionSchema.optional(),
258+
scaling: z.boolean().optional(),
259+
}),
260+
]),
261+
);
262+
263+
const flexBubbleStylesSchema = z.object({
264+
header: z
265+
.object({
266+
backgroundColor: z.string().optional(),
267+
separator: z.boolean().optional(),
268+
separatorColor: z.string().optional(),
269+
})
270+
.optional(),
271+
hero: z
272+
.object({
273+
backgroundColor: z.string().optional(),
274+
separator: z.boolean().optional(),
275+
separatorColor: z.string().optional(),
276+
})
277+
.optional(),
278+
body: z
279+
.object({
280+
backgroundColor: z.string().optional(),
281+
separator: z.boolean().optional(),
282+
separatorColor: z.string().optional(),
283+
})
284+
.optional(),
285+
footer: z
286+
.object({
287+
backgroundColor: z.string().optional(),
288+
separator: z.boolean().optional(),
289+
separatorColor: z.string().optional(),
290+
})
291+
.optional(),
292+
});
293+
294+
const flexBubbleSchema = z.object({
295+
type: z.literal("bubble"),
296+
size: z
297+
.enum(["nano", "micro", "deca", "hecto", "kilo", "mega", "giga"])
298+
.optional(),
299+
direction: z.enum(["ltr", "rtl"]).optional(),
300+
header: flexComponentSchema.optional(),
301+
hero: flexComponentSchema.optional(),
302+
body: flexComponentSchema.optional(),
303+
footer: flexComponentSchema.optional(),
304+
styles: flexBubbleStylesSchema.optional(),
305+
action: flexActionSchema.optional(),
306+
});
307+
308+
const flexCarouselSchema = z.object({
309+
type: z.literal("carousel"),
310+
contents: z.array(flexBubbleSchema),
311+
});
312+
313+
const flexContainerSchema = z.discriminatedUnion("type", [
314+
flexBubbleSchema,
315+
flexCarouselSchema,
316+
]);
317+
3318
export const flexMessageSchema = z.object({
4319
type: z.literal("flex").default("flex"),
5320
altText: z
6321
.string()
7322
.describe("Alternative text shown when flex message cannot be displayed."),
8-
contents: z
9-
.object({
10-
type: z
11-
.enum(["bubble", "carousel"])
12-
.describe(
13-
"Type of the container. 'bubble' for single container, 'carousel' for multiple swipeable bubbles.",
14-
),
15-
})
16-
.passthrough()
17-
.describe(
18-
"Flexible container structure following LINE Flex Message format. For 'bubble' type, can include header, " +
19-
"hero, body, footer, and styles sections. For 'carousel' type, includes an array of bubble containers in " +
20-
"the 'contents' property.",
21-
),
323+
contents: flexContainerSchema.describe(
324+
"Flexible container structure following LINE Flex Message format. For 'bubble' type, can include header, " +
325+
"hero, body, footer, and styles sections. For 'carousel' type, includes an array of bubble containers in " +
326+
"the 'contents' property.",
327+
),
22328
});

0 commit comments

Comments
 (0)