@alepha/react 0.14.1 → 0.14.2

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 (68) hide show
  1. package/dist/auth/index.browser.js +1488 -4
  2. package/dist/auth/index.browser.js.map +1 -1
  3. package/dist/auth/index.d.ts +2 -2
  4. package/dist/auth/index.js +1827 -4
  5. package/dist/auth/index.js.map +1 -1
  6. package/dist/core/index.d.ts +54 -937
  7. package/dist/core/index.d.ts.map +1 -1
  8. package/dist/core/index.js +132 -2010
  9. package/dist/core/index.js.map +1 -1
  10. package/dist/form/index.d.ts.map +1 -1
  11. package/dist/form/index.js +6 -1
  12. package/dist/form/index.js.map +1 -1
  13. package/dist/head/index.browser.js +3 -1
  14. package/dist/head/index.browser.js.map +1 -1
  15. package/dist/head/index.d.ts +552 -8
  16. package/dist/head/index.d.ts.map +1 -1
  17. package/dist/head/index.js +15 -1
  18. package/dist/head/index.js.map +1 -1
  19. package/dist/{core → router}/index.browser.js +126 -516
  20. package/dist/router/index.browser.js.map +1 -0
  21. package/dist/router/index.d.ts +1334 -0
  22. package/dist/router/index.d.ts.map +1 -0
  23. package/dist/router/index.js +1939 -0
  24. package/dist/router/index.js.map +1 -0
  25. package/package.json +12 -6
  26. package/src/auth/index.ts +1 -1
  27. package/src/auth/services/ReactAuth.ts +1 -1
  28. package/src/core/components/ClientOnly.tsx +14 -0
  29. package/src/core/components/ErrorBoundary.tsx +3 -2
  30. package/src/core/contexts/AlephaContext.ts +3 -0
  31. package/src/core/contexts/AlephaProvider.tsx +2 -1
  32. package/src/core/index.ts +13 -102
  33. package/src/form/services/FormModel.ts +5 -0
  34. package/src/head/index.ts +16 -7
  35. package/src/head/interfaces/Head.ts +3 -0
  36. package/src/head/providers/HeadProvider.ts +6 -1
  37. package/src/head/providers/ServerHeadProvider.ts +20 -0
  38. package/src/{core → router}/components/ErrorViewer.tsx +2 -0
  39. package/src/router/components/Link.tsx +21 -0
  40. package/src/{core → router}/components/NestedView.tsx +3 -5
  41. package/src/router/components/NotFound.tsx +30 -0
  42. package/src/router/errors/Redirection.ts +28 -0
  43. package/src/{core → router}/hooks/useActive.ts +6 -2
  44. package/src/{core → router}/hooks/useQueryParams.ts +2 -2
  45. package/src/{core → router}/hooks/useRouter.ts +1 -1
  46. package/src/{core → router}/hooks/useRouterState.ts +1 -1
  47. package/src/{core → router}/index.browser.ts +14 -12
  48. package/src/{core/index.shared-router.ts → router/index.shared.ts} +6 -3
  49. package/src/router/index.ts +125 -0
  50. package/src/{core → router}/primitives/$page.ts +1 -1
  51. package/src/{core → router}/providers/ReactBrowserProvider.ts +3 -13
  52. package/src/{core → router}/providers/ReactBrowserRendererProvider.ts +3 -0
  53. package/src/{core → router}/providers/ReactBrowserRouterProvider.ts +3 -0
  54. package/src/{core → router}/providers/ReactPageProvider.ts +5 -3
  55. package/src/{core → router}/providers/ReactServerProvider.ts +9 -28
  56. package/src/{core → router}/services/ReactPageServerService.ts +3 -0
  57. package/src/{core → router}/services/ReactPageService.ts +5 -5
  58. package/src/{core → router}/services/ReactRouter.ts +26 -5
  59. package/dist/core/index.browser.js.map +0 -1
  60. package/dist/core/index.native.js +0 -403
  61. package/dist/core/index.native.js.map +0 -1
  62. package/src/core/components/Link.tsx +0 -18
  63. package/src/core/components/NotFound.tsx +0 -27
  64. package/src/core/errors/Redirection.ts +0 -13
  65. package/src/core/hooks/useSchema.ts +0 -88
  66. package/src/core/index.native.ts +0 -21
  67. package/src/core/index.shared.ts +0 -9
  68. /package/src/{core → router}/contexts/RouterLayerContext.ts +0 -0
@@ -161,7 +161,8 @@ var HeadProvider = class {
161
161
  ...state.head.link ?? [],
162
162
  ...link,
163
163
  ...head.link ?? []
164
- ]
164
+ ],
165
+ script: [...state.head.script ?? [], ...head.script ?? []]
165
166
  };
166
167
  }
167
168
  fillHeadByPage(page, state, props) {
@@ -187,6 +188,7 @@ var HeadProvider = class {
187
188
  };
188
189
  if (head.meta) state.head.meta = [...state.head.meta ?? [], ...head.meta ?? []];
189
190
  if (head.link) state.head.link = [...state.head.link ?? [], ...head.link ?? []];
191
+ if (head.script) state.head.script = [...state.head.script ?? [], ...head.script ?? []];
190
192
  }
191
193
  };
192
194
 
@@ -232,6 +234,7 @@ var ServerHeadProvider = class {
232
234
  else headContent += `<title>${this.escapeHtml(title)}</title>\n`;
233
235
  if (head.meta) for (const meta of head.meta) headContent += this.renderMetaTag(meta);
234
236
  if (head.link) for (const link of head.link) headContent += `<link rel="${this.escapeHtml(link.rel)}" href="${this.escapeHtml(link.href)}">\n`;
237
+ if (head.script) for (const script of head.script) headContent += this.renderScriptTag(script);
235
238
  result = result.replace(/<head([^>]*)>(.*?)<\/head>/is, (_, existingAttrs, existingHead) => `<head${existingAttrs}>${existingHead}${headContent}</head>`);
236
239
  return result.trim();
237
240
  }
@@ -261,6 +264,12 @@ var ServerHeadProvider = class {
261
264
  if (meta.name) return `<meta name="${this.escapeHtml(meta.name)}" content="${this.escapeHtml(meta.content)}">\n`;
262
265
  return "";
263
266
  }
267
+ renderScriptTag(script) {
268
+ return `<script ${Object.entries(script).filter(([, value]) => value !== false).map(([key, value]) => {
269
+ if (value === true) return key;
270
+ return `${key}="${this.escapeHtml(String(value))}"`;
271
+ }).join(" ")}><\/script>\n`;
272
+ }
264
273
  };
265
274
 
266
275
  //#endregion
@@ -405,6 +414,11 @@ const useHead = (options) => {
405
414
  /**
406
415
  * Fill `<head>` server & client side.
407
416
  *
417
+ * Generate SEO-friendly meta tags and titles for your React application using AlephaReactHead module.
418
+ *
419
+ * This module provides services and primitives to manage the document head both on the server and client side,
420
+ * ensuring that your application is optimized for search engines and social media sharing.
421
+ *
408
422
  * @see {@link ServerHeadProvider}
409
423
  * @module alepha.react.head
410
424
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["meta: HeadMeta[]","link: Array<{ rel: string; href: string }>","attrs: Record<string, string>","match: RegExpExecArray | null","attrs: Record<string, string>","metas: HeadMeta[]"],"sources":["../../src/head/helpers/SeoExpander.ts","../../src/head/providers/HeadProvider.ts","../../src/head/primitives/$head.ts","../../src/head/providers/ServerHeadProvider.ts","../../src/head/providers/BrowserHeadProvider.ts","../../src/head/hooks/useHead.ts","../../src/head/index.ts"],"sourcesContent":["import type { Head, HeadMeta } from \"../interfaces/Head.ts\";\n\n/**\n * Expands Head configuration into SEO meta tags.\n *\n * Generates:\n * - `<meta name=\"description\">` from head.description\n * - `<meta property=\"og:*\">` OpenGraph tags\n * - `<meta name=\"twitter:*\">` Twitter Card tags\n *\n * @example\n * ```ts\n * const helper = new SeoExpander();\n * const { meta, link } = helper.expand({\n * title: \"My App\",\n * description: \"Build amazing apps\",\n * image: \"https://example.com/og.png\",\n * url: \"https://example.com/\",\n * });\n * ```\n */\nexport class SeoExpander {\n public expand(head: Head): {\n meta: HeadMeta[];\n link: Array<{ rel: string; href: string }>;\n } {\n const meta: HeadMeta[] = [];\n const link: Array<{ rel: string; href: string }> = [];\n\n // Only expand SEO if there's meaningful content beyond just title\n const hasSeoContent =\n head.description ||\n head.image ||\n head.url ||\n head.siteName ||\n head.locale ||\n head.type ||\n head.og ||\n head.twitter;\n\n if (!hasSeoContent) {\n return { meta, link };\n }\n\n // Base description\n if (head.description) {\n meta.push({ name: \"description\", content: head.description });\n }\n\n // Canonical URL\n if (head.url) {\n link.push({ rel: \"canonical\", href: head.url });\n }\n\n // OpenGraph tags\n this.expandOpenGraph(head, meta);\n\n // Twitter Card tags\n this.expandTwitter(head, meta);\n\n return { meta, link };\n }\n\n protected expandOpenGraph(head: Head, meta: HeadMeta[]): void {\n const ogTitle = head.og?.title ?? head.title;\n const ogDescription = head.og?.description ?? head.description;\n const ogImage = head.og?.image ?? head.image;\n\n if (head.type || ogTitle) {\n meta.push({ property: \"og:type\", content: head.type ?? \"website\" });\n }\n if (head.url) {\n meta.push({ property: \"og:url\", content: head.url });\n }\n if (ogTitle) {\n meta.push({ property: \"og:title\", content: ogTitle });\n }\n if (ogDescription) {\n meta.push({ property: \"og:description\", content: ogDescription });\n }\n if (ogImage) {\n meta.push({ property: \"og:image\", content: ogImage });\n if (head.imageWidth) {\n meta.push({\n property: \"og:image:width\",\n content: String(head.imageWidth),\n });\n }\n if (head.imageHeight) {\n meta.push({\n property: \"og:image:height\",\n content: String(head.imageHeight),\n });\n }\n if (head.imageAlt) {\n meta.push({ property: \"og:image:alt\", content: head.imageAlt });\n }\n }\n if (head.siteName) {\n meta.push({ property: \"og:site_name\", content: head.siteName });\n }\n if (head.locale) {\n meta.push({ property: \"og:locale\", content: head.locale });\n }\n }\n\n protected expandTwitter(head: Head, meta: HeadMeta[]): void {\n const twitterTitle = head.twitter?.title ?? head.title;\n const twitterDescription = head.twitter?.description ?? head.description;\n const twitterImage = head.twitter?.image ?? head.image;\n\n if (head.twitter?.card || twitterTitle || twitterImage) {\n meta.push({\n name: \"twitter:card\",\n content:\n head.twitter?.card ?? (twitterImage ? \"summary_large_image\" : \"summary\"),\n });\n }\n if (head.url) {\n meta.push({ name: \"twitter:url\", content: head.url });\n }\n if (twitterTitle) {\n meta.push({ name: \"twitter:title\", content: twitterTitle });\n }\n if (twitterDescription) {\n meta.push({ name: \"twitter:description\", content: twitterDescription });\n }\n if (twitterImage) {\n meta.push({ name: \"twitter:image\", content: twitterImage });\n if (head.imageAlt) {\n meta.push({ name: \"twitter:image:alt\", content: head.imageAlt });\n }\n }\n if (head.twitter?.site) {\n meta.push({ name: \"twitter:site\", content: head.twitter.site });\n }\n if (head.twitter?.creator) {\n meta.push({ name: \"twitter:creator\", content: head.twitter.creator });\n }\n }\n}\n","import type { PageRoute, ReactRouterState } from \"@alepha/react\";\nimport { $inject } from \"alepha\";\nimport { SeoExpander } from \"../helpers/SeoExpander.ts\";\nimport type { Head } from \"../interfaces/Head.ts\";\n\nexport class HeadProvider {\n protected readonly seoExpander = $inject(SeoExpander);\n\n public global?: Array<Head | (() => Head)> = [];\n\n public fillHead(state: ReactRouterState) {\n state.head = {\n ...state.head,\n };\n\n for (const h of this.global ?? []) {\n const head = typeof h === \"function\" ? h() : h;\n this.mergeHead(state, head);\n }\n\n for (const layer of state.layers) {\n if (layer.route?.head && !layer.error) {\n this.fillHeadByPage(layer.route, state, layer.props ?? {});\n }\n }\n }\n\n protected mergeHead(state: ReactRouterState, head: Head): void {\n // Expand SEO fields into meta tags\n const { meta, link } = this.seoExpander.expand(head);\n state.head = {\n ...state.head,\n ...head,\n meta: [...(state.head.meta ?? []), ...meta, ...(head.meta ?? [])],\n link: [...(state.head.link ?? []), ...link, ...(head.link ?? [])],\n };\n }\n\n protected fillHeadByPage(\n page: PageRoute,\n state: ReactRouterState,\n props: Record<string, any>,\n ): void {\n if (!page.head) {\n return;\n }\n\n state.head ??= {};\n\n const head =\n typeof page.head === \"function\"\n ? page.head(props, state.head)\n : page.head;\n\n // Expand SEO fields into meta tags\n const { meta, link } = this.seoExpander.expand(head);\n state.head.meta = [...(state.head.meta ?? []), ...meta];\n state.head.link = [...(state.head.link ?? []), ...link];\n\n if (head.title) {\n state.head ??= {};\n\n if (state.head.titleSeparator) {\n state.head.title = `${head.title}${state.head.titleSeparator}${state.head.title}`;\n } else {\n state.head.title = head.title;\n }\n\n state.head.titleSeparator = head.titleSeparator;\n }\n\n if (head.htmlAttributes) {\n state.head.htmlAttributes = {\n ...state.head.htmlAttributes,\n ...head.htmlAttributes,\n };\n }\n\n if (head.bodyAttributes) {\n state.head.bodyAttributes = {\n ...state.head.bodyAttributes,\n ...head.bodyAttributes,\n };\n }\n\n if (head.meta) {\n state.head.meta = [...(state.head.meta ?? []), ...(head.meta ?? [])];\n }\n\n if (head.link) {\n state.head.link = [...(state.head.link ?? []), ...(head.link ?? [])];\n }\n }\n}\n","import { $inject, createPrimitive, Primitive, KIND } from \"alepha\";\nimport type { Head } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"../providers/HeadProvider.ts\";\n\n/**\n * Set global `<head>` options for the application.\n */\nexport const $head = (options: HeadPrimitiveOptions) => {\n return createPrimitive(HeadPrimitive, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type HeadPrimitiveOptions = Head | (() => Head);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class HeadPrimitive extends Primitive<HeadPrimitiveOptions> {\n protected readonly provider = $inject(HeadProvider);\n protected onInit() {\n this.provider.global = [\n ...(this.provider.global ?? []),\n this.options,\n ];\n }\n}\n\n$head[KIND] = HeadPrimitive;\n","import { $hook, $inject } from \"alepha\";\nimport { ServerTimingProvider } from \"alepha/server\";\nimport type { HeadMeta, SimpleHead } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"./HeadProvider.ts\";\n\nexport class ServerHeadProvider {\n protected readonly headProvider = $inject(HeadProvider);\n protected readonly serverTimingProvider = $inject(ServerTimingProvider);\n\n protected readonly onServerRenderEnd = $hook({\n on: \"react:server:render:end\",\n handler: async (ev) => {\n this.serverTimingProvider.beginTiming(\"renderHead\");\n this.headProvider.fillHead(ev.state);\n if (ev.state.head) {\n ev.html = this.renderHead(ev.html, ev.state.head);\n }\n this.serverTimingProvider.endTiming(\"renderHead\");\n },\n });\n\n public renderHead(template: string, head: SimpleHead): string {\n let result = template;\n\n // Inject htmlAttributes\n const htmlAttributes = head.htmlAttributes;\n if (htmlAttributes) {\n result = result.replace(\n /<html([^>]*)>/i,\n (_, existingAttrs) =>\n `<html${this.mergeAttributes(existingAttrs, htmlAttributes)}>`,\n );\n }\n\n // Inject bodyAttributes\n const bodyAttributes = head.bodyAttributes;\n if (bodyAttributes) {\n result = result.replace(\n /<body([^>]*)>/i,\n (_, existingAttrs) =>\n `<body${this.mergeAttributes(existingAttrs, bodyAttributes)}>`,\n );\n }\n\n // Build head content\n let headContent = \"\";\n const title = head.title;\n if (title) {\n if (template.includes(\"<title>\")) {\n result = result.replace(\n /<title>(.*?)<\\/title>/i,\n () => `<title>${this.escapeHtml(title)}</title>`,\n );\n } else {\n headContent += `<title>${this.escapeHtml(title)}</title>\\n`;\n }\n }\n\n if (head.meta) {\n for (const meta of head.meta) {\n headContent += this.renderMetaTag(meta);\n }\n }\n\n if (head.link) {\n for (const link of head.link) {\n headContent += `<link rel=\"${this.escapeHtml(link.rel)}\" href=\"${this.escapeHtml(link.href)}\">\\n`;\n }\n }\n\n // Inject into <head>...</head>\n result = result.replace(\n /<head([^>]*)>(.*?)<\\/head>/is,\n (_, existingAttrs, existingHead) =>\n `<head${existingAttrs}>${existingHead}${headContent}</head>`,\n );\n\n return result.trim();\n }\n\n protected mergeAttributes(\n existing: string,\n attrs: Record<string, string>,\n ): string {\n const existingAttrs = this.parseAttributes(existing);\n const merged = { ...existingAttrs, ...attrs };\n return Object.entries(merged)\n .map(([k, v]) => ` ${k}=\"${this.escapeHtml(v)}\"`)\n .join(\"\");\n }\n\n protected parseAttributes(attrStr: string): Record<string, string> {\n attrStr = attrStr.replaceAll(\"'\", '\"');\n\n const attrs: Record<string, string> = {};\n const attrRegex = /([^\\s=]+)(?:=\"([^\"]*)\")?/g;\n let match: RegExpExecArray | null = attrRegex.exec(attrStr);\n\n while (match) {\n attrs[match[1]] = match[2] ?? \"\";\n match = attrRegex.exec(attrStr);\n }\n\n return attrs;\n }\n\n protected escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n }\n\n protected renderMetaTag(meta: HeadMeta): string {\n // OpenGraph tags use property attribute\n if (meta.property) {\n return `<meta property=\"${this.escapeHtml(meta.property)}\" content=\"${this.escapeHtml(meta.content)}\">\\n`;\n }\n // Standard meta tags use name attribute\n if (meta.name) {\n return `<meta name=\"${this.escapeHtml(meta.name)}\" content=\"${this.escapeHtml(meta.content)}\">\\n`;\n }\n return \"\";\n }\n}\n","import { $hook, $inject } from \"alepha\";\nimport type { Head, HeadMeta } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"./HeadProvider.ts\";\n\nexport class BrowserHeadProvider {\n protected readonly headProvider = $inject(HeadProvider);\n\n protected get document(): Document {\n return window.document;\n }\n\n protected readonly onBrowserRender = $hook({\n on: \"react:browser:render\",\n handler: async ({ state }) => {\n this.headProvider.fillHead(state);\n if (state.head) {\n this.renderHead(this.document, state.head);\n }\n },\n });\n\n protected readonly onTransitionEnd = $hook({\n on: \"react:transition:end\",\n handler: async ({ state }) => {\n this.headProvider.fillHead(state);\n if (state.head) {\n this.renderHead(this.document, state.head);\n }\n },\n });\n\n public getHead(document: Document): Head {\n return {\n get title() {\n return document.title;\n },\n get htmlAttributes() {\n const attrs: Record<string, string> = {};\n for (const attr of document.documentElement.attributes) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n },\n get bodyAttributes() {\n const attrs: Record<string, string> = {};\n for (const attr of document.body.attributes) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n },\n get meta() {\n const metas: HeadMeta[] = [];\n // Get meta tags with name attribute\n for (const meta of document.head.querySelectorAll(\"meta[name]\")) {\n const name = meta.getAttribute(\"name\");\n const content = meta.getAttribute(\"content\");\n if (name && content) {\n metas.push({ name, content });\n }\n }\n // Get meta tags with property attribute (OpenGraph)\n for (const meta of document.head.querySelectorAll(\"meta[property]\")) {\n const property = meta.getAttribute(\"property\");\n const content = meta.getAttribute(\"content\");\n if (property && content) {\n metas.push({ property, content });\n }\n }\n return metas;\n },\n };\n }\n\n public renderHead(document: Document, head: Head): void {\n if (head.title) {\n document.title = head.title;\n }\n\n if (head.bodyAttributes) {\n for (const [key, value] of Object.entries(head.bodyAttributes)) {\n if (value) {\n document.body.setAttribute(key, value);\n } else {\n document.body.removeAttribute(key);\n }\n }\n }\n\n if (head.htmlAttributes) {\n for (const [key, value] of Object.entries(head.htmlAttributes)) {\n if (value) {\n document.documentElement.setAttribute(key, value);\n } else {\n document.documentElement.removeAttribute(key);\n }\n }\n }\n\n if (head.meta) {\n for (const it of head.meta) {\n this.renderMetaTag(document, it);\n }\n }\n\n if (head.link) {\n for (const it of head.link) {\n const { rel, href } = it;\n let link = document.querySelector(`link[rel=\"${rel}\"][href=\"${href}\"]`);\n if (!link) {\n link = document.createElement(\"link\");\n link.setAttribute(\"rel\", rel);\n link.setAttribute(\"href\", href);\n document.head.appendChild(link);\n }\n }\n }\n }\n\n protected renderMetaTag(document: Document, meta: HeadMeta): void {\n const { content } = meta;\n\n // Handle OpenGraph tags (property attribute)\n if (meta.property) {\n const existing = document.querySelector(\n `meta[property=\"${meta.property}\"]`,\n );\n if (existing) {\n existing.setAttribute(\"content\", content);\n } else {\n const newMeta = document.createElement(\"meta\");\n newMeta.setAttribute(\"property\", meta.property);\n newMeta.setAttribute(\"content\", content);\n document.head.appendChild(newMeta);\n }\n return;\n }\n\n // Handle standard meta tags (name attribute)\n if (meta.name) {\n const existing = document.querySelector(`meta[name=\"${meta.name}\"]`);\n if (existing) {\n existing.setAttribute(\"content\", content);\n } else {\n const newMeta = document.createElement(\"meta\");\n newMeta.setAttribute(\"name\", meta.name);\n newMeta.setAttribute(\"content\", content);\n document.head.appendChild(newMeta);\n }\n }\n }\n}\n","import { useInject } from \"@alepha/react\";\nimport { Alepha } from \"alepha\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport type { Head } from \"../interfaces/Head.ts\";\nimport { BrowserHeadProvider } from \"../providers/BrowserHeadProvider.ts\";\n\n/**\n * ```tsx\n * const App = () => {\n * const [head, setHead] = useHead({\n * // will set the document title on the first render\n * title: \"My App\",\n * });\n *\n * return (\n * // This will update the document title when the button is clicked\n * <button onClick={() => setHead({ title: \"Change Title\" })}>\n * Change Title {head.title}\n * </button>\n * );\n * }\n * ```\n */\nexport const useHead = (options?: UseHeadOptions): UseHeadReturn => {\n const alepha = useInject(Alepha);\n\n const current = useMemo(() => {\n if (!alepha.isBrowser()) {\n return {};\n }\n\n return alepha.inject(BrowserHeadProvider).getHead(window.document);\n }, []);\n\n const setHead = useCallback((head?: Head | ((previous?: Head) => Head)) => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n alepha\n .inject(BrowserHeadProvider)\n .renderHead(\n window.document,\n typeof head === \"function\" ? head(current) : head || {},\n );\n }, []);\n\n useEffect(() => {\n if (options) {\n setHead(options);\n }\n }, []);\n\n return [current, setHead];\n};\n\nexport type UseHeadOptions = Head | ((previous?: Head) => Head);\n\nexport type UseHeadReturn = [\n Head,\n (head?: Head | ((previous?: Head) => Head)) => void,\n];\n","import {\n AlephaReact,\n type PageConfigSchema,\n type TPropsDefault,\n type TPropsParentDefault,\n} from \"@alepha/react\";\nimport { $module } from \"alepha\";\nimport { $head } from \"./primitives/$head.ts\";\nimport type { Head } from \"./interfaces/Head.ts\";\nimport { ServerHeadProvider } from \"./providers/ServerHeadProvider.ts\";\nimport { HeadProvider } from \"./providers/HeadProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$head.ts\";\nexport * from \"./hooks/useHead.ts\";\nexport * from \"./interfaces/Head.ts\";\nexport * from \"./helpers/SeoExpander.ts\";\nexport * from \"./providers/ServerHeadProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"@alepha/react\" {\n interface PagePrimitiveOptions<\n TConfig extends PageConfigSchema = PageConfigSchema,\n TProps extends object = TPropsDefault,\n TPropsParent extends object = TPropsParentDefault,\n > {\n head?: Head | ((props: TProps, previous?: Head) => Head);\n }\n\n interface ReactRouterState {\n head: Head;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Fill `<head>` server & client side.\n *\n * @see {@link ServerHeadProvider}\n * @module alepha.react.head\n */\nexport const AlephaReactHead = $module({\n name: \"alepha.react.head\",\n primitives: [$head],\n services: [AlephaReact, ServerHeadProvider, HeadProvider],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/head/helpers/SeoExpander.ts","../../src/head/providers/HeadProvider.ts","../../src/head/primitives/$head.ts","../../src/head/providers/ServerHeadProvider.ts","../../src/head/providers/BrowserHeadProvider.ts","../../src/head/hooks/useHead.ts","../../src/head/index.ts"],"sourcesContent":["import type { Head, HeadMeta } from \"../interfaces/Head.ts\";\n\n/**\n * Expands Head configuration into SEO meta tags.\n *\n * Generates:\n * - `<meta name=\"description\">` from head.description\n * - `<meta property=\"og:*\">` OpenGraph tags\n * - `<meta name=\"twitter:*\">` Twitter Card tags\n *\n * @example\n * ```ts\n * const helper = new SeoExpander();\n * const { meta, link } = helper.expand({\n * title: \"My App\",\n * description: \"Build amazing apps\",\n * image: \"https://example.com/og.png\",\n * url: \"https://example.com/\",\n * });\n * ```\n */\nexport class SeoExpander {\n public expand(head: Head): {\n meta: HeadMeta[];\n link: Array<{ rel: string; href: string }>;\n } {\n const meta: HeadMeta[] = [];\n const link: Array<{ rel: string; href: string }> = [];\n\n // Only expand SEO if there's meaningful content beyond just title\n const hasSeoContent =\n head.description ||\n head.image ||\n head.url ||\n head.siteName ||\n head.locale ||\n head.type ||\n head.og ||\n head.twitter;\n\n if (!hasSeoContent) {\n return { meta, link };\n }\n\n // Base description\n if (head.description) {\n meta.push({ name: \"description\", content: head.description });\n }\n\n // Canonical URL\n if (head.url) {\n link.push({ rel: \"canonical\", href: head.url });\n }\n\n // OpenGraph tags\n this.expandOpenGraph(head, meta);\n\n // Twitter Card tags\n this.expandTwitter(head, meta);\n\n return { meta, link };\n }\n\n protected expandOpenGraph(head: Head, meta: HeadMeta[]): void {\n const ogTitle = head.og?.title ?? head.title;\n const ogDescription = head.og?.description ?? head.description;\n const ogImage = head.og?.image ?? head.image;\n\n if (head.type || ogTitle) {\n meta.push({ property: \"og:type\", content: head.type ?? \"website\" });\n }\n if (head.url) {\n meta.push({ property: \"og:url\", content: head.url });\n }\n if (ogTitle) {\n meta.push({ property: \"og:title\", content: ogTitle });\n }\n if (ogDescription) {\n meta.push({ property: \"og:description\", content: ogDescription });\n }\n if (ogImage) {\n meta.push({ property: \"og:image\", content: ogImage });\n if (head.imageWidth) {\n meta.push({\n property: \"og:image:width\",\n content: String(head.imageWidth),\n });\n }\n if (head.imageHeight) {\n meta.push({\n property: \"og:image:height\",\n content: String(head.imageHeight),\n });\n }\n if (head.imageAlt) {\n meta.push({ property: \"og:image:alt\", content: head.imageAlt });\n }\n }\n if (head.siteName) {\n meta.push({ property: \"og:site_name\", content: head.siteName });\n }\n if (head.locale) {\n meta.push({ property: \"og:locale\", content: head.locale });\n }\n }\n\n protected expandTwitter(head: Head, meta: HeadMeta[]): void {\n const twitterTitle = head.twitter?.title ?? head.title;\n const twitterDescription = head.twitter?.description ?? head.description;\n const twitterImage = head.twitter?.image ?? head.image;\n\n if (head.twitter?.card || twitterTitle || twitterImage) {\n meta.push({\n name: \"twitter:card\",\n content:\n head.twitter?.card ?? (twitterImage ? \"summary_large_image\" : \"summary\"),\n });\n }\n if (head.url) {\n meta.push({ name: \"twitter:url\", content: head.url });\n }\n if (twitterTitle) {\n meta.push({ name: \"twitter:title\", content: twitterTitle });\n }\n if (twitterDescription) {\n meta.push({ name: \"twitter:description\", content: twitterDescription });\n }\n if (twitterImage) {\n meta.push({ name: \"twitter:image\", content: twitterImage });\n if (head.imageAlt) {\n meta.push({ name: \"twitter:image:alt\", content: head.imageAlt });\n }\n }\n if (head.twitter?.site) {\n meta.push({ name: \"twitter:site\", content: head.twitter.site });\n }\n if (head.twitter?.creator) {\n meta.push({ name: \"twitter:creator\", content: head.twitter.creator });\n }\n }\n}\n","import type { PageRoute, ReactRouterState } from \"@alepha/react/router\";\nimport { $inject } from \"alepha\";\nimport { SeoExpander } from \"../helpers/SeoExpander.ts\";\nimport type { Head } from \"../interfaces/Head.ts\";\n\nexport class HeadProvider {\n protected readonly seoExpander = $inject(SeoExpander);\n\n public global?: Array<Head | (() => Head)> = [];\n\n public fillHead(state: ReactRouterState) {\n state.head = {\n ...state.head,\n };\n\n for (const h of this.global ?? []) {\n const head = typeof h === \"function\" ? h() : h;\n this.mergeHead(state, head);\n }\n\n for (const layer of state.layers) {\n if (layer.route?.head && !layer.error) {\n this.fillHeadByPage(layer.route, state, layer.props ?? {});\n }\n }\n }\n\n protected mergeHead(state: ReactRouterState, head: Head): void {\n // Expand SEO fields into meta tags\n const { meta, link } = this.seoExpander.expand(head);\n state.head = {\n ...state.head,\n ...head,\n meta: [...(state.head.meta ?? []), ...meta, ...(head.meta ?? [])],\n link: [...(state.head.link ?? []), ...link, ...(head.link ?? [])],\n script: [...(state.head.script ?? []), ...(head.script ?? [])],\n };\n }\n\n protected fillHeadByPage(\n page: PageRoute,\n state: ReactRouterState,\n props: Record<string, any>,\n ): void {\n if (!page.head) {\n return;\n }\n\n state.head ??= {};\n\n const head =\n typeof page.head === \"function\"\n ? page.head(props, state.head)\n : page.head;\n\n // Expand SEO fields into meta tags\n const { meta, link } = this.seoExpander.expand(head);\n state.head.meta = [...(state.head.meta ?? []), ...meta];\n state.head.link = [...(state.head.link ?? []), ...link];\n\n if (head.title) {\n state.head ??= {};\n\n if (state.head.titleSeparator) {\n state.head.title = `${head.title}${state.head.titleSeparator}${state.head.title}`;\n } else {\n state.head.title = head.title;\n }\n\n state.head.titleSeparator = head.titleSeparator;\n }\n\n if (head.htmlAttributes) {\n state.head.htmlAttributes = {\n ...state.head.htmlAttributes,\n ...head.htmlAttributes,\n };\n }\n\n if (head.bodyAttributes) {\n state.head.bodyAttributes = {\n ...state.head.bodyAttributes,\n ...head.bodyAttributes,\n };\n }\n\n if (head.meta) {\n state.head.meta = [...(state.head.meta ?? []), ...(head.meta ?? [])];\n }\n\n if (head.link) {\n state.head.link = [...(state.head.link ?? []), ...(head.link ?? [])];\n }\n\n if (head.script) {\n state.head.script = [...(state.head.script ?? []), ...(head.script ?? [])];\n }\n }\n}\n","import { $inject, createPrimitive, Primitive, KIND } from \"alepha\";\nimport type { Head } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"../providers/HeadProvider.ts\";\n\n/**\n * Set global `<head>` options for the application.\n */\nexport const $head = (options: HeadPrimitiveOptions) => {\n return createPrimitive(HeadPrimitive, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type HeadPrimitiveOptions = Head | (() => Head);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class HeadPrimitive extends Primitive<HeadPrimitiveOptions> {\n protected readonly provider = $inject(HeadProvider);\n protected onInit() {\n this.provider.global = [\n ...(this.provider.global ?? []),\n this.options,\n ];\n }\n}\n\n$head[KIND] = HeadPrimitive;\n","import { $hook, $inject } from \"alepha\";\nimport { ServerTimingProvider } from \"alepha/server\";\nimport type { HeadMeta, SimpleHead } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"./HeadProvider.ts\";\n\nexport class ServerHeadProvider {\n protected readonly headProvider = $inject(HeadProvider);\n protected readonly serverTimingProvider = $inject(ServerTimingProvider);\n\n protected readonly onServerRenderEnd = $hook({\n on: \"react:server:render:end\",\n handler: async (ev) => {\n this.serverTimingProvider.beginTiming(\"renderHead\");\n this.headProvider.fillHead(ev.state);\n if (ev.state.head) {\n ev.html = this.renderHead(ev.html, ev.state.head);\n }\n this.serverTimingProvider.endTiming(\"renderHead\");\n },\n });\n\n public renderHead(template: string, head: SimpleHead): string {\n let result = template;\n\n // Inject htmlAttributes\n const htmlAttributes = head.htmlAttributes;\n if (htmlAttributes) {\n result = result.replace(\n /<html([^>]*)>/i,\n (_, existingAttrs) =>\n `<html${this.mergeAttributes(existingAttrs, htmlAttributes)}>`,\n );\n }\n\n // Inject bodyAttributes\n const bodyAttributes = head.bodyAttributes;\n if (bodyAttributes) {\n result = result.replace(\n /<body([^>]*)>/i,\n (_, existingAttrs) =>\n `<body${this.mergeAttributes(existingAttrs, bodyAttributes)}>`,\n );\n }\n\n // Build head content\n let headContent = \"\";\n const title = head.title;\n if (title) {\n if (template.includes(\"<title>\")) {\n result = result.replace(\n /<title>(.*?)<\\/title>/i,\n () => `<title>${this.escapeHtml(title)}</title>`,\n );\n } else {\n headContent += `<title>${this.escapeHtml(title)}</title>\\n`;\n }\n }\n\n if (head.meta) {\n for (const meta of head.meta) {\n headContent += this.renderMetaTag(meta);\n }\n }\n\n if (head.link) {\n for (const link of head.link) {\n headContent += `<link rel=\"${this.escapeHtml(link.rel)}\" href=\"${this.escapeHtml(link.href)}\">\\n`;\n }\n }\n\n if (head.script) {\n for (const script of head.script) {\n headContent += this.renderScriptTag(script);\n }\n }\n\n // Inject into <head>...</head>\n result = result.replace(\n /<head([^>]*)>(.*?)<\\/head>/is,\n (_, existingAttrs, existingHead) =>\n `<head${existingAttrs}>${existingHead}${headContent}</head>`,\n );\n\n return result.trim();\n }\n\n protected mergeAttributes(\n existing: string,\n attrs: Record<string, string>,\n ): string {\n const existingAttrs = this.parseAttributes(existing);\n const merged = { ...existingAttrs, ...attrs };\n return Object.entries(merged)\n .map(([k, v]) => ` ${k}=\"${this.escapeHtml(v)}\"`)\n .join(\"\");\n }\n\n protected parseAttributes(attrStr: string): Record<string, string> {\n attrStr = attrStr.replaceAll(\"'\", '\"');\n\n const attrs: Record<string, string> = {};\n const attrRegex = /([^\\s=]+)(?:=\"([^\"]*)\")?/g;\n let match: RegExpExecArray | null = attrRegex.exec(attrStr);\n\n while (match) {\n attrs[match[1]] = match[2] ?? \"\";\n match = attrRegex.exec(attrStr);\n }\n\n return attrs;\n }\n\n protected escapeHtml(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n }\n\n protected renderMetaTag(meta: HeadMeta): string {\n // OpenGraph tags use property attribute\n if (meta.property) {\n return `<meta property=\"${this.escapeHtml(meta.property)}\" content=\"${this.escapeHtml(meta.content)}\">\\n`;\n }\n // Standard meta tags use name attribute\n if (meta.name) {\n return `<meta name=\"${this.escapeHtml(meta.name)}\" content=\"${this.escapeHtml(meta.content)}\">\\n`;\n }\n return \"\";\n }\n\n protected renderScriptTag(script: Record<string, string | boolean>): string {\n const attrs = Object.entries(script)\n .filter(([, value]) => value !== false)\n .map(([key, value]) => {\n // Boolean attributes - render without value if true\n if (value === true) {\n return key;\n }\n return `${key}=\"${this.escapeHtml(String(value))}\"`;\n })\n .join(\" \");\n return `<script ${attrs}></script>\\n`;\n }\n}\n","import { $hook, $inject } from \"alepha\";\nimport type { Head, HeadMeta } from \"../interfaces/Head.ts\";\nimport { HeadProvider } from \"./HeadProvider.ts\";\n\nexport class BrowserHeadProvider {\n protected readonly headProvider = $inject(HeadProvider);\n\n protected get document(): Document {\n return window.document;\n }\n\n protected readonly onBrowserRender = $hook({\n on: \"react:browser:render\",\n handler: async ({ state }) => {\n this.headProvider.fillHead(state);\n if (state.head) {\n this.renderHead(this.document, state.head);\n }\n },\n });\n\n protected readonly onTransitionEnd = $hook({\n on: \"react:transition:end\",\n handler: async ({ state }) => {\n this.headProvider.fillHead(state);\n if (state.head) {\n this.renderHead(this.document, state.head);\n }\n },\n });\n\n public getHead(document: Document): Head {\n return {\n get title() {\n return document.title;\n },\n get htmlAttributes() {\n const attrs: Record<string, string> = {};\n for (const attr of document.documentElement.attributes) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n },\n get bodyAttributes() {\n const attrs: Record<string, string> = {};\n for (const attr of document.body.attributes) {\n attrs[attr.name] = attr.value;\n }\n return attrs;\n },\n get meta() {\n const metas: HeadMeta[] = [];\n // Get meta tags with name attribute\n for (const meta of document.head.querySelectorAll(\"meta[name]\")) {\n const name = meta.getAttribute(\"name\");\n const content = meta.getAttribute(\"content\");\n if (name && content) {\n metas.push({ name, content });\n }\n }\n // Get meta tags with property attribute (OpenGraph)\n for (const meta of document.head.querySelectorAll(\"meta[property]\")) {\n const property = meta.getAttribute(\"property\");\n const content = meta.getAttribute(\"content\");\n if (property && content) {\n metas.push({ property, content });\n }\n }\n return metas;\n },\n };\n }\n\n public renderHead(document: Document, head: Head): void {\n if (head.title) {\n document.title = head.title;\n }\n\n if (head.bodyAttributes) {\n for (const [key, value] of Object.entries(head.bodyAttributes)) {\n if (value) {\n document.body.setAttribute(key, value);\n } else {\n document.body.removeAttribute(key);\n }\n }\n }\n\n if (head.htmlAttributes) {\n for (const [key, value] of Object.entries(head.htmlAttributes)) {\n if (value) {\n document.documentElement.setAttribute(key, value);\n } else {\n document.documentElement.removeAttribute(key);\n }\n }\n }\n\n if (head.meta) {\n for (const it of head.meta) {\n this.renderMetaTag(document, it);\n }\n }\n\n if (head.link) {\n for (const it of head.link) {\n const { rel, href } = it;\n let link = document.querySelector(`link[rel=\"${rel}\"][href=\"${href}\"]`);\n if (!link) {\n link = document.createElement(\"link\");\n link.setAttribute(\"rel\", rel);\n link.setAttribute(\"href\", href);\n document.head.appendChild(link);\n }\n }\n }\n }\n\n protected renderMetaTag(document: Document, meta: HeadMeta): void {\n const { content } = meta;\n\n // Handle OpenGraph tags (property attribute)\n if (meta.property) {\n const existing = document.querySelector(\n `meta[property=\"${meta.property}\"]`,\n );\n if (existing) {\n existing.setAttribute(\"content\", content);\n } else {\n const newMeta = document.createElement(\"meta\");\n newMeta.setAttribute(\"property\", meta.property);\n newMeta.setAttribute(\"content\", content);\n document.head.appendChild(newMeta);\n }\n return;\n }\n\n // Handle standard meta tags (name attribute)\n if (meta.name) {\n const existing = document.querySelector(`meta[name=\"${meta.name}\"]`);\n if (existing) {\n existing.setAttribute(\"content\", content);\n } else {\n const newMeta = document.createElement(\"meta\");\n newMeta.setAttribute(\"name\", meta.name);\n newMeta.setAttribute(\"content\", content);\n document.head.appendChild(newMeta);\n }\n }\n }\n}\n","import { useInject } from \"@alepha/react\";\nimport { Alepha } from \"alepha\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport type { Head } from \"../interfaces/Head.ts\";\nimport { BrowserHeadProvider } from \"../providers/BrowserHeadProvider.ts\";\n\n/**\n * ```tsx\n * const App = () => {\n * const [head, setHead] = useHead({\n * // will set the document title on the first render\n * title: \"My App\",\n * });\n *\n * return (\n * // This will update the document title when the button is clicked\n * <button onClick={() => setHead({ title: \"Change Title\" })}>\n * Change Title {head.title}\n * </button>\n * );\n * }\n * ```\n */\nexport const useHead = (options?: UseHeadOptions): UseHeadReturn => {\n const alepha = useInject(Alepha);\n\n const current = useMemo(() => {\n if (!alepha.isBrowser()) {\n return {};\n }\n\n return alepha.inject(BrowserHeadProvider).getHead(window.document);\n }, []);\n\n const setHead = useCallback((head?: Head | ((previous?: Head) => Head)) => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n alepha\n .inject(BrowserHeadProvider)\n .renderHead(\n window.document,\n typeof head === \"function\" ? head(current) : head || {},\n );\n }, []);\n\n useEffect(() => {\n if (options) {\n setHead(options);\n }\n }, []);\n\n return [current, setHead];\n};\n\nexport type UseHeadOptions = Head | ((previous?: Head) => Head);\n\nexport type UseHeadReturn = [\n Head,\n (head?: Head | ((previous?: Head) => Head)) => void,\n];\n","import { AlephaReact } from \"@alepha/react\";\nimport type {\n PageConfigSchema,\n TPropsDefault,\n TPropsParentDefault,\n} from \"@alepha/react/router\";\nimport { $module } from \"alepha\";\nimport { $head } from \"./primitives/$head.ts\";\nimport type { Head } from \"./interfaces/Head.ts\";\nimport { ServerHeadProvider } from \"./providers/ServerHeadProvider.ts\";\nimport { HeadProvider } from \"./providers/HeadProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$head.ts\";\nexport * from \"./hooks/useHead.ts\";\nexport * from \"./interfaces/Head.ts\";\nexport * from \"./helpers/SeoExpander.ts\";\nexport * from \"./providers/ServerHeadProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n// Augment PagePrimitiveOptions in router module\ndeclare module \"@alepha/react/router\" {\n interface PagePrimitiveOptions<\n TConfig extends PageConfigSchema = PageConfigSchema,\n TProps extends object = TPropsDefault,\n TPropsParent extends object = TPropsParentDefault,\n > {\n head?: Head | ((props: TProps, previous?: Head) => Head);\n }\n}\n\n// Augment ReactRouterState in router module\ndeclare module \"@alepha/react/router\" {\n interface ReactRouterState {\n head: Head;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Fill `<head>` server & client side.\n *\n * Generate SEO-friendly meta tags and titles for your React application using AlephaReactHead module.\n *\n * This module provides services and primitives to manage the document head both on the server and client side,\n * ensuring that your application is optimized for search engines and social media sharing.\n *\n * @see {@link ServerHeadProvider}\n * @module alepha.react.head\n */\nexport const AlephaReactHead = $module({\n name: \"alepha.react.head\",\n primitives: [$head],\n services: [AlephaReact, ServerHeadProvider, HeadProvider],\n});\n"],"mappings":"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"}