@mrmeg/expo-ui 0.17.0 → 0.18.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 +13 -0
- package/LLM_USAGE.md +5 -0
- package/README.md +1 -1
- package/dist/components/BottomSheet.d.ts +9 -1
- package/dist/components/BottomSheet.js +8 -3
- package/dist/hooks/useResources.d.ts +14 -0
- package/dist/hooks/useResources.js +43 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
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.18.0]
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **`BottomSheet.Content` `backgroundStyle` pass-through.** The native sheet
|
|
11
|
+
surface (web vaul panel, Android `containerColor`, iOS
|
|
12
|
+
`presentationBackground`) previously hardcoded the themed card color.
|
|
13
|
+
`BottomSheet.Content` now accepts an optional `backgroundStyle` merged over
|
|
14
|
+
that default, so hosts can pass `{ backgroundColor: "transparent" }` to let
|
|
15
|
+
custom chrome (e.g. a Liquid Glass backdrop) show through. Omitting the prop
|
|
16
|
+
preserves the existing card background. The RN content column still paints
|
|
17
|
+
its own card fill; clear that via `style` when going transparent.
|
|
18
|
+
|
|
6
19
|
## [0.17.0]
|
|
7
20
|
|
|
8
21
|
### Added
|
package/LLM_USAGE.md
CHANGED
|
@@ -76,6 +76,11 @@ On native, `BottomSheet.Content` avoids the soft keyboard by default with
|
|
|
76
76
|
React Native keyboard events. Pass `avoidKeyboard={false}` to opt out for a
|
|
77
77
|
specific sheet.
|
|
78
78
|
|
|
79
|
+
`BottomSheet.Content` themes the native sheet surface with the card color.
|
|
80
|
+
Pass `backgroundStyle={{ backgroundColor: "transparent" }}` (with a `style`
|
|
81
|
+
that clears the content column's card fill) when custom chrome such as a
|
|
82
|
+
glass backdrop should show through; omitting it keeps the card background.
|
|
83
|
+
|
|
79
84
|
i18n is optional. Do not add app-level i18n setup just to use this package.
|
|
80
85
|
Plain children and `text` props work without `i18next` or `react-i18next`.
|
|
81
86
|
`tx` props render fallback text when provided and otherwise render the key
|
package/README.md
CHANGED
|
@@ -374,7 +374,7 @@ Use `StyledText` or its aliases instead of raw `Text` whenever the text is part
|
|
|
374
374
|
/>
|
|
375
375
|
```
|
|
376
376
|
|
|
377
|
-
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`.
|
|
377
|
+
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. `BottomSheet.Content` also accepts `backgroundStyle`, merged over the themed card default on the native sheet surface (web panel, Android `containerColor`, iOS `presentationBackground`) — pass `{ backgroundColor: "transparent" }`, plus a `style` clearing the content column's card fill, to let custom chrome like a glass backdrop show through. Trigger transient feedback with `notify`.
|
|
378
378
|
|
|
379
379
|
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.
|
|
380
380
|
|
|
@@ -117,6 +117,14 @@ interface BottomSheetContentProps extends ViewProps {
|
|
|
117
117
|
avoidKeyboard?: boolean;
|
|
118
118
|
/** Accepted for call-site ergonomics; ignored (platform owns keyboard). */
|
|
119
119
|
dismissKeyboardOnDrag?: boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Style for the native sheet surface behind the RN content — the web (vaul)
|
|
122
|
+
* panel, Android `containerColor`, iOS `presentationBackground`. Merged over
|
|
123
|
+
* the themed card default, so `{ backgroundColor: "transparent" }` lets a
|
|
124
|
+
* custom chrome (e.g. a glass backdrop) show through. The RN content column
|
|
125
|
+
* paints its own card fill too; clear that via `style`.
|
|
126
|
+
*/
|
|
127
|
+
backgroundStyle?: StyleProp<ViewStyle>;
|
|
120
128
|
style?: StyleProp<ViewStyle>;
|
|
121
129
|
children: React.ReactNode;
|
|
122
130
|
}
|
|
@@ -140,7 +148,7 @@ interface BottomSheetCloseProps {
|
|
|
140
148
|
declare function useBottomSheetContext(): BottomSheetContextValue;
|
|
141
149
|
declare function BottomSheetRoot({ open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen, snapPoints, closeOnBackdropPress, children, }: BottomSheetProps): React.JSX.Element;
|
|
142
150
|
declare function BottomSheetTrigger({ asChild, children, style: styleOverride }: BottomSheetTriggerProps): React.JSX.Element;
|
|
143
|
-
declare function BottomSheetContent({ swipeEnabled: _swipeEnabled, avoidKeyboard: _avoidKeyboard, dismissKeyboardOnDrag: _dismissKeyboardOnDrag, style: styleOverride, children, }: BottomSheetContentProps): React.JSX.Element;
|
|
151
|
+
declare function BottomSheetContent({ swipeEnabled: _swipeEnabled, avoidKeyboard: _avoidKeyboard, dismissKeyboardOnDrag: _dismissKeyboardOnDrag, backgroundStyle: backgroundStyleOverride, style: styleOverride, children, }: BottomSheetContentProps): React.JSX.Element;
|
|
144
152
|
declare function BottomSheetHandle({ style }: BottomSheetHandleProps): React.JSX.Element;
|
|
145
153
|
declare function BottomSheetHeader({ children, style, ...props }: BottomSheetHeaderProps): React.JSX.Element;
|
|
146
154
|
declare function BottomSheetBody({ children, style, contentContainerStyle, onContentSizeChange, onLayout, ...props }: BottomSheetBodyProps): React.JSX.Element;
|
|
@@ -296,7 +296,7 @@ function BottomSheetTrigger({ asChild, children, style: styleOverride }) {
|
|
|
296
296
|
// ============================================================================
|
|
297
297
|
function BottomSheetContent({
|
|
298
298
|
// Accepted-but-ignored ergonomics props (platform owns these behaviors):
|
|
299
|
-
swipeEnabled: _swipeEnabled, avoidKeyboard: _avoidKeyboard, dismissKeyboardOnDrag: _dismissKeyboardOnDrag, style: styleOverride, children, }) {
|
|
299
|
+
swipeEnabled: _swipeEnabled, avoidKeyboard: _avoidKeyboard, dismissKeyboardOnDrag: _dismissKeyboardOnDrag, backgroundStyle: backgroundStyleOverride, style: styleOverride, children, }) {
|
|
300
300
|
const { open, onOpenChange, snapPoints, snapIndex, setSnapIndex, hasHeader } = useBottomSheetContext();
|
|
301
301
|
const { theme } = useTheme();
|
|
302
302
|
const dismissDisabled = useDismissDisabled();
|
|
@@ -337,8 +337,13 @@ swipeEnabled: _swipeEnabled, avoidKeyboard: _avoidKeyboard, dismissKeyboardOnDra
|
|
|
337
337
|
if (open)
|
|
338
338
|
onOpenChange(false);
|
|
339
339
|
},
|
|
340
|
-
// Themes the scrim/background on web (vaul)
|
|
341
|
-
|
|
340
|
+
// Themes the scrim/background on web (vaul), Android (containerColor),
|
|
341
|
+
// and iOS (presentationBackground). Flattened so native readers that
|
|
342
|
+
// expect a plain object (not a style array) keep working.
|
|
343
|
+
backgroundStyle: StyleSheet.flatten([
|
|
344
|
+
{ backgroundColor: theme.colors.card },
|
|
345
|
+
backgroundStyleOverride,
|
|
346
|
+
]), children: _jsx(TextColorContext.Provider, { value: theme.colors.foreground, children: _jsx(TextClassContext.Provider, { value: "", children: _jsxs(View, { style: [
|
|
342
347
|
{
|
|
343
348
|
flex: 1,
|
|
344
349
|
maxHeight: detentHeight,
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers the Feather icon font in expo-font's per-request SSR store.
|
|
3
|
+
*
|
|
4
|
+
* Must be called from a **render body** on server-web (see `useResources`
|
|
5
|
+
* below): expo-font enters an `AsyncLocalStorage` store per request, so a
|
|
6
|
+
* module-scope registration lands in at most one request's store. Registering
|
|
7
|
+
* during render means every request emits the `@font-face` rule into
|
|
8
|
+
* `<style id="expo-generated-fonts">` and server-rendered `<Icon>`s agree with
|
|
9
|
+
* the client's first render.
|
|
10
|
+
*
|
|
11
|
+
* No-op on native and on client web (both already covered: native by the
|
|
12
|
+
* effect below, client web by the module-scope call above).
|
|
13
|
+
*/
|
|
14
|
+
export declare function ensureIconFontRegistered(): void;
|
|
1
15
|
interface LoadResourcesResult {
|
|
2
16
|
loaded: boolean;
|
|
3
17
|
error: Error | null;
|
|
@@ -4,15 +4,45 @@ import Feather from "@expo/vector-icons/Feather";
|
|
|
4
4
|
import { Inter_400Regular, Inter_500Medium, Inter_600SemiBold, Inter_700Bold, } from "@expo-google-fonts/inter";
|
|
5
5
|
import { Platform } from "react-native";
|
|
6
6
|
import { useThemeStore } from "../state/themeStore.js";
|
|
7
|
-
// Eager, module-scope load
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
7
|
+
// Eager, module-scope load that primes the Feather font on the *client* before
|
|
8
|
+
// first render: on web it synchronously injects the @font-face rule, which is
|
|
9
|
+
// what makes the client's `Font.isLoaded("feather")` check read true during
|
|
10
|
+
// hydration; on native it just starts the fetch ahead of the effect below
|
|
11
|
+
// (which then no-ops for the already-loaded font).
|
|
12
|
+
//
|
|
13
|
+
// Deliberately guarded off server-web. expo-font's SSR store is per-request
|
|
14
|
+
// AsyncLocalStorage, and Metro's inlineRequires defers this module's evaluation
|
|
15
|
+
// until it is first required during a render — so on the server this line only
|
|
16
|
+
// ever populated the store of whichever request happened to warm the module
|
|
17
|
+
// cache. Requests 2+ then shipped HTML with no @font-face and empty icons while
|
|
18
|
+
// the client rendered glyphs (React #418). Server registration happens
|
|
19
|
+
// per-request in ensureIconFontRegistered() instead.
|
|
20
|
+
if (typeof window !== "undefined") {
|
|
21
|
+
void Font.loadAsync(Feather.font);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Registers the Feather icon font in expo-font's per-request SSR store.
|
|
25
|
+
*
|
|
26
|
+
* Must be called from a **render body** on server-web (see `useResources`
|
|
27
|
+
* below): expo-font enters an `AsyncLocalStorage` store per request, so a
|
|
28
|
+
* module-scope registration lands in at most one request's store. Registering
|
|
29
|
+
* during render means every request emits the `@font-face` rule into
|
|
30
|
+
* `<style id="expo-generated-fonts">` and server-rendered `<Icon>`s agree with
|
|
31
|
+
* the client's first render.
|
|
32
|
+
*
|
|
33
|
+
* No-op on native and on client web (both already covered: native by the
|
|
34
|
+
* effect below, client web by the module-scope call above).
|
|
35
|
+
*/
|
|
36
|
+
export function ensureIconFontRegistered() {
|
|
37
|
+
if (Platform.OS !== "web" || typeof window !== "undefined")
|
|
38
|
+
return;
|
|
39
|
+
if (Font.isLoaded("feather"))
|
|
40
|
+
return; // per-request store; cheap
|
|
41
|
+
// Synchronous on server-web (expo-font routes to registerStaticFont). No
|
|
42
|
+
// `void`/try-catch: a throw here means we're outside a request scope, which
|
|
43
|
+
// must be loud.
|
|
44
|
+
Font.loadAsync(Feather.font);
|
|
45
|
+
}
|
|
16
46
|
// The four static Inter weights StyledText's native family keys point at
|
|
17
47
|
// (see constants/fonts.ts). Native-only: web never renders these family names
|
|
18
48
|
// ("Inter_400Regular" etc.) — fontFamilies.sansSerif resolves every weight to
|
|
@@ -66,6 +96,10 @@ function ensureWebFontStylesheet() {
|
|
|
66
96
|
* un-download Inter. The Feather icon font always loads.
|
|
67
97
|
*/
|
|
68
98
|
export const useResources = () => {
|
|
99
|
+
// Render-body (not effect) so server-web registers the icon font in *this*
|
|
100
|
+
// request's expo-font store — effects never run on the server and a
|
|
101
|
+
// module-scope call only reaches one request. See ensureIconFontRegistered.
|
|
102
|
+
ensureIconFontRegistered();
|
|
69
103
|
const [loaded, setLoaded] = useState(false);
|
|
70
104
|
const [error, setError] = useState(null);
|
|
71
105
|
useEffect(() => {
|