Design system.
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

200 satır
4.8 KiB

  1. import * as React from 'react';
  2. import * as TextControlBase from '@tesseract-design/web-base-textcontrol';
  3. import * as SelectControlBase from '@tesseract-design/web-base-selectcontrol';
  4. type RenderOptionsProps = {
  5. options: SelectControlBase.SelectOption[],
  6. optionComponent?: React.ElementType,
  7. optgroupComponent?: React.ElementType,
  8. level?: number,
  9. }
  10. const RenderOptions: React.VFC<RenderOptionsProps> = ({
  11. options,
  12. optionComponent: Option = 'option',
  13. optgroupComponent: Optgroup = 'optgroup',
  14. level = 0,
  15. }: RenderOptionsProps) => (
  16. <>
  17. {
  18. options.map((o) => {
  19. if (typeof o.value !== 'undefined') {
  20. return (
  21. <Option
  22. key={`${o.label}:${o.value.toString()}`}
  23. value={o.value}
  24. >
  25. {o.label}
  26. </Option>
  27. );
  28. }
  29. if (typeof o.children !== 'undefined') {
  30. if (level === 0) {
  31. return (
  32. <Optgroup
  33. key={o.label}
  34. label={o.label}
  35. >
  36. <RenderOptions
  37. options={o.children}
  38. optionComponent={Option}
  39. optgroupComponent={Optgroup}
  40. level={level + 1}
  41. />
  42. </Optgroup>
  43. );
  44. }
  45. return (
  46. <React.Fragment
  47. key={o.label}
  48. >
  49. <Option
  50. disabled
  51. >
  52. {o.label}
  53. </Option>
  54. <RenderOptions
  55. options={o.children}
  56. optionComponent={Option}
  57. optgroupComponent={Optgroup}
  58. level={level + 1}
  59. />
  60. </React.Fragment>
  61. );
  62. }
  63. return null;
  64. })
  65. }
  66. </>
  67. );
  68. export type DropdownSelectProps = Omit<React.HTMLProps<HTMLSelectElement>, 'size' | 'style' | 'children'> & {
  69. /**
  70. * Short textual description indicating the nature of the component's value.
  71. */
  72. label?: React.ReactNode,
  73. /**
  74. * Short textual description as guidelines for valid input values.
  75. */
  76. hint?: React.ReactNode,
  77. /**
  78. * Size of the component.
  79. */
  80. size?: TextControlBase.TextControlSize,
  81. /**
  82. * Should the component display a border?
  83. */
  84. border?: boolean,
  85. /**
  86. * Should the component occupy the whole width of its parent?
  87. */
  88. block?: boolean,
  89. /**
  90. * Style of the component.
  91. */
  92. style?: TextControlBase.TextControlStyle,
  93. /**
  94. * Is the label hidden?
  95. */
  96. hiddenLabel?: boolean,
  97. /**
  98. * Options available for the component's values.
  99. */
  100. options?: SelectControlBase.SelectOption[],
  101. }
  102. /**
  103. * Component for inputting textual values.
  104. *
  105. * This component supports multiline input and adjusts its layout accordingly.
  106. */
  107. export const DropdownSelect = React.forwardRef<HTMLSelectElement, DropdownSelectProps>(
  108. (
  109. {
  110. label = '',
  111. hint = '',
  112. size = TextControlBase.TextControlSize.MEDIUM,
  113. border = false,
  114. block = false,
  115. style = TextControlBase.TextControlStyle.DEFAULT,
  116. hiddenLabel = false,
  117. multiple: _multiple,
  118. className: _className,
  119. placeholder: _placeholder,
  120. as: _as,
  121. options = [],
  122. ...etcProps
  123. }: DropdownSelectProps,
  124. ref,
  125. ) => {
  126. const styleArgs = React.useMemo<TextControlBase.TextControlBaseArgs>(() => ({
  127. block,
  128. border,
  129. size,
  130. indicator: true,
  131. style,
  132. resizable: true,
  133. predefinedValues: true,
  134. }), [block, border, size, style]);
  135. return (
  136. <div
  137. className={TextControlBase.Root(styleArgs)}
  138. >
  139. <select
  140. {...etcProps}
  141. className={TextControlBase.Input(styleArgs)}
  142. ref={ref}
  143. aria-label={label}
  144. >
  145. <RenderOptions
  146. options={options}
  147. />
  148. </select>
  149. {border && (
  150. <span
  151. data-testid="border"
  152. />
  153. )}
  154. {label && !hiddenLabel && (
  155. <div
  156. className={TextControlBase.LabelWrapper(styleArgs)}
  157. data-testid="label"
  158. >
  159. {label}
  160. </div>
  161. )}
  162. {hint && (
  163. <div
  164. className={TextControlBase.HintWrapper(styleArgs)}
  165. data-testid="hint"
  166. >
  167. <div
  168. className={TextControlBase.Hint()}
  169. >
  170. {hint}
  171. </div>
  172. </div>
  173. )}
  174. <div
  175. className={TextControlBase.IndicatorWrapper(styleArgs)}
  176. >
  177. <svg
  178. className={TextControlBase.Indicator()}
  179. viewBox="0 0 24 24"
  180. role="presentation"
  181. >
  182. <polyline
  183. points="6 9 12 15 18 9"
  184. />
  185. </svg>
  186. </div>
  187. </div>
  188. );
  189. }
  190. );
  191. DropdownSelect.displayName = 'DropdownSelect';