@bquery/bquery 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -120
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/index.d.ts +2 -0
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/library.d.ts +34 -0
- package/dist/component/library.d.ts.map +1 -0
- package/dist/component/types.d.ts +10 -6
- package/dist/component/types.d.ts.map +1 -1
- package/dist/component-CY5MVoYN.js +531 -0
- package/dist/component-CY5MVoYN.js.map +1 -0
- package/dist/component.es.mjs +6 -184
- package/dist/config-DRmZZno3.js +40 -0
- package/dist/config-DRmZZno3.js.map +1 -0
- package/dist/core-CK2Mfpf4.js +648 -0
- package/dist/core-CK2Mfpf4.js.map +1 -0
- package/dist/core-DPdbItcq.js +112 -0
- package/dist/core-DPdbItcq.js.map +1 -0
- package/dist/core.es.mjs +45 -1261
- package/dist/full.d.ts +6 -6
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +98 -92
- package/dist/full.iife.js +173 -3
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +173 -3
- package/dist/full.umd.js.map +1 -1
- package/dist/index.es.mjs +143 -139
- package/dist/motion/transition.d.ts +1 -1
- package/dist/motion/transition.d.ts.map +1 -1
- package/dist/motion/types.d.ts +11 -1
- package/dist/motion/types.d.ts.map +1 -1
- package/dist/motion-C5DRdPnO.js +415 -0
- package/dist/motion-C5DRdPnO.js.map +1 -0
- package/dist/motion.es.mjs +25 -361
- package/dist/object-qGpWr6-J.js +38 -0
- package/dist/object-qGpWr6-J.js.map +1 -0
- package/dist/platform/announcer.d.ts +59 -0
- package/dist/platform/announcer.d.ts.map +1 -0
- package/dist/platform/config.d.ts +92 -0
- package/dist/platform/config.d.ts.map +1 -0
- package/dist/platform/cookies.d.ts +45 -0
- package/dist/platform/cookies.d.ts.map +1 -0
- package/dist/platform/index.d.ts +8 -0
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/meta.d.ts +62 -0
- package/dist/platform/meta.d.ts.map +1 -0
- package/dist/platform-B7JhGBc7.js +361 -0
- package/dist/platform-B7JhGBc7.js.map +1 -0
- package/dist/platform.es.mjs +11 -248
- package/dist/reactive/async-data.d.ts +114 -0
- package/dist/reactive/async-data.d.ts.map +1 -0
- package/dist/reactive/index.d.ts +2 -2
- package/dist/reactive/index.d.ts.map +1 -1
- package/dist/reactive/signal.d.ts +2 -0
- package/dist/reactive/signal.d.ts.map +1 -1
- package/dist/reactive-BDya-ia8.js +253 -0
- package/dist/reactive-BDya-ia8.js.map +1 -0
- package/dist/reactive.es.mjs +18 -34
- package/dist/router-CijiICxt.js +188 -0
- package/dist/router-CijiICxt.js.map +1 -0
- package/dist/router.es.mjs +11 -200
- package/dist/sanitize-jyJ2ryE2.js +302 -0
- package/dist/sanitize-jyJ2ryE2.js.map +1 -0
- package/dist/security/constants.d.ts.map +1 -1
- package/dist/security.es.mjs +10 -56
- package/dist/store-CPK9E62U.js +262 -0
- package/dist/store-CPK9E62U.js.map +1 -0
- package/dist/store.es.mjs +12 -25
- package/dist/view-Cdi0g-qo.js +396 -0
- package/dist/view-Cdi0g-qo.js.map +1 -0
- package/dist/view.es.mjs +10 -430
- package/package.json +15 -11
- package/src/component/component.ts +319 -289
- package/src/component/index.ts +42 -40
- package/src/component/library.ts +504 -0
- package/src/component/types.ts +91 -85
- package/src/core/collection.ts +628 -628
- package/src/core/element.ts +774 -774
- package/src/core/index.ts +48 -48
- package/src/core/utils/function.ts +151 -151
- package/src/full.ts +223 -187
- package/src/motion/animate.ts +113 -113
- package/src/motion/flip.ts +176 -176
- package/src/motion/scroll.ts +57 -57
- package/src/motion/spring.ts +150 -150
- package/src/motion/timeline.ts +246 -246
- package/src/motion/transition.ts +53 -7
- package/src/motion/types.ts +208 -198
- package/src/platform/announcer.ts +208 -0
- package/src/platform/config.ts +163 -0
- package/src/platform/cookies.ts +165 -0
- package/src/platform/index.ts +39 -18
- package/src/platform/meta.ts +168 -0
- package/src/platform/storage.ts +215 -215
- package/src/reactive/async-data.ts +486 -0
- package/src/reactive/core.ts +114 -114
- package/src/reactive/effect.ts +54 -54
- package/src/reactive/index.ts +37 -23
- package/src/reactive/internals.ts +122 -122
- package/src/reactive/signal.ts +29 -20
- package/src/security/constants.ts +211 -209
- package/src/security/sanitize-core.ts +364 -364
- package/src/view/evaluate.ts +290 -290
- package/dist/batch-x7b2eZST.js +0 -13
- package/dist/batch-x7b2eZST.js.map +0 -1
- package/dist/component.es.mjs.map +0 -1
- package/dist/core-BhpuvPhy.js +0 -170
- package/dist/core-BhpuvPhy.js.map +0 -1
- package/dist/core.es.mjs.map +0 -1
- package/dist/full.es.mjs.map +0 -1
- package/dist/index.es.mjs.map +0 -1
- package/dist/motion.es.mjs.map +0 -1
- package/dist/persisted-DHoi3uEs.js +0 -278
- package/dist/persisted-DHoi3uEs.js.map +0 -1
- package/dist/platform.es.mjs.map +0 -1
- package/dist/reactive.es.mjs.map +0 -1
- package/dist/router.es.mjs.map +0 -1
- package/dist/sanitize-Cxvxa-DX.js +0 -283
- package/dist/sanitize-Cxvxa-DX.js.map +0 -1
- package/dist/security.es.mjs.map +0 -1
- package/dist/store.es.mjs.map +0 -1
- package/dist/type-guards-BdKlYYlS.js +0 -32
- package/dist/type-guards-BdKlYYlS.js.map +0 -1
- package/dist/untrack-DNnnqdlR.js +0 -6
- package/dist/untrack-DNnnqdlR.js.map +0 -1
- package/dist/view.es.mjs.map +0 -1
- package/dist/watch-DXXv3iAI.js +0 -58
- package/dist/watch-DXXv3iAI.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactive-BDya-ia8.js","names":[],"sources":["../src/reactive/batch.ts","../src/reactive/computed.ts","../src/reactive/untrack.ts","../src/reactive/async-data.ts","../src/reactive/linked.ts","../src/reactive/persisted.ts","../src/reactive/readonly.ts","../src/reactive/type-guards.ts","../src/reactive/watch.ts"],"sourcesContent":["/**\n * Batched reactive updates.\n */\n\nimport { beginBatch, endBatch } from './internals';\n\n/**\n * Batches multiple signal updates into a single notification cycle.\n *\n * Updates made inside the batch function are deferred until the batch\n * completes, preventing intermediate re-renders and improving performance.\n *\n * @param fn - Function containing multiple signal updates\n */\nexport const batch = (fn: () => void): void => {\n beginBatch();\n try {\n fn();\n } finally {\n endBatch();\n }\n};\n","/**\n * Computed reactive values.\n */\n\nimport {\n clearDependencies,\n getCurrentObserver,\n registerDependency,\n scheduleObserver,\n track,\n type ReactiveSource,\n} from './internals';\n\n/**\n * A computed value that derives from other reactive sources.\n *\n * Computed values are lazily evaluated and cached. They only\n * recompute when their dependencies change.\n *\n * @template T - The type of the computed value\n */\nexport class Computed<T> implements ReactiveSource {\n private cachedValue!: T;\n private dirty = true;\n private subscribers = new Set<() => void>();\n private readonly markDirty = () => {\n this.dirty = true;\n // Create snapshot to avoid issues with subscribers modifying the set during iteration\n const subscribersSnapshot = Array.from(this.subscribers);\n for (const subscriber of subscribersSnapshot) {\n scheduleObserver(subscriber);\n }\n };\n\n /**\n * Creates a new computed value.\n * @param compute - Function that computes the value\n */\n constructor(private readonly compute: () => T) {}\n\n /**\n * Gets the computed value, recomputing if dependencies changed.\n * During untrack calls, getCurrentObserver returns undefined, preventing dependency tracking.\n */\n get value(): T {\n const current = getCurrentObserver();\n if (current) {\n this.subscribers.add(current);\n registerDependency(current, this);\n }\n if (this.dirty) {\n this.dirty = false;\n // Clear old dependencies before recomputing\n clearDependencies(this.markDirty);\n this.cachedValue = track(this.markDirty, this.compute);\n }\n return this.cachedValue;\n }\n\n /**\n * Reads the current computed value without tracking.\n * Useful when you need the value but don't want to create a dependency.\n *\n * @returns The current cached value (recomputes if dirty)\n */\n peek(): T {\n if (this.dirty) {\n this.dirty = false;\n // Clear old dependencies before recomputing\n clearDependencies(this.markDirty);\n this.cachedValue = track(this.markDirty, this.compute);\n }\n return this.cachedValue;\n }\n\n /**\n * Removes an observer from this computed's subscriber set.\n * @internal\n */\n unsubscribe(observer: () => void): void {\n this.subscribers.delete(observer);\n }\n}\n\n/**\n * Creates a new computed value.\n *\n * @template T - The type of the computed value\n * @param fn - Function that computes the value from reactive sources\n * @returns A new Computed instance\n */\nexport const computed = <T>(fn: () => T): Computed<T> => new Computed(fn);\n","/**\n * Dependency tracking control helpers.\n */\n\nimport { withoutCurrentObserver } from './internals';\n\n/**\n * Executes a function without tracking any signal dependencies.\n * Useful when reading a signal value without creating a reactive dependency.\n *\n * This implementation temporarily hides the current observer rather than\n * disabling tracking globally. This ensures that nested reactive internals\n * (e.g., computed recomputation triggered during untrack) can still properly\n * track their own dependencies.\n *\n * @template T - The return type of the function\n * @param fn - The function to execute without tracking\n * @returns The result of the function\n *\n * @example\n * ```ts\n * const count = signal(0);\n * effect(() => {\n * // This read creates a dependency\n * console.log(count.value);\n * // This read does not create a dependency\n * const snapshot = untrack(() => count.value);\n * });\n * ```\n */\nexport const untrack = <T>(fn: () => T): T => withoutCurrentObserver(fn);\n","/**\r\n * Async data and fetch composables built on bQuery signals.\r\n *\r\n * @module bquery/reactive\r\n */\r\n\r\nimport { merge } from '../core/utils/object';\r\nimport { getBqueryConfig, type BqueryFetchParseAs } from '../platform/config';\r\nimport { computed } from './computed';\r\nimport { effect } from './effect';\r\nimport { Signal, signal } from './core';\r\nimport { untrack } from './untrack';\r\n\r\n/** Allowed status values for async composables. */\r\nexport type AsyncDataStatus = 'idle' | 'pending' | 'success' | 'error';\r\n\r\n/** Reactive source types that can trigger refreshes. */\r\nexport type AsyncWatchSource = (() => unknown) | { value: unknown };\r\n\r\n/** Options shared by async composables. */\r\nexport interface UseAsyncDataOptions<TResult, TData = TResult> {\r\n /** Run the handler immediately (default: true). */\r\n immediate?: boolean;\r\n /** Default data value before the first successful execution. */\r\n defaultValue?: TData;\r\n /** Optional reactive sources that trigger refreshes when they change. */\r\n watch?: AsyncWatchSource[];\r\n /** Transform the resolved value before storing it. */\r\n transform?: (value: TResult) => TData;\r\n /** Called after a successful execution. */\r\n onSuccess?: (value: TData) => void;\r\n /** Called after a failed execution. */\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/** Return value of useAsyncData() and useFetch(). */\r\nexport interface AsyncDataState<TData> {\r\n /** Reactive data signal. */\r\n data: Signal<TData | undefined>;\r\n /** Last error encountered by the composable. */\r\n error: Signal<Error | null>;\r\n /** Current lifecycle status. */\r\n status: Signal<AsyncDataStatus>;\r\n /** Computed boolean that mirrors `status === 'pending'`. */\r\n pending: { readonly value: boolean; peek(): boolean };\r\n /** Execute the handler manually. Returns the cached data value when called after dispose(). */\r\n execute: () => Promise<TData | undefined>;\r\n /** Alias for execute(). */\r\n refresh: () => Promise<TData | undefined>;\r\n /** Clear data, error, and status back to the initial state. */\r\n clear: () => void;\r\n /** Dispose reactive watchers and prevent future executions. */\r\n dispose: () => void;\r\n}\r\n\r\n/** Options for useFetch(). */\r\nexport interface UseFetchOptions<TResponse = unknown, TData = TResponse>\r\n extends UseAsyncDataOptions<TResponse, TData>, Omit<RequestInit, 'body' | 'headers'> {\r\n /** Base URL prepended to relative URLs. */\r\n baseUrl?: string;\r\n /** Query parameters appended to the request URL. */\r\n query?: Record<string, unknown>;\r\n /** Request headers. */\r\n headers?: HeadersInit;\r\n /** Request body, including plain objects for JSON requests. */\r\n body?: BodyInit | Record<string, unknown> | unknown[] | null;\r\n /** Override the parser used for the response body. */\r\n parseAs?: BqueryFetchParseAs;\r\n /** Custom fetch implementation for testing or adapters. */\r\n fetcher?: typeof fetch;\r\n}\r\n\r\n/** Input accepted by useFetch(). */\r\nexport type FetchInput = string | URL | Request | (() => string | URL | Request);\r\n\r\nconst normalizeError = (error: unknown): Error => {\r\n if (error instanceof Error) return error;\r\n if (typeof error === 'string') {\r\n return new Error(error);\r\n }\r\n\r\n try {\r\n return new Error(JSON.stringify(error));\r\n } catch {\r\n return new Error(String(error));\r\n }\r\n};\r\n\r\nconst readWatchSource = (source: AsyncWatchSource): unknown => {\r\n if (typeof source === 'function') {\r\n return source();\r\n }\r\n return source.value;\r\n};\r\n\r\nconst toHeaders = (...sources: Array<HeadersInit | undefined>): Headers => {\r\n const headers = new Headers();\r\n for (const source of sources) {\r\n if (!source) continue;\r\n new Headers(source).forEach((value, key) => {\r\n headers.set(key, value);\r\n });\r\n }\r\n return headers;\r\n};\r\n\r\nconst isBodyLike = (value: unknown): value is BodyInit => {\r\n if (typeof value === 'string') return true;\r\n if (value instanceof Blob || value instanceof FormData || value instanceof URLSearchParams) {\r\n return true;\r\n }\r\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) return true;\r\n if (typeof ReadableStream !== 'undefined' && value instanceof ReadableStream) return true;\r\n return typeof value === 'object' && value !== null && ArrayBuffer.isView(value);\r\n};\r\n\r\nconst serializeBody = (\r\n body: UseFetchOptions['body'],\r\n headers: Headers\r\n): BodyInit | null | undefined => {\r\n if (body == null) return body;\r\n if (isBodyLike(body)) return body;\r\n\r\n if (!headers.has('content-type')) {\r\n headers.set('content-type', 'application/json');\r\n }\r\n\r\n return JSON.stringify(body);\r\n};\r\n\r\nconst resolveInput = (input: FetchInput): string | URL | Request => {\r\n return typeof input === 'function' ? input() : input;\r\n};\r\n\r\nconst appendQuery = (url: URL, query: Record<string, unknown>): void => {\r\n for (const [key, value] of Object.entries(query)) {\r\n if (value == null) continue;\r\n\r\n if (Array.isArray(value)) {\r\n for (const item of value) {\r\n if (item != null) {\r\n url.searchParams.append(key, String(item));\r\n }\r\n }\r\n continue;\r\n }\r\n\r\n url.searchParams.set(key, String(value));\r\n }\r\n};\r\n\r\nconst toUrl = (input: string | URL, baseUrl?: string): URL => {\r\n const runtimeBase =\r\n typeof window !== 'undefined' && /^https?:/i.test(window.location.href)\r\n ? window.location.href\r\n : 'http://localhost';\r\n const base = baseUrl ? new URL(baseUrl, runtimeBase).toString() : runtimeBase;\r\n return input instanceof URL ? new URL(input.toString(), base) : new URL(input, base);\r\n};\r\n\r\nconst parseResponse = async <TResponse>(\r\n response: Response,\r\n parseAs: BqueryFetchParseAs\r\n): Promise<TResponse> => {\r\n if (parseAs === 'response') return response as TResponse;\r\n if (parseAs === 'text') return (await response.text()) as TResponse;\r\n if (parseAs === 'blob') return (await response.blob()) as TResponse;\r\n if (parseAs === 'arrayBuffer') return (await response.arrayBuffer()) as TResponse;\r\n if (parseAs === 'formData') return (await response.formData()) as TResponse;\r\n\r\n const text = await response.text();\r\n if (!text) {\r\n return undefined as TResponse;\r\n }\r\n\r\n try {\r\n return JSON.parse(text) as TResponse;\r\n } catch (error) {\r\n const detail = response.url ? ` for ${response.url}` : '';\r\n throw new Error(\r\n `Failed to parse JSON response${detail} (status ${response.status}): ${error instanceof Error ? error.message : String(error)}`\r\n );\r\n }\r\n};\r\n\r\nconst normalizeMethod = (method?: string): string | undefined => {\r\n const normalized = method?.trim();\r\n return normalized ? normalized.toUpperCase() : undefined;\r\n};\r\n\r\nconst resolveMethod = (\r\n explicitMethod: string | undefined,\r\n requestInput: string | URL | Request,\r\n bodyProvided: boolean\r\n): string | undefined => {\r\n const requestMethod =\r\n requestInput instanceof Request ? normalizeMethod(requestInput.method) : undefined;\r\n return explicitMethod ?? requestMethod ?? (bodyProvided ? 'POST' : undefined);\r\n};\r\n\r\nconst resolveRequestInitMethod = (\r\n explicitMethod: string | undefined,\r\n requestInput: string | URL | Request,\r\n method: string | undefined\r\n): string | undefined => {\r\n if (explicitMethod) return explicitMethod;\r\n return requestInput instanceof Request ? undefined : method;\r\n};\r\n\r\nconst toRequestInit = (request: Request): RequestInit => {\r\n const requestMethod = normalizeMethod(request.method);\r\n let body: BodyInit | undefined;\r\n if (requestMethod !== 'GET' && requestMethod !== 'HEAD' && !request.bodyUsed) {\r\n try {\r\n body = request.clone().body ?? undefined;\r\n } catch {\r\n body = undefined;\r\n }\r\n }\r\n\r\n return {\r\n method: requestMethod,\r\n headers: request.headers,\r\n body,\r\n cache: request.cache,\r\n credentials: request.credentials,\r\n integrity: request.integrity,\r\n keepalive: request.keepalive,\r\n mode: request.mode,\r\n redirect: request.redirect,\r\n referrer: request.referrer,\r\n referrerPolicy: request.referrerPolicy,\r\n signal: request.signal,\r\n };\r\n};\r\n\r\n/**\r\n * Create a reactive wrapper around an async resolver.\r\n *\r\n * @template TResult - Raw result type returned by the handler\r\n * @template TData - Stored data type after optional transformation\r\n * @param handler - Async function to execute\r\n * @param options - Execution, transform, and refresh options\r\n * @returns Reactive data state with execute(), refresh(), and clear()\r\n *\r\n * @example\r\n * ```ts\r\n * const user = useAsyncData(() => fetch('/api/user').then((res) => res.json()));\r\n * ```\r\n */\r\nexport const useAsyncData = <TResult, TData = TResult>(\r\n handler: () => Promise<TResult>,\r\n options: UseAsyncDataOptions<TResult, TData> = {}\r\n): AsyncDataState<TData> => {\r\n const immediate = options.immediate ?? true;\r\n const data = signal<TData | undefined>(options.defaultValue);\r\n const error = signal<Error | null>(null);\r\n const status = signal<AsyncDataStatus>('idle');\r\n const pending = computed(() => status.value === 'pending');\r\n let executionId = 0;\r\n let disposed = false;\r\n let stopWatching = (): void => {};\r\n\r\n const clear = (): void => {\r\n executionId += 1;\r\n data.value = options.defaultValue;\r\n error.value = null;\r\n status.value = 'idle';\r\n };\r\n\r\n const dispose = (): void => {\r\n if (disposed) return;\r\n disposed = true;\r\n executionId += 1;\r\n stopWatching();\r\n };\r\n\r\n const execute = async (): Promise<TData | undefined> => {\r\n if (disposed) {\r\n return data.peek();\r\n }\r\n\r\n const currentExecution = ++executionId;\r\n status.value = 'pending';\r\n error.value = null;\r\n\r\n try {\r\n const resolved = await handler();\r\n const transformed = options.transform\r\n ? options.transform(resolved)\r\n : (resolved as unknown as TData);\r\n\r\n if (disposed || currentExecution !== executionId) {\r\n return data.peek();\r\n }\r\n\r\n data.value = transformed;\r\n status.value = 'success';\r\n options.onSuccess?.(transformed);\r\n return transformed;\r\n } catch (caught) {\r\n const normalizedError = normalizeError(caught);\r\n\r\n if (disposed || currentExecution !== executionId) {\r\n return data.peek();\r\n }\r\n\r\n error.value = normalizedError;\r\n status.value = 'error';\r\n options.onError?.(normalizedError);\r\n return data.peek();\r\n }\r\n };\r\n\r\n if (options.watch?.length) {\r\n let initialized = false;\r\n stopWatching = effect(() => {\r\n for (const source of options.watch ?? []) {\r\n readWatchSource(source);\r\n }\r\n\r\n if (!initialized) {\r\n initialized = true;\r\n if (immediate) {\r\n void untrack(() => execute());\r\n }\r\n return;\r\n }\r\n\r\n void untrack(() => execute());\r\n });\r\n } else if (immediate) {\r\n void execute();\r\n }\r\n\r\n return {\r\n data,\r\n error,\r\n status,\r\n pending,\r\n execute,\r\n refresh: execute,\r\n clear,\r\n dispose,\r\n };\r\n};\r\n\r\n/**\r\n * Reactive fetch composable using the browser Fetch API.\r\n *\r\n * @template TResponse - Raw parsed response type\r\n * @template TData - Stored response type after optional transformation\r\n * @param input - Request URL, Request object, or lazy input factory\r\n * @param options - Request and reactive state options\r\n * @returns Reactive fetch state with execute(), refresh(), and clear()\r\n *\r\n * @example\r\n * ```ts\r\n * const users = useFetch<{ id: number; name: string }[]>('/api/users');\r\n * ```\r\n */\r\nexport const useFetch = <TResponse = unknown, TData = TResponse>(\r\n input: FetchInput,\r\n options: UseFetchOptions<TResponse, TData> = {}\r\n): AsyncDataState<TData> => {\r\n const fetchConfig = getBqueryConfig().fetch;\r\n const parseAs = options.parseAs ?? fetchConfig?.parseAs ?? 'json';\r\n const fetcher = options.fetcher ?? fetch;\r\n\r\n return useAsyncData<TResponse, TData>(async () => {\r\n const requestInput = resolveInput(input);\r\n const requestUrl =\r\n typeof requestInput === 'string' || requestInput instanceof URL\r\n ? toUrl(requestInput, options.baseUrl ?? fetchConfig?.baseUrl)\r\n : requestInput instanceof Request && options.query\r\n ? new URL(requestInput.url)\r\n : null;\r\n\r\n if (requestUrl && options.query) {\r\n appendQuery(requestUrl, options.query);\r\n }\r\n\r\n const headers = toHeaders(\r\n fetchConfig?.headers,\r\n requestInput instanceof Request ? requestInput.headers : undefined,\r\n options.headers\r\n );\r\n const bodyProvided = options.body != null;\r\n const explicitMethod = normalizeMethod(options.method);\r\n const method = resolveMethod(explicitMethod, requestInput, bodyProvided);\r\n const bodylessMethod = method === 'GET' || method === 'HEAD' ? method : null;\r\n if (bodyProvided && bodylessMethod) {\r\n throw new Error(`Cannot send a request body with ${bodylessMethod} requests`);\r\n }\r\n const requestInitMethod = resolveRequestInitMethod(explicitMethod, requestInput, method);\r\n const requestInit: RequestInit = {\r\n ...options,\r\n method: requestInitMethod,\r\n headers,\r\n body: serializeBody(options.body, headers),\r\n };\r\n\r\n delete (requestInit as Partial<UseFetchOptions>).baseUrl;\r\n delete (requestInit as Partial<UseFetchOptions>).query;\r\n delete (requestInit as Partial<UseFetchOptions>).parseAs;\r\n delete (requestInit as Partial<UseFetchOptions>).fetcher;\r\n delete (requestInit as Partial<UseFetchOptions>).defaultValue;\r\n delete (requestInit as Partial<UseFetchOptions>).immediate;\r\n delete (requestInit as Partial<UseFetchOptions>).watch;\r\n delete (requestInit as Partial<UseFetchOptions>).transform;\r\n delete (requestInit as Partial<UseFetchOptions>).onSuccess;\r\n delete (requestInit as Partial<UseFetchOptions>).onError;\r\n\r\n let requestTarget: Request | string | URL = requestUrl ?? requestInput;\r\n if (\r\n requestInput instanceof Request &&\r\n requestUrl &&\r\n requestUrl.toString() !== requestInput.url\r\n ) {\r\n // Rebuild Request inputs when query params changed so the updated URL is preserved.\r\n // String/URL inputs already use `requestUrl` directly, so only Request objects need rebuilding.\r\n requestTarget = new Request(requestUrl.toString(), toRequestInit(requestInput));\r\n }\r\n const response = await fetcher(requestTarget, requestInit);\r\n\r\n if (!response.ok) {\r\n throw Object.assign(new Error(`Request failed with status ${response.status}`), {\r\n response,\r\n status: response.status,\r\n statusText: response.statusText,\r\n });\r\n }\r\n\r\n return parseResponse<TResponse>(response, parseAs);\r\n }, options);\r\n};\r\n\r\n/**\r\n * Create a preconfigured useFetch() helper.\r\n *\r\n * @param defaults - Default request options merged into every useFetch() call\r\n * @returns A useFetch-compatible function with merged defaults\r\n *\r\n * @example\r\n * ```ts\r\n * const useApiFetch = createUseFetch({ baseUrl: 'https://api.example.com' });\r\n * const profile = useApiFetch('/profile');\r\n * ```\r\n */\r\n/** Overload for factories without a configured transform, preserving per-call `TResponse -> TData` inference. */\r\nexport function createUseFetch<TDefaultResponse = unknown>(\r\n defaults?: UseFetchOptions<TDefaultResponse, TDefaultResponse>\r\n): <TResponse = TDefaultResponse, TData = TResponse>(\r\n input: FetchInput,\r\n options?: UseFetchOptions<TResponse, TData>\r\n) => AsyncDataState<TData>;\r\n\r\n/** Overload for factories with a configured transform, preserving the transformed factory data type by default. */\r\nexport function createUseFetch<TDefaultResponse = unknown, TDefaultData = TDefaultResponse>(\r\n defaults: UseFetchOptions<TDefaultResponse, TDefaultData>\r\n): <TResponse = TDefaultResponse, TData = TDefaultData>(\r\n input: FetchInput,\r\n options?: UseFetchOptions<TResponse, TData>\r\n) => AsyncDataState<TData>;\r\n\r\nexport function createUseFetch<TDefaultResponse = unknown, TDefaultData = TDefaultResponse>(\r\n defaults: UseFetchOptions<TDefaultResponse, TDefaultData> = {}\r\n) {\r\n return <TResponse = TDefaultResponse, TData = TDefaultData>(\r\n input: FetchInput,\r\n options: UseFetchOptions<TResponse, TData> = {}\r\n ): AsyncDataState<TData> => {\r\n const resolvedDefaults = defaults as unknown as UseFetchOptions<TResponse, TData>;\r\n const mergedQuery = merge({}, resolvedDefaults.query ?? {}, options.query ?? {}) as Record<\r\n string,\r\n unknown\r\n >;\r\n\r\n return useFetch<TResponse, TData>(input, {\r\n ...resolvedDefaults,\r\n ...options,\r\n headers: toHeaders(resolvedDefaults.headers, options.headers),\r\n query: Object.keys(mergedQuery).length > 0 ? mergedQuery : undefined,\r\n });\r\n };\r\n}\r\n","/**\n * Linked (writable) computed helpers.\n */\n\nimport { computed, Computed } from './computed';\n\n/**\n * A writable computed-like signal.\n */\nexport interface LinkedSignal<T> {\n /** Gets or sets the current value with dependency tracking. */\n value: T;\n /** Gets the current value without dependency tracking. */\n peek(): T;\n}\n\n/**\n * Creates a writable computed signal by linking a getter and setter.\n *\n * @template T - The derived value type\n * @param getValue - Getter that derives the current value\n * @param setValue - Setter that writes back to underlying signals\n * @returns A writable computed-like signal\n *\n * @example\n * ```ts\n * const first = signal('Ada');\n * const last = signal('Lovelace');\n * const fullName = linkedSignal(\n * () => `${first.value} ${last.value}`,\n * (next) => {\n * const [a, b] = next.split(' ');\n * first.value = a ?? '';\n * last.value = b ?? '';\n * }\n * );\n * ```\n */\nexport const linkedSignal = <T>(\n getValue: () => T,\n setValue: (value: T) => void\n): LinkedSignal<T> => {\n const derived: Computed<T> = computed(getValue);\n\n return {\n get value(): T {\n return derived.value;\n },\n set value(next: T) {\n setValue(next);\n },\n peek(): T {\n return derived.peek();\n },\n };\n};\n","/**\n * LocalStorage-backed signals.\n */\n\nimport { signal, Signal } from './core';\nimport { effect } from './effect';\n\n/**\n * Creates a signal that persists to localStorage.\n *\n * @template T - The type of the signal value\n * @param key - The localStorage key\n * @param initialValue - The initial value if not found in storage\n * @returns A Signal that syncs with localStorage (falls back to in-memory if unavailable)\n */\nexport const persistedSignal = <T>(key: string, initialValue: T): Signal<T> => {\n // Check if localStorage is available and accessible\n let hasLocalStorage = false;\n let storage: Storage | null = null;\n\n try {\n // In Safari private mode, accessing localStorage can throw SecurityError\n storage = globalThis.localStorage;\n if (storage) {\n // Test actual access to ensure it's not just present but usable\n // Use a randomized test key to avoid overwriting real user data\n const testKey = `__bquery_test_${Math.random().toString(36).slice(2, 9)}__`;\n const testValue = '__test__';\n try {\n storage.setItem(testKey, testValue);\n storage.getItem(testKey);\n hasLocalStorage = true;\n } finally {\n // Ensure we don't leave any test data behind\n try {\n storage.removeItem(testKey);\n } catch {\n // Ignore cleanup errors (e.g., storage becoming unavailable)\n }\n }\n }\n } catch {\n // localStorage unavailable or access denied (Safari private mode, sandboxed iframes, etc.)\n hasLocalStorage = false;\n }\n\n let stored: T = initialValue;\n\n if (hasLocalStorage && storage) {\n try {\n const raw = storage.getItem(key);\n if (raw !== null) {\n stored = JSON.parse(raw) as T;\n }\n } catch {\n // Use initial value on parse error or access denial\n }\n }\n\n const sig = signal(stored);\n\n // Only set up persistence effect if localStorage is available\n if (hasLocalStorage && storage) {\n effect(() => {\n try {\n storage!.setItem(key, JSON.stringify(sig.value));\n } catch {\n // Ignore storage errors (quota exceeded, sandboxed iframes, etc.)\n }\n });\n }\n\n return sig;\n};\n","/**\n * Read-only signal wrappers.\n */\n\nimport type { Signal } from './core';\n\n/**\n * A readonly wrapper around a signal that prevents writes.\n * Provides read-only access to a signal's value while maintaining reactivity.\n *\n * @template T - The type of the wrapped value\n */\nexport interface ReadonlySignal<T> {\n /** Gets the current value with dependency tracking. */\n readonly value: T;\n /** Gets the current value without dependency tracking. */\n peek(): T;\n}\n\n/**\n * Creates a read-only view of a signal.\n * Useful for exposing reactive state without allowing modifications.\n *\n * @template T - The type of the signal value\n * @param sig - The signal to wrap\n * @returns A readonly signal wrapper\n */\nexport const readonly = <T>(sig: Signal<T>): ReadonlySignal<T> => ({\n get value(): T {\n return sig.value;\n },\n peek(): T {\n return sig.peek();\n },\n});\n","/**\n * Type guards for reactive primitives.\n */\n\nimport { Computed } from './computed';\nimport { Signal } from './core';\n\n/**\n * Type guard to check if a value is a Signal instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Signal\n */\nexport const isSignal = (value: unknown): value is Signal<unknown> => value instanceof Signal;\n\n/**\n * Type guard to check if a value is a Computed instance.\n *\n * @param value - The value to check\n * @returns True if the value is a Computed\n */\nexport const isComputed = (value: unknown): value is Computed<unknown> => value instanceof Computed;\n","/**\n * Value watching helpers.\n */\n\nimport type { Computed } from './computed';\nimport type { Signal } from './core';\nimport type { CleanupFn } from './internals';\n\nimport { effect } from './effect';\n\n/**\n * Options for the watch function.\n */\nexport interface WatchOptions<T> {\n /** If true, the callback is invoked immediately with the current value. */\n immediate?: boolean;\n /** Custom equality function. Defaults to Object.is. */\n equals?: (a: T, b: T | undefined) => boolean;\n}\n\n/**\n * Watches a signal or computed value and calls a callback with old and new values.\n * Unlike effect, watch provides access to the previous value.\n * The callback is only invoked when the value actually changes (compared via Object.is or custom equals).\n *\n * @template T - The type of the watched value\n * @param source - The signal or computed to watch\n * @param callback - Function called with (newValue, oldValue) on changes\n * @param options - Watch options\n * @returns A cleanup function to stop watching\n *\n * @example\n * ```ts\n * const count = signal(0);\n * watch(count, (newVal, oldVal) => {\n * console.log(`Changed from ${oldVal} to ${newVal}`);\n * });\n *\n * // With custom equality for objects\n * const user = signal({ id: 1, name: 'Alice' });\n * watch(user, (newVal, oldVal) => { ... }, {\n * equals: (a, b) => a?.id === b?.id\n * });\n * ```\n */\nexport const watch = <T>(\n source: Signal<T> | Computed<T>,\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions<T> = {}\n): CleanupFn => {\n const { immediate = false, equals = Object.is } = options;\n let oldValue: T | undefined;\n let isFirst = true;\n\n return effect(() => {\n const newValue = source.value;\n\n if (isFirst) {\n isFirst = false;\n oldValue = newValue;\n if (immediate) {\n callback(newValue, undefined);\n }\n return;\n }\n\n // Only call callback if value actually changed\n if (!equals(newValue, oldValue)) {\n callback(newValue, oldValue);\n oldValue = newValue;\n }\n });\n};\n"],"mappings":"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"}
|
package/dist/reactive.es.mjs
CHANGED
|
@@ -1,36 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { b as d } from "./batch-x7b2eZST.js";
|
|
4
|
-
import { e as g, i as x, a as S } from "./type-guards-BdKlYYlS.js";
|
|
5
|
-
import { p as v, r as C, w as b } from "./watch-DXXv3iAI.js";
|
|
6
|
-
import { u as w } from "./untrack-DNnnqdlR.js";
|
|
7
|
-
const p = (a, r) => {
|
|
8
|
-
const e = s(a);
|
|
9
|
-
return {
|
|
10
|
-
get value() {
|
|
11
|
-
return e.value;
|
|
12
|
-
},
|
|
13
|
-
set value(t) {
|
|
14
|
-
r(t);
|
|
15
|
-
},
|
|
16
|
-
peek() {
|
|
17
|
-
return e.peek();
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
};
|
|
1
|
+
import { n as s, r as e, t } from "./core-DPdbItcq.js";
|
|
2
|
+
import { a as n, c as r, d as c, f as o, i as l, l as p, n as d, o as m, p as u, r as f, s as g, t as h, u as S } from "./reactive-BDya-ia8.js";
|
|
21
3
|
export {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
g as
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
4
|
+
c as Computed,
|
|
5
|
+
t as Signal,
|
|
6
|
+
u as batch,
|
|
7
|
+
o as computed,
|
|
8
|
+
g as createUseFetch,
|
|
9
|
+
e as effect,
|
|
10
|
+
d as isComputed,
|
|
11
|
+
f as isSignal,
|
|
12
|
+
m as linkedSignal,
|
|
13
|
+
n as persistedSignal,
|
|
14
|
+
l as readonly,
|
|
15
|
+
s as signal,
|
|
16
|
+
S as untrack,
|
|
17
|
+
r as useAsyncData,
|
|
18
|
+
p as useFetch,
|
|
19
|
+
h as watch
|
|
35
20
|
};
|
|
36
|
-
//# sourceMappingURL=reactive.es.mjs.map
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { n as D } from "./core-DPdbItcq.js";
|
|
2
|
+
import { f as W } from "./reactive-BDya-ia8.js";
|
|
3
|
+
var N = null, d = D({
|
|
4
|
+
path: "",
|
|
5
|
+
params: {},
|
|
6
|
+
query: {},
|
|
7
|
+
matched: null,
|
|
8
|
+
hash: ""
|
|
9
|
+
}), K = W(() => d.value), g = () => N, k = (e) => {
|
|
10
|
+
N = e;
|
|
11
|
+
}, b = async (e, n = {}) => {
|
|
12
|
+
const a = g();
|
|
13
|
+
if (!a) throw new Error("bQuery router: No router initialized. Call createRouter() first.");
|
|
14
|
+
await a[n.replace ? "replace" : "push"](e);
|
|
15
|
+
}, U = () => {
|
|
16
|
+
const e = g();
|
|
17
|
+
e ? e.back() : history.back();
|
|
18
|
+
}, Z = () => {
|
|
19
|
+
const e = g();
|
|
20
|
+
e ? e.forward() : history.forward();
|
|
21
|
+
}, T = (e, n = {}) => (a) => {
|
|
22
|
+
a.preventDefault(), b(e, n).catch((t) => {
|
|
23
|
+
console.error("Navigation failed:", t);
|
|
24
|
+
});
|
|
25
|
+
}, j = (e) => {
|
|
26
|
+
const n = e ?? (typeof document < "u" ? document.body : null);
|
|
27
|
+
if (!n) return () => {
|
|
28
|
+
};
|
|
29
|
+
const a = (t) => {
|
|
30
|
+
if (!(t instanceof MouseEvent) || t.defaultPrevented || t.button !== 0 || t.ctrlKey || t.metaKey || t.shiftKey || t.altKey || typeof Element > "u" || !(t.target instanceof Element)) return;
|
|
31
|
+
const r = t.target.closest("a");
|
|
32
|
+
if (!r || !(r instanceof (r.ownerDocument.defaultView?.HTMLAnchorElement ?? HTMLAnchorElement)) || r.target || r.hasAttribute("download") || typeof window > "u" || r.origin !== window.location.origin) return;
|
|
33
|
+
const s = g();
|
|
34
|
+
if (!s) {
|
|
35
|
+
t.preventDefault(), b(r.pathname + r.search + r.hash).catch((h) => {
|
|
36
|
+
console.error("Navigation failed:", h);
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const c = s.base, l = s.hash;
|
|
41
|
+
let f;
|
|
42
|
+
if (l && r.hash && r.hash.startsWith("#/")) f = r.hash.slice(1);
|
|
43
|
+
else {
|
|
44
|
+
let h = r.pathname;
|
|
45
|
+
c && c !== "/" && h.startsWith(c) && (h = h.slice(c.length) || "/"), f = h + r.search + r.hash;
|
|
46
|
+
}
|
|
47
|
+
t.preventDefault(), b(f).catch((h) => {
|
|
48
|
+
console.error("Navigation failed:", h);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
return n.addEventListener("click", a), () => n.removeEventListener("click", a);
|
|
52
|
+
}, _ = (e) => {
|
|
53
|
+
const n = {};
|
|
54
|
+
return new URLSearchParams(e).forEach((a, t) => {
|
|
55
|
+
const r = n[t];
|
|
56
|
+
r === void 0 ? n[t] = a : Array.isArray(r) ? r.push(a) : n[t] = [r, a];
|
|
57
|
+
}), n;
|
|
58
|
+
}, q = (e) => {
|
|
59
|
+
if (e === "*") return /^.*$/;
|
|
60
|
+
const n = "\0P\0", a = "\0W\0";
|
|
61
|
+
let t = e.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, () => n);
|
|
62
|
+
return t = t.replace(/\*/g, a), t = t.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&"), t = t.replace(/\u0000P\u0000/g, () => "([^/]+)"), t = t.replace(/\u0000W\u0000/g, ".*"), new RegExp(`^${t}$`);
|
|
63
|
+
}, C = (e) => {
|
|
64
|
+
const n = e.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);
|
|
65
|
+
return n ? n.map((a) => a.slice(1)) : [];
|
|
66
|
+
}, H = (e, n) => {
|
|
67
|
+
for (const a of n) {
|
|
68
|
+
const t = q(a.path), r = e.match(t);
|
|
69
|
+
if (r) {
|
|
70
|
+
const s = C(a.path), c = {};
|
|
71
|
+
return s.forEach((l, f) => {
|
|
72
|
+
c[l] = r[f + 1] || "";
|
|
73
|
+
}), {
|
|
74
|
+
matched: a,
|
|
75
|
+
params: c
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}, A = (e, n, a, t) => {
|
|
81
|
+
const r = H(e, t);
|
|
82
|
+
return {
|
|
83
|
+
path: e,
|
|
84
|
+
params: r?.params ?? {},
|
|
85
|
+
query: _(n),
|
|
86
|
+
matched: r?.matched ?? null,
|
|
87
|
+
hash: a.replace(/^#/, "")
|
|
88
|
+
};
|
|
89
|
+
}, M = (e, n = "") => {
|
|
90
|
+
const a = [];
|
|
91
|
+
for (const t of e) {
|
|
92
|
+
const r = t.path === "*" ? "*" : `${n}${t.path}`.replace(/\/+/g, "/");
|
|
93
|
+
a.push({
|
|
94
|
+
...t,
|
|
95
|
+
path: r
|
|
96
|
+
}), t.children && a.push(...M(t.children, r));
|
|
97
|
+
}
|
|
98
|
+
return a;
|
|
99
|
+
}, I = (e, n = {}) => {
|
|
100
|
+
const a = g();
|
|
101
|
+
if (!a) throw new Error("bQuery router: No router initialized.");
|
|
102
|
+
const t = a.routes.find((s) => s.name === e);
|
|
103
|
+
if (!t) throw new Error(`bQuery router: Route "${e}" not found.`);
|
|
104
|
+
let r = t.path;
|
|
105
|
+
for (const [s, c] of Object.entries(n)) r = r.replace(`:${s}`, encodeURIComponent(c));
|
|
106
|
+
return r;
|
|
107
|
+
}, G = (e, n = !1) => {
|
|
108
|
+
const a = d.value.path;
|
|
109
|
+
return n ? a === e : a.startsWith(e);
|
|
110
|
+
}, V = (e, n = !1) => W(() => {
|
|
111
|
+
const a = d.value.path;
|
|
112
|
+
return n ? a === e : a.startsWith(e);
|
|
113
|
+
}), B = (e) => {
|
|
114
|
+
const n = g();
|
|
115
|
+
n && n.destroy();
|
|
116
|
+
const { routes: a, base: t = "", hash: r = !1 } = e, s = [], c = [], l = M(a), f = () => {
|
|
117
|
+
if (r) {
|
|
118
|
+
const [i, p = ""] = (window.location.hash.slice(1) || "/").split("#"), [u, v = ""] = i.split("?");
|
|
119
|
+
return {
|
|
120
|
+
pathname: u,
|
|
121
|
+
search: v ? `?${v}` : "",
|
|
122
|
+
hash: p ? `#${p}` : ""
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
let o = window.location.pathname;
|
|
126
|
+
return t && (o === t || o.startsWith(t + "/")) && (o = o.slice(t.length) || "/"), {
|
|
127
|
+
pathname: o,
|
|
128
|
+
search: window.location.search,
|
|
129
|
+
hash: window.location.hash
|
|
130
|
+
};
|
|
131
|
+
}, h = () => {
|
|
132
|
+
const { pathname: o, search: i, hash: p } = f();
|
|
133
|
+
d.value = A(o, i, p, l);
|
|
134
|
+
}, P = async (o, i) => {
|
|
135
|
+
const { pathname: p, search: u, hash: v } = f(), m = A(p, u, v, l), w = new URL(o, window.location.origin), R = A(w.pathname, w.search, w.hash, l);
|
|
136
|
+
for (const y of s) if (await y(R, m) === !1) return;
|
|
137
|
+
const $ = r ? `#${o}` : `${t}${o}`;
|
|
138
|
+
history[i]({}, "", $), h();
|
|
139
|
+
for (const y of c) y(d.value, m);
|
|
140
|
+
}, x = async () => {
|
|
141
|
+
const { pathname: o, search: i, hash: p } = f(), u = d.value, v = A(o, i, p, l);
|
|
142
|
+
for (const m of s) if (await m(v, u) === !1) {
|
|
143
|
+
const w = new URLSearchParams(Object.entries(u.query).flatMap(([S, E]) => Array.isArray(E) ? E.map((z) => [S, z]) : [[S, E]])).toString(), R = w ? `?${w}` : "", $ = u.hash ? `#${u.hash}` : "", y = r ? `#${u.path}${R}${$}` : `${t}${u.path}${R}${$}`;
|
|
144
|
+
history.replaceState({}, "", y);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
h();
|
|
148
|
+
for (const m of c) m(d.value, u);
|
|
149
|
+
};
|
|
150
|
+
window.addEventListener("popstate", x), h();
|
|
151
|
+
const L = {
|
|
152
|
+
push: (o) => P(o, "pushState"),
|
|
153
|
+
replace: (o) => P(o, "replaceState"),
|
|
154
|
+
back: () => history.back(),
|
|
155
|
+
forward: () => history.forward(),
|
|
156
|
+
go: (o) => history.go(o),
|
|
157
|
+
beforeEach: (o) => (s.push(o), () => {
|
|
158
|
+
const i = s.indexOf(o);
|
|
159
|
+
i > -1 && s.splice(i, 1);
|
|
160
|
+
}),
|
|
161
|
+
afterEach: (o) => (c.push(o), () => {
|
|
162
|
+
const i = c.indexOf(o);
|
|
163
|
+
i > -1 && c.splice(i, 1);
|
|
164
|
+
}),
|
|
165
|
+
currentRoute: K,
|
|
166
|
+
routes: l,
|
|
167
|
+
base: t,
|
|
168
|
+
hash: r,
|
|
169
|
+
destroy: () => {
|
|
170
|
+
window.removeEventListener("popstate", x), s.length = 0, c.length = 0, k(null);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
return k(L), L;
|
|
174
|
+
};
|
|
175
|
+
export {
|
|
176
|
+
j as a,
|
|
177
|
+
Z as c,
|
|
178
|
+
I as i,
|
|
179
|
+
b as l,
|
|
180
|
+
G as n,
|
|
181
|
+
T as o,
|
|
182
|
+
V as r,
|
|
183
|
+
U as s,
|
|
184
|
+
B as t,
|
|
185
|
+
K as u
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
//# sourceMappingURL=router-CijiICxt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-CijiICxt.js","names":[],"sources":["../src/router/state.ts","../src/router/navigation.ts","../src/router/links.ts","../src/router/query.ts","../src/router/match.ts","../src/router/utils.ts","../src/router/router.ts"],"sourcesContent":["/**\n * Internal router state (active router and current route signal).\n * @module bquery/router\n */\n\nimport { computed, signal, type ReadonlySignal, type Signal } from '../reactive/index';\nimport type { Route, Router } from './types';\n\n// ============================================================================\n// Internal State\n// ============================================================================\n\n/** @internal */\nlet activeRouter: Router | null = null;\n\n/** @internal */\nexport const routeSignal: Signal<Route> = signal<Route>({\n path: '',\n params: {},\n query: {},\n matched: null,\n hash: '',\n});\n\n/**\n * Reactive signal containing the current route.\n *\n * @example\n * ```ts\n * import { currentRoute } from 'bquery/router';\n * import { effect } from 'bquery/reactive';\n *\n * effect(() => {\n * document.title = `Page: ${currentRoute.value.path}`;\n * });\n * ```\n */\nexport const currentRoute: ReadonlySignal<Route> = computed(() => routeSignal.value);\n\n/** @internal */\nexport const getActiveRouter = (): Router | null => activeRouter;\n\n/** @internal */\nexport const setActiveRouter = (router: Router | null): void => {\n activeRouter = router;\n};\n","/**\n * Navigation helpers and global router access.\n * @module bquery/router\n */\n\nimport { getActiveRouter } from './state';\n\n/**\n * Navigates to a new path.\n *\n * @param path - The path to navigate to\n * @param options - Navigation options\n *\n * @example\n * ```ts\n * import { navigate } from 'bquery/router';\n *\n * // Push to history\n * await navigate('/dashboard');\n *\n * // Replace current entry\n * await navigate('/login', { replace: true });\n * ```\n */\nexport const navigate = async (\n path: string,\n options: { replace?: boolean } = {}\n): Promise<void> => {\n const activeRouter = getActiveRouter();\n if (!activeRouter) {\n throw new Error('bQuery router: No router initialized. Call createRouter() first.');\n }\n\n await activeRouter[options.replace ? 'replace' : 'push'](path);\n};\n\n/**\n * Programmatically go back in history.\n *\n * @example\n * ```ts\n * import { back } from 'bquery/router';\n * back();\n * ```\n */\nexport const back = (): void => {\n const activeRouter = getActiveRouter();\n if (activeRouter) {\n activeRouter.back();\n } else {\n history.back();\n }\n};\n\n/**\n * Programmatically go forward in history.\n *\n * @example\n * ```ts\n * import { forward } from 'bquery/router';\n * forward();\n * ```\n */\nexport const forward = (): void => {\n const activeRouter = getActiveRouter();\n if (activeRouter) {\n activeRouter.forward();\n } else {\n history.forward();\n }\n};\n","/**\n * Link helpers for client-side navigation.\n * @module bquery/router\n */\n\nimport { getActiveRouter } from './state';\nimport { navigate } from './navigation';\n\n// ============================================================================\n// Router Link Helper\n// ============================================================================\n\n/**\n * Creates click handler for router links.\n * Attach to anchor elements to enable client-side navigation.\n *\n * @param path - Target path\n * @param options - Navigation options\n * @returns Click event handler\n *\n * @example\n * ```ts\n * import { link } from 'bquery/router';\n * import { $ } from 'bquery/core';\n *\n * $('#nav-home').on('click', link('/'));\n * $('#nav-about').on('click', link('/about'));\n * ```\n */\nexport const link = (path: string, options: { replace?: boolean } = {}): ((e: Event) => void) => {\n return (e: Event) => {\n e.preventDefault();\n void navigate(path, options).catch((err) => {\n console.error('Navigation failed:', err);\n });\n };\n};\n\n/**\n * Intercepts all link clicks within a container for client-side routing.\n * Only intercepts links with matching origins and no target attribute.\n *\n * @param container - The container element to intercept links in\n * @returns Cleanup function to remove the listener\n *\n * @example\n * ```ts\n * import { interceptLinks } from 'bquery/router';\n *\n * // Intercept all links in the app\n * const cleanup = interceptLinks(document.body);\n *\n * // Later, remove the interceptor\n * cleanup();\n * ```\n */\nexport const interceptLinks = (container?: Element): (() => void) => {\n // Provide safe default in DOM environments only\n const targetContainer = container ?? (typeof document !== 'undefined' ? document.body : null);\n if (!targetContainer) {\n // No container available (SSR or invalid input)\n return () => undefined;\n }\n\n const handler = (e: Event) => {\n // Only intercept standard left-clicks without modifier keys\n if (!(e instanceof MouseEvent)) return;\n if (e.defaultPrevented) return; // Already handled\n if (e.button !== 0) return; // Not left-click (middle-click opens new tab, right-click shows context menu)\n if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return; // Modifier keys (Ctrl/Cmd-click = new tab)\n\n // Guard against non-Element targets and non-DOM environments\n if (typeof Element === 'undefined' || !(e.target instanceof Element)) return;\n const target = e.target as HTMLElement;\n const anchor = target.closest('a');\n\n if (!anchor) return;\n\n // Cross-realm compatible anchor check: use owner document's constructor if available\n const anchorWindow = anchor.ownerDocument.defaultView;\n const AnchorConstructor = anchorWindow?.HTMLAnchorElement ?? HTMLAnchorElement;\n if (!(anchor instanceof AnchorConstructor)) return;\n\n if (anchor.target) return; // Has target attribute\n if (anchor.hasAttribute('download')) return;\n if (typeof window === 'undefined') return; // Non-window environment\n if (anchor.origin !== window.location.origin) return; // External link\n\n // Get active router config to handle base paths correctly.\n // If no router is active, proceed with no base/hash; navigate() will throw a\n // \"No router initialized\" error, which is caught and logged below.\n const router = getActiveRouter();\n if (!router) {\n // No active router - trigger navigate(), allowing its error to be logged here\n e.preventDefault();\n void navigate(anchor.pathname + anchor.search + anchor.hash).catch((err) => {\n console.error('Navigation failed:', err);\n });\n return;\n }\n\n const base = router.base;\n const useHash = router.hash;\n\n // Detect hash-routing mode: links written as href=\"#/page\"\n // In this case, anchor.hash contains the route path\n let path: string;\n if (useHash && anchor.hash && anchor.hash.startsWith('#/')) {\n // Hash-routing mode: extract path from the hash\n // e.g., href=\"#/page?foo=bar\" → path = \"/page?foo=bar\"\n path = anchor.hash.slice(1); // Remove leading #\n } else {\n // History mode: use pathname + search + hash\n // Strip base from pathname to avoid duplication (router.push() re-adds it)\n let pathname = anchor.pathname;\n if (base && base !== '/' && pathname.startsWith(base)) {\n pathname = pathname.slice(base.length) || '/';\n }\n path = pathname + anchor.search + anchor.hash;\n }\n\n e.preventDefault();\n void navigate(path).catch((err) => {\n console.error('Navigation failed:', err);\n });\n };\n\n targetContainer.addEventListener('click', handler);\n return () => targetContainer.removeEventListener('click', handler);\n};\n","/**\n * Query string helpers.\n * @module bquery/router\n */\n\n/**\n * Parses query string into an object.\n * Single values are stored as strings, duplicate keys become arrays.\n * @internal\n *\n * @example\n * parseQuery('?foo=1') // { foo: '1' }\n * parseQuery('?tag=a&tag=b') // { tag: ['a', 'b'] }\n * parseQuery('?x=1&y=2&x=3') // { x: ['1', '3'], y: '2' }\n */\nexport const parseQuery = (search: string): Record<string, string | string[]> => {\n const query: Record<string, string | string[]> = {};\n const params = new URLSearchParams(search);\n\n params.forEach((value, key) => {\n const existing = query[key];\n if (existing === undefined) {\n // First occurrence: store as string\n query[key] = value;\n } else if (Array.isArray(existing)) {\n // Already an array: append\n existing.push(value);\n } else {\n // Second occurrence: convert to array\n query[key] = [existing, value];\n }\n });\n\n return query;\n};\n","/**\n * Route matching helpers.\n * @module bquery/router\n */\n\nimport { parseQuery } from './query';\nimport type { Route, RouteDefinition } from './types';\n\n// ============================================================================\n// Route Matching\n// ============================================================================\n\n/**\n * Converts a route path pattern to a RegExp for matching.\n * Uses placeholder approach to preserve :param and * patterns during escaping.\n * Returns positional capture groups for maximum compatibility.\n * @internal\n */\nconst pathToRegex = (path: string): RegExp => {\n // Handle wildcard-only route\n if (path === '*') {\n return /^.*$/;\n }\n\n // Unique placeholders using null chars (won't appear in normal paths)\n const PARAM_MARKER = '\\u0000P\\u0000';\n const WILDCARD_MARKER = '\\u0000W\\u0000';\n\n // Step 1: Extract :param patterns before escaping\n let pattern = path.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, () => {\n return PARAM_MARKER;\n });\n\n // Step 2: Extract * wildcards before escaping\n pattern = pattern.replace(/\\*/g, WILDCARD_MARKER);\n\n // Step 3: Escape ALL regex metacharacters: \\ ^ $ . * + ? ( ) [ ] { } |\n pattern = pattern.replace(/[\\\\^$.*+?()[\\]{}|]/g, '\\\\$&');\n\n // Step 4: Restore param capture groups (positional, not named)\n pattern = pattern.replace(/\\u0000P\\u0000/g, () => `([^/]+)`);\n\n // Step 5: Restore wildcards as .*\n pattern = pattern.replace(/\\u0000W\\u0000/g, '.*');\n\n return new RegExp(`^${pattern}$`);\n};\n\n/**\n * Extracts param names from a route path.\n * @internal\n */\nconst extractParamNames = (path: string): string[] => {\n const matches = path.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);\n return matches ? matches.map((m) => m.slice(1)) : [];\n};\n\n/**\n * Matches a path against route definitions and extracts params.\n * Uses positional captures for maximum compatibility.\n * @internal\n */\nexport const matchRoute = (\n path: string,\n routes: RouteDefinition[]\n): { matched: RouteDefinition; params: Record<string, string> } | null => {\n for (const route of routes) {\n const regex = pathToRegex(route.path);\n const match = path.match(regex);\n\n if (match) {\n const paramNames = extractParamNames(route.path);\n const params: Record<string, string> = {};\n\n // Map positional captures to param names\n paramNames.forEach((name, index) => {\n params[name] = match[index + 1] || '';\n });\n\n return { matched: route, params };\n }\n }\n\n return null;\n};\n\n/**\n * Creates a Route object from the current URL.\n * @internal\n */\nexport const createRoute = (\n pathname: string,\n search: string,\n hash: string,\n routes: RouteDefinition[]\n): Route => {\n const result = matchRoute(pathname, routes);\n\n return {\n path: pathname,\n params: result?.params ?? {},\n query: parseQuery(search),\n matched: result?.matched ?? null,\n hash: hash.replace(/^#/, ''),\n };\n};\n","/**\n * Router utilities.\n * @module bquery/router\n */\n\nimport { computed, type ReadonlySignal } from '../reactive/index';\nimport { getActiveRouter, routeSignal } from './state';\nimport type { RouteDefinition } from './types';\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\n/**\n * Flattens nested routes into a single array with full paths.\n * Does NOT include the router base - base is only for browser history.\n * @internal\n */\nexport const flattenRoutes = (routes: RouteDefinition[], parentPath = ''): RouteDefinition[] => {\n const result: RouteDefinition[] = [];\n\n for (const route of routes) {\n const fullPath = route.path === '*' ? '*' : `${parentPath}${route.path}`.replace(/\\/+/g, '/');\n\n result.push({\n ...route,\n path: fullPath,\n });\n\n if (route.children) {\n result.push(...flattenRoutes(route.children, fullPath));\n }\n }\n\n return result;\n};\n\n/**\n * Resolves a route by name and params.\n *\n * @param name - The route name\n * @param params - Route params to interpolate\n * @returns The resolved path\n *\n * @example\n * ```ts\n * import { resolve } from 'bquery/router';\n *\n * const path = resolve('user', { id: '42' });\n * // Returns '/user/42' if route is defined as { name: 'user', path: '/user/:id' }\n * ```\n */\nexport const resolve = (name: string, params: Record<string, string> = {}): string => {\n const activeRouter = getActiveRouter();\n if (!activeRouter) {\n throw new Error('bQuery router: No router initialized.');\n }\n\n const route = activeRouter.routes.find((r) => r.name === name);\n if (!route) {\n throw new Error(`bQuery router: Route \"${name}\" not found.`);\n }\n\n let path = route.path;\n for (const [key, value] of Object.entries(params)) {\n path = path.replace(`:${key}`, encodeURIComponent(value));\n }\n\n return path;\n};\n\n/**\n * Checks if a path matches the current route.\n *\n * @param path - Path to check\n * @param exact - Whether to match exactly (default: false)\n * @returns True if the path matches\n *\n * @example\n * ```ts\n * import { isActive } from 'bquery/router';\n *\n * if (isActive('/dashboard')) {\n * // Highlight nav item\n * }\n * ```\n */\nexport const isActive = (path: string, exact = false): boolean => {\n const current = routeSignal.value.path;\n return exact ? current === path : current.startsWith(path);\n};\n\n/**\n * Creates a computed signal that checks if a path is active.\n *\n * @param path - Path to check\n * @param exact - Whether to match exactly\n * @returns A reactive signal\n *\n * @example\n * ```ts\n * import { isActiveSignal } from 'bquery/router';\n * import { effect } from 'bquery/reactive';\n *\n * const dashboardActive = isActiveSignal('/dashboard');\n * effect(() => {\n * navItem.classList.toggle('active', dashboardActive.value);\n * });\n * ```\n */\nexport const isActiveSignal = (path: string, exact = false): ReadonlySignal<boolean> => {\n return computed(() => {\n const current = routeSignal.value.path;\n return exact ? current === path : current.startsWith(path);\n });\n};\n","/**\n * Router creation and lifecycle management.\n * @module bquery/router\n */\n\nimport { createRoute } from './match';\nimport { currentRoute, getActiveRouter, routeSignal, setActiveRouter } from './state';\nimport type { NavigationGuard, Route, Router, RouterOptions } from './types';\nimport { flattenRoutes } from './utils';\n\n// ============================================================================\n// Router Creation\n// ============================================================================\n\n/**\n * Creates and initializes a router instance.\n *\n * @param options - Router configuration\n * @returns The router instance\n *\n * @example\n * ```ts\n * import { createRouter } from 'bquery/router';\n *\n * const router = createRouter({\n * routes: [\n * { path: '/', component: () => import('./pages/Home') },\n * { path: '/about', component: () => import('./pages/About') },\n * { path: '/user/:id', component: () => import('./pages/User') },\n * { path: '*', component: () => import('./pages/NotFound') },\n * ],\n * base: '/app',\n * });\n *\n * router.beforeEach((to, from) => {\n * if (to.path === '/admin' && !isAuthenticated()) {\n * return false; // Cancel navigation\n * }\n * });\n * ```\n */\nexport const createRouter = (options: RouterOptions): Router => {\n // Clean up any existing router to prevent guard leakage\n const existingRouter = getActiveRouter();\n if (existingRouter) {\n existingRouter.destroy();\n }\n\n const { routes, base = '', hash: useHash = false } = options;\n\n // Instance-specific guards and hooks (not shared globally)\n const beforeGuards: NavigationGuard[] = [];\n const afterHooks: Array<(to: Route, from: Route) => void> = [];\n\n // Flatten nested routes (base-relative, not including the base path)\n const flatRoutes = flattenRoutes(routes);\n\n /**\n * Gets the current path from the URL.\n */\n const getCurrentPath = (): { pathname: string; search: string; hash: string } => {\n if (useHash) {\n const hashPath = window.location.hash.slice(1) || '/';\n // In hash routing, URL structure is #/path?query#fragment\n // Extract hash fragment first (after the second #)\n const [pathWithQuery, hashPart = ''] = hashPath.split('#');\n // Then extract query from the path\n const [pathname, search = ''] = pathWithQuery.split('?');\n return {\n pathname,\n search: search ? `?${search}` : '',\n hash: hashPart ? `#${hashPart}` : '',\n };\n }\n\n let pathname = window.location.pathname;\n if (base && (pathname === base || pathname.startsWith(base + '/'))) {\n pathname = pathname.slice(base.length) || '/';\n }\n\n return {\n pathname,\n search: window.location.search,\n hash: window.location.hash,\n };\n };\n\n /**\n * Updates the route signal with current URL state.\n */\n const syncRoute = (): void => {\n const { pathname, search, hash } = getCurrentPath();\n const newRoute = createRoute(pathname, search, hash, flatRoutes);\n routeSignal.value = newRoute;\n };\n\n /**\n * Performs navigation with guards.\n */\n const performNavigation = async (\n path: string,\n method: 'pushState' | 'replaceState'\n ): Promise<void> => {\n const { pathname, search, hash } = getCurrentPath();\n const from = createRoute(pathname, search, hash, flatRoutes);\n\n // Parse the target path\n const url = new URL(path, window.location.origin);\n const to = createRoute(url.pathname, url.search, url.hash, flatRoutes);\n\n // Run beforeEach guards\n for (const guard of beforeGuards) {\n const result = await guard(to, from);\n if (result === false) {\n return; // Cancel navigation\n }\n }\n\n // Update browser history\n const fullPath = useHash ? `#${path}` : `${base}${path}`;\n history[method]({}, '', fullPath);\n\n // Update route signal\n syncRoute();\n\n // Run afterEach hooks\n for (const hook of afterHooks) {\n hook(routeSignal.value, from);\n }\n };\n\n /**\n * Handle popstate events (back/forward).\n */\n const handlePopState = async (): Promise<void> => {\n const { pathname, search, hash } = getCurrentPath();\n const from = routeSignal.value;\n const to = createRoute(pathname, search, hash, flatRoutes);\n\n // Run beforeEach guards (supports async guards)\n for (const guard of beforeGuards) {\n const result = await guard(to, from);\n if (result === false) {\n // Restore previous state with full URL (including query/hash)\n const queryString = new URLSearchParams(\n Object.entries(from.query).flatMap(([key, value]) =>\n Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]\n )\n ).toString();\n const search = queryString ? `?${queryString}` : '';\n const hash = from.hash ? `#${from.hash}` : '';\n const restorePath = useHash\n ? `#${from.path}${search}${hash}`\n : `${base}${from.path}${search}${hash}`;\n history.replaceState({}, '', restorePath);\n return;\n }\n }\n\n syncRoute();\n\n for (const hook of afterHooks) {\n hook(routeSignal.value, from);\n }\n };\n\n // Attach popstate listener\n window.addEventListener('popstate', handlePopState);\n\n // Initialize route\n syncRoute();\n\n const router: Router = {\n push: (path: string) => performNavigation(path, 'pushState'),\n replace: (path: string) => performNavigation(path, 'replaceState'),\n back: () => history.back(),\n forward: () => history.forward(),\n go: (delta: number) => history.go(delta),\n\n beforeEach: (guard: NavigationGuard) => {\n beforeGuards.push(guard);\n return () => {\n const index = beforeGuards.indexOf(guard);\n if (index > -1) beforeGuards.splice(index, 1);\n };\n },\n\n afterEach: (hook: (to: Route, from: Route) => void) => {\n afterHooks.push(hook);\n return () => {\n const index = afterHooks.indexOf(hook);\n if (index > -1) afterHooks.splice(index, 1);\n };\n },\n\n currentRoute,\n routes: flatRoutes,\n base,\n hash: useHash,\n\n destroy: () => {\n window.removeEventListener('popstate', handlePopState);\n beforeGuards.length = 0;\n afterHooks.length = 0;\n setActiveRouter(null);\n },\n };\n\n setActiveRouter(router);\n return router;\n};\n"],"mappings":";;AAaA,IAAI,IAA8B,MAGrB,IAA6B,EAAc;AAAA,EACtD,MAAM;AAAA,EACN,QAAQ,CAAA;AAAA,EACR,OAAO,CAAA;AAAA,EACP,SAAS;AAAA,EACT,MAAM;CACP,GAeY,IAAsC,EAAA,MAAe,EAAY,KAAA,GAGjE,IAAA,MAAuC,GAGvC,IAAA,CAAmB,MAAgC;AAC9D,EAAA,IAAe;GCpBJ,IAAW,OACtB,GACA,IAAiC,CAAA,MACf;AAClB,QAAM,IAAe,EAAA;AACrB,MAAI,CAAC,EACH,OAAM,IAAI,MAAM,kEAAA;AAGlB,QAAM,EAAa,EAAQ,UAAU,YAAY,MAAA,EAAQ,CAAA;GAY9C,IAAA,MAAmB;AAC9B,QAAM,IAAe,EAAA;AACrB,EAAI,IACF,EAAa,KAAA,IAEb,QAAQ,KAAA;GAaC,IAAA,MAAsB;AACjC,QAAM,IAAe,EAAA;AACrB,EAAI,IACF,EAAa,QAAA,IAEb,QAAQ,QAAA;GCvCC,IAAA,CAAQ,GAAc,IAAiC,CAAA,MAClE,CAAQ,MAAa;AACnB,EAAA,EAAE,eAAA,GACG,EAAS,GAAM,CAAA,EAAS,MAAA,CAAO,MAAQ;AAC1C,YAAQ,MAAM,sBAAsB,CAAA;AAAA;GAuB7B,IAAA,CAAkB,MAAsC;AAEnE,QAAM,IAAkB,MAAc,OAAO,WAAa,MAAc,SAAS,OAAO;AACxF,MAAI,CAAC,EAEH,QAAA,MAAA;AAAA;AAGF,QAAM,IAAA,CAAW,MAAa;AAQ5B,QANI,EAAE,aAAa,eACf,EAAE,oBACF,EAAE,WAAW,KACb,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAG1C,OAAO,UAAY,OAAe,EAAE,EAAE,kBAAkB,SAAU;AAEtE,UAAM,IADS,EAAE,OACK,QAAQ,GAAA;AAY9B,QAVI,CAAC,KAKD,EAAE,cAFe,EAAO,cAAc,aACF,qBAAqB,uBAGzD,EAAO,UACP,EAAO,aAAa,UAAA,KACpB,OAAO,SAAW,OAClB,EAAO,WAAW,OAAO,SAAS,OAAQ;AAK9C,UAAM,IAAS,EAAA;AACf,QAAI,CAAC,GAAQ;AAEX,MAAA,EAAE,eAAA,GACG,EAAS,EAAO,WAAW,EAAO,SAAS,EAAO,IAAA,EAAM,MAAA,CAAO,MAAQ;AAC1E,gBAAQ,MAAM,sBAAsB,CAAA;AAAA;AAEtC;AAAA;AAGF,UAAM,IAAO,EAAO,MACd,IAAU,EAAO;AAIvB,QAAI;AACJ,QAAI,KAAW,EAAO,QAAQ,EAAO,KAAK,WAAW,IAAA,EAGnD,CAAA,IAAO,EAAO,KAAK,MAAM,CAAA;AAAA,SACpB;AAGL,UAAI,IAAW,EAAO;AACtB,MAAI,KAAQ,MAAS,OAAO,EAAS,WAAW,CAAA,MAC9C,IAAW,EAAS,MAAM,EAAK,MAAA,KAAW,MAE5C,IAAO,IAAW,EAAO,SAAS,EAAO;AAAA;AAG3C,IAAA,EAAE,eAAA,GACG,EAAS,CAAA,EAAM,MAAA,CAAO,MAAQ;AACjC,cAAQ,MAAM,sBAAsB,CAAA;AAAA;;AAIxC,SAAA,EAAgB,iBAAiB,SAAS,CAAA,GAC1C,MAAa,EAAgB,oBAAoB,SAAS,CAAA;GCjH/C,IAAA,CAAc,MAAsD;AAC/E,QAAM,IAA2C,CAAA;AAClC,aAAI,gBAAgB,CAAA,EAE5B,QAAA,CAAS,GAAO,MAAQ;AAC7B,UAAM,IAAW,EAAM,CAAA;AACvB,IAAI,MAAa,SAEf,EAAM,CAAA,IAAO,IACJ,MAAM,QAAQ,CAAA,IAEvB,EAAS,KAAK,CAAA,IAGd,EAAM,CAAA,IAAO,CAAC,GAAU,CAAA;AAAA,MAIrB;GCfH,IAAA,CAAe,MAAyB;AAE5C,MAAI,MAAS,IACX,QAAO;AAIT,QAAM,IAAe,SACf,IAAkB;AAGxB,MAAI,IAAU,EAAK,QAAQ,8BAAA,MAClB;AAIT,SAAA,IAAU,EAAQ,QAAQ,OAAO,CAAA,GAGjC,IAAU,EAAQ,QAAQ,uBAAuB,MAAA,GAGjD,IAAU,EAAQ,QAAQ,kBAAA,MAAwB,SAAA,GAGlD,IAAU,EAAQ,QAAQ,kBAAkB,IAAA,GAErC,IAAI,OAAO,IAAI,CAAA,GAAQ;GAO1B,IAAA,CAAqB,MAA2B;AACpD,QAAM,IAAU,EAAK,MAAM,4BAAA;AAC3B,SAAO,IAAU,EAAQ,IAAA,CAAK,MAAM,EAAE,MAAM,CAAA,CAAE,IAAI,CAAA;GAQvC,IAAA,CACX,GACA,MACwE;AACxE,aAAW,KAAS,GAAQ;AAC1B,UAAM,IAAQ,EAAY,EAAM,IAAA,GAC1B,IAAQ,EAAK,MAAM,CAAA;AAEzB,QAAI,GAAO;AACT,YAAM,IAAa,EAAkB,EAAM,IAAA,GACrC,IAAiC,CAAA;AAGvC,aAAA,EAAW,QAAA,CAAS,GAAM,MAAU;AAClC,QAAA,EAAO,CAAA,IAAQ,EAAM,IAAQ,CAAA,KAAM;AAAA,UAG9B;AAAA,QAAE,SAAS;AAAA,QAAO,QAAA;AAAA;;;AAI7B,SAAO;GAOI,IAAA,CACX,GACA,GACA,GACA,MACU;AACV,QAAM,IAAS,EAAW,GAAU,CAAA;AAEpC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,GAAQ,UAAU,CAAA;AAAA,IAC1B,OAAO,EAAW,CAAA;AAAA,IAClB,SAAS,GAAQ,WAAW;AAAA,IAC5B,MAAM,EAAK,QAAQ,MAAM,EAAA;AAAA;GCrFhB,IAAA,CAAiB,GAA2B,IAAa,OAA0B;AAC9F,QAAM,IAA4B,CAAA;AAElC,aAAW,KAAS,GAAQ;AAC1B,UAAM,IAAW,EAAM,SAAS,MAAM,MAAM,GAAG,CAAA,GAAa,EAAM,IAAA,GAAO,QAAQ,QAAQ,GAAA;AAEzF,IAAA,EAAO,KAAK;AAAA,MACV,GAAG;AAAA,MACH,MAAM;AAAA,KACP,GAEG,EAAM,YACR,EAAO,KAAK,GAAG,EAAc,EAAM,UAAU,CAAA,CAAS;AAAA;AAI1D,SAAO;GAkBI,IAAA,CAAW,GAAc,IAAiC,CAAA,MAAe;AACpF,QAAM,IAAe,EAAA;AACrB,MAAI,CAAC,EACH,OAAM,IAAI,MAAM,uCAAA;AAGlB,QAAM,IAAQ,EAAa,OAAO,KAAA,CAAM,MAAM,EAAE,SAAS,CAAA;AACzD,MAAI,CAAC,EACH,OAAM,IAAI,MAAM,yBAAyB,CAAA,cAAK;AAGhD,MAAI,IAAO,EAAM;AACjB,aAAW,CAAC,GAAK,CAAA,KAAU,OAAO,QAAQ,CAAA,EACxC,CAAA,IAAO,EAAK,QAAQ,IAAI,CAAA,IAAO,mBAAmB,CAAA,CAAM;AAG1D,SAAO;GAmBI,IAAA,CAAY,GAAc,IAAQ,OAAmB;AAChE,QAAM,IAAU,EAAY,MAAM;AAClC,SAAO,IAAQ,MAAY,IAAO,EAAQ,WAAW,CAAA;GAqB1C,IAAA,CAAkB,GAAc,IAAQ,OAC5C,EAAA,MAAe;AACpB,QAAM,IAAU,EAAY,MAAM;AAClC,SAAO,IAAQ,MAAY,IAAO,EAAQ,WAAW,CAAA;ICxE5C,IAAA,CAAgB,MAAmC;AAE9D,QAAM,IAAiB,EAAA;AACvB,EAAI,KACF,EAAe,QAAA;AAGjB,QAAM,EAAE,QAAA,GAAQ,MAAA,IAAO,IAAI,MAAM,IAAU,GAAA,IAAU,GAG/C,IAAkC,CAAA,GAClC,IAAsD,CAAA,GAGtD,IAAa,EAAc,CAAA,GAK3B,IAAA,MAA2E;AAC/E,QAAI,GAAS;AAIX,YAAM,CAAC,GAAe,IAAW,EAAA,KAHhB,OAAO,SAAS,KAAK,MAAM,CAAA,KAAM,KAGF,MAAM,GAAA,GAEhD,CAAC,GAAU,IAAS,EAAA,IAAM,EAAc,MAAM,GAAA;AACpD,aAAO;AAAA,QACL,UAAA;AAAA,QACA,QAAQ,IAAS,IAAI,CAAA,KAAW;AAAA,QAChC,MAAM,IAAW,IAAI,CAAA,KAAa;AAAA;;AAItC,QAAI,IAAW,OAAO,SAAS;AAC/B,WAAI,MAAS,MAAa,KAAQ,EAAS,WAAW,IAAO,GAAA,OAC3D,IAAW,EAAS,MAAM,EAAK,MAAA,KAAW,MAGrC;AAAA,MACL,UAAA;AAAA,MACA,QAAQ,OAAO,SAAS;AAAA,MACxB,MAAM,OAAO,SAAS;AAAA;KAOpB,IAAA,MAAwB;AAC5B,UAAM,EAAE,UAAA,GAAU,QAAA,GAAQ,MAAA,EAAA,IAAS,EAAA;AAEnC,IAAA,EAAY,QADK,EAAY,GAAU,GAAQ,GAAM,CAAA;AAAA,KAOjD,IAAoB,OACxB,GACA,MACkB;AAClB,UAAM,EAAE,UAAA,GAAU,QAAA,GAAQ,MAAA,EAAA,IAAS,EAAA,GAC7B,IAAO,EAAY,GAAU,GAAQ,GAAM,CAAA,GAG3C,IAAM,IAAI,IAAI,GAAM,OAAO,SAAS,MAAA,GACpC,IAAK,EAAY,EAAI,UAAU,EAAI,QAAQ,EAAI,MAAM,CAAA;AAG3D,eAAW,KAAS,EAElB,KADe,MAAM,EAAM,GAAI,CAAA,MAChB,GACb;AAKJ,UAAM,IAAW,IAAU,IAAI,CAAA,KAAS,GAAG,CAAA,GAAO,CAAA;AAClD,YAAQ,CAAA,EAAQ,CAAA,GAAI,IAAI,CAAA,GAGxB,EAAA;AAGA,eAAW,KAAQ,EACjB,CAAA,EAAK,EAAY,OAAO,CAAA;AAAA,KAOtB,IAAiB,YAA2B;AAChD,UAAM,EAAE,UAAA,GAAU,QAAA,GAAQ,MAAA,EAAA,IAAS,EAAA,GAC7B,IAAO,EAAY,OACnB,IAAK,EAAY,GAAU,GAAQ,GAAM,CAAA;AAG/C,eAAW,KAAS,EAElB,KADe,MAAM,EAAM,GAAI,CAAA,MAChB,IAAO;AAEpB,YAAM,IAAc,IAAI,gBACtB,OAAO,QAAQ,EAAK,KAAA,EAAO,QAAA,CAAS,CAAC,GAAK,CAAA,MACxC,MAAM,QAAQ,CAAA,IAAS,EAAM,IAAA,CAAK,MAAM,CAAC,GAAK,CAAA,CAAE,IAAI,CAAC,CAAC,GAAK,CAAA,CAAM,CAAC,CACnE,EACD,SAAA,GACI,IAAS,IAAc,IAAI,CAAA,KAAgB,IAC3C,IAAO,EAAK,OAAO,IAAI,EAAK,IAAA,KAAS,IACrC,IAAc,IAChB,IAAI,EAAK,IAAA,GAAO,CAAA,GAAS,CAAA,KACzB,GAAG,CAAA,GAAO,EAAK,IAAA,GAAO,CAAA,GAAS,CAAA;AACnC,cAAQ,aAAa,CAAA,GAAI,IAAI,CAAA;AAC7B;AAAA;AAIJ,IAAA,EAAA;AAEA,eAAW,KAAQ,EACjB,CAAA,EAAK,EAAY,OAAO,CAAA;AAAA;AAK5B,SAAO,iBAAiB,YAAY,CAAA,GAGpC,EAAA;AAEA,QAAM,IAAiB;AAAA,IACrB,MAAA,CAAO,MAAiB,EAAkB,GAAM,WAAA;AAAA,IAChD,SAAA,CAAU,MAAiB,EAAkB,GAAM,cAAA;AAAA,IACnD,MAAA,MAAY,QAAQ,KAAA;AAAA,IACpB,SAAA,MAAe,QAAQ,QAAA;AAAA,IACvB,IAAA,CAAK,MAAkB,QAAQ,GAAG,CAAA;AAAA,IAElC,YAAA,CAAa,OACX,EAAa,KAAK,CAAA,GAClB,MAAa;AACX,YAAM,IAAQ,EAAa,QAAQ,CAAA;AACnC,MAAI,IAAQ,MAAI,EAAa,OAAO,GAAO,CAAA;AAAA;IAI/C,WAAA,CAAY,OACV,EAAW,KAAK,CAAA,GAChB,MAAa;AACX,YAAM,IAAQ,EAAW,QAAQ,CAAA;AACjC,MAAI,IAAQ,MAAI,EAAW,OAAO,GAAO,CAAA;AAAA;IAI7C,cAAA;AAAA,IACA,QAAQ;AAAA,IACR,MAAA;AAAA,IACA,MAAM;AAAA,IAEN,SAAA,MAAe;AACb,aAAO,oBAAoB,YAAY,CAAA,GACvC,EAAa,SAAS,GACtB,EAAW,SAAS,GACpB,EAAgB,IAAA;AAAA;;AAIpB,SAAA,EAAgB,CAAA,GACT"}
|
package/dist/router.es.mjs
CHANGED
|
@@ -1,202 +1,13 @@
|
|
|
1
|
-
import { c as
|
|
2
|
-
let M = null;
|
|
3
|
-
const w = D({
|
|
4
|
-
path: "",
|
|
5
|
-
params: {},
|
|
6
|
-
query: {},
|
|
7
|
-
matched: null,
|
|
8
|
-
hash: ""
|
|
9
|
-
}), K = N(() => w.value), y = () => M, k = (e) => {
|
|
10
|
-
M = e;
|
|
11
|
-
}, L = async (e, o = {}) => {
|
|
12
|
-
const r = y();
|
|
13
|
-
if (!r)
|
|
14
|
-
throw new Error("bQuery router: No router initialized. Call createRouter() first.");
|
|
15
|
-
await r[o.replace ? "replace" : "push"](e);
|
|
16
|
-
}, U = () => {
|
|
17
|
-
const e = y();
|
|
18
|
-
e ? e.back() : history.back();
|
|
19
|
-
}, Z = () => {
|
|
20
|
-
const e = y();
|
|
21
|
-
e ? e.forward() : history.forward();
|
|
22
|
-
}, T = (e, o = {}) => (r) => {
|
|
23
|
-
r.preventDefault(), L(e, o).catch((t) => {
|
|
24
|
-
console.error("Navigation failed:", t);
|
|
25
|
-
});
|
|
26
|
-
}, j = (e) => {
|
|
27
|
-
const o = e ?? (typeof document < "u" ? document.body : null);
|
|
28
|
-
if (!o)
|
|
29
|
-
return () => {
|
|
30
|
-
};
|
|
31
|
-
const r = (t) => {
|
|
32
|
-
if (!(t instanceof MouseEvent) || t.defaultPrevented || t.button !== 0 || t.ctrlKey || t.metaKey || t.shiftKey || t.altKey || typeof Element > "u" || !(t.target instanceof Element)) return;
|
|
33
|
-
const n = t.target.closest("a");
|
|
34
|
-
if (!n) return;
|
|
35
|
-
const l = n.ownerDocument.defaultView?.HTMLAnchorElement ?? HTMLAnchorElement;
|
|
36
|
-
if (!(n instanceof l) || n.target || n.hasAttribute("download") || typeof window > "u" || n.origin !== window.location.origin) return;
|
|
37
|
-
const f = y();
|
|
38
|
-
if (!f) {
|
|
39
|
-
t.preventDefault(), L(n.pathname + n.search + n.hash).catch((u) => {
|
|
40
|
-
console.error("Navigation failed:", u);
|
|
41
|
-
});
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const d = f.base, $ = f.hash;
|
|
45
|
-
let g;
|
|
46
|
-
if ($ && n.hash && n.hash.startsWith("#/"))
|
|
47
|
-
g = n.hash.slice(1);
|
|
48
|
-
else {
|
|
49
|
-
let u = n.pathname;
|
|
50
|
-
d && d !== "/" && u.startsWith(d) && (u = u.slice(d.length) || "/"), g = u + n.search + n.hash;
|
|
51
|
-
}
|
|
52
|
-
t.preventDefault(), L(g).catch((u) => {
|
|
53
|
-
console.error("Navigation failed:", u);
|
|
54
|
-
});
|
|
55
|
-
};
|
|
56
|
-
return o.addEventListener("click", r), () => o.removeEventListener("click", r);
|
|
57
|
-
}, _ = (e) => {
|
|
58
|
-
const o = {};
|
|
59
|
-
return new URLSearchParams(e).forEach((t, s) => {
|
|
60
|
-
const n = o[s];
|
|
61
|
-
n === void 0 ? o[s] = t : Array.isArray(n) ? n.push(t) : o[s] = [n, t];
|
|
62
|
-
}), o;
|
|
63
|
-
}, q = (e) => {
|
|
64
|
-
if (e === "*")
|
|
65
|
-
return /^.*$/;
|
|
66
|
-
const o = "\0P\0", r = "\0W\0";
|
|
67
|
-
let t = e.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, () => o);
|
|
68
|
-
return t = t.replace(/\*/g, r), t = t.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&"), t = t.replace(/\u0000P\u0000/g, () => "([^/]+)"), t = t.replace(/\u0000W\u0000/g, ".*"), new RegExp(`^${t}$`);
|
|
69
|
-
}, H = (e) => {
|
|
70
|
-
const o = e.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);
|
|
71
|
-
return o ? o.map((r) => r.slice(1)) : [];
|
|
72
|
-
}, Q = (e, o) => {
|
|
73
|
-
for (const r of o) {
|
|
74
|
-
const t = q(r.path), s = e.match(t);
|
|
75
|
-
if (s) {
|
|
76
|
-
const n = H(r.path), h = {};
|
|
77
|
-
return n.forEach((l, f) => {
|
|
78
|
-
h[l] = s[f + 1] || "";
|
|
79
|
-
}), { matched: r, params: h };
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return null;
|
|
83
|
-
}, P = (e, o, r, t) => {
|
|
84
|
-
const s = Q(e, t);
|
|
85
|
-
return {
|
|
86
|
-
path: e,
|
|
87
|
-
params: s?.params ?? {},
|
|
88
|
-
query: _(o),
|
|
89
|
-
matched: s?.matched ?? null,
|
|
90
|
-
hash: r.replace(/^#/, "")
|
|
91
|
-
};
|
|
92
|
-
}, z = (e, o = "") => {
|
|
93
|
-
const r = [];
|
|
94
|
-
for (const t of e) {
|
|
95
|
-
const s = t.path === "*" ? "*" : `${o}${t.path}`.replace(/\/+/g, "/");
|
|
96
|
-
r.push({
|
|
97
|
-
...t,
|
|
98
|
-
path: s
|
|
99
|
-
}), t.children && r.push(...z(t.children, s));
|
|
100
|
-
}
|
|
101
|
-
return r;
|
|
102
|
-
}, I = (e, o = {}) => {
|
|
103
|
-
const r = y();
|
|
104
|
-
if (!r)
|
|
105
|
-
throw new Error("bQuery router: No router initialized.");
|
|
106
|
-
const t = r.routes.find((n) => n.name === e);
|
|
107
|
-
if (!t)
|
|
108
|
-
throw new Error(`bQuery router: Route "${e}" not found.`);
|
|
109
|
-
let s = t.path;
|
|
110
|
-
for (const [n, h] of Object.entries(o))
|
|
111
|
-
s = s.replace(`:${n}`, encodeURIComponent(h));
|
|
112
|
-
return s;
|
|
113
|
-
}, G = (e, o = !1) => {
|
|
114
|
-
const r = w.value.path;
|
|
115
|
-
return o ? r === e : r.startsWith(e);
|
|
116
|
-
}, V = (e, o = !1) => N(() => {
|
|
117
|
-
const r = w.value.path;
|
|
118
|
-
return o ? r === e : r.startsWith(e);
|
|
119
|
-
}), B = (e) => {
|
|
120
|
-
const o = y();
|
|
121
|
-
o && o.destroy();
|
|
122
|
-
const { routes: r, base: t = "", hash: s = !1 } = e, n = [], h = [], l = z(r), f = () => {
|
|
123
|
-
if (s) {
|
|
124
|
-
const i = window.location.hash.slice(1) || "/", [m, c = ""] = i.split("#"), [R, p = ""] = m.split("?");
|
|
125
|
-
return {
|
|
126
|
-
pathname: R,
|
|
127
|
-
search: p ? `?${p}` : "",
|
|
128
|
-
hash: c ? `#${c}` : ""
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
let a = window.location.pathname;
|
|
132
|
-
return t && (a === t || a.startsWith(t + "/")) && (a = a.slice(t.length) || "/"), {
|
|
133
|
-
pathname: a,
|
|
134
|
-
search: window.location.search,
|
|
135
|
-
hash: window.location.hash
|
|
136
|
-
};
|
|
137
|
-
}, d = () => {
|
|
138
|
-
const { pathname: a, search: i, hash: m } = f(), c = P(a, i, m, l);
|
|
139
|
-
w.value = c;
|
|
140
|
-
}, $ = async (a, i) => {
|
|
141
|
-
const { pathname: m, search: c, hash: R } = f(), p = P(m, c, R, l), A = new URL(a, window.location.origin), E = P(A.pathname, A.search, A.hash, l);
|
|
142
|
-
for (const v of n)
|
|
143
|
-
if (await v(E, p) === !1)
|
|
144
|
-
return;
|
|
145
|
-
const b = s ? `#${a}` : `${t}${a}`;
|
|
146
|
-
history[i]({}, "", b), d();
|
|
147
|
-
for (const v of h)
|
|
148
|
-
v(w.value, p);
|
|
149
|
-
}, g = async () => {
|
|
150
|
-
const { pathname: a, search: i, hash: m } = f(), c = w.value, R = P(a, i, m, l);
|
|
151
|
-
for (const p of n)
|
|
152
|
-
if (await p(R, c) === !1) {
|
|
153
|
-
const E = new URLSearchParams(
|
|
154
|
-
Object.entries(c.query).flatMap(
|
|
155
|
-
([S, x]) => Array.isArray(x) ? x.map((C) => [S, C]) : [[S, x]]
|
|
156
|
-
)
|
|
157
|
-
).toString(), b = E ? `?${E}` : "", v = c.hash ? `#${c.hash}` : "", W = s ? `#${c.path}${b}${v}` : `${t}${c.path}${b}${v}`;
|
|
158
|
-
history.replaceState({}, "", W);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
d();
|
|
162
|
-
for (const p of h)
|
|
163
|
-
p(w.value, c);
|
|
164
|
-
};
|
|
165
|
-
window.addEventListener("popstate", g), d();
|
|
166
|
-
const u = {
|
|
167
|
-
push: (a) => $(a, "pushState"),
|
|
168
|
-
replace: (a) => $(a, "replaceState"),
|
|
169
|
-
back: () => history.back(),
|
|
170
|
-
forward: () => history.forward(),
|
|
171
|
-
go: (a) => history.go(a),
|
|
172
|
-
beforeEach: (a) => (n.push(a), () => {
|
|
173
|
-
const i = n.indexOf(a);
|
|
174
|
-
i > -1 && n.splice(i, 1);
|
|
175
|
-
}),
|
|
176
|
-
afterEach: (a) => (h.push(a), () => {
|
|
177
|
-
const i = h.indexOf(a);
|
|
178
|
-
i > -1 && h.splice(i, 1);
|
|
179
|
-
}),
|
|
180
|
-
currentRoute: K,
|
|
181
|
-
routes: l,
|
|
182
|
-
base: t,
|
|
183
|
-
hash: s,
|
|
184
|
-
destroy: () => {
|
|
185
|
-
window.removeEventListener("popstate", g), n.length = 0, h.length = 0, k(null);
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
return k(u), u;
|
|
189
|
-
};
|
|
1
|
+
import { a as s, c as e, i as r, l as t, n as i, o, r as c, s as n, t as l, u } from "./router-CijiICxt.js";
|
|
190
2
|
export {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
3
|
+
n as back,
|
|
4
|
+
l as createRouter,
|
|
5
|
+
u as currentRoute,
|
|
6
|
+
e as forward,
|
|
7
|
+
s as interceptLinks,
|
|
8
|
+
i as isActive,
|
|
9
|
+
c as isActiveSignal,
|
|
10
|
+
o as link,
|
|
11
|
+
t as navigate,
|
|
12
|
+
r as resolve
|
|
201
13
|
};
|
|
202
|
-
//# sourceMappingURL=router.es.mjs.map
|