@whatworks/payload-select-search-field 1.0.2 → 2.0.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/README.md CHANGED
@@ -28,20 +28,31 @@ import { selectSearch } from '@whatworks/payload-select-search-field'
28
28
  selectSearch({
29
29
  name: 'stripeCustomer',
30
30
  hasMany: true,
31
- passDataToSearchFunction: true,
32
- passSiblingDataToSearchFunction: true,
33
- searchFunction: async ({ query, selectedValues }) => {
34
- return [
35
- { value: 'cus_123', label: `Result for ${query}` },
36
- ...selectedValues.map((value) => ({
37
- value,
38
- label: `Selected: ${value}`,
39
- })),
40
- ]
31
+ search: {
32
+ debounce: {
33
+ query: 250,
34
+ watchedFields: 600,
35
+ },
36
+ passDataToSearchFunction: true,
37
+ passSiblingDataToSearchFunction: true,
38
+ watchFieldPaths: ['customerType', 'region'],
39
+ searchFunction: async ({ query, selectedValues }) => {
40
+ return [
41
+ { value: 'cus_123', label: `Result for ${query}` },
42
+ ...selectedValues.map((value) => ({
43
+ value,
44
+ label: `Selected: ${value}`,
45
+ })),
46
+ ]
47
+ },
41
48
  },
42
49
  })
43
50
  ```
44
51
 
52
+ `debounce` controls request timing:
53
+ - `query`: debounce in ms for search input typing.
54
+ - `watchedFields`: debounce in ms for `watchFieldPaths`-driven refetches.
55
+
45
56
  `searchFunction` receives:
46
57
  - `query`: the current input text.
47
58
  - `selectedValues`: an array of currently selected values (empty array when nothing is selected).
package/dist/endpoint.js CHANGED
@@ -10,9 +10,13 @@ const parseBody = async (req)=>{
10
10
  }
11
11
  return {};
12
12
  };
13
+ const parseData = (value)=>{
14
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
15
+ return value;
16
+ }
17
+ return undefined;
18
+ };
13
19
  export const selectSearchEndpointHandler = ()=>({
14
- method: 'post',
15
- path: selectSearchEndpoint,
16
20
  handler: async (req)=>{
17
21
  if (!req.user) {
18
22
  return Response.json({
@@ -24,14 +28,14 @@ export const selectSearchEndpointHandler = ()=>({
24
28
  let body;
25
29
  try {
26
30
  body = await parseBody(req);
27
- } catch (error) {
31
+ } catch {
28
32
  return Response.json({
29
33
  error: 'Invalid JSON body'
30
34
  }, {
31
35
  status: 400
32
36
  });
33
37
  }
34
- const { entityType, slug, schemaPath } = body;
38
+ const { slug, entityType, schemaPath } = body;
35
39
  if (entityType !== 'collection' && entityType !== 'global') {
36
40
  return Response.json({
37
41
  error: 'Invalid entityType'
@@ -48,6 +52,8 @@ export const selectSearchEndpointHandler = ()=>({
48
52
  }
49
53
  const safeQuery = String(body.query || '').slice(0, maxQueryLength);
50
54
  const selectedValues = Array.isArray(body.selectedValues) ? body.selectedValues.map((value)=>String(value)) : [];
55
+ const data = parseData(body.data);
56
+ const siblingData = parseData(body.siblingData);
51
57
  const config = req.payload.config;
52
58
  const entityConfig = entityType === 'collection' ? config.collections?.find((collection)=>collection.slug === slug) : config.globals?.find((global)=>global.slug === slug);
53
59
  if (!entityConfig) {
@@ -87,12 +93,14 @@ export const selectSearchEndpointHandler = ()=>({
87
93
  const collectionConfig = entityType === 'collection' ? entityConfig : undefined;
88
94
  const globalConfig = entityType === 'global' ? entityConfig : undefined;
89
95
  const options = await searchFunction({
90
- req,
96
+ collection: collectionConfig,
97
+ data,
98
+ field: fieldResult.field,
99
+ global: globalConfig,
91
100
  query: safeQuery,
101
+ req,
92
102
  selectedValues,
93
- field: fieldResult.field,
94
- collection: collectionConfig,
95
- global: globalConfig
103
+ siblingData
96
104
  });
97
105
  if (!Array.isArray(options)) {
98
106
  return Response.json({
@@ -105,7 +113,9 @@ export const selectSearchEndpointHandler = ()=>({
105
113
  options
106
114
  };
107
115
  return Response.json(res);
108
- }
116
+ },
117
+ method: 'post',
118
+ path: selectSearchEndpoint
109
119
  });
110
120
 
111
121
  //# sourceMappingURL=endpoint.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/endpoint.ts"],"sourcesContent":["import type {\n Endpoint,\n PayloadRequest,\n SanitizedCollectionConfig,\n SanitizedGlobalConfig,\n} from 'payload'\nimport { getFieldByPath } from 'payload'\nimport type { SelectSearchRequest, SelectSearchResponse, SelectSearchFunction } from './types.js'\nimport { selectSearchEndpoint } from './endpointName.js'\n\nconst maxQueryLength = 200\n\nconst parseBody = async (req: PayloadRequest): Promise<Partial<SelectSearchRequest>> => {\n if (typeof req.json === 'function') {\n return (await req.json()) as Partial<SelectSearchRequest>\n }\n\n if (req.body && typeof req.body === 'object') {\n return req.body as Partial<SelectSearchRequest>\n }\n\n return {}\n}\n\nexport const selectSearchEndpointHandler = (): Endpoint => ({\n method: 'post',\n path: selectSearchEndpoint,\n handler: async (req: PayloadRequest) => {\n if (!req.user) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n let body: Partial<SelectSearchRequest>\n try {\n body = await parseBody(req)\n } catch (error) {\n return Response.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n\n const { entityType, slug, schemaPath } = body\n if (entityType !== 'collection' && entityType !== 'global') {\n return Response.json({ error: 'Invalid entityType' }, { status: 400 })\n }\n\n if (!slug || !schemaPath) {\n return Response.json({ error: 'Missing slug or schemaPath' }, { status: 400 })\n }\n\n const safeQuery = String(body.query || '').slice(0, maxQueryLength)\n const selectedValues = Array.isArray(body.selectedValues)\n ? body.selectedValues.map((value) => String(value))\n : []\n\n const config = req.payload.config\n const entityConfig =\n entityType === 'collection'\n ? config.collections?.find((collection) => collection.slug === slug)\n : config.globals?.find((global) => global.slug === slug)\n\n if (!entityConfig) {\n return Response.json({ error: 'Unknown entity' }, { status: 404 })\n }\n\n const fields = entityConfig.flattenedFields\n if (!Array.isArray(fields)) {\n return Response.json({ error: 'Fields not searchable' }, { status: 400 })\n }\n\n const fieldResult = getFieldByPath({\n fields,\n path: schemaPath.split('.').slice(1).join('.'),\n })\n\n if (!fieldResult) {\n return Response.json({ error: 'Field not found' }, { status: 400 })\n }\n\n const searchFunction = fieldResult?.field?.custom?.searchFunction as\n | SelectSearchFunction\n | undefined\n\n if (typeof searchFunction !== 'function') {\n return Response.json({ error: 'Field not searchable' }, { status: 400 })\n }\n\n const collectionConfig =\n entityType === 'collection' ? (entityConfig as SanitizedCollectionConfig) : undefined\n const globalConfig =\n entityType === 'global' ? (entityConfig as SanitizedGlobalConfig) : undefined\n\n const options = await searchFunction({\n req,\n query: safeQuery,\n selectedValues,\n field: fieldResult.field,\n collection: collectionConfig,\n global: globalConfig,\n })\n\n if (!Array.isArray(options)) {\n return Response.json({ error: 'Invalid searchFunction response' }, { status: 500 })\n }\n\n const res: SelectSearchResponse = {\n options,\n }\n\n return Response.json(res)\n },\n})\n"],"names":["getFieldByPath","selectSearchEndpoint","maxQueryLength","parseBody","req","json","body","selectSearchEndpointHandler","method","path","handler","user","Response","error","status","entityType","slug","schemaPath","safeQuery","String","query","slice","selectedValues","Array","isArray","map","value","config","payload","entityConfig","collections","find","collection","globals","global","fields","flattenedFields","fieldResult","split","join","searchFunction","field","custom","collectionConfig","undefined","globalConfig","options","res"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/endpoint.ts"],"sourcesContent":["import type {\n Data,\n Endpoint,\n PayloadRequest,\n SanitizedCollectionConfig,\n SanitizedGlobalConfig,\n} from 'payload'\n\nimport { getFieldByPath } from 'payload'\n\nimport type { SelectSearchFunction, SelectSearchRequest, SelectSearchResponse } from './types.js'\n\nimport { selectSearchEndpoint } from './endpointName.js'\n\nconst maxQueryLength = 200\n\nconst parseBody = async (req: PayloadRequest): Promise<Partial<SelectSearchRequest>> => {\n if (typeof req.json === 'function') {\n return (await req.json()) as Partial<SelectSearchRequest>\n }\n\n if (req.body && typeof req.body === 'object') {\n return req.body as Partial<SelectSearchRequest>\n }\n\n return {}\n}\n\nconst parseData = (value: unknown): Data | undefined => {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n return value as Data\n }\n\n return undefined\n}\n\nexport const selectSearchEndpointHandler = (): Endpoint => ({\n handler: async (req: PayloadRequest) => {\n if (!req.user) {\n return Response.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n let body: Partial<SelectSearchRequest>\n try {\n body = await parseBody(req)\n } catch {\n return Response.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n\n const { slug, entityType, schemaPath } = body\n if (entityType !== 'collection' && entityType !== 'global') {\n return Response.json({ error: 'Invalid entityType' }, { status: 400 })\n }\n\n if (!slug || !schemaPath) {\n return Response.json({ error: 'Missing slug or schemaPath' }, { status: 400 })\n }\n\n const safeQuery = String(body.query || '').slice(0, maxQueryLength)\n const selectedValues = Array.isArray(body.selectedValues)\n ? body.selectedValues.map((value) => String(value))\n : []\n const data = parseData(body.data)\n const siblingData = parseData(body.siblingData)\n\n const config = req.payload.config\n const entityConfig =\n entityType === 'collection'\n ? config.collections?.find((collection) => collection.slug === slug)\n : config.globals?.find((global) => global.slug === slug)\n\n if (!entityConfig) {\n return Response.json({ error: 'Unknown entity' }, { status: 404 })\n }\n\n const fields = entityConfig.flattenedFields\n if (!Array.isArray(fields)) {\n return Response.json({ error: 'Fields not searchable' }, { status: 400 })\n }\n\n const fieldResult = getFieldByPath({\n fields,\n path: schemaPath.split('.').slice(1).join('.'),\n })\n\n if (!fieldResult) {\n return Response.json({ error: 'Field not found' }, { status: 400 })\n }\n\n const searchFunction = fieldResult?.field?.custom?.searchFunction as\n | SelectSearchFunction\n | undefined\n\n if (typeof searchFunction !== 'function') {\n return Response.json({ error: 'Field not searchable' }, { status: 400 })\n }\n\n const collectionConfig =\n entityType === 'collection' ? (entityConfig as SanitizedCollectionConfig) : undefined\n const globalConfig =\n entityType === 'global' ? (entityConfig as SanitizedGlobalConfig) : undefined\n\n const options = await searchFunction({\n collection: collectionConfig,\n data,\n field: fieldResult.field,\n global: globalConfig,\n query: safeQuery,\n req,\n selectedValues,\n siblingData,\n })\n\n if (!Array.isArray(options)) {\n return Response.json({ error: 'Invalid searchFunction response' }, { status: 500 })\n }\n\n const res: SelectSearchResponse = {\n options,\n }\n\n return Response.json(res)\n },\n method: 'post',\n path: selectSearchEndpoint,\n})\n"],"names":["getFieldByPath","selectSearchEndpoint","maxQueryLength","parseBody","req","json","body","parseData","value","Array","isArray","undefined","selectSearchEndpointHandler","handler","user","Response","error","status","slug","entityType","schemaPath","safeQuery","String","query","slice","selectedValues","map","data","siblingData","config","payload","entityConfig","collections","find","collection","globals","global","fields","flattenedFields","fieldResult","path","split","join","searchFunction","field","custom","collectionConfig","globalConfig","options","res","method"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { selectSearchEndpointHandler } from './endpoint.js';
2
2
  export { selectSearchEndpoint } from './endpointName.js';
3
3
  export { selectSearchPlugin as selectSearchPlugin } from './plugin.js';
4
+ export { selectSearch } from './selectSearchField.js';
4
5
  export { selectSearchField } from './selectSearchField.js';
5
6
  export type { SelectSearchFunction, SelectSearchFunctionArgs, SelectSearchOption, SelectSearchRequest, SelectSearchResponse, } from './types.js';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- export { selectSearchPlugin as selectSearchPlugin } from './plugin.js';
2
- export { selectSearchEndpoint } from './endpointName.js';
3
1
  export { selectSearchEndpointHandler } from './endpoint.js';
2
+ export { selectSearchEndpoint } from './endpointName.js';
3
+ export { selectSearchPlugin as selectSearchPlugin } from './plugin.js';
4
+ export { selectSearch } from './selectSearchField.js';
4
5
  export { selectSearchField } from './selectSearchField.js';
5
6
 
6
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { selectSearchPlugin as selectSearchPlugin } from './plugin.js'\nexport { selectSearchEndpoint } from './endpointName.js'\nexport { selectSearchEndpointHandler } from './endpoint.js'\nexport { selectSearchField } from './selectSearchField.js'\nexport type {\n SelectSearchFunction,\n SelectSearchFunctionArgs,\n SelectSearchOption,\n SelectSearchRequest,\n SelectSearchResponse,\n} from './types.js'\n"],"names":["selectSearchPlugin","selectSearchEndpoint","selectSearchEndpointHandler","selectSearchField"],"mappings":"AAAA,SAASA,sBAAsBA,kBAAkB,QAAQ,cAAa;AACtE,SAASC,oBAAoB,QAAQ,oBAAmB;AACxD,SAASC,2BAA2B,QAAQ,gBAAe;AAC3D,SAASC,iBAAiB,QAAQ,yBAAwB"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { selectSearchEndpointHandler } from './endpoint.js'\nexport { selectSearchEndpoint } from './endpointName.js'\nexport { selectSearchPlugin as selectSearchPlugin } from './plugin.js'\nexport { selectSearch } from './selectSearchField.js'\nexport { selectSearchField } from './selectSearchField.js'\nexport type {\n SelectSearchFunction,\n SelectSearchFunctionArgs,\n SelectSearchOption,\n SelectSearchRequest,\n SelectSearchResponse,\n} from './types.js'\n"],"names":["selectSearchEndpointHandler","selectSearchEndpoint","selectSearchPlugin","selectSearch","selectSearchField"],"mappings":"AAAA,SAASA,2BAA2B,QAAQ,gBAAe;AAC3D,SAASC,oBAAoB,QAAQ,oBAAmB;AACxD,SAASC,sBAAsBA,kBAAkB,QAAQ,cAAa;AACtE,SAASC,YAAY,QAAQ,yBAAwB;AACrD,SAASC,iBAAiB,QAAQ,yBAAwB"}
package/dist/plugin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { selectSearchEndpointHandler } from './endpoint.js';
2
2
  export const selectSearchPlugin = ()=>{
3
- return async (config)=>{
3
+ return (config)=>{
4
4
  config.endpoints = [
5
5
  ...config.endpoints || [],
6
6
  selectSearchEndpointHandler()
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Plugin } from 'payload'\nimport { selectSearchEndpointHandler } from './endpoint.js'\n\nexport const selectSearchPlugin = (): Plugin => {\n return async (config) => {\n config.endpoints = [...(config.endpoints || []), selectSearchEndpointHandler()]\n return config\n }\n}\n"],"names":["selectSearchEndpointHandler","selectSearchPlugin","config","endpoints"],"mappings":"AACA,SAASA,2BAA2B,QAAQ,gBAAe;AAE3D,OAAO,MAAMC,qBAAqB;IAChC,OAAO,OAAOC;QACZA,OAAOC,SAAS,GAAG;eAAKD,OAAOC,SAAS,IAAI,EAAE;YAAGH;SAA8B;QAC/E,OAAOE;IACT;AACF,EAAC"}
1
+ {"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Plugin } from 'payload'\n\nimport { selectSearchEndpointHandler } from './endpoint.js'\n\nexport const selectSearchPlugin = (): Plugin => {\n return (config) => {\n config.endpoints = [...(config.endpoints || []), selectSearchEndpointHandler()]\n return config\n }\n}\n"],"names":["selectSearchEndpointHandler","selectSearchPlugin","config","endpoints"],"mappings":"AAEA,SAASA,2BAA2B,QAAQ,gBAAe;AAE3D,OAAO,MAAMC,qBAAqB;IAChC,OAAO,CAACC;QACNA,OAAOC,SAAS,GAAG;eAAKD,OAAOC,SAAS,IAAI,EAAE;YAAGH;SAA8B;QAC/E,OAAOE;IACT;AACF,EAAC"}
@@ -1,11 +1,39 @@
1
1
  import type { Field, TextField } from 'payload';
2
2
  import type { SelectSearchFunction } from './types.js';
3
+ export type SelectSearchConfig = {
4
+ /** Debounce timings for client-side option refetching.
5
+ */
6
+ debounce?: SelectSearchDebounceConfig;
7
+ /** Send full form data to `searchFunction` as `data` on each request.
8
+ * @default false
9
+ */
10
+ passDataToSearchFunction?: boolean;
11
+ /** Send sibling field data to `searchFunction` as `siblingData` on each request.
12
+ * @default false
13
+ */
14
+ passSiblingDataToSearchFunction?: boolean;
15
+ searchFunction: SelectSearchFunction;
16
+ /** Re-fetch options when any of these field values change
17
+ * @default []
18
+ */
19
+ watchFieldPaths?: string[];
20
+ };
21
+ export type SelectSearchDebounceConfig = {
22
+ /** Debounce delay (ms) for query typing changes.
23
+ * @default 300
24
+ */
25
+ query?: number;
26
+ /** Debounce delay (ms) for watched field value changes.
27
+ * @default 700
28
+ */
29
+ watchedFields?: number;
30
+ };
3
31
  export type SelectSearchFieldArgs = {
4
32
  admin?: TextField['admin'];
5
33
  custom?: Record<string, unknown>;
6
34
  hasMany?: boolean;
7
- passDataToSearchFunction?: boolean;
8
- searchFunction: SelectSearchFunction;
35
+ search: SelectSearchConfig;
9
36
  type?: 'text';
10
37
  } & Omit<TextField, 'admin' | 'custom' | 'hasMany' | 'type'>;
38
+ export declare const selectSearch: (args: SelectSearchFieldArgs) => Field;
11
39
  export declare const selectSearchField: (args: SelectSearchFieldArgs) => Field;
@@ -1,20 +1,55 @@
1
- export const selectSearchField = (args)=>{
2
- const { searchFunction, ...rest } = args;
1
+ const normalizeWatchFieldPaths = (value)=>{
2
+ if (!Array.isArray(value)) {
3
+ return [];
4
+ }
5
+ const paths = value.map((entry)=>typeof entry === 'string' ? entry.trim() : '').filter(Boolean);
6
+ return Array.from(new Set(paths)).sort();
7
+ };
8
+ const normalizeDebounceMs = (value, fallback, key)=>{
9
+ if (value === undefined) {
10
+ return fallback;
11
+ }
12
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
13
+ throw new Error(`Invalid search.debounce.${key}: expected a finite number >= 0`);
14
+ }
15
+ return Math.floor(value);
16
+ };
17
+ export const selectSearch = (args)=>{
18
+ const { search, ...rest } = args;
19
+ const resolvedPassDataToSearchFunction = search.passDataToSearchFunction === true;
20
+ const resolvedPassSiblingDataToSearchFunction = search.passSiblingDataToSearchFunction === true;
21
+ const resolvedWatchFieldPaths = normalizeWatchFieldPaths(search.watchFieldPaths);
22
+ const resolvedQueryDebounceMs = normalizeDebounceMs(search.debounce?.query, 300, 'query');
23
+ const resolvedWatchedFieldsDebounceMs = normalizeDebounceMs(search.debounce?.watchedFields, 700, 'watchedFields');
3
24
  return {
4
25
  ...rest,
5
26
  type: 'text',
6
- custom: {
7
- ...args.custom,
8
- searchFunction: args.searchFunction
9
- },
10
27
  admin: {
11
28
  ...args.admin,
12
29
  components: {
13
30
  ...args.admin?.components,
14
- Field: args.admin?.components?.Field ?? '@whatworks/payload-select-search-field/client#SelectSearchField'
31
+ Field: {
32
+ clientProps: {
33
+ debounce: {
34
+ query: resolvedQueryDebounceMs,
35
+ watchedFields: resolvedWatchedFieldsDebounceMs
36
+ },
37
+ passDataToSearchFunction: resolvedPassDataToSearchFunction,
38
+ passSiblingDataToSearchFunction: resolvedPassSiblingDataToSearchFunction,
39
+ watchFieldPaths: resolvedWatchFieldPaths
40
+ },
41
+ path: '@whatworks/payload-select-search-field/client#SelectSearchField'
42
+ }
15
43
  }
44
+ },
45
+ custom: {
46
+ ...args.custom,
47
+ searchFunction: search.searchFunction
16
48
  }
17
49
  };
18
50
  };
51
+ export const selectSearchField = (args)=>{
52
+ return selectSearch(args);
53
+ };
19
54
 
20
55
  //# sourceMappingURL=selectSearchField.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/selectSearchField.ts"],"sourcesContent":["import type { Field, TextField } from 'payload'\nimport type { SelectSearchFunction } from './types.js'\n\nexport type SelectSearchFieldArgs = Omit<TextField, 'admin' | 'custom' | 'type' | 'hasMany'> & {\n hasMany?: boolean\n type?: 'text'\n searchFunction: SelectSearchFunction\n custom?: Record<string, unknown>\n admin?: TextField['admin']\n}\n\nexport const selectSearchField = (args: SelectSearchFieldArgs): Field => {\n const { searchFunction, ...rest } = args\n return {\n ...rest,\n type: 'text',\n custom: {\n ...args.custom,\n searchFunction: args.searchFunction,\n },\n admin: {\n ...args.admin,\n components: {\n ...args.admin?.components,\n Field:\n args.admin?.components?.Field ??\n '@whatworks/payload-select-search-field/client#SelectSearchField',\n },\n },\n } as Field\n}\n"],"names":["selectSearchField","args","searchFunction","rest","type","custom","admin","components","Field"],"mappings":"AAWA,OAAO,MAAMA,oBAAoB,CAACC;IAChC,MAAM,EAAEC,cAAc,EAAE,GAAGC,MAAM,GAAGF;IACpC,OAAO;QACL,GAAGE,IAAI;QACPC,MAAM;QACNC,QAAQ;YACN,GAAGJ,KAAKI,MAAM;YACdH,gBAAgBD,KAAKC,cAAc;QACrC;QACAI,OAAO;YACL,GAAGL,KAAKK,KAAK;YACbC,YAAY;gBACV,GAAGN,KAAKK,KAAK,EAAEC,UAAU;gBACzBC,OACEP,KAAKK,KAAK,EAAEC,YAAYC,SACxB;YACJ;QACF;IACF;AACF,EAAC"}
1
+ {"version":3,"sources":["../src/selectSearchField.ts"],"sourcesContent":["import type { Field, TextField } from 'payload'\n\nimport type { SelectSearchFunction } from './types.js'\n\nexport type SelectSearchConfig = {\n /** Debounce timings for client-side option refetching.\n */\n debounce?: SelectSearchDebounceConfig\n /** Send full form data to `searchFunction` as `data` on each request.\n * @default false\n */\n passDataToSearchFunction?: boolean\n /** Send sibling field data to `searchFunction` as `siblingData` on each request.\n * @default false\n */\n passSiblingDataToSearchFunction?: boolean\n searchFunction: SelectSearchFunction\n /** Re-fetch options when any of these field values change\n * @default []\n */\n watchFieldPaths?: string[]\n}\n\nexport type SelectSearchDebounceConfig = {\n /** Debounce delay (ms) for query typing changes.\n * @default 300\n */\n query?: number\n /** Debounce delay (ms) for watched field value changes.\n * @default 700\n */\n watchedFields?: number\n}\n\nexport type SelectSearchFieldArgs = {\n admin?: TextField['admin']\n custom?: Record<string, unknown>\n hasMany?: boolean\n search: SelectSearchConfig\n type?: 'text'\n} & Omit<TextField, 'admin' | 'custom' | 'hasMany' | 'type'>\n\nconst normalizeWatchFieldPaths = (value: unknown): string[] => {\n if (!Array.isArray(value)) {\n return []\n }\n\n const paths = value\n .map((entry) => (typeof entry === 'string' ? entry.trim() : ''))\n .filter(Boolean)\n\n return Array.from(new Set(paths)).sort()\n}\n\nconst normalizeDebounceMs = (\n value: unknown,\n fallback: number,\n key: 'query' | 'watchedFields',\n): number => {\n if (value === undefined) {\n return fallback\n }\n\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw new Error(`Invalid search.debounce.${key}: expected a finite number >= 0`)\n }\n\n return Math.floor(value)\n}\n\nexport const selectSearch = (args: SelectSearchFieldArgs): Field => {\n const { search, ...rest } = args\n\n const resolvedPassDataToSearchFunction = search.passDataToSearchFunction === true\n const resolvedPassSiblingDataToSearchFunction = search.passSiblingDataToSearchFunction === true\n const resolvedWatchFieldPaths = normalizeWatchFieldPaths(search.watchFieldPaths)\n const resolvedQueryDebounceMs = normalizeDebounceMs(search.debounce?.query, 300, 'query')\n const resolvedWatchedFieldsDebounceMs = normalizeDebounceMs(\n search.debounce?.watchedFields,\n 700,\n 'watchedFields',\n )\n\n return {\n ...rest,\n type: 'text',\n admin: {\n ...args.admin,\n components: {\n ...args.admin?.components,\n Field: {\n clientProps: {\n debounce: {\n query: resolvedQueryDebounceMs,\n watchedFields: resolvedWatchedFieldsDebounceMs,\n },\n passDataToSearchFunction: resolvedPassDataToSearchFunction,\n passSiblingDataToSearchFunction: resolvedPassSiblingDataToSearchFunction,\n watchFieldPaths: resolvedWatchFieldPaths,\n },\n path: '@whatworks/payload-select-search-field/client#SelectSearchField',\n },\n },\n },\n custom: {\n ...args.custom,\n searchFunction: search.searchFunction,\n },\n } as Field\n}\n\nexport const selectSearchField = (args: SelectSearchFieldArgs): Field => {\n return selectSearch(args)\n}\n"],"names":["normalizeWatchFieldPaths","value","Array","isArray","paths","map","entry","trim","filter","Boolean","from","Set","sort","normalizeDebounceMs","fallback","key","undefined","Number","isFinite","Error","Math","floor","selectSearch","args","search","rest","resolvedPassDataToSearchFunction","passDataToSearchFunction","resolvedPassSiblingDataToSearchFunction","passSiblingDataToSearchFunction","resolvedWatchFieldPaths","watchFieldPaths","resolvedQueryDebounceMs","debounce","query","resolvedWatchedFieldsDebounceMs","watchedFields","type","admin","components","Field","clientProps","path","custom","searchFunction","selectSearchField"],"mappings":"AA0CA,MAAMA,2BAA2B,CAACC;IAChC,IAAI,CAACC,MAAMC,OAAO,CAACF,QAAQ;QACzB,OAAO,EAAE;IACX;IAEA,MAAMG,QAAQH,MACXI,GAAG,CAAC,CAACC,QAAW,OAAOA,UAAU,WAAWA,MAAMC,IAAI,KAAK,IAC3DC,MAAM,CAACC;IAEV,OAAOP,MAAMQ,IAAI,CAAC,IAAIC,IAAIP,QAAQQ,IAAI;AACxC;AAEA,MAAMC,sBAAsB,CAC1BZ,OACAa,UACAC;IAEA,IAAId,UAAUe,WAAW;QACvB,OAAOF;IACT;IAEA,IAAI,OAAOb,UAAU,YAAY,CAACgB,OAAOC,QAAQ,CAACjB,UAAUA,QAAQ,GAAG;QACrE,MAAM,IAAIkB,MAAM,CAAC,wBAAwB,EAAEJ,IAAI,+BAA+B,CAAC;IACjF;IAEA,OAAOK,KAAKC,KAAK,CAACpB;AACpB;AAEA,OAAO,MAAMqB,eAAe,CAACC;IAC3B,MAAM,EAAEC,MAAM,EAAE,GAAGC,MAAM,GAAGF;IAE5B,MAAMG,mCAAmCF,OAAOG,wBAAwB,KAAK;IAC7E,MAAMC,0CAA0CJ,OAAOK,+BAA+B,KAAK;IAC3F,MAAMC,0BAA0B9B,yBAAyBwB,OAAOO,eAAe;IAC/E,MAAMC,0BAA0BnB,oBAAoBW,OAAOS,QAAQ,EAAEC,OAAO,KAAK;IACjF,MAAMC,kCAAkCtB,oBACtCW,OAAOS,QAAQ,EAAEG,eACjB,KACA;IAGF,OAAO;QACL,GAAGX,IAAI;QACPY,MAAM;QACNC,OAAO;YACL,GAAGf,KAAKe,KAAK;YACbC,YAAY;gBACV,GAAGhB,KAAKe,KAAK,EAAEC,UAAU;gBACzBC,OAAO;oBACLC,aAAa;wBACXR,UAAU;4BACRC,OAAOF;4BACPI,eAAeD;wBACjB;wBACAR,0BAA0BD;wBAC1BG,iCAAiCD;wBACjCG,iBAAiBD;oBACnB;oBACAY,MAAM;gBACR;YACF;QACF;QACAC,QAAQ;YACN,GAAGpB,KAAKoB,MAAM;YACdC,gBAAgBpB,OAAOoB,cAAc;QACvC;IACF;AACF,EAAC;AAED,OAAO,MAAMC,oBAAoB,CAACtB;IAChC,OAAOD,aAAaC;AACtB,EAAC"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n FlattenedField,\n PayloadRequest,\n SanitizedCollectionConfig,\n SanitizedGlobalConfig,\n} from 'payload'\n\nexport type SelectSearchOption = {\n label: string\n value: string\n [key: string]: unknown\n}\n\nexport type SelectSearchFunctionArgs = {\n req: PayloadRequest\n query: string\n selectedValues: string[]\n field: FlattenedField\n collection?: SanitizedCollectionConfig\n global?: SanitizedGlobalConfig\n}\n\nexport type SelectSearchFunction = (\n args: SelectSearchFunctionArgs,\n) => Promise<SelectSearchOption[]> | SelectSearchOption[]\n\nexport type SelectSearchRequest = {\n entityType: 'collection' | 'global'\n slug: string\n schemaPath: string\n query?: string\n selectedValues?: string[]\n}\n\nexport type SelectSearchResponse = {\n options: SelectSearchOption[]\n}\n"],"names":[],"mappings":"AAkCA,WAEC"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n Data,\n FlattenedField,\n PayloadRequest,\n SanitizedCollectionConfig,\n SanitizedGlobalConfig,\n} from 'payload'\n\nexport type SelectSearchOption = {\n [key: string]: unknown\n label: string\n value: string\n}\n\nexport type SelectSearchFunctionArgs = {\n collection?: SanitizedCollectionConfig\n data?: Data\n field: FlattenedField\n global?: SanitizedGlobalConfig\n query: string\n req: PayloadRequest\n selectedValues: string[]\n siblingData?: Data\n}\n\nexport type SelectSearchFunction = (\n args: SelectSearchFunctionArgs,\n) => Promise<SelectSearchOption[]> | SelectSearchOption[]\n\nexport type SelectSearchRequest = {\n data?: Data\n entityType: 'collection' | 'global'\n query?: string\n schemaPath: string\n selectedValues?: string[]\n siblingData?: Data\n slug: string\n}\n\nexport type SelectSearchResponse = {\n options: SelectSearchOption[]\n}\n"],"names":[],"mappings":"AAuCA,WAEC"}
@@ -1,24 +1,42 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { SelectInput, useConfig, useDocumentInfo, useField } from '@payloadcms/ui';
3
+ import { SelectInput, useConfig, useDocumentInfo, useField, useForm, useFormFields } from '@payloadcms/ui';
4
4
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
5
  import { selectSearchEndpoint } from '../endpointName.js';
6
- const debounceMs = 300;
6
+ const defaultQueryDebounceMs = 300;
7
+ const defaultWatchedFieldsDebounceMs = 700;
8
+ const serializeRefetchValue = (value)=>{
9
+ try {
10
+ return JSON.stringify(value) ?? '';
11
+ } catch {
12
+ return '';
13
+ }
14
+ };
7
15
  export const SelectSearchField = (props)=>{
8
16
  const { field, path, schemaPath: schemaPathProp } = props;
9
- const { value, setValue, showError } = useField({
17
+ const { setValue, showError, value } = useField({
10
18
  path
11
19
  });
12
20
  const { collectionSlug, globalSlug } = useDocumentInfo();
13
21
  const { config } = useConfig();
22
+ const { getData, getSiblingData } = useForm();
14
23
  const [options, setOptions] = useState([]);
15
24
  const [inputValue, setInputValue] = useState('');
16
25
  const [remoteError, setRemoteError] = useState(null);
17
26
  const abortRef = useRef(null);
27
+ const fetchOptionsRef = useRef(null);
28
+ const latestInputValueRef = useRef('');
29
+ const hasInitializedWatchedFieldsEffectRef = useRef(false);
18
30
  const entityType = globalSlug ? 'global' : 'collection';
19
31
  const slug = globalSlug || collectionSlug;
20
32
  const schemaPath = schemaPathProp ?? field.name;
21
33
  const hasMany = field.hasMany ?? false;
34
+ const passDataToSearchFunction = props.passDataToSearchFunction === true;
35
+ const passSiblingDataToSearchFunction = props.passSiblingDataToSearchFunction === true;
36
+ // `selectSearch` normalizes these values before passing to `clientProps`.
37
+ const queryDebounceMs = props.debounce?.query ?? defaultQueryDebounceMs;
38
+ const watchedFieldsDebounceMs = props.debounce?.watchedFields ?? defaultWatchedFieldsDebounceMs;
39
+ const watchFieldPaths = props.watchFieldPaths ?? [];
22
40
  const apiPath = config.routes?.api || '/api';
23
41
  const apiRoute = apiPath.startsWith('/') ? apiPath : `/${apiPath}`;
24
42
  const baseURL = config.serverURL || '';
@@ -37,6 +55,22 @@ export const SelectSearchField = (props)=>{
37
55
  hasMany,
38
56
  value
39
57
  ]);
58
+ const watchedFieldPathsRefetchToken = useFormFields(([fields])=>{
59
+ if (watchFieldPaths.length === 0) {
60
+ return '';
61
+ }
62
+ const watchedPathValues = [];
63
+ for (const watchPath of watchFieldPaths){
64
+ if (!Object.prototype.hasOwnProperty.call(fields, watchPath)) {
65
+ continue;
66
+ }
67
+ watchedPathValues.push([
68
+ watchPath,
69
+ fields[watchPath]?.value
70
+ ]);
71
+ }
72
+ return serializeRefetchValue(watchedPathValues);
73
+ });
40
74
  const fetchOptions = useCallback(async (query)=>{
41
75
  if (!slug || !schemaPath) {
42
76
  setOptions([]);
@@ -48,20 +82,27 @@ export const SelectSearchField = (props)=>{
48
82
  const controller = new AbortController();
49
83
  abortRef.current = controller;
50
84
  setRemoteError(null);
85
+ const payload = {
86
+ slug,
87
+ entityType,
88
+ query,
89
+ schemaPath,
90
+ selectedValues
91
+ };
92
+ if (passDataToSearchFunction) {
93
+ payload.data = getData();
94
+ }
95
+ if (passSiblingDataToSearchFunction) {
96
+ payload.siblingData = getSiblingData(path);
97
+ }
51
98
  const res = await fetch(endpointURL, {
52
- method: 'POST',
99
+ body: JSON.stringify(payload),
100
+ credentials: 'include',
53
101
  headers: {
54
102
  'Content-Type': 'application/json'
55
103
  },
56
- credentials: 'include',
57
- signal: controller.signal,
58
- body: JSON.stringify({
59
- entityType,
60
- slug,
61
- schemaPath,
62
- query,
63
- selectedValues
64
- })
104
+ method: 'POST',
105
+ signal: controller.signal
65
106
  });
66
107
  if (!res.ok) {
67
108
  const errorBody = await res.json().catch(()=>null);
@@ -75,26 +116,64 @@ export const SelectSearchField = (props)=>{
75
116
  }, [
76
117
  endpointURL,
77
118
  entityType,
119
+ getData,
120
+ getSiblingData,
121
+ passDataToSearchFunction,
122
+ passSiblingDataToSearchFunction,
123
+ path,
78
124
  schemaPath,
79
125
  selectedValues,
80
126
  slug
81
127
  ]);
128
+ useEffect(()=>{
129
+ fetchOptionsRef.current = fetchOptions;
130
+ }, [
131
+ fetchOptions
132
+ ]);
133
+ useEffect(()=>{
134
+ latestInputValueRef.current = inputValue;
135
+ }, [
136
+ inputValue
137
+ ]);
82
138
  useEffect(()=>{
83
139
  if (!slug || !schemaPath) {
84
140
  return;
85
141
  }
142
+ // Query typing should feel responsive, so use a shorter debounce.
86
143
  const timeout = setTimeout(()=>{
87
- void fetchOptions(inputValue);
88
- }, debounceMs);
144
+ void fetchOptionsRef.current?.(inputValue);
145
+ }, queryDebounceMs);
89
146
  return ()=>{
90
147
  clearTimeout(timeout);
91
148
  };
92
149
  }, [
93
- fetchOptions,
94
150
  inputValue,
151
+ queryDebounceMs,
95
152
  schemaPath,
96
153
  slug
97
154
  ]);
155
+ useEffect(()=>{
156
+ if (!slug || !schemaPath || watchFieldPaths.length === 0) {
157
+ return;
158
+ }
159
+ if (!hasInitializedWatchedFieldsEffectRef.current) {
160
+ hasInitializedWatchedFieldsEffectRef.current = true;
161
+ return;
162
+ }
163
+ // Watched field changes can happen in bursts, so use a longer debounce.
164
+ const timeout = setTimeout(()=>{
165
+ void fetchOptionsRef.current?.(latestInputValueRef.current);
166
+ }, watchedFieldsDebounceMs);
167
+ return ()=>{
168
+ clearTimeout(timeout);
169
+ };
170
+ }, [
171
+ schemaPath,
172
+ slug,
173
+ watchFieldPaths.length,
174
+ watchedFieldsDebounceMs,
175
+ watchedFieldPathsRefetchToken
176
+ ]);
98
177
  useEffect(()=>{
99
178
  return ()=>{
100
179
  if (abortRef.current) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/SelectSearchField.tsx"],"sourcesContent":["'use client'\n\nimport type { OptionObject, TextFieldClientComponent } from 'payload'\nimport type { ReactSelectOption } from '@payloadcms/ui'\nimport { SelectInput, useConfig, useDocumentInfo, useField } from '@payloadcms/ui'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { selectSearchEndpoint } from '../endpointName.js'\n\nconst debounceMs = 300\n\nexport const SelectSearchField: TextFieldClientComponent = (props) => {\n const { field, path, schemaPath: schemaPathProp } = props\n\n const { value, setValue, showError } = useField<string | string[]>({\n path,\n })\n\n const { collectionSlug, globalSlug } = useDocumentInfo()\n const { config } = useConfig()\n\n const [options, setOptions] = useState<OptionObject[]>([])\n\n const [inputValue, setInputValue] = useState('')\n const [remoteError, setRemoteError] = useState<string | null>(null)\n\n const abortRef = useRef<AbortController | null>(null)\n\n const entityType = globalSlug ? 'global' : 'collection'\n const slug = globalSlug || collectionSlug\n\n const schemaPath = schemaPathProp ?? field.name\n const hasMany = field.hasMany ?? false\n\n const apiPath = config.routes?.api || '/api'\n const apiRoute = apiPath.startsWith('/') ? apiPath : `/${apiPath}`\n const baseURL = config.serverURL || ''\n const endpointURL = `${baseURL}${apiRoute}${selectSearchEndpoint}`\n\n const selectedValues = useMemo(() => {\n if (hasMany) {\n return Array.isArray(value) ? value.map((entry) => String(entry)) : []\n }\n\n if (Array.isArray(value) || value === null || value === undefined) {\n return []\n }\n\n return [String(value)]\n }, [hasMany, value])\n\n const fetchOptions = useCallback(\n async (query: string) => {\n if (!slug || !schemaPath) {\n setOptions([])\n return\n }\n\n if (abortRef.current) {\n abortRef.current.abort()\n }\n\n const controller = new AbortController()\n abortRef.current = controller\n\n setRemoteError(null)\n\n const res = await fetch(endpointURL, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: 'include',\n signal: controller.signal,\n body: JSON.stringify({\n entityType,\n slug,\n schemaPath,\n query,\n selectedValues,\n }),\n })\n\n if (!res.ok) {\n const errorBody = await res.json().catch(() => null)\n const message = errorBody?.error || 'Failed to fetch options'\n setRemoteError(message)\n setOptions([])\n return\n }\n\n const data = (await res.json()) as { options?: OptionObject[] }\n setOptions(Array.isArray(data.options) ? data.options : [])\n },\n [endpointURL, entityType, schemaPath, selectedValues, slug],\n )\n\n useEffect(() => {\n if (!slug || !schemaPath) {\n return\n }\n\n const timeout = setTimeout(() => {\n void fetchOptions(inputValue)\n }, debounceMs)\n\n return () => {\n clearTimeout(timeout)\n }\n }, [fetchOptions, inputValue, schemaPath, slug])\n\n useEffect(() => {\n return () => {\n if (abortRef.current) {\n abortRef.current.abort()\n }\n }\n }, [])\n\n const handleChange = useCallback(\n (option: ReactSelectOption | ReactSelectOption[] | null) => {\n if (Array.isArray(option)) {\n const values = option.map((entry) => String(entry.value))\n setValue(values)\n return\n }\n\n if (!option) {\n setValue(hasMany ? [] : null)\n return\n }\n\n setValue(String(option.value))\n },\n [hasMany, setValue],\n )\n\n const description = useMemo(() => {\n if (remoteError) {\n return remoteError\n }\n\n return field.admin?.description\n }, [field.admin?.description, remoteError])\n\n const selectValue = useMemo(() => {\n if (hasMany) {\n return Array.isArray(value) ? value : []\n }\n\n return Array.isArray(value) ? '' : (value ?? '')\n }, [hasMany, value])\n\n return (\n <SelectInput\n description={description}\n hasMany={hasMany}\n label={field.label as string}\n localized={field.localized}\n name={field.name}\n onChange={handleChange as (value: ReactSelectOption | ReactSelectOption[]) => void}\n onInputChange={setInputValue}\n options={options}\n path={path}\n required={field.required}\n showError={showError}\n value={selectValue}\n />\n )\n}\n"],"names":["SelectInput","useConfig","useDocumentInfo","useField","useCallback","useEffect","useMemo","useRef","useState","selectSearchEndpoint","debounceMs","SelectSearchField","props","field","path","schemaPath","schemaPathProp","value","setValue","showError","collectionSlug","globalSlug","config","options","setOptions","inputValue","setInputValue","remoteError","setRemoteError","abortRef","entityType","slug","name","hasMany","apiPath","routes","api","apiRoute","startsWith","baseURL","serverURL","endpointURL","selectedValues","Array","isArray","map","entry","String","undefined","fetchOptions","query","current","abort","controller","AbortController","res","fetch","method","headers","credentials","signal","body","JSON","stringify","ok","errorBody","json","catch","message","error","data","timeout","setTimeout","clearTimeout","handleChange","option","values","description","admin","selectValue","label","localized","onChange","onInputChange","required"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/ui/SelectSearchField.tsx"],"sourcesContent":["'use client'\n\nimport type { ReactSelectOption } from '@payloadcms/ui'\nimport type { OptionObject, TextFieldClientComponent, TextFieldClientProps } from 'payload'\n\nimport {\n SelectInput,\n useConfig,\n useDocumentInfo,\n useField,\n useForm,\n useFormFields,\n} from '@payloadcms/ui'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { SelectSearchRequest } from '../types.js'\n\nimport { selectSearchEndpoint } from '../endpointName.js'\n\nconst defaultQueryDebounceMs = 300\nconst defaultWatchedFieldsDebounceMs = 700\n\nconst serializeRefetchValue = (value: unknown): string => {\n try {\n return JSON.stringify(value) ?? ''\n } catch {\n return ''\n }\n}\n\ntype SelectSearchFieldClientProps = {\n debounce?: {\n query?: number\n watchedFields?: number\n }\n passDataToSearchFunction?: boolean\n passSiblingDataToSearchFunction?: boolean\n watchFieldPaths?: string[]\n} & TextFieldClientProps\n\nexport const SelectSearchField: TextFieldClientComponent = (\n props: SelectSearchFieldClientProps,\n) => {\n const { field, path, schemaPath: schemaPathProp } = props\n\n const { setValue, showError, value } = useField<string | string[]>({\n path,\n })\n\n const { collectionSlug, globalSlug } = useDocumentInfo()\n const { config } = useConfig()\n const { getData, getSiblingData } = useForm()\n\n const [options, setOptions] = useState<OptionObject[]>([])\n\n const [inputValue, setInputValue] = useState('')\n const [remoteError, setRemoteError] = useState<null | string>(null)\n\n const abortRef = useRef<AbortController | null>(null)\n const fetchOptionsRef = useRef<((query: string) => Promise<void>) | null>(null)\n const latestInputValueRef = useRef('')\n const hasInitializedWatchedFieldsEffectRef = useRef(false)\n\n const entityType = globalSlug ? 'global' : 'collection'\n const slug = globalSlug || collectionSlug\n\n const schemaPath = schemaPathProp ?? field.name\n const hasMany = field.hasMany ?? false\n const passDataToSearchFunction = props.passDataToSearchFunction === true\n const passSiblingDataToSearchFunction = props.passSiblingDataToSearchFunction === true\n // `selectSearch` normalizes these values before passing to `clientProps`.\n const queryDebounceMs = props.debounce?.query ?? defaultQueryDebounceMs\n const watchedFieldsDebounceMs = props.debounce?.watchedFields ?? defaultWatchedFieldsDebounceMs\n const watchFieldPaths = props.watchFieldPaths ?? []\n\n const apiPath = config.routes?.api || '/api'\n const apiRoute = apiPath.startsWith('/') ? apiPath : `/${apiPath}`\n const baseURL = config.serverURL || ''\n const endpointURL = `${baseURL}${apiRoute}${selectSearchEndpoint}`\n\n const selectedValues = useMemo(() => {\n if (hasMany) {\n return Array.isArray(value) ? value.map((entry) => String(entry)) : []\n }\n\n if (Array.isArray(value) || value === null || value === undefined) {\n return []\n }\n\n return [String(value)]\n }, [hasMany, value])\n\n const watchedFieldPathsRefetchToken = useFormFields(([fields]) => {\n if (watchFieldPaths.length === 0) {\n return ''\n }\n\n const watchedPathValues: Array<[string, unknown]> = []\n\n for (const watchPath of watchFieldPaths) {\n if (!Object.prototype.hasOwnProperty.call(fields, watchPath)) {\n continue\n }\n\n watchedPathValues.push([watchPath, fields[watchPath]?.value])\n }\n\n return serializeRefetchValue(watchedPathValues)\n })\n\n const fetchOptions = useCallback(\n async (query: string) => {\n if (!slug || !schemaPath) {\n setOptions([])\n return\n }\n\n if (abortRef.current) {\n abortRef.current.abort()\n }\n\n const controller = new AbortController()\n abortRef.current = controller\n\n setRemoteError(null)\n\n const payload: SelectSearchRequest = {\n slug,\n entityType,\n query,\n schemaPath,\n selectedValues,\n }\n\n if (passDataToSearchFunction) {\n payload.data = getData()\n }\n\n if (passSiblingDataToSearchFunction) {\n payload.siblingData = getSiblingData(path)\n }\n\n const res = await fetch(endpointURL, {\n body: JSON.stringify(payload),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n signal: controller.signal,\n })\n\n if (!res.ok) {\n const errorBody = await res.json().catch(() => null)\n const message = errorBody?.error || 'Failed to fetch options'\n setRemoteError(message)\n setOptions([])\n return\n }\n\n const data = (await res.json()) as { options?: OptionObject[] }\n setOptions(Array.isArray(data.options) ? data.options : [])\n },\n [\n endpointURL,\n entityType,\n getData,\n getSiblingData,\n passDataToSearchFunction,\n passSiblingDataToSearchFunction,\n path,\n schemaPath,\n selectedValues,\n slug,\n ],\n )\n\n useEffect(() => {\n fetchOptionsRef.current = fetchOptions\n }, [fetchOptions])\n\n useEffect(() => {\n latestInputValueRef.current = inputValue\n }, [inputValue])\n\n useEffect(() => {\n if (!slug || !schemaPath) {\n return\n }\n\n // Query typing should feel responsive, so use a shorter debounce.\n const timeout = setTimeout(() => {\n void fetchOptionsRef.current?.(inputValue)\n }, queryDebounceMs)\n\n return () => {\n clearTimeout(timeout)\n }\n }, [inputValue, queryDebounceMs, schemaPath, slug])\n\n useEffect(() => {\n if (!slug || !schemaPath || watchFieldPaths.length === 0) {\n return\n }\n\n if (!hasInitializedWatchedFieldsEffectRef.current) {\n hasInitializedWatchedFieldsEffectRef.current = true\n return\n }\n\n // Watched field changes can happen in bursts, so use a longer debounce.\n const timeout = setTimeout(() => {\n void fetchOptionsRef.current?.(latestInputValueRef.current)\n }, watchedFieldsDebounceMs)\n\n return () => {\n clearTimeout(timeout)\n }\n }, [schemaPath, slug, watchFieldPaths.length, watchedFieldsDebounceMs, watchedFieldPathsRefetchToken])\n\n useEffect(() => {\n return () => {\n if (abortRef.current) {\n abortRef.current.abort()\n }\n }\n }, [])\n\n const handleChange = useCallback(\n (option: null | ReactSelectOption | ReactSelectOption[]) => {\n if (Array.isArray(option)) {\n const values = option.map((entry) => String(entry.value))\n setValue(values)\n return\n }\n\n if (!option) {\n setValue(hasMany ? [] : null)\n return\n }\n\n setValue(String(option.value))\n },\n [hasMany, setValue],\n )\n\n const description = useMemo(() => {\n if (remoteError) {\n return remoteError\n }\n\n return field.admin?.description\n }, [field.admin?.description, remoteError])\n\n const selectValue = useMemo(() => {\n if (hasMany) {\n return Array.isArray(value) ? value : []\n }\n\n return Array.isArray(value) ? '' : (value ?? '')\n }, [hasMany, value])\n\n return (\n <SelectInput\n description={description}\n hasMany={hasMany}\n label={field.label as string}\n localized={field.localized}\n name={field.name}\n onChange={handleChange as (value: ReactSelectOption | ReactSelectOption[]) => void}\n onInputChange={setInputValue}\n options={options}\n path={path}\n required={field.required}\n showError={showError}\n value={selectValue}\n />\n )\n}\n"],"names":["SelectInput","useConfig","useDocumentInfo","useField","useForm","useFormFields","useCallback","useEffect","useMemo","useRef","useState","selectSearchEndpoint","defaultQueryDebounceMs","defaultWatchedFieldsDebounceMs","serializeRefetchValue","value","JSON","stringify","SelectSearchField","props","field","path","schemaPath","schemaPathProp","setValue","showError","collectionSlug","globalSlug","config","getData","getSiblingData","options","setOptions","inputValue","setInputValue","remoteError","setRemoteError","abortRef","fetchOptionsRef","latestInputValueRef","hasInitializedWatchedFieldsEffectRef","entityType","slug","name","hasMany","passDataToSearchFunction","passSiblingDataToSearchFunction","queryDebounceMs","debounce","query","watchedFieldsDebounceMs","watchedFields","watchFieldPaths","apiPath","routes","api","apiRoute","startsWith","baseURL","serverURL","endpointURL","selectedValues","Array","isArray","map","entry","String","undefined","watchedFieldPathsRefetchToken","fields","length","watchedPathValues","watchPath","Object","prototype","hasOwnProperty","call","push","fetchOptions","current","abort","controller","AbortController","payload","data","siblingData","res","fetch","body","credentials","headers","method","signal","ok","errorBody","json","catch","message","error","timeout","setTimeout","clearTimeout","handleChange","option","values","description","admin","selectValue","label","localized","onChange","onInputChange","required"],"mappings":"AAAA;;AAKA,SACEA,WAAW,EACXC,SAAS,EACTC,eAAe,EACfC,QAAQ,EACRC,OAAO,EACPC,aAAa,QACR,iBAAgB;AACvB,SAASC,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAIzE,SAASC,oBAAoB,QAAQ,qBAAoB;AAEzD,MAAMC,yBAAyB;AAC/B,MAAMC,iCAAiC;AAEvC,MAAMC,wBAAwB,CAACC;IAC7B,IAAI;QACF,OAAOC,KAAKC,SAAS,CAACF,UAAU;IAClC,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAYA,OAAO,MAAMG,oBAA8C,CACzDC;IAEA,MAAM,EAAEC,KAAK,EAAEC,IAAI,EAAEC,YAAYC,cAAc,EAAE,GAAGJ;IAEpD,MAAM,EAAEK,QAAQ,EAAEC,SAAS,EAAEV,KAAK,EAAE,GAAGZ,SAA4B;QACjEkB;IACF;IAEA,MAAM,EAAEK,cAAc,EAAEC,UAAU,EAAE,GAAGzB;IACvC,MAAM,EAAE0B,MAAM,EAAE,GAAG3B;IACnB,MAAM,EAAE4B,OAAO,EAAEC,cAAc,EAAE,GAAG1B;IAEpC,MAAM,CAAC2B,SAASC,WAAW,GAAGtB,SAAyB,EAAE;IAEzD,MAAM,CAACuB,YAAYC,cAAc,GAAGxB,SAAS;IAC7C,MAAM,CAACyB,aAAaC,eAAe,GAAG1B,SAAwB;IAE9D,MAAM2B,WAAW5B,OAA+B;IAChD,MAAM6B,kBAAkB7B,OAAkD;IAC1E,MAAM8B,sBAAsB9B,OAAO;IACnC,MAAM+B,uCAAuC/B,OAAO;IAEpD,MAAMgC,aAAad,aAAa,WAAW;IAC3C,MAAMe,OAAOf,cAAcD;IAE3B,MAAMJ,aAAaC,kBAAkBH,MAAMuB,IAAI;IAC/C,MAAMC,UAAUxB,MAAMwB,OAAO,IAAI;IACjC,MAAMC,2BAA2B1B,MAAM0B,wBAAwB,KAAK;IACpE,MAAMC,kCAAkC3B,MAAM2B,+BAA+B,KAAK;IAClF,0EAA0E;IAC1E,MAAMC,kBAAkB5B,MAAM6B,QAAQ,EAAEC,SAASrC;IACjD,MAAMsC,0BAA0B/B,MAAM6B,QAAQ,EAAEG,iBAAiBtC;IACjE,MAAMuC,kBAAkBjC,MAAMiC,eAAe,IAAI,EAAE;IAEnD,MAAMC,UAAUzB,OAAO0B,MAAM,EAAEC,OAAO;IACtC,MAAMC,WAAWH,QAAQI,UAAU,CAAC,OAAOJ,UAAU,CAAC,CAAC,EAAEA,SAAS;IAClE,MAAMK,UAAU9B,OAAO+B,SAAS,IAAI;IACpC,MAAMC,cAAc,GAAGF,UAAUF,WAAW7C,sBAAsB;IAElE,MAAMkD,iBAAiBrD,QAAQ;QAC7B,IAAIoC,SAAS;YACX,OAAOkB,MAAMC,OAAO,CAAChD,SAASA,MAAMiD,GAAG,CAAC,CAACC,QAAUC,OAAOD,UAAU,EAAE;QACxE;QAEA,IAAIH,MAAMC,OAAO,CAAChD,UAAUA,UAAU,QAAQA,UAAUoD,WAAW;YACjE,OAAO,EAAE;QACX;QAEA,OAAO;YAACD,OAAOnD;SAAO;IACxB,GAAG;QAAC6B;QAAS7B;KAAM;IAEnB,MAAMqD,gCAAgC/D,cAAc,CAAC,CAACgE,OAAO;QAC3D,IAAIjB,gBAAgBkB,MAAM,KAAK,GAAG;YAChC,OAAO;QACT;QAEA,MAAMC,oBAA8C,EAAE;QAEtD,KAAK,MAAMC,aAAapB,gBAAiB;YACvC,IAAI,CAACqB,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACP,QAAQG,YAAY;gBAC5D;YACF;YAEAD,kBAAkBM,IAAI,CAAC;gBAACL;gBAAWH,MAAM,CAACG,UAAU,EAAEzD;aAAM;QAC9D;QAEA,OAAOD,sBAAsByD;IAC/B;IAEA,MAAMO,eAAexE,YACnB,OAAO2C;QACL,IAAI,CAACP,QAAQ,CAACpB,YAAY;YACxBU,WAAW,EAAE;YACb;QACF;QAEA,IAAIK,SAAS0C,OAAO,EAAE;YACpB1C,SAAS0C,OAAO,CAACC,KAAK;QACxB;QAEA,MAAMC,aAAa,IAAIC;QACvB7C,SAAS0C,OAAO,GAAGE;QAEnB7C,eAAe;QAEf,MAAM+C,UAA+B;YACnCzC;YACAD;YACAQ;YACA3B;YACAuC;QACF;QAEA,IAAIhB,0BAA0B;YAC5BsC,QAAQC,IAAI,GAAGvD;QACjB;QAEA,IAAIiB,iCAAiC;YACnCqC,QAAQE,WAAW,GAAGvD,eAAeT;QACvC;QAEA,MAAMiE,MAAM,MAAMC,MAAM3B,aAAa;YACnC4B,MAAMxE,KAAKC,SAAS,CAACkE;YACrBM,aAAa;YACbC,SAAS;gBACP,gBAAgB;YAClB;YACAC,QAAQ;YACRC,QAAQX,WAAWW,MAAM;QAC3B;QAEA,IAAI,CAACN,IAAIO,EAAE,EAAE;YACX,MAAMC,YAAY,MAAMR,IAAIS,IAAI,GAAGC,KAAK,CAAC,IAAM;YAC/C,MAAMC,UAAUH,WAAWI,SAAS;YACpC9D,eAAe6D;YACfjE,WAAW,EAAE;YACb;QACF;QAEA,MAAMoD,OAAQ,MAAME,IAAIS,IAAI;QAC5B/D,WAAW8B,MAAMC,OAAO,CAACqB,KAAKrD,OAAO,IAAIqD,KAAKrD,OAAO,GAAG,EAAE;IAC5D,GACA;QACE6B;QACAnB;QACAZ;QACAC;QACAe;QACAC;QACAzB;QACAC;QACAuC;QACAnB;KACD;IAGHnC,UAAU;QACR+B,gBAAgByC,OAAO,GAAGD;IAC5B,GAAG;QAACA;KAAa;IAEjBvE,UAAU;QACRgC,oBAAoBwC,OAAO,GAAG9C;IAChC,GAAG;QAACA;KAAW;IAEf1B,UAAU;QACR,IAAI,CAACmC,QAAQ,CAACpB,YAAY;YACxB;QACF;QAEA,kEAAkE;QAClE,MAAM6E,UAAUC,WAAW;YACzB,KAAK9D,gBAAgByC,OAAO,GAAG9C;QACjC,GAAGc;QAEH,OAAO;YACLsD,aAAaF;QACf;IACF,GAAG;QAAClE;QAAYc;QAAiBzB;QAAYoB;KAAK;IAElDnC,UAAU;QACR,IAAI,CAACmC,QAAQ,CAACpB,cAAc8B,gBAAgBkB,MAAM,KAAK,GAAG;YACxD;QACF;QAEA,IAAI,CAAC9B,qCAAqCuC,OAAO,EAAE;YACjDvC,qCAAqCuC,OAAO,GAAG;YAC/C;QACF;QAEA,wEAAwE;QACxE,MAAMoB,UAAUC,WAAW;YACzB,KAAK9D,gBAAgByC,OAAO,GAAGxC,oBAAoBwC,OAAO;QAC5D,GAAG7B;QAEH,OAAO;YACLmD,aAAaF;QACf;IACF,GAAG;QAAC7E;QAAYoB;QAAMU,gBAAgBkB,MAAM;QAAEpB;QAAyBkB;KAA8B;IAErG7D,UAAU;QACR,OAAO;YACL,IAAI8B,SAAS0C,OAAO,EAAE;gBACpB1C,SAAS0C,OAAO,CAACC,KAAK;YACxB;QACF;IACF,GAAG,EAAE;IAEL,MAAMsB,eAAehG,YACnB,CAACiG;QACC,IAAIzC,MAAMC,OAAO,CAACwC,SAAS;YACzB,MAAMC,SAASD,OAAOvC,GAAG,CAAC,CAACC,QAAUC,OAAOD,MAAMlD,KAAK;YACvDS,SAASgF;YACT;QACF;QAEA,IAAI,CAACD,QAAQ;YACX/E,SAASoB,UAAU,EAAE,GAAG;YACxB;QACF;QAEApB,SAAS0C,OAAOqC,OAAOxF,KAAK;IAC9B,GACA;QAAC6B;QAASpB;KAAS;IAGrB,MAAMiF,cAAcjG,QAAQ;QAC1B,IAAI2B,aAAa;YACf,OAAOA;QACT;QAEA,OAAOf,MAAMsF,KAAK,EAAED;IACtB,GAAG;QAACrF,MAAMsF,KAAK,EAAED;QAAatE;KAAY;IAE1C,MAAMwE,cAAcnG,QAAQ;QAC1B,IAAIoC,SAAS;YACX,OAAOkB,MAAMC,OAAO,CAAChD,SAASA,QAAQ,EAAE;QAC1C;QAEA,OAAO+C,MAAMC,OAAO,CAAChD,SAAS,KAAMA,SAAS;IAC/C,GAAG;QAAC6B;QAAS7B;KAAM;IAEnB,qBACE,KAACf;QACCyG,aAAaA;QACb7D,SAASA;QACTgE,OAAOxF,MAAMwF,KAAK;QAClBC,WAAWzF,MAAMyF,SAAS;QAC1BlE,MAAMvB,MAAMuB,IAAI;QAChBmE,UAAUR;QACVS,eAAe7E;QACfH,SAASA;QACTV,MAAMA;QACN2F,UAAU5F,MAAM4F,QAAQ;QACxBvF,WAAWA;QACXV,OAAO4F;;AAGb,EAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whatworks/payload-select-search-field",
3
- "version": "1.0.2",
3
+ "version": "2.0.0",
4
4
  "description": "Payload plugin and field component for server-backed search select fields.",
5
5
  "license": "MIT",
6
6
  "type": "module",