@mrmeg/expo-ui 0.12.1 → 0.13.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/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to `@mrmeg/expo-ui` are documented here. This project
4
4
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
5
 
6
+ ## [0.13.0]
7
+
8
+ ### Added
9
+
10
+ - **`Drawer.Header` now supports a compact app-brand layout.** Use the new
11
+ `icon`, `title`, and `action` slots for a leading brand icon and title with a
12
+ trailing close or `Drawer.ToggleCollapse` control. Existing child-based
13
+ headers remain supported.
14
+
15
+ ### Changed
16
+
17
+ - Expanded peer compatibility through Expo 57, React Native 0.86, and their
18
+ matching `@expo/ui` and gesture-handler releases.
19
+
6
20
  ## [0.12.1]
7
21
 
8
22
  ### Fixed
package/LLM_USAGE.md CHANGED
@@ -212,6 +212,7 @@ Use this table before creating a new app-local primitive.
212
212
  - Use `EmptyState` for no-data or recoverable error regions.
213
213
  - Use `Skeleton` for loading content with stable layout.
214
214
  - Use `Progress` for real progress or indeterminate long-running work.
215
+ - Use `Drawer.Header` with `icon`, `title`, and `action` for a compact app-brand row; place `Drawer.ToggleCollapse` in `action` for a trailing rail control.
215
216
 
216
217
  ## Minimal Examples
217
218
 
@@ -249,6 +250,20 @@ import { Button, Switch, TextInput } from "@mrmeg/expo-ui/components";
249
250
  </Button>
250
251
  ```
251
252
 
253
+ ```tsx
254
+ import { Drawer, Icon } from "@mrmeg/expo-ui/components";
255
+
256
+ <Drawer.Header
257
+ icon={<Icon name="hexagon" color="accent" />}
258
+ title="Acme"
259
+ action={
260
+ <Drawer.ToggleCollapse>
261
+ <Icon name="sidebar" decorative />
262
+ </Drawer.ToggleCollapse>
263
+ }
264
+ />
265
+ ```
266
+
252
267
  ```tsx
253
268
  import { EmptyState, Progress, SkeletonCard } from "@mrmeg/expo-ui/components";
254
269
  import { notify } from "@mrmeg/expo-ui/state";
package/README.md CHANGED
@@ -254,7 +254,7 @@ Most compound components support both direct named imports and dot notation on t
254
254
  | `Card` | `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter` |
255
255
  | `Collapsible` | `CollapsibleTrigger`, `CollapsibleContent` |
256
256
  | `Dialog` | `DialogTrigger`, `DialogContent`, `DialogHeader`, `DialogFooter`, `DialogTitle`, `DialogDescription`, `DialogClose` |
257
- | `Drawer` | `DrawerTrigger`, `DrawerContent`, `DrawerHeader`, `DrawerBody`, `DrawerFooter`, `DrawerClose` |
257
+ | `Drawer` | `DrawerTrigger`, `DrawerContent`, `DrawerHeader`, `DrawerBody`, `DrawerFooter`, `DrawerClose`, `DrawerToggleCollapse` |
258
258
  | `DropdownMenu` | `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuGroup`, `DropdownMenuItem`, `DropdownMenuCheckboxItem`, `DropdownMenuRadioGroup`, `DropdownMenuRadioItem`, `DropdownMenuLabel`, `DropdownMenuSeparator`, `DropdownMenuShortcut`, `DropdownMenuPortal`, `DropdownMenuSub`, `DropdownMenuSubTrigger`, `DropdownMenuSubContent` |
259
259
  | `Popover` | `PopoverTrigger`, `PopoverContent`, `PopoverHeader`, `PopoverBody`, `PopoverFooter` |
260
260
  | `RadioGroup` | `RadioGroupItem` |
@@ -273,6 +273,20 @@ Use `Button.preset`, not `variant`. `default` is the neutral primary action, `se
273
273
 
274
274
  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.
275
275
 
276
+ `Drawer.Header` accepts `icon`, `title`, and `action` slots for a compact app-brand row. Pass a string title to use the package typography, and place `Drawer.ToggleCollapse` in `action` for a trailing rail control:
277
+
278
+ ```tsx
279
+ <Drawer.Header
280
+ icon={<Icon name="hexagon" color="accent" />}
281
+ title="Acme"
282
+ action={
283
+ <Drawer.ToggleCollapse>
284
+ <Icon name="sidebar" decorative />
285
+ </Drawer.ToggleCollapse>
286
+ }
287
+ />
288
+ ```
289
+
276
290
  Mount `UIProvider` once near the root before using `Dialog`, `AlertDialog`, `BottomSheet`, `Drawer`, `DropdownMenu`, `Popover`, `SelectContent`, `Tooltip`, or package notifications. On native, `UIProvider` also wraps app content in the package keyboard-avoiding root by default, so ordinary screens and fixed footers stay above the soft keyboard without repeated app-local wrappers; pass `keyboardAvoiding={false}` to opt out, or use `KeyboardAvoidingView` directly for a subtree with custom behavior. Web skips the root keyboard wrapper unless `keyboardAvoiding` is explicitly enabled. `BottomSheet.Content` listens to React Native keyboard events when `avoidKeyboard` is enabled; it defaults to `true` and can be disabled per sheet. Trigger transient feedback with `notify`.
277
291
 
278
292
  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.
@@ -65,7 +65,14 @@ interface DrawerContentProps extends ViewProps {
65
65
  children: React.ReactNode;
66
66
  }
67
67
  interface DrawerHeaderProps extends ViewProps {
68
- children: React.ReactNode;
68
+ /** Custom header content. Used when the structured slots are omitted. */
69
+ children?: React.ReactNode;
70
+ /** Brand or app icon shown before the title. */
71
+ icon?: React.ReactNode;
72
+ /** Header title. Strings receive the package's default drawer title style. */
73
+ title?: React.ReactNode;
74
+ /** Trailing control, such as a close or rail-collapse button. */
75
+ action?: React.ReactNode;
69
76
  }
70
77
  interface DrawerBodyProps extends ViewProps {
71
78
  children: React.ReactNode;
@@ -95,7 +102,7 @@ declare function DrawerToggleCollapse({ asChild, children, style: styleOverride
95
102
  * so their hooks never run conditionally.
96
103
  */
97
104
  declare function DrawerContent(props: DrawerContentProps): React.JSX.Element;
98
- declare function DrawerHeader({ children, style, ...props }: DrawerHeaderProps): React.JSX.Element;
105
+ declare function DrawerHeader({ children, icon, title, action, style, ...props }: DrawerHeaderProps): React.JSX.Element;
99
106
  declare function DrawerBody({ children, style, ...props }: DrawerBodyProps): React.JSX.Element;
100
107
  declare function DrawerFooter({ children, style, ...props }: DrawerFooterProps): React.JSX.Element;
101
108
  declare function useDrawerClose(): () => void;
@@ -10,6 +10,7 @@ import { shouldUseNativeDriver } from "../lib/animations.js";
10
10
  import { spacing } from "../constants/spacing.js";
11
11
  import { TextColorContext, TextClassContext } from "./StyledText.context";
12
12
  import { useSafeAreaInsets } from "react-native-safe-area-context";
13
+ import { SansSerifBoldText } from "./StyledText.js";
13
14
  /**
14
15
  * Drawer Component with Sub-components
15
16
  *
@@ -536,8 +537,11 @@ swipeEnabled: _swipeEnabled, swipeThreshold: _swipeThreshold, velocityThreshold:
536
537
  // ============================================================================
537
538
  // Drawer Header Component
538
539
  // ============================================================================
539
- function DrawerHeader({ children, style, ...props }) {
540
+ function DrawerHeader({ children, icon, title, action, style, ...props }) {
540
541
  const { theme } = useTheme();
542
+ const { variant, expandedWidth } = useDrawerContext();
543
+ const usesStructuredLayout = icon !== undefined || title !== undefined || action !== undefined;
544
+ const structuredRowWidth = variant === "rail" ? Math.max(0, expandedWidth - spacing.md * 2) : undefined;
541
545
  return (_jsx(View, { style: [
542
546
  {
543
547
  paddingHorizontal: spacing.md,
@@ -545,8 +549,30 @@ function DrawerHeader({ children, style, ...props }) {
545
549
  borderBottomWidth: 1,
546
550
  borderBottomColor: theme.colors.border,
547
551
  },
552
+ usesStructuredLayout && {
553
+ minHeight: 56,
554
+ paddingVertical: spacing.sm,
555
+ flexDirection: "row",
556
+ alignItems: "center",
557
+ gap: spacing.md,
558
+ },
559
+ usesStructuredLayout && variant === "rail" && {
560
+ overflow: "hidden",
561
+ },
548
562
  style,
549
- ], ...props, children: children }));
563
+ ], ...props, children: usesStructuredLayout ? (_jsxs(View, { style: {
564
+ flex: variant === "rail" ? undefined : 1,
565
+ flexShrink: variant === "rail" ? 0 : 1,
566
+ width: structuredRowWidth,
567
+ minWidth: 0,
568
+ flexDirection: "row",
569
+ alignItems: "center",
570
+ gap: spacing.md,
571
+ }, children: [icon === undefined ? null : (_jsx(View, { style: { flexShrink: 0 }, children: icon })), title === undefined ? null : (_jsx(View, { style: { flex: 1, minWidth: 0 }, children: typeof title === "string" || typeof title === "number" ? (_jsx(SansSerifBoldText, { numberOfLines: 1, selectable: false, style: { fontSize: 16, lineHeight: 20 }, children: title })) : (title) })), action === undefined ? null : (_jsx(View, { style: {
572
+ flexShrink: 0,
573
+ alignItems: "center",
574
+ justifyContent: "center",
575
+ }, children: action }))] })) : (children) }));
550
576
  }
551
577
  // ============================================================================
552
578
  // Drawer Body Component
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrmeg/expo-ui",
3
- "version": "0.12.1",
3
+ "version": "0.13.0",
4
4
  "private": false,
5
5
  "description": "Reusable Expo and React Native UI primitives for MrMeg projects.",
6
6
  "keywords": [
@@ -109,14 +109,14 @@
109
109
  "@rn-primitives/tooltip": "~1.4.0"
110
110
  },
111
111
  "peerDependencies": {
112
- "@expo/ui": ">=56.0.0 <57.0.0",
112
+ "@expo/ui": ">=56.0.0 <58.0.0",
113
113
  "@react-native-async-storage/async-storage": ">=2.2.0 <2.3.0",
114
- "expo": ">=55.0.0 <57.0.0",
115
- "expo-font": ">=55.0.0 <57.0.0",
116
- "expo-haptics": ">=55.0.0 <57.0.0",
114
+ "expo": ">=55.0.0 <58.0.0",
115
+ "expo-font": ">=55.0.0 <58.0.0",
116
+ "expo-haptics": ">=55.0.0 <58.0.0",
117
117
  "react": ">=19.2.0 <20.0.0",
118
- "react-native": ">=0.83.0 <0.86.0",
119
- "react-native-gesture-handler": ">=2.30.0 <2.32.0",
118
+ "react-native": ">=0.83.0 <0.87.0",
119
+ "react-native-gesture-handler": ">=2.30.0 <2.33.0",
120
120
  "react-native-keyboard-controller": ">=1.21.0 <2.0.0",
121
121
  "react-native-safe-area-context": ">=5.6.0 <6.0.0",
122
122
  "react-native-screens": ">=4.23.0 <5.0.0",
@@ -125,7 +125,7 @@
125
125
  },
126
126
  "devDependencies": {
127
127
  "@types/react": "~19.2.17",
128
- "react-native-keyboard-controller": "1.21.6",
128
+ "react-native-keyboard-controller": "1.21.9",
129
129
  "typescript": "~6.0.3"
130
130
  }
131
131
  }