Add tick marks to sliders, make using options unified across dropdowns and datalists.pull/1/head
@@ -1,4 +1,6 @@ | |||
export interface SelectOption { | |||
export type SelectOption = string | number | SelectOptionObject; | |||
interface SelectOptionObject { | |||
label: string; | |||
value?: string | number; | |||
children?: SelectOption[]; | |||
@@ -111,7 +111,7 @@ export const MaskedTextInput = React.forwardRef<MaskedTextInputDerivedElement, M | |||
/> | |||
{ | |||
label && ( | |||
<div | |||
<label | |||
data-testid="label" | |||
id={labelId} | |||
className={clsx( | |||
@@ -129,10 +129,10 @@ export const MaskedTextInput = React.forwardRef<MaskedTextInputDerivedElement, M | |||
}, | |||
)} | |||
> | |||
<div className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</div> | |||
</div> | |||
</span> | |||
</label> | |||
) | |||
} | |||
{hint && ( | |||
@@ -126,7 +126,7 @@ export const MultilineTextInput = React.forwardRef<MultilineTextInputDerivedElem | |||
/> | |||
{ | |||
label && ( | |||
<div | |||
<label | |||
data-testid="label" | |||
id={labelId} | |||
className={clsx( | |||
@@ -144,10 +144,10 @@ export const MultilineTextInput = React.forwardRef<MultilineTextInputDerivedElem | |||
}, | |||
)} | |||
> | |||
<div className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</div> | |||
</div> | |||
</span> | |||
</label> | |||
) | |||
} | |||
{hint && ( | |||
@@ -118,7 +118,7 @@ export const TextInput = React.forwardRef<TextInputDerivedElement, TextInputProp | |||
/> | |||
{ | |||
label && ( | |||
<div | |||
<label | |||
data-testid="label" | |||
id={labelId} | |||
className={clsx( | |||
@@ -136,10 +136,10 @@ export const TextInput = React.forwardRef<TextInputDerivedElement, TextInputProp | |||
}, | |||
)} | |||
> | |||
<div className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</div> | |||
</div> | |||
</span> | |||
</label> | |||
) | |||
} | |||
{hint && ( | |||
@@ -1,102 +1,27 @@ | |||
import * as React from 'react'; | |||
import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol'; | |||
import {RenderOptions} from '@tesseract-design/web-option-react'; | |||
import clsx from 'clsx'; | |||
import styles from './style.module.css'; | |||
import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol'; | |||
type SliderOrientation = 'horizontal' | 'vertical'; | |||
interface RenderOptionsProps { | |||
options: (number | SelectControlBase.SelectOption)[], | |||
optionComponent?: React.ElementType, | |||
optgroupComponent?: React.ElementType, | |||
level?: number, | |||
} | |||
const RenderOptions: React.FC<RenderOptionsProps> = ({ | |||
options, | |||
optionComponent: Option = 'option', | |||
optgroupComponent: Optgroup = 'optgroup', | |||
level = 0, | |||
}: RenderOptionsProps) => ( | |||
<> | |||
{ | |||
options.map((o) => { | |||
if (typeof o === 'number') { | |||
return ( | |||
<Option | |||
key={`${o}:${o}`} | |||
value={o} | |||
/> | |||
) | |||
} | |||
if (typeof o.value !== 'undefined') { | |||
return ( | |||
<Option | |||
key={`${o.label}:${o.value.toString()}`} | |||
value={o.value} | |||
label={o.label} | |||
> | |||
{o.label} | |||
</Option> | |||
); | |||
} | |||
if (typeof o.children !== 'undefined') { | |||
if (level === 0) { | |||
return ( | |||
<Optgroup | |||
key={o.label} | |||
label={o.label} | |||
> | |||
<RenderOptions | |||
options={o.children} | |||
optionComponent={Option} | |||
optgroupComponent={Optgroup} | |||
level={level + 1} | |||
/> | |||
</Optgroup> | |||
); | |||
} | |||
return ( | |||
<React.Fragment | |||
key={o.label} | |||
> | |||
<Option | |||
disabled | |||
> | |||
{o.label} | |||
</Option> | |||
<RenderOptions | |||
options={o.children} | |||
optionComponent={Option} | |||
optgroupComponent={Optgroup} | |||
level={level + 1} | |||
/> | |||
</React.Fragment> | |||
); | |||
} | |||
return null; | |||
}) | |||
} | |||
</> | |||
); | |||
export type SliderOrientation = 'horizontal' | 'vertical'; | |||
type SliderDerivedElement = HTMLInputElement; | |||
export interface SliderProps extends Omit<React.HTMLProps<HTMLInputElement>, 'type'> { | |||
orient?: SliderOrientation; | |||
tickMarks?: (number | SelectControlBase.SelectOption)[]; | |||
children?: React.ReactNode; | |||
length?: React.CSSProperties['width']; | |||
} | |||
export const Slider = React.forwardRef<SliderDerivedElement, SliderProps>(({ | |||
className, | |||
style, | |||
tickMarks = [], | |||
children, | |||
orient = 'horizontal', | |||
length, | |||
min = 0, | |||
max = 100, | |||
...etcProps | |||
}, forwardedRef) => { | |||
const [browser, setBrowser] = React.useState<string>(); | |||
@@ -115,39 +40,53 @@ export const Slider = React.forwardRef<SliderDerivedElement, SliderProps>(({ | |||
const tickMarkId = React.useId(); | |||
React.useEffect(() => { | |||
if (!(typeof ref === 'object' && ref.current)) { | |||
if (!(typeof ref === 'object' && ref)) { | |||
return; | |||
} | |||
const {current: slider} = ref; | |||
if (!slider) { | |||
return; | |||
} | |||
const isFirefox = browser === 'firefox'; | |||
const parent = slider?.parentElement as HTMLElement; | |||
const wrapper = slider?.parentElement as HTMLElement; | |||
const parent = wrapper?.parentElement as HTMLElement; | |||
const grandParent = parent?.parentElement as HTMLElement; | |||
if (isFirefox) { | |||
slider.setAttribute('orient', orient); | |||
slider.removeAttribute('data-orient'); | |||
wrapper.dataset[browser] = orient; | |||
wrapper.removeAttribute('data-orient'); | |||
grandParent.style.width = '0px'; | |||
} | |||
return () => { | |||
if (slider && isFirefox) { | |||
grandParent.style.width = 'auto'; | |||
slider.dataset.orient = slider.getAttribute(orient) ?? undefined; | |||
wrapper.removeAttribute(`data-${browser}`); | |||
wrapper.dataset.orient = slider.getAttribute(orient) ?? undefined; | |||
slider.removeAttribute('orient'); | |||
} | |||
}; | |||
}, [ref, orient, browser]); | |||
React.useEffect(() => { | |||
if (!(typeof ref === 'object' && ref.current)) { | |||
if (!(typeof ref === 'object' && ref)) { | |||
return; | |||
} | |||
const {current: slider} = ref; | |||
const parent = slider?.parentElement as HTMLElement; | |||
if (!slider) { | |||
return; | |||
} | |||
const wrapper = slider?.parentElement as HTMLElement; | |||
const parent = wrapper?.parentElement as HTMLElement; | |||
const grandParent = parent?.parentElement as HTMLElement; | |||
const isNotFirefox = typeof browser === 'string' && browser !== 'firefox'; | |||
if (isNotFirefox) { | |||
wrapper.dataset[browser] = orient; | |||
} | |||
const shouldEffectExecute = isNotFirefox && orient === 'vertical' && slider && parent && grandParent; | |||
if (shouldEffectExecute) { | |||
const trueHeight = parent.clientWidth; | |||
@@ -166,22 +105,52 @@ export const Slider = React.forwardRef<SliderDerivedElement, SliderProps>(({ | |||
grandParent.removeAttribute('data-height'); | |||
grandParent.removeAttribute('data-width'); | |||
} | |||
wrapper.removeAttribute(`data-${browser}`); | |||
}; | |||
}, [ref, orient, browser]); | |||
React.useEffect(() => { | |||
if (!(typeof ref === 'object' && ref)) { | |||
return; | |||
} | |||
const {current: slider} = ref; | |||
if (!slider) { | |||
return; | |||
} | |||
const isFirefox = browser === 'firefox'; | |||
const isNotFirefox = typeof browser === 'string' && browser !== 'firefox'; | |||
const tickMarkContainer = slider.nextElementSibling; | |||
if (tickMarkContainer) { | |||
const tickMarks = tickMarkContainer.children[0].children; | |||
Array.from(tickMarks).forEach((tickMarkRaw) => { | |||
const tickMark = tickMarkRaw as HTMLElement; | |||
const offset = tickMark.dataset.offset as string; | |||
if (isNotFirefox) { | |||
tickMark.style.left = offset; | |||
tickMark.style.bottom = ''; | |||
} else if (isFirefox && orient === 'horizontal') { | |||
tickMark.style.left = offset; | |||
tickMark.style.bottom = ''; | |||
} else { | |||
tickMark.style.bottom = offset; | |||
tickMark.style.left = ''; | |||
} | |||
}); | |||
} | |||
}, [ref, orient, browser]); | |||
const block = typeof length === 'string' && length.trim() === '100%'; | |||
return ( | |||
<> | |||
{ | |||
tickMarks.length > 0 | |||
children | |||
&& ( | |||
<datalist | |||
id={tickMarkId} | |||
> | |||
<RenderOptions | |||
options={tickMarks} | |||
/> | |||
{children} | |||
</datalist> | |||
) | |||
} | |||
@@ -203,18 +172,59 @@ export const Slider = React.forwardRef<SliderDerivedElement, SliderProps>(({ | |||
position: 'relative', | |||
}} | |||
> | |||
<input | |||
{...etcProps} | |||
ref={ref} | |||
type="range" | |||
data-orient={orient} | |||
<div | |||
className={clsx( | |||
styles.slider, | |||
'w-full h-full bg-inherit block text-primary ring-secondary/50 rounded-full', | |||
'focus:text-secondary focus:outline-0 focus:ring-4', | |||
'active:text-tertiary active:ring-tertiary/50', | |||
styles['slider-wrapper'], | |||
'flex' | |||
)} | |||
data-orient={orient} | |||
> | |||
<input | |||
{...etcProps} | |||
ref={ref} | |||
min={min} | |||
max={max} | |||
type="range" | |||
list={children ? tickMarkId : undefined} | |||
className={clsx( | |||
styles.slider, | |||
'w-full h-full bg-inherit block text-primary ring-secondary/50 rounded-full', | |||
'focus:text-secondary focus:outline-0 focus:ring-4', | |||
'active:text-tertiary active:ring-tertiary/50', | |||
)} | |||
/> | |||
{Array.isArray(children) && ( | |||
<div className={clsx( | |||
styles['tick-mark-container'], | |||
)}> | |||
<div className="relative w-full h-full"> | |||
{children.map((c) => ( | |||
<div | |||
key={c.props.value} | |||
className={clsx( | |||
styles['tick-mark'], | |||
'absolute w-full h-full box-border', | |||
)} | |||
data-offset={`${(Number(c.props.value) - Number(min)) / (Number(max) - Number(min)) * 100}%`} | |||
> | |||
{/* TODO fix translateX */} | |||
<div | |||
className="flex flex-col text-xs items-center justify-between translate-x-[-50%] h-full" | |||
> | |||
<div | |||
className={clsx( | |||
'w-[1px] h-2', | |||
'bg-current', | |||
)} | |||
/> | |||
{c.props.children} | |||
</div> | |||
</div> | |||
))} | |||
</div> | |||
</div> | |||
)} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
</> | |||
@@ -11,12 +11,14 @@ | |||
.slider::-webkit-slider-container { | |||
width: 100%; | |||
height: 100%; | |||
min-block-size: 0; | |||
background-color: rgb(var(--color-primary) / 50%); | |||
border-radius: 9999px; | |||
display: block; | |||
box-sizing: border-box; | |||
background-clip: content-box; | |||
padding: 0.25em; | |||
appearance: none; | |||
} | |||
.slider::-webkit-slider-runnable-track { | |||
@@ -32,7 +34,7 @@ | |||
.slider::-webkit-slider-thumb { | |||
width: 1em; | |||
height: 200%; | |||
height: 1em; | |||
margin: -0.25em 0 0 0; | |||
border-radius: 9999px; | |||
@@ -60,7 +62,20 @@ | |||
box-shadow: -100000.5em 0 0 100000em rgb(var(--color-tertiary) / 50%); | |||
} | |||
.slider[data-orient='vertical'] { | |||
.slider-wrapper[data-orient='horizontal'] { | |||
flex-direction: column; | |||
} | |||
.slider-wrapper[data-firefox] { | |||
flex-direction: column; | |||
} | |||
.slider-wrapper[data-firefox='vertical'] { | |||
flex-direction: row; | |||
} | |||
.slider-wrapper[data-orient='vertical'] { | |||
flex-direction: column; | |||
rotate: -90deg; | |||
translate: calc(-100% + 0.5em * 2); | |||
transform-origin: calc(100% - 0.5em) 0.5em; | |||
@@ -125,3 +140,22 @@ | |||
.slider[orient='vertical']:active::-moz-range-thumb { | |||
box-shadow: 0 100000.5em 0 100000em rgb(var(--color-tertiary) / 50%); | |||
} | |||
.slider[orient='vertical'] + .tick-mark-container { | |||
flex-direction: row; | |||
} | |||
.slider-wrapper[data-chrome] > input + * { | |||
padding: 0 0.5em; | |||
height: 1.5em; | |||
} | |||
.slider-wrapper[data-firefox='horizontal'] > input + * { | |||
padding: 0 0.5em; | |||
height: 1.5em; | |||
} | |||
.slider-wrapper[data-firefox='vertical'] > input + * { | |||
padding: 0.5em 0; | |||
width: 1.5em; | |||
} |
@@ -113,7 +113,7 @@ export const Spinner = React.forwardRef<SpinnerDerivedElement, SpinnerProps>( | |||
/> | |||
{ | |||
label && ( | |||
<div | |||
<label | |||
data-testid="label" | |||
id={labelId} | |||
className={clsx( | |||
@@ -131,10 +131,10 @@ export const Spinner = React.forwardRef<SpinnerDerivedElement, SpinnerProps>( | |||
}, | |||
)} | |||
> | |||
<div className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</div> | |||
</div> | |||
</span> | |||
</label> | |||
) | |||
} | |||
{hint && ( | |||
@@ -0,0 +1,203 @@ | |||
import * as React from 'react'; | |||
import * as TextControlBase from '@tesseract-design/web-base-textcontrol'; | |||
import clsx from 'clsx'; | |||
type ComboBoxDerivedElement = HTMLInputElement; | |||
export interface ComboBoxProps extends Omit<React.HTMLProps<ComboBoxDerivedElement>, 'size' | 'type' | 'style' | 'label' | 'list'> { | |||
/** | |||
* Short textual description indicating the nature of the component's value. | |||
*/ | |||
label?: React.ReactNode, | |||
/** | |||
* Short textual description as guidelines for valid input values. | |||
*/ | |||
hint?: React.ReactNode, | |||
/** | |||
* Size of the component. | |||
*/ | |||
size?: TextControlBase.TextControlSize, | |||
/** | |||
* Additional description, usually graphical, indicating the nature of the component's value. | |||
*/ | |||
indicator?: React.ReactNode, | |||
/** | |||
* Should the component display a border? | |||
*/ | |||
border?: boolean, | |||
/** | |||
* Should the component occupy the whole width of its parent? | |||
*/ | |||
block?: boolean, | |||
/** | |||
* Type of the component value. | |||
*/ | |||
type?: TextControlBase.TextControlInputType, | |||
/** | |||
* Style of the component. | |||
*/ | |||
variant?: TextControlBase.TextControlVariant, | |||
/** | |||
* Is the label hidden? | |||
*/ | |||
hiddenLabel?: boolean, | |||
} | |||
/** | |||
* Component for inputting textual values. | |||
* | |||
* This component supports multiline input and adjusts its layout accordingly. | |||
*/ | |||
export const ComboBox = React.forwardRef<ComboBoxDerivedElement, ComboBoxProps>( | |||
( | |||
{ | |||
label = '', | |||
hint = '', | |||
indicator, | |||
size = 'medium' as const, | |||
border = false, | |||
block = false, | |||
type = 'text' as const, | |||
variant = 'default' as const, | |||
hiddenLabel = false, | |||
className, | |||
...etcProps | |||
}: ComboBoxProps, | |||
ref, | |||
) => { | |||
const labelId = React.useId(); | |||
return ( | |||
<div | |||
className={clsx( | |||
'relative rounded ring-secondary/50', | |||
'focus-within:ring-4', | |||
{ | |||
'block': block, | |||
'inline-block align-middle': !block, | |||
}, | |||
className, | |||
)} | |||
> | |||
<input | |||
{...etcProps} | |||
ref={ref} | |||
aria-labelledby={labelId} | |||
type={type} | |||
data-testid="input" | |||
className={clsx( | |||
'bg-negative rounded-inherit w-full peer block', | |||
'focus:outline-0', | |||
'disabled:opacity-50 disabled:cursor-not-allowed', | |||
{ | |||
'text-xxs': size === 'small', | |||
'text-xs': size === 'medium', | |||
}, | |||
{ | |||
'pl-4': variant === 'default', | |||
'pl-1.5': variant === 'alternate', | |||
}, | |||
{ | |||
'pt-4': variant === 'alternate', | |||
}, | |||
{ | |||
'pr-4': variant === 'default' && !indicator, | |||
'pr-1.5': variant === 'alternate' && !indicator, | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
{ | |||
'h-10': size === 'small', | |||
'h-12': size === 'medium', | |||
'h-16': size === 'large', | |||
}, | |||
)} | |||
/> | |||
{ | |||
label && ( | |||
<label | |||
data-testid="label" | |||
id={labelId} | |||
className={clsx( | |||
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative', | |||
{ | |||
'sr-only': hiddenLabel, | |||
}, | |||
{ | |||
'pr-1': !indicator, | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
)} | |||
> | |||
<span className="w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</span> | |||
</label> | |||
) | |||
} | |||
{hint && ( | |||
<div | |||
data-testid="hint" | |||
className={clsx( | |||
'absolute left-0 px-1 pointer-events-none text-xxs peer-disabled:opacity-50 leading-none w-full bg-negative', | |||
{ | |||
'bottom-0 pl-4 pb-1': variant === 'default', | |||
'top-0.5': variant === 'alternate', | |||
}, | |||
{ | |||
'pt-2': variant === 'alternate' && size === 'small', | |||
'pt-3': variant === 'alternate' && size !== 'small', | |||
}, | |||
{ | |||
'pr-4': !indicator && variant === 'default', | |||
'pr-1': !indicator && variant === 'alternate', | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
)} | |||
> | |||
<div | |||
className="opacity-50 whitespace-nowrap w-full h-[1.1em] overflow-hidden text-ellipsis" | |||
> | |||
{hint} | |||
</div> | |||
</div> | |||
)} | |||
{indicator && ( | |||
<div | |||
className={clsx( | |||
'text-center flex items-center justify-center peer-disabled:opacity-50 aspect-square absolute bottom-0 right-0 pointer-events-none', | |||
{ | |||
'w-10': size === 'small', | |||
'w-12': size === 'medium', | |||
'w-16': size === 'large', | |||
}, | |||
)} | |||
> | |||
{indicator} | |||
</div> | |||
)} | |||
{ | |||
border && ( | |||
<span | |||
data-testid="border" | |||
className="absolute z-[1] peer-disabled:opacity-50 inset-0 rounded-inherit border-2 border-primary pointer-events-none peer-focus:border-secondary" | |||
/> | |||
) | |||
} | |||
</div> | |||
); | |||
} | |||
); | |||
ComboBox.displayName = 'ComboBox'; |
@@ -1,5 +1,210 @@ | |||
export const DropdownSelect = () => { | |||
return ( | |||
<select /> | |||
) | |||
}; | |||
import * as React from 'react'; | |||
import * as TextControlBase from '@tesseract-design/web-base-textcontrol'; | |||
import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol'; | |||
import clsx from 'clsx'; | |||
import {RenderOptions} from '@/categories/option/react'; | |||
type DropdownSelectDerivedElement = HTMLSelectElement; | |||
export interface DropdownSelectProps extends Omit<React.HTMLProps<DropdownSelectDerivedElement>, 'size' | 'type' | 'style' | 'label' | 'list'> { | |||
/** | |||
* Short textual description indicating the nature of the component's value. | |||
*/ | |||
label?: React.ReactNode, | |||
/** | |||
* Short textual description as guidelines for valid input values. | |||
*/ | |||
hint?: React.ReactNode, | |||
/** | |||
* Size of the component. | |||
*/ | |||
size?: TextControlBase.TextControlSize, | |||
/** | |||
* Additional description, usually graphical, indicating the nature of the component's value. | |||
*/ | |||
indicator?: React.ReactNode, | |||
/** | |||
* Should the component display a border? | |||
*/ | |||
border?: boolean, | |||
/** | |||
* Should the component occupy the whole width of its parent? | |||
*/ | |||
block?: boolean, | |||
/** | |||
* Type of the component value. | |||
*/ | |||
type?: TextControlBase.TextControlInputType, | |||
/** | |||
* Style of the component. | |||
*/ | |||
variant?: TextControlBase.TextControlVariant, | |||
/** | |||
* Is the label hidden? | |||
*/ | |||
hiddenLabel?: boolean, | |||
options?: SelectControlBase.SelectOption[], | |||
} | |||
/** | |||
* Component for inputting textual values. | |||
* | |||
* This component supports multiline input and adjusts its layout accordingly. | |||
*/ | |||
export const DropdownSelect = React.forwardRef<DropdownSelectDerivedElement, DropdownSelectProps>( | |||
( | |||
{ | |||
label = '', | |||
hint = '', | |||
indicator, | |||
size = 'medium' as const, | |||
border = false, | |||
block = false, | |||
type = 'text' as const, | |||
variant = 'default' as const, | |||
hiddenLabel = false, | |||
className, | |||
options = [], | |||
children, | |||
...etcProps | |||
}: DropdownSelectProps, | |||
ref, | |||
) => { | |||
const labelId = React.useId(); | |||
console.log(children); | |||
return ( | |||
<div | |||
className={clsx( | |||
'relative rounded ring-secondary/50 min-w-48', | |||
'focus-within:ring-4', | |||
{ | |||
'block': block, | |||
'inline-block align-middle': !block, | |||
}, | |||
className, | |||
)} | |||
> | |||
<select | |||
{...etcProps} | |||
ref={ref} | |||
aria-labelledby={labelId} | |||
data-testid="input" | |||
className={clsx( | |||
'bg-negative rounded-inherit w-full peer block appearance-none', | |||
'focus:outline-0', | |||
'disabled:opacity-50 disabled:cursor-not-allowed', | |||
{ | |||
'text-xxs': size === 'small', | |||
'text-xs': size === 'medium', | |||
}, | |||
{ | |||
'pl-4': variant === 'default', | |||
'pl-1.5': variant === 'alternate', | |||
}, | |||
{ | |||
'pt-4': variant === 'alternate', | |||
}, | |||
{ | |||
'pr-4': variant === 'default' && !indicator, | |||
'pr-1.5': variant === 'alternate' && !indicator, | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
{ | |||
'h-10': size === 'small', | |||
'h-12': size === 'medium', | |||
'h-16': size === 'large', | |||
}, | |||
)} | |||
> | |||
{children} | |||
</select> | |||
{ | |||
label && ( | |||
<label | |||
data-testid="label" | |||
id={labelId} | |||
className={clsx( | |||
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative', | |||
{ | |||
'sr-only': hiddenLabel, | |||
}, | |||
{ | |||
'pr-1': !indicator, | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
)} | |||
> | |||
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</span> | |||
</label> | |||
) | |||
} | |||
{hint && ( | |||
<div | |||
data-testid="hint" | |||
className={clsx( | |||
'absolute left-0 px-1 pointer-events-none text-xxs peer-disabled:opacity-50 leading-none w-full bg-negative', | |||
{ | |||
'bottom-0 pl-4 pb-1': variant === 'default', | |||
'top-0.5': variant === 'alternate', | |||
}, | |||
{ | |||
'pt-2': variant === 'alternate' && size === 'small', | |||
'pt-3': variant === 'alternate' && size !== 'small', | |||
}, | |||
{ | |||
'pr-4': !indicator && variant === 'default', | |||
'pr-1': !indicator && variant === 'alternate', | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
)} | |||
> | |||
<div | |||
className="opacity-50 whitespace-nowrap w-full h-[1.1em] overflow-hidden text-ellipsis" | |||
> | |||
{hint} | |||
</div> | |||
</div> | |||
)} | |||
{indicator && ( | |||
<div | |||
className={clsx( | |||
'text-center flex items-center justify-center peer-disabled:opacity-50 aspect-square absolute bottom-0 right-0 pointer-events-none', | |||
{ | |||
'w-10': size === 'small', | |||
'w-12': size === 'medium', | |||
'w-16': size === 'large', | |||
}, | |||
)} | |||
> | |||
{indicator} | |||
</div> | |||
)} | |||
{ | |||
border && ( | |||
<span | |||
data-testid="border" | |||
className="absolute z-[1] peer-disabled:opacity-50 inset-0 rounded-inherit border-2 border-primary pointer-events-none peer-focus:border-secondary" | |||
/> | |||
) | |||
} | |||
</div> | |||
); | |||
} | |||
); | |||
DropdownSelect.displayName = 'DropdownSelect'; |
@@ -0,0 +1,23 @@ | |||
import * as React from 'react'; | |||
type MenuSelectDerivedElement = HTMLSelectElement; | |||
export interface MenuSelectProps extends React.HTMLProps<MenuSelectDerivedElement> { | |||
} | |||
export const MenuSelect = React.forwardRef<MenuSelectDerivedElement, MenuSelectProps>(({ | |||
children, | |||
...etcProps | |||
}, forwardedRef) => { | |||
return ( | |||
<div> | |||
<select | |||
{...etcProps} | |||
ref={forwardedRef} | |||
/> | |||
</div> | |||
) | |||
}); | |||
MenuSelect.displayName = 'MenuSelect'; |
@@ -0,0 +1,3 @@ | |||
export const RadioButton = () => ( | |||
<input type="radio" /> | |||
); |
@@ -0,0 +1,3 @@ | |||
export const RadioTickBox = () => ( | |||
<input type="radio" /> | |||
); |
@@ -0,0 +1,76 @@ | |||
import * as SelectControlBase from '@/base/selectcontrol'; | |||
import * as React from 'react'; | |||
export interface RenderOptionsProps { | |||
options: SelectControlBase.SelectOption[], | |||
optionComponent?: React.ElementType, | |||
optgroupComponent?: React.ElementType, | |||
level?: number, | |||
} | |||
export const RenderOptions: React.FC<RenderOptionsProps> = ({ | |||
options, | |||
optionComponent: Option = 'option', | |||
optgroupComponent: Optgroup = 'optgroup', | |||
level = 0, | |||
}: RenderOptionsProps) => ( | |||
options.map((o) => { | |||
if (typeof o === 'number' || typeof o === 'string') { | |||
return ( | |||
<Option | |||
key={`${o}:${o}`} | |||
value={o} | |||
/> | |||
); | |||
} | |||
if (typeof o.value !== 'undefined') { | |||
return ( | |||
<Option | |||
key={`${o.label}:${o.value.toString()}`} | |||
value={o.value} | |||
label={o.label} | |||
> | |||
{o.label} | |||
</Option> | |||
); | |||
} | |||
if (typeof o.children !== 'undefined') { | |||
if (level === 0) { | |||
return ( | |||
<Optgroup | |||
key={o.label} | |||
label={o.label} | |||
> | |||
<RenderOptions | |||
options={o.children} | |||
optionComponent={Option} | |||
optgroupComponent={Optgroup} | |||
level={level + 1} | |||
/> | |||
</Optgroup> | |||
); | |||
} | |||
return ( | |||
<React.Fragment | |||
key={o.label} | |||
> | |||
<Option | |||
disabled | |||
> | |||
{o.label} | |||
</Option> | |||
<RenderOptions | |||
options={o.children} | |||
optionComponent={Option} | |||
optgroupComponent={Optgroup} | |||
level={level + 1} | |||
/> | |||
</React.Fragment> | |||
); | |||
} | |||
return null; | |||
}) | |||
); |
@@ -0,0 +1,203 @@ | |||
import * as React from 'react'; | |||
import * as TextControlBase from '@tesseract-design/web-base-textcontrol'; | |||
import clsx from 'clsx'; | |||
type TagInputDerivedElement = HTMLInputElement; | |||
export interface TagInputProps extends Omit<React.HTMLProps<TagInputDerivedElement>, 'size' | 'type' | 'style' | 'label' | 'list'> { | |||
/** | |||
* Short textual description indicating the nature of the component's value. | |||
*/ | |||
label?: React.ReactNode, | |||
/** | |||
* Short textual description as guidelines for valid input values. | |||
*/ | |||
hint?: React.ReactNode, | |||
/** | |||
* Size of the component. | |||
*/ | |||
size?: TextControlBase.TextControlSize, | |||
/** | |||
* Additional description, usually graphical, indicating the nature of the component's value. | |||
*/ | |||
indicator?: React.ReactNode, | |||
/** | |||
* Should the component display a border? | |||
*/ | |||
border?: boolean, | |||
/** | |||
* Should the component occupy the whole width of its parent? | |||
*/ | |||
block?: boolean, | |||
/** | |||
* Type of the component value. | |||
*/ | |||
type?: TextControlBase.TextControlInputType, | |||
/** | |||
* Style of the component. | |||
*/ | |||
variant?: TextControlBase.TextControlVariant, | |||
/** | |||
* Is the label hidden? | |||
*/ | |||
hiddenLabel?: boolean, | |||
} | |||
/** | |||
* Component for inputting textual values. | |||
* | |||
* This component supports multiline input and adjusts its layout accordingly. | |||
*/ | |||
export const TagInput = React.forwardRef<TagInputDerivedElement, TagInputProps>( | |||
( | |||
{ | |||
label = '', | |||
hint = '', | |||
indicator, | |||
size = 'medium' as const, | |||
border = false, | |||
block = false, | |||
type = 'text' as const, | |||
variant = 'default' as const, | |||
hiddenLabel = false, | |||
className, | |||
...etcProps | |||
}: TagInputProps, | |||
ref, | |||
) => { | |||
const labelId = React.useId(); | |||
return ( | |||
<div | |||
className={clsx( | |||
'relative rounded ring-secondary/50', | |||
'focus-within:ring-4', | |||
{ | |||
'block': block, | |||
'inline-block align-middle': !block, | |||
}, | |||
className, | |||
)} | |||
> | |||
<input | |||
{...etcProps} | |||
ref={ref} | |||
aria-labelledby={labelId} | |||
type={type} | |||
data-testid="input" | |||
className={clsx( | |||
'bg-negative rounded-inherit w-full peer block', | |||
'focus:outline-0', | |||
'disabled:opacity-50 disabled:cursor-not-allowed', | |||
{ | |||
'text-xxs': size === 'small', | |||
'text-xs': size === 'medium', | |||
}, | |||
{ | |||
'pl-4': variant === 'default', | |||
'pl-1.5': variant === 'alternate', | |||
}, | |||
{ | |||
'pt-4': variant === 'alternate', | |||
}, | |||
{ | |||
'pr-4': variant === 'default' && !indicator, | |||
'pr-1.5': variant === 'alternate' && !indicator, | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
{ | |||
'h-10': size === 'small', | |||
'h-12': size === 'medium', | |||
'h-16': size === 'large', | |||
}, | |||
)} | |||
/> | |||
{ | |||
label && ( | |||
<label | |||
data-testid="label" | |||
id={labelId} | |||
className={clsx( | |||
'absolute z-[1] w-full top-0.5 left-0 pointer-events-none pl-1 text-xxs font-bold peer-disabled:opacity-50 peer-focus:text-secondary text-primary leading-none bg-negative', | |||
{ | |||
'sr-only': hiddenLabel, | |||
}, | |||
{ | |||
'pr-1': !indicator, | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
)} | |||
> | |||
<span className="block w-full whitespace-nowrap h-[1.1em] overflow-hidden text-ellipsis"> | |||
{label} | |||
</span> | |||
</label> | |||
) | |||
} | |||
{hint && ( | |||
<div | |||
data-testid="hint" | |||
className={clsx( | |||
'absolute left-0 px-1 pointer-events-none text-xxs peer-disabled:opacity-50 leading-none w-full bg-negative', | |||
{ | |||
'bottom-0 pl-4 pb-1': variant === 'default', | |||
'top-0.5': variant === 'alternate', | |||
}, | |||
{ | |||
'pt-2': variant === 'alternate' && size === 'small', | |||
'pt-3': variant === 'alternate' && size !== 'small', | |||
}, | |||
{ | |||
'pr-4': !indicator && variant === 'default', | |||
'pr-1': !indicator && variant === 'alternate', | |||
}, | |||
{ | |||
'pr-10': indicator && size === 'small', | |||
'pr-12': indicator && size === 'medium', | |||
'pr-16': indicator && size === 'large', | |||
}, | |||
)} | |||
> | |||
<div | |||
className="opacity-50 whitespace-nowrap w-full h-[1.1em] overflow-hidden text-ellipsis" | |||
> | |||
{hint} | |||
</div> | |||
</div> | |||
)} | |||
{indicator && ( | |||
<div | |||
className={clsx( | |||
'text-center flex items-center justify-center peer-disabled:opacity-50 aspect-square absolute bottom-0 right-0 pointer-events-none', | |||
{ | |||
'w-10': size === 'small', | |||
'w-12': size === 'medium', | |||
'w-16': size === 'large', | |||
}, | |||
)} | |||
> | |||
{indicator} | |||
</div> | |||
)} | |||
{ | |||
border && ( | |||
<span | |||
data-testid="border" | |||
className="absolute z-[1] peer-disabled:opacity-50 inset-0 rounded-inherit border-2 border-primary pointer-events-none peer-focus:border-secondary" | |||
/> | |||
) | |||
} | |||
</div> | |||
); | |||
} | |||
); | |||
TagInput.displayName = 'TagInput'; |
@@ -0,0 +1,3 @@ | |||
export const ToggleButton = () => ( | |||
<input type="checkbox" /> | |||
); |
@@ -0,0 +1,3 @@ | |||
export const ToggleSwitch = () => ( | |||
<input type="checkbox" /> | |||
); |
@@ -0,0 +1,3 @@ | |||
export const ToggleTickBox = () => ( | |||
<input type="checkbox" /> | |||
); |
@@ -1 +1,10 @@ | |||
export * from './components/ComboBox'; | |||
export * from './components/DropdownSelect'; | |||
export * from './components/MenuSelect'; | |||
export * from './components/RadioButton'; | |||
export * from './components/RadioTickBox'; | |||
export * from './components/RenderOptions'; | |||
export * from './components/TagInput'; | |||
export * from './components/ToggleButton'; | |||
export * from './components/ToggleSwitch'; | |||
export * from './components/ToggleTickBox'; |
@@ -21,16 +21,30 @@ const NumberPage: NextPage = () => { | |||
<TesseractNumber.Slider | |||
min={-100} | |||
max={100} | |||
tickMarks={[{ label: 'low', value: 25, }, 50]} | |||
/> | |||
</Subsection> | |||
<Subsection title="Default (with tick marks)"> | |||
<TesseractNumber.Slider | |||
min={-100} | |||
max={100} | |||
> | |||
<option value={25}> | |||
low | |||
</option> | |||
<option value={50} /> | |||
</TesseractNumber.Slider> | |||
</Subsection> | |||
<Subsection title="Vertical"> | |||
<TesseractNumber.Slider | |||
min={-100} | |||
max={100} | |||
tickMarks={[{ label: 'low', value: 25, }, 50]} | |||
orient="vertical" | |||
/> | |||
> | |||
<option value={25}> | |||
low | |||
</option> | |||
<option value={50} /> | |||
</TesseractNumber.Slider> | |||
A | |||
</Subsection> | |||
</Section> | |||
@@ -1,8 +1,6 @@ | |||
import { NextPage } from 'next'; | |||
import { TextControlSize, TextControlVariant } from '@tesseract-design/web-base-textcontrol'; | |||
import * as Option from '@tesseract-design/web-option-react'; | |||
import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol'; | |||
import { ButtonSize, ButtonVariant } from '@tesseract-design/web-base-button'; | |||
import { DefaultLayout } from '@/components/DefaultLayout'; | |||
type Props = { | |||
@@ -70,17 +68,20 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4 my-4"> | |||
<div> | |||
<Option.DropdownSelect | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
options={options} | |||
/> | |||
> | |||
<option> | |||
Hello | |||
</option> | |||
</Option.DropdownSelect> | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
border | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -106,7 +107,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -116,7 +117,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.DropdownSelect | |||
border | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -195,7 +196,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.DropdownSelect | |||
border | |||
label="Name" | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
/> | |||
{' '} | |||
but you can call me | |||
@@ -203,7 +204,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.DropdownSelect | |||
border | |||
label="Nickname" | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
/> | |||
. | |||
</div> | |||
@@ -216,8 +217,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -227,8 +228,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.DropdownSelect | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -237,7 +238,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -247,7 +248,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.DropdownSelect | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -256,8 +257,8 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -268,8 +269,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.DropdownSelect | |||
border | |||
block | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="Select" | |||
hint="Type anything here…" | |||
options={options} | |||
@@ -277,7 +278,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="Select" | |||
hint="Type anything here…" | |||
block | |||
@@ -287,7 +288,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.DropdownSelect | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
border | |||
label="Select" | |||
hint="Type anything here…" | |||
@@ -316,7 +317,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.MenuSelect | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -327,7 +328,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.MenuSelect | |||
border | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -356,7 +357,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -367,7 +368,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.MenuSelect | |||
border | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -405,8 +406,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -417,8 +418,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.MenuSelect | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -428,7 +429,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -439,7 +440,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.MenuSelect | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -449,8 +450,8 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -462,8 +463,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.MenuSelect | |||
border | |||
block | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -472,7 +473,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -483,7 +484,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -504,7 +505,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.MenuSelect | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -516,7 +517,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.MenuSelect | |||
border | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -548,7 +549,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.MenuSelect | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -560,7 +561,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.MenuSelect | |||
border | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -618,7 +619,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.RadioButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
name="RadioButton" | |||
> | |||
@@ -637,7 +638,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.RadioButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
name="RadioButton" | |||
> | |||
@@ -655,7 +656,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.RadioButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
disabled | |||
name="RadioButton" | |||
@@ -676,7 +677,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.RadioButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
disabled | |||
name="RadioButton" | |||
@@ -695,7 +696,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.RadioButton | |||
block | |||
border | |||
size={ButtonSize.SMALL} | |||
size="small" | |||
name="RadioButton" | |||
> | |||
Button | |||
@@ -705,8 +706,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.RadioButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.SMALL} | |||
variant="filled" | |||
size="small" | |||
name="RadioButton" | |||
> | |||
Button | |||
@@ -716,7 +717,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.RadioButton | |||
block | |||
border | |||
size={ButtonSize.MEDIUM} | |||
size="medium" | |||
name="RadioButton" | |||
> | |||
Button | |||
@@ -726,8 +727,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.RadioButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.MEDIUM} | |||
variant="filled" | |||
size="medium" | |||
name="RadioButton" | |||
> | |||
Button | |||
@@ -737,7 +738,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.RadioButton | |||
block | |||
border | |||
size={ButtonSize.LARGE} | |||
size="large" | |||
name="RadioButton" | |||
> | |||
Button | |||
@@ -747,8 +748,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.RadioButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.LARGE} | |||
variant="filled" | |||
size="large" | |||
name="RadioButton" | |||
> | |||
Button | |||
@@ -776,7 +777,7 @@ const OptionPage: NextPage<Props> = ({ | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
name="RadioButton" | |||
> | |||
Button | |||
@@ -802,7 +803,7 @@ const OptionPage: NextPage<Props> = ({ | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
name="RadioButton" | |||
subtext={ | |||
<> | |||
@@ -818,7 +819,7 @@ const OptionPage: NextPage<Props> = ({ | |||
block | |||
compact | |||
border | |||
size={ButtonSize.SMALL} | |||
size="small" | |||
name="RadioButton" | |||
subtext={ | |||
<> | |||
@@ -834,8 +835,8 @@ const OptionPage: NextPage<Props> = ({ | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.SMALL} | |||
variant="filled" | |||
size="small" | |||
name="RadioButton" | |||
subtext={ | |||
<> | |||
@@ -887,7 +888,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -898,7 +899,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.TagInput | |||
enhanced | |||
border | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -927,7 +928,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -938,7 +939,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.TagInput | |||
enhanced | |||
border | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -976,8 +977,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -988,8 +989,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.TagInput | |||
enhanced | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -999,7 +1000,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1010,7 +1011,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.TagInput | |||
enhanced | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1020,8 +1021,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1033,8 +1034,8 @@ const OptionPage: NextPage<Props> = ({ | |||
enhanced | |||
border | |||
block | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1043,7 +1044,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="TagInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1054,7 +1055,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
enhanced | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
border | |||
label="TagInput" | |||
hint="Type anything here…" | |||
@@ -1088,7 +1089,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ToggleButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
> | |||
Button | |||
@@ -1105,7 +1106,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ToggleButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
> | |||
Button | |||
@@ -1121,7 +1122,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ToggleButton | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
disabled | |||
> | |||
@@ -1140,7 +1141,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ToggleButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
disabled | |||
> | |||
@@ -1159,7 +1160,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ToggleButton | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
block | |||
indeterminate | |||
> | |||
@@ -1177,7 +1178,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.ToggleButton | |||
block | |||
border | |||
size={ButtonSize.SMALL} | |||
size="small" | |||
> | |||
Button | |||
</Option.ToggleButton> | |||
@@ -1186,8 +1187,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.ToggleButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.SMALL} | |||
variant="filled" | |||
size="small" | |||
> | |||
Button | |||
</Option.ToggleButton> | |||
@@ -1196,7 +1197,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.ToggleButton | |||
block | |||
border | |||
size={ButtonSize.MEDIUM} | |||
size="medium" | |||
> | |||
Button | |||
</Option.ToggleButton> | |||
@@ -1205,8 +1206,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.ToggleButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.MEDIUM} | |||
variant="filled" | |||
size="medium" | |||
> | |||
Button | |||
</Option.ToggleButton> | |||
@@ -1215,7 +1216,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.ToggleButton | |||
block | |||
border | |||
size={ButtonSize.LARGE} | |||
size="large" | |||
> | |||
Button | |||
</Option.ToggleButton> | |||
@@ -1224,8 +1225,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.ToggleButton | |||
block | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.LARGE} | |||
variant="filled" | |||
size="large" | |||
> | |||
Button | |||
</Option.ToggleButton> | |||
@@ -1251,7 +1252,7 @@ const OptionPage: NextPage<Props> = ({ | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
> | |||
Button | |||
</Option.ToggleButton> | |||
@@ -1275,7 +1276,7 @@ const OptionPage: NextPage<Props> = ({ | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
variant="filled" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -1290,7 +1291,7 @@ const OptionPage: NextPage<Props> = ({ | |||
block | |||
compact | |||
border | |||
size={ButtonSize.SMALL} | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -1305,8 +1306,8 @@ const OptionPage: NextPage<Props> = ({ | |||
block | |||
compact | |||
border | |||
variant={ButtonVariant.FILLED} | |||
size={ButtonSize.SMALL} | |||
variant="filled" | |||
size="small" | |||
subtext={ | |||
<> | |||
Subtext | |||
@@ -1422,7 +1423,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.ComboBox | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1433,7 +1434,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ComboBox | |||
border | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1462,7 +1463,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1473,7 +1474,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ComboBox | |||
border | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1511,8 +1512,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1523,8 +1524,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ComboBox | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1534,7 +1535,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1545,7 +1546,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.ComboBox | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1555,8 +1556,8 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1568,8 +1569,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.ComboBox | |||
border | |||
block | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1578,7 +1579,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1589,7 +1590,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.ComboBox | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -1619,7 +1620,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.TagInput | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1629,7 +1630,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
border | |||
size={TextControlSize.SMALL} | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1655,7 +1656,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1665,7 +1666,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
border | |||
size={TextControlSize.LARGE} | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1700,8 +1701,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div className="grid md:grid-cols-2 gap-4"> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1711,8 +1712,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.SMALL} | |||
variant="alternate" | |||
size="small" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1721,7 +1722,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1731,7 +1732,7 @@ const OptionPage: NextPage<Props> = ({ | |||
<div> | |||
<Option.TagInput | |||
border | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1740,8 +1741,8 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1752,8 +1753,8 @@ const OptionPage: NextPage<Props> = ({ | |||
<Option.TagInput | |||
border | |||
block | |||
style={TextControlVariant.ALTERNATE} | |||
size={TextControlSize.LARGE} | |||
variant="alternate" | |||
size="large" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1761,7 +1762,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
indicator="A" | |||
@@ -1771,7 +1772,7 @@ const OptionPage: NextPage<Props> = ({ | |||
</div> | |||
<div> | |||
<Option.TagInput | |||
style={TextControlVariant.ALTERNATE} | |||
variant="alternate" | |||
border | |||
label="MultilineTextInput" | |||
hint="Type anything here…" | |||
@@ -55,8 +55,11 @@ module.exports = { | |||
10: '2.5rem', | |||
12: '3rem', | |||
16: '4rem', | |||
48: '12rem', | |||
64: '16rem', | |||
}, | |||
minHeight: { | |||
6: '1.5rem', | |||
10: '2.5rem', | |||
12: '3rem', | |||
16: '4rem', | |||