(theme: ThemeJson, pick: "dark" | "light")
| 274 | } |
| 275 | |
| 276 | export function resolveTheme(theme: ThemeJson, pick: "dark" | "light"): TuiThemeCurrent { |
| 277 | const defs = theme.defs ?? {} |
| 278 | |
| 279 | const resolveColor = (value: ColorValue, chain: string[] = []): RGBA => { |
| 280 | if (value instanceof RGBA) return value |
| 281 | |
| 282 | if (typeof value === "number") { |
| 283 | return RGBA.fromIndex(value, ansiToRgba(value)) |
| 284 | } |
| 285 | |
| 286 | if (typeof value !== "string") { |
| 287 | return resolveColor(value[pick], chain) |
| 288 | } |
| 289 | |
| 290 | if (value === "transparent" || value === "none") { |
| 291 | return RGBA.fromInts(0, 0, 0, 0) |
| 292 | } |
| 293 | |
| 294 | if (value.startsWith("#")) { |
| 295 | return RGBA.fromHex(value) |
| 296 | } |
| 297 | |
| 298 | if (chain.includes(value)) { |
| 299 | throw new Error(`Circular color reference: ${[...chain, value].join(" -> ")}`) |
| 300 | } |
| 301 | |
| 302 | const next = defs[value] ?? theme.theme[value as ThemeColor] |
| 303 | if (next === undefined) { |
| 304 | throw new Error(`Color reference "${value}" not found in defs or theme`) |
| 305 | } |
| 306 | |
| 307 | return resolveColor(next, [...chain, value]) |
| 308 | } |
| 309 | |
| 310 | const resolved = Object.fromEntries( |
| 311 | Object.entries(theme.theme) |
| 312 | .filter(([key]) => key !== "selectedListItemText" && key !== "backgroundMenu" && key !== "thinkingOpacity") |
| 313 | .map(([key, value]) => [key, resolveColor(value as ColorValue)]), |
| 314 | ) as Partial<Record<ThemeColor, RGBA>> |
| 315 | |
| 316 | return { |
| 317 | ...(resolved as Record<ThemeColor, RGBA>), |
| 318 | selectedListItemText: |
| 319 | theme.theme.selectedListItemText === undefined |
| 320 | ? resolved.background! |
| 321 | : resolveColor(theme.theme.selectedListItemText), |
| 322 | backgroundMenu: |
| 323 | theme.theme.backgroundMenu === undefined ? resolved.backgroundElement! : resolveColor(theme.theme.backgroundMenu), |
| 324 | thinkingOpacity: theme.theme.thinkingOpacity ?? 0.6, |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | function generateGrayScale(bg: RGBA, isDark: boolean, map: (rgba: RGBA) => RGBA): Record<number, RGBA> { |
| 329 | const r = bg.r * 255 |
no test coverage detected