From e2eff909dd13d27d06826292f832f4e2c21ced76 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> Date: Sat, 16 Jan 2021 22:33:18 +0300 Subject: Rewrites Select Component Rewrites select to be more accessible, and to have more predictable behavior across browsers and devices. Signed-off-by: Hassan Abouelela <47495861+HassanAbouelela@users.noreply.github.com> --- src/components/InputTypes/Select.tsx | 154 ++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/components/InputTypes/Select.tsx b/src/components/InputTypes/Select.tsx index de763bf..74c154b 100644 --- a/src/components/InputTypes/Select.tsx +++ b/src/components/InputTypes/Select.tsx @@ -1,43 +1,60 @@ /** @jsx jsx */ import { jsx, css } from "@emotion/react"; import React from "react"; +import { hiddenInput } from "../../commonStyles"; interface SelectProps { options: Array, state_dict: Map } -interface HandlerProps { - props: SelectProps, - ref: React.RefObject -} - const containerStyles = css` - .container { - display: inline-block; - position: relative; + position: relative; + width: min(20rem, 90%); - width: min(20rem, 90%); - height: 100%; - min-height: 2rem; + color: black; + cursor: pointer; - background: whitesmoke; + :focus-within .selected_container { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; - color: black; - text-align: center; + border-bottom-color: transparent; + } +`; - margin-bottom: 0; +const mainWindowStyles = css` + display: inline-block; + position: relative; + background: whitesmoke; - border: 0.1rem solid black; - border-radius: 8px; + width: 100%; + height: 100%; + min-height: 2.5rem; + + margin-bottom: 0; - transition: border-radius 400ms; + overflow: hidden; + z-index: 1; + + :hover, :focus-within { + background-color: lightgray; } - .container.active { - height: auto; - border-radius: 8px 8px 0 0; + .selected_option { + position: absolute; + height: 100%; + width: 100%; + + outline: none; + padding-left: 0.75rem; + line-height: 250%; } + + border: 0.1rem solid black; + border-radius: 8px; + + transition: border-radius 400ms; `; const arrowStyles = css` @@ -58,83 +75,108 @@ const arrowStyles = css` transition: transform 400ms; } - .active .arrow { + :focus-within .arrow { transform: translateY(40%) rotate(225deg); } `; -const optionContainer = css` +const optionContainerStyles = css` .option_container { - display: block; position: absolute; width: 100%; + height: 0; - /* Need to account for margin */ - left: -0.1rem; + top: 2.3rem; + padding-top: 0.2rem; visibility: hidden; opacity: 0; - background: whitesmoke; overflow: hidden; + background: whitesmoke; border: 0.1rem solid black; border-radius: 0 0 8px 8px; border-top: none; transition: opacity 400ms, visibility 400ms; + + * { + cursor: pointer; + } } - .active .option_container { + :focus-within .option_container { + height: auto; visibility: visible; opacity: 1; } + + .option_container .hidden { + display: none; + } `; -class Select extends React.Component { - click_handler(this: HandlerProps, event: React.MouseEvent): void { - if (!this.ref.current) { - return; - } +const inputStyles = css` + position: absolute; + width: 100%; + height: 100%; + + z-index: 2; + + margin: 0; + border: none; + outline: none; +`; - this.ref.current.classList.toggle("active"); +const optionStyles = css` + position: relative; - const target: Element = (event.target as Element); - if (target.id === "option") { - const selected_option: Element = this.ref.current.getElementsByClassName("selected_option")[0]; - const new_option_text: string = target.textContent ?? "..."; + :hover, :focus-within { + background-color: lightgray; + } - if (selected_option.textContent === "..." && target.parentElement) { - target.parentElement.remove(); - } else { - target.textContent = selected_option.textContent; - } + div { + padding: 0.75rem; + } +`; - selected_option.textContent = new_option_text; - this.props.state_dict.set("value", selected_option.textContent); +class Select extends React.Component { + handler(selected_option: React.RefObject, event: React.ChangeEvent): void { + const option_container = event.target.parentElement; + if (!option_container || !option_container.parentElement || !selected_option.current) { + return; } + + // Update stored value + this.props.state_dict.set("value", option_container.textContent); + + // Close the menu + selected_option.current.focus(); + selected_option.current.blur(); + selected_option.current.textContent = option_container.textContent; } render(): JSX.Element { - const container_ref: React.RefObject = React.createRef(); + const selected_option_ref: React.RefObject = React.createRef(); - const element: JSX.Element = ( -
- - ... + return ( +
+
+ +
...
+
-
+
{ this.props.options.map((option, index) => ( -
-
-
{option}
+
+ this.handler.call(this, selected_option_ref, event)}/> +
{option}
)) }
); - - return
{ element }
; } } -- cgit v1.2.3