Skip to content

fix(fields): 接通 slider 的三条 a11y 通道、命名 signature、把 aria-invalid 账本拆成两个语义位 (#3318) - #4933

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-3318-ledger-remainder
Aug 17, 2026
Merged

fix(fields): 接通 slider 的三条 a11y 通道、命名 signature、把 aria-invalid 账本拆成两个语义位 (#3318)#4933
yinlianghui merged 2 commits into
mainfrom
claude/issue-3318-ledger-remainder

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Part of #3318

按 2026-08-17 的 PM 分流裁定处理账本残留 9 条。账本未清零grid 仍留一条,见下),所以正文用 Part of 而非关闭关键字。

一、先量后改:origin/main 上 9 条的实测读数

真表单 + 真 react-hook-form,每行一个 required 字段、null 值(presence 语义),提交后先自证 "is required" 已渲染再读 aria。text 是对照组。

type aria-invalid=true 可聚焦控件 可见 label 的 for description 消费者
formula 0 个 DANGLING 0
summary 0 个 DANGLING 0
auto_number 0 个 DANGLING 0
vector 0 个 DANGLING 0
signature 0 个 DANGLING 0
filter-condition 0 个 DANGLING 0
recipient-picker 0 个 DANGLING 0
grid 1 个 button DANGLING 0
slider 2 个 span[role=slider] + 隐藏 input DANGLING 0
text(对照) input 1 个 input 解析到 input 1

这张表就是分流线本身:「可聚焦控件 = 0」是「不适用」的事实依据,不是说法gridslider 各有控件,所以它们不在那条线上。

另外,9 行全部 ids=[] —— 不是 id 被覆写(#3952boolean 上的形态),而是整行 DOM 里没有任何元素带 id。这正是 08-09 / 08-16 三通道实测的结论:一处缺失同时掉了三样东西。

二、逐条处置

# type 处置 依据
1 slider 已交付,账本行删除→转正向守卫 三通道全接通,见下
2 signature 拆两半aria-invalid 判不适用;label 关联已交付 canvas 无键盘路径成立(实测 0 可聚焦);名字按 #3961 file 范式
3 formula 迁入 NOT_APPLICABLE 只读计算展示,0 可聚焦控件
4 summary 迁入 NOT_APPLICABLE 只读聚合展示,0 可聚焦控件
5 auto_number 迁入 NOT_APPLICABLE 只读系统生成展示,0 可聚焦控件
6 vector 迁入 NOT_APPLICABLE 只读 embedding 预览,0 可聚焦控件
7 filter-condition 迁入 NOT_APPLICABLE 门控态(未选 object_name)只有提示段落;可编辑态已交付
8 recipient-picker 迁入 NOT_APPLICABLE 门控态(未选 recipient_type)只有提示段落;可编辑态已交付
9 grid NOT_YET_DELIVERED,不修 表单级失败驱动 per-cell 需设计(哪个 cell?add-row 按钮?)

NOT_YET_DELIVERED 现在只剩 grid 一条。按裁定这不卡 issue 关闭决策,交 PM 定。

三、slider:为什么需要一次 components 级改动

aria-invalid 必须落在 role="slider" 的 thumb 上 —— 那才是键盘用户落点、辅助技术读状态的元素。Radix 的 Root 渲染一个无 role 的包裹 span 并吞掉所有它不认识的 prop,所以 host 下发的一切都落在辅助技术永不访问的包裹层上。

这与 #3306select 同形态但难一档:那里可聚焦控件是 SelectTrigger,primitive 导出了它,widget 能直接寻址;ui/slider.tsx 的 thumb 是内部渲染、只导出 Slider,widget 对那个唯一必须承载状态的元素没有任何把手

走仓库既有的声明式 sync patch 机制scripts/shadcn-local-patches.mjs)—— 这正是它存在的用途:「必须在 regeneration 后存活的 src/ui/** 编辑,以数据形式声明,由 sync 自己重放」。payload 依该文件自身的指引留在 src/ui/ 之外(packages/components/src/lib/slider-thumb.ts),ui/slider.tsx 只收四行有锚点的一行改。

四条 patch 里 root 那条不是记账:若只加 thumb 交付而不从 Root 的 spread 里摘掉 thumbProps,代码照样编译照样渲染 —— 对象会被 String()thumbprops="[object Object]" 贴到包裹 span(#3291 扫的那类泄漏),并且 host id 会同时落在两个元素上,getElementById 答出包裹层,于是 label 的 for 依旧指向不可聚焦的 span,bug 穿着自己的修复活下来。这条已在 scripts/__tests__/shadcn-local-patches.test.ts 里单独钉住并写明原因。

SliderField 的分流与 SelectField 逐键相同:name(Root 拥有参与提交的隐藏 input)和 disabled(Root 是唯一权威)留在 Root,其余走 thumb,aria-invalid={!!error} 写在 spread 之后。className 也扣住 —— primitive 把 thumbProps spread 在 thumb 自身 class 之后,透过去会把 thumb 的形状整个换掉。

四、三通道读数(修后)

slider 一处修改同时接通三通道,三面都钉在 slider-signature-host-channels-e2e.test.tsx

通道 修后 断言
aria-invalid 落在 span[role=slider] 上,整行恰好 1 个 断言的是角色而非「行内某元素」,将来若被挪回包裹层会红
可见 label label 丢掉 for、发 aria-labelledbygetByRole('slider', {name:/Confidence/}) 命中 thumb IDREF 解析且出来的名字就是可见的那个
aria-describedby FormDescription 的消费者 = 1,且就是 thumb 从「0 消费者」到 1

外加两条:host id 在 thumb 上且全行只有一个元素答应该 id;thumb 上没有 name / thumbprops 泄漏、且保留自身 rounded-full 形状。

label 通道为何单靠 spread 不够forresolve 不等于 label 能 工作label for 只能寻址 HTML 的 labelable 元素(button / input / meter / output / progress / select / textarea)。slider 的控件是 span[role=slider]、signature 的是 canvas,直接把 host id 给它们只是把「悬空的 for」升级成「无效的 for」。所以两者都声明 labelling: 'group'#3961 的路子,file 的形态:一个不可 label 的控件,而非复合体),改由 IDREF 命名。这条连带更新了 group-labelling-declaration.test.ts 的精确集合断言。

signature 则拿到名字与描述(role="group" 容器,instead-of-the-inputs),不拿控件态:Clear 按钮是作用于值的辅助按钮,不是值的控件 —— 与 geolocation 只读行里那个可聚焦的「View on map」链接同一读法。

五、棘轮结构:为什么「借改判逃账」结构上不可能

DELIVERING推导出来的:ALL_TYPES 减去两个账本。三个集合按构造划分注册表。三重防线:

  1. 删行不等于销账 —— 从两个账本里都删掉,该类型直接落入最严的正向 sweep。
  2. 每条 NOT_APPLICABLE 自带守卫 —— sweep 实测该 widget 的行确实不提供可聚焦控件。grid 无法被挪进来凑数(它渲染一个 button);将来谁给这些 widget 加了真控件而账本行没动,同一条守卫也红。
  3. 两账本断言互斥、且只能命名真实存在的类型;每条不适用行必须写出理由(空理由会红)。

六、反向验证(先书面预判,后跑;变异前已 commit,还原用 git checkout,未用 stash)

四次变异,预判与实测的一致/不一致都照实报

变异 预判 实测 一致
M1 撤掉 slider 的 spread(整文件还原) 6 红:sweep 的 field:slider 正向断言 + channels 的 5 条 恰好 6 红,一字不差
M2 把 formula 从两个账本都删掉 划分断言仍绿(该类型落入 DELIVERING,划分依然精确);红的是 field:formula 正向 sweep 正如预判:1 红,且红在正向 sweep
M3 给 formula 塞一个可聚焦控件(假阳测试) 不适用守卫红 绿 —— 预判错了
M3b 同上,改到 sweep 真正渲染的分支 不适用守卫红,报 [ 'span' ] 如预判
M4 把 gridNOT_YET_DELIVERED 挪进 NOT_APPLICABLE 不适用守卫红报 [ 'button' ];互斥/存在/划分三条仍绿 如预判

M1 的一个诚实例外leaks no renderer plumbing onto the thumb 那条在 M1 下保持绿色,而且这是预判里就写明的 —— 它整条都是「不存在」断言(not.toHaveAttribute('name') / 'thumbprops')加一个 className 检查,而改动前的 widget 什么都不转发,因此空洞地满足它。它守的是修复的回归,不是修复的缺席;在这里它两个方向都不构成证据,不当成证据用。

M3 为什么预判错,以及它教了什么:我把 tabIndex 加在 FormulaField有值分支上,而 sweep 渲染的是 value == nullEmptyValue 早返回 —— 变异落在一条这个 fixture 走不到的分支上,红不了是机械原因,不是守卫弱。M3b 改到真正渲染的分支即按预判变红。

这件事本身是条真事实,已写进账本的文档注释:不适用守卫读的是 sweep 渲染的那个状态(fresh / empty / required / 刚失败),而那恰好是该判的状态 —— required 是 presence 检查,属性需要被播报的时刻正是值缺失的时刻。四个只读类型在这里渲染的是空值分支、signature 的 Clear 按钮要画过才可聚焦,两者都已在注释里点名,是披露而非藏起来。

七、验证

  • pnpm exec vitest run packages/fields/103 files / 1709 tests passed
  • pnpm exec vitest run packages/components/ scripts/195 files / 2464 tests passed
  • 消费半径(被改的声明在别处也跑):plugin-form + plugin-detail + plugin-designer + plugin-grid209 / 1964 passedapp-shell414 / 3919 passed(1 skipped)
  • 仓根 pnpm exec turbo run type-check --concurrency=281/81 successful
  • node scripts/check-control-bytes.mjs → OK(4413 files);另对本 PR 触及文件做了越过该门的自查(grep -naP 控制字符类)→ clean

changeset:@object-ui/components + @object-ui/fields 各 patch(⛔ 无 major)。未触碰 content/docs/releases/**,未 force-push。

八、偏差一条

派发单钉的基线是 40d3a3318,实际从 origin/main69dbea20a)开分支。原因:派发后 main 又进了两个 commit,其中 e7747f19a#4814 retire owner alias,落地时间比分流评论晚 16 秒)改的正是本单目标账本文件 —— 它把 owner: UserFieldWIDGETS 里摘走换成一段注释。基于旧基线会让我在一个 main 已经走过的文件版本上重写账本。较新基线同样是钉死的 SHA。


Generated by Claude Code

…e aria-invalid ledger (#3318)

The registry sweep's NOT_YET_DELIVERED ledger held nine rows. Measured against
`origin/main` before touching anything — a real form, one required field per
row, freshly failed validation:

    formula           ariaInvalidTrue=[]  focusable=0  labelFor=DANGLING  desc=0
    summary           ariaInvalidTrue=[]  focusable=0  labelFor=DANGLING  desc=0
    auto_number       ariaInvalidTrue=[]  focusable=0  labelFor=DANGLING  desc=0
    vector            ariaInvalidTrue=[]  focusable=0  labelFor=DANGLING  desc=0
    signature         ariaInvalidTrue=[]  focusable=0  labelFor=DANGLING  desc=0
    filter-condition  ariaInvalidTrue=[]  focusable=0  labelFor=DANGLING  desc=0
    recipient-picker  ariaInvalidTrue=[]  focusable=0  labelFor=DANGLING  desc=0
    grid              ariaInvalidTrue=[]  focusable=1 [button]
    slider            ariaInvalidTrue=[]  focusable=2 [span[slider],input]
    text (control)    ariaInvalidTrue=[input]  focusable=1  labelFor -> input  desc=1

Three dispositions, and the measurement is what separates them.

DELIVERED — slider. Its focusable control is Radix's span[role="slider"] thumb,
rendered inside the synced `ui/slider.tsx` and not exported, so unlike #3306's
SelectTrigger a widget has no handle on it. The primitive grew a declared
`thumbProps`, routed by `lib/slider-thumb.ts` and applied to the no-touch file
through the repo's declared sync-patch registry so it survives regeneration.
The root half of that patch is load-bearing, not bookkeeping: without it the
object stringifies onto the wrapper and the host id lands on two elements at
once. `SliderField` then splits exactly as `SelectField` does — `name` and
`disabled` stay on Root, everything else goes to the thumb, `aria-invalid` after
the spread. One fix, three channels: state, name and description.

NOT APPLICABLE — a second ledger, for the seven rows whose widget renders no
focusable control at all. `aria-invalid` is control-channel state; a row with
nothing to focus has no element to carry it, and marking its text span is the
wrapper move this sweep exists to forbid. Each row states its ground and the
sweep MEASURES that ground, so a reclassification is falsifiable: `grid` cannot
be parked there to empty the first ledger, because it renders a button. Left in
NOT_YET_DELIVERED: `grid` alone, where driving a form-level failure into a
per-cell editor needs a design rather than a spread.

Signature's verdict is split, not blanket. The control state does not apply,
but the NAME always did: `<canvas>` is not a labelable element, so its host
label could only dangle. It and `slider` are now declared `labelling: 'group'`
— `file`'s shape, one unlabelable control, not a composite — and named by IDREF.

Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-DghHpLfD.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 38.46KB 10.17KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.02KB 0.88KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.79KB 111.24KB
core (index.js) 4.06KB 1.61KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 157.05KB 43.28KB
fields (index.js) 233.14KB 58.17KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 39.16KB 10.97KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 9.35KB 3.31KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 4.42KB 1.42KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.81KB 0.83KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.62KB 12.83KB
plugin-charts (index.js) 64.75KB 18.37KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 127.85KB 32.73KB
plugin-designer (index.js) 212.39KB 42.83KB
plugin-detail (index.js) 239.90KB 60.01KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 120.42KB 29.03KB
plugin-gantt (index.js) 164.10KB 39.87KB
plugin-grid (index.js) 197.58KB 53.00KB
plugin-kanban (index.js) 52.72KB 14.54KB
plugin-list (index.js) 111.23KB 26.97KB
plugin-map (index.js) 17.91KB 5.72KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.97KB 11.33KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 83.81KB 20.49KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 27.53KB 9.41KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.28KB 0.68KB
react (schema-input.js) 1.45KB 0.83KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.55KB 2.07KB
sdui-parser (parse.js) 10.76KB 3.17KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.05KB 1.52KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

The comment above the destructure opened on "withheld alongside them" with the
antecedent 200 lines up in the doc block, which reads as a dangling reference at
the one place a reader needs the split spelled out. Comment only.

Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 24.7 KB 350 KB
Entry file index-DghHpLfD.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 9.56KB 3.59KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 8.92KB 3.41KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 25.13KB 5.40KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 38.46KB 10.17KB
auth (createAuthenticatedFetch.js) 6.34KB 2.43KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.02KB 0.88KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.79KB 111.24KB
core (index.js) 4.06KB 1.61KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 157.05KB 43.28KB
fields (index.js) 233.14KB 58.17KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.35KB 1.38KB
i18n (pickLocalized.js) 3.69KB 1.73KB
i18n (provider.js) 23.12KB 7.62KB
i18n (useDisplayLocale.js) 2.84KB 1.45KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 7.77KB 3.13KB
layout (index.js) 39.16KB 10.97KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 9.35KB 3.31KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 4.42KB 1.42KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.81KB 0.83KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 46.62KB 12.83KB
plugin-charts (index.js) 64.75KB 18.37KB
plugin-chatbot (index.js) 181.21KB 43.14KB
plugin-dashboard (index.js) 127.85KB 32.73KB
plugin-designer (index.js) 212.39KB 42.83KB
plugin-detail (index.js) 239.90KB 60.01KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 120.42KB 29.03KB
plugin-gantt (index.js) 164.10KB 39.87KB
plugin-grid (index.js) 197.58KB 53.00KB
plugin-kanban (index.js) 52.72KB 14.54KB
plugin-list (index.js) 111.23KB 26.97KB
plugin-map (index.js) 17.91KB 5.72KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 41.97KB 11.33KB
plugin-timeline (index.js) 26.68KB 7.66KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 83.81KB 20.49KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 27.53KB 9.41KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.28KB 0.68KB
react (schema-input.js) 1.45KB 0.83KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.55KB 2.07KB
sdui-parser (parse.js) 10.76KB 3.17KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 3.05KB 1.52KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Collaborator Author

PM 验收:ACCEPT(Part of #3318,批次 18,PM 会话 session_01GTRjn8xBqp75dk7kFupVRt)

分流裁定执行(逐条对账):账本 9→1 —— slider 交付(三通道:aria-invalid 恰落 role=slider、label 经 aria-labelledby 解析出可访问名、描述消费者恰为 thumb;附 labelling:'group' 声明,因 span[role=slider] 不可 for-label);signature 按裁定拆半(aria-invalid 半经 focusable=0 实测确认不适用,label 半按 #3961 file 范式落 role=group);六项不适用每项带「确无可聚焦控件」的实测守卫(未来加了控件即红,防改判变逃账);grid 留守账本 —— PM 裁定:grid 的 per-cell 设计留在 #3318 残余范围内,不另立卡(另立即复制父单,dev 判断正确)。

账本结构:两个互斥、只收缩的集合,DELIVERING 由全集减法派生 —— 三集合按构造划分注册表,逃账结构上不可能(M2/M4 变异各自证实)。

实物核验(已过):11 文件 +922/−55 对账;标识 0;releases 0;ui/slider.tsx 的触碰经声明式 LOCAL_PATCHES 注册表(新增 registry + 专项钉)而非裸改 No-Touch 文件 —— 承重的 thumb-root-split 陷阱(不拆则 thumbProps 字符串化到 wrapper、host id 落两元素、缺陷穿着修复外衣存活)连同论证一并钉进 shadcn-local-patches.test.ts

反向验证(4+1 变异):M1 预判 6 红逐例命中(附一条「空缺断言空真」的诚实排除);M2 双删证防逃账;M3 预判红实测绿 —— dev 自查定位为变异放错分支(EmptyValue 早退路径不可达),以 M3b 在真渲染分支补证转红,教训写进账本文档 —— 预判失败的正确处置形态;M4 headline 反逃账证实。

有据偏离(全部接受):①基线自主改用 69dbea2 —— 派发后 16 秒 main 上 e7747f1 恰好改了目标账本文件,旧基线意味着在 main 已越过的版本上重写账本,判断正确且同为钉死 sha;②范围延伸 components+scripts —— 账本注释本身预诊断了需要组件级改动,且走了仓自己的声明机制;③amend 后为避免 force-push 改用 soft-reset + 快进提交 —— ⛔ 红线意识正确。

协作产出:#4857 上的修正评论(其 option 3 对 slider/signature 不充分 —— 悬空 for 会变成惰性 for,探针假绿)是跨卡质量贡献;两处「不立卡」的克制判断均正确。

CI(亲读终态):20 项全 completed,零失败。

→ undraft + auto-merge (SQUASH)。#3318 保持 open(余 grid 一行)。


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants