@rocapine/react-native-onboarding 1.10.0 → 1.12.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 (124) hide show
  1. package/dist/evaluateCondition.d.ts +6 -0
  2. package/dist/evaluateCondition.d.ts.map +1 -0
  3. package/dist/evaluateCondition.js +48 -0
  4. package/dist/evaluateCondition.js.map +1 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +12 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/infra/provider/OnboardingProvider.d.ts +2 -0
  10. package/dist/infra/provider/OnboardingProvider.d.ts.map +1 -1
  11. package/dist/infra/provider/OnboardingProvider.js +8 -0
  12. package/dist/infra/provider/OnboardingProvider.js.map +1 -1
  13. package/dist/onboarding-example.d.ts +109 -15
  14. package/dist/onboarding-example.d.ts.map +1 -1
  15. package/dist/onboarding-example.js +44 -1
  16. package/dist/onboarding-example.js.map +1 -1
  17. package/dist/resolveNextStepNumber.d.ts +11 -0
  18. package/dist/resolveNextStepNumber.d.ts.map +1 -0
  19. package/dist/resolveNextStepNumber.js +39 -0
  20. package/dist/resolveNextStepNumber.js.map +1 -0
  21. package/dist/steps/Carousel/types.d.ts +29 -8
  22. package/dist/steps/Carousel/types.d.ts.map +1 -1
  23. package/dist/steps/Carousel/types.js +1 -8
  24. package/dist/steps/Carousel/types.js.map +1 -1
  25. package/dist/steps/Commitment/types.d.ts +29 -8
  26. package/dist/steps/Commitment/types.d.ts.map +1 -1
  27. package/dist/steps/Commitment/types.js +1 -8
  28. package/dist/steps/Commitment/types.js.map +1 -1
  29. package/dist/steps/ComposableScreen/elements/BaseBoxProps.d.ts +28 -6
  30. package/dist/steps/ComposableScreen/elements/BaseBoxProps.d.ts.map +1 -1
  31. package/dist/steps/ComposableScreen/elements/BaseBoxProps.js +11 -2
  32. package/dist/steps/ComposableScreen/elements/BaseBoxProps.js.map +1 -1
  33. package/dist/steps/ComposableScreen/elements/ButtonElement.d.ts +22 -10
  34. package/dist/steps/ComposableScreen/elements/ButtonElement.d.ts.map +1 -1
  35. package/dist/steps/ComposableScreen/elements/ButtonElement.js +0 -1
  36. package/dist/steps/ComposableScreen/elements/ButtonElement.js.map +1 -1
  37. package/dist/steps/ComposableScreen/elements/CarouselElement.d.ts +67 -0
  38. package/dist/steps/ComposableScreen/elements/CarouselElement.d.ts.map +1 -0
  39. package/dist/steps/ComposableScreen/elements/CarouselElement.js +19 -0
  40. package/dist/steps/ComposableScreen/elements/CarouselElement.js.map +1 -0
  41. package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.d.ts +17 -4
  42. package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.d.ts.map +1 -1
  43. package/dist/steps/ComposableScreen/elements/DatePickerElement.d.ts +17 -4
  44. package/dist/steps/ComposableScreen/elements/DatePickerElement.d.ts.map +1 -1
  45. package/dist/steps/ComposableScreen/elements/IconElement.d.ts +16 -4
  46. package/dist/steps/ComposableScreen/elements/IconElement.d.ts.map +1 -1
  47. package/dist/steps/ComposableScreen/elements/ImageElement.d.ts +17 -4
  48. package/dist/steps/ComposableScreen/elements/ImageElement.d.ts.map +1 -1
  49. package/dist/steps/ComposableScreen/elements/InputElement.d.ts +24 -6
  50. package/dist/steps/ComposableScreen/elements/InputElement.d.ts.map +1 -1
  51. package/dist/steps/ComposableScreen/elements/InputElement.js +3 -0
  52. package/dist/steps/ComposableScreen/elements/InputElement.js.map +1 -1
  53. package/dist/steps/ComposableScreen/elements/LottieElement.d.ts +17 -4
  54. package/dist/steps/ComposableScreen/elements/LottieElement.d.ts.map +1 -1
  55. package/dist/steps/ComposableScreen/elements/RadioGroupElement.d.ts +17 -4
  56. package/dist/steps/ComposableScreen/elements/RadioGroupElement.d.ts.map +1 -1
  57. package/dist/steps/ComposableScreen/elements/RiveElement.d.ts +19 -6
  58. package/dist/steps/ComposableScreen/elements/RiveElement.d.ts.map +1 -1
  59. package/dist/steps/ComposableScreen/elements/RiveElement.js +1 -1
  60. package/dist/steps/ComposableScreen/elements/StackElement.d.ts +31 -50
  61. package/dist/steps/ComposableScreen/elements/StackElement.d.ts.map +1 -1
  62. package/dist/steps/ComposableScreen/elements/StackElement.js +2 -22
  63. package/dist/steps/ComposableScreen/elements/StackElement.js.map +1 -1
  64. package/dist/steps/ComposableScreen/elements/TextElement.d.ts +35 -23
  65. package/dist/steps/ComposableScreen/elements/TextElement.d.ts.map +1 -1
  66. package/dist/steps/ComposableScreen/elements/TextElement.js +2 -12
  67. package/dist/steps/ComposableScreen/elements/TextElement.js.map +1 -1
  68. package/dist/steps/ComposableScreen/elements/VideoElement.d.ts +17 -4
  69. package/dist/steps/ComposableScreen/elements/VideoElement.d.ts.map +1 -1
  70. package/dist/steps/ComposableScreen/types.d.ts +37 -4
  71. package/dist/steps/ComposableScreen/types.d.ts.map +1 -1
  72. package/dist/steps/ComposableScreen/types.js +9 -7
  73. package/dist/steps/ComposableScreen/types.js.map +1 -1
  74. package/dist/steps/Loader/types.d.ts +29 -8
  75. package/dist/steps/Loader/types.d.ts.map +1 -1
  76. package/dist/steps/Loader/types.js +1 -8
  77. package/dist/steps/Loader/types.js.map +1 -1
  78. package/dist/steps/MediaContent/types.d.ts +29 -8
  79. package/dist/steps/MediaContent/types.d.ts.map +1 -1
  80. package/dist/steps/MediaContent/types.js +1 -8
  81. package/dist/steps/MediaContent/types.js.map +1 -1
  82. package/dist/steps/Picker/types.d.ts +30 -8
  83. package/dist/steps/Picker/types.d.ts.map +1 -1
  84. package/dist/steps/Picker/types.js +2 -8
  85. package/dist/steps/Picker/types.js.map +1 -1
  86. package/dist/steps/Question/types.d.ts +30 -8
  87. package/dist/steps/Question/types.d.ts.map +1 -1
  88. package/dist/steps/Question/types.js +2 -8
  89. package/dist/steps/Question/types.js.map +1 -1
  90. package/dist/steps/Ratings/types.d.ts +29 -8
  91. package/dist/steps/Ratings/types.d.ts.map +1 -1
  92. package/dist/steps/Ratings/types.js +1 -8
  93. package/dist/steps/Ratings/types.js.map +1 -1
  94. package/dist/steps/common.types.d.ts +109 -0
  95. package/dist/steps/common.types.d.ts.map +1 -1
  96. package/dist/steps/common.types.js +52 -1
  97. package/dist/steps/common.types.js.map +1 -1
  98. package/dist/types.d.ts +2 -0
  99. package/dist/types.d.ts.map +1 -1
  100. package/package.json +5 -2
  101. package/src/__tests__/evaluateCondition.test.ts +167 -0
  102. package/src/__tests__/resolveNextStepNumber.test.ts +309 -0
  103. package/src/evaluateCondition.ts +50 -0
  104. package/src/index.ts +19 -0
  105. package/src/infra/provider/OnboardingProvider.tsx +11 -1
  106. package/src/onboarding-example.ts +44 -1
  107. package/src/resolveNextStepNumber.ts +41 -0
  108. package/src/steps/Carousel/types.ts +2 -9
  109. package/src/steps/Commitment/types.ts +2 -9
  110. package/src/steps/ComposableScreen/elements/BaseBoxProps.ts +22 -4
  111. package/src/steps/ComposableScreen/elements/ButtonElement.ts +0 -2
  112. package/src/steps/ComposableScreen/elements/CarouselElement.ts +30 -0
  113. package/src/steps/ComposableScreen/elements/InputElement.ts +6 -0
  114. package/src/steps/ComposableScreen/elements/RiveElement.ts +2 -2
  115. package/src/steps/ComposableScreen/elements/StackElement.ts +3 -44
  116. package/src/steps/ComposableScreen/elements/TextElement.ts +3 -24
  117. package/src/steps/ComposableScreen/types.ts +18 -8
  118. package/src/steps/Loader/types.ts +2 -9
  119. package/src/steps/MediaContent/types.ts +2 -14
  120. package/src/steps/Picker/types.ts +3 -9
  121. package/src/steps/Question/types.ts +3 -9
  122. package/src/steps/Ratings/types.ts +2 -9
  123. package/src/steps/common.types.ts +72 -0
  124. package/src/types.ts +3 -0
@@ -20,4 +20,113 @@ export declare const ButtonSectionSchema: z.ZodObject<{
20
20
  label: z.ZodOptional<z.ZodString>;
21
21
  icon: z.ZodOptional<z.ZodNullable<z.ZodString>>;
22
22
  }, z.core.$strip>;
23
+ export declare const ConditionOperatorSchema: z.ZodEnum<{
24
+ eq: "eq";
25
+ neq: "neq";
26
+ gt: "gt";
27
+ lt: "lt";
28
+ gte: "gte";
29
+ lte: "lte";
30
+ contains: "contains";
31
+ in: "in";
32
+ not_in: "not_in";
33
+ }>;
34
+ export type ConditionOperator = z.infer<typeof ConditionOperatorSchema>;
35
+ export declare const ConditionValueSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
36
+ export type ConditionValue = z.infer<typeof ConditionValueSchema>;
37
+ export declare const LeafConditionSchema: z.ZodObject<{
38
+ variable: z.ZodString;
39
+ operator: z.ZodEnum<{
40
+ eq: "eq";
41
+ neq: "neq";
42
+ gt: "gt";
43
+ lt: "lt";
44
+ gte: "gte";
45
+ lte: "lte";
46
+ contains: "contains";
47
+ in: "in";
48
+ not_in: "not_in";
49
+ }>;
50
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
51
+ }, z.core.$strip>;
52
+ export type LeafCondition = z.infer<typeof LeafConditionSchema>;
53
+ export type ConditionGroup = {
54
+ logic: "and" | "or";
55
+ conditions: Array<LeafCondition | ConditionGroup>;
56
+ };
57
+ export declare const ConditionGroupSchema: z.ZodType<ConditionGroup>;
58
+ export declare const BranchSchema: z.ZodObject<{
59
+ condition: z.ZodDefault<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
60
+ variable: z.ZodString;
61
+ operator: z.ZodEnum<{
62
+ eq: "eq";
63
+ neq: "neq";
64
+ gt: "gt";
65
+ lt: "lt";
66
+ gte: "gte";
67
+ lte: "lte";
68
+ contains: "contains";
69
+ in: "in";
70
+ not_in: "not_in";
71
+ }>;
72
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
73
+ }, z.core.$strip>, z.ZodType<ConditionGroup, unknown, z.core.$ZodTypeInternals<ConditionGroup, unknown>>]>>>;
74
+ targetStepId: z.ZodString;
75
+ }, z.core.$strip>;
76
+ export type Branch = z.infer<typeof BranchSchema>;
77
+ export declare const NextStepSchema: z.ZodDefault<z.ZodNullable<z.ZodObject<{
78
+ defaultTargetStepId: z.ZodString;
79
+ branches: z.ZodDefault<z.ZodArray<z.ZodObject<{
80
+ condition: z.ZodDefault<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
81
+ variable: z.ZodString;
82
+ operator: z.ZodEnum<{
83
+ eq: "eq";
84
+ neq: "neq";
85
+ gt: "gt";
86
+ lt: "lt";
87
+ gte: "gte";
88
+ lte: "lte";
89
+ contains: "contains";
90
+ in: "in";
91
+ not_in: "not_in";
92
+ }>;
93
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
94
+ }, z.core.$strip>, z.ZodType<ConditionGroup, unknown, z.core.$ZodTypeInternals<ConditionGroup, unknown>>]>>>;
95
+ targetStepId: z.ZodString;
96
+ }, z.core.$strip>>>;
97
+ }, z.core.$strip>>>;
98
+ export type NextStep = z.infer<typeof NextStepSchema>;
99
+ export declare const BaseStepTypeSchema: z.ZodObject<{
100
+ id: z.ZodString;
101
+ name: z.ZodString;
102
+ displayProgressHeader: z.ZodBoolean;
103
+ customPayload: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodAny>>>;
104
+ continueButtonLabel: z.ZodDefault<z.ZodOptional<z.ZodString>>;
105
+ buttonSection: z.ZodOptional<z.ZodObject<{
106
+ label: z.ZodOptional<z.ZodString>;
107
+ icon: z.ZodOptional<z.ZodNullable<z.ZodString>>;
108
+ }, z.core.$strip>>;
109
+ figmaUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
110
+ nextStep: z.ZodDefault<z.ZodNullable<z.ZodObject<{
111
+ defaultTargetStepId: z.ZodString;
112
+ branches: z.ZodDefault<z.ZodArray<z.ZodObject<{
113
+ condition: z.ZodDefault<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
114
+ variable: z.ZodString;
115
+ operator: z.ZodEnum<{
116
+ eq: "eq";
117
+ neq: "neq";
118
+ gt: "gt";
119
+ lt: "lt";
120
+ gte: "gte";
121
+ lte: "lte";
122
+ contains: "contains";
123
+ in: "in";
124
+ not_in: "not_in";
125
+ }>;
126
+ value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
127
+ }, z.core.$strip>, z.ZodType<ConditionGroup, unknown, z.core.$ZodTypeInternals<ConditionGroup, unknown>>]>>>;
128
+ targetStepId: z.ZodString;
129
+ }, z.core.$strip>>>;
130
+ }, z.core.$strip>>>;
131
+ }, z.core.$strip>;
23
132
  //# sourceMappingURL=common.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"common.types.d.ts","sourceRoot":"","sources":["../../src/steps/common.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,mBAAmB,kEAA0C,CAAC;AAE3E,eAAO,MAAM,iBAAiB;;;;;;mBAS5B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;iBAI5B,CAAC;AAEH,eAAO,MAAM,aAAa;;;iBAGxB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;iBAG9B,CAAC"}
1
+ {"version":3,"file":"common.types.d.ts","sourceRoot":"","sources":["../../src/steps/common.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,mBAAmB,kEAA0C,CAAC;AAE3E,eAAO,MAAM,iBAAiB;;;;;;mBAS5B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;iBAI5B,CAAC;AAEH,eAAO,MAAM,aAAa;;;iBAGxB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;iBAG9B,CAAC;AAIH,eAAO,MAAM,uBAAuB;;;;;;;;;;EAUlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,oBAAoB,0IAK/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;iBAI9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,KAAK,CAAC,aAAa,GAAG,cAAc,CAAC,CAAC;CACnD,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAO1D,CAAC;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;iBAGvB,CAAC;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;mBAMX,CAAC;AACjB,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAItD,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAS7B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ButtonSectionSchema = exports.InfoBoxSchema = exports.SocialProofSchema = exports.MediaSourceSchema = exports.CustomPayloadSchema = void 0;
3
+ exports.BaseStepTypeSchema = exports.NextStepSchema = exports.BranchSchema = exports.ConditionGroupSchema = exports.LeafConditionSchema = exports.ConditionValueSchema = exports.ConditionOperatorSchema = exports.ButtonSectionSchema = exports.InfoBoxSchema = exports.SocialProofSchema = exports.MediaSourceSchema = exports.CustomPayloadSchema = void 0;
4
4
  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([
@@ -26,4 +26,55 @@ exports.ButtonSectionSchema = zod_1.z.object({
26
26
  label: zod_1.z.string().optional(),
27
27
  icon: zod_1.z.string().nullish(),
28
28
  });
29
+ // ── Branching / nextStep schemas ─────────────────────────────────────────────
30
+ exports.ConditionOperatorSchema = zod_1.z.enum([
31
+ "eq",
32
+ "neq",
33
+ "gt",
34
+ "lt",
35
+ "gte",
36
+ "lte",
37
+ "contains",
38
+ "in",
39
+ "not_in",
40
+ ]);
41
+ exports.ConditionValueSchema = zod_1.z.union([
42
+ zod_1.z.string(),
43
+ zod_1.z.number(),
44
+ zod_1.z.boolean(),
45
+ zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean()])),
46
+ ]);
47
+ exports.LeafConditionSchema = zod_1.z.object({
48
+ variable: zod_1.z.string().min(1),
49
+ operator: exports.ConditionOperatorSchema,
50
+ value: exports.ConditionValueSchema,
51
+ });
52
+ exports.ConditionGroupSchema = zod_1.z.lazy(() => zod_1.z.object({
53
+ logic: zod_1.z.enum(["and", "or"]),
54
+ conditions: zod_1.z
55
+ .array(zod_1.z.union([exports.LeafConditionSchema, exports.ConditionGroupSchema]))
56
+ .min(1),
57
+ }));
58
+ exports.BranchSchema = zod_1.z.object({
59
+ condition: zod_1.z.union([exports.LeafConditionSchema, exports.ConditionGroupSchema]).nullable().default(null),
60
+ targetStepId: zod_1.z.string().min(1),
61
+ });
62
+ exports.NextStepSchema = zod_1.z
63
+ .object({
64
+ defaultTargetStepId: zod_1.z.string().min(1),
65
+ branches: zod_1.z.array(exports.BranchSchema).default([]),
66
+ })
67
+ .nullable()
68
+ .default(null);
69
+ // ── Base step schema ──────────────────────────────────────────────────────────
70
+ exports.BaseStepTypeSchema = zod_1.z.object({
71
+ id: zod_1.z.string(),
72
+ name: zod_1.z.string(),
73
+ displayProgressHeader: zod_1.z.boolean(),
74
+ customPayload: exports.CustomPayloadSchema,
75
+ continueButtonLabel: zod_1.z.string().optional().default("Continue"),
76
+ buttonSection: exports.ButtonSectionSchema.optional(),
77
+ figmaUrl: zod_1.z.string().nullish(),
78
+ nextStep: exports.NextStepSchema,
79
+ });
29
80
  //# sourceMappingURL=common.types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"common.types.js","sourceRoot":"","sources":["../../src/steps/common.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;AAEU,QAAA,mBAAmB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC1C,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;CAC3B,CAAC,CAAC"}
1
+ {"version":3,"file":"common.types.js","sourceRoot":"","sources":["../../src/steps/common.types.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { NextStep } from "./steps/common.types";
1
2
  /**
2
3
  * Base step type that all onboarding steps must conform to.
3
4
  * This is the minimal interface required by the headless SDK.
@@ -11,6 +12,7 @@ export type BaseStepType = {
11
12
  customPayload?: any;
12
13
  continueButtonLabel?: string;
13
14
  figmaUrl?: string | null;
15
+ nextStep?: NextStep;
14
16
  };
15
17
  export type OnboardingStudioClientOptions<StepType extends BaseStepType = BaseStepType> = {
16
18
  appVersion?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,6BAA6B,CACvC,QAAQ,SAAS,YAAY,GAAG,YAAY,IAC1C;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,UAAU,CAAC,QAAQ,SAAS,YAAY,GAAG,YAAY;IACtE,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,aAAa,EAAE,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,aAAa,CAAC,EAAE,GAAG,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,6BAA6B,CACvC,QAAQ,SAAS,YAAY,GAAG,YAAY,IAC1C;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,UAAU,CAAC,QAAQ,SAAS,YAAY,GAAG,YAAY;IACtE,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,aAAa,EAAE,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocapine/react-native-onboarding",
3
- "version": "1.10.0",
3
+ "version": "1.12.0",
4
4
  "description": "Headless React Native SDK for Rocapine Onboarding Studio - Data fetching, state management, and hooks",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,6 +8,8 @@
8
8
  "build": "tsc",
9
9
  "watch": "tsc --watch",
10
10
  "type:check": "tsc --noEmit",
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
11
13
  "patch": "npm version patch && npm run build && npm publish"
12
14
  },
13
15
  "keywords": [
@@ -29,7 +31,8 @@
29
31
  "@types/react": "^19.0.0",
30
32
  "react": "19.2.0",
31
33
  "react-native": "0.83.4",
32
- "typescript": "^5.0.0"
34
+ "typescript": "^5.0.0",
35
+ "vitest": "^4.1.5"
33
36
  },
34
37
  "peerDependencies": {
35
38
  "react": "*",
@@ -0,0 +1,167 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { evaluateLeaf, evaluateCondition } from "../evaluateCondition";
3
+ import type { Condition } from "../evaluateCondition";
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // evaluateLeaf — operator coverage
7
+ // ---------------------------------------------------------------------------
8
+
9
+ describe("evaluateLeaf — eq", () => {
10
+ it("matches equal strings", () => expect(evaluateLeaf({ variable: "x", operator: "eq", value: "male" }, { x: "male" })).toBe(true));
11
+ it("rejects unequal strings", () => expect(evaluateLeaf({ variable: "x", operator: "eq", value: "male" }, { x: "female" })).toBe(false));
12
+ it("coerces number to string for comparison", () => expect(evaluateLeaf({ variable: "x", operator: "eq", value: "42" }, { x: 42 })).toBe(true));
13
+ it("undefined variable yields false", () => expect(evaluateLeaf({ variable: "x", operator: "eq", value: "foo" }, {})).toBe(false));
14
+ });
15
+
16
+ describe("evaluateLeaf — neq", () => {
17
+ it("passes when values differ", () => expect(evaluateLeaf({ variable: "x", operator: "neq", value: "male" }, { x: "female" })).toBe(true));
18
+ it("fails when values equal", () => expect(evaluateLeaf({ variable: "x", operator: "neq", value: "male" }, { x: "male" })).toBe(false));
19
+ });
20
+
21
+ describe("evaluateLeaf — gt", () => {
22
+ it("passes when variable greater", () => expect(evaluateLeaf({ variable: "age", operator: "gt", value: 18 }, { age: 25 })).toBe(true));
23
+ it("fails when equal", () => expect(evaluateLeaf({ variable: "age", operator: "gt", value: 18 }, { age: 18 })).toBe(false));
24
+ it("fails when less", () => expect(evaluateLeaf({ variable: "age", operator: "gt", value: 18 }, { age: 10 })).toBe(false));
25
+ it("coerces string variable", () => expect(evaluateLeaf({ variable: "age", operator: "gt", value: 18 }, { age: "25" })).toBe(true));
26
+ it("coerces string value", () => expect(evaluateLeaf({ variable: "age", operator: "gt", value: "18" }, { age: 25 })).toBe(true));
27
+ });
28
+
29
+ describe("evaluateLeaf — lt", () => {
30
+ it("passes when variable less", () => expect(evaluateLeaf({ variable: "age", operator: "lt", value: 18 }, { age: 10 })).toBe(true));
31
+ it("fails when equal", () => expect(evaluateLeaf({ variable: "age", operator: "lt", value: 18 }, { age: 18 })).toBe(false));
32
+ it("fails when greater", () => expect(evaluateLeaf({ variable: "age", operator: "lt", value: 18 }, { age: 25 })).toBe(false));
33
+ });
34
+
35
+ describe("evaluateLeaf — gte", () => {
36
+ it("passes when greater", () => expect(evaluateLeaf({ variable: "x", operator: "gte", value: 5 }, { x: 6 })).toBe(true));
37
+ it("passes when equal", () => expect(evaluateLeaf({ variable: "x", operator: "gte", value: 5 }, { x: 5 })).toBe(true));
38
+ it("fails when less", () => expect(evaluateLeaf({ variable: "x", operator: "gte", value: 5 }, { x: 4 })).toBe(false));
39
+ });
40
+
41
+ describe("evaluateLeaf — lte", () => {
42
+ it("passes when less", () => expect(evaluateLeaf({ variable: "x", operator: "lte", value: 5 }, { x: 4 })).toBe(true));
43
+ it("passes when equal", () => expect(evaluateLeaf({ variable: "x", operator: "lte", value: 5 }, { x: 5 })).toBe(true));
44
+ it("fails when greater", () => expect(evaluateLeaf({ variable: "x", operator: "lte", value: 5 }, { x: 6 })).toBe(false));
45
+ });
46
+
47
+ describe("evaluateLeaf — contains (string)", () => {
48
+ it("passes when substring found", () => expect(evaluateLeaf({ variable: "bio", operator: "contains", value: "run" }, { bio: "I love running" })).toBe(true));
49
+ it("fails when substring absent", () => expect(evaluateLeaf({ variable: "bio", operator: "contains", value: "swim" }, { bio: "I love running" })).toBe(false));
50
+ it("coerces number variable to string", () => expect(evaluateLeaf({ variable: "code", operator: "contains", value: "4" }, { code: 42 })).toBe(true));
51
+ });
52
+
53
+ describe("evaluateLeaf — contains (array)", () => {
54
+ it("passes when element in array", () => expect(evaluateLeaf({ variable: "tags", operator: "contains", value: "sport" }, { tags: ["health", "sport"] })).toBe(true));
55
+ it("fails when element absent", () => expect(evaluateLeaf({ variable: "tags", operator: "contains", value: "music" }, { tags: ["health", "sport"] })).toBe(false));
56
+ });
57
+
58
+ describe("evaluateLeaf — in", () => {
59
+ it("passes when variable is in list", () => expect(evaluateLeaf({ variable: "gender", operator: "in", value: ["male", "female"] }, { gender: "male" })).toBe(true));
60
+ it("fails when variable not in list", () => expect(evaluateLeaf({ variable: "gender", operator: "in", value: ["male", "female"] }, { gender: "other" })).toBe(false));
61
+ it("returns false when value is not array", () => expect(evaluateLeaf({ variable: "x", operator: "in", value: "male" as any }, { x: "male" })).toBe(false));
62
+ it("empty list always false", () => expect(evaluateLeaf({ variable: "x", operator: "in", value: [] }, { x: "male" })).toBe(false));
63
+ it("coerces numeric raw to string before comparison", () => expect(evaluateLeaf({ variable: "age", operator: "in", value: ["18", "25"] }, { age: 18 })).toBe(true));
64
+ it("numeric raw not in string list returns false", () => expect(evaluateLeaf({ variable: "age", operator: "in", value: ["30", "40"] }, { age: 18 })).toBe(false));
65
+ });
66
+
67
+ describe("evaluateLeaf — not_in", () => {
68
+ it("passes when variable not in list", () => expect(evaluateLeaf({ variable: "gender", operator: "not_in", value: ["male", "female"] }, { gender: "other" })).toBe(true));
69
+ it("fails when variable is in list", () => expect(evaluateLeaf({ variable: "gender", operator: "not_in", value: ["male", "female"] }, { gender: "male" })).toBe(false));
70
+ it("returns true when value is not array (safe default)", () => expect(evaluateLeaf({ variable: "x", operator: "not_in", value: "male" as any }, { x: "male" })).toBe(true));
71
+ it("coerces numeric raw to string before comparison", () => expect(evaluateLeaf({ variable: "age", operator: "not_in", value: ["18", "25"] }, { age: 30 })).toBe(true));
72
+ it("numeric raw in string list returns false", () => expect(evaluateLeaf({ variable: "age", operator: "not_in", value: ["18", "25"] }, { age: 18 })).toBe(false));
73
+ });
74
+
75
+ describe("evaluateLeaf — unknown operator", () => {
76
+ it("returns false for unknown operator", () => expect(evaluateLeaf({ variable: "x", operator: "xor" as any, value: "y" }, { x: "y" })).toBe(false));
77
+ });
78
+
79
+ // ---------------------------------------------------------------------------
80
+ // evaluateCondition — logic groups
81
+ // ---------------------------------------------------------------------------
82
+
83
+ describe("evaluateCondition — AND group", () => {
84
+ const and: Condition = {
85
+ logic: "and",
86
+ conditions: [
87
+ { variable: "age", operator: "gt", value: 18 },
88
+ { variable: "gender", operator: "eq", value: "male" },
89
+ ],
90
+ };
91
+
92
+ it("passes when all conditions true", () => expect(evaluateCondition(and, { age: 25, gender: "male" })).toBe(true));
93
+ it("fails when one condition false", () => expect(evaluateCondition(and, { age: 25, gender: "female" })).toBe(false));
94
+ it("fails when all conditions false", () => expect(evaluateCondition(and, { age: 10, gender: "female" })).toBe(false));
95
+ });
96
+
97
+ describe("evaluateCondition — OR group", () => {
98
+ const or: Condition = {
99
+ logic: "or",
100
+ conditions: [
101
+ { variable: "age", operator: "lt", value: 18 },
102
+ { variable: "gender", operator: "eq", value: "female" },
103
+ ],
104
+ };
105
+
106
+ it("passes when first condition true", () => expect(evaluateCondition(or, { age: 10, gender: "male" })).toBe(true));
107
+ it("passes when second condition true", () => expect(evaluateCondition(or, { age: 25, gender: "female" })).toBe(true));
108
+ it("passes when both true", () => expect(evaluateCondition(or, { age: 10, gender: "female" })).toBe(true));
109
+ it("fails when all false", () => expect(evaluateCondition(or, { age: 25, gender: "male" })).toBe(false));
110
+ });
111
+
112
+ describe("evaluateCondition — nested groups", () => {
113
+ // (age > 18 AND gender = male) OR (vip = true)
114
+ const nested: Condition = {
115
+ logic: "or",
116
+ conditions: [
117
+ {
118
+ logic: "and",
119
+ conditions: [
120
+ { variable: "age", operator: "gt", value: 18 },
121
+ { variable: "gender", operator: "eq", value: "male" },
122
+ ],
123
+ },
124
+ { variable: "vip", operator: "eq", value: "true" },
125
+ ],
126
+ };
127
+
128
+ it("passes via inner AND branch", () => expect(evaluateCondition(nested, { age: 25, gender: "male", vip: "false" })).toBe(true));
129
+ it("passes via vip branch", () => expect(evaluateCondition(nested, { age: 10, gender: "female", vip: "true" })).toBe(true));
130
+ it("fails when neither branch matches", () => expect(evaluateCondition(nested, { age: 10, gender: "male", vip: "false" })).toBe(false));
131
+ });
132
+
133
+ describe("evaluateCondition — deeply nested (3 levels)", () => {
134
+ // ((a=1 AND b=2) OR c=3) AND d=4
135
+ const deep: Condition = {
136
+ logic: "and",
137
+ conditions: [
138
+ {
139
+ logic: "or",
140
+ conditions: [
141
+ {
142
+ logic: "and",
143
+ conditions: [
144
+ { variable: "a", operator: "eq", value: "1" },
145
+ { variable: "b", operator: "eq", value: "2" },
146
+ ],
147
+ },
148
+ { variable: "c", operator: "eq", value: "3" },
149
+ ],
150
+ },
151
+ { variable: "d", operator: "eq", value: "4" },
152
+ ],
153
+ };
154
+
155
+ it("passes via a+b path with d", () => expect(evaluateCondition(deep, { a: "1", b: "2", c: "0", d: "4" })).toBe(true));
156
+ it("passes via c path with d", () => expect(evaluateCondition(deep, { a: "0", b: "0", c: "3", d: "4" })).toBe(true));
157
+ it("fails when d missing", () => expect(evaluateCondition(deep, { a: "1", b: "2", c: "3", d: "0" })).toBe(false));
158
+ it("fails when inner OR fails and d present", () => expect(evaluateCondition(deep, { a: "0", b: "0", c: "0", d: "4" })).toBe(false));
159
+ });
160
+
161
+ describe("evaluateCondition — leaf passthrough", () => {
162
+ it("delegates to evaluateLeaf directly", () => {
163
+ const leaf: Condition = { variable: "x", operator: "eq", value: "yes" };
164
+ expect(evaluateCondition(leaf, { x: "yes" })).toBe(true);
165
+ expect(evaluateCondition(leaf, { x: "no" })).toBe(false);
166
+ });
167
+ });