@factorialco/f0-react-native 0.19.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.
Files changed (310) hide show
  1. package/README.md +54 -0
  2. package/package.json +84 -0
  3. package/src/components/Activity/ActivityItem/__snapshots__/index.spec.tsx.snap +62 -0
  4. package/src/components/Activity/ActivityItem/index.spec.tsx +103 -0
  5. package/src/components/Activity/ActivityItem/index.tsx +90 -0
  6. package/src/components/Avatars/Avatar.tsx +56 -0
  7. package/src/components/Avatars/BaseAvatar/index.tsx +126 -0
  8. package/src/components/Avatars/BaseAvatar/utils.ts +73 -0
  9. package/src/components/Avatars/CompanyAvatar/__snapshots__/index.spec.tsx.snap +25 -0
  10. package/src/components/Avatars/CompanyAvatar/index.spec.tsx +11 -0
  11. package/src/components/Avatars/CompanyAvatar/index.tsx +36 -0
  12. package/src/components/Avatars/DateAvatar/__snapshots__/index.spec.tsx.snap +18 -0
  13. package/src/components/Avatars/DateAvatar/index.spec.tsx +12 -0
  14. package/src/components/Avatars/DateAvatar/index.tsx +22 -0
  15. package/src/components/Avatars/EmojiAvatar/__snapshots__/index.spec.tsx.snap +37 -0
  16. package/src/components/Avatars/EmojiAvatar/index.spec.tsx +15 -0
  17. package/src/components/Avatars/EmojiAvatar/index.tsx +37 -0
  18. package/src/components/Avatars/FileAvatar/__snapshots__/index.spec.tsx.snap +261 -0
  19. package/src/components/Avatars/FileAvatar/index.spec.tsx +43 -0
  20. package/src/components/Avatars/FileAvatar/index.tsx +117 -0
  21. package/src/components/Avatars/FileAvatar/utils.ts +103 -0
  22. package/src/components/Avatars/IconAvatar/__snapshots__/index.spec.tsx.snap +256 -0
  23. package/src/components/Avatars/IconAvatar/index.spec.tsx +16 -0
  24. package/src/components/Avatars/IconAvatar/index.tsx +31 -0
  25. package/src/components/Avatars/ModuleAvatar/index.tsx +106 -0
  26. package/src/components/Avatars/ModuleAvatar/modules.ts +64 -0
  27. package/src/components/Avatars/PersonAvatar/__snapshots__/index.spec.tsx.snap +25 -0
  28. package/src/components/Avatars/PersonAvatar/index.spec.tsx +13 -0
  29. package/src/components/Avatars/PersonAvatar/index.tsx +38 -0
  30. package/src/components/Avatars/TeamAvatar/__snapshots__/index.spec.tsx.snap +25 -0
  31. package/src/components/Avatars/TeamAvatar/index.spec.tsx +11 -0
  32. package/src/components/Avatars/TeamAvatar/index.tsx +36 -0
  33. package/src/components/Avatars/exports.ts +9 -0
  34. package/src/components/Avatars/types.ts +15 -0
  35. package/src/components/Badge/index.tsx +47 -0
  36. package/src/components/Button/__snapshots__/index.spec.tsx.snap +517 -0
  37. package/src/components/Button/index.spec.tsx +124 -0
  38. package/src/components/Button/index.tsx +233 -0
  39. package/src/components/Counter/__snapshots__/index.spec.tsx.snap +113 -0
  40. package/src/components/Counter/index.spec.tsx +53 -0
  41. package/src/components/Counter/index.tsx +59 -0
  42. package/src/components/ExampleComponent.tsx +22 -0
  43. package/src/components/Icon/README.md +63 -0
  44. package/src/components/Icon/__tests__/Icon.spec.tsx +35 -0
  45. package/src/components/Icon/index.tsx +85 -0
  46. package/src/components/Navigation/PageHeader/__snapshots__/index.spec.tsx.snap +242 -0
  47. package/src/components/Navigation/PageHeader/index.spec.tsx +198 -0
  48. package/src/components/Navigation/PageHeader/index.tsx +53 -0
  49. package/src/components/OneChip/__snapshots__/index.spec.tsx.snap +366 -0
  50. package/src/components/OneChip/index.spec.tsx +69 -0
  51. package/src/components/OneChip/index.tsx +89 -0
  52. package/src/components/OnePreset/__snapshots__/index.spec.tsx.snap +149 -0
  53. package/src/components/OnePreset/index.spec.tsx +46 -0
  54. package/src/components/OnePreset/index.tsx +36 -0
  55. package/src/components/Tags/AlertTab/__snapshots__/index.spec.tsx.snap +292 -0
  56. package/src/components/Tags/AlertTab/index.spec.tsx +18 -0
  57. package/src/components/Tags/AlertTab/index.tsx +61 -0
  58. package/src/components/Tags/BaseTag/index.tsx +64 -0
  59. package/src/components/Tags/DotTag/__snapshots__/index.spec.tsx.snap +1081 -0
  60. package/src/components/Tags/DotTag/index.spec.tsx +14 -0
  61. package/src/components/Tags/DotTag/index.tsx +54 -0
  62. package/src/components/Tags/RawTag/__snapshots__/index.spec.tsx.snap +213 -0
  63. package/src/components/Tags/RawTag/index.spec.tsx +19 -0
  64. package/src/components/Tags/RawTag/index.tsx +41 -0
  65. package/src/components/Tags/Tag.tsx +32 -0
  66. package/src/components/Tags/exports.ts +3 -0
  67. package/src/components/__tests__/ExampleComponent.spec.tsx +16 -0
  68. package/src/components/experimental/Lists/DataList/ItemContainer.tsx +74 -0
  69. package/src/components/experimental/Lists/DataList/actions/CopyAction.tsx +72 -0
  70. package/src/components/experimental/Lists/DataList/actions/GenericAction.tsx +37 -0
  71. package/src/components/experimental/Lists/DataList/index.tsx +186 -0
  72. package/src/components/experimental/Lists/DetailsItem/__snapshots__/index.spec.tsx.snap +759 -0
  73. package/src/components/experimental/Lists/DetailsItem/index.spec.tsx +81 -0
  74. package/src/components/experimental/Lists/DetailsItem/index.tsx +68 -0
  75. package/src/components/experimental/Lists/DetailsItemsList/__snapshots__/index.spec.tsx.snap +671 -0
  76. package/src/components/experimental/Lists/DetailsItemsList/index.spec.tsx +73 -0
  77. package/src/components/experimental/Lists/DetailsItemsList/index.tsx +52 -0
  78. package/src/icons/app/AcademicCap.tsx +31 -0
  79. package/src/icons/app/Add.tsx +21 -0
  80. package/src/icons/app/Ai.tsx +24 -0
  81. package/src/icons/app/Alert.tsx +16 -0
  82. package/src/icons/app/AlertCircle.tsx +19 -0
  83. package/src/icons/app/AlertCircleLine.tsx +17 -0
  84. package/src/icons/app/AlignTextCenter.tsx +21 -0
  85. package/src/icons/app/AlignTextJustify.tsx +21 -0
  86. package/src/icons/app/AlignTextLeft.tsx +21 -0
  87. package/src/icons/app/AlignTextRight.tsx +21 -0
  88. package/src/icons/app/Appearance.tsx +33 -0
  89. package/src/icons/app/Archive.tsx +21 -0
  90. package/src/icons/app/ArchiveOpen.tsx +21 -0
  91. package/src/icons/app/ArrowCycle.tsx +27 -0
  92. package/src/icons/app/ArrowDown.tsx +27 -0
  93. package/src/icons/app/ArrowLeft.tsx +21 -0
  94. package/src/icons/app/ArrowRight.tsx +21 -0
  95. package/src/icons/app/ArrowUp.tsx +21 -0
  96. package/src/icons/app/Bank.tsx +20 -0
  97. package/src/icons/app/BarGraph.tsx +21 -0
  98. package/src/icons/app/Bell.tsx +24 -0
  99. package/src/icons/app/Bold.tsx +23 -0
  100. package/src/icons/app/BookOpen.tsx +21 -0
  101. package/src/icons/app/Briefcase.tsx +18 -0
  102. package/src/icons/app/Bucket.tsx +23 -0
  103. package/src/icons/app/Building.tsx +25 -0
  104. package/src/icons/app/Bullet.tsx +19 -0
  105. package/src/icons/app/Calculator.tsx +17 -0
  106. package/src/icons/app/Calendar.tsx +21 -0
  107. package/src/icons/app/CalendarArrowDown.tsx +21 -0
  108. package/src/icons/app/CalendarArrowLeft.tsx +21 -0
  109. package/src/icons/app/CalendarArrowRight.tsx +21 -0
  110. package/src/icons/app/CameraPlus.tsx +22 -0
  111. package/src/icons/app/ChartLine.tsx +26 -0
  112. package/src/icons/app/ChartPie.tsx +25 -0
  113. package/src/icons/app/Check.tsx +21 -0
  114. package/src/icons/app/CheckCircle.tsx +21 -0
  115. package/src/icons/app/CheckCircleLine.tsx +22 -0
  116. package/src/icons/app/CheckDouble.tsx +21 -0
  117. package/src/icons/app/ChevronDown.tsx +21 -0
  118. package/src/icons/app/ChevronLeft.tsx +21 -0
  119. package/src/icons/app/ChevronRight.tsx +21 -0
  120. package/src/icons/app/ChevronUp.tsx +21 -0
  121. package/src/icons/app/Circle.tsx +16 -0
  122. package/src/icons/app/Clock.tsx +22 -0
  123. package/src/icons/app/Code.tsx +21 -0
  124. package/src/icons/app/Coffee.tsx +24 -0
  125. package/src/icons/app/Comment.tsx +19 -0
  126. package/src/icons/app/Completed.tsx +21 -0
  127. package/src/icons/app/CreditCard.tsx +21 -0
  128. package/src/icons/app/Cross.tsx +21 -0
  129. package/src/icons/app/CrossedCircle.tsx +21 -0
  130. package/src/icons/app/Crown.tsx +21 -0
  131. package/src/icons/app/Delete.tsx +21 -0
  132. package/src/icons/app/Deny.tsx +21 -0
  133. package/src/icons/app/Desktop.tsx +26 -0
  134. package/src/icons/app/DollarBill.tsx +22 -0
  135. package/src/icons/app/DottedCircle.tsx +16 -0
  136. package/src/icons/app/Download.tsx +21 -0
  137. package/src/icons/app/DropdownDefault.tsx +25 -0
  138. package/src/icons/app/DropdownOpen.tsx +25 -0
  139. package/src/icons/app/Ellipsis.tsx +36 -0
  140. package/src/icons/app/EllipsisHorizontal.tsx +18 -0
  141. package/src/icons/app/Envelope.tsx +21 -0
  142. package/src/icons/app/EnvelopeOpen.tsx +23 -0
  143. package/src/icons/app/Exit.tsx +21 -0
  144. package/src/icons/app/ExternalLink.tsx +21 -0
  145. package/src/icons/app/EyeInvisible.tsx +26 -0
  146. package/src/icons/app/EyeVisible.tsx +21 -0
  147. package/src/icons/app/FaceNegative.tsx +21 -0
  148. package/src/icons/app/FaceNeutral.tsx +21 -0
  149. package/src/icons/app/FacePositive.tsx +21 -0
  150. package/src/icons/app/FaceSuperNegative.tsx +21 -0
  151. package/src/icons/app/FaceSuperPositive.tsx +21 -0
  152. package/src/icons/app/Feed.tsx +21 -0
  153. package/src/icons/app/File.tsx +21 -0
  154. package/src/icons/app/FileFilled.tsx +21 -0
  155. package/src/icons/app/Filter.tsx +19 -0
  156. package/src/icons/app/Flag.tsx +21 -0
  157. package/src/icons/app/Folder.tsx +19 -0
  158. package/src/icons/app/Folders.tsx +24 -0
  159. package/src/icons/app/Globe.tsx +26 -0
  160. package/src/icons/app/Graph.tsx +26 -0
  161. package/src/icons/app/Handshake.tsx +29 -0
  162. package/src/icons/app/Heading1.tsx +21 -0
  163. package/src/icons/app/Heading2.tsx +21 -0
  164. package/src/icons/app/Heading3.tsx +21 -0
  165. package/src/icons/app/Heart.tsx +21 -0
  166. package/src/icons/app/HoldHeart.tsx +21 -0
  167. package/src/icons/app/Home.tsx +20 -0
  168. package/src/icons/app/Hub.tsx +51 -0
  169. package/src/icons/app/Image.tsx +21 -0
  170. package/src/icons/app/InProgressTask.tsx +17 -0
  171. package/src/icons/app/Inbox.tsx +26 -0
  172. package/src/icons/app/Info.tsx +21 -0
  173. package/src/icons/app/InfoCircle.tsx +21 -0
  174. package/src/icons/app/InfoCircleLine.tsx +28 -0
  175. package/src/icons/app/Italic.tsx +21 -0
  176. package/src/icons/app/Kanban.tsx +21 -0
  177. package/src/icons/app/Laptop.tsx +20 -0
  178. package/src/icons/app/LayersFront.tsx +26 -0
  179. package/src/icons/app/Lightbulb.tsx +26 -0
  180. package/src/icons/app/Link.tsx +25 -0
  181. package/src/icons/app/LinkRemove.tsx +20 -0
  182. package/src/icons/app/List.tsx +25 -0
  183. package/src/icons/app/LockLocked.tsx +21 -0
  184. package/src/icons/app/LockUnlocked.tsx +21 -0
  185. package/src/icons/app/LogoAvatar.tsx +23 -0
  186. package/src/icons/app/LogoEruditai.tsx +19 -0
  187. package/src/icons/app/LogoTravelperk.tsx +27 -0
  188. package/src/icons/app/Masonry.tsx +19 -0
  189. package/src/icons/app/Maximize.tsx +21 -0
  190. package/src/icons/app/Megaphone.tsx +21 -0
  191. package/src/icons/app/Menu.tsx +21 -0
  192. package/src/icons/app/MessageFrown.tsx +25 -0
  193. package/src/icons/app/MessageHeart.tsx +25 -0
  194. package/src/icons/app/Messages.tsx +21 -0
  195. package/src/icons/app/Microphone.tsx +26 -0
  196. package/src/icons/app/MicrophoneNegative.tsx +26 -0
  197. package/src/icons/app/Minimize.tsx +21 -0
  198. package/src/icons/app/Minus.tsx +21 -0
  199. package/src/icons/app/Mobile.tsx +21 -0
  200. package/src/icons/app/Money.tsx +26 -0
  201. package/src/icons/app/MoneyBag.tsx +24 -0
  202. package/src/icons/app/MoveDown.tsx +44 -0
  203. package/src/icons/app/MoveTop.tsx +34 -0
  204. package/src/icons/app/MoveUp.tsx +42 -0
  205. package/src/icons/app/Office.tsx +31 -0
  206. package/src/icons/app/OlList.tsx +21 -0
  207. package/src/icons/app/PalmTree.tsx +20 -0
  208. package/src/icons/app/Paperclip.tsx +20 -0
  209. package/src/icons/app/PartiallyCompleted.tsx +21 -0
  210. package/src/icons/app/PauseCircle.tsx +21 -0
  211. package/src/icons/app/Pencil.tsx +21 -0
  212. package/src/icons/app/People.tsx +27 -0
  213. package/src/icons/app/Person.tsx +22 -0
  214. package/src/icons/app/Phone.tsx +20 -0
  215. package/src/icons/app/Pin.tsx +22 -0
  216. package/src/icons/app/PixBrazil.tsx +19 -0
  217. package/src/icons/app/Placeholder.tsx +21 -0
  218. package/src/icons/app/Plane.tsx +21 -0
  219. package/src/icons/app/Plus.tsx +21 -0
  220. package/src/icons/app/Present.tsx +31 -0
  221. package/src/icons/app/Printer.tsx +26 -0
  222. package/src/icons/app/Proyector.tsx +22 -0
  223. package/src/icons/app/Question.tsx +22 -0
  224. package/src/icons/app/Quote.tsx +21 -0
  225. package/src/icons/app/Reaction.tsx +32 -0
  226. package/src/icons/app/Receipt.tsx +20 -0
  227. package/src/icons/app/Record.tsx +17 -0
  228. package/src/icons/app/RemoveFavorite.tsx +21 -0
  229. package/src/icons/app/Replace.tsx +21 -0
  230. package/src/icons/app/Reset.tsx +27 -0
  231. package/src/icons/app/Rocket.tsx +26 -0
  232. package/src/icons/app/Salad.tsx +21 -0
  233. package/src/icons/app/Save.tsx +27 -0
  234. package/src/icons/app/Schedule.tsx +32 -0
  235. package/src/icons/app/Search.tsx +17 -0
  236. package/src/icons/app/SearchPerson.tsx +24 -0
  237. package/src/icons/app/Settings.tsx +20 -0
  238. package/src/icons/app/Share.tsx +27 -0
  239. package/src/icons/app/Sliders.tsx +22 -0
  240. package/src/icons/app/SolidPause.tsx +19 -0
  241. package/src/icons/app/SolidPlay.tsx +19 -0
  242. package/src/icons/app/SolidStop.tsx +19 -0
  243. package/src/icons/app/Sort.tsx +21 -0
  244. package/src/icons/app/Sparkles.tsx +25 -0
  245. package/src/icons/app/Spinner.tsx +20 -0
  246. package/src/icons/app/Split.tsx +21 -0
  247. package/src/icons/app/Star.tsx +21 -0
  248. package/src/icons/app/StarFilled.tsx +19 -0
  249. package/src/icons/app/Strikethrough.tsx +21 -0
  250. package/src/icons/app/Suitcase.tsx +22 -0
  251. package/src/icons/app/Table.tsx +21 -0
  252. package/src/icons/app/Target.tsx +31 -0
  253. package/src/icons/app/TextSize.tsx +21 -0
  254. package/src/icons/app/Timer.tsx +27 -0
  255. package/src/icons/app/Underline.tsx +26 -0
  256. package/src/icons/app/Upload.tsx +21 -0
  257. package/src/icons/app/Video.tsx +23 -0
  258. package/src/icons/app/VideoRecorder.tsx +31 -0
  259. package/src/icons/app/VideoRecorderNegative.tsx +22 -0
  260. package/src/icons/app/Wallet.tsx +26 -0
  261. package/src/icons/app/Warning.tsx +21 -0
  262. package/src/icons/app/WhatsappChat.tsx +23 -0
  263. package/src/icons/app/Windows.tsx +21 -0
  264. package/src/icons/app/index.ts +186 -0
  265. package/src/icons/index.ts +5 -0
  266. package/src/icons/modules/Benefits.tsx +25 -0
  267. package/src/icons/modules/Calendar.tsx +21 -0
  268. package/src/icons/modules/Cards.tsx +25 -0
  269. package/src/icons/modules/ClockIn.tsx +21 -0
  270. package/src/icons/modules/Discover.tsx +25 -0
  271. package/src/icons/modules/Documents.tsx +19 -0
  272. package/src/icons/modules/Engagement.tsx +21 -0
  273. package/src/icons/modules/Finance.tsx +21 -0
  274. package/src/icons/modules/Goals.tsx +19 -0
  275. package/src/icons/modules/Home.tsx +19 -0
  276. package/src/icons/modules/Hub.tsx +20 -0
  277. package/src/icons/modules/Inbox.tsx +19 -0
  278. package/src/icons/modules/Kudos.tsx +19 -0
  279. package/src/icons/modules/MyDocuments.tsx +21 -0
  280. package/src/icons/modules/Organization.tsx +19 -0
  281. package/src/icons/modules/Overviews.tsx +23 -0
  282. package/src/icons/modules/Payroll.tsx +25 -0
  283. package/src/icons/modules/Performance.tsx +19 -0
  284. package/src/icons/modules/Profile.tsx +19 -0
  285. package/src/icons/modules/Projects.tsx +21 -0
  286. package/src/icons/modules/Recruitment.tsx +21 -0
  287. package/src/icons/modules/Reports.tsx +21 -0
  288. package/src/icons/modules/Sales.tsx +27 -0
  289. package/src/icons/modules/Settings.tsx +21 -0
  290. package/src/icons/modules/Shifts.tsx +27 -0
  291. package/src/icons/modules/Social.tsx +21 -0
  292. package/src/icons/modules/Software.tsx +19 -0
  293. package/src/icons/modules/Spaces.tsx +21 -0
  294. package/src/icons/modules/Spending.tsx +21 -0
  295. package/src/icons/modules/Tasks.tsx +21 -0
  296. package/src/icons/modules/TimeOff.tsx +21 -0
  297. package/src/icons/modules/TimeTracking.tsx +25 -0
  298. package/src/icons/modules/Trainings.tsx +19 -0
  299. package/src/icons/modules/Treasury.tsx +19 -0
  300. package/src/icons/modules/Workflows.tsx +19 -0
  301. package/src/icons/modules/index.ts +35 -0
  302. package/src/icons/types.ts +9 -0
  303. package/src/index.ts +18 -0
  304. package/src/lib/date.ts +102 -0
  305. package/src/lib/emojis.tsx +47 -0
  306. package/src/lib/iconWithClassName.ts +17 -0
  307. package/src/lib/text.ts +31 -0
  308. package/src/lib/utils.ts +6 -0
  309. package/src/ui/avatar.tsx +113 -0
  310. package/tailwind.config.ts +19 -0
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Factorial One React Native
2
+
3
+ React Native implementation of the Factorial One Design System.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @factorialco/f0-react-native
9
+ # or
10
+ yarn add @factorialco/f0-react-native
11
+ # or
12
+ pnpm add @factorialco/f0-react-native
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```tsx
18
+ import { ExampleComponent } from "@factorialco/f0-react-native";
19
+
20
+ export default function App() {
21
+ return <ExampleComponent text="Hello from Factorial One!" />;
22
+ }
23
+ ```
24
+
25
+ ## Icons
26
+
27
+ The package includes a set of icons that can be imported and used in your React Native application.
28
+
29
+ ```tsx
30
+ import { Icon, AppIcons } from "@factorialco/f0-react-native";
31
+
32
+ // Basic usage
33
+ <Icon icon={AppIcons.Calendar} size="sm" />;
34
+ <Icon icon={AppIcons.Calendar} size="md" />;
35
+ <Icon icon={AppIcons.Calendar} size="lg" />;
36
+ ```
37
+
38
+ ## Development
39
+
40
+ ### Building
41
+
42
+ ```bash
43
+ pnpm build
44
+ ```
45
+
46
+ ### Testing
47
+
48
+ ```bash
49
+ pnpm test
50
+ ```
51
+
52
+ ## License
53
+
54
+ MIT
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@factorialco/f0-react-native",
3
+ "version": "0.19.1",
4
+ "type": "module",
5
+ "description": "React Native components for Factorial One Design System",
6
+ "main": "src/index.ts",
7
+ "module": "src/index.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./src/index.ts"
11
+ },
12
+ "./icons": {
13
+ "import": "./src/icons/index.ts"
14
+ },
15
+ "./icons/app": {
16
+ "import": "./src/icons/app/index.ts"
17
+ },
18
+ "./icons/modules": {
19
+ "import": "./src/icons/modules/index.ts"
20
+ },
21
+ "./tailwind.config": "./tailwind.config.ts"
22
+ },
23
+ "files": [
24
+ "src",
25
+ "tailwind.config.ts"
26
+ ],
27
+ "keywords": [
28
+ "factorial",
29
+ "design-system",
30
+ "react-native",
31
+ "components"
32
+ ],
33
+ "author": "Factorial",
34
+ "license": "MIT",
35
+ "peerDependencies": {
36
+ "date-fns": "^3.6.0",
37
+ "nativewind": "^4.1.23",
38
+ "react": "^18.2.0",
39
+ "react-native": "^0.76.6",
40
+ "react-native-svg": "^15.8.0",
41
+ "tailwindcss": "^3.4.3",
42
+ "twemoji-parser": "^14.0.0",
43
+ "typescript": "^5.7.2"
44
+ },
45
+ "dependencies": {
46
+ "clsx": "^2.1.1",
47
+ "cva": "1.0.0-beta.3",
48
+ "expo-clipboard": "^7.1.4",
49
+ "lodash": "^4.17.21",
50
+ "react-native-safe-area-context": "4.12.0",
51
+ "tailwind-merge": "^2.6.0",
52
+ "@factorialco/f0-core": "1.25.1"
53
+ },
54
+ "devDependencies": {
55
+ "@svgr/cli": "^8.1.0",
56
+ "@testing-library/react-native": "^12.9.0",
57
+ "@types/jest": "^29.5.14",
58
+ "@types/lodash": "^4.17.16",
59
+ "@types/react": "^18.2.0",
60
+ "@types/react-native": "^0.73.0",
61
+ "@types/twemoji-parser": "^13.1.4",
62
+ "globals": "^16.0.0",
63
+ "jest": "^29.7.0",
64
+ "nativewind": "^4.1.23",
65
+ "npm-run-all": "^4.1.5",
66
+ "prettier": "^3.5.2",
67
+ "prettier-plugin-tailwindcss": "^0.6.10",
68
+ "react": "^18.2.0",
69
+ "react-native": "^0.76.6",
70
+ "react-native-svg": "^15.8.0",
71
+ "tailwindcss": "^3.4.3",
72
+ "tailwindcss-animate": "^1.0.7",
73
+ "typescript": "^5.7.2"
74
+ },
75
+ "scripts": {
76
+ "build": "echo 'we ship source code as is'; exit 0",
77
+ "lint": "eslint -c eslint.config.mjs . --report-unused-disable-directives --max-warnings 0",
78
+ "lint-fix": "pnpm run lint -- --fix",
79
+ "test": "jest",
80
+ "generate-icons": "rm -fR src/icons/app/* src/icons/modules/* && run-p generate-app-icons generate-module-icons && find src/icons -name '*.tsx' -exec sed -i '' 's/SVGSVGElement/Svg/g; s/ xmlns=\"http:\\/\\/www.w3.org\\/2000\\/svg\"//g; s/ strokeWidth={[^}]*}//g; s/ strokeWidth=\"[^\"]*\"//g' {} +",
81
+ "generate-app-icons": "npx @svgr/cli --out-dir src/icons/app --native --svg-props className={props.className} ../../packages/core/assets/icons/app",
82
+ "generate-module-icons": "npx @svgr/cli --out-dir src/icons/modules --native --svg-props className={props.className} ../../packages/core/assets/icons/modules"
83
+ }
84
+ }
@@ -0,0 +1,62 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`ActivityItem Snapshot 1`] = `
4
+ <View
5
+ accessibilityLabel="activity-item"
6
+ accessibilityState={
7
+ {
8
+ "busy": undefined,
9
+ "checked": undefined,
10
+ "disabled": undefined,
11
+ "expanded": undefined,
12
+ "selected": undefined,
13
+ }
14
+ }
15
+ accessibilityValue={
16
+ {
17
+ "max": undefined,
18
+ "min": undefined,
19
+ "now": undefined,
20
+ "text": undefined,
21
+ }
22
+ }
23
+ accessible={true}
24
+ className="flex w-full flex-row gap-2 rounded-lg p-2 pr-3 "
25
+ collapsable={false}
26
+ focusable={true}
27
+ onBlur={[Function]}
28
+ onClick={[Function]}
29
+ onFocus={[Function]}
30
+ onResponderGrant={[Function]}
31
+ onResponderMove={[Function]}
32
+ onResponderRelease={[Function]}
33
+ onResponderTerminate={[Function]}
34
+ onResponderTerminationRequest={[Function]}
35
+ onStartShouldSetResponder={[Function]}
36
+ >
37
+ <View
38
+ className="flex-1"
39
+ >
40
+ <Text
41
+ className="line-clamp-1 text-lg font-medium text-f1-foreground"
42
+ >
43
+ Activity Title
44
+ </Text>
45
+ <Text
46
+ className="line-clamp-2 text-lg text-f1-foreground-secondary"
47
+ />
48
+ <View
49
+ className="mt-1.5 flex flex-row"
50
+ >
51
+ <Text
52
+ className="text-md text-f1-foreground-secondary"
53
+ >
54
+ Time off · Today
55
+ </Text>
56
+ </View>
57
+ </View>
58
+ <View
59
+ className="ml-1"
60
+ />
61
+ </View>
62
+ `;
@@ -0,0 +1,103 @@
1
+ import { render, fireEvent, screen } from "@testing-library/react-native";
2
+ import React from "react";
3
+ import { IconType } from "../../Icon";
4
+ import {
5
+ ActivityItem,
6
+ ActivityItemSkeleton,
7
+ } from "../../Activity/ActivityItem";
8
+
9
+ // Mock the IconAvatar component
10
+ jest.mock("../../Avatars/IconAvatar", () => ({
11
+ IconAvatar: () => null,
12
+ }));
13
+
14
+ // Mock dependencies
15
+ const mockIcon: IconType = "check" as unknown as IconType;
16
+ const mockOnPress = jest.fn();
17
+
18
+ describe("ActivityItem", () => {
19
+ const defaultProps = {
20
+ id: "activity-123",
21
+ date: "Today",
22
+ title: "Activity Title",
23
+ category: "Time off",
24
+ onPress: mockOnPress,
25
+ };
26
+
27
+ beforeEach(() => {
28
+ jest.clearAllMocks();
29
+ });
30
+
31
+ it("Snapshot", () => {
32
+ const { toJSON } = render(<ActivityItem {...defaultProps} />);
33
+ expect(toJSON()).toMatchSnapshot();
34
+ });
35
+
36
+ it("renders correctly with required props", () => {
37
+ render(<ActivityItem {...defaultProps} />);
38
+
39
+ const title = screen.getByText("Activity Title");
40
+ const moduleDate = screen.getByText("Time off · Today");
41
+
42
+ expect(title).toBeDefined();
43
+ expect(moduleDate).toBeDefined();
44
+ });
45
+
46
+ it("renders correctly with description", () => {
47
+ render(<ActivityItem {...defaultProps} description="Test description" />);
48
+
49
+ const description = screen.getByText("Test description");
50
+
51
+ expect(description).toBeDefined();
52
+ });
53
+
54
+ it("renders icon container when icon is provided", () => {
55
+ render(<ActivityItem {...defaultProps} icon={mockIcon} />);
56
+
57
+ const icon = screen.getByLabelText("activity-icon-container");
58
+
59
+ expect(icon).toBeDefined();
60
+ });
61
+
62
+ it("does not render icon container when icon is not provided", () => {
63
+ render(<ActivityItem {...defaultProps} />);
64
+
65
+ const icon = screen.queryByLabelText("activity-icon-container");
66
+
67
+ expect(icon).toBeNull();
68
+ });
69
+
70
+ it("shows unread indicator when isUnread is true", () => {
71
+ render(<ActivityItem {...defaultProps} isUnread={true} />);
72
+
73
+ const indicator = screen.getByLabelText("unread-indicator");
74
+
75
+ expect(indicator).toBeDefined();
76
+ });
77
+
78
+ it("does not show unread indicator when isUnread is false", () => {
79
+ render(<ActivityItem {...defaultProps} isUnread={false} />);
80
+
81
+ const indicator = screen.queryByLabelText("unread-indicator");
82
+
83
+ expect(indicator).toBeNull();
84
+ });
85
+
86
+ it("calls onPress with correct id when pressed", () => {
87
+ render(<ActivityItem {...defaultProps} />);
88
+
89
+ fireEvent.press(screen.getByLabelText("activity-item"));
90
+
91
+ expect(mockOnPress).toHaveBeenCalledWith("activity-123");
92
+ });
93
+ });
94
+
95
+ describe("ActivityItemSkeleton", () => {
96
+ it("renders skeleton correctly", () => {
97
+ render(<ActivityItemSkeleton />);
98
+
99
+ const skeleton = screen.getByLabelText("activity-skeleton");
100
+
101
+ expect(skeleton).toBeDefined();
102
+ });
103
+ });
@@ -0,0 +1,90 @@
1
+ import { View, Text, Pressable } from "react-native";
2
+ import { useState } from "react";
3
+ import { IconType } from "../../Icon";
4
+ import { IconAvatar } from "../../Avatars/exports";
5
+
6
+ export type ActivityItemProps = {
7
+ id: string;
8
+ date: string;
9
+ title: string;
10
+ description?: string;
11
+ icon?: IconType;
12
+ category: string;
13
+ isUnread?: boolean;
14
+ onPress: (id: string) => void;
15
+ };
16
+
17
+ export const ActivityItem = ({
18
+ id,
19
+ date,
20
+ title,
21
+ description,
22
+ icon,
23
+ category,
24
+ isUnread = false,
25
+ onPress,
26
+ }: ActivityItemProps) => {
27
+ const [isPressed, setIsPressed] = useState(false);
28
+
29
+ return (
30
+ <Pressable
31
+ className={`flex w-full flex-row gap-2 rounded-lg p-2 pr-3 ${isPressed ? "bg-f1-background-hover" : ""}`}
32
+ onPressIn={() => setIsPressed(false)} // Disabled by default - no use case for now
33
+ onPressOut={() => setIsPressed(false)}
34
+ onPress={() => onPress(id)}
35
+ accessibilityLabel="activity-item"
36
+ >
37
+ {icon && (
38
+ <View accessibilityLabel="activity-icon-container">
39
+ <IconAvatar icon={icon} size="md" />
40
+ </View>
41
+ )}
42
+ <View className="flex-1">
43
+ <Text className="line-clamp-1 text-lg font-medium text-f1-foreground">
44
+ {title}
45
+ </Text>
46
+ <Text className="line-clamp-2 text-lg text-f1-foreground-secondary">
47
+ {description}
48
+ </Text>
49
+ <View className="mt-1.5 flex flex-row">
50
+ <Text className="text-md text-f1-foreground-secondary">{`${category} · ${date}`}</Text>
51
+ </View>
52
+ </View>
53
+ <View className="ml-1">
54
+ {isUnread && (
55
+ <View
56
+ accessibilityLabel="unread-indicator"
57
+ className="mt-1.5 h-2 w-2 rounded-full bg-f1-icon-accent"
58
+ />
59
+ )}
60
+ </View>
61
+ </Pressable>
62
+ );
63
+ };
64
+
65
+ export const ActivityItemSkeleton = () => {
66
+ return (
67
+ <View
68
+ accessibilityLabel="activity-skeleton"
69
+ className="flex w-full flex-row gap-2 rounded-lg p-2 pr-3"
70
+ >
71
+ {/* Avatar skeleton - match IconAvatar's border radius */}
72
+ <View className="h-10 w-10 rounded-lg bg-f1-background-secondary" />
73
+
74
+ <View className="flex-1">
75
+ {/* Title skeleton */}
76
+ <View className="mb-1 h-5 w-3/4 rounded-sm bg-f1-background-secondary" />
77
+
78
+ {/* Description skeleton - two lines */}
79
+ <View className="mb-1 h-5 w-full rounded-sm bg-f1-background-secondary" />
80
+ <View className="mb-1.5 h-5 w-2/3 rounded-sm bg-f1-background-secondary" />
81
+
82
+ {/* Category and date skeleton */}
83
+ <View className="h-5 w-1/2 rounded-sm bg-f1-background-secondary" />
84
+ </View>
85
+
86
+ {/* Space for the unread indicator */}
87
+ <View className="ml-1 w-2" />
88
+ </View>
89
+ );
90
+ };
@@ -0,0 +1,56 @@
1
+ import { sizes } from "../../ui/avatar";
2
+ import { ComponentProps, ReactNode } from "react";
3
+ import { CompanyAvatar } from "./CompanyAvatar";
4
+ import { PersonAvatar } from "./PersonAvatar";
5
+ import { TeamAvatar } from "./TeamAvatar";
6
+
7
+ type PersonAvatarProps = ComponentProps<typeof PersonAvatar>;
8
+ type TeamAvatarProps = ComponentProps<typeof TeamAvatar>;
9
+ type CompanyAvatarProps = ComponentProps<typeof CompanyAvatar>;
10
+
11
+ export type AvatarVariant =
12
+ | ({ type: "person" } & Omit<PersonAvatarProps, "size">)
13
+ | ({ type: "team" } & Omit<TeamAvatarProps, "size">)
14
+ | ({ type: "company" } & Omit<CompanyAvatarProps, "size">);
15
+
16
+ export const Avatar = ({
17
+ avatar,
18
+ size = "xsmall",
19
+ }: {
20
+ avatar: AvatarVariant;
21
+ size?: (typeof sizes)[number];
22
+ }): ReactNode => {
23
+ switch (avatar.type) {
24
+ case "person":
25
+ return (
26
+ <PersonAvatar
27
+ firstName={avatar.firstName}
28
+ lastName={avatar.lastName}
29
+ src={avatar.src}
30
+ size={size}
31
+ aria-label={avatar["aria-label"]}
32
+ aria-labelledby={avatar["aria-labelledby"]}
33
+ />
34
+ );
35
+ case "team":
36
+ return (
37
+ <TeamAvatar
38
+ name={avatar.name}
39
+ src={avatar.src}
40
+ size={size}
41
+ aria-label={avatar["aria-label"]}
42
+ aria-labelledby={avatar["aria-labelledby"]}
43
+ />
44
+ );
45
+ case "company":
46
+ return (
47
+ <CompanyAvatar
48
+ name={avatar.name}
49
+ src={avatar.src}
50
+ size={size}
51
+ aria-label={avatar["aria-label"]}
52
+ aria-labelledby={avatar["aria-labelledby"]}
53
+ />
54
+ );
55
+ }
56
+ };
@@ -0,0 +1,126 @@
1
+ import {
2
+ Avatar as AvatarComponent,
3
+ AvatarFallback,
4
+ AvatarImage,
5
+ } from "../../../ui/avatar";
6
+ import { ComponentProps, useMemo } from "react";
7
+ import { Badge, BadgeProps } from "../../Badge";
8
+ import { getAvatarColor, getInitials } from "./utils";
9
+ import { View } from "react-native";
10
+ import { ModuleAvatar, ModuleAvatarProps } from "../ModuleAvatar";
11
+ import { AvatarBadge } from "../types";
12
+
13
+ const getAvatarSize = (
14
+ size: ShadAvatarProps["size"],
15
+ ): ModuleAvatarProps["size"] | undefined => {
16
+ const sizeMap: Partial<
17
+ Record<
18
+ Exclude<ShadAvatarProps["size"], undefined>,
19
+ ModuleAvatarProps["size"]
20
+ >
21
+ > = {
22
+ xlarge: "lg",
23
+ large: "md",
24
+ small: "sm",
25
+ } as const;
26
+
27
+ return size && sizeMap[size] ? sizeMap[size] : sizeMap.small;
28
+ };
29
+
30
+ const getBadgeSize = (
31
+ size: ShadAvatarProps["size"],
32
+ ): BadgeProps["size"] | undefined => {
33
+ const sizeMap: Partial<
34
+ Record<Exclude<ShadAvatarProps["size"], undefined>, BadgeProps["size"]>
35
+ > = {
36
+ xlarge: "lg",
37
+ large: "md",
38
+ small: "sm",
39
+ } as const;
40
+
41
+ return size && sizeMap[size] ? sizeMap[size] : sizeMap.small;
42
+ };
43
+
44
+ type ShadAvatarProps = ComponentProps<typeof AvatarComponent>;
45
+
46
+ type Props = {
47
+ type: ShadAvatarProps["type"];
48
+ name: string | string[];
49
+ src?: string;
50
+ size?: ShadAvatarProps["size"];
51
+ color?: ShadAvatarProps["color"] | "random";
52
+ badge?: AvatarBadge;
53
+ } & Pick<ShadAvatarProps, "aria-label" | "aria-labelledby">;
54
+
55
+ export const BaseAvatar = ({
56
+ src,
57
+ name,
58
+ size,
59
+ type = "base",
60
+ color = "random",
61
+ "aria-label": ariaLabel,
62
+ "aria-labelledby": ariaLabelledby,
63
+ badge,
64
+ }: Props) => {
65
+ const initials = getInitials(name, size);
66
+ const avatarColor =
67
+ color === "random"
68
+ ? getAvatarColor(Array.isArray(name) ? name.join("") : name)
69
+ : color;
70
+
71
+ const hasAria = Boolean(ariaLabel || ariaLabelledby);
72
+ const badgeSize = getBadgeSize(size);
73
+ const moduleAvatarSize = getAvatarSize(size);
74
+
75
+ const badgeContent = useMemo(
76
+ () =>
77
+ badge ? (
78
+ <>
79
+ {badge.type === "module" && (
80
+ <ModuleAvatar module={badge.module} size={moduleAvatarSize} />
81
+ )}
82
+ {badge.type !== "module" && (
83
+ <Badge type={badge.type} icon={badge.icon} size={badgeSize} />
84
+ )}
85
+ </>
86
+ ) : null,
87
+ [badge, badgeSize, moduleAvatarSize],
88
+ );
89
+
90
+ return (
91
+ <View
92
+ className={`inline-flex ${badge && badge.type === "module" ? "p-[3px]" : ""}`}
93
+ >
94
+ <View className="h-fit w-fit">
95
+ <AvatarComponent
96
+ size={size}
97
+ type={type}
98
+ color={avatarColor}
99
+ role="img"
100
+ aria-hidden={!hasAria}
101
+ aria-label={ariaLabel}
102
+ aria-labelledby={ariaLabelledby}
103
+ data-a11y-color-contrast-ignore
104
+ className={
105
+ src
106
+ ? "dark:bg-f1-background-inverse-secondary bg-f1-background"
107
+ : ""
108
+ }
109
+ >
110
+ {src ? (
111
+ <AvatarImage src={src} alt={initials} />
112
+ ) : (
113
+ <AvatarFallback size={size} data-a11y-color-contrast-ignore>
114
+ {initials}
115
+ </AvatarFallback>
116
+ )}
117
+ </AvatarComponent>
118
+ </View>
119
+ {badge && (
120
+ <View className="absolute -bottom-0.5 -right-0.5">{badgeContent}</View>
121
+ )}
122
+ </View>
123
+ );
124
+ };
125
+
126
+ BaseAvatar.displayName = "BaseAvatar";
@@ -0,0 +1,73 @@
1
+ import {
2
+ color as AvatarColors,
3
+ Avatar as AvatarComponent,
4
+ type as avatarType,
5
+ sizes,
6
+ } from "../../../ui/avatar";
7
+ import { type ComponentProps } from "react";
8
+
9
+ type ShadAvatarProps = ComponentProps<typeof AvatarComponent>;
10
+
11
+ export function getInitials(
12
+ name: string | string[],
13
+ size?: ShadAvatarProps["size"],
14
+ isFile?: boolean,
15
+ ): string {
16
+ const nameArray = Array.isArray(name) ? name : [name];
17
+ const isSmall = size === "xsmall" || size === "small";
18
+ const minChar = isFile ? 3 : 2;
19
+
20
+ if (isSmall) return (nameArray[0][0] ?? "").toUpperCase();
21
+ if (!Array.isArray(name)) return name.slice(0, minChar).toUpperCase();
22
+
23
+ return nameArray
24
+ .slice(0, minChar)
25
+ .map((name) => name[0])
26
+ .join("")
27
+ .toUpperCase();
28
+ }
29
+
30
+ export function getAvatarColor(text: string): ShadAvatarProps["color"] {
31
+ let hash = 0;
32
+
33
+ for (let i = 0; i < text.length; i++) {
34
+ hash = text.charCodeAt(i) + ((hash << 5) - hash);
35
+ hash = hash & hash;
36
+ }
37
+
38
+ const index =
39
+ ((hash % AvatarColors.length) + AvatarColors.length) % AvatarColors.length;
40
+
41
+ return AvatarColors[index];
42
+ }
43
+
44
+ export const getMask = {
45
+ base: {
46
+ xlarge:
47
+ "path('M72 0H0V72H52.202C49.6089 69.459 48 65.9174 48 62C48 54.268 54.268 48 62 48C65.9174 48 69.459 49.6089 72 52.202V0ZM72 71.798C71.9333 71.866 71.866 71.9333 71.798 72H72V71.798Z')",
48
+ large:
49
+ "path('M56 0H0V56H39.0556C37.1554 53.877 36 51.0734 36 48C36 41.3726 41.3726 36 48 36C51.0734 36 53.877 37.1554 56 39.0556V0Z')",
50
+ medium:
51
+ "path('M32 0H0V32H22.2547C21.4638 30.8662 21 29.4872 21 28C21 24.134 24.134 21 28 21C29.4872 21 30.8662 21.4638 32 22.2547V0Z')",
52
+ small:
53
+ "path('M24 0H0V24H14.2547C13.4638 22.8662 13 21.4872 13 20C13 16.134 16.134 13 20 13C21.4872 13 22.8662 13.4638 24 14.2547V0Z')",
54
+ xsmall:
55
+ "path('M20 0H0V20H10.2547C9.46381 18.8662 9 17.4872 9 16C9 12.134 12.134 9 16 9C17.4872 9 18.8662 9.46381 20 10.2547V0Z')",
56
+ },
57
+ rounded: {
58
+ xlarge:
59
+ "path('M69.1842 49.9814C70.9975 45.6828 72 40.9585 72 36C72 16.1177 55.8823 0 36 0C16.1177 0 0 16.1177 0 36C0 55.8823 16.1177 72 36 72C40.9585 72 45.6828 70.9975 49.9814 69.1842C48.7232 67.0839 48 64.6264 48 62C48 54.268 54.268 48 62 48C64.6264 48 67.0839 48.7232 69.1842 49.9814Z')",
60
+ large:
61
+ "path('M54.2534 37.7562C55.3828 34.7182 56 31.4312 56 28C56 12.536 43.464 0 28 0C12.536 0 0 12.536 0 28C0 43.464 12.536 56 28 56C31.4312 56 34.7182 55.3828 37.7562 54.2534C36.6421 52.4324 36 50.2912 36 48C36 41.3726 41.3726 36 48 36C50.2912 36 52.4324 36.6421 54.2534 37.7562Z')",
62
+ medium:
63
+ "path('M30.9702 21.6596C31.6358 19.9001 32 17.9926 32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32C17.9926 32 19.9001 31.6358 21.6596 30.9702C21.2365 30.0686 21 29.0619 21 28C21 24.134 24.134 21 28 21C29.0619 21 30.0686 21.2365 30.9702 21.6596Z')",
64
+ small:
65
+ "path('M23.8119 14.128C23.9355 13.4373 24 12.7262 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C12.7262 24 13.4373 23.9355 14.128 23.8119C13.4145 22.7151 13 21.406 13 20C13 16.134 16.134 13 20 13C21.406 13 22.7151 13.4145 23.8119 14.128Z')",
66
+ xsmall:
67
+ "path('M19.9969 10.2525C19.999 10.1686 20 10.0844 20 10C20 4.47715 15.5228 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20C10.0844 20 10.1686 19.999 10.2525 19.9969C9.46297 18.8636 9 17.4859 9 16C9 12.134 12.134 9 16 9C17.4859 9 18.8636 9.46297 19.9969 10.2525Z')",
68
+ },
69
+ get: (
70
+ type: (typeof avatarType)[number] = "base",
71
+ size: (typeof sizes)[number] = "medium",
72
+ ) => getMask[type][size],
73
+ } as const;
@@ -0,0 +1,25 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`CompanyAvatar Snapshot 1`] = `
4
+ <View
5
+ className="inline-flex "
6
+ >
7
+ <View
8
+ className="h-fit w-fit"
9
+ >
10
+ <View
11
+ aria-hidden={true}
12
+ className="flex shrink-0 items-center justify-center overflow-hidden text-center font-semibold w-8 h-8 rounded bg-[hsl(theme(colors.viridian.50))]"
13
+ data-a11y-color-contrast-ignore={true}
14
+ role="img"
15
+ >
16
+ <Text
17
+ className="text-f1-foreground-inverse/90 text-md"
18
+ data-a11y-color-contrast-ignore={true}
19
+ >
20
+ FA
21
+ </Text>
22
+ </View>
23
+ </View>
24
+ </View>
25
+ `;
@@ -0,0 +1,11 @@
1
+ import { render } from "@testing-library/react-native";
2
+ import React from "react";
3
+ import { CompanyAvatar } from "./";
4
+
5
+ describe("CompanyAvatar", () => {
6
+ it("Snapshot", () => {
7
+ const { toJSON } = render(<CompanyAvatar name="Factorial" />);
8
+
9
+ expect(toJSON()).toMatchSnapshot();
10
+ });
11
+ });