@shoplflow/templates 0.0.55 → 0.1.1

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/index.cjs CHANGED
@@ -1,13 +1,19 @@
1
1
  'use strict';
2
2
 
3
3
  var base = require('@shoplflow/base');
4
- var styled = require('@emotion/styled');
4
+ var styled2 = require('@emotion/styled');
5
5
  var shoplAssets = require('@shoplflow/shopl-assets');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
+ var React6 = require('react');
8
+ var reactTable = require('@tanstack/react-table');
9
+ var lodashEs = require('lodash-es');
10
+ var reactVirtual = require('@tanstack/react-virtual');
11
+ var utils = require('@shoplflow/utils');
7
12
 
8
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
14
 
10
- var styled__default = /*#__PURE__*/_interopDefault(styled);
15
+ var styled2__default = /*#__PURE__*/_interopDefault(styled2);
16
+ var React6__default = /*#__PURE__*/_interopDefault(React6);
11
17
 
12
18
  var __defProp = Object.defineProperty;
13
19
  var __defProps = Object.defineProperties;
@@ -51,7 +57,7 @@ var getTypographyAndColor = (depth) => {
51
57
  return { typography: "body1_700", color: "neutral500" };
52
58
  }
53
59
  };
54
- var StyledRequired = styled__default.default.div`
60
+ var StyledRequired = styled2__default.default.div`
55
61
  color: ${base.colorTokens.red300};
56
62
  font-weight: 700;
57
63
  font-size: 14px;
@@ -104,3 +110,1481 @@ TitleGroup.Header = Header;
104
110
  TitleGroup.Actions = Actions;
105
111
  TitleGroup.Description = Description;
106
112
  exports.TitleGroup = TitleGroup;
113
+ var TableContext = React6.createContext(void 0);
114
+ var useTable = () => {
115
+ const context = React6.useContext(TableContext);
116
+ if (!context) {
117
+ throw new Error("useTable must be used within a TableProvider");
118
+ }
119
+ return context;
120
+ };
121
+ var TableProvider = TableContext.Provider;
122
+ var TableContainer = styled2__default.default.div`
123
+ border: ${({ hasToolbar }) => !hasToolbar && `1px solid ${base.colorTokens.neutral200}`};
124
+ border-radius: 8px;
125
+ background-color: ${base.colorTokens.neutral0};
126
+ width: 100%;
127
+ max-width: 100%;
128
+
129
+ .resizer {
130
+ position: absolute;
131
+ top: 0;
132
+ height: 100%;
133
+ right: 0;
134
+ width: 2px;
135
+ background: ${base.colorTokens.neutral700};
136
+ cursor: col-resize;
137
+ user-select: none;
138
+ touch-action: none;
139
+ }
140
+
141
+ .resizer.isResizing {
142
+ background: ${base.colorTokens.neutral700};
143
+ opacity: 1;
144
+ }
145
+
146
+ @media (hover: hover) {
147
+ .resizer {
148
+ opacity: 0;
149
+ }
150
+
151
+ *:hover > .resizer {
152
+ opacity: 1;
153
+ }
154
+ }
155
+ `;
156
+ var TableHeader = styled2__default.default.thead`
157
+ color: ${base.colorTokens.neutral400};
158
+ background-color: ${base.colorTokens.neutral100};
159
+ font-size: 13px;
160
+ font-weight: 400;
161
+ line-height: 16px;
162
+
163
+ tr {
164
+ border-radius: 8px 8px 0 0;
165
+ }
166
+
167
+ th {
168
+ position: relative;
169
+ padding: 8px;
170
+ height: 48px;
171
+ min-height: 48px;
172
+ background-color: ${base.colorTokens.neutral100};
173
+ vertical-align: middle;
174
+ // 일반 컬럼의 border를 가상 요소로 처리
175
+ &::after {
176
+ content: '';
177
+ position: absolute;
178
+ top: 0;
179
+ right: 0;
180
+ height: 100%;
181
+ width: 1px;
182
+ background-color: ${base.colorTokens.neutral200};
183
+ pointer-events: none;
184
+ }
185
+
186
+ // Fixed border for multi-column headers (colspan)
187
+ &[colspan] {
188
+ position: relative;
189
+
190
+ // Ensure the right border is visible for colspan cells
191
+ &::after {
192
+ content: '';
193
+ position: absolute;
194
+ top: 0;
195
+ right: 0;
196
+ height: 100%;
197
+ width: 1px;
198
+ background-color: ${base.colorTokens.neutral200};
199
+ pointer-events: none;
200
+ display: block;
201
+ }
202
+
203
+ // Add bottom border for spanning headers to make them visually distinct
204
+ &::before {
205
+ content: '';
206
+ position: absolute;
207
+ bottom: 0;
208
+ left: 0;
209
+ width: 100%;
210
+ height: 1px;
211
+ background-color: ${base.colorTokens.neutral200};
212
+ pointer-events: none;
213
+ }
214
+ }
215
+
216
+ // fixed 컬럼의 border를 별도의 가상 요소로 처리
217
+ &[data-pinned='left']::before,
218
+ &[data-pinned='right']::before {
219
+ content: '';
220
+ position: absolute;
221
+ top: 0;
222
+ height: 100%;
223
+ width: 1px;
224
+ background-color: ${base.colorTokens.neutral200};
225
+ pointer-events: none;
226
+ z-index: 5;
227
+ }
228
+
229
+ &[data-pinned='left']::before {
230
+ right: 0;
231
+ }
232
+
233
+ &[data-pinned='right']::before {
234
+ left: 0;
235
+ }
236
+ &:last-child {
237
+ border-right: none;
238
+ }
239
+
240
+ &[data-last-left-pinned='true'] {
241
+ &::after {
242
+ content: '';
243
+ position: absolute;
244
+ top: 0;
245
+ right: -4px; // border 바깥으로 이동
246
+ height: 100%;
247
+ width: 4px;
248
+ pointer-events: none;
249
+ z-index: 11;
250
+ background: linear-gradient(to right, rgba(0, 0, 0, 0.1), transparent);
251
+ }
252
+ }
253
+
254
+ &[data-first-right-pinned='true'] {
255
+ &::before {
256
+ content: '';
257
+ position: absolute;
258
+ top: 0;
259
+ left: -5px; // border 바깥으로 이동
260
+ height: 100%;
261
+ width: 4px;
262
+ pointer-events: none;
263
+ z-index: 11;
264
+ background: linear-gradient(to left, rgba(0, 0, 0, 0.1), transparent);
265
+ }
266
+ }
267
+ }
268
+
269
+ th:last-of-type::after {
270
+ display: none;
271
+ }
272
+ `;
273
+ var TableRow = styled2__default.default.tr`
274
+ &.clickable:hover td {
275
+ background-color: ${base.colorTokens.neutral400_5};
276
+ cursor: pointer;
277
+ }
278
+
279
+ &:hover td[data-no-hover='true'] {
280
+ background-color: ${base.colorTokens.neutral400_5};
281
+ }
282
+ `;
283
+ var TableHead = styled2__default.default.th`
284
+ .table-head[data-filter-open='true'] {
285
+ background-color: black;
286
+ }
287
+ & span {
288
+ color: ${base.colorTokens.neutral400};
289
+ }
290
+ `;
291
+ var TableRootContainer = styled2__default.default.div`
292
+ -ms-overflow-style: none; /* IE and Edge */
293
+ scrollbar-width: none; /* Firefox */
294
+ border: ${({ hasFilterBar, hasToolbar }) => hasFilterBar && !hasToolbar && `1px solid ${base.colorTokens.neutral200}`};
295
+ border-radius: ${({ hasFilterBar, hasToolbar }) => hasFilterBar && !hasToolbar ? "8px 8px 0 0" : "8px"};
296
+
297
+ &::-webkit-scrollbar {
298
+ display: none; /* Chrome, Safari, Opera*/
299
+ }
300
+ `;
301
+ var HeaderTableContainer = styled2__default.default.div`
302
+ width: 100%;
303
+ z-index: 15;
304
+ position: ${({ isSticky }) => isSticky ? "sticky" : ""};
305
+ top: ${({ stickyHeaderMarginTop }) => stickyHeaderMarginTop}px;
306
+ overflow-x: hidden;
307
+ border-radius: ${({ hasHeader }) => !hasHeader ? "8px 8px 0 0" : "0"};
308
+
309
+ -ms-overflow-style: none; /* IE and Edge */
310
+ scrollbar-width: none; /* Firefox */
311
+
312
+ &::-webkit-scrollbar {
313
+ display: none; /* Chrome, Safari, Opera*/
314
+ }
315
+ `;
316
+ var BodyTableContainer = styled2__default.default.div`
317
+ width: 100%;
318
+ overflow-x: scroll;
319
+ -ms-overflow-style: none; /* IE and Edge */
320
+ scrollbar-width: none; /* Firefox */
321
+ border-radius: ${({ hasPagination }) => hasPagination ? "0 0 8px 8px" : "0"};
322
+
323
+ opacity: ${({ isFetching }) => isFetching && 0.7};
324
+ pointer-events: ${({ isFetching }) => isFetching && "none"};
325
+ &::-webkit-scrollbar {
326
+ display: none; /* Chrome, Safari, Opera*/
327
+ }
328
+ `;
329
+ var TableCell = styled2__default.default.td`
330
+ position: relative;
331
+ padding: 8px;
332
+ vertical-align: middle;
333
+ background-color: ${base.colorTokens.neutral0};
334
+
335
+ &:has(li) {
336
+ padding: 0;
337
+ }
338
+
339
+ &[data-last-left-pinned='true'] {
340
+ &::after {
341
+ content: '';
342
+ position: absolute;
343
+ top: 0;
344
+ right: -4px; // border 바깥으로 이동
345
+ height: 100%;
346
+ width: 4px;
347
+ pointer-events: none;
348
+ z-index: 11;
349
+ background: linear-gradient(to right, rgba(0, 0, 0, 0.1), transparent);
350
+ }
351
+ }
352
+
353
+ &[data-first-right-pinned='true'] {
354
+ &::before {
355
+ content: '';
356
+ position: absolute;
357
+ top: 0;
358
+ left: -4px; // border 바깥으로 이동
359
+ height: 100%;
360
+ width: 4px;
361
+ pointer-events: none;
362
+ z-index: 11;
363
+ background: linear-gradient(to left, rgba(0, 0, 0, 0.1), transparent);
364
+ }
365
+ }
366
+ `;
367
+ var TableBody = styled2__default.default.tbody`
368
+ color: ${base.colorTokens.neutral700};
369
+ font-size: 14px;
370
+ position: relative;
371
+
372
+ tr {
373
+ height: 60px;
374
+ cursor: ${({ isClickable }) => isClickable ? "pointer" : "default"};
375
+
376
+ &:not(:last-of-type) {
377
+ border-bottom: ${({ innerBorder }) => innerBorder != null ? innerBorder : "1px solid #eaeaea"};
378
+ }
379
+
380
+ &:hover {
381
+ background-color: ${base.colorTokens.neutral100};
382
+ }
383
+
384
+ // 데이터가 minRows 이하여서 빈칸을 채워준 경우 호버 액션, 커서 액션 모두 OFF
385
+ &[data-empty='true'] {
386
+ border: none; /* 테두리 제거 */
387
+ background-color: transparent; /* 배경색도 투명 처리 (선택 사항) */
388
+ cursor: default;
389
+
390
+ &:hover {
391
+ background-color: unset;
392
+ }
393
+
394
+ td {
395
+ cursor: default;
396
+ }
397
+ }
398
+ }
399
+
400
+ td {
401
+ padding: 8px;
402
+ vertical-align: middle;
403
+ background-color: ${base.colorTokens.neutral0};
404
+ &:not(:first-of-type) {
405
+ border-left: ${({ innerBorder }) => innerBorder != null ? innerBorder : "none"};
406
+ }
407
+ }
408
+ `;
409
+ var PaginationWrapper = styled2__default.default.div`
410
+ position: relative;
411
+ display: flex;
412
+ justify-content: space-between;
413
+ align-items: center;
414
+ width: 100%;
415
+ height: 56px;
416
+ border-top: ${`1px solid ${base.colorTokens.neutral200}`};
417
+
418
+ .table-pagination {
419
+ border-top: none;
420
+ }
421
+ `;
422
+ var BottomContainer = styled2__default.default.div`
423
+ position: sticky;
424
+ width: 100%;
425
+ bottom: 0;
426
+ background-color: ${base.colorTokens.neutral0};
427
+ z-index: 11;
428
+ border-radius: ${({ isEndOfPage }) => isEndOfPage && "0 0 12px 12px"};
429
+ border: ${({ hasFilterBar, hasToolbar }) => hasFilterBar && !hasToolbar && `1px solid ${base.colorTokens.neutral200}`};
430
+ border-top: none;
431
+ `;
432
+ var ScrollContainer = styled2__default.default.div`
433
+ height: 6px;
434
+ position: absolute;
435
+ bottom: 50px;
436
+ width: 100%;
437
+ z-index: 12;
438
+ overflow-x: scroll;
439
+
440
+ ::-webkit-scrollbar {
441
+ width: inherit;
442
+ height: 6px;
443
+ }
444
+
445
+ ::-webkit-scrollbar-thumb {
446
+ background: ${base.colorTokens.neutral400};
447
+ border-radius: 100px;
448
+ }
449
+ `;
450
+ var TableResizer = styled2__default.default.div``;
451
+ var EmptySource = styled2__default.default.div`
452
+ width: 60px;
453
+ `;
454
+ var PaginationLeftSlot = styled2__default.default.div`
455
+ position: absolute;
456
+ left: 16px;
457
+ top: 50%;
458
+ transform: translateY(-50%);
459
+ `;
460
+ var SmallIconButton = styled2__default.default(base.IconButton)`
461
+ svg {
462
+ width: 12px !important;
463
+ height: 12px !important;
464
+ }
465
+ `;
466
+ var TableToolbar = ({ children, filterAccessor }) => {
467
+ const { table, filterValue, setFilterValue } = useTable();
468
+ const totalCount = table.getPrePaginationRowModel().rows.length;
469
+ const onSearch = (value) => {
470
+ var _a;
471
+ if (!filterAccessor) {
472
+ return null;
473
+ }
474
+ setFilterValue(value);
475
+ (_a = table.getColumn(filterAccessor)) == null ? void 0 : _a.setFilterValue(value);
476
+ };
477
+ return /* @__PURE__ */ jsxRuntime.jsx(base.StackContainer.Horizontal, { width: "100%", height: "64px", align: "center", padding: "12px 24px", justify: "space-between", children: children({
478
+ totalCount,
479
+ filterAccessor: filterAccessor != null ? filterAccessor : "",
480
+ onSearch,
481
+ filterValue
482
+ }) });
483
+ };
484
+
485
+ // src/components/Table/utils/index.ts
486
+ var getCommonPinningStyles = (column) => {
487
+ const isPinned = column.getIsPinned();
488
+ return {
489
+ left: isPinned === "left" ? `${column.getStart("left")}px` : void 0,
490
+ right: isPinned === "right" ? `${column.getAfter("right")}px` : void 0,
491
+ position: isPinned ? "sticky" : "relative",
492
+ width: column.getSize(),
493
+ zIndex: isPinned ? 10 : 0
494
+ };
495
+ };
496
+ var PAGE_SIZE = [
497
+ { key: "5", label: "5" },
498
+ { key: "10", label: "10" },
499
+ { key: "20", label: "20" },
500
+ { key: "50", label: "50" },
501
+ { key: "100", label: "100" }
502
+ ];
503
+ var useIntersectionObserver = (target, callback, options) => {
504
+ React6.useEffect(() => {
505
+ if (!target.current) {
506
+ return;
507
+ }
508
+ const observer = new IntersectionObserver(callback, options);
509
+ observer.observe(target.current);
510
+ return () => observer.disconnect();
511
+ }, [callback]);
512
+ };
513
+ var TablePagination = ({
514
+ total,
515
+ defaultPageSize,
516
+ children,
517
+ pageSizeList = PAGE_SIZE,
518
+ setCurrentPage,
519
+ notSizeOption = false,
520
+ currentPage
521
+ }) => {
522
+ const { table, headerRef, bodyRef, tableScrollRef, footerRef, hasFilterBar, hasToolbar } = useTable();
523
+ const { pageSize, pageIndex } = table.getState().pagination;
524
+ const [isEndOfPage, setIsEndOfPage] = React6.useState(false);
525
+ const handleScroll = React6.useCallback(() => {
526
+ if (!headerRef.current || !bodyRef.current || !tableScrollRef.current) {
527
+ return;
528
+ }
529
+ const scrollLeft = tableScrollRef.current.scrollLeft;
530
+ headerRef.current.scrollLeft = scrollLeft;
531
+ bodyRef.current.scrollLeft = scrollLeft;
532
+ }, []);
533
+ const onIntersect = React6.useCallback(
534
+ (entries) => {
535
+ const entry = entries[0];
536
+ entry.isIntersecting ? setIsEndOfPage(true) : setIsEndOfPage(false);
537
+ },
538
+ // eslint-disable-next-line react-hooks/exhaustive-deps
539
+ [isEndOfPage]
540
+ );
541
+ useIntersectionObserver(footerRef, onIntersect, {
542
+ threshold: 1,
543
+ rootMargin: "0px 0px -1px"
544
+ });
545
+ const handlePageChange = React6.useCallback(
546
+ (updater) => {
547
+ const newPage = typeof updater === "function" ? updater(pageIndex) : updater;
548
+ table.setPageIndex(newPage);
549
+ setCurrentPage == null ? void 0 : setCurrentPage({ pageIndex: newPage, pageSize });
550
+ },
551
+ [pageIndex, pageSize, table, setCurrentPage]
552
+ );
553
+ const handlePageSizeChange = React6.useCallback(
554
+ (value) => {
555
+ const newSize = Number(value);
556
+ table.setPageSize(newSize);
557
+ table.setPageIndex(0);
558
+ setCurrentPage == null ? void 0 : setCurrentPage({ pageIndex: 0, pageSize: newSize });
559
+ },
560
+ [table, setCurrentPage]
561
+ );
562
+ const TableColumns = () => /* @__PURE__ */ jsxRuntime.jsx("colgroup", { children: table.getAllColumns().map((column) => {
563
+ const size = column.columnDef.size;
564
+ const minSize = column.columnDef.minSize;
565
+ const maxSize = column.columnDef.maxSize;
566
+ const style = size === 0 ? { width: "100%" } : {
567
+ width: `${size}px`,
568
+ minWidth: `${minSize}px`,
569
+ maxWidth: `${maxSize}px`
570
+ };
571
+ return /* @__PURE__ */ jsxRuntime.jsx("col", { style }, column.id);
572
+ }) });
573
+ React6.useEffect(() => {
574
+ table.setPageSize(defaultPageSize);
575
+ }, [defaultPageSize, table]);
576
+ React6.useEffect(() => {
577
+ table.setPageIndex(currentPage != null ? currentPage : 0);
578
+ }, [table, currentPage]);
579
+ return /* @__PURE__ */ jsxRuntime.jsxs(BottomContainer, { ref: footerRef, isEndOfPage, hasFilterBar, hasToolbar, children: [
580
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollContainer, { ref: tableScrollRef, onScroll: handleScroll, children: /* @__PURE__ */ jsxRuntime.jsx("table", { style: { width: table.getTotalSize() || "100%", height: "6px", tableLayout: "fixed" }, children: /* @__PURE__ */ jsxRuntime.jsx(TableColumns, {}) }) }),
581
+ /* @__PURE__ */ jsxRuntime.jsxs(PaginationWrapper, { children: [
582
+ /* @__PURE__ */ jsxRuntime.jsx(PaginationLeftSlot, { children }),
583
+ /* @__PURE__ */ jsxRuntime.jsx(
584
+ base.Pagination,
585
+ {
586
+ pageSize: `${pageSize}`,
587
+ currentPage: pageIndex,
588
+ itemsTotalCount: total,
589
+ totalCount: Math.ceil(total / Number(pageSize)),
590
+ previousPage: () => handlePageChange(pageIndex - 1),
591
+ nextPage: () => handlePageChange(pageIndex + 1),
592
+ style: { paddingInline: "16px" },
593
+ gotoPage: handlePageChange,
594
+ rightSource: notSizeOption ? /* @__PURE__ */ jsxRuntime.jsx(EmptySource, {}) : /* @__PURE__ */ jsxRuntime.jsx(
595
+ base.Pagination.SizeSelector,
596
+ {
597
+ data: pageSizeList.map((item) => ({ label: item.label, value: item.key })),
598
+ pageSize: `${pageSize}`,
599
+ setPageSize: handlePageSizeChange
600
+ }
601
+ )
602
+ },
603
+ Math.ceil(total / Number(pageSize))
604
+ )
605
+ ] })
606
+ ] });
607
+ };
608
+ var TableFilterBar = React6.memo(({ outsideFilters }) => {
609
+ const { table, setFilterValue, hasToolbar } = useTable();
610
+ const filters = table.getState().columnFilters;
611
+ const prevFiltersRef = React6.useRef();
612
+ const onSearch = (value) => {
613
+ setFilterValue(value);
614
+ table.resetColumnFilters();
615
+ };
616
+ const resetFilters = () => {
617
+ table.setColumnFilters([]);
618
+ const resetColumnFilters = (columns) => {
619
+ columns.forEach((column) => {
620
+ var _a, _b;
621
+ if ((_b = (_a = column.columnDef) == null ? void 0 : _a.meta) == null ? void 0 : _b.onFilterChange) {
622
+ column.columnDef.meta.onFilterChange("");
623
+ }
624
+ if (column.columns && column.columns.length > 0) {
625
+ resetColumnFilters(column.columns);
626
+ }
627
+ });
628
+ };
629
+ resetColumnFilters(table.getAllColumns());
630
+ };
631
+ const handleRemoveFilter = (columnId, filterValue) => {
632
+ var _a, _b, _c, _d;
633
+ const newFilters = table.getState().columnFilters.filter((filter) => !(filter.id === columnId && filter.value === filterValue));
634
+ table.setColumnFilters(newFilters);
635
+ (_d = (_c = (_b = (_a = table.getColumn(columnId)) == null ? void 0 : _a.columnDef) == null ? void 0 : _b.meta) == null ? void 0 : _c.onFilterChange) == null ? void 0 : _d.call(_c, "");
636
+ };
637
+ const getFilterLabel = (columnId, value) => {
638
+ var _a;
639
+ const column = table.getColumn(columnId);
640
+ if (!column || !((_a = column.columnDef.meta) == null ? void 0 : _a.filterOptions)) {
641
+ return value;
642
+ }
643
+ const filterOption = column.columnDef.meta.filterOptions.find((option) => option.value === value);
644
+ return filterOption ? filterOption.label : value;
645
+ };
646
+ React6.useEffect(() => {
647
+ const validFilters = outsideFilters == null ? void 0 : outsideFilters.filter((item) => item.value !== void 0 && item.value !== "").map((item) => ({ id: item.id, value: item.value }));
648
+ if (!lodashEs.isEqual(prevFiltersRef.current, validFilters)) {
649
+ prevFiltersRef.current = validFilters;
650
+ if (validFilters && validFilters.length > 0) {
651
+ table.setColumnFilters(validFilters);
652
+ } else {
653
+ table.setColumnFilters([]);
654
+ }
655
+ }
656
+ }, [outsideFilters, table]);
657
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: filters.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
658
+ base.StackContainer.Horizontal,
659
+ {
660
+ width: "100%",
661
+ align: "center",
662
+ padding: hasToolbar ? "0px 16px 8px" : "0px 0px 8px 0px",
663
+ spacing: "spacing08",
664
+ children: [
665
+ /* @__PURE__ */ jsxRuntime.jsx(
666
+ base.IconButton,
667
+ {
668
+ sizeVar: "XS",
669
+ styleVar: "GHOST",
670
+ onClick: () => {
671
+ resetFilters();
672
+ if (filters) {
673
+ onSearch("");
674
+ }
675
+ },
676
+ children: /* @__PURE__ */ jsxRuntime.jsx(base.Icon, { iconSource: shoplAssets.RefreshIcon, color: "neutral700" })
677
+ }
678
+ ),
679
+ filters.map((filter) => {
680
+ const filterValueString = filter.value;
681
+ const filterLabel = getFilterLabel(filter.id, filterValueString);
682
+ return /* @__PURE__ */ jsxRuntime.jsx(
683
+ base.Tag,
684
+ {
685
+ sizeVar: "XS",
686
+ styleVar: "TINT",
687
+ color: "neutral600",
688
+ background: "neutral150",
689
+ radius: true,
690
+ rightSource: /* @__PURE__ */ jsxRuntime.jsx(
691
+ base.Icon,
692
+ {
693
+ iconSource: shoplAssets.CloseSmallIcon,
694
+ sizeVar: "XS",
695
+ color: "neutral350",
696
+ onClick: () => handleRemoveFilter(filter.id, filterValueString),
697
+ style: { cursor: "pointer" }
698
+ }
699
+ ),
700
+ children: /* @__PURE__ */ jsxRuntime.jsx(base.Text, { typography: "caption_400", color: "neutral600", children: filterLabel })
701
+ },
702
+ `${filter.id}-${filterValueString}`
703
+ );
704
+ })
705
+ ]
706
+ }
707
+ ) });
708
+ });
709
+ var Table = ({
710
+ data,
711
+ columns,
712
+ columnResizing = false,
713
+ children,
714
+ manualPagination = false,
715
+ manualFiltering = false,
716
+ manualSorting = true,
717
+ selectedRows = [],
718
+ onSelectedRowsChange,
719
+ onClickRow
720
+ }) => {
721
+ const [sorting, setSorting] = React6.useState([]);
722
+ const [columnFilters, setColumnFilters] = React6.useState([]);
723
+ const [globalFilter, setGlobalFilter] = React6.useState([]);
724
+ const [columnVisibility, setColumnVisibility] = React6.useState({});
725
+ const [columnPinning, setColumnPinning] = React6.useState({});
726
+ const [rowSelection, setRowSelection] = React6.useState({});
727
+ const [filterValue, setFilterValue] = React6.useState("");
728
+ const visibleColumns = React6.useMemo(() => columns.filter((column) => {
729
+ var _a;
730
+ return !((_a = column.meta) == null ? void 0 : _a.hiddenColumn);
731
+ }), [columns]);
732
+ const table = reactTable.useReactTable({
733
+ data,
734
+ columns: visibleColumns,
735
+ columnResizeMode: "onChange",
736
+ initialState: {
737
+ pagination: {
738
+ pageSize: 100
739
+ }
740
+ },
741
+ state: {
742
+ sorting,
743
+ columnFilters,
744
+ globalFilter,
745
+ columnVisibility,
746
+ columnPinning,
747
+ rowSelection
748
+ },
749
+ defaultColumn: {
750
+ size: 0,
751
+ // TODO: 필터링 기능 추가 시 props로 옵션 처리
752
+ enableColumnFilter: false,
753
+ enableSorting: false,
754
+ enableResizing: true
755
+ },
756
+ onSortingChange: (updater) => {
757
+ var _a, _b;
758
+ const newSorting = typeof updater === "function" ? updater(table.getState().sorting) : updater;
759
+ setSorting(newSorting);
760
+ if (newSorting.length > 0) {
761
+ const { id, desc } = newSorting[0];
762
+ const column = table.getAllLeafColumns().find((col) => col.id === id);
763
+ (_b = (_a = column == null ? void 0 : column.columnDef.meta) == null ? void 0 : _a.onSortChange) == null ? void 0 : _b.call(_a, desc ? "desc" : "asc");
764
+ } else {
765
+ table.getAllLeafColumns().forEach((column) => {
766
+ var _a2, _b2;
767
+ (_b2 = (_a2 = column.columnDef.meta) == null ? void 0 : _a2.onSortChange) == null ? void 0 : _b2.call(_a2, void 0);
768
+ });
769
+ }
770
+ },
771
+ onColumnFiltersChange: (updater) => {
772
+ const newFilters = typeof updater === "function" ? updater(table.getState().columnFilters) : updater;
773
+ setColumnFilters(newFilters);
774
+ newFilters.forEach((filter) => {
775
+ var _a, _b;
776
+ const column = table.getColumn(filter.id);
777
+ if ((_b = (_a = column == null ? void 0 : column.columnDef) == null ? void 0 : _a.meta) == null ? void 0 : _b.onFilterChange) {
778
+ column.columnDef.meta.onFilterChange(filter.value || "");
779
+ }
780
+ });
781
+ },
782
+ onGlobalFilterChange: (updater) => {
783
+ var _a;
784
+ const newGlobalFilter = typeof updater === "function" ? updater(globalFilter) : updater;
785
+ setGlobalFilter(newGlobalFilter);
786
+ if ((_a = table.options.meta) == null ? void 0 : _a.onGlobalFilterChange) {
787
+ table.options.meta.onGlobalFilterChange(newGlobalFilter || "");
788
+ }
789
+ if (newGlobalFilter) {
790
+ table.getAllLeafColumns().forEach((column) => {
791
+ var _a2;
792
+ if (column.getCanFilter() && ((_a2 = column.columnDef.meta) == null ? void 0 : _a2.onFilterChange)) {
793
+ column.columnDef.meta.onFilterChange(newGlobalFilter);
794
+ }
795
+ });
796
+ }
797
+ },
798
+ onColumnVisibilityChange: setColumnVisibility,
799
+ onColumnPinningChange: setColumnPinning,
800
+ onRowSelectionChange: (updater) => {
801
+ const newSelection = typeof updater === "function" ? updater(rowSelection) : updater;
802
+ setRowSelection(newSelection);
803
+ const newSelectedRows = table.getRowModel().rows.filter((row) => newSelection[row.id]).map((row) => row.original);
804
+ onSelectedRowsChange == null ? void 0 : onSelectedRowsChange(newSelectedRows);
805
+ },
806
+ getCoreRowModel: reactTable.getCoreRowModel(),
807
+ getFilteredRowModel: reactTable.getFilteredRowModel(),
808
+ getPaginationRowModel: reactTable.getPaginationRowModel(),
809
+ getSortedRowModel: reactTable.getSortedRowModel(),
810
+ enableColumnResizing: columnResizing,
811
+ manualPagination,
812
+ manualFiltering,
813
+ manualSorting
814
+ });
815
+ const headerRef = React6.useRef(null);
816
+ const bodyRef = React6.useRef(null);
817
+ const footerRef = React6.useRef(null);
818
+ const tableScrollRef = React6.useRef(null);
819
+ const hasToolbar = React6.Children.toArray(children).some((child) => React6.isValidElement(child) && child.type === TableToolbar);
820
+ const hasPagination = React6.Children.toArray(children).some(
821
+ (child) => React6.isValidElement(child) && child.type === TablePagination
822
+ );
823
+ const hasFilterBar = React6.Children.toArray(children).some(
824
+ (child) => React6.isValidElement(child) && child.type === TableFilterBar
825
+ );
826
+ const contextValue = {
827
+ table,
828
+ headerRef,
829
+ bodyRef,
830
+ footerRef,
831
+ tableScrollRef,
832
+ selectedRows,
833
+ onClickRow,
834
+ hasToolbar,
835
+ hasFilterBar,
836
+ hasPagination,
837
+ columnResizing,
838
+ filterValue,
839
+ setFilterValue
840
+ };
841
+ React6.useEffect(() => {
842
+ if (selectedRows.length === 0) {
843
+ table.resetRowSelection();
844
+ }
845
+ }, [onSelectedRowsChange, selectedRows.length, table]);
846
+ return /* @__PURE__ */ jsxRuntime.jsx(TableContainer, { hasToolbar: hasToolbar || hasFilterBar, children: /* @__PURE__ */ jsxRuntime.jsx(TableProvider, { value: contextValue, children }) });
847
+ };
848
+ var TableEmpty = ({ children }) => {
849
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
850
+ };
851
+ var FilterMenu = ({ header, onFilterChange, triggerWidth }) => {
852
+ var _a;
853
+ const columnFilterValue = header.column.getFilterValue();
854
+ const { filterOptions } = (_a = header.column.columnDef.meta) != null ? _a : {};
855
+ const [maxLabelWidth, setMaxLabelWidth] = React6.useState(0);
856
+ const labelRefs = React6.useRef([]);
857
+ React6.useEffect(() => {
858
+ const widths = labelRefs.current.map((ref) => (ref == null ? void 0 : ref.offsetWidth) || 0);
859
+ setMaxLabelWidth(Math.max(...widths, 0));
860
+ }, [filterOptions]);
861
+ const handleFilterChange = (value) => {
862
+ header.column.setFilterValue(value);
863
+ if (onFilterChange) {
864
+ onFilterChange(value);
865
+ }
866
+ };
867
+ if (!header.column.getCanFilter()) {
868
+ return null;
869
+ }
870
+ return /* @__PURE__ */ jsxRuntime.jsx(
871
+ base.StackContainer.Vertical,
872
+ {
873
+ padding: "4px",
874
+ radius: "borderRadius04",
875
+ background: "neutral0",
876
+ width: maxLabelWidth > triggerWidth ? "100%" : `${triggerWidth}px`,
877
+ style: { boxShadow: "0px 8px 16px 0px rgba(0, 0, 0, 0.12)" },
878
+ children: /* @__PURE__ */ jsxRuntime.jsx(base.ScrollArea, { autoHeight: true, autoHeightMax: 240, children: filterOptions == null ? void 0 : filterOptions.map((option, idx) => /* @__PURE__ */ jsxRuntime.jsx(
879
+ base.Menu,
880
+ {
881
+ isSelected: columnFilterValue === option.value,
882
+ onClick: () => handleFilterChange(option.value),
883
+ leftSource: option.icon,
884
+ children: /* @__PURE__ */ jsxRuntime.jsx(
885
+ base.Text,
886
+ {
887
+ typography: "body1_400",
888
+ whiteSpace: "nowrap",
889
+ ref: (el) => labelRefs.current[idx] = el,
890
+ children: option.label
891
+ }
892
+ )
893
+ },
894
+ option.value
895
+ )) })
896
+ }
897
+ );
898
+ };
899
+ var SortMenu = ({ onSortChange, header, triggerWidth }) => {
900
+ var _a, _b;
901
+ const sortLabels = (_b = (_a = header.column.columnDef.meta) == null ? void 0 : _a.sortLabels) != null ? _b : ["\uC624\uB984\uCC28\uC21C", "\uB0B4\uB9BC\uCC28\uC21C", "\uC815\uB82C \uD574\uC81C"];
902
+ const currentSort = header.column.getIsSorted();
903
+ const handleSortChange = (value) => {
904
+ if (value === void 0) {
905
+ header.column.clearSorting();
906
+ } else {
907
+ header.column.toggleSorting(value === "asc", false);
908
+ }
909
+ if (onSortChange) {
910
+ onSortChange(value);
911
+ }
912
+ };
913
+ if (!header.column.getCanSort()) {
914
+ return null;
915
+ }
916
+ return /* @__PURE__ */ jsxRuntime.jsxs(
917
+ base.StackContainer.Vertical,
918
+ {
919
+ padding: "4px",
920
+ radius: "borderRadius04",
921
+ background: "neutral0",
922
+ width: `${triggerWidth}px`,
923
+ style: { boxShadow: "0px 8px 16px 0px rgba(0, 0, 0, 0.12)" },
924
+ children: [
925
+ /* @__PURE__ */ jsxRuntime.jsx(
926
+ base.Menu,
927
+ {
928
+ leftSource: /* @__PURE__ */ jsxRuntime.jsx(base.Icon, { iconSource: shoplAssets.DescIcon, sizeVar: "S" }),
929
+ isSelected: currentSort === "desc",
930
+ onClick: () => handleSortChange("asc"),
931
+ children: sortLabels[0]
932
+ }
933
+ ),
934
+ /* @__PURE__ */ jsxRuntime.jsx(
935
+ base.Menu,
936
+ {
937
+ leftSource: /* @__PURE__ */ jsxRuntime.jsx(base.Icon, { iconSource: shoplAssets.AscIcon, sizeVar: "S" }),
938
+ isSelected: currentSort === "asc",
939
+ onClick: () => handleSortChange("desc"),
940
+ children: sortLabels[1]
941
+ }
942
+ ),
943
+ /* @__PURE__ */ jsxRuntime.jsx(
944
+ base.Menu,
945
+ {
946
+ leftSource: /* @__PURE__ */ jsxRuntime.jsx(base.Icon, { iconSource: shoplAssets.MoreIcon, sizeVar: "S" }),
947
+ isSelected: !currentSort,
948
+ onClick: () => handleSortChange(void 0),
949
+ children: sortLabels[2]
950
+ }
951
+ )
952
+ ]
953
+ }
954
+ );
955
+ };
956
+ var TableHeadTrigger = ({
957
+ header,
958
+ uniqueClass,
959
+ tableHeadRef,
960
+ isOpen,
961
+ onTriggerClick
962
+ }) => {
963
+ var _a, _b;
964
+ const showFilterMenu = header.column.getCanFilter();
965
+ const showSortMenu = header.column.getCanSort();
966
+ const currentSort = header.column.getIsSorted();
967
+ let triggerIcon;
968
+ if (currentSort === "asc") {
969
+ triggerIcon = shoplAssets.AscIcon;
970
+ } else if (currentSort === "desc") {
971
+ triggerIcon = shoplAssets.DescIcon;
972
+ } else {
973
+ triggerIcon = shoplAssets.MoreIcon;
974
+ }
975
+ return /* @__PURE__ */ jsxRuntime.jsxs(
976
+ base.StackContainer.Horizontal,
977
+ {
978
+ width: "100%",
979
+ align: "center",
980
+ style: (_b = (_a = header.column.columnDef.meta) == null ? void 0 : _a.headerProps) == null ? void 0 : _b.style,
981
+ className: uniqueClass,
982
+ ref: tableHeadRef,
983
+ children: [
984
+ reactTable.flexRender(header.column.columnDef.header, header.getContext()),
985
+ showSortMenu && /* @__PURE__ */ jsxRuntime.jsx(
986
+ base.IconButton,
987
+ {
988
+ sizeVar: "XS",
989
+ styleVar: "GHOST",
990
+ onClick: (e) => {
991
+ e.stopPropagation();
992
+ onTriggerClick();
993
+ },
994
+ children: /* @__PURE__ */ jsxRuntime.jsx(base.Icon, { iconSource: triggerIcon, sizeVar: "S", color: "neutral400", className: uniqueClass })
995
+ }
996
+ ),
997
+ showFilterMenu && /* @__PURE__ */ jsxRuntime.jsx(
998
+ SmallIconButton,
999
+ {
1000
+ sizeVar: "XS",
1001
+ styleVar: "GHOST",
1002
+ onClick: (e) => {
1003
+ e.stopPropagation();
1004
+ onTriggerClick();
1005
+ },
1006
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1007
+ base.Icon,
1008
+ {
1009
+ iconSource: isOpen ? shoplAssets.UpArrowSolidXsmallIcon : shoplAssets.DownArrowSolidXsmallIcon,
1010
+ sizeVar: "XS",
1011
+ color: "neutral400"
1012
+ }
1013
+ )
1014
+ }
1015
+ )
1016
+ ]
1017
+ }
1018
+ );
1019
+ };
1020
+ var TableHeadCell = ({ header, onFilterChange, onSortChange }) => {
1021
+ const tableHeadRef = React6.useRef(null);
1022
+ const [triggerWidth, setTriggerWidth] = React6.useState(0);
1023
+ const uniqueClass = `filter-menu-${header.column.id}`;
1024
+ const [isOpen, setIsOpen] = utils.useOutsideClick({
1025
+ selector: `.${uniqueClass}`
1026
+ });
1027
+ const showFilterMenu = header.column.getCanFilter();
1028
+ const showSortMenu = header.column.getCanSort();
1029
+ const hasInteraction = showFilterMenu || showSortMenu;
1030
+ const cursorStyle = hasInteraction ? "pointer" : "default";
1031
+ React6.useEffect(() => {
1032
+ if (tableHeadRef.current) {
1033
+ setTriggerWidth(tableHeadRef.current.clientWidth);
1034
+ }
1035
+ }, [isOpen, tableHeadRef]);
1036
+ return /* @__PURE__ */ jsxRuntime.jsxs(base.Popper, { offset: 4, placement: "bottom-start", strategy: "absolute", children: [
1037
+ /* @__PURE__ */ jsxRuntime.jsx(
1038
+ base.Popper.Trigger,
1039
+ {
1040
+ isOpen,
1041
+ onClick: () => {
1042
+ setIsOpen((prev) => !prev);
1043
+ },
1044
+ style: {
1045
+ cursor: cursorStyle,
1046
+ background: `${(showFilterMenu || showSortMenu) && isOpen ? base.colorTokens.neutral400_5 : base.colorTokens.neutral100}`,
1047
+ padding: `${(showFilterMenu || showSortMenu) && "8px"}`,
1048
+ borderRadius: `${isOpen ? "6px" : "0px"}`
1049
+ },
1050
+ width: "100%",
1051
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1052
+ TableHeadTrigger,
1053
+ {
1054
+ isOpen,
1055
+ header,
1056
+ uniqueClass,
1057
+ tableHeadRef,
1058
+ onTriggerClick: () => setIsOpen((prev) => !prev)
1059
+ }
1060
+ )
1061
+ }
1062
+ ),
1063
+ isOpen && /* @__PURE__ */ jsxRuntime.jsxs(base.Popper.Portal, { children: [
1064
+ showFilterMenu && /* @__PURE__ */ jsxRuntime.jsx(
1065
+ FilterMenu,
1066
+ {
1067
+ header,
1068
+ onFilterChange: (value) => {
1069
+ onFilterChange == null ? void 0 : onFilterChange(value);
1070
+ },
1071
+ triggerWidth: triggerWidth + 16
1072
+ }
1073
+ ),
1074
+ showSortMenu && /* @__PURE__ */ jsxRuntime.jsx(
1075
+ SortMenu,
1076
+ {
1077
+ header,
1078
+ onSortChange: (value) => {
1079
+ onSortChange == null ? void 0 : onSortChange(value);
1080
+ },
1081
+ triggerWidth: triggerWidth + 16
1082
+ }
1083
+ )
1084
+ ] })
1085
+ ] });
1086
+ };
1087
+ var TableHeadCell_default = TableHeadCell;
1088
+ var FixedTable = ({ tableState }) => {
1089
+ const { table, headerRef, bodyRef, tableScrollRef, hasToolbar, hasPagination, onClickRow } = useTable();
1090
+ const {
1091
+ displayedRows,
1092
+ paddingTop,
1093
+ paddingBottom,
1094
+ isEmpty,
1095
+ emptyElement,
1096
+ children,
1097
+ isSticky,
1098
+ stickyHeaderTopPosition,
1099
+ maxHeight = "100%",
1100
+ emptyRowCount = 8
1101
+ } = tableState;
1102
+ const handleScroll = React6.useCallback(() => {
1103
+ if (headerRef.current && bodyRef.current && tableScrollRef.current) {
1104
+ const scrollLeft = bodyRef.current.scrollLeft;
1105
+ headerRef.current.scrollLeft = scrollLeft;
1106
+ tableScrollRef.current.scrollLeft = scrollLeft;
1107
+ }
1108
+ }, []);
1109
+ const TableColumns = () => /* @__PURE__ */ jsxRuntime.jsx("colgroup", { children: table.getAllColumns().map((column) => {
1110
+ const size = column.columnDef.size;
1111
+ const minSize = column.columnDef.minSize;
1112
+ const maxSize = column.columnDef.maxSize;
1113
+ const style = size === 0 ? { width: "100%" } : {
1114
+ width: `${size}px`,
1115
+ minWidth: `${minSize}px`,
1116
+ maxWidth: `${maxSize}px`
1117
+ };
1118
+ return /* @__PURE__ */ jsxRuntime.jsx("col", { style }, column.id);
1119
+ }) });
1120
+ const getFixedCellStyle = (column, isHeader = false) => {
1121
+ var _a, _b, _c, _d;
1122
+ const baseStyle = __spreadValues(__spreadValues({}, getCommonPinningStyles(column)), isHeader ? (_b = (_a = column.columnDef.meta) == null ? void 0 : _a.headerProps) == null ? void 0 : _b.style : (_d = (_c = column.columnDef.meta) == null ? void 0 : _c.cellProps) == null ? void 0 : _d.style);
1123
+ const size = column.columnDef.size;
1124
+ const minSize = column.columnDef.minSize;
1125
+ const maxSize = column.columnDef.maxSize;
1126
+ return __spreadValues(__spreadValues({}, baseStyle), size === 0 ? { width: "100%" } : {
1127
+ width: `${size}px`,
1128
+ minWidth: `${minSize}px`,
1129
+ maxWidth: `${maxSize}px`
1130
+ });
1131
+ };
1132
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1133
+ /* @__PURE__ */ jsxRuntime.jsx(
1134
+ HeaderTableContainer,
1135
+ {
1136
+ ref: headerRef,
1137
+ hasHeader: hasToolbar,
1138
+ isSticky,
1139
+ stickyHeaderMarginTop: stickyHeaderTopPosition,
1140
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1141
+ "table",
1142
+ {
1143
+ style: {
1144
+ width: "100%",
1145
+ overflow: "auto",
1146
+ tableLayout: "fixed"
1147
+ },
1148
+ children: [
1149
+ /* @__PURE__ */ jsxRuntime.jsx(TableColumns, {}),
1150
+ /* @__PURE__ */ jsxRuntime.jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: headerGroup.headers.map((header) => {
1151
+ const isPinned = header.column.getIsPinned();
1152
+ const isLastLeftPinned = isPinned === "left" && header.column.getIsLastColumn("left");
1153
+ const isFirstRightPinned = isPinned === "right" && header.column.getIsFirstColumn("right");
1154
+ const columnRelativeDepth = header.depth - header.column.depth;
1155
+ if (!header.isPlaceholder && columnRelativeDepth > 1 && header.id === header.column.id) {
1156
+ return null;
1157
+ }
1158
+ let rowSpan = 1;
1159
+ if (header.isPlaceholder) {
1160
+ const leafs = header.getLeafHeaders();
1161
+ rowSpan = leafs[leafs.length - 1].depth - header.depth;
1162
+ }
1163
+ return /* @__PURE__ */ jsxRuntime.jsx(
1164
+ TableHead,
1165
+ {
1166
+ "data-last-left-pinned": isLastLeftPinned,
1167
+ "data-first-right-pinned": isFirstRightPinned,
1168
+ "data-pinned": isPinned,
1169
+ style: getFixedCellStyle(header.column, true),
1170
+ colSpan: header.colSpan,
1171
+ rowSpan,
1172
+ children: /* @__PURE__ */ jsxRuntime.jsx(TableHeadCell_default, { header })
1173
+ },
1174
+ header.id
1175
+ );
1176
+ }) }, headerGroup.id)) })
1177
+ ]
1178
+ }
1179
+ )
1180
+ }
1181
+ ),
1182
+ /* @__PURE__ */ jsxRuntime.jsx(base.ScrollArea, { autoHeightMax: maxHeight, autoHeight: true, children: /* @__PURE__ */ jsxRuntime.jsx(BodyTableContainer, { hasPagination, onScroll: handleScroll, ref: bodyRef, children: isEmpty ? children || emptyElement : /* @__PURE__ */ jsxRuntime.jsxs(
1183
+ "table",
1184
+ {
1185
+ style: {
1186
+ width: "100%",
1187
+ overflow: "auto",
1188
+ tableLayout: "fixed"
1189
+ },
1190
+ children: [
1191
+ /* @__PURE__ */ jsxRuntime.jsx(TableColumns, {}),
1192
+ /* @__PURE__ */ jsxRuntime.jsxs(TableBody, { children: [
1193
+ paddingTop > 0 && /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx("td", { style: { height: `${paddingTop}px` } }) }),
1194
+ displayedRows.map((rowObj, i) => {
1195
+ const isVirtual = "virtualRow" in rowObj && rowObj.virtualRow;
1196
+ const row = rowObj.row;
1197
+ const cells = typeof row.getVisibleCells === "function" ? row.getVisibleCells() : row;
1198
+ return /* @__PURE__ */ jsxRuntime.jsx(
1199
+ TableRow,
1200
+ {
1201
+ "data-index": isVirtual ? rowObj.virtualRow.index : i,
1202
+ onClick: () => {
1203
+ var _a;
1204
+ if (typeof row.getVisibleCells === "function") {
1205
+ onClickRow == null ? void 0 : onClickRow(row.original);
1206
+ } else if (Array.isArray(row) && row.length > 0 && ((_a = row[0].row) == null ? void 0 : _a.original)) {
1207
+ onClickRow == null ? void 0 : onClickRow(row[0].row.original);
1208
+ }
1209
+ },
1210
+ className: onClickRow !== void 0 ? "clickable" : "",
1211
+ children: cells.map((cell) => {
1212
+ var _a;
1213
+ const isPinned = cell.column.getIsPinned();
1214
+ const isLastLeftPinned = isPinned === "left" && cell.column.getIsLastColumn("left");
1215
+ const isFirstRightPinned = isPinned === "right" && cell.column.getIsFirstColumn("right");
1216
+ return /* @__PURE__ */ jsxRuntime.jsx(React6.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
1217
+ TableCell,
1218
+ {
1219
+ "data-last-left-pinned": isLastLeftPinned,
1220
+ "data-first-right-pinned": isFirstRightPinned,
1221
+ "data-no-hover": ((_a = cell.column.columnDef.meta) == null ? void 0 : _a.activeHover) ? "true" : void 0,
1222
+ style: getFixedCellStyle(cell.column),
1223
+ children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext())
1224
+ }
1225
+ ) }, cell.id);
1226
+ })
1227
+ },
1228
+ typeof row.id !== "undefined" ? row.id : i
1229
+ );
1230
+ }),
1231
+ paddingBottom > 0 && /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx("td", { style: { height: `${paddingBottom}px` } }) }),
1232
+ emptyRowCount !== 0 && displayedRows.length < emptyRowCount && Array.from({ length: emptyRowCount - displayedRows.length }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(TableRow, { "data-empty": true, children: /* @__PURE__ */ jsxRuntime.jsx(
1233
+ TableCell,
1234
+ {
1235
+ colSpan: table.getAllColumns().length,
1236
+ style: {
1237
+ height: `${60}px`
1238
+ }
1239
+ }
1240
+ ) }, `empty-row-${index}`))
1241
+ ] })
1242
+ ]
1243
+ }
1244
+ ) }) })
1245
+ ] });
1246
+ };
1247
+ var ResizableTable = ({ tableState }) => {
1248
+ const { table, headerRef, bodyRef, tableScrollRef, hasToolbar, hasPagination, onClickRow } = useTable();
1249
+ const {
1250
+ displayedRows,
1251
+ paddingTop,
1252
+ paddingBottom,
1253
+ isEmpty,
1254
+ emptyElement,
1255
+ children,
1256
+ isSticky,
1257
+ stickyHeaderTopPosition,
1258
+ maxHeight = "100%",
1259
+ emptyRowCount = 8
1260
+ } = tableState;
1261
+ const handleScroll = React6.useCallback(() => {
1262
+ if (headerRef.current && bodyRef.current && tableScrollRef.current) {
1263
+ const scrollLeft = bodyRef.current.scrollLeft;
1264
+ headerRef.current.scrollLeft = scrollLeft;
1265
+ tableScrollRef.current.scrollLeft = scrollLeft;
1266
+ }
1267
+ }, []);
1268
+ const columnSizeVars = React6__default.default.useMemo(() => {
1269
+ var _a;
1270
+ const headers = table.getFlatHeaders();
1271
+ const colSizes = {};
1272
+ const visibleHeaders = headers.filter((header) => header.column.getIsVisible());
1273
+ const lastLeafColumns = table.getLeafHeaders();
1274
+ const lastColumnId = (_a = lastLeafColumns[lastLeafColumns.length - 1]) == null ? void 0 : _a.id;
1275
+ visibleHeaders.forEach((header) => {
1276
+ const currentSize = header.column.getSize();
1277
+ const defaultSize = header.column.columnDef.size;
1278
+ const maxSize = header.column.columnDef.maxSize;
1279
+ const isLastColumn = header.id === lastColumnId;
1280
+ let size;
1281
+ if (isLastColumn) {
1282
+ size = "auto";
1283
+ } else if (currentSize !== void 0) {
1284
+ size = currentSize;
1285
+ } else if (typeof defaultSize === "number") {
1286
+ size = defaultSize;
1287
+ } else {
1288
+ size = 200;
1289
+ }
1290
+ if (!isLastColumn && maxSize && typeof size === "number" && size > maxSize) {
1291
+ size = maxSize;
1292
+ }
1293
+ colSizes[`--header-${header.id}-size`] = size;
1294
+ colSizes[`--col-${header.column.id}-size`] = size;
1295
+ });
1296
+ return colSizes;
1297
+ }, [table.getState().columnSizingInfo, table.getState().columnSizing]);
1298
+ const getResizableCellStyle = (column, isHeader = false) => {
1299
+ var _a, _b, _c, _d, _e;
1300
+ const baseStyle = __spreadValues(__spreadValues({}, getCommonPinningStyles(column)), isHeader ? (_b = (_a = column.columnDef.meta) == null ? void 0 : _a.headerProps) == null ? void 0 : _b.style : (_d = (_c = column.columnDef.meta) == null ? void 0 : _c.cellProps) == null ? void 0 : _d.style);
1301
+ const colId = column.id;
1302
+ const headerId = isHeader ? colId : null;
1303
+ const minSize = column.columnDef.minSize || 100;
1304
+ const maxSize = column.columnDef.maxSize;
1305
+ const sizeKey = isHeader ? `--header-${headerId}-size` : `--col-${colId}-size`;
1306
+ const size = columnSizeVars[sizeKey];
1307
+ const isLastColumn = (_e = column.columnDef.meta) == null ? void 0 : _e.isLastColumn;
1308
+ return __spreadProps(__spreadValues(__spreadValues({}, baseStyle), size === "auto" ? { width: "auto", flex: "1 1 auto" } : { width: size ? `${size}px` : "auto" }), {
1309
+ minWidth: `${minSize}px`,
1310
+ maxWidth: isLastColumn ? "none" : `${maxSize || "none"}`
1311
+ });
1312
+ };
1313
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1314
+ /* @__PURE__ */ jsxRuntime.jsx(
1315
+ HeaderTableContainer,
1316
+ {
1317
+ hasHeader: hasToolbar,
1318
+ isSticky,
1319
+ stickyHeaderMarginTop: stickyHeaderTopPosition,
1320
+ ref: headerRef,
1321
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1322
+ "table",
1323
+ {
1324
+ style: {
1325
+ width: `${table.getCenterTotalSize()}px`,
1326
+ minWidth: "100%",
1327
+ tableLayout: "fixed"
1328
+ },
1329
+ children: /* @__PURE__ */ jsxRuntime.jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: headerGroup.headers.map((header) => {
1330
+ const isPinned = header.column.getIsPinned();
1331
+ const isLastLeftPinned = isPinned === "left" && header.column.getIsLastColumn("left");
1332
+ const isFirstRightPinned = isPinned === "right" && header.column.getIsFirstColumn("right");
1333
+ const columnRelativeDepth = header.depth - header.column.depth;
1334
+ if (!header.isPlaceholder && columnRelativeDepth > 1 && header.id === header.column.id) {
1335
+ return null;
1336
+ }
1337
+ let rowSpan = 1;
1338
+ if (header.isPlaceholder) {
1339
+ const leafs = header.getLeafHeaders();
1340
+ rowSpan = leafs[leafs.length - 1].depth - header.depth;
1341
+ }
1342
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1343
+ TableHead,
1344
+ {
1345
+ "data-last-left-pinned": isLastLeftPinned,
1346
+ "data-first-right-pinned": isFirstRightPinned,
1347
+ "data-pinned": isPinned,
1348
+ style: getResizableCellStyle(header.column, true),
1349
+ colSpan: header.colSpan,
1350
+ rowSpan,
1351
+ children: [
1352
+ /* @__PURE__ */ jsxRuntime.jsx(TableHeadCell_default, { header }),
1353
+ header.column.getCanResize() && /* @__PURE__ */ jsxRuntime.jsx(
1354
+ TableResizer,
1355
+ __spreadValues({}, {
1356
+ onDoubleClick: () => header.column.resetSize(),
1357
+ onMouseDown: header.getResizeHandler(),
1358
+ onTouchStart: header.getResizeHandler(),
1359
+ className: `resizer ${header.column.getIsResizing() ? "isResizing" : ""}`
1360
+ })
1361
+ )
1362
+ ]
1363
+ },
1364
+ header.id
1365
+ );
1366
+ }) }, headerGroup.id)) })
1367
+ }
1368
+ )
1369
+ }
1370
+ ),
1371
+ /* @__PURE__ */ jsxRuntime.jsx(base.ScrollArea, { autoHeightMax: maxHeight, autoHeight: true, children: /* @__PURE__ */ jsxRuntime.jsx(BodyTableContainer, { hasPagination, onScroll: handleScroll, ref: bodyRef, children: /* @__PURE__ */ jsxRuntime.jsx(
1372
+ "table",
1373
+ {
1374
+ style: {
1375
+ width: `${table.getCenterTotalSize()}px`,
1376
+ minWidth: "100%",
1377
+ tableLayout: "fixed"
1378
+ },
1379
+ children: /* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: isEmpty ? /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx(
1380
+ TableCell,
1381
+ {
1382
+ colSpan: table.getAllColumns().length,
1383
+ style: {
1384
+ height: "200px",
1385
+ textAlign: "center",
1386
+ verticalAlign: "middle"
1387
+ },
1388
+ children: children || emptyElement
1389
+ }
1390
+ ) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1391
+ paddingTop > 0 && /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx("td", { style: { height: `${paddingTop}px` } }) }),
1392
+ displayedRows.map((rowObj, i) => {
1393
+ const isVirtual = "virtualRow" in rowObj && rowObj.virtualRow;
1394
+ const row = rowObj.row;
1395
+ const cells = typeof row.getVisibleCells === "function" ? row.getVisibleCells() : row;
1396
+ return /* @__PURE__ */ jsxRuntime.jsx(
1397
+ TableRow,
1398
+ {
1399
+ "data-index": isVirtual ? rowObj.virtualRow.index : i,
1400
+ onClick: () => {
1401
+ var _a;
1402
+ if (typeof row.getVisibleCells === "function") {
1403
+ onClickRow == null ? void 0 : onClickRow(row.original);
1404
+ } else if (Array.isArray(row) && row.length > 0 && ((_a = row[0].row) == null ? void 0 : _a.original)) {
1405
+ onClickRow == null ? void 0 : onClickRow(row[0].row.original);
1406
+ }
1407
+ },
1408
+ className: onClickRow !== void 0 ? "clickable" : "",
1409
+ children: cells.map((cell) => {
1410
+ var _a;
1411
+ const isPinned = cell.column.getIsPinned();
1412
+ const isLastLeftPinned = isPinned === "left" && cell.column.getIsLastColumn("left");
1413
+ const isFirstRightPinned = isPinned === "right" && cell.column.getIsFirstColumn("right");
1414
+ return /* @__PURE__ */ jsxRuntime.jsx(
1415
+ TableCell,
1416
+ {
1417
+ "data-last-left-pinned": isLastLeftPinned,
1418
+ "data-first-right-pinned": isFirstRightPinned,
1419
+ "data-no-hover": ((_a = cell.column.columnDef.meta) == null ? void 0 : _a.activeHover) ? "true" : void 0,
1420
+ style: getResizableCellStyle(cell.column),
1421
+ children: reactTable.flexRender(cell.column.columnDef.cell, cell.getContext())
1422
+ },
1423
+ cell.id
1424
+ );
1425
+ })
1426
+ },
1427
+ typeof row.id !== "undefined" ? row.id : i
1428
+ );
1429
+ }),
1430
+ paddingBottom > 0 && /* @__PURE__ */ jsxRuntime.jsx(TableRow, { children: /* @__PURE__ */ jsxRuntime.jsx("td", { style: { height: `${paddingBottom}px` } }) }),
1431
+ emptyRowCount !== 0 && displayedRows.length < emptyRowCount && Array.from({ length: emptyRowCount - displayedRows.length }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(TableRow, { "data-empty": true, children: /* @__PURE__ */ jsxRuntime.jsx(
1432
+ TableCell,
1433
+ {
1434
+ colSpan: table.getAllColumns().length,
1435
+ style: {
1436
+ height: `${60}px`
1437
+ }
1438
+ }
1439
+ ) }, `empty-row-${index}`))
1440
+ ] }) })
1441
+ }
1442
+ ) }) })
1443
+ ] });
1444
+ };
1445
+ var TableMain = ({
1446
+ fixedColumns = [],
1447
+ useVirtualization = false,
1448
+ isSticky = true,
1449
+ stickyHeaderTopPosition = 120,
1450
+ children,
1451
+ maxHeight,
1452
+ emptyRowCount = 8
1453
+ }) => {
1454
+ const { table, hasToolbar, hasFilterBar, columnResizing } = useTable();
1455
+ const { rows } = table.getRowModel();
1456
+ const scrollToFn = React6.useCallback((offset) => {
1457
+ window.scrollTo({
1458
+ top: offset - 120,
1459
+ behavior: "smooth"
1460
+ });
1461
+ }, []);
1462
+ const rowVirtualizer = reactVirtual.useWindowVirtualizer({
1463
+ estimateSize: () => 60,
1464
+ // 각 행의 높이를 60px로 예측
1465
+ count: rows.length,
1466
+ overscan: 10,
1467
+ // 실제 보이는 영역 외에 추가로 렌더링할 아이템 수
1468
+ isScrollingResetDelay: 100,
1469
+ // 스크롤이 멈추고 100ms 후에 스크롤 상태 초기화
1470
+ observeElementOffset: (instance, cb) => reactVirtual.observeWindowOffset(instance, (offset, isScrolling) => cb(offset - 120, isScrolling)),
1471
+ scrollToFn
1472
+ });
1473
+ const { getVirtualItems: virtualRows } = rowVirtualizer;
1474
+ const displayedRows = useVirtualization ? virtualRows().map((virtualRow) => ({ row: rows[virtualRow.index], virtualRow })) : rows.map((row) => ({ row }));
1475
+ const hasVirtualRow = (item) => {
1476
+ return "virtualRow" in item;
1477
+ };
1478
+ const paddingTop = displayedRows.length > 0 && hasVirtualRow(displayedRows[0]) ? displayedRows[0].virtualRow.start : 0;
1479
+ const lastRow = displayedRows[displayedRows.length - 1];
1480
+ const paddingBottom = displayedRows.length > 0 && lastRow && hasVirtualRow(lastRow) ? rowVirtualizer.getTotalSize() - lastRow.virtualRow.end : 0;
1481
+ React6.useEffect(() => {
1482
+ const pinningState = {
1483
+ left: [],
1484
+ right: []
1485
+ };
1486
+ fixedColumns.forEach(({ index, position }) => {
1487
+ const column = table.getAllColumns()[index];
1488
+ if (column == null ? void 0 : column.id) {
1489
+ pinningState[position].push(column.id);
1490
+ }
1491
+ });
1492
+ table.setColumnPinning(pinningState);
1493
+ }, []);
1494
+ const isEmpty = rows.length === 0;
1495
+ let emptyElement;
1496
+ React6__default.default.Children.forEach(children, (child) => {
1497
+ if (React6__default.default.isValidElement(child) && child.type === TableEmpty) {
1498
+ emptyElement = child;
1499
+ }
1500
+ });
1501
+ const tableState = {
1502
+ displayedRows,
1503
+ paddingTop,
1504
+ paddingBottom,
1505
+ isEmpty,
1506
+ emptyElement,
1507
+ children,
1508
+ maxHeight,
1509
+ hasToolbar,
1510
+ isSticky,
1511
+ stickyHeaderTopPosition,
1512
+ emptyRowCount
1513
+ };
1514
+ return /* @__PURE__ */ jsxRuntime.jsx(TableRootContainer, { hasFilterBar, hasToolbar, children: columnResizing ? /* @__PURE__ */ jsxRuntime.jsx(ResizableTable, { tableState }) : /* @__PURE__ */ jsxRuntime.jsx(FixedTable, { tableState }) });
1515
+ };
1516
+ var TableColumnVisibility = () => {
1517
+ const { table } = useTable();
1518
+ const getColumnHeader = (column) => {
1519
+ var _a;
1520
+ const header = column.columnDef.header;
1521
+ if (typeof header === "function") {
1522
+ const headerContent = header();
1523
+ if (typeof headerContent === "string") {
1524
+ return headerContent;
1525
+ }
1526
+ return ((_a = headerContent.props) == null ? void 0 : _a.children) || headerContent;
1527
+ }
1528
+ return header;
1529
+ };
1530
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1531
+ /* @__PURE__ */ jsxRuntime.jsxs(base.Stack.Horizontal, { align: "center", spacing: "spacing12", children: [
1532
+ /* @__PURE__ */ jsxRuntime.jsx(base.Checkbox, { checked: table.getIsAllColumnsVisible(), onClick: table.getToggleAllColumnsVisibilityHandler() }),
1533
+ /* @__PURE__ */ jsxRuntime.jsx(base.Text, { typography: "body1_400", children: "\uC804\uCCB4 \uC120\uD0DD" })
1534
+ ] }),
1535
+ /* @__PURE__ */ jsxRuntime.jsx(base.Stack.Vertical, { spacing: "spacing12", children: table.getAllLeafColumns().map((column) => {
1536
+ return /* @__PURE__ */ jsxRuntime.jsxs(base.Stack.Horizontal, { align: "center", spacing: "spacing12", children: [
1537
+ /* @__PURE__ */ jsxRuntime.jsx(base.Checkbox, { checked: column.getIsVisible(), onClick: column.getToggleVisibilityHandler() }),
1538
+ /* @__PURE__ */ jsxRuntime.jsx(base.Text, { typography: "body1_400", children: getColumnHeader(column) })
1539
+ ] }, column.id);
1540
+ }) })
1541
+ ] });
1542
+ };
1543
+ var TableBtn = styled2__default.default.button`
1544
+ display: flex;
1545
+ align-items: center;
1546
+ gap: 2px;
1547
+ border: 1px solid ${base.colorTokens.neutral200};
1548
+ border-radius: 4px;
1549
+ padding: 4px;
1550
+ background: ${base.colorTokens.neutral150};
1551
+ color: ${base.colorTokens.neutral700};
1552
+ cursor: ${({ onClick }) => onClick ? "pointer" : "default"};
1553
+
1554
+ &:hover {
1555
+ background: ${({ disabled }) => disabled ? base.colorTokens.neutral150 : base.colorTokens.neutral200};
1556
+ }
1557
+
1558
+ &:disabled {
1559
+ cursor: not-allowed;
1560
+ opacity: 0.5;
1561
+ }
1562
+ `;
1563
+ exports.TableButton = (_a) => {
1564
+ var _b = _a, { children, leftSource, rightSource } = _b, buttonProps = __objRest(_b, ["children", "leftSource", "rightSource"]);
1565
+ return /* @__PURE__ */ jsxRuntime.jsxs(TableBtn, __spreadProps(__spreadValues({}, buttonProps), { children: [
1566
+ leftSource && leftSource,
1567
+ /* @__PURE__ */ jsxRuntime.jsx(base.Text, { typography: "body2_500", lineClamp: 2, children }),
1568
+ rightSource && rightSource
1569
+ ] }));
1570
+ };
1571
+ exports.TableBadge = ({ children }) => {
1572
+ return /* @__PURE__ */ jsxRuntime.jsx(base.StackContainer, { radius: "borderRadius04", background: "neutral150", padding: "2px 4px", children: /* @__PURE__ */ jsxRuntime.jsx(base.Text, { typography: "body2_400", children }) });
1573
+ };
1574
+
1575
+ // src/components/Table/components/Table/index.ts
1576
+ exports.Table = Object.assign(Table, {
1577
+ Toolbar: TableToolbar,
1578
+ FilterBar: TableFilterBar,
1579
+ Main: TableMain,
1580
+ Pagination: TablePagination,
1581
+ Empty: TableEmpty,
1582
+ ColumnVisibility: TableColumnVisibility,
1583
+ Button: exports.TableButton,
1584
+ Badge: exports.TableBadge
1585
+ });
1586
+
1587
+ Object.defineProperty(exports, 'createColumnHelper', {
1588
+ enumerable: true,
1589
+ get: function () { return reactTable.createColumnHelper; }
1590
+ });