@vuu-ui/grid-layout 4.0.0-alpha.1

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 (142) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +141 -0
  3. package/package.json +40 -0
  4. package/src/GridCommand.js +395 -0
  5. package/src/GridComponentSettings.js +163 -0
  6. package/src/GridController.js +359 -0
  7. package/src/GridDragCoordinator.js +293 -0
  8. package/src/GridGeometry.js +1298 -0
  9. package/src/GridLayout.css.js +119 -0
  10. package/src/GridLayout.js +120 -0
  11. package/src/GridLayoutContext.js +58 -0
  12. package/src/GridLayoutDocument.js +307 -0
  13. package/src/GridLayoutDocumentIds.js +110 -0
  14. package/src/GridLayoutItem.css.js +46 -0
  15. package/src/GridLayoutItem.js +147 -0
  16. package/src/GridLayoutLegacyCompatibility.js +66 -0
  17. package/src/GridLayoutModel.js +138 -0
  18. package/src/GridLayoutProvider.js +263 -0
  19. package/src/GridLayoutStackedItem.css.js +26 -0
  20. package/src/GridLayoutStackedtem.js +140 -0
  21. package/src/GridModel.js +1289 -0
  22. package/src/GridPlaceholder.css.js +9 -0
  23. package/src/GridPlaceholder.js +24 -0
  24. package/src/GridSnapshot.js +11 -0
  25. package/src/GridSplitter.css.js +62 -0
  26. package/src/GridSplitter.js +26 -0
  27. package/src/GridStack.js +277 -0
  28. package/src/Icon.css.js +8 -0
  29. package/src/Icon.js +26 -0
  30. package/src/IconButton.css.js +9 -0
  31. package/src/IconButton.js +28 -0
  32. package/src/TabDialog.css.js +10 -0
  33. package/src/TabDialog.js +77 -0
  34. package/src/TabMenu.css.js +8 -0
  35. package/src/TabMenu.js +78 -0
  36. package/src/componentToJson.js +41 -0
  37. package/src/drag-drop-next/DragContextNext.js +173 -0
  38. package/src/drag-drop-next/DragDropProviderNext.css.js +72 -0
  39. package/src/drag-drop-next/DragDropProviderNext.js +91 -0
  40. package/src/drag-drop-next/SpaceMan.js +256 -0
  41. package/src/drag-drop-next/TemplateDragSession.js +36 -0
  42. package/src/drag-drop-next/tabstrip-drag-drop.js +251 -0
  43. package/src/grid-dom-utils.js +57 -0
  44. package/src/grid-layout-utils.js +39 -0
  45. package/src/grid-snapshot-adapters.js +435 -0
  46. package/src/index.js +24 -0
  47. package/src/json-value.js +56 -0
  48. package/src/layoutFromJson.js +15 -0
  49. package/src/layoutToJson.js +5 -0
  50. package/src/propUtils.js +15 -0
  51. package/src/react-element-utils.js +15 -0
  52. package/src/typeOf.js +15 -0
  53. package/src/useAsDropTarget.js +229 -0
  54. package/src/useDraggable.js +46 -0
  55. package/src/useEditTabName.js +70 -0
  56. package/src/useGridChildProps.js +47 -0
  57. package/src/useGridControllerSnapshot.js +21 -0
  58. package/src/useGridLayout.js +727 -0
  59. package/src/useGridSplitterResizing.js +262 -0
  60. package/src/useNotDropTarget.js +2 -0
  61. package/types/AddTabDialog.d.ts +5 -0
  62. package/types/GridCommand.d.ts +146 -0
  63. package/types/GridComponentSettings.d.ts +71 -0
  64. package/types/GridController.d.ts +50 -0
  65. package/types/GridDragCoordinator.d.ts +80 -0
  66. package/types/GridGeometry.d.ts +331 -0
  67. package/types/GridLayout.d.ts +20 -0
  68. package/types/GridLayoutContext.d.ts +141 -0
  69. package/types/GridLayoutDocument.d.ts +61 -0
  70. package/types/GridLayoutDocumentIds.d.ts +15 -0
  71. package/types/GridLayoutItem.d.ts +28 -0
  72. package/types/GridLayoutLegacyCompatibility.d.ts +57 -0
  73. package/types/GridLayoutModel.d.ts +72 -0
  74. package/types/GridLayoutProvider.d.ts +59 -0
  75. package/types/GridLayoutStackedtem.d.ts +10 -0
  76. package/types/GridModel.d.ts +504 -0
  77. package/types/GridPlaceholder.d.ts +5 -0
  78. package/types/GridSnapshot.d.ts +49 -0
  79. package/types/GridSplitter.d.ts +10 -0
  80. package/types/GridStack.d.ts +160 -0
  81. package/types/Icon.d.ts +6 -0
  82. package/types/IconButton.d.ts +6 -0
  83. package/types/TabDialog.d.ts +9 -0
  84. package/types/TabMenu.d.ts +7 -0
  85. package/types/componentToJson.d.ts +38 -0
  86. package/types/drag-drop-next/DragContextNext.d.ts +92 -0
  87. package/types/drag-drop-next/DragDropProviderNext.d.ts +23 -0
  88. package/types/drag-drop-next/SpaceMan.d.ts +35 -0
  89. package/types/drag-drop-next/TemplateDragSession.d.ts +21 -0
  90. package/types/drag-drop-next/tabstrip-drag-drop.d.ts +3 -0
  91. package/types/grid-dom-utils.d.ts +17 -0
  92. package/types/grid-layout-utils.d.ts +18 -0
  93. package/types/grid-matrix.d.ts +5 -0
  94. package/types/grid-snapshot-adapters.d.ts +22 -0
  95. package/types/index.d.ts +24 -0
  96. package/types/json-value.d.ts +23 -0
  97. package/types/layoutFromJson.d.ts +4 -0
  98. package/types/layoutToJson.d.ts +3 -0
  99. package/types/propUtils.d.ts +5 -0
  100. package/types/react-element-utils.d.ts +3 -0
  101. package/types/src/AddTabDialog.d.ts +5 -0
  102. package/types/src/GridLayout.d.ts +14 -0
  103. package/types/src/GridLayoutContext.d.ts +88 -0
  104. package/types/src/GridLayoutItem.d.ts +28 -0
  105. package/types/src/GridLayoutModel.d.ts +59 -0
  106. package/types/src/GridLayoutProvider.d.ts +37 -0
  107. package/types/src/GridLayoutStackedtem.d.ts +10 -0
  108. package/types/src/GridModel.d.ts +350 -0
  109. package/types/src/GridPlaceholder.d.ts +5 -0
  110. package/types/src/GridSplitter.d.ts +9 -0
  111. package/types/src/Icon.d.ts +6 -0
  112. package/types/src/IconButton.d.ts +6 -0
  113. package/types/src/TabMenu.d.ts +6 -0
  114. package/types/src/componentToJson.d.ts +32 -0
  115. package/types/src/drag-drop-next/DragContextNext.d.ts +73 -0
  116. package/types/src/drag-drop-next/DragDropProviderNext.d.ts +20 -0
  117. package/types/src/drag-drop-next/SpaceMan.d.ts +35 -0
  118. package/types/src/drag-drop-next/tabstrip-drag-drop.d.ts +3 -0
  119. package/types/src/grid-dom-utils.d.ts +17 -0
  120. package/types/src/grid-layout-utils.d.ts +80 -0
  121. package/types/src/grid-matrix.d.ts +5 -0
  122. package/types/src/index.d.ts +10 -0
  123. package/types/src/layoutFromJson.d.ts +3 -0
  124. package/types/src/layoutToJson.d.ts +2 -0
  125. package/types/src/propUtils.d.ts +5 -0
  126. package/types/src/react-element-utils.d.ts +3 -0
  127. package/types/src/typeOf.d.ts +6 -0
  128. package/types/src/useAsDropTarget.d.ts +7 -0
  129. package/types/src/useDraggable.d.ts +23 -0
  130. package/types/src/useGridChildProps.d.ts +13 -0
  131. package/types/src/useGridLayout.d.ts +43 -0
  132. package/types/src/useGridSplitterResizing.d.ts +12 -0
  133. package/types/src/useNotDropTarget.d.ts +1 -0
  134. package/types/typeOf.d.ts +6 -0
  135. package/types/useAsDropTarget.d.ts +7 -0
  136. package/types/useDraggable.d.ts +24 -0
  137. package/types/useEditTabName.d.ts +11 -0
  138. package/types/useGridChildProps.d.ts +13 -0
  139. package/types/useGridControllerSnapshot.d.ts +7 -0
  140. package/types/useGridLayout.d.ts +53 -0
  141. package/types/useGridSplitterResizing.d.ts +14 -0
  142. package/types/useNotDropTarget.d.ts +1 -0
@@ -0,0 +1,262 @@
1
+ import { useCallback, useEffect, useRef } from "react";
2
+ import { classNameLayoutItem, getGridLayoutItem, getGridSplitter } from "./grid-dom-utils.js";
3
+ import { adjustDistance, getTrackType } from "./grid-layout-utils.js";
4
+ import { DEFAULT_MIN_GRID_ITEM_SIZE } from "./GridModel.js";
5
+ import { queryClosest } from "@vuu-ui/vuu-utils";
6
+ import { throwForGridCommandFailure } from "./GridCommand.js";
7
+ const useGridSplitterResizing = ({ gridController, gridLayoutModel: layoutModel, gridModel, onClick: onClickProp, rowResizeDistribution })=>{
8
+ const resizingState = useRef(void 0);
9
+ const splitterRef = useRef(void 0);
10
+ const transactionRef = useRef(void 0);
11
+ const getResizeAllowance = useCallback((gridLayout, ids, orientation)=>{
12
+ const dimension = "horizontal" === orientation ? "width" : "height";
13
+ const minimum = "horizontal" === orientation ? "minWidth" : "minHeight";
14
+ return Math.min(...ids.map((id)=>{
15
+ const item = gridModel.getChildItem(id, true);
16
+ const element = gridLayout.querySelector(`#${CSS.escape(id)}`);
17
+ if (!element) throw Error(`[useGridSplitterResizing] GridItem #${id} not found in #${gridModel.id}`);
18
+ const size = element.getBoundingClientRect()[dimension];
19
+ return Math.max(0, size - (item[minimum] ?? DEFAULT_MIN_GRID_ITEM_SIZE));
20
+ }));
21
+ }, [
22
+ gridModel
23
+ ]);
24
+ const getProportionalTrackGroups = useCallback((splitter)=>{
25
+ const indicesFor = (ids)=>{
26
+ const items = ids.map((id)=>gridModel.getChildItem(id, true));
27
+ const start = Math.min(...items.map(({ row })=>row.start)) - 1;
28
+ const end = Math.max(...items.map(({ row })=>row.end)) - 1;
29
+ return Array.from({
30
+ length: end - start
31
+ }, (_, index)=>start + index);
32
+ };
33
+ return {
34
+ after: indicesFor(splitter.resizedChildItems.after),
35
+ before: indicesFor(splitter.resizedChildItems.before)
36
+ };
37
+ }, [
38
+ gridModel
39
+ ]);
40
+ const canResizeGroupsProportionally = useCallback(({ after, before })=>{
41
+ const allTrackIndices = before.concat(after);
42
+ return gridModel.childItems.every((item)=>{
43
+ const itemTrackIndices = Array.from({
44
+ length: item.row.end - item.row.start
45
+ }, (_, index)=>item.row.start - 1 + index);
46
+ const crossesBoundary = before.some((index)=>itemTrackIndices.includes(index)) && after.some((index)=>itemTrackIndices.includes(index));
47
+ return !crossesBoundary || allTrackIndices.every((index)=>itemTrackIndices.includes(index));
48
+ });
49
+ }, [
50
+ gridModel
51
+ ]);
52
+ const getProportionalTrackConstraints = useCallback((trackIndices, oppositeTrackIndices)=>{
53
+ gridModel.tracks.measure("row");
54
+ const tracks = gridModel.tracks.getTracks("row");
55
+ const groupTrackSet = new Set(trackIndices);
56
+ const firstTrack = Math.min(...trackIndices);
57
+ const lastTrack = Math.max(...trackIndices);
58
+ const constraints = [];
59
+ for (const item of gridModel.childItems){
60
+ if (item.stackId || item.row.end - 2 < firstTrack || item.row.start - 1 > lastTrack) continue;
61
+ const itemTrackIndices = Array.from({
62
+ length: item.row.end - item.row.start
63
+ }, (_, index)=>item.row.start - 1 + index);
64
+ if (trackIndices.concat(oppositeTrackIndices).every((index)=>itemTrackIndices.includes(index))) continue;
65
+ const overlappingTrackIndices = itemTrackIndices.filter((index)=>groupTrackSet.has(index));
66
+ const externalSize = itemTrackIndices.filter((index)=>!groupTrackSet.has(index)).reduce((total, index)=>total + tracks[index].numericValue, 0);
67
+ const requiredGroupSize = Math.max(0, (item.minHeight ?? DEFAULT_MIN_GRID_ITEM_SIZE) - externalSize);
68
+ if (requiredGroupSize > 0) constraints.push({
69
+ minimum: requiredGroupSize,
70
+ trackIndices: overlappingTrackIndices
71
+ });
72
+ }
73
+ return constraints;
74
+ }, [
75
+ gridModel
76
+ ]);
77
+ const createNewTrackForResize = useCallback((moveBy)=>{
78
+ const resizeOperation = moveBy < 0 ? "contract" : "expand";
79
+ const { current: state } = resizingState;
80
+ if (state) {
81
+ const { splitter } = state;
82
+ const trackType = getTrackType(splitter);
83
+ const [_, resizeTrackIndex] = splitter.resizedGridTracks;
84
+ layoutModel.addTrackForResize(trackType, Math.abs(moveBy), resizeOperation, resizeTrackIndex, state);
85
+ if ("contract" === resizeOperation) {
86
+ splitter.resizedGridTracks[1] += 1;
87
+ splitter.resizedGridTracks[0] += 1;
88
+ }
89
+ state.resizeTrackIsShared = false;
90
+ }
91
+ }, [
92
+ layoutModel
93
+ ]);
94
+ const removeTrack = useCallback((moveBy, resizeOperation)=>{
95
+ const { current: state } = resizingState;
96
+ let restoredDistance = 0;
97
+ if (state) {
98
+ const { resizeTrackIsShared, splitter } = state;
99
+ const [contraTrackIndex, resizeTrackIndex] = splitter.resizedGridTracks;
100
+ const trackType = getTrackType(splitter);
101
+ const targetTrack = "expand" === resizeOperation ? contraTrackIndex : resizeTrackIndex;
102
+ const currentTracks = gridModel.tracks.getTracks(trackType);
103
+ restoredDistance = currentTracks[targetTrack].numericValue;
104
+ const assignDirection = resizeTrackIsShared ? "expand" === resizeOperation ? "bwd" : "fwd" : "expand" === resizeOperation ? "fwd" : "bwd";
105
+ gridModel.removeGridTrack(trackType, targetTrack, assignDirection);
106
+ state.resizeTrackIsShared = true;
107
+ if ("expand" === resizeOperation) {
108
+ splitter.resizedGridTracks[1] -= 1;
109
+ splitter.resizedGridTracks[0] -= 1;
110
+ }
111
+ const adjustedDistance = adjustDistance(moveBy, restoredDistance);
112
+ if (0 !== adjustedDistance && resizeOperation) createNewTrackForResize(adjustedDistance);
113
+ }
114
+ }, [
115
+ gridModel,
116
+ createNewTrackForResize
117
+ ]);
118
+ const moveSplitter = useCallback((moveBy)=>{
119
+ const { current: state } = resizingState;
120
+ const directionOfTravel = moveBy < 0 ? "bwd" : "fwd";
121
+ if (state) {
122
+ if (state.proportionalTrackGroups) {
123
+ state.proportionalMoveBy = (state.proportionalMoveBy ?? 0) + moveBy;
124
+ gridModel.tracks.resizeGroupsProportionally("row", state.proportionalTrackGroups.before, state.proportionalTrackGroups.after, state.proportionalMoveBy, state.proportionalTrackConstraints?.before, state.proportionalTrackConstraints?.after, state.proportionalInitialTrackSizes);
125
+ return;
126
+ }
127
+ const { splitter } = state;
128
+ const [contraTrackIndex, resizeTrackIndex] = splitter.resizedGridTracks;
129
+ const trackType = "vertical" === splitter.orientation ? "row" : "column";
130
+ const tracks = gridModel.tracks.getTracks(trackType);
131
+ const reducedTrack = "fwd" === directionOfTravel ? tracks[contraTrackIndex] : tracks[resizeTrackIndex];
132
+ if (reducedTrack.isFraction) gridModel.tracks.measure(trackType);
133
+ if (!reducedTrack.isFraction && reducedTrack.numericValue - Math.abs(moveBy) <= 0) "fwd" === directionOfTravel ? removeTrack(moveBy, "expand") : removeTrack(moveBy, "contract");
134
+ else gridModel.tracks.resizeBy(trackType, resizeTrackIndex, contraTrackIndex, moveBy);
135
+ }
136
+ }, [
137
+ gridModel,
138
+ removeTrack
139
+ ]);
140
+ const mouseMove = useCallback(({ clientX, clientY })=>{
141
+ const { current: state } = resizingState;
142
+ if (state) {
143
+ const { mousePos, resizeTrackIsShared, splitter } = state;
144
+ const requestedMousePos = "vertical" === splitter.orientation ? clientY : clientX;
145
+ const newMousePos = Math.min(state.maxMousePos, Math.max(state.minMousePos, requestedMousePos));
146
+ if (newMousePos !== mousePos) {
147
+ const moveBy = mousePos - newMousePos;
148
+ state.mousePos = newMousePos;
149
+ if (0 !== moveBy) {
150
+ if (resizeTrackIsShared) createNewTrackForResize(moveBy);
151
+ moveSplitter(moveBy);
152
+ const transaction = transactionRef.current;
153
+ if (transaction) throwForGridCommandFailure(transaction.dispatch({
154
+ type: "regenerate-placeholders"
155
+ }));
156
+ }
157
+ }
158
+ }
159
+ }, [
160
+ createNewTrackForResize,
161
+ moveSplitter
162
+ ]);
163
+ const mouseUp = useCallback(()=>{
164
+ document.removeEventListener("mousemove", mouseMove);
165
+ document.removeEventListener("mouseup", mouseUp);
166
+ if (splitterRef.current) {
167
+ splitterRef.current.classList.remove("vuuGridSplitter-active");
168
+ splitterRef.current = void 0;
169
+ }
170
+ const transaction = transactionRef.current;
171
+ if (transaction) {
172
+ const result = transaction.commit();
173
+ if (!result.ok) throw Error(result.error.message);
174
+ transactionRef.current = void 0;
175
+ }
176
+ resizingState.current = void 0;
177
+ }, [
178
+ mouseMove
179
+ ]);
180
+ const onMouseDown = useCallback((e)=>{
181
+ const splitterElement = getGridSplitter(e.target);
182
+ if (null === splitterElement) return;
183
+ const gridLayout = queryClosest(splitterElement, ".vuuGridLayout", true);
184
+ if (gridLayout.id === gridModel.id) {
185
+ e.preventDefault();
186
+ const transactionResult = gridController.beginTransaction("resize");
187
+ if (!transactionResult.ok) throw Error(transactionResult.error.message);
188
+ transactionRef.current = transactionResult.transaction;
189
+ const splitter = layoutModel.getSplitterById(splitterElement.id);
190
+ const resizeTrackIsShared = layoutModel.isResizeTrackShared(splitter);
191
+ const candidateTrackGroups = "proportional" !== rowResizeDistribution || "vertical" !== splitter.orientation || resizeTrackIsShared ? void 0 : getProportionalTrackGroups(splitter);
192
+ const proportionalTrackGroups = candidateTrackGroups && canResizeGroupsProportionally(candidateTrackGroups) ? candidateTrackGroups : void 0;
193
+ const proportionalTrackConstraints = proportionalTrackGroups ? {
194
+ after: getProportionalTrackConstraints(proportionalTrackGroups.after, proportionalTrackGroups.before),
195
+ before: getProportionalTrackConstraints(proportionalTrackGroups.before, proportionalTrackGroups.after)
196
+ } : void 0;
197
+ const mousePos = "horizontal" === splitter.ariaOrientation ? e.clientY : e.clientX;
198
+ const beforeAllowance = proportionalTrackGroups ? gridModel.tracks.getProportionalResizeAllowance("row", proportionalTrackGroups.before, proportionalTrackConstraints?.before ?? []) : getResizeAllowance(gridLayout, splitter.resizedChildItems.before, splitter.orientation);
199
+ const afterAllowance = proportionalTrackGroups ? gridModel.tracks.getProportionalResizeAllowance("row", proportionalTrackGroups.after, proportionalTrackConstraints?.after ?? []) : getResizeAllowance(gridLayout, splitter.resizedChildItems.after, splitter.orientation);
200
+ resizingState.current = {
201
+ maxMousePos: mousePos + afterAllowance,
202
+ minMousePos: mousePos - beforeAllowance,
203
+ mousePos,
204
+ proportionalTrackConstraints,
205
+ proportionalTrackGroups,
206
+ proportionalInitialTrackSizes: proportionalTrackGroups ? gridModel.tracks.getTracks("row").map((track)=>track.numericValue) : void 0,
207
+ proportionalMoveBy: proportionalTrackGroups ? 0 : void 0,
208
+ resizeTrackIsShared,
209
+ splitter
210
+ };
211
+ document.addEventListener("mousemove", mouseMove);
212
+ document.addEventListener("mouseup", mouseUp);
213
+ splitterElement.classList.add("vuuGridSplitter-active");
214
+ splitterRef.current = splitterElement;
215
+ }
216
+ }, [
217
+ canResizeGroupsProportionally,
218
+ getProportionalTrackGroups,
219
+ getProportionalTrackConstraints,
220
+ getResizeAllowance,
221
+ gridController,
222
+ gridModel,
223
+ layoutModel,
224
+ mouseMove,
225
+ mouseUp,
226
+ rowResizeDistribution
227
+ ]);
228
+ useEffect(()=>()=>{
229
+ document.removeEventListener("mousemove", mouseMove);
230
+ document.removeEventListener("mouseup", mouseUp);
231
+ const transaction = transactionRef.current;
232
+ if (transaction) {
233
+ transaction.rollback();
234
+ transactionRef.current = void 0;
235
+ }
236
+ }, [
237
+ mouseMove,
238
+ mouseUp
239
+ ]);
240
+ const selectedRef = useRef(void 0);
241
+ const clickHandler = useCallback((e)=>{
242
+ const gridLayoutItem = getGridLayoutItem(e.target);
243
+ if (gridLayoutItem) {
244
+ const { left, top } = gridLayoutItem.getBoundingClientRect();
245
+ if (e.clientY < top || e.clientX < left) return;
246
+ if (selectedRef.current) {
247
+ const el = document.getElementById(selectedRef.current);
248
+ el.classList.remove(`${classNameLayoutItem}-active`);
249
+ }
250
+ selectedRef.current = gridLayoutItem.id;
251
+ gridLayoutItem.classList.add(`${classNameLayoutItem}-active`);
252
+ }
253
+ onClickProp?.(e);
254
+ }, [
255
+ onClickProp
256
+ ]);
257
+ return {
258
+ onClick: clickHandler,
259
+ onMouseDown
260
+ };
261
+ };
262
+ export { useGridSplitterResizing };
@@ -0,0 +1,2 @@
1
+ const useNotDropTarget = ()=>({});
2
+ export { useNotDropTarget };
@@ -0,0 +1,5 @@
1
+ export declare const AddTabDialog: ({ open, onConfirm, onCancel, }: {
2
+ open?: boolean;
3
+ onConfirm: (value: string) => void;
4
+ onCancel: () => void;
5
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,146 @@
1
+ import { type GridLayoutSplitDirection } from "@vuu-ui/vuu-utils";
2
+ import { GridLayoutModel, type GridItemRemoveReason } from "./GridLayoutModel";
3
+ import { type GridModel, type TrackSize, type TrackType } from "./GridModel";
4
+ import type { GridItemId, GridItemResizeable, GridSpanSnapshot, StackId } from "./GridSnapshot";
5
+ export interface GridCommandItem {
6
+ readonly column: GridSpanSnapshot;
7
+ readonly contentVisible?: boolean;
8
+ readonly dropTarget?: boolean | string;
9
+ readonly header?: boolean;
10
+ readonly id: GridItemId;
11
+ readonly minHeight?: number;
12
+ readonly minWidth?: number;
13
+ readonly resizeable?: GridItemResizeable;
14
+ readonly row: GridSpanSnapshot;
15
+ readonly title?: string;
16
+ }
17
+ export interface GridCommandResizeConstraint {
18
+ readonly minimum: number;
19
+ readonly trackIndices: readonly number[];
20
+ }
21
+ export type GridTrackResize = {
22
+ readonly contraTrackIndex: number;
23
+ readonly delta: number;
24
+ readonly distribution: "adjacent";
25
+ readonly measuredSizes?: readonly number[];
26
+ readonly resizedTrackIndex: number;
27
+ readonly track: TrackType;
28
+ } | {
29
+ readonly afterConstraints?: readonly GridCommandResizeConstraint[];
30
+ readonly afterTrackIndices: readonly number[];
31
+ readonly beforeConstraints?: readonly GridCommandResizeConstraint[];
32
+ readonly beforeTrackIndices: readonly number[];
33
+ readonly delta: number;
34
+ readonly distribution: "proportional";
35
+ readonly initialSizes?: readonly number[];
36
+ readonly measuredSizes?: readonly number[];
37
+ readonly track: TrackType;
38
+ };
39
+ export type GridCommand = {
40
+ readonly item: GridCommandItem;
41
+ readonly type: "add-item";
42
+ } | {
43
+ readonly itemId: GridItemId;
44
+ readonly position: GridLayoutSplitDirection;
45
+ readonly targetId: GridItemId;
46
+ readonly type: "move-item";
47
+ } | {
48
+ readonly itemId: GridItemId;
49
+ readonly targetId: GridItemId;
50
+ readonly type: "replace-item";
51
+ } | {
52
+ readonly itemId: GridItemId;
53
+ readonly stackId: StackId;
54
+ readonly targetId: GridItemId;
55
+ readonly type: "replace-stack-item";
56
+ } | {
57
+ readonly itemId: GridItemId;
58
+ readonly reason: GridItemRemoveReason;
59
+ readonly type: "remove-item";
60
+ } | {
61
+ readonly index: number;
62
+ readonly size: TrackSize;
63
+ readonly track: TrackType;
64
+ readonly type: "resize-track";
65
+ } | ({
66
+ readonly type: "resize-tracks";
67
+ } & GridTrackResize) | {
68
+ readonly itemId: GridItemId;
69
+ readonly selectedItemId?: GridItemId;
70
+ readonly targetId: GridItemId;
71
+ readonly type: "create-stack";
72
+ } | {
73
+ readonly item: GridCommandItem;
74
+ readonly position?: "after" | "before";
75
+ readonly stackId: StackId;
76
+ readonly targetItemId?: GridItemId;
77
+ readonly type: "add-stack-item";
78
+ } | {
79
+ readonly itemId: GridItemId;
80
+ readonly stackId: StackId;
81
+ readonly type: "remove-stack-item";
82
+ } | {
83
+ readonly fromStackId?: StackId;
84
+ readonly itemId: GridItemId;
85
+ readonly position?: "after" | "before";
86
+ readonly stackId: StackId;
87
+ readonly targetItemId?: GridItemId;
88
+ readonly type: "move-item-to-stack";
89
+ } | {
90
+ readonly itemId: GridItemId;
91
+ readonly position: GridLayoutSplitDirection;
92
+ readonly stackId: StackId;
93
+ readonly targetId: GridItemId;
94
+ readonly type: "move-stack-item-to-grid";
95
+ } | {
96
+ readonly itemId: GridItemId;
97
+ readonly stackId: StackId;
98
+ readonly type: "select-stack-item";
99
+ } | {
100
+ readonly activate?: boolean;
101
+ readonly itemId: GridItemId;
102
+ readonly position: "after" | "before";
103
+ readonly stackId: StackId;
104
+ readonly targetItemId: GridItemId;
105
+ readonly type: "reorder-stack-item";
106
+ } | {
107
+ readonly itemId: GridItemId;
108
+ readonly title: string;
109
+ readonly type: "rename-item";
110
+ } | {
111
+ readonly type: "regenerate-placeholders";
112
+ };
113
+ export type GridCommandErrorCode = "DUPLICATE_ITEM_ID" | "INVALID_ITEM" | "INVALID_TARGET" | "ITEM_NOT_FOUND" | "MEASUREMENT_REQUIRED" | "NON_RESIZABLE" | "STACK_NOT_FOUND" | "TAB_NOT_FOUND" | "TRACK_NOT_FOUND" | "TRANSACTION_ACTIVE" | "TRANSACTION_CLOSED" | "UNSUPPORTED_ACTION";
114
+ export interface GridCommandError {
115
+ readonly code: GridCommandErrorCode;
116
+ readonly message: string;
117
+ }
118
+ export type GridCommandResult = {
119
+ readonly command: GridCommand["type"];
120
+ readonly ok: true;
121
+ } | {
122
+ readonly command: GridCommand["type"];
123
+ readonly error: GridCommandError;
124
+ readonly ok: false;
125
+ };
126
+ export declare class GridCommandExecutionError extends Error {
127
+ readonly code: GridCommandErrorCode;
128
+ constructor({ code, message }: GridCommandError);
129
+ }
130
+ export declare class LegacyGridCommandExecutor {
131
+ private readonly gridModel;
132
+ private readonly gridLayoutModel;
133
+ constructor(gridModel: GridModel, gridLayoutModel?: GridLayoutModel);
134
+ execute(command: GridCommand): GridCommandResult;
135
+ private removeItem;
136
+ private applyMeasurements;
137
+ private validateResizeCommand;
138
+ private requireItem;
139
+ private requireStack;
140
+ private requireTab;
141
+ private requireTracks;
142
+ private validateNewItem;
143
+ private validatePair;
144
+ private rejectStackMember;
145
+ }
146
+ export declare const throwForGridCommandFailure: (result: GridCommandResult) => void;
@@ -0,0 +1,71 @@
1
+ import type { ReactElement } from "react";
2
+ import type { JsonValue } from "./json-value";
3
+ export interface GridSettingsCodecIssue {
4
+ readonly code: string;
5
+ readonly message: string;
6
+ readonly path: string;
7
+ }
8
+ export type GridSettingsCodecResult<T> = {
9
+ readonly ok: true;
10
+ readonly value: T;
11
+ } | {
12
+ readonly error: GridSettingsCodecIssue;
13
+ readonly ok: false;
14
+ };
15
+ export interface GridComponentSettingsCodec<T> {
16
+ readonly decode: (value: JsonValue) => GridSettingsCodecResult<T>;
17
+ readonly encode: (settings: T) => GridSettingsCodecResult<unknown>;
18
+ readonly isSettings: (value: unknown) => value is T;
19
+ readonly migrations?: Readonly<Record<number, (value: JsonValue) => GridSettingsCodecResult<unknown>>>;
20
+ readonly version: number;
21
+ }
22
+ export interface GridComponentSettingsInput {
23
+ readonly id: string;
24
+ readonly settings: unknown;
25
+ readonly type: string;
26
+ }
27
+ export interface EncodedGridComponentSettings {
28
+ readonly id: string;
29
+ readonly settings: JsonValue;
30
+ readonly type: string;
31
+ readonly version: number;
32
+ }
33
+ export interface DecodedGridComponentSettings {
34
+ readonly id: string;
35
+ readonly settings: unknown;
36
+ readonly type: string;
37
+ readonly version: number;
38
+ }
39
+ export type GridComponentSettingsErrorCode = "COMPONENT_DECODE_FAILED" | "COMPONENT_ENCODE_FAILED" | "COMPONENT_MIGRATION_FAILED" | "INVALID_COMPONENT_SETTINGS" | "UNKNOWN_COMPONENT_TYPE" | "UNSUPPORTED_COMPONENT_VERSION";
40
+ export interface GridComponentSettingsError {
41
+ readonly code: GridComponentSettingsErrorCode;
42
+ readonly componentId: string;
43
+ readonly componentType: string;
44
+ readonly message: string;
45
+ readonly path: string;
46
+ readonly version?: number;
47
+ }
48
+ export type GridComponentSettingsResult<T> = {
49
+ readonly ok: true;
50
+ readonly value: T;
51
+ } | {
52
+ readonly error: GridComponentSettingsError;
53
+ readonly ok: false;
54
+ };
55
+ export declare class GridComponentSettingsRegistry {
56
+ #private;
57
+ register<T>(type: string, codec: GridComponentSettingsCodec<T>): void;
58
+ encode(component: GridComponentSettingsInput): GridComponentSettingsResult<EncodedGridComponentSettings>;
59
+ decode(component: EncodedGridComponentSettings): GridComponentSettingsResult<DecodedGridComponentSettings>;
60
+ }
61
+ export type GridComponentRenderer<T> = (settings: T, componentId: string) => ReactElement;
62
+ export declare class GridComponentRendererRegistry {
63
+ #private;
64
+ register<T>(type: string, isSettings: (value: unknown) => value is T, render: GridComponentRenderer<T>): void;
65
+ render(component: DecodedGridComponentSettings): ReactElement;
66
+ }
67
+ export declare class GridLayoutContentRegistry<T> {
68
+ #private;
69
+ entries(): ReadonlyMap<string, T>;
70
+ replace(components: readonly DecodedGridComponentSettings[], resolve: (component: DecodedGridComponentSettings) => T): void;
71
+ }
@@ -0,0 +1,50 @@
1
+ import { LegacyGridCommandExecutor, type GridCommand, type GridCommandResult } from "./GridCommand";
2
+ import type { GridModel } from "./GridModel";
3
+ import type { GridSnapshot } from "./GridSnapshot";
4
+ export type GridTransactionKind = "drag" | "resize";
5
+ export type GridControllerListener = () => void;
6
+ export type GridControllerErrorCode = "TRANSACTION_ACTIVE" | "TRANSACTION_CLOSED";
7
+ export interface GridControllerError {
8
+ readonly code: GridControllerErrorCode;
9
+ readonly message: string;
10
+ }
11
+ export type GridTransactionStartResult = {
12
+ readonly ok: true;
13
+ readonly transaction: GridTransaction;
14
+ } | {
15
+ readonly error: GridControllerError;
16
+ readonly ok: false;
17
+ };
18
+ export type GridTransactionCloseResult = {
19
+ readonly ok: true;
20
+ readonly snapshot: GridSnapshot;
21
+ } | {
22
+ readonly error: GridControllerError;
23
+ readonly ok: false;
24
+ };
25
+ export interface GridTransaction {
26
+ readonly kind: GridTransactionKind;
27
+ commit(): GridTransactionCloseResult;
28
+ dispatch(command: GridCommand): GridCommandResult;
29
+ establishWorkingBaseline(commands: readonly GridCommand[]): GridCommandResult;
30
+ replace(commands: readonly GridCommand[]): GridCommandResult;
31
+ rollback(): GridTransactionCloseResult;
32
+ validateReplacement(commands: readonly GridCommand[]): GridCommandResult;
33
+ }
34
+ export interface GridCommittedTransition {
35
+ readonly commands: readonly GridCommand[];
36
+ readonly kind: "dispatch" | GridTransactionKind;
37
+ readonly previous: GridSnapshot;
38
+ readonly snapshot: GridSnapshot;
39
+ }
40
+ export type GridCommittedTransitionListener = (transition: GridCommittedTransition) => void;
41
+ export declare class GridController {
42
+ #private;
43
+ private readonly gridModel;
44
+ constructor(gridModel: GridModel, revision?: number, executor?: LegacyGridCommandExecutor);
45
+ getSnapshot: () => GridSnapshot;
46
+ subscribe: (listener: GridControllerListener) => (() => void);
47
+ subscribeCommitted: (listener: GridCommittedTransitionListener) => (() => void);
48
+ dispatch(command: GridCommand): GridCommandResult;
49
+ beginTransaction(kind: GridTransactionKind): GridTransactionStartResult;
50
+ }
@@ -0,0 +1,80 @@
1
+ import type { GridCommand, GridCommandItem } from "./GridCommand";
2
+ import type { GridController, GridControllerError } from "./GridController";
3
+ import type { GridId, GridItemId, StackId } from "./GridSnapshot";
4
+ export type GridDragSource = {
5
+ readonly itemId: GridItemId;
6
+ readonly kind: "existing-item";
7
+ readonly sourceGridId: GridId;
8
+ } | {
9
+ readonly itemId: GridItemId;
10
+ readonly kind: "stack-member";
11
+ readonly selected: boolean;
12
+ readonly sourceGridId: GridId;
13
+ readonly stackId: StackId;
14
+ } | {
15
+ readonly item: GridCommandItem;
16
+ readonly kind: "palette-template";
17
+ readonly templateId: string;
18
+ };
19
+ export type GridDropIntent = {
20
+ readonly kind: "replace";
21
+ } | {
22
+ readonly kind: "split";
23
+ readonly position: "east" | "north" | "south" | "west";
24
+ } | {
25
+ readonly kind: "create-stack";
26
+ } | {
27
+ readonly kind: "stack";
28
+ readonly position?: "after" | "before";
29
+ readonly targetItemId?: GridItemId;
30
+ };
31
+ export interface GridDropTarget {
32
+ readonly gridId: GridId;
33
+ readonly intent: GridDropIntent;
34
+ readonly targetId: GridItemId | StackId;
35
+ }
36
+ export type GridDragCoordinatorState = {
37
+ readonly phase: "idle";
38
+ } | {
39
+ readonly phase: "dragging";
40
+ readonly source: GridDragSource;
41
+ } | {
42
+ readonly phase: "previewing";
43
+ readonly plan: GridDropPlan;
44
+ readonly source: GridDragSource;
45
+ readonly target: GridDropTarget;
46
+ } | {
47
+ readonly phase: "committed" | "cancelled";
48
+ readonly source: GridDragSource;
49
+ };
50
+ export type GridDropPlan = {
51
+ readonly commands: readonly GridCommand[];
52
+ readonly source: GridDragSource;
53
+ readonly target: GridDropTarget;
54
+ };
55
+ export type GridDragCoordinatorErrorCode = "CROSS_GRID_DRAG" | "INVALID_TRANSITION" | "TRANSACTION_FAILURE" | "UNSUPPORTED_DROP";
56
+ export interface GridDragCoordinatorError {
57
+ readonly code: GridDragCoordinatorErrorCode;
58
+ readonly message: string;
59
+ }
60
+ export type GridDragCoordinatorResult = {
61
+ readonly ok: true;
62
+ readonly state: GridDragCoordinatorState;
63
+ } | {
64
+ readonly error: GridDragCoordinatorError | GridControllerError;
65
+ readonly ok: false;
66
+ };
67
+ export declare const createGridDropPlan: (source: GridDragSource, target: GridDropTarget) => GridDropPlan | GridDragCoordinatorError;
68
+ export declare class GridDragCoordinator {
69
+ #private;
70
+ readonly gridId: GridId;
71
+ private readonly controller;
72
+ constructor(gridId: GridId, controller: GridController);
73
+ get state(): GridDragCoordinatorState;
74
+ begin(source: GridDragSource): GridDragCoordinatorResult;
75
+ preview(target: GridDropTarget): GridDragCoordinatorResult;
76
+ commit(): GridDragCoordinatorResult;
77
+ clearPreview(): GridDragCoordinatorResult;
78
+ cancel(): GridDragCoordinatorResult;
79
+ dispose(): void;
80
+ }