Mantine 에디터 플러그인 (Mantine Editor Plugins)

@beautifuljs/grid-mantine으로 Mantine Select, DatePicker, ColorPicker, TimePicker를 BeautifulGrid 컬럼에 연결합니다.

#editor-plugin#mantine#portal#date-picker#color-picker#time-picker
검토일: 2026-09-24
LIVE DEMOMantine 에디터 플러그인 (Mantine Editor Plugins) 인터랙티브 예제
인터랙티브 데모를 불러오는 중입니다…
GitHub
import { t } from './i18n';
import * as React from 'react';
import { BGrid, type BGridColumn, type BGridDataItem } from 'beautiful-grid';
import {
  createMantineColorPickerEditorPlugin,
  createMantineDatePickerEditorPlugin,
  createMantineSelectEditorPlugin,
  createMantineTimePickerEditorPlugin,
} from '@beautifuljs/grid-mantine';
import '@beautifuljs/grid-mantine/style.css';
import DataGridContainer from '../components/DataGridContainer';
import { useContainerSize } from '../hooks/useContainerSize';
import { CalendarIcon, ChevronDownIcon, ClockIcon } from './editing/editorIcons';
import {
  applyEditingDataChange,
  cloneEditingOrders,
  type EditingOrder,
  withEditingCellClasses,
} from './editing/shared';

type MantineEditorOrder = EditingOrder & {
  labelColor: string;
  deliveryTime: string;
};

const statusEditor = createMantineSelectEditorPlugin<MantineEditorOrder, EditingOrder['status']>({
  id: 'mantine-status',
  ariaLabel: t('Mantine 주문 상태 선택', 'Mantine Select Order Status'),
  searchable: true,
  options: [
    { value: t('접수', 'Receipt'), label: t('접수', 'Receipt') },
    { value: t('진행', 'In Progress'), label: t('진행', 'In Progress') },
    { value: t('완료', 'Completed'), label: t('완료', 'Completed') },
  ],
});

const deliveryDateEditor = createMantineDatePickerEditorPlugin<MantineEditorOrder>({
  id: 'mantine-delivery-date',
  ariaLabel: t('Mantine 납기일 선택', 'Mantine Select Delivery Date'),
});

const labelColorEditor = createMantineColorPickerEditorPlugin<MantineEditorOrder>({
  id: 'mantine-label-color',
  ariaLabel: t('Mantine 라벨 색상 선택', 'Mantine Select Label Color'),
  colors: ['#228BE6', '#12B886', '#7950F2', '#FD7E14'],
});

const deliveryTimeEditor = createMantineTimePickerEditorPlugin<MantineEditorOrder>({
  id: 'mantine-delivery-time',
  ariaLabel: t('Mantine 배송 시간 선택', 'Mantine Select Delivery Time'),
  minuteStep: 5,
});

const initialColors = ['#228BE6', '#12B886', '#7950F2', '#FD7E14'];
const initialDeliveryTimes = ['09:30', '11:00', '14:30', '16:00'];

const cloneMantineEditorOrders = (): BGridDataItem<MantineEditorOrder>[] =>
  cloneEditingOrders().map((item, index) => ({
    ...item,
    values: {
      ...item.values,
      labelColor: initialColors[index % initialColors.length],
      deliveryTime: initialDeliveryTimes[index % initialDeliveryTimes.length],
    },
  }));

export default function ExternalMantineEditorPluginExample() {
  const [data, setData] = React.useState(cloneMantineEditorOrders);
  const containerRef = React.useRef<HTMLDivElement>(null);
  const { width, height } = useContainerSize(containerRef);

  const columns = React.useMemo<BGridColumn<MantineEditorOrder>[]>(
    () =>
      withEditingCellClasses<MantineEditorOrder>([
        { key: 'orderCode', label: t('주문 코드', 'Order Code'), width: 140, editable: false },
        {
          key: 'status',
          label: 'Mantine Select',
          width: 165,
          editable: true,
          editor: statusEditor,
          editorIcon: { render: <ChevronDownIcon />, ariaLabel: t('Mantine 상태 선택', 'Mantine Select Status') },
        },
        {
          key: 'deliveryDate',
          label: 'Mantine DatePicker',
          width: 175,
          editable: true,
          editor: deliveryDateEditor,
          editorIcon: { render: <CalendarIcon />, ariaLabel: t('Mantine 납기일 선택', 'Mantine Select Delivery Date') },
        },
        {
          key: 'labelColor',
          label: 'Mantine ColorPicker',
          width: 175,
          editable: true,
          editor: labelColorEditor,
          editorIcon: {
            render: ({ value }) => (
              <span
                className='bgrid-color-swatch'
                style={{ backgroundColor: typeof value === 'string' ? value : 'transparent' }}
                aria-hidden='true'
              />
            ),
            ariaLabel: t('Mantine 라벨 색상 선택', 'Mantine Select Label Color'),
          },
        },
        {
          key: 'deliveryTime',
          label: 'Mantine TimePicker',
          width: 175,
          editable: true,
          editor: deliveryTimeEditor,
          editorIcon: { render: <ClockIcon />, ariaLabel: t('Mantine 배송 시간 선택', 'Mantine Select Delivery Time') },
        },
      ]),
    [],
  );

  return (
    <div className='flex min-h-0 flex-col gap-3'>
      <p className='m-0 rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm leading-6 text-slate-700 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-300'>
        <code>@beautifuljs/grid-mantine</code>
        {t(
          '의 Select, DatePicker, ColorPicker, TimePicker를 사용합니다. Cascader와 TreeSelect는 이 통합의 지원 범위에 포함되지 않습니다.',
          ' provides Select, DatePicker, ColorPicker, and TimePicker. Cascader and TreeSelect are outside this integration scope.',
        )}
      </p>
      <DataGridContainer ref={containerRef} style={{ height: 340 }}>
        <BGrid<MantineEditorOrder>
          width={width}
          height={height}
          data={data}
          columns={columns}
          rowKey='id'
          editable
          variant='vertical-bordered'
          onChangeData={(sourceIndex, _columnIndex, values, _column, meta) => {
            setData(current => applyEditingDataChange(current, sourceIndex, values, meta));
          }}
        />
      </DataGridContainer>
    </div>
  );
}

@beautifuljs/grid-mantine은 Mantine 컴포넌트를 BeautifulGrid plugin editor 수명주기에 연결하는 공식 패키지입니다. Select, DatePicker, ColorPicker, TimePicker를 제공하며 각 dropdown과 popover를 Grid 전용 portal에 렌더링합니다.

설치

npm install @beautifuljs/grid-mantine @mantine/core @mantine/dates dayjs

Mantine의 기본 스타일과 plugin 스타일을 애플리케이션 진입점에서 한 번 불러오고, 앱 최상위에 MantineProvider를 둡니다.

import { MantineProvider } from '@mantine/core';
import '@mantine/core/styles.css';
import '@mantine/dates/styles.css';
import 'beautiful-grid/style.css';
import '@beautifuljs/grid-mantine/style.css';

root.render(
  <MantineProvider>
    <App />
  </MantineProvider>,
);

Editor factory 연결

import {
  createMantineColorPickerEditorPlugin,
  createMantineDatePickerEditorPlugin,
  createMantineSelectEditorPlugin,
  createMantineTimePickerEditorPlugin,
} from '@beautifuljs/grid-mantine';

const statusEditor = createMantineSelectEditorPlugin<Order, Order['status']>({
  id: 'order-status',
  ariaLabel: '주문 상태 선택',
  searchable: true,
  options: [
    { value: 'ready', label: '접수' },
    { value: 'done', label: '완료' },
  ],
});

const dateEditor = createMantineDatePickerEditorPlugin<Order>({
  id: 'order-date',
  ariaLabel: '납기일 선택',
});

const colorEditor = createMantineColorPickerEditorPlugin<Order>({
  id: 'order-color',
  ariaLabel: '라벨 색상 선택',
  colors: ['#228BE6', '#12B886', '#FD7E14'],
});

const timeEditor = createMantineTimePickerEditorPlugin<Order>({
  id: 'order-time',
  ariaLabel: '배송 시간 선택',
  minuteStep: 5,
});
const columns: BGridColumn<Order>[] = [
  { key: 'status', label: '상태', editable: true, editor: statusEditor },
  { key: 'deliveryDate', label: '납기일', editable: true, editor: dateEditor },
  { key: 'labelColor', label: '색상', editable: true, editor: colorEditor },
  { key: 'deliveryTime', label: '시간', editable: true, editor: timeEditor },
];

지원 범위와 값 형식

  • Select는 문자열·숫자 option과 검색 모드를 지원합니다.
  • DatePicker는 ISO 형태의 YYYY-MM-DD 문자열을 저장합니다.
  • ColorPicker는 기본적으로 #RRGGBB를 저장하며 alpha 사용 여부를 설정할 수 있습니다.
  • TimePicker는 HH:mm 또는 seconds 옵션을 켠 HH:mm:ss 문자열을 저장합니다.
  • Cascader와 TreeSelect는 Mantine 공식 통합 범위에 포함되지 않습니다.

popup이 닫힐 때 아직 저장하지 않았다면 편집을 취소하고, Apply 또는 값 선택으로 저장한 경우 뒤이어 발생하는 close 이벤트가 결과를 덮어쓰지 않습니다.

패키지 API와 라이선스 정보는 @beautifuljs/grid-mantine npm 페이지에서 확인할 수 있습니다.