alabjs 0.1.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 (277) hide show
  1. package/dist/adapters/cloudflare.d.ts +31 -0
  2. package/dist/adapters/cloudflare.d.ts.map +1 -0
  3. package/dist/adapters/cloudflare.js +30 -0
  4. package/dist/adapters/cloudflare.js.map +1 -0
  5. package/dist/adapters/deno.d.ts +22 -0
  6. package/dist/adapters/deno.d.ts.map +1 -0
  7. package/dist/adapters/deno.js +21 -0
  8. package/dist/adapters/deno.js.map +1 -0
  9. package/dist/adapters/web.d.ts +47 -0
  10. package/dist/adapters/web.d.ts.map +1 -0
  11. package/dist/adapters/web.js +212 -0
  12. package/dist/adapters/web.js.map +1 -0
  13. package/dist/cli.d.ts +11 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +61 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/client/hooks.d.ts +119 -0
  18. package/dist/client/hooks.d.ts.map +1 -0
  19. package/dist/client/hooks.js +220 -0
  20. package/dist/client/hooks.js.map +1 -0
  21. package/dist/client/hooks.test.d.ts +2 -0
  22. package/dist/client/hooks.test.d.ts.map +1 -0
  23. package/dist/client/hooks.test.js +45 -0
  24. package/dist/client/hooks.test.js.map +1 -0
  25. package/dist/client/index.d.ts +6 -0
  26. package/dist/client/index.d.ts.map +1 -0
  27. package/dist/client/index.js +4 -0
  28. package/dist/client/index.js.map +1 -0
  29. package/dist/client/offline.d.ts +52 -0
  30. package/dist/client/offline.d.ts.map +1 -0
  31. package/dist/client/offline.js +90 -0
  32. package/dist/client/offline.js.map +1 -0
  33. package/dist/client/provider.d.ts +12 -0
  34. package/dist/client/provider.d.ts.map +1 -0
  35. package/dist/client/provider.js +10 -0
  36. package/dist/client/provider.js.map +1 -0
  37. package/dist/commands/build.d.ts +18 -0
  38. package/dist/commands/build.d.ts.map +1 -0
  39. package/dist/commands/build.js +173 -0
  40. package/dist/commands/build.js.map +1 -0
  41. package/dist/commands/dev.d.ts +8 -0
  42. package/dist/commands/dev.d.ts.map +1 -0
  43. package/dist/commands/dev.js +447 -0
  44. package/dist/commands/dev.js.map +1 -0
  45. package/dist/commands/info.d.ts +6 -0
  46. package/dist/commands/info.d.ts.map +1 -0
  47. package/dist/commands/info.js +92 -0
  48. package/dist/commands/info.js.map +1 -0
  49. package/dist/commands/ssg.d.ts +8 -0
  50. package/dist/commands/ssg.d.ts.map +1 -0
  51. package/dist/commands/ssg.js +124 -0
  52. package/dist/commands/ssg.js.map +1 -0
  53. package/dist/commands/start.d.ts +7 -0
  54. package/dist/commands/start.d.ts.map +1 -0
  55. package/dist/commands/start.js +26 -0
  56. package/dist/commands/start.js.map +1 -0
  57. package/dist/commands/test.d.ts +24 -0
  58. package/dist/commands/test.d.ts.map +1 -0
  59. package/dist/commands/test.js +87 -0
  60. package/dist/commands/test.js.map +1 -0
  61. package/dist/components/ErrorBoundary.d.ts +38 -0
  62. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  63. package/dist/components/ErrorBoundary.js +46 -0
  64. package/dist/components/ErrorBoundary.js.map +1 -0
  65. package/dist/components/Font.d.ts +57 -0
  66. package/dist/components/Font.d.ts.map +1 -0
  67. package/dist/components/Font.js +33 -0
  68. package/dist/components/Font.js.map +1 -0
  69. package/dist/components/Image.d.ts +74 -0
  70. package/dist/components/Image.d.ts.map +1 -0
  71. package/dist/components/Image.js +85 -0
  72. package/dist/components/Image.js.map +1 -0
  73. package/dist/components/Link.d.ts +23 -0
  74. package/dist/components/Link.d.ts.map +1 -0
  75. package/dist/components/Link.js +48 -0
  76. package/dist/components/Link.js.map +1 -0
  77. package/dist/components/Script.d.ts +37 -0
  78. package/dist/components/Script.d.ts.map +1 -0
  79. package/dist/components/Script.js +70 -0
  80. package/dist/components/Script.js.map +1 -0
  81. package/dist/components/index.d.ts +10 -0
  82. package/dist/components/index.d.ts.map +1 -0
  83. package/dist/components/index.js +6 -0
  84. package/dist/components/index.js.map +1 -0
  85. package/dist/i18n/i18n.test.d.ts +2 -0
  86. package/dist/i18n/i18n.test.d.ts.map +1 -0
  87. package/dist/i18n/i18n.test.js +132 -0
  88. package/dist/i18n/i18n.test.js.map +1 -0
  89. package/dist/i18n/index.d.ts +135 -0
  90. package/dist/i18n/index.d.ts.map +1 -0
  91. package/dist/i18n/index.js +189 -0
  92. package/dist/i18n/index.js.map +1 -0
  93. package/dist/index.d.ts +4 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +3 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/router/code-router.d.ts +204 -0
  98. package/dist/router/code-router.d.ts.map +1 -0
  99. package/dist/router/code-router.js +258 -0
  100. package/dist/router/code-router.js.map +1 -0
  101. package/dist/router/code-router.test.d.ts +2 -0
  102. package/dist/router/code-router.test.d.ts.map +1 -0
  103. package/dist/router/code-router.test.js +128 -0
  104. package/dist/router/code-router.test.js.map +1 -0
  105. package/dist/router/index.d.ts +4 -0
  106. package/dist/router/index.d.ts.map +1 -0
  107. package/dist/router/index.js +2 -0
  108. package/dist/router/index.js.map +1 -0
  109. package/dist/router/manifest.d.ts +12 -0
  110. package/dist/router/manifest.d.ts.map +1 -0
  111. package/dist/router/manifest.js +2 -0
  112. package/dist/router/manifest.js.map +1 -0
  113. package/dist/server/app.d.ts +13 -0
  114. package/dist/server/app.d.ts.map +1 -0
  115. package/dist/server/app.js +407 -0
  116. package/dist/server/app.js.map +1 -0
  117. package/dist/server/cache.d.ts +99 -0
  118. package/dist/server/cache.d.ts.map +1 -0
  119. package/dist/server/cache.js +161 -0
  120. package/dist/server/cache.js.map +1 -0
  121. package/dist/server/cache.test.d.ts +2 -0
  122. package/dist/server/cache.test.d.ts.map +1 -0
  123. package/dist/server/cache.test.js +150 -0
  124. package/dist/server/cache.test.js.map +1 -0
  125. package/dist/server/csrf.d.ts +28 -0
  126. package/dist/server/csrf.d.ts.map +1 -0
  127. package/dist/server/csrf.js +66 -0
  128. package/dist/server/csrf.js.map +1 -0
  129. package/dist/server/csrf.test.d.ts +2 -0
  130. package/dist/server/csrf.test.d.ts.map +1 -0
  131. package/dist/server/csrf.test.js +154 -0
  132. package/dist/server/csrf.test.js.map +1 -0
  133. package/dist/server/image.d.ts +18 -0
  134. package/dist/server/image.d.ts.map +1 -0
  135. package/dist/server/image.js +97 -0
  136. package/dist/server/image.js.map +1 -0
  137. package/dist/server/index.d.ts +57 -0
  138. package/dist/server/index.d.ts.map +1 -0
  139. package/dist/server/index.js +58 -0
  140. package/dist/server/index.js.map +1 -0
  141. package/dist/server/middleware.d.ts +53 -0
  142. package/dist/server/middleware.d.ts.map +1 -0
  143. package/dist/server/middleware.js +80 -0
  144. package/dist/server/middleware.js.map +1 -0
  145. package/dist/server/middleware.test.d.ts +2 -0
  146. package/dist/server/middleware.test.d.ts.map +1 -0
  147. package/dist/server/middleware.test.js +125 -0
  148. package/dist/server/middleware.test.js.map +1 -0
  149. package/dist/server/revalidate.d.ts +49 -0
  150. package/dist/server/revalidate.d.ts.map +1 -0
  151. package/dist/server/revalidate.js +62 -0
  152. package/dist/server/revalidate.js.map +1 -0
  153. package/dist/server/revalidate.test.d.ts +2 -0
  154. package/dist/server/revalidate.test.d.ts.map +1 -0
  155. package/dist/server/revalidate.test.js +93 -0
  156. package/dist/server/revalidate.test.js.map +1 -0
  157. package/dist/server/server-fn.test.d.ts +2 -0
  158. package/dist/server/server-fn.test.d.ts.map +1 -0
  159. package/dist/server/server-fn.test.js +105 -0
  160. package/dist/server/server-fn.test.js.map +1 -0
  161. package/dist/server/sitemap.d.ts +9 -0
  162. package/dist/server/sitemap.d.ts.map +1 -0
  163. package/dist/server/sitemap.js +26 -0
  164. package/dist/server/sitemap.js.map +1 -0
  165. package/dist/server/sitemap.test.d.ts +2 -0
  166. package/dist/server/sitemap.test.d.ts.map +1 -0
  167. package/dist/server/sitemap.test.js +61 -0
  168. package/dist/server/sitemap.test.js.map +1 -0
  169. package/dist/server/sse.d.ts +59 -0
  170. package/dist/server/sse.d.ts.map +1 -0
  171. package/dist/server/sse.js +91 -0
  172. package/dist/server/sse.js.map +1 -0
  173. package/dist/server/sse.test.d.ts +2 -0
  174. package/dist/server/sse.test.d.ts.map +1 -0
  175. package/dist/server/sse.test.js +68 -0
  176. package/dist/server/sse.test.js.map +1 -0
  177. package/dist/signals/index.d.ts +101 -0
  178. package/dist/signals/index.d.ts.map +1 -0
  179. package/dist/signals/index.js +149 -0
  180. package/dist/signals/index.js.map +1 -0
  181. package/dist/signals/signals.test.d.ts +2 -0
  182. package/dist/signals/signals.test.d.ts.map +1 -0
  183. package/dist/signals/signals.test.js +146 -0
  184. package/dist/signals/signals.test.js.map +1 -0
  185. package/dist/ssr/html.d.ts +27 -0
  186. package/dist/ssr/html.d.ts.map +1 -0
  187. package/dist/ssr/html.js +107 -0
  188. package/dist/ssr/html.js.map +1 -0
  189. package/dist/ssr/html.test.d.ts +2 -0
  190. package/dist/ssr/html.test.d.ts.map +1 -0
  191. package/dist/ssr/html.test.js +178 -0
  192. package/dist/ssr/html.test.js.map +1 -0
  193. package/dist/ssr/render.d.ts +46 -0
  194. package/dist/ssr/render.d.ts.map +1 -0
  195. package/dist/ssr/render.js +87 -0
  196. package/dist/ssr/render.js.map +1 -0
  197. package/dist/ssr/router-dev.d.ts +60 -0
  198. package/dist/ssr/router-dev.d.ts.map +1 -0
  199. package/dist/ssr/router-dev.js +205 -0
  200. package/dist/ssr/router-dev.js.map +1 -0
  201. package/dist/ssr/router-dev.test.d.ts +2 -0
  202. package/dist/ssr/router-dev.test.d.ts.map +1 -0
  203. package/dist/ssr/router-dev.test.js +189 -0
  204. package/dist/ssr/router-dev.test.js.map +1 -0
  205. package/dist/test/index.d.ts +93 -0
  206. package/dist/test/index.d.ts.map +1 -0
  207. package/dist/test/index.js +146 -0
  208. package/dist/test/index.js.map +1 -0
  209. package/dist/types/index.d.ts +117 -0
  210. package/dist/types/index.d.ts.map +1 -0
  211. package/dist/types/index.js +2 -0
  212. package/dist/types/index.js.map +1 -0
  213. package/dist/types/napi.d.ts +15 -0
  214. package/dist/types/napi.d.ts.map +1 -0
  215. package/dist/types/napi.js +2 -0
  216. package/dist/types/napi.js.map +1 -0
  217. package/package.json +107 -0
  218. package/src/adapters/cloudflare.ts +30 -0
  219. package/src/adapters/deno.ts +21 -0
  220. package/src/adapters/web.ts +259 -0
  221. package/src/cli.ts +68 -0
  222. package/src/client/hooks.test.ts +54 -0
  223. package/src/client/hooks.ts +329 -0
  224. package/src/client/index.ts +5 -0
  225. package/src/client/offline-sw.ts +191 -0
  226. package/src/client/offline.ts +114 -0
  227. package/src/client/provider.tsx +14 -0
  228. package/src/commands/build.ts +201 -0
  229. package/src/commands/dev.ts +509 -0
  230. package/src/commands/info.ts +111 -0
  231. package/src/commands/ssg.ts +177 -0
  232. package/src/commands/start.ts +32 -0
  233. package/src/commands/test.ts +102 -0
  234. package/src/components/ErrorBoundary.tsx +73 -0
  235. package/src/components/Font.tsx +100 -0
  236. package/src/components/Image.tsx +141 -0
  237. package/src/components/Link.tsx +64 -0
  238. package/src/components/Script.tsx +97 -0
  239. package/src/components/index.ts +9 -0
  240. package/src/i18n/i18n.test.tsx +169 -0
  241. package/src/i18n/index.tsx +256 -0
  242. package/src/index.ts +10 -0
  243. package/src/router/code-router.test.ts +146 -0
  244. package/src/router/code-router.tsx +459 -0
  245. package/src/router/index.ts +18 -0
  246. package/src/router/manifest.ts +13 -0
  247. package/src/server/app.ts +466 -0
  248. package/src/server/cache.test.ts +192 -0
  249. package/src/server/cache.ts +195 -0
  250. package/src/server/csrf.test.ts +199 -0
  251. package/src/server/csrf.ts +80 -0
  252. package/src/server/image.ts +112 -0
  253. package/src/server/index.ts +144 -0
  254. package/src/server/middleware.test.ts +151 -0
  255. package/src/server/middleware.ts +95 -0
  256. package/src/server/revalidate.test.ts +106 -0
  257. package/src/server/revalidate.ts +75 -0
  258. package/src/server/server-fn.test.ts +127 -0
  259. package/src/server/sitemap.test.ts +68 -0
  260. package/src/server/sitemap.ts +30 -0
  261. package/src/server/sse.test.ts +81 -0
  262. package/src/server/sse.ts +110 -0
  263. package/src/signals/index.ts +177 -0
  264. package/src/signals/signals.test.ts +164 -0
  265. package/src/ssr/html.test.ts +200 -0
  266. package/src/ssr/html.ts +140 -0
  267. package/src/ssr/render.ts +144 -0
  268. package/src/ssr/router-dev.test.ts +230 -0
  269. package/src/ssr/router-dev.ts +229 -0
  270. package/src/test/index.ts +206 -0
  271. package/src/types/compiler.d.ts +25 -0
  272. package/src/types/index.ts +147 -0
  273. package/src/types/napi.ts +20 -0
  274. package/src/types/plugins.d.ts +3 -0
  275. package/tsconfig.json +11 -0
  276. package/tsconfig.tsbuildinfo +1 -0
  277. package/vitest.config.ts +32 -0
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Build the Google Fonts v2 URL for the requested family + weights.
4
+ * Format: fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap
5
+ */
6
+ function buildGoogleFontsUrl(props) {
7
+ const { family, weights = [400], subsets = ["latin"], display = "swap", italic = false, } = props;
8
+ const encodedFamily = family.replace(/ /g, "+");
9
+ // Google Fonts v2 axis syntax: "ital,wght@0,400;0,700;1,400;1,700"
10
+ const axes = [];
11
+ const sortedWeights = [...weights].sort((a, b) => a - b);
12
+ if (italic) {
13
+ for (const w of sortedWeights)
14
+ axes.push(`0,${w}`);
15
+ for (const w of sortedWeights)
16
+ axes.push(`1,${w}`);
17
+ const axisTag = `ital,wght@${axes.join(";")}`;
18
+ return `https://fonts.googleapis.com/css2?family=${encodedFamily}:${axisTag}&display=${display}&subset=${subsets.join(",")}`;
19
+ }
20
+ const wghtValues = sortedWeights.join(";");
21
+ return `https://fonts.googleapis.com/css2?family=${encodedFamily}:wght@${wghtValues}&display=${display}&subset=${subsets.join(",")}`;
22
+ }
23
+ /**
24
+ * Renders the `<link>` tags needed to load a Google Font.
25
+ *
26
+ * In production (`alab build --self-host-fonts`), the alab Vite plugin
27
+ * replaces this with self-hosted CSS so no Google request is made.
28
+ */
29
+ export function Font(props) {
30
+ const href = buildGoogleFontsUrl(props);
31
+ return (_jsxs(_Fragment, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" }), _jsx("link", { rel: "stylesheet", href: href })] }));
32
+ }
33
+ //# sourceMappingURL=Font.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Font.js","sourceRoot":"","sources":["../../src/components/Font.tsx"],"names":[],"mappings":";AAmDA;;;GAGG;AACH,SAAS,mBAAmB,CAAC,KAAgB;IAC3C,MAAM,EACJ,MAAM,EACN,OAAO,GAAG,CAAC,GAAG,CAAC,EACf,OAAO,GAAG,CAAC,OAAO,CAAC,EACnB,OAAO,GAAG,MAAM,EAChB,MAAM,GAAG,KAAK,GACf,GAAG,KAAK,CAAC;IAEV,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAEhD,mEAAmE;IACnE,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,aAAa,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAEzD,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,MAAM,CAAC,IAAI,aAAa;YAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,aAAa;YAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,aAAa,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,OAAO,4CAA4C,aAAa,IAAI,OAAO,YAAY,OAAO,WAAW,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC/H,CAAC;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,OAAO,4CAA4C,aAAa,SAAS,UAAU,YAAY,OAAO,WAAW,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACvI,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,KAAgB;IACnC,MAAM,IAAI,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAExC,OAAO,CACL,8BAEE,eAAM,GAAG,EAAC,YAAY,EAAC,IAAI,EAAC,8BAA8B,GAAG,EAC7D,eAAM,GAAG,EAAC,YAAY,EAAC,IAAI,EAAC,2BAA2B,EAAC,WAAW,EAAC,WAAW,GAAG,EAElF,eAAM,GAAG,EAAC,YAAY,EAAC,IAAI,EAAE,IAAI,GAAI,IACpC,CACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,74 @@
1
+ export interface ImageProps {
2
+ /** Source path — relative to `/public` or an absolute URL. */
3
+ src: string;
4
+ alt: string;
5
+ /** Intrinsic width in pixels. Used to generate the srcset breakpoints. */
6
+ width: number;
7
+ /** Intrinsic height in pixels. Used to preserve layout before load. */
8
+ height: number;
9
+ /**
10
+ * The `sizes` attribute passed to the `<img>` element.
11
+ * @example "(max-width: 768px) 100vw, 50vw"
12
+ */
13
+ sizes?: string | undefined;
14
+ /**
15
+ * Mark the image as the LCP element. Sets `loading="eager"` and
16
+ * `fetchpriority="high"` — omit the blur-up placeholder to avoid CLS.
17
+ */
18
+ priority?: boolean | undefined;
19
+ /** Additional class names. */
20
+ className?: string | undefined;
21
+ /** Quality 1–100. Defaults to 80. */
22
+ quality?: number | undefined;
23
+ /**
24
+ * Base64-encoded tiny placeholder generated by `generateBlurPlaceholder()`.
25
+ * When provided, the image fades in over the blurred placeholder for an
26
+ * instant-load feel without layout shift.
27
+ */
28
+ blurDataURL?: string | undefined;
29
+ }
30
+ /**
31
+ * Rust-powered optimised image component.
32
+ *
33
+ * - Generates a `srcset` of WebP variants via `/_alabjs/image` (Rust napi).
34
+ * - Blur-up placeholder support: pass `blurDataURL` from `generateBlurPlaceholder()`.
35
+ * - `loading="lazy"` by default; use `priority` for LCP images.
36
+ * - Always sets `width` + `height` to eliminate CLS (Cumulative Layout Shift).
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * import { Image, generateBlurPlaceholder } from "alabjs/components";
41
+ *
42
+ * // In a server function — runs on the server at build/request time:
43
+ * const blur = await generateBlurPlaceholder("/hero.jpg");
44
+ *
45
+ * // In the page component:
46
+ * <Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority blurDataURL={blur} />
47
+ * ```
48
+ */
49
+ export declare function Image({ src, alt, width, height, sizes, priority, className, quality, blurDataURL, }: ImageProps): import("react").DetailedReactHTMLElement<{
50
+ src: string;
51
+ srcSet: string;
52
+ sizes: string;
53
+ alt: string;
54
+ width: number;
55
+ height: number;
56
+ loading: string;
57
+ fetchPriority: string | undefined;
58
+ decoding: string;
59
+ className: string | undefined;
60
+ style: Record<string, string>;
61
+ }, HTMLElement>;
62
+ /**
63
+ * Generate a Base64 blur-up placeholder for an image in `public/`.
64
+ *
65
+ * Calls the Rust napi binding to resize the image to 8px wide and encode it
66
+ * as a tiny WebP, then Base64-encodes it into a data URL ready for `blurDataURL`.
67
+ *
68
+ * Run this in a server function — it reads from disk and must not run in the browser.
69
+ *
70
+ * @param src - Path relative to `public/` (e.g. `"/hero.jpg"`)
71
+ * @param publicDir - Absolute path to the `public/` directory
72
+ */
73
+ export declare function generateBlurPlaceholder(src: string, publicDir: string): Promise<string>;
74
+ //# sourceMappingURL=Image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../src/components/Image.tsx"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAKD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,KAAK,CAAC,EACpB,GAAG,EACH,GAAG,EACH,KAAK,EACL,MAAM,EACN,KAAK,EACL,QAAgB,EAChB,SAAS,EACT,OAAY,EACZ,WAAW,GACZ,EAAE,UAAU;;;;;;;;;;;;gBAwCZ;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
@@ -0,0 +1,85 @@
1
+ import { createElement } from "react";
2
+ // Standard responsive breakpoints (matches Tailwind + common viewport widths).
3
+ const BREAKPOINTS = [320, 640, 750, 828, 1080, 1200, 1920];
4
+ /**
5
+ * Rust-powered optimised image component.
6
+ *
7
+ * - Generates a `srcset` of WebP variants via `/_alabjs/image` (Rust napi).
8
+ * - Blur-up placeholder support: pass `blurDataURL` from `generateBlurPlaceholder()`.
9
+ * - `loading="lazy"` by default; use `priority` for LCP images.
10
+ * - Always sets `width` + `height` to eliminate CLS (Cumulative Layout Shift).
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * import { Image, generateBlurPlaceholder } from "alabjs/components";
15
+ *
16
+ * // In a server function — runs on the server at build/request time:
17
+ * const blur = await generateBlurPlaceholder("/hero.jpg");
18
+ *
19
+ * // In the page component:
20
+ * <Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority blurDataURL={blur} />
21
+ * ```
22
+ */
23
+ export function Image({ src, alt, width, height, sizes, priority = false, className, quality = 80, blurDataURL, }) {
24
+ const q = Math.max(1, Math.min(100, quality));
25
+ const encodedSrc = encodeURIComponent(src);
26
+ // Build srcset: breakpoints ≤ intrinsic width + the intrinsic width itself.
27
+ const widths = Array.from(new Set([...BREAKPOINTS.filter((w) => w < width), width])).sort((a, b) => a - b);
28
+ const srcset = widths
29
+ .map((w) => `/_alabjs/image?src=${encodedSrc}&w=${w}&q=${q}&fmt=webp ${w}w`)
30
+ .join(", ");
31
+ const defaultSrc = `/_alabjs/image?src=${encodedSrc}&w=${width}&q=${q}&fmt=webp`;
32
+ const style = {
33
+ maxWidth: "100%",
34
+ height: "auto",
35
+ };
36
+ // Blur-up: show the tiny placeholder as a CSS background while the real image loads.
37
+ if (blurDataURL && !priority) {
38
+ style["backgroundImage"] = `url(${blurDataURL})`;
39
+ style["backgroundSize"] = "cover";
40
+ style["backgroundPosition"] = "center";
41
+ }
42
+ return createElement("img", {
43
+ src: defaultSrc,
44
+ srcSet: srcset,
45
+ sizes: sizes ?? `${width}px`,
46
+ alt,
47
+ width,
48
+ height,
49
+ loading: priority ? "eager" : "lazy",
50
+ fetchPriority: priority ? "high" : undefined,
51
+ decoding: "async",
52
+ className,
53
+ style,
54
+ });
55
+ }
56
+ /**
57
+ * Generate a Base64 blur-up placeholder for an image in `public/`.
58
+ *
59
+ * Calls the Rust napi binding to resize the image to 8px wide and encode it
60
+ * as a tiny WebP, then Base64-encodes it into a data URL ready for `blurDataURL`.
61
+ *
62
+ * Run this in a server function — it reads from disk and must not run in the browser.
63
+ *
64
+ * @param src - Path relative to `public/` (e.g. `"/hero.jpg"`)
65
+ * @param publicDir - Absolute path to the `public/` directory
66
+ */
67
+ export async function generateBlurPlaceholder(src, publicDir) {
68
+ const { readFile } = await import("node:fs/promises");
69
+ const { resolve } = await import("node:path");
70
+ const safeSrc = src.replace(/\.\./g, "").replace(/^\/+/, "");
71
+ const filePath = resolve(publicDir, safeSrc);
72
+ const input = await readFile(filePath);
73
+ let napi;
74
+ try {
75
+ napi = (await import("@alabjs/compiler"));
76
+ }
77
+ catch {
78
+ // napi not built — return empty string (image still loads, just no blur effect)
79
+ return "";
80
+ }
81
+ const tiny = await napi.optimizeImage(input, 40, 8, null, "webp");
82
+ const b64 = Buffer.from(tiny).toString("base64");
83
+ return `data:image/webp;base64,${b64}`;
84
+ }
85
+ //# sourceMappingURL=Image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Image.js","sourceRoot":"","sources":["../../src/components/Image.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAgCtC,+EAA+E;AAC/E,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAE3D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,KAAK,CAAC,EACpB,GAAG,EACH,GAAG,EACH,KAAK,EACL,MAAM,EACN,KAAK,EACL,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,OAAO,GAAG,EAAE,EACZ,WAAW,GACA;IACX,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAE3C,4EAA4E;IAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CACvB,IAAI,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAC1D,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAExB,MAAM,MAAM,GAAG,MAAM;SAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,UAAU,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC;SAC3E,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,UAAU,GAAG,sBAAsB,UAAU,MAAM,KAAK,MAAM,CAAC,WAAW,CAAC;IAEjF,MAAM,KAAK,GAA2B;QACpC,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,MAAM;KACf,CAAC;IAEF,qFAAqF;IACrF,IAAI,WAAW,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC7B,KAAK,CAAC,iBAAiB,CAAC,GAAG,OAAO,WAAW,GAAG,CAAC;QACjD,KAAK,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC;QAClC,KAAK,CAAC,oBAAoB,CAAC,GAAG,QAAQ,CAAC;IACzC,CAAC;IAED,OAAO,aAAa,CAAC,KAAK,EAAE;QAC1B,GAAG,EAAE,UAAU;QACf,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,KAAK,IAAI,GAAG,KAAK,IAAI;QAC5B,GAAG;QACH,KAAK;QACL,MAAM;QACN,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;QACpC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QAC5C,QAAQ,EAAE,OAAO;QACjB,SAAS;QACT,KAAK;KACN,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,GAAW,EACX,SAAiB;IAEjB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACtD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAE9C,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAE7C,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEvC,IAAI,IAAiH,CAAC;IACtH,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAgB,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,gFAAgF;QAChF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjD,OAAO,0BAA0B,GAAG,EAAE,CAAC;AACzC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { AnchorHTMLAttributes } from "react";
2
+ export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
3
+ href: string;
4
+ /** Prefetch the target page on hover (default: true). */
5
+ prefetch?: boolean;
6
+ }
7
+ declare global {
8
+ interface Window {
9
+ __alabjs_navigate?: (href: string) => Promise<void>;
10
+ }
11
+ }
12
+ /**
13
+ * Client-side navigation link for AlabJS.
14
+ *
15
+ * Intercepts same-origin clicks and swaps the page content without a full
16
+ * browser reload. Falls back to a standard `<a>` navigation when JavaScript
17
+ * is unavailable or when the user holds a modifier key (Cmd/Ctrl/Shift/Alt).
18
+ *
19
+ * On hover (with `prefetch`, default true), the target page is fetched in the
20
+ * background so the browser caches it before the user clicks.
21
+ */
22
+ export declare function Link({ href, children, prefetch, onClick, ...rest }: LinkProps): import("react/jsx-runtime").JSX.Element;
23
+ //# sourceMappingURL=Link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../../src/components/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAc,MAAM,OAAO,CAAC;AAE9D,MAAM,WAAW,SAAU,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACrD;CACF;AAED;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAe,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,2CAuCpF"}
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Client-side navigation link for AlabJS.
4
+ *
5
+ * Intercepts same-origin clicks and swaps the page content without a full
6
+ * browser reload. Falls back to a standard `<a>` navigation when JavaScript
7
+ * is unavailable or when the user holds a modifier key (Cmd/Ctrl/Shift/Alt).
8
+ *
9
+ * On hover (with `prefetch`, default true), the target page is fetched in the
10
+ * background so the browser caches it before the user clicks.
11
+ */
12
+ export function Link({ href, children, prefetch = true, onClick, ...rest }) {
13
+ const isSameOrigin = (url) => {
14
+ if (url.startsWith("/"))
15
+ return true;
16
+ try {
17
+ return new URL(url).origin === window.location.origin;
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ };
23
+ const handleClick = async (e) => {
24
+ // Let the browser handle modifier-key clicks (open in new tab etc.)
25
+ if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
26
+ return;
27
+ if (!isSameOrigin(href))
28
+ return;
29
+ e.preventDefault();
30
+ onClick?.(e);
31
+ if (typeof window.__alabjs_navigate === "function") {
32
+ await window.__alabjs_navigate(href);
33
+ }
34
+ else {
35
+ window.location.href = href;
36
+ }
37
+ };
38
+ const handleMouseEnter = prefetch
39
+ ? () => {
40
+ if (typeof window.__alabjs_navigate === "function") {
41
+ // Fire-and-forget; browser caches the response automatically.
42
+ fetch(href, { priority: "low" }).catch(() => { });
43
+ }
44
+ }
45
+ : undefined;
46
+ return (_jsx("a", { href: href, onClick: handleClick, onMouseEnter: handleMouseEnter, ...rest, children: children }));
47
+ }
48
+ //# sourceMappingURL=Link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/components/Link.tsx"],"names":[],"mappings":";AAcA;;;;;;;;;GASG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,EAAa;IACnF,MAAM,YAAY,GAAG,CAAC,GAAW,EAAW,EAAE;QAC5C,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,EAAE,CAAgC,EAAE,EAAE;QAC7D,oEAAoE;QACpE,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM;YAAE,OAAO;QAC7D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;YAAE,OAAO;QAEhC,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAEb,IAAI,OAAO,MAAM,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;YACnD,MAAM,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,QAAQ;QAC/B,CAAC,CAAC,GAAG,EAAE;YACH,IAAI,OAAO,MAAM,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;gBACnD,8DAA8D;gBAC9D,KAAK,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAiB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QACH,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO,CACL,YAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,KAAM,IAAI,YAC1E,QAAQ,GACP,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { type HTMLAttributes } from "react";
2
+ export interface ScriptProps extends Omit<HTMLAttributes<HTMLScriptElement>, "src"> {
3
+ /** URL of the external script to load. */
4
+ src: string;
5
+ /**
6
+ * Loading strategy:
7
+ * - `"beforeInteractive"` — injected into `<head>` during SSR; blocks page rendering.
8
+ * Use only for scripts that must run before the page is interactive (e.g., analytics init).
9
+ * - `"afterInteractive"` (default) — loaded after the page becomes interactive via a
10
+ * dynamically appended `<script>` tag. Best for tag managers, chat widgets, etc.
11
+ * - `"lazyOnload"` — deferred until the browser is idle (`requestIdleCallback`).
12
+ * Best for low-priority scripts like A/B testing, heatmaps, social embeds.
13
+ */
14
+ strategy?: "beforeInteractive" | "afterInteractive" | "lazyOnload";
15
+ /** Called once the script has loaded successfully. */
16
+ onLoad?: () => void;
17
+ /** Called if the script fails to load. */
18
+ onError?: () => void;
19
+ }
20
+ /**
21
+ * Load a third-party script with strategy control.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * // Analytics — load after page is interactive
26
+ * <Script src="https://analytics.example.com/script.js" strategy="afterInteractive" />
27
+ *
28
+ * // Chat widget — load when browser is idle
29
+ * <Script
30
+ * src="https://cdn.example.com/chat.js"
31
+ * strategy="lazyOnload"
32
+ * onLoad={() => console.log("Chat ready")}
33
+ * />
34
+ * ```
35
+ */
36
+ export declare function Script({ src, strategy, onLoad, onError, ...rest }: ScriptProps): import("react/jsx-runtime").JSX.Element | null;
37
+ //# sourceMappingURL=Script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Script.d.ts","sourceRoot":"","sources":["../../src/components/Script.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAEvD,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC;IACjF,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,mBAAmB,GAAG,kBAAkB,GAAG,YAAY,CAAC;IACnE,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,MAAM,CAAC,EACrB,GAAG,EACH,QAA6B,EAC7B,MAAM,EACN,OAAO,EACP,GAAG,IAAI,EACR,EAAE,WAAW,kDAqDb"}
@@ -0,0 +1,70 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ /**
4
+ * Load a third-party script with strategy control.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * // Analytics — load after page is interactive
9
+ * <Script src="https://analytics.example.com/script.js" strategy="afterInteractive" />
10
+ *
11
+ * // Chat widget — load when browser is idle
12
+ * <Script
13
+ * src="https://cdn.example.com/chat.js"
14
+ * strategy="lazyOnload"
15
+ * onLoad={() => console.log("Chat ready")}
16
+ * />
17
+ * ```
18
+ */
19
+ export function Script({ src, strategy = "afterInteractive", onLoad, onError, ...rest }) {
20
+ // `beforeInteractive` is handled at SSR time by rendering a real <script> tag.
21
+ // The component returns null on the client to avoid duplicate injection.
22
+ if (strategy === "beforeInteractive") {
23
+ // On the server this renders into the HTML stream; on the client we skip it
24
+ // because the script is already in the <head> from SSR.
25
+ if (typeof window !== "undefined")
26
+ return null;
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
28
+ return _jsx("script", { src: src, ...rest });
29
+ }
30
+ // eslint-disable-next-line react-hooks/rules-of-hooks
31
+ useEffect(() => {
32
+ // Skip during SSR (useEffect only runs in the browser).
33
+ const load = () => {
34
+ if (document.querySelector(`script[src="${CSS.escape(src)}"]`)) {
35
+ // Already loaded by a previous render — fire onLoad immediately.
36
+ onLoad?.();
37
+ return;
38
+ }
39
+ const el = document.createElement("script");
40
+ el.src = src;
41
+ el.async = true;
42
+ if (onLoad)
43
+ el.addEventListener("load", onLoad, { once: true });
44
+ if (onError)
45
+ el.addEventListener("error", onError, { once: true });
46
+ // Copy through any extra data-* or other HTML attributes.
47
+ for (const [k, v] of Object.entries(rest)) {
48
+ if (typeof v === "string")
49
+ el.setAttribute(k, v);
50
+ }
51
+ document.head.appendChild(el);
52
+ };
53
+ if (strategy === "lazyOnload") {
54
+ if ("requestIdleCallback" in window) {
55
+ const id = requestIdleCallback(load);
56
+ return () => cancelIdleCallback(id);
57
+ }
58
+ // Fallback for browsers without requestIdleCallback (Safari < 16.4).
59
+ const t = setTimeout(load, 200);
60
+ return () => clearTimeout(t);
61
+ }
62
+ // "afterInteractive" — load immediately in useEffect (after hydration).
63
+ load();
64
+ return undefined;
65
+ // eslint-disable-next-line react-hooks/exhaustive-deps
66
+ }, [src, strategy]);
67
+ // No DOM output — the <script> is appended imperatively.
68
+ return null;
69
+ }
70
+ //# sourceMappingURL=Script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Script.js","sourceRoot":"","sources":["../../src/components/Script.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAuB,MAAM,OAAO,CAAC;AAqBvD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,MAAM,CAAC,EACrB,GAAG,EACH,QAAQ,GAAG,kBAAkB,EAC7B,MAAM,EACN,OAAO,EACP,GAAG,IAAI,EACK;IACZ,+EAA+E;IAC/E,yEAAyE;IACzE,IAAI,QAAQ,KAAK,mBAAmB,EAAE,CAAC;QACrC,4EAA4E;QAC5E,wDAAwD;QACxD,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO,IAAI,CAAC;QAC/C,8DAA8D;QAC9D,OAAO,iBAAQ,GAAG,EAAE,GAAG,KAAO,IAAY,GAAI,CAAC;IACjD,CAAC;IAED,sDAAsD;IACtD,SAAS,CAAC,GAAG,EAAE;QACb,wDAAwD;QACxD,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,IAAI,QAAQ,CAAC,aAAa,CAAC,eAAe,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/D,iEAAiE;gBACjE,MAAM,EAAE,EAAE,CAAC;gBACX,OAAO;YACT,CAAC;YAED,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC5C,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC;YACb,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC;YAChB,IAAI,MAAM;gBAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAChE,IAAI,OAAO;gBAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAEnE,0DAA0D;YAC1D,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1C,IAAI,OAAO,CAAC,KAAK,QAAQ;oBAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACnD,CAAC;YAED,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAChC,CAAC,CAAC;QAEF,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC9B,IAAI,qBAAqB,IAAI,MAAM,EAAE,CAAC;gBACpC,MAAM,EAAE,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBACrC,OAAO,GAAG,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YACtC,CAAC;YACD,qEAAqE;YACrE,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAChC,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC;QAED,wEAAwE;QACxE,IAAI,EAAE,CAAC;QACP,OAAO,SAAS,CAAC;QACnB,uDAAuD;IACvD,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEpB,yDAAyD;IACzD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ export { Image, generateBlurPlaceholder } from "./Image.js";
2
+ export type { ImageProps } from "./Image.js";
3
+ export { Link } from "./Link.js";
4
+ export type { LinkProps } from "./Link.js";
5
+ export { ErrorBoundary } from "./ErrorBoundary.js";
6
+ export { Script } from "./Script.js";
7
+ export type { ScriptProps } from "./Script.js";
8
+ export { Font } from "./Font.js";
9
+ export type { FontProps } from "./Font.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { Image, generateBlurPlaceholder } from "./Image.js";
2
+ export { Link } from "./Link.js";
3
+ export { ErrorBoundary } from "./ErrorBoundary.js";
4
+ export { Script } from "./Script.js";
5
+ export { Font } from "./Font.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=i18n.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.test.d.ts","sourceRoot":"","sources":["../../src/i18n/i18n.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @vitest-environment jsdom
3
+ */
4
+ import { describe, it, expect } from "vitest";
5
+ import { createElement } from "react";
6
+ import { renderToString } from "react-dom/server";
7
+ import { createI18nConfig, LocaleProvider, useLocale, } from "./index.js";
8
+ // ─── createI18nConfig ─────────────────────────────────────────────────────────
9
+ describe("createI18nConfig", () => {
10
+ it("creates a config with the given locales and default", () => {
11
+ const i18n = createI18nConfig({ locales: ["en", "fil"], defaultLocale: "en" });
12
+ expect(i18n.locales).toEqual(["en", "fil"]);
13
+ expect(i18n.defaultLocale).toBe("en");
14
+ });
15
+ it("throws if defaultLocale is not in locales", () => {
16
+ expect(() => createI18nConfig({ locales: ["en"], defaultLocale: "fil" })).toThrow('[alabjs/i18n] defaultLocale "fil" must be in the locales array');
17
+ });
18
+ });
19
+ // ─── detectLocale ─────────────────────────────────────────────────────────────
20
+ describe("detectLocale", () => {
21
+ const i18n = createI18nConfig({
22
+ locales: ["en", "fil", "es"],
23
+ defaultLocale: "en",
24
+ });
25
+ it("detects locale from URL prefix", () => {
26
+ const req = new Request("http://localhost/fil/about");
27
+ expect(i18n.detectLocale(req)).toBe("fil");
28
+ });
29
+ it("detects locale from cookie", () => {
30
+ const req = new Request("http://localhost/about", {
31
+ headers: { cookie: "locale=es" },
32
+ });
33
+ expect(i18n.detectLocale(req)).toBe("es");
34
+ });
35
+ it("detects locale from Accept-Language header", () => {
36
+ const req = new Request("http://localhost/about", {
37
+ headers: { "accept-language": "fil;q=0.9,en;q=0.8" },
38
+ });
39
+ expect(i18n.detectLocale(req)).toBe("fil");
40
+ });
41
+ it("falls back to defaultLocale when nothing matches", () => {
42
+ const req = new Request("http://localhost/about", {
43
+ headers: { "accept-language": "ja;q=0.9,zh;q=0.8" },
44
+ });
45
+ expect(i18n.detectLocale(req)).toBe("en");
46
+ });
47
+ it("URL prefix takes precedence over cookie", () => {
48
+ const req = new Request("http://localhost/es/page", {
49
+ headers: { cookie: "locale=fil" },
50
+ });
51
+ expect(i18n.detectLocale(req)).toBe("es");
52
+ });
53
+ it("cookie takes precedence over Accept-Language", () => {
54
+ const req = new Request("http://localhost/page", {
55
+ headers: {
56
+ cookie: "locale=fil",
57
+ "accept-language": "es;q=0.9",
58
+ },
59
+ });
60
+ expect(i18n.detectLocale(req)).toBe("fil");
61
+ });
62
+ it("ignores unknown cookie locale", () => {
63
+ const req = new Request("http://localhost/page", {
64
+ headers: { cookie: "locale=ja" },
65
+ });
66
+ expect(i18n.detectLocale(req)).toBe("en");
67
+ });
68
+ it("handles Accept-Language with language subtag matching", () => {
69
+ const req = new Request("http://localhost/page", {
70
+ headers: { "accept-language": "en-US,en;q=0.9" },
71
+ });
72
+ expect(i18n.detectLocale(req)).toBe("en");
73
+ });
74
+ });
75
+ // ─── hasLocalePrefix ──────────────────────────────────────────────────────────
76
+ describe("hasLocalePrefix", () => {
77
+ const i18n = createI18nConfig({
78
+ locales: ["en", "fil"],
79
+ defaultLocale: "en",
80
+ });
81
+ it("returns true for paths with locale prefix", () => {
82
+ expect(i18n.hasLocalePrefix("/en/about")).toBe(true);
83
+ expect(i18n.hasLocalePrefix("/fil/page")).toBe(true);
84
+ });
85
+ it("returns false for paths without locale prefix", () => {
86
+ expect(i18n.hasLocalePrefix("/about")).toBe(false);
87
+ expect(i18n.hasLocalePrefix("/")).toBe(false);
88
+ });
89
+ });
90
+ // ─── stripLocale ──────────────────────────────────────────────────────────────
91
+ describe("stripLocale", () => {
92
+ const i18n = createI18nConfig({
93
+ locales: ["en", "fil"],
94
+ defaultLocale: "en",
95
+ });
96
+ it("strips locale prefix", () => {
97
+ expect(i18n.stripLocale("/en/about")).toBe("/about");
98
+ expect(i18n.stripLocale("/fil/page")).toBe("/page");
99
+ });
100
+ it("returns / for locale-only path", () => {
101
+ expect(i18n.stripLocale("/en")).toBe("/");
102
+ });
103
+ it("returns original path when no locale prefix", () => {
104
+ expect(i18n.stripLocale("/about")).toBe("/about");
105
+ });
106
+ });
107
+ // ─── localePath ───────────────────────────────────────────────────────────────
108
+ describe("localePath", () => {
109
+ const i18n = createI18nConfig({ locales: ["en", "fil"], defaultLocale: "en" });
110
+ it("prefixes path with locale", () => {
111
+ expect(i18n.localePath("fil", "/about")).toBe("/fil/about");
112
+ });
113
+ it("handles path without leading slash", () => {
114
+ expect(i18n.localePath("en", "about")).toBe("/en/about");
115
+ });
116
+ });
117
+ // ─── LocaleProvider + useLocale ───────────────────────────────────────────────
118
+ describe("LocaleProvider + useLocale", () => {
119
+ function LocaleDisplay() {
120
+ const locale = useLocale();
121
+ return createElement("span", null, locale);
122
+ }
123
+ it("provides locale to children via context", () => {
124
+ const html = renderToString(createElement(LocaleProvider, { locale: "fil", children: createElement(LocaleDisplay) }));
125
+ expect(html).toContain("fil");
126
+ });
127
+ it("defaults to en when no provider", () => {
128
+ const html = renderToString(createElement(LocaleDisplay));
129
+ expect(html).toContain("en");
130
+ });
131
+ });
132
+ //# sourceMappingURL=i18n.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.test.js","sourceRoot":"","sources":["../../src/i18n/i18n.test.tsx"],"names":[],"mappings":"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"}