@codecademy/gamut 72.2.3-alpha.83b0a8.0 → 72.2.3-alpha.8ab930.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.
- package/agent-tools/skills/gamut-forms/SKILL.md +0 -16
- package/dist/ConnectedForm/ConnectedFormGroup.js +2 -2
- package/dist/Form/SelectDropdown/SelectDropdown.js +101 -49
- package/dist/Form/SelectDropdown/elements/constants.d.ts +8 -0
- package/dist/Form/SelectDropdown/elements/constants.js +9 -1
- package/dist/Form/SelectDropdown/elements/containers.d.ts +2 -6
- package/dist/Form/SelectDropdown/elements/containers.js +1 -17
- package/dist/Form/SelectDropdown/elements/controls.d.ts +15 -1
- package/dist/Form/SelectDropdown/elements/controls.js +91 -2
- package/dist/Form/SelectDropdown/elements/index.d.ts +1 -2
- package/dist/Form/SelectDropdown/elements/index.js +1 -2
- package/dist/Form/SelectDropdown/elements/options.d.ts +0 -1
- package/dist/Form/SelectDropdown/elements/options.js +2 -5
- package/dist/Form/SelectDropdown/{core/styles.js → styles.js} +12 -30
- package/dist/Form/SelectDropdown/types/component-props.d.ts +6 -54
- package/dist/Form/SelectDropdown/types/internal.d.ts +4 -4
- package/dist/Form/SelectDropdown/types/styles.d.ts +1 -5
- package/dist/Form/SelectDropdown/{core/utils.d.ts → utils.d.ts} +2 -12
- package/dist/Form/SelectDropdown/{core/utils.js → utils.js} +2 -24
- package/dist/Form/styles/index.d.ts +1 -1
- package/dist/Form/styles/index.js +1 -1
- package/dist/Menu/MenuItem.d.ts +2 -0
- package/dist/Menu/MenuItem.js +2 -0
- package/dist/Menu/elements.d.ts +1 -0
- package/dist/Menu/elements.js +7 -5
- package/dist/Tag/index.js +1 -1
- package/dist/Tip/ToolTip/index.d.ts +5 -0
- package/dist/Tip/shared/FloatingTip.js +15 -0
- package/dist/Tip/shared/InlineTip.js +23 -2
- package/dist/Tip/shared/elements.d.ts +1 -1
- package/dist/Tip/shared/elements.js +16 -7
- package/dist/Tip/shared/types.d.ts +2 -1
- package/package.json +6 -6
- package/agent-tools/skills/gamut-select-dropdown/SKILL.md +0 -236
- package/dist/Form/SelectDropdown/core/accessibility.d.ts +0 -3
- package/dist/Form/SelectDropdown/core/accessibility.js +0 -12
- package/dist/Form/SelectDropdown/core/constants.d.ts +0 -13
- package/dist/Form/SelectDropdown/core/constants.js +0 -14
- package/dist/Form/SelectDropdown/hooks/useSelectHandlers.d.ts +0 -22
- package/dist/Form/SelectDropdown/hooks/useSelectHandlers.js +0 -62
- package/dist/Form/SelectDropdown/hooks/useSelectOptions.d.ts +0 -14
- package/dist/Form/SelectDropdown/hooks/useSelectOptions.js +0 -39
- /package/dist/Form/SelectDropdown/{core/styles.d.ts → styles.d.ts} +0 -0
|
@@ -26,22 +26,6 @@ For typical product forms, prefer `GridForm` (declarative `fields`, `LayoutGrid`
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
-
## SelectDropdown vs Select
|
|
30
|
-
|
|
31
|
-
Use `Select` for standard single-select fields where bundle size matters and no special styling is needed. Use `SelectDropdown` when the design calls for any of:
|
|
32
|
-
|
|
33
|
-
- Styled dropdown menu (react-select appearance)
|
|
34
|
-
- Search / typeahead
|
|
35
|
-
- Multi-select with tags
|
|
36
|
-
- Creatable options
|
|
37
|
-
- Option icons, subtitles, right labels, abbreviations, or grouped options
|
|
38
|
-
|
|
39
|
-
`SelectDropdown` carries a larger JS dependency (react-select); don't reach for it as a default drop-in for `Select`.
|
|
40
|
-
|
|
41
|
-
For full SelectDropdown API detail — controlled vs uncontrolled patterns, creatable options, 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.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
29
|
## `FormGroup` (baseline)
|
|
46
30
|
|
|
47
31
|
`packages/gamut/src/Form/elements/FormGroup.tsx`
|
|
@@ -13,7 +13,7 @@ const ErrorAnchor = /*#__PURE__*/_styled(Anchor, {
|
|
|
13
13
|
label: "ErrorAnchor"
|
|
14
14
|
})(css({
|
|
15
15
|
color: 'feedback-error'
|
|
16
|
-
}), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9Db25uZWN0ZWRGb3JtL0Nvbm5lY3RlZEZvcm1Hcm91cC50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBY29CIiwiZmlsZSI6Ii4uLy4uL3NyYy9Db25uZWN0ZWRGb3JtL0Nvbm5lY3RlZEZvcm1Hcm91cC50c3giLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tICdAY29kZWNhZGVteS9nYW11dC1zdHlsZXMnO1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnO1xuaW1wb3J0IHsgdXNlRWZmZWN0LCB1c2VJZCB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7IFJlZ2lzdGVyT3B0aW9ucyB9IGZyb20gJ3JlYWN0LWhvb2stZm9ybSc7XG5cbmltcG9ydCB7IEZvcm1FcnJvciwgRm9ybUdyb3VwLCBGb3JtR3JvdXBMYWJlbCwgRm9ybUdyb3VwUHJvcHMgfSBmcm9tICcuLic7XG5pbXBvcnQgeyBBbmNob3IgfSBmcm9tICcuLi9BbmNob3InO1xuaW1wb3J0IHsgTWFya2Rvd24gfSBmcm9tICcuLi9NYXJrZG93bic7XG5pbXBvcnQgeyBJbmZvVGlwU3ViQ29tcG9uZW50UHJvcHMgfSBmcm9tICcuLi9UaXAvSW5mb1RpcC90eXBlLXV0aWxzJztcbmltcG9ydCB7IFRleHQgfSBmcm9tICcuLi9UeXBvZ3JhcGh5JztcbmltcG9ydCB7IENvbm5lY3RlZEZpZWxkLCBGaWVsZFByb3BzLCBTdWJtaXRDb250ZXh0UHJvcHMgfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IGdldEVycm9yTWVzc2FnZSwgdXNlRmllbGQgfSBmcm9tICcuL3V0aWxzJztcblxuY29uc3QgRXJyb3JBbmNob3IgPSBzdHlsZWQoQW5jaG9yKShcbiAgY3NzKHtcbiAgICBjb2xvcjogJ2ZlZWRiYWNrLWVycm9yJyxcbiAgfSlcbik7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29ubmVjdGVkRm9ybUdyb3VwQmFzZVByb3BzXG4gIGV4dGVuZHMgT21pdDxcbiAgICBGb3JtR3JvdXBQcm9wcyxcbiAgICAnbGFiZWwnIHwgJ2Rpc2FibGVkJyB8ICdkZXNjcmlwdGlvbicgfCAnaHRtbEZvcidcbiAgPiB7XG4gIGN1c3RvbUVycm9yPzogc3RyaW5nO1xuICBlcnJvclR5cGU/OiAnaW5pdGlhbCcgfCAnYWJzb2x1dGUnO1xuICBoaWRlTGFiZWw/OiBib29sZWFuO1xuICBuYW1lOiBzdHJpbmc7XG4gIGxhYmVsOiBSZWFjdC5SZWFjdE5vZGU7XG4gIHJlcXVpcmVkPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIEluZm9UaXAgdG8gZGlzcGxheSBuZXh0IHRvIHRoZSBmaWVsZCBsYWJlbC4gVGhlIEluZm9UaXAgYnV0dG9uIGlzXG4gICAqIGF1dG9tYXRpY2FsbHkgbGFiZWxsZWQgYnkgdGhlIGZpZWxkIGxhYmVsLiBUbyBvdmVycmlkZSB0aGlzIGJlaGF2aW9yLFxuICAgKiBwcm92aWRlIGBhcmlhTGFiZWxgIG9yIGBhcmlhTGFiZWxsZWRieWAuXG4gICAqL1xuICBpbmZvdGlwPzogSW5mb1RpcFN1YkNvbXBvbmVudFByb3BzO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3RlZEZvcm1Hcm91cFByb3BzPFQgZXh0ZW5kcyBDb25uZWN0ZWRGaWVsZD5cbiAgZXh0ZW5kcyBTdWJtaXRDb250ZXh0UHJvcHMsXG4gICAgQ29ubmVjdGVkRm9ybUdyb3VwQmFzZVByb3BzIHtcbiAgLyoqXG4gICAqIEFuIG9iamVjdCBjb25zaXN0aW5nIG9mIGEgYGNvbXBvbmVudGAga2V5IHRvIHNwZWNpZnkgd2hhdCBDb25uZWN0ZWRGb3JtSW5wdXQgdG8gcmVuZGVyIC0gdGhlIHJlbWFpbmluZyBrZXkvdmFsdWUgcGFpcnMgYXJlIHRoYXQgY29tcG9uZW50cyBkZXNpcmVkIHByb3BzLlxuICAgKi9cbiAgZmllbGQ6IE9taXQ8UmVhY3QuQ29tcG9uZW50UHJvcHM8VD4sICduYW1lJyB8ICdkaXNhYmxlZCc+ICZcbiAgICBGaWVsZFByb3BzPFQ+ICYge1xuICAgICAgY3VzdG9tVmFsaWRhdGlvbnM/OiBSZWdpc3Rlck9wdGlvbnM7XG4gICAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIENvbm5lY3RlZEZvcm1Hcm91cDxUIGV4dGVuZHMgQ29ubmVjdGVkRmllbGQ+KHtcbiAgY3VzdG9tRXJyb3IsXG4gIGNoaWxkcmVuLFxuICBkaXNhYmxlZCA9IGZhbHNlLFxuICBlcnJvclR5cGUgPSAnYWJzb2x1dGUnLFxuICBmaWVsZCxcbiAgaGlkZUxhYmVsLFxuICBpZCxcbiAgbGFiZWwsXG4gIG5hbWUsXG4gIGxhYmVsU2l6ZSxcbiAgc3BhY2luZyA9ICdmaXQnLFxuICBpc1NvbG9GaWVsZCxcbiAgaW5mb3RpcCxcbn06IENvbm5lY3RlZEZvcm1Hcm91cFByb3BzPFQ+KSB7XG4gIGNvbnN0IHsgY29tcG9uZW50OiBDb21wb25lbnQsIGN1c3RvbVZhbGlkYXRpb25zLCAuLi5yZXN0IH0gPSBmaWVsZDtcbiAgY29uc3QgeyBlcnJvciwgaXNGaXJzdEVycm9yLCBpc0Rpc2FibGVkLCBzZXRFcnJvciwgdmFsaWRhdGlvbiB9ID0gdXNlRmllbGQoe1xuICAgIG5hbWUsXG4gICAgZGlzYWJsZWQsXG4gICAgY3VzdG9tVmFsaWRhdGlvbnMsXG4gIH0pO1xuICBjb25zdCB1bmlxdWVJZFN1ZmZpeCA9IHVzZUlkKCk7XG4gIGNvbnN0IGh0bWxGb3JJZCA9IGAke25hbWV9LSR7dW5pcXVlSWRTdWZmaXh9YDtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIGlmIChjdXN0b21FcnJvcikge1xuICAgICAgc2V0RXJyb3IobmFtZSwge1xuICAgICAgICB0eXBlOiAnbWFudWFsJyxcbiAgICAgICAgbWVzc2FnZTogY3VzdG9tRXJyb3IsXG4gICAgICB9KTtcbiAgICB9XG4gIH0sIFtjdXN0b21FcnJvciwgbmFtZSwgc2V0RXJyb3JdKTtcblxuICBjb25zdCBmaWVsZElkID0gdHlwZW9mIGlkID09PSAnc3RyaW5nJyA/
|
|
16
|
+
}), process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9Db25uZWN0ZWRGb3JtL0Nvbm5lY3RlZEZvcm1Hcm91cC50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBY29CIiwiZmlsZSI6Ii4uLy4uL3NyYy9Db25uZWN0ZWRGb3JtL0Nvbm5lY3RlZEZvcm1Hcm91cC50c3giLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBjc3MgfSBmcm9tICdAY29kZWNhZGVteS9nYW11dC1zdHlsZXMnO1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnO1xuaW1wb3J0IHsgdXNlRWZmZWN0LCB1c2VJZCB9IGZyb20gJ3JlYWN0JztcbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7IFJlZ2lzdGVyT3B0aW9ucyB9IGZyb20gJ3JlYWN0LWhvb2stZm9ybSc7XG5cbmltcG9ydCB7IEZvcm1FcnJvciwgRm9ybUdyb3VwLCBGb3JtR3JvdXBMYWJlbCwgRm9ybUdyb3VwUHJvcHMgfSBmcm9tICcuLic7XG5pbXBvcnQgeyBBbmNob3IgfSBmcm9tICcuLi9BbmNob3InO1xuaW1wb3J0IHsgTWFya2Rvd24gfSBmcm9tICcuLi9NYXJrZG93bic7XG5pbXBvcnQgeyBJbmZvVGlwU3ViQ29tcG9uZW50UHJvcHMgfSBmcm9tICcuLi9UaXAvSW5mb1RpcC90eXBlLXV0aWxzJztcbmltcG9ydCB7IFRleHQgfSBmcm9tICcuLi9UeXBvZ3JhcGh5JztcbmltcG9ydCB7IENvbm5lY3RlZEZpZWxkLCBGaWVsZFByb3BzLCBTdWJtaXRDb250ZXh0UHJvcHMgfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IGdldEVycm9yTWVzc2FnZSwgdXNlRmllbGQgfSBmcm9tICcuL3V0aWxzJztcblxuY29uc3QgRXJyb3JBbmNob3IgPSBzdHlsZWQoQW5jaG9yKShcbiAgY3NzKHtcbiAgICBjb2xvcjogJ2ZlZWRiYWNrLWVycm9yJyxcbiAgfSlcbik7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29ubmVjdGVkRm9ybUdyb3VwQmFzZVByb3BzXG4gIGV4dGVuZHMgT21pdDxcbiAgICBGb3JtR3JvdXBQcm9wcyxcbiAgICAnbGFiZWwnIHwgJ2Rpc2FibGVkJyB8ICdkZXNjcmlwdGlvbicgfCAnaHRtbEZvcidcbiAgPiB7XG4gIGN1c3RvbUVycm9yPzogc3RyaW5nO1xuICBlcnJvclR5cGU/OiAnaW5pdGlhbCcgfCAnYWJzb2x1dGUnO1xuICBoaWRlTGFiZWw/OiBib29sZWFuO1xuICBuYW1lOiBzdHJpbmc7XG4gIGxhYmVsOiBSZWFjdC5SZWFjdE5vZGU7XG4gIHJlcXVpcmVkPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIEluZm9UaXAgdG8gZGlzcGxheSBuZXh0IHRvIHRoZSBmaWVsZCBsYWJlbC4gVGhlIEluZm9UaXAgYnV0dG9uIGlzXG4gICAqIGF1dG9tYXRpY2FsbHkgbGFiZWxsZWQgYnkgdGhlIGZpZWxkIGxhYmVsLiBUbyBvdmVycmlkZSB0aGlzIGJlaGF2aW9yLFxuICAgKiBwcm92aWRlIGBhcmlhTGFiZWxgIG9yIGBhcmlhTGFiZWxsZWRieWAuXG4gICAqL1xuICBpbmZvdGlwPzogSW5mb1RpcFN1YkNvbXBvbmVudFByb3BzO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3RlZEZvcm1Hcm91cFByb3BzPFQgZXh0ZW5kcyBDb25uZWN0ZWRGaWVsZD5cbiAgZXh0ZW5kcyBTdWJtaXRDb250ZXh0UHJvcHMsXG4gICAgQ29ubmVjdGVkRm9ybUdyb3VwQmFzZVByb3BzIHtcbiAgLyoqXG4gICAqIEFuIG9iamVjdCBjb25zaXN0aW5nIG9mIGEgYGNvbXBvbmVudGAga2V5IHRvIHNwZWNpZnkgd2hhdCBDb25uZWN0ZWRGb3JtSW5wdXQgdG8gcmVuZGVyIC0gdGhlIHJlbWFpbmluZyBrZXkvdmFsdWUgcGFpcnMgYXJlIHRoYXQgY29tcG9uZW50cyBkZXNpcmVkIHByb3BzLlxuICAgKi9cbiAgZmllbGQ6IE9taXQ8UmVhY3QuQ29tcG9uZW50UHJvcHM8VD4sICduYW1lJyB8ICdkaXNhYmxlZCc+ICZcbiAgICBGaWVsZFByb3BzPFQ+ICYge1xuICAgICAgY3VzdG9tVmFsaWRhdGlvbnM/OiBSZWdpc3Rlck9wdGlvbnM7XG4gICAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIENvbm5lY3RlZEZvcm1Hcm91cDxUIGV4dGVuZHMgQ29ubmVjdGVkRmllbGQ+KHtcbiAgY3VzdG9tRXJyb3IsXG4gIGNoaWxkcmVuLFxuICBkaXNhYmxlZCA9IGZhbHNlLFxuICBlcnJvclR5cGUgPSAnYWJzb2x1dGUnLFxuICBmaWVsZCxcbiAgaGlkZUxhYmVsLFxuICBpZCxcbiAgbGFiZWwsXG4gIG5hbWUsXG4gIGxhYmVsU2l6ZSxcbiAgc3BhY2luZyA9ICdmaXQnLFxuICBpc1NvbG9GaWVsZCxcbiAgaW5mb3RpcCxcbn06IENvbm5lY3RlZEZvcm1Hcm91cFByb3BzPFQ+KSB7XG4gIGNvbnN0IHsgY29tcG9uZW50OiBDb21wb25lbnQsIGN1c3RvbVZhbGlkYXRpb25zLCAuLi5yZXN0IH0gPSBmaWVsZDtcbiAgY29uc3QgeyBlcnJvciwgaXNGaXJzdEVycm9yLCBpc0Rpc2FibGVkLCBzZXRFcnJvciwgdmFsaWRhdGlvbiB9ID0gdXNlRmllbGQoe1xuICAgIG5hbWUsXG4gICAgZGlzYWJsZWQsXG4gICAgY3VzdG9tVmFsaWRhdGlvbnMsXG4gIH0pO1xuICBjb25zdCB1bmlxdWVJZFN1ZmZpeCA9IHVzZUlkKCk7XG4gIGNvbnN0IGh0bWxGb3JJZCA9IGAke25hbWV9LSR7dW5pcXVlSWRTdWZmaXh9YDtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIGlmIChjdXN0b21FcnJvcikge1xuICAgICAgc2V0RXJyb3IobmFtZSwge1xuICAgICAgICB0eXBlOiAnbWFudWFsJyxcbiAgICAgICAgbWVzc2FnZTogY3VzdG9tRXJyb3IsXG4gICAgICB9KTtcbiAgICB9XG4gIH0sIFtjdXN0b21FcnJvciwgbmFtZSwgc2V0RXJyb3JdKTtcblxuICBjb25zdCBmaWVsZElkID0gdHlwZW9mIGlkID09PSAnc3RyaW5nJyA/IGlkIDogbmFtZTtcblxuICBjb25zdCByZW5kZXJlZExhYmVsID0gKFxuICAgIDxGb3JtR3JvdXBMYWJlbFxuICAgICAgZGlzYWJsZWQ9e2lzRGlzYWJsZWR9XG4gICAgICBodG1sRm9yPXtpZCB8fCBodG1sRm9ySWR9XG4gICAgICBpbmZvdGlwPXtpbmZvdGlwfVxuICAgICAgaXNTb2xvRmllbGQ9e2lzU29sb0ZpZWxkfVxuICAgICAgcmVxdWlyZWQ9e0Jvb2xlYW4odmFsaWRhdGlvbj8ucmVxdWlyZWQpfVxuICAgICAgc2l6ZT17bGFiZWxTaXplfVxuICAgID5cbiAgICAgIHtsYWJlbH1cbiAgICA8L0Zvcm1Hcm91cExhYmVsPlxuICApO1xuXG4gIGNvbnN0IHRleHRFcnJvciA9IGN1c3RvbUVycm9yIHx8IGdldEVycm9yTWVzc2FnZShlcnJvcik7XG4gIGNvbnN0IHNob3dFcnJvciA9ICEhKHRleHRFcnJvciAmJiAhaGlkZUxhYmVsKTtcbiAgY29uc3QgZXJyb3JJZCA9IHNob3dFcnJvciA/IGAke2ZpZWxkSWR9X2Vycm9yYCA6IHVuZGVmaW5lZDtcblxuICByZXR1cm4gKFxuICAgIDxGb3JtR3JvdXAgc3BhY2luZz17aGlkZUxhYmVsID8gJ3RpZ2h0JyA6IHNwYWNpbmd9PlxuICAgICAge2hpZGVMYWJlbCA/IDxUZXh0IHNjcmVlbnJlYWRlcj57cmVuZGVyZWRMYWJlbH08L1RleHQ+IDogcmVuZGVyZWRMYWJlbH1cbiAgICAgIDxDb21wb25lbnRcbiAgICAgICAgey4uLihyZXN0IGFzIGFueSl9XG4gICAgICAgIGFyaWEtZGVzY3JpYmVkYnk9e2Vycm9ySWR9XG4gICAgICAgIGFyaWEtaW52YWxpZD17c2hvd0Vycm9yfVxuICAgICAgICBjdXN0b21WYWxpZGF0aW9ucz17Y3VzdG9tVmFsaWRhdGlvbnN9XG4gICAgICAgIGRpc2FibGVkPXtkaXNhYmxlZH1cbiAgICAgICAgaHRtbEZvcj17aHRtbEZvcklkfVxuICAgICAgICBuYW1lPXtuYW1lfVxuICAgICAgLz5cbiAgICAgIHtjaGlsZHJlbn1cbiAgICAgIHtzaG93RXJyb3IgJiYgKFxuICAgICAgICA8Rm9ybUVycm9yXG4gICAgICAgICAgYXJpYS1saXZlPXtpc0ZpcnN0RXJyb3IgPyAnYXNzZXJ0aXZlJyA6ICdvZmYnfVxuICAgICAgICAgIGlkPXtlcnJvcklkfVxuICAgICAgICAgIHJvbGU9e2lzRmlyc3RFcnJvciA/ICdhbGVydCcgOiAnc3RhdHVzJ31cbiAgICAgICAgICB2YXJpYW50PXtlcnJvclR5cGV9XG4gICAgICAgID5cbiAgICAgICAgICA8TWFya2Rvd25cbiAgICAgICAgICAgIGlubGluZVxuICAgICAgICAgICAgb3ZlcnJpZGVzPXt7XG4gICAgICAgICAgICAgIGE6IHtcbiAgICAgICAgICAgICAgICBhbGxvd2VkQXR0cmlidXRlczogWydocmVmJywgJ3RhcmdldCddLFxuICAgICAgICAgICAgICAgIGNvbXBvbmVudDogRXJyb3JBbmNob3IsXG4gICAgICAgICAgICAgICAgcHJvY2Vzc05vZGU6IChcbiAgICAgICAgICAgICAgICAgIG5vZGU6IHVua25vd24sXG4gICAgICAgICAgICAgICAgICBwcm9wczogeyBvbkNsaWNrPzogKCkgPT4gdm9pZCB9XG4gICAgICAgICAgICAgICAgKSA9PiB7XG4gICAgICAgICAgICAgICAgICBjb25zdCB7IGtleTogZWxlbWVudEtleSwgLi4ucmVzdCB9ID1cbiAgICAgICAgICAgICAgICAgICAgcHJvcHMgYXMgUmVhY3QuQ29tcG9uZW50UHJvcHM8dHlwZW9mIEVycm9yQW5jaG9yPiAmIHtcbiAgICAgICAgICAgICAgICAgICAgICBrZXk/OiBSZWFjdC5LZXk7XG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICByZXR1cm4gPEVycm9yQW5jaG9yIGtleT17ZWxlbWVudEtleX0gey4uLnJlc3R9IC8+O1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9fVxuICAgICAgICAgICAgc2tpcERlZmF1bHRPdmVycmlkZXM9e3sgYTogdHJ1ZSB9fVxuICAgICAgICAgICAgc3BhY2luZz1cIm5vbmVcIlxuICAgICAgICAgICAgdGV4dD17dGV4dEVycm9yfVxuICAgICAgICAgIC8+XG4gICAgICAgIDwvRm9ybUVycm9yPlxuICAgICAgKX1cbiAgICA8L0Zvcm1Hcm91cD5cbiAgKTtcbn1cbiJdfQ== */");
|
|
17
17
|
export function ConnectedFormGroup({
|
|
18
18
|
customError,
|
|
19
19
|
children,
|
|
@@ -58,7 +58,7 @@ export function ConnectedFormGroup({
|
|
|
58
58
|
const fieldId = typeof id === 'string' ? id : name;
|
|
59
59
|
const renderedLabel = /*#__PURE__*/_jsx(FormGroupLabel, {
|
|
60
60
|
disabled: isDisabled,
|
|
61
|
-
htmlFor:
|
|
61
|
+
htmlFor: id || htmlForId,
|
|
62
62
|
infotip: infotip,
|
|
63
63
|
isSoloField: isSoloField,
|
|
64
64
|
required: Boolean(validation?.required),
|
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
import { useTheme } from '@emotion/react';
|
|
2
|
-
import { useId, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { getMemoizedStyles } from './
|
|
7
|
-
import {
|
|
8
|
-
import { formatGroupLabel, formatOptionLabel, SelectDropdownContext, TypedReactSelect } from './elements';
|
|
9
|
-
import { useSelectHandlers } from './hooks/useSelectHandlers';
|
|
10
|
-
import { useSelectOptions } from './hooks/useSelectOptions';
|
|
4
|
+
import { parseOptions } from '../utils';
|
|
5
|
+
import { AbbreviatedSingleValue, CustomContainer, CustomInput, CustomValueContainer, DropdownButton, formatGroupLabel, formatOptionLabel, IconOption, MultiValueRemoveButton, MultiValueWithColorMode, onFocus, RemoveAllButton, SelectDropdownContext, TypedReactSelect } from './elements';
|
|
6
|
+
import { getMemoizedStyles } from './styles';
|
|
7
|
+
import { filterValueFromOptions, isMultipleSelectProps, isOptionsGrouped, isSingleSelectProps, removeValueFromSelectedOptions } from './utils';
|
|
11
8
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
+
const defaultProps = {
|
|
10
|
+
name: undefined,
|
|
11
|
+
components: {
|
|
12
|
+
DropdownIndicator: DropdownButton,
|
|
13
|
+
IndicatorSeparator: () => null,
|
|
14
|
+
ClearIndicator: RemoveAllButton,
|
|
15
|
+
SelectContainer: CustomContainer,
|
|
16
|
+
ValueContainer: CustomValueContainer,
|
|
17
|
+
MultiValue: MultiValueWithColorMode,
|
|
18
|
+
MultiValueRemove: MultiValueRemoveButton,
|
|
19
|
+
Option: IconOption,
|
|
20
|
+
SingleValue: AbbreviatedSingleValue,
|
|
21
|
+
Input: CustomInput
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const onChangeAction = 'select-option';
|
|
25
|
+
|
|
12
26
|
/**
|
|
13
27
|
* A flexible dropdown select component built on top of react-select.
|
|
14
28
|
*
|
|
@@ -59,58 +73,101 @@ export const SelectDropdown = ({
|
|
|
59
73
|
disabled,
|
|
60
74
|
dropdownWidth,
|
|
61
75
|
error,
|
|
62
|
-
formatCreateLabel = inputValue => `Add "${inputValue}"`,
|
|
63
76
|
id,
|
|
64
77
|
inputProps,
|
|
65
78
|
inputWidth,
|
|
66
|
-
|
|
67
|
-
isSearchable: isSearchableProp = false,
|
|
68
|
-
isValidNewOption,
|
|
79
|
+
isSearchable = false,
|
|
69
80
|
menuAlignment = 'left',
|
|
70
81
|
multiple,
|
|
71
82
|
name,
|
|
72
83
|
onChange,
|
|
73
|
-
onCreateOption,
|
|
74
|
-
onInputChange,
|
|
75
84
|
options,
|
|
76
85
|
placeholder = 'Select an option',
|
|
77
86
|
shownOptionsLimit = 6,
|
|
78
87
|
size,
|
|
79
|
-
validationMessage,
|
|
80
88
|
value,
|
|
81
89
|
zIndex,
|
|
82
90
|
...rest
|
|
83
91
|
}) => {
|
|
84
|
-
// isSearchable is forced true when isCreatable is true (CreatableSelect requires a text input)
|
|
85
|
-
const isSearchable = isCreatable || isSearchableProp;
|
|
86
92
|
const rawInputId = useId();
|
|
87
93
|
const inputId = name ?? `${id}-select-dropdown-${rawInputId}`;
|
|
94
|
+
const [activated, setActivated] = useState(false);
|
|
95
|
+
const [currentFocusedValue, setCurrentFocusedValue] = useState(undefined);
|
|
96
|
+
|
|
97
|
+
// these are used to programatically manage the focus state of our multi-select options + 'Remove all' button
|
|
88
98
|
const removeAllButtonRef = useRef(null);
|
|
89
99
|
const selectInputRef = useRef(null);
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
100
|
+
const selectOptions = useMemo(() => {
|
|
101
|
+
if (!options || Array.isArray(options) && !options.length || typeof options === 'object' && !Array.isArray(options) && Object.keys(options).length === 0) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
if (isOptionsGrouped(options)) {
|
|
105
|
+
return options;
|
|
106
|
+
}
|
|
107
|
+
return parseOptions({
|
|
108
|
+
options,
|
|
109
|
+
id,
|
|
110
|
+
size
|
|
111
|
+
});
|
|
112
|
+
}, [options, id, size]);
|
|
113
|
+
const parsedValue = useMemo(() => {
|
|
114
|
+
if (isOptionsGrouped(selectOptions)) {
|
|
115
|
+
for (const group of selectOptions) {
|
|
116
|
+
if (group.options) {
|
|
117
|
+
const foundOption = group.options.find(option => option.value === value);
|
|
118
|
+
if (foundOption) return foundOption;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
return selectOptions.find(option => option.value === value);
|
|
124
|
+
}, [selectOptions, value]);
|
|
125
|
+
const [multiValues, setMultiValues] = useState(multiple &&
|
|
126
|
+
// To keep this efficient for non-multiSelect
|
|
127
|
+
filterValueFromOptions(selectOptions, value, isOptionsGrouped(selectOptions)));
|
|
128
|
+
|
|
129
|
+
// If the caller changes the initial value, let's update our value to match.
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
const newMultiValues = filterValueFromOptions(selectOptions, value, isOptionsGrouped(selectOptions));
|
|
132
|
+
if (newMultiValues !== multiValues) setMultiValues(newMultiValues);
|
|
133
|
+
|
|
134
|
+
//
|
|
135
|
+
// We only update this when our passed in options or value changes, not multiValues.
|
|
136
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
137
|
+
}, [options, value]);
|
|
138
|
+
const changeHandler = useCallback(optionEvent => {
|
|
139
|
+
setActivated(true);
|
|
140
|
+
|
|
141
|
+
// 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!
|
|
142
|
+
// Should probably come with: https://codecademy.atlassian.net/browse/GM-354
|
|
143
|
+
const onChangeProps = {
|
|
144
|
+
onChange,
|
|
145
|
+
multiple
|
|
146
|
+
};
|
|
147
|
+
if (isSingleSelectProps(onChangeProps)) {
|
|
148
|
+
const singleOptionEvent = optionEvent;
|
|
149
|
+
onChangeProps.onChange?.(singleOptionEvent, {
|
|
150
|
+
action: onChangeAction,
|
|
151
|
+
option: singleOptionEvent
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (isMultipleSelectProps(onChangeProps)) {
|
|
155
|
+
setMultiValues(optionEvent);
|
|
156
|
+
onChangeProps.onChange?.(optionEvent, {
|
|
157
|
+
action: onChangeAction,
|
|
158
|
+
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)
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}, [onChange, multiple]);
|
|
162
|
+
const keyPressHandler = e => {
|
|
163
|
+
if (multiple && e.key === 'Enter' && currentFocusedValue && multiValues) {
|
|
164
|
+
const newMultiValues = removeValueFromSelectedOptions(multiValues, currentFocusedValue);
|
|
165
|
+
if (newMultiValues !== multiValues) setMultiValues(newMultiValues);
|
|
166
|
+
}
|
|
167
|
+
if (removeAllButtonRef.current !== null && e.key === 'ArrowRight' && multiValues && currentFocusedValue === multiValues[multiValues.length - 1].value) {
|
|
168
|
+
removeAllButtonRef.current.focus();
|
|
169
|
+
}
|
|
170
|
+
};
|
|
114
171
|
const theme = useTheme();
|
|
115
172
|
const memoizedStyles = useMemo(() => {
|
|
116
173
|
return getMemoizedStyles(theme, zIndex);
|
|
@@ -123,15 +180,14 @@ export const SelectDropdown = ({
|
|
|
123
180
|
selectInputRef
|
|
124
181
|
},
|
|
125
182
|
children: /*#__PURE__*/_jsx(TypedReactSelect, {
|
|
183
|
+
...defaultProps,
|
|
126
184
|
activated: activated,
|
|
127
185
|
"aria-live": "assertive",
|
|
128
186
|
ariaLiveMessages: {
|
|
129
187
|
onFocus
|
|
130
188
|
},
|
|
131
|
-
components: defaultComponents,
|
|
132
189
|
dropdownWidth: dropdownWidth,
|
|
133
190
|
error: Boolean(error),
|
|
134
|
-
formatCreateLabel: formatCreateLabel,
|
|
135
191
|
formatGroupLabel: formatGroupLabel,
|
|
136
192
|
formatOptionLabel: formatOptionLabel,
|
|
137
193
|
id: id || rest.htmlFor || rawInputId,
|
|
@@ -140,15 +196,12 @@ export const SelectDropdown = ({
|
|
|
140
196
|
...inputProps
|
|
141
197
|
},
|
|
142
198
|
inputWidth: inputWidth,
|
|
143
|
-
isCreatable: isCreatable,
|
|
144
199
|
isDisabled: disabled,
|
|
145
200
|
isMulti: multiple,
|
|
146
|
-
isOptionDisabled: option => option.disabled,
|
|
201
|
+
isOptionDisabled: option => option.disabled ?? false,
|
|
147
202
|
isSearchable: isSearchable,
|
|
148
|
-
isValidNewOption: isValidNewOption,
|
|
149
203
|
menuAlignment: menuAlignment,
|
|
150
204
|
name: name,
|
|
151
|
-
noOptionsMessage: resolveNoOptionsMessage(validationMessage),
|
|
152
205
|
options: selectOptions,
|
|
153
206
|
placeholder: placeholder,
|
|
154
207
|
selectRef: selectInputRef,
|
|
@@ -157,8 +210,7 @@ export const SelectDropdown = ({
|
|
|
157
210
|
styles: memoizedStyles,
|
|
158
211
|
value: multiple ? multiValues : parsedValue,
|
|
159
212
|
onChange: changeHandler,
|
|
160
|
-
|
|
161
|
-
onKeyDown: multiple ? keyPressHandler : undefined,
|
|
213
|
+
onKeyDown: multiple ? e => keyPressHandler(e) : undefined,
|
|
162
214
|
...rest
|
|
163
215
|
})
|
|
164
216
|
});
|
|
@@ -15,6 +15,14 @@ export declare const indicatorIcons: {
|
|
|
15
15
|
size: number;
|
|
16
16
|
icon: import("react").ForwardRefExoticComponent<import("@codecademy/gamut-icons").GamutIconProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
17
17
|
};
|
|
18
|
+
smallSearchable: {
|
|
19
|
+
size: number;
|
|
20
|
+
icon: import("react").ForwardRefExoticComponent<import("@codecademy/gamut-icons").GamutIconProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
21
|
+
};
|
|
22
|
+
mediumSearchable: {
|
|
23
|
+
size: number;
|
|
24
|
+
icon: import("react").ForwardRefExoticComponent<import("@codecademy/gamut-icons").GamutIconProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
25
|
+
};
|
|
18
26
|
smallRemove: {
|
|
19
27
|
size: number;
|
|
20
28
|
icon: import("react").ForwardRefExoticComponent<import("@codecademy/gamut-icons").GamutIconProps & import("react").RefAttributes<SVGSVGElement>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArrowChevronDownIcon, CloseIcon, MiniChevronDownIcon, MiniDeleteIcon } from '@codecademy/gamut-icons';
|
|
1
|
+
import { ArrowChevronDownIcon, CloseIcon, MiniChevronDownIcon, MiniDeleteIcon, SearchIcon } from '@codecademy/gamut-icons';
|
|
2
2
|
export const iconSize = {
|
|
3
3
|
small: 12,
|
|
4
4
|
medium: 16
|
|
@@ -16,6 +16,14 @@ export const indicatorIcons = {
|
|
|
16
16
|
size: iconSize.medium,
|
|
17
17
|
icon: ArrowChevronDownIcon
|
|
18
18
|
},
|
|
19
|
+
smallSearchable: {
|
|
20
|
+
size: iconSize.small,
|
|
21
|
+
icon: SearchIcon
|
|
22
|
+
},
|
|
23
|
+
mediumSearchable: {
|
|
24
|
+
size: iconSize.medium,
|
|
25
|
+
icon: SearchIcon
|
|
26
|
+
},
|
|
19
27
|
smallRemove: {
|
|
20
28
|
size: iconSize.small,
|
|
21
29
|
icon: MiniDeleteIcon
|
|
@@ -24,10 +24,6 @@ export declare const CustomValueContainer: ({ ...rest }: CustomSelectComponentPr
|
|
|
24
24
|
export declare const CustomInput: ({ ...rest }: CustomSelectComponentProps<typeof SelectDropdownElements.Input>) => import("react/jsx-runtime").JSX.Element;
|
|
25
25
|
/**
|
|
26
26
|
* Typed wrapper around react-select component.
|
|
27
|
-
*
|
|
28
|
-
* Creatable-only props (formatCreateLabel, isValidNewOption) are stripped from
|
|
29
|
-
* the non-creatable path so they don't reach ReactSelect. `onCreateOption` is
|
|
30
|
-
* handled in SelectDropdown's changeHandler — do not pass it to CreatableSelect
|
|
31
|
-
* or react-select will skip onChange on create.
|
|
27
|
+
* Provides type safety for the underlying react-select implementation.
|
|
32
28
|
*/
|
|
33
|
-
export declare function TypedReactSelect<OptionType, IsMulti extends boolean = false, GroupType extends GroupBase<OptionType> = GroupBase<OptionType>>({ selectRef,
|
|
29
|
+
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;
|
|
@@ -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
|
-
*
|
|
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 {
|
|
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}
|
|
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/LmN1cnJlbnQgJiZcbiAgICAgIChlLmtleSA9PT0gJ0Fycm93UmlnaHQnIHx8IGUua2V5ID09PSAnQXJyb3dMZWZ0JyB8fCBlLmtleSA9PT0gJ0Fycm93RG93bicpXG4gICAgKSB7XG4gICAgICBzZWxlY3RJbnB1dFJlZi5jdXJyZW50LmZvY3VzKCk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IHN0eWxlID0gZ2V0U3R5bGVzKCdjbGVhckluZGljYXRvcicsIHByb3BzKSBhcyBSZWFjdC5DU1NQcm9wZXJ0aWVzO1xuXG4gIHJldHVybiAoXG4gICAgPEN1c3RvbVN0eWxlZFJlbW92ZUFsbERpdlxuICAgICAgYXJpYS1sYWJlbD1cIlJlbW92ZSBhbGwgc2VsZWN0ZWRcIlxuICAgICAgcm9sZT1cImJ1dHRvblwiXG4gICAgICB0YWJJbmRleD17MH1cbiAgICAgIHsuLi5yZXN0SW5uZXJQcm9wc31cbiAgICAgIHJlZj17cmVtb3ZlQWxsQnV0dG9uUmVmIGFzIFJlYWN0LlJlZjxIVE1MRGl2RWxlbWVudD59XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZ2FtdXQvbm8taW5saW5lLXN0eWxlXG4gICAgICBzdHlsZT17c3R5bGV9XG4gICAgICBvbktleURvd249e29uS2V5UHJlc3N9XG4gICAgPlxuICAgICAgPEluZGljYXRvckljb24gey4uLmljb25Qcm9wc30gY29sb3I9XCJ0ZXh0XCIgLz5cbiAgICA8L0N1c3RvbVN0eWxlZFJlbW92ZUFsbERpdj5cbiAgKTtcbn07XG4iXX0= */");
|
|
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,
|
|
65
|
+
children: [children, rest?.isSelected && /*#__PURE__*/_jsx(CheckIcon, {
|
|
69
66
|
size: selectedIconSize[size ?? 'medium']
|
|
70
67
|
})]
|
|
71
68
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { css, states, variant } from '@codecademy/gamut-styles';
|
|
2
|
-
import { dismissSharedStyles, tagBaseStyles, tagLabelFontSize, tagLabelPadding } from '
|
|
3
|
-
import { formBaseComponentStyles, formBaseFieldStylesObject, formFieldDisabledStyles, formFieldPaddingStyles, InputSelectors } from '
|
|
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
6
|
display: 'flex',
|
|
@@ -62,7 +62,7 @@ const textColor = css({
|
|
|
62
62
|
color: 'text'
|
|
63
63
|
});
|
|
64
64
|
const placeholderColor = css({
|
|
65
|
-
color: 'text-
|
|
65
|
+
color: 'text-disabled'
|
|
66
66
|
});
|
|
67
67
|
export const getMemoizedStyles = (theme, zIndex) => {
|
|
68
68
|
return {
|
|
@@ -137,8 +137,6 @@ export const getMemoizedStyles = (theme, zIndex) => {
|
|
|
137
137
|
error: state.selectProps.error,
|
|
138
138
|
theme
|
|
139
139
|
}),
|
|
140
|
-
// Drop react-select's default menu drop shadow; the border above defines the edge.
|
|
141
|
-
boxShadow: 'none',
|
|
142
140
|
...(dropdownWidth ? {
|
|
143
141
|
minWidth: dropdownWidth,
|
|
144
142
|
width: dropdownWidth
|
|
@@ -196,32 +194,16 @@ export const getMemoizedStyles = (theme, zIndex) => {
|
|
|
196
194
|
backgroundColor: theme.colors['secondary-hover']
|
|
197
195
|
}
|
|
198
196
|
}),
|
|
199
|
-
|
|
200
|
-
...
|
|
201
|
-
|
|
197
|
+
option: (provided, state) => ({
|
|
198
|
+
...getOptionBackground(state.isSelected, state.isFocused)({
|
|
199
|
+
theme
|
|
200
|
+
}),
|
|
201
|
+
alignItems: 'center',
|
|
202
|
+
color: state.isDisabled ? 'text-disabled' : 'default',
|
|
203
|
+
cursor: state.isDisabled ? 'not-allowed' : 'pointer',
|
|
204
|
+
display: 'flex',
|
|
205
|
+
padding: state.selectProps.size === 'small' ? '3px 14px' : '11px 14px'
|
|
202
206
|
}),
|
|
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
207
|
placeholder: provided => ({
|
|
226
208
|
...provided,
|
|
227
209
|
...placeholderColor({
|