From ee18b9030975391cf4abb785bebc8fdc2e657ee5 Mon Sep 17 00:00:00 2001 From: pvcresin Date: Thu, 20 Jul 2023 15:21:11 +0900 Subject: [PATCH 1/2] Add support for @layer --- packages/jss/src/plugins/index.js | 3 + packages/jss/src/plugins/index.js.flow | 3 + packages/jss/src/plugins/layerRule.js | 89 ++++++++++++++++++++++ packages/jss/src/plugins/layerRule.js.flow | 33 ++++++++ packages/jss/tests/integration/rules.js | 28 +++++++ 5 files changed, 156 insertions(+) create mode 100644 packages/jss/src/plugins/layerRule.js create mode 100644 packages/jss/src/plugins/layerRule.js.flow diff --git a/packages/jss/src/plugins/index.js b/packages/jss/src/plugins/index.js index 13d80e7aa..9bf76f9dd 100644 --- a/packages/jss/src/plugins/index.js +++ b/packages/jss/src/plugins/index.js @@ -2,6 +2,7 @@ import pluginStyleRule, {StyleRule} from './styleRule' import pluginConditionalRule, {ConditionalRule} from './conditionalRule' import pluginKeyframesRule, {KeyframesRule} from './keyframesRule' import pluginKeyframeRule, {KeyframeRule} from './keyframeRule' +import pluginLayerRule, {LayerRule} from './layerRule' import pluginFontFaceRule, {FontFaceRule} from './fontFaceRule' import pluginViewportRule, {ViewportRule} from './viewportRule' import pluginSimpleRule, {SimpleRule} from './simpleRule' @@ -11,6 +12,7 @@ export const plugins = [ pluginConditionalRule, pluginKeyframesRule, pluginKeyframeRule, + pluginLayerRule, pluginFontFaceRule, pluginViewportRule, pluginSimpleRule @@ -21,6 +23,7 @@ export { ConditionalRule, KeyframesRule, KeyframeRule, + LayerRule, FontFaceRule, ViewportRule, SimpleRule diff --git a/packages/jss/src/plugins/index.js.flow b/packages/jss/src/plugins/index.js.flow index 76e9c086d..703346e5b 100644 --- a/packages/jss/src/plugins/index.js.flow +++ b/packages/jss/src/plugins/index.js.flow @@ -3,6 +3,7 @@ import PluginStyleRule, {StyleRule} from './styleRule' import PluginConditionalRule, {ConditionalRule} from './conditionalRule' import PluginKeyframesRule, {KeyframesRule} from './keyframesRule' import PluginKeyframeRule, {KeyframeRule} from './keyframeRule' +import PluginLayerRule, {LayerRule} from './layerRule' import PluginFontFaceRule, {FontFaceRule} from './fontFaceRule' import PluginViewportRule, {ViewportRule} from './viewportRule' import PluginSimpleRule, {SimpleRule} from './simpleRule' @@ -12,6 +13,7 @@ export type plugins = [ typeof PluginConditionalRule, typeof PluginKeyframesRule, typeof PluginKeyframeRule, + typeof PluginLayerRule, typeof PluginFontFaceRule, typeof PluginViewportRule, typeof PluginSimpleRule @@ -22,6 +24,7 @@ declare export { ConditionalRule, KeyframesRule, KeyframeRule, + LayerRule, FontFaceRule, ViewportRule, SimpleRule diff --git a/packages/jss/src/plugins/layerRule.js b/packages/jss/src/plugins/layerRule.js new file mode 100644 index 000000000..d724277c1 --- /dev/null +++ b/packages/jss/src/plugins/layerRule.js @@ -0,0 +1,89 @@ +import RuleList from '../RuleList' +import getWhitespaceSymbols from '../utils/getWhitespaceSymbols' + +const defaultToStringOptions = { + indent: 1, + children: true +} + +const atRegExp = /@([\w-]+)/ + +/** + * Rule for @layer + */ +export class LayerRule { + type = 'layer' + + isProcessed = false + + constructor(key, styles, options) { + this.key = key + const atMatch = key.match(atRegExp) + this.at = atMatch ? atMatch[1] : 'unknown' + // Key might contain a unique suffix in case the `name` passed by user was duplicate. + this.query = options.name || `@${this.at}` + this.options = options + this.rules = new RuleList({...options, parent: this}) + + for (const name in styles) { + this.rules.add(name, styles[name]) + } + + this.rules.process() + } + + /** + * Get a rule. + */ + getRule(name) { + return this.rules.get(name) + } + + /** + * Get index of a rule. + */ + indexOf(rule) { + return this.rules.indexOf(rule) + } + + /** + * Create and register rule, run plugins. + */ + addRule(name, style, options) { + const rule = this.rules.add(name, style, options) + if (!rule) return null + this.options.jss.plugins.onProcessRule(rule) + return rule + } + + /** + * Replace rule, run plugins. + */ + replaceRule(name, style, options) { + const newRule = this.rules.replace(name, style, options) + if (newRule) this.options.jss.plugins.onProcessRule(newRule) + return newRule + } + + /** + * Generates a CSS string. + */ + toString(options = defaultToStringOptions) { + const {linebreak} = getWhitespaceSymbols(options) + if (options.indent == null) options.indent = defaultToStringOptions.indent + if (options.children == null) options.children = defaultToStringOptions.children + if (options.children === false) { + return `${this.query} {}` + } + const children = this.rules.toString(options) + return children ? `${this.query} {${linebreak}${children}${linebreak}}` : '' + } +} + +const keyRegExp = /@layer\s+/ + +export default { + onCreateRule(key, styles, options) { + return keyRegExp.test(key) ? new LayerRule(key, styles, options) : null + } +} diff --git a/packages/jss/src/plugins/layerRule.js.flow b/packages/jss/src/plugins/layerRule.js.flow new file mode 100644 index 000000000..d8d47ed2f --- /dev/null +++ b/packages/jss/src/plugins/layerRule.js.flow @@ -0,0 +1,33 @@ +// @flow +import RuleList from '../RuleList' +import type { + CSSMediaRule, + Rule, + RuleOptions, + ToCssOptions, + JssStyle, + // eslint doesn't understand usage with types + // eslint-disable-next-line no-unused-vars + ContainerRule +} from '../flow-types' + +declare export class LayerRule implements ContainerRule { + type: string; + at: string; + key: string; + query: string; + rules: RuleList; + options: RuleOptions; + isProcessed: boolean; + renderable: ?CSSMediaRule; + constructor(key: string, styles: Object, options: RuleOptions): this; + getRule(name: string): Rule; + indexOf(rule: Rule): number; + addRule(name: string, style: JssStyle, options?: RuleOptions): Rule | null; + replaceRule(name: string, style: JssStyle, options?: RuleOptions): Rule | null; + toString(options?: ToCssOptions): string; +} + +declare export default { + onCreateRule(key: string, styles: JssStyle, options: RuleOptions): LayerRule | null +} diff --git a/packages/jss/tests/integration/rules.js b/packages/jss/tests/integration/rules.js index 2a0cb2bfd..01af6ba75 100644 --- a/packages/jss/tests/integration/rules.js +++ b/packages/jss/tests/integration/rules.js @@ -206,6 +206,34 @@ describe('Integration: rules', () => { `) }) + describe('@layer rule', () => { + it('should return CSS', () => { + const rule = jss.createRule('@layer test', { + button: { + color: 'red' + } + }) + expect(rule.type).to.be('layer') + expect(rule.key).to.be('@layer test') + expect(rule.toString()).to.be(stripIndent` + @layer test { + .button-id { + color: red; + } + } + `) + }) + + it('should return CSS without empty rule', () => { + const rule = jss.createRule('@layer test', { + button: {} + }) + expect(rule.type).to.be('layer') + expect(rule.key).to.be('@layer test') + expect(rule.toString()).to.be('') + }) + }) + describe('@media rule', () => { it('should return CSS', () => { const rule = jss.createRule('@media print', {a: {display: 'none'}}) From 06bb2b14fe94a01150f1b324adf7b3fdbe248658 Mon Sep 17 00:00:00 2001 From: pvcresin Date: Tue, 25 Jul 2023 18:37:39 +0900 Subject: [PATCH 2/2] Update size-snapshot --- packages/jss/.size-snapshot.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/jss/.size-snapshot.json b/packages/jss/.size-snapshot.json index 596f44ccf..042960353 100644 --- a/packages/jss/.size-snapshot.json +++ b/packages/jss/.size-snapshot.json @@ -1,30 +1,30 @@ { "jss.js": { - "bundled": 64943, - "minified": 23190, - "gzipped": 7213 + "bundled": 67593, + "minified": 24213, + "gzipped": 7280 }, "jss.min.js": { - "bundled": 63547, - "minified": 22421, - "gzipped": 6867 + "bundled": 66197, + "minified": 23445, + "gzipped": 6945 }, "jss.cjs.js": { - "bundled": 60631, - "minified": 26218, - "gzipped": 7331 + "bundled": 63129, + "minified": 27446, + "gzipped": 7413 }, "jss.esm.js": { - "bundled": 59003, - "minified": 24912, - "gzipped": 7165, + "bundled": 61481, + "minified": 26123, + "gzipped": 7251, "treeshaked": { "rollup": { - "code": 20176, + "code": 21197, "import_statements": 345 }, "webpack": { - "code": 21666 + "code": 22685 } } }