@localess/react 3.0.1-dev.20260408172608 → 3.0.1-dev.20260408183951

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.
package/README.md CHANGED
@@ -309,7 +309,9 @@ const NavLink = ({ data, links }) => (
309
309
 
310
310
  ## Visual Editor Events
311
311
 
312
- When `enableSync: true` is set in `localessInit`, Visual Editor live-editing is handled **automatically** by the `useLocaless` hook — no manual event wiring needed.
312
+ ### With `useLocaless` Hook
313
+
314
+ When `enableSync: true` is set in `localessInit`, the `useLocaless` hook handles the full cycle automatically — initial fetch and live sync updates — with no extra wiring needed.
313
315
 
314
316
  ```tsx
315
317
  'use client';
@@ -318,7 +320,6 @@ import { useLocaless, LocalessComponent, localessEditable } from "@localess/reac
318
320
  import type { Page } from "./.localess/localess";
319
321
 
320
322
  export function PageView({ slug, locale }: { slug: string; locale?: string }) {
321
- // Automatically subscribes to Visual Editor input/change events when enableSync is active
322
323
  const content = useLocaless<Page>(slug, { locale });
323
324
 
324
325
  if (!content) return null;
@@ -333,14 +334,101 @@ export function PageView({ slug, locale }: { slug: string; locale?: string }) {
333
334
  }
334
335
  ```
335
336
 
336
- > `useLocaless` handles the full cycle: initial fetch + live sync updates when inside the editor iframe.
337
+ ### With `LocalessDocument` Component
338
+
339
+ `LocalessDocument` is a component alternative to the hook. Pass it server-fetched content data and it handles live sync updates internally, delegating rendering to `LocalessComponent`.
340
+
341
+ ```tsx
342
+ // app/[locale]/page.tsx (Server Component — fetches data)
343
+ import { getLocalessClient, LocalessDocument } from "@localess/react";
344
+ import type { Page } from "./.localess/localess";
345
+
346
+ export default async function HomePage({ params }: { params: Promise<{ locale?: string }> }) {
347
+ const { locale } = await params;
348
+ const client = getLocalessClient();
349
+ const content = await client.getContentBySlug<Page>('home', { locale });
350
+
351
+ return (
352
+ <LocalessDocument
353
+ data={content.data}
354
+ links={content.links}
355
+ references={content.references}
356
+ />
357
+ );
358
+ }
359
+ ```
360
+
361
+ **Props:**
362
+
363
+ | Prop | Type | Required | Description |
364
+ |------|------|----------|-------------|
365
+ | `data` | `ContentData` | ✅ | Initial content data (typically server-fetched) |
366
+ | `links` | `Links` | ❌ | Resolved links map, forwarded to the inner `LocalessComponent` |
367
+ | `references` | `References` | ❌ | Resolved references map, forwarded to the inner `LocalessComponent` |
368
+ | `ref` | `React.Ref<HTMLElement>` | ❌ | Forwarded to the rendered root element |
369
+ | `...rest` | `any` | ❌ | Any additional props are forwarded |
370
+
371
+ > `LocalessDocument` subscribes to `input` / `change` editor events automatically when `enableSync` is active. It is a Client Component internally — no `'use client'` directive needed at the call site in Server Components.
372
+
373
+ ### Manual Integration
374
+
375
+ If you manage content state yourself without `useLocaless` or `LocalessDocument`, subscribe to editor events directly via `window.localess`:
376
+
377
+ ```tsx
378
+ 'use client';
379
+
380
+ import { useEffect, useState } from "react";
381
+ import { LocalessComponent, localessEditable, isSyncEnabled, isBrowser } from "@localess/react";
382
+ import type { Content, Page } from "./.localess/localess";
383
+
384
+ export function PageClient({ initialContent }: { initialContent: Content<Page> }) {
385
+ const [pageData, setPageData] = useState(initialContent.data);
386
+
387
+ useEffect(() => {
388
+ if (isSyncEnabled() && isBrowser() && window.localess) {
389
+ window.localess.on(['input', 'change'], (event) => {
390
+ if (event.type === 'input' || event.type === 'change') {
391
+ setPageData(event.data);
392
+ }
393
+ });
394
+ }
395
+ // No cleanup needed: window.localess has no .off() method
396
+ }, []);
397
+
398
+ return (
399
+ <main {...localessEditable(pageData)}>
400
+ {pageData?.body.map(item => (
401
+ <LocalessComponent key={item._id} data={item} links={initialContent.links} references={initialContent.references} />
402
+ ))}
403
+ </main>
404
+ );
405
+ }
406
+ ```
407
+
408
+ **Available events via `window.localess.on()`:**
409
+
410
+ | Event | When |
411
+ |-------|------|
412
+ | `input` | User is typing in a field (real-time preview) |
413
+ | `change` | Field value confirmed |
414
+ | `save` | Content saved |
415
+ | `publish` | Content published |
416
+ | `pong` | Editor heartbeat response |
417
+ | `enterSchema` | Editor cursor enters a schema block |
418
+ | `hoverSchema` | Editor cursor hovers over a schema block |
419
+
420
+ > `window.localess` only exposes `.on()` and `.onChange()` — there is no `.off()` method.
337
421
 
338
422
  ---
339
423
 
340
- ## Full Example (Next.js 15 App Router)
424
+ ## Full Example (Next.js 16.2 App Router)
425
+
426
+ The recommended Next.js pattern is to **preload data server-side** and pass it to the Client Component. This avoids a loading flash — the page renders immediately with server data, then Visual Editor sync kicks in if active.
427
+
428
+ ### Setup — `app/layout.tsx`
341
429
 
342
430
  ```tsx
343
- // app/layout.tsx (Server Component — safe to use API token here)
431
+ // Server Component — safe to use API token here
344
432
  import { localessInit } from "@localess/react";
345
433
  import { Page, Header, Teaser, Footer } from "@/components";
346
434
 
@@ -352,16 +440,21 @@ localessInit({
352
440
  components: { Page, Header, Teaser, Footer },
353
441
  });
354
442
 
355
- export default function RootLayout({ children }) {
443
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
356
444
  return <html><body>{children}</body></html>;
357
445
  }
358
446
  ```
359
447
 
448
+ ### Server Component — `app/[locale]/page.tsx`
449
+
450
+ Fetches content during SSR and passes it as a prop. The client component receives it already populated — no loading state needed.
451
+
360
452
  ```tsx
361
- // app/[locale]/page.tsx (Server Component — fetches initial data)
362
453
  import { getLocalessClient } from "@localess/react";
363
- import { PageClient } from "./page-client";
364
- import type { Page } from "./.localess/localess";
454
+ import type { Content, Page } from "./.localess/localess";
455
+
456
+ // Choose one of the three client components below
457
+ import { PageClientHook } from "./page-client-hook";
365
458
 
366
459
  export default async function HomePage({
367
460
  params,
@@ -369,39 +462,106 @@ export default async function HomePage({
369
462
  params: Promise<{ locale?: string }>;
370
463
  }) {
371
464
  const { locale } = await params;
372
- const client = getLocalessClient();
373
- const content = await client.getContentBySlug<Page>('home', { locale });
465
+ const content = await getLocalessClient().getContentBySlug<Page>('home', { locale });
374
466
 
375
- return <PageClient initialContent={content} locale={locale} />;
467
+ return <PageClientHook initialContent={content} locale={locale} />;
376
468
  }
377
469
  ```
378
470
 
471
+ ### Client Component — Option A: `useLocaless` Hook
472
+
473
+ The hook re-fetches on the client and falls back to the server-preloaded data until it resolves. Live sync is wired automatically.
474
+
379
475
  ```tsx
380
- // app/[locale]/page-client.tsx (Client Component — renders + auto-syncs with Visual Editor)
476
+ // app/[locale]/page-client-hook.tsx
381
477
  'use client';
382
478
 
383
479
  import { useLocaless, LocalessComponent, localessEditable } from "@localess/react";
384
480
  import type { Content, Page } from "./.localess/localess";
385
481
 
386
- export function PageClient({
482
+ export function PageClientHook({
387
483
  initialContent,
388
484
  locale,
389
485
  }: {
390
486
  initialContent: Content<Page>;
391
487
  locale?: string;
392
488
  }) {
393
- // Handles initial fetch and Visual Editor live updates automatically
489
+ // ?? initialContent: renders with server data immediately, switches to hook result once ready
394
490
  const content = useLocaless<Page>('home', { locale }) ?? initialContent;
395
491
 
396
492
  return (
397
493
  <main {...localessEditable(content.data)}>
398
494
  {content.data?.body.map(item => (
399
- <LocalessComponent
400
- key={item._id}
401
- data={item}
402
- links={content.links}
403
- references={content.references}
404
- />
495
+ <LocalessComponent key={item._id} data={item} links={content.links} references={content.references} />
496
+ ))}
497
+ </main>
498
+ );
499
+ }
500
+ ```
501
+
502
+ ### Client Component — Option B: `LocalessDocument` Component
503
+
504
+ Skips client re-fetch entirely — uses server-preloaded data and only subscribes to live sync events. Simpler when you don't need client-side refetching.
505
+
506
+ ```tsx
507
+ // app/[locale]/page.tsx (Server Component — no separate client file needed)
508
+ import { getLocalessClient, LocalessDocument } from "@localess/react";
509
+ import type { Page } from "./.localess/localess";
510
+
511
+ export default async function HomePage({
512
+ params,
513
+ }: {
514
+ params: Promise<{ locale?: string }>;
515
+ }) {
516
+ const { locale } = await params;
517
+ const content = await getLocalessClient().getContentBySlug<Page>('home', { locale });
518
+
519
+ // LocalessDocument handles sync internally — no 'use client' wrapper needed here
520
+ return (
521
+ <LocalessDocument
522
+ data={content.data}
523
+ links={content.links}
524
+ references={content.references}
525
+ />
526
+ );
527
+ }
528
+ ```
529
+
530
+ ### Client Component — Option C: Manual
531
+
532
+ Full control over state and sync subscription. Use when you need custom logic around live updates.
533
+
534
+ ```tsx
535
+ // app/[locale]/page-client-manual.tsx
536
+ 'use client';
537
+
538
+ import { useEffect, useState } from "react";
539
+ import { LocalessComponent, localessEditable, isSyncEnabled, isBrowser } from "@localess/react";
540
+ import type { Content, Page } from "./.localess/localess";
541
+
542
+ export function PageClientManual({
543
+ initialContent,
544
+ }: {
545
+ initialContent: Content<Page>;
546
+ }) {
547
+ // Initialize with server-preloaded data — no loading state needed
548
+ const [pageData, setPageData] = useState(initialContent.data);
549
+
550
+ useEffect(() => {
551
+ if (isSyncEnabled() && isBrowser() && window.localess) {
552
+ window.localess.on(['input', 'change'], (event) => {
553
+ if (event.type === 'input' || event.type === 'change') {
554
+ setPageData(event.data);
555
+ }
556
+ });
557
+ }
558
+ // No cleanup needed: window.localess has no .off() method
559
+ }, []);
560
+
561
+ return (
562
+ <main {...localessEditable(pageData)}>
563
+ {pageData?.body.map(item => (
564
+ <LocalessComponent key={item._id} data={item} links={initialContent.links} references={initialContent.references} />
405
565
  ))}
406
566
  </main>
407
567
  );
@@ -418,6 +578,8 @@ The following are re-exported for convenience so you only need to import from `@
418
578
 
419
579
  **Functions:** `localessEditable`, `localessEditableField`, `llEditable` *(deprecated)*, `llEditableField` *(deprecated)*, `isBrowser`, `isServer`, `isIframe`, `resolveAsset`, `findLink`, `useLocaless`, `renderRichTextToReact`, `localessInit`, `getLocalessClient`, `registerComponent`, `unregisterComponent`, `setComponents`, `getComponent`, `setFallbackComponent`, `getFallbackComponent`, `isSyncEnabled`
420
580
 
581
+ **Components:** `LocalessComponent`, `LocalessDocument`
582
+
421
583
  ---
422
584
 
423
585
  ## AI Coding Agents
package/SKILL.md CHANGED
@@ -174,9 +174,9 @@ localessInit({
174
174
 
175
175
  > Never enable sync in production — the script is only meaningful inside the Localess Visual Editor iframe.
176
176
 
177
- ### Receiving Real-time Editor Events
177
+ ### With `useLocaless` Hook
178
178
 
179
- Use the `useLocaless` hook in a Client Component — it **automatically subscribes** to `input` / `change` events when `enableSync` is active. No manual `window.localess.on()` wiring needed.
179
+ The `useLocaless` hook handles the full cycle automatically initial fetch and live sync updates with no extra wiring needed.
180
180
 
181
181
  ```tsx
182
182
  'use client';
@@ -185,7 +185,6 @@ import { useLocaless, LocalessComponent, localessEditable } from "@localess/reac
185
185
  import type { Content, Page } from "./.localess/localess";
186
186
 
187
187
  export function PageClient({ initialContent, locale }: { initialContent: Content<Page>; locale?: string }) {
188
- // Fetches content and auto-syncs with Visual Editor live updates
189
188
  const content = useLocaless<Page>('home', { locale }) ?? initialContent;
190
189
 
191
190
  return (
@@ -203,7 +202,82 @@ export function PageClient({ initialContent, locale }: { initialContent: Content
203
202
  }
204
203
  ```
205
204
 
206
- **Available events (handled internally by `useLocaless`):**
205
+ ### With `LocalessDocument` Component
206
+
207
+ `LocalessDocument` is a component alternative to the hook. It accepts server-fetched `data` and manages live sync updates internally, delegating rendering to `LocalessComponent`. Useful when you prefer a component-based approach over hooks.
208
+
209
+ ```tsx
210
+ // Server Component — pass fetched data directly to LocalessDocument
211
+ import { getLocalessClient, LocalessDocument } from "@localess/react";
212
+ import type { Page } from "./.localess/localess";
213
+
214
+ export default async function HomePage({ params }: { params: Promise<{ locale?: string }> }) {
215
+ const { locale } = await params;
216
+ const client = getLocalessClient();
217
+ const content = await client.getContentBySlug<Page>('home', { locale });
218
+
219
+ return (
220
+ <LocalessDocument
221
+ data={content.data}
222
+ links={content.links}
223
+ references={content.references}
224
+ />
225
+ );
226
+ }
227
+ ```
228
+
229
+ **Props** (same shape as `LocalessComponent`):
230
+
231
+ | Prop | Type | Required | Description |
232
+ |------|------|----------|-------------|
233
+ | `data` | `ContentData` | ✅ | Initial content data |
234
+ | `links` | `Links` | ❌ | Resolved links map |
235
+ | `references` | `References` | ❌ | Resolved references map |
236
+ | `ref` | `React.Ref<HTMLElement>` | ❌ | Forwarded to the rendered root element |
237
+
238
+ > Subscribes to `input` / `change` events automatically when `enableSync` is active. Unlike `useLocaless`, it does not fetch content — it only handles live sync for data passed in as props.
239
+
240
+ ### Manual Integration
241
+
242
+ If you manage content state yourself without `useLocaless` or `LocalessDocument`, subscribe to editor events directly via `window.localess`:
243
+
244
+ ```tsx
245
+ 'use client';
246
+
247
+ import { useEffect, useState } from "react";
248
+ import { LocalessComponent, localessEditable, isSyncEnabled, isBrowser } from "@localess/react";
249
+ import type { Content, Page } from "./.localess/localess";
250
+
251
+ export function PageClient({ initialContent }: { initialContent: Content<Page> }) {
252
+ const [pageData, setPageData] = useState(initialContent.data);
253
+
254
+ useEffect(() => {
255
+ if (isSyncEnabled() && isBrowser() && window.localess) {
256
+ window.localess.on(['input', 'change'], (event) => {
257
+ if (event.type === 'input' || event.type === 'change') {
258
+ setPageData(event.data);
259
+ }
260
+ });
261
+ }
262
+ // No cleanup needed: window.localess has no .off() method
263
+ }, []);
264
+
265
+ return (
266
+ <main {...localessEditable(pageData)}>
267
+ {pageData?.body?.map(item => (
268
+ <LocalessComponent
269
+ key={item._id}
270
+ data={item}
271
+ links={initialContent.links}
272
+ references={initialContent.references}
273
+ />
274
+ ))}
275
+ </main>
276
+ );
277
+ }
278
+ ```
279
+
280
+ **Available events via `window.localess.on()`:**
207
281
 
208
282
  | Event | When |
209
283
  |---------------|-----------------------------------------------|
@@ -219,13 +293,14 @@ export function PageClient({ initialContent, locale }: { initialContent: Content
219
293
 
220
294
  ### Pattern: Split Server/Client Components (Next.js App Router)
221
295
 
222
- Keep data fetching server-side and delegate rendering + sync to a Client Component using `useLocaless`:
296
+ **Preload data server-side** and pass it to the Client Component. The page renders immediately with server data — no loading flash — and Visual Editor sync kicks in on top.
297
+
298
+ **Server Component** (same for all three options below):
223
299
 
224
300
  ```tsx
225
- // app/[locale]/page.tsx — Server Component: fetches initial data
301
+ // app/[locale]/page.tsx
226
302
  import { getLocalessClient } from "@localess/react";
227
- import { PageClient } from "./page-client";
228
- import type { Page } from "./.localess/localess";
303
+ import type { Content, Page } from "./.localess/localess";
229
304
 
230
305
  export default async function HomePage({
231
306
  params,
@@ -233,32 +308,82 @@ export default async function HomePage({
233
308
  params: Promise<{ locale?: string }>;
234
309
  }) {
235
310
  const { locale } = await params;
236
- const client = getLocalessClient();
237
- const content = await client.getContentBySlug<Page>('home', { locale });
311
+ // Data fetched during SSR — preloaded into the client component as a prop
312
+ const content = await getLocalessClient().getContentBySlug<Page>('home', { locale });
238
313
 
239
314
  return <PageClient initialContent={content} locale={locale} />;
240
315
  }
241
316
  ```
242
317
 
318
+ **Option A — `useLocaless` hook**: re-fetches on client, falls back to server data until resolved, auto-syncs with editor.
319
+
243
320
  ```tsx
244
- // app/[locale]/page-client.tsx — Client Component: renders + auto-syncs
321
+ // app/[locale]/page-client.tsx
245
322
  'use client';
246
323
 
247
324
  import { useLocaless, LocalessComponent, localessEditable } from "@localess/react";
248
325
  import type { Content, Page } from "./.localess/localess";
249
326
 
250
327
  export function PageClient({ initialContent, locale }: { initialContent: Content<Page>; locale?: string }) {
328
+ // ?? initialContent: renders server data immediately, switches to hook result once ready
251
329
  const content = useLocaless<Page>('home', { locale }) ?? initialContent;
252
330
 
253
331
  return (
254
332
  <main {...localessEditable(content.data)}>
255
333
  {content.data?.body?.map(item => (
256
- <LocalessComponent
257
- key={item._id}
258
- data={item}
259
- links={content.links}
260
- references={content.references}
261
- />
334
+ <LocalessComponent key={item._id} data={item} links={content.links} references={content.references} />
335
+ ))}
336
+ </main>
337
+ );
338
+ }
339
+ ```
340
+
341
+ **Option B — `LocalessDocument` component**: no client re-fetch, uses server data directly, auto-syncs with editor.
342
+
343
+ ```tsx
344
+ // app/[locale]/page.tsx — no separate client file needed
345
+ import { getLocalessClient, LocalessDocument } from "@localess/react";
346
+ import type { Page } from "./.localess/localess";
347
+
348
+ export default async function HomePage({ params }: { params: Promise<{ locale?: string }> }) {
349
+ const { locale } = await params;
350
+ const content = await getLocalessClient().getContentBySlug<Page>('home', { locale });
351
+
352
+ return (
353
+ <LocalessDocument data={content.data} links={content.links} references={content.references} />
354
+ );
355
+ }
356
+ ```
357
+
358
+ **Option C — Manual**: full control, initialise state with server-preloaded data, subscribe to sync yourself.
359
+
360
+ ```tsx
361
+ // app/[locale]/page-client.tsx
362
+ 'use client';
363
+
364
+ import { useEffect, useState } from "react";
365
+ import { LocalessComponent, localessEditable, isSyncEnabled, isBrowser } from "@localess/react";
366
+ import type { Content, Page } from "./.localess/localess";
367
+
368
+ export function PageClient({ initialContent }: { initialContent: Content<Page> }) {
369
+ // Server-preloaded data used as initial state — no loading flash
370
+ const [pageData, setPageData] = useState(initialContent.data);
371
+
372
+ useEffect(() => {
373
+ if (isSyncEnabled() && isBrowser() && window.localess) {
374
+ window.localess.on(['input', 'change'], (event) => {
375
+ if (event.type === 'input' || event.type === 'change') {
376
+ setPageData(event.data);
377
+ }
378
+ });
379
+ }
380
+ // No cleanup needed: window.localess has no .off() method
381
+ }, []);
382
+
383
+ return (
384
+ <main {...localessEditable(pageData)}>
385
+ {pageData?.body?.map(item => (
386
+ <LocalessComponent key={item._id} data={item} links={initialContent.links} references={initialContent.references} />
262
387
  ))}
263
388
  </main>
264
389
  );
@@ -400,7 +525,7 @@ const [content, translations] = await Promise.all([
400
525
 
401
526
  ---
402
527
 
403
- ## Full Next.js 15 App Router Setup
528
+ ## Full Next.js 16.2 App Router Setup
404
529
 
405
530
  ```typescript
406
531
  // app/layout.tsx (Server Component)
@@ -476,6 +601,7 @@ export { setFallbackComponent, getFallbackComponent, isSyncEnabled }
476
601
 
477
602
  // Rendering
478
603
  export { LocalessComponent } // Dynamic schema-to-component renderer
604
+ export { LocalessDocument } // Schema renderer + built-in Visual Editor sync
479
605
  export { renderRichTextToReact } // Rich text → React nodes
480
606
  export { resolveAsset } // ContentAsset → full URL
481
607
 
package/dist/index.d.mts CHANGED
@@ -10,6 +10,13 @@ type LocalessComponentProps<T extends ContentData = ContentData> = {
10
10
  };
11
11
  declare const LocalessComponent: React.ForwardRefExoticComponent<LocalessComponentProps<ContentData> & React.RefAttributes<HTMLElement>>;
12
12
 
13
+ type LocalessDocumentProps<T extends ContentData = ContentData> = {
14
+ data: T;
15
+ links?: Links;
16
+ references?: References;
17
+ };
18
+ declare const LocalessDocument: React.ForwardRefExoticComponent<LocalessDocumentProps<ContentData> & React.RefAttributes<HTMLElement>>;
19
+
13
20
  type LocalessOptions = LocalessClientOptions & {
14
21
  /**
15
22
  * Components mapping for Localess Component integration
@@ -91,4 +98,4 @@ declare function isSyncEnabled(): boolean;
91
98
  */
92
99
  declare function resolveAsset(asset: ContentAsset): string;
93
100
 
94
- export { LocalessComponent, type LocalessComponentProps, type LocalessOptions, type UseLocalessOptions, findLink, getComponent, getFallbackComponent, getLocalessClient, isSyncEnabled, localessInit, registerComponent, renderRichTextToReact, resolveAsset, setComponents, setFallbackComponent, unregisterComponent, useLocaless };
101
+ export { LocalessComponent, type LocalessComponentProps, LocalessDocument, type LocalessDocumentProps, type LocalessOptions, type UseLocalessOptions, findLink, getComponent, getFallbackComponent, getLocalessClient, isSyncEnabled, localessInit, registerComponent, renderRichTextToReact, resolveAsset, setComponents, setFallbackComponent, unregisterComponent, useLocaless };
package/dist/index.d.ts CHANGED
@@ -10,6 +10,13 @@ type LocalessComponentProps<T extends ContentData = ContentData> = {
10
10
  };
11
11
  declare const LocalessComponent: React.ForwardRefExoticComponent<LocalessComponentProps<ContentData> & React.RefAttributes<HTMLElement>>;
12
12
 
13
+ type LocalessDocumentProps<T extends ContentData = ContentData> = {
14
+ data: T;
15
+ links?: Links;
16
+ references?: References;
17
+ };
18
+ declare const LocalessDocument: React.ForwardRefExoticComponent<LocalessDocumentProps<ContentData> & React.RefAttributes<HTMLElement>>;
19
+
13
20
  type LocalessOptions = LocalessClientOptions & {
14
21
  /**
15
22
  * Components mapping for Localess Component integration
@@ -91,4 +98,4 @@ declare function isSyncEnabled(): boolean;
91
98
  */
92
99
  declare function resolveAsset(asset: ContentAsset): string;
93
100
 
94
- export { LocalessComponent, type LocalessComponentProps, type LocalessOptions, type UseLocalessOptions, findLink, getComponent, getFallbackComponent, getLocalessClient, isSyncEnabled, localessInit, registerComponent, renderRichTextToReact, resolveAsset, setComponents, setFallbackComponent, unregisterComponent, useLocaless };
101
+ export { LocalessComponent, type LocalessComponentProps, LocalessDocument, type LocalessDocumentProps, type LocalessOptions, type UseLocalessOptions, findLink, getComponent, getFallbackComponent, getLocalessClient, isSyncEnabled, localessInit, registerComponent, renderRichTextToReact, resolveAsset, setComponents, setFallbackComponent, unregisterComponent, useLocaless };
package/dist/index.js CHANGED
@@ -21,16 +21,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  LocalessComponent: () => LocalessComponent,
24
+ LocalessDocument: () => LocalessDocument,
24
25
  findLink: () => findLink,
25
26
  getComponent: () => getComponent,
26
27
  getFallbackComponent: () => getFallbackComponent,
27
28
  getLocalessClient: () => getLocalessClient,
28
- isBrowser: () => import_client4.isBrowser,
29
- isIframe: () => import_client4.isIframe,
30
- isServer: () => import_client4.isServer,
29
+ isBrowser: () => import_client5.isBrowser,
30
+ isIframe: () => import_client5.isIframe,
31
+ isServer: () => import_client5.isServer,
31
32
  isSyncEnabled: () => isSyncEnabled,
32
- localessEditable: () => import_client4.localessEditable,
33
- localessEditableField: () => import_client4.localessEditableField,
33
+ localessEditable: () => import_client5.localessEditable,
34
+ localessEditableField: () => import_client5.localessEditableField,
34
35
  localessInit: () => localessInit,
35
36
  registerComponent: () => registerComponent,
36
37
  renderRichTextToReact: () => renderRichTextToReact,
@@ -41,7 +42,7 @@ __export(index_exports, {
41
42
  useLocaless: () => useLocaless
42
43
  });
43
44
  module.exports = __toCommonJS(index_exports);
44
- var import_client4 = require("@localess/client");
45
+ var import_client5 = require("@localess/client");
45
46
 
46
47
  // src/components/localess-component.tsx
47
48
  var import_react = require("react");
@@ -137,11 +138,30 @@ var LocalessComponent = (0, import_react.forwardRef)(({ data, links, references,
137
138
  ] });
138
139
  });
139
140
 
140
- // src/hooks/use-localess.ts
141
+ // src/components/localess-document.tsx
141
142
  var import_react2 = require("react");
142
143
  var import_client3 = require("@localess/client");
144
+ var import_jsx_runtime2 = require("react/jsx-runtime");
145
+ var LocalessDocument = (0, import_react2.forwardRef)(({ data, links, references, ...restProps }, ref) => {
146
+ const [contentData, setContentData] = (0, import_react2.useState)(data);
147
+ (0, import_react2.useEffect)(() => {
148
+ if (isSyncEnabled() && (0, import_client3.isBrowser)()) {
149
+ window.localess?.on(["input", "change"], (event) => {
150
+ console.log("Localess:event", event);
151
+ if (event.type === "change" || event.type === "input") {
152
+ setContentData(event.data);
153
+ }
154
+ });
155
+ }
156
+ });
157
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LocalessComponent, { data: contentData, links, references, ...restProps });
158
+ });
159
+
160
+ // src/hooks/use-localess.ts
161
+ var import_react3 = require("react");
162
+ var import_client4 = require("@localess/client");
143
163
  var useLocaless = (slug, options = {}) => {
144
- const [document, setDocument] = (0, import_react2.useState)();
164
+ const [document, setDocument] = (0, import_react3.useState)();
145
165
  const client = getLocalessClient();
146
166
  let normalizedSlug;
147
167
  if (Array.isArray(slug)) {
@@ -149,11 +169,11 @@ var useLocaless = (slug, options = {}) => {
149
169
  } else {
150
170
  normalizedSlug = slug;
151
171
  }
152
- (0, import_react2.useEffect)(() => {
172
+ (0, import_react3.useEffect)(() => {
153
173
  async function loadDocument() {
154
174
  const document2 = await client.getContentBySlug(normalizedSlug, options);
155
175
  setDocument(document2);
156
- if (isSyncEnabled() && (0, import_client3.isBrowser)()) {
176
+ if (isSyncEnabled() && (0, import_client4.isBrowser)()) {
157
177
  window.localess?.on(["input", "change"], (event) => {
158
178
  if (event.type === "change" || event.type === "input") {
159
179
  setDocument({ ...document2, data: event.data });
@@ -188,7 +208,7 @@ function findLink(links, link) {
188
208
  }
189
209
 
190
210
  // src/richtext.ts
191
- var import_react3 = require("@tiptap/static-renderer/pm/react");
211
+ var import_react4 = require("@tiptap/static-renderer/pm/react");
192
212
  var import_extension_document = require("@tiptap/extension-document");
193
213
  var import_extension_text = require("@tiptap/extension-text");
194
214
  var import_extension_paragraph = require("@tiptap/extension-paragraph");
@@ -205,7 +225,7 @@ var import_extension_code = require("@tiptap/extension-code");
205
225
  var import_extension_code_block_lowlight = require("@tiptap/extension-code-block-lowlight");
206
226
  var import_extension_link = require("@tiptap/extension-link");
207
227
  function renderRichTextToReact(content) {
208
- return (0, import_react3.renderToReactElement)({
228
+ return (0, import_react4.renderToReactElement)({
209
229
  content,
210
230
  extensions: [
211
231
  import_extension_document.Document,
@@ -231,6 +251,7 @@ function renderRichTextToReact(content) {
231
251
  // Annotate the CommonJS export names for ESM import in node:
232
252
  0 && (module.exports = {
233
253
  LocalessComponent,
254
+ LocalessDocument,
234
255
  findLink,
235
256
  getComponent,
236
257
  getFallbackComponent,
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { localessEditable as localessEditable2, localessEditableField, isBrowser as isBrowser2, isServer, isIframe } from "@localess/client";
2
+ import { localessEditable as localessEditable2, localessEditableField, isBrowser as isBrowser3, isServer, isIframe } from "@localess/client";
3
3
 
4
4
  // src/components/localess-component.tsx
5
5
  import { forwardRef } from "react";
@@ -95,11 +95,30 @@ var LocalessComponent = forwardRef(({ data, links, references, ...restProps }, r
95
95
  ] });
96
96
  });
97
97
 
98
- // src/hooks/use-localess.ts
99
- import { useEffect, useState } from "react";
98
+ // src/components/localess-document.tsx
99
+ import { forwardRef as forwardRef2, useEffect, useState } from "react";
100
100
  import { isBrowser } from "@localess/client";
101
+ import { jsx as jsx2 } from "react/jsx-runtime";
102
+ var LocalessDocument = forwardRef2(({ data, links, references, ...restProps }, ref) => {
103
+ const [contentData, setContentData] = useState(data);
104
+ useEffect(() => {
105
+ if (isSyncEnabled() && isBrowser()) {
106
+ window.localess?.on(["input", "change"], (event) => {
107
+ console.log("Localess:event", event);
108
+ if (event.type === "change" || event.type === "input") {
109
+ setContentData(event.data);
110
+ }
111
+ });
112
+ }
113
+ });
114
+ return /* @__PURE__ */ jsx2(LocalessComponent, { data: contentData, links, references, ...restProps });
115
+ });
116
+
117
+ // src/hooks/use-localess.ts
118
+ import { useEffect as useEffect2, useState as useState2 } from "react";
119
+ import { isBrowser as isBrowser2 } from "@localess/client";
101
120
  var useLocaless = (slug, options = {}) => {
102
- const [document, setDocument] = useState();
121
+ const [document, setDocument] = useState2();
103
122
  const client = getLocalessClient();
104
123
  let normalizedSlug;
105
124
  if (Array.isArray(slug)) {
@@ -107,11 +126,11 @@ var useLocaless = (slug, options = {}) => {
107
126
  } else {
108
127
  normalizedSlug = slug;
109
128
  }
110
- useEffect(() => {
129
+ useEffect2(() => {
111
130
  async function loadDocument() {
112
131
  const document2 = await client.getContentBySlug(normalizedSlug, options);
113
132
  setDocument(document2);
114
- if (isSyncEnabled() && isBrowser()) {
133
+ if (isSyncEnabled() && isBrowser2()) {
115
134
  window.localess?.on(["input", "change"], (event) => {
116
135
  if (event.type === "change" || event.type === "input") {
117
136
  setDocument({ ...document2, data: event.data });
@@ -188,11 +207,12 @@ function renderRichTextToReact(content) {
188
207
  }
189
208
  export {
190
209
  LocalessComponent,
210
+ LocalessDocument,
191
211
  findLink,
192
212
  getComponent,
193
213
  getFallbackComponent,
194
214
  getLocalessClient,
195
- isBrowser2 as isBrowser,
215
+ isBrowser3 as isBrowser,
196
216
  isIframe,
197
217
  isServer,
198
218
  isSyncEnabled,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localess/react",
3
- "version": "3.0.1-dev.20260408172608",
3
+ "version": "3.0.1-dev.20260408183951",
4
4
  "description": "ReactJS JavaScript/TypeScript SDK for Localess's API.",
5
5
  "keywords": [
6
6
  "localess",
@@ -46,7 +46,7 @@
46
46
  "react-dom": "^17 || ^18 || ^19"
47
47
  },
48
48
  "dependencies": {
49
- "@localess/client": "3.0.1-dev.20260408172608",
49
+ "@localess/client": "3.0.1-dev.20260408183951",
50
50
  "@tiptap/static-renderer": "^3.20.1",
51
51
  "@tiptap/html": "^3.20.1",
52
52
  "@tiptap/extension-bold": "^3.20.1",