@zendeskgarden/react-grid 9.0.0-next.7 → 9.0.0-next.9
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/dist/esm/elements/Col.js +72 -0
- package/dist/esm/elements/Grid.js +54 -0
- package/dist/esm/elements/Row.js +58 -0
- package/dist/esm/elements/pane/Pane.js +55 -0
- package/dist/esm/elements/pane/PaneProvider.js +197 -0
- package/dist/esm/elements/pane/components/Content.js +30 -0
- package/dist/esm/elements/pane/components/Splitter.js +128 -0
- package/dist/esm/elements/pane/components/SplitterButton.js +91 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/styled/StyledCol.js +73 -0
- package/dist/esm/styled/StyledGrid.js +33 -0
- package/dist/esm/styled/StyledRow.js +53 -0
- package/dist/esm/styled/pane/StyledPane.js +22 -0
- package/dist/esm/styled/pane/StyledPaneContent.js +22 -0
- package/dist/esm/styled/pane/StyledPaneSplitter.js +99 -0
- package/dist/esm/styled/pane/StyledPaneSplitterButton.js +48 -0
- package/dist/esm/styled/pane/StyledPaneSplitterButtonContainer.js +116 -0
- package/dist/esm/types/index.js +16 -0
- package/dist/esm/utils/useGridContext.js +16 -0
- package/dist/esm/utils/usePaneContext.js +16 -0
- package/dist/esm/utils/usePaneProviderContext.js +17 -0
- package/dist/esm/utils/usePaneSplitterContext.js +22 -0
- package/dist/index.cjs.js +22 -36
- package/package.json +7 -7
- package/dist/index.esm.js +0 -978
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { ALIGN_SELF, TEXT_ALIGN } from '../types/index.js';
|
|
10
|
+
import { StyledCol } from '../styled/StyledCol.js';
|
|
11
|
+
import '../styled/StyledGrid.js';
|
|
12
|
+
import '../styled/StyledRow.js';
|
|
13
|
+
import '../styled/pane/StyledPane.js';
|
|
14
|
+
import '../styled/pane/StyledPaneContent.js';
|
|
15
|
+
import '../styled/pane/StyledPaneSplitter.js';
|
|
16
|
+
import '../styled/pane/StyledPaneSplitterButton.js';
|
|
17
|
+
import '../styled/pane/StyledPaneSplitterButtonContainer.js';
|
|
18
|
+
import useGridContext from '../utils/useGridContext.js';
|
|
19
|
+
|
|
20
|
+
const Col = React.forwardRef((_ref, ref) => {
|
|
21
|
+
let {
|
|
22
|
+
size,
|
|
23
|
+
...props
|
|
24
|
+
} = _ref;
|
|
25
|
+
const {
|
|
26
|
+
columns,
|
|
27
|
+
gutters,
|
|
28
|
+
debug
|
|
29
|
+
} = useGridContext();
|
|
30
|
+
return React.createElement(StyledCol, Object.assign({
|
|
31
|
+
sizeAll: size,
|
|
32
|
+
columns: columns,
|
|
33
|
+
gutters: gutters,
|
|
34
|
+
debug: debug,
|
|
35
|
+
ref: ref
|
|
36
|
+
}, props));
|
|
37
|
+
});
|
|
38
|
+
Col.displayName = 'Col';
|
|
39
|
+
Col.propTypes = {
|
|
40
|
+
size: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
41
|
+
xs: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.bool]),
|
|
42
|
+
sm: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.bool]),
|
|
43
|
+
md: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.bool]),
|
|
44
|
+
lg: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.bool]),
|
|
45
|
+
xl: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.bool]),
|
|
46
|
+
alignSelf: PropTypes.oneOf(ALIGN_SELF),
|
|
47
|
+
alignSelfXs: PropTypes.oneOf(ALIGN_SELF),
|
|
48
|
+
alignSelfSm: PropTypes.oneOf(ALIGN_SELF),
|
|
49
|
+
alignSelfMd: PropTypes.oneOf(ALIGN_SELF),
|
|
50
|
+
alignSelfLg: PropTypes.oneOf(ALIGN_SELF),
|
|
51
|
+
alignSelfXl: PropTypes.oneOf(ALIGN_SELF),
|
|
52
|
+
textAlign: PropTypes.oneOf(TEXT_ALIGN),
|
|
53
|
+
textAlignXs: PropTypes.oneOf(TEXT_ALIGN),
|
|
54
|
+
textAlignSm: PropTypes.oneOf(TEXT_ALIGN),
|
|
55
|
+
textAlignMd: PropTypes.oneOf(TEXT_ALIGN),
|
|
56
|
+
textAlignLg: PropTypes.oneOf(TEXT_ALIGN),
|
|
57
|
+
textAlignXl: PropTypes.oneOf(TEXT_ALIGN),
|
|
58
|
+
offset: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
59
|
+
offsetXs: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
60
|
+
offsetSm: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
61
|
+
offsetMd: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
62
|
+
offsetLg: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
63
|
+
offsetXl: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
64
|
+
order: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
65
|
+
orderXs: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
66
|
+
orderSm: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
67
|
+
orderMd: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
68
|
+
orderLg: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
69
|
+
orderXl: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export { Col };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React, { useMemo } from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { SPACE } from '../types/index.js';
|
|
10
|
+
import { GridContext } from '../utils/useGridContext.js';
|
|
11
|
+
import '../styled/StyledCol.js';
|
|
12
|
+
import { StyledGrid } from '../styled/StyledGrid.js';
|
|
13
|
+
import '../styled/StyledRow.js';
|
|
14
|
+
import '../styled/pane/StyledPane.js';
|
|
15
|
+
import '../styled/pane/StyledPaneContent.js';
|
|
16
|
+
import '../styled/pane/StyledPaneSplitter.js';
|
|
17
|
+
import '../styled/pane/StyledPaneSplitterButton.js';
|
|
18
|
+
import '../styled/pane/StyledPaneSplitterButtonContainer.js';
|
|
19
|
+
import { Row } from './Row.js';
|
|
20
|
+
import { Col } from './Col.js';
|
|
21
|
+
|
|
22
|
+
const GridComponent = React.forwardRef((_ref, ref) => {
|
|
23
|
+
let {
|
|
24
|
+
columns,
|
|
25
|
+
debug,
|
|
26
|
+
...props
|
|
27
|
+
} = _ref;
|
|
28
|
+
const value = useMemo(() => ({
|
|
29
|
+
columns,
|
|
30
|
+
gutters: props.gutters,
|
|
31
|
+
debug
|
|
32
|
+
}), [columns, props.gutters, debug]);
|
|
33
|
+
return React.createElement(GridContext.Provider, {
|
|
34
|
+
value: value
|
|
35
|
+
}, React.createElement(StyledGrid, Object.assign({
|
|
36
|
+
debug: debug,
|
|
37
|
+
ref: ref
|
|
38
|
+
}, props)));
|
|
39
|
+
});
|
|
40
|
+
GridComponent.displayName = 'Grid';
|
|
41
|
+
GridComponent.propTypes = {
|
|
42
|
+
columns: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
43
|
+
gutters: PropTypes.oneOf(SPACE),
|
|
44
|
+
debug: PropTypes.bool
|
|
45
|
+
};
|
|
46
|
+
GridComponent.defaultProps = {
|
|
47
|
+
columns: 12,
|
|
48
|
+
gutters: 'md'
|
|
49
|
+
};
|
|
50
|
+
const Grid = GridComponent;
|
|
51
|
+
Grid.Row = Row;
|
|
52
|
+
Grid.Col = Col;
|
|
53
|
+
|
|
54
|
+
export { Grid, GridComponent };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { ALIGN_ITEMS, JUSTIFY_CONTENT, WRAP } from '../types/index.js';
|
|
10
|
+
import useGridContext from '../utils/useGridContext.js';
|
|
11
|
+
import '../styled/StyledCol.js';
|
|
12
|
+
import '../styled/StyledGrid.js';
|
|
13
|
+
import { StyledRow } from '../styled/StyledRow.js';
|
|
14
|
+
import '../styled/pane/StyledPane.js';
|
|
15
|
+
import '../styled/pane/StyledPaneContent.js';
|
|
16
|
+
import '../styled/pane/StyledPaneSplitter.js';
|
|
17
|
+
import '../styled/pane/StyledPaneSplitterButton.js';
|
|
18
|
+
import '../styled/pane/StyledPaneSplitterButtonContainer.js';
|
|
19
|
+
|
|
20
|
+
const Row = React.forwardRef((_ref, ref) => {
|
|
21
|
+
let {
|
|
22
|
+
wrap,
|
|
23
|
+
...props
|
|
24
|
+
} = _ref;
|
|
25
|
+
const {
|
|
26
|
+
gutters,
|
|
27
|
+
debug
|
|
28
|
+
} = useGridContext();
|
|
29
|
+
return React.createElement(StyledRow, Object.assign({
|
|
30
|
+
gutters: gutters,
|
|
31
|
+
debug: debug,
|
|
32
|
+
wrapAll: wrap,
|
|
33
|
+
ref: ref
|
|
34
|
+
}, props));
|
|
35
|
+
});
|
|
36
|
+
Row.displayName = 'Row';
|
|
37
|
+
Row.propTypes = {
|
|
38
|
+
alignItems: PropTypes.oneOf(ALIGN_ITEMS),
|
|
39
|
+
alignItemsXs: PropTypes.oneOf(ALIGN_ITEMS),
|
|
40
|
+
alignItemsSm: PropTypes.oneOf(ALIGN_ITEMS),
|
|
41
|
+
alignItemsMd: PropTypes.oneOf(ALIGN_ITEMS),
|
|
42
|
+
alignItemsLg: PropTypes.oneOf(ALIGN_ITEMS),
|
|
43
|
+
alignItemsXl: PropTypes.oneOf(ALIGN_ITEMS),
|
|
44
|
+
justifyContent: PropTypes.oneOf(JUSTIFY_CONTENT),
|
|
45
|
+
justifyContentXs: PropTypes.oneOf(JUSTIFY_CONTENT),
|
|
46
|
+
justifyContentSm: PropTypes.oneOf(JUSTIFY_CONTENT),
|
|
47
|
+
justifyContentMd: PropTypes.oneOf(JUSTIFY_CONTENT),
|
|
48
|
+
justifyContentLg: PropTypes.oneOf(JUSTIFY_CONTENT),
|
|
49
|
+
justifyContentXl: PropTypes.oneOf(JUSTIFY_CONTENT),
|
|
50
|
+
wrap: PropTypes.oneOf(WRAP),
|
|
51
|
+
wrapXs: PropTypes.oneOf(WRAP),
|
|
52
|
+
wrapSm: PropTypes.oneOf(WRAP),
|
|
53
|
+
wrapMd: PropTypes.oneOf(WRAP),
|
|
54
|
+
wrapLg: PropTypes.oneOf(WRAP),
|
|
55
|
+
wrapXl: PropTypes.oneOf(WRAP)
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export { Row };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React, { forwardRef, useState, useRef, useMemo } from 'react';
|
|
8
|
+
import useResizeObserver from 'use-resize-observer';
|
|
9
|
+
import { mergeRefs } from 'react-merge-refs';
|
|
10
|
+
import { Splitter } from './components/Splitter.js';
|
|
11
|
+
import { Content } from './components/Content.js';
|
|
12
|
+
import { SplitterButton } from './components/SplitterButton.js';
|
|
13
|
+
import '../../styled/StyledCol.js';
|
|
14
|
+
import '../../styled/StyledGrid.js';
|
|
15
|
+
import '../../styled/StyledRow.js';
|
|
16
|
+
import { StyledPane } from '../../styled/pane/StyledPane.js';
|
|
17
|
+
import '../../styled/pane/StyledPaneContent.js';
|
|
18
|
+
import '../../styled/pane/StyledPaneSplitter.js';
|
|
19
|
+
import '../../styled/pane/StyledPaneSplitterButton.js';
|
|
20
|
+
import '../../styled/pane/StyledPaneSplitterButtonContainer.js';
|
|
21
|
+
import { PaneContext } from '../../utils/usePaneContext.js';
|
|
22
|
+
|
|
23
|
+
const PaneComponent = forwardRef((_ref, ref) => {
|
|
24
|
+
let {
|
|
25
|
+
children,
|
|
26
|
+
...props
|
|
27
|
+
} = _ref;
|
|
28
|
+
const [paneId, setPaneId] = useState();
|
|
29
|
+
const observerRef = useRef(null);
|
|
30
|
+
const {
|
|
31
|
+
width = 0,
|
|
32
|
+
height = 0
|
|
33
|
+
} = useResizeObserver({
|
|
34
|
+
ref: observerRef
|
|
35
|
+
});
|
|
36
|
+
const isVisible = useMemo(() => observerRef.current ? width > 0 && height > 0 : true, [width, height]);
|
|
37
|
+
const paneContext = useMemo(() => ({
|
|
38
|
+
isVisible,
|
|
39
|
+
id: paneId,
|
|
40
|
+
setId: id => setPaneId(id)
|
|
41
|
+
}), [paneId, isVisible]);
|
|
42
|
+
return React.createElement(PaneContext.Provider, {
|
|
43
|
+
value: paneContext
|
|
44
|
+
}, React.createElement(StyledPane, Object.assign({
|
|
45
|
+
id: paneId,
|
|
46
|
+
ref: mergeRefs([ref, observerRef])
|
|
47
|
+
}, props), children));
|
|
48
|
+
});
|
|
49
|
+
PaneComponent.displayName = 'Pane';
|
|
50
|
+
const Pane = PaneComponent;
|
|
51
|
+
Pane.Content = Content;
|
|
52
|
+
Pane.Splitter = Splitter;
|
|
53
|
+
Pane.SplitterButton = SplitterButton;
|
|
54
|
+
|
|
55
|
+
export { Pane };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React, { useState, useCallback, useMemo } from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { useId } from '@zendeskgarden/container-utilities';
|
|
10
|
+
import usePaneProviderContext, { PaneProviderContext } from '../../utils/usePaneProviderContext.js';
|
|
11
|
+
|
|
12
|
+
const getPixelsPerFr = (totalFrs, totalDimension) => {
|
|
13
|
+
return totalDimension / totalFrs;
|
|
14
|
+
};
|
|
15
|
+
const convertToPixels = (values, pixelsPerFr) => {
|
|
16
|
+
return Object.entries(values).reduce((prev, _ref) => {
|
|
17
|
+
let [key, value] = _ref;
|
|
18
|
+
prev[key] = value * pixelsPerFr;
|
|
19
|
+
return prev;
|
|
20
|
+
}, {});
|
|
21
|
+
};
|
|
22
|
+
const PaneProvider = _ref2 => {
|
|
23
|
+
let {
|
|
24
|
+
id,
|
|
25
|
+
totalPanesWidth,
|
|
26
|
+
totalPanesHeight,
|
|
27
|
+
defaultRowValues,
|
|
28
|
+
defaultColumnValues,
|
|
29
|
+
rowValues,
|
|
30
|
+
columnValues,
|
|
31
|
+
onChange,
|
|
32
|
+
children
|
|
33
|
+
} = _ref2;
|
|
34
|
+
const isControlled = rowValues !== undefined && rowValues !== null && columnValues !== undefined && columnValues !== null;
|
|
35
|
+
const [rowState, setRowState] = useState(defaultRowValues || {});
|
|
36
|
+
const [columnState, setColumnState] = useState(defaultColumnValues || {});
|
|
37
|
+
const rowsTrack = isControlled ? rowValues : rowState;
|
|
38
|
+
const columnsTrack = isControlled ? columnValues : columnState;
|
|
39
|
+
const setRowsTrack = useCallback(values => {
|
|
40
|
+
if (isControlled && onChange) {
|
|
41
|
+
return onChange(values(rowsTrack), columnsTrack);
|
|
42
|
+
}
|
|
43
|
+
return setRowState(values);
|
|
44
|
+
}, [isControlled, onChange, setRowState, columnsTrack, rowsTrack]);
|
|
45
|
+
const setColumnsTrack = useCallback(values => {
|
|
46
|
+
if (isControlled && onChange) {
|
|
47
|
+
return onChange(rowsTrack, values(columnsTrack));
|
|
48
|
+
}
|
|
49
|
+
return setColumnState(values);
|
|
50
|
+
}, [isControlled, onChange, setColumnState, rowsTrack, columnsTrack]);
|
|
51
|
+
const totalFractions = useMemo(() => ({
|
|
52
|
+
rows: Object.values(rowsTrack).reduce((prev, value) => value + prev, 0),
|
|
53
|
+
columns: Object.values(columnsTrack).reduce((prev, value) => value + prev, 0)
|
|
54
|
+
}), [rowsTrack, columnsTrack]);
|
|
55
|
+
const pixelsPerFr = useMemo(() => ({
|
|
56
|
+
rows: getPixelsPerFr(totalFractions.rows, totalPanesHeight),
|
|
57
|
+
columns: getPixelsPerFr(totalFractions.columns, totalPanesWidth)
|
|
58
|
+
}), [totalFractions, totalPanesHeight, totalPanesWidth]);
|
|
59
|
+
const layoutStateInPixels = useMemo(() => ({
|
|
60
|
+
rows: convertToPixels(rowsTrack, pixelsPerFr.rows),
|
|
61
|
+
columns: convertToPixels(columnsTrack, pixelsPerFr.columns)
|
|
62
|
+
}), [rowsTrack, columnsTrack, pixelsPerFr]);
|
|
63
|
+
const layoutIndices = useMemo(() => {
|
|
64
|
+
const rowArray = Object.keys(rowsTrack);
|
|
65
|
+
const columnArray = Object.keys(columnsTrack);
|
|
66
|
+
const rows = rowArray.reduce((prev, key, index) => {
|
|
67
|
+
prev[key] = index;
|
|
68
|
+
return prev;
|
|
69
|
+
}, {});
|
|
70
|
+
const columns = columnArray.reduce((prev, key, index) => {
|
|
71
|
+
prev[key] = index;
|
|
72
|
+
return prev;
|
|
73
|
+
}, {});
|
|
74
|
+
return {
|
|
75
|
+
rows,
|
|
76
|
+
columns,
|
|
77
|
+
rowArray,
|
|
78
|
+
columnArray
|
|
79
|
+
};
|
|
80
|
+
}, [rowsTrack, columnsTrack]);
|
|
81
|
+
const setRowValue = useCallback((isTop, splitterId, value) => {
|
|
82
|
+
const {
|
|
83
|
+
rows,
|
|
84
|
+
rowArray
|
|
85
|
+
} = layoutIndices;
|
|
86
|
+
const stealFromTraversal = isTop ? -1 : 1;
|
|
87
|
+
const addToTraversal = 0;
|
|
88
|
+
setRowsTrack(state => {
|
|
89
|
+
const oldValue = rowsTrack[splitterId];
|
|
90
|
+
const stealFromIndex = rows[splitterId] + stealFromTraversal;
|
|
91
|
+
const addToIndex = rows[splitterId] + addToTraversal;
|
|
92
|
+
const stealFromKey = rowArray[stealFromIndex];
|
|
93
|
+
const addToKey = rowArray[addToIndex];
|
|
94
|
+
const difference = oldValue - value;
|
|
95
|
+
const nextState = {
|
|
96
|
+
...state
|
|
97
|
+
};
|
|
98
|
+
nextState[addToKey] = rowsTrack[addToKey] - difference;
|
|
99
|
+
nextState[stealFromKey] = rowsTrack[stealFromKey] + difference;
|
|
100
|
+
return nextState;
|
|
101
|
+
});
|
|
102
|
+
}, [layoutIndices, rowsTrack, setRowsTrack]);
|
|
103
|
+
const setColumnValue = useCallback((isStart, splitterId, value) => {
|
|
104
|
+
const {
|
|
105
|
+
columns,
|
|
106
|
+
columnArray
|
|
107
|
+
} = layoutIndices;
|
|
108
|
+
const stealFromTraversal = isStart ? -1 : 1;
|
|
109
|
+
const addToTraversal = 0;
|
|
110
|
+
setColumnsTrack(state => {
|
|
111
|
+
const stealFromIndex = columns[splitterId] + stealFromTraversal;
|
|
112
|
+
const addToIndex = columns[splitterId] + addToTraversal;
|
|
113
|
+
const oldValue = columnsTrack[splitterId];
|
|
114
|
+
const stealFromKey = columnArray[stealFromIndex];
|
|
115
|
+
const addToKey = columnArray[addToIndex];
|
|
116
|
+
const difference = oldValue - value;
|
|
117
|
+
const nextState = {
|
|
118
|
+
...state
|
|
119
|
+
};
|
|
120
|
+
nextState[addToKey] = columnsTrack[addToKey] - difference;
|
|
121
|
+
nextState[stealFromKey] = columnsTrack[stealFromKey] + difference;
|
|
122
|
+
return nextState;
|
|
123
|
+
});
|
|
124
|
+
}, [layoutIndices, columnsTrack, setColumnsTrack]);
|
|
125
|
+
const getColumnValue = useCallback((splitterKey, isPixels) => {
|
|
126
|
+
if (isPixels) {
|
|
127
|
+
return layoutStateInPixels.columns[splitterKey];
|
|
128
|
+
}
|
|
129
|
+
return columnsTrack[splitterKey];
|
|
130
|
+
}, [columnsTrack, layoutStateInPixels]);
|
|
131
|
+
const getRowValue = useCallback((splitterKey, isPixels) => {
|
|
132
|
+
if (isPixels) {
|
|
133
|
+
return layoutStateInPixels.rows[splitterKey];
|
|
134
|
+
}
|
|
135
|
+
return rowsTrack[splitterKey];
|
|
136
|
+
}, [rowsTrack, layoutStateInPixels]);
|
|
137
|
+
const getGridTemplateColumns = useCallback(isPixels => {
|
|
138
|
+
const {
|
|
139
|
+
columnArray
|
|
140
|
+
} = layoutIndices;
|
|
141
|
+
if (isPixels) {
|
|
142
|
+
return columnArray.map(col => `${layoutStateInPixels.columns[col]}px`).join(' ');
|
|
143
|
+
}
|
|
144
|
+
return columnArray.map(col => `${columnsTrack[col]}fr`).join(' ');
|
|
145
|
+
}, [layoutIndices, columnsTrack, layoutStateInPixels]);
|
|
146
|
+
const getGridTemplateRows = useCallback(isPixels => {
|
|
147
|
+
const {
|
|
148
|
+
rowArray
|
|
149
|
+
} = layoutIndices;
|
|
150
|
+
if (isPixels) {
|
|
151
|
+
return rowArray.map(row => `${layoutStateInPixels.rows[row]}px`).join(' ');
|
|
152
|
+
}
|
|
153
|
+
return rowArray.map(row => `${rowsTrack[row]}fr`).join(' ');
|
|
154
|
+
}, [layoutIndices, rowsTrack, layoutStateInPixels]);
|
|
155
|
+
const providerId = useId(id);
|
|
156
|
+
const parentPaneProviderContext = usePaneProviderContext();
|
|
157
|
+
const paneProviderContext = useMemo(() => providerId ? {
|
|
158
|
+
providerId,
|
|
159
|
+
contextData: {
|
|
160
|
+
...parentPaneProviderContext.contextData,
|
|
161
|
+
[providerId]: {
|
|
162
|
+
columnState,
|
|
163
|
+
rowState,
|
|
164
|
+
setRowValue,
|
|
165
|
+
setColumnValue,
|
|
166
|
+
getRowValue,
|
|
167
|
+
getColumnValue,
|
|
168
|
+
totalPanesHeight,
|
|
169
|
+
totalPanesWidth,
|
|
170
|
+
pixelsPerFr
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} : {}, [providerId, parentPaneProviderContext, rowState, columnState, setRowValue, setColumnValue, getRowValue, getColumnValue, totalPanesHeight, totalPanesWidth, pixelsPerFr]);
|
|
174
|
+
return React.createElement(PaneProviderContext.Provider, {
|
|
175
|
+
value: paneProviderContext
|
|
176
|
+
}, children?.({
|
|
177
|
+
id: providerId,
|
|
178
|
+
getRowValue,
|
|
179
|
+
getColumnValue,
|
|
180
|
+
getGridTemplateColumns,
|
|
181
|
+
getGridTemplateRows
|
|
182
|
+
}));
|
|
183
|
+
};
|
|
184
|
+
PaneProvider.displayName = 'PaneProvider';
|
|
185
|
+
PaneProvider.propTypes = {
|
|
186
|
+
id: PropTypes.string,
|
|
187
|
+
totalPanesWidth: PropTypes.number.isRequired,
|
|
188
|
+
totalPanesHeight: PropTypes.number.isRequired,
|
|
189
|
+
defaultRowValues: PropTypes.object,
|
|
190
|
+
defaultColumnValues: PropTypes.object,
|
|
191
|
+
rowValues: PropTypes.object,
|
|
192
|
+
columnValues: PropTypes.object,
|
|
193
|
+
onChange: PropTypes.func,
|
|
194
|
+
children: PropTypes.func
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export { PaneProvider };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React, { forwardRef } from 'react';
|
|
8
|
+
import '../../../styled/StyledCol.js';
|
|
9
|
+
import '../../../styled/StyledGrid.js';
|
|
10
|
+
import '../../../styled/StyledRow.js';
|
|
11
|
+
import '../../../styled/pane/StyledPane.js';
|
|
12
|
+
import { StyledPaneContent } from '../../../styled/pane/StyledPaneContent.js';
|
|
13
|
+
import '../../../styled/pane/StyledPaneSplitter.js';
|
|
14
|
+
import '../../../styled/pane/StyledPaneSplitterButton.js';
|
|
15
|
+
import '../../../styled/pane/StyledPaneSplitterButtonContainer.js';
|
|
16
|
+
import usePaneContext from '../../../utils/usePaneContext.js';
|
|
17
|
+
|
|
18
|
+
const ContentComponent = forwardRef((props, ref) => {
|
|
19
|
+
const {
|
|
20
|
+
isVisible
|
|
21
|
+
} = usePaneContext();
|
|
22
|
+
return React.createElement(StyledPaneContent, Object.assign({
|
|
23
|
+
hidden: !isVisible,
|
|
24
|
+
ref: ref
|
|
25
|
+
}, props));
|
|
26
|
+
});
|
|
27
|
+
ContentComponent.displayName = 'Pane.Content';
|
|
28
|
+
const Content = ContentComponent;
|
|
29
|
+
|
|
30
|
+
export { Content };
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React, { forwardRef, useContext, useRef, useEffect, useMemo } from 'react';
|
|
8
|
+
import { mergeRefs } from 'react-merge-refs';
|
|
9
|
+
import PropTypes from 'prop-types';
|
|
10
|
+
import { ThemeContext } from 'styled-components';
|
|
11
|
+
import { useSplitter } from '@zendeskgarden/container-splitter';
|
|
12
|
+
import { usePaneProviderContextData } from '../../../utils/usePaneProviderContext.js';
|
|
13
|
+
import usePaneContext from '../../../utils/usePaneContext.js';
|
|
14
|
+
import { ORIENTATION } from '../../../types/index.js';
|
|
15
|
+
import '../../../styled/StyledCol.js';
|
|
16
|
+
import '../../../styled/StyledGrid.js';
|
|
17
|
+
import '../../../styled/StyledRow.js';
|
|
18
|
+
import '../../../styled/pane/StyledPane.js';
|
|
19
|
+
import '../../../styled/pane/StyledPaneContent.js';
|
|
20
|
+
import { StyledPaneSplitter } from '../../../styled/pane/StyledPaneSplitter.js';
|
|
21
|
+
import '../../../styled/pane/StyledPaneSplitterButton.js';
|
|
22
|
+
import '../../../styled/pane/StyledPaneSplitterButtonContainer.js';
|
|
23
|
+
import { PaneSplitterContext } from '../../../utils/usePaneSplitterContext.js';
|
|
24
|
+
import { useDocument, useText } from '@zendeskgarden/react-theming';
|
|
25
|
+
|
|
26
|
+
const paneToSplitterOrientation = {
|
|
27
|
+
start: 'vertical',
|
|
28
|
+
end: 'vertical',
|
|
29
|
+
top: 'horizontal',
|
|
30
|
+
bottom: 'horizontal'
|
|
31
|
+
};
|
|
32
|
+
const orientationToDimension = {
|
|
33
|
+
start: 'columns',
|
|
34
|
+
end: 'columns',
|
|
35
|
+
top: 'rows',
|
|
36
|
+
bottom: 'rows'
|
|
37
|
+
};
|
|
38
|
+
const SplitterComponent = forwardRef((_ref, ref) => {
|
|
39
|
+
let {
|
|
40
|
+
children,
|
|
41
|
+
providerId,
|
|
42
|
+
layoutKey,
|
|
43
|
+
min,
|
|
44
|
+
max,
|
|
45
|
+
orientation,
|
|
46
|
+
isFixed,
|
|
47
|
+
onMouseDown,
|
|
48
|
+
onTouchStart,
|
|
49
|
+
onKeyDown,
|
|
50
|
+
onClick,
|
|
51
|
+
...props
|
|
52
|
+
} = _ref;
|
|
53
|
+
const paneProviderContext = usePaneProviderContextData(providerId);
|
|
54
|
+
const paneContext = usePaneContext();
|
|
55
|
+
const themeContext = useContext(ThemeContext);
|
|
56
|
+
const environment = useDocument(themeContext);
|
|
57
|
+
const isRow = orientationToDimension[orientation] === 'rows';
|
|
58
|
+
const separatorRef = useRef(null);
|
|
59
|
+
const splitterOrientation = paneToSplitterOrientation[orientation || 'end'];
|
|
60
|
+
const pixelsPerFr = paneProviderContext ? paneProviderContext.pixelsPerFr[orientationToDimension[orientation]] : 0;
|
|
61
|
+
const value = isRow ? paneProviderContext?.getRowValue(layoutKey, true) : paneProviderContext?.getColumnValue(layoutKey, true);
|
|
62
|
+
const valueInFr = isRow ? paneProviderContext?.getRowValue(layoutKey) : paneProviderContext?.getColumnValue(layoutKey);
|
|
63
|
+
const {
|
|
64
|
+
getSeparatorProps,
|
|
65
|
+
getPrimaryPaneProps
|
|
66
|
+
} = useSplitter({
|
|
67
|
+
orientation: splitterOrientation,
|
|
68
|
+
isLeading: orientation === 'start' || orientation === 'top',
|
|
69
|
+
min: min * pixelsPerFr,
|
|
70
|
+
max: max * pixelsPerFr,
|
|
71
|
+
rtl: themeContext.rtl,
|
|
72
|
+
isFixed,
|
|
73
|
+
environment,
|
|
74
|
+
onChange: valueNow => {
|
|
75
|
+
if (isRow) {
|
|
76
|
+
return paneProviderContext?.setRowValue(orientation === 'top', layoutKey, valueNow / pixelsPerFr);
|
|
77
|
+
}
|
|
78
|
+
return paneProviderContext?.setColumnValue(orientation === 'start', layoutKey, valueNow / pixelsPerFr);
|
|
79
|
+
},
|
|
80
|
+
valueNow: value,
|
|
81
|
+
separatorRef
|
|
82
|
+
});
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (!paneContext.id) {
|
|
85
|
+
paneContext.setId(getPrimaryPaneProps().id);
|
|
86
|
+
}
|
|
87
|
+
}, [paneContext, getPrimaryPaneProps]);
|
|
88
|
+
const ariaLabel = useText(SplitterComponent, props, 'aria-label', `${splitterOrientation} splitter`);
|
|
89
|
+
const separatorProps = getSeparatorProps({
|
|
90
|
+
'aria-controls': paneContext.id,
|
|
91
|
+
'aria-label': ariaLabel,
|
|
92
|
+
onMouseDown,
|
|
93
|
+
onTouchStart,
|
|
94
|
+
onKeyDown,
|
|
95
|
+
onClick
|
|
96
|
+
});
|
|
97
|
+
const size = isRow ? separatorRef.current?.clientWidth : separatorRef.current?.clientHeight;
|
|
98
|
+
return React.createElement(PaneSplitterContext.Provider, {
|
|
99
|
+
value: useMemo(() => ({
|
|
100
|
+
orientation,
|
|
101
|
+
layoutKey,
|
|
102
|
+
min,
|
|
103
|
+
max,
|
|
104
|
+
valueNow: valueInFr,
|
|
105
|
+
size,
|
|
106
|
+
isRow
|
|
107
|
+
}), [orientation, layoutKey, min, max, valueInFr, size, isRow])
|
|
108
|
+
}, React.createElement(StyledPaneSplitter, Object.assign({
|
|
109
|
+
isFixed: isFixed,
|
|
110
|
+
orientation: orientation
|
|
111
|
+
}, separatorProps, props, {
|
|
112
|
+
ref: mergeRefs([separatorRef, ref])
|
|
113
|
+
})), children );
|
|
114
|
+
});
|
|
115
|
+
SplitterComponent.displayName = 'Pane.Splitter';
|
|
116
|
+
SplitterComponent.propTypes = {
|
|
117
|
+
layoutKey: PropTypes.string.isRequired,
|
|
118
|
+
min: PropTypes.number.isRequired,
|
|
119
|
+
max: PropTypes.number.isRequired,
|
|
120
|
+
orientation: PropTypes.oneOf(ORIENTATION),
|
|
121
|
+
isFixed: PropTypes.bool
|
|
122
|
+
};
|
|
123
|
+
SplitterComponent.defaultProps = {
|
|
124
|
+
orientation: 'end'
|
|
125
|
+
};
|
|
126
|
+
const Splitter = SplitterComponent;
|
|
127
|
+
|
|
128
|
+
export { Splitter };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Zendesk, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed under the Apache License, Version 2.0
|
|
5
|
+
* found at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
*/
|
|
7
|
+
import React, { forwardRef, useCallback } from 'react';
|
|
8
|
+
import { Tooltip } from '@zendeskgarden/react-tooltips';
|
|
9
|
+
import { composeEventHandlers } from '@zendeskgarden/container-utilities';
|
|
10
|
+
import '../../../styled/StyledCol.js';
|
|
11
|
+
import '../../../styled/StyledGrid.js';
|
|
12
|
+
import '../../../styled/StyledRow.js';
|
|
13
|
+
import '../../../styled/pane/StyledPane.js';
|
|
14
|
+
import '../../../styled/pane/StyledPaneContent.js';
|
|
15
|
+
import '../../../styled/pane/StyledPaneSplitter.js';
|
|
16
|
+
import { StyledPaneSplitterButton } from '../../../styled/pane/StyledPaneSplitterButton.js';
|
|
17
|
+
import { StyledPaneSplitterButtonContainer } from '../../../styled/pane/StyledPaneSplitterButtonContainer.js';
|
|
18
|
+
import usePaneSplitterContext from '../../../utils/usePaneSplitterContext.js';
|
|
19
|
+
import { usePaneProviderContextData } from '../../../utils/usePaneProviderContext.js';
|
|
20
|
+
|
|
21
|
+
const SplitterButtonComponent = forwardRef((props, ref) => {
|
|
22
|
+
const {
|
|
23
|
+
label,
|
|
24
|
+
placement: defaultPlacement
|
|
25
|
+
} = props;
|
|
26
|
+
const {
|
|
27
|
+
orientation,
|
|
28
|
+
layoutKey,
|
|
29
|
+
min,
|
|
30
|
+
max,
|
|
31
|
+
isRow,
|
|
32
|
+
valueNow,
|
|
33
|
+
size,
|
|
34
|
+
providerId
|
|
35
|
+
} = usePaneSplitterContext();
|
|
36
|
+
const paneProviderContext = usePaneProviderContextData(providerId);
|
|
37
|
+
const isTop = orientation === 'top';
|
|
38
|
+
const isStart = orientation === 'start';
|
|
39
|
+
const isMin = valueNow === min;
|
|
40
|
+
let placement = defaultPlacement;
|
|
41
|
+
if (!defaultPlacement) {
|
|
42
|
+
if (isRow) {
|
|
43
|
+
placement = 'center';
|
|
44
|
+
} else {
|
|
45
|
+
placement = 'start';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const setValue = useCallback(value => {
|
|
49
|
+
if (isRow) {
|
|
50
|
+
paneProviderContext.setRowValue(isTop, layoutKey, value);
|
|
51
|
+
} else {
|
|
52
|
+
paneProviderContext.setColumnValue(isStart, layoutKey, value);
|
|
53
|
+
}
|
|
54
|
+
}, [isRow, isTop, isStart, layoutKey, paneProviderContext]);
|
|
55
|
+
const onClick = composeEventHandlers(props.onClick, () => {
|
|
56
|
+
if (isMin) {
|
|
57
|
+
setValue(max);
|
|
58
|
+
} else {
|
|
59
|
+
setValue(min);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const onKeyDown = composeEventHandlers(props.onKeyDown, event => event.stopPropagation()
|
|
63
|
+
);
|
|
64
|
+
const onMouseDown = composeEventHandlers(props.onMouseDown, event => event.stopPropagation()
|
|
65
|
+
);
|
|
66
|
+
return React.createElement(StyledPaneSplitterButtonContainer, {
|
|
67
|
+
orientation: orientation,
|
|
68
|
+
placement: placement,
|
|
69
|
+
splitterSize: size || 0
|
|
70
|
+
}, React.createElement(Tooltip, {
|
|
71
|
+
content: label,
|
|
72
|
+
zIndex: 2,
|
|
73
|
+
style: {
|
|
74
|
+
cursor: 'default'
|
|
75
|
+
},
|
|
76
|
+
onMouseDown: e => e.stopPropagation()
|
|
77
|
+
}, React.createElement(StyledPaneSplitterButton, Object.assign({
|
|
78
|
+
"aria-label": label
|
|
79
|
+
}, props, {
|
|
80
|
+
orientation: orientation,
|
|
81
|
+
isRotated: isMin,
|
|
82
|
+
ref: ref,
|
|
83
|
+
onClick: onClick,
|
|
84
|
+
onKeyDown: onKeyDown,
|
|
85
|
+
onMouseDown: onMouseDown
|
|
86
|
+
}))));
|
|
87
|
+
});
|
|
88
|
+
SplitterButtonComponent.displayName = 'Pane.SplitterButton';
|
|
89
|
+
const SplitterButton = SplitterButtonComponent;
|
|
90
|
+
|
|
91
|
+
export { SplitterButton };
|