@codecademy/gamut
72.3.072.3.1-alpha.59371c.0
dist/Form/SelectDropdown/SelectDropdown.js~
dist/Form/SelectDropdown/SelectDropdown.jsModified+79−103
Index: package/dist/Form/SelectDropdown/SelectDropdown.js
===================================================================
--- package/dist/Form/SelectDropdown/SelectDropdown.js
+++ package/dist/Form/SelectDropdown/SelectDropdown.js
@@ -1,28 +1,23 @@
+import _styled from "@emotion/styled/base";
+import { screenReaderOnly } from '@codecademy/gamut-styles';
import { useTheme } from '@emotion/react';
-import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
+import { useId, useMemo, useRef, useState } from 'react';
import * as React from 'react';
-import { parseOptions } from '../utils';
-import { AbbreviatedSingleValue, CustomContainer, CustomInput, CustomValueContainer, DropdownButton, formatGroupLabel, formatOptionLabel, IconOption, MultiValueRemoveButton, MultiValueWithColorMode, onFocus, RemoveAllButton, SelectDropdownContext, TypedReactSelect } from './elements';
-import { getMemoizedStyles } from './styles';
-import { filterValueFromOptions, isMultipleSelectProps, isOptionsGrouped, isSingleSelectProps, removeValueFromSelectedOptions } from './utils';
-import { jsx as _jsx } from "react/jsx-runtime";
-const defaultProps = {
- name: undefined,
- components: {
- DropdownIndicator: DropdownButton,
- IndicatorSeparator: () => null,
- ClearIndicator: RemoveAllButton,
- SelectContainer: CustomContainer,
- ValueContainer: CustomValueContainer,
- MultiValue: MultiValueWithColorMode,
- MultiValueRemove: MultiValueRemoveButton,
- Option: IconOption,
- SingleValue: AbbreviatedSingleValue,
- Input: CustomInput
- }
-};
-const onChangeAction = 'select-option';
+import { onFocus } from './core/accessibility';
+import { getDefaultComponents } from './core/constants';
+import { getMemoizedStyles } from './core/styles';
+import { resolveNoOptionsMessage } from './core/utils';
+import { formatGroupLabel, formatOptionLabel, SelectDropdownContext, TypedReactSelect } from './elements';
+import { useNoOptionsAnnouncement } from './hooks/useNoOptionsAnnouncement';
+import { useSelectHandlers } from './hooks/useSelectHandlers';
+import { useSelectOptions } from './hooks/useSelectOptions';
+import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
+/** Announces the custom `validationMessage` menu text - see `useNoOptionsAnnouncement`. */
+const NoOptionsLiveRegion = /*#__PURE__*/_styled("div", {
+ target: "e2dtq0m0",
+ label: "NoOptionsLiveRegion"
+})(screenReaderOnly, process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9Gb3JtL1NlbGVjdERyb3Bkb3duL1NlbGVjdERyb3Bkb3duLnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUF1QjRCIiwiZmlsZSI6Ii4uLy4uLy4uL3NyYy9Gb3JtL1NlbGVjdERyb3Bkb3duL1NlbGVjdERyb3Bkb3duLnRzeCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHNjcmVlblJlYWRlck9ubHkgfSBmcm9tICdAY29kZWNhZGVteS9nYW11dC1zdHlsZXMnO1xuaW1wb3J0IHsgdXNlVGhlbWUgfSBmcm9tICdAZW1vdGlvbi9yZWFjdCc7XG5pbXBvcnQgc3R5bGVkIGZyb20gJ0BlbW90aW9uL3N0eWxlZCc7XG5pbXBvcnQgeyB1c2VJZCwgdXNlTWVtbywgdXNlUmVmLCB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7IFN0eWxlc0NvbmZpZyB9IGZyb20gJ3JlYWN0LXNlbGVjdCc7XG5cbmltcG9ydCB7IG9uRm9jdXMgfSBmcm9tICcuL2NvcmUvYWNjZXNzaWJpbGl0eSc7XG5pbXBvcnQgeyBnZXREZWZhdWx0Q29tcG9uZW50cyB9IGZyb20gJy4vY29yZS9jb25zdGFudHMnO1xuaW1wb3J0IHsgZ2V0TWVtb2l6ZWRTdHlsZXMgfSBmcm9tICcuL2NvcmUvc3R5bGVzJztcbmltcG9ydCB7IHJlc29sdmVOb09wdGlvbnNNZXNzYWdlIH0gZnJvbSAnLi9jb3JlL3V0aWxzJztcbmltcG9ydCB7XG4gIGZvcm1hdEdyb3VwTGFiZWwsXG4gIGZvcm1hdE9wdGlvbkxhYmVsLFxuICBTZWxlY3REcm9wZG93bkNvbnRleHQsXG4gIFR5cGVkUmVhY3RTZWxlY3QsXG59IGZyb20gJy4vZWxlbWVudHMnO1xuaW1wb3J0IHsgdXNlTm9PcHRpb25zQW5ub3VuY2VtZW50IH0gZnJvbSAnLi9ob29rcy91c2VOb09wdGlvbnNBbm5vdW5jZW1lbnQnO1xuaW1wb3J0IHsgdXNlU2VsZWN0SGFuZGxlcnMgfSBmcm9tICcuL2hvb2tzL3VzZVNlbGVjdEhhbmRsZXJzJztcbmltcG9ydCB7IHVzZVNlbGVjdE9wdGlvbnMgfSBmcm9tICcuL2hvb2tzL3VzZVNlbGVjdE9wdGlvbnMnO1xuaW1wb3J0IHsgU2VsZWN0RHJvcGRvd25Qcm9wcyB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKiogQW5ub3VuY2VzIHRoZSBjdXN0b20gYHZhbGlkYXRpb25NZXNzYWdlYCBtZW51IHRleHQgLSBzZWUgYHVzZU5vT3B0aW9uc0Fubm91bmNlbWVudGAuICovXG5jb25zdCBOb09wdGlvbnNMaXZlUmVnaW9uID0gc3R5bGVkLmRpdihzY3JlZW5SZWFkZXJPbmx5KTtcblxuLyoqXG4gKiBBIGZsZXhpYmxlIGRyb3Bkb3duIHNlbGVjdCBjb21wb25lbnQgYnVpbHQgb24gdG9wIG9mIHJlYWN0LXNlbGVjdC5cbiAqXG4gKiBTdXBwb3J0cyBib3RoIHNpbmdsZSBhbmQgbXVsdGktc2VsZWN0IG1vZGVzIHdpdGggY3VzdG9taXphYmxlIG9wdGlvbnMgaW5jbHVkaW5nXG4gKiBpY29ucywgc3VidGl0bGVzLCByaWdodCBsYWJlbHMsIGFuZCBhYmJyZXZpYXRpb25zLiBUaGUgY29tcG9uZW50IHByb3ZpZGVzXG4gKiBhY2Nlc3NpYmlsaXR5IGZlYXR1cmVzLCBrZXlib2FyZCBuYXZpZ2F0aW9uLCBhbmQgcmVzcG9uc2l2ZSBzdHlsaW5nLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIC8vIEJhc2ljIHNpbmdsZSBzZWxlY3RcbiAqIDxTZWxlY3REcm9wZG93blxuICogICBuYW1lPVwiY291bnRyeVwiXG4gKiAgIG9wdGlvbnM9e1tcbiAqICAgICB7IGxhYmVsOiAnVW5pdGVkIFN0YXRlcycsIHZhbHVlOiAndXMnIH0sXG4gKiAgICAgeyBsYWJlbDogJ0NhbmFkYScsIHZhbHVlOiAnY2EnIH1cbiAqICAgXX1cbiAqICAgb25DaGFuZ2U9eyhvcHRpb24pID0+IGNvbnNvbGUubG9nKG9wdGlvbil9XG4gKiAvPlxuICpcbiAqIC8vIE11bHRpLXNlbGVjdCB3aXRoIGljb25zXG4gKiA8U2VsZWN0RHJvcGRvd25cbiAqICAgbmFtZT1cInNraWxsc1wiXG4gKiAgIG11bHRpcGxlXG4gKiAgIG9wdGlvbnM9e1tcbiAqICAgICB7IGxhYmVsOiAnUmVhY3QnLCB2YWx1ZTogJ3JlYWN0JywgaWNvbjogUmVhY3RJY29uIH0sXG4gKiAgICAgeyBsYWJlbDogJ1R5cGVTY3JpcHQnLCB2YWx1ZTogJ3RzJywgaWNvbjogVHlwZVNjcmlwdEljb24gfVxuICogICBdfVxuICogICBvbkNoYW5nZT17KG9wdGlvbnMpID0+IGNvbnNvbGUubG9nKG9wdGlvbnMpfVxuICogLz5cbiAqXG4gKiAvLyBHcm91cGVkIG9wdGlvbnMgd2l0aCBleHRlbmRlZCBmZWF0dXJlc1xuICogPFNlbGVjdERyb3Bkb3duXG4gKiAgIG5hbWU9XCJjYXRlZ29yeVwiXG4gKiAgIHBsYWNlaG9sZGVyPVwiRGVmYXVsdCBwbGFjZWhvbGRlciB0ZXh0XCJcbiAqICAgb3B0aW9ucz17W1xuICogICAgIHtcbiAqICAgICAgIGxhYmVsOiAnRnJvbnRlbmQnLFxuICogICAgICAgb3B0aW9uczogW1xuICogICAgICAgICB7IGxhYmVsOiAnUmVhY3QnLCB2YWx1ZTogJ3JlYWN0Jywgc3VidGl0bGU6ICdVSSBMaWJyYXJ5JyB9LFxuICogICAgICAgICB7IGxhYmVsOiAnVnVlJywgdmFsdWU6ICd2dWUnLCBzdWJ0aXRsZTogJ1Byb2dyZXNzaXZlIEZyYW1ld29yaycgfVxuICogICAgICAgXVxuICogICAgIH1cbiAqICAgXX1cbiAqIC8+XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IFNlbGVjdERyb3Bkb3duOiBSZWFjdC5GQzxTZWxlY3REcm9wZG93blByb3BzPiA9ICh7XG4gIGNyZWF0ZU9wdGlvblBvc2l0aW9uLFxuICBkaXNhYmxlZCxcbiAgZHJvcGRvd25XaWR0aCxcbiAgZXJyb3IsXG4gIGZvcm1hdENyZWF0ZUxhYmVsID0gKGlucHV0VmFsdWU6IHN0cmluZykgPT4gYEFkZCBcIiR7aW5wdXRWYWx1ZX1cImAsXG4gIGlkLFxuICBpbnB1dFByb3BzLFxuICBpbnB1dFdpZHRoLFxuICBpc0NyZWF0YWJsZSA9IGZhbHNlLFxuICBpc1NlYXJjaGFibGU6IGlzU2VhcmNoYWJsZVByb3AgPSBmYWxzZSxcbiAgaXNWYWxpZE5ld09wdGlvbixcbiAgbWVudUFsaWdubWVudCA9ICdsZWZ0JyxcbiAgbXVsdGlwbGUsXG4gIG5hbWUsXG4gIG9uQ2hhbmdlLFxuICBvbkNyZWF0ZU9wdGlvbixcbiAgb25JbnB1dENoYW5nZSxcbiAgb25NZW51Q2xvc2UsXG4gIG9wdGlvbnMsXG4gIHBsYWNlaG9sZGVyID0gJ1NlbGVjdCBhbiBvcHRpb24nLFxuICBzaG93bk9wdGlvbnNMaW1pdCA9IDYsXG4gIHNpemUsXG4gIHZhbGlkYXRpb25NZXNzYWdlLFxuICB2YWx1ZSxcbiAgekluZGV4LFxuICAuLi5yZXN0XG59KSA9PiB7XG4gIC8vIGlzU2VhcmNoYWJsZSBpcyBmb3JjZWQgdHJ1ZSB3aGVuIGlzQ3JlYXRhYmxlIGlzIHRydWUgKENyZWF0YWJsZVNlbGVjdCByZXF1aXJlcyBhIHRleHQgaW5wdXQpXG4gIGNvbnN0IGlzU2VhcmNoYWJsZSA9IGlzQ3JlYXRhYmxlIHx8IGlzU2VhcmNoYWJsZVByb3A7XG4gIGNvbnN0IHJhd0lucHV0SWQgPSB1c2VJZCgpO1xuICBjb25zdCBpbnB1dElkID0gbmFtZSA/PyBgJHtpZCA/PyByYXdJbnB1dElkfS1zZWxlY3QtZHJvcGRvd24tJHtyYXdJbnB1dElkfWA7XG5cbiAgY29uc3QgcmVtb3ZlQWxsQnV0dG9uUmVmID0gdXNlUmVmPEhUTUxEaXZFbGVtZW50PihudWxsKTtcbiAgY29uc3Qgc2VsZWN0SW5wdXRSZWYgPSB1c2VSZWY8SFRNTERpdkVsZW1lbnQ+KG51bGwpO1xuXG4gIGNvbnN0IFtjdXJyZW50Rm9jdXNlZFZhbHVlLCBzZXRDdXJyZW50Rm9jdXNlZFZhbHVlXSA9IHVzZVN0YXRlKHVuZGVmaW5lZCk7XG5cbiAgY29uc3QgeyBzZWxlY3RPcHRpb25zLCBwYXJzZWRWYWx1ZSB9ID0gdXNlU2VsZWN0T3B0aW9ucyh7XG4gICAgb3B0aW9ucyxcbiAgICBpZCxcbiAgICBzaXplLFxuICAgIHZhbHVlOiB2YWx1ZSBhcyBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZCxcbiAgfSk7XG5cbiAgY29uc3Qgbm9PcHRpb25zTWVzc2FnZSA9IHJlc29sdmVOb09wdGlvbnNNZXNzYWdlKHZhbGlkYXRpb25NZXNzYWdlKTtcbiAgY29uc3QgeyBub09wdGlvbnNNZXNzYWdlQ29tcG9uZW50LCBhbm5vdW5jZW1lbnQsIGNsZWFyQW5ub3VuY2VtZW50IH0gPVxuICAgIHVzZU5vT3B0aW9uc0Fubm91bmNlbWVudCgpO1xuICBjb25zdCBjb21wb25lbnRzID0gdXNlTWVtbyhcbiAgICAoKSA9PiBnZXREZWZhdWx0Q29tcG9uZW50cyhub09wdGlvbnNNZXNzYWdlQ29tcG9uZW50KSxcbiAgICBbbm9PcHRpb25zTWVzc2FnZUNvbXBvbmVudF1cbiAgKTtcbiAgY29uc3QgaGFuZGxlTWVudUNsb3NlID0gKCkgPT4ge1xuICAgIGNsZWFyQW5ub3VuY2VtZW50KCk7XG4gICAgb25NZW51Q2xvc2U/LigpO1xuICB9O1xuXG4gIGNvbnN0IHsgYWN0aXZhdGVkLCBtdWx0aVZhbHVlcywgY2hhbmdlSGFuZGxlciwga2V5UHJlc3NIYW5kbGVyIH0gPVxuICAgIHVzZVNlbGVjdEhhbmRsZXJzKHtcbiAgICAgIG9uQ2hhbmdlLFxuICAgICAgbXVsdGlwbGUsXG4gICAgICBvbkNyZWF0ZU9wdGlvbixcbiAgICAgIHNlbGVjdE9wdGlvbnMsXG4gICAgICB2YWx1ZSxcbiAgICAgIGN1cnJlbnRGb2N1c2VkVmFsdWUsXG4gICAgICByZW1vdmVBbGxCdXR0b25SZWYsXG4gICAgfSk7XG5cbiAgY29uc3QgdGhlbWUgPSB1c2VUaGVtZSgpO1xuICBjb25zdCBtZW1vaXplZFN0eWxlcyA9IHVzZU1lbW8oKCk6IFN0eWxlc0NvbmZpZzxhbnksIGZhbHNlPiA9PiB7XG4gICAgcmV0dXJuIGdldE1lbW9pemVkU3R5bGVzKHRoZW1lLCB6SW5kZXgpO1xuICB9LCBbdGhlbWUsIHpJbmRleF0pO1xuXG4gIHJldHVybiAoXG4gICAgPFNlbGVjdERyb3Bkb3duQ29udGV4dC5Qcm92aWRlclxuICAgICAgdmFsdWU9e3tcbiAgICAgICAgY3VycmVudEZvY3VzZWRWYWx1ZSxcbiAgICAgICAgc2V0Q3VycmVudEZvY3VzZWRWYWx1ZSxcbiAgICAgICAgcmVtb3ZlQWxsQnV0dG9uUmVmLFxuICAgICAgICBzZWxlY3RJbnB1dFJlZixcbiAgICAgIH19XG4gICAgPlxuICAgICAgPFR5cGVkUmVhY3RTZWxlY3RcbiAgICAgICAgYWN0aXZhdGVkPXthY3RpdmF0ZWR9XG4gICAgICAgIGFyaWEtbGl2ZT1cImFzc2VydGl2ZVwiXG4gICAgICAgIGFyaWFMaXZlTWVzc2FnZXM9e3sgb25Gb2N1cyB9fVxuICAgICAgICBjb21wb25lbnRzPXtjb21wb25lbnRzfVxuICAgICAgICBjcmVhdGVPcHRpb25Qb3NpdGlvbj17Y3JlYXRlT3B0aW9uUG9zaXRpb259XG4gICAgICAgIGRyb3Bkb3duV2lkdGg9e2Ryb3Bkb3duV2lkdGh9XG4gICAgICAgIGVycm9yPXtCb29sZWFuKGVycm9yKX1cbiAgICAgICAgZm9ybWF0Q3JlYXRlTGFiZWw9e2Zvcm1hdENyZWF0ZUxhYmVsfVxuICAgICAgICBmb3JtYXRHcm91cExhYmVsPXtmb3JtYXRHcm91cExhYmVsfVxuICAgICAgICBmb3JtYXRPcHRpb25MYWJlbD17Zm9ybWF0T3B0aW9uTGFiZWx9XG4gICAgICAgIGlkPXtpZCB8fCByZXN0Lmh0bWxGb3IgfHwgcmF3SW5wdXRJZH1cbiAgICAgICAgaW5wdXRJZD17aW5wdXRJZH1cbiAgICAgICAgaW5wdXRQcm9wcz17eyAuLi5pbnB1dFByb3BzIH19XG4gICAgICAgIGlucHV0V2lkdGg9e2lucHV0V2lkdGh9XG4gICAgICAgIGlzQ3JlYXRhYmxlPXtpc0NyZWF0YWJsZX1cbiAgICAgICAgaXNEaXNhYmxlZD17ZGlzYWJsZWR9XG4gICAgICAgIGlzTXVsdGk9e211bHRpcGxlfVxuICAgICAgICBpc09wdGlvbkRpc2FibGVkPXsob3B0aW9uKSA9PiBvcHRpb24uZGlzYWJsZWR9XG4gICAgICAgIGlzU2VhcmNoYWJsZT17aXNTZWFyY2hhYmxlfVxuICAgICAgICBpc1ZhbGlkTmV3T3B0aW9uPXtpc1ZhbGlkTmV3T3B0aW9ufVxuICAgICAgICBtZW51QWxpZ25tZW50PXttZW51QWxpZ25tZW50fVxuICAgICAgICBuYW1lPXtuYW1lfVxuICAgICAgICBub09wdGlvbnNNZXNzYWdlPXtub09wdGlvbnNNZXNzYWdlfVxuICAgICAgICBvcHRpb25zPXtzZWxlY3RPcHRpb25zfVxuICAgICAgICBwbGFjZWhvbGRlcj17cGxhY2Vob2xkZXJ9XG4gICAgICAgIHNlbGVjdFJlZj17c2VsZWN0SW5wdXRSZWZ9XG4gICAgICAgIHNob3duT3B0aW9uc0xpbWl0PXtzaG93bk9wdGlvbnNMaW1pdH1cbiAgICAgICAgc2l6ZT17c2l6ZX1cbiAgICAgICAgc3R5bGVzPXttZW1vaXplZFN0eWxlc31cbiAgICAgICAgdmFsdWU9e211bHRpcGxlID8gbXVsdGlWYWx1ZXMgOiBwYXJzZWRWYWx1ZX1cbiAgICAgICAgb25DaGFuZ2U9e2NoYW5nZUhhbmRsZXJ9XG4gICAgICAgIG9uSW5wdXRDaGFuZ2U9e29uSW5wdXRDaGFuZ2V9XG4gICAgICAgIG9uS2V5RG93bj17bXVsdGlwbGUgPyBrZXlQcmVzc0hhbmRsZXIgOiB1bmRlZmluZWR9XG4gICAgICAgIG9uTWVudUNsb3NlPXtoYW5kbGVNZW51Q2xvc2V9XG4gICAgICAgIHsuLi5yZXN0fVxuICAgICAgLz5cbiAgICAgIDxOb09wdGlvbnNMaXZlUmVnaW9uIGFyaWEtbGl2ZT1cInBvbGl0ZVwiIHJvbGU9XCJzdGF0dXNcIj5cbiAgICAgICAge2Fubm91bmNlbWVudH1cbiAgICAgIDwvTm9PcHRpb25zTGl2ZVJlZ2lvbj5cbiAgICA8L1NlbGVjdERyb3Bkb3duQ29udGV4dC5Qcm92aWRlcj5cbiAgKTtcbn07XG4iXX0= */");
/**
* A flexible dropdown select component built on top of react-select.
*
@@ -69,149 +64,130 @@
* />
* ```
*/
export const SelectDropdown = ({
+ createOptionPosition,
disabled,
dropdownWidth,
error,
+ formatCreateLabel = inputValue => `Add "${inputValue}"`,
id,
inputProps,
inputWidth,
- isSearchable = false,
+ isCreatable = false,
+ isSearchable: isSearchableProp = false,
+ isValidNewOption,
menuAlignment = 'left',
multiple,
name,
onChange,
+ onCreateOption,
+ onInputChange,
+ onMenuClose,
options,
placeholder = 'Select an option',
shownOptionsLimit = 6,
size,
+ validationMessage,
value,
zIndex,
...rest
}) => {
+ // isSearchable is forced true when isCreatable is true (CreatableSelect requires a text input)
+ const isSearchable = isCreatable || isSearchableProp;
const rawInputId = useId();
- const inputId = name ?? `${id}-select-dropdown-${rawInputId}`;
- const [activated, setActivated] = useState(false);
- const [currentFocusedValue, setCurrentFocusedValue] = useState(undefined);
-
- // these are used to programatically manage the focus state of our multi-select options + 'Remove all' button
+ const inputId = name ?? `${id ?? rawInputId}-select-dropdown-${rawInputId}`;
const removeAllButtonRef = useRef(null);
const selectInputRef = useRef(null);
- const selectOptions = useMemo(() => {
- if (!options || Array.isArray(options) && !options.length || typeof options === 'object' && !Array.isArray(options) && Object.keys(options).length === 0) {
- return [];
- }
- if (isOptionsGrouped(options)) {
- return options;
- }
- return parseOptions({
- options,
- id,
- size
- });
- }, [options, id, size]);
- const parsedValue = useMemo(() => {
- if (isOptionsGrouped(selectOptions)) {
- for (const group of selectOptions) {
- if (group.options) {
- const foundOption = group.options.find(option => option.value === value);
- if (foundOption) return foundOption;
- }
- }
- return undefined;
- }
- return selectOptions.find(option => option.value === value);
- }, [selectOptions, value]);
- const [multiValues, setMultiValues] = useState(multiple &&
- // To keep this efficient for non-multiSelect
- filterValueFromOptions(selectOptions, value, isOptionsGrouped(selectOptions)));
-
- // If the caller changes the initial value, let's update our value to match.
- useEffect(() => {
- const newMultiValues = filterValueFromOptions(selectOptions, value, isOptionsGrouped(selectOptions));
- if (newMultiValues !== multiValues) setMultiValues(newMultiValues);
-
- //
- // We only update this when our passed in options or value changes, not multiValues.
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [options, value]);
- const changeHandler = useCallback(optionEvent => {
- setActivated(true);
-
- // We have to do this because the version of typescript we have doesn't have the transitivity of these type guards yet. But, we will soon!
- // Should probably come with: https://codecademy.atlassian.net/browse/GM-354
- const onChangeProps = {
- onChange,
- multiple
- };
- if (isSingleSelectProps(onChangeProps)) {
- const singleOptionEvent = optionEvent;
- onChangeProps.onChange?.(singleOptionEvent, {
- action: onChangeAction,
- option: singleOptionEvent
- });
- }
- if (isMultipleSelectProps(onChangeProps)) {
- setMultiValues(optionEvent);
- onChangeProps.onChange?.(optionEvent, {
- action: onChangeAction,
- option: undefined // At the moment this isn't used, but when multi select is built for real, boom (https://codecademy.atlassian.net/browse/GM-354)
- });
- }
- }, [onChange, multiple]);
- const keyPressHandler = e => {
- if (multiple && e.key === 'Enter' && currentFocusedValue && multiValues) {
- const newMultiValues = removeValueFromSelectedOptions(multiValues, currentFocusedValue);
- if (newMultiValues !== multiValues) setMultiValues(newMultiValues);
- }
- if (removeAllButtonRef.current !== null && e.key === 'ArrowRight' && multiValues && currentFocusedValue === multiValues[multiValues.length - 1].value) {
- removeAllButtonRef.current.focus();
- }
+ const [currentFocusedValue, setCurrentFocusedValue] = useState(undefined);
+ const {
+ selectOptions,
+ parsedValue
+ } = useSelectOptions({
+ options,
+ id,
+ size,
+ value: value
+ });
+ const noOptionsMessage = resolveNoOptionsMessage(validationMessage);
+ const {
+ noOptionsMessageComponent,
+ announcement,
+ clearAnnouncement
+ } = useNoOptionsAnnouncement();
+ const components = useMemo(() => getDefaultComponents(noOptionsMessageComponent), [noOptionsMessageComponent]);
+ const handleMenuClose = () => {
+ clearAnnouncement();
+ onMenuClose?.();
};
+ const {
+ activated,
+ multiValues,
+ changeHandler,
+ keyPressHandler
+ } = useSelectHandlers({
+ onChange,
+ multiple,
+ onCreateOption,
+ selectOptions,
+ value,
+ currentFocusedValue,
+ removeAllButtonRef
+ });
const theme = useTheme();
const memoizedStyles = useMemo(() => {
return getMemoizedStyles(theme, zIndex);
}, [theme, zIndex]);
- return /*#__PURE__*/_jsx(SelectDropdownContext.Provider, {
+ return /*#__PURE__*/_jsxs(SelectDropdownContext.Provider, {
value: {
currentFocusedValue,
setCurrentFocusedValue,
removeAllButtonRef,
selectInputRef
},
- children: /*#__PURE__*/_jsx(TypedReactSelect, {
- ...defaultProps,
+ children: [/*#__PURE__*/_jsx(TypedReactSelect, {
activated: activated,
"aria-live": "assertive",
ariaLiveMessages: {
onFocus
},
+ components: components,
+ createOptionPosition: createOptionPosition,
dropdownWidth: dropdownWidth,
error: Boolean(error),
+ formatCreateLabel: formatCreateLabel,
formatGroupLabel: formatGroupLabel,
formatOptionLabel: formatOptionLabel,
id: id || rest.htmlFor || rawInputId,
inputId: inputId,
inputProps: {
...inputProps
},
inputWidth: inputWidth,
+ isCreatable: isCreatable,
isDisabled: disabled,
isMulti: multiple,
isOptionDisabled: option => option.disabled,
isSearchable: isSearchable,
+ isValidNewOption: isValidNewOption,
menuAlignment: menuAlignment,
name: name,
+ noOptionsMessage: noOptionsMessage,
options: selectOptions,
placeholder: placeholder,
selectRef: selectInputRef,
shownOptionsLimit: shownOptionsLimit,
size: size,
styles: memoizedStyles,
value: multiple ? multiValues : parsedValue,
onChange: changeHandler,
- onKeyDown: multiple ? e => keyPressHandler(e) : undefined,
+ onInputChange: onInputChange,
+ onKeyDown: multiple ? keyPressHandler : undefined,
+ onMenuClose: handleMenuClose,
...rest
- })
+ }), /*#__PURE__*/_jsx(NoOptionsLiveRegion, {
+ "aria-live": "polite",
+ role: "status",
+ children: announcement
+ })]
});
};
\ No newline at end of file