@vuu-ui/vuu-layout 0.5.13 → 0.5.15
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/package.json +10 -13
- package/src/Component.css +0 -0
- package/src/Component.tsx +20 -0
- package/src/DraggableLayout.css +18 -0
- package/src/DraggableLayout.tsx +26 -0
- package/src/__tests__/flexbox-utils.spec.js +90 -0
- package/src/chest-of-drawers/Chest.css +36 -0
- package/src/chest-of-drawers/Chest.tsx +42 -0
- package/src/chest-of-drawers/Drawer.css +159 -0
- package/src/chest-of-drawers/Drawer.tsx +118 -0
- package/src/chest-of-drawers/index.ts +2 -0
- package/src/common-types.ts +9 -0
- package/src/debug.ts +16 -0
- package/src/drag-drop/BoxModel.ts +551 -0
- package/src/drag-drop/DragState.ts +219 -0
- package/src/drag-drop/Draggable.ts +282 -0
- package/src/drag-drop/DropMenu.css +71 -0
- package/src/drag-drop/DropMenu.tsx +61 -0
- package/src/drag-drop/DropTarget.ts +393 -0
- package/src/drag-drop/DropTargetRenderer.css +40 -0
- package/src/drag-drop/DropTargetRenderer.tsx +277 -0
- package/src/drag-drop/dragDropTypes.ts +47 -0
- package/src/drag-drop/index.ts +5 -0
- package/src/editable-label/EditableLabel.css +28 -0
- package/src/editable-label/EditableLabel.tsx +99 -0
- package/src/editable-label/index.ts +1 -0
- package/src/flexbox/Flexbox.css +45 -0
- package/src/flexbox/Flexbox.tsx +70 -0
- package/src/flexbox/FlexboxLayout.tsx +28 -0
- package/src/flexbox/FluidGrid.css +134 -0
- package/src/flexbox/FluidGrid.tsx +82 -0
- package/src/flexbox/FluidGridLayout.tsx +9 -0
- package/src/flexbox/Splitter.css +140 -0
- package/src/flexbox/Splitter.tsx +127 -0
- package/src/flexbox/flexbox-utils.ts +128 -0
- package/src/flexbox/flexboxTypes.ts +68 -0
- package/src/flexbox/index.ts +5 -0
- package/src/flexbox/useResponsiveSizing.ts +82 -0
- package/src/flexbox/useSplitterResizing.ts +270 -0
- package/src/index.ts +19 -0
- package/src/layout-action.ts +21 -0
- package/src/layout-header/ActionButton.tsx +23 -0
- package/src/layout-header/Header.css +8 -0
- package/src/layout-header/Header.tsx +216 -0
- package/src/layout-header/index.ts +1 -0
- package/src/layout-provider/LayoutProvider.tsx +161 -0
- package/src/layout-provider/LayoutProviderContext.ts +17 -0
- package/src/layout-provider/index.ts +3 -0
- package/src/layout-provider/useLayoutDragDrop.ts +210 -0
- package/src/layout-reducer/flexUtils.ts +276 -0
- package/src/layout-reducer/index.ts +5 -0
- package/src/layout-reducer/insert-layout-element.ts +365 -0
- package/src/layout-reducer/layout-reducer.ts +237 -0
- package/src/layout-reducer/layoutTypes.ts +159 -0
- package/src/layout-reducer/layoutUtils.ts +288 -0
- package/src/layout-reducer/remove-layout-element.ts +226 -0
- package/src/layout-reducer/replace-layout-element.ts +113 -0
- package/src/layout-reducer/resize-flex-children.ts +55 -0
- package/src/layout-reducer/wrap-layout-element.ts +307 -0
- package/src/layout-view/View.css +61 -0
- package/src/layout-view/View.tsx +143 -0
- package/src/layout-view/ViewContext.ts +30 -0
- package/src/layout-view/index.ts +5 -0
- package/src/layout-view/useView.tsx +104 -0
- package/src/layout-view/useViewActionDispatcher.ts +123 -0
- package/src/layout-view/useViewResize.ts +53 -0
- package/src/layout-view/viewTypes.ts +35 -0
- package/src/palette/Palette.css +33 -0
- package/src/palette/Palette.tsx +140 -0
- package/src/palette/PaletteSalt.css +9 -0
- package/src/palette/PaletteSalt.tsx +79 -0
- package/src/palette/index.ts +3 -0
- package/src/placeholder/Placeholder.css +10 -0
- package/src/placeholder/Placeholder.tsx +38 -0
- package/src/placeholder/index.ts +1 -0
- package/src/registry/ComponentRegistry.ts +44 -0
- package/src/registry/index.ts +1 -0
- package/src/responsive/breakpoints.ts +62 -0
- package/src/responsive/index.ts +3 -0
- package/src/responsive/measureMinimumNodeSize.ts +23 -0
- package/src/responsive/overflowUtils.js +14 -0
- package/src/responsive/use-breakpoints.ts +101 -0
- package/src/responsive/useResizeObserver.ts +154 -0
- package/src/responsive/utils.ts +37 -0
- package/src/stack/Stack.css +39 -0
- package/src/stack/Stack.tsx +173 -0
- package/src/stack/StackLayout.tsx +119 -0
- package/src/stack/index.ts +4 -0
- package/src/stack/stackTypes.ts +22 -0
- package/src/tabs/TabPanel.css +12 -0
- package/src/tabs/TabPanel.tsx +17 -0
- package/src/tabs/index.ts +1 -0
- package/src/tools/config-wrapper/ConfigWrapper.tsx +55 -0
- package/src/tools/config-wrapper/index.ts +1 -0
- package/src/tools/devtools-box/layout-configurator.css +112 -0
- package/src/tools/devtools-box/layout-configurator.jsx +369 -0
- package/src/tools/devtools-tree/layout-tree-viewer.css +15 -0
- package/src/tools/devtools-tree/layout-tree-viewer.jsx +36 -0
- package/src/tools/index.ts +4 -0
- package/src/use-persistent-state.ts +112 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/pathUtils.ts +283 -0
- package/src/utils/propUtils.ts +26 -0
- package/src/utils/refUtils.ts +16 -0
- package/src/utils/styleUtils.ts +13 -0
- package/src/utils/typeOf.ts +25 -0
- package/tsconfig-emit-types.json +11 -0
- package/LICENSE +0 -201
- package/cjs/index.js +0 -20
- package/cjs/index.js.map +0 -7
- package/esm/index.js +0 -20
- package/esm/index.js.map +0 -7
- package/index.css +0 -2
- package/index.css.map +0 -7
package/package.json
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vuu-ui/vuu-layout",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.15",
|
|
4
4
|
"description": "VUU Layout Components",
|
|
5
|
+
"main": "src/index.ts",
|
|
5
6
|
"author": "heswell",
|
|
6
7
|
"license": "Apache-2.0",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "node ../../scripts/run-build.mjs",
|
|
10
|
+
"type-defs": "node ../../scripts/build-type-defs.mjs"
|
|
11
|
+
},
|
|
12
|
+
"types": "src/index.ts",
|
|
7
13
|
"peerDependencies": {
|
|
8
14
|
"@salt-ds/core": "1.0.0",
|
|
9
15
|
"@salt-ds/icons": "1.0.0",
|
|
10
16
|
"@heswell/salt-lab": "1.0.0-alpha.0",
|
|
11
|
-
"@vuu-ui/vuu-utils": "0.5.
|
|
17
|
+
"@vuu-ui/vuu-utils": "0.5.15",
|
|
12
18
|
"classnames": "^2.2.6",
|
|
13
19
|
"react": "^17.0.2",
|
|
14
20
|
"react-dom": "^17.0.2"
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
"cjs",
|
|
18
|
-
"esm",
|
|
19
|
-
"index.css",
|
|
20
|
-
"index.css.map",
|
|
21
|
-
"README.md"
|
|
22
|
-
],
|
|
23
|
-
"module": "esm/index.js",
|
|
24
|
-
"main": "cjs/index.js"
|
|
25
|
-
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React, { forwardRef, HTMLAttributes } from 'react';
|
|
2
|
+
import { registerComponent } from './registry/ComponentRegistry';
|
|
3
|
+
|
|
4
|
+
import './Component.css';
|
|
5
|
+
|
|
6
|
+
export interface ComponentProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
|
+
resizeable?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Component = forwardRef(function Component(
|
|
11
|
+
{ resizeable, ...props }: ComponentProps,
|
|
12
|
+
ref: React.ForwardedRef<HTMLDivElement>
|
|
13
|
+
) {
|
|
14
|
+
return <div {...props} className="Component" ref={ref} />;
|
|
15
|
+
}) as React.FunctionComponent<ComponentProps>;
|
|
16
|
+
Component.displayName = 'Component';
|
|
17
|
+
|
|
18
|
+
export default Component;
|
|
19
|
+
|
|
20
|
+
registerComponent('Component', Component);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.DraggableLayout {
|
|
2
|
+
display: inline-block;
|
|
3
|
+
outline: none;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
[data-dragging='true'] {
|
|
7
|
+
position: absolute !important;
|
|
8
|
+
z-index: 100;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.vuuSimpleDraggableWrapper {
|
|
12
|
+
background-color: white;
|
|
13
|
+
box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.2);
|
|
14
|
+
}
|
|
15
|
+
.vuuSimpleDraggableWrapper > * {
|
|
16
|
+
height: 100%;
|
|
17
|
+
width: 100%;
|
|
18
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import classnames from 'classnames';
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { registerComponent } from './registry/ComponentRegistry';
|
|
4
|
+
|
|
5
|
+
import './DraggableLayout.css';
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
+
export const DraggableLayout = function DraggableLayout(props: any) {
|
|
9
|
+
const sourceRef = useRef();
|
|
10
|
+
sourceRef.current = props;
|
|
11
|
+
|
|
12
|
+
const { className: classNameProp, id, style } = props;
|
|
13
|
+
|
|
14
|
+
const className = classnames('DraggableLayout', classNameProp);
|
|
15
|
+
return (
|
|
16
|
+
<div className={className} id={id} style={style}>
|
|
17
|
+
{props.children}
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const componentName = 'DraggableLayout';
|
|
23
|
+
|
|
24
|
+
DraggableLayout.displayName = componentName;
|
|
25
|
+
|
|
26
|
+
registerComponent(componentName, DraggableLayout, 'container');
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findSplitterAndPlaceholderPositions,
|
|
3
|
+
PLACEHOLDER,
|
|
4
|
+
SPLITTER
|
|
5
|
+
} from '../flexbox/flexbox-utils';
|
|
6
|
+
|
|
7
|
+
describe('findSplitterAndPlaceholderPositions', () => {
|
|
8
|
+
let positions;
|
|
9
|
+
describe('WHEN there are less than 2 items', () => {
|
|
10
|
+
it('THEN no splitters are inserted', () => {
|
|
11
|
+
positions = findSplitterAndPlaceholderPositions([]);
|
|
12
|
+
expect(positions).toEqual([]);
|
|
13
|
+
|
|
14
|
+
positions = findSplitterAndPlaceholderPositions([{ resizeable: true }]);
|
|
15
|
+
expect(positions).toEqual([0]);
|
|
16
|
+
|
|
17
|
+
positions = findSplitterAndPlaceholderPositions([{ resizeable: false }]);
|
|
18
|
+
expect(positions).toEqual([0]);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('WHEN there are no resizeable items', () => {
|
|
23
|
+
it('THEN no splitters are inserted', () => {
|
|
24
|
+
positions = findSplitterAndPlaceholderPositions([
|
|
25
|
+
{ resizeable: false },
|
|
26
|
+
{ resizeable: false }
|
|
27
|
+
]);
|
|
28
|
+
expect(positions).toEqual([0, 0]);
|
|
29
|
+
|
|
30
|
+
positions = findSplitterAndPlaceholderPositions([
|
|
31
|
+
{ resizeable: false },
|
|
32
|
+
{ resizeable: false },
|
|
33
|
+
{ resizeable: false }
|
|
34
|
+
]);
|
|
35
|
+
expect(positions).toEqual([0, 0, 0]);
|
|
36
|
+
|
|
37
|
+
positions = findSplitterAndPlaceholderPositions([
|
|
38
|
+
{ resizeable: false },
|
|
39
|
+
{ resizeable: false },
|
|
40
|
+
{ resizeable: false },
|
|
41
|
+
{ resizeable: false }
|
|
42
|
+
]);
|
|
43
|
+
expect(positions).toEqual([0, 0, 0, 0]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('WHEN all items are resizeable', () => {
|
|
48
|
+
it('THEN splitters are inserted between items', () => {
|
|
49
|
+
positions = findSplitterAndPlaceholderPositions([{ resizeable: true }, { resizeable: true }]);
|
|
50
|
+
expect(positions).toEqual([1, 0]);
|
|
51
|
+
|
|
52
|
+
positions = findSplitterAndPlaceholderPositions([
|
|
53
|
+
{ resizeable: true },
|
|
54
|
+
{ resizeable: true },
|
|
55
|
+
{ resizeable: true }
|
|
56
|
+
]);
|
|
57
|
+
expect(positions).toEqual([1, 1, 0]);
|
|
58
|
+
|
|
59
|
+
positions = findSplitterAndPlaceholderPositions([
|
|
60
|
+
{ resizeable: true },
|
|
61
|
+
{ resizeable: true },
|
|
62
|
+
{ resizeable: true },
|
|
63
|
+
{ resizeable: true }
|
|
64
|
+
]);
|
|
65
|
+
expect(positions).toEqual([1, 1, 1, 0]);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('WHEN some items are resizeable', () => {
|
|
70
|
+
it('THEN splitters are inserted where appropriate between items', () => {
|
|
71
|
+
// positions = findSplitterAndPlaceholderPositions([{resizeable: true},{resizeable: true}]);
|
|
72
|
+
// expect(positions).toEqual([1,0])
|
|
73
|
+
|
|
74
|
+
positions = findSplitterAndPlaceholderPositions([
|
|
75
|
+
{ resizeable: false },
|
|
76
|
+
{ resizeable: true },
|
|
77
|
+
{ resizeable: true }
|
|
78
|
+
]);
|
|
79
|
+
expect(positions).toEqual([0, 1, 0]);
|
|
80
|
+
|
|
81
|
+
positions = findSplitterAndPlaceholderPositions([
|
|
82
|
+
{ resizeable: false },
|
|
83
|
+
{ resizeable: true },
|
|
84
|
+
{ resizeable: true },
|
|
85
|
+
{ resizeable: true }
|
|
86
|
+
]);
|
|
87
|
+
expect(positions).toEqual([0, 1, 1, 0]);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
.hwChest {
|
|
2
|
+
--chest-bg: var(--hw-chest-bg, inherit);
|
|
3
|
+
--drawer-bg: var(--hw-drawer-bg, inherit);
|
|
4
|
+
--drawer-size: var(--hw-drawer-size, 200px);
|
|
5
|
+
--drawer-peek-size: var(--hw-drawer-peek-size, 32px);
|
|
6
|
+
--drawer-transition-duration: var(--hw-drawer-transition-duration, 0.4s);
|
|
7
|
+
background-color: var(--chest-bg);
|
|
8
|
+
display: flex;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.hwChest-horizontal {
|
|
12
|
+
flex-direction: row;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.hwChest-vertical {
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.hwChest-content {
|
|
20
|
+
background-color: var(--chest-bg);
|
|
21
|
+
flex-grow: 1;
|
|
22
|
+
flex-shrink: 1;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
/* position: relative; */
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.hwChest-horizontal .hwChest-content {
|
|
31
|
+
flex-basis: 100%;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.hwChest-vertical .hwChest-content {
|
|
35
|
+
flex-basis: 100%;
|
|
36
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React, { HTMLAttributes, ReactElement } from "react";
|
|
2
|
+
import cx from "classnames";
|
|
3
|
+
import Drawer from "./Drawer";
|
|
4
|
+
import { partition } from "@vuu-ui/vuu-utils";
|
|
5
|
+
import { registerComponent } from "../registry/ComponentRegistry";
|
|
6
|
+
|
|
7
|
+
import "./Chest.css";
|
|
8
|
+
|
|
9
|
+
const isDrawer = (component: ReactElement) => component.type === Drawer;
|
|
10
|
+
const isVertical = ({ props: { position = "left" } }: ReactElement) =>
|
|
11
|
+
position.match(/top|bottom/);
|
|
12
|
+
|
|
13
|
+
export interface ChestProps extends HTMLAttributes<HTMLDivElement> {
|
|
14
|
+
children: ReactElement[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const Chest = (props: ChestProps) => {
|
|
18
|
+
const { children, className: classNameProp, id, style } = props;
|
|
19
|
+
const classBase = "hwChest";
|
|
20
|
+
const [drawers, content] = partition(children, isDrawer);
|
|
21
|
+
const [verticalDrawers, horizontalDrawers] = partition(drawers, isVertical);
|
|
22
|
+
const orientation =
|
|
23
|
+
verticalDrawers.length === 0
|
|
24
|
+
? "horizontal"
|
|
25
|
+
: horizontalDrawers.length === 0
|
|
26
|
+
? "vertical"
|
|
27
|
+
: "both";
|
|
28
|
+
|
|
29
|
+
const className = cx(classBase, classNameProp, `${classBase}-${orientation}`);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className={className} id={id} style={style}>
|
|
33
|
+
{drawers}
|
|
34
|
+
<div className={`${classBase}-content`}>{content}</div>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
Chest.displayName = "Chest";
|
|
39
|
+
|
|
40
|
+
export default Chest;
|
|
41
|
+
|
|
42
|
+
registerComponent("Chest", Chest, "container");
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
.vuuDrawer {
|
|
2
|
+
--drawer-leading-edge-border: solid 1px var(--salt-container-primary-borderColor, none);
|
|
3
|
+
--vuu-close-icon-svg: var(--svg-chevron-double-right);
|
|
4
|
+
|
|
5
|
+
transition: flex-basis;
|
|
6
|
+
transition-duration: var(--drawer-transition-duration);
|
|
7
|
+
position: relative;
|
|
8
|
+
z-index: 1;
|
|
9
|
+
flex-basis: 0;
|
|
10
|
+
flex-grow: 1;
|
|
11
|
+
flex-shrink: 1;
|
|
12
|
+
min-width: 0;
|
|
13
|
+
min-height: 0;
|
|
14
|
+
display: flex;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.vuuDrawer-peekaboo {
|
|
18
|
+
flex-basis: var(--drawer-peek-size);
|
|
19
|
+
flex-grow: 0;
|
|
20
|
+
flex-shrink: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.vuuDrawer-inline.vuuDrawer-open {
|
|
24
|
+
flex-basis: var(--drawer-size);
|
|
25
|
+
flex-grow: 0;
|
|
26
|
+
flex-shrink: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.vuuDrawer-liner {
|
|
30
|
+
background-color: var(--drawer-bg);
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
position: relative;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.vuuDrawer-content {
|
|
36
|
+
height: 100%;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: 0;
|
|
40
|
+
right: var(--drawer-peek-size);
|
|
41
|
+
transition: right;
|
|
42
|
+
transition-duration: var(--drawer-transition-duration);
|
|
43
|
+
width: 100%;
|
|
44
|
+
flex: 1 1 100%;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.vuuDrawer-open .vuuDrawer-content {
|
|
48
|
+
right: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* .vuuDrawer:not(.vuuDrawer-open) .vuuDrawer-liner > * {
|
|
52
|
+
display: none;
|
|
53
|
+
} */
|
|
54
|
+
|
|
55
|
+
.vuuDrawer-left {
|
|
56
|
+
border-right: var(--drawer-leading-edge-border);
|
|
57
|
+
}
|
|
58
|
+
.vuuDrawer-right {
|
|
59
|
+
border-left: var(--drawer-leading-edge-border);
|
|
60
|
+
}
|
|
61
|
+
.vuuDrawer-top {
|
|
62
|
+
border-bottom: var(--drawer-leading-edge-border);
|
|
63
|
+
}
|
|
64
|
+
.vuuDrawer-bottom {
|
|
65
|
+
border-top: var(--drawer-leading-edge-border);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.vuuDrawer-left .vuuDrawer-liner,
|
|
69
|
+
.vuuDrawer-right .vuuDrawer-liner {
|
|
70
|
+
height: 100%;
|
|
71
|
+
transition: width;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.vuuDrawer-top .vuuDrawer-liner,
|
|
75
|
+
.vuuDrawer-bottom .vuuDrawer-liner {
|
|
76
|
+
width: 100%;
|
|
77
|
+
transition: height;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.vuuDrawer-inline .vuuDrawer-liner {
|
|
81
|
+
width: 100%;
|
|
82
|
+
height: 100%;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.vuuDrawer-over .vuuDrawer-liner {
|
|
86
|
+
position: absolute;
|
|
87
|
+
transition-duration: 0.4s;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.vuuDrawer-over.vuuDrawer-left .vuuDrawer-liner {
|
|
91
|
+
top: 0;
|
|
92
|
+
left: 0;
|
|
93
|
+
width: 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.vuuDrawer-over.vuuDrawer-right .vuuDrawer-liner {
|
|
97
|
+
top: 0;
|
|
98
|
+
right: 0;
|
|
99
|
+
width: 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.vuuDrawer-over.vuuDrawer-top .vuuDrawer-liner {
|
|
103
|
+
height: 0;
|
|
104
|
+
top: 0;
|
|
105
|
+
left: 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.vuuDrawer-over.vuuDrawer-bottom .vuuDrawer-liner {
|
|
109
|
+
bottom: 0;
|
|
110
|
+
height: 0;
|
|
111
|
+
left: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.vuuDrawer-left.vuuDrawer-over.vuuDrawer-peekaboo .vuuDrawer-liner,
|
|
115
|
+
.vuuDrawer-right.vuuDrawer-over.vuuDrawer-peekaboo .vuuDrawer-liner {
|
|
116
|
+
width: var(--drawer-peek-size);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.vuuDrawer-top.vuuDrawer-over.vuuDrawer-peekaboo .vuuDrawer-liner,
|
|
120
|
+
.vuuDrawer-bottom.vuuDrawer-over.vuuDrawer-peekaboo .vuuDrawer-liner {
|
|
121
|
+
height: var(--drawer-peek-size);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.vuuDrawer-left.vuuDrawer-over.vuuDrawer-open .vuuDrawer-liner,
|
|
125
|
+
.vuuDrawer-right.vuuDrawer-over.vuuDrawer-open .vuuDrawer-liner {
|
|
126
|
+
width: var(--drawer-size);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.vuuDrawer-top.vuuDrawer-over.vuuDrawer-open .vuuDrawer-liner,
|
|
130
|
+
.vuuDrawer-bottom.vuuDrawer-over.vuuDrawer-open .vuuDrawer-liner {
|
|
131
|
+
height: var(--drawer-size);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.vuuDrawer-top,
|
|
135
|
+
.vuuDrawer-left {
|
|
136
|
+
order: 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.vuuDrawer-bottom,
|
|
140
|
+
.vuuDrawer-right {
|
|
141
|
+
order: 99;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.vuuDrawer-left,
|
|
145
|
+
.vuuDrawer-right {
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.vuuToggleButton-container {
|
|
150
|
+
--saltButton-height: 28px;
|
|
151
|
+
--saltButton-width: 28px;
|
|
152
|
+
--vuu-icon-size: 12px;
|
|
153
|
+
flex: 0 0 28px;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.vuuDrawer-open {
|
|
157
|
+
--vuu-close-icon-svg: var(--svg-chevron-double-left);
|
|
158
|
+
|
|
159
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Button, useControlled } from "@salt-ds/core";
|
|
2
|
+
import cx from "classnames";
|
|
3
|
+
import { CSSProperties, HTMLAttributes, useCallback } from "react";
|
|
4
|
+
|
|
5
|
+
import "./Drawer.css";
|
|
6
|
+
|
|
7
|
+
const classBase = "vuuDrawer";
|
|
8
|
+
|
|
9
|
+
const sizeAttribute = (value: string | number) => {
|
|
10
|
+
return typeof value === "string" ? value : value + "px";
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const getStyle = (
|
|
14
|
+
styleProp?: CSSProperties,
|
|
15
|
+
sizeOpen?: number,
|
|
16
|
+
sizeClosed?: number
|
|
17
|
+
) => {
|
|
18
|
+
const hasSizeOpen = sizeOpen !== undefined;
|
|
19
|
+
const hasSizeClosed = sizeClosed !== undefined;
|
|
20
|
+
|
|
21
|
+
if (!styleProp && !hasSizeClosed && !hasSizeOpen) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!hasSizeClosed && !hasSizeOpen) {
|
|
26
|
+
return styleProp;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
...styleProp,
|
|
31
|
+
"--drawer-size": hasSizeOpen ? sizeAttribute(sizeOpen) : undefined,
|
|
32
|
+
"--drawer-peek-size": hasSizeClosed ? sizeAttribute(sizeClosed) : undefined,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export interface DrawerProps extends HTMLAttributes<HTMLDivElement> {
|
|
37
|
+
clickToOpen?: boolean;
|
|
38
|
+
defaultOpen: boolean;
|
|
39
|
+
inline?: boolean;
|
|
40
|
+
open?: boolean;
|
|
41
|
+
peekaboo?: boolean;
|
|
42
|
+
position?: "left" | "right" | "top" | "bottom";
|
|
43
|
+
sizeOpen?: number;
|
|
44
|
+
sizeClosed?: number;
|
|
45
|
+
toggleButton?: "start" | "end";
|
|
46
|
+
}
|
|
47
|
+
const Drawer = ({
|
|
48
|
+
children,
|
|
49
|
+
className: classNameProp,
|
|
50
|
+
clickToOpen,
|
|
51
|
+
defaultOpen,
|
|
52
|
+
sizeOpen,
|
|
53
|
+
sizeClosed,
|
|
54
|
+
style: styleProp,
|
|
55
|
+
open: openProp,
|
|
56
|
+
position = "left",
|
|
57
|
+
inline,
|
|
58
|
+
onClick,
|
|
59
|
+
peekaboo = false,
|
|
60
|
+
toggleButton,
|
|
61
|
+
...props
|
|
62
|
+
}: DrawerProps) => {
|
|
63
|
+
const [open, setOpen] = useControlled({
|
|
64
|
+
controlled: openProp,
|
|
65
|
+
default: defaultOpen ?? false,
|
|
66
|
+
name: "Drawer",
|
|
67
|
+
state: "open",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const className = cx(classBase, classNameProp, `${classBase}-${position}`, {
|
|
71
|
+
[`${classBase}-open`]: open,
|
|
72
|
+
[`${classBase}-inline`]: inline,
|
|
73
|
+
[`${classBase}-over`]: !inline,
|
|
74
|
+
[`${classBase}-peekaboo`]: peekaboo,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const toggleDrawer = useCallback(() => {
|
|
78
|
+
console.log("toggleDrawer");
|
|
79
|
+
setOpen(!open);
|
|
80
|
+
}, [open, setOpen]);
|
|
81
|
+
|
|
82
|
+
const style = getStyle(styleProp, sizeOpen, sizeClosed);
|
|
83
|
+
|
|
84
|
+
const handleClick = clickToOpen ? toggleDrawer : onClick;
|
|
85
|
+
|
|
86
|
+
const renderToggleButton = () => (
|
|
87
|
+
<div className={cx("vuuToggleButton-container")}>
|
|
88
|
+
{open ? (
|
|
89
|
+
<Button
|
|
90
|
+
aria-label="close"
|
|
91
|
+
onClick={toggleDrawer}
|
|
92
|
+
data-icon="close"
|
|
93
|
+
variant="secondary"
|
|
94
|
+
/>
|
|
95
|
+
) : (
|
|
96
|
+
<Button
|
|
97
|
+
aria-label="open"
|
|
98
|
+
onClick={toggleDrawer}
|
|
99
|
+
data-icon="close"
|
|
100
|
+
variant="secondary"
|
|
101
|
+
/>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div {...props} className={className} onClick={handleClick} style={style}>
|
|
108
|
+
{toggleButton == "start" ? renderToggleButton() : null}
|
|
109
|
+
<div className={`${classBase}-liner`}>
|
|
110
|
+
<div className={`${classBase}-content`}>{children}</div>
|
|
111
|
+
</div>
|
|
112
|
+
{toggleButton == "end" ? renderToggleButton() : null}
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
Drawer.displayName = "Drawer";
|
|
117
|
+
|
|
118
|
+
export default Drawer;
|
package/src/debug.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { typeOf } from './utils';
|
|
3
|
+
|
|
4
|
+
export const tree = (el: ReactElement, depth = 0) => {
|
|
5
|
+
const type = typeOf(el);
|
|
6
|
+
const spaces = ' ';
|
|
7
|
+
let str = `\n${spaces.slice(0, depth)}${type}`;
|
|
8
|
+
if (type !== 'View') {
|
|
9
|
+
const els = el.props.children || [];
|
|
10
|
+
(Array.isArray(els) ? els : [els]).forEach((child) => {
|
|
11
|
+
str += tree(child, depth + 1);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return str;
|
|
16
|
+
};
|