Skip to content
This repository was archived by the owner on Jan 14, 2025. It is now read-only.

Commit 84b6395

Browse files
mgr34Matt Goo
authored and
Matt Goo
committed
feat(top-app-bar): add children components for composition
1 parent 66d36b6 commit 84b6395

32 files changed

+1234
-254
lines changed

packages/top-app-bar/Icon.tsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// The MIT License
2+
//
3+
// Copyright (c) 2019 Google, Inc.
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
// THE SOFTWARE.
22+
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
25+
import {cssClasses} from './constants';
26+
27+
28+
export interface IconProps<T> extends React.HTMLProps<T> {
29+
actionItem?: boolean;
30+
className?: string;
31+
children: React.ReactElement<any>;
32+
navIcon?: boolean;
33+
}
34+
35+
36+
const Icon: <T extends Element = HTMLElement>(props: IconProps<T> ) =>
37+
React.ReactElement<HTMLElement> = ({
38+
/* eslint-disable react/prop-types */
39+
actionItem = false,
40+
navIcon = false,
41+
className,
42+
children,
43+
...otherProps
44+
/* eslint-enable react/prop-types */
45+
}) =>
46+
React.cloneElement(children, {
47+
...otherProps,
48+
className: classnames(className, children.props.className, {
49+
[cssClasses.ACTION_ITEM]: actionItem,
50+
[cssClasses.NAV_ICON]: navIcon,
51+
}),
52+
});
53+
54+
export default Icon;

packages/top-app-bar/README.md

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,38 @@ import '@material/react-material-icon/dist/material-icon.css';
2626

2727
### Javascript Instantiation
2828
```js
29-
import TopAppBar, {TopAppBarFixedAdjust} from '@material/react-top-app-bar';
29+
import TopAppBar, {
30+
TopAppBarFixedAdjust,
31+
TopAppBarIcon,
32+
TopAppBarRow,
33+
TopAppBarSection,
34+
TopAppBarTitle,
35+
} from '@material/react-top-app-bar';
3036
import MaterialIcon from '@material/react-material-icon';
3137

3238
const MyComponent = () => {
3339
return (
3440
<div>
35-
<TopAppBar
36-
title='Miami, FL'
37-
navigationIcon={<MaterialIcon
38-
icon='menu'
39-
onClick={() => console.log('click')}
40-
/>}
41-
actionItems={[<MaterialIcon key='item' icon='bookmark' />]}
42-
/>
41+
<TopAppBar>
42+
<TopAppBarRow>
43+
<TopAppBarSection align='start'>
44+
<TopAppBarIcon navIcon tabIndex={0}>
45+
<MaterialIcon hasRipple icon='menu' onClick={() => console.log('click')}/>
46+
</TopAppBarIcon>
47+
<TopAppBarTitle>Miami, FL</TopAppBarTitle>
48+
</TopAppBarSection>
49+
<TopAppBarSection align='end' role='toolbar'>
50+
<TopAppBarIcon actionItem tabIndex={0}>
51+
<MaterialIcon
52+
aria-label="print page"
53+
hasRipple
54+
icon='print'
55+
onClick={() => console.log('print')}
56+
/>
57+
</TopAppBarIcon>
58+
</TopAppBarSection>
59+
</TopAppBarRow>
60+
</TopAppBar>
4361
<TopAppBarFixedAdjust>
4462
My exciting content!
4563
</TopAppBarFixedAdjust>
@@ -56,17 +74,55 @@ Use the `<TopAppBarFixedAdjust />` component to give your content top-padding, s
5674

5775
Prop Name | Type | Description
5876
--- | --- | ---
59-
actionItems | Array | Accepts an array of elements that should be rendered to the opposite side of the title. Note that a single action item should also be passed as an array.
6077
className | String | Classes to be applied to the root element.
61-
title | String | The title of the Top App Bar.
62-
navigationIcon | Element | Appears adjacent to the title. This acts as the main action of the Top App Bar.
6378
short | Boolean | Enables short variant.
6479
shortCollapsed | Boolean | Enables short collapsed variant.
6580
prominent | Boolean | Enables prominent variant.
6681
fixed | Boolean | Enables fixed variant.
6782
dense | Boolean | Enables dense variant.
83+
scrollTarget | React.RefObject | Sets scroll target to different DOM node (default is `window`)
84+
tag | String | Customizes the `TopAppBar` HTML tag. (default: `<header>`)
85+
> NOTES: As per design guidelines, prominent and dense variants should not be used with short or short collapsed. Additionally, dense variants should only be used on desktop. Additionally short top-app-bars should be used with no more than 1 action item.
86+
87+
#### Deprecated TopAppBar Props
88+
89+
The following props are deprecated since v0.11.0 and are scheduled for removal in v0.13.0.
90+
They will still render as expected until v0.13.0, but will output a warning to the console.
91+
92+
Prop Name | Type | Description
93+
--- | --- | ---
94+
actionItems | Array | Accepts an array of elements that should be rendered to the opposite side of the title. Note that a single action item should also be passed as an array.
95+
navigationIcon | Element | Appears adjacent to the title. This acts as the main action of the Top App Bar.
96+
title | String | The Title of the Top App Bar.
97+
98+
### TopAppBarRow
99+
Prop Name | Type | Description
100+
--- | --- | ---
101+
className | String | Classes to be applied to the root element.
102+
tag | String | Customizes the `TopAppBarRow` tag. (default: `<div>`)
103+
104+
### TopAppBarSection
105+
Prop Name | Type | Description
106+
--- | --- | ---
107+
align | Sring ('start' or 'end') | optional property tha aligns section content to either start or end of section
108+
className | String | Classes to be applied to the root element.
109+
tag | String | Customizes the `TopAppBarSection` tag. (default: `<section>`)
110+
> Note: if section contains action items it is reccomended to add property role='toolbar' for a11y purposes
111+
112+
### TopAppBarTitle
113+
Prop Name | Type | Description
114+
--- | --- | ---
115+
className | String | Classes to be applied to the root element.
116+
tag | String | Customizes the `TopAppBarTitle` tag. (default: `<span>`)
68117

69-
> NOTES: As per design guidelines, prominent and dense variants should not be used with short or short collapsed. Additionally, dense variants should only be used on desktop.
118+
### TopAppBarIcon
119+
Prop Name | Type | Description
120+
--- | --- | ---
121+
className | String | Classes to be applied to the root element.
122+
actionItem | Boolean | applies action-item class to icon
123+
navIcon | Boolean | applies nav-icon class to icon
124+
children | React.ReactElement<any> | can be any icon. Material Icons are reccomended
125+
> Notes: (1) consider adding `aria-label` to actionItem's. (2) you may need to manually add ripple or tabindex to icon. (3) Short top-app-bars shold be used with no more than 1 action item.
70126
71127
### TopAppBarFixedAdjust
72128

@@ -89,8 +145,9 @@ Use of [Material Icon's](../material-icon/README.md) for Action Items and Naviga
89145
The navigation icon can be a `<a>`, `<i>`, `<svg>`, `<image>`, `<span>`, etc., but again must be wrapped with the `withRipple HOC`.
90146

91147
```js
92-
<TopAppBar
93-
navigationIcon={<i className='material-icons'>menu</i>} />
148+
<TopAppBarIcon navIcon>
149+
<i className='material-icons'>menu</i>
150+
</TopAppBarIcon>
94151
```
95152

96153
If you decide to use a React Component please see [Integrating with Components](./../../docs/guidelines.md#integrating-with-components).
@@ -100,13 +157,13 @@ If you decide to use a React Component please see [Integrating with Components](
100157
Similar to the [navigation icon](#navigation-icon), it can be `<a>`, `<i>`, `<svg>`, `<image>`, `<span>`, etc., and must be wrapped with the `withRipple HOC`.
101158

102159
```js
103-
<TopAppBar
104-
actionItems={[<i className='material-icons'>bookmark</i>]} />
160+
<TopAppBarIcon actionItem>
161+
<i className='material-icons'>bookmark</i
162+
</TopAppBarIcon>
105163
```
106164

107165
If you decide to use a React Component please see [Integrating with Components](./../../docs/guidelines.md#integrating-with-components).
108166

109-
> NOTE: `actionItems` prop is expecting an array of elements.
110167

111168
## Sass Mixins
112169

packages/top-app-bar/Row.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// The MIT License
2+
//
3+
// Copyright (c) 2019 Google, Inc.
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
// THE SOFTWARE.
22+
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
25+
import {cssClasses} from './constants';
26+
27+
export interface RowProps<T> extends React.HTMLProps<T> {
28+
className?: string;
29+
tag?: string;
30+
};
31+
32+
const Row: <T extends HTMLElement = HTMLDivElement>(props: RowProps<T>) =>
33+
React.ReactElement<T> = ({
34+
/* eslint-disable react/prop-types */
35+
children,
36+
className,
37+
tag: Tag = 'div',
38+
...otherProps
39+
/* eslint-enable react/prop-types */
40+
}) => (
41+
// @ts-ignore https://github.com/Microsoft/TypeScript/issues/28892
42+
<Tag className={classnames(className, cssClasses.ROW)} {...otherProps}>
43+
{children}
44+
</Tag>
45+
);
46+
47+
export default Row;

packages/top-app-bar/Section.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// The MIT License
2+
//
3+
// Copyright (c) 2019 Google, Inc.
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
// THE SOFTWARE.
22+
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
25+
import {cssClasses} from './constants';
26+
27+
export interface SectionProps<T> extends React.HTMLProps<T> {
28+
align?: 'start' | 'end';
29+
className?: string;
30+
tag?: string;
31+
};
32+
33+
const Section: <T extends HTMLElement = HTMLElement>(props: SectionProps<T>) =>
34+
React.ReactElement<T> = ({
35+
/* eslint-disable react/prop-types */
36+
align,
37+
className,
38+
children,
39+
tag: Tag = 'section',
40+
...otherProps
41+
/* eslint-enable react/prop-types */
42+
}) => (
43+
// @ts-ignore https://github.com/Microsoft/TypeScript/issues/28892
44+
<Tag
45+
className={classnames(className, cssClasses.SECTION, {
46+
[cssClasses.SECTION_START]: align === 'start',
47+
[cssClasses.SECTION_END]: align === 'end',
48+
})}
49+
{...otherProps}
50+
>
51+
{children}
52+
</Tag>
53+
);
54+
55+
export default Section;

packages/top-app-bar/Title.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// The MIT License
2+
//
3+
// Copyright (c) 2019 Google, Inc.
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
// THE SOFTWARE.
22+
23+
import * as React from 'react';
24+
import * as classnames from 'classnames';
25+
import {cssClasses} from './constants';
26+
27+
export interface TitleProps<T> extends React.HTMLProps<T> {
28+
className?: string;
29+
tag?: string;
30+
};
31+
32+
const Title: <T extends HTMLElement = HTMLSpanElement>(props: TitleProps<T>) =>
33+
React.ReactElement<T> = ({
34+
/* eslint-disable react/prop-types */
35+
children,
36+
className,
37+
tag: Tag = 'span',
38+
...otherProps
39+
/* eslint-enable react/prop-types */
40+
}) => (
41+
// @ts-ignore https://github.com/Microsoft/TypeScript/issues/28892
42+
<Tag className={classnames(className, cssClasses.TITLE)} {...otherProps} >
43+
{children}
44+
</Tag>
45+
);
46+
47+
export default Title;

packages/top-app-bar/constants.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// The MIT License
2+
//
3+
// Copyright (c) 2019 Google, Inc.
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in
13+
// all copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
const BASE = 'mdc-top-app-bar';
22+
const SECTION = `${BASE}__section`;
23+
const cssClasses = {
24+
BASE,
25+
ROW: `${BASE}__row`,
26+
SECTION,
27+
SECTION_START: `${SECTION}--align-start`,
28+
SECTION_END: `${SECTION}--align-end`,
29+
FIXED: `${BASE}--fixed`,
30+
SHORT: `${BASE}--short`,
31+
SHORT_COLLAPSED: `${BASE}--short-collapsed`,
32+
PROMINENT: `${BASE}--prominent`,
33+
DENSE: `${BASE}--dense`,
34+
TITLE: `${BASE}__title`,
35+
ACTION_ITEM: `${BASE}__action-item`,
36+
NAV_ICON: `${BASE}__navigation-icon`,
37+
};
38+
39+
export {cssClasses};

0 commit comments

Comments
 (0)