@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,69 +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 { PivotGroup } from '../types';
5
- import { GROUP_SPACING } from '../constants';
6
-
7
- export interface AxisLabelsProps<TItem extends object> {
8
- groups: PivotGroup<TItem>[];
9
- bucketWidths: number[];
10
- dimensionFilter: string | null;
11
- hoveredGroup: string | null;
12
- zoomLevel: number;
13
- onHover: (key: string | null) => void;
14
- onClick: (key: string) => void;
15
- containerRef: React.RefObject<HTMLDivElement | null>;
16
- }
17
-
18
- export function AxisLabels<TItem extends object>({
19
- groups,
20
- bucketWidths,
21
- dimensionFilter,
22
- hoveredGroup,
23
- zoomLevel,
24
- onHover,
25
- onClick,
26
- containerRef,
27
- }: AxisLabelsProps<TItem>) {
28
- return (
29
- <div
30
- className="pv-axis-labels"
31
- ref={containerRef}
32
- style={{
33
- pointerEvents: 'none',
34
- gap: `${GROUP_SPACING * zoomLevel}px`,
35
- paddingLeft: 0,
36
- paddingRight: 0,
37
- overflowX: 'hidden',
38
- whiteSpace: 'nowrap',
39
- }}
40
- >
41
- {groups.map((group, index) => {
42
- const isSelected = dimensionFilter === group.key;
43
- const baseBucketWidth = bucketWidths[index] || 0;
44
- // Apply zoom to bucket width
45
- const bucketWidth = baseBucketWidth * zoomLevel;
46
- // Width is just the bucket width - spacing is handled by CSS gap
47
- const width = bucketWidth;
48
-
49
- return (
50
- <button
51
- key={group.key}
52
- type="button"
53
- className={`pv-axis-label ${hoveredGroup === group.key ? 'highlighted' : ''} ${isSelected ? 'selected' : ''}`}
54
- style={{
55
- width,
56
- pointerEvents: 'auto'
57
- }}
58
- onMouseEnter={() => onHover(group.key)}
59
- onMouseLeave={() => onHover(null)}
60
- onClick={() => onClick(group.key)}
61
- >
62
- <span className="pv-axis-label-text">{group.label}</span>
63
- <span className="pv-axis-label-count">{group.count ?? group.items.length}</span>
64
- </button>
65
- );
66
- })}
67
- </div>
68
- );
69
- }
@@ -1,108 +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 { AnimatePresence, motion } from 'framer-motion';
5
-
6
- type WithRecord<TItem> = TItem extends Record<string, unknown> ? TItem : never;
7
-
8
- export interface DetailPanelProps<TItem extends object> {
9
- selectedItem: TItem | null;
10
- onClose: () => void;
11
- }
12
-
13
- export function DetailPanel<TItem extends object>({
14
- selectedItem,
15
- onClose,
16
- }: DetailPanelProps<TItem>) {
17
- const selectedRecord = selectedItem as WithRecord<TItem> | null;
18
-
19
- const selectedContent = selectedRecord
20
- ? ((selectedRecord['content'] as Record<string, unknown> | undefined) ?? {})
21
- : {};
22
-
23
- const metadataEntries = selectedRecord
24
- ? (
25
- [
26
- ['Type', selectedRecord['type']],
27
- [
28
- 'Occurred',
29
- selectedRecord['occurred'] instanceof Date
30
- ? (selectedRecord['occurred'] as Date).toLocaleString()
31
- : selectedRecord['occurred']
32
- ? new Date(String(selectedRecord['occurred'])).toLocaleString()
33
- : undefined,
34
- ],
35
- ['Service', selectedRecord['service']],
36
- ['Environment', selectedRecord['environment']],
37
- ['Tenant', selectedRecord['tenant']],
38
- ['Correlation Id', selectedRecord['correlationId']],
39
- ] as Array<[string, unknown]>
40
- ).filter(([, value]) => value !== undefined && value !== null)
41
- : [];
42
-
43
- const causation = Array.isArray(selectedRecord?.['causation'])
44
- ? (selectedRecord?.['causation'] as unknown[])
45
- : [];
46
-
47
- return (
48
- <AnimatePresence>
49
- {selectedRecord && (
50
- <motion.aside
51
- className="pv-detail-panel"
52
- initial={{ x: '100%' }}
53
- animate={{ x: 0 }}
54
- exit={{ x: '100%' }}
55
- transition={{ type: 'spring', stiffness: 400, damping: 35 }}
56
- >
57
- <header>
58
- <div>
59
- <h2>{String(selectedRecord['name'] ?? selectedRecord['type'] ?? 'Event')}</h2>
60
- {selectedRecord['type'] ? <p>{String(selectedRecord['type'])}</p> : null}
61
- </div>
62
- <button type="button" onClick={onClose} title="Close">
63
- ×
64
- </button>
65
- </header>
66
- <div className="pv-detail-panel-content">
67
- {metadataEntries.length > 0 && (
68
- <section className="pv-detail-meta">
69
- <h3>Metadata</h3>
70
- <dl>
71
- {metadataEntries.map(([key, value]) => (
72
- <div key={key}>
73
- <dt>{key}</dt>
74
- <dd>{String(value)}</dd>
75
- </div>
76
- ))}
77
- </dl>
78
- </section>
79
- )}
80
- {causation.length > 0 && (
81
- <section className="pv-detail-causation">
82
- <h3>Causation</h3>
83
- <div className="pv-pill-row">
84
- {causation.map((value, index) => (
85
- <span key={`${value}-${index}`} className="pv-pill">
86
- {String(value)}
87
- </span>
88
- ))}
89
- </div>
90
- </section>
91
- )}
92
- <section className="pv-detail-content">
93
- <h3>Content</h3>
94
- <dl>
95
- {Object.entries(selectedContent).map(([key, value]) => (
96
- <div key={key}>
97
- <dt>{key}</dt>
98
- <dd>{typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)}</dd>
99
- </div>
100
- ))}
101
- </dl>
102
- </section>
103
- </div>
104
- </motion.aside>
105
- )}
106
- </AnimatePresence>
107
- );
108
- }
@@ -1,189 +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 { useEffect, useRef, useState } from 'react';
5
- import { createPortal } from 'react-dom';
6
- import { AnimatePresence, motion } from 'framer-motion';
7
- import type { PivotFilter, PivotFilterOption, PivotPrimitive } from '../types';
8
- import type { FilterState, RangeFilterState } from '../utils/utils';
9
- import { renderOptionCount } from '../utils/utils';
10
- import { RangeHistogramFilter } from './RangeHistogramFilter';
11
-
12
- export interface FilterPanelProps<TItem extends object> {
13
- isOpen: boolean;
14
- search: string;
15
- filterState: FilterState;
16
- rangeFilterState: RangeFilterState;
17
- expandedFilterKey: string | null;
18
- filterOptions: {
19
- filter: PivotFilter<TItem>;
20
- options: PivotFilterOption[];
21
- numericRange?: { min: number; max: number; values: PivotPrimitive[] };
22
- }[];
23
- anchorRef: React.RefObject<HTMLButtonElement | null>;
24
- onClose: () => void;
25
- onSearchChange: (value: string) => void;
26
- onFilterToggle: (filterKey: string, optionKey: string, multi: boolean | undefined) => void;
27
- onFilterClear: (filterKey: string) => void;
28
- onRangeChange: (filterKey: string, range: [number, number] | null) => void;
29
- onExpandedFilterChange: (key: string | null) => void;
30
- }
31
-
32
- export function FilterPanel<TItem extends object>({
33
- isOpen,
34
- search,
35
- filterState,
36
- rangeFilterState,
37
- expandedFilterKey,
38
- filterOptions,
39
- anchorRef,
40
- onClose,
41
- onSearchChange,
42
- onFilterToggle,
43
- onFilterClear,
44
- onRangeChange,
45
- onExpandedFilterChange,
46
- }: FilterPanelProps<TItem>) {
47
- const panelRef = useRef<HTMLDivElement>(null);
48
- const [position, setPosition] = useState({ top: 0, left: 0 });
49
-
50
- // Calculate position when opening
51
- useEffect(() => {
52
- if (isOpen && anchorRef.current) {
53
- const rect = anchorRef.current.getBoundingClientRect();
54
- setPosition({
55
- top: rect.bottom + 8,
56
- left: rect.left,
57
- });
58
- }
59
- }, [isOpen, anchorRef]);
60
-
61
- // Handle click outside to close
62
- useEffect(() => {
63
- if (!isOpen) return;
64
-
65
- const handleClickOutside = (event: MouseEvent) => {
66
- const target = event.target as Node;
67
- const panel = panelRef.current;
68
- const anchor = anchorRef.current;
69
-
70
- if (panel && !panel.contains(target) && anchor && !anchor.contains(target)) {
71
- onClose();
72
- }
73
- };
74
-
75
- // Use capture phase to ensure we catch the event before any other handlers
76
- // Use timeout to avoid closing immediately when clicking the button to open
77
- const timeoutId = setTimeout(() => {
78
- document.addEventListener('mousedown', handleClickOutside, true);
79
- }, 0);
80
-
81
- return () => {
82
- clearTimeout(timeoutId);
83
- document.removeEventListener('mousedown', handleClickOutside, true);
84
- };
85
- }, [isOpen, anchorRef, onClose]);
86
-
87
- return createPortal(
88
- <AnimatePresence initial={false}>
89
- {isOpen && (
90
- <motion.aside
91
- ref={panelRef}
92
- className="pv-filter-dropdown"
93
- style={{
94
- position: 'fixed',
95
- left: position.left,
96
- top: position.top,
97
- }}
98
- initial={{ opacity: 0, y: -8 }}
99
- animate={{ opacity: 1, y: 0 }}
100
- exit={{ opacity: 0, y: -8 }}
101
- transition={{ duration: 0.15 }}
102
- >
103
- <div className="pv-filter-dropdown-content">
104
- <div className="pv-search">
105
- <input
106
- type="search"
107
- placeholder="Search events"
108
- value={search}
109
- onChange={(event) => onSearchChange(event.target.value)}
110
- />
111
- </div>
112
- <div className="pv-filter-groups">
113
- {filterOptions.map(({ filter, options, numericRange }) => {
114
- const selections = filterState[filter.key] ?? new Set<string>();
115
- const rangeSelection = rangeFilterState[filter.key];
116
- const isExpanded = expandedFilterKey === filter.key;
117
- const isNumeric = filter.type === 'number';
118
-
119
- return (
120
- <div key={filter.key} className={`pv-filter ${isExpanded ? 'expanded' : ''}`}>
121
- <button
122
- type="button"
123
- className="pv-filter-trigger"
124
- onClick={() => onExpandedFilterChange(isExpanded ? null : filter.key)}
125
- >
126
- <span className="pv-filter-label">{filter.label}</span>
127
- <span className="pv-filter-trigger-meta">
128
- {!isNumeric && selections.size > 0 && <span className="pv-filter-count">{selections.size}</span>}
129
- {isNumeric && rangeSelection && <span className="pv-filter-count">Range</span>}
130
- <span className="pv-filter-chevron" />
131
- </span>
132
- </button>
133
- <div className={`pv-filter-content ${isExpanded ? 'expanded' : ''}`}>
134
- {isNumeric && numericRange ? (
135
- <RangeHistogramFilter
136
- values={numericRange.values}
137
- min={numericRange.min}
138
- max={numericRange.max}
139
- buckets={filter.buckets ?? 20}
140
- selectedRange={rangeSelection ?? null}
141
- onChange={(range) => onRangeChange(filter.key, range)}
142
- />
143
- ) : (
144
- <>
145
- <ul>
146
- {options.map((option) => {
147
- const optionKey = option.key;
148
- const checked = selections.has(optionKey);
149
- return (
150
- <li key={option.key}>
151
- <label>
152
- <input
153
- type={filter.multi ? 'checkbox' : 'radio'}
154
- name={`filter-${filter.key}`}
155
- checked={checked}
156
- onChange={() =>
157
- onFilterToggle(filter.key, optionKey, filter.multi ?? false)
158
- }
159
- />
160
- <span>{option.label}</span>
161
- <span className="pv-option-count">{renderOptionCount(option.count)}</span>
162
- </label>
163
- </li>
164
- );
165
- })}
166
- </ul>
167
- {selections.size > 0 && (
168
- <button
169
- type="button"
170
- className="pv-filter-clear"
171
- onClick={() => onFilterClear(filter.key)}
172
- >
173
- Clear
174
- </button>
175
- )}
176
- </>
177
- )}
178
- </div>
179
- </div>
180
- );
181
- })}
182
- </div>
183
- </div>
184
- </motion.aside>
185
- )}
186
- </AnimatePresence>,
187
- document.body
188
- );
189
- }
@@ -1,10 +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 { FilterPanel, type FilterPanelProps } from './FilterPanel';
5
-
6
- export type FilterPanelContainerProps<TItem extends object> = FilterPanelProps<TItem>;
7
-
8
- export function FilterPanelContainer<TItem extends object>(props: FilterPanelContainerProps<TItem>) {
9
- return <FilterPanel {...props} />;
10
- }