@victorylabs/params 0.1.0 → 0.3.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.
Files changed (37) hide show
  1. package/dist/{chunk-NUO3GOXV.js → chunk-5UKBDZTP.js} +37 -2
  2. package/dist/chunk-5UKBDZTP.js.map +1 -0
  3. package/dist/{chunk-43PUAYQP.js → chunk-DSAHBEAQ.js} +44 -18
  4. package/dist/chunk-DSAHBEAQ.js.map +1 -0
  5. package/dist/devtools.d.cts +1 -1
  6. package/dist/devtools.d.ts +1 -1
  7. package/dist/index.cjs +79 -17
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +47 -11
  10. package/dist/index.d.ts +47 -11
  11. package/dist/index.js +5 -3
  12. package/dist/index.js.map +1 -1
  13. package/dist/integrations/forms-reverse.cjs +71 -17
  14. package/dist/integrations/forms-reverse.cjs.map +1 -1
  15. package/dist/integrations/forms-reverse.js +2 -2
  16. package/dist/integrations/forms.cjs +71 -17
  17. package/dist/integrations/forms.cjs.map +1 -1
  18. package/dist/integrations/forms.js +2 -2
  19. package/dist/{params-store-Cgbtn53j.d.cts → params-store-4Lcb1M_X.d.cts} +29 -1
  20. package/dist/{params-store-CguA9-yr.d.ts → params-store-f3pmPdw3.d.ts} +29 -1
  21. package/dist/react.cjs +127 -54
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.cts +42 -4
  24. package/dist/react.d.ts +42 -4
  25. package/dist/react.js +38 -20
  26. package/dist/react.js.map +1 -1
  27. package/dist/storage/idb.cjs +56 -3
  28. package/dist/storage/idb.cjs.map +1 -1
  29. package/dist/storage/idb.d.cts +40 -8
  30. package/dist/storage/idb.d.ts +40 -8
  31. package/dist/storage/idb.js +56 -3
  32. package/dist/storage/idb.js.map +1 -1
  33. package/dist/storage/url.cjs.map +1 -1
  34. package/dist/storage/url.js +1 -1
  35. package/package.json +3 -2
  36. package/dist/chunk-43PUAYQP.js.map +0 -1
  37. package/dist/chunk-NUO3GOXV.js.map +0 -1
package/dist/react.cjs CHANGED
@@ -20,14 +20,30 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/react/index.ts
21
21
  var react_exports = {};
22
22
  __export(react_exports, {
23
+ useDebouncedValue: () => useDebouncedValue,
23
24
  useFieldInput: () => useFieldInput,
24
25
  useFieldValue: () => useFieldValue,
25
26
  useParams: () => useParams
26
27
  });
27
28
  module.exports = __toCommonJS(react_exports);
28
29
 
30
+ // src/react/use-debounced-value.ts
31
+ var import_react = require("react");
32
+ function useDebouncedValue(value, ms) {
33
+ const [debounced, setDebounced] = (0, import_react.useState)(value);
34
+ (0, import_react.useEffect)(() => {
35
+ if (ms <= 0) {
36
+ setDebounced(value);
37
+ return;
38
+ }
39
+ const id = setTimeout(() => setDebounced(value), ms);
40
+ return () => clearTimeout(id);
41
+ }, [value, ms]);
42
+ return debounced;
43
+ }
44
+
29
45
  // src/react/use-field-input.tsx
30
- var import_react2 = require("react");
46
+ var import_react3 = require("react");
31
47
 
32
48
  // src/schema.ts
33
49
  function isStandardSchema(spec) {
@@ -72,7 +88,8 @@ function defaultSerialize(value) {
72
88
  if (typeof value === "number") return Number.isFinite(value) ? String(value) : "";
73
89
  return JSON.stringify(value);
74
90
  }
75
- function extractEnumValues(spec) {
91
+ var customExtractors = /* @__PURE__ */ new Set();
92
+ var extractZodEnum = (spec) => {
76
93
  let current = spec;
77
94
  for (let i = 0; i < 8 && current !== null && typeof current === "object"; i++) {
78
95
  const def = current._def;
@@ -90,13 +107,40 @@ function extractEnumValues(spec) {
90
107
  return void 0;
91
108
  }
92
109
  return void 0;
110
+ };
111
+ var extractValibotEnum = (spec) => {
112
+ let current = spec;
113
+ for (let i = 0; i < 8 && current !== null && typeof current === "object"; i++) {
114
+ if (current.kind !== "schema" || typeof current.type !== "string") return void 0;
115
+ if (current.type === "picklist" || current.type === "enum") {
116
+ return Array.isArray(current.options) ? current.options : void 0;
117
+ }
118
+ if (current.wrapped) {
119
+ current = current.wrapped;
120
+ continue;
121
+ }
122
+ return void 0;
123
+ }
124
+ return void 0;
125
+ };
126
+ var builtInExtractors = [extractZodEnum, extractValibotEnum];
127
+ function extractEnumValues(spec) {
128
+ for (const extractor of customExtractors) {
129
+ const result = extractor(spec);
130
+ if (result !== void 0) return result;
131
+ }
132
+ for (const extractor of builtInExtractors) {
133
+ const result = extractor(spec);
134
+ if (result !== void 0) return result;
135
+ }
136
+ return void 0;
93
137
  }
94
138
 
95
139
  // src/react/use-field-value.ts
96
- var import_react = require("react");
140
+ var import_react2 = require("react");
97
141
  function useFieldValue(store, path) {
98
- const [, forceRender] = (0, import_react.useReducer)((tick) => tick + 1, 0);
99
- (0, import_react.useEffect)(() => store.subscribe(path, forceRender), [store, path]);
142
+ const [, forceRender] = (0, import_react2.useReducer)((tick) => tick + 1, 0);
143
+ (0, import_react2.useEffect)(() => store.subscribe(path, forceRender), [store, path]);
100
144
  return store.getValue(path);
101
145
  }
102
146
 
@@ -105,10 +149,10 @@ function useFieldInput(store, path) {
105
149
  const storeValue = useFieldValue(store, path);
106
150
  const config = store.getFieldConfig(path);
107
151
  const debounceMs = config?.debounce ?? 0;
108
- const [shadow, setShadow] = (0, import_react2.useState)(null);
109
- const debouncerRef = (0, import_react2.useRef)(null);
110
- const lastStoreValueRef = (0, import_react2.useRef)(storeValue);
111
- (0, import_react2.useEffect)(() => {
152
+ const [shadow, setShadow] = (0, import_react3.useState)(null);
153
+ const debouncerRef = (0, import_react3.useRef)(null);
154
+ const lastStoreValueRef = (0, import_react3.useRef)(storeValue);
155
+ (0, import_react3.useEffect)(() => {
112
156
  if (Object.is(lastStoreValueRef.current, storeValue)) return;
113
157
  lastStoreValueRef.current = storeValue;
114
158
  if (shadow !== null && shadow !== defaultSerialize(storeValue)) {
@@ -119,19 +163,19 @@ function useFieldInput(store, path) {
119
163
  if (debounceMs > 0 && debouncerRef.current === null) {
120
164
  debouncerRef.current = createDebouncer(store, path, debounceMs, () => setShadow(null));
121
165
  }
122
- const onChange = (0, import_react2.useCallback)(
166
+ const onChange = (0, import_react3.useCallback)(
123
167
  (event) => {
124
168
  const next = event.target.value;
125
169
  if (debounceMs > 0) {
126
170
  setShadow(next);
127
171
  debouncerRef.current?.trigger(next);
128
172
  } else {
129
- store.set(path, next);
173
+ store.setField(path, next);
130
174
  }
131
175
  },
132
176
  [store, path, debounceMs]
133
177
  );
134
- const onBlur = (0, import_react2.useCallback)(() => {
178
+ const onBlur = (0, import_react3.useCallback)(() => {
135
179
  debouncerRef.current?.flush();
136
180
  }, []);
137
181
  return {
@@ -146,7 +190,7 @@ function createDebouncer(store, path, ms, onCommit) {
146
190
  let pendingValue = null;
147
191
  const commit = () => {
148
192
  if (pendingValue !== null) {
149
- store.set(path, pendingValue);
193
+ store.setField(path, pendingValue);
150
194
  pendingValue = null;
151
195
  onCommit();
152
196
  }
@@ -174,10 +218,10 @@ function createDebouncer(store, path, ms, onCommit) {
174
218
  }
175
219
 
176
220
  // src/react/use-params.tsx
177
- var import_react4 = require("react");
221
+ var import_react5 = require("react");
178
222
 
179
223
  // src/react/use-shared-store.ts
180
- var import_react3 = require("react");
224
+ var import_react4 = require("react");
181
225
 
182
226
  // src/dev.ts
183
227
  var isDev = (() => {
@@ -457,17 +501,43 @@ var ParamsStore = class {
457
501
  getFieldConfig(path) {
458
502
  return this.fieldConfigs[path];
459
503
  }
460
- set(pathOrPartial, valueOrOptions, maybeOptions) {
504
+ // ─── Writes ───────────────────────────────────────────────────────────
505
+ /**
506
+ * Apply a partial update — write multiple fields at once.
507
+ *
508
+ * `set(partial)` is the canonical write form. The path-and-value form
509
+ * (`set(path, value)` historically) is now `setField(path, value)` —
510
+ * see {@link setField}. The split keeps `set`'s single-signature
511
+ * inference clean for the common `set({ [key]: value })` pattern, which
512
+ * previously required `as Partial<T>` casts because TypeScript couldn't
513
+ * resolve the overload from a generic-keyed object literal.
514
+ *
515
+ * @example
516
+ * ```ts
517
+ * p.set({ page: 1, sort: 'updated' })
518
+ * p.set({ [key]: value }) // works without a cast now
519
+ * ```
520
+ */
521
+ set(partial, options) {
461
522
  if (this.disposed) return;
462
- let updates;
463
- let options;
464
- if (typeof pathOrPartial === "string") {
465
- updates = { [pathOrPartial]: valueOrOptions };
466
- options = maybeOptions;
467
- } else {
468
- updates = pathOrPartial;
469
- options = valueOrOptions;
470
- }
523
+ this.applyUpdates(partial, options);
524
+ }
525
+ /**
526
+ * Write a single field by path. Equivalent to `set({ [path]: value })`
527
+ * but skips the object-literal allocation and avoids the inference issue
528
+ * that motivated splitting the API.
529
+ *
530
+ * @example
531
+ * ```ts
532
+ * p.setField('query', 'react')
533
+ * p.setField('filters.tags', ['ts', 'react'])
534
+ * ```
535
+ */
536
+ setField(path, value, options) {
537
+ if (this.disposed) return;
538
+ this.applyUpdates({ [path]: value }, options);
539
+ }
540
+ applyUpdates(updates, options) {
471
541
  const initialChanges = {};
472
542
  for (const [path, v] of Object.entries(updates)) {
473
543
  const old = deepGet(this.values, path);
@@ -499,13 +569,13 @@ var ParamsStore = class {
499
569
  /** Boolean-flip helper. */
500
570
  toggle(path, options) {
501
571
  const current = this.getValue(path);
502
- this.set(path, !current, options);
572
+ this.setField(path, !current, options);
503
573
  }
504
574
  /** Push a value onto an array field. */
505
575
  append(path, value, options) {
506
576
  const current = this.getValue(path);
507
577
  if (!Array.isArray(current)) return;
508
- this.set(path, [...current, value], options);
578
+ this.setField(path, [...current, value], options);
509
579
  }
510
580
  /** Remove the first array element matching `value` by deepEqual. */
511
581
  remove(path, value, options) {
@@ -513,14 +583,14 @@ var ParamsStore = class {
513
583
  if (!Array.isArray(current)) return;
514
584
  const idx = current.findIndex((item) => deepEqual(item, value));
515
585
  if (idx === -1) return;
516
- this.set(path, [...current.slice(0, idx), ...current.slice(idx + 1)], options);
586
+ this.setField(path, [...current.slice(0, idx), ...current.slice(idx + 1)], options);
517
587
  }
518
588
  /** Remove the array element at the given index. */
519
589
  removeAt(path, index, options) {
520
590
  const current = this.getValue(path);
521
591
  if (!Array.isArray(current)) return;
522
592
  if (index < 0 || index >= current.length) return;
523
- this.set(path, [...current.slice(0, index), ...current.slice(index + 1)], options);
593
+ this.setField(path, [...current.slice(0, index), ...current.slice(index + 1)], options);
524
594
  }
525
595
  cycle(path, valuesOrOptions, maybeOptions) {
526
596
  let resolved;
@@ -546,12 +616,12 @@ var ParamsStore = class {
546
616
  const current = this.getValue(path);
547
617
  const idx = resolved.findIndex((o) => deepEqual(o, current));
548
618
  const next = idx === -1 ? resolved[0] : resolved[(idx + 1) % resolved.length];
549
- this.set(path, next, setOpts);
619
+ this.setField(path, next, setOpts);
550
620
  }
551
621
  /** Reset a single field to its default. */
552
622
  clear(path, options) {
553
623
  const def = deepGet(this.defaults, path);
554
- this.set(path, def, options);
624
+ this.setField(path, def, options);
555
625
  }
556
626
  /** Reset all fields to defaults; optional partial overrides + SetOptions. */
557
627
  reset(values, options) {
@@ -805,11 +875,11 @@ function warnOnDuplicateName(def) {
805
875
 
806
876
  // src/react/use-shared-store.ts
807
877
  function useSharedStore(def) {
808
- const storeRef = (0, import_react3.useRef)(null);
878
+ const storeRef = (0, import_react4.useRef)(null);
809
879
  if (storeRef.current === null) {
810
880
  storeRef.current = acquire(def);
811
881
  }
812
- (0, import_react3.useEffect)(
882
+ (0, import_react4.useEffect)(
813
883
  () => () => {
814
884
  release(def);
815
885
  storeRef.current = null;
@@ -822,35 +892,33 @@ function useSharedStore(def) {
822
892
  // src/react/use-params.tsx
823
893
  function useParams(def) {
824
894
  const store = useSharedStore(def);
825
- const [, forceRender] = (0, import_react4.useReducer)((tick) => tick + 1, 0);
826
- (0, import_react4.useEffect)(() => store.subscribe("", forceRender), [store]);
827
- const set = (0, import_react4.useCallback)(
828
- ((pathOrPartial, valueOrOptions, maybeOptions) => {
829
- if (typeof pathOrPartial === "string") {
830
- store.set(pathOrPartial, valueOrOptions, maybeOptions);
831
- } else {
832
- store.set(pathOrPartial, valueOrOptions);
833
- }
834
- }),
895
+ const [, forceRender] = (0, import_react5.useReducer)((tick) => tick + 1, 0);
896
+ (0, import_react5.useEffect)(() => store.subscribe("", forceRender), [store]);
897
+ const set = (0, import_react5.useCallback)(
898
+ (partial, options) => store.set(partial, options),
899
+ [store]
900
+ );
901
+ const setField = (0, import_react5.useCallback)(
902
+ (path, value2, options) => store.setField(path, value2, options),
835
903
  [store]
836
904
  );
837
- const toggle = (0, import_react4.useCallback)(
905
+ const toggle = (0, import_react5.useCallback)(
838
906
  (path, options) => store.toggle(path, options),
839
907
  [store]
840
908
  );
841
- const append = (0, import_react4.useCallback)(
909
+ const append = (0, import_react5.useCallback)(
842
910
  (path, value2, options) => store.append(path, value2, options),
843
911
  [store]
844
912
  );
845
- const removeFn = (0, import_react4.useCallback)(
913
+ const removeFn = (0, import_react5.useCallback)(
846
914
  (path, value2, options) => store.remove(path, value2, options),
847
915
  [store]
848
916
  );
849
- const removeAt = (0, import_react4.useCallback)(
917
+ const removeAt = (0, import_react5.useCallback)(
850
918
  (path, index, options) => store.removeAt(path, index, options),
851
919
  [store]
852
920
  );
853
- const cycle = (0, import_react4.useCallback)(
921
+ const cycle = (0, import_react5.useCallback)(
854
922
  ((path, valuesOrOptions, maybeOptions) => {
855
923
  if (Array.isArray(valuesOrOptions)) {
856
924
  store.cycle(path, valuesOrOptions, maybeOptions);
@@ -862,32 +930,36 @@ function useParams(def) {
862
930
  }),
863
931
  [store]
864
932
  );
865
- const clear = (0, import_react4.useCallback)(
933
+ const clear = (0, import_react5.useCallback)(
866
934
  (path, options) => store.clear(path, options),
867
935
  [store]
868
936
  );
869
- const reset = (0, import_react4.useCallback)(
937
+ const reset = (0, import_react5.useCallback)(
870
938
  (values, options) => store.reset(values, options),
871
939
  [store]
872
940
  );
873
- const subscribe = (0, import_react4.useCallback)(
941
+ const subscribe = (0, import_react5.useCallback)(
874
942
  (path, listener) => store.subscribe(path, listener),
875
943
  [store]
876
944
  );
877
- const toQuery = (0, import_react4.useCallback)(
945
+ const toQuery = (0, import_react5.useCallback)(
878
946
  (overrides) => store.toQuery(overrides),
879
947
  [store]
880
948
  );
881
- const href = (0, import_react4.useCallback)((overrides) => store.href(overrides), [store]);
949
+ const href = (0, import_react5.useCallback)((overrides) => store.href(overrides), [store]);
882
950
  const value = (path) => useFieldValue(store, path);
883
- const deferred = (path) => (0, import_react4.useDeferredValue)(useFieldValue(store, path));
951
+ const deferred = (path) => (0, import_react5.useDeferredValue)(useFieldValue(store, path));
884
952
  const input = (path) => useFieldInput(store, path);
885
953
  return {
954
+ // Cast: store.getValues() returns Partial<T> for the storage layer's
955
+ // sake, but every field in ParamsDefinition declares a default so the
956
+ // hydrated view is structurally complete. See ParamsController.values.
886
957
  values: store.getValues(),
887
958
  value,
888
959
  deferred,
889
960
  input,
890
961
  set,
962
+ setField,
891
963
  toggle,
892
964
  append,
893
965
  remove: removeFn,
@@ -903,6 +975,7 @@ function useParams(def) {
903
975
  }
904
976
  // Annotate the CommonJS export names for ESM import in node:
905
977
  0 && (module.exports = {
978
+ useDebouncedValue,
906
979
  useFieldInput,
907
980
  useFieldValue,
908
981
  useParams