@ncds/ui-admin 1.8.8 → 1.8.9

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,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.Badge = void 0;
7
7
  var _jsxRuntime = require("react/jsx-runtime");
8
+ var _uiAdminIcon = require("@ncds/ui-admin-icon");
8
9
  var _classnames = _interopRequireDefault(require("classnames"));
9
10
  var _utils = require("./utils");
10
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -12,6 +13,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
12
13
  * 뱃지 컴포넌트의 아이콘은 디자인 시스템에서 12px 고정으로 정의되어 있습니다.
13
14
  */
14
15
  const BADGE_ICON_SIZE = 12;
16
+ /** new-badge 박스 안에 들어가는 'N' 아이콘 크기. 박스는 sm 16px / md 20px 이며 아이콘은 그보다 작다(패딩 포함). */
17
+ const NEW_BADGE_ICON_SIZE = {
18
+ sm: 12,
19
+ md: 16
20
+ };
15
21
  const Badge = _ref => {
16
22
  let {
17
23
  label,
@@ -22,6 +28,19 @@ const Badge = _ref => {
22
28
  trailingIcon,
23
29
  size = 'xs'
24
30
  } = _ref;
31
+ // new-badge: 신규 콘텐츠 'N' 마크 전용 타입. label·color·leadingIcon·trailingIcon은 무시되고
32
+ // 색은 --pink-600 으로 고정된다. (디자이너 명세: Icon/FeaturedIcon/Badge로 대체 불가한 전용 표시)
33
+ if (type === 'new-badge') {
34
+ const newBadgeSize = size === 'md' ? 'md' : 'sm';
35
+ const iconSize = NEW_BADGE_ICON_SIZE[newBadgeSize];
36
+ return (0, _jsxRuntime.jsx)("span", {
37
+ className: (0, _classnames.default)('ncua-badge', 'ncua-badge--new-badge', `ncua-badge--new-badge-${newBadgeSize}`, className),
38
+ children: (0, _jsxRuntime.jsx)(_uiAdminIcon.New, {
39
+ width: iconSize,
40
+ height: iconSize
41
+ })
42
+ });
43
+ }
25
44
  return (0, _jsxRuntime.jsxs)("span", {
26
45
  className: (0, _classnames.default)('ncua-badge', `ncua-badge--${type}`, `ncua-badge--${color}`, `ncua-badge--${size}`, className),
27
46
  children: [leadingIcon && (0, _utils.sideSlotRender)({
@@ -14,6 +14,20 @@ var _shared = require("../../shared");
14
14
  var _FileInput = require("../file-input/FileInput");
15
15
  var _ImagePreview = require("./components/ImagePreview");
16
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
+ const toInvalidFile = (file, errorType) => ({
18
+ name: file.name,
19
+ size: file.size,
20
+ type: file.type,
21
+ lastModified: file.lastModified,
22
+ webkitRelativePath: file.webkitRelativePath,
23
+ arrayBuffer: () => file.arrayBuffer(),
24
+ stream: () => file.stream(),
25
+ text: () => file.text(),
26
+ slice: function () {
27
+ return file.slice(...arguments);
28
+ },
29
+ errorType
30
+ });
17
31
  const ImageFileInput = exports.ImageFileInput = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
18
32
  let {
19
33
  size = 'sm',
@@ -81,25 +95,16 @@ const ImageFileInput = exports.ImageFileInput = /*#__PURE__*/(0, _react.forwardR
81
95
  const invalidFiles = [];
82
96
  for (const file of fileList) {
83
97
  if (files.some(f => f.name === file.name && f.size === file.size)) {
84
- invalidFiles.push({
85
- ...file,
86
- errorType: _FileInput.FileInputErrorType.ALREADY_UPLOADED
87
- });
98
+ invalidFiles.push(toInvalidFile(file, _FileInput.FileInputErrorType.ALREADY_UPLOADED));
88
99
  continue;
89
100
  }
90
101
  if (!!maxFileSize && file.size > maxFileSize) {
91
- invalidFiles.push({
92
- ...file,
93
- errorType: _FileInput.FileInputErrorType.EXCEED_MAX_FILE_SIZE
94
- });
102
+ invalidFiles.push(toInvalidFile(file, _FileInput.FileInputErrorType.EXCEED_MAX_FILE_SIZE));
95
103
  continue;
96
104
  }
97
105
  // Skip max count check if maxFileCount is 1 (allow replacement)
98
106
  if (!!maxFileCount && maxFileCount !== 1 && files.length + validFiles.length >= maxFileCount) {
99
- invalidFiles.push({
100
- ...file,
101
- errorType: _FileInput.FileInputErrorType.EXCEED_MAX_FILE_COUNT
102
- });
107
+ invalidFiles.push(toInvalidFile(file, _FileInput.FileInputErrorType.EXCEED_MAX_FILE_COUNT));
103
108
  continue;
104
109
  }
105
110
  validFiles.push(file);
@@ -1,10 +1,16 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { New } from '@ncds/ui-admin-icon';
2
3
  import classNames from 'classnames';
3
4
  import { sideSlotRender } from './utils';
4
5
  /**
5
6
  * 뱃지 컴포넌트의 아이콘은 디자인 시스템에서 12px 고정으로 정의되어 있습니다.
6
7
  */
7
8
  const BADGE_ICON_SIZE = 12;
9
+ /** new-badge 박스 안에 들어가는 'N' 아이콘 크기. 박스는 sm 16px / md 20px 이며 아이콘은 그보다 작다(패딩 포함). */
10
+ const NEW_BADGE_ICON_SIZE = {
11
+ sm: 12,
12
+ md: 16
13
+ };
8
14
  const Badge = _ref => {
9
15
  let {
10
16
  label,
@@ -15,6 +21,19 @@ const Badge = _ref => {
15
21
  trailingIcon,
16
22
  size = 'xs'
17
23
  } = _ref;
24
+ // new-badge: 신규 콘텐츠 'N' 마크 전용 타입. label·color·leadingIcon·trailingIcon은 무시되고
25
+ // 색은 --pink-600 으로 고정된다. (디자이너 명세: Icon/FeaturedIcon/Badge로 대체 불가한 전용 표시)
26
+ if (type === 'new-badge') {
27
+ const newBadgeSize = size === 'md' ? 'md' : 'sm';
28
+ const iconSize = NEW_BADGE_ICON_SIZE[newBadgeSize];
29
+ return _jsx("span", {
30
+ className: classNames('ncua-badge', 'ncua-badge--new-badge', `ncua-badge--new-badge-${newBadgeSize}`, className),
31
+ children: _jsx(New, {
32
+ width: iconSize,
33
+ height: iconSize
34
+ })
35
+ });
36
+ }
18
37
  return _jsxs("span", {
19
38
  className: classNames('ncua-badge', `ncua-badge--${type}`, `ncua-badge--${color}`, `ncua-badge--${size}`, className),
20
39
  children: [leadingIcon && sideSlotRender({
@@ -7,6 +7,20 @@ import { Tooltip } from '../../overlays/tooltip';
7
7
  import { HintText, Label } from '../../shared';
8
8
  import { FileInputErrorType as ImageFileInputErrorType } from '../file-input/FileInput';
9
9
  import { ImagePreview } from './components/ImagePreview';
10
+ const toInvalidFile = (file, errorType) => ({
11
+ name: file.name,
12
+ size: file.size,
13
+ type: file.type,
14
+ lastModified: file.lastModified,
15
+ webkitRelativePath: file.webkitRelativePath,
16
+ arrayBuffer: () => file.arrayBuffer(),
17
+ stream: () => file.stream(),
18
+ text: () => file.text(),
19
+ slice: function () {
20
+ return file.slice(...arguments);
21
+ },
22
+ errorType
23
+ });
10
24
  export const ImageFileInput = /*#__PURE__*/forwardRef((_ref, ref) => {
11
25
  let {
12
26
  size = 'sm',
@@ -74,25 +88,16 @@ export const ImageFileInput = /*#__PURE__*/forwardRef((_ref, ref) => {
74
88
  const invalidFiles = [];
75
89
  for (const file of fileList) {
76
90
  if (files.some(f => f.name === file.name && f.size === file.size)) {
77
- invalidFiles.push({
78
- ...file,
79
- errorType: ImageFileInputErrorType.ALREADY_UPLOADED
80
- });
91
+ invalidFiles.push(toInvalidFile(file, ImageFileInputErrorType.ALREADY_UPLOADED));
81
92
  continue;
82
93
  }
83
94
  if (!!maxFileSize && file.size > maxFileSize) {
84
- invalidFiles.push({
85
- ...file,
86
- errorType: ImageFileInputErrorType.EXCEED_MAX_FILE_SIZE
87
- });
95
+ invalidFiles.push(toInvalidFile(file, ImageFileInputErrorType.EXCEED_MAX_FILE_SIZE));
88
96
  continue;
89
97
  }
90
98
  // Skip max count check if maxFileCount is 1 (allow replacement)
91
99
  if (!!maxFileCount && maxFileCount !== 1 && files.length + validFiles.length >= maxFileCount) {
92
- invalidFiles.push({
93
- ...file,
94
- errorType: ImageFileInputErrorType.EXCEED_MAX_FILE_COUNT
95
- });
100
+ invalidFiles.push(toInvalidFile(file, ImageFileInputErrorType.EXCEED_MAX_FILE_COUNT));
96
101
  continue;
97
102
  }
98
103
  validFiles.push(file);
@@ -1,11 +1,12 @@
1
1
  import type { ColorTone } from '../../../../constant/color';
2
2
  import type { Size } from '../../../../constant/size';
3
3
  import type { SideSlotType } from '../../../types/side-slot';
4
- type BadgeType = 'pill-outline' | 'pill-dark-color';
4
+ type BadgeType = 'pill-outline' | 'pill-dark-color' | 'new-badge';
5
5
  type BadgeColor = Extract<ColorTone, 'neutral' | 'error' | 'warning' | 'success' | 'blue' | 'pink' | 'disabled'>;
6
6
  type BadgeSize = Extract<Size, 'xs' | 'sm' | 'md'>;
7
7
  type BadgeProps = {
8
- label: string;
8
+ /** new-badge 타입에서는 사용되지 않는다(무시됨). 그 외 타입에서는 필수로 전달한다. */
9
+ label?: string;
9
10
  type?: BadgeType;
10
11
  color?: BadgeColor;
11
12
  className?: string;
@@ -1,11 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { New } from '@ncds/ui-admin-icon';
2
3
  import classNames from 'classnames';
3
4
  import { sideSlotRender } from './utils';
4
5
  /**
5
6
  * 뱃지 컴포넌트의 아이콘은 디자인 시스템에서 12px 고정으로 정의되어 있습니다.
6
7
  */
7
8
  const BADGE_ICON_SIZE = 12;
9
+ /** new-badge 박스 안에 들어가는 'N' 아이콘 크기. 박스는 sm 16px / md 20px 이며 아이콘은 그보다 작다(패딩 포함). */
10
+ const NEW_BADGE_ICON_SIZE = { sm: 12, md: 16 };
8
11
  const Badge = ({ label, type = 'pill-outline', color = 'neutral', className, leadingIcon, trailingIcon, size = 'xs', }) => {
12
+ // new-badge: 신규 콘텐츠 'N' 마크 전용 타입. label·color·leadingIcon·trailingIcon은 무시되고
13
+ // 색은 --pink-600 으로 고정된다. (디자이너 명세: Icon/FeaturedIcon/Badge로 대체 불가한 전용 표시)
14
+ if (type === 'new-badge') {
15
+ const newBadgeSize = size === 'md' ? 'md' : 'sm';
16
+ const iconSize = NEW_BADGE_ICON_SIZE[newBadgeSize];
17
+ return (_jsx("span", { className: classNames('ncua-badge', 'ncua-badge--new-badge', `ncua-badge--new-badge-${newBadgeSize}`, className), children: _jsx(New, { width: iconSize, height: iconSize }) }));
18
+ }
9
19
  return (_jsxs("span", { className: classNames('ncua-badge', `ncua-badge--${type}`, `ncua-badge--${color}`, `ncua-badge--${size}`, className), children: [leadingIcon && sideSlotRender({ slot: leadingIcon, defaultIconSize: BADGE_ICON_SIZE }), _jsx("span", { className: "ncua-badge__label", children: label }), trailingIcon && sideSlotRender({ slot: trailingIcon, defaultIconSize: BADGE_ICON_SIZE })] }));
10
20
  };
11
21
  export { Badge };
@@ -7,6 +7,18 @@ import { Tooltip } from '../../overlays/tooltip';
7
7
  import { HintText, Label } from '../../shared';
8
8
  import { FileInputErrorType as ImageFileInputErrorType } from '../file-input/FileInput';
9
9
  import { ImagePreview } from './components/ImagePreview';
10
+ const toInvalidFile = (file, errorType) => ({
11
+ name: file.name,
12
+ size: file.size,
13
+ type: file.type,
14
+ lastModified: file.lastModified,
15
+ webkitRelativePath: file.webkitRelativePath,
16
+ arrayBuffer: () => file.arrayBuffer(),
17
+ stream: () => file.stream(),
18
+ text: () => file.text(),
19
+ slice: (...args) => file.slice(...args),
20
+ errorType,
21
+ });
10
22
  export const ImageFileInput = forwardRef(({ size = 'sm', accept, multiple = false, maxFileSize, maxFileCount, value, onChange, onFileSelect, onFail, buttonLabel = '파일 찾기', imagePreviewTooltipLabel = '이미지 업로드', disabled, label, hintItems, validation, destructive, isRequired, showHelpIcon, hintText, showFileTagList = true, showHintText = true, showFileInput = true, ...props }, ref) => {
11
23
  const fileInputRef = useRef(null);
12
24
  useImperativeHandle(ref, () => fileInputRef.current);
@@ -48,25 +60,16 @@ export const ImageFileInput = forwardRef(({ size = 'sm', accept, multiple = fals
48
60
  const invalidFiles = [];
49
61
  for (const file of fileList) {
50
62
  if (files.some((f) => f.name === file.name && f.size === file.size)) {
51
- invalidFiles.push({
52
- ...file,
53
- errorType: ImageFileInputErrorType.ALREADY_UPLOADED,
54
- });
63
+ invalidFiles.push(toInvalidFile(file, ImageFileInputErrorType.ALREADY_UPLOADED));
55
64
  continue;
56
65
  }
57
66
  if (!!maxFileSize && file.size > maxFileSize) {
58
- invalidFiles.push({
59
- ...file,
60
- errorType: ImageFileInputErrorType.EXCEED_MAX_FILE_SIZE,
61
- });
67
+ invalidFiles.push(toInvalidFile(file, ImageFileInputErrorType.EXCEED_MAX_FILE_SIZE));
62
68
  continue;
63
69
  }
64
70
  // Skip max count check if maxFileCount is 1 (allow replacement)
65
71
  if (!!maxFileCount && maxFileCount !== 1 && files.length + validFiles.length >= maxFileCount) {
66
- invalidFiles.push({
67
- ...file,
68
- errorType: ImageFileInputErrorType.EXCEED_MAX_FILE_COUNT,
69
- });
72
+ invalidFiles.push(toInvalidFile(file, ImageFileInputErrorType.EXCEED_MAX_FILE_COUNT));
70
73
  continue;
71
74
  }
72
75
  validFiles.push(file);
@@ -1,11 +1,12 @@
1
1
  import type { ColorTone } from '../../../../constant/color';
2
2
  import type { Size } from '../../../../constant/size';
3
3
  import type { SideSlotType } from '../../../types/side-slot';
4
- type BadgeType = 'pill-outline' | 'pill-dark-color';
4
+ type BadgeType = 'pill-outline' | 'pill-dark-color' | 'new-badge';
5
5
  type BadgeColor = Extract<ColorTone, 'neutral' | 'error' | 'warning' | 'success' | 'blue' | 'pink' | 'disabled'>;
6
6
  type BadgeSize = Extract<Size, 'xs' | 'sm' | 'md'>;
7
7
  type BadgeProps = {
8
- label: string;
8
+ /** new-badge 타입에서는 사용되지 않는다(무시됨). 그 외 타입에서는 필수로 전달한다. */
9
+ label?: string;
9
10
  type?: BadgeType;
10
11
  color?: BadgeColor;
11
12
  className?: string;
@@ -5017,6 +5017,20 @@ button {
5017
5017
  color: var(--gray-300);
5018
5018
  background-color: var(--gray-100);
5019
5019
  }
5020
+ .ncua-badge--new-badge {
5021
+ justify-content: center;
5022
+ color: var(--pink-600);
5023
+ background-color: var(--pink-200);
5024
+ border-radius: 5px;
5025
+ }
5026
+ .ncua-badge--new-badge-sm {
5027
+ width: 16px;
5028
+ height: 16px;
5029
+ }
5030
+ .ncua-badge--new-badge-md {
5031
+ width: 20px;
5032
+ height: 20px;
5033
+ }
5020
5034
 
5021
5035
  .ncua-badge-group {
5022
5036
  display: inline-flex;
@@ -5965,6 +5979,8 @@ button {
5965
5979
  }
5966
5980
 
5967
5981
  .ncua-table {
5982
+ --ncua-table-header-height: 40px;
5983
+ --ncua-table-default-min-width: 1140px;
5968
5984
  position: relative;
5969
5985
  display: flex;
5970
5986
  flex-direction: column;
@@ -6357,6 +6373,24 @@ button {
6357
6373
  align-items: center;
6358
6374
  line-height: 1;
6359
6375
  }
6376
+ .ncua-table--vertical .ncua-table .ncua-table__header > .ncua-table__row th:first-child {
6377
+ width: auto;
6378
+ min-width: 0;
6379
+ max-width: none;
6380
+ padding: 0 var(--spacing-m);
6381
+ font-size: var(--font-size-xs);
6382
+ font-weight: var(--font-weights-commerce-sans-1);
6383
+ line-height: var(--line-heights-xs);
6384
+ color: var(--gray-500);
6385
+ text-align: center;
6386
+ background: var(--gray-100);
6387
+ border-right: 1px solid var(--gray-200);
6388
+ }
6389
+ .ncua-table--vertical .ncua-table .ncua-table__header > .ncua-table__row th:last-child {
6390
+ padding: 0 var(--spacing-m);
6391
+ text-align: center;
6392
+ font-weight: var(--font-weights-commerce-sans-1);
6393
+ }
6360
6394
  .ncua-table--vertical .ncua-table .ncua-table__body > .ncua-table__row td:first-child,
6361
6395
  .ncua-table--vertical .ncua-table .ncua-table__body > .ncua-table__row th:first-child {
6362
6396
  width: auto;
@@ -6501,7 +6535,15 @@ button {
6501
6535
  border: 1px solid var(--gray-100);
6502
6536
  border-radius: 12px;
6503
6537
  box-shadow: var(--shadow-sm);
6504
- overflow: hidden;
6538
+ }
6539
+ .ncua-block-container > *:first-child {
6540
+ border-radius: 12px 12px 0 0;
6541
+ }
6542
+ .ncua-block-container > *:last-child {
6543
+ border-radius: 0 0 12px 12px;
6544
+ }
6545
+ .ncua-block-container > *:only-child, .ncua-block-container > *:first-child:has(~ *:last-child[style*="display: none"]), .ncua-block-container > *:first-child:has(~ *:last-child[hidden]) {
6546
+ border-radius: 12px;
6505
6547
  }
6506
6548
  .ncua-block-container__body {
6507
6549
  display: flex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ncds/ui-admin",
3
- "version": "1.8.8",
3
+ "version": "1.8.9",
4
4
  "description": "nhn-commerce의 어드민 디자인 시스템입니다.",
5
5
  "scripts": {
6
6
  "barrel": "node barrel.js",
@@ -70,7 +70,7 @@
70
70
  "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "2.1.0",
71
71
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "1.1.0",
72
72
  "@atlaskit/pragmatic-drag-and-drop-react-accessibility": "1.1.4",
73
- "@ncds/ui-admin-icon": "0.1.9",
73
+ "@ncds/ui-admin-icon": "0.1.11",
74
74
  "classnames": "2.5.1",
75
75
  "dompurify": "3.4.1",
76
76
  "flatpickr": "4.6.13",