@vuu-ui/vuu-layout 0.5.9 → 0.5.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 (114) hide show
  1. package/package.json +10 -13
  2. package/src/Component.css +0 -0
  3. package/src/Component.tsx +20 -0
  4. package/src/DraggableLayout.css +18 -0
  5. package/src/DraggableLayout.tsx +26 -0
  6. package/src/__tests__/flexbox-utils.spec.js +90 -0
  7. package/src/chest-of-drawers/Chest.css +36 -0
  8. package/src/chest-of-drawers/Chest.tsx +42 -0
  9. package/src/chest-of-drawers/Drawer.css +159 -0
  10. package/src/chest-of-drawers/Drawer.tsx +118 -0
  11. package/src/chest-of-drawers/index.ts +2 -0
  12. package/src/common-types.ts +9 -0
  13. package/src/debug.ts +16 -0
  14. package/src/drag-drop/BoxModel.ts +551 -0
  15. package/src/drag-drop/DragState.ts +219 -0
  16. package/src/drag-drop/Draggable.ts +282 -0
  17. package/src/drag-drop/DropMenu.css +71 -0
  18. package/src/drag-drop/DropMenu.tsx +61 -0
  19. package/src/drag-drop/DropTarget.ts +393 -0
  20. package/src/drag-drop/DropTargetRenderer.css +40 -0
  21. package/src/drag-drop/DropTargetRenderer.tsx +277 -0
  22. package/src/drag-drop/dragDropTypes.ts +47 -0
  23. package/src/drag-drop/index.ts +5 -0
  24. package/src/editable-label/EditableLabel.css +28 -0
  25. package/src/editable-label/EditableLabel.tsx +99 -0
  26. package/src/editable-label/index.ts +1 -0
  27. package/src/flexbox/Flexbox.css +45 -0
  28. package/src/flexbox/Flexbox.tsx +70 -0
  29. package/src/flexbox/FlexboxLayout.tsx +28 -0
  30. package/src/flexbox/FluidGrid.css +134 -0
  31. package/src/flexbox/FluidGrid.tsx +82 -0
  32. package/src/flexbox/FluidGridLayout.tsx +9 -0
  33. package/src/flexbox/Splitter.css +140 -0
  34. package/src/flexbox/Splitter.tsx +127 -0
  35. package/src/flexbox/flexbox-utils.ts +128 -0
  36. package/src/flexbox/flexboxTypes.ts +68 -0
  37. package/src/flexbox/index.ts +5 -0
  38. package/src/flexbox/useResponsiveSizing.ts +82 -0
  39. package/src/flexbox/useSplitterResizing.ts +270 -0
  40. package/src/index.ts +19 -0
  41. package/src/layout-action.ts +21 -0
  42. package/src/layout-header/ActionButton.tsx +23 -0
  43. package/src/layout-header/Header.css +8 -0
  44. package/src/layout-header/Header.tsx +216 -0
  45. package/src/layout-header/index.ts +1 -0
  46. package/src/layout-provider/LayoutProvider.tsx +161 -0
  47. package/src/layout-provider/LayoutProviderContext.ts +17 -0
  48. package/src/layout-provider/index.ts +3 -0
  49. package/src/layout-provider/useLayoutDragDrop.ts +210 -0
  50. package/src/layout-reducer/flexUtils.ts +276 -0
  51. package/src/layout-reducer/index.ts +5 -0
  52. package/src/layout-reducer/insert-layout-element.ts +365 -0
  53. package/src/layout-reducer/layout-reducer.ts +237 -0
  54. package/src/layout-reducer/layoutTypes.ts +159 -0
  55. package/src/layout-reducer/layoutUtils.ts +288 -0
  56. package/src/layout-reducer/remove-layout-element.ts +226 -0
  57. package/src/layout-reducer/replace-layout-element.ts +113 -0
  58. package/src/layout-reducer/resize-flex-children.ts +55 -0
  59. package/src/layout-reducer/wrap-layout-element.ts +307 -0
  60. package/src/layout-view/View.css +61 -0
  61. package/src/layout-view/View.tsx +143 -0
  62. package/src/layout-view/ViewContext.ts +30 -0
  63. package/src/layout-view/index.ts +5 -0
  64. package/src/layout-view/useView.tsx +104 -0
  65. package/src/layout-view/useViewActionDispatcher.ts +123 -0
  66. package/src/layout-view/useViewResize.ts +53 -0
  67. package/src/layout-view/viewTypes.ts +35 -0
  68. package/src/palette/Palette.css +33 -0
  69. package/src/palette/Palette.tsx +140 -0
  70. package/src/palette/PaletteSalt.css +9 -0
  71. package/src/palette/PaletteSalt.tsx +79 -0
  72. package/src/palette/index.ts +3 -0
  73. package/src/placeholder/Placeholder.css +10 -0
  74. package/src/placeholder/Placeholder.tsx +38 -0
  75. package/src/placeholder/index.ts +1 -0
  76. package/src/registry/ComponentRegistry.ts +44 -0
  77. package/src/registry/index.ts +1 -0
  78. package/src/responsive/breakpoints.ts +62 -0
  79. package/src/responsive/index.ts +3 -0
  80. package/src/responsive/measureMinimumNodeSize.ts +23 -0
  81. package/src/responsive/overflowUtils.js +14 -0
  82. package/src/responsive/use-breakpoints.ts +101 -0
  83. package/src/responsive/useResizeObserver.ts +154 -0
  84. package/src/responsive/utils.ts +37 -0
  85. package/src/stack/Stack.css +39 -0
  86. package/src/stack/Stack.tsx +173 -0
  87. package/src/stack/StackLayout.tsx +119 -0
  88. package/src/stack/index.ts +4 -0
  89. package/src/stack/stackTypes.ts +22 -0
  90. package/src/tabs/TabPanel.css +12 -0
  91. package/src/tabs/TabPanel.tsx +17 -0
  92. package/src/tabs/index.ts +1 -0
  93. package/src/tools/config-wrapper/ConfigWrapper.tsx +55 -0
  94. package/src/tools/config-wrapper/index.ts +1 -0
  95. package/src/tools/devtools-box/layout-configurator.css +112 -0
  96. package/src/tools/devtools-box/layout-configurator.jsx +369 -0
  97. package/src/tools/devtools-tree/layout-tree-viewer.css +15 -0
  98. package/src/tools/devtools-tree/layout-tree-viewer.jsx +36 -0
  99. package/src/tools/index.ts +4 -0
  100. package/src/use-persistent-state.ts +112 -0
  101. package/src/utils/index.ts +5 -0
  102. package/src/utils/pathUtils.ts +283 -0
  103. package/src/utils/propUtils.ts +26 -0
  104. package/src/utils/refUtils.ts +16 -0
  105. package/src/utils/styleUtils.ts +13 -0
  106. package/src/utils/typeOf.ts +25 -0
  107. package/tsconfig-emit-types.json +11 -0
  108. package/LICENSE +0 -201
  109. package/cjs/index.js +0 -20
  110. package/cjs/index.js.map +0 -7
  111. package/esm/index.js +0 -20
  112. package/esm/index.js.map +0 -7
  113. package/index.css +0 -2
  114. package/index.css.map +0 -7
@@ -0,0 +1,276 @@
1
+ import { uuid } from "@vuu-ui/vuu-utils";
2
+ import React, { CSSProperties, ReactElement, ReactNode } from "react";
3
+ import { dimension, rect, rectTuple } from "../common-types";
4
+ import { DropPos } from "../drag-drop/dragDropTypes";
5
+ import { ComponentRegistry } from "../registry/ComponentRegistry";
6
+ import { getProps, resetPath } from "../utils";
7
+ const placeHolderProps = { "data-placeholder": true, "data-resizeable": true };
8
+
9
+ const NO_STYLE = {};
10
+ const auto = "auto";
11
+ const defaultFlexStyle = {
12
+ flexBasis: 0,
13
+ flexGrow: 1,
14
+ flexShrink: 1,
15
+ height: auto,
16
+ width: auto,
17
+ };
18
+
19
+ const CROSS_DIMENSION = {
20
+ height: "width",
21
+ width: "height",
22
+ };
23
+
24
+ export type flexDirection = "row" | "column";
25
+
26
+ type contraDimension = dimension;
27
+ type flexDimensionTuple = [dimension, contraDimension, flexDirection];
28
+ export type position = {
29
+ height?: number;
30
+ width?: number;
31
+ };
32
+
33
+ export const getFlexDimensions = (flexDirection: flexDirection = "row") => {
34
+ if (flexDirection === "row") {
35
+ return ["width", "height", "column"] as flexDimensionTuple;
36
+ } else {
37
+ return ["height", "width", "row"] as flexDimensionTuple;
38
+ }
39
+ };
40
+
41
+ const isPercentageSize = (value: string | number) =>
42
+ typeof value === "string" && value.endsWith("%");
43
+
44
+ export const getIntrinsicSize = (
45
+ component: ReactElement
46
+ ): { height?: number; width?: number } | undefined => {
47
+ const { style: { width = auto, height = auto } = NO_STYLE } = component.props;
48
+
49
+ const numHeight = typeof height === "number";
50
+ const numWidth = typeof width === "number";
51
+
52
+ if (numHeight && numWidth) {
53
+ return { height, width };
54
+ } else if (numHeight) {
55
+ return { height };
56
+ } else if (numWidth) {
57
+ return { width };
58
+ } else {
59
+ return undefined;
60
+ }
61
+ };
62
+
63
+ export function getFlexStyle(
64
+ component: ReactElement,
65
+ dimension: dimension,
66
+ pos?: DropPos
67
+ ) {
68
+ const crossDimension = CROSS_DIMENSION[dimension];
69
+ const {
70
+ style: {
71
+ [crossDimension]: intrinsicCrossSize = auto,
72
+ ...intrinsicStyles
73
+ } = NO_STYLE,
74
+ } = component.props;
75
+
76
+ if (pos && pos[dimension]) {
77
+ return {
78
+ ...intrinsicStyles,
79
+ ...defaultFlexStyle,
80
+ flexBasis: pos[dimension],
81
+ flexGrow: 0,
82
+ flexShrink: 0,
83
+ };
84
+ } else {
85
+ return {
86
+ ...intrinsicStyles,
87
+ ...defaultFlexStyle,
88
+ [crossDimension]: intrinsicCrossSize,
89
+ };
90
+ }
91
+ }
92
+
93
+ export function hasUnboundedFlexStyle(component: ReactElement) {
94
+ const { style: { flex, flexGrow, flexShrink, flexBasis } = NO_STYLE } =
95
+ component.props;
96
+ if (typeof flex === "number") {
97
+ return true;
98
+ }
99
+ if (flexBasis === 0 && flexGrow === 1 && flexShrink === 1) {
100
+ return true;
101
+ }
102
+ if (typeof flexBasis === "number") {
103
+ return false;
104
+ }
105
+ return true;
106
+ }
107
+
108
+ export function getFlexOrIntrinsicStyle(
109
+ component: ReactElement,
110
+ dimension: dimension,
111
+ pos: position
112
+ ) {
113
+ const crossDimension = CROSS_DIMENSION[dimension];
114
+ const {
115
+ style: {
116
+ [dimension]: intrinsicSize = auto,
117
+ [crossDimension]: intrinsicCrossSize = auto,
118
+ ...intrinsicStyles
119
+ } = NO_STYLE,
120
+ } = component.props;
121
+
122
+ if (intrinsicSize !== auto) {
123
+ if (isPercentageSize(intrinsicSize)) {
124
+ return {
125
+ flexBasis: 0,
126
+ flexGrow: 1,
127
+ flexShrink: 1,
128
+ [dimension]: undefined,
129
+ [crossDimension]: intrinsicCrossSize,
130
+ };
131
+ }
132
+ return {
133
+ flexBasis: intrinsicSize,
134
+ flexGrow: 0,
135
+ flexShrink: 0,
136
+ [dimension]: intrinsicSize,
137
+ [crossDimension]: intrinsicCrossSize,
138
+ };
139
+ }
140
+ if (pos && pos[dimension]) {
141
+ return {
142
+ ...intrinsicStyles,
143
+ ...defaultFlexStyle,
144
+ flexBasis: pos[dimension],
145
+ flexGrow: 0,
146
+ flexShrink: 0,
147
+ };
148
+ }
149
+ return {
150
+ ...intrinsicStyles,
151
+ [crossDimension]: intrinsicCrossSize,
152
+ };
153
+ }
154
+
155
+ export function wrapIntrinsicSizeComponentWithFlexbox(
156
+ component: ReactElement,
157
+ flexDirection: flexDirection,
158
+ path: string,
159
+ clientRect?: rect,
160
+ dropRect?: rectTuple
161
+ ) {
162
+ const wrappedChildren = [];
163
+ let pathIndex = 0;
164
+ let endPlaceholder;
165
+
166
+ if (clientRect && dropRect) {
167
+ let startPlaceholder;
168
+ const [dropLeft, dropTop, dropRight, dropBottom] = dropRect;
169
+ [startPlaceholder, endPlaceholder] =
170
+ flexDirection === "column"
171
+ ? [dropTop - clientRect.top, clientRect.bottom - dropBottom]
172
+ : [dropLeft - clientRect.left, clientRect.right - dropRight];
173
+
174
+ if (startPlaceholder) {
175
+ wrappedChildren.push(
176
+ createPlaceHolder(`${path}.${pathIndex++}`, startPlaceholder, {
177
+ flexGrow: 0,
178
+ flexShrink: 0,
179
+ })
180
+ );
181
+ }
182
+ } else {
183
+ endPlaceholder = true;
184
+ }
185
+
186
+ const { version = 0, style } = getProps(component);
187
+
188
+ wrappedChildren.push(
189
+ resetPath(component, `${path}.${pathIndex++}`, {
190
+ version: version + 1,
191
+ style: {
192
+ ...style,
193
+ flexBasis: "auto",
194
+ flexGrow: 0,
195
+ flexShrink: 0,
196
+ },
197
+ })
198
+ );
199
+
200
+ if (endPlaceholder) {
201
+ wrappedChildren.push(
202
+ createPlaceHolder(`${path}.${pathIndex++}`, 0, undefined, {
203
+ [`data-${flexDirection}-placeholder`]: true,
204
+ })
205
+ );
206
+ }
207
+
208
+ return createFlexbox(
209
+ flexDirection,
210
+ { resizeable: false, style: { flexBasis: "auto" } },
211
+ wrappedChildren,
212
+ path
213
+ );
214
+ }
215
+
216
+ const getFlexValue = (
217
+ flexBasis: number,
218
+ flexFill: boolean
219
+ ): number | undefined => {
220
+ if (flexFill) {
221
+ return undefined;
222
+ }
223
+ return flexBasis === 0 ? 1 : 0;
224
+ };
225
+
226
+ export function createFlexbox(
227
+ flexDirection: flexDirection,
228
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
229
+ props: any,
230
+ children: ReactNode,
231
+ path: string
232
+ ) {
233
+ const id = uuid();
234
+ const { flexFill, style, resizeable = true } = props;
235
+ const { flexBasis = flexFill ? undefined : "auto" } = style;
236
+ const flex = getFlexValue(flexBasis, flexFill);
237
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
238
+ return React.createElement<any>(
239
+ ComponentRegistry.Flexbox,
240
+ {
241
+ id,
242
+ key: id,
243
+ path,
244
+ flexFill,
245
+ style: {
246
+ ...style,
247
+ flexDirection,
248
+ flexBasis,
249
+ flexGrow: flex,
250
+ flexShrink: flex,
251
+ },
252
+ resizeable,
253
+ },
254
+ children
255
+ );
256
+ }
257
+
258
+ const baseStyle = { flexGrow: 1, flexShrink: 1 };
259
+
260
+ export function createPlaceHolder(
261
+ path: string,
262
+ size: number,
263
+ style?: CSSProperties,
264
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
265
+ props?: any
266
+ ) {
267
+ const id = uuid();
268
+ return React.createElement("div", {
269
+ ...placeHolderProps,
270
+ ...props,
271
+ "data-path": path,
272
+ id,
273
+ key: id,
274
+ style: { ...baseStyle, ...style, flexBasis: size },
275
+ });
276
+ }
@@ -0,0 +1,5 @@
1
+ export * from './flexUtils';
2
+ export * from './layout-reducer';
3
+ export * from './layoutTypes';
4
+ export * from './layoutUtils';
5
+
@@ -0,0 +1,365 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { uuid } from "@vuu-ui/vuu-utils";
3
+ import React, { ReactElement } from "react";
4
+ import { rectTuple } from "../common-types";
5
+ import { DropPos } from "../drag-drop";
6
+ import { DropTarget } from "../drag-drop/DropTarget";
7
+ import { getProp, getProps, nextStep, resetPath, typeOf } from "../utils";
8
+ import {
9
+ createPlaceHolder,
10
+ flexDirection,
11
+ getFlexDimensions,
12
+ getFlexOrIntrinsicStyle,
13
+ getIntrinsicSize,
14
+ wrapIntrinsicSizeComponentWithFlexbox,
15
+ } from "./flexUtils";
16
+ import { LayoutModel } from "./layoutTypes";
17
+ import { getManagedDimension, LayoutProps } from "./layoutUtils";
18
+
19
+ type insertionPosition = "before" | "after";
20
+
21
+ export function getInsertTabBeforeAfter(stack: LayoutModel, pos: DropPos) {
22
+ const tabs = stack.props.children;
23
+ const tabCount = tabs.length;
24
+ const { index = -1, positionRelativeToTab = "after" } = pos.tab || {};
25
+ return index === -1 || index >= tabCount
26
+ ? [tabs[tabCount - 1], "after"]
27
+ : [tabs[index] ?? null, positionRelativeToTab];
28
+ }
29
+
30
+ export function insertIntoContainer(
31
+ container: ReactElement,
32
+ targetContainer: ReactElement,
33
+ newComponent: ReactElement
34
+ ): ReactElement {
35
+ const {
36
+ active: containerActive,
37
+ children: containerChildren = [],
38
+ path: containerPath,
39
+ } = getProps(container) as LayoutProps;
40
+
41
+ const existingComponentPath = getProp(targetContainer, "path");
42
+ const { idx, finalStep } = nextStep(
43
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
44
+ containerPath!,
45
+ existingComponentPath,
46
+ true
47
+ );
48
+ const [insertedIdx, children] = finalStep
49
+ ? insertIntoChildren(container, containerChildren, newComponent)
50
+ : [
51
+ containerActive,
52
+ containerChildren?.map((child, index) =>
53
+ index === idx
54
+ ? (insertIntoContainer(
55
+ child,
56
+ targetContainer,
57
+ newComponent
58
+ ) as ReactElement)
59
+ : child
60
+ ),
61
+ ];
62
+ const active =
63
+ typeOf(container) === "Stack"
64
+ ? Array.isArray(insertedIdx)
65
+ ? (insertedIdx[0] as number)
66
+ : insertedIdx
67
+ : containerActive;
68
+
69
+ return React.cloneElement(container, { active }, children);
70
+ }
71
+ function insertIntoChildren(
72
+ container: LayoutModel,
73
+ containerChildren: ReactElement[],
74
+ newComponent: ReactElement
75
+ ): [number, ReactElement[]] {
76
+ const containerPath = getProp(container, "path");
77
+ const count = containerChildren?.length;
78
+ const { id = uuid() } = getProps(newComponent);
79
+
80
+ if (count) {
81
+ return [
82
+ count,
83
+ containerChildren.concat(
84
+ resetPath(newComponent, `${containerPath}.${count}`, { id, key: id })
85
+ ),
86
+ ];
87
+ } else {
88
+ return [0, [resetPath(newComponent, `${containerPath}.0`, { id })]];
89
+ }
90
+ }
91
+
92
+ export function insertBesideChild(
93
+ container: ReactElement,
94
+ existingComponent: any,
95
+ newComponent: any,
96
+ insertionPosition: insertionPosition,
97
+ pos?: DropPos,
98
+ clientRect?: any,
99
+ dropRect?: any
100
+ ): ReactElement {
101
+ const {
102
+ active: containerActive,
103
+ children: containerChildren,
104
+ path: containerPath,
105
+ } = getProps(container);
106
+
107
+ const existingComponentPath = getProp(existingComponent, "path");
108
+ const { idx, finalStep } = nextStep(containerPath, existingComponentPath);
109
+ const [insertedIdx, children] = finalStep
110
+ ? updateChildren(
111
+ container,
112
+ containerChildren,
113
+ idx,
114
+ newComponent,
115
+ insertionPosition,
116
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
117
+ pos!,
118
+ clientRect,
119
+ dropRect
120
+ )
121
+ : [
122
+ containerActive,
123
+ containerChildren.map((child: ReactElement, index: number) =>
124
+ index === idx
125
+ ? insertBesideChild(
126
+ child,
127
+ existingComponent,
128
+ newComponent,
129
+ insertionPosition,
130
+ pos,
131
+ clientRect,
132
+ dropRect
133
+ )
134
+ : child
135
+ ),
136
+ ];
137
+
138
+ const active = typeOf(container) === "Stack" ? insertedIdx : containerActive;
139
+ return React.cloneElement(container, { active }, children);
140
+ }
141
+
142
+ function updateChildren(
143
+ container: LayoutModel,
144
+ containerChildren: ReactElement[],
145
+ idx: number,
146
+ newComponent: ReactElement,
147
+ insertionPosition: insertionPosition,
148
+ pos: DropPos,
149
+ clientRect: DropTarget["clientRect"],
150
+ dropRect: DropTarget["dropRect"]
151
+ ) {
152
+ const intrinsicSize = getIntrinsicSize(newComponent);
153
+ if (intrinsicSize?.width && intrinsicSize?.height) {
154
+ return insertIntrinsicSizedComponent(
155
+ container,
156
+ containerChildren,
157
+ idx,
158
+ newComponent,
159
+ insertionPosition,
160
+ clientRect,
161
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
162
+ dropRect!
163
+ );
164
+ } else {
165
+ return insertFlexComponent(
166
+ container,
167
+ containerChildren,
168
+ idx,
169
+ newComponent,
170
+ insertionPosition,
171
+ pos?.width || pos?.height,
172
+ clientRect
173
+ );
174
+ }
175
+ }
176
+
177
+ const getLeadingPlaceholderSize = (
178
+ flexDirection: flexDirection,
179
+ insertionPosition: insertionPosition,
180
+ { top, right, bottom, left }: DropTarget["clientRect"],
181
+ [rectLeft, rectTop, rectRight, rectBottom]: rectTuple
182
+ ) => {
183
+ if (flexDirection === "column" && insertionPosition === "before") {
184
+ return rectTop - top;
185
+ } else if (flexDirection === "column") {
186
+ return bottom - rectBottom;
187
+ } else if (flexDirection === "row" && insertionPosition === "before") {
188
+ return rectLeft - left;
189
+ } else if (flexDirection === "row") {
190
+ return right - rectRight;
191
+ }
192
+ };
193
+
194
+ function insertIntrinsicSizedComponent(
195
+ container: LayoutModel,
196
+ containerChildren: ReactElement[],
197
+ idx: number,
198
+ newComponent: ReactElement,
199
+ insertionPosition: insertionPosition,
200
+ clientRect: DropTarget["clientRect"],
201
+ dropRect: rectTuple
202
+ ) {
203
+ const {
204
+ style: { flexDirection },
205
+ } = getProps(container);
206
+ const [dimension, crossDimension, contraDirection] =
207
+ getFlexDimensions(flexDirection);
208
+ const { [crossDimension]: intrinsicCrossSize, [dimension]: intrinsicSize } =
209
+ getIntrinsicSize(newComponent) as { height: number; width: number };
210
+ const path = getProp(containerChildren[idx], "path");
211
+
212
+ const placeholderSize = getLeadingPlaceholderSize(
213
+ flexDirection,
214
+ insertionPosition,
215
+ clientRect,
216
+ dropRect
217
+ );
218
+
219
+ const [itemToInsert, size] =
220
+ intrinsicCrossSize < clientRect[crossDimension]
221
+ ? [
222
+ wrapIntrinsicSizeComponentWithFlexbox(
223
+ newComponent,
224
+ contraDirection,
225
+ path,
226
+ clientRect,
227
+ dropRect
228
+ ),
229
+ intrinsicSize,
230
+ ]
231
+ : [newComponent, undefined];
232
+
233
+ const placeholder = placeholderSize
234
+ ? createPlaceHolder(path, placeholderSize, { flexGrow: 0, flexShrink: 0 })
235
+ : undefined;
236
+
237
+ if (intrinsicCrossSize > clientRect[crossDimension]) {
238
+ containerChildren = containerChildren.map((child) => {
239
+ if (getProp(child, "placeholder")) {
240
+ return child;
241
+ } else {
242
+ const { [crossDimension]: intrinsicCrossChildSize } = getIntrinsicSize(
243
+ child
244
+ ) as {
245
+ height: number;
246
+ width: number;
247
+ };
248
+ if (
249
+ intrinsicCrossChildSize &&
250
+ intrinsicCrossChildSize < intrinsicCrossSize
251
+ ) {
252
+ return wrapIntrinsicSizeComponentWithFlexbox(
253
+ child,
254
+ contraDirection,
255
+ getProp(child, "path")
256
+ );
257
+ } else {
258
+ return child;
259
+ }
260
+ }
261
+ });
262
+ }
263
+
264
+ return insertFlexComponent(
265
+ container,
266
+ containerChildren,
267
+ idx,
268
+ itemToInsert,
269
+ insertionPosition,
270
+ size,
271
+ clientRect,
272
+ placeholder
273
+ );
274
+ }
275
+
276
+ function insertFlexComponent(
277
+ container: LayoutModel,
278
+ containerChildren: ReactElement[],
279
+ idx: number,
280
+ newComponent: ReactElement,
281
+ insertionPosition: "before" | "after",
282
+ size: number | undefined,
283
+ targetRect: DropTarget["clientRect"],
284
+ placeholder?: ReactElement
285
+ ) {
286
+ const containerPath = getProp(container, "path");
287
+ let insertedIdx = 0;
288
+ const children =
289
+ !containerChildren || containerChildren.length === 0
290
+ ? [newComponent]
291
+ : containerChildren
292
+ .reduce<ReactElement[]>((arr, child, i) => {
293
+ if (idx === i) {
294
+ const [existingComponent, insertedComponent] =
295
+ getStyledComponents(container, child, newComponent, targetRect);
296
+ if (insertionPosition === "before") {
297
+ if (placeholder) {
298
+ arr.push(placeholder, insertedComponent, existingComponent);
299
+ } else {
300
+ arr.push(insertedComponent, existingComponent);
301
+ }
302
+ } else {
303
+ if (placeholder) {
304
+ arr.push(existingComponent, insertedComponent, placeholder);
305
+ } else {
306
+ arr.push(existingComponent, insertedComponent);
307
+ }
308
+ }
309
+ insertedIdx = arr.indexOf(insertedComponent);
310
+ } else {
311
+ arr.push(child);
312
+ }
313
+ return arr;
314
+ }, [])
315
+ .map((child, i) =>
316
+ i < insertedIdx ? child : resetPath(child, `${containerPath}.${i}`)
317
+ );
318
+
319
+ return [insertedIdx, children];
320
+ }
321
+
322
+ function getStyledComponents(
323
+ container: LayoutModel,
324
+ existingComponent: ReactElement,
325
+ newComponent: ReactElement,
326
+ targetRect: DropTarget["clientRect"]
327
+ ): [ReactElement, ReactElement] {
328
+ const id = uuid();
329
+ let { version = 0 } = getProps(newComponent);
330
+ version += 1;
331
+ if (typeOf(container) === "Flexbox") {
332
+ const [dim] = getManagedDimension(container.props.style);
333
+ const splitterSize = 6;
334
+ const size = { [dim]: (targetRect[dim] - splitterSize) / 2 };
335
+ const existingComponentStyle = getFlexOrIntrinsicStyle(
336
+ existingComponent,
337
+ dim,
338
+ size
339
+ );
340
+ const newComponentStyle = getFlexOrIntrinsicStyle(newComponent, dim, size);
341
+
342
+ return [
343
+ React.cloneElement(existingComponent, {
344
+ style: existingComponentStyle,
345
+ }),
346
+ React.cloneElement(newComponent, {
347
+ id,
348
+ version,
349
+ style: newComponentStyle,
350
+ }),
351
+ ];
352
+ } else {
353
+ const {
354
+ style: { left: _1, top: _2, flex: _3, ...style } = {
355
+ left: undefined,
356
+ top: undefined,
357
+ flex: undefined,
358
+ },
359
+ } = getProps(newComponent);
360
+ return [
361
+ existingComponent,
362
+ React.cloneElement(newComponent, { id, version, style }),
363
+ ];
364
+ }
365
+ }