Skip to content

Commit 854f5cb

Browse files
committed
feat(slots): above-toolbar workplace slot (slots.above)
A new slot that always stays ABOVE the toolbar — for presence bars, banners and similar chrome (the spot Google Docs uses for its avatars row). The toolbar box used to re-pin itself as the container's first child on every toolbarContainer access; it now skips children flagged with data-jodit-above-toolbar. Empty slot renders as nothing; non-empty gets the standard border-bottom.
1 parent bae68ee commit 854f5cb

5 files changed

Lines changed: 66 additions & 5 deletions

File tree

src/core/view/view-with-toolbar.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,33 @@ export abstract class ViewWithToolbar extends View implements IViewWithToolbar {
4949
return resolveElement(this.o.toolbar, this.o.shadowRoot || this.od);
5050
}
5151

52-
this.o.toolbar &&
53-
Dom.appendChildFirst(
54-
this.container,
55-
this.__defaultToolbarContainer
56-
);
52+
this.o.toolbar && this.__appendToolbarBox();
5753

5854
return this.__defaultToolbarContainer;
5955
}
6056

57+
/**
58+
* Keep the toolbar box as the first child of the container, except that
59+
* children flagged with `data-jodit-above-toolbar` (e.g. the `above`
60+
* workplace slot used for presence bars and banners) stay above it.
61+
*/
62+
private __appendToolbarBox(): void {
63+
const box = this.__defaultToolbarContainer;
64+
let anchor = this.container.firstElementChild;
65+
66+
while (
67+
anchor &&
68+
anchor !== box &&
69+
anchor.hasAttribute('data-jodit-above-toolbar')
70+
) {
71+
anchor = anchor.nextElementSibling;
72+
}
73+
74+
if (anchor !== box) {
75+
this.container.insertBefore(box, anchor);
76+
}
77+
}
78+
6179
/**
6280
* Change panel container
6381
*/

src/jodit.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,6 +1417,13 @@ export class Jodit extends ViewWithToolbar implements IJodit, Dlgs {
14171417

14181418
const SLOT = 'workplace-slot';
14191419

1420+
// A slot that always stays ABOVE the toolbar (presence bars, banners…).
1421+
// The `data-jodit-above-toolbar` attribute tells ViewWithToolbar to keep
1422+
// the toolbar box below it when (re)attaching the toolbar container.
1423+
const aboveSlot = this.c.div(this.getFullElName(SLOT, 'above'), NOEDIT);
1424+
aboveSlot.setAttribute('data-jodit-above-toolbar', '');
1425+
Dom.appendChildFirst(container, aboveSlot);
1426+
14201427
const topSlot = this.c.div(this.getFullElName(SLOT, 'top'), NOEDIT);
14211428

14221429
container.appendChild(topSlot);
@@ -1468,6 +1475,7 @@ export class Jodit extends ViewWithToolbar implements IJodit, Dlgs {
14681475
container,
14691476
workplace,
14701477
slots: {
1478+
above: aboveSlot,
14711479
top: topSlot,
14721480
bottom: bottomPanel,
14731481
center: centerSlot,

src/styles/slots.less

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
--slot-left-width: auto;
55
--slot-right-width: auto;
66

7+
.jodit-jodit__workplace-slot_above_true,
78
.jodit-jodit__workplace-slot_top_true,
89
.jodit-jodit__workplace-slot_bottom_true {
910
min-width: 0;
@@ -14,6 +15,11 @@
1415
}
1516
}
1617

18+
// Sits above the toolbar (presence bars, banners).
19+
.jodit-jodit__workplace-slot_above_true:not(:empty) {
20+
border-bottom: 1px solid var(--color-border, transparent);
21+
}
22+
1723
.jodit-jodit__workplace-slot_top_true {
1824
height: var(--slot-top-height);
1925

src/styles/slots.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ describe('Test editor slots system', function () {
99
it('Should create all slot elements', function () {
1010
const editor = getJodit();
1111

12+
expect(editor.currentPlace.slots.above).is.not.null;
1213
expect(editor.currentPlace.slots.top).is.not.null;
1314
expect(editor.currentPlace.slots.bottom).is.not.null;
1415
expect(editor.currentPlace.slots.center).is.not.null;
@@ -42,6 +43,32 @@ describe('Test editor slots system', function () {
4243
).is.true;
4344
});
4445

46+
it('Should keep the above slot ABOVE the toolbar box', function () {
47+
const editor = getJodit();
48+
49+
const above = editor.currentPlace.slots.above;
50+
expect(above.hasAttribute('data-jodit-above-toolbar')).is.true;
51+
expect(
52+
above.classList.contains(
53+
'jodit-jodit__workplace-slot_above_true'
54+
)
55+
).is.true;
56+
57+
// The toolbar box must come AFTER the above slot in the container…
58+
const box = editor.toolbarContainer;
59+
expect(box.parentElement).equals(editor.container);
60+
expect(
61+
above.compareDocumentPosition(box) &
62+
Node.DOCUMENT_POSITION_FOLLOWING
63+
).is.above(0);
64+
65+
// …and stay there even after the getter re-attaches the box.
66+
above.appendChild(editor.c.element('div'));
67+
const boxAgain = editor.toolbarContainer;
68+
expect(boxAgain).equals(box);
69+
expect(above.nextElementSibling).equals(box);
70+
});
71+
4572
it('Should hide empty slots', function () {
4673
const editor = getJodit();
4774

src/types/jodit.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ interface IWorkPlace {
3131
container: HTMLDivElement;
3232
workplace: HTMLDivElement;
3333
slots: {
34+
/** Sits above the toolbar (presence bars, banners). */
35+
above: HTMLDivElement;
3436
top: HTMLDivElement;
3537
bottom: HTMLDivElement;
3638
center: HTMLDivElement;

0 commit comments

Comments
 (0)