forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {interpolate, useAnimatedStyle} from 'react-native-reanimated'
2import {useSafeAreaInsets} from 'react-native-safe-area-context'
3
4import {useMinimalShellMode} from '#/state/shell/minimal-mode'
5import {useShellLayout} from '#/state/shell/shell-layout'
6import {IS_LIQUID_GLASS} from '#/env'
7
8// Keep these separated so that we only pay for useAnimatedStyle that gets used.
9
10export function useMinimalShellHeaderTransform() {
11 const {headerMode} = useMinimalShellMode()
12 const {headerHeight} = useShellLayout()
13 const {top: topInset} = useSafeAreaInsets()
14
15 const headerPinnedHeight = IS_LIQUID_GLASS ? topInset : 0
16
17 const headerTransform = useAnimatedStyle(() => {
18 const headerModeValue = headerMode.get()
19 const hHeight = headerHeight.get()
20
21 if (IS_LIQUID_GLASS) {
22 // bit of a hackfix, but: the header can get affected by scrollEdgeEffects
23 // when animating from closed to open. workaround is to trigger a relayout
24 // by offsetting the top position. the actual value doesn't matter, and we
25 // simultaneously offset it using the translate transform.
26 // I think a cleaner way to do it would be to use UIScrollEdgeElementContainerInteraction
27 // manually or something like that, because this kinda sucks -sfn
28 const relayoutingOffset = headerModeValue === 0 ? 1 : 0
29 return {
30 top: relayoutingOffset,
31 pointerEvents: headerModeValue === 0 ? 'auto' : 'none',
32 opacity: Math.pow(1 - headerModeValue, 2),
33 transform: [
34 {
35 translateY:
36 interpolate(
37 headerModeValue,
38 [0, 1],
39 [0, headerPinnedHeight - hHeight],
40 ) - relayoutingOffset,
41 },
42 ],
43 }
44 }
45
46 return {
47 pointerEvents: headerModeValue === 0 ? 'auto' : 'none',
48 opacity: Math.pow(1 - headerModeValue, 2),
49 transform: [
50 {
51 translateY: interpolate(headerModeValue, [0, 1], [0, -hHeight]),
52 },
53 ],
54 }
55 })
56
57 return headerTransform
58}
59
60export function useMinimalShellFooterTransform() {
61 const {footerMode} = useMinimalShellMode()
62 const {footerHeight} = useShellLayout()
63
64 const footerTransform = useAnimatedStyle(() => {
65 const footerModeValue = footerMode.get()
66 return {
67 pointerEvents: footerModeValue === 0 ? 'auto' : 'none',
68 opacity: Math.pow(1 - footerModeValue, 2),
69 transform: [
70 {
71 translateY: interpolate(
72 footerModeValue,
73 [0, 1],
74 [0, footerHeight.get()],
75 ),
76 },
77 ],
78 }
79 })
80
81 return footerTransform
82}
83
84export function useMinimalShellFabTransform() {
85 const {footerMode} = useMinimalShellMode()
86
87 const fabTransform = useAnimatedStyle(() => {
88 return {
89 transform: [
90 {
91 translateY: interpolate(footerMode.get(), [0, 1], [-44, 0]),
92 },
93 ],
94 }
95 })
96 return fabTransform
97}