diff --git a/apps/create/src/templates.ts b/apps/create/src/templates.ts index e9838ef77e..f007a7534f 100644 --- a/apps/create/src/templates.ts +++ b/apps/create/src/templates.ts @@ -172,6 +172,7 @@ Key options for the editor: | \`documentMode\` | \`'editing' \\| 'viewing' \\| 'suggesting'\` | Editor mode | | \`user\` | \`{ name, email }\` | Current user (for comments/tracked changes) | | \`toolbar\` | \`string \\| HTMLElement\` | Toolbar mount selector or element | +| \`contained\` | \`boolean\` | Scroll inside a fixed-height parent instead of expanding | | \`modules.comments\` | \`object\` | Comments panel configuration | | \`modules.collaboration\` | \`object\` | Real-time collaboration (Yjs) | diff --git a/apps/docs/core/react/configuration.mdx b/apps/docs/core/react/configuration.mdx index 71d44100b9..bf6f40d161 100644 --- a/apps/docs/core/react/configuration.mdx +++ b/apps/docs/core/react/configuration.mdx @@ -78,6 +78,23 @@ All props are passed directly to the `` component. Only `documen Hide the toolbar. + + Enable contained mode for fixed-height container embedding. When `true`, SuperDoc fits within its parent's height and scrolls internally. + + Your wrapper must have a definite height (e.g., `height: 400px`, `flex: 1`, or a CSS class with a fixed height). Pass `style={{ height: '100%' }}` to propagate the height. + + ```jsx +
+ +
+ ``` +
+ Show or hide rulers. Uses SuperDoc default if not set. diff --git a/apps/docs/core/superdoc/configuration.mdx b/apps/docs/core/superdoc/configuration.mdx index bc6ce7bf20..89dc5bbd30 100644 --- a/apps/docs/core/superdoc/configuration.mdx +++ b/apps/docs/core/superdoc/configuration.mdx @@ -395,6 +395,42 @@ new SuperDoc({ ``` + + Enable contained mode for fixed-height container embedding. When `true`, SuperDoc fits within its parent's height and scrolls internally instead of expanding to the document's natural height. Works with DOCX, PDF, and HTML documents. + + Use this when embedding SuperDoc inside a panel, sidebar, or any container with a fixed height (e.g., `height: 400px` or `flex: 1`). + + + + ```javascript Usage + const superdoc = new SuperDoc({ + selector: '#editor', + document: file, + contained: true, + }); + ``` + + ```html Full Example + +
+
+
+ + + ``` + +
+
+ **Removed in v1.0** — Use `viewOptions.layout` instead. `'paginated'` → `'print'`, `'responsive'` → `'web'`. diff --git a/apps/docs/snippets/components/superdoc-editor.jsx b/apps/docs/snippets/components/superdoc-editor.jsx index 0d73ed37a1..94ec772d29 100644 --- a/apps/docs/snippets/components/superdoc-editor.jsx +++ b/apps/docs/snippets/components/superdoc-editor.jsx @@ -79,6 +79,7 @@ export const SuperDocEditor = ({ selector: `#${containerIdRef.current}`, html, rulers: true, + contained: true, onReady: () => { setReady(true); if (onReady) onReady(editorRef.current); @@ -151,26 +152,17 @@ export const SuperDocEditor = ({ )} )} -
+
diff --git a/packages/superdoc/CLAUDE.md b/packages/superdoc/CLAUDE.md index 1c6b28c204..f6655ba94c 100644 --- a/packages/superdoc/CLAUDE.md +++ b/packages/superdoc/CLAUDE.md @@ -55,6 +55,17 @@ Uses `layout-engine` for virtualized rendering with pagination. `PresentationEditor.ts` bridges state between modes. See `super-editor/src/core/presentation-editor/` for implementation. +### Fixed-height container embedding +By default SuperDoc expands to the document's full height. To embed it inside a fixed-height container (panel, sidebar, modal, dashboard widget), pass `contained: true`. The parent element must have a definite height. + +```javascript +new SuperDoc({ + selector: '#editor', + document: file, + contained: true, +}); +``` + ## Theming SuperDoc UI is themed via `--sd-*` CSS variables. Use `createTheme()` for JS-based theming or set variables directly in CSS. @@ -76,7 +87,6 @@ document.documentElement.classList.add(theme); - Preset themes — `src/assets/styles/helpers/themes.css` - Backward-compat aliases — `src/assets/styles/helpers/compat.css` - Consumer-facing agent guide — `AGENTS.md` (ships with npm package) - ## Testing - Unit tests: `src/SuperDoc.test.js` diff --git a/packages/superdoc/src/SuperDoc.vue b/packages/superdoc/src/SuperDoc.vue index 94ad2bbb8e..83b40d899f 100644 --- a/packages/superdoc/src/SuperDoc.vue +++ b/packages/superdoc/src/SuperDoc.vue @@ -710,6 +710,7 @@ const editorOptions = (doc) => { disableContextMenu: proxy.$superdoc.config.disableContextMenu, jsonOverride: proxy.$superdoc.config.jsonOverride, viewOptions: proxy.$superdoc.config.viewOptions, + contained: proxy.$superdoc.config.contained, linkPopoverResolver: proxy.$superdoc.config.modules?.links?.popoverResolver, layoutEngineOptions: useLayoutEngine ? { @@ -1441,6 +1442,7 @@ const getPDFViewer = () => { :class="{ 'superdoc--with-sidebar': showCommentsSidebar, 'superdoc--web-layout': proxy.$superdoc.config.viewOptions?.layout === 'web', + 'superdoc--contained': proxy.$superdoc.config.contained, 'high-contrast': isHighContrastMode, }" :style="superdocStyleVars" @@ -1640,6 +1642,21 @@ const getPDFViewer = () => { position: relative; } +/* In contained mode, overlay layers must not take flow space. + * With height:100% resolved on .superdoc__document, this element's + * position:relative + height:100% takes the full container height, + * pushing .superdoc__sub-document out of view. */ +.superdoc--contained .superdoc__comments-layer { + position: absolute; + width: 100%; + pointer-events: none; +} + +/* Re-enable pointer events on comment anchors so highlights remain clickable */ +.superdoc--contained .sd-comment-anchor { + pointer-events: auto; +} + .superdoc__right-sidebar { width: 320px; min-width: 320px; diff --git a/packages/superdoc/src/assets/styles/elements/superdoc.css b/packages/superdoc/src/assets/styles/elements/superdoc.css index a2c637306e..1686029510 100644 --- a/packages/superdoc/src/assets/styles/elements/superdoc.css +++ b/packages/superdoc/src/assets/styles/elements/superdoc.css @@ -47,3 +47,18 @@ .superdoc .ProseMirror-active-search-match { background: var(--sd-ui-search-match-active-bg); } + +/* Contained Mode - fixed-height container embedding with internal scrolling */ +.superdoc--contained, +.superdoc--contained .superdoc__layers, +.superdoc--contained .superdoc__document, +.superdoc--contained .superdoc__sub-document { + height: 100%; +} + +/* Sub-document scroll fallback for non-SuperEditor content (PDF, HTML). + * SuperEditor manages its own scroll container via .super-editor-container.contained, + * but PDF/HTML viewers don't — they need the sub-document to scroll. */ +.superdoc--contained .superdoc__sub-document { + overflow: auto; +} diff --git a/packages/superdoc/src/core/types/index.js b/packages/superdoc/src/core/types/index.js index 2086f40d7e..75f7479003 100644 --- a/packages/superdoc/src/core/types/index.js +++ b/packages/superdoc/src/core/types/index.js @@ -621,6 +621,10 @@ * @property {boolean} [warnOnUnsupportedContent] When true and no onUnsupportedContent callback is provided, emits a console.warn with unsupported items * @property {boolean} [isDebug=false] Whether to enable debug mode * @property {ViewOptions} [viewOptions] Document view options (OOXML ST_View compatible) + * @property {boolean} [contained] Enable contained mode for fixed-height container embedding. + * When true, SuperDoc propagates height through its DOM tree and adds internal scrolling, + * so multi-page documents scroll within the consumer's fixed-height container. + * Default behavior (false) lets the document expand to its natural height. * @property {string} [cspNonce] Content Security Policy nonce for dynamically injected styles * @property {string} [licenseKey] License key for organization identification * @property {{ enabled: boolean, endpoint?: string, metadata?: Record, licenseKey?: string }} [telemetry] Telemetry configuration