@rocapine/react-native-onboarding 1.26.0 → 1.27.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 (47) hide show
  1. package/dist/evaluateCondition.d.ts.map +1 -1
  2. package/dist/evaluateCondition.js +44 -1
  3. package/dist/evaluateCondition.js.map +1 -1
  4. package/dist/index.d.ts +3 -3
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +6 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/onboarding-example.d.ts +282 -111
  9. package/dist/onboarding-example.d.ts.map +1 -1
  10. package/dist/onboarding-example.js +38 -0
  11. package/dist/onboarding-example.js.map +1 -1
  12. package/dist/steps/Carousel/types.d.ts +5 -1
  13. package/dist/steps/Carousel/types.d.ts.map +1 -1
  14. package/dist/steps/Commitment/types.d.ts +5 -1
  15. package/dist/steps/Commitment/types.d.ts.map +1 -1
  16. package/dist/steps/ComposableScreen/elements/ButtonElement.d.ts +5 -1
  17. package/dist/steps/ComposableScreen/elements/ButtonElement.d.ts.map +1 -1
  18. package/dist/steps/ComposableScreen/elements/WheelPickerElement.d.ts +124 -0
  19. package/dist/steps/ComposableScreen/elements/WheelPickerElement.d.ts.map +1 -0
  20. package/dist/steps/ComposableScreen/elements/WheelPickerElement.js +96 -0
  21. package/dist/steps/ComposableScreen/elements/WheelPickerElement.js.map +1 -0
  22. package/dist/steps/ComposableScreen/types.d.ts +14 -1
  23. package/dist/steps/ComposableScreen/types.d.ts.map +1 -1
  24. package/dist/steps/ComposableScreen/types.js +13 -1
  25. package/dist/steps/ComposableScreen/types.js.map +1 -1
  26. package/dist/steps/Loader/types.d.ts +5 -1
  27. package/dist/steps/Loader/types.d.ts.map +1 -1
  28. package/dist/steps/MediaContent/types.d.ts +5 -1
  29. package/dist/steps/MediaContent/types.d.ts.map +1 -1
  30. package/dist/steps/Picker/types.d.ts +5 -1
  31. package/dist/steps/Picker/types.d.ts.map +1 -1
  32. package/dist/steps/Question/types.d.ts +5 -1
  33. package/dist/steps/Question/types.d.ts.map +1 -1
  34. package/dist/steps/Ratings/types.d.ts +5 -1
  35. package/dist/steps/Ratings/types.d.ts.map +1 -1
  36. package/dist/steps/common.types.d.ts +30 -4
  37. package/dist/steps/common.types.d.ts.map +1 -1
  38. package/dist/steps/common.types.js +33 -3
  39. package/dist/steps/common.types.js.map +1 -1
  40. package/package.json +2 -2
  41. package/src/__tests__/evaluateCondition.test.ts +35 -0
  42. package/src/evaluateCondition.ts +41 -1
  43. package/src/index.ts +8 -0
  44. package/src/onboarding-example.ts +38 -0
  45. package/src/steps/ComposableScreen/elements/WheelPickerElement.ts +115 -0
  46. package/src/steps/ComposableScreen/types.ts +17 -0
  47. package/src/steps/common.types.ts +38 -5
@@ -51,8 +51,12 @@ export declare const MediaContentStepTypeSchema: z.ZodObject<{
51
51
  contains: "contains";
52
52
  in: "in";
53
53
  not_in: "not_in";
54
+ is_empty: "is_empty";
55
+ is_not_empty: "is_not_empty";
56
+ is_null: "is_null";
57
+ is_not_null: "is_not_null";
54
58
  }>;
55
- value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
59
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>>;
56
60
  }, z.core.$strip>, z.ZodType<import("../common.types").ConditionGroup, unknown, z.core.$ZodTypeInternals<import("../common.types").ConditionGroup, unknown>>]>>>;
57
61
  targetStepId: z.ZodString;
58
62
  }, z.core.$strip>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/steps/MediaContent/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,6BAA6B;;;;GAAsE,CAAC;AAEjH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;iBAMxC,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGrC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/steps/MediaContent/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,6BAA6B;;;;GAAsE,CAAC;AAEjH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;iBAMxC,CAAC;AAEH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGrC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
@@ -47,8 +47,12 @@ export declare const PickerStepTypeSchema: z.ZodObject<{
47
47
  contains: "contains";
48
48
  in: "in";
49
49
  not_in: "not_in";
50
+ is_empty: "is_empty";
51
+ is_not_empty: "is_not_empty";
52
+ is_null: "is_null";
53
+ is_not_null: "is_not_null";
50
54
  }>;
51
- value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
55
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>>;
52
56
  }, z.core.$strip>, z.ZodType<import("../common.types").ConditionGroup, unknown, z.core.$ZodTypeInternals<import("../common.types").ConditionGroup, unknown>>]>>>;
53
57
  targetStepId: z.ZodString;
54
58
  }, z.core.$strip>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/steps/Picker/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,cAAc;;;;;;;;EAQzB,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;iBAIlC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAI/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC;AACrC,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/steps/Picker/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,cAAc;;;;;;;;EAQzB,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;iBAIlC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAI/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC;AACrC,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC"}
@@ -46,8 +46,12 @@ export declare const QuestionStepTypeSchema: z.ZodObject<{
46
46
  contains: "contains";
47
47
  in: "in";
48
48
  not_in: "not_in";
49
+ is_empty: "is_empty";
50
+ is_not_empty: "is_not_empty";
51
+ is_null: "is_null";
52
+ is_not_null: "is_not_null";
49
53
  }>;
50
- value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
54
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>>;
51
55
  }, z.core.$strip>, z.ZodType<import("../common.types").ConditionGroup, unknown, z.core.$ZodTypeInternals<import("../common.types").ConditionGroup, unknown>>]>>>;
52
56
  targetStepId: z.ZodString;
53
57
  }, z.core.$strip>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/steps/Question/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,YAAY;;;;;iBAKvB,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;iBAMpC,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/steps/Question/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,YAAY;;;;;iBAKvB,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;iBAMpC,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
@@ -35,8 +35,12 @@ export declare const RatingsStepTypeSchema: z.ZodObject<{
35
35
  contains: "contains";
36
36
  in: "in";
37
37
  not_in: "not_in";
38
+ is_empty: "is_empty";
39
+ is_not_empty: "is_not_empty";
40
+ is_null: "is_null";
41
+ is_not_null: "is_not_null";
38
42
  }>;
39
- value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
43
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>>;
40
44
  }, z.core.$strip>, z.ZodType<import("../common.types").ConditionGroup, unknown, z.core.$ZodTypeInternals<import("../common.types").ConditionGroup, unknown>>]>>>;
41
45
  targetStepId: z.ZodString;
42
46
  }, z.core.$strip>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/steps/Ratings/types.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAGpB,eAAO,MAAM,wBAAwB;;;;;;;;;iBAKnC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/steps/Ratings/types.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,KAAK,CAAC;AAGpB,eAAO,MAAM,wBAAwB;;;;;;;;;iBAKnC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -30,8 +30,18 @@ export declare const ConditionOperatorSchema: z.ZodEnum<{
30
30
  contains: "contains";
31
31
  in: "in";
32
32
  not_in: "not_in";
33
+ is_empty: "is_empty";
34
+ is_not_empty: "is_not_empty";
35
+ is_null: "is_null";
36
+ is_not_null: "is_not_null";
33
37
  }>;
34
38
  export type ConditionOperator = z.infer<typeof ConditionOperatorSchema>;
39
+ /**
40
+ * Operators that test the variable alone and ignore `value`. A LeafCondition
41
+ * using one of these may omit `value`; all other operators require it.
42
+ */
43
+ export declare const UNARY_CONDITION_OPERATORS: readonly ["is_empty", "is_not_empty", "is_null", "is_not_null"];
44
+ export declare const isUnaryConditionOperator: (operator: ConditionOperator) => boolean;
35
45
  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
46
  export type ConditionValue = z.infer<typeof ConditionValueSchema>;
37
47
  export declare const LeafConditionSchema: z.ZodObject<{
@@ -46,8 +56,12 @@ export declare const LeafConditionSchema: z.ZodObject<{
46
56
  contains: "contains";
47
57
  in: "in";
48
58
  not_in: "not_in";
59
+ is_empty: "is_empty";
60
+ is_not_empty: "is_not_empty";
61
+ is_null: "is_null";
62
+ is_not_null: "is_not_null";
49
63
  }>;
50
- value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
64
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>>;
51
65
  }, z.core.$strip>;
52
66
  export type LeafCondition = z.infer<typeof LeafConditionSchema>;
53
67
  export type ConditionGroup = {
@@ -68,8 +82,12 @@ export declare const BranchSchema: z.ZodObject<{
68
82
  contains: "contains";
69
83
  in: "in";
70
84
  not_in: "not_in";
85
+ is_empty: "is_empty";
86
+ is_not_empty: "is_not_empty";
87
+ is_null: "is_null";
88
+ is_not_null: "is_not_null";
71
89
  }>;
72
- value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
90
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>>;
73
91
  }, z.core.$strip>, z.ZodType<ConditionGroup, unknown, z.core.$ZodTypeInternals<ConditionGroup, unknown>>]>>>;
74
92
  targetStepId: z.ZodString;
75
93
  }, z.core.$strip>;
@@ -89,8 +107,12 @@ export declare const NextStepSchema: z.ZodDefault<z.ZodNullable<z.ZodObject<{
89
107
  contains: "contains";
90
108
  in: "in";
91
109
  not_in: "not_in";
110
+ is_empty: "is_empty";
111
+ is_not_empty: "is_not_empty";
112
+ is_null: "is_null";
113
+ is_not_null: "is_not_null";
92
114
  }>;
93
- value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
115
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>>;
94
116
  }, z.core.$strip>, z.ZodType<ConditionGroup, unknown, z.core.$ZodTypeInternals<ConditionGroup, unknown>>]>>>;
95
117
  targetStepId: z.ZodString;
96
118
  }, z.core.$strip>>>;
@@ -122,8 +144,12 @@ export declare const BaseStepTypeSchema: z.ZodObject<{
122
144
  contains: "contains";
123
145
  in: "in";
124
146
  not_in: "not_in";
147
+ is_empty: "is_empty";
148
+ is_not_empty: "is_not_empty";
149
+ is_null: "is_null";
150
+ is_not_null: "is_not_null";
125
151
  }>;
126
- value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>;
152
+ value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>]>>;
127
153
  }, z.core.$strip>, z.ZodType<ConditionGroup, unknown, z.core.$ZodTypeInternals<ConditionGroup, unknown>>]>>>;
128
154
  targetStepId: z.ZodString;
129
155
  }, z.core.$strip>>>;
@@ -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;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
+ {"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;;;;;;;;;;;;;;EAiBlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;;;GAGG;AACH,eAAO,MAAM,yBAAyB,iEAKW,CAAC;AAIlD,eAAO,MAAM,wBAAwB,GAAI,UAAU,iBAAiB,KAAG,OACrC,CAAC;AAEnC,eAAO,MAAM,oBAAoB,0IAK/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;iBAc5B,CAAC;AACL,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.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;
3
+ exports.BaseStepTypeSchema = exports.NextStepSchema = exports.BranchSchema = exports.ConditionGroupSchema = exports.LeafConditionSchema = exports.ConditionValueSchema = exports.isUnaryConditionOperator = exports.UNARY_CONDITION_OPERATORS = 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([
@@ -37,17 +37,47 @@ exports.ConditionOperatorSchema = zod_1.z.enum([
37
37
  "contains",
38
38
  "in",
39
39
  "not_in",
40
+ // Unary presence operators — no `value` required. `empty` is type-aware
41
+ // (empty string / empty array / null|undefined); `null` is strictly
42
+ // null|undefined (a set-but-empty value is "not null" yet "is empty").
43
+ "is_empty",
44
+ "is_not_empty",
45
+ "is_null",
46
+ "is_not_null",
40
47
  ]);
48
+ /**
49
+ * Operators that test the variable alone and ignore `value`. A LeafCondition
50
+ * using one of these may omit `value`; all other operators require it.
51
+ */
52
+ exports.UNARY_CONDITION_OPERATORS = [
53
+ "is_empty",
54
+ "is_not_empty",
55
+ "is_null",
56
+ "is_not_null",
57
+ ];
58
+ const UNARY_OPERATOR_SET = new Set(exports.UNARY_CONDITION_OPERATORS);
59
+ const isUnaryConditionOperator = (operator) => UNARY_OPERATOR_SET.has(operator);
60
+ exports.isUnaryConditionOperator = isUnaryConditionOperator;
41
61
  exports.ConditionValueSchema = zod_1.z.union([
42
62
  zod_1.z.string(),
43
63
  zod_1.z.number(),
44
64
  zod_1.z.boolean(),
45
65
  zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean()])),
46
66
  ]);
47
- exports.LeafConditionSchema = zod_1.z.object({
67
+ exports.LeafConditionSchema = zod_1.z
68
+ .object({
48
69
  variable: zod_1.z.string().min(1),
49
70
  operator: exports.ConditionOperatorSchema,
50
- value: exports.ConditionValueSchema,
71
+ value: exports.ConditionValueSchema.optional(),
72
+ })
73
+ .superRefine((data, ctx) => {
74
+ if (!(0, exports.isUnaryConditionOperator)(data.operator) && data.value === undefined) {
75
+ ctx.addIssue({
76
+ code: zod_1.z.ZodIssueCode.custom,
77
+ message: `operator "${data.operator}" requires a value`,
78
+ path: ["value"],
79
+ });
80
+ }
51
81
  });
52
82
  exports.ConditionGroupSchema = zod_1.z.lazy(() => zod_1.z.object({
53
83
  logic: zod_1.z.enum(["and", "or"]),
@@ -1 +1 @@
1
- {"version":3,"file":"common.types.js","sourceRoot":"","sources":["../../src/steps/common.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"common.types.js","sourceRoot":"","sources":["../../src/steps/common.types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocapine/react-native-onboarding",
3
- "version": "1.26.0",
3
+ "version": "1.27.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",
@@ -51,7 +51,7 @@
51
51
  ],
52
52
  "repository": {
53
53
  "type": "git",
54
- "url": "https://github.com/rocapine/react-native-onboarding-studio.git",
54
+ "url": "https://github.com/Rocapine/react-native-onboarding.git",
55
55
  "directory": "packages/onboarding"
56
56
  }
57
57
  }
@@ -76,6 +76,41 @@ describe("evaluateLeaf — unknown operator", () => {
76
76
  it("returns false for unknown operator", () => expect(evaluateLeaf({ variable: "x", operator: "xor" as any, value: "y" }, { x: "y" })).toBe(false));
77
77
  });
78
78
 
79
+ describe("evaluateLeaf — unary is_empty / is_not_empty", () => {
80
+ it("empty string is empty", () => expect(evaluateLeaf({ variable: "x", operator: "is_empty" }, { x: "" })).toBe(true));
81
+ it("whitespace string is empty", () => expect(evaluateLeaf({ variable: "x", operator: "is_empty" }, { x: " " })).toBe(true));
82
+ it("unset variable is empty", () => expect(evaluateLeaf({ variable: "x", operator: "is_empty" }, {})).toBe(true));
83
+ it("empty array is empty", () => expect(evaluateLeaf({ variable: "x", operator: "is_empty" }, { x: [] })).toBe(true));
84
+ it("non-empty string is not empty", () => expect(evaluateLeaf({ variable: "x", operator: "is_not_empty" }, { x: "Paul" })).toBe(true));
85
+ it("zero-string is not empty (0 is a value)", () => expect(evaluateLeaf({ variable: "x", operator: "is_not_empty" }, { x: "0" })).toBe(true));
86
+ it("populated array is not empty", () => expect(evaluateLeaf({ variable: "x", operator: "is_not_empty" }, { x: ["a"] })).toBe(true));
87
+ it("is_not_empty is the negation of is_empty", () => expect(evaluateLeaf({ variable: "x", operator: "is_not_empty" }, { x: "" })).toBe(false));
88
+ });
89
+
90
+ describe("evaluateLeaf — unary is_null / is_not_null", () => {
91
+ it("unset variable is null", () => expect(evaluateLeaf({ variable: "x", operator: "is_null" }, {})).toBe(true));
92
+ it("explicit null is null", () => expect(evaluateLeaf({ variable: "x", operator: "is_null" }, { x: null })).toBe(true));
93
+ it("set-but-empty string is NOT null", () => expect(evaluateLeaf({ variable: "x", operator: "is_not_null" }, { x: "" })).toBe(true));
94
+ it("set value is not null", () => expect(evaluateLeaf({ variable: "x", operator: "is_not_null" }, { x: "Paul" })).toBe(true));
95
+ it("unset variable is_not_null is false", () => expect(evaluateLeaf({ variable: "x", operator: "is_not_null" }, {})).toBe(false));
96
+ });
97
+
98
+ describe("evaluateLeaf — JSON-array-encoded variable values (CheckboxGroup)", () => {
99
+ // Multi-select stores its value as a JSON string; "[]" is an empty selection.
100
+ it('empty "[]" reads as empty', () => expect(evaluateLeaf({ variable: "tags", operator: "is_empty" }, { tags: "[]" })).toBe(true));
101
+ it('empty "[]" is_not_empty is false (gated element falls back on deselect)', () =>
102
+ expect(evaluateLeaf({ variable: "tags", operator: "is_not_empty" }, { tags: "[]" })).toBe(false));
103
+ it('non-empty "[\\"a\\"]" is not empty', () => expect(evaluateLeaf({ variable: "tags", operator: "is_not_empty" }, { tags: '["a"]' })).toBe(true));
104
+ it("contains uses real array membership on encoded value", () =>
105
+ expect(evaluateLeaf({ variable: "tags", operator: "contains", value: "sport" }, { tags: '["health","sport"]' })).toBe(true));
106
+ it("contains is false when element absent from encoded array", () =>
107
+ expect(evaluateLeaf({ variable: "tags", operator: "contains", value: "music" }, { tags: '["health","sport"]' })).toBe(false));
108
+ it("a plain string that is not a JSON array is left untouched", () =>
109
+ expect(evaluateLeaf({ variable: "x", operator: "is_not_empty" }, { x: "[oops" })).toBe(true));
110
+ it("a numeric-looking string is not coerced to empty", () =>
111
+ expect(evaluateLeaf({ variable: "x", operator: "is_not_empty" }, { x: "5" })).toBe(true));
112
+ });
113
+
79
114
  // ---------------------------------------------------------------------------
80
115
  // evaluateCondition — logic groups
81
116
  // ---------------------------------------------------------------------------
@@ -10,8 +10,40 @@ function coerceToNumber(v: unknown): number {
10
10
  return typeof v === "string" ? parseFloat(v) : Number(v);
11
11
  }
12
12
 
13
+ // Multi-select elements (e.g. CheckboxGroup) store their value as a JSON-encoded
14
+ // string[] to fit the string-based variable system, so an empty selection is the
15
+ // literal string "[]". Decode such strings back to an array before evaluating so
16
+ // array-aware operators (is_empty / is_not_empty / contains / in / not_in) see the
17
+ // real collection — otherwise "[]" reads as a non-empty 2-char string. Only strings
18
+ // that parse to an actual array are coerced; scalars and plain text are untouched.
19
+ function decodeArrayValue(raw: unknown): unknown {
20
+ if (typeof raw !== "string") return raw;
21
+ const trimmed = raw.trim();
22
+ if (!(trimmed.startsWith("[") && trimmed.endsWith("]"))) return raw;
23
+ try {
24
+ const parsed = JSON.parse(trimmed);
25
+ return Array.isArray(parsed) ? parsed : raw;
26
+ } catch {
27
+ return raw;
28
+ }
29
+ }
30
+
31
+ // `null`-ness: only null / undefined. A set-but-empty value (e.g. "") is NOT null.
32
+ function isNullish(v: unknown): boolean {
33
+ return v === null || v === undefined;
34
+ }
35
+
36
+ // Type-aware emptiness: null|undefined, empty/whitespace string, or empty array.
37
+ // Numbers and booleans are never "empty" (0 / false are meaningful values).
38
+ function isEmpty(v: unknown): boolean {
39
+ if (isNullish(v)) return true;
40
+ if (typeof v === "string") return v.trim() === "";
41
+ if (Array.isArray(v)) return v.length === 0;
42
+ return false;
43
+ }
44
+
13
45
  export function evaluateLeaf(condition: LeafCondition, variables: Record<string, unknown>): boolean {
14
- const raw = variables[condition.variable];
46
+ const raw = decodeArrayValue(variables[condition.variable]);
15
47
  const { operator, value } = condition;
16
48
 
17
49
  switch (operator) {
@@ -35,6 +67,14 @@ export function evaluateLeaf(condition: LeafCondition, variables: Record<string,
35
67
  return Array.isArray(value) ? value.includes(String(raw)) : false;
36
68
  case "not_in":
37
69
  return Array.isArray(value) ? !value.includes(String(raw)) : true;
70
+ case "is_empty":
71
+ return isEmpty(raw);
72
+ case "is_not_empty":
73
+ return !isEmpty(raw);
74
+ case "is_null":
75
+ return isNullish(raw);
76
+ case "is_not_null":
77
+ return !isNullish(raw);
38
78
  default:
39
79
  return false;
40
80
  }
package/src/index.ts CHANGED
@@ -8,10 +8,16 @@ export type {
8
8
  CustomButtonAction,
9
9
  ComposableVariableEntry,
10
10
  ComposableVariableKind,
11
+ WheelPickerElementProps,
12
+ WheelPickerItem,
13
+ WheelPickerRange,
11
14
  } from "./steps/ComposableScreen/types";
12
15
  export {
13
16
  ButtonActionSchema,
14
17
  CustomButtonActionSchema,
18
+ WheelPickerElementPropsSchema,
19
+ generateWheelPickerRangeItems,
20
+ resolveWheelPickerItems,
15
21
  } from "./steps/ComposableScreen/types";
16
22
  // Hooks and providers
17
23
  export * from "./infra";
@@ -35,4 +41,6 @@ export {
35
41
  NextStepSchema,
36
42
  ConditionOperatorSchema,
37
43
  ConditionValueSchema,
44
+ UNARY_CONDITION_OPERATORS,
45
+ isUnaryConditionOperator,
38
46
  } from "./steps/common.types";
@@ -194,6 +194,21 @@ export const onboardingExample = {
194
194
  },
195
195
  ],
196
196
  },
197
+ {
198
+ // Only shown once `name` has a non-empty value — demonstrates
199
+ // the unary `is_not_empty` condition operator.
200
+ id: "name-greeting",
201
+ type: "Text",
202
+ renderWhen: { variable: "name", operator: "is_not_empty" },
203
+ props: {
204
+ content: "Nice to meet you, {{name}}!",
205
+ mode: "expression",
206
+ fontSize: 14,
207
+ textAlign: "center",
208
+ opacity: 0.6,
209
+ marginVertical: 4,
210
+ },
211
+ },
197
212
  {
198
213
  id: "scroll-demo",
199
214
  type: "ScrollView",
@@ -436,6 +451,29 @@ export const onboardingExample = {
436
451
  marginVertical: 4,
437
452
  },
438
453
  },
454
+ {
455
+ id: "hero-weight-wheel",
456
+ type: "WheelPicker",
457
+ props: {
458
+ variableName: "weight",
459
+ defaultValue: "70",
460
+ range: { min: 40, max: 200, step: 1, unit: "kg" },
461
+ height: 180,
462
+ marginVertical: 8,
463
+ },
464
+ },
465
+ {
466
+ id: "weight-display",
467
+ type: "Text",
468
+ props: {
469
+ content: "Weight: {{weight}}",
470
+ mode: "expression",
471
+ fontSize: 14,
472
+ textAlign: "center",
473
+ opacity: 0.6,
474
+ marginVertical: 4,
475
+ },
476
+ },
439
477
  {
440
478
  id: "hero-carousel",
441
479
  type: "Carousel",
@@ -0,0 +1,115 @@
1
+ import { z } from "zod";
2
+ import { BaseBoxProps, BaseBoxPropsSchema } from "./BaseBoxProps";
3
+
4
+ export type WheelPickerItem = { label: string; value: string };
5
+
6
+ export type WheelPickerRange = {
7
+ min: number;
8
+ max: number;
9
+ step?: number;
10
+ unit?: string;
11
+ };
12
+
13
+ export type WheelPickerElementProps = BaseBoxProps & {
14
+ variableName?: string;
15
+ defaultValue?: string;
16
+ /** Explicit option list. Mutually exclusive with `range`. */
17
+ items?: WheelPickerItem[];
18
+ /** Numeric range that auto-generates options. Mutually exclusive with `items`. */
19
+ range?: WheelPickerRange;
20
+ /** Text color of the wheel items. */
21
+ itemColor?: string;
22
+ /** Font size of the wheel items (iOS `itemStyle`). */
23
+ itemFontSize?: number;
24
+ /** Font family of the wheel items (iOS `itemStyle`). */
25
+ itemFontFamily?: string;
26
+ };
27
+
28
+ // Hard cap on generated range items — guards against runaway ranges
29
+ // (e.g. min 0 / max 1e9 / step 0.01) producing millions of <Picker.Item>.
30
+ const RANGE_MAX_ITEMS = 1000;
31
+
32
+ /**
33
+ * Expand a numeric `range` into wheel items. Shared by the UI renderer,
34
+ * default-collection, and schema validation so all three agree on the exact
35
+ * generated value set (and its string formatting).
36
+ */
37
+ export function generateWheelPickerRangeItems(range: WheelPickerRange): WheelPickerItem[] {
38
+ const step = range.step ?? 1;
39
+ const items: WheelPickerItem[] = [];
40
+ if (!(step > 0) || range.max < range.min) return items;
41
+ for (let i = 0; i < RANGE_MAX_ITEMS; i++) {
42
+ const raw = range.min + i * step;
43
+ if (raw > range.max + 1e-9) break;
44
+ // Trim float accumulation noise (e.g. 0.30000000000000004 → 0.3).
45
+ const value = Math.round(raw * 1e6) / 1e6;
46
+ const valueStr = String(value);
47
+ const label = range.unit ? `${valueStr} ${range.unit}` : valueStr;
48
+ items.push({ label, value: valueStr });
49
+ }
50
+ return items;
51
+ }
52
+
53
+ /**
54
+ * Resolve the effective item list for a WheelPicker: explicit `items` win,
55
+ * otherwise the numeric `range` is expanded. Returns `[]` when neither is set.
56
+ */
57
+ export function resolveWheelPickerItems(props: WheelPickerElementProps): WheelPickerItem[] {
58
+ if (props.items && props.items.length > 0) return props.items;
59
+ if (props.range) return generateWheelPickerRangeItems(props.range);
60
+ return [];
61
+ }
62
+
63
+ const WheelPickerItemSchema = z.object({
64
+ label: z.string().trim().min(1, "item label must not be empty"),
65
+ value: z.string().trim().min(1, "item value must not be empty"),
66
+ });
67
+
68
+ const WheelPickerRangeSchema = z.object({
69
+ min: z.number(),
70
+ max: z.number(),
71
+ step: z.number().positive().optional(),
72
+ unit: z.string().optional(),
73
+ });
74
+
75
+ export const WheelPickerElementPropsSchema = BaseBoxPropsSchema.extend({
76
+ variableName: z.string().optional(),
77
+ defaultValue: z.string().optional(),
78
+ items: z.array(WheelPickerItemSchema).min(1, "items must not be empty").optional(),
79
+ range: WheelPickerRangeSchema.optional(),
80
+ itemColor: z.string().optional(),
81
+ itemFontSize: z.number().optional(),
82
+ itemFontFamily: z.string().optional(),
83
+ }).superRefine((data, ctx) => {
84
+ const hasItems = data.items !== undefined;
85
+ const hasRange = data.range !== undefined;
86
+ // Exactly one source must be present — both or neither is ambiguous.
87
+ if (hasItems === hasRange) {
88
+ ctx.addIssue({
89
+ code: z.ZodIssueCode.custom,
90
+ message: "provide exactly one of `items` or `range`",
91
+ path: hasItems ? ["range"] : ["items"],
92
+ });
93
+ return;
94
+ }
95
+ if (hasRange && data.range!.max < data.range!.min) {
96
+ ctx.addIssue({
97
+ code: z.ZodIssueCode.custom,
98
+ message: "range.max must be >= range.min",
99
+ path: ["range", "max"],
100
+ });
101
+ return;
102
+ }
103
+ const values = resolveWheelPickerItems(data as WheelPickerElementProps).map((i) => i.value);
104
+ const unique = new Set(values);
105
+ if (hasItems && unique.size !== values.length) {
106
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: "item values must be unique", path: ["items"] });
107
+ }
108
+ if (data.defaultValue !== undefined && !unique.has(data.defaultValue)) {
109
+ ctx.addIssue({
110
+ code: z.ZodIssueCode.custom,
111
+ message: "defaultValue must match one of the available values",
112
+ path: ["defaultValue"],
113
+ });
114
+ }
115
+ });
@@ -18,6 +18,7 @@ import { type ButtonElementProps, ButtonElementPropsSchema } from "./elements/Bu
18
18
  import { type RadioGroupElementProps, RadioGroupElementPropsSchema } from "./elements/RadioGroupElement";
19
19
  import { type CheckboxGroupElementProps, CheckboxGroupElementPropsSchema } from "./elements/CheckboxGroupElement";
20
20
  import { type DatePickerElementProps, DatePickerElementPropsSchema } from "./elements/DatePickerElement";
21
+ import { type WheelPickerElementProps, WheelPickerElementPropsSchema } from "./elements/WheelPickerElement";
21
22
  import { type CarouselElementProps, CarouselElementPropsSchema } from "./elements/CarouselElement";
22
23
  import { type ZStackElementProps, ZStackElementPropsSchema } from "./elements/ZStackElement";
23
24
  import { type SafeAreaViewElementProps, SafeAreaViewElementPropsSchema } from "./elements/SafeAreaViewElement";
@@ -42,6 +43,8 @@ export { ButtonActionSchema, CustomButtonActionSchema } from "./elements/ButtonE
42
43
  export type { RadioGroupElementProps } from "./elements/RadioGroupElement";
43
44
  export type { CheckboxGroupElementProps } from "./elements/CheckboxGroupElement";
44
45
  export type { DatePickerElementProps } from "./elements/DatePickerElement";
46
+ export type { WheelPickerElementProps, WheelPickerItem, WheelPickerRange } from "./elements/WheelPickerElement";
47
+ export { WheelPickerElementPropsSchema, generateWheelPickerRangeItems, resolveWheelPickerItems } from "./elements/WheelPickerElement";
45
48
  export type { CarouselElementProps } from "./elements/CarouselElement";
46
49
  export type { ZStackElementProps } from "./elements/ZStackElement";
47
50
  export type { SafeAreaViewElementProps, SafeAreaEdge, SafeAreaEdgeMode } from "./elements/SafeAreaViewElement";
@@ -156,6 +159,13 @@ type UIElement =
156
159
  type: "DatePicker";
157
160
  props: DatePickerElementProps;
158
161
  }
162
+ | {
163
+ id: string;
164
+ name?: string;
165
+ renderWhen?: LeafCondition | ConditionGroup;
166
+ type: "WheelPicker";
167
+ props: WheelPickerElementProps;
168
+ }
159
169
  | {
160
170
  id: string;
161
171
  name?: string;
@@ -284,6 +294,13 @@ const UIElementSchema: z.ZodType<UIElement> = z.lazy(() =>
284
294
  type: z.literal("DatePicker"),
285
295
  props: DatePickerElementPropsSchema,
286
296
  }),
297
+ z.object({
298
+ id: z.string(),
299
+ name: z.string().optional(),
300
+ renderWhen: z.union([LeafConditionSchema, ConditionGroupSchema]).optional(),
301
+ type: z.literal("WheelPicker"),
302
+ props: WheelPickerElementPropsSchema,
303
+ }),
287
304
  z.object({
288
305
  id: z.string(),
289
306
  name: z.string().optional(),