Implement visual accommodations and Full Keyboard Access
Full relative text scaling per DESIGN/10: BoardMetrics is the board strip's geometry as a pure function of the body point size (CardWindowMetrics' twin) — lane plate/header/band, card corner/stripe/padding, masonry spacing, the drop model's nominal card height, resize-handle geometry, trash hatch pitch, and both window floors all derive from an em; CardFaceMetrics folded in. The two fixed font sizes (welcome brand/glyph) went relative; the toolbar search field is 17 ems like the transient bar's. The no-horizontal-scroll invariant is pinned by test at six text sizes by twelve lane counts. Accommodations is Motion's sibling for the visual settings: Increase Contrast adds a flat point to strokes (monotone, hierarchy-preserving), gives borderless card/lane plates a resting separator hairline, and takes faded accents to full alpha; Reduce Transparency turns the transient search bar's glass solid and does the same for the alpha washes that composite over a user-chosen board background (trash plate, hatched header, drag shadow). Reduce Motion audited — every animated surface already routes through Motion with a reduced variant; no gaps. Full Keyboard Access: the template chooser's tiles were pointer-only — now focusable, arrow-navigable (clamped, StyleWellGrid's rule), Space picks, Return stays the sheet's default action, focus names the selection one-way. The board's single tab stop shows its focus ring under FKA (focusEffectDisabled inverts). Style editor verified already conformant. Edge accents verified text-free; trash hatch pitch now font-derived so it still reads as hatching at large text. 1549 unit tests green, both schemes build. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -40,6 +40,15 @@ public struct BannerStripView: View {
|
||||
/// How many rows show before the disclosure takes over.
|
||||
private static let collapseThreshold = 3
|
||||
|
||||
/// The strip's own rhythm, font-derived like everything else the app lays out
|
||||
/// (`BoardMetrics`, 10-accessibility.md ▸ Text scaling: "no fixed point sizes"). It matters here
|
||||
/// because a banner row *wraps* rather than truncating — the cause tail is the half that says
|
||||
/// what to do — so a fixed inset around growing text crowds fast.
|
||||
@MainActor static var rowHorizontalPadding: CGFloat { BoardMetrics.em(0.9, bodyPointSize: pointSize) }
|
||||
@MainActor static var rowVerticalPadding: CGFloat { BoardMetrics.em(0.6, bodyPointSize: pointSize) }
|
||||
@MainActor static var rowSpacing: CGFloat { BoardMetrics.em(0.6, bodyPointSize: pointSize) }
|
||||
@MainActor private static var pointSize: CGFloat { BoardMetrics.bodyPointSize }
|
||||
|
||||
@State private var isExpanded = false
|
||||
|
||||
public init(rows: [BannerRow], onDismiss: @escaping (UUID) -> Void) {
|
||||
@@ -101,15 +110,15 @@ public struct BannerStripView: View {
|
||||
Button {
|
||||
isExpanded.toggle()
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
HStack(spacing: BannerStripView.rowSpacing) {
|
||||
Image(systemName: isExpanded ? "chevron.up" : "chevron.down")
|
||||
.imageScale(.small)
|
||||
Text(isExpanded ? "Show fewer" : "+\(hiddenCount) more")
|
||||
Spacer(minLength: 0)
|
||||
}
|
||||
.font(.callout)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 6)
|
||||
.padding(.horizontal, BannerStripView.rowHorizontalPadding)
|
||||
.padding(.vertical, BannerStripView.rowSpacing)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
@@ -127,7 +136,7 @@ private struct BannerRowView: View {
|
||||
let onDismiss: (UUID) -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .firstTextBaseline, spacing: 8) {
|
||||
HStack(alignment: .firstTextBaseline, spacing: BannerStripView.rowVerticalPadding) {
|
||||
leading
|
||||
|
||||
Text(row.headline)
|
||||
@@ -139,8 +148,8 @@ private struct BannerRowView: View {
|
||||
|
||||
trailingControls
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 8)
|
||||
.padding(.horizontal, BannerStripView.rowHorizontalPadding)
|
||||
.padding(.vertical, BannerStripView.rowVerticalPadding)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(row.tone.fill)
|
||||
// One element per row, tone included: a VoiceOver user must hear *that* this is an error
|
||||
|
||||
Reference in New Issue
Block a user