@bigtablet/design-system 2.3.0 → 2.4.1

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/index.css CHANGED
@@ -625,7 +625,7 @@
625
625
  cursor: not-allowed;
626
626
  }
627
627
 
628
- /* src/ui/select/style.scss */
628
+ /* src/ui/dropdown/style.scss */
629
629
  @keyframes skeleton_loading {
630
630
  0% {
631
631
  background-position: 100% 0;
@@ -634,164 +634,125 @@
634
634
  background-position: 0 0;
635
635
  }
636
636
  }
637
- .select {
637
+ .dropdown {
638
638
  position: relative;
639
639
  display: inline-flex;
640
640
  flex-direction: column;
641
- width: 100%;
642
641
  font-family: "Pretendard", sans-serif;
643
642
  }
644
- .select_fieldset {
645
- padding: 0;
646
- margin: 0;
647
- min-inline-size: 0;
648
- border-radius: 12px;
649
- background-color: #FFFFFF;
650
- transition: border-color 0.2s ease-in-out, background-color 0.2s ease-in-out;
651
- }
652
- .select_variant_outline {
653
- border: 1px solid #E5E5E5;
654
- }
655
- .select_variant_outline:hover:not(.is_disabled) {
656
- border-color: #B3B3B3;
657
- }
658
- .select_variant_outline.is_open {
659
- border-color: #121212;
643
+ .dropdown_size_sm .dropdown_fieldset {
644
+ min-height: 40px;
660
645
  }
661
- .select_variant_filled {
662
- background: #F4F4F4;
663
- border: 1px solid transparent;
646
+ .dropdown_size_md .dropdown_fieldset,
647
+ .dropdown_size_lg .dropdown_fieldset {
648
+ min-height: 56px;
664
649
  }
665
- .select_variant_filled:hover:not(.is_disabled) {
666
- background: rgb(251.7, 251.7, 251.7);
650
+ .dropdown_size_sm .dropdown_control {
651
+ padding: 8px 16px;
667
652
  }
668
- .select_variant_filled.is_open {
669
- background: #FFFFFF;
670
- border-color: #121212;
653
+ .dropdown_size_sm .dropdown_value,
654
+ .dropdown_size_sm .dropdown_placeholder {
655
+ font-size: 12px;
656
+ font-weight: 400;
657
+ line-height: 16px;
658
+ letter-spacing: 0px;
671
659
  }
672
- .select_variant_ghost {
673
- background: transparent;
674
- border: 1px solid transparent;
660
+ .dropdown_fieldset {
661
+ position: relative;
662
+ border: 1px solid #E5E5E5;
663
+ border-radius: 12px;
664
+ background-color: #FFFFFF;
665
+ transition: border-color 0.2s ease-in-out, background-color 0.2s ease-in-out;
675
666
  }
676
- .select_variant_ghost:hover:not(.is_disabled) {
677
- background: rgba(0, 0, 0, 0.05);
667
+ .dropdown_fieldset:hover:not(.is_open):not(.is_disabled) {
668
+ border-color: #B3B3B3;
678
669
  }
679
- .select_variant_ghost.is_open {
680
- background: #FFFFFF;
670
+ .dropdown_fieldset.is_open {
681
671
  border-color: #121212;
682
672
  }
683
- .select_fieldset.is_disabled {
673
+ .dropdown_fieldset.is_disabled {
684
674
  background-color: #F4F4F4;
675
+ border-color: rgba(26, 26, 26, 0.12);
685
676
  }
686
- .select_inner {
687
- display: flex;
688
- align-items: stretch;
689
- padding: 4px 0;
690
- }
691
- .select_size_sm .select_inner {
692
- min-height: 40px;
693
- }
694
- .select_size_md .select_inner {
695
- min-height: 52px;
696
- }
697
- .select_size_lg .select_inner {
698
- min-height: 52px;
699
- }
700
- .select_label {
701
- margin-inline-start: 12px;
677
+ .dropdown_label {
678
+ position: absolute;
679
+ top: -8px;
680
+ left: 12px;
702
681
  padding: 0 4px;
703
- color: #121212;
704
- transition: color 0.2s ease-in-out;
705
- }
706
- .select_label > label {
707
- display: block;
708
- font-family: "Pretendard", sans-serif;
682
+ background: var(--dropdown-surface, #FFFFFF);
709
683
  font-size: 12px;
710
684
  font-weight: 400;
711
685
  line-height: 16px;
686
+ letter-spacing: 0px;
712
687
  letter-spacing: 0.32px;
713
- color: inherit;
688
+ color: #121212;
689
+ white-space: nowrap;
714
690
  pointer-events: none;
715
- cursor: default;
691
+ opacity: 0;
692
+ transition: opacity 0.2s ease-in-out, color 0.2s ease-in-out;
693
+ }
694
+ .dropdown_label.is_visible {
695
+ opacity: 1;
716
696
  }
717
- .select_fieldset.is_disabled .select_label {
697
+ .dropdown_fieldset.is_disabled .dropdown_label {
718
698
  color: rgba(26, 26, 26, 0.38);
719
699
  }
720
- .select_control {
721
- flex: 1;
700
+ .dropdown_control {
701
+ width: 100%;
722
702
  display: inline-flex;
723
703
  align-items: center;
724
- justify-content: space-between;
725
- gap: 8px;
704
+ gap: 4px;
705
+ padding: 12px 16px;
726
706
  cursor: pointer;
727
707
  background: transparent;
728
708
  border: none;
729
709
  outline: none;
730
710
  color: #121212;
731
711
  border-radius: 12px;
712
+ text-align: start;
732
713
  }
733
- .select_control:focus-visible {
714
+ .dropdown_control:focus-visible {
734
715
  box-shadow: 0 0 0 3px rgba(18, 18, 18, 0.15);
735
716
  }
736
- .select_control:disabled,
737
- .select_control.is_disabled {
717
+ .dropdown_control:disabled,
718
+ .dropdown_control.is_disabled {
738
719
  cursor: not-allowed;
739
720
  opacity: 0.38;
740
721
  color: #888888;
741
722
  }
742
- .select_size_sm .select_control {
743
- padding: 8px 16px;
744
- font-size: 12px;
745
- font-weight: 400;
746
- line-height: 16px;
747
- letter-spacing: 0px;
748
- }
749
- .select_size_md .select_control {
750
- padding: 12px 20px;
751
- font-size: 15px;
752
- font-weight: 400;
753
- line-height: 22.5px;
754
- letter-spacing: 0px;
755
- }
756
- .select_size_lg .select_control {
757
- padding: 16px 24px;
758
- font-size: 16px;
759
- font-weight: 400;
760
- line-height: 24px;
761
- letter-spacing: 0px;
762
- }
763
- .select_value {
723
+ .dropdown_value {
764
724
  flex: 1 1 auto;
765
725
  min-width: 0;
766
726
  overflow: hidden;
767
727
  text-overflow: ellipsis;
768
728
  white-space: nowrap;
769
729
  text-align: start;
770
- font-size: 15px;
730
+ font-size: 14px;
771
731
  font-weight: 400;
772
- line-height: 22.5px;
732
+ line-height: 20px;
773
733
  letter-spacing: 0px;
774
734
  }
775
- .select_placeholder {
735
+ .dropdown_placeholder {
776
736
  flex: 1 1 auto;
777
737
  min-width: 0;
778
738
  overflow: hidden;
779
739
  text-overflow: ellipsis;
780
740
  white-space: nowrap;
781
741
  text-align: start;
782
- font-size: 15px;
742
+ font-size: 14px;
783
743
  font-weight: 400;
784
- line-height: 22.5px;
744
+ line-height: 20px;
785
745
  letter-spacing: 0px;
786
- color: #888888;
746
+ color: #666666;
787
747
  }
788
- .select_icon {
748
+ .dropdown_icon {
789
749
  display: inline-flex;
790
750
  align-items: center;
791
751
  justify-content: center;
752
+ flex-shrink: 0;
792
753
  color: #666666;
793
754
  }
794
- .select_list {
755
+ .dropdown_list {
795
756
  position: absolute;
796
757
  z-index: 1000;
797
758
  top: 100%;
@@ -802,51 +763,88 @@
802
763
  margin-top: 4px;
803
764
  background: #FFFFFF;
804
765
  border: 1px solid #E5E5E5;
805
- border-radius: 8px;
766
+ border-radius: 4px;
806
767
  box-shadow: 0 2px 2px -2px rgba(0, 0, 0, 0.2), 0 6px 6px 0px rgba(0, 0, 0, 0.12);
807
768
  max-height: 18rem;
808
769
  overflow-y: auto;
809
770
  overflow-x: hidden;
810
771
  padding: 4px 0;
811
772
  }
812
- .select_list_up {
773
+ .dropdown_list_up {
813
774
  top: auto;
814
775
  bottom: 100%;
815
776
  margin-top: 0;
816
777
  margin-bottom: 4px;
817
778
  }
818
- .select_option {
779
+ .dropdown_option {
819
780
  width: 100%;
820
781
  box-sizing: border-box;
821
- display: grid;
822
- grid-template-columns: 1fr auto;
782
+ display: flex;
823
783
  align-items: center;
824
- gap: 8px;
784
+ gap: 12px;
825
785
  padding: 8px 16px;
786
+ min-height: 56px;
826
787
  cursor: pointer;
827
- color: #121212;
828
788
  background: transparent;
829
- font-size: 15px;
830
- font-weight: 400;
831
- line-height: 22.5px;
832
- letter-spacing: 0px;
789
+ color: #121212;
790
+ }
791
+ .dropdown_option:hover {
792
+ background: rgba(0, 0, 0, 0.05);
793
+ }
794
+ .dropdown_option.is_active {
795
+ background: rgba(0, 0, 0, 0.08);
796
+ }
797
+ .dropdown_option.is_disabled {
798
+ cursor: not-allowed;
799
+ color: #888888;
833
800
  }
834
- .select_option > span:first-child {
801
+ .dropdown_option_icon {
802
+ display: inline-flex;
803
+ align-items: center;
804
+ justify-content: center;
805
+ flex-shrink: 0;
806
+ color: #666666;
807
+ }
808
+ .dropdown_option_content {
809
+ flex: 1;
835
810
  min-width: 0;
811
+ display: flex;
812
+ flex-direction: column;
813
+ }
814
+ .dropdown_option_label {
836
815
  overflow: hidden;
837
816
  text-overflow: ellipsis;
838
817
  white-space: nowrap;
818
+ font-size: 14px;
819
+ font-weight: 500;
820
+ line-height: 20px;
821
+ letter-spacing: 0px;
839
822
  }
840
- .select_option:hover,
841
- .select_option.is_active {
842
- background: #F4F4F4;
843
- }
844
- .select_option.is_selected {
823
+ .is_selected .dropdown_option_label {
845
824
  font-weight: 500;
846
825
  }
847
- .select_option.is_disabled {
848
- cursor: not-allowed;
849
- color: #888888;
826
+ .dropdown_option_supporting {
827
+ overflow: hidden;
828
+ text-overflow: ellipsis;
829
+ white-space: nowrap;
830
+ font-size: 14px;
831
+ font-weight: 400;
832
+ line-height: 20px;
833
+ letter-spacing: 0px;
834
+ color: #666666;
835
+ }
836
+ .dropdown_option_trailing {
837
+ display: inline-flex;
838
+ align-items: center;
839
+ justify-content: center;
840
+ flex-shrink: 0;
841
+ color: #666666;
842
+ }
843
+ .dropdown_option_divider {
844
+ height: 1px;
845
+ background: #E5E5E5;
846
+ border: none;
847
+ margin: 0;
850
848
  }
851
849
 
852
850
  /* src/ui/date-picker/style.scss */
package/dist/index.d.ts CHANGED
@@ -611,6 +611,60 @@ interface DatePickerProps {
611
611
  */
612
612
  declare const DatePicker: ({ label, value, onChange, mode, startYear, endYear: endYearProp, minDate, selectableRange, disabled, fullWidth, width, yearLabel, monthLabel, dayLabel, minDateSrFormat, selectableRangeUntilTodaySrText, }: DatePickerProps) => react_jsx_runtime.JSX.Element;
613
613
 
614
+ type DropdownSize = "sm" | "md" | "lg";
615
+ interface DropdownOption {
616
+ value: string;
617
+ label: string;
618
+ disabled?: boolean;
619
+ /** 옵션 아래에 표시할 보조 텍스트 */
620
+ supportingText?: string;
621
+ /** 옵션 왼쪽 아이콘 */
622
+ leadingIcon?: React$1.ReactNode;
623
+ /** 옵션 오른쪽 아이콘 (미지정 시 선택 상태에 체크 아이콘 자동 표시) */
624
+ trailingIcon?: React$1.ReactNode;
625
+ /** 아이템 아래 구분선 표시 여부 */
626
+ showDivider?: boolean;
627
+ }
628
+ interface DropdownProps {
629
+ /** 드롭다운 요소의 id (미입력 시 자동 생성) */
630
+ id?: string;
631
+ /** 드롭다운 위에 표시할 플로팅 라벨 텍스트 */
632
+ label?: string;
633
+ /** 선택 전 표시할 플레이스홀더 (기본값: "Select…") */
634
+ placeholder?: string;
635
+ /** 표시할 옵션 목록 */
636
+ options: DropdownOption[];
637
+ /** 제어형 선택 값 */
638
+ value?: string | null;
639
+ /** 값 변경 시 호출되는 콜백. 선택된 값과 전체 옵션 객체를 인자로 전달합니다. */
640
+ onChange?: (value: string | null, option?: DropdownOption | null) => void;
641
+ /** 비제어형 초기 선택 값 */
642
+ defaultValue?: string | null;
643
+ /** 비활성화 여부 */
644
+ disabled?: boolean;
645
+ /** 드롭다운 크기 (기본값: "md") */
646
+ size?: DropdownSize;
647
+ /** 컨테이너 전체 너비 차지 여부 */
648
+ fullWidth?: boolean;
649
+ /** 루트 요소에 추가할 className */
650
+ className?: string;
651
+ /**
652
+ * @deprecated variant는 더 이상 지원되지 않습니다. Dropdown은 outline 스타일만 사용합니다.
653
+ */
654
+ variant?: "outline" | "filled" | "ghost";
655
+ /**
656
+ * @deprecated textAlign은 더 이상 지원되지 않습니다.
657
+ */
658
+ textAlign?: "left" | "center";
659
+ }
660
+ /**
661
+ * 드롭다운 컴포넌트를 렌더링한다.
662
+ * 제어형/비제어형 상태를 지원하며, 키보드/마우스 상호작용과 플로팅 라벨을 관리한다.
663
+ * @param props 드롭다운 속성
664
+ * @returns 렌더링된 드롭다운 UI
665
+ */
666
+ declare const Dropdown: ({ id, label, placeholder, options, value, onChange, defaultValue, disabled, size, fullWidth, className, }: DropdownProps) => react_jsx_runtime.JSX.Element;
667
+
614
668
  interface DividerProps extends React$1.HTMLAttributes<HTMLHRElement> {
615
669
  /** 구분선 두께 (기본값: "standard") */
616
670
  weight?: "standard" | "heavy";
@@ -842,49 +896,6 @@ declare const Radio: {
842
896
  displayName: string;
843
897
  };
844
898
 
845
- type SelectSize = "sm" | "md" | "lg";
846
- type SelectVariant = "outline" | "filled" | "ghost";
847
- interface SelectOption {
848
- value: string;
849
- label: string;
850
- disabled?: boolean;
851
- }
852
- interface SelectProps {
853
- /** 셀렉트 요소의 id (미입력 시 자동 생성) */
854
- id?: string;
855
- /** 셀렉트 위에 표시할 라벨 텍스트 */
856
- label?: string;
857
- /** 선택 전 표시할 플레이스홀더 (기본값: "Select…") */
858
- placeholder?: string;
859
- /** 표시할 옵션 목록 */
860
- options: SelectOption[];
861
- /** 제어형 선택 값 */
862
- value?: string | null;
863
- /** 값 변경 시 호출되는 콜백. 선택된 값과 전체 옵션 객체를 인자로 전달합니다. */
864
- onChange?: (value: string | null, option?: SelectOption | null) => void;
865
- /** 비제어형 초기 선택 값 */
866
- defaultValue?: string | null;
867
- /** 비활성화 여부 */
868
- disabled?: boolean;
869
- /** 셀렉트 크기 (기본값: "md") */
870
- size?: SelectSize;
871
- /** 셀렉트 스타일 변형 (기본값: "outline") */
872
- variant?: SelectVariant;
873
- /** 컨테이너 전체 너비 차지 여부 */
874
- fullWidth?: boolean;
875
- /** 루트 요소에 추가할 className */
876
- className?: string;
877
- /** 선택된 값 텍스트 정렬 (기본값: "left") */
878
- textAlign?: "left" | "center";
879
- }
880
- /**
881
- * 셀렉트 컴포넌트를 렌더링한다.
882
- * 제어형/비제어형 상태를 정리하고, 키보드/마우스 상호작용과 드롭다운 표시를 관리한다.
883
- * @param props 셀렉트 속성
884
- * @returns 렌더링된 셀렉트 UI
885
- */
886
- declare const Select: ({ id, label, placeholder, options, value, onChange, defaultValue, disabled, size, variant, fullWidth, className, textAlign, }: SelectProps) => react_jsx_runtime.JSX.Element;
887
-
888
899
  interface SpinnerProps {
889
900
  /** 스피너 크기(px) (기본값: 24) */
890
901
  size?: number;
@@ -1023,4 +1034,4 @@ interface TopLoadingProps {
1023
1034
  */
1024
1035
  declare const TopLoading: ({ progress, color, height, isLoading, ariaLabel, }: TopLoadingProps) => react_jsx_runtime.JSX.Element | null;
1025
1036
 
1026
- export { AlertProvider, Button, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipType, DatePicker, type DatePickerProps, Divider, type DividerProps, FAB, type FABProps, type FABVariant, FileInput, type FileInputProps, Icon, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, type IconName, type IconProps, type IconWeight, LinearProgress, type LinearProgressProps, ListItem, type ListItemProps, Modal, type ModalProps, OtpInput, type OtpInputProps, Pagination, type PaginationProps, Radio, type RadioProps, Select, type SelectOption, type SelectProps, Spinner, type SpinnerProps, TextField, type TextFieldProps, ToastProvider, Toggle, type ToggleProps, TopLoading, type TopLoadingProps, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useToast, zIndex };
1037
+ export { AlertProvider, Button, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipType, DatePicker, type DatePickerProps, Divider, type DividerProps, Dropdown, type DropdownOption, type DropdownProps, type DropdownSize, FAB, type FABProps, type FABVariant, FileInput, type FileInputProps, Icon, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, type IconName, type IconProps, type IconWeight, LinearProgress, type LinearProgressProps, ListItem, type ListItemProps, Modal, type ModalProps, OtpInput, type OtpInputProps, Pagination, type PaginationProps, Radio, type RadioProps, Dropdown as Select, type DropdownOption as SelectOption, type DropdownProps as SelectProps, Spinner, type SpinnerProps, TextField, type TextFieldProps, ToastProvider, Toggle, type ToggleProps, TopLoading, type TopLoadingProps, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useToast, zIndex };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import * as React5 from 'react';
4
4
  import { createContext, useContext, useState, useCallback } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
7
- import { ChevronDown, Check, X, Bell, Info, AlertTriangle, XCircle, CheckCircle2 } from 'lucide-react';
7
+ import { X, ChevronDown, Check, Bell, Info, AlertTriangle, XCircle, CheckCircle2 } from 'lucide-react';
8
8
 
9
9
  // src/styles/a11y/index.ts
10
10
  var a11y = {
@@ -805,7 +805,7 @@ var Chip = ({
805
805
  )
806
806
  ] });
807
807
  };
808
- var Select = ({
808
+ var Dropdown = ({
809
809
  id,
810
810
  label,
811
811
  placeholder = "Select\u2026",
@@ -815,13 +815,11 @@ var Select = ({
815
815
  defaultValue = null,
816
816
  disabled,
817
817
  size = "md",
818
- variant = "outline",
819
818
  fullWidth,
820
- className,
821
- textAlign = "left"
819
+ className
822
820
  }) => {
823
821
  const internalId = React5.useId();
824
- const selectId = id ?? internalId;
822
+ const dropdownId = id ?? internalId;
825
823
  const isControlled = value !== void 0;
826
824
  const [internalValue, setInternalValue] = React5.useState(defaultValue);
827
825
  const currentValue = isControlled ? value ?? null : internalValue;
@@ -834,6 +832,7 @@ var Select = ({
834
832
  () => options.find((o) => o.value === currentValue) ?? null,
835
833
  [options, currentValue]
836
834
  );
835
+ const isLabelVisible = isOpen || !!currentOption;
837
836
  const setValue = React5.useCallback(
838
837
  (next) => {
839
838
  const option = options.find((o) => o.value === next) ?? null;
@@ -842,16 +841,17 @@ var Select = ({
842
841
  },
843
842
  [isControlled, onChange, options]
844
843
  );
845
- const handleOutsideClick = React5.useEffectEvent((e) => {
846
- if (!wrapperRef.current?.contains(e.target)) {
847
- setIsOpen(false);
848
- }
849
- });
850
844
  React5.useEffect(() => {
845
+ const handleOutsideClick = (e) => {
846
+ if (!wrapperRef.current?.contains(e.target)) {
847
+ setIsOpen(false);
848
+ }
849
+ };
851
850
  document.addEventListener("mousedown", handleOutsideClick);
852
851
  return () => document.removeEventListener("mousedown", handleOutsideClick);
853
852
  }, []);
854
853
  const moveActive = (dir) => {
854
+ if (options.length === 0) return;
855
855
  if (!isOpen) {
856
856
  setIsOpen(true);
857
857
  return;
@@ -916,28 +916,20 @@ var Select = ({
916
916
  if (!isOpen) return;
917
917
  const idx = options.findIndex((o) => o.value === currentValue && !o.disabled);
918
918
  setActiveIndex(
919
- idx >= 0 ? idx : Math.max(
920
- 0,
921
- options.findIndex((o) => !o.disabled)
922
- )
919
+ idx >= 0 ? idx : Math.max(0, options.findIndex((o) => !o.disabled))
923
920
  );
924
921
  }, [isOpen, options, currentValue]);
925
922
  React5.useLayoutEffect(() => {
926
923
  if (!isOpen || !controlRef.current) return;
927
924
  const rect = controlRef.current.getBoundingClientRect();
928
- const listHeight = Math.min(options.length * 40, 288);
925
+ const listHeight = Math.min(options.length * 56, 288);
929
926
  const spaceBelow = window.innerHeight - rect.bottom;
930
927
  const spaceAbove = rect.top;
931
928
  setDropUp(spaceBelow < listHeight && spaceAbove > spaceBelow);
932
929
  }, [isOpen, options.length]);
933
- const rootClassName = cn("select", { select_has_label: !!label }, className);
934
- const fieldsetClassName = cn(
935
- "select_fieldset",
936
- `select_variant_${variant}`,
937
- `select_size_${size}`,
938
- { is_open: isOpen, is_disabled: disabled }
939
- );
940
- const listClassName = cn("select_list", { select_list_up: dropUp });
930
+ const rootClassName = cn("dropdown", `dropdown_size_${size}`, className);
931
+ const fieldsetClassName = cn("dropdown_fieldset", { is_open: isOpen, is_disabled: disabled });
932
+ const listClassName = cn("dropdown_list", { dropdown_list_up: dropUp });
941
933
  return /* @__PURE__ */ jsxs(
942
934
  "div",
943
935
  {
@@ -945,73 +937,79 @@ var Select = ({
945
937
  className: rootClassName,
946
938
  style: fullWidth ? { width: "100%" } : void 0,
947
939
  children: [
948
- /* @__PURE__ */ jsxs("fieldset", { className: fieldsetClassName, children: [
949
- label && /* @__PURE__ */ jsx("legend", { className: "select_label", children: /* @__PURE__ */ jsx("label", { htmlFor: selectId, children: label }) }),
950
- /* @__PURE__ */ jsx("div", { className: "select_inner", children: /* @__PURE__ */ jsxs(
940
+ /* @__PURE__ */ jsxs("div", { className: fieldsetClassName, children: [
941
+ label && /* @__PURE__ */ jsx(
942
+ "span",
943
+ {
944
+ className: cn("dropdown_label", { is_visible: isLabelVisible }),
945
+ "aria-hidden": "true",
946
+ children: label
947
+ }
948
+ ),
949
+ /* @__PURE__ */ jsxs(
951
950
  "button",
952
951
  {
953
952
  ref: controlRef,
954
- id: selectId,
953
+ id: dropdownId,
955
954
  type: "button",
956
- className: cn("select_control", { is_disabled: disabled }),
955
+ className: cn("dropdown_control", { is_disabled: disabled }),
957
956
  "aria-haspopup": "listbox",
958
957
  "aria-expanded": isOpen,
959
- "aria-controls": `${selectId}_listbox`,
958
+ "aria-controls": `${dropdownId}_listbox`,
959
+ "aria-label": label,
960
960
  onClick: () => !disabled && setIsOpen((o) => !o),
961
961
  onKeyDown,
962
962
  disabled,
963
963
  children: [
964
- /* @__PURE__ */ jsx(
965
- "span",
966
- {
967
- className: currentOption ? "select_value" : "select_placeholder",
968
- style: textAlign === "left" ? { textAlign: "start" } : void 0,
969
- children: currentOption ? currentOption.label : placeholder
970
- }
971
- ),
972
- /* @__PURE__ */ jsx("span", { className: "select_icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ChevronDown, { size: 16 }) })
964
+ /* @__PURE__ */ jsx("span", { className: currentOption ? "dropdown_value" : "dropdown_placeholder", children: currentOption ? currentOption.label : placeholder }),
965
+ /* @__PURE__ */ jsx("span", { className: "dropdown_icon", "aria-hidden": "true", children: isOpen ? /* @__PURE__ */ jsx(X, { size: 24 }) : /* @__PURE__ */ jsx(ChevronDown, { size: 24 }) })
973
966
  ]
974
967
  }
975
- ) })
968
+ )
976
969
  ] }),
977
- isOpen && /* @__PURE__ */ jsx("div", { id: `${selectId}_listbox`, role: "listbox", className: listClassName, children: options.map((opt, i) => {
978
- const selected = currentValue === opt.value;
979
- const active = i === activeIndex;
980
- const optionClassName = cn("select_option", {
981
- is_selected: selected,
982
- is_active: active,
983
- is_disabled: opt.disabled
984
- });
985
- return /* @__PURE__ */ jsxs(
986
- "div",
987
- {
988
- role: "option",
989
- tabIndex: -1,
990
- "aria-selected": selected,
991
- "aria-disabled": opt.disabled ? true : void 0,
992
- className: optionClassName,
993
- onMouseEnter: () => !opt.disabled && setActiveIndex(i),
994
- onClick: () => {
995
- if (opt.disabled) return;
996
- setValue(opt.value);
997
- setIsOpen(false);
998
- },
999
- onKeyDown: (e) => {
1000
- if (opt.disabled) return;
1001
- if (e.key === "Enter" || e.key === " ") {
1002
- e.preventDefault();
1003
- setValue(opt.value);
1004
- setIsOpen(false);
1005
- }
1006
- },
1007
- children: [
1008
- /* @__PURE__ */ jsx("span", { children: opt.label }),
1009
- selected && /* @__PURE__ */ jsx(Check, { size: 16, "aria-hidden": "true" })
1010
- ]
1011
- },
1012
- opt.value
1013
- );
1014
- }) })
970
+ isOpen && /* @__PURE__ */ jsx(
971
+ "div",
972
+ {
973
+ id: `${dropdownId}_listbox`,
974
+ role: "listbox",
975
+ className: listClassName,
976
+ children: options.map((opt, i) => {
977
+ const selected = currentValue === opt.value;
978
+ const active = i === activeIndex;
979
+ return /* @__PURE__ */ jsxs(React5.Fragment, { children: [
980
+ /* @__PURE__ */ jsxs(
981
+ "div",
982
+ {
983
+ role: "option",
984
+ tabIndex: -1,
985
+ "aria-selected": selected,
986
+ "aria-disabled": opt.disabled ? true : void 0,
987
+ className: cn("dropdown_option", {
988
+ is_selected: selected,
989
+ is_active: active,
990
+ is_disabled: opt.disabled
991
+ }),
992
+ onMouseEnter: () => !opt.disabled && setActiveIndex(i),
993
+ onClick: () => {
994
+ if (opt.disabled) return;
995
+ setValue(opt.value);
996
+ setIsOpen(false);
997
+ },
998
+ children: [
999
+ opt.leadingIcon && /* @__PURE__ */ jsx("span", { className: "dropdown_option_icon", children: opt.leadingIcon }),
1000
+ /* @__PURE__ */ jsxs("span", { className: "dropdown_option_content", children: [
1001
+ /* @__PURE__ */ jsx("span", { className: "dropdown_option_label", children: opt.label }),
1002
+ opt.supportingText && /* @__PURE__ */ jsx("span", { className: "dropdown_option_supporting", children: opt.supportingText })
1003
+ ] }),
1004
+ (selected || opt.trailingIcon) && /* @__PURE__ */ jsx("span", { className: "dropdown_option_trailing", children: opt.trailingIcon ?? /* @__PURE__ */ jsx(Check, { size: 16, "aria-hidden": "true" }) })
1005
+ ]
1006
+ }
1007
+ ),
1008
+ opt.showDivider && /* @__PURE__ */ jsx("div", { className: "dropdown_option_divider", role: "separator" })
1009
+ ] }, opt.value);
1010
+ })
1011
+ }
1012
+ )
1015
1013
  ]
1016
1014
  }
1017
1015
  );
@@ -1168,7 +1166,7 @@ var DatePicker = ({
1168
1166
  "aria-describedby": constraintDesc ? constraintId : void 0,
1169
1167
  children: [
1170
1168
  /* @__PURE__ */ jsx(
1171
- Select,
1169
+ Dropdown,
1172
1170
  {
1173
1171
  size: "sm",
1174
1172
  fullWidth: true,
@@ -1181,7 +1179,7 @@ var DatePicker = ({
1181
1179
  }
1182
1180
  ),
1183
1181
  /* @__PURE__ */ jsx(
1184
- Select,
1182
+ Dropdown,
1185
1183
  {
1186
1184
  size: "sm",
1187
1185
  fullWidth: true,
@@ -1194,7 +1192,7 @@ var DatePicker = ({
1194
1192
  }
1195
1193
  ),
1196
1194
  mode === "year-month-day" && /* @__PURE__ */ jsx(
1197
- Select,
1195
+ Dropdown,
1198
1196
  {
1199
1197
  size: "sm",
1200
1198
  fullWidth: true,
@@ -2544,4 +2542,4 @@ var TopLoading = ({
2544
2542
  );
2545
2543
  };
2546
2544
 
2547
- export { AlertProvider, Button, Card, Checkbox, Chip, DatePicker, Divider, FAB, FileInput, Icon, IconButton, LinearProgress, ListItem, Modal, OtpInput, Pagination, Radio, Select, Spinner, TextField, ToastProvider, Toggle, TopLoading, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useToast, zIndex };
2545
+ export { AlertProvider, Button, Card, Checkbox, Chip, DatePicker, Divider, Dropdown, FAB, FileInput, Icon, IconButton, LinearProgress, ListItem, Modal, OtpInput, Pagination, Radio, Dropdown as Select, Spinner, TextField, ToastProvider, Toggle, TopLoading, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useToast, zIndex };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigtablet/design-system",
3
- "version": "2.3.0",
3
+ "version": "2.4.1",
4
4
  "description": "Bigtablet Design System UI Components",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",
@@ -87,38 +87,38 @@
87
87
  "@semantic-release/github": "^12.0.1",
88
88
  "@semantic-release/npm": "^13.1.1",
89
89
  "@size-limit/preset-small-lib": "^12.0.1",
90
- "@storybook/addon-a11y": "^10.3.5",
91
- "@storybook/addon-docs": "^10.3.3",
92
- "@storybook/addon-vitest": "^10.3.3",
93
- "@storybook/react": "^10.3.3",
94
- "@storybook/react-vite": "^10.3.3",
90
+ "@storybook/addon-a11y": "^10.3.6",
91
+ "@storybook/addon-docs": "^10.3.6",
92
+ "@storybook/addon-vitest": "^10.3.6",
93
+ "@storybook/react": "^10.3.6",
94
+ "@storybook/react-vite": "^10.3.6",
95
95
  "@testing-library/dom": "^10.4.1",
96
96
  "@testing-library/jest-dom": "^6.9.1",
97
97
  "@testing-library/react": "^16.3.2",
98
98
  "@types/node": "^24",
99
99
  "@types/react": "^19.2.14",
100
- "@types/react-dom": "^19",
100
+ "@types/react-dom": "^19.2.3",
101
101
  "@vitest/browser-playwright": "^4.1.2",
102
- "@vitest/coverage-v8": "^4.1.2",
102
+ "@vitest/coverage-v8": "^4.1.5",
103
103
  "chromatic": "^16.0.0",
104
104
  "conventional-changelog-conventionalcommits": "^9.3.1",
105
105
  "esbuild-sass-plugin": "^3.7.0",
106
106
  "husky": "^9.1.7",
107
107
  "jsdom": "^29.0.1",
108
- "lucide-react": "^1.7.0",
109
- "next": "^16.2.3",
110
- "playwright": "^1.57.0",
111
- "react": "^19.2.4",
112
- "react-dom": "^19.2.4",
113
- "sass-embedded": "^1.93.3",
108
+ "lucide-react": "^1.14.0",
109
+ "next": "^16.2.4",
110
+ "playwright": "^1.59.1",
111
+ "react": "^19.2.5",
112
+ "react-dom": "^19.2.5",
113
+ "sass-embedded": "^1.99.0",
114
114
  "semantic-release": "^25.0.1",
115
115
  "size-limit": "^12.0.1",
116
- "storybook": "^10.3.3",
116
+ "storybook": "^10.3.6",
117
117
  "tsup": "^8.5.0",
118
118
  "tsx": "^4.21.0",
119
- "typescript": "^6.0.2",
119
+ "typescript": "^6.0.3",
120
120
  "vite": "^6.4.2",
121
- "vitest": "^4.1.2"
121
+ "vitest": "^4.1.5"
122
122
  },
123
123
  "publishConfig": {
124
124
  "access": "public",
@@ -141,7 +141,8 @@
141
141
  "lodash-es": "^4.18.1",
142
142
  "immutable": "^5.1.5",
143
143
  "minimatch": "^10.2.4",
144
- "handlebars": "^4.7.9"
144
+ "handlebars": "^4.7.9",
145
+ "postcss": "^8.5.10"
145
146
  }
146
147
  }
147
148
  }