@rocapine/react-native-onboarding-ui 1.23.0 → 1.24.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 (39) hide show
  1. package/dist/UI/Pages/ComposableScreen/elements/BaseBoxProps.d.ts +21 -0
  2. package/dist/UI/Pages/ComposableScreen/elements/BaseBoxProps.d.ts.map +1 -1
  3. package/dist/UI/Pages/ComposableScreen/elements/BaseBoxProps.js +10 -1
  4. package/dist/UI/Pages/ComposableScreen/elements/BaseBoxProps.js.map +1 -1
  5. package/dist/UI/Pages/ComposableScreen/elements/ButtonElement.d.ts +289 -4
  6. package/dist/UI/Pages/ComposableScreen/elements/ButtonElement.d.ts.map +1 -1
  7. package/dist/UI/Pages/ComposableScreen/elements/ButtonElement.js +98 -57
  8. package/dist/UI/Pages/ComposableScreen/elements/ButtonElement.js.map +1 -1
  9. package/dist/UI/Pages/ComposableScreen/elements/CarouselElement.d.ts +8 -0
  10. package/dist/UI/Pages/ComposableScreen/elements/CarouselElement.d.ts.map +1 -1
  11. package/dist/UI/Pages/ComposableScreen/elements/CheckboxGroupElement.d.ts +8 -0
  12. package/dist/UI/Pages/ComposableScreen/elements/CheckboxGroupElement.d.ts.map +1 -1
  13. package/dist/UI/Pages/ComposableScreen/elements/DatePickerElement.d.ts +8 -0
  14. package/dist/UI/Pages/ComposableScreen/elements/DatePickerElement.d.ts.map +1 -1
  15. package/dist/UI/Pages/ComposableScreen/elements/IconElement.d.ts +8 -0
  16. package/dist/UI/Pages/ComposableScreen/elements/IconElement.d.ts.map +1 -1
  17. package/dist/UI/Pages/ComposableScreen/elements/ImageElement.d.ts +8 -0
  18. package/dist/UI/Pages/ComposableScreen/elements/ImageElement.d.ts.map +1 -1
  19. package/dist/UI/Pages/ComposableScreen/elements/InputElement.d.ts +8 -0
  20. package/dist/UI/Pages/ComposableScreen/elements/InputElement.d.ts.map +1 -1
  21. package/dist/UI/Pages/ComposableScreen/elements/LottieElement.d.ts +8 -0
  22. package/dist/UI/Pages/ComposableScreen/elements/LottieElement.d.ts.map +1 -1
  23. package/dist/UI/Pages/ComposableScreen/elements/RadioGroupElement.d.ts +8 -0
  24. package/dist/UI/Pages/ComposableScreen/elements/RadioGroupElement.d.ts.map +1 -1
  25. package/dist/UI/Pages/ComposableScreen/elements/RiveElement.d.ts +8 -0
  26. package/dist/UI/Pages/ComposableScreen/elements/RiveElement.d.ts.map +1 -1
  27. package/dist/UI/Pages/ComposableScreen/elements/SafeAreaViewElement.d.ts +8 -0
  28. package/dist/UI/Pages/ComposableScreen/elements/SafeAreaViewElement.d.ts.map +1 -1
  29. package/dist/UI/Pages/ComposableScreen/elements/StackElement.d.ts +8 -0
  30. package/dist/UI/Pages/ComposableScreen/elements/StackElement.d.ts.map +1 -1
  31. package/dist/UI/Pages/ComposableScreen/elements/TextElement.d.ts +8 -0
  32. package/dist/UI/Pages/ComposableScreen/elements/TextElement.d.ts.map +1 -1
  33. package/dist/UI/Pages/ComposableScreen/elements/VideoElement.d.ts +8 -0
  34. package/dist/UI/Pages/ComposableScreen/elements/VideoElement.d.ts.map +1 -1
  35. package/dist/UI/Pages/ComposableScreen/elements/ZStackElement.d.ts +8 -0
  36. package/dist/UI/Pages/ComposableScreen/elements/ZStackElement.d.ts.map +1 -1
  37. package/package.json +1 -1
  38. package/src/UI/Pages/ComposableScreen/elements/BaseBoxProps.ts +20 -0
  39. package/src/UI/Pages/ComposableScreen/elements/ButtonElement.tsx +169 -69
@@ -1 +1 @@
1
- {"version":3,"file":"ZStackElement.d.ts","sourceRoot":"","sources":["../../../../../src/UI/Pages/ComposableScreen/elements/ZStackElement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,YAAY,EAAsB,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAO,MAAM,UAAU,CAAC;AAG9C,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAC9C,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAAqB,CAAC;AAE3D,KAAK,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC;AAE9D,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,eAAe,CAAC;IACzB,GAAG,EAAE,aAAa,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,kBAAkB,KAAK,KAAG,KAAK,CAAC,YA0CtE,CAAC"}
1
+ {"version":3,"file":"ZStackElement.d.ts","sourceRoot":"","sources":["../../../../../src/UI/Pages/ComposableScreen/elements/ZStackElement.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,YAAY,EAAsB,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAO,MAAM,UAAU,CAAC;AAG9C,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAC9C,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAAqB,CAAC;AAE3D,KAAK,eAAe,GAAG,OAAO,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC;AAE9D,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,eAAe,CAAC;IACzB,GAAG,EAAE,aAAa,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,kBAAkB,KAAK,KAAG,KAAK,CAAC,YA0CtE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocapine/react-native-onboarding-ui",
3
- "version": "1.23.0",
3
+ "version": "1.24.0",
4
4
  "description": "UI components and renderers for Rocapine Onboarding Studio - Built on top of the headless SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -40,6 +40,16 @@ export const GradientBackgroundSchema = z.discriminatedUnion("type", [
40
40
  }),
41
41
  ]);
42
42
 
43
+ export type ShadowOffset = {
44
+ width: number;
45
+ height: number;
46
+ };
47
+
48
+ export const ShadowOffsetSchema = z.object({
49
+ width: z.number(),
50
+ height: z.number(),
51
+ });
52
+
43
53
  export type BaseBoxProps = {
44
54
  width?: number | string;
45
55
  height?: number | string;
@@ -64,6 +74,11 @@ export type BaseBoxProps = {
64
74
  borderWidth?: number;
65
75
  borderRadius?: number;
66
76
  borderColor?: string;
77
+ shadowColor?: string;
78
+ shadowOffset?: ShadowOffset;
79
+ shadowOpacity?: number;
80
+ shadowRadius?: number;
81
+ elevation?: number;
67
82
  };
68
83
 
69
84
  export const BaseBoxPropsSchema = z.object({
@@ -90,4 +105,9 @@ export const BaseBoxPropsSchema = z.object({
90
105
  borderWidth: z.number().min(0).optional(),
91
106
  borderRadius: z.number().min(0).optional(),
92
107
  borderColor: z.string().optional(),
108
+ shadowColor: z.string().optional(),
109
+ shadowOffset: ShadowOffsetSchema.optional(),
110
+ shadowOpacity: z.number().min(0).max(1).optional(),
111
+ shadowRadius: z.number().min(0).optional(),
112
+ elevation: z.number().min(0).optional(),
93
113
  });
@@ -1,6 +1,6 @@
1
- import React, { useMemo } from "react";
1
+ import React, { useEffect, useMemo, useRef, useState } from "react";
2
2
  import { z } from "zod";
3
- import { Text, TouchableOpacity } from "react-native";
3
+ import { Animated, Pressable, Text } from "react-native";
4
4
  import {
5
5
  useResolvedFontStyle,
6
6
  evaluateCondition,
@@ -67,12 +67,21 @@ export const ButtonActionSchema = z.union([
67
67
  SetVariableButtonActionSchema,
68
68
  ]);
69
69
 
70
+ type ButtonOverridableProps = BaseBoxProps & {
71
+ variant?: "filled" | "outlined" | "ghost";
72
+ backgroundColor?: string;
73
+ color?: string;
74
+ fontSize?: number;
75
+ fontWeight?: string;
76
+ fontFamily?: string | "inherit";
77
+ fontStyle?: "normal" | "italic";
78
+ textAlign?: "left" | "center" | "right";
79
+ };
80
+
81
+ export type ButtonStyleOverride = Partial<ButtonOverridableProps>;
82
+
70
83
  export type ButtonElementProps = BaseBoxProps & {
71
84
  label: string;
72
- /**
73
- * Ordered list of actions to run on press. Sequential, await async handlers,
74
- * abort on error, `"continue"` is terminal.
75
- */
76
85
  actions?: ButtonAction[];
77
86
  /** @deprecated Use `actions` instead. */
78
87
  action?: "continue";
@@ -85,10 +94,26 @@ export type ButtonElementProps = BaseBoxProps & {
85
94
  fontStyle?: "normal" | "italic";
86
95
  textAlign?: "left" | "center" | "right";
87
96
  disabledWhen?: LeafCondition | ConditionGroup;
97
+ /** @deprecated Use `disabledStyle.backgroundColor`. */
88
98
  disabledBackgroundColor?: string;
99
+ /** @deprecated Use `disabledStyle.color`. */
89
100
  disabledColor?: string;
101
+ pressedStyle?: ButtonStyleOverride;
102
+ disabledStyle?: ButtonStyleOverride;
103
+ transitionDurationMs?: number;
90
104
  };
91
105
 
106
+ export const ButtonStyleOverrideSchema = BaseBoxPropsSchema.extend({
107
+ variant: z.enum(["filled", "outlined", "ghost"]).optional(),
108
+ backgroundColor: z.string().optional(),
109
+ color: z.string().optional(),
110
+ fontSize: z.number().optional(),
111
+ fontWeight: z.string().optional(),
112
+ fontFamily: z.string().optional(),
113
+ fontStyle: z.enum(["normal", "italic"]).optional(),
114
+ textAlign: z.enum(["left", "center", "right"]).optional(),
115
+ }).partial();
116
+
92
117
  export const ButtonElementPropsSchema = BaseBoxPropsSchema.extend({
93
118
  label: z.string().min(1, "label must not be empty"),
94
119
  actions: z.array(ButtonActionSchema).optional(),
@@ -104,6 +129,9 @@ export const ButtonElementPropsSchema = BaseBoxPropsSchema.extend({
104
129
  disabledWhen: z.union([LeafConditionSchema, ConditionGroupSchema]).optional(),
105
130
  disabledBackgroundColor: z.string().optional(),
106
131
  disabledColor: z.string().optional(),
132
+ pressedStyle: ButtonStyleOverrideSchema.optional(),
133
+ disabledStyle: ButtonStyleOverrideSchema.optional(),
134
+ transitionDurationMs: z.number().min(0).optional(),
107
135
  });
108
136
 
109
137
  type ButtonUIElement = Extract<UIElement, { type: "Button" }>;
@@ -113,6 +141,14 @@ type Props = {
113
141
  ctx: RenderContext;
114
142
  };
115
143
 
144
+ const buildShadowStyle = (p: Pick<BaseBoxProps, "shadowColor" | "shadowOffset" | "shadowOpacity" | "shadowRadius" | "elevation">) => ({
145
+ shadowColor: p.shadowColor,
146
+ shadowOffset: p.shadowOffset,
147
+ shadowOpacity: p.shadowOpacity,
148
+ shadowRadius: p.shadowRadius,
149
+ elevation: p.elevation,
150
+ });
151
+
116
152
  export const ButtonElementComponent = ({ element, ctx }: Props): React.ReactElement => {
117
153
  const { theme, onContinue, customActions, variables, setVariable } = ctx;
118
154
  const flatVariables = useMemo(
@@ -125,6 +161,8 @@ export const ButtonElementComponent = ({ element, ctx }: Props): React.ReactElem
125
161
  const isDisabled = element.props.disabledWhen
126
162
  ? evaluateCondition(element.props.disabledWhen, flatVariables)
127
163
  : false;
164
+ const [isPressed, setIsPressed] = useState(false);
165
+
128
166
  const handlePress = async () => {
129
167
  if (isDisabled) return;
130
168
  const { actions, action } = element.props;
@@ -171,119 +209,181 @@ export const ButtonElementComponent = ({ element, ctx }: Props): React.ReactElem
171
209
  }
172
210
  }
173
211
  };
174
- const variant = element.props.variant ?? "filled";
212
+
213
+ // State overrides are merged over base props. disabledStyle wins over the
214
+ // deprecated `disabledBackgroundColor`/`disabledColor` fields; falls back to
215
+ // those when only the legacy fields are set.
216
+ const stateOverride: ButtonStyleOverride = isDisabled
217
+ ? (element.props.disabledStyle ?? {})
218
+ : isPressed
219
+ ? (element.props.pressedStyle ?? {})
220
+ : {};
221
+ const eff = { ...element.props, ...stateOverride };
222
+
223
+ const variant = eff.variant ?? "filled";
175
224
  const isFilled = variant === "filled";
176
225
  const isOutlined = variant === "outlined";
177
- const disabledBg =
178
- element.props.disabledBackgroundColor ?? theme.colors.disable;
179
- const disabledText =
180
- element.props.disabledColor ?? theme.colors.text.disable;
226
+
227
+ const legacyDisabledBg =
228
+ isDisabled && !element.props.disabledStyle
229
+ ? (element.props.disabledBackgroundColor ?? theme.colors.disable)
230
+ : undefined;
231
+ const legacyDisabledText =
232
+ isDisabled && !element.props.disabledStyle
233
+ ? (element.props.disabledColor ?? theme.colors.text.disable)
234
+ : undefined;
235
+
181
236
  const bgColor = isDisabled
182
237
  ? isFilled
183
- ? disabledBg
238
+ ? (eff.backgroundColor ?? legacyDisabledBg ?? theme.colors.disable)
184
239
  : "transparent"
185
240
  : isFilled
186
- ? (element.props.backgroundColor ?? theme.colors.primary)
241
+ ? (eff.backgroundColor ?? theme.colors.primary)
187
242
  : "transparent";
188
243
  const textColor = isDisabled
189
- ? disabledText
244
+ ? (eff.color ?? legacyDisabledText ?? theme.colors.text.disable)
190
245
  : isFilled
191
- ? (element.props.color ?? theme.colors.text.opposite)
192
- : (element.props.color ?? theme.colors.primary);
246
+ ? (eff.color ?? theme.colors.text.opposite)
247
+ : (eff.color ?? theme.colors.primary);
193
248
  const outlinedBorderColor = isDisabled
194
- ? disabledBg
195
- : (element.props.borderColor ?? theme.colors.primary);
249
+ ? (eff.borderColor ?? legacyDisabledBg ?? theme.colors.disable)
250
+ : (eff.borderColor ?? theme.colors.primary);
196
251
 
197
- const hasGradient = isFilled && !isDisabled && !!element.props.backgroundGradient;
198
- const borderRadius = element.props.borderRadius ?? 90;
252
+ const hasGradient = isFilled && !isDisabled && !!eff.backgroundGradient;
253
+ const borderRadius = eff.borderRadius ?? 90;
199
254
  const inheritedFontFamily = resolveInheritedFontFamily(
200
- element.props.fontFamily,
255
+ eff.fontFamily,
201
256
  theme.typography.defaultFontFamily
202
257
  );
203
258
  const resolvedFont = useResolvedFontStyle(
204
259
  inheritedFontFamily,
205
- element.props.fontWeight
260
+ eff.fontWeight
206
261
  );
207
262
 
263
+ // Animate opacity between rest/pressed/disabled. Uses native driver — color
264
+ // and shadow* changes apply instantly on state transition (acceptable for
265
+ // tap-feedback timescales). transitionDurationMs gates animation length.
266
+ const opacityAnim = useRef(new Animated.Value(eff.opacity ?? 1)).current;
267
+ const duration = element.props.transitionDurationMs ?? 150;
268
+ const restOpacity = element.props.opacity ?? 1;
269
+ const pressedOpacity = element.props.pressedStyle?.opacity ?? 0.8;
270
+ const disabledOpacity =
271
+ element.props.disabledStyle?.opacity ?? element.props.opacity ?? 1;
272
+ const targetOpacity = isDisabled
273
+ ? disabledOpacity
274
+ : isPressed
275
+ ? pressedOpacity
276
+ : restOpacity;
277
+
278
+ useEffect(() => {
279
+ Animated.timing(opacityAnim, {
280
+ toValue: targetOpacity,
281
+ duration,
282
+ useNativeDriver: true,
283
+ }).start();
284
+ }, [targetOpacity, duration, opacityAnim]);
285
+
286
+ const shadowStyle = buildShadowStyle(eff);
287
+
208
288
  const labelNode = (
209
289
  <Text
210
290
  style={{
211
291
  color: textColor,
212
- fontSize: element.props.fontSize ?? theme.typography.textStyles.button.fontSize,
292
+ fontSize: eff.fontSize ?? theme.typography.textStyles.button.fontSize,
213
293
  fontWeight: resolvedFont.resolvedToVariant
214
294
  ? undefined
215
295
  : ((resolvedFont.fontWeight as any) ?? theme.typography.textStyles.button.fontWeight),
216
296
  fontFamily: resolvedFont.fontFamily,
217
- fontStyle: element.props.fontStyle,
218
- textAlign: element.props.textAlign ?? "center",
297
+ fontStyle: eff.fontStyle,
298
+ textAlign: eff.textAlign ?? "center",
219
299
  }}
220
300
  >
221
301
  {element.props.label}
222
302
  </Text>
223
303
  );
224
304
 
305
+ const onPressIn = () => setIsPressed(true);
306
+ const onPressOut = () => setIsPressed(false);
307
+
225
308
  if (hasGradient) {
226
309
  return (
227
- <GradientBox
228
- gradient={element.props.backgroundGradient}
310
+ <Animated.View
229
311
  style={{
312
+ ...shadowStyle,
313
+ opacity: opacityAnim,
314
+ width: dim(eff.width),
315
+ height: dim(eff.height),
316
+ margin: eff.margin,
317
+ marginHorizontal: eff.marginHorizontal,
318
+ marginVertical: eff.marginVertical,
319
+ alignSelf: eff.alignSelf ?? (eff.width ? undefined : "stretch"),
230
320
  borderRadius,
231
- borderWidth: isOutlined ? (element.props.borderWidth ?? 1) : (element.props.borderWidth ?? 0),
232
- borderColor: isOutlined ? outlinedBorderColor : element.props.borderColor,
233
- width: dim(element.props.width),
234
- height: dim(element.props.height),
235
- margin: element.props.margin,
236
- marginHorizontal: element.props.marginHorizontal,
237
- marginVertical: element.props.marginVertical,
238
- opacity: element.props.opacity,
239
- alignSelf: element.props.alignSelf ?? (element.props.width ? undefined : "stretch"),
240
- overflow: "hidden",
241
321
  }}
242
322
  >
243
- <TouchableOpacity
244
- activeOpacity={0.8}
245
- onPress={handlePress}
246
- disabled={isDisabled}
323
+ <GradientBox
324
+ gradient={eff.backgroundGradient}
247
325
  style={{
326
+ borderRadius,
327
+ borderWidth: isOutlined ? (eff.borderWidth ?? 1) : (eff.borderWidth ?? 0),
328
+ borderColor: isOutlined ? outlinedBorderColor : eff.borderColor,
329
+ overflow: "hidden",
248
330
  flex: 1,
249
- padding: element.props.padding,
250
- paddingVertical: element.props.paddingVertical ?? 14,
251
- paddingHorizontal: element.props.paddingHorizontal ?? 24,
252
- alignItems: "center",
253
- justifyContent: "center",
254
331
  }}
255
332
  >
256
- {labelNode}
257
- </TouchableOpacity>
258
- </GradientBox>
333
+ <Pressable
334
+ onPress={handlePress}
335
+ onPressIn={onPressIn}
336
+ onPressOut={onPressOut}
337
+ disabled={isDisabled}
338
+ style={{
339
+ flex: 1,
340
+ padding: eff.padding,
341
+ paddingVertical: eff.paddingVertical ?? 14,
342
+ paddingHorizontal: eff.paddingHorizontal ?? 24,
343
+ alignItems: "center",
344
+ justifyContent: "center",
345
+ }}
346
+ >
347
+ {labelNode}
348
+ </Pressable>
349
+ </GradientBox>
350
+ </Animated.View>
259
351
  );
260
352
  }
261
353
 
262
354
  return (
263
- <TouchableOpacity
264
- activeOpacity={0.8}
265
- onPress={handlePress}
266
- disabled={isDisabled}
355
+ <Animated.View
267
356
  style={{
357
+ ...shadowStyle,
358
+ opacity: opacityAnim,
268
359
  backgroundColor: bgColor,
269
360
  borderRadius,
270
- borderWidth: isOutlined ? (element.props.borderWidth ?? 1) : (element.props.borderWidth ?? 0),
271
- borderColor: isOutlined ? outlinedBorderColor : element.props.borderColor,
272
- padding: element.props.padding,
273
- paddingVertical: element.props.paddingVertical ?? 14,
274
- paddingHorizontal: element.props.paddingHorizontal ?? 24,
275
- width: dim(element.props.width),
276
- height: dim(element.props.height),
277
- margin: element.props.margin,
278
- marginHorizontal: element.props.marginHorizontal,
279
- marginVertical: element.props.marginVertical,
280
- opacity: element.props.opacity,
281
- alignSelf: element.props.alignSelf ?? (element.props.width ? undefined : "stretch"),
282
- alignItems: "center",
283
- justifyContent: "center",
361
+ borderWidth: isOutlined ? (eff.borderWidth ?? 1) : (eff.borderWidth ?? 0),
362
+ borderColor: isOutlined ? outlinedBorderColor : eff.borderColor,
363
+ width: dim(eff.width),
364
+ height: dim(eff.height),
365
+ margin: eff.margin,
366
+ marginHorizontal: eff.marginHorizontal,
367
+ marginVertical: eff.marginVertical,
368
+ alignSelf: eff.alignSelf ?? (eff.width ? undefined : "stretch"),
284
369
  }}
285
370
  >
286
- {labelNode}
287
- </TouchableOpacity>
371
+ <Pressable
372
+ onPress={handlePress}
373
+ onPressIn={onPressIn}
374
+ onPressOut={onPressOut}
375
+ disabled={isDisabled}
376
+ style={{
377
+ padding: eff.padding,
378
+ paddingVertical: eff.paddingVertical ?? 14,
379
+ paddingHorizontal: eff.paddingHorizontal ?? 24,
380
+ alignItems: "center",
381
+ justifyContent: "center",
382
+ borderRadius,
383
+ }}
384
+ >
385
+ {labelNode}
386
+ </Pressable>
387
+ </Animated.View>
288
388
  );
289
389
  };