Aur UI

Theme Config

Runtime style configuration for Aur UI.

bash
pnpm add @aur-ui/ui
tsx
import { applyAurStyleConfig, clearAurStyleConfig, type AurStyleColorValue, type AurStyleConfig } from "@aur-ui/ui/lib/theme-config";
lib/theme-config.ts
export type AurStyleColorValue = string | null | undefined;

export type AurStyleConfig = {
  /** Main action hue. Drives `--brand`, `bg-brand`, focus rings, charts, etc. */
  primary?: AurStyleColorValue;
  /** Optional explicit hover color for the main action hue. */
  primaryHover?: AurStyleColorValue;
  /** Optional explicit soft fill for the main action hue. */
  primarySoft?: AurStyleColorValue;
  /** Secondary brand hue. Drives secondary button treatments and chart accents. */
  secondary?: AurStyleColorValue;
  /** Optional explicit hover color for the secondary brand hue. */
  secondaryHover?: AurStyleColorValue;
  /** Optional explicit soft fill for the secondary brand hue. */
  secondarySoft?: AurStyleColorValue;
};

const STYLE_VARIABLES = {
  primary: "--aur-primary",
  primaryHover: "--brand-hover",
  primarySoft: "--brand-soft",
  secondary: "--aur-secondary",
  secondaryHover: "--brand-secondary-hover",
  secondarySoft: "--brand-secondary-soft",
} as const satisfies Record<keyof AurStyleConfig, string>;

type StyleVariable = (typeof STYLE_VARIABLES)[keyof typeof STYLE_VARIABLES];

function resolveTarget(target?: HTMLElement | null) {
  if (target) return target;
  if (typeof document === "undefined") return undefined;
  return document.documentElement;
}

function normalizeColorValue(value: AurStyleColorValue) {
  if (typeof value !== "string") return value;
  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : null;
}

export function clearAurStyleConfig(
  target?: HTMLElement | null,
  variables: Iterable<StyleVariable> = Object.values(STYLE_VARIABLES),
) {
  const element = resolveTarget(target);
  if (!element) return;

  for (const variable of variables) {
    element.style.removeProperty(variable);
  }
}

export function applyAurStyleConfig(
  config: AurStyleConfig,
  target?: HTMLElement | null,
) {
  const element = resolveTarget(target);
  if (!element) return () => {};

  const touched = new Set<StyleVariable>();

  for (const [key, variable] of Object.entries(STYLE_VARIABLES) as Array<
    [keyof AurStyleConfig, StyleVariable]
  >) {
    const value = normalizeColorValue(config[key]);
    if (value === undefined) continue;

    touched.add(variable);
    if (value === null) {
      element.style.removeProperty(variable);
      continue;
    }
    element.style.setProperty(variable, value);
  }

  return () => clearAurStyleConfig(element, touched);
}