Variants와 sizes

Variants와 sizes

커스텀 variants 추가

대부분의 Mantine 컴포넌트는 variant prop을 지원해요. 이 prop은 CSS variables resolver에서 사용할 수 있고, 컴포넌트의 루트 요소에 data-variant="{value}" 속성으로도 노출돼요. 커스텀 variants를 추가하는 가장 쉬운 방법은 [data-variant="{value}"]를 사용하는 스타일을 추가하는 거예요.

Input 컴포넌트에 새 variant를 추가하는 예시:

  • underline variant 스타일이 추가돼요

  • filled variant는 기본 variant이며 추가 스타일을 정의할 필요가 없어요

import { Input, MantineProvider, createTheme } from '@mantine/core';
import classes from './Demo.module.css';

// It is better to add new variants in theme.components
// This way you will be able to use them in anywhere in the app
const theme = createTheme({
  components: {
    Input: Input.extend({ classNames: classes }),
  }
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Input variant="underline" placeholder="Underline input" />
    </MantineProvider>
  );
}

Styles API를 지원하는 모든 Mantine 컴포넌트에 커스텀 variants를 추가할 수 있다는 점에 주의하세요. 라이브러리 쪽에 variants가 정의되어 있지 않아도 돼요.

기존 variants 스타일 재정의

새 variants를 추가하는 것 외에 기존 것도 재정의할 수 있어요. 예를 들어 .input[data-variant="filled"] selector로 Input 컴포넌트의 filled variant를 바꿀 수 있어요.

출처: 문서

본문

커스텀 variants 타입

프로젝트에 mantine.d.ts 파일을 만들고 {x}Props 인터페이스를 새 variant 타입으로 확장해 커스텀 variants의 타입을 정의할 수 있어요.

Button 컴포넌트에 커스텀 variant 타입을 추가하는 예시:

import { ButtonVariant, MantineSize } from '@mantine/core';

type ExtendedButtonVariant = ButtonVariant | 'contrast' | 'radial-gradient';

declare module '@mantine/core' {
  export interface ButtonProps {
    variant?: ExtendedButtonVariant;
  }
}

variantColorResolver

Button, Badge, ActionIcon 및 다른 컴포넌트는 variantColorResolver로 커스텀 variants를 지원해요 – 색상 변경과 새 variants 추가를 모두 지원해요. theme.variantColorResolver는 색상만 담당한다는 점에 주의하세요. 다른 속성을 바꿔야 한다면 data-variant 속성을 사용해요.

import {
  Button,
  Group,
  MantineProvider,
  defaultVariantColorsResolver,
  VariantColorsResolver,
  parseThemeColor,
  rgba,
  darken,
} from '@mantine/core';

const variantColorResolver: VariantColorsResolver = (input) => {
  const defaultResolvedColors = defaultVariantColorsResolver(input);
  const parsedColor = parseThemeColor({
    color: input.color || input.theme.primaryColor,
    theme: input.theme,
  });

  // Override some properties for variant
  if (parsedColor.isThemeColor && parsedColor.color === 'lime' && input.variant === 'filled') {
    return {
      ...defaultResolvedColors,
      color: 'var(--mantine-color-black)',
      hoverColor: 'var(--mantine-color-black)',
    };
  }

  // Completely override variant
  if (input.variant === 'light') {
    return {
      background: rgba(parsedColor.value, 0.1),
      hover: rgba(parsedColor.value, 0.15),
      border: `1px solid ${parsedColor.value}`,
      color: darken(parsedColor.value, 0.1),
    };
  }

  // Add new variants support
  if (input.variant === 'danger') {
    return {
      background: 'var(--mantine-color-red-9)',
      hover: 'var(--mantine-color-red-8)',
      color: 'var(--mantine-color-white)',
      border: 'none',
    };
  }

  return defaultResolvedColors;
};

function Demo() {
  return (
    <MantineProvider theme={{ variantColorResolver }}>
      <Group>
        <Button color="lime" variant="filled">Lime filled button</Button>
        <Button color="orange" variant="light">Orange light button</Button>
        <Button variant="danger">Danger button</Button>
      </Group>
    </MantineProvider>
  );
}

컴포넌트 CSS variables로 sizes 추가

size prop을 지원하는 어떤 컴포넌트든 커스텀 CSS variables resolver를 제공해 커스텀 sizes를 추가할 수 있어요. 보통 이것은 theme.components에서 해요:

import { Button, Group, MantineProvider, createTheme } from '@mantine/core';

const theme = createTheme({
  components: {
    Button: Button.extend({
      vars: (theme, props) => {
        if (props.size === 'xxl') {
          return {
            root: {
              '--button-height': '60px',
              '--button-padding-x': '30px',
              '--button-fz': '24px',
            },
          };
        }

        if (props.size === 'xxs') {
          return {
            root: {
              '--button-height': '24px',
              '--button-padding-x': '10px',
              '--button-fz': '10px',
            },
          };
        }

        return { root: {} };
      },
    }),
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Group>
        <Button size="xxl">XXL Button</Button>
        <Button size="xxs">XXS Button</Button>
      </Group>
    </MantineProvider>
  );
}

data-size 속성으로 sizes 추가

size prop을 지원하는 모든 컴포넌트는 그것을 루트 요소의 data-size="{value}" 속성으로 노출해요. 이것으로 커스텀 sizes를 추가할 수 있어요:

import { Input, createTheme, MantineProvider } from '@mantine/core';
import classes from './Demo.module.css';

const theme = createTheme({
  components: {
    Input: Input.extend({ classNames: classes }),
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <Input size="xxl" placeholder="XXL input" />
    </MantineProvider>
  );
}
.input[data-size='xxl'] {
  --input-height: 60px;
}

정적 CSS variables로 sizes 추가

Mantine 컴포넌트 sizes는 CSS variables로 정의돼요(보통 루트 요소에). 예를 들어 ActionIcon 컴포넌트는 다음 CSS variables를 가져요:

.root {
  --ai-size-xs: 18px;
  --ai-size-sm: 22px;
  --ai-size-md: 28px;
  --ai-size-lg: 34px;
  --ai-size-xl: 44px;
}

이 값들을 Styles API로 재정의하거나 새 size 값을 추가할 수 있어요:

import { ActionIcon, createTheme, Group, MantineThemeProvider } from '@mantine/core';
import { HeartIcon } from '@phosphor-icons/react';
import classes from './Demo.module.css';

const theme = createTheme({
  components: {
    ActionIcon: ActionIcon.extend({
      classNames: classes,
    }),
  },
});

function Demo() {
  return (
    <MantineThemeProvider theme={theme}>
      <Group>
        <ActionIcon size="xl"><HeartIcon /></ActionIcon>
        <ActionIcon size="xxl"><HeartIcon /></ActionIcon>
      </Group>
    </MantineThemeProvider>
  );
}

일부 컴포넌트는 size에 대해 하나 이상의 CSS variable을 가진다는 점에 주의하세요. 예를 들어 Button 컴포넌트는 다음 CSS variables를 가져요:

.root {
  --button-height-xs: 30px;
  --button-height-sm: 36px;
  --button-height-md: 42px;
  --button-height-lg: 50px;
  --button-height-xl: 60px;

  --button-height-compact-xs: 22px;
  --button-height-compact-sm: 26px;
  --button-height-compact-md: 30px;
  --button-height-compact-lg: 34px;
  --button-height-compact-xl: 40px;

  --button-padding-x-xs: 14px;
  --button-padding-x-sm: 18px;
  --button-padding-x-md: 22px;
  --button-padding-x-lg: 26px;
  --button-padding-x-xl: 32px;

  --button-padding-x-compact-xs: 7px;
  --button-padding-x-compact-sm: 8px;
  --button-padding-x-compact-md: 10px;
  --button-padding-x-compact-lg: 12px;
  --button-padding-x-compact-xl: 14px;
}

보통 이런 경우에는 theme의 data-size 속성이나 vars를 사용해 sizes를 커스터마이즈하는 것이 더 편리해요.

더 알아보기 (Learn more)