Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/contextual-loading-spacing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inkcre/ui-web": minor
---

新增 InkLoading 行内 spinner、可见 label 与 InkSkeleton,等待图形响应减少动态效果偏好。Dialog 保留提交期间交互锁,只有执行动作显示 loading;自定义 footer 通过槽状态显式绑定。五个 spacing Token 改为 rem,Figma 导入拒绝单位回退,并同步组件示例与消费者迁移说明。
5 changes: 5 additions & 0 deletions .changeset/dropdown-search-affordance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@inkcre/ui-web": patch
---

为 Dropdown 搜索区增加内边距、前缀搜索图标和键盘焦点反馈,使空搜索框的用途可辨认。
12 changes: 12 additions & 0 deletions docs/design/composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

整理内容先于调整间距。重复的标题、复述同一状态的标签、没有帮助的说明和纯粹填空的图标应直接移除;需要保留的内容,再按当前任务决定出现的位置与时机。已有空间不要求被填满。

默认契约本就应成立的承诺,无须再放入帮助入口。确有按需阅读价值的短说明优先使用原生展开区,并给入口明确名称;影响当前选择的限制、可操作错误和不可逆后果仍紧邻操作呈现。短提示不能成为触屏或键盘用户获取必要信息的唯一途径。

列表帮助识别和比较对象,详情承载进一步阅读,编辑态提供修改所需的信息。不要把三个层级的全部内容同时摆在列表里。有用但暂时次要的信息可放到展开区、详情或次级操作入口中,入口应可发现,并让人知道能在那里找到什么。若用户必须反复展开才能完成主要任务,就需要重新考虑哪些内容应直接出现。

界面随状态改变当前呈现的内容:保存期间保留输入与进度,失败后及时显示对应问题和恢复动作,无须同时陈列所有可能状态。影响当前判断的警告、校验错误和操作后果直接呈现;不能为了视觉简洁藏到容易错过的入口。
Expand All @@ -34,6 +36,8 @@

主要提交应能被辨认为这次修改的完成动作,取消和危险操作与其保持可理解的区别。校验失败应说明需要修改什么;保存失败应保留已经输入的内容,让重试有连续的上下文。保存期间保留动作文字与可读配色,并防止重复执行。

禁用表示当前不能操作,等待图标表示该动作正在执行,两者不能混用。保存期间仅保存按钮显示 loading;无法中止请求时取消按钮可禁用,但不显示执行动画。提交、导入和刷新等动作各自拥有等待状态,结束或失败后恢复相应操作。

固定业务流程与 schema 生成表单承担不同的数据责任。先决定用户如何理解和修改内容,再选择实现;具体组合从 Web 的 InkForm、内置字段、InkField 以及现有配方进入。

## 浮层延续当前任务
Expand All @@ -44,6 +48,14 @@

加载、空结果、失败与确认有不同含义,应分别表达。错误反馈不要抹掉键盘焦点,进行状态也不应伪装成普通不可用状态。

## 按内容结构表达等待

已知列表、标题或属性行的结构时,使用少量骨架块保留阅读位置;结构未知的图谱、内容预览和独立内容区域使用三方块等待。字段选项读取、日志追加等紧凑状态使用行内 spinner 与必要的短说明。骨架不制造假的可点击按钮,宿主负责组合结构和外部留白。

刷新已有内容时保留内容和展开状态,在刷新动作或区域附近表达等待;失败后也保留已有内容,附上错误和重试。首次读取完成后才能判断空结果,失败不能继续显示加载。日志轮询间隔仅呈现静态更新说明,请求实际进行时才播放动画。

每个等待区域只有一次可访问状态播报,骨架与装饰图形不分别播报,不移动焦点。减少动态效果偏好下停止动画,保留状态文字和静态图形。只有真实可测的进度才显示百分比,不为等待增加全页遮罩或虚构进度。

## 容器变化时保留关系

宿主决定页面列数、外部留白和阅读区域,组件负责内部内容与操作布局。确定当前需要呈现的内容后,可用空间缩小时让相关内容换行或按既有阅读顺序排列;不要通过缩小正文、遮掉必要操作或裁切说明来维持双栏外观。
Expand Down
8 changes: 8 additions & 0 deletions packages/web/MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 未发布:场景化加载、Dialog 动作与相对间距

InkLoading 默认仍为三个方块,用于内容区、图谱和预览等待。新增 `variant="spinner"` 与可见 `label`;没有可见标签时继续支持 aria-label。新增 InkSkeleton 单块骨架,用 class/style 定义具体宽高,整个区域由宿主提供一次加载说明。Loading、Skeleton 与 Button 等待图形响应 prefers-reduced-motion。

InkDialog 的 pending 继续锁住内部 InkButton、确认、取消、Escape 和遮罩,但不再让所有按钮显示执行动画。默认 Confirm 显式显示 loading,Cancel 只禁用。自定义 footer 将 `:is-loading` 传给正在执行的按钮;默认槽和 footer 槽均提供 cancel、confirm、isLoading。直接依赖内部字符串 `isLoading` 注入的代码应移除,改用公开 prop/slot。验证保存、失败恢复和 Promise 拒绝后重试,不能把取消显示为正在提交。

五个 ref.space 源值改为 rem:xs/sm/md/lg/xl 为 0.25/0.5/1/2/3.5rem。Token 路径、sys 引用与 Sass/Uno 用法不变,16px 根字号下等大,20px 时间距按比例放大;复核表单、按钮、Dropdown、Tabs、Dialog、Header 的换行。radius 和 ref.size 不变。Figma 的 dimension 提议须保留已有单位,单位变更改为显式仓库迁移。

# 未发布:默认配色与阴影

浅深主题的主动作、普通表面与 Switch 采用中性灰配对;危险按钮底色保持灰红,需要注意的反馈文字使用较纯的语义色。覆盖层阴影缩小偏移与模糊范围。公开角色、组件 API 与调用方式保持不变,升级后重新构建即可获得默认值。
Expand Down
5 changes: 5 additions & 0 deletions packages/web/component-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@
"source": "inkScrim",
"category": "overlays"
},
{
"name": "InkSkeleton",
"source": "inkSkeleton",
"category": "feedback"
},
{
"name": "InkSwitch",
"source": "inkSwitch",
Expand Down
12 changes: 12 additions & 0 deletions packages/web/docs/design/composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

整理内容先于调整间距。重复的标题、复述同一状态的标签、没有帮助的说明和纯粹填空的图标应直接移除;需要保留的内容,再按当前任务决定出现的位置与时机。已有空间不要求被填满。

默认契约本就应成立的承诺,无须再放入帮助入口。确有按需阅读价值的短说明优先使用原生展开区,并给入口明确名称;影响当前选择的限制、可操作错误和不可逆后果仍紧邻操作呈现。短提示不能成为触屏或键盘用户获取必要信息的唯一途径。

列表帮助识别和比较对象,详情承载进一步阅读,编辑态提供修改所需的信息。不要把三个层级的全部内容同时摆在列表里。有用但暂时次要的信息可放到展开区、详情或次级操作入口中,入口应可发现,并让人知道能在那里找到什么。若用户必须反复展开才能完成主要任务,就需要重新考虑哪些内容应直接出现。

界面随状态改变当前呈现的内容:保存期间保留输入与进度,失败后及时显示对应问题和恢复动作,无须同时陈列所有可能状态。影响当前判断的警告、校验错误和操作后果直接呈现;不能为了视觉简洁藏到容易错过的入口。
Expand All @@ -34,6 +36,8 @@

主要提交应能被辨认为这次修改的完成动作,取消和危险操作与其保持可理解的区别。校验失败应说明需要修改什么;保存失败应保留已经输入的内容,让重试有连续的上下文。保存期间保留动作文字与可读配色,并防止重复执行。

禁用表示当前不能操作,等待图标表示该动作正在执行,两者不能混用。保存期间仅保存按钮显示 loading;无法中止请求时取消按钮可禁用,但不显示执行动画。提交、导入和刷新等动作各自拥有等待状态,结束或失败后恢复相应操作。

固定业务流程与 schema 生成表单承担不同的数据责任。先决定用户如何理解和修改内容,再选择实现;具体组合从 Web 的 InkForm、内置字段、InkField 以及现有配方进入。

## 浮层延续当前任务
Expand All @@ -44,6 +48,14 @@

加载、空结果、失败与确认有不同含义,应分别表达。错误反馈不要抹掉键盘焦点,进行状态也不应伪装成普通不可用状态。

## 按内容结构表达等待

已知列表、标题或属性行的结构时,使用少量骨架块保留阅读位置;结构未知的图谱、内容预览和独立内容区域使用三方块等待。字段选项读取、日志追加等紧凑状态使用行内 spinner 与必要的短说明。骨架不制造假的可点击按钮,宿主负责组合结构和外部留白。

刷新已有内容时保留内容和展开状态,在刷新动作或区域附近表达等待;失败后也保留已有内容,附上错误和重试。首次读取完成后才能判断空结果,失败不能继续显示加载。日志轮询间隔仅呈现静态更新说明,请求实际进行时才播放动画。

每个等待区域只有一次可访问状态播报,骨架与装饰图形不分别播报,不移动焦点。减少动态效果偏好下停止动画,保留状态文字和静态图形。只有真实可测的进度才显示百分比,不为等待增加全页遮罩或虚构进度。

## 容器变化时保留关系

宿主决定页面列数、外部留白和阅读区域,组件负责内部内容与操作布局。确定当前需要呈现的内容后,可用空间缩小时让相关内容换行或按既有阅读顺序排列;不要通过缩小正文、遮掉必要操作或裁切说明来维持双栏外观。
Expand Down
25 changes: 18 additions & 7 deletions packages/web/skill.seed.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"JSON configuration editing": "InkJsonEditor",
"Destructive confirmation": "InkDoubleCheck 提供确认弹层;InkDialog 支持异步等待和较复杂决策",
"Custom or positioned overlay": "InkPopup; add InkScrim only when the composition does not already own one",
"Loading state": "InkLoading",
"Loading state": "InkLoading;已知结构首次读取使用 InkSkeleton",
"Empty or error state": "InkPlaceholder",
"Expandable media": "InkImage",
"Paged collection": "InkPagination"
Expand Down Expand Up @@ -73,7 +73,7 @@
"composeWith": ["InkDialog", "InkDoubleCheck", "InkHeader", "InkTooltip"],
"apiCaveats": [
"type 控制 default/square 外形;nativeType 控制 button/submit/reset,默认 button。提交必须使用 nativeType=\"submit\"。",
"click 传出 MouseEvent;disabled、isLoading 或 Dialog 的 pending 禁用动作。图标按钮必须提供 aria-label。",
"click 传出 MouseEvent;disabled、isLoading 或 Dialog 的 pending 禁用动作,仅自身 isLoading 显示等待动画。图标按钮必须提供 aria-label。",
"默认 theme=\"subtle\";主动作显式 primary。文字可换行,最小高度 md=36px、sm=24px;pending 保留标签与相邻 spinner,不使用遮盖标签的覆盖层。"
],
"commonMistakes": [
Expand Down Expand Up @@ -113,7 +113,7 @@
"apiCaveats": [
"modelValue 为 boolean 或 Promise<boolean>;也支持布尔模型配合 isLoading。只应用最新 Promise,拒绝发出 error。",
"pending 阻止确认、取消、遮罩和 Escape;confirm 只发事件,取消发出 cancel 和 update:modelValue(false)。",
"title 提供名称;自定义 header 或无 title 时提供 aria-label/aria-labelledby。默认槽获得 cancel/confirm/isLoading。"
"title 提供名称;自定义 header 或无 title 时提供 aria-label/aria-labelledby。默认槽与 footer 槽获得 cancel/confirm/isLoading;自定义执行按钮显式绑定 isLoading,取消只禁用。"
],
"commonMistakes": [
"Do not nest a second independently controlled scrim beneath the dialog.",
Expand Down Expand Up @@ -292,16 +292,27 @@
],
"avoidWhen": [
"Content is empty or failed; use InkPlaceholder.",
"A static skeleton layout is required."
"A known content structure needs placeholders; use InkSkeleton."
],
"composeWith": ["InkButton", "InkDialog", "InkImage"],
"apiCaveats": [
"提供 role=status 和默认 Loading 名称,可透传 aria-label;不管理请求和相邻按钮状态。"
"默认 blocks 用于内容区/预览,spinner 用于紧凑行内等待;size/density 沿用。label 同时作为可见说明及 status 的 aria-label,重复文字节点 aria-hidden;无 label 时透传 aria-label,默认 Loading。只提供一次 role=status;不管理请求和相邻按钮状态。",
"减少动态效果偏好下停止动画,保留图形与说明;已有内容刷新保留内容,失败后提供局部重试。"
],
"commonMistakes": [
"Do not leave a loading indicator active after the operation reaches an empty or error state."
]
},
"InkSkeleton": {
"intent": ["skeleton", "known content placeholder", "initial loading"],
"preferWhen": ["首次读取的列表、标题或属性行已有明确结构。"],
"avoidWhen": ["结构未知的预览使用 InkLoading blocks;已有内容刷新保留内容。"],
"composeWith": ["InkLoading", "InkButton"],
"apiCaveats": [
"单块默认宽 100%、高 1em,通过 class/style 组合尺寸;aria-hidden,宿主只为整个区域提供一次状态说明。响应浅深主题及 prefers-reduced-motion。"
],
"commonMistakes": ["不要画假的可点击操作,不要在错误或空态保留骨架。"]
},
"InkPagination": {
"intent": ["pagination", "previous and next navigation", "paged collection"],
"preferWhen": [
Expand Down Expand Up @@ -548,9 +559,9 @@
{
"name": "Collection Feedback",
"intent": "Represent pending, empty, error, and paged collection states without conflating them.",
"components": ["InkLoading", "InkPlaceholder", "InkPagination", "InkButton"],
"components": ["InkLoading", "InkSkeleton", "InkPlaceholder", "InkPagination", "InkButton"],
"steps": [
"Show InkLoading only while a request is pending.",
"只在请求期间显示等待。已知结构首次加载用 InkSkeleton,内容预览用 InkLoading 默认 blocks,紧凑状态用 spinner。已有内容刷新及失败保留内容。",
"After completion, choose a specific empty, filtered-empty, permission, or error InkPlaceholder.",
"Render InkPagination only when a valid bounded page model exists.",
"Offer a retry or recovery InkButton only when the action is available."
Expand Down
2 changes: 1 addition & 1 deletion packages/web/skills/ui-web/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ matches a product task.
- JSON configuration editing: InkJsonEditor
- Destructive confirmation: InkDoubleCheck 提供确认弹层;InkDialog 支持异步等待和较复杂决策
- Custom or positioned overlay: InkPopup; add InkScrim only when the composition does not already own one
- Loading state: InkLoading
- Loading state: InkLoading;已知结构首次读取使用 InkSkeleton
- Empty or error state: InkPlaceholder
- Expandable media: InkImage
- Paged collection: InkPagination
Expand Down
4 changes: 4 additions & 0 deletions packages/web/skills/ui-web/references/common-mistakes.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@
- Do not render an orphan scrim without an overlay lifecycle.
- Do not rely on visual dimming alone for modal accessibility.

## InkSkeleton

- 不要画假的可点击操作,不要在错误或空态保留骨架。

## InkSwitch

- Do not optimistically show a successful state when the async change can still fail.
Expand Down
1 change: 1 addition & 0 deletions packages/web/skills/ui-web/references/component-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ component references relevant to the task.
- [InkLoading](components/InkLoading.md): loading indicator; async progress feedback; pending state
- [InkPlaceholder](components/InkPlaceholder.md): empty state; error state; unavailable content guidance
- [InkPopup](components/InkPopup.md): positioned popup; low-level overlay surface; custom controlled overlay
- [InkSkeleton](components/InkSkeleton.md): skeleton; known content placeholder; initial loading
- [InkTooltip](components/InkTooltip.md): contextual hint; hover explanation; supplementary label

## forms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
## API Caveats

- type 控制 default/square 外形;nativeType 控制 button/submit/reset,默认 button。提交必须使用 nativeType="submit"。
- click 传出 MouseEvent;disabled、isLoading 或 Dialog 的 pending 禁用动作。图标按钮必须提供 aria-label。
- click 传出 MouseEvent;disabled、isLoading 或 Dialog 的 pending 禁用动作,仅自身 isLoading 显示等待动画。图标按钮必须提供 aria-label。
- 默认 theme="subtle";主动作显式 primary。文字可换行,最小高度 md=36px、sm=24px;pending 保留标签与相邻 spinner,不使用遮盖标签的覆盖层。

## Common Mistakes
Expand Down
6 changes: 3 additions & 3 deletions packages/web/skills/ui-web/references/components/InkDialog.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,17 @@

- `header`: `{}`
- `default`: `{ cancel: () => void; confirm: () => void; isLoading: boolean; }`
- `footer`: `{}`
- `footer`: `{ cancel: () => void; confirm: () => void; isLoading: boolean; }`

- Public types: None
- Story variants: `Basic`, `with Custom Slots`, `Async`, `Without Cancel`
- Story variants: `Basic`, `Custom footer failure and retry`, `Async`, `Without Cancel`


## API Caveats

- modelValue 为 boolean 或 Promise<boolean>;也支持布尔模型配合 isLoading。只应用最新 Promise,拒绝发出 error。
- pending 阻止确认、取消、遮罩和 Escape;confirm 只发事件,取消发出 cancel 和 update:modelValue(false)。
- title 提供名称;自定义 header 或无 title 时提供 aria-label/aria-labelledby。默认槽获得 cancel/confirm/isLoading。
- title 提供名称;自定义 header 或无 title 时提供 aria-label/aria-labelledby。默认槽与 footer 槽获得 cancel/confirm/isLoading;自定义执行按钮显式绑定 isLoading,取消只禁用。

## Common Mistakes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
## Avoid When

- Content is empty or failed; use InkPlaceholder.
- A static skeleton layout is required.
- A known content structure needs placeholders; use InkSkeleton.

## Compose With

Expand All @@ -36,6 +36,8 @@

| 名称 | 类型 | 必需 | 默认表达式 |
| --- | --- | --- | --- |
| `variant` | `undefined \| "blocks" \| "spinner"` | 否 | `"blocks"` |
| `label` | `undefined \| string` | 否 | `""` |
| `size` | `undefined \| "md" \| "sm" \| "xs"` | 否 | `"md"` |
| `density` | `undefined \| "md" \| "sm"` | 否 | `"md"` |

Expand All @@ -48,12 +50,13 @@
- None.

- Public types: None
- Story variants: `Basic`
- Story variants: `Content waiting`, `Inline spinner`, `Sizes and density`


## API Caveats

- 提供 role=status 和默认 Loading 名称,可透传 aria-label;不管理请求和相邻按钮状态。
- 默认 blocks 用于内容区/预览,spinner 用于紧凑行内等待;size/density 沿用。label 同时作为可见说明及 status 的 aria-label,重复文字节点 aria-hidden;无 label 时透传 aria-label,默认 Loading。只提供一次 role=status;不管理请求和相邻按钮状态。
- 减少动态效果偏好下停止动画,保留图形与说明;已有内容刷新保留内容,失败后提供局部重试。

## Common Mistakes

Expand Down
Loading
Loading