import { type PropsWithChildren, useContext, useMemo } from "react"; import { Theme as TamaguiTheme } from "tamagui"; import type { ThemeName } from "@tamagui/web"; import { PresetContext, type PresetContextValue } from "./PresetContext"; import { defaultKnobs, type Knobs } from "./knobs"; import type { Preset as PresetType } from "./preset.types"; import { getPreset } from "./shared"; export interface PresetProps extends PropsWithChildren { /** Named preset to apply. Looked up from the preset registry. */ preset?: string; /** Tamagui theme name (e.g. "blue", "red"). Wraps children in . */ theme?: ThemeName; /** Partial knob overrides merged on top of the preset's knobs. */ overrides?: Partial; /** When true (default), inherits from parent Preset. When false, replaces entirely. */ cascade?: boolean; } export function Preset({ children, preset: presetName, theme, overrides, cascade = true, }: PresetProps) { const parentCtx = useContext(PresetContext); const ctxValue = useMemo((): PresetContextValue => { // 1. Determine base preset let base: PresetType; if (cascade && parentCtx) { // Start from parent's preset base = { ...parentCtx.preset }; // If a preset name is given, overlay it if (presetName) { const namedPreset = getPreset(presetName); if (namedPreset) { base = { ...namedPreset }; } } // Carry parent overrides forward, then layer ours const mergedOverrides: Partial = { ...parentCtx.overrides, ...overrides, }; return { preset: { ...base, knobs: { ...base.knobs, ...parentCtx.overrides, ...overrides }, }, overrides: Object.keys(mergedOverrides).length > 0 ? mergedOverrides : undefined, }; } // cascade=false or no parent — start fresh const freshDefault: PresetType = { theme: "" as ThemeName, knobs: { ...defaultKnobs }, intents: {}, tints: [], }; if (presetName) { base = getPreset(presetName) ?? freshDefault; } else if (!cascade) { // Explicitly non-cascading: always start from defaults base = freshDefault; } else { // No parent context exists: use defaults base = freshDefault; } if (overrides) { return { preset: { ...base, knobs: { ...base.knobs, ...overrides } }, overrides, }; } return { preset: base }; }, [cascade, parentCtx, presetName, overrides]); let element = {children}; // Wrap with Tamagui when theme is specified if (theme) { element = {element}; } return element; }