Skip to content

SchemaRenderer 的 hidden / hiddenOn 是 #3862 的反极性孪生:hidden: '' / null / 空 source 信封在通用渲染路径上让节点永久消失 #3955

Description

@yinlianghui

Blocked-by: #3850

来源

发现自 #3850 + #3862 的结对实施(PR 分支 claude/issue-3850-3862-empty-predicate-gate)。给 SchemaRenderer 的 disabled 链写「visible 家族等价钉」时,顺手把同一个 useMemo 里 可见性链的另一极性 也量了一遍,发现 hidden / hiddenOn 两条腿有与 #3862 完全同构的缺陷,而且后果比置灰更重:节点整个消失。

不在 #3850 / #3862 的修法面:那两单裁决的落点是「已声明门」定义的下沉 + disabled / disabledOn 两条腿改读,visible 家族一侧被明确裁为保持 !== undefined 不动(它的 true 被取反,与「没有门」同结果,且改动会改变别名优先级)。hidden 腿的 true 不被取反,所以同一个「空谓词 → evaluateCondition 答 true」在这里意味着 HIDE。故独立成单,未认领。

机理

packages/react/src/SchemaRenderer.tsx(origin/main @ 65bb513dc073deb4e72950c287eef32cb56bf8ce),shouldHide 块(287 行起)的最后两条腿:

if (newSchema.hidden !== undefined) {
  return evaluator.evaluateCondition(newSchema.hidden);   // 308-310:不取反
}
if (newSchema.hiddenOn !== undefined) {
  return evaluator.evaluateCondition(newSchema.hiddenOn); // 311-313:不取反
}

ExpressionEvaluator.evaluateCondition 对「没有条件」的唯一默认是 return true(意为 visible/enabled)。前四条腿(visible / visibleWhen / visibleOn / visibility)都写成 !evaluateCondition(...),那个 true 取反后落在「不隐藏」,与「没有门」同结果 —— 良性。hidden / hiddenOn 直接返回,于是 true = 隐藏:空谓词让节点消失,与 #3862 在 disabled 上的 true = 置灰是同一个不对称的第二个出口。

拼法同样是最宽的那一格 !== undefined,所以 hidden: null 也命中(null !== undefined 为真)。

实测(worktree @ 65bb513dc,一次性探针,未提交)

同一个 probe 组件,只换 key,rendered / HIDDEN 是节点是否出现在 DOM:

value                        | visible  | visibleWhen | visibleOn | visibility | hidden   | hiddenOn
''                           | rendered | rendered    | rendered  | rendered   | HIDDEN   | HIDDEN
'   '(纯空白)               | rendered | rendered    | rendered  | rendered   | HIDDEN   | HIDDEN
{dialect:'cel',source:''}    | rendered | rendered    | rendered  | rendered   | HIDDEN   | HIDDEN
null                         | rendered | rendered    | rendered  | rendered   | HIDDEN   | HIDDEN
false                        | HIDDEN   | HIDDEN      | HIDDEN    | HIDDEN     | rendered | rendered
true                         | rendered | rendered    | rendered  | rendered   | HIDDEN   | HIDDEN

false / true 两行都正确(声明了 verdict 就按 verdict 走),坏的正是四行「空」。

为什么值得管

修法(机械,已有唯一定义可读)

#3850 的裁决已经把「已声明门」下沉为 @object-ui/core 的 hasDeclaredPredicate(packages/core/src/evaluator/declaredPredicate.ts,该 PR 落地),disabled / disabledOn 两条腿已改读它。这里同样改读即可:

if (hasDeclaredPredicate(newSchema.hidden)) { ... }
if (hasDeclaredPredicate(newSchema.hiddenOn)) { ... }

⛔ 不要就地补 && !== '' —— 那是把第 N 种「空」拼法写进第 N 个消费者,#3842 / #3849 / #3850 三单合掉的正是这类分身。

需要注意的一处非等价:hidden 腿改读后,hidden: '' 会继续往下落到 hiddenOn(而不是在空谓词上短路),这与 disabled 链在 #3862 修后的行为一致,但它改变了别名优先级,应作为行为变更钉住而不是当作等价。另外前四条 visible 腿是否也统一改读,是一个独立的判断:那侧空谓词良性,改读会改变别名优先级(如 visible: '' + hidden: 'true' 的组合),收益是「一个概念一处定义」,代价是行为变更 —— 建议与本单一起裁,而不是在本单里顺手改。

Related: #3862(同一文件、同一 useMemo、disabled 极性的同族半边)、#3850(「已声明门」范围裁决与定义下沉)、#3842 / #3849 / #3848(动作面与执行入口的同族)、#3492(不变量出处)。未认领。


Generated by Claude Code

Activity

  1. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    Contributor

    Triage: pm:blocked, Blocked-by: #3850 added to the body (defect-class card; queue on unlock).

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. yinlianghui commented on Aug 9, 2026

    @yinlianghui
    CollaboratorAuthor

    PM 分诊(session_01GTRjn8xBqp75dk7kFupVRt):晋级 pm:queue,方向代裁 —— hidden/hiddenOn 按 #3850 既定语义收敛:空谓词(''/null/纯空白/空信封)= 没有门 = 不隐藏,改读下沉后的 hasDeclaredPredicate,⛔ 不新增本地拼法。这是 #3862 反极性孪生在同一裁决线上的机械延伸,无需维护者另裁。

    排程:与 #3960、#3957 三单结对一 PR(文件面互相重叠:declaredPredicate.ts/SchemaRenderer.tsx/core/actions,分开派必然三轮串行),Blocked-by PR #3966(同文件面,其 documented-divergence 钉需要同步更新)—— PR3966 合入后即派。


    Generated by Claude Code

  3. self-assigned this
    on Aug 9, 2026
  4. yinlianghui commented on Aug 9, 2026

    @yinlianghui
    CollaboratorAuthor

    🔒 认领(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt,批次 4)—— 与 #3957、#3960 三单结对一 PR(分诊评论既定,前置 PR #3966 已 MERGED @ main ab3ad4f3f)。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions