@vvedantb/native-ui 0.17.2 → 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/dist/AlertDialog.jsx +123 -0
- package/dist/AmbientBackground.jsx +73 -0
- package/dist/ArtifactList.jsx +59 -0
- package/dist/Avatar.jsx +285 -0
- package/dist/Badge.jsx +154 -0
- package/dist/BottomSheetContainer.jsx +208 -0
- package/dist/BulkActionBar.jsx +717 -0
- package/dist/Button.jsx +344 -0
- package/dist/CaptureButton.jsx +104 -0
- package/dist/Card.jsx +371 -0
- package/dist/Checkbox.jsx +177 -0
- package/dist/Chip.jsx +79 -0
- package/dist/ColorSwatches.jsx +159 -0
- package/dist/ConfirmDialog.jsx +157 -0
- package/dist/DateTimeField.jsx +204 -0
- package/dist/Dialog.jsx +614 -0
- package/dist/DividedList.jsx +120 -0
- package/dist/DropdownMenu.jsx +849 -0
- package/dist/EmptyState.jsx +434 -0
- package/dist/ExpoWebRoot.jsx +134 -0
- package/dist/FloatingFAB.jsx +95 -0
- package/dist/FloatingSurface.jsx +226 -0
- package/dist/FloatingTabBar.jsx +403 -0
- package/dist/HeaderIconButton.jsx +53 -0
- package/dist/IconButton.jsx +157 -0
- package/dist/Input.jsx +96 -0
- package/dist/Label.jsx +96 -0
- package/dist/LabeledSwitchRow.jsx +170 -0
- package/dist/LiquidGlass.jsx +2 -0
- package/dist/ListRow.jsx +281 -0
- package/dist/LoadingState.jsx +205 -0
- package/dist/PageIndicator.jsx +128 -0
- package/dist/PageTitle.jsx +205 -0
- package/dist/Pager.jsx +105 -0
- package/dist/PasswordInput.jsx +120 -0
- package/dist/PillTabs.jsx +300 -0
- package/dist/PinnedBotTile.jsx +212 -0
- package/dist/Progress.jsx +147 -0
- package/dist/SafeAreaContainer.jsx +38 -0
- package/dist/ScreenContainer.jsx +117 -0
- package/dist/SearchInput.jsx +150 -0
- package/dist/SectionLabel.jsx +128 -0
- package/dist/Select.jsx +223 -0
- package/dist/Separator.jsx +95 -0
- package/dist/Sheet.jsx +343 -0
- package/dist/SheetRow.jsx +198 -0
- package/dist/Skeleton.jsx +311 -0
- package/dist/Spinner.jsx +195 -0
- package/dist/StackPageHeader.jsx +160 -0
- package/dist/StatGrid.jsx +74 -0
- package/dist/StatusDot.jsx +129 -0
- package/dist/SurfaceRow.jsx +143 -0
- package/dist/SwipeableRow.jsx +50 -0
- package/dist/Switch.jsx +130 -0
- package/dist/Tabs.jsx +385 -0
- package/dist/Textarea.jsx +103 -0
- package/dist/ThemeToggle.jsx +78 -0
- package/dist/Toast.jsx +396 -0
- package/dist/ai/activity-step-detail.jsx +179 -0
- package/dist/ai/activity-step-label.js +816 -0
- package/dist/ai/activity-step-types.js +14 -0
- package/dist/ai/activity-step.jsx +98 -0
- package/dist/ai/activity-tasks-utils.js +172 -0
- package/dist/ai/activity-timeline.js +47 -0
- package/dist/ai/attachments.jsx +258 -0
- package/dist/ai/card-button.jsx +188 -0
- package/dist/ai/chain-of-thought.jsx +459 -0
- package/dist/ai/chat-jump-rail.jsx +57 -0
- package/dist/ai/chat-text.js +44 -0
- package/dist/ai/chat-thread.jsx +135 -0
- package/dist/ai/choice-question.jsx +925 -0
- package/dist/ai/code-block.jsx +574 -0
- package/dist/ai/collapsible.jsx +275 -0
- package/dist/ai/conversation.jsx +723 -0
- package/dist/ai/file-chip.jsx +198 -0
- package/dist/ai/icon-button.jsx +179 -0
- package/dist/ai/index.js +37 -0
- package/dist/ai/message-action-sheet.jsx +408 -0
- package/dist/ai/message-quote.jsx +241 -0
- package/dist/ai/message.jsx +739 -0
- package/dist/ai/prompt-input-menu.jsx +365 -0
- package/dist/ai/prompt-input.jsx +626 -0
- package/dist/ai/reasoning.jsx +446 -0
- package/dist/ai/reply-quote-chip.jsx +278 -0
- package/dist/ai/response-text.jsx +130 -0
- package/dist/ai/shimmer.jsx +149 -0
- package/dist/ai/sources.jsx +260 -0
- package/dist/ai/subagent-cards.jsx +645 -0
- package/dist/ai/suggestion.jsx +186 -0
- package/dist/ai/tool-approval-card.jsx +359 -0
- package/dist/ai/trace.jsx +728 -0
- package/dist/ai/unified-diff.jsx +280 -0
- package/dist/ai/use-streaming-disclosure.js +70 -0
- package/dist/auth/AuthProviders.jsx +27 -0
- package/dist/auth/AuthScreen.jsx +292 -0
- package/dist/auth/GoogleSignInButton.jsx +188 -0
- package/dist/auth/SecondFactorScreen.jsx +133 -0
- package/dist/auth/SignInScreen.jsx +482 -0
- package/dist/auth/authErrors.js +131 -0
- package/dist/auth/index.js +11 -0
- package/dist/auth/totp.js +378 -0
- package/dist/blur.js +36 -0
- package/dist/brand/AppIcons.jsx +118 -0
- package/dist/brand/AppMark.jsx +128 -0
- package/dist/brand/AppWordmark.jsx +138 -0
- package/dist/brand/GoogleMark.jsx +71 -0
- package/dist/brand/ProviderIcon.jsx +192 -0
- package/dist/brand/familyApps.js +33 -0
- package/dist/brand/index.js +11 -0
- package/dist/brand/svg.js +252 -0
- package/dist/brand/vProAppBenefits.js +19 -0
- package/dist/cn.js +5 -0
- package/dist/colors.js +15 -0
- package/dist/configureTheme.js +72 -0
- package/dist/controlStyles.js +520 -0
- package/dist/definiteSize.js +12 -0
- package/dist/dialogLayout.js +18 -0
- package/dist/entries/ai.js +4 -0
- package/dist/entries/ambient.js +3 -0
- package/dist/entries/auth.js +5 -0
- package/dist/entries/bottom-sheet.js +2 -0
- package/dist/entries/brand.js +2 -0
- package/dist/entries/button.js +2 -0
- package/dist/entries/date-time.js +3 -0
- package/dist/entries/expo-router.js +4 -0
- package/dist/entries/expo-web-root.js +3 -0
- package/dist/entries/floating.js +7 -0
- package/dist/entries/gesture-handler.js +4 -0
- package/dist/entries/keyboard-controller.js +4 -0
- package/dist/entries/layout.js +16 -0
- package/dist/entries/markdown.js +4 -0
- package/dist/entries/marketing.js +3 -0
- package/dist/entries/page-title.js +7 -0
- package/dist/entries/password-input.js +3 -0
- package/dist/entries/primitives.js +57 -0
- package/dist/entries/search-input.js +3 -0
- package/dist/entries/tab-bar.js +4 -0
- package/dist/entries/theme.js +7 -0
- package/dist/entries/toast.js +5 -0
- package/dist/entries/video.js +3 -0
- package/dist/entries/webview.js +4 -0
- package/dist/examples/AiChatGallery.jsx +509 -0
- package/dist/examples/ParityGallery.jsx +1307 -0
- package/dist/floating.js +62 -0
- package/dist/glassBlur.jsx +145 -0
- package/dist/gradient.js +17 -0
- package/dist/haptics.js +44 -0
- package/dist/highlight.js +382 -0
- package/dist/index.js +85 -0
- package/dist/initials.js +4 -0
- package/dist/loadingGrid.js +81 -0
- package/dist/markdown/Markdown.jsx +515 -0
- package/dist/markdown/MarkdownTable.jsx +443 -0
- package/dist/markdown/tableText.js +68 -0
- package/dist/marketing/PricingModal.jsx +608 -0
- package/dist/marketing/UpgradeToProCard.jsx +164 -0
- package/dist/marketing/pricing.js +34 -0
- package/dist/media/ImageGallery.jsx +580 -0
- package/dist/media/MediaCard.jsx +162 -0
- package/dist/media/imageGrid.js +54 -0
- package/dist/motion.js +33 -0
- package/dist/pagerSwipe.js +104 -0
- package/dist/palette.js +104 -0
- package/dist/primitives/button.jsx +127 -0
- package/dist/primitives/card.jsx +249 -0
- package/dist/primitives/icon.jsx +37 -0
- package/dist/primitives/input.jsx +56 -0
- package/dist/primitives/keyboard-controller.jsx +207 -0
- package/dist/primitives/keyboard-parts.jsx +75 -0
- package/dist/primitives/native-only-animated-view.jsx +68 -0
- package/dist/primitives/overlay.jsx +391 -0
- package/dist/primitives/pager-gesture.jsx +131 -0
- package/dist/primitives/select-host.jsx +103 -0
- package/dist/primitives/select.jsx +555 -0
- package/dist/primitives/sheet-drag.jsx +420 -0
- package/dist/primitives/sheet-gesture.jsx +219 -0
- package/dist/primitives/swipe-row-gesture.jsx +341 -0
- package/dist/primitives/switch.jsx +105 -0
- package/dist/primitives/text.jsx +145 -0
- package/dist/primitives/toast-drag-gesture.jsx +94 -0
- package/dist/primitives/use-controllable-state.js +40 -0
- package/dist/primitives/web-click-guard.js +69 -0
- package/dist/push.js +166 -0
- package/dist/relativeTime.js +70 -0
- package/dist/router/RouterStackPageHeader.jsx +53 -0
- package/dist/selectA11y.js +32 -0
- package/dist/settings/MoreFromProjectV.jsx +168 -0
- package/dist/settings/SettingsEmptyState.jsx +102 -0
- package/dist/settings/SettingsField.jsx +49 -0
- package/dist/settings/SettingsSection.jsx +101 -0
- package/dist/settings/SettingsStack.jsx +17 -0
- package/dist/settings/SettingsToggleRow.jsx +163 -0
- package/dist/settings/projectVMobileApps.js +126 -0
- package/dist/settings/relaxedSizeStyle.js +11 -0
- package/dist/sheetDrag.js +76 -0
- package/dist/svgA11y.js +46 -0
- package/dist/swipeRow.js +161 -0
- package/dist/tabBarRoutes.js +41 -0
- package/dist/tabIndicator.js +139 -0
- package/dist/tailwind-preset.cjs +255 -0
- package/dist/tailwind-preset.d.cts +55 -0
- package/dist/theme.jsx +62 -0
- package/dist/toastChrome.js +110 -0
- package/dist/toastDrag.js +51 -0
- package/dist/toastStore.js +54 -0
- package/dist/tokens.js +70 -0
- package/dist/typography.js +40 -0
- package/dist/useReduceMotion.js +32 -0
- package/dist/useReduceTransparency.js +27 -0
- package/dist/useScheme.js +15 -0
- package/dist/video/InlineVideo.jsx +115 -0
- package/dist/webview/HtmlView.jsx +169 -0
- package/dist/webview/HtmlView.web.jsx +63 -0
- package/dist/webview/htmlView.js +43 -0
- package/package.json +70 -33
- package/src/DropdownMenu.tsx +28 -16
- package/src/FloatingTabBar.tsx +78 -41
- package/src/ai/conversation.tsx +12 -8
- package/src/glassBlur.tsx +47 -22
- package/src/primitives/swipe-row-gesture.tsx +11 -2
package/src/FloatingTabBar.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { Pressable, Text, View } from "react-native";
|
|
1
|
+
import { memo, useEffect } from "react";
|
|
2
|
+
import { Pressable, Text, View, type ColorValue } from "react-native";
|
|
3
3
|
import Animated, {
|
|
4
4
|
Easing,
|
|
5
5
|
useAnimatedStyle,
|
|
@@ -108,49 +108,19 @@ export function FloatingTabBar({
|
|
|
108
108
|
? options.tabBarActiveTintColor
|
|
109
109
|
: options.tabBarInactiveTintColor) ??
|
|
110
110
|
tabColors("segmented", focused, scheme).color;
|
|
111
|
-
const onPress = () => {
|
|
112
|
-
const event = navigation.emit({
|
|
113
|
-
type: "tabPress",
|
|
114
|
-
target: route.key,
|
|
115
|
-
canPreventDefault: true,
|
|
116
|
-
});
|
|
117
|
-
if (!focused && !event.defaultPrevented) {
|
|
118
|
-
selectionHaptic();
|
|
119
|
-
navigation.navigate(route.name, route.params);
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
111
|
return (
|
|
124
|
-
<
|
|
112
|
+
<TabBarItem
|
|
125
113
|
key={route.key}
|
|
114
|
+
route={route}
|
|
115
|
+
navigation={navigation}
|
|
116
|
+
focused={focused}
|
|
117
|
+
label={label}
|
|
118
|
+
color={color}
|
|
119
|
+
largerText={largerText}
|
|
120
|
+
renderIcon={options.tabBarIcon}
|
|
126
121
|
testID={options.tabBarButtonTestID}
|
|
127
|
-
accessibilityRole="tab"
|
|
128
|
-
accessibilityState={{ selected: focused }}
|
|
129
122
|
accessibilityLabel={options.tabBarAccessibilityLabel ?? label}
|
|
130
|
-
|
|
131
|
-
className="min-h-12 min-w-12 flex-1 items-center justify-center gap-1"
|
|
132
|
-
style={({ pressed }) => ({ opacity: pressed ? 0.7 : 1 })}
|
|
133
|
-
>
|
|
134
|
-
{options.tabBarIcon
|
|
135
|
-
? options.tabBarIcon({
|
|
136
|
-
focused,
|
|
137
|
-
color,
|
|
138
|
-
size: largerText ? 28 : 24,
|
|
139
|
-
})
|
|
140
|
-
: null}
|
|
141
|
-
<Text
|
|
142
|
-
numberOfLines={1}
|
|
143
|
-
// The bar has a fixed height (`tabBarReserve`), so labels
|
|
144
|
-
// scale with Dynamic Type only up to what fits in it.
|
|
145
|
-
maxFontSizeMultiplier={1.5}
|
|
146
|
-
className={`font-instrument-sans-semibold ${
|
|
147
|
-
largerText ? "text-base" : "text-sm"
|
|
148
|
-
}`}
|
|
149
|
-
style={[{ color }, typeStyle("semibold")]}
|
|
150
|
-
>
|
|
151
|
-
{label}
|
|
152
|
-
</Text>
|
|
153
|
-
</Pressable>
|
|
123
|
+
/>
|
|
154
124
|
);
|
|
155
125
|
})}
|
|
156
126
|
</View>
|
|
@@ -159,6 +129,73 @@ export function FloatingTabBar({
|
|
|
159
129
|
);
|
|
160
130
|
}
|
|
161
131
|
|
|
132
|
+
type TabBarItemProps = {
|
|
133
|
+
route: FloatingTabBarProps["state"]["routes"][number];
|
|
134
|
+
navigation: FloatingTabBarProps["navigation"];
|
|
135
|
+
focused: boolean;
|
|
136
|
+
label: string;
|
|
137
|
+
color: ColorValue;
|
|
138
|
+
largerText: boolean;
|
|
139
|
+
renderIcon: FloatingTabOptions["tabBarIcon"];
|
|
140
|
+
testID: string | undefined;
|
|
141
|
+
accessibilityLabel: string;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* One tab. Memoised: a switch re-renders the bar, and without it every tab
|
|
146
|
+
* and its SVG icon re-rendered too (the kit is not built with React
|
|
147
|
+
* Compiler). Now only the two tabs whose focus changed render. The props are
|
|
148
|
+
* stable between switches: `route` and `navigation` keep their identity, and
|
|
149
|
+
* `tabBarIcon` is the caller's function.
|
|
150
|
+
*/
|
|
151
|
+
const TabBarItem = memo(function TabBarItem({
|
|
152
|
+
route,
|
|
153
|
+
navigation,
|
|
154
|
+
focused,
|
|
155
|
+
label,
|
|
156
|
+
color,
|
|
157
|
+
largerText,
|
|
158
|
+
renderIcon,
|
|
159
|
+
testID,
|
|
160
|
+
accessibilityLabel,
|
|
161
|
+
}: TabBarItemProps) {
|
|
162
|
+
const onPress = () => {
|
|
163
|
+
const event = navigation.emit({
|
|
164
|
+
type: "tabPress",
|
|
165
|
+
target: route.key,
|
|
166
|
+
canPreventDefault: true,
|
|
167
|
+
});
|
|
168
|
+
if (!focused && !event.defaultPrevented) {
|
|
169
|
+
selectionHaptic();
|
|
170
|
+
navigation.navigate(route.name, route.params);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<Pressable
|
|
176
|
+
testID={testID}
|
|
177
|
+
accessibilityRole="tab"
|
|
178
|
+
accessibilityState={{ selected: focused }}
|
|
179
|
+
accessibilityLabel={accessibilityLabel}
|
|
180
|
+
onPress={onPress}
|
|
181
|
+
className="min-h-12 min-w-12 flex-1 items-center justify-center gap-1"
|
|
182
|
+
style={({ pressed }) => ({ opacity: pressed ? 0.7 : 1 })}
|
|
183
|
+
>
|
|
184
|
+
{renderIcon ? renderIcon({ focused, color, size: largerText ? 28 : 24 }) : null}
|
|
185
|
+
<Text
|
|
186
|
+
numberOfLines={1}
|
|
187
|
+
// The bar has a fixed height (`tabBarReserve`), so labels
|
|
188
|
+
// scale with Dynamic Type only up to what fits in it.
|
|
189
|
+
maxFontSizeMultiplier={1.5}
|
|
190
|
+
className={`font-instrument-sans-semibold ${largerText ? "text-base" : "text-sm"}`}
|
|
191
|
+
style={[{ color }, typeStyle("semibold")]}
|
|
192
|
+
>
|
|
193
|
+
{label}
|
|
194
|
+
</Text>
|
|
195
|
+
</Pressable>
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
|
|
162
199
|
/**
|
|
163
200
|
* The pill behind tab `index` of `count` drawn tabs: one tab wide (they share
|
|
164
201
|
* the row equally), `TAB_BAR_PADDING` inside the bar, in
|
package/src/ai/conversation.tsx
CHANGED
|
@@ -531,23 +531,27 @@ export function ConversationScrollButton({
|
|
|
531
531
|
testID={testID}
|
|
532
532
|
// Wider than 44 with its label; only the height needs slop.
|
|
533
533
|
hitSlop={touchSlop(MIN_TOUCH_TARGET, SCROLL_PILL_HEIGHT)}
|
|
534
|
-
style
|
|
534
|
+
// A plain style object: NativeWind drops a function `style` on a
|
|
535
|
+
// native `Pressable`, which lost the pill's row, border and fill.
|
|
536
|
+
style={{
|
|
535
537
|
minHeight: SCROLL_PILL_HEIGHT,
|
|
536
538
|
flexDirection: "row",
|
|
537
539
|
alignItems: "center",
|
|
538
|
-
gap: 6,
|
|
539
540
|
paddingHorizontal: 12,
|
|
540
541
|
borderRadius: tokens.radius.pill,
|
|
541
542
|
borderWidth: 1,
|
|
542
543
|
borderColor: withAlpha(tokens.color.border[scheme], 0.6),
|
|
543
544
|
backgroundColor: tokens.color.surface[scheme],
|
|
544
|
-
|
|
545
|
-
})}
|
|
545
|
+
}}
|
|
546
546
|
>
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
547
|
+
{({ pressed }) => (
|
|
548
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 6, opacity: pressed ? 0.7 : 1 }}>
|
|
549
|
+
<Icon size={largerText ? 20 : 16} color={tokens.color.muted[scheme]} />
|
|
550
|
+
<Text className={cn(labelSize, "font-instrument-sans")} style={[sizeStyle(labelSize), textStyle("muted", scheme)]}>
|
|
551
|
+
{label}
|
|
552
|
+
</Text>
|
|
553
|
+
</View>
|
|
554
|
+
)}
|
|
551
555
|
</Pressable>
|
|
552
556
|
) : (
|
|
553
557
|
<Button
|
package/src/glassBlur.tsx
CHANGED
|
@@ -2,44 +2,68 @@ import {
|
|
|
2
2
|
createContext,
|
|
3
3
|
useContext,
|
|
4
4
|
useLayoutEffect,
|
|
5
|
-
useMemo,
|
|
6
5
|
useRef,
|
|
7
6
|
useState,
|
|
7
|
+
useSyncExternalStore,
|
|
8
8
|
type ComponentRef,
|
|
9
|
-
type Dispatch,
|
|
10
9
|
type ReactNode,
|
|
11
10
|
type RefObject,
|
|
12
|
-
type SetStateAction,
|
|
13
11
|
} from "react";
|
|
14
12
|
import { StyleSheet, View, type ViewProps } from "react-native";
|
|
15
13
|
import { loadBlur } from "./blur";
|
|
16
14
|
|
|
17
15
|
type BlurTargetRef = RefObject<ComponentRef<typeof View> | null>;
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The current blur target, outside React state. A target change (each tab
|
|
19
|
+
* switch hands it from one tab to the next) then re-renders only the glass
|
|
20
|
+
* that subscribes, not the whole tab tree under the provider: as a context
|
|
21
|
+
* value it walked every mounted tab twice per switch.
|
|
22
|
+
*/
|
|
23
|
+
type BlurTargetStore = {
|
|
24
|
+
get: () => BlurTargetRef | null;
|
|
25
|
+
set: (next: BlurTargetRef | null) => void;
|
|
26
|
+
subscribe: (listener: () => void) => () => void;
|
|
22
27
|
};
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
function createBlurTargetStore(): BlurTargetStore {
|
|
30
|
+
let current: BlurTargetRef | null = null;
|
|
31
|
+
const listeners = new Set<() => void>();
|
|
32
|
+
return {
|
|
33
|
+
get: () => current,
|
|
34
|
+
set: (next) => {
|
|
35
|
+
if (next === current) return;
|
|
36
|
+
current = next;
|
|
37
|
+
for (const listener of listeners) listener();
|
|
38
|
+
},
|
|
39
|
+
subscribe: (listener) => {
|
|
40
|
+
listeners.add(listener);
|
|
41
|
+
return () => listeners.delete(listener);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// `null` outside a provider and inside a target (a blur view must not sit
|
|
47
|
+
// inside its own target). The value is the provider's one store, so it never
|
|
48
|
+
// changes.
|
|
49
|
+
const BlurTargetStoreContext = createContext<BlurTargetStore | null>(null);
|
|
25
50
|
|
|
26
|
-
const
|
|
51
|
+
const noSubscribe = () => () => {};
|
|
52
|
+
const noTarget = () => null;
|
|
27
53
|
|
|
28
54
|
/**
|
|
29
55
|
* The mounted `GlassBlurTarget` that floating glass blurs on Android, or
|
|
30
56
|
* `null` outside a `GlassBlurProvider` and inside the target itself.
|
|
31
57
|
*/
|
|
32
58
|
export function useGlassBlurTarget() {
|
|
33
|
-
|
|
59
|
+
const store = useContext(BlurTargetStoreContext);
|
|
60
|
+
return useSyncExternalStore(store?.subscribe ?? noSubscribe, store?.get ?? noTarget, noTarget);
|
|
34
61
|
}
|
|
35
62
|
|
|
36
63
|
export function GlassBlurProvider({ children }: { children: ReactNode }) {
|
|
37
|
-
const [
|
|
38
|
-
const value = useMemo(() => ({ target, setTarget }), [target]);
|
|
64
|
+
const [store] = useState(createBlurTargetStore);
|
|
39
65
|
|
|
40
|
-
return
|
|
41
|
-
<GlassBlurContext.Provider value={value}>{children}</GlassBlurContext.Provider>
|
|
42
|
-
);
|
|
66
|
+
return <BlurTargetStoreContext.Provider value={store}>{children}</BlurTargetStoreContext.Provider>;
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
export type GlassBlurTargetProps = ViewProps & {
|
|
@@ -59,23 +83,24 @@ export function GlassBlurTarget({
|
|
|
59
83
|
children,
|
|
60
84
|
...props
|
|
61
85
|
}: GlassBlurTargetProps) {
|
|
62
|
-
const
|
|
86
|
+
const store = useContext(BlurTargetStoreContext);
|
|
63
87
|
const ref = useRef<ComponentRef<typeof View>>(null);
|
|
64
88
|
const BlurTargetView = loadBlur()?.BlurTargetView;
|
|
65
89
|
|
|
66
90
|
// Publish the ref only once it is attached: expo-blur compares
|
|
67
91
|
// `blurTarget.current` between renders to pick up a new target.
|
|
68
92
|
useLayoutEffect(() => {
|
|
69
|
-
if (!
|
|
93
|
+
if (!store || !active) {
|
|
70
94
|
return;
|
|
71
95
|
}
|
|
72
|
-
|
|
73
|
-
return () =>
|
|
74
|
-
|
|
96
|
+
store.set(ref);
|
|
97
|
+
return () => {
|
|
98
|
+
if (store.get() === ref) store.set(null);
|
|
99
|
+
};
|
|
100
|
+
}, [store, active]);
|
|
75
101
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
102
|
+
// Surfaces in here get no target: a blur view must not sit inside its own.
|
|
103
|
+
const content = <BlurTargetStoreContext.Provider value={null}>{children}</BlurTargetStoreContext.Provider>;
|
|
79
104
|
|
|
80
105
|
return BlurTargetView ? (
|
|
81
106
|
<BlurTargetView ref={ref} style={[styles.fill, style]} {...props}>
|
|
@@ -80,6 +80,12 @@ export function GestureSwipeableRow({
|
|
|
80
80
|
|
|
81
81
|
// Whether this touch began while a row was open, so its release only closes that row. Nothing renders from it.
|
|
82
82
|
const closesOnRelease = useRef(false);
|
|
83
|
+
// The action strips mount on the row's first touch, not with the row: a
|
|
84
|
+
// list of a hundred rows then mounts no hidden buttons and icons up front.
|
|
85
|
+
// A touch lands a few frames before a swipe can move the row, so the strip
|
|
86
|
+
// is there before any of it shows.
|
|
87
|
+
const [revealed, setRevealed] = useState(false);
|
|
88
|
+
const reveal = () => setRevealed(true);
|
|
83
89
|
const webClicks = useWebClickGuard(isSwipeRowOpen);
|
|
84
90
|
const insidePager = useContext(InsidePagerContext);
|
|
85
91
|
const opened = () => {
|
|
@@ -137,6 +143,9 @@ export function GestureSwipeableRow({
|
|
|
137
143
|
.failOffsetY([-SWIPE_FAIL_OFFSET_Y, SWIPE_FAIL_OFFSET_Y]);
|
|
138
144
|
if (activation.failOffsetX !== undefined) pan.failOffsetX(activation.failOffsetX);
|
|
139
145
|
pan
|
|
146
|
+
.onBegin(() => {
|
|
147
|
+
runOnJS(reveal)();
|
|
148
|
+
})
|
|
140
149
|
.onStart(() => {
|
|
141
150
|
cancelAnimation(x);
|
|
142
151
|
start.set(x.get());
|
|
@@ -184,10 +193,10 @@ export function GestureSwipeableRow({
|
|
|
184
193
|
const rowStyle = useAnimatedStyle(() => ({ transform: [{ translateX: x.get() }] }));
|
|
185
194
|
return (
|
|
186
195
|
<View onLayout={(event) => width.set(event.nativeEvent.layout.width)} style={styles.clip}>
|
|
187
|
-
{leadingActions.length > 0 ? (
|
|
196
|
+
{revealed && leadingActions.length > 0 ? (
|
|
188
197
|
<ActionStrip side="leading" actions={leadingActions} x={x} armedScale={armedScale} onPress={press} />
|
|
189
198
|
) : null}
|
|
190
|
-
{trailingActions.length > 0 ? (
|
|
199
|
+
{revealed && trailingActions.length > 0 ? (
|
|
191
200
|
<ActionStrip side="trailing" actions={trailingActions} x={x} armedScale={armedScale} onPress={press} />
|
|
192
201
|
) : null}
|
|
193
202
|
<GestureDetector gesture={pan}>
|