panelui-native 0.5.3 → 0.6.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/README.md +8 -4
- package/lib/module/components/scroll-fade/index.js +156 -0
- package/lib/module/components/scroll-fade/index.js.map +1 -0
- package/lib/module/components/shimmer/index.js +120 -0
- package/lib/module/components/shimmer/index.js.map +1 -0
- package/lib/module/components/surface/index.js +64 -0
- package/lib/module/components/surface/index.js.map +1 -0
- package/lib/module/hooks/index.js +9 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/use-breakpoint.js +39 -0
- package/lib/module/hooks/use-breakpoint.js.map +1 -0
- package/lib/module/hooks/use-copy-to-clipboard.js +62 -0
- package/lib/module/hooks/use-copy-to-clipboard.js.map +1 -0
- package/lib/module/hooks/use-debounced-value.js +24 -0
- package/lib/module/hooks/use-debounced-value.js.map +1 -0
- package/lib/module/hooks/use-disclosure.js +43 -0
- package/lib/module/hooks/use-disclosure.js.map +1 -0
- package/lib/module/hooks/use-keyboard.js +36 -0
- package/lib/module/hooks/use-keyboard.js.map +1 -0
- package/lib/module/hooks/use-previous.js +25 -0
- package/lib/module/hooks/use-previous.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/components/scroll-fade/index.d.ts +38 -0
- package/lib/typescript/src/components/scroll-fade/index.d.ts.map +1 -0
- package/lib/typescript/src/components/shimmer/index.d.ts +42 -0
- package/lib/typescript/src/components/shimmer/index.d.ts.map +1 -0
- package/lib/typescript/src/components/surface/index.d.ts +30 -0
- package/lib/typescript/src/components/surface/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +7 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-breakpoint.d.ts +32 -0
- package/lib/typescript/src/hooks/use-breakpoint.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-copy-to-clipboard.d.ts +30 -0
- package/lib/typescript/src/hooks/use-copy-to-clipboard.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-debounced-value.d.ts +13 -0
- package/lib/typescript/src/hooks/use-debounced-value.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-disclosure.d.ts +32 -0
- package/lib/typescript/src/hooks/use-disclosure.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-keyboard.d.ts +20 -0
- package/lib/typescript/src/hooks/use-keyboard.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-previous.d.ts +15 -0
- package/lib/typescript/src/hooks/use-previous.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +8 -1
- package/src/components/scroll-fade/index.tsx +168 -0
- package/src/components/shimmer/index.tsx +135 -0
- package/src/components/surface/index.tsx +63 -0
- package/src/hooks/index.ts +19 -0
- package/src/hooks/use-breakpoint.ts +52 -0
- package/src/hooks/use-copy-to-clipboard.ts +81 -0
- package/src/hooks/use-debounced-value.ts +23 -0
- package/src/hooks/use-disclosure.ts +57 -0
- package/src/hooks/use-keyboard.ts +43 -0
- package/src/hooks/use-previous.ts +24 -0
- package/src/index.ts +9 -0
- package/theme.css +18 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# PanelUI — React Native UI components for Expo, styled with Tailwind CSS
|
|
2
2
|
|
|
3
3
|
**PanelUI** (`panelui-native`) is an accessible, high-performance React Native component
|
|
4
|
-
library for Expo apps.
|
|
4
|
+
library for Expo apps. 29 typed components — buttons, bottom sheets, dialogs, selects,
|
|
5
5
|
toasts, forms — styled with Tailwind CSS v4 and animated on the UI thread with Reanimated.
|
|
6
6
|
Zero native code, so it runs in Expo Go.
|
|
7
7
|
|
|
@@ -107,7 +107,9 @@ overlays, and the toast viewport.
|
|
|
107
107
|
| `Label` | Form field label with required, invalid and disabled states |
|
|
108
108
|
| `Progress` | Determinate and indeterminate progress bar |
|
|
109
109
|
| `RadioGroup` | Single-select list of options |
|
|
110
|
+
| `ScrollFade` | Fades the edges of a scroll container |
|
|
110
111
|
| `Select` | Picker that opens in a bottom sheet |
|
|
112
|
+
| `Shimmer` | Animated highlight sweeping across content |
|
|
111
113
|
| `Skeleton` | Shimmer placeholder for loading content |
|
|
112
114
|
| `Spinner` | Indeterminate loading indicator |
|
|
113
115
|
| `Steps` | Stepper for multi-step flows, horizontal or vertical |
|
|
@@ -117,9 +119,11 @@ overlays, and the toast viewport.
|
|
|
117
119
|
| `Toast` | Transient notification queue with swipe-to-dismiss |
|
|
118
120
|
| `Typography` | Semantic text presets — `h1`–`h6`, body sizes, inline code |
|
|
119
121
|
|
|
120
|
-
Plus `PanelUIProvider`, `Portal`, `AnimatedPressable`, `Text`,
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
Plus `PanelUIProvider`, `Portal`, `AnimatedPressable`, `Text`, a set of SVG icons (with brand
|
|
123
|
+
marks for Google, Facebook and Apple), and the `cn` class-merging helper.
|
|
124
|
+
|
|
125
|
+
**Hooks:** `useTheme`, `useThemeMode`, `useToast`, `useCopyToClipboard`, `useDisclosure`,
|
|
126
|
+
`useBreakpoint`, `useKeyboard`, `useDebouncedValue`, `usePrevious`.
|
|
123
127
|
|
|
124
128
|
Icons inside a coloured surface inherit a readable colour automatically — `Button` provides the
|
|
125
129
|
foreground its variant reads against, so an icon in `startContent` follows the theme without a
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ScrollFade — fades the edges of a scroll container.
|
|
5
|
+
*
|
|
6
|
+
* The React Native equivalent of shadcn-ui/ui's `scroll-fade` utility
|
|
7
|
+
* (https://ui.shadcn.com/docs/utils/scroll-fade), which is CSS `mask-image`
|
|
8
|
+
* driven by a scroll timeline. React Native has neither masks nor scroll
|
|
9
|
+
* timelines, so the fades are SVG gradients overlaid on each edge, with their
|
|
10
|
+
* opacity following the scroll position.
|
|
11
|
+
*
|
|
12
|
+
* Composition follows heroui-native's ScrollShadow: wrap the scrollable and
|
|
13
|
+
* let the orientation be inferred from its `horizontal` prop.
|
|
14
|
+
*
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <ScrollFade>
|
|
17
|
+
* <ScrollView horizontal>…</ScrollView>
|
|
18
|
+
* </ScrollFade>
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import { Children, cloneElement, isValidElement, useState } from 'react';
|
|
22
|
+
import { View } from 'react-native';
|
|
23
|
+
import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg';
|
|
24
|
+
import { useCSSVariable } from 'uniwind';
|
|
25
|
+
|
|
26
|
+
/** Past this many pixels from an edge, that edge's fade is fully shown. */
|
|
27
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
28
|
+
const FADE_IN_DISTANCE = 24;
|
|
29
|
+
export function ScrollFade({
|
|
30
|
+
className,
|
|
31
|
+
size = 48,
|
|
32
|
+
edges = 'both',
|
|
33
|
+
color,
|
|
34
|
+
children,
|
|
35
|
+
...props
|
|
36
|
+
}) {
|
|
37
|
+
const [startOpacity, setStartOpacity] = useState(0);
|
|
38
|
+
const [endOpacity, setEndOpacity] = useState(0);
|
|
39
|
+
const themeBackground = useCSSVariable('--color-background');
|
|
40
|
+
const fadeColor = color ?? (typeof themeBackground === 'string' ? themeBackground : '#000000');
|
|
41
|
+
const child = Children.only(children);
|
|
42
|
+
const horizontal = /*#__PURE__*/isValidElement(child) ? !!child.props.horizontal : false;
|
|
43
|
+
const handleScroll = event => {
|
|
44
|
+
const {
|
|
45
|
+
contentOffset,
|
|
46
|
+
contentSize,
|
|
47
|
+
layoutMeasurement
|
|
48
|
+
} = event.nativeEvent;
|
|
49
|
+
const offset = horizontal ? contentOffset.x : contentOffset.y;
|
|
50
|
+
const total = horizontal ? contentSize.width : contentSize.height;
|
|
51
|
+
const visible = horizontal ? layoutMeasurement.width : layoutMeasurement.height;
|
|
52
|
+
const remaining = total - visible - offset;
|
|
53
|
+
|
|
54
|
+
// Each edge fades in over the first FADE_IN_DISTANCE px of travel, so an
|
|
55
|
+
// edge with nothing past it shows nothing.
|
|
56
|
+
setStartOpacity(Math.min(offset / FADE_IN_DISTANCE, 1));
|
|
57
|
+
setEndOpacity(Math.min(Math.max(remaining, 0) / FADE_IN_DISTANCE, 1));
|
|
58
|
+
child.props.onScroll?.(event);
|
|
59
|
+
};
|
|
60
|
+
const scrollable = /*#__PURE__*/isValidElement(child) ? /*#__PURE__*/cloneElement(child, {
|
|
61
|
+
onScroll: handleScroll,
|
|
62
|
+
scrollEventThrottle: child.props.scrollEventThrottle ?? 16
|
|
63
|
+
}) : child;
|
|
64
|
+
const showStart = edges !== 'end';
|
|
65
|
+
const showEnd = edges !== 'start';
|
|
66
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
67
|
+
...props,
|
|
68
|
+
className: className,
|
|
69
|
+
children: [scrollable, showStart ? /*#__PURE__*/_jsx(Fade, {
|
|
70
|
+
color: fadeColor,
|
|
71
|
+
size: size,
|
|
72
|
+
horizontal: horizontal,
|
|
73
|
+
opacity: startOpacity,
|
|
74
|
+
edge: "start"
|
|
75
|
+
}) : null, showEnd ? /*#__PURE__*/_jsx(Fade, {
|
|
76
|
+
color: fadeColor,
|
|
77
|
+
size: size,
|
|
78
|
+
horizontal: horizontal,
|
|
79
|
+
opacity: endOpacity,
|
|
80
|
+
edge: "end"
|
|
81
|
+
}) : null]
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
ScrollFade.displayName = 'ScrollFade';
|
|
85
|
+
|
|
86
|
+
/** One edge's gradient, opaque at the edge and clear inwards. */
|
|
87
|
+
function Fade({
|
|
88
|
+
color,
|
|
89
|
+
size,
|
|
90
|
+
horizontal,
|
|
91
|
+
opacity,
|
|
92
|
+
edge
|
|
93
|
+
}) {
|
|
94
|
+
const isStart = edge === 'start';
|
|
95
|
+
const id = `scroll-fade-${edge}-${horizontal ? 'x' : 'y'}`;
|
|
96
|
+
const position = horizontal ? {
|
|
97
|
+
top: 0,
|
|
98
|
+
bottom: 0,
|
|
99
|
+
width: size,
|
|
100
|
+
...(isStart ? {
|
|
101
|
+
left: 0
|
|
102
|
+
} : {
|
|
103
|
+
right: 0
|
|
104
|
+
})
|
|
105
|
+
} : {
|
|
106
|
+
left: 0,
|
|
107
|
+
right: 0,
|
|
108
|
+
height: size,
|
|
109
|
+
...(isStart ? {
|
|
110
|
+
top: 0
|
|
111
|
+
} : {
|
|
112
|
+
bottom: 0
|
|
113
|
+
})
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// The gradient runs from the screen edge inwards, so it is reversed on the
|
|
117
|
+
// end edge.
|
|
118
|
+
const [x2, y2] = horizontal ? [1, 0] : [0, 1];
|
|
119
|
+
return /*#__PURE__*/_jsx(View, {
|
|
120
|
+
pointerEvents: "none",
|
|
121
|
+
style: {
|
|
122
|
+
position: 'absolute',
|
|
123
|
+
opacity,
|
|
124
|
+
...position
|
|
125
|
+
},
|
|
126
|
+
children: /*#__PURE__*/_jsxs(Svg, {
|
|
127
|
+
width: "100%",
|
|
128
|
+
height: "100%",
|
|
129
|
+
children: [/*#__PURE__*/_jsx(Defs, {
|
|
130
|
+
children: /*#__PURE__*/_jsxs(LinearGradient, {
|
|
131
|
+
id: id,
|
|
132
|
+
x1: "0",
|
|
133
|
+
y1: "0",
|
|
134
|
+
x2: String(x2),
|
|
135
|
+
y2: String(y2),
|
|
136
|
+
children: [/*#__PURE__*/_jsx(Stop, {
|
|
137
|
+
offset: "0",
|
|
138
|
+
stopColor: color,
|
|
139
|
+
stopOpacity: isStart ? 1 : 0
|
|
140
|
+
}), /*#__PURE__*/_jsx(Stop, {
|
|
141
|
+
offset: "1",
|
|
142
|
+
stopColor: color,
|
|
143
|
+
stopOpacity: isStart ? 0 : 1
|
|
144
|
+
})]
|
|
145
|
+
})
|
|
146
|
+
}), /*#__PURE__*/_jsx(Rect, {
|
|
147
|
+
x: "0",
|
|
148
|
+
y: "0",
|
|
149
|
+
width: "100%",
|
|
150
|
+
height: "100%",
|
|
151
|
+
fill: `url(#${id})`
|
|
152
|
+
})]
|
|
153
|
+
})
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Children","cloneElement","isValidElement","useState","View","Svg","Defs","LinearGradient","Rect","Stop","useCSSVariable","jsx","_jsx","jsxs","_jsxs","FADE_IN_DISTANCE","ScrollFade","className","size","edges","color","children","props","startOpacity","setStartOpacity","endOpacity","setEndOpacity","themeBackground","fadeColor","child","only","horizontal","handleScroll","event","contentOffset","contentSize","layoutMeasurement","nativeEvent","offset","x","y","total","width","height","visible","remaining","Math","min","max","onScroll","scrollable","scrollEventThrottle","showStart","showEnd","Fade","opacity","edge","displayName","isStart","id","position","top","bottom","left","right","x2","y2","pointerEvents","style","x1","y1","String","stopColor","stopOpacity","fill"],"sourceRoot":"../../../../src","sources":["components/scroll-fade/index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shimmer — an animated highlight sweeping across content.
|
|
5
|
+
*
|
|
6
|
+
* The React Native equivalent of shadcn-ui/ui's `shimmer` utility
|
|
7
|
+
* (https://ui.shadcn.com/docs/utils/shimmer). That one is CSS:
|
|
8
|
+
* `background-clip: text` with a `color-mix()` highlight. React Native has
|
|
9
|
+
* neither, so the highlight is drawn as an SVG gradient band swept across an
|
|
10
|
+
* overlay by Reanimated, on the UI thread.
|
|
11
|
+
*
|
|
12
|
+
* The visible difference: the band passes *over* the content rather than
|
|
13
|
+
* being clipped to glyph shapes. On body-sized text the two read the same; on
|
|
14
|
+
* very large text the web version is crisper.
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <Shimmer>
|
|
18
|
+
* <Text muted>Generating response…</Text>
|
|
19
|
+
* </Shimmer>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import { useEffect, useState } from 'react';
|
|
23
|
+
import { View } from 'react-native';
|
|
24
|
+
import Animated, { cancelAnimation, Easing, useAnimatedStyle, useReducedMotion, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated';
|
|
25
|
+
import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg';
|
|
26
|
+
import { useCSSVariable } from 'uniwind';
|
|
27
|
+
import { cn } from "../../utils/cn.js";
|
|
28
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
29
|
+
export function Shimmer({
|
|
30
|
+
className,
|
|
31
|
+
duration = 2000,
|
|
32
|
+
once = false,
|
|
33
|
+
reverse = false,
|
|
34
|
+
spread = 0.4,
|
|
35
|
+
color,
|
|
36
|
+
intensity = 0.45,
|
|
37
|
+
children,
|
|
38
|
+
...props
|
|
39
|
+
}) {
|
|
40
|
+
const [width, setWidth] = useState(0);
|
|
41
|
+
const progress = useSharedValue(0);
|
|
42
|
+
const reducedMotion = useReducedMotion();
|
|
43
|
+
const themeForeground = useCSSVariable('--color-foreground');
|
|
44
|
+
const highlight = color ?? (typeof themeForeground === 'string' ? themeForeground : '#ffffff');
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
// Respect the OS setting rather than animating regardless — the same
|
|
47
|
+
// thing shadcn's utility does with prefers-reduced-motion.
|
|
48
|
+
if (reducedMotion || width === 0) return;
|
|
49
|
+
progress.value = 0;
|
|
50
|
+
progress.value = withRepeat(withTiming(1, {
|
|
51
|
+
duration,
|
|
52
|
+
easing: Easing.linear
|
|
53
|
+
}), once ? 1 : -1, false);
|
|
54
|
+
return () => cancelAnimation(progress);
|
|
55
|
+
}, [duration, once, reducedMotion, width, progress]);
|
|
56
|
+
const bandWidth = Math.max(width * spread, 1);
|
|
57
|
+
const bandStyle = useAnimatedStyle(() => {
|
|
58
|
+
// Travel from fully off one edge to fully off the other.
|
|
59
|
+
const from = -bandWidth;
|
|
60
|
+
const to = width;
|
|
61
|
+
const x = reverse ? to - progress.value * (to - from) : from + progress.value * (to - from);
|
|
62
|
+
return {
|
|
63
|
+
transform: [{
|
|
64
|
+
translateX: x
|
|
65
|
+
}]
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
const onLayout = event => {
|
|
69
|
+
setWidth(event.nativeEvent.layout.width);
|
|
70
|
+
props.onLayout?.(event);
|
|
71
|
+
};
|
|
72
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
73
|
+
...props,
|
|
74
|
+
onLayout: onLayout,
|
|
75
|
+
className: cn('overflow-hidden', className),
|
|
76
|
+
children: [children, reducedMotion || width === 0 ? null : /*#__PURE__*/_jsx(Animated.View, {
|
|
77
|
+
pointerEvents: "none",
|
|
78
|
+
style: [{
|
|
79
|
+
position: 'absolute',
|
|
80
|
+
top: 0,
|
|
81
|
+
bottom: 0,
|
|
82
|
+
width: bandWidth
|
|
83
|
+
}, bandStyle],
|
|
84
|
+
children: /*#__PURE__*/_jsxs(Svg, {
|
|
85
|
+
width: "100%",
|
|
86
|
+
height: "100%",
|
|
87
|
+
children: [/*#__PURE__*/_jsx(Defs, {
|
|
88
|
+
children: /*#__PURE__*/_jsxs(LinearGradient, {
|
|
89
|
+
id: "shimmer",
|
|
90
|
+
x1: "0",
|
|
91
|
+
y1: "0",
|
|
92
|
+
x2: "1",
|
|
93
|
+
y2: "0",
|
|
94
|
+
children: [/*#__PURE__*/_jsx(Stop, {
|
|
95
|
+
offset: "0",
|
|
96
|
+
stopColor: highlight,
|
|
97
|
+
stopOpacity: 0
|
|
98
|
+
}), /*#__PURE__*/_jsx(Stop, {
|
|
99
|
+
offset: "0.5",
|
|
100
|
+
stopColor: highlight,
|
|
101
|
+
stopOpacity: intensity
|
|
102
|
+
}), /*#__PURE__*/_jsx(Stop, {
|
|
103
|
+
offset: "1",
|
|
104
|
+
stopColor: highlight,
|
|
105
|
+
stopOpacity: 0
|
|
106
|
+
})]
|
|
107
|
+
})
|
|
108
|
+
}), /*#__PURE__*/_jsx(Rect, {
|
|
109
|
+
x: "0",
|
|
110
|
+
y: "0",
|
|
111
|
+
width: "100%",
|
|
112
|
+
height: "100%",
|
|
113
|
+
fill: "url(#shimmer)"
|
|
114
|
+
})]
|
|
115
|
+
})
|
|
116
|
+
})]
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
Shimmer.displayName = 'Shimmer';
|
|
120
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useEffect","useState","View","Animated","cancelAnimation","Easing","useAnimatedStyle","useReducedMotion","useSharedValue","withRepeat","withTiming","Svg","Defs","LinearGradient","Rect","Stop","useCSSVariable","cn","jsx","_jsx","jsxs","_jsxs","Shimmer","className","duration","once","reverse","spread","color","intensity","children","props","width","setWidth","progress","reducedMotion","themeForeground","highlight","value","easing","linear","bandWidth","Math","max","bandStyle","from","to","x","transform","translateX","onLayout","event","nativeEvent","layout","pointerEvents","style","position","top","bottom","height","id","x1","y1","x2","y2","offset","stopColor","stopOpacity","y","fill","displayName"],"sourceRoot":"../../../../src","sources":["components/shimmer/index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Surface — an elevated container.
|
|
5
|
+
*
|
|
6
|
+
* Adapted from: heroui-inc/heroui-native src/components/surface/
|
|
7
|
+
* (the variant ladder and the nesting model for building hierarchy).
|
|
8
|
+
*
|
|
9
|
+
* Both the fill and the corner radius follow the active theme: the variants
|
|
10
|
+
* resolve to themed `--color-surface-*` tokens, and `rounded-3xl` resolves
|
|
11
|
+
* through the per-theme radius scale — so Moon's surfaces are tight and
|
|
12
|
+
* Grass's are soft, without the component knowing anything about either.
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <Surface>
|
|
16
|
+
* <Surface variant="secondary">
|
|
17
|
+
* <Surface variant="tertiary">…</Surface>
|
|
18
|
+
* </Surface>
|
|
19
|
+
* </Surface>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import { forwardRef } from 'react';
|
|
23
|
+
import { StyleSheet, View } from 'react-native';
|
|
24
|
+
import { tv } from 'tailwind-variants';
|
|
25
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
26
|
+
const surfaceVariants = tv({
|
|
27
|
+
base: 'overflow-hidden rounded-3xl p-4',
|
|
28
|
+
variants: {
|
|
29
|
+
variant: {
|
|
30
|
+
default: 'bg-surface',
|
|
31
|
+
secondary: 'bg-surface-secondary',
|
|
32
|
+
tertiary: 'bg-surface-tertiary',
|
|
33
|
+
transparent: 'bg-transparent'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
defaultVariants: {
|
|
37
|
+
variant: 'default'
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
export const Surface = /*#__PURE__*/forwardRef(({
|
|
41
|
+
className,
|
|
42
|
+
variant,
|
|
43
|
+
style,
|
|
44
|
+
...props
|
|
45
|
+
}, ref) => /*#__PURE__*/_jsx(View, {
|
|
46
|
+
ref: ref
|
|
47
|
+
// `borderCurve` has no Tailwind equivalent. On iOS it gives the
|
|
48
|
+
// continuous (squircle) corner Apple uses, which is visibly smoother
|
|
49
|
+
// than a circular arc at this radius; Android ignores it.
|
|
50
|
+
,
|
|
51
|
+
style: [styles.root, style],
|
|
52
|
+
className: surfaceVariants({
|
|
53
|
+
variant,
|
|
54
|
+
className
|
|
55
|
+
}),
|
|
56
|
+
...props
|
|
57
|
+
}));
|
|
58
|
+
Surface.displayName = 'Surface';
|
|
59
|
+
const styles = StyleSheet.create({
|
|
60
|
+
root: {
|
|
61
|
+
borderCurve: 'continuous'
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["forwardRef","StyleSheet","View","tv","jsx","_jsx","surfaceVariants","base","variants","variant","default","secondary","tertiary","transparent","defaultVariants","Surface","className","style","props","ref","styles","root","displayName","create","borderCurve"],"sourceRoot":"../../../../src","sources":["components/surface/index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,UAAU,QAAQ,OAAO;AAClC,SAASC,UAAU,EAAEC,IAAI,QAAwB,cAAc;AAC/D,SAASC,EAAE,QAA2B,mBAAmB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAE1D,MAAMC,eAAe,GAAGH,EAAE,CAAC;EACzBI,IAAI,EAAE,iCAAiC;EACvCC,QAAQ,EAAE;IACRC,OAAO,EAAE;MACPC,OAAO,EAAE,YAAY;MACrBC,SAAS,EAAE,sBAAsB;MACjCC,QAAQ,EAAE,qBAAqB;MAC/BC,WAAW,EAAE;IACf;EACF,CAAC;EACDC,eAAe,EAAE;IACfL,OAAO,EAAE;EACX;AACF,CAAC,CAAC;AAQF,OAAO,MAAMM,OAAO,gBAAGf,UAAU,CAC/B,CAAC;EAAEgB,SAAS;EAAEP,OAAO;EAAEQ,KAAK;EAAE,GAAGC;AAAM,CAAC,EAAEC,GAAG,kBAC3Cd,IAAA,CAACH,IAAI;EACHiB,GAAG,EAAEA;EACL;EACA;EACA;EAAA;EACAF,KAAK,EAAE,CAACG,MAAM,CAACC,IAAI,EAAEJ,KAAK,CAAE;EAC5BD,SAAS,EAAEV,eAAe,CAAC;IAAEG,OAAO;IAAEO;EAAU,CAAC,CAAE;EAAA,GAC/CE;AAAK,CACV,CAEL,CAAC;AAEDH,OAAO,CAACO,WAAW,GAAG,SAAS;AAE/B,MAAMF,MAAM,GAAGnB,UAAU,CAACsB,MAAM,CAAC;EAC/BF,IAAI,EAAE;IAAEG,WAAW,EAAE;EAAa;AACpC,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export { useCopyToClipboard } from "./use-copy-to-clipboard.js";
|
|
4
|
+
export { useDisclosure } from "./use-disclosure.js";
|
|
5
|
+
export { useBreakpoint, BREAKPOINTS } from "./use-breakpoint.js";
|
|
6
|
+
export { useKeyboard } from "./use-keyboard.js";
|
|
7
|
+
export { useDebouncedValue } from "./use-debounced-value.js";
|
|
8
|
+
export { usePrevious } from "./use-previous.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCopyToClipboard","useDisclosure","useBreakpoint","BREAKPOINTS","useKeyboard","useDebouncedValue","usePrevious"],"sourceRoot":"../../../src","sources":["hooks/index.ts"],"mappings":";;AAAA,SACEA,kBAAkB,QAGb,4BAAyB;AAChC,SACEC,aAAa,QAGR,qBAAkB;AACzB,SACEC,aAAa,EACbC,WAAW,QAGN,qBAAkB;AACzB,SAASC,WAAW,QAAgC,mBAAgB;AACpE,SAASC,iBAAiB,QAAQ,0BAAuB;AACzD,SAASC,WAAW,QAAQ,mBAAgB","ignoreList":[]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useWindowDimensions } from 'react-native';
|
|
4
|
+
|
|
5
|
+
/** Tailwind's breakpoints, minus the ones no phone or tablet reaches. */
|
|
6
|
+
export const BREAKPOINTS = {
|
|
7
|
+
sm: 640,
|
|
8
|
+
md: 768,
|
|
9
|
+
lg: 1024,
|
|
10
|
+
xl: 1280
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Responsive state from the window size — the React Native answer to
|
|
14
|
+
* coss.com/ui's `useMediaQuery`, which has no equivalent here.
|
|
15
|
+
*
|
|
16
|
+
* For styling, prefer Uniwind's responsive class prefixes (`md:flex-row`).
|
|
17
|
+
* Reach for this when the *behaviour* changes, not just the look — rendering
|
|
18
|
+
* a sheet on a phone and a dialog on a tablet, say.
|
|
19
|
+
*
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const { isAtLeast } = useBreakpoint();
|
|
22
|
+
* return isAtLeast('md') ? <Dialog …/> : <BottomSheet …/>;
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function useBreakpoint() {
|
|
26
|
+
const {
|
|
27
|
+
width,
|
|
28
|
+
height
|
|
29
|
+
} = useWindowDimensions();
|
|
30
|
+
const current = width >= BREAKPOINTS.xl ? 'xl' : width >= BREAKPOINTS.lg ? 'lg' : width >= BREAKPOINTS.md ? 'md' : width >= BREAKPOINTS.sm ? 'sm' : 'base';
|
|
31
|
+
return {
|
|
32
|
+
current,
|
|
33
|
+
isAtLeast: breakpoint => width >= BREAKPOINTS[breakpoint],
|
|
34
|
+
width,
|
|
35
|
+
height,
|
|
36
|
+
isLandscape: width > height
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=use-breakpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useWindowDimensions","BREAKPOINTS","sm","md","lg","xl","useBreakpoint","width","height","current","isAtLeast","breakpoint","isLandscape"],"sourceRoot":"../../../src","sources":["hooks/use-breakpoint.ts"],"mappings":";;AAAA,SAASA,mBAAmB,QAAQ,cAAc;;AAElD;AACA,OAAO,MAAMC,WAAW,GAAG;EAAEC,EAAE,EAAE,GAAG;EAAEC,EAAE,EAAE,GAAG;EAAEC,EAAE,EAAE,IAAI;EAAEC,EAAE,EAAE;AAAK,CAAU;AAc5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,aAAaA,CAAA,EAAwB;EACnD,MAAM;IAAEC,KAAK;IAAEC;EAAO,CAAC,GAAGR,mBAAmB,CAAC,CAAC;EAE/C,MAAMS,OAA4B,GAChCF,KAAK,IAAIN,WAAW,CAACI,EAAE,GACnB,IAAI,GACJE,KAAK,IAAIN,WAAW,CAACG,EAAE,GACrB,IAAI,GACJG,KAAK,IAAIN,WAAW,CAACE,EAAE,GACrB,IAAI,GACJI,KAAK,IAAIN,WAAW,CAACC,EAAE,GACrB,IAAI,GACJ,MAAM;EAElB,OAAO;IACLO,OAAO;IACPC,SAAS,EAAGC,UAAU,IAAKJ,KAAK,IAAIN,WAAW,CAACU,UAAU,CAAC;IAC3DJ,KAAK;IACLC,MAAM;IACNI,WAAW,EAAEL,KAAK,GAAGC;EACvB,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Copy text to the clipboard, with a temporary "copied" state.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors coss.com/ui's `useCopyToClipboard`.
|
|
8
|
+
*
|
|
9
|
+
* Requires `expo-clipboard`, which is an optional peer dependency — React
|
|
10
|
+
* Native removed `Clipboard` from core, and pulling in a required native
|
|
11
|
+
* module for one hook would cost every consumer who never calls it:
|
|
12
|
+
*
|
|
13
|
+
* ```sh
|
|
14
|
+
* npx expo install expo-clipboard
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* const { copy, copied } = useCopyToClipboard();
|
|
19
|
+
* <Button onPress={() => copy(url)}>{copied ? 'Copied' : 'Copy link'}</Button>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function useCopyToClipboard({
|
|
23
|
+
timeout = 2000,
|
|
24
|
+
onCopy
|
|
25
|
+
} = {}) {
|
|
26
|
+
const [copied, setCopied] = useState(false);
|
|
27
|
+
const timer = useRef(null);
|
|
28
|
+
|
|
29
|
+
// Never leave a timer running against an unmounted component.
|
|
30
|
+
useEffect(() => () => {
|
|
31
|
+
if (timer.current) clearTimeout(timer.current);
|
|
32
|
+
}, []);
|
|
33
|
+
const copy = useCallback(async value => {
|
|
34
|
+
const setString = await loadClipboard();
|
|
35
|
+
await setString(value);
|
|
36
|
+
setCopied(true);
|
|
37
|
+
onCopy?.();
|
|
38
|
+
if (timer.current) clearTimeout(timer.current);
|
|
39
|
+
if (timeout > 0) {
|
|
40
|
+
timer.current = setTimeout(() => setCopied(false), timeout);
|
|
41
|
+
}
|
|
42
|
+
}, [timeout, onCopy]);
|
|
43
|
+
return {
|
|
44
|
+
copy,
|
|
45
|
+
copied
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolves expo-clipboard lazily, so apps that never call this hook are not
|
|
51
|
+
* asked to install it. The import is awaited rather than top-level for the
|
|
52
|
+
* same reason.
|
|
53
|
+
*/
|
|
54
|
+
async function loadClipboard() {
|
|
55
|
+
try {
|
|
56
|
+
const clipboard = await import('expo-clipboard');
|
|
57
|
+
return clipboard.setStringAsync;
|
|
58
|
+
} catch {
|
|
59
|
+
throw new Error('useCopyToClipboard requires expo-clipboard. Install it with: npx expo install expo-clipboard');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=use-copy-to-clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useRef","useState","useCopyToClipboard","timeout","onCopy","copied","setCopied","timer","current","clearTimeout","copy","value","setString","loadClipboard","setTimeout","clipboard","setStringAsync","Error"],"sourceRoot":"../../../src","sources":["hooks/use-copy-to-clipboard.ts"],"mappings":";;AAAA,SAASA,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAchE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,kBAAkBA,CAAC;EACjCC,OAAO,GAAG,IAAI;EACdC;AACyB,CAAC,GAAG,CAAC,CAAC,EAA4B;EAC3D,MAAM,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAGL,QAAQ,CAAC,KAAK,CAAC;EAC3C,MAAMM,KAAK,GAAGP,MAAM,CAAuC,IAAI,CAAC;;EAEhE;EACAD,SAAS,CACP,MAAM,MAAM;IACV,IAAIQ,KAAK,CAACC,OAAO,EAAEC,YAAY,CAACF,KAAK,CAACC,OAAO,CAAC;EAChD,CAAC,EACD,EACF,CAAC;EAED,MAAME,IAAI,GAAGZ,WAAW,CACtB,MAAOa,KAAa,IAAK;IACvB,MAAMC,SAAS,GAAG,MAAMC,aAAa,CAAC,CAAC;IACvC,MAAMD,SAAS,CAACD,KAAK,CAAC;IAEtBL,SAAS,CAAC,IAAI,CAAC;IACfF,MAAM,GAAG,CAAC;IAEV,IAAIG,KAAK,CAACC,OAAO,EAAEC,YAAY,CAACF,KAAK,CAACC,OAAO,CAAC;IAC9C,IAAIL,OAAO,GAAG,CAAC,EAAE;MACfI,KAAK,CAACC,OAAO,GAAGM,UAAU,CAAC,MAAMR,SAAS,CAAC,KAAK,CAAC,EAAEH,OAAO,CAAC;IAC7D;EACF,CAAC,EACD,CAACA,OAAO,EAAEC,MAAM,CAClB,CAAC;EAED,OAAO;IAAEM,IAAI;IAAEL;EAAO,CAAC;AACzB;;AAEA;AACA;AACA;AACA;AACA;AACA,eAAeQ,aAAaA,CAAA,EAAiD;EAC3E,IAAI;IACF,MAAME,SAAS,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC;IAChD,OAAOA,SAAS,CAACC,cAAc;EACjC,CAAC,CAAC,MAAM;IACN,MAAM,IAAIC,KAAK,CACb,8FACF,CAAC;EACH;AACF","ignoreList":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A copy of `value` that only updates once it has stopped changing for
|
|
7
|
+
* `delay` ms — for search fields, where you want the typed value on screen
|
|
8
|
+
* immediately but the query fired once.
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* const [query, setQuery] = useState('');
|
|
12
|
+
* const debounced = useDebouncedValue(query, 300);
|
|
13
|
+
* useEffect(() => { search(debounced); }, [debounced]);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function useDebouncedValue(value, delay = 300) {
|
|
17
|
+
const [debounced, setDebounced] = useState(value);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const timer = setTimeout(() => setDebounced(value), delay);
|
|
20
|
+
return () => clearTimeout(timer);
|
|
21
|
+
}, [value, delay]);
|
|
22
|
+
return debounced;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=use-debounced-value.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useEffect","useState","useDebouncedValue","value","delay","debounced","setDebounced","timer","setTimeout","clearTimeout"],"sourceRoot":"../../../src","sources":["hooks/use-debounced-value.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,OAAO;;AAE3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAAIC,KAAQ,EAAEC,KAAK,GAAG,GAAG,EAAK;EAC7D,MAAM,CAACC,SAAS,EAAEC,YAAY,CAAC,GAAGL,QAAQ,CAACE,KAAK,CAAC;EAEjDH,SAAS,CAAC,MAAM;IACd,MAAMO,KAAK,GAAGC,UAAU,CAAC,MAAMF,YAAY,CAACH,KAAK,CAAC,EAAEC,KAAK,CAAC;IAC1D,OAAO,MAAMK,YAAY,CAACF,KAAK,CAAC;EAClC,CAAC,EAAE,CAACJ,KAAK,EAAEC,KAAK,CAAC,CAAC;EAElB,OAAOC,SAAS;AAClB","ignoreList":[]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Open/closed state for an overlay.
|
|
6
|
+
*
|
|
7
|
+
* The same controlled-or-uncontrolled pattern Dialog, BottomSheet and Select
|
|
8
|
+
* implement internally, lifted out for when you need to drive one from
|
|
9
|
+
* elsewhere — closing a sheet after a request settles, say.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const sheet = useDisclosure();
|
|
13
|
+
* <Button onPress={sheet.open}>Share</Button>
|
|
14
|
+
* <BottomSheet {...sheet.props}>…</BottomSheet>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function useDisclosure({
|
|
18
|
+
defaultOpen = false,
|
|
19
|
+
open: controlledOpen,
|
|
20
|
+
onOpenChange
|
|
21
|
+
} = {}) {
|
|
22
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
23
|
+
const isControlled = controlledOpen !== undefined;
|
|
24
|
+
const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
|
|
25
|
+
const setOpen = useCallback(next => {
|
|
26
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
27
|
+
onOpenChange?.(next);
|
|
28
|
+
}, [isControlled, onOpenChange]);
|
|
29
|
+
const open = useCallback(() => setOpen(true), [setOpen]);
|
|
30
|
+
const close = useCallback(() => setOpen(false), [setOpen]);
|
|
31
|
+
const toggle = useCallback(() => setOpen(!isOpen), [setOpen, isOpen]);
|
|
32
|
+
return useMemo(() => ({
|
|
33
|
+
isOpen,
|
|
34
|
+
open,
|
|
35
|
+
close,
|
|
36
|
+
toggle,
|
|
37
|
+
props: {
|
|
38
|
+
open: isOpen,
|
|
39
|
+
onOpenChange: setOpen
|
|
40
|
+
}
|
|
41
|
+
}), [isOpen, open, close, toggle, setOpen]);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=use-disclosure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useMemo","useState","useDisclosure","defaultOpen","open","controlledOpen","onOpenChange","uncontrolledOpen","setUncontrolledOpen","isControlled","undefined","isOpen","setOpen","next","close","toggle","props"],"sourceRoot":"../../../src","sources":["hooks/use-disclosure.ts"],"mappings":";;AAAA,SAASA,WAAW,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,OAAO;AAkBtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,aAAaA,CAAC;EAC5BC,WAAW,GAAG,KAAK;EACnBC,IAAI,EAAEC,cAAc;EACpBC;AACoB,CAAC,GAAG,CAAC,CAAC,EAAuB;EACjD,MAAM,CAACC,gBAAgB,EAAEC,mBAAmB,CAAC,GAAGP,QAAQ,CAACE,WAAW,CAAC;EACrE,MAAMM,YAAY,GAAGJ,cAAc,KAAKK,SAAS;EACjD,MAAMC,MAAM,GAAGF,YAAY,GAAGJ,cAAc,GAAGE,gBAAgB;EAE/D,MAAMK,OAAO,GAAGb,WAAW,CACxBc,IAAa,IAAK;IACjB,IAAI,CAACJ,YAAY,EAAED,mBAAmB,CAACK,IAAI,CAAC;IAC5CP,YAAY,GAAGO,IAAI,CAAC;EACtB,CAAC,EACD,CAACJ,YAAY,EAAEH,YAAY,CAC7B,CAAC;EAED,MAAMF,IAAI,GAAGL,WAAW,CAAC,MAAMa,OAAO,CAAC,IAAI,CAAC,EAAE,CAACA,OAAO,CAAC,CAAC;EACxD,MAAME,KAAK,GAAGf,WAAW,CAAC,MAAMa,OAAO,CAAC,KAAK,CAAC,EAAE,CAACA,OAAO,CAAC,CAAC;EAC1D,MAAMG,MAAM,GAAGhB,WAAW,CAAC,MAAMa,OAAO,CAAC,CAACD,MAAM,CAAC,EAAE,CAACC,OAAO,EAAED,MAAM,CAAC,CAAC;EAErE,OAAOX,OAAO,CACZ,OAAO;IAAEW,MAAM;IAAEP,IAAI;IAAEU,KAAK;IAAEC,MAAM;IAAEC,KAAK,EAAE;MAAEZ,IAAI,EAAEO,MAAM;MAAEL,YAAY,EAAEM;IAAQ;EAAE,CAAC,CAAC,EACvF,CAACD,MAAM,EAAEP,IAAI,EAAEU,KAAK,EAAEC,MAAM,EAAEH,OAAO,CACvC,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { Keyboard, Platform } from 'react-native';
|
|
5
|
+
/**
|
|
6
|
+
* Keyboard height and visibility, on the JS thread.
|
|
7
|
+
*
|
|
8
|
+
* Use this when the value drives rendering — showing a hint, swapping a
|
|
9
|
+
* layout. For *animating* against the keyboard, use Reanimated's
|
|
10
|
+
* `useAnimatedKeyboard` instead: it runs on the UI thread and tracks the
|
|
11
|
+
* keyboard frame-for-frame, where this fires once per show/hide.
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const { isVisible } = useKeyboard();
|
|
15
|
+
* {isVisible ? null : <Footer />}
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function useKeyboard() {
|
|
19
|
+
const [height, setHeight] = useState(0);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
// iOS reports the frame before it animates; Android only on completion.
|
|
22
|
+
const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
|
|
23
|
+
const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
|
|
24
|
+
const show = Keyboard.addListener(showEvent, event => setHeight(event.endCoordinates.height));
|
|
25
|
+
const hide = Keyboard.addListener(hideEvent, () => setHeight(0));
|
|
26
|
+
return () => {
|
|
27
|
+
show.remove();
|
|
28
|
+
hide.remove();
|
|
29
|
+
};
|
|
30
|
+
}, []);
|
|
31
|
+
return {
|
|
32
|
+
height,
|
|
33
|
+
isVisible: height > 0
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=use-keyboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useEffect","useState","Keyboard","Platform","useKeyboard","height","setHeight","showEvent","OS","hideEvent","show","addListener","event","endCoordinates","hide","remove","isVisible"],"sourceRoot":"../../../src","sources":["hooks/use-keyboard.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAC3C,SAASC,QAAQ,EAAEC,QAAQ,QAAQ,cAAc;AAQjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,WAAWA,CAAA,EAAsB;EAC/C,MAAM,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAGL,QAAQ,CAAC,CAAC,CAAC;EAEvCD,SAAS,CAAC,MAAM;IACd;IACA,MAAMO,SAAS,GAAGJ,QAAQ,CAACK,EAAE,KAAK,KAAK,GAAG,kBAAkB,GAAG,iBAAiB;IAChF,MAAMC,SAAS,GAAGN,QAAQ,CAACK,EAAE,KAAK,KAAK,GAAG,kBAAkB,GAAG,iBAAiB;IAEhF,MAAME,IAAI,GAAGR,QAAQ,CAACS,WAAW,CAACJ,SAAS,EAAGK,KAAK,IACjDN,SAAS,CAACM,KAAK,CAACC,cAAc,CAACR,MAAM,CACvC,CAAC;IACD,MAAMS,IAAI,GAAGZ,QAAQ,CAACS,WAAW,CAACF,SAAS,EAAE,MAAMH,SAAS,CAAC,CAAC,CAAC,CAAC;IAEhE,OAAO,MAAM;MACXI,IAAI,CAACK,MAAM,CAAC,CAAC;MACbD,IAAI,CAACC,MAAM,CAAC,CAAC;IACf,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EAEN,OAAO;IAAEV,MAAM;IAAEW,SAAS,EAAEX,MAAM,GAAG;EAAE,CAAC;AAC1C","ignoreList":[]}
|