@uniai-fe/uds-primitives 0.4.7 → 0.4.8

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 CHANGED
@@ -1,16 +1,43 @@
1
1
  @charset "UTF-8";
2
2
  :root {
3
- --theme-badge-height-xsmall: var(--theme-size-small-1, 20px);
4
- --theme-badge-height-small: var(--theme-size-small-2, 24px);
5
- --theme-badge-padding-inline-xsmall: var(--spacing-padding-3, 6px);
6
- --theme-badge-padding-inline-small: var(--spacing-padding-4, 8px);
7
- --theme-badge-radius: var(--theme-radius-medium-1, 6px);
8
- --theme-badge-font-family: var(--font-caption-medium-family, inherit);
9
- --theme-badge-font-size: var(--font-caption-medium-size, 11px);
10
- --theme-badge-font-weight: 400;
11
- --theme-badge-line-height: var(--font-caption-medium-line-height, 1.5);
12
- --theme-badge-letter-spacing: var(--font-caption-medium-letter-spacing, 0);
13
- --theme-badge-dot-size: var(--spacing-gap-3, 8px);
3
+ --theme-badge-height-xsmall: var(--theme-size-small-1);
4
+ --theme-badge-height-small: var(--theme-size-small-2);
5
+ /* 변경: Figma 2421:619 기준 medium 배지 높이 32px를 추가한다. */
6
+ --theme-badge-height-medium: var(--theme-size-small-3);
7
+ --theme-badge-padding-inline-xsmall: var(--spacing-padding-3);
8
+ --theme-badge-padding-inline-small: var(--spacing-padding-4);
9
+ --theme-badge-padding-inline-medium: var(--spacing-padding-5);
10
+ --theme-badge-radius-xsmall: var(--theme-radius-medium-1);
11
+ --theme-badge-radius-small: var(--theme-radius-medium-1);
12
+ --theme-badge-radius-medium: var(--theme-radius-medium-3);
13
+ --theme-badge-font-family: var(--font-caption-medium-family);
14
+ --theme-badge-font-size-xsmall: var(--font-caption-medium-size);
15
+ --theme-badge-font-size-small: var(--font-caption-large-size);
16
+ --theme-badge-font-size-medium: var(--font-body-xsmall-size);
17
+ /* 변경: Figma badge size 축은 모두 Regular(400) 기준으로 고정한다. */
18
+ --theme-badge-font-weight-xsmall: 400;
19
+ --theme-badge-font-weight-small: 400;
20
+ --theme-badge-font-weight-medium: 400;
21
+ --theme-badge-line-height-xsmall: var(--font-caption-medium-line-height);
22
+ --theme-badge-line-height-small: var(--font-caption-large-line-height);
23
+ --theme-badge-line-height-medium: var(--font-body-xsmall-line-height);
24
+ --theme-badge-letter-spacing-xsmall: var(
25
+ --font-caption-medium-letter-spacing
26
+ );
27
+ --theme-badge-letter-spacing-small: var(--font-caption-large-letter-spacing);
28
+ --theme-badge-letter-spacing-medium: var(--font-body-xsmall-letter-spacing);
29
+ /* 변경: Count xsmall은 Figma 1620:844 기준으로 radius 10px를 사용한다. */
30
+ --theme-badge-count-radius-xsmall: var(--theme-radius-medium-4);
31
+ --theme-badge-dot-size: var(--spacing-gap-3);
32
+ --theme-badge-gap: var(--spacing-gap-1);
33
+ --theme-badge-fill-background-default: var(--color-primary-default);
34
+ --theme-badge-fill-text-default: var(--color-common-100);
35
+ --theme-badge-outlined-background-default: var(--color-surface-static-white);
36
+ --theme-badge-outlined-border-default: var(--color-primary-default);
37
+ --theme-badge-outlined-text-default: var(--color-primary-default);
38
+ --theme-badge-dot-background-default: var(--color-primary-default);
39
+ --theme-badge-count-background-default: var(--color-primary-default);
40
+ --theme-badge-count-text-default: var(--color-common-100);
14
41
  /* layout presets */
15
42
  --button-width: fit-content;
16
43
  --button-flex: 0 0 auto;
@@ -664,6 +691,39 @@
664
691
  --select-multiple-chip-summary-font-weight: 400;
665
692
  /* Typography tokens */
666
693
  --select-text-font-family: var(--font-body-medium-family);
694
+ --tab-height-small: 40px;
695
+ --tab-height-medium: 48px;
696
+ --tab-height-large: 56px;
697
+ /* 변경: Figma node 1176:834/781/739 기준으로 tab label typography를 exact spec으로 다시 고정한다. */
698
+ --tab-label-font-size-small: var(--font-label-medium-size);
699
+ --tab-label-font-weight-small: 700;
700
+ --tab-label-line-height-small: 1.4;
701
+ --tab-label-letter-spacing-small: 0px;
702
+ --tab-label-font-size-medium: var(--font-label-large-size);
703
+ --tab-label-font-weight-medium: 700;
704
+ --tab-label-line-height-medium: 1.4;
705
+ --tab-label-letter-spacing-medium: 0px;
706
+ --tab-label-font-size-large: var(--font-heading-small-size);
707
+ --tab-label-font-weight-large: 700;
708
+ --tab-label-line-height-large: 1.4;
709
+ --tab-label-letter-spacing-large: 0px;
710
+ --tab-gap: var(--spacing-gap-2);
711
+ --tab-root-gap: var(--spacing-gap-3);
712
+ --tab-padding-y: 10px;
713
+ --tab-padding-x: var(--spacing-padding-8);
714
+ --tab-padding-x-small: var(--spacing-padding-4);
715
+ --tab-icon-gap: 6px;
716
+ /* 변경: line track은 foundation에 존재하는 assistive border token(#f2f2f3)을 사용한다. */
717
+ --tab-line-track-color: var(--color-border-assistive);
718
+ --tab-line-track-height: 1px;
719
+ --tab-line-indicator-height: 2px;
720
+ --tab-color-active-default: var(--color-primary-default);
721
+ --tab-color-active: var(--tab-color-active-default);
722
+ --tab-color-hover: color-mix(in srgb, var(--tab-color-active), #000 15%);
723
+ --tab-fill-hover-bg: var(--color-bg-alternative-cool-gray);
724
+ --tab-fill-active-color: var(--color-common-100);
725
+ --tab-inactive-color: var(--color-label-alternative);
726
+ --tab-disabled-opacity: 0.4;
667
727
  --table-border-color: var(--color-border-standard-cool-gray);
668
728
  --table-line-head-background-color: var(--color-surface-static-cool-gray);
669
729
  --table-grid-head-background-color: var(
@@ -785,179 +845,237 @@
785
845
  height: 100%;
786
846
  }
787
847
 
848
+ /* Badge 기본 토큰 래핑 */
788
849
 
789
850
 
790
851
  .badge {
791
852
  --badge-height: var(--theme-badge-height-xsmall);
792
853
  --badge-padding-inline: var(--theme-badge-padding-inline-xsmall);
793
- --badge-gap: var(--spacing-gap-1, 4px);
794
- --badge-fill-bg-color: var(--color-primary-default, #1a6aff);
795
- --badge-fill-label-color: var(--color-common-100, #ffffff);
796
- --badge-outline-border-color: var(--color-primary-default, #1a6aff);
797
- --badge-outline-label-color: var(--color-primary-default, #1a6aff);
798
- --badge-dot-color: var(--color-primary-default, #1a6aff);
854
+ --badge-radius: var(--theme-badge-radius-xsmall);
855
+ --badge-font-size: var(--theme-badge-font-size-xsmall);
856
+ --badge-font-weight: var(--theme-badge-font-weight-xsmall);
857
+ --badge-line-height: var(--theme-badge-line-height-xsmall);
858
+ --badge-letter-spacing: var(--theme-badge-letter-spacing-xsmall);
799
859
  --badge-dot-size: var(--theme-badge-dot-size);
800
860
  display: flex;
801
861
  align-items: center;
802
862
  justify-content: center;
803
- gap: var(--badge-gap);
863
+ gap: var(--theme-badge-gap);
864
+ width: fit-content;
804
865
  height: var(--badge-height);
866
+ margin: 0;
805
867
  padding-inline: var(--badge-padding-inline);
806
868
  padding-block: 0;
807
- border-radius: var(--theme-badge-radius);
808
869
  border: 0;
809
- font-family: var(--theme-badge-font-family);
810
- font-size: var(--theme-badge-font-size);
811
- font-weight: var(--theme-badge-font-weight);
812
- line-height: 1;
813
- letter-spacing: var(--theme-badge-letter-spacing);
814
- white-space: nowrap;
815
870
  box-sizing: border-box;
816
- margin: 0;
817
- width: fit-content;
871
+ border-radius: var(--badge-radius);
872
+ white-space: nowrap;
873
+ font-family: var(--theme-badge-font-family);
874
+ font-size: var(--badge-font-size);
875
+ font-weight: var(--badge-font-weight);
876
+ line-height: var(--badge-line-height);
877
+ letter-spacing: var(--badge-letter-spacing);
818
878
  }
819
879
 
820
880
  .badge:where([data-size=small]) {
821
881
  --badge-height: var(--theme-badge-height-small);
822
882
  --badge-padding-inline: var(--theme-badge-padding-inline-small);
883
+ --badge-radius: var(--theme-badge-radius-small);
884
+ --badge-font-size: var(--theme-badge-font-size-small);
885
+ --badge-font-weight: var(--theme-badge-font-weight-small);
886
+ --badge-line-height: var(--theme-badge-line-height-small);
887
+ --badge-letter-spacing: var(--theme-badge-letter-spacing-small);
888
+ }
889
+
890
+ .badge:where([data-size=medium]) {
891
+ --badge-height: var(--theme-badge-height-medium);
892
+ --badge-padding-inline: var(--theme-badge-padding-inline-medium);
893
+ --badge-radius: var(--theme-badge-radius-medium);
894
+ --badge-font-size: var(--theme-badge-font-size-medium);
895
+ --badge-font-weight: var(--theme-badge-font-weight-medium);
896
+ --badge-line-height: var(--theme-badge-line-height-medium);
897
+ --badge-letter-spacing: var(--theme-badge-letter-spacing-medium);
823
898
  }
824
899
 
900
+ /* 변경: 새 color props를 기본 계약으로 삼고, semantic preset은 style별 selector에서 보정한다. */
825
901
  .badge:where([data-style=fill]) {
826
- background-color: var(--badge-fill-bg-color);
827
- color: var(--badge-fill-label-color);
902
+ background-color: var(--badge-background-color, var(--theme-badge-fill-background-default));
903
+ color: var(--badge-text-color, var(--theme-badge-fill-text-default));
828
904
  border-color: transparent;
829
905
  }
830
906
 
831
907
  .badge:where([data-style=outlined]) {
832
- background-color: var(--color-surface-static-white, #ffffff);
908
+ background-color: var(--badge-background-color, var(--theme-badge-outlined-background-default));
909
+ color: var(--badge-text-color, var(--theme-badge-outlined-text-default));
833
910
  border-width: 1px;
834
911
  border-style: solid;
835
- border-color: var(--badge-outline-border-color);
836
- color: var(--badge-outline-label-color);
912
+ border-color: var(--badge-border-color, var(--theme-badge-outlined-border-default));
913
+ }
914
+
915
+ .badge:where([data-style=count]) {
916
+ background-color: var(--badge-background-color, var(--theme-badge-count-background-default));
917
+ color: var(--badge-text-color, var(--theme-badge-count-text-default));
918
+ border-color: transparent;
919
+ border-radius: calc(var(--badge-height) / 2);
920
+ }
921
+
922
+ .badge:where([data-style=count][data-size=xsmall]) {
923
+ border-radius: var(--theme-badge-count-radius-xsmall);
837
924
  }
838
925
 
839
926
  .badge:where([data-style=dot]) {
840
- padding: 0;
841
- border-width: 0;
842
927
  width: var(--badge-dot-size);
843
- height: var(--badge-dot-size);
844
928
  min-width: 0;
929
+ height: var(--badge-dot-size);
930
+ padding: 0;
931
+ border-width: 0;
845
932
  border-radius: var(--badge-dot-size);
846
933
  background-color: transparent;
847
934
  }
848
935
 
849
- .badge-dot {
936
+ .badge:where([data-style=dot]) .badge-dot {
850
937
  width: var(--badge-dot-size);
851
938
  height: var(--badge-dot-size);
852
- border-radius: 999px;
853
- background-color: var(--badge-dot-color);
854
939
  flex-shrink: 0;
940
+ border-radius: 999px;
941
+ background-color: var(--badge-background-color, var(--theme-badge-dot-background-default));
855
942
  }
856
943
 
857
- .badge-label {
858
- display: inline-flex;
944
+ .badge :where(.badge-label) {
945
+ display: flex;
859
946
  align-items: center;
860
947
  color: inherit;
861
- line-height: 1;
948
+ line-height: inherit;
862
949
  }
863
950
 
864
951
  .badge:where([data-style=dot]) .badge-label {
865
- font-size: 0;
866
- line-height: 0;
867
- height: 0;
868
952
  width: 0;
953
+ height: 0;
869
954
  overflow: hidden;
955
+ font-size: 0;
956
+ line-height: 0;
957
+ }
958
+
959
+ .badge:where([data-style=fill][data-preset=primary]) {
960
+ --badge-background-color: var(--color-primary-default);
961
+ --badge-text-color: var(--color-common-100);
962
+ }
963
+
964
+ .badge:where([data-style=fill][data-preset=secondary]) {
965
+ --badge-background-color: var(--color-secondary-default);
966
+ --badge-text-color: var(--color-primary-default);
967
+ }
968
+
969
+ .badge:where([data-style=fill][data-preset=tertiary]) {
970
+ --badge-background-color: var(--color-cool-gray-10);
971
+ --badge-text-color: var(--color-common-100);
972
+ }
973
+
974
+ .badge:where([data-style=fill][data-preset=gray]) {
975
+ --badge-background-color: var(--color-surface-neutral);
976
+ --badge-text-color: var(--color-label-neutral);
977
+ }
978
+
979
+ .badge:where([data-style=fill][data-preset=green]) {
980
+ --badge-background-color: var(--color-green-95);
981
+ --badge-text-color: var(--color-green-45);
982
+ }
983
+
984
+ .badge:where([data-style=fill][data-preset=yellow]) {
985
+ --badge-background-color: var(--color-yellow-95);
986
+ --badge-text-color: var(--color-yellow-45);
987
+ }
988
+
989
+ .badge:where([data-style=fill][data-preset=orange]) {
990
+ --badge-background-color: var(--color-orange-95);
991
+ --badge-text-color: var(--color-orange-55);
992
+ }
993
+
994
+ .badge:where([data-style=fill][data-preset=red]) {
995
+ --badge-background-color: var(--color-red-95);
996
+ --badge-text-color: var(--color-red-55);
870
997
  }
871
998
 
872
- /* fill intent 별 배경/라벨 컬러 정의 */
873
- .badge:where([data-style=fill][data-intent=primary]) {
874
- --badge-fill-bg-color: var(--color-primary-default, #1a6aff);
875
- --badge-fill-label-color: var(--color-common-100, #ffffff);
999
+ .badge:where([data-style=outlined][data-preset=primary]) {
1000
+ --badge-border-color: var(--color-primary-default);
1001
+ --badge-text-color: var(--color-primary-default);
876
1002
  }
877
1003
 
878
- .badge:where([data-style=fill][data-intent=secondary]) {
879
- --badge-fill-bg-color: var(--color-secondary-default, #e5eeff);
880
- --badge-fill-label-color: var(--color-primary-default, #1a6aff);
1004
+ .badge:where([data-style=outlined][data-preset=secondary]) {
1005
+ --badge-border-color: var(--color-border-standard-blue);
1006
+ --badge-text-color: var(--color-primary-strong);
881
1007
  }
882
1008
 
883
- .badge:where([data-style=fill][data-intent=tertiary]) {
884
- --badge-fill-bg-color: var(--color-cool-gray-10, #18191b);
885
- --badge-fill-label-color: var(--color-common-100, #ffffff);
1009
+ .badge:where([data-style=outlined][data-preset=tertiary]) {
1010
+ --badge-border-color: var(--color-border-heavy);
1011
+ --badge-text-color: var(--color-label-strong);
886
1012
  }
887
1013
 
888
- .badge:where([data-style=fill][data-intent=gray]) {
889
- --badge-fill-bg-color: var(--color-surface-neutral, #f2f2f2);
890
- --badge-fill-label-color: var(--color-label-neutral, #797e86);
1014
+ .badge:where([data-style=outlined][data-preset=gray]) {
1015
+ --badge-border-color: var(--color-border-assistive);
1016
+ --badge-text-color: var(--color-label-standard);
891
1017
  }
892
1018
 
893
- .badge:where([data-style=fill][data-intent=green]) {
894
- --badge-fill-bg-color: var(--color-green-95, #e9fcef);
895
- --badge-fill-label-color: var(--color-green-45, #1dc956);
1019
+ .badge:where([data-style=outlined][data-preset=green]) {
1020
+ --badge-border-color: var(--color-green-45);
1021
+ --badge-text-color: var(--color-green-45);
896
1022
  }
897
1023
 
898
- .badge:where([data-style=fill][data-intent=yellow]) {
899
- --badge-fill-bg-color: var(--color-yellow-95, #fefae7);
900
- --badge-fill-label-color: var(--color-yellow-45, #dab80b);
1024
+ .badge:where([data-style=outlined][data-preset=yellow]) {
1025
+ --badge-border-color: var(--color-yellow-60);
1026
+ --badge-text-color: var(--color-yellow-45);
901
1027
  }
902
1028
 
903
- .badge:where([data-style=fill][data-intent=orange]) {
904
- --badge-fill-bg-color: var(--color-orange-95, #ffeee5);
905
- --badge-fill-label-color: var(--color-orange-55, #ff661a);
1029
+ .badge:where([data-style=outlined][data-preset=orange]) {
1030
+ --badge-border-color: var(--color-orange-70);
1031
+ --badge-text-color: var(--color-orange-55);
906
1032
  }
907
1033
 
908
- .badge:where([data-style=fill][data-intent=red]) {
909
- --badge-fill-bg-color: var(--color-red-95, #fde8e7);
910
- --badge-fill-label-color: var(--color-red-55, #f43625);
1034
+ .badge:where([data-style=outlined][data-preset=red]) {
1035
+ --badge-border-color: var(--color-red-70);
1036
+ --badge-text-color: var(--color-red-55);
911
1037
  }
912
1038
 
913
- /* outlined intent 별 border/label 컬러 정의 */
914
- .badge:where([data-style=outlined][data-intent=primary]) {
915
- --badge-outline-border-color: var(--color-primary-default, #1a6aff);
916
- --badge-outline-label-color: var(--color-primary-default, #1a6aff);
1039
+ .badge:where([data-style=count][data-preset=primary]) {
1040
+ --badge-background-color: var(--color-primary-default);
1041
+ --badge-text-color: var(--color-common-100);
917
1042
  }
918
1043
 
919
- .badge:where([data-style=outlined][data-intent=secondary]) {
920
- --badge-outline-border-color: var(--color-border-standard-blue, #ccdeff);
921
- --badge-outline-label-color: var(--color-primary-strong, #0050e5);
1044
+ .badge:where([data-style=count][data-preset=gray]) {
1045
+ --badge-background-color: var(--color-cool-gray-90);
1046
+ --badge-text-color: var(--color-label-standard);
922
1047
  }
923
1048
 
924
- .badge:where([data-style=outlined][data-intent=tertiary]) {
925
- --badge-outline-border-color: var(--color-border-heavy, #313235);
926
- --badge-outline-label-color: var(--color-label-strong, #18191b);
1049
+ .badge:where([data-style=dot][data-preset=primary]) {
1050
+ --badge-background-color: var(--color-primary-default);
927
1051
  }
928
1052
 
929
- .badge:where([data-style=outlined][data-intent=gray]) {
930
- --badge-outline-border-color: var(--color-border-assistive, #e4e5e7);
931
- --badge-outline-label-color: var(--color-label-standard, #3d3f43);
1053
+ .badge:where([data-style=dot][data-preset=secondary]) {
1054
+ --badge-background-color: var(--color-secondary-default);
932
1055
  }
933
1056
 
934
- .badge:where([data-style=outlined][data-intent=green]) {
935
- --badge-outline-border-color: var(--color-green-45, #1dc956);
936
- --badge-outline-label-color: var(--color-green-45, #1dc956);
1057
+ .badge:where([data-style=dot][data-preset=tertiary]) {
1058
+ --badge-background-color: var(--color-cool-gray-10);
937
1059
  }
938
1060
 
939
- .badge:where([data-style=outlined][data-intent=yellow]) {
940
- --badge-outline-border-color: var(--color-yellow-60, #f5d63d);
941
- --badge-outline-label-color: var(--color-yellow-45, #dab80b);
1061
+ .badge:where([data-style=dot][data-preset=gray]) {
1062
+ --badge-background-color: var(--color-cool-gray-90);
942
1063
  }
943
1064
 
944
- .badge:where([data-style=outlined][data-intent=orange]) {
945
- --badge-outline-border-color: var(--color-orange-70, #ff9966);
946
- --badge-outline-label-color: var(--color-orange-55, #ff661a);
1065
+ .badge:where([data-style=dot][data-preset=green]) {
1066
+ --badge-background-color: var(--color-green-45);
947
1067
  }
948
1068
 
949
- .badge:where([data-style=outlined][data-intent=red]) {
950
- --badge-outline-border-color: var(--color-red-70, #f7796e);
951
- --badge-outline-label-color: var(--color-red-55, #f43625);
1069
+ .badge:where([data-style=dot][data-preset=yellow]) {
1070
+ --badge-background-color: var(--color-yellow-45);
952
1071
  }
953
1072
 
954
- /* dot tone 별 포인트 컬러 */
955
- .badge:where([data-style=dot][data-tone=primary]) {
956
- --badge-dot-color: var(--color-primary-default, #1a6aff);
1073
+ .badge:where([data-style=dot][data-preset=orange]) {
1074
+ --badge-background-color: var(--color-orange-55);
957
1075
  }
958
1076
 
959
- .badge:where([data-style=dot][data-tone=feedback]) {
960
- --badge-dot-color: var(--color-red-55, #f43625);
1077
+ .badge:where([data-style=dot][data-preset=red]) {
1078
+ --badge-background-color: var(--color-red-55);
961
1079
  }
962
1080
 
963
1081
  /* 버튼 전용 토큰은 theme root에서 한 번만 정의하며, size 기반 규칙(--button-{type}-{property}-{size})을 따른다. */
@@ -4299,52 +4417,45 @@ figure.chip {
4299
4417
  stroke: var(--select-icon-fill);
4300
4418
  }
4301
4419
 
4420
+
4421
+
4302
4422
  .tab-root {
4303
- /* Figma node 694:4619 측정값을 CSS 변수로 고정해 Storybook과 실 서비스 간 시각 편차를 줄인다. */
4304
- --tab-label-font-size: var(--font-heading-xsmall-size, 17px);
4305
- --tab-label-font-weight: var(--font-heading-xsmall-weight, 600);
4306
- --tab-label-line-height: 1.4;
4307
- --tab-label-letter-spacing: 0px;
4308
- --tab-gap: var(--spacing-gap-2, 8px);
4309
- --tab-padding-y: 10px;
4310
- --tab-padding-x: var(--spacing-padding-8, 24px);
4311
- --tab-icon-gap: 6px;
4312
- --tab-line-track-color: var(--color-border-divider, #f2f2f3);
4313
- --tab-line-track-height: 1px;
4314
- --tab-line-indicator-height: 2px;
4315
- --tab-color-active-default: #1a6aff;
4316
- --tab-color-active: var(--tab-color-active-default);
4317
- --tab-color-hover: color-mix(in srgb, var(--tab-color-active), #000 15%);
4318
- --tab-line-hover-color: var(--tab-color-hover, var(--tab-color-active));
4319
- --tab-fill-hover-bg: var(--color-bg-alternative-cool-gray, #f2f2f3);
4320
- --tab-fill-active-color: var(--color-common-100, #ffffff);
4321
- --tab-inactive-color: var(--color-label-alternative, #afb1b6);
4322
- --tab-disabled-opacity: 0.4;
4323
- --tab-height: 48px;
4423
+ --tab-height: var(--tab-height-medium);
4424
+ --tab-label-font-size: var(--tab-label-font-size-medium);
4425
+ --tab-label-font-weight: var(--tab-label-font-weight-medium);
4426
+ --tab-label-line-height: var(--tab-label-line-height-medium);
4427
+ --tab-label-letter-spacing: var(--tab-label-letter-spacing-medium);
4324
4428
  width: 100%;
4325
4429
  display: flex;
4326
4430
  flex-direction: column;
4327
- gap: var(--spacing-gap-3);
4431
+ gap: var(--tab-root-gap);
4328
4432
  }
4329
4433
 
4330
4434
  .tab-root:where([data-scale=small]) {
4331
- --tab-label-font-size: var(--font-heading-xxsmall-size, 15px);
4332
- --tab-label-font-weight: var(--font-heading-xxsmall-weight, 600);
4333
- --tab-height: 40px;
4334
- --tab-padding-x: var(--spacing-padding-4, 8px);
4435
+ --tab-height: var(--tab-height-small);
4436
+ --tab-label-font-size: var(--tab-label-font-size-small);
4437
+ --tab-label-font-weight: var(--tab-label-font-weight-small);
4438
+ --tab-label-line-height: var(--tab-label-line-height-small);
4439
+ --tab-label-letter-spacing: var(--tab-label-letter-spacing-small);
4440
+ --tab-padding-x: var(--tab-padding-x-small);
4335
4441
  }
4336
4442
 
4337
4443
  .tab-root:where([data-scale=medium]) {
4338
- --tab-label-font-size: var(--font-heading-xsmall-size, 17px);
4339
- --tab-label-font-weight: var(--font-heading-xsmall-weight, 600);
4340
- --tab-height: 48px;
4444
+ --tab-height: var(--tab-height-medium);
4445
+ --tab-label-font-size: var(--tab-label-font-size-medium);
4446
+ --tab-label-font-weight: var(--tab-label-font-weight-medium);
4447
+ --tab-label-line-height: var(--tab-label-line-height-medium);
4448
+ --tab-label-letter-spacing: var(--tab-label-letter-spacing-medium);
4449
+ --tab-padding-x: var(--spacing-padding-8);
4341
4450
  }
4342
4451
 
4343
4452
  .tab-root:where([data-scale=large]) {
4344
- --tab-label-font-size: var(--font-heading-small-size, 19px);
4345
- --tab-label-font-weight: var(--font-heading-small-weight, 600);
4346
- --tab-height: 56px;
4347
- --tab-padding-x: var(--spacing-padding-8, 24px);
4453
+ --tab-height: var(--tab-height-large);
4454
+ --tab-label-font-size: var(--tab-label-font-size-large);
4455
+ --tab-label-font-weight: var(--tab-label-font-weight-large);
4456
+ --tab-label-line-height: var(--tab-label-line-height-large);
4457
+ --tab-label-letter-spacing: var(--tab-label-letter-spacing-large);
4458
+ --tab-padding-x: var(--spacing-padding-8);
4348
4459
  }
4349
4460
 
4350
4461
  .tab-list {
@@ -4379,7 +4490,7 @@ figure.chip {
4379
4490
  }
4380
4491
 
4381
4492
  .tab-trigger:where(:focus-visible) {
4382
- outline: 2px solid var(--color-focus-ring, var(--color-primary-default));
4493
+ outline: 2px solid var(--color-primary-default);
4383
4494
  outline-offset: 2px;
4384
4495
  }
4385
4496
 
@@ -4415,7 +4526,7 @@ figure.chip {
4415
4526
  content: "";
4416
4527
  position: absolute;
4417
4528
  inset: auto 0 0;
4418
- height: var(--tab-line-track-height, 1px);
4529
+ height: var(--tab-line-track-height);
4419
4530
  background: var(--tab-line-track-color);
4420
4531
  z-index: 0;
4421
4532
  }
@@ -4429,8 +4540,9 @@ figure.chip {
4429
4540
  position: absolute;
4430
4541
  left: 0;
4431
4542
  right: 0;
4432
- bottom: -1px;
4433
- height: var(--tab-line-indicator-height, 2px);
4543
+ /* 변경: scroll container에서 vertical overflow clip 리스크를 피하기 위해 indicator를 내부 바닥에 붙인다. */
4544
+ bottom: 0;
4545
+ height: var(--tab-line-indicator-height);
4434
4546
  background: transparent;
4435
4547
  transform: scaleX(0);
4436
4548
  transform-origin: center;
@@ -4448,7 +4560,7 @@ figure.chip {
4448
4560
  }
4449
4561
 
4450
4562
  .tab-trigger:where([data-variant=line]):where(:not([data-state=active])):hover .tab-trigger-label {
4451
- color: var(--tab-line-hover-color);
4563
+ color: var(--tab-color-hover);
4452
4564
  }
4453
4565
 
4454
4566
  .tab-list:where([data-variant=fill]) {
@@ -4468,8 +4580,8 @@ figure.chip {
4468
4580
  }
4469
4581
 
4470
4582
  .tab-trigger:where([data-variant=fill]) {
4471
- border-radius: 12px;
4472
4583
  min-width: 0;
4584
+ border-radius: 12px;
4473
4585
  }
4474
4586
 
4475
4587
  .tab-trigger:where([data-variant=fill][data-state=active]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniai-fe/uds-primitives",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "description": "UNIAI Design System; Primitives Components Package",
5
5
  "type": "module",
6
6
  "private": false,
@@ -1,12 +1,10 @@
1
1
  /**
2
2
  * Badge; status/info label 렌더링 카테고리 배럴
3
3
  * @desc
4
- * - `Badge`: size/style/intent/tone 축을 렌더링하는 단일 leaf 컴포넌트다.
4
+ * - `Badge`: size/style 색상 props를 렌더링하는 단일 leaf 컴포넌트다.
5
5
  * - `BadgeProps`: badge public props 계약이다.
6
6
  */
7
7
  import "./index.scss";
8
8
 
9
9
  export * from "./markup";
10
- export * from "./hooks";
11
10
  export type * from "./types";
12
- export * from "./utils";
@@ -1,22 +1,24 @@
1
+ import clsx from "clsx";
1
2
  import { forwardRef } from "react";
3
+ import type { CSSProperties } from "react";
2
4
  import type { BadgeProps } from "../types";
3
- import { composeBadgeClassName } from "../utils";
4
5
  import { Slot } from "../../slot";
5
6
 
6
7
  /**
7
8
  * Badge; status/info label 렌더링 leaf 컴포넌트
8
9
  * @component
9
10
  * @param {BadgeProps} props
10
- * @param {"xsmall" | "small"} [props.size="xsmall"] 토큰 size 축이다.
11
- * @param {"fill" | "outlined" | "dot"} [props.style="fill"] 시각 스타일 축이다.
12
- * @param {"primary" | "secondary" | "tertiary" | "gray" | "green" | "yellow" | "orange" | "red"} [props.intent="primary"]
13
- * fill/outlined 스타일에서 사용되는 intent 축이다.
14
- * @param {"primary" | "feedback"} [props.tone="primary"] dot 스타일 전용 tone 축이다.
11
+ * @param {"xsmall" | "small" | "medium"} [props.size="xsmall"] 토큰 size 축이다.
12
+ * @param {"fill" | "outlined" | "dot" | "count"} [props.style="fill"] 시각 스타일 축이다.
13
+ * @param {"primary" | "secondary" | "tertiary" | "gray" | "green" | "yellow" | "orange" | "red"} [props.preset] style에 대응하는 semantic 색상 preset이다.
14
+ * @param {string} [props.textColor] 라벨 텍스트 색상 CSS 값 또는 토큰 참조 문자열이다.
15
+ * @param {string} [props.backgroundColor] 배경 또는 dot 색상 CSS 또는 토큰 참조 문자열이다.
16
+ * @param {string} [props.borderColor] 외곽선 색상 CSS 값 또는 토큰 참조 문자열이다.
15
17
  * @param {React.ReactNode} [props.children] 라벨 텍스트다. dot 스타일에서 생략하면 점만 렌더링한다.
16
18
  * @param {string} [props.className] figure root className override다.
17
19
  * @param {React.CSSProperties} [props.inlineStyle] figure root inline style이다.
18
20
  * @example
19
- * <Badge style="fill" intent="primary">승인됨</Badge>
21
+ * <Badge style="fill" backgroundColor="var(--color-primary-default)" textColor="var(--color-common-100)">승인됨</Badge>
20
22
  */
21
23
  const Badge = forwardRef<HTMLElementTagNameMap["figure"], BadgeProps>(
22
24
  (
@@ -24,33 +26,42 @@ const Badge = forwardRef<HTMLElementTagNameMap["figure"], BadgeProps>(
24
26
  children,
25
27
  size = "xsmall",
26
28
  style = "fill",
27
- intent = "primary",
28
- tone = "primary",
29
+ preset,
30
+ textColor,
31
+ backgroundColor,
32
+ borderColor,
29
33
  className,
30
34
  inlineStyle,
31
35
  ...restProps
32
36
  },
33
37
  ref,
34
38
  ) => {
35
- const combinedClassName = composeBadgeClassName({ size, style, className });
39
+ // 변경: size/style 상태는 data-*로만 표현하고 root className leaf override만 남긴다.
40
+ const combinedClassName = clsx("badge", className);
41
+ // 변경: color props는 preset selector보다 우선하도록 CSS variable을 직접 주입한다.
42
+ const colorStyle = {
43
+ ...inlineStyle,
44
+ ...(textColor ? { "--badge-text-color": textColor } : null),
45
+ ...(backgroundColor
46
+ ? { "--badge-background-color": backgroundColor }
47
+ : null),
48
+ ...(borderColor ? { "--badge-border-color": borderColor } : null),
49
+ } as CSSProperties;
36
50
  // dot 스타일은 실제 원형 포인트 요소를 별도로 렌더링한다.
37
51
  const renderDot =
38
52
  style === "dot" ? (
39
53
  <span className="badge-dot" aria-hidden="true" />
40
54
  ) : null;
41
- const hasLabel = Boolean(children);
42
55
 
43
56
  return (
44
57
  <figure
45
58
  {...restProps}
46
59
  ref={ref}
47
60
  className={combinedClassName}
48
- style={inlineStyle}
61
+ style={colorStyle}
49
62
  data-size={size}
50
63
  data-style={style}
51
- data-intent={style === "dot" ? undefined : intent}
52
- data-tone={style === "dot" ? tone : undefined}
53
- data-has-label={hasLabel ? "true" : undefined}
64
+ data-preset={preset}
54
65
  >
55
66
  {renderDot}
56
67
  {/* 변경: badge 라벨 텍스트 래핑 규칙을 Slot.Text로 통일한다. */}