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 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/footer/index.tsx"],"sourcesContent":["import type { ComponentPropsWithRef, ReactNode } from 'react';\nimport { cx, type KrdsIcon } from '../lib/krds';\n\n/**\n * 푸터 — KRDS `#krds-footer`.\n *\n * 조각을 규격 순서대로 조립해 쓴다 — 로고 → 연락처 → 유틸리티 링크 → 정책 링크 → 저작권 →\n * 운영기관 식별자. **순서를 바꾸지 마라**(규격의 금지 사항).\n * 아이디 선택자라 한 화면에 하나만 두고, 모든 조각을 `Footer` 안에 둔다.\n * 좁은 화면에서 세로로 바뀌어도 DOM 순서는 같다 — 폭마다 다른 순서를 렌더하지 않는다.\n *\n * @example\n * <Footer>\n * <FooterInner>\n * <FooterLogo label=\"○○기관\"><img src=\"/site/logo.svg\" alt=\"\" /></FooterLogo>\n * <FooterContent>\n * <FooterInfo>\n * <FooterAddress>(00000) 모루시 …</FooterAddress>\n * <FooterContacts><FooterContact note=\"(평일 09~18시)\">대표전화 1577-0000</FooterContact></FooterContacts>\n * </FooterInfo>\n * <FooterLinks>\n * <FooterGoLinks><FooterGoLink href=\"/map\">찾아오시는 길</FooterGoLink></FooterGoLinks>\n * </FooterLinks>\n * </FooterContent>\n * <FooterBottom>\n * <FooterBottomText>\n * <FooterMenu>\n * <FooterMenuLink href=\"/policy/privacy\" point>개인정보처리방침</FooterMenuLink>\n * <FooterMenuLink href=\"/policy/copyright\">저작권 정책</FooterMenuLink>\n * </FooterMenu>\n * <FooterCopyright>© 2026 …</FooterCopyright>\n * </FooterBottomText>\n * <FooterIdentifier orgName=\"○○기관\" />\n * </FooterBottom>\n * </FooterInner>\n * </Footer>\n *\n * 자세히: docs/krds/09-부품-노트.md#푸터\n */\n\n/** 푸터 바깥틀 — `<footer id=\"krds-footer\">`. 한 화면에 하나만 둔다. */\nexport type FooterProps = Omit<ComponentPropsWithRef<'footer'>, 'id'>;\n\nexport function Footer({ className, children, ...rest }: FooterProps) {\n return (\n // 모양이 `#krds-footer` 아이디에 걸려 있어 뿌리에는 킷 클래스가 없다. 빈 class 를 남기지 않는다.\n <footer id=\"krds-footer\" className={cx(className) || undefined} {...rest}>\n {children}\n </footer>\n );\n}\n\n/** 관련 사이트 띠 — 킷 `.foot-quick`. 선택 사항이고, 있으면 푸터의 맨 위다. */\nexport function FooterQuick({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('foot-quick', className)} {...rest}>\n <div className=\"inner\">{children}</div>\n </div>\n );\n}\n\n/**\n * 관련 사이트 한 칸 — 킷 `.link`. `href` 를 주면 `<a>`, 없으면 레이어를 여는 `<button>` 이다.\n * 아이콘은 킷이 `::after` 로 붙인다 — 따로 넣지 마라.\n */\nexport type FooterQuickLinkProps =\n | (Omit<ComponentPropsWithRef<'button'>, 'href'> & { href?: undefined })\n | (ComponentPropsWithRef<'a'> & { href: string });\n\nexport function FooterQuickLink(props: FooterQuickLinkProps) {\n const cls = cx('link', props.className);\n\n if (props.href !== undefined) {\n const { className: _a, ...rest } = props as ComponentPropsWithRef<'a'>;\n return <a className={cls} {...rest} />;\n }\n const { className: _b, ...rest } = props as ComponentPropsWithRef<'button'>;\n return <button type=\"button\" className={cls} {...rest} />;\n}\n\n/** 푸터 본문 폭 — 킷 `#krds-footer > .inner`. **`Footer` 의 직계 자식이어야 한다.** */\nexport function FooterInner({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('inner', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/**\n * 서비스 로고 — 킷 `.f-logo`. 킷이 KRDS 로고를 배경 이미지로 그린다.\n * `children` 에 `<img>` 를 넣으려면 그 배경을 지워야 로고가 겹치지 않는다.\n */\nexport type FooterLogoProps = ComponentPropsWithRef<'div'> & {\n /** 스크린리더가 읽을 기관·서비스 이름. 로고가 이미지든 배경이든 반드시 준다. */\n label: string;\n};\n\nexport function FooterLogo({ label, className, children, ...rest }: FooterLogoProps) {\n return (\n <div className={cx('f-logo', className)} {...rest}>\n {children}\n <span className=\"sr-only\">{label}</span>\n </div>\n );\n}\n\n/** 로고 아래 3단(연락처 · 고객센터 · 유틸리티 링크) — 킷 `.f-cnt`. 폭 배분은 킷이 한다. */\nexport function FooterContent({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('f-cnt', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/** 연락처 묶음 — 킷 `.f-info`. `FooterAddress` 와 `FooterContacts` 가 들어간다. */\nexport function FooterInfo({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('f-info', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/** 주소 한 줄 — 킷 `.info-addr`. */\nexport function FooterAddress({ className, children, ...rest }: ComponentPropsWithRef<'p'>) {\n return (\n <p className={cx('info-addr', className)} {...rest}>\n {children}\n </p>\n );\n}\n\n/** 연락 수단 목록 — 킷 `.info-cs`. 안에는 `FooterContact` 만 넣는다. */\nexport function FooterContacts({ className, children, ...rest }: ComponentPropsWithRef<'ul'>) {\n return (\n <ul className={cx('info-cs', className)} {...rest}>\n {children}\n </ul>\n );\n}\n\n/** 연락 수단 한 줄 — 킷 `.info-cs > li > .key-info` (+ 선택 `.more-info`). */\nexport type FooterContactProps = Omit<ComponentPropsWithRef<'li'>, 'children'> & {\n /** 굵게 나오는 본문. 예: `대표전화 1577-1000` */\n children: ReactNode;\n /** 괄호 보조 설명. 예: `(유료, 평일 09시~18시)` — 굵기가 본문으로 돌아간다. */\n note?: ReactNode;\n /** 구분선 뒤에 붙는 덧붙임. 예: 팩스·야간 안내. */\n more?: ReactNode;\n};\n\nexport function FooterContact({ children, note, more, className, ...rest }: FooterContactProps) {\n return (\n <li className={cx(className) || undefined} {...rest}>\n <span className=\"key-info\">\n <strong>{children}</strong>\n {note != null && <span>{note}</span>}\n </span>\n {more != null && <span className=\"more-info\">{more}</span>}\n </li>\n );\n}\n\n/** 고객센터 안내 단 — 킷 `.f-cs`. 안에는 `FooterCsItem` 을 넣는다. */\nexport function FooterCs({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('f-cs', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/** 고객센터 항목 한 벌 — 킷 `.f-cs dl` + `.info-tit`. */\nexport type FooterCsItemProps = Omit<ComponentPropsWithRef<'dl'>, 'title' | 'children'> & {\n /** 항목 이름. 예: `고객센터` */\n title: ReactNode;\n /** 값. 예: `1577-1000` */\n children: ReactNode;\n};\n\nexport function FooterCsItem({ title, children, className, ...rest }: FooterCsItemProps) {\n return (\n <dl className={cx(className) || undefined} {...rest}>\n <dt className=\"info-tit\">{title}</dt>\n <dd>{children}</dd>\n </dl>\n );\n}\n\n/** 유틸리티 링크 묶음 — 킷 `.f-link`. `FooterGoLinks` 와 `FooterSnsLinks` 가 들어간다. */\nexport function FooterLinks({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('f-link', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/** 바로가기 링크 묶음 — 킷 `.link-go`. */\nexport function FooterGoLinks({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('link-go', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/**\n * 바로가기 링크 한 줄 — 킷 `.link-go > a.krds-btn.medium.text`.\n * 여기에 공용 `LinkButton` 을 쓰지 마라 — 킷이 이 자리의 크기를 따로 잡아 어긋난다.\n */\nexport type FooterGoLinkProps = ComponentPropsWithRef<'a'> & {\n /** 뒤에 붙는 킷 아이콘 이름(`ico-` 뺀 것). 기본은 샘플의 `angle` + 오른쪽 회전. */\n icon?: KrdsIcon | null;\n /** 아이콘 회전. 방향은 이름의 일부가 아니라 별도 클래스다 — `icon=\"angle right\"` 로 쓰지 마라. */\n iconDirection?: 'up' | 'down' | 'left' | 'right';\n};\n\nexport function FooterGoLink({\n icon = 'angle',\n iconDirection = 'right',\n className,\n children,\n target,\n title,\n ...rest\n}: FooterGoLinkProps) {\n return (\n <a\n className={cx('krds-btn', 'medium', 'text', className)}\n target={target}\n // 새 창으로 열리면 미리 알린다 — KRDS 접근성 요구. 푸터 샘플의 문구가 「새 창 열기」다.\n title={title ?? (target === '_blank' ? '새 창 열기' : undefined)}\n {...rest}\n >\n {children}\n {icon && <i className={cx(`svg-icon ico-${icon}`, iconDirection)} aria-hidden=\"true\" />}\n </a>\n );\n}\n\n/** 소셜 채널 묶음 — 킷 `.link-sns`. */\nexport function FooterSnsLinks({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('link-sns', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/**\n * 소셜 채널 아이콘 링크 — 킷 `a.krds-btn.xlarge.icon.border`. 채널 이름(`label`)이 필수다.\n * 킷에 있는 아이콘은 `instagram` · `youtube` · `sns-x` · `facebook` · `blog` 다.\n */\nexport type FooterSnsLinkProps = Omit<ComponentPropsWithRef<'a'>, 'children'> & {\n /** 스크린리더가 읽을 채널 이름. 예: `인스타그램` */\n label: string;\n /** 킷 아이콘 이름(`ico-` 뺀 것). 예: `instagram` */\n icon: KrdsIcon;\n};\n\nexport function FooterSnsLink({\n label,\n icon,\n className,\n target = '_blank',\n title = '새 창 열기',\n ...rest\n}: FooterSnsLinkProps) {\n return (\n <a\n className={cx('krds-btn', 'xlarge', 'icon', 'border', className)}\n target={target}\n title={title}\n {...rest}\n >\n <span className=\"sr-only\">{label}</span>\n <i className={`svg-icon ico-${icon}`} aria-hidden=\"true\" />\n </a>\n );\n}\n\n/** 맨 아래 줄 — 킷 `.f-btm`. 안에 `FooterBottomText` 와 `FooterIdentifier` 를 넣는다. */\nexport function FooterBottom({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('f-btm', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/** 정책 링크 + 저작권 한 줄 — 킷 `.f-btm-text`. PC 에서 좌우 양끝으로 벌어진다. */\nexport function FooterBottomText({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('f-btm-text', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/** 정책 링크 묶음 — 킷 `.f-menu`. */\nexport function FooterMenu({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('f-menu', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/** 정책 링크 하나. **개인정보처리방침에는 `point` 를 준다** — 규격이 다른 고지사항과 구분하라고 한다. */\nexport type FooterMenuLinkProps = ComponentPropsWithRef<'a'> & {\n /** 개인정보처리방침처럼 다른 고지사항과 구분해야 하는 링크. 굵게 그린다. */\n point?: boolean;\n};\n\nexport function FooterMenuLink({ point, className, children, ...rest }: FooterMenuLinkProps) {\n return (\n <a className={cx(point && 'point font-bold', className) || undefined} {...rest}>\n {children}\n </a>\n );\n}\n\n/** 저작권 — 킷 `.f-copy`. 규격상 푸터의 마지막 정보다(식별자는 그 뒤의 별도 구획). */\nexport function FooterCopyright({ className, children, ...rest }: ComponentPropsWithRef<'p'>) {\n return (\n <p className={cx('f-copy', className)} {...rest}>\n {children}\n </p>\n );\n}\n\n/**\n * 운영기관 식별자 — KRDS `.krds-identifier`. `FooterBottom` 의 **마지막 자식**으로 넣는다.\n *\n * 로고는 서비스 로고가 아니라 **운영 주체 기관**의 로고다(서비스 로고는 `FooterLogo`).\n * 문구 형식과 요소 배치는 규격이 변형을 금지한다 — `children` 은 번역을 넣는 자리다.\n * 푸터 밖에 독립해 두려면 `ui/identifier` 의 `Identifier` 를 쓴다.\n */\n\n/** KRDS 가 규정한 식별자 문구. 기관명만 갈아 끼운다. */\nexport function identifierText(orgName: string): string {\n return `이 누리집은 ${orgName} 누리집입니다.`;\n}\n\nexport type FooterIdentifierProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {\n /** 운영 기관 이름. 로고의 대체 텍스트로도 쓴다. */\n orgName: string;\n /** 로고 자리에 넣을 것(보통 `<img>`). 생략하면 킷 배경 로고만 나온다. */\n logo?: ReactNode;\n /** 안내 문구. 생략하면 `identifierText(orgName)`. 번역본 말고 다른 문구를 넣지 마라. */\n children?: ReactNode;\n /** 주면 `<section aria-label>` 로 랜드마크가 된다. 본문과 같은 문구를 넣지 마라(두 번 읽힌다). */\n label?: string;\n};\n\nexport function FooterIdentifier({\n orgName,\n logo,\n label,\n className,\n children,\n ...rest\n}: FooterIdentifierProps) {\n const inner = (\n <>\n <span className=\"logo\">\n {logo}\n <span className=\"sr-only\">{orgName}</span>\n </span>\n <span className=\"ban-txt\">{children ?? identifierText(orgName)}</span>\n </>\n );\n\n if (label) {\n return (\n <section\n className={cx('krds-identifier', className)}\n aria-label={label}\n {...(rest as ComponentPropsWithRef<'section'>)}\n >\n {inner}\n </section>\n );\n }\n return (\n <div className={cx('krds-identifier', className)} {...rest}>\n {inner}\n </div>\n );\n}\n"],"mappings":"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","names":["rest"]}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
|
+
import { type KrdsIcon } from '../lib/krds';
|
|
3
|
+
/**
|
|
4
|
+
* 헤더 — KRDS `#krds-header`.
|
|
5
|
+
*
|
|
6
|
+
* 조각을 규격 순서대로 조립한다 — 유틸리티 링크 그룹 → 서비스 아이덴티티(로고) → 주요 기능 버튼
|
|
7
|
+
* → 주메뉴. 그 앞의 건너뛰기 링크(`ui/skip-link`)와 공식 배너(`ui/masthead`)는 `<header>` 밖이라
|
|
8
|
+
* 셸에서 순서를 지켜야 한다.
|
|
9
|
+
* **`HeaderNaviButton`·`HeaderNaviLink` 의 `icon` 은 킷에 있는 5종뿐이다** — 다른 이름을 주면
|
|
10
|
+
* 검은 네모가 나온다. 그 밖의 기능은 `ui/button` 의 `Button` 을 쓴다.
|
|
11
|
+
* 드롭다운 열림 상태는 이 부품이 쥐지 않는다(화면 쪽 클라이언트 부품이 `open` 으로 내려 준다).
|
|
12
|
+
* 좁은 화면 숨김·표시는 킷이 처리하므로 미디어쿼리를 따로 쓰지 않는다.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <Header mobileNav={<MainMenuMobile items={menu} open={open} onClose={close} />}>
|
|
16
|
+
* <HeaderContainer>
|
|
17
|
+
* <HeaderUtility>
|
|
18
|
+
* <HeaderUtilityLink href="/en" icon="global">English</HeaderUtilityLink>
|
|
19
|
+
* </HeaderUtility>
|
|
20
|
+
* <HeaderBranding>
|
|
21
|
+
* <HeaderLogo name="○○기관" src="/site/logo.svg" />
|
|
22
|
+
* <HeaderActions>
|
|
23
|
+
* <HeaderNaviLink icon="login" href="/login">로그인</HeaderNaviLink>
|
|
24
|
+
* <HeaderNaviButton icon="all" onClick={openNav}>전체메뉴</HeaderNaviButton>
|
|
25
|
+
* </HeaderActions>
|
|
26
|
+
* </HeaderBranding>
|
|
27
|
+
* </HeaderContainer>
|
|
28
|
+
* <MainMenu items={menu} />
|
|
29
|
+
* </Header>
|
|
30
|
+
*
|
|
31
|
+
* 자세히: docs/krds/09-부품-노트.md#헤더
|
|
32
|
+
*/
|
|
33
|
+
/** 유틸리티 링크가 이 수 이상이면 드롭다운으로 묶는다(규격). */
|
|
34
|
+
export declare const HEADER_UTILITY_DROPDOWN_THRESHOLD = 5;
|
|
35
|
+
export type HeaderProps = Omit<ComponentPropsWithRef<'header'>, 'id'> & {
|
|
36
|
+
/** `.header-in` 안에 들어갈 것 — `HeaderContainer` 와 `MainMenu`. */
|
|
37
|
+
children?: ReactNode;
|
|
38
|
+
/** 모바일 전체메뉴(`MainMenuMobile`). `.header-in` 밖에 놓여야 헤더 띠에 갇히지 않는다. */
|
|
39
|
+
mobileNav?: ReactNode;
|
|
40
|
+
};
|
|
41
|
+
export declare function Header({ children, mobileNav, className, ...rest }: HeaderProps): import("react").JSX.Element;
|
|
42
|
+
/**
|
|
43
|
+
* 헤더 상단 줄 — 킷 `.header-container > .inner`. 본문과 같은 최대 너비·좌우 여백을 킷이 준다.
|
|
44
|
+
* `className` 은 바깥(`.header-container`)에 붙는다.
|
|
45
|
+
*/
|
|
46
|
+
export declare function HeaderContainer({ className, children, ...rest }: ComponentPropsWithRef<'div'>): import("react").JSX.Element;
|
|
47
|
+
/**
|
|
48
|
+
* 유틸리티 링크 그룹 — 킷 `.header-utility > ul.utility-list`.
|
|
49
|
+
*
|
|
50
|
+
* 자식을 **부품이 `<li>` 로 감싼다** — 직접 `<li>` 를 넣지 마라.
|
|
51
|
+
* **1023px 이하에서 킷이 통째로 감춘다** — 언어 전환처럼 반드시 닿아야 하는 것은
|
|
52
|
+
* 모바일 전체메뉴에도 한 벌 더 둔다. 5개 이상이면 `HeaderDropdown` 으로 묶는다(규격).
|
|
53
|
+
*/
|
|
54
|
+
export type HeaderUtilityProps = ComponentPropsWithRef<'div'> & {
|
|
55
|
+
children?: ReactNode;
|
|
56
|
+
};
|
|
57
|
+
export declare function HeaderUtility({ className, children, ...rest }: HeaderUtilityProps): import("react").JSX.Element;
|
|
58
|
+
/**
|
|
59
|
+
* 유틸리티 링크 한 칸 — 킷 `krds-btn small text`(밑줄 없는 작은 글자 버튼).
|
|
60
|
+
* 여기에 `ui/button` 의 `LinkButton` 을 쓰지 마라 — 그쪽은 밑줄 있는 `link` 변형이다.
|
|
61
|
+
*/
|
|
62
|
+
export type HeaderUtilityLinkProps = Omit<ComponentPropsWithRef<'a'>, 'href'> & {
|
|
63
|
+
href: string;
|
|
64
|
+
/** 글자 앞 아이콘(`ico-` 뺀 이름). 예: 언어 전환의 `global`. */
|
|
65
|
+
icon?: KrdsIcon;
|
|
66
|
+
/** 새 창으로 여는 바깥 주소. `UiLink` 대신 맨 `<a>` 로 그리고 `ico-go` 를 뒤에 붙인다. */
|
|
67
|
+
external?: boolean;
|
|
68
|
+
};
|
|
69
|
+
export declare function HeaderUtilityLink({ href, icon, external, className, children, title, ...rest }: HeaderUtilityLinkProps): import("react").JSX.Element;
|
|
70
|
+
/** 유틸리티 버튼 한 칸 — 화면을 옮기지 않고 레이어·모달을 여는 것(글자·화면 설정 등)에 쓴다. */
|
|
71
|
+
export type HeaderUtilityButtonProps = ComponentPropsWithRef<'button'> & {
|
|
72
|
+
icon?: KrdsIcon;
|
|
73
|
+
};
|
|
74
|
+
export declare function HeaderUtilityButton({ icon, className, children, type, ...rest }: HeaderUtilityButtonProps): import("react").JSX.Element;
|
|
75
|
+
/**
|
|
76
|
+
* 헤더 드롭다운 — 킷 `.krds-drop-wrap`. 언어 전환·개인 메뉴 자리다.
|
|
77
|
+
*
|
|
78
|
+
* **열림 상태를 쥐지 않는다** — `open` 을 받아 그리기만 한다.
|
|
79
|
+
* 바깥 클릭·Esc 로 닫는 것은 화면 쪽 클라이언트 부품이 맡는다.
|
|
80
|
+
* 표 행 동작처럼 키보드 메뉴 규약이 필요한 자리는 `ui/context-menu` 다.
|
|
81
|
+
*/
|
|
82
|
+
export type HeaderDropdownProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {
|
|
83
|
+
/** 여는 단추 글자. */
|
|
84
|
+
label: ReactNode;
|
|
85
|
+
/** 열렸는가. 화면 쪽에서 쥔 상태를 내려 준다. */
|
|
86
|
+
open?: boolean;
|
|
87
|
+
/** 여는 단추를 눌렀을 때. */
|
|
88
|
+
onToggle?: () => void;
|
|
89
|
+
/** 단추 모양. `utility` 는 유틸리티 줄, `navi` 는 `.header-actions` 의 개인 메뉴다. */
|
|
90
|
+
trigger?: 'utility' | 'navi';
|
|
91
|
+
/** `utility` 일 때 글자 앞 아이콘. 예: 언어 전환의 `global`. */
|
|
92
|
+
icon?: KrdsIcon;
|
|
93
|
+
/** `navi` 일 때 쓸 `.btn-navi` 아이콘. 기본 `my`. */
|
|
94
|
+
naviIcon?: HeaderNaviIcon;
|
|
95
|
+
/** 메뉴 정렬. 기본은 단추 가운데 정렬. */
|
|
96
|
+
align?: 'left' | 'center' | 'right';
|
|
97
|
+
/** 목록 위 영역 — 개인 메뉴의 이름·남은 시간 등. */
|
|
98
|
+
top?: ReactNode;
|
|
99
|
+
/** 목록 아래 영역 — 로그아웃·초기화 등. */
|
|
100
|
+
bottom?: ReactNode;
|
|
101
|
+
/** `HeaderDropdownItem` 들. */
|
|
102
|
+
children?: ReactNode;
|
|
103
|
+
};
|
|
104
|
+
export declare function HeaderDropdown({ label, open, onToggle, trigger, icon, naviIcon, align, top, bottom, className, children, ...rest }: HeaderDropdownProps): import("react").JSX.Element;
|
|
105
|
+
/**
|
|
106
|
+
* 드롭다운 한 줄 — 킷 `li > .item-link`. `href` 가 없으면 `<button>` 으로 그린다.
|
|
107
|
+
* 고른 항목에는 `.active` 와 함께 「선택됨」 안내가 붙는다(색만으로 알리지 않기 위해).
|
|
108
|
+
*/
|
|
109
|
+
export type HeaderDropdownItemProps = Omit<ComponentPropsWithRef<'a'>, 'href'> & {
|
|
110
|
+
/** 없으면 `<button type="button">` 이 된다. */
|
|
111
|
+
href?: string;
|
|
112
|
+
/** 지금 고른 항목. `.active` + 「선택됨」 안내가 붙는다. */
|
|
113
|
+
active?: boolean;
|
|
114
|
+
/** 새 창으로 여는 바깥 주소. */
|
|
115
|
+
external?: boolean;
|
|
116
|
+
/** 단추일 때의 클릭 처리. */
|
|
117
|
+
onSelect?: () => void;
|
|
118
|
+
};
|
|
119
|
+
export declare function HeaderDropdownItem({ href, active, external, onSelect, className, children, title, ...rest }: HeaderDropdownItemProps): import("react").JSX.Element;
|
|
120
|
+
/** 로고와 주요 기능 버튼을 담는 줄 — 킷 `.header-branding`. */
|
|
121
|
+
export declare function HeaderBranding({ className, children, ...rest }: ComponentPropsWithRef<'div'>): import("react").JSX.Element;
|
|
122
|
+
/**
|
|
123
|
+
* 서비스 아이덴티티(로고) — 킷 `.logo > a`. 메인 화면으로 가는 링크다.
|
|
124
|
+
*
|
|
125
|
+
* **`src` 를 주지 않으면 킷의 KRDS 로고가 그대로 뜬다.** 로고 칸은 137×56px 고정이라
|
|
126
|
+
* 비율이 다른 파일은 여백이 생긴다 — 파일 쪽에서 맞춘다.
|
|
127
|
+
* 대체 텍스트에 「로고」라는 단어를 넣지 마라(규격).
|
|
128
|
+
*/
|
|
129
|
+
export type HeaderLogoProps = Omit<ComponentPropsWithRef<'a'>, 'href' | 'children'> & {
|
|
130
|
+
/** 스크린리더가 읽을 기관/서비스 이름. 「로고」라는 단어를 넣지 마라. */
|
|
131
|
+
name: string;
|
|
132
|
+
/** 이동 주소. 규격상 메인 화면. */
|
|
133
|
+
href?: string;
|
|
134
|
+
/** 기관 로고 이미지 주소. 없고 `wordmark` 도 없으면 킷의 KRDS 로고가 그대로 뜬다. */
|
|
135
|
+
src?: string;
|
|
136
|
+
/** 로고 파일이 없을 때 글자로 대신한다. 배경 이미지와 고정 너비를 끈다. */
|
|
137
|
+
wordmark?: ReactNode;
|
|
138
|
+
/** 감쌀 제목 태그. 기본 `h2` — 로고가 그 화면의 최상위 제목이면 `h1`, 목차에 안 넣으려면 `div`. */
|
|
139
|
+
heading?: 'h1' | 'h2' | 'div';
|
|
140
|
+
};
|
|
141
|
+
export declare function HeaderLogo({ name, href, src, wordmark, heading, className, style, ...rest }: HeaderLogoProps): import("react").JSX.Element;
|
|
142
|
+
/** 주요 기능 버튼 묶음 — 킷 `.header-actions`. 킷이 오른쪽에 붙인다. */
|
|
143
|
+
export declare function HeaderActions({ className, children, ...rest }: ComponentPropsWithRef<'div'>): import("react").JSX.Element;
|
|
144
|
+
/** `.btn-navi` 가 아이콘을 가진 5종. 다른 이름을 주면 마스크 없는 검은 네모가 남는다. */
|
|
145
|
+
export type HeaderNaviIcon = 'sch' | 'login' | 'join' | 'my' | 'all';
|
|
146
|
+
type NaviBase = {
|
|
147
|
+
/** 킷에 있는 5종 중 하나. 필수 — 빠지면 아이콘 자리가 검은 네모가 된다. */
|
|
148
|
+
icon: HeaderNaviIcon;
|
|
149
|
+
/** 가로형 — 아이콘과 글자를 한 줄에. 기본은 세로형이고, 한 헤더 안에서 섞지 마라. */
|
|
150
|
+
row?: boolean;
|
|
151
|
+
className?: string;
|
|
152
|
+
children?: ReactNode;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* 헤더 주요 기능 버튼 — 킷 `.btn-navi`. 레이어·전체메뉴를 여는 자리다.
|
|
156
|
+
*
|
|
157
|
+
* 좁은 화면에서 `join`·`my` 를, 1024px 이상에서 `all` 을 킷이 감춘다 —
|
|
158
|
+
* 미디어쿼리를 따로 쓰지 마라. `icon="all"` 이면 `aria-controls="mobile-nav"` 가 자동으로 붙는다.
|
|
159
|
+
*/
|
|
160
|
+
export type HeaderNaviButtonProps = Omit<ComponentPropsWithRef<'button'>, 'children'> & NaviBase;
|
|
161
|
+
export declare function HeaderNaviButton({ icon, row, className, children, type, 'aria-controls': ariaControls, ...rest }: HeaderNaviButtonProps): import("react").JSX.Element;
|
|
162
|
+
/** 헤더 주요 기능 링크 — 화면을 옮기는 것(로그인 등)만 링크로 둔다. 레이어는 `HeaderNaviButton`. */
|
|
163
|
+
export type HeaderNaviLinkProps = Omit<ComponentPropsWithRef<'a'>, 'href' | 'children'> & NaviBase & {
|
|
164
|
+
href: string;
|
|
165
|
+
/** 새 창으로 여는 바깥 주소. */
|
|
166
|
+
external?: boolean;
|
|
167
|
+
};
|
|
168
|
+
export declare function HeaderNaviLink({ icon, row, href, external, className, children, title, ...rest }: HeaderNaviLinkProps): import("react").JSX.Element;
|
|
169
|
+
export {};
|
|
170
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/header/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { UiLink } from "../lib/link.js";
|
|
3
|
+
import { Children, isValidElement } from "react";
|
|
4
|
+
import { cx } from "../lib/krds.js";
|
|
5
|
+
const HEADER_UTILITY_DROPDOWN_THRESHOLD = 5;
|
|
6
|
+
function Header({ children, mobileNav, className, ...rest }) {
|
|
7
|
+
return /* @__PURE__ */ jsxs(
|
|
8
|
+
"header",
|
|
9
|
+
{
|
|
10
|
+
className: cx(className) || void 0,
|
|
11
|
+
...rest,
|
|
12
|
+
id: "krds-header",
|
|
13
|
+
children: [
|
|
14
|
+
/* @__PURE__ */ jsx("div", { className: "header-in", children }),
|
|
15
|
+
mobileNav
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function HeaderContainer({ className, children, ...rest }) {
|
|
21
|
+
return /* @__PURE__ */ jsx("div", { className: cx("header-container", className), ...rest, children: /* @__PURE__ */ jsx("div", { className: "inner", children }) });
|
|
22
|
+
}
|
|
23
|
+
function HeaderUtility({ className, children, ...rest }) {
|
|
24
|
+
const items = Children.toArray(children);
|
|
25
|
+
if (process.env.NODE_ENV !== "production" && items.length >= HEADER_UTILITY_DROPDOWN_THRESHOLD) {
|
|
26
|
+
console.warn(
|
|
27
|
+
`[HeaderUtility] \uC720\uD2F8\uB9AC\uD2F0 \uB9C1\uD06C\uAC00 ${items.length}\uAC1C\uB2E4. ${HEADER_UTILITY_DROPDOWN_THRESHOLD}\uAC1C \uC774\uC0C1\uC774\uBA74 \uBE44\uC2B7\uD55C \uAC83\uB07C\uB9AC HeaderDropdown \uC73C\uB85C \uBB36\uC5B4\uB77C(KRDS 02_03).`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return /* @__PURE__ */ jsx("div", { className: cx("header-utility", className), ...rest, children: /* @__PURE__ */ jsx("ul", { className: "utility-list", children: items.map((child, i) => /* @__PURE__ */ jsx("li", { children: child }, isValidElement(child) && child.key || i)) }) });
|
|
31
|
+
}
|
|
32
|
+
const NEW_WINDOW_TITLE = "\uC0C8 \uCC3D \uC5F4\uB9BC";
|
|
33
|
+
function HeaderUtilityLink({
|
|
34
|
+
href,
|
|
35
|
+
icon,
|
|
36
|
+
external,
|
|
37
|
+
className,
|
|
38
|
+
children,
|
|
39
|
+
title,
|
|
40
|
+
...rest
|
|
41
|
+
}) {
|
|
42
|
+
const cls = cx("krds-btn", "small", "text", className);
|
|
43
|
+
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
44
|
+
icon && /* @__PURE__ */ jsx("i", { className: `svg-icon ico-${icon}`, "aria-hidden": "true" }),
|
|
45
|
+
children,
|
|
46
|
+
external && /* @__PURE__ */ jsx("i", { className: "svg-icon ico-go", "aria-hidden": "true" })
|
|
47
|
+
] });
|
|
48
|
+
return external ? /* @__PURE__ */ jsx(
|
|
49
|
+
"a",
|
|
50
|
+
{
|
|
51
|
+
className: cls,
|
|
52
|
+
href,
|
|
53
|
+
target: "_blank",
|
|
54
|
+
rel: "noopener noreferrer",
|
|
55
|
+
title: title ?? NEW_WINDOW_TITLE,
|
|
56
|
+
...rest,
|
|
57
|
+
children: inner
|
|
58
|
+
}
|
|
59
|
+
) : /* @__PURE__ */ jsx(UiLink, { className: cls, href, title, ...rest, children: inner });
|
|
60
|
+
}
|
|
61
|
+
function HeaderUtilityButton({
|
|
62
|
+
icon,
|
|
63
|
+
className,
|
|
64
|
+
children,
|
|
65
|
+
type = "button",
|
|
66
|
+
...rest
|
|
67
|
+
}) {
|
|
68
|
+
return /* @__PURE__ */ jsxs("button", { type, className: cx("krds-btn", "small", "text", className), ...rest, children: [
|
|
69
|
+
icon && /* @__PURE__ */ jsx("i", { className: `svg-icon ico-${icon}`, "aria-hidden": "true" }),
|
|
70
|
+
children
|
|
71
|
+
] });
|
|
72
|
+
}
|
|
73
|
+
function HeaderDropdown({
|
|
74
|
+
label,
|
|
75
|
+
open = false,
|
|
76
|
+
onToggle,
|
|
77
|
+
trigger = "utility",
|
|
78
|
+
icon,
|
|
79
|
+
naviIcon = "my",
|
|
80
|
+
align = "center",
|
|
81
|
+
top,
|
|
82
|
+
bottom,
|
|
83
|
+
className,
|
|
84
|
+
children,
|
|
85
|
+
...rest
|
|
86
|
+
}) {
|
|
87
|
+
const navi = trigger === "navi";
|
|
88
|
+
return /* @__PURE__ */ jsxs(
|
|
89
|
+
"div",
|
|
90
|
+
{
|
|
91
|
+
className: cx(
|
|
92
|
+
"krds-drop-wrap",
|
|
93
|
+
// `.my-drop` 은 1023px 이하에서 킷이 감춘다 — 개인 메뉴는 모바일 전체메뉴 쪽에도 둔다.
|
|
94
|
+
navi && "my-drop",
|
|
95
|
+
align === "left" && "drop-left",
|
|
96
|
+
align === "right" && "drop-right",
|
|
97
|
+
className
|
|
98
|
+
),
|
|
99
|
+
...rest,
|
|
100
|
+
children: [
|
|
101
|
+
/* @__PURE__ */ jsxs(
|
|
102
|
+
"button",
|
|
103
|
+
{
|
|
104
|
+
type: "button",
|
|
105
|
+
className: navi ? cx("btn-navi", naviIcon, "drop-btn") : cx("krds-btn", "small", "text", "drop-btn"),
|
|
106
|
+
"aria-expanded": open,
|
|
107
|
+
onClick: onToggle,
|
|
108
|
+
children: [
|
|
109
|
+
!navi && icon && /* @__PURE__ */ jsx("i", { className: `svg-icon ico-${icon}`, "aria-hidden": "true" }),
|
|
110
|
+
label,
|
|
111
|
+
!navi && /* @__PURE__ */ jsx("i", { className: "svg-icon ico-toggle", "aria-hidden": "true" })
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
),
|
|
115
|
+
/* @__PURE__ */ jsx("div", { className: "drop-menu", style: { display: open ? "block" : "none" }, children: /* @__PURE__ */ jsxs("div", { className: "drop-in", children: [
|
|
116
|
+
top !== void 0 && /* @__PURE__ */ jsx("div", { className: "drop-top", children: top }),
|
|
117
|
+
children !== void 0 && /* @__PURE__ */ jsx("ul", { className: "drop-list", children }),
|
|
118
|
+
bottom !== void 0 && /* @__PURE__ */ jsx("div", { className: "drop-bottom", children: bottom })
|
|
119
|
+
] }) })
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
function HeaderDropdownItem({
|
|
125
|
+
href,
|
|
126
|
+
active,
|
|
127
|
+
external,
|
|
128
|
+
onSelect,
|
|
129
|
+
className,
|
|
130
|
+
children,
|
|
131
|
+
title,
|
|
132
|
+
...rest
|
|
133
|
+
}) {
|
|
134
|
+
const cls = cx("item-link", active && "active", className);
|
|
135
|
+
const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
136
|
+
children,
|
|
137
|
+
external && /* @__PURE__ */ jsx("i", { className: "svg-icon ico-go", "aria-hidden": "true" }),
|
|
138
|
+
active && /* @__PURE__ */ jsx("span", { className: "sr-only", children: "\uC120\uD0DD\uB428" })
|
|
139
|
+
] });
|
|
140
|
+
if (!href) {
|
|
141
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
142
|
+
"button",
|
|
143
|
+
{
|
|
144
|
+
type: "button",
|
|
145
|
+
className: cls,
|
|
146
|
+
onClick: onSelect,
|
|
147
|
+
...rest,
|
|
148
|
+
children: inner
|
|
149
|
+
}
|
|
150
|
+
) });
|
|
151
|
+
}
|
|
152
|
+
return /* @__PURE__ */ jsx("li", { children: external ? /* @__PURE__ */ jsx(
|
|
153
|
+
"a",
|
|
154
|
+
{
|
|
155
|
+
className: cls,
|
|
156
|
+
href,
|
|
157
|
+
target: "_blank",
|
|
158
|
+
rel: "noopener noreferrer",
|
|
159
|
+
title: title ?? NEW_WINDOW_TITLE,
|
|
160
|
+
...rest,
|
|
161
|
+
children: inner
|
|
162
|
+
}
|
|
163
|
+
) : /* @__PURE__ */ jsx(UiLink, { className: cls, href, title, ...rest, children: inner }) });
|
|
164
|
+
}
|
|
165
|
+
function HeaderBranding({ className, children, ...rest }) {
|
|
166
|
+
return /* @__PURE__ */ jsx("div", { className: cx("header-branding", className), ...rest, children });
|
|
167
|
+
}
|
|
168
|
+
function HeaderLogo({
|
|
169
|
+
name,
|
|
170
|
+
href = "/",
|
|
171
|
+
src,
|
|
172
|
+
wordmark,
|
|
173
|
+
heading = "h2",
|
|
174
|
+
className,
|
|
175
|
+
style,
|
|
176
|
+
...rest
|
|
177
|
+
}) {
|
|
178
|
+
const Heading = heading;
|
|
179
|
+
const headingStyle = wordmark ? { width: "auto" } : void 0;
|
|
180
|
+
const linkStyle = {
|
|
181
|
+
...src ? { backgroundImage: `url("${src}")` } : null,
|
|
182
|
+
...wordmark && !src ? { backgroundImage: "none" } : null,
|
|
183
|
+
...style
|
|
184
|
+
};
|
|
185
|
+
return /* @__PURE__ */ jsx(Heading, { className: cx("logo", className), style: headingStyle, children: /* @__PURE__ */ jsx(
|
|
186
|
+
UiLink,
|
|
187
|
+
{
|
|
188
|
+
href,
|
|
189
|
+
style: Object.keys(linkStyle).length ? linkStyle : void 0,
|
|
190
|
+
"aria-label": wordmark ? name : void 0,
|
|
191
|
+
...rest,
|
|
192
|
+
children: wordmark ?? /* @__PURE__ */ jsx("span", { className: "sr-only", children: name })
|
|
193
|
+
}
|
|
194
|
+
) });
|
|
195
|
+
}
|
|
196
|
+
function HeaderActions({ className, children, ...rest }) {
|
|
197
|
+
return /* @__PURE__ */ jsx("div", { className: cx("header-actions", className), ...rest, children });
|
|
198
|
+
}
|
|
199
|
+
function HeaderNaviButton({
|
|
200
|
+
icon,
|
|
201
|
+
row,
|
|
202
|
+
className,
|
|
203
|
+
children,
|
|
204
|
+
type = "button",
|
|
205
|
+
"aria-controls": ariaControls,
|
|
206
|
+
...rest
|
|
207
|
+
}) {
|
|
208
|
+
return /* @__PURE__ */ jsx(
|
|
209
|
+
"button",
|
|
210
|
+
{
|
|
211
|
+
type,
|
|
212
|
+
className: cx("btn-navi", icon, row && "navi-row", className),
|
|
213
|
+
"aria-controls": ariaControls ?? (icon === "all" ? "mobile-nav" : void 0),
|
|
214
|
+
...rest,
|
|
215
|
+
children
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
function HeaderNaviLink({
|
|
220
|
+
icon,
|
|
221
|
+
row,
|
|
222
|
+
href,
|
|
223
|
+
external,
|
|
224
|
+
className,
|
|
225
|
+
children,
|
|
226
|
+
title,
|
|
227
|
+
...rest
|
|
228
|
+
}) {
|
|
229
|
+
const cls = cx("btn-navi", icon, row && "navi-row", className);
|
|
230
|
+
return external ? /* @__PURE__ */ jsx(
|
|
231
|
+
"a",
|
|
232
|
+
{
|
|
233
|
+
className: cls,
|
|
234
|
+
href,
|
|
235
|
+
target: "_blank",
|
|
236
|
+
rel: "noopener noreferrer",
|
|
237
|
+
title: title ?? NEW_WINDOW_TITLE,
|
|
238
|
+
...rest,
|
|
239
|
+
children
|
|
240
|
+
}
|
|
241
|
+
) : /* @__PURE__ */ jsx(UiLink, { className: cls, href, title, ...rest, children });
|
|
242
|
+
}
|
|
243
|
+
export {
|
|
244
|
+
HEADER_UTILITY_DROPDOWN_THRESHOLD,
|
|
245
|
+
Header,
|
|
246
|
+
HeaderActions,
|
|
247
|
+
HeaderBranding,
|
|
248
|
+
HeaderContainer,
|
|
249
|
+
HeaderDropdown,
|
|
250
|
+
HeaderDropdownItem,
|
|
251
|
+
HeaderLogo,
|
|
252
|
+
HeaderNaviButton,
|
|
253
|
+
HeaderNaviLink,
|
|
254
|
+
HeaderUtility,
|
|
255
|
+
HeaderUtilityButton,
|
|
256
|
+
HeaderUtilityLink
|
|
257
|
+
};
|
|
258
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/header/index.tsx"],"sourcesContent":["import { UiLink } from '../lib/link';\nimport { Children, isValidElement, type ComponentPropsWithRef, type ReactNode } from 'react';\nimport { cx, type KrdsIcon } from '../lib/krds';\n\n/**\n * 헤더 — KRDS `#krds-header`.\n *\n * 조각을 규격 순서대로 조립한다 — 유틸리티 링크 그룹 → 서비스 아이덴티티(로고) → 주요 기능 버튼\n * → 주메뉴. 그 앞의 건너뛰기 링크(`ui/skip-link`)와 공식 배너(`ui/masthead`)는 `<header>` 밖이라\n * 셸에서 순서를 지켜야 한다.\n * **`HeaderNaviButton`·`HeaderNaviLink` 의 `icon` 은 킷에 있는 5종뿐이다** — 다른 이름을 주면\n * 검은 네모가 나온다. 그 밖의 기능은 `ui/button` 의 `Button` 을 쓴다.\n * 드롭다운 열림 상태는 이 부품이 쥐지 않는다(화면 쪽 클라이언트 부품이 `open` 으로 내려 준다).\n * 좁은 화면 숨김·표시는 킷이 처리하므로 미디어쿼리를 따로 쓰지 않는다.\n *\n * @example\n * <Header mobileNav={<MainMenuMobile items={menu} open={open} onClose={close} />}>\n * <HeaderContainer>\n * <HeaderUtility>\n * <HeaderUtilityLink href=\"/en\" icon=\"global\">English</HeaderUtilityLink>\n * </HeaderUtility>\n * <HeaderBranding>\n * <HeaderLogo name=\"○○기관\" src=\"/site/logo.svg\" />\n * <HeaderActions>\n * <HeaderNaviLink icon=\"login\" href=\"/login\">로그인</HeaderNaviLink>\n * <HeaderNaviButton icon=\"all\" onClick={openNav}>전체메뉴</HeaderNaviButton>\n * </HeaderActions>\n * </HeaderBranding>\n * </HeaderContainer>\n * <MainMenu items={menu} />\n * </Header>\n *\n * 자세히: docs/krds/09-부품-노트.md#헤더\n */\n\n/** 유틸리티 링크가 이 수 이상이면 드롭다운으로 묶는다(규격). */\nexport const HEADER_UTILITY_DROPDOWN_THRESHOLD = 5;\n\n/* ────────────────────────────────────────────────────────────────────────── */\n/* 뿌리 */\n/* ────────────────────────────────────────────────────────────────────────── */\n\nexport type HeaderProps = Omit<ComponentPropsWithRef<'header'>, 'id'> & {\n /** `.header-in` 안에 들어갈 것 — `HeaderContainer` 와 `MainMenu`. */\n children?: ReactNode;\n /** 모바일 전체메뉴(`MainMenuMobile`). `.header-in` 밖에 놓여야 헤더 띠에 갇히지 않는다. */\n mobileNav?: ReactNode;\n};\n\nexport function Header({ children, mobileNav, className, ...rest }: HeaderProps) {\n return (\n <header\n // 모양이 `#krds-header` 아이디에 걸려 있어 뿌리에는 킷 클래스가 없다. 빈 class 를 남기지 않는다.\n className={cx(className) || undefined}\n {...rest}\n // 킷 CSS 가 물고 있는 선택자다. rest 로 덮이지 않도록 마지막에 고정한다.\n id=\"krds-header\"\n >\n <div className=\"header-in\">{children}</div>\n {mobileNav}\n </header>\n );\n}\n\n/**\n * 헤더 상단 줄 — 킷 `.header-container > .inner`. 본문과 같은 최대 너비·좌우 여백을 킷이 준다.\n * `className` 은 바깥(`.header-container`)에 붙는다.\n */\nexport function HeaderContainer({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('header-container', className)} {...rest}>\n <div className=\"inner\">{children}</div>\n </div>\n );\n}\n\n/* ────────────────────────────────────────────────────────────────────────── */\n/* 유틸리티 링크 그룹 */\n/* ────────────────────────────────────────────────────────────────────────── */\n\n/**\n * 유틸리티 링크 그룹 — 킷 `.header-utility > ul.utility-list`.\n *\n * 자식을 **부품이 `<li>` 로 감싼다** — 직접 `<li>` 를 넣지 마라.\n * **1023px 이하에서 킷이 통째로 감춘다** — 언어 전환처럼 반드시 닿아야 하는 것은\n * 모바일 전체메뉴에도 한 벌 더 둔다. 5개 이상이면 `HeaderDropdown` 으로 묶는다(규격).\n */\nexport type HeaderUtilityProps = ComponentPropsWithRef<'div'> & { children?: ReactNode };\n\nexport function HeaderUtility({ className, children, ...rest }: HeaderUtilityProps) {\n const items = Children.toArray(children);\n\n if (\n process.env.NODE_ENV !== 'production' &&\n items.length >= HEADER_UTILITY_DROPDOWN_THRESHOLD\n ) {\n // 규격: 「유틸리티 링크가 5개 이상 필요한 경우 드롭다운 메뉴를 사용한다」.\n console.warn(\n `[HeaderUtility] 유틸리티 링크가 ${items.length}개다. ` +\n `${HEADER_UTILITY_DROPDOWN_THRESHOLD}개 이상이면 비슷한 것끼리 HeaderDropdown 으로 묶어라(KRDS 02_03).`,\n );\n }\n\n return (\n <div className={cx('header-utility', className)} {...rest}>\n <ul className=\"utility-list\">\n {items.map((child, i) => (\n <li key={(isValidElement(child) && child.key) || i}>{child}</li>\n ))}\n </ul>\n </div>\n );\n}\n\n/**\n * 유틸리티 링크 한 칸 — 킷 `krds-btn small text`(밑줄 없는 작은 글자 버튼).\n * 여기에 `ui/button` 의 `LinkButton` 을 쓰지 마라 — 그쪽은 밑줄 있는 `link` 변형이다.\n */\nexport type HeaderUtilityLinkProps = Omit<ComponentPropsWithRef<'a'>, 'href'> & {\n href: string;\n /** 글자 앞 아이콘(`ico-` 뺀 이름). 예: 언어 전환의 `global`. */\n icon?: KrdsIcon;\n /** 새 창으로 여는 바깥 주소. `UiLink` 대신 맨 `<a>` 로 그리고 `ico-go` 를 뒤에 붙인다. */\n external?: boolean;\n};\n\n/** 새 창 안내 문구. `ui/button` 과 맞춰 하나로 통일한다. */\nconst NEW_WINDOW_TITLE = '새 창 열림';\n\nexport function HeaderUtilityLink({\n href,\n icon,\n external,\n className,\n children,\n title,\n ...rest\n}: HeaderUtilityLinkProps) {\n const cls = cx('krds-btn', 'small', 'text', className);\n const inner = (\n <>\n {icon && <i className={`svg-icon ico-${icon}`} aria-hidden=\"true\" />}\n {children}\n {external && <i className=\"svg-icon ico-go\" aria-hidden=\"true\" />}\n </>\n );\n\n return external ? (\n <a\n className={cls}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title={title ?? NEW_WINDOW_TITLE}\n {...rest}\n >\n {inner}\n </a>\n ) : (\n <UiLink className={cls} href={href} title={title} {...rest}>\n {inner}\n </UiLink>\n );\n}\n\n/** 유틸리티 버튼 한 칸 — 화면을 옮기지 않고 레이어·모달을 여는 것(글자·화면 설정 등)에 쓴다. */\nexport type HeaderUtilityButtonProps = ComponentPropsWithRef<'button'> & { icon?: KrdsIcon };\n\nexport function HeaderUtilityButton({\n icon,\n className,\n children,\n type = 'button',\n ...rest\n}: HeaderUtilityButtonProps) {\n return (\n <button type={type} className={cx('krds-btn', 'small', 'text', className)} {...rest}>\n {icon && <i className={`svg-icon ico-${icon}`} aria-hidden=\"true\" />}\n {children}\n </button>\n );\n}\n\n/* ────────────────────────────────────────────────────────────────────────── */\n/* 드롭다운 */\n/* ────────────────────────────────────────────────────────────────────────── */\n\n/**\n * 헤더 드롭다운 — 킷 `.krds-drop-wrap`. 언어 전환·개인 메뉴 자리다.\n *\n * **열림 상태를 쥐지 않는다** — `open` 을 받아 그리기만 한다.\n * 바깥 클릭·Esc 로 닫는 것은 화면 쪽 클라이언트 부품이 맡는다.\n * 표 행 동작처럼 키보드 메뉴 규약이 필요한 자리는 `ui/context-menu` 다.\n */\nexport type HeaderDropdownProps = Omit<ComponentPropsWithRef<'div'>, 'children'> & {\n /** 여는 단추 글자. */\n label: ReactNode;\n /** 열렸는가. 화면 쪽에서 쥔 상태를 내려 준다. */\n open?: boolean;\n /** 여는 단추를 눌렀을 때. */\n onToggle?: () => void;\n /** 단추 모양. `utility` 는 유틸리티 줄, `navi` 는 `.header-actions` 의 개인 메뉴다. */\n trigger?: 'utility' | 'navi';\n /** `utility` 일 때 글자 앞 아이콘. 예: 언어 전환의 `global`. */\n icon?: KrdsIcon;\n /** `navi` 일 때 쓸 `.btn-navi` 아이콘. 기본 `my`. */\n naviIcon?: HeaderNaviIcon;\n /** 메뉴 정렬. 기본은 단추 가운데 정렬. */\n align?: 'left' | 'center' | 'right';\n /** 목록 위 영역 — 개인 메뉴의 이름·남은 시간 등. */\n top?: ReactNode;\n /** 목록 아래 영역 — 로그아웃·초기화 등. */\n bottom?: ReactNode;\n /** `HeaderDropdownItem` 들. */\n children?: ReactNode;\n};\n\nexport function HeaderDropdown({\n label,\n open = false,\n onToggle,\n trigger = 'utility',\n icon,\n naviIcon = 'my',\n align = 'center',\n top,\n bottom,\n className,\n children,\n ...rest\n}: HeaderDropdownProps) {\n const navi = trigger === 'navi';\n\n return (\n <div\n className={cx(\n 'krds-drop-wrap',\n // `.my-drop` 은 1023px 이하에서 킷이 감춘다 — 개인 메뉴는 모바일 전체메뉴 쪽에도 둔다.\n navi && 'my-drop',\n align === 'left' && 'drop-left',\n align === 'right' && 'drop-right',\n className,\n )}\n {...rest}\n >\n <button\n type=\"button\"\n className={\n navi\n ? cx('btn-navi', naviIcon, 'drop-btn')\n : cx('krds-btn', 'small', 'text', 'drop-btn')\n }\n aria-expanded={open}\n onClick={onToggle}\n >\n {!navi && icon && <i className={`svg-icon ico-${icon}`} aria-hidden=\"true\" />}\n {label}\n {/* 킷 샘플: 유틸리티 드롭다운만 뒤에 여닫음 화살표를 둔다. `.btn-navi` 는 ::before 아이콘이 이미 있다. */}\n {!navi && <i className=\"svg-icon ico-toggle\" aria-hidden=\"true\" />}\n </button>\n <div className=\"drop-menu\" style={{ display: open ? 'block' : 'none' }}>\n <div className=\"drop-in\">\n {top !== undefined && <div className=\"drop-top\">{top}</div>}\n {children !== undefined && <ul className=\"drop-list\">{children}</ul>}\n {bottom !== undefined && <div className=\"drop-bottom\">{bottom}</div>}\n </div>\n </div>\n </div>\n );\n}\n\n/**\n * 드롭다운 한 줄 — 킷 `li > .item-link`. `href` 가 없으면 `<button>` 으로 그린다.\n * 고른 항목에는 `.active` 와 함께 「선택됨」 안내가 붙는다(색만으로 알리지 않기 위해).\n */\nexport type HeaderDropdownItemProps = Omit<ComponentPropsWithRef<'a'>, 'href'> & {\n /** 없으면 `<button type=\"button\">` 이 된다. */\n href?: string;\n /** 지금 고른 항목. `.active` + 「선택됨」 안내가 붙는다. */\n active?: boolean;\n /** 새 창으로 여는 바깥 주소. */\n external?: boolean;\n /** 단추일 때의 클릭 처리. */\n onSelect?: () => void;\n};\n\nexport function HeaderDropdownItem({\n href,\n active,\n external,\n onSelect,\n className,\n children,\n title,\n ...rest\n}: HeaderDropdownItemProps) {\n const cls = cx('item-link', active && 'active', className);\n const inner = (\n <>\n {children}\n {external && <i className=\"svg-icon ico-go\" aria-hidden=\"true\" />}\n {active && <span className=\"sr-only\">선택됨</span>}\n </>\n );\n\n if (!href) {\n return (\n <li>\n <button\n type=\"button\"\n className={cls}\n onClick={onSelect}\n // `<a>` 용 props 를 `<button>` 에 흘리지 않는다 — lang·aria-* 만 쓰이는 자리다.\n {...(rest as ComponentPropsWithRef<'button'>)}\n >\n {inner}\n </button>\n </li>\n );\n }\n\n return (\n <li>\n {external ? (\n <a\n className={cls}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title={title ?? NEW_WINDOW_TITLE}\n {...rest}\n >\n {inner}\n </a>\n ) : (\n <UiLink className={cls} href={href} title={title} {...rest}>\n {inner}\n </UiLink>\n )}\n </li>\n );\n}\n\n/* ────────────────────────────────────────────────────────────────────────── */\n/* 서비스 아이덴티티 · 주요 기능 */\n/* ────────────────────────────────────────────────────────────────────────── */\n\n/** 로고와 주요 기능 버튼을 담는 줄 — 킷 `.header-branding`. */\nexport function HeaderBranding({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('header-branding', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/**\n * 서비스 아이덴티티(로고) — 킷 `.logo > a`. 메인 화면으로 가는 링크다.\n *\n * **`src` 를 주지 않으면 킷의 KRDS 로고가 그대로 뜬다.** 로고 칸은 137×56px 고정이라\n * 비율이 다른 파일은 여백이 생긴다 — 파일 쪽에서 맞춘다.\n * 대체 텍스트에 「로고」라는 단어를 넣지 마라(규격).\n */\nexport type HeaderLogoProps = Omit<ComponentPropsWithRef<'a'>, 'href' | 'children'> & {\n /** 스크린리더가 읽을 기관/서비스 이름. 「로고」라는 단어를 넣지 마라. */\n name: string;\n /** 이동 주소. 규격상 메인 화면. */\n href?: string;\n /** 기관 로고 이미지 주소. 없고 `wordmark` 도 없으면 킷의 KRDS 로고가 그대로 뜬다. */\n src?: string;\n /** 로고 파일이 없을 때 글자로 대신한다. 배경 이미지와 고정 너비를 끈다. */\n wordmark?: ReactNode;\n /** 감쌀 제목 태그. 기본 `h2` — 로고가 그 화면의 최상위 제목이면 `h1`, 목차에 안 넣으려면 `div`. */\n heading?: 'h1' | 'h2' | 'div';\n};\n\nexport function HeaderLogo({\n name,\n href = '/',\n src,\n wordmark,\n heading = 'h2',\n className,\n style,\n ...rest\n}: HeaderLogoProps) {\n const Heading = heading;\n // 글자 로고는 킷의 고정 너비에 갇히면 잘린다. 아이디 선택자를 이기려면 인라인이어야 한다.\n const headingStyle = wordmark ? { width: 'auto' } : undefined;\n const linkStyle = {\n ...(src ? { backgroundImage: `url(\"${src}\")` } : null),\n ...(wordmark && !src ? { backgroundImage: 'none' } : null),\n ...style,\n };\n\n return (\n <Heading className={cx('logo', className)} style={headingStyle}>\n <UiLink\n href={href}\n style={Object.keys(linkStyle).length ? linkStyle : undefined}\n // 보이는 글자가 이름에 포함되도록 넘긴다(WCAG 2.5.3 Label in Name).\n aria-label={wordmark ? name : undefined}\n {...rest}\n >\n {wordmark ?? <span className=\"sr-only\">{name}</span>}\n </UiLink>\n </Heading>\n );\n}\n\n/** 주요 기능 버튼 묶음 — 킷 `.header-actions`. 킷이 오른쪽에 붙인다. */\nexport function HeaderActions({ className, children, ...rest }: ComponentPropsWithRef<'div'>) {\n return (\n <div className={cx('header-actions', className)} {...rest}>\n {children}\n </div>\n );\n}\n\n/** `.btn-navi` 가 아이콘을 가진 5종. 다른 이름을 주면 마스크 없는 검은 네모가 남는다. */\nexport type HeaderNaviIcon = 'sch' | 'login' | 'join' | 'my' | 'all';\n\ntype NaviBase = {\n /** 킷에 있는 5종 중 하나. 필수 — 빠지면 아이콘 자리가 검은 네모가 된다. */\n icon: HeaderNaviIcon;\n /** 가로형 — 아이콘과 글자를 한 줄에. 기본은 세로형이고, 한 헤더 안에서 섞지 마라. */\n row?: boolean;\n className?: string;\n children?: ReactNode;\n};\n\n/**\n * 헤더 주요 기능 버튼 — 킷 `.btn-navi`. 레이어·전체메뉴를 여는 자리다.\n *\n * 좁은 화면에서 `join`·`my` 를, 1024px 이상에서 `all` 을 킷이 감춘다 —\n * 미디어쿼리를 따로 쓰지 마라. `icon=\"all\"` 이면 `aria-controls=\"mobile-nav\"` 가 자동으로 붙는다.\n */\nexport type HeaderNaviButtonProps = Omit<ComponentPropsWithRef<'button'>, 'children'> & NaviBase;\n\nexport function HeaderNaviButton({\n icon,\n row,\n className,\n children,\n type = 'button',\n 'aria-controls': ariaControls,\n ...rest\n}: HeaderNaviButtonProps) {\n return (\n <button\n type={type}\n className={cx('btn-navi', icon, row && 'navi-row', className)}\n // 킷 샘플: 전체메뉴 버튼은 모바일 전체메뉴를 가리킨다. 직접 준 값이 있으면 그것을 쓴다.\n aria-controls={ariaControls ?? (icon === 'all' ? 'mobile-nav' : undefined)}\n {...rest}\n >\n {children}\n </button>\n );\n}\n\n/** 헤더 주요 기능 링크 — 화면을 옮기는 것(로그인 등)만 링크로 둔다. 레이어는 `HeaderNaviButton`. */\nexport type HeaderNaviLinkProps = Omit<ComponentPropsWithRef<'a'>, 'href' | 'children'> &\n NaviBase & {\n href: string;\n /** 새 창으로 여는 바깥 주소. */\n external?: boolean;\n };\n\nexport function HeaderNaviLink({\n icon,\n row,\n href,\n external,\n className,\n children,\n title,\n ...rest\n}: HeaderNaviLinkProps) {\n const cls = cx('btn-navi', icon, row && 'navi-row', className);\n\n return external ? (\n <a\n className={cls}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title={title ?? NEW_WINDOW_TITLE}\n {...rest}\n >\n {children}\n </a>\n ) : (\n <UiLink className={cls} href={href} title={title} {...rest}>\n {children}\n </UiLink>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* 운영기관 식별자 — KRDS `krds-identifier`.
|
|
4
|
+
*
|
|
5
|
+
* 「이 누리집은 [기관]에서 운영하는 누리집입니다.」 안내. 푸터 안 **가장 마지막 구획**에 둔다.
|
|
6
|
+
* 여기 들어가는 로고는 서비스 로고가 아니라 **운영 주체 기관**의 로고다(서비스 로고는 `f-logo`).
|
|
7
|
+
* 문구 형식과 요소 배치는 규격이 변형을 금지한다 — `children` 은 번역을 넣는 자리다.
|
|
8
|
+
* 푸터 골격을 조립할 때는 `ui/footer` 의 `FooterIdentifier` 를 쓴다.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* <Identifier org="○○기관" logoSrc="/site/logo-mark.svg" />
|
|
12
|
+
* <Identifier org="○○기관" variant="text" dark />
|
|
13
|
+
*
|
|
14
|
+
* 자세히: docs/krds/09-부품-노트.md#운영기관식별자
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 표현 방식. `card` 는 흰 면 + 둥근 상자(기본), `text` 는 한 줄짜리 킷 전용 변형이다.
|
|
18
|
+
*/
|
|
19
|
+
export type IdentifierVariant = 'card' | 'text';
|
|
20
|
+
export type IdentifierProps = Omit<ComponentPropsWithRef<'section'>, 'children'> & {
|
|
21
|
+
/** 운영기관명. 안내 문구와 로고 대체 텍스트에 함께 쓰인다. */
|
|
22
|
+
org: string;
|
|
23
|
+
/** 운영기관 로고 이미지 경로. 없으면 `.logo` 를 아예 그리지 않는다(킷 마크가 찍히는 것을 막는다). */
|
|
24
|
+
logoSrc?: string;
|
|
25
|
+
/** 표현 방식. 기본 `card`. */
|
|
26
|
+
variant?: IdentifierVariant;
|
|
27
|
+
/** 어두운 바탕용. 킷에 클래스가 없어 KRDS 반전 토큰으로 그린다. */
|
|
28
|
+
dark?: boolean;
|
|
29
|
+
/** 안내 문구. 다국어 번역을 넣을 때만 쓰고 형식은 바꾸지 않는다. */
|
|
30
|
+
children?: ReactNode;
|
|
31
|
+
/** 구획 이름(`aria-label`). `<section>` 은 이름이 있어야 region 으로 노출된다. */
|
|
32
|
+
label?: string;
|
|
33
|
+
/** 가이드가 허용하는 두 요소. 기본은 `section`. */
|
|
34
|
+
as?: 'section' | 'article';
|
|
35
|
+
className?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function Identifier({ org, logoSrc, variant, dark, label, as: Tag, className, children, ...rest }: IdentifierProps): import("react").JSX.Element;
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/identifier/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG9D;;;;;;;;;;;;;GAaG;AAEH;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC,GAAG;IACjF,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,4CAA4C;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,UAAU,CAAC,EACzB,GAAG,EACH,OAAO,EACP,OAAgB,EAChB,IAAI,EACJ,KAAkB,EAClB,EAAE,EAAE,GAAe,EACnB,SAAS,EACT,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,eAAe,+BA4CjB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cx } from "../lib/krds.js";
|
|
3
|
+
function Identifier({
|
|
4
|
+
org,
|
|
5
|
+
logoSrc,
|
|
6
|
+
variant = "card",
|
|
7
|
+
dark,
|
|
8
|
+
label = "\uC6B4\uC601\uAE30\uAD00 \uC2DD\uBCC4\uC790",
|
|
9
|
+
as: Tag = "section",
|
|
10
|
+
className,
|
|
11
|
+
children,
|
|
12
|
+
...rest
|
|
13
|
+
}) {
|
|
14
|
+
const text = children ?? `\uC774 \uB204\uB9AC\uC9D1\uC740 ${org}\uC5D0\uC11C \uC6B4\uC601\uD558\uB294 \uB204\uB9AC\uC9D1\uC785\uB2C8\uB2E4.`;
|
|
15
|
+
const logo = logoSrc ? /* @__PURE__ */ jsxs(
|
|
16
|
+
"span",
|
|
17
|
+
{
|
|
18
|
+
className: cx(
|
|
19
|
+
"logo",
|
|
20
|
+
// 킷의 KRDS 마크 배경과 고정 폭을 지운다. 높이는 킷 값을 그대로 쓴다.
|
|
21
|
+
"inline-flex items-center bg-none w-auto",
|
|
22
|
+
// text 변형에는 킷 `.logo` 규칙이 닿지 않아 높이가 없다 — 본문 소자 줄에 맞춘다.
|
|
23
|
+
variant === "text" && "h-5"
|
|
24
|
+
),
|
|
25
|
+
children: [
|
|
26
|
+
/* @__PURE__ */ jsx("img", { src: logoSrc, alt: "", className: "h-full w-auto" }),
|
|
27
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: org })
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
) : null;
|
|
31
|
+
const cls = variant === "text" ? cx(
|
|
32
|
+
"krds-identifier-txt",
|
|
33
|
+
// 킷 규칙이 `#krds-footer .f-btm` 안에서만 걸린다 — 밖에서도 같은 줄로 서게 보충한다.
|
|
34
|
+
// 킷의 `white-space:nowrap` 은 옮기지 않는다(긴 기관명이 좁은 화면에서 넘친다).
|
|
35
|
+
"flex items-center gap-2 text-sm",
|
|
36
|
+
dark && "text-fg-inverse",
|
|
37
|
+
className
|
|
38
|
+
) : cx(
|
|
39
|
+
"krds-identifier",
|
|
40
|
+
// 킷의 흰 면(`--krds-light-color-surface-white`)을 반전 토큰으로 덮는다.
|
|
41
|
+
dark && "bg-surface-inverse text-fg-inverse",
|
|
42
|
+
className
|
|
43
|
+
);
|
|
44
|
+
return (
|
|
45
|
+
// rest 를 뒤에 두어 화면 쪽에서 aria-label 을 덮어쓸 수 있게 한다.
|
|
46
|
+
/* @__PURE__ */ jsxs(Tag, { "aria-label": label, className: cls, ...rest, children: [
|
|
47
|
+
logo,
|
|
48
|
+
variant === "text" ? /* @__PURE__ */ jsx("span", { children: text }) : /* @__PURE__ */ jsx("span", { className: "ban-txt", children: text })
|
|
49
|
+
] })
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
Identifier
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=index.js.map
|