@rocapine/react-native-onboarding 1.31.0 → 1.33.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 (66) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/onboarding-example.d.ts +330 -30
  5. package/dist/onboarding-example.d.ts.map +1 -1
  6. package/dist/onboarding-example.js +52 -0
  7. package/dist/onboarding-example.js.map +1 -1
  8. package/dist/steps/ComposableScreen/elements/BaseBoxProps.d.ts +220 -0
  9. package/dist/steps/ComposableScreen/elements/BaseBoxProps.d.ts.map +1 -1
  10. package/dist/steps/ComposableScreen/elements/BaseBoxProps.js +83 -0
  11. package/dist/steps/ComposableScreen/elements/BaseBoxProps.js.map +1 -1
  12. package/dist/steps/ComposableScreen/elements/ButtonElement.d.ts +640 -0
  13. package/dist/steps/ComposableScreen/elements/ButtonElement.d.ts.map +1 -1
  14. package/dist/steps/ComposableScreen/elements/CarouselElement.d.ts +160 -0
  15. package/dist/steps/ComposableScreen/elements/CarouselElement.d.ts.map +1 -1
  16. package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.d.ts +160 -0
  17. package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.d.ts.map +1 -1
  18. package/dist/steps/ComposableScreen/elements/DatePickerElement.d.ts +160 -0
  19. package/dist/steps/ComposableScreen/elements/DatePickerElement.d.ts.map +1 -1
  20. package/dist/steps/ComposableScreen/elements/IconElement.d.ts +160 -0
  21. package/dist/steps/ComposableScreen/elements/IconElement.d.ts.map +1 -1
  22. package/dist/steps/ComposableScreen/elements/ImageElement.d.ts +160 -0
  23. package/dist/steps/ComposableScreen/elements/ImageElement.d.ts.map +1 -1
  24. package/dist/steps/ComposableScreen/elements/InputElement.d.ts +160 -0
  25. package/dist/steps/ComposableScreen/elements/InputElement.d.ts.map +1 -1
  26. package/dist/steps/ComposableScreen/elements/KeyboardAvoidingViewElement.d.ts +160 -0
  27. package/dist/steps/ComposableScreen/elements/KeyboardAvoidingViewElement.d.ts.map +1 -1
  28. package/dist/steps/ComposableScreen/elements/LottieElement.d.ts +160 -0
  29. package/dist/steps/ComposableScreen/elements/LottieElement.d.ts.map +1 -1
  30. package/dist/steps/ComposableScreen/elements/ProgressIndicatorElement.d.ts +160 -0
  31. package/dist/steps/ComposableScreen/elements/ProgressIndicatorElement.d.ts.map +1 -1
  32. package/dist/steps/ComposableScreen/elements/RadioGroupElement.d.ts +160 -0
  33. package/dist/steps/ComposableScreen/elements/RadioGroupElement.d.ts.map +1 -1
  34. package/dist/steps/ComposableScreen/elements/RichTextElement.d.ts +303 -0
  35. package/dist/steps/ComposableScreen/elements/RichTextElement.d.ts.map +1 -0
  36. package/dist/steps/ComposableScreen/elements/RichTextElement.js +20 -0
  37. package/dist/steps/ComposableScreen/elements/RichTextElement.js.map +1 -0
  38. package/dist/steps/ComposableScreen/elements/RiveElement.d.ts +160 -0
  39. package/dist/steps/ComposableScreen/elements/RiveElement.d.ts.map +1 -1
  40. package/dist/steps/ComposableScreen/elements/SafeAreaViewElement.d.ts +160 -0
  41. package/dist/steps/ComposableScreen/elements/SafeAreaViewElement.d.ts.map +1 -1
  42. package/dist/steps/ComposableScreen/elements/ScrollViewElement.d.ts +160 -0
  43. package/dist/steps/ComposableScreen/elements/ScrollViewElement.d.ts.map +1 -1
  44. package/dist/steps/ComposableScreen/elements/StackElement.d.ts +160 -0
  45. package/dist/steps/ComposableScreen/elements/StackElement.d.ts.map +1 -1
  46. package/dist/steps/ComposableScreen/elements/TextElement.d.ts +200 -0
  47. package/dist/steps/ComposableScreen/elements/TextElement.d.ts.map +1 -1
  48. package/dist/steps/ComposableScreen/elements/TextElement.js +6 -0
  49. package/dist/steps/ComposableScreen/elements/TextElement.js.map +1 -1
  50. package/dist/steps/ComposableScreen/elements/VideoElement.d.ts +160 -0
  51. package/dist/steps/ComposableScreen/elements/VideoElement.d.ts.map +1 -1
  52. package/dist/steps/ComposableScreen/elements/WheelPickerElement.d.ts +160 -0
  53. package/dist/steps/ComposableScreen/elements/WheelPickerElement.d.ts.map +1 -1
  54. package/dist/steps/ComposableScreen/elements/ZStackElement.d.ts +160 -0
  55. package/dist/steps/ComposableScreen/elements/ZStackElement.d.ts.map +1 -1
  56. package/dist/steps/ComposableScreen/types.d.ts +12 -0
  57. package/dist/steps/ComposableScreen/types.d.ts.map +1 -1
  58. package/dist/steps/ComposableScreen/types.js +15 -2
  59. package/dist/steps/ComposableScreen/types.js.map +1 -1
  60. package/package.json +1 -1
  61. package/src/index.ts +13 -0
  62. package/src/onboarding-example.ts +52 -0
  63. package/src/steps/ComposableScreen/elements/BaseBoxProps.ts +211 -0
  64. package/src/steps/ComposableScreen/elements/RichTextElement.ts +55 -0
  65. package/src/steps/ComposableScreen/elements/TextElement.ts +14 -0
  66. package/src/steps/ComposableScreen/types.ts +39 -2
@@ -50,6 +50,213 @@ export const ShadowOffsetSchema = z.object({
50
50
  height: z.number(),
51
51
  });
52
52
 
53
+ // ---------------------------------------------------------------------------
54
+ // Animation / Transform surface
55
+ //
56
+ // Schema stays intentionally close to react-native-reanimated: `preset` values
57
+ // are the *exact* reanimated builder names (e.g. `FadeInDown`, `SlideOutLeft`,
58
+ // `LinearTransition`), so the UI renderer resolves them by direct namespace
59
+ // lookup (`Reanimated[preset]`) rather than a translation table. Modifier fields
60
+ // (`duration`/`delay`/`spring`/`easing`) map to reanimated builder methods
61
+ // (`.duration().delay().springify().easing()`).
62
+ // ---------------------------------------------------------------------------
63
+
64
+ // Reuses the easing-name convention from ProgressIndicatorElement.
65
+ export type AnimationEasing = "linear" | "ease-in" | "ease-out" | "ease-in-out";
66
+
67
+ const AnimationEasingSchema = z.enum(["linear", "ease-in", "ease-out", "ease-in-out"]);
68
+
69
+ // Mirrors reanimated's `.springify(config)` — only the fields it accepts.
70
+ // When `spring` is present it wins over `easing` (matches reanimated semantics).
71
+ export type SpringConfig = {
72
+ damping?: number;
73
+ stiffness?: number;
74
+ mass?: number;
75
+ };
76
+
77
+ const SpringConfigSchema = z.object({
78
+ damping: z.number().positive().optional(),
79
+ stiffness: z.number().positive().optional(),
80
+ mass: z.number().positive().optional(),
81
+ });
82
+
83
+ // Exact reanimated entering builder names.
84
+ export type EnteringPreset =
85
+ | "FadeIn" | "FadeInUp" | "FadeInDown" | "FadeInLeft" | "FadeInRight"
86
+ | "SlideInUp" | "SlideInDown" | "SlideInLeft" | "SlideInRight"
87
+ | "ZoomIn" | "ZoomInRotate" | "ZoomInUp" | "ZoomInDown" | "ZoomInLeft" | "ZoomInRight"
88
+ | "ZoomInEasyUp" | "ZoomInEasyDown"
89
+ | "BounceIn" | "BounceInUp" | "BounceInDown" | "BounceInLeft" | "BounceInRight"
90
+ | "FlipInXUp" | "FlipInYLeft" | "FlipInXDown" | "FlipInYRight" | "FlipInEasyX" | "FlipInEasyY"
91
+ | "StretchInX" | "StretchInY"
92
+ | "RotateInDownLeft" | "RotateInDownRight" | "RotateInUpLeft" | "RotateInUpRight"
93
+ | "RollInLeft" | "RollInRight"
94
+ | "PinwheelIn"
95
+ | "LightSpeedInLeft" | "LightSpeedInRight";
96
+
97
+ const EnteringPresetSchema = z.enum([
98
+ "FadeIn", "FadeInUp", "FadeInDown", "FadeInLeft", "FadeInRight",
99
+ "SlideInUp", "SlideInDown", "SlideInLeft", "SlideInRight",
100
+ "ZoomIn", "ZoomInRotate", "ZoomInUp", "ZoomInDown", "ZoomInLeft", "ZoomInRight",
101
+ "ZoomInEasyUp", "ZoomInEasyDown",
102
+ "BounceIn", "BounceInUp", "BounceInDown", "BounceInLeft", "BounceInRight",
103
+ "FlipInXUp", "FlipInYLeft", "FlipInXDown", "FlipInYRight", "FlipInEasyX", "FlipInEasyY",
104
+ "StretchInX", "StretchInY",
105
+ "RotateInDownLeft", "RotateInDownRight", "RotateInUpLeft", "RotateInUpRight",
106
+ "RollInLeft", "RollInRight",
107
+ "PinwheelIn",
108
+ "LightSpeedInLeft", "LightSpeedInRight",
109
+ ]);
110
+
111
+ // Exact reanimated exiting builder names.
112
+ export type ExitingPreset =
113
+ | "FadeOut" | "FadeOutUp" | "FadeOutDown" | "FadeOutLeft" | "FadeOutRight"
114
+ | "SlideOutUp" | "SlideOutDown" | "SlideOutLeft" | "SlideOutRight"
115
+ | "ZoomOut" | "ZoomOutRotate" | "ZoomOutUp" | "ZoomOutDown" | "ZoomOutLeft" | "ZoomOutRight"
116
+ | "ZoomOutEasyUp" | "ZoomOutEasyDown"
117
+ | "BounceOut" | "BounceOutUp" | "BounceOutDown" | "BounceOutLeft" | "BounceOutRight"
118
+ | "FlipOutXUp" | "FlipOutYLeft" | "FlipOutXDown" | "FlipOutYRight" | "FlipOutEasyX" | "FlipOutEasyY"
119
+ | "StretchOutX" | "StretchOutY"
120
+ | "RotateOutDownLeft" | "RotateOutDownRight" | "RotateOutUpLeft" | "RotateOutUpRight"
121
+ | "RollOutLeft" | "RollOutRight"
122
+ | "PinwheelOut"
123
+ | "LightSpeedOutLeft" | "LightSpeedOutRight";
124
+
125
+ const ExitingPresetSchema = z.enum([
126
+ "FadeOut", "FadeOutUp", "FadeOutDown", "FadeOutLeft", "FadeOutRight",
127
+ "SlideOutUp", "SlideOutDown", "SlideOutLeft", "SlideOutRight",
128
+ "ZoomOut", "ZoomOutRotate", "ZoomOutUp", "ZoomOutDown", "ZoomOutLeft", "ZoomOutRight",
129
+ "ZoomOutEasyUp", "ZoomOutEasyDown",
130
+ "BounceOut", "BounceOutUp", "BounceOutDown", "BounceOutLeft", "BounceOutRight",
131
+ "FlipOutXUp", "FlipOutYLeft", "FlipOutXDown", "FlipOutYRight", "FlipOutEasyX", "FlipOutEasyY",
132
+ "StretchOutX", "StretchOutY",
133
+ "RotateOutDownLeft", "RotateOutDownRight", "RotateOutUpLeft", "RotateOutUpRight",
134
+ "RollOutLeft", "RollOutRight",
135
+ "PinwheelOut",
136
+ "LightSpeedOutLeft", "LightSpeedOutRight",
137
+ ]);
138
+
139
+ // Exact reanimated layout-transition builder names.
140
+ export type LayoutPreset =
141
+ | "LinearTransition" | "FadingTransition" | "SequencedTransition"
142
+ | "JumpingTransition" | "CurvedTransition" | "EntryExitTransition";
143
+
144
+ const LayoutPresetSchema = z.enum([
145
+ "LinearTransition", "FadingTransition", "SequencedTransition",
146
+ "JumpingTransition", "CurvedTransition", "EntryExitTransition",
147
+ ]);
148
+
149
+ export type EnteringAnimation = {
150
+ preset: EnteringPreset;
151
+ duration?: number;
152
+ delay?: number;
153
+ easing?: AnimationEasing;
154
+ spring?: SpringConfig;
155
+ };
156
+
157
+ const EnteringAnimationSchema = z.object({
158
+ preset: EnteringPresetSchema,
159
+ duration: z.number().min(0).optional(),
160
+ delay: z.number().min(0).optional(),
161
+ easing: AnimationEasingSchema.optional(),
162
+ spring: SpringConfigSchema.optional(),
163
+ });
164
+
165
+ export type ExitingAnimation = {
166
+ preset: ExitingPreset;
167
+ duration?: number;
168
+ delay?: number;
169
+ easing?: AnimationEasing;
170
+ spring?: SpringConfig;
171
+ };
172
+
173
+ const ExitingAnimationSchema = z.object({
174
+ preset: ExitingPresetSchema,
175
+ duration: z.number().min(0).optional(),
176
+ delay: z.number().min(0).optional(),
177
+ easing: AnimationEasingSchema.optional(),
178
+ spring: SpringConfigSchema.optional(),
179
+ });
180
+
181
+ export type LayoutAnimation = {
182
+ preset: LayoutPreset;
183
+ duration?: number;
184
+ spring?: SpringConfig;
185
+ };
186
+
187
+ const LayoutAnimationSchema = z.object({
188
+ preset: LayoutPresetSchema,
189
+ duration: z.number().min(0).optional(),
190
+ spring: SpringConfigSchema.optional(),
191
+ });
192
+
193
+ // Continuous looping effects — the one piece not named after a reanimated
194
+ // builder. Rendered imperatively with `withRepeat` over `withTiming`.
195
+ export type EffectPreset = "pulse" | "fade" | "rotate" | "shimmer" | "bounce";
196
+
197
+ const EffectPresetSchema = z.enum(["pulse", "fade", "rotate", "shimmer", "bounce"]);
198
+
199
+ export type ElementEffect = {
200
+ preset: EffectPreset;
201
+ duration?: number;
202
+ delay?: number;
203
+ easing?: AnimationEasing;
204
+ loop?: boolean;
205
+ /** pulse: scale bounds (default 0.95 / 1.05). */
206
+ minScale?: number;
207
+ maxScale?: number;
208
+ /** fade: lower opacity bound (default 0.4). */
209
+ minOpacity?: number;
210
+ /** rotate: sweep in degrees (default 360). */
211
+ degrees?: number;
212
+ };
213
+
214
+ const EffectSchema = z.object({
215
+ preset: EffectPresetSchema,
216
+ duration: z.number().min(0).optional(),
217
+ delay: z.number().min(0).optional(),
218
+ easing: AnimationEasingSchema.optional(),
219
+ loop: z.boolean().optional(),
220
+ minScale: z.number().positive().optional(),
221
+ maxScale: z.number().positive().optional(),
222
+ minOpacity: z.number().min(0).max(1).optional(),
223
+ degrees: z.number().optional(),
224
+ });
225
+
226
+ export type ElementAnimation = {
227
+ entering?: EnteringAnimation;
228
+ exiting?: ExitingAnimation;
229
+ layout?: LayoutAnimation;
230
+ effect?: ElementEffect;
231
+ };
232
+
233
+ const ElementAnimationSchema = z.object({
234
+ entering: EnteringAnimationSchema.optional(),
235
+ exiting: ExitingAnimationSchema.optional(),
236
+ layout: LayoutAnimationSchema.optional(),
237
+ effect: EffectSchema.optional(),
238
+ });
239
+
240
+ // Static transform surface — also what `effect` animates at runtime.
241
+ export type ElementTransform = {
242
+ translateX?: number;
243
+ translateY?: number;
244
+ scale?: number;
245
+ scaleX?: number;
246
+ scaleY?: number;
247
+ /** degrees */
248
+ rotate?: number;
249
+ };
250
+
251
+ const TransformSchema = z.object({
252
+ translateX: z.number().optional(),
253
+ translateY: z.number().optional(),
254
+ scale: z.number().optional(),
255
+ scaleX: z.number().optional(),
256
+ scaleY: z.number().optional(),
257
+ rotate: z.number().optional(),
258
+ });
259
+
53
260
  export type BaseBoxProps = {
54
261
  width?: number | string;
55
262
  height?: number | string;
@@ -80,6 +287,8 @@ export type BaseBoxProps = {
80
287
  shadowOpacity?: number;
81
288
  shadowRadius?: number;
82
289
  elevation?: number;
290
+ transform?: ElementTransform;
291
+ animation?: ElementAnimation;
83
292
  };
84
293
 
85
294
  export const BaseBoxPropsSchema = z.object({
@@ -112,4 +321,6 @@ export const BaseBoxPropsSchema = z.object({
112
321
  shadowOpacity: z.number().min(0).max(1).optional(),
113
322
  shadowRadius: z.number().min(0).optional(),
114
323
  elevation: z.number().min(0).optional(),
324
+ transform: TransformSchema.optional(),
325
+ animation: ElementAnimationSchema.optional(),
115
326
  });
@@ -0,0 +1,55 @@
1
+ import { z } from "zod";
2
+ import { BaseBoxProps, BaseBoxPropsSchema } from "./BaseBoxProps";
3
+
4
+ /**
5
+ * Multi-element container that lays out child `Text` elements as a **wrapping
6
+ * flex row** — each child is a full `Text` UIElement that wraps to the next line
7
+ * as a whole unit (word or styled "chip"). Unlike inline `TextSpan`s (the `Text`
8
+ * element's `content[]`, which are nested `<Text>` and so cannot carry box
9
+ * styling), each `RichText` child is a real flex child, so it honors its own box
10
+ * props — `padding`, `borderRadius`, `borderWidth`, `backgroundColor`, `margin`,
11
+ * `transform` (e.g. rotated pills), `renderWhen`, and `expression` mode.
12
+ *
13
+ * The text-style fields below (`fontSize`, `color`, …) act as **inherited
14
+ * defaults**: every child `Text` uses them for any matching prop it omits, so a
15
+ * title's base typography is declared once on the container and only the
16
+ * highlighted "chip" children override (color, background, weight). Children
17
+ * always win over the inherited default.
18
+ *
19
+ * Use this to compose mixed runs of plain words and padded/rounded chips that
20
+ * wrap and align together (e.g. a marketing title with highlighted pills). For
21
+ * pure character-level inline flow with text-only styling, use `Text.content`
22
+ * spans instead.
23
+ */
24
+ export type RichTextElementProps = BaseBoxProps & {
25
+ // Layout (wrapping row)
26
+ gap?: number;
27
+ alignItems?: "flex-start" | "center" | "flex-end" | "baseline" | "stretch";
28
+ justifyContent?: "flex-start" | "center" | "flex-end" | "space-between" | "space-around";
29
+ /** Defaults to `"wrap"` — the whole point of RichText is multi-line wrapping. */
30
+ flexWrap?: "wrap" | "nowrap";
31
+ // Inherited text-style defaults for children
32
+ fontSize?: number;
33
+ fontWeight?: string;
34
+ fontFamily?: string | "inherit";
35
+ fontStyle?: "normal" | "italic";
36
+ color?: string;
37
+ textAlign?: "left" | "center" | "right";
38
+ letterSpacing?: number;
39
+ lineHeight?: number;
40
+ };
41
+
42
+ export const RichTextElementPropsSchema = BaseBoxPropsSchema.extend({
43
+ gap: z.number().optional(),
44
+ alignItems: z.enum(["flex-start", "center", "flex-end", "baseline", "stretch"]).optional(),
45
+ justifyContent: z.enum(["flex-start", "center", "flex-end", "space-between", "space-around"]).optional(),
46
+ flexWrap: z.enum(["wrap", "nowrap"]).optional(),
47
+ fontSize: z.number().optional(),
48
+ fontWeight: z.string().optional(),
49
+ fontFamily: z.string().optional(),
50
+ fontStyle: z.enum(["normal", "italic"]).optional(),
51
+ color: z.string().optional(),
52
+ textAlign: z.enum(["left", "center", "right"]).optional(),
53
+ letterSpacing: z.number().optional(),
54
+ lineHeight: z.number().optional(),
55
+ });
@@ -18,12 +18,20 @@ export type TextSpan = {
18
18
  fontFamily?: string | "inherit";
19
19
  fontSize?: number;
20
20
  letterSpacing?: number;
21
+ lineHeight?: number;
21
22
  color?: string;
23
+ /** Inline highlight behind the span text. */
24
+ backgroundColor?: string;
25
+ /** Per-span opacity (0–1). */
26
+ opacity?: number;
27
+ textTransform?: "none" | "uppercase" | "lowercase" | "capitalize";
22
28
  textDecorationLine?:
23
29
  | "none"
24
30
  | "underline"
25
31
  | "line-through"
26
32
  | "underline line-through";
33
+ textDecorationColor?: string;
34
+ textDecorationStyle?: "solid" | "double" | "dotted" | "dashed";
27
35
  };
28
36
 
29
37
  export const TextSpanSchema = z.object({
@@ -33,10 +41,16 @@ export const TextSpanSchema = z.object({
33
41
  fontFamily: z.string().optional(),
34
42
  fontSize: z.number().optional(),
35
43
  letterSpacing: z.number().optional(),
44
+ lineHeight: z.number().optional(),
36
45
  color: z.string().optional(),
46
+ backgroundColor: z.string().optional(),
47
+ opacity: z.number().min(0).max(1).optional(),
48
+ textTransform: z.enum(["none", "uppercase", "lowercase", "capitalize"]).optional(),
37
49
  textDecorationLine: z
38
50
  .enum(["none", "underline", "line-through", "underline line-through"])
39
51
  .optional(),
52
+ textDecorationColor: z.string().optional(),
53
+ textDecorationStyle: z.enum(["solid", "double", "dotted", "dashed"]).optional(),
40
54
  });
41
55
 
42
56
  export type TextElementProps = BaseBoxProps & {
@@ -8,6 +8,7 @@ import {
8
8
  } from "../common.types";
9
9
  import { type StackElementProps, StackElementPropsSchema } from "./elements/StackElement";
10
10
  import { type TextElementProps, TextElementPropsSchema } from "./elements/TextElement";
11
+ import { type RichTextElementProps, RichTextElementPropsSchema } from "./elements/RichTextElement";
11
12
  import { type ImageElementProps, ImageElementPropsSchema } from "./elements/ImageElement";
12
13
  import { type LottieElementProps, LottieElementPropsSchema } from "./elements/LottieElement";
13
14
  import { type RiveElementProps, RiveElementPropsSchema } from "./elements/RiveElement";
@@ -30,10 +31,25 @@ import {
30
31
  import { type ProgressIndicatorElementProps, ProgressIndicatorElementPropsSchema } from "./elements/ProgressIndicatorElement";
31
32
 
32
33
  export type { BaseBoxProps, GradientBackground, GradientEdge, GradientStop, LinearGradientConfig } from "./elements/BaseBoxProps";
34
+ export type {
35
+ AnimationEasing,
36
+ SpringConfig,
37
+ EnteringPreset,
38
+ ExitingPreset,
39
+ LayoutPreset,
40
+ EffectPreset,
41
+ EnteringAnimation,
42
+ ExitingAnimation,
43
+ LayoutAnimation,
44
+ ElementEffect,
45
+ ElementAnimation,
46
+ ElementTransform,
47
+ } from "./elements/BaseBoxProps";
33
48
  export { BaseBoxPropsSchema, GradientBackgroundSchema } from "./elements/BaseBoxProps";
34
49
  export type { StackElementProps } from "./elements/StackElement";
35
50
  export type { TextElementProps, TextSpan } from "./elements/TextElement";
36
51
  export { TextSpanSchema } from "./elements/TextElement";
52
+ export type { RichTextElementProps } from "./elements/RichTextElement";
37
53
  export type { ImageElementProps } from "./elements/ImageElement";
38
54
  export type { LottieElementProps } from "./elements/LottieElement";
39
55
  export type { RiveElementProps } from "./elements/RiveElement";
@@ -92,6 +108,14 @@ type UIElement =
92
108
  type: "Text";
93
109
  props: TextElementProps;
94
110
  }
111
+ | {
112
+ id: string;
113
+ name?: string;
114
+ renderWhen?: LeafCondition | ConditionGroup;
115
+ type: "RichText";
116
+ props: RichTextElementProps;
117
+ children: Array<Extract<UIElement, { type: "Text" }>>;
118
+ }
95
119
  | {
96
120
  id: string;
97
121
  name?: string;
@@ -217,6 +241,17 @@ type UIElement =
217
241
  props: ProgressIndicatorElementProps;
218
242
  };
219
243
 
244
+ // The `Text` variant, extracted so `RichText` can restrict its children to
245
+ // Text-only (children: z.array(TextUIElementSchema)) while the union references
246
+ // the same object.
247
+ const TextUIElementSchema = z.object({
248
+ id: z.string(),
249
+ name: z.string().optional(),
250
+ renderWhen: z.union([LeafConditionSchema, ConditionGroupSchema]).optional(),
251
+ type: z.literal("Text"),
252
+ props: TextElementPropsSchema,
253
+ });
254
+
220
255
  const UIElementSchema: z.ZodType<UIElement> = z.lazy(() =>
221
256
  z.union([
222
257
  z.object({
@@ -227,12 +262,14 @@ const UIElementSchema: z.ZodType<UIElement> = z.lazy(() =>
227
262
  props: StackElementPropsSchema,
228
263
  children: z.array(UIElementSchema),
229
264
  }),
265
+ TextUIElementSchema,
230
266
  z.object({
231
267
  id: z.string(),
232
268
  name: z.string().optional(),
233
269
  renderWhen: z.union([LeafConditionSchema, ConditionGroupSchema]).optional(),
234
- type: z.literal("Text"),
235
- props: TextElementPropsSchema,
270
+ type: z.literal("RichText"),
271
+ props: RichTextElementPropsSchema,
272
+ children: z.array(TextUIElementSchema),
236
273
  }),
237
274
  z.object({
238
275
  id: z.string(),