@rocapine/react-native-onboarding 1.26.0 → 1.28.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 (57) 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 +314 -111
  9. package/dist/onboarding-example.d.ts.map +1 -1
  10. package/dist/onboarding-example.js +40 -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/CheckboxGroupElement.d.ts +2 -0
  19. package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.d.ts.map +1 -1
  20. package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.js +1 -0
  21. package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.js.map +1 -1
  22. package/dist/steps/ComposableScreen/elements/RadioGroupElement.d.ts +2 -0
  23. package/dist/steps/ComposableScreen/elements/RadioGroupElement.d.ts.map +1 -1
  24. package/dist/steps/ComposableScreen/elements/RadioGroupElement.js +1 -0
  25. package/dist/steps/ComposableScreen/elements/RadioGroupElement.js.map +1 -1
  26. package/dist/steps/ComposableScreen/elements/WheelPickerElement.d.ts +124 -0
  27. package/dist/steps/ComposableScreen/elements/WheelPickerElement.d.ts.map +1 -0
  28. package/dist/steps/ComposableScreen/elements/WheelPickerElement.js +96 -0
  29. package/dist/steps/ComposableScreen/elements/WheelPickerElement.js.map +1 -0
  30. package/dist/steps/ComposableScreen/types.d.ts +14 -1
  31. package/dist/steps/ComposableScreen/types.d.ts.map +1 -1
  32. package/dist/steps/ComposableScreen/types.js +13 -1
  33. package/dist/steps/ComposableScreen/types.js.map +1 -1
  34. package/dist/steps/Loader/types.d.ts +5 -1
  35. package/dist/steps/Loader/types.d.ts.map +1 -1
  36. package/dist/steps/MediaContent/types.d.ts +5 -1
  37. package/dist/steps/MediaContent/types.d.ts.map +1 -1
  38. package/dist/steps/Picker/types.d.ts +5 -1
  39. package/dist/steps/Picker/types.d.ts.map +1 -1
  40. package/dist/steps/Question/types.d.ts +5 -1
  41. package/dist/steps/Question/types.d.ts.map +1 -1
  42. package/dist/steps/Ratings/types.d.ts +5 -1
  43. package/dist/steps/Ratings/types.d.ts.map +1 -1
  44. package/dist/steps/common.types.d.ts +30 -4
  45. package/dist/steps/common.types.d.ts.map +1 -1
  46. package/dist/steps/common.types.js +33 -3
  47. package/dist/steps/common.types.js.map +1 -1
  48. package/package.json +2 -2
  49. package/src/__tests__/evaluateCondition.test.ts +35 -0
  50. package/src/evaluateCondition.ts +41 -1
  51. package/src/index.ts +8 -0
  52. package/src/onboarding-example.ts +40 -0
  53. package/src/steps/ComposableScreen/elements/CheckboxGroupElement.ts +2 -0
  54. package/src/steps/ComposableScreen/elements/RadioGroupElement.ts +2 -0
  55. package/src/steps/ComposableScreen/elements/WheelPickerElement.ts +115 -0
  56. package/src/steps/ComposableScreen/types.ts +17 -0
  57. package/src/steps/common.types.ts +38 -5
@@ -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(),
@@ -41,9 +41,32 @@ export const ConditionOperatorSchema = z.enum([
41
41
  "contains",
42
42
  "in",
43
43
  "not_in",
44
+ // Unary presence operators — no `value` required. `empty` is type-aware
45
+ // (empty string / empty array / null|undefined); `null` is strictly
46
+ // null|undefined (a set-but-empty value is "not null" yet "is empty").
47
+ "is_empty",
48
+ "is_not_empty",
49
+ "is_null",
50
+ "is_not_null",
44
51
  ]);
45
52
  export type ConditionOperator = z.infer<typeof ConditionOperatorSchema>;
46
53
 
54
+ /**
55
+ * Operators that test the variable alone and ignore `value`. A LeafCondition
56
+ * using one of these may omit `value`; all other operators require it.
57
+ */
58
+ export const UNARY_CONDITION_OPERATORS = [
59
+ "is_empty",
60
+ "is_not_empty",
61
+ "is_null",
62
+ "is_not_null",
63
+ ] as const satisfies readonly ConditionOperator[];
64
+
65
+ const UNARY_OPERATOR_SET = new Set<ConditionOperator>(UNARY_CONDITION_OPERATORS);
66
+
67
+ export const isUnaryConditionOperator = (operator: ConditionOperator): boolean =>
68
+ UNARY_OPERATOR_SET.has(operator);
69
+
47
70
  export const ConditionValueSchema = z.union([
48
71
  z.string(),
49
72
  z.number(),
@@ -52,11 +75,21 @@ export const ConditionValueSchema = z.union([
52
75
  ]);
53
76
  export type ConditionValue = z.infer<typeof ConditionValueSchema>;
54
77
 
55
- export const LeafConditionSchema = z.object({
56
- variable: z.string().min(1),
57
- operator: ConditionOperatorSchema,
58
- value: ConditionValueSchema,
59
- });
78
+ export const LeafConditionSchema = z
79
+ .object({
80
+ variable: z.string().min(1),
81
+ operator: ConditionOperatorSchema,
82
+ value: ConditionValueSchema.optional(),
83
+ })
84
+ .superRefine((data, ctx) => {
85
+ if (!isUnaryConditionOperator(data.operator) && data.value === undefined) {
86
+ ctx.addIssue({
87
+ code: z.ZodIssueCode.custom,
88
+ message: `operator "${data.operator}" requires a value`,
89
+ path: ["value"],
90
+ });
91
+ }
92
+ });
60
93
  export type LeafCondition = z.infer<typeof LeafConditionSchema>;
61
94
 
62
95
  export type ConditionGroup = {