@cratis/components 0.1.15 → 0.1.16

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 (46) hide show
  1. package/dist/cjs/PivotViewer/PivotViewer.css +16 -3
  2. package/dist/cjs/PivotViewer/PivotViewer.js +34 -5
  3. package/dist/cjs/PivotViewer/PivotViewer.js.map +1 -1
  4. package/dist/cjs/PivotViewer/components/PivotCanvas.js +0 -2
  5. package/dist/cjs/PivotViewer/components/PivotCanvas.js.map +1 -1
  6. package/dist/cjs/PivotViewer/components/PivotViewerMain.js +4 -2
  7. package/dist/cjs/PivotViewer/components/PivotViewerMain.js.map +1 -1
  8. package/dist/cjs/PivotViewer/components/pivot/visibility.js +0 -20
  9. package/dist/cjs/PivotViewer/components/pivot/visibility.js.map +1 -1
  10. package/dist/cjs/PivotViewer/hooks/usePivotEngine.js +1 -31
  11. package/dist/cjs/PivotViewer/hooks/usePivotEngine.js.map +1 -1
  12. package/dist/cjs/PivotViewer/types.js.map +1 -1
  13. package/dist/cjs/PivotViewer/utils/animations.js +0 -16
  14. package/dist/cjs/PivotViewer/utils/animations.js.map +1 -1
  15. package/dist/esm/PivotViewer/PivotViewer.css +16 -3
  16. package/dist/esm/PivotViewer/PivotViewer.d.ts +1 -1
  17. package/dist/esm/PivotViewer/PivotViewer.d.ts.map +1 -1
  18. package/dist/esm/PivotViewer/PivotViewer.js +34 -5
  19. package/dist/esm/PivotViewer/PivotViewer.js.map +1 -1
  20. package/dist/esm/PivotViewer/PivotViewer.stories.d.ts.map +1 -1
  21. package/dist/esm/PivotViewer/PivotViewer.stories.js +5 -2
  22. package/dist/esm/PivotViewer/PivotViewer.stories.js.map +1 -1
  23. package/dist/esm/PivotViewer/components/PivotCanvas.d.ts.map +1 -1
  24. package/dist/esm/PivotViewer/components/PivotCanvas.js +0 -2
  25. package/dist/esm/PivotViewer/components/PivotCanvas.js.map +1 -1
  26. package/dist/esm/PivotViewer/components/PivotViewerMain.d.ts +2 -1
  27. package/dist/esm/PivotViewer/components/PivotViewerMain.d.ts.map +1 -1
  28. package/dist/esm/PivotViewer/components/PivotViewerMain.js +4 -2
  29. package/dist/esm/PivotViewer/components/PivotViewerMain.js.map +1 -1
  30. package/dist/esm/PivotViewer/components/pivot/visibility.d.ts.map +1 -1
  31. package/dist/esm/PivotViewer/components/pivot/visibility.js +0 -20
  32. package/dist/esm/PivotViewer/components/pivot/visibility.js.map +1 -1
  33. package/dist/esm/PivotViewer/engine/pivot.worker.d.ts.map +1 -1
  34. package/dist/esm/PivotViewer/engine/pivot.worker.js +0 -8
  35. package/dist/esm/PivotViewer/engine/pivot.worker.js.map +1 -1
  36. package/dist/esm/PivotViewer/hooks/usePivotEngine.d.ts.map +1 -1
  37. package/dist/esm/PivotViewer/hooks/usePivotEngine.js +1 -31
  38. package/dist/esm/PivotViewer/hooks/usePivotEngine.js.map +1 -1
  39. package/dist/esm/PivotViewer/types.d.ts +16 -0
  40. package/dist/esm/PivotViewer/types.d.ts.map +1 -1
  41. package/dist/esm/PivotViewer/types.js.map +1 -1
  42. package/dist/esm/PivotViewer/utils/animations.d.ts.map +1 -1
  43. package/dist/esm/PivotViewer/utils/animations.js +0 -16
  44. package/dist/esm/PivotViewer/utils/animations.js.map +1 -1
  45. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PivotViewerMain.js","sources":["../../../../PivotViewer/components/PivotViewerMain.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 type { ReactNode } from 'react';\nimport type { ItemId, LayoutResult, GroupingResult } from '../engine/types';\nimport type { ViewMode } from './Toolbar';\nimport type { PivotDimensionFilter } from '../hooks/useDimensionState';\nimport { Spinner } from './Spinner';\nimport { PivotCanvas } from './PivotCanvas';\nimport { AxisLabels } from './AxisLabels';\nimport { DetailPanel } from './DetailPanel';\n\nexport interface PivotViewerMainProps<TItem extends object> {\n data: TItem[];\n ready: boolean;\n isLoading: boolean;\n visibleIds: Uint32Array;\n grouping: GroupingResult;\n layout: LayoutResult;\n cardWidth: number;\n cardHeight: number;\n zoomLevel: number;\n scrollPosition: { x: number; y: number };\n containerDimensions: { width: number; height: number };\n selectedItem: TItem | null;\n hoveredGroupIndex: number | null;\n isZooming: boolean;\n viewMode: ViewMode;\n cardRenderer?: (item: TItem) => ReactNode;\n resolveId: (item: TItem, index: number) => ItemId;\n emptyContent?: ReactNode;\n dimensionFilter: PivotDimensionFilter;\n onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void;\n onPanStart: (e: React.MouseEvent) => void;\n onPanMove: (e: React.MouseEvent) => void;\n onPanEnd: () => void;\n onGroupHover: (index: number | null) => void;\n onAxisLabelClick: (value: string) => void;\n onCloseDetail: () => void;\n containerRef: React.RefObject<HTMLDivElement | null>;\n axisLabelsRef: React.RefObject<HTMLDivElement | null>;\n spacerRef: React.RefObject<HTMLDivElement | null>;\n}\n\nexport function PivotViewerMain<TItem extends object>({\n data,\n ready,\n isLoading,\n visibleIds,\n grouping,\n layout,\n cardWidth,\n cardHeight,\n zoomLevel,\n scrollPosition,\n containerDimensions,\n selectedItem,\n hoveredGroupIndex,\n isZooming,\n viewMode,\n cardRenderer,\n resolveId,\n emptyContent,\n dimensionFilter,\n onCardClick,\n onPanStart,\n onPanMove,\n onPanEnd,\n onGroupHover,\n onAxisLabelClick,\n onCloseDetail,\n containerRef,\n axisLabelsRef,\n spacerRef,\n}: PivotViewerMainProps<TItem>) {\n const handleViewportClick = (e: React.MouseEvent) => {\n if (isZooming || !containerRef.current) return;\n\n const container = containerRef.current;\n const rect = container.getBoundingClientRect();\n // Use live DOM scroll position for accurate hit testing\n const scrollLeft = container.scrollLeft;\n const scrollTop = container.scrollTop;\n\n const clickX = e.clientX - rect.left + scrollLeft;\n const clickY = e.clientY - rect.top + scrollTop;\n\n const worldX = clickX / zoomLevel;\n const worldY = clickY / zoomLevel;\n\n // Check visible items\n for (let i = 0; i < visibleIds.length; i++) {\n const id = visibleIds[i];\n const pos = layout.positions.get(id);\n if (pos) {\n if (worldX >= pos.x && worldX <= pos.x + cardWidth &&\n worldY >= pos.y && worldY <= pos.y + cardHeight) {\n const item = data[id];\n if (item) {\n onCardClick(item, e.nativeEvent as unknown as MouseEvent, id);\n }\n return;\n }\n }\n }\n };\n\n const handleViewportMouseMove = (e: React.MouseEvent) => {\n if (isZooming || !containerRef.current) return;\n\n const container = containerRef.current;\n const rect = container.getBoundingClientRect();\n const scrollLeft = container.scrollLeft;\n const scrollTop = container.scrollTop;\n\n const mouseX = e.clientX - rect.left + scrollLeft;\n const mouseY = e.clientY - rect.top + scrollTop;\n\n const worldX = mouseX / zoomLevel;\n const worldY = mouseY / zoomLevel;\n\n let isOverCard = false;\n for (let i = 0; i < visibleIds.length; i++) {\n const id = visibleIds[i];\n const pos = layout.positions.get(id);\n if (pos) {\n if (worldX >= pos.x && worldX <= pos.x + cardWidth &&\n worldY >= pos.y && worldY <= pos.y + cardHeight) {\n isOverCard = true;\n break;\n }\n }\n }\n\n container.style.cursor = isOverCard ? 'pointer' : 'default';\n };\n\n return isLoading ? (\n <Spinner />\n ) : (\n <div className=\"pv-groups-wrapper\">\n <div style={{ position: 'relative', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>\n <div\n className={`pv-viewport ${isZooming ? 'pv-zooming' : ''}`}\n ref={containerRef}\n style={{ overflow: 'auto', position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}\n onClick={handleViewportClick}\n onMouseMove={handleViewportMouseMove}\n >\n {/* Spacer for scrolling - explicitly rendered to allow synchronous updates during animation */}\n <div\n ref={spacerRef}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: layout.totalWidth * zoomLevel,\n height: layout.totalHeight * zoomLevel,\n pointerEvents: 'none'\n }}\n />\n\n {!ready && (\n <div className=\"pv-loading\">Building indexes...</div>\n )}\n\n {ready && visibleIds.length === 0 && (\n <div className=\"pv-empty\">\n {emptyContent ?? 'No items to display.'}\n </div>\n )}\n\n {ready && visibleIds.length > 0 && (\n <PivotCanvas\n items={data}\n layout={layout}\n grouping={grouping}\n visibleIds={visibleIds}\n cardWidth={cardWidth}\n cardHeight={cardHeight}\n zoomLevel={zoomLevel}\n panX={scrollPosition.x}\n panY={scrollPosition.y}\n viewportWidth={containerDimensions.width}\n viewportHeight={containerDimensions.height}\n selectedId={selectedItem ? resolveId(selectedItem, 0) : null}\n hoveredGroupIndex={hoveredGroupIndex}\n isZooming={isZooming}\n cardRenderer={cardRenderer}\n resolveId={resolveId}\n onCardClick={onCardClick}\n onPanStart={onPanStart}\n onPanMove={onPanMove}\n onPanEnd={onPanEnd}\n containerRef={containerRef}\n viewMode={viewMode}\n />\n )}\n </div>\n <DetailPanel\n selectedItem={selectedItem}\n onClose={onCloseDetail}\n />\n </div>\n\n {viewMode === 'grouped' && grouping.groups.length > 0 && (\n <AxisLabels\n groups={grouping.groups.map((g) => ({\n key: g.key,\n value: g.value,\n label: String(g.value),\n items: [],\n count: g.ids.length,\n }))}\n bucketWidths={layout.bucketWidths || []}\n zoomLevel={zoomLevel}\n dimensionFilter={dimensionFilter}\n hoveredGroup={hoveredGroupIndex !== null ? String(grouping.groups[hoveredGroupIndex]?.value) : null}\n onHover={(label) => {\n const index = grouping.groups.findIndex(g => String(g.value) === label);\n onGroupHover(index >= 0 ? index : null);\n }}\n onClick={onAxisLabelClick}\n containerRef={axisLabelsRef}\n />\n )}\n </div>\n );\n}\n"],"names":["_jsx","_jsxs"],"mappings":"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"}
1
+ {"version":3,"file":"PivotViewerMain.js","sources":["../../../../PivotViewer/components/PivotViewerMain.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 type { ReactNode } from 'react';\nimport type { ItemId, LayoutResult, GroupingResult } from '../engine/types';\nimport type { ViewMode } from './Toolbar';\nimport type { PivotDimensionFilter } from '../hooks/useDimensionState';\nimport { Spinner } from './Spinner';\nimport { PivotCanvas } from './PivotCanvas';\nimport { AxisLabels } from './AxisLabels';\nimport { DetailPanel } from './DetailPanel';\n\nexport interface PivotViewerMainProps<TItem extends object> {\n data: TItem[];\n ready: boolean;\n isLoading: boolean;\n visibleIds: Uint32Array;\n grouping: GroupingResult;\n layout: LayoutResult;\n cardWidth: number;\n cardHeight: number;\n zoomLevel: number;\n scrollPosition: { x: number; y: number };\n containerDimensions: { width: number; height: number };\n selectedItem: TItem | null;\n hoveredGroupIndex: number | null;\n isZooming: boolean;\n viewMode: ViewMode;\n cardRenderer?: (item: TItem) => ReactNode;\n /** Optional renderer for a custom details panel when a card is selected */\n detailRenderer?: (item: TItem, onClose: () => void) => ReactNode;\n resolveId: (item: TItem, index: number) => ItemId;\n emptyContent?: ReactNode;\n dimensionFilter: PivotDimensionFilter;\n onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void;\n onPanStart: (e: React.MouseEvent) => void;\n onPanMove: (e: React.MouseEvent) => void;\n onPanEnd: () => void;\n onGroupHover: (index: number | null) => void;\n onAxisLabelClick: (value: string) => void;\n onCloseDetail: () => void;\n containerRef: React.RefObject<HTMLDivElement | null>;\n axisLabelsRef: React.RefObject<HTMLDivElement | null>;\n spacerRef: React.RefObject<HTMLDivElement | null>;\n}\n\nexport function PivotViewerMain<TItem extends object>({\n data,\n ready,\n isLoading,\n visibleIds,\n grouping,\n layout,\n cardWidth,\n cardHeight,\n zoomLevel,\n scrollPosition,\n containerDimensions,\n selectedItem,\n hoveredGroupIndex,\n isZooming,\n viewMode,\n cardRenderer,\n detailRenderer,\n resolveId,\n emptyContent,\n dimensionFilter,\n onCardClick,\n onPanStart,\n onPanMove,\n onPanEnd,\n onGroupHover,\n onAxisLabelClick,\n onCloseDetail,\n containerRef,\n axisLabelsRef,\n spacerRef,\n}: PivotViewerMainProps<TItem>) {\n const handleViewportClick = (e: React.MouseEvent) => {\n if (isZooming || !containerRef.current) return;\n\n const container = containerRef.current;\n const rect = container.getBoundingClientRect();\n // Use live DOM scroll position for accurate hit testing\n const scrollLeft = container.scrollLeft;\n const scrollTop = container.scrollTop;\n\n const clickX = e.clientX - rect.left + scrollLeft;\n const clickY = e.clientY - rect.top + scrollTop;\n\n const worldX = clickX / zoomLevel;\n const worldY = clickY / zoomLevel;\n\n // Check visible items\n for (let i = 0; i < visibleIds.length; i++) {\n const id = visibleIds[i];\n const pos = layout.positions.get(id);\n if (pos) {\n if (worldX >= pos.x && worldX <= pos.x + cardWidth &&\n worldY >= pos.y && worldY <= pos.y + cardHeight) {\n const item = data[id];\n if (item) {\n onCardClick(item, e.nativeEvent as unknown as MouseEvent, id);\n }\n return;\n }\n }\n }\n };\n\n const handleViewportMouseMove = (e: React.MouseEvent) => {\n if (isZooming || !containerRef.current) return;\n\n const container = containerRef.current;\n const rect = container.getBoundingClientRect();\n const scrollLeft = container.scrollLeft;\n const scrollTop = container.scrollTop;\n\n const mouseX = e.clientX - rect.left + scrollLeft;\n const mouseY = e.clientY - rect.top + scrollTop;\n\n const worldX = mouseX / zoomLevel;\n const worldY = mouseY / zoomLevel;\n\n let isOverCard = false;\n for (let i = 0; i < visibleIds.length; i++) {\n const id = visibleIds[i];\n const pos = layout.positions.get(id);\n if (pos) {\n if (worldX >= pos.x && worldX <= pos.x + cardWidth &&\n worldY >= pos.y && worldY <= pos.y + cardHeight) {\n isOverCard = true;\n break;\n }\n }\n }\n\n container.style.cursor = isOverCard ? 'pointer' : 'default';\n };\n\n return isLoading ? (\n <Spinner />\n ) : (\n <div className=\"pv-groups-wrapper\">\n <div style={{ position: 'relative', flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>\n <div\n className={`pv-viewport ${isZooming ? 'pv-zooming' : ''}`}\n ref={containerRef}\n style={{ overflow: 'auto', position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}\n onClick={handleViewportClick}\n onMouseMove={handleViewportMouseMove}\n >\n {/* Spacer for scrolling - explicitly rendered to allow synchronous updates during animation */}\n <div\n ref={spacerRef}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: layout.totalWidth * zoomLevel,\n height: layout.totalHeight * zoomLevel,\n pointerEvents: 'none'\n }}\n />\n\n {!ready && (\n <div className=\"pv-loading\">Building indexes...</div>\n )}\n\n {ready && visibleIds.length === 0 && (\n <div className=\"pv-empty\">\n {emptyContent ?? 'No items to display.'}\n </div>\n )}\n\n {ready && visibleIds.length > 0 && (\n <PivotCanvas\n items={data}\n layout={layout}\n grouping={grouping}\n visibleIds={visibleIds}\n cardWidth={cardWidth}\n cardHeight={cardHeight}\n zoomLevel={zoomLevel}\n panX={scrollPosition.x}\n panY={scrollPosition.y}\n viewportWidth={containerDimensions.width}\n viewportHeight={containerDimensions.height}\n selectedId={selectedItem ? resolveId(selectedItem, 0) : null}\n hoveredGroupIndex={hoveredGroupIndex}\n isZooming={isZooming}\n cardRenderer={cardRenderer}\n resolveId={resolveId}\n onCardClick={onCardClick}\n onPanStart={onPanStart}\n onPanMove={onPanMove}\n onPanEnd={onPanEnd}\n containerRef={containerRef}\n viewMode={viewMode}\n />\n )}\n </div>\n {detailRenderer\n ? (selectedItem ? detailRenderer(selectedItem, onCloseDetail) : null)\n : (\n <DetailPanel\n selectedItem={selectedItem}\n onClose={onCloseDetail}\n />\n )}\n </div>\n\n {viewMode === 'grouped' && grouping.groups.length > 0 && (\n <AxisLabels\n groups={grouping.groups.map((g) => ({\n key: g.key,\n value: g.value,\n label: String(g.value),\n items: [],\n count: g.ids.length,\n }))}\n bucketWidths={layout.bucketWidths || []}\n zoomLevel={zoomLevel}\n dimensionFilter={dimensionFilter}\n hoveredGroup={hoveredGroupIndex !== null ? String(grouping.groups[hoveredGroupIndex]?.value) : null}\n onHover={(label) => {\n const index = grouping.groups.findIndex(g => String(g.value) === label);\n onGroupHover(index >= 0 ? index : null);\n }}\n onClick={onAxisLabelClick}\n containerRef={axisLabelsRef}\n />\n )}\n </div>\n );\n}\n"],"names":["_jsx","_jsxs"],"mappings":";;;;;;AA8CM,SAAU,eAAe,CAAuB,EACpD,IAAI,EACJ,KAAK,EACL,SAAS,EACT,UAAU,EACV,QAAQ,EACR,MAAM,EACN,SAAS,EACT,UAAU,EACV,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,SAAS,EACT,YAAY,EACZ,eAAe,EACf,WAAW,EACX,UAAU,EACV,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,SAAS,GACmB,EAAA;AAC5B,IAAA,MAAM,mBAAmB,GAAG,CAAC,CAAmB,KAAI;AAClD,QAAA,IAAI,SAAS,IAAI,CAAC,YAAY,CAAC,OAAO;YAAE;AAExC,QAAA,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO;AACtC,QAAA,MAAM,IAAI,GAAG,SAAS,CAAC,qBAAqB,EAAE;AAE9C,QAAA,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU;AACvC,QAAA,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS;QAErC,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,UAAU;QACjD,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,GAAG,SAAS;AAE/C,QAAA,MAAM,MAAM,GAAG,MAAM,GAAG,SAAS;AACjC,QAAA,MAAM,MAAM,GAAG,MAAM,GAAG,SAAS;AAGjC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC1C,YAAA,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC;YACxB,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,GAAG,EAAE;AACP,gBAAA,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS;AAC9C,oBAAA,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,EAAE;AACnD,oBAAA,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;oBACrB,IAAI,IAAI,EAAE;wBACR,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,WAAoC,EAAE,EAAE,CAAC;oBAC/D;oBACA;gBACF;YACF;QACF;AACF,IAAA,CAAC;AAED,IAAA,MAAM,uBAAuB,GAAG,CAAC,CAAmB,KAAI;AACtD,QAAA,IAAI,SAAS,IAAI,CAAC,YAAY,CAAC,OAAO;YAAE;AAExC,QAAA,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO;AACtC,QAAA,MAAM,IAAI,GAAG,SAAS,CAAC,qBAAqB,EAAE;AAC9C,QAAA,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU;AACvC,QAAA,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS;QAErC,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,UAAU;QACjD,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,GAAG,SAAS;AAE/C,QAAA,MAAM,MAAM,GAAG,MAAM,GAAG,SAAS;AACjC,QAAA,MAAM,MAAM,GAAG,MAAM,GAAG,SAAS;QAEjC,IAAI,UAAU,GAAG,KAAK;AACtB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC1C,YAAA,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC;YACxB,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,GAAG,EAAE;AACP,gBAAA,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS;AAC9C,oBAAA,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,EAAE;oBACnD,UAAU,GAAG,IAAI;oBACjB;gBACF;YACF;QACF;AAEA,QAAA,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS;AAC7D,IAAA,CAAC;IAED,OAAO,SAAS,IACdA,GAAA,CAAC,OAAO,EAAA,EAAA,CAAG,KAEXC,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,mBAAmB,EAAA,QAAA,EAAA,CAChCA,cAAK,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,EAAA,QAAA,EAAA,CACnGA,IAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,CAAA,YAAA,EAAe,SAAS,GAAG,YAAY,GAAG,EAAE,CAAA,CAAE,EACzD,GAAG,EAAE,YAAY,EACjB,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EACvF,OAAO,EAAE,mBAAmB,EAC5B,WAAW,EAAE,uBAAuB,EAAA,QAAA,EAAA,CAGpCD,GAAA,CAAA,KAAA,EAAA,EACI,GAAG,EAAE,SAAS,EACd,KAAK,EAAE;AACH,oCAAA,QAAQ,EAAE,UAAU;AACpB,oCAAA,GAAG,EAAE,CAAC;AACN,oCAAA,IAAI,EAAE,CAAC;AACP,oCAAA,KAAK,EAAE,MAAM,CAAC,UAAU,GAAG,SAAS;AACpC,oCAAA,MAAM,EAAE,MAAM,CAAC,WAAW,GAAG,SAAS;AACtC,oCAAA,aAAa,EAAE;AAClB,iCAAA,EAAA,CACH,EAED,CAAC,KAAK,KACLA,aAAK,SAAS,EAAC,YAAY,EAAA,QAAA,EAAA,qBAAA,EAAA,CAA0B,CACtD,EAEA,KAAK,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,KAC/BA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,UAAU,YACtB,YAAY,IAAI,sBAAsB,EAAA,CACnC,CACP,EAEA,KAAK,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,KAC7BA,GAAA,CAAC,WAAW,EAAA,EACV,KAAK,EAAE,IAAI,EACX,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,cAAc,CAAC,CAAC,EACtB,IAAI,EAAE,cAAc,CAAC,CAAC,EACtB,aAAa,EAAE,mBAAmB,CAAC,KAAK,EACxC,cAAc,EAAE,mBAAmB,CAAC,MAAM,EAC1C,UAAU,EAAE,YAAY,GAAG,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC,GAAG,IAAI,EAC5D,iBAAiB,EAAE,iBAAiB,EACpC,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW,EACxB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,EAAA,CAClB,CACH,CAAA,EAAA,CACG,EACL;AACC,2BAAG,YAAY,GAAG,cAAc,CAAC,YAAY,EAAE,aAAa,CAAC,GAAG,IAAI;2BAElEA,GAAA,CAAC,WAAW,IACV,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,aAAa,EAAA,CACtB,CACH,CAAA,EAAA,CACC,EAEL,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,KACnDA,GAAA,CAAC,UAAU,IACP,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;oBACpC,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,KAAK,EAAE,CAAC,CAAC,KAAK;AACd,oBAAA,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;AACtB,oBAAA,KAAK,EAAE,EAAE;AACT,oBAAA,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM;iBACpB,CAAC,CAAC,EACH,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE,EACvC,SAAS,EAAE,SAAS,EACpB,eAAe,EAAE,eAAe,EAChC,YAAY,EAAE,iBAAiB,KAAK,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,IAAI,EACnG,OAAO,EAAE,CAAC,KAAK,KAAI;oBACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC;AACvE,oBAAA,YAAY,CAAC,KAAK,IAAI,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC;AACzC,gBAAA,CAAC,EACD,OAAO,EAAE,gBAAgB,EACzB,YAAY,EAAE,aAAa,EAAA,CAC3B,CACH,CAAA,EAAA,CACG,CACP;AACH;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"visibility.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/visibility.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,MAAM,WAAW,UAAU,CAAC,KAAK;IAC7B,IAAI,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,WAAW,CAAC;IACxB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC;IAC5E,iBAAiB,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IAC7D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,QA+TrE"}
1
+ {"version":3,"file":"visibility.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/visibility.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,MAAM,WAAW,UAAU,CAAC,KAAK;IAC7B,IAAI,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,WAAW,CAAC;IACxB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC;IAC5E,iBAAiB,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IAC7D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,QA0SrE"}
@@ -5,14 +5,6 @@ function syncSpritesToViewport(params) {
5
5
  const { root, container, sprites, layout, visibleIds, items, cardWidth, cardHeight, panX, panY, panDeltaX, panDeltaY, viewportWidth, viewportHeight, createCardSprite, updateCardContent, zoomLevel, isViewTransition, prevLayout } = params;
6
6
  if (!root || !container)
7
7
  return;
8
- console.log('[syncSpritesToViewport] Called with', {
9
- layoutPositionsSize: layout.positions.size,
10
- visibleIdsSize: visibleIds.length,
11
- spritesSize: sprites.size,
12
- itemsLength: items.length,
13
- isViewTransition,
14
- zoomLevel
15
- });
16
8
  if (isViewTransition && (panDeltaX || panDeltaY)) {
17
9
  const dx = (panDeltaX || 0) / (zoomLevel || 1);
18
10
  const dy = (panDeltaY || 0) / (zoomLevel || 1);
@@ -163,22 +155,17 @@ function syncSpritesToViewport(params) {
163
155
  }
164
156
  const MAX_SPRITES_PER_FRAME = 50;
165
157
  let createdCount = 0;
166
- console.log('[syncSpritesToViewport] About to create sprites for inViewportIds:', inViewportIds.length);
167
- console.log('[syncSpritesToViewport] layout.positions IDs:', Array.from(layout.positions.keys()));
168
158
  for (const id of inViewportIds) {
169
159
  const position = layout.positions.get(id);
170
160
  if (!position) {
171
- console.log('[syncSpritesToViewport] No position for id:', id, 'in layout.positions');
172
161
  continue;
173
162
  }
174
163
  let sprite = sprites.get(id);
175
164
  if (!sprite) {
176
165
  if (createdCount >= MAX_SPRITES_PER_FRAME) {
177
- console.log('[syncSpritesToViewport] Max sprites per frame reached');
178
166
  continue;
179
167
  }
180
168
  createdCount++;
181
- console.log('[syncSpritesToViewport] Creating sprite for id:', id, 'at position:', position);
182
169
  let startX = position.x;
183
170
  let startY = position.y;
184
171
  let shouldAnimate = false;
@@ -214,10 +201,6 @@ function syncSpritesToViewport(params) {
214
201
  }
215
202
  }
216
203
  if (sprite.targetX !== position.x || sprite.targetY !== position.y) {
217
- console.log('[syncSpritesToViewport] Updating sprite target position for id:', id, 'from', {
218
- oldX: sprite.targetX,
219
- oldY: sprite.targetY
220
- }, 'to', position);
221
204
  if (isViewTransition) {
222
205
  sprite.startX = sprite.currentX;
223
206
  sprite.startY = sprite.currentY;
@@ -233,9 +216,6 @@ function syncSpritesToViewport(params) {
233
216
  delete sprite.animationDelay;
234
217
  }
235
218
  }
236
- else {
237
- console.log('[syncSpritesToViewport] Sprite position unchanged for id:', id, 'at', position);
238
- }
239
219
  const item = items[Number(id)];
240
220
  if (item) {
241
221
  updateCardContent(sprite, item);
@@ -1 +1 @@
1
- {"version":3,"file":"visibility.js","sources":["../../../../../PivotViewer/components/pivot/visibility.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 * as PIXI from 'pixi.js';\nimport type { CardSprite } from './constants';\nimport { CARD_GAP } from './constants';\nimport type { LayoutResult } from '../../engine/types';\nimport { destroySprite } from './sprites';\n\nexport interface SyncParams<TItem> {\n root: PIXI.Container | null;\n container: HTMLDivElement | null;\n sprites: Map<string | number, CardSprite>;\n layout: LayoutResult;\n visibleIds: Uint32Array;\n items: TItem[];\n cardWidth: number;\n cardHeight: number;\n panX: number;\n panY: number;\n panDeltaX?: number;\n panDeltaY?: number;\n viewportWidth: number;\n viewportHeight: number;\n zoomLevel: number;\n createCardSprite: (id: string | number, x: number, y: number) => CardSprite;\n updateCardContent: (sprite: CardSprite, item: TItem) => void;\n isViewTransition?: boolean;\n prevLayout?: LayoutResult | null;\n}\n\nexport function syncSpritesToViewport<TItem>(params: SyncParams<TItem>) {\n const { root, container, sprites, layout, visibleIds, items, cardWidth, cardHeight, panX, panY, panDeltaX, panDeltaY, viewportWidth, viewportHeight, createCardSprite, updateCardContent, zoomLevel, isViewTransition, prevLayout } = params;\n if (!root || !container) return;\n\n console.log('[syncSpritesToViewport] Called with', {\n layoutPositionsSize: layout.positions.size,\n visibleIdsSize: visibleIds.length,\n spritesSize: sprites.size,\n itemsLength: items.length,\n isViewTransition,\n zoomLevel\n });\n\n // `visibleIds` comes from callers but this module iterates `layout.positions`.\n // Keep a reference to avoid unused variable lint errors when callers include it.\n void visibleIds;\n\n // Apply pan delta to animating sprites to keep them visually stable during camera jumps\n if (isViewTransition && (panDeltaX || panDeltaY)) {\n const dx = (panDeltaX || 0) / (zoomLevel || 1);\n const dy = (panDeltaY || 0) / (zoomLevel || 1);\n\n for (const sprite of sprites.values()) {\n if (sprite.animationStartTime !== undefined) {\n if (sprite.startX !== undefined) sprite.startX += dx;\n if (sprite.startY !== undefined) sprite.startY += dy;\n sprite.currentX += dx;\n sprite.currentY += dy;\n sprite.container?.position?.set(sprite.currentX, sprite.currentY);\n }\n }\n }\n\n const visibleSet = new Set<string | number>();\n\n // Increase buffer (in world units) to reduce edge cases where rapid\n // scrolling skips sprite creation. Keep buffer in world units and convert\n // DOM pixel measurements into world coordinates below to avoid mixing\n // coordinate spaces which can cause precision drift at browser zooms.\n const baseBufferWorld = Math.max(cardWidth, cardHeight) * 4;\n // Ensure buffer scales with viewport size (in world units) so that when\n // zoomed out we still pre-create enough sprites ahead of the viewport.\n const invScale = zoomLevel && zoomLevel !== 0 ? 1 / zoomLevel : 1;\n // The layout positions are in world units; when the root container is scaled\n // (zoomed) the rendered pixel position = position * zoomLevel. The DOM\n // scroll positions (`container.scrollLeft/Top`) are the authoritative pixel\n // camera offsets; prefer them over the passed `panX/panY` to avoid stale\n // values or race conditions between React state and direct DOM updates.\n const effectivePanX = typeof container.scrollLeft === 'number' ? container.scrollLeft : (panX || 0);\n const effectivePanY = typeof container.scrollTop === 'number' ? container.scrollTop : (panY || 0);\n\n // Convert pixel-based DOM measurements into world units so we compare like\n // with like. root.position is set using -pixels, so the mapping\n // from DOM scroll (pixels) to world units is: world = pixels / zoomLevel.\n const panWorldX = effectivePanX * invScale;\n const panWorldY = effectivePanY * invScale;\n\n // Use the container's measured client size for the viewport dimensions\n // (in pixels). The passed `viewportWidth`/`viewportHeight` can be stale\n // when the browser/device zoom changes; `clientWidth/clientHeight` are\n // authoritative for the actual visible pixel area.\n const viewportPxWidth = container.clientWidth || viewportWidth;\n const viewportPxHeight = container.clientHeight || viewportHeight;\n\n const viewportWorldWidth = viewportPxWidth * invScale;\n const viewportWorldHeight = viewportPxHeight * invScale;\n\n // Ensure bufferWorld is calculated from the actual measured viewport\n // in world units (after converting client pixel dims using invScale).\n // Make buffer adaptive to zoom: when zoomed out (invScale > 1) a small\n // pixel scroll maps to a larger world delta, so increase the buffer.\n // Use the larger of width/height to ensure we buffer enough in both directions.\n const bufferWorld = Math.max(baseBufferWorld * invScale, Math.max(viewportWorldWidth, viewportWorldHeight) * 2.0, baseBufferWorld);\n\n // Do not clamp viewport edges to 0 — allow negative top/left values so the\n // visible window correctly follows the scroll even when the buffer is\n // larger than the current scroll offset.\n const viewportLeftWorld = panWorldX - bufferWorld;\n const viewportRightWorld = panWorldX + viewportWorldWidth + bufferWorld;\n const viewportTopWorld = panWorldY - bufferWorld;\n const viewportBottomWorld = panWorldY + viewportWorldHeight + bufferWorld;\n\n const inViewportIds: (string | number)[] = [];\n // Small tolerance in world units to avoid floating-point edge cases when\n // browser/device zoom or high scroll values produce tiny rounding errors.\n // Scale epsilon with invScale so tolerance grows when zoomed out.\n const worldEpsilon = Math.max(0.5, 0.5 * invScale);\n\n // Iterate layout positions directly to avoid depending on `visibleIds`\n // which may be calculated in a different coordinate space or with\n // different assumptions about zoom. Looping the positions map is\n // deterministic and uses world coordinates directly.\n for (const [id, position] of layout.positions) {\n if (!position) continue;\n const worldX = position.x;\n const worldY = position.y;\n const worldCardW = cardWidth;\n const worldCardH = cardHeight;\n\n if (\n worldX + worldCardW >= viewportLeftWorld - worldEpsilon &&\n worldX <= viewportRightWorld + worldEpsilon &&\n worldY + worldCardH >= viewportTopWorld - worldEpsilon &&\n worldY <= viewportBottomWorld + worldEpsilon\n ) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n }\n\n // Ensure last rows are present when the user scrolls near the bottom.\n // Compute slot/row information and force-insert IDs from the last few\n // rows to avoid missing tiles due to rounding/precision at zoom levels.\n try {\n const slotHeight = cardHeight + (CARD_GAP || 8);\n const totalRows = Math.ceil((layout.totalHeight || 0) / slotHeight) || 0;\n // Determine how many rows are visible in the viewport (world units),\n // then prefetch a fraction of that adjusted by zoom (invScale).\n const rowsVisible = Math.max(1, Math.ceil(viewportWorldHeight / slotHeight));\n const prefetchMultiplier = 0.75; // fraction of viewport to prefetch\n const prefetchRows = Math.max(2, Math.ceil(rowsVisible * prefetchMultiplier * Math.max(1, invScale)));\n const lastRowThresholdY = Math.max(0, (totalRows - prefetchRows) * slotHeight);\n for (const [id, position] of layout.positions) {\n if (position.y >= lastRowThresholdY) {\n if (!visibleSet.has(id)) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n }\n }\n } catch (e) {\n void e;\n }\n\n // If we detect a very large discrepancy between created sprites and the\n // computed in-viewport count, that's a signal our culling math may be\n // unstable (especially at non-100% zoom). In that case, skip hiding this\n // frame as a conservative safeguard to avoid mass disappearing tiles.\n // However, disable this safeguard during view transitions to ensure old sprites are cleaned up.\n // EXCEPT: During view transitions, if scroll position hasn't stabilized yet (e.g., switching to grouped\n // mode triggers a scroll-to-bottom), keep all sprites visible to prevent flickering\n const scrollStabilized = Math.abs(panWorldY - (container.scrollTop * invScale)) < 10;\n const aggressiveCull = (!isViewTransition && sprites.size > Math.max(120, Math.ceil(inViewportIds.length * 1.5))) || \n (isViewTransition && !scrollStabilized);\n\n for (const [id, sprite] of sprites) {\n if (!visibleSet.has(id)) {\n // If view transition is active, check if this sprite has a valid target in the new layout\n // If so, keep it visible and animate it to the new position (even if off-screen)\n if (isViewTransition && layout.positions.has(id)) {\n const newPos = layout.positions.get(id);\n if (newPos) {\n sprite.targetX = newPos.x;\n sprite.targetY = newPos.y;\n\n // Trigger animation if not already animating\n if (sprite.animationStartTime === undefined) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.animationStartTime = Date.now();\n sprite.animationDelay = Math.random() * 300;\n }\n\n try { if (sprite.container) sprite.container.visible = true; } catch (e) { void e; }\n // Don't mark as hidden, so it won't be swept\n if ((sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt) delete (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n continue;\n }\n }\n\n if (aggressiveCull) {\n // Keep sprite visible this frame to avoid visual holes\n try { if (sprite.container) sprite.container.visible = true; } catch (e) { void e; }\n continue;\n }\n\n try {\n if (sprite.container) {\n sprite.container.visible = false;\n }\n (sprite as unknown as { __lastHiddenAt: number }).__lastHiddenAt = Date.now();\n } catch (e) {\n void e;\n }\n } else {\n try {\n if (sprite.container) {\n sprite.container.visible = true;\n }\n if ((sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt) delete (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n } catch (e) { void e; }\n }\n }\n\n // Sweep: actually destroy sprites that have been hidden longer than threshold\n try {\n const SWEEP_MS = 100; // keep hidden sprites for 100ms before destruction (reduced from 500ms for faster mode transitions)\n const now = Date.now();\n for (const [id, sprite] of sprites) {\n const lastHidden = (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n if (lastHidden && now - lastHidden > SWEEP_MS) {\n try {\n // remove from parent if present\n if (sprite.container && sprite.container.parent) sprite.container.parent.removeChild(sprite.container);\n } catch (e) {\n void e;\n }\n try {\n destroySprite(sprite);\n } catch (e) {\n void e;\n }\n sprites.delete(id);\n }\n }\n } catch (e) {\n void e;\n }\n\n // Limit the number of sprites created per frame to avoid choking the GPU/CPU\n // when scrolling rapidly or zooming out significantly.\n const MAX_SPRITES_PER_FRAME = 50;\n let createdCount = 0;\n\n console.log('[syncSpritesToViewport] About to create sprites for inViewportIds:', inViewportIds.length);\n console.log('[syncSpritesToViewport] layout.positions IDs:', Array.from(layout.positions.keys()));\n\n for (const id of inViewportIds) {\n const position = layout.positions.get(id);\n if (!position) {\n console.log('[syncSpritesToViewport] No position for id:', id, 'in layout.positions');\n continue;\n }\n\n let sprite = sprites.get(id);\n if (!sprite) {\n if (createdCount >= MAX_SPRITES_PER_FRAME) {\n console.log('[syncSpritesToViewport] Max sprites per frame reached');\n continue;\n }\n createdCount++;\n\n console.log('[syncSpritesToViewport] Creating sprite for id:', id, 'at position:', position);\n\n let startX = position.x;\n let startY = position.y;\n let shouldAnimate = false;\n\n // If view transition, try to find old position to fly in from\n if (isViewTransition && prevLayout && prevLayout.positions.has(id)) {\n const oldPos = prevLayout.positions.get(id);\n if (oldPos) {\n startX = oldPos.x;\n startY = oldPos.y;\n\n // If we have a pan delta (camera jump), we need to adjust the start position\n // so that the sprite appears at the same visual location relative to the NEW camera.\n // StartWorld = OldWorld + PanDelta\n if (panDeltaX || panDeltaY) {\n const dx = (panDeltaX || 0) / (zoomLevel || 1);\n const dy = (panDeltaY || 0) / (zoomLevel || 1);\n startX += dx;\n startY += dy;\n }\n\n shouldAnimate = true;\n }\n }\n\n sprite = createCardSprite(id, startX, startY);\n sprites.set(id, sprite);\n if (sprite.container) {\n root.addChild(sprite.container);\n sprite.currentX = startX;\n sprite.currentY = startY;\n // Keep sprite.container positioned in world units; animation/update\n // loop will apply root.scale/position to convert to pixels.\n sprite.container.position.set(startX, startY);\n }\n\n if (shouldAnimate) {\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n sprite.startX = startX;\n sprite.startY = startY;\n sprite.animationStartTime = Date.now();\n sprite.animationDelay = Math.random() * 300;\n }\n }\n\n // Check if target changed to trigger animation\n if (sprite.targetX !== position.x || sprite.targetY !== position.y) {\n console.log('[syncSpritesToViewport] Updating sprite target position for id:', id, 'from', {\n oldX: sprite.targetX,\n oldY: sprite.targetY\n }, 'to', position);\n if (isViewTransition) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n sprite.animationStartTime = Date.now();\n // Add random delay for \"organic\" fly effect\n sprite.animationDelay = Math.random() * 300;\n } else {\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n delete sprite.animationStartTime;\n delete sprite.animationDelay;\n }\n } else {\n console.log('[syncSpritesToViewport] Sprite position unchanged for id:', id, 'at', position);\n }\n\n const item = items[Number(id)];\n if (item) {\n updateCardContent(sprite, item);\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"visibility.js","sources":["../../../../../PivotViewer/components/pivot/visibility.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 * as PIXI from 'pixi.js';\nimport type { CardSprite } from './constants';\nimport { CARD_GAP } from './constants';\nimport type { LayoutResult } from '../../engine/types';\nimport { destroySprite } from './sprites';\n\nexport interface SyncParams<TItem> {\n root: PIXI.Container | null;\n container: HTMLDivElement | null;\n sprites: Map<string | number, CardSprite>;\n layout: LayoutResult;\n visibleIds: Uint32Array;\n items: TItem[];\n cardWidth: number;\n cardHeight: number;\n panX: number;\n panY: number;\n panDeltaX?: number;\n panDeltaY?: number;\n viewportWidth: number;\n viewportHeight: number;\n zoomLevel: number;\n createCardSprite: (id: string | number, x: number, y: number) => CardSprite;\n updateCardContent: (sprite: CardSprite, item: TItem) => void;\n isViewTransition?: boolean;\n prevLayout?: LayoutResult | null;\n}\n\nexport function syncSpritesToViewport<TItem>(params: SyncParams<TItem>) {\n const { root, container, sprites, layout, visibleIds, items, cardWidth, cardHeight, panX, panY, panDeltaX, panDeltaY, viewportWidth, viewportHeight, createCardSprite, updateCardContent, zoomLevel, isViewTransition, prevLayout } = params;\n if (!root || !container) return;\n\n // `visibleIds` comes from callers but this module iterates `layout.positions`.\n // Keep a reference to avoid unused variable lint errors when callers include it.\n void visibleIds;\n\n // Apply pan delta to animating sprites to keep them visually stable during camera jumps\n if (isViewTransition && (panDeltaX || panDeltaY)) {\n const dx = (panDeltaX || 0) / (zoomLevel || 1);\n const dy = (panDeltaY || 0) / (zoomLevel || 1);\n\n for (const sprite of sprites.values()) {\n if (sprite.animationStartTime !== undefined) {\n if (sprite.startX !== undefined) sprite.startX += dx;\n if (sprite.startY !== undefined) sprite.startY += dy;\n sprite.currentX += dx;\n sprite.currentY += dy;\n sprite.container?.position?.set(sprite.currentX, sprite.currentY);\n }\n }\n }\n\n const visibleSet = new Set<string | number>();\n\n // Increase buffer (in world units) to reduce edge cases where rapid\n // scrolling skips sprite creation. Keep buffer in world units and convert\n // DOM pixel measurements into world coordinates below to avoid mixing\n // coordinate spaces which can cause precision drift at browser zooms.\n const baseBufferWorld = Math.max(cardWidth, cardHeight) * 4;\n // Ensure buffer scales with viewport size (in world units) so that when\n // zoomed out we still pre-create enough sprites ahead of the viewport.\n const invScale = zoomLevel && zoomLevel !== 0 ? 1 / zoomLevel : 1;\n // The layout positions are in world units; when the root container is scaled\n // (zoomed) the rendered pixel position = position * zoomLevel. The DOM\n // scroll positions (`container.scrollLeft/Top`) are the authoritative pixel\n // camera offsets; prefer them over the passed `panX/panY` to avoid stale\n // values or race conditions between React state and direct DOM updates.\n const effectivePanX = typeof container.scrollLeft === 'number' ? container.scrollLeft : (panX || 0);\n const effectivePanY = typeof container.scrollTop === 'number' ? container.scrollTop : (panY || 0);\n\n // Convert pixel-based DOM measurements into world units so we compare like\n // with like. root.position is set using -pixels, so the mapping\n // from DOM scroll (pixels) to world units is: world = pixels / zoomLevel.\n const panWorldX = effectivePanX * invScale;\n const panWorldY = effectivePanY * invScale;\n\n // Use the container's measured client size for the viewport dimensions\n // (in pixels). The passed `viewportWidth`/`viewportHeight` can be stale\n // when the browser/device zoom changes; `clientWidth/clientHeight` are\n // authoritative for the actual visible pixel area.\n const viewportPxWidth = container.clientWidth || viewportWidth;\n const viewportPxHeight = container.clientHeight || viewportHeight;\n\n const viewportWorldWidth = viewportPxWidth * invScale;\n const viewportWorldHeight = viewportPxHeight * invScale;\n\n // Ensure bufferWorld is calculated from the actual measured viewport\n // in world units (after converting client pixel dims using invScale).\n // Make buffer adaptive to zoom: when zoomed out (invScale > 1) a small\n // pixel scroll maps to a larger world delta, so increase the buffer.\n // Use the larger of width/height to ensure we buffer enough in both directions.\n const bufferWorld = Math.max(baseBufferWorld * invScale, Math.max(viewportWorldWidth, viewportWorldHeight) * 2.0, baseBufferWorld);\n\n // Do not clamp viewport edges to 0 — allow negative top/left values so the\n // visible window correctly follows the scroll even when the buffer is\n // larger than the current scroll offset.\n const viewportLeftWorld = panWorldX - bufferWorld;\n const viewportRightWorld = panWorldX + viewportWorldWidth + bufferWorld;\n const viewportTopWorld = panWorldY - bufferWorld;\n const viewportBottomWorld = panWorldY + viewportWorldHeight + bufferWorld;\n\n const inViewportIds: (string | number)[] = [];\n // Small tolerance in world units to avoid floating-point edge cases when\n // browser/device zoom or high scroll values produce tiny rounding errors.\n // Scale epsilon with invScale so tolerance grows when zoomed out.\n const worldEpsilon = Math.max(0.5, 0.5 * invScale);\n\n // Iterate layout positions directly to avoid depending on `visibleIds`\n // which may be calculated in a different coordinate space or with\n // different assumptions about zoom. Looping the positions map is\n // deterministic and uses world coordinates directly.\n for (const [id, position] of layout.positions) {\n if (!position) continue;\n const worldX = position.x;\n const worldY = position.y;\n const worldCardW = cardWidth;\n const worldCardH = cardHeight;\n\n if (\n worldX + worldCardW >= viewportLeftWorld - worldEpsilon &&\n worldX <= viewportRightWorld + worldEpsilon &&\n worldY + worldCardH >= viewportTopWorld - worldEpsilon &&\n worldY <= viewportBottomWorld + worldEpsilon\n ) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n }\n\n // Ensure last rows are present when the user scrolls near the bottom.\n // Compute slot/row information and force-insert IDs from the last few\n // rows to avoid missing tiles due to rounding/precision at zoom levels.\n try {\n const slotHeight = cardHeight + (CARD_GAP || 8);\n const totalRows = Math.ceil((layout.totalHeight || 0) / slotHeight) || 0;\n // Determine how many rows are visible in the viewport (world units),\n // then prefetch a fraction of that adjusted by zoom (invScale).\n const rowsVisible = Math.max(1, Math.ceil(viewportWorldHeight / slotHeight));\n const prefetchMultiplier = 0.75; // fraction of viewport to prefetch\n const prefetchRows = Math.max(2, Math.ceil(rowsVisible * prefetchMultiplier * Math.max(1, invScale)));\n const lastRowThresholdY = Math.max(0, (totalRows - prefetchRows) * slotHeight);\n for (const [id, position] of layout.positions) {\n if (position.y >= lastRowThresholdY) {\n if (!visibleSet.has(id)) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n }\n }\n } catch (e) {\n void e;\n }\n\n // If we detect a very large discrepancy between created sprites and the\n // computed in-viewport count, that's a signal our culling math may be\n // unstable (especially at non-100% zoom). In that case, skip hiding this\n // frame as a conservative safeguard to avoid mass disappearing tiles.\n // However, disable this safeguard during view transitions to ensure old sprites are cleaned up.\n // EXCEPT: During view transitions, if scroll position hasn't stabilized yet (e.g., switching to grouped\n // mode triggers a scroll-to-bottom), keep all sprites visible to prevent flickering\n const scrollStabilized = Math.abs(panWorldY - (container.scrollTop * invScale)) < 10;\n const aggressiveCull = (!isViewTransition && sprites.size > Math.max(120, Math.ceil(inViewportIds.length * 1.5))) || \n (isViewTransition && !scrollStabilized);\n\n for (const [id, sprite] of sprites) {\n if (!visibleSet.has(id)) {\n // If view transition is active, check if this sprite has a valid target in the new layout\n // If so, keep it visible and animate it to the new position (even if off-screen)\n if (isViewTransition && layout.positions.has(id)) {\n const newPos = layout.positions.get(id);\n if (newPos) {\n sprite.targetX = newPos.x;\n sprite.targetY = newPos.y;\n\n // Trigger animation if not already animating\n if (sprite.animationStartTime === undefined) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.animationStartTime = Date.now();\n sprite.animationDelay = Math.random() * 300;\n }\n\n try { if (sprite.container) sprite.container.visible = true; } catch (e) { void e; }\n // Don't mark as hidden, so it won't be swept\n if ((sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt) delete (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n continue;\n }\n }\n\n if (aggressiveCull) {\n // Keep sprite visible this frame to avoid visual holes\n try { if (sprite.container) sprite.container.visible = true; } catch (e) { void e; }\n continue;\n }\n\n try {\n if (sprite.container) {\n sprite.container.visible = false;\n }\n (sprite as unknown as { __lastHiddenAt: number }).__lastHiddenAt = Date.now();\n } catch (e) {\n void e;\n }\n } else {\n try {\n if (sprite.container) {\n sprite.container.visible = true;\n }\n if ((sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt) delete (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n } catch (e) { void e; }\n }\n }\n\n // Sweep: actually destroy sprites that have been hidden longer than threshold\n try {\n const SWEEP_MS = 100; // keep hidden sprites for 100ms before destruction (reduced from 500ms for faster mode transitions)\n const now = Date.now();\n for (const [id, sprite] of sprites) {\n const lastHidden = (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n if (lastHidden && now - lastHidden > SWEEP_MS) {\n try {\n // remove from parent if present\n if (sprite.container && sprite.container.parent) sprite.container.parent.removeChild(sprite.container);\n } catch (e) {\n void e;\n }\n try {\n destroySprite(sprite);\n } catch (e) {\n void e;\n }\n sprites.delete(id);\n }\n }\n } catch (e) {\n void e;\n }\n\n // Limit the number of sprites created per frame to avoid choking the GPU/CPU\n // when scrolling rapidly or zooming out significantly.\n const MAX_SPRITES_PER_FRAME = 50;\n let createdCount = 0;\n\n\n for (const id of inViewportIds) {\n const position = layout.positions.get(id);\n if (!position) {\n continue;\n }\n\n let sprite = sprites.get(id);\n if (!sprite) {\n if (createdCount >= MAX_SPRITES_PER_FRAME) {\n continue;\n }\n createdCount++;\n\n let startX = position.x;\n let startY = position.y;\n let shouldAnimate = false;\n\n // If view transition, try to find old position to fly in from\n if (isViewTransition && prevLayout && prevLayout.positions.has(id)) {\n const oldPos = prevLayout.positions.get(id);\n if (oldPos) {\n startX = oldPos.x;\n startY = oldPos.y;\n\n // If we have a pan delta (camera jump), we need to adjust the start position\n // so that the sprite appears at the same visual location relative to the NEW camera.\n // StartWorld = OldWorld + PanDelta\n if (panDeltaX || panDeltaY) {\n const dx = (panDeltaX || 0) / (zoomLevel || 1);\n const dy = (panDeltaY || 0) / (zoomLevel || 1);\n startX += dx;\n startY += dy;\n }\n\n shouldAnimate = true;\n }\n }\n\n sprite = createCardSprite(id, startX, startY);\n sprites.set(id, sprite);\n if (sprite.container) {\n root.addChild(sprite.container);\n sprite.currentX = startX;\n sprite.currentY = startY;\n // Keep sprite.container positioned in world units; animation/update\n // loop will apply root.scale/position to convert to pixels.\n sprite.container.position.set(startX, startY);\n }\n\n if (shouldAnimate) {\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n sprite.startX = startX;\n sprite.startY = startY;\n sprite.animationStartTime = Date.now();\n sprite.animationDelay = Math.random() * 300;\n }\n }\n\n // Check if target changed to trigger animation\n if (sprite.targetX !== position.x || sprite.targetY !== position.y) {\n if (isViewTransition) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n sprite.animationStartTime = Date.now();\n // Add random delay for \"organic\" fly effect\n sprite.animationDelay = Math.random() * 300;\n } else {\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n delete sprite.animationStartTime;\n delete sprite.animationDelay;\n }\n }\n\n const item = items[Number(id)];\n if (item) {\n updateCardContent(sprite, item);\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pivot.worker.d.ts","sourceRoot":"","sources":["../../../../PivotViewer/engine/pivot.worker.ts"],"names":[],"mappings":"AAyGA,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"pivot.worker.d.ts","sourceRoot":"","sources":["../../../../PivotViewer/engine/pivot.worker.ts"],"names":[],"mappings":"AA+FA,OAAO,EAAE,CAAC"}
@@ -3,25 +3,20 @@ let store = null;
3
3
  let indexes = null;
4
4
  self.onmessage = (e) => {
5
5
  const message = e.data;
6
- console.log('[Worker] Received message:', message.type);
7
6
  switch (message.type) {
8
7
  case 'buildIndexes': {
9
- console.log('[Worker] Building indexes for', message.store.items.length, 'items');
10
8
  const fieldsArray = message.store.fields;
11
9
  const fieldsMap = new Map(fieldsArray);
12
10
  store = {
13
11
  ...message.store,
14
12
  fields: fieldsMap,
15
13
  };
16
- console.log('[Worker] Store converted, fields:', Array.from(fieldsMap.keys()));
17
14
  if (store) {
18
15
  indexes = buildIndexes(store, message.fields);
19
- console.log('[Worker] Indexes built');
20
16
  const response = {
21
17
  type: 'indexesReady',
22
18
  indexes,
23
19
  };
24
- console.log('[Worker] Posting indexesReady');
25
20
  self.postMessage(response);
26
21
  }
27
22
  break;
@@ -44,14 +39,11 @@ self.onmessage = (e) => {
44
39
  console.error('[Worker] Store or indexes not initialized');
45
40
  return;
46
41
  }
47
- console.log('[Worker] Computing grouping for', message.visibleIds.length, 'items, groupBy:', message.groupBy);
48
42
  const result = computeGrouping(store, indexes, message.visibleIds, message.groupBy);
49
- console.log('[Worker] Grouping computed:', result.groups.length, 'groups');
50
43
  const response = {
51
44
  type: 'groupingResult',
52
45
  result,
53
46
  };
54
- console.log('[Worker] Posting groupingResult');
55
47
  self.postMessage(response);
56
48
  break;
57
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pivot.worker.js","sourceRoot":"","sources":["../../../../PivotViewer/engine/pivot.worker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pivot.worker.js","sourceRoot":"","sources":["../../../../PivotViewer/engine/pivot.worker.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAE/E,IAAI,KAAK,GAAsB,IAAI,CAAC;AACpC,IAAI,OAAO,GAAwB,IAAI,CAAC;AAExC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAgC,EAAE,EAAE;IACpD,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC;IAEvB,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,KAAK,cAAc,CAAC,CAAC,CAAC;YAEpB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,MAAsC,CAAC;YACzE,MAAM,SAAS,GAAG,IAAI,GAAG,CAAgB,WAAW,CAAC,CAAC;YAEtD,KAAK,GAAG;gBACN,GAAG,OAAO,CAAC,KAAK;gBAChB,MAAM,EAAE,SAAS;aAClB,CAAC;YACF,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBAE9C,MAAM,QAAQ,GAAqB;oBACjC,IAAI,EAAE,cAAc;oBACpB,OAAO;iBACR,CAAC;gBACF,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAC7B,CAAC;YACD,MAAM;QACR,CAAC;QAED,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;gBACvB,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;gBAClD,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YAE7D,MAAM,QAAQ,GAAqB;gBACjC,IAAI,EAAE,cAAc;gBACpB,MAAM;aACP,CAAC;YACF,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAC3B,MAAM;QACR,CAAC;QAED,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;gBACvB,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;gBAC3D,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,eAAe,CAC5B,KAAK,EACL,OAAO,EACP,OAAO,CAAC,UAAU,EAClB,OAAO,CAAC,OAAO,CAChB,CAAC;YAEF,MAAM,QAAQ,GAAqB;gBACjC,IAAI,EAAE,gBAAgB;gBACtB,MAAM;aACP,CAAC;YACF,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAC3B,MAAM;QACR,CAAC;QAED,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;gBACvC,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAE3D,MAAM,QAAQ,GAAqB;gBACjC,IAAI,EAAE,YAAY;gBAClB,MAAM;aACP,CAAC;YACF,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YAC3B,MAAM;QACR,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePivotEngine.d.ts","sourceRoot":"","sources":["../../../../PivotViewer/hooks/usePivotEngine.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,UAAU,EACV,YAAY,EACZ,SAAS,EACT,cAAc,EAGd,UAAU,EACX,MAAM,iBAAiB,CAAC;AAGzB,MAAM,WAAW,qBAAqB,CAAC,KAAK,SAAS,MAAM;IACzD,IAAI,EAAE,KAAK,EAAE,CAAC;IACd,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,UAAU,CAAC,CAAC;IAC1D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1F,OAAO,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CAC5E;AAED,wBAAgB,cAAc,CAAC,KAAK,SAAS,MAAM,EAAE,EACnD,IAAI,EACJ,eAAe,EACf,WAAW,GACZ,EAAE,qBAAqB,CAAC,KAAK,CAAC,GAAG,oBAAoB,CA8RrD"}
1
+ {"version":3,"file":"usePivotEngine.d.ts","sourceRoot":"","sources":["../../../../PivotViewer/hooks/usePivotEngine.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,UAAU,EACV,YAAY,EACZ,SAAS,EACT,cAAc,EAGd,UAAU,EACX,MAAM,iBAAiB,CAAC;AAGzB,MAAM,WAAW,qBAAqB,CAAC,KAAK,SAAS,MAAM;IACzD,IAAI,EAAE,KAAK,EAAE,CAAC;IACd,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,UAAU,CAAC,CAAC;IAC1D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1F,OAAO,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;CAC5E;AAED,wBAAgB,cAAc,CAAC,KAAK,SAAS,MAAM,EAAE,EACnD,IAAI,EACJ,eAAe,EACf,WAAW,GACZ,EAAE,qBAAqB,CAAC,KAAK,CAAC,GAAG,oBAAoB,CAiQrD"}
@@ -11,7 +11,6 @@ function usePivotEngine({ data, fieldExtractors, indexFields, }) {
11
11
  const pendingCallbacksRef = useRef(new Map());
12
12
  useEffect(() => {
13
13
  if (typeof window === 'undefined' || typeof Worker === 'undefined') {
14
- console.warn('[PivotEngine] Worker not supported in this environment, using main thread');
15
14
  fallbackRef.current = true;
16
15
  setWorkerAvailable(false);
17
16
  return;
@@ -29,68 +28,49 @@ function usePivotEngine({ data, fieldExtractors, indexFields, }) {
29
28
  const response = await fetch(workerUrl, { method: 'HEAD' });
30
29
  const contentType = response.headers.get('content-type') ?? '';
31
30
  if (!response.ok || !contentType.includes('javascript')) {
32
- console.warn('[PivotEngine] Worker asset not reachable, using main thread');
33
31
  enableFallback();
34
32
  return;
35
33
  }
36
34
  }
37
35
  }
38
- catch (error) {
39
- console.warn('[PivotEngine] Worker preflight failed, using main thread', error);
36
+ catch {
40
37
  enableFallback();
41
38
  return;
42
39
  }
43
40
  if (disposed) {
44
41
  return;
45
42
  }
46
- console.log('[PivotEngine] Creating worker');
47
43
  const worker = new Worker(workerUrl, { type: 'module' });
48
44
  workerRef.current = worker;
49
45
  setWorkerAvailable(true);
50
- console.log('[PivotEngine] Worker created, setting up message handlers');
51
46
  worker.onmessage = (e) => {
52
47
  const message = e.data;
53
- console.log('[PivotEngine] Received message from worker:', message.type);
54
48
  switch (message.type) {
55
49
  case 'indexesReady':
56
- console.log('[PivotEngine] Indexes ready');
57
50
  setReady(true);
58
51
  break;
59
52
  case 'filterResult': {
60
53
  const callback = pendingCallbacksRef.current.get('filter');
61
54
  if (callback) {
62
- console.log('[PivotEngine] Calling filter callback and deleting');
63
55
  callback(message.result);
64
56
  pendingCallbacksRef.current.delete('filter');
65
57
  }
66
- else {
67
- console.warn('[PivotEngine] No callback registered for filter result - ignoring duplicate message');
68
- }
69
58
  break;
70
59
  }
71
60
  case 'groupingResult': {
72
- console.log('[PivotEngine] Received groupingResult:', message.result);
73
61
  const callback = pendingCallbacksRef.current.get('grouping');
74
62
  if (callback) {
75
- console.log('[PivotEngine] Calling grouping callback and deleting');
76
63
  callback(message.result);
77
64
  pendingCallbacksRef.current.delete('grouping');
78
65
  }
79
- else {
80
- console.warn('[PivotEngine] No callback registered for grouping result - ignoring duplicate message');
81
- }
82
66
  break;
83
67
  }
84
68
  case 'sortResult': {
85
69
  const callback = pendingCallbacksRef.current.get('sort');
86
70
  if (callback) {
87
- console.log('[PivotEngine] Calling sort callback and deleting');
88
71
  callback(message.result);
89
72
  pendingCallbacksRef.current.delete('sort');
90
73
  }
91
- else {
92
- console.warn('[PivotEngine] No callback registered for sort result - ignoring duplicate message');
93
- }
94
74
  break;
95
75
  }
96
76
  }
@@ -118,11 +98,9 @@ function usePivotEngine({ data, fieldExtractors, indexFields, }) {
118
98
  };
119
99
  }, [indexFields]);
120
100
  useEffect(() => {
121
- console.log('[PivotEngine] Building indexes for', data.length, 'items');
122
101
  setReady(false);
123
102
  const store = buildStore(data, fieldExtractors);
124
103
  storeRef.current = store;
125
- console.log('[PivotEngine] Store built with', store.items.length, 'items and', store.fields.size, 'fields');
126
104
  try {
127
105
  indexesRef.current = buildIndexes(store, indexFields);
128
106
  }
@@ -141,7 +119,6 @@ function usePivotEngine({ data, fieldExtractors, indexFields, }) {
141
119
  store: serializableStore,
142
120
  fields: indexFields,
143
121
  };
144
- console.log('[PivotEngine] Posting buildIndexes with', fieldsArray.length, 'fields');
145
122
  workerRef.current.postMessage(message);
146
123
  }
147
124
  else {
@@ -175,20 +152,16 @@ function usePivotEngine({ data, fieldExtractors, indexFields, }) {
175
152
  });
176
153
  }, [ready]);
177
154
  const computeGroupingCallback = useCallback((visibleIds, groupBy) => {
178
- console.log('[PivotEngine] computeGroupingCallback called with', visibleIds.length, 'visibleIds');
179
155
  if (pendingCallbacksRef.current.has('grouping')) {
180
- console.warn('[PivotEngine] Grouping already in progress, ignoring duplicate request');
181
156
  return Promise.resolve({ groups: [] });
182
157
  }
183
158
  return new Promise((resolve) => {
184
159
  if (!workerRef.current || fallbackRef.current) {
185
- console.log('[PivotEngine] Using synchronous fallback for grouping');
186
160
  try {
187
161
  const store = storeRef.current;
188
162
  const indexes = indexesRef.current;
189
163
  if (store && indexes) {
190
164
  const result = computeGrouping(store, indexes, visibleIds, groupBy);
191
- console.log('[PivotEngine] Fallback grouping result:', result);
192
165
  resolve(result);
193
166
  return;
194
167
  }
@@ -196,11 +169,9 @@ function usePivotEngine({ data, fieldExtractors, indexFields, }) {
196
169
  catch (e) {
197
170
  console.error('[PivotEngine] fallback computeGrouping error:', e);
198
171
  }
199
- console.warn('[PivotEngine] No store/indexes for fallback, returning empty');
200
172
  resolve({ groups: [] });
201
173
  return;
202
174
  }
203
- console.log('[PivotEngine] Setting grouping callback and posting to worker');
204
175
  pendingCallbacksRef.current.set('grouping', resolve);
205
176
  const message = {
206
177
  type: 'computeGrouping',
@@ -208,7 +179,6 @@ function usePivotEngine({ data, fieldExtractors, indexFields, }) {
208
179
  groupBy,
209
180
  };
210
181
  workerRef.current.postMessage(message);
211
- console.log('[PivotEngine] Message posted to worker');
212
182
  });
213
183
  }, [ready]);
214
184
  const sortIdsCallback = useCallback((visibleIds, sortBy) => {
@@ -1 +1 @@
1
- {"version":3,"file":"usePivotEngine.js","sources":["../../../../PivotViewer/hooks/usePivotEngine.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, useRef, useState, useCallback } from 'react';\nimport type {\n PivotStore,\n PivotIndexes,\n FilterSpec,\n FilterResult,\n GroupSpec,\n GroupingResult,\n WorkerInMessage,\n WorkerOutMessage,\n FieldValue,\n} from '../engine/types';\nimport { buildStore, buildIndexes, applyFilters, computeGrouping, sortIds } from '../engine/store';\n\nexport interface UsePivotEngineOptions<TItem extends object> {\n data: TItem[];\n fieldExtractors: Map<string, (item: TItem) => FieldValue>;\n indexFields: string[];\n}\n\nexport interface UsePivotEngineResult {\n ready: boolean;\n applyFilters: (filters: FilterSpec[]) => Promise<FilterResult>;\n computeGrouping: (visibleIds: Uint32Array, groupBy: GroupSpec) => Promise<GroupingResult>;\n sortIds: (visibleIds: Uint32Array, sortBy: string) => Promise<Uint32Array>;\n}\n\nexport function usePivotEngine<TItem extends object>({\n data,\n fieldExtractors,\n indexFields,\n}: UsePivotEngineOptions<TItem>): UsePivotEngineResult {\n const [ready, setReady] = useState(false);\n const [workerAvailable, setWorkerAvailable] = useState(false);\n const workerRef = useRef<Worker | null>(null);\n const indexesRef = useRef<PivotIndexes | null>(null);\n const fallbackRef = useRef(false);\n const storeRef = useRef<PivotStore | null>(null);\n const pendingCallbacksRef = useRef<Map<string, (result: unknown) => void>>(new Map());\n\n useEffect(() => {\n if (typeof window === 'undefined' || typeof Worker === 'undefined') {\n console.warn('[PivotEngine] Worker not supported in this environment, using main thread');\n fallbackRef.current = true;\n setWorkerAvailable(false);\n return;\n }\n\n const workerUrl = new URL('../engine/pivot.worker.js', import.meta.url);\n let disposed = false;\n\n const enableFallback = () => {\n fallbackRef.current = true;\n workerRef.current = null;\n setWorkerAvailable(false);\n };\n\n const setupWorker = async () => {\n try {\n if (typeof fetch === 'function') {\n const response = await fetch(workerUrl, { method: 'HEAD' });\n const contentType = response.headers.get('content-type') ?? '';\n\n if (!response.ok || !contentType.includes('javascript')) {\n console.warn('[PivotEngine] Worker asset not reachable, using main thread');\n enableFallback();\n return;\n }\n }\n } catch (error) {\n console.warn('[PivotEngine] Worker preflight failed, using main thread', error);\n enableFallback();\n return;\n }\n\n if (disposed) {\n return;\n }\n\n console.log('[PivotEngine] Creating worker');\n const worker = new Worker(workerUrl, { type: 'module' });\n\n workerRef.current = worker;\n setWorkerAvailable(true);\n console.log('[PivotEngine] Worker created, setting up message handlers');\n\n worker.onmessage = (e: MessageEvent<WorkerOutMessage>) => {\n const message = e.data;\n console.log('[PivotEngine] Received message from worker:', message.type);\n\n switch (message.type) {\n case 'indexesReady':\n console.log('[PivotEngine] Indexes ready');\n setReady(true);\n break;\n\n case 'filterResult': {\n const callback = pendingCallbacksRef.current.get('filter');\n if (callback) {\n console.log('[PivotEngine] Calling filter callback and deleting');\n callback(message.result);\n pendingCallbacksRef.current.delete('filter');\n } else {\n console.warn('[PivotEngine] No callback registered for filter result - ignoring duplicate message');\n }\n break;\n }\n\n case 'groupingResult': {\n console.log('[PivotEngine] Received groupingResult:', message.result);\n const callback = pendingCallbacksRef.current.get('grouping');\n if (callback) {\n console.log('[PivotEngine] Calling grouping callback and deleting');\n callback(message.result);\n pendingCallbacksRef.current.delete('grouping');\n } else {\n console.warn('[PivotEngine] No callback registered for grouping result - ignoring duplicate message');\n }\n break;\n }\n\n case 'sortResult': {\n const callback = pendingCallbacksRef.current.get('sort');\n if (callback) {\n console.log('[PivotEngine] Calling sort callback and deleting');\n callback(message.result);\n pendingCallbacksRef.current.delete('sort');\n } else {\n console.warn('[PivotEngine] No callback registered for sort result - ignoring duplicate message');\n }\n break;\n }\n }\n };\n\n worker.onerror = (error) => {\n console.error('[PivotEngine] Worker error:', error);\n enableFallback();\n if (storeRef.current) {\n try {\n indexesRef.current = buildIndexes(storeRef.current, indexFields);\n } catch (e) {\n console.error('[PivotEngine] Failed to build indexes in fallback:', e);\n indexesRef.current = null;\n }\n setReady(true);\n }\n };\n };\n\n void setupWorker();\n\n return () => {\n disposed = true;\n workerRef.current?.terminate();\n workerRef.current = null;\n };\n }, [indexFields]);\n\n useEffect(() => {\n console.log('[PivotEngine] Building indexes for', data.length, 'items');\n setReady(false);\n\n const store = buildStore(data, fieldExtractors);\n storeRef.current = store;\n console.log('[PivotEngine] Store built with', store.items.length, 'items and', store.fields.size, 'fields');\n\n try {\n indexesRef.current = buildIndexes(store, indexFields);\n } catch (e) {\n console.error('[PivotEngine] buildIndexes failed:', e);\n indexesRef.current = null;\n }\n\n if (workerRef.current && !fallbackRef.current) {\n const fieldsArray = Array.from(store.fields.entries());\n const serializableStore = {\n ...store,\n fields: fieldsArray,\n };\n\n const message: WorkerInMessage = {\n type: 'buildIndexes',\n store: serializableStore as unknown as PivotStore,\n fields: indexFields,\n };\n\n console.log('[PivotEngine] Posting buildIndexes with', fieldsArray.length, 'fields');\n workerRef.current.postMessage(message);\n } else {\n setReady(true);\n }\n }, [data, fieldExtractors, indexFields, workerAvailable]);\n\n const applyFiltersCallback = useCallback(\n (filters: FilterSpec[]): Promise<FilterResult> => {\n return new Promise((resolve) => {\n // If worker is not available, use synchronous fallback using local indexes\n if (!workerRef.current || fallbackRef.current) {\n try {\n const store = storeRef.current;\n const indexes = indexesRef.current;\n if (store && indexes) {\n const result = applyFilters(store, indexes, filters);\n resolve(result);\n return;\n }\n } catch (e) {\n console.error('[PivotEngine] fallback applyFilters error:', e);\n }\n\n // if fallback not possible, return empty result\n resolve({ visibleIds: new Uint32Array(0), count: 0 });\n return;\n }\n\n pendingCallbacksRef.current.set('filter', resolve as (result: unknown) => void);\n\n const message: WorkerInMessage = {\n type: 'applyFilters',\n filters,\n };\n\n workerRef.current.postMessage(message);\n });\n },\n [ready]\n );\n\n const computeGroupingCallback = useCallback(\n (visibleIds: Uint32Array, groupBy: GroupSpec): Promise<GroupingResult> => {\n console.log('[PivotEngine] computeGroupingCallback called with', visibleIds.length, 'visibleIds');\n \n // Check if there's already a pending grouping request\n if (pendingCallbacksRef.current.has('grouping')) {\n console.warn('[PivotEngine] Grouping already in progress, ignoring duplicate request');\n return Promise.resolve({ groups: [] });\n }\n \n return new Promise((resolve) => {\n // synchronous fallback if worker unavailable\n if (!workerRef.current || fallbackRef.current) {\n console.log('[PivotEngine] Using synchronous fallback for grouping');\n try {\n const store = storeRef.current;\n const indexes = indexesRef.current;\n if (store && indexes) {\n const result = computeGrouping(store, indexes, visibleIds, groupBy);\n console.log('[PivotEngine] Fallback grouping result:', result);\n resolve(result);\n return;\n }\n } catch (e) {\n console.error('[PivotEngine] fallback computeGrouping error:', e);\n }\n\n console.warn('[PivotEngine] No store/indexes for fallback, returning empty');\n resolve({ groups: [] });\n return;\n }\n\n console.log('[PivotEngine] Setting grouping callback and posting to worker');\n pendingCallbacksRef.current.set('grouping', resolve as (result: unknown) => void);\n\n const message: WorkerInMessage = {\n type: 'computeGrouping',\n visibleIds,\n groupBy,\n };\n\n workerRef.current.postMessage(message);\n console.log('[PivotEngine] Message posted to worker');\n });\n },\n [ready]\n );\n\n const sortIdsCallback = useCallback(\n (visibleIds: Uint32Array, sortBy: string): Promise<Uint32Array> => {\n return new Promise((resolve) => {\n // synchronous fallback if worker unavailable\n if (!workerRef.current || fallbackRef.current) {\n try {\n const store = storeRef.current;\n if (store) {\n const result = sortIds(store, visibleIds, sortBy);\n resolve(result);\n return;\n }\n } catch (e) {\n console.error('[PivotEngine] fallback sortIds error:', e);\n }\n\n resolve(visibleIds);\n return;\n }\n\n pendingCallbacksRef.current.set('sort', resolve as (result: unknown) => void);\n\n const message: WorkerInMessage = {\n type: 'sort',\n ids: visibleIds,\n sortBy,\n };\n\n workerRef.current.postMessage(message);\n });\n },\n [ready]\n );\n\n return {\n ready,\n applyFilters: applyFiltersCallback,\n computeGrouping: computeGroupingCallback,\n sortIds: sortIdsCallback,\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"usePivotEngine.js","sources":["../../../../PivotViewer/hooks/usePivotEngine.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, useRef, useState, useCallback } from 'react';\nimport type {\n PivotStore,\n PivotIndexes,\n FilterSpec,\n FilterResult,\n GroupSpec,\n GroupingResult,\n WorkerInMessage,\n WorkerOutMessage,\n FieldValue,\n} from '../engine/types';\nimport { buildStore, buildIndexes, applyFilters, computeGrouping, sortIds } from '../engine/store';\n\nexport interface UsePivotEngineOptions<TItem extends object> {\n data: TItem[];\n fieldExtractors: Map<string, (item: TItem) => FieldValue>;\n indexFields: string[];\n}\n\nexport interface UsePivotEngineResult {\n ready: boolean;\n applyFilters: (filters: FilterSpec[]) => Promise<FilterResult>;\n computeGrouping: (visibleIds: Uint32Array, groupBy: GroupSpec) => Promise<GroupingResult>;\n sortIds: (visibleIds: Uint32Array, sortBy: string) => Promise<Uint32Array>;\n}\n\nexport function usePivotEngine<TItem extends object>({\n data,\n fieldExtractors,\n indexFields,\n}: UsePivotEngineOptions<TItem>): UsePivotEngineResult {\n const [ready, setReady] = useState(false);\n const [workerAvailable, setWorkerAvailable] = useState(false);\n const workerRef = useRef<Worker | null>(null);\n const indexesRef = useRef<PivotIndexes | null>(null);\n const fallbackRef = useRef(false);\n const storeRef = useRef<PivotStore | null>(null);\n const pendingCallbacksRef = useRef<Map<string, (result: unknown) => void>>(new Map());\n\n useEffect(() => {\n if (typeof window === 'undefined' || typeof Worker === 'undefined') {\n fallbackRef.current = true;\n setWorkerAvailable(false);\n return;\n }\n\n const workerUrl = new URL('../engine/pivot.worker.js', import.meta.url);\n let disposed = false;\n\n const enableFallback = () => {\n fallbackRef.current = true;\n workerRef.current = null;\n setWorkerAvailable(false);\n };\n\n const setupWorker = async () => {\n try {\n if (typeof fetch === 'function') {\n const response = await fetch(workerUrl, { method: 'HEAD' });\n const contentType = response.headers.get('content-type') ?? '';\n\n if (!response.ok || !contentType.includes('javascript')) {\n enableFallback();\n return;\n }\n }\n } catch {\n enableFallback();\n return;\n }\n\n if (disposed) {\n return;\n }\n\n const worker = new Worker(workerUrl, { type: 'module' });\n\n workerRef.current = worker;\n setWorkerAvailable(true);\n\n worker.onmessage = (e: MessageEvent<WorkerOutMessage>) => {\n const message = e.data;\n\n switch (message.type) {\n case 'indexesReady':\n setReady(true);\n break;\n\n case 'filterResult': {\n const callback = pendingCallbacksRef.current.get('filter');\n if (callback) {\n callback(message.result);\n pendingCallbacksRef.current.delete('filter');\n }\n break;\n }\n\n case 'groupingResult': {\n const callback = pendingCallbacksRef.current.get('grouping');\n if (callback) {\n callback(message.result);\n pendingCallbacksRef.current.delete('grouping');\n }\n break;\n }\n\n case 'sortResult': {\n const callback = pendingCallbacksRef.current.get('sort');\n if (callback) {\n callback(message.result);\n pendingCallbacksRef.current.delete('sort');\n }\n break;\n }\n }\n };\n\n worker.onerror = (error) => {\n console.error('[PivotEngine] Worker error:', error);\n enableFallback();\n if (storeRef.current) {\n try {\n indexesRef.current = buildIndexes(storeRef.current, indexFields);\n } catch (e) {\n console.error('[PivotEngine] Failed to build indexes in fallback:', e);\n indexesRef.current = null;\n }\n setReady(true);\n }\n };\n };\n\n void setupWorker();\n\n return () => {\n disposed = true;\n workerRef.current?.terminate();\n workerRef.current = null;\n };\n }, [indexFields]);\n\n useEffect(() => {\n setReady(false);\n\n const store = buildStore(data, fieldExtractors);\n storeRef.current = store;\n\n try {\n indexesRef.current = buildIndexes(store, indexFields);\n } catch (e) {\n console.error('[PivotEngine] buildIndexes failed:', e);\n indexesRef.current = null;\n }\n\n if (workerRef.current && !fallbackRef.current) {\n const fieldsArray = Array.from(store.fields.entries());\n const serializableStore = {\n ...store,\n fields: fieldsArray,\n };\n\n const message: WorkerInMessage = {\n type: 'buildIndexes',\n store: serializableStore as unknown as PivotStore,\n fields: indexFields,\n };\n workerRef.current.postMessage(message);\n } else {\n setReady(true);\n }\n }, [data, fieldExtractors, indexFields, workerAvailable]);\n\n const applyFiltersCallback = useCallback(\n (filters: FilterSpec[]): Promise<FilterResult> => {\n return new Promise((resolve) => {\n // If worker is not available, use synchronous fallback using local indexes\n if (!workerRef.current || fallbackRef.current) {\n try {\n const store = storeRef.current;\n const indexes = indexesRef.current;\n if (store && indexes) {\n const result = applyFilters(store, indexes, filters);\n resolve(result);\n return;\n }\n } catch (e) {\n console.error('[PivotEngine] fallback applyFilters error:', e);\n }\n\n // if fallback not possible, return empty result\n resolve({ visibleIds: new Uint32Array(0), count: 0 });\n return;\n }\n\n pendingCallbacksRef.current.set('filter', resolve as (result: unknown) => void);\n\n const message: WorkerInMessage = {\n type: 'applyFilters',\n filters,\n };\n\n workerRef.current.postMessage(message);\n });\n },\n [ready]\n );\n\n const computeGroupingCallback = useCallback(\n (visibleIds: Uint32Array, groupBy: GroupSpec): Promise<GroupingResult> => {\n // Check if there's already a pending grouping request\n if (pendingCallbacksRef.current.has('grouping')) {\n return Promise.resolve({ groups: [] });\n }\n\n return new Promise((resolve) => {\n // synchronous fallback if worker unavailable\n if (!workerRef.current || fallbackRef.current) {\n try {\n const store = storeRef.current;\n const indexes = indexesRef.current;\n if (store && indexes) {\n const result = computeGrouping(store, indexes, visibleIds, groupBy);\n resolve(result);\n return;\n }\n } catch (e) {\n console.error('[PivotEngine] fallback computeGrouping error:', e);\n }\n\n resolve({ groups: [] });\n return;\n }\n\n pendingCallbacksRef.current.set('grouping', resolve as (result: unknown) => void);\n\n const message: WorkerInMessage = {\n type: 'computeGrouping',\n visibleIds,\n groupBy,\n };\n\n workerRef.current.postMessage(message);\n });\n },\n [ready]\n );\n\n const sortIdsCallback = useCallback(\n (visibleIds: Uint32Array, sortBy: string): Promise<Uint32Array> => {\n return new Promise((resolve) => {\n // synchronous fallback if worker unavailable\n if (!workerRef.current || fallbackRef.current) {\n try {\n const store = storeRef.current;\n if (store) {\n const result = sortIds(store, visibleIds, sortBy);\n resolve(result);\n return;\n }\n } catch (e) {\n console.error('[PivotEngine] fallback sortIds error:', e);\n }\n\n resolve(visibleIds);\n return;\n }\n\n pendingCallbacksRef.current.set('sort', resolve as (result: unknown) => void);\n\n const message: WorkerInMessage = {\n type: 'sort',\n ids: visibleIds,\n sortBy,\n };\n\n workerRef.current.postMessage(message);\n });\n },\n [ready]\n );\n\n return {\n ready,\n applyFilters: applyFiltersCallback,\n computeGrouping: computeGroupingCallback,\n sortIds: sortIdsCallback,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -39,11 +39,27 @@ export interface PivotViewerProps<TItem extends object> {
39
39
  filters?: PivotFilter<TItem>[];
40
40
  defaultDimensionKey?: string;
41
41
  cardRenderer?: (item: TItem) => ReactNode;
42
+ detailRenderer?: (item: TItem, onClose: () => void) => ReactNode;
42
43
  getItemId?: (item: TItem, index: number) => string | number;
43
44
  searchFields?: PropertyAccessor<TItem>[];
44
45
  className?: string;
45
46
  emptyContent?: ReactNode;
46
47
  isLoading?: boolean;
48
+ colors?: Partial<{
49
+ primaryColor: string;
50
+ primaryColorText: string;
51
+ primary500: string;
52
+ surfaceGround: string;
53
+ surfaceCard: string;
54
+ surfaceSection: string;
55
+ surfaceOverlay: string;
56
+ surfaceBorder: string;
57
+ textColor: string;
58
+ textColorSecondary: string;
59
+ highlightBg: string;
60
+ maskbg: string;
61
+ focusRing: string;
62
+ }>;
47
63
  }
48
64
  export type FilterState = Record<string, Set<string>>;
49
65
  export type RangeFilterState = Record<string, [number, number] | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../PivotViewer/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAKjF,MAAM,MAAM,gBAAgB,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC;AAM/D,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,gBAAgB,CAAC,KAAK,CAAC,GAAG,MAAM,CAKhF;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAUxE;AAED,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,MAAM;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc,CAAC,KAAK,SAAS,MAAM;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,cAAc,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,MAAM,CAAC;IAChD,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC;CAC/D;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,MAAM;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,cAAc,CAAC;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,iBAAiB,KAAK,MAAM,CAAC;IAE9D,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IAEpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,MAAM;IACpD,IAAI,EAAE,KAAK,EAAE,CAAC;IACd,UAAU,EAAE,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC;IAC1C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,CAAC;IAC5D,YAAY,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAEtD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../PivotViewer/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sources":["../../../PivotViewer/types.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 { ReactNode } from 'react';\n\nexport type PivotPrimitive = string | number | boolean | Date | null | undefined;\n\n/**\n * Type-safe property accessor for accessing properties, including nested ones\n */\nexport type PropertyAccessor<TItem> = (item: TItem) => unknown;\n\n/**\n * Extract property path from a property accessor function\n * Supports nested properties like item => item.address.city\n */\nexport function getPropertyPath<TItem>(accessor: PropertyAccessor<TItem>): string {\n const fnStr = accessor.toString();\n // Match patterns like: item => item.prop or item => item.prop.nested or (item) => item.prop\n const match = fnStr.match(/(?:=>|return)\\s*[a-zA-Z_$][a-zA-Z0-9_$]*\\.([a-zA-Z_$][a-zA-Z0-9_$.]*)/);\n return match ? match[1] : '';\n}\n\n/**\n * Get the value from an item using a property path string\n * Supports nested properties like \"address.city\"\n */\nexport function getValueByPath<TItem>(item: TItem, path: string): unknown {\n const parts = path.split('.');\n let value: unknown = item;\n for (const part of parts) {\n if (value === null || value === undefined) {\n return undefined;\n }\n value = value[part];\n }\n return value;\n}\n\nexport interface PivotGroup<TItem extends object> {\n key: string;\n label: string;\n value: PivotPrimitive;\n items: TItem[];\n count?: number;\n}\n\nexport interface PivotDimension<TItem extends object> {\n key: string;\n label: string;\n getValue: (item: TItem) => PivotPrimitive;\n formatValue?: (value: PivotPrimitive) => string;\n sort?: (a: PivotGroup<TItem>, b: PivotGroup<TItem>) => number;\n}\n\nexport interface PivotFilterOption {\n key: string;\n label: string;\n value: PivotPrimitive;\n count: number;\n}\n\nexport interface PivotFilter<TItem extends object> {\n key: string;\n label: string;\n getValue: (item: TItem) => PivotPrimitive;\n multi?: boolean;\n options?: PivotFilterOption[];\n sort?: (a: PivotFilterOption, b: PivotFilterOption) => number;\n /** For numeric filters, enables range picker with histogram */\n type?: 'string' | 'number' | 'date';\n /** Number of buckets for the histogram in range filters */\n buckets?: number;\n}\n\nexport interface PivotViewerProps<TItem extends object> {\n data: TItem[];\n dimensions: PivotDimension<TItem>[];\n filters?: PivotFilter<TItem>[];\n defaultDimensionKey?: string;\n cardRenderer?: (item: TItem) => ReactNode;\n getItemId?: (item: TItem, index: number) => string | number;\n searchFields?: PropertyAccessor<TItem>[];\n className?: string;\n emptyContent?: ReactNode;\n isLoading?: boolean;\n}\n\nexport type FilterState = Record<string, Set<string>>;\n\nexport type RangeFilterState = Record<string, [number, number] | null>;\n"],"names":[],"mappings":"AAgBM,SAAU,eAAe,CAAQ,QAAiC,EAAA;AACpE,IAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE;IAEjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,uEAAuE,CAAC;AAClG,IAAA,OAAO,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC;AAMM,SAAU,cAAc,CAAQ,IAAW,EAAE,IAAY,EAAA;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;IAC7B,IAAI,KAAK,GAAY,IAAI;AACzB,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACtB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE;AACvC,YAAA,OAAO,SAAS;QACpB;AACA,QAAA,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;IACvB;AACA,IAAA,OAAO,KAAK;AAChB;;;;"}
1
+ {"version":3,"file":"types.js","sources":["../../../PivotViewer/types.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 { ReactNode } from 'react';\n\nexport type PivotPrimitive = string | number | boolean | Date | null | undefined;\n\n/**\n * Type-safe property accessor for accessing properties, including nested ones\n */\nexport type PropertyAccessor<TItem> = (item: TItem) => unknown;\n\n/**\n * Extract property path from a property accessor function\n * Supports nested properties like item => item.address.city\n */\nexport function getPropertyPath<TItem>(accessor: PropertyAccessor<TItem>): string {\n const fnStr = accessor.toString();\n // Match patterns like: item => item.prop or item => item.prop.nested or (item) => item.prop\n const match = fnStr.match(/(?:=>|return)\\s*[a-zA-Z_$][a-zA-Z0-9_$]*\\.([a-zA-Z_$][a-zA-Z0-9_$.]*)/);\n return match ? match[1] : '';\n}\n\n/**\n * Get the value from an item using a property path string\n * Supports nested properties like \"address.city\"\n */\nexport function getValueByPath<TItem>(item: TItem, path: string): unknown {\n const parts = path.split('.');\n let value: unknown = item;\n for (const part of parts) {\n if (value === null || value === undefined) {\n return undefined;\n }\n value = value[part];\n }\n return value;\n}\n\nexport interface PivotGroup<TItem extends object> {\n key: string;\n label: string;\n value: PivotPrimitive;\n items: TItem[];\n count?: number;\n}\n\nexport interface PivotDimension<TItem extends object> {\n key: string;\n label: string;\n getValue: (item: TItem) => PivotPrimitive;\n formatValue?: (value: PivotPrimitive) => string;\n sort?: (a: PivotGroup<TItem>, b: PivotGroup<TItem>) => number;\n}\n\nexport interface PivotFilterOption {\n key: string;\n label: string;\n value: PivotPrimitive;\n count: number;\n}\n\nexport interface PivotFilter<TItem extends object> {\n key: string;\n label: string;\n getValue: (item: TItem) => PivotPrimitive;\n multi?: boolean;\n options?: PivotFilterOption[];\n sort?: (a: PivotFilterOption, b: PivotFilterOption) => number;\n /** For numeric filters, enables range picker with histogram */\n type?: 'string' | 'number' | 'date';\n /** Number of buckets for the histogram in range filters */\n buckets?: number;\n}\n\nexport interface PivotViewerProps<TItem extends object> {\n data: TItem[];\n dimensions: PivotDimension<TItem>[];\n filters?: PivotFilter<TItem>[];\n defaultDimensionKey?: string;\n cardRenderer?: (item: TItem) => ReactNode;\n /** Optional renderer for the slide-in detail panel when a card is selected */\n detailRenderer?: (item: TItem, onClose: () => void) => ReactNode;\n getItemId?: (item: TItem, index: number) => string | number;\n searchFields?: PropertyAccessor<TItem>[];\n className?: string;\n emptyContent?: ReactNode;\n isLoading?: boolean;\n /**\n * Optional color overrides mapped to PrimeReact-like CSS variables.\n * If omitted, values are taken from the global theme (PrimeReact defaults).\n */\n colors?: Partial<{\n primaryColor: string;\n primaryColorText: string;\n primary500: string;\n surfaceGround: string;\n surfaceCard: string;\n surfaceSection: string;\n surfaceOverlay: string;\n surfaceBorder: string;\n textColor: string;\n textColorSecondary: string;\n highlightBg: string;\n maskbg: string;\n focusRing: string;\n }>;\n}\n\nexport type FilterState = Record<string, Set<string>>;\n\nexport type RangeFilterState = Record<string, [number, number] | null>;\n"],"names":[],"mappings":"AAgBM,SAAU,eAAe,CAAQ,QAAiC,EAAA;AACpE,IAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE;IAEjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,uEAAuE,CAAC;AAClG,IAAA,OAAO,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC;AAMM,SAAU,cAAc,CAAQ,IAAW,EAAE,IAAY,EAAA;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;IAC7B,IAAI,KAAK,GAAY,IAAI;AACzB,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACtB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE;AACvC,YAAA,OAAO,SAAS;QACpB;AACA,QAAA,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;IACvB;AACA,IAAA,OAAO,KAAK;AAChB;;;;"}