[DS-17] Implement Select component + native-only convention pivot #8
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/DS-17"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ticket
DS-17 Implement Select component (Form Inputs category)
Summary
This PR is unusually large in scope for one ticket: implementing
Selectsurfaced a repo-wideconvention decision made during planning, so this branch does both.
1. Repo-wide convention pivot to native-only components
The design-system dropped its dual web (
index.tsx)/native (index.native.tsx) implementationsplit entirely. Storybook already renders native primitives through a
react-native->react-native-webalias (.storybook/main.ts), so a single native implementation now covers bothreal Expo/RN apps and browser preview — there's no DOM-specific version to hand-maintain per
component. New convention (see
CLAUDE.md):Text(the only pre-existing component) migrated to this convention in this same PR, so thewhole repo lands on one consistent pattern rather than a mixed state.
tsupentry;package.jsondropped thereact-nativeexportcondition/field,
react-nativebecame a required peer dependency (was optional),react-domdropped out of
peerDependencies(stays a devDependency for Storybook)..storybook/main.tsgained a secondstoriesglob entry for the literalnative/stories.tsxfilename (doesn't match the default
*.stories.tsxpattern).CLAUDE.md/README.mdupdated to describe and justify the new convention.bunfig.tomlpreload,src/test-utils/happydom.ts,@happy-dom/global-registratordevDependency) — only used by the deleted DOM-basedTexttests.2.
Selectfield component (DS-17 itself)Built fresh with RN core components only (
Pressable,Modal,FlatList,View) — no new UIdependency, matching
Text's zero-dependency precedent. Single-select via a trigger + optionsheet, wired into React Hook Form the same way
Textis (useController, inline error rendering).Styled via NativeWind classNames sourced from existing
designSystemPresettokens.The only prior "Select" in this stack (
swyfft's DOM-only,react-aria-components-based one)was evaluated and rejected as a port candidate — it bakes in Swyfft-specific business logic and
depends on packages not used here, failing the epic checklist's "no app-specific business logic"
and Expo-compatibility items. It was used only as a UX reference (trigger + option list pattern).
Also added
src/nativewind.d.ts— a small local ambient type augmentation addingclassName?: stringtoViewProps/TextProps/PressableProps, since this repo has nonativewinddependency(by design) and react-native's own shipped types have no
classNameprop.Selectis the firstcomponent to actually use
className, surfacing the gap; this mirrors NativeWind's own real typeaugmentation technique rather than adding the dependency.
Pre-PR review remediation (both an initial full pass and a scoped follow-up re-review over the
remediation diff):
Select's trigger now firesfield.onBlur()explicitly on modal close, since RN doesn'tmove focus on a touch press (the trigger's own
onBlurprop never fires on a real device).without selecting.
field.refwired onto the trigger, matchingText's convention.optionslist scrolls instead ofoverflowing.
<Story />instead of callingStory().onBlurreasoning, thenativewind.d.ts"scoped" claim, README's claim aboutdist/resolving under any bundler).sheet-tap-doesn't-dismiss fix (verified by reverting the fix locally and confirming the test
fails, then restoring it).
Deliberately deferred / out of scope (flagged during review, not fixed here to avoid scope
creep beyond this ticket):
nativewindas a real devDependency so Storybook renders actual visual styling(
classNameis currently inert under Storybook's plainreact-native-webrender, by design —overlaps DS-3, theming architecture, still open).
SelectProps/TextProps's duplicatedname/label/placeholder/rulesfields — two components don't yet justify the abstraction.src/text/native/stories.tsx— the approved plan scopedText's migration to moving existingfiles only.
accessibilityState/role on option rows, RNTL mock realismfor
*ByRolequeries) — real but not blocking for a firstSelectimplementation.f2823d763cb4f1bfd4ebView command line instructions
Manual merge helper
Use this merge commit message when completing the merge manually.
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.