feat(tui): track hue source identity (#37550)
This commit is contained in:
parent
87d5b27668
commit
fafb04ed59
6 changed files with 60 additions and 21 deletions
|
|
@ -77,6 +77,7 @@ export function createComponentTheme(current: Accessor<ResolvedThemeView>, mode:
|
|||
|
||||
return {
|
||||
hue,
|
||||
source: (color: RGBA) => current().source(color),
|
||||
increase: (color: RGBA, amount = 1) => current().increase(color, amount),
|
||||
decrease: (color: RGBA, amount = 1) => current().decrease(color, amount),
|
||||
raise: (color: RGBA) => (mode() === "light" ? current().increase(color) : current().decrease(color)),
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export {
|
|||
export type {
|
||||
FormfieldColor,
|
||||
Hue,
|
||||
HueSource,
|
||||
HueScale,
|
||||
ResolvedActionState,
|
||||
ResolvedFormfieldState,
|
||||
|
|
|
|||
|
|
@ -141,35 +141,36 @@ function contextualActions(
|
|||
function resolveView(
|
||||
definition: ThemeTokensDefinition,
|
||||
hue: ResolvedThemeView["hue"],
|
||||
hueSteps: Pick<ResolvedThemeView, "increase" | "decrease">,
|
||||
hueSteps: Pick<ResolvedThemeView, "source" | "increase" | "decrease">,
|
||||
): ResolvedThemeView {
|
||||
const source: Record<string, unknown> = { hue, ...definition }
|
||||
return { ...(createResolver(source)(source, "theme") as ResolvedThemeView), hue, ...hueSteps }
|
||||
}
|
||||
|
||||
function compileHueSteps(hue: ResolvedThemeView["hue"]): Pick<ResolvedThemeView, "increase" | "decrease"> {
|
||||
const index = new Map(
|
||||
Object.values(hue).flatMap((scale) =>
|
||||
HueStep.literals.map((step, position) => [colorKey(scale[step]), { position, scale }] as const),
|
||||
),
|
||||
)
|
||||
function compileHueSteps(
|
||||
hue: ResolvedThemeView["hue"],
|
||||
): Pick<ResolvedThemeView, "source" | "increase" | "decrease"> {
|
||||
const index = new WeakMap<RGBA, { hue: keyof typeof hue; step: HueStep; position: number }>()
|
||||
for (const [name, scale] of Object.entries(hue) as [keyof typeof hue, HueScale][]) {
|
||||
HueStep.literals.forEach((step, position) => index.set(scale[step], { hue: name, step, position }))
|
||||
}
|
||||
const shift = (color: RGBA, amount: number) => {
|
||||
const match = index.get(colorKey(color))
|
||||
const match = index.get(color)
|
||||
if (!match) return color
|
||||
const offset = Number.isFinite(amount) ? Math.trunc(amount) : 0
|
||||
const position = Math.max(0, Math.min(HueStep.literals.length - 1, match.position + offset))
|
||||
return match.scale[HueStep.literals[position]]
|
||||
return hue[match.hue][HueStep.literals[position]]
|
||||
}
|
||||
return {
|
||||
source: (color) => {
|
||||
const match = index.get(color)
|
||||
return match ? { hue: match.hue, step: match.step } : undefined
|
||||
},
|
||||
increase: (color, amount = 1) => shift(color, amount),
|
||||
decrease: (color, amount = 1) => shift(color, -amount),
|
||||
}
|
||||
}
|
||||
|
||||
function colorKey(color: RGBA) {
|
||||
return color.toInts().join(":")
|
||||
}
|
||||
|
||||
function resolveHue(definition: HueDefinition) {
|
||||
const source = definition as Record<string, unknown>
|
||||
const cache = new Map<string, HueScale>()
|
||||
|
|
@ -186,7 +187,8 @@ function resolveHue(definition: HueDefinition) {
|
|||
if (typeof value === "string") {
|
||||
const match = /^\$hue\.([^.]+)$/.exec(value)
|
||||
if (!match?.[1]) throw new Error(`Hue alias "${value}" must reference a hue scale`)
|
||||
const result = resolve(match[1], [...stack, name])
|
||||
const target = resolve(match[1], [...stack, name])
|
||||
const result = Object.fromEntries(HueStep.literals.map((step) => [step, RGBA.clone(target[step])])) as HueScale
|
||||
cache.set(name, result)
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@ export type ResolvedActionState = "default" | ActionState
|
|||
export type ResolvedFormfieldState = ResolvedActionState
|
||||
export type HueScale = Readonly<Record<HueStep, RGBA>>
|
||||
export type Hue = Readonly<Record<BaseHue | HueAlias, HueScale>>
|
||||
export type HueSource = Readonly<{ hue: BaseHue | HueAlias; step: HueStep }>
|
||||
export type StatefulColor = Readonly<Record<ResolvedActionState, RGBA>>
|
||||
export type FormfieldColor = StatefulColor
|
||||
|
||||
export type ResolvedThemeView = {
|
||||
readonly hue: Hue
|
||||
readonly source: (color: RGBA) => HueSource | undefined
|
||||
readonly increase: (color: RGBA, amount?: number) => RGBA
|
||||
readonly decrease: (color: RGBA, amount?: number) => RGBA
|
||||
readonly text: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue