@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.
- package/dist/evaluateCondition.d.ts.map +1 -1
- package/dist/evaluateCondition.js +44 -1
- package/dist/evaluateCondition.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/onboarding-example.d.ts +314 -111
- package/dist/onboarding-example.d.ts.map +1 -1
- package/dist/onboarding-example.js +40 -0
- package/dist/onboarding-example.js.map +1 -1
- package/dist/steps/Carousel/types.d.ts +5 -1
- package/dist/steps/Carousel/types.d.ts.map +1 -1
- package/dist/steps/Commitment/types.d.ts +5 -1
- package/dist/steps/Commitment/types.d.ts.map +1 -1
- package/dist/steps/ComposableScreen/elements/ButtonElement.d.ts +5 -1
- package/dist/steps/ComposableScreen/elements/ButtonElement.d.ts.map +1 -1
- package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.d.ts +2 -0
- package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.d.ts.map +1 -1
- package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.js +1 -0
- package/dist/steps/ComposableScreen/elements/CheckboxGroupElement.js.map +1 -1
- package/dist/steps/ComposableScreen/elements/RadioGroupElement.d.ts +2 -0
- package/dist/steps/ComposableScreen/elements/RadioGroupElement.d.ts.map +1 -1
- package/dist/steps/ComposableScreen/elements/RadioGroupElement.js +1 -0
- package/dist/steps/ComposableScreen/elements/RadioGroupElement.js.map +1 -1
- package/dist/steps/ComposableScreen/elements/WheelPickerElement.d.ts +124 -0
- package/dist/steps/ComposableScreen/elements/WheelPickerElement.d.ts.map +1 -0
- package/dist/steps/ComposableScreen/elements/WheelPickerElement.js +96 -0
- package/dist/steps/ComposableScreen/elements/WheelPickerElement.js.map +1 -0
- package/dist/steps/ComposableScreen/types.d.ts +14 -1
- package/dist/steps/ComposableScreen/types.d.ts.map +1 -1
- package/dist/steps/ComposableScreen/types.js +13 -1
- package/dist/steps/ComposableScreen/types.js.map +1 -1
- package/dist/steps/Loader/types.d.ts +5 -1
- package/dist/steps/Loader/types.d.ts.map +1 -1
- package/dist/steps/MediaContent/types.d.ts +5 -1
- package/dist/steps/MediaContent/types.d.ts.map +1 -1
- package/dist/steps/Picker/types.d.ts +5 -1
- package/dist/steps/Picker/types.d.ts.map +1 -1
- package/dist/steps/Question/types.d.ts +5 -1
- package/dist/steps/Question/types.d.ts.map +1 -1
- package/dist/steps/Ratings/types.d.ts +5 -1
- package/dist/steps/Ratings/types.d.ts.map +1 -1
- package/dist/steps/common.types.d.ts +30 -4
- package/dist/steps/common.types.d.ts.map +1 -1
- package/dist/steps/common.types.js +33 -3
- package/dist/steps/common.types.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/evaluateCondition.test.ts +35 -0
- package/src/evaluateCondition.ts +41 -1
- package/src/index.ts +8 -0
- package/src/onboarding-example.ts +40 -0
- package/src/steps/ComposableScreen/elements/CheckboxGroupElement.ts +2 -0
- package/src/steps/ComposableScreen/elements/RadioGroupElement.ts +2 -0
- package/src/steps/ComposableScreen/elements/WheelPickerElement.ts +115 -0
- package/src/steps/ComposableScreen/types.ts +17 -0
- 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
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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 = {
|