【React】MantineUIのv7.0.0での変更点

はじめに

この記事の概要

こんにちは、株式会社TOKOSのスギタです!
今回は先日アップデートされてv6系からv7系にメジャーアップデートされたMantineの気になった変更箇所をまとめましたので紹介します。

対象読者

  • Reactを用いたWEB制作、WEB開発を行っている方
  • tailwindcssを使用しながらUIライブラリを使用したい方

破壊的変更

まずは破壊的変更からです。

コンポーネントのオーバーライドの方法が大幅に変更になりました。
Emotionに依存しなくなりました。

createStyle関数は使用できなくなりました。

SX propsを使用できなくなりました。

stylespropsはネストされたセレクターをサポートしなくなりました。

より軽量になるのはめちゃくちゃ嬉しいです。

Emotionの依存解消

Emotionの依存しなくなったのでNext.jsのAppRouterのサーバーコンポーネントで使用できるのかなと思っていたのですが、できないみたいです。
Mantineのコンポーネントでは、デフォルトの props とスタイル API 機能に React コンテキストを使用している為(公式Discord参照)
今後もこの機能を削除する予定は無いみたいです。

新要素

color scheme

MantineProviderにcolor schemeを設定できるようになりました。

import { MantineProvider, ColorSchemeScript } from '@mantine/core';

function Demo() {
  return (
    <>
      <ColorSchemeScript defaultColorScheme="auto" />
      <MantineProvider defaultColorScheme="auto">
        <App />
      </MantineProvider>
    </>
  );
}

CSSモジュールとPostCSSのプリセット

CSSモジュールはスタイルを設定するために推奨だが必須ではありません、postcss-preset-mantineを使用することも推奨になりました。

ヘッドレスUI化

@mantine/*/styles.css をインストールしなければヘッドレスUIとしても使用できるようになりました。

テーマ作成関数

createTheme 関数を使うとすべてのテーマのプロパティに対してオーバーライドできるようになりました。

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

const theme = createTheme({
  fontFamily: 'sans-serif',
  primaryColor: 'orange',
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <App />
    </MantineProvider>
  );
}

コンポーネントの機能拡張

extend でコンポーネントの拡張ができるようになりました。

下記はTextInputのデフォルトスタイルをオーバーライドしています。独自のpropsとかも作成できるようになりました。

const theme = createTheme({
  components: {
    TextInput: TextInput.extends({
      styles: (theme, props) => ({
        input: {
          fontSize: props.size === 'compact' ? theme.fontSizes.sm : undefined,
        }
      })
      classNames: {
        root: classes.root,
        input: classes.input,
        label: classes.label,
      },

      defaultProps: {
        size: 'compact',
      },
    }),
  },
});

function Demo() {
  return (
    <MantineProvider theme={theme}>
      <App />
    </MantineProvider>
  );
}

コンポーネントの機能拡張

16進数、RGBA、HSLでカラーの指定が可能になりました。

function Demo() {
  return (
    <Button color="#fff">
    ボタン
    </Button>
  );
}

Comboboxコンポーネント

Autocomplete、Select、Tagsinput、Multiselectのベースとして使用されるComboboxコンポーネントが追加されました。
以前のAutocomplete、Select、Multiselectで実装されていた機能のベースは共通でComboboxコンポーネントが受け持つようになるみたいです。
また公式が出しているDEMOページが素晴らしいので是非一度見てほしいです。

リセットCSSについて

リセットcssのnormalize.cssがなくなりました。かわりに最小限のリセットCSSに変更しました。

html,
body {
  height: 100%;
}

body {
  margin: 0;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

input,
button,
textarea,
select {
  font: inherit;
}

button,
select {
  text-transform: none;
}

この変更で、Tailwind側のリセットCSSとの互換性がよくなるかなと期待したのですが、あまり良くありませんでした。
どうせならばTailwindのリセットCSSとして採用されているmodern-normalize.cssに合わせてくれれば個人的には嬉しかったです。
現状はmodern-normalize.cssがMantineに干渉するプロパティだけ削除して使用するのが良さそうです。

@tailwind components;
@tailwind utilities;

/*
node_modules/tailwindcss/lib/css/preflight.css からコピペしている
Mantineと競合するスタイルのみを削除している
*/

*,
::before,
::after {
  box-sizing: border-box;
  border-width: 0;
  border-style: solid;
  border-color: theme("borderColor.DEFAULT", currentColor);
}

::before,
::after {
  --tw-content: "";
}

html {
  -webkit-text-size-adjust: 100%;
  -moz-tab-size: 4;
  tab-size: 4;
  font-family: theme(
    "fontFamily.sans",
    ui-sans-serif,
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    Roboto,
    "Helvetica Neue",
    Arial,
    "Noto Sans",
    sans-serif,
    "Apple Color Emoji",
    "Segoe UI Emoji",
    "Segoe UI Symbol",
    "Noto Color Emoji"
  );
  /* CSS変数を使っているためコメントアウト */
  /* font-feature-settings: theme(
    "fontFamily.sans[1].fontFeatureSettings",
    normal
  ); */
  /* font-variation-settings: theme(
    "fontFamily.sans[1].fontVariationSettings",
    normal
  ); */
}

body {
  margin: 0;
  line-height: inherit;
  color: #151515 !important;
}

hr {
  height: 0;
  color: inherit;
  border-top-width: 1px;
}

abbr:where([title]) {
  text-decoration: underline dotted;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-size: inherit;
  font-weight: inherit;
}

a {
  color: inherit;
  text-decoration: inherit;
}

b,
strong {
  font-weight: bolder;
}

code,
kbd,
samp,
pre {
  font-family: theme(
    "fontFamily.mono",
    ui-monospace,
    SFMono-Regular,
    Menlo,
    Monaco,
    Consolas,
    "Liberation Mono",
    "Courier New",
    monospace
  );
  font-size: 1em;
}

small {
  font-size: 80%;
}

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

table {
  text-indent: 0;
  border-color: inherit;
  border-collapse: collapse;
}

button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  font-feature-settings: inherit;
  font-variation-settings: inherit;
  font-size: 100%;
  font-weight: inherit;
  line-height: inherit;
  color: inherit;
  margin: 0;
  padding: 0;
}

button,
select {
  text-transform: none;
}

button,
[type="button"],
[type="reset"],
[type="submit"] {
  -webkit-appearance: button;
  /* MantineのButtonの色が上手く当たらないためコメントアウト */
  /* background-color: transparent; */
  background-image: none;
}

:-moz-focusring {
  outline: auto;
}

:-moz-ui-invalid {
  box-shadow: none;
}

progress {
  vertical-align: baseline;
}

::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
  height: auto;
}

[type="search"] {
  -webkit-appearance: textfield;
  outline-offset: -2px;
}

::-webkit-search-decoration {
  -webkit-appearance: none;
}

::-webkit-file-upload-button {
  -webkit-appearance: button;
  font: inherit;
}

summary {
  display: list-item;
}

blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
  margin: 0;
}

fieldset {
  margin: 0;
  padding: 0;
}

legend {
  padding: 0;
}

ol,
ul,
menu {
  list-style: none;
  margin: 0;
  padding: 0;
}

dialog {
  padding: 0;
}

textarea {
  resize: vertical;
}

input::placeholder,
textarea::placeholder {
  opacity: 1;
  color: theme("colors.gray.400", #9ca3af);
}

button,
[role="button"] {
  cursor: pointer;
}

:disabled {
  cursor: default;
}

img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
  display: block;
  vertical-align: middle;
}

img,
video {
  max-width: 100%;
  height: auto;
}

[hidden] {
  display: none;
}

現状はこれで運用しています。また何か良い方法があればご教授していただけたら幸いです。

さいごに

今回はメジャーアップデートされたMantineUIの変更箇所を紹介いたしました。ここに紹介して無いものも在るので一度公式ドキュメントを見ていただければと思います。
また公式ドキュメントの内容構成もアップデートされてコンポーネントの構成等も追記されていたりドキュメントの読みやすさも格段に上がったと思います!