Merge pull request #2004 from coralproject/next-ui-select

[next] SelectField
This commit is contained in:
Kiwi
2018-10-19 20:48:45 +02:00
committed by GitHub
23 changed files with 543 additions and 100 deletions
+119 -54
View File
@@ -3232,6 +3232,17 @@
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
},
"array.prototype.flat": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz",
"integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.10.0",
"function-bind": "^1.1.1"
}
},
"arrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
@@ -9351,53 +9362,72 @@
"dev": true
},
"enzyme": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.3.0.tgz",
"integrity": "sha512-l8csyPyLmtxskTz6pX9W8eDOyH1ckEtDttXk/vlFWCjv00SkjTjtoUrogqp4yEvMyneU9dUJoOLnqFoiHb8IHA==",
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.7.0.tgz",
"integrity": "sha512-QLWx+krGK6iDNyR1KlH5YPZqxZCQaVF6ike1eDJAOg0HvSkSCVImPsdWaNw6v+VrnK92Kg8jIOYhuOSS9sBpyg==",
"dev": true,
"requires": {
"array.prototype.flat": "^1.2.1",
"cheerio": "^1.0.0-rc.2",
"function.prototype.name": "^1.0.3",
"has": "^1.0.1",
"function.prototype.name": "^1.1.0",
"has": "^1.0.3",
"is-boolean-object": "^1.0.0",
"is-callable": "^1.1.3",
"is-callable": "^1.1.4",
"is-number-object": "^1.0.3",
"is-string": "^1.0.4",
"is-subset": "^0.1.1",
"lodash": "^4.17.4",
"object-inspect": "^1.5.0",
"lodash.escape": "^4.0.1",
"lodash.isequal": "^4.5.0",
"object-inspect": "^1.6.0",
"object-is": "^1.0.1",
"object.assign": "^4.1.0",
"object.entries": "^1.0.4",
"object.values": "^1.0.4",
"raf": "^3.4.0",
"rst-selector-parser": "^2.2.3"
"rst-selector-parser": "^2.2.3",
"string.prototype.trim": "^1.1.2"
},
"dependencies": {
"is-callable": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
"dev": true
}
}
},
"enzyme-adapter-react-16": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz",
"integrity": "sha512-kC8pAtU2Jk3OJ0EG8Y2813dg9Ol0TXi7UNxHzHiWs30Jo/hj7alc//G1YpKUsPP1oKl9X+Lkx+WlGJpPYA+nvw==",
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.6.0.tgz",
"integrity": "sha512-ay9eGFpChyUDnjTFMMJHzrb681LF3hPWJLEA7RoLFG9jSWAdAm2V50pGmFV9dYGJgh5HfdiqM+MNvle41Yf/PA==",
"dev": true,
"requires": {
"enzyme-adapter-utils": "^1.3.0",
"lodash": "^4.17.4",
"object.assign": "^4.0.4",
"enzyme-adapter-utils": "^1.8.0",
"function.prototype.name": "^1.1.0",
"object.assign": "^4.1.0",
"object.values": "^1.0.4",
"prop-types": "^15.6.0",
"react-reconciler": "^0.7.0",
"prop-types": "^15.6.2",
"react-is": "^16.5.2",
"react-test-renderer": "^16.0.0-0"
},
"dependencies": {
"react-is": {
"version": "16.5.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.5.2.tgz",
"integrity": "sha512-hSl7E6l25GTjNEZATqZIuWOgSnpXb3kD0DVCujmg46K5zLxsbiKaaT6VO9slkSBDPZfYs30lwfJwbOFOnoEnKQ==",
"dev": true
}
}
},
"enzyme-adapter-utils": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.3.0.tgz",
"integrity": "sha512-vVXSt6uDv230DIv+ebCG66T1Pm36Kv+m74L1TrF4kaE7e1V7Q/LcxO0QRkajk5cA6R3uu9wJf5h13wOTezTbjA==",
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.8.1.tgz",
"integrity": "sha512-s3QB3xQAowaDS2sHhmEqrT13GJC4+n5bG015ZkLv60n9k5vhxxHTQRIneZmQ4hmdCZEBrvUJ89PG6fRI5OEeuQ==",
"dev": true,
"requires": {
"lodash": "^4.17.4",
"object.assign": "^4.0.4",
"prop-types": "^15.6.0"
"function.prototype.name": "^1.1.0",
"object.assign": "^4.1.0",
"prop-types": "^15.6.2"
}
},
"enzyme-to-json": {
@@ -16666,6 +16696,12 @@
"resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
"integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw="
},
"lodash.escape": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
"integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=",
"dev": true
},
"lodash.flatten": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
@@ -16703,6 +16739,12 @@
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
"integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4="
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
"dev": true
},
"lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
@@ -17505,6 +17547,12 @@
"saslprep": "^1.0.0"
}
},
"moo": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz",
"integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==",
"dev": true
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -17672,11 +17720,12 @@
"optional": true
},
"nearley": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/nearley/-/nearley-2.13.0.tgz",
"integrity": "sha512-ioYYogSaZhFlCpRizQgY3UT3G1qFXmHGY/5ozoFE3dMfiCRAeJfh+IPE3/eh9gCZvqLhPCWb4bLt7Bqzo+1mLQ==",
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/nearley/-/nearley-2.15.1.tgz",
"integrity": "sha512-8IUY/rUrKz2mIynUGh8k+tul1awMKEjeHHC5G3FHvvyAW6oq4mQfNp2c0BMea+sYZJvYcrrM6GmZVIle/GRXGw==",
"dev": true,
"requires": {
"moo": "^0.4.3",
"nomnom": "~1.6.2",
"railroad-diagrams": "^1.0.0",
"randexp": "0.4.6",
@@ -21540,15 +21589,15 @@
}
},
"react": {
"version": "16.4.1",
"resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz",
"integrity": "sha512-3GEs0giKp6E0Oh/Y9ZC60CmYgUPnp7voH9fbjWsvXtYFb4EWtgQub0ADSq0sJR0BbHc4FThLLtzlcFaFXIorwg==",
"version": "16.5.2",
"resolved": "https://registry.npmjs.org/react/-/react-16.5.2.tgz",
"integrity": "sha512-FDCSVd3DjVTmbEAjUNX6FgfAmQ+ypJfHUsqUJOYNCBUp1h8lqmtC+0mXJ+JjsWx4KAVTkk1vKd1hLQPvEviSuw==",
"dev": true,
"requires": {
"fbjs": "^0.8.16",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
"prop-types": "^15.6.2",
"schedule": "^0.5.0"
}
},
"react-adopt": {
@@ -21853,15 +21902,15 @@
}
},
"react-dom": {
"version": "16.4.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz",
"integrity": "sha512-1Gin+wghF/7gl4Cqcvr1DxFX2Osz7ugxSwl6gBqCMpdrxHjIFUS7GYxrFftZ9Ln44FHw0JxCFD9YtZsrbR5/4A==",
"version": "16.5.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.5.2.tgz",
"integrity": "sha512-RC8LDw8feuZOHVgzEf7f+cxBr/DnKdqp56VU0lAs1f4UfKc4cU8wU4fTq/mgnvynLQo8OtlPC19NUFh/zjZPuA==",
"dev": true,
"requires": {
"fbjs": "^0.8.16",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
"prop-types": "^15.6.2",
"schedule": "^0.5.0"
}
},
"react-emotion": {
@@ -21963,18 +22012,6 @@
}
}
},
"react-reconciler": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.7.0.tgz",
"integrity": "sha512-50JwZ3yNyMS8fchN+jjWEJOH3Oze7UmhxeoJLn2j6f3NjpfCRbcmih83XTWmzqtar/ivd5f7tvQhvvhism2fgg==",
"dev": true,
"requires": {
"fbjs": "^0.8.16",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0"
}
},
"react-redux": {
"version": "5.0.7",
"resolved": "http://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
@@ -22077,15 +22114,23 @@
"integrity": "sha512-rxlZtZk5t6Y3gqqpaZ1lxY3RqlQcBU5uGsSoZj/hbF3ZweDqPbFHDkczT4emAxeaw37OD96RAAoayFGFQZCdWg=="
},
"react-test-renderer": {
"version": "16.4.2",
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.4.2.tgz",
"integrity": "sha512-vdTPnRMDbxfv4wL4lzN4EkVGXyYs7LE2uImOsqh1FKiP6L5o1oJl8nore5sFi9vxrP9PK3l4rgb/fZ4PVUaWSA==",
"version": "16.5.2",
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.5.2.tgz",
"integrity": "sha512-AGbJYbCVx1J6jdUgI4s0hNp+9LxlgzKvXl0ROA3DHTrtjAr00Po1RhDZ/eAq2VC/ww8AHgpDXULh5V2rhEqqJg==",
"dev": true,
"requires": {
"fbjs": "^0.8.16",
"object-assign": "^4.1.1",
"prop-types": "^15.6.0",
"react-is": "^16.4.2"
"prop-types": "^15.6.2",
"react-is": "^16.5.2",
"schedule": "^0.5.0"
},
"dependencies": {
"react-is": {
"version": "16.5.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.5.2.tgz",
"integrity": "sha512-hSl7E6l25GTjNEZATqZIuWOgSnpXb3kD0DVCujmg46K5zLxsbiKaaT6VO9slkSBDPZfYs30lwfJwbOFOnoEnKQ==",
"dev": true
}
}
},
"react-timeago": {
@@ -23276,6 +23321,15 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true
},
"schedule": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/schedule/-/schedule-0.5.0.tgz",
"integrity": "sha512-HUcJicG5Ou8xfR//c2rPT0lPIRR09vVvN81T9fqfVgBmhERUbDEQoYKjpBxbueJnCPpSu2ujXzOnRQt6x9o/jw==",
"dev": true,
"requires": {
"object-assign": "^4.1.1"
}
},
"schema-utils": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
@@ -24129,6 +24183,17 @@
"function-bind": "^1.0.2"
}
},
"string.prototype.trim": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
"integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.5.0",
"function-bind": "^1.0.2"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+5 -5
View File
@@ -191,8 +191,8 @@
"del": "^3.0.0",
"docz": "^0.5.8",
"dompurify": "^1.0.7",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.6.0",
"enzyme-to-json": "^3.3.4",
"eventemitter2": "^5.0.1",
"final-form": "^4.8.1",
@@ -233,15 +233,15 @@
"pym.js": "^1.3.2",
"query-string": "^6.1.0",
"raw-loader": "^0.5.1",
"react": "^16.4.0",
"react": "^16.5.2",
"react-copy-to-clipboard": "^5.0.1",
"react-dev-utils": "6.0.0-next.3e165448",
"react-dom": "^16.4.0",
"react-dom": "^16.5.2",
"react-final-form": "^3.6.4",
"react-popper": "^1.0.0",
"react-relay": "^1.7.0-rc.1",
"react-responsive": "^5.0.0",
"react-test-renderer": "^16.4.2",
"react-test-renderer": "^16.5.2",
"react-timeago": "^4.1.9",
"react-with-state-props": "^2.0.4",
"recompose": "^0.27.1",
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<React.Fragment>
<Fragment>
<Popup
features="menubar=0,resizable=0,width=350,height=395,top=200,left=500"
focus={false}
@@ -16,5 +16,5 @@ exports[`renders correctly 1`] = `
onRegister={[Function]}
onSignIn={[Function]}
/>
</React.Fragment>
</Fragment>
`;
@@ -1,5 +1,11 @@
import cn from "classnames";
import React, { Ref } from "react";
import React, {
EventHandler,
FocusEvent,
MouseEvent,
Ref,
TouchEvent,
} from "react";
import { ButtonHTMLAttributes, StatelessComponent } from "react";
import {
@@ -24,16 +30,22 @@ interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
*/
classes: typeof styles;
/** This is passed by the `withKeyboardFocus` HOC */
keyboardFocus?: boolean;
/** This is passed by the `withMouseHover` HOC */
mouseHover?: boolean;
/** Internal: Forwarded Ref */
forwardRef?: Ref<HTMLButtonElement>;
type?: "submit" | "reset" | "button";
// These handlers are passed down by the `withMouseHover` HOC.
mouseHover: boolean;
onMouseOver: React.EventHandler<MouseEvent<HTMLElement>>;
onMouseOut: React.EventHandler<MouseEvent<HTMLElement>>;
onTouchEnd: React.EventHandler<TouchEvent<HTMLElement>>;
// These handlers are passed down by the `withKeyboardFocus` HOC.
onFocus: EventHandler<FocusEvent<HTMLElement>>;
onBlur: EventHandler<FocusEvent<HTMLElement>>;
onMouseDown: EventHandler<MouseEvent<HTMLElement>>;
keyboardFocus: boolean;
}
/**
+1 -13
View File
@@ -1,17 +1,5 @@
@font-face {
font-family: "Material Icons";
font-style: normal;
font-weight: 400;
src: local("Material Icons"), local("MaterialIcons-Regular"),
url(material-design-icons/iconfont/MaterialIcons-Regular.woff2)
format("woff2"),
url(material-design-icons/iconfont/MaterialIcons-Regular.woff)
format("woff"),
url(material-design-icons/iconfont/MaterialIcons-Regular.ttf)
format("truetype");
}
.root {
composes: icon from "talk-ui/shared/icon.css";
font-family: "Material Icons";
speak: none;
font-style: normal;
@@ -0,0 +1,14 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-ui/types";
import OptGroup from "./OptGroup";
it("renders correctly", () => {
const props: PropTypesOf<typeof OptGroup> = {
label: "mamals",
children: <span />,
};
const renderer = TestRenderer.create(<OptGroup {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,13 @@
import React from "react";
import { StatelessComponent } from "react";
export interface OptGroupProps {
label: string;
children?: React.ReactNode;
}
const OptionGroup: StatelessComponent<OptGroupProps> = props => {
return <optgroup {...props} />;
};
export default OptionGroup;
@@ -0,0 +1,16 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-ui/types";
import Option from "./Option";
it("renders correctly", () => {
const props: PropTypesOf<typeof Option> = {
disabled: false,
hidden: false,
value: "apple",
children: "Apple",
};
const renderer = TestRenderer.create(<Option {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,15 @@
import React from "react";
import { StatelessComponent } from "react";
export interface OptionProps {
value?: string;
disabled?: boolean;
hidden?: boolean;
children?: React.ReactNode;
}
const Option: StatelessComponent<OptionProps> = props => {
return <option {...props} />;
};
export default Option;
@@ -0,0 +1,65 @@
.root {
position: relative;
display: inline-block;
}
.iconWrapper {
position: absolute;
display: inline-flex;
justify-content: center;
align-items: center;
right: calc(0.5 * var(--spacing-unit));
height: 100%;
user-select: none;
pointer-events: none;
}
.keyboardFocus:focus {
outline-width: 3px;
outline-color: Highlight;
outline-color: -webkit-focus-ring-color;
outline-style: auto;
}
.select {
composes: menuItem from "talk-ui/shared/typography.css";
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: none;
color: var(--palette-text-primary);
&::-moz-focus-inner {
border: 0;
}
&:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #000;
}
&:disabled {
background-color: var(--palette-grey-lightest);
border-color: var(--palette-text-secondary);
color: var(--palette-text-secondary);
}
border: 1px solid var(--palette-text-primary);
border-radius: var(--round-corners);
background-color: var(--palette-common-white);
padding: calc(0.5 * var(--spacing-unit)) calc(2 * var(--spacing-unit))
calc(0.5 * var(--spacing-unit)) var(--spacing-unit);
&::-ms-expand {
display: none;
}
}
.fullWidth {
width: 100%;
}
.iconWrapperDisabled {
color: var(--palette-text-secondary);
}
@@ -0,0 +1,52 @@
---
name: SelectField
menu: UI Kit
---
import { Playground, PropsTable } from 'docz'
import SelectField from './SelectField.tsx'
import Option from './Option.tsx'
import OptGroup from './OptGroup.tsx'
import HorizontalGutter from '../HorizontalGutter'
import Container from "react-with-state-props"
# SelectField
## Basic Use
<Playground>
<Container
state={{ value: "blue" }}
render={props => (
<SelectField value={props.value} onChange={e => props.setValue(e.target.value)}>
<Option value="red">Red Pill</Option>
<Option value="blue">Blue Pill</Option>
</SelectField>
)}/>
</Playground>
## Groups
<Playground>
<Container
state={{ value: "dog" }}
render={props => (
<SelectField value={props.value} onChange={e => props.setValue(e.target.value)}>
<OptGroup label="mammals">
<Option value="dog">Dog</Option>
<Option value="cat">Cat</Option>
</OptGroup>
<OptGroup label="fish">
<Option value="salmon">Salmon</Option>
<Option value="tuna">Tuna</Option>
</OptGroup>
</SelectField>
)}/>
</Playground>
## Disabled
<Playground>
<SelectField disabled>
<Option value="red">Red Pill</Option>
<Option value="blue">Blue Pill</Option>
</SelectField>
</Playground>
@@ -0,0 +1,21 @@
import { noop } from "lodash";
import React from "react";
import TestRenderer from "react-test-renderer";
import { PropTypesOf } from "talk-ui/types";
import SelectField from "./SelectField";
it("renders correctly", () => {
const props: PropTypesOf<typeof SelectField> = {
id: "selectID",
autofocus: true,
name: "selectName",
value: "pie",
className: "customClassName",
fullWidth: true,
onChange: noop,
disabled: true,
};
const renderer = TestRenderer.create(<SelectField {...props} />);
expect(renderer.toJSON()).toMatchSnapshot();
});
@@ -0,0 +1,82 @@
import cn from "classnames";
import React, {
ChangeEvent,
EventHandler,
FocusEvent,
MouseEvent,
} from "react";
import { StatelessComponent } from "react";
import { withKeyboardFocus, withStyles } from "talk-ui/hocs";
import Icon from "../Icon";
import * as styles from "./SelectField.css";
export interface SelectFieldProps {
/**
* Value that has been selected.
*/
value?: string;
/**
* Convenient prop to override the root styling.
*/
className?: string;
/**
* Override or extend the styles applied to the component.
*/
classes: typeof styles;
/*
* If set renders a full width button
*/
fullWidth?: boolean;
id?: string;
autofocus?: boolean;
name?: string;
onChange?: EventHandler<ChangeEvent<HTMLSelectElement>>;
disabled?: boolean;
// These handlers are passed down by the `withKeyboardFocus` HOC.
onFocus: EventHandler<FocusEvent<HTMLSelectElement>>;
onBlur: EventHandler<FocusEvent<HTMLSelectElement>>;
onMouseDown: EventHandler<MouseEvent<HTMLSelectElement>>;
keyboardFocus: boolean;
}
const SelectField: StatelessComponent<SelectFieldProps> = props => {
const {
className,
classes,
fullWidth,
keyboardFocus,
children,
disabled,
...rest
} = props;
const selectClassName = cn(classes.select, {
[classes.fullWidth]: fullWidth,
[classes.keyboardFocus]: keyboardFocus,
});
const iconWrapperClassName = cn(classes.iconWrapper, {
[classes.iconWrapperDisabled]: disabled,
});
return (
<span className={cn(classes.root, className)}>
<select className={selectClassName} disabled={disabled} {...rest}>
{children}
</select>
<span className={iconWrapperClassName} aria-hidden>
<Icon>expand_more</Icon>
</span>
</span>
);
};
const enhanced = withStyles(styles)(withKeyboardFocus(SelectField));
export default enhanced;
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<optgroup
label="mamals"
>
<span />
</optgroup>
`;
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<option
disabled={false}
hidden={false}
value="apple"
>
Apple
</option>
`;
@@ -0,0 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<span
className="SelectField-root customClassName"
>
<select
autofocus={true}
className="SelectField-select SelectField-fullWidth"
disabled={true}
id="selectID"
name="selectName"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
value="pie"
/>
<span
aria-hidden={true}
className="SelectField-iconWrapper SelectField-iconWrapperDisabled"
>
<span
aria-hidden="true"
className="Icon-root Icon-sm"
>
expand_more
</span>
</span>
</span>
`;
@@ -0,0 +1,3 @@
export { default, default as SelectField } from "./SelectField";
export { default as Option } from "./Option";
export { default as OptGroup } from "./OptGroup";
@@ -7,6 +7,7 @@ menu: UI Kit
### Examples
import { Playground } from 'docz'
import { Flex, Step, StepBar } from './index'
<Playground>
+1
View File
@@ -23,3 +23,4 @@ export { default as AriaInfo } from "./AriaInfo";
export { default as Message, MessageIcon } from "./Message";
export { Tab, TabBar, TabContent, TabPane } from "./Tabs";
export { StepBar, Step } from "./Steps";
export { SelectField, Option, OptGroup } from "./SelectField";
@@ -1,6 +1,6 @@
import * as React from "react";
import { FocusEvent, MouseEvent } from "react";
import { hoistStatics } from "recompose";
import { DefaultingInferableComponentEnhancer, hoistStatics } from "recompose";
interface InjectedProps {
onFocus: React.EventHandler<FocusEvent<any>>;
@@ -14,12 +14,14 @@ interface InjectedProps {
* to indicate a focus on the element, that wasn't triggered by mouse
* or touch.
*/
const withKeyboardFocus = hoistStatics<InjectedProps>(
const withKeyboardFocus: DefaultingInferableComponentEnhancer<
InjectedProps
> = hoistStatics<InjectedProps>(
<T extends InjectedProps>(BaseComponent: React.ComponentType<T>) => {
class WithKeyboardFocus extends React.Component<any> {
private lastMouseDownTime: number = 0;
public state = {
keyboardFocus: false,
lastMouseDownTime: 0,
};
private handleFocus: React.EventHandler<FocusEvent<any>> = event => {
@@ -27,7 +29,7 @@ const withKeyboardFocus = hoistStatics<InjectedProps>(
this.props.onFocus(event);
}
const now = new Date().getTime();
if (now - this.state.lastMouseDownTime > 750) {
if (now - this.lastMouseDownTime > 750) {
this.setState({ keyboardFocus: true });
}
};
@@ -43,7 +45,7 @@ const withKeyboardFocus = hoistStatics<InjectedProps>(
if (this.props.onMouseDown) {
this.props.onMouseDown(event);
}
this.setState({ lastMouseDownTime: new Date().getTime() });
this.lastMouseDownTime = new Date().getTime();
};
public render() {
@@ -63,7 +65,4 @@ const withKeyboardFocus = hoistStatics<InjectedProps>(
}
);
// TODO: workaround, add bug link.
export default withKeyboardFocus as <P extends Partial<InjectedProps>>(
BaseComponent: React.ComponentType<P>
) => React.ComponentType<P>;
export default withKeyboardFocus;
+9 -10
View File
@@ -1,6 +1,6 @@
import * as React from "react";
import { MouseEvent, TouchEvent } from "react";
import { hoistStatics } from "recompose";
import { DefaultingInferableComponentEnhancer, hoistStatics } from "recompose";
interface InjectedProps {
onMouseOver: React.EventHandler<MouseEvent<any>>;
@@ -14,19 +14,21 @@ interface InjectedProps {
* to indicate a focus on the element, that wasn't triggered by mouse
* or touch.
*/
const withMouseHover = hoistStatics<InjectedProps>(
const withMouseHover: DefaultingInferableComponentEnhancer<
InjectedProps
> = hoistStatics<InjectedProps>(
<T extends InjectedProps>(BaseComponent: React.ComponentType<T>) => {
class WithMouseHover extends React.Component<any> {
class WithMouseHover extends React.Component<InjectedProps> {
private lastTouchEndTime = 0;
public state = {
mouseHover: false,
lastTouchEndTime: 0,
};
private handleTouchEnd: React.EventHandler<TouchEvent<any>> = event => {
if (this.props.onTouchEnd) {
this.props.onTouchEnd(event);
}
this.setState({ lastTouchEndTime: new Date().getTime() });
this.lastTouchEndTime = new Date().getTime();
};
private handleMouseOver: React.EventHandler<MouseEvent<any>> = event => {
@@ -34,7 +36,7 @@ const withMouseHover = hoistStatics<InjectedProps>(
this.props.onMouseOver(event);
}
const now = new Date().getTime();
if (now - this.state.lastTouchEndTime > 750) {
if (now - this.lastTouchEndTime > 750) {
this.setState({ mouseHover: true });
}
};
@@ -63,7 +65,4 @@ const withMouseHover = hoistStatics<InjectedProps>(
}
);
// TODO: workaround, add bug link.
export default withMouseHover as <P extends Partial<InjectedProps>>(
BaseComponent: React.ComponentType<P>
) => React.ComponentType<P>;
export default withMouseHover;
+37
View File
@@ -0,0 +1,37 @@
@font-face {
font-family: "Material Icons";
font-style: normal;
font-weight: 400;
src: local("Material Icons"), local("MaterialIcons-Regular"),
url(material-design-icons/iconfont/MaterialIcons-Regular.woff2)
format("woff2"),
url(material-design-icons/iconfont/MaterialIcons-Regular.woff)
format("woff"),
url(material-design-icons/iconfont/MaterialIcons-Regular.ttf)
format("truetype");
}
.icon {
font-family: "Material Icons";
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
overflow: hidden;
vertical-align: middle;
display: inline-block;
letter-spacing: 0;
/* Enable Ligatures */
font-feature-settings: "liga";
font-variant-ligatures: "discretionary-ligatures";
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Better Font Rendering */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
+9
View File
@@ -198,3 +198,12 @@
letter-spacing: calc(0.2em / 18);
color: var(--palette-text-primary);
}
.menuItem {
font-size: calc(16rem / var(--rem-base));
font-weight: var(--font-weight-regular);
font-family: var(--font-family-sans-serif);
line-height: calc(19em / 16);
letter-spacing: calc(0.2em / 16);
color: var(--palette-text-primary);
}