Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions core-web/libs/new-block-editor/src/lib/editor/editor.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@
display: block;
}

/* Fill-height mode (see `fillHeight` input): the host becomes a full-height flex column so
the wrapper/panel chain can stretch to fill a bounded parent (e.g. the UVE sidebar drawer).
`min-height: 0` lets the host shrink when it is itself a flex child of the parent. */
:host(.dot-block-editor--fill-height) {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}

/* ─── ProseMirror base ──────────────────────────────────── */
:host ::ng-deep .ProseMirror {
outline: none;
Expand Down
66 changes: 51 additions & 15 deletions core-web/libs/new-block-editor/src/lib/editor/editor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ function normalizeEditorContent(
selector: 'dot-block-editor',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./editor.component.css'],
host: {
// Turns the host into a full-height flex column when `fillHeight` is set, so the
// editor stretches to fill a bounded parent (e.g. the UVE sidebar drawer) instead
// of collapsing to its default fixed height. See `:host(.dot-block-editor--fill-height)`.
'[class.dot-block-editor--fill-height]': 'fillHeight()'
},
providers: [
EditorStore,
SlashMenuService,
Expand Down Expand Up @@ -208,18 +214,15 @@ function normalizeEditorContent(
<div [class]="panelClass()">
@if (editor(); as ed) {
<dot-toolbar
class="shrink-0"
[editor]="ed"
[isFullscreen]="isFullscreen()"
(fullscreenToggle)="toggleFullscreen()"
(contentletEdit)="contentletEdit.emit($event)" />
<div
class="editor-scroll-container relative overflow-y-auto overscroll-contain"
[class.editor-scroll-container--locked]="anyOverlayOpen()"
[style]="
isFullscreen()
? 'flex: 1; min-height: 0;'
: 'height: 500px; resize: vertical; min-height: 200px;'
">
[style]="scrollContainerStyle()">
<div
tiptap
[editor]="ed"
Expand All @@ -235,7 +238,7 @@ function normalizeEditorContent(
</div>

<div
class="flex items-center gap-4 border-t border-gray-100 px-8 py-3 text-sm text-gray-500"
class="flex shrink-0 items-center gap-4 border-t border-gray-100 px-8 py-3 text-sm text-gray-500"
aria-live="polite"
[attr.aria-label]="'dot.block.editor.editor.stats.aria-label' | dm">
<span>
Expand Down Expand Up @@ -340,6 +343,18 @@ export class DotCMSEditorComponent implements OnDestroy, ControlValueAccessor {
*/
readonly hasError = input(false, { transform: booleanAttribute });

/**
* When true, the editor stretches to fill 100% of its parent's height instead of
* using the default fixed, resizable height. The toolbar and stats bar keep their
* natural height; the scroll surface consumes the remaining space.
*
* Set by hosts that render the editor inside a bounded container — e.g. the UVE
* block-editor sidebar drawer — where the editor should fill the available height
* (minus the drawer's own footer buttons). Requires the parent to give the host a
* definite height (the host becomes a flex column via `dot-block-editor--fill-height`).
*/
readonly fillHeight = input(false, { transform: booleanAttribute });

/**
* Emits the editor document as a ProseMirror JSON object on every change.
* The JSP Web-Component host stringifies this value and writes it to a hidden form input;
Expand Down Expand Up @@ -504,17 +519,38 @@ export class DotCMSEditorComponent implements OnDestroy, ControlValueAccessor {
}

/** Backdrop/layout classes for the outer wrapper (fullscreen dimmer vs inline). */
protected readonly wrapperClass = computed(() =>
this.isFullscreen()
? 'fixed inset-0 z-[9998] flex items-center justify-center bg-black/50'
: ''
);
protected readonly wrapperClass = computed(() => {
if (this.isFullscreen()) {
return 'fixed inset-0 z-[9998] flex items-center justify-center bg-black/50';
}

// Fill mode: become a flex column that consumes the host's full height so the panel
// below can stretch. `min-h-0` lets it shrink inside a flex parent.
return this.fillHeight() ? 'flex flex-col h-full min-h-0' : '';
});

/** Inner panel sizing and chrome classes (fullscreen vs default card layout). */
protected readonly panelClass = computed(() =>
this.isFullscreen()
? 'relative flex flex-col w-[90vw] h-[90vh] rounded-lg border border-gray-200 bg-white overflow-hidden'
: 'relative rounded-lg border border-gray-200'
protected readonly panelClass = computed(() => {
if (this.isFullscreen()) {
return 'relative flex flex-col w-[90vw] h-[90vh] rounded-lg border border-gray-200 bg-white overflow-hidden';
}

// Fill mode: flex column that grows to fill the wrapper, so the toolbar + stats bar
// take their natural height and the scroll surface consumes the rest.
return this.fillHeight()
? 'relative flex flex-col flex-1 min-h-0 overflow-hidden rounded-lg border border-gray-200'
: 'relative rounded-lg border border-gray-200';
});

/**
* Inline styles for the scroll surface. In fullscreen or fill mode it flexes to consume
* the remaining height (toolbar + stats bar excluded); otherwise it uses the default
* fixed, user-resizable height.
*/
protected readonly scrollContainerStyle = computed(() =>
this.isFullscreen() || this.fillHeight()
? 'flex: 1; min-height: 0;'
: 'height: 500px; resize: vertical; min-height: 200px;'
);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
[field]="contentlet.field"
[value]="contentlet.content"
[languageId]="contentlet.language"
[fillHeight]="true"
(valueChange)="value.set($event)"
data-testId="dot-block-editor" />
} @else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
.container {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
// Breathing room between the editor and the Cancel/Save footer.
gap: spacing.$spacing-4;
}

// Both editors grow to fill the drawer height; the footer keeps its natural height.
// The new editor fills via its own `fillHeight` input; the legacy editor fills via the
// ::ng-deep `.editor-wrapper` override below.
dot-block-editor,
dot-old-block-editor {
display: flex;
flex-direction: column;
height: calc(100% - 4rem);
flex: 1 1 auto;
min-height: 0;
}
}

Expand All @@ -24,19 +28,34 @@
max-width: 1040px;
}

// The drawer is used as a plain editing surface (no title, not closable), so the
// empty PrimeNG header just wastes vertical space above the editor — hide it.
.p-drawer-header {
display: none;
}

.p-drawer-content {
// The Lara drawer content ships with `padding-top: 0` because the header
// normally supplies the top gap. With the header hidden, restore a top padding
// that matches the left/right/bottom sides (overlay.modal.padding = 1.5rem).
padding-top: spacing.$spacing-4;

.container {
height: 100%;
}
}
}
dot-block-editor .editor-wrapper,

// Legacy editor only: force its internal wrapper to fill the host. The new editor
// (`dot-block-editor`) fills via its `fillHeight` input and no longer renders an
// `.editor-wrapper` element, so it neither needs nor matches this override.
dot-old-block-editor .editor-wrapper {
height: 100% !important;
}
}

footer {
flex: 0 0 auto;
display: flex;
justify-content: flex-end;
gap: spacing.$spacing-3;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ describe('DotBlockEditorSidebarComponent', () => {
expect(blockEditor.field).toEqual(BLOCK_EDITOR_FIELD);
expect(blockEditor.languageId).toBe(EVENT_DATA.language);
expect(blockEditor.value).toEqual(EVENT_DATA.content);
// The editor must fill the drawer height when rendered inline in the UVE sidebar.
expect(blockEditor.fillHeight).toBe(true);
expect(dotContentTypeService.getContentType).toHaveBeenCalledWith('Blog');
});

Expand Down
Loading
Loading