Wrap approval detail and size the box to its content
The first pass put the detail in a ScrollView with fixedSize(horizontal:) and a fixed maxHeight, so the command was forced onto one long line that scrolled horizontally and the box always claimed full height — a tall box with a lot of empty space. Replace it with an ApprovalDetailBox (macOS + iOS) that wraps the text and measures its content height via a PreferenceKey, sizing the box to fit and only scrolling vertically once the content exceeds the max height. No more horizontal scroll; short commands sit in a snug box. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -33,18 +33,11 @@ struct ApprovalCardView: View {
|
|||||||
.background(approval.risk.color.opacity(0.2), in: Capsule())
|
.background(approval.risk.color.opacity(0.2), in: Capsule())
|
||||||
.foregroundStyle(approval.risk.color)
|
.foregroundStyle(approval.risk.color)
|
||||||
}
|
}
|
||||||
// Full, untruncated content in a bounded scroll view — the user must be
|
// Full, untruncated content — the command wraps and the box fits its
|
||||||
// able to read exactly what they are granting, so long commands/paths/inputs
|
// content, only scrolling vertically once it's genuinely tall, so the user
|
||||||
// scroll instead of being clipped to a few lines.
|
// can read exactly what they are granting without a giant half-empty box.
|
||||||
if !approval.input.approvalDetail.isEmpty {
|
if !approval.input.approvalDetail.isEmpty {
|
||||||
ScrollView([.horizontal, .vertical]) {
|
ApprovalDetailBox(text: approval.input.approvalDetail)
|
||||||
Text(approval.input.approvalDetail)
|
|
||||||
.font(.caption.monospaced())
|
|
||||||
.textSelection(.enabled)
|
|
||||||
.padding(8)
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, maxHeight: 200, alignment: .leading)
|
|
||||||
.background(Color(.secondarySystemBackground), in: RoundedRectangle(cornerRadius: 8))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if requiresBiometric && !biometricPassed {
|
if requiresBiometric && !biometricPassed {
|
||||||
@@ -118,3 +111,36 @@ struct ApprovalCardView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The full content of an approval, wrapped and selectable. The box sizes to its
|
||||||
|
/// content and only begins scrolling once the content exceeds `maxHeight`, so a short
|
||||||
|
/// command sits in a snug box while a large paste stays bounded. The text wraps; it
|
||||||
|
/// never scrolls horizontally.
|
||||||
|
private struct ApprovalDetailBox: View {
|
||||||
|
let text: String
|
||||||
|
private let maxHeight: CGFloat = 200
|
||||||
|
@State private var contentHeight: CGFloat = 0
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ScrollView(.vertical) {
|
||||||
|
Text(text)
|
||||||
|
.font(.caption.monospaced())
|
||||||
|
.textSelection(.enabled)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.padding(8)
|
||||||
|
.background(GeometryReader { geo in
|
||||||
|
Color.clear.preference(key: ApprovalDetailHeightKey.self, value: geo.size.height)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
.frame(height: contentHeight == 0 ? nil : min(contentHeight, maxHeight))
|
||||||
|
.onPreferenceChange(ApprovalDetailHeightKey.self) { contentHeight = $0 }
|
||||||
|
.background(Color(.secondarySystemBackground), in: RoundedRectangle(cornerRadius: 8))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ApprovalDetailHeightKey: PreferenceKey {
|
||||||
|
static var defaultValue: CGFloat { 0 }
|
||||||
|
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
||||||
|
value = max(value, nextValue())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user