@wishket/design-system 3.4.2 → 3.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.
- package/dist/Components/Base/Typography/Typography.d.ts +0 -9
- package/dist/Components/Base/Typography/Typography.js +2 -2
- package/dist/Components/DataDisplays/ImageLabel/ImageLabel.js +1 -1
- package/dist/Components/Feedbacks/DialogBox/DialogBox.js +6 -6
- package/dist/Components/Feedbacks/GlobalLoadingIndicator/GlobalLoadingIndicator.js +1 -1
- package/dist/Components/Feedbacks/Tooltip/Tooltip.js +3 -3
- package/dist/Components/Inputs/AutoCompleteList/AutoCompleteList.d.ts +2 -2
- package/dist/Components/Inputs/AutoCompleteList/AutoCompleteList.js +22 -7
- package/dist/Components/Inputs/AutoCompleteList/AutoCompleteList.types.d.ts +17 -0
- package/dist/Components/Inputs/Autocomplete/Autocomplete.d.ts +3 -1
- package/dist/Components/Inputs/Autocomplete/Autocomplete.js +28 -5
- package/dist/Components/Inputs/Autocomplete/Autocomplete.types.d.ts +18 -0
- package/dist/Components/Inputs/Checkbox/Checkbox.js +4 -4
- package/dist/Components/Inputs/Checkbox/Checkbox.parts.js +3 -3
- package/dist/Components/Inputs/Checkbox/Checkbox.types.d.ts +0 -1
- package/dist/Components/Inputs/CheckboxCard/CheckboxCard.js +4 -4
- package/dist/Components/Inputs/CheckboxCard/CheckboxCard.parts.js +4 -4
- package/dist/Components/Inputs/FileUploader/FileUploader.js +4 -4
- package/dist/Components/Inputs/IconButtonDropdown/IconButtonDropdown.js +4 -4
- package/dist/Components/Inputs/Input/Input.js +1 -1
- package/dist/Components/Inputs/Input/PasswordInput.js +3 -3
- package/dist/Components/Inputs/InputChip/InputChip.d.ts +16 -3
- package/dist/Components/Inputs/InputChip/InputChip.js +13 -4
- package/dist/Components/Inputs/Radio/Radio.js +5 -5
- package/dist/Components/Inputs/RadioCard/RadioCard.js +5 -5
- package/dist/Components/Inputs/RadioCard/RadioCard.parts.js +4 -4
- package/dist/Components/Inputs/RangeSlider/RangeSlider.js +2 -2
- package/dist/Components/Inputs/SearchField/SearchField.js +5 -5
- package/dist/Components/Inputs/TextField/TextField.js +1 -1
- package/dist/Components/Inputs/TextFieldDropdown/TextFieldDropdown.d.ts +24 -3
- package/dist/Components/Inputs/TextFieldDropdown/TextFieldDropdown.js +10 -54
- package/dist/Components/Inputs/TextFieldDropdown/TextFieldDropdown.parts.d.ts +9 -0
- package/dist/Components/Inputs/TextFieldDropdown/TextFieldDropdown.parts.js +1 -1
- package/dist/Components/Inputs/TextFieldTrigger/TextFieldTrigger.d.ts +73 -0
- package/dist/Components/Inputs/TextFieldTrigger/TextFieldTrigger.js +62 -0
- package/dist/Components/Inputs/TextFieldTrigger/index.d.ts +2 -0
- package/dist/Components/Inputs/Textarea/Textarea.js +4 -4
- package/dist/Components/Inputs/index.d.ts +1 -0
- package/dist/Components/Navigations/Drawer/Drawer.js +3 -3
- package/dist/Components/Navigations/Menu/MenuBase.js +3 -3
- package/dist/Components/Utils/BackDrop/BackDrop.js +1 -1
- package/dist/Components/Utils/BackDropLiftContainer/BackDropLiftContainer.js +2 -2
- package/dist/Components/Utils/BottomModalContainer/BottomModalContainer.js +1 -1
- package/dist/Components/Utils/FullModalContainer/FullModalContainer.js +1 -1
- package/dist/Components/Utils/Modal/Modal.js +3 -3
- package/dist/Components/Utils/ModalContainer/ModalContainer.js +2 -2
- package/dist/Components/Wrappers/WithBadge/WithBadge.js +2 -2
- package/dist/Components/Wrappers/WithSnackBar/WithSnackBar.js +3 -3
- package/dist/cjs/Components/Base/Typography/Typography.js +1 -1
- package/dist/cjs/Components/DataDisplays/ImageLabel/ImageLabel.js +3 -3
- package/dist/cjs/Components/Feedbacks/DialogBox/DialogBox.js +6 -6
- package/dist/cjs/Components/Feedbacks/GlobalLoadingIndicator/GlobalLoadingIndicator.js +1 -1
- package/dist/cjs/Components/Feedbacks/Tooltip/Tooltip.js +3 -3
- package/dist/cjs/Components/Inputs/AutoCompleteList/AutoCompleteList.js +22 -7
- package/dist/cjs/Components/Inputs/Autocomplete/Autocomplete.js +25 -4
- package/dist/cjs/Components/Inputs/Checkbox/Checkbox.js +4 -4
- package/dist/cjs/Components/Inputs/Checkbox/Checkbox.parts.js +5 -5
- package/dist/cjs/Components/Inputs/CheckboxCard/CheckboxCard.js +4 -4
- package/dist/cjs/Components/Inputs/CheckboxCard/CheckboxCard.parts.js +4 -4
- package/dist/cjs/Components/Inputs/FileUploader/FileUploader.js +6 -6
- package/dist/cjs/Components/Inputs/IconButtonDropdown/IconButtonDropdown.js +3 -3
- package/dist/cjs/Components/Inputs/Input/Input.js +2 -2
- package/dist/cjs/Components/Inputs/Input/PasswordInput.js +2 -2
- package/dist/cjs/Components/Inputs/InputChip/InputChip.js +36 -2
- package/dist/cjs/Components/Inputs/Radio/Radio.js +6 -6
- package/dist/cjs/Components/Inputs/RadioCard/RadioCard.js +4 -4
- package/dist/cjs/Components/Inputs/RadioCard/RadioCard.parts.js +4 -4
- package/dist/cjs/Components/Inputs/RangeSlider/RangeSlider.js +3 -3
- package/dist/cjs/Components/Inputs/SearchField/SearchField.js +3 -3
- package/dist/cjs/Components/Inputs/TextField/TextField.js +2 -2
- package/dist/cjs/Components/Inputs/TextFieldDropdown/TextFieldDropdown.js +10 -8
- package/dist/cjs/Components/Inputs/TextFieldDropdown/TextFieldDropdown.parts.js +1 -1
- package/dist/cjs/Components/Inputs/TextFieldTrigger/TextFieldTrigger.js +62 -0
- package/dist/cjs/Components/Inputs/Textarea/Textarea.js +5 -5
- package/dist/cjs/Components/Navigations/Drawer/Drawer.js +3 -3
- package/dist/cjs/Components/Navigations/Menu/MenuBase.js +3 -3
- package/dist/cjs/Components/Utils/BackDrop/BackDrop.js +1 -1
- package/dist/cjs/Components/Utils/BackDropLiftContainer/BackDropLiftContainer.js +2 -2
- package/dist/cjs/Components/Utils/BottomModalContainer/BottomModalContainer.js +1 -1
- package/dist/cjs/Components/Utils/FullModalContainer/FullModalContainer.js +1 -1
- package/dist/cjs/Components/Utils/Modal/Modal.js +2 -2
- package/dist/cjs/Components/Utils/ModalContainer/ModalContainer.js +2 -2
- package/dist/cjs/Components/Wrappers/WithBadge/WithBadge.js +1 -1
- package/dist/cjs/Components/Wrappers/WithSnackBar/WithSnackBar.js +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -2
- package/scripts/codemods/add-as-link.ts +9 -5
- package/scripts/codemods/menu-split.ts +25 -11
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{twMerge as
|
|
1
|
+
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{twMerge as r}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import{Typography as o}from"../../Base/Typography/Typography.js";import{Box as n}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"react";import{SystemIcon as a}from"../../DataDisplays/SystemIcon/SystemIcon.js";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import"../../DataDisplays/Accordion/Accordion.js";function s(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{},o=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(r).filter((function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable})))),o.forEach((function(t){s(e,t,r[t])}))}return e}function c(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):function(e){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t.push.apply(t,r)}return t}(Object(t)).forEach((function(r){Object.defineProperty(e,r,Object.getOwnPropertyDescriptor(t,r))})),e}
|
|
2
2
|
/**
|
|
3
3
|
* 삭제 가능한 칩(chip) 형태의 입력 컴포넌트입니다.
|
|
4
4
|
*
|
|
5
5
|
* @component
|
|
6
6
|
* @param {Object} props
|
|
7
7
|
* @param {React.ReactNode} props.children - 칩 내부에 표시될 콘텐츠
|
|
8
|
-
* @param {() => void} [props.onDelete] - 삭제 버튼 클릭 시 실행될 콜백
|
|
8
|
+
* @param {() => void} [props.onDelete] - 삭제 버튼 클릭 시 실행될 콜백 함수. 삭제 버튼은 `<button type="button">`으로 렌더되어 클릭뿐 아니라 키보드(Tab 포커스 + Enter/Space)로도 동작합니다.
|
|
9
9
|
* @param {string} [props.className] - 추가적인 CSS 클래스
|
|
10
|
+
* @param {string} [props.deleteLabel] - 삭제 버튼의 접근 가능한 이름. 미지정 시 `children`이 문자열이면 `"{children} 삭제"`, 아니면 `"삭제"`
|
|
11
|
+
* @param {Object} [props.deleteButtonProps] - 삭제 버튼에 직접 전달할 `id` / `tabIndex` / `onFocus`. 칩 묶음의 roving tabindex 구현용이며 단독 사용 시에는 불필요합니다.
|
|
10
12
|
*
|
|
11
13
|
* @example
|
|
12
14
|
* ```tsx
|
|
@@ -23,5 +25,12 @@
|
|
|
23
25
|
* 커스텀 스타일 태그
|
|
24
26
|
* </InputChip>
|
|
25
27
|
* ```
|
|
26
|
-
*/const
|
|
27
|
-
|
|
28
|
+
*/const l=({children:s,onDelete:l,className:p,deleteLabel:y,deleteButtonProps:m})=>{
|
|
29
|
+
// 아이콘만 있는 버튼이라 접근 가능한 이름을 명시해야 한다. children이
|
|
30
|
+
// ReactNode라 항상 텍스트는 아니므로, 문자열/숫자일 때만 칩 텍스트를 이름에
|
|
31
|
+
// 넣고 그 외(엘리먼트, 배열 등)에는 일반 라벨로 폴백한다. 임의 ReactNode에서
|
|
32
|
+
// 텍스트를 추출할 일반적인 방법은 없으므로, 그런 경우 소비자가 deleteLabel로
|
|
33
|
+
// 직접 지정한다.
|
|
34
|
+
const u="string"==typeof s||"number"==typeof s?String(s):void 0,b=null!=y?y:u?`${u} 삭제`:"삭제";/*#__PURE__*/
|
|
35
|
+
return e(n,{"data-testid":"design-system-input-chip--container",className:r("bg-w-gray-100 flex h-6 w-fit max-w-[100px] items-center gap-0.5 rounded-lg px-2 py-px select-none",!!l&&"pr-1.5 pl-2",p),children:[
|
|
36
|
+
/*#__PURE__*/t(o,{variant:"body14",className:"text-w-gray-600 h-6 w-full overflow-hidden break-all text-ellipsis whitespace-nowrap",children:s}),!!l&&/*#__PURE__*/t("button",c(i({},m),{type:"button",onClick:l,"aria-label":b,"data-testid":"design-system-input-chip--delete",className:"flex cursor-pointer items-center",children:/*#__PURE__*/t(a,{name:"small_delete",className:"text-w-gray-400"})}))]})};export{l as InputChip};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";import{jsxs as r,jsx as e}from"react/jsx-runtime";import{twMerge as t}from"tailwind-merge";import{forwardRef as o}from"react";import{Box as i}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";function a(r,e,t){return e in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r}function n(r){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},o=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(t).filter((function(r){return Object.getOwnPropertyDescriptor(t,r).enumerable})))),o.forEach((function(e){a(r,e,t[e])}))}return r}function
|
|
1
|
+
"use client";import{jsxs as r,jsx as e}from"react/jsx-runtime";import{twMerge as t}from"tailwind-merge";import{forwardRef as o}from"react";import"../../Base/Typography/Typography.js";import{Box as i}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";function a(r,e,t){return e in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r}function n(r){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},o=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(t).filter((function(r){return Object.getOwnPropertyDescriptor(t,r).enumerable})))),o.forEach((function(e){a(r,e,t[e])}))}return r}function s(r,e){if(null==r)return{};var t,o,i=function(r,e){if(null==r)return{};var t,o,i={},a=Object.keys(r);for(o=0;o<a.length;o++)t=a[o],e.indexOf(t)>=0||(i[t]=r[t]);return i}(r,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(r);for(o=0;o<a.length;o++)t=a[o],e.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(r,t)&&(i[t]=r[t])}return i}const l=({disabled:r,checked:o,isError:i})=>/*#__PURE__*/e("div",{className:t("relative box-border flex h-[18px] w-[18px] items-center justify-center rounded-full border p-[4px]",!r&&!i&&"group-focus-within:border-primary-500",
|
|
2
2
|
// 체크되었고 비활성화 상태의 경우
|
|
3
3
|
o&&r?"bg-w-white border-primary-100 cursor-not-allowed":
|
|
4
4
|
// 비활성화 상태의 경우
|
|
@@ -8,10 +8,10 @@ o&&!i?"bg-w-white border-primary-500":
|
|
|
8
8
|
// 활성화 상태에서 체크되었고 오류가 있는 경우
|
|
9
9
|
o&&i?"bg-w-white border-w-red-500":
|
|
10
10
|
// 활성화 상태에서 체크되지 않았고 오류가 있는 경우
|
|
11
|
-
!o&&i?"border-w-red-500":"bg-white border-w-gray-200 group-hover:border-primary-500 cursor-pointer"),
|
|
11
|
+
!o&&i?"border-w-red-500":"bg-white border-w-gray-200 group-hover:border-primary-500 cursor-pointer"),"data-testid":"design-system-radio-button",children:/*#__PURE__*/e("div",{className:t("bg-primary size-2 rounded-full transition-all duration-100 ease-in-out",!o&&"h-0 w-0",i&&"bg-w-red-500",r&&"bg-w-gray-200",o&&r&&"bg-primary-100")})}),d=/*#__PURE__*/o(((o,a)=>{var{value:d="",checked:c=!1,disabled:u=!1,isError:b=!1,className:p}=o,y=s(o,["value","checked","disabled","isError","className"]);/*#__PURE__*/
|
|
12
12
|
return r(i,{"data-testid":"design-system-radio",className:t("group relative cursor-pointer",p),children:[
|
|
13
|
-
/*#__PURE__*/e("input",n({ref:a,type:"radio",className:"absolute inset-0 z-10 cursor-pointer opacity-0",value:
|
|
14
|
-
/*#__PURE__*/e(
|
|
13
|
+
/*#__PURE__*/e("input",n({ref:a,type:"radio",className:"absolute inset-0 z-10 cursor-pointer opacity-0",value:d,checked:c,disabled:u},y)),
|
|
14
|
+
/*#__PURE__*/e(l,{checked:c,isError:b,disabled:u})]})}));
|
|
15
15
|
/**
|
|
16
16
|
* 사용자가 여러 옵션 중 하나를 선택할 수 있는 라디오 버튼 컴포넌트입니다.
|
|
17
17
|
*
|
|
@@ -44,4 +44,4 @@ return r(i,{"data-testid":"design-system-radio",className:t("group relative curs
|
|
|
44
44
|
* <Radio value="option5" checked={field.value === 'option5'} onChange={field.onChange} />
|
|
45
45
|
* )}
|
|
46
46
|
* />
|
|
47
|
-
*/
|
|
47
|
+
*/d.displayName="Radio";export{d as Radio};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import"react";import{twMerge as a}from"tailwind-merge";import{Typography as r}from"../../Base/Typography/Typography.js";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{RadioCardContainer as i,StyledRadio as d,RadioCardIcon as s,TitleContainer as o}from"./RadioCard.parts.js";import{useRadioCard as n}from"./useRadioCard.js";const l=l=>{const{disabled:c=!1,checked:m=!1,isError:p=!1,onChange:
|
|
2
|
-
return e("label",{"data-testid":f
|
|
3
|
-
/*#__PURE__*/e(d,{name:B,value:b,isWide:
|
|
4
|
-
/*#__PURE__*/t(o,{isWide:
|
|
5
|
-
/*#__PURE__*/e(r,{"data-testid":"design-system-radioCard--title",variant:"body16",className:a("font-medium",
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import"react";import{twMerge as a}from"tailwind-merge";import{Typography as r}from"../../Base/Typography/Typography.js";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{RadioCardContainer as i,StyledRadio as d,RadioCardIcon as s,TitleContainer as o}from"./RadioCard.parts.js";import{useRadioCard as n}from"./useRadioCard.js";const l=l=>{const{disabled:c=!1,checked:m=!1,isError:p=!1,onChange:g,isWide:h=!1,className:y,iconName:u,title:x,description:C,testId:f,value:b,name:B}=l,N=null!=u?u:h?null:"receipt",{handleChange:j}=n({checked:m,disabled:c,onChange:g});/*#__PURE__*/
|
|
2
|
+
return e("label",{"data-testid":f||"design-system-radioCard",className:"group",children:/*#__PURE__*/t(i,{"data-testid":"design-system-radioCard--container",checked:m,isError:p,isWide:h,disabled:c,className:y,children:[
|
|
3
|
+
/*#__PURE__*/e(d,{name:B,value:b,isWide:h,checked:m,onChange:j,isError:p,disabled:c}),N&&/*#__PURE__*/e(s,{iconName:N,checked:m,isError:p,disabled:c}),
|
|
4
|
+
/*#__PURE__*/t(o,{isWide:h,"data-testid":"design-system-radioCard--titleBox",children:[
|
|
5
|
+
/*#__PURE__*/e(r,{"data-testid":"design-system-radioCard--title",variant:"body16",className:a("font-medium",h?"text-left":"text-center",c?"text-w-gray-300":"text-w-gray-900"),children:x}),C&&/*#__PURE__*/e(r,{variant:"body14",className:a("font-normal",h?"text-left":"text-center",c?"text-w-gray-300":"text-w-gray-600"),"data-testid":"design-system-radioCard--description",children:C})]})]})})};
|
|
6
6
|
/**
|
|
7
7
|
* 라디오 카드 컴포넌트
|
|
8
8
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{jsx as
|
|
2
|
-
return
|
|
3
|
-
return
|
|
4
|
-
return
|
|
1
|
+
import{jsx as r}from"react/jsx-runtime";import{twMerge as e,twJoin as t}from"tailwind-merge";import"../../DataDisplays/Avatar/Avatar.js";import"../../Base/Typography/Typography.js";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"react";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import{ProductIcon as o}from"../../DataDisplays/ProductIcon/ProductIcon.js";import"../../DataDisplays/Accordion/Accordion.js";import{Radio as i}from"../Radio/Radio.js";function n(r,e,t){return e in r?Object.defineProperty(r,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):r[e]=t,r}function s(r){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},o=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(t).filter((function(r){return Object.getOwnPropertyDescriptor(t,r).enumerable})))),o.forEach((function(e){n(r,e,t[e])}))}return r}function a(r,e){return e=null!=e?e:{},Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(e)):function(r){var e=Object.keys(r);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(r);e.push.apply(e,t)}return e}(Object(e)).forEach((function(t){Object.defineProperty(r,t,Object.getOwnPropertyDescriptor(e,t))})),r}function c(r,e){if(null==r)return{};var t,o,i=function(r,e){if(null==r)return{};var t,o,i={},n=Object.keys(r);for(o=0;o<n.length;o++)t=n[o],e.indexOf(t)>=0||(i[t]=r[t]);return i}(r,e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(r);for(o=0;o<n.length;o++)t=n[o],e.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(r,t)&&(i[t]=r[t])}return i}const l=t=>{var{children:o,isWide:i,checked:n,isError:l,disabled:p,className:d}=t,u=c(t,["children","isWide","checked","isError","disabled","className"]);/*#__PURE__*/
|
|
2
|
+
return r("div",a(s({className:e("relative flex h-auto cursor-pointer items-center gap-2 rounded-xl border",i?"min-h-[94px] w-[298px] flex-row gap-3 px-5 py-4":"min-h-fit w-[224px] flex-col justify-center px-4 py-6",!p&&!l&&"group-focus-within:border-primary-500",p&&n&&!l?"cursor-not-allowed border-primary-100":p?"cursor-not-allowed border-w-gray-200":l?"border-w-red-500":n?"border-primary-500":"border-w-gray-200 group-hover:border-primary",p?n&&!l?"bg-primary-10":"bg-w-gray-10":n?l?"bg-w-red-10":"bg-primary-10":"bg-w-white",d)},u),{children:o}))},p=({isWide:e,children:o})=>/*#__PURE__*/r("div",{className:t("flex h-auto w-full flex-col justify-between gap-0.5",e?"items-start":"items-center"),children:o}),d=t=>{var{isWide:o,disabled:n,isError:a,checked:l}=t,p=c(t,["isWide","disabled","isError","checked"]);const d=a&&l&&n;/*#__PURE__*/
|
|
3
|
+
return r(i,s({className:e(!o&&"absolute top-[17px] left-[17px]"),disabled:n||d,checked:!d&&l,isError:a},p))},u=({iconName:t,disabled:i,checked:n,isError:s})=>{const a=s||!n;/*#__PURE__*/
|
|
4
|
+
return r("div",{className:e("flex size-[60px] shrink-0 items-center justify-center",i&&"opacity-30"),"data-testid":"design-system-radioCard--icon",children:/*#__PURE__*/r(o,{name:t,disabled:a})})};export{l as RadioCardContainer,u as RadioCardIcon,d as StyledRadio,p as TitleContainer};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{twMerge as n}from"tailwind-merge";import{useState as r,useEffect as a}from"react";import{Box as i}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},r=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(n).filter((function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable})))),r.forEach((function(t){m(e,t,n[t])}))}return e}function o(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):function(e){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t.push.apply(t,n)}return t}(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))})),e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}const u="\n [&::-moz-range-thumb]:pointer-events-auto\n [&::-moz-range-thumb]:mr-2\n [&::-moz-range-thumb]:-translate-x-1/4\n [&::-moz-range-thumb]:transform\n [&::-moz-range-thumb]:appearance-none\n [&::-moz-range-thumb]:rounded-full\n [&::-moz-range-thumb]:border\n [&::-moz-range-thumb]:border-w-gray-200\n [&::-moz-range-thumb]:bg-transparent\n [&::-moz-range-thumb]:bg-white\n [&::-moz-range-thumb]:shadow-graymedium\n [&::-moz-range-thumb]:outline\n [&::-moz-range-thumb]:inset-ring\n [&::-moz-range-thumb]:inset-ring-w-gray-200\n [&::-moz-range-thumb]:transition-all\n [&::-moz-range-thumb]:duration-150\n [&::-moz-range-thumb]:ease-in-out\n [&::-moz-range-thumb]:dark:bg-w-white\n\n [&::-webkit-slider-thumb]:pointer-events-auto\n [&::-webkit-slider-thumb]:mr-2\n [&::-webkit-slider-thumb]:-translate-x-1/4\n [&::-webkit-slider-thumb]:transform\n [&::-webkit-slider-thumb]:appearance-none\n [&::-webkit-slider-thumb]:rounded-full\n [&::-webkit-slider-thumb]:border\n [&::-webkit-slider-thumb]:border-w-gray-200\n [&::-webkit-slider-thumb]:bg-transparent\n [&::-webkit-slider-thumb]:bg-white\n [&::-webkit-slider-thumb]:shadow-graymedium\n [&::-webkit-slider-thumb]:outline\n [&::-webkit-slider-thumb]:inset-ring\n [&::-webkit-slider-thumb]:inset-ring-w-gray-200\n [&::-webkit-slider-thumb]:transition-all\n [&::-webkit-slider-thumb]:duration-150\n [&::-webkit-slider-thumb]:ease-in-out\n [&::-webkit-slider-thumb]:dark:bg-w-white\n ",b="pointer-events-none [&::-webkit-slider-thumb]:pointer-events-none [&::-moz-range-thumb]:pointer-events-none",d="absolute z-30 h-full w-full cursor-grab appearance-none rounded-full bg-transparent text-transparent",g=m=>{var{variant:g="single",size:h="sm",step:p=10,value:c={min:0,max:0},min:w=0,max:
|
|
2
|
-
/*#__PURE__*/t("input",s({"data-testid":"design-system-rangeSlider--end-thumb-input",type:"range",min:w,max:
|
|
1
|
+
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{twMerge as n}from"tailwind-merge";import{useState as r,useEffect as a}from"react";import"../../Base/Typography/Typography.js";import{Box as i}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},r=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(n).filter((function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable})))),r.forEach((function(t){m(e,t,n[t])}))}return e}function o(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):function(e){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t.push.apply(t,n)}return t}(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))})),e}function l(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}const u="\n [&::-moz-range-thumb]:pointer-events-auto\n [&::-moz-range-thumb]:mr-2\n [&::-moz-range-thumb]:-translate-x-1/4\n [&::-moz-range-thumb]:transform\n [&::-moz-range-thumb]:appearance-none\n [&::-moz-range-thumb]:rounded-full\n [&::-moz-range-thumb]:border\n [&::-moz-range-thumb]:border-w-gray-200\n [&::-moz-range-thumb]:bg-transparent\n [&::-moz-range-thumb]:bg-white\n [&::-moz-range-thumb]:shadow-graymedium\n [&::-moz-range-thumb]:outline\n [&::-moz-range-thumb]:inset-ring\n [&::-moz-range-thumb]:inset-ring-w-gray-200\n [&::-moz-range-thumb]:transition-all\n [&::-moz-range-thumb]:duration-150\n [&::-moz-range-thumb]:ease-in-out\n [&::-moz-range-thumb]:dark:bg-w-white\n\n [&::-webkit-slider-thumb]:pointer-events-auto\n [&::-webkit-slider-thumb]:mr-2\n [&::-webkit-slider-thumb]:-translate-x-1/4\n [&::-webkit-slider-thumb]:transform\n [&::-webkit-slider-thumb]:appearance-none\n [&::-webkit-slider-thumb]:rounded-full\n [&::-webkit-slider-thumb]:border\n [&::-webkit-slider-thumb]:border-w-gray-200\n [&::-webkit-slider-thumb]:bg-transparent\n [&::-webkit-slider-thumb]:bg-white\n [&::-webkit-slider-thumb]:shadow-graymedium\n [&::-webkit-slider-thumb]:outline\n [&::-webkit-slider-thumb]:inset-ring\n [&::-webkit-slider-thumb]:inset-ring-w-gray-200\n [&::-webkit-slider-thumb]:transition-all\n [&::-webkit-slider-thumb]:duration-150\n [&::-webkit-slider-thumb]:ease-in-out\n [&::-webkit-slider-thumb]:dark:bg-w-white\n ",b="pointer-events-none [&::-webkit-slider-thumb]:pointer-events-none [&::-moz-range-thumb]:pointer-events-none",d="absolute z-30 h-full w-full cursor-grab appearance-none rounded-full bg-transparent text-transparent",g=m=>{var{variant:g="single",size:h="sm",step:p=10,value:c={min:0,max:0},min:w=0,max:y=100,onChange:f,className:z,disabled:O}=m,k=l(m,["variant","size","step","value","min","max","onChange","className","disabled"]);const v="dual"===g,{min:x,max:j}=c,N=v?x:0,[P,S]=r({min:N,max:j}),[B,D]=r("end"),$=e=>y===w?0:(e-w)/(y-w)*100,E=(e,t)=>{const n="min"===t,r=n?"start":"end",a=Number(e.target.value),i=n?Math.min(a,P.max):Math.max(a,P.min);D(r);const m=o(s({},P),{[t]:i});S(m),null==f||f(m)},I=()=>"sm"===h?`${u}[&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4`:`${u}[&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:w-5 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:w-5`,M=Math.floor(Number(y)/Number(p))+1;return a((()=>{var e;S({min:v?null!==(e=c.min)&&void 0!==e?e:P.min:0,max:c.max})}),[c.min,c.max]),/*#__PURE__*/e(i,{className:n("relative px-1",z),"data-testid":"design-system-rangeSlider",children:[v&&/*#__PURE__*/t("input",s({"data-testid":"design-system-rangeSlider--start-thumb-input",type:"range",min:w,max:y,step:p,value:P.min,onInput:e=>E(e,"min"),className:n(d,"pointer-events-none",I(),"start"===B&&"z-50",O&&b),disabled:O},k)),
|
|
2
|
+
/*#__PURE__*/t("input",s({"data-testid":"design-system-rangeSlider--end-thumb-input",type:"range",min:w,max:y,value:P.max,onInput:e=>E(e,"max"),step:p,className:n(d,"pointer-events-auto",I(),v&&"pointer-events-none","end"===B&&"z-50",O&&b),disabled:O},k)),
|
|
3
3
|
/*#__PURE__*/e(i,{"data-testid":"design-system-rangeSlider--container",className:n("relative overflow-hidden","sm"===h&&"h-1 rounded-xs","md"===h&&"h-2 rounded"),children:["md"===h&&/*#__PURE__*/t(i,{className:"absolute z-20 flex h-2 w-full items-center justify-between bg-transparent p-0.5",children:[...Array(M)].map(((e,n)=>/*#__PURE__*/t(i,{"data-testid":"design-system-rangeSlider--unit-dot",className:"bg-w-white size-1 rounded-full"},n)))}),
|
|
4
4
|
/*#__PURE__*/t(i,{className:"bg-w-gray-50 absolute top-0 left-0 z-0 h-full w-full","data-testid":"design-system-rangeSlider--rail"}),
|
|
5
5
|
/*#__PURE__*/t(i,{className:n("bg-primary absolute top-0 left-0 z-10 h-full",O&&"bg-w-gray-300"),"data-testid":"design-system-rangeSlider--fill-track",style:{width:`${v?$(P.max)-$(P.min):$(P.max)}%`,left:v?`${$(P.min)}%`:0}})]})]})};export{g as RangeSlider};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as r}from"react";import{twMerge as
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as r}from"react";import{twMerge as o}from"tailwind-merge";import"../../Base/Typography/Typography.js";import{Box as n}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"../../DataDisplays/Avatar/Avatar.js";import{SystemIcon as s}from"../../DataDisplays/SystemIcon/SystemIcon.js";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import"../../DataDisplays/Accordion/Accordion.js";import{TextButtonDropdown as i}from"../TextButtonDropdown/TextButtonDropdown.js";import{TextFieldContainer as a}from"../TextFieldContainer/TextFieldContainer.js";import{Input as l}from"../Input/Input.js";import"../Input/PasswordInput.js";import"../Input/LabelInput.js";import"../Input/InputTypeSelector.js";function c(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function u(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{},o=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(r).filter((function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable})))),o.forEach((function(t){c(e,t,r[t])}))}return e}function p(e,t){if(null==e)return{};var r,o,n=function(e,t){if(null==e)return{};var r,o,n={},s=Object.keys(e);for(o=0;o<s.length;o++)r=s[o],t.indexOf(r)>=0||(n[r]=e[r]);return n}
|
|
2
2
|
/**
|
|
3
3
|
* 검색 필드 컴포넌트
|
|
4
4
|
*
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* ]
|
|
35
35
|
* }}
|
|
36
36
|
* />
|
|
37
|
-
*/(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(
|
|
38
|
-
return e("form",{onSubmit:e=>{e.preventDefault(),d()},"data-testid":"design-system-search-field",children:/*#__PURE__*/e("label",{className:"cursor-text",children:/*#__PURE__*/t(
|
|
39
|
-
/*#__PURE__*/e(
|
|
40
|
-
/*#__PURE__*/e("button",{type:"submit",className:"shrink-0","data-testid":"design-system-search-field--submit-button",disabled:
|
|
37
|
+
*/(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(o=0;o<s.length;o++)r=s[o],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}const m=c=>{var{type:m,onSearch:d,className:y,disabled:f,spellCheck:b,onFocus:j,onBlur:h,filters:g}=c,O=p(c,["type","onSearch","className","disabled","spellCheck","onFocus","onBlur","filters"]);const[I,v]=r(!1);/*#__PURE__*/
|
|
38
|
+
return e("form",{onSubmit:e=>{e.preventDefault(),d()},"data-testid":"design-system-search-field",children:/*#__PURE__*/e("label",{className:"cursor-text",children:/*#__PURE__*/t(a,{isFocused:I,isDisabled:f,className:"overflow-visible",children:[!!g&&/*#__PURE__*/e(n,{className:"shrink-0",children:/*#__PURE__*/e(i,u({disabled:f},g))}),
|
|
39
|
+
/*#__PURE__*/e(l,u({onFocus:e=>{v(!0),null==j||j(e)},onBlur:e=>{v(!1),null==h||h(e)},spellCheck:b||!1,disabled:f},O)),
|
|
40
|
+
/*#__PURE__*/e("button",{type:"submit",className:"shrink-0","data-testid":"design-system-search-field--submit-button",disabled:f,children:/*#__PURE__*/e(s,{testId:"design-system-search-field--submit-button-icon",name:"medium_search",className:o("text-w-gray-600 pointer-events-none",f&&"text-w-gray-300")})})]})})})};export{m as SearchField};
|
|
@@ -38,4 +38,4 @@
|
|
|
38
38
|
* maxLength={50}
|
|
39
39
|
* />
|
|
40
40
|
*/(e,r);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)t=a[n],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}const b=/*#__PURE__*/t(((t,u)=>{var{type:b,name:d,value:g,onChange:y,maxLength:O,disabled:j=!1,placeholder:h,label:x,testId:I,measure:v,isError:w,trailingIcon:P,leadingIcon:S,errorMessage:C,supportMessage:E,variant:F="default",className:L,onBlur:M}=t,T=m(t,["type","name","value","onChange","maxLength","disabled","placeholder","label","testId","measure","isError","trailingIcon","leadingIcon","errorMessage","supportMessage","variant","className","onBlur"]);const[D,N]=n(!1),[k,B]=n(0),q=p({variant:F,type:b,name:d,value:g,placeholder:h,label:x,maxLength:O,onChange:y,isFocused:D,isError:w,onFocus:()=>{N(!0)},disabled:j,onBlur:e=>{N(!1),M&&M(e)}},T),z=w||E||O;return o((()=>{"string"==typeof g&&O&&B(g.length)}),[g,O]),/*#__PURE__*/e("div",{className:a("tracking-default flex w-full flex-col gap-2 select-none",L),"data-testid":I,children:[
|
|
41
|
-
/*#__PURE__*/r("label",{
|
|
41
|
+
/*#__PURE__*/r("label",{className:j?"cursor-not-allowed":"cursor-text",children:/*#__PURE__*/e(l,{leadingIcon:S,trailingIcon:P,measure:v,isFocused:D,isError:w,isDisabled:j,children:["label"===F&&/*#__PURE__*/r(s,f(p({isFixed:!!h},q),{ref:u})),"default"===F&&/*#__PURE__*/r(c,f(p({},q),{ref:u}))]})}),z&&/*#__PURE__*/r(i,{errorMessage:C,supportMessage:E,currentLength:k,maxLength:O})]})}));b.displayName="TextField";export{b as TextField};
|
|
@@ -5,6 +5,12 @@ export type Item = {
|
|
|
5
5
|
value: string;
|
|
6
6
|
leadingIcon?: SystemIconName;
|
|
7
7
|
};
|
|
8
|
+
export type PanelWidth = 'trigger' | 'viewport';
|
|
9
|
+
export interface ResponsivePanelWidth {
|
|
10
|
+
base?: PanelWidth;
|
|
11
|
+
tablet?: PanelWidth;
|
|
12
|
+
desktop?: PanelWidth;
|
|
13
|
+
}
|
|
8
14
|
export interface TextFieldDropdownProps {
|
|
9
15
|
items: Item[];
|
|
10
16
|
onItemClick: (item: Item) => void;
|
|
@@ -17,7 +23,7 @@ export interface TextFieldDropdownProps {
|
|
|
17
23
|
isError?: boolean;
|
|
18
24
|
variant?: SelectBoxVariant;
|
|
19
25
|
label?: string;
|
|
20
|
-
panelWidth?:
|
|
26
|
+
panelWidth?: PanelWidth | ResponsivePanelWidth;
|
|
21
27
|
panelGutter?: number;
|
|
22
28
|
}
|
|
23
29
|
/**
|
|
@@ -37,8 +43,14 @@ export interface TextFieldDropdownProps {
|
|
|
37
43
|
* @param {boolean} [props.isError] - 오류 상태 여부
|
|
38
44
|
* @param {'default' | 'label'} [props.variant='default'] - 트리거(SelectBox)의 디자인 변형 타입. `TextField`의 variant와 동일한 시맨틱입니다.
|
|
39
45
|
* @param {string} [props.label] - `variant="label"`일 때 트리거 위에 플로팅되는 라벨
|
|
40
|
-
* @param {number} [props.panelGutter=20] - `panelWidth
|
|
41
|
-
* @param {'trigger' | 'viewport'} [props.panelWidth='trigger'] - 옵션 패널의 너비 기준.
|
|
46
|
+
* @param {number} [props.panelGutter=20] - `panelWidth`(또는 그 브레이크포인트 값)가 `"viewport"`일 때 패널과 화면 좌우 끝 사이에 둘 여백(px). 기본값 `20`.
|
|
47
|
+
* @param {'trigger' | 'viewport' | {base?: 'trigger'|'viewport', tablet?: 'trigger'|'viewport', desktop?: 'trigger'|'viewport'}} [props.panelWidth='trigger'] - 옵션 패널의 너비 기준.
|
|
48
|
+
* `'trigger'`(기본)는 트리거와 동일한 너비로 트리거 바로 아래에 `absolute`로 겹쳐 펼쳐집니다.
|
|
49
|
+
* `'viewport'`는 트리거가 좁은 컨테이너(예: 모바일 grid 2열)에 있어도 패널이 컨테이너 바깥, 화면 전체 너비로 펼쳐집니다.
|
|
50
|
+
* 이때 패널은 `fixed`가 아니라 in-flow로 렌더되어 자기 높이만큼 실제 영역을 차지하므로(아래 콘텐츠를 밀어냄) 뷰포트 하단에서 잘리지 않고, 옵션이 많으면 패널 내부에서 스크롤됩니다.
|
|
51
|
+
* `{ base, tablet, desktop }` 객체를 주면 `tailwind.config.js`의 `mobile(360px)/tablet(720px)/desktop(960px)` 브레이크포인트별로 다른 값을 지정할 수 있습니다.
|
|
52
|
+
* 지정하지 않은 브레이크포인트는 더 작은 브레이크포인트의 값을 물려받습니다(mobile-first). 예) `{ base: 'viewport', desktop: 'trigger' }` → 모바일·태블릿은 viewport, 데스크탑은 trigger.
|
|
53
|
+
* 이 객체 형태는 CSS 브레이크포인트 클래스 전환으로 처리되어 `matchMedia`/리사이즈 판정 로직이 추가되지 않습니다. 다만 객체의 어느 브레이크포인트든 `'viewport'`를 포함하면, 패널이 열려 있는 동안 트리거의 위치를 추적하는 `scroll`/`resize` 리스너가 (브레이크포인트 수와 무관하게) 1세트 붙습니다 — 이는 `panelWidth="viewport"` 단일 값을 쓸 때와 동일한 수준입니다.
|
|
42
54
|
*
|
|
43
55
|
* @example
|
|
44
56
|
* ```tsx
|
|
@@ -64,6 +76,15 @@ export interface TextFieldDropdownProps {
|
|
|
64
76
|
* onItemClick={(item) => console.log('선택된 아이템:', item)}
|
|
65
77
|
* selectedItem={items[0]}
|
|
66
78
|
* />
|
|
79
|
+
*
|
|
80
|
+
* // 모바일·태블릿은 viewport 전체, 데스크탑은 트리거 폭 그대로
|
|
81
|
+
* <TextFieldDropdown
|
|
82
|
+
* items={items}
|
|
83
|
+
* placeholder="옵션을 선택하세요"
|
|
84
|
+
* onItemClick={(item) => console.log('선택된 아이템:', item)}
|
|
85
|
+
* selectedItem={items[0]}
|
|
86
|
+
* panelWidth={{ base: 'viewport', desktop: 'trigger' }}
|
|
87
|
+
* />
|
|
67
88
|
* ```
|
|
68
89
|
*/
|
|
69
90
|
declare const TextFieldDropdown: ({ selectedItem, items, onItemClick, placeholder, disabled, isError, errorMessage, supportMessage, className, variant, label, panelWidth, panelGutter, }: TextFieldDropdownProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,54 +1,10 @@
|
|
|
1
|
-
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useState as o,useLayoutEffect as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* @param {Item} [props.selectedItem] - 현재 선택된 아이템
|
|
12
|
-
* @param {boolean} [props.disabled] - 비활성화 여부
|
|
13
|
-
* @param {string} [props.supportMessage] - 입력 필드 아래에 표시될 도움말 메시지
|
|
14
|
-
* @param {string} [props.errorMessage] - 오류 발생 시 표시될 메시지
|
|
15
|
-
* @param {string} [props.className] - 추가적인 CSS 클래스명
|
|
16
|
-
* @param {boolean} [props.isError] - 오류 상태 여부
|
|
17
|
-
* @param {'default' | 'label'} [props.variant='default'] - 트리거(SelectBox)의 디자인 변형 타입. `TextField`의 variant와 동일한 시맨틱입니다.
|
|
18
|
-
* @param {string} [props.label] - `variant="label"`일 때 트리거 위에 플로팅되는 라벨
|
|
19
|
-
* @param {number} [props.panelGutter=20] - `panelWidth="viewport"`일 때 패널과 화면 좌우 끝 사이에 둘 여백(px). 기본값 `20`.
|
|
20
|
-
* @param {'trigger' | 'viewport'} [props.panelWidth='trigger'] - 옵션 패널의 너비 기준. `'trigger'`(기본)는 트리거와 동일한 너비로 트리거 바로 아래에 `absolute`로 겹쳐 펼쳐집니다. `'viewport'`는 트리거가 좁은 컨테이너(예: 모바일 grid 2열)에 있어도 패널이 컨테이너 바깥, 화면 전체 너비로 펼쳐집니다. 이때 패널은 `fixed`가 아니라 in-flow로 렌더되어 자기 높이만큼 실제 영역을 차지하므로(아래 콘텐츠를 밀어냄) 뷰포트 하단에서 잘리지 않고, 옵션이 많으면 패널 내부에서 스크롤됩니다.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```tsx
|
|
24
|
-
* const items = [
|
|
25
|
-
* { key: 1, value: '옵션 1', leadingIcon: 'home' },
|
|
26
|
-
* { key: 2, value: '옵션 2', leadingIcon: 'settings' }
|
|
27
|
-
* ];
|
|
28
|
-
*
|
|
29
|
-
* // 기본 동작 — placeholder 기반 트리거
|
|
30
|
-
* <TextFieldDropdown
|
|
31
|
-
* items={items}
|
|
32
|
-
* placeholder="옵션을 선택하세요"
|
|
33
|
-
* onItemClick={(item) => console.log('선택된 아이템:', item)}
|
|
34
|
-
* selectedItem={items[0]}
|
|
35
|
-
* supportMessage="추가 설명이 필요한 경우 이곳에 표시됩니다"
|
|
36
|
-
* />
|
|
37
|
-
*
|
|
38
|
-
* // TextField variant="label"과 동일한 플로팅 라벨 트리거
|
|
39
|
-
* <TextFieldDropdown
|
|
40
|
-
* variant="label"
|
|
41
|
-
* label="업종"
|
|
42
|
-
* items={items}
|
|
43
|
-
* onItemClick={(item) => console.log('선택된 아이템:', item)}
|
|
44
|
-
* selectedItem={items[0]}
|
|
45
|
-
* />
|
|
46
|
-
* ```
|
|
47
|
-
*/const p=({selectedItem:p,items:m,onItemClick:c,placeholder:u,disabled:f,isError:g,errorMessage:v,supportMessage:w,className:x,variant:h="default",label:b,panelWidth:L="trigger",panelGutter:I=20})=>{const{isListOpen:y,focusedIndex:k,ref:C,handleItemClick:j,toggleListOpen:B,handleKeyDown:D}=a({items:m,onItemClick:c,disabled:f}),E=!!w||!!v,F="viewport"===L,[M,N]=o(void 0);
|
|
48
|
-
// viewport 패널은 좁은 컨테이너 바깥, 화면 전체 너비로 펼쳐져야 한다.
|
|
49
|
-
// 단 fixed로 띄우면 out-of-flow라 영역을 차지하지 못해 하단에서 잘리므로,
|
|
50
|
-
// in-flow(relative)로 두고 트리거의 화면상 좌측 위치/뷰포트 너비를 측정해
|
|
51
|
-
// 좌우로 full-bleed시킨다. 높이는 in-flow라 실제 영역을 차지하고,
|
|
52
|
-
// 옵션이 많으면 List 내부(max-height)에서 스크롤된다. (리사이즈/스크롤 시 추적)
|
|
53
|
-
return r((()=>{if(!y||!F)return;const e=C.current;if(!e)return;const t=()=>{const{left:t}=e.getBoundingClientRect(),o=document.documentElement.clientWidth;N({marginLeft:I-t,width:o-2*I})};return t(),window.addEventListener("scroll",t,!0),window.addEventListener("resize",t),()=>{window.removeEventListener("scroll",t,!0),window.removeEventListener("resize",t)}}),[y,F,I,C]),/*#__PURE__*/e("div",{"data-testid":"design-system--textFieldDropdown",ref:C,className:"group/dropdown relative flex w-full flex-col gap-2 outline-hidden",onKeyDown:D,tabIndex:f?-1:0,role:"combobox","aria-haspopup":"listbox","aria-expanded":y,"aria-disabled":f,children:[
|
|
54
|
-
/*#__PURE__*/t(d,{placeholder:u,value:null==p?void 0:p.value,leadingIcon:null==p?void 0:p.leadingIcon,disabled:f,isListOpen:y,onClick:B,error:g,className:x,variant:h,label:b}),E&&/*#__PURE__*/t(s,{errorMessage:v,supportMessage:w}),y&&/*#__PURE__*/t(l,{"data-testid":"design-system--textFieldDropdown-panel",className:i("z-40",F?"relative":i("absolute w-full","label"===h?"top-[72px]":"top-[54px]")),style:F?M:void 0,children:/*#__PURE__*/t(n.Root,{children:m.map(((e,o)=>/*#__PURE__*/t(n.Item,{text:e.value,leadingIcon:e.leadingIcon,onClick:()=>j(e),selected:e.key===(null==p?void 0:p.key),isFocused:o===k},e.key)))})})]})};export{p as TextFieldDropdown};
|
|
1
|
+
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useMemo as l,useState as o,useLayoutEffect as a}from"react";import{twJoin as r}from"tailwind-merge";import"../../Base/Typography/Typography.js";import{Box as i}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{List as s}from"../List/List.js";import{SupportTextContainer as d}from"../SupportTextContainer/SupportTextContainer.js";import{useDropdown as p}from"../../../hooks/useDropdown.js";import{SelectBox as n}from"./TextFieldDropdown.parts.js";const m={base:{trigger:"absolute ml-0 w-full",viewport:"relative ml-[var(--tfd-panel-ml)] w-[var(--tfd-panel-w)]"},tablet:{trigger:"tablet:absolute tablet:ml-0 tablet:w-full",viewport:"tablet:relative tablet:ml-[var(--tfd-panel-ml)] tablet:w-[var(--tfd-panel-w)]"},desktop:{trigger:"desktop:absolute desktop:ml-0 desktop:w-full",viewport:"desktop:relative desktop:ml-[var(--tfd-panel-ml)] desktop:w-[var(--tfd-panel-w)]"}},u={base:{trigger:{default:"top-[54px]",label:"top-[72px]"},viewport:{default:"top-0",label:"top-0"}},tablet:{trigger:{default:"tablet:top-[54px]",label:"tablet:top-[72px]"},viewport:{default:"tablet:top-0",label:"tablet:top-0"}},desktop:{trigger:{default:"desktop:top-[54px]",label:"desktop:top-[72px]"},viewport:{default:"desktop:top-0",label:"desktop:top-0"}}},b=({selectedItem:b,items:v,onItemClick:c,placeholder:w,disabled:f,isError:g,errorMessage:k,supportMessage:x,className:h,variant:y="default",label:L,panelWidth:I="trigger",panelGutter:j=20})=>{const{isListOpen:B,focusedIndex:C,ref:D,handleItemClick:E,toggleListOpen:F,handleKeyDown:T}=p({items:v,onItemClick:c,disabled:f}),M=!!x||!!k,N="viewport"===I,z=l((()=>{return"object"==typeof(e=I)&&null!==e?(e=>{var t;const l=null!==(t=e.base)&&void 0!==t?t:"trigger";var o;const a=null!==(o=e.tablet)&&void 0!==o?o:l;var r;return{base:l,tablet:a,desktop:null!==(r=e.desktop)&&void 0!==r?r:a}})(I):void 0;var e}),[I]),O=void 0!==z&&("viewport"===z.base||"viewport"===z.tablet||"viewport"===z.desktop),K=N||O,[R,S]=o(void 0);a((()=>{if(!B||!K)return;const e=D.current;if(!e)return;const t=()=>{S(((e,t)=>{const{left:l}=e.getBoundingClientRect();return{marginLeft:t-l,width:document.documentElement.clientWidth-2*t}})(e,j))};return t(),window.addEventListener("scroll",t,!0),window.addEventListener("resize",t),()=>{window.removeEventListener("scroll",t,!0),window.removeEventListener("resize",t)}}),[B,K,j,D]);
|
|
2
|
+
// 객체 경로: 측정값을 CSS 커스텀 프로퍼티로만 노출(클래스가 항상 override 가능해야 함).
|
|
3
|
+
const W=R?{"--tfd-panel-ml":`${R.marginLeft}px`,"--tfd-panel-w":`${R.width}px`}:void 0,$=R?{marginLeft:R.marginLeft,width:R.width}:void 0,G=r("z-40",z?((e,t)=>r(m.base[e.base],u.base[e.base][t],m.tablet[e.tablet],u.tablet[e.tablet][t],m.desktop[e.desktop],u.desktop[e.desktop][t]))(z,y):N?"relative":r("absolute w-full","label"===y?"top-[72px]":"top-[54px]")),q=z?W:N?$:void 0;
|
|
4
|
+
// 문자열 경로: 기존과 동일하게 실제 marginLeft/width 인라인 스타일을 그대로 사용.
|
|
5
|
+
/*#__PURE__*/
|
|
6
|
+
return e("div",{"data-testid":"design-system--textFieldDropdown",ref:D,className:"group/dropdown relative flex w-full flex-col gap-2 outline-hidden",onKeyDown:T,tabIndex:f?-1:0,role:"combobox","aria-haspopup":"listbox","aria-expanded":B,"aria-disabled":f,children:[
|
|
7
|
+
/*#__PURE__*/t(n,{placeholder:w,value:null==b?void 0:b.value,leadingIcon:null==b?void 0:b.leadingIcon,disabled:f,isListOpen:B,onClick:F,error:g,className:h,variant:y,label:L}),M&&/*#__PURE__*/t(d,{errorMessage:k,supportMessage:x}),B&&/*#__PURE__*/t(i,{"data-testid":"design-system--textFieldDropdown-panel",className:G,style:q,children:/*#__PURE__*/t(s.Root,{children:v.map(((e,l)=>/*#__PURE__*/t(s.Item,{text:e.value,leadingIcon:e.leadingIcon,onClick:()=>E(e),selected:e.key===(null==b?void 0:b.key),isFocused:l===C},e.key)))})})]})};
|
|
8
|
+
// base -> tablet -> desktop 순으로 값이 없으면 더 작은 브레이크포인트의 값을 물려받는다.
|
|
9
|
+
// (mobile-first cascade. FullBleed의 padding fallback과 동일한 관례)
|
|
10
|
+
export{b as TextFieldDropdown};
|
|
@@ -13,4 +13,13 @@ interface SelectBoxProps {
|
|
|
13
13
|
label?: string;
|
|
14
14
|
}
|
|
15
15
|
export declare const SelectBox: ({ placeholder, value, isListOpen, disabled, error, onClick, className, variant, label, }: SelectBoxProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export interface LabelSelectBoxProps {
|
|
17
|
+
value: string;
|
|
18
|
+
placeholder: string;
|
|
19
|
+
label?: string;
|
|
20
|
+
isFocused?: boolean;
|
|
21
|
+
isError?: boolean;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare const LabelSelectBox: ({ label, value, placeholder, isFocused, isError, disabled, }: LabelSelectBoxProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
25
|
export {};
|
|
@@ -3,4 +3,4 @@ import{jsxs as t,jsx as e}from"react/jsx-runtime";import{twMerge as a,twJoin as
|
|
|
3
3
|
/*#__PURE__*/e("div",{className:r("transition-transform duration-300",c&&"rotate-180"),children:/*#__PURE__*/e(i,{name:"medium_arrow_down",className:m?"text-w-gray-300":"text-w-gray-600",testId:"design-system--selectBox-icon"})})]}),n=({label:i,value:l,placeholder:d,isFocused:n,isError:c,disabled:m})=>{const p=!!d;/*#__PURE__*/
|
|
4
4
|
return t(o,{className:"relative flex h-[42px] w-full flex-col gap-0.5 py-px","data-testid":"design-system--selectBox-label",children:[
|
|
5
5
|
/*#__PURE__*/e("div",{className:a("tracking-default absolute",m?"text-w-gray-400":c?"text-w-red-500":n?"text-primary-500":"text-w-gray-400 group-hover:text-primary-500",p?"typo-caption11":n||l?"scale-[0.6875] -translate-y-0.5 origin-top-left transition-transform duration-300":"typo-body16 transition-transform duration-300 translate-y-2 origin-top-left"),"data-testid":"design-system--label-text",children:i}),
|
|
6
|
-
/*#__PURE__*/e(s,{"data-testid":"design-system--selectBox-text",variant:"body16",className:r(m?"text-w-gray-300":l?"text-w-gray-600":"text-w-gray-300","w-full pt-[14px]"),children:l||(p?d:"")})]})};export{d as SelectBox};
|
|
6
|
+
/*#__PURE__*/e(s,{"data-testid":"design-system--selectBox-text",variant:"body16",className:r(m?"text-w-gray-300":l?"text-w-gray-600":"text-w-gray-300","w-full pt-[14px]"),children:l||(p?d:"")})]})};export{n as LabelSelectBox,d as SelectBox};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef } from 'react';
|
|
2
|
+
import { SelectBoxVariant } from '../TextFieldDropdown/TextFieldDropdown.parts';
|
|
3
|
+
export interface TextFieldTriggerProps extends Omit<ComponentPropsWithoutRef<'button'>, 'type' | 'value'> {
|
|
4
|
+
variant?: SelectBoxVariant;
|
|
5
|
+
label?: string;
|
|
6
|
+
value?: string;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
isError?: boolean;
|
|
9
|
+
errorMessage?: string;
|
|
10
|
+
supportMessage?: string;
|
|
11
|
+
testId?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 입력 필드처럼 보이지만 직접 타이핑하지 않고, 클릭(또는 Enter/Space)으로 별도 UI(모달,
|
|
15
|
+
* 패널 등)를 여는 트리거 컴포넌트입니다. 날짜 선택, 주소 검색, 파일 선택, 회사명 검색
|
|
16
|
+
* 모달처럼 "필드 모양의 트리거"가 필요한 모든 곳에서 사용할 수 있습니다.
|
|
17
|
+
*
|
|
18
|
+
* `readOnly` `TextField`를 트리거로 우회 사용하면 스크린리더가 "편집 가능 텍스트,
|
|
19
|
+
* 읽기 전용"으로 읽고 Enter/Space를 직접 구현해야 하는 문제가 있습니다.
|
|
20
|
+
* `TextFieldTrigger`는 실제 `<button type="button">`으로 렌더링되어 이 문제를 근본적으로
|
|
21
|
+
* 해결합니다 — 브라우저가 포커스, Enter/Space 클릭, disabled 처리를 기본으로 제공합니다.
|
|
22
|
+
* `<button>` 안에 `<input>`을 넣는 것은 invalid HTML이므로, 값은 항상 일반 텍스트로만
|
|
23
|
+
* 표시됩니다.
|
|
24
|
+
*
|
|
25
|
+
* 시각 스타일은 `TextFieldDropdown`의 트리거(`SelectBox`/`LabelSelectBox`)와 동일한
|
|
26
|
+
* `TextFieldContainer` + 라벨 플로팅 애니메이션을 그대로 재사용하며, 에러/서포트 텍스트는
|
|
27
|
+
* `SupportTextContainer`로 렌더링해 같은 폼의 `TextField` 에러와 렌더 경로·스타일이
|
|
28
|
+
* 일치합니다.
|
|
29
|
+
*
|
|
30
|
+
* `className`과 나머지 DOM 속성(rest, 예: `onClick`, `aria-haspopup`, `aria-expanded`)은
|
|
31
|
+
* 모두 시각적 트리거이자 실제 클릭 대상인 `<button>` 엘리먼트 하나에만 적용됩니다.
|
|
32
|
+
* `TextField`처럼 `className`은 바깥 wrapper에, rest는 내부 `<input>`에만 적용되어
|
|
33
|
+
* 커서 영역과 클릭 핸들러 영역이 어긋나는 문제가 `TextFieldTrigger`에는 없습니다.
|
|
34
|
+
*
|
|
35
|
+
* `value`가 비어 있을 때 `placeholder`는 시각적으로만 힌트를 보여주고, `label`이 있는
|
|
36
|
+
* 경우 접근 가능한 이름(accessible name)에 섞여 들어가지 않도록 처리했습니다
|
|
37
|
+
* (예: `label="회사명"`, `placeholder="기업명을 검색하세요"`, `value=""`이면 접근 가능한
|
|
38
|
+
* 이름은 "회사명"입니다). 소비자가 `aria-label`을 직접 넘기면 이 내부 계산보다 항상
|
|
39
|
+
* 우선합니다.
|
|
40
|
+
*
|
|
41
|
+
* @component
|
|
42
|
+
* @param {Object} props
|
|
43
|
+
* @param {'default' | 'label'} [props.variant='default'] - 트리거의 디자인 변형 타입. `TextField`의 variant와 동일한 시맨틱입니다.
|
|
44
|
+
* @param {string} [props.label] - `variant="label"`일 때 트리거 위에 플로팅되는 라벨
|
|
45
|
+
* @param {string} [props.value] - 현재 선택된 값(표시용 텍스트). 직접 타이핑할 수 없으므로 항상 상위 상태에서 내려받습니다.
|
|
46
|
+
* @param {string} [props.placeholder] - 값이 없을 때 표시되는 안내 텍스트
|
|
47
|
+
* @param {boolean} [props.isError] - 오류 상태 표시 여부
|
|
48
|
+
* @param {string} [props.errorMessage] - 오류 발생 시 표시될 메시지
|
|
49
|
+
* @param {string} [props.supportMessage] - 입력 필드 아래에 표시될 도움말 메시지
|
|
50
|
+
* @param {boolean} [props.disabled] - 비활성화 여부. `<button disabled>`로 렌더되어 클릭·키보드 입력이 모두 무시됩니다.
|
|
51
|
+
* @param {string} [props.className] - `<button>`에 적용될 추가 CSS 클래스명
|
|
52
|
+
* @param {string} [props.testId] - 테스트용 ID (`<button>`에 적용)
|
|
53
|
+
* @param {() => void} [props.onClick] - 클릭(및 Enter/Space) 시 호출되는 콜백. 별도의 키보드 핸들러를 구현할 필요가 없습니다.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* const [isOpen, setIsOpen] = useState(false);
|
|
58
|
+
*
|
|
59
|
+
* <TextFieldTrigger
|
|
60
|
+
* variant="label"
|
|
61
|
+
* label="회사명"
|
|
62
|
+
* value={companyName}
|
|
63
|
+
* placeholder="기업명을 검색하세요"
|
|
64
|
+
* isError={hasError}
|
|
65
|
+
* errorMessage={errorMessage}
|
|
66
|
+
* aria-haspopup="dialog"
|
|
67
|
+
* aria-expanded={isOpen}
|
|
68
|
+
* onClick={() => setIsOpen(true)}
|
|
69
|
+
* />
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare const TextFieldTrigger: import("react").ForwardRefExoticComponent<TextFieldTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
73
|
+
export { TextFieldTrigger };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";import{jsxs as e,jsx as r}from"react/jsx-runtime";import{forwardRef as t,useState as o}from"react";import{twJoin as l,twMerge as n}from"tailwind-merge";import{Typography as a}from"../../Base/Typography/Typography.js";import"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import{TextFieldContainer as s}from"../TextFieldContainer/TextFieldContainer.js";import{SupportTextContainer as i}from"../SupportTextContainer/SupportTextContainer.js";import{LabelSelectBox as c}from"../TextFieldDropdown/TextFieldDropdown.parts.js";function u(e,r,t){return r in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e}function p(e){for(var r=1;r<arguments.length;r++){var t=null!=arguments[r]?arguments[r]:{},o=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(o=o.concat(Object.getOwnPropertySymbols(t).filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})))),o.forEach((function(r){u(e,r,t[r])}))}return e}function d(e,r){return r=null!=r?r:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):function(e){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);r.push.apply(r,t)}return r}(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))})),e}function b(e,r){if(null==e)return{};var t,o,l=function(e,r){if(null==e)return{};var t,o,l={},n=Object.keys(e);for(o=0;o<n.length;o++)t=n[o],r.indexOf(t)>=0||(l[t]=e[t]);return l}
|
|
2
|
+
/**
|
|
3
|
+
* 입력 필드처럼 보이지만 직접 타이핑하지 않고, 클릭(또는 Enter/Space)으로 별도 UI(모달,
|
|
4
|
+
* 패널 등)를 여는 트리거 컴포넌트입니다. 날짜 선택, 주소 검색, 파일 선택, 회사명 검색
|
|
5
|
+
* 모달처럼 "필드 모양의 트리거"가 필요한 모든 곳에서 사용할 수 있습니다.
|
|
6
|
+
*
|
|
7
|
+
* `readOnly` `TextField`를 트리거로 우회 사용하면 스크린리더가 "편집 가능 텍스트,
|
|
8
|
+
* 읽기 전용"으로 읽고 Enter/Space를 직접 구현해야 하는 문제가 있습니다.
|
|
9
|
+
* `TextFieldTrigger`는 실제 `<button type="button">`으로 렌더링되어 이 문제를 근본적으로
|
|
10
|
+
* 해결합니다 — 브라우저가 포커스, Enter/Space 클릭, disabled 처리를 기본으로 제공합니다.
|
|
11
|
+
* `<button>` 안에 `<input>`을 넣는 것은 invalid HTML이므로, 값은 항상 일반 텍스트로만
|
|
12
|
+
* 표시됩니다.
|
|
13
|
+
*
|
|
14
|
+
* 시각 스타일은 `TextFieldDropdown`의 트리거(`SelectBox`/`LabelSelectBox`)와 동일한
|
|
15
|
+
* `TextFieldContainer` + 라벨 플로팅 애니메이션을 그대로 재사용하며, 에러/서포트 텍스트는
|
|
16
|
+
* `SupportTextContainer`로 렌더링해 같은 폼의 `TextField` 에러와 렌더 경로·스타일이
|
|
17
|
+
* 일치합니다.
|
|
18
|
+
*
|
|
19
|
+
* `className`과 나머지 DOM 속성(rest, 예: `onClick`, `aria-haspopup`, `aria-expanded`)은
|
|
20
|
+
* 모두 시각적 트리거이자 실제 클릭 대상인 `<button>` 엘리먼트 하나에만 적용됩니다.
|
|
21
|
+
* `TextField`처럼 `className`은 바깥 wrapper에, rest는 내부 `<input>`에만 적용되어
|
|
22
|
+
* 커서 영역과 클릭 핸들러 영역이 어긋나는 문제가 `TextFieldTrigger`에는 없습니다.
|
|
23
|
+
*
|
|
24
|
+
* `value`가 비어 있을 때 `placeholder`는 시각적으로만 힌트를 보여주고, `label`이 있는
|
|
25
|
+
* 경우 접근 가능한 이름(accessible name)에 섞여 들어가지 않도록 처리했습니다
|
|
26
|
+
* (예: `label="회사명"`, `placeholder="기업명을 검색하세요"`, `value=""`이면 접근 가능한
|
|
27
|
+
* 이름은 "회사명"입니다). 소비자가 `aria-label`을 직접 넘기면 이 내부 계산보다 항상
|
|
28
|
+
* 우선합니다.
|
|
29
|
+
*
|
|
30
|
+
* @component
|
|
31
|
+
* @param {Object} props
|
|
32
|
+
* @param {'default' | 'label'} [props.variant='default'] - 트리거의 디자인 변형 타입. `TextField`의 variant와 동일한 시맨틱입니다.
|
|
33
|
+
* @param {string} [props.label] - `variant="label"`일 때 트리거 위에 플로팅되는 라벨
|
|
34
|
+
* @param {string} [props.value] - 현재 선택된 값(표시용 텍스트). 직접 타이핑할 수 없으므로 항상 상위 상태에서 내려받습니다.
|
|
35
|
+
* @param {string} [props.placeholder] - 값이 없을 때 표시되는 안내 텍스트
|
|
36
|
+
* @param {boolean} [props.isError] - 오류 상태 표시 여부
|
|
37
|
+
* @param {string} [props.errorMessage] - 오류 발생 시 표시될 메시지
|
|
38
|
+
* @param {string} [props.supportMessage] - 입력 필드 아래에 표시될 도움말 메시지
|
|
39
|
+
* @param {boolean} [props.disabled] - 비활성화 여부. `<button disabled>`로 렌더되어 클릭·키보드 입력이 모두 무시됩니다.
|
|
40
|
+
* @param {string} [props.className] - `<button>`에 적용될 추가 CSS 클래스명
|
|
41
|
+
* @param {string} [props.testId] - 테스트용 ID (`<button>`에 적용)
|
|
42
|
+
* @param {() => void} [props.onClick] - 클릭(및 Enter/Space) 시 호출되는 콜백. 별도의 키보드 핸들러를 구현할 필요가 없습니다.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```tsx
|
|
46
|
+
* const [isOpen, setIsOpen] = useState(false);
|
|
47
|
+
*
|
|
48
|
+
* <TextFieldTrigger
|
|
49
|
+
* variant="label"
|
|
50
|
+
* label="회사명"
|
|
51
|
+
* value={companyName}
|
|
52
|
+
* placeholder="기업명을 검색하세요"
|
|
53
|
+
* isError={hasError}
|
|
54
|
+
* errorMessage={errorMessage}
|
|
55
|
+
* aria-haspopup="dialog"
|
|
56
|
+
* aria-expanded={isOpen}
|
|
57
|
+
* onClick={() => setIsOpen(true)}
|
|
58
|
+
* />
|
|
59
|
+
* ```
|
|
60
|
+
*/(e,r);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o<n.length;o++)t=n[o],r.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}const f=/*#__PURE__*/t(((t,u)=>{var{variant:f="default",label:y,value:g="",placeholder:m="",isError:O,errorMessage:j,supportMessage:x,disabled:w=!1,className:v,onFocus:h,onBlur:F,testId:P,"aria-label":T}=t,B=b(t,["variant","label","value","placeholder","isError","errorMessage","supportMessage","disabled","className","onFocus","onBlur","testId","aria-label"]);const[S,D]=o(!1),E=!!y&&!g,M=!!x||!!j;/*#__PURE__*/
|
|
61
|
+
return e("div",{className:"tracking-default flex w-full flex-col gap-2 select-none",children:[
|
|
62
|
+
/*#__PURE__*/r("button",d(p({},B),{ref:u,type:"button",disabled:w,onFocus:e=>{D(!0),null==h||h(e)},onBlur:e=>{D(!1),null==F||F(e)},"aria-label":null!=T?T:E?y:void 0,"data-testid":null!=P?P:"design-system--textFieldTrigger",className:n("w-full text-left",w?"cursor-not-allowed":"cursor-pointer",v),children:/*#__PURE__*/r(s,{isFocused:S,isDisabled:w,isError:O,testId:"design-system--textFieldTrigger-box",children:"label"===f?/*#__PURE__*/r(c,{label:y,value:g,placeholder:m,isFocused:S,isError:O,disabled:w}):/*#__PURE__*/r(a,{"data-testid":"design-system--textFieldTrigger-text",variant:"body16",className:l(w&&g?"text-w-gray-300":w&&!g?"text-w-gray-200":g?"text-w-gray-600":"text-w-gray-300","w-full"),children:g||m})})})),M&&/*#__PURE__*/r(i,{errorMessage:j,supportMessage:x})]})}));f.displayName="TextFieldTrigger";export{f as TextFieldTrigger};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useState as r}from"react";import{twMerge as n,twJoin as o}from"tailwind-merge";import{Box as a}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"../../DataDisplays/Avatar/Avatar.js";import{SystemIcon as
|
|
1
|
+
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useState as r}from"react";import{twMerge as n,twJoin as o}from"tailwind-merge";import"../../Base/Typography/Typography.js";import{Box as a}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"../../DataDisplays/Avatar/Avatar.js";import{SystemIcon as s}from"../../DataDisplays/SystemIcon/SystemIcon.js";import"../../DataDisplays/SystemIcon/SystemIcon.constants.js";import"../../DataDisplays/Accordion/Accordion.js";import{TextFieldContainer as i}from"../TextFieldContainer/TextFieldContainer.js";import{SupportTextContainer as l}from"../SupportTextContainer/SupportTextContainer.js";function m(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function u(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{},n=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(n=n.concat(Object.getOwnPropertySymbols(r).filter((function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable})))),n.forEach((function(t){m(e,t,r[t])}))}return e}function p(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}
|
|
2
2
|
/**
|
|
3
3
|
* 사용자가 여러 줄의 텍스트를 입력할 수 있는 textarea 컴포넌트입니다.
|
|
4
4
|
*
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
* />
|
|
42
42
|
* </div>
|
|
43
43
|
* ```
|
|
44
|
-
*/(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}const
|
|
44
|
+
*/(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n<a.length;n++)r=a[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}const c=m=>{var{isError:c=!1,size:f="md",resize:d=!1,isLengthVisible:y=!1,supportText:g,errorText:x,maxLength:h,value:b,disabled:j,name:O,onChange:v,onBlur:w}=m,S=p(m,["isError","size","resize","isLengthVisible","supportText","errorText","maxLength","value","disabled","name","onChange","onBlur"]);const[T,B]=r(!1),D=c||g||y;/*#__PURE__*/
|
|
45
45
|
return e(a,{"data-testid":"design-system-textarea",className:n("flex w-full flex-col gap-2","full"===f?"h-full":"h-fit"),children:[
|
|
46
|
-
/*#__PURE__*/e(i,{isDisabled:j,isError:
|
|
47
|
-
/*#__PURE__*/t("textarea",u({"data-testid":"design-system-textarea--textarea",className:n("scrollbar-list tracking-default placeholder:tracking-default text-w-gray-600 placeholder:text-w-gray-300 w-full overflow-y-scroll py-[11px] pl-4 font-[inherit] font-normal outline-hidden placeholder:font-[inherit]","sm"===f?"min-h-[118px]":"md"===f?"min-h-[238px]":"lg"===f?"min-h-[358px]":"full"===f?"min-h-full":void 0,d?"resize-y":"resize-none",j&&"resize-none"),name:O,value:b,disabled:j,onChange:v,maxLength:h,onFocus:e=>{
|
|
46
|
+
/*#__PURE__*/e(i,{isDisabled:j,isError:c,isFocused:T,isTextarea:!0,className:o("full"===f&&"h-full"),children:[
|
|
47
|
+
/*#__PURE__*/t("textarea",u({"data-testid":"design-system-textarea--textarea",className:n("scrollbar-list tracking-default placeholder:tracking-default text-w-gray-600 placeholder:text-w-gray-300 w-full overflow-y-scroll py-[11px] pl-4 font-[inherit] font-normal outline-hidden placeholder:font-[inherit]","sm"===f?"min-h-[118px]":"md"===f?"min-h-[238px]":"lg"===f?"min-h-[358px]":"full"===f?"min-h-full":void 0,d?"resize-y":"resize-none",j&&"resize-none"),name:O,value:b,disabled:j,onChange:v,maxLength:h,onFocus:e=>{B(!0)},onBlur:e=>{B(!1),w&&w(e)}},S)),d&&/*#__PURE__*/t(s,{name:"small_resizer",className:"text-w-gray-400 absolute right-[5px] bottom-[5px]",testId:"design-system-textarea--resize-icon"})]}),D&&/*#__PURE__*/t(l,{errorMessage:x,supportMessage:g,currentLength:(null==b?void 0:b.toString().length)||0,maxLength:h})]})};export{c as Textarea};
|
|
@@ -22,6 +22,7 @@ export * from './TextButton';
|
|
|
22
22
|
export * from './TextField';
|
|
23
23
|
export * from './List';
|
|
24
24
|
export * from './TextFieldDropdown';
|
|
25
|
+
export * from './TextFieldTrigger';
|
|
25
26
|
export * from './CommentArea';
|
|
26
27
|
export * from './IconButtonDropdown';
|
|
27
28
|
export * from './MultiColumnList';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{jsxs as r,Fragment as e,jsx as
|
|
1
|
+
import{jsxs as r,Fragment as e,jsx as o}from"react/jsx-runtime";import{twMerge as t}from"tailwind-merge";import{BackDrop as i}from"../../Utils/BackDrop/BackDrop.js";import"react";import"../../Base/Typography/Typography.js";import{Box as s}from"../../Base/Layouts/Box/Box.js";import"../../Base/Layouts/FullBleed/FullBleed.js";import"react-dom";import{directionStyle as a,sizeStyle as m,openStyle as l}from"./Drawer.styles.js";
|
|
2
2
|
/**
|
|
3
3
|
* 화면의 가장자리에서 슬라이딩되어 나타나는 서랍형 컴포넌트입니다.
|
|
4
4
|
*
|
|
@@ -25,5 +25,5 @@ import{jsxs as r,Fragment as e,jsx as t}from"react/jsx-runtime";import{twMerge a
|
|
|
25
25
|
* >
|
|
26
26
|
* <div>서랍 내용</div>
|
|
27
27
|
* </Drawer>
|
|
28
|
-
*/const
|
|
29
|
-
/*#__PURE__*/
|
|
28
|
+
*/const p=({isOpen:p,onClose:n,direction:c="right",size:d="quarter",className:B,children:f})=>/*#__PURE__*/r(e,{children:[p&&/*#__PURE__*/o(i,{onClick:n,isBlack:!0}),
|
|
29
|
+
/*#__PURE__*/o(s,{className:t("fixed z-30 flex flex-col bg-white transition-transform duration-300 ease-in-out",a[c],m(d,c),p&&l[c],B),"data-testid":"design-system-drawer",children:f})]});export{p as Drawer};
|