sellmate-design-system-react 0.1.8 → 0.1.10

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 (110) hide show
  1. package/dist/components/SActionModal/SActionModal.cjs +1 -1
  2. package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
  3. package/dist/components/SActionModal/SActionModal.js +1 -1
  4. package/dist/components/SActionModal/SActionModal.js.map +1 -1
  5. package/dist/components/SBarcodeInput/SBarcodeInput.cjs +217 -208
  6. package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
  7. package/dist/components/SBarcodeInput/SBarcodeInput.js +217 -208
  8. package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
  9. package/dist/components/SCalendar/SCalendar.cjs +1 -1
  10. package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
  11. package/dist/components/SCalendar/SCalendar.js +1 -1
  12. package/dist/components/SCalendar/SCalendar.js.map +1 -1
  13. package/dist/components/SChip/SChip.cjs +1 -1
  14. package/dist/components/SChip/SChip.cjs.map +1 -1
  15. package/dist/components/SChip/SChip.d.ts +1 -1
  16. package/dist/components/SChip/SChip.js +1 -1
  17. package/dist/components/SChip/SChip.js.map +1 -1
  18. package/dist/components/SChipInput/SChipInput.cjs +234 -220
  19. package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
  20. package/dist/components/SChipInput/SChipInput.js +234 -220
  21. package/dist/components/SChipInput/SChipInput.js.map +1 -1
  22. package/dist/components/SCircleProgress/SCircleProgress.cjs +31 -14
  23. package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
  24. package/dist/components/SCircleProgress/SCircleProgress.d.ts +2 -0
  25. package/dist/components/SCircleProgress/SCircleProgress.js +31 -14
  26. package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
  27. package/dist/components/SDatePicker/SDatePicker.cjs +222 -213
  28. package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
  29. package/dist/components/SDatePicker/SDatePicker.js +222 -213
  30. package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
  31. package/dist/components/SDateRangePicker/SDateRangePicker.cjs +297 -262
  32. package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
  33. package/dist/components/SDateRangePicker/SDateRangePicker.js +297 -262
  34. package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
  35. package/dist/components/SDropdownButton/SDropdownButton.cjs +4 -4
  36. package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
  37. package/dist/components/SDropdownButton/SDropdownButton.js +4 -4
  38. package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
  39. package/dist/components/SField/SField.cjs +217 -20
  40. package/dist/components/SField/SField.cjs.map +1 -1
  41. package/dist/components/SField/SField.d.ts +11 -0
  42. package/dist/components/SField/SField.js +217 -20
  43. package/dist/components/SField/SField.js.map +1 -1
  44. package/dist/components/SFilePicker/SFilePicker.cjs +315 -276
  45. package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
  46. package/dist/components/SFilePicker/SFilePicker.d.ts +4 -2
  47. package/dist/components/SFilePicker/SFilePicker.js +314 -276
  48. package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
  49. package/dist/components/SInput/SInput.cjs +217 -208
  50. package/dist/components/SInput/SInput.cjs.map +1 -1
  51. package/dist/components/SInput/SInput.js +217 -208
  52. package/dist/components/SInput/SInput.js.map +1 -1
  53. package/dist/components/SKeyValueTable/SKeyValueTable.cjs +631 -450
  54. package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
  55. package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +3 -1
  56. package/dist/components/SKeyValueTable/SKeyValueTable.js +631 -450
  57. package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
  58. package/dist/components/SLoadingContainer/SLoadingContainer.cjs +39 -14
  59. package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
  60. package/dist/components/SLoadingContainer/SLoadingContainer.js +39 -14
  61. package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
  62. package/dist/components/SLoadingContainer/loading.cjs +39 -14
  63. package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
  64. package/dist/components/SLoadingContainer/loading.js +39 -14
  65. package/dist/components/SLoadingContainer/loading.js.map +1 -1
  66. package/dist/components/SLoadingModal/SLoadingModal.cjs +37 -16
  67. package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
  68. package/dist/components/SLoadingModal/SLoadingModal.d.ts +3 -1
  69. package/dist/components/SLoadingModal/SLoadingModal.js +37 -16
  70. package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
  71. package/dist/components/SNumberInput/SNumberInput.cjs +325 -49
  72. package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
  73. package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
  74. package/dist/components/SNumberInput/SNumberInput.js +325 -49
  75. package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
  76. package/dist/components/SPagination/SPagination.cjs +1 -1
  77. package/dist/components/SPagination/SPagination.cjs.map +1 -1
  78. package/dist/components/SPagination/SPagination.js +1 -1
  79. package/dist/components/SPagination/SPagination.js.map +1 -1
  80. package/dist/components/SRadio/SRadioGroup.cjs +1 -1
  81. package/dist/components/SRadio/SRadioGroup.cjs.map +1 -1
  82. package/dist/components/SRadio/SRadioGroup.js +1 -1
  83. package/dist/components/SRadio/SRadioGroup.js.map +1 -1
  84. package/dist/components/SSelect/SSelect.cjs +71 -32
  85. package/dist/components/SSelect/SSelect.cjs.map +1 -1
  86. package/dist/components/SSelect/SSelect.js +71 -32
  87. package/dist/components/SSelect/SSelect.js.map +1 -1
  88. package/dist/components/STable/STable.cjs +108 -49
  89. package/dist/components/STable/STable.cjs.map +1 -1
  90. package/dist/components/STable/STable.js +108 -49
  91. package/dist/components/STable/STable.js.map +1 -1
  92. package/dist/components/STextarea/STextarea.cjs +217 -20
  93. package/dist/components/STextarea/STextarea.cjs.map +1 -1
  94. package/dist/components/STextarea/STextarea.js +217 -20
  95. package/dist/components/STextarea/STextarea.js.map +1 -1
  96. package/dist/components/SToast/SToastContainer.cjs +3 -3
  97. package/dist/components/SToast/SToastContainer.cjs.map +1 -1
  98. package/dist/components/SToast/SToastContainer.js +3 -3
  99. package/dist/components/SToast/SToastContainer.js.map +1 -1
  100. package/dist/components/STooltip/STooltip.cjs +208 -13
  101. package/dist/components/STooltip/STooltip.cjs.map +1 -1
  102. package/dist/components/STooltip/STooltip.js +208 -13
  103. package/dist/components/STooltip/STooltip.js.map +1 -1
  104. package/dist/index.cjs +439 -221
  105. package/dist/index.cjs.map +1 -1
  106. package/dist/index.js +439 -221
  107. package/dist/index.js.map +1 -1
  108. package/dist/styles.css +113 -48
  109. package/dist/theme.css +49 -23
  110. package/package.json +1 -1
@@ -122,7 +122,7 @@ function SRadioGroup({
122
122
  role: "radiogroup",
123
123
  className: cn(
124
124
  "inline-flex",
125
- direction === "vertical" ? "flex-col gap-[8px]" : "flex-row gap-[20px]",
125
+ direction === "vertical" ? "flex-col gap-[var(--cmp-radio-group-gap-vertical)]" : "flex-row gap-[var(--cmp-radio-group-gap-horizontal)]",
126
126
  className
127
127
  ),
128
128
  style,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/cn.ts","../../../src/components/SRadio/SRadio.tsx","../../../src/components/SRadio/SRadioGroup.tsx"],"names":["extendTailwindMerge","clsx","jsxs","jsx"],"mappings":";;;;;;;AAQA,IAAM,UAAUA,iCAAA,CAAoB;AAAA,EAClC,MAAA,EAAQ;AAAA,IACN,WAAA,EAAa;AAAA,MACX,aAAa,CAAC,EAAE,IAAA,EAAM,CAAC,MAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAI,GAAG;AAAA;AAC5F;AAEJ,CAAC,CAAA;AAMM,SAAS,MAAM,MAAA,EAA8B;AAClD,EAAA,OAAO,OAAA,CAAQC,SAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACIO,SAAS,MAAA,CAAO;AAAA,EACrB,GAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,IAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAgB;AAEd,EAAA,MAAM,MAAA,GAAS,OAAO,GAAG,CAAA;AACzB,EAAA,MAAM,UAAU,KAAA,KAAU,GAAA;AAC1B,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,OAAA,kBAAyB,GAAG,CAAA;AAAA,EAChD,CAAA;AAKA,EAAA,MAAM,MAAA,GAAS,IAAA,IAAQ,IAAA,IAAQ,IAAA,KAAS,EAAA;AAGxC,EAAA,MAAM,qBAAA,GAA0D,MAAA,GAC5D,EAAC,GACD;AAAA,IACE,MAAA,EAAQ,OAAA;AAAA,IACR,cAAA,EAAgB,OAAA;AAAA,IAChB,UAAA,EAAY,WAAW,EAAA,GAAK,CAAA;AAAA,IAC5B,SAAA,EAAW,MAAA;AAAA,IACX,aAAa,CAAA,CAAA,KAAK;AAChB,MAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,GAAA,IAAO,CAAA,CAAE,QAAQ,OAAA,EAAS;AACtC,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,MAAA,EAAO;AAAA,MACT;AAAA,IACF;AAAA,GACF;AAEJ,EAAA,uBACEC,eAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACE,GAAG,qBAAA;AAAA,MACJ,SAAA,EAAW,EAAA;AAAA,QACT,oCAAA;AAAA,QACA,WAAW,oBAAA,GAAuB,gBAAA;AAAA,QAClC;AAAA,OACF;AAAA,MACA,KAAA;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,MAAA,oBACCC,cAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,OAAA;AAAA,YACL,IAAA;AAAA,YACA,KAAA,EAAO,MAAA;AAAA,YACP,OAAA;AAAA,YACA,QAAA;AAAA,YAGA,QAAA,EAAU,MAAM,aAAA,GAAgB,GAAG,CAAA;AAAA,YACnC,SAAA,EAAU;AAAA;AAAA,SACZ;AAAA,wBAEFA,cAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,EAAA;AAAA,cACT,qJAAA;AAAA,cACA,CAAC,QAAA,IACC,CAAC,OAAA,IACD;AAAA,aACJ;AAAA,YACA,KAAA,EACE;AAAA,cACE,SAAA,EAAW,WAAW,8BAAA,GAAiC,6BAAA;AAAA,cACvD,aAAA,EAAe,QAAA,GACX,kCAAA,GACA,OAAA,GACE,gCAAA,GACA;AAAA,aACR;AAAA,YAGD,QAAA,EAAA,OAAA,oBACCA,cAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAU,gCAAA;AAAA,gBACV,KAAA,EAAO;AAAA,kBACL,UAAA,EAAY,WACR,+BAAA,GACA;AAAA;AACN;AAAA;AACF;AAAA,SAEJ;AAAA,QACC,KAAA,oBACCD,eAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,iCAAA;AAAA,YACV,KAAA,EAAO;AAAA,cACL,KAAA,EAAO,WAAW,iCAAA,GAAoC;AAAA,aACxD;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAAC,cAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAW,IAAA,EAAC,SAAA,EAAU,uBAAA,EAAwB,OAAO,EAAE,QAAA,EAAU,OAAA,EAAQ,EAC5E,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,8BACAA,cAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAO,EAAE,QAAA,EAAU,OAAA,EAAS,UAAA,EAAY,OAAA,GAAU,GAAA,GAAM,GAAA,EAAI,EAAI,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA;AAC9E;AAAA;AAAA,GAEJ;AAEJ;ACpGO,SAAS,WAAA,CAAY;AAAA,EAC1B,UAAU,EAAC;AAAA,EACX,KAAA;AAAA,EACA,SAAA,GAAY,UAAA;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,SAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,uBACEA,cAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,YAAA;AAAA,MACL,SAAA,EAAW,EAAA;AAAA,QACT,aAAA;AAAA,QACA,SAAA,KAAc,aAAa,oBAAA,GAAuB,qBAAA;AAAA,QAClD;AAAA,OACF;AAAA,MACA,KAAA;AAAA,MAEC,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAA,qBACXA,cAAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UAEC,KAAK,CAAA,CAAE,KAAA;AAAA,UACP,KAAA;AAAA,UACA,OAAO,CAAA,CAAE,KAAA;AAAA,UACT,IAAA,EAAM,SAAA;AAAA,UACN,QAAA,EAAU,YAAY,CAAA,CAAE,QAAA;AAAA,UACxB;AAAA,SAAA;AAAA,QANK,MAAA,CAAO,EAAE,KAAK;AAAA,OAQtB;AAAA;AAAA,GACH;AAEJ","file":"SRadioGroup.cjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * theme.css 의 --text-* 는 기본 Tailwind 폰트사이즈 스케일(xs/sm/base...)이 아닌\n * 숫자 스케일(10~32)이라, 확장 없이는 tailwind-merge 가 이를 텍스트 컬러 그룹으로\n * 오인해 text-12 같은 클래스를 text-(--color-var) 뒤에서 충돌 제거해버린다.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['10', '11', '12', '13', '14', '16', '18', '20', '24', '28', '32'] }],\n },\n },\n});\n\n/**\n * className 병합 유틸.\n * clsx로 조건부 클래스를 합치고, tailwind-merge로 Tailwind 클래스 충돌을 해소한다.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","'use client';\n\nimport { type CSSProperties, type HTMLAttributes } from 'react';\nimport { cn } from '../../lib/cn';\n\n/** 라디오 값 타입 (sd-radio SRadioValue) */\nexport type SRadioValue = string | number | boolean;\n\nexport interface SRadioProps {\n /** 이 라디오의 값 */\n val: SRadioValue;\n /** 그룹의 현재 선택 값 */\n value?: SRadioValue | null;\n /** 라벨 */\n label?: string;\n /** 비활성 */\n disabled?: boolean;\n /** native radio name (form-agnostic 그룹핑) */\n name?: string;\n /** 선택 변경 (sdUpdate) — 선택된 val 전달 */\n onValueChange?: (val: SRadioValue) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/** SRadio — sd-radio 포팅. value===val 이면 선택. 단독 또는 SRadioGroup 안에서 사용. */\nexport function SRadio({\n val,\n value,\n label,\n disabled = false,\n name,\n onValueChange,\n className,\n style,\n}: SRadioProps) {\n // key/name 속성용 문자열 표현\n const valStr = String(val);\n const checked = value === val;\n const select = () => {\n if (!disabled && !checked) onValueChange?.(val);\n };\n\n // name 이 있으면 네이티브 <input type=\"radio\"> 가 실제 상호작용 컨트롤이 된다.\n // 이때 label 에는 role/tabIndex/키핸들러를 주지 않는다 — 상호작용 요소 중첩\n // (role=\"radio\" 안에 native radio) 및 radio 역할 중복을 피한다.\n const native = name != null && name !== '';\n\n // native 모드가 아니면 label 자체가 커스텀 radio 로 동작한다.\n const labelInteractiveProps: HTMLAttributes<HTMLLabelElement> = native\n ? {}\n : {\n 'role': 'radio',\n 'aria-checked': checked,\n 'tabIndex': disabled ? -1 : 0,\n 'onClick': select,\n 'onKeyDown': e => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n select();\n }\n },\n };\n\n return (\n <label\n {...labelInteractiveProps}\n className={cn(\n 'inline-flex items-center gap-[8px]',\n disabled ? 'cursor-not-allowed' : 'cursor-pointer',\n className,\n )}\n style={style}\n >\n {native && (\n <input\n type=\"radio\"\n name={name}\n value={valStr}\n checked={checked}\n disabled={disabled}\n // 네이티브 라디오가 포커스/키보드/선택을 담당한다. label 이 감싸므로\n // 라벨 클릭도 이 input 을 토글하며, onChange 는 값이 실제로 바뀔 때만 발생.\n onChange={() => onValueChange?.(val)}\n className=\"sr-only\"\n />\n )}\n <span\n className={cn(\n 'flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-full border border-solid border-[color:var(--rd-border)] bg-[var(--rd-bg)]',\n !disabled &&\n !checked &&\n 'hover:border-[color:var(--cmp-radio-border-hover)] hover:bg-[var(--cmp-radio-bg-hover)]',\n )}\n style={\n {\n '--rd-bg': disabled ? 'var(--cmp-radio-bg-disabled)' : 'var(--cmp-radio-bg-default)',\n '--rd-border': disabled\n ? 'var(--cmp-radio-border-disabled)'\n : checked\n ? 'var(--cmp-radio-border-active)'\n : 'var(--cmp-radio-border-default)',\n } as CSSProperties\n }\n >\n {checked && (\n <span\n className=\"h-[10px] w-[10px] rounded-full\"\n style={{\n background: disabled\n ? 'var(--cmp-radio-dot-disabled)'\n : 'var(--cmp-radio-dot-default)',\n }}\n />\n )}\n </span>\n {label && (\n <span\n className=\"grid text-[12px] leading-[20px]\"\n style={{\n color: disabled ? 'var(--cmp-radio-label-disabled)' : 'var(--cmp-radio-label-default)',\n }}\n >\n <span aria-hidden className=\"invisible font-medium\" style={{ gridArea: '1 / 1' }}>\n {label}\n </span>\n <span style={{ gridArea: '1 / 1', fontWeight: checked ? 500 : 400 }}>{label}</span>\n </span>\n )}\n </label>\n );\n}\n","'use client';\n\nimport { type CSSProperties } from 'react';\nimport { cn } from '../../lib/cn';\nimport { SRadio, type SRadioValue } from './SRadio';\n\nexport interface SRadioOption {\n /** 옵션 값 (sd-radio-group SRadioOption.value) */\n value: SRadioValue;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SRadioGroupProps {\n /** 옵션 목록 */\n options?: SRadioOption[];\n /** 현재 선택 값 */\n value?: SRadioValue | null;\n /** 배치 방향 */\n direction?: 'vertical' | 'horizontal';\n /** 전체 비활성 */\n disabled?: boolean;\n /** 라디오 name 속성 (form-agnostic 그룹핑) */\n groupName?: string;\n /** 선택 변경 (sdUpdate) */\n onValueChange?: (val: SRadioValue) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/** SRadioGroup — sd-radio-group 포팅. options를 SRadio로 렌더. */\nexport function SRadioGroup({\n options = [],\n value,\n direction = 'vertical',\n disabled = false,\n groupName,\n onValueChange,\n className,\n style,\n}: SRadioGroupProps) {\n return (\n <div\n role=\"radiogroup\"\n className={cn(\n 'inline-flex',\n direction === 'vertical' ? 'flex-col gap-[8px]' : 'flex-row gap-[20px]',\n className,\n )}\n style={style}\n >\n {options.map(o => (\n <SRadio\n key={String(o.value)}\n val={o.value}\n value={value}\n label={o.label}\n name={groupName}\n disabled={disabled || o.disabled}\n onValueChange={onValueChange}\n />\n ))}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../src/lib/cn.ts","../../../src/components/SRadio/SRadio.tsx","../../../src/components/SRadio/SRadioGroup.tsx"],"names":["extendTailwindMerge","clsx","jsxs","jsx"],"mappings":"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","file":"SRadioGroup.cjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * theme.css 의 --text-* 는 기본 Tailwind 폰트사이즈 스케일(xs/sm/base...)이 아닌\n * 숫자 스케일(10~32)이라, 확장 없이는 tailwind-merge 가 이를 텍스트 컬러 그룹으로\n * 오인해 text-12 같은 클래스를 text-(--color-var) 뒤에서 충돌 제거해버린다.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['10', '11', '12', '13', '14', '16', '18', '20', '24', '28', '32'] }],\n },\n },\n});\n\n/**\n * className 병합 유틸.\n * clsx로 조건부 클래스를 합치고, tailwind-merge로 Tailwind 클래스 충돌을 해소한다.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","'use client';\n\nimport { type CSSProperties, type HTMLAttributes } from 'react';\nimport { cn } from '../../lib/cn';\n\n/** 라디오 값 타입 (sd-radio SRadioValue) */\nexport type SRadioValue = string | number | boolean;\n\nexport interface SRadioProps {\n /** 이 라디오의 값 */\n val: SRadioValue;\n /** 그룹의 현재 선택 값 */\n value?: SRadioValue | null;\n /** 라벨 */\n label?: string;\n /** 비활성 */\n disabled?: boolean;\n /** native radio name (form-agnostic 그룹핑) */\n name?: string;\n /** 선택 변경 (sdUpdate) — 선택된 val 전달 */\n onValueChange?: (val: SRadioValue) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/** SRadio — sd-radio 포팅. value===val 이면 선택. 단독 또는 SRadioGroup 안에서 사용. */\nexport function SRadio({\n val,\n value,\n label,\n disabled = false,\n name,\n onValueChange,\n className,\n style,\n}: SRadioProps) {\n // key/name 속성용 문자열 표현\n const valStr = String(val);\n const checked = value === val;\n const select = () => {\n if (!disabled && !checked) onValueChange?.(val);\n };\n\n // name 이 있으면 네이티브 <input type=\"radio\"> 가 실제 상호작용 컨트롤이 된다.\n // 이때 label 에는 role/tabIndex/키핸들러를 주지 않는다 — 상호작용 요소 중첩\n // (role=\"radio\" 안에 native radio) 및 radio 역할 중복을 피한다.\n const native = name != null && name !== '';\n\n // native 모드가 아니면 label 자체가 커스텀 radio 로 동작한다.\n const labelInteractiveProps: HTMLAttributes<HTMLLabelElement> = native\n ? {}\n : {\n 'role': 'radio',\n 'aria-checked': checked,\n 'tabIndex': disabled ? -1 : 0,\n 'onClick': select,\n 'onKeyDown': e => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n select();\n }\n },\n };\n\n return (\n <label\n {...labelInteractiveProps}\n className={cn(\n 'inline-flex items-center gap-[8px]',\n disabled ? 'cursor-not-allowed' : 'cursor-pointer',\n className,\n )}\n style={style}\n >\n {native && (\n <input\n type=\"radio\"\n name={name}\n value={valStr}\n checked={checked}\n disabled={disabled}\n // 네이티브 라디오가 포커스/키보드/선택을 담당한다. label 이 감싸므로\n // 라벨 클릭도 이 input 을 토글하며, onChange 는 값이 실제로 바뀔 때만 발생.\n onChange={() => onValueChange?.(val)}\n className=\"sr-only\"\n />\n )}\n <span\n className={cn(\n 'flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-full border border-solid border-[color:var(--rd-border)] bg-[var(--rd-bg)]',\n !disabled &&\n !checked &&\n 'hover:border-[color:var(--cmp-radio-border-hover)] hover:bg-[var(--cmp-radio-bg-hover)]',\n )}\n style={\n {\n '--rd-bg': disabled ? 'var(--cmp-radio-bg-disabled)' : 'var(--cmp-radio-bg-default)',\n '--rd-border': disabled\n ? 'var(--cmp-radio-border-disabled)'\n : checked\n ? 'var(--cmp-radio-border-active)'\n : 'var(--cmp-radio-border-default)',\n } as CSSProperties\n }\n >\n {checked && (\n <span\n className=\"h-[10px] w-[10px] rounded-full\"\n style={{\n background: disabled\n ? 'var(--cmp-radio-dot-disabled)'\n : 'var(--cmp-radio-dot-default)',\n }}\n />\n )}\n </span>\n {label && (\n <span\n className=\"grid text-[12px] leading-[20px]\"\n style={{\n color: disabled ? 'var(--cmp-radio-label-disabled)' : 'var(--cmp-radio-label-default)',\n }}\n >\n <span aria-hidden className=\"invisible font-medium\" style={{ gridArea: '1 / 1' }}>\n {label}\n </span>\n <span style={{ gridArea: '1 / 1', fontWeight: checked ? 500 : 400 }}>{label}</span>\n </span>\n )}\n </label>\n );\n}\n","'use client';\n\nimport { type CSSProperties } from 'react';\nimport { cn } from '../../lib/cn';\nimport { SRadio, type SRadioValue } from './SRadio';\n\nexport interface SRadioOption {\n /** 옵션 값 (sd-radio-group SRadioOption.value) */\n value: SRadioValue;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SRadioGroupProps {\n /** 옵션 목록 */\n options?: SRadioOption[];\n /** 현재 선택 값 */\n value?: SRadioValue | null;\n /** 배치 방향 */\n direction?: 'vertical' | 'horizontal';\n /** 전체 비활성 */\n disabled?: boolean;\n /** 라디오 name 속성 (form-agnostic 그룹핑) */\n groupName?: string;\n /** 선택 변경 (sdUpdate) */\n onValueChange?: (val: SRadioValue) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/** SRadioGroup — sd-radio-group 포팅. options를 SRadio로 렌더. */\nexport function SRadioGroup({\n options = [],\n value,\n direction = 'vertical',\n disabled = false,\n groupName,\n onValueChange,\n className,\n style,\n}: SRadioGroupProps) {\n return (\n <div\n role=\"radiogroup\"\n className={cn(\n 'inline-flex',\n direction === 'vertical'\n ? 'flex-col gap-[var(--cmp-radio-group-gap-vertical)]'\n : 'flex-row gap-[var(--cmp-radio-group-gap-horizontal)]',\n className,\n )}\n style={style}\n >\n {options.map(o => (\n <SRadio\n key={String(o.value)}\n val={o.value}\n value={value}\n label={o.label}\n name={groupName}\n disabled={disabled || o.disabled}\n onValueChange={onValueChange}\n />\n ))}\n </div>\n );\n}\n"]}
@@ -120,7 +120,7 @@ function SRadioGroup({
120
120
  role: "radiogroup",
121
121
  className: cn(
122
122
  "inline-flex",
123
- direction === "vertical" ? "flex-col gap-[8px]" : "flex-row gap-[20px]",
123
+ direction === "vertical" ? "flex-col gap-[var(--cmp-radio-group-gap-vertical)]" : "flex-row gap-[var(--cmp-radio-group-gap-horizontal)]",
124
124
  className
125
125
  ),
126
126
  style,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/cn.ts","../../../src/components/SRadio/SRadio.tsx","../../../src/components/SRadio/SRadioGroup.tsx"],"names":["jsx"],"mappings":";;;;;AAQA,IAAM,UAAU,mBAAA,CAAoB;AAAA,EAClC,MAAA,EAAQ;AAAA,IACN,WAAA,EAAa;AAAA,MACX,aAAa,CAAC,EAAE,IAAA,EAAM,CAAC,MAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAA,EAAM,MAAM,IAAA,EAAM,IAAI,GAAG;AAAA;AAC5F;AAEJ,CAAC,CAAA;AAMM,SAAS,MAAM,MAAA,EAA8B;AAClD,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACIO,SAAS,MAAA,CAAO;AAAA,EACrB,GAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,IAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAgB;AAEd,EAAA,MAAM,MAAA,GAAS,OAAO,GAAG,CAAA;AACzB,EAAA,MAAM,UAAU,KAAA,KAAU,GAAA;AAC1B,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,OAAA,kBAAyB,GAAG,CAAA;AAAA,EAChD,CAAA;AAKA,EAAA,MAAM,MAAA,GAAS,IAAA,IAAQ,IAAA,IAAQ,IAAA,KAAS,EAAA;AAGxC,EAAA,MAAM,qBAAA,GAA0D,MAAA,GAC5D,EAAC,GACD;AAAA,IACE,MAAA,EAAQ,OAAA;AAAA,IACR,cAAA,EAAgB,OAAA;AAAA,IAChB,UAAA,EAAY,WAAW,EAAA,GAAK,CAAA;AAAA,IAC5B,SAAA,EAAW,MAAA;AAAA,IACX,aAAa,CAAA,CAAA,KAAK;AAChB,MAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,GAAA,IAAO,CAAA,CAAE,QAAQ,OAAA,EAAS;AACtC,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,MAAA,EAAO;AAAA,MACT;AAAA,IACF;AAAA,GACF;AAEJ,EAAA,uBACE,IAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACE,GAAG,qBAAA;AAAA,MACJ,SAAA,EAAW,EAAA;AAAA,QACT,oCAAA;AAAA,QACA,WAAW,oBAAA,GAAuB,gBAAA;AAAA,QAClC;AAAA,OACF;AAAA,MACA,KAAA;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,MAAA,oBACC,GAAA;AAAA,UAAC,OAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,OAAA;AAAA,YACL,IAAA;AAAA,YACA,KAAA,EAAO,MAAA;AAAA,YACP,OAAA;AAAA,YACA,QAAA;AAAA,YAGA,QAAA,EAAU,MAAM,aAAA,GAAgB,GAAG,CAAA;AAAA,YACnC,SAAA,EAAU;AAAA;AAAA,SACZ;AAAA,wBAEF,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,EAAA;AAAA,cACT,qJAAA;AAAA,cACA,CAAC,QAAA,IACC,CAAC,OAAA,IACD;AAAA,aACJ;AAAA,YACA,KAAA,EACE;AAAA,cACE,SAAA,EAAW,WAAW,8BAAA,GAAiC,6BAAA;AAAA,cACvD,aAAA,EAAe,QAAA,GACX,kCAAA,GACA,OAAA,GACE,gCAAA,GACA;AAAA,aACR;AAAA,YAGD,QAAA,EAAA,OAAA,oBACC,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAU,gCAAA;AAAA,gBACV,KAAA,EAAO;AAAA,kBACL,UAAA,EAAY,WACR,+BAAA,GACA;AAAA;AACN;AAAA;AACF;AAAA,SAEJ;AAAA,QACC,KAAA,oBACC,IAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,iCAAA;AAAA,YACV,KAAA,EAAO;AAAA,cACL,KAAA,EAAO,WAAW,iCAAA,GAAoC;AAAA,aACxD;AAAA,YAEA,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAW,IAAA,EAAC,SAAA,EAAU,uBAAA,EAAwB,OAAO,EAAE,QAAA,EAAU,OAAA,EAAQ,EAC5E,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,8BACA,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAO,EAAE,QAAA,EAAU,OAAA,EAAS,UAAA,EAAY,OAAA,GAAU,GAAA,GAAM,GAAA,EAAI,EAAI,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA;AAC9E;AAAA;AAAA,GAEJ;AAEJ;ACpGO,SAAS,WAAA,CAAY;AAAA,EAC1B,UAAU,EAAC;AAAA,EACX,KAAA;AAAA,EACA,SAAA,GAAY,UAAA;AAAA,EACZ,QAAA,GAAW,KAAA;AAAA,EACX,SAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,YAAA;AAAA,MACL,SAAA,EAAW,EAAA;AAAA,QACT,aAAA;AAAA,QACA,SAAA,KAAc,aAAa,oBAAA,GAAuB,qBAAA;AAAA,QAClD;AAAA,OACF;AAAA,MACA,KAAA;AAAA,MAEC,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAA,qBACXA,GAAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UAEC,KAAK,CAAA,CAAE,KAAA;AAAA,UACP,KAAA;AAAA,UACA,OAAO,CAAA,CAAE,KAAA;AAAA,UACT,IAAA,EAAM,SAAA;AAAA,UACN,QAAA,EAAU,YAAY,CAAA,CAAE,QAAA;AAAA,UACxB;AAAA,SAAA;AAAA,QANK,MAAA,CAAO,EAAE,KAAK;AAAA,OAQtB;AAAA;AAAA,GACH;AAEJ","file":"SRadioGroup.js","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * theme.css 의 --text-* 는 기본 Tailwind 폰트사이즈 스케일(xs/sm/base...)이 아닌\n * 숫자 스케일(10~32)이라, 확장 없이는 tailwind-merge 가 이를 텍스트 컬러 그룹으로\n * 오인해 text-12 같은 클래스를 text-(--color-var) 뒤에서 충돌 제거해버린다.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['10', '11', '12', '13', '14', '16', '18', '20', '24', '28', '32'] }],\n },\n },\n});\n\n/**\n * className 병합 유틸.\n * clsx로 조건부 클래스를 합치고, tailwind-merge로 Tailwind 클래스 충돌을 해소한다.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","'use client';\n\nimport { type CSSProperties, type HTMLAttributes } from 'react';\nimport { cn } from '../../lib/cn';\n\n/** 라디오 값 타입 (sd-radio SRadioValue) */\nexport type SRadioValue = string | number | boolean;\n\nexport interface SRadioProps {\n /** 이 라디오의 값 */\n val: SRadioValue;\n /** 그룹의 현재 선택 값 */\n value?: SRadioValue | null;\n /** 라벨 */\n label?: string;\n /** 비활성 */\n disabled?: boolean;\n /** native radio name (form-agnostic 그룹핑) */\n name?: string;\n /** 선택 변경 (sdUpdate) — 선택된 val 전달 */\n onValueChange?: (val: SRadioValue) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/** SRadio — sd-radio 포팅. value===val 이면 선택. 단독 또는 SRadioGroup 안에서 사용. */\nexport function SRadio({\n val,\n value,\n label,\n disabled = false,\n name,\n onValueChange,\n className,\n style,\n}: SRadioProps) {\n // key/name 속성용 문자열 표현\n const valStr = String(val);\n const checked = value === val;\n const select = () => {\n if (!disabled && !checked) onValueChange?.(val);\n };\n\n // name 이 있으면 네이티브 <input type=\"radio\"> 가 실제 상호작용 컨트롤이 된다.\n // 이때 label 에는 role/tabIndex/키핸들러를 주지 않는다 — 상호작용 요소 중첩\n // (role=\"radio\" 안에 native radio) 및 radio 역할 중복을 피한다.\n const native = name != null && name !== '';\n\n // native 모드가 아니면 label 자체가 커스텀 radio 로 동작한다.\n const labelInteractiveProps: HTMLAttributes<HTMLLabelElement> = native\n ? {}\n : {\n 'role': 'radio',\n 'aria-checked': checked,\n 'tabIndex': disabled ? -1 : 0,\n 'onClick': select,\n 'onKeyDown': e => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n select();\n }\n },\n };\n\n return (\n <label\n {...labelInteractiveProps}\n className={cn(\n 'inline-flex items-center gap-[8px]',\n disabled ? 'cursor-not-allowed' : 'cursor-pointer',\n className,\n )}\n style={style}\n >\n {native && (\n <input\n type=\"radio\"\n name={name}\n value={valStr}\n checked={checked}\n disabled={disabled}\n // 네이티브 라디오가 포커스/키보드/선택을 담당한다. label 이 감싸므로\n // 라벨 클릭도 이 input 을 토글하며, onChange 는 값이 실제로 바뀔 때만 발생.\n onChange={() => onValueChange?.(val)}\n className=\"sr-only\"\n />\n )}\n <span\n className={cn(\n 'flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-full border border-solid border-[color:var(--rd-border)] bg-[var(--rd-bg)]',\n !disabled &&\n !checked &&\n 'hover:border-[color:var(--cmp-radio-border-hover)] hover:bg-[var(--cmp-radio-bg-hover)]',\n )}\n style={\n {\n '--rd-bg': disabled ? 'var(--cmp-radio-bg-disabled)' : 'var(--cmp-radio-bg-default)',\n '--rd-border': disabled\n ? 'var(--cmp-radio-border-disabled)'\n : checked\n ? 'var(--cmp-radio-border-active)'\n : 'var(--cmp-radio-border-default)',\n } as CSSProperties\n }\n >\n {checked && (\n <span\n className=\"h-[10px] w-[10px] rounded-full\"\n style={{\n background: disabled\n ? 'var(--cmp-radio-dot-disabled)'\n : 'var(--cmp-radio-dot-default)',\n }}\n />\n )}\n </span>\n {label && (\n <span\n className=\"grid text-[12px] leading-[20px]\"\n style={{\n color: disabled ? 'var(--cmp-radio-label-disabled)' : 'var(--cmp-radio-label-default)',\n }}\n >\n <span aria-hidden className=\"invisible font-medium\" style={{ gridArea: '1 / 1' }}>\n {label}\n </span>\n <span style={{ gridArea: '1 / 1', fontWeight: checked ? 500 : 400 }}>{label}</span>\n </span>\n )}\n </label>\n );\n}\n","'use client';\n\nimport { type CSSProperties } from 'react';\nimport { cn } from '../../lib/cn';\nimport { SRadio, type SRadioValue } from './SRadio';\n\nexport interface SRadioOption {\n /** 옵션 값 (sd-radio-group SRadioOption.value) */\n value: SRadioValue;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SRadioGroupProps {\n /** 옵션 목록 */\n options?: SRadioOption[];\n /** 현재 선택 값 */\n value?: SRadioValue | null;\n /** 배치 방향 */\n direction?: 'vertical' | 'horizontal';\n /** 전체 비활성 */\n disabled?: boolean;\n /** 라디오 name 속성 (form-agnostic 그룹핑) */\n groupName?: string;\n /** 선택 변경 (sdUpdate) */\n onValueChange?: (val: SRadioValue) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/** SRadioGroup — sd-radio-group 포팅. options를 SRadio로 렌더. */\nexport function SRadioGroup({\n options = [],\n value,\n direction = 'vertical',\n disabled = false,\n groupName,\n onValueChange,\n className,\n style,\n}: SRadioGroupProps) {\n return (\n <div\n role=\"radiogroup\"\n className={cn(\n 'inline-flex',\n direction === 'vertical' ? 'flex-col gap-[8px]' : 'flex-row gap-[20px]',\n className,\n )}\n style={style}\n >\n {options.map(o => (\n <SRadio\n key={String(o.value)}\n val={o.value}\n value={value}\n label={o.label}\n name={groupName}\n disabled={disabled || o.disabled}\n onValueChange={onValueChange}\n />\n ))}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../src/lib/cn.ts","../../../src/components/SRadio/SRadio.tsx","../../../src/components/SRadio/SRadioGroup.tsx"],"names":["jsx"],"mappings":"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","file":"SRadioGroup.js","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * theme.css 의 --text-* 는 기본 Tailwind 폰트사이즈 스케일(xs/sm/base...)이 아닌\n * 숫자 스케일(10~32)이라, 확장 없이는 tailwind-merge 가 이를 텍스트 컬러 그룹으로\n * 오인해 text-12 같은 클래스를 text-(--color-var) 뒤에서 충돌 제거해버린다.\n */\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [{ text: ['10', '11', '12', '13', '14', '16', '18', '20', '24', '28', '32'] }],\n },\n },\n});\n\n/**\n * className 병합 유틸.\n * clsx로 조건부 클래스를 합치고, tailwind-merge로 Tailwind 클래스 충돌을 해소한다.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","'use client';\n\nimport { type CSSProperties, type HTMLAttributes } from 'react';\nimport { cn } from '../../lib/cn';\n\n/** 라디오 값 타입 (sd-radio SRadioValue) */\nexport type SRadioValue = string | number | boolean;\n\nexport interface SRadioProps {\n /** 이 라디오의 값 */\n val: SRadioValue;\n /** 그룹의 현재 선택 값 */\n value?: SRadioValue | null;\n /** 라벨 */\n label?: string;\n /** 비활성 */\n disabled?: boolean;\n /** native radio name (form-agnostic 그룹핑) */\n name?: string;\n /** 선택 변경 (sdUpdate) — 선택된 val 전달 */\n onValueChange?: (val: SRadioValue) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/** SRadio — sd-radio 포팅. value===val 이면 선택. 단독 또는 SRadioGroup 안에서 사용. */\nexport function SRadio({\n val,\n value,\n label,\n disabled = false,\n name,\n onValueChange,\n className,\n style,\n}: SRadioProps) {\n // key/name 속성용 문자열 표현\n const valStr = String(val);\n const checked = value === val;\n const select = () => {\n if (!disabled && !checked) onValueChange?.(val);\n };\n\n // name 이 있으면 네이티브 <input type=\"radio\"> 가 실제 상호작용 컨트롤이 된다.\n // 이때 label 에는 role/tabIndex/키핸들러를 주지 않는다 — 상호작용 요소 중첩\n // (role=\"radio\" 안에 native radio) 및 radio 역할 중복을 피한다.\n const native = name != null && name !== '';\n\n // native 모드가 아니면 label 자체가 커스텀 radio 로 동작한다.\n const labelInteractiveProps: HTMLAttributes<HTMLLabelElement> = native\n ? {}\n : {\n 'role': 'radio',\n 'aria-checked': checked,\n 'tabIndex': disabled ? -1 : 0,\n 'onClick': select,\n 'onKeyDown': e => {\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n select();\n }\n },\n };\n\n return (\n <label\n {...labelInteractiveProps}\n className={cn(\n 'inline-flex items-center gap-[8px]',\n disabled ? 'cursor-not-allowed' : 'cursor-pointer',\n className,\n )}\n style={style}\n >\n {native && (\n <input\n type=\"radio\"\n name={name}\n value={valStr}\n checked={checked}\n disabled={disabled}\n // 네이티브 라디오가 포커스/키보드/선택을 담당한다. label 이 감싸므로\n // 라벨 클릭도 이 input 을 토글하며, onChange 는 값이 실제로 바뀔 때만 발생.\n onChange={() => onValueChange?.(val)}\n className=\"sr-only\"\n />\n )}\n <span\n className={cn(\n 'flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-full border border-solid border-[color:var(--rd-border)] bg-[var(--rd-bg)]',\n !disabled &&\n !checked &&\n 'hover:border-[color:var(--cmp-radio-border-hover)] hover:bg-[var(--cmp-radio-bg-hover)]',\n )}\n style={\n {\n '--rd-bg': disabled ? 'var(--cmp-radio-bg-disabled)' : 'var(--cmp-radio-bg-default)',\n '--rd-border': disabled\n ? 'var(--cmp-radio-border-disabled)'\n : checked\n ? 'var(--cmp-radio-border-active)'\n : 'var(--cmp-radio-border-default)',\n } as CSSProperties\n }\n >\n {checked && (\n <span\n className=\"h-[10px] w-[10px] rounded-full\"\n style={{\n background: disabled\n ? 'var(--cmp-radio-dot-disabled)'\n : 'var(--cmp-radio-dot-default)',\n }}\n />\n )}\n </span>\n {label && (\n <span\n className=\"grid text-[12px] leading-[20px]\"\n style={{\n color: disabled ? 'var(--cmp-radio-label-disabled)' : 'var(--cmp-radio-label-default)',\n }}\n >\n <span aria-hidden className=\"invisible font-medium\" style={{ gridArea: '1 / 1' }}>\n {label}\n </span>\n <span style={{ gridArea: '1 / 1', fontWeight: checked ? 500 : 400 }}>{label}</span>\n </span>\n )}\n </label>\n );\n}\n","'use client';\n\nimport { type CSSProperties } from 'react';\nimport { cn } from '../../lib/cn';\nimport { SRadio, type SRadioValue } from './SRadio';\n\nexport interface SRadioOption {\n /** 옵션 값 (sd-radio-group SRadioOption.value) */\n value: SRadioValue;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SRadioGroupProps {\n /** 옵션 목록 */\n options?: SRadioOption[];\n /** 현재 선택 값 */\n value?: SRadioValue | null;\n /** 배치 방향 */\n direction?: 'vertical' | 'horizontal';\n /** 전체 비활성 */\n disabled?: boolean;\n /** 라디오 name 속성 (form-agnostic 그룹핑) */\n groupName?: string;\n /** 선택 변경 (sdUpdate) */\n onValueChange?: (val: SRadioValue) => void;\n className?: string;\n style?: CSSProperties;\n}\n\n/** SRadioGroup — sd-radio-group 포팅. options를 SRadio로 렌더. */\nexport function SRadioGroup({\n options = [],\n value,\n direction = 'vertical',\n disabled = false,\n groupName,\n onValueChange,\n className,\n style,\n}: SRadioGroupProps) {\n return (\n <div\n role=\"radiogroup\"\n className={cn(\n 'inline-flex',\n direction === 'vertical'\n ? 'flex-col gap-[var(--cmp-radio-group-gap-vertical)]'\n : 'flex-row gap-[var(--cmp-radio-group-gap-horizontal)]',\n className,\n )}\n style={style}\n >\n {options.map(o => (\n <SRadio\n key={String(o.value)}\n val={o.value}\n value={value}\n label={o.label}\n name={groupName}\n disabled={disabled || o.disabled}\n onValueChange={onValueChange}\n />\n ))}\n </div>\n );\n}\n"]}
@@ -3091,7 +3091,8 @@ var HIDE_DELAY_MS = 100;
3091
3091
  function useBody(content, message = []) {
3092
3092
  if (content != null) return content;
3093
3093
  if (message.length === 0) return null;
3094
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: line }, i)) });
3094
+ const singleLine = message.length === 1;
3095
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: message.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: singleLine ? "leading-[24px]" : void 0, children: line }, i)) });
3095
3096
  }
3096
3097
  var STooltip = react.forwardRef(function STooltip2({
3097
3098
  content,
@@ -3194,11 +3195,17 @@ var STooltip = react.forwardRef(function STooltip2({
3194
3195
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-[12px]", children: [
3195
3196
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: body }),
3196
3197
  useClose && /* @__PURE__ */ jsxRuntime.jsx(
3197
- RPopover2__namespace.Close,
3198
+ SGhostButton,
3198
3199
  {
3199
- "aria-label": "\uB2EB\uAE30",
3200
- className: "shrink-0 cursor-pointer opacity-70 hover:opacity-100",
3201
- children: /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "close", size: 16, color: fg })
3200
+ icon: "close",
3201
+ size: "xs",
3202
+ intent: tooltipType === "default" ? "inverse" : "default",
3203
+ ariaLabel: "\uB2EB\uAE30",
3204
+ className: "shrink-0",
3205
+ onClick: () => {
3206
+ cancelHide();
3207
+ setOpen(false);
3208
+ }
3202
3209
  }
3203
3210
  )
3204
3211
  ] }),
@@ -3236,8 +3243,8 @@ function useFormField(field) {
3236
3243
  }, [ctx, name]);
3237
3244
  }
3238
3245
  var FIELD_SIZE = {
3239
- sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 12 },
3240
- md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 12 }
3246
+ sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
3247
+ md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
3241
3248
  };
3242
3249
  var ALIGN = {
3243
3250
  start: "flex-start",
@@ -3252,6 +3259,7 @@ var SField = react.forwardRef(function SField2({
3252
3259
  labelTooltip = "",
3253
3260
  labelTooltipProps,
3254
3261
  labelWidth,
3262
+ labelHeight,
3255
3263
  size = "sm",
3256
3264
  addonLabel = "",
3257
3265
  addonAlign = "start",
@@ -3266,6 +3274,7 @@ var SField = react.forwardRef(function SField2({
3266
3274
  readOnly = false,
3267
3275
  width,
3268
3276
  multiline = false,
3277
+ borderless = false,
3269
3278
  children,
3270
3279
  className,
3271
3280
  style,
@@ -3299,8 +3308,8 @@ var SField = react.forwardRef(function SField2({
3299
3308
  const resolvedSuccess = status === "pass";
3300
3309
  const showError = resolvedError && errorMessage !== "";
3301
3310
  const interactive = !disabled && !readOnly;
3302
- const borderColor = disabled ? "var(--color-grey-45)" : interactive && focused ? "var(--sys-color-field-border-focus)" : resolvedSuccess ? "var(--sys-color-field-border-success)" : resolvedError ? "var(--sys-color-field-border-danger)" : "var(--sys-color-field-border-default)";
3303
- const bgColor = disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
3311
+ const borderColor = borderless ? "transparent" : disabled ? "var(--color-grey-45)" : interactive && focused ? "var(--sys-color-field-border-focus)" : resolvedSuccess ? "var(--sys-color-field-border-success)" : resolvedError ? "var(--sys-color-field-border-danger)" : "var(--sys-color-field-border-default)";
3312
+ const bgColor = borderless ? "transparent" : disabled ? "var(--color-grey-30)" : readOnly ? "var(--sys-color-field-bg-readOnly)" : "var(--sys-color-field-bg-default)";
3304
3313
  const textColor = disabled ? "var(--color-grey-65)" : readOnly ? "var(--sys-color-field-text-readOnly)" : "var(--sys-color-field-text-default)";
3305
3314
  return /* @__PURE__ */ jsxRuntime.jsx(
3306
3315
  "div",
@@ -3317,7 +3326,7 @@ var SField = react.forwardRef(function SField2({
3317
3326
  {
3318
3327
  className: "flex shrink-0 items-center font-bold text-(--sys-color-field-text-default)",
3319
3328
  style: {
3320
- height: s.height,
3329
+ height: cssLen(labelHeight) ?? s.height,
3321
3330
  marginRight: s.fieldGap,
3322
3331
  width: cssLen(labelWidth),
3323
3332
  fontSize: s.fontSize,
@@ -3343,14 +3352,14 @@ var SField = react.forwardRef(function SField2({
3343
3352
  {
3344
3353
  className: cn(
3345
3354
  "relative box-border flex min-w-0 items-stretch overflow-hidden border border-solid border-(--field-bc)",
3346
- interactive && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
3355
+ interactive && !borderless && "hover:border-(--sys-color-field-border-focus) hover:shadow-[0px_0px_4px_0px_#0071ff66] focus-within:border-(--sys-color-field-border-focus) focus-within:shadow-[0px_0px_4px_0px_#0071ff66]",
3347
3356
  disabled && "cursor-not-allowed"
3348
3357
  ),
3349
3358
  style: {
3350
3359
  // @ts-expect-error CSS 변수
3351
3360
  "--field-bc": borderColor,
3352
3361
  // focused/hovered prop이 명시된 경우 강조를 즉시 반영
3353
- ...interactive && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
3362
+ ...interactive && !borderless && focused ? { boxShadow: "0px 0px 4px 0px #0071ff66" } : {},
3354
3363
  ...multiline ? { minHeight: s.height } : { height: s.height },
3355
3364
  "width": cssLen(width),
3356
3365
  "borderRadius": s.radius,
@@ -3395,15 +3404,28 @@ function flattenOptions(options, depth = 1) {
3395
3404
  const out = [];
3396
3405
  for (const o of options) {
3397
3406
  const hasChildren = Array.isArray(o.children) && o.children.length > 0;
3398
- out.push({
3399
- value: String(o.value),
3400
- label: o.label,
3401
- disabled: !!o.disabled,
3402
- depth,
3403
- isGroup: hasChildren,
3404
- raw: o.value
3405
- });
3406
- if (hasChildren) out.push(...flattenOptions(o.children, depth + 1));
3407
+ if (hasChildren) {
3408
+ const childFlat = flattenOptions(o.children, depth + 1);
3409
+ const allChildrenDisabled = childFlat.every((c) => c.disabled);
3410
+ out.push({
3411
+ value: String(o.value),
3412
+ label: o.label,
3413
+ disabled: !!o.disabled || allChildrenDisabled,
3414
+ depth,
3415
+ isGroup: true,
3416
+ raw: o.value
3417
+ });
3418
+ out.push(...childFlat);
3419
+ } else {
3420
+ out.push({
3421
+ value: String(o.value),
3422
+ label: o.label,
3423
+ disabled: !!o.disabled,
3424
+ depth,
3425
+ isGroup: false,
3426
+ raw: o.value
3427
+ });
3428
+ }
3407
3429
  }
3408
3430
  return out;
3409
3431
  }
@@ -3527,6 +3549,9 @@ var SSelect = react.forwardRef(function SSelect2({
3527
3549
  );
3528
3550
  const flat = react.useMemo(() => flattenOptions(options), [options]);
3529
3551
  const selectable = react.useMemo(() => selectableOptions(flat), [flat]);
3552
+ const hasLeaf = react.useMemo(() => flat.some((o) => !o.isGroup), [flat]);
3553
+ const allOptionsDisabled = hasLeaf && selectable.length === 0;
3554
+ const effectiveDisabled = disabled || allOptionsDisabled;
3530
3555
  const showSearch = useSearch && selectable.length >= SEARCH_THRESHOLD;
3531
3556
  const labelByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.label])), [flat]);
3532
3557
  const rawByValue = react.useMemo(() => new Map(flat.map((o) => [o.value, o.raw])), [flat]);
@@ -3593,10 +3618,10 @@ var SSelect = react.forwardRef(function SSelect2({
3593
3618
  Ariakit__namespace.Select,
3594
3619
  {
3595
3620
  ref: triggerRef,
3596
- disabled,
3621
+ disabled: effectiveDisabled,
3597
3622
  className: "flex h-full w-full cursor-pointer items-center justify-between gap-[8px] bg-transparent px-[12px] text-left text-[12px] leading-[20px] outline-none disabled:cursor-not-allowed",
3598
3623
  style: {
3599
- color: disabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
3624
+ color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
3600
3625
  },
3601
3626
  children: [
3602
3627
  isHtmlLabel(triggerText) ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -3611,7 +3636,7 @@ var SSelect = react.forwardRef(function SSelect2({
3611
3636
  {
3612
3637
  name: "chevronDown",
3613
3638
  size: 12,
3614
- color: disabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
3639
+ color: effectiveDisabled ? "var(--cmp-select-icon-disabled)" : "var(--cmp-select-icon-default)",
3615
3640
  className: cn("shrink-0 transition-transform duration-200", open && "rotate-180")
3616
3641
  }
3617
3642
  )
@@ -3625,7 +3650,7 @@ var SSelect = react.forwardRef(function SSelect2({
3625
3650
  portalElement: portalContainer,
3626
3651
  gutter: 4,
3627
3652
  sameWidth: !dropdownWidth,
3628
- className: "z-50 overflow-auto rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)] data-[enter]:animate-floating-in-bottom data-[leave]:animate-floating-out-bottom",
3653
+ className: "z-50 overflow-auto rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)] data-[enter]:animate-floating-in-bottom data-[leave]:animate-floating-out-bottom",
3629
3654
  style: {
3630
3655
  maxHeight: dropdownHeight,
3631
3656
  ...dropdownWidth ? { width: dropdownWidth } : {},
@@ -3666,7 +3691,7 @@ var SSelect = react.forwardRef(function SSelect2({
3666
3691
  ),
3667
3692
  hasItems ? /* @__PURE__ */ jsxRuntime.jsx(ItemList, { items: filtered, multi, selected, useSearch: showSearch }) : (
3668
3693
  // 원본 sd-select-listbox__empty (표시할 항목이 없을 때)
3669
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[12px] py-[12px] text-center text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
3694
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
3670
3695
  )
3671
3696
  ]
3672
3697
  }
@@ -3689,7 +3714,7 @@ var SSelect = react.forwardRef(function SSelect2({
3689
3714
  error: error || ruleError !== "",
3690
3715
  status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
3691
3716
  errorMessage: ruleError !== "" ? ruleError : errorMessage,
3692
- disabled,
3717
+ disabled: effectiveDisabled,
3693
3718
  width,
3694
3719
  className,
3695
3720
  style,
@@ -3724,7 +3749,11 @@ function ItemList({
3724
3749
  {
3725
3750
  className: cn(
3726
3751
  "select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
3727
- isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium"
3752
+ isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium",
3753
+ // 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
3754
+ // 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
3755
+ o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
3756
+ o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
3728
3757
  ),
3729
3758
  style: { paddingLeft: padLeft },
3730
3759
  children: o.label
@@ -3738,10 +3767,14 @@ function ItemList({
3738
3767
  {
3739
3768
  value: o.value,
3740
3769
  disabled: o.disabled,
3770
+ accessibleWhenDisabled: true,
3741
3771
  className: cn(
3742
3772
  itemBase,
3743
3773
  isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
3744
- activeClass
3774
+ // Ariakit은 disabled 항목도 hover 시 active(data-active-item) 처리하므로,
3775
+ // 비활성 항목에는 hover 하이라이트를 적용하지 않아 회색 비활성 스타일을 유지한다.
3776
+ // (원본 Stencil의 `--focused...:not(--disabled)` 규칙과 동일한 의도)
3777
+ !o.disabled && activeClass
3745
3778
  ),
3746
3779
  style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
3747
3780
  render: useSearch ? /* @__PURE__ */ jsxRuntime.jsx(Ariakit__namespace.ComboboxItem, {}) : void 0,
@@ -3751,15 +3784,21 @@ function ItemList({
3751
3784
  "span",
3752
3785
  {
3753
3786
  className: cn(
3754
- "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
3755
- isSelected ? "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)] group-data-[active-item]:bg-transparent" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-transparent"
3787
+ "flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
3788
+ o.disabled ? (
3789
+ // 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
3790
+ "cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
3791
+ ) : cn(
3792
+ "group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
3793
+ isSelected ? "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)] group-data-[active-item]:bg-transparent" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-transparent"
3794
+ )
3756
3795
  ),
3757
3796
  children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
3758
3797
  SIcon,
3759
3798
  {
3760
3799
  name: "checkboxCheck",
3761
3800
  size: 12,
3762
- color: "var(--cmp-checkbox-checked-icon-default)"
3801
+ color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
3763
3802
  }
3764
3803
  )
3765
3804
  }