@loword/loword-design-system 0.5.4 → 0.5.5

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.
@@ -1,3 +1,4 @@
1
+ import { type TMimeType } from '../../constants/file.js';
1
2
  export interface LDEditorProps {
2
3
  content: string;
3
4
  onChange?: (html: string) => void;
@@ -13,7 +14,9 @@ export interface LDEditorProps {
13
14
  * 지정하지 않으면 붙여넣은 외부 이미지는 그대로 둔다.
14
15
  */
15
16
  allowedImageHosts?: string[];
17
+ /** 툴바 업로드·이미지 붙여넣기에서 허용할 MIME 타입. 지정하지 않으면 기본 허용 형식을 쓴다. */
18
+ allowedExtensions?: TMimeType[];
16
19
  }
17
- declare const LDEditor: ({ content, onChange, className, handleImageUpload, allowedImageHosts, }: LDEditorProps) => import("react/jsx-runtime").JSX.Element;
20
+ declare const LDEditor: ({ content, onChange, className, handleImageUpload, allowedImageHosts, allowedExtensions, }: LDEditorProps) => import("react/jsx-runtime").JSX.Element;
18
21
  export default LDEditor;
19
22
  //# sourceMappingURL=LDEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AAiKA,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;CAC9B;AAyUD,QAAA,MAAM,QAAQ,GAAI,yEAMf,aAAa,4CAqBf,CAAC;AA6lBF,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;CACjC;AAqVD,QAAA,MAAM,QAAQ,GAAI,4FAOf,aAAa,4CAgCf,CAAC;AAkmBF,eAAe,QAAQ,CAAC"}
@@ -80,9 +80,11 @@ 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) => {
84
- if (!validAllowedExtensions(file, TOOLBAR_ALLOWED_EXTENSIONS)) {
85
- const allowedFiles = TOOLBAR_ALLOWED_EXTENSIONS.map((item) => FILE_EXTENSIONS[item].toUpperCase()).join(', ');
83
+ const uploadImageFile = async (file, handleImageUpload, allowedExtensions = TOOLBAR_ALLOWED_EXTENSIONS) => {
84
+ if (!validAllowedExtensions(file, allowedExtensions)) {
85
+ const allowedFiles = allowedExtensions
86
+ .map((item) => FILE_EXTENSIONS[item].toUpperCase())
87
+ .join(', ');
86
88
  throw new Error(`지원하지 않는 파일 형식입니다. ${allowedFiles} 파일만 업로드 가능합니다.`);
87
89
  }
88
90
  if (!validFileSize(file, TOOLBAR_MAX_SIZE)) {
@@ -257,7 +259,7 @@ const ImagePaste = Extension.create({
257
259
  props: {
258
260
  decorations: (state) => placeholderKey.getState(state),
259
261
  handlePaste: (view, event, slice) => {
260
- const { handleImageUpload, allowedImageHosts } = getConfig();
262
+ const { handleImageUpload, allowedImageHosts, allowedExtensions } = getConfig();
261
263
  if (!handleImageUpload)
262
264
  return false;
263
265
  const html = event.clipboardData?.getData('text/html') ?? '';
@@ -284,10 +286,10 @@ const ImagePaste = Extension.create({
284
286
  ? files[0]
285
287
  : undefined;
286
288
  pasteAfterUpload(view, uploadAll(list.map((src) => isDataUrl(src)
287
- ? dataUrlToFile(src).then((file) => uploadImageFile(file, handleImageUpload))
289
+ ? dataUrlToFile(src).then((file) => uploadImageFile(file, handleImageUpload, allowedExtensions))
288
290
  : (copiedImage
289
291
  ? Promise.resolve(copiedImage)
290
- : urlToFile(src)).then((file) => uploadImageFile(file, handleImageUpload)))).then((srcs) => {
292
+ : urlToFile(src)).then((file) => uploadImageFile(file, handleImageUpload, allowedExtensions)))).then((srcs) => {
291
293
  const urls = new Map(list.map((src, index) => [src, srcs[index] ?? null]));
292
294
  return new Slice(replaceImages(slice.content, urls), slice.openStart, slice.openEnd);
293
295
  }));
@@ -296,7 +298,7 @@ const ImagePaste = Extension.create({
296
298
  // Office는 HTML과 함께 선택 영역을 찍은 PNG를 files에 넣는다. HTML이 있으면 파일은 무시한다.
297
299
  if (html || !files.length)
298
300
  return false;
299
- pasteAfterUpload(view, uploadAll(files.map((file) => uploadImageFile(file, handleImageUpload))).then((srcs) => {
301
+ pasteAfterUpload(view, uploadAll(files.map((file) => uploadImageFile(file, handleImageUpload, allowedExtensions))).then((srcs) => {
300
302
  const nodes = files.flatMap((file, index) => {
301
303
  const src = srcs[index];
302
304
  return src
@@ -318,18 +320,26 @@ const ImagePaste = Extension.create({
318
320
  ];
319
321
  },
320
322
  });
321
- const LDEditor = ({ content, onChange, className, handleImageUpload, allowedImageHosts, }) => {
323
+ const LDEditor = ({ content, onChange, className, handleImageUpload, allowedImageHosts, allowedExtensions, }) => {
322
324
  // 에디터는 첫 렌더의 extensions로 한 번만 만들어진다. 붙여넣기는 최신 props를 ref로 읽는다.
323
- const pasteConfigRef = useRef({ handleImageUpload, allowedImageHosts });
325
+ const pasteConfigRef = useRef({
326
+ handleImageUpload,
327
+ allowedImageHosts,
328
+ allowedExtensions,
329
+ });
324
330
  useEffect(() => {
325
- pasteConfigRef.current = { handleImageUpload, allowedImageHosts };
331
+ pasteConfigRef.current = {
332
+ handleImageUpload,
333
+ allowedImageHosts,
334
+ allowedExtensions,
335
+ };
326
336
  });
327
337
  return (_jsxs(EditorBase.Root, { extensions: [
328
338
  ...createEditorExtensions(),
329
339
  ImagePaste.configure({ getConfig: () => pasteConfigRef.current }),
330
- ], content: content, onChange: onChange, className: className, children: [_jsx(EditorToolbar, { handleImageUpload: handleImageUpload }), _jsx(EditorBase.Content, {})] }));
340
+ ], content: content, onChange: onChange, className: className, children: [_jsx(EditorToolbar, { handleImageUpload: handleImageUpload, allowedExtensions: allowedExtensions }), _jsx(EditorBase.Content, {})] }));
331
341
  };
332
- const EditorToolbar = ({ handleImageUpload, }) => {
342
+ const EditorToolbar = ({ handleImageUpload, allowedExtensions, }) => {
333
343
  const [linkUrl, setLinkUrl] = useState('');
334
344
  const [isMobile, setIsMobile] = useState(false);
335
345
  const { editor } = useEditorContext();
@@ -375,7 +385,7 @@ const EditorToolbar = ({ handleImageUpload, }) => {
375
385
  return;
376
386
  const file = files[0];
377
387
  try {
378
- const src = await uploadImageFile(file, handleImageUpload);
388
+ const src = await uploadImageFile(file, handleImageUpload, allowedExtensions);
379
389
  editor.commands.setImage({
380
390
  src,
381
391
  alt: file.name,
@@ -1,4 +1,4 @@
1
- import { type ComponentProps, type CSSProperties } from 'react';
1
+ import { type ComponentProps, type CSSProperties, type ReactNode } from 'react';
2
2
  import SelectBase, { type SelectOption } from '../../components/LDSelect/SelectBase.js';
3
3
  import type { Color, Size, Variant } from '../../types/common.js';
4
4
  import type { Subset } from '../../types/subset.js';
@@ -35,6 +35,8 @@ export interface LDSelectProps {
35
35
  style?: CSSProperties;
36
36
  /** 드롭다운 콘텐츠 영역 className */
37
37
  contentClassName?: string;
38
+ /** items가 비었을 때 드롭다운에 표시할 내용 */
39
+ emptyMessage?: ReactNode;
38
40
  /** 에러 상태 속성 */
39
41
  'aria-invalid'?: boolean | 'true' | 'false';
40
42
  /** 설명 요소 ID 연결 */
@@ -63,7 +65,7 @@ export type LDSelectItemTextProps = ComponentProps<typeof SelectBase.ItemText>;
63
65
  export type LDSelectItemIndicatorProps = ComponentProps<typeof SelectBase.ItemIndicator>;
64
66
  export type { SelectOption };
65
67
  declare const LDSelect: {
66
- ({ items, placeholder, value, defaultValue, onChange, disabled, name, variant, color, size, align, className, style, contentClassName, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, }: LDSelectProps): import("react/jsx-runtime").JSX.Element;
68
+ ({ items, placeholder, value, defaultValue, onChange, disabled, name, variant, color, size, align, className, style, contentClassName, emptyMessage, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, }: LDSelectProps): import("react/jsx-runtime").JSX.Element;
67
69
  Root: ({ variant, color, size, align, disabled, className, ...props }: LDSelectRootProps) => import("react/jsx-runtime").JSX.Element;
68
70
  Trigger: ({ className, ...props }: LDSelectTriggerProps) => import("react/jsx-runtime").JSX.Element;
69
71
  Value: ({ className, ...props }: LDSelectValueProps) => import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"LDSelect.d.ts","sourceRoot":"","sources":["../../../src/components/LDSelect/LDSelect.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LDSelect.d.ts","sourceRoot":"","sources":["../../../src/components/LDSelect/LDSelect.tsx"],"names":[],"mappings":"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"}
@@ -146,12 +146,14 @@ const Item = ({ className, ...props }) => {
146
146
  const ItemText = SelectBase.ItemText;
147
147
  /** 선택된 옵션에만 표시되는 Styled Compound 영역입니다. */
148
148
  const ItemIndicator = ({ className, ...props }) => (_jsx(SelectBase.ItemIndicator, { ...props, className: cn('ml-auto', className) }));
149
- const LDSelect = ({ items, placeholder = '선택해주세요', value, defaultValue, onChange, disabled = false, name, variant, color = 'neutral', size, align = 'left', className, style, contentClassName, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedby, }) => {
149
+ const LDSelect = ({ items, placeholder = '선택해주세요', value, defaultValue, onChange, disabled = false, name, variant, color = 'neutral', size, align = 'left', className, style, contentClassName, emptyMessage = '데이터가 없습니다.', 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedby, }) => {
150
150
  const iconSize = iconSizes[size ?? 'medium'];
151
151
  const resolvedValue = items.some((item) => item.value === value)
152
152
  ? value
153
153
  : undefined;
154
- return (_jsxs(Root, { value: resolvedValue, defaultValue: defaultValue, onChange: onChange, disabled: disabled, name: name, items: items, variant: variant, color: color, size: size, align: align, children: [_jsx(Trigger, { style: style, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, className: className, children: _jsxs("div", { className: "flex w-full items-center justify-center gap-sm px-3", children: [_jsx(Value, { placeholder: placeholder }), _jsxs("span", { className: "relative shrink-0", style: { width: iconSize, height: iconSize }, children: [_jsx(ChevronDown, { size: iconSize, className: "absolute top-0 left-0 text-neutral500 opacity-100 transition-opacity duration-300 ease-out group-data-[state=open]:opacity-0" }), _jsx(ChevronUp, { size: iconSize, className: "absolute top-0 left-0 text-neutral500 opacity-0 transition-opacity duration-300 ease-out group-data-[state=open]:opacity-100" })] })] }) }), _jsx(Content, { className: contentClassName, children: items.map((opt) => (_jsx(Item, { value: opt.value, children: _jsx(ItemText, { children: opt.label }) }, opt.value))) })] }));
154
+ return (_jsxs(Root, { value: resolvedValue, defaultValue: defaultValue, onChange: onChange, disabled: disabled, name: name, items: items, variant: variant, color: color, size: size, align: align, children: [_jsx(Trigger, { style: style, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, className: className, children: _jsxs("div", { className: "flex w-full items-center justify-center gap-sm px-3", children: [_jsx(Value, { placeholder: placeholder }), _jsxs("span", { className: "relative shrink-0", style: { width: iconSize, height: iconSize }, children: [_jsx(ChevronDown, { size: iconSize, className: "absolute top-0 left-0 text-neutral500 opacity-100 transition-opacity duration-300 ease-out group-data-[state=open]:opacity-0" }), _jsx(ChevronUp, { size: iconSize, className: "absolute top-0 left-0 text-neutral500 opacity-0 transition-opacity duration-300 ease-out group-data-[state=open]:opacity-100" })] })] }) }), _jsx(Content, { className: contentClassName, children: items.length === 0 ? (
155
+ // listbox는 option 자식이 필요하다(aria-required-children) — 선택 불가 option으로 둔다.
156
+ _jsx("li", { role: "option", "aria-disabled": "true", "aria-selected": "false", className: cn(itemVariants({ size: size ?? 'medium', selected: false }), 'cursor-default justify-center py-8 text-neutral500 hover:bg-transparent'), children: emptyMessage })) : (items.map((opt) => (_jsx(Item, { value: opt.value, children: _jsx(ItemText, { children: opt.label }) }, opt.value)))) })] }));
155
157
  };
156
158
  LDSelect.Root = Root;
157
159
  LDSelect.Trigger = Trigger;
@@ -1 +1 @@
1
- {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/constants/file.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;CAIjB,CAAC;AAEX,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAEX,uBAAuB;AACvB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BlB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,eAAe,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC;AAEjE,eAAO,MAAM,yBAAyB,EAEjC,SAAS,EAAE,CAAC;AAEjB,eAAO,MAAM,0BAA0B,ojBAEtC,CAAC;AAEF,2BAA2B;AAC3B,eAAO,MAAM,0BAA0B,EAAE,SAAS,EAQjD,CAAC;AAEF,iCAAiC;AACjC,eAAO,MAAM,gBAAgB,QAAwB,CAAC"}
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/constants/file.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;CAIjB,CAAC;AAEX,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAEX,uBAAuB;AACvB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BlB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,eAAe,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,SAAS,CAAC,CAAC;AAEjE,eAAO,MAAM,yBAAyB,EAEjC,SAAS,EAAE,CAAC;AAEjB,eAAO,MAAM,0BAA0B,ojBAEtC,CAAC;AAEF,2BAA2B;AAC3B,eAAO,MAAM,0BAA0B,EAAE,SAAS,EASjD,CAAC;AAEF,iCAAiC;AACjC,eAAO,MAAM,gBAAgB,QAAwB,CAAC"}
@@ -40,6 +40,7 @@ export const SUPPORTED_IMAGE_MIME_TYPES = SUPPORTED_FILE_MIME_TYPES.filter((type
40
40
  /** 에디터 툴바 이미지 업로드 허용 형식 */
41
41
  export const TOOLBAR_ALLOWED_EXTENSIONS = [
42
42
  'application/pdf',
43
+ 'image/gif',
43
44
  'image/jpg',
44
45
  'image/jpeg',
45
46
  'image/png',
package/dist/index.css CHANGED
@@ -2780,6 +2780,9 @@
2780
2780
  .py-5 {
2781
2781
  padding-block: calc(var(--spacing) * 5);
2782
2782
  }
2783
+ .py-8 {
2784
+ padding-block: calc(var(--spacing) * 8);
2785
+ }
2783
2786
  .py-10 {
2784
2787
  padding-block: calc(var(--spacing) * 10);
2785
2788
  }
@@ -5573,7 +5576,7 @@
5573
5576
  max-width: 100%;
5574
5577
  height: auto !important;
5575
5578
  display: block;
5576
- margin: 1rem auto;
5579
+ margin: 0 auto;
5577
5580
  }
5578
5581
  .ProseMirror img[style*='text-align: left'] {
5579
5582
  margin-left: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loword/loword-design-system",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "로워드 디자인 시스템 컴포넌트 패키지(Tailwind v4)",
5
5
  "keywords": [
6
6
  "react",
@@ -55,7 +55,7 @@
55
55
  max-width: 100%;
56
56
  height: auto !important;
57
57
  display: block;
58
- margin: 1rem auto;
58
+ margin: 0 auto;
59
59
  }
60
60
 
61
61
  .ProseMirror img[style*='text-align: left'] {