@bigtablet/design-system 3.7.0 → 3.9.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 ADDED
@@ -0,0 +1,53 @@
1
+ # Bigtablet Inc. Open Source License
2
+
3
+ ## Table of Contents / 목차
4
+ - [English Version](#english-version)
5
+ - [한국어 버전](#한국어-버전)
6
+
7
+ ---
8
+
9
+ ## English Version
10
+
11
+ This license is issued by **Bigtablet Inc.** (hereinafter referred to as the "Copyright Holder") and is intended to provide the source code to developers, researchers, and other users (hereinafter referred to as "Users").
12
+ Any use that contradicts the purposes stated below is strictly prohibited.
13
+
14
+ ### Terms and Conditions
15
+
16
+ 1. All copyrights for the source code and files opened within this GitHub organization belong to the Copyright Holder.
17
+ 2. All open-source materials are, by default, permitted for **non-commercial use only**.
18
+ 3. Any User who uses, modifies, processes, redistributes, or conducts research with part or all of the open source must clearly indicate the source by referencing the link to the original GitHub repository.
19
+ 4. Commercial use of the open source without explicit or implicit permission from the Copyright Holder is strictly prohibited. For inquiries regarding commercial use, please contact the email address provided in the profile.
20
+ 5. Users are obligated to report any issues, errors, or security vulnerabilities discovered or encountered while using the open source to the Copyright Holder, and are prohibited from exploiting or disclosing them to external parties.
21
+ 6. If unauthorized commercial use is detected, the Copyright Holder reserves the right to take legal action.
22
+ 7. By cloning, forking, or otherwise copying and using a repository containing this open source, the User is deemed to have fully understood and agreed to all the terms of this license.
23
+ 8. This license shall take effect from **September 9, 2025**, and shall have legal force and effect from that date.
24
+ 9. For any additional inquiries, please contact the email address listed in the profile.
25
+
26
+ ### Disclaimer
27
+
28
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
29
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
+
31
+ ---
32
+
33
+ ## 한국어 버전
34
+
35
+ 본 라이선스는 **Bigtablet Inc.**(이하 “저작권자”)에서 발행하였으며, 개발자, 연구자 등 (이하 “사용자”)에게 소스코드를 제공하기 위한 목적으로 공개합니다.
36
+ 아래에 기재된 목적에 반하는 사용은 엄격히 금지됩니다.
37
+
38
+ ### 조항
39
+
40
+ 1. 본 GitHub 조직에 공개된 모든 소스코드와 파일에 대한 저작권은 저작권자에게 있습니다.
41
+ 2. 모든 오픈소스는 원칙적으로 **비상업적 목적**으로만 이용할 수 있습니다.
42
+ 3. 모든 사용자는 오픈소스의 일부 또는 전체를 사용, 수정, 가공, 재배포, 연구할 경우 반드시 해당 GitHub 저장소 링크를 통해 출처를 명시해야 합니다.
43
+ 4. 저작권자의 명시적 또는 묵시적 허가 없이 오픈소스를 상업적 목적으로 이용하는 것을 금합니다. 상업적 이용 문의는 프로필에 기재된 이메일로 연락하시기 바랍니다.
44
+ 5. 사용자는 오픈소스를 이용하는 중 발견되거나 발생한 문제, 오류, 보안 취약점을 저작권자에게 보고할 의무가 있으며 이를 악용하거나 외부로 공유하는 것을 금합니다.
45
+ 6. 무단으로 상업적 이용이 적발될 경우 저작권자는 법적 조치를 취할 권리를 가집니다.
46
+ 7. 오픈소스가 포함된 저장소를 clone, fork 또는 기타 방법으로 복제하여 이용하는 경우, 사용자는 본 라이선스의 모든 조항을 충분히 숙지하였으며 이에 동의한 것으로 간주됩니다.
47
+ 8. 본 라이선스는 **2025년 9월 9일**부터 발효되며, 해당 시점부터 법적 효력을 가집니다.
48
+ 9. 기타 문의 사항은 프로필에 기재된 이메일로 연락하시기 바랍니다.
49
+
50
+ ### 면책 조항
51
+
52
+ 이 소프트웨어는 **“있는 그대로(As-Is)”** 제공되며, 상품성, 특정 목적에의 적합성, 비침해를 포함하되 이에 국한되지 않는 어떠한 형태의 명시적 또는 묵시적 보증도 하지 않습니다.
53
+ 저작권자 또는 기여자는 계약, 불법행위, 기타 어떠한 법적 근거에 의한 것이든 간에, 본 소프트웨어 또는 이를 사용하거나 다른 방식으로 이용함으로 인해 발생하는 모든 청구, 손해, 기타 법적 책임에 대해 책임을 지지 않습니다.
package/README.md CHANGED
@@ -45,7 +45,7 @@ A complete React + TypeScript design system maintained by Bigtablet for internal
45
45
  ## What's inside
46
46
 
47
47
  - **40+ components** across forms, display, feedback, navigation, overlay, and layout<br />
48
- - **11 token domains** - colors, typography, spacing, motion, radius, elevation, and more - exposed as SCSS variables and CSS custom properties<br />
48
+ - **13 token domains** - colors, typography, spacing, motion, radius, elevation, and more - exposed as SCSS variables and CSS custom properties (plus a SCSS-only `layout` domain)<br />
49
49
  - **Light + dark mode** out of the box. `[data-theme="dark"]` or `prefers-color-scheme`, no theme provider required (but available via `ThemeProvider` for runtime toggling)<br />
50
50
  - **Vanilla JS bundle** for non-React backends - Thymeleaf, JSP, PHP, Django<br />
51
51
  - **Accessibility tested** with axe-core in CI · keyboard nav · ARIA throughout
@@ -58,7 +58,7 @@ A complete React + TypeScript design system maintained by Bigtablet for internal
58
58
  pnpm add @bigtablet/design-system react@^19 react-dom@^19 lucide-react
59
59
  ```
60
60
 
61
- Requires React 19 + lucide-react ≥ 0.552. Compatible with Next.js 13+.
61
+ Requires React 19 + lucide-react ≥ 0.552. Next.js is an optional peer dependency at `>=15`.
62
62
 
63
63
  <details>
64
64
  <summary><b>One-line setup</b> - auto-detect package manager + framework</summary>
@@ -102,12 +102,13 @@ showAlert({ title: "Delete?", showCancel: true, onConfirm: ... });
102
102
  ## Components
103
103
 
104
104
  <table>
105
- <tr><td><b>Forms</b></td><td>Button · IconButton · TextField · Textarea · Checkbox · Radio · Toggle · Dropdown · DatePicker · FileInput · OTPInput</td></tr>
105
+ <tr><td><b>Forms</b></td><td>Button · IconButton · TextField · Textarea · Checkbox · Radio · RadioGroup · Toggle · Dropdown · DatePicker · FileInput · ImageCropper · OtpInput</td></tr>
106
106
  <tr><td><b>Display</b></td><td>Card · MediaCard · Hero · Avatar · Badge · Chip · ListItem · Table · Divider · Icon · Accordion</td></tr>
107
107
  <tr><td><b>Feedback</b></td><td>Alert · Toast · Spinner · TopLoading · LinearProgress · Skeleton · EmptyState · ErrorState</td></tr>
108
108
  <tr><td><b>Navigation</b></td><td>Tabs · Sidebar · BottomNav · NavBar · Breadcrumb · Menu · Pagination</td></tr>
109
- <tr><td><b>Overlay</b></td><td>Modal · Tooltip</td></tr>
109
+ <tr><td><b>Overlay</b></td><td>Modal · Drawer · Tooltip · Popover</td></tr>
110
110
  <tr><td><b>Layout</b></td><td>Container · Section · Stack · Grid</td></tr>
111
+ <tr><td><b>System</b></td><td>ThemeProvider</td></tr>
111
112
  </table>
112
113
 
113
114
  →&nbsp;Full API · [`docs/COMPONENTS.md`](./docs/COMPONENTS.md)
@@ -117,7 +118,7 @@ showAlert({ title: "Delete?", showCancel: true, onConfirm: ... });
117
118
  ## Design tokens
118
119
 
119
120
  ```scss
120
- @use "src/styles/token" as token;
121
+ @use "@bigtablet/design-system/scss/token" as token;
121
122
 
122
123
  .card {
123
124
  background: token.$color_bg_solid;
@@ -129,16 +130,18 @@ showAlert({ title: "Delete?", showCancel: true, onConfirm: ... });
129
130
  ```
130
131
 
131
132
  ```css
133
+ /* from @bigtablet/design-system/style.css */
132
134
  .card {
133
135
  background: var(--bt-color-bg-solid);
134
136
  color: var(--bt-color-text-heading);
135
- padding: var(--bt-spacing-16);
136
- border-radius: var(--bt-radius-md);
137
+ border: 1px solid var(--bt-color-border-default);
137
138
  box-shadow: var(--bt-elevation-level1);
138
139
  }
139
140
  ```
140
141
 
141
- `colors`&nbsp;·&nbsp;`spacing`&nbsp;·&nbsp;`typography`&nbsp;·&nbsp;`radius`&nbsp;·&nbsp;`elevation`&nbsp;·&nbsp;`motion`&nbsp;·&nbsp;`z-index`&nbsp;·&nbsp;`breakpoints`&nbsp;·&nbsp;`border-width`&nbsp;·&nbsp;`opacity`&nbsp;·&nbsp;`a11y`
142
+ > The React entry's `style.css` only emits `--bt-color-*`, `--bt-elevation-*`, `--bt-focus-*`, `--bt-sidebar-*`, and `--bt-bottom-nav-*`. Spacing, radius, and typography are **SCSS-only** on this entry - use `scss/token` for them (`--bt-spacing-*` / `--bt-radius-*` exist only in the [Vanilla bundle](./docs/VANILLA.md)).
143
+
144
+ `colors`&nbsp;·&nbsp;`spacing`&nbsp;·&nbsp;`typography`&nbsp;·&nbsp;`radius`&nbsp;·&nbsp;`elevation`&nbsp;·&nbsp;`motion`&nbsp;·&nbsp;`z-index`&nbsp;·&nbsp;`breakpoints`&nbsp;·&nbsp;`border-width`&nbsp;·&nbsp;`opacity`&nbsp;·&nbsp;`skeleton`&nbsp;·&nbsp;`icon`&nbsp;·&nbsp;`a11y`&nbsp;·&nbsp;`layout`<sup>SCSS only</sup>
142
145
 
143
146
  <br />
144
147
 
@@ -150,7 +153,7 @@ For server-rendered apps (Thymeleaf, JSP, PHP, Django):
150
153
  <link rel="stylesheet" href="https://unpkg.com/@bigtablet/design-system/dist/vanilla/bigtablet.min.css">
151
154
  <script src="https://unpkg.com/@bigtablet/design-system/dist/vanilla/bigtablet.min.js"></script>
152
155
 
153
- <button class="bt-button bt-button--md bt-button--primary">Primary</button>
156
+ <button class="bt-button bt-button--md bt-button--filled">Filled</button>
154
157
  ```
155
158
 
156
159
  →&nbsp;Full guide · [`docs/VANILLA.md`](./docs/VANILLA.md)
package/dist/index.css CHANGED
@@ -743,6 +743,11 @@
743
743
  align-items: center;
744
744
  color: var(--bt-color-text-caption);
745
745
  }
746
+ @media (prefers-reduced-motion: reduce) {
747
+ .breadcrumb_link {
748
+ transition: none;
749
+ }
750
+ }
746
751
 
747
752
  /* src/ui/navigation/menu/style.scss */
748
753
  @keyframes skeleton_loading {
@@ -1559,38 +1564,18 @@
1559
1564
  display: inline-flex;
1560
1565
  }
1561
1566
  .popover_position {
1562
- position: absolute;
1563
1567
  z-index: 1000;
1564
1568
  width: max-content;
1565
1569
  }
1566
- .popover_position.popover_placement_top {
1567
- bottom: calc(100% + 8px);
1568
- left: 50%;
1569
- transform: translateX(-50%);
1570
- }
1571
- .popover_position.popover_placement_bottom {
1572
- top: calc(100% + 8px);
1573
- left: 50%;
1574
- transform: translateX(-50%);
1575
- }
1576
- .popover_position.popover_placement_left {
1577
- right: calc(100% + 8px);
1578
- top: 50%;
1579
- transform: translateY(-50%);
1580
- }
1581
- .popover_position.popover_placement_right {
1582
- left: calc(100% + 8px);
1583
- top: 50%;
1584
- transform: translateY(-50%);
1585
- }
1586
1570
  .popover {
1587
1571
  background: var(--bt-color-bg-solid);
1588
1572
  border: 1px solid var(--bt-color-border-default);
1589
1573
  border-radius: 12px;
1590
1574
  box-shadow: var(--bt-elevation-level2);
1591
1575
  padding: 16px;
1592
- min-width: 200px;
1593
- max-width: 320px;
1576
+ box-sizing: border-box;
1577
+ min-width: min(200px, 100%);
1578
+ max-width: min(320px, 100%);
1594
1579
  color: var(--bt-color-text-body);
1595
1580
  font-size: 14px;
1596
1581
  font-weight: 400;
@@ -1632,31 +1617,10 @@
1632
1617
  vertical-align: middle;
1633
1618
  }
1634
1619
  .tooltip_position {
1635
- position: absolute;
1636
1620
  z-index: 1000;
1637
1621
  display: block;
1638
1622
  width: max-content;
1639
1623
  }
1640
- .tooltip_position.tooltip_placement_top {
1641
- bottom: calc(100% + 6px);
1642
- left: 50%;
1643
- transform: translateX(-50%);
1644
- }
1645
- .tooltip_position.tooltip_placement_bottom {
1646
- top: calc(100% + 6px);
1647
- left: 50%;
1648
- transform: translateX(-50%);
1649
- }
1650
- .tooltip_position.tooltip_placement_left {
1651
- right: calc(100% + 6px);
1652
- top: 50%;
1653
- transform: translateY(-50%);
1654
- }
1655
- .tooltip_position.tooltip_placement_right {
1656
- left: calc(100% + 6px);
1657
- top: 50%;
1658
- transform: translateY(-50%);
1659
- }
1660
1624
  .tooltip {
1661
1625
  display: block;
1662
1626
  background: var(--bt-color-accent-strong);
@@ -2038,6 +2002,14 @@
2038
2002
  width: 18px;
2039
2003
  height: 18px;
2040
2004
  }
2005
+ @media (prefers-reduced-motion: reduce) {
2006
+ .chip,
2007
+ .chip::before,
2008
+ .chip_content::before,
2009
+ .chip_icon {
2010
+ transition: none;
2011
+ }
2012
+ }
2041
2013
 
2042
2014
  /* src/ui/display/divider/style.scss */
2043
2015
  @keyframes skeleton_loading {
@@ -2611,6 +2583,11 @@
2611
2583
  opacity: 0.38;
2612
2584
  pointer-events: none;
2613
2585
  }
2586
+ @media (prefers-reduced-motion: reduce) {
2587
+ .list_item_interactive .list_item_state_layer::before {
2588
+ transition: none;
2589
+ }
2590
+ }
2614
2591
 
2615
2592
  /* src/ui/display/media-card/style.scss */
2616
2593
  @keyframes skeleton_loading {
@@ -3588,7 +3565,7 @@
3588
3565
  left: 0;
3589
3566
  height: 3px;
3590
3567
  border-radius: 0 0 0 12px;
3591
- animation: toast_progress var(--toast-duration, 3000ms) linear forwards;
3568
+ animation: toast_progress var(--toast-duration, 3s) linear forwards;
3592
3569
  }
3593
3570
  .toast_progress_success {
3594
3571
  background: var(--bt-color-status-success);
@@ -3737,6 +3714,20 @@
3737
3714
  background-color: var(--bt-color-bg-solid-dim);
3738
3715
  border-color: var(--bt-color-bg-disabled);
3739
3716
  }
3717
+ .dropdown_variant_filled .dropdown_fieldset {
3718
+ border-color: transparent;
3719
+ background-color: var(--bt-color-bg-solid-dim);
3720
+ }
3721
+ .dropdown_variant_filled .dropdown_fieldset:hover:not(.is_open):not(.is_disabled) {
3722
+ border-color: var(--bt-color-border-hover);
3723
+ }
3724
+ .dropdown_variant_filled .dropdown_fieldset.is_open {
3725
+ border-color: var(--bt-color-border-focus);
3726
+ background-color: var(--bt-color-bg-solid);
3727
+ }
3728
+ .dropdown_variant_filled .dropdown_fieldset.is_disabled {
3729
+ border-color: transparent;
3730
+ }
3740
3731
  .dropdown_label {
3741
3732
  display: block;
3742
3733
  font-size: 13px;
@@ -3988,6 +3979,9 @@
3988
3979
  .dropdown_search_input {
3989
3980
  transition: none;
3990
3981
  }
3982
+ .dropdown_fieldset {
3983
+ transition: none;
3984
+ }
3991
3985
  }
3992
3986
 
3993
3987
  /* src/ui/forms/date-picker/style.scss */
@@ -4423,6 +4417,11 @@
4423
4417
  .otp_input_supporting_error {
4424
4418
  color: var(--bt-color-status-error-on-surface);
4425
4419
  }
4420
+ @media (prefers-reduced-motion: reduce) {
4421
+ .otp_input_box {
4422
+ transition: none;
4423
+ }
4424
+ }
4426
4425
 
4427
4426
  /* src/ui/forms/radio-group/style.scss */
4428
4427
  @keyframes skeleton_loading {
@@ -4906,6 +4905,20 @@
4906
4905
  color: var(--bt-color-text-caption);
4907
4906
  transition: color 0.2s ease-in-out;
4908
4907
  }
4908
+ .text_field_variant_filled .text_field_container {
4909
+ border-color: transparent;
4910
+ background-color: var(--bt-color-bg-solid-dim);
4911
+ }
4912
+ .text_field_variant_filled .text_field_container:hover {
4913
+ border-color: var(--bt-color-border-hover);
4914
+ }
4915
+ .text_field_variant_filled .text_field_container:focus-within {
4916
+ border-color: var(--bt-color-border-focus);
4917
+ background-color: var(--bt-color-bg-solid);
4918
+ }
4919
+ .text_field_disabled.text_field_variant_filled .text_field_container {
4920
+ border-color: transparent;
4921
+ }
4909
4922
  .text_field_error .text_field_container {
4910
4923
  border-color: var(--bt-color-status-error);
4911
4924
  }
@@ -4919,6 +4932,19 @@
4919
4932
  .text_field_error .text_field_helper {
4920
4933
  color: var(--bt-color-status-error-on-surface);
4921
4934
  }
4935
+ .text_field_success .text_field_container {
4936
+ border-color: var(--bt-color-status-success);
4937
+ }
4938
+ .text_field_success .text_field_container:hover,
4939
+ .text_field_success .text_field_container:focus-within {
4940
+ border-color: var(--bt-color-status-success);
4941
+ }
4942
+ .text_field_success .text_field_label {
4943
+ color: var(--bt-color-status-success-on-surface);
4944
+ }
4945
+ .text_field_success .text_field_helper {
4946
+ color: var(--bt-color-status-success-on-surface);
4947
+ }
4922
4948
  .text_field_disabled .text_field_container {
4923
4949
  border-color: var(--bt-color-bg-disabled);
4924
4950
  background-color: var(--bt-color-bg-solid-dim);
@@ -4936,6 +4962,14 @@
4936
4962
  .text_field_disabled .text_field_helper {
4937
4963
  opacity: 0.38;
4938
4964
  }
4965
+ @media (prefers-reduced-motion: reduce) {
4966
+ .text_field_label,
4967
+ .text_field_container,
4968
+ .text_field_clear,
4969
+ .text_field_helper {
4970
+ transition: none;
4971
+ }
4972
+ }
4939
4973
 
4940
4974
  /* src/ui/forms/toggle/style.scss */
4941
4975
  @keyframes skeleton_loading {
@@ -5274,6 +5308,12 @@
5274
5308
  letter-spacing: 0px;
5275
5309
  color: var(--bt-color-text-caption);
5276
5310
  }
5311
+ @media (prefers-reduced-motion: reduce) {
5312
+ .pagination_item,
5313
+ .pagination_page_button {
5314
+ transition: none;
5315
+ }
5316
+ }
5277
5317
 
5278
5318
  /* src/ui/overlay/drawer/style.scss */
5279
5319
  @keyframes skeleton_loading {
@@ -5500,6 +5540,11 @@
5500
5540
  .modal_footer_start {
5501
5541
  justify-content: flex-start;
5502
5542
  }
5543
+ @media (prefers-reduced-motion: reduce) {
5544
+ .modal_close {
5545
+ transition: none;
5546
+ }
5547
+ }
5503
5548
 
5504
5549
  /* src/ui/layout/container/style.scss */
5505
5550
  @keyframes skeleton_loading {
package/dist/index.d.ts CHANGED
@@ -368,7 +368,7 @@ interface MenuProps {
368
368
  * @example
369
369
  * ```tsx
370
370
  * <Menu
371
- * trigger={<IconButton icon={<MoreIcon />} />}
371
+ * trigger={<IconButton icon={<MoreIcon />} aria-label="더보기" />}
372
372
  * items={[
373
373
  * { key: "edit", label: "편집", onSelect: handleEdit },
374
374
  * { key: "del", label: "삭제", onSelect: handleDel, destructive: true },
@@ -395,6 +395,15 @@ interface NavBarLocaleConfig {
395
395
  onChange?: (next: string) => void;
396
396
  /** 표시 라벨 - 기본은 옵션의 label, 미지정 시 short code 표시 */
397
397
  hideLabel?: boolean;
398
+ /**
399
+ * locale 트리거 버튼의 접근성 이름 (기본값: 현재 옵션의 label, 없으면 `current` 대문자).
400
+ * `hideLabel` 이 true 면 버튼 안이 아이콘뿐이라 이 값이 유일한 접근성 이름이 된다.
401
+ *
402
+ * ⚠️ `hideLabel` 이 false(기본값)일 때는 이 값이 화면에 보이는 라벨을 덮어쓰므로,
403
+ * 보이는 라벨 텍스트를 **포함**하는 문자열이어야 한다. 그렇지 않으면 음성 제어 사용자가
404
+ * 보이는 대로 말해도 버튼이 잡히지 않는다 (WCAG 2.1 SC 2.5.3 Label in Name 위반).
405
+ */
406
+ ariaLabel?: string;
398
407
  }
399
408
  interface NavBarProps extends React$1.HTMLAttributes<HTMLElement> {
400
409
  /** 왼쪽 brand/로고 영역 */
@@ -560,7 +569,10 @@ interface PopoverProps {
560
569
  trigger: React$1.ReactElement;
561
570
  /** 팝오버 내부 콘텐츠 - 임의 ReactNode (폼/설명/액션 조합) */
562
571
  content: React$1.ReactNode;
563
- /** 위치 (기본값: "bottom") */
572
+ /**
573
+ * 선호 위치 (기본값: "bottom"). 뷰포트를 벗어나면 반대편으로 flip 되고 교차축으로 shift 되므로
574
+ * 실제 위치는 계산 결과를 따른다(Radix `side` + `collisionPadding` 계약). body 로 포탈된다.
575
+ */
564
576
  placement?: PopoverPlacement;
565
577
  /** 제어 모드 - 열림 상태 */
566
578
  open?: boolean;
@@ -568,7 +580,7 @@ interface PopoverProps {
568
580
  defaultOpen?: boolean;
569
581
  /** 열림 상태 변경 콜백 */
570
582
  onOpenChange?: (open: boolean) => void;
571
- /** dialog 접근성 라벨 - content 에 제목이 없을 때 권장 */
583
+ /** 팝오버 접근성 레이블(기본값: "Dialog") - content 에 제목이 없을 때 권장 */
572
584
  "aria-label"?: string;
573
585
  /** dialog 의 접근성 라벨 요소 id */
574
586
  "aria-labelledby"?: string;
@@ -603,7 +615,10 @@ type TooltipPlacement = "top" | "bottom" | "left" | "right";
603
615
  interface TooltipProps {
604
616
  /** 툴팁 콘텐츠 */
605
617
  content: React$1.ReactNode;
606
- /** 위치 (기본값: "top") */
618
+ /**
619
+ * 선호 위치 (기본값: "top"). 뷰포트를 벗어나면 반대편으로 flip 되고 교차축으로 shift 되므로
620
+ * 실제 위치는 계산 결과를 따른다(Radix `side` + `collisionPadding` 계약). body 로 포탈된다.
621
+ */
607
622
  placement?: TooltipPlacement;
608
623
  /** hover 후 지연 시간 ms (기본 200) */
609
624
  delay?: number;
@@ -617,7 +632,7 @@ interface TooltipProps {
617
632
  * @example
618
633
  * ```tsx
619
634
  * <Tooltip content="저장하기">
620
- * <IconButton icon={<SaveIcon />} />
635
+ * <IconButton icon={<SaveIcon />} aria-label="저장" />
621
636
  * </Tooltip>
622
637
  * ```
623
638
  */
@@ -1488,6 +1503,7 @@ interface SpinnerProps {
1488
1503
  */
1489
1504
  declare const Spinner: ({ size, ariaLabel }: SpinnerProps) => React$1.JSX.Element;
1490
1505
 
1506
+ type ToastVariant = "success" | "error" | "warning" | "info" | "default";
1491
1507
  interface ToastProviderProps {
1492
1508
  /** 앱 루트에서 감싸는 자식 요소 */
1493
1509
  children: React$1.ReactNode;
@@ -1621,6 +1637,12 @@ type DatePickerProps = DatePickerBaseProps & DatePickerCallbacks;
1621
1637
  declare const DatePicker: ({ label, value, onValueChange, onChange, mode, startYear, endYear: endYearProp, minDate, selectableRange, disabled, fullWidth, width, yearLabel, monthLabel, dayLabel, minDateSrFormat, selectableRangeUntilTodaySrText, }: DatePickerProps) => React$1.JSX.Element;
1622
1638
 
1623
1639
  type DropdownSize = "sm" | "md" | "lg";
1640
+ /**
1641
+ * 컨트롤 시각 변형. TextField 의 `variant` 와 같은 어휘를 쓴다.
1642
+ * - `outline`: 테두리로 컨트롤을 구분 (기본).
1643
+ * - `filled`: 테두리 대신 채워진 배경으로 구분, 열리면 배경이 solid 로 돌아오며 테두리가 드러남.
1644
+ */
1645
+ type DropdownVariant = "outline" | "filled";
1624
1646
  interface DropdownOption {
1625
1647
  value: string;
1626
1648
  label: string;
@@ -1654,10 +1676,8 @@ interface DropdownCommonProps {
1654
1676
  fullWidth?: boolean;
1655
1677
  /** 루트 요소에 추가할 className */
1656
1678
  className?: string;
1657
- /**
1658
- * @deprecated variant 더 이상 지원되지 않습니다. Dropdown은 outline 스타일만 사용합니다.
1659
- */
1660
- variant?: "outline" | "filled" | "ghost";
1679
+ /** 컨트롤 시각 변형 (기본값: "outline") */
1680
+ variant?: DropdownVariant;
1661
1681
  /**
1662
1682
  * @deprecated textAlign은 더 이상 지원되지 않습니다.
1663
1683
  */
@@ -1884,6 +1904,23 @@ declare const Radio: {
1884
1904
 
1885
1905
  type RadioGroupSize = "sm" | "md" | "lg";
1886
1906
  type RadioGroupOrientation = "vertical" | "horizontal";
1907
+ interface RadioGroupContextValue {
1908
+ /** 그룹 라디오들이 공유하는 name (브라우저 그룹핑) */
1909
+ name: string;
1910
+ /** 현재 선택된 value (없으면 미선택) */
1911
+ value: string | undefined;
1912
+ /** 라디오 선택 시 호출 */
1913
+ onChange: (value: string) => void;
1914
+ /** 그룹 사이즈 — 개별 Radio 의 size 미지정 시 적용 */
1915
+ size: RadioGroupSize;
1916
+ /** 그룹 전체 비활성화 */
1917
+ disabled: boolean;
1918
+ }
1919
+ /**
1920
+ * `Radio` 가 상위 `RadioGroup` 의 컨텍스트를 optional 하게 소비하기 위한 hook.
1921
+ * `RadioGroup` 밖에서 쓰이면 `null` 을 반환 — 이 경우 Radio 는 standalone 으로 동작.
1922
+ */
1923
+ declare function useRadioGroupContext(): RadioGroupContextValue | null;
1887
1924
  interface RadioGroupProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "onChange"> {
1888
1925
  /** 제어형: 선택된 value */
1889
1926
  value?: string;
@@ -1930,6 +1967,12 @@ declare const RadioGroup: {
1930
1967
  };
1931
1968
 
1932
1969
  type TextFieldSize = "sm" | "md" | "lg";
1970
+ /**
1971
+ * 입력 필드 시각 변형.
1972
+ * - `outline`: 테두리로 입력 영역을 구분 (기본).
1973
+ * - `filled`: 테두리 대신 채워진 배경으로 구분, 포커스 시 배경이 solid 로 돌아오며 테두리가 드러남.
1974
+ */
1975
+ type TextFieldVariant = "outline" | "filled";
1933
1976
  /**
1934
1977
  * IME 조합(한글/일본어/중국어) 중 외부 콜백 처리 전략.
1935
1978
  * - `delayed`: 조합 완료 후에만 `onChangeAction` 호출 (기본 - 폼 제출/검증용).
@@ -1939,14 +1982,18 @@ type ImeStrategy = "delayed" | "immediate";
1939
1982
  interface TextFieldProps extends Omit<React$1.InputHTMLAttributes<HTMLInputElement>, "size" | "onChange" | "value" | "defaultValue"> {
1940
1983
  /** 입력 필드 크기 (기본값: "md") */
1941
1984
  size?: TextFieldSize;
1985
+ /** 입력 필드 시각 변형 (기본값: "outline") */
1986
+ variant?: TextFieldVariant;
1942
1987
  /** 입력 필드 위에 표시할 라벨 텍스트 */
1943
1988
  label?: string;
1944
1989
  /** 라벨 표시 여부 (기본값: true) */
1945
1990
  showLabel?: boolean;
1946
1991
  /** 입력 필드 아래에 표시할 도움말 텍스트 */
1947
1992
  supportingText?: string;
1948
- /** 에러 상태 여부 */
1993
+ /** 에러 상태 여부. `success` 와 동시에 지정되면 `error` 가 우선한다. */
1949
1994
  error?: boolean;
1995
+ /** 성공(검증 통과) 상태 여부. `error` 가 true 면 무시된다. */
1996
+ success?: boolean;
1950
1997
  /** 입력 필드 왼쪽에 표시할 아이콘 */
1951
1998
  leadingIcon?: React$1.ReactNode;
1952
1999
  /** 입력 필드 오른쪽에 표시할 아이콘 */
@@ -1981,7 +2028,7 @@ interface TextFieldProps extends Omit<React$1.InputHTMLAttributes<HTMLInputEleme
1981
2028
  * @returns 렌더링된 텍스트 필드 UI
1982
2029
  */
1983
2030
  declare const TextField: {
1984
- ({ id, label, showLabel, supportingText, error, leadingIcon, trailingIcon, clearable, fullWidth, size, className, onValueChange, onChangeAction, imeStrategy, value, defaultValue, transformValue, ref, ...props }: TextFieldProps): React$1.JSX.Element;
2031
+ ({ id, label, showLabel, supportingText, error, success, leadingIcon, trailingIcon, clearable, fullWidth, size, variant, className, onValueChange, onChangeAction, imeStrategy, value, defaultValue, transformValue, ref, ...props }: TextFieldProps): React$1.JSX.Element;
1985
2032
  displayName: string;
1986
2033
  };
1987
2034
 
@@ -2136,7 +2183,8 @@ declare const Button: (props: ButtonProps) => React$1.JSX.Element;
2136
2183
 
2137
2184
  type IconButtonVariant = "standard" | "filled" | "tonal" | "outlined";
2138
2185
  type IconButtonSize = "sm" | "md";
2139
- interface IconButtonProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement> {
2186
+ /** 접근성 이름을 제외한 IconButton 공통 props */
2187
+ interface IconButtonBaseProps extends Omit<React$1.ButtonHTMLAttributes<HTMLButtonElement>, "aria-label" | "aria-labelledby"> {
2140
2188
  /** 아이콘 버튼 스타일 변형 (기본값: "standard") */
2141
2189
  variant?: IconButtonVariant;
2142
2190
  /** 아이콘 버튼 크기 (기본값: "md") */
@@ -2146,9 +2194,40 @@ interface IconButtonProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement
2146
2194
  /** 루트 button 요소 ref (React 19 ref-as-prop) */
2147
2195
  ref?: React$1.Ref<HTMLButtonElement>;
2148
2196
  }
2197
+ /** `aria-label` 로 접근성 이름을 직접 지정 */
2198
+ interface IconButtonWithAriaLabel extends IconButtonBaseProps {
2199
+ /** 아이콘 버튼의 접근성 이름 (필수) */
2200
+ "aria-label": string;
2201
+ /** 접근성 이름을 제공하는 요소 id (선택) */
2202
+ "aria-labelledby"?: string;
2203
+ }
2204
+ /** `aria-labelledby` 로 외부 요소를 참조해 접근성 이름을 지정 */
2205
+ interface IconButtonWithAriaLabelledBy extends IconButtonBaseProps {
2206
+ /** 아이콘 버튼의 접근성 이름 (선택) */
2207
+ "aria-label"?: string;
2208
+ /** 접근성 이름을 제공하는 요소 id (필수) */
2209
+ "aria-labelledby": string;
2210
+ }
2211
+ /**
2212
+ * IconButton props - 접근성 이름을 타입 레벨에서 강제하는 union.
2213
+ * `icon` 은 항상 `aria-hidden` 으로 감싸지므로 `aria-label` 또는 `aria-labelledby` 중
2214
+ * 최소 하나를 반드시 지정해야 한다 (WCAG 2.1 SC 4.1.2 Name, Role, Value).
2215
+ *
2216
+ * @remarks **Breaking change (타입 레벨)** - v3.7.0 이하에서는 두 속성 모두 optional 이었다.
2217
+ * 접근성 이름 없이 `<IconButton icon={<X />} />` 로 사용하던 코드는 이제 **타입 에러**가 난다.
2218
+ * 런타임 렌더링은 바뀌지 않았으므로 `aria-label`(또는 `aria-labelledby`)만 추가하면 된다.
2219
+ * ```tsx
2220
+ * // before (타입 에러 - 접근성 이름 없음)
2221
+ * <IconButton icon={<X />} />
2222
+ * // after
2223
+ * <IconButton icon={<X />} aria-label="닫기" />
2224
+ * ```
2225
+ */
2226
+ type IconButtonProps = IconButtonWithAriaLabel | IconButtonWithAriaLabelledBy;
2149
2227
  /**
2150
2228
  * 아이콘만 표시하는 버튼을 렌더링한다.
2151
2229
  * Figma DS 기준 4가지 variant(standard/filled/tonal/outlined)와 2가지 size(sm/md)를 지원한다.
2230
+ * 아이콘은 `aria-hidden` 이므로 `aria-label` 또는 `aria-labelledby` 가 타입 레벨에서 필수다.
2152
2231
  * @param props 아이콘 버튼 속성
2153
2232
  * @returns 렌더링된 아이콘 버튼 요소
2154
2233
  */
@@ -2444,4 +2523,4 @@ interface StackProps extends React$1.HTMLAttributes<HTMLDivElement> {
2444
2523
  */
2445
2524
  declare const Stack: ({ direction, gap, align, justify, wrap, as: Tag, ref, className, children, style, ...props }: StackProps) => React$1.JSX.Element;
2446
2525
 
2447
- export { Accordion, type AccordionItem, type AccordionProps, AlertProvider, Avatar, type AvatarProps, type AvatarShape, type AvatarSize, Badge, type BadgeProps, type BadgeShape, type BadgeSize, type BadgeVariant, BottomNav, BottomNavItem, type BottomNavItemProps, type BottomNavProps, BottomNavSpacer, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Card, type CardFooterAlign, type CardProps, type CardVariant, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipSize, type ChipTone, type ChipType, Container, type ContainerProps, type ContainerSize, type CropImageSize, type CropOffset, type CropRect, DatePicker, type DatePickerProps, Divider, type DividerProps, Drawer, type DrawerPlacement, type DrawerProps, Dropdown, type DropdownOption, type DropdownProps, type DropdownSize, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, type ErrorStateVariant, FileInput, type FileInputProps, Grid, type GridCols, type GridGap, type GridProps, Hero, type HeroAction, type HeroAlign, type HeroHeight, type HeroOverlay, type HeroProps, Icon, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, type IconProps, ImageCropper, type ImageCropperHandle, type ImageCropperProps, type ImeStrategy, LinearProgress, type LinearProgressProps, ListItem, type ListItemProps, MediaCard, type MediaCardImage, type MediaCardImagePosition, type MediaCardProps, type MediaCardShadow, Menu, type MenuItem, type MenuProps, Modal, type ModalProps, NavBar, type NavBarLayout, type NavBarLocaleConfig, type NavBarLocaleOption, type NavBarProps, type NavBarVariant, NavLink, type NavLinkProps, OtpInput, type OtpInputProps, Pagination, type PaginationProps, Popover, type PopoverPlacement, type PopoverProps, Radio, RadioGroup, type RadioGroupOrientation, type RadioGroupProps, type RadioGroupSize, type RadioProps, type ResolvedTheme, Section, type SectionBg, type SectionProps, type SectionSpacing, Sidebar, SidebarItem, type SidebarItemProps, type SidebarMode, type SidebarProps, SidebarSection, type SidebarSectionProps, Skeleton, type SkeletonProps, type SkeletonVariant, Spinner, type SpinnerProps, Stack, type StackAlign, type StackDirection, type StackGap, type StackJustify, type StackProps, type StackWrap, Tab, TabList, type TabListProps, TabPanel, type TabPanelProps, type TabProps, Table, type TableColumn, type TableProps, type TableSize, type TableSort, type TableSortDirection, Tabs, type TabsProps, type TabsSize, type TabsVariant, TextField, type TextFieldProps, type TextFieldSize, Textarea, type TextareaProps, type TextareaResize, type TextareaSize, type ThemeMode, ThemeProvider, type ThemeProviderProps, ToastProvider, Toggle, type ToggleProps, Tooltip, type TooltipPlacement, type TooltipProps, TopLoading, type TopLoadingProps, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, cn, colors, elevation, iconSize, motion, opacity, radius, skeleton, spacing, typography, useAlert, useFocusTrap, useReducedMotion, useSpringHover, useSpringPresence, useTheme, useToast, zIndex };
2526
+ export { Accordion, type AccordionItem, type AccordionProps, type AlertActionsAlign, type AlertOptions, AlertProvider, type AlertVariant, Avatar, type AvatarProps, type AvatarShape, type AvatarSize, Badge, type BadgeAppearance, type BadgeProps, type BadgeShape, type BadgeSize, type BadgeVariant, BottomNav, BottomNavItem, type BottomNavItemProps, type BottomNavProps, BottomNavSpacer, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonAsAnchor, type ButtonAsButton, type ButtonProps, type ButtonSize, type ButtonVariant, Card, type CardFooterAlign, type CardProps, type CardVariant, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipSize, type ChipTone, type ChipType, Container, type ContainerProps, type ContainerSize, type CropImageSize, type CropOffset, type CropRect, DatePicker, type DatePickerProps, Divider, type DividerProps, Drawer, type DrawerPlacement, type DrawerProps, Dropdown, type DropdownMultipleProps, type DropdownOption, type DropdownProps, type DropdownSingleProps, type DropdownSize, type DropdownVariant, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, type ErrorStateVariant, FileInput, type FileInputProps, type FileInputVariant, Grid, type GridCols, type GridGap, type GridProps, Hero, type HeroAction, type HeroAlign, type HeroHeight, type HeroOverlay, type HeroProps, Icon, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, type IconProps, ImageCropper, type ImageCropperHandle, type ImageCropperProps, type ImeStrategy, LinearProgress, type LinearProgressProps, ListItem, type ListItemProps, MediaCard, type MediaCardImage, type MediaCardImagePosition, type MediaCardProps, type MediaCardShadow, Menu, type MenuItem, type MenuProps, Modal, type ModalFooterAlign, type ModalProps, NavBar, type NavBarLayout, type NavBarLocaleConfig, type NavBarLocaleOption, type NavBarProps, type NavBarVariant, NavLink, type NavLinkProps, OtpInput, type OtpInputProps, Pagination, type PaginationProps, Popover, type PopoverPlacement, type PopoverProps, Radio, RadioGroup, type RadioGroupContextValue, type RadioGroupOrientation, type RadioGroupProps, type RadioGroupSize, type RadioProps, type ResolvedTheme, Section, type SectionBg, type SectionProps, type SectionSpacing, Sidebar, SidebarItem, type SidebarItemProps, type SidebarMode, type SidebarProps, SidebarSection, type SidebarSectionProps, Skeleton, type SkeletonProps, type SkeletonVariant, Spinner, type SpinnerProps, Stack, type StackAlign, type StackDirection, type StackGap, type StackJustify, type StackProps, type StackWrap, Tab, TabList, type TabListProps, TabPanel, type TabPanelProps, type TabProps, Table, type TableColumn, type TableProps, type TableSize, type TableSort, type TableSortDirection, Tabs, type TabsProps, type TabsSize, type TabsVariant, TextField, type TextFieldProps, type TextFieldSize, type TextFieldVariant, Textarea, type TextareaProps, type TextareaResize, type TextareaSize, type ThemeMode, ThemeProvider, type ThemeProviderProps, ToastProvider, type ToastProviderProps, type ToastVariant, Toggle, type ToggleProps, Tooltip, type TooltipPlacement, type TooltipProps, TopLoading, type TopLoadingProps, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, cn, colors, elevation, iconSize, motion, opacity, radius, skeleton, spacing, typography, useAlert, useFocusTrap, useRadioGroupContext, useReducedMotion, useSpringHover, useSpringPresence, useTheme, useToast, zIndex };