@uniai-fe/uds-primitives 0.6.0 → 0.6.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/README.md +16 -4
- package/dist/styles.css +110 -16
- package/package.json +1 -1
- package/src/components/alternate/{markup/index.tsx → Alternate.tsx} +7 -4
- package/src/components/alternate/index.tsx +2 -1
- package/src/components/alternate/layout/Button.tsx +29 -0
- package/src/components/alternate/layout/Container.tsx +24 -0
- package/src/components/alternate/layout/Contents.tsx +42 -0
- package/src/components/alternate/layout/Figure.tsx +24 -0
- package/src/components/alternate/layout/Layout.tsx +27 -0
- package/src/components/alternate/layout/TextButton.tsx +50 -0
- package/src/components/alternate/layout/Title.tsx +25 -0
- package/src/components/alternate/layout/index.tsx +1 -0
- package/src/components/alternate/styles/index.scss +3 -1
- package/src/components/alternate/styles/layout.scss +69 -0
- package/src/components/alternate/styles/{alternate.scss → unit.scss} +16 -16
- package/src/components/alternate/styles/variables.scss +30 -0
- package/src/components/alternate/types/index.ts +2 -77
- package/src/components/alternate/types/layout.ts +126 -0
- package/src/components/alternate/types/unit.ts +77 -0
- package/src/components/alternate/{markup → unit}/empty/Data.tsx +1 -1
- package/src/components/alternate/{markup → unit}/loading/Default.tsx +1 -1
- /package/src/components/alternate/{markup/Label.tsx → unit/Text.tsx} +0 -0
- /package/src/components/alternate/{markup → unit}/loading/Icon.tsx +0 -0
package/README.md
CHANGED
|
@@ -53,10 +53,22 @@ export default function Page() {
|
|
|
53
53
|
- `Alternate.LoadingDefault`
|
|
54
54
|
- `Alternate.LoadingIcon`
|
|
55
55
|
- `Alternate.Text`
|
|
56
|
+
- `Alternate.Layout.Container`
|
|
57
|
+
- `Alternate.Layout.Figure`
|
|
58
|
+
- `Alternate.Layout.Title`
|
|
59
|
+
- `Alternate.Layout.Contents`
|
|
60
|
+
- `Alternate.Layout.TextButton`
|
|
61
|
+
- `Alternate.Layout.Button`
|
|
56
62
|
- `AlternateEmptyDataProps`
|
|
57
63
|
- `AlternateLoadingDefaultProps`
|
|
58
64
|
- `AlternateLoadingIconProps`
|
|
59
65
|
- `AlternateTextProps`
|
|
66
|
+
- `AlternateLayoutContainerProps`
|
|
67
|
+
- `AlternateLayoutFigureProps`
|
|
68
|
+
- `AlternateLayoutTitleProps`
|
|
69
|
+
- `AlternateLayoutContentsProps`
|
|
70
|
+
- `AlternateLayoutTextButtonProps`
|
|
71
|
+
- `AlternateLayoutButtonProps`
|
|
60
72
|
- `Badge`
|
|
61
73
|
- `BadgeProps`
|
|
62
74
|
- `Chip.Default`
|
|
@@ -422,10 +434,10 @@ export default function RootLayout({ children }: { children: ReactNode }) {
|
|
|
422
434
|
|
|
423
435
|
```plaintext
|
|
424
436
|
src/components/{category}/
|
|
425
|
-
markup/
|
|
426
|
-
types/
|
|
427
|
-
styles/
|
|
428
|
-
hooks/
|
|
437
|
+
markup|unit|layout/ // 컴포넌트 구현
|
|
438
|
+
types/ // 외부 노출 타입
|
|
439
|
+
styles/ // SCSS (foundation 토큰 기반)
|
|
440
|
+
hooks/ // 카테고리 전용 훅
|
|
429
441
|
```
|
|
430
442
|
|
|
431
443
|
- 배럴(`components/{category}/index.tsx`)은 항상 `import "./index.scss"`를 포함합니다.
|
package/dist/styles.css
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
@charset "UTF-8";
|
|
2
2
|
:root {
|
|
3
|
+
--alternate-unit-text-color: var(--color-cool-gray-70);
|
|
4
|
+
--alternate-unit-text-font-size: 1.4rem;
|
|
5
|
+
--alternate-unit-text-line-height: 1.5;
|
|
6
|
+
--alternate-unit-gap: var(--spacing-gap-6);
|
|
7
|
+
--alternate-loading-icon-small-size: 2.4rem;
|
|
8
|
+
--alternate-loading-icon-medium-size: 3.6rem;
|
|
9
|
+
--alternate-loading-icon-large-size: 5.2rem;
|
|
10
|
+
--alternate-layout-min-block-size: 320px;
|
|
11
|
+
--alternate-layout-gap: var(--spacing-gap-7);
|
|
12
|
+
--alternate-layout-content-gap: var(--spacing-gap-4);
|
|
13
|
+
--alternate-layout-figure-size: 120px;
|
|
14
|
+
--alternate-layout-title-color: var(--color-label-strong);
|
|
15
|
+
--alternate-layout-title-font-size: var(--font-heading-small-size);
|
|
16
|
+
--alternate-layout-title-line-height: var(--font-heading-small-line-height);
|
|
17
|
+
--alternate-layout-title-letter-spacing: var(
|
|
18
|
+
--font-heading-small-letter-spacing
|
|
19
|
+
);
|
|
20
|
+
--alternate-layout-title-font-weight: var(--font-heading-small-weight);
|
|
21
|
+
--alternate-layout-contents-color: var(--color-label-neutral);
|
|
22
|
+
--alternate-layout-contents-font-size: var(--font-body-small-size);
|
|
23
|
+
--alternate-layout-contents-line-height: var(--font-body-small-line-height);
|
|
24
|
+
--alternate-layout-contents-letter-spacing: var(
|
|
25
|
+
--font-body-small-letter-spacing
|
|
26
|
+
);
|
|
27
|
+
--alternate-layout-contents-font-weight: var(--font-body-small-weight);
|
|
28
|
+
--alternate-layout-text-button-color: var(--color-primary-standard);
|
|
29
|
+
--alternate-layout-text-button-underline-offset: 0.2em;
|
|
3
30
|
--theme-badge-height-xsmall: var(--theme-size-small-1);
|
|
4
31
|
--theme-badge-height-small: var(--theme-size-small-2);
|
|
5
32
|
/* 변경: Figma 2421:619 기준 medium 배지 높이 32px를 추가한다. */
|
|
@@ -821,17 +848,17 @@
|
|
|
821
848
|
}
|
|
822
849
|
}
|
|
823
850
|
.empty-text {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
line-height:
|
|
851
|
+
color: var(--alternate-unit-text-color);
|
|
852
|
+
font-size: var(--alternate-unit-text-font-size);
|
|
853
|
+
line-height: var(--alternate-unit-text-line-height);
|
|
827
854
|
word-break: keep-all;
|
|
828
855
|
text-align: center;
|
|
829
856
|
}
|
|
830
857
|
|
|
831
858
|
.alternate-text {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
line-height:
|
|
859
|
+
color: var(--alternate-unit-text-color);
|
|
860
|
+
font-size: var(--alternate-unit-text-font-size);
|
|
861
|
+
line-height: var(--alternate-unit-text-line-height);
|
|
835
862
|
word-break: keep-all;
|
|
836
863
|
text-align: center;
|
|
837
864
|
}
|
|
@@ -849,25 +876,25 @@
|
|
|
849
876
|
}
|
|
850
877
|
.alternate.is-horizontal.loading .empty-text {
|
|
851
878
|
transform: translateY(0.2rem);
|
|
852
|
-
margin-left:
|
|
879
|
+
margin-left: var(--alternate-unit-gap);
|
|
853
880
|
}
|
|
854
881
|
.alternate.is-horizontal.loading .alternate-text {
|
|
855
882
|
transform: translateY(0.2rem);
|
|
856
|
-
margin-left:
|
|
883
|
+
margin-left: var(--alternate-unit-gap);
|
|
857
884
|
}
|
|
858
885
|
.alternate.is-vertical {
|
|
859
886
|
flex-direction: column;
|
|
860
887
|
}
|
|
861
888
|
.alternate.is-vertical .empty-text {
|
|
862
|
-
margin-top:
|
|
889
|
+
margin-top: var(--alternate-unit-gap);
|
|
863
890
|
}
|
|
864
891
|
.alternate.is-vertical .alternate-text {
|
|
865
|
-
margin-top:
|
|
892
|
+
margin-top: var(--alternate-unit-gap);
|
|
866
893
|
}
|
|
867
894
|
|
|
868
895
|
.alternate-loading-icon {
|
|
869
|
-
width:
|
|
870
|
-
height:
|
|
896
|
+
width: var(--alternate-loading-icon-small-size);
|
|
897
|
+
height: var(--alternate-loading-icon-small-size);
|
|
871
898
|
position: relative;
|
|
872
899
|
margin: 0;
|
|
873
900
|
display: flex;
|
|
@@ -876,18 +903,85 @@
|
|
|
876
903
|
animation: alternate-loading-spin 1s linear infinite;
|
|
877
904
|
}
|
|
878
905
|
.alternate-loading-icon.is-medium {
|
|
879
|
-
width:
|
|
880
|
-
height:
|
|
906
|
+
width: var(--alternate-loading-icon-medium-size);
|
|
907
|
+
height: var(--alternate-loading-icon-medium-size);
|
|
881
908
|
}
|
|
882
909
|
.alternate-loading-icon.is-large {
|
|
883
|
-
width:
|
|
884
|
-
height:
|
|
910
|
+
width: var(--alternate-loading-icon-large-size);
|
|
911
|
+
height: var(--alternate-loading-icon-large-size);
|
|
885
912
|
}
|
|
886
913
|
.alternate-loading-icon svg {
|
|
887
914
|
width: 100%;
|
|
888
915
|
height: 100%;
|
|
889
916
|
}
|
|
890
917
|
|
|
918
|
+
.alternate-layout {
|
|
919
|
+
display: flex;
|
|
920
|
+
flex-direction: column;
|
|
921
|
+
align-items: center;
|
|
922
|
+
justify-content: center;
|
|
923
|
+
width: 100%;
|
|
924
|
+
min-height: var(--alternate-layout-min-block-size);
|
|
925
|
+
box-sizing: border-box;
|
|
926
|
+
gap: var(--alternate-layout-gap);
|
|
927
|
+
text-align: center;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.alternate-layout-figure {
|
|
931
|
+
display: flex;
|
|
932
|
+
align-items: center;
|
|
933
|
+
justify-content: center;
|
|
934
|
+
width: var(--alternate-layout-figure-size);
|
|
935
|
+
height: var(--alternate-layout-figure-size);
|
|
936
|
+
margin: 0;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
.alternate-layout-title {
|
|
940
|
+
margin: 0;
|
|
941
|
+
color: var(--alternate-layout-title-color);
|
|
942
|
+
font-size: var(--alternate-layout-title-font-size);
|
|
943
|
+
line-height: var(--alternate-layout-title-line-height);
|
|
944
|
+
letter-spacing: var(--alternate-layout-title-letter-spacing);
|
|
945
|
+
font-weight: var(--alternate-layout-title-font-weight);
|
|
946
|
+
word-break: keep-all;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.alternate-layout-contents {
|
|
950
|
+
max-width: 48rem;
|
|
951
|
+
margin: 0;
|
|
952
|
+
color: var(--alternate-layout-contents-color);
|
|
953
|
+
font-size: var(--alternate-layout-contents-font-size);
|
|
954
|
+
line-height: var(--alternate-layout-contents-line-height);
|
|
955
|
+
letter-spacing: var(--alternate-layout-contents-letter-spacing);
|
|
956
|
+
font-weight: var(--alternate-layout-contents-font-weight);
|
|
957
|
+
word-break: keep-all;
|
|
958
|
+
}
|
|
959
|
+
.alternate-layout-contents :where(p) {
|
|
960
|
+
margin: 0;
|
|
961
|
+
line-height: inherit;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
.alternate-layout-text-button {
|
|
965
|
+
display: inline;
|
|
966
|
+
padding: 0;
|
|
967
|
+
border: 0;
|
|
968
|
+
background: transparent;
|
|
969
|
+
color: var(--alternate-layout-text-button-color);
|
|
970
|
+
font: inherit;
|
|
971
|
+
text-decoration: underline;
|
|
972
|
+
text-underline-offset: var(--alternate-layout-text-button-underline-offset);
|
|
973
|
+
cursor: pointer;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
.alternate-layout-text-button:where(:disabled) {
|
|
977
|
+
cursor: default;
|
|
978
|
+
opacity: 0.4;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
.alternate-layout-button {
|
|
982
|
+
flex-shrink: 0;
|
|
983
|
+
}
|
|
984
|
+
|
|
891
985
|
/* Badge 기본 토큰 래핑 */
|
|
892
986
|
|
|
893
987
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import AlternateLayout from "./layout/Layout";
|
|
2
|
+
import AlternateEmptyData from "./unit/empty/Data";
|
|
3
|
+
import AlternateText from "./unit/Text";
|
|
4
|
+
import AlternateLoadingDefault from "./unit/loading/Default";
|
|
5
|
+
import AlternateLoadingIcon from "./unit/loading/Icon";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Alternate; empty/loading fallback namespace
|
|
@@ -10,12 +11,14 @@ import AlternateLoadingIcon from "./loading/Icon";
|
|
|
10
11
|
* - `Alternate.LoadingDefault`: 로딩 안내 레이아웃이다.
|
|
11
12
|
* - `Alternate.LoadingIcon`: 단독 스피너 아이콘이다.
|
|
12
13
|
* - `Alternate.Text`: 안내 문구 슬롯이다.
|
|
14
|
+
* - `Alternate.Layout`: edge-case 조합을 위한 anatomy namespace다.
|
|
13
15
|
*/
|
|
14
16
|
const Alternate = {
|
|
15
17
|
EmptyData: AlternateEmptyData,
|
|
16
18
|
LoadingDefault: AlternateLoadingDefault,
|
|
17
19
|
LoadingIcon: AlternateLoadingIcon,
|
|
18
20
|
Text: AlternateText,
|
|
21
|
+
Layout: AlternateLayout,
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
export default Alternate;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* - `Alternate.LoadingDefault`: 로딩 아이콘과 안내 문구를 함께 렌더링한다.
|
|
6
6
|
* - `Alternate.LoadingIcon`: 단독 스피너 아이콘이다.
|
|
7
7
|
* - `Alternate.Text`: fallback 문구 스타일 슬롯이다.
|
|
8
|
+
* - `Alternate.Layout`: edge-case 조합 anatomy다.
|
|
8
9
|
*/
|
|
9
|
-
export { default as Alternate } from "./
|
|
10
|
+
export { default as Alternate } from "./Alternate";
|
|
10
11
|
export type * from "./types";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import { Button } from "../../button";
|
|
5
|
+
import type { AlternateLayoutButtonProps } from "../types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Alternate Layout Button; Button.Default preset adapter
|
|
9
|
+
* @component
|
|
10
|
+
* @param {AlternateLayoutButtonProps} props
|
|
11
|
+
* @param {React.ReactNode} [props.children] 버튼 라벨 또는 콘텐츠다.
|
|
12
|
+
* @param {string} [props.className] 버튼 className override다.
|
|
13
|
+
* @example
|
|
14
|
+
* <Alternate.Layout.Button as="a" href="/">홈으로 이동</Alternate.Layout.Button>
|
|
15
|
+
*/
|
|
16
|
+
export default function AlternateLayoutButton({
|
|
17
|
+
className,
|
|
18
|
+
...buttonProps
|
|
19
|
+
}: AlternateLayoutButtonProps) {
|
|
20
|
+
return (
|
|
21
|
+
<Button.Default
|
|
22
|
+
{...buttonProps}
|
|
23
|
+
className={clsx("alternate-layout-button", className)}
|
|
24
|
+
fill="outlined"
|
|
25
|
+
priority="secondary"
|
|
26
|
+
size="small"
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
|
+
import type { AlternateLayoutContainerProps } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Alternate Layout Container; edge-case anatomy 루트
|
|
6
|
+
* @component
|
|
7
|
+
* @param {AlternateLayoutContainerProps} props
|
|
8
|
+
* @param {string} [props.className] 루트 className override다.
|
|
9
|
+
* @param {React.ReactNode} [props.children] layout 내부 콘텐츠다.
|
|
10
|
+
* @example
|
|
11
|
+
* <Alternate.Layout.Container>
|
|
12
|
+
* <Alternate.Layout.Title>데이터가 없습니다.</Alternate.Layout.Title>
|
|
13
|
+
* </Alternate.Layout.Container>
|
|
14
|
+
*/
|
|
15
|
+
export default function AlternateLayoutContainer({
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
}: AlternateLayoutContainerProps) {
|
|
19
|
+
return (
|
|
20
|
+
<section className={clsx("alternate-layout", className)}>
|
|
21
|
+
{children}
|
|
22
|
+
</section>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
|
+
import { Slot } from "../../slot";
|
|
3
|
+
import type { AlternateLayoutContentsProps } from "../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Alternate Layout Contents; edge-case 본문
|
|
7
|
+
* @component
|
|
8
|
+
* @param {AlternateLayoutContentsProps} props
|
|
9
|
+
* @param {string} [props.className] 본문 className override다.
|
|
10
|
+
* @param {React.ReactNode} [props.children] 본문 콘텐츠다.
|
|
11
|
+
* @example
|
|
12
|
+
* <Alternate.Layout.Contents>다시 시도해 주세요.</Alternate.Layout.Contents>
|
|
13
|
+
*/
|
|
14
|
+
export default function AlternateLayoutContents({
|
|
15
|
+
className,
|
|
16
|
+
children,
|
|
17
|
+
}: AlternateLayoutContentsProps) {
|
|
18
|
+
const contentsClassName = clsx("alternate-layout-contents", className);
|
|
19
|
+
|
|
20
|
+
if (
|
|
21
|
+
children === null ||
|
|
22
|
+
typeof children === "undefined" ||
|
|
23
|
+
typeof children === "boolean"
|
|
24
|
+
) {
|
|
25
|
+
return children;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!["string", "number"].includes(typeof children)) {
|
|
29
|
+
// 변경: 복합 본문은 Contents anatomy 안에 유지해 paragraph/TextButton 구성도 동일 typography를 상속받게 한다.
|
|
30
|
+
return (
|
|
31
|
+
<Slot.Base as="div" className={contentsClassName}>
|
|
32
|
+
{children}
|
|
33
|
+
</Slot.Base>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Slot.Text as="p" className={contentsClassName}>
|
|
39
|
+
{children}
|
|
40
|
+
</Slot.Text>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
|
+
import type { AlternateLayoutFigureProps } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Alternate Layout Figure; edge-case visual 영역
|
|
6
|
+
* @component
|
|
7
|
+
* @param {AlternateLayoutFigureProps} props
|
|
8
|
+
* @param {string} [props.className] figure className override다.
|
|
9
|
+
* @param {React.ReactNode} [props.children] 도입 측이 직접 제어하는 SVG, 이미지, 아이콘 콘텐츠다.
|
|
10
|
+
* @example
|
|
11
|
+
* <Alternate.Layout.Figure>
|
|
12
|
+
* <img src="/empty.svg" alt="" />
|
|
13
|
+
* </Alternate.Layout.Figure>
|
|
14
|
+
*/
|
|
15
|
+
export default function AlternateLayoutFigure({
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
}: AlternateLayoutFigureProps) {
|
|
19
|
+
return (
|
|
20
|
+
<figure className={clsx("alternate-layout-figure", className)}>
|
|
21
|
+
{children}
|
|
22
|
+
</figure>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import AlternateLayoutButton from "./Button";
|
|
2
|
+
import AlternateLayoutContainer from "./Container";
|
|
3
|
+
import AlternateLayoutContents from "./Contents";
|
|
4
|
+
import AlternateLayoutFigure from "./Figure";
|
|
5
|
+
import AlternateLayoutTextButton from "./TextButton";
|
|
6
|
+
import AlternateLayoutTitle from "./Title";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Alternate Layout; edge-case anatomy namespace
|
|
10
|
+
* @desc
|
|
11
|
+
* - `Container`: 화면 상태 조합 루트다.
|
|
12
|
+
* - `Figure`: 도입 측이 제어하는 visual 영역이다.
|
|
13
|
+
* - `Title`: 제목 텍스트 영역이다.
|
|
14
|
+
* - `Contents`: 본문 텍스트 영역이다.
|
|
15
|
+
* - `TextButton`: paragraph 내부 text action이다.
|
|
16
|
+
* - `Button`: Button.Default 기반 action adapter다.
|
|
17
|
+
*/
|
|
18
|
+
const AlternateLayout = {
|
|
19
|
+
Container: AlternateLayoutContainer,
|
|
20
|
+
Figure: AlternateLayoutFigure,
|
|
21
|
+
Title: AlternateLayoutTitle,
|
|
22
|
+
Contents: AlternateLayoutContents,
|
|
23
|
+
TextButton: AlternateLayoutTextButton,
|
|
24
|
+
Button: AlternateLayoutButton,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default AlternateLayout;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import type { AlternateLayoutTextButtonProps } from "../types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Alternate Layout TextButton; paragraph 내부 text action
|
|
8
|
+
* @component
|
|
9
|
+
* @param {AlternateLayoutTextButtonProps} props
|
|
10
|
+
* @param {string} [props.className] action className override다.
|
|
11
|
+
* @param {React.ReactNode} [props.children] action 라벨 콘텐츠다.
|
|
12
|
+
* @param {string} [props.href] 링크 action으로 렌더링할 href다.
|
|
13
|
+
* @param {string} [props.target] 링크 target 값이다.
|
|
14
|
+
* @example
|
|
15
|
+
* <Alternate.Layout.TextButton onClick={onRetry}>다시 시도</Alternate.Layout.TextButton>
|
|
16
|
+
*/
|
|
17
|
+
export default function AlternateLayoutTextButton({
|
|
18
|
+
className,
|
|
19
|
+
children,
|
|
20
|
+
href,
|
|
21
|
+
target,
|
|
22
|
+
type: typeProp,
|
|
23
|
+
...htmlAttrs
|
|
24
|
+
}: AlternateLayoutTextButtonProps) {
|
|
25
|
+
const textButtonClassName = clsx("alternate-layout-text-button", className);
|
|
26
|
+
|
|
27
|
+
if (href) {
|
|
28
|
+
return (
|
|
29
|
+
<a
|
|
30
|
+
className={textButtonClassName}
|
|
31
|
+
href={href}
|
|
32
|
+
target={target}
|
|
33
|
+
{...htmlAttrs}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</a>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 변경: href가 없으면 문장 내부 action을 native button으로 고정한다.
|
|
41
|
+
return (
|
|
42
|
+
<button
|
|
43
|
+
className={textButtonClassName}
|
|
44
|
+
type={typeProp ?? "button"}
|
|
45
|
+
{...htmlAttrs}
|
|
46
|
+
>
|
|
47
|
+
{children}
|
|
48
|
+
</button>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
|
+
import { Slot } from "../../slot";
|
|
3
|
+
import type { AlternateLayoutTitleProps } from "../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Alternate Layout Title; edge-case 제목
|
|
7
|
+
* @component
|
|
8
|
+
* @param {AlternateLayoutTitleProps} props
|
|
9
|
+
* @param {React.ElementType} [props.as="strong"] 렌더링할 제목 요소다.
|
|
10
|
+
* @param {string} [props.className] 제목 className override다.
|
|
11
|
+
* @param {React.ReactNode} [props.children] 제목 콘텐츠다.
|
|
12
|
+
* @example
|
|
13
|
+
* <Alternate.Layout.Title as="h1">페이지를 찾을 수 없습니다.</Alternate.Layout.Title>
|
|
14
|
+
*/
|
|
15
|
+
export default function AlternateLayoutTitle({
|
|
16
|
+
as = "strong",
|
|
17
|
+
className,
|
|
18
|
+
children,
|
|
19
|
+
}: AlternateLayoutTitleProps) {
|
|
20
|
+
return (
|
|
21
|
+
<Slot.Text as={as} className={clsx("alternate-layout-title", className)}>
|
|
22
|
+
{children}
|
|
23
|
+
</Slot.Text>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as AlternateLayout } from "./Layout";
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.alternate-layout {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
width: 100%;
|
|
7
|
+
min-height: var(--alternate-layout-min-block-size);
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
gap: var(--alternate-layout-gap);
|
|
10
|
+
text-align: center;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.alternate-layout-figure {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
width: var(--alternate-layout-figure-size);
|
|
18
|
+
height: var(--alternate-layout-figure-size);
|
|
19
|
+
margin: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.alternate-layout-title {
|
|
23
|
+
margin: 0;
|
|
24
|
+
color: var(--alternate-layout-title-color);
|
|
25
|
+
font-size: var(--alternate-layout-title-font-size);
|
|
26
|
+
line-height: var(--alternate-layout-title-line-height);
|
|
27
|
+
letter-spacing: var(--alternate-layout-title-letter-spacing);
|
|
28
|
+
font-weight: var(--alternate-layout-title-font-weight);
|
|
29
|
+
word-break: keep-all;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.alternate-layout-contents {
|
|
33
|
+
max-width: 48rem;
|
|
34
|
+
margin: 0;
|
|
35
|
+
color: var(--alternate-layout-contents-color);
|
|
36
|
+
font-size: var(--alternate-layout-contents-font-size);
|
|
37
|
+
line-height: var(--alternate-layout-contents-line-height);
|
|
38
|
+
letter-spacing: var(--alternate-layout-contents-letter-spacing);
|
|
39
|
+
font-weight: var(--alternate-layout-contents-font-weight);
|
|
40
|
+
word-break: keep-all;
|
|
41
|
+
|
|
42
|
+
:where(p) {
|
|
43
|
+
// 변경: 복합 Contents의 paragraph도 같은 typography 흐름 안에서 렌더링되도록 기본 문단 여백을 제거한다.
|
|
44
|
+
margin: 0;
|
|
45
|
+
line-height: inherit;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.alternate-layout-text-button {
|
|
50
|
+
// 변경: paragraph 내부 text action이라는 명시 계약에 따라 inline display 예외를 둔다.
|
|
51
|
+
display: inline;
|
|
52
|
+
padding: 0;
|
|
53
|
+
border: 0;
|
|
54
|
+
background: transparent;
|
|
55
|
+
color: var(--alternate-layout-text-button-color);
|
|
56
|
+
font: inherit;
|
|
57
|
+
text-decoration: underline;
|
|
58
|
+
text-underline-offset: var(--alternate-layout-text-button-underline-offset);
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.alternate-layout-text-button:where(:disabled) {
|
|
63
|
+
cursor: default;
|
|
64
|
+
opacity: 0.4;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.alternate-layout-button {
|
|
68
|
+
flex-shrink: 0;
|
|
69
|
+
}
|
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
.empty-text {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
line-height:
|
|
12
|
+
color: var(--alternate-unit-text-color);
|
|
13
|
+
font-size: var(--alternate-unit-text-font-size);
|
|
14
|
+
line-height: var(--alternate-unit-text-line-height);
|
|
15
15
|
word-break: keep-all;
|
|
16
16
|
text-align: center;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
.alternate-text {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
line-height:
|
|
20
|
+
color: var(--alternate-unit-text-color);
|
|
21
|
+
font-size: var(--alternate-unit-text-font-size);
|
|
22
|
+
line-height: var(--alternate-unit-text-line-height);
|
|
23
23
|
word-break: keep-all;
|
|
24
24
|
text-align: center;
|
|
25
25
|
}
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
&.loading {
|
|
39
39
|
.empty-text {
|
|
40
40
|
transform: translateY(0.2rem);
|
|
41
|
-
margin-left:
|
|
41
|
+
margin-left: var(--alternate-unit-gap);
|
|
42
42
|
}
|
|
43
43
|
.alternate-text {
|
|
44
44
|
transform: translateY(0.2rem);
|
|
45
|
-
margin-left:
|
|
45
|
+
margin-left: var(--alternate-unit-gap);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -50,17 +50,17 @@
|
|
|
50
50
|
&.is-vertical {
|
|
51
51
|
flex-direction: column;
|
|
52
52
|
.empty-text {
|
|
53
|
-
margin-top:
|
|
53
|
+
margin-top: var(--alternate-unit-gap);
|
|
54
54
|
}
|
|
55
55
|
.alternate-text {
|
|
56
|
-
margin-top:
|
|
56
|
+
margin-top: var(--alternate-unit-gap);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
.alternate-loading-icon {
|
|
62
|
-
width:
|
|
63
|
-
height:
|
|
62
|
+
width: var(--alternate-loading-icon-small-size);
|
|
63
|
+
height: var(--alternate-loading-icon-small-size);
|
|
64
64
|
position: relative;
|
|
65
65
|
margin: 0;
|
|
66
66
|
display: flex;
|
|
@@ -69,13 +69,13 @@
|
|
|
69
69
|
animation: alternate-loading-spin 1s linear infinite;
|
|
70
70
|
|
|
71
71
|
&.is-medium {
|
|
72
|
-
width:
|
|
73
|
-
height:
|
|
72
|
+
width: var(--alternate-loading-icon-medium-size);
|
|
73
|
+
height: var(--alternate-loading-icon-medium-size);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
&.is-large {
|
|
77
|
-
width:
|
|
78
|
-
height:
|
|
77
|
+
width: var(--alternate-loading-icon-large-size);
|
|
78
|
+
height: var(--alternate-loading-icon-large-size);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
svg {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--alternate-unit-text-color: var(--color-cool-gray-70);
|
|
3
|
+
--alternate-unit-text-font-size: 1.4rem;
|
|
4
|
+
--alternate-unit-text-line-height: 1.5;
|
|
5
|
+
--alternate-unit-gap: var(--spacing-gap-6);
|
|
6
|
+
--alternate-loading-icon-small-size: 2.4rem;
|
|
7
|
+
--alternate-loading-icon-medium-size: 3.6rem;
|
|
8
|
+
--alternate-loading-icon-large-size: 5.2rem;
|
|
9
|
+
|
|
10
|
+
--alternate-layout-min-block-size: 320px;
|
|
11
|
+
--alternate-layout-gap: var(--spacing-gap-7);
|
|
12
|
+
--alternate-layout-content-gap: var(--spacing-gap-4);
|
|
13
|
+
--alternate-layout-figure-size: 120px;
|
|
14
|
+
--alternate-layout-title-color: var(--color-label-strong);
|
|
15
|
+
--alternate-layout-title-font-size: var(--font-heading-small-size);
|
|
16
|
+
--alternate-layout-title-line-height: var(--font-heading-small-line-height);
|
|
17
|
+
--alternate-layout-title-letter-spacing: var(
|
|
18
|
+
--font-heading-small-letter-spacing
|
|
19
|
+
);
|
|
20
|
+
--alternate-layout-title-font-weight: var(--font-heading-small-weight);
|
|
21
|
+
--alternate-layout-contents-color: var(--color-label-neutral);
|
|
22
|
+
--alternate-layout-contents-font-size: var(--font-body-small-size);
|
|
23
|
+
--alternate-layout-contents-line-height: var(--font-body-small-line-height);
|
|
24
|
+
--alternate-layout-contents-letter-spacing: var(
|
|
25
|
+
--font-body-small-letter-spacing
|
|
26
|
+
);
|
|
27
|
+
--alternate-layout-contents-font-weight: var(--font-body-small-weight);
|
|
28
|
+
--alternate-layout-text-button-color: var(--color-primary-standard);
|
|
29
|
+
--alternate-layout-text-button-underline-offset: 0.2em;
|
|
30
|
+
}
|
|
@@ -1,77 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Alternate Direction; fallback 레이아웃 방향 축
|
|
5
|
-
* @typedef {"vertical" | "horizontal"} AlternateDirection
|
|
6
|
-
*/
|
|
7
|
-
export type AlternateDirection = "vertical" | "horizontal";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Alternate Loading Icon Size; 로딩 아이콘 스케일 축
|
|
11
|
-
* @typedef {"small" | "medium" | "large"} AlternateLoadingIconSize
|
|
12
|
-
*/
|
|
13
|
-
export type AlternateLoadingIconSize = "small" | "medium" | "large";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Alternate Text Props; fallback 문구 슬롯 props
|
|
17
|
-
* @property {ReactNode} children 렌더링할 문구 콘텐츠다.
|
|
18
|
-
*/
|
|
19
|
-
export interface AlternateTextProps {
|
|
20
|
-
/**
|
|
21
|
-
* 렌더링할 문구 콘텐츠다.
|
|
22
|
-
*/
|
|
23
|
-
children: ReactNode;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Alternate Empty Data Props; 빈 데이터 안내 레이아웃 props
|
|
28
|
-
* @property {string} [className] 루트 className override다.
|
|
29
|
-
* @property {"vertical" | "horizontal"} [direction] 아이콘/문구 배치 방향이다.
|
|
30
|
-
* @property {ReactNode} [children] 안내 문구 콘텐츠다.
|
|
31
|
-
*/
|
|
32
|
-
export interface AlternateEmptyDataProps {
|
|
33
|
-
/**
|
|
34
|
-
* 루트 className override다.
|
|
35
|
-
*/
|
|
36
|
-
className?: string;
|
|
37
|
-
/**
|
|
38
|
-
* 아이콘/문구 배치 방향이다.
|
|
39
|
-
*/
|
|
40
|
-
direction?: AlternateDirection;
|
|
41
|
-
/**
|
|
42
|
-
* 안내 문구 콘텐츠다.
|
|
43
|
-
*/
|
|
44
|
-
children?: ReactNode;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Alternate Loading Default Props; 로딩 안내 레이아웃 props
|
|
49
|
-
* @property {"vertical" | "horizontal"} [direction] 아이콘/문구 배치 방향이다.
|
|
50
|
-
* @property {ReactNode} [children] 안내 문구 콘텐츠다.
|
|
51
|
-
*/
|
|
52
|
-
export interface AlternateLoadingDefaultProps {
|
|
53
|
-
/**
|
|
54
|
-
* 아이콘/문구 배치 방향이다.
|
|
55
|
-
*/
|
|
56
|
-
direction?: AlternateDirection;
|
|
57
|
-
/**
|
|
58
|
-
* 안내 문구 콘텐츠다.
|
|
59
|
-
*/
|
|
60
|
-
children?: ReactNode;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Alternate Loading Icon Props; 단독 스피너 아이콘 props
|
|
65
|
-
* @property {"small" | "medium" | "large"} [size] 로딩 아이콘 스케일이다.
|
|
66
|
-
* @property {"vertical" | "horizontal"} [direction] 부모 레이아웃 방향 클래스 동기화용 값이다.
|
|
67
|
-
*/
|
|
68
|
-
export interface AlternateLoadingIconProps {
|
|
69
|
-
/**
|
|
70
|
-
* 로딩 아이콘 스케일이다.
|
|
71
|
-
*/
|
|
72
|
-
size?: AlternateLoadingIconSize;
|
|
73
|
-
/**
|
|
74
|
-
* 부모 레이아웃 방향 클래스 동기화용 값이다.
|
|
75
|
-
*/
|
|
76
|
-
direction?: AlternateDirection;
|
|
77
|
-
}
|
|
1
|
+
export type * from "./unit";
|
|
2
|
+
export type * from "./layout";
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef, ElementType, ReactNode } from "react";
|
|
2
|
+
import type { ButtonProps } from "../../button/types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Alternate Layout Container Props; edge-case anatomy 루트 props
|
|
6
|
+
* @property {string} [className] 루트 className override다.
|
|
7
|
+
* @property {ReactNode} [children] layout 내부 콘텐츠다.
|
|
8
|
+
*/
|
|
9
|
+
export interface AlternateLayoutContainerProps {
|
|
10
|
+
/**
|
|
11
|
+
* 루트 className override다.
|
|
12
|
+
*/
|
|
13
|
+
className?: string;
|
|
14
|
+
/**
|
|
15
|
+
* layout 내부 콘텐츠다.
|
|
16
|
+
*/
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Alternate Layout Figure Props; figure 영역 props
|
|
22
|
+
* @property {string} [className] figure className override다.
|
|
23
|
+
* @property {ReactNode} [children] 도입 측이 직접 제어하는 SVG, 이미지, 아이콘 콘텐츠다.
|
|
24
|
+
*/
|
|
25
|
+
export interface AlternateLayoutFigureProps {
|
|
26
|
+
/**
|
|
27
|
+
* figure className override다.
|
|
28
|
+
*/
|
|
29
|
+
className?: string;
|
|
30
|
+
/**
|
|
31
|
+
* 도입 측이 직접 제어하는 SVG, 이미지, 아이콘 콘텐츠다.
|
|
32
|
+
*/
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Alternate Layout Title Props; 제목 텍스트 props
|
|
38
|
+
* @property {ElementType} [as] 렌더링할 제목 요소다. 기본값은 strong이다.
|
|
39
|
+
* @property {string} [className] 제목 className override다.
|
|
40
|
+
* @property {ReactNode} [children] 제목 콘텐츠다.
|
|
41
|
+
*/
|
|
42
|
+
export interface AlternateLayoutTitleProps {
|
|
43
|
+
/**
|
|
44
|
+
* 렌더링할 제목 요소다.
|
|
45
|
+
* 기본값은 strong이다.
|
|
46
|
+
*/
|
|
47
|
+
as?: ElementType;
|
|
48
|
+
/**
|
|
49
|
+
* 제목 className override다.
|
|
50
|
+
*/
|
|
51
|
+
className?: string;
|
|
52
|
+
/**
|
|
53
|
+
* 제목 콘텐츠다.
|
|
54
|
+
*/
|
|
55
|
+
children?: ReactNode;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Alternate Layout Contents Props; 본문 텍스트 props
|
|
60
|
+
* @property {string} [className] 본문 className override다.
|
|
61
|
+
* @property {ReactNode} [children] 본문 콘텐츠다.
|
|
62
|
+
*/
|
|
63
|
+
export interface AlternateLayoutContentsProps {
|
|
64
|
+
/**
|
|
65
|
+
* 본문 className override다.
|
|
66
|
+
*/
|
|
67
|
+
className?: string;
|
|
68
|
+
/**
|
|
69
|
+
* 본문 콘텐츠다.
|
|
70
|
+
*/
|
|
71
|
+
children?: ReactNode;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Alternate Layout Text Button Native Props; 문장 내부 action native props
|
|
76
|
+
*/
|
|
77
|
+
type AlternateLayoutTextButtonNativeProps = Omit<
|
|
78
|
+
ComponentPropsWithoutRef<"button">,
|
|
79
|
+
"children" | "className"
|
|
80
|
+
> &
|
|
81
|
+
Omit<ComponentPropsWithoutRef<"a">, "children" | "className">;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Alternate Layout Text Button Props; 문장 내부 action props
|
|
85
|
+
* @property {string} [className] action className override다.
|
|
86
|
+
* @property {ReactNode} [children] action 라벨 콘텐츠다.
|
|
87
|
+
* @property {string} [href] 링크 action으로 렌더링할 href다.
|
|
88
|
+
* @property {string} [target] 링크 target 값이다.
|
|
89
|
+
*/
|
|
90
|
+
export interface AlternateLayoutTextButtonProps extends AlternateLayoutTextButtonNativeProps {
|
|
91
|
+
/**
|
|
92
|
+
* action className override다.
|
|
93
|
+
*/
|
|
94
|
+
className?: string;
|
|
95
|
+
/**
|
|
96
|
+
* action 라벨 콘텐츠다.
|
|
97
|
+
*/
|
|
98
|
+
children?: ReactNode;
|
|
99
|
+
/**
|
|
100
|
+
* 링크 action으로 렌더링할 href다.
|
|
101
|
+
*/
|
|
102
|
+
href?: string;
|
|
103
|
+
/**
|
|
104
|
+
* 링크 target 값이다.
|
|
105
|
+
*/
|
|
106
|
+
target?: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Alternate Layout Button Props; Button.Default adapter props
|
|
111
|
+
* @extends ButtonProps
|
|
112
|
+
* @property {ElementType} [as] 렌더링할 요소다.
|
|
113
|
+
* @property {ReactNode} [children] 버튼 라벨 또는 콘텐츠다.
|
|
114
|
+
* @property {string} [className] 버튼 className override다.
|
|
115
|
+
* @property {"default" | "readonly" | "disabled"} [state] UI 상태다.
|
|
116
|
+
* @property {boolean} [block] width:100% 확장 여부다.
|
|
117
|
+
* @property {"full" | "fit" | "fill" | "auto" | number | string} [width] Form.Field width preset 또는 custom width다.
|
|
118
|
+
* @property {boolean} [loading] true면 readonly 상태로 렌더링한다.
|
|
119
|
+
* @property {ReactNode} [left] 라벨 왼쪽 콘텐츠다.
|
|
120
|
+
* @property {ReactNode} [right] 라벨 오른쪽 콘텐츠다.
|
|
121
|
+
* @property {"hover" | "pressed"} ["data-user-action"] Interaction 상태 강제 표현용 data attr이다.
|
|
122
|
+
*/
|
|
123
|
+
export interface AlternateLayoutButtonProps extends Omit<
|
|
124
|
+
ButtonProps,
|
|
125
|
+
"fill" | "priority" | "size" | "scale"
|
|
126
|
+
> {}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Alternate Direction; fallback 레이아웃 방향 축
|
|
5
|
+
* @typedef {"vertical" | "horizontal"} AlternateDirection
|
|
6
|
+
*/
|
|
7
|
+
export type AlternateDirection = "vertical" | "horizontal";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Alternate Loading Icon Size; 로딩 아이콘 스케일 축
|
|
11
|
+
* @typedef {"small" | "medium" | "large"} AlternateLoadingIconSize
|
|
12
|
+
*/
|
|
13
|
+
export type AlternateLoadingIconSize = "small" | "medium" | "large";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Alternate Text Props; fallback 문구 슬롯 props
|
|
17
|
+
* @property {ReactNode} children 렌더링할 문구 콘텐츠다.
|
|
18
|
+
*/
|
|
19
|
+
export interface AlternateTextProps {
|
|
20
|
+
/**
|
|
21
|
+
* 렌더링할 문구 콘텐츠다.
|
|
22
|
+
*/
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Alternate Empty Data Props; 빈 데이터 안내 레이아웃 props
|
|
28
|
+
* @property {string} [className] 루트 className override다.
|
|
29
|
+
* @property {"vertical" | "horizontal"} [direction] 아이콘/문구 배치 방향이다.
|
|
30
|
+
* @property {ReactNode} [children] 안내 문구 콘텐츠다.
|
|
31
|
+
*/
|
|
32
|
+
export interface AlternateEmptyDataProps {
|
|
33
|
+
/**
|
|
34
|
+
* 루트 className override다.
|
|
35
|
+
*/
|
|
36
|
+
className?: string;
|
|
37
|
+
/**
|
|
38
|
+
* 아이콘/문구 배치 방향이다.
|
|
39
|
+
*/
|
|
40
|
+
direction?: AlternateDirection;
|
|
41
|
+
/**
|
|
42
|
+
* 안내 문구 콘텐츠다.
|
|
43
|
+
*/
|
|
44
|
+
children?: ReactNode;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Alternate Loading Default Props; 로딩 안내 레이아웃 props
|
|
49
|
+
* @property {"vertical" | "horizontal"} [direction] 아이콘/문구 배치 방향이다.
|
|
50
|
+
* @property {ReactNode} [children] 안내 문구 콘텐츠다.
|
|
51
|
+
*/
|
|
52
|
+
export interface AlternateLoadingDefaultProps {
|
|
53
|
+
/**
|
|
54
|
+
* 아이콘/문구 배치 방향이다.
|
|
55
|
+
*/
|
|
56
|
+
direction?: AlternateDirection;
|
|
57
|
+
/**
|
|
58
|
+
* 안내 문구 콘텐츠다.
|
|
59
|
+
*/
|
|
60
|
+
children?: ReactNode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Alternate Loading Icon Props; 단독 스피너 아이콘 props
|
|
65
|
+
* @property {"small" | "medium" | "large"} [size] 로딩 아이콘 스케일이다.
|
|
66
|
+
* @property {"vertical" | "horizontal"} [direction] 부모 레이아웃 방향 클래스 동기화용 값이다.
|
|
67
|
+
*/
|
|
68
|
+
export interface AlternateLoadingIconProps {
|
|
69
|
+
/**
|
|
70
|
+
* 로딩 아이콘 스케일이다.
|
|
71
|
+
*/
|
|
72
|
+
size?: AlternateLoadingIconSize;
|
|
73
|
+
/**
|
|
74
|
+
* 부모 레이아웃 방향 클래스 동기화용 값이다.
|
|
75
|
+
*/
|
|
76
|
+
direction?: AlternateDirection;
|
|
77
|
+
}
|
|
File without changes
|
|
File without changes
|