[Glitch] Add Select component
Port 218ca366533bb5b8c4d3eb163b6f2d4d1cc6f755 to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
dacbd20081
commit
3c2a06dc24
@ -2,4 +2,4 @@ export { TextInputField } from './text_input_field';
|
|||||||
export { TextAreaField } from './text_area_field';
|
export { TextAreaField } from './text_area_field';
|
||||||
export { CheckboxField, Checkbox } from './checkbox_field';
|
export { CheckboxField, Checkbox } from './checkbox_field';
|
||||||
export { ToggleField, Toggle } from './toggle_field';
|
export { ToggleField, Toggle } from './toggle_field';
|
||||||
export { SelectField } from './select_field';
|
export { SelectField, Select } from './select_field';
|
||||||
|
|||||||
@ -0,0 +1,66 @@
|
|||||||
|
.wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
/* Dropdown indicator icon */
|
||||||
|
&::after {
|
||||||
|
--icon-size: 11px;
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
inset-inline-end: 9px;
|
||||||
|
width: var(--icon-size);
|
||||||
|
background-color: var(--color-text-tertiary);
|
||||||
|
pointer-events: none;
|
||||||
|
mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='black'/></svg>");
|
||||||
|
mask-position: right center;
|
||||||
|
mask-size: var(--icon-size);
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(.select:focus-visible)::after {
|
||||||
|
background-color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:has(.select:disabled)::after {
|
||||||
|
background-color: var(--color-text-disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select {
|
||||||
|
appearance: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 41px;
|
||||||
|
padding-inline-start: 10px;
|
||||||
|
padding-inline-end: 30px;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-primary);
|
||||||
|
background: var(--color-bg-secondary);
|
||||||
|
border: 1px solid var(--color-border-primary);
|
||||||
|
border-radius: 4px;
|
||||||
|
outline: 0;
|
||||||
|
|
||||||
|
@media screen and (width <= 600px) {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: var(--outline-focus-default);
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
color: var(--color-text-disabled);
|
||||||
|
border-color: transparent;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-has-error='true'] & {
|
||||||
|
border-color: var(--color-text-error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||||
|
|
||||||
import { SelectField } from './select_field';
|
import { SelectField, Select } from './select_field';
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Components/Form Fields/SelectField',
|
title: 'Components/Form Fields/SelectField',
|
||||||
@ -8,24 +8,19 @@ const meta = {
|
|||||||
args: {
|
args: {
|
||||||
label: 'Fruit preference',
|
label: 'Fruit preference',
|
||||||
hint: 'Select your favourite fruit or not. Up to you.',
|
hint: 'Select your favourite fruit or not. Up to you.',
|
||||||
},
|
children: (
|
||||||
render(args) {
|
<>
|
||||||
// Component styles require a wrapper class at the moment
|
<option>Apple</option>
|
||||||
return (
|
<option>Banana</option>
|
||||||
<div className='simple_form'>
|
<option>Kiwi</option>
|
||||||
<SelectField {...args}>
|
<option>Lemon</option>
|
||||||
<option>Apple</option>
|
<option>Mango</option>
|
||||||
<option>Banana</option>
|
<option>Orange</option>
|
||||||
<option>Kiwi</option>
|
<option>Pomelo</option>
|
||||||
<option>Lemon</option>
|
<option>Strawberries</option>
|
||||||
<option>Mango</option>
|
<option>Something else</option>
|
||||||
<option>Orange</option>
|
</>
|
||||||
<option>Pomelo</option>
|
),
|
||||||
<option>Strawberries</option>
|
|
||||||
<option>Something else</option>
|
|
||||||
</SelectField>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
} satisfies Meta<typeof SelectField>;
|
} satisfies Meta<typeof SelectField>;
|
||||||
|
|
||||||
@ -59,3 +54,16 @@ export const WithError: Story = {
|
|||||||
hasError: true,
|
hasError: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Plain: Story = {
|
||||||
|
render(args) {
|
||||||
|
return <Select {...args} />;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Disabled: Story = {
|
||||||
|
...Plain,
|
||||||
|
args: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import type { ComponentPropsWithoutRef } from 'react';
|
import type { ComponentPropsWithoutRef } from 'react';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { FormFieldWrapper } from './form_field_wrapper';
|
import { FormFieldWrapper } from './form_field_wrapper';
|
||||||
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
import type { CommonFieldWrapperProps } from './form_field_wrapper';
|
||||||
|
import classes from './select.module.scss';
|
||||||
|
|
||||||
interface Props
|
interface Props
|
||||||
extends ComponentPropsWithoutRef<'select'>, CommonFieldWrapperProps {}
|
extends ComponentPropsWithoutRef<'select'>, CommonFieldWrapperProps {}
|
||||||
@ -25,14 +28,27 @@ export const SelectField = forwardRef<HTMLSelectElement, Props>(
|
|||||||
inputId={id}
|
inputId={id}
|
||||||
>
|
>
|
||||||
{(inputProps) => (
|
{(inputProps) => (
|
||||||
<div className='select-wrapper'>
|
<Select {...otherProps} {...inputProps} ref={ref}>
|
||||||
<select {...otherProps} {...inputProps} ref={ref}>
|
{children}
|
||||||
{children}
|
</Select>
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</FormFieldWrapper>
|
</FormFieldWrapper>
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
SelectField.displayName = 'SelectField';
|
SelectField.displayName = 'SelectField';
|
||||||
|
|
||||||
|
export const Select = forwardRef<
|
||||||
|
HTMLSelectElement,
|
||||||
|
ComponentPropsWithoutRef<'select'>
|
||||||
|
>(({ className, size, ...otherProps }, ref) => (
|
||||||
|
<div className={classes.wrapper}>
|
||||||
|
<select
|
||||||
|
{...otherProps}
|
||||||
|
className={classNames(className, classes.select)}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
|
||||||
|
Select.displayName = 'Select';
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { createSelector } from '@reduxjs/toolkit';
|
|||||||
import type { List as ImmutableList } from 'immutable';
|
import type { List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
import type { SelectItem } from '@/flavours/glitch/components/dropdown_selector';
|
import type { SelectItem } from '@/flavours/glitch/components/dropdown_selector';
|
||||||
|
import { Select } from '@/flavours/glitch/components/form_fields';
|
||||||
import type { RootState } from '@/flavours/glitch/store';
|
import type { RootState } from '@/flavours/glitch/store';
|
||||||
import { useAppSelector } from '@/flavours/glitch/store';
|
import { useAppSelector } from '@/flavours/glitch/store';
|
||||||
|
|
||||||
@ -104,19 +105,17 @@ export const RulesSection: FC<RulesSectionProps> = ({ isLoading = false }) => {
|
|||||||
defaultMessage='Language'
|
defaultMessage='Language'
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<div className='select-wrapper'>
|
<Select onChange={handleLocaleChange} id='language-select'>
|
||||||
<select onChange={handleLocaleChange} id='language-select'>
|
{localeOptions.map((option) => (
|
||||||
{localeOptions.map((option) => (
|
<option
|
||||||
<option
|
key={option.value}
|
||||||
key={option.value}
|
value={option.value}
|
||||||
value={option.value}
|
selected={option.value === selectedLocale}
|
||||||
selected={option.value === selectedLocale}
|
>
|
||||||
>
|
{option.text}
|
||||||
{option.text}
|
</option>
|
||||||
</option>
|
))}
|
||||||
))}
|
</Select>
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user