@mrmeg/expo-ui 0.1.10 → 0.2.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.
- package/LICENSE +21 -0
- package/LLM_USAGE.md +6 -1
- package/README.md +7 -4
- package/dist/components/BottomSheet.d.ts +5 -1
- package/dist/components/BottomSheet.js +30 -12
- package/dist/components/Button.js +1 -1
- package/dist/components/Switch.js +1 -1
- package/dist/hooks/useScalePress.d.ts +2 -2
- package/dist/hooks/useStaggeredEntrance.d.ts +2 -2
- package/llms-full.md +6 -1
- package/llms.txt +2 -0
- package/package.json +4 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matt Megenhardt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/LLM_USAGE.md
CHANGED
|
@@ -68,6 +68,11 @@ export function RootLayout() {
|
|
|
68
68
|
`AlertDialog`, `BottomSheet`, `Drawer`, `DropdownMenu`, `Popover`,
|
|
69
69
|
`SelectContent`, or `Tooltip`.
|
|
70
70
|
|
|
71
|
+
On native, `BottomSheet.Content` avoids the soft keyboard by default through
|
|
72
|
+
`react-native-keyboard-controller`. Mount that library's `KeyboardProvider`
|
|
73
|
+
near the app root before using bottom sheets with text inputs, or pass
|
|
74
|
+
`avoidKeyboard={false}` to opt out for a specific sheet.
|
|
75
|
+
|
|
71
76
|
i18n is optional. Do not add app-level i18n setup just to use this package.
|
|
72
77
|
Plain children and `text` props work without `i18next` or `react-i18next`.
|
|
73
78
|
`tx` props render fallback text when provided and otherwise render the key
|
|
@@ -154,7 +159,7 @@ Use this table before creating a new app-local primitive.
|
|
|
154
159
|
| `Alert` | Cross-platform imperative alerts | Direct `window.alert` or duplicated RN/web branching | Confirm destructive actions, native alert dialogs |
|
|
155
160
|
| `AnimatedView` | Entrance and visibility animation | Hand-rolled Reanimated wrappers | Staggered list rows, revealed panels, animated empty states |
|
|
156
161
|
| `Badge` | Short status labels | Custom pill `View` + `Text` | Draft/active states, counts, plan labels, role tags |
|
|
157
|
-
| `BottomSheet` | Mobile-first modal sheets | Custom absolute-position sheets | Action pickers, mobile filters, quick edit forms |
|
|
162
|
+
| `BottomSheet` | Mobile-first modal sheets | Custom absolute-position sheets | Action pickers, mobile filters, keyboard-aware quick edit forms |
|
|
158
163
|
| `Button` | Commands and CTAs | Pressable plus custom text styling | Submit, save, cancel, delete, navigation CTAs |
|
|
159
164
|
| `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter` | Framed content groups | Ad hoc bordered panels | List items, pricing plans, settings sections, summaries |
|
|
160
165
|
| `Checkbox` | Boolean selection | Custom checkmark controls | Terms consent, checklist items, multi-select filters |
|
package/README.md
CHANGED
|
@@ -31,8 +31,11 @@ Consumers must also install the native and Expo peer dependencies listed in
|
|
|
31
31
|
`package.json`. The tested baseline is Expo SDK 55 with React 19.2, React
|
|
32
32
|
Native 0.83, React Native Web 0.21, Reanimated 4.2, and Worklets 0.7.
|
|
33
33
|
`@rn-primitives/*` packages are managed by `@mrmeg/expo-ui` because they are
|
|
34
|
-
implementation details of the exported UI components.
|
|
35
|
-
|
|
34
|
+
implementation details of the exported UI components. Native bottom sheet
|
|
35
|
+
keyboard avoidance uses `react-native-keyboard-controller`; mount that
|
|
36
|
+
library's `KeyboardProvider` near the app root when sheets contain text
|
|
37
|
+
inputs. i18n setup is optional; plain text and children render without
|
|
38
|
+
`i18next` or `react-i18next`. Start
|
|
36
39
|
consumer apps from the same Expo SDK family or update the package and peer
|
|
37
40
|
ranges deliberately. Keep npm auth tokens in developer or CI configuration,
|
|
38
41
|
not in this repository.
|
|
@@ -165,7 +168,7 @@ All components are exported from `@mrmeg/expo-ui/components`; direct imports suc
|
|
|
165
168
|
| `Alert` | Cross-platform imperative alerts | Direct `window.alert` or duplicated RN/web branching | Confirm destructive actions, native alert dialogs, simple blocking messages |
|
|
166
169
|
| `AnimatedView` | Entrance and visibility animation | Hand-rolled Reanimated wrappers | Staggered list rows, revealed panels, animated empty states |
|
|
167
170
|
| `Badge` | Short status labels | Custom pill `View` + `Text` | Draft/active states, counts, plan labels, role tags |
|
|
168
|
-
| `BottomSheet` | Mobile-first modal sheets | Custom absolute-position sheets | Action pickers, mobile filters, quick edit forms, contextual details |
|
|
171
|
+
| `BottomSheet` | Mobile-first modal sheets | Custom absolute-position sheets | Action pickers, mobile filters, keyboard-aware quick edit forms, contextual details |
|
|
169
172
|
| `Button` | Commands and CTAs | Pressable plus custom text styling | Submit, save, cancel, delete, navigation CTAs, icon-accessory buttons; loading state preserves resting width |
|
|
170
173
|
| `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter` | Framed content groups | Ad hoc bordered panels | List items, pricing plans, settings sections, summaries, dashboards |
|
|
171
174
|
| `Checkbox` | Boolean selection | Custom checkmark controls | Terms consent, checklist items, multi-select filters, notification opt-ins |
|
|
@@ -228,7 +231,7 @@ Use `Button.preset`, not `variant`. `default` is the neutral primary action, `se
|
|
|
228
231
|
|
|
229
232
|
Use `StyledText` or its aliases instead of raw `Text` whenever the text is part of app UI. Use `TextInput` for labeled fields because it already owns label, helper text, error text, clear buttons, password visibility, numeric filtering, and left/right elements.
|
|
230
233
|
|
|
231
|
-
Mount `UIProvider` once near the root before using `Dialog`, `AlertDialog`, `BottomSheet`, `Drawer`, `DropdownMenu`, `Popover`, `SelectContent`, `Tooltip`, or package notifications. Trigger transient feedback from `globalUIStore`.
|
|
234
|
+
Mount `UIProvider` once near the root before using `Dialog`, `AlertDialog`, `BottomSheet`, `Drawer`, `DropdownMenu`, `Popover`, `SelectContent`, `Tooltip`, or package notifications. On native, mount `KeyboardProvider` from `react-native-keyboard-controller` near the root before using `BottomSheet.Content` with text inputs; `avoidKeyboard` defaults to `true` and can be disabled per sheet. Trigger transient feedback from `globalUIStore`.
|
|
232
235
|
|
|
233
236
|
Use `Skeleton` components for loading content with stable dimensions, `EmptyState` for no-data/recoverable errors, `Alert` for blocking confirm/alert dialogs, and `Notification` for transient global feedback.
|
|
234
237
|
|
|
@@ -32,6 +32,10 @@ interface BottomSheetContentProps extends ViewProps {
|
|
|
32
32
|
swipeEnabled?: boolean;
|
|
33
33
|
/** Velocity threshold for quick swipe to close */
|
|
34
34
|
velocityThreshold?: number;
|
|
35
|
+
/** Whether to move the sheet with the native keyboard animation. Default: true. */
|
|
36
|
+
avoidKeyboard?: boolean;
|
|
37
|
+
/** Whether to dismiss the keyboard when a native drag starts. Default: true. */
|
|
38
|
+
dismissKeyboardOnDrag?: boolean;
|
|
35
39
|
style?: StyleProp<ViewStyle>;
|
|
36
40
|
children: React.ReactNode;
|
|
37
41
|
}
|
|
@@ -55,7 +59,7 @@ interface BottomSheetCloseProps {
|
|
|
55
59
|
declare function useBottomSheetContext(): BottomSheetContextValue;
|
|
56
60
|
declare function BottomSheetRoot({ open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen, snapPoints: rawSnapPoints, closeOnBackdropPress, children, }: BottomSheetProps): import("react/jsx-runtime").JSX.Element;
|
|
57
61
|
declare function BottomSheetTrigger({ asChild, children, style: styleOverride }: BottomSheetTriggerProps): import("react/jsx-runtime").JSX.Element;
|
|
58
|
-
declare function BottomSheetContent({ swipeEnabled, velocityThreshold, style: styleOverride, children, ...props }: BottomSheetContentProps): import("react/jsx-runtime").JSX.Element | null;
|
|
62
|
+
declare function BottomSheetContent({ swipeEnabled, velocityThreshold, avoidKeyboard, dismissKeyboardOnDrag, style: styleOverride, children, ...props }: BottomSheetContentProps): import("react/jsx-runtime").JSX.Element | null;
|
|
59
63
|
declare function BottomSheetHandle({ style }: BottomSheetHandleProps): import("react/jsx-runtime").JSX.Element;
|
|
60
64
|
declare function BottomSheetHeader({ children, style, ...props }: BottomSheetHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
61
65
|
declare function BottomSheetBody({ children, style, ...props }: BottomSheetBodyProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { createContext, useCallback, useContext, useEffect, useReducer, useRef, useState } from "react";
|
|
2
|
+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from "react";
|
|
3
3
|
import { View, Pressable, Animated, StyleSheet, Platform, Dimensions, PanResponder, ScrollView, } from "react-native";
|
|
4
4
|
import { Portal } from "@rn-primitives/portal";
|
|
5
5
|
import { FullWindowOverlay as RNFullWindowOverlay } from "react-native-screens";
|
|
6
6
|
import { Pressable as SlotPressable } from "@rn-primitives/slot";
|
|
7
|
+
import { KeyboardController, useKeyboardAnimation } from "react-native-keyboard-controller";
|
|
7
8
|
import { useTheme } from "../hooks/useTheme.js";
|
|
8
9
|
import { spacing } from "../constants/spacing.js";
|
|
9
10
|
import { shouldUseNativeDriver } from "../lib/animations.js";
|
|
@@ -50,6 +51,20 @@ function useBottomSheetContext() {
|
|
|
50
51
|
return context;
|
|
51
52
|
}
|
|
52
53
|
const DragContext = createContext(null);
|
|
54
|
+
function BottomSheetPanel({ accessibilityViewIsModal, children, panHandlers, sheetStyle, styleOverride, translateY, ...props }) {
|
|
55
|
+
return (_jsx(Animated.View, { style: [
|
|
56
|
+
sheetStyle,
|
|
57
|
+
{ transform: [{ translateY }] },
|
|
58
|
+
styleOverride && typeof styleOverride !== "function"
|
|
59
|
+
? StyleSheet.flatten(styleOverride)
|
|
60
|
+
: undefined,
|
|
61
|
+
], accessibilityViewIsModal: accessibilityViewIsModal, ...panHandlers, ...props, children: children }));
|
|
62
|
+
}
|
|
63
|
+
function KeyboardAvoidingBottomSheetPanel(props) {
|
|
64
|
+
const { height: keyboardHeight } = useKeyboardAnimation();
|
|
65
|
+
const composedTranslateY = useMemo(() => Animated.add(props.translateY, keyboardHeight), [keyboardHeight, props.translateY]);
|
|
66
|
+
return _jsx(BottomSheetPanel, { ...props, translateY: composedTranslateY });
|
|
67
|
+
}
|
|
53
68
|
// ============================================================================
|
|
54
69
|
// Utility Functions
|
|
55
70
|
// ============================================================================
|
|
@@ -126,7 +141,7 @@ function BottomSheetTrigger({ asChild, children, style: styleOverride }) {
|
|
|
126
141
|
// ============================================================================
|
|
127
142
|
// Content
|
|
128
143
|
// ============================================================================
|
|
129
|
-
function BottomSheetContent({ swipeEnabled = true, velocityThreshold = 500, style: styleOverride, children, ...props }) {
|
|
144
|
+
function BottomSheetContent({ swipeEnabled = true, velocityThreshold = 500, avoidKeyboard = true, dismissKeyboardOnDrag = true, style: styleOverride, children, ...props }) {
|
|
130
145
|
const sheetContext = useBottomSheetContext();
|
|
131
146
|
const { open, onOpenChange, snapPoints, closeOnBackdropPress } = sheetContext;
|
|
132
147
|
const { theme } = useTheme();
|
|
@@ -224,6 +239,11 @@ function BottomSheetContent({ swipeEnabled = true, velocityThreshold = 500, styl
|
|
|
224
239
|
const progress = 1 - dragFromBase / currentHeightRef.current;
|
|
225
240
|
backdropOpacity.setValue(Math.max(0, progress));
|
|
226
241
|
}, [translateY, backdropOpacity, maxHeight]);
|
|
242
|
+
const dismissKeyboardForDrag = useCallback(() => {
|
|
243
|
+
if (Platform.OS !== "web" && dismissKeyboardOnDrag) {
|
|
244
|
+
void KeyboardController.dismiss();
|
|
245
|
+
}
|
|
246
|
+
}, [dismissKeyboardOnDrag]);
|
|
227
247
|
// ------------------------------------------------------------------
|
|
228
248
|
// Trigger animation during render if open changed
|
|
229
249
|
// ------------------------------------------------------------------
|
|
@@ -287,7 +307,7 @@ function BottomSheetContent({ swipeEnabled = true, velocityThreshold = 500, styl
|
|
|
287
307
|
// ------------------------------------------------------------------
|
|
288
308
|
// Native: PanResponder for swipe gestures on the whole sheet
|
|
289
309
|
// ------------------------------------------------------------------
|
|
290
|
-
const panResponder =
|
|
310
|
+
const panResponder = useMemo(() => Platform.OS !== "web" && swipeEnabled
|
|
291
311
|
? PanResponder.create({
|
|
292
312
|
onStartShouldSetPanResponder: () => false,
|
|
293
313
|
onMoveShouldSetPanResponder: (_evt, gestureState) => {
|
|
@@ -296,6 +316,7 @@ function BottomSheetContent({ swipeEnabled = true, velocityThreshold = 500, styl
|
|
|
296
316
|
const isDownward = gestureState.dy > 0;
|
|
297
317
|
return isVertical && isSignificant && isDownward;
|
|
298
318
|
},
|
|
319
|
+
onPanResponderGrant: dismissKeyboardForDrag,
|
|
299
320
|
onPanResponderMove: (_evt, gestureState) => {
|
|
300
321
|
handleDragMove(gestureState.dy);
|
|
301
322
|
},
|
|
@@ -303,7 +324,7 @@ function BottomSheetContent({ swipeEnabled = true, velocityThreshold = 500, styl
|
|
|
303
324
|
handleDragRelease(Math.max(0, gestureState.dy), gestureState.vy);
|
|
304
325
|
},
|
|
305
326
|
})
|
|
306
|
-
: null)
|
|
327
|
+
: null, [dismissKeyboardForDrag, handleDragMove, handleDragRelease, swipeEnabled]);
|
|
307
328
|
// ------------------------------------------------------------------
|
|
308
329
|
// Web: drag context provides callbacks for Handle's pointer events
|
|
309
330
|
// ------------------------------------------------------------------
|
|
@@ -339,6 +360,9 @@ function BottomSheetContent({ swipeEnabled = true, velocityThreshold = 500, styl
|
|
|
339
360
|
...(Platform.OS === "web" && { zIndex: 51 }),
|
|
340
361
|
};
|
|
341
362
|
const sheetContent = (_jsx(TextColorContext.Provider, { value: textColor, children: _jsx(TextClassContext.Provider, { value: "", children: children }) }));
|
|
363
|
+
const PanelComponent = Platform.OS !== "web" && avoidKeyboard
|
|
364
|
+
? KeyboardAvoidingBottomSheetPanel
|
|
365
|
+
: BottomSheetPanel;
|
|
342
366
|
const contentElement = (_jsx(Portal, { name: "bottom-sheet-portal", children: _jsx(FullWindowOverlay, { children: _jsx(BottomSheetContext.Provider, { value: sheetContext, children: _jsxs(View, { style: StyleSheet.absoluteFill, children: [_jsx(Animated.View, { style: [
|
|
343
367
|
StyleSheet.absoluteFill,
|
|
344
368
|
{
|
|
@@ -346,16 +370,10 @@ function BottomSheetContent({ swipeEnabled = true, velocityThreshold = 500, styl
|
|
|
346
370
|
opacity: backdropOpacity,
|
|
347
371
|
},
|
|
348
372
|
Platform.OS === "web" && { zIndex: 50 },
|
|
349
|
-
], children: _jsx(Pressable, { style: StyleSheet.absoluteFill, onPress: handleBackdropPress }) }), _jsx(
|
|
350
|
-
sheetStyle,
|
|
351
|
-
{ transform: [{ translateY }] },
|
|
352
|
-
styleOverride && typeof styleOverride !== "function"
|
|
353
|
-
? StyleSheet.flatten(styleOverride)
|
|
354
|
-
: undefined,
|
|
355
|
-
], accessibilityViewIsModal: true, ...(Platform.OS === "web" && {
|
|
373
|
+
], children: _jsx(Pressable, { style: StyleSheet.absoluteFill, onPress: handleBackdropPress }) }), _jsx(PanelComponent, { sheetStyle: sheetStyle, styleOverride: styleOverride, translateY: translateY, accessibilityViewIsModal: true, ...(Platform.OS === "web" && {
|
|
356
374
|
role: "dialog",
|
|
357
375
|
"aria-modal": true,
|
|
358
|
-
}),
|
|
376
|
+
}), panHandlers: panResponder ? panResponder.panHandlers : undefined, ...props, children: dragContextValue ? (_jsx(DragContext.Provider, { value: dragContextValue, children: sheetContent })) : (sheetContent) })] }) }) }) }));
|
|
359
377
|
return contentElement;
|
|
360
378
|
}
|
|
361
379
|
// ============================================================================
|
|
@@ -77,7 +77,7 @@ function Switch({ variant = "default", labelOn, labelOff, size = { width: 44, he
|
|
|
77
77
|
disabled: !!props.disabled,
|
|
78
78
|
busy: loading,
|
|
79
79
|
}, children: [_jsx(View, { style: {
|
|
80
|
-
...StyleSheet.
|
|
80
|
+
...StyleSheet.absoluteFill,
|
|
81
81
|
borderRadius: size.height / 2,
|
|
82
82
|
backgroundColor: trackBg,
|
|
83
83
|
borderWidth: 1,
|
|
@@ -43,11 +43,11 @@ interface ScalePressOptions {
|
|
|
43
43
|
* ```
|
|
44
44
|
*/
|
|
45
45
|
export declare function useScalePress(options?: ScalePressOptions): {
|
|
46
|
-
animatedStyle: {
|
|
46
|
+
animatedStyle: import("react-native-reanimated/lib/typescript/hook/commonTypes").AnimatedStyleHandle<{
|
|
47
47
|
transform: {
|
|
48
48
|
scale: number;
|
|
49
49
|
}[];
|
|
50
|
-
}
|
|
50
|
+
}>;
|
|
51
51
|
pressHandlers: {
|
|
52
52
|
onPressIn: () => void;
|
|
53
53
|
onPressOut: () => void;
|
|
@@ -46,7 +46,7 @@ interface StaggeredEntranceOptions {
|
|
|
46
46
|
* })}
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
|
-
export declare function useStaggeredEntrance(options?: StaggeredEntranceOptions): {
|
|
49
|
+
export declare function useStaggeredEntrance(options?: StaggeredEntranceOptions): import("react-native-reanimated/lib/typescript/hook/commonTypes").AnimatedStyleHandle<{
|
|
50
50
|
opacity: number;
|
|
51
51
|
transform?: undefined;
|
|
52
52
|
} | {
|
|
@@ -59,7 +59,7 @@ export declare function useStaggeredEntrance(options?: StaggeredEntranceOptions)
|
|
|
59
59
|
transform: {
|
|
60
60
|
scale: number;
|
|
61
61
|
}[];
|
|
62
|
-
}
|
|
62
|
+
}>;
|
|
63
63
|
/**
|
|
64
64
|
* Convenience constant: default stagger delay between items (ms)
|
|
65
65
|
*/
|
package/llms-full.md
CHANGED
|
@@ -36,6 +36,11 @@ the root when the app uses package feedback or overlay components.
|
|
|
36
36
|
`BottomSheet`, `Drawer`, `DropdownMenu`, `Popover`, `SelectContent`,
|
|
37
37
|
`Tooltip`, or `globalUIStore` notifications.
|
|
38
38
|
|
|
39
|
+
On native, `BottomSheet.Content` composes its sheet transform with
|
|
40
|
+
`react-native-keyboard-controller` keyboard animation values. Mount that
|
|
41
|
+
library's `KeyboardProvider` near the app root before using bottom sheets with
|
|
42
|
+
text inputs, or pass `avoidKeyboard={false}` for sheets that should not move.
|
|
43
|
+
|
|
39
44
|
i18n is optional. Plain children and `text` props work without `i18next` or
|
|
40
45
|
`react-i18next`. Use `configureExpoUiI18n()` only when a consuming app wants
|
|
41
46
|
package `tx` props translated by its app-owned i18n instance.
|
|
@@ -82,7 +87,7 @@ Use this catalog before creating a new app-local primitive.
|
|
|
82
87
|
| `Alert` | `@mrmeg/expo-ui/components` | Cross-platform imperative alerts | Avoid direct `window.alert` and duplicated native/web branching. |
|
|
83
88
|
| `AnimatedView` | `@mrmeg/expo-ui/components` | Entrance and visibility animation | Keep simple reveal effects in the package wrapper. |
|
|
84
89
|
| `Badge` | `@mrmeg/expo-ui/components` | Short status labels | Prefer over custom pill views. |
|
|
85
|
-
| `BottomSheet` | `@mrmeg/expo-ui/components` | Mobile-first modal sheets | Requires root `UIProvider
|
|
90
|
+
| `BottomSheet` | `@mrmeg/expo-ui/components` | Mobile-first modal sheets | Requires root `UIProvider`; native text-input sheets also require `KeyboardProvider`. |
|
|
86
91
|
| `Button` | `@mrmeg/expo-ui/components` | Commands and CTAs | Use `preset`, not `variant`; visible heights are compact. |
|
|
87
92
|
| `Card` | `@mrmeg/expo-ui/components` | Individual framed content groups | Do not wrap whole page sections in cards. |
|
|
88
93
|
| `Checkbox` | `@mrmeg/expo-ui/components` | Boolean selection in forms or lists | Prefer over custom checkmark controls. |
|
package/llms.txt
CHANGED
|
@@ -25,6 +25,8 @@ Call useResources() once near the Expo app root. Mount UIProvider once near the
|
|
|
25
25
|
root before using package notifications or overlay primitives: Dialog,
|
|
26
26
|
AlertDialog, BottomSheet, Drawer, DropdownMenu, Popover, SelectContent, or
|
|
27
27
|
Tooltip.
|
|
28
|
+
On native, mount react-native-keyboard-controller's KeyboardProvider before
|
|
29
|
+
using BottomSheet.Content with text inputs; avoidKeyboard defaults to true.
|
|
28
30
|
|
|
29
31
|
Use useTheme(), useStyles(), semantic tokens, StyledText, and package controls.
|
|
30
32
|
Do not add app-local Appearance or matchMedia listeners for package theme sync.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrmeg/expo-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Reusable Expo and React Native UI primitives for MrMeg projects.",
|
|
6
6
|
"keywords": [
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"universal-ui"
|
|
13
13
|
],
|
|
14
14
|
"author": "Matt Megenhardt",
|
|
15
|
-
"license": "
|
|
15
|
+
"license": "MIT",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "git+https://github.com/mrmeg/expo-template.git",
|
|
@@ -109,6 +109,7 @@
|
|
|
109
109
|
"react": ">=19.2.0 <20.0.0",
|
|
110
110
|
"react-native": ">=0.83.0 <0.84.0",
|
|
111
111
|
"react-native-gesture-handler": "~2.30.0",
|
|
112
|
+
"react-native-keyboard-controller": ">=1.20.0 <2.0.0",
|
|
112
113
|
"react-native-reanimated": "~4.2.0",
|
|
113
114
|
"react-native-safe-area-context": "~5.6.0",
|
|
114
115
|
"react-native-screens": "~4.23.0",
|
|
@@ -118,6 +119,6 @@
|
|
|
118
119
|
},
|
|
119
120
|
"devDependencies": {
|
|
120
121
|
"@types/react": "~19.2.14",
|
|
121
|
-
"typescript": "~
|
|
122
|
+
"typescript": "~6.0.3"
|
|
122
123
|
}
|
|
123
124
|
}
|