Skip to content

Commit

Permalink
[core] Enable support for base and variant styles
Browse files Browse the repository at this point in the history
through css layers. Behind a feature-flag right now but the aim is to
make this default before v1 release.
  • Loading branch information
brijeshb42 committed May 27, 2024
1 parent b4e2d77 commit e0ec514
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 24 deletions.
2 changes: 2 additions & 0 deletions packages/pigment-css-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
"cssesc": "^3.0.0",
"csstype": "^3.1.3",
"lodash": "^4.17.21",
"postcss": "^8.4.38",
"postcss-merge-rules": "^7.0.0",
"stylis": "^4.3.1",
"stylis-plugin-rtl": "^2.1.1"
},
Expand Down
21 changes: 15 additions & 6 deletions packages/pigment-css-react/src/processors/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,9 @@ export class StyledProcessor extends BaseProcessor {
* which we can use to generate our styles.
* Order of processing styles -
* 1. CSS directly declared in styled call
* 3. Variants declared in styled call
* 2. CSS declared in theme object's styledOverrides
* 3. Variants declared in theme object
* 2. Variants declared in styled call
* 3. CSS declared in theme object's styledOverrides
* 4. Variants declared in theme object
*/
build(values: ValueCache): void {
if (this.isTemplateTag) {
Expand Down Expand Up @@ -449,6 +449,7 @@ export class StyledProcessor extends BaseProcessor {
variantsAccumulator,
themeImportIdentifier,
);

const className = this.getClassName();
this.baseClasses.push(className);
this.collectedStyles.push([className, finalStyle, styleArg]);
Expand Down Expand Up @@ -523,8 +524,8 @@ export class StyledProcessor extends BaseProcessor {
styleArg: ExpressionValue | null,
variantsAccumulator?: VariantData[],
themeImportIdentifier?: string,
) {
const { themeArgs = {} } = this.options as IOptions;
): string {
const { themeArgs = {}, experiments = {} } = this.options as IOptions;
const styleObj = typeof styleObjOrFn === 'function' ? styleObjOrFn(themeArgs) : styleObjOrFn;
if (!styleObj) {
return '';
Expand All @@ -551,7 +552,15 @@ export class StyledProcessor extends BaseProcessor {
if (res.length) {
this.collectedVariables.push(...res);
}
return processCssObject(styleObj, themeArgs);
const cssText = processCssObject(styleObj, themeArgs);

if (experiments.styleLayers) {
if (variantsAccumulator) {
return `@layer pigment-base {${cssText}}`;
}
return `@layer pigment-variant {${cssText}}`;
}
return cssText;
}

public override get asSelector(): string {
Expand Down
7 changes: 7 additions & 0 deletions packages/pigment-css-react/src/utils/cssFnValueToVariable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ export type PluginCustomOptions = {
*/
getDirSelector?: (dir: 'ltr' | 'rtl') => string;
};
experiments?: {
/**
* Wrap generated CSS in layers so that all the base styles come before all the variant styles.
* Experimental right now, but will be default by v1 release.
*/
styleLayers?: boolean;
};
};

type CssFnValueToVariableParams = {
Expand Down
8 changes: 6 additions & 2 deletions packages/pigment-css-react/src/utils/generateCss.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { serializeStyles } from '@emotion/serialize';
import { Theme } from './extendTheme';
import { PluginCustomOptions } from './cssFnValueToVariable';

export function generateTokenCss(theme: Theme) {
export function generateTokenCss(
theme: Theme,
experiments: PluginCustomOptions['experiments'] = {},
) {
// use emotion to serialize the object to css string
const { styles } = serializeStyles(theme.generateStyleSheets?.() || []);
return styles;
return experiments.styleLayers ? `@layer pigment-base, pigment-variant;\n${styles}` : styles;
}

export function generateThemeTokens(theme: Theme) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { styled } from '@pigment-css/react';

const SliderRail = styled('span', {
name: 'MuiSlider',
slot: 'Rail',
})({
color: 'red',
variants: [
{
props: { color: 'primary' },
style: {
color: 'tomato',
},
},
{
props: ({ ownerState }) => ownerState.color === 'secondary',
style: {
color: 'salmon',
},
},
],
});

export const SliderOverride = styled(SliderRail)({
color: 'blue',
variants: [
{
props: { color: 'primary' },
style: {
color: 'indigo',
},
},
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@layer pigment-base, pigment-variant;
@layer pigment-base {
.srxh6zy {
color: red;
}
}
@layer pigment-variant {
.srxh6zy-1 {
color: tomato;
}
}
@layer pigment-variant {
.srxh6zy-2 {
color: salmon;
}
}
@layer pigment-base {
.srxh6zy-3 {
font-size: 1.5rem;
}
}
@layer pigment-base {
.s1q936we {
color: blue;
}
}
@layer pigment-variant {
.s1q936we-1 {
color: indigo;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { styled as _styled2 } from '@pigment-css/react';
import _theme2 from '@pigment-css/react/theme';
import { styled as _styled } from '@pigment-css/react';
import _theme from '@pigment-css/react/theme';
const SliderRail = /*#__PURE__*/ _styled('span', {
name: 'MuiSlider',
slot: 'Rail',
})({
classes: ['srxh6zy', 'srxh6zy-3'],
variants: [
{
props: {
color: 'primary',
},
className: 'srxh6zy-1',
},
{
props: ({ ownerState }) => ownerState.color === 'secondary',
className: 'srxh6zy-2',
},
],
});
const _exp3 = /*#__PURE__*/ () => SliderRail;
export const SliderOverride = /*#__PURE__*/ _styled2(_exp3())({
classes: ['s1q936we'],
variants: [
{
props: {
color: 'primary',
},
className: 's1q936we-1',
},
],
});
17 changes: 17 additions & 0 deletions packages/pigment-css-react/tests/styled/styled.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,23 @@ describe('Pigment CSS - styled', () => {
expect(output.css).to.equal(fixture.css);
});

it('should work with variants with layers enabled', async () => {
const { output, fixture } = await runTransformation(
path.join(__dirname, 'fixtures/styled-variants-layer.input.js'),
{
themeArgs: {
theme,
},
experiments: {
styleLayers: true,
},
},
);

expect(output.js).to.equal(fixture.js);
expect(output.css).to.equal(fixture.css);
});

it('should work with theme styleOverrides', async () => {
const { output, fixture } = await runTransformation(
path.join(__dirname, 'fixtures/styled-theme-styleOverrides.input.js'),
Expand Down
16 changes: 7 additions & 9 deletions packages/pigment-css-react/tests/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
transform as wywTransform,
createFileReporter,
} from '@wyw-in-js/transform';
import { PluginCustomOptions, preprocessor } from '@pigment-css/react/utils';
import { PluginCustomOptions, preprocessor, generateTokenCss } from '@pigment-css/react/utils';
import * as prettier from 'prettier';

import sxTransformPlugin from '../exports/sx-plugin';
Expand All @@ -24,10 +24,7 @@ function runSxTransform(code: string, filename: string) {
});
}

export async function runTransformation(
absolutePath: string,
options?: { themeArgs?: { theme?: any }; css?: PluginCustomOptions['css'] },
) {
export async function runTransformation(absolutePath: string, options?: PluginCustomOptions) {
const cache = new TransformCacheCollection();
const { emitter: eventEmitter } = createFileReporter(false);
const inputFilePath = absolutePath;
Expand All @@ -43,9 +40,7 @@ export async function runTransformation(
const babelResult = await runSxTransform(inputContent, inputFilePath);

const pluginOptions = {
themeArgs: {
theme: options?.themeArgs?.theme,
},
...options,
babelOptions: {
configFile: false,
babelrc: false,
Expand Down Expand Up @@ -80,7 +75,10 @@ export async function runTransformation(
...prettierConfig,
parser: 'babel',
});
const formattedCss = await prettier.format(result.cssText ?? '', {
const baseCss = generateTokenCss(options?.themeArgs?.theme ?? {}, options?.experiments);
const originalCss = baseCss + result.cssText ?? '';

const formattedCss = await prettier.format(originalCss, {
...prettierConfig,
parser: 'css',
});
Expand Down
4 changes: 2 additions & 2 deletions packages/pigment-css-unplugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ export const plugin = createUnplugin<PigmentOptions, true>((options) => {
},
transform(_code, id) {
if (id.endsWith('styles.css')) {
return theme ? generateTokenCss(theme) : _code;
return theme ? generateTokenCss(theme, options.experiments) : _code;
}
if (id.includes('pigment-css-react/theme')) {
return `export default ${
Expand All @@ -370,7 +370,7 @@ export const plugin = createUnplugin<PigmentOptions, true>((options) => {
},
load(id) {
if (id === VIRTUAL_CSS_FILE && theme) {
return generateTokenCss(theme);
return generateTokenCss(theme, options.experiments);
}
if (id === VIRTUAL_THEME_FILE) {
return `export default ${
Expand Down
2 changes: 1 addition & 1 deletion packages/pigment-css-vite-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function pigment(options: PigmentOptions) {
},
load(id) {
if (id === VIRTUAL_CSS_FILE) {
return generateTokenCss(theme);
return generateTokenCss(theme, options.experiments);
}
if (id === VIRTUAL_THEME_FILE) {
return `export default ${JSON.stringify(generateThemeTokens(theme))};`;
Expand Down
Loading

0 comments on commit e0ec514

Please sign in to comment.