@factorialco/f0-react-native 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/lib/module/components/Activity/ActivityItem/index.js +1 -1
  2. package/lib/module/components/Avatars/BaseAvatar/index.js +1 -1
  3. package/lib/module/components/Avatars/DateAvatar/index.js +1 -1
  4. package/lib/module/components/Avatars/EmojiAvatar/index.js +1 -1
  5. package/lib/module/components/Avatars/FileAvatar/index.js +1 -1
  6. package/lib/module/components/Avatars/FileAvatar/utils.js +1 -1
  7. package/lib/module/components/Avatars/IconAvatar/index.js +1 -1
  8. package/lib/module/components/Avatars/ModuleAvatar/index.js +1 -1
  9. package/lib/module/components/Badge/index.js +1 -1
  10. package/lib/module/components/Button/index.js +1 -1
  11. package/lib/module/components/Counter/index.js +1 -1
  12. package/lib/module/components/ExampleComponent.js +1 -1
  13. package/lib/module/components/Icon/README.md +1 -1
  14. package/lib/module/components/Navigation/PageHeader/index.js +1 -1
  15. package/lib/module/components/OneChip/index.js +1 -1
  16. package/lib/module/components/OnePreset/index.js +1 -1
  17. package/lib/module/components/Tags/AlertTab/index.js +1 -1
  18. package/lib/module/components/Tags/BaseTag/index.js +1 -1
  19. package/lib/module/components/Tags/DotTag/index.js +1 -1
  20. package/lib/module/components/Tags/RawTag/index.js +1 -1
  21. package/lib/module/components/experimental/Lists/DataList/ItemContainer.js +1 -1
  22. package/lib/module/components/experimental/Lists/DataList/actions/CopyAction.js +1 -1
  23. package/lib/module/components/experimental/Lists/DataList/actions/GenericAction.js +1 -1
  24. package/lib/module/components/experimental/Lists/DataList/index.js +1 -1
  25. package/lib/module/components/experimental/Lists/DetailsItemsList/index.js +1 -1
  26. package/lib/module/components/exports.js +1 -1
  27. package/lib/module/components/exports.js.map +1 -1
  28. package/lib/module/components/primitives/F0Text/F0Text.js +2 -0
  29. package/lib/module/components/primitives/F0Text/F0Text.js.map +1 -0
  30. package/lib/module/components/primitives/F0Text/F0Text.md +297 -0
  31. package/lib/module/components/primitives/F0Text/F0Text.styles.js +2 -0
  32. package/lib/module/components/primitives/F0Text/F0Text.styles.js.map +1 -0
  33. package/lib/module/components/primitives/F0Text/F0Text.types.js +2 -0
  34. package/lib/module/components/primitives/F0Text/F0Text.types.js.map +1 -0
  35. package/lib/module/components/primitives/F0Text/index.js +2 -0
  36. package/lib/module/components/primitives/F0Text/index.js.map +1 -0
  37. package/lib/module/icons/app/QuestionCircle.js +1 -1
  38. package/lib/module/icons/app/QuestionCircle.js.map +1 -1
  39. package/lib/module/icons/app/index.js +1 -1
  40. package/lib/module/icons/app/index.js.map +1 -1
  41. package/lib/module/index.js +1 -1
  42. package/lib/module/index.js.map +1 -1
  43. package/lib/module/lib/utils.js +1 -1
  44. package/lib/module/lib/utils.js.map +1 -1
  45. package/lib/module/styles/theme.css +308 -237
  46. package/lib/module/styles/tokens/colors.js +1 -1
  47. package/lib/module/styles/tokens/colors.js.map +1 -1
  48. package/lib/module/ui/avatar.js +1 -1
  49. package/lib/typescript/components/OneChip/index.d.ts +2 -2
  50. package/lib/typescript/components/exports.d.ts +1 -0
  51. package/lib/typescript/components/exports.d.ts.map +1 -1
  52. package/lib/typescript/components/primitives/F0Text/F0Text.d.ts +8 -0
  53. package/lib/typescript/components/primitives/F0Text/F0Text.d.ts.map +1 -0
  54. package/lib/typescript/components/primitives/F0Text/F0Text.styles.d.ts +141 -0
  55. package/lib/typescript/components/primitives/F0Text/F0Text.styles.d.ts.map +1 -0
  56. package/lib/typescript/components/primitives/F0Text/F0Text.types.d.ts +86 -0
  57. package/lib/typescript/components/primitives/F0Text/F0Text.types.d.ts.map +1 -0
  58. package/lib/typescript/components/primitives/F0Text/index.d.ts +9 -0
  59. package/lib/typescript/components/primitives/F0Text/index.d.ts.map +1 -0
  60. package/lib/typescript/icons/app/index.d.ts +1 -1
  61. package/lib/typescript/icons/app/index.d.ts.map +1 -1
  62. package/lib/typescript/index.d.ts +1 -1
  63. package/lib/typescript/index.d.ts.map +1 -1
  64. package/lib/typescript/lib/utils.d.ts +9 -0
  65. package/lib/typescript/lib/utils.d.ts.map +1 -1
  66. package/lib/typescript/styles/tokens/colors.d.ts +2 -2
  67. package/package.json +2 -2
  68. package/src/components/Activity/ActivityItem/__snapshots__/index.spec.tsx.snap +3 -3
  69. package/src/components/Activity/ActivityItem/index.tsx +10 -10
  70. package/src/components/Avatars/BaseAvatar/index.tsx +1 -1
  71. package/src/components/Avatars/CompanyAvatar/__snapshots__/index.spec.tsx.snap +1 -1
  72. package/src/components/Avatars/DateAvatar/__snapshots__/index.spec.tsx.snap +3 -3
  73. package/src/components/Avatars/DateAvatar/index.tsx +3 -3
  74. package/src/components/Avatars/EmojiAvatar/__snapshots__/index.spec.tsx.snap +3 -3
  75. package/src/components/Avatars/EmojiAvatar/index.tsx +1 -1
  76. package/src/components/Avatars/FileAvatar/__snapshots__/index.spec.tsx.snap +26 -26
  77. package/src/components/Avatars/FileAvatar/index.tsx +2 -2
  78. package/src/components/Avatars/FileAvatar/utils.ts +13 -13
  79. package/src/components/Avatars/IconAvatar/__snapshots__/index.spec.tsx.snap +6 -6
  80. package/src/components/Avatars/IconAvatar/index.tsx +2 -2
  81. package/src/components/Avatars/ModuleAvatar/index.tsx +1 -1
  82. package/src/components/Avatars/PersonAvatar/__snapshots__/index.spec.tsx.snap +1 -1
  83. package/src/components/Avatars/TeamAvatar/__snapshots__/index.spec.tsx.snap +1 -1
  84. package/src/components/Badge/index.tsx +5 -5
  85. package/src/components/Button/__snapshots__/index.spec.tsx.snap +22 -22
  86. package/src/components/Button/index.tsx +22 -22
  87. package/src/components/Counter/__snapshots__/index.spec.tsx.snap +14 -14
  88. package/src/components/Counter/index.tsx +6 -6
  89. package/src/components/ExampleComponent.tsx +2 -2
  90. package/src/components/Icon/README.md +1 -1
  91. package/src/components/Navigation/PageHeader/__snapshots__/index.spec.tsx.snap +4 -4
  92. package/src/components/Navigation/PageHeader/index.tsx +1 -1
  93. package/src/components/OneChip/__snapshots__/index.spec.tsx.snap +11 -11
  94. package/src/components/OneChip/index.tsx +5 -5
  95. package/src/components/OnePreset/__snapshots__/index.spec.tsx.snap +8 -8
  96. package/src/components/OnePreset/index.tsx +3 -3
  97. package/src/components/Tags/AlertTab/__snapshots__/index.spec.tsx.snap +9 -9
  98. package/src/components/Tags/AlertTab/index.tsx +9 -9
  99. package/src/components/Tags/BaseTag/index.tsx +2 -2
  100. package/src/components/Tags/DotTag/__snapshots__/index.spec.tsx.snap +38 -38
  101. package/src/components/Tags/DotTag/index.tsx +1 -1
  102. package/src/components/Tags/RawTag/__snapshots__/index.spec.tsx.snap +6 -6
  103. package/src/components/Tags/RawTag/index.tsx +3 -3
  104. package/src/components/experimental/Lists/DataList/ItemContainer.tsx +2 -2
  105. package/src/components/experimental/Lists/DataList/actions/CopyAction.tsx +4 -4
  106. package/src/components/experimental/Lists/DataList/actions/GenericAction.tsx +3 -3
  107. package/src/components/experimental/Lists/DataList/index.tsx +1 -1
  108. package/src/components/experimental/Lists/DetailsItem/__snapshots__/index.spec.tsx.snap +26 -26
  109. package/src/components/experimental/Lists/DetailsItemsList/__snapshots__/index.spec.tsx.snap +26 -26
  110. package/src/components/experimental/Lists/DetailsItemsList/index.tsx +3 -3
  111. package/src/components/exports.ts +3 -0
  112. package/src/components/primitives/F0Text/F0Text.md +297 -0
  113. package/src/components/primitives/F0Text/F0Text.styles.ts +69 -0
  114. package/src/components/primitives/F0Text/F0Text.tsx +76 -0
  115. package/src/components/primitives/F0Text/F0Text.types.ts +133 -0
  116. package/src/components/primitives/F0Text/__tests__/__snapshots__/index.spec.tsx.snap +316 -0
  117. package/src/components/primitives/F0Text/__tests__/index.spec.tsx +227 -0
  118. package/src/components/primitives/F0Text/index.ts +22 -0
  119. package/src/icons/app/QuestionCircle.tsx +1 -1
  120. package/src/icons/app/index.ts +1 -1
  121. package/src/index.ts +1 -1
  122. package/src/lib/__tests__/utils.spec.ts +48 -0
  123. package/src/lib/utils.ts +19 -0
  124. package/src/styles/theme.css +308 -237
  125. package/src/styles/tokens/colors.ts +2 -2
  126. package/src/ui/avatar.tsx +1 -1
@@ -0,0 +1,316 @@
1
+ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
2
+
3
+ exports[`F0Text Snapshots renders all color variants: color-accent 1`] = `
4
+ <Text
5
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-accent text-left"
6
+ >
7
+ accent
8
+ text
9
+ </Text>
10
+ `;
11
+
12
+ exports[`F0Text Snapshots renders all color variants: color-critical 1`] = `
13
+ <Text
14
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-critical text-left"
15
+ >
16
+ critical
17
+ text
18
+ </Text>
19
+ `;
20
+
21
+ exports[`F0Text Snapshots renders all color variants: color-default 1`] = `
22
+ <Text
23
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
24
+ >
25
+ default
26
+ text
27
+ </Text>
28
+ `;
29
+
30
+ exports[`F0Text Snapshots renders all color variants: color-disabled 1`] = `
31
+ <Text
32
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-disabled text-left"
33
+ >
34
+ disabled
35
+ text
36
+ </Text>
37
+ `;
38
+
39
+ exports[`F0Text Snapshots renders all color variants: color-info 1`] = `
40
+ <Text
41
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-info text-left"
42
+ >
43
+ info
44
+ text
45
+ </Text>
46
+ `;
47
+
48
+ exports[`F0Text Snapshots renders all color variants: color-inverse 1`] = `
49
+ <Text
50
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-inverse text-left"
51
+ >
52
+ inverse
53
+ text
54
+ </Text>
55
+ `;
56
+
57
+ exports[`F0Text Snapshots renders all color variants: color-inverse-secondary 1`] = `
58
+ <Text
59
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-inverse-secondary text-left"
60
+ >
61
+ inverse-secondary
62
+ text
63
+ </Text>
64
+ `;
65
+
66
+ exports[`F0Text Snapshots renders all color variants: color-positive 1`] = `
67
+ <Text
68
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-positive text-left"
69
+ >
70
+ positive
71
+ text
72
+ </Text>
73
+ `;
74
+
75
+ exports[`F0Text Snapshots renders all color variants: color-secondary 1`] = `
76
+ <Text
77
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-secondary text-left"
78
+ >
79
+ secondary
80
+ text
81
+ </Text>
82
+ `;
83
+
84
+ exports[`F0Text Snapshots renders all color variants: color-selected 1`] = `
85
+ <Text
86
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-selected text-left"
87
+ >
88
+ selected
89
+ text
90
+ </Text>
91
+ `;
92
+
93
+ exports[`F0Text Snapshots renders all color variants: color-tertiary 1`] = `
94
+ <Text
95
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-tertiary text-left"
96
+ >
97
+ tertiary
98
+ text
99
+ </Text>
100
+ `;
101
+
102
+ exports[`F0Text Snapshots renders all color variants: color-warning 1`] = `
103
+ <Text
104
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground-warning text-left"
105
+ >
106
+ warning
107
+ text
108
+ </Text>
109
+ `;
110
+
111
+ exports[`F0Text Snapshots renders all typography variants: variant-body-md-default 1`] = `
112
+ <Text
113
+ className="text-[16px] leading-[24px] font-normal text-f0-foreground text-left"
114
+ >
115
+ body-md-default
116
+ text
117
+ </Text>
118
+ `;
119
+
120
+ exports[`F0Text Snapshots renders all typography variants: variant-body-md-medium 1`] = `
121
+ <Text
122
+ className="text-[16px] leading-[24px] font-medium text-f0-foreground text-left"
123
+ >
124
+ body-md-medium
125
+ text
126
+ </Text>
127
+ `;
128
+
129
+ exports[`F0Text Snapshots renders all typography variants: variant-body-md-semibold 1`] = `
130
+ <Text
131
+ className="text-[16px] leading-[24px] font-semibold text-f0-foreground text-left"
132
+ >
133
+ body-md-semibold
134
+ text
135
+ </Text>
136
+ `;
137
+
138
+ exports[`F0Text Snapshots renders all typography variants: variant-body-sm-default 1`] = `
139
+ <Text
140
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
141
+ >
142
+ body-sm-default
143
+ text
144
+ </Text>
145
+ `;
146
+
147
+ exports[`F0Text Snapshots renders all typography variants: variant-body-sm-medium 1`] = `
148
+ <Text
149
+ className="text-[14px] leading-[20px] font-medium text-f0-foreground text-left"
150
+ >
151
+ body-sm-medium
152
+ text
153
+ </Text>
154
+ `;
155
+
156
+ exports[`F0Text Snapshots renders all typography variants: variant-body-sm-semibold 1`] = `
157
+ <Text
158
+ className="text-[14px] leading-[20px] font-semibold text-f0-foreground text-left"
159
+ >
160
+ body-sm-semibold
161
+ text
162
+ </Text>
163
+ `;
164
+
165
+ exports[`F0Text Snapshots renders all typography variants: variant-body-xs-medium 1`] = `
166
+ <Text
167
+ className="text-[12px] leading-[16px] font-medium text-f0-foreground text-left"
168
+ >
169
+ body-xs-medium
170
+ text
171
+ </Text>
172
+ `;
173
+
174
+ exports[`F0Text Snapshots renders all typography variants: variant-heading-lg 1`] = `
175
+ <Text
176
+ className="text-[24px] leading-[32px] tracking-[-0.2px] font-semibold text-f0-foreground text-left"
177
+ >
178
+ heading-lg
179
+ text
180
+ </Text>
181
+ `;
182
+
183
+ exports[`F0Text Snapshots renders all typography variants: variant-heading-md 1`] = `
184
+ <Text
185
+ className="text-[20px] leading-[28px] tracking-[-0.2px] font-semibold text-f0-foreground text-left"
186
+ >
187
+ heading-md
188
+ text
189
+ </Text>
190
+ `;
191
+
192
+ exports[`F0Text Snapshots renders all typography variants: variant-heading-sm 1`] = `
193
+ <Text
194
+ className="text-[16px] leading-[24px] font-semibold text-f0-foreground text-left"
195
+ >
196
+ heading-sm
197
+ text
198
+ </Text>
199
+ `;
200
+
201
+ exports[`F0Text Snapshots renders with alignment options: align-center 1`] = `
202
+ <Text
203
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-center"
204
+ >
205
+ center
206
+ text
207
+ </Text>
208
+ `;
209
+
210
+ exports[`F0Text Snapshots renders with alignment options: align-justify 1`] = `
211
+ <Text
212
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-justify"
213
+ >
214
+ justify
215
+ text
216
+ </Text>
217
+ `;
218
+
219
+ exports[`F0Text Snapshots renders with alignment options: align-left 1`] = `
220
+ <Text
221
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
222
+ >
223
+ left
224
+ text
225
+ </Text>
226
+ `;
227
+
228
+ exports[`F0Text Snapshots renders with alignment options: align-right 1`] = `
229
+ <Text
230
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-right"
231
+ >
232
+ right
233
+ text
234
+ </Text>
235
+ `;
236
+
237
+ exports[`F0Text Snapshots renders with default variant (body-sm-default) 1`] = `
238
+ <Text
239
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
240
+ >
241
+ Default text
242
+ </Text>
243
+ `;
244
+
245
+ exports[`F0Text Snapshots renders with numberOfLines truncation 1`] = `
246
+ <Text
247
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
248
+ ellipsizeMode="tail"
249
+ numberOfLines={2}
250
+ >
251
+ This is a very long text that should be truncated after two lines with an ellipsis at the end
252
+ </Text>
253
+ `;
254
+
255
+ exports[`F0Text Snapshots renders with text decorations: decoration-line-through 1`] = `
256
+ <Text
257
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left line-through"
258
+ >
259
+ line-through
260
+ text
261
+ </Text>
262
+ `;
263
+
264
+ exports[`F0Text Snapshots renders with text decorations: decoration-none 1`] = `
265
+ <Text
266
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
267
+ >
268
+ none
269
+ text
270
+ </Text>
271
+ `;
272
+
273
+ exports[`F0Text Snapshots renders with text decorations: decoration-underline 1`] = `
274
+ <Text
275
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left underline"
276
+ >
277
+ underline
278
+ text
279
+ </Text>
280
+ `;
281
+
282
+ exports[`F0Text Snapshots renders with text transforms: transform-capitalize 1`] = `
283
+ <Text
284
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left capitalize"
285
+ >
286
+ capitalize
287
+ text
288
+ </Text>
289
+ `;
290
+
291
+ exports[`F0Text Snapshots renders with text transforms: transform-lowercase 1`] = `
292
+ <Text
293
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left lowercase"
294
+ >
295
+ lowercase
296
+ text
297
+ </Text>
298
+ `;
299
+
300
+ exports[`F0Text Snapshots renders with text transforms: transform-none 1`] = `
301
+ <Text
302
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left"
303
+ >
304
+ none
305
+ text
306
+ </Text>
307
+ `;
308
+
309
+ exports[`F0Text Snapshots renders with text transforms: transform-uppercase 1`] = `
310
+ <Text
311
+ className="text-[14px] leading-[20px] font-normal text-f0-foreground text-left uppercase"
312
+ >
313
+ uppercase
314
+ text
315
+ </Text>
316
+ `;
@@ -0,0 +1,227 @@
1
+ import { render } from "@testing-library/react-native"
2
+ import React from "react"
3
+ import { Text as RNText } from "react-native"
4
+
5
+ import { F0Text } from "../F0Text"
6
+
7
+ describe("F0Text", () => {
8
+ describe("Snapshots", () => {
9
+ it("renders with default variant (body-sm-default)", () => {
10
+ const { toJSON } = render(<F0Text>Default text</F0Text>)
11
+ expect(toJSON()).toMatchSnapshot()
12
+ })
13
+
14
+ it("renders all typography variants", () => {
15
+ const variants = [
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
+ <F0Text variant={variant}>{variant} text</F0Text>
31
+ )
32
+ expect(toJSON()).toMatchSnapshot(`variant-${variant}`)
33
+ })
34
+ })
35
+
36
+ it("renders all color variants", () => {
37
+ const colors = [
38
+ "default",
39
+ "secondary",
40
+ "tertiary",
41
+ "inverse",
42
+ "inverse-secondary",
43
+ "disabled",
44
+ "accent",
45
+ "critical",
46
+ "info",
47
+ "warning",
48
+ "positive",
49
+ "selected",
50
+ ] as const
51
+
52
+ colors.forEach((color) => {
53
+ const { toJSON } = render(<F0Text color={color}>{color} text</F0Text>)
54
+ expect(toJSON()).toMatchSnapshot(`color-${color}`)
55
+ })
56
+ })
57
+
58
+ it("renders with alignment options", () => {
59
+ const alignments = ["left", "center", "right", "justify"] as const
60
+
61
+ alignments.forEach((align) => {
62
+ const { toJSON } = render(<F0Text align={align}>{align} text</F0Text>)
63
+ expect(toJSON()).toMatchSnapshot(`align-${align}`)
64
+ })
65
+ })
66
+
67
+ it("renders with text decorations", () => {
68
+ const decorations = ["none", "underline", "line-through"] as const
69
+
70
+ decorations.forEach((decoration) => {
71
+ const { toJSON } = render(
72
+ <F0Text decoration={decoration}>{decoration} text</F0Text>
73
+ )
74
+ expect(toJSON()).toMatchSnapshot(`decoration-${decoration}`)
75
+ })
76
+ })
77
+
78
+ it("renders with text transforms", () => {
79
+ const transforms = [
80
+ "none",
81
+ "uppercase",
82
+ "lowercase",
83
+ "capitalize",
84
+ ] as const
85
+
86
+ transforms.forEach((transform) => {
87
+ const { toJSON } = render(
88
+ <F0Text transform={transform}>{transform} text</F0Text>
89
+ )
90
+ expect(toJSON()).toMatchSnapshot(`transform-${transform}`)
91
+ })
92
+ })
93
+
94
+ it("renders with numberOfLines truncation", () => {
95
+ const { toJSON } = render(
96
+ <F0Text numberOfLines={2}>
97
+ This is a very long text that should be truncated after two lines with
98
+ an ellipsis at the end
99
+ </F0Text>
100
+ )
101
+ expect(toJSON()).toMatchSnapshot()
102
+ })
103
+ })
104
+
105
+ describe("Behavior", () => {
106
+ it("renders children correctly", () => {
107
+ const { getByText } = render(<F0Text>Hello World</F0Text>)
108
+ expect(getByText("Hello World")).toBeTruthy()
109
+ })
110
+
111
+ it("applies correct variant classes", () => {
112
+ const { getByText } = render(
113
+ <F0Text variant="heading-lg">Large Heading</F0Text>
114
+ )
115
+ const element = getByText("Large Heading")
116
+ expect(element.props.className).toContain("text-[24px]")
117
+ expect(element.props.className).toContain("leading-[32px]")
118
+ expect(element.props.className).toContain("tracking-[-0.2px]")
119
+ expect(element.props.className).toContain("font-semibold")
120
+ })
121
+
122
+ it("applies correct color classes", () => {
123
+ const { getByText } = render(
124
+ <F0Text color="secondary">Secondary text</F0Text>
125
+ )
126
+ const element = getByText("Secondary text")
127
+ expect(element.props.className).toContain("text-f0-foreground-secondary")
128
+ })
129
+
130
+ it("applies correct alignment classes", () => {
131
+ const { getByText } = render(
132
+ <F0Text align="center">Centered text</F0Text>
133
+ )
134
+ const element = getByText("Centered text")
135
+ expect(element.props.className).toContain("text-center")
136
+ })
137
+
138
+ it("applies decoration classes", () => {
139
+ const { getByText } = render(
140
+ <F0Text decoration="underline">Underlined text</F0Text>
141
+ )
142
+ const element = getByText("Underlined text")
143
+ expect(element.props.className).toContain("underline")
144
+ })
145
+
146
+ it("applies transform classes", () => {
147
+ const { getByText } = render(
148
+ <F0Text transform="uppercase">uppercase text</F0Text>
149
+ )
150
+ const element = getByText("uppercase text")
151
+ expect(element.props.className).toContain("uppercase")
152
+ })
153
+
154
+ it("sets numberOfLines prop correctly", () => {
155
+ const { getByText } = render(
156
+ <F0Text numberOfLines={3}>Multiline text</F0Text>
157
+ )
158
+ const element = getByText("Multiline text")
159
+ expect(element.props.numberOfLines).toBe(3)
160
+ expect(element.props.ellipsizeMode).toBe("tail")
161
+ })
162
+
163
+ it("does not set ellipsizeMode when numberOfLines is not provided", () => {
164
+ const { getByText } = render(<F0Text>Normal text</F0Text>)
165
+ const element = getByText("Normal text")
166
+ expect(element.props.ellipsizeMode).toBeUndefined()
167
+ })
168
+
169
+ it("forwards additional props to React Native Text", () => {
170
+ const onPress = jest.fn()
171
+ const { getByText } = render(
172
+ <F0Text onPress={onPress} testID="test-text">
173
+ Pressable text
174
+ </F0Text>
175
+ )
176
+ const element = getByText("Pressable text")
177
+ expect(element.props.testID).toBe("test-text")
178
+ expect(element.props.onPress).toBe(onPress)
179
+ })
180
+
181
+ it("filters style prop at runtime (prevents override via spread)", () => {
182
+ const propsWithStyle = {
183
+ style: { color: "red" },
184
+ children: "Text with style attempt",
185
+ }
186
+ const { getByText } = render(
187
+ <F0Text {...(propsWithStyle as React.ComponentProps<typeof F0Text>)}>
188
+ Text with style attempt
189
+ </F0Text>
190
+ )
191
+ const element = getByText("Text with style attempt")
192
+ expect(element.props.style).toBeUndefined()
193
+ })
194
+
195
+ it("filters className prop at runtime (prevents override via spread)", () => {
196
+ const propsWithClassName = {
197
+ className: "font-bold text-red-500",
198
+ children: "Text with className attempt",
199
+ }
200
+ const { getByText } = render(
201
+ <F0Text
202
+ {...(propsWithClassName as React.ComponentProps<typeof F0Text>)}
203
+ >
204
+ Text with className attempt
205
+ </F0Text>
206
+ )
207
+ const element = getByText("Text with className attempt")
208
+ expect(element.props.className).not.toContain("font-bold")
209
+ expect(element.props.className).not.toContain("text-red-500")
210
+ })
211
+
212
+ it("handles ref forwarding", () => {
213
+ const ref = React.createRef<RNText>()
214
+ render(<F0Text ref={ref}>Ref text</F0Text>)
215
+ expect(ref.current).toBeTruthy()
216
+ })
217
+
218
+ it("renders nested children", () => {
219
+ const { getByText } = render(
220
+ <F0Text>
221
+ Parent <F0Text variant="body-xs-medium">nested</F0Text> text
222
+ </F0Text>
223
+ )
224
+ expect(getByText("nested")).toBeTruthy()
225
+ })
226
+ })
227
+ })
@@ -0,0 +1,22 @@
1
+ /**
2
+ * F0Text - Text primitive component
3
+ *
4
+ * @see F0Text.md for documentation
5
+ */
6
+
7
+ export { F0Text } from "./F0Text"
8
+ export type {
9
+ F0TextProps,
10
+ TypographyVariant,
11
+ TextColor,
12
+ TextAlign,
13
+ TextDecoration,
14
+ TextTransform,
15
+ } from "./F0Text"
16
+ export {
17
+ TYPOGRAPHY_VARIANTS,
18
+ TEXT_COLORS,
19
+ TEXT_ALIGN,
20
+ TEXT_DECORATIONS,
21
+ TEXT_TRANSFORMS,
22
+ } from "./F0Text"
@@ -12,7 +12,7 @@ const SvgQuestionCircle = (props: SvgProps, ref: Ref<Svg>) => (
12
12
  <Path
13
13
  fill="currentColor"
14
14
  fillRule="evenodd"
15
- d="M12 4.65C7.94071 4.65 4.65 7.94071 4.65 12C4.65 16.0593 7.94071 19.35 12 19.35C16.0593 19.35 19.35 16.0593 19.35 12C19.35 7.94071 16.0593 4.65 12 4.65ZM3.35 12C3.35 7.22274 7.22274 3.35 12 3.35C16.7773 3.35 20.65 7.22274 20.65 12C20.65 16.7773 16.7773 20.65 12 20.65C7.22274 20.65 3.35 16.7773 3.35 12ZM11.25 15.75C11.25 15.3358 11.5858 15 12 15C12.4142 15 12.75 15.3358 12.75 15.75C12.75 16.1642 12.4142 16.5 12 16.5C11.5858 16.5 11.25 16.1642 11.25 15.75ZM10.65 10.5C10.65 9.75442 11.2544 9.15 12 9.15C12.7456 9.15 13.35 9.75442 13.35 10.5V10.5645C13.35 11.2745 12.7745 11.85 12.0645 11.85C11.6699 11.85 11.35 12.1699 11.35 12.5645V13.5C11.35 13.859 11.641 14.15 12 14.15C12.359 14.15 12.65 13.859 12.65 13.5V13.0834C13.7959 12.8181 14.65 11.7911 14.65 10.5645V10.5C14.65 9.03645 13.4636 7.85 12 7.85C10.5364 7.85 9.35 9.03645 9.35 10.5C9.35 10.859 9.64102 11.15 10 11.15C10.359 11.15 10.65 10.859 10.65 10.5Z"
15
+ d="M12 4.65a7.35 7.35 0 1 0 0 14.7 7.35 7.35 0 0 0 0-14.7M3.35 12a8.65 8.65 0 1 1 17.3 0 8.65 8.65 0 0 1-17.3 0m7.9 3.75a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0m-.6-5.25a1.35 1.35 0 1 1 2.7 0v.065c0 .71-.575 1.285-1.285 1.285a.715.715 0 0 0-.715.715v.935a.65.65 0 1 0 1.3 0v-.417a2.586 2.586 0 0 0 2-2.518V10.5a2.65 2.65 0 1 0-5.3 0 .65.65 0 1 0 1.3 0"
16
16
  clipRule="evenodd"
17
17
  />
18
18
  </Svg>
@@ -34,6 +34,7 @@ export { default as PersonPlus } from "./PersonPlus"
34
34
  export { default as Pig } from "./Pig"
35
35
  export { default as PushPin } from "./PushPin"
36
36
  export { default as PushPinSolid } from "./PushPinSolid"
37
+ export { default as QuestionCircle } from "./QuestionCircle"
37
38
  export { default as Record } from "./Record"
38
39
  export { default as Shield } from "./Shield"
39
40
  export { default as SignPost } from "./SignPost"
@@ -196,7 +197,6 @@ export { default as Present } from "./Present"
196
197
  export { default as Printer } from "./Printer"
197
198
  export { default as Proyector } from "./Proyector"
198
199
  export { default as Question } from "./Question"
199
- export { default as QuestionCircle } from "./QuestionCircle"
200
200
  export { default as Quote } from "./Quote"
201
201
  export { default as Reaction } from "./Reaction"
202
202
  export { default as Receipt } from "./Receipt"
package/src/index.ts CHANGED
@@ -5,4 +5,4 @@ export * from "./components/exports"
5
5
  export * from "./icons"
6
6
 
7
7
  // Export utilities
8
- export { cn } from "./lib/utils"
8
+ export { cn, omitProps } from "./lib/utils"
@@ -0,0 +1,48 @@
1
+ import { cn, omitProps } from "../utils"
2
+
3
+ describe("utils", () => {
4
+ describe("omitProps", () => {
5
+ it("returns empty object when given empty object", () => {
6
+ expect(omitProps({}, ["style"])).toEqual({})
7
+ })
8
+
9
+ it("returns all props when no keys to omit", () => {
10
+ const props = { a: 1, b: 2, c: 3 }
11
+ expect(omitProps(props, [])).toEqual(props)
12
+ })
13
+
14
+ it("omits single key", () => {
15
+ const props = { a: 1, b: 2, style: { color: "red" } }
16
+ expect(omitProps(props, ["style"])).toEqual({ a: 1, b: 2 })
17
+ })
18
+
19
+ it("omits multiple keys", () => {
20
+ const props = { a: 1, style: { color: "red" }, className: "text-lg" }
21
+ expect(omitProps(props, ["style", "className"])).toEqual({ a: 1 })
22
+ })
23
+
24
+ it("does not mutate original object", () => {
25
+ const props = { a: 1, style: { color: "red" } }
26
+ omitProps(props, ["style"])
27
+ expect(props).toEqual({ a: 1, style: { color: "red" } })
28
+ })
29
+
30
+ it("works with readonly keys array (F0_TEXT_BANNED_PROPS pattern)", () => {
31
+ const BANNED = ["style"] as const
32
+ const props = { a: 1, style: { color: "red" } }
33
+ expect(omitProps(props, BANNED)).toEqual({ a: 1 })
34
+ })
35
+
36
+ it("ignores keys that do not exist", () => {
37
+ const props = { a: 1, b: 2 }
38
+ expect(omitProps(props, ["style", "className"])).toEqual({ a: 1, b: 2 })
39
+ })
40
+ })
41
+
42
+ describe("cn", () => {
43
+ it("merges class names", () => {
44
+ expect(cn("foo", "bar")).toContain("foo")
45
+ expect(cn("foo", "bar")).toContain("bar")
46
+ })
47
+ })
48
+ })
package/src/lib/utils.ts CHANGED
@@ -7,3 +7,22 @@ export function cn(...args: CnOptions): string {
7
7
  }) ?? ""
8
8
  )
9
9
  }
10
+
11
+ /**
12
+ * Omits specified keys from an object at runtime.
13
+ * Used to filter blocked props (e.g. style, className) before spreading to primitives.
14
+ *
15
+ * @example
16
+ * omitProps(rest, ["style"])
17
+ * omitProps(rest, ["style", "className"])
18
+ */
19
+ export function omitProps<T extends Record<string, unknown>, K extends string>(
20
+ obj: T,
21
+ keys: readonly K[]
22
+ ): Omit<T, K> {
23
+ const result = { ...obj }
24
+ for (const key of keys) {
25
+ delete result[key as keyof T]
26
+ }
27
+ return result as Omit<T, K>
28
+ }