@loword/loword-design-system 0.0.6 → 0.0.7
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/Icon/LucideIcon.d.ts.map +1 -1
- package/dist/components/Icon/LucideIcon.js +9 -1
- package/dist/components/LDAnchor/AnchorBase.d.ts +24 -0
- package/dist/components/LDAnchor/AnchorBase.d.ts.map +1 -0
- package/dist/components/LDAnchor/AnchorBase.js +69 -0
- package/dist/components/LDAnchor/LDAnchor.d.ts +10 -0
- package/dist/components/LDAnchor/LDAnchor.d.ts.map +1 -0
- package/dist/components/LDAnchor/LDAnchor.js +14 -0
- package/dist/components/LDAutoComplete/AutoCompleteBase.d.ts +36 -0
- package/dist/components/LDAutoComplete/AutoCompleteBase.d.ts.map +1 -0
- package/dist/components/LDAutoComplete/AutoCompleteBase.js +175 -0
- package/dist/components/LDAutoComplete/LDAutoComplete.d.ts +19 -0
- package/dist/components/LDAutoComplete/LDAutoComplete.d.ts.map +1 -0
- package/dist/components/LDAutoComplete/LDAutoComplete.js +7 -0
- package/dist/components/LDEditor/EditorBase.js +1 -1
- package/dist/components/LDEditor/LDEditor.d.ts.map +1 -1
- package/dist/components/LDEditor/LDEditor.js +1 -1
- package/dist/components/LDFileUpload/FileUploadBase.d.ts +52 -0
- package/dist/components/LDFileUpload/FileUploadBase.d.ts.map +1 -0
- package/dist/components/LDFileUpload/FileUploadBase.js +186 -0
- package/dist/components/LDFileUpload/LDFileUpload.d.ts +16 -0
- package/dist/components/LDFileUpload/LDFileUpload.d.ts.map +1 -0
- package/dist/components/LDFileUpload/LDFileUpload.js +8 -0
- package/dist/components/LDFileUpload/LDFileUploadList.d.ts +17 -0
- package/dist/components/LDFileUpload/LDFileUploadList.d.ts.map +1 -0
- package/dist/components/LDFileUpload/LDFileUploadList.js +8 -0
- package/dist/components/LDFileUpload/LDImageUpload.d.ts +16 -0
- package/dist/components/LDFileUpload/LDImageUpload.d.ts.map +1 -0
- package/dist/components/LDFileUpload/LDImageUpload.js +8 -0
- package/dist/components/LDFileUpload/LDImageUploadList.d.ts +17 -0
- package/dist/components/LDFileUpload/LDImageUploadList.d.ts.map +1 -0
- package/dist/components/LDFileUpload/LDImageUploadList.js +8 -0
- package/dist/components/LDInput/LDInput.d.ts +2 -1
- package/dist/components/LDInput/LDInput.d.ts.map +1 -1
- package/dist/components/LDInput/LDInput.js +6 -6
- package/dist/constants/file.d.ts +1 -0
- package/dist/constants/file.d.ts.map +1 -1
- package/dist/constants/file.js +1 -0
- package/dist/index.css +239 -4
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/utils/file.d.ts +2 -0
- package/dist/utils/file.d.ts.map +1 -1
- package/dist/utils/file.js +35 -2
- package/package.json +1 -1
- package/src/styles/components/auto-complete.css +72 -0
- package/src/styles/components/index.css +1 -0
- package/dist/components/LDFileUpload/LDFileUploadBase.d.ts +0 -50
- package/dist/components/LDFileUpload/LDFileUploadBase.d.ts.map +0 -1
- package/dist/components/LDFileUpload/LDFileUploadBase.js +0 -102
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LucideIcon.d.ts","sourceRoot":"","sources":["../../../src/components/Icon/LucideIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,EA0BL,KAAK,UAAU,IAAI,cAAc,
|
|
1
|
+
{"version":3,"file":"LucideIcon.d.ts","sourceRoot":"","sources":["../../../src/components/Icon/LucideIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,EA0BL,KAAK,UAAU,IAAI,cAAc,EAalC,MAAM,cAAc,CAAC;AAEtB,QAAA,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAsChD,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,YAAY,CAAC;AAEjD,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,QAAA,MAAM,UAAU,GAAI,2BAA2B,gBAAgB,mDAQ9D,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { ArrowLeft, ArrowRight, Check, ChevronLeft, ChevronRight, ChevronDown, ChevronUp, Copy, Ellipsis, Pencil, Plus, Search, Trash, Trash2, X, ArrowUpRight, Wand, CloudDownload, Calendar, RefreshCw, Settings, RotateCw, Clock, EyeClosed, Minus, Eye, EyeOff, CircleAlert, EllipsisVertical, } from 'lucide-react';
|
|
2
|
+
import { ArrowLeft, ArrowRight, Check, ChevronLeft, ChevronRight, ChevronDown, ChevronUp, Copy, Ellipsis, Pencil, Plus, Search, Trash, Trash2, X, ArrowUpRight, Wand, CloudDownload, Calendar, RefreshCw, Settings, RotateCw, Clock, EyeClosed, Minus, Eye, EyeOff, CircleAlert, EllipsisVertical, Images, File, FileText, FileImage, FileSpreadsheet, FileJson, FileArchive, Repeat, } from 'lucide-react';
|
|
3
3
|
const LUCIDE_ICONS = {
|
|
4
4
|
arrowLeft: ArrowLeft,
|
|
5
5
|
arrowRight: ArrowRight,
|
|
@@ -30,6 +30,14 @@ const LUCIDE_ICONS = {
|
|
|
30
30
|
eyeOff: EyeOff,
|
|
31
31
|
circleAlert: CircleAlert,
|
|
32
32
|
ellipsisVertical: EllipsisVertical,
|
|
33
|
+
images: Images,
|
|
34
|
+
file: File,
|
|
35
|
+
fileText: FileText,
|
|
36
|
+
fileImage: FileImage,
|
|
37
|
+
fileSpreadsheet: FileSpreadsheet,
|
|
38
|
+
fileJson: FileJson,
|
|
39
|
+
fileArchive: FileArchive,
|
|
40
|
+
repeat: Repeat,
|
|
33
41
|
};
|
|
34
42
|
const LucideIcon = ({ name, className, size }) => {
|
|
35
43
|
const IconComponent = LUCIDE_ICONS[name];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
interface RootProps {
|
|
3
|
+
targets: string[];
|
|
4
|
+
sections: ReactNode[];
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export interface NavigationClassNames {
|
|
8
|
+
root?: string;
|
|
9
|
+
item?: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
dot?: string;
|
|
12
|
+
line?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const AnchorBase: {
|
|
15
|
+
Root: (props: RootProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
Navigation: ({ classNames }: {
|
|
17
|
+
classNames?: NavigationClassNames;
|
|
18
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
Sections: ({ sectionClassName }: {
|
|
20
|
+
sectionClassName?: string;
|
|
21
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
};
|
|
23
|
+
export default AnchorBase;
|
|
24
|
+
//# sourceMappingURL=AnchorBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnchorBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDAnchor/AnchorBase.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAmBf,UAAU,SAAS;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAkED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAsDD,eAAO,MAAM,UAAU;kBA5HF,SAAS;iCAwEM;QAAE,UAAU,CAAC,EAAE,oBAAoB,CAAA;KAAE;qCAgCjC;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE;CAwBpE,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useRef, useState, } from 'react';
|
|
3
|
+
const AnchorContext = createContext(null);
|
|
4
|
+
const useAnchorContext = () => {
|
|
5
|
+
const anchorContext = useContext(AnchorContext);
|
|
6
|
+
if (!anchorContext)
|
|
7
|
+
throw new Error('LDAnchor 하위 컴포넌트는 Root 내부에서 사용해야 합니다.');
|
|
8
|
+
return anchorContext;
|
|
9
|
+
};
|
|
10
|
+
const Root = (props) => {
|
|
11
|
+
const [index, setIndex] = useState(0);
|
|
12
|
+
const sectionRefs = useRef(Array(props.sections.length).fill(null));
|
|
13
|
+
const moveToSection = (targetIndex) => {
|
|
14
|
+
setIndex(targetIndex);
|
|
15
|
+
sectionRefs.current?.[targetIndex]?.scrollIntoView({
|
|
16
|
+
behavior: 'smooth',
|
|
17
|
+
block: 'start',
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
sectionRefs.current = Array.from({ length: props.sections.length }, (_, idx) => sectionRefs.current[idx] ?? null);
|
|
22
|
+
}, [props.sections.length]);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const observer = new IntersectionObserver((entries) => {
|
|
25
|
+
entries.forEach((entry) => {
|
|
26
|
+
if (entry.isIntersecting) {
|
|
27
|
+
const index = sectionRefs.current.indexOf(entry.target);
|
|
28
|
+
setIndex(index);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}, {
|
|
32
|
+
threshold: 0.5,
|
|
33
|
+
});
|
|
34
|
+
sectionRefs.current.forEach((ref) => {
|
|
35
|
+
if (ref) {
|
|
36
|
+
observer.observe(ref);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return () => {
|
|
40
|
+
observer.disconnect();
|
|
41
|
+
};
|
|
42
|
+
}, [props.sections.length]);
|
|
43
|
+
return (_jsx(AnchorContext.Provider, { value: {
|
|
44
|
+
targets: props.targets,
|
|
45
|
+
sections: props.sections,
|
|
46
|
+
index,
|
|
47
|
+
sectionRefs,
|
|
48
|
+
moveToSection,
|
|
49
|
+
}, children: props.children }));
|
|
50
|
+
};
|
|
51
|
+
const Navigation = ({ classNames }) => {
|
|
52
|
+
const { targets, index, moveToSection } = useAnchorContext();
|
|
53
|
+
return (_jsx("nav", { className: classNames?.root, children: targets.map((target, idx) => {
|
|
54
|
+
const isActive = idx === index;
|
|
55
|
+
return (_jsxs("div", { className: "flex flex-col items-end", children: [_jsxs("button", { className: classNames?.item, "aria-current": isActive ? 'true' : undefined, onClick: () => moveToSection(idx), children: [_jsx("span", { "data-active": isActive, className: classNames?.label, children: target }), _jsx("span", { "data-active": isActive, className: classNames?.dot })] }), idx < targets.length - 1 && (_jsx("span", { "data-active": idx + 1 === index, className: classNames?.line }))] }, `${target}_${idx}`));
|
|
56
|
+
}) }));
|
|
57
|
+
};
|
|
58
|
+
const Sections = ({ sectionClassName }) => {
|
|
59
|
+
const { sections, sectionRefs } = useAnchorContext();
|
|
60
|
+
return (_jsx(_Fragment, { children: sections.map((item, idx) => (_jsx("section", { ref: (el) => {
|
|
61
|
+
sectionRefs.current[idx] = el;
|
|
62
|
+
}, className: sectionClassName, children: item }, `section_content_${idx}`))) }));
|
|
63
|
+
};
|
|
64
|
+
export const AnchorBase = {
|
|
65
|
+
Root,
|
|
66
|
+
Navigation,
|
|
67
|
+
Sections,
|
|
68
|
+
};
|
|
69
|
+
export default AnchorBase;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface LDAnchorProps {
|
|
3
|
+
targets: string[];
|
|
4
|
+
sections: ReactNode[];
|
|
5
|
+
className?: string;
|
|
6
|
+
navigationClassName?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const LDAnchor: (props: LDAnchorProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default LDAnchor;
|
|
10
|
+
//# sourceMappingURL=LDAnchor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDAnchor.d.ts","sourceRoot":"","sources":["../../../src/components/LDAnchor/LDAnchor.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,QAAQ,GAAI,OAAO,aAAa,4CAqBrC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import cn from '../../utils/cn.js';
|
|
4
|
+
import AnchorBase from './AnchorBase.js';
|
|
5
|
+
const LDAnchor = (props) => {
|
|
6
|
+
return (_jsx(AnchorBase.Root, { targets: props.targets, sections: props.sections, children: _jsxs("div", { className: cn('relative flex flex-col gap-sm', props.className), children: [_jsx(AnchorBase.Navigation, { classNames: {
|
|
7
|
+
root: cn('fixed left-0 top-1/2 -translate-y-1/2 flex flex-col', props.navigationClassName),
|
|
8
|
+
item: 'flex flex-row items-center justify-between cursor-pointer w-full',
|
|
9
|
+
label: 'flex items-center px-md text-lb100 ld-transition data-[active=true]:text-lb500',
|
|
10
|
+
dot: 'size-2 rounded-full bg-lb100 outline-lb500 ld-transition data-[active=true]:bg-transparent data-[active=true]:outline-3',
|
|
11
|
+
line: 'h-20 w-0.5 mr-0.75 bg-lb100 ld-transition data-[active=true]:bg-lb500',
|
|
12
|
+
} }), _jsx(AnchorBase.Sections, { sectionClassName: "flex flex-col rounded-md px-md py-sm" })] }) }));
|
|
13
|
+
};
|
|
14
|
+
export default LDAnchor;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ReactNode, type Ref } from 'react';
|
|
2
|
+
import { type InputSize } from '../../components/LDInput/LDInput.js';
|
|
3
|
+
export interface IAutoCompleteItem {
|
|
4
|
+
id: string | number;
|
|
5
|
+
}
|
|
6
|
+
interface RootProps<T extends IAutoCompleteItem> {
|
|
7
|
+
displayField: Extract<keyof T, string>;
|
|
8
|
+
subFields?: Extract<keyof T, string>[];
|
|
9
|
+
onSelectedItem?: (item: T | null) => void;
|
|
10
|
+
onChange: (query: string) => Promise<T[] | undefined>;
|
|
11
|
+
className?: string;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
ref?: Ref<HTMLDivElement>;
|
|
14
|
+
}
|
|
15
|
+
interface InputProps {
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
size?: InputSize;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
interface ListProps {
|
|
21
|
+
size?: InputSize;
|
|
22
|
+
className?: string;
|
|
23
|
+
emptyMessage?: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
interface ItemProps {
|
|
26
|
+
item: IAutoCompleteItem;
|
|
27
|
+
index: number;
|
|
28
|
+
}
|
|
29
|
+
export declare const LDAutoCompleteBase: {
|
|
30
|
+
Root: <T extends IAutoCompleteItem>({ displayField, subFields, onSelectedItem, onChange, className, children, ref, }: RootProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
Input: ({ placeholder, size, className, }: InputProps) => import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
List: ({ size, className, emptyMessage, }: ListProps) => import("react/jsx-runtime").JSX.Element;
|
|
33
|
+
Item: ({ item, index }: ItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
};
|
|
35
|
+
export default LDAutoCompleteBase;
|
|
36
|
+
//# sourceMappingURL=AutoCompleteBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutoCompleteBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDAutoComplete/AutoCompleteBase.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,GAAG,EAST,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,kCAAkC,CAAC;AAG1C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB;AA4CD,UAAU,SAAS,CAAC,CAAC,SAAS,iBAAiB;IAC7C,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;IACvC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,GAAG,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;CAC3B;AAwJD,UAAU,UAAU;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsCD,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B;AAgDD,UAAU,SAAS;IACjB,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAuCD,eAAO,MAAM,kBAAkB;WA9RjB,CAAC,SAAS,iBAAiB,oFAQtC,SAAS,CAAC,CAAC,CAAC;+CAwJZ,UAAU;+CA0CV,SAAS;4BA+CmB,SAAS;CA0CvC,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useRef, useState, } from 'react';
|
|
4
|
+
import LDSpinner from '../../components/LDSpinner/LDSpinner.js';
|
|
5
|
+
import { inputSizeClasses, } from '../../components/LDInput/LDInput.js';
|
|
6
|
+
import cn from '../../utils/cn.js';
|
|
7
|
+
const getItemValue = (item, field) => item[field];
|
|
8
|
+
const AutoCompleteContext = createContext(null);
|
|
9
|
+
const useAutoCompleteContext = () => {
|
|
10
|
+
const autoCompeleteContext = useContext(AutoCompleteContext);
|
|
11
|
+
if (!autoCompeleteContext)
|
|
12
|
+
throw new Error('LDAutoComplete 하위 컴포넌트는 Root 내부에서 사용해야 합니다.');
|
|
13
|
+
return autoCompeleteContext;
|
|
14
|
+
};
|
|
15
|
+
const autoCompleteSizeClasses = {
|
|
16
|
+
xSmall: 'autocomplete-2xs',
|
|
17
|
+
small: 'autocomplete-xs',
|
|
18
|
+
medium: 'autocomplete-sm',
|
|
19
|
+
large: 'autocomplete-md',
|
|
20
|
+
big: 'autocomplete-lg',
|
|
21
|
+
xLarge: 'autocomplete-xl',
|
|
22
|
+
};
|
|
23
|
+
const Root = ({ displayField, subFields, onSelectedItem, onChange, className, children, ref, }) => {
|
|
24
|
+
const [query, setQuery] = useState('');
|
|
25
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
26
|
+
const [options, setOptions] = useState([]);
|
|
27
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
28
|
+
const [focusedIdx, setFocusedIdx] = useState(-1);
|
|
29
|
+
const [isComposing, setIsComposing] = useState(false);
|
|
30
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
31
|
+
const wrapperRef = useRef(null);
|
|
32
|
+
const itemRefs = useRef([]);
|
|
33
|
+
const combinedRef = useCallback((node) => {
|
|
34
|
+
wrapperRef.current = node;
|
|
35
|
+
if (typeof ref === 'function')
|
|
36
|
+
ref(node);
|
|
37
|
+
else if (ref)
|
|
38
|
+
ref.current = node;
|
|
39
|
+
}, [ref]);
|
|
40
|
+
const handleSelect = (item) => {
|
|
41
|
+
setSelectedItem(item);
|
|
42
|
+
setQuery(String(item[displayField] ?? ''));
|
|
43
|
+
setIsOpen(false);
|
|
44
|
+
setFocusedIdx(-1);
|
|
45
|
+
onSelectedItem?.(item);
|
|
46
|
+
};
|
|
47
|
+
const handleContextSelect = (item) => {
|
|
48
|
+
const option = options.find((candidate) => candidate === item);
|
|
49
|
+
if (option)
|
|
50
|
+
handleSelect(option);
|
|
51
|
+
};
|
|
52
|
+
const handleKeyDown = (e) => {
|
|
53
|
+
if (isComposing)
|
|
54
|
+
return;
|
|
55
|
+
if (e.key === 'Enter') {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
if (isOpen && focusedIdx >= 0 && focusedIdx < options.length) {
|
|
58
|
+
const focused = options[focusedIdx];
|
|
59
|
+
if (focused)
|
|
60
|
+
handleSelect(focused);
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!isOpen)
|
|
65
|
+
return;
|
|
66
|
+
if (options.length === 0)
|
|
67
|
+
return;
|
|
68
|
+
switch (e.key) {
|
|
69
|
+
case 'ArrowDown':
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
setFocusedIdx((prev) => (prev < options.length - 1 ? prev + 1 : prev));
|
|
72
|
+
break;
|
|
73
|
+
case 'ArrowUp':
|
|
74
|
+
e.preventDefault();
|
|
75
|
+
setFocusedIdx((prev) => (prev > 0 ? prev - 1 : -1));
|
|
76
|
+
break;
|
|
77
|
+
case 'Tab':
|
|
78
|
+
e.preventDefault();
|
|
79
|
+
if (e.shiftKey) {
|
|
80
|
+
setFocusedIdx((prev) => (prev > 0 ? prev - 1 : -1));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
setFocusedIdx((prev) => prev < options.length - 1 ? prev + 1 : prev);
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const handleChange = async (text) => {
|
|
89
|
+
setQuery(text);
|
|
90
|
+
if (!text)
|
|
91
|
+
return;
|
|
92
|
+
setIsLoading(true);
|
|
93
|
+
const list = await onChange(text);
|
|
94
|
+
setOptions(list ?? []);
|
|
95
|
+
setIsLoading(false);
|
|
96
|
+
};
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (query === '') {
|
|
99
|
+
setOptions([]);
|
|
100
|
+
setSelectedItem(null);
|
|
101
|
+
setIsOpen(false);
|
|
102
|
+
onSelectedItem?.(null);
|
|
103
|
+
}
|
|
104
|
+
else if (String(selectedItem?.[displayField] ?? '') !== query) {
|
|
105
|
+
setIsOpen(true);
|
|
106
|
+
}
|
|
107
|
+
setFocusedIdx(-1);
|
|
108
|
+
}, [query]);
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
const handleClickOverlay = (e) => {
|
|
111
|
+
if (!wrapperRef.current?.contains(e.target)) {
|
|
112
|
+
setIsOpen(false);
|
|
113
|
+
setFocusedIdx(-1);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
document.addEventListener('mousedown', handleClickOverlay);
|
|
117
|
+
return () => {
|
|
118
|
+
document.removeEventListener('mousedown', handleClickOverlay);
|
|
119
|
+
};
|
|
120
|
+
}, []);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
if (focusedIdx === -1)
|
|
123
|
+
return;
|
|
124
|
+
if (!itemRefs.current[focusedIdx])
|
|
125
|
+
return;
|
|
126
|
+
itemRefs.current[focusedIdx]?.scrollIntoView({ block: 'nearest' });
|
|
127
|
+
}, [focusedIdx]);
|
|
128
|
+
return (_jsx(AutoCompleteContext.Provider, { value: {
|
|
129
|
+
query,
|
|
130
|
+
isOpen,
|
|
131
|
+
isLoading,
|
|
132
|
+
options,
|
|
133
|
+
focusedIdx,
|
|
134
|
+
displayField,
|
|
135
|
+
subFields,
|
|
136
|
+
handleChange,
|
|
137
|
+
handleKeyDown,
|
|
138
|
+
handleSelect: handleContextSelect,
|
|
139
|
+
setIsOpen,
|
|
140
|
+
setFocusedIdx,
|
|
141
|
+
setIsComposing,
|
|
142
|
+
itemRefs,
|
|
143
|
+
}, children: _jsx("div", { ref: combinedRef, className: cn('relative z-40 w-full', className), children: children }) }));
|
|
144
|
+
};
|
|
145
|
+
const Input = ({ placeholder = '검색어를 입력하세요', size = 'medium', className, }) => {
|
|
146
|
+
const { query, isOpen, handleChange, handleKeyDown, setIsComposing, setIsOpen, } = useAutoCompleteContext();
|
|
147
|
+
return (_jsx("input", { type: "text", placeholder: placeholder, value: query, onChange: (e) => handleChange(e.target.value), onKeyDown: handleKeyDown, onCompositionStart: () => setIsComposing(true), onCompositionEnd: () => setIsComposing(false), onFocus: () => {
|
|
148
|
+
if (query)
|
|
149
|
+
setIsOpen(true);
|
|
150
|
+
}, className: cn('w-full rounded-[5px]! border-transparent bg-neutral50 outline-2', inputSizeClasses[size], isOpen ? 'bg-tintBlue outline-lb500' : 'outline-0', className) }));
|
|
151
|
+
};
|
|
152
|
+
const List = ({ size = 'medium', className, emptyMessage = '조회하신 데이터가 없습니다.', }) => {
|
|
153
|
+
const { isOpen, isLoading, options } = useAutoCompleteContext();
|
|
154
|
+
return (_jsxs("div", { className: cn('overflow-y-auto absolute left-0 mt-1 w-full bg-white border shadow-md rounded-[5px] border-mono300 h-45 ld-transition', autoCompleteSizeClasses[size], isOpen
|
|
155
|
+
? 'visible opacity-100 pointer-events-auto'
|
|
156
|
+
: 'invisible opacity-0 pointer-events-none', className), children: [_jsx("ul", { className: cn('ld-transition', options.length > 0 ? 'opacity-100 visible' : 'opacity-0 invisible'), children: options.map((item, index) => (_jsx(Item, { item: item, index: index }, item.id))) }), _jsx("div", { className: cn('flex items-center justify-center text-neutral500 transition-opacity duration-300 ease-in-out', options.length === 0
|
|
157
|
+
? 'opacity-100 visible h-full'
|
|
158
|
+
: 'opacity-0 invisible h-0'), children: isLoading ? (_jsx(LDSpinner, { size: size, className: "text-lb500!" })) : (emptyMessage) })] }));
|
|
159
|
+
};
|
|
160
|
+
const Item = ({ item, index }) => {
|
|
161
|
+
const { displayField, subFields, focusedIdx, setFocusedIdx, handleSelect, itemRefs, } = useAutoCompleteContext();
|
|
162
|
+
return (_jsxs("li", { ref: (el) => {
|
|
163
|
+
itemRefs.current[index] = el;
|
|
164
|
+
}, className: cn('autocomplete-item flex flex-col cursor-pointer ld-transition border-b border-mono300', focusedIdx === index ? 'bg-tintBlue' : 'hover:bg-mono100'), onClick: () => handleSelect(item), onMouseEnter: () => setFocusedIdx(index), children: [_jsx("div", { className: "truncate text-black", children: String(getItemValue(item, displayField) ?? '') }), subFields && subFields.length > 0 && (_jsx("span", { className: "autocomplete-secondary truncate text-neutral500", children: subFields
|
|
165
|
+
.map((field) => String(getItemValue(item, field) ?? ''))
|
|
166
|
+
.filter(Boolean)
|
|
167
|
+
.join(' / ') }))] }));
|
|
168
|
+
};
|
|
169
|
+
export const LDAutoCompleteBase = {
|
|
170
|
+
Root,
|
|
171
|
+
Input,
|
|
172
|
+
List,
|
|
173
|
+
Item,
|
|
174
|
+
};
|
|
175
|
+
export default LDAutoCompleteBase;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReactNode, Ref } from 'react';
|
|
2
|
+
import { type IAutoCompleteItem } from './AutoCompleteBase.js';
|
|
3
|
+
import type { InputSize } from '../LDInput/LDInput.js';
|
|
4
|
+
export interface LDAutoCompleteProps<T extends IAutoCompleteItem> {
|
|
5
|
+
displayField: Extract<keyof T, string>;
|
|
6
|
+
subFields?: Extract<keyof T, string>[];
|
|
7
|
+
onChange: (query: string) => Promise<T[] | undefined>;
|
|
8
|
+
onSelectedItem?: (item: T | null) => void;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
size?: InputSize;
|
|
11
|
+
emptyMessage?: ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
inputClassName?: string;
|
|
14
|
+
listClassName?: string;
|
|
15
|
+
ref?: Ref<HTMLDivElement>;
|
|
16
|
+
}
|
|
17
|
+
declare const LDAutoComplete: <T extends IAutoCompleteItem>({ displayField, subFields, onChange, onSelectedItem, placeholder, size, emptyMessage, className, inputClassName, listClassName, ref, }: LDAutoCompleteProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export default LDAutoComplete;
|
|
19
|
+
//# sourceMappingURL=LDAutoComplete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LDAutoComplete.d.ts","sourceRoot":"","sources":["../../../src/components/LDAutoComplete/LDAutoComplete.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5C,OAA2B,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,iBAAiB;IAC9D,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC;IACvC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC;IACtD,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;CAC3B;AAED,QAAA,MAAM,cAAc,GAAI,CAAC,SAAS,iBAAiB,EAAE,wIAYlD,mBAAmB,CAAC,CAAC,CAAC,4CAsBxB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import LDAutoCompleteBase from './AutoCompleteBase.js';
|
|
4
|
+
const LDAutoComplete = ({ displayField, subFields, onChange, onSelectedItem, placeholder, size, emptyMessage, className, inputClassName, listClassName, ref, }) => {
|
|
5
|
+
return (_jsxs(LDAutoCompleteBase.Root, { displayField: displayField, subFields: subFields, onChange: onChange, onSelectedItem: onSelectedItem, className: className, ref: ref, children: [_jsx(LDAutoCompleteBase.Input, { placeholder: placeholder, size: size, className: inputClassName }), _jsx(LDAutoCompleteBase.List, { size: size, className: listClassName, emptyMessage: emptyMessage })] }));
|
|
6
|
+
};
|
|
7
|
+
export default LDAutoComplete;
|
|
@@ -30,7 +30,7 @@ const Root = ({ extensions, content = '', onChange, className, children, }) => {
|
|
|
30
30
|
editor.commands.setContent(content || '');
|
|
31
31
|
}
|
|
32
32
|
}, [content, editor]);
|
|
33
|
-
return (_jsx(EditorContext.Provider, { value: { editor }, children: _jsx("div", { className:
|
|
33
|
+
return (_jsx(EditorContext.Provider, { value: { editor }, children: _jsx("div", { className: "w-full", children: editor && children }) }));
|
|
34
34
|
};
|
|
35
35
|
const Content = ({ className }) => {
|
|
36
36
|
const { editor } = useEditorContext();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AA0EA,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,
|
|
1
|
+
{"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AA0EA,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;AAmXF,eAAe,QAAQ,CAAC"}
|
|
@@ -38,7 +38,7 @@ const iconBtn = 'p-1 rounded-lg cursor-pointer transition hover:bg-mono100 disab
|
|
|
38
38
|
const activeBtn = 'bg-mono100';
|
|
39
39
|
const LDDivider = () => _jsx("div", { className: "w-px h-6 bg-neutral200 mx-1" });
|
|
40
40
|
const LDEditor = ({ content, onChange, className, handleImageUpload, }) => {
|
|
41
|
-
return (_jsxs(EditorBase.Root, { extensions: createEditorExtensions(), content: content, onChange: onChange, children: [_jsx(EditorToolbar, { handleImageUpload: handleImageUpload }), _jsx(EditorBase.Content, {
|
|
41
|
+
return (_jsxs(EditorBase.Root, { extensions: createEditorExtensions(), content: content, onChange: onChange, className: className, children: [_jsx(EditorToolbar, { handleImageUpload: handleImageUpload }), _jsx(EditorBase.Content, {})] }));
|
|
42
42
|
};
|
|
43
43
|
const EditorToolbar = ({ handleImageUpload, }) => {
|
|
44
44
|
const [linkUrl, setLinkUrl] = useState('');
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Dispatch, type ReactNode, SetStateAction } from 'react';
|
|
2
|
+
import { TMimeType } from '../../constants/file.js';
|
|
3
|
+
import { type LDButtonProps } from '../LDButton/LDButton.js';
|
|
4
|
+
import { IFile } from '../../utils/file.js';
|
|
5
|
+
interface FileUploadContextType {
|
|
6
|
+
recommendedSize?: {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
};
|
|
10
|
+
maxSize: number;
|
|
11
|
+
allowedExtensions: TMimeType[];
|
|
12
|
+
fileList: IFile[];
|
|
13
|
+
setFileList: Dispatch<SetStateAction<IFile[]>>;
|
|
14
|
+
maxFileCount: number;
|
|
15
|
+
/** 추가/교체/삭제로 리스트가 바뀌면 갱신된 전체 파일 리스트로 호출된다. */
|
|
16
|
+
onChangeFile: (files: IFile[]) => void | Promise<void>;
|
|
17
|
+
onDeleteFile: (file: IFile) => Promise<boolean>;
|
|
18
|
+
}
|
|
19
|
+
export declare const useFileUploadContext: () => FileUploadContextType;
|
|
20
|
+
interface RootProps {
|
|
21
|
+
recommendedSize?: {
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
};
|
|
25
|
+
maxSize: number;
|
|
26
|
+
allowedExtensions: TMimeType[];
|
|
27
|
+
fileList: IFile[] | [];
|
|
28
|
+
setFileList: Dispatch<SetStateAction<IFile[] | []>>;
|
|
29
|
+
maxFileCount: number;
|
|
30
|
+
onChangeFile: (files: IFile[]) => void | Promise<void>;
|
|
31
|
+
onDeleteFile: (file: IFile) => Promise<boolean>;
|
|
32
|
+
className?: string;
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
interface InputProps extends Omit<LDButtonProps<'button'>, 'type'> {
|
|
36
|
+
type?: 'default' | 'image';
|
|
37
|
+
label?: string;
|
|
38
|
+
}
|
|
39
|
+
interface ICardListProps {
|
|
40
|
+
type?: 'default' | 'image';
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare const FileUploadBase: {
|
|
44
|
+
Root: ({ recommendedSize, maxSize, allowedExtensions, maxFileCount, fileList, setFileList, onChangeFile, onDeleteFile, className, children, }: RootProps) => import("react/jsx-runtime").JSX.Element;
|
|
45
|
+
Input: ({ type, label, ...props }: InputProps) => import("react/jsx-runtime").JSX.Element;
|
|
46
|
+
CardList: (props: ICardListProps) => import("react/jsx-runtime").JSX.Element;
|
|
47
|
+
Description: ({ className }: {
|
|
48
|
+
className?: string;
|
|
49
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
};
|
|
51
|
+
export default FileUploadBase;
|
|
52
|
+
//# sourceMappingURL=FileUploadBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileUploadBase.d.ts","sourceRoot":"","sources":["../../../src/components/LDFileUpload/FileUploadBase.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,QAAQ,EACR,KAAK,SAAS,EACd,cAAc,EAIf,MAAM,OAAO,CAAC;AAEf,OAAO,EAAmB,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEpE,OAAO,EAIL,KAAK,EAKN,MAAM,kBAAkB,CAAC;AAI1B,UAAU,qBAAqB;IAC7B,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,WAAW,EAAE,QAAQ,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,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;CACjD;AAID,eAAO,MAAM,oBAAoB,6BAUhC,CAAC;AAEF,UAAU,SAAS;IACjB,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,GAAG,EAAE,CAAC;IACvB,WAAW,EAAE,QAAQ,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IACpD,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,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAgCD,UAAU,UAAW,SAAQ,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAChE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgHD,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2ND,eAAO,MAAM,cAAc;mJApWxB,SAAS;uCA4BT,UAAU;sBA+GY,cAAc;iCAqMH;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;CAyBzD,CAAC;AAEF,eAAe,cAAc,CAAC"}
|