|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- import * as React from 'react';
- import * as TextControlBase from '@tesseract-design/web-base-textcontrol';
- import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol';
-
- type RenderOptionsProps = {
- options: SelectControlBase.SelectOption[],
- optionComponent?: React.ElementType,
- optgroupComponent?: React.ElementType,
- level?: number,
- }
-
- const RenderOptions: React.VFC<RenderOptionsProps> = ({
- options,
- optionComponent: Option = 'option',
- optgroupComponent: Optgroup = 'optgroup',
- level = 0,
- }: RenderOptionsProps) => (
- <>
- {
- options.map((o) => {
- if (typeof o.value !== 'undefined') {
- return (
- <Option
- key={`${o.label}:${o.value.toString()}`}
- value={o.value}
- >
- {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 DropdownSelectProps = Omit<React.HTMLProps<HTMLSelectElement>, 'size' | 'style' | 'children'> & {
- /**
- * 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,
- /**
- * Should the component display a border?
- */
- border?: boolean,
- /**
- * Should the component occupy the whole width of its parent?
- */
- block?: boolean,
- /**
- * Style of the component.
- */
- style?: TextControlBase.TextControlStyle,
- /**
- * Is the label hidden?
- */
- hiddenLabel?: boolean,
- /**
- * Options available for the component's values.
- */
- options?: SelectControlBase.SelectOption[],
- }
-
- /**
- * Component for inputting textual values.
- *
- * This component supports multiline input and adjusts its layout accordingly.
- */
- export const DropdownSelect = React.forwardRef<HTMLSelectElement, DropdownSelectProps>(
- (
- {
- label = '',
- hint = '',
- size = TextControlBase.TextControlSize.MEDIUM,
- border = false,
- block = false,
- style = TextControlBase.TextControlStyle.DEFAULT,
- hiddenLabel = false,
- multiple: _multiple,
- className: _className,
- placeholder: _placeholder,
- as: _as,
- options = [],
- ...etcProps
- }: DropdownSelectProps,
- ref,
- ) => {
- const styleArgs = React.useMemo<TextControlBase.TextControlBaseArgs>(() => ({
- block,
- border,
- size,
- indicator: true,
- style,
- resizable: true,
- predefinedValues: true,
- }), [block, border, size, style]);
-
- return (
- <div
- className={TextControlBase.Root(styleArgs)}
- >
- <select
- {...etcProps}
- className={TextControlBase.Input(styleArgs)}
- ref={ref}
- aria-label={label}
- >
- <RenderOptions
- options={options}
- />
- </select>
- {border && (
- <span
- data-testid="border"
- />
- )}
- {label && !hiddenLabel && (
- <div
- className={TextControlBase.LabelWrapper(styleArgs)}
- data-testid="label"
- >
- {label}
- </div>
- )}
- {hint && (
- <div
- className={TextControlBase.HintWrapper(styleArgs)}
- data-testid="hint"
- >
- <div
- className={TextControlBase.Hint()}
- >
- {hint}
- </div>
- </div>
- )}
- <div
- className={TextControlBase.IndicatorWrapper(styleArgs)}
- >
- <svg
- className={TextControlBase.Indicator()}
- viewBox="0 0 24 24"
- role="presentation"
- >
- <polyline
- points="6 9 12 15 18 9"
- />
- </svg>
- </div>
- </div>
- );
- }
- );
-
- DropdownSelect.displayName = 'DropdownSelect';
|