Skip to content
This repository was archived by the owner on Jun 29, 2021. It is now read-only.

Commit 7c9eddc

Browse files
committed
Improvements to layout
- Makes nav optionally draggable - Adds roles for main components - adds dragged to the hook so components can respond to being dragged - Add tests - Simplifies util functions and Root
1 parent 249b3ab commit 7c9eddc

26 files changed

+1331
-644
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports = {
1414
'prettier/@typescript-eslint',
1515

1616
'plugin:react/recommended',
17+
"plugin:react-hooks/recommended",
1718
'plugin:security/recommended',
1819
// remove rules covered by prettier
1920
'prettier/@typescript-eslint',

example/index.tsx

Lines changed: 248 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Footer,
1111
LayoutConfig,
1212
useLayout,
13+
LAYOUT_CONFIG_DEFAULTS,
1314
} from '../dist'
1415
import {
1516
ThemeProvider,
@@ -20,6 +21,12 @@ import {
2021
List,
2122
Container,
2223
ThemeSwitch,
24+
FormGroup,
25+
FormControlLabel,
26+
Switch,
27+
CheckToken,
28+
Slider,
29+
Divider,
2330
} from '@committed/components'
2431
import AccountCircle from '@material-ui/icons/AccountCircle'
2532
import { LoremIpsum } from 'lorem-ipsum'
@@ -35,95 +42,253 @@ const lorem = new LoremIpsum({
3542
},
3643
})
3744

38-
const config: Partial<LayoutConfig> = {
39-
navVariant: {
40-
sm: 'temporary',
41-
md: 'persistent',
42-
lg: 'permanent',
43-
},
44-
headerPosition: {
45-
sm: 'relative',
46-
md: 'sticky',
47-
},
48-
collapsible: {
49-
md: true,
50-
lg: false,
51-
},
52-
headerResponse: {
53-
sm: 'static',
54-
md: 'squeezed',
55-
},
56-
contentResponse: {
57-
sm: 'static',
58-
md: 'squeezed',
59-
},
60-
footerResponse: {
61-
sm: 'static',
62-
md: 'squeezed',
63-
},
64-
navAnchor: 'right',
65-
}
45+
const text = lorem.generateParagraphs(1)
46+
6647
const Layout = () => {
6748
const layout = useLayout()
6849
return <Monospace>{JSON.stringify(layout, null, 2)}</Monospace>
6950
}
7051

71-
const App = () => (
72-
<ThemeProvider>
73-
<Root config={config}>
74-
<Header>
75-
<Typography variant="h5">Application Name</Typography>
76-
<Box flexGrow={1} />
77-
<IconButton color="inherit">
78-
<AccountCircle />
79-
</IconButton>
80-
<ThemeSwitch />
81-
</Header>
82-
<Nav draggable>
83-
<List>
84-
<NavListItem
85-
key="item1"
86-
text="Menu Item 1"
87-
icon={<AccountCircle />}
88-
/>
89-
<NavListItem
90-
key="item2"
91-
text="Menu Item 2"
92-
icon={<AccountCircle />}
93-
/>
94-
<NavListItem
95-
key="item3"
96-
text="Menu Item 3"
97-
icon={<AccountCircle />}
98-
/>
99-
</List>
100-
</Nav>
101-
<Content>
102-
<Container maxWidth="lg">
103-
<Box pt={2}>
104-
<Box mb={2}>
105-
<Typography variant="h4">@committed/layout</Typography>
106-
</Box>
107-
<Layout />
108-
<Box mt={3}>
109-
{new Array(20).fill(null).map((i) => (
110-
<Box mb={1}>
111-
<Typography variant="body2" color="textSecondary">
112-
{lorem.generateParagraphs(1)}
113-
</Typography>
114-
</Box>
115-
))}
52+
interface SelectorProps {
53+
label: string
54+
value: string
55+
setValue: (newValue: string) => void
56+
values: string[]
57+
}
58+
59+
const Selector = ({ label, value, setValue, values }: SelectorProps) => (
60+
<>
61+
<Typography mt={3}>{label}</Typography>
62+
{values.map((key) => (
63+
<CheckToken
64+
color="primary"
65+
selected={value === key}
66+
onClick={() => setValue(key)}
67+
>
68+
{key}
69+
</CheckToken>
70+
))}
71+
<Divider mx={2} />
72+
</>
73+
)
74+
75+
interface NavWidthProps {
76+
setConfigNavWidth: (newValue: number) => void
77+
}
78+
79+
const NavWidth = ({ setConfigNavWidth }) => {
80+
const [hasDragged, setHasDragged] = React.useState(false)
81+
const {
82+
navWidth,
83+
dragged,
84+
setNavWidth,
85+
maxNavWidth,
86+
collapsedWidth,
87+
} = useLayout()
88+
89+
React.useEffect(() => {
90+
if (dragged) setHasDragged(true)
91+
}, [dragged])
92+
93+
const handleChange = (e: any, value: number) => {
94+
if (hasDragged) {
95+
setNavWidth(value)
96+
} else {
97+
setConfigNavWidth(value)
98+
}
99+
}
100+
return (
101+
<Slider
102+
value={navWidth}
103+
onChange={handleChange}
104+
valueLabelDisplay="auto"
105+
min={collapsedWidth}
106+
max={maxNavWidth}
107+
/>
108+
)
109+
}
110+
111+
const App = () => {
112+
const [draggable, setDraggable] = React.useState(false)
113+
114+
const [collapsible, setCollapsible] = React.useState(
115+
LAYOUT_CONFIG_DEFAULTS.collapsible
116+
)
117+
const [collapsedWidth, setCollapsedWidth] = React.useState(
118+
LAYOUT_CONFIG_DEFAULTS.collapsedWidth
119+
)
120+
const [navAnchor, setNavAnchor] = React.useState(
121+
LAYOUT_CONFIG_DEFAULTS.navAnchor
122+
)
123+
const [navVariant, setNavVariant] = React.useState(
124+
LAYOUT_CONFIG_DEFAULTS.navVariant
125+
)
126+
const [navWidth, setNavWidth] = React.useState(
127+
LAYOUT_CONFIG_DEFAULTS.navWidth
128+
)
129+
const [maxNavWidth, setMaxNavWidth] = React.useState(
130+
LAYOUT_CONFIG_DEFAULTS.maxNavWidth
131+
)
132+
const [headerPosition, setHeaderPosition] = React.useState(
133+
LAYOUT_CONFIG_DEFAULTS.headerPosition
134+
)
135+
const [headerResponse, setHeaderResponse] = React.useState(
136+
LAYOUT_CONFIG_DEFAULTS.headerResponse
137+
)
138+
const [contentResponse, setContentResponse] = React.useState(
139+
LAYOUT_CONFIG_DEFAULTS.contentResponse
140+
)
141+
const [footerResponse, setFooterResponse] = React.useState(
142+
LAYOUT_CONFIG_DEFAULTS.footerResponse
143+
)
144+
145+
const config = {
146+
collapsible,
147+
collapsedWidth,
148+
draggable,
149+
navAnchor,
150+
navVariant,
151+
navWidth,
152+
maxNavWidth,
153+
headerPosition,
154+
headerResponse,
155+
contentResponse,
156+
footerResponse,
157+
}
158+
159+
return (
160+
<ThemeProvider>
161+
<Root config={config}>
162+
<Header>
163+
<Typography variant="h5">Application Name</Typography>
164+
<Box flexGrow={1} />
165+
<IconButton color="inherit">
166+
<AccountCircle />
167+
</IconButton>
168+
<ThemeSwitch />
169+
</Header>
170+
<Nav>
171+
<List>
172+
<NavListItem
173+
key="item1"
174+
text="Menu Item 1"
175+
icon={<AccountCircle />}
176+
/>
177+
<NavListItem
178+
key="item2"
179+
text="Menu Item 2"
180+
icon={<AccountCircle />}
181+
/>
182+
<NavListItem
183+
key="item3"
184+
text="Menu Item 3"
185+
icon={<AccountCircle />}
186+
/>
187+
</List>
188+
</Nav>
189+
<Content>
190+
<Container maxWidth="lg">
191+
<Box pt={2}>
192+
<Box mb={2}>
193+
<Typography variant="h4">@committed/layout</Typography>
194+
</Box>
195+
<Layout />
196+
<FormGroup row>
197+
<FormControlLabel
198+
control={
199+
<Switch
200+
checked={draggable}
201+
onChange={() => setDraggable(!draggable)}
202+
color="primary"
203+
/>
204+
}
205+
label="Draggable"
206+
/>
207+
<FormControlLabel
208+
control={
209+
<Switch
210+
checked={collapsible}
211+
onChange={() => setCollapsible(!collapsible)}
212+
color="secondary"
213+
/>
214+
}
215+
label="Collapsible"
216+
/>
217+
</FormGroup>
218+
<Typography>Collapsed Width</Typography>
219+
<Slider
220+
value={collapsedWidth}
221+
onChange={(_e, value) => setCollapsedWidth(value)}
222+
valueLabelDisplay="auto"
223+
min={32}
224+
max={128}
225+
/>
226+
<Typography>Nav width</Typography>
227+
<NavWidth setConfigNavWidth={setNavWidth} />
228+
<Typography>Max Nav width</Typography>
229+
<Slider
230+
value={maxNavWidth}
231+
onChange={(_e, value) => setMaxNavWidth(value)}
232+
valueLabelDisplay="auto"
233+
min={64}
234+
max={2024}
235+
/>
236+
<Selector
237+
label="NavVariant"
238+
value={navVariant}
239+
setValue={setNavVariant}
240+
values={['permanent', 'persistent', 'temporary']}
241+
/>
242+
<Selector
243+
label="NavAnchor"
244+
value={navAnchor}
245+
setValue={setNavAnchor}
246+
values={['left', 'right']}
247+
/>
248+
<Selector
249+
label="HeaderPosition"
250+
value={headerPosition}
251+
setValue={setHeaderPosition}
252+
values={['static', 'relative', 'sticky', 'fixed', 'absolute']}
253+
/>
254+
<Selector
255+
label="HeaderResponse"
256+
value={headerResponse}
257+
setValue={setHeaderResponse}
258+
values={['static', 'squeezed', 'pushed', 'clipped']}
259+
/>
260+
<Selector
261+
label="ContentResponse"
262+
value={contentResponse}
263+
setValue={setContentResponse}
264+
values={['static', 'squeezed', 'pushed']}
265+
/>
266+
<Selector
267+
label="FooterResponse"
268+
value={footerResponse}
269+
setValue={setFooterResponse}
270+
values={['static', 'squeezed', 'pushed']}
271+
/>
272+
<Box mt={3}>
273+
{new Array(20).fill(null).map((i) => (
274+
<Box mb={1}>
275+
<Typography variant="body2" color="textSecondary">
276+
{text}
277+
</Typography>
278+
</Box>
279+
))}
280+
</Box>
116281
</Box>
282+
</Container>
283+
</Content>
284+
<Footer>
285+
<Box p={2}>
286+
<Typography>Footer</Typography>
117287
</Box>
118-
</Container>
119-
</Content>
120-
<Footer>
121-
<Box p={2}>
122-
<Typography>Footer</Typography>
123-
</Box>
124-
</Footer>
125-
</Root>
126-
</ThemeProvider>
127-
)
288+
</Footer>
289+
</Root>
290+
</ThemeProvider>
291+
)
292+
}
128293

129294
ReactDOM.render(<App />, document.getElementById('root'))

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@committed/layout",
3-
"version": "4.1.1",
3+
"version": "4.2.0",
44
"description": "Committed layout library",
55
"author": "Committed",
66
"license": "MIT",
@@ -31,11 +31,11 @@
3131
"deploy-storybook": "storybook-to-ghpages"
3232
},
3333
"peerDependencies": {
34-
"react": ">=16",
35-
"react-dom": ">=16",
3634
"@committed/components": ">=4.0.0",
3735
"@material-ui/core": "^4.9.10",
38-
"@material-ui/icons": "^4.9.1"
36+
"@material-ui/icons": "^4.9.1",
37+
"react": ">=16",
38+
"react-dom": ">=16"
3939
},
4040
"husky": {
4141
"hooks": {
@@ -88,6 +88,7 @@
8888
"babel-loader": "^8.1.0",
8989
"eslint-config-prettier": "^7.0.0",
9090
"eslint-plugin-prettier": "^3.2.0",
91+
"eslint-plugin-react-hooks": "^4.2.0",
9192
"eslint-plugin-security": "^1.4.0",
9293
"husky": "^4.2.5",
9394
"jest-sonar-reporter": "^2.0.0",

0 commit comments

Comments
 (0)