这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module.exports = {
parser: "@typescript-eslint/parser",
extends: ["prettier", "plugin:@typescript-eslint/recommended", "standard"],
plugins: ["@typescript-eslint"],
globals: {
__DEV__: false,
jasmine: false,
beforeAll: false,
afterAll: false,
beforeEach: false,
afterEach: false,
test: false,
expect: false,
describe: false,
jest: false,
it: false,
},
rules: {
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-member-accessibility": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/indent": 0,
"@typescript-eslint/member-delimiter-style": 0,
"@typescript-eslint/no-empty-interface": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-object-literal-type-assertion": 0,
"@typescript-eslint/no-var-requires": 0,
"@typescript-eslint/no-use-before-define": 0,
"comma-dangle": 0,
"multiline-ternary": 0,
"no-undef": 0,
"no-unused-vars": 0,
"no-use-before-define": "off",
"quotes": 0,
"space-before-function-paren": 0,
},
ignorePatterns: ["**/*.snap", "**/*.txt", "bin/ignite"],
}
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"printWidth": 100,
"semi": false,
"singleQuote": false,
"trailingComma": "all",
"quoteProps": "consistent"
}
20 changes: 18 additions & 2 deletions boilerplate/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ module.exports = {
{
name: "react-native",
importNames: ["Text", "Button", "TextInput"],
message: "Use the custom wrapper component from 'app/src/components'.",
}
message: "Use the custom wrapper component from '@/components'.",
},
],
},
],
Expand All @@ -63,5 +63,21 @@ module.exports = {
"no-global-assign": 0,
"quotes": 0,
"space-before-function-paren": 0,
// eslint-import
"import/order": [
"error",
{
"newlines-between": "always",
"groups": ["builtin", "external", "parent", "sibling", "index"],
"pathGroups": [
{
pattern: "@/**",
group: "external",
position: "after",
},
],
},
],
"import/newline-after-import": 1,
},
}
2 changes: 1 addition & 1 deletion boilerplate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import { Image } from 'react-native';

const MyComponent = () => {
return (
<Image source={require('../assets/images/my_image.png')} />
<Image source={require('assets/images/my_image.png')} />
);
};
```
Expand Down
7 changes: 4 additions & 3 deletions boilerplate/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ if (__DEV__) {
require("./devtools/ReactotronConfig.ts")
}
import "./utils/gestureHandler"
import { initI18n } from "./i18n"
import { useFonts } from "expo-font"
import { useEffect, useState } from "react"
import { initialWindowMetrics, SafeAreaProvider } from "react-native-safe-area-context"
import { useFonts } from "expo-font"
import * as Linking from "expo-linking"
import * as SplashScreen from "expo-splash-screen"
import { KeyboardProvider } from "react-native-keyboard-controller"

import { useInitialRootStore } from "./models" // @mst remove-current-line
import { AppNavigator, useNavigationPersistence } from "./navigators"
import * as storage from "./utils/storage"
import { customFontsToLoad } from "./theme"
import { KeyboardProvider } from "react-native-keyboard-controller"
import { initI18n } from "./i18n"
import { loadDateFnsLocale } from "./utils/formatDate"

export const NAVIGATION_PERSISTENCE_KEY = "NAVIGATION_STATE"
Expand Down
6 changes: 4 additions & 2 deletions boilerplate/app/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import {
TextStyle,
ViewStyle,
} from "react-native"

import type { ThemedStyle, ThemedStyleArray } from "@/theme"
import { $styles } from "../theme"
import { Text, TextProps } from "./Text"
import { $styles } from "@/theme"
import { useAppTheme } from "@/utils/useAppTheme"

import { Text, TextProps } from "./Text"

type Presets = "default" | "filled" | "reversed"

export interface ButtonAccessoryProps {
Expand Down
6 changes: 4 additions & 2 deletions boilerplate/app/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import {
ViewProps,
ViewStyle,
} from "react-native"

import type { ThemedStyle, ThemedStyleArray } from "@/theme"
import { $styles } from "../theme"
import { Text, TextProps } from "./Text"
import { $styles } from "@/theme"
import { useAppTheme } from "@/utils/useAppTheme"

import { Text, TextProps } from "./Text"

type Presets = "default" | "reversed"

interface CardProps extends TouchableOpacityProps {
Expand Down
7 changes: 4 additions & 3 deletions boilerplate/app/components/EmptyState.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Image, ImageProps, ImageStyle, StyleProp, TextStyle, View, ViewStyle } from "react-native"

import { Button, ButtonProps } from "./Button"
import { Text, TextProps } from "./Text"
import { useAppTheme } from "@/utils/useAppTheme"
import type { ThemedStyle } from "@/theme"
import { translate } from "@/i18n/translate"

const sadFace = require("../../assets/images/sad-face.png")
import { Text, TextProps } from "./Text"
import { Button, ButtonProps } from "./Button"

const sadFace = require("@assets/images/sad-face.png")

interface EmptyStateProps {
/**
Expand Down
10 changes: 6 additions & 4 deletions boilerplate/app/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import {
View,
ViewStyle,
} from "react-native"

import { isRTL, translate } from "@/i18n"
import { $styles } from "../theme"
import { ExtendedEdge, useSafeAreaInsetsStyle } from "../utils/useSafeAreaInsetsStyle"
import { IconTypes, PressableIcon } from "./Icon"
import { Text, TextProps } from "./Text"
import { $styles } from "@/theme"
import { ExtendedEdge, useSafeAreaInsetsStyle } from "@/utils/useSafeAreaInsetsStyle"
import { useAppTheme } from "@/utils/useAppTheme"
import type { ThemedStyle } from "@/theme"

import { IconTypes, PressableIcon } from "./Icon"
import { Text, TextProps } from "./Text"

export interface HeaderProps {
/**
* The layout of the title relative to the action components.
Expand Down
45 changes: 23 additions & 22 deletions boilerplate/app/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ViewProps,
ViewStyle,
} from "react-native"

import { useAppTheme } from "@/utils/useAppTheme"

export type IconTypes = keyof typeof iconRegistry
Expand Down Expand Up @@ -109,28 +110,28 @@ export function Icon(props: IconProps) {
}

export const iconRegistry = {
back: require("../../assets/icons/back.png"),
bell: require("../../assets/icons/bell.png"),
caretLeft: require("../../assets/icons/caretLeft.png"),
caretRight: require("../../assets/icons/caretRight.png"),
check: require("../../assets/icons/check.png"),
clap: require("../../assets/icons/demo/clap.png"), // @demo remove-current-line
community: require("../../assets/icons/demo/community.png"), // @demo remove-current-line
components: require("../../assets/icons/demo/components.png"), // @demo remove-current-line
debug: require("../../assets/icons/demo/debug.png"), // @demo remove-current-line
github: require("../../assets/icons/demo/github.png"), // @demo remove-current-line
heart: require("../../assets/icons/demo/heart.png"), // @demo remove-current-line
hidden: require("../../assets/icons/hidden.png"),
ladybug: require("../../assets/icons/ladybug.png"),
lock: require("../../assets/icons/lock.png"),
menu: require("../../assets/icons/menu.png"),
more: require("../../assets/icons/more.png"),
pin: require("../../assets/icons/demo/pin.png"), // @demo remove-current-line
podcast: require("../../assets/icons/demo/podcast.png"), // @demo remove-current-line
settings: require("../../assets/icons/settings.png"),
slack: require("../../assets/icons/demo/slack.png"), // @demo remove-current-line
view: require("../../assets/icons/view.png"),
x: require("../../assets/icons/x.png"),
back: require("@assets/icons/back.png"),
bell: require("@assets/icons/bell.png"),
caretLeft: require("@assets/icons/caretLeft.png"),
caretRight: require("@assets/icons/caretRight.png"),
check: require("@assets/icons/check.png"),
clap: require("@assets/icons/demo/clap.png"), // @demo remove-current-line
community: require("@assets/icons/demo/community.png"), // @demo remove-current-line
components: require("@assets/icons/demo/components.png"), // @demo remove-current-line
debug: require("@assets/icons/demo/debug.png"), // @demo remove-current-line
github: require("@assets/icons/demo/github.png"), // @demo remove-current-line
heart: require("@assets/icons/demo/heart.png"), // @demo remove-current-line
hidden: require("@assets/icons/hidden.png"),
ladybug: require("@assets/icons/ladybug.png"),
lock: require("@assets/icons/lock.png"),
menu: require("@assets/icons/menu.png"),
more: require("@assets/icons/more.png"),
pin: require("@assets/icons/demo/pin.png"), // @demo remove-current-line
podcast: require("@assets/icons/demo/podcast.png"), // @demo remove-current-line
settings: require("@assets/icons/settings.png"),
slack: require("@assets/icons/demo/slack.png"), // @demo remove-current-line
view: require("@assets/icons/view.png"),
x: require("@assets/icons/x.png"),
}

const $imageStyleBase: ImageStyle = {
Expand Down
8 changes: 5 additions & 3 deletions boilerplate/app/components/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import {
View,
ViewStyle,
} from "react-native"
import { $styles } from "../theme"
import { Icon, IconTypes } from "./Icon"
import { Text, TextProps } from "./Text"

import { $styles } from "@/theme"
import type { ThemedStyle } from "@/theme"
import { useAppTheme } from "@/utils/useAppTheme"

import { Icon, IconTypes } from "./Icon"
import { Text, TextProps } from "./Text"

export interface ListItemProps extends TouchableOpacityProps {
/**
* How tall the list item should be.
Expand Down
3 changes: 2 additions & 1 deletion boilerplate/app/components/ListView.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ForwardedRef, forwardRef, PropsWithoutRef, ReactElement, RefObject } from "react"
import { FlatList } from "react-native"
import { isRTL } from "@/i18n"
import { FlashList, FlashListProps } from "@shopify/flash-list"

import { isRTL } from "@/i18n"

export type ListViewRef<T> = FlashList<T> | FlatList<T>

export type ListViewProps<T> = PropsWithoutRef<FlashListProps<T>>
Expand Down
5 changes: 3 additions & 2 deletions boilerplate/app/components/Screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import {
View,
ViewStyle,
} from "react-native"
import { $styles } from "../theme"
import { ExtendedEdge, useSafeAreaInsetsStyle } from "../utils/useSafeAreaInsetsStyle"
import { KeyboardAwareScrollView } from "react-native-keyboard-controller"

import { $styles } from "@/theme"
import { ExtendedEdge, useSafeAreaInsetsStyle } from "@/utils/useSafeAreaInsetsStyle"
import { useAppTheme } from "@/utils/useAppTheme"

export const DEFAULT_BOTTOM_OFFSET = 50
Expand Down
3 changes: 2 additions & 1 deletion boilerplate/app/components/Text.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { render } from "@testing-library/react-native"
import { Text } from "./Text"
import { NavigationContainer } from "@react-navigation/native"

import { Text } from "./Text"

/* This is an example component test using react-native-testing-library. For more
* information on how to write your own, see the documentation here:
* https://callstack.github.io/react-native-testing-library/ */
Expand Down
3 changes: 2 additions & 1 deletion boilerplate/app/components/Text.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { TOptions } from "i18next"
// eslint-disable-next-line no-restricted-imports
import { StyleProp, Text as RNText, TextProps as RNTextProps, TextStyle } from "react-native"
import { ReactNode, forwardRef, ForwardedRef } from "react"

import { isRTL, translate, TxKeyPath } from "@/i18n"
import type { ThemedStyle, ThemedStyleArray } from "@/theme"
import { useAppTheme } from "@/utils/useAppTheme"
import { typography } from "@/theme/typography"
import { ReactNode, forwardRef, ForwardedRef } from "react"

type Sizes = keyof typeof $sizeStyles
type Weights = keyof typeof typography.primary
Expand Down
6 changes: 4 additions & 2 deletions boilerplate/app/components/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
View,
ViewStyle,
} from "react-native"

import { isRTL, translate } from "@/i18n"
import type { ThemedStyle, ThemedStyleArray } from "@/theme"
import { $styles } from "../theme"
import { Text, TextProps } from "./Text"
import { $styles } from "@/theme"
import { useAppTheme } from "@/utils/useAppTheme"

import { Text, TextProps } from "./Text"

export interface TextFieldAccessoryProps {
style: StyleProp<ViewStyle | TextStyle | ImageStyle>
status: TextFieldProps["status"]
Expand Down
7 changes: 5 additions & 2 deletions boilerplate/app/components/Toggle/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { useEffect, useRef, useCallback } from "react"
import { Image, ImageStyle, Animated, StyleProp, View, ViewStyle } from "react-native"
import { $styles } from "../../theme"

import { $styles } from "@/theme"
import { useAppTheme } from "@/utils/useAppTheme"

import { iconRegistry, IconTypes } from "../Icon"

import { $inputOuterBase, BaseToggleInputProps, ToggleProps, Toggle } from "./Toggle"
import { useAppTheme } from "@/utils/useAppTheme"

export interface CheckboxToggleProps extends Omit<ToggleProps<CheckboxInputProps>, "ToggleInput"> {
/**
Expand Down
6 changes: 4 additions & 2 deletions boilerplate/app/components/Toggle/Radio.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { useEffect, useRef } from "react"
import { StyleProp, View, ViewStyle, Animated } from "react-native"
import { $styles } from "../../theme"
import { $inputOuterBase, BaseToggleInputProps, ToggleProps, Toggle } from "./Toggle"

import { $styles } from "@/theme"
import { useAppTheme } from "@/utils/useAppTheme"

import { $inputOuterBase, BaseToggleInputProps, ToggleProps, Toggle } from "./Toggle"

export interface RadioToggleProps extends Omit<ToggleProps<RadioInputProps>, "ToggleInput"> {
/**
* Optional style prop that affects the dot View.
Expand Down
3 changes: 2 additions & 1 deletion boilerplate/app/components/Toggle/Switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import {
import { $styles } from "@/theme"
import { iconRegistry } from "@/components/Icon"
import { isRTL } from "@/i18n"
import { $inputOuterBase, BaseToggleInputProps, Toggle, ToggleProps } from "./Toggle"
import { useAppTheme } from "@/utils/useAppTheme"
import type { ThemedStyle } from "@/theme"

import { $inputOuterBase, BaseToggleInputProps, Toggle, ToggleProps } from "./Toggle"

export interface SwitchToggleProps extends Omit<ToggleProps<SwitchInputProps>, "ToggleInput"> {
/**
* Switch-only prop that adds a text/icon label for on/off states.
Expand Down
6 changes: 4 additions & 2 deletions boilerplate/app/components/Toggle/Toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import {
ViewProps,
ViewStyle,
} from "react-native"
import { $styles } from "../../theme"
import { Text, TextProps } from "../Text"

import { $styles } from "@/theme"
import { useAppTheme } from "@/utils/useAppTheme"
import type { ThemedStyle } from "@/theme"

import { Text, TextProps } from "../Text"

export interface ToggleProps<T> extends Omit<TouchableOpacityProps, "style"> {
/**
* A style modifier for different input states.
Expand Down
2 changes: 1 addition & 1 deletion boilerplate/app/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./AutoImage"
export * from "./Button"
export * from "./Card"
export * from "./EmptyState"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

separate thought from this PR but maybe we drop barrel files? I think most of us have moved away from that pattern on projects - what are your thoughts there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We moved away from barrel files on my current project and it reduced a lot of dependency cycles. Could be useful to check Ignite and see how many cycles are in there by default right now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in essence we'd turn the imports from this:

import {
  Button,
  ButtonAccessoryProps,
  Card,
  EmptyState,
  Icon,
  ListView,
  Screen,
  Switch,
  Text,
} from "@/components"

to this?

import { Button, ButtonAccessoryProps } from "@/components/Button"
import { Card } from "@/components/Card"
import { EmptyState } from "@/components/EmptyState"
import { Icon } from "@/components/Icon"
import { ListView } from "@/components/ListView"
import { Screen } from "@/components/Screen"
import { Switch } from "@/components/Toggle/Switch"
import { Text } from "@/components/Text"

Currently reading up on this and will post more thoughts after i run some tests and analysis

Copy link
Contributor

@joshuayoes joshuayoes May 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to using direct import from import aliases instead of barrel files reducing dependency cycles

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the idea of managing a public exports boundary is better enforced using package.json#exports between package modules rather than trying to enforce module boundaries within the same workspace.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we are using dependency-cruiser on a client project to report dependency cycles outside of metro as a part of linting and it works well. The benefit of this approach is that we can keep using barrel files if desired and it will warn when it creates a dependency cycle.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah wherever the components are imported they'd end up on separate lines and the index.ts in app/components gets deleted. But it also exists in other directories:

There's also one in the models, navigators and screens dir. Some export *s in theme.

And then we'd have to update the ignite/templates to not import from the barrel index as well.

Does that sound right, @coolsoftwaretyler ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joshuayoes I used madge to find the circular deps. I think adding a circular-deps test to the CI to make sure there are none is a good idea - #2959

export * from "./Header"
export * from "./Icon"
export * from "./ListItem"
Expand All @@ -9,4 +10,3 @@ export * from "./Screen"
export * from "./Text"
export * from "./TextField"
export * from "./Toggle"
export * from "./EmptyState"
Loading