@butternutbox/pawprint-native 0.10.8 → 0.10.9
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/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +21 -0
- package/dist/index.cjs +696 -775
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +196 -275
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/molecules/Drawer/Drawer.stories.tsx +49 -110
- package/src/components/molecules/Drawer/DrawerBody.tsx +9 -42
- package/src/components/molecules/Drawer/DrawerContent.tsx +41 -122
- package/src/components/molecules/Drawer/DrawerMeasureContext.ts +0 -22
package/package.json
CHANGED
|
@@ -205,6 +205,55 @@ export const LongContent = () => (
|
|
|
205
205
|
</View>
|
|
206
206
|
)
|
|
207
207
|
|
|
208
|
+
// Exercises the panel re-fit: toggling the extra paragraphs grows/shrinks the
|
|
209
|
+
// body after the drawer has opened. The panel should track the content —
|
|
210
|
+
// growing (up to its max, then scrolling) and shrinking back — never leaving a
|
|
211
|
+
// gap or clipping. Regression guard for the 0.10.8 re-measure feedback loop.
|
|
212
|
+
export const DynamicContent = () => {
|
|
213
|
+
const [expanded, setExpanded] = useState(false)
|
|
214
|
+
return (
|
|
215
|
+
<View style={styles.container}>
|
|
216
|
+
<Drawer.Root>
|
|
217
|
+
<Drawer.Trigger>
|
|
218
|
+
<Button variant="filled" colour="primary">
|
|
219
|
+
Open dynamic drawer
|
|
220
|
+
</Button>
|
|
221
|
+
</Drawer.Trigger>
|
|
222
|
+
<Drawer.Portal>
|
|
223
|
+
<Drawer.Overlay />
|
|
224
|
+
<Drawer.Content>
|
|
225
|
+
<Drawer.Header variant="titleAndText">
|
|
226
|
+
<Drawer.Title>Delivery details</Drawer.Title>
|
|
227
|
+
<Drawer.Close />
|
|
228
|
+
</Drawer.Header>
|
|
229
|
+
<Drawer.Body>
|
|
230
|
+
<Typography>{bodyText}</Typography>
|
|
231
|
+
<Button
|
|
232
|
+
variant="outlined"
|
|
233
|
+
colour="secondary"
|
|
234
|
+
onPress={() => setExpanded((prev) => !prev)}
|
|
235
|
+
>
|
|
236
|
+
{expanded ? "Show less" : "Show more"}
|
|
237
|
+
</Button>
|
|
238
|
+
{expanded &&
|
|
239
|
+
Array.from({ length: 12 }, (_, i) => (
|
|
240
|
+
<Typography
|
|
241
|
+
key={i}
|
|
242
|
+
>{`More detail ${i + 1}: ${bodyText}`}</Typography>
|
|
243
|
+
))}
|
|
244
|
+
</Drawer.Body>
|
|
245
|
+
<Drawer.Footer>
|
|
246
|
+
<Button variant="filled" colour="primary">
|
|
247
|
+
Confirm
|
|
248
|
+
</Button>
|
|
249
|
+
</Drawer.Footer>
|
|
250
|
+
</Drawer.Content>
|
|
251
|
+
</Drawer.Portal>
|
|
252
|
+
</Drawer.Root>
|
|
253
|
+
</View>
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
|
|
208
257
|
export const Controlled = () => {
|
|
209
258
|
const [open, setOpen] = useState(false)
|
|
210
259
|
return (
|
|
@@ -321,116 +370,6 @@ export const WithTopContent = () => {
|
|
|
321
370
|
)
|
|
322
371
|
}
|
|
323
372
|
|
|
324
|
-
/**
|
|
325
|
-
* Exercises the panel re-measuring its height when body content changes.
|
|
326
|
-
* Use "Add"/"Remove" to grow and shrink the content: the drawer should re-fit
|
|
327
|
-
* its height each time, and once the content exceeds ~90% of the screen it
|
|
328
|
-
* should cap and the body should scroll instead of growing further.
|
|
329
|
-
*/
|
|
330
|
-
export const DynamicContent = () => {
|
|
331
|
-
const [count, setCount] = useState(1)
|
|
332
|
-
|
|
333
|
-
return (
|
|
334
|
-
<View style={styles.container}>
|
|
335
|
-
<Drawer.Root defaultOpen>
|
|
336
|
-
<Drawer.Trigger>
|
|
337
|
-
<Button variant="filled" colour="primary">
|
|
338
|
-
Open resizable drawer
|
|
339
|
-
</Button>
|
|
340
|
-
</Drawer.Trigger>
|
|
341
|
-
<Drawer.Portal>
|
|
342
|
-
<Drawer.Overlay />
|
|
343
|
-
<Drawer.Content>
|
|
344
|
-
<Drawer.Header variant="titleAndText">
|
|
345
|
-
<Drawer.Title>Resizable content</Drawer.Title>
|
|
346
|
-
<Drawer.Description>{`${count} paragraph${
|
|
347
|
-
count === 1 ? "" : "s"
|
|
348
|
-
}`}</Drawer.Description>
|
|
349
|
-
<Drawer.Close />
|
|
350
|
-
</Drawer.Header>
|
|
351
|
-
<Drawer.Body>
|
|
352
|
-
{Array.from({ length: count }, (_, i) => (
|
|
353
|
-
<Typography
|
|
354
|
-
key={i}
|
|
355
|
-
>{`Paragraph ${i + 1}: ${bodyText}`}</Typography>
|
|
356
|
-
))}
|
|
357
|
-
</Drawer.Body>
|
|
358
|
-
<Drawer.Footer>
|
|
359
|
-
<View style={styles.row}>
|
|
360
|
-
<Button
|
|
361
|
-
variant="filled"
|
|
362
|
-
colour="primary"
|
|
363
|
-
onPress={() => setCount((c) => c + 1)}
|
|
364
|
-
>
|
|
365
|
-
Add
|
|
366
|
-
</Button>
|
|
367
|
-
<Button
|
|
368
|
-
variant="outlined"
|
|
369
|
-
colour="secondary"
|
|
370
|
-
onPress={() => setCount((c) => Math.max(0, c - 1))}
|
|
371
|
-
>
|
|
372
|
-
Remove
|
|
373
|
-
</Button>
|
|
374
|
-
</View>
|
|
375
|
-
</Drawer.Footer>
|
|
376
|
-
</Drawer.Content>
|
|
377
|
-
</Drawer.Portal>
|
|
378
|
-
</Drawer.Root>
|
|
379
|
-
</View>
|
|
380
|
-
)
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Simulates async content loading: the drawer opens compact with a loading
|
|
385
|
-
* message, then re-fits taller once the "loaded" content arrives. Tap "Reload"
|
|
386
|
-
* to replay.
|
|
387
|
-
*/
|
|
388
|
-
export const AsyncContent = () => {
|
|
389
|
-
const [loaded, setLoaded] = useState(false)
|
|
390
|
-
|
|
391
|
-
const load = () => {
|
|
392
|
-
setLoaded(false)
|
|
393
|
-
setTimeout(() => setLoaded(true), 1200)
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return (
|
|
397
|
-
<View style={styles.container}>
|
|
398
|
-
<Drawer.Root onOpenChange={(open) => open && load()}>
|
|
399
|
-
<Drawer.Trigger>
|
|
400
|
-
<Button variant="filled" colour="primary">
|
|
401
|
-
Open async drawer
|
|
402
|
-
</Button>
|
|
403
|
-
</Drawer.Trigger>
|
|
404
|
-
<Drawer.Portal>
|
|
405
|
-
<Drawer.Overlay />
|
|
406
|
-
<Drawer.Content>
|
|
407
|
-
<Drawer.Header variant="titleAndText">
|
|
408
|
-
<Drawer.Title>Delivery details</Drawer.Title>
|
|
409
|
-
<Drawer.Close />
|
|
410
|
-
</Drawer.Header>
|
|
411
|
-
<Drawer.Body>
|
|
412
|
-
{loaded ? (
|
|
413
|
-
Array.from({ length: 5 }, (_, i) => (
|
|
414
|
-
<Typography
|
|
415
|
-
key={i}
|
|
416
|
-
>{`Detail ${i + 1}: ${bodyText}`}</Typography>
|
|
417
|
-
))
|
|
418
|
-
) : (
|
|
419
|
-
<Typography>Loading…</Typography>
|
|
420
|
-
)}
|
|
421
|
-
</Drawer.Body>
|
|
422
|
-
<Drawer.Footer>
|
|
423
|
-
<Button variant="filled" colour="primary" onPress={load}>
|
|
424
|
-
Reload
|
|
425
|
-
</Button>
|
|
426
|
-
</Drawer.Footer>
|
|
427
|
-
</Drawer.Content>
|
|
428
|
-
</Drawer.Portal>
|
|
429
|
-
</Drawer.Root>
|
|
430
|
-
</View>
|
|
431
|
-
)
|
|
432
|
-
}
|
|
433
|
-
|
|
434
373
|
const styles = StyleSheet.create({
|
|
435
374
|
container: {
|
|
436
375
|
padding: 16
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
type LayoutChangeEvent,
|
|
4
|
-
ScrollView,
|
|
5
|
-
ScrollViewProps
|
|
6
|
-
} from "react-native"
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { ScrollView, ScrollViewProps, useWindowDimensions } from "react-native"
|
|
7
3
|
import styled from "@emotion/native"
|
|
8
4
|
import { useTheme } from "@emotion/react"
|
|
9
5
|
import { useDrawerHeaderContext } from "./DrawerHeaderContext"
|
|
10
6
|
import { useDrawerFooterContext } from "./DrawerFooterContext"
|
|
11
|
-
import { useDrawerMeasureContext } from "./DrawerMeasureContext"
|
|
12
7
|
|
|
13
8
|
export type DrawerBodyProps = ScrollViewProps
|
|
14
9
|
|
|
@@ -18,22 +13,21 @@ const StyledScrollView = styled(ScrollView)<{
|
|
|
18
13
|
bodyPaddingHorizontal: number
|
|
19
14
|
bodyPaddingRight: number
|
|
20
15
|
bodyGap: number
|
|
16
|
+
bodyMaxHeight: number
|
|
21
17
|
bodyPaddingBottom: number
|
|
22
18
|
}>(
|
|
23
19
|
({
|
|
24
20
|
bodyPaddingHorizontal,
|
|
25
21
|
bodyPaddingRight,
|
|
26
22
|
bodyGap,
|
|
23
|
+
bodyMaxHeight,
|
|
27
24
|
bodyPaddingBottom
|
|
28
25
|
}) => ({
|
|
29
|
-
// flex: 1 fills the bounded panel so the ScrollView can scroll. The panel
|
|
30
|
-
// (DrawerContent) is the single height authority — the body must NOT set
|
|
31
|
-
// its own maxHeight, or it would cap independently of the panel and corrupt
|
|
32
|
-
// the panel's chrome measurement.
|
|
33
26
|
flex: 1,
|
|
34
27
|
paddingLeft: bodyPaddingHorizontal,
|
|
35
28
|
paddingRight: bodyPaddingRight,
|
|
36
29
|
gap: bodyGap,
|
|
30
|
+
maxHeight: bodyMaxHeight,
|
|
37
31
|
paddingBottom: bodyPaddingBottom
|
|
38
32
|
})
|
|
39
33
|
)
|
|
@@ -43,45 +37,19 @@ const StyledScrollView = styled(ScrollView)<{
|
|
|
43
37
|
* between the header and footer.
|
|
44
38
|
*/
|
|
45
39
|
export const DrawerBody = React.forwardRef<ScrollView, DrawerBodyProps>(
|
|
46
|
-
(
|
|
47
|
-
{
|
|
48
|
-
children,
|
|
49
|
-
contentContainerStyle,
|
|
50
|
-
onLayout,
|
|
51
|
-
onContentSizeChange,
|
|
52
|
-
...props
|
|
53
|
-
},
|
|
54
|
-
ref
|
|
55
|
-
) => {
|
|
40
|
+
({ children, contentContainerStyle, ...props }, ref) => {
|
|
56
41
|
const theme = useTheme()
|
|
57
42
|
const { spacing } = theme.tokens.components.drawer
|
|
58
43
|
const { buttons } = theme.tokens.components
|
|
59
44
|
const { content } = spacing
|
|
60
45
|
const headerContext = useDrawerHeaderContext()
|
|
61
46
|
const footerContext = useDrawerFooterContext()
|
|
62
|
-
const
|
|
47
|
+
const { height: windowHeight } = useWindowDimensions()
|
|
63
48
|
|
|
64
49
|
const gap = parseTokenValue(content.slot.gap)
|
|
65
50
|
const horizontalPadding = parseTokenValue(content.slot.horizontalPadding)
|
|
66
51
|
const topPadding = parseTokenValue(content.slot.verticalPadding)
|
|
67
|
-
|
|
68
|
-
// Report the ScrollView's frame and content heights so DrawerContent can
|
|
69
|
-
// re-fit the panel when the body content changes.
|
|
70
|
-
const handleLayout = useCallback(
|
|
71
|
-
(event: LayoutChangeEvent) => {
|
|
72
|
-
measureContext?.setBodyFrameHeight(event.nativeEvent.layout.height)
|
|
73
|
-
onLayout?.(event)
|
|
74
|
-
},
|
|
75
|
-
[measureContext, onLayout]
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
const handleContentSizeChange = useCallback(
|
|
79
|
-
(width: number, height: number) => {
|
|
80
|
-
measureContext?.setBodyContentHeight(height)
|
|
81
|
-
onContentSizeChange?.(width, height)
|
|
82
|
-
},
|
|
83
|
-
[measureContext, onContentSizeChange]
|
|
84
|
-
)
|
|
52
|
+
const bodyMaxHeight = windowHeight - 300
|
|
85
53
|
|
|
86
54
|
// When there's no header the close button floats in the top-right corner.
|
|
87
55
|
// Reserve space on the right so body content doesn't slide under it.
|
|
@@ -101,9 +69,8 @@ export const DrawerBody = React.forwardRef<ScrollView, DrawerBodyProps>(
|
|
|
101
69
|
bodyPaddingHorizontal={horizontalPadding}
|
|
102
70
|
bodyPaddingRight={paddingRight}
|
|
103
71
|
bodyGap={gap}
|
|
72
|
+
bodyMaxHeight={bodyMaxHeight}
|
|
104
73
|
bodyPaddingBottom={bodyPaddingBottom}
|
|
105
|
-
onLayout={handleLayout}
|
|
106
|
-
onContentSizeChange={handleContentSizeChange}
|
|
107
74
|
contentContainerStyle={[
|
|
108
75
|
{
|
|
109
76
|
gap,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useMemo, useRef
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef } from "react"
|
|
2
2
|
import {
|
|
3
3
|
Animated,
|
|
4
4
|
Easing,
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
import styled from "@emotion/native"
|
|
12
12
|
import { useTheme } from "@emotion/react"
|
|
13
13
|
import { DrawerDragContext } from "./DrawerDragContext"
|
|
14
|
-
import { DrawerMeasureContext } from "./DrawerMeasureContext"
|
|
15
14
|
import { useDrawerContext } from "./DrawerContext"
|
|
16
15
|
import { DrawerFooterContext } from "./DrawerFooterContext"
|
|
17
16
|
import {
|
|
@@ -36,7 +35,7 @@ const StyledPanel = styled(View)<{
|
|
|
36
35
|
panelShadowColor: string
|
|
37
36
|
panelShadowOffsetY: number
|
|
38
37
|
panelShadowBlur: number
|
|
39
|
-
|
|
38
|
+
panelMaxHeight: number
|
|
40
39
|
}>(
|
|
41
40
|
({
|
|
42
41
|
panelBorderRadius,
|
|
@@ -47,12 +46,17 @@ const StyledPanel = styled(View)<{
|
|
|
47
46
|
panelShadowColor,
|
|
48
47
|
panelShadowOffsetY,
|
|
49
48
|
panelShadowBlur,
|
|
50
|
-
|
|
49
|
+
panelMaxHeight
|
|
51
50
|
}) => ({
|
|
52
51
|
width: "100%",
|
|
53
52
|
maxWidth: panelMaxWidth,
|
|
53
|
+
// The panel wraps its content and caps at maxHeight. It is intentionally
|
|
54
|
+
// NOT given a fixed height: letting it size to content means it re-fits
|
|
55
|
+
// automatically whenever the body grows or shrinks (async load, expanding
|
|
56
|
+
// sections). The body's own maxHeight (see DrawerBody) bounds scrolling and
|
|
57
|
+
// keeps the ScrollView from collapsing, so no fixed panel height is needed.
|
|
58
|
+
maxHeight: panelMaxHeight,
|
|
54
59
|
alignSelf: "center",
|
|
55
|
-
...(panelFlex != null ? { flex: panelFlex } : undefined),
|
|
56
60
|
borderTopLeftRadius: panelBorderRadius,
|
|
57
61
|
borderTopRightRadius: panelBorderRadius,
|
|
58
62
|
borderTopWidth: panelBorderWidth,
|
|
@@ -100,10 +104,6 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
100
104
|
|
|
101
105
|
const { height: windowHeight } = useWindowDimensions()
|
|
102
106
|
const maxHeight = windowHeight * 0.9
|
|
103
|
-
// Tallest the body content is allowed to grow before it scrolls. Enforced
|
|
104
|
-
// here (via the panel height) rather than as a maxHeight on the body
|
|
105
|
-
// ScrollView, so the panel stays the single height authority.
|
|
106
|
-
const bodyMaxHeight = windowHeight - 300
|
|
107
107
|
|
|
108
108
|
// Keep a ref so the PanResponder (created once) always calls the latest
|
|
109
109
|
// closeDrawer without becoming a stale closure.
|
|
@@ -119,12 +119,6 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
119
119
|
const isOpenRef = useRef(isOpen)
|
|
120
120
|
const activeAnim = useRef<Animated.CompositeAnimation | null>(null)
|
|
121
121
|
|
|
122
|
-
// After the first onLayout we know the real rendered height (capped at
|
|
123
|
-
// MAX_HEIGHT). We immediately kick off the entry animation from that height
|
|
124
|
-
// and then set explicit height + flex: 1 on the panel so DrawerBody's
|
|
125
|
-
// ScrollView gets a bounded container and can scroll correctly.
|
|
126
|
-
const [panelHeight, setPanelHeight] = useState(0)
|
|
127
|
-
|
|
128
122
|
useEffect(() => {
|
|
129
123
|
const id = translateY.addListener(({ value }) => {
|
|
130
124
|
translateYValue.current = value
|
|
@@ -132,15 +126,6 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
132
126
|
return () => translateY.removeListener(id)
|
|
133
127
|
}, [translateY])
|
|
134
128
|
|
|
135
|
-
// Clamp the cached panel height when the window shrinks (e.g. orientation
|
|
136
|
-
// change) so the entry animation never starts from below the screen.
|
|
137
|
-
useEffect(() => {
|
|
138
|
-
if (panelHeightRef.current > 0 && panelHeightRef.current > maxHeight) {
|
|
139
|
-
setPanelHeight(maxHeight)
|
|
140
|
-
panelHeightRef.current = maxHeight
|
|
141
|
-
}
|
|
142
|
-
}, [maxHeight])
|
|
143
|
-
|
|
144
129
|
const runEntry = useCallback(() => {
|
|
145
130
|
if (panelHeightRef.current === 0) return
|
|
146
131
|
translateY.setValue(panelHeightRef.current)
|
|
@@ -190,85 +175,25 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
190
175
|
|
|
191
176
|
const onLayout = useCallback(
|
|
192
177
|
({ nativeEvent }: { nativeEvent: { layout: { height: number } } }) => {
|
|
193
|
-
// This only bootstraps the first measurement and the entry animation.
|
|
194
|
-
// After entry has run, applyDesiredHeight (driven by the body's
|
|
195
|
-
// content size) is the SOLE authority for panel height — this handler
|
|
196
|
-
// must not keep overriding it, or the two fight and the panel gets
|
|
197
|
-
// pinned to chrome + bodyFrame (leaving a gap) instead of
|
|
198
|
-
// chrome + content.
|
|
199
|
-
if (entryRanRef.current) return
|
|
200
|
-
|
|
201
178
|
const h = nativeEvent.layout.height
|
|
202
179
|
const capped = Math.min(h, maxHeight)
|
|
203
180
|
if (capped <= 0) return
|
|
204
181
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
182
|
+
// The panel wraps its content, so this fires again whenever the body
|
|
183
|
+
// grows or shrinks. Keep the cached height current for the entry/exit
|
|
184
|
+
// and drag-dismiss animations; the panel re-fits itself via layout, so
|
|
185
|
+
// there is nothing else to do here (no state, no feedback loop).
|
|
186
|
+
panelHeightRef.current = capped
|
|
209
187
|
|
|
210
|
-
|
|
188
|
+
// Kick off the entry animation on the first measurement. translateY is
|
|
189
|
+
// still off-screen (9999) at this point, so there is no visible jump.
|
|
190
|
+
if (isOpenRef.current && !entryRanRef.current) {
|
|
211
191
|
runEntry()
|
|
212
192
|
}
|
|
213
193
|
},
|
|
214
194
|
[runEntry, maxHeight]
|
|
215
195
|
)
|
|
216
196
|
|
|
217
|
-
// Re-fit the panel height whenever the body content changes. Desired height
|
|
218
|
-
// is the absolute `chrome + content` (clamped to bodyMax, then maxHeight).
|
|
219
|
-
// `chrome` (header + footer + padding + borders) is invariant for a given
|
|
220
|
-
// drawer, so it is measured ONCE and locked. Deriving it repeatedly from
|
|
221
|
-
// `panelHeight - bodyFrame` is unsafe: those two are only consistent at a
|
|
222
|
-
// settled layout, and mid-resize the frame lags, which inflates chrome and
|
|
223
|
-
// pins the panel to chrome + frame (a gap) instead of chrome + content.
|
|
224
|
-
const chromeRef = useRef(0)
|
|
225
|
-
const bodyContentRef = useRef(0)
|
|
226
|
-
|
|
227
|
-
const applyDesiredHeight = useCallback(() => {
|
|
228
|
-
const chrome = chromeRef.current
|
|
229
|
-
const content = bodyContentRef.current
|
|
230
|
-
const current = panelHeightRef.current
|
|
231
|
-
if (chrome <= 0 || content <= 0 || current <= 0) return
|
|
232
|
-
const desired = Math.min(
|
|
233
|
-
chrome + Math.min(content, bodyMaxHeight),
|
|
234
|
-
maxHeight
|
|
235
|
-
)
|
|
236
|
-
if (Math.abs(desired - current) > 1) {
|
|
237
|
-
panelHeightRef.current = desired
|
|
238
|
-
setPanelHeight(desired)
|
|
239
|
-
}
|
|
240
|
-
}, [maxHeight, bodyMaxHeight])
|
|
241
|
-
|
|
242
|
-
const setBodyFrameHeight = useCallback(
|
|
243
|
-
(frameHeight: number) => {
|
|
244
|
-
// Lock chrome once, from the first settled measurement (initial layout,
|
|
245
|
-
// before any content toggling), where panelHeight and bodyFrame are
|
|
246
|
-
// consistent. It stays fixed thereafter.
|
|
247
|
-
if (chromeRef.current <= 0) {
|
|
248
|
-
const current = panelHeightRef.current
|
|
249
|
-
if (frameHeight > 0 && current > frameHeight) {
|
|
250
|
-
chromeRef.current = current - frameHeight
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
applyDesiredHeight()
|
|
254
|
-
},
|
|
255
|
-
[applyDesiredHeight]
|
|
256
|
-
)
|
|
257
|
-
|
|
258
|
-
const setBodyContentHeight = useCallback(
|
|
259
|
-
(contentHeight: number) => {
|
|
260
|
-
if (contentHeight <= 0) return
|
|
261
|
-
bodyContentRef.current = contentHeight
|
|
262
|
-
applyDesiredHeight()
|
|
263
|
-
},
|
|
264
|
-
[applyDesiredHeight]
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
const measureContextValue = useMemo(
|
|
268
|
-
() => ({ setBodyFrameHeight, setBodyContentHeight }),
|
|
269
|
-
[setBodyFrameHeight, setBodyContentHeight]
|
|
270
|
-
)
|
|
271
|
-
|
|
272
197
|
const panResponder = useRef(
|
|
273
198
|
PanResponder.create({
|
|
274
199
|
// Claim the responder as soon as a touch starts on the grabber so the
|
|
@@ -353,37 +278,31 @@ export const DrawerContent = React.forwardRef<View, DrawerContentProps>(
|
|
|
353
278
|
return (
|
|
354
279
|
<DrawerHeaderContext.Provider value={headerContextValue}>
|
|
355
280
|
<DrawerFooterContext.Provider value={hasFooter}>
|
|
356
|
-
<
|
|
357
|
-
<
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
281
|
+
<DrawerDragContext.Provider value={dragContextValue}>
|
|
282
|
+
<Animated.View
|
|
283
|
+
style={[styles.animatedWrapper, { transform: [{ translateY }] }]}
|
|
284
|
+
>
|
|
285
|
+
<StyledPanel
|
|
286
|
+
ref={ref}
|
|
287
|
+
onLayout={onLayout}
|
|
288
|
+
panelBorderRadius={parseTokenValue(drawer.borderRadius.top)}
|
|
289
|
+
panelBgColor={colour.background.container.default}
|
|
290
|
+
panelMaxWidth={parseTokenValue(drawer.size.maxWidth)}
|
|
291
|
+
panelMaxHeight={maxHeight}
|
|
292
|
+
panelBorderWidth={parseTokenValue(dimensions.borderWidth.sm)}
|
|
293
|
+
panelBorderColor={colour.border.default}
|
|
294
|
+
panelShadowColor={modal.shadow.color}
|
|
295
|
+
panelShadowOffsetY={parseTokenValue(modal.shadow.offsetY)}
|
|
296
|
+
panelShadowBlur={parseTokenValue(modal.shadow.blur)}
|
|
297
|
+
accessible
|
|
298
|
+
accessibilityRole="none"
|
|
299
|
+
accessibilityViewIsModal
|
|
300
|
+
{...props}
|
|
364
301
|
>
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
panelBgColor={colour.background.container.default}
|
|
370
|
-
panelMaxWidth={parseTokenValue(drawer.size.maxWidth)}
|
|
371
|
-
panelFlex={panelHeight > 0 ? 1 : undefined}
|
|
372
|
-
panelBorderWidth={parseTokenValue(dimensions.borderWidth.sm)}
|
|
373
|
-
panelBorderColor={colour.border.default}
|
|
374
|
-
panelShadowColor={modal.shadow.color}
|
|
375
|
-
panelShadowOffsetY={parseTokenValue(modal.shadow.offsetY)}
|
|
376
|
-
panelShadowBlur={parseTokenValue(modal.shadow.blur)}
|
|
377
|
-
accessible
|
|
378
|
-
accessibilityRole="none"
|
|
379
|
-
accessibilityViewIsModal
|
|
380
|
-
{...props}
|
|
381
|
-
>
|
|
382
|
-
{children}
|
|
383
|
-
</StyledPanel>
|
|
384
|
-
</Animated.View>
|
|
385
|
-
</DrawerDragContext.Provider>
|
|
386
|
-
</DrawerMeasureContext.Provider>
|
|
302
|
+
{children}
|
|
303
|
+
</StyledPanel>
|
|
304
|
+
</Animated.View>
|
|
305
|
+
</DrawerDragContext.Provider>
|
|
387
306
|
</DrawerFooterContext.Provider>
|
|
388
307
|
</DrawerHeaderContext.Provider>
|
|
389
308
|
)
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
|
|
3
|
-
export type DrawerMeasureContextValue = {
|
|
4
|
-
/**
|
|
5
|
-
* The drawer body's ScrollView frame height (its laid-out size). Together
|
|
6
|
-
* with the panel height this yields the fixed "chrome" (header + footer +
|
|
7
|
-
* padding), since panel height always equals chrome + body frame.
|
|
8
|
-
*/
|
|
9
|
-
setBodyFrameHeight: (height: number) => void
|
|
10
|
-
/**
|
|
11
|
-
* The drawer body's content height (full scrollable content). Drives the
|
|
12
|
-
* panel's desired height as `chrome + content`, so the drawer re-fits when
|
|
13
|
-
* content changes.
|
|
14
|
-
*/
|
|
15
|
-
setBodyContentHeight: (height: number) => void
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const DrawerMeasureContext =
|
|
19
|
-
React.createContext<DrawerMeasureContextValue | null>(null)
|
|
20
|
-
|
|
21
|
-
export const useDrawerMeasureContext = () =>
|
|
22
|
-
React.useContext(DrawerMeasureContext)
|