@rocapine/react-native-onboarding-ui 1.38.1 → 1.39.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.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedBox.js +9 -3
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedBox.js.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedTextElement.d.ts +319 -0
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedTextElement.d.ts.map +1 -0
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedTextElement.js +173 -0
- package/dist/UI/Pages/ComposableScreen/elements/AnimatedTextElement.js.map +1 -0
- package/dist/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.js +31 -21
- package/dist/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.js.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/renderElement.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/elements/renderElement.js +4 -0
- package/dist/UI/Pages/ComposableScreen/elements/renderElement.js.map +1 -1
- package/dist/UI/Pages/ComposableScreen/types.d.ts +8 -0
- package/dist/UI/Pages/ComposableScreen/types.d.ts.map +1 -1
- package/dist/UI/Pages/ComposableScreen/types.js +8 -0
- package/dist/UI/Pages/ComposableScreen/types.js.map +1 -1
- package/package.json +1 -1
- package/src/UI/Pages/ComposableScreen/elements/AnimatedBox.tsx +9 -3
- package/src/UI/Pages/ComposableScreen/elements/AnimatedTextElement.tsx +191 -0
- package/src/UI/Pages/ComposableScreen/elements/ProgressIndicatorElement.tsx +51 -28
- package/src/UI/Pages/ComposableScreen/elements/renderElement.tsx +5 -0
- package/src/UI/Pages/ComposableScreen/types.ts +19 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React, { useEffect
|
|
2
|
-
import { View,
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { View, TextInput } from "react-native";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import Animated, {
|
|
5
5
|
useSharedValue,
|
|
@@ -67,6 +67,11 @@ export const ProgressIndicatorElementPropsSchema = BaseBoxPropsSchema.extend({
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
|
70
|
+
// Native TextInput label driven from a worklet (like AnimatedText) so the
|
|
71
|
+
// `showLabel` value updates on the UI thread with NO React re-render — a
|
|
72
|
+
// `useState` label would re-render this component on every step hop and churn
|
|
73
|
+
// the reanimated mapper scheduler (destabilizing other on-screen animations).
|
|
74
|
+
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
|
|
70
75
|
|
|
71
76
|
const clamp = (n: number, min: number, max: number): number => Math.max(min, Math.min(max, n));
|
|
72
77
|
|
|
@@ -98,11 +103,6 @@ export const ProgressIndicatorElementComponent = ({ element, ctx }: Props): Reac
|
|
|
98
103
|
const trackColor = props.trackColor ?? theme.colors.neutral.lower;
|
|
99
104
|
const labelColor = props.labelColor ?? theme.colors.text.primary;
|
|
100
105
|
|
|
101
|
-
// Snap a raw value to `step` within [minValue, maxValue]. The label and the
|
|
102
|
-
// written variable carry the snapped value, not a percentage.
|
|
103
|
-
const snap = (v: number): number =>
|
|
104
|
-
clamp(minValue + Math.round((v - minValue) / step) * step, minValue, maxValue);
|
|
105
|
-
|
|
106
106
|
// Bound variable value (input mode, non-autoplay) or static value. `progress`
|
|
107
107
|
// is the value in [minValue, maxValue]; the fill fraction is derived from it.
|
|
108
108
|
const boundRaw = props.variableName ? variables[props.variableName]?.value : undefined;
|
|
@@ -110,9 +110,10 @@ export const ProgressIndicatorElementComponent = ({ element, ctx }: Props): Reac
|
|
|
110
110
|
const target = autoplay ? maxValue : clamp(boundValue ?? props.value ?? initialValue, minValue, maxValue);
|
|
111
111
|
|
|
112
112
|
const progress = useSharedValue(initialValue);
|
|
113
|
-
const [displayValue, setDisplayValue] = useState(snap(initialValue));
|
|
114
113
|
|
|
115
|
-
//
|
|
114
|
+
// (autoplay) Write the step-snapped value to the bound variable. The label is
|
|
115
|
+
// rendered natively (see labelAnimatedProps below), so it does NOT go through
|
|
116
|
+
// React state — this reaction's ONLY job is the variable write.
|
|
116
117
|
// Reaction input is the *step-snapped* value, so the JS callback fires only
|
|
117
118
|
// when the snapped value changes ((maxValue-minValue)/step hops/sweep) rather
|
|
118
119
|
// than every frame — avoids a per-frame context write storm (setVariable
|
|
@@ -126,15 +127,11 @@ export const ProgressIndicatorElementComponent = ({ element, ctx }: Props): Reac
|
|
|
126
127
|
};
|
|
127
128
|
const writesVariable = autoplay && !!variableName;
|
|
128
129
|
// The dependency array is REQUIRED. Without it reanimated tears down and
|
|
129
|
-
// rebuilds this mapper on EVERY render
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
// Recreating also resets `prev` to undefined, defeating the `snapped === prev`
|
|
135
|
-
// guard so the JS callbacks over-fire. Keying on the values the worklet branches
|
|
136
|
-
// on (incl. minValue/maxValue/step) keeps the mapper stable; the JS fns it calls
|
|
137
|
-
// (setDisplayValue, setVariable via writeVariable) are already stable across renders.
|
|
130
|
+
// rebuilds this mapper on EVERY render, resetting `prev` to undefined and
|
|
131
|
+
// defeating the `snapped === prev` guard so the JS callback over-fires.
|
|
132
|
+
// Keying on the values the worklet branches on (minValue/maxValue/step) keeps
|
|
133
|
+
// the mapper stable; the JS fn it calls (setVariable via writeVariable) is
|
|
134
|
+
// already stable across renders.
|
|
138
135
|
useAnimatedReaction(
|
|
139
136
|
() => {
|
|
140
137
|
// Inline snap (worklet — can't call the JS `snap` closure). Captures the
|
|
@@ -144,12 +141,23 @@ export const ProgressIndicatorElementComponent = ({ element, ctx }: Props): Reac
|
|
|
144
141
|
},
|
|
145
142
|
(snapped, prev) => {
|
|
146
143
|
if (snapped === prev) return;
|
|
147
|
-
if (showLabel) runOnJS(setDisplayValue)(snapped);
|
|
148
144
|
if (writesVariable) runOnJS(writeVariable)(snapped);
|
|
149
145
|
},
|
|
150
|
-
[
|
|
146
|
+
[writesVariable, variableName, minValue, maxValue, step]
|
|
151
147
|
);
|
|
152
148
|
|
|
149
|
+
// Native label text, formatted on the UI thread (snapped value + suffix).
|
|
150
|
+
// Mirrors AnimatedText: returns `defaultValue` too so a re-render reconcile
|
|
151
|
+
// can't revert the uncontrolled TextInput to a stale mount-time value.
|
|
152
|
+
const labelAnimatedProps = useAnimatedProps(() => {
|
|
153
|
+
const snapped = Math.max(
|
|
154
|
+
minValue,
|
|
155
|
+
Math.min(maxValue, minValue + Math.round((progress.value - minValue) / step) * step)
|
|
156
|
+
);
|
|
157
|
+
const t = `${snapped}${labelSuffix}`;
|
|
158
|
+
return { text: t, defaultValue: t } as object;
|
|
159
|
+
}, [minValue, maxValue, step, labelSuffix]);
|
|
160
|
+
|
|
153
161
|
// Autoplay: animate initialValue -> maxValue, optionally looping, after `delay`.
|
|
154
162
|
useEffect(() => {
|
|
155
163
|
if (!autoplay) return;
|
|
@@ -231,16 +239,24 @@ export const ProgressIndicatorElementComponent = ({ element, ctx }: Props): Reac
|
|
|
231
239
|
</Svg>
|
|
232
240
|
{props.showLabel ? (
|
|
233
241
|
<View style={{ position: "absolute", alignItems: "center", justifyContent: "center" }}>
|
|
234
|
-
<
|
|
242
|
+
<AnimatedTextInput
|
|
243
|
+
editable={false}
|
|
244
|
+
pointerEvents="none"
|
|
245
|
+
caretHidden
|
|
246
|
+
contextMenuHidden
|
|
247
|
+
underlineColorAndroid="transparent"
|
|
248
|
+
accessibilityRole="text"
|
|
249
|
+
animatedProps={labelAnimatedProps}
|
|
235
250
|
style={{
|
|
251
|
+
padding: 0,
|
|
252
|
+
includeFontPadding: false,
|
|
253
|
+
textAlign: "center",
|
|
236
254
|
color: labelColor,
|
|
237
255
|
fontSize: theme.typography.textStyles.heading2.fontSize,
|
|
238
256
|
fontWeight: theme.typography.fontWeight.bold,
|
|
239
257
|
fontFamily: theme.typography.textStyles.heading2.fontFamily,
|
|
240
258
|
}}
|
|
241
|
-
|
|
242
|
-
{displayValue}{labelSuffix}
|
|
243
|
-
</Text>
|
|
259
|
+
/>
|
|
244
260
|
</View>
|
|
245
261
|
) : null}
|
|
246
262
|
</View>
|
|
@@ -269,8 +285,17 @@ export const ProgressIndicatorElementComponent = ({ element, ctx }: Props): Reac
|
|
|
269
285
|
/>
|
|
270
286
|
</View>
|
|
271
287
|
{props.showLabel ? (
|
|
272
|
-
<
|
|
288
|
+
<AnimatedTextInput
|
|
289
|
+
editable={false}
|
|
290
|
+
pointerEvents="none"
|
|
291
|
+
caretHidden
|
|
292
|
+
contextMenuHidden
|
|
293
|
+
underlineColorAndroid="transparent"
|
|
294
|
+
accessibilityRole="text"
|
|
295
|
+
animatedProps={labelAnimatedProps}
|
|
273
296
|
style={{
|
|
297
|
+
padding: 0,
|
|
298
|
+
includeFontPadding: false,
|
|
274
299
|
marginLeft: 12,
|
|
275
300
|
color: labelColor,
|
|
276
301
|
fontSize: theme.typography.textStyles.label.fontSize,
|
|
@@ -279,9 +304,7 @@ export const ProgressIndicatorElementComponent = ({ element, ctx }: Props): Reac
|
|
|
279
304
|
minWidth: 44,
|
|
280
305
|
textAlign: "right",
|
|
281
306
|
}}
|
|
282
|
-
|
|
283
|
-
{displayValue}{labelSuffix}
|
|
284
|
-
</Text>
|
|
307
|
+
/>
|
|
285
308
|
) : null}
|
|
286
309
|
</View>
|
|
287
310
|
);
|
|
@@ -26,6 +26,7 @@ import { SafeAreaViewElementComponent } from "./SafeAreaViewElement";
|
|
|
26
26
|
import { ScrollViewElementComponent } from "./ScrollViewElement";
|
|
27
27
|
import { KeyboardAvoidingViewElementComponent } from "./KeyboardAvoidingViewElement";
|
|
28
28
|
import { ProgressIndicatorElementComponent } from "./ProgressIndicatorElement";
|
|
29
|
+
import { AnimatedTextElementComponent } from "./AnimatedTextElement";
|
|
29
30
|
import { AnimatedBox } from "./AnimatedBox";
|
|
30
31
|
|
|
31
32
|
// Element types that own their own press / focus / scroll handling. The generic
|
|
@@ -137,6 +138,10 @@ export const renderElement = (
|
|
|
137
138
|
return <ProgressIndicatorElementComponent key={element.id} element={element} ctx={ctx} />;
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
if (element.type === "AnimatedText") {
|
|
142
|
+
return <AnimatedTextElementComponent key={element.id} element={element} ctx={ctx} />;
|
|
143
|
+
}
|
|
144
|
+
|
|
140
145
|
return null;
|
|
141
146
|
})();
|
|
142
147
|
|
|
@@ -37,6 +37,10 @@ import {
|
|
|
37
37
|
type ProgressIndicatorElementProps,
|
|
38
38
|
ProgressIndicatorElementPropsSchema,
|
|
39
39
|
} from "./elements/ProgressIndicatorElement";
|
|
40
|
+
import {
|
|
41
|
+
type AnimatedTextElementProps,
|
|
42
|
+
AnimatedTextElementPropsSchema,
|
|
43
|
+
} from "./elements/AnimatedTextElement";
|
|
40
44
|
|
|
41
45
|
export type { BaseBoxProps } from "./elements/BaseBoxProps";
|
|
42
46
|
export { BaseBoxPropsSchema } from "./elements/BaseBoxProps";
|
|
@@ -70,6 +74,7 @@ export type {
|
|
|
70
74
|
KeyboardAvoidingBehavior,
|
|
71
75
|
} from "./elements/KeyboardAvoidingViewElement";
|
|
72
76
|
export type { ProgressIndicatorElementProps, ProgressEasing } from "./elements/ProgressIndicatorElement";
|
|
77
|
+
export type { AnimatedTextElementProps } from "./elements/AnimatedTextElement";
|
|
73
78
|
|
|
74
79
|
// UIElement union — must live here (not in elements/) to avoid circular deps
|
|
75
80
|
// because the Stack variant's children: UIElement[] references itself.
|
|
@@ -227,6 +232,13 @@ export type UIElement =
|
|
|
227
232
|
renderWhen?: LeafCondition | ConditionGroup;
|
|
228
233
|
type: "ProgressIndicator";
|
|
229
234
|
props: ProgressIndicatorElementProps;
|
|
235
|
+
}
|
|
236
|
+
| {
|
|
237
|
+
id: string;
|
|
238
|
+
name?: string;
|
|
239
|
+
renderWhen?: LeafCondition | ConditionGroup;
|
|
240
|
+
type: "AnimatedText";
|
|
241
|
+
props: AnimatedTextElementProps;
|
|
230
242
|
};
|
|
231
243
|
|
|
232
244
|
// The `Text` variant, extracted so `RichText` can restrict its children to
|
|
@@ -390,6 +402,13 @@ export const UIElementSchema: z.ZodType<UIElement> = z.lazy(() =>
|
|
|
390
402
|
type: z.literal("ProgressIndicator"),
|
|
391
403
|
props: ProgressIndicatorElementPropsSchema,
|
|
392
404
|
}),
|
|
405
|
+
z.object({
|
|
406
|
+
id: z.string(),
|
|
407
|
+
name: z.string().optional(),
|
|
408
|
+
renderWhen: z.union([LeafConditionSchema, ConditionGroupSchema]).optional(),
|
|
409
|
+
type: z.literal("AnimatedText"),
|
|
410
|
+
props: AnimatedTextElementPropsSchema,
|
|
411
|
+
}),
|
|
393
412
|
])
|
|
394
413
|
);
|
|
395
414
|
|