@typecms/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,736 @@
1
+ // src/preview/client.ts
2
+ var DEFAULT_ALLOWED_ORIGINS = [
3
+ "https://app.typecms.com",
4
+ "https://staging.typecms.com",
5
+ "http://localhost:3000",
6
+ "http://localhost:3001"
7
+ ];
8
+ function createPreviewClient(config = {}) {
9
+ const {
10
+ allowedOrigins = DEFAULT_ALLOWED_ORIGINS,
11
+ onInit,
12
+ onUpdate,
13
+ onNavigate,
14
+ onFocus,
15
+ debug = false
16
+ } = config;
17
+ let state = {
18
+ enabled: false,
19
+ entryId: null,
20
+ projectId: null,
21
+ locale: null,
22
+ typeId: null,
23
+ values: {},
24
+ focusedPath: null
25
+ };
26
+ const listeners = /* @__PURE__ */ new Set();
27
+ let isConnected = false;
28
+ let parentOrigin = null;
29
+ function log(...args) {
30
+ if (debug) {
31
+ console.log("[TypeCMS Preview]", ...args);
32
+ }
33
+ }
34
+ function setState(updates) {
35
+ state = { ...state, ...updates };
36
+ listeners.forEach((listener) => listener(state));
37
+ }
38
+ function isAllowedOrigin(origin) {
39
+ return allowedOrigins.some((allowed) => {
40
+ if (allowed === "*") return true;
41
+ const expected = allowed.endsWith("/*") ? allowed.slice(0, -2) : allowed;
42
+ return origin === expected;
43
+ });
44
+ }
45
+ function sendMessage(message) {
46
+ if (!parentOrigin) {
47
+ log("Cannot send message: no parent origin");
48
+ return;
49
+ }
50
+ if (typeof window === "undefined" || !window.parent) {
51
+ log("Cannot send message: not in iframe");
52
+ return;
53
+ }
54
+ log("Sending message:", message.type);
55
+ window.parent.postMessage(message, parentOrigin);
56
+ }
57
+ function handleMessage(event) {
58
+ if (!isAllowedOrigin(event.origin)) {
59
+ log("Ignored message from untrusted origin:", event.origin);
60
+ return;
61
+ }
62
+ const message = event.data;
63
+ if (!message?.type?.startsWith("typecms:preview:")) {
64
+ return;
65
+ }
66
+ log("Received message:", message.type, message);
67
+ parentOrigin = event.origin;
68
+ switch (message.type) {
69
+ case "typecms:preview:init": {
70
+ const initMsg = message;
71
+ setState({
72
+ enabled: true,
73
+ entryId: initMsg.payload.entryId,
74
+ projectId: initMsg.payload.projectId,
75
+ locale: initMsg.payload.locale,
76
+ typeId: initMsg.payload.typeId,
77
+ values: {},
78
+ focusedPath: null
79
+ });
80
+ onInit?.(initMsg.payload);
81
+ const readyMessage = {
82
+ type: "typecms:preview:ready",
83
+ timestamp: Date.now(),
84
+ payload: {
85
+ pathname: typeof window !== "undefined" ? window.location.pathname : "/"
86
+ }
87
+ };
88
+ sendMessage(readyMessage);
89
+ break;
90
+ }
91
+ case "typecms:preview:update": {
92
+ const updateMsg = message;
93
+ if (updateMsg.payload.values) {
94
+ setState({ values: updateMsg.payload.values });
95
+ } else {
96
+ const newValues = { ...state.values };
97
+ setNestedValue(newValues, updateMsg.payload.path, updateMsg.payload.value);
98
+ setState({ values: newValues });
99
+ }
100
+ onUpdate?.(updateMsg.payload);
101
+ break;
102
+ }
103
+ case "typecms:preview:navigate": {
104
+ onNavigate?.(message.payload.url);
105
+ break;
106
+ }
107
+ case "typecms:preview:focus": {
108
+ setState({ focusedPath: message.payload.path });
109
+ onFocus?.(message.payload.path);
110
+ break;
111
+ }
112
+ }
113
+ }
114
+ return {
115
+ /**
116
+ * Start listening for preview messages.
117
+ * Call this on mount.
118
+ */
119
+ connect() {
120
+ if (typeof window === "undefined") {
121
+ log("Cannot connect: not in browser");
122
+ return;
123
+ }
124
+ if (isConnected) {
125
+ log("Already connected");
126
+ return;
127
+ }
128
+ log("Connecting...");
129
+ window.addEventListener("message", handleMessage);
130
+ isConnected = true;
131
+ if (window.parent && window.parent !== window) {
132
+ const hello = {
133
+ type: "typecms:preview:ready",
134
+ timestamp: Date.now(),
135
+ payload: { pathname: window.location?.pathname ?? "/" }
136
+ };
137
+ for (const allowed of allowedOrigins) {
138
+ const target = allowed === "*" ? "*" : allowed.endsWith("/*") ? allowed.slice(0, -2) : allowed;
139
+ try {
140
+ window.parent.postMessage(hello, target);
141
+ } catch {
142
+ }
143
+ }
144
+ }
145
+ },
146
+ /**
147
+ * Stop listening for preview messages.
148
+ * Call this on unmount.
149
+ */
150
+ disconnect() {
151
+ if (typeof window === "undefined") return;
152
+ log("Disconnecting...");
153
+ window.removeEventListener("message", handleMessage);
154
+ isConnected = false;
155
+ parentOrigin = null;
156
+ setState({
157
+ enabled: false,
158
+ entryId: null,
159
+ projectId: null,
160
+ locale: null,
161
+ typeId: null,
162
+ values: {},
163
+ focusedPath: null
164
+ });
165
+ },
166
+ /**
167
+ * Get current preview state.
168
+ */
169
+ getState() {
170
+ return state;
171
+ },
172
+ /**
173
+ * Check if preview mode is active.
174
+ */
175
+ isEnabled() {
176
+ return state.enabled;
177
+ },
178
+ /**
179
+ * Get a preview value by path.
180
+ * Returns undefined if no preview value exists.
181
+ */
182
+ getValue(path) {
183
+ return getNestedValue(state.values, path);
184
+ },
185
+ /**
186
+ * Subscribe to state changes.
187
+ */
188
+ subscribe(listener) {
189
+ listeners.add(listener);
190
+ return () => listeners.delete(listener);
191
+ },
192
+ /**
193
+ * Notify the editor that the preview has navigated.
194
+ */
195
+ notifyNavigation(pathname) {
196
+ const message = {
197
+ type: "typecms:preview:ready",
198
+ timestamp: Date.now(),
199
+ payload: { pathname }
200
+ };
201
+ sendMessage(message);
202
+ },
203
+ /**
204
+ * Notify the editor that a field was clicked in the preview.
205
+ * The editor will scroll to the corresponding field.
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * // On click of an element with data-preview-field attribute:
210
+ * const path = el.closest('[data-preview-field]')?.dataset.previewField
211
+ * if (path) preview.notifyFieldFocus(path)
212
+ * ```
213
+ */
214
+ notifyFieldFocus(path) {
215
+ const message = {
216
+ type: "typecms:preview:focus",
217
+ timestamp: Date.now(),
218
+ payload: { path }
219
+ };
220
+ sendMessage(message);
221
+ }
222
+ };
223
+ }
224
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
225
+ function setNestedValue(obj, path, value) {
226
+ const parts = path.split(".");
227
+ let current = obj;
228
+ for (let i = 0; i < parts.length - 1; i++) {
229
+ const part = parts[i];
230
+ const arrayMatch2 = part.match(/^(\w+)\[(\d+)\]$/);
231
+ if (arrayMatch2) {
232
+ const [, name, indexStr] = arrayMatch2;
233
+ const index = parseInt(indexStr, 10);
234
+ if (UNSAFE_KEYS.has(name)) continue;
235
+ if (!current[name]) {
236
+ current[name] = [];
237
+ }
238
+ const arr = current[name];
239
+ if (!arr[index]) {
240
+ arr[index] = {};
241
+ }
242
+ current = arr[index];
243
+ } else {
244
+ if (UNSAFE_KEYS.has(part)) continue;
245
+ if (!current[part] || typeof current[part] !== "object") {
246
+ current[part] = {};
247
+ }
248
+ current = current[part];
249
+ }
250
+ }
251
+ const lastPart = parts[parts.length - 1];
252
+ const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/);
253
+ if (arrayMatch) {
254
+ const [, name, indexStr] = arrayMatch;
255
+ const index = parseInt(indexStr, 10);
256
+ if (UNSAFE_KEYS.has(name)) return;
257
+ if (!current[name]) {
258
+ current[name] = [];
259
+ }
260
+ current[name][index] = value;
261
+ } else {
262
+ if (UNSAFE_KEYS.has(lastPart)) return;
263
+ current[lastPart] = value;
264
+ }
265
+ }
266
+ function getNestedValue(obj, path) {
267
+ const parts = path.split(".");
268
+ let current = obj;
269
+ for (const part of parts) {
270
+ if (current === null || current === void 0) {
271
+ return void 0;
272
+ }
273
+ const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
274
+ if (arrayMatch) {
275
+ const [, name, indexStr] = arrayMatch;
276
+ const index = parseInt(indexStr, 10);
277
+ const arr = current[name];
278
+ if (!arr) return void 0;
279
+ current = arr[index];
280
+ } else {
281
+ current = current[part];
282
+ }
283
+ }
284
+ return current;
285
+ }
286
+ function deepMerge(target, source) {
287
+ const result = { ...target };
288
+ for (const key of Object.keys(source)) {
289
+ const sourceValue = source[key];
290
+ const targetValue = result[key];
291
+ if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
292
+ result[key] = deepMerge(
293
+ targetValue,
294
+ sourceValue
295
+ );
296
+ } else {
297
+ result[key] = sourceValue;
298
+ }
299
+ }
300
+ return result;
301
+ }
302
+
303
+ // src/preview/overlay.ts
304
+ var DEFAULT_OPTIONS = {
305
+ color: "#3b82f6",
306
+ zIndex: 9999,
307
+ scrollIntoView: true,
308
+ attribute: "data-preview-field"
309
+ };
310
+ function attachPreviewOverlay(client, options = {}) {
311
+ if (typeof window === "undefined" || typeof document === "undefined") {
312
+ return () => {
313
+ };
314
+ }
315
+ const { color, zIndex, scrollIntoView, attribute } = { ...DEFAULT_OPTIONS, ...options };
316
+ const box = document.createElement("div");
317
+ box.setAttribute("data-typecms-preview-overlay", "");
318
+ Object.assign(box.style, {
319
+ position: "fixed",
320
+ display: "none",
321
+ pointerEvents: "none",
322
+ boxSizing: "border-box",
323
+ border: `2px solid ${color}`,
324
+ borderRadius: "4px",
325
+ zIndex: String(zIndex),
326
+ transition: "top 120ms ease, left 120ms ease, width 120ms ease, height 120ms ease"
327
+ });
328
+ document.body.appendChild(box);
329
+ let target = null;
330
+ let lastPath = null;
331
+ function position() {
332
+ if (!target || !target.isConnected) {
333
+ box.style.display = "none";
334
+ return;
335
+ }
336
+ const rect = target.getBoundingClientRect();
337
+ Object.assign(box.style, {
338
+ display: "block",
339
+ top: `${rect.top - 2}px`,
340
+ left: `${rect.left - 2}px`,
341
+ width: `${rect.width + 4}px`,
342
+ height: `${rect.height + 4}px`
343
+ });
344
+ }
345
+ function update(state) {
346
+ const path = state.enabled ? state.focusedPath : null;
347
+ if (path === lastPath) return;
348
+ lastPath = path;
349
+ target = path ? document.querySelector(`[${attribute}="${CSS.escape(path)}"]`) : null;
350
+ if (target && scrollIntoView) {
351
+ target.scrollIntoView({ behavior: "smooth", block: "center" });
352
+ }
353
+ position();
354
+ }
355
+ window.addEventListener("scroll", position, true);
356
+ window.addEventListener("resize", position);
357
+ const unsubscribe = client.subscribe(update);
358
+ update(client.getState());
359
+ return () => {
360
+ unsubscribe();
361
+ window.removeEventListener("scroll", position, true);
362
+ window.removeEventListener("resize", position);
363
+ box.remove();
364
+ target = null;
365
+ };
366
+ }
367
+
368
+ // src/preview/sourcemap.ts
369
+ var DEFAULT_ATTRIBUTE = "data-preview-field";
370
+ var DEFAULT_MIN_LENGTH = 3;
371
+ var ELEMENT_NODE = 1;
372
+ var TEXT_NODE = 3;
373
+ function collectStringLeaves(value, prefix, out) {
374
+ if (typeof value === "string") {
375
+ const text = value.trim();
376
+ if (!text) return;
377
+ const paths = out.get(text);
378
+ if (paths) {
379
+ paths.push(prefix);
380
+ } else {
381
+ out.set(text, [prefix]);
382
+ }
383
+ return;
384
+ }
385
+ if (Array.isArray(value)) {
386
+ for (let i = 0; i < value.length; i++) {
387
+ collectStringLeaves(value[i], `${prefix}[${i}]`, out);
388
+ }
389
+ return;
390
+ }
391
+ if (value && typeof value === "object") {
392
+ for (const key of Object.keys(value)) {
393
+ const childPrefix = prefix ? `${prefix}.${key}` : key;
394
+ collectStringLeaves(value[key], childPrefix, out);
395
+ }
396
+ }
397
+ }
398
+ function ownText(el) {
399
+ const kids = el.childNodes;
400
+ if (!kids) return "";
401
+ let text = "";
402
+ for (let i = 0; i < kids.length; i++) {
403
+ const child = kids[i];
404
+ if (child.nodeType === TEXT_NODE) {
405
+ text += child.textContent ?? "";
406
+ }
407
+ }
408
+ return text.trim();
409
+ }
410
+ function walk(node, visit) {
411
+ if (node.nodeType === ELEMENT_NODE && typeof node.getAttribute === "function") {
412
+ if (!visit(node)) return false;
413
+ }
414
+ const kids = node.childNodes;
415
+ if (!kids) return true;
416
+ for (let i = 0; i < kids.length; i++) {
417
+ if (!walk(kids[i], visit)) return false;
418
+ }
419
+ return true;
420
+ }
421
+ function autoTagPreviewFields(client, options = {}) {
422
+ if (typeof document === "undefined") {
423
+ return () => {
424
+ };
425
+ }
426
+ const attribute = options.attribute ?? DEFAULT_ATTRIBUTE;
427
+ const minLength = options.minLength ?? DEFAULT_MIN_LENGTH;
428
+ const observe = options.observe ?? true;
429
+ const rootNode = options.root ?? document.body;
430
+ const taggedByPath = /* @__PURE__ */ new Map();
431
+ function isStillTagged(path) {
432
+ const el = taggedByPath.get(path);
433
+ if (!el) return false;
434
+ if (el.isConnected === false || el.getAttribute?.(attribute) !== path) {
435
+ taggedByPath.delete(path);
436
+ return false;
437
+ }
438
+ return true;
439
+ }
440
+ let lastState = client.getState();
441
+ function runPass(state) {
442
+ if (!state.enabled) return;
443
+ const values = state.values;
444
+ if (!values || Object.keys(values).length === 0) return;
445
+ const pathsByValue = /* @__PURE__ */ new Map();
446
+ collectStringLeaves(values, "", pathsByValue);
447
+ const candidates = /* @__PURE__ */ new Map();
448
+ pathsByValue.forEach((paths, text) => {
449
+ if (text.length < minLength) return;
450
+ if (paths.length !== 1) return;
451
+ if (isStillTagged(paths[0])) return;
452
+ candidates.set(text, paths[0]);
453
+ });
454
+ if (candidates.size === 0) return;
455
+ walk(rootNode, (el) => {
456
+ if (typeof el.getAttribute !== "function" || typeof el.setAttribute !== "function") {
457
+ return true;
458
+ }
459
+ if (el.getAttribute(attribute) !== null) return true;
460
+ const text = ownText(el);
461
+ if (!text) return true;
462
+ const path = candidates.get(text);
463
+ if (path === void 0) return true;
464
+ el.setAttribute(attribute, path);
465
+ taggedByPath.set(path, el);
466
+ candidates.delete(text);
467
+ return candidates.size > 0;
468
+ });
469
+ }
470
+ const unsubscribe = client.subscribe((state) => {
471
+ lastState = state;
472
+ runPass(state);
473
+ });
474
+ runPass(lastState);
475
+ let observer = null;
476
+ if (observe && typeof MutationObserver !== "undefined") {
477
+ observer = new MutationObserver((mutations) => {
478
+ const hasNodeChanges = mutations.some(
479
+ (m) => m.addedNodes && m.addedNodes.length > 0 || m.removedNodes && m.removedNodes.length > 0
480
+ );
481
+ if (hasNodeChanges) runPass(lastState);
482
+ });
483
+ observer.observe(rootNode, { childList: true, subtree: true });
484
+ }
485
+ return () => {
486
+ unsubscribe();
487
+ observer?.disconnect();
488
+ observer = null;
489
+ taggedByPath.forEach((el) => {
490
+ el.removeAttribute?.(attribute);
491
+ });
492
+ taggedByPath.clear();
493
+ };
494
+ }
495
+
496
+ // src/preview/richtext.ts
497
+ function isPlainObject(value) {
498
+ return typeof value === "object" && value !== null && !Array.isArray(value);
499
+ }
500
+ function isTipTapDoc(value) {
501
+ return isPlainObject(value) && value.type === "doc" && Array.isArray(value.content);
502
+ }
503
+ function isSlateDoc(value) {
504
+ return Array.isArray(value) && value.every((node) => isPlainObject(node) && ("children" in node || "text" in node));
505
+ }
506
+ function shareStructure(prev, next) {
507
+ if (prev === next || prev === void 0) {
508
+ return next;
509
+ }
510
+ if (Array.isArray(prev) && Array.isArray(next)) {
511
+ return shareArray(prev, next);
512
+ }
513
+ if (isPlainObject(prev) && isPlainObject(next)) {
514
+ return shareObject(prev, next);
515
+ }
516
+ return next;
517
+ }
518
+ function shareArray(prev, next) {
519
+ const prevLength = prev.length;
520
+ const nextLength = next.length;
521
+ const result = new Array(nextLength);
522
+ let tail = 0;
523
+ const maxTail = Math.min(prevLength, nextLength);
524
+ while (tail < maxTail) {
525
+ const prevItem = prev[prevLength - 1 - tail];
526
+ const shared = shareStructure(prevItem, next[nextLength - 1 - tail]);
527
+ if (shared !== prevItem) break;
528
+ result[nextLength - 1 - tail] = shared;
529
+ tail++;
530
+ }
531
+ const prevHeadLength = prevLength - tail;
532
+ for (let i = 0; i < nextLength - tail; i++) {
533
+ result[i] = i < prevHeadLength ? shareStructure(prev[i], next[i]) : next[i];
534
+ }
535
+ if (prevLength === nextLength) {
536
+ let allShared = true;
537
+ for (let i = 0; i < nextLength; i++) {
538
+ if (result[i] !== prev[i]) {
539
+ allShared = false;
540
+ break;
541
+ }
542
+ }
543
+ if (allShared) return prev;
544
+ }
545
+ return result;
546
+ }
547
+ function shareObject(prev, next) {
548
+ const nextKeys = Object.keys(next);
549
+ const result = {};
550
+ let allShared = nextKeys.length === Object.keys(prev).length;
551
+ for (const key of nextKeys) {
552
+ const hasPrev = Object.prototype.hasOwnProperty.call(prev, key);
553
+ const shared = hasPrev ? shareStructure(prev[key], next[key]) : next[key];
554
+ result[key] = shared;
555
+ if (!hasPrev || shared !== prev[key]) {
556
+ allShared = false;
557
+ }
558
+ }
559
+ return allShared ? prev : result;
560
+ }
561
+ function createRichTextPreview(options = {}) {
562
+ let lastDoc = options.initial;
563
+ return {
564
+ apply(nextDoc) {
565
+ const shared = shareStructure(lastDoc, nextDoc);
566
+ lastDoc = shared;
567
+ return shared;
568
+ },
569
+ reset() {
570
+ lastDoc = void 0;
571
+ }
572
+ };
573
+ }
574
+
575
+ // src/preview/react.tsx
576
+ import {
577
+ createContext,
578
+ useContext,
579
+ useEffect,
580
+ useRef,
581
+ useState,
582
+ useMemo,
583
+ useCallback
584
+ } from "react";
585
+ import { jsx } from "react/jsx-runtime";
586
+ var PreviewContext = createContext(null);
587
+ function PreviewProvider({ children, overlay, ...config }) {
588
+ const [state, setState] = useState({
589
+ enabled: false,
590
+ entryId: null,
591
+ projectId: null,
592
+ locale: null,
593
+ typeId: null,
594
+ values: {},
595
+ focusedPath: null
596
+ });
597
+ const client = useMemo(() => createPreviewClient(config), []);
598
+ useEffect(() => {
599
+ const unsubscribe = client.subscribe(setState);
600
+ client.connect();
601
+ return () => {
602
+ unsubscribe();
603
+ client.disconnect();
604
+ };
605
+ }, [client]);
606
+ const overlayRef = useRef(overlay);
607
+ overlayRef.current = overlay;
608
+ const overlayEnabled = !!overlay;
609
+ useEffect(() => {
610
+ if (!overlayEnabled) return;
611
+ const current = overlayRef.current;
612
+ return attachPreviewOverlay(client, current === true || !current ? {} : current);
613
+ }, [client, overlayEnabled]);
614
+ const getValue = useCallback(
615
+ (path) => {
616
+ return client.getValue(path);
617
+ },
618
+ [client]
619
+ );
620
+ const mergeContent = useCallback(
621
+ (content) => {
622
+ if (!state.enabled || Object.keys(state.values).length === 0) {
623
+ return content;
624
+ }
625
+ return deepMerge(content, state.values);
626
+ },
627
+ [state.enabled, state.values]
628
+ );
629
+ const notifyNavigation = useCallback(
630
+ (pathname) => {
631
+ client.notifyNavigation(pathname);
632
+ },
633
+ [client]
634
+ );
635
+ const notifyFieldFocus = useCallback(
636
+ (path) => {
637
+ client.notifyFieldFocus(path);
638
+ },
639
+ [client]
640
+ );
641
+ const value = useMemo(
642
+ () => ({
643
+ state,
644
+ isPreview: state.enabled,
645
+ getValue,
646
+ mergeContent,
647
+ notifyNavigation,
648
+ notifyFieldFocus
649
+ }),
650
+ [state, getValue, mergeContent, notifyNavigation, notifyFieldFocus]
651
+ );
652
+ return /* @__PURE__ */ jsx(PreviewContext.Provider, { value, children });
653
+ }
654
+ function usePreviewContext() {
655
+ const context = useContext(PreviewContext);
656
+ if (!context) {
657
+ throw new Error("usePreviewContext must be used within a PreviewProvider");
658
+ }
659
+ return context;
660
+ }
661
+ function useIsPreview() {
662
+ const context = useContext(PreviewContext);
663
+ return context?.state.enabled ?? false;
664
+ }
665
+ function usePreviewState() {
666
+ const context = useContext(PreviewContext);
667
+ return context?.state ?? null;
668
+ }
669
+ function usePreviewValue(path, fallback) {
670
+ const context = useContext(PreviewContext);
671
+ if (!context || !context.state.enabled) {
672
+ return fallback;
673
+ }
674
+ const previewValue = context.getValue(path);
675
+ return previewValue !== void 0 ? previewValue : fallback;
676
+ }
677
+ function usePreviewContent(content) {
678
+ const context = useContext(PreviewContext);
679
+ if (!context || !context.state.enabled) {
680
+ return content;
681
+ }
682
+ return context.mergeContent(content);
683
+ }
684
+ function useFocusedField() {
685
+ const context = useContext(PreviewContext);
686
+ return context?.state.focusedPath ?? null;
687
+ }
688
+ function usePreviewNavigation() {
689
+ const context = useContext(PreviewContext);
690
+ return context?.notifyNavigation ?? (() => {
691
+ });
692
+ }
693
+ function usePreviewFieldFocus() {
694
+ const context = useContext(PreviewContext);
695
+ return context?.notifyFieldFocus ?? (() => {
696
+ });
697
+ }
698
+ function usePreviewRichText(path, fallback) {
699
+ const context = useContext(PreviewContext);
700
+ const previewRef = useRef(null);
701
+ const pathRef = useRef(path);
702
+ if (previewRef.current === null) {
703
+ previewRef.current = createRichTextPreview();
704
+ }
705
+ if (pathRef.current !== path) {
706
+ pathRef.current = path;
707
+ previewRef.current.reset();
708
+ }
709
+ if (!context || !context.state.enabled) {
710
+ return fallback;
711
+ }
712
+ const previewValue = context.getValue(path);
713
+ return previewRef.current.apply(previewValue !== void 0 ? previewValue : fallback);
714
+ }
715
+ export {
716
+ PreviewProvider,
717
+ attachPreviewOverlay,
718
+ autoTagPreviewFields,
719
+ createPreviewClient,
720
+ createRichTextPreview,
721
+ deepMerge,
722
+ getNestedValue,
723
+ isSlateDoc,
724
+ isTipTapDoc,
725
+ shareStructure,
726
+ useFocusedField,
727
+ useIsPreview,
728
+ usePreviewContent,
729
+ usePreviewContext,
730
+ usePreviewFieldFocus,
731
+ usePreviewNavigation,
732
+ usePreviewRichText,
733
+ usePreviewState,
734
+ usePreviewValue
735
+ };
736
+ //# sourceMappingURL=index.mjs.map