Created
August 13, 2018 10:58
-
-
Save fabien0102/c2c98145e28536e271908b3b774b9123 to your computer and use it in GitHub Desktop.
SideFilters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import styled, { keyframes } from "react-emotion"; | |
import { getConfig } from "../../getConfig"; | |
import Wrapper from "./Wrapper"; | |
export interface SelectFilterProps { | |
field: { | |
id: string; | |
name: string; | |
options: { | |
values: string[]; | |
}; | |
}; | |
values: string[]; | |
onChange: (values: string[]) => void; | |
} | |
const toggleCheckboxAnimation = keyframes` | |
0% { | |
opacity: 0; | |
transform: translateY(-50%) scale(0) rotate(45deg); | |
} | |
70% { | |
opacity: 1; | |
transform: translateY(-50%) scale(1.2) rotate(45deg); | |
} | |
100% { | |
transform: translateY(-50%) scale(1) rotate(45deg); | |
} | |
`; | |
// ref: https://codersblock.com/blog/checkbox-trickery-with-css/ | |
const Checkbox = styled("input")` | |
position: absolute; | |
left: -9999px; | |
:checked + label::after { | |
content: ""; | |
display: block; | |
width: 5px; | |
height: 11px; | |
position: absolute; | |
left: 7px; | |
margin: 0 auto; | |
top: 48%; | |
transform: translateY(-50%) rotate(45deg); | |
border-right: 2px solid ${getConfig("color")}; | |
border-bottom: 2px solid ${getConfig("color")}; | |
cursor: pointer; | |
animation: ${toggleCheckboxAnimation} 0.2s ease forwards; | |
} | |
`; | |
const Label = styled("label")` | |
position: relative; | |
cursor: pointer; | |
height: 20px; | |
display: block; | |
margin-bottom: 10px; | |
padding-left: 30px; | |
line-height: 20px; | |
user-select: none; | |
font-size: 12px; | |
color: #545454; | |
:hover { | |
color: ${getConfig("color")}; | |
::before { | |
border: solid 1px ${getConfig("color")}; | |
} | |
} | |
::before { | |
content: ""; | |
cursor: pointer; | |
position: absolute; | |
display: block; | |
top: 0; | |
left: 0; | |
width: 20px; | |
height: 20px; | |
border-radius: 2px; | |
background-color: #f2f2f2; | |
border: solid 1px #c0c0c0; | |
} | |
`; | |
export const SelectFilter: React.SFC<SelectFilterProps> = ({ | |
field, | |
values, | |
onChange | |
}) => ( | |
<Wrapper label={field.name} collapsable> | |
{field.options.values.map(val => ( | |
<div key={val}> | |
<Checkbox | |
id={`${field.name}-${val}`} | |
key={val} | |
type="checkbox" | |
checked={values.includes(val)} | |
onChange={() => { | |
if (values.includes(val)) { | |
onChange(values.filter(i => i !== val)); | |
} else { | |
onChange([...values, val]); | |
} | |
}} | |
/> | |
<Label htmlFor={`${field.name}-${val}`}>{val}</Label> | |
</div> | |
))} | |
</Wrapper> | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Icon } from "@operational/components"; | |
import { kebab, title } from "case"; | |
import isEmpty from "lodash/isEmpty"; | |
import React from "react"; | |
import styled from "react-emotion"; | |
import { FormattedMessage } from "react-intl"; | |
import { getConfig } from "../../getConfig"; | |
export interface WrapperProps { | |
label: string; | |
collapsable?: boolean; | |
} | |
export interface WrapperState { | |
isOpen: boolean; | |
} | |
const Label = styled("label")` | |
font-size: 12px; | |
font-weight: bold; | |
font-style: normal; | |
font-stretch: normal; | |
line-height: 1.25; | |
letter-spacing: normal; | |
text-align: left; | |
color: #909090; | |
display: block; | |
user-select: none; | |
/* Expand the hitbox */ | |
margin: -20px; | |
padding: 20px; | |
/* Clickable label */ | |
${(props: { clickable: boolean }) => | |
props.clickable | |
? ` | |
cursor: pointer; | |
:hover { | |
color: ${getConfig("color")}; | |
} | |
:hover + svg { | |
fill: ${getConfig("color")}; | |
} | |
` | |
: ""}; | |
`; | |
const Arrow = styled(Icon)` | |
position: absolute; | |
right: 20px; | |
top: 20px; | |
pointer-events: none; | |
`; | |
export class Wrapper extends React.Component<WrapperProps, WrapperState> { | |
public readonly state = { | |
isOpen: true | |
}; | |
public render() { | |
const { children, label, collapsable, ...props } = this.props; | |
return ( | |
<div | |
style={{ | |
padding: 20, | |
minHeight: 50, | |
borderBottom: "solid 1px #e8e8e8", | |
position: "relative" | |
}} | |
{...props} | |
> | |
{!isEmpty(label) && ( | |
<Label | |
clickable={Boolean(collapsable)} | |
onClick={() => this.setState(({ isOpen }) => ({ isOpen: !isOpen }))} | |
> | |
<FormattedMessage | |
id={`usecases.labels.${kebab(label)}`} | |
defaultMessage={title(label)} | |
/> | |
</Label> | |
)} | |
{collapsable && ( | |
<Arrow | |
name={this.state.isOpen ? "ChevronUp" : "ChevronRight"} | |
color={this.state.isOpen ? "#909090" : "#e8e8e8"} | |
/> | |
)} | |
{(!collapsable || this.state.isOpen) && ( | |
<div style={{ marginTop: 12 }}>{children}</div> | |
)} | |
</div> | |
); | |
} | |
} | |
export default Wrapper; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment