@effijs/templates 0.0.0-stage → 1.0.0-alpha.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 (367) hide show
  1. package/CONTRIBUTING.md +27 -0
  2. package/LICENSE +22 -0
  3. package/README.md +32 -2
  4. package/ai/SETUP.md +5 -0
  5. package/docs/catalog.md +85 -0
  6. package/forge.manifest.js +75 -0
  7. package/lib/compat.js +40 -0
  8. package/lib/docs/build.js +146 -0
  9. package/lib/install.js +51 -0
  10. package/lib/journal.js +40 -0
  11. package/lib/jsonConfig.js +33 -0
  12. package/lib/migration.js +35 -0
  13. package/lib/names.js +42 -0
  14. package/lib/patch.js +62 -0
  15. package/lib/paths.js +12 -0
  16. package/lib/project.js +48 -0
  17. package/lib/registry.js +99 -0
  18. package/package.json +46 -4
  19. package/platforms/react-native/CATALOG.md +391 -0
  20. package/platforms/react-native/ORIGIN.md +42 -0
  21. package/platforms/react-native/README.md +78 -0
  22. package/platforms/react-native/ai/AGENTS.md.hbs +36 -0
  23. package/platforms/react-native/ai/SETUP.md +89 -0
  24. package/platforms/react-native/compat/matrix.js +150 -0
  25. package/platforms/react-native/configs/babel.js +63 -0
  26. package/platforms/react-native/configs/forgeConfig.js +35 -0
  27. package/platforms/react-native/configs/jsConfigs.js +96 -0
  28. package/platforms/react-native/configs/metro.js +86 -0
  29. package/platforms/react-native/generators/add/generator.js +12 -0
  30. package/platforms/react-native/generators/add/run.js +64 -0
  31. package/platforms/react-native/generators/component/generator.js +75 -0
  32. package/platforms/react-native/generators/component/render.js +69 -0
  33. package/platforms/react-native/generators/component/templates/Common.tsx.hbs +13 -0
  34. package/platforms/react-native/generators/component/templates/index.ts.hbs +13 -0
  35. package/platforms/react-native/generators/component/templates/pm.ts.hbs +7 -0
  36. package/platforms/react-native/generators/component/templates/types.ts.hbs +3 -0
  37. package/platforms/react-native/generators/demo/files/api/app.http +8 -0
  38. package/platforms/react-native/generators/demo/files/api/environment/http-client.env.json +5 -0
  39. package/platforms/react-native/generators/demo/files/entity/category/category.api.ts +18 -0
  40. package/platforms/react-native/generators/demo/files/entity/category/category.dto.ts +15 -0
  41. package/platforms/react-native/generators/demo/files/entity/category/category.service.ts +42 -0
  42. package/platforms/react-native/generators/demo/files/entity/category/category.store.ts +26 -0
  43. package/platforms/react-native/generators/demo/files/entity/category/index.ts +2 -0
  44. package/platforms/react-native/generators/demo/files/entity/product/index.ts +2 -0
  45. package/platforms/react-native/generators/demo/files/entity/product/product.api.ts +49 -0
  46. package/platforms/react-native/generators/demo/files/entity/product/product.dto.ts +120 -0
  47. package/platforms/react-native/generators/demo/files/entity/product/product.service.ts +139 -0
  48. package/platforms/react-native/generators/demo/files/entity/product/product.store.ts +37 -0
  49. package/platforms/react-native/generators/demo/files/feature/product/components/Product.CategorySelect.tsx +36 -0
  50. package/platforms/react-native/generators/demo/files/feature/product/detail/Product.Detail.Screen.tsx +100 -0
  51. package/platforms/react-native/generators/demo/files/feature/product/detail/product.detail.service.ts +33 -0
  52. package/platforms/react-native/generators/demo/files/feature/product/filter/Product.Filter.Screen.tsx +59 -0
  53. package/platforms/react-native/generators/demo/files/feature/product/filter/product.filter.service.ts +78 -0
  54. package/platforms/react-native/generators/demo/files/feature/product/form/Product.Form.Screen.tsx +71 -0
  55. package/platforms/react-native/generators/demo/files/feature/product/form/product.form.service.ts +142 -0
  56. package/platforms/react-native/generators/demo/files/feature/product/index.ts +7 -0
  57. package/platforms/react-native/generators/demo/files/feature/product/list/Product.List.Item.tsx +34 -0
  58. package/platforms/react-native/generators/demo/files/feature/product/list/Product.List.Screen.tsx +106 -0
  59. package/platforms/react-native/generators/demo/files/feature/product/list/product.list.service.ts +47 -0
  60. package/platforms/react-native/generators/demo/files/feature/product/product.feature.ts +29 -0
  61. package/platforms/react-native/generators/demo/files/feature/product/product.hooks.ts +7 -0
  62. package/platforms/react-native/generators/demo/files/feature/product/search/Product.Search.Screen.tsx +82 -0
  63. package/platforms/react-native/generators/demo/files/feature/product/search/product.search.service.ts +97 -0
  64. package/platforms/react-native/generators/demo/files/navigation/navigation.product.ts +46 -0
  65. package/platforms/react-native/generators/demo/generator.js +93 -0
  66. package/platforms/react-native/generators/entity/generator.js +68 -0
  67. package/platforms/react-native/generators/feature/generator.js +224 -0
  68. package/platforms/react-native/generators/feature/render.js +163 -0
  69. package/platforms/react-native/generators/feature/templates/detail.screen.tsx.hbs +25 -0
  70. package/platforms/react-native/generators/feature/templates/detail.service.ts.hbs +14 -0
  71. package/platforms/react-native/generators/feature/templates/feature.ts.hbs +18 -0
  72. package/platforms/react-native/generators/feature/templates/filter.screen.tsx.hbs +17 -0
  73. package/platforms/react-native/generators/feature/templates/filter.service.ts.hbs +14 -0
  74. package/platforms/react-native/generators/feature/templates/form.screen.tsx.hbs +21 -0
  75. package/platforms/react-native/generators/feature/templates/form.service.ts.hbs +37 -0
  76. package/platforms/react-native/generators/feature/templates/hooks.ts.hbs +7 -0
  77. package/platforms/react-native/generators/feature/templates/index.ts.hbs +2 -0
  78. package/platforms/react-native/generators/feature/templates/list.item.tsx.hbs +16 -0
  79. package/platforms/react-native/generators/feature/templates/list.screen.tsx.hbs +34 -0
  80. package/platforms/react-native/generators/feature/templates/list.service.ts.hbs +15 -0
  81. package/platforms/react-native/generators/feature/templates/navigation.ts.hbs +12 -0
  82. package/platforms/react-native/generators/feature/templates/search.screen.tsx.hbs +24 -0
  83. package/platforms/react-native/generators/feature/templates/search.service.ts.hbs +13 -0
  84. package/platforms/react-native/generators/feature/templates/tab.tsx.hbs +8 -0
  85. package/platforms/react-native/generators/init/files/app/app.controller.ts +41 -0
  86. package/platforms/react-native/generators/init/files/app/app.error.ts +1 -0
  87. package/platforms/react-native/generators/init/files/app/app.store.ts +12 -0
  88. package/platforms/react-native/generators/init/files/app/index.ts +19 -0
  89. package/platforms/react-native/generators/init/files/app/splash/Onboarding.Screen.tsx +31 -0
  90. package/platforms/react-native/generators/init/files/app/splash/Splash.Screen.tsx +14 -0
  91. package/platforms/react-native/generators/init/files/app/tabs/home/Home.tab.tsx +24 -0
  92. package/platforms/react-native/generators/init/files/app/tabs/profile/Profile.tab.tsx +1 -0
  93. package/platforms/react-native/generators/init/files/configs/dev.ts.hbs +5 -0
  94. package/platforms/react-native/generators/init/files/configs/index.ts +4 -0
  95. package/platforms/react-native/generators/init/files/configs/prod.ts.hbs +5 -0
  96. package/platforms/react-native/generators/init/files/entity/auth/auth.api.ts +36 -0
  97. package/platforms/react-native/generators/init/files/entity/auth/auth.dto.ts +26 -0
  98. package/platforms/react-native/generators/init/files/entity/auth/auth.service.ts +94 -0
  99. package/platforms/react-native/generators/init/files/entity/auth/auth.session.store.ts +14 -0
  100. package/platforms/react-native/generators/init/files/entity/auth/auth.store.ts +20 -0
  101. package/platforms/react-native/generators/init/files/entity/auth/index.ts +2 -0
  102. package/platforms/react-native/generators/init/files/entity/index.ts +2 -0
  103. package/platforms/react-native/generators/init/files/feature/auth/auth.feature.ts +10 -0
  104. package/platforms/react-native/generators/init/files/feature/auth/auth.hooks.ts +7 -0
  105. package/platforms/react-native/generators/init/files/feature/auth/index.ts +1 -0
  106. package/platforms/react-native/generators/init/files/feature/auth/sign-in/SignIn.Screen.tsx +39 -0
  107. package/platforms/react-native/generators/init/files/feature/auth/sign-in/signIn.service.ts +54 -0
  108. package/platforms/react-native/generators/init/files/feature/auth/sign-up/SignUp.Screen.tsx +64 -0
  109. package/platforms/react-native/generators/init/files/feature/auth/sign-up/signUp.service.ts +73 -0
  110. package/platforms/react-native/generators/init/files/feature/feature.hooks.ts +15 -0
  111. package/platforms/react-native/generators/init/files/feature/index.ts +3 -0
  112. package/platforms/react-native/generators/init/files/feature/profile/Profile.Screen.tsx +52 -0
  113. package/platforms/react-native/generators/init/files/feature/profile/index.ts +1 -0
  114. package/platforms/react-native/generators/init/files/feature/profile/profile.feature.ts +18 -0
  115. package/platforms/react-native/generators/init/files/feature/profile/profile.hooks.ts +7 -0
  116. package/platforms/react-native/generators/init/files/index.ts +16 -0
  117. package/platforms/react-native/generators/init/files/navigation/index.ts +18 -0
  118. package/platforms/react-native/generators/init/files/navigation/navigation.app.ts +58 -0
  119. package/platforms/react-native/generators/init/files/navigation/navigation.features.ts +9 -0
  120. package/platforms/react-native/generators/init/files/navigation/navigation.hooks.ts +5 -0
  121. package/platforms/react-native/generators/init/files/navigation/navigation.tabs.ts +55 -0
  122. package/platforms/react-native/generators/init/files/navigation/navigation.widgets.ts +23 -0
  123. package/platforms/react-native/generators/init/files/services/http/http.base.ts +69 -0
  124. package/platforms/react-native/generators/init/files/services/http/http.error.ts +10 -0
  125. package/platforms/react-native/generators/init/files/services/http/http.service.ts +24 -0
  126. package/platforms/react-native/generators/init/files/services/http/middleware/index.ts +12 -0
  127. package/platforms/react-native/generators/init/files/services/http/middleware/middleware.error.ts +36 -0
  128. package/platforms/react-native/generators/init/files/services/http/middleware/middleware.registry.ts +3 -0
  129. package/platforms/react-native/generators/init/files/services/http/middleware/middleware.token.ts +97 -0
  130. package/platforms/react-native/generators/init/files/services/index.ts +15 -0
  131. package/platforms/react-native/generators/init/files/ui/components/Box/Common.tsx +19 -0
  132. package/platforms/react-native/generators/init/files/ui/components/Box/box.pm.ts +111 -0
  133. package/platforms/react-native/generators/init/files/ui/components/Box/box.types.ts +8 -0
  134. package/platforms/react-native/generators/init/files/ui/components/Box/index.ts +13 -0
  135. package/platforms/react-native/generators/init/files/ui/components/Button/Common.tsx +50 -0
  136. package/platforms/react-native/generators/init/files/ui/components/Button/Touchable.tsx +19 -0
  137. package/platforms/react-native/generators/init/files/ui/components/Button/button.pm.ts +197 -0
  138. package/platforms/react-native/generators/init/files/ui/components/Button/button.types.ts +22 -0
  139. package/platforms/react-native/generators/init/files/ui/components/Button/button.utils.ts +16 -0
  140. package/platforms/react-native/generators/init/files/ui/components/Button/index.ts +19 -0
  141. package/platforms/react-native/generators/init/files/ui/components/Form/Colours.tsx +50 -0
  142. package/platforms/react-native/generators/init/files/ui/components/Form/Common.tsx +38 -0
  143. package/platforms/react-native/generators/init/files/ui/components/Form/ErrorText.tsx +11 -0
  144. package/platforms/react-native/generators/init/files/ui/components/Form/Input.tsx +115 -0
  145. package/platforms/react-native/generators/init/files/ui/components/Form/InputArea.tsx +70 -0
  146. package/platforms/react-native/generators/init/files/ui/components/Form/Label.tsx +18 -0
  147. package/platforms/react-native/generators/init/files/ui/components/Form/Select.tsx +86 -0
  148. package/platforms/react-native/generators/init/files/ui/components/Form/components/SecureTextEntry.tsx +19 -0
  149. package/platforms/react-native/generators/init/files/ui/components/Form/form.error.ts +18 -0
  150. package/platforms/react-native/generators/init/files/ui/components/Form/form.pm.ts +134 -0
  151. package/platforms/react-native/generators/init/files/ui/components/Form/form.types.ts +59 -0
  152. package/platforms/react-native/generators/init/files/ui/components/Form/index.ts +67 -0
  153. package/platforms/react-native/generators/init/files/ui/components/Grid/Common.tsx +11 -0
  154. package/platforms/react-native/generators/init/files/ui/components/Grid/grid.pm.ts +93 -0
  155. package/platforms/react-native/generators/init/files/ui/components/Grid/grid.types.ts +79 -0
  156. package/platforms/react-native/generators/init/files/ui/components/Grid/index.ts +13 -0
  157. package/platforms/react-native/generators/init/files/ui/components/Icon/Common.tsx +19 -0
  158. package/platforms/react-native/generators/init/files/ui/components/Icon/icons.pm.ts +74 -0
  159. package/platforms/react-native/generators/init/files/ui/components/Icon/icons.types.ts +19 -0
  160. package/platforms/react-native/generators/init/files/ui/components/Icon/index.ts +3 -0
  161. package/platforms/react-native/generators/init/files/ui/components/Loading/Loading.tsx +10 -0
  162. package/platforms/react-native/generators/init/files/ui/components/Loading/loading.hook.ts +5 -0
  163. package/platforms/react-native/generators/init/files/ui/components/Loading/loading.service.ts +22 -0
  164. package/platforms/react-native/generators/init/files/ui/components/Loading/loading.store.ts +8 -0
  165. package/platforms/react-native/generators/init/files/ui/components/Screen/Common.tsx +87 -0
  166. package/platforms/react-native/generators/init/files/ui/components/Screen/Content.tsx +77 -0
  167. package/platforms/react-native/generators/init/files/ui/components/Screen/Header.tsx +80 -0
  168. package/platforms/react-native/generators/init/files/ui/components/Screen/HeaderTab.tsx +17 -0
  169. package/platforms/react-native/generators/init/files/ui/components/Screen/SafeAreaHOC.tsx +9 -0
  170. package/platforms/react-native/generators/init/files/ui/components/Screen/index.ts +22 -0
  171. package/platforms/react-native/generators/init/files/ui/components/Text/Common.tsx +20 -0
  172. package/platforms/react-native/generators/init/files/ui/components/Text/index.ts +13 -0
  173. package/platforms/react-native/generators/init/files/ui/components/Text/text.pm.ts +55 -0
  174. package/platforms/react-native/generators/init/files/ui/components/Text/text.types.ts +27 -0
  175. package/platforms/react-native/generators/init/files/ui/components/TextInput/Common.tsx +19 -0
  176. package/platforms/react-native/generators/init/files/ui/components/TextInput/index.ts +15 -0
  177. package/platforms/react-native/generators/init/files/ui/components/TextInput/textInput.pm.ts +65 -0
  178. package/platforms/react-native/generators/init/files/ui/components/TextInput/textInput.types.ts +16 -0
  179. package/platforms/react-native/generators/init/files/ui/components/ThemePicker/ThemePicker.tsx +92 -0
  180. package/platforms/react-native/generators/init/files/ui/components/ThemePicker/index.ts +1 -0
  181. package/platforms/react-native/generators/init/files/ui/components/index.ts +27 -0
  182. package/platforms/react-native/generators/init/files/ui/components/utils/color.ts +19 -0
  183. package/platforms/react-native/generators/init/files/ui/components/utils/index.ts +3 -0
  184. package/platforms/react-native/generators/init/files/ui/components/utils/useLoading.hook.spec.tsx +202 -0
  185. package/platforms/react-native/generators/init/files/ui/components/utils/useLoading.hook.ts +172 -0
  186. package/platforms/react-native/generators/init/files/ui/components/utils/useStore.ts +34 -0
  187. package/platforms/react-native/generators/init/files/ui/fonts/font-icons.ttf +0 -0
  188. package/platforms/react-native/generators/init/files/ui/icons/font-icons.json +53 -0
  189. package/platforms/react-native/generators/init/files/ui/icons/logo.png +0 -0
  190. package/platforms/react-native/generators/init/files/ui/icons/logo.svg +304 -0
  191. package/platforms/react-native/generators/init/files/ui/icons/tabs/icon-1.png +0 -0
  192. package/platforms/react-native/generators/init/files/ui/icons/tabs/icon-2.png +0 -0
  193. package/platforms/react-native/generators/init/files/ui/theme/black/black.color.ts +8 -0
  194. package/platforms/react-native/generators/init/files/ui/theme/black/index.ts +10 -0
  195. package/platforms/react-native/generators/init/files/ui/theme/blue/blue.color.ts +8 -0
  196. package/platforms/react-native/generators/init/files/ui/theme/blue/index.ts +10 -0
  197. package/platforms/react-native/generators/init/files/ui/theme/green/green.color.ts +8 -0
  198. package/platforms/react-native/generators/init/files/ui/theme/green/index.ts +10 -0
  199. package/platforms/react-native/generators/init/files/ui/theme/index.ts +11 -0
  200. package/platforms/react-native/generators/init/files/ui/theme/pink/index.ts +10 -0
  201. package/platforms/react-native/generators/init/files/ui/theme/pink/pink.color.ts +8 -0
  202. package/platforms/react-native/generators/init/files/ui/theme/scheme/index.ts +23 -0
  203. package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.color.ts +139 -0
  204. package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.radius.ts +21 -0
  205. package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.spacing.ts +24 -0
  206. package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.ts +25 -0
  207. package/platforms/react-native/generators/init/files/ui/theme/scheme/theme.scheme.typography.ts +98 -0
  208. package/platforms/react-native/generators/init/files/ui/theme/shared/index.ts +4 -0
  209. package/platforms/react-native/generators/init/files/ui/theme/shared/shared.color.base.ts +79 -0
  210. package/platforms/react-native/generators/init/files/ui/theme/shared/shared.radius.ts +8 -0
  211. package/platforms/react-native/generators/init/files/ui/theme/shared/shared.spacing.ts +9 -0
  212. package/platforms/react-native/generators/init/files/ui/theme/shared/shared.typography.ts +105 -0
  213. package/platforms/react-native/generators/init/files/ui/theme/theme.hooks.ts +7 -0
  214. package/platforms/react-native/generators/init/files/ui/theme/theme.meta.ts +10 -0
  215. package/platforms/react-native/generators/init/files/ui/theme/theme.provider.tsx +19 -0
  216. package/platforms/react-native/generators/init/files/ui/theme/theme.service.ts +36 -0
  217. package/platforms/react-native/generators/init/files/ui/theme/theme.ts +27 -0
  218. package/platforms/react-native/generators/init/files/ui/widgets/index.ts +1 -0
  219. package/platforms/react-native/generators/init/files/ui/widgets/toast/Toast.Item.tsx +175 -0
  220. package/platforms/react-native/generators/init/files/ui/widgets/toast/Toast.Overlay.tsx +46 -0
  221. package/platforms/react-native/generators/init/files/ui/widgets/toast/Toast.Stack.tsx +75 -0
  222. package/platforms/react-native/generators/init/files/ui/widgets/toast/index.ts +7 -0
  223. package/platforms/react-native/generators/init/files/ui/widgets/toast/toast.hooks.ts +18 -0
  224. package/platforms/react-native/generators/init/files/ui/widgets/toast/toast.service.ts +39 -0
  225. package/platforms/react-native/generators/init/files/ui/widgets/toast/toast.store.ts +59 -0
  226. package/platforms/react-native/generators/init/files/ui/widgets/toast/toast.types.ts +18 -0
  227. package/platforms/react-native/generators/init/files/ui/widgets/widgets.feature.ts +14 -0
  228. package/platforms/react-native/generators/init/files/utils/date.ts +11 -0
  229. package/platforms/react-native/generators/init/files/utils/index.ts +12 -0
  230. package/platforms/react-native/generators/init/files/utils/store.persistent.ts +103 -0
  231. package/platforms/react-native/generators/init/files/utils/store.registry.ts +14 -0
  232. package/platforms/react-native/generators/init/files/utils/string.ts +100 -0
  233. package/platforms/react-native/generators/init/generator.js +86 -0
  234. package/platforms/react-native/generators/init/kit.js +23 -0
  235. package/platforms/react-native/generators/init/navigators/expo-router/index.ts +18 -0
  236. package/platforms/react-native/generators/init/navigators/expo-router/navigation.app.ts +8 -0
  237. package/platforms/react-native/generators/init/navigators/expo-router/navigation.features.ts +9 -0
  238. package/platforms/react-native/generators/init/navigators/expo-router/navigation.hooks.ts +5 -0
  239. package/platforms/react-native/generators/init/navigators/expo-router/navigation.tabs.ts +7 -0
  240. package/platforms/react-native/generators/init/navigators/expo-router/navigation.widgets.ts +5 -0
  241. package/platforms/react-native/generators/init/navigators/react-navigation/index.ts +18 -0
  242. package/platforms/react-native/generators/init/navigators/react-navigation/navigation.app.ts +8 -0
  243. package/platforms/react-native/generators/init/navigators/react-navigation/navigation.features.ts +9 -0
  244. package/platforms/react-native/generators/init/navigators/react-navigation/navigation.hooks.ts +5 -0
  245. package/platforms/react-native/generators/init/navigators/react-navigation/navigation.tabs.ts +7 -0
  246. package/platforms/react-native/generators/init/navigators/react-navigation/navigation.widgets.ts +5 -0
  247. package/platforms/react-native/generators/setup/generator.js +225 -0
  248. package/platforms/react-native/generators/util/generator.js +12 -0
  249. package/platforms/react-native/platform.js +32 -0
  250. package/platforms/react-native/runtime.js +57 -0
  251. package/platforms/react-native/solutions/components/BottomSheet/README.md +29 -0
  252. package/platforms/react-native/solutions/components/BottomSheet/files/Common.tsx +120 -0
  253. package/platforms/react-native/solutions/components/BottomSheet/files/Content.tsx +57 -0
  254. package/platforms/react-native/solutions/components/BottomSheet/files/Context.tsx +22 -0
  255. package/platforms/react-native/solutions/components/BottomSheet/files/FlatList.tsx +50 -0
  256. package/platforms/react-native/solutions/components/BottomSheet/files/Header.tsx +57 -0
  257. package/platforms/react-native/solutions/components/BottomSheet/files/Search.tsx +24 -0
  258. package/platforms/react-native/solutions/components/BottomSheet/files/bottomSheet.constants.ts +13 -0
  259. package/platforms/react-native/solutions/components/BottomSheet/files/bottomSheet.types.ts +31 -0
  260. package/platforms/react-native/solutions/components/BottomSheet/files/index.ts +33 -0
  261. package/platforms/react-native/solutions/components/BottomSheet/solution.js +38 -0
  262. package/platforms/react-native/solutions/components/BottomSheetWidgets/README.md +29 -0
  263. package/platforms/react-native/solutions/components/BottomSheetWidgets/files/SelectPicker.tsx +47 -0
  264. package/platforms/react-native/solutions/components/BottomSheetWidgets/files/bottomSheet/Content.BottomSheet.tsx +22 -0
  265. package/platforms/react-native/solutions/components/BottomSheetWidgets/files/bottomSheet/DateTimePicker.BottomSheet.tsx +74 -0
  266. package/platforms/react-native/solutions/components/BottomSheetWidgets/files/bottomSheet/List.BottomSheet.tsx +62 -0
  267. package/platforms/react-native/solutions/components/BottomSheetWidgets/solution.js +49 -0
  268. package/platforms/react-native/solutions/components/Calendar/README.md +29 -0
  269. package/platforms/react-native/solutions/components/Calendar/files/Common.tsx +16 -0
  270. package/platforms/react-native/solutions/components/Calendar/files/Context.tsx +466 -0
  271. package/platforms/react-native/solutions/components/Calendar/files/DayCell.tsx +89 -0
  272. package/platforms/react-native/solutions/components/Calendar/files/MonthView.tsx +41 -0
  273. package/platforms/react-native/solutions/components/Calendar/files/MonthYearOverlay.tsx +51 -0
  274. package/platforms/react-native/solutions/components/Calendar/files/SwipeablePeriod.tsx +44 -0
  275. package/platforms/react-native/solutions/components/Calendar/files/WeekDayTitles.tsx +31 -0
  276. package/platforms/react-native/solutions/components/Calendar/files/WeekView.tsx +40 -0
  277. package/platforms/react-native/solutions/components/Calendar/files/calendar.styles.ts +142 -0
  278. package/platforms/react-native/solutions/components/Calendar/files/calendar.types.ts +126 -0
  279. package/platforms/react-native/solutions/components/Calendar/files/calendar.utils.ts +143 -0
  280. package/platforms/react-native/solutions/components/Calendar/files/index.ts +40 -0
  281. package/platforms/react-native/solutions/components/Calendar/solution.js +38 -0
  282. package/platforms/react-native/solutions/components/Chart/README.md +29 -0
  283. package/platforms/react-native/solutions/components/Chart/files/Cilcular.tsx +140 -0
  284. package/platforms/react-native/solutions/components/Chart/files/index.ts +3 -0
  285. package/platforms/react-native/solutions/components/Chart/solution.js +38 -0
  286. package/platforms/react-native/solutions/components/CheckBox/README.md +29 -0
  287. package/platforms/react-native/solutions/components/CheckBox/files/Common.tsx +55 -0
  288. package/platforms/react-native/solutions/components/CheckBox/files/checkbox.pm.ts +71 -0
  289. package/platforms/react-native/solutions/components/CheckBox/files/index.ts +9 -0
  290. package/platforms/react-native/solutions/components/CheckBox/form/Checkbox.tsx +22 -0
  291. package/platforms/react-native/solutions/components/CheckBox/solution.js +57 -0
  292. package/platforms/react-native/solutions/components/DateTimePicker/README.md +29 -0
  293. package/platforms/react-native/solutions/components/DateTimePicker/files/DateTimePicker.tsx +44 -0
  294. package/platforms/react-native/solutions/components/DateTimePicker/solution.js +45 -0
  295. package/platforms/react-native/solutions/components/Image/README.md +29 -0
  296. package/platforms/react-native/solutions/components/Image/files/SVG.tsx +74 -0
  297. package/platforms/react-native/solutions/components/Image/files/image.pm.ts +25 -0
  298. package/platforms/react-native/solutions/components/Image/files/image.utils.ts +35 -0
  299. package/platforms/react-native/solutions/components/Image/files/index.ts +5 -0
  300. package/platforms/react-native/solutions/components/Image/solution.js +40 -0
  301. package/platforms/react-native/solutions/components/InputSecurity/README.md +29 -0
  302. package/platforms/react-native/solutions/components/InputSecurity/files/InputSecurity.ts +142 -0
  303. package/platforms/react-native/solutions/components/InputSecurity/solution.js +28 -0
  304. package/platforms/react-native/solutions/components/OTP/README.md +29 -0
  305. package/platforms/react-native/solutions/components/OTP/files/Item.tsx +16 -0
  306. package/platforms/react-native/solutions/components/OTP/files/Items.tsx +33 -0
  307. package/platforms/react-native/solutions/components/OTP/files/index.tsx +120 -0
  308. package/platforms/react-native/solutions/components/OTP/files/otp.pm.ts +30 -0
  309. package/platforms/react-native/solutions/components/OTP/solution.js +38 -0
  310. package/platforms/react-native/solutions/components/ProgressIndicator/README.md +29 -0
  311. package/platforms/react-native/solutions/components/ProgressIndicator/files/Circular.tsx +154 -0
  312. package/platforms/react-native/solutions/components/ProgressIndicator/files/Linear.tsx +133 -0
  313. package/platforms/react-native/solutions/components/ProgressIndicator/files/circular.pm.ts +34 -0
  314. package/platforms/react-native/solutions/components/ProgressIndicator/files/index.ts +16 -0
  315. package/platforms/react-native/solutions/components/ProgressIndicator/solution.js +39 -0
  316. package/platforms/react-native/solutions/components/Ruler/README.md +29 -0
  317. package/platforms/react-native/solutions/components/Ruler/files/Common.tsx +44 -0
  318. package/platforms/react-native/solutions/components/Ruler/files/Context.tsx +210 -0
  319. package/platforms/react-native/solutions/components/Ruler/files/Track.tsx +686 -0
  320. package/platforms/react-native/solutions/components/Ruler/files/Value.tsx +60 -0
  321. package/platforms/react-native/solutions/components/Ruler/files/index.ts +23 -0
  322. package/platforms/react-native/solutions/components/Ruler/files/ruler.constants.ts +70 -0
  323. package/platforms/react-native/solutions/components/Ruler/files/ruler.types.ts +98 -0
  324. package/platforms/react-native/solutions/components/Ruler/files/ruler.utils.ts +332 -0
  325. package/platforms/react-native/solutions/components/Ruler/solution.js +38 -0
  326. package/platforms/react-native/solutions/components/Section/README.md +29 -0
  327. package/platforms/react-native/solutions/components/Section/files/Common.tsx +144 -0
  328. package/platforms/react-native/solutions/components/Section/solution.js +37 -0
  329. package/platforms/react-native/solutions/components/Slider/README.md +29 -0
  330. package/platforms/react-native/solutions/components/Slider/files/Container.tsx +5 -0
  331. package/platforms/react-native/solutions/components/Slider/files/Content.tsx +44 -0
  332. package/platforms/react-native/solutions/components/Slider/files/Context.tsx +30 -0
  333. package/platforms/react-native/solutions/components/Slider/files/Pagination.Dot.tsx +61 -0
  334. package/platforms/react-native/solutions/components/Slider/files/index.ts +22 -0
  335. package/platforms/react-native/solutions/components/Slider/solution.js +38 -0
  336. package/platforms/react-native/solutions/components/Switch/README.md +29 -0
  337. package/platforms/react-native/solutions/components/Switch/files/Common.tsx +38 -0
  338. package/platforms/react-native/solutions/components/Switch/files/index.ts +9 -0
  339. package/platforms/react-native/solutions/components/Switch/files/switch.pm.ts +53 -0
  340. package/platforms/react-native/solutions/components/Switch/solution.js +38 -0
  341. package/platforms/react-native/solutions/install.js +97 -0
  342. package/platforms/react-native/solutions/services/firebase-core/README.md +31 -0
  343. package/platforms/react-native/solutions/services/firebase-core/files/index.ts +5 -0
  344. package/platforms/react-native/solutions/services/firebase-core/solution.js +39 -0
  345. package/platforms/react-native/solutions/services/firebase-messaging/README.md +31 -0
  346. package/platforms/react-native/solutions/services/firebase-messaging/files/index.ts +20 -0
  347. package/platforms/react-native/solutions/services/firebase-messaging/solution.js +42 -0
  348. package/platforms/react-native/solutions/utils/permissions/README.md +29 -0
  349. package/platforms/react-native/solutions/utils/permissions/files/permissions.ts +10 -0
  350. package/platforms/react-native/solutions/utils/permissions/solution.js +32 -0
  351. package/presets/react-native-fsd/index.js +25 -0
  352. package/shared/generators/entity/render.js +88 -0
  353. package/shared/generators/entity/templates/crud/api.ts.hbs +36 -0
  354. package/shared/generators/entity/templates/crud/dto.ts.hbs +36 -0
  355. package/shared/generators/entity/templates/crud/service.ts.hbs +73 -0
  356. package/shared/generators/entity/templates/crud/store.ts.hbs +27 -0
  357. package/shared/generators/entity/templates/index.ts.hbs +2 -0
  358. package/shared/generators/entity/templates/simple/api.ts.hbs +16 -0
  359. package/shared/generators/entity/templates/simple/dto.ts.hbs +5 -0
  360. package/shared/generators/entity/templates/simple/service.ts.hbs +26 -0
  361. package/shared/generators/entity/templates/simple/store.ts.hbs +18 -0
  362. package/shared/solutions/utils/date/README.md +29 -0
  363. package/shared/solutions/utils/date/files/date.ts +11 -0
  364. package/shared/solutions/utils/date/solution.js +27 -0
  365. package/shared/solutions/utils/string/README.md +29 -0
  366. package/shared/solutions/utils/string/files/string.ts +100 -0
  367. package/shared/solutions/utils/string/solution.js +27 -0
@@ -0,0 +1,60 @@
1
+ import { useMemo } from 'react';
2
+ import { StyleSheet, TextInput, type TextInputProps } from 'react-native';
3
+ import Animated, { useAnimatedProps } from 'react-native-reanimated';
4
+
5
+ import { useRuler } from './Context';
6
+ import type { IRulerValueProps } from './ruler.types';
7
+ import { formatRulerValue } from './ruler.utils';
8
+
9
+ const VALUE_FONT_SIZE = 32;
10
+
11
+ const AnimatedTextInput = Animated.createAnimatedComponent(TextInput, {
12
+ jsProps: ['text', 'defaultValue'],
13
+ });
14
+
15
+ function estimateValueWidth(charCount: number, fontSize: number): number {
16
+ return Math.ceil(charCount * fontSize * 0.62) + 4;
17
+ }
18
+
19
+ export default function RulerValue({ unit, unitStyle, valueStyle, children }: IRulerValueProps) {
20
+ const context = useRuler();
21
+
22
+ const valueWidth = useMemo(() => {
23
+ const longestValue = formatRulerValue(context.max, context.fractionDigits);
24
+ const charCount = longestValue.length + (unit ? unit.length + 1 : 0);
25
+
26
+ return estimateValueWidth(charCount, VALUE_FONT_SIZE);
27
+ }, [context.fractionDigits, context.max, unit]);
28
+
29
+ const animatedProps = useAnimatedProps(() => {
30
+ const text = unit ? `${context.formattedValue.value} ${unit}` : context.formattedValue.value;
31
+ // `text` is not a typed TextInput prop; it is the native prop ReText uses to update text without re-rendering children.
32
+ return { text, defaultValue: text } as unknown as Partial<TextInputProps>;
33
+ }, [unit, context.formattedValue]);
34
+
35
+ if (children) {
36
+ return <>{children(context)}</>;
37
+ }
38
+
39
+ return (
40
+ <AnimatedTextInput
41
+ editable={false}
42
+ pointerEvents="none"
43
+ underlineColorAndroid="transparent"
44
+ animatedProps={animatedProps}
45
+ style={[styles.value, { minWidth: valueWidth }, valueStyle, unitStyle]}
46
+ />
47
+ );
48
+ }
49
+
50
+ const styles = StyleSheet.create({
51
+ value: {
52
+ fontSize: VALUE_FONT_SIZE,
53
+ fontWeight: '600',
54
+ flexShrink: 0,
55
+ textAlign: 'center',
56
+ fontVariant: ['tabular-nums'],
57
+ color: '#111827',
58
+ padding: 0,
59
+ },
60
+ });
@@ -0,0 +1,23 @@
1
+ import Container from './Common';
2
+ import { useRuler } from './Context';
3
+ import Track from './Track';
4
+ import Value from './Value';
5
+
6
+ type TContainer = typeof Container;
7
+ type TValue = typeof Value;
8
+ type TTrack = typeof Track;
9
+ type TUseRuler = typeof useRuler;
10
+
11
+ interface IRuler extends TContainer {
12
+ Value: TValue;
13
+ Track: TTrack;
14
+ useRuler: TUseRuler;
15
+ }
16
+
17
+ const Ruler = Container as IRuler;
18
+ Ruler.Value = Value;
19
+ Ruler.Track = Track;
20
+ Ruler.useRuler = useRuler;
21
+
22
+ export default Ruler;
23
+ export { useRuler };
@@ -0,0 +1,70 @@
1
+ import type {
2
+ IRulerTrackVisualConfig,
3
+ TRulerCaptionAlign,
4
+ TRulerDecelerationRate,
5
+ TRulerTrackAlign,
6
+ } from './ruler.types';
7
+
8
+ export const DEFAULT_RULER_STEP = 1;
9
+ export const DEFAULT_FRACTION_DIGITS = 0;
10
+
11
+ export const DEFAULT_GAP_BETWEEN_STEPS = 10;
12
+ export const DEFAULT_STEP_WIDTH = 2;
13
+ export const DEFAULT_SHORT_STEP_HEIGHT = 20;
14
+ export const DEFAULT_LONG_STEP_HEIGHT = 40;
15
+ export const DEFAULT_MINOR_STEP_HEIGHT = 12;
16
+ export const DEFAULT_LONG_STEP_INTERVAL = 10;
17
+ export const DEFAULT_INDICATOR_SIZE = 80;
18
+
19
+ export const DEFAULT_INDICATOR_COLOR = '#6366F1';
20
+ export const DEFAULT_SHORT_STEP_COLOR = '#E5E7EB';
21
+ export const DEFAULT_LONG_STEP_COLOR = '#9CA3AF';
22
+ export const DEFAULT_MINOR_STEP_COLOR = '#F3F4F6';
23
+
24
+ export const DEFAULT_DECELERATION_RATE: TRulerDecelerationRate = 'normal';
25
+
26
+ export const RULER_SNAP_TIMING_CONFIG = {
27
+ duration: 120,
28
+ };
29
+
30
+ export const RULER_MIN_FLING_VELOCITY = 80;
31
+
32
+ export const RULER_OFFSET_ALIGN_EPSILON = 0.5;
33
+
34
+ export const RULER_CONTROLLED_TIMING_CONFIG = {
35
+ duration: 100,
36
+ };
37
+
38
+ export const DEFAULT_SHOW_CAPTIONS = true;
39
+ export const DEFAULT_CAPTION_INTERVALS = [1, 5, 10];
40
+ export const DEFAULT_CAPTION_COLOR = '#6B7280';
41
+ export const DEFAULT_CAPTION_FONT_SIZE = 12;
42
+ export const DEFAULT_CAPTION_PADDING = 6;
43
+
44
+ export const CAPTION_TIER_MID = 5;
45
+ export const CAPTION_TIER_HIGH = 10;
46
+
47
+ export const DEFAULT_TRACK_ALIGN: TRulerTrackAlign = 'center';
48
+ export const DEFAULT_CAPTION_ALIGN: TRulerCaptionAlign = 'end';
49
+
50
+ export const DEFAULT_TRACK_VISUAL: IRulerTrackVisualConfig = {
51
+ orientation: 'horizontal',
52
+ indicatorColor: DEFAULT_INDICATOR_COLOR,
53
+ shortStepColor: DEFAULT_SHORT_STEP_COLOR,
54
+ longStepColor: DEFAULT_LONG_STEP_COLOR,
55
+ gapBetweenSteps: DEFAULT_GAP_BETWEEN_STEPS,
56
+ shortStepHeight: DEFAULT_SHORT_STEP_HEIGHT,
57
+ longStepHeight: DEFAULT_LONG_STEP_HEIGHT,
58
+ stepWidth: DEFAULT_STEP_WIDTH,
59
+ longStepInterval: DEFAULT_LONG_STEP_INTERVAL,
60
+ indicatorSize: DEFAULT_INDICATOR_SIZE,
61
+ decelerationRate: DEFAULT_DECELERATION_RATE,
62
+ };
63
+
64
+ export function resolveDeceleration(rate: TRulerDecelerationRate): number {
65
+ if (typeof rate === 'number') {
66
+ return rate;
67
+ }
68
+
69
+ return rate === 'fast' ? 0.99 : 0.998;
70
+ }
@@ -0,0 +1,98 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { StyleProp, TextStyle, ViewStyle } from 'react-native';
3
+ import type { SharedValue } from 'react-native-reanimated';
4
+
5
+ export type TRulerOrientation = 'horizontal' | 'vertical';
6
+
7
+ export type TRulerDecelerationRate = 'normal' | 'fast' | number;
8
+
9
+ export type TRulerTrackAlign = 'start' | 'center' | 'end';
10
+
11
+ export type TRulerCaptionAlign = 'start' | 'end';
12
+
13
+ export type TRulerTickTier = 'long' | 'medium' | 'minor';
14
+
15
+ export interface IRulerMathConfig {
16
+ min: number;
17
+ max: number;
18
+ step: number;
19
+ stepSize: number;
20
+ stepCount: number;
21
+ }
22
+
23
+ export interface IRulerTrackVisualConfig {
24
+ orientation: TRulerOrientation;
25
+ indicatorColor: string;
26
+ shortStepColor: string;
27
+ longStepColor: string;
28
+ gapBetweenSteps: number;
29
+ shortStepHeight: number;
30
+ longStepHeight: number;
31
+ stepWidth: number;
32
+ longStepInterval: number;
33
+ indicatorSize: number;
34
+ decelerationRate: TRulerDecelerationRate;
35
+ }
36
+
37
+ export interface IRulerProps {
38
+ min: number;
39
+ max: number;
40
+ step?: number;
41
+ fractionDigits?: number;
42
+ value?: number;
43
+ defaultValue?: number;
44
+ onChange?: (value: number) => void;
45
+ onChangeEnd?: (value: number) => void;
46
+ children?: ReactNode;
47
+ }
48
+
49
+ export interface IRulerTrackProps {
50
+ orientation?: TRulerOrientation;
51
+ indicatorColor?: string;
52
+ shortStepColor?: string;
53
+ longStepColor?: string;
54
+ gapBetweenSteps?: number;
55
+ shortStepHeight?: number;
56
+ longStepHeight?: number;
57
+ stepWidth?: number;
58
+ /** Value interval between long ticks (e.g. `1` places long ticks at 1, 2, 3…). Defaults to the sole `captionIntervals` entry, otherwise `10`. */
59
+ longStepInterval?: number;
60
+ indicatorSize?: number;
61
+ decelerationRate?: TRulerDecelerationRate;
62
+ showCaptions?: boolean;
63
+ captionIntervals?: number[];
64
+ captionColor?: string;
65
+ captionFontSize?: number;
66
+ trackAlign?: TRulerTrackAlign;
67
+ captionAlign?: TRulerCaptionAlign;
68
+ /** Visual-only finer tick interval between selectable `step` positions. */
69
+ subStep?: number;
70
+ minorStepHeight?: number;
71
+ minorStepColor?: string;
72
+ style?: StyleProp<ViewStyle>;
73
+ }
74
+
75
+ export interface IRulerValueProps {
76
+ unit?: string;
77
+ unitStyle?: StyleProp<TextStyle>;
78
+ valueStyle?: StyleProp<TextStyle>;
79
+ children?: (ctx: IRulerContextValue) => ReactNode;
80
+ }
81
+
82
+ export interface IRulerContextValue {
83
+ value: SharedValue<number>;
84
+ formattedValue: SharedValue<string>;
85
+ offset: SharedValue<number>;
86
+ isDragging: SharedValue<boolean>;
87
+ min: number;
88
+ max: number;
89
+ step: number;
90
+ fractionDigits: number;
91
+ stepCount: number;
92
+ stepSize: SharedValue<number>;
93
+ maxOffset: SharedValue<number>;
94
+ trackVisual: IRulerTrackVisualConfig;
95
+ viewportWidth: SharedValue<number>;
96
+ viewportHeight: SharedValue<number>;
97
+ updateTrackVisual: (config: Partial<IRulerTrackVisualConfig>) => void;
98
+ }
@@ -0,0 +1,332 @@
1
+ import {
2
+ DEFAULT_CAPTION_INTERVALS,
3
+ DEFAULT_LONG_STEP_INTERVAL,
4
+ RULER_OFFSET_ALIGN_EPSILON,
5
+ } from './ruler.constants';
6
+ import type { IRulerMathConfig, TRulerCaptionAlign, TRulerTickTier, TRulerTrackAlign } from './ruler.types';
7
+
8
+ export function clamp(value: number, min: number, max: number): number {
9
+ 'worklet';
10
+
11
+ return Math.min(max, Math.max(min, value));
12
+ }
13
+
14
+ export function getStepCount(min: number, max: number, step: number): number {
15
+ return Math.round((max - min) / step);
16
+ }
17
+
18
+ export function getStepSize(stepWidth: number, gapBetweenSteps: number): number {
19
+ return stepWidth + gapBetweenSteps;
20
+ }
21
+
22
+ export function getMaxOffset(stepCount: number, stepSize: number): number {
23
+ return stepCount * stepSize;
24
+ }
25
+
26
+ export function valueToIndex(value: number, min: number, step: number): number {
27
+ 'worklet';
28
+
29
+ return Math.round((value - min) / step);
30
+ }
31
+
32
+ export function indexToValue(index: number, min: number, step: number, max: number): number {
33
+ 'worklet';
34
+
35
+ return clamp(min + index * step, min, max);
36
+ }
37
+
38
+ export function valueToOffset(value: number, config: IRulerMathConfig): number {
39
+ 'worklet';
40
+
41
+ const index = valueToIndex(value, config.min, config.step);
42
+ const clampedIndex = clamp(index, 0, config.stepCount);
43
+ return clampedIndex * config.stepSize;
44
+ }
45
+
46
+ export function offsetToIndex(offset: number, stepSize: number): number {
47
+ 'worklet';
48
+
49
+ return Math.round(offset / stepSize);
50
+ }
51
+
52
+ export function offsetToValue(offset: number, config: IRulerMathConfig): number {
53
+ 'worklet';
54
+
55
+ const index = offsetToIndex(offset, config.stepSize);
56
+ const clampedIndex = clamp(index, 0, config.stepCount);
57
+ return indexToValue(clampedIndex, config.min, config.step, config.max);
58
+ }
59
+
60
+ export function snapOffset(offset: number, config: IRulerMathConfig): number {
61
+ 'worklet';
62
+
63
+ const index = offsetToIndex(offset, config.stepSize);
64
+ const clampedIndex = clamp(index, 0, config.stepCount);
65
+ return clampedIndex * config.stepSize;
66
+ }
67
+
68
+ export function rescaleOffsetToStepSize(
69
+ offset: number,
70
+ fromStepSize: number,
71
+ toStepSize: number,
72
+ stepCount: number,
73
+ ): number {
74
+ 'worklet';
75
+
76
+ const index = clamp(offsetToIndex(offset, fromStepSize), 0, stepCount);
77
+ return index * toStepSize;
78
+ }
79
+
80
+ export function isOffsetAligned(offset: number, stepSize: number, epsilon?: number): boolean {
81
+ 'worklet';
82
+
83
+ if (stepSize <= 0) {
84
+ return true;
85
+ }
86
+
87
+ const _epsilon = epsilon || RULER_OFFSET_ALIGN_EPSILON;
88
+ const nearestIndex = Math.round(offset / stepSize);
89
+ return Math.abs(offset - nearestIndex * stepSize) < _epsilon;
90
+ }
91
+
92
+ /**
93
+ * Returns the largest interval (e.g. 10 > 5 > 1) that `delta` is a multiple of,
94
+ * or `null` when `delta` does not align with any of the provided intervals.
95
+ */
96
+ export function isValueOnInterval(delta: number, interval: number, epsilon = 1e-6): boolean {
97
+ 'worklet';
98
+
99
+ if (interval <= 0) {
100
+ return false;
101
+ }
102
+
103
+ const absDelta = Math.abs(delta);
104
+ const remainder = absDelta % interval;
105
+ const distanceToMultiple = Math.min(remainder, interval - remainder);
106
+
107
+ return distanceToMultiple < epsilon;
108
+ }
109
+
110
+ export function isLongStep(index: number, min: number, step: number, max: number, longStepInterval: number): boolean {
111
+ 'worklet';
112
+
113
+ const value = indexToValue(index, min, step, max);
114
+ return isValueOnInterval(value - min, longStepInterval);
115
+ }
116
+
117
+ export function getTickTier(
118
+ value: number,
119
+ min: number,
120
+ step: number,
121
+ longStepInterval: number,
122
+ subStep?: number,
123
+ ): TRulerTickTier | null {
124
+ 'worklet';
125
+
126
+ const delta = value - min;
127
+
128
+ if (isValueOnInterval(delta, longStepInterval)) {
129
+ return 'long';
130
+ }
131
+
132
+ if (isValueOnInterval(delta, step)) {
133
+ return 'medium';
134
+ }
135
+
136
+ if (subStep !== undefined && subStep > 0 && isValueOnInterval(delta, subStep)) {
137
+ return 'minor';
138
+ }
139
+
140
+ return null;
141
+ }
142
+
143
+ export function getSubStepsPerMainStep(step: number, subStep: number): number {
144
+ return Math.round(step / subStep);
145
+ }
146
+
147
+ export function validateSubStep(step: number, subStep: number): void {
148
+ if (subStep <= 0) {
149
+ throw new Error('Ruler: `subStep` must be greater than 0.');
150
+ }
151
+
152
+ if (subStep >= step) {
153
+ throw new Error('Ruler: `subStep` must be less than `step`.');
154
+ }
155
+
156
+ if (!isValueOnInterval(step, subStep)) {
157
+ throw new Error('Ruler: `step` must be an even multiple of `subStep`.');
158
+ }
159
+ }
160
+
161
+ export function deriveLongStepIntervalFromStep(step: number): number {
162
+ return step * 2;
163
+ }
164
+
165
+ export function resolveLongStepInterval(
166
+ longStepInterval: number | undefined,
167
+ captionIntervals: number[],
168
+ step?: number,
169
+ fallback = DEFAULT_LONG_STEP_INTERVAL,
170
+ ): number {
171
+ if (longStepInterval !== undefined) {
172
+ return longStepInterval;
173
+ }
174
+
175
+ if (captionIntervals.length === 1) {
176
+ const interval = captionIntervals[0];
177
+
178
+ if (step === undefined || interval >= step) {
179
+ return interval;
180
+ }
181
+
182
+ return deriveLongStepIntervalFromStep(step);
183
+ }
184
+
185
+ if (step !== undefined && step > Math.max(...captionIntervals)) {
186
+ return deriveLongStepIntervalFromStep(step);
187
+ }
188
+
189
+ return fallback;
190
+ }
191
+
192
+ export function getCaptionTier(delta: number, intervals: number[] = DEFAULT_CAPTION_INTERVALS): number | null {
193
+ 'worklet';
194
+
195
+ const epsilon = 1e-6;
196
+ const absDelta = Math.abs(delta);
197
+ const sortedDescending = [...intervals].filter(interval => interval > 0).sort((a, b) => b - a);
198
+
199
+ for (const interval of sortedDescending) {
200
+ if (isValueOnInterval(absDelta, interval, epsilon)) {
201
+ return interval;
202
+ }
203
+ }
204
+
205
+ return null;
206
+ }
207
+
208
+ /**
209
+ * Computes the static list of step indices (from `min`) that should render a caption,
210
+ * based on which value deltas align with one of `intervals`.
211
+ */
212
+ export function getCaptionIndices(
213
+ min: number,
214
+ max: number,
215
+ step: number,
216
+ intervals: number[] = DEFAULT_CAPTION_INTERVALS,
217
+ ): number[] {
218
+ const stepCount = getStepCount(min, max, step);
219
+ const indices: number[] = [];
220
+
221
+ for (let index = 0; index <= stepCount; index += 1) {
222
+ const value = indexToValue(index, min, step, max);
223
+ const delta = value - min;
224
+
225
+ if (getCaptionTier(delta, intervals) !== null) {
226
+ indices.push(index);
227
+ }
228
+ }
229
+
230
+ return indices;
231
+ }
232
+
233
+ export function formatRulerValue(value: number, fractionDigits: number): string {
234
+ 'worklet';
235
+
236
+ return value.toFixed(fractionDigits);
237
+ }
238
+
239
+ /**
240
+ * Ticks are positioned at `viewport / 2 + index * stepSize - offset`; this
241
+ * returns the index range whose positions fall inside the viewport (with one
242
+ * step of slack on both sides).
243
+ */
244
+ export function getVisibleTickRange(
245
+ offset: number,
246
+ viewport: number,
247
+ stepSize: number,
248
+ stepCount: number,
249
+ ): { start: number; end: number } {
250
+ 'worklet';
251
+
252
+ const halfViewport = viewport / 2;
253
+ const start = Math.floor((offset - halfViewport - stepSize) / stepSize);
254
+ const end = Math.ceil((offset + halfViewport + stepSize) / stepSize);
255
+ return {
256
+ start: clamp(start, 0, stepCount),
257
+ end: clamp(end, 0, stepCount),
258
+ };
259
+ }
260
+
261
+ /**
262
+ * Resolves the cross-axis origin (top for horizontal, left for vertical) of
263
+ * a piece of content (a tick, the indicator, ...) within the available
264
+ * cross-axis space, based on the requested alignment.
265
+ */
266
+ export function resolveCrossAxisOrigin(crossAxisSize: number, contentSize: number, align: TRulerTrackAlign): number {
267
+ 'worklet';
268
+
269
+ if (crossAxisSize <= 0 || contentSize <= 0) {
270
+ return 0;
271
+ }
272
+
273
+ if (align === 'start') {
274
+ return 0;
275
+ }
276
+
277
+ if (align === 'end') {
278
+ return Math.max(0, crossAxisSize - contentSize);
279
+ }
280
+
281
+ return Math.max(0, (crossAxisSize - contentSize) / 2);
282
+ }
283
+
284
+ export interface ITrackBandLayout {
285
+ tickBandOrigin: number;
286
+ captionBandOrigin: number;
287
+ }
288
+
289
+ /**
290
+ * Reserves non-overlapping cross-axis bands for the tick and caption groups.
291
+ *
292
+ * The ticks and captions are treated as a single block: `trackAlign` places
293
+ * that block within the cross-axis space, `captionAlign` decides on which
294
+ * side of the ticks the captions are rendered.
295
+ */
296
+ export function resolveTrackBandLayout(
297
+ crossAxisSize: number,
298
+ tickBandSize: number,
299
+ captionBandSize: number,
300
+ padding: number,
301
+ trackAlign: TRulerTrackAlign,
302
+ captionAlign: TRulerCaptionAlign,
303
+ showCaptions: boolean,
304
+ ): ITrackBandLayout {
305
+ 'worklet';
306
+
307
+ const hasCaptions = showCaptions && captionBandSize > 0;
308
+ const captionSpace = hasCaptions ? captionBandSize + padding : 0;
309
+ const blockOrigin = resolveCrossAxisOrigin(crossAxisSize, tickBandSize + captionSpace, trackAlign);
310
+
311
+ if (hasCaptions && captionAlign === 'start') {
312
+ return {
313
+ captionBandOrigin: blockOrigin,
314
+ tickBandOrigin: blockOrigin + captionSpace,
315
+ };
316
+ }
317
+
318
+ return {
319
+ tickBandOrigin: blockOrigin,
320
+ captionBandOrigin: blockOrigin + tickBandSize + padding,
321
+ };
322
+ }
323
+
324
+ export function validateRulerProps(min: number, max: number, step: number): void {
325
+ if (min >= max) {
326
+ throw new Error('Ruler: `min` must be less than `max`.');
327
+ }
328
+
329
+ if (step <= 0) {
330
+ throw new Error('Ruler: `step` must be greater than 0.');
331
+ }
332
+ }
@@ -0,0 +1,38 @@
1
+ export default {
2
+ "id": "component:Ruler",
3
+ "type": "component",
4
+ "platforms": [
5
+ "react-native"
6
+ ],
7
+ "title": "Ruler",
8
+ "description": "Ruler from the previous template kit. Treat the API as experimental until it is wired into a screen.",
9
+ "status": "experimental",
10
+ "since": "1.0.0",
11
+ "tags": [
12
+ "ui",
13
+ "kit"
14
+ ],
15
+ "requires": [],
16
+ "dependencies": [],
17
+ "files": [
18
+ {
19
+ "from": "files",
20
+ "to": "ui/components/Ruler"
21
+ }
22
+ ],
23
+ "register": [
24
+ {
25
+ "file": "ui/components/index.ts",
26
+ "marker": "components-import",
27
+ "code": "import Ruler from './Ruler';\n"
28
+ },
29
+ {
30
+ "file": "ui/components/index.ts",
31
+ "marker": "components-export",
32
+ "code": " Ruler,\n"
33
+ }
34
+ ],
35
+ "manual": [],
36
+ "api": "Default export from ui/components/Ruler.",
37
+ "example": "import Ruler from '@components/Ruler';"
38
+ };
@@ -0,0 +1,29 @@
1
+ # Section
2
+
3
+ Segmented section control.
4
+
5
+ ## API
6
+
7
+ Section with data, onChange, and variant.
8
+
9
+ ## Example
10
+
11
+ ```tsx
12
+ <Section data={tabs} onChange={setTab} />
13
+ ```
14
+
15
+ ## Dependencies
16
+
17
+ None beyond the setup baseline.
18
+
19
+ No other solutions are required.
20
+
21
+ ## Manual steps
22
+
23
+ None.
24
+
25
+ ## Added in
26
+
27
+ 1.0.0 (`stable`).
28
+
29
+ Install with `forge g add --id component:Section`.