@medway-ui/native 1.1.1 → 1.2.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 (218) hide show
  1. package/README.md +238 -105
  2. package/lib/commonjs/components/Alert.js +5 -4
  3. package/lib/commonjs/components/Alert.js.map +1 -1
  4. package/lib/commonjs/components/Avatar.js +2 -1
  5. package/lib/commonjs/components/Avatar.js.map +1 -1
  6. package/lib/commonjs/components/Badge.js +2 -1
  7. package/lib/commonjs/components/Badge.js.map +1 -1
  8. package/lib/commonjs/components/Button.js +3 -2
  9. package/lib/commonjs/components/Button.js.map +1 -1
  10. package/lib/commonjs/components/CardNews.js +7 -6
  11. package/lib/commonjs/components/CardNews.js.map +1 -1
  12. package/lib/commonjs/components/Carousel.js +122 -0
  13. package/lib/commonjs/components/Carousel.js.map +1 -0
  14. package/lib/commonjs/components/Checkbox.js +11 -2
  15. package/lib/commonjs/components/Checkbox.js.map +1 -1
  16. package/lib/commonjs/components/DropdownMenu.js +225 -0
  17. package/lib/commonjs/components/DropdownMenu.js.map +1 -0
  18. package/lib/commonjs/components/EmptyState.js +19 -20
  19. package/lib/commonjs/components/EmptyState.js.map +1 -1
  20. package/lib/commonjs/components/Feed.js +82 -0
  21. package/lib/commonjs/components/Feed.js.map +1 -0
  22. package/lib/commonjs/components/FeedNotice.js +76 -0
  23. package/lib/commonjs/components/FeedNotice.js.map +1 -0
  24. package/lib/commonjs/components/Input.js +21 -9
  25. package/lib/commonjs/components/Input.js.map +1 -1
  26. package/lib/commonjs/components/InvitePopover.js +196 -0
  27. package/lib/commonjs/components/InvitePopover.js.map +1 -0
  28. package/lib/commonjs/components/Label.js +2 -1
  29. package/lib/commonjs/components/Label.js.map +1 -1
  30. package/lib/commonjs/components/LeaderboardCard.js +58 -0
  31. package/lib/commonjs/components/LeaderboardCard.js.map +1 -0
  32. package/lib/commonjs/components/MemberRow.js +131 -0
  33. package/lib/commonjs/components/MemberRow.js.map +1 -0
  34. package/lib/commonjs/components/PageHeader.js +3 -2
  35. package/lib/commonjs/components/PageHeader.js.map +1 -1
  36. package/lib/commonjs/components/PostForm.js +182 -0
  37. package/lib/commonjs/components/PostForm.js.map +1 -0
  38. package/lib/commonjs/components/PrizeCollection.js +135 -0
  39. package/lib/commonjs/components/PrizeCollection.js.map +1 -0
  40. package/lib/commonjs/components/RadioGroup.js +22 -0
  41. package/lib/commonjs/components/RadioGroup.js.map +1 -1
  42. package/lib/commonjs/components/SectionHeader.js +36 -0
  43. package/lib/commonjs/components/SectionHeader.js.map +1 -0
  44. package/lib/commonjs/components/Switch.js +33 -19
  45. package/lib/commonjs/components/Switch.js.map +1 -1
  46. package/lib/commonjs/components/Tabs.js +156 -0
  47. package/lib/commonjs/components/Tabs.js.map +1 -0
  48. package/lib/commonjs/components/Tag.js +2 -1
  49. package/lib/commonjs/components/Tag.js.map +1 -1
  50. package/lib/commonjs/components/Text.js +60 -0
  51. package/lib/commonjs/components/Text.js.map +1 -0
  52. package/lib/commonjs/components/Toast.js +3 -2
  53. package/lib/commonjs/components/Toast.js.map +1 -1
  54. package/lib/commonjs/components/Tooltip.js +2 -2
  55. package/lib/commonjs/components/Tooltip.js.map +1 -1
  56. package/lib/commonjs/hooks/useThemeColor.js +66 -29
  57. package/lib/commonjs/hooks/useThemeColor.js.map +1 -1
  58. package/lib/commonjs/index.js +319 -1
  59. package/lib/commonjs/index.js.map +1 -1
  60. package/lib/commonjs/lib/overlay-host.js +101 -0
  61. package/lib/commonjs/lib/overlay-host.js.map +1 -0
  62. package/lib/commonjs/lib/typography.js +26 -0
  63. package/lib/commonjs/lib/typography.js.map +1 -0
  64. package/lib/commonjs/nativewind-env.d.js +0 -1
  65. package/lib/commonjs/nativewind-env.d.js.map +1 -1
  66. package/lib/module/components/Alert.js +3 -2
  67. package/lib/module/components/Alert.js.map +1 -1
  68. package/lib/module/components/Avatar.js +2 -1
  69. package/lib/module/components/Avatar.js.map +1 -1
  70. package/lib/module/components/Badge.js +2 -1
  71. package/lib/module/components/Badge.js.map +1 -1
  72. package/lib/module/components/Button.js +2 -1
  73. package/lib/module/components/Button.js.map +1 -1
  74. package/lib/module/components/CardNews.js +2 -1
  75. package/lib/module/components/CardNews.js.map +1 -1
  76. package/lib/module/components/Carousel.js +117 -0
  77. package/lib/module/components/Carousel.js.map +1 -0
  78. package/lib/module/components/Checkbox.js +12 -2
  79. package/lib/module/components/Checkbox.js.map +1 -1
  80. package/lib/module/components/DropdownMenu.js +216 -0
  81. package/lib/module/components/DropdownMenu.js.map +1 -0
  82. package/lib/module/components/EmptyState.js +19 -20
  83. package/lib/module/components/EmptyState.js.map +1 -1
  84. package/lib/module/components/Feed.js +77 -0
  85. package/lib/module/components/Feed.js.map +1 -0
  86. package/lib/module/components/FeedNotice.js +73 -0
  87. package/lib/module/components/FeedNotice.js.map +1 -0
  88. package/lib/module/components/Input.js +21 -9
  89. package/lib/module/components/Input.js.map +1 -1
  90. package/lib/module/components/InvitePopover.js +183 -0
  91. package/lib/module/components/InvitePopover.js.map +1 -0
  92. package/lib/module/components/Label.js +2 -1
  93. package/lib/module/components/Label.js.map +1 -1
  94. package/lib/module/components/LeaderboardCard.js +53 -0
  95. package/lib/module/components/LeaderboardCard.js.map +1 -0
  96. package/lib/module/components/MemberRow.js +127 -0
  97. package/lib/module/components/MemberRow.js.map +1 -0
  98. package/lib/module/components/PageHeader.js +2 -1
  99. package/lib/module/components/PageHeader.js.map +1 -1
  100. package/lib/module/components/PostForm.js +174 -0
  101. package/lib/module/components/PostForm.js.map +1 -0
  102. package/lib/module/components/PrizeCollection.js +127 -0
  103. package/lib/module/components/PrizeCollection.js.map +1 -0
  104. package/lib/module/components/RadioGroup.js +21 -1
  105. package/lib/module/components/RadioGroup.js.map +1 -1
  106. package/lib/module/components/SectionHeader.js +33 -0
  107. package/lib/module/components/SectionHeader.js.map +1 -0
  108. package/lib/module/components/Switch.js +34 -20
  109. package/lib/module/components/Switch.js.map +1 -1
  110. package/lib/module/components/Tabs.js +148 -0
  111. package/lib/module/components/Tabs.js.map +1 -0
  112. package/lib/module/components/Tag.js +2 -1
  113. package/lib/module/components/Tag.js.map +1 -1
  114. package/lib/module/components/Text.js +58 -0
  115. package/lib/module/components/Text.js.map +1 -0
  116. package/lib/module/components/Toast.js +2 -1
  117. package/lib/module/components/Toast.js.map +1 -1
  118. package/lib/module/components/Tooltip.js +1 -1
  119. package/lib/module/components/Tooltip.js.map +1 -1
  120. package/lib/module/hooks/useThemeColor.js +66 -31
  121. package/lib/module/hooks/useThemeColor.js.map +1 -1
  122. package/lib/module/index.js +27 -3
  123. package/lib/module/index.js.map +1 -1
  124. package/lib/module/lib/overlay-host.js +96 -0
  125. package/lib/module/lib/overlay-host.js.map +1 -0
  126. package/lib/module/lib/typography.js +22 -0
  127. package/lib/module/lib/typography.js.map +1 -0
  128. package/lib/module/nativewind-env.d.js +0 -1
  129. package/lib/module/nativewind-env.d.js.map +1 -1
  130. package/lib/typescript/components/Alert.d.ts.map +1 -1
  131. package/lib/typescript/components/Avatar.d.ts.map +1 -1
  132. package/lib/typescript/components/Badge.d.ts.map +1 -1
  133. package/lib/typescript/components/Button.d.ts.map +1 -1
  134. package/lib/typescript/components/CardNews.d.ts.map +1 -1
  135. package/lib/typescript/components/Carousel.d.ts +29 -0
  136. package/lib/typescript/components/Carousel.d.ts.map +1 -0
  137. package/lib/typescript/components/Checkbox.d.ts.map +1 -1
  138. package/lib/typescript/components/DropdownMenu.d.ts +39 -0
  139. package/lib/typescript/components/DropdownMenu.d.ts.map +1 -0
  140. package/lib/typescript/components/EmptyState.d.ts +1 -1
  141. package/lib/typescript/components/EmptyState.d.ts.map +1 -1
  142. package/lib/typescript/components/Feed.d.ts +22 -0
  143. package/lib/typescript/components/Feed.d.ts.map +1 -0
  144. package/lib/typescript/components/FeedNotice.d.ts +17 -0
  145. package/lib/typescript/components/FeedNotice.d.ts.map +1 -0
  146. package/lib/typescript/components/Input.d.ts +3 -2
  147. package/lib/typescript/components/Input.d.ts.map +1 -1
  148. package/lib/typescript/components/InvitePopover.d.ts +46 -0
  149. package/lib/typescript/components/InvitePopover.d.ts.map +1 -0
  150. package/lib/typescript/components/Label.d.ts.map +1 -1
  151. package/lib/typescript/components/LeaderboardCard.d.ts +16 -0
  152. package/lib/typescript/components/LeaderboardCard.d.ts.map +1 -0
  153. package/lib/typescript/components/MemberRow.d.ts +40 -0
  154. package/lib/typescript/components/MemberRow.d.ts.map +1 -0
  155. package/lib/typescript/components/PageHeader.d.ts.map +1 -1
  156. package/lib/typescript/components/PostForm.d.ts +50 -0
  157. package/lib/typescript/components/PostForm.d.ts.map +1 -0
  158. package/lib/typescript/components/PrizeCollection.d.ts +35 -0
  159. package/lib/typescript/components/PrizeCollection.d.ts.map +1 -0
  160. package/lib/typescript/components/RadioGroup.d.ts +10 -2
  161. package/lib/typescript/components/RadioGroup.d.ts.map +1 -1
  162. package/lib/typescript/components/SectionHeader.d.ts +12 -0
  163. package/lib/typescript/components/SectionHeader.d.ts.map +1 -0
  164. package/lib/typescript/components/Switch.d.ts.map +1 -1
  165. package/lib/typescript/components/Tabs.d.ts +32 -0
  166. package/lib/typescript/components/Tabs.d.ts.map +1 -0
  167. package/lib/typescript/components/Tag.d.ts.map +1 -1
  168. package/lib/typescript/components/Text.d.ts +23 -0
  169. package/lib/typescript/components/Text.d.ts.map +1 -0
  170. package/lib/typescript/components/Toast.d.ts +1 -1
  171. package/lib/typescript/components/Toast.d.ts.map +1 -1
  172. package/lib/typescript/components/Tooltip.d.ts.map +1 -1
  173. package/lib/typescript/hooks/useThemeColor.d.ts +4 -2
  174. package/lib/typescript/hooks/useThemeColor.d.ts.map +1 -1
  175. package/lib/typescript/index.d.ts +28 -4
  176. package/lib/typescript/index.d.ts.map +1 -1
  177. package/lib/typescript/lib/overlay-host.d.ts +23 -0
  178. package/lib/typescript/lib/overlay-host.d.ts.map +1 -0
  179. package/lib/typescript/lib/typography.d.ts +12 -0
  180. package/lib/typescript/lib/typography.d.ts.map +1 -0
  181. package/package.json +13 -3
  182. package/setup/MedwayUiProvider.tsx +15 -4
  183. package/setup/babel-brownfield.js +70 -0
  184. package/setup/metro.js +95 -24
  185. package/setup/tailwind.js +76 -8
  186. package/setup/tokens.native.css +8 -3
  187. package/src/components/Alert.tsx +4 -2
  188. package/src/components/Avatar.tsx +3 -1
  189. package/src/components/Badge.tsx +3 -1
  190. package/src/components/Button.tsx +3 -7
  191. package/src/components/CardNews.tsx +2 -1
  192. package/src/components/Carousel.tsx +152 -0
  193. package/src/components/Checkbox.tsx +14 -4
  194. package/src/components/DropdownMenu.tsx +312 -0
  195. package/src/components/EmptyState.tsx +21 -23
  196. package/src/components/Feed.tsx +96 -0
  197. package/src/components/FeedNotice.tsx +112 -0
  198. package/src/components/Input.tsx +11 -6
  199. package/src/components/InvitePopover.tsx +240 -0
  200. package/src/components/Label.tsx +3 -1
  201. package/src/components/LeaderboardCard.tsx +70 -0
  202. package/src/components/MemberRow.tsx +157 -0
  203. package/src/components/PageHeader.tsx +3 -1
  204. package/src/components/PostForm.tsx +250 -0
  205. package/src/components/PrizeCollection.tsx +190 -0
  206. package/src/components/RadioGroup.tsx +32 -3
  207. package/src/components/SectionHeader.tsx +45 -0
  208. package/src/components/Switch.tsx +65 -59
  209. package/src/components/Tabs.tsx +182 -0
  210. package/src/components/Tag.tsx +3 -1
  211. package/src/components/Text.tsx +66 -0
  212. package/src/components/Toast.tsx +3 -1
  213. package/src/components/Tooltip.tsx +2 -1
  214. package/src/hooks/useThemeColor.ts +77 -32
  215. package/src/index.ts +147 -6
  216. package/src/lib/overlay-host.tsx +102 -0
  217. package/src/lib/typography.ts +21 -0
  218. package/src/nativewind-env.d.ts +2 -0
@@ -0,0 +1,23 @@
1
+ import React, { type ReactNode } from 'react';
2
+ type HostOrigin = {
3
+ x: number;
4
+ y: number;
5
+ };
6
+ type OverlayHostContextValue = {
7
+ mount: (id: string, node: ReactNode) => void;
8
+ unmount: (id: string) => void;
9
+ /** Mede a origem do host na janela (para converter pageX/pageY → coords do host). */
10
+ measureHostOrigin: (callback: (origin: HostOrigin) => void) => void;
11
+ };
12
+ /**
13
+ * Host de overlay no topo da árvore Medway UI.
14
+ * Usado pelo DropdownMenu porque o Portal zustand do rn-primitives
15
+ * não renderiza de forma confiável dentro da stack (RNSScreen) deste app.
16
+ */
17
+ declare function OverlayHostProvider({ children }: {
18
+ children: ReactNode;
19
+ }): React.JSX.Element;
20
+ declare function useOverlayHost(): OverlayHostContextValue;
21
+ export { OverlayHostProvider, useOverlayHost };
22
+ export type { HostOrigin };
23
+ //# sourceMappingURL=overlay-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay-host.d.ts","sourceRoot":"","sources":["../../../src/lib/overlay-host.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,KAAK,UAAU,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,KAAK,uBAAuB,GAAG;IAC7B,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IAC7C,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,qFAAqF;IACrF,iBAAiB,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,KAAK,IAAI,CAAC;CACrE,CAAC;AAIF;;;;GAIG;AACH,iBAAS,mBAAmB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,qBAoDjE;AAED,iBAAS,cAAc,4BAMtB;AAaD,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,CAAC;AAC/C,YAAY,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { TextStyle } from 'react-native';
2
+ /** Montserrat files registered by the host app (ex.: App.js useFonts). */
3
+ export declare const fontFamilyRegular: "MontserratRegular";
4
+ export declare const fontFamilyMedium: "MontserratMedium";
5
+ export declare const fontFamilySemibold: "MontserratSemiBold";
6
+ /** Figma body-sm/medium */
7
+ export declare const bodySmMediumStyle: TextStyle;
8
+ /** Figma body-xs/medium */
9
+ export declare const bodyXsMediumStyle: TextStyle;
10
+ /** Figma body-sm/semibold */
11
+ export declare const bodySmSemiboldStyle: TextStyle;
12
+ //# sourceMappingURL=typography.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typography.d.ts","sourceRoot":"","sources":["../../../src/lib/typography.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,EAAG,mBAA4B,CAAC;AAC9D,eAAO,MAAM,gBAAgB,EAAG,kBAA2B,CAAC;AAC5D,eAAO,MAAM,kBAAkB,EAAG,oBAA6B,CAAC;AAEhE,2BAA2B;AAC3B,eAAO,MAAM,iBAAiB,EAAE,SAE/B,CAAC;AAEF,2BAA2B;AAC3B,eAAO,MAAM,iBAAiB,EAAE,SAE/B,CAAC;AAEF,6BAA6B;AAC7B,eAAO,MAAM,mBAAmB,EAAE,SAEjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medway-ui/native",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Medway UI components for React Native (iOS/Android via Expo)",
5
5
  "author": "Alekcarvalho",
6
6
  "license": "MIT",
@@ -47,12 +47,14 @@
47
47
  "@rn-primitives/avatar": "^1.0.0",
48
48
  "@rn-primitives/checkbox": "^1.0.0",
49
49
  "@rn-primitives/dialog": "^1.0.0",
50
+ "@rn-primitives/dropdown-menu": "^1.5.2",
50
51
  "@rn-primitives/popover": "^1.0.0",
51
- "@rn-primitives/portal": "^1.4.0",
52
+ "@rn-primitives/portal": "^1.5.2",
52
53
  "@rn-primitives/radio-group": "^1.0.0",
53
54
  "@rn-primitives/select": "^1.0.0",
54
55
  "@rn-primitives/slot": "^1.0.0",
55
56
  "@rn-primitives/switch": "^1.0.0",
57
+ "@rn-primitives/tabs": "^1.5.2",
56
58
  "@rn-primitives/tooltip": "^1.0.0"
57
59
  },
58
60
  "peerDependencies": {
@@ -87,6 +89,9 @@
87
89
  }
88
90
  },
89
91
  "devDependencies": {
92
+ "@medway-ui/icons": "^1.12.0",
93
+ "@react-navigation/native": "^7.3.18",
94
+ "@react-navigation/native-stack": "^7.18.10",
90
95
  "@types/react": "^19",
91
96
  "class-variance-authority": "^0.7.1",
92
97
  "clsx": "^2.1.1",
@@ -110,7 +115,12 @@
110
115
  }
111
116
  ],
112
117
  "module",
113
- "typescript"
118
+ [
119
+ "typescript",
120
+ {
121
+ "project": "tsconfig.build.json"
122
+ }
123
+ ]
114
124
  ]
115
125
  },
116
126
  "publishConfig": {
@@ -3,8 +3,9 @@ import { View, StyleSheet } from 'react-native';
3
3
  import { PortalHost } from '@rn-primitives/portal';
4
4
  import { useColorScheme } from 'nativewind';
5
5
 
6
+ import { OverlayHostProvider } from '../src/lib/overlay-host';
7
+
6
8
  import './global.css';
7
- import '@/lib/medwayIcons';
8
9
 
9
10
  type MedwayUiTheme = 'light' | 'dark' | 'system';
10
11
 
@@ -26,7 +27,8 @@ type MedwayUiProviderProps = {
26
27
 
27
28
  /**
28
29
  * Carrega tokens + Tailwind (NativeWind) para a subárvore.
29
- * PortalHost é obrigatório para Select, Dialog, Popover e Tooltip (@rn-primitives).
30
+ * - OverlayHostProvider: DropdownMenu (acima da stack, sem Modal/Portal zustand)
31
+ * - PortalHost: Select/Dialog/Popover/Tooltip do rn-primitives
30
32
  *
31
33
  * Dark mode: requer `darkMode: 'class'` no tailwind do app (via createMedwayUiTailwindConfig).
32
34
  */
@@ -45,8 +47,12 @@ function MedwayUiProvider({
45
47
 
46
48
  return (
47
49
  <View style={styles.root} className={isDark ? 'dark' : undefined}>
48
- {children}
49
- <PortalHost />
50
+ <OverlayHostProvider>
51
+ {children}
52
+ <View style={styles.portalHost} pointerEvents="box-none">
53
+ <PortalHost />
54
+ </View>
55
+ </OverlayHostProvider>
50
56
  </View>
51
57
  );
52
58
  }
@@ -55,6 +61,11 @@ const styles = StyleSheet.create({
55
61
  root: {
56
62
  flex: 1,
57
63
  },
64
+ portalHost: {
65
+ ...StyleSheet.absoluteFill,
66
+ zIndex: 99990,
67
+ elevation: 99990,
68
+ },
58
69
  });
59
70
 
60
71
  export { MedwayUiProvider };
@@ -1,3 +1,4 @@
1
+ const fs = require('fs');
1
2
  const path = require('path');
2
3
 
3
4
  const DEFAULT_APP_PAGES_DIR = 'medway-ui';
@@ -15,6 +16,72 @@ function createNativeWindScopeTest(options = {}) {
15
16
  };
16
17
  }
17
18
 
19
+ function createMedwayUiSourceTest() {
20
+ return function isMedwayUiSourceFile(currentFile) {
21
+ return (
22
+ currentFile.includes(`${path.sep}@medway-ui${path.sep}native${path.sep}`) ||
23
+ currentFile.includes(`${path.sep}medway-ui${path.sep}native${path.sep}`)
24
+ );
25
+ };
26
+ }
27
+
28
+ function resolveMedwayUiNativeSrc(projectRoot) {
29
+ const npmNativeSrc = path.join(projectRoot, 'node_modules/@medway-ui/native/src');
30
+
31
+ if (fs.existsSync(npmNativeSrc) && !isNativePackageSymlinkedToMonorepo(projectRoot)) {
32
+ return npmNativeSrc;
33
+ }
34
+
35
+ const monorepoNativeSrc = path.resolve(projectRoot, '../medway-ui/native/src');
36
+ if (fs.existsSync(monorepoNativeSrc)) {
37
+ return monorepoNativeSrc;
38
+ }
39
+
40
+ return npmNativeSrc;
41
+ }
42
+
43
+ function isNativePackageSymlinkedToMonorepo(projectRoot) {
44
+ const nativePath = path.join(projectRoot, 'node_modules/@medway-ui/native');
45
+
46
+ if (!fs.existsSync(nativePath)) {
47
+ return false;
48
+ }
49
+
50
+ try {
51
+ const nativeRealPath = fs.realpathSync(nativePath);
52
+ const monorepoNativePath = fs.realpathSync(
53
+ path.resolve(projectRoot, '../medway-ui/native'),
54
+ );
55
+
56
+ return nativeRealPath === monorepoNativePath;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ function createMedwayUiAliasResolver(projectRoot) {
63
+ const medwayUiNativeSrc = resolveMedwayUiNativeSrc(projectRoot);
64
+ const isMedwayUiSourceFile = createMedwayUiSourceTest();
65
+
66
+ return function resolveMedwayUiAlias(sourcePath, currentFile) {
67
+ if (!isMedwayUiSourceFile(currentFile) || !sourcePath.startsWith('@/')) {
68
+ return undefined;
69
+ }
70
+
71
+ const relativePath = sourcePath.slice(2);
72
+ const extensions = ['', '.tsx', '.ts', '.jsx', '.js', '/index.tsx', '/index.ts'];
73
+
74
+ for (const ext of extensions) {
75
+ const candidate = path.join(medwayUiNativeSrc, `${relativePath}${ext}`);
76
+ if (fs.existsSync(candidate)) {
77
+ return candidate;
78
+ }
79
+ }
80
+
81
+ return undefined;
82
+ };
83
+ }
84
+
18
85
  function loadCssInteropBabelPlugin(projectRoot) {
19
86
  return require(
20
87
  require.resolve('react-native-css-interop/dist/babel-plugin', {
@@ -46,5 +113,8 @@ function createBrownfieldOverride(options = {}) {
46
113
  module.exports = {
47
114
  createBrownfieldOverride,
48
115
  createNativeWindScopeTest,
116
+ createMedwayUiAliasResolver,
117
+ createMedwayUiSourceTest,
118
+ resolveMedwayUiNativeSrc,
49
119
  DEFAULT_APP_PAGES_DIR,
50
120
  };
package/setup/metro.js CHANGED
@@ -29,7 +29,9 @@ function resolveMedwayAlias(moduleName, medwayUiNativeSrc, medwayUiSharedSrc) {
29
29
 
30
30
  return (
31
31
  tryResolveMedwayModule(path.join(medwayUiNativeSrc, relativePath)) ??
32
- tryResolveMedwayModule(path.join(medwayUiSharedSrc, relativePath))
32
+ (medwayUiSharedSrc
33
+ ? tryResolveMedwayModule(path.join(medwayUiSharedSrc, relativePath))
34
+ : null)
33
35
  );
34
36
  }
35
37
 
@@ -92,43 +94,112 @@ function resolveBareModule(moduleName, searchRoots) {
92
94
  return null;
93
95
  }
94
96
 
97
+ /**
98
+ * Detecta monorepo file: (`../medway-ui`) vs pacotes npm (`node_modules/@medway-ui`).
99
+ * Prioriza npm quando o pacote não é symlink para o clone local.
100
+ */
101
+ function isNativePackageSymlinkedToMonorepo(projectRoot) {
102
+ const nativePath = path.join(projectRoot, 'node_modules/@medway-ui/native');
103
+
104
+ if (!fs.existsSync(nativePath)) {
105
+ return false;
106
+ }
107
+
108
+ try {
109
+ const nativeRealPath = fs.realpathSync(nativePath);
110
+ const monorepoNativePath = fs.realpathSync(
111
+ path.resolve(projectRoot, '../medway-ui/native'),
112
+ );
113
+
114
+ return nativeRealPath === monorepoNativePath;
115
+ } catch {
116
+ return false;
117
+ }
118
+ }
119
+
120
+ function detectLinkedMedwayUiRoot(projectRoot) {
121
+ const npmScopedRoot = 'node_modules/@medway-ui';
122
+ const npmNativeSrc = path.resolve(projectRoot, npmScopedRoot, 'native/src');
123
+
124
+ if (fs.existsSync(npmNativeSrc) && !isNativePackageSymlinkedToMonorepo(projectRoot)) {
125
+ return npmScopedRoot;
126
+ }
127
+
128
+ const monorepoRoot = '../medway-ui';
129
+ const monorepoNativeSrc = path.resolve(projectRoot, monorepoRoot, 'native/src');
130
+
131
+ if (fs.existsSync(monorepoNativeSrc)) {
132
+ return monorepoRoot;
133
+ }
134
+
135
+ if (fs.existsSync(npmNativeSrc)) {
136
+ return npmScopedRoot;
137
+ }
138
+
139
+ return monorepoRoot;
140
+ }
141
+
142
+ function resolveMedwayUiPaths(projectRoot, linkedMedwayUiRoot, nativePackageRoot) {
143
+ const medwayUiRoot = path.resolve(projectRoot, linkedMedwayUiRoot);
144
+ const linkedNativeSrc = path.resolve(medwayUiRoot, 'native/src');
145
+ const npmNativeSrc = path.join(nativePackageRoot, 'src');
146
+ const isMonorepoLink = fs.existsSync(linkedNativeSrc);
147
+
148
+ return {
149
+ medwayUiRoot: isMonorepoLink ? medwayUiRoot : nativePackageRoot,
150
+ medwayUiNativeRoot: isMonorepoLink
151
+ ? path.resolve(medwayUiRoot, 'native')
152
+ : nativePackageRoot,
153
+ medwayUiNativeSrc: isMonorepoLink ? linkedNativeSrc : npmNativeSrc,
154
+ medwayUiSharedSrc: isMonorepoLink ? path.resolve(medwayUiRoot, 'src') : null,
155
+ isMonorepoLink,
156
+ };
157
+ }
158
+
95
159
  /**
96
160
  * Metro + NativeWind para @medway-ui/native (monorepo file: ou npm).
97
161
  *
98
162
  * @param {import('expo/metro-config').MetroConfig} config
99
163
  * @param {object} [options]
100
164
  * @param {string} options.projectRoot
101
- * @param {string} [options.linkedMedwayUiRoot='../medway-ui'] - clone local no monorepo
165
+ * @param {string} [options.linkedMedwayUiRoot] - auto-detecta monorepo ou npm quando omitido
102
166
  * @param {boolean} [options.resolveNativeSource=true] - aponta @medway-ui/native para src/
103
167
  */
104
168
  function withMedwayUi(config, options = {}) {
105
169
  const projectRoot = options.projectRoot ?? process.cwd();
106
- const linkedMedwayUiRoot = options.linkedMedwayUiRoot ?? '../medway-ui';
170
+ const linkedMedwayUiRoot =
171
+ options.linkedMedwayUiRoot ?? detectLinkedMedwayUiRoot(projectRoot);
107
172
  const resolveNativeSource = options.resolveNativeSource ?? true;
108
173
 
109
174
  const nativePackageRoot = path.resolve(__dirname, '..');
110
175
  const globalCssInput = path.join(nativePackageRoot, 'setup/global.css');
111
176
 
112
- const medwayUiRoot = path.resolve(projectRoot, linkedMedwayUiRoot);
113
- const medwayUiNativeRoot = path.resolve(medwayUiRoot, 'native');
114
- const medwayUiNativeSrc = path.resolve(medwayUiNativeRoot, 'src');
115
- const medwayUiSharedSrc = path.resolve(medwayUiRoot, 'src');
116
- const escapedMedwayUiRoot = medwayUiRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
117
-
118
- config.watchFolders = [...(config.watchFolders ?? []), medwayUiRoot];
119
-
120
- const existingBlockList = config.resolver.blockList;
121
- const blockListArray = Array.isArray(existingBlockList)
122
- ? existingBlockList
123
- : existingBlockList
124
- ? [existingBlockList]
125
- : [];
126
-
127
- config.resolver.blockList = [
128
- ...blockListArray,
129
- new RegExp(`${escapedMedwayUiRoot}[\\\\/]native[\\\\/]node_modules[\\\\/].*`),
130
- new RegExp(`${escapedMedwayUiRoot}[\\\\/]node_modules[\\\\/].*`),
131
- ];
177
+ const {
178
+ medwayUiRoot,
179
+ medwayUiNativeRoot,
180
+ medwayUiNativeSrc,
181
+ medwayUiSharedSrc,
182
+ isMonorepoLink,
183
+ } = resolveMedwayUiPaths(projectRoot, linkedMedwayUiRoot, nativePackageRoot);
184
+
185
+ if (isMonorepoLink) {
186
+ const escapedMedwayUiRoot = medwayUiRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
187
+
188
+ config.watchFolders = [...(config.watchFolders ?? []), medwayUiRoot];
189
+
190
+ const existingBlockList = config.resolver.blockList;
191
+ const blockListArray = Array.isArray(existingBlockList)
192
+ ? existingBlockList
193
+ : existingBlockList
194
+ ? [existingBlockList]
195
+ : [];
196
+
197
+ config.resolver.blockList = [
198
+ ...blockListArray,
199
+ new RegExp(`${escapedMedwayUiRoot}[\\\\/]native[\\\\/]node_modules[\\\\/].*`),
200
+ new RegExp(`${escapedMedwayUiRoot}[\\\\/]node_modules[\\\\/].*`),
201
+ ];
202
+ }
132
203
 
133
204
  function isMedwayUiOrigin(originModulePath) {
134
205
  return (
@@ -192,4 +263,4 @@ function withMedwayUi(config, options = {}) {
192
263
  });
193
264
  }
194
265
 
195
- module.exports = { withMedwayUi };
266
+ module.exports = { withMedwayUi, detectLinkedMedwayUiRoot, resolveMedwayUiPaths };
package/setup/tailwind.js CHANGED
@@ -1,13 +1,69 @@
1
+ const fs = require('fs');
1
2
  const path = require('path');
2
3
 
3
4
  function loadDesignTokens(projectRoot) {
4
- return require(require.resolve('@medway-ui/core/tokens', { paths: [projectRoot] }));
5
+ const tokensPath = require.resolve('@medway-ui/core/tokens', {
6
+ paths: [projectRoot],
7
+ });
8
+
9
+ try {
10
+ return require(tokensPath);
11
+ } catch (error) {
12
+ // Node 22+ não permite require de .ts dentro de node_modules.
13
+ if (error?.code !== 'ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING') {
14
+ throw error;
15
+ }
16
+
17
+ const jiti = require('jiti')(path.join(projectRoot, 'tailwind.config.js'));
18
+ return jiti(tokensPath);
19
+ }
5
20
  }
6
21
 
7
22
  function resolveNativePackageRoot() {
8
23
  return path.resolve(__dirname, '..');
9
24
  }
10
25
 
26
+ /**
27
+ * React Native registers Montserrat as separate family names per weight
28
+ * (MontserratMedium, MontserratSemiBold, …). Numeric fontWeight + "Montserrat"
29
+ * does not resolve the file, so weight utilities must set fontFamily instead.
30
+ * Keys stay aligned with Medway UI tokens (`regular` | `medium` | `semibold` | …).
31
+ */
32
+ const NATIVE_MONTSERRAT_BY_WEIGHT = {
33
+ thin: 'MontserratLight',
34
+ extralight: 'MontserratLight',
35
+ light: 'MontserratLight',
36
+ normal: 'Montserrat',
37
+ regular: 'Montserrat',
38
+ medium: 'MontserratMedium',
39
+ semibold: 'MontserratSemiBold',
40
+ bold: 'MontserratBold',
41
+ extrabold: 'MontserratExtraBold',
42
+ black: 'MontserratBlack',
43
+ };
44
+
45
+ function createNativeMontserratFontPlugin() {
46
+ // Lazy-require so greenfield web tooling can still import this file if needed.
47
+ const plugin = require('tailwindcss/plugin');
48
+
49
+ return plugin(({ addBase, addUtilities }) => {
50
+ addBase({
51
+ '*': {
52
+ fontFamily: 'Montserrat',
53
+ },
54
+ });
55
+
56
+ addUtilities(
57
+ Object.fromEntries(
58
+ Object.entries(NATIVE_MONTSERRAT_BY_WEIGHT).map(([weight, fontFamily]) => [
59
+ `.font-${weight}`,
60
+ { fontFamily },
61
+ ]),
62
+ ),
63
+ );
64
+ });
65
+ }
66
+
11
67
  /**
12
68
  * Tailwind config para apps com @medway-ui/native.
13
69
  *
@@ -23,14 +79,12 @@ function createMedwayUiTailwindConfig(options = {}) {
23
79
  colors,
24
80
  fontFamily,
25
81
  fontSize,
26
- fontWeight,
27
82
  lineHeight,
28
83
  borderRadius,
29
84
  boxShadow,
30
85
  } = loadDesignTokens(projectRoot);
31
86
 
32
87
  const nativeRoot = resolveNativePackageRoot();
33
- const nativeSrc = path.join(nativeRoot, 'src');
34
88
 
35
89
  const libContent = [
36
90
  path.join(nativeRoot, 'src/**/*.{js,jsx,ts,tsx}'),
@@ -38,9 +92,15 @@ function createMedwayUiTailwindConfig(options = {}) {
38
92
  ];
39
93
 
40
94
  if (linkedMedwayUiRoot) {
41
- libContent.push(
42
- path.resolve(projectRoot, linkedMedwayUiRoot, 'native/src/**/*.{ts,tsx}'),
95
+ const linkedNativeSrc = path.resolve(
96
+ projectRoot,
97
+ linkedMedwayUiRoot,
98
+ 'native/src',
43
99
  );
100
+
101
+ if (fs.existsSync(linkedNativeSrc)) {
102
+ libContent.push(path.join(linkedNativeSrc, '**/*.{ts,tsx}'));
103
+ }
44
104
  }
45
105
 
46
106
  return {
@@ -48,17 +108,25 @@ function createMedwayUiTailwindConfig(options = {}) {
48
108
  darkMode: 'class',
49
109
  presets: [require('nativewind/preset')],
50
110
  theme: {
111
+ // Disable numeric font-weight utilities; RN needs fontFamily per weight.
112
+ fontWeight: {},
51
113
  extend: {
52
114
  colors,
53
- fontFamily,
115
+ fontFamily: {
116
+ ...fontFamily,
117
+ sans: ['Montserrat'],
118
+ },
54
119
  fontSize,
55
- fontWeight,
56
120
  lineHeight,
57
121
  borderRadius,
58
122
  boxShadow,
59
123
  },
60
124
  },
125
+ plugins: [createNativeMontserratFontPlugin()],
61
126
  };
62
127
  }
63
128
 
64
- module.exports = { createMedwayUiTailwindConfig };
129
+ module.exports = {
130
+ createMedwayUiTailwindConfig,
131
+ NATIVE_MONTSERRAT_BY_WEIGHT,
132
+ };
@@ -545,11 +545,15 @@
545
545
  --color-gradient-pt-bg-2: var(--color-gray-450);
546
546
 
547
547
  /* === Typography fontfamily === */
548
- --font-sans:
549
- "Montserrat", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
550
- "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
548
+ /* RN: single family name (loaded via expo-font as "Montserrat"). */
549
+ --font-sans: Montserrat;
551
550
 
552
551
  /* === Typography weight === */
552
+ /*
553
+ * Token keys stay the same as web. On native, Tailwind maps these class
554
+ * names (font-medium, font-semibold, …) to Montserrat* fontFamily files
555
+ * in setup/tailwind.js — numeric fontWeight is not used for RN text.
556
+ */
553
557
  --font-weight-regular: 400;
554
558
  --font-weight-medium: 500;
555
559
  --font-weight-semibold: 600;
@@ -615,6 +619,7 @@
615
619
  --sidebar-width-mobile: 256px;
616
620
  --sidebar-width-icon: 72px;
617
621
  }
622
+
618
623
  .dark {
619
624
  /* === Dark base colors === */
620
625
  --color-background: var(--color-gray-850);
@@ -4,7 +4,9 @@ import {
4
4
  useMemo,
5
5
  type ReactNode,
6
6
  } from "react";
7
- import { View, Text, Pressable, type ViewProps, type PressableProps } from "react-native";
7
+ import { View, Pressable, type ViewProps, type PressableProps } from "react-native";
8
+
9
+ import { Text } from "@/components/Text";
8
10
  import { cva, type VariantProps } from "class-variance-authority";
9
11
  import { CloseMd } from "@medway-ui/icons/native";
10
12
  import { useThemeColor } from "@/hooks/useThemeColor";
@@ -141,7 +143,7 @@ function AlertDescription({ className, children, ...props }: ViewProps & { child
141
143
  <View className={cn("", className)} {...props}>
142
144
  <Text
143
145
  numberOfLines={3}
144
- className={cn("text-sm leading-5", alertTextColorVariants({ variant }))}
146
+ className={cn("text-sm font-medium leading-5", alertTextColorVariants({ variant }))}
145
147
  >
146
148
  {children}
147
149
  </Text>
@@ -1,5 +1,7 @@
1
1
  import { type ReactNode } from "react";
2
- import { View, Text, type ViewProps } from "react-native";
2
+ import { View, type ViewProps } from "react-native";
3
+
4
+ import { Text } from "@/components/Text";
3
5
  import * as AvatarPrimitive from "@rn-primitives/avatar";
4
6
  import { cva, type VariantProps } from "class-variance-authority";
5
7
  import { User } from "@medway-ui/icons/native";
@@ -1,5 +1,7 @@
1
1
  import { type ReactNode } from "react";
2
- import { View, Text, type ViewProps } from "react-native";
2
+ import { View, type ViewProps } from "react-native";
3
+
4
+ import { Text } from "@/components/Text";
3
5
  import { cva, type VariantProps } from "class-variance-authority";
4
6
  import { cn } from "@/lib/utils";
5
7
 
@@ -1,11 +1,7 @@
1
1
  import { type ReactNode } from "react";
2
- import {
3
- Pressable,
4
- View,
5
- Text,
6
- type PressableProps,
7
- type ViewStyle,
8
- } from "react-native";
2
+ import { Pressable, View, type PressableProps, type ViewStyle } from "react-native";
3
+
4
+ import { Text } from "@/components/Text";
9
5
  import { cva, type VariantProps } from "class-variance-authority";
10
6
  import { cn } from "@/lib/utils";
11
7
  import { Loading } from "@/components/Loading";
@@ -8,13 +8,14 @@ import {
8
8
  } from "react";
9
9
  import {
10
10
  Image,
11
- Text,
12
11
  View,
13
12
  useWindowDimensions,
14
13
  type ImageProps,
15
14
  type ViewProps,
16
15
  } from "react-native";
17
16
 
17
+ import { Text } from "@/components/Text";
18
+
18
19
  import { Avatar, AvatarFallback, AvatarImage } from "@/components/Avatar";
19
20
  import { Button, type ButtonProps } from "@/components/Button";
20
21
  import { FallbackImage } from "@/components/FallbackImage";