@timeax/form-palette 0.0.30 → 0.0.32

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/extra.mjs CHANGED
@@ -216,19 +216,139 @@ function mapOptions(rawList, mapping, ctx) {
216
216
  }
217
217
 
218
218
  // src/presets/lister/engine/search.ts
219
- function optionText(o3) {
220
- var _a;
221
- const l2 = o3.label;
222
- if (typeof l2 === "string") return l2;
223
- if (typeof l2 === "number") return String(l2);
224
- const rl = (_a = o3.raw) == null ? void 0 : _a.label;
225
- if (typeof rl === "string") return rl;
226
- return String(o3.value);
227
- }
228
- function filterOptionsLocal(options, query) {
219
+ function getPath2(obj, path) {
220
+ if (!obj || !path) return void 0;
221
+ if (!path.includes(".")) return obj[path];
222
+ let cur = obj;
223
+ for (const part of path.split(".")) {
224
+ if (cur == null) return void 0;
225
+ cur = cur[part];
226
+ }
227
+ return cur;
228
+ }
229
+ function toText(v2) {
230
+ if (v2 == null) return "";
231
+ if (typeof v2 === "string") return v2;
232
+ if (typeof v2 === "number" || typeof v2 === "boolean") return String(v2);
233
+ return "";
234
+ }
235
+ function collectAllText(obj, out, depth = 2, budget = { n: 80 }) {
236
+ if (obj == null || budget.n <= 0) return;
237
+ const t4 = typeof obj;
238
+ if (t4 === "string" || t4 === "number" || t4 === "boolean") {
239
+ out.push(String(obj));
240
+ budget.n -= 1;
241
+ return;
242
+ }
243
+ if (depth <= 0) return;
244
+ if (Array.isArray(obj)) {
245
+ for (const x2 of obj) collectAllText(x2, out, depth - 1, budget);
246
+ return;
247
+ }
248
+ if (t4 === "object") {
249
+ for (const k2 of Object.keys(obj)) {
250
+ collectAllText(obj[k2], out, depth - 1, budget);
251
+ if (budget.n <= 0) break;
252
+ }
253
+ }
254
+ }
255
+ function matchQueryInText(q2, text) {
256
+ if (!q2) return true;
257
+ return text.toLowerCase().includes(q2);
258
+ }
259
+ function buildSearchTextForKeys(raw, keys) {
260
+ const parts = [];
261
+ for (const k2 of keys) {
262
+ const key = String(k2);
263
+ const v2 = getPath2(raw, key);
264
+ if (v2 == null) continue;
265
+ if (Array.isArray(v2)) {
266
+ for (const x2 of v2) {
267
+ const s4 = toText(x2);
268
+ if (s4) parts.push(s4);
269
+ }
270
+ continue;
271
+ }
272
+ const s3 = toText(v2);
273
+ if (s3) parts.push(s3);
274
+ }
275
+ return parts.join(" ");
276
+ }
277
+ function matchesSearch(raw, q2, search) {
278
+ if (!q2) return true;
279
+ if (search == null ? void 0 : search.searchAll) {
280
+ return matchQueryInText(q2, buildSearchTextAll(raw));
281
+ }
282
+ if (Array.isArray(search == null ? void 0 : search.searchOnly) && search.searchOnly.length) {
283
+ return matchQueryInText(
284
+ q2,
285
+ buildSearchTextForKeys(raw, search.searchOnly)
286
+ );
287
+ }
288
+ if (typeof (search == null ? void 0 : search.subject) === "string" && search.subject) {
289
+ return matchQueryInText(
290
+ q2,
291
+ buildSearchTextForKeys(raw, [search.subject])
292
+ );
293
+ }
294
+ return matchQueryInText(q2, buildSearchTextAll(raw));
295
+ }
296
+ function buildSearchTextAll(raw) {
297
+ const parts = [];
298
+ collectAllText(raw, parts, 2);
299
+ return parts.join(" ");
300
+ }
301
+ function isEmptyFilterValue(v2) {
302
+ if (v2 === void 0 || v2 === null) return true;
303
+ if (typeof v2 === "string" && v2.trim() === "") return true;
304
+ return Array.isArray(v2) && v2.length === 0;
305
+ }
306
+ function matchesFilters(raw, filters) {
307
+ if (!filters) return true;
308
+ for (const key of Object.keys(filters)) {
309
+ if (key === "search" || key === "subject" || key === "searchAll" || key === "searchOnly") {
310
+ continue;
311
+ }
312
+ const fv = filters[key];
313
+ if (isEmptyFilterValue(fv)) continue;
314
+ const rv = getPath2(raw, key);
315
+ if (Array.isArray(fv)) {
316
+ if (Array.isArray(rv)) {
317
+ const ok = rv.some((x2) => fv.includes(x2));
318
+ if (!ok) return false;
319
+ } else {
320
+ if (!fv.includes(rv)) return false;
321
+ }
322
+ continue;
323
+ }
324
+ if (Array.isArray(rv)) {
325
+ if (!rv.includes(fv)) return false;
326
+ continue;
327
+ }
328
+ if (String(rv) !== String(fv)) return false;
329
+ }
330
+ return true;
331
+ }
332
+ function filterRawListLocal(rawList, query, search, filters, opts) {
333
+ let list = Array.isArray(rawList) ? rawList : [];
334
+ const ctx = { query, search, filters };
335
+ const filtersLocal = (opts == null ? void 0 : opts.filtersSpec) && opts.filtersSpec.local;
336
+ if (typeof filtersLocal === "function") {
337
+ const out = filtersLocal(list, ctx);
338
+ if (Array.isArray(out)) list = out;
339
+ } else {
340
+ list = list.filter(
341
+ (r5) => matchesFilters(r5, filters)
342
+ );
343
+ }
229
344
  const q2 = (query != null ? query : "").trim().toLowerCase();
230
- if (!q2) return options;
231
- return options.filter((o3) => optionText(o3).toLowerCase().includes(q2));
345
+ if (!q2) return list;
346
+ const searchLocal = (opts == null ? void 0 : opts.searchSpec) && opts.searchSpec.local;
347
+ if (typeof searchLocal === "function") {
348
+ const out = searchLocal(list, ctx);
349
+ if (Array.isArray(out)) return out;
350
+ }
351
+ return list.filter((r5) => matchesSearch(r5, q2, search));
232
352
  }
233
353
 
234
354
  // src/presets/lister/engine/selection.ts
@@ -390,7 +510,8 @@ function initialSessionState(sessionId) {
390
510
  filtersPatch: {},
391
511
  effectiveFilters: void 0,
392
512
  // IMPORTANT: these are now OPTION IDS (not db values)
393
- selectedFilterValues: []
513
+ selectedFilterValues: [],
514
+ searchPayload: void 0
394
515
  };
395
516
  }
396
517
  function buildSearchPayloadFromTarget(target) {
@@ -402,7 +523,7 @@ function buildSearchPayloadFromTarget(target) {
402
523
  return subject ? { subject } : void 0;
403
524
  }
404
525
  if (target.mode === "only") {
405
- const only = Array.isArray(target.only) ? target.only.filter(Boolean) : void 0;
526
+ const only = Array.isArray(target.only) ? target.only.filter((v2) => v2 !== null && v2 !== void 0) : void 0;
406
527
  return only && only.length ? { searchOnly: only } : void 0;
407
528
  }
408
529
  return void 0;
@@ -659,16 +780,15 @@ function ListerProvider(props) {
659
780
  );
660
781
  const fetchAndHydrate = React.useCallback(
661
782
  async (id, reason, override) => {
662
- var _a2, _b2, _c2, _d, _e, _f, _g, _h;
783
+ var _a2, _b2, _c2, _d, _e, _f, _g;
663
784
  const s0 = getSession(id);
664
785
  if (!(s0 == null ? void 0 : s0.definition)) return;
665
786
  const myReq = ((_a2 = reqIdBySessionRef.current[id]) != null ? _a2 : 0) + 1;
666
787
  reqIdBySessionRef.current[id] = myReq;
667
788
  const query = (_b2 = override == null ? void 0 : override.query) != null ? _b2 : s0.query;
668
789
  const filters = (_d = (_c2 = override == null ? void 0 : override.filters) != null ? _c2 : s0.effectiveFilters) != null ? _d : s0.filters;
669
- const search = (_f = override == null ? void 0 : override.search) != null ? _f : buildSearchPayloadFromTarget(
670
- (_e = getSession(id)) == null ? void 0 : _e.searchTarget
671
- );
790
+ const hasSearchOverride = !!override && Object.prototype.hasOwnProperty.call(override, "search");
791
+ const search = hasSearchOverride ? override.search : (_e = s0.searchPayload) != null ? _e : buildSearchPayloadFromTarget(s0.searchTarget);
672
792
  patchSession(id, {
673
793
  errorCode: void 0,
674
794
  loading: reason !== "refresh",
@@ -701,7 +821,7 @@ function ListerProvider(props) {
701
821
  details: {
702
822
  sessionId: id,
703
823
  kind: s3 == null ? void 0 : s3.kind,
704
- endpoint: (_h = (_g = s3 == null ? void 0 : s3.definition) == null ? void 0 : _g.source) == null ? void 0 : _h.endpoint,
824
+ endpoint: (_g = (_f = s3 == null ? void 0 : s3.definition) == null ? void 0 : _f.source) == null ? void 0 : _g.endpoint,
705
825
  query,
706
826
  filters,
707
827
  search
@@ -755,7 +875,7 @@ function ListerProvider(props) {
755
875
  nextPatch,
756
876
  spec
757
877
  );
758
- shouldFetch = (spec == null ? void 0 : spec.autoFetch) !== false;
878
+ shouldFetch = (spec == null ? void 0 : spec.autoFetch) !== false && s4.searchMode !== "local";
759
879
  return {
760
880
  ...s4,
761
881
  filtersPatch: nextPatch,
@@ -844,7 +964,7 @@ function ListerProvider(props) {
844
964
  );
845
965
  const apiOpenAny = React.useCallback(
846
966
  async (kindOrDef, filters, opts) => {
847
- var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i;
967
+ var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i, _j, _k, _l;
848
968
  const mode = (_a2 = opts == null ? void 0 : opts.mode) != null ? _a2 : "single";
849
969
  try {
850
970
  const def = typeof kindOrDef === "string" ? getPreset(kindOrDef) : kindOrDef;
@@ -867,7 +987,8 @@ function ListerProvider(props) {
867
987
  const pos = anchorToPos(opts == null ? void 0 : opts.anchor);
868
988
  const filtersSpec = (_d = opts == null ? void 0 : opts.filtersSpec) != null ? _d : prev == null ? void 0 : prev.filtersSpec;
869
989
  const filtersPatch = (_e = prev == null ? void 0 : prev.filtersPatch) != null ? _e : {};
870
- const selectedFilterValues = (_f = prev == null ? void 0 : prev.selectedFilterValues) != null ? _f : [];
990
+ const resolvedSearchMode = (_g = (_f = opts == null ? void 0 : opts.searchMode) != null ? _f : prev == null ? void 0 : prev.searchMode) != null ? _g : "remote";
991
+ const selectedFilterValues = (_h = prev == null ? void 0 : prev.selectedFilterValues) != null ? _h : [];
871
992
  const effectiveFilters = computeEffectiveFilters(
872
993
  filters,
873
994
  filtersPatch,
@@ -875,10 +996,10 @@ function ListerProvider(props) {
875
996
  );
876
997
  const searchSpec = def == null ? void 0 : def.search;
877
998
  const defaultCol = searchSpec == null ? void 0 : searchSpec.default;
878
- const defaultSearchTarget = defaultCol ? { mode: "subject", subject: defaultCol, only: null } : void 0;
879
- const searchTarget = (_g = prev == null ? void 0 : prev.searchTarget) != null ? _g : defaultSearchTarget;
880
- const initialQuery = (_i = (_h = opts == null ? void 0 : opts.initialQuery) != null ? _h : prev == null ? void 0 : prev.query) != null ? _i : "";
881
- const searchPayload = buildSearchPayloadFromTarget(searchTarget);
999
+ const defaultSearchTarget2 = defaultCol ? { mode: "subject", subject: defaultCol, only: null } : void 0;
1000
+ const searchTarget = (_i = prev == null ? void 0 : prev.searchTarget) != null ? _i : defaultSearchTarget2;
1001
+ const initialQuery = (_k = (_j = opts == null ? void 0 : opts.initialQuery) != null ? _j : prev == null ? void 0 : prev.query) != null ? _k : "";
1002
+ const searchPayload = (_l = prev == null ? void 0 : prev.searchPayload) != null ? _l : buildSearchPayloadFromTarget(searchTarget);
882
1003
  const { rawList, optionsList } = await performFetch(
883
1004
  def,
884
1005
  effectiveFilters,
@@ -886,7 +1007,7 @@ function ListerProvider(props) {
886
1007
  );
887
1008
  return await new Promise(
888
1009
  (resolve) => {
889
- var _a3, _b3, _c3, _d2;
1010
+ var _a3, _b3, _c3;
890
1011
  const base = initialSessionState(sessionId);
891
1012
  const nextSession = {
892
1013
  ...prev ? { ...prev } : base,
@@ -902,12 +1023,12 @@ function ListerProvider(props) {
902
1023
  draggable: (_a3 = opts == null ? void 0 : opts.draggable) != null ? _a3 : true,
903
1024
  position: pos,
904
1025
  hasMoved: false,
905
- searchMode: (_b3 = opts == null ? void 0 : opts.searchMode) != null ? _b3 : "remote",
1026
+ searchMode: resolvedSearchMode,
906
1027
  query: initialQuery,
907
1028
  searchSpec,
908
1029
  searchTarget,
909
- showRefresh: (_c3 = opts == null ? void 0 : opts.showRefresh) != null ? _c3 : false,
910
- refreshMode: (_d2 = opts == null ? void 0 : opts.refreshMode) != null ? _d2 : "preserve-selection",
1030
+ showRefresh: (_b3 = opts == null ? void 0 : opts.showRefresh) != null ? _b3 : false,
1031
+ refreshMode: (_c3 = opts == null ? void 0 : opts.refreshMode) != null ? _c3 : "preserve-selection",
911
1032
  // filters
912
1033
  filtersSpec,
913
1034
  filtersPatch,
@@ -1125,17 +1246,32 @@ function ListerProvider(props) {
1125
1246
  );
1126
1247
  const setSearchMode = React.useCallback(
1127
1248
  (id, mode) => {
1249
+ var _a2;
1250
+ const s3 = getSession(id);
1251
+ if (!s3) return;
1252
+ const prevMode = s3.searchMode;
1128
1253
  patchSession(id, { searchMode: mode });
1254
+ if (prevMode === mode) return;
1255
+ if (mode === "local") {
1256
+ fetchAndHydrate(id, "refresh", {
1257
+ filters: (_a2 = s3.effectiveFilters) != null ? _a2 : s3.filters,
1258
+ query: "",
1259
+ // base fetch (unsearched)
1260
+ search: void 0
1261
+ // force NO search payload
1262
+ });
1263
+ }
1129
1264
  },
1130
- [patchSession]
1265
+ [fetchAndHydrate, getSession, patchSession]
1131
1266
  );
1132
1267
  const scheduleRemoteFetch = React.useCallback(
1133
1268
  (id, q2, payloadOverride) => {
1134
1269
  if (timerBySessionRef.current[id])
1135
1270
  clearTimeout(timerBySessionRef.current[id]);
1136
1271
  timerBySessionRef.current[id] = setTimeout(() => {
1272
+ var _a2;
1137
1273
  const s3 = getSession(id);
1138
- const search = payloadOverride != null ? payloadOverride : buildSearchPayloadFromTarget(s3 == null ? void 0 : s3.searchTarget);
1274
+ const search = (_a2 = payloadOverride != null ? payloadOverride : s3 == null ? void 0 : s3.searchPayload) != null ? _a2 : buildSearchPayloadFromTarget(s3 == null ? void 0 : s3.searchTarget);
1139
1275
  fetchAndHydrate(id, "search", { query: q2, search });
1140
1276
  }, debounceMs);
1141
1277
  },
@@ -1144,7 +1280,10 @@ function ListerProvider(props) {
1144
1280
  const setSearchTarget = React.useCallback(
1145
1281
  (id, target) => {
1146
1282
  var _a2, _b2;
1147
- patchSession(id, { searchTarget: target });
1283
+ patchSession(id, {
1284
+ searchTarget: target,
1285
+ searchPayload: void 0
1286
+ });
1148
1287
  const s3 = getSession(id);
1149
1288
  const mode = (_a2 = s3 == null ? void 0 : s3.searchMode) != null ? _a2 : "remote";
1150
1289
  const q2 = (_b2 = s3 == null ? void 0 : s3.query) != null ? _b2 : "";
@@ -1156,7 +1295,7 @@ function ListerProvider(props) {
1156
1295
  );
1157
1296
  const searchLocalImpl = React.useCallback(
1158
1297
  (id, q2, payload) => {
1159
- patchSession(id, { query: q2 });
1298
+ patchSession(id, { query: q2, searchPayload: payload });
1160
1299
  const s3 = getSession(id);
1161
1300
  if (!s3) return;
1162
1301
  if (s3.searchMode === "hybrid") {
@@ -1167,7 +1306,7 @@ function ListerProvider(props) {
1167
1306
  );
1168
1307
  const searchRemoteImpl = React.useCallback(
1169
1308
  (id, q2, payload) => {
1170
- patchSession(id, { query: q2 });
1309
+ patchSession(id, { query: q2, searchPayload: payload });
1171
1310
  scheduleRemoteFetch(id, q2, payload);
1172
1311
  },
1173
1312
  [patchSession, scheduleRemoteFetch]
@@ -1195,13 +1334,30 @@ function ListerProvider(props) {
1195
1334
  );
1196
1335
  const getVisibleOptions = React.useCallback(
1197
1336
  (id) => {
1337
+ var _a2, _b2, _c2, _d;
1198
1338
  const s3 = getSession(id);
1199
1339
  if (!s3) return [];
1200
- if (s3.searchMode === "local")
1201
- return filterOptionsLocal(s3.optionsList, s3.query);
1202
- if (s3.searchMode === "hybrid")
1203
- return filterOptionsLocal(s3.optionsList, s3.query);
1204
- return s3.optionsList;
1340
+ if (s3.searchMode === "remote") return s3.optionsList;
1341
+ const def = s3.definition;
1342
+ if (!def) return [];
1343
+ const filters = (_a2 = s3.effectiveFilters) != null ? _a2 : s3.filters;
1344
+ const payload = (_b2 = s3.searchPayload) != null ? _b2 : buildSearchPayloadFromTarget(s3 == null ? void 0 : s3.searchTarget);
1345
+ const visibleRaw = filterRawListLocal(
1346
+ (_c2 = s3.rawList) != null ? _c2 : [],
1347
+ s3.query,
1348
+ payload,
1349
+ filters,
1350
+ {
1351
+ searchSpec: (_d = s3.searchSpec) != null ? _d : def.search,
1352
+ filtersSpec: s3.filtersSpec
1353
+ }
1354
+ );
1355
+ const mapCtx = { query: s3.query, filters };
1356
+ return mapOptions(
1357
+ visibleRaw,
1358
+ def.mapping,
1359
+ mapCtx
1360
+ );
1205
1361
  },
1206
1362
  [getSession]
1207
1363
  );
@@ -1266,50 +1422,6 @@ function ListerProvider(props) {
1266
1422
  );
1267
1423
  return /* @__PURE__ */ jsx(Ctx.Provider, { value, children: props.children });
1268
1424
  }
1269
- function useLister() {
1270
- const ctx = React.useContext(Ctx);
1271
- if (!ctx)
1272
- throw new Error("useLister must be used within <ListerProvider />");
1273
- const api = React.useMemo(() => {
1274
- const fetch = ((kindOrDef, filters, opts) => ctx.apiFetchAny(kindOrDef, filters, opts));
1275
- const open = ((kindOrDef, filters, opts) => ctx.apiOpenAny(kindOrDef, filters, opts));
1276
- return {
1277
- fetch,
1278
- open,
1279
- registerPreset: (kind, def) => ctx.registerPreset(kind, def),
1280
- getPreset: (kind) => ctx.getPreset(kind)
1281
- };
1282
- }, [ctx]);
1283
- const active = ctx.store.activeId ? ctx.store.sessions[ctx.store.activeId] : void 0;
1284
- return {
1285
- api,
1286
- store: ctx.store,
1287
- state: active,
1288
- actions: {
1289
- focus: ctx.focus,
1290
- dispose: ctx.dispose,
1291
- apply: ctx.apply,
1292
- cancel: ctx.cancel,
1293
- close: ctx.close,
1294
- toggle: ctx.toggle,
1295
- select: ctx.select,
1296
- deselect: ctx.deselect,
1297
- clear: ctx.clear,
1298
- setQuery: ctx.setQuery,
1299
- setSearchMode: ctx.setSearchMode,
1300
- setSearchTarget: ctx.setSearchTarget,
1301
- searchLocal: ctx.searchLocal,
1302
- searchRemote: ctx.searchRemote,
1303
- refresh: ctx.refresh,
1304
- setPosition: ctx.setPosition,
1305
- getFilterCtx: ctx.getFilterCtx,
1306
- applyFilterOption: ctx.applyFilterOption,
1307
- registerPreset: ctx.registerPreset,
1308
- getPreset: ctx.getPreset,
1309
- getVisibleOptions: ctx.getVisibleOptions
1310
- }
1311
- };
1312
- }
1313
1425
 
1314
1426
  // ../../node_modules/clsx/dist/clsx.mjs
1315
1427
  function r(e4) {
@@ -25971,7 +26083,7 @@ function SearchBar(props) {
25971
26083
  {
25972
26084
  variant: "select",
25973
26085
  mode: "button",
25974
- value: searchMode,
26086
+ defaultValue: searchMode,
25975
26087
  triggerClassName: "border-none ring-0 shadow-none! px-1! cursor-pointer",
25976
26088
  options: [
25977
26089
  {
@@ -26248,6 +26360,429 @@ function FooterBar(props) {
26248
26360
  }
26249
26361
  );
26250
26362
  }
26363
+ function useLister() {
26364
+ const ctx = React.useContext(Ctx);
26365
+ if (!ctx)
26366
+ throw new Error("useLister must be used within <ListerProvider />");
26367
+ const api = React.useMemo(() => {
26368
+ const fetch = ((kindOrDef, filters, opts) => ctx.apiFetchAny(kindOrDef, filters, opts));
26369
+ const open = ((kindOrDef, filters, opts) => ctx.apiOpenAny(kindOrDef, filters, opts));
26370
+ return {
26371
+ fetch,
26372
+ open,
26373
+ registerPreset: (kind, def) => ctx.registerPreset(kind, def),
26374
+ getPreset: (kind) => ctx.getPreset(kind)
26375
+ };
26376
+ }, [ctx]);
26377
+ const active = ctx.store.activeId ? ctx.store.sessions[ctx.store.activeId] : void 0;
26378
+ return {
26379
+ api,
26380
+ store: ctx.store,
26381
+ state: active,
26382
+ actions: {
26383
+ focus: ctx.focus,
26384
+ dispose: ctx.dispose,
26385
+ apply: ctx.apply,
26386
+ cancel: ctx.cancel,
26387
+ close: ctx.close,
26388
+ toggle: ctx.toggle,
26389
+ select: ctx.select,
26390
+ deselect: ctx.deselect,
26391
+ clear: ctx.clear,
26392
+ setQuery: ctx.setQuery,
26393
+ setSearchMode: ctx.setSearchMode,
26394
+ setSearchTarget: ctx.setSearchTarget,
26395
+ searchLocal: ctx.searchLocal,
26396
+ searchRemote: ctx.searchRemote,
26397
+ refresh: ctx.refresh,
26398
+ setPosition: ctx.setPosition,
26399
+ getFilterCtx: ctx.getFilterCtx,
26400
+ applyFilterOption: ctx.applyFilterOption,
26401
+ registerPreset: ctx.registerPreset,
26402
+ getPreset: ctx.getPreset,
26403
+ getVisibleOptions: ctx.getVisibleOptions
26404
+ }
26405
+ };
26406
+ }
26407
+ function defaultSearchTarget(search) {
26408
+ const def = search == null ? void 0 : search.default;
26409
+ return def ? { mode: "subject", subject: def, only: null } : void 0;
26410
+ }
26411
+ function isKey(x2) {
26412
+ return typeof x2 === "string" || typeof x2 === "number";
26413
+ }
26414
+ function useData(opts) {
26415
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
26416
+ const ctx = React.useContext(Ctx);
26417
+ if (!ctx) throw new Error("useData must be used within <ListerProvider />");
26418
+ const enabled = (_a = opts.enabled) != null ? _a : true;
26419
+ const debounceMs = (_b = opts.debounceMs) != null ? _b : 300;
26420
+ const [data, setData] = React.useState(() => {
26421
+ var _a2;
26422
+ return (_a2 = opts.initial) != null ? _a2 : [];
26423
+ });
26424
+ const [loading, setLoading] = React.useState(false);
26425
+ const [error, setError] = React.useState(void 0);
26426
+ const [query, _setQuery] = React.useState("");
26427
+ const [searchMode, _setSearchMode] = React.useState(
26428
+ (_c = opts.searchMode) != null ? _c : "remote"
26429
+ );
26430
+ const [searchTarget, _setSearchTarget] = React.useState(() => defaultSearchTarget(opts.search));
26431
+ const [filters, _setFilters] = React.useState(
26432
+ opts.filters
26433
+ );
26434
+ const selectionMode = (_e = (_d = opts.selection) == null ? void 0 : _d.mode) != null ? _e : "none";
26435
+ const selectionPrune = (_g = (_f = opts.selection) == null ? void 0 : _f.prune) != null ? _g : "never";
26436
+ const getItemKey = React.useMemo(() => {
26437
+ var _a2;
26438
+ const key = (_a2 = opts.selection) == null ? void 0 : _a2.key;
26439
+ if (!key) {
26440
+ return (item) => {
26441
+ var _a3;
26442
+ const v2 = (_a3 = item == null ? void 0 : item.id) != null ? _a3 : item == null ? void 0 : item.value;
26443
+ return isKey(v2) ? v2 : null;
26444
+ };
26445
+ }
26446
+ if (typeof key === "function") {
26447
+ return (item) => {
26448
+ const v2 = key(item);
26449
+ return isKey(v2) ? v2 : null;
26450
+ };
26451
+ }
26452
+ return (item) => {
26453
+ const v2 = item == null ? void 0 : item[key];
26454
+ return isKey(v2) ? v2 : null;
26455
+ };
26456
+ }, [(_h = opts.selection) == null ? void 0 : _h.key]);
26457
+ const [selectedIdsArr, setSelectedIdsArr] = React.useState([]);
26458
+ const selectedCacheRef = React.useRef(/* @__PURE__ */ new Map());
26459
+ const reqIdRef = React.useRef(0);
26460
+ const timerRef = React.useRef(null);
26461
+ const didMountRef = React.useRef(false);
26462
+ const skipNextModeEffectRef = React.useRef(false);
26463
+ const inlineDef = React.useMemo(() => {
26464
+ var _a2;
26465
+ return makeInlineDef({
26466
+ id: opts.id,
26467
+ endpoint: opts.endpoint,
26468
+ method: (_a2 = opts.method) != null ? _a2 : "GET",
26469
+ selector: opts.selector,
26470
+ buildRequest: opts.buildRequest,
26471
+ search: opts.search
26472
+ });
26473
+ }, [
26474
+ opts.id,
26475
+ opts.endpoint,
26476
+ opts.method,
26477
+ opts.selector,
26478
+ opts.buildRequest,
26479
+ opts.search
26480
+ ]);
26481
+ const dataById = React.useMemo(() => {
26482
+ const map = /* @__PURE__ */ new Map();
26483
+ if (selectionMode === "none") return map;
26484
+ for (const item of data) {
26485
+ const k2 = getItemKey(item);
26486
+ if (k2 == null) continue;
26487
+ map.set(k2, item);
26488
+ }
26489
+ return map;
26490
+ }, [data, getItemKey, selectionMode]);
26491
+ const normalizeIds = React.useCallback((v2) => {
26492
+ return Array.isArray(v2) ? v2 : [v2];
26493
+ }, []);
26494
+ const commitSelectedCache = React.useCallback(
26495
+ (list) => {
26496
+ if (selectionMode === "none") return;
26497
+ for (const item of list) {
26498
+ const k2 = getItemKey(item);
26499
+ if (k2 == null) continue;
26500
+ selectedCacheRef.current.set(k2, item);
26501
+ }
26502
+ },
26503
+ [getItemKey, selectionMode]
26504
+ );
26505
+ const fetchImpl = React.useCallback(
26506
+ async (override) => {
26507
+ var _a2, _b2, _c2, _d2, _e2, _f2;
26508
+ if (!enabled) return data;
26509
+ const q2 = (_a2 = override == null ? void 0 : override.query) != null ? _a2 : query;
26510
+ const f2 = (_b2 = override == null ? void 0 : override.filters) != null ? _b2 : filters;
26511
+ const t4 = (_c2 = override == null ? void 0 : override.searchTarget) != null ? _c2 : searchTarget;
26512
+ const myReq = ++reqIdRef.current;
26513
+ setLoading(true);
26514
+ setError(void 0);
26515
+ try {
26516
+ const payload = (_d2 = override == null ? void 0 : override.search) != null ? _d2 : buildSearchPayloadFromTarget(t4);
26517
+ const res = await ctx.apiFetchAny(inlineDef, f2, {
26518
+ query: q2,
26519
+ search: payload
26520
+ });
26521
+ const list = (_f2 = (_e2 = res == null ? void 0 : res.rawList) != null ? _e2 : res == null ? void 0 : res.raw) != null ? _f2 : [];
26522
+ commitSelectedCache(list);
26523
+ if (selectionMode !== "none" && selectionPrune === "missing") {
26524
+ const nextIds = /* @__PURE__ */ new Set();
26525
+ for (const item of list) {
26526
+ const k2 = getItemKey(item);
26527
+ if (k2 != null) nextIds.add(k2);
26528
+ }
26529
+ setSelectedIdsArr(
26530
+ (prev) => prev.filter((x2) => nextIds.has(x2))
26531
+ );
26532
+ }
26533
+ if (reqIdRef.current !== myReq) return list;
26534
+ setData(list);
26535
+ setLoading(false);
26536
+ return list;
26537
+ } catch (e4) {
26538
+ if (reqIdRef.current !== myReq) return data;
26539
+ setError(e4);
26540
+ setLoading(false);
26541
+ return data;
26542
+ }
26543
+ },
26544
+ [
26545
+ commitSelectedCache,
26546
+ ctx,
26547
+ data,
26548
+ enabled,
26549
+ filters,
26550
+ getItemKey,
26551
+ inlineDef,
26552
+ query,
26553
+ searchTarget,
26554
+ selectionMode,
26555
+ selectionPrune
26556
+ ]
26557
+ );
26558
+ const refresh = React.useCallback(() => {
26559
+ void fetchImpl();
26560
+ }, [fetchImpl]);
26561
+ const setQuery = React.useCallback((q2) => _setQuery(q2), []);
26562
+ const setSearchMode = React.useCallback(
26563
+ (m2) => {
26564
+ if (timerRef.current) clearTimeout(timerRef.current);
26565
+ if (m2 === "remote" || m2 === "hybrid") {
26566
+ skipNextModeEffectRef.current = true;
26567
+ _setSearchMode(m2);
26568
+ void fetchImpl();
26569
+ return;
26570
+ }
26571
+ _setSearchMode(m2);
26572
+ if (m2 === "local") {
26573
+ void fetchImpl({
26574
+ query: "",
26575
+ search: void 0
26576
+ });
26577
+ }
26578
+ },
26579
+ [fetchImpl]
26580
+ );
26581
+ const setSearchTarget = React.useCallback(
26582
+ (t4) => {
26583
+ _setSearchTarget(t4);
26584
+ if (searchMode === "remote" || searchMode === "hybrid") {
26585
+ if (timerRef.current) clearTimeout(timerRef.current);
26586
+ timerRef.current = setTimeout(() => {
26587
+ void fetchImpl({ searchTarget: t4 });
26588
+ }, debounceMs);
26589
+ }
26590
+ },
26591
+ [debounceMs, fetchImpl, searchMode]
26592
+ );
26593
+ const setFilters = React.useCallback(
26594
+ (next) => _setFilters(next),
26595
+ []
26596
+ );
26597
+ const patchFilters = React.useCallback((patch) => {
26598
+ _setFilters((prev) => ({
26599
+ ...prev != null ? prev : {},
26600
+ ...patch
26601
+ }));
26602
+ }, []);
26603
+ const clearFilters = React.useCallback(() => _setFilters(void 0), []);
26604
+ const fetchOnMount = (_i = opts.fetchOnMount) != null ? _i : !opts.initial;
26605
+ React.useEffect(() => {
26606
+ if (!enabled) return;
26607
+ if (!fetchOnMount) return;
26608
+ void fetchImpl();
26609
+ }, []);
26610
+ React.useEffect(() => {
26611
+ if (!enabled) return;
26612
+ if (!didMountRef.current) {
26613
+ didMountRef.current = true;
26614
+ return;
26615
+ }
26616
+ if (searchMode !== "remote" && searchMode !== "hybrid") return;
26617
+ if (skipNextModeEffectRef.current) {
26618
+ skipNextModeEffectRef.current = false;
26619
+ return;
26620
+ }
26621
+ if (timerRef.current) clearTimeout(timerRef.current);
26622
+ timerRef.current = setTimeout(() => {
26623
+ void fetchImpl();
26624
+ }, debounceMs);
26625
+ return () => {
26626
+ if (timerRef.current) clearTimeout(timerRef.current);
26627
+ };
26628
+ }, [debounceMs, enabled, fetchImpl, query, searchMode, searchTarget]);
26629
+ React.useEffect(() => {
26630
+ if (!enabled) return;
26631
+ if (opts.autoFetchOnFilterChange === false) return;
26632
+ if (!didMountRef.current) return;
26633
+ if (searchMode !== "remote" && searchMode !== "hybrid") return;
26634
+ void fetchImpl();
26635
+ }, [enabled, fetchImpl, filters, opts.autoFetchOnFilterChange, searchMode]);
26636
+ const visible = React.useMemo(() => {
26637
+ if (searchMode !== "local" && searchMode !== "hybrid") return data;
26638
+ const payload = buildSearchPayloadFromTarget(searchTarget);
26639
+ let list = data;
26640
+ if ((payload == null ? void 0 : payload.searchOnly) && payload.searchOnly.length) {
26641
+ const allow = new Set(payload.searchOnly);
26642
+ list = list.filter((item) => {
26643
+ const k2 = getItemKey(item);
26644
+ return k2 != null && allow.has(k2);
26645
+ });
26646
+ }
26647
+ const q2 = query.trim();
26648
+ if (!q2) return list;
26649
+ const ql = q2.toLowerCase();
26650
+ if (payload == null ? void 0 : payload.subject) {
26651
+ const key = payload.subject;
26652
+ return list.filter(
26653
+ (item) => {
26654
+ var _a2;
26655
+ return String((_a2 = item == null ? void 0 : item[key]) != null ? _a2 : "").toLowerCase().includes(ql);
26656
+ }
26657
+ );
26658
+ }
26659
+ return list.filter(
26660
+ (item) => String(item != null ? item : "").toLowerCase().includes(ql)
26661
+ );
26662
+ }, [data, getItemKey, query, searchMode, searchTarget]);
26663
+ const selectedIds = React.useMemo(() => {
26664
+ var _a2;
26665
+ if (selectionMode === "none") return null;
26666
+ if (selectionMode === "single") return (_a2 = selectedIdsArr[0]) != null ? _a2 : null;
26667
+ return selectedIdsArr;
26668
+ }, [selectionMode, selectedIdsArr]);
26669
+ const isSelected = React.useCallback(
26670
+ (id) => {
26671
+ if (selectionMode === "none") return false;
26672
+ return selectedIdsArr.includes(id);
26673
+ },
26674
+ [selectedIdsArr, selectionMode]
26675
+ );
26676
+ const clearSelection = React.useCallback(() => {
26677
+ if (selectionMode === "none") return;
26678
+ setSelectedIdsArr([]);
26679
+ }, [selectionMode]);
26680
+ const select = React.useCallback(
26681
+ (idOrIds) => {
26682
+ if (selectionMode === "none") return;
26683
+ const ids = normalizeIds(idOrIds).filter(isKey);
26684
+ if (!ids.length) return;
26685
+ for (const id of ids) {
26686
+ const hit = dataById.get(id);
26687
+ if (hit) selectedCacheRef.current.set(id, hit);
26688
+ }
26689
+ if (selectionMode === "single") {
26690
+ setSelectedIdsArr([ids[0]]);
26691
+ return;
26692
+ }
26693
+ setSelectedIdsArr((prev) => {
26694
+ const set = new Set(prev);
26695
+ for (const id of ids) set.add(id);
26696
+ return Array.from(set);
26697
+ });
26698
+ },
26699
+ [dataById, normalizeIds, selectionMode]
26700
+ );
26701
+ const deselect = React.useCallback(
26702
+ (idOrIds) => {
26703
+ if (selectionMode === "none") return;
26704
+ const ids = new Set(normalizeIds(idOrIds).filter(isKey));
26705
+ if (!ids.size) return;
26706
+ setSelectedIdsArr((prev) => {
26707
+ const next = prev.filter((x2) => !ids.has(x2));
26708
+ if (selectionMode === "single") return next.slice(0, 1);
26709
+ return next;
26710
+ });
26711
+ },
26712
+ [normalizeIds, selectionMode]
26713
+ );
26714
+ const toggle = React.useCallback(
26715
+ (id) => {
26716
+ if (selectionMode === "none") return;
26717
+ const hit = dataById.get(id);
26718
+ if (hit) selectedCacheRef.current.set(id, hit);
26719
+ if (selectionMode === "single") {
26720
+ setSelectedIdsArr((prev) => prev[0] === id ? [] : [id]);
26721
+ return;
26722
+ }
26723
+ setSelectedIdsArr((prev) => {
26724
+ const set = new Set(prev);
26725
+ if (set.has(id)) set.delete(id);
26726
+ else set.add(id);
26727
+ return Array.from(set);
26728
+ });
26729
+ },
26730
+ [dataById, selectionMode]
26731
+ );
26732
+ const selected = React.useMemo(() => {
26733
+ var _a2, _b2, _c2, _d2;
26734
+ if (selectionMode === "none") return null;
26735
+ if (selectionMode === "single") {
26736
+ const id = selectedIdsArr[0];
26737
+ if (id == null) return null;
26738
+ return (_b2 = (_a2 = dataById.get(id)) != null ? _a2 : selectedCacheRef.current.get(id)) != null ? _b2 : null;
26739
+ }
26740
+ const out = [];
26741
+ for (const id of selectedIdsArr) {
26742
+ const item = (_d2 = (_c2 = dataById.get(id)) != null ? _c2 : selectedCacheRef.current.get(id)) != null ? _d2 : null;
26743
+ if (item) out.push(item);
26744
+ }
26745
+ return out;
26746
+ }, [dataById, selectedIdsArr, selectionMode]);
26747
+ const getSelection = React.useCallback(() => selected, [selected]);
26748
+ React.useEffect(() => {
26749
+ if (selectionMode === "none") {
26750
+ setSelectedIdsArr([]);
26751
+ return;
26752
+ }
26753
+ if (selectionMode === "single") {
26754
+ setSelectedIdsArr((prev) => prev.length ? [prev[0]] : []);
26755
+ }
26756
+ }, [selectionMode]);
26757
+ return {
26758
+ id: opts.id,
26759
+ data,
26760
+ visible,
26761
+ loading,
26762
+ error,
26763
+ query,
26764
+ setQuery,
26765
+ searchMode,
26766
+ setSearchMode,
26767
+ searchTarget,
26768
+ setSearchTarget,
26769
+ filters,
26770
+ setFilters,
26771
+ patchFilters,
26772
+ clearFilters,
26773
+ selectionMode,
26774
+ selectedIds,
26775
+ selected,
26776
+ select,
26777
+ deselect,
26778
+ toggle,
26779
+ clearSelection,
26780
+ isSelected,
26781
+ getSelection,
26782
+ refresh,
26783
+ fetch: fetchImpl
26784
+ };
26785
+ }
26251
26786
  /*! Bundled license information:
26252
26787
 
26253
26788
  lucide-react/dist/esm/shared/src/utils.js:
@@ -26298,6 +26833,6 @@ lucide-react/dist/esm/lucide-react.js:
26298
26833
  *)
26299
26834
  */
26300
26835
 
26301
- export { FooterBar, HeaderBar, json_editor_default as JsonEditor, ListerProvider, ListerUI, OptionList, SearchBar, useLister };
26836
+ export { Ctx, FooterBar, HeaderBar, json_editor_default as JsonEditor, ListerProvider, ListerUI, OptionList, SearchBar, buildSearchPayloadFromTarget, useData, useLister };
26302
26837
  //# sourceMappingURL=extra.mjs.map
26303
26838
  //# sourceMappingURL=extra.mjs.map