@cratis/components 0.1.9 → 0.1.10

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 (101) hide show
  1. package/dist/cjs/PivotViewer/PivotViewer.css +1258 -0
  2. package/dist/cjs/PivotViewer/components/Spinner.css +77 -0
  3. package/dist/cjs/TimeMachine/EventsView.css +213 -0
  4. package/dist/cjs/TimeMachine/TimeMachine.css +567 -0
  5. package/dist/esm/PivotViewer/PivotViewer.css +1258 -0
  6. package/dist/esm/PivotViewer/components/Spinner.css +77 -0
  7. package/dist/esm/TimeMachine/EventsView.css +213 -0
  8. package/dist/esm/TimeMachine/TimeMachine.css +567 -0
  9. package/package.json +3 -4
  10. package/.storybook/main.ts +0 -24
  11. package/CommandDialog/CommandDialog.stories.tsx +0 -25
  12. package/CommandDialog/CommandDialog.tsx +0 -161
  13. package/CommandDialog/index.ts +0 -4
  14. package/CommandForm/CommandForm.stories.tsx +0 -24
  15. package/CommandForm/CommandForm.tsx +0 -266
  16. package/CommandForm/CommandFormField.tsx +0 -27
  17. package/CommandForm/CommandFormFields.tsx +0 -142
  18. package/CommandForm/DatePickerField.tsx +0 -57
  19. package/CommandForm/DropdownField.tsx +0 -65
  20. package/CommandForm/InputTextField.tsx +0 -62
  21. package/CommandForm/SliderField.tsx +0 -68
  22. package/CommandForm/index.ts +0 -10
  23. package/Common/ErrorBoundary.stories.tsx +0 -10
  24. package/Common/ErrorBoundary.tsx +0 -41
  25. package/Common/FormElement.stories.tsx +0 -10
  26. package/Common/FormElement.tsx +0 -20
  27. package/Common/Page.stories.tsx +0 -10
  28. package/Common/Page.tsx +0 -21
  29. package/Common/index.ts +0 -6
  30. package/DataPage/DataPage.stories.tsx +0 -10
  31. package/DataPage/DataPage.tsx +0 -191
  32. package/DataPage/index.ts +0 -4
  33. package/DataTables/DataTableForObservableQuery.stories.tsx +0 -10
  34. package/DataTables/DataTableForObservableQuery.tsx +0 -97
  35. package/DataTables/DataTableForQuery.stories.tsx +0 -10
  36. package/DataTables/DataTableForQuery.tsx +0 -97
  37. package/DataTables/index.ts +0 -5
  38. package/Dialogs/BusyIndicatorDialog.stories.tsx +0 -26
  39. package/Dialogs/BusyIndicatorDialog.tsx +0 -26
  40. package/Dialogs/ConfirmationDialog.stories.tsx +0 -36
  41. package/Dialogs/ConfirmationDialog.tsx +0 -75
  42. package/Dialogs/index.ts +0 -5
  43. package/Dropdown/Dropdown.tsx +0 -23
  44. package/Dropdown/index.ts +0 -4
  45. package/PivotViewer/PivotViewer.stories.tsx +0 -24
  46. package/PivotViewer/PivotViewer.tsx +0 -791
  47. package/PivotViewer/components/AxisLabels.tsx +0 -69
  48. package/PivotViewer/components/DetailPanel.tsx +0 -108
  49. package/PivotViewer/components/FilterPanel.tsx +0 -189
  50. package/PivotViewer/components/FilterPanelContainer.tsx +0 -10
  51. package/PivotViewer/components/PivotCanvas.tsx +0 -660
  52. package/PivotViewer/components/PivotViewerMain.tsx +0 -229
  53. package/PivotViewer/components/RangeHistogramFilter.tsx +0 -220
  54. package/PivotViewer/components/Spinner.tsx +0 -21
  55. package/PivotViewer/components/Toolbar.tsx +0 -130
  56. package/PivotViewer/components/ToolbarContainer.tsx +0 -10
  57. package/PivotViewer/components/index.ts +0 -12
  58. package/PivotViewer/components/pivot/animation.ts +0 -108
  59. package/PivotViewer/components/pivot/buckets.ts +0 -152
  60. package/PivotViewer/components/pivot/colorResolver.ts +0 -67
  61. package/PivotViewer/components/pivot/constants.ts +0 -46
  62. package/PivotViewer/components/pivot/sprites.ts +0 -265
  63. package/PivotViewer/components/pivot/visibility.ts +0 -319
  64. package/PivotViewer/constants.ts +0 -9
  65. package/PivotViewer/engine/layout.ts +0 -149
  66. package/PivotViewer/engine/pivot.worker.ts +0 -86
  67. package/PivotViewer/engine/store.ts +0 -437
  68. package/PivotViewer/engine/types.ts +0 -255
  69. package/PivotViewer/hooks/index.ts +0 -13
  70. package/PivotViewer/hooks/useContainerDimensions.ts +0 -45
  71. package/PivotViewer/hooks/useDimensionState.ts +0 -53
  72. package/PivotViewer/hooks/useFilterOptions.ts +0 -36
  73. package/PivotViewer/hooks/useFilterPanelDrag.ts +0 -49
  74. package/PivotViewer/hooks/useFilterState.ts +0 -106
  75. package/PivotViewer/hooks/useFilteredData.ts +0 -119
  76. package/PivotViewer/hooks/usePanning.ts +0 -163
  77. package/PivotViewer/hooks/usePivotEngine.ts +0 -252
  78. package/PivotViewer/hooks/useSelectedItem.ts +0 -402
  79. package/PivotViewer/hooks/useWheelZoom.ts +0 -114
  80. package/PivotViewer/hooks/useZoomState.ts +0 -34
  81. package/PivotViewer/index.ts +0 -7
  82. package/PivotViewer/types.ts +0 -59
  83. package/PivotViewer/utils/animations.ts +0 -249
  84. package/PivotViewer/utils/constants.ts +0 -20
  85. package/PivotViewer/utils/index.ts +0 -6
  86. package/PivotViewer/utils/selection.ts +0 -292
  87. package/PivotViewer/utils/utils.ts +0 -259
  88. package/TimeMachine/EventsView.stories.tsx +0 -10
  89. package/TimeMachine/EventsView.tsx +0 -119
  90. package/TimeMachine/Properties.stories.tsx +0 -10
  91. package/TimeMachine/Properties.tsx +0 -98
  92. package/TimeMachine/ReadModelView.stories.tsx +0 -10
  93. package/TimeMachine/ReadModelView.tsx +0 -143
  94. package/TimeMachine/TimeMachine.stories.tsx +0 -10
  95. package/TimeMachine/TimeMachine.tsx +0 -244
  96. package/TimeMachine/index.ts +0 -8
  97. package/TimeMachine/types.ts +0 -23
  98. package/global.d.ts +0 -11
  99. package/index.ts +0 -22
  100. package/useOverlayZIndex.ts +0 -32
  101. package/vite.config.ts +0 -80
@@ -1,114 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { useCallback, useEffect } from 'react';
5
- import { ZOOM_MIN, ZOOM_MAX } from '../utils/utils';
6
-
7
- export function useWheelZoom(
8
- containerRef: React.RefObject<HTMLDivElement | null>,
9
- zoomLevel: number,
10
- setZoomLevel: (zoom: number) => void
11
- ) {
12
- const handleWheel = useCallback((e: WheelEvent) => {
13
- if (e.ctrlKey || e.metaKey) {
14
- e.preventDefault();
15
-
16
- const container = containerRef.current;
17
- if (!container) return;
18
-
19
- container.style.scrollBehavior = 'auto';
20
-
21
- const rect = container.getBoundingClientRect();
22
- const cursorX = e.clientX - rect.left;
23
- const cursorY = e.clientY - rect.top;
24
- const scrollX = container.scrollLeft;
25
- const scrollY = container.scrollTop;
26
-
27
- const delta = -e.deltaY * 0.01;
28
- const newZoom = Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, zoomLevel + delta));
29
- const zoomRatio = newZoom / zoomLevel;
30
-
31
- const newScrollLeft = (scrollX + cursorX) * zoomRatio - cursorX;
32
- const newScrollTop = (scrollY + cursorY) * zoomRatio - cursorY;
33
-
34
- setZoomLevel(newZoom);
35
-
36
- setTimeout(() => {
37
- container.scrollLeft = Math.max(0, newScrollLeft);
38
- container.scrollTop = Math.max(0, newScrollTop);
39
- setTimeout(() => {
40
- container.style.scrollBehavior = '';
41
- }, 50);
42
- }, 0);
43
- }
44
- }, [zoomLevel, setZoomLevel, containerRef]);
45
-
46
- useEffect(() => {
47
- const container = containerRef.current;
48
- if (!container) return;
49
-
50
- container.addEventListener('wheel', handleWheel, { passive: false });
51
-
52
- let lastTouchDistance = 0;
53
- let currentZoom = zoomLevel;
54
-
55
- const handleTouchStart = (e: TouchEvent) => {
56
- if (e.touches.length === 2) {
57
- const dx = e.touches[0].clientX - e.touches[1].clientX;
58
- const dy = e.touches[0].clientY - e.touches[1].clientY;
59
- lastTouchDistance = Math.sqrt(dx * dx + dy * dy);
60
- currentZoom = zoomLevel;
61
- }
62
- };
63
-
64
- const handleTouchMove = (e: TouchEvent) => {
65
- if (e.touches.length === 2) {
66
- e.preventDefault();
67
- const dx = e.touches[0].clientX - e.touches[1].clientX;
68
- const dy = e.touches[0].clientY - e.touches[1].clientY;
69
- const distance = Math.sqrt(dx * dx + dy * dy);
70
-
71
- const centerX = (e.touches[0].clientX + e.touches[1].clientX) / 2;
72
- const centerY = (e.touches[0].clientY + e.touches[1].clientY) / 2;
73
- const rect = container.getBoundingClientRect();
74
- const cursorX = centerX - rect.left;
75
- const cursorY = centerY - rect.top;
76
-
77
- if (lastTouchDistance > 0) {
78
- const scale = distance / lastTouchDistance;
79
- const newZoom = Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, currentZoom * scale));
80
- const zoomRatio = newZoom / zoomLevel;
81
-
82
- const contentX = container.scrollLeft + cursorX;
83
- const contentY = container.scrollTop + cursorY;
84
-
85
- const newScrollLeft = contentX * zoomRatio - cursorX;
86
- const newScrollTop = contentY * zoomRatio - cursorY;
87
-
88
- setZoomLevel(newZoom);
89
-
90
- requestAnimationFrame(() => {
91
- container.scrollLeft = Math.max(0, newScrollLeft);
92
- container.scrollTop = Math.max(0, newScrollTop);
93
- });
94
- }
95
- lastTouchDistance = distance;
96
- }
97
- };
98
-
99
- const handleTouchEnd = () => {
100
- lastTouchDistance = 0;
101
- };
102
-
103
- container.addEventListener('touchstart', handleTouchStart, { passive: true });
104
- container.addEventListener('touchmove', handleTouchMove, { passive: false });
105
- container.addEventListener('touchend', handleTouchEnd, { passive: true });
106
-
107
- return () => {
108
- container.removeEventListener('wheel', handleWheel);
109
- container.removeEventListener('touchstart', handleTouchStart);
110
- container.removeEventListener('touchmove', handleTouchMove);
111
- container.removeEventListener('touchend', handleTouchEnd);
112
- };
113
- }, [handleWheel, zoomLevel, setZoomLevel, containerRef]);
114
- }
@@ -1,34 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { useState, useCallback } from 'react';
5
- import { ZOOM_MIN, ZOOM_MAX } from '../utils/utils';
6
-
7
- export function useZoomState(initialZoom = 1) {
8
- const [zoomLevel, setZoomLevel] = useState(initialZoom);
9
-
10
- const handleZoomChange = useCallback((newZoom: number) => {
11
- setZoomLevel(Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, newZoom)));
12
- }, []);
13
-
14
- const handleZoomIn = useCallback(() => {
15
- handleZoomChange(zoomLevel + 0.2);
16
- }, [zoomLevel, handleZoomChange]);
17
-
18
- const handleZoomOut = useCallback(() => {
19
- handleZoomChange(zoomLevel - 0.2);
20
- }, [zoomLevel, handleZoomChange]);
21
-
22
- const handleZoomSlider = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
23
- handleZoomChange(parseFloat(e.target.value));
24
- }, [handleZoomChange]);
25
-
26
- return {
27
- zoomLevel,
28
- setZoomLevel,
29
- handleZoomChange,
30
- handleZoomIn,
31
- handleZoomOut,
32
- handleZoomSlider,
33
- };
34
- }
@@ -1,7 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { PivotViewer } from './PivotViewer';
5
-
6
- export { PivotViewer, PivotViewer as PivotViewerOptimized };
7
- export type { PivotViewerProps, PivotDimension, PivotFilter, PivotFilterOption, PivotGroup, PivotPrimitive } from './types';
@@ -1,59 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import type { ReactNode } from 'react';
5
-
6
- export type PivotPrimitive = string | number | boolean | Date | null | undefined;
7
-
8
- export interface PivotGroup<TItem extends object> {
9
- key: string;
10
- label: string;
11
- value: PivotPrimitive;
12
- items: TItem[];
13
- count?: number;
14
- }
15
-
16
- export interface PivotDimension<TItem extends object> {
17
- key: string;
18
- label: string;
19
- getValue: (item: TItem) => PivotPrimitive;
20
- formatValue?: (value: PivotPrimitive) => string;
21
- sort?: (a: PivotGroup<TItem>, b: PivotGroup<TItem>) => number;
22
- }
23
-
24
- export interface PivotFilterOption {
25
- key: string;
26
- label: string;
27
- value: PivotPrimitive;
28
- count: number;
29
- }
30
-
31
- export interface PivotFilter<TItem extends object> {
32
- key: string;
33
- label: string;
34
- getValue: (item: TItem) => PivotPrimitive;
35
- multi?: boolean;
36
- options?: PivotFilterOption[];
37
- sort?: (a: PivotFilterOption, b: PivotFilterOption) => number;
38
- /** For numeric filters, enables range picker with histogram */
39
- type?: 'string' | 'number' | 'date';
40
- /** Number of buckets for the histogram in range filters */
41
- buckets?: number;
42
- }
43
-
44
- export interface PivotViewerProps<TItem extends object> {
45
- data: TItem[];
46
- dimensions: PivotDimension<TItem>[];
47
- filters?: PivotFilter<TItem>[];
48
- defaultDimensionKey?: string;
49
- cardRenderer?: (item: TItem) => ReactNode;
50
- getItemId?: (item: TItem, index: number) => string | number;
51
- searchFields?: (keyof TItem)[];
52
- className?: string;
53
- emptyContent?: ReactNode;
54
- isLoading?: boolean;
55
- }
56
-
57
- export type FilterState = Record<string, Set<string>>;
58
-
59
- export type RangeFilterState = Record<string, [number, number] | null>;
@@ -1,249 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- export type EasingFunction = (t: number) => number;
5
-
6
- export const easeOutCubic: EasingFunction = (t: number) => 1 - Math.pow(1 - t, 3);
7
-
8
- export interface ZoomAnimationParams {
9
- startZoom: number;
10
- targetZoom: number;
11
- duration?: number;
12
- easing?: EasingFunction;
13
- }
14
-
15
- export interface ScrollAnimationParams {
16
- targetScrollLeft: number;
17
- targetScrollTop: number;
18
- }
19
-
20
- export interface ZoomScrollAnimationParams extends ZoomAnimationParams, ScrollAnimationParams {
21
- container: HTMLElement;
22
- cardPosition?: { x: number; y: number; width: number; height: number } | null;
23
- targetCardPosition?: { x: number; y: number; width: number; height: number } | null;
24
- getCardPositionAtZoom?: (zoom: number) => { x: number; y: number; width: number; height: number } | null;
25
- getLayoutSizeAtZoom?: (zoom: number) => { width: number; height: number };
26
- spacer?: HTMLElement | null;
27
- onUpdate: (zoom: number) => void;
28
- onComplete?: () => void;
29
- startScrollLeft?: number; // Optional explicit start scroll
30
- startScrollTop?: number; // Optional explicit start scroll
31
- }
32
-
33
- /**
34
- * Animate zoom and scroll together, keeping a specific element centered
35
- */
36
- export function animateZoomAndScroll({
37
- container,
38
- cardPosition,
39
- targetCardPosition,
40
- getCardPositionAtZoom,
41
- getLayoutSizeAtZoom,
42
- spacer,
43
- startZoom,
44
- targetZoom,
45
- targetScrollLeft,
46
- targetScrollTop,
47
- duration = 300,
48
- easing = easeOutCubic,
49
- onUpdate,
50
- onComplete,
51
- startScrollLeft,
52
- startScrollTop,
53
- }: ZoomScrollAnimationParams): () => void {
54
- container.style.scrollBehavior = 'auto';
55
-
56
- let startTime: number | null = null;
57
- let rafId: number | null = null;
58
-
59
- // Capture start scroll if not provided
60
- const initialScrollLeft = startScrollLeft ?? container.scrollLeft;
61
- const initialScrollTop = startScrollTop ?? container.scrollTop;
62
-
63
- // Calculate initial center point relative to viewport
64
- const startCardCenterX = cardPosition ? (cardPosition.x * startZoom + (cardPosition.width * startZoom) / 2) : 0;
65
- const startCardCenterY = cardPosition ? (cardPosition.y * startZoom + (cardPosition.height * startZoom) / 2) : 0;
66
-
67
- const startCardScreenX = startCardCenterX - initialScrollLeft;
68
- const startCardScreenY = startCardCenterY - initialScrollTop;
69
-
70
- const animate = (timestamp: number) => {
71
- if (startTime === null) {
72
- startTime = timestamp;
73
- }
74
-
75
- const elapsed = timestamp - startTime;
76
- const progress = Math.min(1, elapsed / duration);
77
- const easedProgress = easing(progress);
78
-
79
- const currentZoom = startZoom + (targetZoom - startZoom) * easedProgress;
80
-
81
- // Update spacer size synchronously if possible
82
- if (spacer && getLayoutSizeAtZoom) {
83
- const size = getLayoutSizeAtZoom(currentZoom);
84
- if (size) {
85
- spacer.style.width = `${size.width * currentZoom}px`;
86
- spacer.style.height = `${size.height * currentZoom}px`;
87
- }
88
- }
89
-
90
- onUpdate(currentZoom);
91
-
92
- if (cardPosition) {
93
- let currentCardX: number;
94
- let currentCardY: number;
95
-
96
- if (getCardPositionAtZoom) {
97
- const pos = getCardPositionAtZoom(currentZoom);
98
- if (pos) {
99
- currentCardX = pos.x;
100
- currentCardY = pos.y;
101
- } else {
102
- currentCardX = cardPosition.x;
103
- currentCardY = cardPosition.y;
104
- }
105
- } else {
106
- // Interpolate card position if target is provided (for layouts that change with zoom)
107
- currentCardX = targetCardPosition
108
- ? cardPosition.x + (targetCardPosition.x - cardPosition.x) * easedProgress
109
- : cardPosition.x;
110
- currentCardY = targetCardPosition
111
- ? cardPosition.y + (targetCardPosition.y - cardPosition.y) * easedProgress
112
- : cardPosition.y;
113
- }
114
-
115
- // Calculate where the card center is at current zoom
116
- const currentCardCenterX = currentCardX * currentZoom + (cardPosition.width * currentZoom) / 2;
117
- const currentCardCenterY = currentCardY * currentZoom + (cardPosition.height * currentZoom) / 2;
118
-
119
- // Calculate where the card center will be at the end of animation (relative to viewport)
120
- // Target scroll position is where we want to end up
121
- const endCardX = targetCardPosition ? targetCardPosition.x : cardPosition.x;
122
- const endCardY = targetCardPosition ? targetCardPosition.y : cardPosition.y;
123
-
124
- const endCardCenterX = endCardX * targetZoom + (cardPosition.width * targetZoom) / 2;
125
- const endCardCenterY = endCardY * targetZoom + (cardPosition.height * targetZoom) / 2;
126
-
127
- const endCardScreenX = endCardCenterX - targetScrollLeft;
128
- const endCardScreenY = endCardCenterY - targetScrollTop;
129
-
130
- // Interpolate the desired screen position
131
- const desiredScreenX = startCardScreenX + (endCardScreenX - startCardScreenX) * easedProgress;
132
- const desiredScreenY = startCardScreenY + (endCardScreenY - startCardScreenY) * easedProgress;
133
-
134
- // Calculate needed scroll position to put card at desired screen position
135
- const neededScrollLeft = currentCardCenterX - desiredScreenX;
136
- const neededScrollTop = currentCardCenterY - desiredScreenY;
137
-
138
- let maxScrollLeft = container.scrollWidth - container.clientWidth;
139
- let maxScrollTop = container.scrollHeight - container.clientHeight;
140
-
141
- // If we have explicit layout size, use it for clamping to avoid DOM sync issues
142
- if (getLayoutSizeAtZoom) {
143
- const size = getLayoutSizeAtZoom(currentZoom);
144
- if (size) {
145
- maxScrollLeft = Math.max(0, size.width * currentZoom - container.clientWidth);
146
- maxScrollTop = Math.max(0, size.height * currentZoom - container.clientHeight);
147
- }
148
- }
149
-
150
- // We can't clamp strictly during animation because the scrollWidth/Height might not have updated yet
151
- // if the spacer hasn't resized. But usually spacer resizes immediately on zoom update.
152
- // For safety, we just set it.
153
- container.scrollLeft = Math.min(Math.max(0, neededScrollLeft), maxScrollLeft);
154
- container.scrollTop = Math.min(Math.max(0, neededScrollTop), maxScrollTop);
155
- } else {
156
- // If no card position, just interpolate scroll position
157
- // Use captured initial scroll positions for linear interpolation
158
- const currentScrollLeft = initialScrollLeft + (targetScrollLeft - initialScrollLeft) * easedProgress;
159
- const currentScrollTop = initialScrollTop + (targetScrollTop - initialScrollTop) * easedProgress;
160
-
161
- container.scrollLeft = currentScrollLeft;
162
- container.scrollTop = currentScrollTop;
163
- }
164
-
165
- if (progress < 1) {
166
- rafId = requestAnimationFrame(animate);
167
- } else {
168
- container.style.scrollBehavior = '';
169
- container.scrollLeft = targetScrollLeft;
170
- container.scrollTop = targetScrollTop;
171
- onComplete?.();
172
- }
173
- };
174
-
175
- rafId = requestAnimationFrame(animate);
176
-
177
- return () => {
178
- if (rafId !== null) {
179
- cancelAnimationFrame(rafId);
180
- container.style.scrollBehavior = '';
181
- }
182
- };
183
- }
184
-
185
- /**
186
- * Calculate scroll position to center a card in viewport, accounting for detail panel
187
- */
188
- export function calculateCenterScrollPosition(
189
- container: HTMLElement,
190
- cardPosition: { x: number; y: number; width: number; height: number },
191
- zoomLevel: number,
192
- detailPanelWidth: number = 0,
193
- totalHeight?: number
194
- ): { scrollLeft: number; scrollTop: number } {
195
- const cardCenterX = cardPosition.x * zoomLevel + (cardPosition.width * zoomLevel) / 2;
196
- const cardCenterY = cardPosition.y * zoomLevel + (cardPosition.height * zoomLevel) / 2;
197
-
198
- const availableWidth = container.clientWidth - detailPanelWidth;
199
- const targetX = availableWidth / 2;
200
- const targetY = container.clientHeight / 2;
201
-
202
- const scrollLeft = Math.max(0, cardCenterX - targetX);
203
- let scrollTop = Math.max(0, cardCenterY - targetY);
204
-
205
- console.log('[Animation] calculateCenterScrollPosition', {
206
- cardY: cardPosition.y,
207
- zoomLevel,
208
- cardCenterY,
209
- targetY,
210
- initialScrollTop: scrollTop,
211
- totalHeight,
212
- containerHeight: container.clientHeight
213
- });
214
-
215
- // If totalHeight is provided, clamp to valid scroll range
216
- if (totalHeight) {
217
- const contentHeight = totalHeight * zoomLevel;
218
- const viewportHeight = container.clientHeight;
219
- const maxScrollTop = Math.max(0, contentHeight - viewportHeight);
220
-
221
- console.log('[Animation] Clamping', {
222
- contentHeight,
223
- viewportHeight,
224
- maxScrollTop,
225
- currentScrollTop: scrollTop,
226
- clamped: Math.min(scrollTop, maxScrollTop)
227
- });
228
-
229
- scrollTop = Math.min(scrollTop, maxScrollTop);
230
- }
231
-
232
- return { scrollLeft, scrollTop };
233
- }
234
-
235
- /**
236
- * Smooth scroll to position
237
- */
238
- export function smoothScrollTo(
239
- container: HTMLElement,
240
- scrollLeft: number,
241
- scrollTop: number,
242
- smooth: boolean = true
243
- ): void {
244
- container.scrollTo({
245
- left: scrollLeft,
246
- top: scrollTop,
247
- behavior: smooth ? 'smooth' : 'auto',
248
- });
249
- }
@@ -1,20 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- // Zoom constants
5
- export const ZOOM_MIN = 0.1;
6
- export const ZOOM_MAX = 3;
7
- export const ZOOM_STEP = 0.05;
8
-
9
- // Layout constants
10
- export const GROUP_SPACING = 40;
11
- export const CARD_GAP = 8;
12
- export const CARDS_PER_COLUMN = 5;
13
- export const BASE_CARD_WIDTH = 180;
14
- export const BASE_CARD_HEIGHT = 140;
15
- export const DETAIL_PANEL_WIDTH = 380;
16
-
17
- // Animation constants
18
- export const ZOOM_ANIMATION_DURATION = 300;
19
- export const ZOOM_MULTIPLIER = 1.15;
20
- export const MIN_ZOOM_ON_SELECT = 1.2;
@@ -1,6 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- export * from './utils';
5
- export * from './animations';
6
- export * from './selection';