# Grid 栅格

24 栅格布局系统，配合 `oas-grid-item` 划分列宽，支持间距、偏移与自定义总列数；设置 `columns` 后切换为自动等分布局（simple-grid）。

## 基础栅格

<DemoBlock title="三等分">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

## 不等分

<DemoBlock title="不等分">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="6"><div class="demo-grid-box">span 6</div></oas-grid-item>
    <oas-grid-item span="12"><div class="demo-grid-box">span 12</div></oas-grid-item>
    <oas-grid-item span="6"><div class="demo-grid-box">span 6</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

## 偏移

<DemoBlock title="偏移 offset">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="12"><div class="demo-grid-box">span 12</div></oas-grid-item>
    <oas-grid-item span="8" offset="4"><div class="demo-grid-box">span 8 offset 4</div></oas-grid-item>
    <oas-grid-item span="4" offset="6"><div class="demo-grid-box">span 4 offset 6</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

## 自定义总列数

<DemoBlock title="自定义 cols">
  <oas-grid cols="12" gap="12px" style="width: 100%">
    <oas-grid-item span="6"><div class="demo-grid-box">span 6 / 12 列</div></oas-grid-item>
    <oas-grid-item span="6"><div class="demo-grid-box">span 6 / 12 列</div></oas-grid-item>
    <oas-grid-item span="4"><div class="demo-grid-box">span 4</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

## 自动列（simple-grid）

设置 `columns` 后按 `repeat(n, 1fr)` 自动等分，子项 span 被忽略（span 仅在无 `columns` 时生效），与 24 列栅格并存不冲突。

<DemoBlock title="columns 自动等分">
  <oas-grid columns="3" gap="12px" style="width: 100%">
    <div class="demo-grid-box">1</div>
    <div class="demo-grid-box">2</div>
    <div class="demo-grid-box">3</div>
    <div class="demo-grid-box">4</div>
    <div class="demo-grid-box">5</div>
    <div class="demo-grid-box">6</div>
  </oas-grid>
</DemoBlock>

<DemoBlock title="columns 忽略 span">
  <oas-grid columns="4" gap="12px" style="width: 100%">
    <oas-grid-item span="8"><div class="demo-grid-box">span 8 被忽略</div></oas-grid-item>
    <oas-grid-item span="24"><div class="demo-grid-box">span 24 被忽略</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">span 8 被忽略</div></oas-grid-item>
    <oas-grid-item span="24"><div class="demo-grid-box">span 24 被忽略</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

## 响应式等分列数

`columns` 支持断点简写：基础值 + 空格分隔的若干 `断点:值`（断点协议与 `span` 一致，`sm`=640 / `md`=768 / `lg`=1024 / `xl`=1280，移动优先）。子项仍为等分自动布局、忽略 span。拖窄窗口可观察列数变化。

<DemoBlock title="columns 断点：1 → sm:2 → md:3">
  <oas-grid columns="1 sm:2 md:3" gap="12px" style="width: 100%">
    <div class="demo-grid-box">1</div>
    <div class="demo-grid-box">2</div>
    <div class="demo-grid-box">3</div>
    <div class="demo-grid-box">4</div>
    <div class="demo-grid-box">5</div>
    <div class="demo-grid-box">6</div>
  </oas-grid>
  <p class="demo-grid-note">&lt;640px 每行 1 列；≥640px 每行 2 列；≥768px 每行 3 列。</p>
</DemoBlock>

## 最小子项宽度（自适应宫格）

`min-child-width` 指定每个子项的最小宽度（如 `180px`，纯数字按 px），网格以 `auto-fit + minmax` 依据容器可用宽度自动计算列数——子项免写断点即可流式重排。与 `columns` 并存时 `columns` 优先（`min-child-width` 被忽略）；该模式下子项 `span` / `offset` 同样不生效（自动排布）。

<DemoBlock title="min-child-width 自适应宫格">
  <oas-grid min-child-width="180px" gap="12px" style="width: 100%">
    <div class="demo-grid-box">1</div>
    <div class="demo-grid-box">2</div>
    <div class="demo-grid-box">3</div>
    <div class="demo-grid-box">4</div>
    <div class="demo-grid-box">5</div>
    <div class="demo-grid-box">6</div>
    <div class="demo-grid-box">7</div>
    <div class="demo-grid-box">8</div>
  </oas-grid>
  <p class="demo-grid-note">拖窄/加宽容器观察列数自动增减，无需任何断点。</p>
</DemoBlock>

## 大间距

<DemoBlock title="间距 gap">
  <oas-grid gap="24px" style="width: 100%">
    <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

## 行列间距分离

`gap` 支持两值语法：空格或逗号分隔「行 列」（如 `8 16` / `8,16`），分别控制 row-gap 与 column-gap；单值仍为两轴同值（零回归）。`row-gap` / `column-gap` 属性可单独设置并覆盖 `gap` 对应轴。

<DemoBlock title="gap 两值：行 8 列 24">
  <oas-grid gap="8 24" style="width: 100%">
    <oas-grid-item span="8"><div class="demo-grid-box">行距 8 / 列距 24</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">行距 8 / 列距 24</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">行距 8 / 列距 24</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">行距 8 / 列距 24</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">行距 8 / 列距 24</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">行距 8 / 列距 24</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

<DemoBlock title="gap 逗号双值 + row-gap/column-gap 分离属性">
  <oas-grid gap="8" column-gap="32" style="width: 100%">
    <oas-grid-item span="12"><div class="demo-grid-box">column-gap="32"</div></oas-grid-item>
    <oas-grid-item span="12"><div class="demo-grid-box">column-gap="32"</div></oas-grid-item>
  </oas-grid>
  <oas-grid gap="4,32" style="width: 100%">
    <oas-grid-item span="8"><div class="demo-grid-box">gap="4,32"</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">gap="4,32"</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">gap="4,32"</div></oas-grid-item>
  </oas-grid>
  <oas-grid gap="8" row-gap="24" style="width: 100%; margin-top: 16px">
    <oas-grid-item span="8"><div class="demo-grid-box">gap 8 + row-gap 24</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">gap 8 + row-gap 24</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">gap 8 + row-gap 24</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">行距 24 / 列距 8</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">行距 24 / 列距 8</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">行距 24 / 列距 8</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

## 响应式断点

`span` / `offset` 支持断点简写：基础值 + 空格分隔的若干 `断点:值`（断点 `sm`=640 / `md`=768 / `lg`=1024 / `xl`=1280，移动优先）。拖窄窗口可观察列数变化。

<DemoBlock title="span 断点：24 → md:12 → lg:8">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="24 md:12 lg:8"><div class="demo-grid-box">span 24 / md 12 / lg 8</div></oas-grid-item>
    <oas-grid-item span="24 md:12 lg:8"><div class="demo-grid-box">span 24 / md 12 / lg 8</div></oas-grid-item>
    <oas-grid-item span="24 md:12 lg:8"><div class="demo-grid-box">span 24 / md 12 / lg 8</div></oas-grid-item>
  </oas-grid>
  <p class="demo-grid-note">&lt;640px 每项占满一行；≥768px 两项一行；≥1024px 三等分。</p>
</DemoBlock>

<DemoBlock title="offset 断点：0 → md:4">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="24 md:16"><div class="demo-grid-box">span 24 / md 16</div></oas-grid-item>
    <oas-grid-item span="24 md:4" offset="0 md:4"><div class="demo-grid-box">span 4 offset 4（md 起）</div></oas-grid-item>
  </oas-grid>
  <p class="demo-grid-note">≥768px 右侧项从第 5 列起、占 4 列（offset 4 / span 4）。</p>
</DemoBlock>

## 自宽列

`span="auto"` 让子项按内容自然宽度排布（不展开占列），可与 `offset` 组合。

<DemoBlock title="span=auto 自宽列">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="auto"><div class="demo-grid-box">auto 自适应</div></oas-grid-item>
    <oas-grid-item span="auto" offset="4"><div class="demo-grid-box">auto offset 4</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
    <oas-grid-item span="4"><div class="demo-grid-box">span 4</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

## 容器对齐

`justify` 控制行内轴（justify-items），`align` 控制块向轴（align-items）；合法值直写，非法回落 `stretch` + dev 告警。

<DemoBlock title="justify 行内轴对齐">
  <div class="demo-grid-col">
    <span class="demo-grid-label">justify="start"（默认行为）</span>
    <oas-grid gap="8px" justify="start" style="width: 100%">
      <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
    </oas-grid>
    <span class="demo-grid-label">justify="center"</span>
    <oas-grid gap="8px" justify="center" style="width: 100%">
      <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
    </oas-grid>
    <span class="demo-grid-label">justify="end"</span>
    <oas-grid gap="8px" justify="end" style="width: 100%">
      <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box">span 8</div></oas-grid-item>
    </oas-grid>
  </div>
</DemoBlock>

<DemoBlock title="align 块向轴对齐（固定高度）">
  <div class="demo-grid-col">
    <span class="demo-grid-label">align="start"</span>
    <oas-grid gap="8px" align="start" style="width: 100%; height: 80px">
      <oas-grid-item span="8"><div class="demo-grid-box short">矮</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box">高 40</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box tall">高 64</div></oas-grid-item>
    </oas-grid>
    <span class="demo-grid-label">align="center"</span>
    <oas-grid gap="8px" align="center" style="width: 100%; height: 80px">
      <oas-grid-item span="8"><div class="demo-grid-box short">矮</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box">高 40</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box tall">高 64</div></oas-grid-item>
    </oas-grid>
    <span class="demo-grid-label">align="baseline"</span>
    <oas-grid gap="8px" align="baseline" style="width: 100%; height: 80px">
      <oas-grid-item span="8"><div class="demo-grid-box short">矮</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box">高 40</div></oas-grid-item>
      <oas-grid-item span="8"><div class="demo-grid-box tall">高 64</div></oas-grid-item>
    </oas-grid>
  </div>
</DemoBlock>

## 重排（order / push / pull）

- `order` 表达重排：不改 DOM/源码顺序（语义与读屏顺序保持），仅视觉排序变化
- `push` / `pull`（PRD P2）偏移式平移：在 `offset` 基础上把起始线右移 / 左移 N 列（净偏移 = push − pull，叠加 offset）；净偏移 ≤ 0 时回落自动放置

<DemoBlock title="末位列提到首位（order）">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="8"><div class="demo-grid-box">源码第 1 列（order 0）</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">源码第 2 列（order 0）</div></oas-grid-item>
    <oas-grid-item span="8" order="-1"><div class="demo-grid-box">源码第 3 列（order -1 → 首位）</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

<DemoBlock title="push/pull 偏移平移">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="6"><div class="demo-grid-box">span 6</div></oas-grid-item>
    <oas-grid-item span="6" push="6"><div class="demo-grid-box">span 6 push 6（右移 6 列）</div></oas-grid-item>
    <oas-grid-item span="6" offset="6"><div class="demo-grid-box">span 6 offset 6</div></oas-grid-item>
    <oas-grid-item span="6" offset="6" pull="6"><div class="demo-grid-box">span 6 offset 6 pull 6（拉回本行首）</div></oas-grid-item>
  </oas-grid>
</DemoBlock>

<DemoBlock title="自定义顺序（order）">
  <oas-grid gap="12px" style="width: 100%">
    <oas-grid-item span="6" order="3"><div class="demo-grid-box">A（order 3）</div></oas-grid-item>
    <oas-grid-item span="6" order="1"><div class="demo-grid-box">B（order 1）</div></oas-grid-item>
    <oas-grid-item span="6" order="2"><div class="demo-grid-box">C（order 2）</div></oas-grid-item>
    <oas-grid-item span="6" order="0"><div class="demo-grid-box">D（order 0）</div></oas-grid-item>
  </oas-grid>
  <p class="demo-grid-note">视觉顺序：D（0）→ B（1）→ C（2）→ A（3）。</p>
</DemoBlock>

## 折叠行（collapsed-rows）

`collapsed-rows` 指定折叠态显示的行数（按子项 span/offset 累计的行模型）：超出行数的子项隐藏，末尾出现「展开」尾格（占所在行剩余列）；点击展开后尾格转为「收起」可折回。折叠状态写回受控 `collapsed` 属性并派发 `oas-collapse`；`columns` / `min-child-width` 自动布局下不启用（行模型依赖 span/offset 语义）；行模型按 24 列累计，`cols` 非 24 时行数判定与实际布局有偏差（push/pull 不参与行模型），此组合慎用；总行数不超过 `collapsed-rows` 时不写 `collapsed`（无可折叠内容，全量可见且无尾格）。

<DemoBlock title="collapsed-rows=1 查询条件折叠">
  <oas-grid collapsed-rows="1" gap="12px" style="width: 100%">
    <oas-grid-item span="8"><div class="demo-grid-box">条件 1</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">条件 2</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">条件 3</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">条件 4（第 2 行）</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">条件 5（第 2 行）</div></oas-grid-item>
    <oas-grid-item span="8"><div class="demo-grid-box">条件 6（第 2 行）</div></oas-grid-item>
  </oas-grid>
  <p class="demo-grid-note">默认只显示首行（条件 1~3），点尾格「展开」查看全部，「收起」折回。</p>
</DemoBlock>

## 子项 flex 通道

`oas-grid-item` 的 `flex` 属性内联直写 CSS `flex` 简写（grid 布局下按 CSS 规范不被消费、零干扰），供子项被用于 flex 容器等宿主场景透传。

<style>
  .demo-grid-box {
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--oas-color-bg-hover);
    border-radius: var(--oas-radius-md);
    font-size: var(--oas-font-size-xs);
    color: var(--oas-color-text-secondary);
  }
  /* 4 级主色梯度循环：便于区分相邻块（token 派生，dark 自适应）。
     渐变点选在「浅底深字」与「实底浅字」各自达标的两段，中段（浅底与白字都不够）不出现 */
  oas-grid > *:nth-child(4n+1) .demo-grid-box,
  oas-grid > .demo-grid-box:nth-child(4n+1) {
    background: color-mix(in srgb, var(--oas-color-primary) 10%, var(--oas-color-bg));
    color: var(--oas-color-primary-text);
  }
  oas-grid > *:nth-child(4n+2) .demo-grid-box,
  oas-grid > .demo-grid-box:nth-child(4n+2) {
    background: color-mix(in srgb, var(--oas-color-primary) 22%, var(--oas-color-bg));
    color: var(--oas-color-primary-text);
  }
  oas-grid > *:nth-child(4n+3) .demo-grid-box,
  oas-grid > .demo-grid-box:nth-child(4n+3) {
    background: color-mix(in srgb, var(--oas-color-primary) 78%, var(--oas-color-bg));
    color: var(--oas-color-text-on-primary);
  }
  oas-grid > *:nth-child(4n+4) .demo-grid-box,
  oas-grid > .demo-grid-box:nth-child(4n+4) {
    background: var(--oas-color-primary);
    color: var(--oas-color-text-on-primary);
  }
  /* dark 下主色变浅（#9ecdff），拉大梯度间距保持可分辨。
     档位对齐 light 的两段式：浅底两档（14%/22%）配主色浅字、实底两档（90%/100%）
     配 on-primary 深字——中间混合段（底不够亮配深字、又不够暗配浅字）不出现 */
  .dark oas-grid > *:nth-child(4n+1) .demo-grid-box,
  .dark oas-grid > .demo-grid-box:nth-child(4n+1) {
    background: color-mix(in srgb, var(--oas-color-primary) 14%, var(--oas-color-bg));
    color: var(--oas-color-primary);
  }
  .dark oas-grid > *:nth-child(4n+2) .demo-grid-box,
  .dark oas-grid > .demo-grid-box:nth-child(4n+2) {
    background: color-mix(in srgb, var(--oas-color-primary) 22%, var(--oas-color-bg));
    color: var(--oas-color-primary);
  }
  .dark oas-grid > *:nth-child(4n+3) .demo-grid-box,
  .dark oas-grid > .demo-grid-box:nth-child(4n+3) {
    background: color-mix(in srgb, var(--oas-color-primary) 90%, var(--oas-color-bg));
    color: var(--oas-color-text-on-primary);
  }
  .dark oas-grid > *:nth-child(4n+4) .demo-grid-box,
  .dark oas-grid > .demo-grid-box:nth-child(4n+4) {
    background: var(--oas-color-primary);
    color: var(--oas-color-text-on-primary);
  }
  .demo-grid-box.short {
    height: 28px;
  }
  .demo-grid-box.tall {
    height: 64px;
  }
  .demo-grid-col {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
  }
  .demo-grid-label {
    font-size: var(--oas-font-size-xs);
    color: var(--oas-color-text-secondary);
  }
  .demo-grid-note {
    font-size: var(--oas-font-size-xs);
    color: var(--oas-color-text-secondary);
    margin-top: 8px;
  }
</style>

## API

### oas-grid

#### 属性

| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| `align` | 块向轴对齐（align-items）：`start` / `center` / `end` / `stretch` / `baseline`；非法值回落 `stretch` + dev 告警（同值去重） | `string` | — |
| `collapsed` | 折叠行受控属性（collapsed-rows 配套；首帧缺省组件写入折叠态，宿主/尾格可切换） | — | — |
| `collapsed-rows` | 折叠态显示行数：超出隐藏 + 展开/收起尾格（写回 collapsed 并派发 oas-collapse） | `string` | `1` |
| `cols` | 总列数 | `string` | `24` |
| `column-gap` | 列间距独立设置（同上） | `string` | — |
| `columns` | 自动等分列数（simple-grid，有值时忽略子项 span）：支持断点简写（如 3 md:2 sm:1，断点 sm=640/md=768/lg=1024/xl=1280）；与 min-child-width 并存时优先 | `string` | — |
| `gap` | 间距；单值两轴同值，两值空格分隔「行 列」（如 `8 16` 行 8 列 16）；三值以上非法静默回落 `0` | `string` | `0` |
| `justify` | 行内轴对齐（justify-items）：`start` / `center` / `end` / `stretch`；非法值回落 `stretch` + dev 告警（同值去重） | `string` | — |
| `min-child-width` | 子项最小宽度（如 180px，纯数字按 px）：auto-fit + minmax 依容器宽度自动计算列数（子项免断点流式重排）；与 columns 并存时 columns 优先，该模式下子项 span/offset 不生效 | `string` | — |
| `row-gap` | 行间距独立设置（覆盖 gap 对应轴，纯数字按 px） | `string` | — |

#### 事件

| 事件 | 说明 |
| --- | --- |
| `oas-collapse` | 折叠行尾格切换时派发，`detail: { collapsed }` |

#### 插槽

| 名称 | 说明 |
| --- | --- |
| 默认 | 栅格子项（`oas-grid-item`） |

#### CSS 变量

| CSS 变量 | 默认值 |
| --- | --- |
| `--oas-grid-columns` | `repeat(${base ?? 1}, 1fr)` |

### oas-grid-item

#### 属性

| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| `flex` | 内联直写 CSS flex 简写（grid 下不参与布局，flex 容器场景透传） | `string` | — |
| `offset` | 左侧偏移列数；支持断点简写（如 `0 lg:4`：基础值 + 空格分隔 `断点:值`，断点 sm=640 / md=768 / lg=1024 / xl=1280） | `string` | `0` |
| `order` | 排序权重（数字，默认 0）；数值越大越靠后，用于列重排（偏移重排场景的等价表达） | `string` | `0` |
| `pull` | 起始线左移 N 列（同上） | `string` | `0` |
| `push` | 起始线右移 N 列（净偏移 push−pull 叠加 offset） | `string` | `0` |
| `span` | 跨列数；支持 `auto`（内容自然宽）与断点简写（如 `24 md:12`：基础值 + 空格分隔 `断点:值`，断点 sm=640 / md=768 / lg=1024 / xl=1280） | `string` | `24` |

#### 插槽

| 名称 | 说明 |
| --- | --- |
| 默认 | 栅格单元内容 |

#### CSS 变量

| CSS 变量 | 默认值 |
| --- | --- |
| `--oas-grid-item-column` | `${baseColumn}` |

`oas-grid` 渲染为 CSS Grid，子项为 24 份中的一份；`oas-grid-item` 通过 `span` 声明占位。设置 `columns` 后自动等分、忽略 span，普通元素子项也可直接放入。
