@uniai-fe/uds-primitives 0.3.18 → 0.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/styles.css +57 -27
- package/package.json +1 -1
- package/src/components/badge/markup/Badge.tsx +3 -5
- package/src/components/badge/styles/index.scss +2 -1
- package/src/components/button/index.tsx +7 -1
- package/src/components/button/markup/Base.tsx +5 -10
- package/src/components/button/markup/Label.tsx +23 -0
- package/src/components/button/markup/index.ts +1 -0
- package/src/components/button/types/index.ts +1 -0
- package/src/components/button/types/label.ts +9 -0
- package/src/components/checkbox/markup/Checkbox.tsx +9 -4
- package/src/components/checkbox/styles/index.scss +6 -4
- package/src/components/chip/index.tsx +1 -2
- package/src/components/chip/markup/Chip.tsx +36 -24
- package/src/components/chip/markup/DefaultStyle.tsx +34 -19
- package/src/components/chip/markup/InputStyle.tsx +17 -7
- package/src/components/chip/markup/Label.tsx +15 -0
- package/src/components/chip/markup/ListRoot.tsx +88 -0
- package/src/components/chip/markup/RemoveButton.tsx +4 -1
- package/src/components/chip/markup/index.tsx +13 -1
- package/src/components/chip/styles/chip.scss +43 -15
- package/src/components/chip/types/options.ts +22 -14
- package/src/components/chip/types/props-internal.ts +9 -5
- package/src/components/chip/types/props.ts +127 -46
- package/src/components/chip/utils/index.ts +1 -1
- package/src/components/form/markup/form-field/Header.tsx +3 -1
- package/src/components/input/markup/file/UploadedChip.tsx +5 -5
- package/src/components/input/types/file.ts +1 -1
- package/src/components/radio/markup/Radio.tsx +9 -4
- package/src/components/radio/styles/index.scss +6 -4
- package/src/components/segmented-control/markup/Label.tsx +22 -0
- package/src/components/segmented-control/markup/List.tsx +2 -3
- package/src/components/segmented-control/markup/index.ts +1 -0
- package/src/components/segmented-control/styles/index.scss +4 -4
- package/src/components/segmented-control/types/index.ts +9 -0
- package/src/components/select/markup/foundation/Base.tsx +3 -8
- package/src/components/select/markup/foundation/Selected.tsx +3 -2
- package/src/components/slot/index.tsx +2 -6
- package/src/components/slot/markup/Text.tsx +34 -0
- package/src/components/slot/markup/index.tsx +7 -0
- package/src/components/slot/types/index.ts +2 -0
- package/src/components/slot/types/text.ts +24 -0
- package/src/components/table/markup/foundation/Cell.tsx +4 -12
- package/src/components/table/markup/foundation/Td.tsx +4 -7
- package/src/components/table/markup/foundation/Text.tsx +16 -0
- package/src/components/table/markup/foundation/Th.tsx +4 -7
- package/src/components/table/markup/foundation/index.tsx +2 -0
- package/src/components/table/types/foundation.ts +9 -0
- package/src/components/tooltip/markup/Message.tsx +3 -1
- package/src/components/tooltip/markup/Text.tsx +21 -0
- package/src/components/tooltip/markup/index.tsx +3 -0
- package/src/components/tooltip/types/index.ts +1 -0
- package/src/components/tooltip/types/text.ts +9 -0
- package/src/index.scss +0 -1
- package/src/index.tsx +0 -1
- package/src/components/chip/utils/class-name.ts +0 -36
- package/src/components/label/hooks/index.ts +0 -4
- package/src/components/label/img/.gitkeep +0 -0
- package/src/components/label/index.scss +0 -1
- package/src/components/label/index.tsx +0 -4
- package/src/components/label/markup/index.tsx +0 -4
- package/src/components/label/styles/index.scss +0 -0
- package/src/components/label/types/index.ts +0 -4
- package/src/components/label/utils/index.ts +0 -4
- /package/src/components/slot/markup/{Component.tsx → Base.tsx} +0 -0
package/dist/styles.css
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
--theme-badge-radius: var(--theme-radius-medium-1, 6px);
|
|
8
8
|
--theme-badge-font-family: var(--font-caption-medium-family, inherit);
|
|
9
9
|
--theme-badge-font-size: var(--font-caption-medium-size, 11px);
|
|
10
|
-
--theme-badge-font-weight:
|
|
10
|
+
--theme-badge-font-weight: 400;
|
|
11
11
|
--theme-badge-line-height: var(--font-caption-medium-line-height, 1.5);
|
|
12
12
|
--theme-badge-letter-spacing: var(--font-caption-medium-letter-spacing, 0);
|
|
13
13
|
--theme-badge-dot-size: var(--spacing-gap-3, 8px);
|
|
@@ -188,6 +188,7 @@
|
|
|
188
188
|
--theme-checkbox-surface-selected-disabled: rgba(26, 106, 255, 0.28);
|
|
189
189
|
--theme-checkbox-label-color: var(--color-label-strong);
|
|
190
190
|
--theme-checkbox-label-disabled: var(--color-label-disabled);
|
|
191
|
+
--theme-checkbox-label-font-weight: 400;
|
|
191
192
|
--theme-checkbox-helper-color: var(--color-label-neutral);
|
|
192
193
|
--theme-checkbox-helper-disabled: var(--color-label-disabled);
|
|
193
194
|
--theme-checkbox-icon-default: transparent;
|
|
@@ -439,6 +440,7 @@
|
|
|
439
440
|
--theme-radio-disabled-selected-fill: var(--color-primary-default);
|
|
440
441
|
--theme-radio-label-color: var(--color-label-strong);
|
|
441
442
|
--theme-radio-label-disabled: var(--color-label-disabled);
|
|
443
|
+
--theme-radio-label-font-weight: 400;
|
|
442
444
|
--theme-radio-helper-color: var(--color-label-neutral);
|
|
443
445
|
--theme-radio-helper-disabled: var(--color-label-disabled);
|
|
444
446
|
--theme-radio-card-background: var(--color-common-100);
|
|
@@ -1723,17 +1725,17 @@
|
|
|
1723
1725
|
cursor: not-allowed;
|
|
1724
1726
|
}
|
|
1725
1727
|
|
|
1726
|
-
.checkbox-label
|
|
1727
|
-
font-weight: var(--
|
|
1728
|
+
.checkbox-label {
|
|
1729
|
+
font-weight: var(--theme-checkbox-label-font-weight);
|
|
1728
1730
|
user-select: none;
|
|
1729
1731
|
}
|
|
1730
1732
|
|
|
1731
|
-
.checkbox-field[data-size=medium] .checkbox-label
|
|
1733
|
+
.checkbox-field[data-size=medium] .checkbox-label {
|
|
1732
1734
|
font-size: var(--font-body-xsmall-size);
|
|
1733
1735
|
line-height: var(--font-body-xsmall-line-height);
|
|
1734
1736
|
}
|
|
1735
1737
|
|
|
1736
|
-
.checkbox-field[data-size=large] .checkbox-label
|
|
1738
|
+
.checkbox-field[data-size=large] .checkbox-label {
|
|
1737
1739
|
font-size: var(--font-body-medium-size);
|
|
1738
1740
|
line-height: var(--font-body-medium-line-height);
|
|
1739
1741
|
}
|
|
@@ -1754,6 +1756,7 @@
|
|
|
1754
1756
|
|
|
1755
1757
|
|
|
1756
1758
|
.chip {
|
|
1759
|
+
--chip-current-height: var(--theme-chip-height);
|
|
1757
1760
|
--chip-gap: var(--theme-chip-gap);
|
|
1758
1761
|
--chip-bg: transparent;
|
|
1759
1762
|
--chip-border-color: transparent;
|
|
@@ -1762,7 +1765,7 @@
|
|
|
1762
1765
|
align-items: center;
|
|
1763
1766
|
justify-content: center;
|
|
1764
1767
|
gap: var(--chip-gap);
|
|
1765
|
-
height: var(--
|
|
1768
|
+
height: var(--chip-current-height);
|
|
1766
1769
|
padding-left: var(--theme-chip-padding-horizontal);
|
|
1767
1770
|
padding-right: var(--theme-chip-padding-horizontal);
|
|
1768
1771
|
padding-block: 0;
|
|
@@ -1796,35 +1799,47 @@ figure.chip {
|
|
|
1796
1799
|
outline-offset: 2px;
|
|
1797
1800
|
}
|
|
1798
1801
|
|
|
1799
|
-
.chip:where([data-
|
|
1800
|
-
.chip:where([data-kind=filter-rounded]) {
|
|
1802
|
+
.chip:where([data-style=filter][data-fill=solid]) {
|
|
1801
1803
|
--chip-bg: var(--color-surface-standard);
|
|
1802
1804
|
--chip-label-color: var(--color-label-neutral);
|
|
1803
1805
|
--chip-border-color: transparent;
|
|
1804
1806
|
}
|
|
1805
1807
|
|
|
1806
|
-
.chip:where([data-
|
|
1807
|
-
|
|
1808
|
+
.chip:where([data-style=filter][data-fill=outlined]) {
|
|
1809
|
+
--chip-bg: var(--color-common-100);
|
|
1810
|
+
--chip-label-color: var(--color-label-neutral);
|
|
1811
|
+
--chip-border-color: var(--color-border-standard-cool-gray);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
.chip:where([data-style=filter][data-selected=true]) {
|
|
1808
1815
|
--chip-bg: var(--color-surface-heavy);
|
|
1809
1816
|
--chip-label-color: var(--color-common-100);
|
|
1817
|
+
--chip-border-color: transparent;
|
|
1810
1818
|
}
|
|
1811
1819
|
|
|
1812
|
-
.chip:where([data-
|
|
1813
|
-
border-radius: var(--
|
|
1820
|
+
.chip:where([data-style][data-rounded=true]) {
|
|
1821
|
+
border-radius: calc(var(--chip-current-height) / 2);
|
|
1814
1822
|
}
|
|
1815
1823
|
|
|
1816
|
-
.chip:where([data-
|
|
1824
|
+
.chip:where([data-style=assist][data-fill=solid]) {
|
|
1817
1825
|
--chip-bg: var(--color-surface-static-neutral);
|
|
1818
1826
|
--chip-label-color: var(--color-label-strong);
|
|
1819
1827
|
--chip-gap: var(--theme-chip-assist-gap);
|
|
1820
1828
|
--chip-border-color: transparent;
|
|
1821
1829
|
}
|
|
1822
1830
|
|
|
1823
|
-
.chip:where([data-
|
|
1831
|
+
.chip:where([data-style=assist][data-fill=outlined]) {
|
|
1832
|
+
--chip-bg: var(--color-common-100);
|
|
1833
|
+
--chip-label-color: var(--color-label-strong);
|
|
1834
|
+
--chip-gap: var(--theme-chip-assist-gap);
|
|
1835
|
+
--chip-border-color: var(--color-border-standard-cool-gray);
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
.chip:where([data-style=assist][data-selected=true]) {
|
|
1824
1839
|
--chip-label-color: var(--color-primary-default);
|
|
1825
1840
|
}
|
|
1826
1841
|
|
|
1827
|
-
.chip:where([data-
|
|
1842
|
+
.chip:where([data-style=input]) {
|
|
1828
1843
|
--chip-gap: var(--theme-chip-input-gap);
|
|
1829
1844
|
--chip-bg: var(--color-common-100);
|
|
1830
1845
|
--chip-label-color: var(--color-label-standard);
|
|
@@ -1833,12 +1848,13 @@ figure.chip {
|
|
|
1833
1848
|
padding-right: var(--theme-chip-input-padding-right);
|
|
1834
1849
|
}
|
|
1835
1850
|
|
|
1836
|
-
.chip:where([data-
|
|
1851
|
+
.chip:where([data-style=input][data-removable=false]) {
|
|
1837
1852
|
padding-left: var(--theme-chip-padding-horizontal);
|
|
1838
1853
|
padding-right: var(--theme-chip-padding-horizontal);
|
|
1839
1854
|
}
|
|
1840
1855
|
|
|
1841
1856
|
.chip:where([data-size=table]) {
|
|
1857
|
+
--chip-current-height: var(--theme-chip-height-table);
|
|
1842
1858
|
height: var(--theme-chip-height-table);
|
|
1843
1859
|
padding-left: var(--theme-chip-padding-horizontal-table);
|
|
1844
1860
|
padding-right: var(--theme-chip-padding-horizontal-table);
|
|
@@ -1854,22 +1870,22 @@ figure.chip {
|
|
|
1854
1870
|
line-height: var(--theme-chip-line-height-table);
|
|
1855
1871
|
}
|
|
1856
1872
|
|
|
1857
|
-
.chip:where([data-size=table][data-
|
|
1873
|
+
.chip:where([data-size=table][data-style=input]) {
|
|
1858
1874
|
padding-left: var(--theme-chip-padding-left-table);
|
|
1859
1875
|
padding-right: var(--theme-chip-padding-right-table);
|
|
1860
1876
|
}
|
|
1861
1877
|
|
|
1862
|
-
.chip:where([data-size=table][data-
|
|
1878
|
+
.chip:where([data-size=table][data-style=input][data-removable=false]) {
|
|
1863
1879
|
padding-left: var(--theme-chip-padding-horizontal-table);
|
|
1864
1880
|
padding-right: var(--theme-chip-padding-horizontal-table);
|
|
1865
1881
|
}
|
|
1866
1882
|
|
|
1867
|
-
.chip:where([data-size=table][data-
|
|
1883
|
+
.chip:where([data-size=table][data-style=input]) .chip-remove-button {
|
|
1868
1884
|
width: fit-content;
|
|
1869
1885
|
height: fit-content;
|
|
1870
1886
|
}
|
|
1871
1887
|
|
|
1872
|
-
.chip:where([data-
|
|
1888
|
+
.chip:where([data-style=input][data-selected=true]) {
|
|
1873
1889
|
--chip-border-color: var(--color-border-standard-blue);
|
|
1874
1890
|
}
|
|
1875
1891
|
|
|
@@ -1916,6 +1932,20 @@ figure.chip {
|
|
|
1916
1932
|
height: 100%;
|
|
1917
1933
|
}
|
|
1918
1934
|
|
|
1935
|
+
.chip-list {
|
|
1936
|
+
display: flex;
|
|
1937
|
+
flex-wrap: wrap;
|
|
1938
|
+
align-items: center;
|
|
1939
|
+
gap: var(--spacing-gap-2);
|
|
1940
|
+
margin: 0;
|
|
1941
|
+
padding: 0;
|
|
1942
|
+
list-style: none;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
.chip-list-item {
|
|
1946
|
+
display: flex;
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1919
1949
|
/* Divider 토큰도 전역 :root 범위에 선언한다. */
|
|
1920
1950
|
|
|
1921
1951
|
|
|
@@ -3396,17 +3426,17 @@ figure.chip {
|
|
|
3396
3426
|
cursor: not-allowed;
|
|
3397
3427
|
}
|
|
3398
3428
|
|
|
3399
|
-
.radio-label
|
|
3400
|
-
font-weight: var(--
|
|
3429
|
+
.radio-label {
|
|
3430
|
+
font-weight: var(--theme-radio-label-font-weight);
|
|
3401
3431
|
user-select: none;
|
|
3402
3432
|
}
|
|
3403
3433
|
|
|
3404
|
-
.radio-field[data-size=medium] .radio-label
|
|
3434
|
+
.radio-field[data-size=medium] .radio-label {
|
|
3405
3435
|
font-size: var(--font-body-xsmall-size);
|
|
3406
3436
|
line-height: var(--font-body-xsmall-line-height);
|
|
3407
3437
|
}
|
|
3408
3438
|
|
|
3409
|
-
.radio-field[data-size=large] .radio-label
|
|
3439
|
+
.radio-field[data-size=large] .radio-label {
|
|
3410
3440
|
font-size: var(--font-body-medium-size);
|
|
3411
3441
|
line-height: var(--font-body-medium-line-height);
|
|
3412
3442
|
}
|
|
@@ -3537,7 +3567,7 @@ figure.chip {
|
|
|
3537
3567
|
--segmented-item-padding-x: 22px;
|
|
3538
3568
|
--segmented-item-padding-y: 4px;
|
|
3539
3569
|
--segmented-item-font-size: var(--font-heading-xxsmall-size, 15px);
|
|
3540
|
-
--segmented-item-font-weight:
|
|
3570
|
+
--segmented-item-font-weight: 500;
|
|
3541
3571
|
--segmented-item-line-height: var(--font-heading-xxsmall-line-height, 1.5);
|
|
3542
3572
|
position: relative;
|
|
3543
3573
|
display: block;
|
|
@@ -3618,7 +3648,7 @@ figure.chip {
|
|
|
3618
3648
|
outline-offset: 2px;
|
|
3619
3649
|
}
|
|
3620
3650
|
|
|
3621
|
-
.segmented-control-
|
|
3651
|
+
.segmented-control-label {
|
|
3622
3652
|
display: flex;
|
|
3623
3653
|
align-items: center;
|
|
3624
3654
|
justify-content: center;
|
|
@@ -3630,7 +3660,7 @@ figure.chip {
|
|
|
3630
3660
|
transition: color 0.2s ease;
|
|
3631
3661
|
}
|
|
3632
3662
|
|
|
3633
|
-
.segmented-control-button:where([data-state=on]) .segmented-control-
|
|
3663
|
+
.segmented-control-button:where([data-state=on]) .segmented-control-label {
|
|
3634
3664
|
color: var(--segmented-label-active-color);
|
|
3635
3665
|
}
|
|
3636
3666
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { forwardRef } from "react";
|
|
2
2
|
import type { BadgeProps } from "../types";
|
|
3
3
|
import { composeBadgeClassName } from "../utils";
|
|
4
|
+
import { Slot } from "../../slot";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Badge 컴포넌트; size/style/intent 축을 data attribute로 노출한다.
|
|
@@ -50,11 +51,8 @@ const Badge = forwardRef<HTMLElementTagNameMap["figure"], BadgeProps>(
|
|
|
50
51
|
data-has-label={hasLabel ? "true" : undefined}
|
|
51
52
|
>
|
|
52
53
|
{renderDot}
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
) : (
|
|
56
|
-
children
|
|
57
|
-
)}
|
|
54
|
+
{/* 변경: badge 라벨 텍스트 래핑 규칙을 Slot.Text로 통일한다. */}
|
|
55
|
+
<Slot.Text className="badge-label">{children}</Slot.Text>
|
|
58
56
|
</figure>
|
|
59
57
|
);
|
|
60
58
|
},
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
--theme-badge-radius: var(--theme-radius-medium-1, 6px);
|
|
7
7
|
--theme-badge-font-family: var(--font-caption-medium-family, inherit);
|
|
8
8
|
--theme-badge-font-size: var(--font-caption-medium-size, 11px);
|
|
9
|
-
|
|
9
|
+
// 변경: Badge label font-weight는 디자인 규칙에 맞춰 400으로 고정한다.
|
|
10
|
+
--theme-badge-font-weight: 400;
|
|
10
11
|
--theme-badge-line-height: var(--font-caption-medium-line-height, 1.5);
|
|
11
12
|
--theme-badge-letter-spacing: var(--font-caption-medium-letter-spacing, 0);
|
|
12
13
|
--theme-badge-dot-size: var(--spacing-gap-3, 8px);
|
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import "./index.scss";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
ButtonDefault,
|
|
8
|
+
ButtonText,
|
|
9
|
+
ButtonRounded,
|
|
10
|
+
ButtonLabel,
|
|
11
|
+
} from "./markup";
|
|
7
12
|
|
|
8
13
|
export const Button = {
|
|
9
14
|
Default: ButtonDefault,
|
|
10
15
|
Text: ButtonText,
|
|
11
16
|
Rounded: ButtonRounded,
|
|
17
|
+
Label: ButtonLabel,
|
|
12
18
|
};
|
|
13
19
|
|
|
14
20
|
export * from "./hooks";
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { forwardRef } from "react";
|
|
5
5
|
import type { ButtonProps } from "../types";
|
|
6
|
-
import {
|
|
6
|
+
import { Slot } from "../../slot";
|
|
7
|
+
import ButtonLabel from "./Label";
|
|
7
8
|
import {
|
|
8
9
|
getFormFieldWidthAttr,
|
|
9
10
|
getFormFieldWidthValue,
|
|
@@ -85,7 +86,7 @@ const ButtonDefault = forwardRef<HTMLElement, ButtonProps>(
|
|
|
85
86
|
: style;
|
|
86
87
|
|
|
87
88
|
return (
|
|
88
|
-
<
|
|
89
|
+
<Slot.Base
|
|
89
90
|
className={clsx(
|
|
90
91
|
"button",
|
|
91
92
|
`button-fill-${fill}`,
|
|
@@ -112,19 +113,13 @@ const ButtonDefault = forwardRef<HTMLElement, ButtonProps>(
|
|
|
112
113
|
{left}
|
|
113
114
|
</span>
|
|
114
115
|
)}
|
|
115
|
-
|
|
116
|
-
<span className="button-label" data-slot="label">
|
|
117
|
-
{children}
|
|
118
|
-
</span>
|
|
119
|
-
) : (
|
|
120
|
-
children
|
|
121
|
-
)}
|
|
116
|
+
<ButtonLabel data-slot="label">{children}</ButtonLabel>
|
|
122
117
|
{right && (
|
|
123
118
|
<span className="button-right" data-slot="right">
|
|
124
119
|
{right}
|
|
125
120
|
</span>
|
|
126
121
|
)}
|
|
127
|
-
</
|
|
122
|
+
</Slot.Base>
|
|
128
123
|
);
|
|
129
124
|
},
|
|
130
125
|
);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import { Slot } from "../../slot";
|
|
3
|
+
import type { ButtonLabelProps } from "../types/label";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ButtonLabel; Button namespace에서 재사용 가능한 label 래퍼.
|
|
7
|
+
* @component
|
|
8
|
+
* @param {ButtonLabelProps} props
|
|
9
|
+
* @param {React.ElementType} [props.as="span"] 렌더링할 요소.
|
|
10
|
+
* @param {React.ReactNode} [props.children] 문자열/숫자는 button-label span으로 렌더하고, 그 외 ReactNode는 그대로 반환한다.
|
|
11
|
+
* @param {string} [props.className] button-label과 병합할 className.
|
|
12
|
+
* @example
|
|
13
|
+
* <Button.Label>확인</Button.Label>
|
|
14
|
+
*/
|
|
15
|
+
export default function ButtonLabel({
|
|
16
|
+
className,
|
|
17
|
+
...restProps
|
|
18
|
+
}: ButtonLabelProps) {
|
|
19
|
+
// Button 전용 라벨 클래스는 namespace 컴포넌트에서 고정 주입한다.
|
|
20
|
+
return (
|
|
21
|
+
<Slot.Text className={clsx("button-label", className)} {...restProps} />
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SlotTextProps } from "../../slot";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ButtonLabelProps; Button 전용 label 래퍼 props.
|
|
5
|
+
* @property {React.ElementType} [as] 렌더링할 요소. 기본값은 span.
|
|
6
|
+
* @property {React.ReactNode} [children] 문자열/숫자는 래핑하고, 그 외 ReactNode는 그대로 반환한다.
|
|
7
|
+
* @property {string} [className] 기본 button-label 클래스와 병합할 className.
|
|
8
|
+
*/
|
|
9
|
+
export type ButtonLabelProps = SlotTextProps;
|
|
@@ -4,13 +4,14 @@ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
|
4
4
|
import type { CheckboxFieldProps, CheckboxProps, CheckboxSize } from "../types";
|
|
5
5
|
import CheckLargeIcon from "../img/check-large.svg";
|
|
6
6
|
import CheckMediumIcon from "../img/check-medium.svg";
|
|
7
|
+
import { Slot } from "../../slot";
|
|
7
8
|
|
|
8
9
|
const CHECKBOX_CLASSNAME = "checkbox";
|
|
9
10
|
const CHECKBOX_SURFACE_CLASSNAME = "checkbox-surface";
|
|
10
11
|
const CHECKBOX_INDICATOR_CLASSNAME = "checkbox-indicator";
|
|
11
12
|
const CHECKBOX_FIELD_CLASSNAME = "checkbox-field";
|
|
12
13
|
const CHECKBOX_LABEL_WRAPPER_CLASSNAME = "checkbox-label-wrapper";
|
|
13
|
-
const
|
|
14
|
+
const CHECKBOX_LABEL_CLASSNAME = "checkbox-label";
|
|
14
15
|
const CHECKBOX_HELPER_CLASSNAME = "checkbox-helper";
|
|
15
16
|
|
|
16
17
|
const getIndicatorIcon = (size: CheckboxSize) =>
|
|
@@ -95,7 +96,10 @@ const CheckboxField = forwardRef<HTMLButtonElement, CheckboxFieldProps>(
|
|
|
95
96
|
) {
|
|
96
97
|
const generatedId = useId();
|
|
97
98
|
const checkboxId = id ?? generatedId;
|
|
98
|
-
const labelId =
|
|
99
|
+
const labelId =
|
|
100
|
+
label && ["string", "number"].includes(typeof label)
|
|
101
|
+
? `${checkboxId}-label`
|
|
102
|
+
: undefined;
|
|
99
103
|
const helperId = helperText ? `${checkboxId}-helper` : undefined;
|
|
100
104
|
// Label/helper는 Root 외부에서 htmlFor/aria 연결을 유지한다.
|
|
101
105
|
|
|
@@ -126,9 +130,10 @@ const CheckboxField = forwardRef<HTMLButtonElement, CheckboxFieldProps>(
|
|
|
126
130
|
ref={ref}
|
|
127
131
|
/>
|
|
128
132
|
{label ? (
|
|
129
|
-
|
|
133
|
+
// 변경: label 렌더는 Slot.Text 단일 경로로 통일하고, aria-labelledby는 텍스트일 때만 연결한다.
|
|
134
|
+
<Slot.Text id={labelId} className={CHECKBOX_LABEL_CLASSNAME}>
|
|
130
135
|
{label}
|
|
131
|
-
</
|
|
136
|
+
</Slot.Text>
|
|
132
137
|
) : null}
|
|
133
138
|
</label>
|
|
134
139
|
{helperText ? (
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
--theme-checkbox-surface-selected-disabled: rgba(26, 106, 255, 0.28);
|
|
16
16
|
--theme-checkbox-label-color: var(--color-label-strong);
|
|
17
17
|
--theme-checkbox-label-disabled: var(--color-label-disabled);
|
|
18
|
+
// 변경: Checkbox label font-weight는 디자인 규칙에 맞춰 400으로 고정한다.
|
|
19
|
+
--theme-checkbox-label-font-weight: 400;
|
|
18
20
|
--theme-checkbox-helper-color: var(--color-label-neutral);
|
|
19
21
|
--theme-checkbox-helper-disabled: var(--color-label-disabled);
|
|
20
22
|
--theme-checkbox-icon-default: transparent;
|
|
@@ -148,17 +150,17 @@
|
|
|
148
150
|
cursor: not-allowed;
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
.checkbox-label
|
|
152
|
-
font-weight: var(--
|
|
153
|
+
.checkbox-label {
|
|
154
|
+
font-weight: var(--theme-checkbox-label-font-weight);
|
|
153
155
|
user-select: none;
|
|
154
156
|
}
|
|
155
157
|
|
|
156
|
-
.checkbox-field[data-size="medium"] .checkbox-label
|
|
158
|
+
.checkbox-field[data-size="medium"] .checkbox-label {
|
|
157
159
|
font-size: var(--font-body-xsmall-size);
|
|
158
160
|
line-height: var(--font-body-xsmall-line-height);
|
|
159
161
|
}
|
|
160
162
|
|
|
161
|
-
.checkbox-field[data-size="large"] .checkbox-label
|
|
163
|
+
.checkbox-field[data-size="large"] .checkbox-label {
|
|
162
164
|
font-size: var(--font-body-medium-size);
|
|
163
165
|
line-height: var(--font-body-medium-line-height);
|
|
164
166
|
}
|
|
@@ -1,48 +1,55 @@
|
|
|
1
1
|
import { forwardRef, type Ref } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
2
3
|
import type { ChipInputProps, ChipProps } from "../types";
|
|
3
|
-
import
|
|
4
|
+
import ChipClickableStyle from "./DefaultStyle";
|
|
4
5
|
import ChipInputStyle from "./InputStyle";
|
|
5
6
|
|
|
6
|
-
//
|
|
7
|
+
// chipStyle === "input" 조합에서 props를 ChipInputProps로 좁히기 위한 type guard.
|
|
7
8
|
const isChipInputProps = (props: ChipProps): props is ChipInputProps =>
|
|
8
|
-
props.
|
|
9
|
+
props.chipStyle === "input";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* Chip Markup;
|
|
12
|
+
* Chip Markup; Style별 렌더 분기 Orchestrator 컴포넌트
|
|
12
13
|
* @component
|
|
13
14
|
* @param {ChipProps} props Chip 공통/종류별 props
|
|
14
|
-
* @param {"filter" | "
|
|
15
|
+
* @param {"filter" | "assist" | "input"} [props.chipStyle="filter"] Chip 스타일
|
|
16
|
+
* @param {"solid" | "outlined"} [props.fill="solid"] Chip 채움 스타일
|
|
17
|
+
* @param {boolean} [props.rounded=false] pill radius 적용 여부
|
|
15
18
|
* @param {React.ReactNode} [props.children] Chip 라벨/콘텐츠
|
|
16
|
-
* @param {boolean} [props.selected] 선택 상태; filter
|
|
17
|
-
* @param {React.ReactNode} [props.leading] assist
|
|
19
|
+
* @param {boolean} [props.selected] 선택 상태; filter 스타일에서 `aria-pressed`로 반영
|
|
20
|
+
* @param {React.ReactNode} [props.leading] assist 스타일 좌측 slot
|
|
18
21
|
* @param {"default" | "table"} [props.size="default"] 사이즈 축
|
|
19
|
-
* @param {string} [props.removeButtonLabel="선택 항목 삭제"] input
|
|
20
|
-
* @param {boolean} [props.disabled] input
|
|
21
|
-
* @param {(event: MouseEvent<HTMLButtonElement>) => void} [props.onRemove] input
|
|
22
|
-
* @param {(event: MouseEvent<HTMLButtonElement>) => void} [props.onClick] interactive
|
|
23
|
-
* @param {"button" | "submit" | "reset"} [props.type] interactive
|
|
22
|
+
* @param {string} [props.removeButtonLabel="선택 항목 삭제"] input 스타일 remove 버튼 라벨
|
|
23
|
+
* @param {boolean} [props.disabled] input 스타일 비활성화 여부
|
|
24
|
+
* @param {(event: MouseEvent<HTMLButtonElement>) => void} [props.onRemove] input 스타일 remove 핸들러
|
|
25
|
+
* @param {(event: MouseEvent<HTMLButtonElement>) => void} [props.onClick] interactive 스타일 click 핸들러
|
|
26
|
+
* @param {"button" | "submit" | "reset"} [props.type] interactive 스타일 button type
|
|
24
27
|
* @param {string} [props.className] root className
|
|
25
28
|
* @param {string} [props.id] root id
|
|
26
29
|
* @param {string} [props.title] root title
|
|
27
30
|
* @description
|
|
28
|
-
* - `
|
|
29
|
-
* - `
|
|
30
|
-
* - native HTML attrs는
|
|
31
|
-
* @returns {JSX.Element}
|
|
31
|
+
* - `chipStyle="input"`이면 `<figure>`를 렌더하고, 나머지 스타일은 `<button>`을 렌더한다.
|
|
32
|
+
* - `chipStyle="input"`일 때 remove 버튼 클릭 이벤트는 root click으로 버블링되지 않도록 내부에서 차단한다.
|
|
33
|
+
* - native HTML attrs는 style에 맞는 root 요소로 그대로 전달된다.
|
|
34
|
+
* @returns {JSX.Element} style에 맞는 Chip root 요소
|
|
32
35
|
* @example
|
|
33
|
-
* <
|
|
36
|
+
* <ChipDefault chipStyle="filter" fill="solid" selected rounded>
|
|
34
37
|
* 전체
|
|
35
|
-
* </
|
|
38
|
+
* </ChipDefault>
|
|
36
39
|
* @example
|
|
37
|
-
* <
|
|
40
|
+
* <ChipDefault chipStyle="input" onRemove={event => console.log(event.type)}>
|
|
38
41
|
* 첨부파일.pdf
|
|
39
|
-
* </
|
|
42
|
+
* </ChipDefault>
|
|
40
43
|
*/
|
|
41
|
-
const
|
|
44
|
+
const ChipDefault = forwardRef<HTMLElement, ChipProps>((props, ref) => {
|
|
45
|
+
const mergedClassName = clsx("chip-default", props.className);
|
|
46
|
+
|
|
42
47
|
if (isChipInputProps(props)) {
|
|
43
48
|
return (
|
|
44
49
|
<ChipInputStyle
|
|
45
50
|
{...props}
|
|
51
|
+
// 변경: 역할 className을 루트 컴포넌트에서 누적 전달한다.
|
|
52
|
+
className={mergedClassName}
|
|
46
53
|
// 변경: 하위 스타일 컴포넌트가 forwardRef를 사용하므로 ref를 직접 전달한다.
|
|
47
54
|
ref={ref as Ref<HTMLElementTagNameMap["figure"]>}
|
|
48
55
|
/>
|
|
@@ -50,11 +57,16 @@ const Chip = forwardRef<HTMLElement, ChipProps>((props, ref) => {
|
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
return (
|
|
60
|
+
// 변경: 역할 className을 루트 컴포넌트에서 누적 전달한다.
|
|
53
61
|
// 변경: interactive 경로도 forwardRef 기반 ref 전달로 통일한다.
|
|
54
|
-
<
|
|
62
|
+
<ChipClickableStyle
|
|
63
|
+
{...props}
|
|
64
|
+
className={mergedClassName}
|
|
65
|
+
ref={ref as Ref<HTMLButtonElement>}
|
|
66
|
+
/>
|
|
55
67
|
);
|
|
56
68
|
});
|
|
57
69
|
|
|
58
|
-
|
|
70
|
+
ChipDefault.displayName = "Chip.Default";
|
|
59
71
|
|
|
60
|
-
export {
|
|
72
|
+
export { ChipDefault };
|