@loword/loword-design-system 0.2.2 → 0.2.3

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.
Files changed (35) hide show
  1. package/dist/components/LDDatePicker/LDDatePicker.js +1 -1
  2. package/dist/components/LDDateRangePicker/LDDateRangePicker.js +2 -2
  3. package/dist/components/LDEditor/EditorBase.d.ts.map +1 -1
  4. package/dist/components/LDEditor/EditorBase.js +25 -2
  5. package/dist/components/LDEditor/LDEditor.d.ts.map +1 -1
  6. package/dist/components/LDEditor/LDEditor.js +2 -1
  7. package/dist/components/LDFileUpload/FileUploadBase.d.ts +20 -4
  8. package/dist/components/LDFileUpload/FileUploadBase.d.ts.map +1 -1
  9. package/dist/components/LDFileUpload/FileUploadBase.js +41 -18
  10. package/dist/components/LDFileUpload/LDFileUpload.d.ts +19 -6
  11. package/dist/components/LDFileUpload/LDFileUpload.d.ts.map +1 -1
  12. package/dist/components/LDFileUpload/LDFileUpload.js +124 -28
  13. package/dist/components/LDFileUpload/LDFileUploadList.js +1 -1
  14. package/dist/components/LDInput/LDInput.d.ts +3 -1
  15. package/dist/components/LDInput/LDInput.d.ts.map +1 -1
  16. package/dist/components/LDInput/LDInput.js +10 -4
  17. package/dist/components/LDModal/LDModal.d.ts +7 -6
  18. package/dist/components/LDModal/LDModal.d.ts.map +1 -1
  19. package/dist/components/LDModal/LDModalView.d.ts +3 -3
  20. package/dist/components/LDModal/LDModalView.d.ts.map +1 -1
  21. package/dist/components/LDModal/LDModalView.js +6 -5
  22. package/dist/components/LDSelect/LDMultiSelect.js +1 -1
  23. package/dist/components/LDSelect/LDSelect.js +1 -1
  24. package/dist/components/LDTable/LDTable.js +2 -2
  25. package/dist/components/LDTextarea/LDTextarea.js +7 -7
  26. package/dist/components/LDTimePicker/LDTimePicker.js +1 -1
  27. package/dist/index.css +49 -6
  28. package/dist/index.d.ts +2 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +0 -1
  31. package/dist/utils/file.d.ts +2 -0
  32. package/dist/utils/file.d.ts.map +1 -1
  33. package/dist/utils/file.js +1 -0
  34. package/package.json +1 -1
  35. package/src/styles/components/editor.css +14 -0
@@ -102,6 +102,6 @@ const LDDatePicker = ({ variant = 'filled', color = 'neutral', value, defaultVal
102
102
  setSelectedDate(value);
103
103
  setSelectedTime(toTimeString(value));
104
104
  }, [open, value]);
105
- return (_jsx("div", { className: cn(block ? 'w-full' : 'w-auto', className), children: _jsxs(PopoverBase.Root, { open: open, onOpenChange: handleOpenChange, children: [_jsxs("div", { style: style, className: cn('relative h-9.5 w-full cursor-pointer rounded-[5px] px-4 display14', 'flex flex-row items-center justify-between gap-4', 'bold outline-2 outline-transparent ld-transition', variantColorClasses[variant][color], disabled && 'cursor-not-allowed opacity-50', triggerClassName), children: [_jsx("span", { "aria-hidden": true, className: cn('truncate', !displayDate && 'text-mono400'), children: displayDate ? formattedDate : placeholderText }), _jsx(PopoverBase.Trigger, { "aria-label": displayDate ? formattedDate : placeholderText, disabled: disabled, className: cn('absolute inset-0 rounded-[5px] outline-none', disabled ? 'cursor-not-allowed' : 'cursor-pointer') }), _jsxs("div", { className: "pointer-events-none relative flex shrink-0 items-center gap-xs", children: [showRotate && (_jsx("button", { type: "button", "aria-label": "\uCD08\uAE30\uD654", disabled: disabled, onClick: handleReset, className: "pointer-events-auto flex cursor-pointer items-center text-mono400 ld-transition disabled:cursor-not-allowed", children: _jsx(RotateCw, { size: 15 }) })), trailingIcon] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral200 bg-white p-0 shadow-md", children: _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex max-h-90 flex-row", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "single", locale: ko, selected: selectedDate, onSelect: handleSelect, disabled: isDateDisabled, colorSet: colorSet }), isExistTime && (_jsx(CalendarTimePicker, { value: selectedTime, onChange: handleSelectedTime, colorSet: colorSet, className: "shrink-0" }))] }), _jsxs("div", { className: "flex items-center justify-end gap-sm border-t border-neutral100 py-xs px-sm", children: [_jsx(LDButton, { variant: "outline", color: "neutral", onClick: handleCancel, children: "\uCDE8\uC18C" }), _jsx(LDButton, { onClick: handleConfirm, children: "\uD655\uC778" })] })] }) })] }) }));
105
+ return (_jsx("div", { className: cn(block ? 'w-full' : 'w-auto', className), children: _jsxs(PopoverBase.Root, { open: open, onOpenChange: handleOpenChange, children: [_jsxs("div", { style: style, className: cn('relative h-9.5 w-full cursor-pointer rounded-[5px] px-4 display14', 'flex flex-row items-center justify-between gap-4', 'bold outline-2 outline-transparent ld-transition', variantColorClasses[variant][color], disabled && 'cursor-not-allowed opacity-50', triggerClassName), children: [_jsx("span", { "aria-hidden": true, className: cn('truncate', !displayDate && 'text-neutral300'), children: displayDate ? formattedDate : placeholderText }), _jsx(PopoverBase.Trigger, { "aria-label": displayDate ? formattedDate : placeholderText, disabled: disabled, className: cn('absolute inset-0 rounded-[5px] outline-none', disabled ? 'cursor-not-allowed' : 'cursor-pointer') }), _jsxs("div", { className: "pointer-events-none relative flex shrink-0 items-center gap-xs", children: [showRotate && (_jsx("button", { type: "button", "aria-label": "\uCD08\uAE30\uD654", disabled: disabled, onClick: handleReset, className: "pointer-events-auto flex cursor-pointer items-center text-mono400 ld-transition disabled:cursor-not-allowed", children: _jsx(RotateCw, { size: 15 }) })), trailingIcon] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral200 bg-white p-0 shadow-md", children: _jsxs("div", { className: "flex flex-col", children: [_jsxs("div", { className: "flex max-h-90 flex-row", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "single", locale: ko, selected: selectedDate, onSelect: handleSelect, disabled: isDateDisabled, colorSet: colorSet }), isExistTime && (_jsx(CalendarTimePicker, { value: selectedTime, onChange: handleSelectedTime, colorSet: colorSet, className: "shrink-0" }))] }), _jsxs("div", { className: "flex items-center justify-end gap-sm border-t border-neutral100 py-xs px-sm", children: [_jsx(LDButton, { variant: "outline", color: "neutral", onClick: handleCancel, children: "\uCDE8\uC18C" }), _jsx(LDButton, { onClick: handleConfirm, children: "\uD655\uC778" })] })] }) })] }) }));
106
106
  };
107
107
  export default LDDatePicker;
@@ -85,10 +85,10 @@ const LDDateRangePicker = ({ variant = 'filled', value, onChange, disabled = fal
85
85
  })();
86
86
  const renderDateRange = () => {
87
87
  if (!displayRange?.from) {
88
- return (_jsx("span", { className: "whitespace-nowrap text-mono400", children: placeholderText }));
88
+ return (_jsx("span", { className: "whitespace-nowrap text-neutral300", children: placeholderText }));
89
89
  }
90
90
  if (!displayRange.to) {
91
- return (_jsxs("span", { className: "text-mono400", children: [dayjs(displayRange.from).format(displayFmt), " ~ ", placeholderFmt] }));
91
+ return (_jsxs("span", { className: "text-neutral300", children: [dayjs(displayRange.from).format(displayFmt), " ~ ", placeholderFmt] }));
92
92
  }
93
93
  return (_jsxs(_Fragment, { children: [dayjs(displayRange.from).format(displayFmt), " ~", ' ', dayjs(displayRange.to).format(displayFmt)] }));
94
94
  };
@@ -1 +1 @@
1
- {"version":3,"file":"EditorBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/EditorBase.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,MAAM,EAEX,KAAK,UAAU,EAEhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AAKf,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAID,eAAO,MAAM,gBAAgB,yBAS5B,CAAC;AAGF,UAAU,SAAS;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAwCD,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAeD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA0BD,UAAU,oBAAoB;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,SAAS,CAAC;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,SAAS,CAAC,CAAC;CACrE;AA0CD,UAAU,aAAa;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgBD,eAAO,MAAM,UAAU;oEA9JpB,SAAS;6BAoCoB,YAAY;wCAWE,YAAY;yFA2BvD,kBAAkB;sDA4BlB,oBAAoB;;mDA0C+B,aAAa;CAmBlE,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"EditorBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/EditorBase.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,MAAM,EAEX,KAAK,UAAU,EAEhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAKf,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAID,eAAO,MAAM,gBAAgB,yBAS5B,CAAC;AAGF,UAAU,SAAS;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAwCD,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAeD,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA0BD,UAAU,oBAAoB;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,SAAS,CAAC;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,KAAK,SAAS,CAAC,CAAC;CACrE;AA0ED,UAAU,aAAa;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgBD,eAAO,MAAM,UAAU;oEA9LpB,SAAS;6BAoCoB,YAAY;wCAWE,YAAY;yFA2BvD,kBAAkB;sDA4BlB,oBAAoB;;mDA0E+B,aAAa;CAmBlE,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { EditorContent, useEditor, } from '@tiptap/react';
4
- import { createContext, useContext, useEffect, useRef, useState, } from 'react';
4
+ import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState, } from 'react';
5
5
  import cn from '../../utils/cn.js';
6
6
  const EditorContext = createContext(null);
7
7
  export const useEditorContext = () => {
@@ -51,7 +51,10 @@ const ToolbarButton = ({ disabled, onClick, className, children, 'aria-label': a
51
51
  };
52
52
  const ToolbarDropdown = ({ trigger, className, children, }) => {
53
53
  const [open, setOpen] = useState(false);
54
+ // 패널 기준 위치는 트리거 왼쪽. 툴바(=에디터 폭) 오른쪽을 넘는 만큼만 왼쪽으로 밀어 넣는다.
55
+ const [shift, setShift] = useState(0);
54
56
  const ref = useRef(null);
57
+ const panelRef = useRef(null);
55
58
  const toggle = () => setOpen((prev) => !prev);
56
59
  const close = () => setOpen(false);
57
60
  useEffect(() => {
@@ -63,7 +66,27 @@ const ToolbarDropdown = ({ trigger, className, children, }) => {
63
66
  document.addEventListener('mousedown', handler);
64
67
  return () => document.removeEventListener('mousedown', handler);
65
68
  }, []);
66
- return (_jsxs("div", { ref: ref, className: "relative", children: [trigger({ open, toggle }), open && (_jsx("div", { className: cn('absolute top-full left-0 z-50 mt-1', className), children: typeof children === 'function' ? children({ close }) : children }))] }));
69
+ // paint 전에 위치를 확정해야 열리는 프레임이 튀지 않는다.
70
+ // Root가 editor 생성 전엔 children을 렌더하지 않으므로 서버에서는 실행되지 않는다.
71
+ useLayoutEffect(() => {
72
+ if (!open)
73
+ return;
74
+ const measure = () => {
75
+ const bounds = ref.current?.parentElement;
76
+ const panel = panelRef.current;
77
+ if (!ref.current || !bounds || !panel)
78
+ return;
79
+ const boundsRect = bounds.getBoundingClientRect();
80
+ const triggerRect = ref.current.getBoundingClientRect();
81
+ const overflow = triggerRect.left + panel.offsetWidth - boundsRect.right;
82
+ // 왼쪽 경계도 넘지 않도록 밀 수 있는 양을 제한한다.
83
+ setShift(Math.max(0, Math.min(overflow, triggerRect.left - boundsRect.left)));
84
+ };
85
+ measure();
86
+ window.addEventListener('resize', measure);
87
+ return () => window.removeEventListener('resize', measure);
88
+ }, [open]);
89
+ return (_jsxs("div", { ref: ref, className: "relative", children: [trigger({ open, toggle }), open && (_jsx("div", { ref: panelRef, style: { left: -shift }, className: cn('absolute top-full z-50 mt-1', className), children: typeof children === 'function' ? children({ close }) : children }))] }));
67
90
  };
68
91
  const Toolbar = Object.assign(ToolbarRoot, {
69
92
  LDButton: ToolbarButton,
@@ -1 +1 @@
1
- {"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AA4EA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAC7B,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC9B;AAED,QAAA,MAAM,QAAQ,GAAI,sDAKf,aAAa,4CAYf,CAAC;AAujBF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AA4EA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAC7B,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC9B;AAED,QAAA,MAAM,QAAQ,GAAI,sDAKf,aAAa,4CAYf,CAAC;AAyjBF,eAAe,QAAQ,CAAC"}
@@ -77,6 +77,7 @@ const EditorToolbar = ({ handleImageUpload, }) => {
77
77
  canUndo: editor.can().undo(),
78
78
  canRedo: editor.can().redo(),
79
79
  isLink: editor.isActive('link'),
80
+ hasSelection: !editor.state.selection.empty,
80
81
  };
81
82
  },
82
83
  });
@@ -148,7 +149,7 @@ const EditorToolbar = ({ handleImageUpload, }) => {
148
149
  justify: '양쪽 정렬',
149
150
  }[align];
150
151
  return (_jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().setTextAlign(align).run(), className: cn(iconBtn, state.align[align] && activeBtn), "aria-label": alignLabel, children: _jsx(Icon, { className: "size-5" }) }, align));
151
- })] })), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleBulletList().run(), className: cn(iconBtn, state.isBulletList && activeBtn), "aria-label": "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", children: _jsx(List, { className: "size-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleOrderedList().run(), className: cn(iconBtn, state.isOrderedList && activeBtn), "aria-label": "\uBC88\uD638 \uBAA9\uB85D", children: _jsx(ListOrdered, { className: "size-5" }) }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.canUndo, onClick: () => editor.chain().focus().undo().run(), className: iconBtn, "aria-label": "\uB418\uB3CC\uB9AC\uAE30", children: _jsx(Undo, { className: "size-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.canRedo, onClick: () => editor.chain().focus().redo().run(), className: iconBtn, "aria-label": "\uB2E4\uC2DC \uC2E4\uD589", children: _jsx(Redo, { className: "size-5" }) }), !isMobile && (_jsxs(_Fragment, { children: [_jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.Dropdown, { className: "min-w-70 rounded-lg border border-neutral200 bg-white p-3 shadow-lg", trigger: ({ toggle }) => (_jsx(EditorBase.Toolbar.LDButton, { onClick: () => {
152
+ })] })), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleBulletList().run(), className: cn(iconBtn, state.isBulletList && activeBtn), "aria-label": "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D", children: _jsx(List, { className: "size-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleOrderedList().run(), className: cn(iconBtn, state.isOrderedList && activeBtn), "aria-label": "\uBC88\uD638 \uBAA9\uB85D", children: _jsx(ListOrdered, { className: "size-5" }) }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.canUndo, onClick: () => editor.chain().focus().undo().run(), className: iconBtn, "aria-label": "\uB418\uB3CC\uB9AC\uAE30", children: _jsx(Undo, { className: "size-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.canRedo, onClick: () => editor.chain().focus().redo().run(), className: iconBtn, "aria-label": "\uB2E4\uC2DC \uC2E4\uD589", children: _jsx(Redo, { className: "size-5" }) }), !isMobile && (_jsxs(_Fragment, { children: [_jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.Dropdown, { className: "min-w-70 rounded-lg border border-neutral200 bg-white p-3 shadow-lg", trigger: ({ toggle }) => (_jsx(EditorBase.Toolbar.LDButton, { disabled: !state.hasSelection, onClick: () => {
152
153
  setLinkUrl(editor.getAttributes('link').href || '');
153
154
  toggle();
154
155
  }, className: cn(iconBtn, state.isLink && activeBtn), "aria-label": "\uB9C1\uD06C", children: _jsx(Link2, { className: "size-5" }) })), children: ({ close }) => {
@@ -1,6 +1,12 @@
1
1
  import { type Dispatch, type HTMLAttributes, type InputHTMLAttributes, type ReactNode, type Ref, type SetStateAction } from 'react';
2
2
  import { type TMimeType } from '../../constants/file.js';
3
3
  import { type IFile } from '../../utils/file.js';
4
+ /** 인풋마다 다르게 줄 수 있는 파일 허용 조건입니다. 생략한 항목은 Root 값을 씁니다. */
5
+ export interface FileUploadOptions {
6
+ maxSize?: number;
7
+ allowedExtensions?: TMimeType[];
8
+ maxFileCount?: number;
9
+ }
4
10
  interface FileUploadContextValue {
5
11
  recommendedSize?: {
6
12
  width: number;
@@ -9,13 +15,17 @@ interface FileUploadContextValue {
9
15
  maxSize: number;
10
16
  allowedExtensions: TMimeType[];
11
17
  fileList: IFile[];
18
+ linkList: string[];
12
19
  maxFileCount: number;
13
20
  disabled?: boolean;
14
21
  readOnly?: boolean;
15
22
  locked: boolean;
16
- addFiles: (files: File[]) => Promise<void>;
17
- replaceFile: (file: File, index: number) => Promise<void>;
23
+ addFiles: (files: File[], options?: FileUploadOptions) => Promise<void>;
24
+ replaceFile: (file: File, index: number, options?: FileUploadOptions) => Promise<void>;
18
25
  deleteFile: (index: number) => Promise<void>;
26
+ addLink: () => Promise<void>;
27
+ changeLink: (index: number, value: string) => Promise<void>;
28
+ deleteLink: (index: number) => Promise<void>;
19
29
  }
20
30
  export declare const useFileUploadContext: () => FileUploadContextValue;
21
31
  export interface FileUploadBaseRootProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onChange'> {
@@ -27,6 +37,10 @@ export interface FileUploadBaseRootProps extends Omit<HTMLAttributes<HTMLDivElem
27
37
  allowedExtensions?: TMimeType[];
28
38
  fileList: IFile[];
29
39
  setFileList: Dispatch<SetStateAction<IFile[]>>;
40
+ /** 첨부된 링크 목록입니다. `Input type="link"`·`LinkList`를 쓸 때 넘깁니다. */
41
+ linkList?: string[];
42
+ setLinkList?: Dispatch<SetStateAction<string[]>>;
43
+ onChangeLink?: (links: string[]) => void | Promise<void>;
30
44
  maxFileCount: number;
31
45
  onChangeFile: (files: IFile[]) => void | Promise<void>;
32
46
  onDeleteFile: (file: IFile) => Promise<boolean>;
@@ -37,12 +51,14 @@ export interface FileUploadBaseRootProps extends Omit<HTMLAttributes<HTMLDivElem
37
51
  }
38
52
  export interface FileUploadBaseInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'multiple' | 'onChange' | 'type'> {
39
53
  replaceIndex?: number;
54
+ /** 이 인풋에만 적용할 파일 허용 조건입니다. 생략한 항목은 Root 값을 씁니다. */
55
+ options?: FileUploadOptions;
40
56
  onChange?: InputHTMLAttributes<HTMLInputElement>['onChange'];
41
57
  ref?: Ref<HTMLInputElement>;
42
58
  }
43
59
  export declare const FileUploadBase: {
44
- Root: ({ recommendedSize, maxSize, allowedExtensions: allowedExtensionsProp, maxFileCount, fileList, setFileList, onChangeFile, onDeleteFile, disabled, readOnly, children, ref, ...props }: FileUploadBaseRootProps) => import("react/jsx-runtime").JSX.Element;
45
- Input: ({ replaceIndex, onClick, onChange, disabled, ref, ...props }: FileUploadBaseInputProps) => import("react/jsx-runtime").JSX.Element;
60
+ Root: ({ recommendedSize, maxSize, allowedExtensions: allowedExtensionsProp, maxFileCount, fileList, setFileList, linkList: linkListProp, setLinkList, onChangeLink, onChangeFile, onDeleteFile, disabled, readOnly, children, ref, ...props }: FileUploadBaseRootProps) => import("react/jsx-runtime").JSX.Element;
61
+ Input: ({ replaceIndex, options, onClick, onChange, disabled, ref, ...props }: FileUploadBaseInputProps) => import("react/jsx-runtime").JSX.Element;
46
62
  };
47
63
  export default FileUploadBase;
48
64
  //# sourceMappingURL=FileUploadBase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FileUploadBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDFileUpload/FileUploadBase.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,GAAG,EACR,KAAK,cAAc,EAEpB,MAAM,OAAO,CAAC;AAGf,OAAO,EAGL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAGL,KAAK,KAAK,EAKX,MAAM,cAAc,CAAC;AAEtB,UAAU,sBAAsB;IAC9B,eAAe,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,SAAS,EAAE,CAAC;IAC/B,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;AAID,eAAO,MAAM,oBAAoB,8BAUhC,CAAC;AAEF,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CACnD,cAAc,CAAC,cAAc,CAAC,EAC9B,UAAU,GAAG,UAAU,CACxB;IACC,eAAe,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,SAAS,EAAE,CAAC;IAChC,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,WAAW,EAAE,QAAQ,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,GAAG,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;CAC3B;AAgID,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,UAAU,GAAG,UAAU,GAAG,MAAM,CACjC;IACC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,UAAU,CAAC,CAAC;IAC7D,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAsCD,eAAO,MAAM,cAAc;iMA7JxB,uBAAuB;0EAgIvB,wBAAwB;CA6BkB,CAAC;AAE9C,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"FileUploadBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDFileUpload/FileUploadBase.tsx"],"names":[],"mappings":"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"}
@@ -12,29 +12,38 @@ export const useFileUploadContext = () => {
12
12
  }
13
13
  return context;
14
14
  };
15
- const Root = ({ recommendedSize, maxSize, allowedExtensions: allowedExtensionsProp, maxFileCount, fileList, setFileList, onChangeFile, onDeleteFile, disabled, readOnly, children, ref, ...props }) => {
15
+ const Root = ({ recommendedSize, maxSize, allowedExtensions: allowedExtensionsProp, maxFileCount, fileList, setFileList, linkList: linkListProp, setLinkList, onChangeLink, onChangeFile, onDeleteFile, disabled, readOnly, children, ref, ...props }) => {
16
16
  const allowedExtensions = allowedExtensionsProp?.length
17
17
  ? allowedExtensionsProp
18
18
  : SUPPORTED_FILE_MIME_TYPES;
19
19
  const locked = Boolean(disabled || readOnly);
20
- const validateFile = async (file) => {
21
- if (!validAllowedExtensions(file, allowedExtensions)) {
22
- const allowed = allowedExtensions
20
+ const linkList = linkListProp ?? [];
21
+ // 인풋마다 허용 조건이 다를 수 있어, Root 값 위에 인풋이 준 옵션을 덮어쓴다.
22
+ const resolveOptions = (options) => ({
23
+ maxSize: options?.maxSize ?? maxSize,
24
+ allowedExtensions: options?.allowedExtensions?.length
25
+ ? options.allowedExtensions
26
+ : allowedExtensions,
27
+ maxFileCount: options?.maxFileCount ?? maxFileCount,
28
+ });
29
+ const validateFile = async (file, resolved) => {
30
+ if (!validAllowedExtensions(file, resolved.allowedExtensions)) {
31
+ const allowed = resolved.allowedExtensions
23
32
  .map((item) => FILE_EXTENSIONS[item].toUpperCase())
24
33
  .join(', ');
25
34
  return `지원하지 않는 파일 형식입니다. ${allowed} 파일만 업로드 가능합니다.`;
26
35
  }
27
- if (!validFileSize(file, maxSize)) {
28
- return `파일 크기가 너무 큽니다. ${getFileSizeUnit(maxSize)} 이하 파일을 선택해주세요.`;
36
+ if (!validFileSize(file, resolved.maxSize)) {
37
+ return `파일 크기가 너무 큽니다. ${getFileSizeUnit(resolved.maxSize)} 이하 파일을 선택해주세요.`;
29
38
  }
30
39
  if (isImage(file.name) && !(await validImageSize(file))) {
31
40
  return '이미지 해상도가 너무 큽니다. 더 작은 크기의 이미지를 선택해주세요.';
32
41
  }
33
42
  return null;
34
43
  };
35
- const convertFiles = async (files) => {
44
+ const convertFiles = async (files, resolved) => {
36
45
  for (const file of files) {
37
- const error = await validateFile(file);
46
+ const error = await validateFile(file, resolved);
38
47
  if (error) {
39
48
  LDToast.error(error);
40
49
  return null;
@@ -50,20 +59,21 @@ const Root = ({ recommendedSize, maxSize, allowedExtensions: allowedExtensionsPr
50
59
  return null;
51
60
  }
52
61
  };
53
- const addFiles = async (files) => {
54
- if (fileList.length + files.length > maxFileCount) {
55
- LDToast.error(`최대 ${maxFileCount}개까지 업로드할 있습니다.`);
62
+ const addFiles = async (files, options) => {
63
+ const resolved = resolveOptions(options);
64
+ if (fileList.length + files.length > resolved.maxFileCount) {
65
+ LDToast.error(`최대 ${resolved.maxFileCount}개까지 업로드할 수 있습니다.`);
56
66
  return;
57
67
  }
58
- const converted = await convertFiles(files);
68
+ const converted = await convertFiles(files, resolved);
59
69
  if (!converted)
60
70
  return;
61
71
  const next = [...fileList, ...converted];
62
72
  setFileList(next);
63
73
  await onChangeFile(next);
64
74
  };
65
- const replaceFile = async (file, index) => {
66
- const [converted] = (await convertFiles([file])) ?? [];
75
+ const replaceFile = async (file, index, options) => {
76
+ const [converted] = (await convertFiles([file], resolveOptions(options))) ?? [];
67
77
  if (!converted)
68
78
  return;
69
79
  const next = fileList.map((item, itemIndex) => itemIndex === index ? converted : item);
@@ -85,11 +95,20 @@ const Root = ({ recommendedSize, maxSize, allowedExtensions: allowedExtensionsPr
85
95
  LDToast.error('파일 삭제 중 문제가 발생했습니다. 잠시후 다시 시도해주세요.');
86
96
  }
87
97
  };
98
+ // 링크는 파일이 아니라 검증·변환 대상이 아니므로 목록 갱신만 하고 onChangeLink로 알린다.
99
+ const applyLinks = async (next) => {
100
+ setLinkList?.(next);
101
+ await onChangeLink?.(next);
102
+ };
103
+ const addLink = () => applyLinks([...linkList, '']);
104
+ const changeLink = (index, value) => applyLinks(linkList.map((item, itemIndex) => (itemIndex === index ? value : item)));
105
+ const deleteLink = (index) => applyLinks(linkList.filter((_, itemIndex) => itemIndex !== index));
88
106
  return (_jsx(FileUploadContext, { value: {
89
107
  recommendedSize,
90
108
  maxSize,
91
109
  allowedExtensions,
92
110
  fileList,
111
+ linkList,
93
112
  maxFileCount,
94
113
  disabled,
95
114
  readOnly,
@@ -97,11 +116,15 @@ const Root = ({ recommendedSize, maxSize, allowedExtensions: allowedExtensionsPr
97
116
  addFiles,
98
117
  replaceFile,
99
118
  deleteFile,
119
+ addLink,
120
+ changeLink,
121
+ deleteLink,
100
122
  }, children: _jsx("div", { ref: ref, ...props, children: children }) }));
101
123
  };
102
- const Input = ({ replaceIndex, onClick, onChange, disabled, ref, ...props }) => {
124
+ const Input = ({ replaceIndex, options, onClick, onChange, disabled, ref, ...props }) => {
103
125
  const { maxFileCount, locked, addFiles, replaceFile } = useFileUploadContext();
104
- return (_jsx("input", { ref: ref, ...props, type: "file", multiple: replaceIndex === undefined && maxFileCount > 1, disabled: locked || disabled, onClick: (event) => {
126
+ const resolvedMaxFileCount = options?.maxFileCount ?? maxFileCount;
127
+ return (_jsx("input", { ref: ref, ...props, type: "file", multiple: replaceIndex === undefined && resolvedMaxFileCount > 1, disabled: locked || disabled, onClick: (event) => {
105
128
  onClick?.(event);
106
129
  if (!event.defaultPrevented)
107
130
  event.currentTarget.value = '';
@@ -113,9 +136,9 @@ const Input = ({ replaceIndex, onClick, onChange, disabled, ref, ...props }) =>
113
136
  if (!files.length)
114
137
  return;
115
138
  if (replaceIndex === undefined)
116
- await addFiles(files);
139
+ await addFiles(files, options);
117
140
  else if (files[0])
118
- await replaceFile(files[0], replaceIndex);
141
+ await replaceFile(files[0], replaceIndex, options);
119
142
  } }));
120
143
  };
121
144
  export const FileUploadBase = { Root, Input };
@@ -1,6 +1,6 @@
1
- import { type HTMLAttributes } from 'react';
1
+ import { type HTMLAttributes, type ReactNode } from 'react';
2
2
  import { type LDButtonProps } from '../../components/LDButton/LDButton.js';
3
- import { type FileUploadBaseRootProps } from '../../components/LDFileUpload/FileUploadBase.js';
3
+ import { type FileUploadBaseRootProps, type FileUploadOptions } from '../../components/LDFileUpload/FileUploadBase.js';
4
4
  export interface LDFileUploadClassNames {
5
5
  root?: string;
6
6
  input?: string;
@@ -12,23 +12,36 @@ export interface LDFileUploadRootProps extends FileUploadBaseRootProps {
12
12
  classNames?: LDFileUploadClassNames;
13
13
  }
14
14
  export interface LDFileUploadInputProps extends Omit<LDButtonProps<'button'>, 'type'> {
15
- type?: 'default' | 'image';
15
+ type?: 'default' | 'attachment' | 'image' | 'link';
16
16
  label?: string;
17
+ /** 라벨 앞 아이콘입니다. `type="default"`에서는 `leftIcon`을 씁니다. */
18
+ icon?: ReactNode;
19
+ /** 이 인풋에만 적용할 파일 허용 조건입니다. 생략한 항목은 Root 값을 씁니다. */
20
+ options?: FileUploadOptions;
17
21
  }
18
22
  export interface LDFileUploadCardListProps {
19
23
  type?: 'default' | 'image';
24
+ /** 카드에 업로드 시각 라벨을 표시합니다. `uploadedAt`이 있는 파일만 표시됩니다. */
25
+ isExistUploadedAt?: boolean;
26
+ className?: string;
27
+ }
28
+ export interface LDFileUploadLinkListProps {
29
+ placeholder?: string;
20
30
  className?: string;
21
31
  }
22
32
  export type LDFileUploadDescriptionProps = HTMLAttributes<HTMLParagraphElement>;
23
33
  export interface LDFileUploadProps extends Omit<LDFileUploadRootProps, 'children' | 'classNames' | 'maxFileCount'> {
24
34
  isExistDescription?: boolean;
35
+ /** 카드에 업로드 시각 라벨을 표시합니다. */
36
+ isExistUploadedAt?: boolean;
25
37
  }
26
38
  /** 한 개의 일반 파일을 업로드하는 기본 조합입니다. */
27
39
  declare const LDFileUpload: {
28
- ({ recommendedSize, isExistDescription, fileList, ...props }: LDFileUploadProps): import("react/jsx-runtime").JSX.Element;
40
+ ({ recommendedSize, isExistDescription, isExistUploadedAt, fileList, ...props }: LDFileUploadProps): import("react/jsx-runtime").JSX.Element;
29
41
  Root: ({ className, classNames, children, ...props }: LDFileUploadRootProps) => import("react/jsx-runtime").JSX.Element;
30
- Input: ({ type, label, className, ...props }: LDFileUploadInputProps) => import("react/jsx-runtime").JSX.Element | null;
31
- CardList: ({ type, className, }: LDFileUploadCardListProps) => import("react/jsx-runtime").JSX.Element;
42
+ Input: ({ type, label, icon, options, className, ...props }: LDFileUploadInputProps) => import("react/jsx-runtime").JSX.Element | null;
43
+ CardList: ({ type, isExistUploadedAt, className, }: LDFileUploadCardListProps) => import("react/jsx-runtime").JSX.Element;
44
+ LinkList: ({ placeholder, className, }: LDFileUploadLinkListProps) => import("react/jsx-runtime").JSX.Element;
32
45
  Description: ({ className, ...props }: LDFileUploadDescriptionProps) => import("react/jsx-runtime").JSX.Element;
33
46
  };
34
47
  export default LDFileUpload;
@@ -1 +1 @@
1
- {"version":3,"file":"LDFileUpload.d.ts","sourceRoot":"","sources":["../../../src/components/LDFileUpload/LDFileUpload.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,cAAc,EAAc,MAAM,OAAO,CAAC;AAEvE,OAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE9E,OAAuB,EACrB,KAAK,uBAAuB,EAE7B,MAAM,0CAA0C,CAAC;AAMlD,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE,UAAU,CAAC,EAAE,sBAAsB,CAAC;CACrC;AAuBD,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,aAAa,CAAC,QAAQ,CAAC,EACvB,MAAM,CACP;IACC,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmDD,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmJD,MAAM,MAAM,4BAA4B,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;AA8BhF,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,qBAAqB,EACrB,UAAU,GAAG,YAAY,GAAG,cAAc,CAC3C;IACC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,kCAAkC;AAClC,QAAA,MAAM,YAAY;kEAKf,iBAAiB;0DAzQjB,qBAAqB;kDA6BrB,sBAAsB;qCAoDtB,yBAAyB;2CAgJkB,4BAA4B;CAkDzE,CAAC;AAOF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"LDFileUpload.d.ts","sourceRoot":"","sources":["../../../src/components/LDFileUpload/LDFileUpload.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAEf,OAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE9E,OAAuB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EAEvB,MAAM,0CAA0C,CAAC;AAqFlD,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE,UAAU,CAAC,EAAE,sBAAsB,CAAC;CACrC;AAuBD,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,aAAa,CAAC,QAAQ,CAAC,EACvB,MAAM,CACP;IACC,IAAI,CAAC,EAAE,SAAS,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,mDAAmD;IACnD,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AA6FD,MAAM,WAAW,yBAAyB;IACxC,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6HD,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwDD,MAAM,MAAM,4BAA4B,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;AA6BhF,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,qBAAqB,EACrB,UAAU,GAAG,YAAY,GAAG,cAAc,CAC3C;IACC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,kCAAkC;AAClC,QAAA,MAAM,YAAY;qFAMf,iBAAiB;0DAhWjB,qBAAqB;iEAmCrB,sBAAsB;wDA+FtB,yBAAyB;4CA+HzB,yBAAyB;2CAqDkB,4BAA4B;CAwDzE,CAAC;AAQF,eAAe,YAAY,CAAC"}
@@ -1,76 +1,172 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Images, Trash2 } from 'lucide-react';
4
- import { createContext, useContext } from 'react';
3
+ import dayjs from 'dayjs';
4
+ import { Images, Link2, Paperclip, Plus, Trash2, X } from 'lucide-react';
5
+ import { createContext, useContext, } from 'react';
5
6
  import LDButton from '../../components/LDButton/LDButton.js';
6
7
  import LDCarousel from '../../components/LDCarousel/LDCarousel.js';
7
8
  import FileUploadBase, { useFileUploadContext, } from '../../components/LDFileUpload/FileUploadBase.js';
9
+ import InputBase from '../../components/LDInput/InputBase.js';
8
10
  import RenderIcon from '../../components/RenderIcon/RenderIcon.js';
11
+ import Show from '../../components/Show/Show.js';
9
12
  import { FILE_EXTENSIONS } from '../../constants/file.js';
10
13
  import cn from '../../utils/cn.js';
11
- import { getFileIcon, getFileSizeUnit, isImage } from '../../utils/file.js';
14
+ import { getFileSizeUnit } from '../../utils/file.js';
15
+ import tv from '../../utils/tv.js';
16
+ // disabled·readOnly·기본 상태의 커서는 서로 배타적이다. cursor-not-allowed 는 hover:cursor-pointer 와
17
+ // tailwind-merge 상 다른 그룹이어서 축만으로는 지워지지 않으므로, 겹치지 않게 compound 로 갈라 놓는다.
18
+ const cursorVariants = {
19
+ disabled: { true: 'cursor-not-allowed', false: '' },
20
+ readOnly: { true: '', false: '' },
21
+ };
22
+ const cursorCompounds = [
23
+ { disabled: false, readOnly: true, className: 'cursor-default' },
24
+ { disabled: false, readOnly: false, className: 'hover:cursor-pointer' },
25
+ ];
26
+ const attachInputVariants = tv({
27
+ base: 'flex w-full flex-row items-center gap-sm rounded-[10px] bg-neutral50 p-5 display16 bold text-neutral700 ld-transition',
28
+ variants: {
29
+ disabled: {
30
+ true: 'cursor-not-allowed opacity-50',
31
+ false: 'hover:cursor-pointer hover:bg-neutral100',
32
+ },
33
+ },
34
+ });
35
+ const imageInputVariants = tv({
36
+ base: 'flex size-21 items-center justify-center rounded-xl bg-neutral50 text-neutral500 outline-3 -outline-offset-3 outline-neutral100 outline-dotted ld-transition',
37
+ variants: {
38
+ disabled: {
39
+ true: 'cursor-not-allowed opacity-50',
40
+ false: 'hover:cursor-pointer hover:bg-neutral-100 hover:text-neutral600 hover:outline-neutral200',
41
+ },
42
+ },
43
+ });
44
+ const imageCardVariants = tv({
45
+ base: 'group relative block size-21 overflow-hidden rounded-xl outline-3 -outline-offset-3 outline-neutral200',
46
+ variants: cursorVariants,
47
+ compoundVariants: cursorCompounds,
48
+ });
49
+ const imageCardOverlayVariants = tv({
50
+ base: 'pointer-events-none absolute inset-0 opacity-0 ld-transition',
51
+ variants: { locked: { false: 'bg-black/25 group-hover:opacity-100' } },
52
+ });
53
+ const imageCardDeleteVariants = tv({
54
+ base: 'absolute top-2 right-2 flex size-5 min-w-0 items-center justify-center rounded-sm bg-neutral-100 px-0 text-neutral700 opacity-0 ld-transition',
55
+ variants: { locked: { false: 'group-hover:opacity-100' } },
56
+ });
57
+ const cardVariants = tv({
58
+ base: 'flex w-full flex-row items-center justify-between gap-md rounded-[10px] bg-tintBlue p-5',
59
+ variants: cursorVariants,
60
+ compoundVariants: cursorCompounds,
61
+ });
62
+ const cardDeleteVariants = tv({
63
+ base: 'flex size-4.5 min-w-0 items-center justify-center px-0 text-lb500 ld-transition',
64
+ variants: { locked: { true: 'pointer-events-none opacity-0' } },
65
+ });
66
+ // 링크 카드는 파일 카드와 같은 규격(bg-tintBlue·p-5·rounded-[10px])을 쓰되, 안쪽이 실제 input이라
67
+ // 스타일 박스가 래퍼로 올라가고 focus는 내부 input에 가므로 LDInput처럼 focus-within으로 반응한다.
68
+ const linkCardVariants = tv({
69
+ base: 'flex w-full flex-row items-center gap-sm rounded-[10px] bg-tintBlue p-5 outline-2 -outline-offset-2 outline-transparent outline-solid ld-transition focus-within:outline-lb500',
70
+ variants: {
71
+ disabled: { true: 'cursor-not-allowed opacity-50', false: '' },
72
+ },
73
+ });
74
+ const linkFieldVariants = tv({
75
+ base: 'ld-input-field -my-2 h-full w-full min-w-0 border-0 bg-transparent px-0 py-2 display16 bold text-lb500 placeholder-lb300 outline-none read-only:cursor-not-allowed',
76
+ variants: {
77
+ disabled: { true: 'cursor-not-allowed', false: '' },
78
+ },
79
+ });
12
80
  const StyleContext = createContext({});
13
81
  /** 파일 업로드의 상태와 Styled 파트를 연결하는 루트입니다. */
14
82
  const Root = ({ className, classNames = {}, children, ...props }) => (_jsx(StyleContext, { value: classNames, children: _jsx(FileUploadBase.Root, { ...props, className: cn('flex w-full flex-col gap-sm ld-transition', className, classNames.root), children: children }) }));
15
83
  /** 새 파일을 선택하는 입력입니다. */
16
- const Input = ({ type = 'default', label = '파일 선택', className, ...props }) => {
17
- const { disabled, readOnly } = useFileUploadContext();
84
+ const Input = ({ type = 'default', label, icon, options, className, ...props }) => {
85
+ const { disabled, readOnly, addLink } = useFileUploadContext();
18
86
  const classNames = useContext(StyleContext);
19
87
  if (readOnly)
20
88
  return null;
21
- const fileInput = (_jsx(FileUploadBase.Input, { "aria-label": label, className: "sr-only" }));
89
+ const resolvedLabel = label ??
90
+ {
91
+ attachment: '파일 첨부하기',
92
+ link: '링크 첨부하기',
93
+ default: '파일 선택',
94
+ }[type === 'image' ? 'default' : type];
95
+ const fileInput = (_jsx(FileUploadBase.Input, { options: options, "aria-label": resolvedLabel, className: "sr-only" }));
96
+ // 링크는 파일 선택 대화창이 아니라 빈 입력 행을 추가하는 버튼이라 file input을 두지 않는다.
97
+ if (type === 'link') {
98
+ return (_jsxs("button", { type: "button", onClick: addLink, disabled: disabled, className: attachInputVariants({
99
+ disabled: !!disabled,
100
+ className: cn(className, classNames.input),
101
+ }), children: [_jsx(RenderIcon, { className: "size-5", children: icon ?? _jsx(Link2, {}) }), resolvedLabel] }));
102
+ }
103
+ if (type === 'attachment') {
104
+ return (_jsxs("label", { className: attachInputVariants({
105
+ disabled: !!disabled,
106
+ className: cn(className, classNames.input),
107
+ }), children: [_jsx(RenderIcon, { className: "size-5", children: icon ?? _jsx(Plus, {}) }), resolvedLabel, fileInput] }));
108
+ }
22
109
  if (type === 'image') {
23
- return (_jsxs("label", { className: cn('flex size-21 items-center justify-center rounded-xl bg-neutral50 text-neutral500 outline-3 -outline-offset-3 outline-neutral100 outline-dotted ld-transition', disabled
24
- ? 'cursor-not-allowed opacity-50'
25
- : 'hover:cursor-pointer hover:bg-neutral-100 hover:text-neutral600 hover:outline-neutral200', className, classNames.input), children: [_jsx(RenderIcon, { className: "size-6", children: _jsx(Images, {}) }), fileInput] }));
110
+ return (_jsxs("label", { className: imageInputVariants({
111
+ // 미지정도 false 분기(hover)를 타야 하므로 boolean으로 좁혀 넘긴다.
112
+ disabled: !!disabled,
113
+ className: cn(className, classNames.input),
114
+ }), children: [_jsx(RenderIcon, { className: "size-6", children: icon ?? _jsx(Images, {}) }), fileInput] }));
26
115
  }
27
- return (_jsxs(LDButton, { as: "label", ...props, className: cn(className, classNames.input), disabled: disabled, children: [label, fileInput] }));
116
+ return (_jsxs(LDButton, { as: "label", ...props, className: cn(className, classNames.input), disabled: disabled, children: [resolvedLabel, fileInput] }));
28
117
  };
29
118
  /** 선택된 파일을 교체하거나 삭제할 수 있는 목록입니다. */
30
- const CardList = ({ type = 'default', className, }) => {
119
+ const CardList = ({ type = 'default', isExistUploadedAt = true, className, }) => {
31
120
  const { fileList, disabled, readOnly, locked, deleteFile } = useFileUploadContext();
32
121
  const classNames = useContext(StyleContext);
33
122
  if (type === 'image') {
34
- const cards = fileList.map((file, index) => (_jsxs("label", { className: cn('group relative block size-21 overflow-hidden rounded-[21px] outline-3 -outline-offset-3 outline-neutral200', disabled
35
- ? 'cursor-not-allowed'
36
- : readOnly
37
- ? 'cursor-default'
38
- : 'hover:cursor-pointer', classNames.card), children: [_jsx("img", { src: file.src, alt: file.fileName, className: "size-full object-cover" }), _jsx("span", { className: cn('pointer-events-none absolute inset-0 opacity-0 ld-transition', !locked && 'bg-black/25 group-hover:opacity-100') }), _jsx(FileUploadBase.Input, { replaceIndex: index, "aria-label": `${file.fileName} 교체`, className: "sr-only" }), _jsx(LDButton, { onClick: async (event) => {
123
+ const cards = fileList.map((file, index) => (_jsxs("label", { className: imageCardVariants({
124
+ disabled: !!disabled,
125
+ readOnly: !!readOnly,
126
+ className: classNames.card,
127
+ }), children: [_jsx("img", { src: file.src, alt: file.fileName, className: "size-full object-cover" }), _jsx("span", { className: imageCardOverlayVariants({ locked }) }), _jsx(FileUploadBase.Input, { replaceIndex: index, "aria-label": `${file.fileName} 교체`, className: "sr-only" }), _jsx(LDButton, { onClick: async (event) => {
39
128
  event.preventDefault();
40
129
  event.stopPropagation();
41
130
  await deleteFile(index);
42
- }, disabled: locked, variant: "ghost", leftIcon: _jsx(Trash2, {}), color: "neutral", className: cn('absolute top-2 right-2 flex size-5 min-w-0 items-center justify-center rounded-sm bg-neutral-100 px-0 text-neutral700 opacity-0 ld-transition', !locked && 'group-hover:opacity-100') })] }, `${file.fileName}_${index}`)));
131
+ }, disabled: locked, variant: "ghost", leftIcon: _jsx(Trash2, {}), color: "neutral", className: imageCardDeleteVariants({ locked }) })] }, `${file.fileName}_${index}`)));
43
132
  if (fileList.length <= 1) {
44
133
  return (_jsx("div", { className: cn('flex flex-row gap-sm', className, classNames.cardList), children: cards }));
45
134
  }
46
135
  return (_jsx(LDCarousel, { className: cn(className, classNames.cardList), slidesPerView: "auto", gap: 8, arrowPosition: "none", showDots: false, slides: cards }));
47
136
  }
48
- return (_jsx("div", { className: cn('flex w-full flex-col gap-sm', className, classNames.cardList), children: fileList.map((file, index) => (_jsxs("label", { className: cn('flex w-full flex-row items-center justify-between rounded-lg bg-neutral50 px-4 py-3', disabled
49
- ? 'cursor-not-allowed'
50
- : readOnly
51
- ? 'cursor-default'
52
- : 'hover:cursor-pointer', classNames.card), children: [_jsxs("div", { className: "flex flex-row items-center gap-sm", children: [_jsx("div", { className: "size-15 overflow-hidden rounded-lg", children: _jsx("div", { className: "flex size-full items-center justify-center bg-white text-neutral500", children: isImage(file.fileName) ? (_jsx("img", { src: file.src, alt: file.fileName, className: "size-full object-cover" })) : (_jsx(RenderIcon, { className: "size-8", children: getFileIcon(file.fileName) })) }) }), _jsx("div", { className: "display16 text-neutral700", children: file.fileName })] }), _jsx(FileUploadBase.Input, { replaceIndex: index, "aria-label": `${file.fileName} 교체`, className: "sr-only" }), _jsx(LDButton, { onClick: async (event) => {
137
+ return (_jsx("div", { className: cn('flex w-full flex-col gap-sm', className, classNames.cardList), children: fileList.map((file, index) => (_jsxs("label", { className: cardVariants({
138
+ disabled: !!disabled,
139
+ readOnly: !!readOnly,
140
+ className: classNames.card,
141
+ }), children: [_jsxs("div", { className: "flex flex-row items-center gap-sm", children: [_jsx(RenderIcon, { className: "size-5 text-lb500", children: _jsx(Paperclip, {}) }), _jsxs("div", { className: "flex items-center justify-center gap-sm mobile:flex-col mobile:items-start mobile:gap-2xs", children: [_jsx("span", { className: "display16 bold text-lb500", children: file.fileName }), _jsx(Show, { when: isExistUploadedAt && file.uploadedAt, children: (uploadedAt) => (_jsxs("span", { className: "rounded-[5px] bg-blue200 px-1.5 py-0.75 display10 medium text-white", children: [dayjs(uploadedAt).format('YYYY-MM-DD HH:mm'), " \uB9C8\uC9C0\uB9C9 \uC5C5\uB85C\uB4DC"] })) })] })] }), _jsx(FileUploadBase.Input, { replaceIndex: index, "aria-label": `${file.fileName} 교체`, className: "sr-only" }), _jsx(LDButton, { onClick: async (event) => {
53
142
  event.preventDefault();
54
143
  event.stopPropagation();
55
144
  await deleteFile(index);
56
- }, disabled: locked, variant: "ghost", leftIcon: _jsx(Trash2, {}), size: "large", color: "neutral", className: cn('flex size-10 min-w-0 items-center justify-center rounded-sm bg-white px-0 text-neutral500 ld-transition', locked && 'pointer-events-none opacity-0') })] }, `${file.fileName}_${index}`))) }));
145
+ }, disabled: locked, variant: "ghost", leftIcon: _jsx(X, { className: "size-4.5" }), color: "neutral", className: cardDeleteVariants({ locked }) })] }, `${file.fileName}_${index}`))) }));
146
+ };
147
+ /** 첨부된 링크를 실시간으로 편집하거나 삭제할 수 있는 목록입니다. */
148
+ const LinkList = ({ placeholder = '링크를 입력해주세요', className, }) => {
149
+ const { linkList, disabled, readOnly, locked, changeLink, deleteLink } = useFileUploadContext();
150
+ const classNames = useContext(StyleContext);
151
+ return (_jsx("div", { className: cn('flex w-full flex-col gap-sm', className, classNames.cardList), children: linkList.map((link, index) => (_jsxs(InputBase.Root, { block: true, className: linkCardVariants({
152
+ disabled: !!disabled,
153
+ className: classNames.card,
154
+ }), children: [_jsx(RenderIcon, { className: "size-5 shrink-0 text-lb500", children: _jsx(Link2, {}) }), _jsx(InputBase.Field, { type: "url", value: link, placeholder: placeholder, "aria-label": `링크 ${index + 1}`, disabled: disabled, readOnly: readOnly, onChange: (event) => changeLink(index, event.target.value), className: linkFieldVariants({ disabled: !!disabled }) }), _jsx(LDButton, { onClick: () => deleteLink(index), "aria-label": `링크 ${index + 1} 삭제`, disabled: locked, variant: "ghost", leftIcon: _jsx(X, { className: "size-4.5" }), color: "neutral", className: cardDeleteVariants({ locked }) })] }, index))) }));
57
155
  };
58
156
  /** 업로드 제한 조건을 안내합니다. */
59
157
  const Description = ({ className, ...props }) => {
60
158
  const { recommendedSize, maxSize, allowedExtensions, maxFileCount } = useFileUploadContext();
61
159
  const classNames = useContext(StyleContext);
62
- const recommendedSizeText = recommendedSize
63
- ? `권장 사이즈 ${recommendedSize.width}x${recommendedSize.height}, `
64
- : '';
65
160
  const extensionsText = allowedExtensions
66
161
  .map((item) => FILE_EXTENSIONS[item])
67
162
  .join(', ');
68
- return (_jsxs("p", { ...props, className: cn('display12 semibold text-neutral400', className, classNames.description), children: [recommendedSizeText, "\uCD5C\uB300 \uD06C\uAE30 ", getFileSizeUnit(maxSize), " (", extensionsText, ")", maxFileCount > 1 && `, 최대 ${maxFileCount}개`] }));
163
+ return (_jsxs("p", { ...props, className: cn('display12 semibold text-neutral400', className, classNames.description), children: [_jsx(Show, { when: recommendedSize, children: ({ width, height }) => `권장 사이즈 ${width}x${height}, ` }), "\uCD5C\uB300 \uD06C\uAE30 ", getFileSizeUnit(maxSize), " (", extensionsText, ")", _jsx(Show, { when: maxFileCount > 1, children: `, 최대 ${maxFileCount}개` })] }));
69
164
  };
70
165
  /** 한 개의 일반 파일을 업로드하는 기본 조합입니다. */
71
- const LDFileUpload = ({ recommendedSize = { width: 1200, height: 800 }, isExistDescription, fileList, ...props }) => (_jsxs(Root, { ...props, fileList: fileList, recommendedSize: recommendedSize, maxFileCount: 1, children: [fileList[0]?.src ? _jsx(CardList, {}) : _jsx(Input, { className: "w-fit" }), isExistDescription && _jsx(Description, {})] }));
166
+ const LDFileUpload = ({ recommendedSize = { width: 1200, height: 800 }, isExistDescription, isExistUploadedAt, fileList, ...props }) => (_jsxs(Root, { ...props, fileList: fileList, recommendedSize: recommendedSize, maxFileCount: 1, children: [_jsx(Show, { when: fileList[0]?.src, fallback: _jsx(Input, { className: "w-fit" }), children: _jsx(CardList, { isExistUploadedAt: isExistUploadedAt }) }), _jsx(Show, { when: isExistDescription, children: _jsx(Description, {}) })] }));
72
167
  LDFileUpload.Root = Root;
73
168
  LDFileUpload.Input = Input;
74
169
  LDFileUpload.CardList = CardList;
170
+ LDFileUpload.LinkList = LinkList;
75
171
  LDFileUpload.Description = Description;
76
172
  export default LDFileUpload;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import LDFileUpload from '../../components/LDFileUpload/LDFileUpload.js';
3
3
  /** 여러 개의 일반 파일을 업로드하는 기본 조합입니다. */
4
- const LDFileUploadList = ({ recommendedSize = { width: 1200, height: 800 }, isExistDescription, fileList, maxFileCount, disabled, ...props }) => (_jsxs(LDFileUpload.Root, { ...props, fileList: fileList, recommendedSize: recommendedSize, maxFileCount: maxFileCount, disabled: disabled, children: [fileList.length < maxFileCount && !disabled && (_jsx(LDFileUpload.Input, { className: "w-fit" })), isExistDescription && _jsx(LDFileUpload.Description, {}), fileList.length > 0 && _jsx(LDFileUpload.CardList, {})] }));
4
+ const LDFileUploadList = ({ recommendedSize = { width: 1200, height: 800 }, isExistDescription, fileList, maxFileCount, disabled, ...props }) => (_jsxs(LDFileUpload.Root, { ...props, fileList: fileList, recommendedSize: recommendedSize, maxFileCount: maxFileCount, disabled: disabled, children: [fileList.length > 0 && _jsx(LDFileUpload.CardList, {}), fileList.length < maxFileCount && !disabled && (_jsx(LDFileUpload.Input, { type: "attachment" })), isExistDescription && _jsx(LDFileUpload.Description, {})] }));
5
5
  export default LDFileUploadList;
@@ -19,6 +19,8 @@ export interface LDInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>
19
19
  block?: boolean;
20
20
  /** 래퍼(Root div)에 적용할 className */
21
21
  rootClassName?: string;
22
+ /** 좌측 부가 요소 (아이콘 등) */
23
+ leftAddon?: ReactNode;
22
24
  /** 우측 부가 요소 (아이콘 등) */
23
25
  rightAddon?: ReactNode;
24
26
  /** 우측 addon 컨테이너 ref (addon 폭·위치 측정용) */
@@ -28,6 +30,6 @@ export interface LDInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>
28
30
  /** input 요소 ref */
29
31
  ref?: Ref<HTMLInputElement>;
30
32
  }
31
- declare const LDInput: ({ variant, color, size, block, type, disabled, className, rootClassName, style, rightAddon, addonRef, suffix, hiddenPasswordToggle, ref, value, defaultValue, onChange, ...props }: LDInputProps) => import("react/jsx-runtime").JSX.Element;
33
+ declare const LDInput: ({ variant, color, size, block, type, disabled, className, rootClassName, style, leftAddon, rightAddon, addonRef, suffix, hiddenPasswordToggle, ref, value, defaultValue, onChange, ...props }: LDInputProps) => import("react/jsx-runtime").JSX.Element;
32
34
  export default LDInput;
33
35
  //# sourceMappingURL=LDInput.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LDInput.d.ts","sourceRoot":"","sources":["../../../src/components/LDInput/LDInput.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,GAAG,EAIT,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAK7C,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;AAC3E,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,MAAM,CAC5B,IAAI,EACJ,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAC/D,CAAC;AAKF,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAOvD,CAAC;AAIF,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAO/C,CAAC;AAqKF,MAAM,WAAW,YAAa,SAAQ,IAAI,CACxC,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,OAAO,GAAG,MAAM,CACjB;IACC,mBAAmB;IACnB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,YAAY;IACZ,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,uBAAuB;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uBAAuB;IACvB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,GAAG,CAAC,eAAe,CAAC,CAAC;IAChC,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB;IACnB,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAED,QAAA,MAAM,OAAO,GAAI,oLAmBd,YAAY,4CAoKd,CAAC;AAEF,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"LDInput.d.ts","sourceRoot":"","sources":["../../../src/components/LDInput/LDInput.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,GAAG,EAIT,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAK7C,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;AAC3E,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,MAAM,CAC5B,IAAI,EACJ,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAC/D,CAAC;AAKF,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAOvD,CAAC;AAIF,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAO/C,CAAC;AAqKF,MAAM,WAAW,YAAa,SAAQ,IAAI,CACxC,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,OAAO,GAAG,MAAM,CACjB;IACC,mBAAmB;IACnB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,YAAY;IACZ,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,uBAAuB;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kCAAkC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uBAAuB;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,uBAAuB;IACvB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,GAAG,CAAC,eAAe,CAAC,CAAC;IAChC,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB;IACnB,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAED,QAAA,MAAM,OAAO,GAAI,+LAoBd,YAAY,4CAqLd,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -172,13 +172,14 @@ const passwordToggleVariants = tv({
172
172
  disabled: { true: 'cursor-not-allowed', false: 'cursor-pointer' },
173
173
  },
174
174
  });
175
- const LDInput = ({ variant, color = 'neutral', size, block = false, type = 'text', disabled = false, className, rootClassName, style, rightAddon, addonRef, suffix, hiddenPasswordToggle = false, ref, value, defaultValue, onChange, ...props }) => {
175
+ const LDInput = ({ variant, color = 'neutral', size, block = false, type = 'text', disabled = false, className, rootClassName, style, leftAddon, rightAddon, addonRef, suffix, hiddenPasswordToggle = false, ref, value, defaultValue, onChange, ...props }) => {
176
176
  const [passwordVisible, setPasswordVisible] = useState(false);
177
177
  const [inputValue, setInputValue] = useState(() => String(value ?? defaultValue ?? ''));
178
178
  const [suffixLeft, setSuffixLeft] = useState(0); // suffix의 최종 left 위치(px)
179
179
  const valueRef = useRef(null); // 값 폭 측정용 숨은 span
180
180
  const suffixRef = useRef(null); // suffix 자체 폭 측정용
181
181
  const rootRef = useRef(null); // Root 래퍼(패딩·폭 측정용, suffix 위치 계산)
182
+ const leftAddonRef = useRef(null); // 좌측 addon 폭 측정용(suffix 위치 보정)
182
183
  const isPasswordToggle = !hiddenPasswordToggle && type === 'password';
183
184
  const resolvedType = isPasswordToggle
184
185
  ? passwordVisible
@@ -206,11 +207,16 @@ const LDInput = ({ variant, color = 'neutral', size, block = false, type = 'text
206
207
  const cs = getComputedStyle(root);
207
208
  const padLeft = parseFloat(cs.paddingLeft) || 0; // "12px" → 12
208
209
  const padRight = parseFloat(cs.paddingRight) || 0;
210
+ // leftAddon이 있으면 input 시작점이 addon 폭 + gap만큼 밀린다. suffix도 같이 밀어야 값 뒤에 붙는다.
211
+ const leftAddonEl = leftAddonRef.current;
212
+ const leftOffset = leftAddonEl
213
+ ? leftAddonEl.offsetWidth + (parseFloat(cs.columnGap) || 0)
214
+ : 0;
209
215
  // 값 뒤에 붙이되, suffix 오른끝이 Root 안쪽 오른 경계를 넘지 않게 clamp.
210
216
  // clientWidth = content+padding (border 제외) → 안쪽 폭
211
217
  const maxLeft = root.clientWidth - padRight - suffixWidth;
212
- setSuffixLeft(Math.min(padLeft + valueWidth + SUFFIX_GAP, maxLeft));
213
- }, [displayedValue, resolvedSize, suffix]);
218
+ setSuffixLeft(Math.min(padLeft + leftOffset + valueWidth + SUFFIX_GAP, maxLeft));
219
+ }, [displayedValue, resolvedSize, suffix, leftAddon]);
214
220
  const passwordToggleAddon = isPasswordToggle ? (_jsxs("button", { type: "button", "aria-label": passwordVisible ? '비밀번호 숨기기' : '비밀번호 표시', "aria-pressed": passwordVisible, onClick: () => setPasswordVisible(!passwordVisible), disabled: disabled, style: { width: iconSize, height: iconSize }, className: passwordToggleVariants({ disabled }), children: [_jsx(Eye, { size: iconSize, className: cn('absolute top-1/2 left-1/2 -translate-1/2 ld-transition', passwordVisible ? 'opacity-100' : 'opacity-0') }), _jsx(EyeOff, { size: iconSize, className: cn('absolute top-1/2 left-1/2 -translate-1/2 ld-transition', passwordVisible ? 'opacity-0' : 'opacity-100') })] })) : null;
215
221
  const { width, height, minWidth, maxWidth, minHeight, maxHeight, ...fieldStyle } = style ?? {};
216
222
  // 텍스트 - addon 간격(gap)은 inline으로 부여(패딩의 절반).
@@ -236,7 +242,7 @@ const LDInput = ({ variant, color = 'neutral', size, block = false, type = 'text
236
242
  const hasAddon = Boolean(rightAddon) || Boolean(passwordToggleAddon);
237
243
  // label 없이 쓰일 수 있어 접근 가능한 이름을 placeholder/name으로 폴백한다.
238
244
  const ariaLabel = props['aria-label'] ?? props.placeholder ?? props.name;
239
- return (_jsxs(InputBase.Root, { ref: rootRef, block: block, style: rootStyle, className: rootClass, children: [_jsx(InputBase.Field, { ref: ref, type: resolvedType, disabled: disabled, className: fieldClassName, style: fieldStyle, value: value, defaultValue: defaultValue, onChange: (event) => {
245
+ return (_jsxs(InputBase.Root, { ref: rootRef, block: block, style: rootStyle, className: rootClass, children: [leftAddon && (_jsx(InputBase.Addon, { ref: leftAddonRef, style: { gap: addonGap }, className: addonVariants({ size: resolvedSize }), children: leftAddon })), _jsx(InputBase.Field, { ref: ref, type: resolvedType, disabled: disabled, className: fieldClassName, style: fieldStyle, value: value, defaultValue: defaultValue, onChange: (event) => {
240
246
  setInputValue(event.target.value);
241
247
  onChange?.(event);
242
248
  }, ...props, "aria-label": ariaLabel }), suffix && displayedValue && (_jsxs(_Fragment, { children: [_jsx("span", { ref: valueRef, "aria-hidden": "true", className: suffixMeasureVariants({ size: resolvedSize }), children: displayedValue }), _jsx("span", { ref: suffixRef, "aria-hidden": "true", className: suffixVariants({ size: resolvedSize }), style: { left: `${suffixLeft}px` }, children: suffix })] })), hasAddon && (_jsxs(InputBase.Addon, { ref: addonRef, style: { gap: addonGap }, className: addonVariants({ size: resolvedSize }), children: [rightAddon, passwordToggleAddon] }))] }));
@@ -1,13 +1,14 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
1
2
  import { type ModalSize, TModalClassNames } from '../../components/LDModal/LDModalView.js';
2
3
  import type { Variant } from '../../types/common.js';
3
4
  import type { Subset } from '../../types/subset.js';
4
5
  export interface LDModalOptions<T = undefined> {
5
- name?: string;
6
- title?: string;
7
- description?: string;
8
- content?: React.ReactNode | ((args: {
6
+ name?: ReactNode;
7
+ title?: ReactNode;
8
+ description?: ReactNode;
9
+ content?: ReactNode | ((args: {
9
10
  onClose: (value?: T) => void;
10
- }) => React.ReactNode);
11
+ }) => ReactNode);
11
12
  buttons?: {
12
13
  value: T;
13
14
  label: string;
@@ -24,7 +25,7 @@ export interface LDModalOptions<T = undefined> {
24
25
  /** 모달 패널에 적용할 추가 CSS 클래스 */
25
26
  className?: string;
26
27
  /** 모달 패널 인라인 스타일 (자유 width/height 등) */
27
- style?: React.CSSProperties;
28
+ style?: CSSProperties;
28
29
  onBeforeClose?: () => Promise<boolean> | boolean;
29
30
  classNames?: TModalClassNames;
30
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LDModal.d.ts","sourceRoot":"","sources":["../../../src/components/LDModal/LDModal.tsx"],"names":[],"mappings":"AAKA,OAAoB,EAElB,KAAK,SAAS,EACd,gBAAgB,EACjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,SAAS;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EACJ,KAAK,CAAC,SAAS,GACf,CAAC,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAClE,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC;QACT,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;QACzD,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;QACvC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;KAC1D,EAAE,CAAC;IACJ,eAAe;IACf,gBAAgB,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,+BAA+B;IAC/B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACtC,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjD,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,QAAA,MAAM,OAAO,GAAI,CAAC,GAAG,SAAS,EAC5B,SAAS,cAAc,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,CAAC,GAAG,SAAS,CA2EvB,CAAC;AAEF,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"LDModal.d.ts","sourceRoot":"","sources":["../../../src/components/LDModal/LDModal.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAoB,MAAM,OAAO,CAAC;AAG7E,OAAoB,EAElB,KAAK,SAAS,EACd,gBAAgB,EACjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,SAAS;IAC3C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,CAAA;KAAE,KAAK,SAAS,CAAC,CAAC;IAC9E,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC;QACT,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;QACzD,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;QACvC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;KAC1D,EAAE,CAAC;IACJ,eAAe;IACf,gBAAgB,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IACpC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,+BAA+B;IAC/B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACtC,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjD,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,QAAA,MAAM,OAAO,GAAI,CAAC,GAAG,SAAS,EAC5B,SAAS,cAAc,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,CAAC,GAAG,SAAS,CA2EvB,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -35,11 +35,11 @@ export interface LDModalViewProps {
35
35
  /** 열림 상태 변경 시 호출되는 콜백 */
36
36
  onOpenChange?: (open: boolean) => void;
37
37
  /** 서브 타이틀 (title 위에 표시) */
38
- name?: string;
38
+ name?: ReactNode;
39
39
  /** 모달 제목 */
40
- title?: string;
40
+ title?: ReactNode;
41
41
  /** 모달 설명 텍스트 */
42
- description?: string;
42
+ description?: ReactNode;
43
43
  /** 본문 콘텐츠 */
44
44
  children?: ReactNode;
45
45
  /** 모달 너비 프리셋 */
@@ -1 +1 @@
1
- {"version":3,"file":"LDModalView.d.ts","sourceRoot":"","sources":["../../../src/components/LDModal/LDModalView.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,OAAO,CAAC;AAI/C,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAI7C,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,KAAK,EAAE,CAAC,CAAC;IACT,gBAAgB;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;IACzD,eAAe;IACf,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IACvC,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,gBAAgB;IAC/B,yBAAyB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0BAA0B;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yBAAyB;IACzB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,gBAAgB;IAChB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,eAAe;IACf,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,aAAa;IACb,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACtC,0BAA0B;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AA6CD,QAAA,MAAM,WAAW,GAAI,iJAelB,gBAAgB,4CAkLlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"LDModalView.d.ts","sourceRoot":"","sources":["../../../src/components/LDModal/LDModalView.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAU,MAAM,OAAO,CAAC;AAK/C,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAI7C,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,KAAK,EAAE,CAAC,CAAC;IACT,gBAAgB;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;IACzD,eAAe;IACf,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IACvC,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,gBAAgB;IAC/B,yBAAyB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0BAA0B;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yBAAyB;IACzB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,2BAA2B;IAC3B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,YAAY;IACZ,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,gBAAgB;IAChB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,aAAa;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,gBAAgB;IAChB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,eAAe;IACf,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,aAAa;IACb,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACtC,0BAA0B;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AA6CD,QAAA,MAAM,WAAW,GAAI,iJAelB,gBAAgB,4CAkLlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -3,6 +3,7 @@ import { Check, CircleAlert, X } from 'lucide-react';
3
3
  import { useRef } from 'react';
4
4
  import LDButton from '../../components/LDButton/LDButton.js';
5
5
  import ModalBase from '../../components/LDModal/ModalBase.js';
6
+ import Show from '../../components/Show/Show.js';
6
7
  import cn from '../../utils/cn.js';
7
8
  // ── 스타일 매핑 ──
8
9
  const sizeClasses = {
@@ -62,10 +63,10 @@ const LDModalView = ({ open, defaultOpen, onOpenChange, name, title, description
62
63
  overlayRef.current)
63
64
  onOpenChange?.(false);
64
65
  overlayRef.current = false;
65
- }, children: _jsxs("div", { className: cn('relative rounded-2xl bg-white p-5', sizeClasses[size], 'mobile:max-w-[calc(100vw-40px)]', scrollBehavior === 'inside' && 'flex max-h-[90dvh] flex-col', classNames?.layout), style: style, onClick: (e) => e.stopPropagation(), children: [_jsx(ModalBase.Close, { asChild: true, className: cn('absolute top-4 right-5 cursor-pointer text-neutral500 outline-hidden', classNames?.close), children: _jsx(LDButton, { variant: "ghost", color: "neutral", leftIcon: _jsx(X, {}), compact: true }) }), _jsxs("div", { className: cn('flex w-full shrink-0 flex-col', scrollBehavior === 'inside' && 'min-h-0 flex-1', layoutGapSizeClasses[size], !hasHeader && noHeaderPaddingTopSizeClasses[size], classNames?.panel), children: [hasHeader && (_jsxs("div", { className: "flex w-full shrink-0 flex-col items-center gap-5 py-5 text-center", children: [icon === 'success' && (_jsx("div", { className: cn('flex items-center justify-center rounded-full bg-hyper-blue', statusIconSizeClasses[size]), children: _jsx(Check, { className: "text-white" }) })), icon === 'fail' && (_jsx("div", { className: cn('flex items-center justify-center rounded-full bg-danger600', statusIconSizeClasses[size]), children: _jsx(CircleAlert, { className: "text-white" }) })), name && (_jsx("span", { className: "display16 bold whitespace-pre-wrap text-neutral500", children: name })), title && (_jsx(ModalBase.Title, { className: cn('text-center display28 bold whitespace-pre-wrap', classNames?.title), children: title })), description && (_jsx(ModalBase.Description, { className: cn('text-center display14 whitespace-pre-wrap text-neutral500', classNames?.description), children: description }))] })), children && (_jsx("div", { className: cn(scrollBehavior === 'inside' &&
66
- 'min-h-10 flex-1 overflow-y-auto'), children: children })), buttons?.list && buttons?.list?.length > 0 && (_jsx("div", { className: cn('flex mobile:flex-1 mobile:flex-col mobile:items-center', buttons.direction === 'column' ? 'flex-col' : 'flex-row', buttonsGapSizeClasses[size]), children: buttons?.list?.map((button, index) => {
67
- const isFirst = index === 0;
68
- return (_jsx("div", { className: "flex w-full flex-1", children: _jsx(LDButton, { type: "button", onClick: () => handleClick(button), variant: button.variant ?? (isFirst ? 'solid' : 'outline'), color: button.color ?? (isFirst ? 'point' : 'neutral'), size: buttonSizeClasses[size], block: true, children: button.label }) }, String(button.value)));
69
- }) }))] })] }) })] }));
66
+ }, children: _jsxs("div", { className: cn('relative rounded-2xl bg-white p-5', sizeClasses[size], 'mobile:max-w-[calc(100vw-40px)]', scrollBehavior === 'inside' && 'flex max-h-[90dvh] flex-col', classNames?.layout), style: style, onClick: (e) => e.stopPropagation(), children: [_jsx(ModalBase.Close, { asChild: true, className: cn('absolute top-4 right-5 cursor-pointer text-neutral500 outline-hidden', classNames?.close), children: _jsx(LDButton, { variant: "ghost", color: "neutral", leftIcon: _jsx(X, {}), compact: true }) }), _jsxs("div", { className: cn('flex w-full shrink-0 flex-col', scrollBehavior === 'inside' && 'min-h-0 flex-1', layoutGapSizeClasses[size], !hasHeader && noHeaderPaddingTopSizeClasses[size], classNames?.panel), children: [_jsx(Show, { when: hasHeader, children: _jsxs("div", { className: "flex w-full shrink-0 flex-col items-center gap-5 py-5 text-center", children: [_jsx(Show, { when: icon === 'success', children: _jsx("div", { className: cn('flex items-center justify-center rounded-full bg-hyper-blue', statusIconSizeClasses[size]), children: _jsx(Check, { className: "text-white" }) }) }), _jsx(Show, { when: icon === 'fail', children: _jsx("div", { className: cn('flex items-center justify-center rounded-full bg-danger600', statusIconSizeClasses[size]), children: _jsx(CircleAlert, { className: "text-white" }) }) }), _jsx(Show, { when: name, children: _jsx("span", { className: "display16 bold whitespace-pre-wrap text-neutral500", children: name }) }), _jsx(Show, { when: title, children: _jsx(ModalBase.Title, { className: cn('text-center display28 bold whitespace-pre-wrap', classNames?.title), children: title }) }), _jsx(Show, { when: description, children: _jsx(ModalBase.Description, { className: cn('text-center display14 whitespace-pre-wrap text-neutral500', classNames?.description), children: description }) })] }) }), _jsx(Show, { when: children, children: _jsx("div", { className: cn(scrollBehavior === 'inside' &&
67
+ 'min-h-10 flex-1 overflow-y-auto'), children: children }) }), _jsx(Show, { when: buttons?.list?.length, children: _jsx("div", { className: cn('flex mobile:flex-1 mobile:flex-col mobile:items-center', buttons?.direction === 'column' ? 'flex-col' : 'flex-row', buttonsGapSizeClasses[size]), children: buttons?.list?.map((button, index) => {
68
+ const isFirst = index === 0;
69
+ return (_jsx("div", { className: "flex w-full flex-1", children: _jsx(LDButton, { type: "button", onClick: () => handleClick(button), variant: button.variant ?? (isFirst ? 'solid' : 'outline'), color: button.color ?? (isFirst ? 'point' : 'neutral'), size: buttonSizeClasses[size], block: true, children: button.label }) }, String(button.value)));
70
+ }) }) })] })] }) })] }));
70
71
  };
71
72
  export default LDModalView;
@@ -136,7 +136,7 @@ const LDMultiSelect = ({ items, placeholder = '선택해주세요', value = [],
136
136
  size,
137
137
  disabled,
138
138
  className,
139
- }), children: truncate ? (_jsxs("div", { className: "flex w-full items-center justify-center gap-sm px-3 py-1.5", children: [_jsx(SelectBase.Value, { placeholder: placeholder, className: valueVariants({ align }), placeholderClassName: "text-neutral200" }), chevron] })) : (_jsxs("div", { className: "flex w-full items-center justify-between gap-sm px-3 py-1.5", children: [_jsx("div", { className: chipListVariants({ align }), children: value.length === 0 ? (_jsx("span", { className: "text-neutral200", children: placeholder })) : (value.map((v) => {
139
+ }), children: truncate ? (_jsxs("div", { className: "flex w-full items-center justify-center gap-sm px-3 py-1.5", children: [_jsx(SelectBase.Value, { placeholder: placeholder, className: valueVariants({ align }), placeholderClassName: "text-neutral300" }), chevron] })) : (_jsxs("div", { className: "flex w-full items-center justify-between gap-sm px-3 py-1.5", children: [_jsx("div", { className: chipListVariants({ align }), children: value.length === 0 ? (_jsx("span", { className: "text-neutral300", children: placeholder })) : (value.map((v) => {
140
140
  const label = items.find((i) => i.value === v)?.label || v;
141
141
  return (_jsxs("span", { className: "flex animate-fade-in items-center justify-between rounded-sm border border-neutral100 bg-white px-2 py-1 display12 text-neutral900", children: [label, _jsx("div", { role: "button", "aria-label": `${label} 삭제`, onClick: (e) => {
142
142
  e.stopPropagation();
@@ -129,7 +129,7 @@ const Trigger = ({ className, ...props }) => {
129
129
  /** 현재 선택값을 표시하는 Styled Compound 영역입니다. */
130
130
  const Value = ({ className, ...props }) => {
131
131
  const { align } = useContext(LDSelectStyleContext);
132
- return (_jsx(SelectBase.Value, { ...props, className: valueVariants({ align, className }), placeholderClassName: cn('text-neutral200', props.placeholderClassName) }));
132
+ return (_jsx(SelectBase.Value, { ...props, className: valueVariants({ align, className }), placeholderClassName: cn('text-neutral300', props.placeholderClassName) }));
133
133
  };
134
134
  /** 옵션 목록을 표시하는 Styled Compound 영역입니다. */
135
135
  const Content = ({ className, openClassName = 'opacity-100', closedClassName = 'pointer-events-none opacity-0', ...props }) => (_jsx(SelectBase.Content, { ...props, className: cn('mt-1 scrollbar-hide flex max-h-57.5 w-full flex-col gap-3xs overflow-y-auto rounded-[5px] border border-mono100 bg-white p-2 transition-opacity duration-300 ease-out', className), openClassName: openClassName, closedClassName: closedClassName }));
@@ -12,10 +12,10 @@ const Toolbar = ({ title, totalCount, rightSideContents, className, }) => {
12
12
  // ── Styled Sub-components ──
13
13
  const Header = ({ className, children, ...props }) => (_jsx(TableBase.Header, { className: cn('h-9 border-b border-neutral700 bg-mono100 ld-transition hover:bg-mono200', className), ...props, children: children }));
14
14
  const HeaderRow = ({ className, children, ...props }) => (_jsx(TableBase.HeaderRow, { className: className, ...props, children: children }));
15
- const HeaderCell = ({ className, children, ...props }) => (_jsx(TableBase.HeaderCell, { className: cn('px-5 display12 regular', className), ...props, children: children }));
15
+ const HeaderCell = ({ className, children, ...props }) => (_jsx(TableBase.HeaderCell, { className: cn('px-5 display14 bold tablet-down:display12', className), ...props, children: children }));
16
16
  const Body = ({ className, children, ...props }) => (_jsx(TableBase.Body, { className: className, ...props, children: children }));
17
17
  const Row = ({ className, children, ...props }) => (_jsx(TableBase.Row, { className: cn('h-13 border-b border-neutral100 ld-transition hover:bg-mono50', className), ...props, children: children }));
18
- const Cell = ({ className, children, ...props }) => (_jsx(TableBase.Cell, { className: cn('px-5 display14 regular', className), ...props, children: children }));
18
+ const Cell = ({ className, children, ...props }) => (_jsx(TableBase.Cell, { className: cn('px-5 display16 regular tablet-down:display14', className), ...props, children: children }));
19
19
  LDTable.Header = Header;
20
20
  LDTable.HeaderRow = HeaderRow;
21
21
  LDTable.HeaderCell = HeaderCell;
@@ -53,15 +53,15 @@ const fieldVariants = tv({
53
53
  ],
54
54
  });
55
55
  const textareaVariants = tv({
56
- base: 'w-full bg-transparent px-1 py-0 outline-none placeholder:text-mono400 read-only:cursor-default disabled:cursor-not-allowed disabled:text-mono400',
56
+ base: 'w-full bg-transparent px-1 py-0 outline-none placeholder:text-neutral300 read-only:cursor-default disabled:cursor-not-allowed disabled:text-mono400',
57
57
  variants: {
58
58
  size: {
59
- '2xsmall': 'display10',
60
- xsmall: 'display12',
61
- small: 'display14',
62
- medium: 'display16',
63
- large: 'display18',
64
- xlarge: 'display20',
59
+ '2xsmall': 'display10 leading-relaxed',
60
+ xsmall: 'display12 leading-relaxed',
61
+ small: 'display14 leading-relaxed',
62
+ medium: 'display16 leading-relaxed',
63
+ large: 'display18 leading-relaxed',
64
+ xlarge: 'display20 leading-relaxed',
65
65
  },
66
66
  },
67
67
  });
@@ -87,7 +87,7 @@ const LDTimePicker = ({ value, defaultValue, onChange, placeholder = 'HH:MM', di
87
87
  e.preventDefault();
88
88
  setOpen(true);
89
89
  }
90
- }, placeholder: placeholder, "aria-label": "\uC2DC\uAC04 \uC785\uB825", disabled: disabled, readOnly: !isEditable, className: cn('absolute inset-0 w-full flex-1 rounded-[5px] bg-transparent px-4 outline-none', !resolved && 'text-neutral500', !isEditable && 'cursor-pointer') }) }), _jsxs("div", { className: "z-10 flex shrink-0 items-center gap-2", onClick: () => {
90
+ }, placeholder: placeholder, "aria-label": "\uC2DC\uAC04 \uC785\uB825", disabled: disabled, readOnly: !isEditable, className: cn('absolute inset-0 w-full flex-1 rounded-[5px] bg-transparent px-4 outline-none', !resolved && 'text-neutral300', !isEditable && 'cursor-pointer') }) }), _jsxs("div", { className: "z-10 flex shrink-0 items-center gap-2", onClick: () => {
91
91
  if (disabled)
92
92
  return;
93
93
  setOpen((o) => !o);
package/dist/index.css CHANGED
@@ -29,6 +29,7 @@
29
29
  --text-lg--line-height: calc(1.75 / 1.125);
30
30
  --font-weight-normal: 400;
31
31
  --tracking-tight: -0.025em;
32
+ --leading-relaxed: 1.625;
32
33
  --radius-xs: 0.125rem;
33
34
  --radius-sm: 0.25rem;
34
35
  --radius-md: 0.375rem;
@@ -97,6 +98,7 @@
97
98
  --color-warning800: #b38000;
98
99
  --color-lb50: #e0e9ff;
99
100
  --color-lb100: #c3d4ff;
101
+ --color-lb300: #95b2fa;
100
102
  --color-lb500: #6891f8;
101
103
  --color-lb600: #5883ee;
102
104
  --color-lb700: #4a75df;
@@ -597,6 +599,9 @@
597
599
  .mx-auto {
598
600
  margin-inline: auto;
599
601
  }
602
+ .-my-2 {
603
+ margin-block: calc(var(--spacing) * -2);
604
+ }
600
605
  .prose {
601
606
  color: var(--tw-prose-body);
602
607
  max-width: 65ch;
@@ -1343,6 +1348,10 @@
1343
1348
  width: calc(var(--spacing) * 4);
1344
1349
  height: calc(var(--spacing) * 4);
1345
1350
  }
1351
+ .size-4\.5 {
1352
+ width: calc(var(--spacing) * 4.5);
1353
+ height: calc(var(--spacing) * 4.5);
1354
+ }
1346
1355
  .size-5 {
1347
1356
  width: calc(var(--spacing) * 5);
1348
1357
  height: calc(var(--spacing) * 5);
@@ -1379,10 +1388,6 @@
1379
1388
  width: calc(var(--spacing) * 12.5);
1380
1389
  height: calc(var(--spacing) * 12.5);
1381
1390
  }
1382
- .size-15 {
1383
- width: calc(var(--spacing) * 15);
1384
- height: calc(var(--spacing) * 15);
1385
- }
1386
1391
  .size-16 {
1387
1392
  width: calc(var(--spacing) * 16);
1388
1393
  height: calc(var(--spacing) * 16);
@@ -2426,6 +2431,9 @@
2426
2431
  .bg-blue100 {
2427
2432
  background-color: var(--color-blue100);
2428
2433
  }
2434
+ .bg-blue200 {
2435
+ background-color: var(--color-blue200);
2436
+ }
2429
2437
  .bg-current {
2430
2438
  background-color: currentcolor;
2431
2439
  }
@@ -2694,6 +2702,9 @@
2694
2702
  .py-0\.5 {
2695
2703
  padding-block: calc(var(--spacing) * 0.5);
2696
2704
  }
2705
+ .py-0\.75 {
2706
+ padding-block: calc(var(--spacing) * 0.75);
2707
+ }
2697
2708
  .py-1 {
2698
2709
  padding-block: calc(var(--spacing) * 1);
2699
2710
  }
@@ -2972,6 +2983,10 @@
2972
2983
  --tw-leading: 1;
2973
2984
  line-height: 1;
2974
2985
  }
2986
+ .leading-relaxed {
2987
+ --tw-leading: var(--leading-relaxed);
2988
+ line-height: var(--leading-relaxed);
2989
+ }
2975
2990
  .font-normal {
2976
2991
  --tw-font-weight: var(--font-weight-normal);
2977
2992
  font-weight: var(--font-weight-normal);
@@ -3158,6 +3173,11 @@
3158
3173
  .underline-offset-\[4px\] {
3159
3174
  text-underline-offset: 4px;
3160
3175
  }
3176
+ .placeholder-lb300 {
3177
+ &::placeholder {
3178
+ color: var(--color-lb300);
3179
+ }
3180
+ }
3161
3181
  .placeholder-neutral300 {
3162
3182
  &::placeholder {
3163
3183
  color: var(--color-neutral300);
@@ -3542,9 +3562,9 @@
3542
3562
  --tw-ring-offset-shadow: var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
3543
3563
  }
3544
3564
  }
3545
- .placeholder\:text-mono400 {
3565
+ .placeholder\:text-neutral300 {
3546
3566
  &::placeholder {
3547
- color: var(--color-mono400);
3567
+ color: var(--color-neutral300);
3548
3568
  }
3549
3569
  }
3550
3570
  .after\:absolute {
@@ -4688,11 +4708,21 @@
4688
4708
  align-items: center;
4689
4709
  }
4690
4710
  }
4711
+ .mobile\:items-start {
4712
+ @media (max-width: calc(768px - 1px)) {
4713
+ align-items: flex-start;
4714
+ }
4715
+ }
4691
4716
  .mobile\:gap-1 {
4692
4717
  @media (max-width: calc(768px - 1px)) {
4693
4718
  gap: calc(var(--spacing) * 1);
4694
4719
  }
4695
4720
  }
4721
+ .mobile\:gap-2xs {
4722
+ @media (max-width: calc(768px - 1px)) {
4723
+ gap: var(--spacing_4);
4724
+ }
4725
+ }
4696
4726
  .mobile\:overflow-hidden {
4697
4727
  @media (max-width: calc(768px - 1px)) {
4698
4728
  overflow: hidden;
@@ -4756,6 +4786,13 @@
4756
4786
  letter-spacing: var(--tracking-display12);
4757
4787
  }
4758
4788
  }
4789
+ .tablet-down\:display14 {
4790
+ @media (max-width: calc(992px - 1px)) {
4791
+ font-size: var(--text-display14);
4792
+ line-height: var(--leading-display14);
4793
+ letter-spacing: var(--tracking-display14);
4794
+ }
4795
+ }
4759
4796
  .\[\&_svg\]\:icon-2xs {
4760
4797
  & svg {
4761
4798
  width: var(--control-icon-2xs);
@@ -5419,6 +5456,12 @@
5419
5456
  .prose :is(strong, b) {
5420
5457
  color: inherit !important;
5421
5458
  }
5459
+ .ProseMirror :first-child {
5460
+ margin-top: 0;
5461
+ }
5462
+ .ProseMirror :last-child {
5463
+ margin-bottom: 0;
5464
+ }
5422
5465
  }
5423
5466
  .ProseMirror img {
5424
5467
  max-width: 100%;
package/dist/index.d.ts CHANGED
@@ -23,7 +23,8 @@ export { type DrawerButton, default as LDDrawer, type LDDrawerBodyProps, type LD
23
23
  export { default as LDEditor } from './components/LDEditor/LDEditor.js';
24
24
  export { default as LDViewer } from './components/LDEditor/LDViewer.js';
25
25
  export { type EmptySize, default as LDEmpty, type LDEmptyProps, } from './components/LDEmpty/LDEmpty.js';
26
- export { default as LDFileUpload, type LDFileUploadCardListProps, type LDFileUploadClassNames, type LDFileUploadDescriptionProps, type LDFileUploadInputProps, type LDFileUploadProps, type LDFileUploadRootProps, } from './components/LDFileUpload/LDFileUpload.js';
26
+ export { type FileUploadOptions as LDFileUploadOptions } from './components/LDFileUpload/FileUploadBase.js';
27
+ export { default as LDFileUpload, type LDFileUploadCardListProps, type LDFileUploadClassNames, type LDFileUploadDescriptionProps, type LDFileUploadInputProps, type LDFileUploadLinkListProps, type LDFileUploadProps, type LDFileUploadRootProps, } from './components/LDFileUpload/LDFileUpload.js';
27
28
  export { default as LDFileUploadList, type LDFileUploadListProps, } from './components/LDFileUpload/LDFileUploadList.js';
28
29
  export { default as LDImageUpload, type LDImageUploadProps, } from './components/LDFileUpload/LDImageUpload.js';
29
30
  export { default as LDImageUploadList, type LDImageUploadListProps, } from './components/LDFileUpload/LDImageUploadList.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -44,7 +44,6 @@ export { default as LDEditor } from './components/LDEditor/LDEditor.js';
44
44
  export { default as LDViewer } from './components/LDEditor/LDViewer.js';
45
45
  // LDEmpty
46
46
  export { default as LDEmpty, } from './components/LDEmpty/LDEmpty.js';
47
- // LDFileUpload
48
47
  export { default as LDFileUpload, } from './components/LDFileUpload/LDFileUpload.js';
49
48
  export { default as LDFileUploadList, } from './components/LDFileUpload/LDFileUploadList.js';
50
49
  export { default as LDImageUpload, } from './components/LDFileUpload/LDImageUpload.js';
@@ -4,6 +4,8 @@ export interface IFile {
4
4
  fileName: string;
5
5
  fileBase64: string;
6
6
  src: string;
7
+ /** 업로드 시각(ISO). 새로 업로드한 파일에 자동으로 붙습니다. */
8
+ uploadedAt?: string;
7
9
  }
8
10
  export declare const isImage: (src: string) => boolean;
9
11
  export declare const isImageOrPdf: (src: string) => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":"AASA,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,YACW,CAAC;AAE/C,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,YACU,CAAC;AAgCnD,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,KAAG,YAM9C,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,UAAU,SAAS,KAClB,cAAc,GAAG,MAEnB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,MAAM,IAAI,KAAG,OAAO,CAAC,OAAO,CAoB1D,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,EAAE,SAAS,MAAM,YAExD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,MAAM,IAAI,EACV,mBAAmB,SAAS,EAAE,YAG/B,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,oBAS7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,IAAI,KAAG,OAAO,CAAC,MAAM,CAM5D,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,MAAM,IAAI,KAAG,OAAO,CAAC,KAAK,CAY5D,CAAC"}
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":"AASA,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,YACW,CAAC;AAE/C,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,YACU,CAAC;AAgCnD,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,KAAG,YAM9C,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,UAAU,SAAS,KAClB,cAAc,GAAG,MAEnB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,MAAM,IAAI,KAAG,OAAO,CAAC,OAAO,CAoB1D,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,EAAE,SAAS,MAAM,YAExD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,MAAM,IAAI,EACV,mBAAmB,SAAS,EAAE,YAG/B,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,oBAS7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,IAAI,KAAG,OAAO,CAAC,MAAM,CAM5D,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,MAAM,IAAI,KAAG,OAAO,CAAC,KAAK,CAa5D,CAAC"}
@@ -92,5 +92,6 @@ export const fileToBase64 = async (file) => {
92
92
  fileName: file.name,
93
93
  fileBase64: base64,
94
94
  src: result,
95
+ uploadedAt: new Date().toISOString(),
95
96
  };
96
97
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loword/loword-design-system",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "로워드 디자인 시스템 컴포넌트 패키지(Tailwind v4)",
5
5
  "keywords": [
6
6
  "react",
@@ -30,6 +30,20 @@
30
30
  .prose :is(strong, b) {
31
31
  color: inherit !important;
32
32
  }
33
+
34
+ /* prose 기본값은 블록 요소에 상하 대칭 여백(my)을 준다. 문서 처음/끝에서는
35
+ 그 여백이 컨테이너 안쪽 빈 공간으로 보이므로 제거한다.
36
+ 기준을 .prose가 아니라 .ProseMirror로 잡는 이유: LDViewer는 prose를
37
+ EditorContent 래퍼에 주므로 본문 블록이 .prose의 손자가 된다.
38
+ 직계 자식(>)으로 한정하지 않는 이유: li > p, blockquote > p처럼 중첩된
39
+ 블록도 자기 부모의 처음/끝이면 같은 규칙이 적용돼야 한다. */
40
+ .ProseMirror :first-child {
41
+ margin-top: 0;
42
+ }
43
+
44
+ .ProseMirror :last-child {
45
+ margin-bottom: 0;
46
+ }
33
47
  }
34
48
 
35
49
  /* 이미지 정렬 스타일 */