@factorialco/f0-react-native 0.27.0 → 0.28.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/README.md +44 -32
- package/lib/module/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.js +2 -0
- package/lib/module/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.js.map +1 -0
- package/lib/module/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.md +159 -0
- package/lib/module/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.types.js +2 -0
- package/lib/module/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.types.js.map +1 -0
- package/lib/module/components/primitives/F0Text/AnimatedF0Text/index.js +2 -0
- package/lib/module/components/primitives/F0Text/AnimatedF0Text/index.js.map +1 -0
- package/lib/module/components/primitives/F0Text/F0Text/F0Text.js +2 -0
- package/lib/module/components/primitives/F0Text/F0Text/F0Text.js.map +1 -0
- package/{src/components/primitives → lib/module/components/primitives/F0Text}/F0Text/F0Text.md +86 -18
- package/lib/module/components/primitives/F0Text/F0Text/F0Text.styles.js +2 -0
- package/lib/module/components/primitives/F0Text/F0Text/F0Text.styles.js.map +1 -0
- package/lib/module/components/primitives/F0Text/F0Text/F0Text.types.js +2 -0
- package/lib/module/components/primitives/F0Text/F0Text/F0Text.types.js.map +1 -0
- package/lib/module/components/primitives/F0Text/F0Text/index.js +2 -0
- package/lib/module/components/primitives/F0Text/F0Text/index.js.map +1 -0
- package/lib/module/components/primitives/F0Text/index.js +1 -1
- package/lib/module/components/primitives/F0Text/index.js.map +1 -1
- package/lib/module/styles/theme.css +7 -0
- package/lib/typescript/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.d.ts +5 -0
- package/lib/typescript/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.d.ts.map +1 -0
- package/lib/typescript/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.types.d.ts +45 -0
- package/lib/typescript/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.types.d.ts.map +1 -0
- package/lib/typescript/components/primitives/F0Text/AnimatedF0Text/index.d.ts +8 -0
- package/lib/typescript/components/primitives/F0Text/AnimatedF0Text/index.d.ts.map +1 -0
- package/lib/typescript/components/primitives/F0Text/F0Text/F0Text.d.ts.map +1 -0
- package/lib/typescript/components/primitives/F0Text/{F0Text.styles.d.ts → F0Text/F0Text.styles.d.ts} +6 -2
- package/lib/typescript/components/primitives/F0Text/F0Text/F0Text.styles.d.ts.map +1 -0
- package/lib/typescript/components/primitives/F0Text/{F0Text.types.d.ts → F0Text/F0Text.types.d.ts} +1 -1
- package/lib/typescript/components/primitives/F0Text/F0Text/F0Text.types.d.ts.map +1 -0
- package/lib/typescript/components/primitives/F0Text/F0Text/index.d.ts +9 -0
- package/lib/typescript/components/primitives/F0Text/F0Text/index.d.ts.map +1 -0
- package/lib/typescript/components/primitives/F0Text/index.d.ts +5 -2
- package/lib/typescript/components/primitives/F0Text/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.md +159 -0
- package/src/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.tsx +72 -0
- package/src/components/primitives/F0Text/AnimatedF0Text/AnimatedF0Text.types.ts +61 -0
- package/src/components/primitives/F0Text/AnimatedF0Text/__tests__/AnimatedF0Text.spec.tsx +131 -0
- package/src/components/primitives/F0Text/AnimatedF0Text/__tests__/__snapshots__/AnimatedF0Text.spec.tsx.snap +144 -0
- package/src/components/primitives/F0Text/AnimatedF0Text/index.ts +8 -0
- package/{lib/module/components/primitives → src/components/primitives/F0Text}/F0Text/F0Text.md +86 -18
- package/src/components/primitives/F0Text/{F0Text.styles.ts → F0Text/F0Text.styles.ts} +5 -2
- package/src/components/primitives/F0Text/{F0Text.tsx → F0Text/F0Text.tsx} +1 -1
- package/src/components/primitives/F0Text/{F0Text.types.ts → F0Text/F0Text.types.ts} +1 -0
- package/src/components/primitives/F0Text/{__tests__/index.spec.tsx → F0Text/__tests__/F0Text.spec.tsx} +1 -0
- package/src/components/primitives/F0Text/{__tests__/__snapshots__/index.spec.tsx.snap → F0Text/__tests__/__snapshots__/F0Text.spec.tsx.snap} +9 -0
- package/src/components/primitives/F0Text/F0Text/index.ts +22 -0
- package/src/components/primitives/F0Text/index.ts +6 -2
- package/src/styles/theme.css +7 -0
- package/lib/module/components/primitives/F0Text/F0Text.js +0 -2
- package/lib/module/components/primitives/F0Text/F0Text.js.map +0 -1
- package/lib/module/components/primitives/F0Text/F0Text.styles.js +0 -2
- package/lib/module/components/primitives/F0Text/F0Text.styles.js.map +0 -1
- package/lib/module/components/primitives/F0Text/F0Text.types.js +0 -2
- package/lib/module/components/primitives/F0Text/F0Text.types.js.map +0 -1
- package/lib/typescript/components/primitives/F0Text/F0Text.d.ts.map +0 -1
- package/lib/typescript/components/primitives/F0Text/F0Text.styles.d.ts.map +0 -1
- package/lib/typescript/components/primitives/F0Text/F0Text.types.d.ts.map +0 -1
- /package/lib/typescript/components/primitives/F0Text/{F0Text.d.ts → F0Text/F0Text.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"F0Text.d.ts","sourceRoot":"","sources":["../../../../../../src/components/primitives/F0Text/F0Text/F0Text.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,cAAc,CAAA;AAK7C,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAoDvE,eAAO,MAAM,MAAM,uGAA8B,CAAA;AAGjD,YAAY,EAAE,WAAW,EAAE,CAAA;AAC3B,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,cAAc,EACd,aAAa,GACd,MAAM,gBAAgB,CAAA"}
|
package/lib/typescript/components/primitives/F0Text/{F0Text.styles.d.ts → F0Text/F0Text.styles.d.ts}
RENAMED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type VariantProps } from "tailwind-variants";
|
|
2
2
|
/**
|
|
3
3
|
* Text component variants using tailwind-variants
|
|
4
|
-
* Font weights (font-normal, font-medium, font-semibold) map to
|
|
5
|
-
* Inter font families (Inter-Regular, Inter-Medium, Inter-SemiBold)
|
|
4
|
+
* Font weights (font-normal, font-medium, font-semibold, font-bold) map to
|
|
5
|
+
* Inter font families (Inter-Regular, Inter-Medium, Inter-SemiBold, Inter-Bold)
|
|
6
|
+
* via --font-* CSS variables defined in @theme.
|
|
6
7
|
*/
|
|
7
8
|
export declare const textVariants: import("tailwind-variants").TVReturnType<{
|
|
8
9
|
variant: {
|
|
10
|
+
"heading-xl": string;
|
|
9
11
|
"heading-lg": string;
|
|
10
12
|
"heading-md": string;
|
|
11
13
|
"heading-sm": string;
|
|
@@ -50,6 +52,7 @@ export declare const textVariants: import("tailwind-variants").TVReturnType<{
|
|
|
50
52
|
};
|
|
51
53
|
}, undefined, "", {
|
|
52
54
|
variant: {
|
|
55
|
+
"heading-xl": string;
|
|
53
56
|
"heading-lg": string;
|
|
54
57
|
"heading-md": string;
|
|
55
58
|
"heading-sm": string;
|
|
@@ -94,6 +97,7 @@ export declare const textVariants: import("tailwind-variants").TVReturnType<{
|
|
|
94
97
|
};
|
|
95
98
|
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
96
99
|
variant: {
|
|
100
|
+
"heading-xl": string;
|
|
97
101
|
"heading-lg": string;
|
|
98
102
|
"heading-md": string;
|
|
99
103
|
"heading-sm": string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"F0Text.styles.d.ts","sourceRoot":"","sources":["../../../../../../src/components/primitives/F0Text/F0Text/F0Text.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CA6DvB,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,YAAY,CAAC,CAAA"}
|
package/lib/typescript/components/primitives/F0Text/{F0Text.types.d.ts → F0Text/F0Text.types.d.ts}
RENAMED
|
@@ -8,7 +8,7 @@ export declare const F0_TEXT_BANNED_PROPS: readonly ["style", "className"];
|
|
|
8
8
|
/**
|
|
9
9
|
* Typography variant types based on semantic design tokens
|
|
10
10
|
*/
|
|
11
|
-
export declare const TYPOGRAPHY_VARIANTS: readonly ["heading-lg", "heading-md", "heading-sm", "body-md-default", "body-md-medium", "body-md-semibold", "body-sm-default", "body-sm-medium", "body-sm-semibold", "body-xs-medium"];
|
|
11
|
+
export declare const TYPOGRAPHY_VARIANTS: readonly ["heading-xl", "heading-lg", "heading-md", "heading-sm", "body-md-default", "body-md-medium", "body-md-semibold", "body-sm-default", "body-sm-medium", "body-sm-semibold", "body-xs-medium"];
|
|
12
12
|
export type TypographyVariant = (typeof TYPOGRAPHY_VARIANTS)[number];
|
|
13
13
|
/**
|
|
14
14
|
* Text color variants aligned with F0 semantic color system
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"F0Text.types.d.ts","sourceRoot":"","sources":["../../../../../../src/components/primitives/F0Text/F0Text/F0Text.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,IAAI,WAAW,EAAE,MAAM,cAAc,CAAA;AAE5D;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,iCAAkC,CAAA;AAEnE;;GAEG;AACH,eAAO,MAAM,mBAAmB,uMAYtB,CAAA;AAEV,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpE;;GAEG;AACH,eAAO,MAAM,WAAW,4JAad,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpD;;GAEG;AACH,eAAO,MAAM,UAAU,iDAAkD,CAAA;AAEzE,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;AAEnD;;GAEG;AACH,eAAO,MAAM,gBAAgB,gDAAiD,CAAA;AAE9E,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE9D;;GAEG;AACH,eAAO,MAAM,eAAe,2DAKlB,CAAA;AAEV,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAA;AAE5D;;;GAGG;AACH,UAAU,mBAAoB,SAAQ,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9D;;;OAGG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAA;IAEjB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAA;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,cAAc,CAAA;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,aAAa,CAAA;IAEzB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAE1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* F0Text - Text primitive component
|
|
3
|
+
*
|
|
4
|
+
* @see F0Text.md for documentation
|
|
5
|
+
*/
|
|
6
|
+
export { F0Text } from "./F0Text";
|
|
7
|
+
export type { F0TextProps, TypographyVariant, TextColor, TextAlign, TextDecoration, TextTransform, } from "./F0Text";
|
|
8
|
+
export { TYPOGRAPHY_VARIANTS, TEXT_COLORS, TEXT_ALIGN, TEXT_DECORATIONS, TEXT_TRANSFORMS, } from "./F0Text";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/primitives/F0Text/F0Text/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,cAAc,EACd,aAAa,GACd,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,MAAM,UAAU,CAAA"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* F0Text - Text primitive
|
|
2
|
+
* F0Text - Text primitive components
|
|
3
3
|
*
|
|
4
|
-
* @see F0Text.md for documentation
|
|
4
|
+
* @see F0Text/F0Text.md for documentation
|
|
5
|
+
* @see AnimatedF0Text/AnimatedF0Text.md for animated variant documentation
|
|
5
6
|
*/
|
|
6
7
|
export { F0Text } from "./F0Text";
|
|
7
8
|
export type { F0TextProps, TypographyVariant, TextColor, TextAlign, TextDecoration, TextTransform, } from "./F0Text";
|
|
8
9
|
export { TYPOGRAPHY_VARIANTS, TEXT_COLORS, TEXT_ALIGN, TEXT_DECORATIONS, TEXT_TRANSFORMS, } from "./F0Text";
|
|
10
|
+
export { AnimatedF0Text } from "./AnimatedF0Text";
|
|
11
|
+
export type { AnimatedF0TextProps } from "./AnimatedF0Text";
|
|
9
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/primitives/F0Text/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/primitives/F0Text/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,SAAS,EACT,cAAc,EACd,aAAa,GACd,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# AnimatedF0Text
|
|
2
|
+
|
|
3
|
+
Animated text primitive for React Native with semantic typography variants and Reanimated animation support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- All F0Text semantic typography variants and colors
|
|
8
|
+
- Reanimated `entering`/`exiting` layout animations
|
|
9
|
+
- Animated `style` prop for custom animations via `useAnimatedStyle`
|
|
10
|
+
- Layout transition animations
|
|
11
|
+
- Shares the same typography system as F0Text
|
|
12
|
+
- Performance optimized with React.memo and useMemo
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { AnimatedF0Text } from "@factorialco/f0-react-native"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Requires `react-native-reanimated` as a peer dependency.
|
|
21
|
+
|
|
22
|
+
## When to use AnimatedF0Text vs F0Text
|
|
23
|
+
|
|
24
|
+
| Use case | Component |
|
|
25
|
+
| ------------------------------------------------- | ---------------- |
|
|
26
|
+
| Static text, no animation | `F0Text` |
|
|
27
|
+
| Text that fades in/out | `AnimatedF0Text` |
|
|
28
|
+
| Text with entering/exiting transitions | `AnimatedF0Text` |
|
|
29
|
+
| Text driven by animated values (scroll, gestures) | `AnimatedF0Text` |
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Entering/Exiting Animations
|
|
34
|
+
|
|
35
|
+
<!-- prettier-ignore -->
|
|
36
|
+
```tsx
|
|
37
|
+
import { AnimatedF0Text } from "@factorialco/f0-react-native"
|
|
38
|
+
import { FadeIn, FadeOut, SlideInLeft } from "react-native-reanimated"
|
|
39
|
+
|
|
40
|
+
<>
|
|
41
|
+
<AnimatedF0Text
|
|
42
|
+
variant="heading-xl"
|
|
43
|
+
entering={FadeIn.duration(300)}
|
|
44
|
+
exiting={FadeOut.duration(200)}
|
|
45
|
+
>
|
|
46
|
+
Welcome back
|
|
47
|
+
</AnimatedF0Text>
|
|
48
|
+
|
|
49
|
+
<AnimatedF0Text variant="heading-md" entering={SlideInLeft.springify()}>
|
|
50
|
+
Slide in heading
|
|
51
|
+
</AnimatedF0Text>
|
|
52
|
+
</>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Custom Animated Styles
|
|
56
|
+
|
|
57
|
+
<!-- prettier-ignore -->
|
|
58
|
+
```tsx
|
|
59
|
+
import { AnimatedF0Text } from "@factorialco/f0-react-native"
|
|
60
|
+
import { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated"
|
|
61
|
+
|
|
62
|
+
const opacity = useSharedValue(0)
|
|
63
|
+
|
|
64
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
65
|
+
opacity: opacity.value,
|
|
66
|
+
transform: [{ translateY: withTiming(opacity.value * -10) }],
|
|
67
|
+
}))
|
|
68
|
+
|
|
69
|
+
<>
|
|
70
|
+
<AnimatedF0Text variant="body-md-default" style={animatedStyle}>
|
|
71
|
+
Custom animated text
|
|
72
|
+
</AnimatedF0Text>
|
|
73
|
+
</>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Layout Transitions
|
|
77
|
+
|
|
78
|
+
<!-- prettier-ignore -->
|
|
79
|
+
```tsx
|
|
80
|
+
import { AnimatedF0Text } from "@factorialco/f0-react-native"
|
|
81
|
+
import { LinearTransition } from "react-native-reanimated"
|
|
82
|
+
|
|
83
|
+
<>
|
|
84
|
+
<AnimatedF0Text
|
|
85
|
+
variant="body-sm-default"
|
|
86
|
+
layout={LinearTransition.springify()}
|
|
87
|
+
>
|
|
88
|
+
{dynamicContent}
|
|
89
|
+
</AnimatedF0Text>
|
|
90
|
+
</>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## API Reference
|
|
94
|
+
|
|
95
|
+
### Props
|
|
96
|
+
|
|
97
|
+
AnimatedF0Text accepts all F0Text semantic props plus Reanimated animation props.
|
|
98
|
+
|
|
99
|
+
#### Typography Props (shared with F0Text)
|
|
100
|
+
|
|
101
|
+
| Prop | Type | Default | Description |
|
|
102
|
+
| --------------- | ------------------- | ------------------- | ---------------------------------------- |
|
|
103
|
+
| `variant` | `TypographyVariant` | `'body-sm-default'` | Typography variant |
|
|
104
|
+
| `color` | `TextColor` | `'default'` | Text color from F0 semantic color system |
|
|
105
|
+
| `align` | `TextAlign` | `'left'` | Text alignment |
|
|
106
|
+
| `decoration` | `TextDecoration` | `'none'` | Text decoration |
|
|
107
|
+
| `transform` | `TextTransform` | `'none'` | Text transform |
|
|
108
|
+
| `numberOfLines` | `number` | `undefined` | Max lines before truncation |
|
|
109
|
+
|
|
110
|
+
#### Animation Props
|
|
111
|
+
|
|
112
|
+
| Prop | Type | Description |
|
|
113
|
+
| ---------- | ------------------------------------------------- | -------------------------------------------------------------- |
|
|
114
|
+
| `entering` | `EntryOrExitLayoutType` | Reanimated entering animation (e.g. `FadeIn`, `SlideInLeft`) |
|
|
115
|
+
| `exiting` | `EntryOrExitLayoutType` | Reanimated exiting animation (e.g. `FadeOut`, `SlideOutRight`) |
|
|
116
|
+
| `layout` | `BaseAnimationBuilder \| LayoutAnimationFunction` | Layout transition animation |
|
|
117
|
+
| `style` | `AnimatedStyle` | Animated style from `useAnimatedStyle` |
|
|
118
|
+
|
|
119
|
+
All React Native `TextProps` are also supported (onPress, testID, etc.).
|
|
120
|
+
|
|
121
|
+
### Typography Variants
|
|
122
|
+
|
|
123
|
+
See [F0Text documentation](../F0Text/F0Text.md) for the full list of typography variants and colors.
|
|
124
|
+
|
|
125
|
+
## Architecture
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
F0Text/ # Parent folder for text primitives
|
|
129
|
+
├── F0Text/ # Static text component
|
|
130
|
+
│ ├── F0Text.tsx
|
|
131
|
+
│ ├── F0Text.types.ts # Shared types (TypographyVariant, TextColor, etc.)
|
|
132
|
+
│ ├── F0Text.styles.ts # Shared styles (textVariants)
|
|
133
|
+
│ ├── F0Text.md
|
|
134
|
+
│ ├── index.ts
|
|
135
|
+
│ └── __tests__/
|
|
136
|
+
├── AnimatedF0Text/ # Animated text component
|
|
137
|
+
│ ├── AnimatedF0Text.tsx # Animated text (Reanimated Animated.Text)
|
|
138
|
+
│ ├── AnimatedF0Text.types.ts
|
|
139
|
+
│ ├── AnimatedF0Text.md
|
|
140
|
+
│ ├── index.ts
|
|
141
|
+
│ └── __tests__/
|
|
142
|
+
└── index.ts # Barrel re-exporting both
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- **Types** are imported from `../F0Text/F0Text.types.ts` (`TypographyVariant`, `TextColor`, etc.)
|
|
146
|
+
- **Styles** are imported from `../F0Text/F0Text.styles.ts` (`textVariants`)
|
|
147
|
+
|
|
148
|
+
This ensures both components always produce identical typography output.
|
|
149
|
+
|
|
150
|
+
## Accessibility
|
|
151
|
+
|
|
152
|
+
- Fully supports React Native `Text` accessibility props
|
|
153
|
+
- Animations respect the device's reduced motion setting when using Reanimated's built-in animations
|
|
154
|
+
|
|
155
|
+
## Performance
|
|
156
|
+
|
|
157
|
+
- **React.memo**: Prevents re-renders when props unchanged
|
|
158
|
+
- **useMemo**: Memoizes className computation
|
|
159
|
+
- Only imported when animation is needed (tree-shakeable)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { Text as RNText } from "react-native"
|
|
3
|
+
import Animated from "react-native-reanimated"
|
|
4
|
+
|
|
5
|
+
import { textVariants } from "../F0Text/F0Text.styles"
|
|
6
|
+
|
|
7
|
+
import type { AnimatedF0TextProps } from "./AnimatedF0Text.types"
|
|
8
|
+
|
|
9
|
+
const AnimatedText = Animated.createAnimatedComponent(RNText)
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* AnimatedF0Text - Animated text primitive with semantic typography variants
|
|
13
|
+
*
|
|
14
|
+
* Uses Reanimated's Animated.Text under the hood while sharing the same
|
|
15
|
+
* typography system as F0Text. Supports `entering`, `exiting`, `layout`
|
|
16
|
+
* animations and animated `style` props.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* <AnimatedF0Text variant="heading-xl" entering={FadeIn.duration(300)}>
|
|
20
|
+
* Welcome back
|
|
21
|
+
* </AnimatedF0Text>
|
|
22
|
+
*/
|
|
23
|
+
const AnimatedF0TextComponent = React.forwardRef<
|
|
24
|
+
React.ComponentRef<typeof AnimatedText>,
|
|
25
|
+
AnimatedF0TextProps
|
|
26
|
+
>(
|
|
27
|
+
(
|
|
28
|
+
{
|
|
29
|
+
variant = "body-sm-default",
|
|
30
|
+
color = "default",
|
|
31
|
+
align = "left",
|
|
32
|
+
decoration = "none",
|
|
33
|
+
transform = "none",
|
|
34
|
+
children,
|
|
35
|
+
numberOfLines,
|
|
36
|
+
style,
|
|
37
|
+
...rest
|
|
38
|
+
},
|
|
39
|
+
ref
|
|
40
|
+
) => {
|
|
41
|
+
const textClassName = React.useMemo(
|
|
42
|
+
() =>
|
|
43
|
+
textVariants({
|
|
44
|
+
variant,
|
|
45
|
+
color,
|
|
46
|
+
align,
|
|
47
|
+
decoration,
|
|
48
|
+
transform,
|
|
49
|
+
}),
|
|
50
|
+
[variant, color, align, decoration, transform]
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<AnimatedText
|
|
55
|
+
ref={ref}
|
|
56
|
+
{...rest}
|
|
57
|
+
className={textClassName}
|
|
58
|
+
style={style}
|
|
59
|
+
numberOfLines={numberOfLines}
|
|
60
|
+
ellipsizeMode={numberOfLines ? "tail" : undefined}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
</AnimatedText>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
AnimatedF0TextComponent.displayName = "AnimatedF0Text"
|
|
69
|
+
|
|
70
|
+
export const AnimatedF0Text = React.memo(AnimatedF0TextComponent)
|
|
71
|
+
|
|
72
|
+
export type { AnimatedF0TextProps }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { TextProps as RNTextProps } from "react-native"
|
|
2
|
+
import type { AnimatedProps } from "react-native-reanimated"
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
TextAlign,
|
|
6
|
+
TextColor,
|
|
7
|
+
TextDecoration,
|
|
8
|
+
TextTransform,
|
|
9
|
+
TypographyVariant,
|
|
10
|
+
} from "../F0Text/F0Text.types"
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Props for the AnimatedF0Text component.
|
|
14
|
+
*
|
|
15
|
+
* Combines F0Text semantic typography props with Reanimated animation
|
|
16
|
+
* capabilities (`entering`, `exiting`, `layout`, animated `style`).
|
|
17
|
+
*/
|
|
18
|
+
export interface AnimatedF0TextProps extends Omit<
|
|
19
|
+
AnimatedProps<RNTextProps>,
|
|
20
|
+
"className"
|
|
21
|
+
> {
|
|
22
|
+
/**
|
|
23
|
+
* Semantic typography variant
|
|
24
|
+
* @default "body-sm-default"
|
|
25
|
+
*/
|
|
26
|
+
variant?: TypographyVariant
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Text color from F0 semantic color system
|
|
30
|
+
* @default "default"
|
|
31
|
+
*/
|
|
32
|
+
color?: TextColor
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Text alignment
|
|
36
|
+
* @default "left"
|
|
37
|
+
*/
|
|
38
|
+
align?: TextAlign
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Text decoration
|
|
42
|
+
* @default "none"
|
|
43
|
+
*/
|
|
44
|
+
decoration?: TextDecoration
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Text transform
|
|
48
|
+
* @default "none"
|
|
49
|
+
*/
|
|
50
|
+
transform?: TextTransform
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Maximum number of lines before truncating with ellipsis
|
|
54
|
+
*/
|
|
55
|
+
numberOfLines?: number
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Children content
|
|
59
|
+
*/
|
|
60
|
+
children?: React.ReactNode
|
|
61
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { render } from "@testing-library/react-native"
|
|
2
|
+
import React from "react"
|
|
3
|
+
|
|
4
|
+
import { AnimatedF0Text } from "../AnimatedF0Text"
|
|
5
|
+
|
|
6
|
+
describe("AnimatedF0Text", () => {
|
|
7
|
+
describe("Snapshots", () => {
|
|
8
|
+
it("renders with default variant (body-sm-default)", () => {
|
|
9
|
+
const { toJSON } = render(<AnimatedF0Text>Default text</AnimatedF0Text>)
|
|
10
|
+
expect(toJSON()).toMatchSnapshot()
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it("renders all typography variants", () => {
|
|
14
|
+
const variants = [
|
|
15
|
+
"heading-xl",
|
|
16
|
+
"heading-lg",
|
|
17
|
+
"heading-md",
|
|
18
|
+
"heading-sm",
|
|
19
|
+
"body-md-default",
|
|
20
|
+
"body-md-medium",
|
|
21
|
+
"body-md-semibold",
|
|
22
|
+
"body-sm-default",
|
|
23
|
+
"body-sm-medium",
|
|
24
|
+
"body-sm-semibold",
|
|
25
|
+
"body-xs-medium",
|
|
26
|
+
] as const
|
|
27
|
+
|
|
28
|
+
variants.forEach((variant) => {
|
|
29
|
+
const { toJSON } = render(
|
|
30
|
+
<AnimatedF0Text variant={variant}>{variant} text</AnimatedF0Text>
|
|
31
|
+
)
|
|
32
|
+
expect(toJSON()).toMatchSnapshot(`variant-${variant}`)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("renders with color variants", () => {
|
|
37
|
+
const colors = ["default", "secondary", "accent", "critical"] as const
|
|
38
|
+
|
|
39
|
+
colors.forEach((color) => {
|
|
40
|
+
const { toJSON } = render(
|
|
41
|
+
<AnimatedF0Text color={color}>{color} text</AnimatedF0Text>
|
|
42
|
+
)
|
|
43
|
+
expect(toJSON()).toMatchSnapshot(`color-${color}`)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe("Behavior", () => {
|
|
49
|
+
it("renders children correctly", () => {
|
|
50
|
+
const { getByText } = render(<AnimatedF0Text>Hello World</AnimatedF0Text>)
|
|
51
|
+
expect(getByText("Hello World")).toBeTruthy()
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it("applies correct variant classes", () => {
|
|
55
|
+
const { getByText } = render(
|
|
56
|
+
<AnimatedF0Text variant="heading-xl">XL Heading</AnimatedF0Text>
|
|
57
|
+
)
|
|
58
|
+
const element = getByText("XL Heading")
|
|
59
|
+
expect(element.props.className).toContain("text-[36px]")
|
|
60
|
+
expect(element.props.className).toContain("leading-[40px]")
|
|
61
|
+
expect(element.props.className).toContain("tracking-[-0.2px]")
|
|
62
|
+
expect(element.props.className).toContain("font-semibold")
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it("applies correct color classes", () => {
|
|
66
|
+
const { getByText } = render(
|
|
67
|
+
<AnimatedF0Text color="secondary">Secondary text</AnimatedF0Text>
|
|
68
|
+
)
|
|
69
|
+
const element = getByText("Secondary text")
|
|
70
|
+
expect(element.props.className).toContain("text-f0-foreground-secondary")
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it("applies correct alignment classes", () => {
|
|
74
|
+
const { getByText } = render(
|
|
75
|
+
<AnimatedF0Text align="center">Centered text</AnimatedF0Text>
|
|
76
|
+
)
|
|
77
|
+
const element = getByText("Centered text")
|
|
78
|
+
expect(element.props.className).toContain("text-center")
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it("applies decoration classes", () => {
|
|
82
|
+
const { getByText } = render(
|
|
83
|
+
<AnimatedF0Text decoration="underline">Underlined text</AnimatedF0Text>
|
|
84
|
+
)
|
|
85
|
+
const element = getByText("Underlined text")
|
|
86
|
+
expect(element.props.className).toContain("underline")
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it("applies transform classes", () => {
|
|
90
|
+
const { getByText } = render(
|
|
91
|
+
<AnimatedF0Text transform="uppercase">uppercase text</AnimatedF0Text>
|
|
92
|
+
)
|
|
93
|
+
const element = getByText("uppercase text")
|
|
94
|
+
expect(element.props.className).toContain("uppercase")
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it("sets numberOfLines prop correctly", () => {
|
|
98
|
+
const { getByText } = render(
|
|
99
|
+
<AnimatedF0Text numberOfLines={3}>Multiline text</AnimatedF0Text>
|
|
100
|
+
)
|
|
101
|
+
const element = getByText("Multiline text")
|
|
102
|
+
expect(element.props.numberOfLines).toBe(3)
|
|
103
|
+
expect(element.props.ellipsizeMode).toBe("tail")
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it("does not set ellipsizeMode when numberOfLines is not provided", () => {
|
|
107
|
+
const { getByText } = render(<AnimatedF0Text>Normal text</AnimatedF0Text>)
|
|
108
|
+
const element = getByText("Normal text")
|
|
109
|
+
expect(element.props.ellipsizeMode).toBeUndefined()
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it("accepts style prop for animated styles", () => {
|
|
113
|
+
const animatedStyle = { opacity: 0.5 }
|
|
114
|
+
const { getByText } = render(
|
|
115
|
+
<AnimatedF0Text style={animatedStyle}>Styled text</AnimatedF0Text>
|
|
116
|
+
)
|
|
117
|
+
const element = getByText("Styled text")
|
|
118
|
+
expect(element.props.style).toEqual(animatedStyle)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it("forwards additional props", () => {
|
|
122
|
+
const { getByText } = render(
|
|
123
|
+
<AnimatedF0Text testID="test-animated-text">
|
|
124
|
+
Pressable text
|
|
125
|
+
</AnimatedF0Text>
|
|
126
|
+
)
|
|
127
|
+
const element = getByText("Pressable text")
|
|
128
|
+
expect(element.props.testID).toBe("test-animated-text")
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
|
2
|
+
|
|
3
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-body-md-default 1`] = `
|
|
4
|
+
<Text
|
|
5
|
+
className="text-[16px] leading-[24px] font-normal text-f0-foreground text-left"
|
|
6
|
+
>
|
|
7
|
+
body-md-default
|
|
8
|
+
text
|
|
9
|
+
</Text>
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-body-md-medium 1`] = `
|
|
13
|
+
<Text
|
|
14
|
+
className="text-[16px] leading-[24px] font-medium text-f0-foreground text-left"
|
|
15
|
+
>
|
|
16
|
+
body-md-medium
|
|
17
|
+
text
|
|
18
|
+
</Text>
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-body-md-semibold 1`] = `
|
|
22
|
+
<Text
|
|
23
|
+
className="text-[16px] leading-[24px] font-semibold text-f0-foreground text-left"
|
|
24
|
+
>
|
|
25
|
+
body-md-semibold
|
|
26
|
+
text
|
|
27
|
+
</Text>
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-body-sm-default 1`] = `
|
|
31
|
+
<Text
|
|
32
|
+
className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
|
|
33
|
+
>
|
|
34
|
+
body-sm-default
|
|
35
|
+
text
|
|
36
|
+
</Text>
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-body-sm-medium 1`] = `
|
|
40
|
+
<Text
|
|
41
|
+
className="text-[14px] leading-[20px] font-medium text-f0-foreground text-left"
|
|
42
|
+
>
|
|
43
|
+
body-sm-medium
|
|
44
|
+
text
|
|
45
|
+
</Text>
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-body-sm-semibold 1`] = `
|
|
49
|
+
<Text
|
|
50
|
+
className="text-[14px] leading-[20px] font-semibold text-f0-foreground text-left"
|
|
51
|
+
>
|
|
52
|
+
body-sm-semibold
|
|
53
|
+
text
|
|
54
|
+
</Text>
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-body-xs-medium 1`] = `
|
|
58
|
+
<Text
|
|
59
|
+
className="text-[12px] leading-[16px] font-medium text-f0-foreground text-left"
|
|
60
|
+
>
|
|
61
|
+
body-xs-medium
|
|
62
|
+
text
|
|
63
|
+
</Text>
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-heading-lg 1`] = `
|
|
67
|
+
<Text
|
|
68
|
+
className="text-[24px] leading-[32px] tracking-[-0.2px] font-semibold text-f0-foreground text-left"
|
|
69
|
+
>
|
|
70
|
+
heading-lg
|
|
71
|
+
text
|
|
72
|
+
</Text>
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-heading-md 1`] = `
|
|
76
|
+
<Text
|
|
77
|
+
className="text-[20px] leading-[28px] tracking-[-0.2px] font-semibold text-f0-foreground text-left"
|
|
78
|
+
>
|
|
79
|
+
heading-md
|
|
80
|
+
text
|
|
81
|
+
</Text>
|
|
82
|
+
`;
|
|
83
|
+
|
|
84
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-heading-sm 1`] = `
|
|
85
|
+
<Text
|
|
86
|
+
className="text-[16px] leading-[24px] font-semibold text-f0-foreground text-left"
|
|
87
|
+
>
|
|
88
|
+
heading-sm
|
|
89
|
+
text
|
|
90
|
+
</Text>
|
|
91
|
+
`;
|
|
92
|
+
|
|
93
|
+
exports[`AnimatedF0Text Snapshots renders all typography variants: variant-heading-xl 1`] = `
|
|
94
|
+
<Text
|
|
95
|
+
className="text-[36px] leading-[40px] tracking-[-0.2px] font-semibold text-f0-foreground text-left"
|
|
96
|
+
>
|
|
97
|
+
heading-xl
|
|
98
|
+
text
|
|
99
|
+
</Text>
|
|
100
|
+
`;
|
|
101
|
+
|
|
102
|
+
exports[`AnimatedF0Text Snapshots renders with color variants: color-accent 1`] = `
|
|
103
|
+
<Text
|
|
104
|
+
className="text-[14px] leading-[20px] font-normal text-f0-foreground-accent text-left"
|
|
105
|
+
>
|
|
106
|
+
accent
|
|
107
|
+
text
|
|
108
|
+
</Text>
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
exports[`AnimatedF0Text Snapshots renders with color variants: color-critical 1`] = `
|
|
112
|
+
<Text
|
|
113
|
+
className="text-[14px] leading-[20px] font-normal text-f0-foreground-critical text-left"
|
|
114
|
+
>
|
|
115
|
+
critical
|
|
116
|
+
text
|
|
117
|
+
</Text>
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
exports[`AnimatedF0Text Snapshots renders with color variants: color-default 1`] = `
|
|
121
|
+
<Text
|
|
122
|
+
className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
|
|
123
|
+
>
|
|
124
|
+
default
|
|
125
|
+
text
|
|
126
|
+
</Text>
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
exports[`AnimatedF0Text Snapshots renders with color variants: color-secondary 1`] = `
|
|
130
|
+
<Text
|
|
131
|
+
className="text-[14px] leading-[20px] font-normal text-f0-foreground-secondary text-left"
|
|
132
|
+
>
|
|
133
|
+
secondary
|
|
134
|
+
text
|
|
135
|
+
</Text>
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
exports[`AnimatedF0Text Snapshots renders with default variant (body-sm-default) 1`] = `
|
|
139
|
+
<Text
|
|
140
|
+
className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
|
|
141
|
+
>
|
|
142
|
+
Default text
|
|
143
|
+
</Text>
|
|
144
|
+
`;
|