Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@tanstack/start-client-core

Package Overview
Dependencies
Maintainers
5
Versions
383
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tanstack/start-client-core - npm Package Compare versions

Comparing version
1.169.4
to
1.170.0
+18
dist/esm/hydration.d.ts
export { condition } from './hydration/condition.js';
export type { HydrationCondition } from './hydration/condition.js';
export { hydrateIdAttribute, hydrateInteractionEventsAttribute, hydrateWhenAttribute, } from './hydration/constants.js';
export declare const hydrateIdSelector = "[data-ts-hydrate-id]";
export { idle } from './hydration/idle.js';
export type { IdleHydrationOptions } from './hydration/idle.js';
export { interaction } from './hydration/interaction.js';
export { load } from './hydration/load.js';
export { media } from './hydration/media.js';
export { never } from './hydration/never.js';
export { clearResolvedGateIdsInMarker, createResolvedGate, getFallbackHtml, getMarkerGate, getOrCreateGate, onGateResolve, releaseGate, resolveHydrationMarker, runHydrationStrategyCleanup, saveFallbackHtml, waitForHydrationPrefetchStrategy, } from './hydration/runtime.js';
export { withHydrationRenderer } from './hydration/renderer.js';
export { visible } from './hydration/visible.js';
export { listenForDelegatedHydrationIntent } from './hydration/interaction.js';
export type { VisibleHydrationOptions } from './hydration/visible.js';
export type { HydrationGateRecord } from './hydration/runtime.js';
export type { HydrationStrategyWithRenderer } from './hydration/renderer.js';
export type { HydrationInteractionEvent, HydrationInteractionEvents, HydrationMarkerAttributes, HydrationPrefetchContext, HydrationPrefetchFunction, HydrationPrefetchWhen, HydrationPrefetchStrategy, HydrationPrefetchWaitReason, HydrationRuntimeContext, HydrationRuntimeGate, HydrationStrategy, HydrationStrategyTypes, HydrationWhen, } from './hydration/types.js';
import { hydrateIdAttribute, hydrateInteractionEventsAttribute, hydrateWhenAttribute } from "./hydration/constants.js";
import { condition } from "./hydration/condition.js";
import { idle } from "./hydration/idle.js";
import { clearResolvedGateIdsInMarker, createResolvedGate, getFallbackHtml, getMarkerGate, getOrCreateGate, onGateResolve, releaseGate, resolveHydrationMarker, runHydrationStrategyCleanup, saveFallbackHtml, waitForHydrationPrefetchStrategy } from "./hydration/runtime.js";
import { interaction, listenForDelegatedHydrationIntent } from "./hydration/interaction.js";
import { load } from "./hydration/load.js";
import { media } from "./hydration/media.js";
import { never } from "./hydration/never.js";
import { withHydrationRenderer } from "./hydration/renderer.js";
import { visible } from "./hydration/visible.js";
//#region src/hydration.ts
var hydrateIdSelector = `[${hydrateIdAttribute}]`;
//#endregion
export { clearResolvedGateIdsInMarker, condition, createResolvedGate, getFallbackHtml, getMarkerGate, getOrCreateGate, hydrateIdAttribute, hydrateIdSelector, hydrateInteractionEventsAttribute, hydrateWhenAttribute, idle, interaction, listenForDelegatedHydrationIntent, load, media, never, onGateResolve, releaseGate, resolveHydrationMarker, runHydrationStrategyCleanup, saveFallbackHtml, visible, waitForHydrationPrefetchStrategy, withHydrationRenderer };
//# sourceMappingURL=hydration.js.map
{"version":3,"file":"hydration.js","names":[],"sources":["../../src/hydration.ts"],"sourcesContent":["import { hydrateIdAttribute } from './hydration/constants'\n\nexport { condition } from './hydration/condition'\nexport type { HydrationCondition } from './hydration/condition'\nexport {\n hydrateIdAttribute,\n hydrateInteractionEventsAttribute,\n hydrateWhenAttribute,\n} from './hydration/constants'\nexport const hydrateIdSelector = `[${hydrateIdAttribute}]`\nexport { idle } from './hydration/idle'\nexport type { IdleHydrationOptions } from './hydration/idle'\nexport { interaction } from './hydration/interaction'\nexport { load } from './hydration/load'\nexport { media } from './hydration/media'\nexport { never } from './hydration/never'\nexport {\n clearResolvedGateIdsInMarker,\n createResolvedGate,\n getFallbackHtml,\n getMarkerGate,\n getOrCreateGate,\n onGateResolve,\n releaseGate,\n resolveHydrationMarker,\n runHydrationStrategyCleanup,\n saveFallbackHtml,\n waitForHydrationPrefetchStrategy,\n} from './hydration/runtime'\nexport { withHydrationRenderer } from './hydration/renderer'\nexport { visible } from './hydration/visible'\nexport { listenForDelegatedHydrationIntent } from './hydration/interaction'\nexport type { VisibleHydrationOptions } from './hydration/visible'\nexport type { HydrationGateRecord } from './hydration/runtime'\nexport type { HydrationStrategyWithRenderer } from './hydration/renderer'\nexport type {\n HydrationInteractionEvent,\n HydrationInteractionEvents,\n HydrationMarkerAttributes,\n HydrationPrefetchContext,\n HydrationPrefetchFunction,\n HydrationPrefetchWhen,\n HydrationPrefetchStrategy,\n HydrationPrefetchWaitReason,\n HydrationRuntimeContext,\n HydrationRuntimeGate,\n HydrationStrategy,\n HydrationStrategyTypes,\n HydrationWhen,\n} from './hydration/types'\n"],"mappings":";;;;;;;;;;;AASA,IAAa,oBAAoB,IAAI,mBAAmB"}
import { HydrationStrategy } from './types.js';
declare const conditionType = "condition";
export type HydrationCondition = boolean | (() => boolean);
export declare function condition(condition: HydrationCondition): HydrationStrategy<typeof conditionType, false>;
export {};
//#region src/hydration/condition.ts
var conditionType = "condition";
/* @__NO_SIDE_EFFECTS__ */
function condition(condition) {
return {
_t: conditionType,
_d: () => !(typeof condition === "function" ? condition() : condition),
_s: ({ gate }) => {
if (typeof condition === "function" ? condition() : condition) gate.resolve();
}
};
}
//#endregion
export { condition };
//# sourceMappingURL=condition.js.map
{"version":3,"file":"condition.js","names":[],"sources":["../../../src/hydration/condition.ts"],"sourcesContent":["import type { HydrationStrategy } from './types'\n\nconst conditionType = 'condition'\n\nexport type HydrationCondition = boolean | (() => boolean)\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function condition(\n condition: HydrationCondition,\n): HydrationStrategy<typeof conditionType, false> {\n return {\n _t: conditionType,\n _d: () => !(typeof condition === 'function' ? condition() : condition),\n _s: ({ gate }) => {\n if (typeof condition === 'function' ? condition() : condition) {\n gate!.resolve()\n }\n },\n }\n}\n"],"mappings":";AAEA,IAAM,gBAAgB;;AAKtB,SAAgB,UACd,WACgD;AAChD,QAAO;EACL,IAAI;EACJ,UAAU,EAAE,OAAO,cAAc,aAAa,WAAW,GAAG;EAC5D,KAAK,EAAE,WAAW;AAChB,OAAI,OAAO,cAAc,aAAa,WAAW,GAAG,UAClD,MAAM,SAAS;;EAGpB"}
export declare const hydrateIdAttribute = "data-ts-hydrate-id";
export declare const hydrateWhenAttribute = "data-ts-hydrate-when";
export declare const hydrateInteractionEventsAttribute = "data-ts-hydrate-interaction-events";
//#region src/hydration/constants.ts
var hydrateIdAttribute = "data-ts-hydrate-id";
var hydrateWhenAttribute = "data-ts-hydrate-when";
var hydrateInteractionEventsAttribute = "data-ts-hydrate-interaction-events";
//#endregion
export { hydrateIdAttribute, hydrateInteractionEventsAttribute, hydrateWhenAttribute };
//# sourceMappingURL=constants.js.map
{"version":3,"file":"constants.js","names":[],"sources":["../../../src/hydration/constants.ts"],"sourcesContent":["export const hydrateIdAttribute = 'data-ts-hydrate-id'\nexport const hydrateWhenAttribute = 'data-ts-hydrate-when'\nexport const hydrateInteractionEventsAttribute =\n 'data-ts-hydrate-interaction-events'\n"],"mappings":";AAAA,IAAa,qBAAqB;AAClC,IAAa,uBAAuB;AACpC,IAAa,oCACX"}
import { HydrationPrefetchStrategy } from './types.js';
declare const idleType = "idle";
export type IdleHydrationOptions = {
timeout?: number;
};
export declare function idle(options?: IdleHydrationOptions): HydrationPrefetchStrategy<typeof idleType>;
export {};
//#region src/hydration/idle.ts
var idleType = "idle";
function idle(options = {}) {
const timeout = options.timeout ?? 2e3;
return {
_t: idleType,
_s: ({ gate, prefetch }) => {
const schedule = globalThis;
const callback = prefetch ?? gate.resolve;
if (schedule.requestIdleCallback) {
const handle = schedule.requestIdleCallback(callback, { timeout });
return () => schedule.cancelIdleCallback?.(handle);
}
const timeoutId = globalThis.setTimeout(callback, timeout);
return () => globalThis.clearTimeout(timeoutId);
}
};
}
//#endregion
export { idle };
//# sourceMappingURL=idle.js.map
{"version":3,"file":"idle.js","names":[],"sources":["../../../src/hydration/idle.ts"],"sourcesContent":["import type { HydrationPrefetchStrategy } from './types'\n\nconst idleType = 'idle'\n\nexport type IdleHydrationOptions = {\n timeout?: number\n}\n\nexport function idle(\n options: IdleHydrationOptions = {},\n): HydrationPrefetchStrategy<typeof idleType> {\n const timeout = options.timeout ?? 2000\n\n return {\n _t: idleType,\n _s: ({ gate, prefetch }) => {\n const schedule = globalThis as unknown as {\n requestIdleCallback?: (\n callback: IdleRequestCallback,\n options?: IdleRequestOptions,\n ) => number\n cancelIdleCallback?: (handle: number) => void\n }\n const callback = prefetch ?? gate!.resolve\n\n if (schedule.requestIdleCallback) {\n const handle = schedule.requestIdleCallback(callback, { timeout })\n return () => schedule.cancelIdleCallback?.(handle)\n }\n\n const timeoutId = globalThis.setTimeout(callback, timeout)\n return () => globalThis.clearTimeout(timeoutId)\n },\n }\n}\n"],"mappings":";AAEA,IAAM,WAAW;AAMjB,SAAgB,KACd,UAAgC,EAAE,EACU;CAC5C,MAAM,UAAU,QAAQ,WAAW;AAEnC,QAAO;EACL,IAAI;EACJ,KAAK,EAAE,MAAM,eAAe;GAC1B,MAAM,WAAW;GAOjB,MAAM,WAAW,YAAY,KAAM;AAEnC,OAAI,SAAS,qBAAqB;IAChC,MAAM,SAAS,SAAS,oBAAoB,UAAU,EAAE,SAAS,CAAC;AAClE,iBAAa,SAAS,qBAAqB,OAAO;;GAGpD,MAAM,YAAY,WAAW,WAAW,UAAU,QAAQ;AAC1D,gBAAa,WAAW,aAAa,UAAU;;EAElD"}
import { HydrationInteractionEvents, HydrationPrefetchStrategy, HydrationRuntimeContext } from './types.js';
export type InteractionHydrationOptions = {
events?: HydrationInteractionEvents;
};
declare const interactionType = "interaction";
export declare function listenForDelegatedHydrationIntent(element: Element, context: HydrationRuntimeContext): (() => void) | undefined;
export declare function interaction(options?: InteractionHydrationOptions): HydrationPrefetchStrategy<typeof interactionType>;
export {};
import { hydrateIdAttribute, hydrateInteractionEventsAttribute, hydrateWhenAttribute } from "./constants.js";
import { clearResolvedGateIdsInMarker, getMarkerGate, resolveHydrationMarker } from "./runtime.js";
//#region src/hydration/interaction.ts
var hydrateIdSelector = `[${hydrateIdAttribute}]`;
var defaultInteractionEvents = [
"pointerenter",
"focusin",
"pointerdown",
"click"
];
var supportedInteractionEvents = [
"auxclick",
"click",
"contextmenu",
"dblclick",
"focusin",
"keydown",
"keyup",
"mousedown",
"mouseenter",
"mouseover",
"mouseup",
"pointerdown",
"pointerenter",
"pointerover",
"pointerup"
];
var interactionType = "interaction";
var dynamicType = "dynamic";
var delegatedHydrateSelector = `${`[${hydrateWhenAttribute}="${interactionType}"]`},[${hydrateWhenAttribute}="${dynamicType}"]`;
var replayEventsByGateId = /* @__PURE__ */ new Map();
function getIntentListenerEvents(marker, events) {
const listenerEvents = new Set(events);
marker.querySelectorAll(delegatedHydrateSelector).forEach((childMarker) => {
if (childMarker.getAttribute("data-ts-hydrate-when") === dynamicType) {
supportedInteractionEvents.forEach((eventName) => {
listenerEvents.add(eventName);
});
return;
}
const attr = childMarker.getAttribute(hydrateInteractionEventsAttribute);
for (const eventName of attr === null ? defaultInteractionEvents : attr.split(/\s+/).filter(Boolean)) listenerEvents.add(eventName);
});
return [...listenerEvents];
}
function queueHydrationReplayEvent(marker, event) {
if (!event.bubbles) return;
const id = marker.getAttribute(hydrateIdAttribute);
const when = marker.getAttribute(hydrateWhenAttribute);
if (!id || !when || when === "never") return;
const target = event.target;
if (!target) return;
if (getMarkerGate(marker)?.resolved) return;
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
let targetPath = [];
if (target instanceof Node && marker.contains(target)) {
let node = target instanceof Element ? target : target.parentElement;
while (node && node !== marker) {
const parent = node.parentElement;
if (!parent) {
targetPath = [];
break;
}
targetPath.push(Array.prototype.indexOf.call(parent.children, node));
node = parent;
}
targetPath.reverse();
}
const pendingEvents = replayEventsByGateId.get(id) ?? [];
pendingEvents.push({
marker,
targetPath,
type: event.type,
event
});
replayEventsByGateId.set(id, pendingEvents);
}
if (typeof document !== "undefined") {
const onIntent = (event) => {
const target = event.target;
if (!(target instanceof Element)) return;
let marker = target.closest(hydrateIdSelector);
const markers = [];
let shouldHandle = false;
while (marker) {
markers.push(marker);
const when = marker.getAttribute(hydrateWhenAttribute);
if (when === dynamicType) shouldHandle ||= event.type === "click";
else if (when === interactionType) {
const attr = marker.getAttribute(hydrateInteractionEventsAttribute);
const events = attr === null ? defaultInteractionEvents : attr.split(/\s+/).filter(Boolean);
shouldHandle ||= events.includes(event.type);
}
marker = marker.parentElement?.closest(hydrateIdSelector) ?? null;
}
if (!shouldHandle) return;
markers.reverse();
if (markers.every((marker) => getMarkerGate(marker))) return;
markers.forEach((marker) => {
queueHydrationReplayEvent(marker, event);
resolveHydrationMarker(marker);
});
};
supportedInteractionEvents.forEach((eventName) => {
document.addEventListener(eventName, onIntent, true);
});
}
function listenForIntent(element, events, context) {
const onIntent = (event) => {
const target = event.target;
let marker;
if (target instanceof Element) {
const closestMarker = target.closest(hydrateIdSelector);
marker = closestMarker && element.contains(closestMarker) ? closestMarker : element;
} else marker = element;
const markers = [];
while (marker) {
if (marker.hasAttribute("data-ts-hydrate-id")) markers.push(marker);
if (marker === element) break;
marker = marker.parentElement;
}
if (!markers.includes(element)) markers.push(element);
markers.reverse();
if (context.delegated && !markers.some((marker) => marker.getAttribute("data-ts-hydrate-when") === interactionType || marker.getAttribute("data-ts-hydrate-when") === dynamicType)) return;
markers.forEach((marker) => {
queueHydrationReplayEvent(marker, event);
resolveHydrationMarker(marker);
});
};
let disposed = false;
events.forEach((eventName) => {
element.addEventListener(eventName, onIntent, true);
});
return () => {
if (disposed) return;
disposed = true;
events.forEach((eventName) => {
element.removeEventListener(eventName, onIntent, true);
});
};
}
function listenForDelegatedHydrationIntent(element, context) {
const listenerEvents = getIntentListenerEvents(element, []);
if (!listenerEvents.length) return;
const cleanupIntent = listenForIntent(element, listenerEvents, {
...context,
delegated: true
});
return () => {
cleanupIntent();
clearResolvedGateIdsInMarker(element);
};
}
/* @__NO_SIDE_EFFECTS__ */
function interaction(options = {}) {
let events = defaultInteractionEvents;
if (options.events !== void 0) {
const eventList = typeof options.events === "string" ? [options.events] : options.events;
const normalizedEvents = [];
const seen = /* @__PURE__ */ new Set();
for (const eventName of eventList) {
if (!eventName || seen.has(eventName)) continue;
seen.add(eventName);
normalizedEvents.push(eventName);
}
events = normalizedEvents;
}
const eventKey = events.join(" ");
return {
_t: interactionType,
_s: (context) => {
const element = context.element;
if (!element) return;
const prefetch = context.prefetch;
if (prefetch) {
if (!events.length) return;
let disposed = false;
events.forEach((eventName) => {
element.addEventListener(eventName, prefetch, true);
});
return () => {
if (disposed) return;
disposed = true;
events.forEach((eventName) => {
element.removeEventListener(eventName, prefetch, true);
});
};
}
const listenerEvents = getIntentListenerEvents(element, events);
const cleanupIntent = listenerEvents.length ? listenForIntent(element, listenerEvents, context) : void 0;
return () => {
cleanupIntent?.();
clearResolvedGateIdsInMarker(element);
};
},
_o: (id) => {
globalThis.requestAnimationFrame(() => {
const pendingEvents = replayEventsByGateId.get(id);
if (!pendingEvents?.length) return;
replayEventsByGateId.delete(id);
for (const pendingEvent of pendingEvents) {
let replayTarget = pendingEvent.marker;
for (const index of pendingEvent.targetPath) {
replayTarget = replayTarget.children[index] ?? null;
if (!replayTarget) break;
}
const event = pendingEvent.event;
replayTarget ??= pendingEvent.marker;
replayTarget.dispatchEvent(event instanceof MouseEvent ? new MouseEvent(event.type, event) : event instanceof FocusEvent ? new FocusEvent(event.type, event) : new Event(event.type, event));
}
});
},
_a: () => options.events === void 0 ? void 0 : { [hydrateInteractionEventsAttribute]: eventKey }
};
}
//#endregion
export { interaction, listenForDelegatedHydrationIntent };
//# sourceMappingURL=interaction.js.map
{"version":3,"file":"interaction.js","names":[],"sources":["../../../src/hydration/interaction.ts"],"sourcesContent":["import {\n hydrateIdAttribute,\n hydrateInteractionEventsAttribute,\n hydrateWhenAttribute,\n} from './constants'\nimport {\n clearResolvedGateIdsInMarker,\n getMarkerGate,\n resolveHydrationMarker,\n} from './runtime'\nimport type {\n HydrationInteractionEvents,\n HydrationPrefetchStrategy,\n HydrationRuntimeContext,\n} from './types'\n\nexport type InteractionHydrationOptions = {\n events?: HydrationInteractionEvents\n}\n\nconst hydrateIdSelector = `[${hydrateIdAttribute}]`\n\ntype PendingReplayEvent = {\n marker: Element\n targetPath: Array<number>\n type: string\n event: Event\n}\n\nconst defaultInteractionEvents = [\n 'pointerenter',\n 'focusin',\n 'pointerdown',\n 'click',\n] as const\nconst supportedInteractionEvents = [\n 'auxclick',\n 'click',\n 'contextmenu',\n 'dblclick',\n 'focusin',\n 'keydown',\n 'keyup',\n 'mousedown',\n 'mouseenter',\n 'mouseover',\n 'mouseup',\n 'pointerdown',\n 'pointerenter',\n 'pointerover',\n 'pointerup',\n] as const\nconst interactionType = 'interaction'\nconst dynamicType = 'dynamic'\nconst interactionHydrateSelector = `[${hydrateWhenAttribute}=\"${interactionType}\"]`\nconst delegatedHydrateSelector = `${interactionHydrateSelector},[${hydrateWhenAttribute}=\"${dynamicType}\"]`\nconst replayEventsByGateId = /* @__PURE__ */ new Map<\n string,\n Array<PendingReplayEvent>\n>()\n\nfunction getIntentListenerEvents(\n marker: Element,\n events: ReadonlyArray<string>,\n) {\n const listenerEvents = new Set(events)\n\n marker.querySelectorAll(delegatedHydrateSelector).forEach((childMarker) => {\n if (childMarker.getAttribute(hydrateWhenAttribute) === dynamicType) {\n supportedInteractionEvents.forEach((eventName) => {\n listenerEvents.add(eventName)\n })\n return\n }\n\n const attr = childMarker.getAttribute(hydrateInteractionEventsAttribute)\n for (const eventName of attr === null\n ? defaultInteractionEvents\n : attr.split(/\\s+/).filter(Boolean)) {\n listenerEvents.add(eventName)\n }\n })\n\n return [...listenerEvents]\n}\n\nfunction queueHydrationReplayEvent(marker: Element, event: Event) {\n if (!event.bubbles) return\n\n const id = marker.getAttribute(hydrateIdAttribute)\n const when = marker.getAttribute(hydrateWhenAttribute)\n if (!id || !when || when === 'never') return\n\n const target = event.target\n if (!target) return\n\n const gate = getMarkerGate(marker)\n if (gate?.resolved) return\n\n event.preventDefault()\n event.stopPropagation()\n event.stopImmediatePropagation()\n\n let targetPath: Array<number> = []\n if (target instanceof Node && marker.contains(target)) {\n let node: Element | null =\n target instanceof Element ? target : target.parentElement\n\n while (node && node !== marker) {\n const parent = node.parentElement\n if (!parent) {\n targetPath = []\n break\n }\n targetPath.push(Array.prototype.indexOf.call(parent.children, node))\n node = parent\n }\n targetPath.reverse()\n }\n\n const pendingEvents = replayEventsByGateId.get(id) ?? []\n pendingEvents.push({\n marker,\n targetPath,\n type: event.type,\n event,\n })\n replayEventsByGateId.set(id, pendingEvents)\n}\n\nif (typeof document !== 'undefined') {\n const onIntent = (event: Event) => {\n const target = event.target\n if (!(target instanceof Element)) return\n\n let marker: Element | null = target.closest(hydrateIdSelector)\n const markers: Array<Element> = []\n let shouldHandle = false\n\n while (marker) {\n markers.push(marker)\n\n const when = marker.getAttribute(hydrateWhenAttribute)\n if (when === dynamicType) {\n shouldHandle ||= event.type === 'click'\n } else if (when === interactionType) {\n const attr = marker.getAttribute(hydrateInteractionEventsAttribute)\n const events: ReadonlyArray<string> =\n attr === null\n ? defaultInteractionEvents\n : attr.split(/\\s+/).filter(Boolean)\n shouldHandle ||= events.includes(event.type)\n }\n\n marker = marker.parentElement?.closest(hydrateIdSelector) ?? null\n }\n\n if (!shouldHandle) return\n\n markers.reverse()\n if (markers.every((marker) => getMarkerGate(marker))) return\n\n markers.forEach((marker) => {\n queueHydrationReplayEvent(marker, event)\n resolveHydrationMarker(marker)\n })\n }\n\n supportedInteractionEvents.forEach((eventName) => {\n document.addEventListener(eventName, onIntent, true)\n })\n}\n\nfunction listenForIntent(\n element: Element,\n events: ReadonlyArray<string>,\n context: HydrationRuntimeContext,\n) {\n const onIntent = (event: Event) => {\n const target = event.target\n let marker: Element | null\n if (target instanceof Element) {\n const closestMarker = target.closest(hydrateIdSelector)\n marker =\n closestMarker && element.contains(closestMarker)\n ? closestMarker\n : element\n } else {\n marker = element\n }\n\n const markers: Array<Element> = []\n while (marker) {\n if (marker.hasAttribute(hydrateIdAttribute)) {\n markers.push(marker)\n }\n if (marker === element) break\n marker = marker.parentElement\n }\n\n if (!markers.includes(element)) {\n markers.push(element)\n }\n\n markers.reverse()\n\n if (\n context.delegated &&\n !markers.some(\n (marker) =>\n marker.getAttribute(hydrateWhenAttribute) === interactionType ||\n marker.getAttribute(hydrateWhenAttribute) === dynamicType,\n )\n ) {\n return\n }\n\n markers.forEach((marker) => {\n queueHydrationReplayEvent(marker, event)\n resolveHydrationMarker(marker)\n })\n }\n let disposed = false\n\n events.forEach((eventName) => {\n element.addEventListener(eventName, onIntent, true)\n })\n\n return () => {\n if (disposed) return\n disposed = true\n events.forEach((eventName) => {\n element.removeEventListener(eventName, onIntent, true)\n })\n }\n}\n\nexport function listenForDelegatedHydrationIntent(\n element: Element,\n context: HydrationRuntimeContext,\n) {\n const listenerEvents = getIntentListenerEvents(element, [])\n if (!listenerEvents.length) return\n\n const cleanupIntent = listenForIntent(element, listenerEvents, {\n ...context,\n delegated: true,\n })\n return () => {\n cleanupIntent()\n clearResolvedGateIdsInMarker(element)\n }\n}\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function interaction(\n options: InteractionHydrationOptions = {},\n): HydrationPrefetchStrategy<typeof interactionType> {\n let events: ReadonlyArray<string> = defaultInteractionEvents\n if (options.events !== undefined) {\n const eventList: ReadonlyArray<string> =\n typeof options.events === 'string' ? [options.events] : options.events\n const normalizedEvents: Array<string> = []\n const seen = new Set<string>()\n\n for (const eventName of eventList) {\n if (!eventName || seen.has(eventName)) continue\n seen.add(eventName)\n normalizedEvents.push(eventName)\n }\n\n events = normalizedEvents\n }\n\n const eventKey = events.join(' ')\n\n return {\n _t: interactionType,\n _s: (context) => {\n const element = context.element\n if (!element) return\n const prefetch = context.prefetch\n if (prefetch) {\n if (!events.length) return\n let disposed = false\n\n events.forEach((eventName) => {\n element.addEventListener(eventName, prefetch, true)\n })\n\n return () => {\n if (disposed) return\n disposed = true\n events.forEach((eventName) => {\n element.removeEventListener(eventName, prefetch, true)\n })\n }\n }\n\n const listenerEvents = getIntentListenerEvents(element, events)\n const cleanupIntent = listenerEvents.length\n ? listenForIntent(element, listenerEvents, context)\n : undefined\n return () => {\n cleanupIntent?.()\n clearResolvedGateIdsInMarker(element)\n }\n },\n _o: (id) => {\n globalThis.requestAnimationFrame(() => {\n const pendingEvents = replayEventsByGateId.get(id)\n if (!pendingEvents?.length) return\n\n replayEventsByGateId.delete(id)\n\n for (const pendingEvent of pendingEvents) {\n let replayTarget: Element | null = pendingEvent.marker\n for (const index of pendingEvent.targetPath) {\n replayTarget = replayTarget.children[index] ?? null\n if (!replayTarget) break\n }\n\n const event = pendingEvent.event\n replayTarget ??= pendingEvent.marker\n replayTarget.dispatchEvent(\n event instanceof MouseEvent\n ? new MouseEvent(event.type, event)\n : event instanceof FocusEvent\n ? new FocusEvent(event.type, event)\n : new Event(event.type, event),\n )\n }\n })\n },\n _a: () =>\n options.events === undefined\n ? undefined\n : {\n [hydrateInteractionEventsAttribute]: eventKey,\n },\n }\n}\n"],"mappings":"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"}
import { HydrationPrefetchStrategy } from './types.js';
declare const loadType = "load";
export declare function load(): HydrationPrefetchStrategy<typeof loadType>;
export {};
//#region src/hydration/load.ts
var loadStrategy = {
_t: "load",
_d: () => false,
_s: ({ gate, prefetch }) => {
(prefetch ?? gate.resolve)();
}
};
/* @__NO_SIDE_EFFECTS__ */
function load() {
return loadStrategy;
}
//#endregion
export { load };
//# sourceMappingURL=load.js.map
{"version":3,"file":"load.js","names":[],"sources":["../../../src/hydration/load.ts"],"sourcesContent":["import type { HydrationPrefetchStrategy } from './types'\n\nconst loadType = 'load'\n\nconst loadStrategy: HydrationPrefetchStrategy<typeof loadType> = {\n _t: loadType,\n _d: () => false,\n _s: ({ gate, prefetch }) => {\n ;(prefetch ?? gate!.resolve)()\n },\n}\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function load(): HydrationPrefetchStrategy<typeof loadType> {\n return loadStrategy\n}\n"],"mappings":";AAIA,IAAM,eAA2D;CAC/D,IAHe;CAIf,UAAU;CACV,KAAK,EAAE,MAAM,eAAe;AACzB,GAAC,YAAY,KAAM,UAAU;;CAEjC;;AAGD,SAAgB,OAAmD;AACjE,QAAO"}
import { HydrationPrefetchStrategy } from './types.js';
declare const mediaType = "media";
export declare function media(query: string): HydrationPrefetchStrategy<typeof mediaType>;
export {};
//#region src/hydration/media.ts
var mediaType = "media";
/* @__NO_SIDE_EFFECTS__ */
function media(query) {
return {
_t: mediaType,
_s: ({ gate, prefetch }) => {
if (!query) return;
const callback = prefetch ?? gate.resolve;
const mediaQuery = window.matchMedia(query);
const onChange = () => {
if (mediaQuery.matches) callback();
};
mediaQuery.addEventListener("change", onChange);
onChange();
return () => mediaQuery.removeEventListener("change", onChange);
}
};
}
//#endregion
export { media };
//# sourceMappingURL=media.js.map
{"version":3,"file":"media.js","names":[],"sources":["../../../src/hydration/media.ts"],"sourcesContent":["import type { HydrationPrefetchStrategy } from './types'\n\nconst mediaType = 'media'\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function media(\n query: string,\n): HydrationPrefetchStrategy<typeof mediaType> {\n return {\n _t: mediaType,\n _s: ({ gate, prefetch }) => {\n if (!query) return\n\n const callback = prefetch ?? gate!.resolve\n const mediaQuery = window.matchMedia(query)\n const onChange = () => {\n if (mediaQuery.matches) callback()\n }\n mediaQuery.addEventListener('change', onChange)\n onChange()\n\n return () => mediaQuery.removeEventListener('change', onChange)\n },\n }\n}\n"],"mappings":";AAEA,IAAM,YAAY;;AAGlB,SAAgB,MACd,OAC6C;AAC7C,QAAO;EACL,IAAI;EACJ,KAAK,EAAE,MAAM,eAAe;AAC1B,OAAI,CAAC,MAAO;GAEZ,MAAM,WAAW,YAAY,KAAM;GACnC,MAAM,aAAa,OAAO,WAAW,MAAM;GAC3C,MAAM,iBAAiB;AACrB,QAAI,WAAW,QAAS,WAAU;;AAEpC,cAAW,iBAAiB,UAAU,SAAS;AAC/C,aAAU;AAEV,gBAAa,WAAW,oBAAoB,UAAU,SAAS;;EAElE"}
import { HydrationStrategy } from './types.js';
declare const neverType = "never";
export declare function never(): HydrationStrategy<typeof neverType, false>;
export {};
//#region src/hydration/never.ts
var neverStrategy = {
_t: "never",
_d: () => true
};
/* @__NO_SIDE_EFFECTS__ */
function never() {
return neverStrategy;
}
//#endregion
export { never };
//# sourceMappingURL=never.js.map
{"version":3,"file":"never.js","names":[],"sources":["../../../src/hydration/never.ts"],"sourcesContent":["import type { HydrationStrategy } from './types'\n\nconst neverType = 'never'\n\nconst neverStrategy: HydrationStrategy<typeof neverType, false> = {\n _t: neverType,\n _d: () => true,\n}\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function never(): HydrationStrategy<typeof neverType, false> {\n return neverStrategy\n}\n"],"mappings":";AAIA,IAAM,gBAA4D;CAChE,IAHgB;CAIhB,UAAU;CACX;;AAGD,SAAgB,QAAoD;AAClE,QAAO"}
import { HydrationStrategy } from './types.js';
export type HydrationStrategyWithRenderer<TStrategy extends HydrationStrategy, TRenderer> = TStrategy & {
_h: TRenderer;
};
export declare function withHydrationRenderer<TStrategy extends HydrationStrategy, TRenderer>(strategy: TStrategy, renderer: TRenderer): HydrationStrategyWithRenderer<TStrategy, TRenderer>;
//#region src/hydration/renderer.ts
/* @__NO_SIDE_EFFECTS__ */
function withHydrationRenderer(strategy, renderer) {
return /* @__PURE__ */ Object.assign(strategy, { _h: renderer });
}
//#endregion
export { withHydrationRenderer };
//# sourceMappingURL=renderer.js.map
{"version":3,"file":"renderer.js","names":[],"sources":["../../../src/hydration/renderer.ts"],"sourcesContent":["import type { HydrationStrategy } from './types'\n\nexport type HydrationStrategyWithRenderer<\n TStrategy extends HydrationStrategy,\n TRenderer,\n> = TStrategy & {\n _h: TRenderer\n}\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function withHydrationRenderer<\n TStrategy extends HydrationStrategy,\n TRenderer,\n>(\n strategy: TStrategy,\n renderer: TRenderer,\n): HydrationStrategyWithRenderer<TStrategy, TRenderer> {\n return /* @__PURE__ */ Object.assign(strategy, {\n _h: renderer,\n })\n}\n"],"mappings":";;AAUA,SAAgB,sBAId,UACA,UACqD;AACrD,QAAuB,uBAAO,OAAO,UAAU,EAC7C,IAAI,UACL,CAAC"}
import { HydrationPrefetchStrategy, HydrationPrefetchWaitReason, HydrationRuntimeGate, HydrationWhen } from './types.js';
export type HydrationGateRecord = HydrationRuntimeGate & {
id: string;
when: HydrationWhen;
promise: Promise<void>;
consumers: number;
resolveListeners: Set<() => void>;
};
export declare function createResolvedGate(id: string, when: HydrationWhen): HydrationGateRecord;
export declare function getOrCreateGate(id: string, when: HydrationWhen): HydrationGateRecord;
export declare function releaseGate(gate: HydrationGateRecord): void;
export declare function onGateResolve(gate: HydrationGateRecord, listener: () => void): () => void;
export declare function runHydrationStrategyCleanup(cleanup: void | (() => void)): (() => void) | undefined;
export declare function waitForHydrationPrefetchStrategy(strategy: HydrationPrefetchStrategy, options: {
element: Element | null;
signal: AbortSignal;
onHydrate: (listener: () => void) => () => void;
}): Promise<HydrationPrefetchWaitReason>;
export declare function getMarkerGate(marker: Element): HydrationGateRecord | undefined;
export declare function resolveHydrationMarker(marker: Element): void;
export declare function clearResolvedGateIdsInMarker(marker: Element): void;
export declare function saveFallbackHtml(id: string, element: Element): void;
export declare function getFallbackHtml(id: string): string | undefined;
import { hydrateIdAttribute, hydrateWhenAttribute } from "./constants.js";
//#region src/hydration/runtime.ts
var hydrateIdSelector = `[${hydrateIdAttribute}]`;
var gateRegistry = /* @__PURE__ */ new Map();
var resolvedGateIds = /* @__PURE__ */ new Set();
var fallbackHtmlByGateId = /* @__PURE__ */ new Map();
function createResolvedGate(id, when) {
return {
id,
when,
promise: Promise.resolve(),
resolve: () => {},
resolved: true,
consumers: 0,
resolveListeners: /* @__PURE__ */ new Set()
};
}
function getOrCreateGate(id, when) {
const existing = gateRegistry.get(id);
if (existing?.when === when) {
existing.consumers++;
return existing;
}
let resolvePromise;
const gate = {
id,
promise: new Promise((resolve) => {
resolvePromise = resolve;
}),
resolved: false,
consumers: 1,
when,
resolveListeners: /* @__PURE__ */ new Set(),
resolve: () => {
if (gate.resolved) return;
gate.resolved = true;
resolvePromise();
gate.resolveListeners.forEach((listener) => listener());
gate.resolveListeners.clear();
}
};
gateRegistry.set(id, gate);
if (when !== "never" && resolvedGateIds.has(id)) {
resolvedGateIds.delete(id);
gate.resolve();
}
return gate;
}
function releaseGate(gate) {
resolvedGateIds.delete(gate.id);
gate.consumers--;
if (gate.consumers > 0) return;
if (gateRegistry.get(gate.id) === gate) {
gateRegistry.delete(gate.id);
fallbackHtmlByGateId.delete(gate.id);
gate.resolveListeners.clear();
}
}
function onGateResolve(gate, listener) {
if (gate.resolved) {
listener();
return () => {};
}
gate.resolveListeners.add(listener);
return () => {
gate.resolveListeners.delete(listener);
};
}
function runHydrationStrategyCleanup(cleanup) {
if (typeof cleanup === "function") return cleanup;
}
function waitForHydrationPrefetchStrategy(strategy, options) {
if (options.signal.aborted) return Promise.resolve("abort");
return new Promise((resolve) => {
const state = { disposed: false };
const cleanupStrategyRef = { current: void 0 };
let cleanupHydrate = () => {};
const finish = (reason) => {
if (state.disposed) return;
state.disposed = true;
options.signal.removeEventListener("abort", onAbort);
cleanupHydrate();
runHydrationStrategyCleanup(cleanupStrategyRef.current)?.();
resolve(reason);
};
const onAbort = () => finish("abort");
options.signal.addEventListener("abort", onAbort, { once: true });
cleanupHydrate = options.onHydrate(() => finish("hydrate"));
const cleanupStrategy = strategy._s?.({
element: options.element,
prefetch: () => finish("prefetch")
});
cleanupStrategyRef.current = cleanupStrategy;
if (state.disposed) runHydrationStrategyCleanup(cleanupStrategy)?.();
});
}
function getMarkerGate(marker) {
const id = marker.getAttribute(hydrateIdAttribute);
return id ? gateRegistry.get(id) : void 0;
}
function resolveHydrationMarker(marker) {
const id = marker.getAttribute(hydrateIdAttribute);
const when = marker.getAttribute(hydrateWhenAttribute);
if (!id || !when || when === "never") return;
const gate = gateRegistry.get(id);
if (gate) {
if (gate.when !== "never") gate.resolve();
return;
}
resolvedGateIds.add(id);
}
function clearResolvedGateIdsInMarker(marker) {
const ownId = marker.getAttribute(hydrateIdAttribute);
if (ownId) resolvedGateIds.delete(ownId);
marker.querySelectorAll(hydrateIdSelector).forEach((childMarker) => {
const childId = childMarker.getAttribute(hydrateIdAttribute);
if (childId) resolvedGateIds.delete(childId);
});
}
function saveFallbackHtml(id, element) {
if (!fallbackHtmlByGateId.has(id)) fallbackHtmlByGateId.set(id, element.innerHTML);
}
function getFallbackHtml(id) {
return fallbackHtmlByGateId.get(id);
}
//#endregion
export { clearResolvedGateIdsInMarker, createResolvedGate, getFallbackHtml, getMarkerGate, getOrCreateGate, onGateResolve, releaseGate, resolveHydrationMarker, runHydrationStrategyCleanup, saveFallbackHtml, waitForHydrationPrefetchStrategy };
//# sourceMappingURL=runtime.js.map
{"version":3,"file":"runtime.js","names":[],"sources":["../../../src/hydration/runtime.ts"],"sourcesContent":["import { hydrateIdAttribute, hydrateWhenAttribute } from './constants'\nimport type {\n HydrationPrefetchStrategy,\n HydrationPrefetchWaitReason,\n HydrationRuntimeGate,\n HydrationWhen,\n} from './types'\n\nconst hydrateIdSelector = `[${hydrateIdAttribute}]`\n\nexport type HydrationGateRecord = HydrationRuntimeGate & {\n id: string\n when: HydrationWhen\n promise: Promise<void>\n consumers: number\n resolveListeners: Set<() => void>\n}\n\nconst gateRegistry = /* @__PURE__ */ new Map<string, HydrationGateRecord>()\nconst resolvedGateIds = /* @__PURE__ */ new Set<string>()\nconst fallbackHtmlByGateId = /* @__PURE__ */ new Map<string, string>()\n\nexport function createResolvedGate(\n id: string,\n when: HydrationWhen,\n): HydrationGateRecord {\n return {\n id,\n when,\n promise: Promise.resolve(),\n resolve: () => {},\n resolved: true,\n consumers: 0,\n resolveListeners: new Set<() => void>(),\n }\n}\n\nexport function getOrCreateGate(\n id: string,\n when: HydrationWhen,\n): HydrationGateRecord {\n const existing = gateRegistry.get(id)\n if (existing?.when === when) {\n existing.consumers++\n return existing\n }\n\n let resolvePromise!: () => void\n const promise = new Promise<void>((resolve) => {\n resolvePromise = resolve\n })\n\n const gate: HydrationGateRecord = {\n id,\n promise,\n resolved: false,\n consumers: 1,\n when,\n resolveListeners: new Set(),\n resolve: () => {\n if (gate.resolved) return\n gate.resolved = true\n resolvePromise()\n gate.resolveListeners.forEach((listener) => listener())\n gate.resolveListeners.clear()\n },\n }\n\n gateRegistry.set(id, gate)\n if (when !== 'never' && resolvedGateIds.has(id)) {\n resolvedGateIds.delete(id)\n gate.resolve()\n }\n return gate\n}\n\nexport function releaseGate(gate: HydrationGateRecord) {\n resolvedGateIds.delete(gate.id)\n gate.consumers--\n if (gate.consumers > 0) return\n if (gateRegistry.get(gate.id) === gate) {\n gateRegistry.delete(gate.id)\n fallbackHtmlByGateId.delete(gate.id)\n gate.resolveListeners.clear()\n }\n}\n\nexport function onGateResolve(gate: HydrationGateRecord, listener: () => void) {\n if (gate.resolved) {\n listener()\n return () => {}\n }\n\n gate.resolveListeners.add(listener)\n return () => {\n gate.resolveListeners.delete(listener)\n }\n}\n\nexport function runHydrationStrategyCleanup(cleanup: void | (() => void)) {\n if (typeof cleanup === 'function') return cleanup\n return undefined\n}\n\nexport function waitForHydrationPrefetchStrategy(\n strategy: HydrationPrefetchStrategy,\n options: {\n element: Element | null\n signal: AbortSignal\n onHydrate: (listener: () => void) => () => void\n },\n): Promise<HydrationPrefetchWaitReason> {\n if (options.signal.aborted) {\n return Promise.resolve('abort')\n }\n\n return new Promise((resolve) => {\n const state = { disposed: false }\n const cleanupStrategyRef: { current: void | (() => void) } = {\n current: undefined,\n }\n let cleanupHydrate = () => {}\n\n const finish = (reason: HydrationPrefetchWaitReason) => {\n if (state.disposed) return\n state.disposed = true\n options.signal.removeEventListener('abort', onAbort)\n cleanupHydrate()\n runHydrationStrategyCleanup(cleanupStrategyRef.current)?.()\n resolve(reason)\n }\n\n const onAbort = () => finish('abort')\n\n options.signal.addEventListener('abort', onAbort, { once: true })\n cleanupHydrate = options.onHydrate(() => finish('hydrate'))\n const cleanupStrategy = strategy._s?.({\n element: options.element,\n prefetch: () => finish('prefetch'),\n })\n cleanupStrategyRef.current = cleanupStrategy\n if (state.disposed) {\n runHydrationStrategyCleanup(cleanupStrategy)?.()\n }\n })\n}\n\nexport function getMarkerGate(marker: Element) {\n const id = marker.getAttribute(hydrateIdAttribute)\n return id ? gateRegistry.get(id) : undefined\n}\n\nexport function resolveHydrationMarker(marker: Element) {\n const id = marker.getAttribute(hydrateIdAttribute)\n const when = marker.getAttribute(hydrateWhenAttribute)\n if (!id || !when || when === 'never') {\n return\n }\n\n const gate = gateRegistry.get(id)\n if (gate) {\n if (gate.when !== 'never') gate.resolve()\n return\n }\n\n resolvedGateIds.add(id)\n}\n\nexport function clearResolvedGateIdsInMarker(marker: Element) {\n const ownId = marker.getAttribute(hydrateIdAttribute)\n if (ownId) {\n resolvedGateIds.delete(ownId)\n }\n\n marker.querySelectorAll(hydrateIdSelector).forEach((childMarker) => {\n const childId = childMarker.getAttribute(hydrateIdAttribute)\n if (childId) {\n resolvedGateIds.delete(childId)\n }\n })\n}\n\nexport function saveFallbackHtml(id: string, element: Element) {\n if (!fallbackHtmlByGateId.has(id)) {\n fallbackHtmlByGateId.set(id, element.innerHTML)\n }\n}\n\nexport function getFallbackHtml(id: string) {\n return fallbackHtmlByGateId.get(id)\n}\n"],"mappings":"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"}
export type HydrationWhen = 'load' | 'idle' | 'visible' | 'media' | 'interaction' | 'condition' | 'never' | 'dynamic';
export type HydrationInteractionEvent = 'auxclick' | 'click' | 'contextmenu' | 'dblclick' | 'focusin' | 'keydown' | 'keyup' | 'mousedown' | 'mouseenter' | 'mouseover' | 'mouseup' | 'pointerdown' | 'pointerenter' | 'pointerover' | 'pointerup';
export type HydrationInteractionEvents = HydrationInteractionEvent | ReadonlyArray<HydrationInteractionEvent>;
export type HydrationMarkerAttributes = Record<string, string | undefined>;
export type HydrationRuntimeGate = {
id?: string;
when?: HydrationWhen;
resolved: boolean;
resolve: () => void;
};
export type HydrationRuntimeContext = {
element: Element | null;
gate?: HydrationRuntimeGate;
prefetch?: () => void;
delegated?: boolean;
};
export type HydrationStrategyTypes<TWhen extends HydrationWhen = HydrationWhen, TCanPrefetch extends boolean = boolean> = {
when: TWhen;
canPrefetch: TCanPrefetch;
};
export type HydrationStrategy<TWhen extends HydrationWhen = HydrationWhen, TCanPrefetch extends boolean = boolean> = {
_t?: TWhen;
readonly '~types'?: HydrationStrategyTypes<TWhen, TCanPrefetch>;
_d?: () => boolean;
_s?: (context: HydrationRuntimeContext) => void | (() => void);
_o?: (id: string) => void;
_a?: () => HydrationMarkerAttributes | undefined;
};
export type HydrationPrefetchWhen = Exclude<HydrationWhen, 'condition' | 'never' | 'dynamic'>;
export type HydrationPrefetchStrategy<TWhen extends HydrationPrefetchWhen = HydrationPrefetchWhen> = HydrationStrategy<TWhen, true>;
export type HydrationPrefetchWaitReason = 'prefetch' | 'hydrate' | 'abort';
export type HydrationPrefetchContext = {
element: Element | null;
signal: AbortSignal;
preload: () => Promise<void>;
waitFor: (strategy: HydrationPrefetchStrategy) => Promise<HydrationPrefetchWaitReason>;
};
export type HydrationPrefetchFunction = (context: HydrationPrefetchContext) => void | Promise<void>;
import { HydrationPrefetchStrategy } from './types.js';
declare const visibleType = "visible";
export type VisibleHydrationOptions = {
rootMargin?: string;
threshold?: number | Array<number>;
};
export declare function visible(options?: VisibleHydrationOptions): HydrationPrefetchStrategy<typeof visibleType>;
export {};
//#region src/hydration/visible.ts
var visibleType = "visible";
var observerRegistry = /* @__PURE__ */ new Map();
function cleanupVisibleObserverEntry(observerEntry) {
if (observerEntry.elements.size > 0) return;
observerEntry.observer.disconnect();
observerRegistry.delete(observerEntry.key);
}
/* @__NO_SIDE_EFFECTS__ */
function visible(options = {}) {
const rootMargin = options.rootMargin ?? "600px";
const threshold = options.threshold ?? 0;
return {
_t: visibleType,
_s: ({ element, gate, prefetch }) => {
const callback = prefetch ?? gate.resolve;
if (!element) {
callback();
return;
}
const key = `${rootMargin}|${Array.isArray(threshold) ? threshold.join(",") : String(threshold)}`;
let observerEntry = observerRegistry.get(key);
if (!observerEntry) {
const entry = {
key,
elements: /* @__PURE__ */ new Map(),
observer: new IntersectionObserver((entries) => {
for (const intersectingEntry of entries) {
if (!intersectingEntry.isIntersecting) continue;
const callbacks = entry.elements.get(intersectingEntry.target);
if (!callbacks) continue;
callbacks.forEach((callback) => callback());
entry.elements.delete(intersectingEntry.target);
entry.observer.unobserve(intersectingEntry.target);
cleanupVisibleObserverEntry(entry);
}
}, {
rootMargin,
threshold
})
};
observerRegistry.set(key, entry);
observerEntry = entry;
}
let callbacks = observerEntry.elements.get(element);
if (!callbacks) {
callbacks = /* @__PURE__ */ new Set();
observerEntry.elements.set(element, callbacks);
observerEntry.observer.observe(element);
}
callbacks.add(callback);
return () => {
const currentCallbacks = observerEntry.elements.get(element);
currentCallbacks?.delete(callback);
if (currentCallbacks?.size === 0) {
observerEntry.elements.delete(element);
observerEntry.observer.unobserve(element);
}
cleanupVisibleObserverEntry(observerEntry);
};
}
};
}
//#endregion
export { visible };
//# sourceMappingURL=visible.js.map
{"version":3,"file":"visible.js","names":[],"sources":["../../../src/hydration/visible.ts"],"sourcesContent":["import type { HydrationPrefetchStrategy } from './types'\n\nconst visibleType = 'visible'\n\nexport type VisibleHydrationOptions = {\n rootMargin?: string\n threshold?: number | Array<number>\n}\n\ntype VisibleObserverEntry = {\n key: string\n observer: IntersectionObserver\n elements: Map<Element, Set<() => void>>\n}\n\nconst observerRegistry = /* @__PURE__ */ new Map<string, VisibleObserverEntry>()\n\nfunction cleanupVisibleObserverEntry(observerEntry: VisibleObserverEntry) {\n if (observerEntry.elements.size > 0) return\n observerEntry.observer.disconnect()\n observerRegistry.delete(observerEntry.key)\n}\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function visible(\n options: VisibleHydrationOptions = {},\n): HydrationPrefetchStrategy<typeof visibleType> {\n const rootMargin = options.rootMargin ?? '600px'\n const threshold = options.threshold ?? 0\n\n return {\n _t: visibleType,\n _s: ({ element, gate, prefetch }) => {\n const callback = prefetch ?? gate!.resolve\n\n if (!element) {\n callback()\n return\n }\n\n const key = `${rootMargin}|${\n Array.isArray(threshold) ? threshold.join(',') : String(threshold)\n }`\n let observerEntry = observerRegistry.get(key)\n\n if (!observerEntry) {\n const entry: VisibleObserverEntry = {\n key,\n elements: new Map<Element, Set<() => void>>(),\n observer: new IntersectionObserver(\n (entries) => {\n for (const intersectingEntry of entries) {\n if (!intersectingEntry.isIntersecting) continue\n\n const callbacks = entry.elements.get(intersectingEntry.target)\n if (!callbacks) continue\n\n callbacks.forEach((callback) => callback())\n entry.elements.delete(intersectingEntry.target)\n entry.observer.unobserve(intersectingEntry.target)\n cleanupVisibleObserverEntry(entry)\n }\n },\n { rootMargin, threshold },\n ),\n }\n observerRegistry.set(key, entry)\n observerEntry = entry\n }\n\n let callbacks = observerEntry.elements.get(element)\n if (!callbacks) {\n callbacks = new Set()\n observerEntry.elements.set(element, callbacks)\n observerEntry.observer.observe(element)\n }\n callbacks.add(callback)\n\n return () => {\n const currentCallbacks = observerEntry.elements.get(element)\n currentCallbacks?.delete(callback)\n if (currentCallbacks?.size === 0) {\n observerEntry.elements.delete(element)\n observerEntry.observer.unobserve(element)\n }\n cleanupVisibleObserverEntry(observerEntry)\n }\n },\n }\n}\n"],"mappings":";AAEA,IAAM,cAAc;AAapB,IAAM,mCAAmC,IAAI,KAAmC;AAEhF,SAAS,4BAA4B,eAAqC;AACxE,KAAI,cAAc,SAAS,OAAO,EAAG;AACrC,eAAc,SAAS,YAAY;AACnC,kBAAiB,OAAO,cAAc,IAAI;;;AAI5C,SAAgB,QACd,UAAmC,EAAE,EACU;CAC/C,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,YAAY,QAAQ,aAAa;AAEvC,QAAO;EACL,IAAI;EACJ,KAAK,EAAE,SAAS,MAAM,eAAe;GACnC,MAAM,WAAW,YAAY,KAAM;AAEnC,OAAI,CAAC,SAAS;AACZ,cAAU;AACV;;GAGF,MAAM,MAAM,GAAG,WAAW,GACxB,MAAM,QAAQ,UAAU,GAAG,UAAU,KAAK,IAAI,GAAG,OAAO,UAAU;GAEpE,IAAI,gBAAgB,iBAAiB,IAAI,IAAI;AAE7C,OAAI,CAAC,eAAe;IAClB,MAAM,QAA8B;KAClC;KACA,0BAAU,IAAI,KAA+B;KAC7C,UAAU,IAAI,sBACX,YAAY;AACX,WAAK,MAAM,qBAAqB,SAAS;AACvC,WAAI,CAAC,kBAAkB,eAAgB;OAEvC,MAAM,YAAY,MAAM,SAAS,IAAI,kBAAkB,OAAO;AAC9D,WAAI,CAAC,UAAW;AAEhB,iBAAU,SAAS,aAAa,UAAU,CAAC;AAC3C,aAAM,SAAS,OAAO,kBAAkB,OAAO;AAC/C,aAAM,SAAS,UAAU,kBAAkB,OAAO;AAClD,mCAA4B,MAAM;;QAGtC;MAAE;MAAY;MAAW,CAC1B;KACF;AACD,qBAAiB,IAAI,KAAK,MAAM;AAChC,oBAAgB;;GAGlB,IAAI,YAAY,cAAc,SAAS,IAAI,QAAQ;AACnD,OAAI,CAAC,WAAW;AACd,gCAAY,IAAI,KAAK;AACrB,kBAAc,SAAS,IAAI,SAAS,UAAU;AAC9C,kBAAc,SAAS,QAAQ,QAAQ;;AAEzC,aAAU,IAAI,SAAS;AAEvB,gBAAa;IACX,MAAM,mBAAmB,cAAc,SAAS,IAAI,QAAQ;AAC5D,sBAAkB,OAAO,SAAS;AAClC,QAAI,kBAAkB,SAAS,GAAG;AAChC,mBAAc,SAAS,OAAO,QAAQ;AACtC,mBAAc,SAAS,UAAU,QAAQ;;AAE3C,gCAA4B,cAAc;;;EAG/C"}
import { hydrateIdAttribute } from './hydration/constants'
export { condition } from './hydration/condition'
export type { HydrationCondition } from './hydration/condition'
export {
hydrateIdAttribute,
hydrateInteractionEventsAttribute,
hydrateWhenAttribute,
} from './hydration/constants'
export const hydrateIdSelector = `[${hydrateIdAttribute}]`
export { idle } from './hydration/idle'
export type { IdleHydrationOptions } from './hydration/idle'
export { interaction } from './hydration/interaction'
export { load } from './hydration/load'
export { media } from './hydration/media'
export { never } from './hydration/never'
export {
clearResolvedGateIdsInMarker,
createResolvedGate,
getFallbackHtml,
getMarkerGate,
getOrCreateGate,
onGateResolve,
releaseGate,
resolveHydrationMarker,
runHydrationStrategyCleanup,
saveFallbackHtml,
waitForHydrationPrefetchStrategy,
} from './hydration/runtime'
export { withHydrationRenderer } from './hydration/renderer'
export { visible } from './hydration/visible'
export { listenForDelegatedHydrationIntent } from './hydration/interaction'
export type { VisibleHydrationOptions } from './hydration/visible'
export type { HydrationGateRecord } from './hydration/runtime'
export type { HydrationStrategyWithRenderer } from './hydration/renderer'
export type {
HydrationInteractionEvent,
HydrationInteractionEvents,
HydrationMarkerAttributes,
HydrationPrefetchContext,
HydrationPrefetchFunction,
HydrationPrefetchWhen,
HydrationPrefetchStrategy,
HydrationPrefetchWaitReason,
HydrationRuntimeContext,
HydrationRuntimeGate,
HydrationStrategy,
HydrationStrategyTypes,
HydrationWhen,
} from './hydration/types'
import type { HydrationStrategy } from './types'
const conditionType = 'condition'
export type HydrationCondition = boolean | (() => boolean)
/* @__NO_SIDE_EFFECTS__ */
export function condition(
condition: HydrationCondition,
): HydrationStrategy<typeof conditionType, false> {
return {
_t: conditionType,
_d: () => !(typeof condition === 'function' ? condition() : condition),
_s: ({ gate }) => {
if (typeof condition === 'function' ? condition() : condition) {
gate!.resolve()
}
},
}
}
export const hydrateIdAttribute = 'data-ts-hydrate-id'
export const hydrateWhenAttribute = 'data-ts-hydrate-when'
export const hydrateInteractionEventsAttribute =
'data-ts-hydrate-interaction-events'
import type { HydrationPrefetchStrategy } from './types'
const idleType = 'idle'
export type IdleHydrationOptions = {
timeout?: number
}
export function idle(
options: IdleHydrationOptions = {},
): HydrationPrefetchStrategy<typeof idleType> {
const timeout = options.timeout ?? 2000
return {
_t: idleType,
_s: ({ gate, prefetch }) => {
const schedule = globalThis as unknown as {
requestIdleCallback?: (
callback: IdleRequestCallback,
options?: IdleRequestOptions,
) => number
cancelIdleCallback?: (handle: number) => void
}
const callback = prefetch ?? gate!.resolve
if (schedule.requestIdleCallback) {
const handle = schedule.requestIdleCallback(callback, { timeout })
return () => schedule.cancelIdleCallback?.(handle)
}
const timeoutId = globalThis.setTimeout(callback, timeout)
return () => globalThis.clearTimeout(timeoutId)
},
}
}
import {
hydrateIdAttribute,
hydrateInteractionEventsAttribute,
hydrateWhenAttribute,
} from './constants'
import {
clearResolvedGateIdsInMarker,
getMarkerGate,
resolveHydrationMarker,
} from './runtime'
import type {
HydrationInteractionEvents,
HydrationPrefetchStrategy,
HydrationRuntimeContext,
} from './types'
export type InteractionHydrationOptions = {
events?: HydrationInteractionEvents
}
const hydrateIdSelector = `[${hydrateIdAttribute}]`
type PendingReplayEvent = {
marker: Element
targetPath: Array<number>
type: string
event: Event
}
const defaultInteractionEvents = [
'pointerenter',
'focusin',
'pointerdown',
'click',
] as const
const supportedInteractionEvents = [
'auxclick',
'click',
'contextmenu',
'dblclick',
'focusin',
'keydown',
'keyup',
'mousedown',
'mouseenter',
'mouseover',
'mouseup',
'pointerdown',
'pointerenter',
'pointerover',
'pointerup',
] as const
const interactionType = 'interaction'
const dynamicType = 'dynamic'
const interactionHydrateSelector = `[${hydrateWhenAttribute}="${interactionType}"]`
const delegatedHydrateSelector = `${interactionHydrateSelector},[${hydrateWhenAttribute}="${dynamicType}"]`
const replayEventsByGateId = /* @__PURE__ */ new Map<
string,
Array<PendingReplayEvent>
>()
function getIntentListenerEvents(
marker: Element,
events: ReadonlyArray<string>,
) {
const listenerEvents = new Set(events)
marker.querySelectorAll(delegatedHydrateSelector).forEach((childMarker) => {
if (childMarker.getAttribute(hydrateWhenAttribute) === dynamicType) {
supportedInteractionEvents.forEach((eventName) => {
listenerEvents.add(eventName)
})
return
}
const attr = childMarker.getAttribute(hydrateInteractionEventsAttribute)
for (const eventName of attr === null
? defaultInteractionEvents
: attr.split(/\s+/).filter(Boolean)) {
listenerEvents.add(eventName)
}
})
return [...listenerEvents]
}
function queueHydrationReplayEvent(marker: Element, event: Event) {
if (!event.bubbles) return
const id = marker.getAttribute(hydrateIdAttribute)
const when = marker.getAttribute(hydrateWhenAttribute)
if (!id || !when || when === 'never') return
const target = event.target
if (!target) return
const gate = getMarkerGate(marker)
if (gate?.resolved) return
event.preventDefault()
event.stopPropagation()
event.stopImmediatePropagation()
let targetPath: Array<number> = []
if (target instanceof Node && marker.contains(target)) {
let node: Element | null =
target instanceof Element ? target : target.parentElement
while (node && node !== marker) {
const parent = node.parentElement
if (!parent) {
targetPath = []
break
}
targetPath.push(Array.prototype.indexOf.call(parent.children, node))
node = parent
}
targetPath.reverse()
}
const pendingEvents = replayEventsByGateId.get(id) ?? []
pendingEvents.push({
marker,
targetPath,
type: event.type,
event,
})
replayEventsByGateId.set(id, pendingEvents)
}
if (typeof document !== 'undefined') {
const onIntent = (event: Event) => {
const target = event.target
if (!(target instanceof Element)) return
let marker: Element | null = target.closest(hydrateIdSelector)
const markers: Array<Element> = []
let shouldHandle = false
while (marker) {
markers.push(marker)
const when = marker.getAttribute(hydrateWhenAttribute)
if (when === dynamicType) {
shouldHandle ||= event.type === 'click'
} else if (when === interactionType) {
const attr = marker.getAttribute(hydrateInteractionEventsAttribute)
const events: ReadonlyArray<string> =
attr === null
? defaultInteractionEvents
: attr.split(/\s+/).filter(Boolean)
shouldHandle ||= events.includes(event.type)
}
marker = marker.parentElement?.closest(hydrateIdSelector) ?? null
}
if (!shouldHandle) return
markers.reverse()
if (markers.every((marker) => getMarkerGate(marker))) return
markers.forEach((marker) => {
queueHydrationReplayEvent(marker, event)
resolveHydrationMarker(marker)
})
}
supportedInteractionEvents.forEach((eventName) => {
document.addEventListener(eventName, onIntent, true)
})
}
function listenForIntent(
element: Element,
events: ReadonlyArray<string>,
context: HydrationRuntimeContext,
) {
const onIntent = (event: Event) => {
const target = event.target
let marker: Element | null
if (target instanceof Element) {
const closestMarker = target.closest(hydrateIdSelector)
marker =
closestMarker && element.contains(closestMarker)
? closestMarker
: element
} else {
marker = element
}
const markers: Array<Element> = []
while (marker) {
if (marker.hasAttribute(hydrateIdAttribute)) {
markers.push(marker)
}
if (marker === element) break
marker = marker.parentElement
}
if (!markers.includes(element)) {
markers.push(element)
}
markers.reverse()
if (
context.delegated &&
!markers.some(
(marker) =>
marker.getAttribute(hydrateWhenAttribute) === interactionType ||
marker.getAttribute(hydrateWhenAttribute) === dynamicType,
)
) {
return
}
markers.forEach((marker) => {
queueHydrationReplayEvent(marker, event)
resolveHydrationMarker(marker)
})
}
let disposed = false
events.forEach((eventName) => {
element.addEventListener(eventName, onIntent, true)
})
return () => {
if (disposed) return
disposed = true
events.forEach((eventName) => {
element.removeEventListener(eventName, onIntent, true)
})
}
}
export function listenForDelegatedHydrationIntent(
element: Element,
context: HydrationRuntimeContext,
) {
const listenerEvents = getIntentListenerEvents(element, [])
if (!listenerEvents.length) return
const cleanupIntent = listenForIntent(element, listenerEvents, {
...context,
delegated: true,
})
return () => {
cleanupIntent()
clearResolvedGateIdsInMarker(element)
}
}
/* @__NO_SIDE_EFFECTS__ */
export function interaction(
options: InteractionHydrationOptions = {},
): HydrationPrefetchStrategy<typeof interactionType> {
let events: ReadonlyArray<string> = defaultInteractionEvents
if (options.events !== undefined) {
const eventList: ReadonlyArray<string> =
typeof options.events === 'string' ? [options.events] : options.events
const normalizedEvents: Array<string> = []
const seen = new Set<string>()
for (const eventName of eventList) {
if (!eventName || seen.has(eventName)) continue
seen.add(eventName)
normalizedEvents.push(eventName)
}
events = normalizedEvents
}
const eventKey = events.join(' ')
return {
_t: interactionType,
_s: (context) => {
const element = context.element
if (!element) return
const prefetch = context.prefetch
if (prefetch) {
if (!events.length) return
let disposed = false
events.forEach((eventName) => {
element.addEventListener(eventName, prefetch, true)
})
return () => {
if (disposed) return
disposed = true
events.forEach((eventName) => {
element.removeEventListener(eventName, prefetch, true)
})
}
}
const listenerEvents = getIntentListenerEvents(element, events)
const cleanupIntent = listenerEvents.length
? listenForIntent(element, listenerEvents, context)
: undefined
return () => {
cleanupIntent?.()
clearResolvedGateIdsInMarker(element)
}
},
_o: (id) => {
globalThis.requestAnimationFrame(() => {
const pendingEvents = replayEventsByGateId.get(id)
if (!pendingEvents?.length) return
replayEventsByGateId.delete(id)
for (const pendingEvent of pendingEvents) {
let replayTarget: Element | null = pendingEvent.marker
for (const index of pendingEvent.targetPath) {
replayTarget = replayTarget.children[index] ?? null
if (!replayTarget) break
}
const event = pendingEvent.event
replayTarget ??= pendingEvent.marker
replayTarget.dispatchEvent(
event instanceof MouseEvent
? new MouseEvent(event.type, event)
: event instanceof FocusEvent
? new FocusEvent(event.type, event)
: new Event(event.type, event),
)
}
})
},
_a: () =>
options.events === undefined
? undefined
: {
[hydrateInteractionEventsAttribute]: eventKey,
},
}
}
import type { HydrationPrefetchStrategy } from './types'
const loadType = 'load'
const loadStrategy: HydrationPrefetchStrategy<typeof loadType> = {
_t: loadType,
_d: () => false,
_s: ({ gate, prefetch }) => {
;(prefetch ?? gate!.resolve)()
},
}
/* @__NO_SIDE_EFFECTS__ */
export function load(): HydrationPrefetchStrategy<typeof loadType> {
return loadStrategy
}
import type { HydrationPrefetchStrategy } from './types'
const mediaType = 'media'
/* @__NO_SIDE_EFFECTS__ */
export function media(
query: string,
): HydrationPrefetchStrategy<typeof mediaType> {
return {
_t: mediaType,
_s: ({ gate, prefetch }) => {
if (!query) return
const callback = prefetch ?? gate!.resolve
const mediaQuery = window.matchMedia(query)
const onChange = () => {
if (mediaQuery.matches) callback()
}
mediaQuery.addEventListener('change', onChange)
onChange()
return () => mediaQuery.removeEventListener('change', onChange)
},
}
}
import type { HydrationStrategy } from './types'
const neverType = 'never'
const neverStrategy: HydrationStrategy<typeof neverType, false> = {
_t: neverType,
_d: () => true,
}
/* @__NO_SIDE_EFFECTS__ */
export function never(): HydrationStrategy<typeof neverType, false> {
return neverStrategy
}
import type { HydrationStrategy } from './types'
export type HydrationStrategyWithRenderer<
TStrategy extends HydrationStrategy,
TRenderer,
> = TStrategy & {
_h: TRenderer
}
/* @__NO_SIDE_EFFECTS__ */
export function withHydrationRenderer<
TStrategy extends HydrationStrategy,
TRenderer,
>(
strategy: TStrategy,
renderer: TRenderer,
): HydrationStrategyWithRenderer<TStrategy, TRenderer> {
return /* @__PURE__ */ Object.assign(strategy, {
_h: renderer,
})
}
import { hydrateIdAttribute, hydrateWhenAttribute } from './constants'
import type {
HydrationPrefetchStrategy,
HydrationPrefetchWaitReason,
HydrationRuntimeGate,
HydrationWhen,
} from './types'
const hydrateIdSelector = `[${hydrateIdAttribute}]`
export type HydrationGateRecord = HydrationRuntimeGate & {
id: string
when: HydrationWhen
promise: Promise<void>
consumers: number
resolveListeners: Set<() => void>
}
const gateRegistry = /* @__PURE__ */ new Map<string, HydrationGateRecord>()
const resolvedGateIds = /* @__PURE__ */ new Set<string>()
const fallbackHtmlByGateId = /* @__PURE__ */ new Map<string, string>()
export function createResolvedGate(
id: string,
when: HydrationWhen,
): HydrationGateRecord {
return {
id,
when,
promise: Promise.resolve(),
resolve: () => {},
resolved: true,
consumers: 0,
resolveListeners: new Set<() => void>(),
}
}
export function getOrCreateGate(
id: string,
when: HydrationWhen,
): HydrationGateRecord {
const existing = gateRegistry.get(id)
if (existing?.when === when) {
existing.consumers++
return existing
}
let resolvePromise!: () => void
const promise = new Promise<void>((resolve) => {
resolvePromise = resolve
})
const gate: HydrationGateRecord = {
id,
promise,
resolved: false,
consumers: 1,
when,
resolveListeners: new Set(),
resolve: () => {
if (gate.resolved) return
gate.resolved = true
resolvePromise()
gate.resolveListeners.forEach((listener) => listener())
gate.resolveListeners.clear()
},
}
gateRegistry.set(id, gate)
if (when !== 'never' && resolvedGateIds.has(id)) {
resolvedGateIds.delete(id)
gate.resolve()
}
return gate
}
export function releaseGate(gate: HydrationGateRecord) {
resolvedGateIds.delete(gate.id)
gate.consumers--
if (gate.consumers > 0) return
if (gateRegistry.get(gate.id) === gate) {
gateRegistry.delete(gate.id)
fallbackHtmlByGateId.delete(gate.id)
gate.resolveListeners.clear()
}
}
export function onGateResolve(gate: HydrationGateRecord, listener: () => void) {
if (gate.resolved) {
listener()
return () => {}
}
gate.resolveListeners.add(listener)
return () => {
gate.resolveListeners.delete(listener)
}
}
export function runHydrationStrategyCleanup(cleanup: void | (() => void)) {
if (typeof cleanup === 'function') return cleanup
return undefined
}
export function waitForHydrationPrefetchStrategy(
strategy: HydrationPrefetchStrategy,
options: {
element: Element | null
signal: AbortSignal
onHydrate: (listener: () => void) => () => void
},
): Promise<HydrationPrefetchWaitReason> {
if (options.signal.aborted) {
return Promise.resolve('abort')
}
return new Promise((resolve) => {
const state = { disposed: false }
const cleanupStrategyRef: { current: void | (() => void) } = {
current: undefined,
}
let cleanupHydrate = () => {}
const finish = (reason: HydrationPrefetchWaitReason) => {
if (state.disposed) return
state.disposed = true
options.signal.removeEventListener('abort', onAbort)
cleanupHydrate()
runHydrationStrategyCleanup(cleanupStrategyRef.current)?.()
resolve(reason)
}
const onAbort = () => finish('abort')
options.signal.addEventListener('abort', onAbort, { once: true })
cleanupHydrate = options.onHydrate(() => finish('hydrate'))
const cleanupStrategy = strategy._s?.({
element: options.element,
prefetch: () => finish('prefetch'),
})
cleanupStrategyRef.current = cleanupStrategy
if (state.disposed) {
runHydrationStrategyCleanup(cleanupStrategy)?.()
}
})
}
export function getMarkerGate(marker: Element) {
const id = marker.getAttribute(hydrateIdAttribute)
return id ? gateRegistry.get(id) : undefined
}
export function resolveHydrationMarker(marker: Element) {
const id = marker.getAttribute(hydrateIdAttribute)
const when = marker.getAttribute(hydrateWhenAttribute)
if (!id || !when || when === 'never') {
return
}
const gate = gateRegistry.get(id)
if (gate) {
if (gate.when !== 'never') gate.resolve()
return
}
resolvedGateIds.add(id)
}
export function clearResolvedGateIdsInMarker(marker: Element) {
const ownId = marker.getAttribute(hydrateIdAttribute)
if (ownId) {
resolvedGateIds.delete(ownId)
}
marker.querySelectorAll(hydrateIdSelector).forEach((childMarker) => {
const childId = childMarker.getAttribute(hydrateIdAttribute)
if (childId) {
resolvedGateIds.delete(childId)
}
})
}
export function saveFallbackHtml(id: string, element: Element) {
if (!fallbackHtmlByGateId.has(id)) {
fallbackHtmlByGateId.set(id, element.innerHTML)
}
}
export function getFallbackHtml(id: string) {
return fallbackHtmlByGateId.get(id)
}
export type HydrationWhen =
| 'load'
| 'idle'
| 'visible'
| 'media'
| 'interaction'
| 'condition'
| 'never'
| 'dynamic'
export type HydrationInteractionEvent =
| 'auxclick'
| 'click'
| 'contextmenu'
| 'dblclick'
| 'focusin'
| 'keydown'
| 'keyup'
| 'mousedown'
| 'mouseenter'
| 'mouseover'
| 'mouseup'
| 'pointerdown'
| 'pointerenter'
| 'pointerover'
| 'pointerup'
export type HydrationInteractionEvents =
| HydrationInteractionEvent
| ReadonlyArray<HydrationInteractionEvent>
export type HydrationMarkerAttributes = Record<string, string | undefined>
export type HydrationRuntimeGate = {
id?: string
when?: HydrationWhen
resolved: boolean
resolve: () => void
}
export type HydrationRuntimeContext = {
element: Element | null
gate?: HydrationRuntimeGate
prefetch?: () => void
delegated?: boolean
}
export type HydrationStrategyTypes<
TWhen extends HydrationWhen = HydrationWhen,
TCanPrefetch extends boolean = boolean,
> = {
when: TWhen
canPrefetch: TCanPrefetch
}
export type HydrationStrategy<
TWhen extends HydrationWhen = HydrationWhen,
TCanPrefetch extends boolean = boolean,
> = {
_t?: TWhen
readonly '~types'?: HydrationStrategyTypes<TWhen, TCanPrefetch>
_d?: () => boolean
_s?: (context: HydrationRuntimeContext) => void | (() => void)
_o?: (id: string) => void
_a?: () => HydrationMarkerAttributes | undefined
}
export type HydrationPrefetchWhen = Exclude<
HydrationWhen,
'condition' | 'never' | 'dynamic'
>
export type HydrationPrefetchStrategy<
TWhen extends HydrationPrefetchWhen = HydrationPrefetchWhen,
> = HydrationStrategy<TWhen, true>
export type HydrationPrefetchWaitReason = 'prefetch' | 'hydrate' | 'abort'
export type HydrationPrefetchContext = {
element: Element | null
signal: AbortSignal
preload: () => Promise<void>
waitFor: (
strategy: HydrationPrefetchStrategy,
) => Promise<HydrationPrefetchWaitReason>
}
export type HydrationPrefetchFunction = (
context: HydrationPrefetchContext,
) => void | Promise<void>
import type { HydrationPrefetchStrategy } from './types'
const visibleType = 'visible'
export type VisibleHydrationOptions = {
rootMargin?: string
threshold?: number | Array<number>
}
type VisibleObserverEntry = {
key: string
observer: IntersectionObserver
elements: Map<Element, Set<() => void>>
}
const observerRegistry = /* @__PURE__ */ new Map<string, VisibleObserverEntry>()
function cleanupVisibleObserverEntry(observerEntry: VisibleObserverEntry) {
if (observerEntry.elements.size > 0) return
observerEntry.observer.disconnect()
observerRegistry.delete(observerEntry.key)
}
/* @__NO_SIDE_EFFECTS__ */
export function visible(
options: VisibleHydrationOptions = {},
): HydrationPrefetchStrategy<typeof visibleType> {
const rootMargin = options.rootMargin ?? '600px'
const threshold = options.threshold ?? 0
return {
_t: visibleType,
_s: ({ element, gate, prefetch }) => {
const callback = prefetch ?? gate!.resolve
if (!element) {
callback()
return
}
const key = `${rootMargin}|${
Array.isArray(threshold) ? threshold.join(',') : String(threshold)
}`
let observerEntry = observerRegistry.get(key)
if (!observerEntry) {
const entry: VisibleObserverEntry = {
key,
elements: new Map<Element, Set<() => void>>(),
observer: new IntersectionObserver(
(entries) => {
for (const intersectingEntry of entries) {
if (!intersectingEntry.isIntersecting) continue
const callbacks = entry.elements.get(intersectingEntry.target)
if (!callbacks) continue
callbacks.forEach((callback) => callback())
entry.elements.delete(intersectingEntry.target)
entry.observer.unobserve(intersectingEntry.target)
cleanupVisibleObserverEntry(entry)
}
},
{ rootMargin, threshold },
),
}
observerRegistry.set(key, entry)
observerEntry = entry
}
let callbacks = observerEntry.elements.get(element)
if (!callbacks) {
callbacks = new Set()
observerEntry.elements.set(element, callbacks)
observerEntry.observer.observe(element)
}
callbacks.add(callback)
return () => {
const currentCallbacks = observerEntry.elements.get(element)
currentCallbacks?.delete(callback)
if (currentCallbacks?.size === 0) {
observerEntry.elements.delete(element)
observerEntry.observer.unobserve(element)
}
cleanupVisibleObserverEntry(observerEntry)
}
},
}
}
+13
-1
import { AnyRouter } from '@tanstack/router-core';
export declare function hydrateStart(): Promise<AnyRouter>;
type HotContext = {
data?: Record<string, unknown>;
dispose?: (cb: (data: Record<string, unknown>) => void) => void;
};
declare global {
interface ImportMeta {
hot?: HotContext;
webpackHot?: HotContext;
}
}
declare function hydrateStart(): Promise<AnyRouter>;
declare const exportedHydrateStart: typeof hydrateStart;
export { exportedHydrateStart as hydrateStart };

@@ -30,5 +30,24 @@ import { ServerFunctionSerializationAdapter } from "./ServerFunctionSerializationAdapter.js";

}
function hydrateStartWithHmr() {
const hot = import.meta.hot ?? import.meta.webpackHot;
if (!hot) return hydrateStart();
const key = "tss-hydrate-start-promise";
const hotData = hot.data ??= {};
let hydrationPromise = hotData[key];
if (!hydrationPromise) {
hydrationPromise = hydrateStart().catch((error) => {
if (hotData[key] === hydrationPromise) hotData[key] = void 0;
throw error;
});
hotData[key] = hydrationPromise;
}
hot.dispose?.((data) => {
data[key] = hotData[key];
});
return hydrationPromise;
}
var exportedHydrateStart = process.env.NODE_ENV !== "production" ? hydrateStartWithHmr : hydrateStart;
//#endregion
export { hydrateStart };
export { exportedHydrateStart };
//# sourceMappingURL=hydrateStart.js.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"hydrateStart.js","names":[],"sources":["../../../src/client/hydrateStart.ts"],"sourcesContent":["import { hydrate } from '@tanstack/router-core/ssr/client'\n\nimport { startInstance } from '#tanstack-start-entry'\nimport {\n hasPluginAdapters,\n pluginSerializationAdapters,\n} from '#tanstack-start-plugin-adapters'\nimport { getRouter } from '#tanstack-router-entry'\nimport { ServerFunctionSerializationAdapter } from './ServerFunctionSerializationAdapter'\nimport type { AnyRouter, AnySerializationAdapter } from '@tanstack/router-core'\nimport type { AnyStartInstanceOptions } from '../createStart'\n\nexport async function hydrateStart(): Promise<AnyRouter> {\n const router = await getRouter()\n\n let serializationAdapters: Array<AnySerializationAdapter>\n if (startInstance) {\n const startOptions = await startInstance.getOptions()\n startOptions.serializationAdapters =\n startOptions.serializationAdapters ?? []\n window.__TSS_START_OPTIONS__ = startOptions as AnyStartInstanceOptions\n serializationAdapters = startOptions.serializationAdapters\n router.options.defaultSsr = startOptions.defaultSsr\n } else {\n serializationAdapters = []\n window.__TSS_START_OPTIONS__ = {\n serializationAdapters,\n } as AnyStartInstanceOptions\n }\n\n // Only spread plugin adapters if any are configured (this will tree-shake away otherwise)\n if (hasPluginAdapters) {\n serializationAdapters.push(...pluginSerializationAdapters)\n }\n serializationAdapters.push(ServerFunctionSerializationAdapter)\n if (router.options.serializationAdapters) {\n serializationAdapters.push(...router.options.serializationAdapters)\n }\n\n router.update({\n basepath: process.env.TSS_ROUTER_BASEPATH,\n ...{ serializationAdapters },\n })\n if (!router.stores.matchesId.get().length) {\n await hydrate(router)\n }\n\n return router\n}\n"],"mappings":";;;;;;AAYA,eAAsB,eAAmC;CACvD,MAAM,SAAS,MAAM,WAAW;CAEhC,IAAI;AACJ,KAAI,eAAe;EACjB,MAAM,eAAe,MAAM,cAAc,YAAY;AACrD,eAAa,wBACX,aAAa,yBAAyB,EAAE;AAC1C,SAAO,wBAAwB;AAC/B,0BAAwB,aAAa;AACrC,SAAO,QAAQ,aAAa,aAAa;QACpC;AACL,0BAAwB,EAAE;AAC1B,SAAO,wBAAwB,EAC7B,uBACD;;AAIH,KAAI,kBACF,uBAAsB,KAAK,GAAG,4BAA4B;AAE5D,uBAAsB,KAAK,mCAAmC;AAC9D,KAAI,OAAO,QAAQ,sBACjB,uBAAsB,KAAK,GAAG,OAAO,QAAQ,sBAAsB;AAGrE,QAAO,OAAO;EACZ,UAAU,QAAQ,IAAI;EACjB;EACN,CAAC;AACF,KAAI,CAAC,OAAO,OAAO,UAAU,KAAK,CAAC,OACjC,OAAM,QAAQ,OAAO;AAGvB,QAAO"}
{"version":3,"file":"hydrateStart.js","names":[],"sources":["../../../src/client/hydrateStart.ts"],"sourcesContent":["import { hydrate } from '@tanstack/router-core/ssr/client'\nimport { startInstance } from '#tanstack-start-entry'\nimport {\n hasPluginAdapters,\n pluginSerializationAdapters,\n} from '#tanstack-start-plugin-adapters'\nimport { getRouter } from '#tanstack-router-entry'\nimport { ServerFunctionSerializationAdapter } from './ServerFunctionSerializationAdapter'\nimport type { AnyRouter, AnySerializationAdapter } from '@tanstack/router-core'\nimport type { AnyStartInstanceOptions } from '../createStart'\n\ntype HotContext = {\n data?: Record<string, unknown>\n dispose?: (cb: (data: Record<string, unknown>) => void) => void\n}\n\ndeclare global {\n interface ImportMeta {\n hot?: HotContext\n webpackHot?: HotContext\n }\n}\n\nasync function hydrateStart(): Promise<AnyRouter> {\n const router = await getRouter()\n\n let serializationAdapters: Array<AnySerializationAdapter>\n if (startInstance) {\n const startOptions = await startInstance.getOptions()\n startOptions.serializationAdapters =\n startOptions.serializationAdapters ?? []\n window.__TSS_START_OPTIONS__ = startOptions as AnyStartInstanceOptions\n serializationAdapters = startOptions.serializationAdapters\n router.options.defaultSsr = startOptions.defaultSsr\n } else {\n serializationAdapters = []\n window.__TSS_START_OPTIONS__ = {\n serializationAdapters,\n } as AnyStartInstanceOptions\n }\n\n // Only spread plugin adapters if any are configured (this will tree-shake away otherwise)\n if (hasPluginAdapters) {\n serializationAdapters.push(...pluginSerializationAdapters)\n }\n serializationAdapters.push(ServerFunctionSerializationAdapter)\n if (router.options.serializationAdapters) {\n serializationAdapters.push(...router.options.serializationAdapters)\n }\n\n router.update({\n basepath: process.env.TSS_ROUTER_BASEPATH,\n ...{ serializationAdapters },\n })\n if (!router.stores.matchesId.get().length) {\n await hydrate(router)\n }\n\n return router\n}\n\nfunction hydrateStartWithHmr(): Promise<AnyRouter> {\n const hot = import.meta.hot ?? import.meta.webpackHot\n\n if (!hot) {\n return hydrateStart()\n }\n\n const key = 'tss-hydrate-start-promise'\n const hotData = (hot.data ??= {})\n let hydrationPromise = hotData[key] as Promise<AnyRouter> | undefined\n\n if (!hydrationPromise) {\n hydrationPromise = hydrateStart().catch((error) => {\n if (hotData[key] === hydrationPromise) {\n hotData[key] = undefined\n }\n\n throw error\n })\n\n hotData[key] = hydrationPromise\n }\n\n hot.dispose?.((data) => {\n data[key] = hotData[key]\n })\n\n return hydrationPromise\n}\n\nconst exportedHydrateStart =\n process.env.NODE_ENV !== 'production' ? hydrateStartWithHmr : hydrateStart\n\nexport { exportedHydrateStart as hydrateStart }\n"],"mappings":";;;;;;AAuBA,eAAe,eAAmC;CAChD,MAAM,SAAS,MAAM,WAAW;CAEhC,IAAI;AACJ,KAAI,eAAe;EACjB,MAAM,eAAe,MAAM,cAAc,YAAY;AACrD,eAAa,wBACX,aAAa,yBAAyB,EAAE;AAC1C,SAAO,wBAAwB;AAC/B,0BAAwB,aAAa;AACrC,SAAO,QAAQ,aAAa,aAAa;QACpC;AACL,0BAAwB,EAAE;AAC1B,SAAO,wBAAwB,EAC7B,uBACD;;AAIH,KAAI,kBACF,uBAAsB,KAAK,GAAG,4BAA4B;AAE5D,uBAAsB,KAAK,mCAAmC;AAC9D,KAAI,OAAO,QAAQ,sBACjB,uBAAsB,KAAK,GAAG,OAAO,QAAQ,sBAAsB;AAGrE,QAAO,OAAO;EACZ,UAAU,QAAQ,IAAI;EACjB;EACN,CAAC;AACF,KAAI,CAAC,OAAO,OAAO,UAAU,KAAK,CAAC,OACjC,OAAM,QAAQ,OAAO;AAGvB,QAAO;;AAGT,SAAS,sBAA0C;CACjD,MAAM,MAAA,OAAA,KAAA,OAAyB,OAAO,KAAK;AAE3C,KAAI,CAAC,IACH,QAAO,cAAc;CAGvB,MAAM,MAAM;CACZ,MAAM,UAAW,IAAI,SAAS,EAAE;CAChC,IAAI,mBAAmB,QAAQ;AAE/B,KAAI,CAAC,kBAAkB;AACrB,qBAAmB,cAAc,CAAC,OAAO,UAAU;AACjD,OAAI,QAAQ,SAAS,iBACnB,SAAQ,OAAO,KAAA;AAGjB,SAAM;IACN;AAEF,UAAQ,OAAO;;AAGjB,KAAI,WAAW,SAAS;AACtB,OAAK,OAAO,QAAQ;GACpB;AAEF,QAAO;;AAGT,IAAM,uBAAA,QAAA,IAAA,aACqB,eAAe,sBAAsB"}

@@ -1,2 +0,2 @@

import { hydrateStart } from "./hydrateStart.js";
export { hydrateStart };
import { exportedHydrateStart } from "./hydrateStart.js";
export { exportedHydrateStart as hydrateStart };
{
"name": "@tanstack/start-client-core",
"version": "1.169.4",
"version": "1.170.0",
"description": "Modern and scalable routing for React applications",

@@ -47,2 +47,20 @@ "author": "Tanner Linsley",

},
"./hydration": {
"import": {
"types": "./dist/esm/hydration.d.ts",
"default": "./dist/esm/hydration.js"
}
},
"./hydration/constants": {
"import": {
"types": "./dist/esm/hydration/constants.d.ts",
"default": "./dist/esm/hydration/constants.js"
}
},
"./hydration/runtime": {
"import": {
"types": "./dist/esm/hydration/runtime.d.ts",
"default": "./dist/esm/hydration/runtime.js"
}
},
"./package.json": "./package.json"

@@ -52,8 +70,11 @@ },

"#tanstack-start-entry": {
"types": "./src/start-entry.d.ts",
"default": "./dist/esm/fake-entries/start.js"
},
"#tanstack-router-entry": {
"types": "./src/start-entry.d.ts",
"default": "./dist/esm/fake-entries/router.js"
},
"#tanstack-start-plugin-adapters": {
"types": "./src/start-entry.d.ts",
"default": "./dist/esm/fake-entries/plugin-adapters.js"

@@ -75,5 +96,5 @@ }

"seroval": "^1.5.4",
"@tanstack/router-core": "1.171.2",
"@tanstack/router-core": "1.171.3",
"@tanstack/start-fn-stubs": "1.162.0",
"@tanstack/start-storage-context": "1.167.4"
"@tanstack/start-storage-context": "1.167.5"
},

@@ -80,0 +101,0 @@ "devDependencies": {

import { hydrate } from '@tanstack/router-core/ssr/client'
import { startInstance } from '#tanstack-start-entry'

@@ -13,3 +12,15 @@ import {

export async function hydrateStart(): Promise<AnyRouter> {
type HotContext = {
data?: Record<string, unknown>
dispose?: (cb: (data: Record<string, unknown>) => void) => void
}
declare global {
interface ImportMeta {
hot?: HotContext
webpackHot?: HotContext
}
}
async function hydrateStart(): Promise<AnyRouter> {
const router = await getRouter()

@@ -51,1 +62,36 @@

}
function hydrateStartWithHmr(): Promise<AnyRouter> {
const hot = import.meta.hot ?? import.meta.webpackHot
if (!hot) {
return hydrateStart()
}
const key = 'tss-hydrate-start-promise'
const hotData = (hot.data ??= {})
let hydrationPromise = hotData[key] as Promise<AnyRouter> | undefined
if (!hydrationPromise) {
hydrationPromise = hydrateStart().catch((error) => {
if (hotData[key] === hydrationPromise) {
hotData[key] = undefined
}
throw error
})
hotData[key] = hydrationPromise
}
hot.dispose?.((data) => {
data[key] = hotData[key]
})
return hydrationPromise
}
const exportedHydrateStart =
process.env.NODE_ENV !== 'production' ? hydrateStartWithHmr : hydrateStart
export { exportedHydrateStart as hydrateStart }