├── .gitignore
├── .npmignore
├── src
├── Box.js
├── Menu.js
├── relect.css
└── Relect.js
├── example
├── src
│ ├── index.scss
│ └── index.js
└── index.html
├── README.md
├── package.json
└── lib
├── relect.css
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | .DS_Store
4 | example/dist/
5 | *.log
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | webpack.config.js
2 | .gitignore
3 | example
4 | .npmignore
5 | .idea
6 | node_modules
7 | .DS_Store
8 | package-lock.json
9 | yarn.lock
10 | build
11 |
--------------------------------------------------------------------------------
/src/Box.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const BoxContent = props => {
4 | const { chosen, options, disabled } = props;
5 | if (typeof chosen === 'number' && options[chosen] !== void 0) {
6 | const clear = disabled ? null : ;
7 | return {options[chosen].text || options[chosen]}{clear};
8 | } else {
9 | return {props.placeholder}
10 | }
11 | }
12 |
13 | const Box = props => {
14 | const className = 'relect-box' + (props.disabled ? ' relect-box-disabled' : '');
15 | return (
16 |
17 | {BoxContent(props)}
18 |
19 |
20 | )
21 | }
22 |
23 | export default Box;
24 |
--------------------------------------------------------------------------------
/src/Menu.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class Menu extends React.Component {
4 | render() {
5 | const { props } = this;
6 | const style = {
7 | top : props.height - 1,
8 | display : props.showMenu && !props.disabled ? '' : 'none',
9 | lineHeight : props.optionHeight + 'px',
10 | maxHeight : props.optionHeight * 8 + 2
11 | };
12 |
13 | const options = props.options.map((item, index) => {
14 | const className = index === props.focused ? 'relect-focused-option' : '';
15 | return (
16 |
21 | {item.text || item}
22 |
23 | )
24 | });
25 |
26 | return ;
27 | }
28 | }
29 |
30 | export default Menu;
31 |
--------------------------------------------------------------------------------
/example/src/index.scss:
--------------------------------------------------------------------------------
1 | .wrapper {
2 | width: 600px;
3 | height: 320px;
4 | margin: 0 auto;
5 | text-align: center;
6 | padding-top: 36px;
7 | box-sizing: border-box;
8 | border-radius: 4px;
9 | background: #fff;
10 | box-shadow: 0 1px 3px rgba(0, 0, 0, .35);
11 | }
12 | .title,
13 | .intro {
14 | color: #fff;
15 | text-align: center;
16 | text-shadow: 0 1px 2px rgba(0,0,0,0.2);
17 | }
18 | .title {
19 | font-size: 70px;
20 | margin: 0;
21 | @media (max-width: 600px) {
22 | font-size: 40px;
23 | }
24 | }
25 | .intro {
26 | font-size: 30px;
27 | margin: 15px 10px 40px;
28 | @media (max-width: 600px) {
29 | font-size: 20px;
30 | }
31 | }
32 | .btn {
33 | cursor: pointer;
34 | display: inline-block;
35 | width: 35%;
36 | color: #586481;
37 | font-size: 14px;
38 | background: #fff;
39 | line-height: 30px;
40 | border-radius: 2px;
41 | margin: 20px 15px 0;
42 | border: 1px solid #586481;
43 | transition: .2s background, .2s color;
44 | &:hover {
45 | color: #fff;
46 | background: #586481;
47 | }
48 | &:focus {
49 | outline: none;
50 | }
51 | }
52 | .btn-area {
53 | margin-top: 16px;
54 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Relect
2 | A Tiny React Single Select Component.
3 | [Example](http://chenjiahan.github.io/relect/)
4 |
5 | ## Install
6 |
7 | npm i relect -S
8 |
9 | ## Usage
10 | ``` javascript
11 | import React from 'react';
12 | import Relect from 'relect';
13 |
14 | // include styles
15 | import 'relect/lib/relect.css';
16 |
17 | const options = [
18 | { text: 'one', value: 1 },
19 | { text: 'two', value: 2 }
20 | ];
21 |
22 | class App extends React.Component {
23 |
24 | constructor(props) {
25 | super(props);
26 | this.state = { chosen : null }
27 | }
28 |
29 | onChange(index) {
30 | this.setState({ chosen : index });
31 | }
32 |
33 | render() {
34 | return (
35 |
39 | )
40 | }
41 | }
42 | ```
43 | ## Props
44 |
45 | Property|Type|Default|Description
46 | ---|---|---|---
47 | width|number|240|width of select
48 | height|number|36|height of select
49 | options|array|/|options
50 | chosen|number|/|index of chosen option
51 | tabIndex|number|-1|tab order
52 | disabled|bool|false|whether to disable select
53 | autoBlur|bool|false|auto blur after selection
54 | placeholder|string|/|placeholder text
55 | optionHeight|number|30|height of option
56 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "relect",
3 | "version": "1.2.1",
4 | "description": "A Tiny React Single Select Component.",
5 | "main": "lib/index.js",
6 | "devDependencies": {
7 | "autoprefixer-loader": "^3.1.0",
8 | "babel": "^6.1.18",
9 | "babel-core": "^6.3.21",
10 | "babel-loader": "^7.0.0",
11 | "babel-preset-es2015": "^6.24.1",
12 | "babel-preset-react": "^6.24.1",
13 | "babel-preset-stage-0": "^6.24.1",
14 | "babel-runtime": "^6.23.0",
15 | "babel-types": "^6.24.1",
16 | "css-loader": "^0.28.4",
17 | "node-sass": "^4.5.3",
18 | "react": "^16.2.0",
19 | "react-dom": "^16.2.0",
20 | "sass-loader": "^6.0.5",
21 | "shelljs": "^0.8.5",
22 | "style-loader": "^0.19.0",
23 | "webpack": "^3.10.0",
24 | "webpack-dev-server": "^3.1.11",
25 | "webpack-merge": "^4.1.0"
26 | },
27 | "scripts": {
28 | "dev": "node_modules/.bin/webpack-dev-server --config ./build/webpack.dev.conf.js",
29 | "build": "webpack -p --hide-modules --config ./build/webpack.prod.conf.js && cp src/relect.css lib",
30 | "release": "npm run build && npm publish"
31 | },
32 | "repository": {
33 | "type": "git",
34 | "url": "git+https://github.com/chenjiahan/relect.git"
35 | },
36 | "keywords": [
37 | "react",
38 | "select",
39 | "react-select",
40 | "react-component"
41 | ],
42 | "author": "neverland",
43 | "license": "ISC",
44 | "bugs": {
45 | "url": "https://github.com/chenjiahan/relect/issues"
46 | },
47 | "homepage": "https://github.com/chenjiahan/relect#readme",
48 | "dependencies": {
49 | "prop-types": "^15.5.10"
50 | },
51 | "babel": {
52 | "presets": [
53 | "es2015",
54 | "stage-0",
55 | "react"
56 | ]
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Relect
6 |
7 |
46 |
47 |
48 |
49 |
50 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/example/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | // import Relect from '../../src/Relect';
4 | import './index.scss';
5 | import '../../lib/relect.css';
6 | import Relect from '../../lib';
7 |
8 |
9 | const objectOptions = [
10 | { val: 0, text: 'Jon Snow' },
11 | { val: 1, text: 'Ned Stark' },
12 | { val: 2, text: 'Tywin' },
13 | { val: 3, text: 'Robb' },
14 | { val: 4, text: 'Sansa' },
15 | { val: 5, text: 'Arya' },
16 | { val: 6, text: 'Bran' },
17 | { val: 7, text: 'Cersei' },
18 | { val: 8, text: 'Jaime' },
19 | { val: 9, text: 'Joffrey' },
20 | { val: 10, text: 'Tyrion' },
21 | { val: 11, text: 'Stannis' },
22 | { val: 12, text: 'Melisandre' }
23 | ];
24 |
25 | const arrayOptions = ['one', 'two', 'three', 'four', 'five', 'six'];
26 |
27 | class App extends React.Component {
28 |
29 | constructor(props) {
30 | super(props);
31 |
32 | this.state = {
33 | chosen : null,
34 | disabled : false,
35 | option : objectOptions
36 | }
37 | }
38 |
39 | handleChange(chosen) {
40 | this.setState({ chosen });
41 | };
42 |
43 | clear() {
44 | this.setState({ chosen: null });
45 | }
46 |
47 | selectFirstOption() {
48 | this.setState({ chosen: 0 });
49 | }
50 |
51 | setDisable() {
52 | this.setState({ disabled: !this.state.disabled });
53 | }
54 |
55 | selectTywin() {
56 | for (let i = 0; i < objectOptions.length; i++) {
57 | if (objectOptions[i].text === 'Tywin') {
58 | this.setState({ chosen: i });
59 | return;
60 | }
61 | }
62 | }
63 |
64 | simpleOption() {
65 | this.setState({ option : arrayOptions });
66 | }
67 |
68 | objectOption() {
69 | this.setState({ option : objectOptions });
70 | }
71 |
72 | render() {
73 | return (
74 |
75 |
Relect
76 |
A Tiny React Single Select Component.
77 |
78 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | )
95 | }
96 | }
97 |
98 | ReactDOM.render(
99 | ,
100 | document.getElementById('app')
101 | );
102 |
--------------------------------------------------------------------------------
/lib/relect.css:
--------------------------------------------------------------------------------
1 | /* -- relect container -- */
2 | .relect {
3 | cursor: pointer;
4 | text-align: left;
5 | position: relative;
6 | display: inline-block;
7 | -webkit-user-select: none;
8 | -moz-user-select: none;
9 | -ms-user-select: none;
10 | user-select: none;
11 | }
12 | .relect:hover .relect-box {
13 | border-color: #B9B9B9;
14 | box-shadow: 0 0 2px rgba(0, 0, 0, .14);
15 | }
16 | .relect:hover .relect-option {
17 | border-top-color: #B9B9B9;
18 | }
19 | .relect:focus {
20 | outline: none;
21 | }
22 | .relect:focus .relect-box {
23 | border-color: #29B6F6;
24 | box-shadow: 0 0 2px rgba(41, 182, 246, .3);
25 | }
26 | .relect:focus .relect-option {
27 | border-top-color: #29B6F6;
28 | }
29 | .relect:hover .relect-box-disabled,
30 | .relect:focus .relect-box-disabled {
31 | box-shadow: none;
32 | border-color: #D9D9D9;
33 | }
34 |
35 | /* -- box && option -- */
36 | .relect-box,
37 | .relect-option {
38 | width: inherit;
39 | background: #fff;
40 | -webkit-box-sizing: border-box;
41 | -moz-box-sizing: border-box;
42 | box-sizing: border-box;
43 | }
44 |
45 | /* -- box -- */
46 | .relect-box {
47 | padding: 0 10px;
48 | border-radius: 2px;
49 | display: inline-block;
50 | border: 1px solid #D9D9D9;
51 | box-shadow: 0 0 1px rgba(0, 0, 0, .14);
52 | -webkit-transition: border-color .2s, box-shadow .2s;
53 | transition: border-color .2s, box-shadow .2s;
54 | }
55 | .relect-box-disabled {
56 | color: #AAA;
57 | cursor: default;
58 | background: #f8f8f8;
59 | box-shadow: none;
60 | }
61 | .relect-placeholder {
62 | color: #999;
63 | display: inline-block;
64 | }
65 |
66 | /* -- option -- */
67 | .relect-option {
68 | position: absolute;
69 | left: 0;
70 | margin: 0;
71 | padding: 0;
72 | z-index: 10;
73 | list-style: none;
74 | overflow-y: auto;
75 | border: 1px solid #D9D9D9;
76 | border-radius: 0 0 2px 2px;
77 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
78 | -webkit-animation: slide-enter .2s both cubic-bezier(.8, 0, 0, 1);
79 | animation: slide-enter .2s both cubic-bezier(.8, 0, 0, 1);
80 | }
81 | .relect-option li {
82 | padding: 0 10px;
83 | }
84 | .relect-option::-webkit-scrollbar {
85 | width: 8px;
86 | border-left: 1px solid rgba(0, 0, 0, .1);
87 | }
88 | .relect-option::-webkit-scrollbar-thumb {
89 | border-radius: 8px;
90 | background: rgba(0, 0, 0, .1);
91 | }
92 | .relect-option::-webkit-scrollbar-thumb:hover {
93 | background: rgba(0, 0, 0, .2);
94 | }
95 | .relect-focused-option {
96 | color: #fff;
97 | background: #29B6F6;
98 | border-radius: 2px;
99 | box-shadow: 0 0 1px rgba(0,0,0,.14);
100 | }
101 | @-webkit-keyframes slide-enter {
102 | from {
103 | opacity: 0;
104 | -webkit-transform: scaleY(0);
105 | transform: scaleY(0);
106 | }
107 | from, to {
108 | -webkit-transform-origin: top;
109 | transform-origin: top;
110 | }
111 | to {
112 | opacity: 1;
113 | -webkit-transform: scaleY(1);
114 | transform: scaleY(1);
115 | }
116 | }
117 | @keyframes slide-enter {
118 | from {
119 | opacity: 0;
120 | -webkit-transform: scaleY(0);
121 | transform: scaleY(0);
122 | }
123 | from, to {
124 | -webkit-transform-origin: top;
125 | transform-origin: top;
126 | }
127 | to {
128 | opacity: 1;
129 | -webkit-transform: scaleY(1);
130 | transform: scaleY(1);
131 | }
132 | }
133 |
134 | /* -- arrow -- */
135 | .relect-arrow {
136 | position: absolute;
137 | top: 50%;
138 | right: 12px;
139 | width: 0;
140 | height: 0;
141 | z-index: 1;
142 | font-size: 0;
143 | overflow: hidden;
144 | margin-top: -3px;
145 | border: solid 6px;
146 | border-color: #B9B9B9 transparent transparent;
147 | }
148 | .relect-arrow:hover {
149 | border-top-color: #A0A0A0;
150 | }
151 | .relect-box-disabled .relect-arrow:hover {
152 | border-top-color: #B9B9B9;
153 | }
154 |
155 | /* -- clear -- */
156 | .relect-clear {
157 | position: absolute;
158 | cursor: pointer;
159 | top: 50%;
160 | right: 32px;
161 | width: 12px;
162 | height: 12px;
163 | margin-top: -6px;
164 | }
165 | .relect-clear:before,
166 | .relect-clear:after {
167 | position: absolute;
168 | content: '';
169 | top: 50%;
170 | left: 0;
171 | width: 100%;
172 | height: 2px;
173 | margin-top: -1px;
174 | border-radius: 100%;
175 | background: #B9B9B9;
176 | -webkit-transition: background .2s;
177 | transition: background .2s;
178 | }
179 | .relect-clear:before {
180 | -webkit-transform: rotate(45deg);
181 | transform: rotate(45deg);
182 | }
183 | .relect-clear:after {
184 | -webkit-transform: rotate(-45deg);
185 | transform: rotate(-45deg);
186 | }
187 | .relect-clear:hover:before,
188 | .relect-clear:hover:after {
189 | background: #FF7D7D;
190 | }
191 |
--------------------------------------------------------------------------------
/src/relect.css:
--------------------------------------------------------------------------------
1 | /* -- relect container -- */
2 | .relect {
3 | cursor: pointer;
4 | text-align: left;
5 | position: relative;
6 | display: inline-block;
7 | -webkit-user-select: none;
8 | -moz-user-select: none;
9 | -ms-user-select: none;
10 | user-select: none;
11 | }
12 | .relect:hover .relect-box {
13 | border-color: #B9B9B9;
14 | box-shadow: 0 0 2px rgba(0, 0, 0, .14);
15 | }
16 | .relect:hover .relect-option {
17 | border-top-color: #B9B9B9;
18 | }
19 | .relect:focus {
20 | outline: none;
21 | }
22 | .relect:focus .relect-box {
23 | border-color: #29B6F6;
24 | box-shadow: 0 0 2px rgba(41, 182, 246, .3);
25 | }
26 | .relect:focus .relect-option {
27 | border-top-color: #29B6F6;
28 | }
29 | .relect:hover .relect-box-disabled,
30 | .relect:focus .relect-box-disabled {
31 | box-shadow: none;
32 | border-color: #D9D9D9;
33 | }
34 |
35 | /* -- box && option -- */
36 | .relect-box,
37 | .relect-option {
38 | width: inherit;
39 | background: #fff;
40 | -webkit-box-sizing: border-box;
41 | -moz-box-sizing: border-box;
42 | box-sizing: border-box;
43 | }
44 |
45 | /* -- box -- */
46 | .relect-box {
47 | padding: 0 10px;
48 | border-radius: 2px;
49 | display: inline-block;
50 | border: 1px solid #D9D9D9;
51 | box-shadow: 0 0 1px rgba(0, 0, 0, .14);
52 | -webkit-transition: border-color .2s, box-shadow .2s;
53 | transition: border-color .2s, box-shadow .2s;
54 | }
55 | .relect-box-disabled {
56 | color: #AAA;
57 | cursor: default;
58 | background: #f8f8f8;
59 | box-shadow: none;
60 | }
61 | .relect-placeholder {
62 | color: #999;
63 | display: inline-block;
64 | }
65 |
66 | /* -- option -- */
67 | .relect-option {
68 | position: absolute;
69 | left: 0;
70 | margin: 0;
71 | padding: 0;
72 | z-index: 10;
73 | list-style: none;
74 | overflow-y: auto;
75 | border: 1px solid #D9D9D9;
76 | border-radius: 0 0 2px 2px;
77 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
78 | -webkit-animation: slide-enter .2s both cubic-bezier(.8, 0, 0, 1);
79 | animation: slide-enter .2s both cubic-bezier(.8, 0, 0, 1);
80 | }
81 | .relect-option li {
82 | padding: 0 10px;
83 | }
84 | .relect-option::-webkit-scrollbar {
85 | width: 8px;
86 | border-left: 1px solid rgba(0, 0, 0, .1);
87 | }
88 | .relect-option::-webkit-scrollbar-thumb {
89 | border-radius: 8px;
90 | background: rgba(0, 0, 0, .1);
91 | }
92 | .relect-option::-webkit-scrollbar-thumb:hover {
93 | background: rgba(0, 0, 0, .2);
94 | }
95 | .relect-focused-option {
96 | color: #fff;
97 | background: #29B6F6;
98 | border-radius: 2px;
99 | box-shadow: 0 0 1px rgba(0,0,0,.14);
100 | }
101 | @-webkit-keyframes slide-enter {
102 | from {
103 | opacity: 0;
104 | -webkit-transform: scaleY(0);
105 | transform: scaleY(0);
106 | }
107 | from, to {
108 | -webkit-transform-origin: top;
109 | transform-origin: top;
110 | }
111 | to {
112 | opacity: 1;
113 | -webkit-transform: scaleY(1);
114 | transform: scaleY(1);
115 | }
116 | }
117 | @keyframes slide-enter {
118 | from {
119 | opacity: 0;
120 | -webkit-transform: scaleY(0);
121 | transform: scaleY(0);
122 | }
123 | from, to {
124 | -webkit-transform-origin: top;
125 | transform-origin: top;
126 | }
127 | to {
128 | opacity: 1;
129 | -webkit-transform: scaleY(1);
130 | transform: scaleY(1);
131 | }
132 | }
133 |
134 | /* -- arrow -- */
135 | .relect-arrow {
136 | position: absolute;
137 | top: 50%;
138 | right: 12px;
139 | width: 0;
140 | height: 0;
141 | z-index: 1;
142 | font-size: 0;
143 | overflow: hidden;
144 | margin-top: -3px;
145 | border: solid 6px;
146 | border-color: #B9B9B9 transparent transparent;
147 | }
148 | .relect-arrow:hover {
149 | border-top-color: #A0A0A0;
150 | }
151 | .relect-box-disabled .relect-arrow:hover {
152 | border-top-color: #B9B9B9;
153 | }
154 |
155 | /* -- clear -- */
156 | .relect-clear {
157 | position: absolute;
158 | cursor: pointer;
159 | top: 50%;
160 | right: 32px;
161 | width: 12px;
162 | height: 12px;
163 | margin-top: -6px;
164 | }
165 | .relect-clear:before,
166 | .relect-clear:after {
167 | position: absolute;
168 | content: '';
169 | top: 50%;
170 | left: 0;
171 | width: 100%;
172 | height: 2px;
173 | margin-top: -1px;
174 | border-radius: 100%;
175 | background: #B9B9B9;
176 | -webkit-transition: background .2s;
177 | transition: background .2s;
178 | }
179 | .relect-clear:before {
180 | -webkit-transform: rotate(45deg);
181 | transform: rotate(45deg);
182 | }
183 | .relect-clear:after {
184 | -webkit-transform: rotate(-45deg);
185 | transform: rotate(-45deg);
186 | }
187 | .relect-clear:hover:before,
188 | .relect-clear:hover:after {
189 | background: #FF7D7D;
190 | }
191 |
--------------------------------------------------------------------------------
/src/Relect.js:
--------------------------------------------------------------------------------
1 | /* ===============================
2 | * Relect v1.1.0
3 | * https://github.com/chenjiahan/relect
4 | * =============================== */
5 |
6 | import React from 'react';
7 | import ReactDOM from 'react-dom';
8 | import PropTypes from 'prop-types';
9 | import Menu from './Menu';
10 | import Box from './Box';
11 |
12 | class Relect extends React.Component {
13 |
14 | static propTypes = {
15 | width : PropTypes.number,
16 | height : PropTypes.number,
17 | chosen : PropTypes.any,
18 | options : PropTypes.array,
19 | tabIndex : PropTypes.number,
20 | autoBlur : PropTypes.bool,
21 | disabled : PropTypes.bool,
22 | placeholder : PropTypes.string,
23 | optionHeight : PropTypes.number
24 | };
25 |
26 | static defaultProps = {
27 | width : 240,
28 | height : 36,
29 | options : [],
30 | tabIndex : -1,
31 | autoBlur : false,
32 | disabled : false,
33 | placeholder : '',
34 | optionHeight : 30
35 | };
36 |
37 | state = {
38 | focused : null, // index of focused option
39 | showMenu : false // whether show option
40 | };
41 |
42 | toggleMenu = () => {
43 | this.setState({ showMenu: !this.state.showMenu });
44 | };
45 |
46 | onChoose = index => {
47 | this.props.onChange(index);
48 | this.setState({ showMenu : false });
49 |
50 | if (this.props.autoBlur) {
51 | this.relectDOM && this.relectDOM.blur();
52 | }
53 | };
54 |
55 | onClear = e => {
56 | e.stopPropagation();
57 | this.setState({ showMenu : false });
58 | this.props.onChange(null);
59 | };
60 |
61 | onBlur = (e) => {
62 | if (e.target === e.currentTarget) {
63 | this.setState({ showMenu : false })
64 | }
65 | };
66 |
67 | onKeyDown = e => {
68 | switch (e.which) {
69 | case 8 : // Delete
70 | this.onClear(e);
71 | break;
72 | case 27: // Esc
73 | this.setState({ showMenu : false });
74 | break;
75 | case 13: // Enter
76 | case 32: // Space
77 | if (this.state.showMenu && this.state.focused !== null) {
78 | this.onChoose(this.state.focused);
79 | } else {
80 | this.toggleMenu();
81 | }
82 | break;
83 | case 38: // Up
84 | this.moveFocusedOption(-1);
85 | break;
86 | case 40: // Down
87 | this.moveFocusedOption(1);
88 | break;
89 | default:
90 | return;
91 | }
92 | e.preventDefault();
93 | };
94 |
95 | moveFocusedOption = move => {
96 | if (!this.state.showMenu) {
97 | this.setState({ showMenu : true });
98 | return;
99 | }
100 |
101 | let { focused } = this.state;
102 | let { length } = this.props.options;
103 | focused = focused === null ? 0 : (focused + move + length) % length;
104 | this.focusOption(focused);
105 | };
106 |
107 | focusOption = focused => {
108 | this.setState({ focused });
109 |
110 | // calc offset
111 | // displays up to 8 options in the same time
112 | let length = this.props.options.length;
113 | if (length > 8) {
114 | let height = this.props.optionHeight;
115 | let current = this.menuDOM.scrollTop;
116 | let max = Math.min((length - 8) * height, focused * height);
117 | let min = Math.max(0, (focused - 7) * height);
118 |
119 | if (current > max) {
120 | this.menuDOM.scrollTop = max;
121 | } else if (current < min) {
122 | this.menuDOM.scrollTop = min;
123 | }
124 | }
125 | };
126 |
127 | render() {
128 | const { props } = this;
129 | const { showMenu, focused } = this.state;
130 | const style = {
131 | width : props.width,
132 | lineHeight : props.height - 2 + 'px'
133 | };
134 |
135 | return (
136 | { this.relectDOM = node; }}
143 | >
144 |
149 |
157 | )
158 | }
159 | }
160 |
161 | export default Relect;
162 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | module.exports=function(e){function t(o){if(n[o])return n[o].exports;var r=n[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:o})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="lib/",t(t.s=1)}([function(e,t){e.exports=require("react")},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function u(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var i=Object.assign||function(e){for(var t=1;t8){var n=o.props.optionHeight,r=o.menuDOM.scrollTop,u=Math.min((t-8)*n,e*n),a=Math.max(0,(e-7)*n);r>u?o.menuDOM.scrollTop=u:r