podo-ui 0.3.16 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ export interface ChipProps {
3
+ children: React.ReactNode;
4
+ theme?: 'default' | 'blue' | 'green' | 'orange' | 'yellow' | 'red';
5
+ type?: 'default' | 'fill' | 'border';
6
+ size?: 'sm' | 'md';
7
+ round?: boolean;
8
+ icon?: string;
9
+ onDelete?: () => void;
10
+ className?: string;
11
+ }
12
+ declare const Chip: React.FC<ChipProps>;
13
+ export default Chip;
14
+ //# sourceMappingURL=chip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chip.d.ts","sourceRoot":"","sources":["../../../react/atom/chip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnE,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;IACrC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CA4B7B,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const Chip = ({ children, theme = 'default', type = 'default', size = 'md', round = false, icon, onDelete, className = '', }) => {
3
+ const chipClasses = [
4
+ 'chip',
5
+ theme !== 'default' && theme,
6
+ type !== 'default' && type,
7
+ size !== 'md' && size,
8
+ round && 'round',
9
+ className,
10
+ ]
11
+ .filter(Boolean)
12
+ .join(' ');
13
+ return (_jsxs("div", { className: chipClasses, children: [icon && _jsx("i", { className: `icon ${icon}` }), children, onDelete && _jsx("button", { "aria-label": "\uC0AD\uC81C", onClick: onDelete })] }));
14
+ };
15
+ export default Chip;
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- export type ToolbarItem = 'undo-redo' | 'paragraph' | 'text-style' | 'color' | 'align' | 'list' | 'table' | 'link' | 'image' | 'youtube' | 'format' | 'code';
2
+ export type ToolbarItem = 'undo-redo' | 'paragraph' | 'text-style' | 'color' | 'align' | 'list' | 'table' | 'link' | 'image' | 'youtube' | 'hr' | 'format' | 'code';
3
3
  export interface EditorProps {
4
4
  value: string;
5
5
  width?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../react/atom/editor.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,WAAW,GACX,YAAY,GACZ,OAAO,GACP,OAAO,GACP,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,GACP,SAAS,GACT,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,SAAS,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,QAAA,MAAM,MAAM,0GAWT,WAAW,4CAssIb,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../react/atom/editor.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,WAAW,GACX,YAAY,GACZ,OAAO,GACP,OAAO,GACP,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,GACP,SAAS,GACT,IAAI,GACJ,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,SAAS,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,QAAA,MAAM,MAAM,0GAWT,WAAW,4CAovIb,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -86,7 +86,6 @@ const Editor = ({ value = '', width = '100%', height = '400px', minHeight, maxHe
86
86
  const tableContextMenuRef = useRef(null);
87
87
  // 다중 셀 선택 관련 상태
88
88
  const [selectedTableCells, setSelectedTableCells] = useState([]);
89
- const [isSelectingCells, setIsSelectingCells] = useState(false);
90
89
  const [selectionStartCell, setSelectionStartCell] = useState(null);
91
90
  const isSelectingCellsRef = useRef(false); // 최신 상태 추적을 위한 ref
92
91
  const justFinishedDraggingRef = useRef(false); // 드래그가 방금 끝났는지 추적
@@ -103,6 +102,7 @@ const Editor = ({ value = '', width = '100%', height = '400px', minHeight, maxHe
103
102
  'link',
104
103
  'image',
105
104
  'youtube',
105
+ 'hr',
106
106
  'format',
107
107
  'code',
108
108
  ];
@@ -1102,7 +1102,6 @@ const Editor = ({ value = '', width = '100%', height = '400px', minHeight, maxHe
1102
1102
  // selectionStartCell이 있고, 다른 셀로 이동한 경우에만 드래그 선택 모드 활성화
1103
1103
  if (selectionStartCell && cell !== selectionStartCell && !isSelectingCellsRef.current) {
1104
1104
  isSelectingCellsRef.current = true;
1105
- setIsSelectingCells(true);
1106
1105
  e.preventDefault();
1107
1106
  e.stopPropagation();
1108
1107
  }
@@ -1141,7 +1140,6 @@ const Editor = ({ value = '', width = '100%', height = '400px', minHeight, maxHe
1141
1140
  isMouseDownRef.current = false;
1142
1141
  // 드래그 선택 모드 무조건 종료 (선택된 셀은 유지)
1143
1142
  isSelectingCellsRef.current = false;
1144
- setIsSelectingCells(false);
1145
1143
  // selectionStartCell은 유지하여 선택 상태 보존
1146
1144
  }, []);
1147
1145
  // 셀 선택 해제
@@ -1729,6 +1727,36 @@ const Editor = ({ value = '', width = '100%', height = '400px', minHeight, maxHe
1729
1727
  editorRef.current?.focus();
1730
1728
  handleInput();
1731
1729
  };
1730
+ // HR(구분선) 삽입
1731
+ const insertHR = () => {
1732
+ if (!editorRef.current)
1733
+ return;
1734
+ editorRef.current.focus();
1735
+ const selection = window.getSelection();
1736
+ if (!selection || selection.rangeCount === 0)
1737
+ return;
1738
+ const range = selection.getRangeAt(0);
1739
+ // HR 엘리먼트 생성
1740
+ const hr = document.createElement('hr');
1741
+ hr.style.border = 'none';
1742
+ hr.style.borderTop = '1px solid #ddd';
1743
+ hr.style.margin = '10px 0';
1744
+ // 새 문단 생성 (HR 다음에 커서를 위치시키기 위함)
1745
+ const newP = document.createElement('p');
1746
+ newP.innerHTML = '<br>';
1747
+ // HR과 새 문단 삽입
1748
+ range.deleteContents();
1749
+ range.insertNode(hr);
1750
+ hr.after(newP);
1751
+ // 커서를 새 문단으로 이동
1752
+ const newRange = document.createRange();
1753
+ newRange.selectNodeContents(newP);
1754
+ newRange.collapse(true);
1755
+ selection.removeAllRanges();
1756
+ selection.addRange(newRange);
1757
+ editorRef.current.focus();
1758
+ handleInput();
1759
+ };
1732
1760
  // 다중 셀 선택 범위 계산
1733
1761
  const getCellsInRange = (startCell, endCell) => {
1734
1762
  const table = startCell.closest('table');
@@ -2778,7 +2806,7 @@ const Editor = ({ value = '', width = '100%', height = '400px', minHeight, maxHe
2778
2806
  }
2779
2807
  setCurrentAlign(option.value);
2780
2808
  setIsAlignDropdownOpen(false);
2781
- }, title: option.label, children: _jsx("i", { className: styles[option.icon] }) }, option.value))) }))] })), isToolbarItemEnabled('list') && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: styles.toolbarButton, onClick: () => execCommand('insertUnorderedList'), title: "\uBAA9\uB85D", children: _jsx("i", { className: styles.listUl }) }), _jsx("button", { type: "button", className: styles.toolbarButton, onClick: () => execCommand('insertOrderedList'), title: "\uBC88\uD638 \uBAA9\uB85D", children: _jsx("i", { className: styles.listOl }) })] })), isToolbarItemEnabled('table') && (_jsxs("div", { ref: tableButtonRef, style: { position: 'relative' }, children: [_jsx("button", { type: "button", className: styles.toolbarButton, onClick: () => {
2809
+ }, title: option.label, children: _jsx("i", { className: styles[option.icon] }) }, option.value))) }))] })), isToolbarItemEnabled('list') && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: styles.toolbarButton, onClick: () => execCommand('insertUnorderedList'), title: "\uBAA9\uB85D", children: _jsx("i", { className: styles.listUl }) }), _jsx("button", { type: "button", className: styles.toolbarButton, onClick: () => execCommand('insertOrderedList'), title: "\uBC88\uD638 \uBAA9\uB85D", children: _jsx("i", { className: styles.listOl }) })] })), isToolbarItemEnabled('hr') && (_jsx("button", { type: "button", className: styles.toolbarButton, onClick: insertHR, title: "\uAD6C\uBD84\uC120", children: _jsx("i", { className: styles.hr }) })), isToolbarItemEnabled('table') && (_jsxs("div", { ref: tableButtonRef, style: { position: 'relative' }, children: [_jsx("button", { type: "button", className: styles.toolbarButton, onClick: () => {
2782
2810
  // 현재 선택 영역 저장
2783
2811
  const selection = window.getSelection();
2784
2812
  if (selection && selection.rangeCount > 0) {
@@ -210,6 +210,11 @@
210
210
  -webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"/></svg>');
211
211
  }
212
212
 
213
+ &.hr {
214
+ mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M0 224c0-17.7 14.3-32 32-32H608c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32z"/></svg>');
215
+ -webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M0 224c0-17.7 14.3-32 32-32H608c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32z"/></svg>');
216
+ }
217
+
213
218
  &.code {
214
219
  mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/></svg>');
215
220
  -webkit-mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="currentColor" d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/></svg>');
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
- import { ToastPosition, ToastVariant } from './toast';
2
+ import { ToastPosition, ToastTheme } from './toast';
3
3
  interface ToastOptions {
4
4
  header?: string;
5
5
  message: string;
6
- variant?: ToastVariant;
7
- type?: 'type01' | 'type02';
6
+ theme?: ToastTheme;
7
+ border?: boolean;
8
8
  long?: boolean;
9
9
  duration?: number;
10
10
  width?: string | number;
@@ -1 +1 @@
1
- {"version":3,"file":"toast-provider.d.ts","sourceRoot":"","sources":["../../../react/molecule/toast-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA2D,MAAM,OAAO,CAAC;AAEhF,OAAc,EAAc,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAQzE,UAAU,YAAY;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,MAAM,CAAC;IAC7C,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAID,eAAO,MAAM,QAAQ,wBAMpB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAoFjE,CAAC"}
1
+ {"version":3,"file":"toast-provider.d.ts","sourceRoot":"","sources":["../../../react/molecule/toast-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA2D,MAAM,OAAO,CAAC;AAEhF,OAAc,EAAc,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAQvE,UAAU,YAAY;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,MAAM,CAAC;IAC7C,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAID,eAAO,MAAM,QAAQ,wBAMpB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,CAoFjE,CAAC"}
@@ -28,8 +28,8 @@ export const ToastProvider = ({ children }) => {
28
28
  position,
29
29
  header: options.header,
30
30
  message: options.message,
31
- variant: options.variant,
32
- type: options.type,
31
+ theme: options.theme,
32
+ border: options.border,
33
33
  long: options.long,
34
34
  duration: options.duration,
35
35
  width: options.width,
@@ -59,6 +59,6 @@ export const ToastProvider = ({ children }) => {
59
59
  const positionToasts = getToastsByPosition(position);
60
60
  if (positionToasts.length === 0)
61
61
  return null;
62
- return (_jsx("div", { className: `${styles.toastContainer} ${styles[position]}`, children: positionToasts.map((toast) => (_jsx(Toast, { id: toast.id, header: toast.header, message: toast.message, variant: toast.variant, type: toast.type, long: toast.long, duration: toast.duration, width: toast.width, onClose: hideToast }, toast.id))) }, position));
62
+ return (_jsx("div", { className: `${styles.toastContainer} ${styles[position]}`, children: positionToasts.map((toast) => (_jsx(Toast, { id: toast.id, header: toast.header, message: toast.message, theme: toast.theme, border: toast.border, long: toast.long, duration: toast.duration, width: toast.width, onClose: hideToast }, toast.id))) }, position));
63
63
  }) }), document.body)] }));
64
64
  };
@@ -1,11 +1,11 @@
1
1
  export type ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'center-left' | 'center' | 'center-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
2
- export type ToastVariant = 'default' | 'primary' | 'info' | 'success' | 'warning' | 'danger';
2
+ export type ToastTheme = 'default' | 'primary' | 'info' | 'success' | 'warning' | 'danger';
3
3
  export interface ToastProps {
4
4
  id: string;
5
5
  header?: string;
6
6
  message: string;
7
- variant?: ToastVariant;
8
- type?: 'type01' | 'type02';
7
+ theme?: ToastTheme;
8
+ border?: boolean;
9
9
  long?: boolean;
10
10
  duration?: number;
11
11
  width?: string | number;
@@ -1 +1 @@
1
- {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../react/molecule/toast.tsx"],"names":[],"mappings":"AAKA,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,QAAQ,GACR,cAAc,GACd,aAAa,GACb,eAAe,GACf,cAAc,CAAC;AAEnB,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE7F,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CAmF/B,CAAC;AAEF,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../react/molecule/toast.tsx"],"names":[],"mappings":"AAKA,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,QAAQ,GACR,cAAc,GACd,aAAa,GACb,eAAe,GACf,cAAc,CAAC;AAEnB,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE3F,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA+E/B,CAAC;AAEF,eAAe,KAAK,CAAC"}
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from 'react';
4
4
  import styles from './toast.module.scss';
5
- const Toast = ({ id, header, message, variant = 'default', type = 'type01', long = false, duration = 3000, width, onClose, }) => {
5
+ const Toast = ({ id, header, message, theme = 'default', border = false, long = false, duration = 3000, width, onClose, }) => {
6
6
  const [isVisible, setIsVisible] = useState(false);
7
7
  const [isClosing, setIsClosing] = useState(false);
8
8
  useEffect(() => {
@@ -26,9 +26,9 @@ const Toast = ({ id, header, message, variant = 'default', type = 'type01', long
26
26
  };
27
27
  const toastClasses = [
28
28
  'toast',
29
- variant,
30
- type === 'type02' ? 'toast-border' : '',
31
- long ? 'toast-long' : '',
29
+ theme,
30
+ border ? 'border' : '',
31
+ long ? 'long' : '',
32
32
  styles.toastAnimation,
33
33
  isVisible && !isClosing ? styles.fadeIn : '',
34
34
  isClosing ? styles.fadeOut : '',
@@ -39,7 +39,7 @@ const Toast = ({ id, header, message, variant = 'default', type = 'type01', long
39
39
  width: width ? (typeof width === 'number' ? `${width}px` : width) : 'auto',
40
40
  };
41
41
  const getIcon = () => {
42
- switch (variant) {
42
+ switch (theme) {
43
43
  case 'success':
44
44
  return 'icon-check';
45
45
  case 'warning':
@@ -53,6 +53,6 @@ const Toast = ({ id, header, message, variant = 'default', type = 'type01', long
53
53
  return 'icon-info';
54
54
  }
55
55
  };
56
- return (_jsxs("div", { className: toastClasses, style: toastStyle, children: [_jsx("div", { className: "toast-icon", children: _jsx("i", { className: getIcon() }) }), _jsxs("div", { className: "toast-content", children: [header && !long && _jsx("div", { className: "toast-header", children: header }), _jsx("div", { className: "toast-body", children: message })] }), _jsx("button", { className: "toast-close", onClick: handleClose, children: _jsx("i", { className: "icon-close" }) })] }));
56
+ return (_jsxs("div", { className: toastClasses, style: toastStyle, children: [_jsx("i", { className: getIcon() }), _jsxs("div", { className: "toast-content", children: [header && !long && _jsx("div", { className: "toast-header", children: header }), _jsx("div", { className: "toast-body", children: message })] }), _jsx("button", { onClick: handleClose, "aria-label": "\uB2EB\uAE30" })] }));
57
57
  };
58
58
  export default Toast;
package/global.scss CHANGED
@@ -39,6 +39,11 @@
39
39
  @forward './scss/button/layout';
40
40
  @forward './scss/button/class';
41
41
 
42
+ /*
43
+ Atom
44
+ */
45
+ @forward './scss/atom/chip';
46
+
42
47
  /*
43
48
  Form
44
49
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "podo-ui",
3
- "version": "0.3.16",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "author": "hada0127 <work@tarucy.net>",
6
6
  "license": "MIT",
@@ -0,0 +1,232 @@
1
+ @use '../color/function' as *;
2
+
3
+ .chip {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ gap: 4px;
7
+ border-radius: 6px; // round=no (기본값)
8
+ font-family: var(--font-family);
9
+ font-weight: 400;
10
+ line-height: 1.6;
11
+ cursor: default;
12
+ user-select: none;
13
+ transition: all 0.2s;
14
+
15
+ // 기본 스타일 (theme: default, type: default, size: md)
16
+ // type: default = 진한 배경
17
+ padding: 2px 8px;
18
+ font-size: 16px;
19
+ background-color: color('default-deep');
20
+ color: color('default-deep-reverse');
21
+ border: none;
22
+
23
+ // 아이콘
24
+ i {
25
+ flex-shrink: 0;
26
+ line-height: 1;
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: center;
30
+ width: 24px;
31
+ height: 24px;
32
+ margin-right: 0 !important;
33
+
34
+ &::before {
35
+ font-size: 24px !important;
36
+ }
37
+ }
38
+
39
+ // 삭제 버튼 (chip 하위 button 요소)
40
+ button {
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ background: none;
45
+ border: none;
46
+ cursor: pointer;
47
+ padding: 0;
48
+ margin: 0;
49
+ width: 24px;
50
+ height: 24px;
51
+ font-size: 18px;
52
+ line-height: 1;
53
+ transition: opacity 0.2s;
54
+ flex-shrink: 0;
55
+ color: inherit;
56
+
57
+ &:hover {
58
+ opacity: 0.7;
59
+ }
60
+
61
+ // union 아이콘 사용
62
+ &::before {
63
+ content: '';
64
+ display: block;
65
+ width: 24px;
66
+ height: 24px;
67
+ background-color: currentColor;
68
+ mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4.39339 4.39339C4.65143 4.13535 5.06764 4.13535 5.32568 4.39339L9 8.06771L12.6743 4.39339C12.9324 4.13535 13.3486 4.13535 13.6066 4.39339C13.8647 4.65143 13.8647 5.06764 13.6066 5.32568L9.93229 9L13.6066 12.6743C13.8647 12.9324 13.8647 13.3486 13.6066 13.6066C13.3486 13.8647 12.9324 13.8647 12.6743 13.6066L9 9.93229L5.32568 13.6066C5.06764 13.8647 4.65143 13.8647 4.39339 13.6066C4.13535 13.3486 4.13535 12.9324 4.39339 12.6743L8.06771 9L4.39339 5.32568C4.13535 5.06764 4.13535 4.65143 4.39339 4.39339Z' fill='black'/%3E%3C/svg%3E");
69
+ mask-repeat: no-repeat;
70
+ mask-position: center;
71
+ mask-size: contain;
72
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4.39339 4.39339C4.65143 4.13535 5.06764 4.13535 5.32568 4.39339L9 8.06771L12.6743 4.39339C12.9324 4.13535 13.3486 4.13535 13.6066 4.39339C13.8647 4.65143 13.8647 5.06764 13.6066 5.32568L9.93229 9L13.6066 12.6743C13.8647 12.9324 13.8647 13.3486 13.6066 13.6066C13.3486 13.8647 12.9324 13.8647 12.6743 13.6066L9 9.93229L5.32568 13.6066C5.06764 13.8647 4.65143 13.8647 4.39339 13.6066C4.13535 13.3486 4.13535 12.9324 4.39339 12.6743L8.06771 9L4.39339 5.32568C4.13535 5.06764 4.13535 4.65143 4.39339 4.39339Z' fill='black'/%3E%3C/svg%3E");
73
+ -webkit-mask-repeat: no-repeat;
74
+ -webkit-mask-position: center;
75
+ -webkit-mask-size: contain;
76
+ }
77
+ }
78
+
79
+ // round=yes variant (완전히 둥근 모서리)
80
+ &.round {
81
+ border-radius: 100px;
82
+ }
83
+
84
+ // Size variants
85
+ &.sm {
86
+ padding: 2px 8px;
87
+ font-size: 12px;
88
+ gap: 4px;
89
+
90
+ i {
91
+ width: 16px;
92
+ height: 16px;
93
+
94
+ &::before {
95
+ font-size: 16px !important;
96
+ }
97
+ }
98
+
99
+ button {
100
+ width: 16px;
101
+ height: 16px;
102
+
103
+ &::before {
104
+ width: 16px;
105
+ height: 16px;
106
+ }
107
+ }
108
+ }
109
+
110
+ &.md {
111
+ padding: 2px 8px;
112
+ font-size: 16px;
113
+ gap: 4px;
114
+
115
+ i {
116
+ width: 24px;
117
+ height: 24px;
118
+
119
+ &::before {
120
+ font-size: 24px !important;
121
+ }
122
+ }
123
+
124
+ button {
125
+ width: 24px;
126
+ height: 24px;
127
+
128
+ &::before {
129
+ width: 24px;
130
+ height: 24px;
131
+ }
132
+ }
133
+ }
134
+
135
+ // Theme colors - type: default (진한 배경)
136
+ &.blue {
137
+ background-color: color('info');
138
+ color: color('info-reverse');
139
+ }
140
+
141
+ &.green {
142
+ background-color: color('success');
143
+ color: color('success-reverse');
144
+ }
145
+
146
+ &.yellow,
147
+ &.orange {
148
+ background-color: color('warning');
149
+ color: color('warning-reverse');
150
+ }
151
+
152
+ &.red {
153
+ background-color: color('danger');
154
+ color: color('danger-reverse');
155
+ }
156
+
157
+ // Type: fill (옅은 배경)
158
+ &.fill {
159
+ background-color: color('default-fill');
160
+ color: color('text-sub');
161
+
162
+ i {
163
+ color: color('text-body');
164
+ }
165
+
166
+ &.blue {
167
+ background-color: color('info-fill');
168
+ color: color('info-hover');
169
+
170
+ i {
171
+ color: color('info');
172
+ }
173
+ }
174
+
175
+ &.green {
176
+ background-color: color('success-fill');
177
+ color: color('success-hover');
178
+
179
+ i {
180
+ color: color('success');
181
+ }
182
+ }
183
+
184
+ &.yellow,
185
+ &.orange {
186
+ background-color: color('warning-fill');
187
+ color: color('warning-hover');
188
+
189
+ i {
190
+ color: color('warning');
191
+ }
192
+ }
193
+
194
+ &.red {
195
+ background-color: color('danger-fill');
196
+ color: color('danger-hover');
197
+
198
+ i {
199
+ color: color('danger');
200
+ }
201
+ }
202
+ }
203
+
204
+ // Type: border (테두리만)
205
+ &.border {
206
+ background-color: transparent;
207
+ border: 1px solid;
208
+ color: color('text-sub');
209
+ border-color: color('border');
210
+
211
+ &.blue {
212
+ color: color('info');
213
+ border-color: color('info');
214
+ }
215
+
216
+ &.green {
217
+ color: color('success');
218
+ border-color: color('success');
219
+ }
220
+
221
+ &.yellow,
222
+ &.orange {
223
+ color: color('warning');
224
+ border-color: color('warning');
225
+ }
226
+
227
+ &.red {
228
+ color: color('danger');
229
+ border-color: color('danger');
230
+ }
231
+ }
232
+ }
@@ -7,25 +7,27 @@
7
7
  align-items: flex-start;
8
8
  gap: s(3);
9
9
  padding: s(4) s(5);
10
- border-radius: r(1);
11
- background-color: color('bg-elevation-1');
10
+ border-radius: r(1); // 2px (border=no 기본값)
11
+ background-color: color('default-fill');
12
12
  border: none;
13
- border-top: 4px solid color('border');
13
+ border-top: 4px solid color('default-deep');
14
14
  position: relative;
15
15
  min-width: 320px;
16
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
17
16
 
18
- // Icon area
19
- .toast-icon {
17
+ // Icon (직접 i 요소 사용)
18
+ > i {
20
19
  flex-shrink: 0;
21
20
  width: 24px;
22
21
  height: 24px;
23
22
  display: flex;
24
23
  align-items: center;
25
24
  justify-content: center;
25
+ color: color('text-sub');
26
+ margin: 0 !important;
26
27
 
27
- i {
28
- font-size: 20px;
28
+ &::before {
29
+ font-size: 24px !important;
30
+ margin: 0 !important;
29
31
  }
30
32
  }
31
33
 
@@ -34,7 +36,7 @@
34
36
  flex: 1;
35
37
  display: flex;
36
38
  flex-direction: column;
37
- gap: s(1);
39
+ gap: 4px;
38
40
  }
39
41
 
40
42
  .toast-header {
@@ -50,8 +52,8 @@
50
52
  color: color('text-body');
51
53
  }
52
54
 
53
- // Close button
54
- .toast-close {
55
+ // Close button (toast 하위 button 요소)
56
+ button {
55
57
  flex-shrink: 0;
56
58
  width: 24px;
57
59
  height: 24px;
@@ -59,22 +61,37 @@
59
61
  align-items: center;
60
62
  justify-content: center;
61
63
  cursor: pointer;
62
- color: color('text-action');
64
+ color: color('text-sub');
63
65
  background: none;
64
66
  border: none;
65
67
  padding: 0;
68
+ margin: 0;
69
+ transition: opacity 0.2s;
66
70
 
67
71
  &:hover {
68
- color: color('text-action-hover');
69
- }
70
-
71
- i {
72
- font-size: 16px;
72
+ opacity: 0.7;
73
+ }
74
+
75
+ // union 아이콘 (X) 사용
76
+ &::before {
77
+ content: '';
78
+ display: block;
79
+ width: 24px;
80
+ height: 24px;
81
+ background-color: currentColor;
82
+ mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4.39339 4.39339C4.65143 4.13535 5.06764 4.13535 5.32568 4.39339L9 8.06771L12.6743 4.39339C12.9324 4.13535 13.3486 4.13535 13.6066 4.39339C13.8647 4.65143 13.8647 5.06764 13.6066 5.32568L9.93229 9L13.6066 12.6743C13.8647 12.9324 13.8647 13.3486 13.6066 13.6066C13.3486 13.8647 12.9324 13.8647 12.6743 13.6066L9 9.93229L5.32568 13.6066C5.06764 13.8647 4.65143 13.8647 4.39339 13.6066C4.13535 13.3486 4.13535 12.9324 4.39339 12.6743L8.06771 9L4.39339 5.32568C4.13535 5.06764 4.13535 4.65143 4.39339 4.39339Z' fill='black'/%3E%3C/svg%3E");
83
+ mask-repeat: no-repeat;
84
+ mask-position: center;
85
+ mask-size: contain;
86
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg width='18' height='18' viewBox='0 0 18 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M4.39339 4.39339C4.65143 4.13535 5.06764 4.13535 5.32568 4.39339L9 8.06771L12.6743 4.39339C12.9324 4.13535 13.3486 4.13535 13.6066 4.39339C13.8647 4.65143 13.8647 5.06764 13.6066 5.32568L9.93229 9L13.6066 12.6743C13.8647 12.9324 13.8647 13.3486 13.6066 13.6066C13.3486 13.8647 12.9324 13.8647 12.6743 13.6066L9 9.93229L5.32568 13.6066C5.06764 13.8647 4.65143 13.8647 4.39339 13.6066C4.13535 13.3486 4.13535 12.9324 4.39339 12.6743L8.06771 9L4.39339 5.32568C4.13535 5.06764 4.13535 4.65143 4.39339 4.39339Z' fill='black'/%3E%3C/svg%3E");
87
+ -webkit-mask-repeat: no-repeat;
88
+ -webkit-mask-position: center;
89
+ -webkit-mask-size: contain;
73
90
  }
74
91
  }
75
92
 
76
93
  // Long variant (horizontal layout, left border)
77
- &.toast-long {
94
+ &.long {
78
95
  .toast-content {
79
96
  flex-direction: row;
80
97
  align-items: center;
@@ -89,19 +106,20 @@
89
106
  white-space: nowrap;
90
107
  }
91
108
 
92
- &:not(.toast-border) {
109
+ &:not(.border) {
93
110
  border-top: none;
94
111
  border-left: 4px solid color('border');
95
112
  }
96
113
  }
97
114
 
98
- // Type 02 - Only full outline border (no thick colored border)
99
- &.toast-border {
100
- border: 1px solid color('border');
115
+ // Border variant - Full outline border with rounded corners
116
+ &.border {
117
+ border: 1px solid color('default-pressed');
118
+ border-radius: r(6); // 16px
119
+ padding: s(5); // 16px all sides
101
120
 
102
- &.toast-long {
103
- border: 1px solid color('border');
104
- border-top: 1px solid color('border');
121
+ &.long {
122
+ border: 1px solid color('default-pressed');
105
123
  }
106
124
  }
107
125
 
@@ -110,16 +128,21 @@
110
128
  background-color: color('info-fill');
111
129
  border-top-color: color('info');
112
130
 
113
- .toast-icon {
131
+ > i {
132
+ color: color('info');
133
+ }
134
+
135
+ .toast-header,
136
+ .toast-body {
114
137
  color: color('info');
115
138
  }
116
139
 
117
- &.toast-long:not(.toast-border) {
140
+ &.long:not(.border) {
118
141
  border-top: none;
119
142
  border-left-color: color('info');
120
143
  }
121
144
 
122
- &.toast-border {
145
+ &.border {
123
146
  border-color: color('info');
124
147
  }
125
148
  }
@@ -128,16 +151,16 @@
128
151
  background-color: color('success-fill');
129
152
  border-top-color: color('success');
130
153
 
131
- .toast-icon {
154
+ > i {
132
155
  color: color('success');
133
156
  }
134
157
 
135
- &.toast-long:not(.toast-border) {
158
+ &.long:not(.border) {
136
159
  border-top: none;
137
160
  border-left-color: color('success');
138
161
  }
139
162
 
140
- &.toast-border {
163
+ &.border {
141
164
  border-color: color('success');
142
165
  }
143
166
  }
@@ -146,16 +169,16 @@
146
169
  background-color: color('warning-fill');
147
170
  border-top-color: color('warning');
148
171
 
149
- .toast-icon {
172
+ > i {
150
173
  color: color('warning');
151
174
  }
152
175
 
153
- &.toast-long:not(.toast-border) {
176
+ &.long:not(.border) {
154
177
  border-top: none;
155
178
  border-left-color: color('warning');
156
179
  }
157
180
 
158
- &.toast-border {
181
+ &.border {
159
182
  border-color: color('warning');
160
183
  }
161
184
  }
@@ -164,16 +187,16 @@
164
187
  background-color: color('danger-fill');
165
188
  border-top-color: color('danger');
166
189
 
167
- .toast-icon {
190
+ > i {
168
191
  color: color('danger');
169
192
  }
170
193
 
171
- &.toast-long:not(.toast-border) {
194
+ &.long:not(.border) {
172
195
  border-top: none;
173
196
  border-left-color: color('danger');
174
197
  }
175
198
 
176
- &.toast-border {
199
+ &.border {
177
200
  border-color: color('danger');
178
201
  }
179
202
  }
@@ -183,16 +206,16 @@
183
206
  background-color: color('default-fill');
184
207
  border-top-color: color('default-deep');
185
208
 
186
- .toast-icon {
187
- color: color('text-action');
209
+ > i {
210
+ color: color('text-sub');
188
211
  }
189
212
 
190
- &.toast-long:not(.toast-border) {
213
+ &.long:not(.border) {
191
214
  border-top: none;
192
215
  border-left-color: color('default-deep');
193
216
  }
194
217
 
195
- &.toast-border {
218
+ &.border {
196
219
  border-color: color('default-pressed');
197
220
  }
198
221
  }
@@ -202,16 +225,21 @@
202
225
  background-color: color('primary-fill');
203
226
  border-top-color: color('primary');
204
227
 
205
- .toast-icon {
228
+ > i {
229
+ color: color('primary');
230
+ }
231
+
232
+ .toast-header,
233
+ .toast-body {
206
234
  color: color('primary');
207
235
  }
208
236
 
209
- &.toast-long:not(.toast-border) {
237
+ &.long:not(.border) {
210
238
  border-top: none;
211
239
  border-left-color: color('primary');
212
240
  }
213
241
 
214
- &.toast-border {
242
+ &.border {
215
243
  border-color: color('primary');
216
244
  }
217
245
  }