Skip to content

macOS: a borderless TextField with a background color overhangs its stack by 2pt on each side #11739

Description

@steinybot

A borderless TextField that has a background color is 4pt wider than the stack it fills on macOS. It overhangs the stack by 2pt on each side, so its border and background draw outside the column.

Image

Repro

import {
  App, Text, TextField, VStack, setPadding, textfieldSetBackgroundColor, textfieldSetBorderless,
  widgetMatchParentWidth, widgetSetBackgroundColor, widgetSetBorderColor, widgetSetBorderWidth,
  widgetSetHeight, widgetSetWidth,
} from "perry/ui"

function field(withBackground: boolean) {
  const f = TextField("", () => {})
  textfieldSetBorderless(f, 1)
  if (withBackground) textfieldSetBackgroundColor(f, 1, 1, 1, 1)
  widgetSetBorderColor(f, 0, 0, 0, 1)
  widgetSetBorderWidth(f, 1)
  return f
}

const a = field(true)
const b = field(false)
const column = VStack(6, [Text("textfieldSetBackgroundColor:"), a, Text("no background color:"), b])
widgetSetWidth(column, 300)
widgetSetBackgroundColor(column, 0.75, 0.87, 1, 1)
for (const f of [a, b]) {
  widgetMatchParentWidth(f)
  widgetSetHeight(f, 32)
}
const root = VStack(0, [column])
setPadding(root, 24, 40, 24, 40)
widgetSetBackgroundColor(root, 1, 1, 1, 1)

App({ title: "TextField width", width: 380, height: 160, body: root })

Expected: both fields are 300pt wide at x = 0.
Actual: field a is 304pt wide at x = -2. Field b is 300pt wide at x = 0. Geisterhand's /widgets?tree=true reports the same frames.

Cause

15158cd "pad text fields as CSS padding does" (#11665) made textfieldSetBackgroundColor paint the layer and call setDrawsBackground(false) on the field. An NSTextField with no bezel, no border, and no background is shaped like a label to AppKit. AppKit gives it a label's alignmentRectInsets: 2pt on the left and the right. Auto Layout pins the alignment rect to the stack, so the frame grows 2pt past each edge. The layer border and the layer background draw on the frame.

Measured with the field pinned to a 590pt stack:

Build textfieldSetBackgroundColor drawsBackground alignmentRectInsets Frame
main (d368f62) no true 0, 0 x 0, w 590
main (d368f62) yes false 2, 2 x -2, w 594
main (d368f62) yes, bezeled false 0, 0 x 0, w 590
before #11661 (4d4cd17) yes true 0, 0 x 0, w 590

native_textfield_cell.rs sets each field's frame by hand, so it does not see the inset.

Proposed fix

Make PerryTextField and PerrySecureTextField return zero alignmentRectInsets. A field must fill the width it is pinned to, whatever it draws. Add a native test that pins a borderless field with a background to a stack and checks that its frame matches the stack's width.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions