@cratis/components 4.26.3 → 4.27.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.
Files changed (129) hide show
  1. package/compat-manifest.json +11 -11
  2. package/dist/esm/Common/CratisComponentsProvider.d.ts +4 -0
  3. package/dist/esm/Common/CratisComponentsProvider.d.ts.map +1 -1
  4. package/dist/esm/Common/CratisComponentsProvider.js +1 -0
  5. package/dist/esm/Common/CratisComponentsProvider.js.map +1 -1
  6. package/dist/esm/DataPage/DataPage.d.ts +2 -0
  7. package/dist/esm/DataPage/DataPage.d.ts.map +1 -1
  8. package/dist/esm/DataPage/DataPage.js.map +1 -1
  9. package/dist/esm/DataTables/DataTableForObservableQuery.d.ts +2 -0
  10. package/dist/esm/DataTables/DataTableForObservableQuery.d.ts.map +1 -1
  11. package/dist/esm/DataTables/DataTableForObservableQuery.js +1 -1
  12. package/dist/esm/DataTables/DataTableForObservableQuery.js.map +1 -1
  13. package/dist/esm/DataTables/DataTableForQuery.d.ts +2 -0
  14. package/dist/esm/DataTables/DataTableForQuery.d.ts.map +1 -1
  15. package/dist/esm/DataTables/DataTableForQuery.js +1 -1
  16. package/dist/esm/DataTables/DataTableForQuery.js.map +1 -1
  17. package/dist/esm/DataTables/PaginatorPageItem.d.ts +13 -0
  18. package/dist/esm/DataTables/PaginatorPageItem.d.ts.map +1 -0
  19. package/dist/esm/DataTables/PaginatorPageItem.js +4 -0
  20. package/dist/esm/DataTables/PaginatorPageItem.js.map +1 -0
  21. package/dist/esm/DataTables/TablePaginator.d.ts +22 -2
  22. package/dist/esm/DataTables/TablePaginator.d.ts.map +1 -1
  23. package/dist/esm/DataTables/TablePaginator.js.map +1 -1
  24. package/dist/esm/DataTables/TablePaginatorImplementation.d.ts +1 -1
  25. package/dist/esm/DataTables/TablePaginatorImplementation.d.ts.map +1 -1
  26. package/dist/esm/DataTables/TablePaginatorImplementation.js +8 -3
  27. package/dist/esm/DataTables/TablePaginatorImplementation.js.map +1 -1
  28. package/dist/esm/DataTables/TablePaginatorPages.d.ts +9 -0
  29. package/dist/esm/DataTables/TablePaginatorPages.d.ts.map +1 -0
  30. package/dist/esm/DataTables/TablePaginatorPages.js +20 -0
  31. package/dist/esm/DataTables/TablePaginatorPages.js.map +1 -0
  32. package/dist/esm/DataTables/index.d.ts +2 -0
  33. package/dist/esm/DataTables/index.d.ts.map +1 -1
  34. package/dist/esm/DataTables/index.js +1 -0
  35. package/dist/esm/DataTables/index.js.map +1 -1
  36. package/dist/esm/DataTables/paginatorPages.d.ts +15 -0
  37. package/dist/esm/DataTables/paginatorPages.d.ts.map +1 -0
  38. package/dist/esm/DataTables/paginatorPages.js +40 -0
  39. package/dist/esm/DataTables/paginatorPages.js.map +1 -0
  40. package/dist/esm/Filter/FilterGroup.d.ts +23 -0
  41. package/dist/esm/Filter/FilterGroup.d.ts.map +1 -0
  42. package/dist/esm/Filter/FilterGroup.js +51 -0
  43. package/dist/esm/Filter/FilterGroup.js.map +1 -0
  44. package/dist/esm/Filter/FilterPanel.d.ts.map +1 -1
  45. package/dist/esm/Filter/FilterPanel.js +24 -257
  46. package/dist/esm/Filter/FilterPanel.js.map +1 -1
  47. package/dist/esm/Filter/FilterSearchBox.d.ts +10 -0
  48. package/dist/esm/Filter/FilterSearchBox.d.ts.map +1 -0
  49. package/dist/esm/Filter/FilterSearchBox.js +10 -0
  50. package/dist/esm/Filter/FilterSearchBox.js.map +1 -0
  51. package/dist/esm/Filter/measurePanelPlacement.d.ts +31 -0
  52. package/dist/esm/Filter/measurePanelPlacement.d.ts.map +1 -0
  53. package/dist/esm/Filter/measurePanelPlacement.js +132 -0
  54. package/dist/esm/Filter/measurePanelPlacement.js.map +1 -0
  55. package/dist/esm/Filter/usePanelDismissal.d.ts +32 -0
  56. package/dist/esm/Filter/usePanelDismissal.d.ts.map +1 -0
  57. package/dist/esm/Filter/usePanelDismissal.js +63 -0
  58. package/dist/esm/Filter/usePanelDismissal.js.map +1 -0
  59. package/dist/esm/Filter/usePanelPosition.d.ts +24 -0
  60. package/dist/esm/Filter/usePanelPosition.d.ts.map +1 -0
  61. package/dist/esm/Filter/usePanelPosition.js +85 -0
  62. package/dist/esm/Filter/usePanelPosition.js.map +1 -0
  63. package/dist/esm/Filter/useResolvedAnchor.d.ts +17 -0
  64. package/dist/esm/Filter/useResolvedAnchor.d.ts.map +1 -0
  65. package/dist/esm/Filter/useResolvedAnchor.js +16 -0
  66. package/dist/esm/Filter/useResolvedAnchor.js.map +1 -0
  67. package/dist/esm/PivotViewer/PivotViewer.d.ts.map +1 -1
  68. package/dist/esm/PivotViewer/PivotViewer.js +47 -207
  69. package/dist/esm/PivotViewer/PivotViewer.js.map +1 -1
  70. package/dist/esm/PivotViewer/components/pivot/sprites.js +1 -1
  71. package/dist/esm/PivotViewer/components/pivot/syncScrollSprites.d.ts +2 -2
  72. package/dist/esm/PivotViewer/components/pivot/syncScrollSprites.d.ts.map +1 -1
  73. package/dist/esm/PivotViewer/components/pivot/syncScrollSprites.js +1 -1
  74. package/dist/esm/PivotViewer/components/pivot/syncScrollSprites.js.map +1 -1
  75. package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.d.ts.map +1 -1
  76. package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.js +8 -2
  77. package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.js.map +1 -1
  78. package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.d.ts.map +1 -1
  79. package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.js +49 -28
  80. package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.js.map +1 -1
  81. package/dist/esm/PivotViewer/components/pivot/visibility.d.ts +12 -2
  82. package/dist/esm/PivotViewer/components/pivot/visibility.d.ts.map +1 -1
  83. package/dist/esm/PivotViewer/components/pivot/visibility.js +34 -194
  84. package/dist/esm/PivotViewer/components/pivot/visibility.js.map +1 -1
  85. package/dist/esm/PivotViewer/components/pivot/visibilityHelpers.d.ts +114 -0
  86. package/dist/esm/PivotViewer/components/pivot/visibilityHelpers.d.ts.map +1 -0
  87. package/dist/esm/PivotViewer/components/pivot/visibilityHelpers.js +306 -0
  88. package/dist/esm/PivotViewer/components/pivot/visibilityHelpers.js.map +1 -0
  89. package/dist/esm/PivotViewer/hooks/useColorCssVariables.d.ts +9 -0
  90. package/dist/esm/PivotViewer/hooks/useColorCssVariables.d.ts.map +1 -0
  91. package/dist/esm/PivotViewer/hooks/useColorCssVariables.js +32 -0
  92. package/dist/esm/PivotViewer/hooks/useColorCssVariables.js.map +1 -0
  93. package/dist/esm/PivotViewer/hooks/usePivotViewerGrouping.d.ts +27 -0
  94. package/dist/esm/PivotViewer/hooks/usePivotViewerGrouping.d.ts.map +1 -0
  95. package/dist/esm/PivotViewer/hooks/usePivotViewerGrouping.js +40 -0
  96. package/dist/esm/PivotViewer/hooks/usePivotViewerGrouping.js.map +1 -0
  97. package/dist/esm/PivotViewer/hooks/usePivotViewerInteractions.d.ts +27 -0
  98. package/dist/esm/PivotViewer/hooks/usePivotViewerInteractions.d.ts.map +1 -0
  99. package/dist/esm/PivotViewer/hooks/usePivotViewerInteractions.js +46 -0
  100. package/dist/esm/PivotViewer/hooks/usePivotViewerInteractions.js.map +1 -0
  101. package/dist/esm/PivotViewer/hooks/useRawGrouping.d.ts +22 -0
  102. package/dist/esm/PivotViewer/hooks/useRawGrouping.d.ts.map +1 -0
  103. package/dist/esm/PivotViewer/hooks/useRawGrouping.js +56 -0
  104. package/dist/esm/PivotViewer/hooks/useRawGrouping.js.map +1 -0
  105. package/dist/esm/PivotViewer/hooks/useScrollPositionTracking.d.ts +12 -0
  106. package/dist/esm/PivotViewer/hooks/useScrollPositionTracking.d.ts.map +1 -0
  107. package/dist/esm/PivotViewer/hooks/useScrollPositionTracking.js +20 -0
  108. package/dist/esm/PivotViewer/hooks/useScrollPositionTracking.js.map +1 -0
  109. package/dist/esm/PivotViewer/hooks/useViewerLayout.d.ts +16 -0
  110. package/dist/esm/PivotViewer/hooks/useViewerLayout.d.ts.map +1 -0
  111. package/dist/esm/PivotViewer/hooks/useViewerLayout.js +29 -0
  112. package/dist/esm/PivotViewer/hooks/useViewerLayout.js.map +1 -0
  113. package/dist/esm/PivotViewer/hooks/useVisibleIds.d.ts +21 -0
  114. package/dist/esm/PivotViewer/hooks/useVisibleIds.d.ts.map +1 -0
  115. package/dist/esm/PivotViewer/hooks/useVisibleIds.js +34 -0
  116. package/dist/esm/PivotViewer/hooks/useVisibleIds.js.map +1 -0
  117. package/dist/esm/configuration/CratisComponentsDefaults.d.ts.map +1 -1
  118. package/dist/esm/configuration/CratisComponentsDefaults.js +2 -0
  119. package/dist/esm/configuration/CratisComponentsDefaults.js.map +1 -1
  120. package/dist/esm/styles.DataPage.css +51 -6
  121. package/dist/esm/styles.DataTables.css +51 -6
  122. package/dist/esm/styles.SchemaEditor.css +51 -6
  123. package/dist/esm/styles.css +51 -6
  124. package/dist/esm/styles.renderer.builtin.css +51 -6
  125. package/dist/esm/types/parts.d.ts +4 -1
  126. package/dist/esm/types/parts.d.ts.map +1 -1
  127. package/dist/esm/types/parts.js +4 -1
  128. package/dist/esm/types/parts.js.map +1 -1
  129. package/package.json +1 -1
@@ -1,11 +1,9 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useRef, useState, useEffect, useMemo, useCallback } from 'react';
3
- import { usePivotEngine } from './hooks/usePivotEngine.js';
4
- import { computeLayout } from './engine/layout.js';
2
+ import { useRef, useState, useEffect } from 'react';
5
3
  import { useFilterState } from './hooks/useFilterState.js';
6
4
  import { useDimensionState } from './hooks/useDimensionState.js';
7
5
  import { useZoomState } from './hooks/useZoomState.js';
8
- import { BASE_CARD_HEIGHT, BASE_CARD_WIDTH, CARDS_PER_COLUMN } from './constants.js';
6
+ import { BASE_CARD_HEIGHT, BASE_CARD_WIDTH } from './constants.js';
9
7
  import { PivotViewerMain } from './components/PivotViewerMain.js';
10
8
  import { FilterPanelContainer } from './components/FilterPanelContainer.js';
11
9
  import { ToolbarContainer } from './components/ToolbarContainer.js';
@@ -14,18 +12,32 @@ import { usePanning } from './hooks/usePanning.js';
14
12
  import { useWheelZoom } from './hooks/useWheelZoom.js';
15
13
  import { useZoomScrollAnchor } from './hooks/useZoomScrollAnchor.js';
16
14
  import 'react-dom';
17
- import { useFieldExtractors } from './hooks/useFieldExtractors.js';
18
- import { useCurrentFilters, useCurrentGroupBy } from './hooks/useCurrentFilters.js';
19
- import { useCardSelection } from './hooks/useCardSelection.js';
20
- import { useDetailPanelClose } from './hooks/useDetailPanelClose.js';
21
- import { useScrollSync } from './hooks/useScrollSync.js';
22
- import { useAnimationModeTracking } from './hooks/useAnimationModeTracking.js';
23
- import { useViewModeScrollHandling } from './hooks/useViewModeScrollHandling.js';
24
15
  import { useContainerDimensions } from './hooks/useContainerDimensions.js';
25
- import { presentGrouping } from './utils/presentGrouping.js';
26
- import { filterVisibleIdsBySearch } from './utils/search.js';
27
- import { resolveInternalItemIndex } from './utils/idResolution.js';
16
+ import { useColorCssVariables } from './hooks/useColorCssVariables.js';
17
+ import { useViewerLayout } from './hooks/useViewerLayout.js';
18
+ import { useScrollPositionTracking } from './hooks/useScrollPositionTracking.js';
19
+ import { usePivotViewerGrouping } from './hooks/usePivotViewerGrouping.js';
20
+ import { usePivotViewerInteractions } from './hooks/usePivotViewerInteractions.js';
28
21
 
22
+ function countActiveFilters(filterState, rangeFilterState) {
23
+ const selectionCount = Object.values(filterState).reduce((sum, vals) => sum + vals.size, 0);
24
+ return selectionCount + Object.values(rangeFilterState).filter((r) => r !== null).length;
25
+ }
26
+ function filtersClassName(hasFilters, filtersOpen) {
27
+ if (!hasFilters)
28
+ return 'no-filters';
29
+ return filtersOpen ? 'filters-open' : 'filters-closed';
30
+ }
31
+ function buildViewerClassName(className, hasFilters, filtersOpen, viewMode) {
32
+ return [
33
+ 'pivot-viewer',
34
+ className,
35
+ filtersClassName(hasFilters, filtersOpen),
36
+ viewMode === 'grouped' ? 'grouped-mode' : 'collection-mode',
37
+ ]
38
+ .filter(Boolean)
39
+ .join(' ');
40
+ }
29
41
  function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRenderer, detailRenderer, getItemId, searchFields, title, className, emptyContent, isLoading = false, loadingLabel, labels, colors, }) {
30
42
  const containerRef = useRef(null);
31
43
  const filterButtonRef = useRef(null);
@@ -36,8 +48,6 @@ function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRende
36
48
  const [filtersOpen, setFiltersOpen] = useState(false);
37
49
  const [selectedItem, setSelectedItem] = useState(null);
38
50
  const [isZooming, setIsZooming] = useState(false);
39
- const [visibleIds, setVisibleIds] = useState(new Uint32Array(0));
40
- const [rawGrouping, setRawGrouping] = useState({ groups: [] });
41
51
  const [hoveredGroupIndex, setHoveredGroupIndex] = useState(null);
42
52
  const [preSelectionState, setPreSelectionState] = useState(null);
43
53
  const [, setAnimationMode] = useState('layout');
@@ -49,143 +59,22 @@ function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRende
49
59
  useWheelZoom(containerRef, zoomLevel, setZoomLevel);
50
60
  useZoomScrollAnchor(containerRef, spacerRef, viewMode);
51
61
  const containerDimensions = useContainerDimensions(containerRef, isLoading);
52
- useEffect(() => {
53
- const container = containerRef.current;
54
- if (!container)
55
- return;
56
- const handleScroll = () => {
57
- setScrollPosition({
58
- x: container.scrollLeft,
59
- y: container.scrollTop,
60
- });
61
- };
62
- container.addEventListener('scroll', handleScroll);
63
- return () => container.removeEventListener('scroll', handleScroll);
64
- }, []);
65
- const { fieldExtractors, indexFields } = useFieldExtractors(dimensions, filters);
66
- const { ready, applyFilters: engineApplyFilters, computeGrouping, sortIds, } = usePivotEngine({
62
+ useScrollPositionTracking(containerRef, setScrollPosition);
63
+ const { ready, visibleIds, grouping } = usePivotViewerGrouping({
67
64
  data,
68
- fieldExtractors,
69
- indexFields,
70
- });
71
- const currentFilters = useCurrentFilters(filters, filterState, rangeFilterState, dimensionFilter, activeDimension);
72
- const currentGroupBy = useCurrentGroupBy(activeDimensionKey, dimensions);
73
- useEffect(() => {
74
- if (!ready)
75
- return;
76
- let cancelled = false;
77
- void engineApplyFilters(currentFilters).then((result) => {
78
- if (cancelled)
79
- return;
80
- let ids = result.visibleIds;
81
- if (ids.length === 0 && currentFilters.length === 0 && data.length > 0) {
82
- const fallbackIds = new Uint32Array(data.length);
83
- for (let i = 0; i < data.length; i++) {
84
- fallbackIds[i] = i;
85
- }
86
- ids = fallbackIds;
87
- }
88
- setVisibleIds(filterVisibleIdsBySearch(data, ids, search, searchFields));
89
- });
90
- return () => {
91
- cancelled = true;
92
- };
93
- }, [ready, currentFilters, engineApplyFilters, data, search, searchFields]);
94
- useEffect(() => {
95
- if (!ready || visibleIds.length === 0) {
96
- setRawGrouping({ groups: [] });
97
- return;
98
- }
99
- let cancelled = false;
100
- if (viewMode === 'collection') {
101
- if (activeDimensionKey) {
102
- void sortIds(visibleIds, activeDimensionKey).then((sortedIds) => {
103
- if (cancelled)
104
- return;
105
- setRawGrouping({
106
- groups: [
107
- {
108
- key: 'all',
109
- label: 'All Items',
110
- value: 'all',
111
- ids: sortedIds,
112
- count: sortedIds.length,
113
- },
114
- ],
115
- });
116
- });
117
- }
118
- else {
119
- setRawGrouping({
120
- groups: [
121
- {
122
- key: 'all',
123
- label: 'All Items',
124
- value: 'all',
125
- ids: visibleIds,
126
- count: visibleIds.length,
127
- },
128
- ],
129
- });
130
- }
131
- }
132
- else {
133
- void computeGrouping(visibleIds, currentGroupBy).then((result) => {
134
- if (!cancelled)
135
- setRawGrouping(result);
136
- });
137
- }
138
- return () => {
139
- cancelled = true;
140
- };
141
- }, [
142
- ready,
143
- visibleIds,
144
- currentGroupBy,
145
- viewMode,
146
- computeGrouping,
147
- sortIds,
65
+ dimensions,
66
+ filters,
67
+ filterState,
68
+ rangeFilterState,
69
+ dimensionFilter,
70
+ activeDimension,
148
71
  activeDimensionKey,
149
- ]);
150
- const grouping = useMemo(() => viewMode === 'grouped' ? presentGrouping(rawGrouping, activeDimension, data) : rawGrouping, [viewMode, rawGrouping, activeDimension, data]);
151
- const layout = useMemo(() => {
152
- const cardWidth = BASE_CARD_WIDTH;
153
- const cardHeight = BASE_CARD_HEIGHT;
154
- const containerWidth = containerDimensions.width / zoomLevel;
155
- const containerHeight = viewMode === 'collection'
156
- ? containerDimensions.height / zoomLevel
157
- : containerDimensions.height;
158
- const result = computeLayout(grouping, {
159
- viewMode,
160
- cardWidth,
161
- cardHeight,
162
- cardsPerColumn: CARDS_PER_COLUMN,
163
- containerWidth,
164
- containerHeight,
165
- });
166
- return result;
167
- }, [
168
- grouping,
169
- viewMode,
170
- zoomLevel,
171
- containerDimensions.width,
172
- containerDimensions.height,
173
- ]);
174
- const resolveId = useCallback((item) => resolveInternalItemIndex(data, item, getItemId), [data, getItemId]);
175
- useAnimationModeTracking(filterState, rangeFilterState, search, activeDimensionKey, viewMode, setAnimationMode);
176
- useScrollSync(containerRef, axisLabelsRef, viewMode);
177
- useViewModeScrollHandling({
178
- containerRef,
72
+ searchFields,
73
+ search,
179
74
  viewMode,
180
- grouping,
181
- layout,
182
- selectedItem,
183
- zoomLevel,
184
- resolveId,
185
- data,
186
- setPreSelectionState,
187
75
  });
188
- const handleCardClick = useCardSelection({
76
+ const layout = useViewerLayout(grouping, viewMode, zoomLevel, containerDimensions);
77
+ const { resolveId, handleCardClick, closeDetail } = usePivotViewerInteractions({
189
78
  data,
190
79
  isPanning,
191
80
  selectedItem,
@@ -193,29 +82,18 @@ function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRende
193
82
  viewMode,
194
83
  layout,
195
84
  containerRef,
85
+ axisLabelsRef,
196
86
  spacerRef,
197
87
  containerDimensions,
198
88
  scrollPosition,
199
89
  preSelectionState,
200
90
  grouping,
201
91
  getItemId,
202
- resolveId,
203
- setZoomLevel,
204
- setIsZooming,
205
- setSelectedItem,
206
- setPreSelectionState,
207
- });
208
- const closeDetail = useDetailPanelClose({
209
- selectedItem,
210
- preSelectionState,
211
- zoomLevel,
212
- viewMode,
213
- layout,
214
- containerRef,
215
- containerDimensions,
216
- grouping,
217
- data,
218
- resolveId,
92
+ filterState,
93
+ rangeFilterState,
94
+ search,
95
+ activeDimensionKey,
96
+ setAnimationMode,
219
97
  setZoomLevel,
220
98
  setIsZooming,
221
99
  setSelectedItem,
@@ -225,50 +103,12 @@ function PivotViewer({ data, dimensions, filters, defaultDimensionKey, cardRende
225
103
  const cardHeight = BASE_CARD_HEIGHT;
226
104
  const filterOptions = useFilterOptions(data, filters, filterState, rangeFilterState);
227
105
  const hasFilters = Boolean(filters && filters.length > 0);
228
- const activeFilterCount = Object.values(filterState).reduce((sum, vals) => sum + vals.size, 0) + Object.values(rangeFilterState).filter((r) => r !== null).length;
229
- const viewerClassName = [
230
- 'pivot-viewer',
231
- className,
232
- hasFilters ? (filtersOpen ? 'filters-open' : 'filters-closed') : 'no-filters',
233
- viewMode === 'grouped' ? 'grouped-mode' : 'collection-mode',
234
- ]
235
- .filter(Boolean)
236
- .join(' ');
106
+ const activeFilterCount = countActiveFilters(filterState, rangeFilterState);
107
+ const viewerClassName = buildViewerClassName(className, hasFilters, filtersOpen, viewMode);
237
108
  useEffect(() => {
238
109
  setSelectedItem(null);
239
110
  }, [viewMode]);
240
- const cssVariables = useMemo(() => {
241
- const vars = {};
242
- if (!colors)
243
- return vars;
244
- if (colors.primaryColor)
245
- vars['--cratis-primary-color'] = colors.primaryColor;
246
- if (colors.primaryColorText)
247
- vars['--cratis-primary-color-text'] = colors.primaryColorText;
248
- if (colors.primary500)
249
- vars['--cratis-primary-500'] = colors.primary500;
250
- if (colors.surfaceGround)
251
- vars['--cratis-surface-ground'] = colors.surfaceGround;
252
- if (colors.surfaceCard)
253
- vars['--cratis-surface-card'] = colors.surfaceCard;
254
- if (colors.surfaceSection)
255
- vars['--cratis-surface-section'] = colors.surfaceSection;
256
- if (colors.surfaceOverlay)
257
- vars['--cratis-surface-overlay'] = colors.surfaceOverlay;
258
- if (colors.surfaceBorder)
259
- vars['--cratis-surface-border'] = colors.surfaceBorder;
260
- if (colors.textColor)
261
- vars['--cratis-text-color'] = colors.textColor;
262
- if (colors.textColorSecondary)
263
- vars['--cratis-text-color-secondary'] = colors.textColorSecondary;
264
- if (colors.highlightBg)
265
- vars['--cratis-highlight-bg'] = colors.highlightBg;
266
- if (colors.maskbg)
267
- vars['--cratis-maskbg'] = colors.maskbg;
268
- if (colors.focusRing)
269
- vars['--cratis-focus-ring'] = colors.focusRing;
270
- return vars;
271
- }, [colors]);
111
+ const cssVariables = useColorCssVariables(colors);
272
112
  return (jsxs("div", { className: viewerClassName, style: cssVariables, children: [jsx(FilterPanelContainer, { isOpen: filtersOpen && hasFilters, filterLabel: labels?.filters, searchPlaceholder: labels?.search, searchGroup: labels?.searchGroup, 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 }), jsxs("main", { className: 'pv-main', children: [jsx(ToolbarContainer, { hasFilters: hasFilters, filtersOpen: filtersOpen, filteredCount: visibleIds.length, viewMode: viewMode, zoomLevel: zoomLevel, activeDimensionKey: activeDimensionKey, dimensions: dimensions, activeFilterCount: activeFilterCount, title: title, labels: labels, onFiltersToggle: () => setFiltersOpen((prev) => !prev), onViewModeChange: setViewMode, onZoomIn: handleZoomIn, onZoomOut: handleZoomOut, onZoomSlider: handleZoomSlider, onZoomReset: handleZoomReset, onZoomChange: handleZoomChange, onDimensionChange: setActiveDimensionKey, filterButtonRef: filterButtonRef }), jsx(PivotViewerMain, { data: data, ready: ready, isLoading: isLoading, loadingLabel: loadingLabel ?? labels?.loading ?? 'Loading…', viewportLabel: labels?.viewport ?? 'Card area', visibleIds: visibleIds, grouping: grouping, layout: layout, cardWidth: cardWidth, cardHeight: cardHeight, zoomLevel: zoomLevel, scrollPosition: scrollPosition, containerDimensions: containerDimensions, selectedItem: selectedItem, hoveredGroupIndex: hoveredGroupIndex, isZooming: isZooming, viewMode: viewMode, cardRenderer: cardRenderer, colorOverrides: colors, 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 })] })] }));
273
113
  }
274
114
 
@@ -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 {\n BASE_CARD_WIDTH,\n BASE_CARD_HEIGHT,\n CARDS_PER_COLUMN,\n GROUP_SPACING,\n} from './constants';\nimport { PivotViewerMain } from './components/PivotViewerMain';\nimport { FilterPanelContainer } from './components/FilterPanelContainer';\nimport { ToolbarContainer } from './components/ToolbarContainer';\nimport { usePanning, useWheelZoom, useZoomScrollAnchor, useFilterOptions } from './hooks';\nimport { useContainerDimensions } from './hooks/useContainerDimensions';\nimport type { ViewMode } from './components/Toolbar';\nimport { useFieldExtractors } from './hooks/useFieldExtractors';\nimport { presentGrouping } from './utils/presentGrouping';\nimport { useCurrentFilters, useCurrentGroupBy } from './hooks/useCurrentFilters';\nimport { filterVisibleIdsBySearch } from './utils/search';\nimport { resolveInternalItemIndex } from './utils/idResolution';\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\n/**\n * A faceted, zoomable card-grid visualization inspired by Microsoft's PivotViewer.\n * Renders a large set of items as cards that can be grouped by any of a set of\n * declared dimensions, filtered through faceted panels, searched by text, and\n * zoomed/panned around freely. A detail pane shows the selected card's full\n * information.\n *\n * Backed by PIXI.js for high-performance rendering, so it gracefully handles\n * thousands of items. Consumers supply their own `cardRenderer` and\n * `detailRenderer` to control card and detail content; the component handles\n * grouping, filtering, panning, zooming, and selection internally.\n *\n * Use this for exploratory data analysis UIs over large collections (catalogs,\n * inventories, telemetry samples). For tabular display, use {@link DataPage}\n * or {@link DataTableForQuery}.\n *\n * @typeParam TItem - The item type contained in {@link PivotViewerProps.data}.\n * @param props - {@link PivotViewerProps}.\n */\nexport function PivotViewer<TItem extends object>({\n data,\n dimensions,\n filters,\n defaultDimensionKey,\n cardRenderer,\n detailRenderer,\n getItemId,\n searchFields,\n title,\n className,\n emptyContent,\n isLoading = false,\n loadingLabel,\n labels,\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 [rawGrouping, setRawGrouping] = useState<GroupingResult>({ groups: [] });\n const [hoveredGroupIndex, setHoveredGroupIndex] = useState<number | null>(null);\n const [preSelectionState, setPreSelectionState] = useState<{\n zoom: number;\n scrollLeft: number;\n scrollTop: number;\n } | 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 handleZoomReset,\n handleZoomChange,\n } = useZoomState(1);\n\n const { isPanning, handlePanStart, handlePanMove, handlePanEnd } = usePanning(\n containerRef,\n undefined,\n setScrollPosition,\n );\n\n useWheelZoom(containerRef, zoomLevel, setZoomLevel);\n useZoomScrollAnchor(containerRef, spacerRef, viewMode);\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 {\n ready,\n applyFilters: engineApplyFilters,\n computeGrouping,\n sortIds,\n } = 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 dimensionFilter,\n activeDimension,\n );\n\n const currentGroupBy = useCurrentGroupBy(activeDimensionKey, dimensions);\n\n // Apply filters, then narrow the result by search - a post-filter step over the visible\n // Uint32 ids so it applies identically whether the engine result came from the worker or\n // its synchronous fallback.\n useEffect(() => {\n if (!ready) return;\n\n let cancelled = false;\n void engineApplyFilters(currentFilters).then((result) => {\n if (cancelled) return;\n let ids = result.visibleIds;\n\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 (ids.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 ids = fallbackIds;\n }\n\n setVisibleIds(filterVisibleIdsBySearch(data, ids, search, searchFields));\n });\n return () => {\n cancelled = true;\n };\n }, [ready, currentFilters, engineApplyFilters, data, search, searchFields]);\n\n // Compute grouping. Every async branch ignores a result after its dependencies change, so an\n // older worker response can never overwrite a newer filter/search/view selection.\n useEffect(() => {\n if (!ready || visibleIds.length === 0) {\n setRawGrouping({ groups: [] });\n return;\n }\n\n let cancelled = false;\n if (viewMode === 'collection') {\n // In collection mode, create a single group with all items.\n if (activeDimensionKey) {\n void sortIds(visibleIds, activeDimensionKey).then((sortedIds) => {\n if (cancelled) return;\n setRawGrouping({\n groups: [\n {\n key: 'all',\n label: 'All Items',\n value: 'all',\n ids: sortedIds,\n count: sortedIds.length,\n },\n ],\n });\n });\n } else {\n setRawGrouping({\n groups: [\n {\n key: 'all',\n label: 'All Items',\n value: 'all',\n ids: visibleIds,\n count: visibleIds.length,\n },\n ],\n });\n }\n } else {\n void computeGrouping(visibleIds, currentGroupBy).then((result) => {\n if (!cancelled) setRawGrouping(result);\n });\n }\n\n return () => {\n cancelled = true;\n };\n }, [\n ready,\n visibleIds,\n currentGroupBy,\n viewMode,\n computeGrouping,\n sortIds,\n activeDimensionKey,\n ]);\n\n const grouping = useMemo(\n () => viewMode === 'grouped' ? presentGrouping(rawGrouping, activeDimension, data) : rawGrouping,\n [viewMode, rawGrouping, activeDimension, data],\n );\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 =\n 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 }, [\n grouping,\n viewMode,\n zoomLevel,\n containerDimensions.width,\n containerDimensions.height,\n ]);\n\n const resolveId = useCallback(\n (item: TItem) => resolveInternalItemIndex(data, item, getItemId),\n [data, getItemId],\n );\n\n // Track animation mode changes\n useAnimationModeTracking(\n filterState,\n rangeFilterState,\n search,\n activeDimensionKey,\n viewMode,\n setAnimationMode,\n );\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 containerRef,\n spacerRef,\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 containerRef,\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 =\n Object.values(filterState).reduce(\n (sum: number, vals) => sum + (vals as Set<string>).size,\n 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 // Deselect any selected card when switching between view modes\n useEffect(() => {\n setSelectedItem(null);\n }, [viewMode]);\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['--cratis-primary-color'] = colors.primaryColor;\n if (colors.primaryColorText)\n vars['--cratis-primary-color-text'] = colors.primaryColorText;\n if (colors.primary500) vars['--cratis-primary-500'] = colors.primary500;\n if (colors.surfaceGround) vars['--cratis-surface-ground'] = colors.surfaceGround;\n if (colors.surfaceCard) vars['--cratis-surface-card'] = colors.surfaceCard;\n if (colors.surfaceSection)\n vars['--cratis-surface-section'] = colors.surfaceSection;\n if (colors.surfaceOverlay)\n vars['--cratis-surface-overlay'] = colors.surfaceOverlay;\n if (colors.surfaceBorder) vars['--cratis-surface-border'] = colors.surfaceBorder;\n if (colors.textColor) vars['--cratis-text-color'] = colors.textColor;\n if (colors.textColorSecondary)\n vars['--cratis-text-color-secondary'] = colors.textColorSecondary;\n if (colors.highlightBg) vars['--cratis-highlight-bg'] = colors.highlightBg;\n if (colors.maskbg) vars['--cratis-maskbg'] = colors.maskbg;\n if (colors.focusRing) vars['--cratis-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 filterLabel={labels?.filters}\n searchPlaceholder={labels?.search}\n searchGroup={labels?.searchGroup}\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 title={title}\n labels={labels}\n onFiltersToggle={() => setFiltersOpen((prev) => !prev)}\n onViewModeChange={setViewMode}\n onZoomIn={handleZoomIn}\n onZoomOut={handleZoomOut}\n onZoomSlider={handleZoomSlider}\n onZoomReset={handleZoomReset}\n onZoomChange={handleZoomChange}\n onDimensionChange={setActiveDimensionKey}\n filterButtonRef={filterButtonRef}\n />\n\n <PivotViewerMain\n data={data}\n ready={ready}\n isLoading={isLoading}\n loadingLabel={loadingLabel ?? labels?.loading ?? 'Loading…'}\n viewportLabel={labels?.viewport ?? 'Card area'}\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 colorOverrides={colors}\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":["_jsxs","_jsx"],"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 { useEffect, useRef, useState } from 'react';\nimport type { PivotViewerProps } from './types';\nimport { useFilterState } from './hooks/useFilterState';\nimport { useDimensionState } from './hooks/useDimensionState';\nimport { useZoomState } from './hooks/useZoomState';\nimport { BASE_CARD_WIDTH, BASE_CARD_HEIGHT } from './constants';\nimport { PivotViewerMain } from './components/PivotViewerMain';\nimport { FilterPanelContainer } from './components/FilterPanelContainer';\nimport { ToolbarContainer } from './components/ToolbarContainer';\nimport { usePanning, useWheelZoom, useZoomScrollAnchor, useFilterOptions } from './hooks';\nimport { useContainerDimensions } from './hooks/useContainerDimensions';\nimport type { ViewMode } from './components/Toolbar';\nimport { useColorCssVariables } from './hooks/useColorCssVariables';\nimport { useViewerLayout } from './hooks/useViewerLayout';\nimport { useScrollPositionTracking } from './hooks/useScrollPositionTracking';\nimport { usePivotViewerGrouping } from './hooks/usePivotViewerGrouping';\nimport { usePivotViewerInteractions } from './hooks/usePivotViewerInteractions';\n\nfunction countActiveFilters(\n filterState: Record<string, unknown>,\n rangeFilterState: Record<string, unknown>,\n): number {\n const selectionCount = Object.values(filterState).reduce(\n (sum: number, vals) => sum + (vals as Set<string>).size,\n 0,\n );\n return selectionCount + Object.values(rangeFilterState).filter((r) => r !== null).length;\n}\n\nfunction filtersClassName(hasFilters: boolean, filtersOpen: boolean): string {\n if (!hasFilters) return 'no-filters';\n return filtersOpen ? 'filters-open' : 'filters-closed';\n}\n\nfunction buildViewerClassName(\n className: string | undefined,\n hasFilters: boolean,\n filtersOpen: boolean,\n viewMode: ViewMode,\n): string {\n return [\n 'pivot-viewer',\n className,\n filtersClassName(hasFilters, filtersOpen),\n viewMode === 'grouped' ? 'grouped-mode' : 'collection-mode',\n ]\n .filter(Boolean)\n .join(' ');\n}\n\n/**\n * A faceted, zoomable card-grid visualization inspired by Microsoft's PivotViewer.\n * Renders a large set of items as cards that can be grouped by any of a set of\n * declared dimensions, filtered through faceted panels, searched by text, and\n * zoomed/panned around freely. A detail pane shows the selected card's full\n * information.\n *\n * Backed by PIXI.js for high-performance rendering, so it gracefully handles\n * thousands of items. Consumers supply their own `cardRenderer` and\n * `detailRenderer` to control card and detail content; the component handles\n * grouping, filtering, panning, zooming, and selection internally.\n *\n * Use this for exploratory data analysis UIs over large collections (catalogs,\n * inventories, telemetry samples). For tabular display, use {@link DataPage}\n * or {@link DataTableForQuery}.\n *\n * @typeParam TItem - The item type contained in {@link PivotViewerProps.data}.\n * @param props - {@link PivotViewerProps}.\n */\nexport function PivotViewer<TItem extends object>({\n data,\n dimensions,\n filters,\n defaultDimensionKey,\n cardRenderer,\n detailRenderer,\n getItemId,\n searchFields,\n title,\n className,\n emptyContent,\n isLoading = false,\n loadingLabel,\n labels,\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 [hoveredGroupIndex, setHoveredGroupIndex] = useState<number | null>(null);\n const [preSelectionState, setPreSelectionState] = useState<{\n zoom: number;\n scrollLeft: number;\n scrollTop: number;\n } | 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 handleZoomReset,\n handleZoomChange,\n } = useZoomState(1);\n\n const { isPanning, handlePanStart, handlePanMove, handlePanEnd } = usePanning(\n containerRef,\n undefined,\n setScrollPosition,\n );\n\n useWheelZoom(containerRef, zoomLevel, setZoomLevel);\n useZoomScrollAnchor(containerRef, spacerRef, viewMode);\n\n // Track container dimensions for responsive layout\n const containerDimensions = useContainerDimensions(containerRef, isLoading);\n\n useScrollPositionTracking(containerRef, setScrollPosition);\n\n const { ready, visibleIds, grouping } = usePivotViewerGrouping({\n data,\n dimensions,\n filters,\n filterState,\n rangeFilterState,\n dimensionFilter,\n activeDimension,\n activeDimensionKey,\n searchFields,\n search,\n viewMode,\n });\n\n const layout = useViewerLayout(grouping, viewMode, zoomLevel, containerDimensions);\n\n const { resolveId, handleCardClick, closeDetail } = usePivotViewerInteractions({\n data,\n isPanning,\n selectedItem,\n zoomLevel,\n viewMode,\n layout,\n containerRef,\n axisLabelsRef,\n spacerRef,\n containerDimensions,\n scrollPosition,\n preSelectionState,\n grouping,\n getItemId,\n filterState,\n rangeFilterState,\n search,\n activeDimensionKey,\n setAnimationMode,\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 = countActiveFilters(filterState, rangeFilterState);\n const viewerClassName = buildViewerClassName(className, hasFilters, filtersOpen, viewMode);\n\n // Deselect any selected card when switching between view modes\n useEffect(() => {\n setSelectedItem(null);\n }, [viewMode]);\n\n const cssVariables = useColorCssVariables(colors);\n\n return (\n <div className={viewerClassName} style={cssVariables as React.CSSProperties}>\n <FilterPanelContainer\n isOpen={filtersOpen && hasFilters}\n filterLabel={labels?.filters}\n searchPlaceholder={labels?.search}\n searchGroup={labels?.searchGroup}\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 title={title}\n labels={labels}\n onFiltersToggle={() => setFiltersOpen((prev) => !prev)}\n onViewModeChange={setViewMode}\n onZoomIn={handleZoomIn}\n onZoomOut={handleZoomOut}\n onZoomSlider={handleZoomSlider}\n onZoomReset={handleZoomReset}\n onZoomChange={handleZoomChange}\n onDimensionChange={setActiveDimensionKey}\n filterButtonRef={filterButtonRef}\n />\n\n <PivotViewerMain\n data={data}\n ready={ready}\n isLoading={isLoading}\n loadingLabel={loadingLabel ?? labels?.loading ?? 'Loading…'}\n viewportLabel={labels?.viewport ?? 'Card area'}\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 colorOverrides={colors}\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":["_jsxs","_jsx"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import * as PIXI from 'pixi.js';
2
- import { CARD_RADIUS, CARD_GAP, CARD_PADDING } from './constants.js';
2
+ import { CARD_RADIUS, CARD_PADDING, CARD_GAP } from './constants.js';
3
3
  import { ellipsizeLine, ellipsizeBlock } from './ellipsize.js';
4
4
 
5
5
  const VALUES_INSET = 65;
@@ -1,5 +1,5 @@
1
1
  import type { LayoutResult } from '../../engine/types.js';
2
- import { type SyncParams } from './visibility.js';
2
+ import { type SyncParams, type SyncResult } from './visibility.js';
3
3
  /** Keep the scroll path's transition layout in sync with the normal render path. */
4
- export declare function syncScrollSprites<TItem>(params: Omit<SyncParams<TItem>, 'prevLayout'>, previousLayout: LayoutResult | null): void;
4
+ export declare function syncScrollSprites<TItem>(params: Omit<SyncParams<TItem>, 'prevLayout'>, previousLayout: LayoutResult | null): SyncResult;
5
5
  //# sourceMappingURL=syncScrollSprites.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"syncScrollSprites.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/syncScrollSprites.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAoB,CAAC;AACvD,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,iBAAc,CAAC;AAEtE,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,EAAE,cAAc,EAAE,YAAY,GAAG,IAAI,QAE1H"}
1
+ {"version":3,"file":"syncScrollSprites.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/syncScrollSprites.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAoB,CAAC;AACvD,OAAO,EAAyB,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAc,CAAC;AAEvF,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,EAAE,cAAc,EAAE,YAAY,GAAG,IAAI,GAAG,UAAU,CAEvI"}
@@ -1,7 +1,7 @@
1
1
  import { syncSpritesToViewport } from './visibility.js';
2
2
 
3
3
  function syncScrollSprites(params, previousLayout) {
4
- syncSpritesToViewport({ ...params, prevLayout: previousLayout });
4
+ return syncSpritesToViewport({ ...params, prevLayout: previousLayout });
5
5
  }
6
6
 
7
7
  export { syncScrollSprites };
@@ -1 +1 @@
1
- {"version":3,"file":"syncScrollSprites.js","sources":["../../../../../PivotViewer/components/pivot/syncScrollSprites.ts"],"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 type { LayoutResult } from '../../engine/types';\nimport { syncSpritesToViewport, type SyncParams } from './visibility';\n\n/** Keep the scroll path's transition layout in sync with the normal render path. */\nexport function syncScrollSprites<TItem>(params: Omit<SyncParams<TItem>, 'prevLayout'>, previousLayout: LayoutResult | null) {\n syncSpritesToViewport({ ...params, prevLayout: previousLayout });\n}\n"],"names":[],"mappings":";;AAOM,SAAU,iBAAiB,CAAQ,MAA6C,EAAE,cAAmC,EAAA;IACvH,qBAAqB,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AACpE;;"}
1
+ {"version":3,"file":"syncScrollSprites.js","sources":["../../../../../PivotViewer/components/pivot/syncScrollSprites.ts"],"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 type { LayoutResult } from '../../engine/types';\nimport { syncSpritesToViewport, type SyncParams, type SyncResult } from './visibility';\n\n/** Keep the scroll path's transition layout in sync with the normal render path. */\nexport function syncScrollSprites<TItem>(params: Omit<SyncParams<TItem>, 'prevLayout'>, previousLayout: LayoutResult | null): SyncResult {\n return syncSpritesToViewport({ ...params, prevLayout: previousLayout });\n}\n"],"names":[],"mappings":";;AAOM,SAAU,iBAAiB,CAAQ,MAA6C,EAAE,cAAmC,EAAA;IACvH,OAAO,qBAAqB,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AAC3E;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePivotScrollSync.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/usePivotScrollSync.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,+EAOpD,kBAAkB,CAAC,KAAK,CAAC,SAoK3B,CAAC"}
1
+ {"version":3,"file":"usePivotScrollSync.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/usePivotScrollSync.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,+EAOpD,kBAAkB,CAAC,KAAK,CAAC,SA6K3B,CAAC"}
@@ -17,10 +17,11 @@ const usePivotScrollSync = ({ props, stage, transition, cardColorsRef, onCardCli
17
17
  const container = parentContainerRef.current;
18
18
  const app = appRef.current;
19
19
  const pendingRef = { scheduled: false };
20
+ let frameHandle = 0;
20
21
  const processScroll = () => {
21
22
  pendingRef.scheduled = false;
22
23
  try {
23
- syncScrollSprites({
24
+ const { pending } = syncScrollSprites({
24
25
  root: rootRef.current,
25
26
  groupsContainer: groupsContainerRef.current,
26
27
  container: parentContainerRef.current,
@@ -47,6 +48,10 @@ const usePivotScrollSync = ({ props, stage, transition, cardColorsRef, onCardCli
47
48
  prevScrollLeftRef.current = container.scrollLeft || 0;
48
49
  needsRenderRef.current = true;
49
50
  app.renderer?.render(app.stage);
51
+ if (pending) {
52
+ pendingRef.scheduled = true;
53
+ frameHandle = requestAnimationFrame(processScroll);
54
+ }
50
55
  }
51
56
  catch (e) {
52
57
  console.error('[PivotCanvas] processScroll error', e);
@@ -55,12 +60,13 @@ const usePivotScrollSync = ({ props, stage, transition, cardColorsRef, onCardCli
55
60
  const onScroll = () => {
56
61
  if (!pendingRef.scheduled) {
57
62
  pendingRef.scheduled = true;
58
- requestAnimationFrame(processScroll);
63
+ frameHandle = requestAnimationFrame(processScroll);
59
64
  }
60
65
  };
61
66
  container.addEventListener('scroll', onScroll, { passive: true });
62
67
  return () => {
63
68
  container.removeEventListener('scroll', onScroll);
69
+ cancelAnimationFrame(frameHandle);
64
70
  };
65
71
  }, [
66
72
  pixiReady,
@@ -1 +1 @@
1
- {"version":3,"file":"usePivotScrollSync.js","sources":["../../../../../PivotViewer/components/pivot/usePivotScrollSync.ts"],"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 { useEffect } from 'react';\nimport { asReactMouseEvent } from './asReactMouseEvent';\nimport type { CardSprite } from './constants';\nimport {\n createCardSprite as createCardSpriteExternal,\n updateCardContent as updateCardContentExternal,\n} from './sprites';\nimport { syncScrollSprites } from './syncScrollSprites';\nimport type { PivotRenderContext } from './PivotRenderContext';\n\n/**\n * Syncs the card sprites once per animation frame while the viewport scrolls, natively or\n * programmatically.\n * @param context The props, stage, transition state and colors.\n */\nexport const usePivotScrollSync = <TItem extends object>({\n props,\n stage,\n transition,\n cardColorsRef,\n onCardClickRef,\n onPanStartRef,\n}: PivotRenderContext<TItem>) => {\n const {\n items,\n layout,\n grouping,\n visibleIds,\n cardWidth,\n cardHeight,\n zoomLevel,\n panX,\n panY,\n viewportWidth,\n viewportHeight,\n selectedId,\n viewMode,\n cardRenderer,\n resolveId,\n onPanStart,\n onCardClick,\n containerRef: parentContainerRef,\n } = props;\n const { rootRef, groupsContainerRef, spritesRef, appRef, needsRenderRef, pixiReady } =\n stage;\n const {\n isViewTransitionRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n prevScrollTopRef,\n prevScrollLeftRef,\n } = transition;\n\n // Listen to native scroll events on the parent container so we update the\n // Pixi world immediately when the user scrolls (native scrollbar or\n // programmatic). This ensures `syncSpritesToViewport` runs on scroll and\n // creates/destroys sprites as the viewport moves.\n useEffect(() => {\n if (\n !pixiReady ||\n !parentContainerRef ||\n !parentContainerRef.current ||\n !appRef.current ||\n !rootRef.current\n )\n return;\n\n const container = parentContainerRef.current;\n const app = appRef.current;\n\n // rAF-batched scroll handling: process scroll once per animation frame to avoid heavy synchronous work inside\n // the scroll event which causes jank and de-synchronisation between the\n // compositor and Pixi render updates.\n const pendingRef = { scheduled: false } as { scheduled: boolean };\n\n const processScroll = () => {\n pendingRef.scheduled = false;\n try {\n // Note: We delegate root/groups container positioning to syncSpritesToViewport\n // because it encapsulates the logic for conditional vertical alignment (offsetY)\n // in different view modes. Manually setting position here would overwrite that logic.\n\n syncScrollSprites(\n {\n root: rootRef.current,\n groupsContainer: groupsContainerRef.current,\n container: parentContainerRef.current,\n sprites: spritesRef.current,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n panX,\n panY,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n createCardSprite: (id: string | number, x: number, y: number) =>\n createCardSpriteExternal(\n id,\n x,\n y,\n items as TItem[],\n (item, e, id) => onCardClickRef.current(item, e, id),\n (e) => onPanStartRef.current(asReactMouseEvent(e)),\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n resolveId,\n ),\n updateCardContent: (sprite: CardSprite, item: TItem) =>\n updateCardContentExternal(\n sprite,\n item,\n selectedId,\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n ),\n isViewTransition: isViewTransitionRef.current,\n viewMode,\n transitionSeenIds: transitionSeenIdsRef.current,\n prevScrollTop: prevScrollTopRef.current,\n prevScrollLeft: prevScrollLeftRef.current,\n },\n transitionLayoutRef.current,\n );\n\n // Update previous scroll position for next frame\n prevScrollTopRef.current = container.scrollTop || 0;\n prevScrollLeftRef.current = container.scrollLeft || 0;\n needsRenderRef.current = true;\n app.renderer?.render(app.stage);\n } catch (e) {\n console.error('[PivotCanvas] processScroll error', e);\n }\n };\n\n const onScroll = () => {\n // schedule the work for the next animation frame\n if (!pendingRef.scheduled) {\n pendingRef.scheduled = true;\n requestAnimationFrame(processScroll);\n }\n };\n\n container.addEventListener('scroll', onScroll, { passive: true });\n\n return () => {\n container.removeEventListener('scroll', onScroll);\n };\n }, [\n pixiReady,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n panX,\n panY,\n grouping,\n viewMode,\n selectedId,\n onCardClick,\n onPanStart,\n appRef,\n cardColorsRef,\n groupsContainerRef,\n isViewTransitionRef,\n needsRenderRef,\n onCardClickRef,\n onPanStartRef,\n parentContainerRef,\n prevScrollLeftRef,\n prevScrollTopRef,\n rootRef,\n spritesRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n ]);\n};\n"],"names":["createCardSpriteExternal","updateCardContentExternal"],"mappings":"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"}
1
+ {"version":3,"file":"usePivotScrollSync.js","sources":["../../../../../PivotViewer/components/pivot/usePivotScrollSync.ts"],"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 { useEffect } from 'react';\nimport { asReactMouseEvent } from './asReactMouseEvent';\nimport type { CardSprite } from './constants';\nimport {\n createCardSprite as createCardSpriteExternal,\n updateCardContent as updateCardContentExternal,\n} from './sprites';\nimport { syncScrollSprites } from './syncScrollSprites';\nimport type { PivotRenderContext } from './PivotRenderContext';\n\n/**\n * Syncs the card sprites once per animation frame while the viewport scrolls, natively or\n * programmatically.\n * @param context The props, stage, transition state and colors.\n */\nexport const usePivotScrollSync = <TItem extends object>({\n props,\n stage,\n transition,\n cardColorsRef,\n onCardClickRef,\n onPanStartRef,\n}: PivotRenderContext<TItem>) => {\n const {\n items,\n layout,\n grouping,\n visibleIds,\n cardWidth,\n cardHeight,\n zoomLevel,\n panX,\n panY,\n viewportWidth,\n viewportHeight,\n selectedId,\n viewMode,\n cardRenderer,\n resolveId,\n onPanStart,\n onCardClick,\n containerRef: parentContainerRef,\n } = props;\n const { rootRef, groupsContainerRef, spritesRef, appRef, needsRenderRef, pixiReady } =\n stage;\n const {\n isViewTransitionRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n prevScrollTopRef,\n prevScrollLeftRef,\n } = transition;\n\n // Listen to native scroll events on the parent container so we update the\n // Pixi world immediately when the user scrolls (native scrollbar or\n // programmatic). This ensures `syncSpritesToViewport` runs on scroll and\n // creates/destroys sprites as the viewport moves.\n useEffect(() => {\n if (\n !pixiReady ||\n !parentContainerRef ||\n !parentContainerRef.current ||\n !appRef.current ||\n !rootRef.current\n )\n return;\n\n const container = parentContainerRef.current;\n const app = appRef.current;\n\n // rAF-batched scroll handling: process scroll once per animation frame to avoid heavy synchronous work inside\n // the scroll event which causes jank and de-synchronisation between the\n // compositor and Pixi render updates.\n const pendingRef = { scheduled: false } as { scheduled: boolean };\n let frameHandle = 0;\n\n const processScroll = () => {\n pendingRef.scheduled = false;\n try {\n // Note: We delegate root/groups container positioning to syncSpritesToViewport\n // because it encapsulates the logic for conditional vertical alignment (offsetY)\n // in different view modes. Manually setting position here would overwrite that logic.\n\n const { pending } = syncScrollSprites(\n {\n root: rootRef.current,\n groupsContainer: groupsContainerRef.current,\n container: parentContainerRef.current,\n sprites: spritesRef.current,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n panX,\n panY,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n createCardSprite: (id: string | number, x: number, y: number) =>\n createCardSpriteExternal(\n id,\n x,\n y,\n items as TItem[],\n (item, e, id) => onCardClickRef.current(item, e, id),\n (e) => onPanStartRef.current(asReactMouseEvent(e)),\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n resolveId,\n ),\n updateCardContent: (sprite: CardSprite, item: TItem) =>\n updateCardContentExternal(\n sprite,\n item,\n selectedId,\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n ),\n isViewTransition: isViewTransitionRef.current,\n viewMode,\n transitionSeenIds: transitionSeenIdsRef.current,\n prevScrollTop: prevScrollTopRef.current,\n prevScrollLeft: prevScrollLeftRef.current,\n },\n transitionLayoutRef.current,\n );\n\n // Update previous scroll position for next frame\n prevScrollTopRef.current = container.scrollTop || 0;\n prevScrollLeftRef.current = container.scrollLeft || 0;\n needsRenderRef.current = true;\n app.renderer?.render(app.stage);\n\n // Creation was deferred by the per-frame budget: continue on the next frame\n // until the buffer is filled.\n if (pending) {\n pendingRef.scheduled = true;\n frameHandle = requestAnimationFrame(processScroll);\n }\n } catch (e) {\n console.error('[PivotCanvas] processScroll error', e);\n }\n };\n\n const onScroll = () => {\n // schedule the work for the next animation frame\n if (!pendingRef.scheduled) {\n pendingRef.scheduled = true;\n frameHandle = requestAnimationFrame(processScroll);\n }\n };\n\n container.addEventListener('scroll', onScroll, { passive: true });\n\n return () => {\n container.removeEventListener('scroll', onScroll);\n cancelAnimationFrame(frameHandle);\n };\n }, [\n pixiReady,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n panX,\n panY,\n grouping,\n viewMode,\n selectedId,\n onCardClick,\n onPanStart,\n appRef,\n cardColorsRef,\n groupsContainerRef,\n isViewTransitionRef,\n needsRenderRef,\n onCardClickRef,\n onPanStartRef,\n parentContainerRef,\n prevScrollLeftRef,\n prevScrollTopRef,\n rootRef,\n spritesRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n ]);\n};\n"],"names":["createCardSpriteExternal","updateCardContentExternal"],"mappings":";;;;;AAkBO,MAAM,kBAAkB,GAAG,CAAuB,EACrD,KAAK,EACL,KAAK,EACL,UAAU,EACV,aAAa,EACb,cAAc,EACd,aAAa,GACW,KAAI;AAC5B,IAAA,MAAM,EACF,KAAK,EACL,MAAM,EACN,QAAQ,EACR,UAAU,EACV,SAAS,EACT,UAAU,EACV,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,aAAa,EACb,cAAc,EACd,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,YAAY,EAAE,kBAAkB,GACnC,GAAG,KAAK;AACT,IAAA,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,GAChF,KAAK;AACT,IAAA,MAAM,EACF,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GACpB,GAAG,UAAU;IAMd,SAAS,CAAC,MAAK;AACX,QAAA,IACI,CAAC,SAAS;AACV,YAAA,CAAC,kBAAkB;YACnB,CAAC,kBAAkB,CAAC,OAAO;YAC3B,CAAC,MAAM,CAAC,OAAO;YACf,CAAC,OAAO,CAAC,OAAO;YAEhB;AAEJ,QAAA,MAAM,SAAS,GAAG,kBAAkB,CAAC,OAAO;AAC5C,QAAA,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO;AAK1B,QAAA,MAAM,UAAU,GAAG,EAAE,SAAS,EAAE,KAAK,EAA4B;QACjE,IAAI,WAAW,GAAG,CAAC;QAEnB,MAAM,aAAa,GAAG,MAAK;AACvB,YAAA,UAAU,CAAC,SAAS,GAAG,KAAK;AAC5B,YAAA,IAAI;AAKA,gBAAA,MAAM,EAAE,OAAO,EAAE,GAAG,iBAAiB,CACjC;oBACI,IAAI,EAAE,OAAO,CAAC,OAAO;oBACrB,eAAe,EAAE,kBAAkB,CAAC,OAAO;oBAC3C,SAAS,EAAE,kBAAkB,CAAC,OAAO;oBACrC,OAAO,EAAE,UAAU,CAAC,OAAO;oBAC3B,MAAM;oBACN,UAAU;oBACV,KAAK;oBACL,SAAS;oBACT,UAAU;oBACV,IAAI;oBACJ,IAAI;oBACJ,SAAS;oBACT,aAAa;oBACb,cAAc;AACd,oBAAA,gBAAgB,EAAE,CAAC,EAAmB,EAAE,CAAS,EAAE,CAAS,KACxDA,gBAAwB,CACpB,EAAE,EACF,CAAC,EACD,CAAC,EACD,KAAgB,EAChB,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,EACpD,CAAC,CAAC,KAAK,aAAa,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAClD,SAAS,EACT,UAAU,EACV,aAAa,CAAC,OAAO,EACrB,YAAY,EACZ,SAAS,CACZ;oBACL,iBAAiB,EAAE,CAAC,MAAkB,EAAE,IAAW,KAC/CC,iBAAyB,CACrB,MAAM,EACN,IAAI,EACJ,UAAU,EACV,SAAS,EACT,UAAU,EACV,aAAa,CAAC,OAAO,EACrB,YAAY,CACf;oBACL,gBAAgB,EAAE,mBAAmB,CAAC,OAAO;oBAC7C,QAAQ;oBACR,iBAAiB,EAAE,oBAAoB,CAAC,OAAO;oBAC/C,aAAa,EAAE,gBAAgB,CAAC,OAAO;oBACvC,cAAc,EAAE,iBAAiB,CAAC,OAAO;AAC5C,iBAAA,EACD,mBAAmB,CAAC,OAAO,CAC9B;gBAGD,gBAAgB,CAAC,OAAO,GAAG,SAAS,CAAC,SAAS,IAAI,CAAC;gBACnD,iBAAiB,CAAC,OAAO,GAAG,SAAS,CAAC,UAAU,IAAI,CAAC;AACrD,gBAAA,cAAc,CAAC,OAAO,GAAG,IAAI;gBAC7B,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC;gBAI/B,IAAI,OAAO,EAAE;AACT,oBAAA,UAAU,CAAC,SAAS,GAAG,IAAI;AAC3B,oBAAA,WAAW,GAAG,qBAAqB,CAAC,aAAa,CAAC;gBACtD;YACJ;YAAE,OAAO,CAAC,EAAE;AACR,gBAAA,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,CAAC,CAAC;YACzD;AACJ,QAAA,CAAC;QAED,MAAM,QAAQ,GAAG,MAAK;AAElB,YAAA,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE;AACvB,gBAAA,UAAU,CAAC,SAAS,GAAG,IAAI;AAC3B,gBAAA,WAAW,GAAG,qBAAqB,CAAC,aAAa,CAAC;YACtD;AACJ,QAAA,CAAC;AAED,QAAA,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAEjE,QAAA,OAAO,MAAK;AACR,YAAA,SAAS,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC;YACjD,oBAAoB,CAAC,WAAW,CAAC;AACrC,QAAA,CAAC;AACL,IAAA,CAAC,EAAE;QACC,SAAS;QACT,MAAM;QACN,UAAU;QACV,KAAK;QACL,SAAS;QACT,UAAU;QACV,SAAS;QACT,aAAa;QACb,cAAc;QACd,IAAI;QACJ,IAAI;QACJ,QAAQ;QACR,QAAQ;QACR,UAAU;QACV,WAAW;QACX,UAAU;QACV,MAAM;QACN,aAAa;QACb,kBAAkB;QAClB,mBAAmB;QACnB,cAAc;QACd,cAAc;QACd,aAAa;QACb,kBAAkB;QAClB,iBAAiB;QACjB,gBAAgB;QAChB,OAAO;QACP,UAAU;QACV,mBAAmB;QACnB,oBAAoB;AACvB,KAAA,CAAC;AACN;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePivotSpriteSync.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/usePivotSpriteSync.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,+EAOpD,kBAAkB,CAAC,KAAK,CAAC,SAuM3B,CAAC"}
1
+ {"version":3,"file":"usePivotSpriteSync.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/usePivotSpriteSync.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,+EAOpD,kBAAkB,CAAC,KAAK,CAAC,SAkO3B,CAAC"}