๐ŸŽ‰ ๋‹ค์Œ๊ณผ ๊ฐ™์€ CSS ์Šคํƒ€์ผ์˜ React Native์šฉ @akalli/components ์Šค๋งˆํŠธ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

10857 ๋‹จ์–ด
@akalli/components์€ ์Šค๋งˆํŠธ ๊ตฌ์„ฑ ์š”์†Œ ๋ฐ ์–‘์‹ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์˜ React Native์šฉ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. styled-components๊ฐ€ ์žˆ๋Š” chakra-ui/native-base ์•„์ด๋””์–ด์˜ ์ž์‹์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Enough talk, just an example can make this clear lol :).



import { Text, View } from "@akalli/components";

export const Component = memo((props: IPropsHeader) => {
  return (
    <View _style={styles.view}>
      <Text _style={styles.text}>My text here</Text>
      <Text _style="color: blue;">Inline styles support too!</Text>
    </View>
  );
});

const styles = {
  view: `
    height: 100px;
    background-color: red;
    width: 100%;
  `,
  text: `
    color: white;
    font-size: 24px;
  `,
};


์Šคํƒ€์ผinline์„ ๋„ฃ๊ฑฐ๋‚˜ const ๋˜๋Š” object์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ›„๋“œ ์•„๋ž˜์—์„œ ๋ชจ๋‘ ์Šคํƒ€์ผ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค.

์„ค์น˜


npm install @akalli/components styled-components react-native-svg yup

์šฉ๋ฒ•



์ด ๊ตฌ์„ฑ์š”์†Œ lib์™€ ์—ฐ๊ด€๋œ special props๋Š” _๋กœ ์‹๋ณ„๋ฉ๋‹ˆ๋‹ค. prop with _๊ฐ€ ํ‘œ์‹œ๋  ๋•Œ๋งˆ๋‹ค ์ด๋Š” ์šฐ๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ค‘ ํ•˜๋‚˜๋ผ๋Š” ์˜๋ฏธ์ด๋ฉฐ ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ์€ react-native์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  TypeScript ๋•๋ถ„์— ๊ตฌ์„ฑ ์š”์†Œ์—์„œ _๋ฅผ ๋ˆŒ๋Ÿฌ ์‚ฌ์šฉํ•  ์˜ˆ์•ฝ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌ์„ฑํ’ˆ



์ŠคํŽ˜์…œ ๋ทฐ



  • ๋ณด๊ธฐ - RN์˜ ๋ณด๊ธฐ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

  • HSection ๋ฐ VSection - ๋ณด๊ธฐ์ด์ง€๋งŒ ๋ฐฉํ–ฅ์ด ์ง€์ •๋˜๊ณ  ์˜๋ฏธ๋ก ์ ์ž…๋‹ˆ๋‹ค.

  • ScrollView - RN์˜ ScrollView์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

  • Center, HCenter ๋ฐ VCenter - ์ค‘์•™ ์ง‘์ค‘ํ™” ์Šคํƒ€์ผ์ด ๋‹ค๋ฅธ ๋ณด๊ธฐ์ž…๋‹ˆ๋‹ค.

  • ํ‘œ์‹œ - ์กฐ๊ฑด ๋…ผ๋ฆฌ๊ฐ€ ์žˆ๋Š” ๋ณด๊ธฐ๋กœ, ๋ณด๋‹ค ๋ช…ํ™•ํ•˜๊ณ  ์˜๋ฏธ๋ก ์ ์ธ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์„ ๋งŒ๋“œ๋Š” ๋ฐ ์ข‹์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์ž˜๋ชป๋œ ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์†Œํ’ˆ_fallback์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

  • ๊ธฐ์šธ๊ธฐ



  • FlatList - FlatList์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

  • SectionList - SectionList์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

  • ์ž…๋ ฅ



  • TextInput - RN์˜ TextInput๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

  • ์ž…๋ ฅ - ํ™•์ธ ํ›„ํฌ useMyForm(yup๊ณผ ํ†ตํ•ฉ๋จ)๊ณผ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š” ์ž…๋ ฅ์ž…๋‹ˆ๋‹ค.

  • ๊ธฐํƒ€



  • ํ—ค๋” - ์•„์ด์ฝ˜์œผ๋กœ ํ—ค๋”๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋” ์‰ฌ์šด ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

  • ํ…Œ๋งˆ ๋ฐ ๋ณ€ํ˜•




    const initialTheme = {
      colors: {},
      fontSizes: {},
      variants: {
        viewBgRed:`
          background-color: red;
        `
      }
    }
    
    <MyThemeProvider theme={initialTheme}>
      <View _variant='viewBgRed'>
       <Text>Hey coders!</Text>
      </View>
    </MyThemeProvider>
    


    ํ›„ํฌ



  • useMyStyle - ์ด ํ›„ํฌ๋Š” ๋™์  ์Šคํƒ€์ผ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ  ๋™์ ์œผ๋กœ ์Šคํƒ€์ผ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • // This will only be called again when lang changes.
     const changeLangButtonStyle = useMyStyle(styles.changeLangButton(lang), [
        lang,
      ]);
    
    


  • useMyStyledComponent - ์ด๋ฅผ ํ†ตํ•ด ์šฐ๋ฆฌ์˜ ์ฒ ํ•™์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž์‹ ๋งŒ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • useMyTheme - ํ…Œ๋งˆ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์•ฑ์„ ๋‹น์‚ฌMyThemeProvider ๋ฐ ํ”ผ๋“œtheme prop๋กœ ๋ž˜ํ•‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • useMyForm - ์ด ํ›„ํฌ๋Š” ์–‘์‹ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ์‚ฌ์šฉ๋˜๋ฉฐ yup๊ณผ ํ†ตํ•ฉ๋ฉ๋‹ˆ๋‹ค.

  • const schema = yup.object().shape({
      name: yup
        .string()
        .min(5, "put at least 5 letters")
        .required("Name is required"),
      email: yup.string().email("Not valid email").required("Email is required"),
    });
    
     const { register, handleSubmitForm } = useMyForm({ schema });
    
      <Input
              _variant="inputForm"
              _register={register}
              _key="name" // This key must be the same as yup schema
              _label="Name"
              _placeholder="Seu nome"
              _customStyles={styles.inputDataClient}
              _colors={{
                main: "#7a7a7a",
                error: "#f5427b",
              }}
            />
           ...
    



    const styles = { 
      inputDataClient: {
        label: `
          font-size: 20px; 
          text-align: left;
    
        `,
        input: `
          font-size: 18px; 
          padding-left: 15px; 
          height: 40px;
          border-radius: 8px;
          color: #A7A7A8;
        `,
        container: `
          margin-top: 20px; 
          align-items: flex-start;
        `,
      },
    }
    


    ์ด ํ”„๋กœ์ ํŠธ๋Š” ๋…๋ฆฝ์ ์ด์ง€๋งŒ npx์— ์‰ฝ๊ฒŒ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋Š” ํ›จ์”ฌ ๋” ํฐ ์—‘์Šคํฌ ํ…œํ”Œ๋ฆฟ ํŒจํ‚ค์ง€์˜ ์ผ๋ถ€์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

    ๋งŒ๋‚˜๋‹ค: @akalli/create-akalli-app

    GitHub์˜ ๋ชจ๋“  ์˜คํ”ˆ ์†Œ์Šค์ž…๋‹ˆ๋‹ค. ์ฒดํฌ ์•„์›ƒํ•˜๊ณ  ์˜์‹ฌ์ด๋‚˜ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉด ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๋‚ด ์ด๋ฉ”์ผ[email protected]๋กœ ์—ฐ๋ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ