import { isSafeCssUrlReference, removeBreakpointMediaDeclaration, setBreakpointMediaDeclaration, } from "./breakpoint-media.js"; import { isComponentInstance, instanceFromNode, type ComponentInstance, } from "./component-model"; import type { TailwindBreakpointPrefix } from "./design-state.js"; import { getPropertyClasses, parseClassGroups, parseClassToken, removeMaxWidthPropertyClass, setMaxWidthPropertyClass, setPropertyClass, removePropertyClass, utilityStem, } from "./responsive-classes.js"; import type { DesignSourceType } from "./source-mode"; export type CodeLayerSourceKind = | "design-file" | "inline-html" | "local-file" | "remote-url"; export interface CodeLayerSource { kind: CodeLayerSourceKind; sourceType?: DesignSourceType; designId?: string; fileId?: string; filename?: string; path?: string; url?: string; connectionId?: string; routeId?: string; artboardId?: string; bridgeUrl?: string; revision?: string; } export interface CodeLayerSourceSpan { start: number; end: number; openStart: number; openEnd: number; contentStart?: number; contentEnd?: number; closeStart?: number; closeEnd?: number; } export type VisualStyleProperty = | "width" | "height" | "min-width" | "max-width" | "min-height" | "max-height" | "left" | "top" | "right" | "bottom" | "inset" | "position" | "display" | "color" | "background" | "background-color" | "background-image" | "background-size" | "background-repeat" | "background-position" | "background-blend-mode" | "fill" | "fill-opacity" | "opacity" | "mix-blend-mode" | "font-size" | "font-weight" | "font-family" | "font-style" | "letter-spacing" | "line-height" | "text-align" | "text-decoration" | "text-transform" | "white-space" | "overflow" | "overflow-x" | "overflow-y" | "text-overflow" | "border" | "border-width" | "border-style" | "border-color" | "border-radius" | "border-top-left-radius" | "border-top-right-radius" | "border-bottom-left-radius" | "border-bottom-right-radius" | "stroke" | "stroke-width" | "stroke-opacity" | "stroke-dasharray" | "stroke-linecap" | "stroke-linejoin" | "outline" | "outline-width" | "outline-style" | "outline-color" | "outline-offset" | "-webkit-text-stroke-width" | "-webkit-text-stroke-color" | "box-shadow" | "text-shadow" | "filter" | "backdrop-filter" | "transform" | "transform-origin" | "rotate" | "scale" | "translate" | "padding" | "padding-top" | "padding-right" | "padding-bottom" | "padding-left" | "margin" | "margin-top" | "margin-right" | "margin-bottom" | "margin-left" | "gap" | "row-gap" | "column-gap" | "flex" | "flex-direction" | "flex-wrap" | "flex-grow" | "flex-shrink" | "flex-basis" | "order" | "align-self" | "align-items" | "align-content" | "justify-content" | "justify-items" | "justify-self" | "grid-column" | "grid-row" | "grid-template-columns" | "grid-template-rows" | "grid-auto-flow" | "grid-auto-columns" | "grid-auto-rows" | "box-sizing" | "aspect-ratio" | "z-index"; export interface StyleToken { property: VisualStyleProperty; /** * The resolved value at the *base* breakpoint (unprefixed), or the inline * style value. For class-sourced tokens this is the utility string of the * base class (e.g. `"text-sm"`). Use `breakpointValues` to inspect how the * value differs across responsive prefixes. */ value: string; token: string; source: "inline-style" | "class"; confidence: number; /** * For class-sourced tokens only: the resolved utility string per responsive * prefix. Only prefixes that have an explicit class token are included. * * @example * // className="text-sm md:text-base lg:text-lg" * // styleToken for "color" property would have: * // breakpointValues = { base: "text-sm", md: "text-base", lg: "text-lg" } */ breakpointValues?: Partial>; /** * For class-sourced tokens only: the prefixes (other than `"base"`) at which * this property has a responsive override in the class list. Populated when * `breakpointValues` has keys other than `"base"`. */ overriddenAtPrefixes?: TailwindBreakpointPrefix[]; } export interface LayoutContext { parentId?: string; parentSelector?: string; siblingIndex: number; nthOfType: number; display?: string; position?: string; width?: string; height?: string; flexDirection?: string; alignItems?: string; justifyContent?: string; gap?: string; padding?: string; parentDisplay?: string; parentFlexDirection?: string; parentGap?: string; isFlexContainer: boolean; isGridContainer: boolean; } export type EditCapability = | { kind: "style"; properties: VisualStyleProperty[]; confidence: number; reason?: string; } | { kind: "class"; operations: Array<"add" | "remove" | "replace" | "set">; confidence: number; reason?: string; } | { /** * Responsive-class editing — adds, replaces, or removes a Tailwind * utility at a specific breakpoint prefix without touching other * breakpoints. Uses the helpers in `responsive-classes.ts` * (setPropertyClass / removePropertyClass) and the same deterministic * HTML-patch path as `class` edits. * * The `prefix` field indicates the active breakpoint scope for which * this capability was computed (derived from the canvas frame width via * `widthToPrefix`). Callers may target any prefix — `prefix` is * informational, not a constraint. */ kind: "responsive-class"; /** Active breakpoint scope (informational). */ prefix: TailwindBreakpointPrefix; operations: Array<"add" | "remove" | "replace">; /** Properties that currently have per-breakpoint overrides (non-empty means overrides exist). */ overriddenProperties: string[]; confidence: number; reason?: string; } | { /** * Breakpoint-scoped raw style editing (§6.4) — the `@media` fallback * for values responsive class prefixes can't express. Writes into the * managed `