|
|
@ -1,5 +1,9 @@
|
|
|
|
|
|
|
|
import { convert } from 'chromatism'
|
|
|
|
|
|
|
|
import { alphaBlend, getTextColor, rgba2css } from '../color_convert/color_convert.js'
|
|
|
|
|
|
|
|
|
|
|
|
import Underlay from 'src/components/underlay.style.js'
|
|
|
|
import Underlay from 'src/components/underlay.style.js'
|
|
|
|
import Panel from 'src/components/panel.style.js'
|
|
|
|
import Panel from 'src/components/panel.style.js'
|
|
|
|
|
|
|
|
import PanelHeader from 'src/components/panel_header.style.js'
|
|
|
|
import Button from 'src/components/button.style.js'
|
|
|
|
import Button from 'src/components/button.style.js'
|
|
|
|
import Text from 'src/components/text.style.js'
|
|
|
|
import Text from 'src/components/text.style.js'
|
|
|
|
import Icon from 'src/components/icon.style.js'
|
|
|
|
import Icon from 'src/components/icon.style.js'
|
|
|
@ -8,6 +12,7 @@ const root = Underlay
|
|
|
|
const components = {
|
|
|
|
const components = {
|
|
|
|
Underlay,
|
|
|
|
Underlay,
|
|
|
|
Panel,
|
|
|
|
Panel,
|
|
|
|
|
|
|
|
PanelHeader,
|
|
|
|
Button,
|
|
|
|
Button,
|
|
|
|
Text,
|
|
|
|
Text,
|
|
|
|
Icon
|
|
|
|
Icon
|
|
|
@ -34,7 +39,7 @@ export const ruleToSelector = (rule) => {
|
|
|
|
const component = components[rule.component]
|
|
|
|
const component = components[rule.component]
|
|
|
|
const { states, variants, selector } = component
|
|
|
|
const { states, variants, selector } = component
|
|
|
|
|
|
|
|
|
|
|
|
const applicableStates = (rule.state.filter(x => x !== 'normal') || []).map(state => states[state])
|
|
|
|
const applicableStates = ((rule.state || []).filter(x => x !== 'normal')).map(state => states[state])
|
|
|
|
|
|
|
|
|
|
|
|
const applicableVariantName = (rule.variant || 'normal')
|
|
|
|
const applicableVariantName = (rule.variant || 'normal')
|
|
|
|
let applicableVariant = ''
|
|
|
|
let applicableVariant = ''
|
|
|
@ -63,12 +68,37 @@ export const init = (ruleset) => {
|
|
|
|
const addRule = (rule) => {
|
|
|
|
const addRule = (rule) => {
|
|
|
|
rules.push(rule)
|
|
|
|
rules.push(rule)
|
|
|
|
rulesByComponent[rule.component] = rulesByComponent[rule.component] || []
|
|
|
|
rulesByComponent[rule.component] = rulesByComponent[rule.component] || []
|
|
|
|
rulesByComponent.push(rule)
|
|
|
|
rulesByComponent[rule.component].push(rule)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ruleset.forEach(rule => {
|
|
|
|
const findRules = (combination) => rule => {
|
|
|
|
|
|
|
|
if (combination.component !== rule.component) return false
|
|
|
|
|
|
|
|
if (Object.prototype.hasOwnProperty.call(rule, 'variant')) {
|
|
|
|
|
|
|
|
if (combination.variant !== rule.variant) return false
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (combination.variant !== 'normal') return false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (Object.prototype.hasOwnProperty.call(rule, 'state')) {
|
|
|
|
|
|
|
|
const ruleStatesSet = new Set(['normal', ...(rule.state || [])])
|
|
|
|
|
|
|
|
return combination.state.every(state => ruleStatesSet.has(state))
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (combination.state.length !== 1 || combination.state[0] !== 'normal') return false
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
const findLowerLevelRule = (parent, filter = () => true) => {
|
|
|
|
|
|
|
|
let lowerLevelComponent = null
|
|
|
|
|
|
|
|
let currentParent = parent
|
|
|
|
|
|
|
|
while (currentParent) {
|
|
|
|
|
|
|
|
const rulesParent = ruleset.filter(findRules(currentParent, true))
|
|
|
|
|
|
|
|
lowerLevelComponent = rulesParent[rulesParent.length - 1]
|
|
|
|
|
|
|
|
currentParent = currentParent.parent
|
|
|
|
|
|
|
|
if (lowerLevelComponent && filter(lowerLevelComponent)) currentParent = null
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return filter(lowerLevelComponent) ? lowerLevelComponent : null
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const processInnerComponent = (component, parent) => {
|
|
|
|
const processInnerComponent = (component, parent) => {
|
|
|
|
const {
|
|
|
|
const {
|
|
|
@ -87,18 +117,82 @@ export const init = (ruleset) => {
|
|
|
|
return stateCombinations.map(state => ({ variant, state }))
|
|
|
|
return stateCombinations.map(state => ({ variant, state }))
|
|
|
|
}).reduce((acc, x) => [...acc, ...x], [])
|
|
|
|
}).reduce((acc, x) => [...acc, ...x], [])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const VIRTUAL_COMPONENTS = new Set(['Text', 'Link', 'Icon'])
|
|
|
|
|
|
|
|
|
|
|
|
stateVariantCombination.forEach(combination => {
|
|
|
|
stateVariantCombination.forEach(combination => {
|
|
|
|
// addRule(({
|
|
|
|
const existingRules = ruleset.filter(findRules({ component: component.name, ...combination }))
|
|
|
|
// parent,
|
|
|
|
const lastRule = existingRules[existingRules.length - 1]
|
|
|
|
// component: component.name,
|
|
|
|
|
|
|
|
// state: combination.state,
|
|
|
|
if (existingRules.length !== 0) {
|
|
|
|
// variant: combination.variant
|
|
|
|
const { directives } = lastRule
|
|
|
|
// }))
|
|
|
|
const rgb = convert(directives.background).rgb
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: DEFAULT TEXT COLOR
|
|
|
|
|
|
|
|
const bg = findLowerLevelRule(parent)?.cache.background || convert('#FFFFFF').rgb
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!lastRule.cache?.background) {
|
|
|
|
|
|
|
|
const blend = directives.opacity < 1 ? alphaBlend(rgb, directives.opacity, bg) : rgb
|
|
|
|
|
|
|
|
lastRule.cache = lastRule.cache || {}
|
|
|
|
|
|
|
|
lastRule.cache.background = blend
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
addRule(lastRule)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (VIRTUAL_COMPONENTS.has(component.name)) {
|
|
|
|
|
|
|
|
const selector = component.name + ruleToSelector({ component: component.name, ...combination })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const lowerLevel = findLowerLevelRule(parent, (r) => {
|
|
|
|
|
|
|
|
if (components[r.component].validInnerComponents.indexOf(component.name) < 0) return false
|
|
|
|
|
|
|
|
if (r.cache?.background === undefined) return false
|
|
|
|
|
|
|
|
if (r.cache.textDefined) {
|
|
|
|
|
|
|
|
return !r.cache.textDefined[selector]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
if (!lowerLevel) return
|
|
|
|
|
|
|
|
lowerLevel.cache.textDefined = lowerLevel.cache.textDefined || {}
|
|
|
|
|
|
|
|
lowerLevel.cache.textDefined[selector] = true
|
|
|
|
|
|
|
|
addRule({
|
|
|
|
|
|
|
|
parent,
|
|
|
|
|
|
|
|
component: component.name,
|
|
|
|
|
|
|
|
...combination,
|
|
|
|
|
|
|
|
directives: {
|
|
|
|
|
|
|
|
// TODO: DEFAULT TEXT COLOR
|
|
|
|
|
|
|
|
textColor: getTextColor(convert(lowerLevel.cache.background).rgb, convert('#FFFFFF').rgb, component.name === 'Link'),
|
|
|
|
|
|
|
|
// Debug: lets you see what it think background color should be
|
|
|
|
|
|
|
|
background: convert(lowerLevel.cache.background).hex
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
innerComponents.forEach(innerComponent => processInnerComponent(innerComponent, { parent, component: name, ...combination }))
|
|
|
|
innerComponents.forEach(innerComponent => processInnerComponent(innerComponent, { parent, component: name, ...combination }))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
processInnerComponent(components[rootName])
|
|
|
|
processInnerComponent(components[rootName])
|
|
|
|
return rules
|
|
|
|
|
|
|
|
|
|
|
|
// console.info(rules.map(x => [
|
|
|
|
|
|
|
|
// (parent?.component || 'root') + ' -> ' + x.component,
|
|
|
|
|
|
|
|
// // 'Cached background:' + convert(bg).hex,
|
|
|
|
|
|
|
|
// // 'Color: ' + convert(x.directives.background).hex + ' A:' + x.directives.opacity,
|
|
|
|
|
|
|
|
// JSON.stringify(x.directives)
|
|
|
|
|
|
|
|
// // '=> Blend: ' + convert(x.cache.background).hex
|
|
|
|
|
|
|
|
// ].join(' ')))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
raw: rules,
|
|
|
|
|
|
|
|
css: rules.map(rule => {
|
|
|
|
|
|
|
|
const header = ruleToSelector(rule) + ' {'
|
|
|
|
|
|
|
|
const footer = '}'
|
|
|
|
|
|
|
|
const directives = Object.entries(rule.directives).map(([k, v]) => {
|
|
|
|
|
|
|
|
switch (k) {
|
|
|
|
|
|
|
|
case 'background': return 'background-color: ' + rgba2css({ ...convert(v).rgb, a: rule.directives.opacity ?? 1 })
|
|
|
|
|
|
|
|
case 'textColor': return 'color: ' + rgba2css({ ...convert(v).rgb, a: rule.directives.opacity ?? 1 })
|
|
|
|
|
|
|
|
default: return ''
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}).filter(x => x).map(x => ' ' + x).join(';\n')
|
|
|
|
|
|
|
|
return [header, directives, footer].join('\n')
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|