@ncds/ui-admin 1.8.4 → 1.8.6
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/cjs/assets/scripts/featuredIcon.js +87 -0
- package/dist/cjs/assets/scripts/notification/FloatingNotification.js +178 -0
- package/dist/cjs/assets/scripts/notification/FullWidthNotification.js +133 -0
- package/dist/cjs/assets/scripts/notification/MessageNotification.js +159 -0
- package/dist/cjs/assets/scripts/notification/Notification.js +120 -0
- package/dist/cjs/assets/scripts/notification/const/classNames.js +50 -0
- package/dist/cjs/assets/scripts/notification/const/icons.js +31 -0
- package/dist/cjs/assets/scripts/notification/const/index.js +87 -0
- package/dist/cjs/assets/scripts/notification/const/sizes.js +46 -0
- package/dist/cjs/assets/scripts/notification/const/types.js +14 -0
- package/dist/cjs/assets/scripts/notification/index.js +116 -0
- package/dist/cjs/assets/scripts/notification/positionSync.js +180 -0
- package/dist/cjs/assets/scripts/notification/utils.js +122 -0
- package/dist/cjs/assets/scripts/shared/ButtonCloseX.js +45 -0
- package/dist/cjs/assets/scripts/utils/sanitize.js +39 -0
- package/dist/cjs/src/components/data-display/data-grid/DataGrid.js +5 -1
- package/dist/cjs/src/components/data-display/table/Table.js +118 -96
- package/dist/cjs/src/components/data-display/table/useTableScrollbars.js +187 -0
- package/dist/cjs/src/components/forms-and-input/combo-box/ComboBox.js +11 -10
- package/dist/cjs/src/components/forms-and-input/image-file-input/ImageFileInput.js +5 -2
- package/dist/cjs/src/components/forms-and-input/select-box/SelectBox.js +67 -29
- package/dist/cjs/src/components/forms-and-input/slider/Slider.js +2 -3
- package/dist/cjs/src/components/overlays/dropdown/Dropdown.js +47 -19
- package/dist/cjs/src/components/overlays/notification/CalloutNotification.js +25 -0
- package/dist/cjs/src/components/overlays/notification/FloatingNotification.js +86 -13
- package/dist/cjs/src/components/overlays/notification/Notification.js +7 -0
- package/dist/cjs/src/components/overlays/notification/host.js +12 -0
- package/dist/cjs/src/components/overlays/tooltip/Tooltip.js +57 -44
- package/dist/cjs/src/components/select-dropdown/SelectDropdown.js +2 -1
- package/dist/cjs/src/contexts/FloatingContext.js +11 -0
- package/dist/cjs/src/contexts/index.js +16 -0
- package/dist/cjs/src/hooks/index.js +11 -0
- package/dist/cjs/src/hooks/useFloatingPosition.js +78 -0
- package/dist/cjs/src/hooks/usePortalState.js +17 -0
- package/dist/cjs/src/types/component-meta.js +8 -1
- package/dist/cjs/src/utils/dropdown/maxSelection.js +35 -0
- package/dist/cjs/src/utils/dropdown/multiSelect.js +72 -15
- package/dist/esm/assets/scripts/featuredIcon.js +80 -0
- package/dist/esm/assets/scripts/notification/FloatingNotification.js +171 -0
- package/dist/esm/assets/scripts/notification/FullWidthNotification.js +126 -0
- package/dist/esm/assets/scripts/notification/MessageNotification.js +152 -0
- package/dist/esm/assets/scripts/notification/Notification.js +113 -0
- package/dist/esm/assets/scripts/notification/const/classNames.js +44 -0
- package/dist/esm/assets/scripts/notification/const/icons.js +25 -0
- package/dist/esm/assets/scripts/notification/const/index.js +4 -0
- package/dist/esm/assets/scripts/notification/const/sizes.js +40 -0
- package/dist/esm/assets/scripts/notification/const/types.js +8 -0
- package/dist/esm/assets/scripts/notification/index.js +10 -0
- package/dist/esm/assets/scripts/notification/positionSync.js +171 -0
- package/dist/esm/assets/scripts/notification/utils.js +109 -0
- package/dist/esm/assets/scripts/shared/ButtonCloseX.js +37 -0
- package/dist/esm/assets/scripts/utils/sanitize.js +31 -0
- package/dist/esm/src/components/data-display/data-grid/DataGrid.js +5 -1
- package/dist/esm/src/components/data-display/table/Table.js +118 -96
- package/dist/esm/src/components/data-display/table/useTableScrollbars.js +179 -0
- package/dist/esm/src/components/forms-and-input/combo-box/ComboBox.js +11 -10
- package/dist/esm/src/components/forms-and-input/image-file-input/ImageFileInput.js +5 -2
- package/dist/esm/src/components/forms-and-input/select-box/SelectBox.js +67 -29
- package/dist/esm/src/components/forms-and-input/slider/Slider.js +1 -2
- package/dist/esm/src/components/overlays/dropdown/Dropdown.js +47 -19
- package/dist/esm/src/components/overlays/notification/CalloutNotification.js +19 -0
- package/dist/esm/src/components/overlays/notification/FloatingNotification.js +86 -14
- package/dist/esm/src/components/overlays/notification/Notification.js +7 -0
- package/dist/esm/src/components/overlays/notification/host.js +9 -0
- package/dist/esm/src/components/overlays/tooltip/Tooltip.js +58 -45
- package/dist/esm/src/components/select-dropdown/SelectDropdown.js +2 -1
- package/dist/esm/src/contexts/FloatingContext.js +4 -0
- package/dist/esm/src/contexts/index.js +1 -0
- package/dist/esm/src/hooks/index.js +1 -0
- package/dist/esm/src/hooks/useFloatingPosition.js +71 -0
- package/dist/esm/src/hooks/usePortalState.js +10 -0
- package/dist/esm/src/types/component-meta.js +5 -1
- package/dist/esm/src/utils/dropdown/maxSelection.js +27 -0
- package/dist/esm/src/utils/dropdown/multiSelect.js +70 -14
- package/dist/temp/assets/scripts/featuredIcon.d.ts +22 -0
- package/dist/temp/assets/scripts/featuredIcon.js +79 -0
- package/dist/temp/assets/scripts/notification/FloatingNotification.d.ts +24 -0
- package/dist/temp/assets/scripts/notification/FloatingNotification.js +156 -0
- package/dist/temp/assets/scripts/notification/FullWidthNotification.d.ts +21 -0
- package/dist/temp/assets/scripts/notification/FullWidthNotification.js +111 -0
- package/dist/temp/assets/scripts/notification/MessageNotification.d.ts +22 -0
- package/dist/temp/assets/scripts/notification/MessageNotification.js +140 -0
- package/dist/temp/assets/scripts/notification/Notification.d.ts +22 -0
- package/dist/temp/assets/scripts/notification/Notification.js +112 -0
- package/dist/temp/assets/scripts/notification/const/classNames.d.ts +43 -0
- package/dist/temp/assets/scripts/notification/const/classNames.js +44 -0
- package/dist/temp/assets/scripts/notification/const/icons.d.ts +25 -0
- package/dist/temp/assets/scripts/notification/const/icons.js +25 -0
- package/dist/temp/assets/scripts/notification/const/index.d.ts +5 -0
- package/dist/temp/assets/scripts/notification/const/index.js +4 -0
- package/dist/temp/assets/scripts/notification/const/sizes.d.ts +32 -0
- package/dist/temp/assets/scripts/notification/const/sizes.js +40 -0
- package/dist/temp/assets/scripts/notification/const/types.d.ts +19 -0
- package/dist/temp/assets/scripts/notification/const/types.js +8 -0
- package/dist/temp/assets/scripts/notification/index.d.ts +8 -0
- package/dist/temp/assets/scripts/notification/index.js +10 -0
- package/dist/temp/assets/scripts/notification/positionSync.d.ts +50 -0
- package/dist/temp/assets/scripts/notification/positionSync.js +170 -0
- package/dist/temp/assets/scripts/notification/utils.d.ts +8 -0
- package/dist/temp/assets/scripts/notification/utils.js +115 -0
- package/dist/temp/assets/scripts/shared/ButtonCloseX.d.ts +5 -0
- package/dist/temp/assets/scripts/shared/ButtonCloseX.js +33 -0
- package/dist/temp/assets/scripts/utils/sanitize.d.ts +22 -0
- package/dist/temp/assets/scripts/utils/sanitize.js +31 -0
- package/dist/temp/src/components/data-display/data-grid/DataGrid.js +1 -1
- package/dist/temp/src/components/data-display/data-grid/DataGrid.types.d.ts +7 -0
- package/dist/temp/src/components/data-display/table/Table.d.ts +4 -1
- package/dist/temp/src/components/data-display/table/Table.js +53 -68
- package/dist/temp/src/components/data-display/table/types.d.ts +18 -0
- package/dist/temp/src/components/data-display/table/useTableScrollbars.d.ts +25 -0
- package/dist/temp/src/components/data-display/table/useTableScrollbars.js +136 -0
- package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.d.ts +8 -0
- package/dist/temp/src/components/forms-and-input/combo-box/ComboBox.js +7 -11
- package/dist/temp/src/components/forms-and-input/image-file-input/ImageFileInput.js +1 -1
- package/dist/temp/src/components/forms-and-input/select-box/SelectBox.d.ts +13 -0
- package/dist/temp/src/components/forms-and-input/select-box/SelectBox.js +30 -3
- package/dist/temp/src/components/forms-and-input/slider/Slider.d.ts +0 -1
- package/dist/temp/src/components/forms-and-input/slider/Slider.js +0 -1
- package/dist/temp/src/components/overlays/dropdown/Dropdown.d.ts +5 -0
- package/dist/temp/src/components/overlays/dropdown/Dropdown.js +35 -11
- package/dist/temp/src/components/overlays/notification/CalloutNotification.d.ts +9 -0
- package/dist/temp/src/components/overlays/notification/CalloutNotification.js +6 -0
- package/dist/temp/src/components/overlays/notification/FloatingNotification.d.ts +15 -0
- package/dist/temp/src/components/overlays/notification/FloatingNotification.js +81 -13
- package/dist/temp/src/components/overlays/notification/Notification.d.ts +18 -3
- package/dist/temp/src/components/overlays/notification/Notification.js +4 -0
- package/dist/temp/src/components/overlays/notification/host.d.ts +9 -0
- package/dist/temp/src/components/overlays/notification/host.js +9 -0
- package/dist/temp/src/components/overlays/tooltip/Tooltip.d.ts +5 -1
- package/dist/temp/src/components/overlays/tooltip/Tooltip.js +25 -22
- package/dist/temp/src/components/select-dropdown/SelectDropdown.d.ts +6 -0
- package/dist/temp/src/components/select-dropdown/SelectDropdown.js +2 -2
- package/dist/temp/src/contexts/FloatingContext.d.ts +6 -0
- package/dist/temp/src/contexts/FloatingContext.js +4 -0
- package/dist/temp/src/contexts/index.d.ts +1 -0
- package/dist/temp/src/contexts/index.js +1 -0
- package/dist/temp/src/hooks/index.d.ts +1 -0
- package/dist/temp/src/hooks/index.js +1 -0
- package/dist/temp/src/hooks/useFloatingPosition.d.ts +19 -0
- package/dist/temp/src/hooks/useFloatingPosition.js +55 -0
- package/dist/temp/src/hooks/usePortalState.d.ts +6 -0
- package/dist/temp/src/hooks/usePortalState.js +7 -0
- package/dist/temp/src/types/component-meta.d.ts +6 -2
- package/dist/temp/src/types/component-meta.js +14 -1
- package/dist/temp/src/utils/dropdown/maxSelection.d.ts +24 -0
- package/dist/temp/src/utils/dropdown/maxSelection.js +28 -0
- package/dist/temp/src/utils/dropdown/multiSelect.d.ts +42 -2
- package/dist/temp/src/utils/dropdown/multiSelect.js +66 -13
- package/dist/types/assets/scripts/featuredIcon.d.ts +22 -0
- package/dist/types/assets/scripts/notification/FloatingNotification.d.ts +24 -0
- package/dist/types/assets/scripts/notification/FullWidthNotification.d.ts +21 -0
- package/dist/types/assets/scripts/notification/MessageNotification.d.ts +22 -0
- package/dist/types/assets/scripts/notification/Notification.d.ts +22 -0
- package/dist/types/assets/scripts/notification/const/classNames.d.ts +43 -0
- package/dist/types/assets/scripts/notification/const/icons.d.ts +25 -0
- package/dist/types/assets/scripts/notification/const/index.d.ts +5 -0
- package/dist/types/assets/scripts/notification/const/sizes.d.ts +32 -0
- package/dist/types/assets/scripts/notification/const/types.d.ts +19 -0
- package/dist/types/assets/scripts/notification/index.d.ts +8 -0
- package/dist/types/assets/scripts/notification/positionSync.d.ts +50 -0
- package/dist/types/assets/scripts/notification/utils.d.ts +8 -0
- package/dist/types/assets/scripts/shared/ButtonCloseX.d.ts +5 -0
- package/dist/types/assets/scripts/utils/sanitize.d.ts +22 -0
- package/dist/types/src/components/data-display/data-grid/DataGrid.types.d.ts +7 -0
- package/dist/types/src/components/data-display/table/Table.d.ts +4 -1
- package/dist/types/src/components/data-display/table/types.d.ts +18 -0
- package/dist/types/src/components/data-display/table/useTableScrollbars.d.ts +25 -0
- package/dist/types/src/components/forms-and-input/combo-box/ComboBox.d.ts +8 -0
- package/dist/types/src/components/forms-and-input/select-box/SelectBox.d.ts +13 -0
- package/dist/types/src/components/forms-and-input/slider/Slider.d.ts +0 -1
- package/dist/types/src/components/overlays/dropdown/Dropdown.d.ts +5 -0
- package/dist/types/src/components/overlays/notification/CalloutNotification.d.ts +9 -0
- package/dist/types/src/components/overlays/notification/FloatingNotification.d.ts +15 -0
- package/dist/types/src/components/overlays/notification/Notification.d.ts +18 -3
- package/dist/types/src/components/overlays/notification/host.d.ts +9 -0
- package/dist/types/src/components/overlays/tooltip/Tooltip.d.ts +5 -1
- package/dist/types/src/components/select-dropdown/SelectDropdown.d.ts +6 -0
- package/dist/types/src/contexts/FloatingContext.d.ts +6 -0
- package/dist/types/src/contexts/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/useFloatingPosition.d.ts +19 -0
- package/dist/types/src/hooks/usePortalState.d.ts +6 -0
- package/dist/types/src/types/component-meta.d.ts +6 -2
- package/dist/types/src/utils/dropdown/maxSelection.d.ts +24 -0
- package/dist/types/src/utils/dropdown/multiSelect.d.ts +42 -2
- package/dist/ui-admin/assets/styles/style.css +312 -64
- package/package.json +1 -1
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ChevronDown, ChevronSelectorVertical, ChevronUp } from '@ncds/ui-admin-icon';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
|
-
import { Children, forwardRef,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
4
|
+
import { Children, forwardRef, useRef } from 'react';
|
|
5
|
+
import { FloatingProvider } from '../../../contexts/FloatingContext';
|
|
6
|
+
import { TABLE_HEADER_HEIGHT, useTableHorizontalScrollbar, useTableVerticalScrollbar } from './useTableScrollbars';
|
|
7
|
+
// 가로 스크롤 디자인 기준 폭 — 14인치 모니터 + LNB 고려한 디자인 권장 너비
|
|
8
|
+
const DEFAULT_HORIZONTAL_SCROLL_MIN_WIDTH = 1140;
|
|
9
|
+
const FLOATING_PORTAL_VALUE = {
|
|
10
|
+
preferPortal: true
|
|
11
|
+
};
|
|
12
|
+
// TABLE_HEADER_HEIGHT·DEFAULT_HORIZONTAL_SCROLL_MIN_WIDTH를 CSS 커스텀 프로퍼티로 주입 — SCSS fallback 단일 소스
|
|
13
|
+
const WRAPPER_STYLE = {
|
|
14
|
+
'--ncua-table-header-height': `${TABLE_HEADER_HEIGHT}px`,
|
|
15
|
+
'--ncua-table-default-min-width': `${DEFAULT_HORIZONTAL_SCROLL_MIN_WIDTH}px`
|
|
16
|
+
};
|
|
11
17
|
// Sort Icons (@ncds/ui-admin-icon)
|
|
12
18
|
// ──────────────────────────────────────────────
|
|
13
19
|
const SORT_ICONS = {
|
|
@@ -72,6 +78,7 @@ const HeaderCell = /*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
|
72
78
|
sortDirection,
|
|
73
79
|
onSort,
|
|
74
80
|
width,
|
|
81
|
+
minWidth,
|
|
75
82
|
style,
|
|
76
83
|
...rest
|
|
77
84
|
} = _ref4;
|
|
@@ -84,7 +91,8 @@ const HeaderCell = /*#__PURE__*/forwardRef((_ref4, ref) => {
|
|
|
84
91
|
}),
|
|
85
92
|
style: {
|
|
86
93
|
...style,
|
|
87
|
-
width
|
|
94
|
+
width,
|
|
95
|
+
minWidth
|
|
88
96
|
},
|
|
89
97
|
"aria-sort": isSortable ? ARIA_SORT_MAP[sortDirection] : undefined,
|
|
90
98
|
onClick: isSortable ? onSort : undefined,
|
|
@@ -153,10 +161,11 @@ const Pagination = _ref7 => {
|
|
|
153
161
|
Pagination.displayName = 'Table.Pagination';
|
|
154
162
|
const ColGroup = _ref8 => {
|
|
155
163
|
let {
|
|
156
|
-
widths
|
|
164
|
+
widths,
|
|
165
|
+
minWidths
|
|
157
166
|
} = _ref8;
|
|
158
167
|
const resolveColWidth = width => {
|
|
159
|
-
if (width === 'auto') return undefined;
|
|
168
|
+
if (width === undefined || width === 'auto') return undefined;
|
|
160
169
|
if (typeof width === 'number') return `${width}px`;
|
|
161
170
|
return width;
|
|
162
171
|
};
|
|
@@ -165,7 +174,8 @@ const ColGroup = _ref8 => {
|
|
|
165
174
|
// biome-ignore lint/suspicious/noArrayIndexKey: colgroup columns never reorder or change
|
|
166
175
|
_jsx("col", {
|
|
167
176
|
style: {
|
|
168
|
-
width: resolveColWidth(width)
|
|
177
|
+
width: resolveColWidth(width),
|
|
178
|
+
minWidth: resolveColWidth(minWidths?.[index])
|
|
169
179
|
}
|
|
170
180
|
}, index))
|
|
171
181
|
});
|
|
@@ -227,6 +237,8 @@ const TableComponent = /*#__PURE__*/forwardRef((_ref0, ref) => {
|
|
|
227
237
|
maxHeight,
|
|
228
238
|
hoverable = true,
|
|
229
239
|
selectable = false,
|
|
240
|
+
horizontalScroll = false,
|
|
241
|
+
minWidth,
|
|
230
242
|
children,
|
|
231
243
|
className,
|
|
232
244
|
...rest
|
|
@@ -251,85 +263,99 @@ const TableComponent = /*#__PURE__*/forwardRef((_ref0, ref) => {
|
|
|
251
263
|
// Custom scrollbar refs (used only in fixed-header mode)
|
|
252
264
|
const scrollContainerRef = useRef(null);
|
|
253
265
|
const scrollAreaRef = useRef(null);
|
|
266
|
+
const scrollbarRef = useRef(null);
|
|
254
267
|
const thumbRef = useRef(null);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
areaEl?.removeAttribute('data-dragging');
|
|
307
|
-
document.removeEventListener('mousemove', onMove);
|
|
308
|
-
document.removeEventListener('mouseup', onUp);
|
|
309
|
-
};
|
|
310
|
-
document.addEventListener('mousemove', onMove);
|
|
311
|
-
document.addEventListener('mouseup', onUp);
|
|
268
|
+
// 가로 스크롤바 refs (horizontalScroll 모드)
|
|
269
|
+
const hScrollContainerRef = useRef(null);
|
|
270
|
+
const hScrollbarRef = useRef(null);
|
|
271
|
+
const hThumbRef = useRef(null);
|
|
272
|
+
const fixedScrollEnabled = !!(fixedHeader && maxHeight);
|
|
273
|
+
const {
|
|
274
|
+
handleThumbMouseDown
|
|
275
|
+
} = useTableVerticalScrollbar({
|
|
276
|
+
enabled: fixedScrollEnabled,
|
|
277
|
+
scrollContainerRef,
|
|
278
|
+
scrollAreaRef,
|
|
279
|
+
thumbRef
|
|
280
|
+
});
|
|
281
|
+
const {
|
|
282
|
+
handleHThumbMouseDown
|
|
283
|
+
} = useTableHorizontalScrollbar({
|
|
284
|
+
enabled: horizontalScroll,
|
|
285
|
+
hScrollContainerRef,
|
|
286
|
+
hScrollbarRef,
|
|
287
|
+
hThumbRef
|
|
288
|
+
});
|
|
289
|
+
// <colgroup> + <thead> + <tbody> 묶음 — fixed-header 분기와 horizontalScroll 분기 모두에서 재사용
|
|
290
|
+
const renderTable = () => _jsxs("table", {
|
|
291
|
+
className: "ncua-table__table",
|
|
292
|
+
role: "table",
|
|
293
|
+
children: [colGroupContent, headerContent, tableContent]
|
|
294
|
+
});
|
|
295
|
+
// fixed-header 시 scroll-area + scrollbar 래핑, 아니면 <table> 그대로.
|
|
296
|
+
// withScrollbar=false 이면 scrollbar를 제외 — horizontalScroll 분기에서 scrollbar를
|
|
297
|
+
// h-scroll-container 형제 위치에 별도 렌더해 가로 스크롤 시 viewport 우측에 자연 고정.
|
|
298
|
+
const renderScrollableArea = function () {
|
|
299
|
+
let includeVerticalScrollbar = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
|
|
300
|
+
return fixedScrollEnabled ? _jsxs("div", {
|
|
301
|
+
ref: scrollAreaRef,
|
|
302
|
+
className: "ncua-table__scroll-area",
|
|
303
|
+
children: [_jsx("div", {
|
|
304
|
+
ref: scrollContainerRef,
|
|
305
|
+
className: "ncua-table__scroll-container",
|
|
306
|
+
style: scrollStyle,
|
|
307
|
+
children: renderTable()
|
|
308
|
+
}), includeVerticalScrollbar && _jsx("div", {
|
|
309
|
+
ref: scrollbarRef,
|
|
310
|
+
className: "ncua-table__scrollbar",
|
|
311
|
+
"aria-hidden": "true",
|
|
312
|
+
children: _jsx("div", {
|
|
313
|
+
ref: thumbRef,
|
|
314
|
+
className: "ncua-table__scrollbar-thumb",
|
|
315
|
+
onMouseDown: handleThumbMouseDown
|
|
316
|
+
})
|
|
317
|
+
})]
|
|
318
|
+
}) : renderTable();
|
|
312
319
|
};
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
+
// horizontalScroll=true 시 외곽 wrapper + FloatingProvider 부착.
|
|
321
|
+
// 핵심 — __h-scroll-container 는 <table>(또는 scroll-area) 만 감싸고, footer/pagination 은
|
|
322
|
+
// 그 바깥에서 항상 고정 위치. 세로 스크롤바는 h-scroll-container 형제로 배치되어
|
|
323
|
+
// 가로 스크롤에 영향받지 않고 .ncua-table 우측에 absolute 고정된다.
|
|
324
|
+
if (horizontalScroll) {
|
|
325
|
+
const resolvedMinWidth = minWidth ?? DEFAULT_HORIZONTAL_SCROLL_MIN_WIDTH;
|
|
326
|
+
// CSS 변수로 전달 — SCSS 에서 max(100%, var(--ncua-table-min-width)) 로 부모 너비를 항상 보장한다.
|
|
327
|
+
// (inline min-width 를 직접 주면 부모보다 작은 값에서 wrapper 가 좁아져 콘텐츠가 깨짐)
|
|
328
|
+
const innerStyle = {
|
|
329
|
+
'--ncua-table-min-width': typeof resolvedMinWidth === 'number' ? `${resolvedMinWidth}px` : resolvedMinWidth
|
|
330
|
+
};
|
|
331
|
+
return _jsx(FloatingProvider, {
|
|
332
|
+
value: FLOATING_PORTAL_VALUE,
|
|
333
|
+
children: _jsxs("div", {
|
|
334
|
+
ref: ref,
|
|
335
|
+
className: "ncua-table-wrapper",
|
|
336
|
+
style: WRAPPER_STYLE,
|
|
320
337
|
children: [_jsxs("div", {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
children: [
|
|
324
|
-
ref:
|
|
325
|
-
className: "ncua-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
338
|
+
className: tableClasses,
|
|
339
|
+
...rest,
|
|
340
|
+
children: [_jsxs("div", {
|
|
341
|
+
ref: hScrollContainerRef,
|
|
342
|
+
className: "ncua-table__h-scroll-container",
|
|
343
|
+
children: [_jsx("div", {
|
|
344
|
+
className: "ncua-table__h-scroll-inner",
|
|
345
|
+
style: innerStyle,
|
|
346
|
+
children: renderScrollableArea(false)
|
|
347
|
+
}), _jsx("div", {
|
|
348
|
+
ref: hScrollbarRef,
|
|
349
|
+
className: "ncua-table__h-scrollbar",
|
|
350
|
+
"aria-hidden": "true",
|
|
351
|
+
children: _jsx("div", {
|
|
352
|
+
ref: hThumbRef,
|
|
353
|
+
className: "ncua-table__h-scrollbar-thumb",
|
|
354
|
+
onMouseDown: handleHThumbMouseDown
|
|
355
|
+
})
|
|
356
|
+
})]
|
|
357
|
+
}), fixedScrollEnabled && _jsx("div", {
|
|
358
|
+
ref: scrollbarRef,
|
|
333
359
|
className: "ncua-table__scrollbar",
|
|
334
360
|
"aria-hidden": "true",
|
|
335
361
|
children: _jsx("div", {
|
|
@@ -337,23 +363,19 @@ const TableComponent = /*#__PURE__*/forwardRef((_ref0, ref) => {
|
|
|
337
363
|
className: "ncua-table__scrollbar-thumb",
|
|
338
364
|
onMouseDown: handleThumbMouseDown
|
|
339
365
|
})
|
|
340
|
-
})]
|
|
341
|
-
}),
|
|
342
|
-
})
|
|
366
|
+
}), footerContent]
|
|
367
|
+
}), paginationContent]
|
|
368
|
+
})
|
|
343
369
|
});
|
|
344
370
|
}
|
|
345
|
-
const tableElement = _jsxs("table", {
|
|
346
|
-
className: "ncua-table__table",
|
|
347
|
-
role: "table",
|
|
348
|
-
children: [colGroupContent, headerContent, tableContent]
|
|
349
|
-
});
|
|
350
371
|
return _jsxs("div", {
|
|
351
372
|
ref: ref,
|
|
352
373
|
className: "ncua-table-wrapper",
|
|
374
|
+
style: WRAPPER_STYLE,
|
|
353
375
|
children: [_jsxs("div", {
|
|
354
376
|
className: tableClasses,
|
|
355
377
|
...rest,
|
|
356
|
-
children: [
|
|
378
|
+
children: [renderScrollableArea(), footerContent]
|
|
357
379
|
}), paginationContent]
|
|
358
380
|
});
|
|
359
381
|
});
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
// ──────────────────────────────────────────────
|
|
3
|
+
// 상수 — Table.tsx 와 _table.scss 양쪽에서 동기화 필요
|
|
4
|
+
// ──────────────────────────────────────────────
|
|
5
|
+
// $table-header-height
|
|
6
|
+
export const TABLE_HEADER_HEIGHT = 40;
|
|
7
|
+
// 세로/가로 thumb 최소 크기
|
|
8
|
+
export const SCROLLBAR_THUMB_MIN_HEIGHT = 40;
|
|
9
|
+
export const H_SCROLLBAR_THUMB_MIN_WIDTH = 40;
|
|
10
|
+
// SCSS .ncua-table__h-scrollbar { left/right: var(--spacing-s) = 8px } 와 동기화
|
|
11
|
+
export const H_SCROLLBAR_SIDE_GAP = 8;
|
|
12
|
+
// 세로 트랙 상하 여백 합계 — top 8 + bottom 8 = 16 (header 회피분 40 은 별도 처리)
|
|
13
|
+
// biome-ignore lint/style/useExportsLast: 상수는 문서 주석과 함께 상단에 정의
|
|
14
|
+
export const SCROLLBAR_TRACK_OFFSET = 16;
|
|
15
|
+
const startDrag = (e, options) => {
|
|
16
|
+
e.preventDefault();
|
|
17
|
+
const {
|
|
18
|
+
axis,
|
|
19
|
+
scrollEl,
|
|
20
|
+
thumbEl,
|
|
21
|
+
draggingTarget = scrollEl,
|
|
22
|
+
sideGap = 0
|
|
23
|
+
} = options;
|
|
24
|
+
draggingTarget.setAttribute('data-dragging', '');
|
|
25
|
+
if (axis === 'y') {
|
|
26
|
+
const startY = e.clientY;
|
|
27
|
+
const startScrollTop = scrollEl.scrollTop;
|
|
28
|
+
const {
|
|
29
|
+
scrollHeight,
|
|
30
|
+
clientHeight
|
|
31
|
+
} = scrollEl;
|
|
32
|
+
const thumbHeight = thumbEl.offsetHeight;
|
|
33
|
+
const ratio = (scrollHeight - clientHeight) / (clientHeight - thumbHeight);
|
|
34
|
+
const onMove = ev => {
|
|
35
|
+
scrollEl.scrollTop = startScrollTop + (ev.clientY - startY) * ratio;
|
|
36
|
+
};
|
|
37
|
+
const onUp = () => {
|
|
38
|
+
draggingTarget.removeAttribute('data-dragging');
|
|
39
|
+
document.removeEventListener('mousemove', onMove);
|
|
40
|
+
document.removeEventListener('mouseup', onUp);
|
|
41
|
+
};
|
|
42
|
+
document.addEventListener('mousemove', onMove);
|
|
43
|
+
document.addEventListener('mouseup', onUp);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const startX = e.clientX;
|
|
47
|
+
const startScrollLeft = scrollEl.scrollLeft;
|
|
48
|
+
const {
|
|
49
|
+
scrollWidth,
|
|
50
|
+
clientWidth
|
|
51
|
+
} = scrollEl;
|
|
52
|
+
const thumbWidth = thumbEl.offsetWidth;
|
|
53
|
+
const trackWidth = clientWidth - sideGap * 2;
|
|
54
|
+
const ratio = (scrollWidth - clientWidth) / (trackWidth - thumbWidth);
|
|
55
|
+
const onMove = ev => {
|
|
56
|
+
scrollEl.scrollLeft = startScrollLeft + (ev.clientX - startX) * ratio;
|
|
57
|
+
};
|
|
58
|
+
const onUp = () => {
|
|
59
|
+
draggingTarget.removeAttribute('data-dragging');
|
|
60
|
+
document.removeEventListener('mousemove', onMove);
|
|
61
|
+
document.removeEventListener('mouseup', onUp);
|
|
62
|
+
};
|
|
63
|
+
document.addEventListener('mousemove', onMove);
|
|
64
|
+
document.addEventListener('mouseup', onUp);
|
|
65
|
+
};
|
|
66
|
+
export const useTableVerticalScrollbar = _ref => {
|
|
67
|
+
let {
|
|
68
|
+
enabled,
|
|
69
|
+
scrollContainerRef,
|
|
70
|
+
scrollAreaRef,
|
|
71
|
+
thumbRef
|
|
72
|
+
} = _ref;
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (!enabled) return;
|
|
75
|
+
const scrollEl = scrollContainerRef.current;
|
|
76
|
+
const thumbEl = thumbRef.current;
|
|
77
|
+
if (!scrollEl || !thumbEl) return;
|
|
78
|
+
const update = () => {
|
|
79
|
+
const {
|
|
80
|
+
scrollTop,
|
|
81
|
+
scrollHeight,
|
|
82
|
+
clientHeight
|
|
83
|
+
} = scrollEl;
|
|
84
|
+
if (scrollHeight <= clientHeight) {
|
|
85
|
+
thumbEl.style.height = '0';
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const trackHeight = (scrollAreaRef.current?.clientHeight ?? clientHeight) - TABLE_HEADER_HEIGHT - SCROLLBAR_TRACK_OFFSET;
|
|
89
|
+
const thumbHeight = Math.max(SCROLLBAR_THUMB_MIN_HEIGHT, clientHeight / scrollHeight * trackHeight);
|
|
90
|
+
const thumbTop = scrollTop / (scrollHeight - clientHeight) * (trackHeight - thumbHeight);
|
|
91
|
+
thumbEl.style.height = `${thumbHeight}px`;
|
|
92
|
+
thumbEl.style.transform = `translateY(${thumbTop}px)`;
|
|
93
|
+
};
|
|
94
|
+
scrollEl.addEventListener('scroll', update, {
|
|
95
|
+
passive: true
|
|
96
|
+
});
|
|
97
|
+
const observer = new ResizeObserver(update);
|
|
98
|
+
observer.observe(scrollEl);
|
|
99
|
+
if (scrollAreaRef.current) observer.observe(scrollAreaRef.current);
|
|
100
|
+
update();
|
|
101
|
+
return () => {
|
|
102
|
+
scrollEl.removeEventListener('scroll', update);
|
|
103
|
+
observer.disconnect();
|
|
104
|
+
};
|
|
105
|
+
}, [enabled, scrollContainerRef, scrollAreaRef, thumbRef]);
|
|
106
|
+
const handleThumbMouseDown = e => {
|
|
107
|
+
const scrollEl = scrollContainerRef.current;
|
|
108
|
+
const thumbEl = thumbRef.current;
|
|
109
|
+
const areaEl = scrollAreaRef.current;
|
|
110
|
+
if (!scrollEl || !thumbEl) return;
|
|
111
|
+
startDrag(e, {
|
|
112
|
+
axis: 'y',
|
|
113
|
+
scrollEl,
|
|
114
|
+
thumbEl,
|
|
115
|
+
draggingTarget: areaEl ?? scrollEl
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
handleThumbMouseDown
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
export const useTableHorizontalScrollbar = _ref2 => {
|
|
123
|
+
let {
|
|
124
|
+
enabled,
|
|
125
|
+
hScrollContainerRef,
|
|
126
|
+
hScrollbarRef,
|
|
127
|
+
hThumbRef
|
|
128
|
+
} = _ref2;
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
if (!enabled) return;
|
|
131
|
+
const hScrollEl = hScrollContainerRef.current;
|
|
132
|
+
const hScrollbarEl = hScrollbarRef.current;
|
|
133
|
+
const hThumbEl = hThumbRef.current;
|
|
134
|
+
if (!hScrollEl || !hScrollbarEl || !hThumbEl) return;
|
|
135
|
+
const update = () => {
|
|
136
|
+
const {
|
|
137
|
+
scrollLeft,
|
|
138
|
+
scrollWidth,
|
|
139
|
+
clientWidth
|
|
140
|
+
} = hScrollEl;
|
|
141
|
+
if (scrollWidth <= clientWidth) {
|
|
142
|
+
hThumbEl.style.width = '0';
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// transform으로 스크롤 오프셋 보정 — reflow 없이 compositor-only 이동
|
|
146
|
+
hScrollbarEl.style.transform = `translateX(${scrollLeft}px)`;
|
|
147
|
+
hScrollbarEl.style.width = `${clientWidth - H_SCROLLBAR_SIDE_GAP * 2}px`;
|
|
148
|
+
const trackWidth = clientWidth - H_SCROLLBAR_SIDE_GAP * 2;
|
|
149
|
+
const thumbWidth = Math.max(H_SCROLLBAR_THUMB_MIN_WIDTH, clientWidth / scrollWidth * trackWidth);
|
|
150
|
+
const thumbLeft = scrollLeft / (scrollWidth - clientWidth) * (trackWidth - thumbWidth);
|
|
151
|
+
hThumbEl.style.width = `${thumbWidth}px`;
|
|
152
|
+
hThumbEl.style.transform = `translateX(${thumbLeft}px)`;
|
|
153
|
+
};
|
|
154
|
+
hScrollEl.addEventListener('scroll', update, {
|
|
155
|
+
passive: true
|
|
156
|
+
});
|
|
157
|
+
const ro = new ResizeObserver(update);
|
|
158
|
+
ro.observe(hScrollEl);
|
|
159
|
+
update();
|
|
160
|
+
return () => {
|
|
161
|
+
hScrollEl.removeEventListener('scroll', update);
|
|
162
|
+
ro.disconnect();
|
|
163
|
+
};
|
|
164
|
+
}, [enabled, hScrollContainerRef, hScrollbarRef, hThumbRef]);
|
|
165
|
+
const handleHThumbMouseDown = e => {
|
|
166
|
+
const hScrollEl = hScrollContainerRef.current;
|
|
167
|
+
const hThumbEl = hThumbRef.current;
|
|
168
|
+
if (!hScrollEl || !hThumbEl) return;
|
|
169
|
+
startDrag(e, {
|
|
170
|
+
axis: 'x',
|
|
171
|
+
scrollEl: hScrollEl,
|
|
172
|
+
thumbEl: hThumbEl,
|
|
173
|
+
sideGap: H_SCROLLBAR_SIDE_GAP
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
handleHThumbMouseDown
|
|
178
|
+
};
|
|
179
|
+
};
|
|
@@ -10,13 +10,6 @@ import { SelectDropdown } from '../../select-dropdown';
|
|
|
10
10
|
import { HintText } from '../../shared/hintText/HintText';
|
|
11
11
|
import { InputBase } from '../input-base/InputBase';
|
|
12
12
|
const defaultMaxHeight = 275;
|
|
13
|
-
const toggleMultiSelectValue = (currentValue, optionId) => {
|
|
14
|
-
const currentValues = Array.isArray(currentValue) ? currentValue : [];
|
|
15
|
-
if (currentValues.includes(optionId)) {
|
|
16
|
-
return currentValues.filter(v => v !== optionId);
|
|
17
|
-
}
|
|
18
|
-
return [...currentValues, optionId];
|
|
19
|
-
};
|
|
20
13
|
const notifyFormChange = (register, multiple, newValue) => {
|
|
21
14
|
if (register?.onChange) {
|
|
22
15
|
register.onChange({
|
|
@@ -48,6 +41,7 @@ const ComboBox = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
48
41
|
required = false,
|
|
49
42
|
multiple = false,
|
|
50
43
|
showFooterButtons = false,
|
|
44
|
+
maxSelection,
|
|
51
45
|
onEdit,
|
|
52
46
|
...props
|
|
53
47
|
} = _ref;
|
|
@@ -60,7 +54,8 @@ const ComboBox = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
60
54
|
const handleOptionSelect = option => {
|
|
61
55
|
if (disabled) return;
|
|
62
56
|
if (multiple) {
|
|
63
|
-
const newValue =
|
|
57
|
+
const newValue = tryToggle(option.id, Array.isArray(value) ? value : []);
|
|
58
|
+
if (newValue === null) return;
|
|
64
59
|
onChange?.(newValue);
|
|
65
60
|
notifyFormChange(register, multiple, newValue);
|
|
66
61
|
return;
|
|
@@ -137,6 +132,7 @@ const ComboBox = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
137
132
|
// 나머지는 useDropdown 훅에서 처리
|
|
138
133
|
dropdownHandleKeyDown(e);
|
|
139
134
|
};
|
|
135
|
+
// biome-ignore lint/style/noNonNullAssertion: forwardRef 패턴에서 internalRef는 첫 렌더 후 항상 존재
|
|
140
136
|
useImperativeHandle(ref, () => internalRef.current, []);
|
|
141
137
|
const trailingElement = {
|
|
142
138
|
type: 'custom',
|
|
@@ -166,8 +162,12 @@ const ComboBox = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
166
162
|
buttonText: selectAllButtonText,
|
|
167
163
|
toggleSelectAll,
|
|
168
164
|
getSelectedTagsData,
|
|
169
|
-
removeTag
|
|
170
|
-
|
|
165
|
+
removeTag,
|
|
166
|
+
isMaxSelectionActive,
|
|
167
|
+
tryToggle
|
|
168
|
+
} = useMultiSelect(currentSelectedValues, optionItems, {
|
|
169
|
+
maxSelection
|
|
170
|
+
});
|
|
171
171
|
const handleSelectAll = () => {
|
|
172
172
|
if (!multiple || !onChange) return;
|
|
173
173
|
const newSelectedValues = toggleSelectAll();
|
|
@@ -253,6 +253,7 @@ const ComboBox = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
253
253
|
multiple: multiple,
|
|
254
254
|
showFooterButtons: showFooter,
|
|
255
255
|
selectAllButtonText: selectAllButtonText,
|
|
256
|
+
showSelectAllAction: !isMaxSelectionActive,
|
|
256
257
|
onSelectAll: handleSelectAll,
|
|
257
258
|
onEdit: handleEdit,
|
|
258
259
|
onComplete: handleComplete,
|
|
@@ -132,9 +132,12 @@ export const ImageFileInput = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
132
132
|
onClick: handleBrowseClick,
|
|
133
133
|
disabled: disabled,
|
|
134
134
|
label: imagePreviewTooltipLabel
|
|
135
|
-
}),
|
|
135
|
+
}), _jsx(Tooltip, {
|
|
136
136
|
content: imagePreviewTooltipLabel,
|
|
137
|
-
position: "bottom"
|
|
137
|
+
position: "bottom",
|
|
138
|
+
tooltipType: "black",
|
|
139
|
+
forceVisible: isButtonHovered && !disabled,
|
|
140
|
+
disablePortal: true
|
|
138
141
|
})]
|
|
139
142
|
})]
|
|
140
143
|
});
|