@rocapine/react-native-onboarding-ui 1.0.1 → 1.1.3

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.
@@ -10,10 +10,10 @@ export declare const LoaderStepPayloadSchema: z.ZodObject<{
10
10
  completed: z.ZodString;
11
11
  }, z.core.$strip>>;
12
12
  didYouKnowImages: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
13
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
13
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
14
14
  localPathId: z.ZodString;
15
15
  }, z.core.$strip>, z.ZodObject<{
16
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
16
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
17
17
  url: z.ZodString;
18
18
  }, z.core.$strip>]>>>>;
19
19
  duration: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
@@ -35,10 +35,10 @@ export declare const LoaderStepTypeSchema: z.ZodObject<{
35
35
  completed: z.ZodString;
36
36
  }, z.core.$strip>>;
37
37
  didYouKnowImages: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
38
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
38
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
39
39
  localPathId: z.ZodString;
40
40
  }, z.core.$strip>, z.ZodObject<{
41
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
41
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
42
42
  url: z.ZodString;
43
43
  }, z.core.$strip>]>>>>;
44
44
  duration: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
@@ -1,10 +1,10 @@
1
1
  import { z } from "zod";
2
2
  export declare const MediaContentStepPayloadSchema: z.ZodObject<{
3
3
  mediaSource: z.ZodUnion<readonly [z.ZodObject<{
4
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
4
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
5
5
  localPathId: z.ZodString;
6
6
  }, z.core.$strip>, z.ZodObject<{
7
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
7
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
8
8
  url: z.ZodString;
9
9
  }, z.core.$strip>]>;
10
10
  title: z.ZodString;
@@ -22,10 +22,10 @@ export declare const MediaContentStepTypeSchema: z.ZodObject<{
22
22
  displayProgressHeader: z.ZodBoolean;
23
23
  payload: z.ZodObject<{
24
24
  mediaSource: z.ZodUnion<readonly [z.ZodObject<{
25
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
25
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
26
26
  localPathId: z.ZodString;
27
27
  }, z.core.$strip>, z.ZodObject<{
28
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
28
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
29
29
  url: z.ZodString;
30
30
  }, z.core.$strip>]>;
31
31
  title: z.ZodString;
@@ -1,10 +1,10 @@
1
1
  import { z } from "zod";
2
2
  export declare const CustomPayloadSchema: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodAny>>>;
3
3
  export declare const MediaSourceSchema: z.ZodUnion<readonly [z.ZodObject<{
4
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
4
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
5
5
  localPathId: z.ZodString;
6
6
  }, z.core.$strip>, z.ZodObject<{
7
- type: z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"image">, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
7
+ type: z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodLiteral<"video">, z.ZodLiteral<"image">]>, z.ZodLiteral<"lottie">]>, z.ZodLiteral<"rive">]>;
8
8
  url: z.ZodString;
9
9
  }, z.core.$strip>]>;
10
10
  export declare const SocialProofSchema: z.ZodObject<{
@@ -5,11 +5,11 @@ const zod_1 = require("zod");
5
5
  exports.CustomPayloadSchema = zod_1.z.record(zod_1.z.string(), zod_1.z.any()).nullish();
6
6
  exports.MediaSourceSchema = zod_1.z.union([
7
7
  zod_1.z.object({
8
- type: zod_1.z.literal("image").or(zod_1.z.literal("lottie")).or(zod_1.z.literal("rive")),
8
+ type: zod_1.z.literal("video").or(zod_1.z.literal("image")).or(zod_1.z.literal("lottie")).or(zod_1.z.literal("rive")),
9
9
  localPathId: zod_1.z.string(),
10
10
  }),
11
11
  zod_1.z.object({
12
- type: zod_1.z.literal("image").or(zod_1.z.literal("lottie")).or(zod_1.z.literal("rive")),
12
+ type: zod_1.z.literal("video").or(zod_1.z.literal("image")).or(zod_1.z.literal("lottie")).or(zod_1.z.literal("rive")),
13
13
  url: zod_1.z.string(),
14
14
  }),
15
15
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/UI/Pages/types.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAEX,QAAA,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;AAE9D,QAAA,iBAAiB,GAAG,OAAC,CAAC,KAAK,CAAC;IACvC,OAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACtE,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE;KACxB,CAAC;IACF,OAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACtE,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE;KAChB,CAAC;CACH,CAAC,CAAC;AAEU,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE;IACxB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAEU,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,CAAC;IACpC,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;IACjB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;CACpB,CAAC,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/UI/Pages/types.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAEX,QAAA,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;AAE9D,QAAA,iBAAiB,GAAG,OAAC,CAAC,KAAK,CAAC;IACvC,OAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7F,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE;KACxB,CAAC;IACF,OAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7F,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE;KAChB,CAAC;CACH,CAAC,CAAC;AAEU,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE;IACxB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;IACnB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAEU,QAAA,aAAa,GAAG,OAAC,CAAC,MAAM,CAAC;IACpC,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;IACjB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;CACpB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@rocapine/react-native-onboarding-ui",
3
- "version": "1.0.1",
3
+ "version": "1.1.3",
4
4
  "description": "UI components and renderers for Rocapine Onboarding Studio - Built on top of the headless SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc && cp -r src/assets dist/",
9
- "prepare": "npm run build",
10
9
  "watch": "tsc --watch",
11
10
  "patch": "npm version patch && npm run build && npm publish"
12
11
  },
@@ -14,10 +14,13 @@ The Error Boundary is a Higher Order Component (HOC) that wraps all renderers to
14
14
  All renderers are automatically wrapped with the `withErrorBoundary` HOC:
15
15
 
16
16
  ```typescript
17
- import { QuestionRenderer as QuestionRendererBase } from './Renderer';
18
- import { withErrorBoundary } from '../../ErrorBoundary';
17
+ import { QuestionRenderer as QuestionRendererBase } from "./Renderer";
18
+ import { withErrorBoundary } from "../../ErrorBoundary";
19
19
 
20
- export const QuestionRenderer = withErrorBoundary(QuestionRendererBase, 'Question');
20
+ export const QuestionRenderer = withErrorBoundary(
21
+ QuestionRendererBase,
22
+ "Question"
23
+ );
21
24
  ```
22
25
 
23
26
  When a Zod validation error occurs (e.g., missing required fields, wrong types), the error boundary will display:
@@ -32,17 +35,18 @@ If you pass an invalid payload:
32
35
 
33
36
  ```typescript
34
37
  const invalidStep = {
35
- id: 'test',
36
- type: 'Question',
38
+ id: "test",
39
+ type: "Question",
37
40
  payload: {
38
- title: 'Test',
41
+ title: "Test",
39
42
  // Missing required 'answers' field
40
43
  // Missing required 'multipleAnswer' field
41
- }
44
+ },
42
45
  } as any;
43
46
  ```
44
47
 
45
48
  The error boundary will show:
49
+
46
50
  ```
47
51
  ⚠️ Invalid Step Payload
48
52
  Step Type: Question
@@ -59,11 +63,11 @@ Validation Errors:
59
63
  You can also use the ErrorBoundary component directly:
60
64
 
61
65
  ```typescript
62
- import { ErrorBoundary } from '@rocapine/react-native-onboarding-studio';
66
+ import { ErrorBoundary } from "@rocapine/react-native-onboarding";
63
67
 
64
68
  <ErrorBoundary stepType="MyCustomComponent">
65
69
  <MyCustomComponent />
66
- </ErrorBoundary>
70
+ </ErrorBoundary>;
67
71
  ```
68
72
 
69
73
  ## Testing
@@ -14,15 +14,13 @@ type ContentProps = {
14
14
  const MediaContentRendererBase = ({ step, onContinue, theme = defaultTheme }: ContentProps) => {
15
15
  // Validate the schema
16
16
  const validatedData = MediaContentStepTypeSchema.parse(step);
17
- const { mediaSource, title, description } = validatedData.payload;
17
+ const { mediaSource, title, description, layoutStyle = "default" } = validatedData.payload;
18
18
 
19
19
  const renderMedia = () => {
20
20
  if (mediaSource.type === "image") {
21
- // Check if it's a local path or URL
22
21
  if ("localPathId" in mediaSource) {
23
- // TODO: Map localPathId to actual local image path
24
22
  return (
25
- <View style={[styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
23
+ <View style={[styles.mediaContainer, styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
26
24
  <Text style={[getTextStyle(theme, "body"), styles.placeholderText, { color: theme.colors.text.disable }]}>
27
25
  Image: {mediaSource.localPathId}
28
26
  </Text>
@@ -30,36 +28,92 @@ const MediaContentRendererBase = ({ step, onContinue, theme = defaultTheme }: Co
30
28
  );
31
29
  } else if ("url" in mediaSource) {
32
30
  return (
33
- <Image
34
- source={{ uri: mediaSource.url }}
35
- style={styles.mediaImage}
36
- resizeMode="cover"
37
- />
31
+ <View style={styles.mediaContainer}>
32
+ <Image source={{ uri: mediaSource.url }} style={styles.mediaImage} resizeMode="cover" />
33
+ </View>
38
34
  );
39
35
  }
40
36
  } else if (mediaSource.type === "lottie") {
41
- // TODO: Implement Lottie animation support
42
37
  return (
43
- <View style={[styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
38
+ <View style={[styles.mediaContainer, styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
44
39
  <Text style={[getTextStyle(theme, "body"), styles.placeholderText, { color: theme.colors.text.disable }]}>Lottie Animation</Text>
45
40
  </View>
46
41
  );
47
42
  } else if (mediaSource.type === "rive") {
48
- // Rive animation placeholder
49
43
  return (
50
- <View style={[styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
44
+ <View style={[styles.mediaContainer, styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
51
45
  <Text style={[getTextStyle(theme, "body"), styles.placeholderText, { color: theme.colors.text.disable }]}>Rive Animation</Text>
52
46
  </View>
53
47
  );
54
48
  }
55
49
 
56
50
  return (
57
- <View style={[styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
51
+ <View style={[styles.mediaContainer, styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
58
52
  <Text style={[getTextStyle(theme, "body"), styles.placeholderText, { color: theme.colors.text.disable }]}>Media</Text>
59
53
  </View>
60
54
  );
61
55
  };
62
56
 
57
+ const renderTextBlock = () => (
58
+ <>
59
+ <Text style={[getTextStyle(theme, "heading1"), styles.title, { color: theme.colors.text.primary }]}>{title}</Text>
60
+ {description && <Text style={[getTextStyle(theme, "heading3"), styles.subtitle, { color: theme.colors.text.secondary }]}>{description}</Text>}
61
+ </>
62
+ );
63
+
64
+ const renderContent = () => {
65
+ switch (layoutStyle) {
66
+ case "media_bottom":
67
+ return (
68
+ <ScrollView
69
+ contentContainerStyle={[styles.scrollContent, { paddingTop: 0 }]}
70
+ showsVerticalScrollIndicator={false}
71
+ alwaysBounceVertical={false}
72
+ >
73
+ <View style={[styles.container, styles.containerSpaceBetween]}>
74
+ <View style={styles.textBlock}>{renderTextBlock()}</View>
75
+ <View style={styles.flexSpacer} />
76
+ {renderMedia()}
77
+ </View>
78
+ </ScrollView>
79
+ );
80
+
81
+ case "media_top":
82
+ return (
83
+ <ScrollView
84
+ contentContainerStyle={styles.scrollContent}
85
+ showsVerticalScrollIndicator={false}
86
+ alwaysBounceVertical={false}
87
+ >
88
+ <View style={styles.container}>
89
+ {renderMedia()}
90
+ {renderTextBlock()}
91
+ </View>
92
+ </ScrollView>
93
+ );
94
+
95
+ case "default":
96
+ default:
97
+ return (
98
+ <ScrollView
99
+ contentContainerStyle={styles.scrollContent}
100
+ showsVerticalScrollIndicator={false}
101
+ alwaysBounceVertical={false}
102
+ >
103
+ <View style={[styles.container, styles.containerCenter]}>
104
+ <Text style={[getTextStyle(theme, "heading1"), styles.title, { color: theme.colors.text.primary }]}>{title}</Text>
105
+ {renderMedia()}
106
+ {description && (
107
+ <Text style={[getTextStyle(theme, "heading3"), styles.subtitle, { color: theme.colors.text.secondary }]}>
108
+ {description}
109
+ </Text>
110
+ )}
111
+ </View>
112
+ </ScrollView>
113
+ );
114
+ }
115
+ };
116
+
63
117
  return (
64
118
  <OnboardingTemplate
65
119
  step={step}
@@ -67,22 +121,7 @@ const MediaContentRendererBase = ({ step, onContinue, theme = defaultTheme }: Co
67
121
  theme={theme}
68
122
  button={{ text: validatedData.continueButtonLabel }}
69
123
  >
70
- <ScrollView
71
- contentContainerStyle={styles.scrollContent}
72
- showsVerticalScrollIndicator={false}
73
- alwaysBounceVertical={false}
74
- >
75
- <View style={styles.container}>
76
- {/* Title */}
77
- <Text style={[getTextStyle(theme, "heading1"), styles.title, { color: theme.colors.text.primary }]}>{title}</Text>
78
-
79
- {/* Media Content */}
80
- <View style={styles.mediaContainer}>{renderMedia()}</View>
81
-
82
- {/* Description/Subtitle */}
83
- {description && <Text style={[getTextStyle(theme, "heading3"), styles.subtitle, { color: theme.colors.text.secondary }]}>{description}</Text>}
84
- </View>
85
- </ScrollView>
124
+ {renderContent()}
86
125
  </OnboardingTemplate>
87
126
  );
88
127
  };
@@ -99,13 +138,28 @@ const styles = StyleSheet.create({
99
138
  gap: 24,
100
139
  alignItems: "center",
101
140
  },
141
+ containerCenter: {
142
+ justifyContent: "center",
143
+ },
144
+ containerSpaceBetween: {
145
+ justifyContent: "flex-start",
146
+ paddingTop: 32,
147
+ },
148
+ flexSpacer: {
149
+ flex: 0.4,
150
+ },
151
+ textBlock: {
152
+ gap: 8,
153
+ alignItems: "center",
154
+ width: "100%",
155
+ },
102
156
  title: {
103
157
  textAlign: "center",
104
158
  letterSpacing: -0.76,
105
159
  },
106
160
  mediaContainer: {
107
161
  width: "100%",
108
- height: 400,
162
+ aspectRatio: 1,
109
163
  borderRadius: 32,
110
164
  overflow: "hidden",
111
165
  },
@@ -5,11 +5,16 @@ import {
5
5
  SocialProofSchema,
6
6
  } from "../types";
7
7
 
8
+ export const MediaContentLayoutStyleSchema = z
9
+ .enum(["default", "media_top", "media_bottom"])
10
+ .default("default");
11
+
8
12
  export const MediaContentStepPayloadSchema = z.object({
9
13
  mediaSource: MediaSourceSchema,
10
14
  title: z.string(),
11
15
  description: z.string().nullish(),
12
16
  socialProof: SocialProofSchema.nullish(),
17
+ layoutStyle: MediaContentLayoutStyleSchema.optional(),
13
18
  });
14
19
 
15
20
  export const MediaContentStepTypeSchema = z.object({
@@ -4,11 +4,11 @@ export const CustomPayloadSchema = z.record(z.string(), z.any()).nullish();
4
4
 
5
5
  export const MediaSourceSchema = z.union([
6
6
  z.object({
7
- type: z.literal("image").or(z.literal("lottie")).or(z.literal("rive")),
7
+ type: z.literal("video").or(z.literal("image")).or(z.literal("lottie")).or(z.literal("rive")),
8
8
  localPathId: z.string(),
9
9
  }),
10
10
  z.object({
11
- type: z.literal("image").or(z.literal("lottie")).or(z.literal("rive")),
11
+ type: z.literal("video").or(z.literal("image")).or(z.literal("lottie")).or(z.literal("rive")),
12
12
  url: z.string(),
13
13
  }),
14
14
  ]);