oficina / sheets Public

Use thin header dividers and a single cell editing border

Reviewed by GPT-6 Astra. Visually verified the editing fixture; native typing/resize tests and iOS simulator build pass.
Paul Campbell pushed by paul@keymail.dev 39a67f39b17ee08c7ec62f6a604112e665e19b08 parent 32546da
4 files changed, +18 −11
  • native/apple/Sources/SheetsKit/SheetCellEditor.swift +2 −0
  • native/apple/Sources/SheetsKit/SheetGrid.swift +5 −5
  • native/apple/Sources/SheetsKit/SheetResizeHandle.swift +6 −1
  • native/apple/Tests/SheetsKitTests/SheetNativeInteractionTests.swift +5 −5

CI passed — run details

diff --git a/native/apple/Sources/SheetsKit/SheetCellEditor.swift b/native/apple/Sources/SheetsKit/SheetCellEditor.swift
index 5871425..162aef2 100644
--- a/native/apple/Sources/SheetsKit/SheetCellEditor.swift
+++ b/native/apple/Sources/SheetsKit/SheetCellEditor.swift
@@ -14,6 +14,8 @@ struct SheetCellEditor: NSViewRepresentable {
func makeNSView(context: Context) -> CellTextField {
let field = CellTextField()
field.isBordered = false; field.drawsBackground = false
+ // The cell already draws its selection border around the full cell.
+ field.focusRingType = .none
field.font = .systemFont(ofSize: 13)
field.delegate = context.coordinator
field.stringValue = text
diff --git a/native/apple/Sources/SheetsKit/SheetGrid.swift b/native/apple/Sources/SheetsKit/SheetGrid.swift
index 11fa242..d01be06 100644
--- a/native/apple/Sources/SheetsKit/SheetGrid.swift
+++ b/native/apple/Sources/SheetsKit/SheetGrid.swift
@@ -14,14 +14,14 @@ struct SheetGrid: View {
Section {
ForEach(0..<model.rows, id: \.self) { row in
HStack(spacing: 0) {
- VStack(spacing: 0) {
+ ZStack(alignment: .bottom) {
Button { selectRow(row) } label: {
- Text(String(row + 1)).frame(width: 48, height: max(0, height(row) - 8)).background(.quaternary)
+ Text(String(row + 1)).frame(width: 48, height: height(row)).background(.quaternary)
}.buttonStyle(.plain).accessibilityLabel(String(format: sheetsMacString("Select row %d"), row + 1))
#if os(macOS)
resizeHandle(axis: "row", index: row).frame(width: 48, height: 8)
#else
- Rectangle().fill(.secondary.opacity(0.15)).frame(width: 48, height: 8)
+ Color.clear.frame(width: 48, height: 8)
.contentShape(.rect).gesture(resizeGesture(axis: "row", index: row))
.accessibilityHidden(true)
#endif
@@ -40,10 +40,10 @@ struct SheetGrid: View {
HStack(spacing: 0) {
Text("").frame(width: 48, height: 32)
ForEach(0..<model.cols, id: \.self) { col in
- HStack(spacing: 0) {
+ ZStack(alignment: .trailing) {
Button { selectColumn(col) } label: {
Text(Coordinate(r: 0, c: col).ref.dropLast())
- .frame(width: max(0, width(col) - 8), height: 32)
+ .frame(width: width(col), height: 32)
.contentShape(.rect)
}.buttonStyle(.plain)
.accessibilityLabel(String(format: sheetsMacString("Select column %@"), String(Coordinate(r: 0, c: col).ref.dropLast())))
diff --git a/native/apple/Sources/SheetsKit/SheetResizeHandle.swift b/native/apple/Sources/SheetsKit/SheetResizeHandle.swift
index 36d1cc0..c1ef577 100644
--- a/native/apple/Sources/SheetsKit/SheetResizeHandle.swift
+++ b/native/apple/Sources/SheetsKit/SheetResizeHandle.swift
@@ -14,7 +14,12 @@ struct SheetResizeHandle: NSViewRepresentable {
final class Handle: NSControl {
override func draw(_ dirtyRect: NSRect) {
NSColor.secondaryLabelColor.withAlphaComponent(0.15).setFill()
- bounds.fill()
+ // Keep the 8-point mouse target, but paint only the grid boundary.
+ let pixel = 1 / (window?.backingScaleFactor ?? 2)
+ let rule = actions?.vertical == true
+ ? NSRect(x: bounds.minX, y: bounds.minY, width: bounds.width, height: pixel)
+ : NSRect(x: bounds.maxX - pixel, y: bounds.minY, width: pixel, height: bounds.height)
+ rule.fill()
}
var actions: SheetResizeHandle?
private var start: NSPoint?
diff --git a/native/apple/Tests/SheetsKitTests/SheetNativeInteractionTests.swift b/native/apple/Tests/SheetsKitTests/SheetNativeInteractionTests.swift
index 7b33d64..8ff1ddd 100644
--- a/native/apple/Tests/SheetsKitTests/SheetNativeInteractionTests.swift
+++ b/native/apple/Tests/SheetsKitTests/SheetNativeInteractionTests.swift
@@ -31,6 +31,11 @@ final class SheetNativeInteractionTests: XCTestCase {
key("e", code: 14, window: window)
try await Task.sleep(for: .milliseconds(100))
XCTAssertEqual(model.draft, "he", "The initial character must not be selected and overwritten")
+ if ProcessInfo.processInfo.environment["OFICINA_CAPTURE_FIXTURES"] == "1",
+ let bitmap = host.bitmapImageRepForCachingDisplay(in: host.bounds) {
+ host.cacheDisplay(in: host.bounds, to: bitmap)
+ try bitmap.representation(using: .png, properties: [:])?.write(to: URL(fileURLWithPath: "/tmp/oficina-sheets-grid-fixture.png"))
+ }
key("\t", code: 48, window: window)
try await Task.sleep(for: .milliseconds(500))
XCTAssertEqual(model.selection.start, Coordinate(r: 0, c: 0))
@@ -42,11 +47,6 @@ final class SheetNativeInteractionTests: XCTestCase {
try await Task.sleep(for: .milliseconds(100))
XCTAssertFalse(model.hasUnconfirmedChanges)
XCTAssertEqual(model.selection.start, Coordinate(r: 0, c: 0))
- if ProcessInfo.processInfo.environment["OFICINA_CAPTURE_FIXTURES"] == "1",
- let bitmap = host.bitmapImageRepForCachingDisplay(in: host.bounds) {
- host.cacheDisplay(in: host.bounds, to: bitmap)
- try bitmap.representation(using: .png, properties: [:])?.write(to: URL(fileURLWithPath: "/tmp/oficina-sheets-grid-fixture.png"))
- }
// Column B header then row 2 header select complete ranges.
click(NSPoint(x: 200, y: 375), window: window)
try await Task.sleep(for: .milliseconds(100))