doccraft 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.
Files changed (64) hide show
  1. package/README.md +84 -0
  2. package/dist/blocks/base-styles.d.ts +6 -0
  3. package/dist/blocks/for-block/extension.d.ts +16 -0
  4. package/dist/blocks/for-block/index.d.ts +2 -0
  5. package/dist/blocks/for-block/styles.d.ts +2 -0
  6. package/dist/blocks/for-block/view.d.ts +2 -0
  7. package/dist/blocks/if-block/extension.d.ts +11 -0
  8. package/dist/blocks/if-block/index.d.ts +2 -0
  9. package/dist/blocks/if-block/styles.d.ts +2 -0
  10. package/dist/blocks/if-block/view.d.ts +2 -0
  11. package/dist/blocks/index.d.ts +5 -0
  12. package/dist/blocks/readonly-block/extension.d.ts +12 -0
  13. package/dist/blocks/readonly-block/index.d.ts +2 -0
  14. package/dist/blocks/readonly-block/styles.d.ts +2 -0
  15. package/dist/blocks/readonly-block/view.d.ts +2 -0
  16. package/dist/blocks/types.d.ts +47 -0
  17. package/dist/canvas/HeaderFooterField.d.ts +11 -0
  18. package/dist/canvas/PageCanvas.d.ts +16 -0
  19. package/dist/canvas/canvas-config.d.ts +25 -0
  20. package/dist/core/DocCraft.d.ts +54 -0
  21. package/dist/core/page-flow-plugin.d.ts +22 -0
  22. package/dist/core/use-editor.d.ts +14 -0
  23. package/dist/doccraft.cjs +1006 -0
  24. package/dist/doccraft.cjs.map +1 -0
  25. package/dist/doccraft.css +2 -0
  26. package/dist/doccraft.js +53090 -0
  27. package/dist/doccraft.js.map +1 -0
  28. package/dist/extensions/TemplateVariableView.d.ts +2 -0
  29. package/dist/extensions/page-break.d.ts +9 -0
  30. package/dist/extensions/paste-handler.d.ts +14 -0
  31. package/dist/extensions/resizable-image.d.ts +15 -0
  32. package/dist/extensions/template-variable.d.ts +21 -0
  33. package/dist/hooks/use-block-styles.d.ts +7 -0
  34. package/dist/image/HfResizableImage.d.ts +2 -0
  35. package/dist/image/ImageCropOverlay.d.ts +14 -0
  36. package/dist/image/ImageNodeView.d.ts +2 -0
  37. package/dist/index.d.ts +13 -0
  38. package/dist/pdf-C0490ZCf.js +15393 -0
  39. package/dist/pdf-C0490ZCf.js.map +1 -0
  40. package/dist/pdf-DDIBR0qz.cjs +12 -0
  41. package/dist/pdf-DDIBR0qz.cjs.map +1 -0
  42. package/dist/table/TableControls.d.ts +6 -0
  43. package/dist/toolbar/BubbleToolbar.d.ts +6 -0
  44. package/dist/toolbar/EditorActions.d.ts +25 -0
  45. package/dist/toolbar/EditorToolbar.d.ts +17 -0
  46. package/dist/toolbar/toolbar-config.d.ts +3 -0
  47. package/dist/types.d.ts +35 -0
  48. package/dist/ui/button.d.ts +8 -0
  49. package/dist/ui/card.d.ts +11 -0
  50. package/dist/ui/dialog.d.ts +17 -0
  51. package/dist/ui/dropdown-menu.d.ts +29 -0
  52. package/dist/ui/input.d.ts +3 -0
  53. package/dist/ui/label.d.ts +3 -0
  54. package/dist/ui/popover.d.ts +9 -0
  55. package/dist/ui/separator.d.ts +3 -0
  56. package/dist/ui/toggle-group.d.ts +10 -0
  57. package/dist/ui/toggle.d.ts +8 -0
  58. package/dist/ui/tooltip.d.ts +6 -0
  59. package/dist/utils/cn.d.ts +2 -0
  60. package/dist/utils/export-html.d.ts +39 -0
  61. package/dist/utils/image-utils.d.ts +8 -0
  62. package/dist/utils/import-docx.d.ts +20 -0
  63. package/dist/utils/import-pdf.d.ts +19 -0
  64. package/package.json +93 -0
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # doccraft
2
+
3
+ A visual template editor for React. Build HTML templates with `{{variables}}`, loops, and conditionals in a Google Docs-like editor. Output clean HTML for Jinja, Handlebars, Mustache, or any template engine.
4
+
5
+ Built on [TipTap](https://tiptap.dev) and [ProseMirror](https://prosemirror.net).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install doccraft
11
+ ```
12
+
13
+ Peer dependencies: `react` and `react-dom` (v18 or v19).
14
+
15
+ ## Usage
16
+
17
+ ```tsx
18
+ import { useRef } from 'react'
19
+ import { DocCraft, type DocCraftRef, forBlock, ifBlock } from 'doccraft'
20
+
21
+ function TemplateEditor() {
22
+ const ref = useRef<DocCraftRef>(null)
23
+
24
+ return (
25
+ <DocCraft
26
+ ref={ref}
27
+ variables={[
28
+ { key: 'name', label: 'Name' },
29
+ { key: 'email', label: 'Email' },
30
+ ]}
31
+ blocks={[forBlock, ifBlock]}
32
+ onChange={(html) => saveTemplate(html)}
33
+ />
34
+ )
35
+ }
36
+ ```
37
+
38
+ > Styles are auto-imported. No separate CSS import needed.
39
+
40
+ ## What It Does
41
+
42
+ Users design documents visually. The editor outputs HTML with template syntax:
43
+
44
+ ```
45
+ Visual editor -> HTML output
46
+ ----------------- ---------------------
47
+ [name chip] -> {{name}}
48
+ [For: item in items] -> <div data-block-for="item in items">
49
+ [item.name chip] -> {{item.name}}
50
+ [End for] -> </div>
51
+ ```
52
+
53
+ Feed the HTML to Jinja, Handlebars, or any template engine, then generate PDFs.
54
+
55
+ ## API Reference
56
+
57
+ See the [full documentation](../../README.md) for complete API reference including:
58
+
59
+ - All props (canvas, toolbar, theme, extensions, actions, header/footer)
60
+ - Ref methods (getHTML, getPdfHTML, getPreviewHTML, setContent, etc.)
61
+ - Canvas presets (A4, email, custom)
62
+ - Toolbar presets (full, minimal, document)
63
+ - Custom block plugins
64
+ - Import/export utilities
65
+ - PDF generation examples
66
+
67
+ ### Quick Reference
68
+
69
+ | Export | Description |
70
+ |--------|-------------|
71
+ | `DocCraft` | Main editor component |
72
+ | `DocCraftRef` | Ref type for programmatic control |
73
+ | `DocCraftProps` | Props type |
74
+ | `forBlock` | For-loop block plugin |
75
+ | `ifBlock` | If-condition block plugin |
76
+ | `readonlyBlock` | Read-only block plugin |
77
+ | `importDocx(file)` | Import .docx files |
78
+ | `importPdf(file)` | Import .pdf files |
79
+ | `exportToPdfHtml(html, opts)` | Generate PDF-ready HTML |
80
+ | `exportToPreviewHtml(html, opts)` | Generate visual preview HTML |
81
+
82
+ ## License
83
+
84
+ MIT
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Shared structural styles for all editor blocks.
3
+ * Injected once when any block is registered.
4
+ * Individual block colors/themes come from each block's own styles.
5
+ */
6
+ export declare const BLOCK_BASE_STYLES = "\n.s-block {\n position: relative;\n margin: 0.75em 0;\n border-radius: 6px;\n border: 1.5px solid transparent;\n transition: border-color 0.15s;\n}\n.s-block--selected {\n border-color: currentColor;\n}\n.s-block__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 10px;\n border-radius: 5px 5px 0 0;\n font-size: 11px;\n font-weight: 500;\n user-select: none;\n gap: 6px;\n}\n.s-block__header-left {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n flex: 1;\n}\n.s-block__footer {\n padding: 3px 10px;\n border-radius: 0 0 5px 5px;\n font-size: 10px;\n font-weight: 500;\n user-select: none;\n opacity: 0.7;\n}\n.s-block__body {\n padding: 8px 12px;\n min-height: 2em;\n}\n.s-block__expr {\n cursor: default;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.s-block__expr strong {\n font-weight: 700;\n font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;\n}\n.s-block__expr-edit {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n.s-block__expr-kw {\n opacity: 0.7;\n}\n.s-block__expr-input {\n background: rgba(255,255,255,0.3);\n border: 1px solid rgba(255,255,255,0.5);\n border-radius: 3px;\n padding: 0 4px;\n font-size: 11px;\n font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;\n font-weight: 700;\n color: inherit;\n outline: none;\n min-width: 3ch;\n}\n.s-block__expr-input:focus {\n border-color: rgba(255,255,255,0.8);\n background: rgba(255,255,255,0.4);\n}\n.s-block__delete {\n opacity: 0;\n transition: opacity 0.15s;\n flex-shrink: 0;\n background: none;\n border: none;\n color: inherit;\n cursor: pointer;\n padding: 2px;\n border-radius: 3px;\n display: flex;\n align-items: center;\n}\n.s-block__delete:hover {\n background: rgba(0,0,0,0.1);\n}\n.s-block:hover .s-block__delete,\n.s-block--selected .s-block__delete {\n opacity: 1;\n}\n";
@@ -0,0 +1,16 @@
1
+ import { Node } from '@tiptap/core';
2
+ declare module '@tiptap/core' {
3
+ interface Commands<ReturnType> {
4
+ forBlock: {
5
+ insertForBlock: (options: {
6
+ iterVar: string;
7
+ listVar: string;
8
+ }) => ReturnType;
9
+ };
10
+ }
11
+ }
12
+ export interface ForBlockOptions {
13
+ /** Available variables the user can pick as the list source */
14
+ variables: import('../../types').TemplateVariable[];
15
+ }
16
+ export declare const ForBlockExtension: Node<ForBlockOptions, any>;
@@ -0,0 +1,2 @@
1
+ import type { EditorBlockPlugin } from '../types';
2
+ export declare const forBlock: EditorBlockPlugin;
@@ -0,0 +1,2 @@
1
+ export declare const FOR_BLOCK_STYLES = "\n.s-block--for { color: #1d4ed8; }\n.s-block--for__header { background: #dbeafe; color: #1e40af; }\n.s-block--for__footer { background: #dbeafe; color: #1e40af; }\n.s-block--for .s-block__body {\n background: #f0f7ff;\n border-left: 2px solid #93c5fd;\n border-right: 2px solid #93c5fd;\n}\n\n/* Variable picker */\n.s-block__var-picker-wrap {\n position: relative;\n display: inline-flex;\n}\n.s-block__var-picker-btn {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n background: rgba(255,255,255,0.3);\n border: 1px solid rgba(255,255,255,0.5);\n border-radius: 3px;\n padding: 0 6px 0 4px;\n font-size: 11px;\n font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;\n font-weight: 700;\n color: inherit;\n cursor: pointer;\n min-width: 3ch;\n line-height: 1.6;\n}\n.s-block__var-picker-btn:hover {\n background: rgba(255,255,255,0.5);\n}\n.s-block__var-picker-dropdown {\n position: absolute;\n top: 100%;\n left: 0;\n margin-top: 4px;\n background: white;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n min-width: 160px;\n max-height: 200px;\n overflow-y: auto;\n z-index: 50;\n padding: 4px;\n}\n.s-block__var-picker-item {\n display: block;\n width: 100%;\n text-align: left;\n padding: 4px 8px;\n font-size: 12px;\n font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, monospace;\n color: #374151;\n background: none;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n}\n.s-block__var-picker-item:hover {\n background: #dbeafe;\n color: #1e40af;\n}\n.s-block__var-picker-item.active {\n background: #bfdbfe;\n color: #1e40af;\n font-weight: 600;\n}\n.s-block__var-picker-empty {\n padding: 8px;\n font-size: 11px;\n color: #9ca3af;\n text-align: center;\n}\n.s-block__var-picker-divider {\n height: 1px;\n background: #e5e7eb;\n margin: 4px 0;\n}\n.s-block__var-picker-custom {\n padding: 4px;\n}\n.s-block__var-picker-custom .s-block__expr-input {\n background: #f9fafb;\n border-color: #d1d5db;\n color: #374151;\n width: 100%;\n padding: 2px 6px;\n}\n\n/* Done button */\n.s-block__expr-done {\n background: rgba(255,255,255,0.4);\n border: 1px solid rgba(255,255,255,0.6);\n border-radius: 3px;\n padding: 0 8px;\n font-size: 10px;\n color: inherit;\n cursor: pointer;\n margin-left: 4px;\n line-height: 1.6;\n}\n.s-block__expr-done:hover {\n background: rgba(255,255,255,0.6);\n}\n";
2
+ export declare const FOR_BLOCK_EXPORT_STYLES = "\ndiv[data-block-for] {\n border-left: 3px solid #93c5fd;\n padding-left: 12px;\n margin: 0.5em 0;\n}\n";
@@ -0,0 +1,2 @@
1
+ import { type NodeViewProps } from '@tiptap/react';
2
+ export declare function ForBlockView({ node, updateAttributes, deleteNode, selected, extension, editor }: NodeViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { Node } from '@tiptap/core';
2
+ declare module '@tiptap/core' {
3
+ interface Commands<ReturnType> {
4
+ ifBlock: {
5
+ insertIfBlock: (options: {
6
+ condition: string;
7
+ }) => ReturnType;
8
+ };
9
+ }
10
+ }
11
+ export declare const IfBlockExtension: Node<any, any>;
@@ -0,0 +1,2 @@
1
+ import type { EditorBlockPlugin } from '../types';
2
+ export declare const ifBlock: EditorBlockPlugin;
@@ -0,0 +1,2 @@
1
+ export declare const IF_BLOCK_STYLES = "\n.s-block--if { color: #b45309; }\n.s-block--if__header { background: #fef3c7; color: #92400e; }\n.s-block--if__footer { background: #fef3c7; color: #92400e; }\n.s-block--if .s-block__body {\n background: #fffbeb;\n border-left: 2px solid #fcd34d;\n border-right: 2px solid #fcd34d;\n}\n";
2
+ export declare const IF_BLOCK_EXPORT_STYLES = "\ndiv[data-block-if] {\n border-left: 3px solid #fcd34d;\n padding-left: 12px;\n margin: 0.5em 0;\n}\n";
@@ -0,0 +1,2 @@
1
+ import { type NodeViewProps } from '@tiptap/react';
2
+ export declare function IfBlockView({ node, updateAttributes, deleteNode, selected, editor }: NodeViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ export type { EditorBlockPlugin } from './types';
2
+ export { BLOCK_BASE_STYLES } from './base-styles';
3
+ export { forBlock } from './for-block';
4
+ export { ifBlock } from './if-block';
5
+ export { readonlyBlock } from './readonly-block';
@@ -0,0 +1,12 @@
1
+ import { Node } from '@tiptap/core';
2
+ declare module '@tiptap/core' {
3
+ interface Commands<ReturnType> {
4
+ readonlyBlock: {
5
+ insertReadOnlyBlock: (options: {
6
+ content: string;
7
+ label?: string;
8
+ }) => ReturnType;
9
+ };
10
+ }
11
+ }
12
+ export declare const ReadOnlyBlockExtension: Node<any, any>;
@@ -0,0 +1,2 @@
1
+ import type { EditorBlockPlugin } from '../types';
2
+ export declare const readonlyBlock: EditorBlockPlugin;
@@ -0,0 +1,2 @@
1
+ export declare const READONLY_BLOCK_STYLES = "\n.s-block--readonly { color: #4b5563; }\n.s-block--readonly__header { background: #e5e7eb; color: #374151; }\n.s-block--readonly__body {\n background: #f9fafb;\n border-left: 2px solid #d1d5db;\n border-right: 2px solid #d1d5db;\n border-bottom: 2px solid #d1d5db;\n border-radius: 0 0 5px 5px;\n color: #6b7280;\n cursor: default;\n}\n";
2
+ export declare const READONLY_BLOCK_EXPORT_STYLES = "\ndiv[data-block-readonly] {\n background: #f9fafb;\n border: 1px solid #e5e7eb;\n border-radius: 4px;\n padding: 8px 12px;\n margin: 0.5em 0;\n color: #6b7280;\n}\n";
@@ -0,0 +1,2 @@
1
+ import { type NodeViewProps } from '@tiptap/react';
2
+ export declare function ReadOnlyBlockView({ node, deleteNode, selected, editor }: NodeViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,47 @@
1
+ import type { Node } from '@tiptap/core';
2
+ import type { ComponentType } from 'react';
3
+ /**
4
+ * Runtime context passed to block plugins during registration.
5
+ * Contains editor-level state the block may need.
6
+ */
7
+ export interface BlockContext {
8
+ /** Available template variables in the editor */
9
+ variables: import('../types').TemplateVariable[];
10
+ }
11
+ /**
12
+ * Interface every editor block plugin must implement.
13
+ *
14
+ * A block is a self-contained plugin that provides:
15
+ * - A TipTap Node extension (schema, commands, parsing)
16
+ * - Its own CSS styles (injected at mount, cleaned up on unmount)
17
+ * - Metadata for the toolbar (name, icon, description)
18
+ * - An insert handler for the toolbar to call
19
+ *
20
+ * Blocks own their entire lifecycle — the editor core knows nothing
21
+ * about block internals. It just registers the extension and shows
22
+ * the block in the toolbar.
23
+ */
24
+ export interface EditorBlockPlugin {
25
+ /** Unique block name — must match the TipTap extension name */
26
+ name: string;
27
+ /** Display label for the toolbar */
28
+ label: string;
29
+ /** Lucide icon component for the toolbar */
30
+ icon: ComponentType<{
31
+ className?: string;
32
+ }>;
33
+ /** Short description shown in toolbar tooltip */
34
+ description?: string;
35
+ /**
36
+ * The TipTap Node extension.
37
+ * Can be a static extension or a factory that receives runtime context
38
+ * (e.g., current variables list) and returns a configured extension.
39
+ */
40
+ extension: Node | ((ctx: BlockContext) => Node);
41
+ /** CSS styles for this block — injected into <head> when the block is registered */
42
+ styles: string;
43
+ /** CSS styles for PDF/preview export — included in exported HTML */
44
+ exportStyles?: string;
45
+ /** Called when the user clicks the block in the toolbar. Should call editor commands to insert. */
46
+ insert: (editor: import('@tiptap/react').Editor) => void;
47
+ }
@@ -0,0 +1,11 @@
1
+ import { type Editor } from '@tiptap/react';
2
+ interface HeaderFooterFieldProps {
3
+ content: string;
4
+ onChange: (html: string) => void;
5
+ placeholder: string;
6
+ isEditing: boolean;
7
+ onStartEdit: () => void;
8
+ editorRef?: React.MutableRefObject<Editor | null>;
9
+ }
10
+ export declare function HeaderFooterField({ content, onChange, placeholder, isEditing, onStartEdit, editorRef, }: HeaderFooterFieldProps): import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -0,0 +1,16 @@
1
+ import { type Editor } from '@tiptap/react';
2
+ import type { ResolvedCanvas } from './canvas-config';
3
+ import type { ThemeConfig } from '../types';
4
+ interface PageCanvasProps {
5
+ editor: Editor;
6
+ canvas: ResolvedCanvas;
7
+ header?: string;
8
+ footer?: string;
9
+ onHeaderChange?: (value: string) => void;
10
+ onFooterChange?: (value: string) => void;
11
+ onActiveHfEditor?: (editor: Editor | null) => void;
12
+ readOnly?: boolean;
13
+ theme?: ThemeConfig;
14
+ }
15
+ export declare function PageCanvas({ editor, canvas, header, footer, onHeaderChange, onFooterChange, onActiveHfEditor, readOnly, theme }: PageCanvasProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
@@ -0,0 +1,25 @@
1
+ import type { CanvasConfig } from '../types';
2
+ export declare const CANVAS_PRESETS: Record<string, CanvasConfig>;
3
+ export interface ResolvedCanvas {
4
+ width: string;
5
+ height: string | undefined;
6
+ padding: {
7
+ top: string;
8
+ right: string;
9
+ bottom: string;
10
+ left: string;
11
+ };
12
+ paginate: boolean;
13
+ pageGap: number;
14
+ widthPx: number;
15
+ heightPx: number | undefined;
16
+ paddingPx: {
17
+ top: number;
18
+ right: number;
19
+ bottom: number;
20
+ left: number;
21
+ };
22
+ contentHeightPx: number | undefined;
23
+ }
24
+ export declare function resolveCanvas(canvas: string | CanvasConfig | undefined): ResolvedCanvas;
25
+ export declare function cssToPixels(value: string): number;
@@ -0,0 +1,54 @@
1
+ import { type EditorActionsConfig } from '../toolbar/EditorActions';
2
+ import type { EditorBlockPlugin } from '../blocks/types';
3
+ import type { CanvasConfig, ToolbarConfig, TemplateVariable, ExtensionsConfig, ThemeConfig } from '../types';
4
+ import '../editor.css';
5
+ export interface DocCraftRef {
6
+ getHTML: () => string;
7
+ getPdfHTML: (options?: {
8
+ title?: string;
9
+ }) => string;
10
+ getPreviewHTML: (options?: {
11
+ title?: string;
12
+ }) => string;
13
+ getJSON: () => Record<string, unknown>;
14
+ setContent: (html: string) => void;
15
+ getVariables: () => TemplateVariable[];
16
+ getHeader: () => string;
17
+ getFooter: () => string;
18
+ setHeader: (text: string) => void;
19
+ setFooter: (text: string) => void;
20
+ setReadOnly: (readOnly: boolean) => void;
21
+ isReadOnly: () => boolean;
22
+ focus: () => void;
23
+ clear: () => void;
24
+ }
25
+ export interface DocCraftProps {
26
+ content?: string;
27
+ placeholder?: string;
28
+ onChange?: (html: string) => void;
29
+ className?: string;
30
+ variables?: TemplateVariable[] | false;
31
+ blocks?: EditorBlockPlugin[];
32
+ header?: string;
33
+ footer?: string;
34
+ /**
35
+ * Read-only mode. Disables content editing but keeps the document visible.
36
+ * Toolbar remains visible (unless showToolbar={false}) so the user can
37
+ * click the Edit/Preview toggle to switch modes.
38
+ * Can be toggled programmatically via ref.setReadOnly().
39
+ */
40
+ readOnly?: boolean;
41
+ /**
42
+ * Whether to show the toolbar. Defaults to true.
43
+ * Set to false to completely hide the toolbar — the user cannot
44
+ * switch between edit/preview modes (true read-only display).
45
+ */
46
+ showToolbar?: boolean;
47
+ actions?: boolean | EditorActionsConfig;
48
+ toolbarActions?: React.ReactNode;
49
+ canvas?: 'a4' | 'email' | CanvasConfig;
50
+ toolbar?: 'full' | 'minimal' | 'document' | ToolbarConfig;
51
+ extensions?: ExtensionsConfig;
52
+ theme?: ThemeConfig;
53
+ }
54
+ export declare const DocCraft: import("react").ForwardRefExoticComponent<DocCraftProps & import("react").RefAttributes<DocCraftRef>>;
@@ -0,0 +1,22 @@
1
+ import { Extension } from '@tiptap/core';
2
+ interface PageFlowOptions {
3
+ contentHeight: number;
4
+ paddingTop: number;
5
+ paddingBottom: number;
6
+ pageGap: number;
7
+ enabled: boolean;
8
+ }
9
+ /**
10
+ * Page Flow Extension
11
+ *
12
+ * Injects CSS margin-top rules via a <style> tag to push content that
13
+ * crosses page boundaries to the next page's content area.
14
+ *
15
+ * Uses nth-child selectors. To avoid layout thrashing:
16
+ * - Debounces at 100ms (not every keystroke)
17
+ * - Only recomputes when content structure changes
18
+ * - Clears rules, reads clean positions, re-applies in one rAF
19
+ * (single reflow instead of clear-measure-apply cycle)
20
+ */
21
+ export declare const PageFlowExtension: Extension<PageFlowOptions, any>;
22
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { EditorBlockPlugin } from '../blocks/types';
2
+ import type { ResolvedCanvas } from '../canvas/canvas-config';
3
+ import type { TemplateVariable as TemplateVariableType, ExtensionsConfig } from '../types';
4
+ interface UseEditorOptions {
5
+ content?: string;
6
+ placeholder?: string;
7
+ variables?: TemplateVariableType[] | false;
8
+ blocks?: EditorBlockPlugin[];
9
+ canvas?: ResolvedCanvas;
10
+ extensions?: ExtensionsConfig;
11
+ onUpdate?: (html: string) => void;
12
+ }
13
+ export declare function useEditor(options?: UseEditorOptions): import("@tiptap/core").Editor;
14
+ export {};