create-du-app 0.1.3 → 0.1.4
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.
- package/README.md +10 -7
- package/package.json +6 -5
- package/src/index.js +8 -8
- package/src/prompts.js +1 -1
- package/templates/mobile/expo/.env.example +5 -0
- package/templates/mobile/expo/.eslintrc.js +7 -0
- package/templates/mobile/expo/.prettierrc.js +7 -0
- package/templates/mobile/expo/.svgrrc.js +9 -0
- package/templates/mobile/expo/README.md +42 -7
- package/templates/mobile/expo/_gitignore +20 -0
- package/templates/mobile/expo/_package.json +62 -1
- package/templates/mobile/expo/app.json +18 -0
- package/templates/mobile/expo/babel.config.js +21 -0
- package/templates/mobile/expo/index.js +5 -0
- package/templates/mobile/expo/metro.config.js +31 -0
- package/templates/mobile/expo/src/app/App.tsx +24 -0
- package/templates/mobile/expo/src/app/app-provider.tsx +36 -0
- package/templates/mobile/expo/src/app/config/translation.ts +26 -0
- package/templates/mobile/expo/src/app/index.ts +1 -0
- package/templates/mobile/expo/src/app/navigation/app-route-type.ts +27 -0
- package/templates/mobile/expo/src/app/navigation/bottom-tabs.tsx +34 -0
- package/templates/mobile/expo/src/app/navigation/index.tsx +14 -0
- package/templates/mobile/expo/src/app/stores/auth.store.ts +33 -0
- package/templates/mobile/expo/src/app/stores/common.store.ts +19 -0
- package/templates/mobile/expo/src/app/stores/index.ts +3 -0
- package/templates/mobile/expo/src/app/stores/loading.store.ts +22 -0
- package/templates/mobile/expo/src/assets/Images/empty-list.png +0 -0
- package/templates/mobile/expo/src/assets/Images/index.ts +5 -0
- package/templates/mobile/expo/src/assets/Images/screen-bg-gradian.png +0 -0
- package/templates/mobile/expo/src/assets/i18n/en.json +12 -0
- package/templates/mobile/expo/src/assets/i18n/fr.json +12 -0
- package/templates/mobile/expo/src/assets/lotties/index.ts +3 -0
- package/templates/mobile/expo/src/assets/lotties/loading.json +1 -0
- package/templates/mobile/expo/src/assets/svgs/arrow-left.svg +3 -0
- package/templates/mobile/expo/src/assets/svgs/arrow-right.svg +3 -0
- package/templates/mobile/expo/src/assets/svgs/calendar.svg +12 -0
- package/templates/mobile/expo/src/assets/svgs/check.svg +3 -0
- package/templates/mobile/expo/src/assets/svgs/close.svg +3 -0
- package/templates/mobile/expo/src/assets/svgs/eye-hide.svg +3 -0
- package/templates/mobile/expo/src/assets/svgs/eye.svg +4 -0
- package/templates/mobile/expo/src/assets/svgs/index.ts +29 -0
- package/templates/mobile/expo/src/assets/svgs/minus.svg +3 -0
- package/templates/mobile/expo/src/assets/svgs/plus.svg +3 -0
- package/templates/mobile/expo/src/assets/svgs/search.svg +3 -0
- package/templates/mobile/expo/src/assets/svgs/toast-error.svg +5 -0
- package/templates/mobile/expo/src/assets/svgs/toast-success.svg +4 -0
- package/templates/mobile/expo/src/core/api/endpoints.ts +8 -0
- package/templates/mobile/expo/src/core/api/example.api.ts +53 -0
- package/templates/mobile/expo/src/core/api/index.ts +4 -0
- package/templates/mobile/expo/src/core/components/common/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/common/list-empty/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/common/list-empty/list-empty.tsx +30 -0
- package/templates/mobile/expo/src/core/components/common/list-empty/list-empty.type.ts +5 -0
- package/templates/mobile/expo/src/core/components/forms/hf-date-time.tsx +301 -0
- package/templates/mobile/expo/src/core/components/forms/hf-password-input.tsx +153 -0
- package/templates/mobile/expo/src/core/components/forms/hf-text-input.tsx +59 -0
- package/templates/mobile/expo/src/core/components/forms/hf-time-picker.tsx +117 -0
- package/templates/mobile/expo/src/core/components/forms/index.ts +4 -0
- package/templates/mobile/expo/src/core/components/index.ts +5 -0
- package/templates/mobile/expo/src/core/components/loading/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/loading/loading-app/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/loading/loading-app/loading-app.tsx +50 -0
- package/templates/mobile/expo/src/core/components/offline/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/offline/offline-banner.tsx +186 -0
- package/templates/mobile/expo/src/core/components/screen/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/screen/screen-container/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/screen/screen-container/screen-container.tsx +252 -0
- package/templates/mobile/expo/src/core/components/splash/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/splash/splash-overlay/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/splash/splash-overlay/splash-overlay.tsx +93 -0
- package/templates/mobile/expo/src/core/components/ui/animated-list-item/animated-list-item.tsx +48 -0
- package/templates/mobile/expo/src/core/components/ui/animated-list-item/animated-list-item.type.ts +10 -0
- package/templates/mobile/expo/src/core/components/ui/animated-list-item/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/app-image/app-image.tsx +104 -0
- package/templates/mobile/expo/src/core/components/ui/app-image/app-image.type.ts +19 -0
- package/templates/mobile/expo/src/core/components/ui/app-image/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/asset-placeholder/asset-placeholder.tsx +76 -0
- package/templates/mobile/expo/src/core/components/ui/asset-placeholder/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/ui/avatar-image/avatar-image.tsx +90 -0
- package/templates/mobile/expo/src/core/components/ui/avatar-image/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/ui/bottom-sheet/bottom-sheet.tsx +145 -0
- package/templates/mobile/expo/src/core/components/ui/bottom-sheet/bottom-sheet.type.ts +10 -0
- package/templates/mobile/expo/src/core/components/ui/bottom-sheet/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/button/button.style.ts +146 -0
- package/templates/mobile/expo/src/core/components/ui/button/button.tsx +97 -0
- package/templates/mobile/expo/src/core/components/ui/button/button.type.ts +47 -0
- package/templates/mobile/expo/src/core/components/ui/button/index.ts +4 -0
- package/templates/mobile/expo/src/core/components/ui/checkbox/checkbox.tsx +127 -0
- package/templates/mobile/expo/src/core/components/ui/checkbox/checkbox.type.ts +24 -0
- package/templates/mobile/expo/src/core/components/ui/checkbox/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/collapsible-section/collapsible-section.tsx +141 -0
- package/templates/mobile/expo/src/core/components/ui/collapsible-section/collapsible-section.type.ts +10 -0
- package/templates/mobile/expo/src/core/components/ui/collapsible-section/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/components.registry.json +313 -0
- package/templates/mobile/expo/src/core/components/ui/field/field-frame.tsx +62 -0
- package/templates/mobile/expo/src/core/components/ui/field/field.shared.ts +31 -0
- package/templates/mobile/expo/src/core/components/ui/header/header.tsx +196 -0
- package/templates/mobile/expo/src/core/components/ui/header/header.type.ts +30 -0
- package/templates/mobile/expo/src/core/components/ui/header/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/icon-button/icon-button.style.ts +23 -0
- package/templates/mobile/expo/src/core/components/ui/icon-button/icon-button.tsx +66 -0
- package/templates/mobile/expo/src/core/components/ui/icon-button/icon-button.type.ts +25 -0
- package/templates/mobile/expo/src/core/components/ui/icon-button/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/image-slider/image-slider.tsx +107 -0
- package/templates/mobile/expo/src/core/components/ui/image-slider/image-slider.type.ts +10 -0
- package/templates/mobile/expo/src/core/components/ui/image-slider/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/index.ts +25 -0
- package/templates/mobile/expo/src/core/components/ui/label/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/label/label.tsx +36 -0
- package/templates/mobile/expo/src/core/components/ui/label/label.type.ts +12 -0
- package/templates/mobile/expo/src/core/components/ui/modal/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/modal/modal.tsx +62 -0
- package/templates/mobile/expo/src/core/components/ui/modal/modal.type.ts +11 -0
- package/templates/mobile/expo/src/core/components/ui/otp-input/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/otp-input/otp-input.tsx +129 -0
- package/templates/mobile/expo/src/core/components/ui/otp-input/otp-input.type.ts +20 -0
- package/templates/mobile/expo/src/core/components/ui/page-dots/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/ui/page-dots/page-dots.tsx +60 -0
- package/templates/mobile/expo/src/core/components/ui/radio/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/radio/radio.tsx +121 -0
- package/templates/mobile/expo/src/core/components/ui/radio/radio.type.ts +20 -0
- package/templates/mobile/expo/src/core/components/ui/screen/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/ui/screen/screen-gradient.tsx +33 -0
- package/templates/mobile/expo/src/core/components/ui/search-box/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/search-box/search-box.tsx +162 -0
- package/templates/mobile/expo/src/core/components/ui/search-box/search-box.type.ts +26 -0
- package/templates/mobile/expo/src/core/components/ui/segmented-control/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/segmented-control/segmented-control.tsx +86 -0
- package/templates/mobile/expo/src/core/components/ui/segmented-control/segmented-control.type.ts +22 -0
- package/templates/mobile/expo/src/core/components/ui/skeleton/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/skeleton/skeleton.tsx +106 -0
- package/templates/mobile/expo/src/core/components/ui/skeleton/skeleton.type.ts +8 -0
- package/templates/mobile/expo/src/core/components/ui/success-state/index.ts +1 -0
- package/templates/mobile/expo/src/core/components/ui/success-state/success-state.tsx +68 -0
- package/templates/mobile/expo/src/core/components/ui/tabs/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/tabs/tabs.tsx +273 -0
- package/templates/mobile/expo/src/core/components/ui/tabs/tabs.type.ts +21 -0
- package/templates/mobile/expo/src/core/components/ui/tag-input/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/tag-input/tag-input.tsx +146 -0
- package/templates/mobile/expo/src/core/components/ui/tag-input/tag-input.type.ts +22 -0
- package/templates/mobile/expo/src/core/components/ui/text-area/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/text-area/text-area.tsx +90 -0
- package/templates/mobile/expo/src/core/components/ui/text-area/text-area.type.ts +20 -0
- package/templates/mobile/expo/src/core/components/ui/text-field/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/text-field/text-field.tsx +116 -0
- package/templates/mobile/expo/src/core/components/ui/text-field/text-field.type.ts +21 -0
- package/templates/mobile/expo/src/core/components/ui/toggle/index.ts +2 -0
- package/templates/mobile/expo/src/core/components/ui/toggle/toggle.tsx +110 -0
- package/templates/mobile/expo/src/core/components/ui/toggle/toggle.type.ts +19 -0
- package/templates/mobile/expo/src/core/constants/external-urls.constant.ts +5 -0
- package/templates/mobile/expo/src/core/constants/hard-data.constant.ts +0 -0
- package/templates/mobile/expo/src/core/constants/index.ts +2 -0
- package/templates/mobile/expo/src/core/constants/type.constant.ts +3 -0
- package/templates/mobile/expo/src/core/context/index.ts +1 -0
- package/templates/mobile/expo/src/core/context/shared-transition-context.tsx +35 -0
- package/templates/mobile/expo/src/core/hook/index.ts +8 -0
- package/templates/mobile/expo/src/core/hook/useActiveRouteName.ts +63 -0
- package/templates/mobile/expo/src/core/hook/useAppNavigation.tsx +7 -0
- package/templates/mobile/expo/src/core/hook/useBottomInset.tsx +26 -0
- package/templates/mobile/expo/src/core/hook/useDebounce.tsx +16 -0
- package/templates/mobile/expo/src/core/hook/useEndReached.tsx +46 -0
- package/templates/mobile/expo/src/core/hook/useManualRefetch.ts +56 -0
- package/templates/mobile/expo/src/core/hook/useNetworkStatus.ts +68 -0
- package/templates/mobile/expo/src/core/hook/useTimeout.tsx +30 -0
- package/templates/mobile/expo/src/core/index.ts +7 -0
- package/templates/mobile/expo/src/core/services/api.service.ts +230 -0
- package/templates/mobile/expo/src/core/services/device-id.service.ts +23 -0
- package/templates/mobile/expo/src/core/services/index.ts +3 -0
- package/templates/mobile/expo/src/core/services/session-end.bridge.ts +26 -0
- package/templates/mobile/expo/src/core/theme/dark.theme.ts +10 -0
- package/templates/mobile/expo/src/core/theme/index.ts +5 -0
- package/templates/mobile/expo/src/core/theme/light.theme.ts +44 -0
- package/templates/mobile/expo/src/core/theme/theme-context.tsx +82 -0
- package/templates/mobile/expo/src/core/theme/theme.types.ts +26 -0
- package/templates/mobile/expo/src/core/theme/use-themed-styles.ts +25 -0
- package/templates/mobile/expo/src/core/utils/color.util.tsx +198 -0
- package/templates/mobile/expo/src/core/utils/date.util.ts +97 -0
- package/templates/mobile/expo/src/core/utils/device-locale.util.ts +22 -0
- package/templates/mobile/expo/src/core/utils/emitter/index.ts +161 -0
- package/templates/mobile/expo/src/core/utils/emitter/type.ts +40 -0
- package/templates/mobile/expo/src/core/utils/enum.util.tsx +15 -0
- package/templates/mobile/expo/src/core/utils/font.util.tsx +42 -0
- package/templates/mobile/expo/src/core/utils/func.util.ts +48 -0
- package/templates/mobile/expo/src/core/utils/greeting.util.ts +20 -0
- package/templates/mobile/expo/src/core/utils/image-format.util.ts +117 -0
- package/templates/mobile/expo/src/core/utils/image-picker.util.ts +84 -0
- package/templates/mobile/expo/src/core/utils/index.ts +18 -0
- package/templates/mobile/expo/src/core/utils/linking.util.ts +16 -0
- package/templates/mobile/expo/src/core/utils/navigation.util.tsx +100 -0
- package/templates/mobile/expo/src/core/utils/number-format.ts +28 -0
- package/templates/mobile/expo/src/core/utils/query-client.util.ts +35 -0
- package/templates/mobile/expo/src/core/utils/query-persister.util.ts +36 -0
- package/templates/mobile/expo/src/core/utils/schema.util.tsx +2713 -0
- package/templates/mobile/expo/src/core/utils/size.util.tsx +74 -0
- package/templates/mobile/expo/src/core/utils/storage.util.tsx +53 -0
- package/templates/mobile/expo/src/core/utils/toast.util.tsx +151 -0
- package/templates/mobile/expo/src/core/utils/translator.util.tsx +23 -0
- package/templates/mobile/expo/src/core/utils/typography.util.tsx +69 -0
- package/templates/mobile/expo/src/core/utils/validate.util.tsx +13 -0
- package/templates/mobile/expo/src/declarations.d.ts +54 -0
- package/templates/mobile/expo/src/modules/home/home.screen.tsx +33 -0
- package/templates/mobile/expo/src/modules/profile/profile.screen.tsx +29 -0
- package/templates/mobile/expo/src/scripts/link-fonts.js +60 -0
- package/templates/mobile/expo/src/scripts/sync-images.js +56 -0
- package/templates/mobile/expo/src/scripts/sync-svgs.js +50 -0
- package/templates/mobile/expo/src/types/models.d.ts +24 -0
- package/templates/mobile/expo/tsconfig.json +19 -0
- package/templates/mobile/rn/.env.example +5 -0
- package/templates/mobile/rn/.eslintrc.js +7 -0
- package/templates/mobile/rn/.prettierrc.js +7 -0
- package/templates/mobile/rn/.svgrrc.js +9 -0
- package/templates/mobile/rn/README.md +40 -7
- package/templates/mobile/rn/_gitignore +24 -0
- package/templates/mobile/rn/_package.json +67 -1
- package/templates/mobile/rn/app.json +4 -0
- package/templates/mobile/rn/babel.config.js +18 -0
- package/templates/mobile/rn/index.js +8 -0
- package/templates/mobile/rn/metro.config.js +33 -0
- package/templates/mobile/rn/src/app/App.tsx +24 -0
- package/templates/mobile/rn/src/app/app-provider.tsx +36 -0
- package/templates/mobile/rn/src/app/config/translation.ts +26 -0
- package/templates/mobile/rn/src/app/index.ts +1 -0
- package/templates/mobile/rn/src/app/navigation/app-route-type.ts +27 -0
- package/templates/mobile/rn/src/app/navigation/bottom-tabs.tsx +34 -0
- package/templates/mobile/rn/src/app/navigation/index.tsx +14 -0
- package/templates/mobile/rn/src/app/stores/auth.store.ts +33 -0
- package/templates/mobile/rn/src/app/stores/common.store.ts +19 -0
- package/templates/mobile/rn/src/app/stores/index.ts +3 -0
- package/templates/mobile/rn/src/app/stores/loading.store.ts +22 -0
- package/templates/mobile/rn/src/assets/Images/empty-list.png +0 -0
- package/templates/mobile/rn/src/assets/Images/index.ts +5 -0
- package/templates/mobile/rn/src/assets/Images/screen-bg-gradian.png +0 -0
- package/templates/mobile/rn/src/assets/i18n/en.json +12 -0
- package/templates/mobile/rn/src/assets/i18n/fr.json +12 -0
- package/templates/mobile/rn/src/assets/lotties/index.ts +3 -0
- package/templates/mobile/rn/src/assets/lotties/loading.json +1 -0
- package/templates/mobile/rn/src/assets/svgs/arrow-left.svg +3 -0
- package/templates/mobile/rn/src/assets/svgs/arrow-right.svg +3 -0
- package/templates/mobile/rn/src/assets/svgs/calendar.svg +12 -0
- package/templates/mobile/rn/src/assets/svgs/check.svg +3 -0
- package/templates/mobile/rn/src/assets/svgs/close.svg +3 -0
- package/templates/mobile/rn/src/assets/svgs/eye-hide.svg +3 -0
- package/templates/mobile/rn/src/assets/svgs/eye.svg +4 -0
- package/templates/mobile/rn/src/assets/svgs/index.ts +29 -0
- package/templates/mobile/rn/src/assets/svgs/minus.svg +3 -0
- package/templates/mobile/rn/src/assets/svgs/plus.svg +3 -0
- package/templates/mobile/rn/src/assets/svgs/search.svg +3 -0
- package/templates/mobile/rn/src/assets/svgs/toast-error.svg +5 -0
- package/templates/mobile/rn/src/assets/svgs/toast-success.svg +4 -0
- package/templates/mobile/rn/src/core/api/endpoints.ts +8 -0
- package/templates/mobile/rn/src/core/api/example.api.ts +53 -0
- package/templates/mobile/rn/src/core/api/index.ts +4 -0
- package/templates/mobile/rn/src/core/components/common/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/common/list-empty/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/common/list-empty/list-empty.tsx +30 -0
- package/templates/mobile/rn/src/core/components/common/list-empty/list-empty.type.ts +5 -0
- package/templates/mobile/rn/src/core/components/forms/hf-date-time.tsx +301 -0
- package/templates/mobile/rn/src/core/components/forms/hf-password-input.tsx +153 -0
- package/templates/mobile/rn/src/core/components/forms/hf-text-input.tsx +59 -0
- package/templates/mobile/rn/src/core/components/forms/hf-time-picker.tsx +117 -0
- package/templates/mobile/rn/src/core/components/forms/index.ts +4 -0
- package/templates/mobile/rn/src/core/components/index.ts +5 -0
- package/templates/mobile/rn/src/core/components/loading/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/loading/loading-app/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/loading/loading-app/loading-app.tsx +50 -0
- package/templates/mobile/rn/src/core/components/offline/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/offline/offline-banner.tsx +186 -0
- package/templates/mobile/rn/src/core/components/screen/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/screen/screen-container/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/screen/screen-container/screen-container.tsx +252 -0
- package/templates/mobile/rn/src/core/components/splash/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/splash/splash-overlay/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/splash/splash-overlay/splash-overlay.tsx +93 -0
- package/templates/mobile/rn/src/core/components/ui/animated-list-item/animated-list-item.tsx +48 -0
- package/templates/mobile/rn/src/core/components/ui/animated-list-item/animated-list-item.type.ts +10 -0
- package/templates/mobile/rn/src/core/components/ui/animated-list-item/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/app-image/app-image.tsx +104 -0
- package/templates/mobile/rn/src/core/components/ui/app-image/app-image.type.ts +19 -0
- package/templates/mobile/rn/src/core/components/ui/app-image/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/asset-placeholder/asset-placeholder.tsx +76 -0
- package/templates/mobile/rn/src/core/components/ui/asset-placeholder/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/ui/avatar-image/avatar-image.tsx +90 -0
- package/templates/mobile/rn/src/core/components/ui/avatar-image/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/ui/bottom-sheet/bottom-sheet.tsx +145 -0
- package/templates/mobile/rn/src/core/components/ui/bottom-sheet/bottom-sheet.type.ts +10 -0
- package/templates/mobile/rn/src/core/components/ui/bottom-sheet/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/button/button.style.ts +146 -0
- package/templates/mobile/rn/src/core/components/ui/button/button.tsx +97 -0
- package/templates/mobile/rn/src/core/components/ui/button/button.type.ts +47 -0
- package/templates/mobile/rn/src/core/components/ui/button/index.ts +4 -0
- package/templates/mobile/rn/src/core/components/ui/checkbox/checkbox.tsx +127 -0
- package/templates/mobile/rn/src/core/components/ui/checkbox/checkbox.type.ts +24 -0
- package/templates/mobile/rn/src/core/components/ui/checkbox/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/collapsible-section/collapsible-section.tsx +141 -0
- package/templates/mobile/rn/src/core/components/ui/collapsible-section/collapsible-section.type.ts +10 -0
- package/templates/mobile/rn/src/core/components/ui/collapsible-section/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/components.registry.json +313 -0
- package/templates/mobile/rn/src/core/components/ui/field/field-frame.tsx +62 -0
- package/templates/mobile/rn/src/core/components/ui/field/field.shared.ts +31 -0
- package/templates/mobile/rn/src/core/components/ui/header/header.tsx +196 -0
- package/templates/mobile/rn/src/core/components/ui/header/header.type.ts +30 -0
- package/templates/mobile/rn/src/core/components/ui/header/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/icon-button/icon-button.style.ts +23 -0
- package/templates/mobile/rn/src/core/components/ui/icon-button/icon-button.tsx +66 -0
- package/templates/mobile/rn/src/core/components/ui/icon-button/icon-button.type.ts +25 -0
- package/templates/mobile/rn/src/core/components/ui/icon-button/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/image-slider/image-slider.tsx +107 -0
- package/templates/mobile/rn/src/core/components/ui/image-slider/image-slider.type.ts +10 -0
- package/templates/mobile/rn/src/core/components/ui/image-slider/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/index.ts +25 -0
- package/templates/mobile/rn/src/core/components/ui/label/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/label/label.tsx +36 -0
- package/templates/mobile/rn/src/core/components/ui/label/label.type.ts +12 -0
- package/templates/mobile/rn/src/core/components/ui/modal/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/modal/modal.tsx +62 -0
- package/templates/mobile/rn/src/core/components/ui/modal/modal.type.ts +11 -0
- package/templates/mobile/rn/src/core/components/ui/otp-input/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/otp-input/otp-input.tsx +129 -0
- package/templates/mobile/rn/src/core/components/ui/otp-input/otp-input.type.ts +20 -0
- package/templates/mobile/rn/src/core/components/ui/page-dots/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/ui/page-dots/page-dots.tsx +60 -0
- package/templates/mobile/rn/src/core/components/ui/radio/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/radio/radio.tsx +121 -0
- package/templates/mobile/rn/src/core/components/ui/radio/radio.type.ts +20 -0
- package/templates/mobile/rn/src/core/components/ui/screen/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/ui/screen/screen-gradient.tsx +33 -0
- package/templates/mobile/rn/src/core/components/ui/search-box/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/search-box/search-box.tsx +162 -0
- package/templates/mobile/rn/src/core/components/ui/search-box/search-box.type.ts +26 -0
- package/templates/mobile/rn/src/core/components/ui/segmented-control/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/segmented-control/segmented-control.tsx +86 -0
- package/templates/mobile/rn/src/core/components/ui/segmented-control/segmented-control.type.ts +22 -0
- package/templates/mobile/rn/src/core/components/ui/skeleton/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/skeleton/skeleton.tsx +106 -0
- package/templates/mobile/rn/src/core/components/ui/skeleton/skeleton.type.ts +8 -0
- package/templates/mobile/rn/src/core/components/ui/success-state/index.ts +1 -0
- package/templates/mobile/rn/src/core/components/ui/success-state/success-state.tsx +68 -0
- package/templates/mobile/rn/src/core/components/ui/tabs/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/tabs/tabs.tsx +273 -0
- package/templates/mobile/rn/src/core/components/ui/tabs/tabs.type.ts +21 -0
- package/templates/mobile/rn/src/core/components/ui/tag-input/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/tag-input/tag-input.tsx +146 -0
- package/templates/mobile/rn/src/core/components/ui/tag-input/tag-input.type.ts +22 -0
- package/templates/mobile/rn/src/core/components/ui/text-area/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/text-area/text-area.tsx +90 -0
- package/templates/mobile/rn/src/core/components/ui/text-area/text-area.type.ts +20 -0
- package/templates/mobile/rn/src/core/components/ui/text-field/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/text-field/text-field.tsx +116 -0
- package/templates/mobile/rn/src/core/components/ui/text-field/text-field.type.ts +21 -0
- package/templates/mobile/rn/src/core/components/ui/toggle/index.ts +2 -0
- package/templates/mobile/rn/src/core/components/ui/toggle/toggle.tsx +110 -0
- package/templates/mobile/rn/src/core/components/ui/toggle/toggle.type.ts +19 -0
- package/templates/mobile/rn/src/core/constants/external-urls.constant.ts +5 -0
- package/templates/mobile/rn/src/core/constants/hard-data.constant.ts +0 -0
- package/templates/mobile/rn/src/core/constants/index.ts +2 -0
- package/templates/mobile/rn/src/core/constants/type.constant.ts +3 -0
- package/templates/mobile/rn/src/core/context/index.ts +1 -0
- package/templates/mobile/rn/src/core/context/shared-transition-context.tsx +35 -0
- package/templates/mobile/rn/src/core/hook/index.ts +8 -0
- package/templates/mobile/rn/src/core/hook/useActiveRouteName.ts +63 -0
- package/templates/mobile/rn/src/core/hook/useAppNavigation.tsx +7 -0
- package/templates/mobile/rn/src/core/hook/useBottomInset.tsx +26 -0
- package/templates/mobile/rn/src/core/hook/useDebounce.tsx +16 -0
- package/templates/mobile/rn/src/core/hook/useEndReached.tsx +46 -0
- package/templates/mobile/rn/src/core/hook/useManualRefetch.ts +56 -0
- package/templates/mobile/rn/src/core/hook/useNetworkStatus.ts +68 -0
- package/templates/mobile/rn/src/core/hook/useTimeout.tsx +30 -0
- package/templates/mobile/rn/src/core/index.ts +7 -0
- package/templates/mobile/rn/src/core/services/api.service.ts +230 -0
- package/templates/mobile/rn/src/core/services/device-id.service.ts +23 -0
- package/templates/mobile/rn/src/core/services/index.ts +3 -0
- package/templates/mobile/rn/src/core/services/session-end.bridge.ts +26 -0
- package/templates/mobile/rn/src/core/theme/dark.theme.ts +10 -0
- package/templates/mobile/rn/src/core/theme/index.ts +5 -0
- package/templates/mobile/rn/src/core/theme/light.theme.ts +44 -0
- package/templates/mobile/rn/src/core/theme/theme-context.tsx +82 -0
- package/templates/mobile/rn/src/core/theme/theme.types.ts +26 -0
- package/templates/mobile/rn/src/core/theme/use-themed-styles.ts +25 -0
- package/templates/mobile/rn/src/core/utils/color.util.tsx +198 -0
- package/templates/mobile/rn/src/core/utils/date.util.ts +97 -0
- package/templates/mobile/rn/src/core/utils/device-locale.util.ts +22 -0
- package/templates/mobile/rn/src/core/utils/emitter/index.ts +161 -0
- package/templates/mobile/rn/src/core/utils/emitter/type.ts +40 -0
- package/templates/mobile/rn/src/core/utils/enum.util.tsx +15 -0
- package/templates/mobile/rn/src/core/utils/font.util.tsx +42 -0
- package/templates/mobile/rn/src/core/utils/func.util.ts +48 -0
- package/templates/mobile/rn/src/core/utils/greeting.util.ts +20 -0
- package/templates/mobile/rn/src/core/utils/image-format.util.ts +117 -0
- package/templates/mobile/rn/src/core/utils/image-picker.util.ts +84 -0
- package/templates/mobile/rn/src/core/utils/index.ts +18 -0
- package/templates/mobile/rn/src/core/utils/linking.util.ts +16 -0
- package/templates/mobile/rn/src/core/utils/navigation.util.tsx +100 -0
- package/templates/mobile/rn/src/core/utils/number-format.ts +28 -0
- package/templates/mobile/rn/src/core/utils/query-client.util.ts +35 -0
- package/templates/mobile/rn/src/core/utils/query-persister.util.ts +36 -0
- package/templates/mobile/rn/src/core/utils/schema.util.tsx +2713 -0
- package/templates/mobile/rn/src/core/utils/size.util.tsx +74 -0
- package/templates/mobile/rn/src/core/utils/storage.util.tsx +53 -0
- package/templates/mobile/rn/src/core/utils/toast.util.tsx +151 -0
- package/templates/mobile/rn/src/core/utils/translator.util.tsx +23 -0
- package/templates/mobile/rn/src/core/utils/typography.util.tsx +69 -0
- package/templates/mobile/rn/src/core/utils/validate.util.tsx +13 -0
- package/templates/mobile/rn/src/declarations.d.ts +54 -0
- package/templates/mobile/rn/src/modules/home/home.screen.tsx +33 -0
- package/templates/mobile/rn/src/modules/profile/profile.screen.tsx +29 -0
- package/templates/mobile/rn/src/scripts/link-fonts.js +60 -0
- package/templates/mobile/rn/src/scripts/sync-images.js +56 -0
- package/templates/mobile/rn/src/scripts/sync-svgs.js +50 -0
- package/templates/mobile/rn/src/types/models.d.ts +24 -0
- package/templates/mobile/rn/tsconfig.json +21 -0
- package/templates/shared/src/api-endpoints.ts +8 -0
- package/templates/shared/src/enums.ts +34 -0
- package/templates/shared/src/external-urls.ts +5 -0
- package/templates/shared/src/index.ts +6 -3
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// ScreenContainer.tsx — Design-System scaffold (Life-Master-Design).
|
|
2
|
+
//
|
|
3
|
+
// Rewritten from the legacy imoni light-theme container. The public prop API is
|
|
4
|
+
// kept backwards-compatible (legacy screens keep compiling) while the rendering
|
|
5
|
+
// now uses the themed DS background + the DS `Header`. New screens should use
|
|
6
|
+
// the DS props: `headerVariant`, `onBackPress`, `backLabel`, `headerLeft`,
|
|
7
|
+
// `headerRightNode`, `scroll`.
|
|
8
|
+
import { Font, fontSize, horizontalScale, isIOS, Spacing } from '@src/core/utils';
|
|
9
|
+
import { ThemeColors, useTheme, useThemedStyles } from '@src/core/theme';
|
|
10
|
+
import React, { PropsWithChildren, ReactNode } from 'react';
|
|
11
|
+
import {
|
|
12
|
+
Image,
|
|
13
|
+
ImageSourcePropType,
|
|
14
|
+
NativeScrollEvent,
|
|
15
|
+
NativeSyntheticEvent,
|
|
16
|
+
StatusBar,
|
|
17
|
+
StyleProp,
|
|
18
|
+
StyleSheet,
|
|
19
|
+
View,
|
|
20
|
+
ViewStyle,
|
|
21
|
+
} from 'react-native';
|
|
22
|
+
import { ScrollView } from 'react-native-gesture-handler';
|
|
23
|
+
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller';
|
|
24
|
+
import { Edge, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
25
|
+
import { ImgScreenBgGradian } from '@src/assets/Images';
|
|
26
|
+
import Header from '../../ui/header/header';
|
|
27
|
+
import { HeaderVariant } from '../../ui/header/header.type';
|
|
28
|
+
|
|
29
|
+
interface Props {
|
|
30
|
+
style?: StyleProp<ViewStyle>;
|
|
31
|
+
/** Apply the top safe-area inset (status bar / notch). @default true */
|
|
32
|
+
safeTop?: boolean;
|
|
33
|
+
/** Apply the bottom safe-area inset (home indicator). @default true */
|
|
34
|
+
safeBottom?: boolean;
|
|
35
|
+
/** @deprecated legacy background switch — ignored by the DS scaffold. */
|
|
36
|
+
bgType?: 'default' | 'full';
|
|
37
|
+
renderBottom?: () => React.ReactNode;
|
|
38
|
+
/**
|
|
39
|
+
* Full-screen background image. Defaults to the dark gradient in dark mode
|
|
40
|
+
* and to no image (flat themed background) in light mode.
|
|
41
|
+
*/
|
|
42
|
+
background?: ImageSourcePropType;
|
|
43
|
+
/** Keyboard-aware scroll for forms. @default true */
|
|
44
|
+
isForm?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Extra breathing space (px) kept between the focused input and the top of
|
|
47
|
+
* the keyboard while `isForm`. The scroll view animates the whole form up by
|
|
48
|
+
* this much past the keyboard. @default Spacing.spacing_2xl (32)
|
|
49
|
+
*/
|
|
50
|
+
bottomOffset?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Let the built-in `KeyboardAwareScrollView` auto-scroll the focused input
|
|
53
|
+
* into view. Set `false` when the screen drives its own keyboard animation
|
|
54
|
+
* (e.g. a translateY/height worklet) so the two don't fight. @default true
|
|
55
|
+
*/
|
|
56
|
+
keyboardAware?: boolean;
|
|
57
|
+
showHeader?: boolean;
|
|
58
|
+
/** @deprecated Use typeButtonBack instead */
|
|
59
|
+
buttonBackType?: 'default' | 'white' | 'blur';
|
|
60
|
+
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
61
|
+
onContentSizeChange?: (contentWidth: number, contentHeight: number) => void;
|
|
62
|
+
|
|
63
|
+
// --- DS props (additive) ---
|
|
64
|
+
/** DS Header layout. @default 'default' (or 'back' when only a back action is set) */
|
|
65
|
+
headerVariant?: HeaderVariant;
|
|
66
|
+
/** Header title (rendered by the `welcome` / `default` variants). */
|
|
67
|
+
title?: string;
|
|
68
|
+
/** Header subtitle under the title. */
|
|
69
|
+
subtitle?: string;
|
|
70
|
+
/** Back handler for the `back`/`step` header. */
|
|
71
|
+
onBackPress?: () => void;
|
|
72
|
+
/** Label for the `back` header variant. */
|
|
73
|
+
backLabel?: string;
|
|
74
|
+
/** Left slot node for the DS Header. */
|
|
75
|
+
headerLeft?: ReactNode;
|
|
76
|
+
/** Right slot node for the DS Header (e.g. avatar, skip). */
|
|
77
|
+
headerRightNode?: ReactNode;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const ScreenContainer = (props: PropsWithChildren<Props>) => {
|
|
81
|
+
const { colors, resolved } = useTheme();
|
|
82
|
+
const styles = useThemedStyles(makeStyles);
|
|
83
|
+
const {
|
|
84
|
+
children,
|
|
85
|
+
style = {},
|
|
86
|
+
safeTop = true,
|
|
87
|
+
safeBottom = true,
|
|
88
|
+
renderBottom = () => null,
|
|
89
|
+
// Dark mode keeps the gradient artwork; light mode falls back to the flat
|
|
90
|
+
// themed background until a light gradient asset is provided.
|
|
91
|
+
background = resolved === 'dark' ? ImgScreenBgGradian : undefined,
|
|
92
|
+
isForm = true,
|
|
93
|
+
bottomOffset = Spacing.spacing_2xl, // 32
|
|
94
|
+
keyboardAware = true,
|
|
95
|
+
showHeader = true,
|
|
96
|
+
onScroll,
|
|
97
|
+
onContentSizeChange,
|
|
98
|
+
headerVariant = 'default',
|
|
99
|
+
title,
|
|
100
|
+
subtitle,
|
|
101
|
+
onBackPress,
|
|
102
|
+
backLabel,
|
|
103
|
+
headerLeft,
|
|
104
|
+
headerRightNode,
|
|
105
|
+
} = props;
|
|
106
|
+
|
|
107
|
+
// SafeAreaView handles the TOP inset (status bar / notch) only. The bottom
|
|
108
|
+
// edge is applied manually below: on Android `insets.bottom` is ~0 on
|
|
109
|
+
// 3-button-nav devices, so SafeAreaView's `bottom` edge leaves no padding.
|
|
110
|
+
// We pad with `bottomInset` (floored on Android) instead — gated on
|
|
111
|
+
// `safeBottom` so screens that opt out keep zero bottom padding.
|
|
112
|
+
const resolvedEdges: Edge[] = [...(safeTop ? (['top'] as const) : [])];
|
|
113
|
+
|
|
114
|
+
const rawInsets = useSafeAreaInsets();
|
|
115
|
+
// Applied as paddingBottom on the inner wrapper below — i.e. exactly where
|
|
116
|
+
// SafeAreaView's `bottom` edge used to pad, so iOS layout is unchanged. iOS
|
|
117
|
+
// keeps the real home-indicator inset; Android floors to 16 so the padding
|
|
118
|
+
// never collapses on devices that report ~0 (3-button nav).
|
|
119
|
+
const bottomInset = safeBottom
|
|
120
|
+
? isIOS
|
|
121
|
+
? rawInsets.bottom
|
|
122
|
+
: Math.max(rawInsets.bottom, 16)
|
|
123
|
+
: 0;
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
const renderHeader = () => {
|
|
127
|
+
if (!showHeader) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
return (
|
|
131
|
+
<View style={styles.header}>
|
|
132
|
+
<Header
|
|
133
|
+
variant={headerVariant}
|
|
134
|
+
title={title}
|
|
135
|
+
subtitle={subtitle}
|
|
136
|
+
left={headerLeft}
|
|
137
|
+
right={headerRightNode}
|
|
138
|
+
onBackPress={onBackPress}
|
|
139
|
+
backLabel={backLabel}
|
|
140
|
+
/>
|
|
141
|
+
</View>
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// The `back`/`step` Header variants don't render the title; show it as a
|
|
146
|
+
// centered block at the top of the body (matches the Figma auth screens).
|
|
147
|
+
const body = (
|
|
148
|
+
<>
|
|
149
|
+
{children}
|
|
150
|
+
</>
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<View style={styles.container}>
|
|
155
|
+
<StatusBar
|
|
156
|
+
barStyle={resolved === 'dark' ? 'light-content' : 'dark-content'}
|
|
157
|
+
backgroundColor={colors.transparent}
|
|
158
|
+
translucent
|
|
159
|
+
/>
|
|
160
|
+
{background ? (
|
|
161
|
+
<Image source={background} style={styles.background} resizeMode="cover" />
|
|
162
|
+
) : null}
|
|
163
|
+
<SafeAreaView style={styles.safe} edges={resolvedEdges}>
|
|
164
|
+
<View style={[styles.safe, { paddingBottom: bottomInset }]}>
|
|
165
|
+
{renderHeader()}
|
|
166
|
+
|
|
167
|
+
{isForm ? (
|
|
168
|
+
<KeyboardAwareScrollView
|
|
169
|
+
ScrollViewComponent={ScrollView as any}
|
|
170
|
+
showsVerticalScrollIndicator={false}
|
|
171
|
+
onScroll={onScroll}
|
|
172
|
+
scrollEventThrottle={16}
|
|
173
|
+
onContentSizeChange={onContentSizeChange}
|
|
174
|
+
// Animate the whole form up past the keyboard (UI-thread,
|
|
175
|
+
// Reanimated) and keep `bottomOffset` of breathing room
|
|
176
|
+
// above the focused caret. `mode="layout"` makes the flex
|
|
177
|
+
// layout (topSpacer / marginTop:auto actions / gap) reflow
|
|
178
|
+
// around the keyboard space so inputs are never covered.
|
|
179
|
+
bottomOffset={bottomOffset}
|
|
180
|
+
mode="layout"
|
|
181
|
+
// When false, the screen drives its own keyboard animation
|
|
182
|
+
// (translateY/height worklet) and this view stops auto-scrolling.
|
|
183
|
+
enabled={keyboardAware}
|
|
184
|
+
keyboardDismissMode="interactive"
|
|
185
|
+
keyboardShouldPersistTaps="handled"
|
|
186
|
+
contentContainerStyle={[styles.content, style]}
|
|
187
|
+
>
|
|
188
|
+
{body}
|
|
189
|
+
</KeyboardAwareScrollView>
|
|
190
|
+
) : (
|
|
191
|
+
// Non-form screens (e.g. the auth screens) render a plain View.
|
|
192
|
+
<View style={[styles.content, styles.flex, style]}>{body}</View>
|
|
193
|
+
)}
|
|
194
|
+
|
|
195
|
+
<View style={styles.bottom}>{renderBottom()}</View>
|
|
196
|
+
</View>
|
|
197
|
+
</SafeAreaView>
|
|
198
|
+
</View>
|
|
199
|
+
);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
export default ScreenContainer;
|
|
203
|
+
|
|
204
|
+
const makeStyles = (c: ThemeColors) =>
|
|
205
|
+
StyleSheet.create({
|
|
206
|
+
container: {
|
|
207
|
+
flex: 1,
|
|
208
|
+
backgroundColor: c.bg_elevation_level_1_normal,
|
|
209
|
+
},
|
|
210
|
+
background: {
|
|
211
|
+
...StyleSheet.absoluteFill,
|
|
212
|
+
width: '100%',
|
|
213
|
+
height: '100%',
|
|
214
|
+
},
|
|
215
|
+
safe: {
|
|
216
|
+
flex: 1,
|
|
217
|
+
},
|
|
218
|
+
header: {
|
|
219
|
+
paddingHorizontal: horizontalScale(Spacing.spacing_base), // 16
|
|
220
|
+
paddingBottom: Spacing.spacing_sm,
|
|
221
|
+
},
|
|
222
|
+
content: {
|
|
223
|
+
paddingHorizontal: horizontalScale(Spacing.spacing_xl), // 24
|
|
224
|
+
paddingTop: Spacing.spacing_base,
|
|
225
|
+
flex: 1,
|
|
226
|
+
},
|
|
227
|
+
flex: {
|
|
228
|
+
flex: 1,
|
|
229
|
+
},
|
|
230
|
+
bottom: {
|
|
231
|
+
paddingHorizontal: horizontalScale(Spacing.spacing_xl), // 24
|
|
232
|
+
},
|
|
233
|
+
titleBlock: {
|
|
234
|
+
alignItems: 'center',
|
|
235
|
+
gap: Spacing.spacing_s_nudge, // 6
|
|
236
|
+
marginBottom: Spacing.spacing_2xl, // 32
|
|
237
|
+
},
|
|
238
|
+
title: {
|
|
239
|
+
fontFamily: Font.dmSansSemiBold,
|
|
240
|
+
fontSize: fontSize(28),
|
|
241
|
+
lineHeight: 36,
|
|
242
|
+
color: c.fg_neutral_normal,
|
|
243
|
+
textAlign: 'center',
|
|
244
|
+
},
|
|
245
|
+
subtitle: {
|
|
246
|
+
fontFamily: Font.dmSansRegular,
|
|
247
|
+
fontSize: fontSize(12),
|
|
248
|
+
lineHeight: 18,
|
|
249
|
+
color: c.fg_neutral_faded,
|
|
250
|
+
textAlign: 'center',
|
|
251
|
+
},
|
|
252
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './splash-overlay';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as SplashOverlay } from './splash-overlay';
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { ImgScreenBgGradian } from '@src/assets/Images';
|
|
2
|
+
import { verticalScale } from '@src/core';
|
|
3
|
+
import React, { useEffect } from 'react';
|
|
4
|
+
import { Image, Platform, StyleSheet } from 'react-native';
|
|
5
|
+
import Animated, {
|
|
6
|
+
useAnimatedStyle,
|
|
7
|
+
useSharedValue,
|
|
8
|
+
withTiming,
|
|
9
|
+
} from 'react-native-reanimated';
|
|
10
|
+
|
|
11
|
+
const LOGO = require('@src/assets/splash/logo-white.png');
|
|
12
|
+
|
|
13
|
+
const FADE_OUT_MS = 350;
|
|
14
|
+
|
|
15
|
+
interface SplashOverlayProps {
|
|
16
|
+
/**
|
|
17
|
+
* Flip to `true` once the app is ready (launch route resolved + native
|
|
18
|
+
* splash hidden). The overlay then fades out and unmounts itself.
|
|
19
|
+
*/
|
|
20
|
+
hidden: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Android-only fake splash.
|
|
25
|
+
*
|
|
26
|
+
* iOS renders a full-bleed gradient splash via the native storyboard
|
|
27
|
+
* (with-splash-screen-fix plugin). Android 12+ can only show a centred icon on
|
|
28
|
+
* a solid colour, so after the native splash hands off we cover the first
|
|
29
|
+
* frames with this React overlay — the shared `ImgScreenBgGradian` background
|
|
30
|
+
* + logo — then fade it out, giving Android a gradient launch look. No-op on
|
|
31
|
+
* iOS, which keeps its full-bleed native storyboard splash.
|
|
32
|
+
*/
|
|
33
|
+
const SplashOverlay = ({ hidden }: SplashOverlayProps) => {
|
|
34
|
+
const opacity = useSharedValue(1);
|
|
35
|
+
const gone = useSharedValue(false);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (hidden) {
|
|
39
|
+
opacity.value = withTiming(0, { duration: FADE_OUT_MS }, finished => {
|
|
40
|
+
if (finished) {
|
|
41
|
+
gone.value = true;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}, [hidden, opacity, gone]);
|
|
46
|
+
|
|
47
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
48
|
+
opacity: opacity.value,
|
|
49
|
+
// Drop out of the tree (and stop intercepting touches) once faded.
|
|
50
|
+
display: gone.value ? 'none' : 'flex',
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
if (Platform.OS !== 'android') {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Animated.View
|
|
59
|
+
style={[styles.container, animatedStyle]}
|
|
60
|
+
pointerEvents="none">
|
|
61
|
+
<Image
|
|
62
|
+
source={ImgScreenBgGradian}
|
|
63
|
+
style={styles.image}
|
|
64
|
+
/>
|
|
65
|
+
|
|
66
|
+
<Image source={LOGO} style={styles.logo} resizeMode="contain" />
|
|
67
|
+
</Animated.View>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const styles = StyleSheet.create({
|
|
72
|
+
container: {
|
|
73
|
+
position: 'absolute',
|
|
74
|
+
top: 0,
|
|
75
|
+
left: 0,
|
|
76
|
+
right: 0,
|
|
77
|
+
bottom: 0,
|
|
78
|
+
zIndex: 9999,
|
|
79
|
+
justifyContent: 'center',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
},
|
|
82
|
+
image: {
|
|
83
|
+
position: 'absolute',
|
|
84
|
+
height: '100%',
|
|
85
|
+
width: '100%'
|
|
86
|
+
},
|
|
87
|
+
logo: {
|
|
88
|
+
height: verticalScale(160),
|
|
89
|
+
width: verticalScale(110)
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export default SplashOverlay;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Pressable } from 'react-native';
|
|
3
|
+
import Animated, { FadeInRight, FadeOutRight, Layout } from 'react-native-reanimated';
|
|
4
|
+
import { AnimatedListItemProps } from './animated-list-item.type';
|
|
5
|
+
|
|
6
|
+
const ANIMATION_DELAY_STAGGER = 50;
|
|
7
|
+
const ANIMATION_DURATION = 200;
|
|
8
|
+
const ENTERING_BASE = FadeInRight.duration(ANIMATION_DURATION).springify();
|
|
9
|
+
const EXITING = FadeOutRight.duration(ANIMATION_DURATION);
|
|
10
|
+
const LAYOUT = Layout.springify();
|
|
11
|
+
const PressableAnimated = Animated.createAnimatedComponent(Pressable);
|
|
12
|
+
|
|
13
|
+
const AnimatedListItem: React.FC<AnimatedListItemProps> = ({
|
|
14
|
+
children,
|
|
15
|
+
index,
|
|
16
|
+
style,
|
|
17
|
+
delayStagger = ANIMATION_DELAY_STAGGER,
|
|
18
|
+
onPress,
|
|
19
|
+
}) => {
|
|
20
|
+
const entering = ENTERING_BASE.delay(index * delayStagger);
|
|
21
|
+
|
|
22
|
+
if (onPress) {
|
|
23
|
+
return (
|
|
24
|
+
<PressableAnimated
|
|
25
|
+
entering={entering}
|
|
26
|
+
exiting={EXITING}
|
|
27
|
+
layout={LAYOUT}
|
|
28
|
+
style={style}
|
|
29
|
+
onPress={onPress}
|
|
30
|
+
>
|
|
31
|
+
{children}
|
|
32
|
+
</PressableAnimated>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Animated.View
|
|
38
|
+
entering={entering}
|
|
39
|
+
exiting={EXITING}
|
|
40
|
+
layout={LAYOUT}
|
|
41
|
+
style={style}
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
</Animated.View>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default AnimatedListItem;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { ThemeColors, useThemedStyles } from '@src/core/theme';
|
|
2
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
Animated,
|
|
5
|
+
Image,
|
|
6
|
+
ImageStyle,
|
|
7
|
+
StyleProp,
|
|
8
|
+
StyleSheet,
|
|
9
|
+
View,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import FastImage, { ImageStyle as FastImageStyle } from 'react-native-fast-image';
|
|
12
|
+
import { AppImageProps } from './app-image.type';
|
|
13
|
+
|
|
14
|
+
const ImageSkeleton: React.FC<{ style?: StyleProp<ImageStyle> }> = ({ style }) => {
|
|
15
|
+
const styles = useThemedStyles(makeStyles);
|
|
16
|
+
const shimmer = useRef(new Animated.Value(0)).current;
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const loop = Animated.loop(
|
|
20
|
+
Animated.sequence([
|
|
21
|
+
Animated.timing(shimmer, { toValue: 1, duration: 900, useNativeDriver: true }),
|
|
22
|
+
Animated.timing(shimmer, { toValue: 0, duration: 900, useNativeDriver: true }),
|
|
23
|
+
]),
|
|
24
|
+
);
|
|
25
|
+
loop.start();
|
|
26
|
+
return () => loop.stop();
|
|
27
|
+
}, [shimmer]);
|
|
28
|
+
|
|
29
|
+
const opacity = shimmer.interpolate({ inputRange: [0, 1], outputRange: [0.4, 0.9] });
|
|
30
|
+
|
|
31
|
+
return <Animated.View style={[styles.skeleton, style, { opacity }]} />;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const AppImage: React.FC<AppImageProps> = ({ style, source, resizeMode, containerStyle, immutable, ...rest }) => {
|
|
35
|
+
const styles = useThemedStyles(makeStyles);
|
|
36
|
+
// Start true so the shimmer shows immediately on mount and stays up until the
|
|
37
|
+
// first load resolves; flipping it false on load-end/error reveals the image.
|
|
38
|
+
// For an immutable source the bitmap is already cached on remount, so starting
|
|
39
|
+
// false avoids a shimmer flash before onLoadEnd fires (LIFEMASTER-364).
|
|
40
|
+
const [loading, setLoading] = useState(!immutable);
|
|
41
|
+
|
|
42
|
+
// Handle empty or invalid source. Keep `style` so the slot preserves its
|
|
43
|
+
// dimensions (e.g. a hero/cover) instead of collapsing to 0px while the real
|
|
44
|
+
// source is still loading or missing.
|
|
45
|
+
if (!source || (typeof source === 'object' && 'uri' in source && !source.uri)) {
|
|
46
|
+
return <View style={style} />;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Local image or non-http/https uri
|
|
50
|
+
if (
|
|
51
|
+
typeof source === 'number' ||
|
|
52
|
+
!(source?.uri?.startsWith('http://') || source?.uri?.startsWith('https://'))
|
|
53
|
+
) {
|
|
54
|
+
return <Image style={style} source={source} resizeMode={resizeMode} {...rest} />;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Remote image with loading indicator
|
|
58
|
+
// `source` is narrowed to `ImageURISource` here: the `number` case returned above.
|
|
59
|
+
const uri = source.uri ?? '';
|
|
60
|
+
return (
|
|
61
|
+
<View style={[styles.container, containerStyle]}>
|
|
62
|
+
<FastImage
|
|
63
|
+
// Default (mutable) path remounts on URL change so a re-uploaded avatar
|
|
64
|
+
// reloads instead of FastImage keeping the old native view + cached
|
|
65
|
+
// bitmap; `cache: web` revalidates a stable URL (server fix is a unique
|
|
66
|
+
// filename per upload, LIFEMASTER-260). An `immutable` source has a
|
|
67
|
+
// content-addressed URL, so we skip the remount and cache it immutably —
|
|
68
|
+
// the bitmap is served instantly on remount with no reload/flash
|
|
69
|
+
// (LIFEMASTER-364).
|
|
70
|
+
key={immutable ? undefined : uri}
|
|
71
|
+
style={style as FastImageStyle}
|
|
72
|
+
source={{
|
|
73
|
+
uri: uri || '',
|
|
74
|
+
priority: FastImage.priority.normal,
|
|
75
|
+
cache: immutable
|
|
76
|
+
? FastImage.cacheControl.immutable
|
|
77
|
+
: FastImage.cacheControl.web,
|
|
78
|
+
}}
|
|
79
|
+
// For an immutable (already-cached) source, don't re-raise the shimmer on
|
|
80
|
+
// load-start: the bitmap is there instantly, so a flash to loading would
|
|
81
|
+
// be the very reload artifact we're removing (LIFEMASTER-364).
|
|
82
|
+
onLoadStart={() => !immutable && setLoading(true)}
|
|
83
|
+
onLoadEnd={() => setLoading(false)}
|
|
84
|
+
onError={() => setLoading(false)}
|
|
85
|
+
resizeMode={resizeMode}
|
|
86
|
+
/>
|
|
87
|
+
{loading && <ImageSkeleton style={style} />}
|
|
88
|
+
</View>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export default AppImage;
|
|
93
|
+
|
|
94
|
+
const makeStyles = (c: ThemeColors) =>
|
|
95
|
+
StyleSheet.create({
|
|
96
|
+
container: {
|
|
97
|
+
justifyContent: 'center',
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
},
|
|
100
|
+
skeleton: {
|
|
101
|
+
position: 'absolute',
|
|
102
|
+
backgroundColor: c.hE3E3E3,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ImagePropsBase, ImageStyle, ImageURISource, StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
import { ResizeMode } from 'react-native-fast-image';
|
|
3
|
+
|
|
4
|
+
export interface AppImageProps extends ImagePropsBase {
|
|
5
|
+
source: ImageURISource | number;
|
|
6
|
+
style?: StyleProp<ImageStyle>;
|
|
7
|
+
containerStyle?: StyleProp<ViewStyle>;
|
|
8
|
+
resizeMode?: ResizeMode;
|
|
9
|
+
/**
|
|
10
|
+
* Treat the remote image as immutable (stable URL → content never changes), so
|
|
11
|
+
* FastImage serves the cached bitmap instantly on every remount instead of
|
|
12
|
+
* revalidating over the network. Use for content-addressed images (e.g. player
|
|
13
|
+
* covers): it stops the artwork from flashing/reloading when the same image
|
|
14
|
+
* remounts — like expanding the mini-player to full screen on Android
|
|
15
|
+
* (LIFEMASTER-364). Leave off for images that can change behind a stable URL
|
|
16
|
+
* (e.g. a re-uploaded avatar), which need the default revalidating `web` cache.
|
|
17
|
+
*/
|
|
18
|
+
immutable?: boolean;
|
|
19
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Colors, Font, fontSize, Radius } from '@src/core/utils'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { DimensionValue, StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
4
|
+
|
|
5
|
+
interface AssetPlaceholderProps {
|
|
6
|
+
/** Asset name from the FE handoff asset checklist (e.g. 'onboarding-clarity'). */
|
|
7
|
+
name: string
|
|
8
|
+
/** Figma node id the asset comes from. */
|
|
9
|
+
figmaNodeId?: string
|
|
10
|
+
width?: DimensionValue
|
|
11
|
+
height?: DimensionValue
|
|
12
|
+
rounded?: boolean
|
|
13
|
+
style?: StyleProp<ViewStyle>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Placeholder for an image / illustration / icon that is NOT yet exported from
|
|
18
|
+
* Figma. Reserves the correct space and labels the missing asset so the layout
|
|
19
|
+
* stays intact until the real asset is imported.
|
|
20
|
+
*
|
|
21
|
+
* Replace every usage with the real asset listed in the FE handoff checklist.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <AssetPlaceholder name="onboarding-clarity" figmaNodeId="16:6784" width={240} height={240} rounded />
|
|
25
|
+
*/
|
|
26
|
+
const AssetPlaceholder = ({
|
|
27
|
+
name,
|
|
28
|
+
figmaNodeId,
|
|
29
|
+
width = '100%',
|
|
30
|
+
height = 160,
|
|
31
|
+
rounded = false,
|
|
32
|
+
style,
|
|
33
|
+
}: AssetPlaceholderProps) => {
|
|
34
|
+
return (
|
|
35
|
+
<View
|
|
36
|
+
style={[
|
|
37
|
+
styles.box,
|
|
38
|
+
{ width, height },
|
|
39
|
+
rounded && styles.rounded,
|
|
40
|
+
style,
|
|
41
|
+
]}
|
|
42
|
+
accessibilityRole="image"
|
|
43
|
+
accessibilityLabel={`asset:${name}`}
|
|
44
|
+
>
|
|
45
|
+
<Text style={styles.label}>{name}</Text>
|
|
46
|
+
{figmaNodeId ? <Text style={styles.node}>{figmaNodeId}</Text> : null}
|
|
47
|
+
</View>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default AssetPlaceholder
|
|
52
|
+
|
|
53
|
+
const styles = StyleSheet.create({
|
|
54
|
+
box: {
|
|
55
|
+
alignItems: 'center',
|
|
56
|
+
justifyContent: 'center',
|
|
57
|
+
borderWidth: 1,
|
|
58
|
+
borderStyle: 'dashed',
|
|
59
|
+
borderColor: Colors.bd_neutral_faded,
|
|
60
|
+
backgroundColor: Colors.bg_input,
|
|
61
|
+
borderRadius: Radius.radius_lg,
|
|
62
|
+
},
|
|
63
|
+
rounded: {
|
|
64
|
+
borderRadius: Radius.radius_full,
|
|
65
|
+
},
|
|
66
|
+
label: {
|
|
67
|
+
fontFamily: Font.dmSansMedium,
|
|
68
|
+
fontSize: fontSize(12),
|
|
69
|
+
color: Colors.fg_neutral_faded,
|
|
70
|
+
},
|
|
71
|
+
node: {
|
|
72
|
+
fontFamily: Font.dmSansRegular,
|
|
73
|
+
fontSize: fontSize(10),
|
|
74
|
+
color: Colors.fg_neutral_faded,
|
|
75
|
+
},
|
|
76
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as AssetPlaceholder } from './asset-placeholder'
|