@uniai-fe/uds-primitives 0.4.7 → 0.5.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.
Files changed (36) hide show
  1. package/README.md +3 -0
  2. package/dist/styles.css +325 -138
  3. package/package.json +1 -1
  4. package/src/components/badge/index.tsx +1 -3
  5. package/src/components/badge/markup/Badge.tsx +26 -15
  6. package/src/components/badge/styles/badge.scss +244 -0
  7. package/src/components/badge/styles/index.scss +2 -187
  8. package/src/components/badge/styles/variables.scss +41 -0
  9. package/src/components/badge/types/index.ts +3 -77
  10. package/src/components/badge/types/options.ts +25 -0
  11. package/src/components/badge/types/props.ts +53 -0
  12. package/src/components/switch/index.scss +1 -0
  13. package/src/components/switch/index.tsx +10 -0
  14. package/src/components/switch/markup/Switch.tsx +76 -0
  15. package/src/components/switch/markup/index.ts +1 -0
  16. package/src/components/switch/styles/index.scss +2 -0
  17. package/src/components/switch/styles/switch.scss +63 -0
  18. package/src/components/switch/styles/variables.scss +21 -0
  19. package/src/components/switch/types/index.ts +1 -0
  20. package/src/components/switch/types/switch.ts +46 -0
  21. package/src/components/tab/index.tsx +1 -2
  22. package/src/components/tab/markup/Label.tsx +22 -0
  23. package/src/components/tab/markup/TabList.tsx +27 -29
  24. package/src/components/tab/markup/TabRoot.tsx +16 -71
  25. package/src/components/tab/markup/TabTrigger.tsx +2 -15
  26. package/src/components/tab/styles/index.scss +2 -198
  27. package/src/components/tab/styles/tab.scss +190 -0
  28. package/src/components/tab/styles/variables.scss +39 -0
  29. package/src/components/tab/types/index.ts +29 -6
  30. package/src/components/tab/utils/tab-context.ts +1 -6
  31. package/src/index.scss +1 -0
  32. package/src/index.tsx +1 -0
  33. package/src/components/badge/hooks/index.ts +0 -4
  34. package/src/components/badge/img/.gitkeep +0 -0
  35. package/src/components/badge/utils/index.ts +0 -21
  36. package/src/components/tab/hooks/index.ts +0 -4
package/README.md CHANGED
@@ -153,6 +153,9 @@ export default function Page() {
153
153
  - `Slot.Text`
154
154
  - `SlotComponentProps`
155
155
  - `SlotTextProps`
156
+ - `Switch`
157
+ - `SwitchProps`
158
+ - `SwitchSize`
156
159
  - `TabRoot`
157
160
  - `TabList`
158
161
  - `TabTrigger`
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,56 @@
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
+ --switch-track-width-small: 48px;
695
+ --switch-track-height-small: 24px;
696
+ --switch-track-padding-small: 3px;
697
+ --switch-handle-size-small: 18px;
698
+ --switch-track-width-medium: 68px;
699
+ --switch-track-height-medium: 34px;
700
+ --switch-track-padding-medium: 2px;
701
+ --switch-handle-size-medium: 30px;
702
+ --switch-track-background-unchecked: var(--color-surface-strong);
703
+ --switch-track-background-checked: var(--color-primary-standard);
704
+ --switch-thumb-background: var(--color-surface-static-white);
705
+ --switch-thumb-shadow-unchecked:
706
+ 0px 2px 8px rgba(0, 0, 0, 0.04), 0px 0px 4px rgba(0, 0, 0, 0.08);
707
+ --switch-thumb-shadow-checked:
708
+ 0px 2px 8px rgba(0, 0, 0, 0.08), 0px 0px 4px rgba(0, 0, 0, 0.12);
709
+ --switch-focus-ring: var(--color-primary-focus);
710
+ --switch-disabled-opacity: 0.4;
711
+ --tab-height-small: 40px;
712
+ --tab-height-medium: 48px;
713
+ --tab-height-large: 56px;
714
+ /* 변경: Figma node 1176:834/781/739 기준으로 tab label typography를 exact spec으로 다시 고정한다. */
715
+ --tab-label-font-size-small: var(--font-label-medium-size);
716
+ --tab-label-font-weight-small: 700;
717
+ --tab-label-line-height-small: 1.4;
718
+ --tab-label-letter-spacing-small: 0px;
719
+ --tab-label-font-size-medium: var(--font-label-large-size);
720
+ --tab-label-font-weight-medium: 700;
721
+ --tab-label-line-height-medium: 1.4;
722
+ --tab-label-letter-spacing-medium: 0px;
723
+ --tab-label-font-size-large: var(--font-heading-small-size);
724
+ --tab-label-font-weight-large: 700;
725
+ --tab-label-line-height-large: 1.4;
726
+ --tab-label-letter-spacing-large: 0px;
727
+ --tab-gap: var(--spacing-gap-2);
728
+ --tab-root-gap: var(--spacing-gap-3);
729
+ --tab-padding-y: 10px;
730
+ --tab-padding-x: var(--spacing-padding-8);
731
+ --tab-padding-x-small: var(--spacing-padding-4);
732
+ --tab-icon-gap: 6px;
733
+ /* 변경: line track은 foundation에 존재하는 assistive border token(#f2f2f3)을 사용한다. */
734
+ --tab-line-track-color: var(--color-border-assistive);
735
+ --tab-line-track-height: 1px;
736
+ --tab-line-indicator-height: 2px;
737
+ --tab-color-active-default: var(--color-primary-default);
738
+ --tab-color-active: var(--tab-color-active-default);
739
+ --tab-color-hover: color-mix(in srgb, var(--tab-color-active), #000 15%);
740
+ --tab-fill-hover-bg: var(--color-bg-alternative-cool-gray);
741
+ --tab-fill-active-color: var(--color-common-100);
742
+ --tab-inactive-color: var(--color-label-alternative);
743
+ --tab-disabled-opacity: 0.4;
667
744
  --table-border-color: var(--color-border-standard-cool-gray);
668
745
  --table-line-head-background-color: var(--color-surface-static-cool-gray);
669
746
  --table-grid-head-background-color: var(
@@ -785,179 +862,237 @@
785
862
  height: 100%;
786
863
  }
787
864
 
865
+ /* Badge 기본 토큰 래핑 */
788
866
 
789
867
 
790
868
  .badge {
791
869
  --badge-height: var(--theme-badge-height-xsmall);
792
870
  --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);
871
+ --badge-radius: var(--theme-badge-radius-xsmall);
872
+ --badge-font-size: var(--theme-badge-font-size-xsmall);
873
+ --badge-font-weight: var(--theme-badge-font-weight-xsmall);
874
+ --badge-line-height: var(--theme-badge-line-height-xsmall);
875
+ --badge-letter-spacing: var(--theme-badge-letter-spacing-xsmall);
799
876
  --badge-dot-size: var(--theme-badge-dot-size);
800
877
  display: flex;
801
878
  align-items: center;
802
879
  justify-content: center;
803
- gap: var(--badge-gap);
880
+ gap: var(--theme-badge-gap);
881
+ width: fit-content;
804
882
  height: var(--badge-height);
883
+ margin: 0;
805
884
  padding-inline: var(--badge-padding-inline);
806
885
  padding-block: 0;
807
- border-radius: var(--theme-badge-radius);
808
886
  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
887
  box-sizing: border-box;
816
- margin: 0;
817
- width: fit-content;
888
+ border-radius: var(--badge-radius);
889
+ white-space: nowrap;
890
+ font-family: var(--theme-badge-font-family);
891
+ font-size: var(--badge-font-size);
892
+ font-weight: var(--badge-font-weight);
893
+ line-height: var(--badge-line-height);
894
+ letter-spacing: var(--badge-letter-spacing);
818
895
  }
819
896
 
820
897
  .badge:where([data-size=small]) {
821
898
  --badge-height: var(--theme-badge-height-small);
822
899
  --badge-padding-inline: var(--theme-badge-padding-inline-small);
900
+ --badge-radius: var(--theme-badge-radius-small);
901
+ --badge-font-size: var(--theme-badge-font-size-small);
902
+ --badge-font-weight: var(--theme-badge-font-weight-small);
903
+ --badge-line-height: var(--theme-badge-line-height-small);
904
+ --badge-letter-spacing: var(--theme-badge-letter-spacing-small);
905
+ }
906
+
907
+ .badge:where([data-size=medium]) {
908
+ --badge-height: var(--theme-badge-height-medium);
909
+ --badge-padding-inline: var(--theme-badge-padding-inline-medium);
910
+ --badge-radius: var(--theme-badge-radius-medium);
911
+ --badge-font-size: var(--theme-badge-font-size-medium);
912
+ --badge-font-weight: var(--theme-badge-font-weight-medium);
913
+ --badge-line-height: var(--theme-badge-line-height-medium);
914
+ --badge-letter-spacing: var(--theme-badge-letter-spacing-medium);
823
915
  }
824
916
 
917
+ /* 변경: 새 color props를 기본 계약으로 삼고, semantic preset은 style별 selector에서 보정한다. */
825
918
  .badge:where([data-style=fill]) {
826
- background-color: var(--badge-fill-bg-color);
827
- color: var(--badge-fill-label-color);
919
+ background-color: var(--badge-background-color, var(--theme-badge-fill-background-default));
920
+ color: var(--badge-text-color, var(--theme-badge-fill-text-default));
828
921
  border-color: transparent;
829
922
  }
830
923
 
831
924
  .badge:where([data-style=outlined]) {
832
- background-color: var(--color-surface-static-white, #ffffff);
925
+ background-color: var(--badge-background-color, var(--theme-badge-outlined-background-default));
926
+ color: var(--badge-text-color, var(--theme-badge-outlined-text-default));
833
927
  border-width: 1px;
834
928
  border-style: solid;
835
- border-color: var(--badge-outline-border-color);
836
- color: var(--badge-outline-label-color);
929
+ border-color: var(--badge-border-color, var(--theme-badge-outlined-border-default));
930
+ }
931
+
932
+ .badge:where([data-style=count]) {
933
+ background-color: var(--badge-background-color, var(--theme-badge-count-background-default));
934
+ color: var(--badge-text-color, var(--theme-badge-count-text-default));
935
+ border-color: transparent;
936
+ border-radius: calc(var(--badge-height) / 2);
937
+ }
938
+
939
+ .badge:where([data-style=count][data-size=xsmall]) {
940
+ border-radius: var(--theme-badge-count-radius-xsmall);
837
941
  }
838
942
 
839
943
  .badge:where([data-style=dot]) {
840
- padding: 0;
841
- border-width: 0;
842
944
  width: var(--badge-dot-size);
843
- height: var(--badge-dot-size);
844
945
  min-width: 0;
946
+ height: var(--badge-dot-size);
947
+ padding: 0;
948
+ border-width: 0;
845
949
  border-radius: var(--badge-dot-size);
846
950
  background-color: transparent;
847
951
  }
848
952
 
849
- .badge-dot {
953
+ .badge:where([data-style=dot]) .badge-dot {
850
954
  width: var(--badge-dot-size);
851
955
  height: var(--badge-dot-size);
852
- border-radius: 999px;
853
- background-color: var(--badge-dot-color);
854
956
  flex-shrink: 0;
957
+ border-radius: 999px;
958
+ background-color: var(--badge-background-color, var(--theme-badge-dot-background-default));
855
959
  }
856
960
 
857
- .badge-label {
858
- display: inline-flex;
961
+ .badge :where(.badge-label) {
962
+ display: flex;
859
963
  align-items: center;
860
964
  color: inherit;
861
- line-height: 1;
965
+ line-height: inherit;
862
966
  }
863
967
 
864
968
  .badge:where([data-style=dot]) .badge-label {
865
- font-size: 0;
866
- line-height: 0;
867
- height: 0;
868
969
  width: 0;
970
+ height: 0;
869
971
  overflow: hidden;
972
+ font-size: 0;
973
+ line-height: 0;
974
+ }
975
+
976
+ .badge:where([data-style=fill][data-preset=primary]) {
977
+ --badge-background-color: var(--color-primary-default);
978
+ --badge-text-color: var(--color-common-100);
979
+ }
980
+
981
+ .badge:where([data-style=fill][data-preset=secondary]) {
982
+ --badge-background-color: var(--color-secondary-default);
983
+ --badge-text-color: var(--color-primary-default);
984
+ }
985
+
986
+ .badge:where([data-style=fill][data-preset=tertiary]) {
987
+ --badge-background-color: var(--color-cool-gray-10);
988
+ --badge-text-color: var(--color-common-100);
989
+ }
990
+
991
+ .badge:where([data-style=fill][data-preset=gray]) {
992
+ --badge-background-color: var(--color-surface-neutral);
993
+ --badge-text-color: var(--color-label-neutral);
994
+ }
995
+
996
+ .badge:where([data-style=fill][data-preset=green]) {
997
+ --badge-background-color: var(--color-green-95);
998
+ --badge-text-color: var(--color-green-45);
999
+ }
1000
+
1001
+ .badge:where([data-style=fill][data-preset=yellow]) {
1002
+ --badge-background-color: var(--color-yellow-95);
1003
+ --badge-text-color: var(--color-yellow-45);
1004
+ }
1005
+
1006
+ .badge:where([data-style=fill][data-preset=orange]) {
1007
+ --badge-background-color: var(--color-orange-95);
1008
+ --badge-text-color: var(--color-orange-55);
870
1009
  }
871
1010
 
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);
1011
+ .badge:where([data-style=fill][data-preset=red]) {
1012
+ --badge-background-color: var(--color-red-95);
1013
+ --badge-text-color: var(--color-red-55);
876
1014
  }
877
1015
 
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);
1016
+ .badge:where([data-style=outlined][data-preset=primary]) {
1017
+ --badge-border-color: var(--color-primary-default);
1018
+ --badge-text-color: var(--color-primary-default);
881
1019
  }
882
1020
 
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);
1021
+ .badge:where([data-style=outlined][data-preset=secondary]) {
1022
+ --badge-border-color: var(--color-border-standard-blue);
1023
+ --badge-text-color: var(--color-primary-strong);
886
1024
  }
887
1025
 
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);
1026
+ .badge:where([data-style=outlined][data-preset=tertiary]) {
1027
+ --badge-border-color: var(--color-border-heavy);
1028
+ --badge-text-color: var(--color-label-strong);
891
1029
  }
892
1030
 
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);
1031
+ .badge:where([data-style=outlined][data-preset=gray]) {
1032
+ --badge-border-color: var(--color-border-assistive);
1033
+ --badge-text-color: var(--color-label-standard);
896
1034
  }
897
1035
 
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);
1036
+ .badge:where([data-style=outlined][data-preset=green]) {
1037
+ --badge-border-color: var(--color-green-45);
1038
+ --badge-text-color: var(--color-green-45);
901
1039
  }
902
1040
 
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);
1041
+ .badge:where([data-style=outlined][data-preset=yellow]) {
1042
+ --badge-border-color: var(--color-yellow-60);
1043
+ --badge-text-color: var(--color-yellow-45);
906
1044
  }
907
1045
 
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);
1046
+ .badge:where([data-style=outlined][data-preset=orange]) {
1047
+ --badge-border-color: var(--color-orange-70);
1048
+ --badge-text-color: var(--color-orange-55);
911
1049
  }
912
1050
 
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);
1051
+ .badge:where([data-style=outlined][data-preset=red]) {
1052
+ --badge-border-color: var(--color-red-70);
1053
+ --badge-text-color: var(--color-red-55);
917
1054
  }
918
1055
 
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);
1056
+ .badge:where([data-style=count][data-preset=primary]) {
1057
+ --badge-background-color: var(--color-primary-default);
1058
+ --badge-text-color: var(--color-common-100);
922
1059
  }
923
1060
 
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);
1061
+ .badge:where([data-style=count][data-preset=gray]) {
1062
+ --badge-background-color: var(--color-cool-gray-90);
1063
+ --badge-text-color: var(--color-label-standard);
927
1064
  }
928
1065
 
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);
1066
+ .badge:where([data-style=dot][data-preset=primary]) {
1067
+ --badge-background-color: var(--color-primary-default);
932
1068
  }
933
1069
 
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);
1070
+ .badge:where([data-style=dot][data-preset=secondary]) {
1071
+ --badge-background-color: var(--color-secondary-default);
937
1072
  }
938
1073
 
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);
1074
+ .badge:where([data-style=dot][data-preset=tertiary]) {
1075
+ --badge-background-color: var(--color-cool-gray-10);
942
1076
  }
943
1077
 
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);
1078
+ .badge:where([data-style=dot][data-preset=gray]) {
1079
+ --badge-background-color: var(--color-cool-gray-90);
947
1080
  }
948
1081
 
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);
1082
+ .badge:where([data-style=dot][data-preset=green]) {
1083
+ --badge-background-color: var(--color-green-45);
952
1084
  }
953
1085
 
954
- /* dot tone 별 포인트 컬러 */
955
- .badge:where([data-style=dot][data-tone=primary]) {
956
- --badge-dot-color: var(--color-primary-default, #1a6aff);
1086
+ .badge:where([data-style=dot][data-preset=yellow]) {
1087
+ --badge-background-color: var(--color-yellow-45);
957
1088
  }
958
1089
 
959
- .badge:where([data-style=dot][data-tone=feedback]) {
960
- --badge-dot-color: var(--color-red-55, #f43625);
1090
+ .badge:where([data-style=dot][data-preset=orange]) {
1091
+ --badge-background-color: var(--color-orange-55);
1092
+ }
1093
+
1094
+ .badge:where([data-style=dot][data-preset=red]) {
1095
+ --badge-background-color: var(--color-red-55);
961
1096
  }
962
1097
 
963
1098
  /* 버튼 전용 토큰은 theme root에서 한 번만 정의하며, size 기반 규칙(--button-{type}-{property}-{size})을 따른다. */
@@ -4299,52 +4434,103 @@ figure.chip {
4299
4434
  stroke: var(--select-icon-fill);
4300
4435
  }
4301
4436
 
4437
+
4438
+
4439
+ .switch {
4440
+ --switch-track-width: var(--switch-track-width-small);
4441
+ --switch-track-height: var(--switch-track-height-small);
4442
+ --switch-track-padding: var(--switch-track-padding-small);
4443
+ --switch-handle-size: var(--switch-handle-size-small);
4444
+ display: flex;
4445
+ align-items: center;
4446
+ justify-content: flex-start;
4447
+ width: var(--switch-track-width);
4448
+ min-width: var(--switch-track-width);
4449
+ height: var(--switch-track-height);
4450
+ padding: var(--switch-track-padding);
4451
+ border: none;
4452
+ border-radius: 999px;
4453
+ background-color: var(--switch-track-background-unchecked);
4454
+ cursor: pointer;
4455
+ transition: background-color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
4456
+ }
4457
+
4458
+ .switch:where([data-size=medium]) {
4459
+ --switch-track-width: var(--switch-track-width-medium);
4460
+ --switch-track-height: var(--switch-track-height-medium);
4461
+ --switch-track-padding: var(--switch-track-padding-medium);
4462
+ --switch-handle-size: var(--switch-handle-size-medium);
4463
+ }
4464
+
4465
+ .switch:where([data-state=checked]) {
4466
+ background-color: var(--switch-track-background-checked);
4467
+ }
4468
+
4469
+ .switch:where(:focus-visible) {
4470
+ box-shadow: 0 0 0 2px var(--switch-focus-ring);
4471
+ }
4472
+
4473
+ .switch:where(:disabled) {
4474
+ cursor: not-allowed;
4475
+ opacity: var(--switch-disabled-opacity);
4476
+ }
4477
+
4478
+ .switch-handle {
4479
+ display: flex;
4480
+ width: var(--switch-handle-size);
4481
+ min-width: var(--switch-handle-size);
4482
+ height: var(--switch-handle-size);
4483
+ border-radius: 999px;
4484
+ background-color: var(--switch-thumb-background);
4485
+ box-shadow: var(--switch-thumb-shadow-unchecked);
4486
+ transition: transform 0.2s ease;
4487
+ }
4488
+
4489
+ .switch:where([data-state=checked]) .switch-handle {
4490
+ /* 변경: handle 이동 거리는 frame width - handle size - 양쪽 padding 합으로 고정한다. */
4491
+ box-shadow: var(--switch-thumb-shadow-checked);
4492
+ transform: translateX(calc(var(--switch-track-width) - var(--switch-handle-size) - var(--switch-track-padding) * 2));
4493
+ }
4494
+
4495
+
4496
+
4302
4497
  .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;
4498
+ --tab-height: var(--tab-height-medium);
4499
+ --tab-label-font-size: var(--tab-label-font-size-medium);
4500
+ --tab-label-font-weight: var(--tab-label-font-weight-medium);
4501
+ --tab-label-line-height: var(--tab-label-line-height-medium);
4502
+ --tab-label-letter-spacing: var(--tab-label-letter-spacing-medium);
4324
4503
  width: 100%;
4325
4504
  display: flex;
4326
4505
  flex-direction: column;
4327
- gap: var(--spacing-gap-3);
4506
+ gap: var(--tab-root-gap);
4328
4507
  }
4329
4508
 
4330
4509
  .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);
4510
+ --tab-height: var(--tab-height-small);
4511
+ --tab-label-font-size: var(--tab-label-font-size-small);
4512
+ --tab-label-font-weight: var(--tab-label-font-weight-small);
4513
+ --tab-label-line-height: var(--tab-label-line-height-small);
4514
+ --tab-label-letter-spacing: var(--tab-label-letter-spacing-small);
4515
+ --tab-padding-x: var(--tab-padding-x-small);
4335
4516
  }
4336
4517
 
4337
4518
  .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;
4519
+ --tab-height: var(--tab-height-medium);
4520
+ --tab-label-font-size: var(--tab-label-font-size-medium);
4521
+ --tab-label-font-weight: var(--tab-label-font-weight-medium);
4522
+ --tab-label-line-height: var(--tab-label-line-height-medium);
4523
+ --tab-label-letter-spacing: var(--tab-label-letter-spacing-medium);
4524
+ --tab-padding-x: var(--spacing-padding-8);
4341
4525
  }
4342
4526
 
4343
4527
  .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);
4528
+ --tab-height: var(--tab-height-large);
4529
+ --tab-label-font-size: var(--tab-label-font-size-large);
4530
+ --tab-label-font-weight: var(--tab-label-font-weight-large);
4531
+ --tab-label-line-height: var(--tab-label-line-height-large);
4532
+ --tab-label-letter-spacing: var(--tab-label-letter-spacing-large);
4533
+ --tab-padding-x: var(--spacing-padding-8);
4348
4534
  }
4349
4535
 
4350
4536
  .tab-list {
@@ -4379,7 +4565,7 @@ figure.chip {
4379
4565
  }
4380
4566
 
4381
4567
  .tab-trigger:where(:focus-visible) {
4382
- outline: 2px solid var(--color-focus-ring, var(--color-primary-default));
4568
+ outline: 2px solid var(--color-primary-default);
4383
4569
  outline-offset: 2px;
4384
4570
  }
4385
4571
 
@@ -4415,7 +4601,7 @@ figure.chip {
4415
4601
  content: "";
4416
4602
  position: absolute;
4417
4603
  inset: auto 0 0;
4418
- height: var(--tab-line-track-height, 1px);
4604
+ height: var(--tab-line-track-height);
4419
4605
  background: var(--tab-line-track-color);
4420
4606
  z-index: 0;
4421
4607
  }
@@ -4429,8 +4615,9 @@ figure.chip {
4429
4615
  position: absolute;
4430
4616
  left: 0;
4431
4617
  right: 0;
4432
- bottom: -1px;
4433
- height: var(--tab-line-indicator-height, 2px);
4618
+ /* 변경: scroll container에서 vertical overflow clip 리스크를 피하기 위해 indicator를 내부 바닥에 붙인다. */
4619
+ bottom: 0;
4620
+ height: var(--tab-line-indicator-height);
4434
4621
  background: transparent;
4435
4622
  transform: scaleX(0);
4436
4623
  transform-origin: center;
@@ -4448,7 +4635,7 @@ figure.chip {
4448
4635
  }
4449
4636
 
4450
4637
  .tab-trigger:where([data-variant=line]):where(:not([data-state=active])):hover .tab-trigger-label {
4451
- color: var(--tab-line-hover-color);
4638
+ color: var(--tab-color-hover);
4452
4639
  }
4453
4640
 
4454
4641
  .tab-list:where([data-variant=fill]) {
@@ -4468,8 +4655,8 @@ figure.chip {
4468
4655
  }
4469
4656
 
4470
4657
  .tab-trigger:where([data-variant=fill]) {
4471
- border-radius: 12px;
4472
4658
  min-width: 0;
4659
+ border-radius: 12px;
4473
4660
  }
4474
4661
 
4475
4662
  .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.5.0",
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";