@vanilla-extract/css
Advanced tools
Comparing version 0.1.0 to 0.2.0
# @vanilla-extract/css | ||
## 0.2.0 | ||
### Minor Changes | ||
- [#20](https://github.com/seek-oss/vanilla-extract/pull/20) [`3311914`](https://github.com/seek-oss/vanilla-extract/commit/3311914d92406cda5d5bb71ee72075501f868bd5) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Ensure generated hashes are scoped by package | ||
vanilla-extract uses file path to ensure unique identifier (e.g. class names, CSS Variables, keyframes, etc) hashes across your application. This information is added to your `*.css.ts` files at build time. The issue with this approach is it meant `*.css.ts` files couldn't be pre-compiled when being published to npm. | ||
This change adds support for pre-compilation of packages by adding package name information to identifier hashes. | ||
* [#25](https://github.com/seek-oss/vanilla-extract/pull/25) [`c4bedd5`](https://github.com/seek-oss/vanilla-extract/commit/c4bedd571f0c21291b58e050589b4db9465c0460) Thanks [@markdalgleish](https://github.com/markdalgleish)! - The `createInlineTheme` function has now moved to the `@vanilla-extract/dynamic` package. | ||
```diff | ||
-import { createInlineTheme } from '@vanilla-extract/css/createInlineTheme'; | ||
+import { createInlineTheme } from '@vanilla-extract/dynamic'; | ||
``` | ||
## 0.1.0 | ||
### Minor Changes | ||
- e83ad50: Initial release |
@@ -1,4 +0,5 @@ | ||
export declare function setFileScope(newFileScope: string): void; | ||
import type { FileScope } from './types'; | ||
export declare function setFileScope(filePath: string, packageName?: string): void; | ||
export declare function endFileScope(): void; | ||
export declare function getFileScope(): string; | ||
export declare function getFileScope(): FileScope; | ||
export declare function getAndIncrementRefCounter(): number; |
import './runtimeAdapter'; | ||
export type { StyleRule, GlobalStyleRule, Adapter } from './types'; | ||
export type { StyleRule, GlobalStyleRule, Adapter, FileScope } from './types'; | ||
export * from './identifier'; | ||
@@ -4,0 +4,0 @@ export * from './theme'; |
@@ -1,2 +0,3 @@ | ||
import type { Contract, MapLeafNodes, ThemeVars, Tokens } from './types'; | ||
import type { Contract, MapLeafNodes } from '@vanilla-extract/private'; | ||
import type { ThemeVars, Tokens } from './types'; | ||
export declare function createGlobalTheme<ThemeTokens extends Tokens>(selector: string, tokens: ThemeTokens): ThemeVars<ThemeTokens>; | ||
@@ -3,0 +4,0 @@ export declare function createGlobalTheme<ThemeContract extends Contract>(selector: string, themeContract: ThemeContract, tokens: ThemeVars<ThemeContract>): void; |
@@ -0,3 +1,4 @@ | ||
import type { Contract, MapLeafNodes } from '@vanilla-extract/private'; | ||
import type { PropertiesFallback, AtRule } from 'csstype'; | ||
import type { SimplePseudos } from './transformCSS'; | ||
import type { SimplePseudos } from './transformCss'; | ||
declare type BasicCSSProperties = PropertiesFallback<string | number>; | ||
@@ -56,17 +57,15 @@ export interface CSSKeyframes { | ||
export declare type CSS = CSSStyleBlock | CSSFontFaceBlock | CSSKeyframesBlock | CSSSelectorBlock; | ||
export declare type FileScope = { | ||
packageName?: string; | ||
filePath: string; | ||
}; | ||
export interface Adapter { | ||
appendCss: (css: CSS, fileScope: string) => void; | ||
appendCss: (css: CSS, fileScope: FileScope) => void; | ||
registerClassName: (className: string) => void; | ||
onEndFileScope: (fileScope: string) => void; | ||
onEndFileScope: (fileScope: FileScope) => void; | ||
} | ||
export declare type Contract = { | ||
[key: string]: string | null | Contract; | ||
}; | ||
export declare type Tokens = { | ||
[key: string]: string | Tokens; | ||
}; | ||
export declare type MapLeafNodes<Obj, LeafType> = { | ||
[Prop in keyof Obj]: Obj[Prop] extends Record<string | number, any> ? MapLeafNodes<Obj[Prop], LeafType> : LeafType; | ||
}; | ||
export declare type ThemeVars<ThemeContract extends Contract> = MapLeafNodes<ThemeContract, string>; | ||
export {}; |
@@ -1,11 +0,8 @@ | ||
import { MapLeafNodes } from './types'; | ||
declare type BasicObj = { | ||
[key: string]: any; | ||
}; | ||
export declare function get(obj: any, path: Array<string>): any; | ||
export declare function forEach<Input extends BasicObj>(obj: Input | undefined, fn: <Key extends keyof Input>(value: Input[Key], key: string) => void): void; | ||
export declare function omit<Input extends BasicObj, OmitKey extends string>(obj: Input | undefined, omitKeys: Array<OmitKey>): Omit<Input, OmitKey>; | ||
export declare function mapKeys<Input extends BasicObj>(obj: Input | undefined, fn: <Key extends keyof Input>(value: Input[Key], key: string) => string): Record<string, Input[keyof Input]>; | ||
export declare function walkObject<T, MapTo>(obj: T, fn: (value: string | number, path: Array<string>) => MapTo, path?: Array<string>): MapLeafNodes<T, MapTo>; | ||
export declare function isEqual(a: any, b: any): boolean; | ||
export {}; |
@@ -1,2 +0,2 @@ | ||
import type { Contract, MapLeafNodes } from './types'; | ||
import { Contract, MapLeafNodes } from '@vanilla-extract/private'; | ||
declare type ThemeVars<ThemeContract extends Contract> = MapLeafNodes<ThemeContract, string>; | ||
@@ -3,0 +3,0 @@ export declare function createVar(debugId?: string): string; |
@@ -5,8 +5,8 @@ 'use strict'; | ||
var cssesc = require('cssesc'); | ||
var validateSelector = require('./validateSelector-a9e44540.browser.cjs.js'); | ||
var utils = require('./utils-03507b0d.browser.cjs.js'); | ||
var transformCss_dist_vanillaExtractCssTransformCss = require('../transformCss/dist/vanilla-extract-css-transformCss.browser.cjs.js'); | ||
var adapter_dist_vanillaExtractCssAdapter = require('../adapter/dist/vanilla-extract-css-adapter.browser.cjs.js'); | ||
var hash = require('@emotion/hash'); | ||
var fileScope_dist_vanillaExtractCssFileScope = require('../fileScope/dist/vanilla-extract-css-fileScope.browser.cjs.js'); | ||
var _private = require('@vanilla-extract/private'); | ||
var cssesc = require('cssesc'); | ||
var dedent = require('dedent'); | ||
@@ -17,291 +17,6 @@ require('css-selector-parser'); | ||
var hash__default = /*#__PURE__*/_interopDefault(hash); | ||
var cssesc__default = /*#__PURE__*/_interopDefault(cssesc); | ||
var hash__default = /*#__PURE__*/_interopDefault(hash); | ||
var dedent__default = /*#__PURE__*/_interopDefault(dedent); | ||
const UNITLESS = { | ||
boxFlex: true, | ||
boxFlexGroup: true, | ||
columnCount: true, | ||
flex: true, | ||
flexGrow: true, | ||
flexPositive: true, | ||
flexShrink: true, | ||
flexNegative: true, | ||
fontWeight: true, | ||
lineClamp: true, | ||
lineHeight: true, | ||
opacity: true, | ||
order: true, | ||
orphans: true, | ||
tabSize: true, | ||
widows: true, | ||
zIndex: true, | ||
zoom: true, | ||
fillOpacity: true, | ||
strokeDashoffset: true, | ||
strokeOpacity: true, | ||
strokeWidth: true | ||
}; | ||
const simplePseudos = [':-moz-any-link', ':-moz-full-screen', ':-moz-placeholder', ':-moz-read-only', ':-moz-read-write', ':-ms-fullscreen', ':-ms-input-placeholder', ':-webkit-any-link', ':-webkit-full-screen', '::-moz-placeholder', '::-moz-progress-bar', '::-moz-range-progress', '::-moz-range-thumb', '::-moz-range-track', '::-moz-selection', '::-ms-backdrop', '::-ms-browse', '::-ms-check', '::-ms-clear', '::-ms-fill', '::-ms-fill-lower', '::-ms-fill-upper', '::-ms-reveal', '::-ms-thumb', '::-ms-ticks-after', '::-ms-ticks-before', '::-ms-tooltip', '::-ms-track', '::-ms-value', '::-webkit-backdrop', '::-webkit-input-placeholder', '::-webkit-progress-bar', '::-webkit-progress-inner-value', '::-webkit-progress-value', '::-webkit-slider-runnable-track', '::-webkit-slider-thumb', '::after', '::backdrop', '::before', '::cue', '::first-letter', '::first-line', '::grammar-error', '::placeholder', '::selection', '::spelling-error', ':active', ':after', ':any-link', ':before', ':blank', ':checked', ':default', ':defined', ':disabled', ':empty', ':enabled', ':first', ':first-child', ':first-letter', ':first-line', ':first-of-type', ':focus', ':focus-visible', ':focus-within', ':fullscreen', ':hover', ':in-range', ':indeterminate', ':invalid', ':last-child', ':last-of-type', ':left', ':link', ':only-child', ':only-of-type', ':optional', ':out-of-range', ':placeholder-shown', ':read-only', ':read-write', ':required', ':right', ':root', ':scope', ':target', ':valid', ':visited']; | ||
function dashify(str) { | ||
return str.replace(/([A-Z])/g, '-$1').replace(/^ms-/, '-ms-').toLowerCase(); | ||
} | ||
const DOUBLE_SPACE = ' '; | ||
const simplePseudoSet = new Set(simplePseudos); | ||
const specialKeys = [...simplePseudos, '@media', '@supports', 'selectors']; | ||
class Stylesheet { | ||
constructor(localClassNames) { | ||
this.rules = []; | ||
this.conditionalRules = []; | ||
this.fontFaceRules = []; | ||
this.keyframesRules = []; | ||
this.localClassNameRegex = localClassNames.length > 0 ? RegExp(`(${localClassNames.join('|')})`, 'g') : null; | ||
} | ||
processCssObj(root) { | ||
if (root.type === 'fontFace') { | ||
this.fontFaceRules.push(root.rule); | ||
return; | ||
} | ||
if (root.type === 'keyframes') { | ||
this.keyframesRules.push(root); | ||
return; | ||
} // Add main styles | ||
const mainRule = utils.omit(root.rule, specialKeys); | ||
this.addRule({ | ||
selector: root.selector, | ||
rule: mainRule | ||
}); | ||
this.transformSimplePsuedos(root, root.rule); | ||
this.transformMedia(root, root.rule['@media']); | ||
this.transformSupports(root, root.rule['@supports']); | ||
this.transformSelectors(root, root.rule); | ||
} | ||
addRule(cssRule) { | ||
// Run `pixelifyProperties` before `transformVars` as we don't want to pixelify CSS Vars | ||
const rule = this.transformVars(this.pixelifyProperties(cssRule.rule)); | ||
const selector = this.transformSelector(cssRule.selector); | ||
if (cssRule.conditions) { | ||
this.conditionalRules.push({ | ||
selector, | ||
rule, | ||
conditions: cssRule.conditions.sort() | ||
}); | ||
} else { | ||
this.rules.push({ | ||
selector, | ||
rule | ||
}); | ||
} | ||
} | ||
pixelifyProperties(cssRule) { | ||
utils.forEach(cssRule, (value, key) => { | ||
if (typeof value === 'number' && value !== 0 && !UNITLESS[key]) { | ||
// @ts-expect-error Any ideas? | ||
cssRule[key] = `${value}px`; | ||
} | ||
}); | ||
return cssRule; | ||
} | ||
transformVars({ | ||
vars, | ||
...rest | ||
}) { | ||
if (!vars) { | ||
return rest; | ||
} | ||
return { ...utils.mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
...rest | ||
}; | ||
} | ||
transformSelector(selector) { | ||
return this.localClassNameRegex ? selector.replace(this.localClassNameRegex, (_, className, index) => { | ||
if (index > 0 && selector[index - 1] === '.') { | ||
return className; | ||
} | ||
return `.${cssesc__default['default'](className, { | ||
isIdentifier: true | ||
})}`; | ||
}) : selector; | ||
} | ||
transformSelectors(root, rule, conditions) { | ||
utils.forEach(rule.selectors, (selectorRule, selector) => { | ||
if (root.type !== 'local') { | ||
throw new Error(`Selectors are not allowed within ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
const transformedSelector = this.transformSelector(selector.replace(RegExp('&', 'g'), root.selector)); | ||
validateSelector.validateSelector(transformedSelector, root.selector); | ||
this.addRule({ | ||
conditions, | ||
selector: transformedSelector, | ||
rule: utils.omit(selectorRule, specialKeys) | ||
}); | ||
const selectorRoot = { | ||
type: 'selector', | ||
selector: transformedSelector, | ||
rule: selectorRule | ||
}; | ||
this.transformSupports(selectorRoot, selectorRule['@supports'], conditions); | ||
this.transformMedia(selectorRoot, selectorRule['@media'], conditions); | ||
}); | ||
} | ||
transformMedia(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (mediaRule, query) => { | ||
const conditions = [`@media ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: utils.omit(mediaRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, mediaRule, conditions); | ||
this.transformSelectors(root, mediaRule, conditions); | ||
} | ||
this.transformSupports(root, mediaRule['@supports'], conditions); | ||
}); | ||
} | ||
transformSupports(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (supportsRule, query) => { | ||
const conditions = [`@supports ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: utils.omit(supportsRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, supportsRule, conditions); | ||
this.transformSelectors(root, supportsRule, conditions); | ||
} | ||
this.transformMedia(root, supportsRule['@media'], conditions); | ||
}); | ||
} | ||
transformSimplePsuedos(root, rule, conditions) { | ||
for (const key of Object.keys(rule)) { | ||
// Process simple psuedos | ||
if (simplePseudoSet.has(key)) { | ||
if (root.type !== 'local') { | ||
throw new Error(`Simple pseudos are not valid in ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
this.addRule({ | ||
conditions, | ||
selector: `${root.selector}${key}`, | ||
rule: rule[key] | ||
}); | ||
} | ||
} | ||
} | ||
toPostcssJs() { | ||
const styles = {}; | ||
if (this.fontFaceRules.length > 0) { | ||
styles['@font-face'] = this.fontFaceRules; | ||
} | ||
this.keyframesRules.forEach(rule => { | ||
styles[`@keyframes ${rule.name}`] = rule.rule; | ||
}); | ||
for (const rule of [...this.rules, ...this.conditionalRules]) { | ||
if (rule.conditions && utils.isEqual(styles[rule.selector], rule.rule)) { | ||
// Ignore conditional rules if they are identical to a non-conditional rule | ||
continue; | ||
} | ||
if (Object.keys(rule.rule).length === 0) { | ||
// Ignore empty rules | ||
continue; | ||
} | ||
let styleNode = styles; | ||
for (const condition of rule.conditions || []) { | ||
if (!styleNode[condition]) { | ||
styleNode[condition] = {}; | ||
} | ||
styleNode = styleNode[condition]; | ||
} | ||
styleNode[rule.selector] = { ...styleNode[rule.selector], | ||
...rule.rule | ||
}; | ||
} | ||
return styles; | ||
} | ||
toCss() { | ||
const styles = this.toPostcssJs(); | ||
function walkCss(v, indent = '') { | ||
const rules = []; | ||
for (const key of Object.keys(v)) { | ||
const value = v[key]; | ||
if (value && Array.isArray(value)) { | ||
rules.push(...value.map(v => walkCss({ | ||
[key]: v | ||
}, indent).join('\n'))); | ||
} else if (value && typeof value === 'object') { | ||
rules.push(`${indent}${key} {\n${walkCss(value, indent + DOUBLE_SPACE).join('\n')}\n${indent}}`); | ||
} else { | ||
rules.push(`${indent}${key.startsWith('--') ? key : dashify(key)}: ${value};`); | ||
} | ||
} | ||
return rules; | ||
} | ||
return walkCss(styles); | ||
} | ||
} | ||
function transformCss({ | ||
localClassNames, | ||
cssObjs | ||
}) { | ||
const stylesheet = new Stylesheet(localClassNames); | ||
for (const root of cssObjs) { | ||
stylesheet.processCssObj(root); | ||
} | ||
return stylesheet.toCss(); | ||
} | ||
const stylesheets = {}; | ||
@@ -311,5 +26,10 @@ const localClassNames = new Set(); | ||
function getStylesheet(fileScope) { | ||
if (stylesheets[fileScope]) { | ||
return stylesheets[fileScope]; | ||
function getStylesheet({ | ||
packageName, | ||
filePath | ||
}) { | ||
const fileScopeId = packageName ? `${packageName}${filePath}` : filePath; | ||
if (stylesheets[fileScopeId]) { | ||
return stylesheets[fileScopeId]; | ||
} | ||
@@ -324,3 +44,3 @@ | ||
stylesheets[fileScope] = styleEl.sheet; | ||
stylesheets[fileScopeId] = styleEl.sheet; | ||
return styleEl.sheet; | ||
@@ -337,3 +57,3 @@ } | ||
onEndFileScope: fileScope => { | ||
const css = transformCss({ | ||
const css = transformCss_dist_vanillaExtractCssTransformCss.transformCss({ | ||
localClassNames: Array.from(localClassNames), | ||
@@ -374,4 +94,6 @@ cssObjs: bufferedCSSObjs | ||
function getShortFileName() { | ||
const fileScope = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const matches = fileScope.match(/.*\/(.*)\..*\..*$/); | ||
const { | ||
filePath | ||
} = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const matches = filePath.match(/.*\/(.*)\..*\..*$/); | ||
@@ -387,3 +109,8 @@ if (matches && matches[1]) { | ||
const refCount = fileScope_dist_vanillaExtractCssFileScope.getAndIncrementRefCounter(); | ||
const identifier = process.env.NODE_ENV !== 'production' && debugId ? `${getShortFileName()}_${debugId}__${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}` : `${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}`; | ||
const { | ||
filePath, | ||
packageName | ||
} = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const fileScopeHash = hash__default['default'](packageName ? `${packageName}${filePath}` : filePath); | ||
const identifier = process.env.NODE_ENV !== 'production' && debugId ? `${getShortFileName()}_${debugId}__${fileScopeHash}${refCount}` : `${fileScopeHash}${refCount}`; | ||
return identifier.match(/^[0-9]/) ? `_${identifier}` : identifier; | ||
@@ -394,3 +121,8 @@ } | ||
const refCount = fileScope_dist_vanillaExtractCssFileScope.getAndIncrementRefCounter(); | ||
const varName = process.env.NODE_ENV !== 'production' && debugId ? `${debugId}__${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}` : `${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
const { | ||
filePath, | ||
packageName | ||
} = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const fileScopeHash = hash__default['default'](packageName ? `${packageName}${filePath}` : filePath); | ||
const varName = process.env.NODE_ENV !== 'production' && debugId ? `${debugId}__${fileScopeHash}${refCount}` : `${fileScopeHash}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
// See https://github.com/postcss/postcss-js/blob/d5127d4278c133f333f1c66f990f3552a907128e/parser.js#L30 | ||
@@ -425,4 +157,4 @@ | ||
utils.walkObject(tokens, (value, path) => { | ||
varSetters[utils.get(varContract, path)] = String(value); | ||
_private.walkObject(tokens, (value, path) => { | ||
varSetters[_private.get(varContract, path)] = String(value); | ||
}); | ||
@@ -432,3 +164,3 @@ return varSetters; | ||
function createThemeVars(themeContract) { | ||
return utils.walkObject(themeContract, (_value, path) => { | ||
return _private.walkObject(themeContract, (_value, path) => { | ||
return createVar(path.join('-')); | ||
@@ -435,0 +167,0 @@ }); |
@@ -1,295 +0,10 @@ | ||
import cssesc from 'cssesc'; | ||
import { v as validateSelector } from './validateSelector-2dda5781.browser.esm.js'; | ||
import { o as omit, f as forEach, m as mapKeys, i as isEqual, w as walkObject, g as get } from './utils-24d5030c.browser.esm.js'; | ||
import { transformCss } from '../transformCss/dist/vanilla-extract-css-transformCss.browser.esm.js'; | ||
import { setAdapter, appendCss, registerClassName } from '../adapter/dist/vanilla-extract-css-adapter.browser.esm.js'; | ||
import hash from '@emotion/hash'; | ||
import { getAndIncrementRefCounter, getFileScope } from '../fileScope/dist/vanilla-extract-css-fileScope.browser.esm.js'; | ||
import { walkObject, get } from '@vanilla-extract/private'; | ||
import cssesc from 'cssesc'; | ||
import dedent from 'dedent'; | ||
import 'css-selector-parser'; | ||
const UNITLESS = { | ||
boxFlex: true, | ||
boxFlexGroup: true, | ||
columnCount: true, | ||
flex: true, | ||
flexGrow: true, | ||
flexPositive: true, | ||
flexShrink: true, | ||
flexNegative: true, | ||
fontWeight: true, | ||
lineClamp: true, | ||
lineHeight: true, | ||
opacity: true, | ||
order: true, | ||
orphans: true, | ||
tabSize: true, | ||
widows: true, | ||
zIndex: true, | ||
zoom: true, | ||
fillOpacity: true, | ||
strokeDashoffset: true, | ||
strokeOpacity: true, | ||
strokeWidth: true | ||
}; | ||
const simplePseudos = [':-moz-any-link', ':-moz-full-screen', ':-moz-placeholder', ':-moz-read-only', ':-moz-read-write', ':-ms-fullscreen', ':-ms-input-placeholder', ':-webkit-any-link', ':-webkit-full-screen', '::-moz-placeholder', '::-moz-progress-bar', '::-moz-range-progress', '::-moz-range-thumb', '::-moz-range-track', '::-moz-selection', '::-ms-backdrop', '::-ms-browse', '::-ms-check', '::-ms-clear', '::-ms-fill', '::-ms-fill-lower', '::-ms-fill-upper', '::-ms-reveal', '::-ms-thumb', '::-ms-ticks-after', '::-ms-ticks-before', '::-ms-tooltip', '::-ms-track', '::-ms-value', '::-webkit-backdrop', '::-webkit-input-placeholder', '::-webkit-progress-bar', '::-webkit-progress-inner-value', '::-webkit-progress-value', '::-webkit-slider-runnable-track', '::-webkit-slider-thumb', '::after', '::backdrop', '::before', '::cue', '::first-letter', '::first-line', '::grammar-error', '::placeholder', '::selection', '::spelling-error', ':active', ':after', ':any-link', ':before', ':blank', ':checked', ':default', ':defined', ':disabled', ':empty', ':enabled', ':first', ':first-child', ':first-letter', ':first-line', ':first-of-type', ':focus', ':focus-visible', ':focus-within', ':fullscreen', ':hover', ':in-range', ':indeterminate', ':invalid', ':last-child', ':last-of-type', ':left', ':link', ':only-child', ':only-of-type', ':optional', ':out-of-range', ':placeholder-shown', ':read-only', ':read-write', ':required', ':right', ':root', ':scope', ':target', ':valid', ':visited']; | ||
function dashify(str) { | ||
return str.replace(/([A-Z])/g, '-$1').replace(/^ms-/, '-ms-').toLowerCase(); | ||
} | ||
const DOUBLE_SPACE = ' '; | ||
const simplePseudoSet = new Set(simplePseudos); | ||
const specialKeys = [...simplePseudos, '@media', '@supports', 'selectors']; | ||
class Stylesheet { | ||
constructor(localClassNames) { | ||
this.rules = []; | ||
this.conditionalRules = []; | ||
this.fontFaceRules = []; | ||
this.keyframesRules = []; | ||
this.localClassNameRegex = localClassNames.length > 0 ? RegExp(`(${localClassNames.join('|')})`, 'g') : null; | ||
} | ||
processCssObj(root) { | ||
if (root.type === 'fontFace') { | ||
this.fontFaceRules.push(root.rule); | ||
return; | ||
} | ||
if (root.type === 'keyframes') { | ||
this.keyframesRules.push(root); | ||
return; | ||
} // Add main styles | ||
const mainRule = omit(root.rule, specialKeys); | ||
this.addRule({ | ||
selector: root.selector, | ||
rule: mainRule | ||
}); | ||
this.transformSimplePsuedos(root, root.rule); | ||
this.transformMedia(root, root.rule['@media']); | ||
this.transformSupports(root, root.rule['@supports']); | ||
this.transformSelectors(root, root.rule); | ||
} | ||
addRule(cssRule) { | ||
// Run `pixelifyProperties` before `transformVars` as we don't want to pixelify CSS Vars | ||
const rule = this.transformVars(this.pixelifyProperties(cssRule.rule)); | ||
const selector = this.transformSelector(cssRule.selector); | ||
if (cssRule.conditions) { | ||
this.conditionalRules.push({ | ||
selector, | ||
rule, | ||
conditions: cssRule.conditions.sort() | ||
}); | ||
} else { | ||
this.rules.push({ | ||
selector, | ||
rule | ||
}); | ||
} | ||
} | ||
pixelifyProperties(cssRule) { | ||
forEach(cssRule, (value, key) => { | ||
if (typeof value === 'number' && value !== 0 && !UNITLESS[key]) { | ||
// @ts-expect-error Any ideas? | ||
cssRule[key] = `${value}px`; | ||
} | ||
}); | ||
return cssRule; | ||
} | ||
transformVars({ | ||
vars, | ||
...rest | ||
}) { | ||
if (!vars) { | ||
return rest; | ||
} | ||
return { ...mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
...rest | ||
}; | ||
} | ||
transformSelector(selector) { | ||
return this.localClassNameRegex ? selector.replace(this.localClassNameRegex, (_, className, index) => { | ||
if (index > 0 && selector[index - 1] === '.') { | ||
return className; | ||
} | ||
return `.${cssesc(className, { | ||
isIdentifier: true | ||
})}`; | ||
}) : selector; | ||
} | ||
transformSelectors(root, rule, conditions) { | ||
forEach(rule.selectors, (selectorRule, selector) => { | ||
if (root.type !== 'local') { | ||
throw new Error(`Selectors are not allowed within ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
const transformedSelector = this.transformSelector(selector.replace(RegExp('&', 'g'), root.selector)); | ||
validateSelector(transformedSelector, root.selector); | ||
this.addRule({ | ||
conditions, | ||
selector: transformedSelector, | ||
rule: omit(selectorRule, specialKeys) | ||
}); | ||
const selectorRoot = { | ||
type: 'selector', | ||
selector: transformedSelector, | ||
rule: selectorRule | ||
}; | ||
this.transformSupports(selectorRoot, selectorRule['@supports'], conditions); | ||
this.transformMedia(selectorRoot, selectorRule['@media'], conditions); | ||
}); | ||
} | ||
transformMedia(root, rules, parentConditions = []) { | ||
forEach(rules, (mediaRule, query) => { | ||
const conditions = [`@media ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: omit(mediaRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, mediaRule, conditions); | ||
this.transformSelectors(root, mediaRule, conditions); | ||
} | ||
this.transformSupports(root, mediaRule['@supports'], conditions); | ||
}); | ||
} | ||
transformSupports(root, rules, parentConditions = []) { | ||
forEach(rules, (supportsRule, query) => { | ||
const conditions = [`@supports ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: omit(supportsRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, supportsRule, conditions); | ||
this.transformSelectors(root, supportsRule, conditions); | ||
} | ||
this.transformMedia(root, supportsRule['@media'], conditions); | ||
}); | ||
} | ||
transformSimplePsuedos(root, rule, conditions) { | ||
for (const key of Object.keys(rule)) { | ||
// Process simple psuedos | ||
if (simplePseudoSet.has(key)) { | ||
if (root.type !== 'local') { | ||
throw new Error(`Simple pseudos are not valid in ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
this.addRule({ | ||
conditions, | ||
selector: `${root.selector}${key}`, | ||
rule: rule[key] | ||
}); | ||
} | ||
} | ||
} | ||
toPostcssJs() { | ||
const styles = {}; | ||
if (this.fontFaceRules.length > 0) { | ||
styles['@font-face'] = this.fontFaceRules; | ||
} | ||
this.keyframesRules.forEach(rule => { | ||
styles[`@keyframes ${rule.name}`] = rule.rule; | ||
}); | ||
for (const rule of [...this.rules, ...this.conditionalRules]) { | ||
if (rule.conditions && isEqual(styles[rule.selector], rule.rule)) { | ||
// Ignore conditional rules if they are identical to a non-conditional rule | ||
continue; | ||
} | ||
if (Object.keys(rule.rule).length === 0) { | ||
// Ignore empty rules | ||
continue; | ||
} | ||
let styleNode = styles; | ||
for (const condition of rule.conditions || []) { | ||
if (!styleNode[condition]) { | ||
styleNode[condition] = {}; | ||
} | ||
styleNode = styleNode[condition]; | ||
} | ||
styleNode[rule.selector] = { ...styleNode[rule.selector], | ||
...rule.rule | ||
}; | ||
} | ||
return styles; | ||
} | ||
toCss() { | ||
const styles = this.toPostcssJs(); | ||
function walkCss(v, indent = '') { | ||
const rules = []; | ||
for (const key of Object.keys(v)) { | ||
const value = v[key]; | ||
if (value && Array.isArray(value)) { | ||
rules.push(...value.map(v => walkCss({ | ||
[key]: v | ||
}, indent).join('\n'))); | ||
} else if (value && typeof value === 'object') { | ||
rules.push(`${indent}${key} {\n${walkCss(value, indent + DOUBLE_SPACE).join('\n')}\n${indent}}`); | ||
} else { | ||
rules.push(`${indent}${key.startsWith('--') ? key : dashify(key)}: ${value};`); | ||
} | ||
} | ||
return rules; | ||
} | ||
return walkCss(styles); | ||
} | ||
} | ||
function transformCss({ | ||
localClassNames, | ||
cssObjs | ||
}) { | ||
const stylesheet = new Stylesheet(localClassNames); | ||
for (const root of cssObjs) { | ||
stylesheet.processCssObj(root); | ||
} | ||
return stylesheet.toCss(); | ||
} | ||
const stylesheets = {}; | ||
@@ -299,5 +14,10 @@ const localClassNames = new Set(); | ||
function getStylesheet(fileScope) { | ||
if (stylesheets[fileScope]) { | ||
return stylesheets[fileScope]; | ||
function getStylesheet({ | ||
packageName, | ||
filePath | ||
}) { | ||
const fileScopeId = packageName ? `${packageName}${filePath}` : filePath; | ||
if (stylesheets[fileScopeId]) { | ||
return stylesheets[fileScopeId]; | ||
} | ||
@@ -312,3 +32,3 @@ | ||
stylesheets[fileScope] = styleEl.sheet; | ||
stylesheets[fileScopeId] = styleEl.sheet; | ||
return styleEl.sheet; | ||
@@ -361,4 +81,6 @@ } | ||
function getShortFileName() { | ||
const fileScope = getFileScope(); | ||
const matches = fileScope.match(/.*\/(.*)\..*\..*$/); | ||
const { | ||
filePath | ||
} = getFileScope(); | ||
const matches = filePath.match(/.*\/(.*)\..*\..*$/); | ||
@@ -374,3 +96,8 @@ if (matches && matches[1]) { | ||
const refCount = getAndIncrementRefCounter(); | ||
const identifier = process.env.NODE_ENV !== 'production' && debugId ? `${getShortFileName()}_${debugId}__${hash(getFileScope())}${refCount}` : `${hash(getFileScope())}${refCount}`; | ||
const { | ||
filePath, | ||
packageName | ||
} = getFileScope(); | ||
const fileScopeHash = hash(packageName ? `${packageName}${filePath}` : filePath); | ||
const identifier = process.env.NODE_ENV !== 'production' && debugId ? `${getShortFileName()}_${debugId}__${fileScopeHash}${refCount}` : `${fileScopeHash}${refCount}`; | ||
return identifier.match(/^[0-9]/) ? `_${identifier}` : identifier; | ||
@@ -381,3 +108,8 @@ } | ||
const refCount = getAndIncrementRefCounter(); | ||
const varName = process.env.NODE_ENV !== 'production' && debugId ? `${debugId}__${hash(getFileScope())}${refCount}` : `${hash(getFileScope())}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
const { | ||
filePath, | ||
packageName | ||
} = getFileScope(); | ||
const fileScopeHash = hash(packageName ? `${packageName}${filePath}` : filePath); | ||
const varName = process.env.NODE_ENV !== 'production' && debugId ? `${debugId}__${fileScopeHash}${refCount}` : `${fileScopeHash}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
// See https://github.com/postcss/postcss-js/blob/d5127d4278c133f333f1c66f990f3552a907128e/parser.js#L30 | ||
@@ -384,0 +116,0 @@ |
@@ -5,8 +5,8 @@ 'use strict'; | ||
var cssesc = require('cssesc'); | ||
var validateSelector = require('./validateSelector-acadedf9.cjs.dev.js'); | ||
var utils = require('./utils-c5ab417f.cjs.dev.js'); | ||
var transformCss_dist_vanillaExtractCssTransformCss = require('../transformCss/dist/vanilla-extract-css-transformCss.cjs.dev.js'); | ||
var adapter_dist_vanillaExtractCssAdapter = require('../adapter/dist/vanilla-extract-css-adapter.cjs.dev.js'); | ||
var hash = require('@emotion/hash'); | ||
var fileScope_dist_vanillaExtractCssFileScope = require('../fileScope/dist/vanilla-extract-css-fileScope.cjs.dev.js'); | ||
var _private = require('@vanilla-extract/private'); | ||
var cssesc = require('cssesc'); | ||
var dedent = require('dedent'); | ||
@@ -17,291 +17,6 @@ require('css-selector-parser'); | ||
var hash__default = /*#__PURE__*/_interopDefault(hash); | ||
var cssesc__default = /*#__PURE__*/_interopDefault(cssesc); | ||
var hash__default = /*#__PURE__*/_interopDefault(hash); | ||
var dedent__default = /*#__PURE__*/_interopDefault(dedent); | ||
const UNITLESS = { | ||
boxFlex: true, | ||
boxFlexGroup: true, | ||
columnCount: true, | ||
flex: true, | ||
flexGrow: true, | ||
flexPositive: true, | ||
flexShrink: true, | ||
flexNegative: true, | ||
fontWeight: true, | ||
lineClamp: true, | ||
lineHeight: true, | ||
opacity: true, | ||
order: true, | ||
orphans: true, | ||
tabSize: true, | ||
widows: true, | ||
zIndex: true, | ||
zoom: true, | ||
fillOpacity: true, | ||
strokeDashoffset: true, | ||
strokeOpacity: true, | ||
strokeWidth: true | ||
}; | ||
const simplePseudos = [':-moz-any-link', ':-moz-full-screen', ':-moz-placeholder', ':-moz-read-only', ':-moz-read-write', ':-ms-fullscreen', ':-ms-input-placeholder', ':-webkit-any-link', ':-webkit-full-screen', '::-moz-placeholder', '::-moz-progress-bar', '::-moz-range-progress', '::-moz-range-thumb', '::-moz-range-track', '::-moz-selection', '::-ms-backdrop', '::-ms-browse', '::-ms-check', '::-ms-clear', '::-ms-fill', '::-ms-fill-lower', '::-ms-fill-upper', '::-ms-reveal', '::-ms-thumb', '::-ms-ticks-after', '::-ms-ticks-before', '::-ms-tooltip', '::-ms-track', '::-ms-value', '::-webkit-backdrop', '::-webkit-input-placeholder', '::-webkit-progress-bar', '::-webkit-progress-inner-value', '::-webkit-progress-value', '::-webkit-slider-runnable-track', '::-webkit-slider-thumb', '::after', '::backdrop', '::before', '::cue', '::first-letter', '::first-line', '::grammar-error', '::placeholder', '::selection', '::spelling-error', ':active', ':after', ':any-link', ':before', ':blank', ':checked', ':default', ':defined', ':disabled', ':empty', ':enabled', ':first', ':first-child', ':first-letter', ':first-line', ':first-of-type', ':focus', ':focus-visible', ':focus-within', ':fullscreen', ':hover', ':in-range', ':indeterminate', ':invalid', ':last-child', ':last-of-type', ':left', ':link', ':only-child', ':only-of-type', ':optional', ':out-of-range', ':placeholder-shown', ':read-only', ':read-write', ':required', ':right', ':root', ':scope', ':target', ':valid', ':visited']; | ||
function dashify(str) { | ||
return str.replace(/([A-Z])/g, '-$1').replace(/^ms-/, '-ms-').toLowerCase(); | ||
} | ||
const DOUBLE_SPACE = ' '; | ||
const simplePseudoSet = new Set(simplePseudos); | ||
const specialKeys = [...simplePseudos, '@media', '@supports', 'selectors']; | ||
class Stylesheet { | ||
constructor(localClassNames) { | ||
this.rules = []; | ||
this.conditionalRules = []; | ||
this.fontFaceRules = []; | ||
this.keyframesRules = []; | ||
this.localClassNameRegex = localClassNames.length > 0 ? RegExp(`(${localClassNames.join('|')})`, 'g') : null; | ||
} | ||
processCssObj(root) { | ||
if (root.type === 'fontFace') { | ||
this.fontFaceRules.push(root.rule); | ||
return; | ||
} | ||
if (root.type === 'keyframes') { | ||
this.keyframesRules.push(root); | ||
return; | ||
} // Add main styles | ||
const mainRule = utils.omit(root.rule, specialKeys); | ||
this.addRule({ | ||
selector: root.selector, | ||
rule: mainRule | ||
}); | ||
this.transformSimplePsuedos(root, root.rule); | ||
this.transformMedia(root, root.rule['@media']); | ||
this.transformSupports(root, root.rule['@supports']); | ||
this.transformSelectors(root, root.rule); | ||
} | ||
addRule(cssRule) { | ||
// Run `pixelifyProperties` before `transformVars` as we don't want to pixelify CSS Vars | ||
const rule = this.transformVars(this.pixelifyProperties(cssRule.rule)); | ||
const selector = this.transformSelector(cssRule.selector); | ||
if (cssRule.conditions) { | ||
this.conditionalRules.push({ | ||
selector, | ||
rule, | ||
conditions: cssRule.conditions.sort() | ||
}); | ||
} else { | ||
this.rules.push({ | ||
selector, | ||
rule | ||
}); | ||
} | ||
} | ||
pixelifyProperties(cssRule) { | ||
utils.forEach(cssRule, (value, key) => { | ||
if (typeof value === 'number' && value !== 0 && !UNITLESS[key]) { | ||
// @ts-expect-error Any ideas? | ||
cssRule[key] = `${value}px`; | ||
} | ||
}); | ||
return cssRule; | ||
} | ||
transformVars({ | ||
vars, | ||
...rest | ||
}) { | ||
if (!vars) { | ||
return rest; | ||
} | ||
return { ...utils.mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
...rest | ||
}; | ||
} | ||
transformSelector(selector) { | ||
return this.localClassNameRegex ? selector.replace(this.localClassNameRegex, (_, className, index) => { | ||
if (index > 0 && selector[index - 1] === '.') { | ||
return className; | ||
} | ||
return `.${cssesc__default['default'](className, { | ||
isIdentifier: true | ||
})}`; | ||
}) : selector; | ||
} | ||
transformSelectors(root, rule, conditions) { | ||
utils.forEach(rule.selectors, (selectorRule, selector) => { | ||
if (root.type !== 'local') { | ||
throw new Error(`Selectors are not allowed within ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
const transformedSelector = this.transformSelector(selector.replace(RegExp('&', 'g'), root.selector)); | ||
validateSelector.validateSelector(transformedSelector, root.selector); | ||
this.addRule({ | ||
conditions, | ||
selector: transformedSelector, | ||
rule: utils.omit(selectorRule, specialKeys) | ||
}); | ||
const selectorRoot = { | ||
type: 'selector', | ||
selector: transformedSelector, | ||
rule: selectorRule | ||
}; | ||
this.transformSupports(selectorRoot, selectorRule['@supports'], conditions); | ||
this.transformMedia(selectorRoot, selectorRule['@media'], conditions); | ||
}); | ||
} | ||
transformMedia(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (mediaRule, query) => { | ||
const conditions = [`@media ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: utils.omit(mediaRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, mediaRule, conditions); | ||
this.transformSelectors(root, mediaRule, conditions); | ||
} | ||
this.transformSupports(root, mediaRule['@supports'], conditions); | ||
}); | ||
} | ||
transformSupports(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (supportsRule, query) => { | ||
const conditions = [`@supports ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: utils.omit(supportsRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, supportsRule, conditions); | ||
this.transformSelectors(root, supportsRule, conditions); | ||
} | ||
this.transformMedia(root, supportsRule['@media'], conditions); | ||
}); | ||
} | ||
transformSimplePsuedos(root, rule, conditions) { | ||
for (const key of Object.keys(rule)) { | ||
// Process simple psuedos | ||
if (simplePseudoSet.has(key)) { | ||
if (root.type !== 'local') { | ||
throw new Error(`Simple pseudos are not valid in ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
this.addRule({ | ||
conditions, | ||
selector: `${root.selector}${key}`, | ||
rule: rule[key] | ||
}); | ||
} | ||
} | ||
} | ||
toPostcssJs() { | ||
const styles = {}; | ||
if (this.fontFaceRules.length > 0) { | ||
styles['@font-face'] = this.fontFaceRules; | ||
} | ||
this.keyframesRules.forEach(rule => { | ||
styles[`@keyframes ${rule.name}`] = rule.rule; | ||
}); | ||
for (const rule of [...this.rules, ...this.conditionalRules]) { | ||
if (rule.conditions && utils.isEqual(styles[rule.selector], rule.rule)) { | ||
// Ignore conditional rules if they are identical to a non-conditional rule | ||
continue; | ||
} | ||
if (Object.keys(rule.rule).length === 0) { | ||
// Ignore empty rules | ||
continue; | ||
} | ||
let styleNode = styles; | ||
for (const condition of rule.conditions || []) { | ||
if (!styleNode[condition]) { | ||
styleNode[condition] = {}; | ||
} | ||
styleNode = styleNode[condition]; | ||
} | ||
styleNode[rule.selector] = { ...styleNode[rule.selector], | ||
...rule.rule | ||
}; | ||
} | ||
return styles; | ||
} | ||
toCss() { | ||
const styles = this.toPostcssJs(); | ||
function walkCss(v, indent = '') { | ||
const rules = []; | ||
for (const key of Object.keys(v)) { | ||
const value = v[key]; | ||
if (value && Array.isArray(value)) { | ||
rules.push(...value.map(v => walkCss({ | ||
[key]: v | ||
}, indent).join('\n'))); | ||
} else if (value && typeof value === 'object') { | ||
rules.push(`${indent}${key} {\n${walkCss(value, indent + DOUBLE_SPACE).join('\n')}\n${indent}}`); | ||
} else { | ||
rules.push(`${indent}${key.startsWith('--') ? key : dashify(key)}: ${value};`); | ||
} | ||
} | ||
return rules; | ||
} | ||
return walkCss(styles); | ||
} | ||
} | ||
function transformCss({ | ||
localClassNames, | ||
cssObjs | ||
}) { | ||
const stylesheet = new Stylesheet(localClassNames); | ||
for (const root of cssObjs) { | ||
stylesheet.processCssObj(root); | ||
} | ||
return stylesheet.toCss(); | ||
} | ||
const stylesheets = {}; | ||
@@ -311,5 +26,10 @@ const localClassNames = new Set(); | ||
function getStylesheet(fileScope) { | ||
if (stylesheets[fileScope]) { | ||
return stylesheets[fileScope]; | ||
function getStylesheet({ | ||
packageName, | ||
filePath | ||
}) { | ||
const fileScopeId = packageName ? `${packageName}${filePath}` : filePath; | ||
if (stylesheets[fileScopeId]) { | ||
return stylesheets[fileScopeId]; | ||
} | ||
@@ -324,3 +44,3 @@ | ||
stylesheets[fileScope] = styleEl.sheet; | ||
stylesheets[fileScopeId] = styleEl.sheet; | ||
return styleEl.sheet; | ||
@@ -337,3 +57,3 @@ } | ||
onEndFileScope: fileScope => { | ||
const css = transformCss({ | ||
const css = transformCss_dist_vanillaExtractCssTransformCss.transformCss({ | ||
localClassNames: Array.from(localClassNames), | ||
@@ -374,4 +94,6 @@ cssObjs: bufferedCSSObjs | ||
function getShortFileName() { | ||
const fileScope = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const matches = fileScope.match(/.*\/(.*)\..*\..*$/); | ||
const { | ||
filePath | ||
} = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const matches = filePath.match(/.*\/(.*)\..*\..*$/); | ||
@@ -387,3 +109,8 @@ if (matches && matches[1]) { | ||
const refCount = fileScope_dist_vanillaExtractCssFileScope.getAndIncrementRefCounter(); | ||
const identifier = process.env.NODE_ENV !== 'production' && debugId ? `${getShortFileName()}_${debugId}__${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}` : `${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}`; | ||
const { | ||
filePath, | ||
packageName | ||
} = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const fileScopeHash = hash__default['default'](packageName ? `${packageName}${filePath}` : filePath); | ||
const identifier = process.env.NODE_ENV !== 'production' && debugId ? `${getShortFileName()}_${debugId}__${fileScopeHash}${refCount}` : `${fileScopeHash}${refCount}`; | ||
return identifier.match(/^[0-9]/) ? `_${identifier}` : identifier; | ||
@@ -394,3 +121,8 @@ } | ||
const refCount = fileScope_dist_vanillaExtractCssFileScope.getAndIncrementRefCounter(); | ||
const varName = process.env.NODE_ENV !== 'production' && debugId ? `${debugId}__${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}` : `${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
const { | ||
filePath, | ||
packageName | ||
} = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const fileScopeHash = hash__default['default'](packageName ? `${packageName}${filePath}` : filePath); | ||
const varName = process.env.NODE_ENV !== 'production' && debugId ? `${debugId}__${fileScopeHash}${refCount}` : `${fileScopeHash}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
// See https://github.com/postcss/postcss-js/blob/d5127d4278c133f333f1c66f990f3552a907128e/parser.js#L30 | ||
@@ -425,4 +157,4 @@ | ||
utils.walkObject(tokens, (value, path) => { | ||
varSetters[utils.get(varContract, path)] = String(value); | ||
_private.walkObject(tokens, (value, path) => { | ||
varSetters[_private.get(varContract, path)] = String(value); | ||
}); | ||
@@ -432,3 +164,3 @@ return varSetters; | ||
function createThemeVars(themeContract) { | ||
return utils.walkObject(themeContract, (_value, path) => { | ||
return _private.walkObject(themeContract, (_value, path) => { | ||
return createVar(path.join('-')); | ||
@@ -435,0 +167,0 @@ }); |
@@ -5,8 +5,8 @@ 'use strict'; | ||
var cssesc = require('cssesc'); | ||
var validateSelector = require('./validateSelector-5a593081.cjs.prod.js'); | ||
var utils = require('./utils-2b734f0b.cjs.prod.js'); | ||
var transformCss_dist_vanillaExtractCssTransformCss = require('../transformCss/dist/vanilla-extract-css-transformCss.cjs.prod.js'); | ||
var adapter_dist_vanillaExtractCssAdapter = require('../adapter/dist/vanilla-extract-css-adapter.cjs.prod.js'); | ||
var hash = require('@emotion/hash'); | ||
var fileScope_dist_vanillaExtractCssFileScope = require('../fileScope/dist/vanilla-extract-css-fileScope.cjs.prod.js'); | ||
var _private = require('@vanilla-extract/private'); | ||
var cssesc = require('cssesc'); | ||
var dedent = require('dedent'); | ||
@@ -17,291 +17,6 @@ require('css-selector-parser'); | ||
var hash__default = /*#__PURE__*/_interopDefault(hash); | ||
var cssesc__default = /*#__PURE__*/_interopDefault(cssesc); | ||
var hash__default = /*#__PURE__*/_interopDefault(hash); | ||
var dedent__default = /*#__PURE__*/_interopDefault(dedent); | ||
const UNITLESS = { | ||
boxFlex: true, | ||
boxFlexGroup: true, | ||
columnCount: true, | ||
flex: true, | ||
flexGrow: true, | ||
flexPositive: true, | ||
flexShrink: true, | ||
flexNegative: true, | ||
fontWeight: true, | ||
lineClamp: true, | ||
lineHeight: true, | ||
opacity: true, | ||
order: true, | ||
orphans: true, | ||
tabSize: true, | ||
widows: true, | ||
zIndex: true, | ||
zoom: true, | ||
fillOpacity: true, | ||
strokeDashoffset: true, | ||
strokeOpacity: true, | ||
strokeWidth: true | ||
}; | ||
const simplePseudos = [':-moz-any-link', ':-moz-full-screen', ':-moz-placeholder', ':-moz-read-only', ':-moz-read-write', ':-ms-fullscreen', ':-ms-input-placeholder', ':-webkit-any-link', ':-webkit-full-screen', '::-moz-placeholder', '::-moz-progress-bar', '::-moz-range-progress', '::-moz-range-thumb', '::-moz-range-track', '::-moz-selection', '::-ms-backdrop', '::-ms-browse', '::-ms-check', '::-ms-clear', '::-ms-fill', '::-ms-fill-lower', '::-ms-fill-upper', '::-ms-reveal', '::-ms-thumb', '::-ms-ticks-after', '::-ms-ticks-before', '::-ms-tooltip', '::-ms-track', '::-ms-value', '::-webkit-backdrop', '::-webkit-input-placeholder', '::-webkit-progress-bar', '::-webkit-progress-inner-value', '::-webkit-progress-value', '::-webkit-slider-runnable-track', '::-webkit-slider-thumb', '::after', '::backdrop', '::before', '::cue', '::first-letter', '::first-line', '::grammar-error', '::placeholder', '::selection', '::spelling-error', ':active', ':after', ':any-link', ':before', ':blank', ':checked', ':default', ':defined', ':disabled', ':empty', ':enabled', ':first', ':first-child', ':first-letter', ':first-line', ':first-of-type', ':focus', ':focus-visible', ':focus-within', ':fullscreen', ':hover', ':in-range', ':indeterminate', ':invalid', ':last-child', ':last-of-type', ':left', ':link', ':only-child', ':only-of-type', ':optional', ':out-of-range', ':placeholder-shown', ':read-only', ':read-write', ':required', ':right', ':root', ':scope', ':target', ':valid', ':visited']; | ||
function dashify(str) { | ||
return str.replace(/([A-Z])/g, '-$1').replace(/^ms-/, '-ms-').toLowerCase(); | ||
} | ||
const DOUBLE_SPACE = ' '; | ||
const simplePseudoSet = new Set(simplePseudos); | ||
const specialKeys = [...simplePseudos, '@media', '@supports', 'selectors']; | ||
class Stylesheet { | ||
constructor(localClassNames) { | ||
this.rules = []; | ||
this.conditionalRules = []; | ||
this.fontFaceRules = []; | ||
this.keyframesRules = []; | ||
this.localClassNameRegex = localClassNames.length > 0 ? RegExp(`(${localClassNames.join('|')})`, 'g') : null; | ||
} | ||
processCssObj(root) { | ||
if (root.type === 'fontFace') { | ||
this.fontFaceRules.push(root.rule); | ||
return; | ||
} | ||
if (root.type === 'keyframes') { | ||
this.keyframesRules.push(root); | ||
return; | ||
} // Add main styles | ||
const mainRule = utils.omit(root.rule, specialKeys); | ||
this.addRule({ | ||
selector: root.selector, | ||
rule: mainRule | ||
}); | ||
this.transformSimplePsuedos(root, root.rule); | ||
this.transformMedia(root, root.rule['@media']); | ||
this.transformSupports(root, root.rule['@supports']); | ||
this.transformSelectors(root, root.rule); | ||
} | ||
addRule(cssRule) { | ||
// Run `pixelifyProperties` before `transformVars` as we don't want to pixelify CSS Vars | ||
const rule = this.transformVars(this.pixelifyProperties(cssRule.rule)); | ||
const selector = this.transformSelector(cssRule.selector); | ||
if (cssRule.conditions) { | ||
this.conditionalRules.push({ | ||
selector, | ||
rule, | ||
conditions: cssRule.conditions.sort() | ||
}); | ||
} else { | ||
this.rules.push({ | ||
selector, | ||
rule | ||
}); | ||
} | ||
} | ||
pixelifyProperties(cssRule) { | ||
utils.forEach(cssRule, (value, key) => { | ||
if (typeof value === 'number' && value !== 0 && !UNITLESS[key]) { | ||
// @ts-expect-error Any ideas? | ||
cssRule[key] = `${value}px`; | ||
} | ||
}); | ||
return cssRule; | ||
} | ||
transformVars({ | ||
vars, | ||
...rest | ||
}) { | ||
if (!vars) { | ||
return rest; | ||
} | ||
return { ...utils.mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
...rest | ||
}; | ||
} | ||
transformSelector(selector) { | ||
return this.localClassNameRegex ? selector.replace(this.localClassNameRegex, (_, className, index) => { | ||
if (index > 0 && selector[index - 1] === '.') { | ||
return className; | ||
} | ||
return `.${cssesc__default['default'](className, { | ||
isIdentifier: true | ||
})}`; | ||
}) : selector; | ||
} | ||
transformSelectors(root, rule, conditions) { | ||
utils.forEach(rule.selectors, (selectorRule, selector) => { | ||
if (root.type !== 'local') { | ||
throw new Error(`Selectors are not allowed within ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
const transformedSelector = this.transformSelector(selector.replace(RegExp('&', 'g'), root.selector)); | ||
validateSelector.validateSelector(transformedSelector, root.selector); | ||
this.addRule({ | ||
conditions, | ||
selector: transformedSelector, | ||
rule: utils.omit(selectorRule, specialKeys) | ||
}); | ||
const selectorRoot = { | ||
type: 'selector', | ||
selector: transformedSelector, | ||
rule: selectorRule | ||
}; | ||
this.transformSupports(selectorRoot, selectorRule['@supports'], conditions); | ||
this.transformMedia(selectorRoot, selectorRule['@media'], conditions); | ||
}); | ||
} | ||
transformMedia(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (mediaRule, query) => { | ||
const conditions = [`@media ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: utils.omit(mediaRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, mediaRule, conditions); | ||
this.transformSelectors(root, mediaRule, conditions); | ||
} | ||
this.transformSupports(root, mediaRule['@supports'], conditions); | ||
}); | ||
} | ||
transformSupports(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (supportsRule, query) => { | ||
const conditions = [`@supports ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: utils.omit(supportsRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, supportsRule, conditions); | ||
this.transformSelectors(root, supportsRule, conditions); | ||
} | ||
this.transformMedia(root, supportsRule['@media'], conditions); | ||
}); | ||
} | ||
transformSimplePsuedos(root, rule, conditions) { | ||
for (const key of Object.keys(rule)) { | ||
// Process simple psuedos | ||
if (simplePseudoSet.has(key)) { | ||
if (root.type !== 'local') { | ||
throw new Error(`Simple pseudos are not valid in ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
this.addRule({ | ||
conditions, | ||
selector: `${root.selector}${key}`, | ||
rule: rule[key] | ||
}); | ||
} | ||
} | ||
} | ||
toPostcssJs() { | ||
const styles = {}; | ||
if (this.fontFaceRules.length > 0) { | ||
styles['@font-face'] = this.fontFaceRules; | ||
} | ||
this.keyframesRules.forEach(rule => { | ||
styles[`@keyframes ${rule.name}`] = rule.rule; | ||
}); | ||
for (const rule of [...this.rules, ...this.conditionalRules]) { | ||
if (rule.conditions && utils.isEqual(styles[rule.selector], rule.rule)) { | ||
// Ignore conditional rules if they are identical to a non-conditional rule | ||
continue; | ||
} | ||
if (Object.keys(rule.rule).length === 0) { | ||
// Ignore empty rules | ||
continue; | ||
} | ||
let styleNode = styles; | ||
for (const condition of rule.conditions || []) { | ||
if (!styleNode[condition]) { | ||
styleNode[condition] = {}; | ||
} | ||
styleNode = styleNode[condition]; | ||
} | ||
styleNode[rule.selector] = { ...styleNode[rule.selector], | ||
...rule.rule | ||
}; | ||
} | ||
return styles; | ||
} | ||
toCss() { | ||
const styles = this.toPostcssJs(); | ||
function walkCss(v, indent = '') { | ||
const rules = []; | ||
for (const key of Object.keys(v)) { | ||
const value = v[key]; | ||
if (value && Array.isArray(value)) { | ||
rules.push(...value.map(v => walkCss({ | ||
[key]: v | ||
}, indent).join('\n'))); | ||
} else if (value && typeof value === 'object') { | ||
rules.push(`${indent}${key} {\n${walkCss(value, indent + DOUBLE_SPACE).join('\n')}\n${indent}}`); | ||
} else { | ||
rules.push(`${indent}${key.startsWith('--') ? key : dashify(key)}: ${value};`); | ||
} | ||
} | ||
return rules; | ||
} | ||
return walkCss(styles); | ||
} | ||
} | ||
function transformCss({ | ||
localClassNames, | ||
cssObjs | ||
}) { | ||
const stylesheet = new Stylesheet(localClassNames); | ||
for (const root of cssObjs) { | ||
stylesheet.processCssObj(root); | ||
} | ||
return stylesheet.toCss(); | ||
} | ||
const stylesheets = {}; | ||
@@ -311,5 +26,10 @@ const localClassNames = new Set(); | ||
function getStylesheet(fileScope) { | ||
if (stylesheets[fileScope]) { | ||
return stylesheets[fileScope]; | ||
function getStylesheet({ | ||
packageName, | ||
filePath | ||
}) { | ||
const fileScopeId = packageName ? `${packageName}${filePath}` : filePath; | ||
if (stylesheets[fileScopeId]) { | ||
return stylesheets[fileScopeId]; | ||
} | ||
@@ -324,3 +44,3 @@ | ||
stylesheets[fileScope] = styleEl.sheet; | ||
stylesheets[fileScopeId] = styleEl.sheet; | ||
return styleEl.sheet; | ||
@@ -337,3 +57,3 @@ } | ||
onEndFileScope: fileScope => { | ||
const css = transformCss({ | ||
const css = transformCss_dist_vanillaExtractCssTransformCss.transformCss({ | ||
localClassNames: Array.from(localClassNames), | ||
@@ -375,3 +95,8 @@ cssObjs: bufferedCSSObjs | ||
const refCount = fileScope_dist_vanillaExtractCssFileScope.getAndIncrementRefCounter(); | ||
const identifier = `${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}`; | ||
const { | ||
filePath, | ||
packageName | ||
} = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const fileScopeHash = hash__default['default'](packageName ? `${packageName}${filePath}` : filePath); | ||
const identifier = `${fileScopeHash}${refCount}`; | ||
return identifier.match(/^[0-9]/) ? `_${identifier}` : identifier; | ||
@@ -382,3 +107,8 @@ } | ||
const refCount = fileScope_dist_vanillaExtractCssFileScope.getAndIncrementRefCounter(); | ||
const varName = `${hash__default['default'](fileScope_dist_vanillaExtractCssFileScope.getFileScope())}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
const { | ||
filePath, | ||
packageName | ||
} = fileScope_dist_vanillaExtractCssFileScope.getFileScope(); | ||
const fileScopeHash = hash__default['default'](packageName ? `${packageName}${filePath}` : filePath); | ||
const varName = `${fileScopeHash}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
// See https://github.com/postcss/postcss-js/blob/d5127d4278c133f333f1c66f990f3552a907128e/parser.js#L30 | ||
@@ -413,4 +143,4 @@ | ||
utils.walkObject(tokens, (value, path) => { | ||
varSetters[utils.get(varContract, path)] = String(value); | ||
_private.walkObject(tokens, (value, path) => { | ||
varSetters[_private.get(varContract, path)] = String(value); | ||
}); | ||
@@ -420,3 +150,3 @@ return varSetters; | ||
function createThemeVars(themeContract) { | ||
return utils.walkObject(themeContract, (_value, path) => { | ||
return _private.walkObject(themeContract, (_value, path) => { | ||
return createVar(path.join('-')); | ||
@@ -423,0 +153,0 @@ }); |
@@ -1,295 +0,10 @@ | ||
import cssesc from 'cssesc'; | ||
import { v as validateSelector } from './validateSelector-cfc75bf8.esm.js'; | ||
import { o as omit, f as forEach, m as mapKeys, i as isEqual, w as walkObject, g as get } from './utils-fbd6ce24.esm.js'; | ||
import { transformCss } from '../transformCss/dist/vanilla-extract-css-transformCss.esm.js'; | ||
import { setAdapter, appendCss, registerClassName } from '../adapter/dist/vanilla-extract-css-adapter.esm.js'; | ||
import hash from '@emotion/hash'; | ||
import { getAndIncrementRefCounter, getFileScope } from '../fileScope/dist/vanilla-extract-css-fileScope.esm.js'; | ||
import { walkObject, get } from '@vanilla-extract/private'; | ||
import cssesc from 'cssesc'; | ||
import dedent from 'dedent'; | ||
import 'css-selector-parser'; | ||
const UNITLESS = { | ||
boxFlex: true, | ||
boxFlexGroup: true, | ||
columnCount: true, | ||
flex: true, | ||
flexGrow: true, | ||
flexPositive: true, | ||
flexShrink: true, | ||
flexNegative: true, | ||
fontWeight: true, | ||
lineClamp: true, | ||
lineHeight: true, | ||
opacity: true, | ||
order: true, | ||
orphans: true, | ||
tabSize: true, | ||
widows: true, | ||
zIndex: true, | ||
zoom: true, | ||
fillOpacity: true, | ||
strokeDashoffset: true, | ||
strokeOpacity: true, | ||
strokeWidth: true | ||
}; | ||
const simplePseudos = [':-moz-any-link', ':-moz-full-screen', ':-moz-placeholder', ':-moz-read-only', ':-moz-read-write', ':-ms-fullscreen', ':-ms-input-placeholder', ':-webkit-any-link', ':-webkit-full-screen', '::-moz-placeholder', '::-moz-progress-bar', '::-moz-range-progress', '::-moz-range-thumb', '::-moz-range-track', '::-moz-selection', '::-ms-backdrop', '::-ms-browse', '::-ms-check', '::-ms-clear', '::-ms-fill', '::-ms-fill-lower', '::-ms-fill-upper', '::-ms-reveal', '::-ms-thumb', '::-ms-ticks-after', '::-ms-ticks-before', '::-ms-tooltip', '::-ms-track', '::-ms-value', '::-webkit-backdrop', '::-webkit-input-placeholder', '::-webkit-progress-bar', '::-webkit-progress-inner-value', '::-webkit-progress-value', '::-webkit-slider-runnable-track', '::-webkit-slider-thumb', '::after', '::backdrop', '::before', '::cue', '::first-letter', '::first-line', '::grammar-error', '::placeholder', '::selection', '::spelling-error', ':active', ':after', ':any-link', ':before', ':blank', ':checked', ':default', ':defined', ':disabled', ':empty', ':enabled', ':first', ':first-child', ':first-letter', ':first-line', ':first-of-type', ':focus', ':focus-visible', ':focus-within', ':fullscreen', ':hover', ':in-range', ':indeterminate', ':invalid', ':last-child', ':last-of-type', ':left', ':link', ':only-child', ':only-of-type', ':optional', ':out-of-range', ':placeholder-shown', ':read-only', ':read-write', ':required', ':right', ':root', ':scope', ':target', ':valid', ':visited']; | ||
function dashify(str) { | ||
return str.replace(/([A-Z])/g, '-$1').replace(/^ms-/, '-ms-').toLowerCase(); | ||
} | ||
const DOUBLE_SPACE = ' '; | ||
const simplePseudoSet = new Set(simplePseudos); | ||
const specialKeys = [...simplePseudos, '@media', '@supports', 'selectors']; | ||
class Stylesheet { | ||
constructor(localClassNames) { | ||
this.rules = []; | ||
this.conditionalRules = []; | ||
this.fontFaceRules = []; | ||
this.keyframesRules = []; | ||
this.localClassNameRegex = localClassNames.length > 0 ? RegExp(`(${localClassNames.join('|')})`, 'g') : null; | ||
} | ||
processCssObj(root) { | ||
if (root.type === 'fontFace') { | ||
this.fontFaceRules.push(root.rule); | ||
return; | ||
} | ||
if (root.type === 'keyframes') { | ||
this.keyframesRules.push(root); | ||
return; | ||
} // Add main styles | ||
const mainRule = omit(root.rule, specialKeys); | ||
this.addRule({ | ||
selector: root.selector, | ||
rule: mainRule | ||
}); | ||
this.transformSimplePsuedos(root, root.rule); | ||
this.transformMedia(root, root.rule['@media']); | ||
this.transformSupports(root, root.rule['@supports']); | ||
this.transformSelectors(root, root.rule); | ||
} | ||
addRule(cssRule) { | ||
// Run `pixelifyProperties` before `transformVars` as we don't want to pixelify CSS Vars | ||
const rule = this.transformVars(this.pixelifyProperties(cssRule.rule)); | ||
const selector = this.transformSelector(cssRule.selector); | ||
if (cssRule.conditions) { | ||
this.conditionalRules.push({ | ||
selector, | ||
rule, | ||
conditions: cssRule.conditions.sort() | ||
}); | ||
} else { | ||
this.rules.push({ | ||
selector, | ||
rule | ||
}); | ||
} | ||
} | ||
pixelifyProperties(cssRule) { | ||
forEach(cssRule, (value, key) => { | ||
if (typeof value === 'number' && value !== 0 && !UNITLESS[key]) { | ||
// @ts-expect-error Any ideas? | ||
cssRule[key] = `${value}px`; | ||
} | ||
}); | ||
return cssRule; | ||
} | ||
transformVars({ | ||
vars, | ||
...rest | ||
}) { | ||
if (!vars) { | ||
return rest; | ||
} | ||
return { ...mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
...rest | ||
}; | ||
} | ||
transformSelector(selector) { | ||
return this.localClassNameRegex ? selector.replace(this.localClassNameRegex, (_, className, index) => { | ||
if (index > 0 && selector[index - 1] === '.') { | ||
return className; | ||
} | ||
return `.${cssesc(className, { | ||
isIdentifier: true | ||
})}`; | ||
}) : selector; | ||
} | ||
transformSelectors(root, rule, conditions) { | ||
forEach(rule.selectors, (selectorRule, selector) => { | ||
if (root.type !== 'local') { | ||
throw new Error(`Selectors are not allowed within ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
const transformedSelector = this.transformSelector(selector.replace(RegExp('&', 'g'), root.selector)); | ||
validateSelector(transformedSelector, root.selector); | ||
this.addRule({ | ||
conditions, | ||
selector: transformedSelector, | ||
rule: omit(selectorRule, specialKeys) | ||
}); | ||
const selectorRoot = { | ||
type: 'selector', | ||
selector: transformedSelector, | ||
rule: selectorRule | ||
}; | ||
this.transformSupports(selectorRoot, selectorRule['@supports'], conditions); | ||
this.transformMedia(selectorRoot, selectorRule['@media'], conditions); | ||
}); | ||
} | ||
transformMedia(root, rules, parentConditions = []) { | ||
forEach(rules, (mediaRule, query) => { | ||
const conditions = [`@media ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: omit(mediaRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, mediaRule, conditions); | ||
this.transformSelectors(root, mediaRule, conditions); | ||
} | ||
this.transformSupports(root, mediaRule['@supports'], conditions); | ||
}); | ||
} | ||
transformSupports(root, rules, parentConditions = []) { | ||
forEach(rules, (supportsRule, query) => { | ||
const conditions = [`@supports ${query}`, ...parentConditions]; | ||
this.addRule({ | ||
conditions, | ||
selector: root.selector, | ||
rule: omit(supportsRule, specialKeys) | ||
}); | ||
if (root.type === 'local') { | ||
this.transformSimplePsuedos(root, supportsRule, conditions); | ||
this.transformSelectors(root, supportsRule, conditions); | ||
} | ||
this.transformMedia(root, supportsRule['@media'], conditions); | ||
}); | ||
} | ||
transformSimplePsuedos(root, rule, conditions) { | ||
for (const key of Object.keys(rule)) { | ||
// Process simple psuedos | ||
if (simplePseudoSet.has(key)) { | ||
if (root.type !== 'local') { | ||
throw new Error(`Simple pseudos are not valid in ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
} | ||
this.addRule({ | ||
conditions, | ||
selector: `${root.selector}${key}`, | ||
rule: rule[key] | ||
}); | ||
} | ||
} | ||
} | ||
toPostcssJs() { | ||
const styles = {}; | ||
if (this.fontFaceRules.length > 0) { | ||
styles['@font-face'] = this.fontFaceRules; | ||
} | ||
this.keyframesRules.forEach(rule => { | ||
styles[`@keyframes ${rule.name}`] = rule.rule; | ||
}); | ||
for (const rule of [...this.rules, ...this.conditionalRules]) { | ||
if (rule.conditions && isEqual(styles[rule.selector], rule.rule)) { | ||
// Ignore conditional rules if they are identical to a non-conditional rule | ||
continue; | ||
} | ||
if (Object.keys(rule.rule).length === 0) { | ||
// Ignore empty rules | ||
continue; | ||
} | ||
let styleNode = styles; | ||
for (const condition of rule.conditions || []) { | ||
if (!styleNode[condition]) { | ||
styleNode[condition] = {}; | ||
} | ||
styleNode = styleNode[condition]; | ||
} | ||
styleNode[rule.selector] = { ...styleNode[rule.selector], | ||
...rule.rule | ||
}; | ||
} | ||
return styles; | ||
} | ||
toCss() { | ||
const styles = this.toPostcssJs(); | ||
function walkCss(v, indent = '') { | ||
const rules = []; | ||
for (const key of Object.keys(v)) { | ||
const value = v[key]; | ||
if (value && Array.isArray(value)) { | ||
rules.push(...value.map(v => walkCss({ | ||
[key]: v | ||
}, indent).join('\n'))); | ||
} else if (value && typeof value === 'object') { | ||
rules.push(`${indent}${key} {\n${walkCss(value, indent + DOUBLE_SPACE).join('\n')}\n${indent}}`); | ||
} else { | ||
rules.push(`${indent}${key.startsWith('--') ? key : dashify(key)}: ${value};`); | ||
} | ||
} | ||
return rules; | ||
} | ||
return walkCss(styles); | ||
} | ||
} | ||
function transformCss({ | ||
localClassNames, | ||
cssObjs | ||
}) { | ||
const stylesheet = new Stylesheet(localClassNames); | ||
for (const root of cssObjs) { | ||
stylesheet.processCssObj(root); | ||
} | ||
return stylesheet.toCss(); | ||
} | ||
const stylesheets = {}; | ||
@@ -299,5 +14,10 @@ const localClassNames = new Set(); | ||
function getStylesheet(fileScope) { | ||
if (stylesheets[fileScope]) { | ||
return stylesheets[fileScope]; | ||
function getStylesheet({ | ||
packageName, | ||
filePath | ||
}) { | ||
const fileScopeId = packageName ? `${packageName}${filePath}` : filePath; | ||
if (stylesheets[fileScopeId]) { | ||
return stylesheets[fileScopeId]; | ||
} | ||
@@ -312,3 +32,3 @@ | ||
stylesheets[fileScope] = styleEl.sheet; | ||
stylesheets[fileScopeId] = styleEl.sheet; | ||
return styleEl.sheet; | ||
@@ -361,4 +81,6 @@ } | ||
function getShortFileName() { | ||
const fileScope = getFileScope(); | ||
const matches = fileScope.match(/.*\/(.*)\..*\..*$/); | ||
const { | ||
filePath | ||
} = getFileScope(); | ||
const matches = filePath.match(/.*\/(.*)\..*\..*$/); | ||
@@ -374,3 +96,8 @@ if (matches && matches[1]) { | ||
const refCount = getAndIncrementRefCounter(); | ||
const identifier = process.env.NODE_ENV !== 'production' && debugId ? `${getShortFileName()}_${debugId}__${hash(getFileScope())}${refCount}` : `${hash(getFileScope())}${refCount}`; | ||
const { | ||
filePath, | ||
packageName | ||
} = getFileScope(); | ||
const fileScopeHash = hash(packageName ? `${packageName}${filePath}` : filePath); | ||
const identifier = process.env.NODE_ENV !== 'production' && debugId ? `${getShortFileName()}_${debugId}__${fileScopeHash}${refCount}` : `${fileScopeHash}${refCount}`; | ||
return identifier.match(/^[0-9]/) ? `_${identifier}` : identifier; | ||
@@ -381,3 +108,8 @@ } | ||
const refCount = getAndIncrementRefCounter(); | ||
const varName = process.env.NODE_ENV !== 'production' && debugId ? `${debugId}__${hash(getFileScope())}${refCount}` : `${hash(getFileScope())}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
const { | ||
filePath, | ||
packageName | ||
} = getFileScope(); | ||
const fileScopeHash = hash(packageName ? `${packageName}${filePath}` : filePath); | ||
const varName = process.env.NODE_ENV !== 'production' && debugId ? `${debugId}__${fileScopeHash}${refCount}` : `${fileScopeHash}${refCount}`; // Dashify CSS var names to replicate postcss-js behaviour | ||
// See https://github.com/postcss/postcss-js/blob/d5127d4278c133f333f1c66f990f3552a907128e/parser.js#L30 | ||
@@ -384,0 +116,0 @@ |
@@ -9,5 +9,8 @@ 'use strict'; | ||
const fileScopes = []; | ||
function setFileScope(newFileScope) { | ||
function setFileScope(filePath, packageName) { | ||
refCounter = 0; | ||
fileScopes.unshift(newFileScope); | ||
fileScopes.unshift({ | ||
filePath, | ||
packageName | ||
}); | ||
} | ||
@@ -14,0 +17,0 @@ function endFileScope() { |
@@ -5,5 +5,8 @@ import { onEndFileScope } from '../../adapter/dist/vanilla-extract-css-adapter.browser.esm.js'; | ||
const fileScopes = []; | ||
function setFileScope(newFileScope) { | ||
function setFileScope(filePath, packageName) { | ||
refCounter = 0; | ||
fileScopes.unshift(newFileScope); | ||
fileScopes.unshift({ | ||
filePath, | ||
packageName | ||
}); | ||
} | ||
@@ -10,0 +13,0 @@ function endFileScope() { |
@@ -9,5 +9,8 @@ 'use strict'; | ||
const fileScopes = []; | ||
function setFileScope(newFileScope) { | ||
function setFileScope(filePath, packageName) { | ||
refCounter = 0; | ||
fileScopes.unshift(newFileScope); | ||
fileScopes.unshift({ | ||
filePath, | ||
packageName | ||
}); | ||
} | ||
@@ -14,0 +17,0 @@ function endFileScope() { |
@@ -9,5 +9,8 @@ 'use strict'; | ||
const fileScopes = []; | ||
function setFileScope(newFileScope) { | ||
function setFileScope(filePath, packageName) { | ||
refCounter = 0; | ||
fileScopes.unshift(newFileScope); | ||
fileScopes.unshift({ | ||
filePath, | ||
packageName | ||
}); | ||
} | ||
@@ -14,0 +17,0 @@ function endFileScope() { |
@@ -5,5 +5,8 @@ import { onEndFileScope } from '../../adapter/dist/vanilla-extract-css-adapter.esm.js'; | ||
const fileScopes = []; | ||
function setFileScope(newFileScope) { | ||
function setFileScope(filePath, packageName) { | ||
refCounter = 0; | ||
fileScopes.unshift(newFileScope); | ||
fileScopes.unshift({ | ||
filePath, | ||
packageName | ||
}); | ||
} | ||
@@ -10,0 +13,0 @@ function endFileScope() { |
{ | ||
"name": "@vanilla-extract/css", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Zero-runtime Stylesheets-in-TypeScript", | ||
@@ -17,4 +17,3 @@ "sideEffects": true, | ||
"transformCss.ts", | ||
"fileScope.ts", | ||
"createInlineTheme.ts" | ||
"fileScope.ts" | ||
] | ||
@@ -26,4 +25,3 @@ }, | ||
"/transformCss", | ||
"/fileScope", | ||
"/createInlineTheme" | ||
"/fileScope" | ||
], | ||
@@ -39,2 +37,3 @@ "repository": { | ||
"@emotion/hash": "^0.8.0", | ||
"@vanilla-extract/private": "^0.1.0", | ||
"css-selector-parser": "^1.4.1", | ||
@@ -41,0 +40,0 @@ "cssesc": "^3.0.0", |
170
README.md
@@ -33,2 +33,4 @@ # 🧁 vanilla-extract | ||
🙈 Optional API for dynamic runtime theming. | ||
--- | ||
@@ -79,2 +81,5 @@ | ||
- [Setup](#setup) | ||
- [webpack](#webpack) | ||
- [esbuild](#esbuild) | ||
- [Gatsby](#gatsby) | ||
- [API](#api) | ||
@@ -86,3 +91,2 @@ - [style](#style) | ||
- [createGlobalTheme](#createglobaltheme) | ||
- [createInlineTheme](#createinlinetheme) | ||
- [createThemeVars](#createthemevars) | ||
@@ -96,2 +100,6 @@ - [assignVars](#assignvars) | ||
- [globalKeyframes](#globalkeyframes) | ||
- [Dynamic API](#dynamic-api) | ||
- [createInlineTheme](#createinlinetheme) | ||
- [setElementTheme](#setelementtheme) | ||
- [setElementVar](#setelementvar) | ||
- [Utility functions](#utility-functions) | ||
@@ -106,2 +114,6 @@ - [calc](#calc) | ||
There are currently a few integrations to choose from. | ||
### webpack | ||
1. Install the dependencies. | ||
@@ -161,2 +173,29 @@ | ||
### esbuild | ||
1. Install the dependencies. | ||
```bash | ||
$ yarn add --dev @vanilla-extract/css @vanilla-extract/esbuild-plugin | ||
``` | ||
2. Add the [esbuild](https://esbuild.github.io/) plugin to your build script. | ||
```js | ||
const { vanillaExtractPlugin } = require('@vanilla-extract/esbuild-plugin'); | ||
require('esbuild').build({ | ||
entryPoints: ['app.ts'], | ||
bundle: true, | ||
plugins: [vanillaExtractPlugin()], | ||
outfile: 'out.js', | ||
}).catch(() => process.exit(1)) | ||
``` | ||
> Please note: There are currently no automatic readable class names during development. However, you can still manually provide a debug ID as the last argument to functions that generate scoped styles, e.g. `export const className = style({ ... }, 'className');` | ||
### Gatsby | ||
To add to your [Gatsby](https://www.gatsbyjs.com) site, use the [gatsby-plugin-vanilla-extract](https://github.com/KyleAMathews/gatsby-plugin-vanilla-extract) plugin. | ||
--- | ||
@@ -166,2 +205,4 @@ | ||
> 🍬 If you're a [treat](https://seek-oss.github.io/treat) user, check out our [migration guide.](./docs/treat-migration-guide.md) | ||
### style | ||
@@ -226,2 +267,8 @@ | ||
> 💡 To improve maintainability, each `style` block can only target a single element. To enforce this, all selectors must target the `&` character which is a reference to the current element. For example, `'&:hover:not(:active)'` is considered valid, while `'& > a'` and ``[`& ${childClass}`]`` are not. | ||
> | ||
>If you want to target another scoped class then it should be defined within the `style` block of that class instead. For example, ``[`& ${childClass}`]`` is invalid since it targets `${childClass}`, so it should instead be defined in the `style` block for `childClass`. | ||
> | ||
>If you want to globally target child nodes within the current element (e.g. `'& > a'`), you should use [`globalStyle`](#globalstyle) instead. | ||
### globalStyle | ||
@@ -239,2 +286,14 @@ | ||
Global selectors can also contain references to other scoped class names. | ||
```ts | ||
import { globalStyle } from '@vanilla-extract/css'; | ||
export const parentClass = style({}); | ||
globalStyle(`${parentClass} > a`, { | ||
color: 'pink' | ||
}); | ||
``` | ||
### mapToStyles | ||
@@ -334,23 +393,2 @@ | ||
### createInlineTheme | ||
Generates a custom theme at runtime as an inline style object. | ||
```ts | ||
import { createInlineTheme } from '@vanilla-extract/css/createInlineTheme'; | ||
import { themeVars, exampleStyle } from './styles.css.ts'; | ||
const customTheme = createInlineTheme(themeVars, { | ||
small: 4, | ||
medium: 8, | ||
large: 16 | ||
}); | ||
document.write(` | ||
<section style="${customTheme}"> | ||
<h1 class="${exampleStyle}">Hello world!</h1> | ||
</section> | ||
`); | ||
``` | ||
### createThemeVars | ||
@@ -398,15 +436,22 @@ | ||
Allows you to set an entire collection of CSS Variables anywhere within a style block. | ||
Assigns a collection of CSS Variables anywhere within a style block. | ||
> 💡 This is useful for creating responsive themes since it can be used within an `@media` block. | ||
> 💡 This is useful for creating responsive themes since it can be used within `@media` blocks. | ||
```ts | ||
import { style, assignVars } from '@vanilla-extract/css'; | ||
import { themeVars } from './vars.css.ts'; | ||
import { style, createThemeVars, assignVars } from '@vanilla-extract/css'; | ||
export const exampleStyle = style({ | ||
export const themeVars = createThemeVars({ | ||
space: { | ||
small: null, | ||
medium: null, | ||
large: null | ||
} | ||
}); | ||
export const responsiveSpaceTheme = style({ | ||
vars: assignVars(themeVars.space, { | ||
small: 4, | ||
medium: 8, | ||
large: 16 | ||
small: '4px', | ||
medium: '8px', | ||
large: '16px' | ||
}), | ||
@@ -416,5 +461,5 @@ '@media': { | ||
vars: assignVars(themeVars.space, { | ||
small: 8, | ||
medium: 16, | ||
large: 32 | ||
small: '8px', | ||
medium: '16px', | ||
large: '32px' | ||
}) | ||
@@ -551,2 +596,61 @@ } | ||
## Dynamic API | ||
We also provide a lightweight standalone package to support dynamic runtime theming. | ||
```bash | ||
$ yarn add --dev @vanilla-extract/dynamic | ||
``` | ||
### createInlineTheme | ||
Generates a custom theme at runtime as an inline style object. | ||
```ts | ||
import { createInlineTheme } from '@vanilla-extract/dynamic'; | ||
import { themeVars, exampleStyle } from './styles.css.ts'; | ||
const customTheme = createInlineTheme(themeVars, { | ||
small: '4px', | ||
medium: '8px', | ||
large: '16px' | ||
}); | ||
document.write(` | ||
<section style="${customTheme}"> | ||
<h1 class="${exampleStyle}">Hello world!</h1> | ||
</section> | ||
`); | ||
``` | ||
### setElementTheme | ||
Sets a collection of CSS Variables on an element. | ||
```ts | ||
import { setElementTheme } from '@vanilla-extract/dynamic'; | ||
import { themeVars } from './styles.css.ts'; | ||
const element = document.getElementById('myElement'); | ||
setElementTheme(element, themeVars, { | ||
small: '4px', | ||
medium: '8px', | ||
large: '16px' | ||
}); | ||
``` | ||
> 💡 All variables passed into this function must be assigned or it’s a type error. | ||
### setElementVar | ||
Sets a single var on an element. | ||
```ts | ||
import { setElementVar } from '@vanilla-extract/dynamic'; | ||
import { themeVars } from './styles.css.ts'; | ||
const element = document.getElementById('myElement'); | ||
setElementVar(element, themeVars.color.brand, 'darksalmon'); | ||
``` | ||
## Utility functions | ||
@@ -553,0 +657,0 @@ |
@@ -5,7 +5,6 @@ 'use strict'; | ||
var _private = require('@vanilla-extract/private'); | ||
var cssesc = require('cssesc'); | ||
var validateSelector = require('../../dist/validateSelector-a9e44540.browser.cjs.js'); | ||
var utils = require('../../dist/utils-03507b0d.browser.cjs.js'); | ||
require('css-selector-parser'); | ||
require('dedent'); | ||
var cssSelectorParser = require('css-selector-parser'); | ||
var dedent = require('dedent'); | ||
@@ -15,3 +14,116 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; } | ||
var cssesc__default = /*#__PURE__*/_interopDefault(cssesc); | ||
var dedent__default = /*#__PURE__*/_interopDefault(dedent); | ||
function escapeRegex(string) { | ||
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
} | ||
const parser = new cssSelectorParser.CssSelectorParser(); | ||
parser.registerSelectorPseudos('has'); | ||
parser.registerNestingOperators('>', '+', '~'); | ||
parser.registerAttrEqualityMods('^', '$', '*', '~'); | ||
parser.enableSubstitutes(); | ||
const validateSelector = (selector, targetClassName) => { | ||
const replaceTarget = () => { | ||
const targetRegex = new RegExp(`.${escapeRegex(cssesc__default['default'](targetClassName, { | ||
isIdentifier: true | ||
}))}`, 'g'); | ||
return selector.replace(targetRegex, '&'); | ||
}; | ||
return selector.split(',').map(selectorPart => { | ||
if (selectorPart.indexOf(targetClassName) === -1) { | ||
throw new Error(dedent__default['default']` | ||
Invalid selector: ${replaceTarget()} | ||
Selectors must target the ampersand character ('&'), which refers to the generated class name, e.g. '&:nth-child(2n)' | ||
`); | ||
} | ||
let currentRule; | ||
try { | ||
const result = parser.parse(selectorPart); | ||
if (result.type === 'ruleSet') { | ||
currentRule = result.rule; | ||
} else { | ||
throw new Error(); | ||
} | ||
} catch (err) { | ||
throw new Error(`Invalid selector: ${replaceTarget()}`); | ||
} | ||
while (currentRule.rule) { | ||
currentRule = currentRule.rule; | ||
} | ||
const targetRule = currentRule; | ||
if (!Array.isArray(targetRule.classNames) || !targetRule.classNames.find(className => className === targetClassName)) { | ||
throw new Error(dedent__default['default']` | ||
Invalid selector: ${replaceTarget()} | ||
Style selectors must end with the '&' character (along with any modifiers), e.g. ${'`${parent} &`'} or ${'`${parent} &:hover`'}. | ||
This is to ensure that each style block only affects the styling of a single class. | ||
If your selector is targeting another class, you should move it to the style definition for that class, e.g. given we have styles for 'parent' and 'child' elements, instead of adding a selector of ${'`& ${child}`'}) to 'parent', you should add ${'`${parent} &`'} to 'child'). | ||
If your selector is targeting something global, use the 'globalStyle' function instead, e.g. if you wanted to write ${'`& h1`'}, you should instead write 'globalStyle(${'`${parent} h1`'}, { ... })' | ||
`); | ||
} | ||
}); | ||
}; | ||
function forEach(obj, fn) { | ||
for (const key in obj) { | ||
fn(obj[key], key); | ||
} | ||
} | ||
function omit(obj, omitKeys) { | ||
let result = {}; | ||
for (const key in obj) { | ||
if (omitKeys.indexOf(key) === -1) { | ||
result[key] = obj[key]; | ||
} | ||
} | ||
return result; | ||
} | ||
function mapKeys(obj, fn) { | ||
let result = {}; | ||
for (const key in obj) { | ||
result[fn(obj[key], key)] = obj[key]; | ||
} | ||
return result; | ||
} | ||
function isEqual(a, b) { | ||
if (typeof a !== typeof b) { | ||
return false; | ||
} | ||
if (typeof a === 'object') { | ||
const keys1 = Object.keys(a); | ||
const keys2 = Object.keys(b); | ||
if (keys1.length !== keys2.length) { | ||
return false; | ||
} | ||
for (const key in a) { | ||
if (!isEqual(a[key], b[key])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} else { | ||
return a === b; | ||
} | ||
} | ||
const UNITLESS = { | ||
@@ -72,3 +184,3 @@ boxFlex: true, | ||
const mainRule = utils.omit(root.rule, specialKeys); | ||
const mainRule = omit(root.rule, specialKeys); | ||
this.addRule({ | ||
@@ -104,3 +216,3 @@ selector: root.selector, | ||
pixelifyProperties(cssRule) { | ||
utils.forEach(cssRule, (value, key) => { | ||
forEach(cssRule, (value, key) => { | ||
if (typeof value === 'number' && value !== 0 && !UNITLESS[key]) { | ||
@@ -122,11 +234,3 @@ // @ts-expect-error Any ideas? | ||
return { ...utils.mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
return { ...mapKeys(vars, (_value, key) => _private.getVarName(key)), | ||
...rest | ||
@@ -149,3 +253,3 @@ }; | ||
transformSelectors(root, rule, conditions) { | ||
utils.forEach(rule.selectors, (selectorRule, selector) => { | ||
forEach(rule.selectors, (selectorRule, selector) => { | ||
if (root.type !== 'local') { | ||
@@ -156,7 +260,7 @@ throw new Error(`Selectors are not allowed within ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
const transformedSelector = this.transformSelector(selector.replace(RegExp('&', 'g'), root.selector)); | ||
validateSelector.validateSelector(transformedSelector, root.selector); | ||
validateSelector(transformedSelector, root.selector); | ||
this.addRule({ | ||
conditions, | ||
selector: transformedSelector, | ||
rule: utils.omit(selectorRule, specialKeys) | ||
rule: omit(selectorRule, specialKeys) | ||
}); | ||
@@ -174,3 +278,3 @@ const selectorRoot = { | ||
transformMedia(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (mediaRule, query) => { | ||
forEach(rules, (mediaRule, query) => { | ||
const conditions = [`@media ${query}`, ...parentConditions]; | ||
@@ -180,3 +284,3 @@ this.addRule({ | ||
selector: root.selector, | ||
rule: utils.omit(mediaRule, specialKeys) | ||
rule: omit(mediaRule, specialKeys) | ||
}); | ||
@@ -194,3 +298,3 @@ | ||
transformSupports(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (supportsRule, query) => { | ||
forEach(rules, (supportsRule, query) => { | ||
const conditions = [`@supports ${query}`, ...parentConditions]; | ||
@@ -200,3 +304,3 @@ this.addRule({ | ||
selector: root.selector, | ||
rule: utils.omit(supportsRule, specialKeys) | ||
rule: omit(supportsRule, specialKeys) | ||
}); | ||
@@ -242,3 +346,3 @@ | ||
for (const rule of [...this.rules, ...this.conditionalRules]) { | ||
if (rule.conditions && utils.isEqual(styles[rule.selector], rule.rule)) { | ||
if (rule.conditions && isEqual(styles[rule.selector], rule.rule)) { | ||
// Ignore conditional rules if they are identical to a non-conditional rule | ||
@@ -245,0 +349,0 @@ continue; |
@@ -0,7 +1,118 @@ | ||
import { getVarName } from '@vanilla-extract/private'; | ||
import cssesc from 'cssesc'; | ||
import { v as validateSelector } from '../../dist/validateSelector-2dda5781.browser.esm.js'; | ||
import { o as omit, f as forEach, m as mapKeys, i as isEqual } from '../../dist/utils-24d5030c.browser.esm.js'; | ||
import 'css-selector-parser'; | ||
import 'dedent'; | ||
import { CssSelectorParser } from 'css-selector-parser'; | ||
import dedent from 'dedent'; | ||
function escapeRegex(string) { | ||
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
} | ||
const parser = new CssSelectorParser(); | ||
parser.registerSelectorPseudos('has'); | ||
parser.registerNestingOperators('>', '+', '~'); | ||
parser.registerAttrEqualityMods('^', '$', '*', '~'); | ||
parser.enableSubstitutes(); | ||
const validateSelector = (selector, targetClassName) => { | ||
const replaceTarget = () => { | ||
const targetRegex = new RegExp(`.${escapeRegex(cssesc(targetClassName, { | ||
isIdentifier: true | ||
}))}`, 'g'); | ||
return selector.replace(targetRegex, '&'); | ||
}; | ||
return selector.split(',').map(selectorPart => { | ||
if (selectorPart.indexOf(targetClassName) === -1) { | ||
throw new Error(dedent` | ||
Invalid selector: ${replaceTarget()} | ||
Selectors must target the ampersand character ('&'), which refers to the generated class name, e.g. '&:nth-child(2n)' | ||
`); | ||
} | ||
let currentRule; | ||
try { | ||
const result = parser.parse(selectorPart); | ||
if (result.type === 'ruleSet') { | ||
currentRule = result.rule; | ||
} else { | ||
throw new Error(); | ||
} | ||
} catch (err) { | ||
throw new Error(`Invalid selector: ${replaceTarget()}`); | ||
} | ||
while (currentRule.rule) { | ||
currentRule = currentRule.rule; | ||
} | ||
const targetRule = currentRule; | ||
if (!Array.isArray(targetRule.classNames) || !targetRule.classNames.find(className => className === targetClassName)) { | ||
throw new Error(dedent` | ||
Invalid selector: ${replaceTarget()} | ||
Style selectors must end with the '&' character (along with any modifiers), e.g. ${'`${parent} &`'} or ${'`${parent} &:hover`'}. | ||
This is to ensure that each style block only affects the styling of a single class. | ||
If your selector is targeting another class, you should move it to the style definition for that class, e.g. given we have styles for 'parent' and 'child' elements, instead of adding a selector of ${'`& ${child}`'}) to 'parent', you should add ${'`${parent} &`'} to 'child'). | ||
If your selector is targeting something global, use the 'globalStyle' function instead, e.g. if you wanted to write ${'`& h1`'}, you should instead write 'globalStyle(${'`${parent} h1`'}, { ... })' | ||
`); | ||
} | ||
}); | ||
}; | ||
function forEach(obj, fn) { | ||
for (const key in obj) { | ||
fn(obj[key], key); | ||
} | ||
} | ||
function omit(obj, omitKeys) { | ||
let result = {}; | ||
for (const key in obj) { | ||
if (omitKeys.indexOf(key) === -1) { | ||
result[key] = obj[key]; | ||
} | ||
} | ||
return result; | ||
} | ||
function mapKeys(obj, fn) { | ||
let result = {}; | ||
for (const key in obj) { | ||
result[fn(obj[key], key)] = obj[key]; | ||
} | ||
return result; | ||
} | ||
function isEqual(a, b) { | ||
if (typeof a !== typeof b) { | ||
return false; | ||
} | ||
if (typeof a === 'object') { | ||
const keys1 = Object.keys(a); | ||
const keys2 = Object.keys(b); | ||
if (keys1.length !== keys2.length) { | ||
return false; | ||
} | ||
for (const key in a) { | ||
if (!isEqual(a[key], b[key])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} else { | ||
return a === b; | ||
} | ||
} | ||
const UNITLESS = { | ||
@@ -110,11 +221,3 @@ boxFlex: true, | ||
return { ...mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
return { ...mapKeys(vars, (_value, key) => getVarName(key)), | ||
...rest | ||
@@ -121,0 +224,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
export * from "../../dist/declarations/src/transformCSS"; | ||
export * from "../../dist/declarations/src/transformCss"; |
@@ -5,7 +5,6 @@ 'use strict'; | ||
var _private = require('@vanilla-extract/private'); | ||
var cssesc = require('cssesc'); | ||
var validateSelector = require('../../dist/validateSelector-acadedf9.cjs.dev.js'); | ||
var utils = require('../../dist/utils-c5ab417f.cjs.dev.js'); | ||
require('css-selector-parser'); | ||
require('dedent'); | ||
var cssSelectorParser = require('css-selector-parser'); | ||
var dedent = require('dedent'); | ||
@@ -15,3 +14,116 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; } | ||
var cssesc__default = /*#__PURE__*/_interopDefault(cssesc); | ||
var dedent__default = /*#__PURE__*/_interopDefault(dedent); | ||
function escapeRegex(string) { | ||
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
} | ||
const parser = new cssSelectorParser.CssSelectorParser(); | ||
parser.registerSelectorPseudos('has'); | ||
parser.registerNestingOperators('>', '+', '~'); | ||
parser.registerAttrEqualityMods('^', '$', '*', '~'); | ||
parser.enableSubstitutes(); | ||
const validateSelector = (selector, targetClassName) => { | ||
const replaceTarget = () => { | ||
const targetRegex = new RegExp(`.${escapeRegex(cssesc__default['default'](targetClassName, { | ||
isIdentifier: true | ||
}))}`, 'g'); | ||
return selector.replace(targetRegex, '&'); | ||
}; | ||
return selector.split(',').map(selectorPart => { | ||
if (selectorPart.indexOf(targetClassName) === -1) { | ||
throw new Error(dedent__default['default']` | ||
Invalid selector: ${replaceTarget()} | ||
Selectors must target the ampersand character ('&'), which refers to the generated class name, e.g. '&:nth-child(2n)' | ||
`); | ||
} | ||
let currentRule; | ||
try { | ||
const result = parser.parse(selectorPart); | ||
if (result.type === 'ruleSet') { | ||
currentRule = result.rule; | ||
} else { | ||
throw new Error(); | ||
} | ||
} catch (err) { | ||
throw new Error(`Invalid selector: ${replaceTarget()}`); | ||
} | ||
while (currentRule.rule) { | ||
currentRule = currentRule.rule; | ||
} | ||
const targetRule = currentRule; | ||
if (!Array.isArray(targetRule.classNames) || !targetRule.classNames.find(className => className === targetClassName)) { | ||
throw new Error(dedent__default['default']` | ||
Invalid selector: ${replaceTarget()} | ||
Style selectors must end with the '&' character (along with any modifiers), e.g. ${'`${parent} &`'} or ${'`${parent} &:hover`'}. | ||
This is to ensure that each style block only affects the styling of a single class. | ||
If your selector is targeting another class, you should move it to the style definition for that class, e.g. given we have styles for 'parent' and 'child' elements, instead of adding a selector of ${'`& ${child}`'}) to 'parent', you should add ${'`${parent} &`'} to 'child'). | ||
If your selector is targeting something global, use the 'globalStyle' function instead, e.g. if you wanted to write ${'`& h1`'}, you should instead write 'globalStyle(${'`${parent} h1`'}, { ... })' | ||
`); | ||
} | ||
}); | ||
}; | ||
function forEach(obj, fn) { | ||
for (const key in obj) { | ||
fn(obj[key], key); | ||
} | ||
} | ||
function omit(obj, omitKeys) { | ||
let result = {}; | ||
for (const key in obj) { | ||
if (omitKeys.indexOf(key) === -1) { | ||
result[key] = obj[key]; | ||
} | ||
} | ||
return result; | ||
} | ||
function mapKeys(obj, fn) { | ||
let result = {}; | ||
for (const key in obj) { | ||
result[fn(obj[key], key)] = obj[key]; | ||
} | ||
return result; | ||
} | ||
function isEqual(a, b) { | ||
if (typeof a !== typeof b) { | ||
return false; | ||
} | ||
if (typeof a === 'object') { | ||
const keys1 = Object.keys(a); | ||
const keys2 = Object.keys(b); | ||
if (keys1.length !== keys2.length) { | ||
return false; | ||
} | ||
for (const key in a) { | ||
if (!isEqual(a[key], b[key])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} else { | ||
return a === b; | ||
} | ||
} | ||
const UNITLESS = { | ||
@@ -72,3 +184,3 @@ boxFlex: true, | ||
const mainRule = utils.omit(root.rule, specialKeys); | ||
const mainRule = omit(root.rule, specialKeys); | ||
this.addRule({ | ||
@@ -104,3 +216,3 @@ selector: root.selector, | ||
pixelifyProperties(cssRule) { | ||
utils.forEach(cssRule, (value, key) => { | ||
forEach(cssRule, (value, key) => { | ||
if (typeof value === 'number' && value !== 0 && !UNITLESS[key]) { | ||
@@ -122,11 +234,3 @@ // @ts-expect-error Any ideas? | ||
return { ...utils.mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
return { ...mapKeys(vars, (_value, key) => _private.getVarName(key)), | ||
...rest | ||
@@ -149,3 +253,3 @@ }; | ||
transformSelectors(root, rule, conditions) { | ||
utils.forEach(rule.selectors, (selectorRule, selector) => { | ||
forEach(rule.selectors, (selectorRule, selector) => { | ||
if (root.type !== 'local') { | ||
@@ -156,7 +260,7 @@ throw new Error(`Selectors are not allowed within ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
const transformedSelector = this.transformSelector(selector.replace(RegExp('&', 'g'), root.selector)); | ||
validateSelector.validateSelector(transformedSelector, root.selector); | ||
validateSelector(transformedSelector, root.selector); | ||
this.addRule({ | ||
conditions, | ||
selector: transformedSelector, | ||
rule: utils.omit(selectorRule, specialKeys) | ||
rule: omit(selectorRule, specialKeys) | ||
}); | ||
@@ -174,3 +278,3 @@ const selectorRoot = { | ||
transformMedia(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (mediaRule, query) => { | ||
forEach(rules, (mediaRule, query) => { | ||
const conditions = [`@media ${query}`, ...parentConditions]; | ||
@@ -180,3 +284,3 @@ this.addRule({ | ||
selector: root.selector, | ||
rule: utils.omit(mediaRule, specialKeys) | ||
rule: omit(mediaRule, specialKeys) | ||
}); | ||
@@ -194,3 +298,3 @@ | ||
transformSupports(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (supportsRule, query) => { | ||
forEach(rules, (supportsRule, query) => { | ||
const conditions = [`@supports ${query}`, ...parentConditions]; | ||
@@ -200,3 +304,3 @@ this.addRule({ | ||
selector: root.selector, | ||
rule: utils.omit(supportsRule, specialKeys) | ||
rule: omit(supportsRule, specialKeys) | ||
}); | ||
@@ -242,3 +346,3 @@ | ||
for (const rule of [...this.rules, ...this.conditionalRules]) { | ||
if (rule.conditions && utils.isEqual(styles[rule.selector], rule.rule)) { | ||
if (rule.conditions && isEqual(styles[rule.selector], rule.rule)) { | ||
// Ignore conditional rules if they are identical to a non-conditional rule | ||
@@ -245,0 +349,0 @@ continue; |
@@ -5,7 +5,6 @@ 'use strict'; | ||
var _private = require('@vanilla-extract/private'); | ||
var cssesc = require('cssesc'); | ||
var validateSelector = require('../../dist/validateSelector-5a593081.cjs.prod.js'); | ||
var utils = require('../../dist/utils-2b734f0b.cjs.prod.js'); | ||
require('css-selector-parser'); | ||
require('dedent'); | ||
var cssSelectorParser = require('css-selector-parser'); | ||
var dedent = require('dedent'); | ||
@@ -15,3 +14,116 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; } | ||
var cssesc__default = /*#__PURE__*/_interopDefault(cssesc); | ||
var dedent__default = /*#__PURE__*/_interopDefault(dedent); | ||
function escapeRegex(string) { | ||
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
} | ||
const parser = new cssSelectorParser.CssSelectorParser(); | ||
parser.registerSelectorPseudos('has'); | ||
parser.registerNestingOperators('>', '+', '~'); | ||
parser.registerAttrEqualityMods('^', '$', '*', '~'); | ||
parser.enableSubstitutes(); | ||
const validateSelector = (selector, targetClassName) => { | ||
const replaceTarget = () => { | ||
const targetRegex = new RegExp(`.${escapeRegex(cssesc__default['default'](targetClassName, { | ||
isIdentifier: true | ||
}))}`, 'g'); | ||
return selector.replace(targetRegex, '&'); | ||
}; | ||
return selector.split(',').map(selectorPart => { | ||
if (selectorPart.indexOf(targetClassName) === -1) { | ||
throw new Error(dedent__default['default']` | ||
Invalid selector: ${replaceTarget()} | ||
Selectors must target the ampersand character ('&'), which refers to the generated class name, e.g. '&:nth-child(2n)' | ||
`); | ||
} | ||
let currentRule; | ||
try { | ||
const result = parser.parse(selectorPart); | ||
if (result.type === 'ruleSet') { | ||
currentRule = result.rule; | ||
} else { | ||
throw new Error(); | ||
} | ||
} catch (err) { | ||
throw new Error(`Invalid selector: ${replaceTarget()}`); | ||
} | ||
while (currentRule.rule) { | ||
currentRule = currentRule.rule; | ||
} | ||
const targetRule = currentRule; | ||
if (!Array.isArray(targetRule.classNames) || !targetRule.classNames.find(className => className === targetClassName)) { | ||
throw new Error(dedent__default['default']` | ||
Invalid selector: ${replaceTarget()} | ||
Style selectors must end with the '&' character (along with any modifiers), e.g. ${'`${parent} &`'} or ${'`${parent} &:hover`'}. | ||
This is to ensure that each style block only affects the styling of a single class. | ||
If your selector is targeting another class, you should move it to the style definition for that class, e.g. given we have styles for 'parent' and 'child' elements, instead of adding a selector of ${'`& ${child}`'}) to 'parent', you should add ${'`${parent} &`'} to 'child'). | ||
If your selector is targeting something global, use the 'globalStyle' function instead, e.g. if you wanted to write ${'`& h1`'}, you should instead write 'globalStyle(${'`${parent} h1`'}, { ... })' | ||
`); | ||
} | ||
}); | ||
}; | ||
function forEach(obj, fn) { | ||
for (const key in obj) { | ||
fn(obj[key], key); | ||
} | ||
} | ||
function omit(obj, omitKeys) { | ||
let result = {}; | ||
for (const key in obj) { | ||
if (omitKeys.indexOf(key) === -1) { | ||
result[key] = obj[key]; | ||
} | ||
} | ||
return result; | ||
} | ||
function mapKeys(obj, fn) { | ||
let result = {}; | ||
for (const key in obj) { | ||
result[fn(obj[key], key)] = obj[key]; | ||
} | ||
return result; | ||
} | ||
function isEqual(a, b) { | ||
if (typeof a !== typeof b) { | ||
return false; | ||
} | ||
if (typeof a === 'object') { | ||
const keys1 = Object.keys(a); | ||
const keys2 = Object.keys(b); | ||
if (keys1.length !== keys2.length) { | ||
return false; | ||
} | ||
for (const key in a) { | ||
if (!isEqual(a[key], b[key])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} else { | ||
return a === b; | ||
} | ||
} | ||
const UNITLESS = { | ||
@@ -72,3 +184,3 @@ boxFlex: true, | ||
const mainRule = utils.omit(root.rule, specialKeys); | ||
const mainRule = omit(root.rule, specialKeys); | ||
this.addRule({ | ||
@@ -104,3 +216,3 @@ selector: root.selector, | ||
pixelifyProperties(cssRule) { | ||
utils.forEach(cssRule, (value, key) => { | ||
forEach(cssRule, (value, key) => { | ||
if (typeof value === 'number' && value !== 0 && !UNITLESS[key]) { | ||
@@ -122,11 +234,3 @@ // @ts-expect-error Any ideas? | ||
return { ...utils.mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
return { ...mapKeys(vars, (_value, key) => _private.getVarName(key)), | ||
...rest | ||
@@ -149,3 +253,3 @@ }; | ||
transformSelectors(root, rule, conditions) { | ||
utils.forEach(rule.selectors, (selectorRule, selector) => { | ||
forEach(rule.selectors, (selectorRule, selector) => { | ||
if (root.type !== 'local') { | ||
@@ -156,7 +260,7 @@ throw new Error(`Selectors are not allowed within ${root.type === 'global' ? '"globalStyle"' : '"selectors"'}`); | ||
const transformedSelector = this.transformSelector(selector.replace(RegExp('&', 'g'), root.selector)); | ||
validateSelector.validateSelector(transformedSelector, root.selector); | ||
validateSelector(transformedSelector, root.selector); | ||
this.addRule({ | ||
conditions, | ||
selector: transformedSelector, | ||
rule: utils.omit(selectorRule, specialKeys) | ||
rule: omit(selectorRule, specialKeys) | ||
}); | ||
@@ -174,3 +278,3 @@ const selectorRoot = { | ||
transformMedia(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (mediaRule, query) => { | ||
forEach(rules, (mediaRule, query) => { | ||
const conditions = [`@media ${query}`, ...parentConditions]; | ||
@@ -180,3 +284,3 @@ this.addRule({ | ||
selector: root.selector, | ||
rule: utils.omit(mediaRule, specialKeys) | ||
rule: omit(mediaRule, specialKeys) | ||
}); | ||
@@ -194,3 +298,3 @@ | ||
transformSupports(root, rules, parentConditions = []) { | ||
utils.forEach(rules, (supportsRule, query) => { | ||
forEach(rules, (supportsRule, query) => { | ||
const conditions = [`@supports ${query}`, ...parentConditions]; | ||
@@ -200,3 +304,3 @@ this.addRule({ | ||
selector: root.selector, | ||
rule: utils.omit(supportsRule, specialKeys) | ||
rule: omit(supportsRule, specialKeys) | ||
}); | ||
@@ -242,3 +346,3 @@ | ||
for (const rule of [...this.rules, ...this.conditionalRules]) { | ||
if (rule.conditions && utils.isEqual(styles[rule.selector], rule.rule)) { | ||
if (rule.conditions && isEqual(styles[rule.selector], rule.rule)) { | ||
// Ignore conditional rules if they are identical to a non-conditional rule | ||
@@ -245,0 +349,0 @@ continue; |
@@ -0,7 +1,118 @@ | ||
import { getVarName } from '@vanilla-extract/private'; | ||
import cssesc from 'cssesc'; | ||
import { v as validateSelector } from '../../dist/validateSelector-cfc75bf8.esm.js'; | ||
import { o as omit, f as forEach, m as mapKeys, i as isEqual } from '../../dist/utils-fbd6ce24.esm.js'; | ||
import 'css-selector-parser'; | ||
import 'dedent'; | ||
import { CssSelectorParser } from 'css-selector-parser'; | ||
import dedent from 'dedent'; | ||
function escapeRegex(string) { | ||
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | ||
} | ||
const parser = new CssSelectorParser(); | ||
parser.registerSelectorPseudos('has'); | ||
parser.registerNestingOperators('>', '+', '~'); | ||
parser.registerAttrEqualityMods('^', '$', '*', '~'); | ||
parser.enableSubstitutes(); | ||
const validateSelector = (selector, targetClassName) => { | ||
const replaceTarget = () => { | ||
const targetRegex = new RegExp(`.${escapeRegex(cssesc(targetClassName, { | ||
isIdentifier: true | ||
}))}`, 'g'); | ||
return selector.replace(targetRegex, '&'); | ||
}; | ||
return selector.split(',').map(selectorPart => { | ||
if (selectorPart.indexOf(targetClassName) === -1) { | ||
throw new Error(dedent` | ||
Invalid selector: ${replaceTarget()} | ||
Selectors must target the ampersand character ('&'), which refers to the generated class name, e.g. '&:nth-child(2n)' | ||
`); | ||
} | ||
let currentRule; | ||
try { | ||
const result = parser.parse(selectorPart); | ||
if (result.type === 'ruleSet') { | ||
currentRule = result.rule; | ||
} else { | ||
throw new Error(); | ||
} | ||
} catch (err) { | ||
throw new Error(`Invalid selector: ${replaceTarget()}`); | ||
} | ||
while (currentRule.rule) { | ||
currentRule = currentRule.rule; | ||
} | ||
const targetRule = currentRule; | ||
if (!Array.isArray(targetRule.classNames) || !targetRule.classNames.find(className => className === targetClassName)) { | ||
throw new Error(dedent` | ||
Invalid selector: ${replaceTarget()} | ||
Style selectors must end with the '&' character (along with any modifiers), e.g. ${'`${parent} &`'} or ${'`${parent} &:hover`'}. | ||
This is to ensure that each style block only affects the styling of a single class. | ||
If your selector is targeting another class, you should move it to the style definition for that class, e.g. given we have styles for 'parent' and 'child' elements, instead of adding a selector of ${'`& ${child}`'}) to 'parent', you should add ${'`${parent} &`'} to 'child'). | ||
If your selector is targeting something global, use the 'globalStyle' function instead, e.g. if you wanted to write ${'`& h1`'}, you should instead write 'globalStyle(${'`${parent} h1`'}, { ... })' | ||
`); | ||
} | ||
}); | ||
}; | ||
function forEach(obj, fn) { | ||
for (const key in obj) { | ||
fn(obj[key], key); | ||
} | ||
} | ||
function omit(obj, omitKeys) { | ||
let result = {}; | ||
for (const key in obj) { | ||
if (omitKeys.indexOf(key) === -1) { | ||
result[key] = obj[key]; | ||
} | ||
} | ||
return result; | ||
} | ||
function mapKeys(obj, fn) { | ||
let result = {}; | ||
for (const key in obj) { | ||
result[fn(obj[key], key)] = obj[key]; | ||
} | ||
return result; | ||
} | ||
function isEqual(a, b) { | ||
if (typeof a !== typeof b) { | ||
return false; | ||
} | ||
if (typeof a === 'object') { | ||
const keys1 = Object.keys(a); | ||
const keys2 = Object.keys(b); | ||
if (keys1.length !== keys2.length) { | ||
return false; | ||
} | ||
for (const key in a) { | ||
if (!isEqual(a[key], b[key])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} else { | ||
return a === b; | ||
} | ||
} | ||
const UNITLESS = { | ||
@@ -110,11 +221,3 @@ boxFlex: true, | ||
return { ...mapKeys(vars, (_value, key) => { | ||
const matches = key.match(/^var\((.*)\)$/); | ||
if (matches) { | ||
return matches[1]; | ||
} | ||
return key; | ||
}), | ||
return { ...mapKeys(vars, (_value, key) => getVarName(key)), | ||
...rest | ||
@@ -121,0 +224,0 @@ }; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
697
12
138275
6
46
3266
1
+ Added@vanilla-extract/private@0.1.2(transitive)