Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/components/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ const LabelWithTooltipWrapper = styled.div`
type RadioProps = PropsWithChildren<
Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>>;

export const Radio = ({ children, disabled, ...props }: RadioProps & {tooltipText?: string}) => {
export const Radio = ({ children, disabled, labelAs, ...props }: RadioProps & {
tooltipText?: string;
labelAs?: string;
}) => {

const state = useTooltipTriggerState({delay: 0});
const ref = React.useRef(null);
Expand All @@ -64,7 +67,7 @@ export const Radio = ({ children, disabled, ...props }: RadioProps & {tooltipTex
return props.tooltipText
? <div>
<LabelWithTooltipWrapper>
<StyledLabel ref={ref} isDisabled={disabled} aria-disabled={disabled} {...triggerProps}>
<StyledLabel ref={ref} as={labelAs as any} isDisabled={disabled} aria-disabled={disabled} {...triggerProps}>
<StyledInput type="radio" onFocus={() => state.open()} isDisabled={disabled} aria-disabled={disabled} {...props} />
{children}
{state.isOpen && (
Expand All @@ -73,7 +76,7 @@ export const Radio = ({ children, disabled, ...props }: RadioProps & {tooltipTex
</StyledLabel>
</LabelWithTooltipWrapper>
</div>
: <StyledLabel isDisabled={disabled} aria-disabled={disabled}>
: <StyledLabel isDisabled={disabled} as={labelAs as any} aria-disabled={disabled}>
<StyledInput type="radio" isDisabled={disabled} aria-disabled={disabled} {...props} />
{children}
</StyledLabel>;
Expand Down
35 changes: 31 additions & 4 deletions src/components/forms/controlled/inputTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ type MakeControlled<T extends React.ComponentType<any>> =
name: string;
emptyDisabledValue?: boolean;
};
type MakeControlledCheckbox<T extends React.ComponentType<any>> =
Omit<React.ComponentPropsWithoutRef<T>, 'checked'> & {
name: string;
emptyDisabledValue?: boolean;
};

const useEmptyDisabledValue = (
props: {disabled?: boolean; emptyDisabledValue?: boolean},
Expand Down Expand Up @@ -43,7 +48,7 @@ export const TextInput = (props: MakeControlled<typeof Uncontrolled.TextInput>)
return <Uncontrolled.TextInput
{...props}
name={namespace + '.' + props.name}
value={value || ''}
value={(value ?? '').toString()}
onChangeValue={onChangeValue}
/>;
};
Expand All @@ -67,10 +72,10 @@ export const TextArea = (props: MakeControlled<typeof Uncontrolled.TextArea>) =>
/>;
};

export const Radio = (props: MakeControlled<typeof Uncontrolled.Radio>) => {
export const Radio = (props: MakeControlledCheckbox<typeof Uncontrolled.Radio>) => {
const {data, namespace, setInput} = useFormHelpers();

const onChangeValue = (value: boolean | undefined) => {
const onChangeValue = (value: string) => {
props.onChangeValue?.(value);
setInput.field(props.name)(value);
};
Expand All @@ -85,7 +90,7 @@ export const Radio = (props: MakeControlled<typeof Uncontrolled.Radio>) => {
/>;
};

export const Checkbox = (props: MakeControlled<typeof Uncontrolled.Checkbox>) => {
export const Checkbox = (props: MakeControlledCheckbox<typeof Uncontrolled.Checkbox>) => {
const {data, namespace, setInput} = useFormHelpers();

const onChangeValue = (value: boolean | undefined) => {
Expand Down Expand Up @@ -171,3 +176,25 @@ export const File = (props: MakeControlled<typeof Uncontrolled.File>) => {
onChangeValue={onChangeValue}
/>;
};

export const RangeInput = (props: MakeControlled<typeof Uncontrolled.RangeInput>) => {
const {data, namespace, setInput} = useFormHelpers();

const onChangeValue = (value: number | undefined) => {
props.onChangeValue?.(value);
setInput.field(props.name)(value);
};

const value = data[props.name];
const numberValue = parseFloat((value ?? '').toString());
const formValue = isNaN(numberValue) ? '' : numberValue;

useEmptyDisabledValue(props, formValue, onChangeValue);

return <Uncontrolled.RangeInput
{...props}
name={namespace + '.' + props.name}
value={formValue}
onChangeValue={onChangeValue}
/>;
}
11 changes: 9 additions & 2 deletions src/components/forms/uncontrolled/inputType.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from "styled-components";
import { Checkbox } from "./inputTypes";
import { Checkbox, RangeInput } from "./inputTypes";


const CheckboxGroup = styled.div`
Expand Down Expand Up @@ -39,4 +39,11 @@ export const disabledCheckbox = () => <>
{renderCheckboxes({error: [], disabled: true, label: 'Checkbox Label', variant: 'disabled', size: 1.6})}
{renderCheckboxes({error: [], disabled: true, label: 'Checkbox Label', variant: 'disabled', size: 1.8})}
{renderCheckboxes({error: [], disabled: true, label: 'Checkbox Label', variant: 'disabled', size: 2.0})}
</>;
</>;

export const slider = () => <>
<RangeInput min={0} max={100} defaultValue={50} label="Label" name="name" help="Help text" />
<RangeInput min={0} max={100} defaultValue={50} label="Label" name="name" help="Help text"
labels={[{value: 0, label: '0%'}, {value: 50, label: '50%'}, {value: 100, label: '100%'}]}
/>
</>;
53 changes: 50 additions & 3 deletions src/components/forms/uncontrolled/inputTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export const Select = ({
* radio element
*/
type RadioProps = React.ComponentPropsWithoutRef<'input'> & InputProps & {
onChangeValue?: (value: boolean | undefined) => void;
onChangeValue?: (value: string) => void;
wrapperProps?: React.ComponentPropsWithoutRef<'label'>;
tooltipText?: string;
};
Expand All @@ -182,8 +182,10 @@ export const Radio = ({
}: RadioProps) => {
return <FormInputWrapper {...wrapperProps}>
<RadioLine>
<StyledRadio {...props} onChange={e => {
onChangeValue?.(!!e.target.checked);
<StyledRadio {...props} labelAs="div" onChange={e => {
if (e.target.checked) {
onChangeValue?.(e.target.value);
}
props.onChange?.(e);
}}>
<RadioFormLabelText><RequiredIndicator show={props.required} />{label}</RadioFormLabelText>
Expand Down Expand Up @@ -271,3 +273,48 @@ export const File = ({label, help, wrapperProps, onChangeValue, uploader, value,
<HelpText value={help} />
</FormInputWrapper>;
};

const RangeInputWrapper = styled(FormInputWrapper)`
datalist {
display: flex;
justify-content: space-between;
writing-mode:unset;
flex-direction: row;
padding: 0 1em;

option {
width: 0;
text-align: center;
display: flex;
justify-content: center;
}
}
`;
type RangeProps = React.ComponentPropsWithoutRef<'input'> & InputProps & {
wrapperProps?: React.ComponentPropsWithoutRef<'label'>;
onChangeValue?: (value: number | undefined) => void;
labels?: {value: number; label: string}[];
};
export const RangeInput = ({label, help, wrapperProps, onChangeValue, labels, ...props}: RangeProps) => {
const datalistId = React.useMemo(() => `datalist-${Math.random().toString(36).substring(2, 15)}`, []);

return <RangeInputWrapper {...wrapperProps}>
<FormLabelText><RequiredIndicator show={props.required} />{label}:</FormLabelText>
<input type="range" {...props}
list={labels && labels.length > 0 ? datalistId : undefined}
onChange={e => {
const newValue = parseFloat(e.target.value);
onChangeValue?.(isNaN(newValue) ? undefined : newValue);
props.onChange?.(e);
}}
/>
{labels && labels.length > 0 && (
<datalist id={datalistId}>
{labels.map(label => (
<option key={label.value} value={label.value} label={label.label} />
))}
</datalist>
)}
<HelpText value={help} />
</RangeInputWrapper>;
}
Loading