@kanso-labs/react-native-kanso-ui 0.4.0 → 0.5.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/autocomplete/index.js +39 -0
- package/dist/autocomplete/index.js.map +1 -0
- package/dist/button/index.d.ts +2 -1
- package/dist/button/index.js +35 -2
- package/dist/button/index.js.map +1 -1
- package/dist/button/pending.js +1 -1
- package/dist/button/slots.d.ts +2 -1
- package/dist/button/slots.js.map +1 -1
- package/dist/chip/index.js +1 -1
- package/dist/components/autocomplete/index.d.ts +49 -0
- package/dist/components/autocomplete/index.js +87 -0
- package/dist/components/autocomplete/index.js.map +1 -0
- package/dist/components/avatar/index.d.ts +1 -1
- package/dist/components/button/index.d.ts +2 -2
- package/dist/components/button/index.js +196 -150
- package/dist/components/button/index.js.map +1 -1
- package/dist/components/card/index.d.ts +1 -1
- package/dist/components/card/index.js +1 -1
- package/dist/components/checkbox/index.d.ts +1 -1
- package/dist/components/checkbox/index.js +106 -193
- package/dist/components/checkbox/index.js.map +1 -1
- package/dist/components/chip/index.d.ts +1 -1
- package/dist/components/chip-group/index.d.ts +1 -1
- package/dist/components/chip-group/index.js +1 -1
- package/dist/components/copy-field/index.d.ts +1 -1
- package/dist/components/copy-field/index.js +1 -1
- package/dist/components/currency/index.d.ts +1 -1
- package/dist/components/currency/index.js +1 -1
- package/dist/components/dialog/index.d.ts +1 -1
- package/dist/components/dialog/index.js +3 -2
- package/dist/components/dialog/index.js.map +1 -1
- package/dist/components/icon-button/index.d.ts +2 -2
- package/dist/components/icon-button/index.js +205 -159
- package/dist/components/icon-button/index.js.map +1 -1
- package/dist/components/link/index.d.ts +1 -1
- package/dist/components/link/index.js +1 -1
- package/dist/components/list/index.d.ts +216 -0
- package/dist/components/list/index.js +1118 -0
- package/dist/components/list/index.js.map +1 -0
- package/dist/components/list-item/index.d.ts +63 -0
- package/dist/components/list-item/index.js +275 -0
- package/dist/components/list-item/index.js.map +1 -0
- package/dist/components/menu/index.d.ts +309 -0
- package/dist/components/menu/index.js +1283 -0
- package/dist/components/menu/index.js.map +1 -0
- package/dist/components/meter/index.d.ts +1 -1
- package/dist/components/meter/index.js +1 -1
- package/dist/components/number-field/index.d.ts +1 -1
- package/dist/components/number-field/index.js +2 -2
- package/dist/components/popover/index.d.ts +140 -0
- package/dist/components/popover/index.js +704 -0
- package/dist/components/popover/index.js.map +1 -0
- package/dist/components/product-icon/index.d.ts +1 -1
- package/dist/components/progress-indicator/index.d.ts +1 -1
- package/dist/components/progress-indicator/index.js +1 -1
- package/dist/components/radio-group/index.d.ts +1 -1
- package/dist/components/radio-group/index.js +1 -1
- package/dist/components/search-field/index.d.ts +12 -4
- package/dist/components/search-field/index.js +64 -58
- package/dist/components/search-field/index.js.map +1 -1
- package/dist/components/segmented-button/index.d.ts +1 -1
- package/dist/components/segmented-button/index.js +1 -1
- package/dist/components/separator/index.d.ts +1 -1
- package/dist/components/separator/index.js +1 -1
- package/dist/components/sheet/index.d.ts +1 -1
- package/dist/components/sheet/index.js +3 -2
- package/dist/components/sheet/index.js.map +1 -1
- package/dist/components/snackbar/index.d.ts +1 -1
- package/dist/components/snackbar/index.js +1 -1
- package/dist/components/stack/index.d.ts +1 -1
- package/dist/components/stack/index.js +1 -1
- package/dist/components/switch/index.d.ts +1 -1
- package/dist/components/switch/index.js +1 -1
- package/dist/components/text/index.d.ts +1 -1
- package/dist/components/text/index.js +1 -1
- package/dist/components/text-field/index.d.ts +1 -1
- package/dist/components/text-field/index.js +1 -1
- package/dist/control/checkbox-box.js +137 -0
- package/dist/control/checkbox-box.js.map +1 -0
- package/dist/control/index.js +1 -1
- package/dist/field/index.d.ts +1 -1
- package/dist/field/index.js +1 -1
- package/dist/form/index.d.ts +1 -1
- package/dist/glyphs/index.js +21 -2
- package/dist/glyphs/index.js.map +1 -1
- package/dist/i18n/index.js +16 -1
- package/dist/i18n/index.js.map +1 -1
- package/dist/i18n/messages.js +272 -34
- package/dist/i18n/messages.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +7 -2
- package/dist/indicator/index.d.ts +1 -1
- package/dist/indicator/index.js +2 -2
- package/dist/mark/index.d.ts +1 -1
- package/dist/mark/index.js +1 -1
- package/dist/modal/index.d.ts +1 -1
- package/dist/modal/index.js +2 -9
- package/dist/modal/index.js.map +1 -1
- package/dist/overlay/anchored.d.ts +2 -0
- package/dist/overlay/anchored.js +182 -0
- package/dist/overlay/anchored.js.map +1 -0
- package/dist/overlay/host.d.ts +2 -0
- package/dist/overlay/host.js +1 -1
- package/dist/overlay/index.d.ts +4 -0
- package/dist/overlay/panel.js +215 -0
- package/dist/overlay/panel.js.map +1 -0
- package/dist/overlay/placement.d.ts +8 -0
- package/dist/overlay/placement.js +87 -0
- package/dist/overlay/placement.js.map +1 -0
- package/dist/press/index.js +1 -1
- package/dist/ref/index.js +15 -0
- package/dist/ref/index.js.map +1 -0
- package/dist/router/index.js +1 -1
- package/dist/row/index.js +158 -0
- package/dist/row/index.js.map +1 -0
- package/dist/row/styles.js +51 -0
- package/dist/row/styles.js.map +1 -0
- package/dist/theme/scope.js +1 -1
- package/dist/theme-scope.d.ts +1 -1
- package/dist/theme-scope.js +1 -1
- package/dist/typography/fonts.js +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Autocomplete } from "./components/autocomplete/index.js";
|
|
1
2
|
import { useIconStyle } from "./glyphs/icon-style.js";
|
|
2
3
|
import { useTheme } from "./theme/scope.js";
|
|
3
4
|
import { Avatar } from "./components/avatar/index.js";
|
|
@@ -16,17 +17,21 @@ import { Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTi
|
|
|
16
17
|
import { Form } from "./components/form/index.js";
|
|
17
18
|
import { IconButton } from "./components/icon-button/index.js";
|
|
18
19
|
import { Link } from "./components/link/index.js";
|
|
20
|
+
import { List, ListLoadMore, ListRow, ListSection } from "./components/list/index.js";
|
|
21
|
+
import { ListItem } from "./components/list-item/index.js";
|
|
22
|
+
import { Separator } from "./components/separator/index.js";
|
|
23
|
+
import { Menu, MenuContent, MenuItem, MenuLoadMore, MenuSection, MenuSeparator, MenuSubmenu } from "./components/menu/index.js";
|
|
19
24
|
import { Meter } from "./components/meter/index.js";
|
|
20
25
|
import { NumberField } from "./components/number-field/index.js";
|
|
26
|
+
import { Popover, PopoverContent, PopoverDescription, PopoverTitle } from "./components/popover/index.js";
|
|
21
27
|
import { ProductIcon } from "./components/product-icon/index.js";
|
|
22
28
|
import { Radio, RadioGroup } from "./components/radio-group/index.js";
|
|
23
29
|
import { SearchField } from "./components/search-field/index.js";
|
|
24
30
|
import { SegmentedButton, SegmentedButtonSegment } from "./components/segmented-button/index.js";
|
|
25
|
-
import { Separator } from "./components/separator/index.js";
|
|
26
31
|
import { Sheet, SheetBody, SheetContent, SheetFooter, SheetHandle, SheetHeader, SheetTitle } from "./components/sheet/index.js";
|
|
27
32
|
import { Snackbar } from "./components/snackbar/index.js";
|
|
28
33
|
import { Stack } from "./components/stack/index.js";
|
|
29
34
|
import { Switch } from "./components/switch/index.js";
|
|
30
35
|
import { TextField } from "./components/text-field/index.js";
|
|
31
36
|
import { ThemeScope } from "./theme-scope.js";
|
|
32
|
-
export { Avatar, Button, Card, Checkbox, Chip, ChipGroup, ChipGroupChip, CopyField, Currency, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Form, IconButton, Link, Meter, NumberField, ProductIcon, ProgressIndicator, Radio, RadioGroup, RouterProvider, SearchField, SegmentedButton, SegmentedButtonSegment, Separator, Sheet, SheetBody, SheetContent, SheetFooter, SheetHandle, SheetHeader, SheetTitle, Snackbar, Stack, Switch, Text, TextField, ThemeScope, useIconStyle, useTheme, useWindowSizeClass };
|
|
37
|
+
export { Autocomplete, Avatar, Button, Card, Checkbox, Chip, ChipGroup, ChipGroupChip, CopyField, Currency, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Form, IconButton, Link, List, ListItem, ListLoadMore, ListRow, ListSection, Menu, MenuContent, MenuItem, MenuLoadMore, MenuSection, MenuSeparator, MenuSubmenu, Meter, NumberField, Popover, PopoverContent, PopoverDescription, PopoverTitle, ProductIcon, ProgressIndicator, Radio, RadioGroup, RouterProvider, SearchField, SegmentedButton, SegmentedButtonSegment, Separator, Sheet, SheetBody, SheetContent, SheetFooter, SheetHandle, SheetHeader, SheetTitle, Snackbar, Stack, Switch, Text, TextField, ThemeScope, useIconStyle, useTheme, useWindowSizeClass };
|
package/dist/indicator/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { localeOf } from "../number/locale.js";
|
|
1
2
|
import { useIconStyle } from "../glyphs/icon-style.js";
|
|
2
3
|
import { useTheme } from "../theme/scope.js";
|
|
3
4
|
import { composeStyles } from "../theme/styles.js";
|
|
4
5
|
import { withOpacity } from "../theme/color.js";
|
|
5
6
|
import { Text as Text$1 } from "../components/text/index.js";
|
|
6
|
-
import { localeOf } from "../number/locale.js";
|
|
7
7
|
import { styles, stylesOf } from "./styles.js";
|
|
8
8
|
import { c } from "react/compiler-runtime";
|
|
9
|
-
import { View } from "react-native";
|
|
10
9
|
import { useEffect, useState } from "react";
|
|
11
10
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { View } from "react-native";
|
|
12
12
|
import Animated, { Easing, useAnimatedStyle, useReducedMotion, useSharedValue, withTiming } from "react-native-reanimated";
|
|
13
13
|
import { NumberFormatter } from "@internationalized/number";
|
|
14
14
|
//#region src/indicator/index.tsx
|
package/dist/mark/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./styles.js";
|
|
2
|
-
import { ImageProps, StyleProp, View, ViewProps, ViewStyle } from "react-native";
|
|
3
2
|
import { ComponentRef, Ref } from "react";
|
|
3
|
+
import { ImageProps, StyleProp, View, ViewProps, ViewStyle } from "react-native";
|
|
4
4
|
//#region src/mark/index.d.ts
|
|
5
5
|
/** The native props a picture's own `Image` takes, as Avatar and ProductIcon take them. */
|
|
6
6
|
type MarkImageProps = Pick<ImageProps, 'crossOrigin' | 'fadeDuration' | 'progressiveRenderingEnabled' | 'referrerPolicy' | 'resizeMethod'>;
|
package/dist/mark/index.js
CHANGED
|
@@ -6,8 +6,8 @@ import { useImageLoadingStatus } from "./image.js";
|
|
|
6
6
|
import { initialOfThing, initialsOfPerson } from "./initials.js";
|
|
7
7
|
import { DIAMETERS, GLYPH_SHARE, initialsStylesOf, markStyles, markStylesOf } from "./styles.js";
|
|
8
8
|
import { c } from "react/compiler-runtime";
|
|
9
|
-
import { Image, Text, View } from "react-native";
|
|
10
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { Image, Text, View } from "react-native";
|
|
11
11
|
//#region src/mark/index.tsx
|
|
12
12
|
const KINDS = {
|
|
13
13
|
person: {
|
package/dist/modal/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "../button/slots.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
2
3
|
import { HostInstance, ViewProps, ViewStyle } from "react-native";
|
|
3
|
-
import { ReactNode, Ref } from "react";
|
|
4
4
|
import "react-native-reanimated";
|
|
5
5
|
import "react-native-safe-area-context";
|
|
6
6
|
import "react-stately/useOverlayTriggerState";
|
package/dist/modal/index.js
CHANGED
|
@@ -5,9 +5,9 @@ import { AnimatedPressable } from "../button/index.js";
|
|
|
5
5
|
import { withOpacity } from "../theme/color.js";
|
|
6
6
|
import { OverlayHost } from "../overlay/host.js";
|
|
7
7
|
import { c } from "react/compiler-runtime";
|
|
8
|
-
import { AccessibilityInfo, I18nManager, Modal, Platform, StyleSheet } from "react-native";
|
|
9
8
|
import { useEffect, useRef, useState } from "react";
|
|
10
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { AccessibilityInfo, I18nManager, Modal, Platform, StyleSheet } from "react-native";
|
|
11
11
|
import { useOverlayTriggerState } from "react-stately/useOverlayTriggerState";
|
|
12
12
|
//#region src/modal/index.tsx
|
|
13
13
|
const NO_INSETS = {
|
|
@@ -143,13 +143,6 @@ function panelRoleOf(role, labelledBy) {
|
|
|
143
143
|
role
|
|
144
144
|
};
|
|
145
145
|
}
|
|
146
|
-
function refsOf(own, other) {
|
|
147
|
-
return (node) => {
|
|
148
|
-
own(node);
|
|
149
|
-
if (typeof other === "function") other(node);
|
|
150
|
-
else if (other !== null && other !== void 0) other.current = node;
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
146
|
function registerOf(setParts) {
|
|
154
147
|
return (part) => {
|
|
155
148
|
setParts((parts) => ({
|
|
@@ -279,6 +272,6 @@ function useReturnFocus(present, outer) {
|
|
|
279
272
|
useEffect(t0, t1);
|
|
280
273
|
}
|
|
281
274
|
//#endregion
|
|
282
|
-
export { ModalWindow, NO_INSETS, insetsOf, panelRoleOf,
|
|
275
|
+
export { ModalWindow, NO_INSETS, insetsOf, panelRoleOf, registerOf, useModalState, useModalTrigger };
|
|
283
276
|
|
|
284
277
|
//# sourceMappingURL=index.js.map
|
package/dist/modal/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["ReactNode","Ref","GestureResponderEvent","HostInstance","ModalProps","ViewProps","ViewStyle","AnimatedStyle","EdgeInsets","OverlayTriggerState","useCallback","useEffect","useMemo","useRef","useState","AccessibilityInfo","I18nManager","Modal","Platform","StyleSheet","useOverlayTriggerState","ButtonSlots","ResolvedTheme","AnimatedPressable","ButtonSlotContext","OverlayHost","withOpacity","useTheme","composeStyles","themedStyles","NO_INSETS","bottom","left","right","top","ORIENTATIONS","SCRIM_OPACITY","stylesOf","colors","create","scrim","backgroundColor","position","ModalOpenProps","defaultOpen","isOpen","onOpenChange","ModalTrigger","state","trigger","ModalWindowProps","children","isKeyboardDismissDisabled","labelledBy","onClose","onScrimPress","title","focusOf","OS","sendAccessibilityEvent","ignore","insetsOf","insets","rtl","isRTL","paddingBottom","paddingEnd","paddingStart","paddingTop","ModalWindow","t0","$","_c","styles","T0","t1","t2","undefined","t3","t4","t5","t6","t8","t9","T1","t10","T2","T3","t11","t12","t13","t14","t15","t16","t17","t18","t7","panelRoleOf","role","Pick","refsOf","own","node","T","other","current","registerOf","setParts","update","parts","Readonly","Record","Part","part","useModalState","outer","props","present","setPresent","close","slots","useReturnFocus","useModalTrigger","setTrigger","context","default","event","target","currentTarget","open","shown","gone","_c"],"sources":["../../src/modal/index.tsx"],"sourcesContent":["import type { ReactNode, Ref } from 'react'\nimport type {\n GestureResponderEvent,\n HostInstance,\n ModalProps,\n ViewProps,\n ViewStyle,\n} from 'react-native'\nimport type { AnimatedStyle } from 'react-native-reanimated'\nimport type { EdgeInsets } from 'react-native-safe-area-context'\nimport type { OverlayTriggerState } from 'react-stately/useOverlayTriggerState'\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n AccessibilityInfo,\n I18nManager,\n Modal,\n Platform,\n StyleSheet,\n} from 'react-native'\nimport { useOverlayTriggerState } from 'react-stately/useOverlayTriggerState'\n\nimport type { ButtonSlots } from '../button/slots'\nimport type { ResolvedTheme } from '../theme/scope'\n\nimport { AnimatedPressable } from '../button'\nimport { ButtonSlotContext } from '../button/slots'\nimport { OverlayHost } from '../overlay'\nimport { withOpacity } from '../theme/color'\nimport { useTheme } from '../theme/scope'\nimport { composeStyles, themedStyles } from '../theme/styles'\n\n// The window a modal surface is drawn in, and what a dialog and a sheet share\n// around it: the trigger that opens it, the open state, the scrim, and where\n// focus goes as it shows and once it has gone. Internal: nothing here is\n// exported from the package.\n//\n// **It is a React Native `Modal`**, which keeps React context, so the surface\n// keeps the `ThemeScope` around it, and which is a window of its own on iOS\n// and Android, above the screen and its overlays. The window therefore hosts\n// overlays of its own, so a snackbar or a popover raised from inside it draws\n// above it rather than under it.\n\n// Outside a SafeAreaProvider the insets are unknown, and the window's own edge\n// is the best bound there is.\nconst NO_INSETS: EdgeInsets = { bottom: 0, left: 0, right: 0, top: 0 }\n\n// iOS presents a `Modal` in portrait alone unless told otherwise, which would\n// turn an app held sideways round as the surface opened.\nconst ORIENTATIONS: ModalProps['supportedOrientations'] = [\n 'portrait',\n 'portrait-upside-down',\n 'landscape',\n 'landscape-left',\n 'landscape-right',\n]\n\n// The scrim is the scrim role at 32%, the opacity Material Design gives a\n// modal's scrim and web mixes in.\nconst SCRIM_OPACITY = 0.32\n\nconst stylesOf = themedStyles(({ colors }: ResolvedTheme) =>\n StyleSheet.create({\n scrim: {\n backgroundColor: withOpacity(colors.scrim, SCRIM_OPACITY),\n bottom: 0,\n left: 0,\n position: 'absolute',\n right: 0,\n top: 0,\n },\n }),\n)\n\n/** Whether a modal surface is open, and who holds that state. */\ntype ModalOpenProps = {\n readonly defaultOpen?: boolean\n readonly isOpen?: boolean\n readonly onOpenChange?: (isOpen: boolean) => void\n}\n\n/**\n * What a surface's trigger part hands its content: the open state, and the\n * button that last opened it, for focus to return to.\n */\ntype ModalTrigger = {\n readonly state: OverlayTriggerState\n readonly trigger: HostInstance | null\n}\n\ntype ModalWindowProps = {\n readonly children?: ReactNode\n /** Whether Android's back gesture and Escape on web leave it open. */\n readonly isKeyboardDismissDisabled: boolean\n /** The headline's id, which names the window on web. */\n readonly labelledBy: string | undefined\n /** What the back gesture and Escape call. */\n readonly onClose: () => void\n /** What a press on the scrim calls, or nothing where it closes nothing. */\n readonly onScrimPress: (() => void) | undefined\n /** The scrim's motion. */\n readonly scrim: AnimatedStyle<ViewStyle>\n /** The headline, which a screen reader is sent to once the window shows. */\n readonly title: HostInstance | null\n}\n\n// Sends the screen reader to the headline once the window has shown. React\n// Native Web's `Modal` moves focus into itself.\nfunction focusOf(title: HostInstance | null) {\n return () => {\n if (title !== null && Platform.OS !== 'web') {\n AccessibilityInfo.sendAccessibilityEvent(title, 'focus')\n }\n }\n}\n\n// What the back gesture does on a surface it may not close: nothing, rather\n// than leaving the handler out, which Android warns about.\nfunction ignore() {}\n\n// The safe area as padding. The insets are physical edges, and React Native\n// swaps a left and a right style under a right-to-left layout, so they are\n// handed over as the start and end they are in the direction the layout runs.\nfunction insetsOf(insets: EdgeInsets): ViewStyle {\n const rtl = I18nManager.isRTL\n\n return {\n paddingBottom: insets.bottom,\n paddingEnd: rtl ? insets.left : insets.right,\n paddingStart: rtl ? insets.right : insets.left,\n paddingTop: insets.top,\n }\n}\n\n/**\n * The window a modal surface is drawn in: the `Modal`, the overlays it hosts,\n * and the scrim, with the surface itself as its children.\n */\nfunction ModalWindow({\n children,\n isKeyboardDismissDisabled,\n labelledBy,\n onClose,\n onScrimPress,\n scrim,\n title,\n}: ModalWindowProps) {\n const styles = stylesOf(useTheme())\n\n return (\n <Modal\n animationType=\"none\"\n aria-labelledby={Platform.OS === 'web' ? labelledBy : undefined}\n navigationBarTranslucent\n onRequestClose={isKeyboardDismissDisabled ? ignore : onClose}\n onShow={focusOf(title)}\n statusBarTranslucent\n supportedOrientations={ORIENTATIONS}\n transparent\n visible\n >\n {/* Nothing in the window takes the trigger's slot, the overlays it\n hosts included, so a button in a snackbar raised from the surface\n opens nothing; only the surface's buttons take the close slot. */}\n <ButtonSlotContext value={null}>\n <OverlayHost>\n {/* A screen reader and a keyboard skip the scrim: the first closes\n the surface with the back or escape gesture, the second with\n Escape. React Native Web's Pressable is a tab stop unless told\n otherwise, whatever `focusable` says. */}\n <AnimatedPressable\n accessible={false}\n aria-hidden\n focusable={false}\n onPress={onScrimPress}\n style={composeStyles<AnimatedStyle<ViewStyle>>(styles.scrim, scrim)}\n tabIndex={-1}\n />\n {children}\n </OverlayHost>\n </ButtonSlotContext>\n </Modal>\n )\n}\n\n// The surface's role and name on iOS and Android. On web React Native Web's\n// `Modal` is the dialog element, so the surface takes neither there.\nfunction panelRoleOf(\n role: 'alertdialog' | 'dialog',\n labelledBy: string | undefined,\n): Pick<ViewProps, 'aria-labelledby' | 'aria-modal' | 'role'> {\n if (Platform.OS === 'web') {\n return {}\n }\n\n return { 'aria-labelledby': labelledBy, 'aria-modal': true, role }\n}\n\n// Every ref a node is handed to, the part's own and the call site's.\nfunction refsOf<T>(own: (node: null | T) => void, other: Ref<T> | undefined) {\n return (node: null | T) => {\n own(node)\n if (typeof other === 'function') {\n other(node)\n } else if (other !== null && other !== undefined) {\n other.current = node\n }\n }\n}\n\n// Counts each part as it mounts and unmounts, so the parts around it know\n// which of them are there.\nfunction registerOf<Part extends string>(\n setParts: (\n update: (\n parts: Readonly<Record<Part, number>>,\n ) => Readonly<Record<Part, number>>,\n ) => void,\n) {\n return (part: Part) => {\n setParts((parts) => ({ ...parts, [part]: parts[part] + 1 }))\n\n return () => {\n setParts((parts) => ({ ...parts, [part]: parts[part] - 1 }))\n }\n }\n}\n\n/**\n * The open state a surface's content part reads: its trigger's, inside one,\n * and its own otherwise. `present` stays true from the moment it opens until\n * the call site's exit has run and set it false, and the close slot and the\n * scrim close it through `close`.\n */\nfunction useModalState(outer: ModalTrigger | null, props: ModalOpenProps) {\n const own = useOverlayTriggerState(props)\n const state = outer?.state ?? own\n const [present, setPresent] = useState(state.isOpen)\n const close = useCallback(() => {\n state.close()\n }, [state])\n const slots = useMemo<ButtonSlots>(() => ({ close }), [close])\n\n // Mounted the moment it opens, and kept until its exit has run.\n if (state.isOpen && !present) {\n setPresent(true)\n }\n\n useReturnFocus(present, outer)\n\n return { close, present, setPresent, slots, state }\n}\n\n/**\n * The open state a surface's trigger part holds, and the default slot a\n * button inside it fills: it records itself as the button focus returns to,\n * and opens the surface. React Native types the target as a bare view tag\n * too, which focus cannot be sent to, so such a press records nothing.\n */\nfunction useModalTrigger(props: ModalOpenProps) {\n const state = useOverlayTriggerState(props)\n const [trigger, setTrigger] = useState<HostInstance | null>(null)\n const context = useMemo<ModalTrigger>(\n () => ({ state, trigger }),\n [state, trigger],\n )\n const slots = useMemo<ButtonSlots>(\n () => ({\n default: (event: GestureResponderEvent) => {\n const target = event.currentTarget\n\n setTrigger(typeof target === 'number' ? null : target)\n state.open()\n },\n }),\n [state],\n )\n\n return { context, slots }\n}\n\n// Sends the screen reader back to the button that opened the surface once it\n// has gone. React Native Web's `Modal` restores focus itself.\nfunction useReturnFocus(present: boolean, outer: ModalTrigger | null) {\n const shown = useRef(present)\n\n useEffect(() => {\n const trigger = outer?.trigger ?? null\n const gone = shown.current && !present\n\n shown.current = present\n if (gone && trigger !== null && Platform.OS !== 'web') {\n AccessibilityInfo.sendAccessibilityEvent(trigger, 'focus')\n }\n }, [outer, present])\n}\n\nexport {\n insetsOf,\n ModalWindow,\n NO_INSETS,\n panelRoleOf,\n refsOf,\n registerOf,\n useModalState,\n useModalTrigger,\n}\nexport type { ModalOpenProps, ModalTrigger }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["ReactNode","GestureResponderEvent","HostInstance","ModalProps","ViewProps","ViewStyle","AnimatedStyle","EdgeInsets","OverlayTriggerState","useCallback","useEffect","useMemo","useRef","useState","AccessibilityInfo","I18nManager","Modal","Platform","StyleSheet","useOverlayTriggerState","ButtonSlots","ResolvedTheme","AnimatedPressable","ButtonSlotContext","OverlayHost","withOpacity","useTheme","composeStyles","themedStyles","NO_INSETS","bottom","left","right","top","ORIENTATIONS","SCRIM_OPACITY","stylesOf","colors","create","scrim","backgroundColor","position","ModalOpenProps","defaultOpen","isOpen","onOpenChange","ModalTrigger","state","trigger","ModalWindowProps","children","isKeyboardDismissDisabled","labelledBy","onClose","onScrimPress","title","focusOf","OS","sendAccessibilityEvent","ignore","insetsOf","insets","rtl","isRTL","paddingBottom","paddingEnd","paddingStart","paddingTop","ModalWindow","t0","$","_c","styles","T0","t1","t2","undefined","t3","t4","t5","t6","t8","t9","T1","t10","T2","T3","t11","t12","t13","t14","t15","t16","t17","t18","t7","panelRoleOf","role","Pick","registerOf","setParts","update","parts","Readonly","Record","Part","part","useModalState","outer","props","own","present","setPresent","close","slots","useReturnFocus","useModalTrigger","setTrigger","context","default","event","target","currentTarget","open","shown","gone","current","_c"],"sources":["../../src/modal/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport type {\n GestureResponderEvent,\n HostInstance,\n ModalProps,\n ViewProps,\n ViewStyle,\n} from 'react-native'\nimport type { AnimatedStyle } from 'react-native-reanimated'\nimport type { EdgeInsets } from 'react-native-safe-area-context'\nimport type { OverlayTriggerState } from 'react-stately/useOverlayTriggerState'\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport {\n AccessibilityInfo,\n I18nManager,\n Modal,\n Platform,\n StyleSheet,\n} from 'react-native'\nimport { useOverlayTriggerState } from 'react-stately/useOverlayTriggerState'\n\nimport type { ButtonSlots } from '../button/slots'\nimport type { ResolvedTheme } from '../theme/scope'\n\nimport { AnimatedPressable } from '../button'\nimport { ButtonSlotContext } from '../button/slots'\nimport { OverlayHost } from '../overlay'\nimport { withOpacity } from '../theme/color'\nimport { useTheme } from '../theme/scope'\nimport { composeStyles, themedStyles } from '../theme/styles'\n\n// The window a modal surface is drawn in, and what a dialog and a sheet share\n// around it: the trigger that opens it, the open state, the scrim, and where\n// focus goes as it shows and once it has gone. Internal: nothing here is\n// exported from the package.\n//\n// **It is a React Native `Modal`**, which keeps React context, so the surface\n// keeps the `ThemeScope` around it, and which is a window of its own on iOS\n// and Android, above the screen and its overlays. The window therefore hosts\n// overlays of its own, so a snackbar or a popover raised from inside it draws\n// above it rather than under it.\n\n// Outside a SafeAreaProvider the insets are unknown, and the window's own edge\n// is the best bound there is.\nconst NO_INSETS: EdgeInsets = { bottom: 0, left: 0, right: 0, top: 0 }\n\n// iOS presents a `Modal` in portrait alone unless told otherwise, which would\n// turn an app held sideways round as the surface opened.\nconst ORIENTATIONS: ModalProps['supportedOrientations'] = [\n 'portrait',\n 'portrait-upside-down',\n 'landscape',\n 'landscape-left',\n 'landscape-right',\n]\n\n// The scrim is the scrim role at 32%, the opacity Material Design gives a\n// modal's scrim and web mixes in.\nconst SCRIM_OPACITY = 0.32\n\nconst stylesOf = themedStyles(({ colors }: ResolvedTheme) =>\n StyleSheet.create({\n scrim: {\n backgroundColor: withOpacity(colors.scrim, SCRIM_OPACITY),\n bottom: 0,\n left: 0,\n position: 'absolute',\n right: 0,\n top: 0,\n },\n }),\n)\n\n/** Whether a modal surface is open, and who holds that state. */\ntype ModalOpenProps = {\n readonly defaultOpen?: boolean\n readonly isOpen?: boolean\n readonly onOpenChange?: (isOpen: boolean) => void\n}\n\n/**\n * What a surface's trigger part hands its content: the open state, and the\n * button that last opened it, for focus to return to.\n */\ntype ModalTrigger = {\n readonly state: OverlayTriggerState\n readonly trigger: HostInstance | null\n}\n\ntype ModalWindowProps = {\n readonly children?: ReactNode\n /** Whether Android's back gesture and Escape on web leave it open. */\n readonly isKeyboardDismissDisabled: boolean\n /** The headline's id, which names the window on web. */\n readonly labelledBy: string | undefined\n /** What the back gesture and Escape call. */\n readonly onClose: () => void\n /** What a press on the scrim calls, or nothing where it closes nothing. */\n readonly onScrimPress: (() => void) | undefined\n /** The scrim's motion. */\n readonly scrim: AnimatedStyle<ViewStyle>\n /** The headline, which a screen reader is sent to once the window shows. */\n readonly title: HostInstance | null\n}\n\n// Sends the screen reader to the headline once the window has shown. React\n// Native Web's `Modal` moves focus into itself.\nfunction focusOf(title: HostInstance | null) {\n return () => {\n if (title !== null && Platform.OS !== 'web') {\n AccessibilityInfo.sendAccessibilityEvent(title, 'focus')\n }\n }\n}\n\n// What the back gesture does on a surface it may not close: nothing, rather\n// than leaving the handler out, which Android warns about.\nfunction ignore() {}\n\n// The safe area as padding. The insets are physical edges, and React Native\n// swaps a left and a right style under a right-to-left layout, so they are\n// handed over as the start and end they are in the direction the layout runs.\nfunction insetsOf(insets: EdgeInsets): ViewStyle {\n const rtl = I18nManager.isRTL\n\n return {\n paddingBottom: insets.bottom,\n paddingEnd: rtl ? insets.left : insets.right,\n paddingStart: rtl ? insets.right : insets.left,\n paddingTop: insets.top,\n }\n}\n\n/**\n * The window a modal surface is drawn in: the `Modal`, the overlays it hosts,\n * and the scrim, with the surface itself as its children.\n */\nfunction ModalWindow({\n children,\n isKeyboardDismissDisabled,\n labelledBy,\n onClose,\n onScrimPress,\n scrim,\n title,\n}: ModalWindowProps) {\n const styles = stylesOf(useTheme())\n\n return (\n <Modal\n animationType=\"none\"\n aria-labelledby={Platform.OS === 'web' ? labelledBy : undefined}\n navigationBarTranslucent\n onRequestClose={isKeyboardDismissDisabled ? ignore : onClose}\n onShow={focusOf(title)}\n statusBarTranslucent\n supportedOrientations={ORIENTATIONS}\n transparent\n visible\n >\n {/* Nothing in the window takes the trigger's slot, the overlays it\n hosts included, so a button in a snackbar raised from the surface\n opens nothing; only the surface's buttons take the close slot. */}\n <ButtonSlotContext value={null}>\n <OverlayHost>\n {/* A screen reader and a keyboard skip the scrim: the first closes\n the surface with the back or escape gesture, the second with\n Escape. React Native Web's Pressable is a tab stop unless told\n otherwise, whatever `focusable` says. */}\n <AnimatedPressable\n accessible={false}\n aria-hidden\n focusable={false}\n onPress={onScrimPress}\n style={composeStyles<AnimatedStyle<ViewStyle>>(styles.scrim, scrim)}\n tabIndex={-1}\n />\n {children}\n </OverlayHost>\n </ButtonSlotContext>\n </Modal>\n )\n}\n\n// The surface's role and name on iOS and Android. On web React Native Web's\n// `Modal` is the dialog element, so the surface takes neither there.\nfunction panelRoleOf(\n role: 'alertdialog' | 'dialog',\n labelledBy: string | undefined,\n): Pick<ViewProps, 'aria-labelledby' | 'aria-modal' | 'role'> {\n if (Platform.OS === 'web') {\n return {}\n }\n\n return { 'aria-labelledby': labelledBy, 'aria-modal': true, role }\n}\n\n// Counts each part as it mounts and unmounts, so the parts around it know\n// which of them are there.\nfunction registerOf<Part extends string>(\n setParts: (\n update: (\n parts: Readonly<Record<Part, number>>,\n ) => Readonly<Record<Part, number>>,\n ) => void,\n) {\n return (part: Part) => {\n setParts((parts) => ({ ...parts, [part]: parts[part] + 1 }))\n\n return () => {\n setParts((parts) => ({ ...parts, [part]: parts[part] - 1 }))\n }\n }\n}\n\n/**\n * The open state a surface's content part reads: its trigger's, inside one,\n * and its own otherwise. `present` stays true from the moment it opens until\n * the call site's exit has run and set it false, and the close slot and the\n * scrim close it through `close`.\n */\nfunction useModalState(outer: ModalTrigger | null, props: ModalOpenProps) {\n const own = useOverlayTriggerState(props)\n const state = outer?.state ?? own\n const [present, setPresent] = useState(state.isOpen)\n const close = useCallback(() => {\n state.close()\n }, [state])\n const slots = useMemo<ButtonSlots>(() => ({ close }), [close])\n\n // Mounted the moment it opens, and kept until its exit has run.\n if (state.isOpen && !present) {\n setPresent(true)\n }\n\n useReturnFocus(present, outer)\n\n return { close, present, setPresent, slots, state }\n}\n\n/**\n * The open state a surface's trigger part holds, and the default slot a\n * button inside it fills: it records itself as the button focus returns to,\n * and opens the surface. React Native types the target as a bare view tag\n * too, which focus cannot be sent to, so such a press records nothing.\n */\nfunction useModalTrigger(props: ModalOpenProps) {\n const state = useOverlayTriggerState(props)\n const [trigger, setTrigger] = useState<HostInstance | null>(null)\n const context = useMemo<ModalTrigger>(\n () => ({ state, trigger }),\n [state, trigger],\n )\n const slots = useMemo<ButtonSlots>(\n () => ({\n default: (event: GestureResponderEvent) => {\n const target = event.currentTarget\n\n setTrigger(typeof target === 'number' ? null : target)\n state.open()\n },\n }),\n [state],\n )\n\n return { context, slots }\n}\n\n// Sends the screen reader back to the button that opened the surface once it\n// has gone. React Native Web's `Modal` restores focus itself.\nfunction useReturnFocus(present: boolean, outer: ModalTrigger | null) {\n const shown = useRef(present)\n\n useEffect(() => {\n const trigger = outer?.trigger ?? null\n const gone = shown.current && !present\n\n shown.current = present\n if (gone && trigger !== null && Platform.OS !== 'web') {\n AccessibilityInfo.sendAccessibilityEvent(trigger, 'focus')\n }\n }, [outer, present])\n}\n\nexport {\n insetsOf,\n ModalWindow,\n NO_INSETS,\n panelRoleOf,\n registerOf,\n useModalState,\n useModalTrigger,\n}\nexport type { ModalOpenProps, ModalTrigger }\n"],"mappings":";;;;;;;;;;;;AA6CA,MAAM6B,YAAwB;CAAEC,QAAQ;CAAGC,MAAM;CAAGC,OAAO;CAAGC,KAAK;AAAE;AAIrE,MAAMC,eAAoD;CACxD;CACA;CACA;CACA;CACA;AAAiB;AAKnB,MAAMC,gBAAgB;AAEtB,MAAMC,WAAWR,cAAc,EAAES,aAC/BnB,WAAWoB,OAAO,EAChBC,OAAO;CACLC,iBAAiBf,YAAYY,OAAOE,OAAOJ,aAAa;CACxDL,QAAQ;CACRC,MAAM;CACNU,UAAU;CACVT,OAAO;CACPC,KAAK;AACP,EACF,CAAC,CACH;AAoCA,SAASuB,QAAQD,OAA4B;CAC3C,aAAa;EACX,IAAIA,UAAU,QAAQtC,SAASwC,OAAO,OACpC3C,kBAAkB4C,uBAAuBH,OAAO,OAAO;CAE3D;AACF;AAIA,SAASI,SAAS,CAAC;AAKnB,SAASC,SAASC,QAA+B;CAC/C,MAAMC,MAAM/C,YAAYgD;CAExB,OAAO;EACLC,eAAeH,OAAO/B;EACtBmC,YAAYH,MAAMD,OAAO9B,OAAO8B,OAAO7B;EACvCkC,cAAcJ,MAAMD,OAAO7B,QAAQ6B,OAAO9B;EAC1CoC,YAAYN,OAAO5B;CACrB;AACF;;;;;AAMA,SAAAmC,YAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAqB,MAAA,EAAArB,UAAAC,2BAAAC,YAAAC,SAAAC,cAAAf,OAAAgB,UAAAc;CASnB,MAAAG,SAAepC,SAASV,SAAS,CAAC;CAG/B,MAAA+C,KAAAzD;CACe,MAAA0D,KAAA;CACG,MAAAC,KAAA1D,SAAQwC,OAAQ,QAAhBL,aAAAwB,KAAAA;CACjB,MAAAC,KAAA;CACgB,MAAAC,KAAA3B,4BAAAQ,SAAAN;CAA4C,IAAA0B;CAAA,IAAAT,EAAA,OAAAf,OAAA;EACpDwB,KAAAvB,QAAQD,KAAK;EAACe,EAAA,KAAAf;EAAAe,EAAA,KAAAS;CAAA,OAAAA,KAAAT,EAAA;CACtB,MAAAU,KAAA;CACuB9C,MAAAA,KAAAA;CACvB,MAAA+C,KAAA;CACA,MAAAC,KAAA;CAKC,MAAAC,KAAA5D;CAAyB,MAAA6D,MAAA;CACvB,MAAAC,KAAA7D;CAKE,MAAA8D,KAAAhE;CACa,MAAAiE,MAAA;CACZ,MAAAC,MAAA;CACW,MAAAC,MAAA;CAEJ,MAAAC,MAAA/D,cAAwC6C,OAAMjC,OAAQA,KAAK;CAAC,IAAAoD;CAAA,IAAArB,EAAA,OAAAgB,MAAAhB,EAAA,OAAAhB,gBAAAgB,EAAA,OAAAoB,KAAA;EALrEC,MAAA,oBAAC,IAAD;GACc,YAAAJ;GACZ,eAAAC;GACW,WAAAC;GACFnC,SAAAA;GACF,OAAAoC;GACG,UAAA;EAAE,CAAA;EACZpB,EAAA,KAAAgB;EAAAhB,EAAA,KAAAhB;EAAAgB,EAAA,KAAAoB;EAAApB,EAAA,KAAAqB;CAAA,OAAAA,MAAArB,EAAA;CAAA,IAAAsB;CAAA,IAAAtB,EAAA,OAAAe,MAAAf,EAAA,OAAApB,YAAAoB,EAAA,OAAAqB,KAAA;EAZJC,MAAA,qBAAC,IAAD,EAAA,UAAA,CAKED,KAQCzC,QAbS,EAAA,CAAA;EAcEoB,EAAA,KAAAe;EAAAf,EAAA,KAAApB;EAAAoB,EAAA,KAAAqB;EAAArB,EAAA,KAAAsB;CAAA,OAAAA,MAAAtB,EAAA;CAAA,IAAAuB;CAAA,IAAAvB,EAAA,QAAAa,MAAAb,EAAA,QAAAsB,KAAA;EAfhBC,MAAA,oBAAC,IAAD;GAA0B,OAAAT;GACxBQ,UAAAA;EADgB,CAAA;EAgBEtB,EAAA,MAAAa;EAAAb,EAAA,MAAAsB;EAAAtB,EAAA,MAAAuB;CAAA,OAAAA,MAAAvB,EAAA;CAAA,IAAAwB;CAAA,IAAAxB,EAAA,QAAAG,MAAAH,EAAA,QAAAuB,OAAAvB,EAAA,QAAAK,MAAAL,EAAA,QAAAQ,MAAAR,EAAA,QAAAS,MAAAT,EAAA,QAAAyB,IAAA;EA9BtBD,MAAA,oBAAC,IAAD;GACgB,eAAApB;GACG,mBAAAC;GACjB,0BAAAE;GACgB,gBAAAC;GACR,QAAAC;GACR,sBAAAC;GACuB9C,uBAAAA;GACvB,aAAA+C;GACA,SAAAC;GAKAW,UAAAA;EAdI,CAAA;EA+BEvB,EAAA,MAAAG;EAAAH,EAAA,MAAAuB;EAAAvB,EAAA,MAAAK;EAAAL,EAAA,MAAAQ;EAAAR,EAAA,MAAAS;EAAAT,EAAA,MAAAyB;EAAAzB,EAAA,MAAAwB;CAAA,OAAAA,MAAAxB,EAAA;CAAA,OA/BRwB;AA+BQ;AAMZ,SAASE,YACPC,MACA7C,YAC4D;CAC5D,IAAInC,SAASwC,OAAO,OAClB,OAAO,CAAC;CAGV,OAAO;EAAE,mBAAmBL;EAAY,cAAc;EAAM6C;CAAK;AACnE;AAIA,SAASE,WACPC,UAKA;CACA,QAAQM,SAAe;EACrBN,UAAUE,WAAW;GAAE,GAAGA;IAAQI,OAAOJ,MAAMI,QAAQ;EAAE,EAAE;EAE3D,aAAa;GACXN,UAAUE,WAAW;IAAE,GAAGA;KAAQI,OAAOJ,MAAMI,QAAQ;GAAE,EAAE;EAC7D;CACF;AACF;;;;;;;AAQA,SAAAC,cAAAC,OAAAC,OAAA;CAAA,MAAAvC,IAAAC,EAAA,CAAA;CACE,MAAAuC,MAAY3F,uBAAuB0F,KAAK;CACxC,MAAA9D,QAAc6D,OAAK7D,SAAL+D;CACd,MAAA,CAAAC,SAAAC,cAA8BnG,SAASkC,MAAKH,MAAO;CAAC,IAAAyB;CAAA,IAAAC,EAAA,OAAAvB,OAAA;EAC1BsB,WAAA;GACxBtB,MAAKkE,MAAO;EAAC;EACd3C,EAAA,KAAAvB;EAAAuB,EAAA,KAAAD;CAAA,OAAAA,KAAAC,EAAA;CAFD,MAAA2C,QAAc5C;CAEH,IAAAK;CAAA,IAAAJ,EAAA,OAAA2C,OAAA;EAC+BvC,KAAA,EAAAuC,MAAQ;EAAC3C,EAAA,KAAA2C;EAAA3C,EAAA,KAAAI;CAAA,OAAAA,KAAAJ,EAAA;CAAnD,MAAA4C,QAA0CxC;CAG1C,IAAI3B,MAAKH,UAAL,CAAiBmE,SACnBC,WAAW,IAAI;CAGjBG,eAAeJ,SAASH,KAAK;CAAC,IAAAjC;CAAA,IAAAL,EAAA,OAAA2C,SAAA3C,EAAA,OAAAyC,WAAAzC,EAAA,OAAA4C,SAAA5C,EAAA,OAAAvB,OAAA;EAEvB4B,KAAA;GAAAsC;GAAAF;GAAAC;GAAAE;GAAAnE;EAA2C;EAACuB,EAAA,KAAA2C;EAAA3C,EAAA,KAAAyC;EAAAzC,EAAA,KAAA4C;EAAA5C,EAAA,KAAAvB;EAAAuB,EAAA,KAAAK;CAAA,OAAAA,KAAAL,EAAA;CAAA,OAA5CK;AAA4C;;;;;;;AASrD,SAAAyC,gBAAAP,OAAA;CAAA,MAAAvC,IAAAC,EAAA,CAAA;CACE,MAAAxB,QAAc5B,uBAAuB0F,KAAK;CAC1C,MAAA,CAAA7D,SAAAqE,cAA8BxG,SAA8B,IAAI;CAAC,IAAAwD;CAAA,IAAAC,EAAA,OAAAvB,SAAAuB,EAAA,OAAAtB,SAAA;EAExDqB,KAAA;GAAAtB;GAAAC;EAAiB;EAACsB,EAAA,KAAAvB;EAAAuB,EAAA,KAAAtB;EAAAsB,EAAA,KAAAD;CAAA,OAAAA,KAAAC,EAAA;CAD3B,MAAAgD,UACSjD;CAER,IAAAK;CAAA,IAAAJ,EAAA,OAAAvB,OAAA;EAEQ2B,KAAA,EAAA6C,UACIC,UAAA;GACP,MAAAC,SAAeD,MAAKE;GAEpBL,WAAW,OAAOI,WAAW,WAAlB,OAAAA,MAA0C;GACrD1E,MAAK4E,KAAM;EAAC,EAEhB;EAACrD,EAAA,KAAAvB;EAAAuB,EAAA,KAAAI;CAAA,OAAAA,KAAAJ,EAAA;CARH,MAAA4C,QACSxC;CASR,IAAAC;CAAA,IAAAL,EAAA,OAAAgD,WAAAhD,EAAA,OAAA4C,OAAA;EAEMvC,KAAA;GAAA2C;GAAAJ;EAAiB;EAAC5C,EAAA,KAAAgD;EAAAhD,EAAA,KAAA4C;EAAA5C,EAAA,KAAAK;CAAA,OAAAA,KAAAL,EAAA;CAAA,OAAlBK;AAAkB;AAK3B,SAAAwC,eAAAJ,SAAAH,OAAA;CAAA,MAAAtC,IAAAC,EAAA,CAAA;CACE,MAAAqD,QAAchH,OAAOmG,OAAO;CAAC,IAAA1C;CAAA,IAAAC,EAAA,OAAAsC,OAAA5D,WAAAsB,EAAA,OAAAyC,SAAA;EAEnB1C,WAAA;GACR,MAAArB,UAAgB4D,OAAK5D,WAAL;GAChB,MAAA6E,OAAaD,MAAKE,WAAL,CAAkBf;GAE/Ba,MAAKE,UAAWf;GAChB,IAAIc,QAAQ7E,YAAY,QAAQ/B,SAAQwC,OAAQ,OAC9C3C,kBAAiB4C,uBAAwBV,SAAS,OAAO;EAC1D;EACFsB,EAAA,KAAAsC,OAAA5D;EAAAsB,EAAA,KAAAyC;EAAAzC,EAAA,KAAAD;CAAA,OAAAA,KAAAC,EAAA;CAAA,IAAAI;CAAA,IAAAJ,EAAA,OAAAsC,SAAAtC,EAAA,OAAAyC,SAAA;EAAErC,KAAA,CAACkC,OAAOG,OAAO;EAACzC,EAAA,KAAAsC;EAAAtC,EAAA,KAAAyC;EAAAzC,EAAA,KAAAI;CAAA,OAAAA,KAAAJ,EAAA;CARnB5D,UAAU2D,IAQPK,EAAgB;AAAC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { useTheme } from "../theme/scope.js";
|
|
2
|
+
import { OverlayHostContext } from "./host.js";
|
|
3
|
+
import { boundsOf, place } from "./placement.js";
|
|
4
|
+
import { c } from "react/compiler-runtime";
|
|
5
|
+
import { use, useEffect, useState } from "react";
|
|
6
|
+
import { Dimensions, I18nManager, useWindowDimensions } from "react-native";
|
|
7
|
+
import { SafeAreaInsetsContext } from "react-native-safe-area-context";
|
|
8
|
+
//#region src/overlay/anchored.ts
|
|
9
|
+
const HIDDEN = {
|
|
10
|
+
left: 0,
|
|
11
|
+
opacity: 0,
|
|
12
|
+
pointerEvents: "none",
|
|
13
|
+
position: "absolute",
|
|
14
|
+
top: 0
|
|
15
|
+
};
|
|
16
|
+
const NO_INSETS = {
|
|
17
|
+
bottom: 0,
|
|
18
|
+
left: 0,
|
|
19
|
+
right: 0,
|
|
20
|
+
top: 0
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Places a surface drawn in an `Overlay` beside the view that opened it, as
|
|
24
|
+
* web's anchored overlays are placed: on `side`, lined up by `align`, flipped
|
|
25
|
+
* to the opposite side at the edge of the window, and kept inside the safe
|
|
26
|
+
* area's insets with `spacing.md` to spare, the padding React Aria keeps from
|
|
27
|
+
* the edge of the viewport. On `top` and `bottom`, `start` and `end` follow
|
|
28
|
+
* `I18nManager.isRTL`.
|
|
29
|
+
*
|
|
30
|
+
* The anchor is measured with `measureInWindow` whenever the surface reports
|
|
31
|
+
* a new size or the window changes size.
|
|
32
|
+
*/
|
|
33
|
+
function useAnchoredPlacement(t0) {
|
|
34
|
+
const $ = c(31);
|
|
35
|
+
const { align: t1, alignOffset: t2, anchor, side: t3, sideOffset } = t0;
|
|
36
|
+
const align = t1 === void 0 ? "center" : t1;
|
|
37
|
+
const alignOffset = t2 === void 0 ? 0 : t2;
|
|
38
|
+
const side = t3 === void 0 ? "bottom" : t3;
|
|
39
|
+
const store = use(OverlayHostContext);
|
|
40
|
+
const { spacing } = useTheme();
|
|
41
|
+
const window = useWindowDimensions();
|
|
42
|
+
const insets = use(SafeAreaInsetsContext) ?? NO_INSETS;
|
|
43
|
+
const [measured, setMeasured] = useState(null);
|
|
44
|
+
const [surface, setSurface] = useState(null);
|
|
45
|
+
let t4;
|
|
46
|
+
if ($[0] !== anchor.current || $[1] !== store || $[2] !== surface) {
|
|
47
|
+
t4 = () => {
|
|
48
|
+
const measure = () => {
|
|
49
|
+
const layer = store?.layer() ?? null;
|
|
50
|
+
const target = anchor.current;
|
|
51
|
+
if (surface === null || layer === null || target === null) return;
|
|
52
|
+
layer.measureInWindow((originX, originY) => {
|
|
53
|
+
target.measureInWindow((x, y, width, height) => {
|
|
54
|
+
setMeasured({
|
|
55
|
+
anchor: {
|
|
56
|
+
height,
|
|
57
|
+
width,
|
|
58
|
+
x,
|
|
59
|
+
y
|
|
60
|
+
},
|
|
61
|
+
origin: {
|
|
62
|
+
x: originX,
|
|
63
|
+
y: originY
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
measure();
|
|
70
|
+
const subscription = Dimensions.addEventListener("change", measure);
|
|
71
|
+
return () => {
|
|
72
|
+
subscription.remove();
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
$[0] = anchor.current;
|
|
76
|
+
$[1] = store;
|
|
77
|
+
$[2] = surface;
|
|
78
|
+
$[3] = t4;
|
|
79
|
+
} else t4 = $[3];
|
|
80
|
+
let t5;
|
|
81
|
+
if ($[4] !== anchor || $[5] !== store || $[6] !== surface) {
|
|
82
|
+
t5 = [
|
|
83
|
+
anchor,
|
|
84
|
+
store,
|
|
85
|
+
surface
|
|
86
|
+
];
|
|
87
|
+
$[4] = anchor;
|
|
88
|
+
$[5] = store;
|
|
89
|
+
$[6] = surface;
|
|
90
|
+
$[7] = t5;
|
|
91
|
+
} else t5 = $[7];
|
|
92
|
+
useEffect(t4, t5);
|
|
93
|
+
let t6;
|
|
94
|
+
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
|
|
95
|
+
t6 = (event) => {
|
|
96
|
+
const { height: height_0, width: width_0 } = event.nativeEvent.layout;
|
|
97
|
+
setSurface((known) => known?.height === height_0 && known.width === width_0 ? known : {
|
|
98
|
+
height: height_0,
|
|
99
|
+
width: width_0
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
$[8] = t6;
|
|
103
|
+
} else t6 = $[8];
|
|
104
|
+
const onLayout = t6;
|
|
105
|
+
if (measured === null || surface === null) {
|
|
106
|
+
let t7;
|
|
107
|
+
if ($[9] !== side) {
|
|
108
|
+
t7 = {
|
|
109
|
+
onLayout,
|
|
110
|
+
placed: false,
|
|
111
|
+
side,
|
|
112
|
+
style: HIDDEN
|
|
113
|
+
};
|
|
114
|
+
$[9] = side;
|
|
115
|
+
$[10] = t7;
|
|
116
|
+
} else t7 = $[10];
|
|
117
|
+
return t7;
|
|
118
|
+
}
|
|
119
|
+
let t7;
|
|
120
|
+
if ($[11] !== align || $[12] !== alignOffset || $[13] !== insets || $[14] !== measured.anchor || $[15] !== side || $[16] !== sideOffset || $[17] !== spacing.md || $[18] !== spacing.sm || $[19] !== surface || $[20] !== window) {
|
|
121
|
+
t7 = place({
|
|
122
|
+
align,
|
|
123
|
+
alignOffset,
|
|
124
|
+
anchor: measured.anchor,
|
|
125
|
+
bounds: boundsOf(window, insets, spacing.md),
|
|
126
|
+
rtl: I18nManager.isRTL,
|
|
127
|
+
side,
|
|
128
|
+
sideOffset: sideOffset ?? spacing.sm,
|
|
129
|
+
surface
|
|
130
|
+
});
|
|
131
|
+
$[11] = align;
|
|
132
|
+
$[12] = alignOffset;
|
|
133
|
+
$[13] = insets;
|
|
134
|
+
$[14] = measured.anchor;
|
|
135
|
+
$[15] = side;
|
|
136
|
+
$[16] = sideOffset;
|
|
137
|
+
$[17] = spacing.md;
|
|
138
|
+
$[18] = spacing.sm;
|
|
139
|
+
$[19] = surface;
|
|
140
|
+
$[20] = window;
|
|
141
|
+
$[21] = t7;
|
|
142
|
+
} else t7 = $[21];
|
|
143
|
+
const placement = t7;
|
|
144
|
+
const x_0 = placement.x - measured.origin.x;
|
|
145
|
+
const t8 = placement.y - measured.origin.y;
|
|
146
|
+
let t9;
|
|
147
|
+
if ($[22] !== x_0) {
|
|
148
|
+
t9 = I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL ? { right: x_0 } : { left: x_0 };
|
|
149
|
+
$[22] = x_0;
|
|
150
|
+
$[23] = t9;
|
|
151
|
+
} else t9 = $[23];
|
|
152
|
+
let t10;
|
|
153
|
+
if ($[24] !== placement.maxHeight || $[25] !== t8 || $[26] !== t9) {
|
|
154
|
+
t10 = {
|
|
155
|
+
maxHeight: placement.maxHeight,
|
|
156
|
+
position: "absolute",
|
|
157
|
+
top: t8,
|
|
158
|
+
...t9
|
|
159
|
+
};
|
|
160
|
+
$[24] = placement.maxHeight;
|
|
161
|
+
$[25] = t8;
|
|
162
|
+
$[26] = t9;
|
|
163
|
+
$[27] = t10;
|
|
164
|
+
} else t10 = $[27];
|
|
165
|
+
let t11;
|
|
166
|
+
if ($[28] !== placement.side || $[29] !== t10) {
|
|
167
|
+
t11 = {
|
|
168
|
+
onLayout,
|
|
169
|
+
placed: true,
|
|
170
|
+
side: placement.side,
|
|
171
|
+
style: t10
|
|
172
|
+
};
|
|
173
|
+
$[28] = placement.side;
|
|
174
|
+
$[29] = t10;
|
|
175
|
+
$[30] = t11;
|
|
176
|
+
} else t11 = $[30];
|
|
177
|
+
return t11;
|
|
178
|
+
}
|
|
179
|
+
//#endregion
|
|
180
|
+
export { useAnchoredPlacement };
|
|
181
|
+
|
|
182
|
+
//# sourceMappingURL=anchored.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchored.js","names":["RefObject","HostInstance","LayoutChangeEvent","ViewStyle","use","useEffect","useState","Dimensions","I18nManager","useWindowDimensions","SafeAreaInsetsContext","OverlayAlign","OverlaySide","Rect","Size","useTheme","OverlayHostContext","boundsOf","place","AnchoredPlacement","onLayout","event","placed","side","style","AnchoredPlacementOptions","align","alignOffset","anchor","Pick","sideOffset","Measured","origin","x","y","HIDDEN","left","opacity","pointerEvents","position","top","NO_INSETS","bottom","right","useAnchoredPlacement","t0","$","_c","t1","t2","t3","undefined","store","spacing","window","insets","measured","setMeasured","surface","setSurface","t4","current","measure","layer","target","measureInWindow","originX","originY","width","height","subscription","addEventListener","remove","t5","t6","Symbol","for","height_0","width_0","nativeEvent","layout","known","t7","md","sm","bounds","rtl","isRTL","placement","x_0","t8","t9","doLeftAndRightSwapInRTL","t10","maxHeight","t11","_c"],"sources":["../../src/overlay/anchored.ts"],"sourcesContent":["import type { RefObject } from 'react'\nimport type { HostInstance, LayoutChangeEvent, ViewStyle } from 'react-native'\n\nimport { use, useEffect, useState } from 'react'\nimport { Dimensions, I18nManager, useWindowDimensions } from 'react-native'\nimport { SafeAreaInsetsContext } from 'react-native-safe-area-context'\n\nimport type { OverlayAlign, OverlaySide, Rect, Size } from './placement'\n\nimport { useTheme } from '../theme/scope'\nimport { OverlayHostContext } from './host'\nimport { boundsOf, place } from './placement'\n\ntype AnchoredPlacement = {\n /**\n * Hand to the surface's own `onLayout`. The surface is placed once it has\n * reported its size, and placed again whenever that size changes.\n */\n readonly onLayout: (event: LayoutChangeEvent) => void\n /**\n * Whether the surface has been placed. Until it has, it is laid out out of\n * sight, and a screen reader cannot be sent to it.\n */\n readonly placed: boolean\n /** The side the surface opened on, which is the opposite one after a flip. */\n readonly side: OverlaySide\n /**\n * The surface's position in the overlay layer, and the height it may take.\n * Until it has been placed it is laid out out of sight, to be measured.\n */\n readonly style: ViewStyle\n}\n\ntype AnchoredPlacementOptions = {\n /**\n * Where the surface sits along the side it opens on.\n * @default 'center'\n */\n readonly align?: OverlayAlign | undefined\n /** Moves the surface along that side, in dp: right or down when positive. */\n readonly alignOffset?: number | undefined\n /** The view the surface opens beside. */\n readonly anchor: RefObject<null | Pick<HostInstance, 'measureInWindow'>>\n /**\n * Which side of the anchor the surface opens on. It flips to the opposite\n * side when there is no room.\n * @default 'bottom'\n */\n readonly side?: OverlaySide | undefined\n /**\n * The gap between the anchor and the surface, in dp.\n * @default spacing.sm\n */\n readonly sideOffset?: number | undefined\n}\n\ntype Measured = {\n readonly anchor: Rect\n /** Where the overlay layer starts in the window. */\n readonly origin: { readonly x: number; readonly y: number }\n}\n\nconst HIDDEN: ViewStyle = {\n left: 0,\n opacity: 0,\n pointerEvents: 'none',\n position: 'absolute',\n top: 0,\n}\n\n// Outside a SafeAreaProvider the insets are unknown, and the window's own edge\n// is the best bound there is.\nconst NO_INSETS = { bottom: 0, left: 0, right: 0, top: 0 }\n\n/**\n * Places a surface drawn in an `Overlay` beside the view that opened it, as\n * web's anchored overlays are placed: on `side`, lined up by `align`, flipped\n * to the opposite side at the edge of the window, and kept inside the safe\n * area's insets with `spacing.md` to spare, the padding React Aria keeps from\n * the edge of the viewport. On `top` and `bottom`, `start` and `end` follow\n * `I18nManager.isRTL`.\n *\n * The anchor is measured with `measureInWindow` whenever the surface reports\n * a new size or the window changes size.\n */\nfunction useAnchoredPlacement({\n align = 'center',\n alignOffset = 0,\n anchor,\n side = 'bottom',\n sideOffset,\n}: AnchoredPlacementOptions): AnchoredPlacement {\n const store = use(OverlayHostContext)\n const { spacing } = useTheme()\n const window = useWindowDimensions()\n const insets = use(SafeAreaInsetsContext) ?? NO_INSETS\n const [measured, setMeasured] = useState<Measured | null>(null)\n const [surface, setSurface] = useState<null | Size>(null)\n\n useEffect(() => {\n // The layer is measured as well as the anchor, since the host need not\n // start at the window's corner: the surface is placed in the layer, and\n // the anchor is measured in the window.\n const measure = () => {\n const layer = store?.layer() ?? null\n const target = anchor.current\n\n if (surface === null || layer === null || target === null) {\n return\n }\n\n layer.measureInWindow((originX, originY) => {\n target.measureInWindow((x, y, width, height) => {\n setMeasured({\n anchor: { height, width, x, y },\n origin: { x: originX, y: originY },\n })\n })\n })\n }\n\n measure()\n\n // A rotation or a resized window can move the anchor without the\n // surface changing size.\n const subscription = Dimensions.addEventListener('change', measure)\n\n return () => {\n subscription.remove()\n }\n }, [anchor, store, surface])\n\n const onLayout = (event: LayoutChangeEvent) => {\n const { height, width } = event.nativeEvent.layout\n\n setSurface((known) =>\n known?.height === height && known.width === width\n ? known\n : { height, width },\n )\n }\n\n if (measured === null || surface === null) {\n return { onLayout, placed: false, side, style: HIDDEN }\n }\n\n const placement = place({\n align,\n alignOffset,\n anchor: measured.anchor,\n bounds: boundsOf(window, insets, spacing.md),\n rtl: I18nManager.isRTL,\n side,\n sideOffset: sideOffset ?? spacing.sm,\n surface,\n })\n const x = placement.x - measured.origin.x\n\n return {\n onLayout,\n placed: true,\n side: placement.side,\n style: {\n maxHeight: placement.maxHeight,\n position: 'absolute',\n top: placement.y - measured.origin.y,\n // The placement is in physical coordinates, as `measureInWindow`\n // reports them. React Native swaps `left` and `right` in a right-to-left\n // layout unless an app turns that off, so there `right` is what puts\n // the surface's left edge where the placement says.\n ...(I18nManager.isRTL && I18nManager.doLeftAndRightSwapInRTL\n ? { right: x }\n : { left: x }),\n },\n }\n}\n\nexport type { AnchoredPlacement, AnchoredPlacementOptions }\n\nexport { useAnchoredPlacement }\n"],"mappings":"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"}
|
package/dist/overlay/host.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ScopeContext, useScope } from "../theme/scope.js";
|
|
2
2
|
import { c } from "react/compiler-runtime";
|
|
3
|
-
import { StyleSheet, View } from "react-native";
|
|
4
3
|
import { createContext, use, useId, useLayoutEffect, useState, useSyncExternalStore } from "react";
|
|
5
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { StyleSheet, View } from "react-native";
|
|
6
6
|
//#region src/overlay/host.tsx
|
|
7
7
|
const OverlayHostContext = createContext(null);
|
|
8
8
|
const styles = StyleSheet.create({ fill: {
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { useTheme } from "../theme/scope.js";
|
|
2
|
+
import { c } from "react/compiler-runtime";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { AccessibilityInfo, BackHandler, Platform, Pressable, StyleSheet } from "react-native";
|
|
6
|
+
import { Easing, useAnimatedStyle, useReducedMotion, useSharedValue, withTiming } from "react-native-reanimated";
|
|
7
|
+
//#region src/overlay/panel.tsx
|
|
8
|
+
const SCALE_FROM = .95;
|
|
9
|
+
/** The edge a panel grows from, the one facing its anchor. */
|
|
10
|
+
const PANEL_ORIGINS = {
|
|
11
|
+
bottom: "top",
|
|
12
|
+
left: "right",
|
|
13
|
+
right: "left",
|
|
14
|
+
top: "bottom"
|
|
15
|
+
};
|
|
16
|
+
const styles = StyleSheet.create({ layer: {
|
|
17
|
+
bottom: 0,
|
|
18
|
+
left: 0,
|
|
19
|
+
position: "absolute",
|
|
20
|
+
right: 0,
|
|
21
|
+
top: 0
|
|
22
|
+
} });
|
|
23
|
+
/**
|
|
24
|
+
* The layer a press outside a non-modal panel lands on, drawn just before the
|
|
25
|
+
* panel so it sits under it. The press goes no further, so a press on the
|
|
26
|
+
* trigger closes the panel rather than opening it again, as on web. Nothing
|
|
27
|
+
* but that press reaches it: React Native Web's Pressable is a tab stop
|
|
28
|
+
* unless told otherwise, whatever `focusable` says.
|
|
29
|
+
*/
|
|
30
|
+
function DismissLayer(t0) {
|
|
31
|
+
const $ = c(2);
|
|
32
|
+
const { onPress } = t0;
|
|
33
|
+
let t1;
|
|
34
|
+
if ($[0] !== onPress) {
|
|
35
|
+
t1 = /* @__PURE__ */ jsx(Pressable, {
|
|
36
|
+
accessible: false,
|
|
37
|
+
"aria-hidden": true,
|
|
38
|
+
focusable: false,
|
|
39
|
+
onPress,
|
|
40
|
+
style: styles.layer,
|
|
41
|
+
tabIndex: -1
|
|
42
|
+
});
|
|
43
|
+
$[0] = onPress;
|
|
44
|
+
$[1] = t1;
|
|
45
|
+
} else t1 = $[1];
|
|
46
|
+
return t1;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Closes a non-modal panel from Android's back gesture, as a `Modal` closes a
|
|
50
|
+
* modal one. React Native calls the latest listener first, so a panel opened
|
|
51
|
+
* from another closes before the one it came from. React Native Web has no
|
|
52
|
+
* back gesture, and its BackHandler reports an error when one is listened for,
|
|
53
|
+
* so nothing listens there.
|
|
54
|
+
*/
|
|
55
|
+
function useBackToClose(close, active) {
|
|
56
|
+
const $ = c(4);
|
|
57
|
+
let t0;
|
|
58
|
+
let t1;
|
|
59
|
+
if ($[0] !== active || $[1] !== close) {
|
|
60
|
+
t0 = () => {
|
|
61
|
+
if (!active || Platform.OS === "web") return;
|
|
62
|
+
const subscription = BackHandler.addEventListener("hardwareBackPress", () => {
|
|
63
|
+
close();
|
|
64
|
+
return true;
|
|
65
|
+
});
|
|
66
|
+
return () => {
|
|
67
|
+
subscription.remove();
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
t1 = [active, close];
|
|
71
|
+
$[0] = active;
|
|
72
|
+
$[1] = close;
|
|
73
|
+
$[2] = t0;
|
|
74
|
+
$[3] = t1;
|
|
75
|
+
} else {
|
|
76
|
+
t0 = $[2];
|
|
77
|
+
t1 = $[3];
|
|
78
|
+
}
|
|
79
|
+
useEffect(t0, t1);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Sends the screen reader to `target` once `ready`, which a panel passes once
|
|
83
|
+
* it has been placed, and so can be seen. React Native Web has no screen
|
|
84
|
+
* reader of its own to send.
|
|
85
|
+
*/
|
|
86
|
+
function useFocusOnPlaced(ready, target) {
|
|
87
|
+
const $ = c(4);
|
|
88
|
+
let t0;
|
|
89
|
+
let t1;
|
|
90
|
+
if ($[0] !== ready || $[1] !== target) {
|
|
91
|
+
t0 = () => {
|
|
92
|
+
if (ready && target !== null && Platform.OS !== "web") AccessibilityInfo.sendAccessibilityEvent(target, "focus");
|
|
93
|
+
};
|
|
94
|
+
t1 = [ready, target];
|
|
95
|
+
$[0] = ready;
|
|
96
|
+
$[1] = target;
|
|
97
|
+
$[2] = t0;
|
|
98
|
+
$[3] = t1;
|
|
99
|
+
} else {
|
|
100
|
+
t0 = $[2];
|
|
101
|
+
t1 = $[3];
|
|
102
|
+
}
|
|
103
|
+
useEffect(t0, t1);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A panel's motion, and the timer that unmounts it once its exit has run: it
|
|
107
|
+
* fades and scales up from 95% over the short3 duration on the emphasised
|
|
108
|
+
* decelerating curve, and back over short2 on the accelerating one. The
|
|
109
|
+
* entrance waits for the panel to be placed, so it is not spent while the
|
|
110
|
+
* panel is still hidden being measured, and the panel stays transparent
|
|
111
|
+
* until then. Under reduced motion it arrives and leaves at once.
|
|
112
|
+
*/
|
|
113
|
+
function usePanelMotion(isOpen, placed, setPresent) {
|
|
114
|
+
const $ = c(8);
|
|
115
|
+
const { motion } = useTheme();
|
|
116
|
+
const reduceMotion = useReducedMotion();
|
|
117
|
+
const shown = useSharedValue(0);
|
|
118
|
+
let t0;
|
|
119
|
+
let t1;
|
|
120
|
+
if ($[0] !== isOpen || $[1] !== motion || $[2] !== placed || $[3] !== reduceMotion || $[4] !== setPresent || $[5] !== shown) {
|
|
121
|
+
t0 = () => {
|
|
122
|
+
if (isOpen && !placed) return;
|
|
123
|
+
if (isOpen) {
|
|
124
|
+
shown.set(reduceMotion ? 1 : withTiming(1, {
|
|
125
|
+
duration: motion.durationShort3,
|
|
126
|
+
easing: Easing.bezier(...motion.easingEmphasizedDecelerate)
|
|
127
|
+
}));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (reduceMotion) {
|
|
131
|
+
shown.set(0);
|
|
132
|
+
setPresent(false);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
shown.set(withTiming(0, {
|
|
136
|
+
duration: motion.durationShort2,
|
|
137
|
+
easing: Easing.bezier(...motion.easingEmphasizedAccelerate)
|
|
138
|
+
}));
|
|
139
|
+
const timer = setTimeout(() => {
|
|
140
|
+
setPresent(false);
|
|
141
|
+
}, motion.durationShort2);
|
|
142
|
+
return () => {
|
|
143
|
+
clearTimeout(timer);
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
t1 = [
|
|
147
|
+
isOpen,
|
|
148
|
+
motion,
|
|
149
|
+
placed,
|
|
150
|
+
reduceMotion,
|
|
151
|
+
setPresent,
|
|
152
|
+
shown
|
|
153
|
+
];
|
|
154
|
+
$[0] = isOpen;
|
|
155
|
+
$[1] = motion;
|
|
156
|
+
$[2] = placed;
|
|
157
|
+
$[3] = reduceMotion;
|
|
158
|
+
$[4] = setPresent;
|
|
159
|
+
$[5] = shown;
|
|
160
|
+
$[6] = t0;
|
|
161
|
+
$[7] = t1;
|
|
162
|
+
} else {
|
|
163
|
+
t0 = $[6];
|
|
164
|
+
t1 = $[7];
|
|
165
|
+
}
|
|
166
|
+
useEffect(t0, t1);
|
|
167
|
+
return useAnimatedStyle(() => {
|
|
168
|
+
"worklet";
|
|
169
|
+
const progress = shown.get();
|
|
170
|
+
return {
|
|
171
|
+
opacity: progress,
|
|
172
|
+
transform: [{ scale: SCALE_FROM + .050000000000000044 * progress }]
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Sends the screen reader back to the trigger once a panel has gone, unless
|
|
178
|
+
* `quiet` says nothing moved it there, as a pointer resting on a hover
|
|
179
|
+
* trigger does not. React Native Web's `Modal` restores focus itself, and has
|
|
180
|
+
* no screen reader to send otherwise.
|
|
181
|
+
*/
|
|
182
|
+
function useReturnFocus(present, quiet, trigger) {
|
|
183
|
+
const $ = c(8);
|
|
184
|
+
const shown = useRef(present);
|
|
185
|
+
let t0;
|
|
186
|
+
if ($[0] !== present || $[1] !== quiet || $[2] !== trigger.current) {
|
|
187
|
+
t0 = () => {
|
|
188
|
+
const gone = shown.current && !present;
|
|
189
|
+
const target = trigger.current;
|
|
190
|
+
shown.current = present;
|
|
191
|
+
if (gone && !quiet && target !== null && Platform.OS !== "web") AccessibilityInfo.sendAccessibilityEvent(target, "focus");
|
|
192
|
+
};
|
|
193
|
+
$[0] = present;
|
|
194
|
+
$[1] = quiet;
|
|
195
|
+
$[2] = trigger.current;
|
|
196
|
+
$[3] = t0;
|
|
197
|
+
} else t0 = $[3];
|
|
198
|
+
let t1;
|
|
199
|
+
if ($[4] !== present || $[5] !== quiet || $[6] !== trigger) {
|
|
200
|
+
t1 = [
|
|
201
|
+
quiet,
|
|
202
|
+
present,
|
|
203
|
+
trigger
|
|
204
|
+
];
|
|
205
|
+
$[4] = present;
|
|
206
|
+
$[5] = quiet;
|
|
207
|
+
$[6] = trigger;
|
|
208
|
+
$[7] = t1;
|
|
209
|
+
} else t1 = $[7];
|
|
210
|
+
useEffect(t0, t1);
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
export { DismissLayer, PANEL_ORIGINS, useBackToClose, useFocusOnPlaced, usePanelMotion, useReturnFocus };
|
|
214
|
+
|
|
215
|
+
//# sourceMappingURL=panel.js.map
|