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
17 changes: 17 additions & 0 deletions Demo/App.swiftpm/Sources/AppearancePlaygrounds.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,24 @@ struct AppearancePlayground: View {
Text("Centered overlay").foregroundColor(.white).bold()
}
}
Example("Unknown modifier → red outline") {
Text("Carries a modifier the interpreter doesn't recognize")
.padding()
.unrecognizedModifier()
}
}
}
}
}

/// A stand-in for a modifier the interpreter has no fold for — emits a kind
/// outside the known set, so the renderer flags it with a red outline.
struct _UnrecognizedModifier: RenderModifier {
var _modifierNode: ModifierNode { ModifierNode(kind: "notImplementedInInterpreter") }
}

extension View {
func unrecognizedModifier() -> ModifiedContent<Self, _UnrecognizedModifier> {
modifier(_UnrecognizedModifier())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -980,12 +980,27 @@ internal fun ViewNode.composeModifiers(): Modifier {
if (off) modifier.alpha(0.38f) else modifier
}

else -> modifier // unknown modifier: ignore, never crash rendering
else -> modifier // consumed elsewhere (Text/RenderChild/effects) or unknown
}
}
// Schema-drift visibility: a kind no consumer recognizes gets a red outline,
// the modifier-level analog of the unknown-node diagnostic.
if (modifiers.any { it.kind !in KNOWN_MODIFIER_KINDS }) {
modifier = modifier.border(1.dp, Color.Red)
}
return modifier
}

// Every modifier kind some consumer handles — composeModifiers folds most;
// the rest are read by RenderText, RenderChild (environment), RenderEffects, or
// container branches (tag/tabItem). A kind outside this set is schema drift.
private val KNOWN_MODIFIER_KINDS = setOf(
"padding", "frame", "background", "cornerRadius", "offset", "rotation",
"scale", "opacity", "border", "shadow", "clipShape", "onTapGesture", "disabled",
"font", "fontWeight", "italic", "foregroundColor", "lineLimit", "multilineTextAlignment",
"tint", "onAppear", "onDisappear", "task", "onChange", "animation", "tag", "tabItem",
)

// Folds a frame entry: fixed size, fill (maxWidth/Height .infinity), bounded
// (widthIn/heightIn), and content alignment within the resulting box.
@Composable
Expand Down
Loading