commit: b55aeb54f659cf1cdb7f1f006447c99def0d583d
parent f46adb6724bccc39cbb3f3723f29724dfb600395
Author: Henry Jameson <me@hjkos.com>
Date: Fri, 25 Oct 2024 16:39:37 +0300
better error reporting
Diffstat:
2 files changed, 240 insertions(+), 219 deletions(-)
diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js
@@ -732,10 +732,18 @@ export default {
.reduce((acc, [k, v]) => ({ ...acc, [k]: `color | ${v}` }), {})
}
+ const virtualDirectivesRule = {
+ component: 'Root',
+ directives: Object.fromEntries(
+ virtualDirectives.map(vd => [`--${vd.name}`, `${vd.valType} | ${vd.value}`])
+ )
+ }
+
const rules = init({
inputRuleset: [
- ...editorFriendlyToOriginal.value,
- paletteRule
+ paletteRule,
+ virtualDirectivesRule,
+ ...editorFriendlyToOriginal.value
],
ultimateBackgroundColor: '#000000',
liteMode: true,
diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js
@@ -63,54 +63,62 @@ export const findShadow = (shadows, { dynamicVars, staticVars }) => {
}
export const findColor = (color, { dynamicVars, staticVars }) => {
- if (typeof color !== 'string' || (!color.startsWith('--') && !color.startsWith('$'))) return color
- let targetColor = null
- if (color.startsWith('--')) {
- // Modifier support is pretty much for v2 themes only
- const [variable, modifier] = color.split(/,/g).map(str => str.trim())
- const variableSlot = variable.substring(2)
- if (variableSlot === 'stack') {
- const { r, g, b } = dynamicVars.stacked
- targetColor = { r, g, b }
- } else if (variableSlot.startsWith('parent')) {
- if (variableSlot === 'parent') {
- const { r, g, b } = dynamicVars.lowerLevelBackground
+ try {
+ if (typeof color !== 'string' || (!color.startsWith('--') && !color.startsWith('$'))) return color
+ let targetColor = null
+ if (color.startsWith('--')) {
+ // Modifier support is pretty much for v2 themes only
+ const [variable, modifier] = color.split(/,/g).map(str => str.trim())
+ const variableSlot = variable.substring(2)
+ if (variableSlot === 'stack') {
+ const { r, g, b } = dynamicVars.stacked
targetColor = { r, g, b }
+ } else if (variableSlot.startsWith('parent')) {
+ if (variableSlot === 'parent') {
+ const { r, g, b } = dynamicVars.lowerLevelBackground
+ targetColor = { r, g, b }
+ } else {
+ const virtualSlot = variableSlot.replace(/^parent/, '')
+ targetColor = convert(dynamicVars.lowerLevelVirtualDirectivesRaw[virtualSlot]).rgb
+ }
} else {
- const virtualSlot = variableSlot.replace(/^parent/, '')
- targetColor = convert(dynamicVars.lowerLevelVirtualDirectivesRaw[virtualSlot]).rgb
- }
- } else {
- switch (variableSlot) {
- case 'inheritedBackground':
- targetColor = convert(dynamicVars.inheritedBackground).rgb
- break
- case 'background':
- targetColor = convert(dynamicVars.background).rgb
- break
- default:
- targetColor = convert(staticVars[variableSlot]).rgb
+ switch (variableSlot) {
+ case 'inheritedBackground':
+ targetColor = convert(dynamicVars.inheritedBackground).rgb
+ break
+ case 'background':
+ targetColor = convert(dynamicVars.background).rgb
+ break
+ default:
+ targetColor = convert(staticVars[variableSlot]).rgb
+ }
}
- }
- if (modifier) {
- const effectiveBackground = dynamicVars.lowerLevelBackground ?? targetColor
- const isLightOnDark = relativeLuminance(convert(effectiveBackground).rgb) < 0.5
- const mod = isLightOnDark ? 1 : -1
- targetColor = brightness(Number.parseFloat(modifier) * mod, targetColor).rgb
+ if (modifier) {
+ const effectiveBackground = dynamicVars.lowerLevelBackground ?? targetColor
+ const isLightOnDark = relativeLuminance(convert(effectiveBackground).rgb) < 0.5
+ const mod = isLightOnDark ? 1 : -1
+ targetColor = brightness(Number.parseFloat(modifier) * mod, targetColor).rgb
+ }
}
- }
- if (color.startsWith('$')) {
- try {
- targetColor = process(color, colorFunctions, { findColor }, { dynamicVars, staticVars })
- } catch (e) {
- console.error('Failure executing color function', e)
- targetColor = '#FF00FF'
+ if (color.startsWith('$')) {
+ try {
+ targetColor = process(color, colorFunctions, { findColor }, { dynamicVars, staticVars })
+ } catch (e) {
+ console.error('Failure executing color function', e)
+ targetColor = '#FF00FF'
+ }
}
+ // Color references other color
+ return targetColor
+ } catch (e) {
+ throw new Error(`Couldn't find color "${color}", variables are:
+Static:
+${JSON.stringify(staticVars, null, 2)}
+Dynamic:
+${JSON.stringify(dynamicVars, null, 2)}`)
}
- // Color references other color
- return targetColor
}
const getTextColorAlpha = (directives, intendedTextColor, dynamicVars, staticVars) => {
@@ -241,212 +249,217 @@ export const init = ({
const nonEditableComponents = new Set(Object.values(components).filter(c => c.notEditable).map(c => c.name))
const processCombination = (combination) => {
- const selector = ruleToSelector(combination, true)
- const cssSelector = ruleToSelector(combination)
-
- const parentSelector = selector.split(/ /g).slice(0, -1).join(' ')
- const soloSelector = selector.split(/ /g).slice(-1)[0]
-
- const lowerLevelSelector = parentSelector
- let lowerLevelBackground = computed[lowerLevelSelector]?.background
- if (editMode && !lowerLevelBackground) {
- // FIXME hack for editor until it supports handling component backgrounds
- lowerLevelBackground = '#00FFFF'
- }
- const lowerLevelVirtualDirectives = computed[lowerLevelSelector]?.virtualDirectives
- const lowerLevelVirtualDirectivesRaw = computed[lowerLevelSelector]?.virtualDirectivesRaw
+ try {
+ const selector = ruleToSelector(combination, true)
+ const cssSelector = ruleToSelector(combination)
- const dynamicVars = computed[selector] || {
- lowerLevelBackground,
- lowerLevelVirtualDirectives,
- lowerLevelVirtualDirectivesRaw
- }
+ const parentSelector = selector.split(/ /g).slice(0, -1).join(' ')
+ const soloSelector = selector.split(/ /g).slice(-1)[0]
- // Inheriting all of the applicable rules
- const existingRules = ruleset.filter(findRules(combination))
- const computedDirectives =
- existingRules
- .map(r => r.directives)
- .reduce((acc, directives) => ({ ...acc, ...directives }), {})
- const computedRule = {
- ...combination,
- directives: computedDirectives
- }
-
- computed[selector] = computed[selector] || {}
- computed[selector].computedRule = computedRule
- computed[selector].dynamicVars = dynamicVars
-
- if (virtualComponents.has(combination.component)) {
- const virtualName = [
- '--',
- combination.component.toLowerCase(),
- combination.variant === 'normal'
- ? ''
- : combination.variant[0].toUpperCase() + combination.variant.slice(1).toLowerCase(),
- ...sortBy(combination.state.filter(x => x !== 'normal')).map(state => state[0].toUpperCase() + state.slice(1).toLowerCase())
- ].join('')
-
- let inheritedTextColor = computedDirectives.textColor
- let inheritedTextAuto = computedDirectives.textAuto
- let inheritedTextOpacity = computedDirectives.textOpacity
- let inheritedTextOpacityMode = computedDirectives.textOpacityMode
- const lowerLevelTextSelector = [...selector.split(/ /g).slice(0, -1), soloSelector].join(' ')
- const lowerLevelTextRule = computed[lowerLevelTextSelector]
-
- if (inheritedTextColor == null || inheritedTextOpacity == null || inheritedTextOpacityMode == null) {
- inheritedTextColor = computedDirectives.textColor ?? lowerLevelTextRule.textColor
- inheritedTextAuto = computedDirectives.textAuto ?? lowerLevelTextRule.textAuto
- inheritedTextOpacity = computedDirectives.textOpacity ?? lowerLevelTextRule.textOpacity
- inheritedTextOpacityMode = computedDirectives.textOpacityMode ?? lowerLevelTextRule.textOpacityMode
+ const lowerLevelSelector = parentSelector
+ let lowerLevelBackground = computed[lowerLevelSelector]?.background
+ if (editMode && !lowerLevelBackground) {
+ // FIXME hack for editor until it supports handling component backgrounds
+ lowerLevelBackground = '#00FFFF'
}
+ const lowerLevelVirtualDirectives = computed[lowerLevelSelector]?.virtualDirectives
+ const lowerLevelVirtualDirectivesRaw = computed[lowerLevelSelector]?.virtualDirectivesRaw
- const newTextRule = {
- ...computedRule,
- directives: {
- ...computedRule.directives,
- textColor: inheritedTextColor,
- textAuto: inheritedTextAuto ?? 'preserve',
- textOpacity: inheritedTextOpacity,
- textOpacityMode: inheritedTextOpacityMode
- }
+ const dynamicVars = computed[selector] || {
+ lowerLevelBackground,
+ lowerLevelVirtualDirectives,
+ lowerLevelVirtualDirectivesRaw
}
- dynamicVars.inheritedBackground = lowerLevelBackground
- dynamicVars.stacked = convert(stacked[lowerLevelSelector]).rgb
-
- const intendedTextColor = convert(findColor(inheritedTextColor, { dynamicVars, staticVars })).rgb
- const textColor = newTextRule.directives.textAuto === 'no-auto'
- ? intendedTextColor
- : getTextColor(
- convert(stacked[lowerLevelSelector]).rgb,
- intendedTextColor,
- newTextRule.directives.textAuto === 'preserve'
- )
- const virtualDirectives = computed[lowerLevelSelector].virtualDirectives || {}
- const virtualDirectivesRaw = computed[lowerLevelSelector].virtualDirectivesRaw || {}
-
- // Storing color data in lower layer to use as custom css properties
- virtualDirectives[virtualName] = getTextColorAlpha(newTextRule.directives, textColor, dynamicVars)
- virtualDirectivesRaw[virtualName] = textColor
-
- computed[lowerLevelSelector].virtualDirectives = virtualDirectives
- computed[lowerLevelSelector].virtualDirectivesRaw = virtualDirectivesRaw
-
- return {
- dynamicVars,
- selector: cssSelector.split(/ /g).slice(0, -1).join(' '),
+ // Inheriting all of the applicable rules
+ const existingRules = ruleset.filter(findRules(combination))
+ const computedDirectives =
+ existingRules
+ .map(r => r.directives)
+ .reduce((acc, directives) => ({ ...acc, ...directives }), {})
+ const computedRule = {
...combination,
- directives: {},
- virtualDirectives: {
- [virtualName]: getTextColorAlpha(newTextRule.directives, textColor, dynamicVars)
- },
- virtualDirectivesRaw: {
- [virtualName]: textColor
- }
+ directives: computedDirectives
}
- } else {
+
computed[selector] = computed[selector] || {}
+ computed[selector].computedRule = computedRule
+ computed[selector].dynamicVars = dynamicVars
+
+ if (virtualComponents.has(combination.component)) {
+ const virtualName = [
+ '--',
+ combination.component.toLowerCase(),
+ combination.variant === 'normal'
+ ? ''
+ : combination.variant[0].toUpperCase() + combination.variant.slice(1).toLowerCase(),
+ ...sortBy(combination.state.filter(x => x !== 'normal')).map(state => state[0].toUpperCase() + state.slice(1).toLowerCase())
+ ].join('')
+
+ let inheritedTextColor = computedDirectives.textColor
+ let inheritedTextAuto = computedDirectives.textAuto
+ let inheritedTextOpacity = computedDirectives.textOpacity
+ let inheritedTextOpacityMode = computedDirectives.textOpacityMode
+ const lowerLevelTextSelector = [...selector.split(/ /g).slice(0, -1), soloSelector].join(' ')
+ const lowerLevelTextRule = computed[lowerLevelTextSelector]
+
+ if (inheritedTextColor == null || inheritedTextOpacity == null || inheritedTextOpacityMode == null) {
+ inheritedTextColor = computedDirectives.textColor ?? lowerLevelTextRule.textColor
+ inheritedTextAuto = computedDirectives.textAuto ?? lowerLevelTextRule.textAuto
+ inheritedTextOpacity = computedDirectives.textOpacity ?? lowerLevelTextRule.textOpacity
+ inheritedTextOpacityMode = computedDirectives.textOpacityMode ?? lowerLevelTextRule.textOpacityMode
+ }
- // TODO: DEFAULT TEXT COLOR
- const lowerLevelStackedBackground = stacked[lowerLevelSelector] || convert(ultimateBackgroundColor).rgb
-
- if (computedDirectives.background) {
- let inheritRule = null
- const variantRules = ruleset.filter(
- findRules({
- component: combination.component,
- variant: combination.variant,
- parent: combination.parent
- })
- )
- const lastVariantRule = variantRules[variantRules.length - 1]
- if (lastVariantRule) {
- inheritRule = lastVariantRule
- } else {
- const normalRules = ruleset.filter(findRules({
- component: combination.component,
- parent: combination.parent
- }))
- const lastNormalRule = normalRules[normalRules.length - 1]
- inheritRule = lastNormalRule
+ const newTextRule = {
+ ...computedRule,
+ directives: {
+ ...computedRule.directives,
+ textColor: inheritedTextColor,
+ textAuto: inheritedTextAuto ?? 'preserve',
+ textOpacity: inheritedTextOpacity,
+ textOpacityMode: inheritedTextOpacityMode
+ }
+ }
+
+ dynamicVars.inheritedBackground = lowerLevelBackground
+ dynamicVars.stacked = convert(stacked[lowerLevelSelector]).rgb
+
+ const intendedTextColor = convert(findColor(inheritedTextColor, { dynamicVars, staticVars })).rgb
+ const textColor = newTextRule.directives.textAuto === 'no-auto'
+ ? intendedTextColor
+ : getTextColor(
+ convert(stacked[lowerLevelSelector]).rgb,
+ intendedTextColor,
+ newTextRule.directives.textAuto === 'preserve'
+ )
+ const virtualDirectives = computed[lowerLevelSelector].virtualDirectives || {}
+ const virtualDirectivesRaw = computed[lowerLevelSelector].virtualDirectivesRaw || {}
+
+ // Storing color data in lower layer to use as custom css properties
+ virtualDirectives[virtualName] = getTextColorAlpha(newTextRule.directives, textColor, dynamicVars)
+ virtualDirectivesRaw[virtualName] = textColor
+
+ computed[lowerLevelSelector].virtualDirectives = virtualDirectives
+ computed[lowerLevelSelector].virtualDirectivesRaw = virtualDirectivesRaw
+
+ return {
+ dynamicVars,
+ selector: cssSelector.split(/ /g).slice(0, -1).join(' '),
+ ...combination,
+ directives: {},
+ virtualDirectives: {
+ [virtualName]: getTextColorAlpha(newTextRule.directives, textColor, dynamicVars)
+ },
+ virtualDirectivesRaw: {
+ [virtualName]: textColor
+ }
}
+ } else {
+ computed[selector] = computed[selector] || {}
+
+ // TODO: DEFAULT TEXT COLOR
+ const lowerLevelStackedBackground = stacked[lowerLevelSelector] || convert(ultimateBackgroundColor).rgb
+
+ if (computedDirectives.background) {
+ let inheritRule = null
+ const variantRules = ruleset.filter(
+ findRules({
+ component: combination.component,
+ variant: combination.variant,
+ parent: combination.parent
+ })
+ )
+ const lastVariantRule = variantRules[variantRules.length - 1]
+ if (lastVariantRule) {
+ inheritRule = lastVariantRule
+ } else {
+ const normalRules = ruleset.filter(findRules({
+ component: combination.component,
+ parent: combination.parent
+ }))
+ const lastNormalRule = normalRules[normalRules.length - 1]
+ inheritRule = lastNormalRule
+ }
- const inheritSelector = ruleToSelector({ ...inheritRule, parent: combination.parent }, true)
- const inheritedBackground = computed[inheritSelector].background
+ const inheritSelector = ruleToSelector({ ...inheritRule, parent: combination.parent }, true)
+ const inheritedBackground = computed[inheritSelector].background
- dynamicVars.inheritedBackground = inheritedBackground
+ dynamicVars.inheritedBackground = inheritedBackground
- const rgb = convert(findColor(computedDirectives.background, { dynamicVars, staticVars })).rgb
+ const rgb = convert(findColor(computedDirectives.background, { dynamicVars, staticVars })).rgb
- if (!stacked[selector]) {
- let blend
- const alpha = computedDirectives.opacity ?? 1
- if (alpha >= 1) {
- blend = rgb
- } else if (alpha <= 0) {
- blend = lowerLevelStackedBackground
- } else {
- blend = alphaBlend(rgb, computedDirectives.opacity, lowerLevelStackedBackground)
+ if (!stacked[selector]) {
+ let blend
+ const alpha = computedDirectives.opacity ?? 1
+ if (alpha >= 1) {
+ blend = rgb
+ } else if (alpha <= 0) {
+ blend = lowerLevelStackedBackground
+ } else {
+ blend = alphaBlend(rgb, computedDirectives.opacity, lowerLevelStackedBackground)
+ }
+ stacked[selector] = blend
+ computed[selector].background = { ...rgb, a: computedDirectives.opacity ?? 1 }
}
- stacked[selector] = blend
- computed[selector].background = { ...rgb, a: computedDirectives.opacity ?? 1 }
}
- }
- if (computedDirectives.shadow) {
- dynamicVars.shadow = flattenDeep(findShadow(flattenDeep(computedDirectives.shadow), { dynamicVars, staticVars }))
- }
+ if (computedDirectives.shadow) {
+ dynamicVars.shadow = flattenDeep(findShadow(flattenDeep(computedDirectives.shadow), { dynamicVars, staticVars }))
+ }
- if (!stacked[selector]) {
- computedDirectives.background = 'transparent'
- computedDirectives.opacity = 0
- stacked[selector] = lowerLevelStackedBackground
- computed[selector].background = { ...lowerLevelStackedBackground, a: 0 }
- }
+ if (!stacked[selector]) {
+ computedDirectives.background = 'transparent'
+ computedDirectives.opacity = 0
+ stacked[selector] = lowerLevelStackedBackground
+ computed[selector].background = { ...lowerLevelStackedBackground, a: 0 }
+ }
- dynamicVars.stacked = stacked[selector]
- dynamicVars.background = computed[selector].background
+ dynamicVars.stacked = stacked[selector]
+ dynamicVars.background = computed[selector].background
- const dynamicSlots = Object.entries(computedDirectives).filter(([k, v]) => k.startsWith('--'))
+ const dynamicSlots = Object.entries(computedDirectives).filter(([k, v]) => k.startsWith('--'))
- dynamicSlots.forEach(([k, v]) => {
- const [type, value] = v.split('|').map(x => x.trim()) // woah, Extreme!
- switch (type) {
- case 'color': {
- const color = findColor(value, { dynamicVars, staticVars })
- dynamicVars[k] = color
- if (combination.component === rootComponentName) {
- staticVars[k.substring(2)] = color
+ dynamicSlots.forEach(([k, v]) => {
+ const [type, value] = v.split('|').map(x => x.trim()) // woah, Extreme!
+ switch (type) {
+ case 'color': {
+ const color = findColor(value, { dynamicVars, staticVars })
+ dynamicVars[k] = color
+ if (combination.component === rootComponentName) {
+ staticVars[k.substring(2)] = color
+ }
+ break
}
- break
- }
- case 'shadow': {
- const shadow = value.split(/,/g).map(s => s.trim()).filter(x => x)
- dynamicVars[k] = shadow
- if (combination.component === rootComponentName) {
- staticVars[k.substring(2)] = shadow
+ case 'shadow': {
+ const shadow = value.split(/,/g).map(s => s.trim()).filter(x => x)
+ dynamicVars[k] = shadow
+ if (combination.component === rootComponentName) {
+ staticVars[k.substring(2)] = shadow
+ }
+ break
}
- break
- }
- case 'generic': {
- dynamicVars[k] = value
- if (combination.component === rootComponentName) {
- staticVars[k.substring(2)] = value
+ case 'generic': {
+ dynamicVars[k] = value
+ if (combination.component === rootComponentName) {
+ staticVars[k.substring(2)] = value
+ }
+ break
}
- break
}
+ })
+
+ const rule = {
+ dynamicVars,
+ selector: cssSelector,
+ ...combination,
+ directives: computedDirectives
}
- })
- const rule = {
- dynamicVars,
- selector: cssSelector,
- ...combination,
- directives: computedDirectives
+ return rule
}
-
- return rule
+ } catch (e) {
+ const { component, variant, state } = combination
+ throw new Error(`Error processing combination ${component}.${variant}:${state.join(':')}: ${e}`)
}
}