@loword/loword-design-system 0.7.0 → 0.7.2
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.
- package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts +3 -1
- package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts.map +1 -1
- package/dist/components/LDDateRangePicker/LDDateRangePicker.js +8 -4
- package/dist/components/LDEditor/LDEditor.d.ts +8 -1
- package/dist/components/LDEditor/LDEditor.d.ts.map +1 -1
- package/dist/components/LDEditor/LDEditor.js +17 -12
- package/dist/utils/file.d.ts +4 -1
- package/dist/utils/file.d.ts.map +1 -1
- package/dist/utils/file.js +3 -3
- package/package.json +1 -1
|
@@ -56,7 +56,9 @@ export interface LDDateRangePickerProps {
|
|
|
56
56
|
triggerClassName?: string;
|
|
57
57
|
/** 달력·시간 컬럼의 선택 강조 색 */
|
|
58
58
|
colorSet?: CalendarColorSet;
|
|
59
|
+
/** false면 daily 모드에서 시간 선택을 숨기고 날짜만 표시한다. 값의 시각은 바꾸지 않는다(LDDatePicker와 동일) */
|
|
60
|
+
isExistTime?: boolean;
|
|
59
61
|
}
|
|
60
|
-
declare const LDDateRangePicker: ({ variant, value, onChange, disabled, block, color, placeholder, dateFormat, timeFormat, isDisableAfterNow, isAutoClose, viewMode, initialValue, trailingIcon, onRangeComplete, onResetComplete, className, style, triggerClassName, colorSet, }: LDDateRangePickerProps) => import("react/jsx-runtime").JSX.Element;
|
|
62
|
+
declare const LDDateRangePicker: ({ variant, value, onChange, disabled, block, color, placeholder, dateFormat, timeFormat, isDisableAfterNow, isAutoClose, viewMode, initialValue, trailingIcon, onRangeComplete, onResetComplete, className, style, triggerClassName, colorSet, isExistTime, }: LDDateRangePickerProps) => import("react/jsx-runtime").JSX.Element;
|
|
61
63
|
export default LDDateRangePicker;
|
|
62
64
|
//# sourceMappingURL=LDDateRangePicker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LDDateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/LDDateRangePicker/LDDateRangePicker.tsx"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAKf,OAAmB,EACjB,KAAK,gBAAgB,EACtB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAQ7C,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAC3C,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAChE,KAAK,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAC/C,KAAK,sBAAsB,GAAG,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;AACpE,MAAM,MAAM,oBAAoB,GAAG,MAAM,CACvC,KAAK,EACL,SAAS,GAAG,OAAO,GAAG,QAAQ,CAC/B,CAAC;AAcF,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,gCAAgC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,KAAK,IAAI,CAAC;IAClD,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,2BAA2B;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,iBAAiB;IACjB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,4BAA4B;IAC5B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,EAAE,EAAE,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IAC5D,0BAA0B;IAC1B,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,uBAAuB;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"LDDateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/LDDateRangePicker/LDDateRangePicker.tsx"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAKf,OAAmB,EACjB,KAAK,gBAAgB,EACtB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAQ7C,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAC3C,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAChE,KAAK,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAC/C,KAAK,sBAAsB,GAAG,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;AACpE,MAAM,MAAM,oBAAoB,GAAG,MAAM,CACvC,KAAK,EACL,SAAS,GAAG,OAAO,GAAG,QAAQ,CAC/B,CAAC;AAcF,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,gCAAgC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,KAAK,IAAI,CAAC;IAClD,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,2BAA2B;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,iBAAiB;IACjB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,4BAA4B;IAC5B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,EAAE,EAAE,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IAC5D,0BAA0B;IAC1B,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,uBAAuB;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAwBD,QAAA,MAAM,iBAAiB,GAAI,+PAsBxB,sBAAsB,4CAqWxB,CAAC;AAiMF,eAAe,iBAAiB,CAAC"}
|
|
@@ -31,8 +31,10 @@ const variantColorClasses = {
|
|
|
31
31
|
danger: 'bg-transparent text-neutral900 border-none outline-2 outline-danger600 outline-solid -outline-offset-2',
|
|
32
32
|
},
|
|
33
33
|
};
|
|
34
|
-
const LDDateRangePicker = ({ variant = 'filled', value, onChange, disabled = false, block = false, color = 'neutral', placeholder, dateFormat, timeFormat = 'HH:mm:ss', isDisableAfterNow = false, isAutoClose = false, viewMode = 'daily', initialValue, trailingIcon = _jsx(Calendar, { size: 15, className: "text-mono400" }), onRangeComplete, onResetComplete, className, style, triggerClassName, colorSet, }) => {
|
|
34
|
+
const LDDateRangePicker = ({ variant = 'filled', value, onChange, disabled = false, block = false, color = 'neutral', placeholder, dateFormat, timeFormat = 'HH:mm:ss', isDisableAfterNow = false, isAutoClose = false, viewMode = 'daily', initialValue, trailingIcon = _jsx(Calendar, { size: 15, className: "text-mono400" }), onRangeComplete, onResetComplete, className, style, triggerClassName, colorSet, isExistTime = true, }) => {
|
|
35
35
|
const fmt = dateFormat ?? dateFormats[viewMode];
|
|
36
|
+
// 시간을 그리고 표시하는 건 daily 모드에서 isExistTime일 때뿐이다
|
|
37
|
+
const showTime = viewMode === 'daily' && isExistTime;
|
|
36
38
|
const [open, setOpen] = useState(false);
|
|
37
39
|
const [leftMonth, setLeftMonth] = useState(new Date());
|
|
38
40
|
const [rightMonth, setRightMonth] = useState(dayjs().add(1, 'month').toDate());
|
|
@@ -68,12 +70,14 @@ const LDDateRangePicker = ({ variant = 'filled', value, onChange, disabled = fal
|
|
|
68
70
|
to: r.to ? combineDateTime(r.to, toTimeRef.current) : undefined,
|
|
69
71
|
};
|
|
70
72
|
}, []);
|
|
71
|
-
const placeholderFmt =
|
|
73
|
+
const placeholderFmt = showTime
|
|
72
74
|
? `${dateFormats[viewMode]} ${DEFAULT_TIME_PLACEHOLDER}`
|
|
73
75
|
: dateFormats[viewMode];
|
|
74
76
|
const placeholderText = placeholder ?? `${placeholderFmt} ~ ${placeholderFmt}`;
|
|
75
77
|
const displayRange = composeRange(selectedRange);
|
|
76
|
-
const displayFmt =
|
|
78
|
+
const displayFmt = showTime
|
|
79
|
+
? `${fmt} ${normalizeTimeFormat(timeFormat)}`
|
|
80
|
+
: fmt;
|
|
77
81
|
/* 트리거의 접근 이름(aria-label)용 평문. 화면 표시는 renderDateRange가 담당한다 */
|
|
78
82
|
const displayText = (() => {
|
|
79
83
|
if (!displayRange?.from)
|
|
@@ -176,7 +180,7 @@ const LDDateRangePicker = ({ variant = 'filled', value, onChange, disabled = fal
|
|
|
176
180
|
: 'pointer-events-none opacity-0'), onClick: handleReset, children: _jsx(RotateCw, { size: 15 }) }), trailingIcon] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral-200 bg-white p-0 shadow-md", children: _jsxs("div", { style: {
|
|
177
181
|
'--calendar-accent': colorSet?.accent,
|
|
178
182
|
'--calendar-accent-bg': colorSet?.accentBg,
|
|
179
|
-
}, className: "flex flex-col [--calendar-accent-bg:var(--color-tintBlue)] [--calendar-accent:var(--color-lb500)]", children: [viewMode === 'daily' && (_jsxs("div", { className: "flex flex-row mobile:flex-col", children: [_jsxs("div", { className: "flex max-h-90 flex-row", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: selectedRange, onSelect: handleDailySelect, month: leftMonth, onMonthChange: setLeftMonth, endMonth: leftEndMonth, disabled: isDateDisabled, colorSet: colorSet }), _jsx(CalendarTimePicker, { value: fromTime, onChange: handleFromTime, colorSet: colorSet, className: "shrink-0" })] }), _jsx(LDDivider, { orientation: "vertical", className: "inline-block h-auto self-stretch mobile:hidden" }), _jsx(LDDivider, { orientation: "horizontal", className: "hidden w-auto self-stretch mobile:inline-block" }), _jsxs("div", { className: "flex max-h-90 flex-row", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: selectedRange, onSelect: handleDailySelect, month: rightMonth, onMonthChange: setRightMonth, startMonth: rightStartMonth, disabled: isDateDisabled, colorSet: colorSet }), _jsx(CalendarTimePicker, { value: toTime, onChange: handleToTime, colorSet: colorSet, className: "shrink-0" })] })] })), viewMode === 'monthly' && (_jsx(MonthRangePicker, { value: selectedRange, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), viewMode === 'yearly' && (_jsx(YearRangePicker, { value: selectedRange, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), !isAutoClose && (_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" })] }))] }) })] }) }));
|
|
183
|
+
}, className: "flex flex-col [--calendar-accent-bg:var(--color-tintBlue)] [--calendar-accent:var(--color-lb500)]", children: [viewMode === 'daily' && (_jsxs("div", { className: "flex flex-row mobile:flex-col", children: [_jsxs("div", { className: "flex max-h-90 flex-row", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: selectedRange, onSelect: handleDailySelect, month: leftMonth, onMonthChange: setLeftMonth, endMonth: leftEndMonth, disabled: isDateDisabled, colorSet: colorSet }), showTime && (_jsx(CalendarTimePicker, { value: fromTime, onChange: handleFromTime, colorSet: colorSet, className: "shrink-0" }))] }), _jsx(LDDivider, { orientation: "vertical", className: "inline-block h-auto self-stretch mobile:hidden" }), _jsx(LDDivider, { orientation: "horizontal", className: "hidden w-auto self-stretch mobile:inline-block" }), _jsxs("div", { className: "flex max-h-90 flex-row", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: selectedRange, onSelect: handleDailySelect, month: rightMonth, onMonthChange: setRightMonth, startMonth: rightStartMonth, disabled: isDateDisabled, colorSet: colorSet }), showTime && (_jsx(CalendarTimePicker, { value: toTime, onChange: handleToTime, colorSet: colorSet, className: "shrink-0" }))] })] })), viewMode === 'monthly' && (_jsx(MonthRangePicker, { value: selectedRange, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), viewMode === 'yearly' && (_jsx(YearRangePicker, { value: selectedRange, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), !isAutoClose && (_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" })] }))] }) })] }) }));
|
|
180
184
|
};
|
|
181
185
|
// ── MonthRangePicker ──
|
|
182
186
|
const MonthRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
|
|
@@ -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;
|
|
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,
|
|
91
|
-
throw new Error(`파일 크기가 너무 큽니다. ${getFileSizeUnit(
|
|
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
|
|
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,
|
|
290
|
+
? dataUrlToFile(src).then((file) => uploadImageFile(file, config))
|
|
290
291
|
: (copiedImage
|
|
291
292
|
? Promise.resolve(copiedImage)
|
|
292
|
-
: urlToFile(src)).then((file) => uploadImageFile(file,
|
|
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,
|
|
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 = (
|
|
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,
|
|
396
|
+
const src = await uploadImageFile(file, uploadConfig);
|
|
392
397
|
editor.commands.setImage({
|
|
393
398
|
src,
|
|
394
399
|
alt: file.name,
|
package/dist/utils/file.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/utils/file.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/utils/file.js
CHANGED
|
@@ -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 <=
|
|
51
|
-
image.naturalHeight <=
|
|
50
|
+
const isValid = image.naturalWidth <= maxImageSize.width &&
|
|
51
|
+
image.naturalHeight <= maxImageSize.height;
|
|
52
52
|
URL.revokeObjectURL(url);
|
|
53
53
|
resolve(isValid);
|
|
54
54
|
};
|