@kopexa/tiptap 17.8.5 → 17.9.1

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/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _tiptap_core from '@tiptap/core';
2
- import { Node, JSONContent } from '@tiptap/core';
2
+ import { Node, JSONContent, Content as Content$1 } from '@tiptap/core';
3
3
  export { Content, JSONContent } from '@tiptap/core';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import { HocuspocusProvider } from '@hocuspocus/provider';
@@ -646,6 +646,121 @@ type BasicEditorProps = GetExtensionsOptions & EditorBasicVariants & {
646
646
  };
647
647
  declare const BasicEditor: ({ variant, bordered, content, variables, variableValues, showToolbar, pagesOptions, ...options }: BasicEditorProps) => react_jsx_runtime.JSX.Element;
648
648
 
649
+ type EditorViewProps = EditorBasicVariants & Pick<GetExtensionsOptions, "customExtensions" | "disabled"> & {
650
+ /**
651
+ * The TipTap content to render.
652
+ * Accepts JSON, HTML string, Markdown string, or plain text.
653
+ * Internally parsed via `safeParseContent` — same as the `Editor` component.
654
+ */
655
+ content?: Content$1 | undefined;
656
+ /** Additional CSS class names for the root container. */
657
+ className?: string;
658
+ };
659
+ /**
660
+ * Client-side read-only viewer for TipTap content.
661
+ *
662
+ * Uses a real TipTap editor instance in `editable: false` mode, so all
663
+ * NodeViews (images with file-reference resolution, callouts, code blocks,
664
+ * math, tables, etc.) render exactly as they do in the editor — but
665
+ * without the toolbar, bubble menus, slash commands, or collaboration.
666
+ *
667
+ * **Why not `generateHTML`?** Some node types use React NodeViews that
668
+ * resolve data at render time (e.g., images stored as file references that
669
+ * need a signed URL). `generateHTML` produces static HTML and cannot run
670
+ * these React components, resulting in broken images and missing features.
671
+ *
672
+ * **When to use:**
673
+ * - Detail pages, previews, or anywhere you need to display editor content
674
+ * with full NodeView fidelity (image resolution, interactive blocks).
675
+ * - Must be used inside `EditorFileProvider` if your content contains
676
+ * file-reference images.
677
+ *
678
+ * **For server-side rendering** (RSC, SSR, Node.js) where no React NodeViews
679
+ * are needed, use `EditorStaticView` instead. It uses `@tiptap/html` with
680
+ * a virtual DOM and produces pure HTML — but images must already be resolved.
681
+ *
682
+ * @example
683
+ * ```tsx
684
+ * import { EditorView } from "@kopexa/tiptap";
685
+ *
686
+ * function DocumentPreview({ content }: { content: JSONContent }) {
687
+ * return <EditorView content={content} variant="document" />;
688
+ * }
689
+ * ```
690
+ *
691
+ * @example With file resolution
692
+ * ```tsx
693
+ * import { EditorFileProvider, EditorView } from "@kopexa/tiptap";
694
+ *
695
+ * function DocumentDetail({ content }: { content: JSONContent }) {
696
+ * return (
697
+ * <EditorFileProvider onUpload={upload} onResolve={resolve}>
698
+ * <EditorView content={content} variant="document" />
699
+ * </EditorFileProvider>
700
+ * );
701
+ * }
702
+ * ```
703
+ */
704
+ declare function EditorView({ content, variant, bordered, className, customExtensions, disabled, }: EditorViewProps): react_jsx_runtime.JSX.Element | null;
705
+
706
+ type EditorStaticViewProps = EditorBasicVariants & Pick<GetExtensionsOptions, "customExtensions" | "disabled"> & {
707
+ /**
708
+ * The TipTap content to render.
709
+ * Accepts JSON, HTML string, Markdown string, or plain text.
710
+ * Internally parsed via `safeParseContent` — same as the `Editor` component.
711
+ */
712
+ content?: Content$1 | undefined;
713
+ /** Additional CSS class names for the root container. */
714
+ className?: string;
715
+ };
716
+ /**
717
+ * Static HTML viewer for TipTap content.
718
+ *
719
+ * Converts TipTap `JSONContent` to HTML using `generateHTML` from `@tiptap/html`
720
+ * (virtual DOM — no browser required) and renders it with the same styling as
721
+ * the `Editor` component. Works in **Server Components (RSC)**, SSR, and
722
+ * Node.js environments.
723
+ *
724
+ * Uses the full set of registered extensions to ensure all node/mark types
725
+ * produce correct HTML (tables, callouts, code blocks, math, etc.).
726
+ *
727
+ * **Limitations:**
728
+ * - React NodeViews are NOT rendered. Node types that rely on React components
729
+ * (e.g., images with file-reference resolution) will output their default
730
+ * HTML representation. Images stored as file references will NOT be resolved —
731
+ * ensure image `src` values are already displayable URLs before passing content.
732
+ * - No interactive features (no selection, no cursor, no scroll-to-hash).
733
+ *
734
+ * **When to use:**
735
+ * - Server-rendered pages, email templates, PDF generation, or static exports
736
+ * where you need a lightweight, non-interactive HTML representation.
737
+ * - When all image URLs in the content are already resolved (not file references).
738
+ *
739
+ * **For client-side rendering** with full NodeView fidelity (image resolution,
740
+ * interactive blocks), use `EditorView` instead.
741
+ *
742
+ * @example Server Component
743
+ * ```tsx
744
+ * // app/documents/[id]/page.tsx (RSC)
745
+ * import { EditorStaticView } from "@kopexa/tiptap";
746
+ *
747
+ * export default async function DocumentPage({ params }) {
748
+ * const doc = await fetchDocument(params.id);
749
+ * return <EditorStaticView content={doc.content} variant="document" />;
750
+ * }
751
+ * ```
752
+ *
753
+ * @example Client Component
754
+ * ```tsx
755
+ * import { EditorStaticView } from "@kopexa/tiptap";
756
+ *
757
+ * function LightweightPreview({ content }: { content: JSONContent }) {
758
+ * return <EditorStaticView content={content} variant="inline" />;
759
+ * }
760
+ * ```
761
+ */
762
+ declare function EditorStaticView({ content, variant, bordered, className, customExtensions, disabled, }: EditorStaticViewProps): react_jsx_runtime.JSX.Element | null;
763
+
649
764
  /**
650
765
  * Handles image upload with progress tracking and abort capability
651
766
  * @param file The file to upload
@@ -689,4 +804,4 @@ declare function sanitizeUrl(inputUrl: string, baseUrl: string, protocols?: Prot
689
804
  */
690
805
  declare function generateColorFromId(id: string): string;
691
806
 
692
- export { CalloutNode, type CalloutNodeAttrs, type CalloutVariant, type CollabUser, CollaborationProvider, type CollaborationProviderProps, type CollaborationState, type CollaborationStatus, BasicEditor as Editor, type EditorFileHandler, EditorFileProvider, type EditorFileProviderProps, type GetExtensionsOptions, ImageNode, ImageUploadNode, InlineMath, type InlineMathAttrs, MathBlock, type MathBlockAttrs, type ResolvedCollabUser, TocNode, type VariableDefinition, VariableFillerDialog, type VariableFillerDialogProps, VariableNode, type VariableNodeAttrs, type VariableOptions, VariableProvider, type VariableProviderProps, VariableSuggestion, type VariableSuggestionProps, convertFileToBase64, extractVariablesFromContent, generateColorFromId, getExtensions, handleImageUpload, isAllowedUri, sanitizeUrl, useCollaboration, useCollaborationRequired, useDocumentVisibility, useEditorFile, useEditorFileRequired, useIdle, useVariables, useVariablesWithFallback };
807
+ export { CalloutNode, type CalloutNodeAttrs, type CalloutVariant, type CollabUser, CollaborationProvider, type CollaborationProviderProps, type CollaborationState, type CollaborationStatus, BasicEditor as Editor, type EditorFileHandler, EditorFileProvider, type EditorFileProviderProps, EditorStaticView, type EditorStaticViewProps, EditorView, type EditorViewProps, type GetExtensionsOptions, ImageNode, ImageUploadNode, InlineMath, type InlineMathAttrs, MathBlock, type MathBlockAttrs, type ResolvedCollabUser, TocNode, type VariableDefinition, VariableFillerDialog, type VariableFillerDialogProps, VariableNode, type VariableNodeAttrs, type VariableOptions, VariableProvider, type VariableProviderProps, VariableSuggestion, type VariableSuggestionProps, convertFileToBase64, extractVariablesFromContent, generateColorFromId, getExtensions, handleImageUpload, isAllowedUri, sanitizeUrl, useCollaboration, useCollaborationRequired, useDocumentVisibility, useEditorFile, useEditorFileRequired, useIdle, useVariables, useVariablesWithFallback };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _tiptap_core from '@tiptap/core';
2
- import { Node, JSONContent } from '@tiptap/core';
2
+ import { Node, JSONContent, Content as Content$1 } from '@tiptap/core';
3
3
  export { Content, JSONContent } from '@tiptap/core';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import { HocuspocusProvider } from '@hocuspocus/provider';
@@ -646,6 +646,121 @@ type BasicEditorProps = GetExtensionsOptions & EditorBasicVariants & {
646
646
  };
647
647
  declare const BasicEditor: ({ variant, bordered, content, variables, variableValues, showToolbar, pagesOptions, ...options }: BasicEditorProps) => react_jsx_runtime.JSX.Element;
648
648
 
649
+ type EditorViewProps = EditorBasicVariants & Pick<GetExtensionsOptions, "customExtensions" | "disabled"> & {
650
+ /**
651
+ * The TipTap content to render.
652
+ * Accepts JSON, HTML string, Markdown string, or plain text.
653
+ * Internally parsed via `safeParseContent` — same as the `Editor` component.
654
+ */
655
+ content?: Content$1 | undefined;
656
+ /** Additional CSS class names for the root container. */
657
+ className?: string;
658
+ };
659
+ /**
660
+ * Client-side read-only viewer for TipTap content.
661
+ *
662
+ * Uses a real TipTap editor instance in `editable: false` mode, so all
663
+ * NodeViews (images with file-reference resolution, callouts, code blocks,
664
+ * math, tables, etc.) render exactly as they do in the editor — but
665
+ * without the toolbar, bubble menus, slash commands, or collaboration.
666
+ *
667
+ * **Why not `generateHTML`?** Some node types use React NodeViews that
668
+ * resolve data at render time (e.g., images stored as file references that
669
+ * need a signed URL). `generateHTML` produces static HTML and cannot run
670
+ * these React components, resulting in broken images and missing features.
671
+ *
672
+ * **When to use:**
673
+ * - Detail pages, previews, or anywhere you need to display editor content
674
+ * with full NodeView fidelity (image resolution, interactive blocks).
675
+ * - Must be used inside `EditorFileProvider` if your content contains
676
+ * file-reference images.
677
+ *
678
+ * **For server-side rendering** (RSC, SSR, Node.js) where no React NodeViews
679
+ * are needed, use `EditorStaticView` instead. It uses `@tiptap/html` with
680
+ * a virtual DOM and produces pure HTML — but images must already be resolved.
681
+ *
682
+ * @example
683
+ * ```tsx
684
+ * import { EditorView } from "@kopexa/tiptap";
685
+ *
686
+ * function DocumentPreview({ content }: { content: JSONContent }) {
687
+ * return <EditorView content={content} variant="document" />;
688
+ * }
689
+ * ```
690
+ *
691
+ * @example With file resolution
692
+ * ```tsx
693
+ * import { EditorFileProvider, EditorView } from "@kopexa/tiptap";
694
+ *
695
+ * function DocumentDetail({ content }: { content: JSONContent }) {
696
+ * return (
697
+ * <EditorFileProvider onUpload={upload} onResolve={resolve}>
698
+ * <EditorView content={content} variant="document" />
699
+ * </EditorFileProvider>
700
+ * );
701
+ * }
702
+ * ```
703
+ */
704
+ declare function EditorView({ content, variant, bordered, className, customExtensions, disabled, }: EditorViewProps): react_jsx_runtime.JSX.Element | null;
705
+
706
+ type EditorStaticViewProps = EditorBasicVariants & Pick<GetExtensionsOptions, "customExtensions" | "disabled"> & {
707
+ /**
708
+ * The TipTap content to render.
709
+ * Accepts JSON, HTML string, Markdown string, or plain text.
710
+ * Internally parsed via `safeParseContent` — same as the `Editor` component.
711
+ */
712
+ content?: Content$1 | undefined;
713
+ /** Additional CSS class names for the root container. */
714
+ className?: string;
715
+ };
716
+ /**
717
+ * Static HTML viewer for TipTap content.
718
+ *
719
+ * Converts TipTap `JSONContent` to HTML using `generateHTML` from `@tiptap/html`
720
+ * (virtual DOM — no browser required) and renders it with the same styling as
721
+ * the `Editor` component. Works in **Server Components (RSC)**, SSR, and
722
+ * Node.js environments.
723
+ *
724
+ * Uses the full set of registered extensions to ensure all node/mark types
725
+ * produce correct HTML (tables, callouts, code blocks, math, etc.).
726
+ *
727
+ * **Limitations:**
728
+ * - React NodeViews are NOT rendered. Node types that rely on React components
729
+ * (e.g., images with file-reference resolution) will output their default
730
+ * HTML representation. Images stored as file references will NOT be resolved —
731
+ * ensure image `src` values are already displayable URLs before passing content.
732
+ * - No interactive features (no selection, no cursor, no scroll-to-hash).
733
+ *
734
+ * **When to use:**
735
+ * - Server-rendered pages, email templates, PDF generation, or static exports
736
+ * where you need a lightweight, non-interactive HTML representation.
737
+ * - When all image URLs in the content are already resolved (not file references).
738
+ *
739
+ * **For client-side rendering** with full NodeView fidelity (image resolution,
740
+ * interactive blocks), use `EditorView` instead.
741
+ *
742
+ * @example Server Component
743
+ * ```tsx
744
+ * // app/documents/[id]/page.tsx (RSC)
745
+ * import { EditorStaticView } from "@kopexa/tiptap";
746
+ *
747
+ * export default async function DocumentPage({ params }) {
748
+ * const doc = await fetchDocument(params.id);
749
+ * return <EditorStaticView content={doc.content} variant="document" />;
750
+ * }
751
+ * ```
752
+ *
753
+ * @example Client Component
754
+ * ```tsx
755
+ * import { EditorStaticView } from "@kopexa/tiptap";
756
+ *
757
+ * function LightweightPreview({ content }: { content: JSONContent }) {
758
+ * return <EditorStaticView content={content} variant="inline" />;
759
+ * }
760
+ * ```
761
+ */
762
+ declare function EditorStaticView({ content, variant, bordered, className, customExtensions, disabled, }: EditorStaticViewProps): react_jsx_runtime.JSX.Element | null;
763
+
649
764
  /**
650
765
  * Handles image upload with progress tracking and abort capability
651
766
  * @param file The file to upload
@@ -689,4 +804,4 @@ declare function sanitizeUrl(inputUrl: string, baseUrl: string, protocols?: Prot
689
804
  */
690
805
  declare function generateColorFromId(id: string): string;
691
806
 
692
- export { CalloutNode, type CalloutNodeAttrs, type CalloutVariant, type CollabUser, CollaborationProvider, type CollaborationProviderProps, type CollaborationState, type CollaborationStatus, BasicEditor as Editor, type EditorFileHandler, EditorFileProvider, type EditorFileProviderProps, type GetExtensionsOptions, ImageNode, ImageUploadNode, InlineMath, type InlineMathAttrs, MathBlock, type MathBlockAttrs, type ResolvedCollabUser, TocNode, type VariableDefinition, VariableFillerDialog, type VariableFillerDialogProps, VariableNode, type VariableNodeAttrs, type VariableOptions, VariableProvider, type VariableProviderProps, VariableSuggestion, type VariableSuggestionProps, convertFileToBase64, extractVariablesFromContent, generateColorFromId, getExtensions, handleImageUpload, isAllowedUri, sanitizeUrl, useCollaboration, useCollaborationRequired, useDocumentVisibility, useEditorFile, useEditorFileRequired, useIdle, useVariables, useVariablesWithFallback };
807
+ export { CalloutNode, type CalloutNodeAttrs, type CalloutVariant, type CollabUser, CollaborationProvider, type CollaborationProviderProps, type CollaborationState, type CollaborationStatus, BasicEditor as Editor, type EditorFileHandler, EditorFileProvider, type EditorFileProviderProps, EditorStaticView, type EditorStaticViewProps, EditorView, type EditorViewProps, type GetExtensionsOptions, ImageNode, ImageUploadNode, InlineMath, type InlineMathAttrs, MathBlock, type MathBlockAttrs, type ResolvedCollabUser, TocNode, type VariableDefinition, VariableFillerDialog, type VariableFillerDialogProps, VariableNode, type VariableNodeAttrs, type VariableOptions, VariableProvider, type VariableProviderProps, VariableSuggestion, type VariableSuggestionProps, convertFileToBase64, extractVariablesFromContent, generateColorFromId, getExtensions, handleImageUpload, isAllowedUri, sanitizeUrl, useCollaboration, useCollaborationRequired, useDocumentVisibility, useEditorFile, useEditorFileRequired, useIdle, useVariables, useVariablesWithFallback };
package/dist/index.js CHANGED
@@ -35,6 +35,8 @@ __export(index_exports, {
35
35
  CollaborationProvider: () => CollaborationProvider,
36
36
  Editor: () => BasicEditor,
37
37
  EditorFileProvider: () => EditorFileProvider,
38
+ EditorStaticView: () => EditorStaticView,
39
+ EditorView: () => EditorView,
38
40
  ImageNode: () => ImageNode,
39
41
  ImageUploadNode: () => ImageUploadNode,
40
42
  InlineMath: () => InlineMath,
@@ -4024,6 +4026,7 @@ var useCreateEditor = ({
4024
4026
  const fileHandlerFromContext = useEditorFile();
4025
4027
  const fileHandler = fileHandlerProp != null ? fileHandlerProp : fileHandlerFromContext;
4026
4028
  const collaboration = useCollaboration();
4029
+ const [collabSyncing, setCollabSyncing] = (0, import_react33.useState)(!!collaboration);
4027
4030
  const [extensions] = (0, import_react33.useState)(
4028
4031
  () => getExtensions({
4029
4032
  editable,
@@ -4038,6 +4041,7 @@ var useCreateEditor = ({
4038
4041
  disabled
4039
4042
  })
4040
4043
  );
4044
+ const { onCreate: userOnCreate, ...restOptions } = options;
4041
4045
  const editor = (0, import_react32.useEditor)({
4042
4046
  editorProps: {
4043
4047
  attributes: {
@@ -4055,14 +4059,40 @@ var useCreateEditor = ({
4055
4059
  onChange == null ? void 0 : onChange(editor2.getJSON());
4056
4060
  },
4057
4061
  content: safeParseContent(content),
4058
- ...options
4062
+ // Seed empty collaborative documents with initial content.
4063
+ // When the Collaboration extension is active, TipTap ignores the `content`
4064
+ // prop entirely — content comes from the Y.Doc. If the Hocuspocus server
4065
+ // delivers an empty doc (e.g. a freshly created version), we populate it
4066
+ // with the `content` prop once after the initial sync.
4067
+ onCreate: (ctx) => {
4068
+ if (collaboration) {
4069
+ const provider = collaboration.provider;
4070
+ if (provider && !provider.isSynced) {
4071
+ provider.on("synced", () => {
4072
+ setTimeout(() => {
4073
+ if (ctx.editor.isEmpty && content) {
4074
+ ctx.editor.commands.setContent(safeParseContent(content));
4075
+ }
4076
+ setCollabSyncing(false);
4077
+ }, 0);
4078
+ });
4079
+ } else {
4080
+ if (ctx.editor.isEmpty && content) {
4081
+ ctx.editor.commands.setContent(safeParseContent(content));
4082
+ }
4083
+ setCollabSyncing(false);
4084
+ }
4085
+ }
4086
+ userOnCreate == null ? void 0 : userOnCreate(ctx);
4087
+ },
4088
+ ...restOptions
4059
4089
  });
4060
4090
  (0, import_react33.useEffect)(() => {
4061
4091
  if (editor && editor.isEditable !== editable) {
4062
4092
  editor.setEditable(editable);
4063
4093
  }
4064
4094
  }, [editor, editable]);
4065
- return editor;
4095
+ return { editor, collabSyncing };
4066
4096
  };
4067
4097
  function getExtensions({
4068
4098
  editable,
@@ -8190,7 +8220,7 @@ var BasicEditor = ({
8190
8220
  pagesOptions,
8191
8221
  ...options
8192
8222
  }) => {
8193
- const editor = useCreateEditor({
8223
+ const { editor, collabSyncing } = useCreateEditor({
8194
8224
  content,
8195
8225
  enableVariables: !!(variables == null ? void 0 : variables.length),
8196
8226
  pagesOptions,
@@ -8201,7 +8231,7 @@ var BasicEditor = ({
8201
8231
  (name) => variableValues == null ? void 0 : variableValues[name],
8202
8232
  [variableValues]
8203
8233
  );
8204
- if (!editor) {
8234
+ if (!editor || collabSyncing) {
8205
8235
  return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(LoadingSpinner, {});
8206
8236
  }
8207
8237
  const isBottomToolbar = variant === "field";
@@ -8338,12 +8368,93 @@ function LoadingSpinner({ text = "Connecting..." }) {
8338
8368
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: styles.text(), children: text })
8339
8369
  ] }) });
8340
8370
  }
8371
+
8372
+ // src/presets/view/index.tsx
8373
+ var import_theme10 = require("@kopexa/theme");
8374
+ var import_react62 = require("@tiptap/react");
8375
+ var import_jsx_runtime35 = require("react/jsx-runtime");
8376
+ function EditorView({
8377
+ content,
8378
+ variant,
8379
+ bordered,
8380
+ className,
8381
+ customExtensions,
8382
+ disabled
8383
+ }) {
8384
+ const { editor } = useCreateEditor({
8385
+ content,
8386
+ editable: false,
8387
+ customExtensions,
8388
+ disabled
8389
+ });
8390
+ const styles = (0, import_theme10.editorBasic)({ variant, bordered });
8391
+ if (!editor) {
8392
+ return null;
8393
+ }
8394
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: styles.root({ className }), "data-slot": "editor-view", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_react62.EditorContext.Provider, { value: { editor }, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: styles.wrapper(), children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8395
+ import_react62.EditorContent,
8396
+ {
8397
+ editor,
8398
+ role: "presentation",
8399
+ className: styles.content()
8400
+ }
8401
+ ) }) }) });
8402
+ }
8403
+
8404
+ // src/presets/view/static.tsx
8405
+ var import_theme11 = require("@kopexa/theme");
8406
+ var import_html = require("@tiptap/html");
8407
+ var import_react63 = require("react");
8408
+ var import_jsx_runtime36 = require("react/jsx-runtime");
8409
+ function EditorStaticView({
8410
+ content,
8411
+ variant,
8412
+ bordered,
8413
+ className,
8414
+ customExtensions,
8415
+ disabled
8416
+ }) {
8417
+ const extensions = (0, import_react63.useMemo)(
8418
+ () => getExtensions({
8419
+ editable: false,
8420
+ customExtensions,
8421
+ disabled
8422
+ }),
8423
+ [customExtensions, disabled]
8424
+ );
8425
+ const html = (0, import_react63.useMemo)(() => {
8426
+ const parsed = safeParseContent(content);
8427
+ if (!parsed) return "";
8428
+ const json = parsed;
8429
+ if (json.content && Array.isArray(json.content) && json.content.length === 0) {
8430
+ return "";
8431
+ }
8432
+ try {
8433
+ return (0, import_html.generateHTML)(json, extensions);
8434
+ } catch {
8435
+ return "";
8436
+ }
8437
+ }, [content, extensions]);
8438
+ const styles = (0, import_theme11.editorBasic)({ variant, bordered });
8439
+ if (!html) {
8440
+ return null;
8441
+ }
8442
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: styles.root({ className }), "data-slot": "editor-static-view", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: styles.wrapper(), children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: styles.content(), children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
8443
+ "div",
8444
+ {
8445
+ className: "tiptap ProseMirror",
8446
+ dangerouslySetInnerHTML: { __html: html }
8447
+ }
8448
+ ) }) }) });
8449
+ }
8341
8450
  // Annotate the CommonJS export names for ESM import in node:
8342
8451
  0 && (module.exports = {
8343
8452
  CalloutNode,
8344
8453
  CollaborationProvider,
8345
8454
  Editor,
8346
8455
  EditorFileProvider,
8456
+ EditorStaticView,
8457
+ EditorView,
8347
8458
  ImageNode,
8348
8459
  ImageUploadNode,
8349
8460
  InlineMath,
package/dist/index.mjs CHANGED
@@ -4022,6 +4022,7 @@ var useCreateEditor = ({
4022
4022
  const fileHandlerFromContext = useEditorFile();
4023
4023
  const fileHandler = fileHandlerProp != null ? fileHandlerProp : fileHandlerFromContext;
4024
4024
  const collaboration = useCollaboration();
4025
+ const [collabSyncing, setCollabSyncing] = useState13(!!collaboration);
4025
4026
  const [extensions] = useState13(
4026
4027
  () => getExtensions({
4027
4028
  editable,
@@ -4036,6 +4037,7 @@ var useCreateEditor = ({
4036
4037
  disabled
4037
4038
  })
4038
4039
  );
4040
+ const { onCreate: userOnCreate, ...restOptions } = options;
4039
4041
  const editor = useEditor({
4040
4042
  editorProps: {
4041
4043
  attributes: {
@@ -4053,14 +4055,40 @@ var useCreateEditor = ({
4053
4055
  onChange == null ? void 0 : onChange(editor2.getJSON());
4054
4056
  },
4055
4057
  content: safeParseContent(content),
4056
- ...options
4058
+ // Seed empty collaborative documents with initial content.
4059
+ // When the Collaboration extension is active, TipTap ignores the `content`
4060
+ // prop entirely — content comes from the Y.Doc. If the Hocuspocus server
4061
+ // delivers an empty doc (e.g. a freshly created version), we populate it
4062
+ // with the `content` prop once after the initial sync.
4063
+ onCreate: (ctx) => {
4064
+ if (collaboration) {
4065
+ const provider = collaboration.provider;
4066
+ if (provider && !provider.isSynced) {
4067
+ provider.on("synced", () => {
4068
+ setTimeout(() => {
4069
+ if (ctx.editor.isEmpty && content) {
4070
+ ctx.editor.commands.setContent(safeParseContent(content));
4071
+ }
4072
+ setCollabSyncing(false);
4073
+ }, 0);
4074
+ });
4075
+ } else {
4076
+ if (ctx.editor.isEmpty && content) {
4077
+ ctx.editor.commands.setContent(safeParseContent(content));
4078
+ }
4079
+ setCollabSyncing(false);
4080
+ }
4081
+ }
4082
+ userOnCreate == null ? void 0 : userOnCreate(ctx);
4083
+ },
4084
+ ...restOptions
4057
4085
  });
4058
4086
  useEffect14(() => {
4059
4087
  if (editor && editor.isEditable !== editable) {
4060
4088
  editor.setEditable(editable);
4061
4089
  }
4062
4090
  }, [editor, editable]);
4063
- return editor;
4091
+ return { editor, collabSyncing };
4064
4092
  };
4065
4093
  function getExtensions({
4066
4094
  editable,
@@ -8287,7 +8315,7 @@ var BasicEditor = ({
8287
8315
  pagesOptions,
8288
8316
  ...options
8289
8317
  }) => {
8290
- const editor = useCreateEditor({
8318
+ const { editor, collabSyncing } = useCreateEditor({
8291
8319
  content,
8292
8320
  enableVariables: !!(variables == null ? void 0 : variables.length),
8293
8321
  pagesOptions,
@@ -8298,7 +8326,7 @@ var BasicEditor = ({
8298
8326
  (name) => variableValues == null ? void 0 : variableValues[name],
8299
8327
  [variableValues]
8300
8328
  );
8301
- if (!editor) {
8329
+ if (!editor || collabSyncing) {
8302
8330
  return /* @__PURE__ */ jsx34(LoadingSpinner, {});
8303
8331
  }
8304
8332
  const isBottomToolbar = variant === "field";
@@ -8435,11 +8463,92 @@ function LoadingSpinner({ text = "Connecting..." }) {
8435
8463
  /* @__PURE__ */ jsx34("div", { className: styles.text(), children: text })
8436
8464
  ] }) });
8437
8465
  }
8466
+
8467
+ // src/presets/view/index.tsx
8468
+ import { editorBasic as editorBasic2 } from "@kopexa/theme";
8469
+ import { EditorContent as EditorContent2, EditorContext as EditorContext2 } from "@tiptap/react";
8470
+ import { jsx as jsx35 } from "react/jsx-runtime";
8471
+ function EditorView({
8472
+ content,
8473
+ variant,
8474
+ bordered,
8475
+ className,
8476
+ customExtensions,
8477
+ disabled
8478
+ }) {
8479
+ const { editor } = useCreateEditor({
8480
+ content,
8481
+ editable: false,
8482
+ customExtensions,
8483
+ disabled
8484
+ });
8485
+ const styles = editorBasic2({ variant, bordered });
8486
+ if (!editor) {
8487
+ return null;
8488
+ }
8489
+ return /* @__PURE__ */ jsx35("div", { className: styles.root({ className }), "data-slot": "editor-view", children: /* @__PURE__ */ jsx35(EditorContext2.Provider, { value: { editor }, children: /* @__PURE__ */ jsx35("div", { className: styles.wrapper(), children: /* @__PURE__ */ jsx35(
8490
+ EditorContent2,
8491
+ {
8492
+ editor,
8493
+ role: "presentation",
8494
+ className: styles.content()
8495
+ }
8496
+ ) }) }) });
8497
+ }
8498
+
8499
+ // src/presets/view/static.tsx
8500
+ import { editorBasic as editorBasic3 } from "@kopexa/theme";
8501
+ import { generateHTML } from "@tiptap/html";
8502
+ import { useMemo as useMemo20 } from "react";
8503
+ import { jsx as jsx36 } from "react/jsx-runtime";
8504
+ function EditorStaticView({
8505
+ content,
8506
+ variant,
8507
+ bordered,
8508
+ className,
8509
+ customExtensions,
8510
+ disabled
8511
+ }) {
8512
+ const extensions = useMemo20(
8513
+ () => getExtensions({
8514
+ editable: false,
8515
+ customExtensions,
8516
+ disabled
8517
+ }),
8518
+ [customExtensions, disabled]
8519
+ );
8520
+ const html = useMemo20(() => {
8521
+ const parsed = safeParseContent(content);
8522
+ if (!parsed) return "";
8523
+ const json = parsed;
8524
+ if (json.content && Array.isArray(json.content) && json.content.length === 0) {
8525
+ return "";
8526
+ }
8527
+ try {
8528
+ return generateHTML(json, extensions);
8529
+ } catch {
8530
+ return "";
8531
+ }
8532
+ }, [content, extensions]);
8533
+ const styles = editorBasic3({ variant, bordered });
8534
+ if (!html) {
8535
+ return null;
8536
+ }
8537
+ return /* @__PURE__ */ jsx36("div", { className: styles.root({ className }), "data-slot": "editor-static-view", children: /* @__PURE__ */ jsx36("div", { className: styles.wrapper(), children: /* @__PURE__ */ jsx36("div", { className: styles.content(), children: /* @__PURE__ */ jsx36(
8538
+ "div",
8539
+ {
8540
+ className: "tiptap ProseMirror",
8541
+ dangerouslySetInnerHTML: { __html: html }
8542
+ }
8543
+ ) }) }) });
8544
+ }
8438
8545
  export {
8439
8546
  CalloutNode,
8440
8547
  CollaborationProvider,
8441
8548
  BasicEditor as Editor,
8442
8549
  EditorFileProvider,
8550
+ EditorStaticView,
8551
+ EditorView,
8443
8552
  ImageNode,
8444
8553
  ImageUploadNode,
8445
8554
  InlineMath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kopexa/tiptap",
3
- "version": "17.8.5",
3
+ "version": "17.9.1",
4
4
  "description": "our tiptap components",
5
5
  "keywords": [
6
6
  "tiptap"
@@ -28,7 +28,7 @@
28
28
  "motion": ">=12.23.6",
29
29
  "react": ">=19.0.0-rc.0",
30
30
  "react-dom": ">=19.0.0-rc.0",
31
- "@kopexa/theme": "17.24.2"
31
+ "@kopexa/theme": "17.24.5"
32
32
  },
33
33
  "dependencies": {
34
34
  "@floating-ui/dom": "^1.7.4",
@@ -54,6 +54,7 @@
54
54
  "@tiptap/extension-typography": "^3.20.0",
55
55
  "@tiptap/extension-unique-id": "^3.20.0",
56
56
  "@tiptap/extensions": "^3.20.0",
57
+ "@tiptap/html": "^3.20.0",
57
58
  "@tiptap/pm": "^3.20.0",
58
59
  "@tiptap/react": "^3.20.0",
59
60
  "@tiptap/starter-kit": "^3.20.0",
@@ -61,34 +62,34 @@
61
62
  "dompurify": "^3.3.1",
62
63
  "katex": "^0.16.33",
63
64
  "jsx-dom-cjs": "^8.1.6",
64
- "markdown-it": "^14.1.0",
65
+ "markdown-it": "^14.1.1",
65
66
  "react-hotkeys-hook": "^5.2.4",
66
67
  "react-intl": "^7.1.14",
67
68
  "y-indexeddb": "^9.0.12",
68
69
  "yjs": "^13.6.0",
69
- "@kopexa/button": "17.0.54",
70
- "@kopexa/callout": "17.0.54",
71
- "@kopexa/dialog": "17.2.19",
72
- "@kopexa/dropdown-menu": "17.0.54",
73
- "@kopexa/editor-utils": "17.1.5",
74
- "@kopexa/chip": "17.1.51",
70
+ "@kopexa/button": "17.0.57",
71
+ "@kopexa/callout": "17.0.57",
72
+ "@kopexa/chip": "17.1.54",
73
+ "@kopexa/dialog": "17.2.22",
75
74
  "@kopexa/extension-pages": "17.0.45",
76
- "@kopexa/extension-code": "17.0.54",
77
- "@kopexa/extension-controlref": "17.1.36",
78
- "@kopexa/extension-table": "17.1.6",
79
- "@kopexa/input": "17.0.54",
80
- "@kopexa/label": "17.0.54",
81
- "@kopexa/popover": "17.2.19",
82
- "@kopexa/select": "17.2.19",
83
- "@kopexa/icons": "17.7.19",
84
- "@kopexa/switch": "17.2.19",
85
- "@kopexa/react-utils": "17.0.54",
86
- "@kopexa/separator": "17.0.54",
87
- "@kopexa/shared-utils": "17.0.54",
88
- "@kopexa/toolbar": "17.2.19",
89
- "@kopexa/use-composed-ref": "17.0.54",
90
- "@kopexa/use-is-mobile": "17.0.54",
91
- "@kopexa/tabs": "17.0.54"
75
+ "@kopexa/editor-utils": "17.1.8",
76
+ "@kopexa/dropdown-menu": "17.0.57",
77
+ "@kopexa/extension-code": "17.0.57",
78
+ "@kopexa/extension-controlref": "17.1.39",
79
+ "@kopexa/extension-table": "17.1.9",
80
+ "@kopexa/input": "17.0.57",
81
+ "@kopexa/label": "17.0.57",
82
+ "@kopexa/icons": "17.7.22",
83
+ "@kopexa/popover": "17.2.22",
84
+ "@kopexa/select": "17.2.22",
85
+ "@kopexa/separator": "17.0.57",
86
+ "@kopexa/shared-utils": "17.0.57",
87
+ "@kopexa/switch": "17.2.22",
88
+ "@kopexa/use-is-mobile": "17.0.57",
89
+ "@kopexa/use-composed-ref": "17.0.57",
90
+ "@kopexa/toolbar": "17.2.22",
91
+ "@kopexa/react-utils": "17.0.57",
92
+ "@kopexa/tabs": "17.0.57"
92
93
  },
93
94
  "clean-package": "../../../clean-package.config.json",
94
95
  "module": "dist/index.mjs",