vue-context-storage 0.1.7 → 0.1.9

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.
@@ -1,8 +1,8 @@
1
- import { ContextStorageHandlerConstructor } from '../../handlers';
2
- import { contextStorageQueryHandler } from '../../symbols';
1
+ import { ContextStorageHandlerConstructor } from '../../handlers.ts';
2
+ import { contextStorageQueryHandler } from '../../symbols.ts';
3
3
  import { MaybeRefOrGetter } from 'vue';
4
4
  import { LocationQuery } from 'vue-router';
5
- import { ContextStorageQueryRegisteredItem, IContextStorageQueryHandler, QueryHandlerBaseOptions, RegisterQueryHandlerBaseOptions, RegisterQueryHandlerOptions } from './types';
5
+ import { ContextStorageQueryRegisteredItem, IContextStorageQueryHandler, QueryHandlerBaseOptions, RegisterQueryHandlerBaseOptions, RegisterQueryHandlerOptions } from './types.ts';
6
6
  export declare function useContextStorageQueryHandler<T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options?: RegisterQueryHandlerBaseOptions<T>): void;
7
7
  export declare class ContextStorageQueryHandler implements IContextStorageQueryHandler {
8
8
  #private;
@@ -1,8 +1,8 @@
1
- import { ContextStorageHandlerConstructor } from '../../handlers';
2
- import { contextStorageQueryHandler } from '../../symbols';
1
+ import { ContextStorageHandlerConstructor } from '../../handlers.ts';
2
+ import { contextStorageQueryHandler } from '../../symbols.ts';
3
3
  import { MaybeRefOrGetter } from 'vue';
4
4
  import { LocationQuery } from 'vue-router';
5
- import { ContextStorageQueryRegisteredItem, IContextStorageQueryHandler, QueryHandlerBaseOptions, RegisterQueryHandlerBaseOptions, RegisterQueryHandlerOptions } from './types';
5
+ import { ContextStorageQueryRegisteredItem, IContextStorageQueryHandler, QueryHandlerBaseOptions, RegisterQueryHandlerBaseOptions, RegisterQueryHandlerOptions } from './types.ts';
6
6
  export declare function useContextStorageQueryHandler<T extends Record<string, unknown>>(data: MaybeRefOrGetter<T>, options?: RegisterQueryHandlerBaseOptions<T>): void;
7
7
  export declare class ContextStorageQueryHandler implements IContextStorageQueryHandler {
8
8
  #private;
@@ -1,4 +1,4 @@
1
- import { QueryValue } from './types';
1
+ import { QueryValue } from './types.ts';
2
2
  export declare function asNumber(value: QueryValue | number | undefined): number;
3
3
  export declare function asNumber(value: QueryValue | number | undefined, options: {
4
4
  nullable: true;
@@ -1,4 +1,4 @@
1
- import { QueryValue } from './types';
1
+ import { QueryValue } from './types.ts';
2
2
  export declare function asNumber(value: QueryValue | number | undefined): number;
3
3
  export declare function asNumber(value: QueryValue | number | undefined, options: {
4
4
  nullable: true;
@@ -1,6 +1,6 @@
1
1
  import { LocationQueryValue } from 'vue-router';
2
2
  import { MaybeRefOrGetter, UnwrapNestedRefs, WatchHandle } from 'vue';
3
- import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers';
3
+ import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers.ts';
4
4
  export type QueryValue = LocationQueryValue | LocationQueryValue[];
5
5
  export type DeepTransformValuesToLocationQueryValue<T> = {
6
6
  [K in keyof T]?: T[K] extends object ? T[K] extends Array<any> ? QueryValue : DeepTransformValuesToLocationQueryValue<T[K]> : QueryValue;
@@ -1,6 +1,6 @@
1
1
  import { LocationQueryValue } from 'vue-router';
2
2
  import { MaybeRefOrGetter, UnwrapNestedRefs, WatchHandle } from 'vue';
3
- import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers';
3
+ import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers.ts';
4
4
  export type QueryValue = LocationQueryValue | LocationQueryValue[];
5
5
  export type DeepTransformValuesToLocationQueryValue<T> = {
6
6
  [K in keyof T]?: T[K] extends object ? T[K] extends Array<any> ? QueryValue : DeepTransformValuesToLocationQueryValue<T[K]> : QueryValue;
package/dist/index.cjs CHANGED
@@ -21,7 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  }) : target, mod));
22
22
 
23
23
  //#endregion
24
- const lodash_es = __toESM(require("lodash-es"));
24
+ const lodash = __toESM(require("lodash"));
25
25
  const vue = __toESM(require("vue"));
26
26
  const vue_router = __toESM(require("vue-router"));
27
27
 
@@ -197,7 +197,7 @@ var ContextStorageQueryHandler = class ContextStorageQueryHandler {
197
197
  if (this.preventSyncRegisteredToQueryByAfterEachRoute) return;
198
198
  const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered();
199
199
  this.currentQuery = newQueryRaw;
200
- if ((0, lodash_es.isEqual)(newQuery, this.route.query)) return;
200
+ if ((0, lodash.isEqual)(newQuery, this.route.query)) return;
201
201
  this.preventAfterEachRouteCallsWhileCallingRouter = true;
202
202
  try {
203
203
  if (this.options.mode === "replace") await this.router.replace({
@@ -246,15 +246,15 @@ var ContextStorageQueryHandler = class ContextStorageQueryHandler {
246
246
  * This can happen when directly navigating to a route, for example through a menu item.
247
247
  */
248
248
  if (!deserializedKeys.length) {
249
- (0, lodash_es.merge)(itemData, item.initialData);
249
+ (0, lodash.merge)(itemData, item.initialData);
250
250
  return;
251
251
  }
252
252
  if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) delete deserialized[this.options.emptyPlaceholder];
253
253
  }
254
254
  if (item.options?.transform) deserialized = item.options.transform(deserialized, item.initialData);
255
- else if (mergeOnlyExistingKeysWithoutTransform) deserialized = (0, lodash_es.pick)(deserialized, Object.keys(item.initialData));
256
- if ((0, lodash_es.isEqual)(itemData, deserialized)) return;
257
- (0, lodash_es.merge)(itemData, deserialized);
255
+ else if (mergeOnlyExistingKeysWithoutTransform) deserialized = (0, lodash.pick)(deserialized, Object.keys(item.initialData));
256
+ if ((0, lodash.isEqual)(itemData, deserialized)) return;
257
+ (0, lodash.merge)(itemData, deserialized);
258
258
  }
259
259
  syncInitialStateToRegistered() {
260
260
  this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item));
@@ -264,7 +264,7 @@ var ContextStorageQueryHandler = class ContextStorageQueryHandler {
264
264
  const watchHandle = (0, vue.watch)(data, () => this.syncRegisteredToQuery(), { deep: true });
265
265
  const item = {
266
266
  data,
267
- initialData: (0, lodash_es.cloneDeep)((0, vue.toValue)(data)),
267
+ initialData: (0, lodash.cloneDeep)((0, vue.toValue)(data)),
268
268
  options,
269
269
  watchHandle
270
270
  };
@@ -313,6 +313,171 @@ var ContextStorageQueryHandler = class ContextStorageQueryHandler {
313
313
  }
314
314
  };
315
315
 
316
+ //#endregion
317
+ //#region src/injectionSymbols.ts
318
+ const contextStorageCollectionInjectKey = collection;
319
+ const contextStorageCollectionItemInjectKey = collectionItem;
320
+ const contextStorageHandlersInjectKey = handlers;
321
+ const contextStorageQueryHandlerInjectKey = contextStorageQueryHandler;
322
+
323
+ //#endregion
324
+ //#region src/components/ContextStorageActivator.vue
325
+ const _sfc_main$3 = (0, vue.defineComponent)({ setup(_, { slots }) {
326
+ const collection$1 = (0, vue.inject)(contextStorageCollectionInjectKey);
327
+ const item = (0, vue.inject)(contextStorageCollectionItemInjectKey);
328
+ const onActivate = () => {
329
+ collection$1.setActive(item);
330
+ };
331
+ return () => (0, vue.h)("div", { onMousedown: onActivate }, slots.default?.());
332
+ } });
333
+ var ContextStorageActivator_default = _sfc_main$3;
334
+
335
+ //#endregion
336
+ //#region src/collection.ts
337
+ var ContextStorageCollection = class {
338
+ active = void 0;
339
+ collection = [];
340
+ onActiveChangeCallbacks = [];
341
+ constructor(handlerConstructors) {
342
+ this.handlerConstructors = handlerConstructors;
343
+ }
344
+ onActiveChange(callback) {
345
+ this.onActiveChangeCallbacks.push(callback);
346
+ }
347
+ first() {
348
+ return this.collection[0];
349
+ }
350
+ findItemByKey(key) {
351
+ return this.collection.find((item) => item.key === key);
352
+ }
353
+ add(options) {
354
+ const handlers$1 = this.handlerConstructors.map((constructor) => new constructor());
355
+ const item = {
356
+ handlers: handlers$1,
357
+ key: options.key
358
+ };
359
+ this.collection.push(item);
360
+ return item;
361
+ }
362
+ remove(removeItem) {
363
+ if (this.collection.indexOf(removeItem) === -1) throw new Error("[ContextStorage] Item not found in collection");
364
+ this.collection = this.collection.filter((item) => item !== removeItem);
365
+ if (this.active === removeItem && this.collection.length > 0) this.setActive(this.collection[this.collection.length - 1]);
366
+ }
367
+ setActive(activeItem) {
368
+ if (this.active === activeItem) return;
369
+ const hasActiveBefore = this.active !== void 0;
370
+ this.active = activeItem;
371
+ this.collection.forEach((item) => {
372
+ Object.values(item.handlers).forEach((handler) => {
373
+ if (handler.setEnabled) handler.setEnabled(item === activeItem, !hasActiveBefore);
374
+ });
375
+ });
376
+ this.onActiveChangeCallbacks.forEach((callback) => callback(activeItem));
377
+ }
378
+ };
379
+
380
+ //#endregion
381
+ //#region src/components/ContextStorageCollection.vue
382
+ const _sfc_main$2 = (0, vue.defineComponent)({
383
+ props: { handlers: {
384
+ type: Object,
385
+ default: defaultHandlers
386
+ } },
387
+ setup({ handlers: handlers$1 }, { slots }) {
388
+ const lastActive = (0, vue.computed)({
389
+ get: () => localStorage.getItem("context-storage-last-active") || "main",
390
+ set: (value) => localStorage.setItem("context-storage-last-active", value)
391
+ });
392
+ const router = (0, vue_router.useRouter)();
393
+ const initialNavigatorState = /* @__PURE__ */ new Map();
394
+ const initialNavigatorStateResolvers = /* @__PURE__ */ new Map();
395
+ handlers$1.forEach((handler) => {
396
+ if (!handler.getInitialStateResolver) return;
397
+ initialNavigatorStateResolvers.set(handler, handler.getInitialStateResolver());
398
+ });
399
+ router.isReady().then(() => {
400
+ initialNavigatorStateResolvers.forEach((resolver, handler) => {
401
+ initialNavigatorState.set(handler, resolver());
402
+ });
403
+ activateLastActiveItem();
404
+ });
405
+ const collection$1 = new ContextStorageCollection(handlers$1);
406
+ collection$1.onActiveChange((item) => {
407
+ lastActive.value = item.key;
408
+ });
409
+ (0, vue.provide)(contextStorageCollectionInjectKey, collection$1);
410
+ const activateInitialItem = (item) => {
411
+ item.handlers.forEach((handler) => {
412
+ const state = initialNavigatorState.get(handler.constructor);
413
+ if (!state) return;
414
+ handler.setInitialState?.(state);
415
+ });
416
+ collection$1.setActive(item);
417
+ };
418
+ const activateLastActiveItem = () => {
419
+ const lastActiveItem = collection$1.findItemByKey(lastActive.value);
420
+ if (lastActiveItem) {
421
+ activateInitialItem(lastActiveItem);
422
+ return;
423
+ }
424
+ const firstItem = collection$1.first();
425
+ if (!firstItem) throw new Error("[ContextStorage] Cannot find first item in collection");
426
+ activateInitialItem(firstItem);
427
+ };
428
+ return () => {
429
+ return slots.default?.();
430
+ };
431
+ }
432
+ });
433
+ var ContextStorageCollection_default = _sfc_main$2;
434
+
435
+ //#endregion
436
+ //#region src/components/ContextStorageProvider.vue
437
+ const _sfc_main$1 = (0, vue.defineComponent)({
438
+ props: { itemKey: {
439
+ type: String,
440
+ required: true
441
+ } },
442
+ setup(props, { slots }) {
443
+ const collection$1 = (0, vue.inject)(contextStorageCollectionInjectKey);
444
+ if (!collection$1) throw new Error("[ContextStorage] Context storage collection not found");
445
+ const item = collection$1.add({ key: props.itemKey });
446
+ (0, vue.provide)(contextStorageCollectionItemInjectKey, item);
447
+ (0, vue.provide)(contextStorageHandlersInjectKey, item.handlers);
448
+ item.handlers.forEach((handler) => {
449
+ (0, vue.provide)(handler.getInjectionKey(), handler);
450
+ });
451
+ (0, vue.onUnmounted)(() => {
452
+ collection$1.remove(item);
453
+ });
454
+ return () => slots.default?.();
455
+ }
456
+ });
457
+ var ContextStorageProvider_default = _sfc_main$1;
458
+
459
+ //#endregion
460
+ //#region src/components/ContextStorage.vue
461
+ const _sfc_main = /* @__PURE__ */ (0, vue.defineComponent)({
462
+ __name: "ContextStorage",
463
+ props: { handlers: { default: () => defaultHandlers } },
464
+ setup(__props) {
465
+ return (_ctx, _cache) => {
466
+ return (0, vue.openBlock)(), (0, vue.createBlock)(ContextStorageCollection_default, { handlers: __props.handlers }, {
467
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)(ContextStorageProvider_default, { "item-key": "main" }, {
468
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)(ContextStorageActivator_default, null, {
469
+ default: (0, vue.withCtx)(() => [(0, vue.renderSlot)(_ctx.$slots, "default")]),
470
+ _: 3
471
+ })]),
472
+ _: 3
473
+ })]),
474
+ _: 3
475
+ }, 8, ["handlers"]);
476
+ };
477
+ }
478
+ });
479
+ var ContextStorage_default = _sfc_main;
480
+
316
481
  //#endregion
317
482
  //#region src/handlers/query/transform-helpers.ts
318
483
  function asNumber(value, options) {
@@ -375,18 +540,15 @@ const transform = {
375
540
  asBoolean
376
541
  };
377
542
 
378
- //#endregion
379
- //#region src/injectionSymbols.ts
380
- const contextStorageCollectionInjectKey = collection;
381
- const contextStorageCollectionItemInjectKey = collectionItem;
382
- const contextStorageHandlersInjectKey = handlers;
383
- const contextStorageQueryHandlerInjectKey = contextStorageQueryHandler;
384
-
385
543
  //#endregion
386
544
  //#region src/index.ts
387
545
  const defaultHandlers = [ContextStorageQueryHandler];
388
546
 
389
547
  //#endregion
548
+ exports.ContextStorage = ContextStorage_default;
549
+ exports.ContextStorageActivator = ContextStorageActivator_default;
550
+ exports.ContextStorageCollection = ContextStorageCollection_default;
551
+ exports.ContextStorageProvider = ContextStorageProvider_default;
390
552
  exports.ContextStorageQueryHandler = ContextStorageQueryHandler;
391
553
  exports.asArray = asArray;
392
554
  exports.asBoolean = asBoolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["params: Record<string, unknown>","options: SerializeOptions","result: LocationQuery","params: Record<string, any>","collection: unique symbol","collectionItem: unique symbol","handlers: unique symbol","contextStorageQueryHandler: unique symbol","data: MaybeRefOrGetter<T>","options?: RegisterQueryHandlerBaseOptions<T>","query: LocationQuery","sorted: LocationQuery","options: QueryHandlerBaseOptions","state: Record<string, unknown> | undefined","state: boolean","initial: boolean","#buildQueryFromRegistered","item: ContextStorageQueryRegisteredItem<T>","options: RegisterQueryHandlerOptions<T>","newQueryRaw: LocationQuery","value: QueryValue | number | undefined","options?: AsNumberOptions","value: QueryValue | undefined","options?: AsStringOptions","options?: AsNumberArrayOptions","arrayValue: (string | null)[]","options?: AsArrayOptions<T>","arrayValue: QueryValue[]","transform","options?: AsBooleanOptions","transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n}","contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection>","contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem>","contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n>","contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n>","defaultHandlers: ContextStorageHandlerConstructor[]"],"sources":["../src/handlers/query/helpers.ts","../src/symbols.ts","../src/handlers/query/index.ts","../src/handlers/query/transform-helpers.ts","../src/injectionSymbols.ts","../src/index.ts"],"sourcesContent":["import { LocationQuery } from 'vue-router'\n\nexport interface SerializeOptions {\n /**\n * Custom prefix for serialized keys.\n * @example\n * - prefix: 'filters' => 'filters[key]'\n * - prefix: 'search' => 'search[key]'\n * - prefix: '' => 'key' (no prefix)\n */\n prefix?: string\n}\n\n/**\n * Serializes filter parameters into a URL-friendly format.\n *\n * @param params - Raw parameters object to serialize\n * @param options - Serialization options\n * @returns Serialized parameters with prefixed keys\n *\n * @example\n * // With default prefix 'filters'\n * serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })\n * // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }\n *\n * @example\n * // With custom prefix\n * serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })\n * // => { 'search[name]': 'John', 'search[all]': '1' }\n *\n * @example\n * // Without prefix\n * serializeFiltersParams({ page: 1, all: false }, { prefix: '' })\n * // => { 'page': '1', 'all': '0' }\n */\nexport function serializeParams(\n params: Record<string, unknown>,\n options: SerializeOptions = {},\n): LocationQuery {\n const { prefix = '' } = options\n\n const result: LocationQuery = {}\n\n Object.keys(params).forEach((key) => {\n const value = params[key]\n\n // Skip empty values, null, and empty arrays\n if (value === '') {\n return\n }\n\n if (value === null) {\n return\n }\n\n if (Array.isArray(value) && value.length === 0) {\n return\n }\n\n // Format the key with prefix (or without if prefix is empty)\n const formattedKey = prefix ? `${prefix}[${key}]` : key\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n // Serialize arrays directly: a=1&a=2&a=3\n result[formattedKey] = value.map(String)\n } else {\n Object.assign(\n result,\n serializeParams(value as Record<string, unknown>, {\n ...options,\n prefix: formattedKey,\n }),\n )\n }\n } else if (typeof value === 'boolean') {\n result[formattedKey] = value ? '1' : '0'\n } else {\n result[formattedKey] = String(value)\n }\n })\n\n return result\n}\n\n/**\n * Deserializes query parameters from a URL-friendly format back to an object.\n *\n * @param params - Serialized parameters object\n * @returns Deserialized parameters object\n *\n * @example\n * deserializeParams({ 'filters[status]': 'active', search: 'test' })\n * // => { filters: {status: 'active'}, search: 'test' }\n */\nexport function deserializeParams(params: Record<string, any>): Record<string, any> {\n return Object.keys(params).reduce<Record<string, any>>((acc, key) => {\n const value = params[key]\n\n // Parse nested structure: 'filters[status]' -> { filters: { status: value } }\n const bracketMatch = key.match(/^([^[]+)\\[(.+)]$/)\n\n if (bracketMatch) {\n const [, rootKey, nestedPath] = bracketMatch\n\n // Initialize root object if needed\n if (!acc[rootKey]) {\n acc[rootKey] = {}\n }\n\n // Parse nested path: 'created_at][from' -> ['created_at', 'from']\n const pathParts = nestedPath.split('][')\n\n // Navigate/create nested structure\n let current = acc[rootKey]\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i]\n if (!current[part]) {\n current[part] = {}\n }\n current = current[part]\n }\n\n // Set the final value\n const finalKey = pathParts[pathParts.length - 1]\n current[finalKey] = value\n } else {\n // No brackets - simple key\n acc[key] = value\n }\n\n return acc\n }, {})\n}\n","export const collection: unique symbol = Symbol('context-storage-collection')\nexport const collectionItem: unique symbol = Symbol('context-storage-collection-item')\nexport const handlers: unique symbol = Symbol('context-storage-handlers')\nexport const contextStorageQueryHandler: unique symbol = Symbol('context-storage-query-handler')\n","import { ContextStorageHandlerConstructor } from '../../handlers'\nimport { deserializeParams, serializeParams } from './helpers'\nimport { contextStorageQueryHandler } from '../../symbols'\nimport { cloneDeep, isEqual, merge, pick } from 'lodash-es'\nimport { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'\nimport { LocationQuery, useRoute, useRouter } from 'vue-router'\nimport {\n ContextStorageQueryRegisteredItem,\n IContextStorageQueryHandler,\n QueryHandlerBaseOptions,\n RegisterQueryHandlerBaseOptions,\n RegisterQueryHandlerOptions,\n} from './types'\n\nexport function useContextStorageQueryHandler<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options?: RegisterQueryHandlerBaseOptions<T>,\n): void {\n const handler = inject<InstanceType<typeof ContextStorageQueryHandler>>(\n contextStorageQueryHandler,\n )\n\n if (!handler) {\n throw new Error('[ContextStorage] ContextStorageQueryHandler is not provided')\n }\n\n const currentInstance = getCurrentInstance()\n const uid = currentInstance?.uid || 0\n\n const causer = new Error().stack?.split('\\n')[2]?.trimStart() || 'unknown'\n\n const stop = handler.register(data, { causer, uid, ...options })\n onBeforeUnmount(() => {\n stop()\n })\n}\n\nfunction sortQueryByReference(query: LocationQuery, ...references: LocationQuery[]): LocationQuery {\n const sorted: LocationQuery = {}\n\n const referenceKeys = new Set<string>()\n\n references.forEach((reference) => {\n Object.keys(reference).forEach((key) => {\n referenceKeys.add(key)\n })\n })\n\n referenceKeys.forEach((key) => {\n if (key in query && !(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n Object.keys(query).forEach((key) => {\n if (!(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n return sorted\n}\n\nexport class ContextStorageQueryHandler implements IContextStorageQueryHandler {\n private enabled = false\n private registered: ContextStorageQueryRegisteredItem<any>[] = []\n private currentQuery: LocationQuery | undefined = undefined\n private readonly route: ReturnType<typeof useRoute>\n private router: ReturnType<typeof useRouter>\n private initialState?: Record<string, unknown>\n private hasAnyRegistered = false\n private preventSyncRegisteredToQueryByAfterEachRoute = false\n private preventAfterEachRouteCallsWhileCallingRouter = false\n\n static customQueryHandlerOptions: QueryHandlerBaseOptions = {}\n\n private readonly options: Required<QueryHandlerBaseOptions> = {\n mode: 'replace',\n emptyPlaceholder: '_',\n mergeOnlyExistingKeysWithoutTransform: true,\n preserveUnusedKeys: false,\n preserveEmptyState: false,\n }\n\n // noinspection JSUnusedGlobalSymbols\n static configure(options: QueryHandlerBaseOptions): ContextStorageHandlerConstructor {\n ContextStorageQueryHandler.customQueryHandlerOptions = options\n\n return ContextStorageQueryHandler\n }\n\n constructor() {\n this.route = useRoute()\n this.router = useRouter()\n\n this.options = {\n ...this.options,\n ...ContextStorageQueryHandler.customQueryHandlerOptions,\n }\n\n const stopAfterEach = this.router.afterEach(() => {\n this.afterEachRoute()\n })\n\n onBeforeUnmount(() => {\n stopAfterEach()\n })\n }\n\n getInjectionKey(): typeof contextStorageQueryHandler {\n return contextStorageQueryHandler\n }\n\n setInitialState(state: Record<string, unknown> | undefined): void {\n this.initialState = state\n }\n\n static getInitialStateResolver(): () => LocationQuery {\n const route = useRoute()\n\n return () => route.query\n }\n\n setEnabled(state: boolean, initial: boolean): void {\n const prevState = this.enabled\n this.enabled = state\n\n if (this.hasAnyRegistered) {\n if (initial) {\n this.syncInitialStateToRegistered()\n }\n\n if ((state && !prevState) || !initial) {\n this.syncRegisteredToQuery()\n }\n }\n }\n\n async syncRegisteredToQuery(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n if (this.preventSyncRegisteredToQueryByAfterEachRoute) {\n return\n }\n\n const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered()\n\n this.currentQuery = newQueryRaw\n\n if (isEqual(newQuery, this.route.query)) {\n return\n }\n\n this.preventAfterEachRouteCallsWhileCallingRouter = true\n try {\n if (this.options.mode === 'replace') {\n await this.router.replace({ ...this.route, query: newQuery })\n } else {\n await this.router.push({ ...this.route, query: newQuery })\n }\n } catch (e) {\n console.error('[ContextStorage] Got error while routing', e)\n }\n this.preventAfterEachRouteCallsWhileCallingRouter = false\n }\n\n afterEachRoute(): void {\n if (!this.enabled) {\n return\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n return\n }\n\n this.setInitialState(this.route.query)\n\n this.preventSyncRegisteredToQueryByAfterEachRoute = true\n queueMicrotask(() => {\n this.preventSyncRegisteredToQueryByAfterEachRoute = false\n\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n\n setTimeout(() => {\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n }\n\n syncInitialStateToRegisteredItem<T extends Record<string, unknown>>(\n item: ContextStorageQueryRegisteredItem<T>,\n ): void {\n if (this.initialState === undefined) {\n return\n }\n\n let deserialized = deserializeParams(this.initialState)\n\n const {\n prefix,\n mergeOnlyExistingKeysWithoutTransform = this.options.mergeOnlyExistingKeysWithoutTransform,\n } = item.options || {}\n\n if (typeof prefix === 'string' && prefix.length > 0) {\n deserialized = deserialized[prefix]\n }\n\n if (deserialized === undefined) {\n return\n }\n\n const itemData = toValue(item.data)\n\n /**\n * null can be if query parameter only has a name without a value sign\n */\n if (deserialized !== null) {\n const deserializedKeys = Object.keys(deserialized)\n\n /**\n * If the data is empty, return the initial value.\n *\n * This can happen when directly navigating to a route, for example through a menu item.\n */\n if (!deserializedKeys.length) {\n merge(itemData, item.initialData)\n return\n }\n\n if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) {\n delete deserialized[this.options.emptyPlaceholder]\n }\n }\n\n if (item.options?.transform) {\n deserialized = item.options.transform(deserialized, item.initialData)\n } else {\n if (mergeOnlyExistingKeysWithoutTransform) {\n deserialized = pick(deserialized, Object.keys(item.initialData))\n }\n }\n\n if (isEqual(itemData, deserialized)) {\n return\n }\n\n merge(itemData, deserialized)\n }\n\n syncInitialStateToRegistered(): void {\n this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item))\n }\n\n register<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options: RegisterQueryHandlerOptions<T>,\n ): () => void {\n this.hasAnyRegistered = true\n\n const watchHandle = watch(data, () => this.syncRegisteredToQuery(), {\n deep: true,\n })\n\n const item: ContextStorageQueryRegisteredItem<T> = {\n data,\n initialData: cloneDeep(toValue(data)) as T,\n options,\n watchHandle,\n }\n this.registered.push(item)\n\n const syncCallback = (): void => {\n this.syncInitialStateToRegisteredItem(item)\n this.syncRegisteredToQuery()\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n /**\n * Macrotask solves syncing issues when syncRegisteredToQuery called after HMR\n */\n setTimeout(syncCallback)\n } else {\n queueMicrotask(syncCallback)\n }\n\n return (): void => {\n this.registered.splice(this.registered.indexOf(item), 1)\n this.syncRegisteredToQuery()\n }\n }\n\n #buildQueryFromRegistered(): { newQuery: LocationQuery; newQueryRaw: LocationQuery } {\n const newQueryRaw: LocationQuery = {}\n\n this.registered.forEach((item) => {\n const { prefix, preserveEmptyState = this.options.preserveEmptyState } = item.options || {}\n const patch = serializeParams(toValue(item.data), {\n prefix,\n })\n\n const patchKeys = Object.keys(patch)\n\n // If there are key intersections between the query and the patch, a warning is issued.\n // Patches should not overwrite each other, otherwise, upon reload, an incorrect value will be restored.\n patchKeys.forEach((key) => {\n if (newQueryRaw.hasOwnProperty(key)) {\n console.warn(\n `[ContextStorage] Key ${key} is already present, overriding ` +\n (item.options?.causer || ''),\n )\n }\n })\n\n if (!patchKeys.length && preserveEmptyState) {\n patch[prefix || this.options.emptyPlaceholder] = null\n }\n\n Object.assign(newQueryRaw, patch)\n })\n\n let newQuery = { ...newQueryRaw }\n\n /*\n * It will not delete from the query the keys that are not used in the patch.\n *\n * It will only work if the registered item has a transform, otherwise without\n * it - all keys are dumped into item.data during the initial fill from initialState\n */\n if (this.options.preserveUnusedKeys) {\n newQuery = { ...this.route.query, ...newQuery }\n }\n\n if (this.currentQuery !== undefined) {\n //Perform a diff of keys between currentQuery and newQueryRaw, and remove the keys that are in currentQuery but not in newQueryRaw.\n //This is necessary to ensure that the query string does not contain keys that are no longer used.\n Object.keys(this.currentQuery).forEach((key) => {\n if (!newQueryRaw.hasOwnProperty(key)) {\n delete newQuery[key]\n }\n })\n }\n\n if (Object.keys(newQuery).length > 1 && newQuery[this.options.emptyPlaceholder] === null) {\n delete newQuery[this.options.emptyPlaceholder]\n }\n\n newQuery = sortQueryByReference(newQuery, newQueryRaw)\n\n return { newQuery, newQueryRaw }\n }\n}\n","import { QueryValue } from './types'\n\ninterface AsNumberOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: number\n}\n\nexport function asNumber(value: QueryValue | number | undefined): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable: true; fallbackValue?: number },\n): number | null | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: number },\n): number | null\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: number },\n): number | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: number },\n): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options?: AsNumberOptions,\n): number | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : 0,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n value = Number(value)\n\n return isNaN(value) ? fallbackValue : value\n}\n\ninterface AsStringOptions<T extends readonly string[] = string[]> {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: T extends readonly string[] ? T[number] : string\n allowedValues?: T\n}\n\nexport function asString(value: QueryValue | undefined): string\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number]\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: string },\n): string | null | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: string },\n): string | null\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: string },\n): string | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: string },\n): string\nexport function asString(\n value: QueryValue | undefined,\n options?: AsStringOptions,\n): QueryValue | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : '',\n allowedValues,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n const stringValue = value ?? fallbackValue\n\n if (allowedValues && typeof stringValue === 'string' && !allowedValues.includes(stringValue)) {\n return fallbackValue\n }\n\n return stringValue\n}\n\ninterface AsNumberArrayOptions {\n nullable?: boolean\n}\n\nexport function asNumberArray(value: QueryValue | undefined): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable: true },\n): number[] | null\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable?: false },\n): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options?: AsNumberArrayOptions,\n): number[] | null {\n const { nullable = false } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: (string | null)[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else if (typeof value === 'string') {\n arrayValue = [value]\n } else {\n arrayValue = []\n }\n\n return arrayValue.map((item) => {\n if (item === null) {\n return 0\n }\n const num = Number(item)\n return isNaN(num) ? 0 : num\n })\n}\n\ninterface AsArrayOptions<T> {\n nullable?: boolean\n missable?: boolean\n transform?: (value: QueryValue) => T\n}\n\nexport function asArray<T>(value: QueryValue | undefined): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; transform?: (value: QueryValue) => T },\n): T[] | null | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; transform?: (value: QueryValue) => T },\n): T[] | null\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; transform?: (value: QueryValue) => T },\n): T[] | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; transform?: (value: QueryValue) => T },\n): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options?: AsArrayOptions<T>,\n): T[] | null | undefined {\n const { nullable = false, missable = false, transform } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: QueryValue[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else {\n arrayValue = [value]\n }\n\n if (transform) {\n return arrayValue.map((item) => transform(item))\n }\n\n return arrayValue as T[]\n}\n\ninterface AsBooleanOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: boolean\n}\n\nexport function asBoolean(value: QueryValue | undefined): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: boolean },\n): boolean | null | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: boolean },\n): boolean | null\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: boolean },\n): boolean | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: boolean },\n): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options?: AsBooleanOptions,\n): boolean | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : false,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined || value === null) {\n return fallbackValue\n }\n\n if (typeof value === 'string') {\n const lowerValue = value.toLowerCase()\n if (lowerValue === 'true' || lowerValue === '1') {\n return true\n }\n if (lowerValue === 'false' || lowerValue === '0') {\n return false\n }\n }\n\n return fallbackValue\n}\n\nexport const transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n} = {\n asString,\n asNumber,\n asArray,\n asNumberArray,\n asBoolean,\n}\n","import { ContextStorageCollection, ContextStorageCollectionItem } from './collection'\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\nimport { InjectionKey } from 'vue'\n\nexport const contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection> = collection\nexport const contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem> =\n collectionItem\nexport const contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n> = handlers\n\nexport const contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n> = contextStorageQueryHandler\n","// Core exports\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport type { ContextStorageHandlerConstructor } from './handlers'\n\nexport type {\n ContextStorageHandler,\n ContextStorageHandlerConstructor,\n RegisterBaseOptions,\n} from './handlers'\n\nexport { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'\n\n// Query helpers\nexport { deserializeParams, serializeParams } from './handlers/query/helpers'\nexport type { SerializeOptions } from './handlers/query/helpers'\n\n// Query transform helpers\nexport {\n asArray,\n asBoolean,\n asNumber,\n asNumberArray,\n asString,\n transform,\n} from './handlers/query/transform-helpers'\n\n// Injection symbols\nexport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n contextStorageQueryHandlerInjectKey,\n} from './injectionSymbols'\n\n// Symbols\nexport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\n\nexport const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]\nexport type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'\n\n// Export only type for ContextStorageCollectionItem to avoid naming conflict with component\nexport type { ContextStorageCollectionItem } from './collection'\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["params: Record<string, unknown>","options: SerializeOptions","result: LocationQuery","params: Record<string, any>","collection: unique symbol","collectionItem: unique symbol","handlers: unique symbol","contextStorageQueryHandler: unique symbol","data: MaybeRefOrGetter<T>","options?: RegisterQueryHandlerBaseOptions<T>","query: LocationQuery","sorted: LocationQuery","options: QueryHandlerBaseOptions","state: Record<string, unknown> | undefined","state: boolean","initial: boolean","#buildQueryFromRegistered","item: ContextStorageQueryRegisteredItem<T>","options: RegisterQueryHandlerOptions<T>","newQueryRaw: LocationQuery","contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection>","contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem>","contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n>","contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n>","handlerConstructors: ContextStorageHandlerConstructor[]","callback: (item: ContextStorageCollectionItem) => void","key: string","options: ItemOptions","handlers","item: ContextStorageCollectionItem","removeItem: ContextStorageCollectionItem","activeItem: ContextStorageCollectionItem","value: QueryValue | number | undefined","options?: AsNumberOptions","value: QueryValue | undefined","options?: AsStringOptions","options?: AsNumberArrayOptions","arrayValue: (string | null)[]","options?: AsArrayOptions<T>","arrayValue: QueryValue[]","transform","options?: AsBooleanOptions","transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n}","defaultHandlers: ContextStorageHandlerConstructor[]"],"sources":["../src/handlers/query/helpers.ts","../src/symbols.ts","../src/handlers/query/index.ts","../src/injectionSymbols.ts","../src/components/ContextStorageActivator.vue","../src/collection.ts","../src/components/ContextStorageCollection.vue","../src/components/ContextStorageProvider.vue","../src/components/ContextStorage.vue","../src/handlers/query/transform-helpers.ts","../src/index.ts"],"sourcesContent":["import { LocationQuery } from 'vue-router'\n\nexport interface SerializeOptions {\n /**\n * Custom prefix for serialized keys.\n * @example\n * - prefix: 'filters' => 'filters[key]'\n * - prefix: 'search' => 'search[key]'\n * - prefix: '' => 'key' (no prefix)\n */\n prefix?: string\n}\n\n/**\n * Serializes filter parameters into a URL-friendly format.\n *\n * @param params - Raw parameters object to serialize\n * @param options - Serialization options\n * @returns Serialized parameters with prefixed keys\n *\n * @example\n * // With default prefix 'filters'\n * serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })\n * // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }\n *\n * @example\n * // With custom prefix\n * serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })\n * // => { 'search[name]': 'John', 'search[all]': '1' }\n *\n * @example\n * // Without prefix\n * serializeFiltersParams({ page: 1, all: false }, { prefix: '' })\n * // => { 'page': '1', 'all': '0' }\n */\nexport function serializeParams(\n params: Record<string, unknown>,\n options: SerializeOptions = {},\n): LocationQuery {\n const { prefix = '' } = options\n\n const result: LocationQuery = {}\n\n Object.keys(params).forEach((key) => {\n const value = params[key]\n\n // Skip empty values, null, and empty arrays\n if (value === '') {\n return\n }\n\n if (value === null) {\n return\n }\n\n if (Array.isArray(value) && value.length === 0) {\n return\n }\n\n // Format the key with prefix (or without if prefix is empty)\n const formattedKey = prefix ? `${prefix}[${key}]` : key\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n // Serialize arrays directly: a=1&a=2&a=3\n result[formattedKey] = value.map(String)\n } else {\n Object.assign(\n result,\n serializeParams(value as Record<string, unknown>, {\n ...options,\n prefix: formattedKey,\n }),\n )\n }\n } else if (typeof value === 'boolean') {\n result[formattedKey] = value ? '1' : '0'\n } else {\n result[formattedKey] = String(value)\n }\n })\n\n return result\n}\n\n/**\n * Deserializes query parameters from a URL-friendly format back to an object.\n *\n * @param params - Serialized parameters object\n * @returns Deserialized parameters object\n *\n * @example\n * deserializeParams({ 'filters[status]': 'active', search: 'test' })\n * // => { filters: {status: 'active'}, search: 'test' }\n */\nexport function deserializeParams(params: Record<string, any>): Record<string, any> {\n return Object.keys(params).reduce<Record<string, any>>((acc, key) => {\n const value = params[key]\n\n // Parse nested structure: 'filters[status]' -> { filters: { status: value } }\n const bracketMatch = key.match(/^([^[]+)\\[(.+)]$/)\n\n if (bracketMatch) {\n const [, rootKey, nestedPath] = bracketMatch\n\n // Initialize root object if needed\n if (!acc[rootKey]) {\n acc[rootKey] = {}\n }\n\n // Parse nested path: 'created_at][from' -> ['created_at', 'from']\n const pathParts = nestedPath.split('][')\n\n // Navigate/create nested structure\n let current = acc[rootKey]\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i]\n if (!current[part]) {\n current[part] = {}\n }\n current = current[part]\n }\n\n // Set the final value\n const finalKey = pathParts[pathParts.length - 1]\n current[finalKey] = value\n } else {\n // No brackets - simple key\n acc[key] = value\n }\n\n return acc\n }, {})\n}\n","export const collection: unique symbol = Symbol('context-storage-collection')\nexport const collectionItem: unique symbol = Symbol('context-storage-collection-item')\nexport const handlers: unique symbol = Symbol('context-storage-handlers')\nexport const contextStorageQueryHandler: unique symbol = Symbol('context-storage-query-handler')\n","import { ContextStorageHandlerConstructor } from '../../handlers.ts'\nimport { deserializeParams, serializeParams } from './helpers.ts'\nimport { contextStorageQueryHandler } from '../../symbols.ts'\nimport { cloneDeep, isEqual, merge, pick } from 'lodash'\nimport { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'\nimport { LocationQuery, useRoute, useRouter } from 'vue-router'\nimport {\n ContextStorageQueryRegisteredItem,\n IContextStorageQueryHandler,\n QueryHandlerBaseOptions,\n RegisterQueryHandlerBaseOptions,\n RegisterQueryHandlerOptions,\n} from './types.ts'\n\nexport function useContextStorageQueryHandler<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options?: RegisterQueryHandlerBaseOptions<T>,\n): void {\n const handler = inject<InstanceType<typeof ContextStorageQueryHandler>>(\n contextStorageQueryHandler,\n )\n\n if (!handler) {\n throw new Error('[ContextStorage] ContextStorageQueryHandler is not provided')\n }\n\n const currentInstance = getCurrentInstance()\n const uid = currentInstance?.uid || 0\n\n const causer = new Error().stack?.split('\\n')[2]?.trimStart() || 'unknown'\n\n const stop = handler.register(data, { causer, uid, ...options })\n onBeforeUnmount(() => {\n stop()\n })\n}\n\nfunction sortQueryByReference(query: LocationQuery, ...references: LocationQuery[]): LocationQuery {\n const sorted: LocationQuery = {}\n\n const referenceKeys = new Set<string>()\n\n references.forEach((reference) => {\n Object.keys(reference).forEach((key) => {\n referenceKeys.add(key)\n })\n })\n\n referenceKeys.forEach((key) => {\n if (key in query && !(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n Object.keys(query).forEach((key) => {\n if (!(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n return sorted\n}\n\nexport class ContextStorageQueryHandler implements IContextStorageQueryHandler {\n private enabled = false\n private registered: ContextStorageQueryRegisteredItem<any>[] = []\n private currentQuery: LocationQuery | undefined = undefined\n private readonly route: ReturnType<typeof useRoute>\n private router: ReturnType<typeof useRouter>\n private initialState?: Record<string, unknown>\n private hasAnyRegistered = false\n private preventSyncRegisteredToQueryByAfterEachRoute = false\n private preventAfterEachRouteCallsWhileCallingRouter = false\n\n static customQueryHandlerOptions: QueryHandlerBaseOptions = {}\n\n private readonly options: Required<QueryHandlerBaseOptions> = {\n mode: 'replace',\n emptyPlaceholder: '_',\n mergeOnlyExistingKeysWithoutTransform: true,\n preserveUnusedKeys: false,\n preserveEmptyState: false,\n }\n\n // noinspection JSUnusedGlobalSymbols\n static configure(options: QueryHandlerBaseOptions): ContextStorageHandlerConstructor {\n ContextStorageQueryHandler.customQueryHandlerOptions = options\n\n return ContextStorageQueryHandler\n }\n\n constructor() {\n this.route = useRoute()\n this.router = useRouter()\n\n this.options = {\n ...this.options,\n ...ContextStorageQueryHandler.customQueryHandlerOptions,\n }\n\n const stopAfterEach = this.router.afterEach(() => {\n this.afterEachRoute()\n })\n\n onBeforeUnmount(() => {\n stopAfterEach()\n })\n }\n\n getInjectionKey(): typeof contextStorageQueryHandler {\n return contextStorageQueryHandler\n }\n\n setInitialState(state: Record<string, unknown> | undefined): void {\n this.initialState = state\n }\n\n static getInitialStateResolver(): () => LocationQuery {\n const route = useRoute()\n\n return () => route.query\n }\n\n setEnabled(state: boolean, initial: boolean): void {\n const prevState = this.enabled\n this.enabled = state\n\n if (this.hasAnyRegistered) {\n if (initial) {\n this.syncInitialStateToRegistered()\n }\n\n if ((state && !prevState) || !initial) {\n this.syncRegisteredToQuery()\n }\n }\n }\n\n async syncRegisteredToQuery(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n if (this.preventSyncRegisteredToQueryByAfterEachRoute) {\n return\n }\n\n const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered()\n\n this.currentQuery = newQueryRaw\n\n if (isEqual(newQuery, this.route.query)) {\n return\n }\n\n this.preventAfterEachRouteCallsWhileCallingRouter = true\n try {\n if (this.options.mode === 'replace') {\n await this.router.replace({ ...this.route, query: newQuery })\n } else {\n await this.router.push({ ...this.route, query: newQuery })\n }\n } catch (e) {\n console.error('[ContextStorage] Got error while routing', e)\n }\n this.preventAfterEachRouteCallsWhileCallingRouter = false\n }\n\n afterEachRoute(): void {\n if (!this.enabled) {\n return\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n return\n }\n\n this.setInitialState(this.route.query)\n\n this.preventSyncRegisteredToQueryByAfterEachRoute = true\n queueMicrotask(() => {\n this.preventSyncRegisteredToQueryByAfterEachRoute = false\n\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n\n setTimeout(() => {\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n }\n\n syncInitialStateToRegisteredItem<T extends Record<string, unknown>>(\n item: ContextStorageQueryRegisteredItem<T>,\n ): void {\n if (this.initialState === undefined) {\n return\n }\n\n let deserialized = deserializeParams(this.initialState)\n\n const {\n prefix,\n mergeOnlyExistingKeysWithoutTransform = this.options.mergeOnlyExistingKeysWithoutTransform,\n } = item.options || {}\n\n if (typeof prefix === 'string' && prefix.length > 0) {\n deserialized = deserialized[prefix]\n }\n\n if (deserialized === undefined) {\n return\n }\n\n const itemData = toValue(item.data)\n\n /**\n * null can be if query parameter only has a name without a value sign\n */\n if (deserialized !== null) {\n const deserializedKeys = Object.keys(deserialized)\n\n /**\n * If the data is empty, return the initial value.\n *\n * This can happen when directly navigating to a route, for example through a menu item.\n */\n if (!deserializedKeys.length) {\n merge(itemData, item.initialData)\n return\n }\n\n if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) {\n delete deserialized[this.options.emptyPlaceholder]\n }\n }\n\n if (item.options?.transform) {\n deserialized = item.options.transform(deserialized, item.initialData)\n } else {\n if (mergeOnlyExistingKeysWithoutTransform) {\n deserialized = pick(deserialized, Object.keys(item.initialData))\n }\n }\n\n if (isEqual(itemData, deserialized)) {\n return\n }\n\n merge(itemData, deserialized)\n }\n\n syncInitialStateToRegistered(): void {\n this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item))\n }\n\n register<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options: RegisterQueryHandlerOptions<T>,\n ): () => void {\n this.hasAnyRegistered = true\n\n const watchHandle = watch(data, () => this.syncRegisteredToQuery(), {\n deep: true,\n })\n\n const item: ContextStorageQueryRegisteredItem<T> = {\n data,\n initialData: cloneDeep(toValue(data)) as T,\n options,\n watchHandle,\n }\n this.registered.push(item)\n\n const syncCallback = (): void => {\n this.syncInitialStateToRegisteredItem(item)\n this.syncRegisteredToQuery()\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n /**\n * Macrotask solves syncing issues when syncRegisteredToQuery called after HMR\n */\n setTimeout(syncCallback)\n } else {\n queueMicrotask(syncCallback)\n }\n\n return (): void => {\n this.registered.splice(this.registered.indexOf(item), 1)\n this.syncRegisteredToQuery()\n }\n }\n\n #buildQueryFromRegistered(): { newQuery: LocationQuery; newQueryRaw: LocationQuery } {\n const newQueryRaw: LocationQuery = {}\n\n this.registered.forEach((item) => {\n const { prefix, preserveEmptyState = this.options.preserveEmptyState } = item.options || {}\n const patch = serializeParams(toValue(item.data), {\n prefix,\n })\n\n const patchKeys = Object.keys(patch)\n\n // If there are key intersections between the query and the patch, a warning is issued.\n // Patches should not overwrite each other, otherwise, upon reload, an incorrect value will be restored.\n patchKeys.forEach((key) => {\n if (newQueryRaw.hasOwnProperty(key)) {\n console.warn(\n `[ContextStorage] Key ${key} is already present, overriding ` +\n (item.options?.causer || ''),\n )\n }\n })\n\n if (!patchKeys.length && preserveEmptyState) {\n patch[prefix || this.options.emptyPlaceholder] = null\n }\n\n Object.assign(newQueryRaw, patch)\n })\n\n let newQuery = { ...newQueryRaw }\n\n /*\n * It will not delete from the query the keys that are not used in the patch.\n *\n * It will only work if the registered item has a transform, otherwise without\n * it - all keys are dumped into item.data during the initial fill from initialState\n */\n if (this.options.preserveUnusedKeys) {\n newQuery = { ...this.route.query, ...newQuery }\n }\n\n if (this.currentQuery !== undefined) {\n //Perform a diff of keys between currentQuery and newQueryRaw, and remove the keys that are in currentQuery but not in newQueryRaw.\n //This is necessary to ensure that the query string does not contain keys that are no longer used.\n Object.keys(this.currentQuery).forEach((key) => {\n if (!newQueryRaw.hasOwnProperty(key)) {\n delete newQuery[key]\n }\n })\n }\n\n if (Object.keys(newQuery).length > 1 && newQuery[this.options.emptyPlaceholder] === null) {\n delete newQuery[this.options.emptyPlaceholder]\n }\n\n newQuery = sortQueryByReference(newQuery, newQueryRaw)\n\n return { newQuery, newQueryRaw }\n }\n}\n","import { ContextStorageCollection, ContextStorageCollectionItem } from './collection'\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\nimport { InjectionKey } from 'vue'\n\nexport const contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection> = collection\nexport const contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem> =\n collectionItem\nexport const contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n> = handlers\n\nexport const contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n> = contextStorageQueryHandler\n","<script lang=\"ts\">\nimport { defineComponent, h, inject } from 'vue'\nimport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n} from '../injectionSymbols'\n\nexport default defineComponent({\n setup(_, { slots }) {\n const collection = inject(contextStorageCollectionInjectKey)!\n const item = inject(contextStorageCollectionItemInjectKey)!\n\n const onActivate = () => {\n collection.setActive(item)\n }\n\n return () => h('div', { onMousedown: onActivate }, slots.default?.())\n },\n})\n</script>\n","import { ContextStorageHandler, ContextStorageHandlerConstructor } from './handlers'\n\nexport type ContextStorageCollectionItem = {\n key: string\n handlers: ContextStorageHandler[]\n}\n\ninterface ItemOptions {\n key: string\n}\n\nexport class ContextStorageCollection {\n public active?: ContextStorageCollectionItem = undefined\n private collection: ContextStorageCollectionItem[] = []\n private onActiveChangeCallbacks: ((item: ContextStorageCollectionItem) => void)[] = []\n\n constructor(private handlerConstructors: ContextStorageHandlerConstructor[]) {}\n\n onActiveChange(callback: (item: ContextStorageCollectionItem) => void): void {\n this.onActiveChangeCallbacks.push(callback)\n }\n\n first(): ContextStorageCollectionItem | undefined {\n return this.collection[0]\n }\n\n findItemByKey(key: string): ContextStorageCollectionItem | undefined {\n return this.collection.find((item) => item.key === key)\n }\n\n add(options: ItemOptions): ContextStorageCollectionItem {\n const handlers = this.handlerConstructors.map((constructor) => new constructor())\n\n const item: ContextStorageCollectionItem = { handlers, key: options.key }\n\n this.collection.push(item)\n\n return item\n }\n\n remove(removeItem: ContextStorageCollectionItem): void {\n if (this.collection.indexOf(removeItem) === -1) {\n throw new Error('[ContextStorage] Item not found in collection')\n }\n\n this.collection = this.collection.filter((item) => item !== removeItem)\n\n if (this.active === removeItem && this.collection.length > 0) {\n this.setActive(this.collection[this.collection.length - 1])\n }\n }\n\n setActive(activeItem: ContextStorageCollectionItem): void {\n if (this.active === activeItem) {\n return\n }\n\n const hasActiveBefore = this.active !== undefined\n this.active = activeItem\n\n this.collection.forEach((item) => {\n Object.values(item.handlers).forEach((handler) => {\n if (handler.setEnabled) {\n handler.setEnabled(item === activeItem, !hasActiveBefore)\n }\n })\n })\n\n this.onActiveChangeCallbacks.forEach((callback) => callback(activeItem))\n }\n}\n","<script lang=\"ts\">\nimport { ContextStorageCollection, ContextStorageCollectionItem } from '../collection'\nimport { ContextStorageHandlerConstructor } from '../handlers'\nimport { contextStorageCollectionInjectKey } from '../injectionSymbols'\nimport { computed, defineComponent, PropType, provide } from 'vue'\nimport { useRouter } from 'vue-router'\nimport { defaultHandlers } from '../index.ts'\n\nexport default defineComponent({\n props: {\n handlers: {\n type: Object as PropType<ContextStorageHandlerConstructor[]>,\n default: defaultHandlers,\n },\n },\n setup({ handlers }, { slots }) {\n const lastActive = computed({\n get: () => localStorage.getItem('context-storage-last-active') || 'main',\n set: (value) => localStorage.setItem('context-storage-last-active', value),\n })\n\n const router = useRouter()\n\n const initialNavigatorState = new Map<\n ContextStorageHandlerConstructor,\n Record<string, unknown>\n >()\n const initialNavigatorStateResolvers = new Map<\n ContextStorageHandlerConstructor,\n () => Record<string, unknown>\n >()\n\n handlers.forEach((handler) => {\n if (!handler.getInitialStateResolver) {\n return\n }\n\n initialNavigatorStateResolvers.set(handler, handler.getInitialStateResolver())\n })\n\n router.isReady().then(() => {\n initialNavigatorStateResolvers.forEach((resolver, handler) => {\n initialNavigatorState.set(handler, resolver())\n })\n\n activateLastActiveItem()\n })\n\n const collection = new ContextStorageCollection(handlers)\n collection.onActiveChange((item) => {\n lastActive.value = item.key\n })\n\n provide(contextStorageCollectionInjectKey, collection)\n\n const activateInitialItem = (item: ContextStorageCollectionItem) => {\n item.handlers.forEach((handler) => {\n const state = initialNavigatorState.get(\n handler.constructor as ContextStorageHandlerConstructor,\n )\n\n if (!state) {\n return\n }\n\n handler.setInitialState?.(state)\n })\n\n collection.setActive(item)\n }\n\n const activateLastActiveItem = () => {\n const lastActiveItem = collection.findItemByKey(lastActive.value)\n if (lastActiveItem) {\n activateInitialItem(lastActiveItem)\n return\n }\n\n const firstItem = collection.first()\n if (!firstItem) {\n throw new Error('[ContextStorage] Cannot find first item in collection')\n }\n\n activateInitialItem(firstItem)\n }\n\n return () => {\n return slots.default?.()\n }\n },\n})\n</script>\n","<script lang=\"ts\">\nimport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n} from '../injectionSymbols'\nimport { defineComponent, inject, onUnmounted, provide } from 'vue'\n\nexport default defineComponent({\n props: {\n itemKey: {\n type: String,\n required: true,\n },\n },\n setup(props, { slots }) {\n const collection = inject(contextStorageCollectionInjectKey)\n if (!collection) throw new Error('[ContextStorage] Context storage collection not found')\n\n const item = collection.add({\n key: props.itemKey,\n })\n\n provide(contextStorageCollectionItemInjectKey, item)\n provide(contextStorageHandlersInjectKey, item.handlers)\n\n item.handlers.forEach((handler) => {\n provide(handler.getInjectionKey(), handler)\n })\n\n onUnmounted(() => {\n collection.remove(item)\n })\n\n return () => slots.default?.()\n },\n})\n</script>\n","<template>\n <ContextStorageCollection :handlers=\"handlers\">\n <ContextStorageProvider item-key=\"main\">\n <ContextStorageActivator>\n <slot />\n </ContextStorageActivator>\n </ContextStorageProvider>\n </ContextStorageCollection>\n</template>\n\n<script setup lang=\"ts\">\nimport ContextStorageActivator from './ContextStorageActivator.vue'\nimport ContextStorageCollection from './ContextStorageCollection.vue'\nimport ContextStorageProvider from './ContextStorageProvider.vue'\nimport { ContextStorageHandlerConstructor } from '../handlers'\nimport { defaultHandlers } from '../index'\n\ninterface Props {\n handlers: ContextStorageHandlerConstructor[]\n}\n\nconst { handlers = defaultHandlers } = defineProps<Props>()\n</script>\n","import { QueryValue } from './types.ts'\n\ninterface AsNumberOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: number\n}\n\nexport function asNumber(value: QueryValue | number | undefined): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable: true; fallbackValue?: number },\n): number | null | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: number },\n): number | null\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: number },\n): number | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: number },\n): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options?: AsNumberOptions,\n): number | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : 0,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n value = Number(value)\n\n return isNaN(value) ? fallbackValue : value\n}\n\ninterface AsStringOptions<T extends readonly string[] = string[]> {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: T extends readonly string[] ? T[number] : string\n allowedValues?: T\n}\n\nexport function asString(value: QueryValue | undefined): string\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number]\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: string },\n): string | null | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: string },\n): string | null\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: string },\n): string | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: string },\n): string\nexport function asString(\n value: QueryValue | undefined,\n options?: AsStringOptions,\n): QueryValue | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : '',\n allowedValues,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n const stringValue = value ?? fallbackValue\n\n if (allowedValues && typeof stringValue === 'string' && !allowedValues.includes(stringValue)) {\n return fallbackValue\n }\n\n return stringValue\n}\n\ninterface AsNumberArrayOptions {\n nullable?: boolean\n}\n\nexport function asNumberArray(value: QueryValue | undefined): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable: true },\n): number[] | null\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable?: false },\n): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options?: AsNumberArrayOptions,\n): number[] | null {\n const { nullable = false } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: (string | null)[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else if (typeof value === 'string') {\n arrayValue = [value]\n } else {\n arrayValue = []\n }\n\n return arrayValue.map((item) => {\n if (item === null) {\n return 0\n }\n const num = Number(item)\n return isNaN(num) ? 0 : num\n })\n}\n\ninterface AsArrayOptions<T> {\n nullable?: boolean\n missable?: boolean\n transform?: (value: QueryValue) => T\n}\n\nexport function asArray<T>(value: QueryValue | undefined): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; transform?: (value: QueryValue) => T },\n): T[] | null | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; transform?: (value: QueryValue) => T },\n): T[] | null\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; transform?: (value: QueryValue) => T },\n): T[] | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; transform?: (value: QueryValue) => T },\n): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options?: AsArrayOptions<T>,\n): T[] | null | undefined {\n const { nullable = false, missable = false, transform } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: QueryValue[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else {\n arrayValue = [value]\n }\n\n if (transform) {\n return arrayValue.map((item) => transform(item))\n }\n\n return arrayValue as T[]\n}\n\ninterface AsBooleanOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: boolean\n}\n\nexport function asBoolean(value: QueryValue | undefined): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: boolean },\n): boolean | null | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: boolean },\n): boolean | null\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: boolean },\n): boolean | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: boolean },\n): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options?: AsBooleanOptions,\n): boolean | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : false,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined || value === null) {\n return fallbackValue\n }\n\n if (typeof value === 'string') {\n const lowerValue = value.toLowerCase()\n if (lowerValue === 'true' || lowerValue === '1') {\n return true\n }\n if (lowerValue === 'false' || lowerValue === '0') {\n return false\n }\n }\n\n return fallbackValue\n}\n\nexport const transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n} = {\n asString,\n asNumber,\n asArray,\n asNumberArray,\n asBoolean,\n}\n","// Core exports\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport type { ContextStorageHandlerConstructor } from './handlers'\n\nexport { default as ContextStorageActivator } from './components/ContextStorageActivator.vue'\nexport { default as ContextStorageCollection } from './components/ContextStorageCollection.vue'\nexport { default as ContextStorageProvider } from './components/ContextStorageProvider.vue'\nexport { default as ContextStorage } from './components/ContextStorage.vue'\n\nexport type {\n ContextStorageHandler,\n ContextStorageHandlerConstructor,\n RegisterBaseOptions,\n} from './handlers'\n\nexport { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'\n\n// Query helpers\nexport { deserializeParams, serializeParams } from './handlers/query/helpers.ts'\nexport type { SerializeOptions } from './handlers/query/helpers.ts'\n\n// Query transform helpers\nexport {\n asArray,\n asBoolean,\n asNumber,\n asNumberArray,\n asString,\n transform,\n} from './handlers/query/transform-helpers.ts'\n\n// Injection symbols\nexport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n contextStorageQueryHandlerInjectKey,\n} from './injectionSymbols'\n\n// Symbols\nexport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\n\nexport const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]\nexport type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,11 +1,14 @@
1
1
  import type { ContextStorageHandlerConstructor } from './handlers';
2
+ export { default as ContextStorageActivator } from './components/ContextStorageActivator.vue';
3
+ export { default as ContextStorageCollection } from './components/ContextStorageCollection.vue';
4
+ export { default as ContextStorageProvider } from './components/ContextStorageProvider.vue';
5
+ export { default as ContextStorage } from './components/ContextStorage.vue';
2
6
  export type { ContextStorageHandler, ContextStorageHandlerConstructor, RegisterBaseOptions, } from './handlers';
3
7
  export { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query';
4
- export { deserializeParams, serializeParams } from './handlers/query/helpers';
5
- export type { SerializeOptions } from './handlers/query/helpers';
6
- export { asArray, asBoolean, asNumber, asNumberArray, asString, transform, } from './handlers/query/transform-helpers';
8
+ export { deserializeParams, serializeParams } from './handlers/query/helpers.ts';
9
+ export type { SerializeOptions } from './handlers/query/helpers.ts';
10
+ export { asArray, asBoolean, asNumber, asNumberArray, asString, transform, } from './handlers/query/transform-helpers.ts';
7
11
  export { contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandlerInjectKey, } from './injectionSymbols';
8
12
  export { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols';
9
13
  export declare const defaultHandlers: ContextStorageHandlerConstructor[];
10
14
  export type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types';
11
- export type { ContextStorageCollectionItem } from './collection';
package/dist/index.d.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  import type { ContextStorageHandlerConstructor } from './handlers';
2
+ export { default as ContextStorageActivator } from './components/ContextStorageActivator.vue';
3
+ export { default as ContextStorageCollection } from './components/ContextStorageCollection.vue';
4
+ export { default as ContextStorageProvider } from './components/ContextStorageProvider.vue';
5
+ export { default as ContextStorage } from './components/ContextStorage.vue';
2
6
  export type { ContextStorageHandler, ContextStorageHandlerConstructor, RegisterBaseOptions, } from './handlers';
3
7
  export { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query';
4
- export { deserializeParams, serializeParams } from './handlers/query/helpers';
5
- export type { SerializeOptions } from './handlers/query/helpers';
6
- export { asArray, asBoolean, asNumber, asNumberArray, asString, transform, } from './handlers/query/transform-helpers';
8
+ export { deserializeParams, serializeParams } from './handlers/query/helpers.ts';
9
+ export type { SerializeOptions } from './handlers/query/helpers.ts';
10
+ export { asArray, asBoolean, asNumber, asNumberArray, asString, transform, } from './handlers/query/transform-helpers.ts';
7
11
  export { contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandlerInjectKey, } from './injectionSymbols';
8
12
  export { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols';
9
13
  export declare const defaultHandlers: ContextStorageHandlerConstructor[];
10
14
  export type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types';
11
- export type { ContextStorageCollectionItem } from './collection';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { cloneDeep, isEqual, merge, pick } from "lodash-es";
2
- import { getCurrentInstance, inject, onBeforeUnmount, toValue, watch } from "vue";
1
+ import { cloneDeep, isEqual, merge, pick } from "lodash";
2
+ import { computed, createBlock, createVNode, defineComponent, getCurrentInstance, h, inject, onBeforeUnmount, onUnmounted, openBlock, provide, renderSlot, toValue, watch, withCtx } from "vue";
3
3
  import { useRoute, useRouter } from "vue-router";
4
4
 
5
5
  //#region src/handlers/query/helpers.ts
@@ -290,6 +290,171 @@ var ContextStorageQueryHandler = class ContextStorageQueryHandler {
290
290
  }
291
291
  };
292
292
 
293
+ //#endregion
294
+ //#region src/injectionSymbols.ts
295
+ const contextStorageCollectionInjectKey = collection;
296
+ const contextStorageCollectionItemInjectKey = collectionItem;
297
+ const contextStorageHandlersInjectKey = handlers;
298
+ const contextStorageQueryHandlerInjectKey = contextStorageQueryHandler;
299
+
300
+ //#endregion
301
+ //#region src/components/ContextStorageActivator.vue
302
+ const _sfc_main$3 = defineComponent({ setup(_, { slots }) {
303
+ const collection$1 = inject(contextStorageCollectionInjectKey);
304
+ const item = inject(contextStorageCollectionItemInjectKey);
305
+ const onActivate = () => {
306
+ collection$1.setActive(item);
307
+ };
308
+ return () => h("div", { onMousedown: onActivate }, slots.default?.());
309
+ } });
310
+ var ContextStorageActivator_default = _sfc_main$3;
311
+
312
+ //#endregion
313
+ //#region src/collection.ts
314
+ var ContextStorageCollection = class {
315
+ active = void 0;
316
+ collection = [];
317
+ onActiveChangeCallbacks = [];
318
+ constructor(handlerConstructors) {
319
+ this.handlerConstructors = handlerConstructors;
320
+ }
321
+ onActiveChange(callback) {
322
+ this.onActiveChangeCallbacks.push(callback);
323
+ }
324
+ first() {
325
+ return this.collection[0];
326
+ }
327
+ findItemByKey(key) {
328
+ return this.collection.find((item) => item.key === key);
329
+ }
330
+ add(options) {
331
+ const handlers$1 = this.handlerConstructors.map((constructor) => new constructor());
332
+ const item = {
333
+ handlers: handlers$1,
334
+ key: options.key
335
+ };
336
+ this.collection.push(item);
337
+ return item;
338
+ }
339
+ remove(removeItem) {
340
+ if (this.collection.indexOf(removeItem) === -1) throw new Error("[ContextStorage] Item not found in collection");
341
+ this.collection = this.collection.filter((item) => item !== removeItem);
342
+ if (this.active === removeItem && this.collection.length > 0) this.setActive(this.collection[this.collection.length - 1]);
343
+ }
344
+ setActive(activeItem) {
345
+ if (this.active === activeItem) return;
346
+ const hasActiveBefore = this.active !== void 0;
347
+ this.active = activeItem;
348
+ this.collection.forEach((item) => {
349
+ Object.values(item.handlers).forEach((handler) => {
350
+ if (handler.setEnabled) handler.setEnabled(item === activeItem, !hasActiveBefore);
351
+ });
352
+ });
353
+ this.onActiveChangeCallbacks.forEach((callback) => callback(activeItem));
354
+ }
355
+ };
356
+
357
+ //#endregion
358
+ //#region src/components/ContextStorageCollection.vue
359
+ const _sfc_main$2 = defineComponent({
360
+ props: { handlers: {
361
+ type: Object,
362
+ default: defaultHandlers
363
+ } },
364
+ setup({ handlers: handlers$1 }, { slots }) {
365
+ const lastActive = computed({
366
+ get: () => localStorage.getItem("context-storage-last-active") || "main",
367
+ set: (value) => localStorage.setItem("context-storage-last-active", value)
368
+ });
369
+ const router = useRouter();
370
+ const initialNavigatorState = /* @__PURE__ */ new Map();
371
+ const initialNavigatorStateResolvers = /* @__PURE__ */ new Map();
372
+ handlers$1.forEach((handler) => {
373
+ if (!handler.getInitialStateResolver) return;
374
+ initialNavigatorStateResolvers.set(handler, handler.getInitialStateResolver());
375
+ });
376
+ router.isReady().then(() => {
377
+ initialNavigatorStateResolvers.forEach((resolver, handler) => {
378
+ initialNavigatorState.set(handler, resolver());
379
+ });
380
+ activateLastActiveItem();
381
+ });
382
+ const collection$1 = new ContextStorageCollection(handlers$1);
383
+ collection$1.onActiveChange((item) => {
384
+ lastActive.value = item.key;
385
+ });
386
+ provide(contextStorageCollectionInjectKey, collection$1);
387
+ const activateInitialItem = (item) => {
388
+ item.handlers.forEach((handler) => {
389
+ const state = initialNavigatorState.get(handler.constructor);
390
+ if (!state) return;
391
+ handler.setInitialState?.(state);
392
+ });
393
+ collection$1.setActive(item);
394
+ };
395
+ const activateLastActiveItem = () => {
396
+ const lastActiveItem = collection$1.findItemByKey(lastActive.value);
397
+ if (lastActiveItem) {
398
+ activateInitialItem(lastActiveItem);
399
+ return;
400
+ }
401
+ const firstItem = collection$1.first();
402
+ if (!firstItem) throw new Error("[ContextStorage] Cannot find first item in collection");
403
+ activateInitialItem(firstItem);
404
+ };
405
+ return () => {
406
+ return slots.default?.();
407
+ };
408
+ }
409
+ });
410
+ var ContextStorageCollection_default = _sfc_main$2;
411
+
412
+ //#endregion
413
+ //#region src/components/ContextStorageProvider.vue
414
+ const _sfc_main$1 = defineComponent({
415
+ props: { itemKey: {
416
+ type: String,
417
+ required: true
418
+ } },
419
+ setup(props, { slots }) {
420
+ const collection$1 = inject(contextStorageCollectionInjectKey);
421
+ if (!collection$1) throw new Error("[ContextStorage] Context storage collection not found");
422
+ const item = collection$1.add({ key: props.itemKey });
423
+ provide(contextStorageCollectionItemInjectKey, item);
424
+ provide(contextStorageHandlersInjectKey, item.handlers);
425
+ item.handlers.forEach((handler) => {
426
+ provide(handler.getInjectionKey(), handler);
427
+ });
428
+ onUnmounted(() => {
429
+ collection$1.remove(item);
430
+ });
431
+ return () => slots.default?.();
432
+ }
433
+ });
434
+ var ContextStorageProvider_default = _sfc_main$1;
435
+
436
+ //#endregion
437
+ //#region src/components/ContextStorage.vue
438
+ const _sfc_main = /* @__PURE__ */ defineComponent({
439
+ __name: "ContextStorage",
440
+ props: { handlers: { default: () => defaultHandlers } },
441
+ setup(__props) {
442
+ return (_ctx, _cache) => {
443
+ return openBlock(), createBlock(ContextStorageCollection_default, { handlers: __props.handlers }, {
444
+ default: withCtx(() => [createVNode(ContextStorageProvider_default, { "item-key": "main" }, {
445
+ default: withCtx(() => [createVNode(ContextStorageActivator_default, null, {
446
+ default: withCtx(() => [renderSlot(_ctx.$slots, "default")]),
447
+ _: 3
448
+ })]),
449
+ _: 3
450
+ })]),
451
+ _: 3
452
+ }, 8, ["handlers"]);
453
+ };
454
+ }
455
+ });
456
+ var ContextStorage_default = _sfc_main;
457
+
293
458
  //#endregion
294
459
  //#region src/handlers/query/transform-helpers.ts
295
460
  function asNumber(value, options) {
@@ -352,17 +517,10 @@ const transform = {
352
517
  asBoolean
353
518
  };
354
519
 
355
- //#endregion
356
- //#region src/injectionSymbols.ts
357
- const contextStorageCollectionInjectKey = collection;
358
- const contextStorageCollectionItemInjectKey = collectionItem;
359
- const contextStorageHandlersInjectKey = handlers;
360
- const contextStorageQueryHandlerInjectKey = contextStorageQueryHandler;
361
-
362
520
  //#endregion
363
521
  //#region src/index.ts
364
522
  const defaultHandlers = [ContextStorageQueryHandler];
365
523
 
366
524
  //#endregion
367
- export { ContextStorageQueryHandler, asArray, asBoolean, asNumber, asNumberArray, asString, collection, collectionItem, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandler, contextStorageQueryHandlerInjectKey, defaultHandlers, deserializeParams, handlers, serializeParams, transform, useContextStorageQueryHandler };
525
+ export { ContextStorage_default as ContextStorage, ContextStorageActivator_default as ContextStorageActivator, ContextStorageCollection_default as ContextStorageCollection, ContextStorageProvider_default as ContextStorageProvider, ContextStorageQueryHandler, asArray, asBoolean, asNumber, asNumberArray, asString, collection, collectionItem, contextStorageCollectionInjectKey, contextStorageCollectionItemInjectKey, contextStorageHandlersInjectKey, contextStorageQueryHandler, contextStorageQueryHandlerInjectKey, defaultHandlers, deserializeParams, handlers, serializeParams, transform, useContextStorageQueryHandler };
368
526
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["params: Record<string, unknown>","options: SerializeOptions","result: LocationQuery","params: Record<string, any>","collection: unique symbol","collectionItem: unique symbol","handlers: unique symbol","contextStorageQueryHandler: unique symbol","data: MaybeRefOrGetter<T>","options?: RegisterQueryHandlerBaseOptions<T>","query: LocationQuery","sorted: LocationQuery","options: QueryHandlerBaseOptions","state: Record<string, unknown> | undefined","state: boolean","initial: boolean","#buildQueryFromRegistered","item: ContextStorageQueryRegisteredItem<T>","options: RegisterQueryHandlerOptions<T>","newQueryRaw: LocationQuery","value: QueryValue | number | undefined","options?: AsNumberOptions","value: QueryValue | undefined","options?: AsStringOptions","options?: AsNumberArrayOptions","arrayValue: (string | null)[]","options?: AsArrayOptions<T>","arrayValue: QueryValue[]","transform","options?: AsBooleanOptions","transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n}","contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection>","contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem>","contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n>","contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n>","defaultHandlers: ContextStorageHandlerConstructor[]"],"sources":["../src/handlers/query/helpers.ts","../src/symbols.ts","../src/handlers/query/index.ts","../src/handlers/query/transform-helpers.ts","../src/injectionSymbols.ts","../src/index.ts"],"sourcesContent":["import { LocationQuery } from 'vue-router'\n\nexport interface SerializeOptions {\n /**\n * Custom prefix for serialized keys.\n * @example\n * - prefix: 'filters' => 'filters[key]'\n * - prefix: 'search' => 'search[key]'\n * - prefix: '' => 'key' (no prefix)\n */\n prefix?: string\n}\n\n/**\n * Serializes filter parameters into a URL-friendly format.\n *\n * @param params - Raw parameters object to serialize\n * @param options - Serialization options\n * @returns Serialized parameters with prefixed keys\n *\n * @example\n * // With default prefix 'filters'\n * serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })\n * // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }\n *\n * @example\n * // With custom prefix\n * serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })\n * // => { 'search[name]': 'John', 'search[all]': '1' }\n *\n * @example\n * // Without prefix\n * serializeFiltersParams({ page: 1, all: false }, { prefix: '' })\n * // => { 'page': '1', 'all': '0' }\n */\nexport function serializeParams(\n params: Record<string, unknown>,\n options: SerializeOptions = {},\n): LocationQuery {\n const { prefix = '' } = options\n\n const result: LocationQuery = {}\n\n Object.keys(params).forEach((key) => {\n const value = params[key]\n\n // Skip empty values, null, and empty arrays\n if (value === '') {\n return\n }\n\n if (value === null) {\n return\n }\n\n if (Array.isArray(value) && value.length === 0) {\n return\n }\n\n // Format the key with prefix (or without if prefix is empty)\n const formattedKey = prefix ? `${prefix}[${key}]` : key\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n // Serialize arrays directly: a=1&a=2&a=3\n result[formattedKey] = value.map(String)\n } else {\n Object.assign(\n result,\n serializeParams(value as Record<string, unknown>, {\n ...options,\n prefix: formattedKey,\n }),\n )\n }\n } else if (typeof value === 'boolean') {\n result[formattedKey] = value ? '1' : '0'\n } else {\n result[formattedKey] = String(value)\n }\n })\n\n return result\n}\n\n/**\n * Deserializes query parameters from a URL-friendly format back to an object.\n *\n * @param params - Serialized parameters object\n * @returns Deserialized parameters object\n *\n * @example\n * deserializeParams({ 'filters[status]': 'active', search: 'test' })\n * // => { filters: {status: 'active'}, search: 'test' }\n */\nexport function deserializeParams(params: Record<string, any>): Record<string, any> {\n return Object.keys(params).reduce<Record<string, any>>((acc, key) => {\n const value = params[key]\n\n // Parse nested structure: 'filters[status]' -> { filters: { status: value } }\n const bracketMatch = key.match(/^([^[]+)\\[(.+)]$/)\n\n if (bracketMatch) {\n const [, rootKey, nestedPath] = bracketMatch\n\n // Initialize root object if needed\n if (!acc[rootKey]) {\n acc[rootKey] = {}\n }\n\n // Parse nested path: 'created_at][from' -> ['created_at', 'from']\n const pathParts = nestedPath.split('][')\n\n // Navigate/create nested structure\n let current = acc[rootKey]\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i]\n if (!current[part]) {\n current[part] = {}\n }\n current = current[part]\n }\n\n // Set the final value\n const finalKey = pathParts[pathParts.length - 1]\n current[finalKey] = value\n } else {\n // No brackets - simple key\n acc[key] = value\n }\n\n return acc\n }, {})\n}\n","export const collection: unique symbol = Symbol('context-storage-collection')\nexport const collectionItem: unique symbol = Symbol('context-storage-collection-item')\nexport const handlers: unique symbol = Symbol('context-storage-handlers')\nexport const contextStorageQueryHandler: unique symbol = Symbol('context-storage-query-handler')\n","import { ContextStorageHandlerConstructor } from '../../handlers'\nimport { deserializeParams, serializeParams } from './helpers'\nimport { contextStorageQueryHandler } from '../../symbols'\nimport { cloneDeep, isEqual, merge, pick } from 'lodash-es'\nimport { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'\nimport { LocationQuery, useRoute, useRouter } from 'vue-router'\nimport {\n ContextStorageQueryRegisteredItem,\n IContextStorageQueryHandler,\n QueryHandlerBaseOptions,\n RegisterQueryHandlerBaseOptions,\n RegisterQueryHandlerOptions,\n} from './types'\n\nexport function useContextStorageQueryHandler<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options?: RegisterQueryHandlerBaseOptions<T>,\n): void {\n const handler = inject<InstanceType<typeof ContextStorageQueryHandler>>(\n contextStorageQueryHandler,\n )\n\n if (!handler) {\n throw new Error('[ContextStorage] ContextStorageQueryHandler is not provided')\n }\n\n const currentInstance = getCurrentInstance()\n const uid = currentInstance?.uid || 0\n\n const causer = new Error().stack?.split('\\n')[2]?.trimStart() || 'unknown'\n\n const stop = handler.register(data, { causer, uid, ...options })\n onBeforeUnmount(() => {\n stop()\n })\n}\n\nfunction sortQueryByReference(query: LocationQuery, ...references: LocationQuery[]): LocationQuery {\n const sorted: LocationQuery = {}\n\n const referenceKeys = new Set<string>()\n\n references.forEach((reference) => {\n Object.keys(reference).forEach((key) => {\n referenceKeys.add(key)\n })\n })\n\n referenceKeys.forEach((key) => {\n if (key in query && !(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n Object.keys(query).forEach((key) => {\n if (!(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n return sorted\n}\n\nexport class ContextStorageQueryHandler implements IContextStorageQueryHandler {\n private enabled = false\n private registered: ContextStorageQueryRegisteredItem<any>[] = []\n private currentQuery: LocationQuery | undefined = undefined\n private readonly route: ReturnType<typeof useRoute>\n private router: ReturnType<typeof useRouter>\n private initialState?: Record<string, unknown>\n private hasAnyRegistered = false\n private preventSyncRegisteredToQueryByAfterEachRoute = false\n private preventAfterEachRouteCallsWhileCallingRouter = false\n\n static customQueryHandlerOptions: QueryHandlerBaseOptions = {}\n\n private readonly options: Required<QueryHandlerBaseOptions> = {\n mode: 'replace',\n emptyPlaceholder: '_',\n mergeOnlyExistingKeysWithoutTransform: true,\n preserveUnusedKeys: false,\n preserveEmptyState: false,\n }\n\n // noinspection JSUnusedGlobalSymbols\n static configure(options: QueryHandlerBaseOptions): ContextStorageHandlerConstructor {\n ContextStorageQueryHandler.customQueryHandlerOptions = options\n\n return ContextStorageQueryHandler\n }\n\n constructor() {\n this.route = useRoute()\n this.router = useRouter()\n\n this.options = {\n ...this.options,\n ...ContextStorageQueryHandler.customQueryHandlerOptions,\n }\n\n const stopAfterEach = this.router.afterEach(() => {\n this.afterEachRoute()\n })\n\n onBeforeUnmount(() => {\n stopAfterEach()\n })\n }\n\n getInjectionKey(): typeof contextStorageQueryHandler {\n return contextStorageQueryHandler\n }\n\n setInitialState(state: Record<string, unknown> | undefined): void {\n this.initialState = state\n }\n\n static getInitialStateResolver(): () => LocationQuery {\n const route = useRoute()\n\n return () => route.query\n }\n\n setEnabled(state: boolean, initial: boolean): void {\n const prevState = this.enabled\n this.enabled = state\n\n if (this.hasAnyRegistered) {\n if (initial) {\n this.syncInitialStateToRegistered()\n }\n\n if ((state && !prevState) || !initial) {\n this.syncRegisteredToQuery()\n }\n }\n }\n\n async syncRegisteredToQuery(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n if (this.preventSyncRegisteredToQueryByAfterEachRoute) {\n return\n }\n\n const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered()\n\n this.currentQuery = newQueryRaw\n\n if (isEqual(newQuery, this.route.query)) {\n return\n }\n\n this.preventAfterEachRouteCallsWhileCallingRouter = true\n try {\n if (this.options.mode === 'replace') {\n await this.router.replace({ ...this.route, query: newQuery })\n } else {\n await this.router.push({ ...this.route, query: newQuery })\n }\n } catch (e) {\n console.error('[ContextStorage] Got error while routing', e)\n }\n this.preventAfterEachRouteCallsWhileCallingRouter = false\n }\n\n afterEachRoute(): void {\n if (!this.enabled) {\n return\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n return\n }\n\n this.setInitialState(this.route.query)\n\n this.preventSyncRegisteredToQueryByAfterEachRoute = true\n queueMicrotask(() => {\n this.preventSyncRegisteredToQueryByAfterEachRoute = false\n\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n\n setTimeout(() => {\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n }\n\n syncInitialStateToRegisteredItem<T extends Record<string, unknown>>(\n item: ContextStorageQueryRegisteredItem<T>,\n ): void {\n if (this.initialState === undefined) {\n return\n }\n\n let deserialized = deserializeParams(this.initialState)\n\n const {\n prefix,\n mergeOnlyExistingKeysWithoutTransform = this.options.mergeOnlyExistingKeysWithoutTransform,\n } = item.options || {}\n\n if (typeof prefix === 'string' && prefix.length > 0) {\n deserialized = deserialized[prefix]\n }\n\n if (deserialized === undefined) {\n return\n }\n\n const itemData = toValue(item.data)\n\n /**\n * null can be if query parameter only has a name without a value sign\n */\n if (deserialized !== null) {\n const deserializedKeys = Object.keys(deserialized)\n\n /**\n * If the data is empty, return the initial value.\n *\n * This can happen when directly navigating to a route, for example through a menu item.\n */\n if (!deserializedKeys.length) {\n merge(itemData, item.initialData)\n return\n }\n\n if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) {\n delete deserialized[this.options.emptyPlaceholder]\n }\n }\n\n if (item.options?.transform) {\n deserialized = item.options.transform(deserialized, item.initialData)\n } else {\n if (mergeOnlyExistingKeysWithoutTransform) {\n deserialized = pick(deserialized, Object.keys(item.initialData))\n }\n }\n\n if (isEqual(itemData, deserialized)) {\n return\n }\n\n merge(itemData, deserialized)\n }\n\n syncInitialStateToRegistered(): void {\n this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item))\n }\n\n register<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options: RegisterQueryHandlerOptions<T>,\n ): () => void {\n this.hasAnyRegistered = true\n\n const watchHandle = watch(data, () => this.syncRegisteredToQuery(), {\n deep: true,\n })\n\n const item: ContextStorageQueryRegisteredItem<T> = {\n data,\n initialData: cloneDeep(toValue(data)) as T,\n options,\n watchHandle,\n }\n this.registered.push(item)\n\n const syncCallback = (): void => {\n this.syncInitialStateToRegisteredItem(item)\n this.syncRegisteredToQuery()\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n /**\n * Macrotask solves syncing issues when syncRegisteredToQuery called after HMR\n */\n setTimeout(syncCallback)\n } else {\n queueMicrotask(syncCallback)\n }\n\n return (): void => {\n this.registered.splice(this.registered.indexOf(item), 1)\n this.syncRegisteredToQuery()\n }\n }\n\n #buildQueryFromRegistered(): { newQuery: LocationQuery; newQueryRaw: LocationQuery } {\n const newQueryRaw: LocationQuery = {}\n\n this.registered.forEach((item) => {\n const { prefix, preserveEmptyState = this.options.preserveEmptyState } = item.options || {}\n const patch = serializeParams(toValue(item.data), {\n prefix,\n })\n\n const patchKeys = Object.keys(patch)\n\n // If there are key intersections between the query and the patch, a warning is issued.\n // Patches should not overwrite each other, otherwise, upon reload, an incorrect value will be restored.\n patchKeys.forEach((key) => {\n if (newQueryRaw.hasOwnProperty(key)) {\n console.warn(\n `[ContextStorage] Key ${key} is already present, overriding ` +\n (item.options?.causer || ''),\n )\n }\n })\n\n if (!patchKeys.length && preserveEmptyState) {\n patch[prefix || this.options.emptyPlaceholder] = null\n }\n\n Object.assign(newQueryRaw, patch)\n })\n\n let newQuery = { ...newQueryRaw }\n\n /*\n * It will not delete from the query the keys that are not used in the patch.\n *\n * It will only work if the registered item has a transform, otherwise without\n * it - all keys are dumped into item.data during the initial fill from initialState\n */\n if (this.options.preserveUnusedKeys) {\n newQuery = { ...this.route.query, ...newQuery }\n }\n\n if (this.currentQuery !== undefined) {\n //Perform a diff of keys between currentQuery and newQueryRaw, and remove the keys that are in currentQuery but not in newQueryRaw.\n //This is necessary to ensure that the query string does not contain keys that are no longer used.\n Object.keys(this.currentQuery).forEach((key) => {\n if (!newQueryRaw.hasOwnProperty(key)) {\n delete newQuery[key]\n }\n })\n }\n\n if (Object.keys(newQuery).length > 1 && newQuery[this.options.emptyPlaceholder] === null) {\n delete newQuery[this.options.emptyPlaceholder]\n }\n\n newQuery = sortQueryByReference(newQuery, newQueryRaw)\n\n return { newQuery, newQueryRaw }\n }\n}\n","import { QueryValue } from './types'\n\ninterface AsNumberOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: number\n}\n\nexport function asNumber(value: QueryValue | number | undefined): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable: true; fallbackValue?: number },\n): number | null | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: number },\n): number | null\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: number },\n): number | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: number },\n): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options?: AsNumberOptions,\n): number | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : 0,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n value = Number(value)\n\n return isNaN(value) ? fallbackValue : value\n}\n\ninterface AsStringOptions<T extends readonly string[] = string[]> {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: T extends readonly string[] ? T[number] : string\n allowedValues?: T\n}\n\nexport function asString(value: QueryValue | undefined): string\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number]\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: string },\n): string | null | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: string },\n): string | null\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: string },\n): string | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: string },\n): string\nexport function asString(\n value: QueryValue | undefined,\n options?: AsStringOptions,\n): QueryValue | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : '',\n allowedValues,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n const stringValue = value ?? fallbackValue\n\n if (allowedValues && typeof stringValue === 'string' && !allowedValues.includes(stringValue)) {\n return fallbackValue\n }\n\n return stringValue\n}\n\ninterface AsNumberArrayOptions {\n nullable?: boolean\n}\n\nexport function asNumberArray(value: QueryValue | undefined): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable: true },\n): number[] | null\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable?: false },\n): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options?: AsNumberArrayOptions,\n): number[] | null {\n const { nullable = false } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: (string | null)[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else if (typeof value === 'string') {\n arrayValue = [value]\n } else {\n arrayValue = []\n }\n\n return arrayValue.map((item) => {\n if (item === null) {\n return 0\n }\n const num = Number(item)\n return isNaN(num) ? 0 : num\n })\n}\n\ninterface AsArrayOptions<T> {\n nullable?: boolean\n missable?: boolean\n transform?: (value: QueryValue) => T\n}\n\nexport function asArray<T>(value: QueryValue | undefined): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; transform?: (value: QueryValue) => T },\n): T[] | null | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; transform?: (value: QueryValue) => T },\n): T[] | null\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; transform?: (value: QueryValue) => T },\n): T[] | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; transform?: (value: QueryValue) => T },\n): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options?: AsArrayOptions<T>,\n): T[] | null | undefined {\n const { nullable = false, missable = false, transform } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: QueryValue[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else {\n arrayValue = [value]\n }\n\n if (transform) {\n return arrayValue.map((item) => transform(item))\n }\n\n return arrayValue as T[]\n}\n\ninterface AsBooleanOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: boolean\n}\n\nexport function asBoolean(value: QueryValue | undefined): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: boolean },\n): boolean | null | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: boolean },\n): boolean | null\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: boolean },\n): boolean | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: boolean },\n): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options?: AsBooleanOptions,\n): boolean | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : false,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined || value === null) {\n return fallbackValue\n }\n\n if (typeof value === 'string') {\n const lowerValue = value.toLowerCase()\n if (lowerValue === 'true' || lowerValue === '1') {\n return true\n }\n if (lowerValue === 'false' || lowerValue === '0') {\n return false\n }\n }\n\n return fallbackValue\n}\n\nexport const transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n} = {\n asString,\n asNumber,\n asArray,\n asNumberArray,\n asBoolean,\n}\n","import { ContextStorageCollection, ContextStorageCollectionItem } from './collection'\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\nimport { InjectionKey } from 'vue'\n\nexport const contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection> = collection\nexport const contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem> =\n collectionItem\nexport const contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n> = handlers\n\nexport const contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n> = contextStorageQueryHandler\n","// Core exports\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport type { ContextStorageHandlerConstructor } from './handlers'\n\nexport type {\n ContextStorageHandler,\n ContextStorageHandlerConstructor,\n RegisterBaseOptions,\n} from './handlers'\n\nexport { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'\n\n// Query helpers\nexport { deserializeParams, serializeParams } from './handlers/query/helpers'\nexport type { SerializeOptions } from './handlers/query/helpers'\n\n// Query transform helpers\nexport {\n asArray,\n asBoolean,\n asNumber,\n asNumberArray,\n asString,\n transform,\n} from './handlers/query/transform-helpers'\n\n// Injection symbols\nexport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n contextStorageQueryHandlerInjectKey,\n} from './injectionSymbols'\n\n// Symbols\nexport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\n\nexport const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]\nexport type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'\n\n// Export only type for ContextStorageCollectionItem to avoid naming conflict with component\nexport type { ContextStorageCollectionItem } from './collection'\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["params: Record<string, unknown>","options: SerializeOptions","result: LocationQuery","params: Record<string, any>","collection: unique symbol","collectionItem: unique symbol","handlers: unique symbol","contextStorageQueryHandler: unique symbol","data: MaybeRefOrGetter<T>","options?: RegisterQueryHandlerBaseOptions<T>","query: LocationQuery","sorted: LocationQuery","options: QueryHandlerBaseOptions","state: Record<string, unknown> | undefined","state: boolean","initial: boolean","#buildQueryFromRegistered","item: ContextStorageQueryRegisteredItem<T>","options: RegisterQueryHandlerOptions<T>","newQueryRaw: LocationQuery","contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection>","contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem>","contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n>","contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n>","handlerConstructors: ContextStorageHandlerConstructor[]","callback: (item: ContextStorageCollectionItem) => void","key: string","options: ItemOptions","handlers","item: ContextStorageCollectionItem","removeItem: ContextStorageCollectionItem","activeItem: ContextStorageCollectionItem","value: QueryValue | number | undefined","options?: AsNumberOptions","value: QueryValue | undefined","options?: AsStringOptions","options?: AsNumberArrayOptions","arrayValue: (string | null)[]","options?: AsArrayOptions<T>","arrayValue: QueryValue[]","transform","options?: AsBooleanOptions","transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n}","defaultHandlers: ContextStorageHandlerConstructor[]"],"sources":["../src/handlers/query/helpers.ts","../src/symbols.ts","../src/handlers/query/index.ts","../src/injectionSymbols.ts","../src/components/ContextStorageActivator.vue","../src/collection.ts","../src/components/ContextStorageCollection.vue","../src/components/ContextStorageProvider.vue","../src/components/ContextStorage.vue","../src/handlers/query/transform-helpers.ts","../src/index.ts"],"sourcesContent":["import { LocationQuery } from 'vue-router'\n\nexport interface SerializeOptions {\n /**\n * Custom prefix for serialized keys.\n * @example\n * - prefix: 'filters' => 'filters[key]'\n * - prefix: 'search' => 'search[key]'\n * - prefix: '' => 'key' (no prefix)\n */\n prefix?: string\n}\n\n/**\n * Serializes filter parameters into a URL-friendly format.\n *\n * @param params - Raw parameters object to serialize\n * @param options - Serialization options\n * @returns Serialized parameters with prefixed keys\n *\n * @example\n * // With default prefix 'filters'\n * serializeFiltersParams({ status: 'active', tags: ['a', 'b'] })\n * // => { 'filters[status]': 'active', 'filters[tags]': 'a,b' }\n *\n * @example\n * // With custom prefix\n * serializeFiltersParams({ name: 'John', all: true }, { prefix: 'search' })\n * // => { 'search[name]': 'John', 'search[all]': '1' }\n *\n * @example\n * // Without prefix\n * serializeFiltersParams({ page: 1, all: false }, { prefix: '' })\n * // => { 'page': '1', 'all': '0' }\n */\nexport function serializeParams(\n params: Record<string, unknown>,\n options: SerializeOptions = {},\n): LocationQuery {\n const { prefix = '' } = options\n\n const result: LocationQuery = {}\n\n Object.keys(params).forEach((key) => {\n const value = params[key]\n\n // Skip empty values, null, and empty arrays\n if (value === '') {\n return\n }\n\n if (value === null) {\n return\n }\n\n if (Array.isArray(value) && value.length === 0) {\n return\n }\n\n // Format the key with prefix (or without if prefix is empty)\n const formattedKey = prefix ? `${prefix}[${key}]` : key\n\n if (typeof value === 'object') {\n if (Array.isArray(value)) {\n // Serialize arrays directly: a=1&a=2&a=3\n result[formattedKey] = value.map(String)\n } else {\n Object.assign(\n result,\n serializeParams(value as Record<string, unknown>, {\n ...options,\n prefix: formattedKey,\n }),\n )\n }\n } else if (typeof value === 'boolean') {\n result[formattedKey] = value ? '1' : '0'\n } else {\n result[formattedKey] = String(value)\n }\n })\n\n return result\n}\n\n/**\n * Deserializes query parameters from a URL-friendly format back to an object.\n *\n * @param params - Serialized parameters object\n * @returns Deserialized parameters object\n *\n * @example\n * deserializeParams({ 'filters[status]': 'active', search: 'test' })\n * // => { filters: {status: 'active'}, search: 'test' }\n */\nexport function deserializeParams(params: Record<string, any>): Record<string, any> {\n return Object.keys(params).reduce<Record<string, any>>((acc, key) => {\n const value = params[key]\n\n // Parse nested structure: 'filters[status]' -> { filters: { status: value } }\n const bracketMatch = key.match(/^([^[]+)\\[(.+)]$/)\n\n if (bracketMatch) {\n const [, rootKey, nestedPath] = bracketMatch\n\n // Initialize root object if needed\n if (!acc[rootKey]) {\n acc[rootKey] = {}\n }\n\n // Parse nested path: 'created_at][from' -> ['created_at', 'from']\n const pathParts = nestedPath.split('][')\n\n // Navigate/create nested structure\n let current = acc[rootKey]\n for (let i = 0; i < pathParts.length - 1; i++) {\n const part = pathParts[i]\n if (!current[part]) {\n current[part] = {}\n }\n current = current[part]\n }\n\n // Set the final value\n const finalKey = pathParts[pathParts.length - 1]\n current[finalKey] = value\n } else {\n // No brackets - simple key\n acc[key] = value\n }\n\n return acc\n }, {})\n}\n","export const collection: unique symbol = Symbol('context-storage-collection')\nexport const collectionItem: unique symbol = Symbol('context-storage-collection-item')\nexport const handlers: unique symbol = Symbol('context-storage-handlers')\nexport const contextStorageQueryHandler: unique symbol = Symbol('context-storage-query-handler')\n","import { ContextStorageHandlerConstructor } from '../../handlers.ts'\nimport { deserializeParams, serializeParams } from './helpers.ts'\nimport { contextStorageQueryHandler } from '../../symbols.ts'\nimport { cloneDeep, isEqual, merge, pick } from 'lodash'\nimport { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'\nimport { LocationQuery, useRoute, useRouter } from 'vue-router'\nimport {\n ContextStorageQueryRegisteredItem,\n IContextStorageQueryHandler,\n QueryHandlerBaseOptions,\n RegisterQueryHandlerBaseOptions,\n RegisterQueryHandlerOptions,\n} from './types.ts'\n\nexport function useContextStorageQueryHandler<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options?: RegisterQueryHandlerBaseOptions<T>,\n): void {\n const handler = inject<InstanceType<typeof ContextStorageQueryHandler>>(\n contextStorageQueryHandler,\n )\n\n if (!handler) {\n throw new Error('[ContextStorage] ContextStorageQueryHandler is not provided')\n }\n\n const currentInstance = getCurrentInstance()\n const uid = currentInstance?.uid || 0\n\n const causer = new Error().stack?.split('\\n')[2]?.trimStart() || 'unknown'\n\n const stop = handler.register(data, { causer, uid, ...options })\n onBeforeUnmount(() => {\n stop()\n })\n}\n\nfunction sortQueryByReference(query: LocationQuery, ...references: LocationQuery[]): LocationQuery {\n const sorted: LocationQuery = {}\n\n const referenceKeys = new Set<string>()\n\n references.forEach((reference) => {\n Object.keys(reference).forEach((key) => {\n referenceKeys.add(key)\n })\n })\n\n referenceKeys.forEach((key) => {\n if (key in query && !(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n Object.keys(query).forEach((key) => {\n if (!(key in sorted)) {\n sorted[key] = query[key]\n }\n })\n\n return sorted\n}\n\nexport class ContextStorageQueryHandler implements IContextStorageQueryHandler {\n private enabled = false\n private registered: ContextStorageQueryRegisteredItem<any>[] = []\n private currentQuery: LocationQuery | undefined = undefined\n private readonly route: ReturnType<typeof useRoute>\n private router: ReturnType<typeof useRouter>\n private initialState?: Record<string, unknown>\n private hasAnyRegistered = false\n private preventSyncRegisteredToQueryByAfterEachRoute = false\n private preventAfterEachRouteCallsWhileCallingRouter = false\n\n static customQueryHandlerOptions: QueryHandlerBaseOptions = {}\n\n private readonly options: Required<QueryHandlerBaseOptions> = {\n mode: 'replace',\n emptyPlaceholder: '_',\n mergeOnlyExistingKeysWithoutTransform: true,\n preserveUnusedKeys: false,\n preserveEmptyState: false,\n }\n\n // noinspection JSUnusedGlobalSymbols\n static configure(options: QueryHandlerBaseOptions): ContextStorageHandlerConstructor {\n ContextStorageQueryHandler.customQueryHandlerOptions = options\n\n return ContextStorageQueryHandler\n }\n\n constructor() {\n this.route = useRoute()\n this.router = useRouter()\n\n this.options = {\n ...this.options,\n ...ContextStorageQueryHandler.customQueryHandlerOptions,\n }\n\n const stopAfterEach = this.router.afterEach(() => {\n this.afterEachRoute()\n })\n\n onBeforeUnmount(() => {\n stopAfterEach()\n })\n }\n\n getInjectionKey(): typeof contextStorageQueryHandler {\n return contextStorageQueryHandler\n }\n\n setInitialState(state: Record<string, unknown> | undefined): void {\n this.initialState = state\n }\n\n static getInitialStateResolver(): () => LocationQuery {\n const route = useRoute()\n\n return () => route.query\n }\n\n setEnabled(state: boolean, initial: boolean): void {\n const prevState = this.enabled\n this.enabled = state\n\n if (this.hasAnyRegistered) {\n if (initial) {\n this.syncInitialStateToRegistered()\n }\n\n if ((state && !prevState) || !initial) {\n this.syncRegisteredToQuery()\n }\n }\n }\n\n async syncRegisteredToQuery(): Promise<void> {\n if (!this.enabled) {\n return\n }\n\n if (this.preventSyncRegisteredToQueryByAfterEachRoute) {\n return\n }\n\n const { newQuery, newQueryRaw } = this.#buildQueryFromRegistered()\n\n this.currentQuery = newQueryRaw\n\n if (isEqual(newQuery, this.route.query)) {\n return\n }\n\n this.preventAfterEachRouteCallsWhileCallingRouter = true\n try {\n if (this.options.mode === 'replace') {\n await this.router.replace({ ...this.route, query: newQuery })\n } else {\n await this.router.push({ ...this.route, query: newQuery })\n }\n } catch (e) {\n console.error('[ContextStorage] Got error while routing', e)\n }\n this.preventAfterEachRouteCallsWhileCallingRouter = false\n }\n\n afterEachRoute(): void {\n if (!this.enabled) {\n return\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n return\n }\n\n this.setInitialState(this.route.query)\n\n this.preventSyncRegisteredToQueryByAfterEachRoute = true\n queueMicrotask(() => {\n this.preventSyncRegisteredToQueryByAfterEachRoute = false\n\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n\n setTimeout(() => {\n this.syncInitialStateToRegistered()\n this.syncRegisteredToQuery()\n })\n }\n\n syncInitialStateToRegisteredItem<T extends Record<string, unknown>>(\n item: ContextStorageQueryRegisteredItem<T>,\n ): void {\n if (this.initialState === undefined) {\n return\n }\n\n let deserialized = deserializeParams(this.initialState)\n\n const {\n prefix,\n mergeOnlyExistingKeysWithoutTransform = this.options.mergeOnlyExistingKeysWithoutTransform,\n } = item.options || {}\n\n if (typeof prefix === 'string' && prefix.length > 0) {\n deserialized = deserialized[prefix]\n }\n\n if (deserialized === undefined) {\n return\n }\n\n const itemData = toValue(item.data)\n\n /**\n * null can be if query parameter only has a name without a value sign\n */\n if (deserialized !== null) {\n const deserializedKeys = Object.keys(deserialized)\n\n /**\n * If the data is empty, return the initial value.\n *\n * This can happen when directly navigating to a route, for example through a menu item.\n */\n if (!deserializedKeys.length) {\n merge(itemData, item.initialData)\n return\n }\n\n if (deserializedKeys.length === 1 && deserialized[this.options.emptyPlaceholder] === null) {\n delete deserialized[this.options.emptyPlaceholder]\n }\n }\n\n if (item.options?.transform) {\n deserialized = item.options.transform(deserialized, item.initialData)\n } else {\n if (mergeOnlyExistingKeysWithoutTransform) {\n deserialized = pick(deserialized, Object.keys(item.initialData))\n }\n }\n\n if (isEqual(itemData, deserialized)) {\n return\n }\n\n merge(itemData, deserialized)\n }\n\n syncInitialStateToRegistered(): void {\n this.registered.forEach((item) => this.syncInitialStateToRegisteredItem(item))\n }\n\n register<T extends Record<string, unknown>>(\n data: MaybeRefOrGetter<T>,\n options: RegisterQueryHandlerOptions<T>,\n ): () => void {\n this.hasAnyRegistered = true\n\n const watchHandle = watch(data, () => this.syncRegisteredToQuery(), {\n deep: true,\n })\n\n const item: ContextStorageQueryRegisteredItem<T> = {\n data,\n initialData: cloneDeep(toValue(data)) as T,\n options,\n watchHandle,\n }\n this.registered.push(item)\n\n const syncCallback = (): void => {\n this.syncInitialStateToRegisteredItem(item)\n this.syncRegisteredToQuery()\n }\n\n if (this.preventAfterEachRouteCallsWhileCallingRouter) {\n /**\n * Macrotask solves syncing issues when syncRegisteredToQuery called after HMR\n */\n setTimeout(syncCallback)\n } else {\n queueMicrotask(syncCallback)\n }\n\n return (): void => {\n this.registered.splice(this.registered.indexOf(item), 1)\n this.syncRegisteredToQuery()\n }\n }\n\n #buildQueryFromRegistered(): { newQuery: LocationQuery; newQueryRaw: LocationQuery } {\n const newQueryRaw: LocationQuery = {}\n\n this.registered.forEach((item) => {\n const { prefix, preserveEmptyState = this.options.preserveEmptyState } = item.options || {}\n const patch = serializeParams(toValue(item.data), {\n prefix,\n })\n\n const patchKeys = Object.keys(patch)\n\n // If there are key intersections between the query and the patch, a warning is issued.\n // Patches should not overwrite each other, otherwise, upon reload, an incorrect value will be restored.\n patchKeys.forEach((key) => {\n if (newQueryRaw.hasOwnProperty(key)) {\n console.warn(\n `[ContextStorage] Key ${key} is already present, overriding ` +\n (item.options?.causer || ''),\n )\n }\n })\n\n if (!patchKeys.length && preserveEmptyState) {\n patch[prefix || this.options.emptyPlaceholder] = null\n }\n\n Object.assign(newQueryRaw, patch)\n })\n\n let newQuery = { ...newQueryRaw }\n\n /*\n * It will not delete from the query the keys that are not used in the patch.\n *\n * It will only work if the registered item has a transform, otherwise without\n * it - all keys are dumped into item.data during the initial fill from initialState\n */\n if (this.options.preserveUnusedKeys) {\n newQuery = { ...this.route.query, ...newQuery }\n }\n\n if (this.currentQuery !== undefined) {\n //Perform a diff of keys between currentQuery and newQueryRaw, and remove the keys that are in currentQuery but not in newQueryRaw.\n //This is necessary to ensure that the query string does not contain keys that are no longer used.\n Object.keys(this.currentQuery).forEach((key) => {\n if (!newQueryRaw.hasOwnProperty(key)) {\n delete newQuery[key]\n }\n })\n }\n\n if (Object.keys(newQuery).length > 1 && newQuery[this.options.emptyPlaceholder] === null) {\n delete newQuery[this.options.emptyPlaceholder]\n }\n\n newQuery = sortQueryByReference(newQuery, newQueryRaw)\n\n return { newQuery, newQueryRaw }\n }\n}\n","import { ContextStorageCollection, ContextStorageCollectionItem } from './collection'\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\nimport { InjectionKey } from 'vue'\n\nexport const contextStorageCollectionInjectKey: InjectionKey<ContextStorageCollection> = collection\nexport const contextStorageCollectionItemInjectKey: InjectionKey<ContextStorageCollectionItem> =\n collectionItem\nexport const contextStorageHandlersInjectKey: InjectionKey<\n ContextStorageCollectionItem['handlers']\n> = handlers\n\nexport const contextStorageQueryHandlerInjectKey: InjectionKey<\n InstanceType<typeof ContextStorageQueryHandler>\n> = contextStorageQueryHandler\n","<script lang=\"ts\">\nimport { defineComponent, h, inject } from 'vue'\nimport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n} from '../injectionSymbols'\n\nexport default defineComponent({\n setup(_, { slots }) {\n const collection = inject(contextStorageCollectionInjectKey)!\n const item = inject(contextStorageCollectionItemInjectKey)!\n\n const onActivate = () => {\n collection.setActive(item)\n }\n\n return () => h('div', { onMousedown: onActivate }, slots.default?.())\n },\n})\n</script>\n","import { ContextStorageHandler, ContextStorageHandlerConstructor } from './handlers'\n\nexport type ContextStorageCollectionItem = {\n key: string\n handlers: ContextStorageHandler[]\n}\n\ninterface ItemOptions {\n key: string\n}\n\nexport class ContextStorageCollection {\n public active?: ContextStorageCollectionItem = undefined\n private collection: ContextStorageCollectionItem[] = []\n private onActiveChangeCallbacks: ((item: ContextStorageCollectionItem) => void)[] = []\n\n constructor(private handlerConstructors: ContextStorageHandlerConstructor[]) {}\n\n onActiveChange(callback: (item: ContextStorageCollectionItem) => void): void {\n this.onActiveChangeCallbacks.push(callback)\n }\n\n first(): ContextStorageCollectionItem | undefined {\n return this.collection[0]\n }\n\n findItemByKey(key: string): ContextStorageCollectionItem | undefined {\n return this.collection.find((item) => item.key === key)\n }\n\n add(options: ItemOptions): ContextStorageCollectionItem {\n const handlers = this.handlerConstructors.map((constructor) => new constructor())\n\n const item: ContextStorageCollectionItem = { handlers, key: options.key }\n\n this.collection.push(item)\n\n return item\n }\n\n remove(removeItem: ContextStorageCollectionItem): void {\n if (this.collection.indexOf(removeItem) === -1) {\n throw new Error('[ContextStorage] Item not found in collection')\n }\n\n this.collection = this.collection.filter((item) => item !== removeItem)\n\n if (this.active === removeItem && this.collection.length > 0) {\n this.setActive(this.collection[this.collection.length - 1])\n }\n }\n\n setActive(activeItem: ContextStorageCollectionItem): void {\n if (this.active === activeItem) {\n return\n }\n\n const hasActiveBefore = this.active !== undefined\n this.active = activeItem\n\n this.collection.forEach((item) => {\n Object.values(item.handlers).forEach((handler) => {\n if (handler.setEnabled) {\n handler.setEnabled(item === activeItem, !hasActiveBefore)\n }\n })\n })\n\n this.onActiveChangeCallbacks.forEach((callback) => callback(activeItem))\n }\n}\n","<script lang=\"ts\">\nimport { ContextStorageCollection, ContextStorageCollectionItem } from '../collection'\nimport { ContextStorageHandlerConstructor } from '../handlers'\nimport { contextStorageCollectionInjectKey } from '../injectionSymbols'\nimport { computed, defineComponent, PropType, provide } from 'vue'\nimport { useRouter } from 'vue-router'\nimport { defaultHandlers } from '../index.ts'\n\nexport default defineComponent({\n props: {\n handlers: {\n type: Object as PropType<ContextStorageHandlerConstructor[]>,\n default: defaultHandlers,\n },\n },\n setup({ handlers }, { slots }) {\n const lastActive = computed({\n get: () => localStorage.getItem('context-storage-last-active') || 'main',\n set: (value) => localStorage.setItem('context-storage-last-active', value),\n })\n\n const router = useRouter()\n\n const initialNavigatorState = new Map<\n ContextStorageHandlerConstructor,\n Record<string, unknown>\n >()\n const initialNavigatorStateResolvers = new Map<\n ContextStorageHandlerConstructor,\n () => Record<string, unknown>\n >()\n\n handlers.forEach((handler) => {\n if (!handler.getInitialStateResolver) {\n return\n }\n\n initialNavigatorStateResolvers.set(handler, handler.getInitialStateResolver())\n })\n\n router.isReady().then(() => {\n initialNavigatorStateResolvers.forEach((resolver, handler) => {\n initialNavigatorState.set(handler, resolver())\n })\n\n activateLastActiveItem()\n })\n\n const collection = new ContextStorageCollection(handlers)\n collection.onActiveChange((item) => {\n lastActive.value = item.key\n })\n\n provide(contextStorageCollectionInjectKey, collection)\n\n const activateInitialItem = (item: ContextStorageCollectionItem) => {\n item.handlers.forEach((handler) => {\n const state = initialNavigatorState.get(\n handler.constructor as ContextStorageHandlerConstructor,\n )\n\n if (!state) {\n return\n }\n\n handler.setInitialState?.(state)\n })\n\n collection.setActive(item)\n }\n\n const activateLastActiveItem = () => {\n const lastActiveItem = collection.findItemByKey(lastActive.value)\n if (lastActiveItem) {\n activateInitialItem(lastActiveItem)\n return\n }\n\n const firstItem = collection.first()\n if (!firstItem) {\n throw new Error('[ContextStorage] Cannot find first item in collection')\n }\n\n activateInitialItem(firstItem)\n }\n\n return () => {\n return slots.default?.()\n }\n },\n})\n</script>\n","<script lang=\"ts\">\nimport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n} from '../injectionSymbols'\nimport { defineComponent, inject, onUnmounted, provide } from 'vue'\n\nexport default defineComponent({\n props: {\n itemKey: {\n type: String,\n required: true,\n },\n },\n setup(props, { slots }) {\n const collection = inject(contextStorageCollectionInjectKey)\n if (!collection) throw new Error('[ContextStorage] Context storage collection not found')\n\n const item = collection.add({\n key: props.itemKey,\n })\n\n provide(contextStorageCollectionItemInjectKey, item)\n provide(contextStorageHandlersInjectKey, item.handlers)\n\n item.handlers.forEach((handler) => {\n provide(handler.getInjectionKey(), handler)\n })\n\n onUnmounted(() => {\n collection.remove(item)\n })\n\n return () => slots.default?.()\n },\n})\n</script>\n","<template>\n <ContextStorageCollection :handlers=\"handlers\">\n <ContextStorageProvider item-key=\"main\">\n <ContextStorageActivator>\n <slot />\n </ContextStorageActivator>\n </ContextStorageProvider>\n </ContextStorageCollection>\n</template>\n\n<script setup lang=\"ts\">\nimport ContextStorageActivator from './ContextStorageActivator.vue'\nimport ContextStorageCollection from './ContextStorageCollection.vue'\nimport ContextStorageProvider from './ContextStorageProvider.vue'\nimport { ContextStorageHandlerConstructor } from '../handlers'\nimport { defaultHandlers } from '../index'\n\ninterface Props {\n handlers: ContextStorageHandlerConstructor[]\n}\n\nconst { handlers = defaultHandlers } = defineProps<Props>()\n</script>\n","import { QueryValue } from './types.ts'\n\ninterface AsNumberOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: number\n}\n\nexport function asNumber(value: QueryValue | number | undefined): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable: true; fallbackValue?: number },\n): number | null | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: number },\n): number | null\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: number },\n): number | undefined\nexport function asNumber(\n value: QueryValue | number | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: number },\n): number\nexport function asNumber(\n value: QueryValue | number | undefined,\n options?: AsNumberOptions,\n): number | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : 0,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n value = Number(value)\n\n return isNaN(value) ? fallbackValue : value\n}\n\ninterface AsStringOptions<T extends readonly string[] = string[]> {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: T extends readonly string[] ? T[number] : string\n allowedValues?: T\n}\n\nexport function asString(value: QueryValue | undefined): string\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable: true\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | null\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable: true\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number] | undefined\nexport function asString<T extends readonly string[]>(\n value: QueryValue | undefined,\n options: {\n nullable?: false\n missable?: false\n fallbackValue?: T[number]\n allowedValues: T\n },\n): T[number]\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: string },\n): string | null | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: string },\n): string | null\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: string },\n): string | undefined\nexport function asString(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: string },\n): string\nexport function asString(\n value: QueryValue | undefined,\n options?: AsStringOptions,\n): QueryValue | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : '',\n allowedValues,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n const stringValue = value ?? fallbackValue\n\n if (allowedValues && typeof stringValue === 'string' && !allowedValues.includes(stringValue)) {\n return fallbackValue\n }\n\n return stringValue\n}\n\ninterface AsNumberArrayOptions {\n nullable?: boolean\n}\n\nexport function asNumberArray(value: QueryValue | undefined): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable: true },\n): number[] | null\nexport function asNumberArray(\n value: QueryValue | undefined,\n options: { nullable?: false },\n): number[]\nexport function asNumberArray(\n value: QueryValue | undefined,\n options?: AsNumberArrayOptions,\n): number[] | null {\n const { nullable = false } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: (string | null)[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else if (typeof value === 'string') {\n arrayValue = [value]\n } else {\n arrayValue = []\n }\n\n return arrayValue.map((item) => {\n if (item === null) {\n return 0\n }\n const num = Number(item)\n return isNaN(num) ? 0 : num\n })\n}\n\ninterface AsArrayOptions<T> {\n nullable?: boolean\n missable?: boolean\n transform?: (value: QueryValue) => T\n}\n\nexport function asArray<T>(value: QueryValue | undefined): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; transform?: (value: QueryValue) => T },\n): T[] | null | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; transform?: (value: QueryValue) => T },\n): T[] | null\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; transform?: (value: QueryValue) => T },\n): T[] | undefined\nexport function asArray<T>(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; transform?: (value: QueryValue) => T },\n): T[]\nexport function asArray<T>(\n value: QueryValue | undefined,\n options?: AsArrayOptions<T>,\n): T[] | null | undefined {\n const { nullable = false, missable = false, transform } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined) {\n return nullable ? null : []\n }\n\n let arrayValue: QueryValue[]\n\n if (Array.isArray(value)) {\n arrayValue = value\n } else {\n arrayValue = [value]\n }\n\n if (transform) {\n return arrayValue.map((item) => transform(item))\n }\n\n return arrayValue as T[]\n}\n\ninterface AsBooleanOptions {\n nullable?: boolean\n missable?: boolean\n fallbackValue?: boolean\n}\n\nexport function asBoolean(value: QueryValue | undefined): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable: true; fallbackValue?: boolean },\n): boolean | null | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable: true; missable?: false; fallbackValue?: boolean },\n): boolean | null\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable: true; fallbackValue?: boolean },\n): boolean | undefined\nexport function asBoolean(\n value: QueryValue | undefined,\n options: { nullable?: false; missable?: false; fallbackValue?: boolean },\n): boolean\nexport function asBoolean(\n value: QueryValue | undefined,\n options?: AsBooleanOptions,\n): boolean | null | undefined {\n const {\n nullable = false,\n missable = false,\n fallbackValue = missable ? undefined : nullable ? null : false,\n } = options || {}\n\n if (value === null && nullable) {\n return null\n }\n\n if (value === undefined && missable) {\n return undefined\n }\n\n if (value === undefined || value === null) {\n return fallbackValue\n }\n\n if (typeof value === 'string') {\n const lowerValue = value.toLowerCase()\n if (lowerValue === 'true' || lowerValue === '1') {\n return true\n }\n if (lowerValue === 'false' || lowerValue === '0') {\n return false\n }\n }\n\n return fallbackValue\n}\n\nexport const transform: {\n asString: typeof asString\n asNumber: typeof asNumber\n asArray: typeof asArray\n asNumberArray: typeof asNumberArray\n asBoolean: typeof asBoolean\n} = {\n asString,\n asNumber,\n asArray,\n asNumberArray,\n asBoolean,\n}\n","// Core exports\nimport { ContextStorageQueryHandler } from './handlers/query'\nimport type { ContextStorageHandlerConstructor } from './handlers'\n\nexport { default as ContextStorageActivator } from './components/ContextStorageActivator.vue'\nexport { default as ContextStorageCollection } from './components/ContextStorageCollection.vue'\nexport { default as ContextStorageProvider } from './components/ContextStorageProvider.vue'\nexport { default as ContextStorage } from './components/ContextStorage.vue'\n\nexport type {\n ContextStorageHandler,\n ContextStorageHandlerConstructor,\n RegisterBaseOptions,\n} from './handlers'\n\nexport { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'\n\n// Query helpers\nexport { deserializeParams, serializeParams } from './handlers/query/helpers.ts'\nexport type { SerializeOptions } from './handlers/query/helpers.ts'\n\n// Query transform helpers\nexport {\n asArray,\n asBoolean,\n asNumber,\n asNumberArray,\n asString,\n transform,\n} from './handlers/query/transform-helpers.ts'\n\n// Injection symbols\nexport {\n contextStorageCollectionInjectKey,\n contextStorageCollectionItemInjectKey,\n contextStorageHandlersInjectKey,\n contextStorageQueryHandlerInjectKey,\n} from './injectionSymbols'\n\n// Symbols\nexport { collection, collectionItem, contextStorageQueryHandler, handlers } from './symbols'\n\nexport const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]\nexport type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,72 +1,83 @@
1
- {
2
- "name": "vue-context-storage",
3
- "version": "0.1.7",
4
- "description": "Vue 3 context storage system with URL query synchronization support",
5
- "repository": {
6
- "type": "git",
7
- "url": "https://github.com/lviobio/vue-context-storage.git"
8
- },
9
- "type": "module",
10
- "main": "./dist/index.cjs",
11
- "module": "./dist/index.js",
12
- "types": "./dist/index.d.ts",
13
- "exports": {
14
- ".": {
15
- "import": "./src/main.ts",
16
- "require": {
17
- "types": "./dist/index.d.cts",
18
- "default": "./dist/index.cjs"
19
- }
20
- }
21
- },
22
- "files": [
23
- "dist",
24
- "src",
25
- "README.md"
26
- ],
27
- "scripts": {
28
- "build": "tsdown",
29
- "dev": "tsdown --watch",
30
- "check": "npm run ts:check && npm run lint:check && npm run format:check && npm run dependency-cruiser:check",
31
- "ts:check": "tsc --noEmit",
32
- "format": "prettier --write src/",
33
- "format:check": "prettier --check src/",
34
- "lint": "eslint . --fix",
35
- "lint:check": "eslint .",
36
- "dependency-cruiser:check": "depcruise --config .dependency-cruiser.cjs src",
37
- "prepublishOnly": "npm run check && npm run build"
38
- },
39
- "keywords": [
40
- "vue",
41
- "vue3",
42
- "context",
43
- "storage",
44
- "state-management",
45
- "query-sync"
46
- ],
47
- "author": "",
48
- "license": "MIT",
49
- "peerDependencies": {
50
- "vue": "^3.5.0",
51
- "vue-router": "^4.0.0"
52
- },
53
- "dependencies": {
54
- "lodash-es": "^4.17.21"
55
- },
56
- "devDependencies": {
57
- "@eslint/js": "^9.39.2",
58
- "@types/lodash-es": "^4.17.12",
59
- "@types/node": "^20.0.0",
60
- "@vue/eslint-config-typescript": "^14.6.0",
61
- "dependency-cruiser": "^17.3.6",
62
- "eslint": "^9.39.2",
63
- "eslint-config-prettier": "^10.1.8",
64
- "eslint-plugin-vue": "^10.6.2",
65
- "prettier": "^3.7.4",
66
- "tsdown": "^0.3.0",
67
- "typescript": "^5.9.0",
68
- "typescript-eslint": "^8.51.0",
69
- "vue": "^3.5.26",
70
- "vue-router": "^4.6.4"
71
- }
72
- }
1
+ {
2
+ "name": "vue-context-storage",
3
+ "version": "0.1.9",
4
+ "description": "Vue 3 context storage system with URL query synchronization support",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/lviobio/vue-context-storage.git"
8
+ },
9
+ "type": "module",
10
+ "main": "./dist/index.cjs",
11
+ "module": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "require": {
20
+ "types": "./dist/index.d.cts",
21
+ "default": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "./components": {
25
+ "import": "./src/components.ts"
26
+ },
27
+ "./plugin": {
28
+ "import": "./src/plugin.ts"
29
+ }
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "src",
34
+ "README.md"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsdown",
38
+ "dev": "tsdown --watch",
39
+ "check": "npm run ts:check && npm run lint:check && npm run format:check && npm run dependency-cruiser:check",
40
+ "ts:check": "tsc --noEmit",
41
+ "format": "prettier --write src/",
42
+ "format:check": "prettier --check src/",
43
+ "lint": "eslint . --fix",
44
+ "lint:check": "eslint .",
45
+ "dependency-cruiser:check": "depcruise --config .dependency-cruiser.cjs src",
46
+ "prepublishOnly": "npm run check && npm run build"
47
+ },
48
+ "keywords": [
49
+ "vue",
50
+ "vue3",
51
+ "context",
52
+ "storage",
53
+ "state-management",
54
+ "query-sync"
55
+ ],
56
+ "author": "",
57
+ "license": "MIT",
58
+ "peerDependencies": {
59
+ "vue": "^3.5.0",
60
+ "vue-router": "^4.0.0"
61
+ },
62
+ "dependencies": {
63
+ "lodash": "^4.17.21"
64
+ },
65
+ "devDependencies": {
66
+ "@eslint/js": "^9.39.2",
67
+ "@types/lodash": "^4.17.15",
68
+ "@types/node": "^20.0.0",
69
+ "@vue/eslint-config-typescript": "^14.6.0",
70
+ "dependency-cruiser": "^17.3.6",
71
+ "eslint": "^9.39.2",
72
+ "eslint-config-prettier": "^10.1.8",
73
+ "eslint-plugin-vue": "^10.6.2",
74
+ "prettier": "^3.7.4",
75
+ "tsdown": "^0.3.0",
76
+ "typescript": "^5.9.0",
77
+ "typescript-eslint": "^8.51.0",
78
+ "unplugin-vue": "^7.1.0",
79
+ "vue": "^3.5.26",
80
+ "vue-router": "^4.6.4",
81
+ "vue-tsc": "^3.2.1"
82
+ }
83
+ }
@@ -4,7 +4,7 @@ import { ContextStorageHandlerConstructor } from '../handlers'
4
4
  import { contextStorageCollectionInjectKey } from '../injectionSymbols'
5
5
  import { computed, defineComponent, PropType, provide } from 'vue'
6
6
  import { useRouter } from 'vue-router'
7
- import { defaultHandlers } from '../index'
7
+ import { defaultHandlers } from '../index.ts'
8
8
 
9
9
  export default defineComponent({
10
10
  props: {
@@ -1,12 +1,5 @@
1
- // Main entry point that includes everything (for ESM usage)
2
- // This ensures all imports come from the same module instance
3
- export * from './index'
4
-
5
- // Components
1
+ // Vue components - import directly from source
6
2
  export { default as ContextStorageActivator } from './components/ContextStorageActivator.vue'
7
3
  export { default as ContextStorageCollection } from './components/ContextStorageCollection.vue'
8
4
  export { default as ContextStorageProvider } from './components/ContextStorageProvider.vue'
9
5
  export { default as ContextStorage } from './components/ContextStorage.vue'
10
-
11
- // Plugin
12
- export { VueContextStoragePlugin, VueContextStoragePlugin as default } from './plugin'
@@ -1,7 +1,7 @@
1
- import { ContextStorageHandlerConstructor } from '../../handlers'
2
- import { deserializeParams, serializeParams } from './helpers'
3
- import { contextStorageQueryHandler } from '../../symbols'
4
- import { cloneDeep, isEqual, merge, pick } from 'lodash-es'
1
+ import { ContextStorageHandlerConstructor } from '../../handlers.ts'
2
+ import { deserializeParams, serializeParams } from './helpers.ts'
3
+ import { contextStorageQueryHandler } from '../../symbols.ts'
4
+ import { cloneDeep, isEqual, merge, pick } from 'lodash'
5
5
  import { getCurrentInstance, inject, MaybeRefOrGetter, onBeforeUnmount, toValue, watch } from 'vue'
6
6
  import { LocationQuery, useRoute, useRouter } from 'vue-router'
7
7
  import {
@@ -10,7 +10,7 @@ import {
10
10
  QueryHandlerBaseOptions,
11
11
  RegisterQueryHandlerBaseOptions,
12
12
  RegisterQueryHandlerOptions,
13
- } from './types'
13
+ } from './types.ts'
14
14
 
15
15
  export function useContextStorageQueryHandler<T extends Record<string, unknown>>(
16
16
  data: MaybeRefOrGetter<T>,
@@ -1,4 +1,4 @@
1
- import { QueryValue } from './types'
1
+ import { QueryValue } from './types.ts'
2
2
 
3
3
  interface AsNumberOptions {
4
4
  nullable?: boolean
@@ -1,6 +1,6 @@
1
1
  import { LocationQueryValue } from 'vue-router'
2
2
  import { MaybeRefOrGetter, UnwrapNestedRefs, WatchHandle } from 'vue'
3
- import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers'
3
+ import { ContextStorageHandler, RegisterBaseOptions } from '../../handlers.ts'
4
4
 
5
5
  export type QueryValue = LocationQueryValue | LocationQueryValue[]
6
6
 
package/src/index.ts CHANGED
@@ -2,6 +2,11 @@
2
2
  import { ContextStorageQueryHandler } from './handlers/query'
3
3
  import type { ContextStorageHandlerConstructor } from './handlers'
4
4
 
5
+ export { default as ContextStorageActivator } from './components/ContextStorageActivator.vue'
6
+ export { default as ContextStorageCollection } from './components/ContextStorageCollection.vue'
7
+ export { default as ContextStorageProvider } from './components/ContextStorageProvider.vue'
8
+ export { default as ContextStorage } from './components/ContextStorage.vue'
9
+
5
10
  export type {
6
11
  ContextStorageHandler,
7
12
  ContextStorageHandlerConstructor,
@@ -11,8 +16,8 @@ export type {
11
16
  export { ContextStorageQueryHandler, useContextStorageQueryHandler } from './handlers/query'
12
17
 
13
18
  // Query helpers
14
- export { deserializeParams, serializeParams } from './handlers/query/helpers'
15
- export type { SerializeOptions } from './handlers/query/helpers'
19
+ export { deserializeParams, serializeParams } from './handlers/query/helpers.ts'
20
+ export type { SerializeOptions } from './handlers/query/helpers.ts'
16
21
 
17
22
  // Query transform helpers
18
23
  export {
@@ -22,7 +27,7 @@ export {
22
27
  asNumberArray,
23
28
  asString,
24
29
  transform,
25
- } from './handlers/query/transform-helpers'
30
+ } from './handlers/query/transform-helpers.ts'
26
31
 
27
32
  // Injection symbols
28
33
  export {
@@ -37,6 +42,3 @@ export { collection, collectionItem, contextStorageQueryHandler, handlers } from
37
42
 
38
43
  export const defaultHandlers: ContextStorageHandlerConstructor[] = [ContextStorageQueryHandler]
39
44
  export type { QueryValue, IContextStorageQueryHandler } from './handlers/query/types'
40
-
41
- // Export only type for ContextStorageCollectionItem to avoid naming conflict with component
42
- export type { ContextStorageCollectionItem } from './collection'