@loword/loword-design-system 0.6.0 → 0.7.1

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.
@@ -16,7 +16,14 @@ export interface LDEditorProps {
16
16
  allowedImageHosts?: string[];
17
17
  /** 툴바 업로드·이미지 붙여넣기에서 허용할 MIME 타입. 지정하지 않으면 기본 허용 형식을 쓴다. */
18
18
  allowedExtensions?: TMimeType[];
19
+ /** 툴바 업로드·이미지 붙여넣기에서 허용할 최대 파일 크기(byte). 기본 5MB. */
20
+ maxSize?: number;
21
+ /** 툴바 업로드·이미지 붙여넣기에서 허용할 최대 해상도(px). 기본 16000x16000. */
22
+ maxImageSize?: {
23
+ width: number;
24
+ height: number;
25
+ };
19
26
  }
20
- declare const LDEditor: ({ content, onChange, className, handleImageUpload, allowedImageHosts, allowedExtensions, }: LDEditorProps) => import("react/jsx-runtime").JSX.Element;
27
+ declare const LDEditor: ({ content, onChange, className, handleImageUpload, allowedImageHosts, allowedExtensions, maxSize, maxImageSize, }: LDEditorProps) => import("react/jsx-runtime").JSX.Element;
21
28
  export default LDEditor;
22
29
  //# sourceMappingURL=LDEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AAwCA,OAAO,EAEL,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAC;AAqH1B,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,0DAA0D;IAC1D,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;IAC7B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,SAAS,EAAE,CAAC;CACjC;AAqVD,QAAA,MAAM,QAAQ,GAAI,4FAOf,aAAa,4CAgCf,CAAC;AAwmBF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AAwCA,OAAO,EAEL,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAC;AAqH1B,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,0DAA0D;IAC1D,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;IAC7B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,SAAS,EAAE,CAAC;IAChC,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD;AA+UD,QAAA,MAAM,QAAQ,GAAI,mHASf,aAAa,4CAsCf,CAAC;AAimBF,eAAe,QAAQ,CAAC"}
@@ -80,17 +80,17 @@ const LDDivider = () => _jsx("div", { className: "mx-1 h-6 w-px bg-neutral200" }
80
80
  // 두어 줄이 바뀌어도 새 줄이 구분선으로 시작하지 않게 한다.
81
81
  const ToolbarGroup = ({ children }) => (_jsx("div", { className: "flex items-center gap-2", children: children }));
82
82
  // 검증을 통과하면 업로드한 URL을 반환하고, 실패하면 토스트에 띄울 사유를 담아 throw한다.
83
- const uploadImageFile = async (file, handleImageUpload, allowedExtensions = TOOLBAR_ALLOWED_EXTENSIONS) => {
83
+ const uploadImageFile = async (file, { handleImageUpload, allowedExtensions = TOOLBAR_ALLOWED_EXTENSIONS, maxSize = TOOLBAR_MAX_SIZE, maxImageSize, }) => {
84
84
  if (!validAllowedExtensions(file, allowedExtensions)) {
85
85
  const allowedFiles = allowedExtensions
86
86
  .map((item) => FILE_EXTENSIONS[item].toUpperCase())
87
87
  .join(', ');
88
88
  throw new Error(`지원하지 않는 파일 형식입니다. ${allowedFiles} 파일만 업로드 가능합니다.`);
89
89
  }
90
- if (!validFileSize(file, TOOLBAR_MAX_SIZE)) {
91
- throw new Error(`파일 크기가 너무 큽니다. ${getFileSizeUnit(TOOLBAR_MAX_SIZE)} 이하 파일을 선택해주세요.`);
90
+ if (!validFileSize(file, maxSize)) {
91
+ throw new Error(`파일 크기가 너무 큽니다. ${getFileSizeUnit(maxSize)} 이하 파일을 선택해주세요.`);
92
92
  }
93
- if (isImage(file.name) && !(await validImageSize(file))) {
93
+ if (isImage(file.name) && !(await validImageSize(file, maxImageSize))) {
94
94
  throw new Error('이미지 해상도가 너무 큽니다. 더 작은 이미지를 선택해주세요.');
95
95
  }
96
96
  let src;
@@ -259,7 +259,8 @@ const ImagePaste = Extension.create({
259
259
  props: {
260
260
  decorations: (state) => placeholderKey.getState(state),
261
261
  handlePaste: (view, event, slice) => {
262
- const { handleImageUpload, allowedImageHosts, allowedExtensions } = getConfig();
262
+ const config = getConfig();
263
+ const { handleImageUpload, allowedImageHosts } = config;
263
264
  if (!handleImageUpload)
264
265
  return false;
265
266
  const html = event.clipboardData?.getData('text/html') ?? '';
@@ -286,10 +287,10 @@ const ImagePaste = Extension.create({
286
287
  ? files[0]
287
288
  : undefined;
288
289
  pasteAfterUpload(view, uploadAll(list.map((src) => isDataUrl(src)
289
- ? dataUrlToFile(src).then((file) => uploadImageFile(file, handleImageUpload, allowedExtensions))
290
+ ? dataUrlToFile(src).then((file) => uploadImageFile(file, config))
290
291
  : (copiedImage
291
292
  ? Promise.resolve(copiedImage)
292
- : urlToFile(src)).then((file) => uploadImageFile(file, handleImageUpload, allowedExtensions)))).then((srcs) => {
293
+ : urlToFile(src)).then((file) => uploadImageFile(file, config)))).then((srcs) => {
293
294
  const urls = new Map(list.map((src, index) => [src, srcs[index] ?? null]));
294
295
  return new Slice(replaceImages(slice.content, urls), slice.openStart, slice.openEnd);
295
296
  }));
@@ -298,7 +299,7 @@ const ImagePaste = Extension.create({
298
299
  // Office는 HTML과 함께 선택 영역을 찍은 PNG를 files에 넣는다. HTML이 있으면 파일은 무시한다.
299
300
  if (html || !files.length)
300
301
  return false;
301
- pasteAfterUpload(view, uploadAll(files.map((file) => uploadImageFile(file, handleImageUpload, allowedExtensions))).then((srcs) => {
302
+ pasteAfterUpload(view, uploadAll(files.map((file) => uploadImageFile(file, config))).then((srcs) => {
302
303
  const nodes = files.flatMap((file, index) => {
303
304
  const src = srcs[index];
304
305
  return src
@@ -320,26 +321,30 @@ const ImagePaste = Extension.create({
320
321
  ];
321
322
  },
322
323
  });
323
- const LDEditor = ({ content, onChange, className, handleImageUpload, allowedImageHosts, allowedExtensions, }) => {
324
+ const LDEditor = ({ content, onChange, className, handleImageUpload, allowedImageHosts, allowedExtensions, maxSize, maxImageSize, }) => {
324
325
  // 에디터는 첫 렌더의 extensions로 한 번만 만들어진다. 붙여넣기는 최신 props를 ref로 읽는다.
325
326
  const pasteConfigRef = useRef({
326
327
  handleImageUpload,
327
328
  allowedImageHosts,
328
329
  allowedExtensions,
330
+ maxSize,
331
+ maxImageSize,
329
332
  });
330
333
  useEffect(() => {
331
334
  pasteConfigRef.current = {
332
335
  handleImageUpload,
333
336
  allowedImageHosts,
334
337
  allowedExtensions,
338
+ maxSize,
339
+ maxImageSize,
335
340
  };
336
341
  });
337
342
  return (_jsxs(EditorBase.Root, { extensions: [
338
343
  ...createEditorExtensions(),
339
344
  ImagePaste.configure({ getConfig: () => pasteConfigRef.current }),
340
- ], content: content, onChange: onChange, className: className, children: [_jsx(EditorToolbar, { handleImageUpload: handleImageUpload, allowedExtensions: allowedExtensions }), _jsx(EditorBase.Content, {})] }));
345
+ ], content: content, onChange: onChange, className: className, children: [_jsx(EditorToolbar, { handleImageUpload: handleImageUpload, allowedExtensions: allowedExtensions, maxSize: maxSize, maxImageSize: maxImageSize }), _jsx(EditorBase.Content, {})] }));
341
346
  };
342
- const EditorToolbar = ({ handleImageUpload, allowedExtensions, }) => {
347
+ const EditorToolbar = (uploadConfig) => {
343
348
  const [linkUrl, setLinkUrl] = useState('');
344
349
  const [isMobile, setIsMobile] = useState(false);
345
350
  const { editor } = useEditorContext();
@@ -388,7 +393,7 @@ const EditorToolbar = ({ handleImageUpload, allowedExtensions, }) => {
388
393
  return;
389
394
  const file = files[0];
390
395
  try {
391
- const src = await uploadImageFile(file, handleImageUpload, allowedExtensions);
396
+ const src = await uploadImageFile(file, uploadConfig);
392
397
  editor.commands.setImage({
393
398
  src,
394
399
  alt: file.name,
@@ -32,6 +32,11 @@ export interface LDFileUploadAttachmentListProps {
32
32
  labelPlaceholder?: string;
33
33
  /** 파일 카드에 업로드 시각 라벨을 표시합니다. */
34
34
  isExistUploadedAt?: boolean;
35
+ /**
36
+ * 손잡이를 끌어 순서를 바꿀 수 있게 합니다. 서버가 첨부 순서를 저장하는 화면에서만 켭니다.
37
+ * @default false
38
+ */
39
+ sortable?: boolean;
35
40
  className?: string;
36
41
  }
37
42
  export type LDFileUploadDescriptionProps = HTMLAttributes<HTMLParagraphElement>;
@@ -46,7 +51,7 @@ declare const LDFileUpload: {
46
51
  Root: ({ className, classNames, children, ...props }: LDFileUploadRootProps) => import("react/jsx-runtime").JSX.Element;
47
52
  Input: ({ type, label, icon, options, className, ...props }: LDFileUploadInputProps) => import("react/jsx-runtime").JSX.Element | null;
48
53
  CardList: ({ type, isExistUploadedAt, className, }: LDFileUploadCardListProps) => import("react/jsx-runtime").JSX.Element;
49
- AttachmentList: ({ placeholder, labelPlaceholder, isExistUploadedAt, className, }: LDFileUploadAttachmentListProps) => import("react/jsx-runtime").JSX.Element;
54
+ AttachmentList: ({ placeholder, labelPlaceholder, isExistUploadedAt, sortable, className, }: LDFileUploadAttachmentListProps) => import("react/jsx-runtime").JSX.Element;
50
55
  Description: ({ className, ...props }: LDFileUploadDescriptionProps) => import("react/jsx-runtime").JSX.Element;
51
56
  };
52
57
  export default LDFileUpload;
@@ -1 +1 @@
1
- {"version":3,"file":"LDFileUpload.d.ts","sourceRoot":"","sources":["../../../src/components/LDFileUpload/LDFileUpload.tsx"],"names":[],"mappings":"AA8BA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAEf,OAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE9E,OAAuB,EAErB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EAEvB,MAAM,0CAA0C,CAAC;AAuFlD,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;AAyUD,MAAM,WAAW,+BAA+B;IAC9C,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyFD,MAAM,MAAM,4BAA4B,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;AA6BhF,MAAM,WAAW,iBACf,SACE,IAAI,CACF,qBAAqB,EACrB,UAAU,GAAG,YAAY,GAAG,cAAc,GAAG,MAAM,uBAAuB,CAC3E,EACD,uBAAuB;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,kCAAkC;AAClC,QAAA,MAAM,YAAY;qFAMf,iBAAiB;0DArlBjB,qBAAqB;iEAmCrB,sBAAsB;wDA+FtB,yBAAyB;uFAqVzB,+BAA+B;2CAiFY,4BAA4B;CA2DzE,CAAC;AAQF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"LDFileUpload.d.ts","sourceRoot":"","sources":["../../../src/components/LDFileUpload/LDFileUpload.tsx"],"names":[],"mappings":"AA8BA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAEf,OAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE9E,OAAuB,EAErB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EAEvB,MAAM,0CAA0C,CAAC;AAuFlD,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;AA8UD,MAAM,WAAW,+BAA+B;IAC9C,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoGD,MAAM,MAAM,4BAA4B,GAAG,cAAc,CAAC,oBAAoB,CAAC,CAAC;AA6BhF,MAAM,WAAW,iBACf,SACE,IAAI,CACF,qBAAqB,EACrB,UAAU,GAAG,YAAY,GAAG,cAAc,GAAG,MAAM,uBAAuB,CAC3E,EACD,uBAAuB;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,kCAAkC;AAClC,QAAA,MAAM,YAAY;qFAMf,iBAAiB;0DA1mBjB,qBAAqB;iEAmCrB,sBAAsB;wDA+FtB,yBAAyB;iGAgWzB,+BAA+B;2CA2FY,4BAA4B;CA2DzE,CAAC;AAQF,eAAe,YAAY,CAAC"}
@@ -201,23 +201,23 @@ const LinkRow = ({ link, index, linkNumber, placeholder, labelPlaceholder, handl
201
201
  * 드래그로 순서를 바꾸는 항목 래퍼.
202
202
  * 파일 카드는 누르면 교체 창이 열리고 링크 행에는 입력칸이 있어, 카드 전체가 아니라 손잡이로만 끈다.
203
203
  */
204
- const SortableAttachment = ({ id, name, children, }) => {
204
+ const SortableAttachment = ({ id, name, sortable, children, }) => {
205
205
  const { locked } = useFileUploadContext();
206
- const { setNodeRef, setActivatorNodeRef, attributes, listeners, transform, transition, isDragging, isSorting, } = useSortable({ id, disabled: locked });
206
+ const { setNodeRef, setActivatorNodeRef, attributes, listeners, transform, transition, isDragging, isSorting, } = useSortable({ id, disabled: locked || !sortable });
207
207
  return (_jsx("div", { ref: setNodeRef, className: cn(isDragging && 'relative z-10 opacity-80'), style: {
208
208
  transform: CSS.Transform.toString(transform),
209
209
  // 인덱스를 id로 쓰므로 놓는 순간 같은 노드에 다른 항목이 들어간다. 그때 transition이 돌면
210
210
  // 이전 자리에서 미끄러져 오는 것처럼 보이므로, 끄는 동안(isSorting)에만 애니메이션한다.
211
211
  transition: isSorting && !isDragging ? transition : undefined,
212
- }, children: children(_jsx("button", { type: "button", ref: setActivatorNodeRef, ...attributes, ...listeners, "aria-label": `${name} 순서 변경`, disabled: locked,
212
+ }, children: children(sortable && (_jsx("button", { type: "button", ref: setActivatorNodeRef, ...attributes, ...listeners, "aria-label": `${name} 순서 변경`, disabled: locked,
213
213
  // 손잡이 클릭이 카드로 올라가면 파일이 열린다
214
- onClick: (event) => event.stopPropagation(), className: "shrink-0 cursor-grab touch-none text-lb300 active:cursor-grabbing disabled:cursor-not-allowed", children: _jsx(GripVertical, { className: "size-5" }) })) }));
214
+ onClick: (event) => event.stopPropagation(), className: "shrink-0 cursor-grab touch-none text-lb300 active:cursor-grabbing disabled:cursor-not-allowed", children: _jsx(GripVertical, { className: "size-5" }) }))) }));
215
215
  };
216
216
  /**
217
- * 파일과 링크가 섞인 첨부 목록입니다. 손잡이를 끌어 순서를 바꿉니다.
217
+ * 파일과 링크가 섞인 첨부 목록입니다. `sortable`을 켜면 손잡이를 끌어 순서를 바꿉니다.
218
218
  * Root에 `attachmentList`·`setAttachmentList`를 넘겨야 합니다.
219
219
  */
220
- const AttachmentList = ({ placeholder = '링크를 입력해주세요', labelPlaceholder = '링크 이름', isExistUploadedAt = true, className, }) => {
220
+ const AttachmentList = ({ placeholder = '링크를 입력해주세요', labelPlaceholder = '링크 이름', isExistUploadedAt = true, sortable = false, className, }) => {
221
221
  const { attachmentList, moveAttachment } = useFileUploadContext();
222
222
  const classNames = useContext(StyleContext);
223
223
  // SSR에서 dnd-kit 접근성 id가 서버·클라이언트로 어긋나지 않게 고정한다.
@@ -235,12 +235,12 @@ const AttachmentList = ({ placeholder = '링크를 입력해주세요', labelPla
235
235
  return (_jsx(DndContext, { id: dndId, sensors: sensors, collisionDetection: closestCenter, modifiers: [restrictToVerticalAxis], onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: ids, strategy: verticalListSortingStrategy, children: _jsx("div", { className: cn('flex w-full flex-col gap-sm', className, classNames.cardList), children: attachmentList.map((item, index) => {
236
236
  const id = String(index);
237
237
  if (item.type === 'file') {
238
- return (_jsx(SortableAttachment, { id: id, name: item.file.fileName, children: (handle) => (_jsx(FileCard, { file: item.file, index: index, isExistUploadedAt: isExistUploadedAt, handle: handle })) }, id));
238
+ return (_jsx(SortableAttachment, { id: id, name: item.file.fileName, sortable: sortable, children: (handle) => (_jsx(FileCard, { file: item.file, index: index, isExistUploadedAt: isExistUploadedAt, handle: handle })) }, id));
239
239
  }
240
240
  const linkNumber = attachmentList
241
241
  .slice(0, index + 1)
242
242
  .filter((other) => other.type === 'link').length;
243
- return (_jsx(SortableAttachment, { id: id, name: `링크 ${linkNumber}`, children: (handle) => (_jsx(LinkRow, { link: item, index: index, linkNumber: linkNumber, placeholder: placeholder, labelPlaceholder: labelPlaceholder, handle: handle })) }, id));
243
+ return (_jsx(SortableAttachment, { id: id, name: `링크 ${linkNumber}`, sortable: sortable, children: (handle) => (_jsx(LinkRow, { link: item, index: index, linkNumber: linkNumber, placeholder: placeholder, labelPlaceholder: labelPlaceholder, handle: handle })) }, id));
244
244
  }) }) }) }));
245
245
  };
246
246
  /** 업로드 제한 조건을 안내합니다. */
@@ -11,7 +11,10 @@ export declare const isImage: (src: string) => boolean;
11
11
  export declare const isImageOrPdf: (src: string) => boolean;
12
12
  export declare const getFileIcon: (fileName: string) => ReactElement;
13
13
  export declare const getFileExtensionFromMimeType: (mimeType: TMimeType) => TFileExtension | string;
14
- export declare const validImageSize: (file: File) => Promise<boolean>;
14
+ export declare const validImageSize: (file: File, maxImageSize?: {
15
+ width: number;
16
+ height: number;
17
+ }) => Promise<boolean>;
15
18
  export declare const validFileSize: (file: File, maxSize: number) => boolean;
16
19
  export declare const validAllowedExtensions: (file: File, allowedExtensions: TMimeType[]) => boolean;
17
20
  export declare const getFileSizeUnit: (number: number) => string | number;
@@ -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;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,YAS/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"}
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,GACzB,MAAM,IAAI,EACV,eAAc;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAmB,KAC/D,OAAO,CAAC,OAAO,CAoBjB,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,EAAE,SAAS,MAAM,YAExD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,MAAM,IAAI,EACV,mBAAmB,SAAS,EAAE,YAS/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"}
@@ -42,13 +42,13 @@ export const getFileIcon = (fileName) => {
42
42
  export const getFileExtensionFromMimeType = (mimeType) => {
43
43
  return FILE_EXTENSIONS[mimeType] || mimeType.split('/')[1] || 'unknown';
44
44
  };
45
- export const validImageSize = (file) => {
45
+ export const validImageSize = (file, maxImageSize = MAX_IMAGE_SIZE) => {
46
46
  return new Promise((resolve) => {
47
47
  const image = new Image();
48
48
  const url = URL.createObjectURL(file);
49
49
  image.onload = () => {
50
- const isValid = image.naturalWidth <= MAX_IMAGE_SIZE.width &&
51
- image.naturalHeight <= MAX_IMAGE_SIZE.height;
50
+ const isValid = image.naturalWidth <= maxImageSize.width &&
51
+ image.naturalHeight <= maxImageSize.height;
52
52
  URL.revokeObjectURL(url);
53
53
  resolve(isValid);
54
54
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loword/loword-design-system",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "로워드 디자인 시스템 컴포넌트 패키지(Tailwind v4)",
5
5
  "keywords": [
6
6
  "react",