@factorialco/f0-react-native 0.29.0 → 0.30.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 (100) hide show
  1. package/lib/module/components/Avatars/IconAvatar/index.js +1 -1
  2. package/lib/module/components/Avatars/IconAvatar/index.js.map +1 -1
  3. package/lib/module/components/Avatars/ModuleAvatar/index.js +1 -1
  4. package/lib/module/components/Avatars/ModuleAvatar/index.js.map +1 -1
  5. package/lib/module/components/Badge/index.js +1 -1
  6. package/lib/module/components/Badge/index.js.map +1 -1
  7. package/lib/module/components/Button/index.js +1 -1
  8. package/lib/module/components/Button/index.js.map +1 -1
  9. package/lib/module/components/Button/index.spec.js +1 -1
  10. package/lib/module/components/Button/index.spec.js.map +1 -1
  11. package/lib/module/components/Icon/index.js +1 -1
  12. package/lib/module/components/Icon/index.js.map +1 -1
  13. package/lib/module/components/OneChip/index.js +1 -1
  14. package/lib/module/components/OneChip/index.js.map +1 -1
  15. package/lib/module/components/Tags/AlertTab/index.js +1 -1
  16. package/lib/module/components/Tags/AlertTab/index.js.map +1 -1
  17. package/lib/module/components/Tags/RawTag/index.js +1 -1
  18. package/lib/module/components/Tags/RawTag/index.js.map +1 -1
  19. package/lib/module/components/experimental/Lists/DataList/ItemContainer.js +1 -1
  20. package/lib/module/components/experimental/Lists/DataList/ItemContainer.js.map +1 -1
  21. package/lib/module/components/experimental/Lists/DataList/actions/CopyAction.js +1 -1
  22. package/lib/module/components/experimental/Lists/DataList/actions/CopyAction.js.map +1 -1
  23. package/lib/module/components/experimental/Lists/DataList/actions/GenericAction.js +1 -1
  24. package/lib/module/components/experimental/Lists/DataList/actions/GenericAction.js.map +1 -1
  25. package/lib/module/components/exports.js +1 -1
  26. package/lib/module/components/exports.js.map +1 -1
  27. package/lib/module/components/primitives/F0Icon/F0Icon.js +2 -0
  28. package/lib/module/components/primitives/F0Icon/F0Icon.js.map +1 -0
  29. package/lib/module/components/primitives/F0Icon/F0Icon.md +187 -0
  30. package/lib/module/components/primitives/F0Icon/F0Icon.styles.js +2 -0
  31. package/lib/module/components/primitives/F0Icon/F0Icon.styles.js.map +1 -0
  32. package/lib/module/components/primitives/F0Icon/F0Icon.types.js +2 -0
  33. package/lib/module/components/primitives/F0Icon/F0Icon.types.js.map +1 -0
  34. package/lib/module/components/primitives/F0Icon/index.js +2 -0
  35. package/lib/module/components/primitives/F0Icon/index.js.map +1 -0
  36. package/lib/module/icons/index.js +1 -1
  37. package/lib/module/icons/index.js.map +1 -1
  38. package/lib/typescript/components/Activity/ActivityItem/index.d.ts +1 -1
  39. package/lib/typescript/components/Activity/ActivityItem/index.d.ts.map +1 -1
  40. package/lib/typescript/components/Avatars/IconAvatar/index.d.ts +1 -1
  41. package/lib/typescript/components/Avatars/IconAvatar/index.d.ts.map +1 -1
  42. package/lib/typescript/components/Avatars/ModuleAvatar/index.d.ts +1 -1
  43. package/lib/typescript/components/Avatars/ModuleAvatar/index.d.ts.map +1 -1
  44. package/lib/typescript/components/Badge/index.d.ts +1 -1
  45. package/lib/typescript/components/Badge/index.d.ts.map +1 -1
  46. package/lib/typescript/components/Button/index.d.ts +1 -1
  47. package/lib/typescript/components/Button/index.d.ts.map +1 -1
  48. package/lib/typescript/components/Icon/index.d.ts +7 -14
  49. package/lib/typescript/components/Icon/index.d.ts.map +1 -1
  50. package/lib/typescript/components/OneChip/index.d.ts +1 -1
  51. package/lib/typescript/components/OneChip/index.d.ts.map +1 -1
  52. package/lib/typescript/components/Tags/RawTag/index.d.ts +1 -1
  53. package/lib/typescript/components/Tags/RawTag/index.d.ts.map +1 -1
  54. package/lib/typescript/components/experimental/Lists/DataList/ItemContainer.d.ts +1 -1
  55. package/lib/typescript/components/experimental/Lists/DataList/ItemContainer.d.ts.map +1 -1
  56. package/lib/typescript/components/experimental/Lists/DataList/actions/CopyAction.d.ts.map +1 -1
  57. package/lib/typescript/components/experimental/Lists/DataList/index.d.ts +1 -1
  58. package/lib/typescript/components/experimental/Lists/DataList/index.d.ts.map +1 -1
  59. package/lib/typescript/components/exports.d.ts +2 -1
  60. package/lib/typescript/components/exports.d.ts.map +1 -1
  61. package/lib/typescript/components/primitives/F0Icon/F0Icon.d.ts +25 -0
  62. package/lib/typescript/components/primitives/F0Icon/F0Icon.d.ts.map +1 -0
  63. package/lib/typescript/components/primitives/F0Icon/F0Icon.styles.d.ts +90 -0
  64. package/lib/typescript/components/primitives/F0Icon/F0Icon.styles.d.ts.map +1 -0
  65. package/lib/typescript/components/primitives/F0Icon/F0Icon.types.d.ts +47 -0
  66. package/lib/typescript/components/primitives/F0Icon/F0Icon.types.d.ts.map +1 -0
  67. package/lib/typescript/components/primitives/F0Icon/index.d.ts +10 -0
  68. package/lib/typescript/components/primitives/F0Icon/index.d.ts.map +1 -0
  69. package/lib/typescript/icons/index.d.ts +0 -1
  70. package/lib/typescript/icons/index.d.ts.map +1 -1
  71. package/package.json +1 -1
  72. package/src/components/Activity/ActivityItem/index.spec.tsx +1 -1
  73. package/src/components/Activity/ActivityItem/index.tsx +1 -1
  74. package/src/components/Avatars/IconAvatar/index.tsx +6 -2
  75. package/src/components/Avatars/ModuleAvatar/index.tsx +1 -1
  76. package/src/components/Badge/index.tsx +2 -2
  77. package/src/components/Button/index.spec.tsx +3 -4
  78. package/src/components/Button/index.tsx +19 -13
  79. package/src/components/Icon/__tests__/Icon.spec.tsx +0 -4
  80. package/src/components/Icon/index.tsx +7 -26
  81. package/src/components/OneChip/index.tsx +3 -3
  82. package/src/components/Tags/AlertTab/index.tsx +2 -2
  83. package/src/components/Tags/RawTag/index.tsx +2 -2
  84. package/src/components/experimental/Lists/DataList/ItemContainer.tsx +2 -2
  85. package/src/components/experimental/Lists/DataList/actions/CopyAction.tsx +7 -10
  86. package/src/components/experimental/Lists/DataList/actions/GenericAction.tsx +2 -2
  87. package/src/components/experimental/Lists/DataList/index.tsx +1 -1
  88. package/src/components/experimental/Lists/DetailsItem/__snapshots__/index.spec.tsx.snap +4 -4
  89. package/src/components/experimental/Lists/DetailsItemsList/__snapshots__/index.spec.tsx.snap +1 -1
  90. package/src/components/exports.ts +2 -1
  91. package/src/components/primitives/F0Icon/F0Icon.md +187 -0
  92. package/src/components/primitives/F0Icon/F0Icon.styles.ts +43 -0
  93. package/src/components/primitives/F0Icon/F0Icon.tsx +73 -0
  94. package/src/components/primitives/F0Icon/F0Icon.types.ts +77 -0
  95. package/src/components/primitives/F0Icon/__tests__/F0Icon.spec.tsx +131 -0
  96. package/src/components/primitives/F0Icon/__tests__/F0Icon.tokens.spec.ts +39 -0
  97. package/src/components/primitives/F0Icon/index.ts +10 -0
  98. package/src/icons/index.ts +0 -1
  99. package/lib/module/components/Icon/README.md +0 -63
  100. package/src/components/Icon/README.md +0 -63
@@ -0,0 +1,77 @@
1
+ import type { ForwardRefExoticComponent, RefAttributes } from "react"
2
+ import type { SvgProps } from "react-native-svg"
3
+ import type { Svg } from "react-native-svg"
4
+ import type { VariantProps } from "tailwind-variants"
5
+
6
+ import type { iconVariants } from "./F0Icon.styles"
7
+
8
+ /**
9
+ * Icon component type - forward ref to SVG component with className support
10
+ */
11
+ export type IconType = ForwardRefExoticComponent<
12
+ SvgProps &
13
+ RefAttributes<Svg> & {
14
+ className?: string
15
+ }
16
+ >
17
+
18
+ /**
19
+ * Icon color variants derived from f0-icon-* tokens in src/styles/theme.css
20
+ * Sync is enforced by F0Icon.tokens.spec.ts
21
+ */
22
+ export const ICON_COLORS = [
23
+ "default",
24
+ "secondary",
25
+ "inverse",
26
+ "bold",
27
+ "critical",
28
+ "critical-bold",
29
+ "accent",
30
+ "info",
31
+ "warning",
32
+ "positive",
33
+ "promote",
34
+ "selected",
35
+ "selected-hover",
36
+ "mood-super-negative",
37
+ "mood-negative",
38
+ "mood-neutral",
39
+ "mood-positive",
40
+ "mood-super-positive",
41
+ ] as const
42
+
43
+ export type IconColor = (typeof ICON_COLORS)[number]
44
+
45
+ /**
46
+ * Public F0Icon props
47
+ * Supports semantic color via `color` prop, with `className` as escape hatch.
48
+ */
49
+ export interface F0IconProps extends Omit<SvgProps, "style"> {
50
+ /**
51
+ * Tailwind className for custom styling or color overrides.
52
+ * Prefer the `color` prop for semantic icon colors.
53
+ */
54
+ className?: string
55
+
56
+ /**
57
+ * Semantic icon color from the F0 design system
58
+ * Maps to f0-icon-* tokens (e.g. color="critical" -> text-f0-icon-critical)
59
+ */
60
+ color?: IconColor
61
+
62
+ /**
63
+ * Icon component to render (from icons directory)
64
+ */
65
+ icon: IconType
66
+
67
+ /**
68
+ * Icon size variant
69
+ * @default 'md'
70
+ */
71
+ size?: VariantProps<typeof iconVariants>["size"]
72
+
73
+ /**
74
+ * Test ID for testing
75
+ */
76
+ testID?: string
77
+ }
@@ -0,0 +1,131 @@
1
+ import { render } from "@testing-library/react-native"
2
+ import React from "react"
3
+
4
+ import { Archive } from "../../../../icons/app"
5
+ import { Home } from "../../../../icons/modules"
6
+ import { applyIconInterop } from "../F0Icon"
7
+ import F0Icon from "../F0Icon"
8
+
9
+ describe("F0Icon", () => {
10
+ it("renders correctly with an app icon", () => {
11
+ const { getByTestId } = render(<F0Icon icon={Archive} testID="icon" />)
12
+ expect(getByTestId("icon")).toBeTruthy()
13
+ })
14
+
15
+ it("renders correctly with a module icon", () => {
16
+ const { getByTestId } = render(<F0Icon icon={Home} testID="icon" />)
17
+ expect(getByTestId("icon")).toBeTruthy()
18
+ })
19
+
20
+ it("applies the correct size variant", () => {
21
+ const { getByTestId } = render(
22
+ <F0Icon icon={Archive} size="lg" testID="icon" />
23
+ )
24
+ expect(getByTestId("icon")).toBeTruthy()
25
+ })
26
+
27
+ it("returns null when no icon is provided", () => {
28
+ // @ts-expect-error - Testing runtime behavior
29
+ const { queryByTestId } = render(<F0Icon testID="icon" />)
30
+ expect(queryByTestId("icon")).toBeNull()
31
+ })
32
+
33
+ it("applies default size when size prop is not provided", () => {
34
+ const { getByTestId } = render(<F0Icon icon={Archive} testID="icon" />)
35
+ expect(getByTestId("icon")).toBeTruthy()
36
+ })
37
+
38
+ it("forwards ref correctly", () => {
39
+ const ref = React.createRef<React.ElementRef<typeof F0Icon>>()
40
+ render(<F0Icon icon={Archive} ref={ref} testID="icon" />)
41
+ expect(ref.current).toBeTruthy()
42
+ })
43
+
44
+ it("renders with a color prop", () => {
45
+ const { getByTestId } = render(
46
+ <F0Icon icon={Archive} color="critical" testID="icon" />
47
+ )
48
+ expect(getByTestId("icon")).toBeTruthy()
49
+ })
50
+
51
+ it("caches wrapped icon: applyIconInterop returns same instance for same icon", () => {
52
+ const wrapped1 = applyIconInterop(Archive)
53
+ const wrapped2 = applyIconInterop(Archive)
54
+ expect(wrapped1).toBe(wrapped2)
55
+ })
56
+
57
+ it("caches per icon type: different icons return different wrapped instances", () => {
58
+ const wrappedArchive = applyIconInterop(Archive)
59
+ const wrappedHome = applyIconInterop(Home)
60
+ expect(wrappedArchive).not.toBe(wrappedHome)
61
+ })
62
+
63
+ it("renders with both color and className", () => {
64
+ const { getByTestId } = render(
65
+ <F0Icon icon={Archive} color="info" className="-ml-0.5" testID="icon" />
66
+ )
67
+ expect(getByTestId("icon")).toBeTruthy()
68
+ })
69
+
70
+ describe("className — cn() merging", () => {
71
+ it("passes through layout classes from className", () => {
72
+ const { getByTestId } = render(
73
+ <F0Icon icon={Archive} className="-ml-0.5" testID="icon" />
74
+ )
75
+ const element = getByTestId("icon")
76
+ expect(element.props.className).toContain("-ml-0.5")
77
+ })
78
+
79
+ it("merges conflicting size: custom w-* overrides variant", () => {
80
+ const { getByTestId } = render(
81
+ <F0Icon icon={Archive} size="md" className="h-10 w-10" testID="icon" />
82
+ )
83
+ const element = getByTestId("icon")
84
+ expect(element.props.className).toContain("w-10")
85
+ expect(element.props.className).toContain("h-10")
86
+ expect(element.props.className).not.toContain("w-5")
87
+ expect(element.props.className).not.toContain("h-5")
88
+ })
89
+
90
+ it("merges conflicting color: custom text-* overrides variant", () => {
91
+ const { getByTestId } = render(
92
+ <F0Icon
93
+ icon={Archive}
94
+ color="critical"
95
+ className="text-red-500"
96
+ testID="icon"
97
+ />
98
+ )
99
+ const element = getByTestId("icon")
100
+ expect(element.props.className).toContain("text-red-500")
101
+ expect(element.props.className).not.toContain("text-f0-icon-critical")
102
+ })
103
+
104
+ it("uses only variant classes when className is undefined", () => {
105
+ const { getByTestId } = render(
106
+ <F0Icon icon={Archive} size="sm" color="positive" testID="icon" />
107
+ )
108
+ const element = getByTestId("icon")
109
+ expect(element.props.className).toContain("w-4")
110
+ expect(element.props.className).toContain("h-4")
111
+ expect(element.props.className).toContain("text-f0-icon-positive")
112
+ })
113
+
114
+ it("combines non-conflicting variant and className", () => {
115
+ const { getByTestId } = render(
116
+ <F0Icon
117
+ icon={Archive}
118
+ size="lg"
119
+ color="info"
120
+ className="opacity-50"
121
+ testID="icon"
122
+ />
123
+ )
124
+ const element = getByTestId("icon")
125
+ expect(element.props.className).toContain("w-6")
126
+ expect(element.props.className).toContain("h-6")
127
+ expect(element.props.className).toContain("text-f0-icon-info")
128
+ expect(element.props.className).toContain("opacity-50")
129
+ })
130
+ })
131
+ })
@@ -0,0 +1,39 @@
1
+ // @ts-ignore - Node built-ins are available in Jest runtime
2
+ import fs from "fs"
3
+ // @ts-ignore - Node built-ins are available in Jest runtime
4
+ import path from "path"
5
+
6
+ import { ICON_COLORS } from "../F0Icon.types"
7
+
8
+ describe("F0Icon token sync", () => {
9
+ it("ICON_COLORS matches f0-icon-* tokens in theme.css", () => {
10
+ const css = fs.readFileSync(
11
+ // @ts-ignore - __dirname is available in Jest runtime
12
+ path.resolve(__dirname, "../../../../styles/theme.css"),
13
+ "utf-8"
14
+ )
15
+
16
+ // Extract all --color-f0-icon-<name> tokens, excluding sub-tokens
17
+ // that are already captured (e.g. --color-f0-icon-mood-positive
18
+ // but not --color-f0-icon which maps to "default")
19
+ const tokenRegex = /--color-f0-icon-([a-z0-9][a-z0-9-]*):/g
20
+ const tokensFromCSS = new Set<string>()
21
+ let match: RegExpExecArray | null
22
+ while ((match = tokenRegex.exec(css)) !== null) {
23
+ tokensFromCSS.add(match[1])
24
+ }
25
+
26
+ // "default" in ICON_COLORS maps to the base --color-f0-icon token
27
+ const colorsFromType = new Set<string>(
28
+ ICON_COLORS.filter((c) => c !== "default")
29
+ )
30
+
31
+ const missingInType = [...tokensFromCSS].filter(
32
+ (t) => !colorsFromType.has(t)
33
+ )
34
+ const extraInType = [...colorsFromType].filter((t) => !tokensFromCSS.has(t))
35
+
36
+ expect(missingInType).toEqual([])
37
+ expect(extraInType).toEqual([])
38
+ })
39
+ })
@@ -0,0 +1,10 @@
1
+ /**
2
+ * F0Icon - Icon primitive component
3
+ *
4
+ * @see F0Icon.md for documentation
5
+ */
6
+
7
+ export { default as F0Icon } from "./F0Icon"
8
+ export type { F0IconProps, IconType, IconColor } from "./F0Icon.types"
9
+ export { ICON_COLORS } from "./F0Icon.types"
10
+ export { applyIconInterop } from "./F0Icon"
@@ -2,4 +2,3 @@ import * as AppIcons from "./app"
2
2
  import * as ModuleIcons from "./modules"
3
3
  export { AppIcons, ModuleIcons }
4
4
  export * from "./types"
5
- export { Icon } from "../components/Icon"
@@ -1,63 +0,0 @@
1
- # Icon Component
2
-
3
- The Icon component is used to render SVG icons from the F0 Design System in React Native applications.
4
-
5
- ## Import Pattern
6
-
7
- ```tsx
8
- // Import the Icon component
9
- import { Icon } from "@factorialco/f0-react-native";
10
-
11
- // Import specific icons from app or modules directories
12
- import { AppIcons, ModuleIcons } from "@factorialco/f0-react-native";
13
-
14
- // Use the Icon component with the icon as a prop
15
- <Icon icon={AppIcons.Archive} size="md" />
16
- <Icon icon={ModuleIcons.Home} size="lg" />
17
- ```
18
-
19
- ## Props
20
-
21
- | Prop | Type | Default | Description |
22
- | --------- | ---------------------------- | ------- | --------------------------------------- |
23
- | icon | IconType | | The icon component to render |
24
- | size | "xs" \| "sm" \| "md" \| "lg" | "md" | The size of the icon |
25
- | className | string | | Additional classes for styling the icon |
26
- | testID | string | | Test ID for testing |
27
- | ...props | SvgProps | | Additional props for the SVG component |
28
-
29
- ## Styling with UniWind
30
-
31
- The Icon component is designed to work with UniWind, allowing you to style icons using Tailwind CSS classes:
32
-
33
- ```tsx
34
- // Style using Tailwind CSS classes
35
- <Icon icon={AppIcons.Archive} className="text-f0-icon-secondary" />
36
- ```
37
-
38
- ## Available Icons
39
-
40
- The library includes two sets of icons:
41
-
42
- 1. **App Icons** - General purpose icons used throughout the application
43
- 2. **Module Icons** - Icons representing specific modules in the Factorial application
44
-
45
- ## Examples
46
-
47
- ```tsx
48
- import { Icon } from "@factorialco/f0-react-native";
49
- import { AppIcons, ModuleIcons } from "@factorialco/f0-react-native";
50
-
51
- // Basic usage
52
- <Icon icon={AppIcons.Calendar} />
53
-
54
- // With size variant
55
- <Icon icon={AppIcons.ChevronDown} size="xs" />
56
- <Icon icon={AppIcons.Check} size="sm" />
57
- <Icon icon={ModuleIcons.Home} size="md" />
58
- <Icon icon={ModuleIcons.Settings} size="lg" />
59
-
60
- // With color styling
61
- <Icon icon={AppIcons.Heart} className="text-red-500" />
62
- <Icon icon={AppIcons.InfoCircle} className="text-blue-500" />
63
- ```
@@ -1,63 +0,0 @@
1
- # Icon Component
2
-
3
- The Icon component is used to render SVG icons from the F0 Design System in React Native applications.
4
-
5
- ## Import Pattern
6
-
7
- ```tsx
8
- // Import the Icon component
9
- import { Icon } from "@factorialco/f0-react-native";
10
-
11
- // Import specific icons from app or modules directories
12
- import { AppIcons, ModuleIcons } from "@factorialco/f0-react-native";
13
-
14
- // Use the Icon component with the icon as a prop
15
- <Icon icon={AppIcons.Archive} size="md" />
16
- <Icon icon={ModuleIcons.Home} size="lg" />
17
- ```
18
-
19
- ## Props
20
-
21
- | Prop | Type | Default | Description |
22
- | --------- | ---------------------------- | ------- | --------------------------------------- |
23
- | icon | IconType | | The icon component to render |
24
- | size | "xs" \| "sm" \| "md" \| "lg" | "md" | The size of the icon |
25
- | className | string | | Additional classes for styling the icon |
26
- | testID | string | | Test ID for testing |
27
- | ...props | SvgProps | | Additional props for the SVG component |
28
-
29
- ## Styling with UniWind
30
-
31
- The Icon component is designed to work with UniWind, allowing you to style icons using Tailwind CSS classes:
32
-
33
- ```tsx
34
- // Style using Tailwind CSS classes
35
- <Icon icon={AppIcons.Archive} className="text-f0-icon-secondary" />
36
- ```
37
-
38
- ## Available Icons
39
-
40
- The library includes two sets of icons:
41
-
42
- 1. **App Icons** - General purpose icons used throughout the application
43
- 2. **Module Icons** - Icons representing specific modules in the Factorial application
44
-
45
- ## Examples
46
-
47
- ```tsx
48
- import { Icon } from "@factorialco/f0-react-native";
49
- import { AppIcons, ModuleIcons } from "@factorialco/f0-react-native";
50
-
51
- // Basic usage
52
- <Icon icon={AppIcons.Calendar} />
53
-
54
- // With size variant
55
- <Icon icon={AppIcons.ChevronDown} size="xs" />
56
- <Icon icon={AppIcons.Check} size="sm" />
57
- <Icon icon={ModuleIcons.Home} size="md" />
58
- <Icon icon={ModuleIcons.Settings} size="lg" />
59
-
60
- // With color styling
61
- <Icon icon={AppIcons.Heart} className="text-red-500" />
62
- <Icon icon={AppIcons.InfoCircle} className="text-blue-500" />
63
- ```