moru-krds-react 0.1.0
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/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/accordion/index.d.ts +63 -0
- package/dist/accordion/index.d.ts.map +1 -0
- package/dist/accordion/index.js +145 -0
- package/dist/accordion/index.js.map +1 -0
- package/dist/alert/index.d.ts +44 -0
- package/dist/alert/index.d.ts.map +1 -0
- package/dist/alert/index.js +66 -0
- package/dist/alert/index.js.map +1 -0
- package/dist/avatar/index.d.ts +102 -0
- package/dist/avatar/index.d.ts.map +1 -0
- package/dist/avatar/index.js +146 -0
- package/dist/avatar/index.js.map +1 -0
- package/dist/badge/index.d.ts +49 -0
- package/dist/badge/index.d.ts.map +1 -0
- package/dist/badge/index.js +41 -0
- package/dist/badge/index.js.map +1 -0
- package/dist/breadcrumb/index.d.ts +43 -0
- package/dist/breadcrumb/index.d.ts.map +1 -0
- package/dist/breadcrumb/index.js +43 -0
- package/dist/breadcrumb/index.js.map +1 -0
- package/dist/button/index.d.ts +78 -0
- package/dist/button/index.d.ts.map +1 -0
- package/dist/button/index.js +83 -0
- package/dist/button/index.js.map +1 -0
- package/dist/checkbox/index.d.ts +97 -0
- package/dist/checkbox/index.d.ts.map +1 -0
- package/dist/checkbox/index.js +110 -0
- package/dist/checkbox/index.js.map +1 -0
- package/dist/combobox/index.d.ts +135 -0
- package/dist/combobox/index.d.ts.map +1 -0
- package/dist/combobox/index.js +416 -0
- package/dist/combobox/index.js.map +1 -0
- package/dist/context-menu/index.d.ts +94 -0
- package/dist/context-menu/index.d.ts.map +1 -0
- package/dist/context-menu/index.js +399 -0
- package/dist/context-menu/index.js.map +1 -0
- package/dist/critical-alert/index.d.ts +39 -0
- package/dist/critical-alert/index.d.ts.map +1 -0
- package/dist/critical-alert/index.js +50 -0
- package/dist/critical-alert/index.js.map +1 -0
- package/dist/data-table/index.d.ts +94 -0
- package/dist/data-table/index.d.ts.map +1 -0
- package/dist/data-table/index.js +128 -0
- package/dist/data-table/index.js.map +1 -0
- package/dist/disclosure/index.d.ts +35 -0
- package/dist/disclosure/index.d.ts.map +1 -0
- package/dist/disclosure/index.js +54 -0
- package/dist/disclosure/index.js.map +1 -0
- package/dist/drawer/index.d.ts +106 -0
- package/dist/drawer/index.d.ts.map +1 -0
- package/dist/drawer/index.js +352 -0
- package/dist/drawer/index.js.map +1 -0
- package/dist/empty-state/index.d.ts +86 -0
- package/dist/empty-state/index.d.ts.map +1 -0
- package/dist/empty-state/index.js +138 -0
- package/dist/empty-state/index.js.map +1 -0
- package/dist/env.d.js +1 -0
- package/dist/env.d.js.map +1 -0
- package/dist/field/index.d.ts +149 -0
- package/dist/field/index.d.ts.map +1 -0
- package/dist/field/index.js +121 -0
- package/dist/field/index.js.map +1 -0
- package/dist/file-upload/index.d.ts +140 -0
- package/dist/file-upload/index.d.ts.map +1 -0
- package/dist/file-upload/index.js +249 -0
- package/dist/file-upload/index.js.map +1 -0
- package/dist/footer/index.d.ts +155 -0
- package/dist/footer/index.d.ts.map +1 -0
- package/dist/footer/index.js +186 -0
- package/dist/footer/index.js.map +1 -0
- package/dist/header/index.d.ts +170 -0
- package/dist/header/index.d.ts.map +1 -0
- package/dist/header/index.js +258 -0
- package/dist/header/index.js.map +1 -0
- package/dist/identifier/index.d.ts +38 -0
- package/dist/identifier/index.d.ts.map +1 -0
- package/dist/identifier/index.js +55 -0
- package/dist/identifier/index.js.map +1 -0
- package/dist/in-page-navigation/index.d.ts +71 -0
- package/dist/in-page-navigation/index.d.ts.map +1 -0
- package/dist/in-page-navigation/index.js +137 -0
- package/dist/in-page-navigation/index.js.map +1 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/input-group/index.d.ts +66 -0
- package/dist/input-group/index.d.ts.map +1 -0
- package/dist/input-group/index.js +85 -0
- package/dist/input-group/index.js.map +1 -0
- package/dist/lib/krds.d.ts +45 -0
- package/dist/lib/krds.d.ts.map +1 -0
- package/dist/lib/krds.js +11 -0
- package/dist/lib/krds.js.map +1 -0
- package/dist/lib/link.d.ts +34 -0
- package/dist/lib/link.d.ts.map +1 -0
- package/dist/lib/link.js +8 -0
- package/dist/lib/link.js.map +1 -0
- package/dist/main-menu/index.d.ts +123 -0
- package/dist/main-menu/index.d.ts.map +1 -0
- package/dist/main-menu/index.js +613 -0
- package/dist/main-menu/index.js.map +1 -0
- package/dist/masthead/index.d.ts +25 -0
- package/dist/masthead/index.d.ts.map +1 -0
- package/dist/masthead/index.js +21 -0
- package/dist/masthead/index.js.map +1 -0
- package/dist/modal/index.d.ts +105 -0
- package/dist/modal/index.d.ts.map +1 -0
- package/dist/modal/index.js +285 -0
- package/dist/modal/index.js.map +1 -0
- package/dist/pagination/index.d.ts +58 -0
- package/dist/pagination/index.d.ts.map +1 -0
- package/dist/pagination/index.js +82 -0
- package/dist/pagination/index.js.map +1 -0
- package/dist/progress/index.d.ts +58 -0
- package/dist/progress/index.d.ts.map +1 -0
- package/dist/progress/index.js +125 -0
- package/dist/progress/index.js.map +1 -0
- package/dist/radio/index.d.ts +111 -0
- package/dist/radio/index.d.ts.map +1 -0
- package/dist/radio/index.js +136 -0
- package/dist/radio/index.js.map +1 -0
- package/dist/resize/index.d.ts +118 -0
- package/dist/resize/index.d.ts.map +1 -0
- package/dist/resize/index.js +342 -0
- package/dist/resize/index.js.map +1 -0
- package/dist/scroll-area/index.d.ts +40 -0
- package/dist/scroll-area/index.d.ts.map +1 -0
- package/dist/scroll-area/index.js +52 -0
- package/dist/scroll-area/index.js.map +1 -0
- package/dist/select/index.d.ts +67 -0
- package/dist/select/index.d.ts.map +1 -0
- package/dist/select/index.js +61 -0
- package/dist/select/index.js.map +1 -0
- package/dist/separator/index.d.ts +47 -0
- package/dist/separator/index.d.ts.map +1 -0
- package/dist/separator/index.js +61 -0
- package/dist/separator/index.js.map +1 -0
- package/dist/side-navigation/index.d.ts +78 -0
- package/dist/side-navigation/index.d.ts.map +1 -0
- package/dist/side-navigation/index.js +188 -0
- package/dist/side-navigation/index.js.map +1 -0
- package/dist/skeleton/index.d.ts +76 -0
- package/dist/skeleton/index.d.ts.map +1 -0
- package/dist/skeleton/index.js +78 -0
- package/dist/skeleton/index.js.map +1 -0
- package/dist/skip-link/index.d.ts +46 -0
- package/dist/skip-link/index.d.ts.map +1 -0
- package/dist/skip-link/index.js +37 -0
- package/dist/skip-link/index.js.map +1 -0
- package/dist/spinner/index.d.ts +58 -0
- package/dist/spinner/index.d.ts.map +1 -0
- package/dist/spinner/index.js +36 -0
- package/dist/spinner/index.js.map +1 -0
- package/dist/step-indicator/index.d.ts +41 -0
- package/dist/step-indicator/index.d.ts.map +1 -0
- package/dist/step-indicator/index.js +63 -0
- package/dist/step-indicator/index.js.map +1 -0
- package/dist/structured-list/index.d.ts +150 -0
- package/dist/structured-list/index.d.ts.map +1 -0
- package/dist/structured-list/index.js +194 -0
- package/dist/structured-list/index.js.map +1 -0
- package/dist/tab/index.d.ts +108 -0
- package/dist/tab/index.d.ts.map +1 -0
- package/dist/tab/index.js +198 -0
- package/dist/tab/index.js.map +1 -0
- package/dist/table/index.d.ts +75 -0
- package/dist/table/index.d.ts.map +1 -0
- package/dist/table/index.js +91 -0
- package/dist/table/index.js.map +1 -0
- package/dist/tag/index.d.ts +71 -0
- package/dist/tag/index.d.ts.map +1 -0
- package/dist/tag/index.js +45 -0
- package/dist/tag/index.js.map +1 -0
- package/dist/text-input/index.d.ts +69 -0
- package/dist/text-input/index.d.ts.map +1 -0
- package/dist/text-input/index.js +70 -0
- package/dist/text-input/index.js.map +1 -0
- package/dist/text-list/index.d.ts +71 -0
- package/dist/text-list/index.d.ts.map +1 -0
- package/dist/text-list/index.js +79 -0
- package/dist/text-list/index.js.map +1 -0
- package/dist/textarea/index.d.ts +29 -0
- package/dist/textarea/index.d.ts.map +1 -0
- package/dist/textarea/index.js +69 -0
- package/dist/textarea/index.js.map +1 -0
- package/dist/toast/index.d.ts +76 -0
- package/dist/toast/index.d.ts.map +1 -0
- package/dist/toast/index.js +183 -0
- package/dist/toast/index.js.map +1 -0
- package/dist/tooltip/index.d.ts +84 -0
- package/dist/tooltip/index.d.ts.map +1 -0
- package/dist/tooltip/index.js +329 -0
- package/dist/tooltip/index.js.map +1 -0
- package/package.json +57 -0
- package/src/accordion/index.tsx +251 -0
- package/src/alert/index.tsx +111 -0
- package/src/avatar/index.tsx +272 -0
- package/src/badge/index.tsx +91 -0
- package/src/breadcrumb/index.tsx +125 -0
- package/src/button/index.tsx +190 -0
- package/src/checkbox/index.tsx +247 -0
- package/src/combobox/index.tsx +700 -0
- package/src/context-menu/index.tsx +623 -0
- package/src/critical-alert/index.tsx +102 -0
- package/src/data-table/index.tsx +289 -0
- package/src/disclosure/index.tsx +87 -0
- package/src/drawer/index.tsx +516 -0
- package/src/empty-state/index.tsx +256 -0
- package/src/env.d.ts +10 -0
- package/src/field/index.tsx +307 -0
- package/src/file-upload/index.tsx +492 -0
- package/src/footer/index.tsx +393 -0
- package/src/header/index.tsx +498 -0
- package/src/identifier/index.tsx +96 -0
- package/src/in-page-navigation/index.tsx +258 -0
- package/src/index.ts +72 -0
- package/src/input-group/index.tsx +197 -0
- package/src/lib/krds.ts +75 -0
- package/src/lib/link.tsx +35 -0
- package/src/main-menu/index.tsx +912 -0
- package/src/masthead/index.tsx +50 -0
- package/src/modal/index.tsx +457 -0
- package/src/pagination/index.tsx +198 -0
- package/src/progress/index.tsx +198 -0
- package/src/radio/index.tsx +283 -0
- package/src/resize/index.tsx +541 -0
- package/src/scroll-area/index.tsx +96 -0
- package/src/select/index.tsx +136 -0
- package/src/separator/index.tsx +107 -0
- package/src/side-navigation/index.tsx +336 -0
- package/src/skeleton/index.tsx +172 -0
- package/src/skip-link/index.tsx +89 -0
- package/src/spinner/index.tsx +98 -0
- package/src/step-indicator/index.tsx +122 -0
- package/src/structured-list/index.tsx +395 -0
- package/src/tab/index.tsx +348 -0
- package/src/table/index.tsx +186 -0
- package/src/tag/index.tsx +127 -0
- package/src/text-input/index.tsx +156 -0
- package/src/text-list/index.tsx +177 -0
- package/src/textarea/index.tsx +113 -0
- package/src/toast/index.tsx +311 -0
- package/src/tooltip/index.tsx +496 -0
- package/styles/krds-tailwind.css +335 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
import { cx, type KrdsIcon } from '../lib/krds';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 푸터 — KRDS `#krds-footer`.
|
|
6
|
+
*
|
|
7
|
+
* 조각을 규격 순서대로 조립해 쓴다 — 로고 → 연락처 → 유틸리티 링크 → 정책 링크 → 저작권 →
|
|
8
|
+
* 운영기관 식별자. **순서를 바꾸지 마라**(규격의 금지 사항).
|
|
9
|
+
* 아이디 선택자라 한 화면에 하나만 두고, 모든 조각을 `Footer` 안에 둔다.
|
|
10
|
+
* 좁은 화면에서 세로로 바뀌어도 DOM 순서는 같다 — 폭마다 다른 순서를 렌더하지 않는다.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <Footer>
|
|
14
|
+
* <FooterInner>
|
|
15
|
+
* <FooterLogo label="○○기관"><img src="/site/logo.svg" alt="" /></FooterLogo>
|
|
16
|
+
* <FooterContent>
|
|
17
|
+
* <FooterInfo>
|
|
18
|
+
* <FooterAddress>(00000) 모루시 …</FooterAddress>
|
|
19
|
+
* <FooterContacts><FooterContact note="(평일 09~18시)">대표전화 1577-0000</FooterContact></FooterContacts>
|
|
20
|
+
* </FooterInfo>
|
|
21
|
+
* <FooterLinks>
|
|
22
|
+
* <FooterGoLinks><FooterGoLink href="/map">찾아오시는 길</FooterGoLink></FooterGoLinks>
|
|
23
|
+
* </FooterLinks>
|
|
24
|
+
* </FooterContent>
|
|
25
|
+
* <FooterBottom>
|
|
26
|
+
* <FooterBottomText>
|
|
27
|
+
* <FooterMenu>
|
|
28
|
+
* <FooterMenuLink href="/policy/privacy" point>개인정보처리방침</FooterMenuLink>
|
|
29
|
+
* <FooterMenuLink href="/policy/copyright">저작권 정책</FooterMenuLink>
|
|
30
|
+
* </FooterMenu>
|
|
31
|
+
* <FooterCopyright>© 2026 …</FooterCopyright>
|
|
32
|
+
* </FooterBottomText>
|
|
33
|
+
* <FooterIdentifier orgName="○○기관" />
|
|
34
|
+
* </FooterBottom>
|
|
35
|
+
* </FooterInner>
|
|
36
|
+
* </Footer>
|
|
37
|
+
*
|
|
38
|
+
* 자세히: docs/krds/09-부품-노트.md#푸터
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** 푸터 바깥틀 — `<footer id="krds-footer">`. 한 화면에 하나만 둔다. */
|
|
42
|
+
export type FooterProps = Omit<ComponentPropsWithRef<'footer'>, 'id'>;
|
|
43
|
+
|
|
44
|
+
export function Footer({ className, children, ...rest }: FooterProps) {
|
|
45
|
+
return (
|
|
46
|
+
// 모양이 `#krds-footer` 아이디에 걸려 있어 뿌리에는 킷 클래스가 없다. 빈 class 를 남기지 않는다.
|
|
47
|
+
<footer id="krds-footer" className={cx(className) || undefined} {...rest}>
|
|
48
|
+
{children}
|
|
49
|
+
</footer>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** 관련 사이트 띠 — 킷 `.foot-quick`. 선택 사항이고, 있으면 푸터의 맨 위다. */
|
|
54
|
+
export function FooterQuick({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
55
|
+
return (
|
|
56
|
+
<div className={cx('foot-quick', className)} {...rest}>
|
|
57
|
+
<div className="inner">{children}</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 관련 사이트 한 칸 — 킷 `.link`. `href` 를 주면 `<a>`, 없으면 레이어를 여는 `<button>` 이다.
|
|
64
|
+
* 아이콘은 킷이 `::after` 로 붙인다 — 따로 넣지 마라.
|
|
65
|
+
*/
|
|
66
|
+
export type FooterQuickLinkProps =
|
|
67
|
+
| (Omit<ComponentPropsWithRef<'button'>, 'href'> & { href?: undefined })
|
|
68
|
+
| (ComponentPropsWithRef<'a'> & { href: string });
|
|
69
|
+
|
|
70
|
+
export function FooterQuickLink(props: FooterQuickLinkProps) {
|
|
71
|
+
const cls = cx('link', props.className);
|
|
72
|
+
|
|
73
|
+
if (props.href !== undefined) {
|
|
74
|
+
const { className: _a, ...rest } = props as ComponentPropsWithRef<'a'>;
|
|
75
|
+
return <a className={cls} {...rest} />;
|
|
76
|
+
}
|
|
77
|
+
const { className: _b, ...rest } = props as ComponentPropsWithRef<'button'>;
|
|
78
|
+
return <button type="button" className={cls} {...rest} />;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** 푸터 본문 폭 — 킷 `#krds-footer > .inner`. **`Footer` 의 직계 자식이어야 한다.** */
|
|
82
|
+
export function FooterInner({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
83
|
+
return (
|
|
84
|
+
<div className={cx('inner', className)} {...rest}>
|
|
85
|
+
{children}
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 서비스 로고 — 킷 `.f-logo`. 킷이 KRDS 로고를 배경 이미지로 그린다.
|
|
92
|
+
* `children` 에 `<img>` 를 넣으려면 그 배경을 지워야 로고가 겹치지 않는다.
|
|
93
|
+
*/
|
|
94
|
+
export type FooterLogoProps = ComponentPropsWithRef<'div'> & {
|
|
95
|
+
/** 스크린리더가 읽을 기관·서비스 이름. 로고가 이미지든 배경이든 반드시 준다. */
|
|
96
|
+
label: string;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export function FooterLogo({ label, className, children, ...rest }: FooterLogoProps) {
|
|
100
|
+
return (
|
|
101
|
+
<div className={cx('f-logo', className)} {...rest}>
|
|
102
|
+
{children}
|
|
103
|
+
<span className="sr-only">{label}</span>
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** 로고 아래 3단(연락처 · 고객센터 · 유틸리티 링크) — 킷 `.f-cnt`. 폭 배분은 킷이 한다. */
|
|
109
|
+
export function FooterContent({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
110
|
+
return (
|
|
111
|
+
<div className={cx('f-cnt', className)} {...rest}>
|
|
112
|
+
{children}
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** 연락처 묶음 — 킷 `.f-info`. `FooterAddress` 와 `FooterContacts` 가 들어간다. */
|
|
118
|
+
export function FooterInfo({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
119
|
+
return (
|
|
120
|
+
<div className={cx('f-info', className)} {...rest}>
|
|
121
|
+
{children}
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** 주소 한 줄 — 킷 `.info-addr`. */
|
|
127
|
+
export function FooterAddress({ className, children, ...rest }: ComponentPropsWithRef<'p'>) {
|
|
128
|
+
return (
|
|
129
|
+
<p className={cx('info-addr', className)} {...rest}>
|
|
130
|
+
{children}
|
|
131
|
+
</p>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** 연락 수단 목록 — 킷 `.info-cs`. 안에는 `FooterContact` 만 넣는다. */
|
|
136
|
+
export function FooterContacts({ className, children, ...rest }: ComponentPropsWithRef<'ul'>) {
|
|
137
|
+
return (
|
|
138
|
+
<ul className={cx('info-cs', className)} {...rest}>
|
|
139
|
+
{children}
|
|
140
|
+
</ul>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** 연락 수단 한 줄 — 킷 `.info-cs > li > .key-info` (+ 선택 `.more-info`). */
|
|
145
|
+
export type FooterContactProps = Omit<ComponentPropsWithRef<'li'>, 'children'> & {
|
|
146
|
+
/** 굵게 나오는 본문. 예: `대표전화 1577-1000` */
|
|
147
|
+
children: ReactNode;
|
|
148
|
+
/** 괄호 보조 설명. 예: `(유료, 평일 09시~18시)` — 굵기가 본문으로 돌아간다. */
|
|
149
|
+
note?: ReactNode;
|
|
150
|
+
/** 구분선 뒤에 붙는 덧붙임. 예: 팩스·야간 안내. */
|
|
151
|
+
more?: ReactNode;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export function FooterContact({ children, note, more, className, ...rest }: FooterContactProps) {
|
|
155
|
+
return (
|
|
156
|
+
<li className={cx(className) || undefined} {...rest}>
|
|
157
|
+
<span className="key-info">
|
|
158
|
+
<strong>{children}</strong>
|
|
159
|
+
{note != null && <span>{note}</span>}
|
|
160
|
+
</span>
|
|
161
|
+
{more != null && <span className="more-info">{more}</span>}
|
|
162
|
+
</li>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** 고객센터 안내 단 — 킷 `.f-cs`. 안에는 `FooterCsItem` 을 넣는다. */
|
|
167
|
+
export function FooterCs({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
168
|
+
return (
|
|
169
|
+
<div className={cx('f-cs', className)} {...rest}>
|
|
170
|
+
{children}
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** 고객센터 항목 한 벌 — 킷 `.f-cs dl` + `.info-tit`. */
|
|
176
|
+
export type FooterCsItemProps = Omit<ComponentPropsWithRef<'dl'>, 'title' | 'children'> & {
|
|
177
|
+
/** 항목 이름. 예: `고객센터` */
|
|
178
|
+
title: ReactNode;
|
|
179
|
+
/** 값. 예: `1577-1000` */
|
|
180
|
+
children: ReactNode;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export function FooterCsItem({ title, children, className, ...rest }: FooterCsItemProps) {
|
|
184
|
+
return (
|
|
185
|
+
<dl className={cx(className) || undefined} {...rest}>
|
|
186
|
+
<dt className="info-tit">{title}</dt>
|
|
187
|
+
<dd>{children}</dd>
|
|
188
|
+
</dl>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** 유틸리티 링크 묶음 — 킷 `.f-link`. `FooterGoLinks` 와 `FooterSnsLinks` 가 들어간다. */
|
|
193
|
+
export function FooterLinks({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
194
|
+
return (
|
|
195
|
+
<div className={cx('f-link', className)} {...rest}>
|
|
196
|
+
{children}
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** 바로가기 링크 묶음 — 킷 `.link-go`. */
|
|
202
|
+
export function FooterGoLinks({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
203
|
+
return (
|
|
204
|
+
<div className={cx('link-go', className)} {...rest}>
|
|
205
|
+
{children}
|
|
206
|
+
</div>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* 바로가기 링크 한 줄 — 킷 `.link-go > a.krds-btn.medium.text`.
|
|
212
|
+
* 여기에 공용 `LinkButton` 을 쓰지 마라 — 킷이 이 자리의 크기를 따로 잡아 어긋난다.
|
|
213
|
+
*/
|
|
214
|
+
export type FooterGoLinkProps = ComponentPropsWithRef<'a'> & {
|
|
215
|
+
/** 뒤에 붙는 킷 아이콘 이름(`ico-` 뺀 것). 기본은 샘플의 `angle` + 오른쪽 회전. */
|
|
216
|
+
icon?: KrdsIcon | null;
|
|
217
|
+
/** 아이콘 회전. 방향은 이름의 일부가 아니라 별도 클래스다 — `icon="angle right"` 로 쓰지 마라. */
|
|
218
|
+
iconDirection?: 'up' | 'down' | 'left' | 'right';
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export function FooterGoLink({
|
|
222
|
+
icon = 'angle',
|
|
223
|
+
iconDirection = 'right',
|
|
224
|
+
className,
|
|
225
|
+
children,
|
|
226
|
+
target,
|
|
227
|
+
title,
|
|
228
|
+
...rest
|
|
229
|
+
}: FooterGoLinkProps) {
|
|
230
|
+
return (
|
|
231
|
+
<a
|
|
232
|
+
className={cx('krds-btn', 'medium', 'text', className)}
|
|
233
|
+
target={target}
|
|
234
|
+
// 새 창으로 열리면 미리 알린다 — KRDS 접근성 요구. 푸터 샘플의 문구가 「새 창 열기」다.
|
|
235
|
+
title={title ?? (target === '_blank' ? '새 창 열기' : undefined)}
|
|
236
|
+
{...rest}
|
|
237
|
+
>
|
|
238
|
+
{children}
|
|
239
|
+
{icon && <i className={cx(`svg-icon ico-${icon}`, iconDirection)} aria-hidden="true" />}
|
|
240
|
+
</a>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** 소셜 채널 묶음 — 킷 `.link-sns`. */
|
|
245
|
+
export function FooterSnsLinks({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
246
|
+
return (
|
|
247
|
+
<div className={cx('link-sns', className)} {...rest}>
|
|
248
|
+
{children}
|
|
249
|
+
</div>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* 소셜 채널 아이콘 링크 — 킷 `a.krds-btn.xlarge.icon.border`. 채널 이름(`label`)이 필수다.
|
|
255
|
+
* 킷에 있는 아이콘은 `instagram` · `youtube` · `sns-x` · `facebook` · `blog` 다.
|
|
256
|
+
*/
|
|
257
|
+
export type FooterSnsLinkProps = Omit<ComponentPropsWithRef<'a'>, 'children'> & {
|
|
258
|
+
/** 스크린리더가 읽을 채널 이름. 예: `인스타그램` */
|
|
259
|
+
label: string;
|
|
260
|
+
/** 킷 아이콘 이름(`ico-` 뺀 것). 예: `instagram` */
|
|
261
|
+
icon: KrdsIcon;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export function FooterSnsLink({
|
|
265
|
+
label,
|
|
266
|
+
icon,
|
|
267
|
+
className,
|
|
268
|
+
target = '_blank',
|
|
269
|
+
title = '새 창 열기',
|
|
270
|
+
...rest
|
|
271
|
+
}: FooterSnsLinkProps) {
|
|
272
|
+
return (
|
|
273
|
+
<a
|
|
274
|
+
className={cx('krds-btn', 'xlarge', 'icon', 'border', className)}
|
|
275
|
+
target={target}
|
|
276
|
+
title={title}
|
|
277
|
+
{...rest}
|
|
278
|
+
>
|
|
279
|
+
<span className="sr-only">{label}</span>
|
|
280
|
+
<i className={`svg-icon ico-${icon}`} aria-hidden="true" />
|
|
281
|
+
</a>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** 맨 아래 줄 — 킷 `.f-btm`. 안에 `FooterBottomText` 와 `FooterIdentifier` 를 넣는다. */
|
|
286
|
+
export function FooterBottom({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
287
|
+
return (
|
|
288
|
+
<div className={cx('f-btm', className)} {...rest}>
|
|
289
|
+
{children}
|
|
290
|
+
</div>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** 정책 링크 + 저작권 한 줄 — 킷 `.f-btm-text`. PC 에서 좌우 양끝으로 벌어진다. */
|
|
295
|
+
export function FooterBottomText({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
296
|
+
return (
|
|
297
|
+
<div className={cx('f-btm-text', className)} {...rest}>
|
|
298
|
+
{children}
|
|
299
|
+
</div>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** 정책 링크 묶음 — 킷 `.f-menu`. */
|
|
304
|
+
export function FooterMenu({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {
|
|
305
|
+
return (
|
|
306
|
+
<div className={cx('f-menu', className)} {...rest}>
|
|
307
|
+
{children}
|
|
308
|
+
</div>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** 정책 링크 하나. **개인정보처리방침에는 `point` 를 준다** — 규격이 다른 고지사항과 구분하라고 한다. */
|
|
313
|
+
export type FooterMenuLinkProps = ComponentPropsWithRef<'a'> & {
|
|
314
|
+
/** 개인정보처리방침처럼 다른 고지사항과 구분해야 하는 링크. 굵게 그린다. */
|
|
315
|
+
point?: boolean;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
export function FooterMenuLink({ point, className, children, ...rest }: FooterMenuLinkProps) {
|
|
319
|
+
return (
|
|
320
|
+
<a className={cx(point && 'point font-bold', className) || undefined} {...rest}>
|
|
321
|
+
{children}
|
|
322
|
+
</a>
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** 저작권 — 킷 `.f-copy`. 규격상 푸터의 마지막 정보다(식별자는 그 뒤의 별도 구획). */
|
|
327
|
+
export function FooterCopyright({ className, children, ...rest }: ComponentPropsWithRef<'p'>) {
|
|
328
|
+
return (
|
|
329
|
+
<p className={cx('f-copy', className)} {...rest}>
|
|
330
|
+
{children}
|
|
331
|
+
</p>
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* 운영기관 식별자 — KRDS `.krds-identifier`. `FooterBottom` 의 **마지막 자식**으로 넣는다.
|
|
337
|
+
*
|
|
338
|
+
* 로고는 서비스 로고가 아니라 **운영 주체 기관**의 로고다(서비스 로고는 `FooterLogo`).
|
|
339
|
+
* 문구 형식과 요소 배치는 규격이 변형을 금지한다 — `children` 은 번역을 넣는 자리다.
|
|
340
|
+
* 푸터 밖에 독립해 두려면 `ui/identifier` 의 `Identifier` 를 쓴다.
|
|
341
|
+
*/
|
|
342
|
+
|
|
343
|
+
/** KRDS 가 규정한 식별자 문구. 기관명만 갈아 끼운다. */
|
|
344
|
+
export function identifierText(orgName: string): string {
|
|
345
|
+
return `이 누리집은 ${orgName} 누리집입니다.`;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export type FooterIdentifierProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {
|
|
349
|
+
/** 운영 기관 이름. 로고의 대체 텍스트로도 쓴다. */
|
|
350
|
+
orgName: string;
|
|
351
|
+
/** 로고 자리에 넣을 것(보통 `<img>`). 생략하면 킷 배경 로고만 나온다. */
|
|
352
|
+
logo?: ReactNode;
|
|
353
|
+
/** 안내 문구. 생략하면 `identifierText(orgName)`. 번역본 말고 다른 문구를 넣지 마라. */
|
|
354
|
+
children?: ReactNode;
|
|
355
|
+
/** 주면 `<section aria-label>` 로 랜드마크가 된다. 본문과 같은 문구를 넣지 마라(두 번 읽힌다). */
|
|
356
|
+
label?: string;
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
export function FooterIdentifier({
|
|
360
|
+
orgName,
|
|
361
|
+
logo,
|
|
362
|
+
label,
|
|
363
|
+
className,
|
|
364
|
+
children,
|
|
365
|
+
...rest
|
|
366
|
+
}: FooterIdentifierProps) {
|
|
367
|
+
const inner = (
|
|
368
|
+
<>
|
|
369
|
+
<span className="logo">
|
|
370
|
+
{logo}
|
|
371
|
+
<span className="sr-only">{orgName}</span>
|
|
372
|
+
</span>
|
|
373
|
+
<span className="ban-txt">{children ?? identifierText(orgName)}</span>
|
|
374
|
+
</>
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
if (label) {
|
|
378
|
+
return (
|
|
379
|
+
<section
|
|
380
|
+
className={cx('krds-identifier', className)}
|
|
381
|
+
aria-label={label}
|
|
382
|
+
{...(rest as ComponentPropsWithRef<'section'>)}
|
|
383
|
+
>
|
|
384
|
+
{inner}
|
|
385
|
+
</section>
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
return (
|
|
389
|
+
<div className={cx('krds-identifier', className)} {...rest}>
|
|
390
|
+
{inner}
|
|
391
|
+
</div>
|
|
392
|
+
);
|
|
393
|
+
}
|