@mediacubeco/expo-template-fsd 1.0.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 (143) hide show
  1. package/.claude/mcp.json +0 -0
  2. package/.claude/rules/abstract-skills-agents.mdc +25 -0
  3. package/.claude/rules/app-routing.mdc +47 -0
  4. package/.claude/rules/exports-at-end.mdc +55 -0
  5. package/.claude/rules/kebab-case-naming.mdc +29 -0
  6. package/.claude/rules/prettier-eslint-typescript.mdc +24 -0
  7. package/.claude/settings.json +0 -0
  8. package/.claude/skills/generate-api-model/SKILL.md +98 -0
  9. package/.claude/skills/generate-api-model-mock/SKILL.md +56 -0
  10. package/.env +1 -0
  11. package/.env.example +1 -0
  12. package/.husky/pre-commit +6 -0
  13. package/.secret/README.md +26 -0
  14. package/README.md +36 -0
  15. package/app.config.js +54 -0
  16. package/env.d.ts +7 -0
  17. package/eslint.config.js +14 -0
  18. package/i18next.d.ts +12 -0
  19. package/package.json +76 -0
  20. package/prettier.config.js +9 -0
  21. package/src/app/_app.tsx +18 -0
  22. package/src/app/_layout.tsx +20 -0
  23. package/src/app/_splash.tsx +22 -0
  24. package/src/entities/.gitkeep +0 -0
  25. package/src/features/.gitkeep +0 -0
  26. package/src/screens/.gitkeep +0 -0
  27. package/src/shared/assets/fonts/index.ts +7 -0
  28. package/src/shared/assets/icons/index.ts +3 -0
  29. package/src/shared/assets/icons/like.tsx +17 -0
  30. package/src/shared/assets/icons/type.ts +6 -0
  31. package/src/shared/assets/images/default.png +0 -0
  32. package/src/shared/assets/images/index.ts +11 -0
  33. package/src/shared/assets/images/logo-android-background.png +0 -0
  34. package/src/shared/assets/images/logo-android-foreground.png +0 -0
  35. package/src/shared/assets/images/logo-android-monochrome.png +0 -0
  36. package/src/shared/assets/images/logo-ios.png +0 -0
  37. package/src/shared/assets/images/logo-web.png +0 -0
  38. package/src/shared/assets/images/splash-dark.png +0 -0
  39. package/src/shared/assets/images/splash.png +0 -0
  40. package/src/shared/assets/index.ts +4 -0
  41. package/src/shared/assets/translations/en.ts +3 -0
  42. package/src/shared/assets/translations/index.ts +9 -0
  43. package/src/shared/assets/translations/ru.ts +3 -0
  44. package/src/shared/constants/environment.ts +13 -0
  45. package/src/shared/constants/index.ts +1 -0
  46. package/src/shared/hooks/index.ts +4 -0
  47. package/src/shared/hooks/use-animated.ts +194 -0
  48. package/src/shared/hooks/use-breakpoints.ts +25 -0
  49. package/src/shared/hooks/use-mixins.ts +36 -0
  50. package/src/shared/hooks/use-safe-area.ts +56 -0
  51. package/src/shared/lib/api/api.provider.tsx +47 -0
  52. package/src/shared/lib/api/api.ts +7 -0
  53. package/src/shared/lib/api/api.types.ts +9 -0
  54. package/src/shared/lib/api/constants/index.ts +6 -0
  55. package/src/shared/lib/api/entities/common.ts +28 -0
  56. package/src/shared/lib/api/entities/index.ts +1 -0
  57. package/src/shared/lib/api/hooks/common.ts +31 -0
  58. package/src/shared/lib/api/hooks/index.ts +0 -0
  59. package/src/shared/lib/api/index.ts +4 -0
  60. package/src/shared/lib/api/models/api-instance/api-instance.constants.ts +9 -0
  61. package/src/shared/lib/api/models/api-instance/api-instance.ts +118 -0
  62. package/src/shared/lib/api/models/api-instance/api-instance.types.ts +31 -0
  63. package/src/shared/lib/api/models/api-instance/api-instance.utils.ts +22 -0
  64. package/src/shared/lib/api/models/api-instance/index.ts +1 -0
  65. package/src/shared/lib/api/models/index.ts +1 -0
  66. package/src/shared/lib/api/repositories/auth/auth.ts +18 -0
  67. package/src/shared/lib/api/repositories/auth/auth.types.ts +22 -0
  68. package/src/shared/lib/api/repositories/auth/index.ts +1 -0
  69. package/src/shared/lib/api/repositories/index.ts +1 -0
  70. package/src/shared/lib/api/resources/common.ts +8 -0
  71. package/src/shared/lib/api/resources/index.ts +1 -0
  72. package/src/shared/lib/api/utils/index.ts +1 -0
  73. package/src/shared/lib/api/utils/storage.ts +9 -0
  74. package/src/shared/lib/index.ts +4 -0
  75. package/src/shared/lib/localization/components/index.ts +1 -0
  76. package/src/shared/lib/localization/components/localization-translate/index.ts +1 -0
  77. package/src/shared/lib/localization/components/localization-translate/localization-translate.tsx +5 -0
  78. package/src/shared/lib/localization/components/localization-translate/localization-translate.types.ts +0 -0
  79. package/src/shared/lib/localization/constants/index.ts +54 -0
  80. package/src/shared/lib/localization/hooks/index.ts +2 -0
  81. package/src/shared/lib/localization/hooks/use-localization-setup.ts +34 -0
  82. package/src/shared/lib/localization/hooks/use-localization-text.ts +9 -0
  83. package/src/shared/lib/localization/hooks/use-localization.ts +23 -0
  84. package/src/shared/lib/localization/index.ts +4 -0
  85. package/src/shared/lib/localization/localization.provider.tsx +30 -0
  86. package/src/shared/lib/localization/localization.types.ts +5 -0
  87. package/src/shared/lib/localization/utils/index.ts +1 -0
  88. package/src/shared/lib/localization/utils/storage.ts +11 -0
  89. package/src/shared/lib/navigation/components/index.ts +1 -0
  90. package/src/shared/lib/navigation/components/navigation-logger/index.ts +1 -0
  91. package/src/shared/lib/navigation/components/navigation-logger/navigation-logger.ts +17 -0
  92. package/src/shared/lib/navigation/components/navigation-logger/navigation-logger.types.ts +0 -0
  93. package/src/shared/lib/navigation/hooks/index.ts +3 -0
  94. package/src/shared/lib/navigation/hooks/use-navigation-options.ts +94 -0
  95. package/src/shared/lib/navigation/hooks/use-navigation-params.ts +9 -0
  96. package/src/shared/lib/navigation/hooks/use-navigation.ts +9 -0
  97. package/src/shared/lib/navigation/index.ts +7 -0
  98. package/src/shared/lib/navigation/navigation.provider.tsx +26 -0
  99. package/src/shared/lib/navigation/navigation.types.ts +5 -0
  100. package/src/shared/lib/theme/constants/borders.ts +8 -0
  101. package/src/shared/lib/theme/constants/colors.ts +57 -0
  102. package/src/shared/lib/theme/constants/delays.ts +8 -0
  103. package/src/shared/lib/theme/constants/durations.ts +8 -0
  104. package/src/shared/lib/theme/constants/fonts.ts +7 -0
  105. package/src/shared/lib/theme/constants/index.ts +54 -0
  106. package/src/shared/lib/theme/constants/shadows.ts +40 -0
  107. package/src/shared/lib/theme/constants/sizes.ts +32 -0
  108. package/src/shared/lib/theme/constants/transparencies.ts +10 -0
  109. package/src/shared/lib/theme/constants/weights.ts +13 -0
  110. package/src/shared/lib/theme/hooks/index.ts +2 -0
  111. package/src/shared/lib/theme/hooks/use-theme-mode.ts +9 -0
  112. package/src/shared/lib/theme/hooks/use-theme-setup.ts +49 -0
  113. package/src/shared/lib/theme/hooks/use-theme.ts +15 -0
  114. package/src/shared/lib/theme/index.ts +4 -0
  115. package/src/shared/lib/theme/theme.context.ts +6 -0
  116. package/src/shared/lib/theme/theme.provider.tsx +60 -0
  117. package/src/shared/lib/theme/theme.types.ts +15 -0
  118. package/src/shared/lib/theme/utils/index.ts +1 -0
  119. package/src/shared/lib/theme/utils/storage.ts +11 -0
  120. package/src/shared/ui/atoms/index.ts +1 -0
  121. package/src/shared/ui/index.ts +4 -0
  122. package/src/shared/ui/molecules/index.ts +2 -0
  123. package/src/shared/ui/molecules/keyboard-area/index.ts +2 -0
  124. package/src/shared/ui/molecules/keyboard-area/keyboard-area.styles.ts +20 -0
  125. package/src/shared/ui/molecules/keyboard-area/keyboard-area.tsx +34 -0
  126. package/src/shared/ui/molecules/keyboard-area/keyboard-area.types.ts +3 -0
  127. package/src/shared/ui/molecules/refresh-control/index.ts +2 -0
  128. package/src/shared/ui/molecules/refresh-control/refresh-control.tsx +32 -0
  129. package/src/shared/ui/molecules/refresh-control/refresh-control.types.ts +6 -0
  130. package/src/shared/ui/organisms/index.ts +1 -0
  131. package/src/shared/ui/templates/index.ts +1 -0
  132. package/src/shared/ui/templates/screen-container/index.ts +12 -0
  133. package/src/shared/ui/templates/screen-container/screen-container-list.tsx +23 -0
  134. package/src/shared/ui/templates/screen-container/screen-container-scroll.tsx +23 -0
  135. package/src/shared/ui/templates/screen-container/screen-container-section-list.tsx +24 -0
  136. package/src/shared/ui/templates/screen-container/screen-container.hooks.tsx +72 -0
  137. package/src/shared/ui/templates/screen-container/screen-container.styles.ts +45 -0
  138. package/src/shared/ui/templates/screen-container/screen-container.types.tsx +75 -0
  139. package/src/shared/utils/generators.ts +11 -0
  140. package/src/shared/utils/index.ts +1 -0
  141. package/src/widgets/.gitkeep +0 -0
  142. package/svg.d.ts +7 -0
  143. package/tsconfig.json +8 -0
@@ -0,0 +1,57 @@
1
+ const PALETTE = {
2
+ 'LIGHT/WHITE': '#FFFFFF',
3
+ 'LIGHT/BLACK': '#111416',
4
+ 'LIGHT/GRAY': '#D4D4D4',
5
+
6
+ 'LIGHT/NEUTRAL': '#57626F',
7
+ 'LIGHT/DISABLED': '#C3CAD1',
8
+ 'LIGHT/SURFACE': '#F5F8FD',
9
+ 'LIGHT/FAINT': '#EFF2F7',
10
+
11
+ 'LIGHT/PRIMARY': '#6115CD',
12
+ 'LIGHT/PRIMARY_ACTIVE': '#4E11A4',
13
+ 'LIGHT/PRIMARY_DISABLED': '#D5C9FF',
14
+
15
+ 'LIGHT/ACCENT': '#FF2B75',
16
+ 'LIGHT/ACCENT_ACTIVE': '#E62464',
17
+ 'LIGHT/ACCENT_DISABLED': '#FFBAD2',
18
+
19
+ 'TRANSPARENT': '#FFFFFF00',
20
+ }
21
+
22
+ const LIGHT_COLORS_COMMON = {
23
+ PRIMARY: PALETTE['LIGHT/PRIMARY'],
24
+ PRIMARY_ACTIVE: PALETTE['LIGHT/PRIMARY_ACTIVE'],
25
+ PRIMARY_DISABLED: PALETTE['LIGHT/PRIMARY_DISABLED'],
26
+
27
+ ACCENT: PALETTE['LIGHT/ACCENT'],
28
+ ACCENT_ACTIVE: PALETTE['LIGHT/ACCENT_ACTIVE'],
29
+ ACCENT_DISABLED: PALETTE['LIGHT/ACCENT_DISABLED'],
30
+
31
+ TRANSPARENT: PALETTE['TRANSPARENT'],
32
+ }
33
+
34
+ const LIGHT_COLORS = {
35
+ FILL: {
36
+ BASE: PALETTE['LIGHT/SURFACE'],
37
+ NEUTRAL: PALETTE['LIGHT/FAINT'],
38
+ CONTRAST: PALETTE['LIGHT/WHITE'],
39
+ DISABLED: PALETTE['LIGHT/GRAY'],
40
+ ...LIGHT_COLORS_COMMON,
41
+ },
42
+ STROKE: {
43
+ BASE: PALETTE['LIGHT/FAINT'],
44
+ ...LIGHT_COLORS_COMMON,
45
+ },
46
+ TYPOGRAPHY: {
47
+ BASE: PALETTE['LIGHT/BLACK'],
48
+ NEUTRAL: PALETTE['LIGHT/NEUTRAL'],
49
+ CONTRAST: PALETTE['LIGHT/WHITE'],
50
+ DISABLED: PALETTE['LIGHT/DISABLED'],
51
+ ...LIGHT_COLORS_COMMON,
52
+ },
53
+ }
54
+
55
+ const DARK_COLORS = LIGHT_COLORS
56
+
57
+ export { LIGHT_COLORS, DARK_COLORS }
@@ -0,0 +1,8 @@
1
+ const DELAYS = {
2
+ EMPTY: 0,
3
+ SHORT: 100,
4
+ BASE: 200,
5
+ LONG: 500,
6
+ }
7
+
8
+ export { DELAYS }
@@ -0,0 +1,8 @@
1
+ const DURATIONS = {
2
+ EMPTY: 0,
3
+ SHORT: 100,
4
+ BASE: 200,
5
+ LONG: 500,
6
+ }
7
+
8
+ export { DURATIONS }
@@ -0,0 +1,7 @@
1
+ const FONTS = {
2
+ BASE_MEDIUM: 'BASE_MEDIUM',
3
+ BASE_SEMIBOLD: 'BASE_SEMIBOLD',
4
+ BASE_BOLD: 'BASE_BOLD',
5
+ }
6
+
7
+ export { FONTS }
@@ -0,0 +1,54 @@
1
+ import { BORDERS } from './borders'
2
+ import { DARK_COLORS, LIGHT_COLORS } from './colors'
3
+ import { DELAYS } from './delays'
4
+ import { DURATIONS } from './durations'
5
+ import { FONTS } from './fonts'
6
+ import { SHADOWS } from './shadows'
7
+ import { SIZES } from './sizes'
8
+ import { TRANSPARENCIES } from './transparencies'
9
+ import { WEIGHTS } from './weights'
10
+
11
+ const common = {
12
+ BORDERS,
13
+ // COLORS,
14
+ DELAYS,
15
+ DURATIONS,
16
+ FONTS,
17
+ SHADOWS,
18
+ SIZES,
19
+ TRANSPARENCIES,
20
+ WEIGHTS,
21
+ }
22
+
23
+ const lightTheme = {
24
+ ...common,
25
+ COLORS: LIGHT_COLORS,
26
+ }
27
+
28
+ const darkTheme = {
29
+ ...common,
30
+ COLORS: DARK_COLORS,
31
+ }
32
+
33
+ enum ThemeMode {
34
+ Light = 'light',
35
+ Dark = 'dark',
36
+ System = 'system',
37
+ }
38
+
39
+ enum ThemeModeSystem {
40
+ Light = 'light',
41
+ Dark = 'dark',
42
+ }
43
+
44
+ enum ThemeModeStatusBar {
45
+ Dark = 'dark-content',
46
+ Light = 'light-content',
47
+ }
48
+
49
+ const themes = {
50
+ [ThemeModeSystem.Light]: lightTheme,
51
+ [ThemeModeSystem.Dark]: darkTheme,
52
+ }
53
+
54
+ export { ThemeMode, ThemeModeSystem, ThemeModeStatusBar, themes }
@@ -0,0 +1,40 @@
1
+ const SHADOWS = {
2
+ EMPTY: {
3
+ elevation: 0,
4
+ shadowOpacity: 0,
5
+ shadowRadius: 0,
6
+ shadowOffset: {
7
+ width: 0,
8
+ height: 0,
9
+ },
10
+ },
11
+ THIN: {
12
+ elevation: 2,
13
+ shadowOpacity: 0.2,
14
+ shadowRadius: 1.5,
15
+ shadowOffset: {
16
+ width: 0,
17
+ height: 1,
18
+ },
19
+ },
20
+ BASE: {
21
+ elevation: 12,
22
+ shadowOpacity: 0.4,
23
+ shadowRadius: 6,
24
+ shadowOffset: {
25
+ width: 0,
26
+ height: 6,
27
+ },
28
+ },
29
+ FAT: {
30
+ elevation: 24,
31
+ shadowRadius: 16,
32
+ shadowOpacity: 0.6,
33
+ shadowOffset: {
34
+ width: 0,
35
+ height: 12,
36
+ },
37
+ },
38
+ }
39
+
40
+ export { SHADOWS }
@@ -0,0 +1,32 @@
1
+ const SIZES = {
2
+ 'EMPTY': 0,
3
+ '2XS': 0.5,
4
+ 'XS': 1,
5
+ 'S': 2,
6
+ 'M': 4,
7
+ 'L': 8,
8
+ 'XL': 12,
9
+ '2XL': 16,
10
+ '3XL': 20,
11
+ '4XL': 24,
12
+ '5XL': 28,
13
+ '6XL': 32,
14
+ '7XL': 36,
15
+ '8XL': 40,
16
+ '9XL': 44,
17
+ '10XL': 48,
18
+ '11XL': 52,
19
+ '12XL': 56,
20
+ '13XL': 60,
21
+ '14XL': 64,
22
+ '15XL': 68,
23
+ '16XL': 72,
24
+ '17XL': 76,
25
+ '18XL': 80,
26
+ '19XL': 84,
27
+ '20XL': 88,
28
+ 'MAX': '100%' as const,
29
+ 'INFINITY': Number.MAX_SAFE_INTEGER,
30
+ }
31
+
32
+ export { SIZES }
@@ -0,0 +1,10 @@
1
+ const TRANSPARENCIES = {
2
+ VISIBLE: 1,
3
+ WEAK: 0.8,
4
+ HALF: 0.4,
5
+ STRONG: 0.2,
6
+ LIGHT: 0.1,
7
+ INVISIBLE: 0,
8
+ }
9
+
10
+ export { TRANSPARENCIES }
@@ -0,0 +1,13 @@
1
+ const WEIGHTS = {
2
+ // THIN: '100',
3
+ // EXTRA_LIGHT: '200',
4
+ // LIGHT: '300',
5
+ // REGULAR: '400',
6
+ MEDIUM: '500',
7
+ SEMIBOLD: '600',
8
+ BOLD: '700',
9
+ // EXTRA_BOLD: '800',
10
+ // BLACK: '900',
11
+ } as const
12
+
13
+ export { WEIGHTS }
@@ -0,0 +1,2 @@
1
+ export * from './use-theme-mode'
2
+ export * from './use-theme-setup'
@@ -0,0 +1,9 @@
1
+ import { useTheme } from './use-theme'
2
+
3
+ const useThemeMode = () => {
4
+ const { theme } = useTheme()
5
+
6
+ return theme
7
+ }
8
+
9
+ export { useThemeMode }
@@ -0,0 +1,49 @@
1
+ import { Log } from '@mediacubeco/base/helpers'
2
+ import { useCallback } from 'react'
3
+ import { ThemeMode, ThemeModeSystem } from '../constants'
4
+ import { useTheme } from './use-theme'
5
+
6
+ const useThemeSetup = () => {
7
+ const { themeMode, themeModeSystem, setThemeMode } = useTheme()
8
+
9
+ const isThemeModeSystem = themeMode === ThemeMode.System
10
+ const isThemeModeSystemLight = isThemeModeSystem && themeModeSystem === ThemeModeSystem.Light
11
+ const isThemeModeSystemDark = isThemeModeSystem && themeModeSystem === ThemeModeSystem.Dark
12
+
13
+ const isThemeModeLight = themeMode === ThemeMode.Light || isThemeModeSystemLight
14
+ const isThemeModeDark = themeMode === ThemeMode.Dark || isThemeModeSystemDark
15
+
16
+ const setThemeModeLight = useCallback(() => {
17
+ setThemeMode(ThemeMode.Light)
18
+
19
+ Log.formatted.info('light', 'theme mode')
20
+ }, [setThemeMode])
21
+
22
+ const setThemeModeDark = useCallback(() => {
23
+ setThemeMode(ThemeMode.Dark)
24
+
25
+ Log.formatted.info('dark', 'theme mode')
26
+ }, [setThemeMode])
27
+
28
+ const setThemeModeSystem = useCallback(() => {
29
+ setThemeMode(ThemeMode.System)
30
+
31
+ Log.formatted.info('system', 'theme mode')
32
+ }, [setThemeMode])
33
+
34
+ return {
35
+ themeMode,
36
+ themeModeSystem,
37
+ isThemeModeSystem,
38
+ isThemeModeSystemLight,
39
+ isThemeModeSystemDark,
40
+ isThemeModeLight,
41
+ isThemeModeDark,
42
+ setThemeMode,
43
+ setThemeModeLight,
44
+ setThemeModeDark,
45
+ setThemeModeSystem,
46
+ }
47
+ }
48
+
49
+ export { useThemeSetup }
@@ -0,0 +1,15 @@
1
+ import { ErrorHandler } from '@mediacubeco/base/helpers'
2
+ import { useContext } from 'react'
3
+ import { ThemeContext } from '../theme.context'
4
+
5
+ const useTheme = () => {
6
+ const context = useContext(ThemeContext)
7
+
8
+ if (!context) {
9
+ ErrorHandler.throw('useTheme can not be used outside ThemeProvider')
10
+ }
11
+
12
+ return context
13
+ }
14
+
15
+ export { useTheme }
@@ -0,0 +1,4 @@
1
+ export { ThemeMode, ThemeModeSystem } from './constants'
2
+ export { useThemeSetup, useThemeMode } from './hooks'
3
+ export { default as ThemeProvider } from './theme.provider'
4
+ export type { Theme } from './theme.types'
@@ -0,0 +1,6 @@
1
+ import { createContext } from 'react'
2
+ import { ThemeContextValue } from './theme.types'
3
+
4
+ const ThemeContext = createContext<null | ThemeContextValue>(null)
5
+
6
+ export { ThemeContext }
@@ -0,0 +1,60 @@
1
+ import { useEffect, useMemo, useRef, useState } from 'react'
2
+ import { StatusBar, useColorScheme } from 'react-native'
3
+ import { themeStorage } from './utils'
4
+ import { ThemeMode, ThemeModeStatusBar, ThemeModeSystem, themes } from './constants'
5
+ import { ThemeContext } from './theme.context'
6
+ import { ThemeProviderProps } from './theme.types'
7
+
8
+ const ThemeProvider = ({ children }: ThemeProviderProps) => {
9
+ const didDefine = useRef(false)
10
+ const [themeMode, setThemeMode] = useState(ThemeMode.System)
11
+ const themeModeSystem = (useColorScheme() as ThemeModeSystem) ?? ThemeModeSystem.Light
12
+
13
+ const currentThemeMode = {
14
+ [ThemeMode.Light]: ThemeModeSystem.Light,
15
+ [ThemeMode.Dark]: ThemeModeSystem.Dark,
16
+ [ThemeMode.System]: themeModeSystem,
17
+ }[themeMode]
18
+
19
+ const theme = useMemo(() => {
20
+ return themes[currentThemeMode]
21
+ }, [currentThemeMode])
22
+
23
+ useEffect(() => {
24
+ const defineThemeMode = async () => {
25
+ const storageThemeMode = await themeStorage.mode.get()
26
+
27
+ if (storageThemeMode) {
28
+ setThemeMode(storageThemeMode as ThemeMode)
29
+ }
30
+
31
+ didDefine.current = true
32
+ }
33
+
34
+ defineThemeMode()
35
+ }, [])
36
+
37
+ useEffect(() => {
38
+ const updateThemeMode = async () => {
39
+ if (didDefine.current) {
40
+ await themeStorage.mode.set(themeMode)
41
+ }
42
+ }
43
+
44
+ updateThemeMode()
45
+ }, [themeMode])
46
+
47
+ useEffect(() => {
48
+ StatusBar.setBarStyle(
49
+ currentThemeMode === ThemeModeSystem.Dark ? ThemeModeStatusBar.Light : ThemeModeStatusBar.Dark
50
+ )
51
+ }, [currentThemeMode])
52
+
53
+ return (
54
+ <ThemeContext.Provider value={{ theme, themeMode, themeModeSystem, setThemeMode }}>
55
+ {children}
56
+ </ThemeContext.Provider>
57
+ )
58
+ }
59
+
60
+ export default ThemeProvider
@@ -0,0 +1,15 @@
1
+ import { Dispatch, PropsWithChildren, SetStateAction } from 'react'
2
+ import { ThemeMode, ThemeModeSystem, themes } from './constants'
3
+
4
+ type Theme = (typeof themes)[ThemeModeSystem]
5
+
6
+ interface ThemeContextValue {
7
+ theme: Theme
8
+ themeMode: ThemeMode
9
+ themeModeSystem: ThemeModeSystem
10
+ setThemeMode: Dispatch<SetStateAction<ThemeMode>>
11
+ }
12
+
13
+ type ThemeProviderProps = PropsWithChildren
14
+
15
+ export type { Theme, ThemeContextValue, ThemeProviderProps }
@@ -0,0 +1 @@
1
+ export * from './storage'
@@ -0,0 +1,11 @@
1
+ import { Storage } from '@mediacubeco/base/services'
2
+ import * as SecureStore from 'expo-secure-store'
3
+ import { ThemeMode } from '../constants'
4
+
5
+ const themeStorage = new Storage({
6
+ get: SecureStore.getItemAsync,
7
+ set: SecureStore.setItemAsync,
8
+ delete: SecureStore.deleteItemAsync,
9
+ }).create<'mode', ThemeMode>('mode')
10
+
11
+ export { themeStorage }
@@ -0,0 +1 @@
1
+ export const atoms = {}
@@ -0,0 +1,4 @@
1
+ export * from './atoms'
2
+ export * from './molecules'
3
+ export * from './organisms'
4
+ export * from './templates'
@@ -0,0 +1,2 @@
1
+ export * from './keyboard-area'
2
+ export * from './refresh-control'
@@ -0,0 +1,2 @@
1
+ export { default as KeyboardArea } from './keyboard-area'
2
+ export type { KeyboardAreaProps } from './keyboard-area.types'
@@ -0,0 +1,20 @@
1
+ import { useAnimated, useAnimatedStyle, useSafeArea } from '../../../hooks'
2
+
3
+ const useKeyboardAreaStyles = () => {
4
+ const { BOTTOM } = useSafeArea()
5
+ const [safeAreaHeight] = useAnimated(BOTTOM)
6
+ const [keyboardHeight] = useAnimated<number>(0)
7
+
8
+ const keyboardAnimatedStyle = useAnimatedStyle(() => {
9
+ return {
10
+ height: keyboardHeight.value - safeAreaHeight.value,
11
+ }
12
+ })
13
+
14
+ return {
15
+ keyboardHeight,
16
+ keyboardAnimatedStyle,
17
+ }
18
+ }
19
+
20
+ export { useKeyboardAreaStyles }
@@ -0,0 +1,34 @@
1
+ import { View } from 'react-native'
2
+ import { useKeyboardHandler } from 'react-native-keyboard-controller'
3
+ import { animate } from '../../../hooks'
4
+ import { useKeyboardAreaStyles } from './keyboard-area.styles'
5
+ import { KeyboardAreaProps } from './keyboard-area.types'
6
+
7
+ const KeyboardAnimatedArea = animate(View)
8
+
9
+ const KeyboardArea = ({}: KeyboardAreaProps) => {
10
+ const { keyboardHeight, keyboardAnimatedStyle } = useKeyboardAreaStyles()
11
+
12
+ useKeyboardHandler(
13
+ {
14
+ onStart: () => {
15
+ 'worklet'
16
+ },
17
+ onMove: (event) => {
18
+ 'worklet'
19
+
20
+ keyboardHeight.set(event.height)
21
+ },
22
+ onEnd: (event) => {
23
+ 'worklet'
24
+
25
+ keyboardHeight.set(event.height)
26
+ },
27
+ },
28
+ []
29
+ )
30
+
31
+ return <KeyboardAnimatedArea style={keyboardAnimatedStyle} />
32
+ }
33
+
34
+ export default KeyboardArea
@@ -0,0 +1,3 @@
1
+ type KeyboardAreaProps = {}
2
+
3
+ export type { KeyboardAreaProps }
@@ -0,0 +1,2 @@
1
+ export { default as RefreshControl } from './refresh-control'
2
+ export type { RefreshControlProps } from './refresh-control.types'
@@ -0,0 +1,32 @@
1
+ import { runCallback } from '@mediacubeco/base/utils'
2
+ import { useCallback, useState } from 'react'
3
+ import { RefreshControl as NativeRefreshControl } from 'react-native'
4
+ import { useSafeArea } from '../../../hooks'
5
+ import { useThemeMode } from '../../../lib'
6
+ import { RefreshControlProps } from './refresh-control.types'
7
+
8
+ const RefreshControl = ({ withOffset = true, onRefresh, ...props }: RefreshControlProps) => {
9
+ const [isRefreshing, setIsRefreshing] = useState(false)
10
+ const { TOP } = useSafeArea()
11
+ const { COLORS } = useThemeMode()
12
+
13
+ const handleRefresh = useCallback(async () => {
14
+ setIsRefreshing(true)
15
+
16
+ await runCallback(onRefresh)
17
+
18
+ setIsRefreshing(false)
19
+ }, [onRefresh])
20
+
21
+ return (
22
+ <NativeRefreshControl
23
+ refreshing={isRefreshing}
24
+ onRefresh={handleRefresh}
25
+ progressViewOffset={withOffset ? TOP : 0}
26
+ tintColor={COLORS.TYPOGRAPHY.PRIMARY}
27
+ {...props}
28
+ />
29
+ )
30
+ }
31
+
32
+ export default RefreshControl
@@ -0,0 +1,6 @@
1
+ type RefreshControlProps = {
2
+ withOffset: boolean
3
+ onRefresh: () => any | Promise<any>
4
+ }
5
+
6
+ export type { RefreshControlProps }
@@ -0,0 +1 @@
1
+ export const organisms = {}
@@ -0,0 +1 @@
1
+ export * from './screen-container'
@@ -0,0 +1,12 @@
1
+ export { default as ScreenContainerScroll } from './screen-container-scroll'
2
+ export { default as ScreenContainerList } from './screen-container-list'
3
+ export { default as ScreenContainerSectionList } from './screen-container-section-list'
4
+ export type {
5
+ ScreenContainerListProps,
6
+ ScreenContainerScrollProps,
7
+ ScreenContainerSectionListProps,
8
+ ScreenContainerListRenderItemInfo,
9
+ ScreenContainerSectionListRenderItemInfo,
10
+ ScreenContainerSectionListRenderHeaderInfo,
11
+ ScreenContainerSectionListRenderFooterInfo,
12
+ } from './screen-container.types'
@@ -0,0 +1,23 @@
1
+ import { FlatList, View } from 'react-native'
2
+ import { useScreenContainerProps } from './screen-container.hooks'
3
+ import { ScreenContainerListProps } from './screen-container.types'
4
+
5
+ const ScreenContainerList = <Item,>(props: ScreenContainerListProps<Item>) => {
6
+ const { reference, header, footer, wrapperStyle, outerStyle, innerStyle, ...flatListProps } =
7
+ useScreenContainerProps<ScreenContainerListProps<Item>>(props)
8
+
9
+ return (
10
+ <View style={wrapperStyle}>
11
+ {header}
12
+ <FlatList
13
+ ref={reference}
14
+ style={outerStyle}
15
+ contentContainerStyle={innerStyle}
16
+ {...flatListProps}
17
+ />
18
+ {footer}
19
+ </View>
20
+ )
21
+ }
22
+
23
+ export default ScreenContainerList
@@ -0,0 +1,23 @@
1
+ import { ScrollView, View } from 'react-native'
2
+ import { useScreenContainerProps } from './screen-container.hooks'
3
+ import { ScreenContainerScrollProps } from './screen-container.types'
4
+
5
+ const ScreenContainerScroll = (props: ScreenContainerScrollProps) => {
6
+ const { reference, header, footer, wrapperStyle, outerStyle, innerStyle, ...scrollViewProps } =
7
+ useScreenContainerProps<ScreenContainerScrollProps>(props)
8
+
9
+ return (
10
+ <View style={wrapperStyle}>
11
+ {header}
12
+ <ScrollView
13
+ ref={reference}
14
+ style={outerStyle}
15
+ contentContainerStyle={innerStyle}
16
+ {...scrollViewProps}
17
+ />
18
+ {footer}
19
+ </View>
20
+ )
21
+ }
22
+
23
+ export default ScreenContainerScroll
@@ -0,0 +1,24 @@
1
+ import { SectionList, View } from 'react-native'
2
+ import { useScreenContainerProps } from './screen-container.hooks'
3
+ import { ScreenContainerSectionListProps } from './screen-container.types'
4
+
5
+ const ScreenContainerSectionList = <Item,>(props: ScreenContainerSectionListProps<Item>) => {
6
+ const { reference, header, footer, wrapperStyle, outerStyle, innerStyle, ...sectionListProps } =
7
+ useScreenContainerProps<ScreenContainerSectionListProps<Item>>(props)
8
+
9
+ return (
10
+ <View style={wrapperStyle}>
11
+ {header}
12
+ <SectionList
13
+ ref={reference}
14
+ style={outerStyle}
15
+ contentContainerStyle={innerStyle}
16
+ stickySectionHeadersEnabled={false}
17
+ {...sectionListProps}
18
+ />
19
+ {footer}
20
+ </View>
21
+ )
22
+ }
23
+
24
+ export default ScreenContainerSectionList