Skip to content

fix(components): prefix the CSS properties Safari needs prefixed - #3066

Open
Lisa18289 wants to merge 1 commit into
mainfrom
claude/affectionate-ardinghelli-52f608
Open

fix(components): prefix the CSS properties Safari needs prefixed#3066
Lisa18289 wants to merge 1 commit into
mainfrom
claude/affectionate-ardinghelli-52f608

Conversation

@Lisa18289

@Lisa18289 Lisa18289 commented Sep 2, 2026

Copy link
Copy Markdown
Member

Safari honours user-select and backdrop-filter only behind -webkit-, and we ship the components' CSS through no autoprefixer. So the LightBox gallery item stayed selectable while swiping, and the overlay backdrop behind every Modal and LightBox did not blur below Safari 18.

This adds autoprefixer to the PostCSS pipeline. It goes into vite.config.ts rather than the build config, so dev, Storybook, the browser tests and the published CSS all carry the same prefixes.

The part worth a look is browserslist, which declares our supported range for the first time and is what decides which prefixes get written. It is a single baseline widely available query — Safari 17.2+, Chrome 121+, Edge, Firefox, Android Chrome and Firefox — so no version is pinned by hand. It sits in packages/components/package.json and not in the root because Next reads browserslist too, and a root entry would change the docs build along with it.

Costs 96 bytes: three declarations in all.css, nothing else.

🤖 Generated with Claude Code

@Lisa18289 Lisa18289 added the run-visual-tests Runs the full visual regression suite against the existing baselines and fails the check on mismatch label Sep 2, 2026
@Lisa18289 Lisa18289 self-assigned this Sep 2, 2026
@github-actions github-actions Bot removed the run-visual-tests Runs the full visual regression suite against the existing baselines and fails the check on mismatch label Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for ./packages/components/

Status Category Percentage Covered / Total
🔵 Lines 78.69% 746 / 948
🔵 Statements 78.57% 763 / 971
🔵 Functions 80.09% 165 / 206
🔵 Branches 70.33% 377 / 536
File CoverageNo changed files found.
Generated in workflow #6657 for commit 1f52c4d by the Vitest Coverage Report Action

@Lisa18289
Lisa18289 force-pushed the claude/affectionate-ardinghelli-52f608 branch from ec452e2 to 72795a8 Compare September 2, 2026 06:06
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

❌ Visual Regression Tests Failed

At least one shard did not pass. If snapshots differ from the committed baselines, download the visual-diffs-* artifacts from this run to inspect the actual/diff images (a shard that failed before comparison, e.g. during install or browser setup, leaves none).

If the differences are intentional, update the baselines by adding the update-screenshots label to the PR.

Run details

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

Preview environments are ready:

Type URL
docs pr-3066.docs.review.flow-components.de
storybook pr-3066.storybook.review.flow-components.de

Images:

  • docs: ghcr.io/mittwald/flow/docs:pr-3066
  • storybook: ghcr.io/mittwald/flow/storybook:pr-3066

@Lisa18289
Lisa18289 marked this pull request as ready for review September 2, 2026 06:15
@Lisa18289
Lisa18289 requested a review from a team September 2, 2026 06:15
@Lisa18289
Lisa18289 marked this pull request as draft September 2, 2026 06:16
@Lisa18289
Lisa18289 force-pushed the claude/affectionate-ardinghelli-52f608 branch from 72795a8 to 64f0640 Compare September 2, 2026 06:28
@Lisa18289 Lisa18289 changed the title fix(LightBox): apply user-select in Safari fix(components): prefix the CSS properties Safari needs prefixed Sep 2, 2026
@Lisa18289
Lisa18289 force-pushed the claude/affectionate-ardinghelli-52f608 branch 2 times, most recently from 5b6f915 to 876773e Compare September 2, 2026 08:41
@Lisa18289
Lisa18289 marked this pull request as ready for review September 2, 2026 08:57
Lisa18289 added a commit that referenced this pull request Sep 2, 2026
A ListItem and a table row are click targets, and React Aria sets
`user-select: none` on them for the duration of a press, so their text could not
be selected. The item's title and subtitle and the table's cells now opt back
in, and a click that ends a pointer interaction which changed the text selection
is swallowed in the capture phase — React Aria triggers the press from the click
event, so selecting a heading would otherwise activate the item as well.

A click that did not change the selection still activates the item, including
one landing inside an existing selection, where the browser keeps the selection
alive until after the click. A click without a pointer interaction — keyboard,
screen reader, `element.click()` — carries no selection change and is never
swallowed.

The title box hugs its text exactly, so a drag would have had to hit the text
pixel for pixel. The header around it is selectable as well, and the title
carries padding cancelled out by the same negative margin, so a drag can start
beside the text without moving it.

Only a native drag creates a real text selection, and every parallel test file
shares one page and one Playwright cursor, so another file's click releases the
held button mid-drag. The `browser-mouse` project gives those tests a page of
their own, one file at a time.

Needs #3066 to work in Safari: WebKit has no unprefixed `user-select`, so
without autoprefixer the rule does not apply there and the webkit browser
project fails.

Closes #895

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Lisa18289 added a commit that referenced this pull request Sep 2, 2026
A ListItem and a table row are click targets, and React Aria sets
`user-select: none` on them for the duration of a press, so their text could not
be selected. The item's title and subtitle and the table's cells now opt back
in, and the click that ends a mouse drag is swallowed in the capture phase —
React Aria triggers the press from the click event, so selecting a heading would
otherwise activate the item as well.

Dragging never activates an item, whether or not it selected text: a drag that
missed the text would otherwise navigate away rather than do nothing. A click
that changed the text selection is swallowed regardless of distance, which
covers selecting a single character and selecting by long press on touch.

An ordinary click still activates the item, including one that wobbles a few
pixels or lands inside an existing selection, where the browser keeps the
selection alive until after the click. A drag that started on an interactive
child is left alone, as is any click arriving without a pointer interaction —
keyboard, screen reader, `element.click()`.

The title box hugs its text exactly, so a drag would have had to hit the text
pixel for pixel. The header around it is selectable as well, and the title
carries padding cancelled out by the same negative margin, so a drag can start
beside the text without moving it.

Only a native drag creates a real text selection, and every parallel test file
shares one page and one Playwright cursor, so another file's click releases the
held button mid-drag. The `browser-mouse` project gives those tests a page of
their own, one file at a time.

Needs #3066 to work in Safari: WebKit has no unprefixed `user-select`, so
without autoprefixer the rule does not apply there and the webkit browser
project fails.

Closes #895

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Lisa18289
Lisa18289 force-pushed the claude/affectionate-ardinghelli-52f608 branch from 876773e to 6d41d90 Compare September 3, 2026 11:12
Lisa18289 added a commit that referenced this pull request Sep 3, 2026
A ListItem and a table row are click targets, and React Aria sets
`user-select: none` on them for the duration of a press, so their text could not
be selected. The item's title and subtitle and the table's cells now opt back
in, and the click that ends a mouse drag is swallowed in the capture phase —
React Aria triggers the press from the click event, so selecting a heading would
otherwise activate the item as well.

Dragging never activates an item, whether or not it selected text: a drag that
missed the text would otherwise navigate away rather than do nothing. A click
that changed the text selection is swallowed regardless of distance, which
covers selecting a single character and selecting by long press on touch.

An ordinary click still activates the item, including one that wobbles a few
pixels or lands inside an existing selection, where the browser keeps the
selection alive until after the click. A drag that started on an interactive
child is left alone, as is any click arriving without a pointer interaction —
keyboard, screen reader, `element.click()`.

The title box hugs its text exactly, so a drag would have had to hit the text
pixel for pixel. The header around it is selectable as well, and the title
carries padding cancelled out by the same negative margin, so a drag can start
beside the text without moving it.

Only a native drag creates a real text selection, and every parallel test file
shares one page and one Playwright cursor, so another file's click releases the
held button mid-drag. The `browser-mouse` project gives those tests a page of
their own, one file at a time.

Needs #3066 to work in Safari: WebKit has no unprefixed `user-select`, so
without autoprefixer the rule does not apply there and the webkit browser
project fails.

Closes #895

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Lisa18289
Lisa18289 enabled auto-merge (squash) September 3, 2026 11:13
@Lisa18289
Lisa18289 force-pushed the claude/affectionate-ardinghelli-52f608 branch from 6d41d90 to 86864db Compare September 3, 2026 11:15
Lisa18289 added a commit that referenced this pull request Sep 3, 2026
A ListItem and a table row are click targets, and React Aria sets
`user-select: none` on them for the duration of a press, so their text could not
be selected. The item's title and subtitle and the table's cells now opt back
in, and the click that ends a mouse drag is swallowed in the capture phase —
React Aria triggers the press from the click event, so selecting a heading would
otherwise activate the item as well.

Dragging never activates an item, whether or not it selected text: a drag that
missed the text would otherwise navigate away rather than do nothing. A click
that changed the text selection is swallowed regardless of distance, which
covers selecting a single character and selecting by long press on touch.

An ordinary click still activates the item, including one that wobbles a few
pixels or lands inside an existing selection, where the browser keeps the
selection alive until after the click. A drag that started on an interactive
child is left alone, as is any click arriving without a pointer interaction —
keyboard, screen reader, `element.click()`.

The title box hugs its text exactly, so a drag would have had to hit the text
pixel for pixel. The header around it is selectable as well, and the title
carries padding cancelled out by the same negative margin, so a drag can start
beside the text without moving it.

Only a native drag creates a real text selection, and every parallel test file
shares one page and one Playwright cursor, so another file's click releases the
held button mid-drag. The `browser-mouse` project gives those tests a page of
their own, one file at a time.

Needs #3066 to work in Safari: WebKit has no unprefixed `user-select`, so
without autoprefixer the rule does not apply there and the webkit browser
project fails.

Closes #895

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Safari honours `user-select` and `backdrop-filter` only behind `-webkit-`, and
the components build shipped its CSS through no autoprefixer. Two rules were
dead there: the LightBox gallery item stayed selectable while swiping, and the
overlay backdrop behind every Modal and LightBox did not blur below Safari 18.

Autoprefixer goes into the dev config rather than the build config, so dev,
Storybook, the browser tests and the published CSS all carry the same prefixes —
the release build merges on top and concatenates the plugin list.

`browserslist` declares the supported range for the first time, as a single
`baseline widely available` query: whatever has been supported across the core
engines for 30 months. It pins no version by hand and moves with the Baseline
data, and it still reaches back far enough to cover the two rules above
(Safari 17.2, Chrome 121). Autoprefixer's own `defaults` would be both worse and
noisier here — it starts at Safari 18, so it misses the backdrop entirely, while
adding ~90 declarations for Opera Mini and Firefox 63.

Verified against the built artifact, not the plugin in isolation: `all.css` and
`all-layered.css` gain three declarations and nothing else, with the layer
structure unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Lisa18289
Lisa18289 force-pushed the claude/affectionate-ardinghelli-52f608 branch from 86864db to 1f52c4d Compare September 3, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant