@vuu-ui/vuu-layout 0.5.10 → 0.5.11
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.
- package/LICENSE +201 -0
- package/cjs/index.js +20 -0
- package/cjs/index.js.map +7 -0
- package/esm/index.js +20 -0
- package/esm/index.js.map +7 -0
- package/index.css +2 -0
- package/index.css.map +7 -0
- package/package.json +13 -10
- package/src/Component.css +0 -0
- package/src/Component.tsx +0 -20
- package/src/DraggableLayout.css +0 -18
- package/src/DraggableLayout.tsx +0 -26
- package/src/__tests__/flexbox-utils.spec.js +0 -90
- package/src/chest-of-drawers/Chest.css +0 -36
- package/src/chest-of-drawers/Chest.tsx +0 -42
- package/src/chest-of-drawers/Drawer.css +0 -159
- package/src/chest-of-drawers/Drawer.tsx +0 -118
- package/src/chest-of-drawers/index.ts +0 -2
- package/src/common-types.ts +0 -9
- package/src/debug.ts +0 -16
- package/src/drag-drop/BoxModel.ts +0 -551
- package/src/drag-drop/DragState.ts +0 -219
- package/src/drag-drop/Draggable.ts +0 -282
- package/src/drag-drop/DropMenu.css +0 -71
- package/src/drag-drop/DropMenu.tsx +0 -61
- package/src/drag-drop/DropTarget.ts +0 -393
- package/src/drag-drop/DropTargetRenderer.css +0 -40
- package/src/drag-drop/DropTargetRenderer.tsx +0 -277
- package/src/drag-drop/dragDropTypes.ts +0 -47
- package/src/drag-drop/index.ts +0 -5
- package/src/editable-label/EditableLabel.css +0 -28
- package/src/editable-label/EditableLabel.tsx +0 -99
- package/src/editable-label/index.ts +0 -1
- package/src/flexbox/Flexbox.css +0 -45
- package/src/flexbox/Flexbox.tsx +0 -70
- package/src/flexbox/FlexboxLayout.tsx +0 -28
- package/src/flexbox/FluidGrid.css +0 -134
- package/src/flexbox/FluidGrid.tsx +0 -82
- package/src/flexbox/FluidGridLayout.tsx +0 -9
- package/src/flexbox/Splitter.css +0 -140
- package/src/flexbox/Splitter.tsx +0 -127
- package/src/flexbox/flexbox-utils.ts +0 -128
- package/src/flexbox/flexboxTypes.ts +0 -68
- package/src/flexbox/index.ts +0 -5
- package/src/flexbox/useResponsiveSizing.ts +0 -82
- package/src/flexbox/useSplitterResizing.ts +0 -270
- package/src/index.ts +0 -19
- package/src/layout-action.ts +0 -21
- package/src/layout-header/ActionButton.tsx +0 -23
- package/src/layout-header/Header.css +0 -8
- package/src/layout-header/Header.tsx +0 -216
- package/src/layout-header/index.ts +0 -1
- package/src/layout-provider/LayoutProvider.tsx +0 -161
- package/src/layout-provider/LayoutProviderContext.ts +0 -17
- package/src/layout-provider/index.ts +0 -3
- package/src/layout-provider/useLayoutDragDrop.ts +0 -210
- package/src/layout-reducer/flexUtils.ts +0 -276
- package/src/layout-reducer/index.ts +0 -5
- package/src/layout-reducer/insert-layout-element.ts +0 -365
- package/src/layout-reducer/layout-reducer.ts +0 -237
- package/src/layout-reducer/layoutTypes.ts +0 -159
- package/src/layout-reducer/layoutUtils.ts +0 -288
- package/src/layout-reducer/remove-layout-element.ts +0 -226
- package/src/layout-reducer/replace-layout-element.ts +0 -113
- package/src/layout-reducer/resize-flex-children.ts +0 -55
- package/src/layout-reducer/wrap-layout-element.ts +0 -307
- package/src/layout-view/View.css +0 -61
- package/src/layout-view/View.tsx +0 -143
- package/src/layout-view/ViewContext.ts +0 -30
- package/src/layout-view/index.ts +0 -5
- package/src/layout-view/useView.tsx +0 -104
- package/src/layout-view/useViewActionDispatcher.ts +0 -123
- package/src/layout-view/useViewResize.ts +0 -53
- package/src/layout-view/viewTypes.ts +0 -35
- package/src/palette/Palette.css +0 -33
- package/src/palette/Palette.tsx +0 -140
- package/src/palette/PaletteSalt.css +0 -9
- package/src/palette/PaletteSalt.tsx +0 -79
- package/src/palette/index.ts +0 -3
- package/src/placeholder/Placeholder.css +0 -10
- package/src/placeholder/Placeholder.tsx +0 -38
- package/src/placeholder/index.ts +0 -1
- package/src/registry/ComponentRegistry.ts +0 -44
- package/src/registry/index.ts +0 -1
- package/src/responsive/breakpoints.ts +0 -62
- package/src/responsive/index.ts +0 -3
- package/src/responsive/measureMinimumNodeSize.ts +0 -23
- package/src/responsive/overflowUtils.js +0 -14
- package/src/responsive/use-breakpoints.ts +0 -101
- package/src/responsive/useResizeObserver.ts +0 -154
- package/src/responsive/utils.ts +0 -37
- package/src/stack/Stack.css +0 -39
- package/src/stack/Stack.tsx +0 -173
- package/src/stack/StackLayout.tsx +0 -119
- package/src/stack/index.ts +0 -4
- package/src/stack/stackTypes.ts +0 -22
- package/src/tabs/TabPanel.css +0 -12
- package/src/tabs/TabPanel.tsx +0 -17
- package/src/tabs/index.ts +0 -1
- package/src/tools/config-wrapper/ConfigWrapper.tsx +0 -55
- package/src/tools/config-wrapper/index.ts +0 -1
- package/src/tools/devtools-box/layout-configurator.css +0 -112
- package/src/tools/devtools-box/layout-configurator.jsx +0 -369
- package/src/tools/devtools-tree/layout-tree-viewer.css +0 -15
- package/src/tools/devtools-tree/layout-tree-viewer.jsx +0 -36
- package/src/tools/index.ts +0 -4
- package/src/use-persistent-state.ts +0 -112
- package/src/utils/index.ts +0 -5
- package/src/utils/pathUtils.ts +0 -283
- package/src/utils/propUtils.ts +0 -26
- package/src/utils/refUtils.ts +0 -16
- package/src/utils/styleUtils.ts +0 -13
- package/src/utils/typeOf.ts +0 -25
- package/tsconfig-emit-types.json +0 -11
package/src/flexbox/Splitter.tsx
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import cx from 'classnames';
|
|
2
|
-
import React, { HTMLAttributes, KeyboardEvent, useCallback, useRef, useState } from 'react';
|
|
3
|
-
|
|
4
|
-
import './Splitter.css';
|
|
5
|
-
|
|
6
|
-
export type SplitterDragStartHandler = (index: number) => void;
|
|
7
|
-
export type SplitterDragHandler = (index: number, distance: number) => void;
|
|
8
|
-
export type SplitterDragEndHandler = () => void;
|
|
9
|
-
|
|
10
|
-
export interface SplitterProps
|
|
11
|
-
extends Omit<HTMLAttributes<HTMLDivElement>, 'onDrag' | 'onDragStart'> {
|
|
12
|
-
column: boolean;
|
|
13
|
-
index: number;
|
|
14
|
-
onDragStart: SplitterDragStartHandler;
|
|
15
|
-
onDrag: SplitterDragHandler;
|
|
16
|
-
onDragEnd: SplitterDragEndHandler;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const Splitter = React.memo(function Splitter({
|
|
20
|
-
column,
|
|
21
|
-
index,
|
|
22
|
-
onDrag,
|
|
23
|
-
onDragEnd,
|
|
24
|
-
onDragStart,
|
|
25
|
-
style
|
|
26
|
-
}: SplitterProps) {
|
|
27
|
-
const ignoreClick = useRef<boolean>();
|
|
28
|
-
const rootRef = useRef<HTMLDivElement>(null);
|
|
29
|
-
const lastPos = useRef<number>(0);
|
|
30
|
-
|
|
31
|
-
const [active, setActive] = useState(false);
|
|
32
|
-
|
|
33
|
-
const handleKeyDownDrag = useCallback(
|
|
34
|
-
({ key, shiftKey }) => {
|
|
35
|
-
const distance = shiftKey ? 10 : 1;
|
|
36
|
-
if (column && key === 'ArrowDown') {
|
|
37
|
-
onDrag(index, distance);
|
|
38
|
-
} else if (column && key === 'ArrowUp') {
|
|
39
|
-
onDrag(index, -distance);
|
|
40
|
-
} else if (!column && key === 'ArrowLeft') {
|
|
41
|
-
onDrag(index, -distance);
|
|
42
|
-
} else if (!column && key === 'ArrowRight') {
|
|
43
|
-
onDrag(index, distance);
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
[column, index, onDrag]
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const handleKeyDownInitDrag = useCallback(
|
|
50
|
-
(evt) => {
|
|
51
|
-
const { key } = evt;
|
|
52
|
-
const horizontalMove = key === 'ArrowLeft' || key === 'ArrowRIght';
|
|
53
|
-
const verticalMove = key === 'ArrowUp' || key === 'ArrowDown';
|
|
54
|
-
if ((column && verticalMove) || (!column && horizontalMove)) {
|
|
55
|
-
onDragStart(index);
|
|
56
|
-
handleKeyDownDrag(evt);
|
|
57
|
-
keyDownHandlerRef.current = handleKeyDownDrag;
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
[column, handleKeyDownDrag, index, onDragStart]
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
const keyDownHandlerRef = useRef(handleKeyDownInitDrag);
|
|
64
|
-
const handleKeyDown = (evt: KeyboardEvent) => keyDownHandlerRef.current(evt);
|
|
65
|
-
|
|
66
|
-
const handleMouseMove = useCallback(
|
|
67
|
-
(e) => {
|
|
68
|
-
ignoreClick.current = true;
|
|
69
|
-
const pos = e[column ? 'clientY' : 'clientX'];
|
|
70
|
-
const diff = pos - lastPos.current;
|
|
71
|
-
if (pos && pos !== lastPos.current) {
|
|
72
|
-
onDrag(index, diff);
|
|
73
|
-
}
|
|
74
|
-
lastPos.current = pos;
|
|
75
|
-
},
|
|
76
|
-
[column, index, onDrag]
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
const handleMouseUp = useCallback(() => {
|
|
80
|
-
window.removeEventListener('mousemove', handleMouseMove, false);
|
|
81
|
-
window.removeEventListener('mouseup', handleMouseUp, false);
|
|
82
|
-
onDragEnd();
|
|
83
|
-
setActive(false);
|
|
84
|
-
rootRef.current?.focus();
|
|
85
|
-
}, [handleMouseMove, onDragEnd, setActive]);
|
|
86
|
-
|
|
87
|
-
const handleMouseDown = useCallback(
|
|
88
|
-
(e) => {
|
|
89
|
-
lastPos.current = column ? e.clientY : e.clientX;
|
|
90
|
-
onDragStart(index);
|
|
91
|
-
window.addEventListener('mousemove', handleMouseMove, false);
|
|
92
|
-
window.addEventListener('mouseup', handleMouseUp, false);
|
|
93
|
-
e.preventDefault();
|
|
94
|
-
setActive(true);
|
|
95
|
-
},
|
|
96
|
-
[column, handleMouseMove, handleMouseUp, index, onDragStart, setActive]
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const handleClick = () => {
|
|
100
|
-
if (ignoreClick.current) {
|
|
101
|
-
ignoreClick.current = false;
|
|
102
|
-
} else {
|
|
103
|
-
rootRef.current?.focus();
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const handleBlur = () => {
|
|
108
|
-
keyDownHandlerRef.current = handleKeyDownInitDrag;
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const className = cx('Splitter', 'focusable', { active, column });
|
|
112
|
-
return (
|
|
113
|
-
<div
|
|
114
|
-
className={className}
|
|
115
|
-
data-splitter
|
|
116
|
-
ref={rootRef}
|
|
117
|
-
role="separator"
|
|
118
|
-
style={style}
|
|
119
|
-
onBlur={handleBlur}
|
|
120
|
-
onClick={handleClick}
|
|
121
|
-
onKeyDown={handleKeyDown}
|
|
122
|
-
onMouseDown={handleMouseDown}
|
|
123
|
-
tabIndex={0}>
|
|
124
|
-
<div className="grab-zone" />
|
|
125
|
-
</div>
|
|
126
|
-
);
|
|
127
|
-
});
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { ReactElement } from 'react';
|
|
2
|
-
import { getIntrinsicSize, hasUnboundedFlexStyle } from '../layout-reducer/flexUtils';
|
|
3
|
-
import { getProp } from '../utils';
|
|
4
|
-
import type { BreakPoint, ContentMeta } from './flexboxTypes';
|
|
5
|
-
|
|
6
|
-
const NO_INTRINSIC_SIZE: {
|
|
7
|
-
height?: number;
|
|
8
|
-
width?: number;
|
|
9
|
-
} = {};
|
|
10
|
-
|
|
11
|
-
export const SPLITTER = 1;
|
|
12
|
-
export const PLACEHOLDER = 2;
|
|
13
|
-
|
|
14
|
-
const isIntrinsicallySized = (item: ContentMeta) => typeof item.intrinsicSize === 'number';
|
|
15
|
-
|
|
16
|
-
const getBreakPointValues = (breakPoints: BreakPoint[], component: ReactElement) => {
|
|
17
|
-
const values: { [key: string]: number | undefined } = {};
|
|
18
|
-
breakPoints.forEach((breakPoint) => {
|
|
19
|
-
values[breakPoint] = getProp(component, breakPoint);
|
|
20
|
-
});
|
|
21
|
-
return values;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const gatherChildMeta = (
|
|
25
|
-
children: ReactElement[],
|
|
26
|
-
dimension: 'width' | 'height',
|
|
27
|
-
breakPoints?: BreakPoint[]
|
|
28
|
-
) => {
|
|
29
|
-
return children.map((child, index) => {
|
|
30
|
-
const resizeable = getProp(child, 'resizeable');
|
|
31
|
-
const { [dimension]: intrinsicSize } = getIntrinsicSize(child) ?? NO_INTRINSIC_SIZE;
|
|
32
|
-
const flexOpen = hasUnboundedFlexStyle(child);
|
|
33
|
-
if (breakPoints) {
|
|
34
|
-
return {
|
|
35
|
-
index,
|
|
36
|
-
flexOpen,
|
|
37
|
-
intrinsicSize,
|
|
38
|
-
resizeable,
|
|
39
|
-
...getBreakPointValues(breakPoints, child)
|
|
40
|
-
};
|
|
41
|
-
} else {
|
|
42
|
-
return { index, flexOpen, intrinsicSize, resizeable };
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// Splitters are inserted AFTER the associated index, so
|
|
48
|
-
// never a splitter in last position.
|
|
49
|
-
// Placeholder goes before (first) OR after(last) index
|
|
50
|
-
export const findSplitterAndPlaceholderPositions = (childMeta: ContentMeta[]) => {
|
|
51
|
-
const count = childMeta.length;
|
|
52
|
-
const allIntrinsic = childMeta.every(isIntrinsicallySized);
|
|
53
|
-
const splitterPositions = Array(count).fill(0);
|
|
54
|
-
if (allIntrinsic) {
|
|
55
|
-
splitterPositions[0] = PLACEHOLDER;
|
|
56
|
-
splitterPositions[count - 1] = PLACEHOLDER;
|
|
57
|
-
}
|
|
58
|
-
if (count < 2) {
|
|
59
|
-
return splitterPositions;
|
|
60
|
-
} else {
|
|
61
|
-
// 1) From the left, check each item.
|
|
62
|
-
// Once we hit a resizable item, set this index and all subsequent indices,
|
|
63
|
-
// except for last, to SPLITTER
|
|
64
|
-
for (let i = 0, resizeablesLeft = 0; i < count - 1; i++) {
|
|
65
|
-
if (childMeta[i].resizeable && !resizeablesLeft) {
|
|
66
|
-
resizeablesLeft = SPLITTER;
|
|
67
|
-
}
|
|
68
|
-
splitterPositions[i] += resizeablesLeft;
|
|
69
|
-
}
|
|
70
|
-
// 2) Now check from the right. Undo splitter insertion until we reach a point
|
|
71
|
-
// where there is a resizeable to our right.
|
|
72
|
-
for (let i = count - 1; i > 0; i--) {
|
|
73
|
-
if (splitterPositions[i] & SPLITTER) {
|
|
74
|
-
splitterPositions[i] -= SPLITTER;
|
|
75
|
-
}
|
|
76
|
-
if (childMeta[i].resizeable) {
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return splitterPositions;
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const identifyResizeParties = (contentMeta: ContentMeta[], idx: number) => {
|
|
85
|
-
const idx1 = getLeadingResizeablePos(contentMeta, idx);
|
|
86
|
-
const idx2 = getTrailingResizeablePos(contentMeta, idx);
|
|
87
|
-
const participants = idx1 !== -1 && idx2 !== -1 ? [idx1, idx2] : undefined;
|
|
88
|
-
const bystanders = identifyResizeBystanders(contentMeta, participants);
|
|
89
|
-
return [participants, bystanders];
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
function identifyResizeBystanders(contentMeta: ContentMeta[], participants?: number[]) {
|
|
93
|
-
if (participants) {
|
|
94
|
-
const bystanders = [];
|
|
95
|
-
for (let i = 0; i < contentMeta.length; i++) {
|
|
96
|
-
if (contentMeta[i].flexOpen && !participants.includes(i)) {
|
|
97
|
-
bystanders.push(i);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return bystanders;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function getLeadingResizeablePos(contentMeta: ContentMeta[], idx: number) {
|
|
105
|
-
let pos = idx,
|
|
106
|
-
resizeable = false;
|
|
107
|
-
while (pos >= 1 && !resizeable) {
|
|
108
|
-
pos = pos - 1;
|
|
109
|
-
resizeable = isResizeable(contentMeta, pos);
|
|
110
|
-
}
|
|
111
|
-
return pos;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function getTrailingResizeablePos(contentMeta: ContentMeta[], idx: number) {
|
|
115
|
-
let pos = idx,
|
|
116
|
-
resizeable = false;
|
|
117
|
-
const count = contentMeta.length;
|
|
118
|
-
while (pos < count && !resizeable) {
|
|
119
|
-
pos = pos + 1;
|
|
120
|
-
resizeable = isResizeable(contentMeta, pos);
|
|
121
|
-
}
|
|
122
|
-
return pos === count ? -1 : pos;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function isResizeable(contentMeta: ContentMeta[], idx: number): boolean {
|
|
126
|
-
const { placeholder, splitter, resizeable, intrinsicSize } = contentMeta[idx];
|
|
127
|
-
return Boolean(!splitter && !intrinsicSize && (placeholder || resizeable));
|
|
128
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CSSProperties,
|
|
3
|
-
HTMLAttributes,
|
|
4
|
-
MutableRefObject,
|
|
5
|
-
ReactElement,
|
|
6
|
-
ReactNode,
|
|
7
|
-
} from "react";
|
|
8
|
-
import { SplitterProps } from "./Splitter";
|
|
9
|
-
|
|
10
|
-
export interface LayoutContainerProps {
|
|
11
|
-
resizeable?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface FlexboxProps
|
|
15
|
-
extends LayoutContainerProps,
|
|
16
|
-
HTMLAttributes<HTMLDivElement> {
|
|
17
|
-
breakPoints?: BreakPointsProp;
|
|
18
|
-
children: ReactElement[];
|
|
19
|
-
cols?: number;
|
|
20
|
-
column?: true;
|
|
21
|
-
fullPage?: number;
|
|
22
|
-
flexFill?: boolean;
|
|
23
|
-
gap?: number;
|
|
24
|
-
onSplitterMoved?: (content: ContentMeta[]) => void;
|
|
25
|
-
row?: true;
|
|
26
|
-
spacing?: number;
|
|
27
|
-
splitterSize?: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface FlexboxLayoutProps extends FlexboxProps {
|
|
31
|
-
path: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface SplitterHookProps {
|
|
35
|
-
children: ReactNode;
|
|
36
|
-
onSplitterMoved?: (content: ContentMeta[]) => void;
|
|
37
|
-
style?: CSSProperties;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface SplitterHookResult {
|
|
41
|
-
content: ReactElement[];
|
|
42
|
-
rootRef: MutableRefObject<HTMLDivElement | null>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export type SplitterFactory = (index: number) => ReactElement<SplitterProps>;
|
|
46
|
-
|
|
47
|
-
export type ContentMeta = {
|
|
48
|
-
currentSize?: number;
|
|
49
|
-
flexOpen?: boolean;
|
|
50
|
-
flexBasis?: number;
|
|
51
|
-
intrinsicSize?: number;
|
|
52
|
-
minSize?: number;
|
|
53
|
-
placeholder?: boolean;
|
|
54
|
-
resizeable?: boolean;
|
|
55
|
-
shim?: boolean;
|
|
56
|
-
splitter?: boolean;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export type FlexSize = {
|
|
60
|
-
size: number;
|
|
61
|
-
minSize: number;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export type BreakPoint = "xs" | "sm" | "md" | "lg" | "xl";
|
|
65
|
-
export type BreakPoints = BreakPoint[];
|
|
66
|
-
export type BreakPointsProp = {
|
|
67
|
-
[keys in BreakPoint]?: number;
|
|
68
|
-
};
|
package/src/flexbox/index.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { getUniqueId } from "@vuu-ui/vuu-utils";
|
|
2
|
-
import {
|
|
3
|
-
cloneElement,
|
|
4
|
-
CSSProperties,
|
|
5
|
-
isValidElement,
|
|
6
|
-
ReactElement,
|
|
7
|
-
useCallback,
|
|
8
|
-
useMemo,
|
|
9
|
-
useRef,
|
|
10
|
-
} from "react";
|
|
11
|
-
import { gatherChildMeta } from "./flexbox-utils";
|
|
12
|
-
import { BreakPoint } from "./flexboxTypes";
|
|
13
|
-
|
|
14
|
-
const breakPoints: BreakPoint[] = ["xs", "sm", "md", "lg", "xl"];
|
|
15
|
-
|
|
16
|
-
const DEFAULT_COLS = 12;
|
|
17
|
-
|
|
18
|
-
export const useResponsiveSizing = ({
|
|
19
|
-
children: childrenProp,
|
|
20
|
-
cols: colsProp,
|
|
21
|
-
style,
|
|
22
|
-
}: {
|
|
23
|
-
children: ReactElement[];
|
|
24
|
-
cols?: number;
|
|
25
|
-
style?: CSSProperties;
|
|
26
|
-
}) => {
|
|
27
|
-
const rootRef = useRef(null);
|
|
28
|
-
const metaRef = useRef(null);
|
|
29
|
-
const contentRef = useRef<ReactElement[]>();
|
|
30
|
-
const cols = colsProp ?? DEFAULT_COLS;
|
|
31
|
-
|
|
32
|
-
const isColumn = style?.flexDirection === "column";
|
|
33
|
-
const dimension = isColumn ? "height" : "width";
|
|
34
|
-
|
|
35
|
-
const children = useMemo(
|
|
36
|
-
() =>
|
|
37
|
-
Array.isArray(childrenProp)
|
|
38
|
-
? childrenProp
|
|
39
|
-
: isValidElement(childrenProp)
|
|
40
|
-
? [childrenProp]
|
|
41
|
-
: [],
|
|
42
|
-
[childrenProp]
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
const buildContent = useCallback(
|
|
46
|
-
(children, dimension): [ReactElement[], any] => {
|
|
47
|
-
const childMeta = gatherChildMeta(children, dimension, breakPoints);
|
|
48
|
-
const content = [];
|
|
49
|
-
const meta = [];
|
|
50
|
-
for (let i = 0; i < children.length; i++) {
|
|
51
|
-
const child = children[i];
|
|
52
|
-
const {
|
|
53
|
-
style: { flex, ...rest },
|
|
54
|
-
} = child.props;
|
|
55
|
-
content.push(
|
|
56
|
-
cloneElement(child, {
|
|
57
|
-
key: getUniqueId(),
|
|
58
|
-
style: {
|
|
59
|
-
...rest,
|
|
60
|
-
"--parent-col-count": cols,
|
|
61
|
-
},
|
|
62
|
-
})
|
|
63
|
-
);
|
|
64
|
-
meta.push(childMeta[i]);
|
|
65
|
-
}
|
|
66
|
-
return [content, meta];
|
|
67
|
-
},
|
|
68
|
-
[cols]
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
useMemo(() => {
|
|
72
|
-
const [content, meta] = buildContent(children, dimension);
|
|
73
|
-
metaRef.current = meta;
|
|
74
|
-
contentRef.current = content;
|
|
75
|
-
}, [buildContent, children, dimension]);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
cols,
|
|
79
|
-
content: contentRef.current,
|
|
80
|
-
rootRef,
|
|
81
|
-
};
|
|
82
|
-
};
|
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import { getUniqueId } from "@vuu-ui/vuu-utils";
|
|
2
|
-
import React, {
|
|
3
|
-
ReactElement,
|
|
4
|
-
useCallback,
|
|
5
|
-
useMemo,
|
|
6
|
-
useRef,
|
|
7
|
-
useState,
|
|
8
|
-
} from "react";
|
|
9
|
-
import { Placeholder } from "../placeholder";
|
|
10
|
-
import { Splitter } from "./Splitter";
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
findSplitterAndPlaceholderPositions,
|
|
14
|
-
gatherChildMeta,
|
|
15
|
-
identifyResizeParties,
|
|
16
|
-
PLACEHOLDER,
|
|
17
|
-
SPLITTER,
|
|
18
|
-
} from "./flexbox-utils";
|
|
19
|
-
import {
|
|
20
|
-
ContentMeta,
|
|
21
|
-
FlexSize,
|
|
22
|
-
SplitterFactory,
|
|
23
|
-
SplitterHookProps,
|
|
24
|
-
SplitterHookResult,
|
|
25
|
-
} from "./flexboxTypes";
|
|
26
|
-
|
|
27
|
-
const originalContentOnly = (meta: ContentMeta) =>
|
|
28
|
-
!meta.splitter && !meta.placeholder;
|
|
29
|
-
|
|
30
|
-
export const useSplitterResizing = ({
|
|
31
|
-
children: childrenProp,
|
|
32
|
-
onSplitterMoved,
|
|
33
|
-
style,
|
|
34
|
-
}: SplitterHookProps): SplitterHookResult => {
|
|
35
|
-
const rootRef = useRef<HTMLDivElement>(null);
|
|
36
|
-
const metaRef = useRef<ContentMeta[]>();
|
|
37
|
-
const contentRef = useRef<ReactElement[]>();
|
|
38
|
-
const assignedKeys = useRef([]);
|
|
39
|
-
const [, forceUpdate] = useState({});
|
|
40
|
-
|
|
41
|
-
const setContent = (content: ReactElement[]) => {
|
|
42
|
-
contentRef.current = content;
|
|
43
|
-
forceUpdate({});
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const isColumn = style?.flexDirection === "column";
|
|
47
|
-
const dimension = isColumn ? "height" : "width";
|
|
48
|
-
const children = useMemo(
|
|
49
|
-
() =>
|
|
50
|
-
Array.isArray(childrenProp)
|
|
51
|
-
? childrenProp
|
|
52
|
-
: React.isValidElement(childrenProp)
|
|
53
|
-
? [childrenProp]
|
|
54
|
-
: [],
|
|
55
|
-
[childrenProp]
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const handleDragStart = useCallback(
|
|
59
|
-
(index) => {
|
|
60
|
-
const { current: contentMeta } = metaRef;
|
|
61
|
-
if (contentMeta) {
|
|
62
|
-
const [participants, bystanders] = identifyResizeParties(
|
|
63
|
-
contentMeta,
|
|
64
|
-
index
|
|
65
|
-
);
|
|
66
|
-
if (participants) {
|
|
67
|
-
participants.forEach((index) => {
|
|
68
|
-
const el = rootRef.current?.childNodes[index] as HTMLElement;
|
|
69
|
-
if (el) {
|
|
70
|
-
const { size, minSize } = measureElement(el, dimension);
|
|
71
|
-
contentMeta[index].currentSize = size;
|
|
72
|
-
contentMeta[index].minSize = minSize;
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
if (bystanders) {
|
|
76
|
-
bystanders.forEach((index) => {
|
|
77
|
-
const el = rootRef.current?.childNodes[index] as HTMLElement;
|
|
78
|
-
if (el) {
|
|
79
|
-
const { [dimension]: size } = el.getBoundingClientRect();
|
|
80
|
-
contentMeta[index].flexBasis = size;
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
[dimension]
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
const handleDrag = useCallback(
|
|
91
|
-
(idx, distance) => {
|
|
92
|
-
if (contentRef.current && metaRef.current) {
|
|
93
|
-
setContent(
|
|
94
|
-
resizeContent(
|
|
95
|
-
contentRef.current,
|
|
96
|
-
metaRef.current,
|
|
97
|
-
distance,
|
|
98
|
-
dimension
|
|
99
|
-
)
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
[dimension]
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
const handleDragEnd = useCallback(() => {
|
|
107
|
-
const contentMeta = metaRef.current;
|
|
108
|
-
if (contentMeta) {
|
|
109
|
-
onSplitterMoved?.(contentMeta.filter(originalContentOnly));
|
|
110
|
-
}
|
|
111
|
-
contentMeta?.forEach((meta) => {
|
|
112
|
-
meta.currentSize = undefined;
|
|
113
|
-
meta.flexBasis = undefined;
|
|
114
|
-
meta.flexOpen = false;
|
|
115
|
-
});
|
|
116
|
-
}, [onSplitterMoved]);
|
|
117
|
-
|
|
118
|
-
const createSplitter: SplitterFactory = useCallback(
|
|
119
|
-
(i) => {
|
|
120
|
-
return React.createElement(Splitter, {
|
|
121
|
-
column: isColumn,
|
|
122
|
-
index: i,
|
|
123
|
-
key: `splitter-${i}`,
|
|
124
|
-
onDrag: handleDrag,
|
|
125
|
-
onDragEnd: handleDragEnd,
|
|
126
|
-
onDragStart: handleDragStart,
|
|
127
|
-
});
|
|
128
|
-
},
|
|
129
|
-
[handleDrag, handleDragEnd, handleDragStart, isColumn]
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
useMemo(() => {
|
|
133
|
-
const [content, meta] = buildContent(
|
|
134
|
-
children,
|
|
135
|
-
dimension,
|
|
136
|
-
createSplitter,
|
|
137
|
-
assignedKeys.current
|
|
138
|
-
);
|
|
139
|
-
metaRef.current = meta;
|
|
140
|
-
contentRef.current = content;
|
|
141
|
-
}, [children, createSplitter, dimension]);
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
content: contentRef.current || [],
|
|
145
|
-
rootRef,
|
|
146
|
-
};
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
function buildContent(
|
|
150
|
-
children: ReactElement[],
|
|
151
|
-
dimension: "width" | "height",
|
|
152
|
-
createSplitter: SplitterFactory,
|
|
153
|
-
keys: any[]
|
|
154
|
-
): [any[], ContentMeta[]] {
|
|
155
|
-
const childMeta = gatherChildMeta(children, dimension);
|
|
156
|
-
const splitterAndPlaceholderPositions =
|
|
157
|
-
findSplitterAndPlaceholderPositions(childMeta);
|
|
158
|
-
const content = [];
|
|
159
|
-
const meta: ContentMeta[] = [];
|
|
160
|
-
for (let i = 0; i < children.length; i++) {
|
|
161
|
-
const child = children[i];
|
|
162
|
-
if (i === 0 && splitterAndPlaceholderPositions[i] & PLACEHOLDER) {
|
|
163
|
-
content.push(createPlaceholder(i));
|
|
164
|
-
meta.push({ placeholder: true, shim: true });
|
|
165
|
-
}
|
|
166
|
-
if (child.key == null) {
|
|
167
|
-
const key = keys[i] || (keys[i] = getUniqueId());
|
|
168
|
-
content.push(React.cloneElement(child, { key }));
|
|
169
|
-
} else {
|
|
170
|
-
content.push(child);
|
|
171
|
-
}
|
|
172
|
-
meta.push(childMeta[i]);
|
|
173
|
-
|
|
174
|
-
if (i > 0 && splitterAndPlaceholderPositions[i] & PLACEHOLDER) {
|
|
175
|
-
content.push(createPlaceholder(i));
|
|
176
|
-
meta.push({ placeholder: true });
|
|
177
|
-
} else if (splitterAndPlaceholderPositions[i] & SPLITTER) {
|
|
178
|
-
content.push(createSplitter(content.length));
|
|
179
|
-
meta.push({ splitter: true });
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return [content, meta];
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function resizeContent(
|
|
186
|
-
content: ReactElement[],
|
|
187
|
-
contentMeta: ContentMeta[],
|
|
188
|
-
distance: number,
|
|
189
|
-
dimension: "width" | "height"
|
|
190
|
-
) {
|
|
191
|
-
const metaUpdated = updateMeta(contentMeta, distance);
|
|
192
|
-
if (!metaUpdated) {
|
|
193
|
-
return content;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return content.map((child, idx) => {
|
|
197
|
-
const meta = contentMeta[idx];
|
|
198
|
-
const { currentSize, flexOpen, flexBasis } = meta;
|
|
199
|
-
const hasCurrentSize = currentSize !== undefined;
|
|
200
|
-
if (hasCurrentSize || flexOpen) {
|
|
201
|
-
const { flexBasis: actualFlexBasis } = child.props.style || {};
|
|
202
|
-
const size = hasCurrentSize ? meta.currentSize : flexBasis;
|
|
203
|
-
if (size !== actualFlexBasis) {
|
|
204
|
-
return React.cloneElement(child, {
|
|
205
|
-
style: {
|
|
206
|
-
...child.props.style,
|
|
207
|
-
flexBasis: size,
|
|
208
|
-
[dimension]: "auto",
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
} else {
|
|
212
|
-
return child;
|
|
213
|
-
}
|
|
214
|
-
} else {
|
|
215
|
-
return child;
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
//TODO detect cursor move beyond drag limit and suspend further resize until cursoe re-engages with splitter
|
|
221
|
-
function updateMeta(contentMeta: ContentMeta[], distance: number) {
|
|
222
|
-
const resizeTargets: number[] = [];
|
|
223
|
-
|
|
224
|
-
contentMeta.forEach((meta, idx) => {
|
|
225
|
-
if (meta.currentSize !== undefined) {
|
|
226
|
-
resizeTargets.push(idx);
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// we want the target being reduced first, this may limit the distance we can apply
|
|
231
|
-
const target1 = distance < 0 ? resizeTargets[0] : resizeTargets[1];
|
|
232
|
-
|
|
233
|
-
const { currentSize = 0, minSize = 0 } = contentMeta[target1];
|
|
234
|
-
if (currentSize === minSize) {
|
|
235
|
-
// size is already 0, we cannot go further
|
|
236
|
-
return false;
|
|
237
|
-
} else if (Math.abs(distance) > currentSize - minSize) {
|
|
238
|
-
// reduce to 0
|
|
239
|
-
const multiplier = distance < 0 ? -1 : 1;
|
|
240
|
-
distance = Math.max(0, currentSize - minSize) * multiplier;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const leadingItem = contentMeta[resizeTargets[0]] as ContentMeta;
|
|
244
|
-
const { currentSize: leadingSize = 0 } = leadingItem;
|
|
245
|
-
leadingItem.currentSize = leadingSize + distance;
|
|
246
|
-
|
|
247
|
-
const trailingItem = contentMeta[resizeTargets[1]] as ContentMeta;
|
|
248
|
-
const { currentSize: trailingSize = 0 } = trailingItem;
|
|
249
|
-
trailingItem.currentSize = trailingSize - distance;
|
|
250
|
-
|
|
251
|
-
return true;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function createPlaceholder(index: number) {
|
|
255
|
-
return React.createElement(Placeholder, {
|
|
256
|
-
shim: index === 0,
|
|
257
|
-
key: `placeholder-${index}`,
|
|
258
|
-
} as any);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function measureElement(
|
|
262
|
-
el: HTMLElement,
|
|
263
|
-
dimension: "width" | "height"
|
|
264
|
-
): FlexSize {
|
|
265
|
-
const { [dimension]: size } = el.getBoundingClientRect();
|
|
266
|
-
const style = getComputedStyle(el);
|
|
267
|
-
const minSizeVal = style.getPropertyValue(`min-${dimension}`);
|
|
268
|
-
const minSize = minSizeVal.endsWith("px") ? parseInt(minSizeVal, 10) : 0;
|
|
269
|
-
return { size, minSize };
|
|
270
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export * from "@vuu-ui/vuu-popups/src/dialog";
|
|
2
|
-
export * from "./chest-of-drawers";
|
|
3
|
-
export * from "./common-types";
|
|
4
|
-
export { default as Component } from "./Component";
|
|
5
|
-
export * from "./drag-drop";
|
|
6
|
-
export * from "./DraggableLayout";
|
|
7
|
-
export * from "./flexbox";
|
|
8
|
-
export { Action } from "./layout-action";
|
|
9
|
-
export * from "./layout-header";
|
|
10
|
-
export * from "./layout-provider";
|
|
11
|
-
export * from "./layout-view";
|
|
12
|
-
export * from "./palette";
|
|
13
|
-
export * from "./placeholder";
|
|
14
|
-
export * from "./registry";
|
|
15
|
-
export * from "./responsive";
|
|
16
|
-
export * from "./stack";
|
|
17
|
-
export * from "./tools";
|
|
18
|
-
export * from "./use-persistent-state";
|
|
19
|
-
export * from "./utils";
|