Skip to content

Commit

Permalink
feat(makeStyles): add an ability to increase specificity (#16232)
Browse files Browse the repository at this point in the history
* feat(makeStyles): add an ability to increase specificity

* Change files
  • Loading branch information
layershifter authored Dec 17, 2020
1 parent 81651e8 commit 30587bf
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "patch",
"comment": "feat(makeStyles): add an ability to increase specificity",
"packageName": "@fluentui/make-styles",
"email": "[email protected]",
"dependentChangeType": "patch",
"date": "2020-12-17T10:05:34.220Z"
}
5 changes: 4 additions & 1 deletion packages/make-styles/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"extends": ["plugin:@fluentui/eslint-plugin/react"],
"root": true
"root": true,
"rules": {
"@typescript-eslint/naming-convention": "off"
}
}
12 changes: 10 additions & 2 deletions packages/make-styles/src/makeStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import {
MakeStylesResolvedDefinition,
} from './types';

export function makeStyles<Selectors, Tokens>(definitions: MakeStylesDefinition<Selectors, Tokens>[]) {
export function makeStyles<Selectors, Tokens>(
definitions: MakeStylesDefinition<Selectors, Tokens>[],
unstable_cssPriority: number = 0,
) {
const cxCache: Record<string, string> = {};

return function computeClasses(
Expand All @@ -23,12 +26,17 @@ export function makeStyles<Selectors, Tokens>(definitions: MakeStylesDefinition<
tokens = CAN_USE_CSS_VARIABLES ? null : options.tokens;
resolvedDefinitions = CAN_USE_CSS_VARIABLES
? ((definitions as unknown) as MakeStylesResolvedDefinition<Selectors, Tokens>[])
: resolveDefinitions((definitions as unknown) as MakeStylesResolvedDefinition<Selectors, Tokens>[], tokens);
: resolveDefinitions(
(definitions as unknown) as MakeStylesResolvedDefinition<Selectors, Tokens>[],
tokens,
unstable_cssPriority,
);
} else {
tokens = CAN_USE_CSS_VARIABLES ? createCSSVariablesProxy(options.tokens) : options.tokens;
resolvedDefinitions = resolveDefinitions(
(definitions as unknown) as MakeStylesResolvedDefinition<Selectors, Tokens>[],
tokens,
unstable_cssPriority,
);
}

Expand Down
11 changes: 9 additions & 2 deletions packages/make-styles/src/runtime/compileCSS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@ interface CompileCSSOptions {

property: string;
value: number | string;

unstable_cssPriority: number;
}

function repeatSelector(selector: string, times: number) {
return new Array(times + 2).join(selector);
}

export function compileCSS(options: CompileCSSOptions): string {
const { className, media, pseudo, support, property, value } = options;
const { className, media, pseudo, support, property, value, unstable_cssPriority } = options;

const cssDeclaration = `{ ${hyphenateProperty(property)}: ${value}; }`;

Expand All @@ -31,7 +37,8 @@ export function compileCSS(options: CompileCSSOptions): string {

return serialize(compile(cssRule), middleware([stringify]));
} else {
let cssRule = `.${className}${pseudo} ${cssDeclaration}`;
const classNameSelector = repeatSelector(`.${className}`, unstable_cssPriority);
let cssRule = `${classNameSelector}${pseudo} ${cssDeclaration}`;

if (media) {
cssRule = `@media ${media} { ${cssRule} }`;
Expand Down
10 changes: 7 additions & 3 deletions packages/make-styles/src/runtime/resolveDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const graphSet = (graphNode: Map<any, any>, path: any[], value: any) => {
export function resolveDefinitions<Selectors, Tokens>(
definitions: MakeStylesResolvedDefinition<Selectors, Tokens>[],
tokens: Tokens | null,
unstable_cssPriority: number,
): MakeStylesResolvedDefinition<Selectors, Tokens>[] {
return definitions.map((definition, i) => {
const matcher = definition[0];
Expand All @@ -61,7 +62,7 @@ export function resolveDefinitions<Selectors, Tokens>(
const styles: MakeStyles =
typeof styleRule === 'function' ? (styleRule as MakeStylesStyleFunctionRule<Tokens>)(tokens!!) : styleRule!!;

definitions[i][2] = resolveStyleRules(styles);
definitions[i][2] = resolveStyleRules(styles, unstable_cssPriority);

return [matcher, undefined, definition[2]];
}
Expand All @@ -77,7 +78,10 @@ export function resolveDefinitions<Selectors, Tokens>(
return [matcher, undefined, resolvedStyles];
}

const resolveStyles1 = resolveStyleRules((styleRule as MakeStylesStyleFunctionRule<Tokens>)(tokens!!));
const resolveStyles1 = resolveStyleRules(
(styleRule as MakeStylesStyleFunctionRule<Tokens>)(tokens!!),
unstable_cssPriority,
);
graphSet(graph, path, resolveStyles1);

return [matcher, undefined, resolveStyles1];
Expand All @@ -87,7 +91,7 @@ export function resolveDefinitions<Selectors, Tokens>(
return [matcher, undefined, resolvedRule];
}

definitions[i][2] = resolveStyleRules(styleRule!!);
definitions[i][2] = resolveStyleRules(styleRule!!, unstable_cssPriority);

return [matcher, undefined, definition[2]];
});
Expand Down
57 changes: 57 additions & 0 deletions packages/make-styles/src/runtime/resolveStyleRules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,5 +383,62 @@ describe('resolveStyleRules', () => {
}
`);
});

it('allows to increase specificity', () => {
expect(resolveStyleRules({ color: 'red' }, 1)).toMatchInlineSnapshot(`
.fe3e8s91.fe3e8s91 {
color: red;
}
`);
expect(resolveStyleRules({ color: 'red' }, 2)).toMatchInlineSnapshot(`
.fe3e8s92.fe3e8s92.fe3e8s92 {
color: red;
}
`);
});

it('allows to increase for media queries', () => {
expect(
resolveStyleRules(
{
'@media screen and (max-width: 992px)': {
color: 'red',
},
},
1,
),
).toMatchInlineSnapshot(`
@media screen and (max-width: 992px) {
.f1ojdyje1.f1ojdyje1 {
color: red;
}
}
`);
});

it('allows to increase for RTL', () => {
expect(resolveStyleRules({ left: '5px' }, 1)).toMatchInlineSnapshot(`
.f5b3q4t1.f5b3q4t1 {
left: 5px;
}
.rf5b3q4t1.rf5b3q4t1 {
right: 5px;
}
`);
});

it('generates unique classnames with different specificity', () => {
function getFirstClassName(resolvedStyles: Record<string, MakeStylesResolvedRule>): string {
return resolvedStyles[Object.keys(resolvedStyles)[0]][0];
}

const classnamesSet = new Set<string>();

classnamesSet.add(getFirstClassName(resolveStyleRules({ color: 'red' })));
classnamesSet.add(getFirstClassName(resolveStyleRules({ color: 'red' }, 1)));
classnamesSet.add(getFirstClassName(resolveStyleRules({ color: 'red' }, 2)));

expect(classnamesSet.size).toBe(3);
});
});
});
22 changes: 17 additions & 5 deletions packages/make-styles/src/runtime/resolveStyleRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { normalizeNestedProperty } from './utils/normalizeNestedProperty';

export function resolveStyleRules(
styles: MakeStyles,
unstable_cssPriority: number = 0,
pseudo = '',
media = '',
support = '',
Expand All @@ -35,14 +36,17 @@ export function resolveStyleRules(
const key = pseudo + media + support + property;

// trimming of values is required to generate consistent hashes
const className = HASH_PREFIX + hashString(pseudo + media + support + property + value.toString().trim());
const classNameHash = hashString(pseudo + media + support + property + value.toString().trim());
const className = HASH_PREFIX + classNameHash + (unstable_cssPriority === 0 ? '' : unstable_cssPriority);

const css = compileCSS({
className,
media,
pseudo,
property,
support,
value,
unstable_cssPriority
});

const rtl = convertProperty(property, value);
Expand All @@ -56,6 +60,7 @@ export function resolveStyleRules(
property: rtl.key,
support,
value: rtl.value,
unstable_cssPriority
});

// There is no sense to store RTL className as it's "r" + regular className
Expand All @@ -65,15 +70,22 @@ export function resolveStyleRules(
}
} else if (isObject(value)) {
if (isNestedSelector(property)) {
resolveStyleRules(value, pseudo + normalizeNestedProperty(property), media, support, result);
resolveStyleRules(
value,
unstable_cssPriority,
pseudo + normalizeNestedProperty(property),
media,
support,
result,
);
} else if (isMediaQuerySelector(property)) {
const combinedMediaQuery = generateCombinedQuery(media, property.slice(6).trim());

resolveStyleRules(value, pseudo, combinedMediaQuery, support, result);
resolveStyleRules(value, unstable_cssPriority, pseudo, combinedMediaQuery, support, result);
} else if (isSupportQuerySelector(property)) {
const combinedSupportQuery = generateCombinedQuery(support, property.slice(9).trim());

resolveStyleRules(value, pseudo, media, combinedSupportQuery, result);
resolveStyleRules(value, unstable_cssPriority, pseudo, media, combinedSupportQuery, result);
} else if (property === 'animationName') {
// TODO: support RTL!
const keyframe = compileKeyframeRule(value);
Expand All @@ -84,7 +96,7 @@ export function resolveStyleRules(

result[animationName] = [animationName, keyframeCSS /* rtlCSS */];

resolveStyleRules({ animationName }, pseudo, media, support, result);
resolveStyleRules({ animationName }, unstable_cssPriority, pseudo, media, support, result);
}
}
});
Expand Down

0 comments on commit 30587bf

Please sign in to comment.