Lane selection sheds its slab — a hairline edge with a soft halo, intensity inverse to area
The whole-lane wash-and-solid-ring scaled its emphasis with the lane's area: what read as a ring on a card read as a slab on a column. Resettled as the system focus ring's vocabulary at selection strength — a hairline accent edge with a soft accent glow bleeding outward, riding the stroke shape rather than the translucent plate (a shadow behind it would bleed through as murk), and no wash at all: nothing tints the cards' backdrop, and lane colour stays the accent band's alone. Under Increase Contrast the halo yields to the solid full-alpha ring — "strengthens borders" means crisper, and a blur is the one thing a border cannot become — so the setting sees exactly the indicator it always has; cards and trash rows are card-scale and keep the solid ring at every contrast. One selection vocabulary, pinned by Accommodations.drawsSelectionHalo and its test. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -75,6 +75,20 @@ enum Accommodations {
|
|||||||
contrast == .increased ? 1 : base
|
contrast == .increased ? 1 : base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether a selected lane draws its **halo** — the soft accent glow bleeding outward from the
|
||||||
|
/// plate's hairline edge (`LaneView.selectionStroke`), the system focus ring's vocabulary at
|
||||||
|
/// selection strength.
|
||||||
|
///
|
||||||
|
/// Under Increase Contrast the answer is no, and that is the setting's own logic rather than a
|
||||||
|
/// retreat: "strengthens borders and the selection indicator" means *crisper*, and a blur is
|
||||||
|
/// the one thing a border cannot become. The edge instead goes full-alpha and heavier
|
||||||
|
/// (`accentOpacity`, `borderWidth` at the solid ring's base), so the setting sees the same
|
||||||
|
/// unambiguous solid ring it always has — the halo is the resting treatment's softness, not
|
||||||
|
/// the indicator itself.
|
||||||
|
static func drawsSelectionHalo(contrast: ColorSchemeContrast) -> Bool {
|
||||||
|
contrast != .increased
|
||||||
|
}
|
||||||
|
|
||||||
/// Increase Contrast, asked of AppKit rather than of the SwiftUI environment — for callers built
|
/// Increase Contrast, asked of AppKit rather than of the SwiftUI environment — for callers built
|
||||||
/// outside a rendered hierarchy, where the environment's accessibility values are not reliably
|
/// outside a rendered hierarchy, where the environment's accessibility values are not reliably
|
||||||
/// populated (`Motion.prefersReducedMotion`'s constituency).
|
/// populated (`Motion.prefersReducedMotion`'s constituency).
|
||||||
|
|||||||
@@ -175,10 +175,6 @@ struct LaneView: View, Equatable {
|
|||||||
}
|
}
|
||||||
.padding(BoardMetrics.lanePlatePadding(bodyPointSize: pointSize))
|
.padding(BoardMetrics.lanePlatePadding(bodyPointSize: pointSize))
|
||||||
}
|
}
|
||||||
.background(selectionBackground)
|
|
||||||
// Behind the selection wash, not composed into it: the plate is the lane's resting
|
|
||||||
// surface, the wash above it is the selection's own layer, and stacked `.background`s
|
|
||||||
// put the later one further back.
|
|
||||||
.background(lanePlate)
|
.background(lanePlate)
|
||||||
.overlay(selectionStroke)
|
.overlay(selectionStroke)
|
||||||
// The deferred cut's dim (04-interactions.md ▸ Clipboard) — on the whole lane, because a cut
|
// The deferred cut's dim (04-interactions.md ▸ Clipboard) — on the whole lane, because a cut
|
||||||
@@ -1081,28 +1077,35 @@ struct LaneView: View, Equatable {
|
|||||||
.fill(Accommodations.lanePlateWash(reduceTransparency: reduceTransparency).style)
|
.fill(Accommodations.lanePlateWash(reduceTransparency: reduceTransparency).style)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The selection treatment: a subtle whole-lane accent wash and stroke. Deliberately quiet —
|
/// The selection treatment: a hairline accent edge with a soft accent glow bleeding outward —
|
||||||
/// 03-board-ui.md gives lane *colour* to the top-edge accent band, so selection must not read as
|
/// the system focus ring's vocabulary at selection strength (resettled 2026-08-06, replacing
|
||||||
/// a fill that would compete with it once that lands.
|
/// the whole-lane wash-and-solid-ring, whose emphasis scaled with the lane's area: what read as
|
||||||
private var selectionBackground: some View {
|
/// a ring on a card read as a slab on a column). No wash at all now — nothing tints the cards'
|
||||||
RoundedRectangle(cornerRadius: cornerRadius)
|
/// backdrop, and lane *colour* stays the accent band's alone (03-board-ui.md § Styling).
|
||||||
.fill(isSelected ? AnyShapeStyle(Color.accentColor.opacity(0.08)) : AnyShapeStyle(.clear))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The selection ring — and, under Increase Contrast, the plate's resting edge as well
|
|
||||||
/// (10-accessibility.md: "Increase Contrast strengthens borders and the selection indicator";
|
|
||||||
/// `Accommodations`, and `CardFaceView.plateStroke` for the same three-way branch on a card).
|
|
||||||
///
|
///
|
||||||
/// A lane is otherwise bounded by its quiet wash and the gap between it and its neighbour,
|
/// The glow rides the stroke shape, never the plate: the plate is translucent
|
||||||
/// which is the distinction the setting most needs to restore here.
|
/// (`Accommodations.lanePlateWash`), and a shadow drawn behind it would bleed through as murk.
|
||||||
|
/// Under Increase Contrast the halo yields to the solid full-alpha ring — the two width bases
|
||||||
|
/// below — so the setting's selection indicator is exactly what it was before the resettlement
|
||||||
|
/// (`Accommodations.drawsSelectionHalo`; the trash's lane rows and `CardFaceView` are
|
||||||
|
/// card-scale and keep the solid ring at every contrast: one selection vocabulary, intensity
|
||||||
|
/// inverse to area).
|
||||||
private var selectionStroke: some View {
|
private var selectionStroke: some View {
|
||||||
RoundedRectangle(cornerRadius: cornerRadius)
|
RoundedRectangle(cornerRadius: cornerRadius)
|
||||||
.strokeBorder(plateStroke, lineWidth: plateStrokeWidth)
|
.strokeBorder(plateStroke, lineWidth: plateStrokeWidth)
|
||||||
|
.shadow(color: haloColor, radius: 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The halo's glow — clear whenever the halo doesn't draw, because a conditional modifier
|
||||||
|
/// would change the overlay's identity where a clear shadow just paints nothing.
|
||||||
|
private var haloColor: Color {
|
||||||
|
guard isSelected, Accommodations.drawsSelectionHalo(contrast: contrast) else { return .clear }
|
||||||
|
return Color.accentColor.opacity(0.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var plateStroke: AnyShapeStyle {
|
private var plateStroke: AnyShapeStyle {
|
||||||
if isSelected {
|
if isSelected {
|
||||||
AnyShapeStyle(Color.accentColor)
|
AnyShapeStyle(Color.accentColor.opacity(Accommodations.accentOpacity(0.55, contrast: contrast)))
|
||||||
} else if Accommodations.drawsRestingBorder(contrast: contrast) {
|
} else if Accommodations.drawsRestingBorder(contrast: contrast) {
|
||||||
AnyShapeStyle(.separator)
|
AnyShapeStyle(.separator)
|
||||||
} else {
|
} else {
|
||||||
@@ -1111,7 +1114,10 @@ struct LaneView: View, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var plateStrokeWidth: CGFloat {
|
private var plateStrokeWidth: CGFloat {
|
||||||
Accommodations.borderWidth(isSelected ? 1.5 : 1, contrast: contrast)
|
// The halo's edge is a hairline; with the halo off (Increase Contrast) the selected edge
|
||||||
|
// returns to the solid ring's 1.5 base, which `borderWidth` then strengthens as ever.
|
||||||
|
let base: CGFloat = isSelected && !Accommodations.drawsSelectionHalo(contrast: contrast) ? 1.5 : 1
|
||||||
|
return Accommodations.borderWidth(base, contrast: contrast)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Rename plumbing
|
// MARK: - Rename plumbing
|
||||||
|
|||||||
@@ -255,6 +255,15 @@ struct IncreaseContrastTests {
|
|||||||
#expect(Accommodations.accentOpacity(base, contrast: .increased) == 1)
|
#expect(Accommodations.accentOpacity(base, contrast: .increased) == 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The selected lane's glow is the resting treatment's softness, not the indicator itself:
|
||||||
|
/// under Increase Contrast it yields to the solid full-alpha ring, because "strengthens
|
||||||
|
/// borders" means crisper and a blur is the one thing a border cannot become.
|
||||||
|
@Test("The selection halo yields to Increase Contrast")
|
||||||
|
func theHaloYieldsToIncreaseContrast() {
|
||||||
|
#expect(Accommodations.drawsSelectionHalo(contrast: .standard))
|
||||||
|
#expect(!Accommodations.drawsSelectionHalo(contrast: .increased))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Reduce Transparency
|
// MARK: - Reduce Transparency
|
||||||
|
|||||||
Reference in New Issue
Block a user