Skip to content

Commit

Permalink
fix(toolkit/observable): position document root in CSS layer when usi…
Browse files Browse the repository at this point in the history
…ng `fromBoundingClientRect$`

CSS layers have lower priority than normal CSS declarations, and the layer name indicates the styling originates from `@scion/toolkit`.
  • Loading branch information
danielwiehl committed Oct 10, 2024
1 parent de8d31a commit c1fef65
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import {fromBoundingClientRect$} from './bounding-client-rect.observable';
import {ObserveCaptor} from '@scion/toolkit/testing';
import {Arrays} from '@scion/toolkit/util';

const destroyAfterEach = true;
const disposables = new Array<() => void>();
Expand Down Expand Up @@ -452,6 +453,52 @@ describe('fromBoundingClientRect$', () => {
expect(emitCaptor.getLastValue()).toEqual(jasmine.objectContaining({x: x2, y: y2 - 20, width: 100, height: 100}));
});

it('should position document root element (html)', async () => {
// Precondition: Ensure document root not to be positioned so its position will be changed to 'relative'.
document.documentElement.style.setProperty('position', 'static');

const subscription = fromBoundingClientRect$(document.body).subscribe();
onDestroy(() => subscription.unsubscribe());

// Remove style from precondition.
document.documentElement.style.removeProperty('position');

// Expect document root to be positioned.
expect(getComputedStyle(document.documentElement)).toEqual(jasmine.objectContaining({
position: 'relative',
}));
});

it('should allow overriding positioning of document root element (html)', async () => {
// Precondition: Ensure document root not to be positioned so its position will be changed to 'relative'.
document.documentElement.style.setProperty('position', 'static');

const subscription = fromBoundingClientRect$(document.body).subscribe();
onDestroy(() => subscription.unsubscribe());

// Remove style from precondition.
document.documentElement.style.removeProperty('position');

// Expect document root to be positioned.
expect(getComputedStyle(document.documentElement)).toEqual(jasmine.objectContaining({
position: 'relative',
}));

// Override positioning of root element.
const styleSheet = new CSSStyleSheet();
styleSheet.insertRule(`
html {
position: absolute;
}`);
document.adoptedStyleSheets.push(styleSheet);
onDestroy(() => Arrays.remove(document.adoptedStyleSheets, styleSheet));

// Expect overrides to be applied.
expect(getComputedStyle(document.documentElement)).toEqual(jasmine.objectContaining({
position: 'absolute',
}));
});

describe('Moving element out of the viewport', async () => {

it('should emit until moved the element out of the viewport (moving element to the right)', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,16 @@ function ensureElementPositioned(element: HTMLElement): void {
return;
}

// Position the HTML root using a constructable stylesheet to not clutter its element styles.
// Declare styles for the document root element (`<html>`) in a CSS layer.
// CSS layers have lower priority than "regular" CSS declarations, and the layer name indicates the styles are from @scion/toolkit.
if (element === document.documentElement) {
const styleSheet = new CSSStyleSheet({});
styleSheet.insertRule(`html { position: relative; }`);
styleSheet.insertRule(`
@layer sci-toolkit {
:root {
position: relative;
}
}`);
document.adoptedStyleSheets.push(styleSheet);
console?.warn?.('[@scion/toolkit] fromBoundingClientRect$ requires the document root element (<html>) to be positioned relative or absolute. Changing positioning to relative.');
}
Expand Down

0 comments on commit c1fef65

Please sign in to comment.