Skip to content

Commit

Permalink
chore: create demo page
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanHotsiy committed Mar 13, 2018
1 parent 28f2391 commit 83eaa5f
Show file tree
Hide file tree
Showing 5 changed files with 491 additions and 5 deletions.
215 changes: 215 additions & 0 deletions demo/ComboBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/**
* Could not find ready-to-use component with required behaviour so
* I quickly hacked my own. Will refactor into separate npm package later
*/

import * as React from 'react';
import styled, { StyledFunction } from 'styled-components';

function withProps<T, U extends HTMLElement = HTMLElement>(
styledFunction: StyledFunction<React.HTMLProps<U>>,
): StyledFunction<T & React.HTMLProps<U>> {
return styledFunction;
}

const DropDownItem = withProps<{ active: boolean }>(styled.li)`
${props => ((props as any).active ? 'background-color: #eee' : '')};
padding: 13px 16px;
&:hover {
background-color: #eee;
}
cursor: pointer;
text-overflow: ellipsis;
overflow: hidden;
`;

const DropDownList = styled.ul`
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12),
0 3px 1px -2px rgba(0, 0, 0, 0.2);
background: #fff;
border-radius: 0 0 2px 2px;
top: 100%;
left: 0;
right: 0;
z-index: 200;
overflow: hidden;
position: absolute;
list-style: none;
margin: 4px 0 0 0;
padding: 5px 0;
font-family: 'Lato';
overflow: hidden;
`;

const ComboBoxWrap = styled.div`
position: relative;
width: 100%;
max-width: 500px;
display: flex;
`;

const Input = styled.input`
box-sizing: border-box;
width: 100%;
padding: 0 10px;
color: #555;
background-color: #fff;
border: 1px solid #ccc;
font-size: 16px;
height: 28px;
box-sizing: border-box;
vertical-align: middle;
line-height: 1;
outline: none;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus {
border-color: #66afe9;
outline: 0;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
}
`;

const Button = styled.button`
background-color: #fff;
color: #333;
padding: 2px 10px;
touch-action: manipulation;
cursor: pointer;
user-select: none;
border: 1px solid #ccc;
border-left: 0;
font-size: 16px;
height: 28px;
box-sizing: border-box;
vertical-align: middle;
line-height: 1;
outline: none;
width: 80px;
`;

export interface ComboBoxProps {
onChange?: (val: string) => void;
options: { value: string; label: string }[];
placeholder?: string;
value?: string;
}
export interface ComboBoxState {
open: boolean;
value: string;
activeItemIdx: number;
}

export default class ComboBox extends React.Component<ComboBoxProps, ComboBoxState> {
state = {
open: false,
value: this.props.value || '',
activeItemIdx: -1,
};

open = () => {
this.setState({
open: true,
});
};

close = () => {
this.setState({
open: false,
activeItemIdx: -1,
});
};

handleChange = e => {
this.updateValue(e.currentTarget.value);
};

updateValue(value) {
this.setState({
value,
activeItemIdx: -1,
});
}

handleSelect(value: string) {
this.updateValue(value);
if (this.props.onChange) {
this.props.onChange(value);
}
this.close();
}

handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.keyCode === 13) {
this.handleSelect(e.currentTarget.value);
} else if (e.keyCode === 40) {
const activeItemIdx = Math.min(this.props.options.length - 1, ++this.state.activeItemIdx);
this.setState({
open: true,
activeItemIdx,
value: this.props.options[activeItemIdx].value,
});
e.preventDefault();
} else if (e.keyCode === 38) {
const activeItemIdx = Math.max(0, --this.state.activeItemIdx);
this.setState({
activeItemIdx,
value: this.props.options[activeItemIdx].value,
});
e.preventDefault();
} else if (e.keyCode === 27) {
this.close();
}
};

handleBlur = () => {
setTimeout(() => this.close(), 100);
};

handleItemClick = (val, idx) => {
this.handleSelect(val);
this.setState({
activeItemIdx: idx,
});
};

render() {
const { open, value, activeItemIdx } = this.state;
const { options, placeholder } = this.props;
return (
<ComboBoxWrap>
<Input
placeholder={placeholder}
onChange={this.handleChange}
value={value}
onFocus={this.open}
onBlur={this.handleBlur}
onKeyDown={this.handleKeyPress}
/>
<Button onClick={() => this.handleSelect(this.state.value)}> TRY IT </Button>
{open && (
<DropDownList>
{options.map((option, idx) => (
<DropDownItem
active={idx == activeItemIdx}
key={option.value}
onMouseDown={() => {
this.handleItemClick(option.value, idx);
}}
>
<small>
<strong>{option.label}</strong>
</small>
<br />
{option.value}
</DropDownItem>
))}
</DropDownList>
)}
</ComboBoxWrap>
);
}
}
23 changes: 19 additions & 4 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

<head>
<meta charset="UTF-8" />
<title>ReDoc</title>
<title>ReDoc Interactive Demo</title>
<meta name="description" content="ReDoc Interactive Demo. OpenAPI/Swagger-generated API Reference Documentation" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
margin: 0;
Expand All @@ -18,8 +20,21 @@
</head>

<body>
<redoc spec-url="./openapi.yaml"></redoc>
<script src="../bundles/redoc.standalone.js"></script>
<div id="container"> </div>

<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');

if (window.location.host === 'rebilly.github.io') {
ga('create', 'UA-81703547-1', 'auto');
ga('send', 'pageview');
}
</script>
</body>

</html>
</html>
Loading

0 comments on commit 83eaa5f

Please sign in to comment.