@rocapine/react-native-onboarding-ui 1.30.0 → 1.32.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/UI/Pages/ComposableScreen/elements/AnimatedBox.d.ts +21 -0
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedBox.d.ts.map +1 -0
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedBox.js +140 -0
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedBox.js.map +1 -0
- package/dist/UI/Pages/ComposableScreen/elements/BaseBoxProps.d.ts +220 -0
- package/dist/UI/Pages/ComposableScreen/elements/BaseBoxProps.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/BaseBoxProps.js +83 -0
- package/dist/UI/Pages/ComposableScreen/elements/BaseBoxProps.js.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/ButtonElement.d.ts +640 -0
- package/dist/UI/Pages/ComposableScreen/elements/ButtonElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/CarouselElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/CarouselElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/CheckboxGroupElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/CheckboxGroupElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/DatePickerElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/DatePickerElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/IconElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/IconElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/ImageElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/ImageElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/InputElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/InputElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/KeyboardAvoidingViewElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/KeyboardAvoidingViewElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/LottieElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/LottieElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.js +2 -8
- package/dist/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.js.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/RadioGroupElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/RadioGroupElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/RiveElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/RiveElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/SafeAreaViewElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/SafeAreaViewElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/ScrollViewElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/ScrollViewElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/StackElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/StackElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/TextElement.d.ts +245 -2
- package/dist/UI/Pages/ComposableScreen/elements/TextElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/TextElement.js +58 -6
- package/dist/UI/Pages/ComposableScreen/elements/TextElement.js.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/VideoElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/VideoElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/ZStackElement.d.ts +160 -0
- package/dist/UI/Pages/ComposableScreen/elements/ZStackElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/buildAnimation.d.ts +9 -0
- package/dist/UI/Pages/ComposableScreen/elements/buildAnimation.d.ts.map +1 -0
- package/dist/UI/Pages/ComposableScreen/elements/buildAnimation.js +106 -0
- package/dist/UI/Pages/ComposableScreen/elements/buildAnimation.js.map +1 -0
- package/dist/UI/Pages/ComposableScreen/elements/renderElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/renderElement.js +72 -58
- package/dist/UI/Pages/ComposableScreen/elements/renderElement.js.map +1 -1
- package/package.json +1 -1
- package/src/UI/Pages/ComposableScreen/elements/AnimatedBox.tsx +133 -0
- package/src/UI/Pages/ComposableScreen/elements/BaseBoxProps.ts +211 -0
- package/src/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.tsx +1 -9
- package/src/UI/Pages/ComposableScreen/elements/TextElement.tsx +93 -5
- package/src/UI/Pages/ComposableScreen/elements/buildAnimation.ts +83 -0
- package/src/UI/Pages/ComposableScreen/elements/renderElement.tsx +28 -1
|
@@ -7,8 +7,48 @@ import { UIElement } from "../types";
|
|
|
7
7
|
import { RenderContext, interpolate, dim, resolveInheritedFontFamily } from "./shared";
|
|
8
8
|
import { GradientBox } from "./GradientBox";
|
|
9
9
|
|
|
10
|
+
export type TextSpan = {
|
|
11
|
+
text: string;
|
|
12
|
+
fontWeight?: string;
|
|
13
|
+
fontStyle?: "normal" | "italic";
|
|
14
|
+
fontFamily?: string | "inherit";
|
|
15
|
+
fontSize?: number;
|
|
16
|
+
letterSpacing?: number;
|
|
17
|
+
lineHeight?: number;
|
|
18
|
+
color?: string;
|
|
19
|
+
backgroundColor?: string;
|
|
20
|
+
opacity?: number;
|
|
21
|
+
textTransform?: "none" | "uppercase" | "lowercase" | "capitalize";
|
|
22
|
+
textDecorationLine?:
|
|
23
|
+
| "none"
|
|
24
|
+
| "underline"
|
|
25
|
+
| "line-through"
|
|
26
|
+
| "underline line-through";
|
|
27
|
+
textDecorationColor?: string;
|
|
28
|
+
textDecorationStyle?: "solid" | "double" | "dotted" | "dashed";
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const TextSpanSchema = z.object({
|
|
32
|
+
text: z.string(),
|
|
33
|
+
fontWeight: z.string().optional(),
|
|
34
|
+
fontStyle: z.enum(["normal", "italic"]).optional(),
|
|
35
|
+
fontFamily: z.string().optional(),
|
|
36
|
+
fontSize: z.number().optional(),
|
|
37
|
+
letterSpacing: z.number().optional(),
|
|
38
|
+
lineHeight: z.number().optional(),
|
|
39
|
+
color: z.string().optional(),
|
|
40
|
+
backgroundColor: z.string().optional(),
|
|
41
|
+
opacity: z.number().min(0).max(1).optional(),
|
|
42
|
+
textTransform: z.enum(["none", "uppercase", "lowercase", "capitalize"]).optional(),
|
|
43
|
+
textDecorationLine: z
|
|
44
|
+
.enum(["none", "underline", "line-through", "underline line-through"])
|
|
45
|
+
.optional(),
|
|
46
|
+
textDecorationColor: z.string().optional(),
|
|
47
|
+
textDecorationStyle: z.enum(["solid", "double", "dotted", "dashed"]).optional(),
|
|
48
|
+
});
|
|
49
|
+
|
|
10
50
|
export type TextElementProps = BaseBoxProps & {
|
|
11
|
-
content: string;
|
|
51
|
+
content: string | TextSpan[];
|
|
12
52
|
mode?: "plain" | "expression";
|
|
13
53
|
fontSize?: number;
|
|
14
54
|
fontWeight?: string;
|
|
@@ -21,7 +61,7 @@ export type TextElementProps = BaseBoxProps & {
|
|
|
21
61
|
};
|
|
22
62
|
|
|
23
63
|
export const TextElementPropsSchema = BaseBoxPropsSchema.extend({
|
|
24
|
-
content: z.string(),
|
|
64
|
+
content: z.union([z.string(), z.array(TextSpanSchema)]),
|
|
25
65
|
mode: z.enum(["plain", "expression"]).optional(),
|
|
26
66
|
fontSize: z.number().optional(),
|
|
27
67
|
fontWeight: z.string().optional(),
|
|
@@ -33,6 +73,46 @@ export const TextElementPropsSchema = BaseBoxPropsSchema.extend({
|
|
|
33
73
|
lineHeight: z.number().optional(),
|
|
34
74
|
});
|
|
35
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Renders one inline span. Isolated as its own component so the
|
|
78
|
+
* `useResolvedFontStyle` hook is called once per stable component instance —
|
|
79
|
+
* calling the hook in a `.map` loop inside the parent would break rules of
|
|
80
|
+
* hooks when the span count changes.
|
|
81
|
+
*/
|
|
82
|
+
const RichTextSpan = ({
|
|
83
|
+
span,
|
|
84
|
+
baseFontFamily,
|
|
85
|
+
}: {
|
|
86
|
+
span: TextSpan;
|
|
87
|
+
baseFontFamily: string | undefined;
|
|
88
|
+
}): React.ReactElement => {
|
|
89
|
+
const fontFamily = resolveInheritedFontFamily(span.fontFamily, baseFontFamily);
|
|
90
|
+
const resolved = useResolvedFontStyle(fontFamily, span.fontWeight);
|
|
91
|
+
return (
|
|
92
|
+
<Text
|
|
93
|
+
style={{
|
|
94
|
+
fontFamily: resolved.fontFamily,
|
|
95
|
+
fontWeight: resolved.resolvedToVariant
|
|
96
|
+
? undefined
|
|
97
|
+
: (span.fontWeight as any),
|
|
98
|
+
fontStyle: span.fontStyle,
|
|
99
|
+
fontSize: span.fontSize,
|
|
100
|
+
letterSpacing: span.letterSpacing,
|
|
101
|
+
lineHeight: span.lineHeight,
|
|
102
|
+
color: span.color,
|
|
103
|
+
backgroundColor: span.backgroundColor,
|
|
104
|
+
opacity: span.opacity,
|
|
105
|
+
textTransform: span.textTransform,
|
|
106
|
+
textDecorationLine: span.textDecorationLine,
|
|
107
|
+
textDecorationColor: span.textDecorationColor,
|
|
108
|
+
textDecorationStyle: span.textDecorationStyle,
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
{span.text}
|
|
112
|
+
</Text>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
36
116
|
type TextUIElement = Extract<UIElement, { type: "Text" }>;
|
|
37
117
|
|
|
38
118
|
type Props = {
|
|
@@ -44,8 +124,12 @@ type Props = {
|
|
|
44
124
|
export const TextElementComponent = ({ element, ctx, parentType }: Props): React.ReactElement => {
|
|
45
125
|
const { theme, variables } = ctx;
|
|
46
126
|
const p = element.props;
|
|
47
|
-
const
|
|
48
|
-
|
|
127
|
+
const isExpression = p.mode === "expression";
|
|
128
|
+
const content: string | TextSpan[] = Array.isArray(p.content)
|
|
129
|
+
? isExpression
|
|
130
|
+
? p.content.map((s) => ({ ...s, text: interpolate(s.text, variables) }))
|
|
131
|
+
: p.content
|
|
132
|
+
: isExpression
|
|
49
133
|
? interpolate(p.content, variables)
|
|
50
134
|
: p.content;
|
|
51
135
|
const inheritedFontFamily = resolveInheritedFontFamily(
|
|
@@ -88,7 +172,11 @@ export const TextElementComponent = ({ element, ctx, parentType }: Props): React
|
|
|
88
172
|
opacity: p.backgroundGradient ? undefined : p.opacity,
|
|
89
173
|
}}
|
|
90
174
|
>
|
|
91
|
-
{content
|
|
175
|
+
{typeof content === "string"
|
|
176
|
+
? content
|
|
177
|
+
: content.map((s, i) => (
|
|
178
|
+
<RichTextSpan key={i} span={s} baseFontFamily={inheritedFontFamily} />
|
|
179
|
+
))}
|
|
92
180
|
</Text>
|
|
93
181
|
);
|
|
94
182
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as Reanimated from "react-native-reanimated";
|
|
2
|
+
import { Easing } from "react-native-reanimated";
|
|
3
|
+
import type {
|
|
4
|
+
AnimationEasing,
|
|
5
|
+
EnteringAnimation,
|
|
6
|
+
ExitingAnimation,
|
|
7
|
+
LayoutAnimation,
|
|
8
|
+
} from "@rocapine/react-native-onboarding";
|
|
9
|
+
|
|
10
|
+
// CSS-style cubic-bezier curves matching the selectable easing names. Shared by
|
|
11
|
+
// the animation builders here and by ProgressIndicatorElement (single source).
|
|
12
|
+
export const EASING_MAP: Record<
|
|
13
|
+
AnimationEasing,
|
|
14
|
+
ReturnType<typeof Easing.bezier> | typeof Easing.linear
|
|
15
|
+
> = {
|
|
16
|
+
linear: Easing.linear,
|
|
17
|
+
"ease-in": Easing.bezier(0.42, 0, 1, 1),
|
|
18
|
+
"ease-out": Easing.bezier(0, 0, 0.58, 1),
|
|
19
|
+
"ease-in-out": Easing.bezier(0.42, 0, 0.58, 1),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Reanimated builders are exported by name off the namespace. Looking them up by
|
|
23
|
+
// the schema's `preset` string is what keeps the JSON 1:1 with reanimated — the
|
|
24
|
+
// preset value *is* the builder name. Unknown/typo presets degrade to `undefined`
|
|
25
|
+
// (no animation) instead of crashing, so a payload referencing a preset the host's
|
|
26
|
+
// installed reanimated version lacks still mounts.
|
|
27
|
+
type AnyBuilder = any;
|
|
28
|
+
|
|
29
|
+
const resolveBuilder = (preset: string): AnyBuilder | undefined => {
|
|
30
|
+
const b = (Reanimated as unknown as Record<string, AnyBuilder>)[preset];
|
|
31
|
+
return b ?? undefined;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const applySpringOrEasing = (
|
|
35
|
+
builder: AnyBuilder,
|
|
36
|
+
spring?: { damping?: number; stiffness?: number; mass?: number },
|
|
37
|
+
easing?: AnimationEasing
|
|
38
|
+
): AnyBuilder => {
|
|
39
|
+
// reanimated: `spring` (`.springify()`) and `.easing()` are mutually exclusive.
|
|
40
|
+
// Spring wins, matching the schema contract.
|
|
41
|
+
if (spring) {
|
|
42
|
+
let b = builder.springify();
|
|
43
|
+
if (spring.damping != null) b = b.damping(spring.damping);
|
|
44
|
+
if (spring.stiffness != null) b = b.stiffness(spring.stiffness);
|
|
45
|
+
if (spring.mass != null) b = b.mass(spring.mass);
|
|
46
|
+
return b;
|
|
47
|
+
}
|
|
48
|
+
if (easing) return builder.easing(EASING_MAP[easing]);
|
|
49
|
+
return builder;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const buildTransition = (
|
|
53
|
+
cfg: EnteringAnimation | ExitingAnimation | undefined
|
|
54
|
+
): AnyBuilder | undefined => {
|
|
55
|
+
if (!cfg) return undefined;
|
|
56
|
+
let b = resolveBuilder(cfg.preset);
|
|
57
|
+
if (!b) return undefined;
|
|
58
|
+
if (cfg.duration != null) b = b.duration(cfg.duration);
|
|
59
|
+
if (cfg.delay != null) b = b.delay(cfg.delay);
|
|
60
|
+
return applySpringOrEasing(b, cfg.spring, cfg.easing);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const buildEntering = (cfg: EnteringAnimation | undefined): AnyBuilder | undefined =>
|
|
64
|
+
buildTransition(cfg);
|
|
65
|
+
|
|
66
|
+
export const buildExiting = (cfg: ExitingAnimation | undefined): AnyBuilder | undefined =>
|
|
67
|
+
buildTransition(cfg);
|
|
68
|
+
|
|
69
|
+
export const buildLayout = (cfg: LayoutAnimation | undefined): AnyBuilder | undefined => {
|
|
70
|
+
if (!cfg) return undefined;
|
|
71
|
+
let b = resolveBuilder(cfg.preset);
|
|
72
|
+
if (!b) return undefined;
|
|
73
|
+
// Layout transitions are referenced as static builder objects; calling a
|
|
74
|
+
// modifier returns a configured instance.
|
|
75
|
+
if (cfg.duration != null) b = b.duration(cfg.duration);
|
|
76
|
+
if (cfg.spring) {
|
|
77
|
+
b = b.springify();
|
|
78
|
+
if (cfg.spring.damping != null) b = b.damping(cfg.spring.damping);
|
|
79
|
+
if (cfg.spring.stiffness != null) b = b.stiffness(cfg.spring.stiffness);
|
|
80
|
+
if (cfg.spring.mass != null) b = b.mass(cfg.spring.mass);
|
|
81
|
+
}
|
|
82
|
+
return b;
|
|
83
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { evaluateCondition } from "@rocapine/react-native-onboarding";
|
|
3
3
|
import { UIElement } from "../types";
|
|
4
|
+
import { BaseBoxProps } from "./BaseBoxProps";
|
|
4
5
|
import { RenderContext } from "./shared";
|
|
5
6
|
import { StackElementComponent } from "./StackElement";
|
|
6
7
|
import { TextElementComponent } from "./TextElement";
|
|
@@ -21,6 +22,7 @@ import { SafeAreaViewElementComponent } from "./SafeAreaViewElement";
|
|
|
21
22
|
import { ScrollViewElementComponent } from "./ScrollViewElement";
|
|
22
23
|
import { KeyboardAvoidingViewElementComponent } from "./KeyboardAvoidingViewElement";
|
|
23
24
|
import { ProgressIndicatorElementComponent } from "./ProgressIndicatorElement";
|
|
25
|
+
import { AnimatedBox } from "./AnimatedBox";
|
|
24
26
|
|
|
25
27
|
export const renderElement = (
|
|
26
28
|
element: UIElement,
|
|
@@ -34,6 +36,9 @@ export const renderElement = (
|
|
|
34
36
|
if (!evaluateCondition(element.renderWhen, flatVars)) return null;
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
// Dispatch to the concrete element renderer. Captured into `node` so a single
|
|
40
|
+
// AnimatedBox wrapper can apply animation/transform to any of the 15 types.
|
|
41
|
+
const node = ((): React.ReactNode => {
|
|
37
42
|
if (element.type === "YStack" || element.type === "XStack") {
|
|
38
43
|
return <StackElementComponent key={element.id} element={element} ctx={ctx} parentType={parentType} />;
|
|
39
44
|
}
|
|
@@ -110,5 +115,27 @@ export const renderElement = (
|
|
|
110
115
|
return <ProgressIndicatorElementComponent key={element.id} element={element} ctx={ctx} />;
|
|
111
116
|
}
|
|
112
117
|
|
|
113
|
-
|
|
118
|
+
return null;
|
|
119
|
+
})();
|
|
120
|
+
|
|
121
|
+
// Wrap only when motion is requested — zero overhead (no extra view) otherwise.
|
|
122
|
+
// Cast to BaseBoxProps: not every element's props type extends it (e.g.
|
|
123
|
+
// WheelPicker), but the animation/transform/flex/alignSelf fields are all
|
|
124
|
+
// optional BaseBoxProps members and simply read as undefined when absent.
|
|
125
|
+
const p = element.props as BaseBoxProps;
|
|
126
|
+
if (node !== null && (p.animation || p.transform)) {
|
|
127
|
+
return (
|
|
128
|
+
<AnimatedBox
|
|
129
|
+
key={element.id}
|
|
130
|
+
animation={p.animation}
|
|
131
|
+
transform={p.transform}
|
|
132
|
+
flex={p.flex}
|
|
133
|
+
alignSelf={p.alignSelf}
|
|
134
|
+
>
|
|
135
|
+
{node}
|
|
136
|
+
</AnimatedBox>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return node;
|
|
114
141
|
};
|