# 组件与样式

组件从 `@minidocs/astro/components` 导入。每个组件都会把没有列出的属性原样传给渲染出的元素，`class` 会和组件自己的 class 合并。

## 组件

### 布局

| 组件               | 渲染为         | 参数                         |
| ---------------- | ----------- | -------------------------- |
| `Layout.Root`    | `<div>`     | 无                          |
| `Layout.Header`  | `<header>`  | `end` slot 放在右侧            |
| `Layout.Title`   | `<a>`       | `href`                     |
| `Layout.Sidebar` | `<aside>`   | 无                          |
| `Layout.Main`    | `<main>`    | 无                          |
| `Layout.Aside`   | `<details>` | `title`：这一栏的标题，收起时也是按钮上的文字 |
| `Prose`          | `<article>` | 无                          |

### 侧边栏

| 组件                | 渲染为                                          | 参数                                                                                         |
| ----------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `Sidebar.Root`    | `<nav>`                                      | `id`；`label`：导航的无障碍名称                                                                      |
| `Sidebar.List`    | `<ul>`                                       | 无                                                                                          |
| `Sidebar.Item`    | `<li>`                                       | 无                                                                                          |
| `Sidebar.Link`    | `<a>`                                        | `href`；`current`：是否是当前页面                                                                   |
| `Sidebar.Label`   | `<span>`                                     | 无                                                                                          |
| `Sidebar.Group`   | 没有 `href` 或在自己的页面上时是 `<details>`，否则是 `<div>` | `open`：初始是否展开；`name`：同名的分组互斥展开；`href`：分组自己的页面；`current`：分组自己的页面是否是当前页面。标题写在 `label` slot 里 |
| `Sidebar.Trigger` | `<button>`                                   | `target`：要打开和关闭的 `Sidebar.Root` 的 `id`                                                     |

`Sidebar.Link` 也接受 `open` 并忽略它，所以 `nav.of(node)` 可以展开到任何一个组件上。

### 本页目录

| 组件         | 渲染为     | 参数            |
| ---------- | ------- | ------------- |
| `Toc.Root` | `<nav>` | `label`       |
| `Toc.List` | `<ul>`  | 无             |
| `Toc.Item` | `<li>`  | 无             |
| `Toc.Link` | `<a>`   | `slug`：标题的 id |

### 翻页

| 组件            | 渲染为      | 参数                           |
| ------------- | -------- | ---------------------------- |
| `Pager.Root`  | `<nav>`  | `label`                      |
| `Pager.Link`  | `<a>`    | `href`；`rel`：`prev` 或 `next` |
| `Pager.Label` | `<span>` | 无                            |
| `Pager.Title` | `<span>` | 无                            |

### 提示框

| 组件              | 渲染为                 | 参数                                                              |
| --------------- | ------------------- | --------------------------------------------------------------- |
| `Callout.Root`  | `<div role="note">` | `type`：`note`、`tip`、`important`、`warning` 或 `caution`，默认 `note` |
| `Callout.Title` | `<p>`               | 无                                                               |

### 搜索

| 组件                                              | 渲染为        | 参数                                                                   |
| ----------------------------------------------- | ---------- | -------------------------------------------------------------------- |
| `Search.Trigger`                                | `<button>` | `target`：`Search.Root` 的 `id`；`shortcut`：快捷键，默认 `Mod+K`，`false` 表示没有 |
| `Search.Shortcut`                               | `<kbd>`    | 无                                                                    |
| `Search.Root`                                   | `<search>` | `id`，必填                                                              |
| `Search.Dialog`                                 | `<dialog>` | `label`                                                              |
| `Search.Input`                                  | `<input>`  | `label`、`placeholder`                                                |
| `Search.Results`                                | `<div>`    | `label`                                                              |
| `Search.Idle`、`Loading`、`Found`、`Empty`、`Error` | `<div>`    | 无                                                                    |
| `Search.Query`、`Search.Count`                   | `<span>`   | 无                                                                    |

## 交互函数

组件自带交互。自己写 HTML、不用组件时，从 `@minidocs/astro/behaviors` 导入对应的函数，加到元素上。每个函数都返回一个清理函数。

| 函数                                                  | 作用                                                                         |
| --------------------------------------------------- | -------------------------------------------------------------------------- |
| `attachSidebar(root)`                               | 记住分组的展开状态和滚动位置，跨页面恢复。分组要带 `data-md-sidebar-group`                          |
| `attachTrigger(button)`                             | 用按钮打开和关闭 `aria-controls` 指向的元素，按 Esc 或点击外面时关闭                              |
| `attachToc(root)`                                   | 给正在阅读的那一节的链接加上 `aria-current="true"`。链接是 `root` 里所有 `href` 以 `#` 开头的 `<a>` |
| `attachSearch(root, { source, render, debounce? })` | 运行搜索。`debounce` 是停止输入多少毫秒后开始搜索，默认 `100`                                    |
| `splitMarks(html)`                                  | 把带 `<mark>` 的 HTML 拆成 `{ text, marked }` 片段，其他标签只保留文字                      |

## 事件

都会冒泡。

| 事件                  | 派发在           | 什么时候                      | `detail`            |
| ------------------- | ------------- | ------------------------- | ------------------- |
| `md:sidebar-toggle` | 侧边栏           | 用 `Sidebar.Trigger` 打开或关闭 | `{ open }`          |
| `md:toc-change`     | `Toc.Root`    | 正在阅读的那一节变了                | `{ link }`          |
| `md:search-open`    | `Search.Root` | 对话框打开                     | 无                   |
| `md:search-close`   | `Search.Root` | 对话框关闭                     | 无                   |
| `md:search-select`  | `Search.Root` | 选中了一个结果                   | `{ option, query }` |
| `md:search-error`   | `Search.Root` | `source` 抛出了错误            | `{ error, query }`  |

## CSS 变量

默认样式的变量都定义在 `:root` 上，可以在你的样式里覆盖。

| 变量                                 | 作用                                  |
| ---------------------------------- | ----------------------------------- |
| `--md-color-bg`                    | 页面和抽屉的背景                            |
| `--md-color-heading`               | 标题、加粗文字、悬停时的文字                      |
| `--md-color-text`                  | 正文                                  |
| `--md-color-muted`                 | 次要文字，比如目录和列表符号                      |
| `--md-color-border`                | 导轨、边框、分隔线                           |
| `--md-color-accent`                | 当前位置和链接，默认和 `--md-color-heading` 相同 |
| `--md-color-hover`                 | 悬停时的背景                              |
| `--md-color-current`               | 当前页面的背景                             |
| `--md-color-code-bg`               | 代码块的背景                              |
| `--md-color-note`                  | `note` 提示框的颜色                       |
| `--md-color-tip`                   | `tip` 提示框的颜色                        |
| `--md-color-important`             | `important` 提示框的颜色                  |
| `--md-color-warning`               | `warning` 提示框的颜色                    |
| `--md-color-caution`               | `caution` 提示框的颜色                    |
| `--md-font-sans`                   | 用了 `Layout.Root` 时的页面字体             |
| `--md-font-mono`                   | 代码字体                                |
| `--md-radius`                      | 侧边栏每一项、按钮、图片的圆角                     |
| `--md-focus-ring`                  | 键盘焦点的轮廓                             |
| `--md-sidebar-font-size`           | 侧边栏的字号                              |
| `--md-sidebar-item-padding-block`  | 侧边栏每一项上下的内边距                        |
| `--md-sidebar-item-padding-inline` | 侧边栏每一项左右的内边距                        |
| `--md-sidebar-indent`              | 嵌套层级的导轨离上一级的距离                      |
| `--md-sidebar-rail-gap`            | 导轨和子项之间的距离                          |
| `--md-toc-font-size`               | 目录的字号                               |
| `--md-toc-indent`                  | 目录每一层的缩进                            |
| `--md-prose-font-size`             | 正文字号                                |
| `--md-prose-line-height`           | 正文行高，默认 1.75                        |
| `--md-header-height`               | 标题栏的高度，侧边栏和目录的吸顶位置也由它决定             |
| `--md-layout-sidebar-width`        | 侧边栏一栏的宽度                            |
| `--md-layout-main-width`           | 正文一栏的最大宽度                           |
| `--md-layout-aside-width`          | 本页目录一栏的宽度                           |
| `--md-layout-drawer-width`         | 窄屏下抽屉的宽度                            |

## class 和状态

| class                                                   | 元素                                           |
| ------------------------------------------------------- | -------------------------------------------- |
| `.md-layout`                                            | `Layout.Root`                                |
| `.md-layout-header`                                     | `Layout.Header`                              |
| `.md-layout-title`                                      | `Layout.Title`                               |
| `.md-layout-sidebar`                                    | `Layout.Sidebar`                             |
| `.md-layout-main`                                       | `Layout.Main`                                |
| `.md-layout-aside`                                      | `Layout.Aside`                               |
| `.md-prose`                                             | `Prose`                                      |
| `.md-sidebar`                                           | `Sidebar.Root`                               |
| `.md-sidebar-list`                                      | `Sidebar.List`                               |
| `.md-sidebar-item`                                      | `Sidebar.Item`                               |
| `.md-sidebar-link`                                      | `Sidebar.Link`                               |
| `.md-sidebar-label`                                     | `Sidebar.Label`                              |
| `.md-sidebar-group`                                     | `Sidebar.Group`                              |
| `.md-sidebar-group-title`                               | 分组的标题，可能是链接，也可能是 `<summary>`                 |
| `.md-sidebar-trigger`                                   | `Sidebar.Trigger`                            |
| `.md-toc`                                               | `Toc.Root`                                   |
| `.md-toc-list`                                          | `Toc.List`                                   |
| `.md-toc-item`                                          | `Toc.Item`                                   |
| `.md-toc-link`                                          | `Toc.Link`                                   |
| `.md-pager`                                             | `Pager.Root`                                 |
| `.md-pager-link`                                        | `Pager.Link`                                 |
| `.md-pager-label`                                       | `Pager.Label`                                |
| `.md-pager-title`                                       | `Pager.Title`                                |
| `.md-callout`                                           | `Callout.Root`，以及 `:::type` 和 `> [!TYPE]` 语法 |
| `.md-callout-title`                                     | `Callout.Title`，以及指令语法的标题                    |
| `.md-search`                                            | `Search.Root`                                |
| `.md-search-trigger`                                    | `Search.Trigger`                             |
| `.md-search-shortcut`                                   | `Search.Shortcut`                            |
| `.md-search-dialog`                                     | `Search.Dialog`                              |
| `.md-search-input`                                      | `Search.Input`                               |
| `.md-search-results`                                    | `Search.Results`                             |
| `.md-search-idle`、`-loading`、`-found`、`-empty`、`-error` | 各个状态组件                                       |
| `.md-search-query`、`.md-search-count`                   | `Search.Query`、`Search.Count`                |

| 状态         | 选择器                                                            |
| ---------- | -------------------------------------------------------------- |
| 当前页面       | `[aria-current="page"]`                                        |
| 目录里正在阅读的标题 | `.md-toc-link[aria-current="true"]`                            |
| 当前页面所在的那一项 | `.md-sidebar-item:has(> [aria-current])`                       |
| 分组展开或收起    | `.md-sidebar-group[data-state="open"]`、`[data-state="closed"]` |
| 侧边栏打开或关闭   | `.md-sidebar[data-state="open"]`                               |
| 外部链接       | `.md-sidebar-link[data-external]`                              |
| 上一页或下一页    | `.md-pager-link[rel="prev"]`、`[rel="next"]`                    |
| 提示框的类型     | `.md-callout[data-type="tip"]` 等                               |
| 搜索的状态      | `.md-search[data-status="found"]` 等，查询进行中时带 `aria-busy`        |
| 搜索结果里选中的选项 | `[role="option"][aria-selected="true"]`                        |
