@react-native-motion-kit/text-motion 0.0.0-stage → 0.1.1
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/CHANGELOG.md +14 -0
- package/LICENSE +20 -0
- package/README.ko.md +104 -0
- package/README.md +103 -2
- package/lib/module/accessibility/index.js +4 -0
- package/lib/module/accessibility/index.js.map +1 -0
- package/lib/module/accessibility/policies.js +39 -0
- package/lib/module/accessibility/policies.js.map +1 -0
- package/lib/module/controls/brand.js +4 -0
- package/lib/module/controls/brand.js.map +1 -0
- package/lib/module/controls/controls.js +28 -0
- package/lib/module/controls/controls.js.map +1 -0
- package/lib/module/controls/descriptors.js +55 -0
- package/lib/module/controls/descriptors.js.map +1 -0
- package/lib/module/controls/index.js +4 -0
- package/lib/module/controls/index.js.map +1 -0
- package/lib/module/effects/compose.js +48 -0
- package/lib/module/effects/compose.js.map +1 -0
- package/lib/module/effects/fade.js +15 -0
- package/lib/module/effects/fade.js.map +1 -0
- package/lib/module/effects/index.js +12 -0
- package/lib/module/effects/index.js.map +1 -0
- package/lib/module/effects/lineReveal.js +17 -0
- package/lib/module/effects/lineReveal.js.map +1 -0
- package/lib/module/effects/pulse.js +14 -0
- package/lib/module/effects/pulse.js.map +1 -0
- package/lib/module/effects/rise.js +14 -0
- package/lib/module/effects/rise.js.map +1 -0
- package/lib/module/effects/scale.js +15 -0
- package/lib/module/effects/scale.js.map +1 -0
- package/lib/module/effects/shake.js +14 -0
- package/lib/module/effects/shake.js.map +1 -0
- package/lib/module/effects/slide.js +15 -0
- package/lib/module/effects/slide.js.map +1 -0
- package/lib/module/effects/typewriter.js +19 -0
- package/lib/module/effects/typewriter.js.map +1 -0
- package/lib/module/effects/validation.js +10 -0
- package/lib/module/effects/validation.js.map +1 -0
- package/lib/module/index.js +10 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/presets/index.js +35 -0
- package/lib/module/presets/index.js.map +1 -0
- package/lib/module/recipe/component.js +60 -0
- package/lib/module/recipe/component.js.map +1 -0
- package/lib/module/recipe/defineTextMotion.js +9 -0
- package/lib/module/recipe/defineTextMotion.js.map +1 -0
- package/lib/module/recipe/descriptors.js +60 -0
- package/lib/module/recipe/descriptors.js.map +1 -0
- package/lib/module/recipe/index.js +5 -0
- package/lib/module/recipe/index.js.map +1 -0
- package/lib/module/recipe/recipe.js +163 -0
- package/lib/module/recipe/recipe.js.map +1 -0
- package/lib/module/renderers/index.js +5 -0
- package/lib/module/renderers/index.js.map +1 -0
- package/lib/module/renderers/nativeText.js +494 -0
- package/lib/module/renderers/nativeText.js.map +1 -0
- package/lib/module/renderers/nativeTextControls.js +96 -0
- package/lib/module/renderers/nativeTextControls.js.map +1 -0
- package/lib/module/renderers/nativeTextLineLayout.js +290 -0
- package/lib/module/renderers/nativeTextLineLayout.js.map +1 -0
- package/lib/module/renderers/nativeTextPlayback.js +91 -0
- package/lib/module/renderers/nativeTextPlayback.js.map +1 -0
- package/lib/module/renderers/overlayText.js +543 -0
- package/lib/module/renderers/overlayText.js.map +1 -0
- package/lib/module/renderers/overlayTextLayout.js +182 -0
- package/lib/module/renderers/overlayTextLayout.js.map +1 -0
- package/lib/module/renderers/rendererMotion.js +264 -0
- package/lib/module/renderers/rendererMotion.js.map +1 -0
- package/lib/module/split/createToken.js +19 -0
- package/lib/module/split/createToken.js.map +1 -0
- package/lib/module/split/custom.js +57 -0
- package/lib/module/split/custom.js.map +1 -0
- package/lib/module/split/graphemes.js +25 -0
- package/lib/module/split/graphemes.js.map +1 -0
- package/lib/module/split/index.js +7 -0
- package/lib/module/split/index.js.map +1 -0
- package/lib/module/split/lines.js +43 -0
- package/lib/module/split/lines.js.map +1 -0
- package/lib/module/split/segmenter.js +74 -0
- package/lib/module/split/segmenter.js.map +1 -0
- package/lib/module/split/words.js +28 -0
- package/lib/module/split/words.js.map +1 -0
- package/lib/module/timeline/index.js +7 -0
- package/lib/module/timeline/index.js.map +1 -0
- package/lib/module/timeline/parallel.js +21 -0
- package/lib/module/timeline/parallel.js.map +1 -0
- package/lib/module/timeline/sequence.js +18 -0
- package/lib/module/timeline/sequence.js.map +1 -0
- package/lib/module/timeline/stagger.js +43 -0
- package/lib/module/timeline/stagger.js.map +1 -0
- package/lib/module/timeline/validation.js +24 -0
- package/lib/module/timeline/validation.js.map +1 -0
- package/lib/module/timeline/wave.js +25 -0
- package/lib/module/timeline/wave.js.map +1 -0
- package/lib/module/types/index.js +4 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/types/recipe.js +4 -0
- package/lib/module/types/recipe.js.map +1 -0
- package/lib/module/types/renderer.js +27 -0
- package/lib/module/types/renderer.js.map +1 -0
- package/lib/module/types/token.js +2 -0
- package/lib/module/types/token.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/accessibility/index.d.ts +2 -0
- package/lib/typescript/src/accessibility/index.d.ts.map +1 -0
- package/lib/typescript/src/accessibility/policies.d.ts +13 -0
- package/lib/typescript/src/accessibility/policies.d.ts.map +1 -0
- package/lib/typescript/src/controls/brand.d.ts +2 -0
- package/lib/typescript/src/controls/brand.d.ts.map +1 -0
- package/lib/typescript/src/controls/controls.d.ts +28 -0
- package/lib/typescript/src/controls/controls.d.ts.map +1 -0
- package/lib/typescript/src/controls/descriptors.d.ts +14 -0
- package/lib/typescript/src/controls/descriptors.d.ts.map +1 -0
- package/lib/typescript/src/controls/index.d.ts +3 -0
- package/lib/typescript/src/controls/index.d.ts.map +1 -0
- package/lib/typescript/src/effects/compose.d.ts +11 -0
- package/lib/typescript/src/effects/compose.d.ts.map +1 -0
- package/lib/typescript/src/effects/fade.d.ts +10 -0
- package/lib/typescript/src/effects/fade.d.ts.map +1 -0
- package/lib/typescript/src/effects/index.d.ts +10 -0
- package/lib/typescript/src/effects/index.d.ts.map +1 -0
- package/lib/typescript/src/effects/lineReveal.d.ts +11 -0
- package/lib/typescript/src/effects/lineReveal.d.ts.map +1 -0
- package/lib/typescript/src/effects/pulse.d.ts +8 -0
- package/lib/typescript/src/effects/pulse.d.ts.map +1 -0
- package/lib/typescript/src/effects/rise.d.ts +8 -0
- package/lib/typescript/src/effects/rise.d.ts.map +1 -0
- package/lib/typescript/src/effects/scale.d.ts +10 -0
- package/lib/typescript/src/effects/scale.d.ts.map +1 -0
- package/lib/typescript/src/effects/shake.d.ts +8 -0
- package/lib/typescript/src/effects/shake.d.ts.map +1 -0
- package/lib/typescript/src/effects/slide.d.ts +10 -0
- package/lib/typescript/src/effects/slide.d.ts.map +1 -0
- package/lib/typescript/src/effects/typewriter.d.ts +13 -0
- package/lib/typescript/src/effects/typewriter.d.ts.map +1 -0
- package/lib/typescript/src/effects/validation.d.ts +2 -0
- package/lib/typescript/src/effects/validation.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +15 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/presets/index.d.ts +10 -0
- package/lib/typescript/src/presets/index.d.ts.map +1 -0
- package/lib/typescript/src/recipe/component.d.ts +3 -0
- package/lib/typescript/src/recipe/component.d.ts.map +1 -0
- package/lib/typescript/src/recipe/defineTextMotion.d.ts +4 -0
- package/lib/typescript/src/recipe/defineTextMotion.d.ts.map +1 -0
- package/lib/typescript/src/recipe/descriptors.d.ts +15 -0
- package/lib/typescript/src/recipe/descriptors.d.ts.map +1 -0
- package/lib/typescript/src/recipe/index.d.ts +4 -0
- package/lib/typescript/src/recipe/index.d.ts.map +1 -0
- package/lib/typescript/src/recipe/recipe.d.ts +67 -0
- package/lib/typescript/src/recipe/recipe.d.ts.map +1 -0
- package/lib/typescript/src/renderers/index.d.ts +3 -0
- package/lib/typescript/src/renderers/index.d.ts.map +1 -0
- package/lib/typescript/src/renderers/nativeText.d.ts +13 -0
- package/lib/typescript/src/renderers/nativeText.d.ts.map +1 -0
- package/lib/typescript/src/renderers/nativeTextControls.d.ts +16 -0
- package/lib/typescript/src/renderers/nativeTextControls.d.ts.map +1 -0
- package/lib/typescript/src/renderers/nativeTextLineLayout.d.ts +84 -0
- package/lib/typescript/src/renderers/nativeTextLineLayout.d.ts.map +1 -0
- package/lib/typescript/src/renderers/nativeTextPlayback.d.ts +21 -0
- package/lib/typescript/src/renderers/nativeTextPlayback.d.ts.map +1 -0
- package/lib/typescript/src/renderers/overlayText.d.ts +13 -0
- package/lib/typescript/src/renderers/overlayText.d.ts.map +1 -0
- package/lib/typescript/src/renderers/overlayTextLayout.d.ts +36 -0
- package/lib/typescript/src/renderers/overlayTextLayout.d.ts.map +1 -0
- package/lib/typescript/src/renderers/rendererMotion.d.ts +53 -0
- package/lib/typescript/src/renderers/rendererMotion.d.ts.map +1 -0
- package/lib/typescript/src/split/createToken.d.ts +11 -0
- package/lib/typescript/src/split/createToken.d.ts.map +1 -0
- package/lib/typescript/src/split/custom.d.ts +17 -0
- package/lib/typescript/src/split/custom.d.ts.map +1 -0
- package/lib/typescript/src/split/graphemes.d.ts +4 -0
- package/lib/typescript/src/split/graphemes.d.ts.map +1 -0
- package/lib/typescript/src/split/index.d.ts +5 -0
- package/lib/typescript/src/split/index.d.ts.map +1 -0
- package/lib/typescript/src/split/lines.d.ts +4 -0
- package/lib/typescript/src/split/lines.d.ts.map +1 -0
- package/lib/typescript/src/split/segmenter.d.ts +18 -0
- package/lib/typescript/src/split/segmenter.d.ts.map +1 -0
- package/lib/typescript/src/split/words.d.ts +4 -0
- package/lib/typescript/src/split/words.d.ts.map +1 -0
- package/lib/typescript/src/timeline/index.d.ts +5 -0
- package/lib/typescript/src/timeline/index.d.ts.map +1 -0
- package/lib/typescript/src/timeline/parallel.d.ts +4 -0
- package/lib/typescript/src/timeline/parallel.d.ts.map +1 -0
- package/lib/typescript/src/timeline/sequence.d.ts +4 -0
- package/lib/typescript/src/timeline/sequence.d.ts.map +1 -0
- package/lib/typescript/src/timeline/stagger.d.ts +11 -0
- package/lib/typescript/src/timeline/stagger.d.ts.map +1 -0
- package/lib/typescript/src/timeline/validation.d.ts +4 -0
- package/lib/typescript/src/timeline/validation.d.ts.map +1 -0
- package/lib/typescript/src/timeline/wave.d.ts +11 -0
- package/lib/typescript/src/timeline/wave.d.ts.map +1 -0
- package/lib/typescript/src/types/index.d.ts +6 -0
- package/lib/typescript/src/types/index.d.ts.map +1 -0
- package/lib/typescript/src/types/recipe.d.ts +123 -0
- package/lib/typescript/src/types/recipe.d.ts.map +1 -0
- package/lib/typescript/src/types/renderer.d.ts +51 -0
- package/lib/typescript/src/types/renderer.d.ts.map +1 -0
- package/lib/typescript/src/types/token.d.ts +35 -0
- package/lib/typescript/src/types/token.d.ts.map +1 -0
- package/package.json +117 -3
- package/src/accessibility/index.ts +7 -0
- package/src/accessibility/policies.ts +60 -0
- package/src/controls/brand.ts +3 -0
- package/src/controls/controls.ts +41 -0
- package/src/controls/descriptors.ts +83 -0
- package/src/controls/index.ts +2 -0
- package/src/effects/compose.ts +98 -0
- package/src/effects/fade.ts +22 -0
- package/src/effects/index.ts +9 -0
- package/src/effects/lineReveal.ts +28 -0
- package/src/effects/pulse.ts +19 -0
- package/src/effects/rise.ts +19 -0
- package/src/effects/scale.ts +22 -0
- package/src/effects/shake.ts +19 -0
- package/src/effects/slide.ts +22 -0
- package/src/effects/typewriter.ts +16 -0
- package/src/effects/validation.ts +9 -0
- package/src/index.tsx +46 -0
- package/src/presets/index.ts +42 -0
- package/src/recipe/component.tsx +88 -0
- package/src/recipe/defineTextMotion.ts +6 -0
- package/src/recipe/descriptors.ts +158 -0
- package/src/recipe/index.ts +3 -0
- package/src/recipe/recipe.ts +359 -0
- package/src/renderers/index.ts +2 -0
- package/src/renderers/nativeText.tsx +813 -0
- package/src/renderers/nativeTextControls.ts +131 -0
- package/src/renderers/nativeTextLineLayout.ts +495 -0
- package/src/renderers/nativeTextPlayback.ts +204 -0
- package/src/renderers/overlayText.tsx +945 -0
- package/src/renderers/overlayTextLayout.ts +312 -0
- package/src/renderers/rendererMotion.ts +483 -0
- package/src/split/createToken.ts +26 -0
- package/src/split/custom.ts +92 -0
- package/src/split/graphemes.ts +27 -0
- package/src/split/index.ts +9 -0
- package/src/split/lines.ts +35 -0
- package/src/split/segmenter.ts +111 -0
- package/src/split/words.ts +28 -0
- package/src/timeline/index.ts +4 -0
- package/src/timeline/parallel.ts +30 -0
- package/src/timeline/sequence.ts +29 -0
- package/src/timeline/stagger.ts +60 -0
- package/src/timeline/validation.ts +29 -0
- package/src/timeline/wave.ts +34 -0
- package/src/types/index.ts +34 -0
- package/src/types/recipe.ts +195 -0
- package/src/types/renderer.ts +91 -0
- package/src/types/token.ts +39 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TextMotionAnyEffect,
|
|
3
|
+
TextMotionAnyEffectDescriptor,
|
|
4
|
+
TextMotionEffect,
|
|
5
|
+
TextMotionEffectDescriptorOptions,
|
|
6
|
+
} from '../types/recipe';
|
|
7
|
+
import type { TextMotionRendererCapability } from '../types/renderer';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
attachTextMotionEffectDescriptor,
|
|
11
|
+
readTextMotionEffectDescriptor,
|
|
12
|
+
} from '../recipe/descriptors';
|
|
13
|
+
|
|
14
|
+
const DEFAULT_EFFECT_OPTIONS: TextMotionEffectDescriptorOptions = {};
|
|
15
|
+
const NATIVE_TEXT_CAPABILITIES: readonly ['native-text'] = ['native-text'];
|
|
16
|
+
|
|
17
|
+
function uniqueCapabilities<Capabilities extends TextMotionRendererCapability>(
|
|
18
|
+
capabilities: readonly Capabilities[],
|
|
19
|
+
): readonly Capabilities[] {
|
|
20
|
+
return Array.from(new Set(capabilities));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Compose multiple effects into one ordered effect. */
|
|
24
|
+
export function composeTextMotionEffects<Capabilities extends TextMotionRendererCapability>(
|
|
25
|
+
effects: readonly TextMotionEffect<Capabilities>[],
|
|
26
|
+
): TextMotionEffect<Capabilities> {
|
|
27
|
+
const descriptors = effects.map(readTextMotionEffectDescriptor);
|
|
28
|
+
const requiredCapabilities = uniqueCapabilities(
|
|
29
|
+
descriptors.flatMap((descriptor) => descriptor.requiredCapabilities),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const composed = {
|
|
33
|
+
and<NextCapabilities extends TextMotionRendererCapability, NextName extends string>(
|
|
34
|
+
effect: TextMotionEffect<NextCapabilities, NextName>,
|
|
35
|
+
) {
|
|
36
|
+
return composeTextMotionEffects<Capabilities | NextCapabilities>([...effects, effect]);
|
|
37
|
+
},
|
|
38
|
+
} as TextMotionEffect<Capabilities>;
|
|
39
|
+
|
|
40
|
+
return attachTextMotionEffectDescriptor<Capabilities, TextMotionEffectDescriptorOptions, string>(
|
|
41
|
+
composed,
|
|
42
|
+
{
|
|
43
|
+
kind: 'effect',
|
|
44
|
+
name: descriptors.map((descriptor) => descriptor.name).join('+'),
|
|
45
|
+
requiredCapabilities,
|
|
46
|
+
effects,
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Create a custom native-text effect without descriptor options. */
|
|
52
|
+
export function createTextMotionEffect<Name extends string>(
|
|
53
|
+
name: Name,
|
|
54
|
+
): TextMotionEffect<'native-text', Name>;
|
|
55
|
+
|
|
56
|
+
/** Create a custom native-text effect with typed descriptor options. */
|
|
57
|
+
export function createTextMotionEffect<
|
|
58
|
+
Name extends string,
|
|
59
|
+
Options extends TextMotionEffectDescriptorOptions,
|
|
60
|
+
>(name: Name, options: Options): TextMotionEffect<'native-text', Name>;
|
|
61
|
+
|
|
62
|
+
/** Create a custom effect with typed descriptor options and renderer capabilities. */
|
|
63
|
+
export function createTextMotionEffect<
|
|
64
|
+
Name extends string,
|
|
65
|
+
Options extends TextMotionEffectDescriptorOptions,
|
|
66
|
+
Capabilities extends TextMotionRendererCapability,
|
|
67
|
+
>(
|
|
68
|
+
name: Name,
|
|
69
|
+
options: Options,
|
|
70
|
+
requiredCapabilities: readonly Capabilities[],
|
|
71
|
+
): TextMotionEffect<Capabilities, Name>;
|
|
72
|
+
|
|
73
|
+
/** Create a custom text-motion effect for built-in or custom renderers. */
|
|
74
|
+
export function createTextMotionEffect(
|
|
75
|
+
name: string,
|
|
76
|
+
options: TextMotionEffectDescriptorOptions = DEFAULT_EFFECT_OPTIONS,
|
|
77
|
+
requiredCapabilities: readonly TextMotionRendererCapability[] = NATIVE_TEXT_CAPABILITIES,
|
|
78
|
+
): TextMotionAnyEffect {
|
|
79
|
+
const effect = {
|
|
80
|
+
and<NextCapabilities extends TextMotionRendererCapability, NextName extends string>(
|
|
81
|
+
nextEffect: TextMotionEffect<NextCapabilities, NextName>,
|
|
82
|
+
) {
|
|
83
|
+
return composeTextMotionEffects<TextMotionRendererCapability | NextCapabilities>([
|
|
84
|
+
effect,
|
|
85
|
+
nextEffect,
|
|
86
|
+
]);
|
|
87
|
+
},
|
|
88
|
+
} as TextMotionAnyEffect;
|
|
89
|
+
|
|
90
|
+
const descriptor: TextMotionAnyEffectDescriptor = {
|
|
91
|
+
kind: 'effect',
|
|
92
|
+
name,
|
|
93
|
+
options,
|
|
94
|
+
requiredCapabilities,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return attachTextMotionEffectDescriptor(effect, descriptor);
|
|
98
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createTextMotionEffect } from './compose';
|
|
2
|
+
import { validateFiniteEffectNumber } from './validation';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link fade}. */
|
|
5
|
+
export type FadeOptions = {
|
|
6
|
+
/** Starting opacity. Defaults to `0`. */
|
|
7
|
+
from?: number;
|
|
8
|
+
/** Ending opacity. Defaults to `1`. */
|
|
9
|
+
to?: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Fade each token between opacity values. */
|
|
13
|
+
export function fade(options: FadeOptions = {}) {
|
|
14
|
+
return createTextMotionEffect(
|
|
15
|
+
'fade',
|
|
16
|
+
{
|
|
17
|
+
from: validateFiniteEffectNumber(options.from ?? 0, 'fade from'),
|
|
18
|
+
to: validateFiniteEffectNumber(options.to ?? 1, 'fade to'),
|
|
19
|
+
},
|
|
20
|
+
['style-transform'],
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { composeTextMotionEffects, createTextMotionEffect } from './compose';
|
|
2
|
+
export { fade, type FadeOptions } from './fade';
|
|
3
|
+
export { lineReveal, type LineRevealOptions } from './lineReveal';
|
|
4
|
+
export { pulse, type PulseOptions } from './pulse';
|
|
5
|
+
export { rise, type RiseOptions } from './rise';
|
|
6
|
+
export { scale, type ScaleOptions } from './scale';
|
|
7
|
+
export { shake, type ShakeOptions } from './shake';
|
|
8
|
+
export { slide, type SlideOptions } from './slide';
|
|
9
|
+
export { typewriter } from './typewriter';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TextMotionLineMaskCapability } from '../types/renderer';
|
|
2
|
+
|
|
3
|
+
import { createTextMotionRendererCapability } from '../types/renderer';
|
|
4
|
+
import { createTextMotionEffect } from './compose';
|
|
5
|
+
import { validateFiniteEffectNumber } from './validation';
|
|
6
|
+
|
|
7
|
+
const LINE_MASK_CAPABILITY: TextMotionLineMaskCapability =
|
|
8
|
+
createTextMotionRendererCapability('line-mask');
|
|
9
|
+
|
|
10
|
+
/** Options for {@link lineReveal}. */
|
|
11
|
+
export type LineRevealOptions = {
|
|
12
|
+
/** Initial downward offset in points. Defaults to `16`. */
|
|
13
|
+
y?: number;
|
|
14
|
+
/** Initial opacity before each rendered line reveals. Defaults to `0`. */
|
|
15
|
+
fromOpacity?: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** Reveal each React Native rendered line through an `overlayText()` line mask. */
|
|
19
|
+
export function lineReveal(options: LineRevealOptions = {}) {
|
|
20
|
+
return createTextMotionEffect(
|
|
21
|
+
'lineReveal',
|
|
22
|
+
{
|
|
23
|
+
fromOpacity: validateFiniteEffectNumber(options.fromOpacity ?? 0, 'lineReveal fromOpacity'),
|
|
24
|
+
y: validateFiniteEffectNumber(options.y ?? 16, 'lineReveal y'),
|
|
25
|
+
},
|
|
26
|
+
[LINE_MASK_CAPABILITY, 'style-transform'],
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createTextMotionEffect } from './compose';
|
|
2
|
+
import { validateFiniteEffectNumber } from './validation';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link pulse}. */
|
|
5
|
+
export type PulseOptions = {
|
|
6
|
+
/** Peak pulse scale reached around the middle of the motion. Defaults to `1.04`. */
|
|
7
|
+
scale?: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/** Briefly emphasize each token by scaling it up and returning to its final scale. */
|
|
11
|
+
export function pulse(options: PulseOptions = {}) {
|
|
12
|
+
return createTextMotionEffect(
|
|
13
|
+
'pulse',
|
|
14
|
+
{
|
|
15
|
+
scale: validateFiniteEffectNumber(options.scale ?? 1.04, 'pulse scale'),
|
|
16
|
+
},
|
|
17
|
+
['style-transform'],
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createTextMotionEffect } from './compose';
|
|
2
|
+
import { validateFiniteEffectNumber } from './validation';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link rise}. */
|
|
5
|
+
export type RiseOptions = {
|
|
6
|
+
/** Initial downward offset in pixels. Defaults to `12`. */
|
|
7
|
+
y?: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/** Move each token upward from a vertical offset. */
|
|
11
|
+
export function rise(options: RiseOptions = {}) {
|
|
12
|
+
return createTextMotionEffect(
|
|
13
|
+
'rise',
|
|
14
|
+
{
|
|
15
|
+
y: validateFiniteEffectNumber(options.y ?? 12, 'rise y'),
|
|
16
|
+
},
|
|
17
|
+
['style-transform'],
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createTextMotionEffect } from './compose';
|
|
2
|
+
import { validateFiniteEffectNumber } from './validation';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link scale}. */
|
|
5
|
+
export type ScaleOptions = {
|
|
6
|
+
/** Starting scale. Defaults to `0.96`. */
|
|
7
|
+
from?: number;
|
|
8
|
+
/** Ending scale. Defaults to `1`. */
|
|
9
|
+
to?: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Scale each token between two scale values. */
|
|
13
|
+
export function scale(options: ScaleOptions = {}) {
|
|
14
|
+
return createTextMotionEffect(
|
|
15
|
+
'scale',
|
|
16
|
+
{
|
|
17
|
+
from: validateFiniteEffectNumber(options.from ?? 0.96, 'scale from'),
|
|
18
|
+
to: validateFiniteEffectNumber(options.to ?? 1, 'scale to'),
|
|
19
|
+
},
|
|
20
|
+
['style-transform'],
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createTextMotionEffect } from './compose';
|
|
2
|
+
import { validateFiniteEffectNumber } from './validation';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link shake}. */
|
|
5
|
+
export type ShakeOptions = {
|
|
6
|
+
/** Initial horizontal offset in pixels. Defaults to `4`. */
|
|
7
|
+
x?: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/** Offset each token horizontally for a shake-like entrance. */
|
|
11
|
+
export function shake(options: ShakeOptions = {}) {
|
|
12
|
+
return createTextMotionEffect(
|
|
13
|
+
'shake',
|
|
14
|
+
{
|
|
15
|
+
x: validateFiniteEffectNumber(options.x ?? 4, 'shake x'),
|
|
16
|
+
},
|
|
17
|
+
['style-transform'],
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createTextMotionEffect } from './compose';
|
|
2
|
+
import { validateFiniteEffectNumber } from './validation';
|
|
3
|
+
|
|
4
|
+
/** Options for {@link slide}. */
|
|
5
|
+
export type SlideOptions = {
|
|
6
|
+
/** Initial horizontal offset in pixels. Defaults to `0`. */
|
|
7
|
+
x?: number;
|
|
8
|
+
/** Initial vertical offset in pixels. Defaults to `12`. */
|
|
9
|
+
y?: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Move each token from an x/y offset into place. */
|
|
13
|
+
export function slide(options: SlideOptions = {}) {
|
|
14
|
+
return createTextMotionEffect(
|
|
15
|
+
'slide',
|
|
16
|
+
{
|
|
17
|
+
x: validateFiniteEffectNumber(options.x ?? 0, 'slide x'),
|
|
18
|
+
y: validateFiniteEffectNumber(options.y ?? 12, 'slide y'),
|
|
19
|
+
},
|
|
20
|
+
['style-transform'],
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createTextMotionEffect } from './compose';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reveal each native-text token when its local progress becomes positive.
|
|
5
|
+
*
|
|
6
|
+
* Keeps the final token layout in place. Combine with `graphemes()`, `stagger(seconds)`,
|
|
7
|
+
* and `.motion({ kind: 'timing', options: { duration: 0 } })` for instant character reveals.
|
|
8
|
+
* The splitter and timeline determine the reveal units and order; whitespace does not
|
|
9
|
+
* consume a motion index. Other effects retain their own opacity and transforms.
|
|
10
|
+
*
|
|
11
|
+
* External `progress` follows the recipe timeline, not the fraction of visible characters.
|
|
12
|
+
* Decreasing progress can hide tokens again. Requires `nativeText()`.
|
|
13
|
+
*/
|
|
14
|
+
export function typewriter() {
|
|
15
|
+
return createTextMotionEffect('typewriter');
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const ERROR_PREFIX = '@react-native-motion-kit/text-motion';
|
|
2
|
+
|
|
3
|
+
export function validateFiniteEffectNumber(value: number, label: string): number {
|
|
4
|
+
if (Number.isFinite(value)) {
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
throw new Error(`${ERROR_PREFIX} ${label} must be a finite number.`);
|
|
9
|
+
}
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export { parentLabelPolicy } from './accessibility';
|
|
2
|
+
export { useTextMotionControls } from './controls';
|
|
3
|
+
export { fade, lineReveal, pulse, rise, scale, shake, slide, typewriter } from './effects';
|
|
4
|
+
export { defineTextMotion } from './recipe';
|
|
5
|
+
export { nativeText, overlayText } from './renderers';
|
|
6
|
+
export { custom, graphemes, lines, words } from './split';
|
|
7
|
+
export { parallel, sequence, stagger, wave } from './timeline';
|
|
8
|
+
export type { ParentLabelPolicyOptions } from './accessibility';
|
|
9
|
+
export type { TextMotionControls } from './controls';
|
|
10
|
+
export type {
|
|
11
|
+
FadeOptions,
|
|
12
|
+
LineRevealOptions,
|
|
13
|
+
PulseOptions,
|
|
14
|
+
RiseOptions,
|
|
15
|
+
ScaleOptions,
|
|
16
|
+
ShakeOptions,
|
|
17
|
+
SlideOptions,
|
|
18
|
+
} from './effects';
|
|
19
|
+
export type { NativeTextRendererOptions, OverlayTextRendererOptions } from './renderers';
|
|
20
|
+
export type {
|
|
21
|
+
TextMotionCustomSplit,
|
|
22
|
+
TextMotionCustomSplitResult,
|
|
23
|
+
TextMotionCustomSplitToken,
|
|
24
|
+
} from './split';
|
|
25
|
+
export type {
|
|
26
|
+
TextMotionStaggerFrom,
|
|
27
|
+
TextMotionStaggerOptions,
|
|
28
|
+
TextMotionWaveOptions,
|
|
29
|
+
} from './timeline';
|
|
30
|
+
export type {
|
|
31
|
+
TextMotionAccessibilityPolicy,
|
|
32
|
+
TextMotionComponent,
|
|
33
|
+
TextMotionComponentAccessibilityProps,
|
|
34
|
+
TextMotionComponentProps,
|
|
35
|
+
TextMotionComponentTextProps,
|
|
36
|
+
TextMotionEffect,
|
|
37
|
+
TextMotionMotionConfig,
|
|
38
|
+
TextMotionSpringOptions,
|
|
39
|
+
TextMotionTimingOptions,
|
|
40
|
+
TextMotionRenderer,
|
|
41
|
+
TextMotionRendererCapability,
|
|
42
|
+
TextMotionRendererProps,
|
|
43
|
+
TextMotionSplitter,
|
|
44
|
+
TextMotionTimeline,
|
|
45
|
+
TextMotionToken,
|
|
46
|
+
} from './types';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { TextMotionSplitRenderableRecipeBuilder } from '../recipe/recipe';
|
|
2
|
+
|
|
3
|
+
import { fade, pulse, rise, scale } from '../effects';
|
|
4
|
+
import { defineTextMotion } from '../recipe';
|
|
5
|
+
import { nativeText } from '../renderers';
|
|
6
|
+
import { words } from '../split';
|
|
7
|
+
import { stagger, wave } from '../timeline';
|
|
8
|
+
|
|
9
|
+
type NativeTextPresetBuilder = TextMotionSplitRenderableRecipeBuilder<
|
|
10
|
+
'native-text' | 'style-transform'
|
|
11
|
+
>;
|
|
12
|
+
|
|
13
|
+
/** Editorial title reveal with centered stagger, rise, fade, and subtle scale. */
|
|
14
|
+
export function editorialRise(): NativeTextPresetBuilder {
|
|
15
|
+
return defineTextMotion()
|
|
16
|
+
.split(words())
|
|
17
|
+
.layout(nativeText())
|
|
18
|
+
.timeline(stagger(0.032, { from: 'center' }))
|
|
19
|
+
.effect(
|
|
20
|
+
rise({ y: 14 })
|
|
21
|
+
.and(fade())
|
|
22
|
+
.and(scale({ from: 0.98 })),
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Soft wave reveal for friendly product copy. */
|
|
27
|
+
export function softWave(): NativeTextPresetBuilder {
|
|
28
|
+
return defineTextMotion()
|
|
29
|
+
.split(words())
|
|
30
|
+
.layout(nativeText())
|
|
31
|
+
.timeline(wave({ amplitude: 0.06, wavelength: 5 }))
|
|
32
|
+
.effect(fade().and(rise({ y: 8 })));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Gentle emphasis preset for small labels and inline highlight copy. */
|
|
36
|
+
export function gentleEmphasis(): NativeTextPresetBuilder {
|
|
37
|
+
return defineTextMotion()
|
|
38
|
+
.split(words())
|
|
39
|
+
.layout(nativeText())
|
|
40
|
+
.timeline(stagger(0.024))
|
|
41
|
+
.effect(pulse({ scale: 1.06 }).and(fade()));
|
|
42
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TextMotionComponent,
|
|
3
|
+
TextMotionComponentProps,
|
|
4
|
+
TextMotionInternalRecipeConfig,
|
|
5
|
+
TextMotionRendererCapability,
|
|
6
|
+
} from '../types';
|
|
7
|
+
import type { TextMotionToken } from '../types/token';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
flattenTextMotionEffectDescriptors,
|
|
11
|
+
readTextMotionRendererDescriptor,
|
|
12
|
+
readTextMotionSplitterDescriptor,
|
|
13
|
+
} from './descriptors';
|
|
14
|
+
|
|
15
|
+
function validateTextMotionRendererCapabilities(
|
|
16
|
+
recipe: TextMotionInternalRecipeConfig<TextMotionRendererCapability>,
|
|
17
|
+
renderer: ReturnType<typeof readTextMotionRendererDescriptor>,
|
|
18
|
+
): void {
|
|
19
|
+
flattenTextMotionEffectDescriptors(recipe.effects).forEach((effect) => {
|
|
20
|
+
effect.requiredCapabilities.forEach((capability) => {
|
|
21
|
+
if (renderer.capabilities.includes(capability)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
throw new Error(
|
|
26
|
+
`@react-native-motion-kit/text-motion effect "${effect.name}" requires capability "${capability}", but renderer "${renderer.kind}" does not provide it.`,
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createDefaultToken(text: string): TextMotionToken<'custom'> {
|
|
33
|
+
return {
|
|
34
|
+
id: 'token-0',
|
|
35
|
+
index: 0,
|
|
36
|
+
metadata: { reason: 'default-unsplit-token' },
|
|
37
|
+
sourceRange: { start: 0, end: text.length },
|
|
38
|
+
text,
|
|
39
|
+
unit: 'custom',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function createTextMotionComponent(
|
|
44
|
+
recipe: TextMotionInternalRecipeConfig<TextMotionRendererCapability>,
|
|
45
|
+
): TextMotionComponent {
|
|
46
|
+
function TextMotionComponent({ children, ...textProps }: TextMotionComponentProps) {
|
|
47
|
+
if (typeof children !== 'string') {
|
|
48
|
+
throw new Error(
|
|
49
|
+
'@react-native-motion-kit/text-motion expects a string child. Pass plain text or split non-string content before rendering.',
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const splitter = recipe.splitter
|
|
54
|
+
? readTextMotionSplitterDescriptor(recipe.splitter)
|
|
55
|
+
: undefined;
|
|
56
|
+
const renderer = recipe.renderer
|
|
57
|
+
? readTextMotionRendererDescriptor(recipe.renderer)
|
|
58
|
+
: undefined;
|
|
59
|
+
const rendererMotionUnit = renderer?.motionUnit ?? 'source-token';
|
|
60
|
+
|
|
61
|
+
if (recipe.splitter && rendererMotionUnit === 'rendered-line') {
|
|
62
|
+
throw new Error(
|
|
63
|
+
'@react-native-motion-kit/text-motion rendered-line renderers cannot be combined with .split(...). Remove the splitter or choose a source-token renderer such as nativeText().',
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const tokens = splitter ? splitter.split(children) : [createDefaultToken(children)];
|
|
68
|
+
const Renderer = renderer?.Component;
|
|
69
|
+
|
|
70
|
+
if (!Renderer) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
'@react-native-motion-kit/text-motion requires a renderer. Add .layout(nativeText()) or another renderer before .component().',
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
validateTextMotionRendererCapabilities(recipe, renderer);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Renderer recipe={recipe} textProps={textProps} tokens={tokens}>
|
|
80
|
+
{children}
|
|
81
|
+
</Renderer>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
TextMotionComponent.displayName = 'TextMotionComponent';
|
|
86
|
+
|
|
87
|
+
return TextMotionComponent;
|
|
88
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TextMotionAnyEffect,
|
|
3
|
+
TextMotionAnyEffectDescriptor,
|
|
4
|
+
TextMotionAnyTimeline,
|
|
5
|
+
TextMotionAnyTimelineDescriptor,
|
|
6
|
+
TextMotionEffect,
|
|
7
|
+
TextMotionEffectDescriptor,
|
|
8
|
+
TextMotionEffectDescriptorOptions,
|
|
9
|
+
TextMotionTimeline,
|
|
10
|
+
TextMotionTimelineDescriptor,
|
|
11
|
+
TextMotionTimelineDescriptorOptions,
|
|
12
|
+
} from '../types/recipe';
|
|
13
|
+
import type {
|
|
14
|
+
TextMotionRenderer,
|
|
15
|
+
TextMotionRendererCapability,
|
|
16
|
+
TextMotionRendererDescriptor,
|
|
17
|
+
TextMotionRenderedLineRenderer,
|
|
18
|
+
TextMotionSourceTokenRenderer,
|
|
19
|
+
} from '../types/renderer';
|
|
20
|
+
import type {
|
|
21
|
+
TextMotionSplitter,
|
|
22
|
+
TextMotionSplitterDescriptor,
|
|
23
|
+
TextMotionTokenUnit,
|
|
24
|
+
} from '../types/token';
|
|
25
|
+
|
|
26
|
+
const effectDescriptors = new WeakMap<TextMotionAnyEffect, TextMotionAnyEffectDescriptor>();
|
|
27
|
+
const timelineDescriptors = new WeakMap<TextMotionAnyTimeline, TextMotionAnyTimelineDescriptor>();
|
|
28
|
+
const splitterDescriptors = new WeakMap<TextMotionSplitter, TextMotionSplitterDescriptor>();
|
|
29
|
+
const rendererDescriptors = new WeakMap<
|
|
30
|
+
TextMotionRenderer<TextMotionRendererCapability, unknown>,
|
|
31
|
+
TextMotionRendererDescriptor<TextMotionRendererCapability, unknown>
|
|
32
|
+
>();
|
|
33
|
+
|
|
34
|
+
type TextMotionRendererHandle<
|
|
35
|
+
Capabilities extends TextMotionRendererCapability,
|
|
36
|
+
Recipe,
|
|
37
|
+
MotionUnit extends 'source-token' | 'rendered-line',
|
|
38
|
+
> = MotionUnit extends 'rendered-line'
|
|
39
|
+
? TextMotionRenderedLineRenderer<Capabilities, Recipe>
|
|
40
|
+
: TextMotionSourceTokenRenderer<Capabilities, Recipe>;
|
|
41
|
+
|
|
42
|
+
export function attachTextMotionEffectDescriptor<
|
|
43
|
+
RequiredCapabilities extends TextMotionRendererCapability,
|
|
44
|
+
Options extends TextMotionEffectDescriptorOptions,
|
|
45
|
+
Name extends string,
|
|
46
|
+
>(
|
|
47
|
+
effect: TextMotionEffect<RequiredCapabilities, Name>,
|
|
48
|
+
descriptor: TextMotionEffectDescriptor<RequiredCapabilities, Options, Name>,
|
|
49
|
+
): TextMotionEffect<RequiredCapabilities, Name> {
|
|
50
|
+
effectDescriptors.set(effect, descriptor);
|
|
51
|
+
|
|
52
|
+
return effect;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function readTextMotionEffectDescriptor<
|
|
56
|
+
RequiredCapabilities extends TextMotionRendererCapability,
|
|
57
|
+
Name extends string,
|
|
58
|
+
>(
|
|
59
|
+
effect: TextMotionEffect<RequiredCapabilities, Name>,
|
|
60
|
+
): TextMotionEffectDescriptor<RequiredCapabilities, TextMotionEffectDescriptorOptions, Name> {
|
|
61
|
+
const descriptor = effectDescriptors.get(effect);
|
|
62
|
+
|
|
63
|
+
if (descriptor) {
|
|
64
|
+
return descriptor as TextMotionEffectDescriptor<
|
|
65
|
+
RequiredCapabilities,
|
|
66
|
+
TextMotionEffectDescriptorOptions,
|
|
67
|
+
Name
|
|
68
|
+
>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
throw new Error('@react-native-motion-kit/text-motion received an unknown effect handle.');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function flattenTextMotionEffectDescriptors(
|
|
75
|
+
effects: readonly TextMotionAnyEffect[],
|
|
76
|
+
): readonly TextMotionAnyEffectDescriptor[] {
|
|
77
|
+
return effects.flatMap((effect) => {
|
|
78
|
+
const descriptor = readTextMotionEffectDescriptor(effect);
|
|
79
|
+
|
|
80
|
+
return descriptor.effects
|
|
81
|
+
? flattenTextMotionEffectDescriptors(descriptor.effects)
|
|
82
|
+
: [descriptor];
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function createTextMotionTimelineHandle<
|
|
87
|
+
Options extends TextMotionTimelineDescriptorOptions,
|
|
88
|
+
Name extends string,
|
|
89
|
+
>(descriptor: TextMotionTimelineDescriptor<Options, Name>): TextMotionTimeline<Name> {
|
|
90
|
+
const timeline = {} as TextMotionTimeline<Name>;
|
|
91
|
+
timelineDescriptors.set(timeline, descriptor);
|
|
92
|
+
|
|
93
|
+
return timeline;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function readTextMotionTimelineDescriptor(
|
|
97
|
+
timeline: TextMotionAnyTimeline,
|
|
98
|
+
): TextMotionAnyTimelineDescriptor {
|
|
99
|
+
const descriptor = timelineDescriptors.get(timeline);
|
|
100
|
+
|
|
101
|
+
if (descriptor) {
|
|
102
|
+
return descriptor;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
throw new Error('@react-native-motion-kit/text-motion received an unknown timeline handle.');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function createTextMotionSplitterHandle<Unit extends TextMotionTokenUnit>(
|
|
109
|
+
descriptor: TextMotionSplitterDescriptor<Unit>,
|
|
110
|
+
): TextMotionSplitter<Unit> {
|
|
111
|
+
const splitter = {} as TextMotionSplitter<Unit>;
|
|
112
|
+
splitterDescriptors.set(splitter, descriptor);
|
|
113
|
+
|
|
114
|
+
return splitter;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function readTextMotionSplitterDescriptor<Unit extends TextMotionTokenUnit>(
|
|
118
|
+
splitter: TextMotionSplitter<Unit>,
|
|
119
|
+
): TextMotionSplitterDescriptor<Unit> {
|
|
120
|
+
const descriptor = splitterDescriptors.get(splitter);
|
|
121
|
+
|
|
122
|
+
if (descriptor) {
|
|
123
|
+
return descriptor as TextMotionSplitterDescriptor<Unit>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
throw new Error('@react-native-motion-kit/text-motion received an unknown splitter handle.');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function createTextMotionRendererHandle<
|
|
130
|
+
Capabilities extends TextMotionRendererCapability,
|
|
131
|
+
Recipe,
|
|
132
|
+
MotionUnit extends 'source-token' | 'rendered-line' = 'source-token',
|
|
133
|
+
>(
|
|
134
|
+
descriptor: TextMotionRendererDescriptor<Capabilities, Recipe, MotionUnit>,
|
|
135
|
+
): TextMotionRendererHandle<Capabilities, Recipe, MotionUnit> {
|
|
136
|
+
const renderer = {} as TextMotionRendererHandle<Capabilities, Recipe, MotionUnit>;
|
|
137
|
+
rendererDescriptors.set(
|
|
138
|
+
renderer,
|
|
139
|
+
descriptor as TextMotionRendererDescriptor<TextMotionRendererCapability, unknown>,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
return renderer;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function readTextMotionRendererDescriptor<
|
|
146
|
+
Capabilities extends TextMotionRendererCapability,
|
|
147
|
+
Recipe,
|
|
148
|
+
>(
|
|
149
|
+
renderer: TextMotionRenderer<Capabilities, Recipe>,
|
|
150
|
+
): TextMotionRendererDescriptor<Capabilities, Recipe> {
|
|
151
|
+
const descriptor = rendererDescriptors.get(renderer);
|
|
152
|
+
|
|
153
|
+
if (descriptor) {
|
|
154
|
+
return descriptor as TextMotionRendererDescriptor<Capabilities, Recipe>;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
throw new Error('@react-native-motion-kit/text-motion received an unknown renderer handle.');
|
|
158
|
+
}
|