ding-react-admin 2.2.0 → 2.2.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/dist/index.js +689 -653
- package/dist/src/components/AppHub.d.ts +3 -1
- package/dist/src/components/AppHub.d.ts.map +1 -1
- package/dist/src/crud/fields/ReferenceField.d.ts.map +1 -1
- package/dist/src/crud/fields/ReferenceManyField.d.ts.map +1 -1
- package/dist/src/crud/filters/ReferenceFilter.d.ts.map +1 -1
- package/dist/src/crud/utils/choiceSelectionUtils.d.ts +7 -0
- package/dist/src/crud/utils/choiceSelectionUtils.d.ts.map +1 -1
- package/dist/src/crud/utils/referenceSelectSelectedProps.d.ts +6 -0
- package/dist/src/crud/utils/referenceSelectSelectedProps.d.ts.map +1 -0
- package/dist/src/crud/utils/useChoices.d.ts +1 -0
- package/dist/src/crud/utils/useChoices.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/AppHub.tsx +10 -3
- package/src/crud/fields/ReferenceField.tsx +28 -18
- package/src/crud/fields/ReferenceManyField.tsx +15 -6
- package/src/crud/filters/ReferenceFilter.tsx +19 -4
- package/src/crud/utils/choiceSelectionUtils.test.ts +23 -0
- package/src/crud/utils/choiceSelectionUtils.ts +25 -0
- package/src/crud/utils/referenceSelectSelectedProps.ts +22 -0
- package/src/crud/utils/useChoices.ts +78 -19
|
@@ -10,6 +10,8 @@ export type AppHubProps = {
|
|
|
10
10
|
className?: string;
|
|
11
11
|
/** Max width of the centered hub content. Default `960`. */
|
|
12
12
|
maxWidth?: number;
|
|
13
|
+
/** When true, shows a centered spinner instead of the app grid. */
|
|
14
|
+
loading?: boolean;
|
|
13
15
|
};
|
|
14
|
-
export declare function AppHub({ apps, menuItems, onAppClick, onMenuClick, menuSearchPlaceholder, className, maxWidth, }: AppHubProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare function AppHub({ apps, menuItems, onAppClick, onMenuClick, menuSearchPlaceholder, className, maxWidth, loading, }: AppHubProps): import("react/jsx-runtime").JSX.Element;
|
|
15
17
|
//# sourceMappingURL=AppHub.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppHub.d.ts","sourceRoot":"","sources":["../../../src/components/AppHub.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGxC,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,MAAM,CAAC,EACrB,IAAI,EACJ,SAAS,EACT,UAAU,EACV,WAAW,EACX,qBAAmD,EACnD,SAAS,EACT,QAAc,
|
|
1
|
+
{"version":3,"file":"AppHub.d.ts","sourceRoot":"","sources":["../../../src/components/AppHub.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGxC,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,MAAM,CAAC,EACrB,IAAI,EACJ,SAAS,EACT,UAAU,EACV,WAAW,EACX,qBAAmD,EACnD,SAAS,EACT,QAAc,EACd,OAAe,GAChB,EAAE,WAAW,2CA+Gb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReferenceField.d.ts","sourceRoot":"","sources":["../../../../src/crud/fields/ReferenceField.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,cAAc,EACf,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"ReferenceField.d.ts","sourceRoot":"","sources":["../../../../src/crud/fields/ReferenceField.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,cAAc,EACf,MAAM,UAAU,CAAC;AAWlB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAC/C,cAAc,GAAG;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wDAAwD;IACxD,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,wEAAwE;IACxE,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,YAAY,GAAG,SAAS,EAChC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KACnB,IAAI,CAAC;IACV,4EAA4E;IAC5E,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,mEAAmE;IACnE,oBAAoB,CAAC,EAAE,mBAAmB,CAAC;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qBAAqB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAsIJ,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,IAAI,EACJ,KAAK,EACL,SAAS,EACT,OAAO,EACP,WAAoB,EACpB,WAAkB,EAClB,QAAQ,EACR,KAAK,EACL,MAAM,EACN,UAAU,EACV,QAAQ,EAAE,YAAY,EACtB,SAAS,EACT,UAAU,EACV,aAAa,EACb,IAAW,EACX,YAAY,EACZ,aAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EACnB,gBAAuB,EACvB,qBAAqB,EACrB,aAAa,GACd,EAAE,mBAAmB,2CA4CrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReferenceManyField.d.ts","sourceRoot":"","sources":["../../../../src/crud/fields/ReferenceManyField.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"ReferenceManyField.d.ts","sourceRoot":"","sources":["../../../../src/crud/fields/ReferenceManyField.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAW5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,uBAAuB,GAAG,eAAe,GACnD,cAAc,GAAG;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,oBAAoB,CAAC,EAAE,mBAAmB,CAAC;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qBAAqB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAuHJ,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,IAAI,EACJ,KAAK,EACL,SAAS,EACT,OAAO,EACP,WAAoB,EACpB,WAAkB,EAClB,QAAQ,EACR,KAAK,EACL,MAAM,EACN,UAAiB,EACjB,SAAS,EACT,QAAQ,EAAE,YAAY,EACtB,IAAW,EACX,YAAY,EACZ,aAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EACnB,gBAAuB,EACvB,qBAAqB,EACrB,aAAa,GACd,EAAE,uBAAuB,2CAyCzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReferenceFilter.d.ts","sourceRoot":"","sources":["../../../../src/crud/filters/ReferenceFilter.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"ReferenceFilter.d.ts","sourceRoot":"","sources":["../../../../src/crud/filters/ReferenceFilter.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAU9E,MAAM,MAAM,iBAAiB,GAAG,eAAe,GAAG;IAChD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA0BF,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,KAAK,EACL,OAAO,EACP,QAAQ,GACT,EAAE,iBAAiB,QA2BnB;AAED,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAChD,cAAc,GAAG;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAwEJ,wBAAgB,eAAe,CAAC,EAC9B,MAAM,EACN,KAAK,EACL,SAAS,EACT,OAAO,EACP,WAAoB,EACpB,WAAkB,EAClB,QAAQ,EACR,MAAM,EACN,IAAW,EACX,aAAoB,EACpB,qBAAqB,EACrB,aAAa,GACd,EAAE,oBAAoB,QAgDtB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,oBAAoB,2CAE9D"}
|
|
@@ -7,4 +7,11 @@ export declare function collectSelectedRecords(selectedValues: unknown | unknown
|
|
|
7
7
|
export declare function resolveOptionLabel(record: Record<string, unknown>, optionLabel: string | ((record: Record<string, unknown>) => string)): string;
|
|
8
8
|
export declare function recordsToOptions(records: Record<string, unknown>[], optionLabel: string | ((record: Record<string, unknown>) => string), optionValue: string): ChoiceOption[];
|
|
9
9
|
export declare function mergeOptions(existing: ChoiceOption[], incoming: ChoiceOption[]): ChoiceOption[];
|
|
10
|
+
/** Selected ids that do not yet have a matching option (label still unresolved). */
|
|
11
|
+
export declare function unresolvedSelectedIds(selectedIds: unknown[], knownOptions: ChoiceOption[]): unknown[];
|
|
12
|
+
/**
|
|
13
|
+
* Keep options for currently selected ids when replacing the dropdown list
|
|
14
|
+
* (e.g. closing a lazy select) so selected labels do not flash back to raw ids.
|
|
15
|
+
*/
|
|
16
|
+
export declare function keepSelectedOptions(previous: ChoiceOption[], selectedIds: unknown[], embeddedOptions?: ChoiceOption[]): ChoiceOption[];
|
|
10
17
|
//# sourceMappingURL=choiceSelectionUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"choiceSelectionUtils.d.ts","sourceRoot":"","sources":["../../../../src/crud/utils/choiceSelectionUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,MAAM,GAClB,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOlC;AAED,wBAAgB,SAAS,CACvB,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,MAAM,GAAG,SAAS,CAS7B;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,MAAM,GAClB,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAKrB;AAED,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,EAC/C,WAAW,EAAE,MAAM,GAClB,OAAO,EAAE,CAUX;AAED,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,EAC/C,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,SAAS,EAChF,WAAW,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CA4B3B;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,GAClE,MAAM,CAGR;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAClC,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,EACnE,WAAW,EAAE,MAAM,GAClB,YAAY,EAAE,CAMhB;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,YAAY,EAAE,EACxB,QAAQ,EAAE,YAAY,EAAE,GACvB,YAAY,EAAE,CAKhB"}
|
|
1
|
+
{"version":3,"file":"choiceSelectionUtils.d.ts","sourceRoot":"","sources":["../../../../src/crud/utils/choiceSelectionUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,MAAM,GAClB,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOlC;AAED,wBAAgB,SAAS,CACvB,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,MAAM,GAAG,SAAS,CAS7B;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,MAAM,GAClB,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAKrB;AAED,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,EAC/C,WAAW,EAAE,MAAM,GAClB,OAAO,EAAE,CAUX;AAED,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,OAAO,GAAG,OAAO,EAAE,GAAG,SAAS,EAC/C,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,SAAS,EAChF,WAAW,EAAE,MAAM,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CA4B3B;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,GAClE,MAAM,CAGR;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAClC,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,EACnE,WAAW,EAAE,MAAM,GAClB,YAAY,EAAE,CAMhB;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,YAAY,EAAE,EACxB,QAAQ,EAAE,YAAY,EAAE,GACvB,YAAY,EAAE,CAKhB;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,OAAO,EAAE,EACtB,YAAY,EAAE,YAAY,EAAE,GAC3B,OAAO,EAAE,CAIX;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EAAE,EACxB,WAAW,EAAE,OAAO,EAAE,EACtB,eAAe,GAAE,YAAY,EAAO,GACnC,YAAY,EAAE,CAKhB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SelectProps } from 'antd';
|
|
2
|
+
/** Select loading/disabled while selected labels resolve via getOne. */
|
|
3
|
+
export declare function referenceSelectSelectedProps(listLoading: boolean, selectedLoading: boolean, disabled?: boolean): Pick<SelectProps, "loading" | "disabled">;
|
|
4
|
+
/** Omit the raw id from the Select while the selected label is still loading. */
|
|
5
|
+
export declare function referenceSelectDisplayValue<T>(selectedLoading: boolean, value: T, empty: T): T;
|
|
6
|
+
//# sourceMappingURL=referenceSelectSelectedProps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"referenceSelectSelectedProps.d.ts","sourceRoot":"","sources":["../../../../src/crud/utils/referenceSelectSelectedProps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAExC,wEAAwE;AACxE,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,OAAO,EACpB,eAAe,EAAE,OAAO,EACxB,QAAQ,CAAC,EAAE,OAAO,GACjB,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,UAAU,CAAC,CAK3C;AAED,iFAAiF;AACjF,wBAAgB,2BAA2B,CAAC,CAAC,EAC3C,eAAe,EAAE,OAAO,EACxB,KAAK,EAAE,CAAC,EACR,KAAK,EAAE,CAAC,GACP,CAAC,CAEH"}
|
|
@@ -28,6 +28,7 @@ export type UseChoicesOptions = {
|
|
|
28
28
|
export declare function useChoices(loader: ChoicesLoader | undefined, reference: string | undefined, optionLabel?: string | ((record: Record<string, unknown>) => string), optionValue?: string, search?: string, hookOptions?: UseChoicesOptions): {
|
|
29
29
|
options: ChoiceOption[];
|
|
30
30
|
loading: boolean;
|
|
31
|
+
selectedLoading: boolean;
|
|
31
32
|
labelForValue: (value: unknown) => string;
|
|
32
33
|
labelsForValues: (values: unknown[]) => string;
|
|
33
34
|
optionForValue: (value: unknown) => ChoiceOption | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChoices.d.ts","sourceRoot":"","sources":["../../../../src/crud/utils/useChoices.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"useChoices.d.ts","sourceRoot":"","sources":["../../../../src/crud/utils/useChoices.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAc5D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iGAAiG;IACjG,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,mEAAmE;IACnE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;IACrC;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACtE;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAyEF,wBAAgB,UAAU,CACxB,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,GAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAU,EAC5E,WAAW,SAAO,EAClB,MAAM,CAAC,EAAE,MAAM,EACf,WAAW,GAAE,iBAAsB;;;;2BA6OzB,OAAO,KAAG,MAAM;8BAQf,OAAO,EAAE,KAAG,MAAM;4BAQnB,OAAO,KAAG,YAAY,GAAG,SAAS;;EAc7C"}
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Card, Col, List, Row, Space, Typography, theme } from "antd";
|
|
1
|
+
import { Card, Col, List, Row, Space, Spin, Typography, theme } from "antd";
|
|
2
2
|
import { useMemo, useState } from "react";
|
|
3
3
|
import { useNavigate } from "react-router-dom";
|
|
4
4
|
import {
|
|
@@ -19,6 +19,8 @@ export type AppHubProps = {
|
|
|
19
19
|
className?: string;
|
|
20
20
|
/** Max width of the centered hub content. Default `960`. */
|
|
21
21
|
maxWidth?: number;
|
|
22
|
+
/** When true, shows a centered spinner instead of the app grid. */
|
|
23
|
+
loading?: boolean;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export function AppHub({
|
|
@@ -29,6 +31,7 @@ export function AppHub({
|
|
|
29
31
|
menuSearchPlaceholder = "Search menus across apps…",
|
|
30
32
|
className,
|
|
31
33
|
maxWidth = 960,
|
|
34
|
+
loading = false,
|
|
32
35
|
}: AppHubProps) {
|
|
33
36
|
const navigate = useNavigate();
|
|
34
37
|
const { token } = theme.useToken();
|
|
@@ -70,7 +73,7 @@ export function AppHub({
|
|
|
70
73
|
paddingInline: token.paddingMD,
|
|
71
74
|
}}
|
|
72
75
|
>
|
|
73
|
-
{menuItems?.length ? (
|
|
76
|
+
{menuItems?.length && !loading ? (
|
|
74
77
|
<div style={{ maxWidth: 480, margin: "0 auto 24px" }}>
|
|
75
78
|
<NavMenuSearch
|
|
76
79
|
value={query}
|
|
@@ -81,7 +84,11 @@ export function AppHub({
|
|
|
81
84
|
</div>
|
|
82
85
|
) : null}
|
|
83
86
|
|
|
84
|
-
{
|
|
87
|
+
{loading ? (
|
|
88
|
+
<div style={{ display: "flex", justifyContent: "center", padding: token.paddingXL }}>
|
|
89
|
+
<Spin size="large" />
|
|
90
|
+
</div>
|
|
91
|
+
) : isSearching ? (
|
|
85
92
|
<List
|
|
86
93
|
bordered
|
|
87
94
|
dataSource={menuResults}
|
|
@@ -11,6 +11,10 @@ import type {
|
|
|
11
11
|
import { valueAsId, resolveOptionLabel } from "../utils/choiceSelectionUtils";
|
|
12
12
|
import { referenceSelectDropdownProps } from "../utils/referenceSelectDropdownProps";
|
|
13
13
|
import { referenceSelectNotFoundContent } from "../utils/referenceSelectNotFoundContent";
|
|
14
|
+
import {
|
|
15
|
+
referenceSelectDisplayValue,
|
|
16
|
+
referenceSelectSelectedProps,
|
|
17
|
+
} from "../utils/referenceSelectSelectedProps";
|
|
14
18
|
import { useChoices } from "../utils/useChoices";
|
|
15
19
|
import { FieldWrapper } from "./FieldWrapper";
|
|
16
20
|
import { ReferenceInputActions } from "./ReferenceInputActions";
|
|
@@ -88,19 +92,25 @@ function ReferenceFieldSelect({
|
|
|
88
92
|
const active = dropdownOpen || Boolean(searchText);
|
|
89
93
|
const selectValue = valueAsId(value, optionValue);
|
|
90
94
|
|
|
91
|
-
const { options, loading, optionForValue, reload } =
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
95
|
+
const { options, loading, selectedLoading, optionForValue, reload } =
|
|
96
|
+
useChoices(
|
|
97
|
+
choices,
|
|
98
|
+
reference,
|
|
99
|
+
optionLabel,
|
|
100
|
+
optionValue,
|
|
101
|
+
search ? searchText : undefined,
|
|
102
|
+
{
|
|
103
|
+
lazy,
|
|
104
|
+
active,
|
|
105
|
+
selectedValues: value,
|
|
106
|
+
selectedRecords,
|
|
107
|
+
fetchSelected,
|
|
108
|
+
},
|
|
109
|
+
);
|
|
110
|
+
const selectState = referenceSelectSelectedProps(
|
|
111
|
+
loading,
|
|
112
|
+
selectedLoading,
|
|
113
|
+
disabled,
|
|
104
114
|
);
|
|
105
115
|
|
|
106
116
|
const selectOptions = useMemo(
|
|
@@ -130,14 +140,14 @@ function ReferenceFieldSelect({
|
|
|
130
140
|
const select = (
|
|
131
141
|
<Select
|
|
132
142
|
{...referenceSelectDropdownProps({ popupMatchSelectWidth, popupMinWidth })}
|
|
133
|
-
value={selectValue}
|
|
143
|
+
value={referenceSelectDisplayValue(selectedLoading, selectValue, undefined)}
|
|
134
144
|
onChange={(next) => {
|
|
135
145
|
onChange(next);
|
|
136
146
|
onValueChange?.(next, optionForValue(next), { name: fieldName });
|
|
137
147
|
}}
|
|
138
148
|
options={selectOptions}
|
|
139
|
-
loading={loading}
|
|
140
|
-
notFoundContent={referenceSelectNotFoundContent(loading)}
|
|
149
|
+
loading={selectState.loading}
|
|
150
|
+
notFoundContent={referenceSelectNotFoundContent(selectState.loading)}
|
|
141
151
|
showSearch={search}
|
|
142
152
|
filterOption={search ? false : undefined}
|
|
143
153
|
onSearch={search ? setSearchText : undefined}
|
|
@@ -146,7 +156,7 @@ function ReferenceFieldSelect({
|
|
|
146
156
|
if (!open) setSearchText(undefined);
|
|
147
157
|
}}
|
|
148
158
|
allowClear={allowClear}
|
|
149
|
-
disabled={disabled}
|
|
159
|
+
disabled={selectState.disabled}
|
|
150
160
|
optionFilterProp="label"
|
|
151
161
|
style={{ width: "100%", minWidth: 160, ...inputStyle }}
|
|
152
162
|
/>
|
|
@@ -165,7 +175,7 @@ function ReferenceFieldSelect({
|
|
|
165
175
|
referenceDefaultValues={referenceDefaultValues}
|
|
166
176
|
referenceModalWidth={referenceModalWidth}
|
|
167
177
|
selectedId={selectValue}
|
|
168
|
-
disabled={disabled}
|
|
178
|
+
disabled={selectState.disabled}
|
|
169
179
|
onCreated={applyRecord}
|
|
170
180
|
onUpdated={() => void reload()}
|
|
171
181
|
/>
|
|
@@ -5,6 +5,10 @@ import type { BaseSourceProps, FieldRules, ReferenceProps } from "../types";
|
|
|
5
5
|
import { valuesAsIds } from "../utils/choiceSelectionUtils";
|
|
6
6
|
import { referenceSelectDropdownProps } from "../utils/referenceSelectDropdownProps";
|
|
7
7
|
import { referenceSelectNotFoundContent } from "../utils/referenceSelectNotFoundContent";
|
|
8
|
+
import {
|
|
9
|
+
referenceSelectDisplayValue,
|
|
10
|
+
referenceSelectSelectedProps,
|
|
11
|
+
} from "../utils/referenceSelectSelectedProps";
|
|
8
12
|
import { useChoices } from "../utils/useChoices";
|
|
9
13
|
import { FieldWrapper } from "./FieldWrapper";
|
|
10
14
|
import { ReferenceInputActions } from "./ReferenceInputActions";
|
|
@@ -68,7 +72,7 @@ function ReferenceManyFieldSelect({
|
|
|
68
72
|
const active = dropdownOpen || Boolean(searchText);
|
|
69
73
|
const selectValue = valuesAsIds(value, optionValue);
|
|
70
74
|
|
|
71
|
-
const { options, loading, reload } = useChoices(
|
|
75
|
+
const { options, loading, selectedLoading, reload } = useChoices(
|
|
72
76
|
choices,
|
|
73
77
|
reference,
|
|
74
78
|
optionLabel,
|
|
@@ -82,6 +86,11 @@ function ReferenceManyFieldSelect({
|
|
|
82
86
|
fetchSelected,
|
|
83
87
|
},
|
|
84
88
|
);
|
|
89
|
+
const selectState = referenceSelectSelectedProps(
|
|
90
|
+
loading,
|
|
91
|
+
selectedLoading,
|
|
92
|
+
disabled,
|
|
93
|
+
);
|
|
85
94
|
|
|
86
95
|
const selectOptions = useMemo(
|
|
87
96
|
() =>
|
|
@@ -96,11 +105,11 @@ function ReferenceManyFieldSelect({
|
|
|
96
105
|
<Select
|
|
97
106
|
{...referenceSelectDropdownProps({ popupMatchSelectWidth, popupMinWidth })}
|
|
98
107
|
mode="multiple"
|
|
99
|
-
value={selectValue}
|
|
108
|
+
value={referenceSelectDisplayValue(selectedLoading, selectValue, [])}
|
|
100
109
|
onChange={onChange}
|
|
101
110
|
options={selectOptions}
|
|
102
|
-
loading={loading}
|
|
103
|
-
notFoundContent={referenceSelectNotFoundContent(loading)}
|
|
111
|
+
loading={selectState.loading}
|
|
112
|
+
notFoundContent={referenceSelectNotFoundContent(selectState.loading)}
|
|
104
113
|
showSearch={search}
|
|
105
114
|
filterOption={search ? false : undefined}
|
|
106
115
|
onSearch={search ? setSearchText : undefined}
|
|
@@ -109,7 +118,7 @@ function ReferenceManyFieldSelect({
|
|
|
109
118
|
if (!open) setSearchText(undefined);
|
|
110
119
|
}}
|
|
111
120
|
allowClear={allowClear}
|
|
112
|
-
disabled={disabled}
|
|
121
|
+
disabled={selectState.disabled}
|
|
113
122
|
optionFilterProp="label"
|
|
114
123
|
style={{ width: "100%" }}
|
|
115
124
|
/>
|
|
@@ -127,7 +136,7 @@ function ReferenceManyFieldSelect({
|
|
|
127
136
|
referenceTitle={referenceTitle}
|
|
128
137
|
referenceDefaultValues={referenceDefaultValues}
|
|
129
138
|
referenceModalWidth={referenceModalWidth}
|
|
130
|
-
disabled={disabled}
|
|
139
|
+
disabled={selectState.disabled}
|
|
131
140
|
onCreated={(record) => {
|
|
132
141
|
const id = record[optionValue];
|
|
133
142
|
const current = Array.isArray(selectValue) ? selectValue : [];
|
|
@@ -5,6 +5,10 @@ import { useRegisterFilter } from "../context/FilterContext";
|
|
|
5
5
|
import { useChoices } from "../utils/useChoices";
|
|
6
6
|
import { referenceSelectDropdownProps } from "../utils/referenceSelectDropdownProps";
|
|
7
7
|
import { referenceSelectNotFoundContent } from "../utils/referenceSelectNotFoundContent";
|
|
8
|
+
import {
|
|
9
|
+
referenceSelectDisplayValue,
|
|
10
|
+
referenceSelectSelectedProps,
|
|
11
|
+
} from "../utils/referenceSelectSelectedProps";
|
|
8
12
|
|
|
9
13
|
export type SelectFilterProps = BaseSourceProps & {
|
|
10
14
|
choices: ChoiceOption[];
|
|
@@ -98,7 +102,7 @@ function ReferenceFilterInput({
|
|
|
98
102
|
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
99
103
|
const active = dropdownOpen || Boolean(searchText);
|
|
100
104
|
|
|
101
|
-
const { options, loading } = useChoices(
|
|
105
|
+
const { options, loading, selectedLoading } = useChoices(
|
|
102
106
|
choices,
|
|
103
107
|
reference,
|
|
104
108
|
optionLabel,
|
|
@@ -106,6 +110,12 @@ function ReferenceFilterInput({
|
|
|
106
110
|
search ? searchText : undefined,
|
|
107
111
|
{ lazy, active, selectedValues: value, fetchSelected },
|
|
108
112
|
);
|
|
113
|
+
const selectState = referenceSelectSelectedProps(loading, selectedLoading);
|
|
114
|
+
const selectValue = value as
|
|
115
|
+
| string
|
|
116
|
+
| number
|
|
117
|
+
| (string | number)[]
|
|
118
|
+
| undefined;
|
|
109
119
|
|
|
110
120
|
return (
|
|
111
121
|
<Select
|
|
@@ -113,14 +123,19 @@ function ReferenceFilterInput({
|
|
|
113
123
|
allowClear
|
|
114
124
|
mode={multiple ? "multiple" : undefined}
|
|
115
125
|
placeholder={label ?? source}
|
|
116
|
-
value={
|
|
126
|
+
value={referenceSelectDisplayValue(
|
|
127
|
+
selectedLoading,
|
|
128
|
+
selectValue,
|
|
129
|
+
(multiple ? [] : undefined) as typeof selectValue,
|
|
130
|
+
)}
|
|
117
131
|
onChange={onChange}
|
|
118
132
|
options={options.map((o) => ({
|
|
119
133
|
label: o.label,
|
|
120
134
|
value: o.value as string | number,
|
|
121
135
|
}))}
|
|
122
|
-
loading={loading}
|
|
123
|
-
|
|
136
|
+
loading={selectState.loading}
|
|
137
|
+
disabled={selectState.disabled}
|
|
138
|
+
notFoundContent={referenceSelectNotFoundContent(selectState.loading)}
|
|
124
139
|
showSearch={search}
|
|
125
140
|
filterOption={search ? false : undefined}
|
|
126
141
|
onSearch={search ? setSearchText : undefined}
|
|
@@ -2,8 +2,10 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
import {
|
|
3
3
|
collectSelectedRecords,
|
|
4
4
|
isRecordObject,
|
|
5
|
+
keepSelectedOptions,
|
|
5
6
|
normalizeSelectedIds,
|
|
6
7
|
recordsToOptions,
|
|
8
|
+
unresolvedSelectedIds,
|
|
7
9
|
valueAsId,
|
|
8
10
|
valuesAsIds,
|
|
9
11
|
} from "./choiceSelectionUtils";
|
|
@@ -42,4 +44,25 @@ describe("choiceSelectionUtils", () => {
|
|
|
42
44
|
},
|
|
43
45
|
]);
|
|
44
46
|
});
|
|
47
|
+
|
|
48
|
+
it("finds selected ids that do not yet have options", () => {
|
|
49
|
+
const options = [{ label: "One", value: "1" }];
|
|
50
|
+
expect(unresolvedSelectedIds(["1", "2"], [])).toEqual(["1", "2"]);
|
|
51
|
+
expect(unresolvedSelectedIds(["1", "2"], options)).toEqual(["2"]);
|
|
52
|
+
expect(unresolvedSelectedIds(["1"], options)).toEqual([]);
|
|
53
|
+
expect(unresolvedSelectedIds([], options)).toEqual([]);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("keeps selected options when replacing a lazy dropdown list", () => {
|
|
57
|
+
const previous = [
|
|
58
|
+
{ label: "One", value: "1" },
|
|
59
|
+
{ label: "Two", value: "2" },
|
|
60
|
+
];
|
|
61
|
+
const embedded = [{ label: "Embedded", value: "3" }];
|
|
62
|
+
expect(keepSelectedOptions(previous, ["2"], embedded)).toEqual([
|
|
63
|
+
{ label: "Embedded", value: "3" },
|
|
64
|
+
{ label: "Two", value: "2" },
|
|
65
|
+
]);
|
|
66
|
+
expect(keepSelectedOptions(previous, [], [])).toEqual([]);
|
|
67
|
+
});
|
|
45
68
|
});
|
|
@@ -114,3 +114,28 @@ export function mergeOptions(
|
|
|
114
114
|
for (const option of incoming) byValue.set(option.value, option);
|
|
115
115
|
return Array.from(byValue.values());
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
/** Selected ids that do not yet have a matching option (label still unresolved). */
|
|
119
|
+
export function unresolvedSelectedIds(
|
|
120
|
+
selectedIds: unknown[],
|
|
121
|
+
knownOptions: ChoiceOption[],
|
|
122
|
+
): unknown[] {
|
|
123
|
+
return selectedIds.filter(
|
|
124
|
+
(value) => !knownOptions.some((option) => option.value === value),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Keep options for currently selected ids when replacing the dropdown list
|
|
130
|
+
* (e.g. closing a lazy select) so selected labels do not flash back to raw ids.
|
|
131
|
+
*/
|
|
132
|
+
export function keepSelectedOptions(
|
|
133
|
+
previous: ChoiceOption[],
|
|
134
|
+
selectedIds: unknown[],
|
|
135
|
+
embeddedOptions: ChoiceOption[] = [],
|
|
136
|
+
): ChoiceOption[] {
|
|
137
|
+
const keep = previous.filter((option) =>
|
|
138
|
+
selectedIds.some((value) => option.value === value),
|
|
139
|
+
);
|
|
140
|
+
return mergeOptions(embeddedOptions, keep);
|
|
141
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SelectProps } from "antd";
|
|
2
|
+
|
|
3
|
+
/** Select loading/disabled while selected labels resolve via getOne. */
|
|
4
|
+
export function referenceSelectSelectedProps(
|
|
5
|
+
listLoading: boolean,
|
|
6
|
+
selectedLoading: boolean,
|
|
7
|
+
disabled?: boolean,
|
|
8
|
+
): Pick<SelectProps, "loading" | "disabled"> {
|
|
9
|
+
return {
|
|
10
|
+
loading: listLoading || selectedLoading,
|
|
11
|
+
disabled: Boolean(disabled || selectedLoading),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Omit the raw id from the Select while the selected label is still loading. */
|
|
16
|
+
export function referenceSelectDisplayValue<T>(
|
|
17
|
+
selectedLoading: boolean,
|
|
18
|
+
value: T,
|
|
19
|
+
empty: T,
|
|
20
|
+
): T {
|
|
21
|
+
return selectedLoading ? empty : value;
|
|
22
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { useDataProvider } from "../../context/DataProvider";
|
|
3
3
|
import type { Identifier } from "../../data/dataProviderTypes";
|
|
4
4
|
import type { ChoiceOption, ChoicesLoader } from "../types";
|
|
5
5
|
import {
|
|
6
6
|
collectSelectedRecords,
|
|
7
|
+
keepSelectedOptions,
|
|
7
8
|
mergeOptions,
|
|
8
9
|
normalizeSelectedIds,
|
|
9
10
|
recordsToOptions,
|
|
10
11
|
resolveOptionLabel,
|
|
12
|
+
unresolvedSelectedIds,
|
|
11
13
|
} from "./choiceSelectionUtils";
|
|
12
14
|
|
|
13
15
|
const choicesCache = new Map<string, ChoiceOption[]>();
|
|
@@ -174,6 +176,19 @@ export function useChoices(
|
|
|
174
176
|
return !choicesCache.has(cacheKey);
|
|
175
177
|
});
|
|
176
178
|
|
|
179
|
+
const [selectedLoading, setSelectedLoading] = useState(() =>
|
|
180
|
+
Boolean(
|
|
181
|
+
fetchSelected &&
|
|
182
|
+
reference &&
|
|
183
|
+
unresolvedSelectedIds(normalizedSelected, embeddedOptions).length,
|
|
184
|
+
),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const optionsRef = useRef(options);
|
|
188
|
+
optionsRef.current = options;
|
|
189
|
+
const normalizedSelectedRef = useRef(normalizedSelected);
|
|
190
|
+
normalizedSelectedRef.current = normalizedSelected;
|
|
191
|
+
|
|
177
192
|
useEffect(() => {
|
|
178
193
|
if (!embeddedOptions.length) return;
|
|
179
194
|
setOptions((prev) => mergeOptions(prev, embeddedOptions));
|
|
@@ -192,7 +207,16 @@ export function useChoices(
|
|
|
192
207
|
const key = loaderKey(effectiveLoader, search);
|
|
193
208
|
const cached = choicesCache.get(key);
|
|
194
209
|
if (cached && !search) {
|
|
195
|
-
setOptions(
|
|
210
|
+
setOptions((prev) =>
|
|
211
|
+
mergeOptions(
|
|
212
|
+
keepSelectedOptions(
|
|
213
|
+
prev,
|
|
214
|
+
normalizedSelectedRef.current,
|
|
215
|
+
embeddedOptions,
|
|
216
|
+
),
|
|
217
|
+
cached,
|
|
218
|
+
),
|
|
219
|
+
);
|
|
196
220
|
setLoading(false);
|
|
197
221
|
return;
|
|
198
222
|
}
|
|
@@ -200,7 +224,13 @@ export function useChoices(
|
|
|
200
224
|
|
|
201
225
|
setLoading(true);
|
|
202
226
|
if (lazy) {
|
|
203
|
-
setOptions(
|
|
227
|
+
setOptions((prev) =>
|
|
228
|
+
keepSelectedOptions(
|
|
229
|
+
prev,
|
|
230
|
+
normalizedSelectedRef.current,
|
|
231
|
+
embeddedOptions,
|
|
232
|
+
),
|
|
233
|
+
);
|
|
204
234
|
}
|
|
205
235
|
|
|
206
236
|
try {
|
|
@@ -212,12 +242,27 @@ export function useChoices(
|
|
|
212
242
|
search,
|
|
213
243
|
useCache,
|
|
214
244
|
);
|
|
215
|
-
setOptions(
|
|
245
|
+
setOptions((prev) =>
|
|
246
|
+
mergeOptions(
|
|
247
|
+
keepSelectedOptions(
|
|
248
|
+
prev,
|
|
249
|
+
normalizedSelectedRef.current,
|
|
250
|
+
embeddedOptions,
|
|
251
|
+
),
|
|
252
|
+
result,
|
|
253
|
+
),
|
|
254
|
+
);
|
|
216
255
|
} catch {
|
|
217
256
|
if (!normalizedSelected.length && !embeddedOptions.length) {
|
|
218
257
|
setOptions([]);
|
|
219
258
|
} else if (lazy) {
|
|
220
|
-
setOptions(
|
|
259
|
+
setOptions((prev) =>
|
|
260
|
+
keepSelectedOptions(
|
|
261
|
+
prev,
|
|
262
|
+
normalizedSelectedRef.current,
|
|
263
|
+
embeddedOptions,
|
|
264
|
+
),
|
|
265
|
+
);
|
|
221
266
|
}
|
|
222
267
|
} finally {
|
|
223
268
|
setLoading(false);
|
|
@@ -241,20 +286,30 @@ export function useChoices(
|
|
|
241
286
|
|
|
242
287
|
useEffect(() => {
|
|
243
288
|
if (lazy && !active && !search) {
|
|
244
|
-
setOptions(
|
|
289
|
+
setOptions((prev) =>
|
|
290
|
+
keepSelectedOptions(prev, normalizedSelected, embeddedOptions),
|
|
291
|
+
);
|
|
245
292
|
setLoading(false);
|
|
246
293
|
}
|
|
247
|
-
}, [lazy, active, search, embeddedOptions]);
|
|
294
|
+
}, [lazy, active, search, embeddedOptions, normalizedSelected]);
|
|
248
295
|
|
|
249
296
|
useEffect(() => {
|
|
250
|
-
if (!fetchSelected || !reference || !normalizedSelected.length)
|
|
297
|
+
if (!fetchSelected || !reference || !normalizedSelected.length) {
|
|
298
|
+
setSelectedLoading(false);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
251
301
|
|
|
252
|
-
const idsToFetch =
|
|
253
|
-
|
|
302
|
+
const idsToFetch = unresolvedSelectedIds(
|
|
303
|
+
normalizedSelected,
|
|
304
|
+
mergeOptions(embeddedOptions, optionsRef.current),
|
|
254
305
|
);
|
|
255
|
-
if (!idsToFetch.length)
|
|
306
|
+
if (!idsToFetch.length) {
|
|
307
|
+
setSelectedLoading(false);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
256
310
|
|
|
257
311
|
let cancelled = false;
|
|
312
|
+
setSelectedLoading(true);
|
|
258
313
|
|
|
259
314
|
void (async () => {
|
|
260
315
|
const resolved: ChoiceOption[] = [];
|
|
@@ -274,14 +329,17 @@ export function useChoices(
|
|
|
274
329
|
});
|
|
275
330
|
}
|
|
276
331
|
}
|
|
277
|
-
if (cancelled
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
332
|
+
if (cancelled) return;
|
|
333
|
+
|
|
334
|
+
if (resolved.length) {
|
|
335
|
+
setOptions((prev) => {
|
|
336
|
+
const missing = resolved.filter(
|
|
337
|
+
(option) => !prev.some((existing) => existing.value === option.value),
|
|
338
|
+
);
|
|
339
|
+
return missing.length ? mergeOptions(prev, missing) : prev;
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
setSelectedLoading(false);
|
|
285
343
|
})();
|
|
286
344
|
|
|
287
345
|
return () => {
|
|
@@ -322,6 +380,7 @@ export function useChoices(
|
|
|
322
380
|
return {
|
|
323
381
|
options,
|
|
324
382
|
loading,
|
|
383
|
+
selectedLoading,
|
|
325
384
|
labelForValue,
|
|
326
385
|
labelsForValues,
|
|
327
386
|
optionForValue,
|