Home Reference Source

src/style/Stylesheet.js

import { Declaration, DeclarationList } from './Declaration.js'
import { Combinator, SelectorElement, SelectorFragmentList } from './Selector.js'

/**
Stylesheet is initialized with KSS data JSON emitted by postcss-potassium. 
It holds the parsed data used to apply styles to a Three.js scene.
*/
class Stylesheet {
	/**
	@param {Object} kssData - the style JSON emitted by postcss-potassium
	*/
	constructor(kssData) {
		this._data = kssData
		for (let i = 0; i < this._data.rules.length; i++) {
			this._data.rules[i].index = i
			this._data.rules[i].selectors = this._parseSelectors(this._data.rules[i].selectors)
			this._data.rules[i].declarations = this._parseDeclarations(this._data.rules[i].declarations)
		}
		this._loadIndex = -1 // Will be set by Stylist
	}

	/**
	The Stylist sets this to the index in the load order the stylesheet
	Used to break ties in cascade precedence
	*/
	get loadIndex() {
		return this._loadIndex
	}
	set loadIndex(val) {
		this._loadIndex = val
	}

	get data() {
		return this._data
	}

	get raw() {
		const lines = []
		for (const rule of this._data.rules) {
			for (const selector of rule.selectors) {
				lines.push(selector.raw)
			}
			lines.push('{')
			for (const declaration of rule.declarations) {
				lines.push('\t' + declaration.raw)
			}
			lines.push('}\n')
		}
		return lines.join('\n')
	}

	updateLocalStyles(node) {
		// Now test each rule
		for (const rule of this._data.rules) {
			const matchingSelector = rule.selectors.find(sfList => sfList.matches(node))
			if (!matchingSelector) continue
			node.styles.matchingRules.push({
				rule: rule,
				stylesheet: this,
				selector: matchingSelector
			})
			for (const declaration of rule.declarations) {
				node.styles.localStyles.add(declaration, matchingSelector, this, rule)
			}
			node.styles.localStyles.sort()
		}
	}

	/**
	@param {Array<string>} rawSelectors selector strings
	@return {Array<SelectorFragmentList>}
	*/
	_parseSelectors(rawSelectors) {
		return rawSelectors.map(rawSelector => {
			return SelectorFragmentList.Parse(rawSelector)
		})
	}

	/**
	@param rawDeclarations {Array<string>}
	@return {Array<DeclarationList>}
	*/
	_parseDeclarations(rawDeclarations) {
		const declarations = rawDeclarations.map(rawDeclaration => new Declaration(rawDeclaration))
		return new DeclarationList(declarations)
	}
}

export default Stylesheet