Skip to content

fix(core): one platform detection, and Unknown is no answer either - #5394

Open
Astro-Han wants to merge 1 commit into
facebook:mainfrom
Astro-Han:fix/5325-followup-shared-apple-platform-detection
Open

fix(core): one platform detection, and Unknown is no answer either#5394
Astro-Han wants to merge 1 commit into
facebook:mainfrom
Astro-Han:fix/5325-followup-shared-apple-platform-detection

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #5325, picking up both review notes from @cixzhang. No separate issue: the behaviour was confirmed a bug in review there.

Unknown is no answer either

platform in the User-Agent Client Hints spec is a closed set: "Android", "Chrome OS", "Chromium OS", "iOS", "Linux", "macOS", "Windows", "Unknown". The last is the spec's value for "cannot say", so it names a platform no more than '' does. #5325 stopped '' from reading as "not Apple", but /mac/i.test('Unknown') is still false, so Unknown kept answering negatively without ever reaching navigator.platform.

If anything it is the likelier of the two to appear. '' is not a legal value, so only a careless embedder emits it; Unknown is what a careful one emits. Both fall through now, matched case-insensitively after a trim.

One detection instead of two

detectMac and isApplePlatform were byte-identical copies held together by a docstring claiming one mirrored the other, which is why #5253 had to be fixed in two places at once. They are now utils/isApplePlatform.ts, imported by both, so the Unknown change lands in one place.

It is deliberately not named in utils/index.ts. The package root does export * from './utils', so adding it to that barrel would publish it as API, the trap #5316 pulled back from. It is imported by path instead, as interactionModality already is, and pnpm sync:exports:check is clean.

The kept name is isApplePlatform rather than detectMac: the predicate matches iPhone/iPad/iPod as well as Mac, and Kbd reads it into a local isMac for glyph choice.

Tests

utils/isApplePlatform.test.ts, 8 cases over the implementation's branches: a client-hints platform that names one (both directions), the five that name none ('', whitespace, Unknown, UNKNOWN, a non-string, each asserted both ways against navigator.platform), absent client hints, and no navigator at all. Removing the sentinel check turns all five "names none" rows red, including #5253's original blank case.

#5325's blank-platform tests at the two call sites are removed rather than kept. With one implementation there is one place to test the logic, and what proves each surface still consults it is the pair of tests predating #5325 that spoof MacIntel directly. Keeping them would have been a third copy of a fact already established twice.

Validation

347 tests pass across utils/, Kbd/, useHotkeys.test.ts and serverSafeComponents.test.ts. typecheck, eslint, check:repo and sync:exports:check are clean. A [fix] changeset is included.

Prepared with Claude Code, reviewed and verified by me before opening.

Follow-up to facebook#5325, which taught `useHotkeys` and `Kbd` to fall through to
`navigator.platform` when `userAgentData.platform` is blank.

`Unknown` is the User-Agent Client Hints spec's own value for "cannot say",
and it names a platform no more than `''` does. It still committed to the
client-hints branch, evaluated `/mac/i.test('Unknown')`, and answered "not
Apple" without reaching the fallback. It is arguably likelier to appear than
a blank: `''` is not a value the spec allows, so only a careless embedder
emits it, while `Unknown` is what a careful one emits. Both now fall through.

The two detections were independent copies kept aligned by a docstring
claiming one mirrored the other. They are now a single internal util that
both import, so the next change to this logic cannot land on one surface and
miss the other, and the behaviour has one place to be tested.

The util is deliberately absent from `utils/index.ts`: the package root does
`export * from './utils'`, so naming it there would publish it as API.
Imported by path instead, as `interactionModality` is.

With one implementation there is one place to test it, so facebook#5325's blank-
platform tests at the two call sites fold into the util's own suite. What
proves each surface still consults the detection is the pair of tests that
predate facebook#5325 and spoof `MacIntel` directly.
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Error Error Aug 24, 2026 4:20am

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 24, 2026
@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge labels Aug 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

Kbd (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 123 -
Complexity N/A Medium (10) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.8KB 1.2KB

Accessibility Audit

Status: No accessibility violations detected.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

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

Labels

CLA Signed This label is managed by the Meta Open Source bot. community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant