@gj-kit/expo-ui core concepts
React Native and web primitives: an unnamed IconButton, Tabs, or Slider is a compile error.
Why this boundary exists
Section titled “Why this boundary exists”In a React Native design system the failures are silent: an IconButton ships with no accessibility label, a Tabs value is typo’d so the panel renders blank, an EmptyState action renders a button whose onPress was never wired, and a hand-assembled theme object leaks undefined into a style prop. None of that fails the build — it fails on a screen reader, in production, on someone else’s device.
Accessibility is part of the component contract
Section titled “Accessibility is part of the component contract”Accessible names, press handlers, and range labels are required by component types, not left as a review checklist after layout work.
Controlled state has a complete shape
Section titled “Controlled state has a complete shape”Tabs carry literal item values through to their panels, so a missing panel becomes a type error instead of an empty screen.
What the package enforces
Section titled “What the package enforces”- Measured Android popup coordinates — Android anchored Menu and Select measure root-relative trigger page coordinates to match the full-window Modal. Status-bar insets are not hardcoded; iOS and web retain their existing placement paths.
- Accessible names the type demands — IconButton without accessibilityLabel, a rich-children Button with no name, and a range Slider given one label instead of a two-thumb tuple are all rejected.
- Dead buttons do not compile — ButtonInteractionProps is a union: onPress is required unless disabled or loading is literally true, and an EmptyState action must carry both label and onPress.
- Tabs cannot lose a panel — panels is typed
Readonly<Record<NoInfer<ItemValue>, NonNullable<ReactNode>>>and value is NoInfer-wrapped, so a typo’d value, a missing panel, and a null panel all fail typecheck. - createTheme is the only door — UiProvider’s theme prop accepts only a branded Theme or ThemePair produced by createTheme or createThemes; a hand-assembled token object is a compile error.
- No design literals in the source — A guard test walks every .tsx file under src/components recursively and fails on any quoted hex color, any numeric fontSize, or any quoted numeric fontWeight.
What remains application-owned
Section titled “What remains application-owned”Keep optional safe-area and React Native Web peers behind their documented subpaths. Supply application copy through strings rather than baking product copy into primitives.
Continue with the two verified recipes.