@atlaskit/react-select 0.0.2
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/CHANGELOG.md +9 -0
- package/LICENSE.md +11 -0
- package/README.md +10 -0
- package/async/package.json +15 -0
- package/base/package.json +15 -0
- package/creatable/package.json +15 -0
- package/dist/cjs/accessibility/helpers.js +34 -0
- package/dist/cjs/accessibility/index.js +74 -0
- package/dist/cjs/async-creatable.js +27 -0
- package/dist/cjs/async.js +30 -0
- package/dist/cjs/builtins.js +18 -0
- package/dist/cjs/components/containers.js +100 -0
- package/dist/cjs/components/control.js +67 -0
- package/dist/cjs/components/group.js +79 -0
- package/dist/cjs/components/index.js +53 -0
- package/dist/cjs/components/indicators.js +214 -0
- package/dist/cjs/components/input.js +93 -0
- package/dist/cjs/components/internal/a11y-text.js +34 -0
- package/dist/cjs/components/internal/dummy-input.js +43 -0
- package/dist/cjs/components/internal/index.js +34 -0
- package/dist/cjs/components/internal/required-input.js +43 -0
- package/dist/cjs/components/internal/scroll-manager.js +57 -0
- package/dist/cjs/components/internal/use-scroll-capture.js +132 -0
- package/dist/cjs/components/internal/use-scroll-lock.js +149 -0
- package/dist/cjs/components/live-region.js +153 -0
- package/dist/cjs/components/menu.js +464 -0
- package/dist/cjs/components/multi-value.js +129 -0
- package/dist/cjs/components/option.js +62 -0
- package/dist/cjs/components/placeholder.js +39 -0
- package/dist/cjs/components/single-value.js +46 -0
- package/dist/cjs/creatable.js +30 -0
- package/dist/cjs/diacritics.js +274 -0
- package/dist/cjs/filters.js +50 -0
- package/dist/cjs/index.js +55 -0
- package/dist/cjs/nonce-provider.js +30 -0
- package/dist/cjs/select.js +1803 -0
- package/dist/cjs/state-manager.js +31 -0
- package/dist/cjs/styles.js +66 -0
- package/dist/cjs/theme.js +42 -0
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/use-async.js +156 -0
- package/dist/cjs/use-creatable.js +114 -0
- package/dist/cjs/use-state-manager.js +83 -0
- package/dist/cjs/utils.js +357 -0
- package/dist/es2019/accessibility/helpers.js +24 -0
- package/dist/es2019/accessibility/index.js +72 -0
- package/dist/es2019/async-creatable.js +17 -0
- package/dist/es2019/async.js +16 -0
- package/dist/es2019/builtins.js +4 -0
- package/dist/es2019/components/containers.js +100 -0
- package/dist/es2019/components/control.js +62 -0
- package/dist/es2019/components/group.js +74 -0
- package/dist/es2019/components/index.js +41 -0
- package/dist/es2019/components/indicators.js +211 -0
- package/dist/es2019/components/input.js +88 -0
- package/dist/es2019/components/internal/a11y-text.js +25 -0
- package/dist/es2019/components/internal/dummy-input.js +36 -0
- package/dist/es2019/components/internal/index.js +4 -0
- package/dist/es2019/components/internal/required-input.js +35 -0
- package/dist/es2019/components/internal/scroll-manager.js +49 -0
- package/dist/es2019/components/internal/use-scroll-capture.js +128 -0
- package/dist/es2019/components/internal/use-scroll-lock.js +143 -0
- package/dist/es2019/components/live-region.js +151 -0
- package/dist/es2019/components/menu.js +466 -0
- package/dist/es2019/components/multi-value.js +134 -0
- package/dist/es2019/components/option.js +57 -0
- package/dist/es2019/components/placeholder.js +34 -0
- package/dist/es2019/components/single-value.js +41 -0
- package/dist/es2019/creatable.js +15 -0
- package/dist/es2019/diacritics.js +264 -0
- package/dist/es2019/filters.js +36 -0
- package/dist/es2019/index.js +8 -0
- package/dist/es2019/nonce-provider.js +19 -0
- package/dist/es2019/select.js +1766 -0
- package/dist/es2019/state-manager.js +22 -0
- package/dist/es2019/styles.js +56 -0
- package/dist/es2019/theme.js +36 -0
- package/dist/es2019/types.js +1 -0
- package/dist/es2019/use-async.js +117 -0
- package/dist/es2019/use-creatable.js +81 -0
- package/dist/es2019/use-state-manager.js +60 -0
- package/dist/es2019/utils.js +309 -0
- package/dist/esm/accessibility/helpers.js +24 -0
- package/dist/esm/accessibility/index.js +68 -0
- package/dist/esm/async-creatable.js +17 -0
- package/dist/esm/async.js +16 -0
- package/dist/esm/builtins.js +12 -0
- package/dist/esm/components/containers.js +96 -0
- package/dist/esm/components/control.js +62 -0
- package/dist/esm/components/group.js +74 -0
- package/dist/esm/components/index.js +43 -0
- package/dist/esm/components/indicators.js +209 -0
- package/dist/esm/components/input.js +88 -0
- package/dist/esm/components/internal/a11y-text.js +27 -0
- package/dist/esm/components/internal/dummy-input.js +37 -0
- package/dist/esm/components/internal/index.js +4 -0
- package/dist/esm/components/internal/required-input.js +36 -0
- package/dist/esm/components/internal/scroll-manager.js +49 -0
- package/dist/esm/components/internal/use-scroll-capture.js +126 -0
- package/dist/esm/components/internal/use-scroll-lock.js +143 -0
- package/dist/esm/components/live-region.js +148 -0
- package/dist/esm/components/menu.js +460 -0
- package/dist/esm/components/multi-value.js +122 -0
- package/dist/esm/components/option.js +57 -0
- package/dist/esm/components/placeholder.js +34 -0
- package/dist/esm/components/single-value.js +41 -0
- package/dist/esm/creatable.js +15 -0
- package/dist/esm/diacritics.js +268 -0
- package/dist/esm/filters.js +43 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/nonce-provider.js +20 -0
- package/dist/esm/select.js +1794 -0
- package/dist/esm/state-manager.js +22 -0
- package/dist/esm/styles.js +58 -0
- package/dist/esm/theme.js +36 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/use-async.js +149 -0
- package/dist/esm/use-creatable.js +107 -0
- package/dist/esm/use-state-manager.js +76 -0
- package/dist/esm/utils.js +328 -0
- package/dist/types/accessibility/helpers.d.ts +5 -0
- package/dist/types/accessibility/index.d.ts +125 -0
- package/dist/types/async-creatable.d.ts +10 -0
- package/dist/types/async.d.ts +9 -0
- package/dist/types/builtins.d.ts +5 -0
- package/dist/types/components/containers.d.ts +50 -0
- package/dist/types/components/control.d.ts +33 -0
- package/dist/types/components/group.d.ts +53 -0
- package/dist/types/components/index.d.ts +73 -0
- package/dist/types/components/indicators.d.ts +72 -0
- package/dist/types/components/input.d.ts +33 -0
- package/dist/types/components/internal/a11y-text.d.ts +8 -0
- package/dist/types/components/internal/dummy-input.d.ts +9 -0
- package/dist/types/components/internal/index.d.ts +4 -0
- package/dist/types/components/internal/required-input.d.ts +10 -0
- package/dist/types/components/internal/scroll-manager.d.ts +17 -0
- package/dist/types/components/internal/use-scroll-capture.d.ts +12 -0
- package/dist/types/components/internal/use-scroll-lock.d.ts +9 -0
- package/dist/types/components/live-region.d.ts +24 -0
- package/dist/types/components/menu.d.ts +130 -0
- package/dist/types/components/multi-value.d.ts +47 -0
- package/dist/types/components/option.d.ts +49 -0
- package/dist/types/components/placeholder.d.ts +22 -0
- package/dist/types/components/single-value.d.ts +28 -0
- package/dist/types/creatable.d.ts +10 -0
- package/dist/types/diacritics.d.ts +1 -0
- package/dist/types/filters.d.ts +15 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/nonce-provider.d.ts +8 -0
- package/dist/types/select.d.ts +616 -0
- package/dist/types/state-manager.d.ts +17 -0
- package/dist/types/styles.d.ts +68 -0
- package/dist/types/theme.d.ts +27 -0
- package/dist/types/types.d.ts +134 -0
- package/dist/types/use-async.d.ts +31 -0
- package/dist/types/use-creatable.d.ts +46 -0
- package/dist/types/use-state-manager.d.ts +15 -0
- package/dist/types/utils.d.ts +44 -0
- package/dist/types-ts4.5/accessibility/helpers.d.ts +5 -0
- package/dist/types-ts4.5/accessibility/index.d.ts +125 -0
- package/dist/types-ts4.5/async-creatable.d.ts +10 -0
- package/dist/types-ts4.5/async.d.ts +9 -0
- package/dist/types-ts4.5/builtins.d.ts +5 -0
- package/dist/types-ts4.5/components/containers.d.ts +50 -0
- package/dist/types-ts4.5/components/control.d.ts +33 -0
- package/dist/types-ts4.5/components/group.d.ts +53 -0
- package/dist/types-ts4.5/components/index.d.ts +73 -0
- package/dist/types-ts4.5/components/indicators.d.ts +72 -0
- package/dist/types-ts4.5/components/input.d.ts +33 -0
- package/dist/types-ts4.5/components/internal/a11y-text.d.ts +8 -0
- package/dist/types-ts4.5/components/internal/dummy-input.d.ts +9 -0
- package/dist/types-ts4.5/components/internal/index.d.ts +4 -0
- package/dist/types-ts4.5/components/internal/required-input.d.ts +10 -0
- package/dist/types-ts4.5/components/internal/scroll-manager.d.ts +17 -0
- package/dist/types-ts4.5/components/internal/use-scroll-capture.d.ts +12 -0
- package/dist/types-ts4.5/components/internal/use-scroll-lock.d.ts +9 -0
- package/dist/types-ts4.5/components/live-region.d.ts +24 -0
- package/dist/types-ts4.5/components/menu.d.ts +130 -0
- package/dist/types-ts4.5/components/multi-value.d.ts +47 -0
- package/dist/types-ts4.5/components/option.d.ts +49 -0
- package/dist/types-ts4.5/components/placeholder.d.ts +22 -0
- package/dist/types-ts4.5/components/single-value.d.ts +28 -0
- package/dist/types-ts4.5/creatable.d.ts +10 -0
- package/dist/types-ts4.5/diacritics.d.ts +1 -0
- package/dist/types-ts4.5/filters.d.ts +15 -0
- package/dist/types-ts4.5/index.d.ts +28 -0
- package/dist/types-ts4.5/nonce-provider.d.ts +8 -0
- package/dist/types-ts4.5/select.d.ts +616 -0
- package/dist/types-ts4.5/state-manager.d.ts +17 -0
- package/dist/types-ts4.5/styles.d.ts +68 -0
- package/dist/types-ts4.5/theme.d.ts +27 -0
- package/dist/types-ts4.5/types.d.ts +134 -0
- package/dist/types-ts4.5/use-async.d.ts +31 -0
- package/dist/types-ts4.5/use-creatable.d.ts +46 -0
- package/dist/types-ts4.5/use-state-manager.d.ts +15 -0
- package/dist/types-ts4.5/utils.d.ts +44 -0
- package/package.json +83 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
|
+
import Select from './select';
|
|
4
|
+
import useStateManager from './use-state-manager';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* __StateManagedSelect__
|
|
8
|
+
*
|
|
9
|
+
* A state managed select {description}.
|
|
10
|
+
*
|
|
11
|
+
* - [Examples](https://atlassian.design/components/{packageName}/examples)
|
|
12
|
+
* - [Code](https://atlassian.design/components/{packageName}/code)
|
|
13
|
+
* - [Usage](https://atlassian.design/components/{packageName}/usage)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const StateManagedSelect = /*#__PURE__*/forwardRef((props, ref) => {
|
|
17
|
+
const baseSelectProps = useStateManager(props);
|
|
18
|
+
return /*#__PURE__*/React.createElement(Select, _extends({
|
|
19
|
+
ref: ref
|
|
20
|
+
}, baseSelectProps));
|
|
21
|
+
});
|
|
22
|
+
export default StateManagedSelect;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { containerCSS, indicatorsContainerCSS, valueContainerCSS } from './components/containers';
|
|
2
|
+
import { css as controlCSS } from './components/control';
|
|
3
|
+
import { groupCSS, groupHeadingCSS } from './components/group';
|
|
4
|
+
import { clearIndicatorCSS, dropdownIndicatorCSS, indicatorSeparatorCSS, loadingIndicatorCSS } from './components/indicators';
|
|
5
|
+
import { inputCSS } from './components/input';
|
|
6
|
+
import { loadingMessageCSS, menuCSS, menuListCSS, menuPortalCSS, noOptionsMessageCSS } from './components/menu';
|
|
7
|
+
import { multiValueCSS, multiValueLabelCSS, multiValueRemoveCSS } from './components/multi-value';
|
|
8
|
+
import { optionCSS } from './components/option';
|
|
9
|
+
import { placeholderCSS } from './components/placeholder';
|
|
10
|
+
import { css as singleValueCSS } from './components/single-value';
|
|
11
|
+
export const defaultStyles = {
|
|
12
|
+
clearIndicator: clearIndicatorCSS,
|
|
13
|
+
container: containerCSS,
|
|
14
|
+
control: controlCSS,
|
|
15
|
+
dropdownIndicator: dropdownIndicatorCSS,
|
|
16
|
+
group: groupCSS,
|
|
17
|
+
groupHeading: groupHeadingCSS,
|
|
18
|
+
indicatorsContainer: indicatorsContainerCSS,
|
|
19
|
+
indicatorSeparator: indicatorSeparatorCSS,
|
|
20
|
+
input: inputCSS,
|
|
21
|
+
loadingIndicator: loadingIndicatorCSS,
|
|
22
|
+
loadingMessage: loadingMessageCSS,
|
|
23
|
+
menu: menuCSS,
|
|
24
|
+
menuList: menuListCSS,
|
|
25
|
+
menuPortal: menuPortalCSS,
|
|
26
|
+
multiValue: multiValueCSS,
|
|
27
|
+
multiValueLabel: multiValueLabelCSS,
|
|
28
|
+
multiValueRemove: multiValueRemoveCSS,
|
|
29
|
+
noOptionsMessage: noOptionsMessageCSS,
|
|
30
|
+
option: optionCSS,
|
|
31
|
+
placeholder: placeholderCSS,
|
|
32
|
+
singleValue: singleValueCSS,
|
|
33
|
+
valueContainer: valueContainerCSS
|
|
34
|
+
};
|
|
35
|
+
// Merge Utility
|
|
36
|
+
// Allows consumers to extend a base Select with additional styles
|
|
37
|
+
|
|
38
|
+
export function mergeStyles(source, target = {}) {
|
|
39
|
+
// initialize with source styles
|
|
40
|
+
const styles = {
|
|
41
|
+
...source
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// massage in target styles
|
|
45
|
+
Object.keys(target).forEach(keyAsString => {
|
|
46
|
+
const key = keyAsString;
|
|
47
|
+
if (source[key]) {
|
|
48
|
+
styles[key] = (rsCss, props) => {
|
|
49
|
+
return target[key](source[key](rsCss, props), props);
|
|
50
|
+
};
|
|
51
|
+
} else {
|
|
52
|
+
styles[key] = target[key];
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return styles;
|
|
56
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const colors = {
|
|
2
|
+
primary: '#2684FF',
|
|
3
|
+
primary75: '#4C9AFF',
|
|
4
|
+
primary50: '#B2D4FF',
|
|
5
|
+
primary25: '#DEEBFF',
|
|
6
|
+
danger: '#DE350B',
|
|
7
|
+
dangerLight: '#FFBDAD',
|
|
8
|
+
neutral0: 'hsl(0, 0%, 100%)',
|
|
9
|
+
neutral5: 'hsl(0, 0%, 95%)',
|
|
10
|
+
neutral10: 'hsl(0, 0%, 90%)',
|
|
11
|
+
neutral20: 'hsl(0, 0%, 80%)',
|
|
12
|
+
neutral30: 'hsl(0, 0%, 70%)',
|
|
13
|
+
neutral40: 'hsl(0, 0%, 60%)',
|
|
14
|
+
neutral50: 'hsl(0, 0%, 50%)',
|
|
15
|
+
neutral60: 'hsl(0, 0%, 40%)',
|
|
16
|
+
neutral70: 'hsl(0, 0%, 30%)',
|
|
17
|
+
neutral80: 'hsl(0, 0%, 20%)',
|
|
18
|
+
neutral90: 'hsl(0, 0%, 10%)'
|
|
19
|
+
};
|
|
20
|
+
const borderRadius = 4;
|
|
21
|
+
// Used to calculate consistent margin/padding on elements
|
|
22
|
+
const baseUnit = 4;
|
|
23
|
+
// The minimum height of the control
|
|
24
|
+
const controlHeight = 38;
|
|
25
|
+
// The amount of space between the control and menu */
|
|
26
|
+
const menuGutter = baseUnit * 2;
|
|
27
|
+
export const spacing = {
|
|
28
|
+
baseUnit,
|
|
29
|
+
controlHeight,
|
|
30
|
+
menuGutter
|
|
31
|
+
};
|
|
32
|
+
export const defaultTheme = {
|
|
33
|
+
borderRadius,
|
|
34
|
+
colors,
|
|
35
|
+
spacing
|
|
36
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { handleInputChange } from './utils';
|
|
3
|
+
// TODO: Fill in the hook {description}.
|
|
4
|
+
/**
|
|
5
|
+
* {description}.
|
|
6
|
+
*/
|
|
7
|
+
export default function useAsync({
|
|
8
|
+
defaultOptions: propsDefaultOptions = false,
|
|
9
|
+
cacheOptions = false,
|
|
10
|
+
loadOptions: propsLoadOptions,
|
|
11
|
+
options: propsOptions,
|
|
12
|
+
isLoading: propsIsLoading = false,
|
|
13
|
+
onInputChange: propsOnInputChange,
|
|
14
|
+
filterOption = null,
|
|
15
|
+
...restSelectProps
|
|
16
|
+
}) {
|
|
17
|
+
const {
|
|
18
|
+
inputValue: propsInputValue
|
|
19
|
+
} = restSelectProps;
|
|
20
|
+
const lastRequest = useRef(undefined);
|
|
21
|
+
const mounted = useRef(false);
|
|
22
|
+
const [defaultOptions, setDefaultOptions] = useState(Array.isArray(propsDefaultOptions) ? propsDefaultOptions : undefined);
|
|
23
|
+
const [stateInputValue, setStateInputValue] = useState(typeof propsInputValue !== 'undefined' ? propsInputValue : '');
|
|
24
|
+
const [isLoading, setIsLoading] = useState(propsDefaultOptions === true);
|
|
25
|
+
const [loadedInputValue, setLoadedInputValue] = useState(undefined);
|
|
26
|
+
const [loadedOptions, setLoadedOptions] = useState([]);
|
|
27
|
+
const [passEmptyOptions, setPassEmptyOptions] = useState(false);
|
|
28
|
+
const [optionsCache, setOptionsCache] = useState({});
|
|
29
|
+
const [prevDefaultOptions, setPrevDefaultOptions] = useState(undefined);
|
|
30
|
+
const [prevCacheOptions, setPrevCacheOptions] = useState(undefined);
|
|
31
|
+
if (cacheOptions !== prevCacheOptions) {
|
|
32
|
+
setOptionsCache({});
|
|
33
|
+
setPrevCacheOptions(cacheOptions);
|
|
34
|
+
}
|
|
35
|
+
if (propsDefaultOptions !== prevDefaultOptions) {
|
|
36
|
+
setDefaultOptions(Array.isArray(propsDefaultOptions) ? propsDefaultOptions : undefined);
|
|
37
|
+
setPrevDefaultOptions(propsDefaultOptions);
|
|
38
|
+
}
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
mounted.current = true;
|
|
41
|
+
return () => {
|
|
42
|
+
mounted.current = false;
|
|
43
|
+
};
|
|
44
|
+
}, []);
|
|
45
|
+
const loadOptions = useCallback((inputValue, callback) => {
|
|
46
|
+
if (!propsLoadOptions) {
|
|
47
|
+
return callback();
|
|
48
|
+
}
|
|
49
|
+
const loader = propsLoadOptions(inputValue, callback);
|
|
50
|
+
if (loader && typeof loader.then === 'function') {
|
|
51
|
+
loader.then(callback, () => callback());
|
|
52
|
+
}
|
|
53
|
+
}, [propsLoadOptions]);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (propsDefaultOptions === true) {
|
|
56
|
+
loadOptions(stateInputValue, options => {
|
|
57
|
+
if (!mounted.current) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
setDefaultOptions(options || []);
|
|
61
|
+
setIsLoading(!!lastRequest.current);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
// NOTE: this effect is designed to only run when the component mounts,
|
|
65
|
+
// so we don't want to include any hook dependencies
|
|
66
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
67
|
+
}, []);
|
|
68
|
+
const onInputChange = useCallback((newValue, actionMeta) => {
|
|
69
|
+
const inputValue = handleInputChange(newValue, actionMeta, propsOnInputChange);
|
|
70
|
+
if (!inputValue) {
|
|
71
|
+
lastRequest.current = undefined;
|
|
72
|
+
setStateInputValue('');
|
|
73
|
+
setLoadedInputValue('');
|
|
74
|
+
setLoadedOptions([]);
|
|
75
|
+
setIsLoading(false);
|
|
76
|
+
setPassEmptyOptions(false);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (cacheOptions && optionsCache[inputValue]) {
|
|
80
|
+
setStateInputValue(inputValue);
|
|
81
|
+
setLoadedInputValue(inputValue);
|
|
82
|
+
setLoadedOptions(optionsCache[inputValue]);
|
|
83
|
+
setIsLoading(false);
|
|
84
|
+
setPassEmptyOptions(false);
|
|
85
|
+
} else {
|
|
86
|
+
const request = lastRequest.current = {};
|
|
87
|
+
setStateInputValue(inputValue);
|
|
88
|
+
setIsLoading(true);
|
|
89
|
+
setPassEmptyOptions(!loadedInputValue);
|
|
90
|
+
loadOptions(inputValue, options => {
|
|
91
|
+
if (!mounted) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (request !== lastRequest.current) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
lastRequest.current = undefined;
|
|
98
|
+
setIsLoading(false);
|
|
99
|
+
setLoadedInputValue(inputValue);
|
|
100
|
+
setLoadedOptions(options || []);
|
|
101
|
+
setPassEmptyOptions(false);
|
|
102
|
+
setOptionsCache(options ? {
|
|
103
|
+
...optionsCache,
|
|
104
|
+
[inputValue]: options
|
|
105
|
+
} : optionsCache);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}, [cacheOptions, loadOptions, loadedInputValue, optionsCache, propsOnInputChange]);
|
|
109
|
+
const options = passEmptyOptions ? [] : stateInputValue && loadedInputValue ? loadedOptions : defaultOptions || [];
|
|
110
|
+
return {
|
|
111
|
+
...restSelectProps,
|
|
112
|
+
options,
|
|
113
|
+
isLoading: isLoading || propsIsLoading,
|
|
114
|
+
onInputChange,
|
|
115
|
+
filterOption
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { getOptionLabel as baseGetOptionLabel, getOptionValue as baseGetOptionValue } from './builtins';
|
|
3
|
+
import { cleanValue, valueTernary } from './utils';
|
|
4
|
+
const compareOption = (inputValue = '', option, accessors) => {
|
|
5
|
+
const candidate = String(inputValue).toLowerCase();
|
|
6
|
+
const optionValue = String(accessors.getOptionValue(option)).toLowerCase();
|
|
7
|
+
const optionLabel = String(accessors.getOptionLabel(option)).toLowerCase();
|
|
8
|
+
return optionValue === candidate || optionLabel === candidate;
|
|
9
|
+
};
|
|
10
|
+
const builtins = {
|
|
11
|
+
formatCreateLabel: inputValue => `Create "${inputValue}"`,
|
|
12
|
+
isValidNewOption: (inputValue, selectValue, selectOptions, accessors) => !(!inputValue || selectValue.some(option => compareOption(inputValue, option, accessors)) || selectOptions.some(option => compareOption(inputValue, option, accessors))),
|
|
13
|
+
getNewOptionData: (inputValue, optionLabel) => ({
|
|
14
|
+
label: optionLabel,
|
|
15
|
+
value: inputValue,
|
|
16
|
+
__isNew__: true
|
|
17
|
+
})
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// TODO: Fill in the hook {description}.
|
|
21
|
+
/**
|
|
22
|
+
* {description}.
|
|
23
|
+
*/
|
|
24
|
+
export default function useCreatable({
|
|
25
|
+
allowCreateWhileLoading = false,
|
|
26
|
+
createOptionPosition = 'last',
|
|
27
|
+
formatCreateLabel = builtins.formatCreateLabel,
|
|
28
|
+
//@ts-ignore
|
|
29
|
+
isValidNewOption = builtins.isValidNewOption,
|
|
30
|
+
//@ts-ignore
|
|
31
|
+
getNewOptionData = builtins.getNewOptionData,
|
|
32
|
+
onCreateOption,
|
|
33
|
+
options: propsOptions = [],
|
|
34
|
+
onChange: propsOnChange,
|
|
35
|
+
...restSelectProps
|
|
36
|
+
}) {
|
|
37
|
+
const {
|
|
38
|
+
getOptionValue = baseGetOptionValue,
|
|
39
|
+
getOptionLabel = baseGetOptionLabel,
|
|
40
|
+
inputValue,
|
|
41
|
+
isLoading,
|
|
42
|
+
isMulti,
|
|
43
|
+
value,
|
|
44
|
+
name
|
|
45
|
+
} = restSelectProps;
|
|
46
|
+
const newOption = useMemo(() =>
|
|
47
|
+
//@ts-ignore
|
|
48
|
+
isValidNewOption(inputValue, cleanValue(value), propsOptions, {
|
|
49
|
+
getOptionValue,
|
|
50
|
+
getOptionLabel
|
|
51
|
+
}) ? getNewOptionData(inputValue, formatCreateLabel(inputValue)) : undefined, [formatCreateLabel, getNewOptionData, getOptionLabel, getOptionValue, inputValue, isValidNewOption, propsOptions, value]);
|
|
52
|
+
const options = useMemo(() => (allowCreateWhileLoading || !isLoading) && newOption ? createOptionPosition === 'first' ? [newOption, ...propsOptions] : [...propsOptions, newOption] : propsOptions, [allowCreateWhileLoading, createOptionPosition, isLoading, newOption, propsOptions]);
|
|
53
|
+
const onChange = useCallback((newValue, actionMeta) => {
|
|
54
|
+
if (actionMeta.action !== 'select-option') {
|
|
55
|
+
return propsOnChange(newValue, actionMeta);
|
|
56
|
+
}
|
|
57
|
+
const valueArray = Array.isArray(newValue) ? newValue : [newValue];
|
|
58
|
+
if (valueArray[valueArray.length - 1] === newOption) {
|
|
59
|
+
if (onCreateOption) {
|
|
60
|
+
onCreateOption(inputValue);
|
|
61
|
+
} else {
|
|
62
|
+
const newOptionData = getNewOptionData(inputValue, inputValue);
|
|
63
|
+
const newActionMeta = {
|
|
64
|
+
action: 'create-option',
|
|
65
|
+
name,
|
|
66
|
+
option: newOptionData
|
|
67
|
+
};
|
|
68
|
+
propsOnChange(
|
|
69
|
+
//@ts-ignore
|
|
70
|
+
valueTernary(isMulti, [...cleanValue(value), newOptionData], newOptionData), newActionMeta);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
propsOnChange(newValue, actionMeta);
|
|
75
|
+
}, [getNewOptionData, inputValue, isMulti, name, newOption, onCreateOption, propsOnChange, value]);
|
|
76
|
+
return {
|
|
77
|
+
...restSelectProps,
|
|
78
|
+
options,
|
|
79
|
+
onChange
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
|
+
// TODO: Fill in the hook {description}.
|
|
3
|
+
/**
|
|
4
|
+
* {description}.
|
|
5
|
+
*/
|
|
6
|
+
export default function useStateManager({
|
|
7
|
+
defaultInputValue = '',
|
|
8
|
+
defaultMenuIsOpen = false,
|
|
9
|
+
defaultValue = null,
|
|
10
|
+
inputValue: propsInputValue,
|
|
11
|
+
menuIsOpen: propsMenuIsOpen,
|
|
12
|
+
onChange: propsOnChange,
|
|
13
|
+
onInputChange: propsOnInputChange,
|
|
14
|
+
onMenuClose: propsOnMenuClose,
|
|
15
|
+
onMenuOpen: propsOnMenuOpen,
|
|
16
|
+
value: propsValue,
|
|
17
|
+
...restSelectProps
|
|
18
|
+
}) {
|
|
19
|
+
const [stateInputValue, setStateInputValue] = useState(propsInputValue !== undefined ? propsInputValue : defaultInputValue);
|
|
20
|
+
const [stateMenuIsOpen, setStateMenuIsOpen] = useState(propsMenuIsOpen !== undefined ? propsMenuIsOpen : defaultMenuIsOpen);
|
|
21
|
+
const [stateValue, setStateValue] = useState(propsValue !== undefined ? propsValue : defaultValue);
|
|
22
|
+
const onChange = useCallback((value, actionMeta) => {
|
|
23
|
+
if (typeof propsOnChange === 'function') {
|
|
24
|
+
propsOnChange(value, actionMeta);
|
|
25
|
+
}
|
|
26
|
+
setStateValue(value);
|
|
27
|
+
}, [propsOnChange]);
|
|
28
|
+
const onInputChange = useCallback((value, actionMeta) => {
|
|
29
|
+
let newValue;
|
|
30
|
+
if (typeof propsOnInputChange === 'function') {
|
|
31
|
+
newValue = propsOnInputChange(value, actionMeta);
|
|
32
|
+
}
|
|
33
|
+
setStateInputValue(newValue !== undefined ? newValue : value);
|
|
34
|
+
}, [propsOnInputChange]);
|
|
35
|
+
const onMenuOpen = useCallback(() => {
|
|
36
|
+
if (typeof propsOnMenuOpen === 'function') {
|
|
37
|
+
propsOnMenuOpen();
|
|
38
|
+
}
|
|
39
|
+
setStateMenuIsOpen(true);
|
|
40
|
+
}, [propsOnMenuOpen]);
|
|
41
|
+
const onMenuClose = useCallback(() => {
|
|
42
|
+
if (typeof propsOnMenuClose === 'function') {
|
|
43
|
+
propsOnMenuClose();
|
|
44
|
+
}
|
|
45
|
+
setStateMenuIsOpen(false);
|
|
46
|
+
}, [propsOnMenuClose]);
|
|
47
|
+
const inputValue = propsInputValue !== undefined ? propsInputValue : stateInputValue;
|
|
48
|
+
const menuIsOpen = propsMenuIsOpen !== undefined ? propsMenuIsOpen : stateMenuIsOpen;
|
|
49
|
+
const value = propsValue !== undefined ? propsValue : stateValue;
|
|
50
|
+
return {
|
|
51
|
+
...restSelectProps,
|
|
52
|
+
inputValue,
|
|
53
|
+
menuIsOpen,
|
|
54
|
+
onChange,
|
|
55
|
+
onInputChange,
|
|
56
|
+
onMenuClose,
|
|
57
|
+
onMenuOpen,
|
|
58
|
+
value
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// ==============================
|
|
2
|
+
// NO OP
|
|
3
|
+
// ==============================
|
|
4
|
+
|
|
5
|
+
export const noop = () => {};
|
|
6
|
+
export const emptyString = () => '';
|
|
7
|
+
|
|
8
|
+
// ==============================
|
|
9
|
+
// Class Name Prefixer
|
|
10
|
+
// ==============================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* String representation of component state for styling with class names.
|
|
14
|
+
*
|
|
15
|
+
* Expects an array of strings OR a string/object pair:
|
|
16
|
+
* - className(['comp', 'comp-arg', 'comp-arg-2'])
|
|
17
|
+
* @returns 'react-select__comp react-select__comp-arg react-select__comp-arg-2'
|
|
18
|
+
* - className('comp', { some: true, state: false })
|
|
19
|
+
* @returns 'react-select__comp react-select__comp--some'
|
|
20
|
+
*/
|
|
21
|
+
function applyPrefixToName(prefix, name) {
|
|
22
|
+
if (!name) {
|
|
23
|
+
return prefix;
|
|
24
|
+
} else if (name[0] === '-') {
|
|
25
|
+
return prefix + name;
|
|
26
|
+
} else {
|
|
27
|
+
return prefix + '__' + name;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function classNames(prefix, state, ...classNameList) {
|
|
31
|
+
const arr = [...classNameList];
|
|
32
|
+
if (state && prefix) {
|
|
33
|
+
for (let key in state) {
|
|
34
|
+
if (state.hasOwnProperty(key) && state[key]) {
|
|
35
|
+
arr.push(`${applyPrefixToName(prefix, key)}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return arr.filter(i => i).map(i => String(i).trim()).join(' ');
|
|
40
|
+
}
|
|
41
|
+
// ==============================
|
|
42
|
+
// Clean Value
|
|
43
|
+
// ==============================
|
|
44
|
+
|
|
45
|
+
export const cleanValue = value => {
|
|
46
|
+
if (isArray(value)) {
|
|
47
|
+
return value.filter(Boolean);
|
|
48
|
+
}
|
|
49
|
+
if (typeof value === 'object' && value !== null) {
|
|
50
|
+
return [value];
|
|
51
|
+
}
|
|
52
|
+
return [];
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// ==============================
|
|
56
|
+
// Clean Common Props
|
|
57
|
+
// ==============================
|
|
58
|
+
|
|
59
|
+
export const cleanCommonProps = props => {
|
|
60
|
+
//className
|
|
61
|
+
const {
|
|
62
|
+
className,
|
|
63
|
+
// not listed in commonProps documentation, needs to be removed to allow Emotion to generate classNames
|
|
64
|
+
clearValue,
|
|
65
|
+
cx,
|
|
66
|
+
getStyles,
|
|
67
|
+
getClassNames,
|
|
68
|
+
getValue,
|
|
69
|
+
hasValue,
|
|
70
|
+
isMulti,
|
|
71
|
+
isRtl,
|
|
72
|
+
options,
|
|
73
|
+
// not listed in commonProps documentation
|
|
74
|
+
selectOption,
|
|
75
|
+
selectProps,
|
|
76
|
+
setValue,
|
|
77
|
+
theme,
|
|
78
|
+
// not listed in commonProps documentation
|
|
79
|
+
...innerProps
|
|
80
|
+
} = props;
|
|
81
|
+
return {
|
|
82
|
+
...innerProps
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// ==============================
|
|
87
|
+
// Get Style Props
|
|
88
|
+
// ==============================
|
|
89
|
+
|
|
90
|
+
export const getStyleProps = (props, name, classNamesState) => {
|
|
91
|
+
const {
|
|
92
|
+
cx,
|
|
93
|
+
getStyles,
|
|
94
|
+
getClassNames,
|
|
95
|
+
className
|
|
96
|
+
} = props;
|
|
97
|
+
return {
|
|
98
|
+
css: getStyles(name, props),
|
|
99
|
+
className: cx(classNamesState !== null && classNamesState !== void 0 ? classNamesState : {}, getClassNames(name, props), className)
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// ==============================
|
|
104
|
+
// Handle Input Change
|
|
105
|
+
// ==============================
|
|
106
|
+
|
|
107
|
+
export function handleInputChange(inputValue, actionMeta, onInputChange) {
|
|
108
|
+
if (onInputChange) {
|
|
109
|
+
const newValue = onInputChange(inputValue, actionMeta);
|
|
110
|
+
if (typeof newValue === 'string') {
|
|
111
|
+
return newValue;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return inputValue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ==============================
|
|
118
|
+
// Scroll Helpers
|
|
119
|
+
// ==============================
|
|
120
|
+
|
|
121
|
+
export function isDocumentElement(el) {
|
|
122
|
+
return [document.documentElement, document.body, window].indexOf(el) > -1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Normalized Scroll Top
|
|
126
|
+
// ------------------------------
|
|
127
|
+
|
|
128
|
+
export function normalizedHeight(el) {
|
|
129
|
+
if (isDocumentElement(el)) {
|
|
130
|
+
return window.innerHeight;
|
|
131
|
+
}
|
|
132
|
+
return el.clientHeight;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Normalized scrollTo & scrollTop
|
|
136
|
+
// ------------------------------
|
|
137
|
+
|
|
138
|
+
export function getScrollTop(el) {
|
|
139
|
+
if (isDocumentElement(el)) {
|
|
140
|
+
return window.pageYOffset;
|
|
141
|
+
}
|
|
142
|
+
return el.scrollTop;
|
|
143
|
+
}
|
|
144
|
+
export function scrollTo(el, top) {
|
|
145
|
+
// with a scroll distance, we perform scroll on the element
|
|
146
|
+
if (isDocumentElement(el)) {
|
|
147
|
+
window.scrollTo(0, top);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
el.scrollTop = top;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Get Scroll Parent
|
|
154
|
+
// ------------------------------
|
|
155
|
+
|
|
156
|
+
export function getScrollParent(element) {
|
|
157
|
+
let style = getComputedStyle(element);
|
|
158
|
+
const excludeStaticParent = style.position === 'absolute';
|
|
159
|
+
const overflowRx = /(auto|scroll)/;
|
|
160
|
+
if (style.position === 'fixed') {
|
|
161
|
+
return document.documentElement;
|
|
162
|
+
}
|
|
163
|
+
for (let parent = element; parent = parent.parentElement;) {
|
|
164
|
+
style = getComputedStyle(parent);
|
|
165
|
+
if (excludeStaticParent && style.position === 'static') {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (overflowRx.test(style.overflow + style.overflowY + style.overflowX)) {
|
|
169
|
+
return parent;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return document.documentElement;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Animated Scroll To
|
|
176
|
+
// ------------------------------
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @param t: time (elapsed)
|
|
180
|
+
* @param b: initial value
|
|
181
|
+
* @param c: amount of change
|
|
182
|
+
* @param d: duration
|
|
183
|
+
*/
|
|
184
|
+
function easeOutCubic(t, b, c, d) {
|
|
185
|
+
return c * ((t = t / d - 1) * t * t + 1) + b;
|
|
186
|
+
}
|
|
187
|
+
export function animatedScrollTo(element, to, duration = 200, callback = noop) {
|
|
188
|
+
const start = getScrollTop(element);
|
|
189
|
+
const change = to - start;
|
|
190
|
+
const increment = 10;
|
|
191
|
+
let currentTime = 0;
|
|
192
|
+
function animateScroll() {
|
|
193
|
+
currentTime += increment;
|
|
194
|
+
const val = easeOutCubic(currentTime, start, change, duration);
|
|
195
|
+
scrollTo(element, val);
|
|
196
|
+
if (currentTime < duration) {
|
|
197
|
+
window.requestAnimationFrame(animateScroll);
|
|
198
|
+
} else {
|
|
199
|
+
callback(element);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
animateScroll();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Scroll Into View
|
|
206
|
+
// ------------------------------
|
|
207
|
+
|
|
208
|
+
export function scrollIntoView(menuEl, focusedEl) {
|
|
209
|
+
const menuRect = menuEl.getBoundingClientRect();
|
|
210
|
+
const focusedRect = focusedEl.getBoundingClientRect();
|
|
211
|
+
const overScroll = focusedEl.offsetHeight / 3;
|
|
212
|
+
if (focusedRect.bottom + overScroll > menuRect.bottom) {
|
|
213
|
+
scrollTo(menuEl, Math.min(focusedEl.offsetTop + focusedEl.clientHeight - menuEl.offsetHeight + overScroll, menuEl.scrollHeight));
|
|
214
|
+
} else if (focusedRect.top - overScroll < menuRect.top) {
|
|
215
|
+
scrollTo(menuEl, Math.max(focusedEl.offsetTop - overScroll, 0));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ==============================
|
|
220
|
+
// Get bounding client object
|
|
221
|
+
// ==============================
|
|
222
|
+
|
|
223
|
+
// cannot get keys using array notation with DOMRect
|
|
224
|
+
export function getBoundingClientObj(element) {
|
|
225
|
+
const rect = element.getBoundingClientRect();
|
|
226
|
+
return {
|
|
227
|
+
bottom: rect.bottom,
|
|
228
|
+
height: rect.height,
|
|
229
|
+
left: rect.left,
|
|
230
|
+
right: rect.right,
|
|
231
|
+
top: rect.top,
|
|
232
|
+
width: rect.width
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
// ==============================
|
|
236
|
+
// String to Key (kebabify)
|
|
237
|
+
// ==============================
|
|
238
|
+
|
|
239
|
+
export function toKey(str) {
|
|
240
|
+
return str.replace(/\W/g, '-');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ==============================
|
|
244
|
+
// Touch Capability Detector
|
|
245
|
+
// ==============================
|
|
246
|
+
|
|
247
|
+
export function isTouchCapable() {
|
|
248
|
+
try {
|
|
249
|
+
document.createEvent('TouchEvent');
|
|
250
|
+
return true;
|
|
251
|
+
} catch (e) {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ==============================
|
|
257
|
+
// Mobile Device Detector
|
|
258
|
+
// ==============================
|
|
259
|
+
|
|
260
|
+
export function isMobileDevice() {
|
|
261
|
+
try {
|
|
262
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
263
|
+
} catch (e) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ==============================
|
|
269
|
+
// Passive Event Detector
|
|
270
|
+
// ==============================
|
|
271
|
+
|
|
272
|
+
// https://github.com/rafgraph/detect-it/blob/main/src/index.ts#L19-L36
|
|
273
|
+
let passiveOptionAccessed = false;
|
|
274
|
+
const options = {
|
|
275
|
+
get passive() {
|
|
276
|
+
return passiveOptionAccessed = true;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
// check for SSR
|
|
280
|
+
const w = typeof window !== 'undefined' ? window : {};
|
|
281
|
+
if (w.addEventListener && w.removeEventListener) {
|
|
282
|
+
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
|
|
283
|
+
w.addEventListener('p', noop, options);
|
|
284
|
+
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
|
|
285
|
+
w.removeEventListener('p', noop, false);
|
|
286
|
+
}
|
|
287
|
+
export const supportsPassiveEvents = passiveOptionAccessed;
|
|
288
|
+
export function notNullish(item) {
|
|
289
|
+
return item != null;
|
|
290
|
+
}
|
|
291
|
+
export function isArray(arg) {
|
|
292
|
+
return Array.isArray(arg);
|
|
293
|
+
}
|
|
294
|
+
export function valueTernary(isMulti, multiValue, singleValue) {
|
|
295
|
+
return isMulti ? multiValue : singleValue;
|
|
296
|
+
}
|
|
297
|
+
export function singleValueAsValue(singleValue) {
|
|
298
|
+
return singleValue;
|
|
299
|
+
}
|
|
300
|
+
export function multiValueAsValue(multiValue) {
|
|
301
|
+
return multiValue;
|
|
302
|
+
}
|
|
303
|
+
export const removeProps = (propsObj, ...properties) => {
|
|
304
|
+
let propsMap = Object.entries(propsObj).filter(([key]) => !properties.includes(key));
|
|
305
|
+
return propsMap.reduce((newProps, [key, val]) => {
|
|
306
|
+
newProps[key] = val;
|
|
307
|
+
return newProps;
|
|
308
|
+
}, {});
|
|
309
|
+
};
|