@pyreon/zero 0.14.0 → 0.16.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.
Files changed (114) hide show
  1. package/lib/api-routes-Ci0kVmM4.js +146 -0
  2. package/lib/client.js +7 -2
  3. package/lib/csp.js +19 -9
  4. package/lib/env.js +6 -6
  5. package/lib/font.js +3 -3
  6. package/lib/{fs-router-CQ7Zxeca.js → fs-router-MewHc5SB.js} +56 -24
  7. package/lib/i18n-routing.js +112 -1
  8. package/lib/image-plugin.js +4 -0
  9. package/lib/image.js +141 -108
  10. package/lib/index.js +253 -132
  11. package/lib/link.js +1 -49
  12. package/lib/og-image.js +5 -5
  13. package/lib/rolldown-runtime-CjeV3_4I.js +18 -0
  14. package/lib/script.js +115 -74
  15. package/lib/seo.js +186 -15
  16. package/lib/server.js +275 -1247
  17. package/lib/theme.js +1 -50
  18. package/lib/types/config.d.ts +275 -3
  19. package/lib/types/env.d.ts +2 -2
  20. package/lib/types/i18n-routing.d.ts +197 -6
  21. package/lib/types/image.d.ts +105 -5
  22. package/lib/types/index.d.ts +640 -178
  23. package/lib/types/link.d.ts +3 -3
  24. package/lib/types/script.d.ts +78 -6
  25. package/lib/types/seo.d.ts +128 -4
  26. package/lib/types/server.d.ts +603 -77
  27. package/lib/types/theme.d.ts +2 -2
  28. package/lib/vite-plugin-xjWZwudX.js +2454 -0
  29. package/package.json +16 -13
  30. package/src/adapters/bun.ts +20 -1
  31. package/src/adapters/cloudflare.ts +78 -1
  32. package/src/adapters/index.ts +25 -3
  33. package/src/adapters/netlify.ts +63 -1
  34. package/src/adapters/node.ts +25 -1
  35. package/src/adapters/static.ts +26 -1
  36. package/src/adapters/validate.ts +8 -1
  37. package/src/adapters/vercel.ts +76 -1
  38. package/src/adapters/warn-missing-env.ts +49 -0
  39. package/src/app.ts +35 -1
  40. package/src/client.ts +18 -0
  41. package/src/csp.ts +28 -12
  42. package/src/entry-server.ts +55 -5
  43. package/src/env.ts +7 -7
  44. package/src/font.ts +3 -3
  45. package/src/fs-router.ts +123 -4
  46. package/src/i18n-routing.ts +246 -12
  47. package/src/image.tsx +242 -91
  48. package/src/index.ts +4 -4
  49. package/src/isr.ts +24 -6
  50. package/src/manifest.ts +675 -0
  51. package/src/og-image.ts +5 -5
  52. package/src/script.tsx +159 -36
  53. package/src/seo.ts +346 -15
  54. package/src/server.ts +10 -2
  55. package/src/ssg-plugin.ts +1523 -0
  56. package/src/types.ts +329 -19
  57. package/src/vercel-revalidate-handler.ts +204 -0
  58. package/src/vite-plugin.ts +326 -68
  59. package/lib/actions.js.map +0 -1
  60. package/lib/ai.js.map +0 -1
  61. package/lib/api-routes.js.map +0 -1
  62. package/lib/cache.js.map +0 -1
  63. package/lib/client.js.map +0 -1
  64. package/lib/compression.js.map +0 -1
  65. package/lib/config.js.map +0 -1
  66. package/lib/cors.js.map +0 -1
  67. package/lib/csp.js.map +0 -1
  68. package/lib/env.js.map +0 -1
  69. package/lib/favicon.js.map +0 -1
  70. package/lib/font.js.map +0 -1
  71. package/lib/fs-router-3xzp-4Wj.js.map +0 -1
  72. package/lib/fs-router-CQ7Zxeca.js.map +0 -1
  73. package/lib/i18n-routing.js.map +0 -1
  74. package/lib/image-plugin.js.map +0 -1
  75. package/lib/image.js.map +0 -1
  76. package/lib/index.js.map +0 -1
  77. package/lib/link.js.map +0 -1
  78. package/lib/logger.js.map +0 -1
  79. package/lib/meta.js.map +0 -1
  80. package/lib/middleware.js.map +0 -1
  81. package/lib/og-image.js.map +0 -1
  82. package/lib/rate-limit.js.map +0 -1
  83. package/lib/script.js.map +0 -1
  84. package/lib/seo.js.map +0 -1
  85. package/lib/server.js.map +0 -1
  86. package/lib/testing.js.map +0 -1
  87. package/lib/theme.js.map +0 -1
  88. package/lib/types/actions.d.ts.map +0 -1
  89. package/lib/types/ai.d.ts.map +0 -1
  90. package/lib/types/api-routes.d.ts.map +0 -1
  91. package/lib/types/cache.d.ts.map +0 -1
  92. package/lib/types/client.d.ts.map +0 -1
  93. package/lib/types/compression.d.ts.map +0 -1
  94. package/lib/types/config.d.ts.map +0 -1
  95. package/lib/types/cors.d.ts.map +0 -1
  96. package/lib/types/csp.d.ts.map +0 -1
  97. package/lib/types/env.d.ts.map +0 -1
  98. package/lib/types/favicon.d.ts.map +0 -1
  99. package/lib/types/font.d.ts.map +0 -1
  100. package/lib/types/i18n-routing.d.ts.map +0 -1
  101. package/lib/types/image-plugin.d.ts.map +0 -1
  102. package/lib/types/image.d.ts.map +0 -1
  103. package/lib/types/index.d.ts.map +0 -1
  104. package/lib/types/link.d.ts.map +0 -1
  105. package/lib/types/logger.d.ts.map +0 -1
  106. package/lib/types/meta.d.ts.map +0 -1
  107. package/lib/types/middleware.d.ts.map +0 -1
  108. package/lib/types/og-image.d.ts.map +0 -1
  109. package/lib/types/rate-limit.d.ts.map +0 -1
  110. package/lib/types/script.d.ts.map +0 -1
  111. package/lib/types/seo.d.ts.map +0 -1
  112. package/lib/types/server.d.ts.map +0 -1
  113. package/lib/types/testing.d.ts.map +0 -1
  114. package/lib/types/theme.d.ts.map +0 -1
package/lib/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createContext, createRef, onMount, onUnmount } from "@pyreon/core";
2
2
  import { effect, signal } from "@pyreon/reactivity";
3
+ import { jsx, jsxs } from "@pyreon/core/jsx-runtime";
3
4
  import { useRouter } from "@pyreon/router";
4
5
  import { useHead } from "@pyreon/head";
5
6
 
@@ -27,83 +28,37 @@ function useIntersectionObserver(getElement, onIntersect, rootMargin = "200px")
27
28
  });
28
29
  }
29
30
 
30
- //#endregion
31
- //#region ../../core/core/lib/jsx-runtime.js
32
- /**
33
- * Hyperscript function — the compiled output of JSX.
34
- * `<div class="x">hello</div>` → `h("div", { class: "x" }, "hello")`
35
- *
36
- * Generic on P so TypeScript validates props match the component's signature
37
- * at the call site, then stores the result in the loosely-typed VNode.
38
- */
39
- /** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */
40
- const EMPTY_PROPS = {};
41
- function h(type, props, ...children) {
42
- return {
43
- type,
44
- props: props ?? EMPTY_PROPS,
45
- children: normalizeChildren(children),
46
- key: props?.key ?? null
47
- };
48
- }
49
- function normalizeChildren(children) {
50
- for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
51
- return children;
52
- }
53
- function flattenChildren(children) {
54
- const result = [];
55
- for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));
56
- else result.push(child);
57
- return result;
58
- }
59
- /**
60
- * JSX automatic runtime.
61
- *
62
- * When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
63
- * rewrites JSX to imports from this file automatically:
64
- * <div class="x" /> → jsx("div", { class: "x" })
65
- */
66
- function jsx(type, props, key) {
67
- const { children, ...rest } = props;
68
- const propsWithKey = key != null ? {
69
- ...rest,
70
- key
71
- } : rest;
72
- if (typeof type === "function") return h(type, children !== void 0 ? {
73
- ...propsWithKey,
74
- children
75
- } : propsWithKey);
76
- return h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);
77
- }
78
- const jsxs = jsx;
79
-
80
31
  //#endregion
81
32
  //#region src/image.tsx
82
33
  /**
83
- * Optimized image component with lazy loading, responsive images,
84
- * multi-format <picture> support, and blur-up placeholders.
34
+ * Composable that provides all image optimization behavior lazy loading,
35
+ * srcset/sizes resolution, format selection, blur-placeholder state,
36
+ * load tracking.
85
37
  *
86
- * @example
87
- * // With imagePlugin spread the import directly
88
- * import hero from "./hero.jpg?optimize"
89
- * <Image {...hero} alt="Hero" priority />
38
+ * Use this for full control when `createImage` is too opinionated about
39
+ * the surrounding markup (e.g. custom container layouts, non-`<div>`
40
+ * wrappers, additional overlay elements).
90
41
  *
91
42
  * @example
92
- * // Manual usage
93
- * <Image src="/hero.jpg" alt="Hero" width={1200} height={630} />
43
+ * function MyImage(props: ImageProps) {
44
+ * const img = useImage(props)
45
+ * return (
46
+ * <figure ref={img.containerRef} style={img.containerStyle}>
47
+ * <img
48
+ * src={img.src}
49
+ * srcSet={img.srcSet}
50
+ * sizes={img.sizes}
51
+ * alt={props.alt}
52
+ * loading={img.loading}
53
+ * onLoad={img.handleLoad}
54
+ * style={img.imageStyle}
55
+ * />
56
+ * <figcaption>{props.alt}</figcaption>
57
+ * </figure>
58
+ * )
59
+ * }
94
60
  */
95
- function Image(props) {
96
- if (props.raw) return /* @__PURE__ */ jsx("img", {
97
- src: props.src,
98
- alt: props.alt,
99
- width: props.width,
100
- height: props.height,
101
- class: props.class,
102
- style: props.style,
103
- decoding: props.decoding ?? "async",
104
- loading: props.loading ?? "lazy",
105
- fetchPriority: props.priority ? "high" : void 0
106
- });
61
+ function useImage(props) {
107
62
  const isEager = props.priority || props.loading === "eager";
108
63
  const loaded = signal(isEager);
109
64
  const inView = signal(isEager);
@@ -111,7 +66,7 @@ function Image(props) {
111
66
  const resolvedSrcset = typeof props.srcset === "string" ? props.srcset : props.srcset?.map((s) => `${s.src} ${s.width}w`).join(", ");
112
67
  const sizes = props.sizes ?? "100vw";
113
68
  const fit = props.fit ?? "cover";
114
- const hasFormats = props.formats && props.formats.length > 0;
69
+ const hasFormats = !!(props.formats && props.formats.length > 0);
115
70
  const aspectRatio = `${props.width} / ${props.height}`;
116
71
  if (!isEager) useIntersectionObserver(() => containerRef.current ?? void 0, () => inView.set(true));
117
72
  const containerStyle = [
@@ -122,53 +77,131 @@ function Image(props) {
122
77
  "width: 100%",
123
78
  props.style
124
79
  ].filter(Boolean).join("; ");
125
- const imgEl = /* @__PURE__ */ jsx("img", {
80
+ const imageStyle = () => [
81
+ "display: block",
82
+ "width: 100%",
83
+ "height: 100%",
84
+ `object-fit: ${fit}`,
85
+ "transition: opacity 0.3s ease",
86
+ props.placeholder && !loaded() ? "opacity: 0" : "opacity: 1"
87
+ ].join("; ");
88
+ const placeholderStyle = () => [
89
+ "position: absolute",
90
+ "inset: 0",
91
+ "width: 100%",
92
+ "height: 100%",
93
+ "object-fit: cover",
94
+ "filter: blur(20px)",
95
+ "transform: scale(1.1)",
96
+ "transition: opacity 0.4s ease",
97
+ loaded() ? "opacity: 0; pointer-events: none" : "opacity: 1"
98
+ ].join("; ");
99
+ return {
100
+ containerRef,
101
+ inView,
102
+ loaded,
126
103
  src: () => inView() ? props.src : "",
127
104
  srcSet: () => !hasFormats && inView() && resolvedSrcset ? resolvedSrcset : "",
128
105
  sizes: resolvedSrcset ? sizes : void 0,
129
- alt: props.alt,
130
- width: props.width,
131
- height: props.height,
106
+ aspectRatio,
107
+ containerStyle,
108
+ imageStyle,
109
+ placeholderStyle,
132
110
  loading: isEager ? "eager" : "lazy",
133
- decoding: props.decoding ?? "async",
134
111
  fetchPriority: props.priority ? "high" : void 0,
135
- onLoad: () => loaded.set(true),
136
- style: () => [
137
- "display: block",
138
- "width: 100%",
139
- "height: 100%",
140
- `object-fit: ${fit}`,
141
- "transition: opacity 0.3s ease",
142
- props.placeholder && !loaded() ? "opacity: 0" : "opacity: 1"
143
- ].join("; ")
144
- });
145
- return /* @__PURE__ */ jsxs("div", {
146
- ref: containerRef,
147
- class: props.class,
148
- style: containerStyle,
149
- children: [props.placeholder && /* @__PURE__ */ jsx("img", {
112
+ handleLoad: () => loaded.set(true),
113
+ formats: props.formats,
114
+ hasFormats
115
+ };
116
+ }
117
+ /**
118
+ * Higher-order component that wraps any component with image optimization.
119
+ *
120
+ * The wrapped component receives {@link ImageRenderProps} with the pre-rendered
121
+ * `image` JSX (bare `<img>` OR `<picture>` tree depending on formats), the
122
+ * pre-rendered `placeholder` JSX, and the container ref + styles. Consumers
123
+ * compose those pieces with whatever wrapper element / layout they want.
124
+ *
125
+ * @example
126
+ * // Custom figure-based image with caption
127
+ * const FigureImage = createImage((props) => (
128
+ * <figure ref={props.containerRef} class={props.class} style={props.containerStyle}>
129
+ * {props.placeholder}
130
+ * {props.image}
131
+ * <figcaption>Caption goes here</figcaption>
132
+ * </figure>
133
+ * ))
134
+ *
135
+ * // Usage — identical to default <Image>
136
+ * <FigureImage src="/hero.jpg" alt="Hero" width={1200} height={630} />
137
+ */
138
+ function createImage(Component) {
139
+ return function WrappedImage(props) {
140
+ if (props.raw) return /* @__PURE__ */ jsx("img", {
141
+ src: props.src,
142
+ alt: props.alt,
143
+ width: props.width,
144
+ height: props.height,
145
+ class: props.class,
146
+ style: props.style,
147
+ decoding: props.decoding ?? "async",
148
+ loading: props.loading ?? "lazy",
149
+ fetchPriority: props.priority ? "high" : void 0
150
+ });
151
+ const img = useImage(props);
152
+ const imgEl = /* @__PURE__ */ jsx("img", {
153
+ src: img.src,
154
+ srcSet: img.srcSet,
155
+ sizes: img.sizes,
156
+ alt: props.alt,
157
+ width: props.width,
158
+ height: props.height,
159
+ loading: img.loading,
160
+ decoding: props.decoding ?? "async",
161
+ fetchPriority: img.fetchPriority,
162
+ onLoad: img.handleLoad,
163
+ style: img.imageStyle
164
+ });
165
+ const placeholderEl = props.placeholder ? /* @__PURE__ */ jsx("img", {
150
166
  src: props.placeholder,
151
167
  alt: "",
152
168
  "aria-hidden": "true",
153
169
  loading: "eager",
154
- style: () => [
155
- "position: absolute",
156
- "inset: 0",
157
- "width: 100%",
158
- "height: 100%",
159
- "object-fit: cover",
160
- "filter: blur(20px)",
161
- "transform: scale(1.1)",
162
- "transition: opacity 0.4s ease",
163
- loaded() ? "opacity: 0; pointer-events: none" : "opacity: 1"
164
- ].join("; ")
165
- }), hasFormats ? /* @__PURE__ */ jsxs("picture", { children: [props.formats?.map((fmt) => /* @__PURE__ */ jsx("source", {
170
+ style: img.placeholderStyle
171
+ }) : null;
172
+ const imageEl = img.hasFormats ? /* @__PURE__ */ jsxs("picture", { children: [img.formats?.map((fmt) => /* @__PURE__ */ jsx("source", {
166
173
  type: fmt.type,
167
- srcSet: () => inView() ? fmt.srcset ?? "" : "",
168
- sizes
169
- })), imgEl] }) : imgEl]
170
- });
174
+ srcSet: () => img.inView() ? fmt.srcset ?? "" : "",
175
+ sizes: img.sizes
176
+ })), imgEl] }) : imgEl;
177
+ return /* @__PURE__ */ jsx(Component, {
178
+ containerRef: img.containerRef,
179
+ class: props.class,
180
+ containerStyle: img.containerStyle,
181
+ placeholder: placeholderEl,
182
+ image: imageEl
183
+ });
184
+ };
171
185
  }
186
+ /**
187
+ * Default optimized image component with lazy loading, responsive srcset,
188
+ * `<picture>` multi-format support, and blur-up placeholders.
189
+ *
190
+ * @example
191
+ * // With imagePlugin — spread the import directly
192
+ * import hero from "./hero.jpg?optimize"
193
+ * <Image {...hero} alt="Hero" priority />
194
+ *
195
+ * @example
196
+ * // Manual usage
197
+ * <Image src="/hero.jpg" alt="Hero" width={1200} height={630} />
198
+ */
199
+ const Image = createImage((props) => /* @__PURE__ */ jsxs("div", {
200
+ ref: props.containerRef,
201
+ class: props.class,
202
+ style: props.containerStyle,
203
+ children: [props.placeholder, props.image]
204
+ }));
172
205
 
173
206
  //#endregion
174
207
  //#region src/link.tsx
@@ -355,36 +388,67 @@ const Link = createLink((props) => /* @__PURE__ */ jsx("a", {
355
388
  //#endregion
356
389
  //#region src/script.tsx
357
390
  /**
358
- * Optimized script loading component.
359
- *
360
- * @example
361
- * // Load analytics after page is interactive
362
- * <Script src="https://analytics.example.com/script.js" strategy="onIdle" />
391
+ * Composable that provides all script loading behavior — strategy state
392
+ * machine (afterHydration / onIdle / onInteraction / onViewport),
393
+ * deduplication, load/error tracking.
363
394
  *
364
- * // Load chat widget when user scrolls
365
- * <Script src="/chat-widget.js" strategy="onViewport" />
395
+ * Returns reactive signals (`loaded`, `errored`, `pending`) so consumers
396
+ * can render loading indicators, retry buttons, or analytics-readiness
397
+ * gates without re-implementing the strategy machine.
366
398
  *
367
- * // Inline script with deferred execution
368
- * <Script strategy="afterHydration">
369
- * {`console.log("App hydrated!")`}
370
- * <\/Script>
399
+ * @example
400
+ * function MyScript(props: ScriptProps) {
401
+ * const s = useScript(props)
402
+ * return (
403
+ * <>
404
+ * {() => s.loaded() ? <Analytics /> : <Skeleton />}
405
+ * {() => s.needsSentinel && <div ref={s.sentinelRef} style="width:0;height:0" />}
406
+ * </>
407
+ * )
408
+ * }
371
409
  */
372
- function Script(props) {
410
+ function useScript(props) {
411
+ const strategy = props.strategy ?? "afterHydration";
412
+ const loaded = signal(false);
413
+ const errored = signal(false);
414
+ const pending = signal(strategy !== "beforeHydration" && strategy !== "afterHydration");
415
+ const sentinelRef = strategy === "onViewport" ? createRef() : void 0;
373
416
  function loadScript() {
374
417
  if (typeof document === "undefined") return;
375
- if (props.id && document.getElementById(props.id)) return;
418
+ if (props.id && document.getElementById(props.id)) {
419
+ loaded.set(true);
420
+ pending.set(false);
421
+ return;
422
+ }
376
423
  const script = document.createElement("script");
377
424
  if (props.src) script.src = props.src;
378
425
  if (props.id) script.id = props.id;
379
426
  script.async = props.async !== false;
380
- if (props.onLoad) script.onload = props.onLoad;
381
- if (props.onError) script.onerror = () => props.onError?.(/* @__PURE__ */ new Error(`Failed to load: ${props.src}`));
382
- if (props.children && !props.src) script.textContent = props.children;
427
+ script.onload = () => {
428
+ loaded.set(true);
429
+ pending.set(false);
430
+ props.onLoad?.();
431
+ };
432
+ script.onerror = () => {
433
+ errored.set(true);
434
+ pending.set(false);
435
+ props.onError?.(/* @__PURE__ */ new Error(`Failed to load: ${props.src}`));
436
+ };
437
+ if (props.children && !props.src) {
438
+ script.textContent = props.children;
439
+ setTimeout(() => {
440
+ loaded.set(true);
441
+ pending.set(false);
442
+ }, 0);
443
+ }
383
444
  document.head.appendChild(script);
384
445
  }
385
446
  onMount(() => {
386
- switch (props.strategy ?? "afterHydration") {
387
- case "beforeHydration": break;
447
+ switch (strategy) {
448
+ case "beforeHydration":
449
+ loaded.set(true);
450
+ pending.set(false);
451
+ break;
388
452
  case "afterHydration":
389
453
  loadScript();
390
454
  break;
@@ -415,15 +479,72 @@ function Script(props) {
415
479
  case "onViewport": break;
416
480
  }
417
481
  });
418
- const sentinelRef = createRef();
419
- const strategy = props.strategy ?? "afterHydration";
420
482
  if (strategy === "onViewport") useIntersectionObserver(() => sentinelRef.current ?? void 0, () => loadScript());
421
- if (strategy === "onViewport") return /* @__PURE__ */ jsx("div", {
422
- ref: sentinelRef,
483
+ return {
484
+ sentinelRef,
485
+ loaded,
486
+ errored,
487
+ pending,
488
+ needsSentinel: strategy === "onViewport",
489
+ load: loadScript
490
+ };
491
+ }
492
+ /**
493
+ * Higher-order component that wraps any component with script load behavior.
494
+ *
495
+ * The wrapped component receives {@link ScriptRenderProps} with the sentinel
496
+ * ref, load-state signals, and a `needsSentinel` flag. Use this when you want
497
+ * to render a loading indicator, retry button, or custom analytics-readiness
498
+ * gate around the script load.
499
+ *
500
+ * @example
501
+ * // Script with a loading indicator
502
+ * const TrackedScript = createScript((props) => (
503
+ * <>
504
+ * {() => props.pending() && <Spinner />}
505
+ * {() => props.errored() && <button onClick={() => location.reload()}>Retry</button>}
506
+ * {props.needsSentinel && <div ref={props.sentinelRef} style="width:0;height:0" />}
507
+ * </>
508
+ * ))
509
+ *
510
+ * <TrackedScript src="/analytics.js" strategy="onIdle" />
511
+ */
512
+ function createScript(Component) {
513
+ return function WrappedScript(props) {
514
+ const s = useScript(props);
515
+ return /* @__PURE__ */ jsx(Component, {
516
+ sentinelRef: s.sentinelRef,
517
+ needsSentinel: s.needsSentinel,
518
+ loaded: s.loaded,
519
+ errored: s.errored,
520
+ pending: s.pending
521
+ });
522
+ };
523
+ }
524
+ /**
525
+ * Default optimized script component. Renders a 0×0 sentinel `<div>` for the
526
+ * `onViewport` strategy (so IntersectionObserver has an element to observe),
527
+ * `null` for every other strategy.
528
+ *
529
+ * @example
530
+ * // Load analytics after page is interactive
531
+ * <Script src="https://analytics.example.com/script.js" strategy="onIdle" />
532
+ *
533
+ * // Load chat widget when user scrolls
534
+ * <Script src="/chat-widget.js" strategy="onViewport" />
535
+ *
536
+ * // Inline script with deferred execution
537
+ * <Script strategy="afterHydration">
538
+ * {`console.log("App hydrated!")`}
539
+ * <\/Script>
540
+ */
541
+ const Script = createScript((props) => {
542
+ if (!props.needsSentinel) return null;
543
+ return /* @__PURE__ */ jsx("div", {
544
+ ref: props.sentinelRef,
423
545
  style: "width:0;height:0;overflow:hidden"
424
546
  });
425
- return null;
426
- }
547
+ });
427
548
 
428
549
  //#endregion
429
550
  //#region src/i18n-routing.ts
@@ -997,5 +1118,5 @@ function aiPlugin(..._) {
997
1118
  }
998
1119
 
999
1120
  //#endregion
1000
- export { Image, Link, Meta, Script, ThemeToggle, aiPlugin, buildLocalePath, buildMetaTags, createLink, createServer, defineConfig, extractLocaleFromPath, faviconPlugin, initTheme, ogImagePlugin, prefetchRoute, resolvedTheme, seoPlugin, setLocale, setSSRThemeDefault, setTheme, theme, themeScript, toggleTheme, useLink, useLocale, validateEnv };
1121
+ export { Image, Link, Meta, Script, ThemeToggle, aiPlugin, buildLocalePath, buildMetaTags, createImage, createLink, createScript, createServer, defineConfig, extractLocaleFromPath, faviconPlugin, initTheme, ogImagePlugin, prefetchRoute, resolvedTheme, seoPlugin, setLocale, setSSRThemeDefault, setTheme, theme, themeScript, toggleTheme, useImage, useLink, useLocale, useScript, validateEnv };
1001
1122
  //# sourceMappingURL=index.js.map
package/lib/link.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createRef, onMount, onUnmount } from "@pyreon/core";
2
2
  import { useRouter } from "@pyreon/router";
3
+ import { jsx } from "@pyreon/core/jsx-runtime";
3
4
 
4
5
  //#region src/utils/use-intersection-observer.ts
5
6
  /**
@@ -25,55 +26,6 @@ function useIntersectionObserver(getElement, onIntersect, rootMargin = "200px")
25
26
  });
26
27
  }
27
28
 
28
- //#endregion
29
- //#region ../../core/core/lib/jsx-runtime.js
30
- /**
31
- * Hyperscript function — the compiled output of JSX.
32
- * `<div class="x">hello</div>` → `h("div", { class: "x" }, "hello")`
33
- *
34
- * Generic on P so TypeScript validates props match the component's signature
35
- * at the call site, then stores the result in the loosely-typed VNode.
36
- */
37
- /** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */
38
- const EMPTY_PROPS = {};
39
- function h(type, props, ...children) {
40
- return {
41
- type,
42
- props: props ?? EMPTY_PROPS,
43
- children: normalizeChildren(children),
44
- key: props?.key ?? null
45
- };
46
- }
47
- function normalizeChildren(children) {
48
- for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
49
- return children;
50
- }
51
- function flattenChildren(children) {
52
- const result = [];
53
- for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));
54
- else result.push(child);
55
- return result;
56
- }
57
- /**
58
- * JSX automatic runtime.
59
- *
60
- * When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
61
- * rewrites JSX to imports from this file automatically:
62
- * <div class="x" /> → jsx("div", { class: "x" })
63
- */
64
- function jsx(type, props, key) {
65
- const { children, ...rest } = props;
66
- const propsWithKey = key != null ? {
67
- ...rest,
68
- key
69
- } : rest;
70
- if (typeof type === "function") return h(type, children !== void 0 ? {
71
- ...propsWithKey,
72
- children
73
- } : propsWithKey);
74
- return h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);
75
- }
76
-
77
29
  //#endregion
78
30
  //#region src/link.tsx
79
31
  const MAX_PREFETCH_CACHE = 200;
package/lib/og-image.js CHANGED
@@ -71,14 +71,14 @@ function buildTextOverlaySvg(layers, width, height, locale) {
71
71
  const lines = [];
72
72
  let currentLine = "";
73
73
  const estimateWidth = (s) => {
74
- let width = 0;
74
+ let w = 0;
75
75
  for (let i = 0; i < s.length; i++) {
76
76
  const code = s.charCodeAt(i);
77
- if (code >= 12288 && code <= 40959) width += fontSize * 1;
78
- else if (code <= 126 && "iljft!|:;.,'".includes(s[i])) width += fontSize * .35;
79
- else width += fontSize * .55;
77
+ if (code >= 12288 && code <= 40959) w += fontSize * 1;
78
+ else if (code <= 126 && "iljft!|:;.,'".includes(s[i])) w += fontSize * .35;
79
+ else w += fontSize * .55;
80
80
  }
81
- return width;
81
+ return w;
82
82
  };
83
83
  for (const word of words) {
84
84
  const testLine = currentLine ? `${currentLine} ${word}` : word;
@@ -0,0 +1,18 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) {
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ }
11
+ if (!no_symbols) {
12
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ }
14
+ return target;
15
+ };
16
+
17
+ //#endregion
18
+ export { __exportAll as t };