@codecademy/gamut

71.0.071.0.1-alpha.69ab4c.0
~

Modified (15 files)

Index: package/dist/Form/SelectDropdown/elements/constants.js
===================================================================
--- package/dist/Form/SelectDropdown/elements/constants.js
+++ package/dist/Form/SelectDropdown/elements/constants.js
@@ -1,5 +1,5 @@
-import { ArrowChevronDownIcon, CloseIcon, MiniChevronDownIcon, MiniDeleteIcon, SearchIcon } from '@codecademy/gamut-icons';
+import { ArrowChevronDownIcon, CloseIcon, MiniChevronDownIcon, MiniDeleteIcon } from '@codecademy/gamut-icons';
 export const iconSize = {
   small: 12,
   medium: 16
 };
@@ -15,16 +15,8 @@
   mediumChevron: {
     size: iconSize.medium,
     icon: ArrowChevronDownIcon
   },
-  smallSearchable: {
-    size: iconSize.small,
-    icon: SearchIcon
-  },
-  mediumSearchable: {
-    size: iconSize.medium,
-    icon: SearchIcon
-  },
   smallRemove: {
     size: iconSize.small,
     icon: MiniDeleteIcon
   },
Index: package/dist/Form/SelectDropdown/elements/containers.js
===================================================================
--- package/dist/Form/SelectDropdown/elements/containers.js
+++ package/dist/Form/SelectDropdown/elements/containers.js
@@ -1,6 +1,7 @@
 import { createContext, useLayoutEffect } from 'react';
 import ReactSelect, { components as SelectDropdownElements } from 'react-select';
+import CreatableSelect from 'react-select/creatable';
 import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
 /**
  * React context for sharing state between SelectDropdown components.
  * Provides access to focus state and refs for keyboard navigation.
@@ -115,14 +116,29 @@
 };
 
 /**
  * Typed wrapper around react-select component.
- * Provides type safety for the underlying react-select implementation.
+ * Renders CreatableSelect when isCreatable is true, ReactSelect otherwise.
+ * Creatable-only props (formatCreateLabel, isValidNewOption) are stripped from
+ * the non-creatable path so they don't reach ReactSelect. `onCreateOption` is
+ * handled in SelectDropdown's changeHandler — do not pass it to CreatableSelect
+ * or react-select will skip onChange on create.
  */
 export function TypedReactSelect({
   selectRef,
+  isCreatable,
+  formatCreateLabel,
+  isValidNewOption,
   ...props
 }) {
+  if (isCreatable) {
+    return /*#__PURE__*/_jsx(CreatableSelect, {
+      ...props,
+      formatCreateLabel: formatCreateLabel,
+      isValidNewOption: isValidNewOption,
+      ref: selectRef
+    });
+  }
   return /*#__PURE__*/_jsx(ReactSelect, {
     ...props,
     ref: selectRef
   });
Index: package/dist/Form/SelectDropdown/elements/controls.js
===================================================================
--- package/dist/Form/SelectDropdown/elements/controls.js
+++ package/dist/Form/SelectDropdown/elements/controls.js
@@ -35,17 +35,15 @@
  * The icon type depends on whether the select is searchable or not.
  */
 export const DropdownButton = props => {
   const {
-    size,
-    isSearchable
+    size
   } = props.selectProps;
   const color = props.isDisabled ? 'text-disabled' : 'text';
   const iconSize = size ?? 'medium';
-  const iconType = isSearchable ? 'Searchable' : 'Chevron';
   const {
     ...iconProps
-  } = indicatorIcons[`${iconSize}${iconType}`];
+  } = indicatorIcons[`${iconSize}Chevron`];
   const {
     icon: IndicatorIcon
   } = iconProps;
   return /*#__PURE__*/_jsx(DropdownIndicator, {
@@ -65,9 +63,9 @@
   },
   '&:focus-visible': {
     outline: `2px solid ${theme.colors.primary}`
   }
-}), 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== */");
+}), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9Gb3JtL1NlbGVjdERyb3Bkb3duL2VsZW1lbnRzL2NvbnRyb2xzLnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFvRGlDIiwiZmlsZSI6Ii4uLy4uLy4uLy4uL3NyYy9Gb3JtL1NlbGVjdERyb3Bkb3duL2VsZW1lbnRzL2NvbnRyb2xzLnRzeCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNzcywgdGhlbWUgfSBmcm9tICdAY29kZWNhZGVteS9nYW11dC1zdHlsZXMnO1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnO1xuaW1wb3J0IHsgS2V5Ym9hcmRFdmVudCwgdXNlQ29udGV4dCB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7XG4gIEFyaWFPbkZvY3VzLFxuICBjb21wb25lbnRzIGFzIFNlbGVjdERyb3Bkb3duRWxlbWVudHMsXG59IGZyb20gJ3JlYWN0LXNlbGVjdCc7XG5cbmltcG9ydCB7IEV4dGVuZGVkT3B0aW9uLCBTaXplZEluZGljYXRvclByb3BzIH0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHsgaW5kaWNhdG9ySWNvbnMgfSBmcm9tICcuL2NvbnN0YW50cyc7XG5pbXBvcnQgeyBTZWxlY3REcm9wZG93bkNvbnRleHQgfSBmcm9tICcuL2NvbnRhaW5lcnMnO1xuXG5jb25zdCB7IERyb3Bkb3duSW5kaWNhdG9yIH0gPSBTZWxlY3REcm9wZG93bkVsZW1lbnRzO1xuXG4vKipcbiAqIEdlbmVyYXRlcyBhY2Nlc3NpYmxlIGZvY3VzIG1lc3NhZ2VzIGZvciBzY3JlZW4gcmVhZGVycy5cbiAqIFByb3ZpZGVzIGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50bHkgZm9jdXNlZCBvcHRpb24uXG4gKlxuICogQHBhcmFtIHBhcmFtcyAtIE9iamVjdCBjb250YWluaW5nIHRoZSBmb2N1c2VkIG9wdGlvbiBkZXRhaWxzXG4gKiBAcmV0dXJucyBGb3JtYXR0ZWQgYWNjZXNzaWJpbGl0eSBtZXNzYWdlXG4gKi9cbmV4cG9ydCBjb25zdCBvbkZvY3VzOiBBcmlhT25Gb2N1czxFeHRlbmRlZE9wdGlvbj4gPSAoe1xuICBmb2N1c2VkOiB7IGxhYmVsLCBzdWJ0aXRsZSwgcmlnaHRMYWJlbCwgZGlzYWJsZWQgfSxcbn0pID0+IHtcbiAgY29uc3QgZm9ybWF0dGVkU3VidGl0bGUgPSBgLCAke3N1YnRpdGxlfWA7XG4gIGNvbnN0IGZvcm1hdHRlZFJpZ2h0TGFiZWwgPSBgLCAke3JpZ2h0TGFiZWx9YDtcblxuICBjb25zdCBtc2cgPSBgWW91IGFyZSBjdXJyZW50bHkgZm9jdXNlZCBvbiBvcHRpb24gJHtsYWJlbH0ke1xuICAgIHN1YnRpdGxlID8gZm9ybWF0dGVkU3VidGl0bGUgOiAnJ1xuICB9ICR7cmlnaHRMYWJlbCA/IGZvcm1hdHRlZFJpZ2h0TGFiZWwgOiAnJ30ke2Rpc2FibGVkID8gJywgZGlzYWJsZWQnIDogJyd9YDtcblxuICByZXR1cm4gbXNnO1xufTtcblxuLyoqXG4gKiBDdXN0b20gZHJvcGRvd24gaW5kaWNhdG9yIHRoYXQgc2hvd3MgZWl0aGVyIGEgY2hldnJvbiBvciBzZWFyY2ggaWNvbi5cbiAqIFRoZSBpY29uIHR5cGUgZGVwZW5kcyBvbiB3aGV0aGVyIHRoZSBzZWxlY3QgaXMgc2VhcmNoYWJsZSBvciBub3QuXG4gKi9cbmV4cG9ydCBjb25zdCBEcm9wZG93bkJ1dHRvbiA9IChwcm9wczogU2l6ZWRJbmRpY2F0b3JQcm9wcykgPT4ge1xuICBjb25zdCB7IHNpemUgfSA9IHByb3BzLnNlbGVjdFByb3BzO1xuICBjb25zdCBjb2xvciA9IHByb3BzLmlzRGlzYWJsZWQgPyAndGV4dC1kaXNhYmxlZCcgOiAndGV4dCc7XG4gIGNvbnN0IGljb25TaXplID0gc2l6ZSA/PyAnbWVkaXVtJztcbiAgY29uc3QgeyAuLi5pY29uUHJvcHMgfSA9IGluZGljYXRvckljb25zW2Ake2ljb25TaXplfUNoZXZyb25gXTtcbiAgY29uc3QgeyBpY29uOiBJbmRpY2F0b3JJY29uIH0gPSBpY29uUHJvcHM7XG5cbiAgcmV0dXJuIChcbiAgICA8RHJvcGRvd25JbmRpY2F0b3Igey4uLnByb3BzfT5cbiAgICAgIDxJbmRpY2F0b3JJY29uIHsuLi5pY29uUHJvcHN9IGNvbG9yPXtjb2xvcn0gLz5cbiAgICA8L0Ryb3Bkb3duSW5kaWNhdG9yPlxuICApO1xufTtcblxuY29uc3QgQ3VzdG9tU3R5bGVkUmVtb3ZlQWxsRGl2ID0gc3R5bGVkKCdkaXYnKShcbiAgY3NzKHtcbiAgICAnJjpmb2N1cyc6IHtcbiAgICAgIG91dGxpbmU6IGAycHggc29saWQgJHt0aGVtZS5jb2xvcnMucHJpbWFyeX1gLFxuICAgIH0sXG4gICAgJyY6Zm9jdXMtdmlzaWJsZSc6IHtcbiAgICAgIG91dGxpbmU6IGAycHggc29saWQgJHt0aGVtZS5jb2xvcnMucHJpbWFyeX1gLFxuICAgIH0sXG4gIH0pXG4pO1xuXG4vKipcbiAqIEN1c3RvbSByZW1vdmUgYWxsIGJ1dHRvbiBmb3IgbXVsdGktc2VsZWN0IG1vZGUuXG4gKiBQcm92aWRlcyBrZXlib2FyZCBuYXZpZ2F0aW9uIGFuZCBhY2Nlc3NpYmxlIHJlbW92YWwgb2YgYWxsIHNlbGVjdGVkIHZhbHVlcy5cbiAqL1xuZXhwb3J0IGNvbnN0IFJlbW92ZUFsbEJ1dHRvbiA9IChwcm9wczogU2l6ZWRJbmRpY2F0b3JQcm9wcykgPT4ge1xuICBjb25zdCB7XG4gICAgZ2V0U3R5bGVzLFxuICAgIGlubmVyUHJvcHM6IHsgLi4ucmVzdElubmVyUHJvcHMgfSxcbiAgICBzZWxlY3RQcm9wczogeyBzaXplIH0sXG4gIH0gPSBwcm9wcztcblxuICBjb25zdCB7IHJlbW92ZUFsbEJ1dHRvblJlZiwgc2VsZWN0SW5wdXRSZWYgfSA9IHVzZUNvbnRleHQoXG4gICAgU2VsZWN0RHJvcGRvd25Db250ZXh0XG4gICk7XG5cbiAgY29uc3QgaWNvblNpemUgPSBzaXplID8/ICdtZWRpdW0nO1xuICBjb25zdCB7IC4uLmljb25Qcm9wcyB9ID0gaW5kaWNhdG9ySWNvbnNbYCR7aWNvblNpemV9UmVtb3ZlYF07XG4gIGNvbnN0IHsgaWNvbjogSW5kaWNhdG9ySWNvbiB9ID0gaWNvblByb3BzO1xuXG4gIGNvbnN0IG9uS2V5UHJlc3MgPSAoZTogS2V5Ym9hcmRFdmVudDxIVE1MRGl2RWxlbWVudD4pID0+IHtcbiAgICBpZiAoZS5rZXkgPT09ICdFbnRlcicgJiYgcmVzdElubmVyUHJvcHMub25Nb3VzZURvd24pIHtcbiAgICAgIHJlc3RJbm5lclByb3BzLm9uTW91c2VEb3duKGUgYXMgYW55KTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBzZWxlY3RJbnB1dFJlZj8uY3VycmVudCAmJlxuICAgICAgKGUua2V5ID09PSAnQXJyb3dSaWdodCcgfHwgZS5rZXkgPT09ICdBcnJvd0xlZnQnIHx8IGUua2V5ID09PSAnQXJyb3dEb3duJylcbiAgICApIHtcbiAgICAgIHNlbGVjdElucHV0UmVmPy5jdXJyZW50LmZvY3VzKCk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IHN0eWxlID0gZ2V0U3R5bGVzKCdjbGVhckluZGljYXRvcicsIHByb3BzKSBhcyBSZWFjdC5DU1NQcm9wZXJ0aWVzO1xuXG4gIHJldHVybiAoXG4gICAgPEN1c3RvbVN0eWxlZFJlbW92ZUFsbERpdlxuICAgICAgYXJpYS1sYWJlbD1cIlJlbW92ZSBhbGwgc2VsZWN0ZWRcIlxuICAgICAgcm9sZT1cImJ1dHRvblwiXG4gICAgICB0YWJJbmRleD17MH1cbiAgICAgIHsuLi5yZXN0SW5uZXJQcm9wc31cbiAgICAgIHJlZj17cmVtb3ZlQWxsQnV0dG9uUmVmfVxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGdhbXV0L25vLWlubGluZS1zdHlsZVxuICAgICAgc3R5bGU9e3N0eWxlfVxuICAgICAgb25LZXlEb3duPXtvbktleVByZXNzfVxuICAgID5cbiAgICAgIDxJbmRpY2F0b3JJY29uIHsuLi5pY29uUHJvcHN9IGNvbG9yPVwidGV4dFwiIC8+XG4gICAgPC9DdXN0b21TdHlsZWRSZW1vdmVBbGxEaXY+XG4gICk7XG59O1xuIl19 */");
 
 /**
  * Custom remove all button for multi-select mode.
  * Provides keyboard navigation and accessible removal of all selected values.
Index: package/dist/Form/SelectDropdown/elements/options.js
===================================================================
--- package/dist/Form/SelectDropdown/elements/options.js
+++ package/dist/Form/SelectDropdown/elements/options.js
@@ -43,8 +43,9 @@
 
 /**
  * Custom option component that displays a check icon for selected items.
  * Also manages ARIA attributes for accessibility.
+ * Skips the check icon for react-select/creatable's "Add" row (__isNew__).
  */
 export const IconOption = ({
   children,
   ...rest
@@ -53,17 +54,19 @@
     size
   } = rest.selectProps;
   const {
     isFocused,
-    innerProps
+    innerProps,
+    data
   } = rest;
+  const isNew = data?.__isNew__;
   return /*#__PURE__*/_jsxs(SelectDropdownElements.Option, {
     ...rest,
     innerProps: {
       ...innerProps,
       'aria-selected': isFocused
     },
-    children: [children, rest?.isSelected && /*#__PURE__*/_jsx(CheckIcon, {
+    children: [children, !isNew && rest?.isSelected && /*#__PURE__*/_jsx(CheckIcon, {
       size: selectedIconSize[size ?? 'medium']
     })]
   });
 };
Index: package/dist/Form/SelectDropdown/SelectDropdown.js
===================================================================
--- package/dist/Form/SelectDropdown/SelectDropdown.js
+++ package/dist/Form/SelectDropdown/SelectDropdown.js
@@ -3,9 +3,9 @@
 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 { filterValueFromOptions, getCreatedOptionValue, isMultipleSelectProps, isOptionsGrouped, isSingleSelectProps, removeValueFromSelectedOptions } from './utils';
 import { jsx as _jsx } from "react/jsx-runtime";
 const defaultProps = {
   name: undefined,
   components: {
@@ -72,24 +72,32 @@
 export const SelectDropdown = ({
   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,
   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);
@@ -125,41 +133,43 @@
   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.
+  // Sync multi-select value from props when controlled (`value` is a string[]).
+  // Uncontrolled multi (`value` undefined or '') keeps selection in local state.
   useEffect(() => {
+    if (!multiple || !Array.isArray(value)) return;
     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 => {
+  }, [options, value, multiple]);
+  const changeHandler = useCallback((optionEvent, actionMeta) => {
     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
+    if (actionMeta.action === 'create-option') {
+      const createdValue = getCreatedOptionValue(optionEvent, actionMeta, multiple);
+      if (createdValue) {
+        onCreateOption?.(createdValue);
+      }
+    }
     const onChangeProps = {
       onChange,
       multiple
     };
+    const forwardedMeta = actionMeta.action === 'create-option' ? actionMeta : {
+      action: onChangeAction,
+      option: isMultipleSelectProps(onChangeProps) ? undefined : optionEvent
+    };
     if (isSingleSelectProps(onChangeProps)) {
       const singleOptionEvent = optionEvent;
-      onChangeProps.onChange?.(singleOptionEvent, {
-        action: onChangeAction,
-        option: singleOptionEvent
-      });
+      onChangeProps.onChange?.(singleOptionEvent, forwardedMeta);
     }
     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)
-      });
+      onChangeProps.onChange?.(optionEvent, forwardedMeta);
     }
-  }, [onChange, multiple]);
+  }, [onChange, multiple, onCreateOption]);
   const keyPressHandler = e => {
     if (multiple && e.key === 'Enter' && currentFocusedValue && multiValues) {
       const newMultiValues = removeValueFromSelectedOptions(multiValues, currentFocusedValue);
       if (newMultiValues !== multiValues) setMultiValues(newMultiValues);
@@ -167,8 +177,10 @@
     if (removeAllButtonRef.current !== null && e.key === 'ArrowRight' && multiValues && currentFocusedValue === multiValues[multiValues.length - 1].value) {
       removeAllButtonRef.current.focus();
     }
   };
+  const noOptionsMessage = validationMessage === undefined ? undefined // fall back to react-select default ("No options")
+  : typeof validationMessage === 'function' ? validationMessage : () => validationMessage;
   const theme = useTheme();
   const memoizedStyles = useMemo(() => {
     return getMemoizedStyles(theme, zIndex);
   }, [theme, zIndex]);
@@ -187,30 +199,35 @@
         onFocus
       },
       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,
+      onInputChange: onInputChange,
       onKeyDown: multiple ? e => keyPressHandler(e) : undefined,
       ...rest
     })
   });
Index: package/dist/Form/SelectDropdown/styles.js
===================================================================
--- package/dist/Form/SelectDropdown/styles.js
+++ package/dist/Form/SelectDropdown/styles.js
@@ -136,8 +136,10 @@
         ...dropdownBorderStates({
           error: state.selectProps.error,
           theme
         }),
+        // Drop react-select's default menu drop shadow; the border above defines the edge.
+        boxShadow: 'none',
         ...(dropdownWidth ? {
           minWidth: dropdownWidth,
           width: dropdownWidth
         } : {}),
@@ -193,18 +195,34 @@
       ':hover': {
         backgroundColor: theme.colors['secondary-hover']
       }
     }),
-    option: (provided, state) => ({
-      ...getOptionBackground(state.isSelected, state.isFocused)({
-        theme
-      }),
-      alignItems: 'center',
-      color: state.isDisabled ? 'text-disabled' : 'default',
-      cursor: state.isDisabled ? 'not-allowed' : 'pointer',
-      display: 'flex',
-      padding: state.selectProps.size === 'small' ? '3px 14px' : '11px 14px'
+    noOptionsMessage: provided => ({
+      ...provided,
+      color: theme.colors['text-secondary']
     }),
+    option: (provided, state) => {
+      const isNew = state.data?.__isNew__;
+      const isSmall = state.selectProps.size === 'small';
+      return {
+        ...getOptionBackground(state.isSelected, state.isFocused)({
+          theme
+        }),
+        alignItems: 'center',
+        color: isNew ? state.isDisabled ? theme.colors['text-disabled'] : theme.colors.primary : state.isDisabled ? theme.colors['text-disabled'] : theme.colors.text,
+        cursor: state.isDisabled ? 'not-allowed' : 'pointer',
+        display: 'flex',
+        padding: isSmall ? '3px 14px' : '11px 14px',
+        ...(isNew && {
+          // Gradient creates the 1px divider line centred in the 16px spacer above the option text
+          backgroundImage: `linear-gradient(${theme.colors['text-disabled']} 1px, transparent 1px)`,
+          backgroundPosition: '0 8px',
+          backgroundRepeat: 'no-repeat',
+          backgroundSize: '100% 1px',
+          paddingTop: isSmall ? '19px' : '27px'
+        })
+      };
+    },
     placeholder: provided => ({
       ...provided,
       ...placeholderColor({
         theme
Index: package/dist/Form/SelectDropdown/utils.js
===================================================================
--- package/dist/Form/SelectDropdown/utils.js
+++ package/dist/Form/SelectDropdown/utils.js
@@ -1,6 +1,20 @@
 export const isMultipleSelectProps = props => !!props.multiple;
 export const isSingleSelectProps = props => !props.multiple;
+/**
+ * Resolves the value for a newly created option from react-select action metadata
+ * or the onChange option payload. Returns undefined when no reliable value exists.
+ */
+export const getCreatedOptionValue = (optionEvent, actionMeta, multiple) => {
+  const metaValue = actionMeta.option?.value;
+  if (metaValue) return metaValue;
+  if (!multiple) {
+    const value = optionEvent.value;
+    return value || undefined;
+  }
+  const newOption = optionEvent.find(option => option.__isNew__);
+  return newOption?.value || undefined;
+};
 export const isOptionGroup = obj => obj != null && typeof obj === 'object' && 'options' in obj && obj.options !== undefined;
 export const isOptionsGrouped = options => Array.isArray(options) && options.some(option => isOptionGroup(option));
 
 /**
Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,16 +1,16 @@
 {
   "name": "@codecademy/gamut",
   "description": "Styleguide & Component library for Codecademy",
-  "version": "71.0.0",
+  "version": "71.0.1-alpha.69ab4c.0",
   "author": "Codecademy Engineering <[email protected]>",
   "bin": "./bin/gamut.mjs",
   "dependencies": {
-    "@codecademy/gamut-icons": "9.57.7",
-    "@codecademy/gamut-illustrations": "0.58.13",
-    "@codecademy/gamut-patterns": "0.10.32",
-    "@codecademy/gamut-styles": "20.0.0",
-    "@codecademy/variance": "0.26.1",
+    "@codecademy/gamut-icons": "9.57.8-alpha.69ab4c.0",
+    "@codecademy/gamut-illustrations": "0.58.14-alpha.69ab4c.0",
+    "@codecademy/gamut-patterns": "0.10.33-alpha.69ab4c.0",
+    "@codecademy/gamut-styles": "20.0.1-alpha.69ab4c.0",
+    "@codecademy/variance": "0.26.2-alpha.69ab4c.0",
     "@formatjs/intl-locale": "5.3.1",
     "@react-aria/interactions": "3.25.0",
     "@types/marked": "^4.0.8",
     "@vidstack/react": "^1.12.12",
Index: package/agent-tools/skills/gamut-forms/SKILL.md
===================================================================
--- package/agent-tools/skills/gamut-forms/SKILL.md
+++ package/agent-tools/skills/gamut-forms/SKILL.md
@@ -25,8 +25,14 @@
 - Checkbox, Radio, Select: same pairing; checkbox/radio use the visually hidden input pattern from `@codecademy/gamut-styles` where applicable.
 
 ---
 
+## SelectDropdown
+
+For `SelectDropdown` — single vs multi value, controlled vs uncontrolled patterns, creatable options, and react-select action metadata — use [`gamut-select-dropdown`](../gamut-select-dropdown/SKILL.md). Generic `FormGroup` wiring (labels, errors, live regions) still applies as documented below; SelectDropdown-specific state contracts live in that skill.
+
+---
+
 ## `FormGroup` (baseline)
 
 [`FormGroup.tsx`](https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/Form/elements/FormGroup.tsx)
Index: package/dist/Form/SelectDropdown/types/component-props.d.ts
===================================================================
--- package/dist/Form/SelectDropdown/types/component-props.d.ts
+++ package/dist/Form/SelectDropdown/types/component-props.d.ts
@@ -1,6 +1,6 @@
 import { Ref, SelectHTMLAttributes } from 'react';
-import { Props as NamedProps } from 'react-select';
+import { Options as OptionsType, Props as NamedProps } from 'react-select';
 import { SelectComponentProps } from '../../inputs/Select';
 import { OptionStrict, SelectDropdownGroup, SelectDropdownOptions } from './options';
 import { ReactSelectAdditionalProps, SelectDropdownSizes, SharedProps } from './styles';
 /**
@@ -27,9 +27,9 @@
 /**
  * Core props interface that defines the essential properties for SelectDropdown.
  * This interface combines base props with react-select props and HTML select attributes.
  */
-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 {
+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 {
     /** Required name attribute for the select input */
     name: string;
     /** Placeholder text shown when no option is selected.
      * Placeholder text is not recommended for accessibility. If you need to use placeholder text,
@@ -37,8 +37,41 @@
      * I.e - if the placeholder text describes an action you'd like the user to take, please use a label instead. */
     placeholder?: string;
     /** Array of options or option groups to display in the dropdown */
     options?: SelectDropdownOptions | SelectDropdownGroup[];
+    /**
+     * Allows users to create new options by typing a value not in the options list.
+     * When true, isSearchable is automatically set to true.
+     * Pair with onCreateOption to persist new options.
+     */
+    isCreatable?: boolean;
+    /**
+     * Called when the user confirms a new option via the "Add" row.
+     * Convenience callback for persisting the new value to your `options` list.
+     * Selection updates are delivered through `onChange` with `action: 'create-option'`.
+     */
+    onCreateOption?: (inputValue: string) => void;
+    /**
+     * Customises the label shown in the "Add" row.
+     * Defaults to: (inputValue) => `Add "${inputValue}"`.
+     */
+    formatCreateLabel?: (inputValue: string) => React.ReactNode;
+    /**
+     * Controls when the "Add" row is visible.
+     * Receives the current input, selected values, and all options.
+     * Defaults to react-select's built-in logic (hidden when input matches an existing option label).
+     * Use cases: minimum-length gating, pattern validation, case-insensitive dedup, max-items cap.
+     */
+    isValidNewOption?: (inputValue: string, value: OptionsType<OptionStrict>, options: OptionsType<OptionStrict>) => boolean;
+    /**
+     * Customizes the message shown inside the dropdown menu when no option matches
+     * the current input (react-select's "No options" state). Useful for surfacing
+     * validation/error text directly in the dropdown. Accepts a node, or a function
+     * receiving the current input value.
+     */
+    validationMessage?: React.ReactNode | ((obj: {
+        inputValue: string;
+    }) => React.ReactNode);
 }
 /**
  * Props for single-select mode.
  * When multiple is false or undefined, only one option can be selected.
@@ -59,12 +92,24 @@
     /** Callback fired when the selected values change */
     onChange?: NamedProps<OptionStrict, true>['onChange'];
 }
 /**
+ * Enforces that isSearchable cannot be false when isCreatable is true.
+ * Creatable mode requires the search input so users can type new option values.
+ */
+type CreatableConstraint = {
+    isCreatable?: false | undefined;
+    isSearchable?: boolean;
+} | {
+    isCreatable: true;
+    isSearchable?: true;
+};
+/**
  * Union type for all SelectDropdown prop variants.
- * Supports both single and multi-select modes through discriminated union.
+ * Supports both single and multi-select modes through discriminated union,
+ * intersected with CreatableConstraint to enforce isSearchable compatibility.
  */
-export type SelectDropdownProps = SingleSelectDropdownProps | MultiSelectDropdownProps;
+export type SelectDropdownProps = (SingleSelectDropdownProps | MultiSelectDropdownProps) & CreatableConstraint;
 /**
  * Base interface for onChange-related props.
  * Used internally for type checking and prop validation.
  */
@@ -75,10 +120,17 @@
     onChange?: SingleSelectDropdownProps['onChange'] | MultiSelectDropdownProps['onChange'];
 }
 /**
  * Props for the typed React Select component wrapper.
- * Extends ReactSelectAdditionalProps with an optional ref.
+ * Extends ReactSelectAdditionalProps with an optional ref and creatable flag.
  */
 export interface TypedReactSelectProps extends ReactSelectAdditionalProps {
     /** Optional ref to the underlying react-select component */
     selectRef?: Ref<any>;
+    /** When true, renders CreatableSelect instead of ReactSelect */
+    isCreatable?: boolean;
+    /** Customises the "Add" row label */
+    formatCreateLabel?: (inputValue: string) => React.ReactNode;
+    /** Controls visibility of the "Add" row */
+    isValidNewOption?: (inputValue: string, value: OptionsType<OptionStrict>, options: OptionsType<OptionStrict>) => boolean;
 }
+export {};
Index: package/dist/Form/SelectDropdown/elements/constants.d.ts
===================================================================
--- package/dist/Form/SelectDropdown/elements/constants.d.ts
+++ package/dist/Form/SelectDropdown/elements/constants.d.ts
@@ -14,16 +14,8 @@
     mediumChevron: {
         size: number;
         icon: import("react").ForwardRefExoticComponent<import("@codecademy/gamut-icons").GamutIconProps & import("react").RefAttributes<SVGSVGElement>>;
     };
-    smallSearchable: {
-        size: number;
-        icon: import("react").ForwardRefExoticComponent<import("@codecademy/gamut-icons").GamutIconProps & import("react").RefAttributes<SVGSVGElement>>;
-    };
-    mediumSearchable: {
-        size: number;
-        icon: import("react").ForwardRefExoticComponent<import("@codecademy/gamut-icons").GamutIconProps & import("react").RefAttributes<SVGSVGElement>>;
-    };
     smallRemove: {
         size: number;
         icon: import("react").ForwardRefExoticComponent<import("@codecademy/gamut-icons").GamutIconProps & import("react").RefAttributes<SVGSVGElement>>;
     };
Index: package/dist/Form/SelectDropdown/elements/containers.d.ts
===================================================================
--- package/dist/Form/SelectDropdown/elements/containers.d.ts
+++ package/dist/Form/SelectDropdown/elements/containers.d.ts
@@ -23,7 +23,11 @@
  */
 export declare const CustomInput: ({ ...rest }: CustomSelectComponentProps<typeof SelectDropdownElements.Input>) => import("react/jsx-runtime").JSX.Element;
 /**
  * Typed wrapper around react-select component.
- * Provides type safety for the underlying react-select implementation.
+ * Renders CreatableSelect when isCreatable is true, ReactSelect otherwise.
+ * Creatable-only props (formatCreateLabel, isValidNewOption) are stripped from
+ * the non-creatable path so they don't reach ReactSelect. `onCreateOption` is
+ * handled in SelectDropdown's changeHandler — do not pass it to CreatableSelect
+ * or react-select will skip onChange on create.
  */
-export declare function TypedReactSelect<OptionType, IsMulti extends boolean = false, GroupType extends GroupBase<OptionType> = GroupBase<OptionType>>({ selectRef, ...props }: Props<OptionType, IsMulti, GroupType> & TypedReactSelectProps): import("react/jsx-runtime").JSX.Element;
+export declare function TypedReactSelect<OptionType, IsMulti extends boolean = false, GroupType extends GroupBase<OptionType> = GroupBase<OptionType>>({ selectRef, isCreatable, formatCreateLabel, isValidNewOption, ...props }: Props<OptionType, IsMulti, GroupType> & TypedReactSelectProps): import("react/jsx-runtime").JSX.Element;
Index: package/dist/Form/SelectDropdown/elements/options.d.ts
===================================================================
--- package/dist/Form/SelectDropdown/elements/options.d.ts
+++ package/dist/Form/SelectDropdown/elements/options.d.ts
@@ -2,8 +2,9 @@
 import { CustomSelectComponentProps, ExtendedOption, SelectDropdownGroup } from '../types';
 /**
  * Custom option component that displays a check icon for selected items.
  * Also manages ARIA attributes for accessibility.
+ * Skips the check icon for react-select/creatable's "Add" row (__isNew__).
  */
 export declare const IconOption: ({ children, ...rest }: CustomSelectComponentProps<typeof SelectDropdownElements.Option>) => import("react/jsx-runtime").JSX.Element;
 /**
  * Custom single value component that displays abbreviated text when available.
Index: package/dist/Form/SelectDropdown/types/styles.d.ts
===================================================================
--- package/dist/Form/SelectDropdown/types/styles.d.ts
+++ package/dist/Form/SelectDropdown/types/styles.d.ts
@@ -68,6 +68,10 @@
  */
 export type OptionState = BaseSelectComponentProps & InteractionStates & {
     /** Whether the option is selected */
     isSelected: boolean;
+    /** Option data — includes __isNew__ for react-select/creatable's "Add" row */
+    data?: {
+        __isNew__?: boolean;
+    };
 };
 export {};
Index: package/dist/Form/SelectDropdown/utils.d.ts
===================================================================
--- package/dist/Form/SelectDropdown/utils.d.ts
+++ package/dist/Form/SelectDropdown/utils.d.ts
@@ -1,8 +1,14 @@
+import { ActionMeta, Options as OptionsType } from 'react-select';
 import { SelectOptionBase } from '../utils';
-import { BaseOnChangeProps, ExtendedOption, MultiSelectDropdownProps, SelectDropdownGroup, SelectDropdownOptions, SelectDropdownProps, SingleSelectDropdownProps } from './types';
+import { BaseOnChangeProps, ExtendedOption, MultiSelectDropdownProps, OptionStrict, SelectDropdownGroup, SelectDropdownOptions, SelectDropdownProps, SingleSelectDropdownProps } from './types';
 export declare const isMultipleSelectProps: (props: BaseOnChangeProps) => props is MultiSelectDropdownProps;
 export declare const isSingleSelectProps: (props: BaseOnChangeProps) => props is SingleSelectDropdownProps;
+/**
+ * Resolves the value for a newly created option from react-select action metadata
+ * or the onChange option payload. Returns undefined when no reliable value exists.
+ */
+export declare const getCreatedOptionValue: (optionEvent: OptionStrict | OptionsType<OptionStrict>, actionMeta: ActionMeta<OptionStrict>, multiple?: boolean) => string | undefined;
 export declare const isOptionGroup: (obj: unknown) => obj is SelectDropdownGroup;
 export declare const isOptionsGrouped: (options: SelectDropdownOptions) => options is SelectDropdownGroup[];
 /**
  * Filters options based on the selected value(s).