# Customization sheets

Typed component parts, variant conditions, defaults, and deterministic override layers.

## One portable contract
A component sheet identifies a component and supplies visual defaults and ordered rules. Rules target public parts, variant conditions, interaction states, breakpoints or fixed container-query bounds.

The compiler emits CSS and a minimal component profile. Centralized authoring does not require retaining every component's customization in the browser.

## Precedence
Library defaults are overridden by brand, product and local configuration, then explicit instance props. Profiles accumulate part classes and only contribute defaults they actually specify.

CSS layer order is fixed by the layer prelude. Within one layer, overlapping rules still require deterministic stylesheet order. Class-name accumulation is not a replacement for the CSS cascade.

## Static and executable configuration
Portable sheets contain validated data. Slot constructors, callbacks and arbitrary executable customization remain code-bound on the appropriate server or client side.

The optional runtime styled helper binds a compiled sheet to a React element. It is not a compatibility implementation of MUI sx and does not accept unrestricted runtime CSS callback syntax.

## Responsive rules
Spacing values can update through CSS variables. A threshold inside a compiled media query cannot be changed by assigning a similarly named custom property. Change the compiled profile or use an explicit dynamic rule-generation path.

The live compiler below is intentionally part of a developer-tool page, not part of the ordinary Button payload.

## Open typed variants
The type-only visual-variants registry is generated from component descriptors. ComponentVariantOverrides accepts keys such as button.variant with additional string values. Extend the runtime authoring descriptor with extendDescriptor and compile matching rules as well: TypeScript augmentation alone does not create a style.

Composed styledPart controls accept a typed variants prop. It is removed before DOM forwarding and inherited by descendant parts through ComponentStyleScope. Generic collection roots remain composable without erasing their value types. Server-safe Text, Heading, Surface and supported display parts accept explicit profiles rather than requiring a client hook.

## Theme versus component axes
Theme axes select token contexts. Component variants select a control's appearance and do not create new theme contexts. Their schemas, generation, precedence and runtime responsibilities are intentionally distinct. This avoids a global all-component configuration payload.

## Print-aware component sheets

A rule can select `media: 'print'` or `media: 'screen'`, in addition to a breakpoint or container condition. Numeric transition durations and delays are milliseconds; numeric length properties are pixels. Invalid typed-token/property pairs fail compilation.

```ts
const printRule = {
  id: 'printed-action',
  part: 'root',
  media: 'print',
  declarations: { color: 'black', boxShadow: 'none', breakInside: 'avoid' },
} as const;
```

## Pattern labels

Command palette, transfer list and toaster labels also accept code-bound component settings. Close/dismiss labels, empty messages, action labels and announcement formatters can be localized without replacing the component. This is not a bundled complete translation catalog.

## Named interaction presets

The shared `interaction` prop is separate from component size, tone and surface variants. Use its `variant` to choose a feedback preset, `level` to choose strength, and `effects` for individual behavior overrides. Initial adoption covers slider roots and custom ScrollArea roots; unsupported components do not advertise this prop.

For a custom named preset, augment `InteractionVariantOverrides` in `@fayegram-ai/faye-ui/contracts/interaction` and provide matching CSS or profile classes. A custom name starts from the minimal feedback baseline; TypeScript augmentation alone does not supply its styling. The root hooks `data-faye-ui-interaction-variant`, `data-faye-ui-interaction-level` and `data-faye-ui-track-effect` identify the resolved choices. Public interaction tokens can customize expansion without targeting internal paint layers.

The typed effect union and target map can grow as additional component capabilities are implemented. Existing configuration syntax remains the same; there is no separate enhanced-mode customization API.

## Executable example source

```tsx
'use client';
import { useMemo, useState } from 'react';
import { compileSheet } from '@fayegram-ai/faye-ui/styles';
import { SheetInspector } from '@fayegram-ai/faye-ui/devtools/inspector';
import { buttonDescriptor } from '@fayegram-ai/faye-ui/controls/button.descriptor';
import { Slider } from '@fayegram-ai/faye-ui/controls/slider';
import { Checkbox } from '@fayegram-ai/faye-ui/controls/checkbox';
import { ControlLabel } from '@fayegram-ai/faye-ui/controls/field-layout';
import { Button } from '@fayegram-ai/faye-ui/controls/button';
import { ThemeScope, ComponentStyleScope } from '@fayegram-ai/faye-ui/provider/provider';
import { Stack, Inline } from '@fayegram-ai/faye-ui/layout/layout';
import { Section, Result } from '../example';
export default function Customization() {
    const [weight, setWeight] = useState(500), [uppercase, setUppercase] = useState(false);
    const sheet = useMemo(() => compileSheet({ schemaVersion: 1, id: 'docs-button', component: 'button', defaults: { tone: 'accent' }, rules: [{ id: 'label', part: 'label', declarations: { fontWeight: weight, textTransform: uppercase ? 'uppercase' : 'none' } }, { id: 'root', part: 'root', when: { variant: 'solid' }, declarations: { borderRadius: { token: 'radius.control' }, paddingInline: { token: 'space.6' } } }] }, buttonDescriptor), [weight, uppercase]);
    return <Section title="Live, validated component sheet" note="This studio intentionally includes the authoring compiler. Ordinary precompiled consumers do not need it in the browser."><style>{sheet.css}</style><Stack gap="4"><Stack gap="3"><Slider.Root min={400} max={700} step={100} value={weight} onValueChange={setWeight}><span>Label weight: <Slider.Value/></span><Slider.Control><Slider.Track><Slider.Indicator/><Slider.Thumb aria-label="Label weight"/></Slider.Track></Slider.Control></Slider.Root><ControlLabel label="Uppercase labels">{attrs => <Checkbox.Root {...attrs} checked={uppercase} onCheckedChange={setUppercase}><Checkbox.Indicator/></Checkbox.Root>}</ControlLabel></Stack><ThemeScope profiles={[sheet.profile]}><ComponentStyleScope name="button" variants={{ size: 'sm' }}><Inline wrap><Button variant="solid">Profile default</Button><Button variant="outline">Outline</Button><Button tone="danger" variant="solid">Explicit intent wins</Button></Inline></ComponentStyleScope></ThemeScope><Result>{JSON.stringify(sheet.profile, null, 2)}</Result><SheetInspector sheet={sheet}/></Stack></Section>;
}
```
