@coherent.js/client 1.1.1 → 2.0.0-rc.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 +126 -66
- package/dist/chunk-EAOAAY2X.js +1550 -0
- package/dist/chunk-EAOAAY2X.js.map +7 -0
- package/dist/{chunk-N36BSMJU.js → chunk-UYL3RRRC.js} +134 -32
- package/dist/chunk-UYL3RRRC.js.map +7 -0
- package/dist/events/index.js +1 -1
- package/dist/hmr.js +34 -4
- package/dist/hmr.js.map +3 -3
- package/dist/index.js +598 -1732
- package/dist/index.js.map +4 -4
- package/dist/router.js +209 -31
- package/dist/router.js.map +2 -2
- package/package.json +4 -1
- package/types/hmr.d.ts +32 -1
- package/types/index.d.ts +258 -701
- package/types/router.d.ts +34 -11
- package/dist/chunk-N36BSMJU.js.map +0 -7
package/types/router.d.ts
CHANGED
|
@@ -20,16 +20,16 @@ export interface RouteTransition {
|
|
|
20
20
|
|
|
21
21
|
/** Route configuration */
|
|
22
22
|
export interface RouteConfig {
|
|
23
|
-
/** Route path pattern */
|
|
24
|
-
path
|
|
23
|
+
/** Route path pattern (the `addRoute()` argument is what counts) */
|
|
24
|
+
path?: string;
|
|
25
25
|
/** Component to render (can be async for code splitting) */
|
|
26
26
|
component: CoherentComponent | (() => Promise<CoherentComponent>);
|
|
27
27
|
/** Route metadata */
|
|
28
28
|
meta?: Record<string, any>;
|
|
29
|
-
/** Before enter guard */
|
|
30
|
-
beforeEnter?: (to: Route, from: Route | null) => boolean | Promise<boolean>;
|
|
31
|
-
/** Before leave guard */
|
|
32
|
-
beforeLeave?: (to: Route, from: Route) => boolean | Promise<boolean>;
|
|
29
|
+
/** Before enter guard; returning `false` cancels the navigation */
|
|
30
|
+
beforeEnter?: (to: Route, from: Route | null) => boolean | void | Promise<boolean | void>;
|
|
31
|
+
/** Before leave guard; returning `false` cancels the navigation */
|
|
32
|
+
beforeLeave?: (to: Route, from: Route) => boolean | void | Promise<boolean | void>;
|
|
33
33
|
/** Prefetch priority */
|
|
34
34
|
priority?: number;
|
|
35
35
|
/** Custom transition for this route */
|
|
@@ -38,9 +38,15 @@ export interface RouteConfig {
|
|
|
38
38
|
|
|
39
39
|
/** Current route state */
|
|
40
40
|
export interface Route {
|
|
41
|
+
/** Path without query or hash, e.g. `/users/42` */
|
|
41
42
|
path: string;
|
|
43
|
+
/** Path as navigated to, e.g. `/users/42?tab=posts#top` */
|
|
44
|
+
fullPath?: string;
|
|
45
|
+
/** Values of the matched pattern's `:params` (and `pathMatch` for `*`) */
|
|
46
|
+
params?: Record<string, string>;
|
|
42
47
|
component?: CoherentComponent;
|
|
43
48
|
meta?: Record<string, any>;
|
|
49
|
+
/** `#hash`, including the `#`, or `''` */
|
|
44
50
|
hash?: string;
|
|
45
51
|
query?: Record<string, string>;
|
|
46
52
|
}
|
|
@@ -65,7 +71,9 @@ export interface ScrollBehaviorConfig {
|
|
|
65
71
|
|
|
66
72
|
/** Router configuration options */
|
|
67
73
|
export interface RouterConfig {
|
|
74
|
+
/** How URLs are written once `start()` is called; defaults to `'history'` */
|
|
68
75
|
mode?: 'history' | 'hash';
|
|
76
|
+
/** Path prefix of the app in history mode, e.g. `'/app'` */
|
|
69
77
|
base?: string;
|
|
70
78
|
prefetch?: {
|
|
71
79
|
enabled?: boolean;
|
|
@@ -121,23 +129,38 @@ export interface RouterStats {
|
|
|
121
129
|
|
|
122
130
|
/** Router instance */
|
|
123
131
|
export interface Router {
|
|
124
|
-
/**
|
|
132
|
+
/**
|
|
133
|
+
* Add a route. `path` may contain `:param` segments and end in `/*`;
|
|
134
|
+
* exact paths win over patterns, patterns match in registration order.
|
|
135
|
+
*/
|
|
125
136
|
addRoute(path: string, config: RouteConfig): void;
|
|
126
|
-
/**
|
|
137
|
+
/**
|
|
138
|
+
* Navigate to a path (with optional `?query` and `#hash`), adding a history
|
|
139
|
+
* entry. Resolves `false` when no route matches, a guard cancels, loading
|
|
140
|
+
* fails, or a later navigation superseded this one.
|
|
141
|
+
*/
|
|
127
142
|
push(path: string, options?: Partial<Route>): Promise<boolean>;
|
|
128
|
-
/**
|
|
143
|
+
/** Like `push()`, replacing the current history entry */
|
|
129
144
|
replace(path: string, options?: Partial<Route>): Promise<boolean>;
|
|
130
|
-
/** Go back in history */
|
|
145
|
+
/** Go back in history (the browser's after `start()`, the router's before) */
|
|
131
146
|
back(): void;
|
|
132
147
|
/** Go forward in history */
|
|
133
148
|
forward(): void;
|
|
149
|
+
/**
|
|
150
|
+
* Follow the browser: navigate to the current location, handle back/forward
|
|
151
|
+
* (popstate, or hashchange in hash mode) and, unless `interceptLinks` is
|
|
152
|
+
* `false`, clicks on same-origin links to registered routes.
|
|
153
|
+
*/
|
|
154
|
+
start(options?: { interceptLinks?: boolean }): Promise<boolean>;
|
|
155
|
+
/** Detach the listeners added by `start()` */
|
|
156
|
+
stop(): void;
|
|
134
157
|
/** Prefetch a single route */
|
|
135
158
|
prefetchRoute(path: string, priority?: number): Promise<void>;
|
|
136
159
|
/** Prefetch multiple routes */
|
|
137
160
|
prefetchRoutes(paths: string[], priority?: number): void;
|
|
138
161
|
/** Setup prefetch strategy for an element */
|
|
139
162
|
setupPrefetchStrategy(element: HTMLElement, path: string): void;
|
|
140
|
-
/** Get route configuration
|
|
163
|
+
/** Get the route configuration registered for, or matching, a path */
|
|
141
164
|
getRoute(path: string): RouteConfig | undefined;
|
|
142
165
|
/** Get all registered routes */
|
|
143
166
|
getRoutes(): RouteConfig[];
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/events/registry.js", "../src/events/wrapper.js", "../src/events/delegation.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * Handler Registry for Coherent.js Event Delegation\n *\n * Maps handler IDs to their corresponding functions and component context.\n * Handlers are identified by ID (from data-coherent-{event} attributes) rather\n * than by element reference, allowing them to survive DOM updates.\n */\n\n/**\n * HandlerRegistry class\n * Stores handler functions with their associated component context\n */\nexport class HandlerRegistry {\n constructor() {\n /** @type {Map<string, {handler: Function, componentRef: object|null}>} */\n this.handlers = new Map();\n }\n\n /**\n * Register a handler with optional component context\n * @param {string} handlerId - Unique identifier for the handler\n * @param {Function} handler - The event handler function\n * @param {object|null} componentRef - Optional component reference with state/setState\n */\n register(handlerId, handler, componentRef = null) {\n if (typeof handler !== 'function') {\n throw new Error(`Handler must be a function, received: ${typeof handler}`);\n }\n this.handlers.set(handlerId, { handler, componentRef });\n }\n\n /**\n * Unregister a handler by ID\n * @param {string} handlerId - The handler ID to remove\n * @returns {boolean} True if handler was removed, false if not found\n */\n unregister(handlerId) {\n return this.handlers.delete(handlerId);\n }\n\n /**\n * Get a handler entry by ID\n * @param {string} handlerId - The handler ID to look up\n * @returns {{handler: Function, componentRef: object|null}|undefined} Handler entry or undefined\n */\n get(handlerId) {\n return this.handlers.get(handlerId);\n }\n\n /**\n * Check if a handler is registered\n * @param {string} handlerId - The handler ID to check\n * @returns {boolean} True if handler exists\n */\n has(handlerId) {\n return this.handlers.has(handlerId);\n }\n\n /**\n * Clear all registered handlers\n */\n clear() {\n this.handlers.clear();\n }\n\n /**\n * Get all handler IDs registered for a specific component\n * @param {object} componentRef - The component reference to search for\n * @returns {string[]} Array of handler IDs belonging to this component\n */\n getByComponent(componentRef) {\n if (!componentRef) {\n return [];\n }\n\n const handlerIds = [];\n for (const [handlerId, entry] of this.handlers) {\n if (entry.componentRef === componentRef) {\n handlerIds.push(handlerId);\n }\n }\n return handlerIds;\n }\n\n /**\n * Get the number of registered handlers\n * @returns {number} Count of registered handlers\n */\n get size() {\n return this.handlers.size;\n }\n}\n\n/**\n * Singleton handler registry instance\n * Use this for global event delegation\n */\nexport const handlerRegistry = new HandlerRegistry();\n", "/**\n * Event Wrapper for Coherent.js\n *\n * Wraps native DOM events with component context, providing handlers\n * access to component state, setState, and props.\n */\n\n/**\n * @typedef {object} CoherentEvent\n * @property {Event} originalEvent - The native DOM event\n * @property {Element} target - The element with the data-coherent-* attribute\n * @property {function(): void} preventDefault - Delegates to originalEvent.preventDefault()\n * @property {function(): void} stopPropagation - Delegates to originalEvent.stopPropagation()\n * @property {function|null} component - The component function (if available)\n * @property {object|null} state - Current component state (if available)\n * @property {function|null} setState - State setter function (if available)\n * @property {object|null} props - Component props (if available)\n */\n\n/**\n * Wrap a native DOM event with component context\n *\n * @param {Event} originalEvent - The native DOM event\n * @param {Element} target - The element that matched the data attribute selector\n * @param {object|null} componentRef - Optional component reference object\n * @param {function} [componentRef.component] - The component function\n * @param {object} [componentRef.state] - Current component state\n * @param {function} [componentRef.setState] - State setter function\n * @param {object} [componentRef.props] - Component props\n * @returns {CoherentEvent} Wrapped event with component context\n */\nexport function wrapEvent(originalEvent, target, componentRef = null) {\n return {\n // Native event access\n originalEvent,\n target,\n\n // Delegate common methods\n preventDefault() {\n originalEvent.preventDefault();\n },\n\n stopPropagation() {\n originalEvent.stopPropagation();\n },\n\n // Component context (null if no componentRef provided)\n component: componentRef?.component ?? null,\n state: componentRef?.state ?? null,\n setState: componentRef?.setState ?? null,\n props: componentRef?.props ?? null,\n };\n}\n", "/**\n * Event Delegation for Coherent.js\n *\n * Document-level event delegation that routes events to handlers via\n * data-coherent-{eventType} attributes. This ensures event handlers\n * survive DOM updates since they're registered by ID, not by element.\n */\n\nimport { handlerRegistry as defaultRegistry } from './registry.js';\nimport { wrapEvent } from './wrapper.js';\n\n/**\n * EventDelegation class\n * Manages document-level event listeners and routes to registered handlers\n */\nexport class EventDelegation {\n /**\n * @param {import('./registry.js').HandlerRegistry} [registry] - Handler registry instance\n */\n constructor(registry = defaultRegistry) {\n this.registry = registry;\n this.initialized = false;\n this.root = null;\n this.boundHandlers = new Map();\n\n /**\n * Event types to delegate\n * Focus/blur use capture phase because they don't bubble\n */\n this.eventTypes = [\n 'click',\n 'change',\n 'input',\n 'submit',\n 'focus',\n 'blur',\n 'keydown',\n 'keyup',\n 'keypress',\n ];\n }\n\n /**\n * Initialize event delegation by attaching listeners to the root element\n * @param {Document|Element} [root=document] - Root element for event delegation\n */\n initialize(root = typeof document !== 'undefined' ? document : null) {\n if (this.initialized) {\n return;\n }\n\n if (!root) {\n // No DOM available (SSR context)\n return;\n }\n\n this.root = root;\n\n for (const eventType of this.eventTypes) {\n const handler = (event) => this.handleEvent(event, eventType);\n\n // Focus and blur don't bubble - must use capture phase\n const useCapture = eventType === 'focus' || eventType === 'blur';\n\n // Submit needs preventDefault capability, others can be passive\n const options = {\n capture: useCapture,\n passive: eventType !== 'submit',\n };\n\n root.addEventListener(eventType, handler, options);\n this.boundHandlers.set(eventType, { handler, options });\n }\n\n this.initialized = true;\n }\n\n /**\n * Handle a delegated event\n * @param {Event} event - The DOM event\n * @param {string} eventType - The type of event (click, change, etc.)\n */\n handleEvent(event, eventType) {\n const target = event.target;\n if (!target || typeof target.closest !== 'function') {\n return;\n }\n\n // Find the nearest element with the appropriate data attribute\n const attrName = `data-coherent-${eventType}`;\n const delegateTarget = target.closest(`[${attrName}]`);\n\n if (!delegateTarget) {\n return;\n }\n\n // Get the handler ID from the attribute\n const handlerId = delegateTarget.getAttribute(attrName);\n if (!handlerId) {\n return;\n }\n\n // Look up the handler in the registry\n const entry = this.registry.get(handlerId);\n if (!entry) {\n return;\n }\n\n // Wrap the event with component context and call the handler\n const wrappedEvent = wrapEvent(event, delegateTarget, entry.componentRef);\n entry.handler(wrappedEvent);\n }\n\n /**\n * Destroy the event delegation system\n * Removes all listeners and clears the registry\n */\n destroy() {\n if (!this.initialized || !this.root) {\n return;\n }\n\n // Remove all event listeners\n for (const [eventType, { handler, options }] of this.boundHandlers) {\n this.root.removeEventListener(eventType, handler, options);\n }\n\n this.boundHandlers.clear();\n this.registry.clear();\n this.initialized = false;\n this.root = null;\n }\n\n /**\n * Check if the delegation system is initialized\n * @returns {boolean} True if initialized\n */\n isInitialized() {\n return this.initialized;\n }\n}\n\n/**\n * Singleton event delegation instance\n * Use this for global event delegation\n */\nexport const eventDelegation = new EventDelegation();\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|