@tenphi/cookbook 0.20.4 → 0.20.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -39,8 +39,9 @@ export default defineDocsConfig({
39
39
 
40
40
  For local fonts, place files in `public/fonts/` and use
41
41
  `fonts: { body: { family: "My Font", files: [{ src: "/fonts/my-font.woff2" }] } }`.
42
- See [Theme and components](./docs/theme-and-components.md) for all named
43
- sub-elements and the custom component flow.
42
+ See [Component styles](./docs/component-styles.md) for all named
43
+ sub-elements and [Custom components](./docs/custom-components.md) for the
44
+ custom component flow.
44
45
 
45
46
  Without configuration, a root `README.md` becomes `/` and
46
47
  `docs/**/*.{md,mdx}` supplies the remaining pages. Cookbook includes its Astro renderer,
@@ -61,7 +62,7 @@ export const ProjectBadge = defineComponent("ProjectBadge", {
61
62
  Customize this component's root through `theme.customStyles.ProjectBadge`; it has no
62
63
  named sub-elements. The `/styling` entry point also exports `tasty`, `useGlobalStyles`,
63
64
  `resolveComponentStyles`, `mergeStyles`, and the `Styles` type. Cookbook extracts
64
- the CSS automatically. See [Theme and components](https://cookbook.tenphi.me/theme-and-components/)
65
+ the CSS automatically. See [Custom components](https://cookbook.tenphi.me/custom-components/)
65
66
  for a complete custom logo and site title example.
66
67
 
67
68
  Lint these styles with the plugin and Cookbook validation preset from
@@ -79,5 +80,5 @@ The entry point exports the default Tasty ESLint plugin, `recommended` and `stri
79
80
  rule maps, and the upstream configuration types. The preset recognizes Cookbook's
80
81
  theme names and custom styling helpers, including `defineComponent`. `extends`
81
82
  merges your additional tokens, states, and presets with these built-ins.
82
- See [Linting custom styles](https://cookbook.tenphi.me/theme-and-components/#linting-custom-styles)
83
+ See [Linting custom styles](https://cookbook.tenphi.me/custom-components/#linting-custom-styles)
83
84
  for ESLint and oxlint configuration examples.
@@ -5,7 +5,15 @@ sidebar:
5
5
  order: 4
6
6
  ---
7
7
 
8
- import { Callout, CodeGroup, Tab, Tabs } from "@tenphi/cookbook/components";
8
+ import {
9
+ Callout,
10
+ Card,
11
+ CodeGroup,
12
+ Preview,
13
+ Steps,
14
+ Tab,
15
+ Tabs,
16
+ } from "@tenphi/cookbook/components";
9
17
 
10
18
  Write ordinary Markdown for most pages. Use MDX when a page needs components,
11
19
  and import them from `@tenphi/cookbook/components`. Local MDX is supported by
@@ -73,7 +81,73 @@ Each panel retains keyboard-accessible tabs and readable fallback content.
73
81
  ]}
74
82
  />
75
83
 
76
- ## Other components
84
+ ## Cards, steps, and previews
85
+
86
+ Use a card to link to another page, or omit `href` to present a standalone
87
+ summary. `Steps` renders an ordered list; put ordinary `li` elements inside it.
88
+
89
+ ```mdx
90
+ import { Card, Steps } from "@tenphi/cookbook/components";
91
+
92
+ <Card title="On-page navigation" href="#on-page-navigation">
93
+ Offer a compact contents list on smaller screens.
94
+ </Card>
95
+
96
+ <Steps>
97
+ <li>Choose a content source.</li>
98
+ <li>Configure the navigation.</li>
99
+ <li>Build and check the output.</li>
100
+ </Steps>
101
+ ```
102
+
103
+ <Card title="On-page navigation" href="#on-page-navigation">
104
+ Offer a compact contents list on smaller screens.
105
+ </Card>
106
+
107
+ <Steps>
108
+ <li>Choose a content source.</li>
109
+ <li>Configure the navigation.</li>
110
+ <li>Build and check the output.</li>
111
+ </Steps>
112
+
113
+ `Preview` runs HTML and optional JavaScript in a sandboxed iframe with a source
114
+ disclosure. It cannot access the documentation page's origin. Its `css` prop is
115
+ for the isolated preview document; style the documentation shell with Tasty.
116
+
117
+ ```mdx
118
+ import { Preview } from "@tenphi/cookbook/components";
119
+
120
+ <Preview
121
+ title="A simple button"
122
+ html={'<button type="button">Try it</button>'}
123
+ css={"button { padding: 0.75rem; }"}
124
+ />
125
+ ```
126
+
127
+ <Preview
128
+ title="A simple button"
129
+ html={'<button type="button">Try it</button>'}
130
+ css={"button { padding: 0.75rem; }"}
131
+ />
132
+
133
+ ## Cookbook logo
134
+
135
+ `Logo` renders the Cookbook mark. Use `label` when it carries meaning or
136
+ `decorative` beside nearby text that already names the site. To display your
137
+ own artwork in the header and drawer, configure
138
+ [`site.logo`](./configuration.md#site-logo).
139
+
140
+ ## Diff snippets
141
+
142
+ Use a `diff` code fence to highlight additions and deletions. The `+` and `-`
143
+ markers remain visible independently of their theme-aware backgrounds:
144
+
145
+ ```diff
146
+ -formatOkhsl(v.h, v.s * 100, l * 100);
147
+ +formatOkhsl(v.h, v.s, l);
148
+ ```
149
+
150
+ ## Component props
77
151
 
78
152
  | Component | Props and behavior |
79
153
  | --------- | --------------------------------------------------------------------------------------------------- |
@@ -84,7 +158,7 @@ Each panel retains keyboard-accessible tabs and readable fallback content.
84
158
 
85
159
  The public package exports each component's props type, such as `TabProps`,
86
160
  `CalloutProps`, and `CodeGroupProps`. Styles and all named sub-elements are
87
- listed in [Theme and components](./theme-and-components.md#style-customization).
161
+ listed in [Component styles](./component-styles.md#style-customization).
88
162
 
89
163
  ## On-page navigation
90
164
 
@@ -27,7 +27,7 @@ set of selectors to override after rendering:
27
27
  responsive `theme.states` once. Components consume those roles consistently.
28
28
  - Change a built-in component through a **partial**
29
29
  `theme.styles.<ComponentName>` Tasty object. Cookbook merges it into the full
30
- base style before extracting CSS. Its [named component parts](./theme-and-components.md#style-customization)
30
+ base style before extracting CSS. Its [named component parts](./component-styles.md#style-customization)
31
31
  are published so a header title, search field, or sidebar item can be changed
32
32
  without copying an entire component.
33
33
  - Add a styled component with `defineComponent()` or replace markup and behavior
@@ -52,9 +52,9 @@ export default defineDocsConfig({
52
52
  ```
53
53
 
54
54
  This style contract is specific to Cookbook's Tasty and Glaze system. Structural
55
- changes still require an Astro override. Read the [customization rules](./customization-rules.md)
56
- and [theme reference](./theme-and-components.md) for the supported names and
57
- the full design-system API.
55
+ changes still require an Astro override. Read the [customization rules](./customization-rules.md),
56
+ [theme guide](./theme-and-components.md), and [component styles reference](./component-styles.md)
57
+ for the supported configuration and names.
58
58
 
59
59
  ## Start with the material you have
60
60
 
@@ -0,0 +1,399 @@
1
+ ---
2
+ title: Component styles
3
+ description: Customize built-in UI surfaces through partial Tasty style objects and named sub-elements.
4
+ ---
5
+ For color roles and design tokens, start with the
6
+ [theme overview](./theme-and-components.md). For your own components, see
7
+ [Custom components](./custom-components.md).
8
+
9
+ ## Style customization
10
+
11
+ Cookbook-owned interface elements are direct `tasty()` components. Supported
12
+ Cookbook components and generated Markdown surfaces use Tasty style trees.
13
+ Customize them by name under `theme.styles`; the configuration is resolved
14
+ before CSS generation, so this is not a selector-based CSS override.
15
+
16
+ Cookbook merges your partial style object with the component's base styles
17
+ before Tasty extracts CSS. The generated stylesheet contains the resolved
18
+ style, so you can change an element without copying its full defaults.
19
+
20
+ Start with the area you want to change, then use the complete sub-element
21
+ inventory below to find its exact anatomy:
22
+
23
+ | Page area | Style names to inspect |
24
+ | ----------------------------- | ------------------------------------------------------------------------------------ |
25
+ | Header, title, and navigation | `HeaderFrame`, `Header`, `SiteLogo`, `HeaderLinks`, `TopNavigation` |
26
+ | Sidebar and mobile menu | `Sidebar`, `MobileMenuToggle`, `MobileNavigationTabs`, `MobileMenuFooter` |
27
+ | Article text and headings | `Markdown`, `MarkdownHeading`, `Heading`, `MainContent` |
28
+ | Code and diagrams | `MarkdownCodeBlock`, `MarkdownInlineCode`, `SyntaxHighlight`, `CodeGroup`, `Mermaid` |
29
+ | Search | `SearchButton`, `Search`, `SearchResults` |
30
+ | Table of contents | `TableOfContents`, `MobileTableOfContents`, `TableOfContentsLayout` |
31
+ | Cards, notes, and tabs | `Card`, `Callout`, `MarkdownAlert`, `Tabs` |
32
+ | Footer and page controls | `Footer`, `Pagination`, `PageActions`, `ThemeSelect` |
33
+
34
+ For example, this changes a typography role and one named element without
35
+ copying a component's full style tree:
36
+
37
+ ```ts
38
+ theme: {
39
+ presets: { h2: { fontSize: "1.75rem" } },
40
+ styles: {
41
+ Sidebar: {
42
+ LinkLabel: {
43
+ preset: "body",
44
+ whiteSpace: { "": "nowrap", "@mobile": "normal" }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ The `@mobile` value sits with the default value in one Tasty state map. Shared
52
+ tokens and presets keep the component aligned with the rest of the site, while
53
+ Glaze resolves semantic colors across the configured schemes and contrast
54
+ modes.
55
+
56
+ ### Responsive states
57
+
58
+ Cookbook registers these Tasty state aliases for `theme.styles`, custom
59
+ components, and recipes. Widths use CSS `rem` units; their pixel values depend
60
+ on the browser's font-size settings.
61
+
62
+ | State | Condition | Typical use |
63
+ | ----------------- | -------------------------------- | -------------------------------------------------- |
64
+ | `@compact` | width ≤ 23rem | Hide optional header controls in very narrow space |
65
+ | `@small` | width ≤ 40rem | Stack compact grids |
66
+ | `@shell-mobile` | width ≤ 48rem | Switch the page shell to its narrow arrangement |
67
+ | `@shell-desktop` | width > 48rem | Restore the wider shell arrangement |
68
+ | `@mobile` | width < 50rem | Mobile navigation and component layouts |
69
+ | `@desktop` | width ≥ 50rem | Desktop navigation and component layouts |
70
+ | `@medium-layout` | 50rem ≤ width < 72rem | Intermediate two-column layouts |
71
+ | `@narrow-layout` | width < 72rem | Hide or reposition the desktop table of contents |
72
+ | `@reduced-motion` | `prefers-reduced-motion: reduce` | Remove optional motion |
73
+
74
+ The 48rem shell boundary, 50rem navigation boundary, and 72rem contents
75
+ boundary serve different parts of the layout; their ranges intentionally
76
+ overlap. Use the default state key `""` for the value outside the listed
77
+ condition. Add your own aliases with `theme.states`; redefining a built-in
78
+ alias also changes the renderer's responsive layout, so check the whole site
79
+ when doing so.
80
+
81
+ In a generated site, run `npm run validate` (or the matching package manager's
82
+ command) after editing `docs.config.ts`. It checks TypeScript theme properties,
83
+ then runs Cookbook's preflight and production output checks. A misspelled
84
+ preset or built-in sub-element property fails type checking.
85
+
86
+ Provide only the root and named
87
+ [sub-element](./upstream/tasty/docs/dsl.md#sub-element) properties you want to
88
+ override. Cookbook deep-merges that partial style object into the complete
89
+ base style object inside the renderer, following Tasty's
90
+ [state-map merge semantics](./upstream/tasty/docs/dsl.md#extending-vs-replacing-state-maps):
91
+
92
+ ```ts
93
+ theme: {
94
+ styles: {
95
+ ThemeSelect: {
96
+ Trigger: {
97
+ border: "#border-strong"
98
+ },
99
+ Panel: {
100
+ padding: "1x",
101
+ shadow: "0 1rem 3rem #shadow"
102
+ }
103
+ },
104
+ TopNavigation: {
105
+ Link: { preset: "body" },
106
+ CurrentLink: { color: "#accent-text" }
107
+ },
108
+ Sidebar: {
109
+ LinkLabel: { whiteSpace: "normal" }
110
+ },
111
+ TableOfContents: {
112
+ LinkLabel: { whiteSpace: "normal" }
113
+ },
114
+ MobileMenuToggle: {
115
+ Page: { color: "#accent-text" }
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ No merge helper or base style object is required in user configuration. Style
122
+ customization has one behavior: every supplied object is a partial override and
123
+ is merged into the base inside Cookbook.
124
+
125
+ Every configurable surface accepts styles at the root plus the named Tasty
126
+ sub-elements below. The list is generated from the public component registry so
127
+ it stays complete when a surface changes.
128
+
129
+ ### Complete component anatomy
130
+
131
+ <!-- component-anatomy:start -->
132
+
133
+ #### Page shell
134
+
135
+ * `Document`: `All`, `Body`, `Control`, `Pointer`, `ResponsiveWidth`, `ResponsiveHeight`, `Hidden`, `PrintHidden`, `DesktopBlock`, `DesktopFlex`, `ScreenReaderOnly`, `Strong`, `Link`, `NarrowBlock`, `MobileBlock`, `Code`, `FocusRing`, `CurrentLink`, `SearchOpen`
136
+ * `Layout`: `Islands`, `LockedPage`, `Light`, `Auto`
137
+ * `PageFrame`: `MainFrame`, `SidebarFrame`, `Columns`
138
+ * `MainPane`: `WithSidebars`
139
+ * `MainContent`: `ContentSpacing`, `Container`, `Panel`, `FirstPanel`, `BodyPanel`
140
+ * `HeaderFrame`: None
141
+ * `Heading`: `Level1`, `Level2`, `Level3`, `Level4`, `Level5`, `Level6`, `PageTitle`
142
+ * `Banner`: `Link`
143
+ * `SkipLink`: `Focus`
144
+
145
+ #### Navigation and controls
146
+
147
+ * `Header`: `Primary`, `TitleAndSearch`, `Title`, `LogoLink`, `Logo`, `SiteTitle`, `Search`, `SearchElement`, `Tools`, `ToolItem`, `Social`, `MobileTheme`, `MobileLanguage`
148
+ * `HeaderLinks`: `Desktop`, `DesktopLink`, `Link`, `HoverLink`, `PrimaryLink`, `HoverPrimaryLink`, `Trigger`, `HoverTrigger`, `Panel`, `OpenPanel`, `PanelNavigation`, `PanelLink`, `FirstPanelLink`, `Close`, `HoverClose`
149
+ * `SearchButton`: `PendingShortcut`, `Label`, `Shortcut`, `Hover`, `Active`, `NativeIcon`, `Icon`
150
+ * `Sidebar`: `Backdrop`, `OpenBackdrop`, `MobileHeading`, `HomeLink`, `HomeLogo`, `HomeLabel`, `Close`, `HoverClose`, `CloseIcon`, `CurrentLink`, `OpenPane`, `EnteredPane`, `Content`, `Tree`, `List`, `Item`, `TopLevelSpacing`, `GroupSpacing`, `NestedItem`, `SectionHeading`, `Control`, `Summary`, `GroupLabel`, `GroupLabelText`, `Link`, `LinkLabel`, `InteractiveControl`, `SummaryMarker`, `Caret`, `ExpandedCaret`, `LinkedSummary`, `GroupLink`, `LinkedSectionHeading`, `SectionLink`, `Badge`, `TopLevelLink`
151
+ * `MobileMenuToggle`: `Control`, `Icon`, `Section`, `Page`, `HoverControl`, `ActiveControl`
152
+ * `MobileNavigationTabs`: `Trigger`, `Marker`, `Caret`, `ExpandedCaret`, `Label`, `List`, `Item`, `Link`, `HoverLink`, `CurrentLink`
153
+ * `MobileMenuFooter`: `Social`
154
+ * `TopNavigation`: `Scrollbar`, `Link`, `HoverLink`, `CurrentLink`, `ActiveIndicator`
155
+ * `TableOfContentsLayout`: `WithMobile`, `Content`
156
+ * `TableOfContents`: `Heading`, `List`, `Item`, `Link`, `LinkLabel`, `HoverLink`, `CurrentLink`
157
+ * `MobileTableOfContents`: `Summary`, `List`, `NestedList`, `Item`, `Link`, `HoverLink`, `Focus`
158
+ * `Pagination`: `Link`, `PreviousLink`, `NextLink`, `NextIcon`, `NextLabel`, `HoverLink`, `ActiveLink`, `Title`, `LoneNextLink`, `Icon`, `PreviousIconRtl`, `NextIconRtl`
159
+ * `VersionSwitcher`: `Trigger`, `HoverTrigger`, `TriggerLabel`, `Caret`, `Panel`, `OpenPanel`, `PanelTitle`, `Options`, `Link`, `HoverLink`, `CurrentLink`, `Checkmark`, `SelectedCheckmark`
160
+ * `LanguageSelect`: `Compact`, `Trigger`, `HoverTrigger`, `ActiveTrigger`, `LabelIcon`, `TriggerLabel`, `Caret`, `CompactTrigger`, `CompactLabel`, `CompactCaret`, `Label`, `HoverLabel`, `Select`, `CompactSelect`, `CompactLabelIcon`, `SidebarTrigger`, `Panel`, `SidebarPanel`, `OpenPanel`, `PanelTitle`, `Options`, `Option`, `HoverOption`, `CurrentOption`, `Fallback`, `Checkmark`, `SelectedCheckmark`
161
+ * `SocialIcons`: `Link`, `HoverLink`, `Icon`
162
+ * `ThemeSelect`: `Trigger`, `HoverTrigger`, `ActiveTrigger`, `Icon`, `Panel`, `OpenPanel`, `Section`, `SectionSpacing`, `SectionLabel`, `Option`, `HoverOption`, `CheckedOption`, `FocusedOption`, `Input`, `OptionIcon`, `Checkmark`, `SelectedCheckmark`
163
+
164
+ #### Rendered content
165
+
166
+ * `Markdown`: `Block`, `BlockSpacing`, `HeadingSpacing`, `List`, `CompactItem`, `ListItem`, `DefinitionTerm`, `DefinitionDescription`, `Link`, `HoverLink`, `Quote`, `Rule`, `Details`, `HoverDetails`, `Summary`, `OpenSummary`, `SummaryMarker`, `SummaryIcon`, `OpenSummaryIcon`, `Code`
167
+ * `MarkdownHeading`: `Heading`, `Heading1`, `Heading2`, `Heading3`, `Heading4`, `Heading5`, `Heading6`, `Link`, `RevealedLink`, `HoverLink`, `LinkIcon`, `CopiedLink`, `CopiedLinkIcon`, `CopiedIcon`
168
+ * `MarkdownCodeBlock`: `Pre`, `CopyButton`, `HoverCopyButton`, `CopiedButton`, `CopyIcon`, `CopiedIcon`, `Code`, `Diff`, `DiffCode`, `DiffLine`, `EmptyDiffLine`, `InsertedLine`, `DeletedLine`
169
+ * `MarkdownInlineCode`: None
170
+ * `MarkdownTable`: `Table`, `Cell`, `LastBodyRowCell`, `HeaderCell`, `Scroll`
171
+ * `MarkdownAlert`: `Note`, `Tip`, `Caution`, `Danger`, `Title`, `FirstContent`
172
+ * `SyntaxHighlight`: `Scroll`, `Wrap`, `Marker`, `Comment`, `Punctuation`, `Keyword`, `String`, `Token`, `Property`, `Number`, `Function`, `Value`, `Operator`, `Text`, `Bg`, `Inserted`, `Deleted`, `Italic`, `Strong`, `Underline`
173
+ * `Mermaid`: `Diagram`, `Text`, `MonoText`
174
+ * `MermaidSource`: None
175
+
176
+ #### Authoring components
177
+
178
+ * `Card`: `Heading2`, `Heading3`, `Paragraph`
179
+ * `Callout`: `Title`, `Body`, `Tip`, `Caution`, `Danger`
180
+ * `CodeGroup`: `Caption`, `Pre`, `Code`
181
+ * `Tab`: `Heading`, `Hidden`, `HiddenHeading`
182
+ * `Tabs`: `List`, `Button`, `SelectedButton`, `FocusedButton`
183
+ * `Steps`: `Item`, `Marker`
184
+ * `Hero`: `Visual`, `DarkVisual`, `LightVisual`, `Stack`, `Copy`, `Title`, `Tagline`, `Actions`, `Action`, `HoverAction`, `PrimaryAction`, `SecondaryAction`, `MinimalAction`, `ActionIcon`
185
+ * `Preview`: `Caption`, `Stage`, `Frame`, `Code`, `Summary`, `HoverSummary`, `ActiveSummary`, `Pre`
186
+ * `SiteLogo`: `Image`, `Light`, `Dark`
187
+ * `Logo`: `Svg`, `Mark`
188
+ * `PageActions`: `Control`, `Hover`, `Focus`, `Pending`, `Status`
189
+ * `Footer`: `Meta`, `LoneMetaItem`, `MetaLink`, `HoverMetaLink`, `Credit`, `CreditLink`, `HoverCreditLink`
190
+ * `PackageVersion`: None
191
+
192
+ #### Search
193
+
194
+ * `Search`: `Status`, `Dialog`, `CloseIcon`, `OpenDialog`, `EnteredDialog`, `Backdrop`, `EnteredBackdrop`, `Frame`, `Container`, `Close`, `HoverClose`, `ActiveClose`
195
+ * `SearchResults`: `UI`, `Form`, `Drawer`, `Input`, `Clear`, `Results`, `Result`, `ResultLink`, `SearchIcon`, `ClearIcon`, `SuppressedClear`, `Message`, `List`, `Title`, `Excerpt`, `NestedResult`, `Match`, `More`, `HoverMore`
196
+
197
+ <!-- component-anatomy:end -->
198
+
199
+ `COOKBOOK_COMPONENT_NAMES` publishes the configuration names, and
200
+ `COOKBOOK_COMPONENT_SUB_ELEMENTS` publishes the complete sub-element lists for
201
+ theme editors and other tooling. The corresponding TypeScript types are
202
+ `CookbookComponentName`, `CookbookComponentSubElementName`,
203
+ `CookbookComponentStyles`, `ComponentStyleConfig`, and `ComponentStylesConfig`.
204
+ Known configuration names provide editor suggestions for their named
205
+ sub-elements. `ThemeSelect` styles the combined Appearance panel; replace old
206
+ `Select` and `Picker` overrides with `Trigger` and `Panel`. The separate
207
+ `ContrastSelect` surface is replaced by the same `ThemeSelect` panel and option
208
+ sub-elements. `SocialIcons` styles the shared icon-button links in the header
209
+ and mobile menu. On wider layouts, heading permalinks sit to the left of the
210
+ heading and are revealed on heading hover or keyboard focus. On mobile they
211
+ stay visible and inline so the target is not clipped by the narrower content
212
+ gutter. Customize the behavior with `MarkdownHeading.Link`,
213
+ `MarkdownHeading.RevealedLink`, and `MarkdownHeading.LinkIcon`. The `#` icon
214
+ scales with its heading and stays centered in the link target across heading
215
+ levels and screen widths. Activating a heading link copies the full page URL
216
+ with that section’s fragment without scrolling or changing the current URL. A
217
+ checkmark and screen-reader status confirm the copy; clipboard failures are
218
+ announced. Modified clicks and links
219
+ without JavaScript retain native anchor behavior. Customize the confirmation
220
+ with `MarkdownHeading.CopiedLink`, `MarkdownHeading.CopiedLinkIcon` (the hidden
221
+ original icon), and `MarkdownHeading.CopiedIcon` (the checkmark).
222
+
223
+ Root properties customize each navigation container. For example, overriding
224
+ `Sidebar.LinkLabel.whiteSpace` keeps the other base `LinkLabel` properties
225
+ because the configured object is merged by default.
226
+ By default, the footer credit uses the primary body text color, while its
227
+ Cookbook link uses the semantic brand link color.
228
+
229
+ `components.overrides` remains the structural escape hatch for replacing an
230
+ Astro component. Prefer `theme.styles` when the markup and behavior remain the
231
+ same.
232
+
233
+ Register custom names and their partial Tasty objects in `theme.customStyles`.
234
+ Built-in names belong in `theme.styles` and reject misspelled sub-elements.
235
+ Custom names can also target a matching user-authored `data-tasty-anatomy` attribute.
236
+ The name must match the string passed to `defineComponent()` or
237
+ `resolveComponentStyles()`, or the `data-tasty-anatomy` value. A production
238
+ build warns when a configured custom name has no matching component style
239
+ resolver or rendered anatomy attribute.
240
+
241
+ The default renderer runs Tasty in Astro extract mode. Direct components and
242
+ the remaining document/vendor bridge styles are collected into shared static
243
+ CSS during the build, while appearance controls add only the small client
244
+ behavior needed to persist selected theme and contrast modes. The compact
245
+ Cookbook logo is shown beside the project title in the default top bar, links
246
+ to the localized home page, and is also the default generated favicon. Use
247
+ [`site.favicon`](./configuration.md#site-icons) to generate the complete icon
248
+ set from project artwork.
249
+
250
+ ## Static behavior
251
+
252
+ Documentation content, navigation, headings, code, and images remain readable
253
+ without client JavaScript. Search, mobile navigation, copy controls, appearance
254
+ persistence, and executable previews enhance the static output.
255
+
256
+ ### Appearance and navigation
257
+
258
+ The Appearance button in the desktop and mobile header opens one panel with
259
+ Color scheme and Contrast sections. Color scheme offers Light, Dark, and Auto;
260
+ Contrast offers Normal, High, and Auto. Each preference is independent, and
261
+ selections are saved in the browser. The panel supports keyboard navigation,
262
+ Escape, and outside-click dismissal. The Appearance, Language, Version, and mobile links
263
+ popovers each fade and scale vertically from 96% to 100% over 120ms when
264
+ opening and closing. Reduced motion disables the transition. Customize the
265
+ Appearance states with
266
+ `theme.styles.ThemeSelect.Panel` and `OpenPanel`; the root `$popover-transition`
267
+ token controls the duration. Contrast can follow the system, force the
268
+ normal palette, or activate the Glaze high-contrast palette.
269
+ System mode responds to `prefers-contrast: more`; an explicit selection is
270
+ persisted and takes precedence over that media query.
271
+
272
+ Interactive controls step up exactly one surface level: a control on `surface`
273
+ uses `surface-2`, while a control on `surface-2` uses `surface-3`. Hover and
274
+ pressed states build on that elevated surface without changing the border.
275
+ Inputs stay on their surrounding surface so their border remains the visual
276
+ boundary. Primary buttons and selected navigation use the fixed-mode
277
+ `accent-surface` and its paired light `accent-surface-text`. The brand fill
278
+ keeps its polarity in dark mode while Glaze adjusts it to preserve label
279
+ contrast.
280
+
281
+ Page navigation keeps Next first in the keyboard order. It appears above
282
+ Previous on narrow screens; wider layouts show Previous at the start and Next
283
+ at the end.
284
+
285
+ ### Responsive header and navigation
286
+
287
+ The header uses `#header`, generated from `theme.palette.header` (or the page
288
+ surface) at 70% opacity in all four appearance modes, with a 16px backdrop blur.
289
+ Customize the outer bar with `theme.styles.HeaderFrame`, its contents with
290
+ `Header`, and header buttons with `HeaderLinks` and `SearchButton`.
291
+
292
+ Below 50rem, page navigation moves into a header row and opens a left drawer.
293
+ `MobileMenuToggle.Section` and `Page` style its breadcrumb labels. The drawer
294
+ contains the complete active section, a collapsible `MobileNavigationTabs`
295
+ selector, and a close button. The drawer slides in and out over 120ms and
296
+ disables motion when the reader prefers reduced motion. Its mobile shadow uses
297
+ the Glaze `shadow`-typed `#shadow` token. Customize the movement and shadow through
298
+ `theme.styles.Sidebar`, and the underlay through `Sidebar.Backdrop` and
299
+ `OpenBackdrop`. `theme.palette.overlay` supplies the underlay declaration, which defaults
300
+ to black at 50% opacity. Glaze resolves it in fixed mode with tone remapping
301
+ disabled, so it stays black in dark and high-contrast schemes.
302
+ Icon buttons retain their plain desktop appearance on mobile. More uses
303
+ left-aligned navigation links with a `1bw` gap, without primary button variants.
304
+ `HeaderLinks.PanelLink` styles the menu rows; `FirstPanelLink` reserves space
305
+ for the close button. The inset divider above the tabs belongs to `TopNavigation`.
306
+
307
+ The desktop table of contents is hidden below 72rem. Set
308
+ `tableOfContents: { mobile: true }` to show an optional compact disclosure there.
309
+ On desktop, the current section is marked as the page scrolls and its link stays
310
+ visible in a long contents list. Customize its appearance with
311
+ `theme.styles.TableOfContents.CurrentLink`.
312
+ `MobileTableOfContents` owns its summary and links; `TableOfContentsLayout`
313
+ controls placement. `Layout` controls shared
314
+ navigation dimensions and the drawer's scroll lock; `PageFrame` styles the
315
+ page container and content columns.
316
+
317
+ ### Header control shape
318
+
319
+ Header buttons and the mobile drawer close button use the independent
320
+ `$header-control-radius` token, which defaults to `999px` for pill and circular
321
+ shapes. Set it to `8px` for the same corners as the default content controls:
322
+
323
+ ```ts
324
+ theme: {
325
+ tokens: { "$header-control-radius": "8px" }
326
+ }
327
+ ```
328
+
329
+ `$radius` continues to control code-copy buttons, navigation items, and other
330
+ content controls. Individual `theme.styles` overrides still take precedence.
331
+ The mobile header divider spans the viewport while its content keeps the
332
+ configured horizontal padding.
333
+
334
+ ## Customize shared page surfaces
335
+
336
+ Each bridge has a complete base style tree; supply only the properties you
337
+ want to change. Sub-elements keep their selectors and all other defaults.
338
+ For example, a compact search dialog and quieter pagination need no CSS:
339
+
340
+ ```ts
341
+ theme: {
342
+ styles: {
343
+ Search: { Dialog: { inlineSize: "max 32rem" } },
344
+ SearchResults: { ResultLink: { color: "#accent-text" } },
345
+ Pagination: { Link: { padding: "1.5x", fill: "#surface" } },
346
+ Banner: { padding: "1x 2x" },
347
+ Markdown: { Quote: { color: "#text", inlinePadding: "3x start" } },
348
+ },
349
+ }
350
+ ```
351
+
352
+ `Document` owns resets, base typography, generic controls, responsive media,
353
+ and accessibility utilities. `MainPane` and `MainContent` own the content
354
+ layout. `Markdown` owns prose, lists, links, quotations, and disclosure
355
+ anatomy. `Search` owns the dialog; `SearchResults` owns the Pagefind UI.
356
+ `MarkdownAlert` styles rendered alert blockquotes; `Card`, `Callout`, and
357
+ `Steps` style Cookbook components.
358
+
359
+ Custom components created with `defineComponent()` receive `theme.customStyles`
360
+ overrides during server rendering. Units, recipes, states, and presets are
361
+ resolved there and emitted as static CSS. Cookbook ships no Tasty/Glaze browser
362
+ runtime, theme configuration, or style hydration setup. Browser scripts and
363
+ `client:*` islands must not import Cookbook styling, Tasty, or Glaze; the build
364
+ rejects these imports. Attach small interaction scripts to server-rendered markup
365
+ or pass already-styled static markup into a client island.
366
+
367
+ Code fences and `CodeGroup` use the same `MarkdownCodeBlock` style tree. Its
368
+ root `$copy-button-size` defaults to `2rem`; the copy control and vertical
369
+ padding share it, keeping equal top, right, and bottom insets on one-line
370
+ snippets. The padding follows the `code` preset's line height. Override it with
371
+ `theme.styles.MarkdownCodeBlock` when changing the control size or code layout.
372
+
373
+ ### Syntax highlighting and isolated previews
374
+
375
+ Shiki classifies code; Tasty renders every token using Glaze's semantic syntax
376
+ colors. Customize token rules with `theme.styles.SyntaxHighlight`, or their
377
+ colors with `theme.palette` (for example `syntax-keyword`). The default
378
+ `syntax-bg` stays white in light mode and takes a slight brand-hued tint, close
379
+ to the page background's saturation, in dark mode. Set
380
+ `theme.palette["syntax-bg"]` to give code its own color seed;
381
+ syntax text and token contrast resolve against that surface. Code fences, including
382
+ MDX and diff blocks, use classes without inline style attributes. Custom Shiki
383
+ transformers should emit classes; unsupported inline declarations fail with a
384
+ configuration hint.
385
+
386
+ The production build rejects style attributes, style blocks (including inside
387
+ shadow-root templates), and non-Tasty stylesheets throughout documentation HTML.
388
+ It parses actual markup, so escaped examples and strings in scripts are allowed.
389
+ The explicit exception is the separate document in a sandboxed `Preview` iframe;
390
+ it cannot access its parent's origin. Configure its size with
391
+ `theme.styles.Preview.Frame`. The documentation shell supports the CSP directive
392
+ `style-src-attr 'none'`. A host's CSP may also restrict the preview document; when
393
+ using that directive, authored previews must use style blocks rather than style
394
+ attributes.
395
+
396
+ Search uses an owned, keyboard-accessible dialog with Pagefind's indexing and
397
+ results UI. Its clear-button sizing is adapted to `SearchResults.Input` styles,
398
+ so the browser does not need inline layout declarations. The adapter is checked
399
+ against the pinned Pagefind UI version during builds.