@shoplflow/templates 0.0.54 → 0.1.0

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