@codecademy/gamut 72.2.4-alpha.628984.0 → 72.2.4-alpha.716ed7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/agent-tools/skills/gamut-forms/SKILL.md +0 -16
  2. package/dist/Anchor/index.js +3 -3
  3. package/dist/BarChart/layout/GridLines.js +5 -5
  4. package/dist/BodyPortal/index.d.ts +4 -3
  5. package/dist/BodyPortal/index.js +3 -3
  6. package/dist/Box/props.js +2 -2
  7. package/dist/Button/shared/styles.js +2 -2
  8. package/dist/DataList/EmptyRows.js +2 -1
  9. package/dist/DatePicker/DatePickerCalendar/Calendar/CalendarWrapper.js +2 -1
  10. package/dist/DatePicker/DatePickerCalendar/Calendar/utils/elements.js +5 -5
  11. package/dist/Flyout/index.js +2 -1
  12. package/dist/Form/SelectDropdown/SelectDropdown.js +101 -48
  13. package/dist/Form/SelectDropdown/elements/constants.d.ts +8 -0
  14. package/dist/Form/SelectDropdown/elements/constants.js +9 -1
  15. package/dist/Form/SelectDropdown/elements/containers.d.ts +2 -6
  16. package/dist/Form/SelectDropdown/elements/containers.js +1 -17
  17. package/dist/Form/SelectDropdown/elements/controls.d.ts +15 -1
  18. package/dist/Form/SelectDropdown/elements/controls.js +91 -2
  19. package/dist/Form/SelectDropdown/elements/index.d.ts +1 -2
  20. package/dist/Form/SelectDropdown/elements/index.js +1 -2
  21. package/dist/Form/SelectDropdown/elements/options.d.ts +0 -1
  22. package/dist/Form/SelectDropdown/elements/options.js +2 -5
  23. package/dist/Form/SelectDropdown/{core/styles.js → styles.js} +20 -33
  24. package/dist/Form/SelectDropdown/types/component-props.d.ts +6 -54
  25. package/dist/Form/SelectDropdown/types/internal.d.ts +3 -3
  26. package/dist/Form/SelectDropdown/types/styles.d.ts +1 -5
  27. package/dist/Form/SelectDropdown/{core/utils.d.ts → utils.d.ts} +2 -12
  28. package/dist/Form/SelectDropdown/{core/utils.js → utils.js} +0 -23
  29. package/dist/Form/styles/index.d.ts +1 -1
  30. package/dist/Form/styles/index.js +1 -1
  31. package/dist/List/TableHeader.js +2 -1
  32. package/dist/List/elements.js +12 -12
  33. package/dist/Menu/elements.js +8 -8
  34. package/dist/Overlay/index.d.ts +3 -2
  35. package/dist/Overlay/index.js +3 -3
  36. package/dist/PatternBackdrop/PatternBackdrop.js +4 -4
  37. package/dist/Popover/elements.js +8 -6
  38. package/dist/Popover/styles/base.js +2 -2
  39. package/dist/Popover/styles/variants.js +2 -2
  40. package/dist/PopoverContainer/PopoverContainer.js +3 -2
  41. package/dist/Tabs/TabButton.js +4 -4
  42. package/dist/Tabs/Tabs.js +4 -4
  43. package/dist/Tabs/styles.js +2 -2
  44. package/dist/Tip/PreviewTip/elements.js +4 -4
  45. package/dist/Tip/shared/InlineTip.js +2 -1
  46. package/dist/Tip/shared/elements.js +8 -8
  47. package/dist/Toaster/index.js +2 -1
  48. package/dist/Typography/Text.js +4 -4
  49. package/package.json +6 -6
  50. package/agent-tools/skills/gamut-select-dropdown/SKILL.md +0 -236
  51. package/dist/Form/SelectDropdown/core/accessibility.d.ts +0 -3
  52. package/dist/Form/SelectDropdown/core/accessibility.js +0 -12
  53. package/dist/Form/SelectDropdown/core/constants.d.ts +0 -13
  54. package/dist/Form/SelectDropdown/core/constants.js +0 -14
  55. package/dist/Form/SelectDropdown/hooks/useSelectHandlers.d.ts +0 -22
  56. package/dist/Form/SelectDropdown/hooks/useSelectHandlers.js +0 -62
  57. package/dist/Form/SelectDropdown/hooks/useSelectOptions.d.ts +0 -14
  58. package/dist/Form/SelectDropdown/hooks/useSelectOptions.js +0 -39
  59. /package/dist/Form/SelectDropdown/{core/styles.d.ts → styles.d.ts} +0 -0
@@ -1,6 +1,5 @@
1
1
  import { createContext, useLayoutEffect } from 'react';
2
2
  import ReactSelect, { components as SelectDropdownElements } from 'react-select';
3
- import CreatableSelect from 'react-select/creatable';
4
3
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
4
  /**
6
5
  * React context for sharing state between SelectDropdown components.
@@ -117,27 +116,12 @@ export const CustomInput = ({
117
116
 
118
117
  /**
119
118
  * Typed wrapper around react-select component.
120
- * Renders CreatableSelect when isCreatable is true, ReactSelect otherwise.
121
- * Creatable-only props (formatCreateLabel, isValidNewOption) are stripped from
122
- * the non-creatable path so they don't reach ReactSelect. `onCreateOption` is
123
- * handled in SelectDropdown's changeHandler — do not pass it to CreatableSelect
124
- * or react-select will skip onChange on create.
119
+ * Provides type safety for the underlying react-select implementation.
125
120
  */
126
121
  export function TypedReactSelect({
127
122
  selectRef,
128
- isCreatable,
129
- formatCreateLabel,
130
- isValidNewOption,
131
123
  ...props
132
124
  }) {
133
- if (isCreatable) {
134
- return /*#__PURE__*/_jsx(CreatableSelect, {
135
- ...props,
136
- formatCreateLabel: formatCreateLabel,
137
- isValidNewOption: isValidNewOption,
138
- ref: selectRef
139
- });
140
- }
141
125
  return /*#__PURE__*/_jsx(ReactSelect, {
142
126
  ...props,
143
127
  ref: selectRef
@@ -1,6 +1,20 @@
1
- import { SizedIndicatorProps } from '../types';
1
+ import { AriaOnFocus } from 'react-select';
2
+ import { ExtendedOption, SizedIndicatorProps } from '../types';
3
+ /**
4
+ * Generates accessible focus messages for screen readers.
5
+ * Provides detailed information about the currently focused option.
6
+ *
7
+ * @param params - Object containing the focused option details
8
+ * @returns Formatted accessibility message
9
+ */
10
+ export declare const onFocus: AriaOnFocus<ExtendedOption>;
2
11
  /**
3
12
  * Custom dropdown indicator that shows either a chevron or search icon.
4
13
  * The icon type depends on whether the select is searchable or not.
5
14
  */
6
15
  export declare const DropdownButton: (props: SizedIndicatorProps) => import("react/jsx-runtime").JSX.Element;
16
+ /**
17
+ * Custom remove all button for multi-select mode.
18
+ * Provides keyboard navigation and accessible removal of all selected values.
19
+ */
20
+ export declare const RemoveAllButton: (props: SizedIndicatorProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,23 +1,50 @@
1
+ import _styled from "@emotion/styled/base";
2
+ import { css, theme } from '@codecademy/gamut-styles';
3
+ import { useContext } from 'react';
1
4
  import { components as SelectDropdownElements } from 'react-select';
2
5
  import { indicatorIcons } from './constants';
6
+ import { SelectDropdownContext } from './containers';
3
7
  import { jsx as _jsx } from "react/jsx-runtime";
4
8
  const {
5
9
  DropdownIndicator
6
10
  } = SelectDropdownElements;
7
11
 
12
+ /**
13
+ * Generates accessible focus messages for screen readers.
14
+ * Provides detailed information about the currently focused option.
15
+ *
16
+ * @param params - Object containing the focused option details
17
+ * @returns Formatted accessibility message
18
+ */
19
+ export const onFocus = ({
20
+ focused: {
21
+ label,
22
+ subtitle,
23
+ rightLabel,
24
+ disabled
25
+ }
26
+ }) => {
27
+ const formattedSubtitle = `, ${subtitle}`;
28
+ const formattedRightLabel = `, ${rightLabel}`;
29
+ const msg = `You are currently focused on option ${label}${subtitle ? formattedSubtitle : ''} ${rightLabel ? formattedRightLabel : ''}${disabled ? ', disabled' : ''}`;
30
+ return msg;
31
+ };
32
+
8
33
  /**
9
34
  * Custom dropdown indicator that shows either a chevron or search icon.
10
35
  * The icon type depends on whether the select is searchable or not.
11
36
  */
12
37
  export const DropdownButton = props => {
13
38
  const {
14
- size
39
+ size,
40
+ isSearchable
15
41
  } = props.selectProps;
16
42
  const color = props.isDisabled ? 'text-disabled' : 'text';
17
43
  const iconSize = size ?? 'medium';
44
+ const iconType = isSearchable ? 'Searchable' : 'Chevron';
18
45
  const {
19
46
  ...iconProps
20
- } = indicatorIcons[`${iconSize}Chevron`];
47
+ } = indicatorIcons[`${iconSize}${iconType}`];
21
48
  const {
22
49
  icon: IndicatorIcon
23
50
  } = iconProps;
@@ -28,4 +55,66 @@ export const DropdownButton = props => {
28
55
  color: color
29
56
  })
30
57
  });
58
+ };
59
+ const CustomStyledRemoveAllDiv = /*#__PURE__*/_styled('div', {
60
+ target: "e1xkmr70",
61
+ label: "CustomStyledRemoveAllDiv"
62
+ })(css({
63
+ '&:focus': {
64
+ outline: `2px solid ${theme.colors.primary}`
65
+ },
66
+ '&:focus-visible': {
67
+ outline: `2px solid ${theme.colors.primary}`
68
+ }
69
+ }), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9Gb3JtL1NlbGVjdERyb3Bkb3duL2VsZW1lbnRzL2NvbnRyb2xzLnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFxRGlDIiwiZmlsZSI6Ii4uLy4uLy4uLy4uL3NyYy9Gb3JtL1NlbGVjdERyb3Bkb3duL2VsZW1lbnRzL2NvbnRyb2xzLnRzeCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNzcywgdGhlbWUgfSBmcm9tICdAY29kZWNhZGVteS9nYW11dC1zdHlsZXMnO1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnO1xuaW1wb3J0IHsgS2V5Ym9hcmRFdmVudCwgdXNlQ29udGV4dCB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7XG4gIEFyaWFPbkZvY3VzLFxuICBjb21wb25lbnRzIGFzIFNlbGVjdERyb3Bkb3duRWxlbWVudHMsXG59IGZyb20gJ3JlYWN0LXNlbGVjdCc7XG5cbmltcG9ydCB7IEV4dGVuZGVkT3B0aW9uLCBTaXplZEluZGljYXRvclByb3BzIH0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHsgaW5kaWNhdG9ySWNvbnMgfSBmcm9tICcuL2NvbnN0YW50cyc7XG5pbXBvcnQgeyBTZWxlY3REcm9wZG93bkNvbnRleHQgfSBmcm9tICcuL2NvbnRhaW5lcnMnO1xuXG5jb25zdCB7IERyb3Bkb3duSW5kaWNhdG9yIH0gPSBTZWxlY3REcm9wZG93bkVsZW1lbnRzO1xuXG4vKipcbiAqIEdlbmVyYXRlcyBhY2Nlc3NpYmxlIGZvY3VzIG1lc3NhZ2VzIGZvciBzY3JlZW4gcmVhZGVycy5cbiAqIFByb3ZpZGVzIGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50bHkgZm9jdXNlZCBvcHRpb24uXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIE9iamVjdCBjb250YWluaW5nIHRoZSBmb2N1c2VkIG9wdGlvbiBkZXRhaWxzXG4gKiBAcmV0dXJucyBGb3JtYXR0ZWQgYWNjZXNzaWJpbGl0eSBtZXNzYWdlXG4gKi9cbmV4cG9ydCBjb25zdCBvbkZvY3VzOiBBcmlhT25Gb2N1czxFeHRlbmRlZE9wdGlvbj4gPSAoe1xuICBmb2N1c2VkOiB7IGxhYmVsLCBzdWJ0aXRsZSwgcmlnaHRMYWJlbCwgZGlzYWJsZWQgfSxcbn0pID0+IHtcbiAgY29uc3QgZm9ybWF0dGVkU3VidGl0bGUgPSBgLCAke3N1YnRpdGxlfWA7XG4gIGNvbnN0IGZvcm1hdHRlZFJpZ2h0TGFiZWwgPSBgLCAke3JpZ2h0TGFiZWx9YDtcblxuICBjb25zdCBtc2cgPSBgWW91IGFyZSBjdXJyZW50bHkgZm9jdXNlZCBvbiBvcHRpb24gJHtsYWJlbH0ke1xuICAgIHN1YnRpdGxlID8gZm9ybWF0dGVkU3VidGl0bGUgOiAnJ1xuICB9ICR7cmlnaHRMYWJlbCA/IGZvcm1hdHRlZFJpZ2h0TGFiZWwgOiAnJ30ke2Rpc2FibGVkID8gJywgZGlzYWJsZWQnIDogJyd9YDtcblxuICByZXR1cm4gbXNnO1xufTtcblxuLyoqXG4gKiBDdXN0b20gZHJvcGRvd24gaW5kaWNhdG9yIHRoYXQgc2hvd3MgZWl0aGVyIGEgY2hldnJvbiBvciBzZWFyY2ggaWNvbi5cbiAqIFRoZSBpY29uIHR5cGUgZGVwZW5kcyBvbiB3aGV0aGVyIHRoZSBzZWxlY3QgaXMgc2VhcmNoYWJsZSBvciBub3QuXG4gKi9cbmV4cG9ydCBjb25zdCBEcm9wZG93bkJ1dHRvbiA9IChwcm9wczogU2l6ZWRJbmRpY2F0b3JQcm9wcykgPT4ge1xuICBjb25zdCB7IHNpemUsIGlzU2VhcmNoYWJsZSB9ID0gcHJvcHMuc2VsZWN0UHJvcHM7XG4gIGNvbnN0IGNvbG9yID0gcHJvcHMuaXNEaXNhYmxlZCA/ICd0ZXh0LWRpc2FibGVkJyA6ICd0ZXh0JztcbiAgY29uc3QgaWNvblNpemUgPSBzaXplID8/ICdtZWRpdW0nO1xuICBjb25zdCBpY29uVHlwZSA9IGlzU2VhcmNoYWJsZSA/ICdTZWFyY2hhYmxlJyA6ICdDaGV2cm9uJztcbiAgY29uc3QgeyAuLi5pY29uUHJvcHMgfSA9IGluZGljYXRvckljb25zW2Ake2ljb25TaXplfSR7aWNvblR5cGV9YF07XG4gIGNvbnN0IHsgaWNvbjogSW5kaWNhdG9ySWNvbiB9ID0gaWNvblByb3BzO1xuXG4gIHJldHVybiAoXG4gICAgPERyb3Bkb3duSW5kaWNhdG9yIHsuLi5wcm9wc30+XG4gICAgICA8SW5kaWNhdG9ySWNvbiB7Li4uaWNvblByb3BzfSBjb2xvcj17Y29sb3J9IC8+XG4gICAgPC9Ecm9wZG93bkluZGljYXRvcj5cbiAgKTtcbn07XG5cbmNvbnN0IEN1c3RvbVN0eWxlZFJlbW92ZUFsbERpdiA9IHN0eWxlZCgnZGl2JykoXG4gIGNzcyh7XG4gICAgJyY6Zm9jdXMnOiB7XG4gICAgICBvdXRsaW5lOiBgMnB4IHNvbGlkICR7dGhlbWUuY29sb3JzLnByaW1hcnl9YCxcbiAgICB9LFxuICAgICcmOmZvY3VzLXZpc2libGUnOiB7XG4gICAgICBvdXRsaW5lOiBgMnB4IHNvbGlkICR7dGhlbWUuY29sb3JzLnByaW1hcnl9YCxcbiAgICB9LFxuICB9KVxuKTtcblxuLyoqXG4gKiBDdXN0b20gcmVtb3ZlIGFsbCBidXR0b24gZm9yIG11bHRpLXNlbGVjdCBtb2RlLlxuICogUHJvdmlkZXMga2V5Ym9hcmQgbmF2aWdhdGlvbiBhbmQgYWNjZXNzaWJsZSByZW1vdmFsIG9mIGFsbCBzZWxlY3RlZCB2YWx1ZXMuXG4gKi9cbmV4cG9ydCBjb25zdCBSZW1vdmVBbGxCdXR0b24gPSAocHJvcHM6IFNpemVkSW5kaWNhdG9yUHJvcHMpID0+IHtcbiAgY29uc3Qge1xuICAgIGdldFN0eWxlcyxcbiAgICBpbm5lclByb3BzOiB7IC4uLnJlc3RJbm5lclByb3BzIH0sXG4gICAgc2VsZWN0UHJvcHM6IHsgc2l6ZSB9LFxuICB9ID0gcHJvcHM7XG5cbiAgY29uc3QgeyByZW1vdmVBbGxCdXR0b25SZWYsIHNlbGVjdElucHV0UmVmIH0gPSB1c2VDb250ZXh0KFxuICAgIFNlbGVjdERyb3Bkb3duQ29udGV4dFxuICApO1xuXG4gIGNvbnN0IGljb25TaXplID0gc2l6ZSA/PyAnbWVkaXVtJztcbiAgY29uc3QgeyAuLi5pY29uUHJvcHMgfSA9IGluZGljYXRvckljb25zW2Ake2ljb25TaXplfVJlbW92ZWBdO1xuICBjb25zdCB7IGljb246IEluZGljYXRvckljb24gfSA9IGljb25Qcm9wcztcblxuICBjb25zdCBvbktleVByZXNzID0gKGU6IEtleWJvYXJkRXZlbnQ8SFRNTERpdkVsZW1lbnQ+KSA9PiB7XG4gICAgaWYgKGUua2V5ID09PSAnRW50ZXInICYmIHJlc3RJbm5lclByb3BzLm9uTW91c2VEb3duKSB7XG4gICAgICByZXN0SW5uZXJQcm9wcy5vbk1vdXNlRG93bihlIGFzIGFueSk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgc2VsZWN0SW5wdXRSZWY/LmN1cnJlbnQgJiZcbiAgICAgIChlLmtleSA9PT0gJ0Fycm93UmlnaHQnIHx8IGUua2V5ID09PSAnQXJyb3dMZWZ0JyB8fCBlLmtleSA9PT0gJ0Fycm93RG93bicpXG4gICAgKSB7XG4gICAgICBzZWxlY3RJbnB1dFJlZj8uY3VycmVudC5mb2N1cygpO1xuICAgIH1cbiAgfTtcblxuICBjb25zdCBzdHlsZSA9IGdldFN0eWxlcygnY2xlYXJJbmRpY2F0b3InLCBwcm9wcykgYXMgUmVhY3QuQ1NTUHJvcGVydGllcztcblxuICByZXR1cm4gKFxuICAgIDxDdXN0b21TdHlsZWRSZW1vdmVBbGxEaXZcbiAgICAgIGFyaWEtbGFiZWw9XCJSZW1vdmUgYWxsIHNlbGVjdGVkXCJcbiAgICAgIHJvbGU9XCJidXR0b25cIlxuICAgICAgdGFiSW5kZXg9ezB9XG4gICAgICB7Li4ucmVzdElubmVyUHJvcHN9XG4gICAgICByZWY9e3JlbW92ZUFsbEJ1dHRvblJlZn1cbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBnYW11dC9uby1pbmxpbmUtc3R5bGVcbiAgICAgIHN0eWxlPXtzdHlsZX1cbiAgICAgIG9uS2V5RG93bj17b25LZXlQcmVzc31cbiAgICA+XG4gICAgICA8SW5kaWNhdG9ySWNvbiB7Li4uaWNvblByb3BzfSBjb2xvcj1cInRleHRcIiAvPlxuICAgIDwvQ3VzdG9tU3R5bGVkUmVtb3ZlQWxsRGl2PlxuICApO1xufTtcbiJdfQ== */");
70
+
71
+ /**
72
+ * Custom remove all button for multi-select mode.
73
+ * Provides keyboard navigation and accessible removal of all selected values.
74
+ */
75
+ export const RemoveAllButton = props => {
76
+ const {
77
+ getStyles,
78
+ innerProps: {
79
+ ...restInnerProps
80
+ },
81
+ selectProps: {
82
+ size
83
+ }
84
+ } = props;
85
+ const {
86
+ removeAllButtonRef,
87
+ selectInputRef
88
+ } = useContext(SelectDropdownContext);
89
+ const iconSize = size ?? 'medium';
90
+ const {
91
+ ...iconProps
92
+ } = indicatorIcons[`${iconSize}Remove`];
93
+ const {
94
+ icon: IndicatorIcon
95
+ } = iconProps;
96
+ const onKeyPress = e => {
97
+ if (e.key === 'Enter' && restInnerProps.onMouseDown) {
98
+ restInnerProps.onMouseDown(e);
99
+ }
100
+ if (selectInputRef?.current && (e.key === 'ArrowRight' || e.key === 'ArrowLeft' || e.key === 'ArrowDown')) {
101
+ selectInputRef?.current.focus();
102
+ }
103
+ };
104
+ const style = getStyles('clearIndicator', props);
105
+ return /*#__PURE__*/_jsx(CustomStyledRemoveAllDiv, {
106
+ "aria-label": "Remove all selected",
107
+ role: "button",
108
+ tabIndex: 0,
109
+ ...restInnerProps,
110
+ ref: removeAllButtonRef
111
+ // eslint-disable-next-line gamut/no-inline-style
112
+ ,
113
+ style: style,
114
+ onKeyDown: onKeyPress,
115
+ children: /*#__PURE__*/_jsx(IndicatorIcon, {
116
+ ...iconProps,
117
+ color: "text"
118
+ })
119
+ });
31
120
  };
@@ -1,6 +1,5 @@
1
1
  export { iconSize, selectedIconSize, indicatorIcons } from './constants';
2
2
  export { MultiValueWithColorMode, MultiValueRemoveButton, RemoveAllButton, } from './multi-value';
3
- export { DropdownButton } from './controls';
4
- export { onFocus } from '../core/accessibility';
3
+ export { DropdownButton, onFocus } from './controls';
5
4
  export { SelectDropdownContext, CustomContainer, CustomInput, CustomValueContainer, TypedReactSelect, } from './containers';
6
5
  export { IconOption, AbbreviatedSingleValue, formatOptionLabel, formatGroupLabel, } from './options';
@@ -1,6 +1,5 @@
1
1
  export { iconSize, selectedIconSize, indicatorIcons } from './constants';
2
2
  export { MultiValueWithColorMode, MultiValueRemoveButton, RemoveAllButton } from './multi-value';
3
- export { DropdownButton } from './controls';
4
- export { onFocus } from '../core/accessibility';
3
+ export { DropdownButton, onFocus } from './controls';
5
4
  export { SelectDropdownContext, CustomContainer, CustomInput, CustomValueContainer, TypedReactSelect } from './containers';
6
5
  export { IconOption, AbbreviatedSingleValue, formatOptionLabel, formatGroupLabel } from './options';
@@ -3,7 +3,6 @@ import { CustomSelectComponentProps, ExtendedOption, SelectDropdownGroup } from
3
3
  /**
4
4
  * Custom option component that displays a check icon for selected items.
5
5
  * Also manages ARIA attributes for accessibility.
6
- * Skips the check icon for react-select/creatable's "Add" row (__isNew__).
7
6
  */
8
7
  export declare const IconOption: ({ children, ...rest }: CustomSelectComponentProps<typeof SelectDropdownElements.Option>) => import("react/jsx-runtime").JSX.Element;
9
8
  /**
@@ -44,7 +44,6 @@ const IconOptionLabel = ({
44
44
  /**
45
45
  * Custom option component that displays a check icon for selected items.
46
46
  * Also manages ARIA attributes for accessibility.
47
- * Skips the check icon for react-select/creatable's "Add" row (__isNew__).
48
47
  */
49
48
  export const IconOption = ({
50
49
  children,
@@ -55,17 +54,15 @@ export const IconOption = ({
55
54
  } = rest.selectProps;
56
55
  const {
57
56
  isFocused,
58
- innerProps,
59
- data
57
+ innerProps
60
58
  } = rest;
61
- const isNew = data?.__isNew__;
62
59
  return /*#__PURE__*/_jsxs(SelectDropdownElements.Option, {
63
60
  ...rest,
64
61
  innerProps: {
65
62
  ...innerProps,
66
63
  'aria-selected': isFocused
67
64
  },
68
- children: [children, !isNew && rest?.isSelected && /*#__PURE__*/_jsx(CheckIcon, {
65
+ children: [children, rest?.isSelected && /*#__PURE__*/_jsx(CheckIcon, {
69
66
  size: selectedIconSize[size ?? 'medium']
70
67
  })]
71
68
  });
@@ -1,10 +1,9 @@
1
- import { css, states, variant } from '@codecademy/gamut-styles';
2
- import { dismissSharedStyles, tagBaseStyles, tagLabelFontSize, tagLabelPadding } from '../../../Tag/styles';
3
- import { formBaseComponentStyles, formBaseFieldStylesObject, formFieldDisabledStyles, formFieldPaddingStyles, InputSelectors } from '../../styles';
1
+ import { css, states, variant, zIndices } from '@codecademy/gamut-styles';
2
+ import { dismissSharedStyles, tagBaseStyles, tagLabelFontSize, tagLabelPadding } from '../../Tag/styles';
3
+ import { formBaseComponentStyles, formBaseFieldStylesObject, formFieldDisabledStyles, formFieldPaddingStyles, InputSelectors } from '../styles';
4
4
  const selectDropdownStyles = css({
5
5
  ...formBaseFieldStylesObject,
6
- display: 'flex',
7
- zIndex: 3
6
+ display: 'flex'
8
7
  });
9
8
  const selectFocusStyles = {
10
9
  color: 'primary',
@@ -62,7 +61,7 @@ const textColor = css({
62
61
  color: 'text'
63
62
  });
64
63
  const placeholderColor = css({
65
- color: 'text-secondary'
64
+ color: 'text-disabled'
66
65
  });
67
66
  export const getMemoizedStyles = (theme, zIndex) => {
68
67
  return {
@@ -137,8 +136,6 @@ export const getMemoizedStyles = (theme, zIndex) => {
137
136
  error: state.selectProps.error,
138
137
  theme
139
138
  }),
140
- // Drop react-select's default menu drop shadow; the border above defines the edge.
141
- boxShadow: 'none',
142
139
  ...(dropdownWidth ? {
143
140
  minWidth: dropdownWidth,
144
141
  width: dropdownWidth
@@ -149,6 +146,12 @@ export const getMemoizedStyles = (theme, zIndex) => {
149
146
  } : {})
150
147
  };
151
148
  },
149
+ menuPortal: provided => ({
150
+ ...provided,
151
+ // The menu is portaled to the body, so it stacks at the page root as a popover —
152
+ // above sticky headers and modal content. A raw `zIndex` prop overrides as an escape hatch.
153
+ zIndex: zIndex ?? zIndices.popover
154
+ }),
152
155
  menuList: (provided, state) => {
153
156
  const sizeInteger = state.selectProps.size === 'small' ? 2 : 3;
154
157
  const maxHeight = `${(state.selectProps.shownOptionsLimit ?? 6) * sizeInteger}rem`;
@@ -196,32 +199,16 @@ export const getMemoizedStyles = (theme, zIndex) => {
196
199
  backgroundColor: theme.colors['secondary-hover']
197
200
  }
198
201
  }),
199
- noOptionsMessage: provided => ({
200
- ...provided,
201
- color: theme.colors['text-secondary']
202
+ option: (provided, state) => ({
203
+ ...getOptionBackground(state.isSelected, state.isFocused)({
204
+ theme
205
+ }),
206
+ alignItems: 'center',
207
+ color: state.isDisabled ? 'text-disabled' : 'default',
208
+ cursor: state.isDisabled ? 'not-allowed' : 'pointer',
209
+ display: 'flex',
210
+ padding: state.selectProps.size === 'small' ? '3px 14px' : '11px 14px'
202
211
  }),
203
- option: (provided, state) => {
204
- const isNew = state.data?.__isNew__;
205
- const isSmall = state.selectProps.size === 'small';
206
- return {
207
- ...getOptionBackground(state.isSelected, state.isFocused)({
208
- theme
209
- }),
210
- alignItems: 'center',
211
- color: state.isDisabled ? theme.colors['text-disabled'] : isNew ? theme.colors.primary : theme.colors.text,
212
- cursor: state.isDisabled ? 'not-allowed' : 'pointer',
213
- display: 'flex',
214
- padding: isSmall ? '3px 14px' : '11px 14px',
215
- ...(isNew && {
216
- // Gradient creates the 1px divider line at the top edge of the option background
217
- backgroundImage: `linear-gradient(${theme.colors['text-disabled']} 1px, transparent 1px)`,
218
- backgroundPosition: '0 0',
219
- backgroundRepeat: 'no-repeat',
220
- backgroundSize: '100% 1px',
221
- paddingTop: isSmall ? '11px' : '19px'
222
- })
223
- };
224
- },
225
212
  placeholder: provided => ({
226
213
  ...provided,
227
214
  ...placeholderColor({
@@ -1,5 +1,5 @@
1
1
  import { Ref, SelectHTMLAttributes } from 'react';
2
- import { Options as OptionsType, Props as NamedProps } from 'react-select';
2
+ import { Props as NamedProps } from 'react-select';
3
3
  import { SelectComponentProps } from '../../inputs/Select';
4
4
  import { OptionStrict, SelectDropdownGroup, SelectDropdownOptions } from './options';
5
5
  import { ReactSelectAdditionalProps, SelectDropdownSizes, SharedProps } from './styles';
@@ -28,7 +28,7 @@ export type SelectDropdownBaseProps = Omit<SelectComponentProps, 'onChange' | 'd
28
28
  * Core props interface that defines the essential properties for SelectDropdown.
29
29
  * This interface combines base props with react-select props and HTML select attributes.
30
30
  */
31
- export interface SelectDropdownCoreProps extends SelectDropdownBaseProps, Omit<NamedProps<OptionStrict, boolean>, 'formatOptionLabel' | 'isDisabled' | 'value' | 'options' | 'components' | 'styles' | 'theme' | 'onChange' | 'multiple' | 'isSearchable'>, Pick<SelectHTMLAttributes<HTMLSelectElement>, 'value' | 'disabled' | 'onClick'>, SharedProps {
31
+ export interface SelectDropdownCoreProps extends SelectDropdownBaseProps, Omit<NamedProps<OptionStrict, boolean>, 'formatOptionLabel' | 'isDisabled' | 'value' | 'options' | 'components' | 'styles' | 'theme' | 'onChange' | 'multiple'>, Pick<SelectHTMLAttributes<HTMLSelectElement>, 'value' | 'disabled' | 'onClick'>, SharedProps {
32
32
  /** Required name attribute for the select input */
33
33
  name: string;
34
34
  /** Placeholder text shown when no option is selected.
@@ -38,39 +38,6 @@ export interface SelectDropdownCoreProps extends SelectDropdownBaseProps, Omit<N
38
38
  placeholder?: string;
39
39
  /** Array of options or option groups to display in the dropdown */
40
40
  options?: SelectDropdownOptions | SelectDropdownGroup[];
41
- /**
42
- * Allows users to create new options by typing a value not in the options list.
43
- * When true, isSearchable is automatically set to true.
44
- * Pair with onCreateOption to persist new options.
45
- */
46
- isCreatable?: boolean;
47
- /**
48
- * Called when the user confirms a new option via the "Add" row.
49
- * Convenience callback for persisting the new value to your `options` list.
50
- * Selection updates are delivered through `onChange` with `action: 'create-option'`.
51
- */
52
- onCreateOption?: (inputValue: string) => void;
53
- /**
54
- * Customises the label shown in the "Add" row.
55
- * Defaults to: (inputValue) => `Add "${inputValue}"`.
56
- */
57
- formatCreateLabel?: (inputValue: string) => React.ReactNode;
58
- /**
59
- * Controls when the "Add" row is visible.
60
- * Receives the current input, selected values, and all options.
61
- * Defaults to react-select's built-in logic (hidden when input matches an existing option label).
62
- * Use cases: minimum-length gating, pattern validation, case-insensitive dedup, max-items cap.
63
- */
64
- isValidNewOption?: (inputValue: string, value: OptionsType<OptionStrict>, options: OptionsType<OptionStrict>) => boolean;
65
- /**
66
- * Customizes the message shown inside the dropdown menu when no option matches
67
- * the current input (react-select's "No options" state). Useful for surfacing
68
- * validation/error text directly in the dropdown. Accepts a node, or a function
69
- * receiving the current input value.
70
- */
71
- validationMessage?: React.ReactNode | ((obj: {
72
- inputValue: string;
73
- }) => React.ReactNode);
74
41
  }
75
42
  /**
76
43
  * Props for single-select mode.
@@ -92,23 +59,11 @@ export interface MultiSelectDropdownProps extends SelectDropdownCoreProps {
92
59
  /** Callback fired when the selected values change */
93
60
  onChange?: NamedProps<OptionStrict, true>['onChange'];
94
61
  }
95
- /**
96
- * Enforces that isSearchable cannot be false when isCreatable is true.
97
- * Creatable mode requires the search input so users can type new option values.
98
- */
99
- type CreatableConstraint = {
100
- isCreatable?: false | undefined;
101
- isSearchable?: boolean;
102
- } | {
103
- isCreatable: true;
104
- isSearchable?: true;
105
- };
106
62
  /**
107
63
  * Union type for all SelectDropdown prop variants.
108
- * Supports both single and multi-select modes through discriminated union,
109
- * intersected with CreatableConstraint to enforce isSearchable compatibility.
64
+ * Supports both single and multi-select modes through discriminated union.
110
65
  */
111
- export type SelectDropdownProps = (SingleSelectDropdownProps | MultiSelectDropdownProps) & CreatableConstraint;
66
+ export type SelectDropdownProps = SingleSelectDropdownProps | MultiSelectDropdownProps;
112
67
  /**
113
68
  * Base interface for onChange-related props.
114
69
  * Used internally for type checking and prop validation.
@@ -121,12 +76,9 @@ export interface BaseOnChangeProps {
121
76
  }
122
77
  /**
123
78
  * Props for the typed React Select component wrapper.
124
- * Extends ReactSelectAdditionalProps with an optional ref and creatable flag.
79
+ * Extends ReactSelectAdditionalProps with an optional ref.
125
80
  */
126
- export interface TypedReactSelectProps extends ReactSelectAdditionalProps, Pick<SelectDropdownCoreProps, 'formatCreateLabel' | 'isValidNewOption'> {
81
+ export interface TypedReactSelectProps extends ReactSelectAdditionalProps {
127
82
  /** Optional ref to the underlying react-select component */
128
83
  selectRef?: Ref<any>;
129
- /** When true, renders CreatableSelect instead of ReactSelect */
130
- isCreatable?: boolean;
131
84
  }
132
- export {};
@@ -14,7 +14,7 @@ export type InternalSelectProps = {
14
14
  * Ref type for programmatic focus management.
15
15
  * Used for managing focus on select input and remove all button.
16
16
  */
17
- export type ProgrammaticFocusRef = React.MutableRefObject<HTMLDivElement> | React.MutableRefObject<null>;
17
+ export type ProgramaticFocusRef = React.MutableRefObject<HTMLDivElement> | React.MutableRefObject<null>;
18
18
  /**
19
19
  * Context value for SelectDropdown internal state management.
20
20
  * Provides access to focus state and refs for keyboard navigation.
@@ -25,9 +25,9 @@ export interface SelectDropdownContextValueTypes {
25
25
  /** Function to update the currently focused value */
26
26
  setCurrentFocusedValue?: React.Dispatch<React.SetStateAction<unknown>>;
27
27
  /** Ref to the select input for programmatic focus */
28
- selectInputRef?: ProgrammaticFocusRef;
28
+ selectInputRef?: ProgramaticFocusRef;
29
29
  /** Ref to the remove all button for programmatic focus */
30
- removeAllButtonRef?: ProgrammaticFocusRef;
30
+ removeAllButtonRef?: ProgramaticFocusRef;
31
31
  }
32
32
  /**
33
33
  * Props for sized indicator components (dropdown arrow, search icon, etc.).
@@ -1,5 +1,5 @@
1
1
  import { StyleProps } from '@codecademy/variance';
2
- import { conditionalBorderStates } from '../core/styles';
2
+ import { conditionalBorderStates } from '../styles';
3
3
  import { InternalInputsProps } from './component-props';
4
4
  /**
5
5
  * Size variants for the SelectDropdown component.
@@ -69,9 +69,5 @@ export type ControlState = BaseSelectComponentProps & InteractionStates & {
69
69
  export type OptionState = BaseSelectComponentProps & InteractionStates & {
70
70
  /** Whether the option is selected */
71
71
  isSelected: boolean;
72
- /** Option data — includes __isNew__ for react-select/creatable's "Add" row */
73
- data?: {
74
- __isNew__?: boolean;
75
- };
76
72
  };
77
73
  export {};
@@ -1,14 +1,7 @@
1
- import * as React from 'react';
2
- import { ActionMeta, Options as OptionsType } from 'react-select';
3
- import { SelectOptionBase } from '../../utils';
4
- import { BaseOnChangeProps, ExtendedOption, MultiSelectDropdownProps, OptionStrict, SelectDropdownGroup, SelectDropdownOptions, SelectDropdownProps, SingleSelectDropdownProps } from '../types';
1
+ import { SelectOptionBase } from '../utils';
2
+ import { BaseOnChangeProps, ExtendedOption, MultiSelectDropdownProps, SelectDropdownGroup, SelectDropdownOptions, SelectDropdownProps, SingleSelectDropdownProps } from './types';
5
3
  export declare const isMultipleSelectProps: (props: BaseOnChangeProps) => props is MultiSelectDropdownProps;
6
4
  export declare const isSingleSelectProps: (props: BaseOnChangeProps) => props is SingleSelectDropdownProps;
7
- /**
8
- * Resolves the value for a newly created option from react-select action metadata
9
- * or the onChange option payload. Returns undefined when no reliable value exists.
10
- */
11
- export declare const getCreatedOptionValue: (optionEvent: OptionStrict | OptionsType<OptionStrict>, actionMeta: ActionMeta<OptionStrict>, multiple?: boolean) => string | undefined;
12
5
  export declare const isOptionGroup: (obj: unknown) => obj is SelectDropdownGroup;
13
6
  export declare const isOptionsGrouped: (options: SelectDropdownOptions) => options is SelectDropdownGroup[];
14
7
  /**
@@ -30,7 +23,4 @@ export declare const filterValueFromOptions: (options: SelectOptionBase[] | Sele
30
23
  * @param value - The value or values to remove
31
24
  * @returns New array with the specified values removed
32
25
  */
33
- export declare const resolveNoOptionsMessage: (validationMessage: SelectDropdownProps["validationMessage"]) => ((obj: {
34
- inputValue: string;
35
- }) => React.ReactNode) | undefined;
36
26
  export declare const removeValueFromSelectedOptions: (selectedOptions: ExtendedOption[] | SelectOptionBase[], value: SelectDropdownProps["value"]) => SelectOptionBase[];
@@ -1,21 +1,5 @@
1
1
  export const isMultipleSelectProps = props => !!props.multiple;
2
2
  export const isSingleSelectProps = props => !props.multiple;
3
- /**
4
- * Resolves the value for a newly created option from react-select action metadata
5
- * or the onChange option payload. Returns undefined when no reliable value exists.
6
- */
7
- export const getCreatedOptionValue = (optionEvent, actionMeta, multiple) => {
8
- const metaValue = actionMeta.option?.value;
9
- if (metaValue) return metaValue;
10
- if (!multiple) {
11
- const {
12
- value
13
- } = optionEvent;
14
- return value || undefined;
15
- }
16
- const newOption = optionEvent.find(option => option.__isNew__);
17
- return newOption?.value || undefined;
18
- };
19
3
  export const isOptionGroup = obj => obj != null && typeof obj === 'object' && 'options' in obj && obj.options !== undefined;
20
4
  export const isOptionsGrouped = options => Array.isArray(options) && options.some(option => isOptionGroup(option));
21
5
 
@@ -44,13 +28,6 @@ export const filterValueFromOptions = (options, value, optionsAreGrouped) => {
44
28
  * @param value - The value or values to remove
45
29
  * @returns New array with the specified values removed
46
30
  */
47
- export const resolveNoOptionsMessage = validationMessage => {
48
- if (validationMessage === undefined) return undefined;
49
- if (typeof validationMessage === 'function') {
50
- return validationMessage;
51
- }
52
- return () => validationMessage;
53
- };
54
31
  export const removeValueFromSelectedOptions = (selectedOptions, value) => {
55
32
  return selectedOptions.filter(option => {
56
33
  if (Array.isArray(value)) {
@@ -1,4 +1,4 @@
1
1
  export * from './shared-system-props';
2
2
  export * from './Checkbox-styles';
3
3
  export * from './Radio-styles';
4
- export * from '../SelectDropdown/core/styles';
4
+ export * from '../SelectDropdown/styles';
@@ -1,4 +1,4 @@
1
1
  export * from './shared-system-props';
2
2
  export * from './Checkbox-styles';
3
3
  export * from './Radio-styles';
4
- export * from '../SelectDropdown/core/styles';
4
+ export * from '../SelectDropdown/styles';
@@ -1,3 +1,4 @@
1
+ import { zIndices } from '@codecademy/gamut-styles';
1
2
  import { forwardRef } from 'react';
2
3
  import { Box } from '../Box';
3
4
  import { HeaderRowEl } from './elements';
@@ -17,7 +18,7 @@ export const TableHeader = /*#__PURE__*/forwardRef(({
17
18
  display: "block",
18
19
  position: "sticky",
19
20
  top: 0,
20
- zIndex: 2,
21
+ zIndex: zIndices.foreground,
21
22
  children: /*#__PURE__*/_jsx(HeaderRowEl, {
22
23
  ...rest,
23
24
  ref: ref,