@octanejs/select 0.1.13 → 0.1.15
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/package.json +5 -5
- package/src/animated/input.tsrx +4 -2
- package/src/animated/transitions.tsrx +17 -15
- package/src/animated/value-container.tsrx +2 -2
- package/src/async-creatable.tsrx +8 -7
- package/src/async.tsrx +1 -1
- package/src/components.tsrx +71 -61
- package/src/creatable.tsrx +6 -3
- package/src/select.tsrx +466 -459
- package/src/state-managed-select.tsrx +2 -3
- package/src/style-context.tsrx +3 -11
- package/src/use-async.tsrx +63 -59
- package/src/use-creatable.tsrx +61 -54
- package/src/use-state-manager.tsrx +17 -15
|
@@ -6,8 +6,7 @@ export type Props<
|
|
|
6
6
|
Option = unknown,
|
|
7
7
|
IsMulti extends boolean = boolean,
|
|
8
8
|
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
9
|
-
> =
|
|
10
|
-
StateManagerProps<Option, IsMulti, Group>;
|
|
9
|
+
> = StateManagerProps<Option, IsMulti, Group>;
|
|
11
10
|
|
|
12
11
|
export function StateManagedSelect<
|
|
13
12
|
Option = unknown,
|
|
@@ -15,5 +14,5 @@ export function StateManagedSelect<
|
|
|
15
14
|
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
16
15
|
>(props: Props<Option, IsMulti, Group>) @{
|
|
17
16
|
const selectProps = useStateManager<Option, IsMulti, Group>(props);
|
|
18
|
-
<Select {...selectProps as SelectProps<Option, IsMulti, Group>} />
|
|
17
|
+
<Select {...(selectProps as SelectProps<Option, IsMulti, Group>)} />
|
|
19
18
|
}
|
package/src/style-context.tsrx
CHANGED
|
@@ -11,11 +11,7 @@ interface StyleContextValue {
|
|
|
11
11
|
|
|
12
12
|
const StyleContext = createContext<StyleContextValue | null>(null);
|
|
13
13
|
|
|
14
|
-
export function NonceProvider(props: {
|
|
15
|
-
nonce: string;
|
|
16
|
-
children?: OctaneNode;
|
|
17
|
-
cacheKey: string;
|
|
18
|
-
}) @{
|
|
14
|
+
export function NonceProvider(props: { nonce: string; children?: OctaneNode; cacheKey: string }) @{
|
|
19
15
|
const value = useMemo(
|
|
20
16
|
() => ({
|
|
21
17
|
cache: createStyleCache({ key: props.cacheKey, nonce: props.nonce }),
|
|
@@ -28,10 +24,6 @@ export function NonceProvider(props: {
|
|
|
28
24
|
|
|
29
25
|
export function useStyleResolver() {
|
|
30
26
|
const context = useContext(StyleContext);
|
|
31
|
-
return (cssValue: CSSObjectWithLabel, className?: unknown) =>
|
|
32
|
-
cssValue,
|
|
33
|
-
className,
|
|
34
|
-
context?.cache,
|
|
35
|
-
context?.nonce,
|
|
36
|
-
);
|
|
27
|
+
return (cssValue: CSSObjectWithLabel, className?: unknown) =>
|
|
28
|
+
resolveComponentStyle(cssValue, className, context?.cache, context?.nonce);
|
|
37
29
|
}
|
package/src/use-async.tsrx
CHANGED
|
@@ -9,15 +9,18 @@ export interface AsyncAdditionalProps<Option, Group extends GroupBase<Option>> {
|
|
|
9
9
|
// Matches upstream's deliberately opaque cache invalidation token.
|
|
10
10
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
11
|
cacheOptions?: any;
|
|
12
|
-
loadOptions?: (
|
|
13
|
-
|
|
14
|
-
Group
|
|
15
|
-
|
|
12
|
+
loadOptions?: (
|
|
13
|
+
inputValue: string,
|
|
14
|
+
callback: (options: OptionsOrGroups<Option, Group>) => void,
|
|
15
|
+
) => Promise<OptionsOrGroups<Option, Group>> | void;
|
|
16
16
|
isLoading?: boolean;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export type AsyncProps<
|
|
20
|
-
|
|
19
|
+
export type AsyncProps<
|
|
20
|
+
Option,
|
|
21
|
+
IsMulti extends boolean,
|
|
22
|
+
Group extends GroupBase<Option>,
|
|
23
|
+
> = StateManagerProps<Option, IsMulti, Group> & AsyncAdditionalProps<Option, Group>;
|
|
21
24
|
|
|
22
25
|
export function useAsync<
|
|
23
26
|
Option,
|
|
@@ -47,12 +50,11 @@ export function useAsync<
|
|
|
47
50
|
const [defaultOptions, setDefaultOptions] = useLinkedState<
|
|
48
51
|
OptionsOrGroups<Option, Group> | boolean,
|
|
49
52
|
OptionsOrGroups<Option, Group> | undefined
|
|
50
|
-
>(
|
|
51
|
-
|
|
52
|
-
(nextDefaultOptions) => Array.isArray(nextDefaultOptions) ? nextDefaultOptions : undefined,
|
|
53
|
+
>(propsDefaultOptions, (nextDefaultOptions) =>
|
|
54
|
+
Array.isArray(nextDefaultOptions) ? nextDefaultOptions : undefined,
|
|
53
55
|
);
|
|
54
56
|
const [stateInputValue, setStateInputValue] = useState(
|
|
55
|
-
typeof propsInputValue !== 'undefined' ? propsInputValue as string : '',
|
|
57
|
+
typeof propsInputValue !== 'undefined' ? (propsInputValue as string) : '',
|
|
56
58
|
);
|
|
57
59
|
const [isLoading, setIsLoading] = useState(propsDefaultOptions === true);
|
|
58
60
|
const [loadedInputValue, setLoadedInputValue] = useState<string | undefined>(undefined);
|
|
@@ -73,17 +75,17 @@ export function useAsync<
|
|
|
73
75
|
};
|
|
74
76
|
}, []);
|
|
75
77
|
|
|
76
|
-
const loadOptions = useCallback(
|
|
77
|
-
inputValue: string,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
78
|
+
const loadOptions = useCallback(
|
|
79
|
+
(inputValue: string, callback: (options?: OptionsOrGroups<Option, Group>) => void) => {
|
|
80
|
+
if (!propsLoadOptions) {
|
|
81
|
+
callback();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const loader = propsLoadOptions(inputValue, callback);
|
|
85
|
+
if (loader && typeof loader.then === 'function') loader.then(callback, () => callback());
|
|
86
|
+
},
|
|
87
|
+
[propsLoadOptions],
|
|
88
|
+
);
|
|
87
89
|
|
|
88
90
|
useEffect(() => {
|
|
89
91
|
if (propsDefaultOptions === true) {
|
|
@@ -95,46 +97,48 @@ export function useAsync<
|
|
|
95
97
|
}
|
|
96
98
|
}, []);
|
|
97
99
|
|
|
98
|
-
const onInputChange = useCallback(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
const onInputChange = useCallback(
|
|
101
|
+
(newValue: string, actionMeta: InputActionMeta) => {
|
|
102
|
+
const inputValue = handleInputChange(newValue, actionMeta, propsOnInputChange);
|
|
103
|
+
if (!inputValue) {
|
|
104
|
+
lastRequest.current = undefined;
|
|
105
|
+
setStateInputValue('');
|
|
106
|
+
setLoadedInputValue('');
|
|
107
|
+
setLoadedOptions([]);
|
|
108
|
+
setIsLoading(false);
|
|
109
|
+
setPassEmptyOptions(false);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (cacheOptions && optionsCache[inputValue]) {
|
|
113
|
+
setStateInputValue(inputValue);
|
|
114
|
+
setLoadedInputValue(inputValue);
|
|
115
|
+
setLoadedOptions(optionsCache[inputValue]);
|
|
116
|
+
setIsLoading(false);
|
|
117
|
+
setPassEmptyOptions(false);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const request = (lastRequest.current = {});
|
|
110
121
|
setStateInputValue(inputValue);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
setLoadedInputValue(inputValue);
|
|
126
|
-
setLoadedOptions(options || []);
|
|
127
|
-
setPassEmptyOptions(false);
|
|
128
|
-
setOptionsCache(options ? { ...optionsCache, [inputValue]: options } : optionsCache);
|
|
129
|
-
});
|
|
130
|
-
}, [cacheOptions, loadOptions, loadedInputValue, optionsCache, propsOnInputChange]);
|
|
122
|
+
setIsLoading(true);
|
|
123
|
+
setPassEmptyOptions(!loadedInputValue);
|
|
124
|
+
loadOptions(inputValue, (options) => {
|
|
125
|
+
if (!mounted.current || request !== lastRequest.current) return;
|
|
126
|
+
lastRequest.current = undefined;
|
|
127
|
+
setIsLoading(false);
|
|
128
|
+
setLoadedInputValue(inputValue);
|
|
129
|
+
setLoadedOptions(options || []);
|
|
130
|
+
setPassEmptyOptions(false);
|
|
131
|
+
setOptionsCache(options ? { ...optionsCache, [inputValue]: options } : optionsCache);
|
|
132
|
+
});
|
|
133
|
+
},
|
|
134
|
+
[cacheOptions, loadOptions, loadedInputValue, optionsCache, propsOnInputChange],
|
|
135
|
+
);
|
|
131
136
|
|
|
132
|
-
const options =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
: (defaultOptions || []) as OptionsOrGroups<Option, Group>;
|
|
137
|
+
const options = passEmptyOptions
|
|
138
|
+
? []
|
|
139
|
+
: stateInputValue && loadedInputValue
|
|
140
|
+
? loadedOptions
|
|
141
|
+
: ((defaultOptions || []) as OptionsOrGroups<Option, Group>);
|
|
138
142
|
|
|
139
143
|
return {
|
|
140
144
|
...restSelectProps,
|
package/src/use-creatable.tsrx
CHANGED
|
@@ -26,21 +26,28 @@ export interface CreatableAdditionalProps<Option, Group extends GroupBase<Option
|
|
|
26
26
|
allowCreateWhileLoading?: boolean;
|
|
27
27
|
createOptionPosition?: 'first' | 'last';
|
|
28
28
|
formatCreateLabel?: (inputValue: string) => OctaneNode;
|
|
29
|
-
isValidNewOption?: (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
isValidNewOption?: (
|
|
30
|
+
inputValue: string,
|
|
31
|
+
value: Options<Option>,
|
|
32
|
+
options: OptionsOrGroups<Option, Group>,
|
|
33
|
+
accessors: Accessors<Option>,
|
|
34
|
+
) => boolean;
|
|
33
35
|
getNewOptionData?: (inputValue: string, optionLabel: OctaneNode) => Option;
|
|
34
36
|
onCreateOption?: (inputValue: string) => void;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
export type CreatableBaseProps<
|
|
38
|
-
|
|
39
|
+
export type CreatableBaseProps<
|
|
40
|
+
Option,
|
|
41
|
+
IsMulti extends boolean,
|
|
42
|
+
Group extends GroupBase<Option>,
|
|
43
|
+
> = PublicBaseSelectProps<Option, IsMulti, Group> & CreatableAdditionalProps<Option, Group>;
|
|
39
44
|
|
|
40
45
|
function compareOption<Option>(inputValue: string, option: Option, accessors: Accessors<Option>) {
|
|
41
46
|
const candidate = String(inputValue).toLowerCase();
|
|
42
|
-
return
|
|
43
|
-
String(accessors.
|
|
47
|
+
return (
|
|
48
|
+
String(accessors.getOptionValue(option)).toLowerCase() === candidate ||
|
|
49
|
+
String(accessors.getOptionLabel(option)).toLowerCase() === candidate
|
|
50
|
+
);
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
const builtins = {
|
|
@@ -51,9 +58,11 @@ const builtins = {
|
|
|
51
58
|
selectOptions: OptionsOrGroups<Option, Group>,
|
|
52
59
|
accessors: Accessors<Option>,
|
|
53
60
|
) {
|
|
54
|
-
return !(
|
|
61
|
+
return !(
|
|
62
|
+
!inputValue ||
|
|
55
63
|
selectValue.some((option) => compareOption(inputValue, option, accessors)) ||
|
|
56
|
-
selectOptions.some((option) => compareOption(inputValue, option as Option, accessors))
|
|
64
|
+
selectOptions.some((option) => compareOption(inputValue, option as Option, accessors))
|
|
65
|
+
);
|
|
57
66
|
},
|
|
58
67
|
getNewOptionData(inputValue: string, optionLabel: OctaneNode) {
|
|
59
68
|
return { label: optionLabel, value: inputValue, __isNew__: true };
|
|
@@ -68,7 +77,10 @@ export function useCreatable<Option, IsMulti extends boolean, Group extends Grou
|
|
|
68
77
|
createOptionPosition = 'last',
|
|
69
78
|
formatCreateLabel = builtins.formatCreateLabel,
|
|
70
79
|
isValidNewOption = builtins.isValidNewOption,
|
|
71
|
-
getNewOptionData = builtins.getNewOptionData as unknown as (
|
|
80
|
+
getNewOptionData = builtins.getNewOptionData as unknown as (
|
|
81
|
+
inputValue: string,
|
|
82
|
+
optionLabel: OctaneNode,
|
|
83
|
+
) => Option,
|
|
72
84
|
onCreateOption,
|
|
73
85
|
options: propsOptions = [],
|
|
74
86
|
onChange: propsOnChange,
|
|
@@ -85,10 +97,13 @@ export function useCreatable<Option, IsMulti extends boolean, Group extends Grou
|
|
|
85
97
|
} = restSelectProps;
|
|
86
98
|
|
|
87
99
|
const newOption = useMemo(
|
|
88
|
-
() =>
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
() =>
|
|
101
|
+
isValidNewOption(inputValue, cleanValue(value), propsOptions, {
|
|
102
|
+
getOptionValue,
|
|
103
|
+
getOptionLabel,
|
|
104
|
+
})
|
|
105
|
+
? getNewOptionData(inputValue, formatCreateLabel(inputValue))
|
|
106
|
+
: undefined,
|
|
92
107
|
[
|
|
93
108
|
formatCreateLabel,
|
|
94
109
|
getNewOptionData,
|
|
@@ -102,49 +117,41 @@ export function useCreatable<Option, IsMulti extends boolean, Group extends Grou
|
|
|
102
117
|
);
|
|
103
118
|
|
|
104
119
|
const options = useMemo(
|
|
105
|
-
() =>
|
|
106
|
-
|
|
107
|
-
?
|
|
108
|
-
|
|
109
|
-
|
|
120
|
+
() =>
|
|
121
|
+
(allowCreateWhileLoading || !isLoading) && newOption
|
|
122
|
+
? createOptionPosition === 'first'
|
|
123
|
+
? [newOption, ...propsOptions]
|
|
124
|
+
: [...propsOptions, newOption]
|
|
125
|
+
: propsOptions,
|
|
110
126
|
[allowCreateWhileLoading, createOptionPosition, isLoading, newOption, propsOptions],
|
|
111
127
|
);
|
|
112
128
|
|
|
113
|
-
const onChange = useCallback(
|
|
114
|
-
newValue: OnChangeValue<Option, IsMulti>,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
propsOnChange?.(newValue, actionMeta);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
const valueArray = Array.isArray(newValue) ? newValue : [newValue];
|
|
122
|
-
if (valueArray[valueArray.length - 1] === newOption) {
|
|
123
|
-
if (onCreateOption) onCreateOption(inputValue);
|
|
124
|
-
else {
|
|
125
|
-
const newOptionData = getNewOptionData(inputValue, inputValue);
|
|
126
|
-
propsOnChange?.(
|
|
127
|
-
valueTernary(
|
|
128
|
-
isMulti,
|
|
129
|
-
[...cleanValue(value), newOptionData],
|
|
130
|
-
newOptionData,
|
|
131
|
-
) as OnChangeValue<Option, IsMulti>,
|
|
132
|
-
{ action: 'create-option', name, option: newOptionData },
|
|
133
|
-
);
|
|
129
|
+
const onChange = useCallback(
|
|
130
|
+
(newValue: OnChangeValue<Option, IsMulti>, actionMeta: ActionMeta<Option>) => {
|
|
131
|
+
if (actionMeta.action !== 'select-option') {
|
|
132
|
+
propsOnChange?.(newValue, actionMeta);
|
|
133
|
+
return;
|
|
134
134
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
135
|
+
const valueArray = Array.isArray(newValue) ? newValue : [newValue];
|
|
136
|
+
if (valueArray[valueArray.length - 1] === newOption) {
|
|
137
|
+
if (onCreateOption) onCreateOption(inputValue);
|
|
138
|
+
else {
|
|
139
|
+
const newOptionData = getNewOptionData(inputValue, inputValue);
|
|
140
|
+
propsOnChange?.(
|
|
141
|
+
valueTernary(
|
|
142
|
+
isMulti,
|
|
143
|
+
[...cleanValue(value), newOptionData],
|
|
144
|
+
newOptionData,
|
|
145
|
+
) as OnChangeValue<Option, IsMulti>,
|
|
146
|
+
{ action: 'create-option', name, option: newOptionData },
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
propsOnChange?.(newValue, actionMeta);
|
|
152
|
+
},
|
|
153
|
+
[getNewOptionData, inputValue, isMulti, name, newOption, onCreateOption, propsOnChange, value],
|
|
154
|
+
);
|
|
148
155
|
|
|
149
156
|
return { ...restSelectProps, options, onChange } as CreatableBaseProps<Option, IsMulti, Group>;
|
|
150
157
|
}
|
|
@@ -22,10 +22,9 @@ export type StateManagerProps<
|
|
|
22
22
|
Option = unknown,
|
|
23
23
|
IsMulti extends boolean = boolean,
|
|
24
24
|
Group extends GroupBase<Option> = GroupBase<Option>,
|
|
25
|
-
> =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
> & StateManagerAdditionalProps<Option>;
|
|
25
|
+
> = Omit<PublicBaseSelectProps<Option, IsMulti, Group>, StateManagedPropKeys> &
|
|
26
|
+
Partial<PublicBaseSelectProps<Option, IsMulti, Group>> &
|
|
27
|
+
StateManagerAdditionalProps<Option>;
|
|
29
28
|
|
|
30
29
|
export function useStateManager<
|
|
31
30
|
Option,
|
|
@@ -57,17 +56,20 @@ export function useStateManager<
|
|
|
57
56
|
propsValue !== undefined ? propsValue : defaultValue,
|
|
58
57
|
);
|
|
59
58
|
|
|
60
|
-
const onChange = useCallback(
|
|
61
|
-
value: OnChangeValue<Option, IsMulti>,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const onInputChange = useCallback(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
59
|
+
const onChange = useCallback(
|
|
60
|
+
(value: OnChangeValue<Option, IsMulti>, actionMeta: ActionMeta<Option>) => {
|
|
61
|
+
propsOnChange?.(value, actionMeta);
|
|
62
|
+
setStateValue(value);
|
|
63
|
+
},
|
|
64
|
+
[propsOnChange],
|
|
65
|
+
);
|
|
66
|
+
const onInputChange = useCallback(
|
|
67
|
+
(value: string, actionMeta: InputActionMeta) => {
|
|
68
|
+
const newValue = propsOnInputChange?.(value, actionMeta);
|
|
69
|
+
setStateInputValue(newValue !== undefined ? newValue : value);
|
|
70
|
+
},
|
|
71
|
+
[propsOnInputChange],
|
|
72
|
+
);
|
|
71
73
|
const onMenuOpen = useCallback(() => {
|
|
72
74
|
propsOnMenuOpen?.();
|
|
73
75
|
setStateMenuIsOpen(true);
|