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

Commit 14b22bc

Browse files
author
Matt Goo
committed
feat(select): enhanced select (#823)
1 parent b400013 commit 14b22bc

27 files changed

+1704
-571
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@
148148
"testdouble": "^3.6.0",
149149
"ts-loader": "^3.5.0",
150150
"ts-node": "^7.0.1",
151-
"typescript": "^3.2.2",
151+
"typescript": "^3.3.3",
152152
"typescript-eslint-parser": "^21.0.1",
153153
"utility-types": "^2.1.0",
154154
"uuid": "^3.3.2",

packages/list/index.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,6 @@ export default class List extends React.Component<ListProps, ListState> {
185185
return [];
186186
}
187187

188-
// this is a proxy for ListItem
189-
getListElements = () => {
190-
return this.listElements;
191-
}
192-
193188
get classes() {
194189
const {
195190
className,

packages/menu-surface/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export interface MenuSurfaceProps extends React.HTMLProps<HTMLDivElement> {
4444
};
4545
onClose?: () => void;
4646
onOpen?: () => void;
47+
onMount?: (isMounted: boolean) => void;
4748
quickOpen?: boolean;
4849
open?: boolean;
4950
fixed?: boolean;
@@ -148,6 +149,9 @@ class MenuSurface extends React.Component<MenuSurfaceProps, MenuSurfaceState> {
148149
if (this.props.quickOpen !== prevProps.quickOpen) {
149150
this.foundation.setQuickOpen(this.props.quickOpen!);
150151
}
152+
if (this.state.mounted !== prevState.mounted) {
153+
this.props.onMount && this.props.onMount(this.state.mounted);
154+
}
151155
}
152156

153157
componentWillUnmount() {
@@ -344,6 +348,7 @@ class MenuSurface extends React.Component<MenuSurfaceProps, MenuSurfaceState> {
344348
onKeyDown,
345349
styles,
346350
quickOpen,
351+
onMount,
347352
/* eslint-enable */
348353
children,
349354
...otherProps

packages/menu/index.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const {cssClasses} = MDCMenuFoundation;
3333
export interface MenuProps extends MenuSurfaceProps {
3434
children: React.ReactElement<MenuList>;
3535
onSelected?: (index: number, item: Element) => void;
36+
ref?: React.Ref<any>;
3637
};
3738

3839
export interface MenuState {
@@ -130,12 +131,7 @@ class Menu extends React.Component<MenuProps, MenuState> {
130131

131132
handleOpen: MenuSurfaceProps['onOpen'] = () => {
132133
const {onOpen} = this.props;
133-
if (onOpen) {
134-
onOpen();
135-
}
136-
if (this.listElements.length > 0) {
137-
(this.listElements[0] as HTMLElement).focus();
138-
}
134+
onOpen && onOpen();
139135
}
140136

141137
render() {
@@ -147,11 +143,9 @@ class Menu extends React.Component<MenuProps, MenuState> {
147143
onOpen,
148144
children,
149145
onSelected,
150-
ref,
151146
/* eslint-enable no-unused-vars */
152147
...otherProps
153148
} = this.props;
154-
155149
return (
156150
<MenuSurface
157151
tabIndex={-1}
@@ -166,7 +160,6 @@ class Menu extends React.Component<MenuProps, MenuState> {
166160
);
167161
}
168162

169-
170163
renderChild() {
171164
const {children} = this.props;
172165
const {foundation} = this.state;
@@ -194,8 +187,8 @@ export {
194187
ListDivider as MenuListDivider,
195188
ListGroup as MenuListGroup,
196189
ListGroupSubheader as MenuListGroupSubheader,
197-
ListItemGraphic as MenuListGraphic,
198-
ListItemMeta as MenuListMeta,
190+
ListItemGraphic as MenuListItemGraphic,
191+
ListItemMeta as MenuListItemMeta,
199192
ListItemText as MenuListItemText,
200193
} from '@material/react-list';
201194
export {MenuListProps} from './MenuList';

packages/select/BaseSelect.tsx

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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 NativeSelect, {
25+
NativeSelectProps, // eslint-disable-line no-unused-vars
26+
} from './NativeSelect';
27+
import EnhancedSelect, {
28+
EnhancedSelectProps, // eslint-disable-line no-unused-vars
29+
} from './EnhancedSelect';
30+
import {MDCSelectFoundation} from '@material/select/foundation';
31+
32+
export type BaseSelectProps<T extends HTMLElement>
33+
= (T extends HTMLSelectElement ? NativeSelectProps : EnhancedSelectProps);
34+
35+
export interface CommonSelectProps {
36+
enhanced: boolean;
37+
className?: string;
38+
disabled?: boolean;
39+
foundation?: MDCSelectFoundation;
40+
value?: string;
41+
selectClassName?: string;
42+
}
43+
44+
export class BaseSelect<T extends HTMLElement = HTMLSelectElement>
45+
extends React.Component<BaseSelectProps<T>> {
46+
static defaultProps = {
47+
enhanced: false,
48+
selectClassName: '',
49+
};
50+
51+
handleFocus = (evt: React.FocusEvent<T>) => {
52+
const {foundation, onFocus} = this.props;
53+
if (foundation) {
54+
foundation.handleFocus();
55+
}
56+
onFocus && onFocus(evt);
57+
};
58+
59+
handleBlur = (evt: React.FocusEvent<T>) => {
60+
const {foundation, onBlur} = this.props;
61+
if (foundation) {
62+
foundation.handleBlur();
63+
}
64+
onBlur && onBlur(evt);
65+
};
66+
67+
handleTouchStart = (evt: React.TouchEvent<T>) => {
68+
const {foundation, onTouchStart} = this.props;
69+
if (foundation) {
70+
foundation.handleClick(this.getNormalizedXCoordinate(evt));
71+
}
72+
onTouchStart && onTouchStart(evt);
73+
}
74+
75+
handleMouseDown = (evt: React.MouseEvent<T>) => {
76+
const {foundation, onMouseDown} = this.props;
77+
if (foundation) {
78+
foundation.handleClick(this.getNormalizedXCoordinate(evt));
79+
}
80+
onMouseDown && onMouseDown(evt);
81+
}
82+
83+
handleClick = (evt: React.MouseEvent<T>) => {
84+
const {foundation, onClick} = this.props;
85+
if (foundation) {
86+
foundation.handleClick(this.getNormalizedXCoordinate(evt));
87+
}
88+
onClick && onClick(evt);
89+
}
90+
91+
handleKeyDown = (evt: React.KeyboardEvent<T>) => {
92+
const {foundation, onKeyDown} = this.props;
93+
if (foundation) {
94+
foundation.handleKeydown(evt.nativeEvent);
95+
}
96+
onKeyDown && onKeyDown(evt);
97+
}
98+
99+
private isTouchEvent = (evt: MouseEvent | TouchEvent): evt is TouchEvent => {
100+
return Boolean((evt as TouchEvent).touches);
101+
}
102+
103+
private getNormalizedXCoordinate
104+
= (evt: React.MouseEvent<T> | React.TouchEvent<T>) => {
105+
const targetClientRect = (evt.currentTarget as Element).getBoundingClientRect();
106+
const xCoordinate
107+
= this.isTouchEvent(evt.nativeEvent) ? evt.nativeEvent.touches[0].clientX : evt.nativeEvent.clientX;
108+
return xCoordinate - targetClientRect.left;
109+
}
110+
111+
112+
render() {
113+
const {
114+
/* eslint-disable no-unused-vars */
115+
onFocus,
116+
onBlur,
117+
onClick,
118+
onMouseDown,
119+
onTouchStart,
120+
ref,
121+
/* eslint-enable no-unused-vars */
122+
enhanced,
123+
children,
124+
onKeyDown,
125+
selectClassName,
126+
...otherProps
127+
} = this.props;
128+
129+
const props = {
130+
onFocus: this.handleFocus,
131+
onBlur: this.handleBlur,
132+
onMouseDown: this.handleMouseDown,
133+
onClick: this.handleClick,
134+
onTouchStart: this.handleTouchStart,
135+
className: selectClassName,
136+
...otherProps,
137+
};
138+
139+
if (enhanced) {
140+
return (
141+
<EnhancedSelect
142+
onKeyDown={this.handleKeyDown}
143+
{...props}
144+
>
145+
{children}
146+
</EnhancedSelect>
147+
);
148+
}
149+
return (
150+
<NativeSelect
151+
onKeyDown={onKeyDown}
152+
{...props}
153+
>
154+
{children}
155+
</NativeSelect>
156+
);
157+
}
158+
}

0 commit comments

Comments
 (0)