@ncds/ui-admin 1.8.21-alpha.16 → 1.8.21-alpha.18

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.
@@ -5,12 +5,18 @@ import { forwardRef, useEffect, useRef, useState } from 'react';
5
5
  import { COLOR } from '../../../../constant/color';
6
6
  import { HintText } from '../../shared/hintText/HintText';
7
7
  import { Label } from '../../shared/label/Label';
8
- // 슬롯 아이콘(leadingElement/trailingElement) 상태 아이콘(clear·validation·destructive)은 같은 크기를 쓴다.
8
+ // 슬롯 아이콘(leadingElement/trailingElement) 인풋 크기에 맞춰 커진다.
9
9
  // slot.size 를 명시하면 그 값이 우선한다.
10
10
  const iconSvgSize = {
11
11
  xs: 14,
12
12
  sm: 20,
13
13
  };
14
+ // 상태 아이콘(clear·validation·destructive)은 인풋 크기와 무관하게 16px 로 고정한다.
15
+ // 슬롯 아이콘은 sm 에서 20px 로 커지므로 두 상수를 하나로 합치지 않는다.
16
+ const statusIconSvgSize = {
17
+ xs: 14,
18
+ sm: 16,
19
+ };
14
20
  const InputBase = forwardRef(({ size = 'xs', required, label, hintText, disabled, fullWidth = false, validation, destructive, leadingElement, trailingElement, showHelpIcon, maxLength, showTextCount, clearText, onClearText, className, ...props }, ref) => {
15
21
  const inputRef = useRef(null);
16
22
  // controlled 인풋은 props.value 로 길이를 알 수 있으므로 상태를 두지 않는다.
@@ -76,14 +82,14 @@ const InputBase = forwardRef(({ size = 'xs', required, label, hintText, disabled
76
82
  const renderClearButton = () => {
77
83
  if (!clearText)
78
84
  return null;
79
- return (_jsx("button", { type: "button", className: classNames('ncua-input__icon-wrap', 'ncua-input__right-icon', 'ncua-input__clear'), onClick: onClearText, children: _jsx(X, { className: "ncua-input__clear-icon", width: iconSvgSize[size], height: iconSvgSize[size] }) }));
85
+ return (_jsx("button", { type: "button", className: classNames('ncua-input__icon-wrap', 'ncua-input__right-icon', 'ncua-input__clear'), onClick: onClearText, children: _jsx(X, { className: "ncua-input__clear-icon", width: statusIconSvgSize[size], height: statusIconSvgSize[size] }) }));
80
86
  };
81
87
  const renderStatusIcon = () => {
82
88
  if (destructive) {
83
- return (_jsx("div", { className: "ncua-input__icon-wrap ncua-input__right-icon", children: _jsx(InfoCircle, { className: "ncua-input__destructive-icon", width: iconSvgSize[size], height: iconSvgSize[size] }) }));
89
+ return (_jsx("div", { className: "ncua-input__icon-wrap ncua-input__right-icon", children: _jsx(InfoCircle, { className: "ncua-input__destructive-icon", width: statusIconSvgSize[size], height: statusIconSvgSize[size] }) }));
84
90
  }
85
91
  if (validation) {
86
- return (_jsx("div", { className: "ncua-input__icon-wrap ncua-input__right-icon", children: _jsx(CheckCircle, { className: "ncua-input__validation-icon", width: iconSvgSize[size], height: iconSvgSize[size] }) }));
92
+ return (_jsx("div", { className: "ncua-input__icon-wrap ncua-input__right-icon", children: _jsx(CheckCircle, { className: "ncua-input__validation-icon", width: statusIconSvgSize[size], height: statusIconSvgSize[size] }) }));
87
93
  }
88
94
  return null;
89
95
  };
@@ -64,11 +64,12 @@ describe('InputBase — 아이콘 사이즈', () => {
64
64
  const svg = container.querySelector(selector);
65
65
  return { width: svg?.getAttribute('width'), height: svg?.getAttribute('height') };
66
66
  };
67
- // 슬롯 아이콘과 상태 아이콘은 같은 크기를 쓴다 과거 상태 아이콘만 sm=16으로 어긋나 있었다
67
+ // 슬롯 아이콘은 인풋 크기에 연동돼 sm 에서 20px 커지지만,
68
+ // 상태 아이콘(clear·validation·destructive)은 16px 로 고정한다.
68
69
  it.each([
69
- ['xs', '14'],
70
- ['sm', '20'],
71
- ])('size=%s 일 때 슬롯 아이콘과 상태 아이콘이 모두 %spx로 렌더된다', (size, expected) => {
70
+ ['xs', '14', '14'],
71
+ ['sm', '20', '16'],
72
+ ])('size=%s 일 때 슬롯 아이콘은 %spx, 상태 아이콘은 %spx로 렌더된다', (size, slotExpected, statusExpected) => {
72
73
  // Given/When: 슬롯 아이콘과 clear 버튼, destructive 상태를 함께 렌더하면
73
74
  const view = mountInputBase({
74
75
  size,
@@ -77,20 +78,21 @@ describe('InputBase — 아이콘 사이즈', () => {
77
78
  onClearText: vi.fn(),
78
79
  leadingElement: { type: 'icon', icon: SearchLg },
79
80
  });
80
- // Then: 슬롯·clear·destructive 아이콘의 크기가 서로 어긋나지 않는다
81
- const expectedSize = { width: expected, height: expected };
82
- expect(iconSizeOf(view.container, '.ncua-input__left-icon')).toEqual(expectedSize);
83
- expect(iconSizeOf(view.container, '.ncua-input__clear-icon')).toEqual(expectedSize);
84
- expect(iconSizeOf(view.container, '.ncua-input__destructive-icon')).toEqual(expectedSize);
81
+ // Then: 슬롯 아이콘만 인풋 크기를 따라가고, 상태 아이콘은 16px 을 넘지 않는다
82
+ const slotSize = { width: slotExpected, height: slotExpected };
83
+ const statusSize = { width: statusExpected, height: statusExpected };
84
+ expect(iconSizeOf(view.container, '.ncua-input__left-icon')).toEqual(slotSize);
85
+ expect(iconSizeOf(view.container, '.ncua-input__clear-icon')).toEqual(statusSize);
86
+ expect(iconSizeOf(view.container, '.ncua-input__destructive-icon')).toEqual(statusSize);
85
87
  view.unmount();
86
88
  });
87
89
  it.each([
88
90
  ['xs', '14'],
89
- ['sm', '20'],
90
- ])('size=%s 일 때 validation 아이콘도 %spx로 렌더된다', (size, expected) => {
91
+ ['sm', '16'],
92
+ ])('size=%s 일 때 validation 아이콘은 %spx로 렌더된다', (size, expected) => {
91
93
  // Given/When: validation 상태로 렌더하면
92
94
  const view = mountInputBase({ size, validation: true });
93
- // Then: 다른 아이콘과 같은 크기다
95
+ // Then: 다른 상태 아이콘과 같은 크기다
94
96
  expect(iconSizeOf(view.container, '.ncua-input__validation-icon')).toEqual({
95
97
  width: expected,
96
98
  height: expected,
@@ -119,7 +119,7 @@ const PostcodeSearchModal = ({ open, onClose, zIndex, className, searchQuery, on
119
119
  };
120
120
  return (_jsxs(Modal, { isOpen: open, onClose: onClose, size: "md", zIndex: zIndex, className: className, children: [_jsx(Modal.Header, { title: MODAL_TITLE, onClose: onClose, showDivider: true }), _jsx(Modal.Content, { children: _jsxs("div", { className: "ncua-postcode-search-modal", ref: rootRef, children: [_jsxs("div", { className: classnames('ncua-postcode-search-modal__search-area', {
121
121
  'is-fixed': hasResults && isContentScrolled,
122
- }), children: [_jsxs("div", { className: "ncua-postcode-search-modal__search", children: [_jsx(InputBase, { className: "ncua-postcode-search-modal__search-input", size: "sm", fullWidth: true, value: searchQuery, onChange: handleSearchQueryChange, onKeyDown: handleSearchKeyDown, placeholder: SEARCH_PLACEHOLDER, destructive: hasError, hintText: errorCode ? (ERROR_HINT[errorCode] ?? DEFAULT_ERROR_HINT) : undefined }), _jsx(Button, { className: "ncua-postcode-search-modal__search-button", label: SEARCH_BUTTON_LABEL, size: "sm", hierarchy: "secondary", onClick: handleSearch })] }), showSearchHint && (_jsxs("div", { children: [_jsx("p", { className: "ncua-postcode-search-modal__result-title", children: "\uC544\uB798 \uC870\uD569\uC73C\uB85C \uAC80\uC0C9 \uC2DC \uC8FC\uC18C\uB97C \uB354 \uC27D\uAC8C \uCC3E\uC744 \uC218 \uC788\uC5B4\uC694." }), _jsx("p", { className: "ncua-postcode-search-modal__result-desc", children: "\uB3C4\uB85C\uBA85+\uAC74\uBB3C\uBC88\uD638, \uC9C0\uC5ED\uBA85+\uC9C0\uBC88, \uC9C0\uC5ED\uBA85+\uAC74\uBB3C\uBA85(\uC544\uD30C\uD2B8\uBA85)" })] }))] }), !hasResults && _jsx(PostcodeSearchModal.Tip, {}), hasResults && (_jsxs(_Fragment, { children: [_jsxs("p", { className: "ncua-postcode-search-modal__count", children: ["\uAC80\uC0C9 ", _jsx("b", { children: totalCount }), "\uAC1C"] }), _jsx("ul", { className: "ncua-postcode-search-modal__list", children: results.map((result, index) => (_jsx("li", { className: "ncua-postcode-search-modal__item", children: _jsx(Radio, { name: RESULT_RADIO_NAME, value: result.zipCode, checked: selectedKey === resultKey(result), onChange: () => {
122
+ }), children: [_jsxs("div", { className: "ncua-postcode-search-modal__search", children: [_jsx(InputBase, { className: "ncua-postcode-search-modal__search-input", size: "sm", fullWidth: true, value: searchQuery, clearText: !!searchQuery, onClearText: () => onSearchQueryChange(''), onChange: handleSearchQueryChange, onKeyDown: handleSearchKeyDown, placeholder: SEARCH_PLACEHOLDER, destructive: hasError, hintText: errorCode ? (ERROR_HINT[errorCode] ?? DEFAULT_ERROR_HINT) : undefined }), _jsx(Button, { className: "ncua-postcode-search-modal__search-button", label: SEARCH_BUTTON_LABEL, size: "sm", hierarchy: "secondary", onClick: handleSearch })] }), showSearchHint && (_jsxs("div", { children: [_jsx("p", { className: "ncua-postcode-search-modal__result-title", children: "\uC544\uB798 \uC870\uD569\uC73C\uB85C \uAC80\uC0C9 \uC2DC \uC8FC\uC18C\uB97C \uB354 \uC27D\uAC8C \uCC3E\uC744 \uC218 \uC788\uC5B4\uC694." }), _jsx("p", { className: "ncua-postcode-search-modal__result-desc", children: "\uB3C4\uB85C\uBA85+\uAC74\uBB3C\uBC88\uD638, \uC9C0\uC5ED\uBA85+\uC9C0\uBC88, \uC9C0\uC5ED\uBA85+\uAC74\uBB3C\uBA85(\uC544\uD30C\uD2B8\uBA85)" })] }))] }), !hasResults && _jsx(PostcodeSearchModal.Tip, {}), hasResults && (_jsxs(_Fragment, { children: [_jsxs("p", { className: "ncua-postcode-search-modal__count", children: ["\uAC80\uC0C9 ", _jsx("b", { children: totalCount }), "\uAC1C"] }), _jsx("ul", { className: "ncua-postcode-search-modal__list", children: results.map((result, index) => (_jsx("li", { className: "ncua-postcode-search-modal__item", children: _jsx(Radio, { name: RESULT_RADIO_NAME, value: result.zipCode, checked: selectedKey === resultKey(result), onChange: () => {
123
123
  setSelectedKey(resultKey(result));
124
124
  onSelect(result);
125
125
  }, text: _jsxs(_Fragment, { children: [_jsxs("span", { className: "ncua-postcode-search-modal__addr-line", children: [_jsx("span", { className: "ncua-postcode-search-modal__badge", children: ROAD_BADGE_LABEL }), _jsx("span", { className: "ncua-postcode-search-modal__item-road", children: result.roadAddress }), _jsx("span", { className: "ncua-postcode-search-modal__item-zip", children: result.zipCode })] }), _jsxs("span", { className: "ncua-postcode-search-modal__addr-line", children: [_jsx("span", { className: "ncua-postcode-search-modal__badge", children: JIBUN_BADGE_LABEL }), _jsx("span", { className: "ncua-postcode-search-modal__item-jibun", children: result.jibunAddress })] })] }) }) }, `${result.zipCode}-${index}`))) }), _jsx("div", { className: "ncua-postcode-search-modal__pagination", children: _jsx(Pagination, { totalCount: totalCount, itemCountPerPage: pageSize, pageCount: PAGER_WINDOW, currentPage: currentPage, breakPoint: isMobile ? 'mo' : 'pc', onPageChange: onPageChange }) })] })), showEmptyState && (_jsx("div", { className: "ncua-postcode-search-modal__empty", children: _jsx(EmptyState, { title: EMPTY_TITLE, description: EMPTY_DESCRIPTION }) }))] }) })] }));