Skip to content

Commit

Permalink
#color fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
somebee committed May 7, 2024
1 parent 86c1b74 commit 261d23e
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 98 deletions.
11 changes: 11 additions & 0 deletions packages/imba/src/compiler/colord.imba
@@ -0,0 +1,11 @@
import * as cd from "colord"
import lchPlugin from "colord/plugins/lch"
cd.extend([lchPlugin])

export const colord = cd.colord

export def toLchArray str
let res = cd.colord(str).toLch()
return [res.l,res.c,res.h,res.a]


2 changes: 2 additions & 0 deletions packages/imba/src/compiler/constants.imba1
Expand Up @@ -89,6 +89,8 @@ export var OPERATOR_ALIASES =
export var HEREGEX_OMIT = /\s+(?:#.*)?/g
export var HEREGEX = /// ^ /{3} ([\s\S]+?) /{3} ([a-z]{0,8}) (?!\w) ///

export var HEX_REGEX = /^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6}([A-Fa-f0-9]{2})?)$/

export var TAG_GLOBAL_ATTRIBUTES = {
itemid: 1
itemprop: 1
Expand Down
4 changes: 2 additions & 2 deletions packages/imba/src/compiler/grammar.imba1
Expand Up @@ -488,7 +488,7 @@ var grammar =

StyleColor: [
o 'COLOR' do StyleColor.new(A1)
o 'COLORMIX ( StyleFunctionArgs )' do StyleColorMix.new(A1,A3).set(params: A3)
o 'COLORMIX ( StyleFunctionArgs )' do StyleColorMix.new(A1,A3.setEnds(A2,A4)).set(params: A3).setEnds(A1,A4)
]

StyleTerm: [
Expand All @@ -502,7 +502,7 @@ var grammar =
o 'String' do A1
o 'StyleTermPlaceholder' do A1
o 'CSSURL' do StyleURL.new(A1)
o 'CSSFUNCTION ( StyleFunctionArgs )' do StyleFunction.new(A1,A3)
o 'CSSFUNCTION ( StyleFunctionArgs )' do StyleFunction.new(A1,A3.setEnds(A2,A4)).setEnds(A1,A4)
o 'CSSIDENTIFIER' do StyleIdentifier.new(A1)
o 'COMPARE StyleTerm' do A2.set(op: A1)
]
Expand Down
4 changes: 2 additions & 2 deletions packages/imba/src/compiler/lexer.imba1
Expand Up @@ -175,8 +175,8 @@ var NUMBER = ///
^ 0x[\da-f_]+ | # hex
^ 0b[01_]+ | # binary
^ 0o[\d_]+ | # binary
^ \-?(?:\d[_\d]*)\.?\d[_\d]* (?:e[+-]?\d+)? | # decimal2
^ \-?\d*\.?\d+ (?:e[+-]?\d+)? # decimal
^ [\-]?(?:\d[_\d]*)\.?\d[_\d]* (?:e[+-]?\d+)? | # decimal2
^ [\-]?\d*\.?\d+ (?:e[+-]?\d+)? # decimal

///i

Expand Down
129 changes: 54 additions & 75 deletions packages/imba/src/compiler/nodes.imba1
Expand Up @@ -6,6 +6,7 @@ var helpers = require './helpers'
var constants = require './constants'
var fspath = require 'path'
import {conv} from '../../vendor/colors'
import {colord} from './colord'

import ImbaParseError,ImbaTraverseError from './errors'
import Token from './token'
Expand Down Expand Up @@ -1756,7 +1757,7 @@ export class ListNode < Node

def initialize list
setup
@nodes = load(list or [])
@nodes = load(list == null ? [] : list)
@indentation = null

# PERF acces @nodes directly?
Expand Down Expand Up @@ -12006,12 +12007,11 @@ export class StyleDeclaration < StyleNode
self

def clone name, params
params = @expr.clone unless params
params = @expr.clone if params == null
if typeof params == 'string' or typeof params == 'number'
params = [params]
if !(params isa Array) and (!(params isa ListNode) or params isa StyleOperation)
params = [params]

StyleDeclaration.new(@property.clone(name),params)

def visit stack, o
Expand Down Expand Up @@ -12052,7 +12052,6 @@ export class StyleDeclaration < StyleNode
if res isa Array
@expr = StyleExpressions.new(res)
elif res isa Object
# console.log 'theme has method',method,res
for own k,v of res
if k.indexOf('&') >= 0
let body = StyleBody.new([])
Expand Down Expand Up @@ -12108,15 +12107,19 @@ export class StyleProperty < StyleNode
@token = token
let raw = String(@token)

if raw[0] == '#'
@kind = 'color'
# also split
@parts = raw.replace(/(^|\b)\$/g,'--').split(/\b(?=[\^\.\@\!])/g) # .split(/[\.\@]/g)

for part,i in @parts
@parts[i] = part.replace(/^\.(?=[^\.])/,'@.')

@name = String(@parts[0])
@name = String(@parts[0])

if raw[0] == '#'
@kind = 'color'
if constants.HEX_REGEX.test(@name)
error("Color name {@name} cannot be identical to valid hex color",loc: token[0] or token)


if let m = @name.match(/^(\d+)([a-zA-Z]+)$/)
@number = parseInt(m[1])
Expand Down Expand Up @@ -12382,31 +12385,24 @@ export class StyleFunction < Node
@lcha.push(part)

unless name == 'lch'
let nums = []
let alpha = @lcha[3]
let kind = name.slice(0,3)

let fmt = {
rgb: [2.55,2.55,2.55]
hsl: [1,1,1]
}[kind] or [0.01,0.01,0.01]

for part,i in @lcha
unless part isa StyleDimension
unless i > 2 # alpha channel can be dynamic
error("Dynamic part not allowed in non-lch #color definitions", loc: part)

if i < 3
nums.push(part.toFloat(fmt[i]))
if !(part isa StyleDimension) and i < 3
return error("Dynamic part not allowed in non-lch #color definitions", loc: part)

let converter = conv[name]

unless converter and converter:lch
error("Cannot convert {name} to lch", loc: @name)

@lcha = converter.lch(nums)
@lcha.push(alpha) if alpha
try
let inside = @params.c
if alpha and !(alpha isa StyleDimension)
inside = inside.replace(alpha.c,'1')
let full = "{name}({inside})"

let col = colord(full).toLch()
@lcha = [col:l,col:c,col:h,col:a]
@lcha[3] = alpha if alpha
catch e
error("Failed to parse color", loc: self)
self

def lcha
Expand Down Expand Up @@ -12445,25 +12441,20 @@ export class StyleIdentifier < StyleTerm

def visit stack
let raw = toString

super


if raw.match(/^[lcha]$/)
super
let mix = stack.up(StyleColorMix)
@colormix = mix
@resolvedValue = "var(--u_{@colormix.@name}{raw.toUpperCase()})"

elif raw.match(/^([a-zA-Z]+\d+|black|white)$/)
color = "{raw}"
if self:param
color += "/" + self:param.toAlpha


else
if raw.match(/^([a-zA-Z]+\d+|black|white)$/)
color = "{raw}"
if self:param
color += "/" + self:param.toAlpha
super

def c o
if @resolvedValue
return @resolvedValue

if @colormix
return "var(--u_{@colormix.@name}{toString.toUpperCase()})"

Expand All @@ -12487,37 +12478,26 @@ export class StyleColor < StyleTerm

def visit
super
let name = @name = toRaw.slice(1)

if true # @property and @property.isColor
# only needed for the property color?
if let m = name.match(/^([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6}([A-Fa-f0-9]{2})?)$/)
let a = m[2] ? (parseInt(m[2],16) / 255) : 1
let lch = conv:hex.lch(name.slice(0,6))

# Rounding conversion to nearest .1
for num,i in lch
lch[i] = Math.floor(num * 10) / 10

if name[0].match(/\d/)
@lcha = lch
@lcha.push(a)
else
# Cannot know for sure that a color name is not really a hex color
@lcha = [
"var(--u_{name}L,{lch[0]})"
"var(--u_{name}C,{lch[1]})"
"var(--u_{name}H,{lch[2]})"
"var(--u_{name}A,{a})"
]
let raw = toRaw
let name = @name = raw.slice(1)

else
@lcha = [
"var(--u_{name}L)"
"var(--u_{name}C)"
"var(--u_{name}H)"
"var(--u_{name}A,1)"
]
# only needed for the property color?
if let m = raw.match(constants.HEX_REGEX)
@hex = yes
let col = colord(raw).toLch()
@lcha = [col:l,col:c,col:h,col:a]
else
@lcha = [
"var(--u_{name}L)"
"var(--u_{name}C)"
"var(--u_{name}H)"
"var(--u_{name}A,1)"
]

let a = self:param and self:param.toAlpha
if a != null
a = "var(--{a.slice(1)},100%)" if a[0] == '$'
@lcha[3] = a

def lcha
@lcha
Expand All @@ -12526,17 +12506,16 @@ export class StyleColor < StyleTerm
let raw = toRaw
let name = raw.slice(1)
let rich = Color.from(raw)
let a = self:param ? self:param.toAlpha : "var(--u_{name}A,1)"

if a[0] == '$'
a = "var(--{a.slice(1)},100%)"

if @property and @property.isColor
console.log 'deprecated'
return rich.toVar

return "lch(var(--u_{name}L) var(--u_{name}C) var(--u_{name}H) / {a})"
let [l,c,h,a] = @lcha
if @hex and a == 1
return raw

return "hsla2({rich.toVar},{a})"
return "lch({l} {c} {h} / {a})"

export class StyleColorMix < StyleTerm

Expand Down
26 changes: 11 additions & 15 deletions packages/imba/src/compiler/styler.imba
Expand Up @@ -2,6 +2,7 @@
# var conv = require('../../vendor/colors')
import * as selparser from './selparse'
import {conv} from '../../vendor/colors'
import {colord,toLchArray} from './colord.imba'
import {fonts,colors,variants,named_colors} from './theme.imba'
import * as theme from './theme.imba'

Expand Down Expand Up @@ -396,6 +397,9 @@ export def parseColorString str, to = 'hsl'
if named_colors[str]
str = named_colors[str]

if to == 'lch'
return toLchArray(str)

if str[0] == '#'
let hex = conv.hex.rgb(str)
return conv.rgb.hsl(hex)
Expand All @@ -404,19 +408,14 @@ export def parseColorString str, to = 'hsl'
let [a,b,c,d = ''] = m[2].replace(/[\,\/]/g,' ').split(/\s+/g)

let out

console.log 'parsing',str,a,b,c,m,m[2].replace(/[,\/]/g,' ')

let parse

a=parseColorPart(a)
b=parseColorPart(b)
c=parseColorPart(c)

if to == 'lch'

return conv.rgb.lch([a,b,c])


if m[1] == 'rgb' or m[1] == 'rgba'
out = conv.rgb.hsl([parseFloat(a),parseFloat(b),parseFloat(c)])

Expand Down Expand Up @@ -447,10 +446,9 @@ export class Color
s = s
l = l
a = a
lch = conv.hsl.lch([h,s,l])

def lcha
#lcha ||= conv.hsl.lch([h,s,l]).concat(a)
#lcha ||= toLchArray("hsla({h} {s}% {l}% / {a})")

def alpha a = 1
new Color(name,h,s,l,a)
Expand All @@ -476,7 +474,7 @@ export class Color
# "{h.toFixed(2)},{s.toFixed(2)}%,{l.toFixed(2)}%"

def toLchString
let [l,c,h] = lch
let [l,c,h,a] = lcha!
`lcha({l.toFixed(2)} {c.toFixed(2)} {h.toFixed(2)}% / {a})`

def c
Expand Down Expand Up @@ -1125,15 +1123,10 @@ export class StyleTheme
let val = expr[0][0]
let [l,c,h,a] = [null,null,null,1]

let color

if val..lcha
[l,c,h,a] = val.lcha!
elif val.._resolvedValue isa Color
color = val.._resolvedValue

if color
[l,c,h] = color.lch
[l,c,h,a] = val._resolvedValue.lcha!

if typeof l == 'number'
l = Math.round(l * 10) / 10
Expand All @@ -1142,10 +1135,12 @@ export class StyleTheme
if typeof h == 'number'
h = Math.round(h * 10) / 10


if l != null
o[`--u_{name}L`] = l
o[`--u_{name}C`] = c
o[`--u_{name}H`] = h.._resolvedValue ?? h # no?
# o[`--u_{name}N`] = l > 50 ? 0 : 100
o[`--u_{name}A`] = a ?? 1
# o[pre] = color.toLchString()

Expand All @@ -1157,6 +1152,7 @@ export class StyleTheme

# aliased colors
if ns and typeof palette[ns] == 'string'

return $color(palette[ns] + name.slice(ns.length))

if ns == 'hue'
Expand Down
8 changes: 4 additions & 4 deletions packages/imba/test/apps/style/colormix.imba
Expand Up @@ -2,15 +2,15 @@ global css @root
$alpha:0.3
#bg:#fa0006
# red is lch(54 106.85 40.86)
# lch(52.2 102 39.3)
# lch(53.3 104.3 40.2)

#bg2:lch(50 50 100)
#bg3:lch(50 50 100 / 0.5)
#bg4:lch(40 40 100 / $alpha)

tag App
<self>
css c:#bg bg:#bg(0 0.5c 1h)
css c:#bg
<$a[c:#bg(l 0 h)]>
<$b[c:#bg2]>
<$c[c:#bg3]>
Expand All @@ -22,8 +22,8 @@ let color = do(el)

let app = imba.mount(<App>)

test do eq color(app),'lch(52.2 102 39.3)'
test do eq color(app.$a),'lch(52.2 0 39.3)'
test do eq color(app),'lch(53.3 104.3 40.2)'
test do eq color(app.$a),'lch(53.3 0 40.2)'
test do eq color(app.$b),'lch(50 50 100)'
test do eq color(app.$c),'lch(50 50 100 / 0.5)'
test do eq color(app.$d),'lch(40 40 100 / 0.3)'
Expand Down

0 comments on commit 261d23e

Please sign in to comment.