@mrmeg/expo-ui 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/CHANGELOG.md +712 -0
  2. package/LLM_USAGE.md +260 -32
  3. package/README.md +558 -101
  4. package/dist/components/Accordion.js +12 -6
  5. package/dist/components/AnimatedView.d.ts +1 -1
  6. package/dist/components/AnimatedView.js +5 -2
  7. package/dist/components/Avatar.d.ts +1 -1
  8. package/dist/components/Avatar.js +2 -2
  9. package/dist/components/Badge.js +5 -1
  10. package/dist/components/BottomSheet.d.ts +66 -9
  11. package/dist/components/BottomSheet.js +143 -39
  12. package/dist/components/Button.d.ts +20 -4
  13. package/dist/components/Button.js +64 -43
  14. package/dist/components/Card.d.ts +1 -1
  15. package/dist/components/Card.js +24 -4
  16. package/dist/components/Carousel.js +2 -2
  17. package/dist/components/Checkbox.js +51 -44
  18. package/dist/components/Collapsible.js +7 -3
  19. package/dist/components/Dialog.js +178 -29
  20. package/dist/components/Drawer.d.ts +1 -1
  21. package/dist/components/Drawer.js +65 -55
  22. package/dist/components/DropdownMenu.js +11 -7
  23. package/dist/components/EmptyState.d.ts +2 -2
  24. package/dist/components/EmptyState.js +5 -2
  25. package/dist/components/Hydrated.d.ts +31 -0
  26. package/dist/components/Hydrated.js +30 -0
  27. package/dist/components/Icon.d.ts +17 -5
  28. package/dist/components/Icon.js +31 -10
  29. package/dist/components/InputOTP.js +7 -3
  30. package/dist/components/Item.d.ts +103 -4
  31. package/dist/components/Item.js +168 -15
  32. package/dist/components/KeyboardAvoidingView.d.ts +1 -1
  33. package/dist/components/KeyboardAvoidingView.js +4 -1
  34. package/dist/components/Label.js +3 -2
  35. package/dist/components/MaxWidthContainer.js +1 -1
  36. package/dist/components/Notification.js +45 -27
  37. package/dist/components/Popover.d.ts +18 -5
  38. package/dist/components/Popover.js +72 -8
  39. package/dist/components/Progress.js +8 -6
  40. package/dist/components/RadioGroup.js +52 -49
  41. package/dist/components/Screen.d.ts +61 -0
  42. package/dist/components/Screen.js +62 -0
  43. package/dist/components/SectionHeader.d.ts +1 -1
  44. package/dist/components/SegmentedControl.d.ts +12 -4
  45. package/dist/components/SegmentedControl.js +94 -4
  46. package/dist/components/Select.js +21 -26
  47. package/dist/components/Skeleton.js +24 -10
  48. package/dist/components/Slider.d.ts +11 -3
  49. package/dist/components/Slider.js +74 -6
  50. package/dist/components/StatCard.d.ts +4 -2
  51. package/dist/components/StatCard.js +3 -1
  52. package/dist/components/StyledText.d.ts +7 -1
  53. package/dist/components/StyledText.js +5 -3
  54. package/dist/components/Switch.d.ts +1 -1
  55. package/dist/components/Switch.js +23 -32
  56. package/dist/components/Tabs.d.ts +2 -2
  57. package/dist/components/Tabs.js +13 -24
  58. package/dist/components/TextInput.d.ts +1 -1
  59. package/dist/components/TextInput.js +73 -27
  60. package/dist/components/Toggle.d.ts +2 -42
  61. package/dist/components/Toggle.js +38 -27
  62. package/dist/components/ToggleGroup.d.ts +1 -1
  63. package/dist/components/ToggleGroup.js +37 -32
  64. package/dist/components/Tooltip.d.ts +1 -1
  65. package/dist/components/Tooltip.js +9 -3
  66. package/dist/components/UIProvider.d.ts +22 -2
  67. package/dist/components/UIProvider.js +15 -3
  68. package/dist/components/bottomSheetDismiss.d.ts +19 -0
  69. package/dist/components/bottomSheetDismiss.js +44 -0
  70. package/dist/components/bottomSheetHostSupport.d.ts +46 -0
  71. package/dist/components/bottomSheetHostSupport.js +67 -0
  72. package/dist/components/index.d.ts +46 -44
  73. package/dist/components/index.js +2 -0
  74. package/dist/components/keyboardDismiss.d.ts +25 -0
  75. package/dist/components/keyboardDismiss.js +60 -3
  76. package/dist/components/nativeTextField.android.js +13 -9
  77. package/dist/constants/colors.d.ts +40 -5
  78. package/dist/constants/colors.js +26 -8
  79. package/dist/constants/fonts.d.ts +41 -2
  80. package/dist/constants/fonts.js +46 -7
  81. package/dist/constants/index.d.ts +5 -4
  82. package/dist/constants/index.js +1 -0
  83. package/dist/constants/interaction.d.ts +18 -0
  84. package/dist/constants/interaction.js +18 -0
  85. package/dist/constants/spacing.d.ts +2 -1
  86. package/dist/constants/spacing.js +2 -1
  87. package/dist/design-system.json +154 -2
  88. package/dist/hooks/index.d.ts +12 -7
  89. package/dist/hooks/index.js +5 -0
  90. package/dist/hooks/useDimensions.d.ts +13 -8
  91. package/dist/hooks/useDimensions.js +123 -48
  92. package/dist/hooks/useFocusVisible.d.ts +30 -0
  93. package/dist/hooks/useFocusVisible.js +45 -0
  94. package/dist/hooks/useFontStyle.d.ts +2 -2
  95. package/dist/hooks/useFontStyle.js +3 -2
  96. package/dist/hooks/useHydrated.d.ts +13 -0
  97. package/dist/hooks/useHydrated.js +19 -0
  98. package/dist/hooks/useNotificationOffset.d.ts +20 -0
  99. package/dist/hooks/useNotificationOffset.js +34 -0
  100. package/dist/hooks/useResources.d.ts +21 -20
  101. package/dist/hooks/useResources.js +72 -68
  102. package/dist/hooks/useScalePress.d.ts +8 -5
  103. package/dist/hooks/useScalePress.js +16 -9
  104. package/dist/hooks/useShape.d.ts +24 -0
  105. package/dist/hooks/useShape.js +24 -0
  106. package/dist/hooks/useStaggeredEntrance.js +9 -7
  107. package/dist/hooks/useTheme.d.ts +3 -3
  108. package/dist/hooks/useTheme.js +177 -66
  109. package/dist/hooks/useWindowInsets.d.ts +13 -0
  110. package/dist/hooks/useWindowInsets.js +23 -0
  111. package/dist/index.d.ts +5 -5
  112. package/dist/lib/composeRefs.d.ts +8 -0
  113. package/dist/lib/composeRefs.js +20 -0
  114. package/dist/lib/haptics.d.ts +12 -0
  115. package/dist/lib/haptics.js +21 -0
  116. package/dist/lib/index.d.ts +6 -4
  117. package/dist/lib/index.js +2 -0
  118. package/dist/lib/interFonts.d.ts +15 -0
  119. package/dist/lib/interFonts.js +1 -0
  120. package/dist/lib/interFonts.native.d.ts +3 -0
  121. package/dist/lib/interFonts.native.js +20 -0
  122. package/dist/lib/popoverPlacement.d.ts +36 -0
  123. package/dist/lib/popoverPlacement.js +29 -0
  124. package/dist/lib/stateSurface.d.ts +28 -0
  125. package/dist/lib/stateSurface.js +30 -0
  126. package/dist/lib/themedStyles.d.ts +1 -1
  127. package/dist/lib/useAnimatedValue.d.ts +15 -0
  128. package/dist/lib/useAnimatedValue.js +19 -0
  129. package/dist/lib/webHitTarget.d.ts +40 -0
  130. package/dist/lib/webHitTarget.js +37 -0
  131. package/dist/state/feedbackStore.d.ts +24 -0
  132. package/dist/state/feedbackStore.js +16 -0
  133. package/dist/state/globalUIStore.d.ts +27 -0
  134. package/dist/state/globalUIStore.js +23 -0
  135. package/dist/state/index.d.ts +7 -5
  136. package/dist/state/index.js +2 -0
  137. package/dist/state/initialScheme.d.ts +27 -0
  138. package/dist/state/initialScheme.js +29 -0
  139. package/dist/state/notify.d.ts +1 -1
  140. package/dist/state/themeColorScope.d.ts +1 -1
  141. package/dist/state/themeStore.d.ts +69 -16
  142. package/dist/state/themeStore.js +65 -38
  143. package/llms-full.md +56 -8
  144. package/llms.txt +10 -1
  145. package/package.json +69 -2
package/llms-full.md CHANGED
@@ -90,6 +90,52 @@ When the saved theme preference is `system`, the package theme store owns OS
90
90
  color-scheme sync, including web `prefers-color-scheme`. Apps must not add their
91
91
  own `Appearance` or `matchMedia` listeners for package components.
92
92
 
93
+ ## Screen Layout
94
+
95
+ Screens are flat. On a 390 pt phone each nested inset comes out of the content:
96
+ rows boxed in a bordered group inside a padded screen start 33 pt from each edge
97
+ (16 + 1 + 16) with 324 pt left for them; the same rows in an `ItemGroup` start
98
+ 16 pt in with 358 pt.
99
+
100
+ - One horizontal inset per screen: `spacing.screenPadding` (16). Either a
101
+ container pads or its children do, never both. `Item` rows and `ItemGroup`
102
+ titles and footers carry the 16 themselves, so a scroll view of groups gets
103
+ no horizontal padding; text, forms, and buttons between them pad their own
104
+ wrapper.
105
+ - No boxes as layout: no bordered, shadowed, or tinted rounded panel (or `Card`)
106
+ around a section, a form, or a group of rows. Separate sections with a header,
107
+ `spacing.sectionSpacing` (24), or a hairline (`Separator`).
108
+ - Lists and settings are `ItemGroup` + `Item`: full-width rows and touch
109
+ targets, hairlines inset under the title, no card per row, no border around
110
+ the group. Rows are direct children; the group separates them.
111
+ - Forms: fields span the column, grouped under section headers, not cards.
112
+ - Primary content (photos, video, maps, QR codes, charts) sizes to the column
113
+ width, never a fixed size floating in whitespace.
114
+ - Wide screens cap and centre the column (`width: "100%", maxWidth: 640,
115
+ alignSelf: "center"` on the scroll content; 960 for dense grids) instead of
116
+ boxing it.
117
+ - `Card` is for one item in a collection (feed entry, grid tile, carousel slide)
118
+ or a single tappable object; `StatCard` likewise (a scrolling metrics rail, a
119
+ tappable metric). Never nest them.
120
+ - Dialog, sheet, and popover chrome keep their surfaces.
121
+
122
+ ```tsx
123
+ <ScrollView contentContainerStyle={{ width: "100%", maxWidth: 640, alignSelf: "center", paddingVertical: spacing.md, gap: spacing.sectionSpacing }}>
124
+ <ItemGroup title="Account" footer="Signed in as jane@example.com">
125
+ <Item onPress={openProfile}>
126
+ <ItemMedia icon="user" />
127
+ <ItemContent><ItemTitle>Edit profile</ItemTitle></ItemContent>
128
+ <ItemActions><Icon name="chevron-right" size={18} color="mutedForeground" /></ItemActions>
129
+ </Item>
130
+ <Item>
131
+ <ItemMedia icon="bell" />
132
+ <ItemContent><ItemTitle>Notifications</ItemTitle></ItemContent>
133
+ <ItemActions><Switch checked={enabled} onCheckedChange={setEnabled} /></ItemActions>
134
+ </Item>
135
+ </ItemGroup>
136
+ </ScrollView>
137
+ ```
138
+
93
139
  ## Component Catalog
94
140
 
95
141
  Every component is exported from `@mrmeg/expo-ui/components`, and from
@@ -105,7 +151,7 @@ before creating a new app-local primitive.
105
151
  | `Badge` | Short status labels | Prefer over custom pill views. |
106
152
  | `BottomSheet` | Mobile-first modal sheets | Requires root `UIProvider`. Native sheet via `@expo/ui`; `swipeEnabled`, `avoidKeyboard`, `dismissKeyboardOnDrag` are accepted but ignored (the iOS sheet presentation and Android Material3 keep content above the keyboard; never nest a `KeyboardAvoidingView` in a sheet). |
107
153
  | `Button` | Commands and CTAs | Use `preset`, not `variant`; heights are 28/32/40. |
108
- | `Card` | Individual framed content groups | Do not wrap whole page sections in cards. |
154
+ | `Card` | One item in a collection (feed entry, grid tile, carousel slide) or a single tappable object | Not a layout box: never around a section, form, or row group; never nested. Parts pad `spacing.cardPadding`. |
109
155
  | `Carousel` | Small known set of horizontally snapping slides | Renders every child (no virtualization); fractional `itemWidth` measures the viewport until first layout. |
110
156
  | `Checkbox` | Boolean selection in forms or lists | Prefer over custom checkmark controls. |
111
157
  | `Collapsible` | One-off disclosure | Use for advanced settings or helper sections. |
@@ -118,6 +164,7 @@ before creating a new app-local primitive.
118
164
  | `Icon` | Lucide or custom icons with theme tokens | `color` takes a theme color name; pass `decorative` to hide from a11y. |
119
165
  | `InputOTP` | Verification code entry | Prefer over manually managed text input groups. |
120
166
  | `Item` | List / settings rows | Applies the row density tokens and a 44px native hit area (40px on web). |
167
+ | `ItemGroup` | A titled group of full-width `Item` rows | Props: `title`, `description`, `footer`, `style`, `testID`. Draws inset hairlines between rows; no border, fill, or horizontal padding, so the parent must not pad either. |
121
168
  | `KeyboardAvoidingView` | Native keyboard-aware roots, composer footers, form-heavy subtrees | `UIProvider` already mounts one root; use directly only for custom subtrees. |
122
169
  | `Label` | Accessible form labels | Two distinct ids: `nativeID` is the label's, `htmlFor` is the input's `nativeID`. Never reuse one id for both. |
123
170
  | `MaxWidthContainer` | Centered responsive width | Use for web and tablet constrained layouts. |
@@ -131,7 +178,7 @@ before creating a new app-local primitive.
131
178
  | `Separator` | Horizontal or vertical dividers | Prefer over border-only spacer views. |
132
179
  | `Skeleton` | Loading placeholders | Use stable dimensions to avoid layout shift. |
133
180
  | `Slider` | Numeric value selection | Backed by `@expo/ui`; prefer over custom pan gesture tracks. |
134
- | `StatCard` | Metric tile | Props: `label`, `value`, `unit`, `change` (`{ value, direction }`), `icon`, `onPress`. |
181
+ | `StatCard` | Metric tile in a collection, or one tappable metric | Props: `label`, `value`, `unit`, `change` (`{ value, direction }`), `icon`, `onPress`. A Card, so the same rule applies. |
135
182
  | `StatusBar` | Theme-aware native status bar | Usually mounted through `UIProvider`. |
136
183
  | `StyledText` | Theme-aware typography | Prefer semantic aliases over raw `Text`. |
137
184
  | `Switch` | Binary settings | Prefer over custom toggles for on/off state. |
@@ -156,9 +203,10 @@ option sets.
156
203
  `Dialog` blocking decisions · `Popover` contextual controls · `Tooltip` short
157
204
  explanations · `DropdownMenu` action lists.
158
205
 
159
- `Card` individual repeated or framed items, never a wrapper around full page
160
- sections · `EmptyState` no-data or recoverable errors · `Skeleton` loading
161
- content with stable layout · `Progress` real or indeterminate progress.
206
+ `ItemGroup` + `Item` lists and settings · `Card` one item in a collection or one
207
+ tappable object, never a wrapper around a section, form, or row group, never
208
+ nested · `EmptyState` no-data or recoverable errors · `Skeleton` loading content
209
+ with stable layout · `Progress` real or indeterminate progress.
162
210
 
163
211
  ## Notifications
164
212
 
@@ -196,6 +244,6 @@ selectors and tests. Use `notify` for imperative triggers in app code.
196
244
  ## Validation
197
245
 
198
246
  Changing package code or shipped docs? Run the gates from the monorepo root:
199
- `ui:typecheck`, `ui:test`, `ui:build`, `ui:pack`, `ui:consumer-smoke`
200
- (`bun run <gate>`). Docs-only changes need at least `ui:pack`, which proves the
201
- new docs land in the npm tarball.
247
+ `typecheck`, `test`, `build`, `pack`, `consumer-smoke` (`bun run pkg ui <gate>`).
248
+ Docs-only changes need at least `bun run pkg ui pack`, which proves the new docs
249
+ land in the npm tarball.
package/llms.txt CHANGED
@@ -30,7 +30,16 @@ gestures and keyboard avoidance; swipeEnabled, avoidKeyboard, and
30
30
  dismissKeyboardOnDrag are accepted but ignored. On iOS the sheet presentation
31
31
  lifts or shrinks the hosted content so Footer and Body end at the keyboard's
32
32
  top (device-verified); Android avoidance is Material3's. Do not nest a
33
- KeyboardAvoidingView inside a sheet.
33
+ KeyboardAvoidingView inside a sheet. Open the next modal from the sheet's
34
+ onDismissed callback (fires once the sheet is fully gone), not from
35
+ onOpenChange(false).
36
+
37
+ Screens are flat: one 16 pt horizontal inset (spacing.screenPadding), either
38
+ on the container or on its children, never both. Lists and settings are
39
+ ItemGroup + Item (full-width rows, inset hairlines), never rows inside a
40
+ bordered, shadowed, or tinted panel. Card is for one item in a collection or one
41
+ tappable object; never nest Cards. Media and charts fill the column width; wide
42
+ screens cap and centre the column. LLM_USAGE.md "Screen Layout" has the rules.
34
43
 
35
44
  Use useTheme(), useStyles(), semantic tokens, StyledText, and package controls.
36
45
  Do not add app-local Appearance or matchMedia listeners for theme sync. On web
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrmeg/expo-ui",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "private": false,
5
5
  "description": "Reusable Expo and React Native UI primitives for MrMeg projects.",
6
6
  "keywords": [
@@ -29,6 +29,10 @@
29
29
  },
30
30
  "main": "./dist/index.js",
31
31
  "types": "./dist/index.d.ts",
32
+ "sideEffects": [
33
+ "./src/state/themeStore.ts",
34
+ "./dist/state/themeStore.js"
35
+ ],
32
36
  "files": [
33
37
  "dist",
34
38
  "package.json",
@@ -40,42 +44,105 @@
40
44
  ],
41
45
  "exports": {
42
46
  ".": {
47
+ "@mrmeg/source": "./src/index.ts",
43
48
  "types": "./dist/index.d.ts",
44
49
  "default": "./dist/index.js"
45
50
  },
46
51
  "./components": {
52
+ "@mrmeg/source": "./src/components/index.ts",
53
+ "types": "./dist/components/index.d.ts",
54
+ "default": "./dist/components/index.js"
55
+ },
56
+ "./components/bottomSheetDismiss": {
57
+ "@mrmeg/source": "./src/components/bottomSheetDismiss.ts",
58
+ "types": "./dist/components/bottomSheetDismiss.d.ts",
59
+ "default": "./dist/components/bottomSheetDismiss.js"
60
+ },
61
+ "./components/bottomSheetHostSupport": {
62
+ "@mrmeg/source": "./src/components/bottomSheetHostSupport.ts",
63
+ "types": "./dist/components/bottomSheetHostSupport.d.ts",
64
+ "default": "./dist/components/bottomSheetHostSupport.js"
65
+ },
66
+ "./components/iconRegistry.generated": {
67
+ "@mrmeg/source": "./src/components/iconRegistry.generated.ts",
68
+ "types": "./dist/components/iconRegistry.generated.d.ts",
69
+ "default": "./dist/components/iconRegistry.generated.js"
70
+ },
71
+ "./components/index": {
72
+ "@mrmeg/source": "./src/components/index.ts",
47
73
  "types": "./dist/components/index.d.ts",
48
74
  "default": "./dist/components/index.js"
49
75
  },
76
+ "./components/keyboardController": {
77
+ "@mrmeg/source": {
78
+ "react-native": "./src/components/keyboardController.native.ts",
79
+ "default": "./src/components/keyboardController.ts"
80
+ },
81
+ "types": "./dist/components/keyboardController.d.ts",
82
+ "default": "./dist/components/keyboardController.js"
83
+ },
84
+ "./components/keyboardDismiss": {
85
+ "@mrmeg/source": "./src/components/keyboardDismiss.ts",
86
+ "types": "./dist/components/keyboardDismiss.d.ts",
87
+ "default": "./dist/components/keyboardDismiss.js"
88
+ },
89
+ "./components/keyboardFocusRegistry": {
90
+ "@mrmeg/source": "./src/components/keyboardFocusRegistry.ts",
91
+ "types": "./dist/components/keyboardFocusRegistry.d.ts",
92
+ "default": "./dist/components/keyboardFocusRegistry.js"
93
+ },
94
+ "./components/StyledText.context": {
95
+ "@mrmeg/source": "./src/components/StyledText.context.ts",
96
+ "types": "./dist/components/StyledText.context.d.ts",
97
+ "default": "./dist/components/StyledText.context.js"
98
+ },
50
99
  "./components/*": {
100
+ "@mrmeg/source": "./src/components/*.tsx",
51
101
  "types": "./dist/components/*.d.ts",
52
102
  "default": "./dist/components/*.js"
53
103
  },
54
104
  "./constants": {
105
+ "@mrmeg/source": "./src/constants/index.ts",
55
106
  "types": "./dist/constants/index.d.ts",
56
107
  "default": "./dist/constants/index.js"
57
108
  },
58
109
  "./constants/*": {
110
+ "@mrmeg/source": "./src/constants/*.ts",
59
111
  "types": "./dist/constants/*.d.ts",
60
112
  "default": "./dist/constants/*.js"
61
113
  },
62
114
  "./hooks": {
115
+ "@mrmeg/source": "./src/hooks/index.ts",
63
116
  "types": "./dist/hooks/index.d.ts",
64
117
  "default": "./dist/hooks/index.js"
65
118
  },
119
+ "./hooks/useReduceMotion": {
120
+ "@mrmeg/source": "./src/hooks/useReduceMotion.tsx",
121
+ "types": "./dist/hooks/useReduceMotion.d.ts",
122
+ "default": "./dist/hooks/useReduceMotion.js"
123
+ },
66
124
  "./hooks/*": {
125
+ "@mrmeg/source": "./src/hooks/*.ts",
67
126
  "types": "./dist/hooks/*.d.ts",
68
127
  "default": "./dist/hooks/*.js"
69
128
  },
70
129
  "./state": {
130
+ "@mrmeg/source": "./src/state/index.ts",
71
131
  "types": "./dist/state/index.d.ts",
72
132
  "default": "./dist/state/index.js"
73
133
  },
134
+ "./state/themeColorScope": {
135
+ "@mrmeg/source": "./src/state/themeColorScope.tsx",
136
+ "types": "./dist/state/themeColorScope.d.ts",
137
+ "default": "./dist/state/themeColorScope.js"
138
+ },
74
139
  "./state/*": {
140
+ "@mrmeg/source": "./src/state/*.ts",
75
141
  "types": "./dist/state/*.d.ts",
76
142
  "default": "./dist/state/*.js"
77
143
  },
78
144
  "./lib": {
145
+ "@mrmeg/source": "./src/lib/index.ts",
79
146
  "types": "./dist/lib/index.d.ts",
80
147
  "default": "./dist/lib/index.js"
81
148
  },
@@ -129,7 +196,7 @@
129
196
  "zustand": ">=5.0.0 <6.0.0"
130
197
  },
131
198
  "devDependencies": {
132
- "@types/react": "~19.2.18",
199
+ "@types/react": "~19.3.0",
133
200
  "typescript": "~6.0.3"
134
201
  }
135
202
  }