@7shifts/sous-chef 4.11.0 → 4.12.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/dist/forms/AsyncSelectField/AsyncSelectField.d.ts +4 -3
- package/dist/forms/AsyncSelectField/CustomList/CustomList.d.ts +2 -1
- package/dist/forms/AsyncSelectField/types.d.ts +1 -0
- package/dist/index.js +143 -64
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +124 -54
- package/dist/index.modern.js.map +1 -1
- package/llms-instructions/guidelines/AsyncSelectField.guidelines.md +86 -11
- package/llms-instructions/llms-components.md +1 -1
- package/llms-instructions/llms-tokens.md +1 -0
- package/package.json +1 -1
|
@@ -2,14 +2,15 @@ import React from 'react';
|
|
|
2
2
|
import type { Props as SelectProps } from '../SelectField/SelectField';
|
|
3
3
|
import { AsyncSelectOptions } from './types';
|
|
4
4
|
type Props<T> = {
|
|
5
|
-
/** It is a function that takes the input search as
|
|
6
|
-
loadOptions: (inputValue: string) => Promise<AsyncSelectOptions<T>>;
|
|
5
|
+
/** It is a function that takes the input search and an optional cursor as parameters and returns a Promise with all the options, if there are more options to load, and optionally the next cursor. If it brings all the options on the first load, it won't call `loadOptions` to perform the search. */
|
|
6
|
+
loadOptions: (inputValue: string, cursor?: string | null) => Promise<AsyncSelectOptions<T>>;
|
|
7
7
|
/** It fires `loadOptions` again if this key value changes. Used when it depends on other fields to load its options */
|
|
8
8
|
key?: string | number;
|
|
9
9
|
} & Omit<SelectProps<T>, 'options'>;
|
|
10
10
|
/**
|
|
11
11
|
* A variation of select field that loads a dynamic list of options from a source rather than a fixed set of options. Use when you need to select from a dynamic list that can change such as roles, employees, locations, etc.
|
|
12
|
-
* Instead of passing
|
|
12
|
+
* Instead of passing an `options` prop, this component requires a `loadOptions` prop.
|
|
13
|
+
* Supports scroll-to-load-more: when the user scrolls to the bottom of the menu and a `nextCursor` is returned, the next page is automatically fetched and appended.
|
|
13
14
|
* */
|
|
14
15
|
declare const AsyncSelectField: <T extends unknown>({ loadOptions, ...props }: Props<T>) => React.JSX.Element;
|
|
15
16
|
export default AsyncSelectField;
|
|
@@ -3,6 +3,7 @@ import { components } from 'react-select';
|
|
|
3
3
|
type Props = ComponentProps<typeof components.MenuList> & {
|
|
4
4
|
hasMoreOptions: boolean;
|
|
5
5
|
hasMoreOptionsFirstLoad: boolean | null | undefined;
|
|
6
|
+
isLoadingMore: boolean;
|
|
6
7
|
};
|
|
7
|
-
declare const CustomList: ({ children, hasMoreOptions, hasMoreOptionsFirstLoad, ...props }: Props) => React.JSX.Element;
|
|
8
|
+
declare const CustomList: ({ children, hasMoreOptions, hasMoreOptionsFirstLoad, isLoadingMore, ...props }: Props) => React.JSX.Element;
|
|
8
9
|
export default CustomList;
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,6 @@ var originalStylers = require('react-day-picker/dist/style.module.css');
|
|
|
15
15
|
require('react-toastify/dist/ReactToastify.css');
|
|
16
16
|
var libphonenumberJs = require('libphonenumber-js');
|
|
17
17
|
var Select = require('react-select');
|
|
18
|
-
var AsyncSelect = require('react-select/async');
|
|
19
18
|
var dateFns = require('date-fns');
|
|
20
19
|
var getDay = require('date-fns/getDay');
|
|
21
20
|
var getDate = require('date-fns/getDate');
|
|
@@ -54,7 +53,6 @@ var dateFnsParse__default = /*#__PURE__*/_interopDefaultLegacy(dateFnsParse);
|
|
|
54
53
|
var startOfDay__default = /*#__PURE__*/_interopDefaultLegacy(startOfDay);
|
|
55
54
|
var originalStylers__default = /*#__PURE__*/_interopDefaultLegacy(originalStylers);
|
|
56
55
|
var Select__default = /*#__PURE__*/_interopDefaultLegacy(Select);
|
|
57
|
-
var AsyncSelect__default = /*#__PURE__*/_interopDefaultLegacy(AsyncSelect);
|
|
58
56
|
var getDay__default = /*#__PURE__*/_interopDefaultLegacy(getDay);
|
|
59
57
|
var getDate__default = /*#__PURE__*/_interopDefaultLegacy(getDate);
|
|
60
58
|
var getDaysInMonth__default = /*#__PURE__*/_interopDefaultLegacy(getDaysInMonth);
|
|
@@ -17649,18 +17647,23 @@ var MultiSelectField = function MultiSelectField(_ref) {
|
|
|
17649
17647
|
|
|
17650
17648
|
var styles$r = {"custom-list":"_cSkvD"};
|
|
17651
17649
|
|
|
17652
|
-
var _excluded$b4 = ["children", "hasMoreOptions", "hasMoreOptionsFirstLoad"];
|
|
17650
|
+
var _excluded$b4 = ["children", "hasMoreOptions", "hasMoreOptionsFirstLoad", "isLoadingMore"];
|
|
17653
17651
|
var CustomList = function CustomList(_ref) {
|
|
17654
17652
|
var children = _ref.children,
|
|
17655
17653
|
hasMoreOptions = _ref.hasMoreOptions,
|
|
17656
17654
|
hasMoreOptionsFirstLoad = _ref.hasMoreOptionsFirstLoad,
|
|
17655
|
+
isLoadingMore = _ref.isLoadingMore,
|
|
17657
17656
|
props = _objectWithoutPropertiesLoose(_ref, _excluded$b4);
|
|
17658
17657
|
var __ = useTranslation('AsyncSelectField');
|
|
17659
17658
|
var showFooter = hasMoreOptions;
|
|
17660
17659
|
if (props.selectProps.inputValue === '' && typeof hasMoreOptionsFirstLoad === 'boolean') {
|
|
17661
17660
|
showFooter = hasMoreOptionsFirstLoad;
|
|
17662
17661
|
}
|
|
17663
|
-
return React__default["default"].createElement(Select.components.MenuList, _extends({}, props), React__default["default"].createElement(React.Fragment, null, children,
|
|
17662
|
+
return React__default["default"].createElement(Select.components.MenuList, _extends({}, props), React__default["default"].createElement(React.Fragment, null, children, isLoadingMore ? React__default["default"].createElement(Inline, {
|
|
17663
|
+
justifyContent: "center"
|
|
17664
|
+
}, React__default["default"].createElement(Spinner, {
|
|
17665
|
+
size: 20
|
|
17666
|
+
})) : showFooter && props.options.length > 0 && React__default["default"].createElement(Inline, {
|
|
17664
17667
|
justifyContent: "center"
|
|
17665
17668
|
}, React__default["default"].createElement("div", {
|
|
17666
17669
|
className: styles$r['custom-list']
|
|
@@ -17668,61 +17671,123 @@ var CustomList = function CustomList(_ref) {
|
|
|
17668
17671
|
};
|
|
17669
17672
|
|
|
17670
17673
|
var _excluded$b3 = ["loadOptions"];
|
|
17674
|
+
var MenuListContext = React__default["default"].createContext({
|
|
17675
|
+
hasMoreOptions: false,
|
|
17676
|
+
hasMoreOptionsFirstLoad: null,
|
|
17677
|
+
isLoadingMore: false
|
|
17678
|
+
});
|
|
17679
|
+
// Defined outside the component so the reference is stable — prevents MenuList from
|
|
17680
|
+
// unmounting/remounting (and losing scroll position) on every state change.
|
|
17681
|
+
var AsyncMenuList = function AsyncMenuList(menuListProps) {
|
|
17682
|
+
var ctx = React__default["default"].useContext(MenuListContext);
|
|
17683
|
+
return React__default["default"].createElement(CustomList, _extends({}, menuListProps, ctx));
|
|
17684
|
+
};
|
|
17671
17685
|
/**
|
|
17672
17686
|
* A variation of select field that loads a dynamic list of options from a source rather than a fixed set of options. Use when you need to select from a dynamic list that can change such as roles, employees, locations, etc.
|
|
17673
|
-
* Instead of passing
|
|
17687
|
+
* Instead of passing an `options` prop, this component requires a `loadOptions` prop.
|
|
17688
|
+
* Supports scroll-to-load-more: when the user scrolls to the bottom of the menu and a `nextCursor` is returned, the next page is automatically fetched and appended.
|
|
17674
17689
|
* */
|
|
17675
17690
|
var AsyncSelectField = function AsyncSelectField(_ref) {
|
|
17676
17691
|
var loadOptions = _ref.loadOptions,
|
|
17677
17692
|
props = _objectWithoutPropertiesLoose(_ref, _excluded$b3);
|
|
17678
|
-
var _useState = React.useState(
|
|
17679
|
-
|
|
17680
|
-
|
|
17681
|
-
var _useState2 = React.useState(),
|
|
17682
|
-
|
|
17683
|
-
|
|
17693
|
+
var _useState = React.useState([]),
|
|
17694
|
+
displayedOptions = _useState[0],
|
|
17695
|
+
setDisplayedOptions = _useState[1];
|
|
17696
|
+
var _useState2 = React.useState(false),
|
|
17697
|
+
isLoading = _useState2[0],
|
|
17698
|
+
setIsLoading = _useState2[1];
|
|
17684
17699
|
var _useState3 = React.useState(false),
|
|
17685
|
-
|
|
17686
|
-
|
|
17687
|
-
var _useState4 = React.useState(
|
|
17688
|
-
|
|
17689
|
-
|
|
17690
|
-
var
|
|
17691
|
-
|
|
17692
|
-
|
|
17693
|
-
|
|
17694
|
-
|
|
17695
|
-
|
|
17696
|
-
|
|
17700
|
+
isLoadingMore = _useState3[0],
|
|
17701
|
+
setIsLoadingMore = _useState3[1];
|
|
17702
|
+
var _useState4 = React.useState(''),
|
|
17703
|
+
inputValue = _useState4[0],
|
|
17704
|
+
setInputValue = _useState4[1];
|
|
17705
|
+
var _useState5 = React.useState(false),
|
|
17706
|
+
hasMore = _useState5[0],
|
|
17707
|
+
setHasMore = _useState5[1];
|
|
17708
|
+
var _useState6 = React.useState(null),
|
|
17709
|
+
nextCursor = _useState6[0],
|
|
17710
|
+
setNextCursor = _useState6[1];
|
|
17711
|
+
var _useState7 = React.useState(null),
|
|
17712
|
+
localOptions = _useState7[0],
|
|
17713
|
+
setLocalOptions = _useState7[1];
|
|
17714
|
+
var _useState8 = React.useState(null),
|
|
17715
|
+
hasMoreOptionsFirstLoad = _useState8[0],
|
|
17716
|
+
setHasMoreOptionsFirstLoad = _useState8[1];
|
|
17717
|
+
var loadOptionsRef = React.useRef(loadOptions);
|
|
17718
|
+
React.useEffect(function () {
|
|
17719
|
+
loadOptionsRef.current = loadOptions;
|
|
17720
|
+
}, [loadOptions]);
|
|
17721
|
+
var fetchIdRef = React.useRef(0);
|
|
17722
|
+
var firstLoadDoneRef = React.useRef(false);
|
|
17723
|
+
// All dependencies are refs and stable state setters — safe with empty dep array.
|
|
17724
|
+
var fetchOptions = React.useCallback(function (input) {
|
|
17725
|
+
var id = ++fetchIdRef.current;
|
|
17726
|
+
setIsLoading(true);
|
|
17727
|
+
loadOptionsRef.current(input, null).then(function (_ref2) {
|
|
17728
|
+
var options = _ref2.options,
|
|
17729
|
+
more = _ref2.hasMore,
|
|
17730
|
+
resultCursor = _ref2.nextCursor;
|
|
17731
|
+
if (id !== fetchIdRef.current) return;
|
|
17732
|
+
if (!firstLoadDoneRef.current) {
|
|
17733
|
+
firstLoadDoneRef.current = true;
|
|
17734
|
+
setHasMoreOptionsFirstLoad(more && resultCursor == null);
|
|
17735
|
+
if (!more) setLocalOptions(options);
|
|
17736
|
+
}
|
|
17737
|
+
setDisplayedOptions(options);
|
|
17738
|
+
setHasMore(more);
|
|
17739
|
+
setNextCursor(resultCursor != null ? resultCursor : null);
|
|
17740
|
+
setIsLoading(false);
|
|
17741
|
+
})["catch"](function () {
|
|
17742
|
+
if (id !== fetchIdRef.current) return;
|
|
17743
|
+
setIsLoading(false);
|
|
17697
17744
|
});
|
|
17698
|
-
|
|
17699
|
-
|
|
17700
|
-
|
|
17701
|
-
|
|
17702
|
-
|
|
17703
|
-
|
|
17745
|
+
},
|
|
17746
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17747
|
+
[]);
|
|
17748
|
+
var debouncedFetchOptions = React.useMemo(function () {
|
|
17749
|
+
return lodashEs.debounce(fetchOptions, 500, {
|
|
17750
|
+
leading: true
|
|
17751
|
+
});
|
|
17752
|
+
}, [fetchOptions]);
|
|
17753
|
+
React.useEffect(function () {
|
|
17754
|
+
fetchOptions('');
|
|
17755
|
+
}, [fetchOptions]);
|
|
17756
|
+
var handleSearch = function handleSearch(value) {
|
|
17757
|
+
++fetchIdRef.current;
|
|
17758
|
+
setIsLoadingMore(false);
|
|
17704
17759
|
if (localOptions) {
|
|
17705
|
-
|
|
17760
|
+
var filtered = localOptions.filter(function (option) {
|
|
17761
|
+
return option.label.toLowerCase().includes(value.toLowerCase());
|
|
17762
|
+
});
|
|
17763
|
+
setDisplayedOptions(filtered);
|
|
17706
17764
|
return;
|
|
17707
17765
|
}
|
|
17708
|
-
|
|
17709
|
-
|
|
17710
|
-
|
|
17711
|
-
|
|
17712
|
-
|
|
17713
|
-
|
|
17714
|
-
|
|
17715
|
-
|
|
17716
|
-
|
|
17717
|
-
|
|
17718
|
-
|
|
17719
|
-
|
|
17720
|
-
|
|
17721
|
-
|
|
17722
|
-
|
|
17723
|
-
|
|
17724
|
-
|
|
17725
|
-
|
|
17766
|
+
setDisplayedOptions([]);
|
|
17767
|
+
setHasMore(false);
|
|
17768
|
+
setNextCursor(null);
|
|
17769
|
+
setIsLoading(true);
|
|
17770
|
+
debouncedFetchOptions(value);
|
|
17771
|
+
};
|
|
17772
|
+
var handleScrollToBottom = function handleScrollToBottom() {
|
|
17773
|
+
if (isLoadingMore || !hasMore || !nextCursor) return;
|
|
17774
|
+
// Capture the search generation so a concurrent query change can invalidate this response.
|
|
17775
|
+
var id = fetchIdRef.current;
|
|
17776
|
+
setIsLoadingMore(true);
|
|
17777
|
+
loadOptionsRef.current(inputValue, nextCursor).then(function (_ref3) {
|
|
17778
|
+
var options = _ref3.options,
|
|
17779
|
+
more = _ref3.hasMore,
|
|
17780
|
+
resultCursor = _ref3.nextCursor;
|
|
17781
|
+
if (id !== fetchIdRef.current) return;
|
|
17782
|
+
setDisplayedOptions(function (prev) {
|
|
17783
|
+
return [].concat(prev, options);
|
|
17784
|
+
});
|
|
17785
|
+
setHasMore(more);
|
|
17786
|
+
setNextCursor(resultCursor != null ? resultCursor : null);
|
|
17787
|
+
setIsLoadingMore(false);
|
|
17788
|
+
})["catch"](function () {
|
|
17789
|
+
if (id !== fetchIdRef.current) return;
|
|
17790
|
+
setIsLoadingMore(false);
|
|
17726
17791
|
});
|
|
17727
17792
|
};
|
|
17728
17793
|
var _useSelectField = useSelectField(_extends({}, props, {
|
|
@@ -17730,24 +17795,38 @@ var AsyncSelectField = function AsyncSelectField(_ref) {
|
|
|
17730
17795
|
})),
|
|
17731
17796
|
fieldProps = _useSelectField.fieldProps,
|
|
17732
17797
|
selectProps = _useSelectField.selectProps;
|
|
17733
|
-
|
|
17798
|
+
var menuListComponents = React.useMemo(function () {
|
|
17799
|
+
return _extends({}, selectProps.components, {
|
|
17800
|
+
MenuList: AsyncMenuList
|
|
17801
|
+
});
|
|
17802
|
+
},
|
|
17803
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17804
|
+
[selectProps.components]);
|
|
17805
|
+
return React__default["default"].createElement(MenuListContext.Provider, {
|
|
17806
|
+
value: {
|
|
17807
|
+
hasMoreOptions: hasMore && nextCursor === null,
|
|
17808
|
+
hasMoreOptionsFirstLoad: hasMoreOptionsFirstLoad,
|
|
17809
|
+
isLoadingMore: isLoadingMore
|
|
17810
|
+
}
|
|
17811
|
+
}, React__default["default"].createElement(Field, _extends({}, fieldProps), React__default["default"].createElement(AffixContainer, {
|
|
17734
17812
|
prefix: props.prefix
|
|
17735
|
-
}, React__default["default"].createElement(
|
|
17736
|
-
components:
|
|
17737
|
-
|
|
17738
|
-
|
|
17739
|
-
|
|
17740
|
-
|
|
17741
|
-
|
|
17813
|
+
}, React__default["default"].createElement(Select__default["default"], _extends({}, selectProps, {
|
|
17814
|
+
components: menuListComponents,
|
|
17815
|
+
options: displayedOptions,
|
|
17816
|
+
isLoading: isLoading,
|
|
17817
|
+
inputValue: inputValue,
|
|
17818
|
+
onInputChange: function onInputChange(value, _ref4) {
|
|
17819
|
+
var action = _ref4.action;
|
|
17820
|
+
if (action !== 'input-blur' && action !== 'menu-close') {
|
|
17821
|
+
setInputValue(value);
|
|
17742
17822
|
}
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
17748
|
-
|
|
17749
|
-
|
|
17750
|
-
}))));
|
|
17823
|
+
if (action === 'input-change') {
|
|
17824
|
+
handleSearch(value);
|
|
17825
|
+
}
|
|
17826
|
+
},
|
|
17827
|
+
onMenuScrollToBottom: handleScrollToBottom,
|
|
17828
|
+
filterOption: null
|
|
17829
|
+
})))));
|
|
17751
17830
|
};
|
|
17752
17831
|
|
|
17753
17832
|
var useDateFieldControllers = function useDateFieldControllers(_ref) {
|