@cratis/components 0.1.15 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/PivotViewer/PivotViewer.css +32 -19
- package/dist/cjs/PivotViewer/PivotViewer.js +44 -8
- package/dist/cjs/PivotViewer/PivotViewer.js.map +1 -1
- package/dist/cjs/PivotViewer/components/PivotCanvas.js +32 -51
- package/dist/cjs/PivotViewer/components/PivotCanvas.js.map +1 -1
- package/dist/cjs/PivotViewer/components/PivotViewerMain.js +4 -2
- package/dist/cjs/PivotViewer/components/PivotViewerMain.js.map +1 -1
- package/dist/cjs/PivotViewer/components/Toolbar.js +1 -1
- package/dist/cjs/PivotViewer/components/Toolbar.js.map +1 -1
- package/dist/cjs/PivotViewer/components/pivot/animation.js +4 -3
- package/dist/cjs/PivotViewer/components/pivot/animation.js.map +1 -1
- package/dist/cjs/PivotViewer/components/pivot/groups.js +151 -0
- package/dist/cjs/PivotViewer/components/pivot/groups.js.map +1 -0
- package/dist/cjs/PivotViewer/components/pivot/sprites.js +1 -15
- package/dist/cjs/PivotViewer/components/pivot/sprites.js.map +1 -1
- package/dist/cjs/PivotViewer/components/pivot/visibility.js +50 -27
- package/dist/cjs/PivotViewer/components/pivot/visibility.js.map +1 -1
- package/dist/cjs/PivotViewer/engine/layout.js +11 -7
- package/dist/cjs/PivotViewer/engine/layout.js.map +1 -1
- package/dist/cjs/PivotViewer/hooks/useCurrentFilters.js.map +1 -1
- package/dist/cjs/PivotViewer/hooks/usePanning.js +8 -4
- package/dist/cjs/PivotViewer/hooks/usePanning.js.map +1 -1
- package/dist/cjs/PivotViewer/hooks/usePivotEngine.js +1 -31
- package/dist/cjs/PivotViewer/hooks/usePivotEngine.js.map +1 -1
- package/dist/cjs/PivotViewer/hooks/useViewModeScrollHandling.js +4 -3
- package/dist/cjs/PivotViewer/hooks/useViewModeScrollHandling.js.map +1 -1
- package/dist/cjs/PivotViewer/types.js.map +1 -1
- package/dist/cjs/PivotViewer/utils/animations.js +11 -19
- package/dist/cjs/PivotViewer/utils/animations.js.map +1 -1
- package/dist/cjs/PivotViewer/utils/cardPosition.js +0 -3
- package/dist/cjs/PivotViewer/utils/cardPosition.js.map +1 -1
- package/dist/cjs/PivotViewer/utils/constants.js +2 -2
- package/dist/cjs/PivotViewer/utils/constants.js.map +1 -1
- package/dist/esm/PivotViewer/PivotViewer.css +32 -19
- package/dist/esm/PivotViewer/PivotViewer.d.ts +1 -1
- package/dist/esm/PivotViewer/PivotViewer.d.ts.map +1 -1
- package/dist/esm/PivotViewer/PivotViewer.js +45 -9
- package/dist/esm/PivotViewer/PivotViewer.js.map +1 -1
- package/dist/esm/PivotViewer/PivotViewer.stories.d.ts.map +1 -1
- package/dist/esm/PivotViewer/PivotViewer.stories.js +5 -2
- package/dist/esm/PivotViewer/PivotViewer.stories.js.map +1 -1
- package/dist/esm/PivotViewer/components/PivotCanvas.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/PivotCanvas.js +33 -52
- package/dist/esm/PivotViewer/components/PivotCanvas.js.map +1 -1
- package/dist/esm/PivotViewer/components/PivotViewerMain.d.ts +2 -1
- package/dist/esm/PivotViewer/components/PivotViewerMain.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/PivotViewerMain.js +4 -2
- package/dist/esm/PivotViewer/components/PivotViewerMain.js.map +1 -1
- package/dist/esm/PivotViewer/components/Toolbar.js +1 -1
- package/dist/esm/PivotViewer/components/Toolbar.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/animation.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/animation.js +4 -3
- package/dist/esm/PivotViewer/components/pivot/animation.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/groups.d.ts +6 -0
- package/dist/esm/PivotViewer/components/pivot/groups.d.ts.map +1 -0
- package/dist/esm/PivotViewer/components/pivot/groups.js +129 -0
- package/dist/esm/PivotViewer/components/pivot/groups.js.map +1 -0
- package/dist/esm/PivotViewer/components/pivot/sprites.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/sprites.js +2 -15
- package/dist/esm/PivotViewer/components/pivot/sprites.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/visibility.d.ts +4 -0
- package/dist/esm/PivotViewer/components/pivot/visibility.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/visibility.js +50 -27
- package/dist/esm/PivotViewer/components/pivot/visibility.js.map +1 -1
- package/dist/esm/PivotViewer/engine/layout.js +11 -7
- package/dist/esm/PivotViewer/engine/layout.js.map +1 -1
- package/dist/esm/PivotViewer/engine/pivot.worker.d.ts.map +1 -1
- package/dist/esm/PivotViewer/engine/pivot.worker.js +0 -8
- package/dist/esm/PivotViewer/engine/pivot.worker.js.map +1 -1
- package/dist/esm/PivotViewer/engine/types.d.ts +1 -0
- package/dist/esm/PivotViewer/engine/types.d.ts.map +1 -1
- package/dist/esm/PivotViewer/hooks/useCurrentFilters.js.map +1 -1
- package/dist/esm/PivotViewer/hooks/useFilteredData.d.ts +1 -1
- package/dist/esm/PivotViewer/hooks/useFilteredData.js +4 -4
- package/dist/esm/PivotViewer/hooks/useFilteredData.js.map +1 -1
- package/dist/esm/PivotViewer/hooks/usePanning.d.ts.map +1 -1
- package/dist/esm/PivotViewer/hooks/usePanning.js +8 -4
- package/dist/esm/PivotViewer/hooks/usePanning.js.map +1 -1
- package/dist/esm/PivotViewer/hooks/usePivotEngine.d.ts.map +1 -1
- package/dist/esm/PivotViewer/hooks/usePivotEngine.js +1 -31
- package/dist/esm/PivotViewer/hooks/usePivotEngine.js.map +1 -1
- package/dist/esm/PivotViewer/hooks/useViewModeScrollHandling.d.ts.map +1 -1
- package/dist/esm/PivotViewer/hooks/useViewModeScrollHandling.js +4 -3
- package/dist/esm/PivotViewer/hooks/useViewModeScrollHandling.js.map +1 -1
- package/dist/esm/PivotViewer/types.d.ts +16 -0
- package/dist/esm/PivotViewer/types.d.ts.map +1 -1
- package/dist/esm/PivotViewer/types.js.map +1 -1
- package/dist/esm/PivotViewer/utils/animations.js +11 -19
- package/dist/esm/PivotViewer/utils/animations.js.map +1 -1
- package/dist/esm/PivotViewer/utils/cardPosition.js +1 -4
- package/dist/esm/PivotViewer/utils/cardPosition.js.map +1 -1
- package/dist/esm/PivotViewer/utils/constants.d.ts +4 -4
- package/dist/esm/PivotViewer/utils/constants.d.ts.map +1 -1
- package/dist/esm/PivotViewer/utils/constants.js +2 -2
- package/dist/esm/PivotViewer/utils/constants.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/cjs/PivotViewer/components/pivot/buckets.js +0 -124
- package/dist/cjs/PivotViewer/components/pivot/buckets.js.map +0 -1
- package/dist/esm/PivotViewer/components/pivot/buckets.d.ts +0 -6
- package/dist/esm/PivotViewer/components/pivot/buckets.d.ts.map +0 -1
- package/dist/esm/PivotViewer/components/pivot/buckets.js +0 -102
- package/dist/esm/PivotViewer/components/pivot/buckets.js.map +0 -1
|
@@ -4,12 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
.pivot-viewer {
|
|
6
6
|
position: relative;
|
|
7
|
-
|
|
7
|
+
/* CRITICAL: Don't set explicit height - let parent control it via container constraints */
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
min-height: 0; /* allow children to size without forcing overflow */
|
|
11
|
+
max-height: 100%; /* respect parent height if set */
|
|
8
12
|
width: 100%;
|
|
9
|
-
background
|
|
13
|
+
/* Keep root neutral; move visual background to the viewport so it never exceeds the container */
|
|
14
|
+
background: var(--surface-ground);
|
|
10
15
|
color: var(--text-color);
|
|
11
16
|
overflow: hidden;
|
|
12
17
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
18
|
+
/* Ensure we shrink within flex parent */
|
|
19
|
+
flex: 1 1 0%;
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
.pv-filter-panel {
|
|
@@ -276,7 +283,8 @@
|
|
|
276
283
|
display: flex;
|
|
277
284
|
flex-direction: column;
|
|
278
285
|
min-height: 0;
|
|
279
|
-
|
|
286
|
+
flex: 1 1 auto; /* grow within pivot-viewer */
|
|
287
|
+
height: auto;
|
|
280
288
|
padding-left: 0;
|
|
281
289
|
overflow: hidden;
|
|
282
290
|
}
|
|
@@ -571,7 +579,7 @@
|
|
|
571
579
|
cursor: grabbing;
|
|
572
580
|
}
|
|
573
581
|
|
|
574
|
-
/* Groups wrapper for
|
|
582
|
+
/* Groups wrapper for grouped mode with axis labels */
|
|
575
583
|
.pv-groups-wrapper {
|
|
576
584
|
display: flex;
|
|
577
585
|
flex-direction: column;
|
|
@@ -581,7 +589,12 @@
|
|
|
581
589
|
background: transparent;
|
|
582
590
|
}
|
|
583
591
|
|
|
584
|
-
|
|
592
|
+
/* Visual background belongs to the scrollable viewport area so it respects container bounds */
|
|
593
|
+
.pv-viewport {
|
|
594
|
+
background: radial-gradient(circle at 25% 20%, var(--primary-500), var(--surface-ground));
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.pv-groups-grouped {
|
|
585
598
|
flex: 1;
|
|
586
599
|
padding-bottom: 0;
|
|
587
600
|
}
|
|
@@ -599,21 +612,21 @@
|
|
|
599
612
|
transition: background 180ms ease;
|
|
600
613
|
}
|
|
601
614
|
|
|
602
|
-
/*
|
|
603
|
-
.pv-group-
|
|
615
|
+
/* Grouped mode groups need to align cards to bottom and extend full height */
|
|
616
|
+
.pv-group-grouped {
|
|
604
617
|
justify-content: flex-end;
|
|
605
618
|
position: relative;
|
|
606
619
|
min-height: 100%; /* Ensure full height for hover */
|
|
607
620
|
width: var(--column-width); /* Fixed width even when empty */
|
|
608
621
|
}
|
|
609
622
|
|
|
610
|
-
/* Zebra striping for
|
|
611
|
-
.pv-group-
|
|
623
|
+
/* Zebra striping for grouped mode - every other group gets a lighter background */
|
|
624
|
+
.pv-group-grouped:nth-child(even)::before {
|
|
612
625
|
background: rgba(255, 255, 255, 0.03);
|
|
613
626
|
}
|
|
614
627
|
|
|
615
628
|
/* Full-height hover highlight that extends to the top */
|
|
616
|
-
.pv-group-
|
|
629
|
+
.pv-group-grouped::before {
|
|
617
630
|
content: '';
|
|
618
631
|
position: absolute;
|
|
619
632
|
inset: 0;
|
|
@@ -624,14 +637,14 @@
|
|
|
624
637
|
z-index: 0;
|
|
625
638
|
}
|
|
626
639
|
|
|
627
|
-
.pv-group-
|
|
628
|
-
.pv-group-
|
|
640
|
+
.pv-group-grouped:hover::before,
|
|
641
|
+
.pv-group-grouped.highlighted::before {
|
|
629
642
|
background: var(--surface-hover);
|
|
630
643
|
}
|
|
631
644
|
|
|
632
645
|
/* Zebra striping hover state - combine with stripe background */
|
|
633
|
-
.pv-group-
|
|
634
|
-
.pv-group-
|
|
646
|
+
.pv-group-grouped:nth-child(even):hover::before,
|
|
647
|
+
.pv-group-grouped:nth-child(even).highlighted::before {
|
|
635
648
|
background: var(--surface-hover);
|
|
636
649
|
}
|
|
637
650
|
|
|
@@ -667,25 +680,25 @@
|
|
|
667
680
|
width: var(--column-width, auto);
|
|
668
681
|
}
|
|
669
682
|
|
|
670
|
-
.pv-cards-
|
|
683
|
+
.pv-cards-grouped {
|
|
671
684
|
/* Grid fills left-to-right with fixed columns */
|
|
672
685
|
grid-template-columns: repeat(var(--cards-per-row, 5), 1fr);
|
|
673
686
|
grid-auto-flow: row;
|
|
674
687
|
width: var(--column-width);
|
|
675
688
|
}
|
|
676
689
|
|
|
677
|
-
.pv-cards-
|
|
690
|
+
.pv-cards-grouped .pv-card {
|
|
678
691
|
/* Cards maintain their direction */
|
|
679
692
|
}
|
|
680
693
|
|
|
681
|
-
/* Empty placeholder cells in
|
|
694
|
+
/* Empty placeholder cells in grouped grid */
|
|
682
695
|
.pv-card-placeholder {
|
|
683
696
|
visibility: hidden;
|
|
684
697
|
width: var(--card-width);
|
|
685
698
|
height: var(--card-height);
|
|
686
699
|
}
|
|
687
700
|
|
|
688
|
-
/* Axis labels at bottom of
|
|
701
|
+
/* Axis labels at bottom of grouped view */
|
|
689
702
|
.pv-axis-labels {
|
|
690
703
|
display: flex;
|
|
691
704
|
align-items: stretch;
|
|
@@ -715,7 +728,7 @@
|
|
|
715
728
|
font: inherit;
|
|
716
729
|
}
|
|
717
730
|
|
|
718
|
-
/* Zebra striping for axis labels - match the
|
|
731
|
+
/* Zebra striping for axis labels - match the grouped columns */
|
|
719
732
|
.pv-axis-label:nth-child(even) {
|
|
720
733
|
background: rgba(255, 255, 255, 0.03);
|
|
721
734
|
}
|
|
@@ -25,7 +25,7 @@ var useAnimationModeTracking = require('./hooks/useAnimationModeTracking.js');
|
|
|
25
25
|
var useViewModeScrollHandling = require('./hooks/useViewModeScrollHandling.js');
|
|
26
26
|
var useContainerDimensions = require('./hooks/useContainerDimensions.js');
|
|
27
27
|
|
|
28
|
-
function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRenderer, getItemId, searchFields, className, emptyContent, isLoading = false, }) {
|
|
28
|
+
function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRenderer, detailRenderer, getItemId, searchFields, className, emptyContent, isLoading = false, colors, }) {
|
|
29
29
|
const containerRef = React.useRef(null);
|
|
30
30
|
const filterButtonRef = React.useRef(null);
|
|
31
31
|
const axisLabelsRef = React.useRef(null);
|
|
@@ -72,9 +72,17 @@ function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRende
|
|
|
72
72
|
if (!ready)
|
|
73
73
|
return;
|
|
74
74
|
engineApplyFilters(currentFilters).then((result) => {
|
|
75
|
+
if (result.visibleIds.length === 0 && currentFilters.length === 0 && data.length > 0) {
|
|
76
|
+
const fallbackIds = new Uint32Array(data.length);
|
|
77
|
+
for (let i = 0; i < data.length; i++) {
|
|
78
|
+
fallbackIds[i] = i;
|
|
79
|
+
}
|
|
80
|
+
setVisibleIds(fallbackIds);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
75
83
|
setVisibleIds(result.visibleIds);
|
|
76
84
|
});
|
|
77
|
-
}, [ready, currentFilters, engineApplyFilters]);
|
|
85
|
+
}, [ready, currentFilters, engineApplyFilters, data.length]);
|
|
78
86
|
const lastGroupingRequest = React.useRef(null);
|
|
79
87
|
React.useEffect(() => {
|
|
80
88
|
if (!ready || visibleIds.length === 0) {
|
|
@@ -115,13 +123,10 @@ function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRende
|
|
|
115
123
|
lastRequest.viewMode === viewMode &&
|
|
116
124
|
lastRequest.groupBy?.field === currentGroupBy.field &&
|
|
117
125
|
lastRequest.visibleIds === visibleIds) {
|
|
118
|
-
console.log('[PivotViewer] Skipping duplicate grouping request');
|
|
119
126
|
return;
|
|
120
127
|
}
|
|
121
128
|
lastGroupingRequest.current = { viewMode, groupBy: currentGroupBy, visibleIds };
|
|
122
|
-
console.log('[PivotViewer] Computing grouping for', visibleIds.length, 'items');
|
|
123
129
|
computeGrouping(visibleIds, currentGroupBy).then((result) => {
|
|
124
|
-
console.log('[PivotViewer] Grouping result received:', result.groups.length, 'groups');
|
|
125
130
|
setGrouping(result);
|
|
126
131
|
});
|
|
127
132
|
}, [ready, visibleIds, currentGroupBy, viewMode, computeGrouping, sortIds, activeDimensionKey]);
|
|
@@ -137,7 +142,6 @@ function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRende
|
|
|
137
142
|
cardWidth,
|
|
138
143
|
cardHeight,
|
|
139
144
|
cardsPerColumn: constants.CARDS_PER_COLUMN,
|
|
140
|
-
groupSpacing: constants.GROUP_SPACING,
|
|
141
145
|
containerWidth,
|
|
142
146
|
containerHeight,
|
|
143
147
|
});
|
|
@@ -207,11 +211,43 @@ function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRende
|
|
|
207
211
|
'pivot-viewer',
|
|
208
212
|
className,
|
|
209
213
|
hasFilters ? (filtersOpen ? 'filters-open' : 'filters-closed') : 'no-filters',
|
|
210
|
-
viewMode === 'grouped' ? '
|
|
214
|
+
viewMode === 'grouped' ? 'grouped-mode' : 'collection-mode',
|
|
211
215
|
]
|
|
212
216
|
.filter(Boolean)
|
|
213
217
|
.join(' ');
|
|
214
|
-
|
|
218
|
+
const cssVariables = React.useMemo(() => {
|
|
219
|
+
const vars = {};
|
|
220
|
+
if (!colors)
|
|
221
|
+
return vars;
|
|
222
|
+
if (colors.primaryColor)
|
|
223
|
+
vars['--primary-color'] = colors.primaryColor;
|
|
224
|
+
if (colors.primaryColorText)
|
|
225
|
+
vars['--primary-color-text'] = colors.primaryColorText;
|
|
226
|
+
if (colors.primary500)
|
|
227
|
+
vars['--primary-500'] = colors.primary500;
|
|
228
|
+
if (colors.surfaceGround)
|
|
229
|
+
vars['--surface-ground'] = colors.surfaceGround;
|
|
230
|
+
if (colors.surfaceCard)
|
|
231
|
+
vars['--surface-card'] = colors.surfaceCard;
|
|
232
|
+
if (colors.surfaceSection)
|
|
233
|
+
vars['--surface-section'] = colors.surfaceSection;
|
|
234
|
+
if (colors.surfaceOverlay)
|
|
235
|
+
vars['--surface-overlay'] = colors.surfaceOverlay;
|
|
236
|
+
if (colors.surfaceBorder)
|
|
237
|
+
vars['--surface-border'] = colors.surfaceBorder;
|
|
238
|
+
if (colors.textColor)
|
|
239
|
+
vars['--text-color'] = colors.textColor;
|
|
240
|
+
if (colors.textColorSecondary)
|
|
241
|
+
vars['--text-color-secondary'] = colors.textColorSecondary;
|
|
242
|
+
if (colors.highlightBg)
|
|
243
|
+
vars['--highlight-bg'] = colors.highlightBg;
|
|
244
|
+
if (colors.maskbg)
|
|
245
|
+
vars['--maskbg'] = colors.maskbg;
|
|
246
|
+
if (colors.focusRing)
|
|
247
|
+
vars['--focus-ring'] = colors.focusRing;
|
|
248
|
+
return vars;
|
|
249
|
+
}, [colors]);
|
|
250
|
+
return (jsxRuntime.jsxs("div", { className: viewerClassName, style: cssVariables, children: [jsxRuntime.jsx(FilterPanelContainer.FilterPanelContainer, { isOpen: filtersOpen && hasFilters, search: search, filterState: filterState, rangeFilterState: rangeFilterState, expandedFilterKey: expandedFilterKey, filterOptions: filterOptions, anchorRef: filterButtonRef, onClose: () => setFiltersOpen(false), onSearchChange: setSearch, onFilterToggle: handleToggleFilter, onFilterClear: handleClearFilter, onRangeChange: handleRangeChange, onExpandedFilterChange: setExpandedFilterKey }), jsxRuntime.jsxs("main", { className: "pv-main", children: [jsxRuntime.jsx(ToolbarContainer.ToolbarContainer, { hasFilters: hasFilters, filtersOpen: filtersOpen, filteredCount: visibleIds.length, viewMode: viewMode, zoomLevel: zoomLevel, activeDimensionKey: activeDimensionKey, dimensions: dimensions, activeFilterCount: activeFilterCount, onFiltersToggle: () => setFiltersOpen((prev) => !prev), onViewModeChange: setViewMode, onZoomIn: handleZoomIn, onZoomOut: handleZoomOut, onZoomSlider: handleZoomSlider, onDimensionChange: setActiveDimensionKey, filterButtonRef: filterButtonRef }), jsxRuntime.jsx(PivotViewerMain.PivotViewerMain, { data: data, ready: ready, isLoading: isLoading, visibleIds: visibleIds, grouping: grouping, layout: layout$1, cardWidth: cardWidth, cardHeight: cardHeight, zoomLevel: zoomLevel, scrollPosition: scrollPosition, containerDimensions: containerDimensions, selectedItem: selectedItem, hoveredGroupIndex: hoveredGroupIndex, isZooming: isZooming, viewMode: viewMode, cardRenderer: cardRenderer, detailRenderer: detailRenderer, resolveId: resolveId, emptyContent: emptyContent, dimensionFilter: dimensionFilter, onCardClick: handleCardClick, onPanStart: handlePanStart, onPanMove: handlePanMove, onPanEnd: handlePanEnd, onGroupHover: setHoveredGroupIndex, onAxisLabelClick: handleAxisLabelClick, onCloseDetail: closeDetail, containerRef: containerRef, axisLabelsRef: axisLabelsRef, spacerRef: spacerRef })] })] }));
|
|
215
251
|
}
|
|
216
252
|
|
|
217
253
|
exports.PivotViewer = PivotViewer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PivotViewer.js","sources":["../../../PivotViewer/PivotViewer.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { PivotViewerProps } from './types';\nimport type { GroupingResult } from './engine/types';\nimport { usePivotEngine } from './hooks/usePivotEngine';\nimport { computeLayout } from './engine/layout';\nimport { useFilterState } from './hooks/useFilterState';\nimport { useDimensionState } from './hooks/useDimensionState';\nimport { useZoomState } from './hooks/useZoomState';\nimport { BASE_CARD_WIDTH, BASE_CARD_HEIGHT, CARDS_PER_COLUMN, GROUP_SPACING } from './constants';\nimport './PivotViewer.css';\nimport { PivotViewerMain } from './components/PivotViewerMain';\nimport { FilterPanelContainer } from './components/FilterPanelContainer';\nimport { ToolbarContainer } from './components/ToolbarContainer';\nimport { usePanning, useWheelZoom, useFilterOptions } from './hooks';\nimport { useContainerDimensions } from './hooks/useContainerDimensions';\nimport type { ViewMode } from './components/Toolbar';\nimport { useFieldExtractors } from './hooks/useFieldExtractors';\nimport { useCurrentFilters, useCurrentGroupBy } from './hooks/useCurrentFilters';\nimport { useCardSelection } from './hooks/useCardSelection';\nimport { useDetailPanelClose } from './hooks/useDetailPanelClose';\nimport { useScrollSync } from './hooks/useScrollSync';\nimport { useAnimationModeTracking } from './hooks/useAnimationModeTracking';\nimport { useViewModeScrollHandling } from './hooks/useViewModeScrollHandling';\n\nexport function PivotViewer<TItem extends object>({\n data,\n dimensions,\n filters,\n defaultDimensionKey,\n cardRenderer,\n getItemId,\n searchFields,\n className,\n emptyContent,\n isLoading = false,\n}: PivotViewerProps<TItem>) {\n // Refs\n const containerRef = useRef<HTMLDivElement>(null!);\n const filterButtonRef = useRef<HTMLButtonElement>(null!);\n const axisLabelsRef = useRef<HTMLDivElement>(null!);\n const spacerRef = useRef<HTMLDivElement>(null!);\n\n // State\n const [search, setSearch] = useState('');\n const [viewMode, setViewMode] = useState<ViewMode>('collection');\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [selectedItem, setSelectedItem] = useState<TItem | null>(null);\n const [isZooming, setIsZooming] = useState(false);\n const [visibleIds, setVisibleIds] = useState<Uint32Array>(new Uint32Array(0));\n const [grouping, setGrouping] = useState<GroupingResult>({ groups: [] });\n const [hoveredGroupIndex, setHoveredGroupIndex] = useState<number | null>(null);\n const [preSelectionState, setPreSelectionState] = useState<{ zoom: number; scrollLeft: number; scrollTop: number } | null>(null);\n const [, setAnimationMode] = useState<'layout' | 'filter'>('layout');\n const [scrollPosition, setScrollPosition] = useState({ x: 0, y: 0 });\n\n // Filter hooks\n const {\n filterState,\n rangeFilterState,\n expandedFilterKey,\n setExpandedFilterKey,\n handleToggleFilter,\n handleClearFilter,\n handleRangeChange,\n } = useFilterState(filters);\n\n // Dimension hooks\n const {\n activeDimensionKey,\n setActiveDimensionKey,\n activeDimension,\n dimensionFilter,\n handleAxisLabelClick,\n } = useDimensionState(dimensions, defaultDimensionKey);\n\n // Zoom and pan hooks\n const {\n zoomLevel,\n setZoomLevel,\n handleZoomIn,\n handleZoomOut,\n handleZoomSlider,\n } = useZoomState(1);\n\n const {\n isPanning,\n handlePanStart,\n handlePanMove,\n handlePanEnd,\n } = usePanning(containerRef, undefined, setScrollPosition);\n\n useWheelZoom(containerRef, zoomLevel, setZoomLevel);\n\n // Track container dimensions for responsive layout\n const containerDimensions = useContainerDimensions(containerRef, isLoading);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n setScrollPosition({\n x: container.scrollLeft,\n y: container.scrollTop,\n });\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, []);\n\n // Build field extractors for the columnar store\n const { fieldExtractors, indexFields } = useFieldExtractors(dimensions, filters);\n\n // Initialize the Web Worker engine\n const { ready, applyFilters: engineApplyFilters, computeGrouping, sortIds } = usePivotEngine({\n data,\n fieldExtractors,\n indexFields,\n });\n\n // Build filter specs from UI state\n const currentFilters = useCurrentFilters(\n filters,\n filterState,\n rangeFilterState,\n search,\n searchFields,\n dimensionFilter,\n activeDimension,\n );\n\n const currentGroupBy = useCurrentGroupBy(activeDimensionKey, dimensions);\n\n // Apply filters\n useEffect(() => {\n if (!ready) return;\n\n engineApplyFilters(currentFilters).then((result) => {\n setVisibleIds(result.visibleIds);\n });\n }, [ready, currentFilters, engineApplyFilters]);\n\n // Compute grouping\n const lastGroupingRequest = useRef<{ viewMode: ViewMode; groupBy: unknown; visibleIds: Uint32Array } | null>(null);\n \n useEffect(() => {\n if (!ready || visibleIds.length === 0) {\n setGrouping({ groups: [] });\n lastGroupingRequest.current = null;\n return;\n }\n\n if (viewMode === 'collection') {\n // In collection mode, create a single group with all items\n // Sort items if activeDimensionKey is set\n if (activeDimensionKey) {\n sortIds(visibleIds, activeDimensionKey).then((sortedIds) => {\n setGrouping({\n groups: [{\n key: 'all',\n label: 'All Items',\n value: 'all',\n ids: sortedIds,\n count: sortedIds.length\n }]\n });\n });\n } else {\n setGrouping({\n groups: [{\n key: 'all',\n label: 'All Items',\n value: 'all',\n ids: visibleIds,\n count: visibleIds.length\n }]\n });\n }\n lastGroupingRequest.current = null;\n return;\n }\n\n // Check if this is the same request as last time to prevent duplicate computations\n const lastRequest = lastGroupingRequest.current;\n if (\n lastRequest &&\n lastRequest.viewMode === viewMode &&\n (lastRequest.groupBy as unknown as typeof currentGroupBy)?.field === currentGroupBy.field &&\n lastRequest.visibleIds === visibleIds\n ) {\n console.log('[PivotViewer] Skipping duplicate grouping request');\n return;\n }\n\n lastGroupingRequest.current = { viewMode, groupBy: currentGroupBy, visibleIds };\n \n console.log('[PivotViewer] Computing grouping for', visibleIds.length, 'items');\n computeGrouping(visibleIds, currentGroupBy).then((result) => {\n console.log('[PivotViewer] Grouping result received:', result.groups.length, 'groups');\n setGrouping(result);\n });\n }, [ready, visibleIds, currentGroupBy, viewMode, computeGrouping, sortIds, activeDimensionKey]);\n\n // Compute layout\n const layout = useMemo(() => {\n // Calculate layout at base dimensions (zoom is applied as transform)\n const cardWidth = BASE_CARD_WIDTH;\n const cardHeight = BASE_CARD_HEIGHT;\n const containerWidth = containerDimensions.width / zoomLevel;\n // For grouped mode, use fixed container height to ensure stable layout during zoom\n const containerHeight = viewMode === 'collection'\n ? containerDimensions.height / zoomLevel\n : containerDimensions.height;\n\n const result = computeLayout(grouping, {\n viewMode,\n cardWidth,\n cardHeight,\n cardsPerColumn: CARDS_PER_COLUMN,\n groupSpacing: GROUP_SPACING,\n containerWidth,\n containerHeight,\n });\n\n return result;\n }, [grouping, viewMode, zoomLevel, containerDimensions.width, containerDimensions.height]);\n\n const resolveId = useCallback((item: TItem, index: number) => {\n if (getItemId) {\n const id = getItemId(item, index);\n return typeof id === 'number' ? id : index;\n }\n const id = (item as Record<string, unknown>)['id'];\n return typeof id === 'number' ? id : index;\n }, [getItemId]);\n\n // Track animation mode changes\n useAnimationModeTracking(filterState, rangeFilterState, search, activeDimensionKey, viewMode, setAnimationMode);\n\n // Sync axis labels scroll with container scroll\n useScrollSync(containerRef, axisLabelsRef, viewMode);\n\n // Handle scroll positioning when switching view modes or grouping changes\n useViewModeScrollHandling({\n containerRef,\n viewMode,\n grouping,\n layout,\n selectedItem,\n zoomLevel,\n resolveId,\n data,\n setPreSelectionState,\n });\n\n // Handle card selection (click)\n const handleCardClick = useCardSelection({\n data,\n isPanning,\n selectedItem,\n zoomLevel,\n viewMode,\n layout,\n containerDimensions,\n scrollPosition,\n preSelectionState,\n grouping,\n getItemId,\n resolveId,\n setZoomLevel,\n setIsZooming,\n setSelectedItem,\n setPreSelectionState,\n });\n\n // Handle detail panel close\n const closeDetail = useDetailPanelClose({\n selectedItem,\n preSelectionState,\n zoomLevel,\n viewMode,\n layout,\n containerDimensions,\n grouping,\n data,\n resolveId,\n setZoomLevel,\n setIsZooming,\n setSelectedItem,\n setPreSelectionState,\n });\n\n // Use base card dimensions - zoom is applied as transform in canvas\n const cardWidth = BASE_CARD_WIDTH;\n const cardHeight = BASE_CARD_HEIGHT;\n\n // Calculate filter options\n const filterOptions = useFilterOptions(data, filters, filterState, rangeFilterState);\n\n const hasFilters = Boolean(filters && filters.length > 0);\n const activeFilterCount = Object.values(filterState).reduce((sum: number, vals) => sum + (vals as Set<string>).size, 0) +\n Object.values(rangeFilterState).filter(r => r !== null).length;\n\n const viewerClassName = [\n 'pivot-viewer',\n className,\n hasFilters ? (filtersOpen ? 'filters-open' : 'filters-closed') : 'no-filters',\n viewMode === 'grouped' ? 'bucket-mode' : 'collection-mode',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={viewerClassName}>\n <FilterPanelContainer\n isOpen={filtersOpen && hasFilters}\n search={search}\n filterState={filterState}\n rangeFilterState={rangeFilterState}\n expandedFilterKey={expandedFilterKey}\n filterOptions={filterOptions}\n anchorRef={filterButtonRef}\n onClose={() => setFiltersOpen(false)}\n onSearchChange={setSearch}\n onFilterToggle={handleToggleFilter}\n onFilterClear={handleClearFilter}\n onRangeChange={handleRangeChange}\n onExpandedFilterChange={setExpandedFilterKey}\n />\n\n <main className=\"pv-main\">\n <ToolbarContainer\n hasFilters={hasFilters}\n filtersOpen={filtersOpen}\n filteredCount={visibleIds.length}\n viewMode={viewMode}\n zoomLevel={zoomLevel}\n activeDimensionKey={activeDimensionKey}\n dimensions={dimensions}\n activeFilterCount={activeFilterCount}\n onFiltersToggle={() => setFiltersOpen((prev) => !prev)}\n onViewModeChange={setViewMode}\n onZoomIn={handleZoomIn}\n onZoomOut={handleZoomOut}\n onZoomSlider={handleZoomSlider}\n onDimensionChange={setActiveDimensionKey}\n filterButtonRef={filterButtonRef}\n />\n\n <PivotViewerMain\n data={data}\n ready={ready}\n isLoading={isLoading}\n visibleIds={visibleIds}\n grouping={grouping}\n layout={layout}\n cardWidth={cardWidth}\n cardHeight={cardHeight}\n zoomLevel={zoomLevel}\n scrollPosition={scrollPosition}\n containerDimensions={containerDimensions}\n selectedItem={selectedItem}\n hoveredGroupIndex={hoveredGroupIndex}\n isZooming={isZooming}\n viewMode={viewMode}\n cardRenderer={cardRenderer}\n resolveId={resolveId}\n emptyContent={emptyContent}\n dimensionFilter={dimensionFilter}\n onCardClick={handleCardClick}\n onPanStart={handlePanStart as (e: React.MouseEvent) => void}\n onPanMove={handlePanMove as (e: React.MouseEvent) => void}\n onPanEnd={handlePanEnd}\n onGroupHover={setHoveredGroupIndex}\n onAxisLabelClick={handleAxisLabelClick}\n onCloseDetail={closeDetail}\n containerRef={containerRef}\n axisLabelsRef={axisLabelsRef}\n spacerRef={spacerRef}\n />\n </main>\n </div>\n );\n}\n"],"names":["useRef","useState","useFilterState","useDimensionState","useZoomState","usePanning","useWheelZoom","useContainerDimensions","useEffect","useFieldExtractors","usePivotEngine","useCurrentFilters","useCurrentGroupBy","layout","useMemo","BASE_CARD_WIDTH","BASE_CARD_HEIGHT","computeLayout","CARDS_PER_COLUMN","GROUP_SPACING","useCallback","useAnimationModeTracking","useScrollSync","useViewModeScrollHandling","useCardSelection","useDetailPanelClose","useFilterOptions","_jsxs","_jsx","FilterPanelContainer","ToolbarContainer","PivotViewerMain"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PivotViewer.js","sources":["../../../PivotViewer/PivotViewer.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { PivotViewerProps } from './types';\nimport type { GroupingResult } from './engine/types';\nimport { usePivotEngine } from './hooks/usePivotEngine';\nimport { computeLayout } from './engine/layout';\nimport { useFilterState } from './hooks/useFilterState';\nimport { useDimensionState } from './hooks/useDimensionState';\nimport { useZoomState } from './hooks/useZoomState';\nimport { BASE_CARD_WIDTH, BASE_CARD_HEIGHT, CARDS_PER_COLUMN, GROUP_SPACING } from './constants';\nimport './PivotViewer.css';\nimport { PivotViewerMain } from './components/PivotViewerMain';\nimport { FilterPanelContainer } from './components/FilterPanelContainer';\nimport { ToolbarContainer } from './components/ToolbarContainer';\nimport { usePanning, useWheelZoom, useFilterOptions } from './hooks';\nimport { useContainerDimensions } from './hooks/useContainerDimensions';\nimport type { ViewMode } from './components/Toolbar';\nimport { useFieldExtractors } from './hooks/useFieldExtractors';\nimport { useCurrentFilters, useCurrentGroupBy } from './hooks/useCurrentFilters';\nimport { useCardSelection } from './hooks/useCardSelection';\nimport { useDetailPanelClose } from './hooks/useDetailPanelClose';\nimport { useScrollSync } from './hooks/useScrollSync';\nimport { useAnimationModeTracking } from './hooks/useAnimationModeTracking';\nimport { useViewModeScrollHandling } from './hooks/useViewModeScrollHandling';\n\nexport function PivotViewer<TItem extends object>({\n data,\n dimensions,\n filters,\n defaultDimensionKey,\n cardRenderer,\n detailRenderer,\n getItemId,\n searchFields,\n className,\n emptyContent,\n isLoading = false,\n colors,\n}: PivotViewerProps<TItem>) {\n // Refs\n const containerRef = useRef<HTMLDivElement>(null!);\n const filterButtonRef = useRef<HTMLButtonElement>(null!);\n const axisLabelsRef = useRef<HTMLDivElement>(null!);\n const spacerRef = useRef<HTMLDivElement>(null!);\n\n // State\n const [search, setSearch] = useState('');\n const [viewMode, setViewMode] = useState<ViewMode>('collection');\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [selectedItem, setSelectedItem] = useState<TItem | null>(null);\n const [isZooming, setIsZooming] = useState(false);\n const [visibleIds, setVisibleIds] = useState<Uint32Array>(new Uint32Array(0));\n const [grouping, setGrouping] = useState<GroupingResult>({ groups: [] });\n const [hoveredGroupIndex, setHoveredGroupIndex] = useState<number | null>(null);\n const [preSelectionState, setPreSelectionState] = useState<{ zoom: number; scrollLeft: number; scrollTop: number } | null>(null);\n const [, setAnimationMode] = useState<'layout' | 'filter'>('layout');\n const [scrollPosition, setScrollPosition] = useState({ x: 0, y: 0 });\n\n // Filter hooks\n const {\n filterState,\n rangeFilterState,\n expandedFilterKey,\n setExpandedFilterKey,\n handleToggleFilter,\n handleClearFilter,\n handleRangeChange,\n } = useFilterState(filters);\n\n // Dimension hooks\n const {\n activeDimensionKey,\n setActiveDimensionKey,\n activeDimension,\n dimensionFilter,\n handleAxisLabelClick,\n } = useDimensionState(dimensions, defaultDimensionKey);\n\n // Zoom and pan hooks\n const {\n zoomLevel,\n setZoomLevel,\n handleZoomIn,\n handleZoomOut,\n handleZoomSlider,\n } = useZoomState(1);\n\n const {\n isPanning,\n handlePanStart,\n handlePanMove,\n handlePanEnd,\n } = usePanning(containerRef, undefined, setScrollPosition);\n\n useWheelZoom(containerRef, zoomLevel, setZoomLevel);\n\n // Track container dimensions for responsive layout\n const containerDimensions = useContainerDimensions(containerRef, isLoading);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n setScrollPosition({\n x: container.scrollLeft,\n y: container.scrollTop,\n });\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, []);\n\n // Build field extractors for the columnar store\n const { fieldExtractors, indexFields } = useFieldExtractors(dimensions, filters);\n\n // Initialize the Web Worker engine\n const { ready, applyFilters: engineApplyFilters, computeGrouping, sortIds } = usePivotEngine({\n data,\n fieldExtractors,\n indexFields,\n });\n\n // Build filter specs from UI state\n const currentFilters = useCurrentFilters(\n filters,\n filterState,\n rangeFilterState,\n search,\n searchFields,\n dimensionFilter,\n activeDimension,\n );\n\n const currentGroupBy = useCurrentGroupBy(activeDimensionKey, dimensions);\n\n // Apply filters\n useEffect(() => {\n if (!ready) return;\n\n engineApplyFilters(currentFilters).then((result) => {\n // If the engine failed to return any IDs while no filters are active,\n // fall back to showing the full dataset so the canvas never renders empty.\n if (result.visibleIds.length === 0 && currentFilters.length === 0 && data.length > 0) {\n const fallbackIds = new Uint32Array(data.length);\n for (let i = 0; i < data.length; i++) {\n fallbackIds[i] = i;\n }\n setVisibleIds(fallbackIds);\n return;\n }\n\n setVisibleIds(result.visibleIds);\n });\n }, [ready, currentFilters, engineApplyFilters, data.length]);\n\n // Compute grouping\n const lastGroupingRequest = useRef<{ viewMode: ViewMode; groupBy: unknown; visibleIds: Uint32Array } | null>(null);\n \n useEffect(() => {\n if (!ready || visibleIds.length === 0) {\n setGrouping({ groups: [] });\n lastGroupingRequest.current = null;\n return;\n }\n\n if (viewMode === 'collection') {\n // In collection mode, create a single group with all items\n // Sort items if activeDimensionKey is set\n if (activeDimensionKey) {\n sortIds(visibleIds, activeDimensionKey).then((sortedIds) => {\n setGrouping({\n groups: [{\n key: 'all',\n label: 'All Items',\n value: 'all',\n ids: sortedIds,\n count: sortedIds.length\n }]\n });\n });\n } else {\n setGrouping({\n groups: [{\n key: 'all',\n label: 'All Items',\n value: 'all',\n ids: visibleIds,\n count: visibleIds.length\n }]\n });\n }\n lastGroupingRequest.current = null;\n return;\n }\n\n // Check if this is the same request as last time to prevent duplicate computations\n const lastRequest = lastGroupingRequest.current;\n if (\n lastRequest &&\n lastRequest.viewMode === viewMode &&\n (lastRequest.groupBy as unknown as typeof currentGroupBy)?.field === currentGroupBy.field &&\n lastRequest.visibleIds === visibleIds\n ) {\n return;\n }\n\n lastGroupingRequest.current = { viewMode, groupBy: currentGroupBy, visibleIds };\n \n computeGrouping(visibleIds, currentGroupBy).then((result) => {\n setGrouping(result);\n });\n }, [ready, visibleIds, currentGroupBy, viewMode, computeGrouping, sortIds, activeDimensionKey]);\n\n // Compute layout\n const layout = useMemo(() => {\n // Calculate layout at base dimensions (zoom is applied as transform)\n const cardWidth = BASE_CARD_WIDTH;\n const cardHeight = BASE_CARD_HEIGHT;\n const containerWidth = containerDimensions.width / zoomLevel;\n // For grouped mode, use fixed container height to ensure stable layout during zoom\n const containerHeight = viewMode === 'collection'\n ? containerDimensions.height / zoomLevel\n : containerDimensions.height;\n\n const result = computeLayout(grouping, {\n viewMode,\n cardWidth,\n cardHeight,\n cardsPerColumn: CARDS_PER_COLUMN,\n groupSpacing: GROUP_SPACING,\n containerWidth,\n containerHeight,\n });\n\n return result;\n }, [grouping, viewMode, zoomLevel, containerDimensions.width, containerDimensions.height]);\n\n const resolveId = useCallback((item: TItem, index: number) => {\n if (getItemId) {\n const id = getItemId(item, index);\n return typeof id === 'number' ? id : index;\n }\n const id = (item as Record<string, unknown>)['id'];\n return typeof id === 'number' ? id : index;\n }, [getItemId]);\n\n // Track animation mode changes\n useAnimationModeTracking(filterState, rangeFilterState, search, activeDimensionKey, viewMode, setAnimationMode);\n\n // Sync axis labels scroll with container scroll\n useScrollSync(containerRef, axisLabelsRef, viewMode);\n\n // Handle scroll positioning when switching view modes or grouping changes\n useViewModeScrollHandling({\n containerRef,\n viewMode,\n grouping,\n layout,\n selectedItem,\n zoomLevel,\n resolveId,\n data,\n setPreSelectionState,\n });\n\n // Handle card selection (click)\n const handleCardClick = useCardSelection({\n data,\n isPanning,\n selectedItem,\n zoomLevel,\n viewMode,\n layout,\n containerDimensions,\n scrollPosition,\n preSelectionState,\n grouping,\n getItemId,\n resolveId,\n setZoomLevel,\n setIsZooming,\n setSelectedItem,\n setPreSelectionState,\n });\n\n // Handle detail panel close\n const closeDetail = useDetailPanelClose({\n selectedItem,\n preSelectionState,\n zoomLevel,\n viewMode,\n layout,\n containerDimensions,\n grouping,\n data,\n resolveId,\n setZoomLevel,\n setIsZooming,\n setSelectedItem,\n setPreSelectionState,\n });\n\n // Use base card dimensions - zoom is applied as transform in canvas\n const cardWidth = BASE_CARD_WIDTH;\n const cardHeight = BASE_CARD_HEIGHT;\n\n // Calculate filter options\n const filterOptions = useFilterOptions(data, filters, filterState, rangeFilterState);\n\n const hasFilters = Boolean(filters && filters.length > 0);\n const activeFilterCount = Object.values(filterState).reduce((sum: number, vals) => sum + (vals as Set<string>).size, 0) +\n Object.values(rangeFilterState).filter(r => r !== null).length;\n\n const viewerClassName = [\n 'pivot-viewer',\n className,\n hasFilters ? (filtersOpen ? 'filters-open' : 'filters-closed') : 'no-filters',\n viewMode === 'grouped' ? 'grouped-mode' : 'collection-mode',\n ]\n .filter(Boolean)\n .join(' ');\n\n // Map provided color overrides to CSS variables understood by the component.\n const cssVariables = useMemo(() => {\n const vars: Record<string, string> = {};\n if (!colors) return vars;\n if (colors.primaryColor) vars['--primary-color'] = colors.primaryColor;\n if (colors.primaryColorText) vars['--primary-color-text'] = colors.primaryColorText;\n if (colors.primary500) vars['--primary-500'] = colors.primary500;\n if (colors.surfaceGround) vars['--surface-ground'] = colors.surfaceGround;\n if (colors.surfaceCard) vars['--surface-card'] = colors.surfaceCard;\n if (colors.surfaceSection) vars['--surface-section'] = colors.surfaceSection;\n if (colors.surfaceOverlay) vars['--surface-overlay'] = colors.surfaceOverlay;\n if (colors.surfaceBorder) vars['--surface-border'] = colors.surfaceBorder;\n if (colors.textColor) vars['--text-color'] = colors.textColor;\n if (colors.textColorSecondary) vars['--text-color-secondary'] = colors.textColorSecondary;\n if (colors.highlightBg) vars['--highlight-bg'] = colors.highlightBg;\n if (colors.maskbg) vars['--maskbg'] = colors.maskbg;\n if (colors.focusRing) vars['--focus-ring'] = colors.focusRing;\n return vars;\n }, [colors]);\n\n return (\n <div className={viewerClassName} style={cssVariables as React.CSSProperties}>\n <FilterPanelContainer\n isOpen={filtersOpen && hasFilters}\n search={search}\n filterState={filterState}\n rangeFilterState={rangeFilterState}\n expandedFilterKey={expandedFilterKey}\n filterOptions={filterOptions}\n anchorRef={filterButtonRef}\n onClose={() => setFiltersOpen(false)}\n onSearchChange={setSearch}\n onFilterToggle={handleToggleFilter}\n onFilterClear={handleClearFilter}\n onRangeChange={handleRangeChange}\n onExpandedFilterChange={setExpandedFilterKey}\n />\n\n <main className=\"pv-main\">\n <ToolbarContainer\n hasFilters={hasFilters}\n filtersOpen={filtersOpen}\n filteredCount={visibleIds.length}\n viewMode={viewMode}\n zoomLevel={zoomLevel}\n activeDimensionKey={activeDimensionKey}\n dimensions={dimensions}\n activeFilterCount={activeFilterCount}\n onFiltersToggle={() => setFiltersOpen((prev) => !prev)}\n onViewModeChange={setViewMode}\n onZoomIn={handleZoomIn}\n onZoomOut={handleZoomOut}\n onZoomSlider={handleZoomSlider}\n onDimensionChange={setActiveDimensionKey}\n filterButtonRef={filterButtonRef}\n />\n\n <PivotViewerMain\n data={data}\n ready={ready}\n isLoading={isLoading}\n visibleIds={visibleIds}\n grouping={grouping}\n layout={layout}\n cardWidth={cardWidth}\n cardHeight={cardHeight}\n zoomLevel={zoomLevel}\n scrollPosition={scrollPosition}\n containerDimensions={containerDimensions}\n selectedItem={selectedItem}\n hoveredGroupIndex={hoveredGroupIndex}\n isZooming={isZooming}\n viewMode={viewMode}\n cardRenderer={cardRenderer}\n detailRenderer={detailRenderer}\n resolveId={resolveId}\n emptyContent={emptyContent}\n dimensionFilter={dimensionFilter}\n onCardClick={handleCardClick}\n onPanStart={handlePanStart as (e: React.MouseEvent) => void}\n onPanMove={handlePanMove as (e: React.MouseEvent) => void}\n onPanEnd={handlePanEnd}\n onGroupHover={setHoveredGroupIndex}\n onAxisLabelClick={handleAxisLabelClick}\n onCloseDetail={closeDetail}\n containerRef={containerRef}\n axisLabelsRef={axisLabelsRef}\n spacerRef={spacerRef}\n />\n </main>\n </div>\n );\n}\n"],"names":["useRef","useState","useFilterState","useDimensionState","useZoomState","usePanning","useWheelZoom","useContainerDimensions","useEffect","useFieldExtractors","usePivotEngine","useCurrentFilters","useCurrentGroupBy","layout","useMemo","BASE_CARD_WIDTH","BASE_CARD_HEIGHT","computeLayout","CARDS_PER_COLUMN","useCallback","useAnimationModeTracking","useScrollSync","useViewModeScrollHandling","useCardSelection","useDetailPanelClose","useFilterOptions","_jsxs","_jsx","FilterPanelContainer","ToolbarContainer","PivotViewerMain"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ var PIXI = require('pixi.js');
|
|
|
5
5
|
var colorResolver = require('./pivot/colorResolver.js');
|
|
6
6
|
var sprites = require('./pivot/sprites.js');
|
|
7
7
|
var visibility = require('./pivot/visibility.js');
|
|
8
|
-
var
|
|
8
|
+
var groups = require('./pivot/groups.js');
|
|
9
9
|
var animation = require('./pivot/animation.js');
|
|
10
10
|
var constants = require('./pivot/constants.js');
|
|
11
11
|
|
|
@@ -29,13 +29,12 @@ function _interopNamespaceDefault(e) {
|
|
|
29
29
|
var PIXI__namespace = /*#__PURE__*/_interopNamespaceDefault(PIXI);
|
|
30
30
|
|
|
31
31
|
function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeight, zoomLevel, panX, panY, viewportWidth, viewportHeight, selectedId, hoveredGroupIndex, isZooming: _isZooming = false, resolveId: _resolveId, onCardClick, onPanStart, onPanMove, onPanEnd, viewMode, cardRenderer, containerRef, }) {
|
|
32
|
-
console.log('[PivotCanvas] Render', { viewMode });
|
|
33
32
|
const parentContainerRef = containerRef;
|
|
34
33
|
const canvasRef = React.useRef(null);
|
|
35
34
|
const spacerRef = React.useRef(null);
|
|
36
35
|
const appRef = React.useRef(null);
|
|
37
36
|
const rootRef = React.useRef(null);
|
|
38
|
-
const
|
|
37
|
+
const groupsContainerRef = React.useRef(null);
|
|
39
38
|
const spritesRef = React.useRef(new Map());
|
|
40
39
|
const animationFrameRef = React.useRef(0);
|
|
41
40
|
const mountedRef = React.useRef(true);
|
|
@@ -48,6 +47,8 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
48
47
|
const previousViewModeRef = React.useRef(viewMode);
|
|
49
48
|
const prevLayoutRef = React.useRef(null);
|
|
50
49
|
const prevGroupingRef = React.useRef(null);
|
|
50
|
+
const prevScrollTopRef = React.useRef(0);
|
|
51
|
+
const prevScrollLeftRef = React.useRef(0);
|
|
51
52
|
const cardColorsRef = React.useRef(constants.DEFAULT_COLORS);
|
|
52
53
|
const cssColorResolver = React.useMemo(() => colorResolver.createCssColorResolver(), []);
|
|
53
54
|
const onPanStartRef = React.useRef(onPanStart);
|
|
@@ -99,9 +100,9 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
99
100
|
return;
|
|
100
101
|
}
|
|
101
102
|
appRef.current = app;
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
app.stage.addChild(
|
|
103
|
+
const groupsContainer = new PIXI__namespace.Container();
|
|
104
|
+
groupsContainerRef.current = groupsContainer;
|
|
105
|
+
app.stage.addChild(groupsContainer);
|
|
105
106
|
const root = new PIXI__namespace.Container();
|
|
106
107
|
rootRef.current = root;
|
|
107
108
|
app.stage.addChild(root);
|
|
@@ -122,6 +123,9 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
122
123
|
overlayParent.appendChild(c);
|
|
123
124
|
canvasRef.current = c;
|
|
124
125
|
}
|
|
126
|
+
else {
|
|
127
|
+
console.error('PivotCanvas: Could not find canvas element from Pixi application');
|
|
128
|
+
}
|
|
125
129
|
if (canvasRef.current && parentContainerRef.current) {
|
|
126
130
|
const parentBounds = parentContainerRef.current.getBoundingClientRect();
|
|
127
131
|
void parentBounds;
|
|
@@ -175,7 +179,7 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
175
179
|
appRef.current = null;
|
|
176
180
|
rootRef.current = null;
|
|
177
181
|
}
|
|
178
|
-
|
|
182
|
+
spritesRef.current.clear();
|
|
179
183
|
try {
|
|
180
184
|
const parentEl = parentContainerRef.current;
|
|
181
185
|
if (parentEl) {
|
|
@@ -223,9 +227,9 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
223
227
|
};
|
|
224
228
|
}, [pixiReady, viewportWidth, viewportHeight]);
|
|
225
229
|
React.useEffect(() => {
|
|
226
|
-
if (!
|
|
230
|
+
if (!groupsContainerRef.current || !parentContainerRef.current || !pixiReady)
|
|
227
231
|
return;
|
|
228
|
-
|
|
232
|
+
groups.updateGroupBackgrounds(groupsContainerRef.current, parentContainerRef.current, grouping, layout, zoomLevel, cardColorsRef.current, viewMode);
|
|
229
233
|
needsRenderRef.current = true;
|
|
230
234
|
appRef.current?.renderer?.render(appRef.current.stage);
|
|
231
235
|
}, [grouping, layout, zoomLevel, viewMode, pixiReady]);
|
|
@@ -235,22 +239,12 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
235
239
|
}
|
|
236
240
|
const viewModeChanged = previousViewModeRef.current !== viewMode;
|
|
237
241
|
const groupingChanged = prevGroupingRef.current !== grouping;
|
|
238
|
-
|
|
242
|
+
const layoutChanged = prevLayoutRef.current !== layout;
|
|
243
|
+
if (viewModeChanged || groupingChanged || layoutChanged) {
|
|
239
244
|
isViewTransitionRef.current = true;
|
|
240
245
|
lastViewChangeTimeRef.current = Date.now();
|
|
241
246
|
previousViewModeRef.current = viewMode;
|
|
242
247
|
prevGroupingRef.current = grouping;
|
|
243
|
-
console.log('[PivotCanvas] View mode or grouping changed - marking sprites for cleanup');
|
|
244
|
-
for (const sprite of spritesRef.current.values()) {
|
|
245
|
-
try {
|
|
246
|
-
if (sprite.container) {
|
|
247
|
-
sprite.container.visible = false;
|
|
248
|
-
}
|
|
249
|
-
sprite.__lastHiddenAt = Date.now();
|
|
250
|
-
}
|
|
251
|
-
catch (e) {
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
248
|
}
|
|
255
249
|
if (spacerRef.current) {
|
|
256
250
|
const spacer = spacerRef.current;
|
|
@@ -265,8 +259,11 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
265
259
|
const panDeltaX = panX - prevPanRef.current.x;
|
|
266
260
|
const panDeltaY = panY - prevPanRef.current.y;
|
|
267
261
|
prevPanRef.current = { x: panX, y: panY };
|
|
262
|
+
const currentScrollTop = parentContainerRef.current?.scrollTop || 0;
|
|
263
|
+
const currentScrollLeft = parentContainerRef.current?.scrollLeft || 0;
|
|
268
264
|
visibility.syncSpritesToViewport({
|
|
269
265
|
root: rootRef.current,
|
|
266
|
+
groupsContainer: groupsContainerRef.current,
|
|
270
267
|
container: parentContainerRef.current,
|
|
271
268
|
sprites: spritesRef.current,
|
|
272
269
|
layout,
|
|
@@ -281,11 +278,16 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
281
278
|
zoomLevel,
|
|
282
279
|
viewportWidth,
|
|
283
280
|
viewportHeight,
|
|
281
|
+
viewMode,
|
|
284
282
|
createCardSprite: (id, x, y) => sprites.createCardSprite(id, x, y, items, (item, e, id) => (onCardClickRef.current)(item, e, id), (e) => (onPanStart)(e), cardWidth, cardHeight, cardColorsRef.current),
|
|
285
283
|
updateCardContent: (sprite, item) => sprites.updateCardContent(sprite, item, selectedId, cardWidth, cardHeight, cardColorsRef.current),
|
|
286
|
-
isViewTransition: isViewTransitionRef.current
|
|
284
|
+
isViewTransition: isViewTransitionRef.current,
|
|
287
285
|
prevLayout: prevLayoutRef.current,
|
|
286
|
+
prevScrollTop: prevScrollTopRef.current,
|
|
287
|
+
prevScrollLeft: prevScrollLeftRef.current,
|
|
288
288
|
});
|
|
289
|
+
prevScrollTopRef.current = currentScrollTop;
|
|
290
|
+
prevScrollLeftRef.current = currentScrollLeft;
|
|
289
291
|
needsRenderRef.current = true;
|
|
290
292
|
if (appRef.current?.renderer && rootRef.current) {
|
|
291
293
|
appRef.current.renderer.render(appRef.current.stage);
|
|
@@ -304,21 +306,6 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
304
306
|
React.useEffect(() => {
|
|
305
307
|
prevLayoutRef.current = layout;
|
|
306
308
|
}, [layout]);
|
|
307
|
-
React.useEffect(() => {
|
|
308
|
-
if (!rootRef.current || !bucketsContainerRef.current)
|
|
309
|
-
return;
|
|
310
|
-
const effectivePanX = parentContainerRef.current ? parentContainerRef.current.scrollLeft : panX;
|
|
311
|
-
const effectivePanY = parentContainerRef.current ? parentContainerRef.current.scrollTop : panY;
|
|
312
|
-
if (rootRef.current.scale && bucketsContainerRef.current.scale) {
|
|
313
|
-
rootRef.current.scale.set(zoomLevel);
|
|
314
|
-
bucketsContainerRef.current.scale.set(zoomLevel);
|
|
315
|
-
}
|
|
316
|
-
if (rootRef.current.position && bucketsContainerRef.current.position) {
|
|
317
|
-
rootRef.current.position.set(-effectivePanX, -effectivePanY);
|
|
318
|
-
bucketsContainerRef.current.position.set(-effectivePanX, -effectivePanY);
|
|
319
|
-
}
|
|
320
|
-
appRef.current?.renderer?.render(appRef.current.stage);
|
|
321
|
-
}, [zoomLevel, panX, panY]);
|
|
322
309
|
React.useEffect(() => {
|
|
323
310
|
if (!rootRef.current)
|
|
324
311
|
return;
|
|
@@ -347,20 +334,9 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
347
334
|
const effectivePanY = container.scrollTop;
|
|
348
335
|
lastScroll.x = effectivePanX;
|
|
349
336
|
lastScroll.y = effectivePanY;
|
|
350
|
-
if (rootRef.current && bucketsContainerRef.current) {
|
|
351
|
-
if (rootRef.current.scale && bucketsContainerRef.current.scale) {
|
|
352
|
-
rootRef.current.scale.set(zoomLevel);
|
|
353
|
-
bucketsContainerRef.current.scale.set(zoomLevel);
|
|
354
|
-
}
|
|
355
|
-
const invScale = zoomLevel && zoomLevel !== 0 ? 1 / zoomLevel : 1;
|
|
356
|
-
void invScale;
|
|
357
|
-
if (rootRef.current.position && bucketsContainerRef.current.position) {
|
|
358
|
-
rootRef.current.position.set(-effectivePanX, -effectivePanY);
|
|
359
|
-
bucketsContainerRef.current.position.set(-effectivePanX, -effectivePanY);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
337
|
visibility.syncSpritesToViewport({
|
|
363
338
|
root: rootRef.current,
|
|
339
|
+
groupsContainer: groupsContainerRef.current,
|
|
364
340
|
container: parentContainerRef.current,
|
|
365
341
|
sprites: spritesRef.current,
|
|
366
342
|
layout,
|
|
@@ -375,8 +351,13 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
375
351
|
viewportHeight,
|
|
376
352
|
createCardSprite: (id, x, y) => sprites.createCardSprite(id, x, y, items, (item, e, id) => (onCardClickRef.current)(item, e, id), (e) => (onPanStartRef.current)(e), cardWidth, cardHeight, cardColorsRef.current),
|
|
377
353
|
updateCardContent: (sprite, item) => sprites.updateCardContent(sprite, item, selectedId, cardWidth, cardHeight, cardColorsRef.current),
|
|
378
|
-
isViewTransition: isViewTransitionRef.current
|
|
354
|
+
isViewTransition: isViewTransitionRef.current,
|
|
355
|
+
viewMode,
|
|
356
|
+
prevScrollTop: prevScrollTopRef.current,
|
|
357
|
+
prevScrollLeft: prevScrollLeftRef.current,
|
|
379
358
|
});
|
|
359
|
+
prevScrollTopRef.current = container.scrollTop || 0;
|
|
360
|
+
prevScrollLeftRef.current = container.scrollLeft || 0;
|
|
380
361
|
needsRenderRef.current = true;
|
|
381
362
|
app.renderer?.render(app.stage);
|
|
382
363
|
}
|
|
@@ -408,7 +389,7 @@ function PivotCanvas({ items, layout, grouping, visibleIds, cardWidth, cardHeigh
|
|
|
408
389
|
}
|
|
409
390
|
}
|
|
410
391
|
function updateHighlight() {
|
|
411
|
-
|
|
392
|
+
groups.updateHighlight(groupsContainerRef.current, parentContainerRef.current, grouping, layout, hoveredGroupIndex, cardWidth, zoomLevel);
|
|
412
393
|
}
|
|
413
394
|
return null;
|
|
414
395
|
}
|