@emberkit/core 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"hydration.d.ts","sourceRoot":"","sources":["../../../src/hydration/helpers/hydration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAItD,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/D;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,OAAO,GAAG,MAAM,EAC3B,OAAO,EAAE,UAAU,GAAG,IAAI,EAC1B,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAiBf;AA4CD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAcjF;AAgCD,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC7B,GACL,UAAU,CA0BZ;AAwCD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
1
+ {"version":3,"file":"hydration.d.ts","sourceRoot":"","sources":["../../../src/hydration/helpers/hydration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAMtD,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/D;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,OAAO,GAAG,MAAM,EAC3B,OAAO,EAAE,UAAU,GAAG,IAAI,EAC1B,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAiBf;AA4CD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAcjF;AAgCD,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC7B,GACL,UAAU,CA4BZ;AAwCD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -1,6 +1,8 @@
1
1
  import { createElement } from '../../runtime/index.js';
2
2
  import { analyzeTree, getHydrationCandidates } from './analyzer.js';
3
+ import { observeOnce } from '../../viewport/observe-once.js';
3
4
  const hydrationCache = new Map();
5
+ let lazyHydrationIdCounter = 0;
4
6
  export async function hydrateSelective(container, element, options = {}) {
5
7
  const root = typeof container === 'string' ? document.querySelector(container) : container;
6
8
  if (!root || !element)
@@ -87,13 +89,15 @@ function mapHandlerToEvent(handler) {
87
89
  }
88
90
  export function createLazyHydration(loader, options = {}) {
89
91
  const { fallback = createElement('div', { 'data-loading': '' }, 'Loading...'), timeout, onLoaded, onError, } = options;
92
+ const lazyId = `ek-hydrate-${++lazyHydrationIdCounter}`;
90
93
  const container = createElement('div', {
91
94
  'data-lazy': '',
95
+ 'data-lazy-id': lazyId,
92
96
  'data-loader': loader.toString(),
93
97
  }, fallback);
94
98
  if (typeof IntersectionObserver !== 'undefined') {
95
99
  requestAnimationFrame(() => {
96
- observeAndHydrate(container, loader, timeout, onLoaded, onError);
100
+ observeAndHydrate(lazyId, loader, timeout, onLoaded, onError);
97
101
  });
98
102
  }
99
103
  else {
@@ -101,17 +105,15 @@ export function createLazyHydration(loader, options = {}) {
101
105
  }
102
106
  return container;
103
107
  }
104
- function observeAndHydrate(container, loader, timeout, onLoaded, onError) {
105
- const observer = new IntersectionObserver((entries) => {
106
- if (entries[0]?.isIntersecting) {
107
- observer.disconnect();
108
- loadImmediately(loader, onLoaded, onError);
109
- }
110
- }, { rootMargin: '100px' });
111
- const root = document.querySelector(`[data-lazy]`);
112
- if (root) {
113
- observer.observe(root);
108
+ function observeAndHydrate(lazyId, loader, timeout, onLoaded, onError) {
109
+ const root = document.querySelector(`[data-lazy-id="${lazyId}"]`);
110
+ if (!root) {
111
+ return;
114
112
  }
113
+ observeOnce(root, () => {
114
+ void timeout;
115
+ void loadImmediately(loader, onLoaded, onError);
116
+ }, { rootMargin: '100px' });
115
117
  }
116
118
  async function loadImmediately(loader, onLoaded, onError) {
117
119
  try {
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export type { Signal, WritableSignal, ReadonlySignal } from './signals/index.js'
11
11
  export { createMarkdownParser, parseMarkdown, renderMarkdown, extractFrontmatter, } from './markdown/index.js';
12
12
  export { compileMDX, compileSync, useMDX } from './mdx/index.js';
13
13
  export { DataCache, createCache, getCached, setCache, prefetch } from './cache/index.js';
14
+ export { LazyInView, hydrateLazyInView, clearLazyRegistry } from './viewport/index.js';
14
15
  export { renderToHTMLString } from './ssr/helpers/render-html.js';
15
16
  export { drainHeadContent } from './meta/head-registry.js';
16
17
  export { Head } from './meta/index.js';
@@ -18,6 +19,7 @@ export type { HeadProps } from './meta/index.js';
18
19
  export { generateMeta, generateBreadcrumbs, generateArticleSchema, generateProductSchema, } from './meta/index.js';
19
20
  export type { MetaData, OpenGraphData, TwitterCardData } from './meta/index.js';
20
21
  export type { FC, RouteComponent, RouteChildren, RouteParams } from './runtime/types.js';
22
+ export type { LazyInViewProps } from './viewport/index.js';
21
23
  export type { Logger, LoggerOptions, LogLevel, RequestLog, ResponseLog } from './logger/types.js';
22
24
  export declare function defineConfig(config: Record<string, unknown>): Record<string, unknown>;
23
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,QAAsB,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,KAAK,EACL,OAAO,EACP,MAAM,EACN,QAAQ,EACR,MAAM,GACP,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnF,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEhF,YAAY,EAAE,EAAE,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEzF,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAElG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAErF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,OAAO,QAAsB,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,KAAK,EACL,OAAO,EACP,MAAM,EACN,QAAQ,EACR,MAAM,GACP,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnF,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEhF,YAAY,EAAE,EAAE,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACzF,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAElG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAErF"}
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ export { createErrorBoundary, createLoadingBoundary } from './boundaries/index.j
10
10
  export { createMarkdownParser, parseMarkdown, renderMarkdown, extractFrontmatter, } from './markdown/index.js';
11
11
  export { compileMDX, compileSync, useMDX } from './mdx/index.js';
12
12
  export { DataCache, createCache, getCached, setCache, prefetch } from './cache/index.js';
13
+ export { LazyInView, hydrateLazyInView, clearLazyRegistry } from './viewport/index.js';
13
14
  export { renderToHTMLString } from './ssr/helpers/render-html.js';
14
15
  export { drainHeadContent } from './meta/head-registry.js';
15
16
  export { Head } from './meta/index.js';
@@ -1,5 +1,8 @@
1
1
  import type { JSXElementProps, JSXNode, DOMElement, JSXElement } from './types.js';
2
2
  export declare function createElement(type: string | ((props: JSXElementProps) => JSXNode), props?: Record<string, unknown> | null, ...children: unknown[]): DOMElement;
3
+ export declare function attachEventHandlers(container: Element): void;
4
+ export declare function hydrateSignalBindings(container: Element): void;
5
+ export declare function hydrateSubtree(container: Element): void;
3
6
  export declare function render(element: JSXElement | string | null | ((props: Record<string, unknown>) => JSXNode), container: Element | string, options?: {
4
7
  hydrate?: boolean;
5
8
  routes?: Array<{
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKnF,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,EACpD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,GAAG,QAAQ,EAAE,OAAO,EAAE,GACrB,UAAU,CAYZ;AA6ID,wBAAgB,MAAM,CACpB,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,EACnF,SAAS,EAAE,OAAO,GAAG,MAAM,EAC3B,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAA;SAAE,CAAC,CAAC;KACpF,CAAC,CAAC;CACJ,GACA,IAAI,CAmFN;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE9F;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAE9C;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,UAAU,CAEjE;AAED,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMnF,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,EACpD,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACtC,GAAG,QAAQ,EAAE,OAAO,EAAE,GACrB,UAAU,CAYZ;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAY5D;AAqED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAwD9D;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAGvD;AAED,wBAAgB,MAAM,CACpB,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,EACnF,SAAS,EAAE,OAAO,GAAG,MAAM,EAC3B,OAAO,CAAC,EAAE;IACR,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAA;SAAE,CAAC,CAAC;KACpF,CAAC,CAAC;CACJ,GACA,IAAI,CAmFN;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAE9F;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAE9C;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,UAAU,CAEjE;AAED,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,OAAO,EAAE,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { renderToString, getHandler, clearHandlers } from './helpers/render.js';
2
2
  import { getSignalByIndex } from '../signals/helpers/core.js';
3
3
  import { matchRoute } from './helpers/match.js';
4
+ import { hydrateLazyInView } from '../viewport/index.js';
4
5
  export function createElement(type, props, ...children) {
5
6
  const resolvedProps = props ?? {};
6
7
  const flatChildren = children.flat().filter((child) => child != null && child !== false);
@@ -12,7 +13,7 @@ export function createElement(type, props, ...children) {
12
13
  props: resolvedProps,
13
14
  };
14
15
  }
15
- function attachEventHandlers(container) {
16
+ export function attachEventHandlers(container) {
16
17
  const elements = container.querySelectorAll('[data-ekclick]');
17
18
  elements.forEach((el) => {
18
19
  const id = el.getAttribute('data-ekclick');
@@ -68,10 +69,10 @@ function renderToTarget(layout, target, routeComponent, routeProps) {
68
69
  };
69
70
  const html = renderToString(jsxElement);
70
71
  target.innerHTML = html;
71
- attachEventHandlers(target);
72
- hydrateSignalBindings(target);
72
+ hydrateSubtree(target);
73
+ hydrateLazyInView(target);
73
74
  }
74
- function hydrateSignalBindings(container) {
75
+ export function hydrateSignalBindings(container) {
75
76
  const els = container.querySelectorAll('[data-ek-bind]');
76
77
  els.forEach((el) => {
77
78
  const idx = parseInt(el.getAttribute('data-ek-bind') ?? '', 10);
@@ -130,6 +131,10 @@ function hydrateSignalBindings(container) {
130
131
  });
131
132
  });
132
133
  }
134
+ export function hydrateSubtree(container) {
135
+ attachEventHandlers(container);
136
+ hydrateSignalBindings(container);
137
+ }
133
138
  export function render(element, container, options) {
134
139
  if (!element)
135
140
  return;
@@ -0,0 +1,2 @@
1
+ export declare function hydrateLazyInView(container: Element): void;
2
+ //# sourceMappingURL=hydrate-lazy-in-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrate-lazy-in-view.d.ts","sourceRoot":"","sources":["../../src/viewport/hydrate-lazy-in-view.ts"],"names":[],"mappings":"AAsBA,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAwC1D"}
@@ -0,0 +1,41 @@
1
+ import { hydrateSubtree } from '../runtime/index.js';
2
+ import { renderToString } from '../runtime/helpers/render.js';
3
+ import { getLazyContent, unregisterLazyContent } from './registry.js';
4
+ import { observeOnce } from './observe-once.js';
5
+ function getLazyHosts(container) {
6
+ const hosts = [];
7
+ if (container.matches('[data-ek-lazy-in-view]:not([data-ek-lazy-loaded])')) {
8
+ hosts.push(container);
9
+ }
10
+ hosts.push(...Array.from(container.querySelectorAll('[data-ek-lazy-in-view]:not([data-ek-lazy-loaded])')));
11
+ return hosts;
12
+ }
13
+ export function hydrateLazyInView(container) {
14
+ const hosts = getLazyHosts(container);
15
+ hosts.forEach((host) => {
16
+ const id = host.getAttribute('data-ek-lazy-in-view');
17
+ const rootMargin = host.getAttribute('data-ek-lazy-root-margin') ?? '200px';
18
+ if (!id) {
19
+ return;
20
+ }
21
+ observeOnce(host, () => {
22
+ const loader = getLazyContent(id);
23
+ if (!loader) {
24
+ return;
25
+ }
26
+ const content = loader();
27
+ const html = content == null || content === false
28
+ ? ''
29
+ : typeof content === 'string' || typeof content === 'number'
30
+ ? String(content)
31
+ : renderToString(content);
32
+ host.innerHTML = html;
33
+ host.setAttribute('data-ek-lazy-loaded', 'true');
34
+ host.removeAttribute('aria-busy');
35
+ hydrateSubtree(host);
36
+ if (host.getAttribute('data-ek-lazy-once') !== 'false') {
37
+ unregisterLazyContent(id);
38
+ }
39
+ }, { rootMargin });
40
+ });
41
+ }
@@ -0,0 +1,5 @@
1
+ export * from './hydrate-lazy-in-view.js';
2
+ export * from './lazy-in-view.js';
3
+ export * from './observe-once.js';
4
+ export * from './registry.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/viewport/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './hydrate-lazy-in-view.js';
2
+ export * from './lazy-in-view.js';
3
+ export * from './observe-once.js';
4
+ export * from './registry.js';
@@ -0,0 +1,13 @@
1
+ import type { JSXElementProps, JSXNode } from '../runtime/types.js';
2
+ export interface LazyInViewProps extends Omit<JSXElementProps, 'children'> {
3
+ as?: string;
4
+ children: JSXNode | (() => JSXNode);
5
+ className?: string;
6
+ fallback?: JSXNode;
7
+ minHeight?: number | string;
8
+ once?: boolean;
9
+ rootMargin?: string;
10
+ ssr?: 'lazy' | 'eager';
11
+ }
12
+ export declare function LazyInView({ as, children, className, fallback, minHeight, once, rootMargin, ssr, style, ...rest }: LazyInViewProps): JSXNode;
13
+ //# sourceMappingURL=lazy-in-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-in-view.d.ts","sourceRoot":"","sources":["../../src/viewport/lazy-in-view.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGpE,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAMD,wBAAgB,UAAU,CAAC,EACzB,EAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAe,EACf,SAAS,EACT,IAAW,EACX,UAAoB,EACpB,GAAY,EACZ,KAAK,EACL,GAAG,IAAI,EACR,EAAE,eAAe,GAAG,OAAO,CA6B3B"}
@@ -0,0 +1,28 @@
1
+ import { createElement } from '../runtime/index.js';
2
+ import { nextLazyId, registerLazyContent } from './registry.js';
3
+ function resolveLazyContent(children) {
4
+ return typeof children === 'function' ? children() : children;
5
+ }
6
+ export function LazyInView({ as = 'div', children, className, fallback = null, minHeight, once = true, rootMargin = '200px', ssr = 'lazy', style, ...rest }) {
7
+ const id = nextLazyId();
8
+ const loader = () => resolveLazyContent(children);
9
+ registerLazyContent(id, loader);
10
+ const shouldRenderLazy = ssr === 'lazy';
11
+ const resolvedStyle = minHeight == null
12
+ ? style
13
+ : {
14
+ ...(typeof style === 'object' && style !== null ? style : {}),
15
+ minHeight,
16
+ };
17
+ return createElement(as, {
18
+ ...rest,
19
+ 'aria-busy': shouldRenderLazy ? 'true' : undefined,
20
+ className,
21
+ 'data-ek-lazy-in-view': id,
22
+ 'data-ek-lazy-once': String(once),
23
+ 'data-ek-lazy-root-margin': rootMargin,
24
+ 'data-ek-lazy-loaded': shouldRenderLazy ? undefined : 'true',
25
+ style: resolvedStyle,
26
+ }, shouldRenderLazy ? fallback : loader());
27
+ }
28
+ ;
@@ -0,0 +1,6 @@
1
+ export interface ObserveOnceOptions {
2
+ rootMargin?: string;
3
+ threshold?: number;
4
+ }
5
+ export declare function observeOnce(element: Element, callback: () => void, options?: ObserveOnceOptions): () => void;
6
+ //# sourceMappingURL=observe-once.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe-once.d.ts","sourceRoot":"","sources":["../../src/viewport/observe-once.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,IAAI,EACpB,OAAO,GAAE,kBAAuB,GAC/B,MAAM,IAAI,CA0BZ"}
@@ -0,0 +1,20 @@
1
+ export function observeOnce(element, callback, options = {}) {
2
+ if (typeof IntersectionObserver === 'undefined') {
3
+ callback();
4
+ return () => { };
5
+ }
6
+ const observer = new IntersectionObserver((entries) => {
7
+ if (!entries[0]?.isIntersecting) {
8
+ return;
9
+ }
10
+ observer.disconnect();
11
+ callback();
12
+ }, {
13
+ rootMargin: options.rootMargin,
14
+ threshold: options.threshold,
15
+ });
16
+ observer.observe(element);
17
+ return () => {
18
+ observer.disconnect();
19
+ };
20
+ }
@@ -0,0 +1,7 @@
1
+ import type { JSXNode } from '../runtime/types.js';
2
+ export declare function registerLazyContent(id: string, loader: () => JSXNode): void;
3
+ export declare function getLazyContent(id: string): (() => JSXNode) | undefined;
4
+ export declare function unregisterLazyContent(id: string): void;
5
+ export declare function clearLazyRegistry(): void;
6
+ export declare function nextLazyId(): string;
7
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/viewport/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAMnD,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,OAAO,GAAG,IAAI,CAE3E;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,SAAS,CAEtE;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEtD;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAGnC"}
@@ -0,0 +1,19 @@
1
+ const lazyContentRegistry = new Map();
2
+ let lazyIdCounter = 0;
3
+ export function registerLazyContent(id, loader) {
4
+ lazyContentRegistry.set(id, loader);
5
+ }
6
+ export function getLazyContent(id) {
7
+ return lazyContentRegistry.get(id);
8
+ }
9
+ export function unregisterLazyContent(id) {
10
+ lazyContentRegistry.delete(id);
11
+ }
12
+ export function clearLazyRegistry() {
13
+ lazyContentRegistry.clear();
14
+ lazyIdCounter = 0;
15
+ }
16
+ export function nextLazyId() {
17
+ lazyIdCounter += 1;
18
+ return `ek-lazy-${lazyIdCounter}`;
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emberkit/core",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "Lightweight TypeScript-first JSX framework core",