Custom RadioButton
This commit is contained in:
@@ -10,13 +10,13 @@ const Container = styled.label`
|
||||
user-select: none;
|
||||
|
||||
/* On mouse-over, add a grey background color */
|
||||
&:hover input ~ .custombox {
|
||||
&:hover input ~ .custom-cbox {
|
||||
background-color: #d4d0c7; /* grey1 */
|
||||
}
|
||||
`;
|
||||
|
||||
/* Hide the browser's default checkbox */
|
||||
const DefaultBox = styled.input`
|
||||
const HiddenDefaultElement = styled.input`
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
@@ -24,14 +24,14 @@ const DefaultBox = styled.input`
|
||||
`;
|
||||
|
||||
/* Create a custom checkbox */
|
||||
const CustomBox = styled.span<{checked?: boolean}>`
|
||||
const CustomCBoxElement = styled.span<{checked?: boolean}>`
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
background-color: ${(props) => props.checked ? "#002d3a" : "#efece4"}; /* dark-blue or grey2 */
|
||||
background-color: ${(props) => props.checked ? "#57b2df" : "#efece4"}; /* blue1 or grey2 */
|
||||
|
||||
&:focus &:before {
|
||||
transition: box-shadow 150ms ease;
|
||||
@@ -47,7 +47,7 @@ const CustomBox = styled.span<{checked?: boolean}>`
|
||||
}
|
||||
`;
|
||||
|
||||
const Checkmark = styled.span`
|
||||
const Checkmark = styled.div`
|
||||
position: absolute;
|
||||
left: 0.375em;
|
||||
top: calc(0.25em - 1px);
|
||||
@@ -66,15 +66,15 @@ type CheckboxProps = Omit<
|
||||
const Checkbox: React.FC<CheckboxProps> = ({children, checked, ...props}) => (
|
||||
<Container>
|
||||
{children}
|
||||
<DefaultBox
|
||||
<HiddenDefaultElement
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
{...props}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
<CustomBox tabIndex={0} checked={checked} className="custombox">
|
||||
<CustomCBoxElement tabIndex={0} checked={checked} className="custom-cbox">
|
||||
{checked && (<Checkmark />)}
|
||||
</CustomBox>
|
||||
</CustomCBoxElement>
|
||||
</Container>
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
const Container = styled.label`
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-left: 2rem;
|
||||
cursor: pointer;
|
||||
font-size: 1.5rem; /* 24px */
|
||||
user-select: none;
|
||||
|
||||
/* On mouse-over, add a grey background color */
|
||||
&:hover input ~ .custom-radio {
|
||||
background-color: #d4d0c7; /* grey1 */
|
||||
}
|
||||
`;
|
||||
|
||||
const HiddenDefaultElement = styled.input`
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
width: 0;
|
||||
`;
|
||||
|
||||
const CustomRadioElement = styled.span<{checked?: boolean}>`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
background-color: ${(props) => props.checked ? "#57b2df" : "#efece4"}; /* blue1 or grey2 */
|
||||
border-radius: 50%;
|
||||
`;
|
||||
|
||||
const Indicator = styled.div`
|
||||
position: absolute;
|
||||
top: 0.25em;
|
||||
left: 0.25em;
|
||||
width: 0.5em;
|
||||
height: 0.5em;
|
||||
border-radius: 50%;
|
||||
background: white;
|
||||
`;
|
||||
|
||||
type RadioButtonProps = Omit<
|
||||
React.InputHTMLAttributes<HTMLInputElement>,
|
||||
"type"
|
||||
>;
|
||||
|
||||
const RadioButton: React.FC<RadioButtonProps> = ({
|
||||
checked,
|
||||
children,
|
||||
...props
|
||||
}) => (
|
||||
<Container>
|
||||
{children}
|
||||
<HiddenDefaultElement
|
||||
type="radio"
|
||||
checked={checked}
|
||||
{...props}
|
||||
tabIndex={-1}
|
||||
/>
|
||||
<CustomRadioElement tabIndex={0} checked={checked} className="custom-radio">
|
||||
{checked && (<Indicator />)}
|
||||
</CustomRadioElement>
|
||||
</Container>
|
||||
);
|
||||
|
||||
export default RadioButton;
|
||||
@@ -0,0 +1,74 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { WidgetProps } from "react-jsonschema-form";
|
||||
import RadioButton from "./RadioButton";
|
||||
|
||||
type RadioButtonWidgetProps = Omit<WidgetProps, "options"> & {
|
||||
options: any;
|
||||
};
|
||||
|
||||
const RadioButtonContainer = styled.div`
|
||||
margin-bottom: 0.5rem;
|
||||
`;
|
||||
|
||||
const RadioButtonWidget: React.FC<RadioButtonWidgetProps> = (props) => {
|
||||
const {
|
||||
options,
|
||||
value,
|
||||
required,
|
||||
disabled,
|
||||
readonly,
|
||||
autofocus,
|
||||
onBlur,
|
||||
onFocus,
|
||||
onChange,
|
||||
id,
|
||||
} = props;
|
||||
// Generating a unique field name to identify this set of radio buttons
|
||||
const name = Math.random().toString();
|
||||
const { enumOptions, enumDisabled, inline } = options;
|
||||
// checked={checked} has been moved above name={name}, As mentioned in #349;
|
||||
// this is a temporary fix for radio button rendering bug in React, facebook/react#7630.
|
||||
return (
|
||||
<div className="field-radio-group" id={id}>
|
||||
{enumOptions.map((option, i) => {
|
||||
const checked = option.value === value;
|
||||
const itemDisabled =
|
||||
enumDisabled && enumDisabled.indexOf(option.value) != -1;
|
||||
const disabledCls =
|
||||
disabled || itemDisabled || readonly ? "disabled" : "";
|
||||
const radio = (
|
||||
<RadioButton
|
||||
checked={checked}
|
||||
name={name}
|
||||
required={required}
|
||||
value={option.value}
|
||||
disabled={disabled || itemDisabled || readonly}
|
||||
autoFocus={autofocus && i === 0}
|
||||
onChange={() => onChange(option.value)}
|
||||
onBlur={onBlur && (event => onBlur(id, event.target.value))}
|
||||
onFocus={onFocus && (event => onFocus(id, event.target.value))}
|
||||
>
|
||||
{option.label}
|
||||
</RadioButton>
|
||||
);
|
||||
|
||||
return inline ? (
|
||||
<label key={i} className={`radio-inline ${disabledCls}`}>
|
||||
{radio}
|
||||
</label>
|
||||
) : (
|
||||
<RadioButtonContainer key={i} className={disabledCls}>
|
||||
{radio}
|
||||
</RadioButtonContainer>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
RadioButtonWidget.defaultProps = {
|
||||
autofocus: false,
|
||||
};
|
||||
|
||||
export default RadioButtonWidget;
|
||||
@@ -7,9 +7,10 @@ import { buildSchema, buildUISchema } from "./FormUtils";
|
||||
import AsideSection from "@components/AsideSection";
|
||||
import MainSection from "@components/MainSection";
|
||||
import Checkboxes from "@components/Checkbox/Checkboxes";
|
||||
import RadioButtonWidget from "@components/RadioButton/RadioButtonWidget";
|
||||
|
||||
const customWidgets = {
|
||||
// "radio": Checkbox,
|
||||
"radio": RadioButtonWidget,
|
||||
"checkboxes": Checkboxes
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user