来源
发现自 #3849(PR #3861)实施时对第三种拼法的逐处核对。#3849 的正文把它列为「实施时请按落点逐一确认」的注意事项,但它不在 #3849 的文件面(#3849 只动五个渲染器落点),也不在 #3850 的修法面(见下「与 #3850 的关系」),故独立成单,未认领。
机理
「是否声明了 disabled 门」在仓里第三次被回答,这次的拼法是 !== undefined,范围比 != null 还要宽一格。
packages/react/src/SchemaRenderer.tsx:322-334(origin/main @ 993336f7c481e1fd724512363b8b2f15b305da86):
// Evaluate disabled: disabled / disabledOn
const isDisabled = (() => {
if (newSchema.disabled !== undefined) {
return evaluator.evaluateCondition(newSchema.disabled);
}
if (newSchema.disabledOn !== undefined) {
return evaluator.evaluateCondition(newSchema.disabledOn);
}
return false;
})();
if (isDisabled) {
newSchema._disabled = true;
}
ExpressionEvaluator.evaluateCondition(packages/core/src/evaluator/ExpressionEvaluator.ts:238-240)对空谓词的答复是「没有条件 → 可见/可用」:
// No condition → default to visible/enabled (undefined, null, '').
if (!condition) {
return true;
}
于是链条闭合:disabled: '' 通过 !== undefined 这一关 → evaluateCondition('') 返回 true → _disabled = true。方向不对称与 #3842 / #3849 完全相同 —— 同一个 true 在 visible 上意味着「显示」(该侧 visible !== undefined 因此良性,SchemaRenderer.tsx:287 的 !evaluateCondition('') = !true = 不隐藏),在 disabled 上意味着「禁用」。
比 != null 家族多亏一格:disabled: null 也会置灰(null !== undefined 为真 → evaluateCondition(null) 为 true)。!= null 的五处落点至少把 null 排在门外。
值不是死的:它会被转发成组件 prop
这一点是 #3849 正文没有建立的部分。_disabled 不是内部标记而已 —— SchemaRenderer.tsx:461 把它交给被渲染组件:
disabled: __disabled || undefined,
(同一处 SchemaRenderer.tsx:411 把 _disabled 从 componentProps 里剥掉,正是为了改用这条显式通道。)所以任何接受 disabled prop 的渲染器 —— 输入控件、按钮、表单字段 —— 在元数据写了 disabled: '' 时会被真正置灰。
求值块在 evaluatedSchema 的 useMemo 里无条件执行(SchemaRenderer.tsx:285 起的可见性块之后,不带任何 type 判定),因此覆盖的是走 SchemaRenderer 的全部节点,而不是某个渲染器。这也正是 #3823 分诊时说「组件级 visible 门大多休眠,因为 SchemaRenderer 更早一层就判了」的那一层 —— 在 disabled 方向上,这一层自己就是缺陷所在。
严重度请分诊裁。证据取自源码链(file:line 如上),未另跑运行期探针 —— 探针属 #3849 之外的文件面,本单只做静态取证。
修法上的岔路(需先裁,不该由实施者顺手定)
想「统一改读那唯一定义」有个包依赖障碍:hasDeclaredVisibilityGate 定义在 packages/components/src/renderers/action/visibility-gate.ts,而 SchemaRenderer 在 packages/react。按仓内拓扑 components 依赖 react,反向导入是禁止的方向 —— 所以这里要么把定义上提(@object-ui/core 或 @object-ui/types 一侧),要么另想办法。#3842 已裁「不上提 core」,但那条裁定的语境是动作面五个落点,不是这条跨包路径;是否为了 SchemaRenderer 重新审视上提,是一个需要维护者裁的契约问题。
⛔ 明确不推荐:在 SchemaRenderer 里就地补一个 && !== '' —— 那就是把第四种「空」的拼法写进第四个消费者,#3842 / #3849 刚刚合掉的正是这类分身。
不是它的子集:#3850 收的是「空的范围」在 hasDeclaredVisibilityGate / toPredicateInput / evaluateCondition 三处不一致(空 source 信封那道夹缝),它的修法落点是 hasDeclaredVisibilityGate 那唯一定义或 producer 侧校验。SchemaRenderer 不调用 hasDeclaredVisibilityGate,自带一套内联判定,所以把 #3850 修完这一处仍然是错的 —— 按「附着而非散落」的判据,这属于独立单而非 #3850 的子单。但两单共享同一个「定义该放在哪一层」的裁定面,建议同批裁。
Related: #3842 / PR #3851(action:button + DeclaredActionsBar 两处,'' 半边已修)、#3849 / PR #3861(其余五处渲染落点,!= null → hasDeclaredVisibilityGate)、#3850(空 source 信封的范围不一致,同一裁定面)、#3848(执行入口 ActionRunner 的同族半边)、#3492(不变量出处)。未认领。
来源
发现自 #3849(PR #3861)实施时对第三种拼法的逐处核对。#3849 的正文把它列为「实施时请按落点逐一确认」的注意事项,但它不在 #3849 的文件面(#3849 只动五个渲染器落点),也不在 #3850 的修法面(见下「与 #3850 的关系」),故独立成单,未认领。
机理
「是否声明了
disabled门」在仓里第三次被回答,这次的拼法是!== undefined,范围比!= null还要宽一格。packages/react/src/SchemaRenderer.tsx:322-334(origin/main@993336f7c481e1fd724512363b8b2f15b305da86):ExpressionEvaluator.evaluateCondition(packages/core/src/evaluator/ExpressionEvaluator.ts:238-240)对空谓词的答复是「没有条件 → 可见/可用」:于是链条闭合:
disabled: ''通过!== undefined这一关 →evaluateCondition('')返回true→_disabled = true。方向不对称与 #3842 / #3849 完全相同 —— 同一个true在visible上意味着「显示」(该侧visible !== undefined因此良性,SchemaRenderer.tsx:287的!evaluateCondition('')=!true= 不隐藏),在disabled上意味着「禁用」。比
!= null家族多亏一格:disabled: null也会置灰(null !== undefined为真 →evaluateCondition(null)为true)。!= null的五处落点至少把null排在门外。值不是死的:它会被转发成组件 prop
这一点是 #3849 正文没有建立的部分。
_disabled不是内部标记而已 ——SchemaRenderer.tsx:461把它交给被渲染组件:(同一处
SchemaRenderer.tsx:411把_disabled从componentProps里剥掉,正是为了改用这条显式通道。)所以任何接受disabledprop 的渲染器 —— 输入控件、按钮、表单字段 —— 在元数据写了disabled: ''时会被真正置灰。求值块在
evaluatedSchema的useMemo里无条件执行(SchemaRenderer.tsx:285起的可见性块之后,不带任何 type 判定),因此覆盖的是走SchemaRenderer的全部节点,而不是某个渲染器。这也正是 #3823 分诊时说「组件级visible门大多休眠,因为SchemaRenderer更早一层就判了」的那一层 —— 在disabled方向上,这一层自己就是缺陷所在。严重度请分诊裁。证据取自源码链(file:line 如上),未另跑运行期探针 —— 探针属 #3849 之外的文件面,本单只做静态取证。
修法上的岔路(需先裁,不该由实施者顺手定)
想「统一改读那唯一定义」有个包依赖障碍:
hasDeclaredVisibilityGate定义在packages/components/src/renderers/action/visibility-gate.ts,而SchemaRenderer在packages/react。按仓内拓扑components依赖react,反向导入是禁止的方向 —— 所以这里要么把定义上提(@object-ui/core或@object-ui/types一侧),要么另想办法。#3842 已裁「不上提 core」,但那条裁定的语境是动作面五个落点,不是这条跨包路径;是否为了SchemaRenderer重新审视上提,是一个需要维护者裁的契约问题。⛔ 明确不推荐:在
SchemaRenderer里就地补一个&& !== ''—— 那就是把第四种「空」的拼法写进第四个消费者,#3842 / #3849 刚刚合掉的正是这类分身。与 #3850 的关系
不是它的子集:#3850 收的是「空的范围」在
hasDeclaredVisibilityGate/toPredicateInput/evaluateCondition三处不一致(空source信封那道夹缝),它的修法落点是hasDeclaredVisibilityGate那唯一定义或 producer 侧校验。SchemaRenderer不调用hasDeclaredVisibilityGate,自带一套内联判定,所以把 #3850 修完这一处仍然是错的 —— 按「附着而非散落」的判据,这属于独立单而非 #3850 的子单。但两单共享同一个「定义该放在哪一层」的裁定面,建议同批裁。Related: #3842 / PR #3851(
action:button+DeclaredActionsBar两处,''半边已修)、#3849 / PR #3861(其余五处渲染落点,!= null→hasDeclaredVisibilityGate)、#3850(空source信封的范围不一致,同一裁定面)、#3848(执行入口ActionRunner的同族半边)、#3492(不变量出处)。未认领。