Skip to content

Commit

Permalink
chore: add support for priorities in @griffel/shadow-dom (#541)
Browse files Browse the repository at this point in the history
* chore: add support for priority in CSS rules [shadow DOM renderer]

* review feedback
  • Loading branch information
layershifter authored Apr 24, 2024
1 parent 990967b commit b4ed7ac
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "chore: export getStyleSheetKey() for internal usage",
"packageName": "@griffel/core",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "chore: add support for priority in CSS rules",
"packageName": "@griffel/shadow-dom",
"email": "[email protected]",
"dependentChangeType": "patch"
}
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export { __resetCSS } from './__resetCSS';
export { __resetStyles } from './__resetStyles';

export { normalizeCSSBucketEntry } from './runtime/utils/normalizeCSSBucketEntry';
export { styleBucketOrdering } from './renderer/getStyleSheetForBucket';
export { styleBucketOrdering, getStyleSheetKey } from './renderer/getStyleSheetForBucket';
export { defaultCompareMediaQueries } from './renderer/createDOMRenderer';
export { getStyleBucketName } from './runtime/getStyleBucketName';
export { reduceToClassNameForSlots } from './runtime/reduceToClassNameForSlots';
Expand Down
76 changes: 61 additions & 15 deletions packages/shadow-dom/src/createShadowDOMRenderer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,22 @@ expect.addSnapshotSerializer({
});

describe('createShadowDOMRenderer', () => {
it('returns a renderer', () => {
const shadowRoot = document.createElement('div').attachShadow({ mode: 'open' });

expect(createShadowDOMRenderer(shadowRoot)).toHaveProperty('adoptedStyleSheets');
});
let shadowRoot: ShadowRoot;
let renderer: ReturnType<typeof createShadowDOMRenderer>;

describe('CSS insertion', () => {
let shadowRoot: ShadowRoot;
let renderer: ReturnType<typeof createShadowDOMRenderer>;
beforeEach(() => {
shadowRoot = document.createElement('div').attachShadow({ mode: 'open' });

beforeEach(() => {
shadowRoot = document.createElement('div').attachShadow({ mode: 'open' });
// jsdom doesn't support adoptedStyleSheets yet
shadowRoot.adoptedStyleSheets = [];
});

// jsdom doesn't support adoptedStyleSheets yet
shadowRoot.adoptedStyleSheets = [];
});
it('returns a renderer', () => {
expect(createShadowDOMRenderer(shadowRoot)).toHaveProperty('adoptedStyleSheets');
});

it('inserts styles in the correct order', () => {
describe('sheets ordering', () => {
it('handles bucket order', () => {
renderer = createShadowDOMRenderer(shadowRoot);

renderer.insertCSSRules({ d: ['a {}'] });
Expand Down Expand Up @@ -119,7 +117,55 @@ describe('createShadowDOMRenderer', () => {
`);
});

it('inserts sheets after other sheets', () => {
it('handles priorities of CSS rules', () => {
renderer = createShadowDOMRenderer(shadowRoot);

renderer.insertCSSRules({
d: ['.prio0 {}', ['.prio-2 {}', { p: -2 }], ['.prio-1 {}', { p: -1 }], ['.prio-3 {}', { p: -3 }]],
});
renderer.insertCSSRules({ f: ['.prio0:focus {}', ['.prio-1:focus {}', { p: -1 }]] });

expect(renderer.adoptedStyleSheets).toMatchInlineSnapshot(`
[
{
"bucketName": "d",
"metadata": {
"p": -3
}
},
{
"bucketName": "d",
"metadata": {
"p": -2
}
},
{
"bucketName": "d",
"metadata": {
"p": -1
}
},
{
"bucketName": "d",
"metadata": {}
},
{
"bucketName": "f",
"metadata": {
"p": -1
}
},
{
"bucketName": "f",
"metadata": {}
}
]
`);
});
});

describe('insertionPoint', () => {
it('inserts sheets after other sheets by default', () => {
const other1 = createSheetWithId('other1');
const other2 = createSheetWithId('other2');

Expand Down
11 changes: 7 additions & 4 deletions packages/shadow-dom/src/createShadowDOMRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { normalizeCSSBucketEntry, safeInsertRule } from '@griffel/core';
import { getStyleSheetKey, normalizeCSSBucketEntry, safeInsertRule } from '@griffel/core';
import type { GriffelRenderer, StyleBucketName } from '@griffel/core';

import { createFallbackRenderer } from './createFallbackRenderer';
import type { ExtendedCSSStyleSheet, GriffelShadowDOMRenderer } from './types';
import { findInsertionPoint, findShadowRootInsertionPoint } from './findInsertionPoint';
import type { ExtendedCSSStyleSheet, GriffelShadowDOMRenderer } from './types';

const SUPPORTS_CONSTRUCTABLE_STYLESHEETS: boolean = (() => {
try {
Expand Down Expand Up @@ -31,8 +31,11 @@ function getCSSStyleSheetForBucket(

onStyleSheetInsert: (stylesheet: ExtendedCSSStyleSheet) => void,
): ExtendedCSSStyleSheet {
const isMediaBucket = bucketName === 'm';
const styleSheetKey: StyleBucketName | string = isMediaBucket ? ((bucketName + metadata['m']) as string) : bucketName;
const styleSheetKey = getStyleSheetKey(
bucketName,
(metadata['m'] as string | undefined) ?? '',
(metadata['p'] as number | undefined) ?? 0,
);

if (!cssSheetsCache[styleSheetKey]) {
const styleSheet = new CSSStyleSheet() as ExtendedCSSStyleSheet;
Expand Down
29 changes: 23 additions & 6 deletions packages/shadow-dom/src/findInsertionPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,46 @@ const styleBucketOrderingMap = styleBucketOrdering.reduce((acc, cur, j) => {
return acc;
}, {} as Record<StyleBucketName, number>);

function isSameInsertionKey(sheetA: ExtendedCSSStyleSheet, sheetB: ExtendedCSSStyleSheet): boolean {
const targetKey = sheetA.bucketName + ((sheetA.metadata['m'] as string | undefined) ?? '');
const elementKey = sheetB.bucketName + ((sheetB.metadata['m'] as string | undefined) ?? '');

return targetKey === elementKey;
}

export function findInsertionPoint(
renderer: GriffelShadowDOMRenderer,
styleSheet: ExtendedCSSStyleSheet,
targetStyleSheet: ExtendedCSSStyleSheet,
): ExtendedCSSStyleSheet | null {
let styleSheets = renderer.adoptedStyleSheets;
const targetOrder = styleBucketOrderingMap[styleSheet.bucketName];

const targetOrder = styleBucketOrderingMap[targetStyleSheet.bucketName];
const targetPriority = (targetStyleSheet.metadata['p'] as number | undefined) ?? 0;

let comparer = (sheet: ExtendedCSSStyleSheet): number => targetOrder - styleBucketOrderingMap[sheet.bucketName];

if (styleSheet.bucketName === 'm' && styleSheet.metadata) {
if (targetStyleSheet.bucketName === 'm' && targetStyleSheet.metadata) {
const mediaElements = renderer.adoptedStyleSheets.filter(styleSheet => styleSheet.bucketName === 'm');

if (mediaElements.length) {
styleSheets = mediaElements;
comparer = sheet =>
renderer.compareMediaQueries(styleSheet.metadata['m'] as string, sheet.metadata['m'] as string);
renderer.compareMediaQueries(targetStyleSheet.metadata['m'] as string, sheet.metadata['m'] as string);
}
}

const comparerWithPriority = (sheet: ExtendedCSSStyleSheet): number => {
if (isSameInsertionKey(sheet, targetStyleSheet)) {
return targetPriority - ((sheet.metadata['p'] as number | undefined) ?? 0);
}

return comparer(sheet);
};

for (let l = styleSheets.length, i = l - 1; i >= 0; i--) {
const styleElement = styleSheets[i];
const styleSheet = styleSheets[i];

if (comparer(styleElement) > 0) {
if (comparerWithPriority(styleSheet) > 0) {
return styleSheets[i + 1] ?? null;
}
}
Expand Down

0 comments on commit b4ed7ac

Please sign in to comment.