@shadng/sng-ui 1.0.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/LICENSE +21 -0
- package/README.md +75 -0
- package/cli/sng-ui.js +331 -0
- package/ng-package.json +29 -0
- package/package.json +64 -0
- package/registry.json +72 -0
- package/src/lib/accordion/cn.ts +6 -0
- package/src/lib/accordion/index.ts +18 -0
- package/src/lib/accordion/sng-accordion-content.ts +131 -0
- package/src/lib/accordion/sng-accordion-item.ts +299 -0
- package/src/lib/accordion/sng-accordion-trigger.ts +137 -0
- package/src/lib/accordion/sng-accordion.ts +118 -0
- package/src/lib/accordion/sng-accordion.types.ts +82 -0
- package/src/lib/alert/cn.ts +6 -0
- package/src/lib/alert/index.ts +3 -0
- package/src/lib/alert/sng-alert-description.ts +49 -0
- package/src/lib/alert/sng-alert-title.ts +46 -0
- package/src/lib/alert/sng-alert.ts +48 -0
- package/src/lib/avatar/cn.ts +6 -0
- package/src/lib/avatar/index.ts +3 -0
- package/src/lib/avatar/sng-avatar-fallback.ts +50 -0
- package/src/lib/avatar/sng-avatar-image.ts +73 -0
- package/src/lib/avatar/sng-avatar.ts +60 -0
- package/src/lib/badge/cn.ts +6 -0
- package/src/lib/badge/index.ts +1 -0
- package/src/lib/badge/sng-badge.ts +36 -0
- package/src/lib/breadcrumb/cn.ts +6 -0
- package/src/lib/breadcrumb/index.ts +7 -0
- package/src/lib/breadcrumb/sng-breadcrumb-ellipsis.ts +61 -0
- package/src/lib/breadcrumb/sng-breadcrumb-item.ts +47 -0
- package/src/lib/breadcrumb/sng-breadcrumb-link.ts +43 -0
- package/src/lib/breadcrumb/sng-breadcrumb-list.ts +42 -0
- package/src/lib/breadcrumb/sng-breadcrumb-page.ts +44 -0
- package/src/lib/breadcrumb/sng-breadcrumb-separator.ts +60 -0
- package/src/lib/breadcrumb/sng-breadcrumb.ts +52 -0
- package/src/lib/button/cn.ts +6 -0
- package/src/lib/button/index.ts +2 -0
- package/src/lib/button/sng-button.ts +264 -0
- package/src/lib/calendar/cn.ts +6 -0
- package/src/lib/calendar/index.ts +2 -0
- package/src/lib/calendar/sng-calendar.ts +753 -0
- package/src/lib/card/cn.ts +6 -0
- package/src/lib/card/index.ts +6 -0
- package/src/lib/card/sng-card-content.ts +36 -0
- package/src/lib/card/sng-card-description.ts +38 -0
- package/src/lib/card/sng-card-footer.ts +34 -0
- package/src/lib/card/sng-card-header.ts +34 -0
- package/src/lib/card/sng-card-title.ts +48 -0
- package/src/lib/card/sng-card.ts +43 -0
- package/src/lib/carousel/cn.ts +6 -0
- package/src/lib/carousel/index.ts +18 -0
- package/src/lib/carousel/sng-carousel.ts +526 -0
- package/src/lib/checkbox/cn.ts +6 -0
- package/src/lib/checkbox/index.ts +1 -0
- package/src/lib/checkbox/sng-checkbox.ts +154 -0
- package/src/lib/code-block/cn.ts +6 -0
- package/src/lib/code-block/index.ts +1 -0
- package/src/lib/code-block/sng-code-block.ts +296 -0
- package/src/lib/dialog/cn.ts +6 -0
- package/src/lib/dialog/index.ts +37 -0
- package/src/lib/dialog/sng-dialog-close.ts +76 -0
- package/src/lib/dialog/sng-dialog-content.ts +132 -0
- package/src/lib/dialog/sng-dialog-description.ts +36 -0
- package/src/lib/dialog/sng-dialog-footer.ts +39 -0
- package/src/lib/dialog/sng-dialog-header.ts +39 -0
- package/src/lib/dialog/sng-dialog-title.ts +52 -0
- package/src/lib/dialog/sng-dialog.service.ts +222 -0
- package/src/lib/dialog/sng-dialog.ts +224 -0
- package/src/lib/drawer/cn.ts +6 -0
- package/src/lib/drawer/index.ts +36 -0
- package/src/lib/drawer/sng-drawer-close.ts +28 -0
- package/src/lib/drawer/sng-drawer-content.ts +135 -0
- package/src/lib/drawer/sng-drawer-description.ts +29 -0
- package/src/lib/drawer/sng-drawer-footer.ts +34 -0
- package/src/lib/drawer/sng-drawer-handle.ts +30 -0
- package/src/lib/drawer/sng-drawer-header.ts +30 -0
- package/src/lib/drawer/sng-drawer-title.ts +27 -0
- package/src/lib/drawer/sng-drawer-trigger.ts +21 -0
- package/src/lib/drawer/sng-drawer-wrapper.ts +27 -0
- package/src/lib/drawer/sng-drawer.ts +166 -0
- package/src/lib/file-input/cn.ts +6 -0
- package/src/lib/file-input/index.ts +1 -0
- package/src/lib/file-input/sng-file-input.ts +288 -0
- package/src/lib/hover-card/cn.ts +6 -0
- package/src/lib/hover-card/index.ts +3 -0
- package/src/lib/hover-card/sng-hover-card-content.ts +100 -0
- package/src/lib/hover-card/sng-hover-card-trigger.ts +43 -0
- package/src/lib/hover-card/sng-hover-card.ts +246 -0
- package/src/lib/input/cn.ts +6 -0
- package/src/lib/input/index.ts +1 -0
- package/src/lib/input/sng-input.ts +160 -0
- package/src/lib/layout/cn.ts +6 -0
- package/src/lib/layout/index.ts +98 -0
- package/src/lib/layout/sng-layout-footer.ts +37 -0
- package/src/lib/layout/sng-layout-header.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-content.ts +149 -0
- package/src/lib/layout/sng-layout-sidebar-footer.ts +54 -0
- package/src/lib/layout/sng-layout-sidebar-group-action.ts +67 -0
- package/src/lib/layout/sng-layout-sidebar-group-content.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-group-label.ts +53 -0
- package/src/lib/layout/sng-layout-sidebar-group.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-header.ts +54 -0
- package/src/lib/layout/sng-layout-sidebar-input.ts +112 -0
- package/src/lib/layout/sng-layout-sidebar-inset.ts +45 -0
- package/src/lib/layout/sng-layout-sidebar-menu-action.ts +84 -0
- package/src/lib/layout/sng-layout-sidebar-menu-badge.ts +47 -0
- package/src/lib/layout/sng-layout-sidebar-menu-button.ts +160 -0
- package/src/lib/layout/sng-layout-sidebar-menu-item.ts +40 -0
- package/src/lib/layout/sng-layout-sidebar-menu-skeleton.ts +71 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub-button.ts +142 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub-item.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-menu-sub.ts +48 -0
- package/src/lib/layout/sng-layout-sidebar-menu.ts +41 -0
- package/src/lib/layout/sng-layout-sidebar-provider.ts +189 -0
- package/src/lib/layout/sng-layout-sidebar-rail.ts +60 -0
- package/src/lib/layout/sng-layout-sidebar-separator.ts +38 -0
- package/src/lib/layout/sng-layout-sidebar-trigger.ts +97 -0
- package/src/lib/layout/sng-layout-sidebar.ts +254 -0
- package/src/lib/menu/cn.ts +6 -0
- package/src/lib/menu/index.ts +21 -0
- package/src/lib/menu/sng-context-trigger.ts +128 -0
- package/src/lib/menu/sng-menu-checkbox-item.ts +91 -0
- package/src/lib/menu/sng-menu-item.ts +80 -0
- package/src/lib/menu/sng-menu-label.ts +47 -0
- package/src/lib/menu/sng-menu-radio-group.ts +38 -0
- package/src/lib/menu/sng-menu-radio-item.ts +94 -0
- package/src/lib/menu/sng-menu-separator.ts +27 -0
- package/src/lib/menu/sng-menu-shortcut.ts +25 -0
- package/src/lib/menu/sng-menu-sub-content.ts +267 -0
- package/src/lib/menu/sng-menu-sub-trigger.ts +68 -0
- package/src/lib/menu/sng-menu-sub.ts +124 -0
- package/src/lib/menu/sng-menu-tokens.ts +52 -0
- package/src/lib/menu/sng-menu-trigger.ts +266 -0
- package/src/lib/menu/sng-menu.ts +100 -0
- package/src/lib/nav-menu/cn.ts +6 -0
- package/src/lib/nav-menu/index.ts +6 -0
- package/src/lib/nav-menu/sng-nav-menu-content.ts +72 -0
- package/src/lib/nav-menu/sng-nav-menu-item.ts +109 -0
- package/src/lib/nav-menu/sng-nav-menu-link.ts +54 -0
- package/src/lib/nav-menu/sng-nav-menu-list.ts +43 -0
- package/src/lib/nav-menu/sng-nav-menu-trigger.ts +98 -0
- package/src/lib/nav-menu/sng-nav-menu.ts +99 -0
- package/src/lib/otp-input/cn.ts +6 -0
- package/src/lib/otp-input/index.ts +14 -0
- package/src/lib/otp-input/sng-otp-input-group.ts +38 -0
- package/src/lib/otp-input/sng-otp-input-separator.ts +43 -0
- package/src/lib/otp-input/sng-otp-input-slot.ts +128 -0
- package/src/lib/otp-input/sng-otp-input-tokens.ts +20 -0
- package/src/lib/otp-input/sng-otp-input.ts +301 -0
- package/src/lib/popover/cn.ts +6 -0
- package/src/lib/popover/index.ts +3 -0
- package/src/lib/popover/sng-popover-content.ts +66 -0
- package/src/lib/popover/sng-popover-trigger.ts +44 -0
- package/src/lib/popover/sng-popover.ts +218 -0
- package/src/lib/preview-box/cn.ts +6 -0
- package/src/lib/preview-box/index.ts +5 -0
- package/src/lib/preview-box/sng-code-block.ts +80 -0
- package/src/lib/preview-box/sng-html-block.ts +79 -0
- package/src/lib/preview-box/sng-preview-block.ts +47 -0
- package/src/lib/preview-box/sng-preview-box.ts +369 -0
- package/src/lib/preview-box/sng-style-block.ts +80 -0
- package/src/lib/progress/cn.ts +6 -0
- package/src/lib/progress/index.ts +1 -0
- package/src/lib/progress/sng-progress.ts +65 -0
- package/src/lib/radio/cn.ts +6 -0
- package/src/lib/radio/index.ts +5 -0
- package/src/lib/radio/sng-radio-item.ts +100 -0
- package/src/lib/radio/sng-radio.ts +54 -0
- package/src/lib/resizable/cn.ts +6 -0
- package/src/lib/resizable/index.ts +3 -0
- package/src/lib/resizable/sng-resizable-group.ts +188 -0
- package/src/lib/resizable/sng-resizable-handle.ts +236 -0
- package/src/lib/resizable/sng-resizable-panel.ts +71 -0
- package/src/lib/search-input/cn.ts +6 -0
- package/src/lib/search-input/index.ts +16 -0
- package/src/lib/search-input/sng-search-input-context.ts +24 -0
- package/src/lib/search-input/sng-search-input-empty.ts +42 -0
- package/src/lib/search-input/sng-search-input-group.ts +69 -0
- package/src/lib/search-input/sng-search-input-item.ts +164 -0
- package/src/lib/search-input/sng-search-input-list.ts +34 -0
- package/src/lib/search-input/sng-search-input-separator.ts +32 -0
- package/src/lib/search-input/sng-search-input-shortcut.ts +29 -0
- package/src/lib/search-input/sng-search-input.ts +368 -0
- package/src/lib/select/cn.ts +6 -0
- package/src/lib/select/index.ts +7 -0
- package/src/lib/select/sng-select-content.ts +27 -0
- package/src/lib/select/sng-select-empty.ts +48 -0
- package/src/lib/select/sng-select-group.ts +29 -0
- package/src/lib/select/sng-select-item.ts +140 -0
- package/src/lib/select/sng-select-label.ts +29 -0
- package/src/lib/select/sng-select-separator.ts +29 -0
- package/src/lib/select/sng-select.ts +326 -0
- package/src/lib/separator/cn.ts +6 -0
- package/src/lib/separator/index.ts +1 -0
- package/src/lib/separator/sng-separator.ts +40 -0
- package/src/lib/skeleton/cn.ts +6 -0
- package/src/lib/skeleton/index.ts +1 -0
- package/src/lib/skeleton/sng-skeleton.ts +49 -0
- package/src/lib/slider/cn.ts +6 -0
- package/src/lib/slider/index.ts +2 -0
- package/src/lib/slider/sng-slider.ts +137 -0
- package/src/lib/sng-table/cn.ts +6 -0
- package/src/lib/sng-table/flex-render.ts +222 -0
- package/src/lib/sng-table/index.ts +85 -0
- package/src/lib/sng-table/sng-table-body.ts +59 -0
- package/src/lib/sng-table/sng-table-caption.ts +49 -0
- package/src/lib/sng-table/sng-table-cell.ts +62 -0
- package/src/lib/sng-table/sng-table-footer.ts +60 -0
- package/src/lib/sng-table/sng-table-head.ts +66 -0
- package/src/lib/sng-table/sng-table-header.ts +48 -0
- package/src/lib/sng-table/sng-table-pagination.ts +265 -0
- package/src/lib/sng-table/sng-table-row.ts +65 -0
- package/src/lib/sng-table/sng-table.ts +67 -0
- package/src/lib/sng-table-core/core/create-cell.ts +117 -0
- package/src/lib/sng-table-core/core/create-column.ts +266 -0
- package/src/lib/sng-table-core/core/create-header.ts +271 -0
- package/src/lib/sng-table-core/core/create-row.ts +293 -0
- package/src/lib/sng-table-core/core/create-table.ts +534 -0
- package/src/lib/sng-table-core/core/types.ts +1197 -0
- package/src/lib/sng-table-core/core/utils.ts +307 -0
- package/src/lib/sng-table-core/features/column-filtering.ts +376 -0
- package/src/lib/sng-table-core/features/column-ordering.ts +159 -0
- package/src/lib/sng-table-core/features/column-pinning.ts +219 -0
- package/src/lib/sng-table-core/features/column-sizing.ts +268 -0
- package/src/lib/sng-table-core/features/column-visibility.ts +128 -0
- package/src/lib/sng-table-core/features/faceting.ts +279 -0
- package/src/lib/sng-table-core/features/fuzzy-filtering.ts +188 -0
- package/src/lib/sng-table-core/features/global-filtering.ts +128 -0
- package/src/lib/sng-table-core/features/pagination.ts +179 -0
- package/src/lib/sng-table-core/features/row-expanding.ts +181 -0
- package/src/lib/sng-table-core/features/row-grouping.ts +235 -0
- package/src/lib/sng-table-core/features/row-pinning.ts +196 -0
- package/src/lib/sng-table-core/features/row-selection.ts +298 -0
- package/src/lib/sng-table-core/features/sorting.ts +425 -0
- package/src/lib/sng-table-core/features/virtualization.ts +298 -0
- package/src/lib/sng-table-core/index.ts +235 -0
- package/src/lib/sng-table-core/row-models/core-row-model.ts +256 -0
- package/src/lib/sng-table-core/row-models/expanded-row-model.ts +175 -0
- package/src/lib/sng-table-core/row-models/filtered-row-model.ts +307 -0
- package/src/lib/sng-table-core/row-models/grouped-row-model.ts +290 -0
- package/src/lib/sng-table-core/row-models/paginated-row-model.ts +135 -0
- package/src/lib/sng-table-core/row-models/sorted-row-model.ts +197 -0
- package/src/lib/styles/sng-themes.css +164 -0
- package/src/lib/switch/cn.ts +6 -0
- package/src/lib/switch/index.ts +1 -0
- package/src/lib/switch/sng-switch.ts +137 -0
- package/src/lib/tabs/cn.ts +6 -0
- package/src/lib/tabs/index.ts +4 -0
- package/src/lib/tabs/sng-tabs-content.ts +66 -0
- package/src/lib/tabs/sng-tabs-list.ts +55 -0
- package/src/lib/tabs/sng-tabs-trigger.ts +86 -0
- package/src/lib/tabs/sng-tabs.ts +83 -0
- package/src/lib/toast/cn.ts +6 -0
- package/src/lib/toast/index.ts +3 -0
- package/src/lib/toast/sng-toast.service.ts +258 -0
- package/src/lib/toast/sng-toast.ts +101 -0
- package/src/lib/toast/sng-toaster.ts +67 -0
- package/src/lib/toggle/cn.ts +6 -0
- package/src/lib/toggle/index.ts +6 -0
- package/src/lib/toggle/sng-toggle-group-item.ts +89 -0
- package/src/lib/toggle/sng-toggle-group.ts +85 -0
- package/src/lib/toggle/sng-toggle.ts +78 -0
- package/src/lib/toggle-group/index.ts +6 -0
- package/src/lib/tooltip/cn.ts +6 -0
- package/src/lib/tooltip/index.ts +5 -0
- package/src/lib/tooltip/sng-tooltip-content.ts +64 -0
- package/src/lib/tooltip/sng-tooltip.ts +216 -0
- package/src/public-api.ts +207 -0
- package/tsconfig.json +24 -0
- package/tsconfig.lib.json +17 -0
- package/tsconfig.lib.prod.json +11 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Core row model for sng-table-core
|
|
3
|
+
*
|
|
4
|
+
* The core row model is the foundation of all row processing.
|
|
5
|
+
* It takes raw data and converts it into Row instances.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Row, RowModel, Table, RowModelFn } from '../core/types';
|
|
9
|
+
import { buildRowsFromData, applyFeaturesToRow } from '../core/create-row';
|
|
10
|
+
import { memo, flattenBy } from '../core/utils';
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// CORE ROW MODEL FACTORY
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Factory function to create the core row model
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const table = createTable(() => ({
|
|
22
|
+
* data: myData,
|
|
23
|
+
* columns: myColumns,
|
|
24
|
+
* getCoreRowModel: getCoreRowModel(),
|
|
25
|
+
* }));
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function getCoreRowModel<TData>(): RowModelFn<TData> {
|
|
29
|
+
return (table: Table<TData>) => {
|
|
30
|
+
return memo(
|
|
31
|
+
// Dependencies - recompute when these change
|
|
32
|
+
() => [table.options.data],
|
|
33
|
+
|
|
34
|
+
// Compute function
|
|
35
|
+
() => buildCoreRowModel(table),
|
|
36
|
+
|
|
37
|
+
// Options
|
|
38
|
+
{
|
|
39
|
+
debug: table.options.debugRows,
|
|
40
|
+
debugLabel: 'getCoreRowModel',
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ============================================================================
|
|
47
|
+
// CORE ROW MODEL BUILDER
|
|
48
|
+
// ============================================================================
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Build the core row model from data
|
|
52
|
+
*/
|
|
53
|
+
function buildCoreRowModel<TData>(table: Table<TData>): RowModel<TData> {
|
|
54
|
+
const { data } = table.options;
|
|
55
|
+
|
|
56
|
+
// Build rows from data (without features applied yet)
|
|
57
|
+
const rows = buildRowsFromData(table, data);
|
|
58
|
+
|
|
59
|
+
// Flatten all rows (including sub-rows)
|
|
60
|
+
const flatRows = flattenBy(rows, (row) =>
|
|
61
|
+
row.subRows.length ? row.subRows : undefined
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Build rows by ID lookup
|
|
65
|
+
const rowsById: Record<string, Row<TData>> = {};
|
|
66
|
+
for (const row of flatRows) {
|
|
67
|
+
rowsById[row.id] = row;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Apply features to all rows AFTER they're all built
|
|
71
|
+
// This prevents circular dependency during hierarchical row building
|
|
72
|
+
for (const row of flatRows) {
|
|
73
|
+
applyFeaturesToRow(row, table);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
rows,
|
|
78
|
+
flatRows,
|
|
79
|
+
rowsById,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// HELPER FUNCTIONS
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Create an empty row model
|
|
89
|
+
*/
|
|
90
|
+
export function createEmptyRowModel<TData>(): RowModel<TData> {
|
|
91
|
+
return {
|
|
92
|
+
rows: [],
|
|
93
|
+
flatRows: [],
|
|
94
|
+
rowsById: {},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Filter rows while maintaining hierarchy
|
|
100
|
+
*/
|
|
101
|
+
export function filterRows<TData>(
|
|
102
|
+
rows: Row<TData>[],
|
|
103
|
+
filterFn: (row: Row<TData>) => boolean,
|
|
104
|
+
options?: {
|
|
105
|
+
filterFromLeafRows?: boolean;
|
|
106
|
+
maxDepth?: number;
|
|
107
|
+
}
|
|
108
|
+
): Row<TData>[] {
|
|
109
|
+
const { filterFromLeafRows = false, maxDepth = 100 } = options ?? {};
|
|
110
|
+
|
|
111
|
+
if (filterFromLeafRows) {
|
|
112
|
+
return filterRowsFromLeaves(rows, filterFn, maxDepth);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return filterRowsFromRoot(rows, filterFn, maxDepth);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Filter rows starting from root (parent-first)
|
|
120
|
+
* If parent matches, include all children
|
|
121
|
+
*/
|
|
122
|
+
function filterRowsFromRoot<TData>(
|
|
123
|
+
rows: Row<TData>[],
|
|
124
|
+
filterFn: (row: Row<TData>) => boolean,
|
|
125
|
+
maxDepth: number,
|
|
126
|
+
currentDepth = 0
|
|
127
|
+
): Row<TData>[] {
|
|
128
|
+
const result: Row<TData>[] = [];
|
|
129
|
+
|
|
130
|
+
for (const row of rows) {
|
|
131
|
+
const passes = filterFn(row);
|
|
132
|
+
|
|
133
|
+
if (passes) {
|
|
134
|
+
// Parent matches - include it with all sub-rows as-is
|
|
135
|
+
result.push(row);
|
|
136
|
+
} else if (currentDepth < maxDepth && row.subRows.length) {
|
|
137
|
+
// Parent doesn't match, but check children
|
|
138
|
+
const filteredSubRows = filterRowsFromRoot(
|
|
139
|
+
row.subRows,
|
|
140
|
+
filterFn,
|
|
141
|
+
maxDepth,
|
|
142
|
+
currentDepth + 1
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
if (filteredSubRows.length) {
|
|
146
|
+
// Some children match - create a copy of row with filtered children
|
|
147
|
+
result.push({
|
|
148
|
+
...row,
|
|
149
|
+
subRows: filteredSubRows,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Filter rows starting from leaves (child-first)
|
|
160
|
+
* Include parent if any child matches
|
|
161
|
+
*/
|
|
162
|
+
function filterRowsFromLeaves<TData>(
|
|
163
|
+
rows: Row<TData>[],
|
|
164
|
+
filterFn: (row: Row<TData>) => boolean,
|
|
165
|
+
maxDepth: number,
|
|
166
|
+
currentDepth = 0
|
|
167
|
+
): Row<TData>[] {
|
|
168
|
+
const result: Row<TData>[] = [];
|
|
169
|
+
|
|
170
|
+
for (const row of rows) {
|
|
171
|
+
let filteredSubRows: Row<TData>[] = [];
|
|
172
|
+
|
|
173
|
+
if (currentDepth < maxDepth && row.subRows.length) {
|
|
174
|
+
// First, filter children
|
|
175
|
+
filteredSubRows = filterRowsFromLeaves(
|
|
176
|
+
row.subRows,
|
|
177
|
+
filterFn,
|
|
178
|
+
maxDepth,
|
|
179
|
+
currentDepth + 1
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Check if this row passes or has passing children
|
|
184
|
+
const passes = filterFn(row);
|
|
185
|
+
|
|
186
|
+
if (passes || filteredSubRows.length) {
|
|
187
|
+
result.push({
|
|
188
|
+
...row,
|
|
189
|
+
subRows: filteredSubRows,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Sort rows while maintaining hierarchy
|
|
199
|
+
*/
|
|
200
|
+
export function sortRows<TData>(
|
|
201
|
+
rows: Row<TData>[],
|
|
202
|
+
sortFn: (a: Row<TData>, b: Row<TData>) => number
|
|
203
|
+
): Row<TData>[] {
|
|
204
|
+
// Sort this level
|
|
205
|
+
const sortedRows = [...rows].sort(sortFn);
|
|
206
|
+
|
|
207
|
+
// Recursively sort sub-rows
|
|
208
|
+
return sortedRows.map((row) => {
|
|
209
|
+
if (row.subRows.length) {
|
|
210
|
+
return {
|
|
211
|
+
...row,
|
|
212
|
+
subRows: sortRows(row.subRows, sortFn),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return row;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Paginate rows (flat - doesn't handle hierarchy specially)
|
|
221
|
+
*/
|
|
222
|
+
export function paginateRows<TData>(
|
|
223
|
+
rows: Row<TData>[],
|
|
224
|
+
pageIndex: number,
|
|
225
|
+
pageSize: number
|
|
226
|
+
): Row<TData>[] {
|
|
227
|
+
const start = pageIndex * pageSize;
|
|
228
|
+
const end = start + pageSize;
|
|
229
|
+
return rows.slice(start, end);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Expand rows - include sub-rows of expanded rows in the flat list
|
|
234
|
+
*/
|
|
235
|
+
export function expandRows<TData>(
|
|
236
|
+
rows: Row<TData>[],
|
|
237
|
+
isExpanded: (row: Row<TData>) => boolean
|
|
238
|
+
): Row<TData>[] {
|
|
239
|
+
const result: Row<TData>[] = [];
|
|
240
|
+
|
|
241
|
+
function addRow(row: Row<TData>) {
|
|
242
|
+
result.push(row);
|
|
243
|
+
|
|
244
|
+
if (isExpanded(row) && row.subRows.length) {
|
|
245
|
+
for (const subRow of row.subRows) {
|
|
246
|
+
addRow(subRow);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
for (const row of rows) {
|
|
252
|
+
addRow(row);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Expanded row model for sng-table-core
|
|
3
|
+
*
|
|
4
|
+
* Flattens expanded rows into a single list for rendering.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Row, RowModel, Table, RowModelFn, ExpandedState } from '../core/types';
|
|
8
|
+
import { memo } from '../core/utils';
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// EXPANDED ROW MODEL FACTORY
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Factory function to create the expanded row model
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const table = createTable(() => ({
|
|
20
|
+
* data: myData,
|
|
21
|
+
* columns: myColumns,
|
|
22
|
+
* getCoreRowModel: getCoreRowModel(),
|
|
23
|
+
* getExpandedRowModel: getExpandedRowModel(),
|
|
24
|
+
* enableExpanding: true,
|
|
25
|
+
* }));
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function getExpandedRowModel<TData>(): RowModelFn<TData> {
|
|
29
|
+
return (table: Table<TData>) => {
|
|
30
|
+
return memo(
|
|
31
|
+
// Dependencies
|
|
32
|
+
() => [
|
|
33
|
+
table.getState().expanded,
|
|
34
|
+
getPreExpandedRowModel(table),
|
|
35
|
+
],
|
|
36
|
+
|
|
37
|
+
// Compute function
|
|
38
|
+
() => {
|
|
39
|
+
const { expanded } = table.getState();
|
|
40
|
+
const preExpandedRowModel = getPreExpandedRowModel(table);
|
|
41
|
+
|
|
42
|
+
// If no expansion state, return pre-expanded model
|
|
43
|
+
if (!expanded || (typeof expanded === 'object' && !Object.keys(expanded).length)) {
|
|
44
|
+
return preExpandedRowModel;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return buildExpandedRowModel(table, preExpandedRowModel, expanded);
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
// Options
|
|
51
|
+
{
|
|
52
|
+
debug: table.options.debugRows,
|
|
53
|
+
debugLabel: 'getExpandedRowModel',
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// EXPANDED ROW MODEL BUILDER
|
|
61
|
+
// ============================================================================
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Build the expanded row model
|
|
65
|
+
*/
|
|
66
|
+
function buildExpandedRowModel<TData>(
|
|
67
|
+
table: Table<TData>,
|
|
68
|
+
rowModel: RowModel<TData>,
|
|
69
|
+
expanded: ExpandedState
|
|
70
|
+
): RowModel<TData> {
|
|
71
|
+
const { paginateExpandedRows = true } = table.options;
|
|
72
|
+
|
|
73
|
+
// Expand rows
|
|
74
|
+
const expandedRows = expandRows(rowModel.rows, expanded, paginateExpandedRows);
|
|
75
|
+
|
|
76
|
+
// Flatten expanded rows
|
|
77
|
+
const flatRows = flattenExpandedRows(expandedRows, expanded);
|
|
78
|
+
|
|
79
|
+
// Build rows by ID lookup
|
|
80
|
+
const rowsById: Record<string, Row<TData>> = {};
|
|
81
|
+
for (const row of flatRows) {
|
|
82
|
+
rowsById[row.id] = row;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
rows: expandedRows,
|
|
87
|
+
flatRows,
|
|
88
|
+
rowsById,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the row model before expansion (sorted or filtered or core)
|
|
94
|
+
*/
|
|
95
|
+
function getPreExpandedRowModel<TData>(table: Table<TData>): RowModel<TData> {
|
|
96
|
+
// Pipeline: core -> filtered -> sorted -> expanded -> paginated
|
|
97
|
+
// We want the model just before expanded
|
|
98
|
+
|
|
99
|
+
// Try sorted first
|
|
100
|
+
if (table.getSortedRowModel) {
|
|
101
|
+
return table.getSortedRowModel();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Then filtered
|
|
105
|
+
if (table.getFilteredRowModel) {
|
|
106
|
+
return table.getFilteredRowModel();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Finally core
|
|
110
|
+
return table.getCoreRowModel();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Expand rows based on expanded state
|
|
115
|
+
*/
|
|
116
|
+
function expandRows<TData>(
|
|
117
|
+
rows: Row<TData>[],
|
|
118
|
+
expanded: ExpandedState,
|
|
119
|
+
paginateExpandedRows: boolean
|
|
120
|
+
): Row<TData>[] {
|
|
121
|
+
if (!paginateExpandedRows) {
|
|
122
|
+
// If not paginating expanded rows, just return as-is
|
|
123
|
+
// The pagination will handle expansion
|
|
124
|
+
return rows;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Otherwise, we need to include sub-rows in the row list for pagination
|
|
128
|
+
const result: Row<TData>[] = [];
|
|
129
|
+
|
|
130
|
+
function processRow(row: Row<TData>) {
|
|
131
|
+
result.push(row);
|
|
132
|
+
|
|
133
|
+
const isExpanded = expanded === true || (expanded as Record<string, boolean>)[row.id];
|
|
134
|
+
|
|
135
|
+
if (isExpanded && row.subRows.length) {
|
|
136
|
+
for (const subRow of row.subRows) {
|
|
137
|
+
processRow(subRow);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
for (const row of rows) {
|
|
143
|
+
processRow(row);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Flatten expanded rows
|
|
151
|
+
*/
|
|
152
|
+
function flattenExpandedRows<TData>(
|
|
153
|
+
rows: Row<TData>[],
|
|
154
|
+
expanded: ExpandedState
|
|
155
|
+
): Row<TData>[] {
|
|
156
|
+
const result: Row<TData>[] = [];
|
|
157
|
+
|
|
158
|
+
function processRow(row: Row<TData>) {
|
|
159
|
+
result.push(row);
|
|
160
|
+
|
|
161
|
+
const isExpanded = expanded === true || (expanded as Record<string, boolean>)[row.id];
|
|
162
|
+
|
|
163
|
+
if (isExpanded && row.subRows.length) {
|
|
164
|
+
for (const subRow of row.subRows) {
|
|
165
|
+
processRow(subRow);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for (const row of rows) {
|
|
171
|
+
processRow(row);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return result;
|
|
175
|
+
}
|