css_utils.js (5352B)
- import { convert } from 'chromatism'
- import { hex2rgb, rgba2css } from '../color_convert/color_convert.js'
- export const parseCssShadow = (text) => {
- const dimensions = /(\d[a-z]*\s?){2,4}/.exec(text)?.[0]
- const inset = /inset/.exec(text)?.[0]
- const color = text.replace(dimensions, '').replace(inset, '')
- const [x, y, blur = 0, spread = 0] = dimensions.split(/ /).filter(x => x).map(x => x.trim())
- const isInset = inset?.trim() === 'inset'
- const colorString = color.split(/ /).filter(x => x).map(x => x.trim())[0]
- return {
- x,
- y,
- blur,
- spread,
- inset: isInset,
- color: colorString
- }
- }
- export const getCssColorString = (color, alpha = 1) => rgba2css({ ...convert(color).rgb, a: alpha })
- export const getCssShadow = (input, usesDropShadow) => {
- if (input.length === 0) {
- return 'none'
- }
- return input
- .filter(_ => usesDropShadow ? _.inset : _)
- .map((shad) => [
- shad.x,
- shad.y,
- shad.blur,
- shad.spread
- ].map(_ => _ + 'px ').concat([
- getCssColorString(shad.color, shad.alpha),
- shad.inset ? 'inset' : ''
- ]).join(' ')).join(', ')
- }
- export const getCssShadowFilter = (input) => {
- if (input.length === 0) {
- return 'none'
- }
- return input
- // drop-shadow doesn't support inset or spread
- .filter((shad) => !shad.inset && Number(shad.spread) === 0)
- .map((shad) => [
- shad.x,
- shad.y,
- // drop-shadow's blur is twice as strong compared to box-shadow
- shad.blur / 2
- ].map(_ => _ + 'px').concat([
- getCssColorString(shad.color, shad.alpha)
- ]).join(' '))
- .map(_ => `drop-shadow(${_})`)
- .join(' ')
- }
- // `debug` changes what backgrounds are used to "stacked" solid colors so you can see
- // what theme engine "thinks" is actual background color is for purposes of text color
- // generation and for when --stacked variable is used
- export const getCssRules = (rules, debug) => rules.map(rule => {
- let selector = rule.selector
- if (!selector) {
- selector = 'html'
- }
- const header = selector + ' {'
- const footer = '}'
- const virtualDirectives = Object.entries(rule.virtualDirectives || {}).map(([k, v]) => {
- return ' ' + k + ': ' + v
- }).join(';\n')
- const directives = Object.entries(rule.directives).map(([k, v]) => {
- switch (k) {
- case 'roundness': {
- return ' ' + [
- '--roundness: ' + v + 'px'
- ].join(';\n ')
- }
- case 'shadow': {
- return ' ' + [
- '--shadow: ' + getCssShadow(rule.dynamicVars.shadow),
- '--shadowFilter: ' + getCssShadowFilter(rule.dynamicVars.shadow),
- '--shadowInset: ' + getCssShadow(rule.dynamicVars.shadow, true)
- ].join(';\n ')
- }
- case 'background': {
- if (debug) {
- return `
- --background: ${getCssColorString(rule.dynamicVars.stacked)};
- background-color: ${getCssColorString(rule.dynamicVars.stacked)};
- `
- }
- if (v === 'transparent') {
- if (rule.component === 'Root') return []
- return [
- rule.directives.backgroundNoCssColor !== 'yes' ? ('background-color: ' + v) : '',
- ' --background: ' + v
- ].filter(x => x).join(';\n')
- }
- const color = getCssColorString(rule.dynamicVars.background, rule.directives.opacity)
- const cssDirectives = ['--background: ' + color]
- if (rule.directives.backgroundNoCssColor !== 'yes') {
- cssDirectives.push('background-color: ' + color)
- }
- return cssDirectives.filter(x => x).join(';\n')
- }
- case 'blur': {
- const cssDirectives = []
- if (rule.directives.opacity < 1) {
- cssDirectives.push(`--backdrop-filter: blur(${v}) `)
- if (rule.directives.backgroundNoCssColor !== 'yes') {
- cssDirectives.push(`backdrop-filter: blur(${v}) `)
- }
- }
- return cssDirectives.join(';\n')
- }
- case 'font': {
- return 'font-family: ' + v
- }
- case 'textColor': {
- if (rule.directives.textNoCssColor === 'yes') { return '' }
- return 'color: ' + v
- }
- default:
- if (k.startsWith('--')) {
- const [type, value] = v.split('|').map(x => x.trim()) // woah, Extreme!
- switch (type) {
- case 'color': {
- const color = rule.dynamicVars[k]
- if (typeof color === 'string') {
- return k + ': ' + rgba2css(hex2rgb(color))
- } else {
- return k + ': ' + rgba2css(color)
- }
- }
- case 'generic':
- return k + ': ' + value
- default:
- return ''
- }
- }
- return ''
- }
- }).filter(x => x).map(x => ' ' + x).join(';\n')
- return [
- header,
- directives + ';',
- (rule.component === 'Text' && rule.state.indexOf('faint') < 0 && rule.directives.textNoCssColor !== 'yes') ? ' color: var(--text);' : '',
- '',
- virtualDirectives,
- footer
- ].join('\n')
- }).filter(x => x)
- export const getScopedVersion = (rules, newScope) => {
- return rules.map(x => {
- if (x.startsWith('html')) {
- return x.replace('html', newScope)
- } else if (x.startsWith('#content')) {
- return x.replace('#content', newScope)
- } else {
- return newScope + ' > ' + x
- }
- })
- }