Odyssey UI v1.0.0

Components

Forms

采集用户输入的整套控件:语义化的 .ody-field 包裹层,配合原生 input / select / textarea 的轻量皮肤。所有控件的强调色、焦点环与状态色都走 --ody-* token,亮暗主题自动对齐;点右上角图标可即时预览暗色。

表单控件是渐进增强的原生元素 —— 不需要 odyssey.js 即可工作。焦点环由 :focus-visible 触发(4px --ody-ring),校验态用 .is-invalid / aria-invalid 或字段级 .has-error 表达。

Field · 字段容器

.ody-field 把标签、控件、提示、错误竖直组织成一组。.ody-label 为标签;.ody-hint 为辅助说明;.ody-error 为错误文案。必填标记有两种写法:字段级 .ody-field--required 或标签级 .ody-label--required,都会在标签后追加红色 *。校验失败时给字段加 .has-error(标签变红)并给控件加 .is-invalid(描边变红)。

我们不会公开你的邮箱地址。
密码至少需要 8 位字符。
<!-- 带提示 -->
<div class="ody-field">
  <label class="ody-label">邮箱</label>
  <input class="ody-input" type="email" placeholder="you@example.com">
  <span class="ody-hint">我们不会公开你的邮箱地址。</span>
</div>

<!-- 必填(字段级标记) -->
<div class="ody-field ody-field--required">
  <label class="ody-label">用户名</label>
  <input class="ody-input" type="text" placeholder="必填">
</div>

<!-- 校验失败 -->
<div class="ody-field has-error">
  <label class="ody-label">密码</label>
  <input class="ody-input is-invalid" type="password" value="123" aria-invalid="true">
  <span class="ody-error">密码至少需要 8 位字符。</span>
</div>

Input · 文本输入

.ody-input 适配 text / number / password / search 等原生类型。尺寸用 --sm / --lg;禁用用原生 disabled;校验失败用 .is-invalid(或 aria-invalid="true")。

类型

<input class="ody-input" type="text" placeholder="文本 · text">
<input class="ody-input" type="number" value="42">
<input class="ody-input" type="password" value="secret">
<input class="ody-input" type="search" placeholder="搜索 · search">

尺寸

<input class="ody-input ody-input--sm" placeholder="Small · --sm">
<input class="ody-input" placeholder="Default">
<input class="ody-input ody-input--lg" placeholder="Large · --lg">

状态

<input class="ody-input" placeholder="禁用 · disabled" disabled>
<input class="ody-input is-invalid" value="非法输入" aria-invalid="true">

Textarea · 多行文本

.ody-textarea.ody-input 同源,默认最小高度 96px、可竖直拉伸;同样支持 disabled.is-invalid

<textarea class="ody-textarea" placeholder="写点什么…"></textarea>
<textarea class="ody-textarea is-invalid" aria-invalid="true">内容过短</textarea>
<textarea class="ody-textarea" placeholder="禁用" disabled></textarea>

Select · 下拉选择

.ody-select 抹掉原生箭头,用内联 SVG 重绘统一的下拉指示符(data-URI,无外链)。支持 disabled.is-invalid

<select class="ody-select">
  <option value="">选择区域…</option>
  <option>华北 · Beijing</option>
  <option>华东 · Shanghai</option>
  <option>华南 · Shenzhen</option>
</select>

<select class="ody-select is-invalid" aria-invalid="true">…</select>
<select class="ody-select" disabled>…</select>

Checkbox · 复选框

.ody-checkbox 包裹原生 <input type="checkbox">,用 accent-color 上强调色、并附带 :focus-visible 焦点环。禁用时给包裹层加 .is-disabled 并给 input 加 disabled

<label class="ody-checkbox"><input type="checkbox" checked> 记住我</label>
<label class="ody-checkbox"><input type="checkbox"> 订阅产品更新</label>
<label class="ody-checkbox is-disabled"><input type="checkbox" disabled> 已锁定选项</label>

Radio · 单选框

.ody-radio 与复选框同构,用同一 name 分组即互斥。禁用同样用 .is-disabled + disabled

<label class="ody-radio"><input type="radio" name="plan" checked> 月付</label>
<label class="ody-radio"><input type="radio" name="plan"> 年付</label>
<label class="ody-radio is-disabled"><input type="radio" name="plan" disabled> 企业版(暂不可选)</label>

Switch · 开关

开关是一个 .ody-switch 标签,内含 .ody-switch__control(包住原生 checkbox 与 .ody-switch__track 轨道)与可选的文字。勾选时轨道染上强调色、滑块右移;禁用给 input 加 disabled

<label class="ody-switch">
  <span class="ody-switch__control">
    <input type="checkbox" checked>
    <span class="ody-switch__track"></span>
  </span>
  <span>启用桌面通知</span>
</label>

<!-- 禁用:给 input 加 disabled -->
<label class="ody-switch">
  <span class="ody-switch__control">
    <input type="checkbox" checked disabled>
    <span class="ody-switch__track"></span>
  </span>
  <span>强制开启(禁用)</span>
</label>

Range · 滑块(带徽章)

.ody-range 是皮肤化的原生 type="range"。用 .ody-field__row 把滑块与 .ody-field__out 数值徽章横排;徽章的实时数值用一小段内联 oninput 同步(纯原生,无需 odyssey.js)。

60
8
<div class="ody-field">
  <label class="ody-label">音量</label>
  <div class="ody-field__row">
    <input class="ody-range" type="range" min="0" max="100" value="60"
           oninput="this.parentNode.querySelector('.ody-field__out').textContent=this.value">
    <span class="ody-field__out">60</span>
  </div>
</div>

Input group · 输入组(前后缀)

.ody-input-group.ody-input 与一或两个 .ody-input-group__addon 拼成一体:首个 addon 为前缀、末尾 addon 为后缀,圆角与描边自动接缝。加 --icon 修饰并把 <svg> 作为首个子元素,可在框内嵌一个前置图标。

https:// .w33d.xyz
¥
<!-- 前缀 + 后缀 -->
<div class="ody-input-group">
  <span class="ody-input-group__addon">https://</span>
  <input class="ody-input" placeholder="your-site">
  <span class="ody-input-group__addon">.w33d.xyz</span>
</div>

<!-- 仅前缀 -->
<div class="ody-input-group">
  <span class="ody-input-group__addon">¥</span>
  <input class="ody-input" type="number" value="99">
</div>

<!-- 框内前置图标 -->
<div class="ody-input-group ody-input-group--icon">
  <svg viewBox="0 0 24 24" …><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
  <input class="ody-input" type="search" placeholder="搜索…">
</div>

File · 文件选择

.ody-file 皮肤化原生 type="file"::file-selector-button,让「选择文件」按钮与库内其它控件同风格。支持 multipledisabled

<input class="ody-file" type="file">
<input class="ody-file" type="file" multiple>
<input class="ody-file" type="file" disabled>

Form layouts · 表单布局

默认布局为堆叠式:字段用 .ody-field 竖直排列,操作区用 .ody-form__actions 归拢按钮。内联式.ody-form--inline:字段横向流式排列、底部对齐,适合筛选条与工具栏。

内联 · inline

<form class="ody-form--inline">
  <div class="ody-field">
    <label class="ody-label">关键词</label>
    <input class="ody-input" placeholder="搜索…">
  </div>
  <div class="ody-field">
    <label class="ody-label">状态</label>
    <select class="ody-select">
      <option>全部</option>
      <option>启用</option>
      <option>停用</option>
    </select>
  </div>
  <button class="ody-btn ody-btn--primary" type="submit">筛选</button>
</form>

堆叠 · stacked

可选,最多 140 字。
<form>
  <div class="ody-field ody-field--required">
    <label class="ody-label">项目名称</label>
    <input class="ody-input" placeholder="例如 holdfast-web">
  </div>
  <div class="ody-field">
    <label class="ody-label">描述</label>
    <textarea class="ody-textarea" placeholder="一句话说明…"></textarea>
    <span class="ody-hint">可选,最多 140 字。</span>
  </div>
  <label class="ody-switch">
    <span class="ody-switch__control">
      <input type="checkbox" checked>
      <span class="ody-switch__track"></span>
    </span>
    <span>创建后立即部署</span>
  </label>
  <div class="ody-form__actions">
    <button class="ody-btn ody-btn--primary" type="submit">创建项目</button>
    <button class="ody-btn ody-btn--subtle" type="button">取消</button>
  </div>
</form>