fimo 0.8.0 → 0.9.0-experimental.10

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 (218) hide show
  1. package/assets/agent-templates/content-translator/scripts/write-locale-files.ts +66 -0
  2. package/assets/agents-starter/claude/settings.json +19 -0
  3. package/assets/content-templates/hooks-template.eta +4 -2
  4. package/assets/content-templates/types-template.eta +67 -1
  5. package/assets/skills/fimo/SKILL.md +1 -1
  6. package/assets/skills/fimo/references/content.md +86 -15
  7. package/assets/skills/fimo/references/translations.md +75 -0
  8. package/assets/skills/fimo-cli/SKILL.md +6 -2
  9. package/assets/skills/fimo-cli/references/content.md +61 -2
  10. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +20 -4
  11. package/assets/skills/fimo-cli/references/integrations.md +5 -1
  12. package/assets/skills/fimo-cli/references/webhooks.md +162 -0
  13. package/assets/skills/fimo-migration/SKILL.md +24 -2
  14. package/assets/skills/fimo-migration/references/content.md +24 -0
  15. package/assets/skills/fimo-migration/references/manifest.md +46 -0
  16. package/assets/skills/fimo-migration/references/pages.md +234 -0
  17. package/assets/skills/fimo-migration/references/qa.md +24 -2
  18. package/assets/skills/fimo-migration/references/workflow.md +12 -1
  19. package/assets/skills/fimo-migration/references/wrap.md +662 -0
  20. package/assets/skills/fimo-studio/SKILL.md +5 -3
  21. package/assets/skills/fimo-studio/references/cms.md +9 -1
  22. package/assets/skills/fimo-studio/references/visual-editing.md +5 -3
  23. package/assets/skills/fimo-studio/references/webhooks.md +42 -0
  24. package/dist/build/vite/plugins/translations.d.ts +2 -8
  25. package/dist/build/vite/plugins/translations.js +31 -131
  26. package/dist/cli/bundle.json +1 -1
  27. package/dist/cli/index.js +1337 -189
  28. package/dist/runtime/app/FimoProviders.d.ts +1 -11
  29. package/dist/runtime/app/FimoProviders.js +31 -30
  30. package/dist/runtime/astro/index.d.ts +2 -0
  31. package/dist/runtime/astro/index.js +3 -0
  32. package/dist/runtime/astro/server.d.ts +3 -0
  33. package/dist/runtime/astro/server.js +6 -0
  34. package/dist/runtime/content/client/internal.js +1 -0
  35. package/dist/runtime/content/client/types.d.ts +16 -0
  36. package/dist/runtime/core/BuiltWithBadge.d.ts +2 -0
  37. package/dist/runtime/core/BuiltWithBadge.js +68 -0
  38. package/dist/runtime/i18n/FimoLocaleContext.js +1 -0
  39. package/dist/runtime/next/FimoNextProviders.d.ts +24 -0
  40. package/dist/runtime/next/FimoNextProviders.js +20 -0
  41. package/dist/runtime/next/FimoNextScripts.d.ts +10 -0
  42. package/dist/runtime/next/FimoNextScripts.js +19 -0
  43. package/dist/runtime/next/index.d.ts +14 -0
  44. package/dist/runtime/next/index.js +14 -0
  45. package/dist/runtime/next/server.d.ts +2 -0
  46. package/dist/runtime/next/server.js +4 -0
  47. package/dist/runtime/nuxt/composables.d.ts +9 -0
  48. package/dist/runtime/nuxt/composables.js +57 -0
  49. package/dist/runtime/nuxt/index.d.ts +3 -0
  50. package/dist/runtime/nuxt/index.js +6 -0
  51. package/dist/runtime/nuxt/server.d.ts +3 -0
  52. package/dist/runtime/nuxt/server.js +6 -0
  53. package/dist/runtime/primitives/components/RichText.d.ts +5 -1
  54. package/dist/runtime/primitives/components/RichText.js +2 -2
  55. package/dist/runtime/primitives/labels-hook.d.ts +33 -0
  56. package/dist/runtime/primitives/labels-hook.js +41 -0
  57. package/dist/runtime/primitives/labels-store.d.ts +12 -0
  58. package/dist/runtime/primitives/labels-store.js +60 -0
  59. package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +5 -3
  60. package/dist/runtime/primitives/lib/useFimoLiveValue.js +11 -4
  61. package/dist/runtime/primitives/translations.d.ts +1 -27
  62. package/dist/runtime/primitives/translations.js +7 -85
  63. package/dist/runtime/react/FimoSpaProviders.d.ts +36 -0
  64. package/dist/runtime/react/FimoSpaProviders.js +122 -0
  65. package/dist/runtime/react/index.d.ts +35 -0
  66. package/dist/runtime/react/index.js +40 -0
  67. package/dist/runtime/react/spa-content-cache.d.ts +38 -0
  68. package/dist/runtime/react/spa-content-cache.js +64 -0
  69. package/dist/runtime/remix/FimoRemixProviders.d.ts +16 -0
  70. package/dist/runtime/remix/FimoRemixProviders.js +12 -0
  71. package/dist/runtime/remix/FimoRemixScripts.d.ts +10 -0
  72. package/dist/runtime/remix/FimoRemixScripts.js +19 -0
  73. package/dist/runtime/remix/index.d.ts +12 -0
  74. package/dist/runtime/remix/index.js +11 -0
  75. package/dist/runtime/remix/server.d.ts +2 -0
  76. package/dist/runtime/remix/server.js +2 -0
  77. package/dist/runtime/seo/neutral.d.ts +22 -0
  78. package/dist/runtime/seo/neutral.js +17 -0
  79. package/dist/runtime/shared/display-routes.d.ts +14 -0
  80. package/dist/runtime/shared/display-routes.js +25 -0
  81. package/dist/runtime/shared/fimo-config.server.d.ts +0 -1
  82. package/dist/runtime/shared/fimo-config.server.js +1 -13
  83. package/dist/runtime/shared/fimo-config.types.d.ts +2 -0
  84. package/dist/runtime/shared/i18n-messages.d.ts +29 -0
  85. package/dist/runtime/shared/i18n-messages.js +79 -0
  86. package/dist/runtime/shared/labels-fetch.pure.d.ts +17 -0
  87. package/dist/runtime/shared/labels-fetch.pure.js +71 -0
  88. package/dist/runtime/shared/labels-fetch.server.d.ts +7 -0
  89. package/dist/runtime/shared/labels-fetch.server.js +97 -0
  90. package/dist/runtime/shared/labels-t.pure.d.ts +2 -0
  91. package/dist/runtime/shared/labels-t.pure.js +10 -0
  92. package/dist/runtime/strapi/client.d.ts +30 -0
  93. package/dist/runtime/strapi/client.js +132 -0
  94. package/dist/runtime/strapi/index.d.ts +5 -0
  95. package/dist/runtime/strapi/index.js +6 -0
  96. package/dist/runtime/strapi/reshape.d.ts +50 -0
  97. package/dist/runtime/strapi/reshape.js +121 -0
  98. package/dist/runtime/svelte/index.d.ts +3 -0
  99. package/dist/runtime/svelte/index.js +7 -0
  100. package/dist/runtime/svelte/server.d.ts +3 -0
  101. package/dist/runtime/svelte/server.js +6 -0
  102. package/dist/runtime/vue/index.d.ts +3 -0
  103. package/dist/runtime/vue/index.js +5 -0
  104. package/dist/runtime/vue/server.d.ts +3 -0
  105. package/dist/runtime/vue/server.js +6 -0
  106. package/dist/runtime/wrapped/FimoFileLink.d.ts +17 -0
  107. package/dist/runtime/wrapped/FimoFileLink.js +19 -0
  108. package/dist/runtime/wrapped/FimoMediaImage.d.ts +14 -0
  109. package/dist/runtime/wrapped/FimoMediaImage.js +20 -0
  110. package/dist/runtime/wrapped/FimoMediaVideo.d.ts +14 -0
  111. package/dist/runtime/wrapped/FimoMediaVideo.js +20 -0
  112. package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +26 -0
  113. package/dist/runtime/wrapped/FimoRichTextBlock.js +22 -0
  114. package/dist/runtime/wrapped/FimoText.d.ts +22 -0
  115. package/dist/runtime/wrapped/FimoText.js +20 -0
  116. package/dist/runtime/wrapped/WrappedContentContext.d.ts +28 -0
  117. package/dist/runtime/wrapped/WrappedContentContext.js +30 -0
  118. package/dist/runtime/wrapped/WrappedProviders.d.ts +33 -0
  119. package/dist/runtime/wrapped/WrappedProviders.js +101 -0
  120. package/dist/runtime/wrapped/content-fetch.pure.d.ts +20 -0
  121. package/dist/runtime/wrapped/content-fetch.pure.js +106 -0
  122. package/dist/runtime/wrapped/dom.d.ts +4 -0
  123. package/dist/runtime/wrapped/dom.js +23 -0
  124. package/dist/runtime/wrapped/server.d.ts +80 -0
  125. package/dist/runtime/wrapped/server.js +207 -0
  126. package/dist/scripts/apply-wrap-templates.d.ts +61 -0
  127. package/dist/scripts/apply-wrap-templates.js +137 -0
  128. package/dist/scripts/apply-wrap.d.ts +73 -0
  129. package/dist/scripts/apply-wrap.js +340 -0
  130. package/dist/scripts/cms/discover.d.ts +2 -0
  131. package/dist/scripts/cms/discover.js +17 -0
  132. package/dist/scripts/cms/example-content.d.ts +33 -0
  133. package/dist/scripts/cms/example-content.js +165 -0
  134. package/dist/scripts/cms/strapi/detect.d.ts +2 -0
  135. package/dist/scripts/cms/strapi/detect.js +186 -0
  136. package/dist/scripts/cms/strapi/index.d.ts +3 -0
  137. package/dist/scripts/cms/strapi/index.js +25 -0
  138. package/dist/scripts/cms/strapi/list-source.d.ts +17 -0
  139. package/dist/scripts/cms/strapi/list-source.js +90 -0
  140. package/dist/scripts/cms/strapi/schema-map.d.ts +9 -0
  141. package/dist/scripts/cms/strapi/schema-map.js +289 -0
  142. package/dist/scripts/cms/strapi/shapes.d.ts +25 -0
  143. package/dist/scripts/cms/strapi/shapes.js +48 -0
  144. package/dist/scripts/cms/strapi/touchpoints.d.ts +31 -0
  145. package/dist/scripts/cms/strapi/touchpoints.js +145 -0
  146. package/dist/scripts/cms/strapi/wire-client.d.ts +15 -0
  147. package/dist/scripts/cms/strapi/wire-client.js +107 -0
  148. package/dist/scripts/cms/strapi/wiring.d.ts +17 -0
  149. package/dist/scripts/cms/strapi/wiring.js +46 -0
  150. package/dist/scripts/cms/types.d.ts +145 -0
  151. package/dist/scripts/cms/types.js +11 -0
  152. package/dist/scripts/detect-framework.d.ts +39 -0
  153. package/dist/scripts/detect-framework.js +139 -0
  154. package/dist/scripts/draft-rows.d.ts +19 -0
  155. package/dist/scripts/draft-rows.js +178 -0
  156. package/dist/scripts/draft-schemas.d.ts +27 -0
  157. package/dist/scripts/draft-schemas.js +247 -0
  158. package/dist/scripts/extract-translations.js +16 -11
  159. package/dist/scripts/frameworks/astro/routes.d.ts +3 -0
  160. package/dist/scripts/frameworks/astro/routes.js +44 -0
  161. package/dist/scripts/frameworks/astro/template-style.d.ts +7 -0
  162. package/dist/scripts/frameworks/astro/template-style.js +19 -0
  163. package/dist/scripts/frameworks/discover.d.ts +83 -0
  164. package/dist/scripts/frameworks/discover.js +288 -0
  165. package/dist/scripts/frameworks/discovered-route.d.ts +9 -0
  166. package/dist/scripts/frameworks/discovered-route.js +17 -0
  167. package/dist/scripts/frameworks/next/rewire.d.ts +43 -0
  168. package/dist/scripts/frameworks/next/rewire.js +282 -0
  169. package/dist/scripts/frameworks/next/routes.d.ts +30 -0
  170. package/dist/scripts/frameworks/next/routes.js +176 -0
  171. package/dist/scripts/frameworks/next/wiring.d.ts +33 -0
  172. package/dist/scripts/frameworks/next/wiring.js +186 -0
  173. package/dist/scripts/frameworks/nuxt/routes.d.ts +3 -0
  174. package/dist/scripts/frameworks/nuxt/routes.js +38 -0
  175. package/dist/scripts/frameworks/nuxt/template-style.d.ts +9 -0
  176. package/dist/scripts/frameworks/nuxt/template-style.js +27 -0
  177. package/dist/scripts/frameworks/remix/routes.d.ts +3 -0
  178. package/dist/scripts/frameworks/remix/routes.js +36 -0
  179. package/dist/scripts/frameworks/support.d.ts +75 -0
  180. package/dist/scripts/frameworks/support.js +165 -0
  181. package/dist/scripts/frameworks/sveltekit/routes.d.ts +3 -0
  182. package/dist/scripts/frameworks/sveltekit/routes.js +35 -0
  183. package/dist/scripts/frameworks/sveltekit/template-style.d.ts +9 -0
  184. package/dist/scripts/frameworks/sveltekit/template-style.js +54 -0
  185. package/dist/scripts/frameworks/vite/routes.d.ts +20 -0
  186. package/dist/scripts/frameworks/vite/routes.js +143 -0
  187. package/dist/scripts/frameworks/vite/wiring.d.ts +22 -0
  188. package/dist/scripts/frameworks/vite/wiring.js +144 -0
  189. package/dist/scripts/i18n-namespace.d.ts +27 -0
  190. package/dist/scripts/i18n-namespace.js +155 -0
  191. package/dist/scripts/lib/humanize.d.ts +14 -0
  192. package/dist/scripts/lib/humanize.js +54 -0
  193. package/dist/scripts/lib/validation-report.d.ts +1 -3
  194. package/dist/scripts/lib/validation-report.js +3 -9
  195. package/dist/scripts/render-parity/capture.d.ts +64 -0
  196. package/dist/scripts/render-parity/capture.js +436 -0
  197. package/dist/scripts/render-parity/compare.d.ts +59 -0
  198. package/dist/scripts/render-parity/compare.js +0 -0
  199. package/dist/scripts/render-parity/normalize-html.d.ts +13 -0
  200. package/dist/scripts/render-parity/normalize-html.js +223 -0
  201. package/dist/scripts/render-parity/types.d.ts +41 -0
  202. package/dist/scripts/render-parity/types.js +1 -0
  203. package/dist/scripts/routes/bindings.d.ts +93 -0
  204. package/dist/scripts/routes/bindings.js +117 -0
  205. package/dist/scripts/routes/label-prefixes.d.ts +49 -0
  206. package/dist/scripts/routes/label-prefixes.js +136 -0
  207. package/dist/scripts/routes/module-resolve.d.ts +20 -0
  208. package/dist/scripts/routes/module-resolve.js +78 -0
  209. package/dist/scripts/routes/page-structure.d.ts +72 -0
  210. package/dist/scripts/routes/page-structure.js +234 -0
  211. package/dist/scripts/scan-wrappable.d.ts +200 -0
  212. package/dist/scripts/scan-wrappable.js +1355 -0
  213. package/dist/scripts/validate-route-metadata.js +11 -0
  214. package/dist/scripts/validate-schemas.js +42 -1
  215. package/package.json +88 -4
  216. package/release.json +2 -2
  217. package/templates/react-router/package.json +1 -1
  218. package/templates/react-router/translations/en.json +1 -0
@@ -1,15 +1,5 @@
1
1
  import React from 'react';
2
- export interface ParamInfo {
3
- schema: string;
4
- queryField: string;
5
- displayField: string;
6
- }
7
- export interface DisplayRoute {
8
- id: string;
9
- name: string;
10
- path: string;
11
- params?: Record<string, ParamInfo>;
12
- }
2
+ export type { DisplayRoute, ParamInfo } from '../shared/display-routes.js';
13
3
  export interface FimoProvidersProps {
14
4
  children?: React.ReactNode;
15
5
  locale?: string;
@@ -1,5 +1,6 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Suspense, useCallback, useEffect, useMemo } from 'react';
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { QueryClient, QueryClientProvider, useQueryClient } from '@tanstack/react-query';
3
+ import { Suspense, useCallback, useEffect, useMemo, useState } from 'react';
3
4
  import { ErrorBoundary } from 'react-error-boundary';
4
5
  import { useLocation, useNavigate } from 'react-router';
5
6
  // @ts-ignore - virtual module provided by fimoConfigPlugin in fimo/vite
@@ -11,31 +12,10 @@ import { ViteLifecycles } from '../core/ViteLifecycles.js';
11
12
  import { FimoLocaleProvider } from '../i18n/FimoLocaleContext.js';
12
13
  import { getFimoTextDirection, resolveFimoLocale, toHtmlLang } from '../i18n/locale.js';
13
14
  import { ScreenshotProvider } from '../iframe/ScreenshotProvider.js';
15
+ import { getDisplayRoutes as getDisplayRoutesFromConfig } from '../shared/display-routes.js';
14
16
  import { OptionalTracking } from '../t/OptionalTracking.js';
15
- const titleCase = (seg) => seg
16
- .replace(/[_\-]+/g, ' ')
17
- .replace(/([a-z])([A-Z])/g, '$1 $2')
18
- .split(/\s+/)
19
- .filter(Boolean)
20
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
21
- .join(' ');
22
- const generateRouteName = (path) => {
23
- if (path === '/') {
24
- return 'Home';
25
- }
26
- const firstSegment = path.replace(/^\//, '').split('/')[0];
27
- return titleCase(firstSegment);
28
- };
29
17
  function getDisplayRoutes() {
30
- const configRoutes = fimoConfig.routes ?? {};
31
- return Object.entries(configRoutes)
32
- .filter(([, route]) => route.path)
33
- .map(([id, route]) => ({
34
- id,
35
- path: route.path,
36
- name: route.name || generateRouteName(route.path),
37
- params: route.params,
38
- }));
18
+ return getDisplayRoutesFromConfig(fimoConfig);
39
19
  }
40
20
  function PreviewBridge() {
41
21
  const navigate = useNavigate();
@@ -80,6 +60,27 @@ function PreviewBridge() {
80
60
  }, [navigate, sendRoutes, sendLocationChange]);
81
61
  return null;
82
62
  }
63
+ /**
64
+ * Template projects mount their own QueryClientProvider in root.tsx, but an
65
+ * ADOPTED app wired straight onto FimoProviders (react-router library SPAs)
66
+ * has none — and the inner runtime (RefreshContentProvider, content clients)
67
+ * calls useQueryClient(). Mount a fallback client only when no provider
68
+ * exists above, so both worlds work and template caches stay untouched.
69
+ */
70
+ function EnsureQueryClient({ children }) {
71
+ let existing = null;
72
+ try {
73
+ existing = useQueryClient();
74
+ }
75
+ catch {
76
+ existing = null;
77
+ }
78
+ const [fallbackClient] = useState(() => new QueryClient());
79
+ if (existing) {
80
+ return _jsx(_Fragment, { children: children });
81
+ }
82
+ return _jsx(QueryClientProvider, { client: fallbackClient, children: children });
83
+ }
83
84
  export function FimoProviders({ children, locale }) {
84
85
  const location = useLocation();
85
86
  const localeResolution = useMemo(() => resolveFimoLocale({ pathname: location.pathname }, fimoConfig), [location.pathname]);
@@ -92,9 +93,9 @@ export function FimoProviders({ children, locale }) {
92
93
  document.documentElement.lang = toHtmlLang(activeLocale);
93
94
  document.documentElement.dir = activeDir;
94
95
  }, [activeDir, activeLocale]);
95
- return (_jsx(ErrorBoundary, { FallbackComponent: AppErrorBoundary, onError: onError, children: _jsx(FimoLocaleProvider, { value: {
96
- ...localeResolution,
97
- locale: activeLocale,
98
- dir: activeDir,
99
- }, children: _jsx(DataSourcesProvider, { children: _jsx(ScreenshotProvider, { children: _jsx(ViteLifecycles, { children: _jsxs(RefreshContentProvider, { children: [_jsx(PreviewBridge, {}), _jsx(OptionalTracking, { routes: getDisplayRoutes() }), _jsx(Suspense, { children: children })] }) }) }) }) }) }));
96
+ return (_jsx(ErrorBoundary, { FallbackComponent: AppErrorBoundary, onError: onError, children: _jsx(EnsureQueryClient, { children: _jsx(FimoLocaleProvider, { value: {
97
+ ...localeResolution,
98
+ locale: activeLocale,
99
+ dir: activeDir,
100
+ }, children: _jsx(DataSourcesProvider, { children: _jsx(ScreenshotProvider, { children: _jsx(ViteLifecycles, { children: _jsxs(RefreshContentProvider, { children: [_jsx(PreviewBridge, {}), _jsx(OptionalTracking, { routes: getDisplayRoutes() }), _jsx(Suspense, { children: children })] }) }) }) }) }) }) }));
100
101
  }
@@ -0,0 +1,2 @@
1
+ export * from './server.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,3 @@
1
+ // fimo/astro — see ./server.js (Astro is server-loader + DOM-attrs based;
2
+ // no client component set in v1).
3
+ export * from './server.js';
@@ -0,0 +1,3 @@
1
+ export * from '../wrapped/server.js';
2
+ export { fimoLabelAttrs, fimoMediaAttrs } from '../wrapped/dom.js';
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,6 @@
1
+ // fimo/astro/server — Astro adapter, server surface. The loaders are
2
+ // framework-neutral (Astro needs no React): call them in server-side code
3
+ // (frontmatter / load functions / useAsyncData) and render values with the
4
+ // DOM attribute helpers so edit mode can select the elements.
5
+ export * from '../wrapped/server.js';
6
+ export { fimoLabelAttrs, fimoMediaAttrs } from '../wrapped/dom.js';
@@ -179,6 +179,7 @@ function wrapReference(value, uid, resolve) {
179
179
  function wrapField(field, value, source, resolve) {
180
180
  switch (field.type) {
181
181
  case 'string':
182
+ case 'text':
182
183
  return value != null ? new FimoString(value, source) : value;
183
184
  case 'richtext':
184
185
  return value != null ? new FimoRichText(value, source) : value;
@@ -18,6 +18,7 @@ export type ContentResult<T extends {
18
18
  export interface ContentSchemaField {
19
19
  type?: string;
20
20
  required?: boolean;
21
+ default?: unknown;
21
22
  /** Media fields: multiple assets. */
22
23
  multiple?: boolean;
23
24
  /** Reference fields: to-many. */
@@ -26,6 +27,21 @@ export interface ContentSchemaField {
26
27
  target?: string;
27
28
  /** Polymorphic reference fields: allowed target schema uids. */
28
29
  targets?: readonly string[];
30
+ min?: number;
31
+ max?: number;
32
+ minLength?: number;
33
+ maxLength?: number;
34
+ regex?: string;
35
+ schema?: {
36
+ fields: Readonly<Record<string, ContentSchemaField>>;
37
+ } | {
38
+ oneOf: readonly {
39
+ uid: string;
40
+ label: string;
41
+ description?: string;
42
+ fields: Readonly<Record<string, ContentSchemaField>>;
43
+ }[];
44
+ };
29
45
  }
30
46
  export interface ContentSchema {
31
47
  uid: string;
@@ -0,0 +1,2 @@
1
+ export declare function BuiltWithBadge(): import("react").ReactPortal | null;
2
+ //# sourceMappingURL=BuiltWithBadge.d.ts.map
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ const STORAGE_KEY = 'fimoBadgeDismissed';
5
+ export function BuiltWithBadge() {
6
+ const hideFimoBadge = __FIMO_HIDE_BADGE__;
7
+ const [visible, setVisible] = useState(false);
8
+ useEffect(() => {
9
+ try {
10
+ const dismissed = sessionStorage.getItem(STORAGE_KEY) === 'true';
11
+ setVisible(!dismissed);
12
+ }
13
+ catch {
14
+ setVisible(true);
15
+ }
16
+ }, []);
17
+ if (hideFimoBadge) {
18
+ return null;
19
+ } // hide fimo badge config
20
+ // @ts-ignore
21
+ if (!import.meta.env.PROD) {
22
+ return null;
23
+ } // only show in prod
24
+ if (!visible) {
25
+ return null;
26
+ }
27
+ if (typeof document === 'undefined') {
28
+ return null;
29
+ }
30
+ return createPortal(_jsx("div", { style: {
31
+ position: 'fixed',
32
+ right: '16px',
33
+ bottom: '16px',
34
+ zIndex: 100000,
35
+ margin: 0,
36
+ }, children: _jsxs("div", { style: {
37
+ display: 'flex',
38
+ alignItems: 'center',
39
+ gap: '8px',
40
+ borderRadius: '9999px',
41
+ color: '#fff',
42
+ boxShadow: '0 12px 30px rgba(0, 0, 0, 0.35)',
43
+ padding: '8px 12px',
44
+ fontSize: '12px',
45
+ lineHeight: 1.2,
46
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
47
+ fontFamily: 'ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif',
48
+ }, children: [_jsxs("a", { href: "https://fimo.ai", target: "_blank", rel: "noopener noreferrer", style: {
49
+ display: 'inline-flex',
50
+ alignItems: 'center',
51
+ gap: '8px',
52
+ color: '#fff',
53
+ textDecoration: 'none',
54
+ }, children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 24 12", fill: "none", children: _jsx("path", { d: "M22.8569 4.85715H14.9866L15.9132 3.58186C16.5027 2.77062 17.4534 2.28627 18.4561 2.28627H22.8569C23.4882 2.28627 23.9999 1.7745 23.9999 1.14328C23.9999 0.512061 23.4884 0 22.8569 0H18.4561C16.7239 0 15.082 0.836671 14.0639 2.23798L12.1611 4.85715H6.9979C5.2657 4.85715 3.62379 5.69382 2.60567 7.09513L0.360255 10.1852C-0.0109321 10.6958 0.10251 11.4108 0.613142 11.7817C0.816023 11.9291 1.05119 12 1.28408 12C1.63755 12 1.98616 11.8366 2.20962 11.5288L4.45474 8.43872C5.04424 7.62748 5.99493 7.14314 6.99762 7.14314H10.5L8.28977 10.1852C7.91858 10.6958 8.03203 11.4108 8.54266 11.7817C8.74554 11.9291 8.98071 12 9.2136 12C9.56707 12 9.91568 11.8366 10.1391 11.5288L12.3843 8.43872C12.9738 7.62748 13.9244 7.14314 14.9271 7.14314H22.8566C23.4879 7.14314 23.9996 6.63136 23.9996 6.00014C23.9996 5.36893 23.4879 4.85715 22.8566 4.85715H22.8569Z", fill: "white" }) }), _jsx("span", { style: { fontWeight: 600 }, children: "Built with Fimo" })] }), _jsx("button", { "aria-label": "Dismiss badge", style: {
55
+ color: '#ddd',
56
+ background: 'transparent',
57
+ cursor: 'pointer',
58
+ border: 'none',
59
+ padding: 0,
60
+ lineHeight: 0,
61
+ }, onClick: () => {
62
+ try {
63
+ sessionStorage.setItem(STORAGE_KEY, 'true');
64
+ }
65
+ catch { }
66
+ setVisible(false);
67
+ }, type: "button", children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [_jsx("path", { d: "M18 6 6 18" }), _jsx("path", { d: "m6 6 12 12" })] }) })] }) }), document.body);
68
+ }
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx } from "react/jsx-runtime";
2
3
  import { createContext, useContext } from 'react';
3
4
  const fallbackLocale = {
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import type { FimoConfig } from '../shared/fimo-config.types.js';
3
+ import type { WrappedMediaEntry, WrappedRichTextEntry } from '../wrapped/WrappedContentContext.js';
4
+ import { type WrappedLabels } from '../wrapped/WrappedProviders.js';
5
+ export type FimoNextLabels = WrappedLabels;
6
+ export interface FimoNextProvidersProps {
7
+ config: FimoConfig;
8
+ labels?: FimoNextLabels;
9
+ media?: Record<string, WrappedMediaEntry>;
10
+ richText?: Record<string, WrappedRichTextEntry>;
11
+ locale?: string;
12
+ children?: React.ReactNode;
13
+ }
14
+ /**
15
+ * Fimo providers for wrapped Next.js apps — the Next adapter supplies only
16
+ * the navigation hooks; everything else lives in the framework-neutral
17
+ * WrappedProviders. Mount once in the root layout:
18
+ *
19
+ * const config = loadFimoConfig();
20
+ * const labels = await loadFimoLabels();
21
+ * <FimoNextProviders config={config} labels={labels}>{children}</FimoNextProviders>
22
+ */
23
+ export declare function FimoNextProviders(props: FimoNextProvidersProps): import("react/jsx-runtime").JSX.Element;
24
+ //# sourceMappingURL=FimoNextProviders.d.ts.map
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { usePathname, useRouter } from 'next/navigation';
4
+ import { useMemo } from 'react';
5
+ import { WrappedProviders } from '../wrapped/WrappedProviders.js';
6
+ /**
7
+ * Fimo providers for wrapped Next.js apps — the Next adapter supplies only
8
+ * the navigation hooks; everything else lives in the framework-neutral
9
+ * WrappedProviders. Mount once in the root layout:
10
+ *
11
+ * const config = loadFimoConfig();
12
+ * const labels = await loadFimoLabels();
13
+ * <FimoNextProviders config={config} labels={labels}>{children}</FimoNextProviders>
14
+ */
15
+ export function FimoNextProviders(props) {
16
+ const router = useRouter();
17
+ const pathname = usePathname();
18
+ const navigation = useMemo(() => ({ pathname, navigate: (to) => router.push(to) }), [pathname, router]);
19
+ return _jsx(WrappedProviders, { ...props, navigation: navigation });
20
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Renders the Fimo preview client script in development so the Fimo Studio
3
+ * preview can select/edit elements. Mount inside <head> in the root layout.
4
+ *
5
+ * The script URL comes from NEXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL (written by
6
+ * `fimo init` for wrapped projects, pointing at `<apiUrl>/preview.js`).
7
+ * Renders nothing in production builds.
8
+ */
9
+ export declare function FimoNextScripts(): import("react/jsx-runtime").JSX.Element | null;
10
+ //# sourceMappingURL=FimoNextScripts.d.ts.map
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Renders the Fimo preview client script in development so the Fimo Studio
4
+ * preview can select/edit elements. Mount inside <head> in the root layout.
5
+ *
6
+ * The script URL comes from NEXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL (written by
7
+ * `fimo init` for wrapped projects, pointing at `<apiUrl>/preview.js`).
8
+ * Renders nothing in production builds.
9
+ */
10
+ export function FimoNextScripts() {
11
+ if (process.env.NODE_ENV !== 'development') {
12
+ return null;
13
+ }
14
+ const previewScriptUrl = process.env.NEXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL;
15
+ if (!previewScriptUrl) {
16
+ return null;
17
+ }
18
+ return _jsx("script", { type: "module", src: previewScriptUrl });
19
+ }
@@ -0,0 +1,14 @@
1
+ export { FimoNextProviders } from './FimoNextProviders.js';
2
+ export type { FimoNextLabels, FimoNextProvidersProps } from './FimoNextProviders.js';
3
+ export { FimoNextScripts } from './FimoNextScripts.js';
4
+ export { FimoText } from '../wrapped/FimoText.js';
5
+ export { FimoRichTextBlock } from '../wrapped/FimoRichTextBlock.js';
6
+ export { FimoMediaImage } from '../wrapped/FimoMediaImage.js';
7
+ export { FimoMediaVideo } from '../wrapped/FimoMediaVideo.js';
8
+ export { FimoFileLink } from '../wrapped/FimoFileLink.js';
9
+ export { useWrappedMedia, useWrappedRichText } from '../wrapped/WrappedContentContext.js';
10
+ export type { WrappedMediaEntry, WrappedRichTextEntry } from '../wrapped/WrappedContentContext.js';
11
+ export { useLabels, useTranslations } from '../primitives/labels-hook.js';
12
+ export { Text, Image, Video, RichText } from '../react/index.js';
13
+ export type { FimoConfig } from '../shared/fimo-config.types.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,14 @@
1
+ // fimo/next — the Next.js adapter for wrapped (migrated) sites.
2
+ // Client components; server loaders live in fimo/next/server.
3
+ export { FimoNextProviders } from './FimoNextProviders.js';
4
+ export { FimoNextScripts } from './FimoNextScripts.js';
5
+ export { FimoText } from '../wrapped/FimoText.js';
6
+ export { FimoRichTextBlock } from '../wrapped/FimoRichTextBlock.js';
7
+ export { FimoMediaImage } from '../wrapped/FimoMediaImage.js';
8
+ export { FimoMediaVideo } from '../wrapped/FimoMediaVideo.js';
9
+ export { FimoFileLink } from '../wrapped/FimoFileLink.js';
10
+ export { useWrappedMedia, useWrappedRichText } from '../wrapped/WrappedContentContext.js';
11
+ // Framework-neutral React surface, re-exported for convenience so wrapped
12
+ // apps import everything from fimo/next.
13
+ export { useLabels, useTranslations } from '../primitives/labels-hook.js';
14
+ export { Text, Image, Video, RichText } from '../react/index.js';
@@ -0,0 +1,2 @@
1
+ export * from '../wrapped/server.js';
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,4 @@
1
+ // fimo/next/server — the Next.js adapter's server surface. The loaders are
2
+ // framework-neutral and live in ../wrapped/server.js; this module is the
3
+ // adapter-facing entry so future adapters (fimo/astro) mirror it.
4
+ export * from '../wrapped/server.js';
@@ -0,0 +1,9 @@
1
+ export declare function useFimoLabels(locale?: string): Promise<Record<string, string>>;
2
+ /**
3
+ * Server-loaded, hydration-safe label accessor for `<script setup>`:
4
+ *
5
+ * const t = await useFimoT();
6
+ * <h1 v-bind="fimoLabelAttrs('hero.title')">{{ t('hero.title', 'Fallback') }}</h1>
7
+ */
8
+ export declare function useFimoT(locale?: string): Promise<(key: string, fallback?: string) => string>;
9
+ //# sourceMappingURL=composables.d.ts.map
@@ -0,0 +1,57 @@
1
+ // Nuxt composables over the PURE label-fetch core. Constraints proven by the
2
+ // nuxtship dogfood, in order:
3
+ // - no node builtins anywhere in this module graph (`<script setup>` imports
4
+ // land in the client bundle; named imports from externalized builtins hard-
5
+ // fail `nuxt build`);
6
+ // - no `#app` import (Vite's dep optimizer prebundles node_modules with no
7
+ // knowledge of Nuxt aliases);
8
+ // - no `nuxt/app` import either (server-side the package is a nitro external
9
+ // resolved by raw node, where nuxt/app's internal `#build/*` imports do not
10
+ // exist).
11
+ // So: import only from 'vue', reach the Nuxt app via the current component
12
+ // instance, and hand labels to the client through `nuxtApp.payload.data` —
13
+ // the exact bucket useAsyncData serializes into the page payload.
14
+ import { getCurrentInstance } from 'vue';
15
+ import { fetchLabelDictionary, resolveTenantApiUrl } from '../shared/labels-fetch.pure.js';
16
+ function currentNuxtApp() {
17
+ const instance = getCurrentInstance();
18
+ const vueApp = instance?.appContext?.app;
19
+ return vueApp?.$nuxt ?? vueApp?.config?.globalProperties?.$nuxt ?? instance?.proxy?.$nuxt;
20
+ }
21
+ export async function useFimoLabels(locale = 'en') {
22
+ const key = `__fimo_labels_${locale}`;
23
+ const payloadData = currentNuxtApp()?.payload?.data;
24
+ const cached = payloadData?.[key];
25
+ if (cached) {
26
+ return cached;
27
+ }
28
+ // `typeof window` (not import.meta.server): as a nitro external this module
29
+ // runs as plain node ESM where Nuxt's import.meta flags do not exist.
30
+ if (typeof window !== 'undefined') {
31
+ return {};
32
+ }
33
+ const apiUrl = resolveTenantApiUrl(process.env);
34
+ if (!apiUrl) {
35
+ return {};
36
+ }
37
+ try {
38
+ const { labels } = await fetchLabelDictionary(apiUrl, locale);
39
+ if (payloadData) {
40
+ payloadData[key] = labels;
41
+ }
42
+ return labels;
43
+ }
44
+ catch {
45
+ return {};
46
+ }
47
+ }
48
+ /**
49
+ * Server-loaded, hydration-safe label accessor for `<script setup>`:
50
+ *
51
+ * const t = await useFimoT();
52
+ * <h1 v-bind="fimoLabelAttrs('hero.title')">{{ t('hero.title', 'Fallback') }}</h1>
53
+ */
54
+ export async function useFimoT(locale = 'en') {
55
+ const labels = await useFimoLabels(locale);
56
+ return (key, fallback = '') => labels[key] ?? fallback;
57
+ }
@@ -0,0 +1,3 @@
1
+ export { fimoLabelAttrs, fimoMediaAttrs, FIMO_SOURCE_ATTR } from '../wrapped/dom.js';
2
+ export { useFimoLabels, useFimoT } from './composables.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,6 @@
1
+ // fimo/nuxt — CLIENT-SAFE surface for universal Vue SFCs. Never re-export
2
+ // the server barrel here: a `<script setup>` import lands in the client
3
+ // bundle, and the server loaders read fs/env (the nuxtship dogfood broke
4
+ // `nuxt build` exactly this way). Server routes import fimo/nuxt/server.
5
+ export { fimoLabelAttrs, fimoMediaAttrs, FIMO_SOURCE_ATTR } from '../wrapped/dom.js';
6
+ export { useFimoLabels, useFimoT } from './composables.js';
@@ -0,0 +1,3 @@
1
+ export * from '../wrapped/server.js';
2
+ export { fimoLabelAttrs, fimoMediaAttrs } from '../wrapped/dom.js';
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,6 @@
1
+ // fimo/nuxt/server — Nuxt adapter, server surface. The loaders are
2
+ // framework-neutral (Nuxt needs no React): call them in server-side code
3
+ // (frontmatter / load functions / useAsyncData) and render values with the
4
+ // DOM attribute helpers so edit mode can select the elements.
5
+ export * from '../wrapped/server.js';
6
+ export { fimoLabelAttrs, fimoMediaAttrs } from '../wrapped/dom.js';
@@ -3,7 +3,11 @@ import { type FimoRichText, type FimoRichTextComponents } from '../lib/index.js'
3
3
  type RichTextProps = {
4
4
  value: FimoRichText;
5
5
  components?: FimoRichTextComponents;
6
+ /** Wrapper element. Use `span` when the block sits inside phrasing
7
+ * content (a `<p>`): a div there is invalid HTML — the browser closes
8
+ * the paragraph early and React trashes the hydrated tree. */
9
+ as?: 'div' | 'span';
6
10
  } & Omit<ComponentPropsWithoutRef<'div'>, 'children'>;
7
- export declare function RichText({ value, components, ...props }: RichTextProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function RichText({ value, components, as: Wrapper, ...props }: RichTextProps): import("react/jsx-runtime").JSX.Element;
8
12
  export {};
9
13
  //# sourceMappingURL=RichText.d.ts.map
@@ -128,8 +128,8 @@ function renderNode(node, components, key) {
128
128
  }
129
129
  return _jsx(Fragment, { children: children }, key);
130
130
  }
131
- export function RichText({ value, components, ...props }) {
131
+ export function RichText({ value, components, as: Wrapper = 'div', ...props }) {
132
132
  const source = value[FIMO_SOURCE];
133
133
  const { value: liveContent, ref } = useFimoLiveValue(value.content);
134
- return (_jsx("div", { ref: ref, ...props, "data-fimo-source": source, "data-fimo-richtext": "", children: renderNode(liveContent, components, 0) }));
134
+ return (_jsx(Wrapper, { ref: ref, ...props, "data-fimo-source": source, "data-fimo-richtext": "", children: renderNode(liveContent, components, 0) }));
135
135
  }
@@ -0,0 +1,33 @@
1
+ import { FimoString } from './lib/index.js';
2
+ /**
3
+ * Hook to provide a label function (`t`).
4
+ *
5
+ * Returns FimoString with source tracking for inline editing.
6
+ * Use with <Text> component for rendering, or String() for escape hatch.
7
+ *
8
+ * The optional `fallback` renders when the key has no value in the store —
9
+ * used by wrapped (migrated) projects where the original hardcoded string
10
+ * stays in code as a resilience fallback. Template projects keep the
11
+ * single-argument form (labels are DB-owned there).
12
+ *
13
+ * @example
14
+ * const { t } = useLabels();
15
+ *
16
+ * // With Text component (recommended)
17
+ * <Text value={t('welcome')} />
18
+ *
19
+ * // Escape hatch for attributes
20
+ * <input placeholder={String(t('email.placeholder'))} />
21
+ */
22
+ export declare function useLabels(): {
23
+ t: (fullKey: string, fallback?: string) => FimoString;
24
+ locale: string;
25
+ };
26
+ /**
27
+ * Legacy alias for older projects. Prefer useLabels() in new code.
28
+ */
29
+ export declare function useTranslations(): {
30
+ t: (fullKey: string, fallback?: string) => FimoString;
31
+ locale: string;
32
+ };
33
+ //# sourceMappingURL=labels-hook.d.ts.map
@@ -0,0 +1,41 @@
1
+ import { useSyncExternalStore } from 'react';
2
+ import { useLocale } from '../i18n/FimoLocaleContext.js';
3
+ import { getLabelSnapshot, subscribeLabels } from './labels-store.js';
4
+ import { FimoString } from './lib/index.js';
5
+ /**
6
+ * Hook to provide a label function (`t`).
7
+ *
8
+ * Returns FimoString with source tracking for inline editing.
9
+ * Use with <Text> component for rendering, or String() for escape hatch.
10
+ *
11
+ * The optional `fallback` renders when the key has no value in the store —
12
+ * used by wrapped (migrated) projects where the original hardcoded string
13
+ * stays in code as a resilience fallback. Template projects keep the
14
+ * single-argument form (labels are DB-owned there).
15
+ *
16
+ * @example
17
+ * const { t } = useLabels();
18
+ *
19
+ * // With Text component (recommended)
20
+ * <Text value={t('welcome')} />
21
+ *
22
+ * // Escape hatch for attributes
23
+ * <input placeholder={String(t('email.placeholder'))} />
24
+ */
25
+ export function useLabels() {
26
+ const localeContext = useLocale();
27
+ const labels = useSyncExternalStore(subscribeLabels, getLabelSnapshot, getLabelSnapshot);
28
+ const t = (fullKey, fallback) => {
29
+ const locale = localeContext.locale || labels.defaultLocale || 'en';
30
+ const dictionary = labels.dictionaries[locale] ?? labels.dictionaries[labels.defaultLocale] ?? {};
31
+ const text = dictionary[fullKey] ?? fallback ?? '';
32
+ return new FimoString(text, `__labels.${locale}.${fullKey}.value`);
33
+ };
34
+ return { t, locale: localeContext.locale };
35
+ }
36
+ /**
37
+ * Legacy alias for older projects. Prefer useLabels() in new code.
38
+ */
39
+ export function useTranslations() {
40
+ return useLabels();
41
+ }
@@ -0,0 +1,12 @@
1
+ export interface LabelState {
2
+ dictionaries: Record<string, Record<string, string>>;
3
+ defaultLocale: string;
4
+ signature: string;
5
+ updatedAt: string | null;
6
+ }
7
+ export declare function subscribeLabels(listener: () => void): () => void;
8
+ export declare function getLabelSnapshot(): LabelState;
9
+ export declare function setLabelState(next: LabelState): void;
10
+ export declare function hydrateLabels(bundle: LabelState): void;
11
+ export declare function applyLabelUpdate(payload: unknown): void;
12
+ //# sourceMappingURL=labels-store.d.ts.map
@@ -0,0 +1,60 @@
1
+ // Framework-neutral label store. No Vite virtual modules, no HMR, no React:
2
+ // adapters (fimo/ui via ./translations.ts, fimo/next, ...) hydrate it with
3
+ // their own label source and the hook layer subscribes to it.
4
+ const labelListeners = new Set();
5
+ let labelState = {
6
+ dictionaries: {},
7
+ defaultLocale: 'en',
8
+ signature: '__fimo-labels-uninitialized__',
9
+ updatedAt: null,
10
+ };
11
+ export function subscribeLabels(listener) {
12
+ labelListeners.add(listener);
13
+ return () => {
14
+ labelListeners.delete(listener);
15
+ };
16
+ }
17
+ export function getLabelSnapshot() {
18
+ return labelState;
19
+ }
20
+ export function setLabelState(next) {
21
+ if (next.signature === labelState.signature) {
22
+ return;
23
+ }
24
+ labelState = next;
25
+ for (const listener of labelListeners) {
26
+ listener();
27
+ }
28
+ }
29
+ export function hydrateLabels(bundle) {
30
+ setLabelState(bundle);
31
+ }
32
+ function isRecord(value) {
33
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
34
+ }
35
+ function normalizeDictionaries(value) {
36
+ if (!isRecord(value)) {
37
+ return null;
38
+ }
39
+ const dictionaries = {};
40
+ for (const [locale, labels] of Object.entries(value)) {
41
+ if (!isRecord(labels)) {
42
+ continue;
43
+ }
44
+ dictionaries[locale] = Object.fromEntries(Object.entries(labels).filter((entry) => typeof entry[1] === 'string'));
45
+ }
46
+ return dictionaries;
47
+ }
48
+ export function applyLabelUpdate(payload) {
49
+ if (!isRecord(payload)) {
50
+ return;
51
+ }
52
+ const dictionaries = normalizeDictionaries(payload.dictionaries);
53
+ if (!dictionaries) {
54
+ return;
55
+ }
56
+ const defaultLocale = typeof payload.defaultLocale === 'string' ? payload.defaultLocale : labelState.defaultLocale;
57
+ const signature = typeof payload.signature === 'string' ? payload.signature : JSON.stringify({ dictionaries, defaultLocale });
58
+ const updatedAt = typeof payload.updatedAt === 'string' ? payload.updatedAt : null;
59
+ setLabelState({ dictionaries, defaultLocale, signature, updatedAt });
60
+ }