@fountain-ui/lab 3.0.0-alpha.2 → 3.0.0-alpha.21

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.
Files changed (77) hide show
  1. package/build/commonjs/AnimatedY/AnimatedY.js +1 -1
  2. package/build/commonjs/AnimatedY/AnimatedY.js.map +1 -1
  3. package/build/commonjs/BottomSheet/BottomSheetNative.js +39 -12
  4. package/build/commonjs/BottomSheet/BottomSheetNative.js.map +1 -1
  5. package/build/commonjs/BottomSheet/BottomSheetProps.js.map +1 -1
  6. package/build/commonjs/BottomSheet/BottomSheetWeb.js +15 -9
  7. package/build/commonjs/BottomSheet/BottomSheetWeb.js.map +1 -1
  8. package/build/commonjs/BottomSheet/useDynamicSnapPoints.js +1 -7
  9. package/build/commonjs/BottomSheet/useDynamicSnapPoints.js.map +1 -1
  10. package/build/commonjs/BottomSheet/useDynamicSnapPoints.native.js +22 -0
  11. package/build/commonjs/BottomSheet/useDynamicSnapPoints.native.js.map +1 -0
  12. package/build/commonjs/Carousel/Carousel.js +4 -2
  13. package/build/commonjs/Carousel/Carousel.js.map +1 -1
  14. package/build/commonjs/Carousel/CarouselProps.js.map +1 -1
  15. package/build/commonjs/Carousel/components/InternalContext.js +2 -1
  16. package/build/commonjs/Carousel/components/InternalContext.js.map +1 -1
  17. package/build/commonjs/Carousel/components/ItemView.js +3 -1
  18. package/build/commonjs/Carousel/components/ItemView.js.map +1 -1
  19. package/build/commonjs/ComicViewer/FastScroll.js +9 -11
  20. package/build/commonjs/ComicViewer/FastScroll.js.map +1 -1
  21. package/build/commonjs/FlipCard/FlipCard.js +2 -2
  22. package/build/commonjs/FlipCard/FlipCard.js.map +1 -1
  23. package/build/commonjs/StatusBarProvider/StatusBarProvider.js +1 -1
  24. package/build/commonjs/StatusBarProvider/StatusBarProvider.js.map +1 -1
  25. package/build/commonjs/hooks/useUnstableCollapsibleAppBar.js +2 -6
  26. package/build/commonjs/hooks/useUnstableCollapsibleAppBar.js.map +1 -1
  27. package/build/commonjs/hooks/useUnstableToggleDisplayStyle.js +1 -1
  28. package/build/commonjs/hooks/useUnstableToggleDisplayStyle.js.map +1 -1
  29. package/build/module/AnimatedY/AnimatedY.js +1 -1
  30. package/build/module/AnimatedY/AnimatedY.js.map +1 -1
  31. package/build/module/BottomSheet/BottomSheetNative.js +37 -13
  32. package/build/module/BottomSheet/BottomSheetNative.js.map +1 -1
  33. package/build/module/BottomSheet/BottomSheetProps.js.map +1 -1
  34. package/build/module/BottomSheet/BottomSheetWeb.js +14 -9
  35. package/build/module/BottomSheet/BottomSheetWeb.js.map +1 -1
  36. package/build/module/BottomSheet/useDynamicSnapPoints.js +2 -8
  37. package/build/module/BottomSheet/useDynamicSnapPoints.js.map +1 -1
  38. package/build/module/BottomSheet/useDynamicSnapPoints.native.js +14 -0
  39. package/build/module/BottomSheet/useDynamicSnapPoints.native.js.map +1 -0
  40. package/build/module/Carousel/Carousel.js +4 -2
  41. package/build/module/Carousel/Carousel.js.map +1 -1
  42. package/build/module/Carousel/CarouselProps.js.map +1 -1
  43. package/build/module/Carousel/components/InternalContext.js +2 -1
  44. package/build/module/Carousel/components/InternalContext.js.map +1 -1
  45. package/build/module/Carousel/components/ItemView.js +3 -1
  46. package/build/module/Carousel/components/ItemView.js.map +1 -1
  47. package/build/module/ComicViewer/FastScroll.js +6 -9
  48. package/build/module/ComicViewer/FastScroll.js.map +1 -1
  49. package/build/module/FlipCard/FlipCard.js +2 -2
  50. package/build/module/FlipCard/FlipCard.js.map +1 -1
  51. package/build/module/StatusBarProvider/StatusBarProvider.js +1 -1
  52. package/build/module/StatusBarProvider/StatusBarProvider.js.map +1 -1
  53. package/build/module/hooks/useUnstableCollapsibleAppBar.js +2 -6
  54. package/build/module/hooks/useUnstableCollapsibleAppBar.js.map +1 -1
  55. package/build/module/hooks/useUnstableToggleDisplayStyle.js +1 -1
  56. package/build/module/hooks/useUnstableToggleDisplayStyle.js.map +1 -1
  57. package/build/typescript/BottomSheet/BottomSheetProps.d.ts +9 -1
  58. package/build/typescript/BottomSheet/useDynamicSnapPoints.native.d.ts +21 -0
  59. package/build/typescript/Carousel/Carousel.d.ts +1 -1
  60. package/build/typescript/Carousel/CarouselProps.d.ts +7 -0
  61. package/build/typescript/Carousel/components/InternalContext.d.ts +1 -0
  62. package/package.json +5 -4
  63. package/src/AnimatedY/AnimatedY.tsx +1 -1
  64. package/src/BottomSheet/BottomSheetNative.tsx +51 -18
  65. package/src/BottomSheet/BottomSheetProps.ts +11 -1
  66. package/src/BottomSheet/BottomSheetWeb.tsx +15 -7
  67. package/src/BottomSheet/useDynamicSnapPoints.native.ts +15 -0
  68. package/src/BottomSheet/useDynamicSnapPoints.ts +2 -9
  69. package/src/Carousel/Carousel.tsx +3 -0
  70. package/src/Carousel/CarouselProps.ts +8 -0
  71. package/src/Carousel/components/InternalContext.ts +2 -0
  72. package/src/Carousel/components/ItemView.tsx +2 -0
  73. package/src/ComicViewer/FastScroll.tsx +7 -13
  74. package/src/FlipCard/FlipCard.tsx +2 -2
  75. package/src/StatusBarProvider/StatusBarProvider.tsx +2 -2
  76. package/src/hooks/useUnstableCollapsibleAppBar.ts +2 -6
  77. package/src/hooks/useUnstableToggleDisplayStyle.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"names":["useCallback","useRef","Platform","useAnimatedScrollHandler","useAnimatedStyle","useDerivedValue","useSharedValue","withTiming","useSafeAreaInsets","useAppbarStyles","useElevationStyle","useHeight","defaultOptions","shouldTranslateYReset","ANIMATION_DURATION_MILLIS","SUPPORTS_DRAG_DETECTION","OS","useLargerValueOfLastTwoValues","value","refLatestTwoValues","current","shift","push","Math","max","useUnstableCollapsibleAppBar","userOptions","styles","safeAreaInsets","appBarHeight","onAppBarLayout","appBarMaxHeight","collapsibleToolbarHeight","onCollapsibleToolbarLayout","maxTranslateY","translateY","lastTranslateY","lastOffsetY","prevOffsetY","overlapped","vectorY","elevationStyle","animatedStyle","transform","boxShadow","elevation","shadowColor","shadowOffset","shadowRadius","shadowOpacity","indexRef","offsetsRef","onScrollViewChanged","nextIndex","prevIndex","duration","savedOffsetY","scrollHandler","onBeginDrag","onMomentumBegin","onScroll","event","offsetY","contentOffset","y","ty","maxTy","deltaY","dy","min","onEndDrag","onMomentumEnd","threshold","nextTranslateY","hasCollapsible","appBarStyle","paddingTop","top","floating","undefined","scrollContentInsets"],"sources":["useUnstableCollapsibleAppBar.ts"],"sourcesContent":["import { useCallback, useRef } from 'react';\nimport { Falsy, Platform, RegisteredStyle, ScrollViewProps, ViewProps, ViewStyle } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport {\n useAnimatedScrollHandler,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport useAppbarStyles from './useAppbarStyles';\nimport useElevationStyle from './useElevationStyle';\nimport useHeight from './useHeight';\n\ntype WebOnlyStyle = { boxShadow: any };\n\ntype ViewStyleProp = Array<ViewStyle | RegisteredStyle<ViewStyle> | WebOnlyStyle | Falsy>;\n\ntype OnScroll = ScrollViewProps['onScroll'];\n\ntype OnLayoutCallback = ViewProps['onLayout'];\n\nexport interface ContentInsets {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n}\n\nexport interface Options {\n shouldTranslateYReset?: boolean;\n}\n\nexport interface CollapsibleAppBar {\n appBarStyle: ViewStyleProp;\n vectorY: SharedValue<number>;\n onAppBarLayout: OnLayoutCallback;\n onCollapsibleToolbarLayout: OnLayoutCallback;\n onScroll: OnScroll;\n onScrollViewChanged: (index: number) => void;\n scrollContentInsets: ContentInsets;\n}\n\nconst defaultOptions: Required<Options> = {\n shouldTranslateYReset: false,\n};\n\nconst ANIMATION_DURATION_MILLIS = 100;\n\nconst SUPPORTS_DRAG_DETECTION = Platform.OS !== 'web';\n\nfunction useLargerValueOfLastTwoValues(value: number) {\n const refLatestTwoValues = useRef([0, 0]);\n\n refLatestTwoValues.current.shift();\n refLatestTwoValues.current.push(value);\n\n return Math.max(...refLatestTwoValues.current);\n}\n\nexport default function useUnstableCollapsibleAppBar(userOptions: Options = defaultOptions): CollapsibleAppBar {\n const { shouldTranslateYReset }: Required<Options> = {\n ...defaultOptions,\n ...userOptions,\n };\n\n const styles = useAppbarStyles();\n\n const safeAreaInsets = useSafeAreaInsets();\n\n const [appBarHeight, onAppBarLayout] = useHeight();\n const appBarMaxHeight = useLargerValueOfLastTwoValues(appBarHeight);\n const [collapsibleToolbarHeight, onCollapsibleToolbarLayout] = useHeight();\n\n const maxTranslateY = useDerivedValue(() => -collapsibleToolbarHeight, [collapsibleToolbarHeight]);\n\n const translateY = useSharedValue<number>(0);\n const lastTranslateY = useSharedValue<number>(0);\n const lastOffsetY = useSharedValue<number>(0);\n const prevOffsetY = useSharedValue<number>(0);\n const overlapped = useSharedValue<boolean>(false);\n const vectorY = useSharedValue<number>(0);\n\n const elevationStyle = useElevationStyle(4);\n const animatedStyle = useAnimatedStyle(() => {\n const transform = [{ translateY: translateY.value }];\n\n if (Platform.OS === 'web') {\n return {\n transform,\n boxShadow: overlapped.value ? elevationStyle?.boxShadow : 0,\n };\n }\n if (Platform.OS === 'android') {\n return {\n transform,\n elevation: overlapped.value ? elevationStyle?.elevation : 0,\n };\n }\n if (Platform.OS === 'ios') {\n return {\n transform,\n shadowColor: elevationStyle?.shadowColor,\n shadowOffset: elevationStyle?.shadowOffset,\n shadowRadius: elevationStyle?.shadowRadius,\n shadowOpacity: overlapped.value ? elevationStyle?.shadowOpacity : 0,\n };\n }\n return {};\n }, [\n /**\n * FIXME: Consider add `elevationStyle` to dependencies.\n */\n ]);\n\n const indexRef = useRef<number>(0);\n const offsetsRef = useRef<Array<number>>([]);\n\n const onScrollViewChanged = useCallback((nextIndex: number) => {\n const prevIndex = indexRef.current;\n if (prevIndex === nextIndex) {\n if (shouldTranslateYReset) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n\n vectorY.value = 0;\n offsetsRef.current = [];\n overlapped.value = false;\n }\n\n return;\n }\n\n offsetsRef.current[prevIndex] = lastOffsetY.value;\n\n const savedOffsetY = offsetsRef.current[nextIndex] ?? 0;\n lastOffsetY.value = savedOffsetY;\n\n indexRef.current = nextIndex;\n\n // Determine whether to overlap every time index is changed.\n overlapped.value = savedOffsetY > 0;\n\n // If next ScrollView's offset is too short, expand app bar.\n if (translateY.value < 0 && savedOffsetY < appBarHeight) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n\n vectorY.value = 0;\n }\n }, [appBarHeight]);\n\n const scrollHandler = useAnimatedScrollHandler({\n onBeginDrag: () => {\n lastTranslateY.value = translateY.value;\n },\n onMomentumBegin: () => {\n lastTranslateY.value = translateY.value;\n },\n onScroll: (event) => {\n const offsetY = event.contentOffset.y;\n\n const ty = translateY.value;\n const maxTy = maxTranslateY.value;\n\n const deltaY = offsetY - prevOffsetY.value;\n vectorY.value = (vectorY.value * deltaY >= 0 && offsetY > 0) ? vectorY.value + deltaY : deltaY;\n prevOffsetY.value = offsetY;\n\n if (SUPPORTS_DRAG_DETECTION) {\n const dy = offsetY - lastOffsetY.value;\n\n translateY.value = offsetY <= 0 ? 0 : Math.min(Math.max(lastTranslateY.value - dy, maxTy), 0);\n\n overlapped.value = offsetY + translateY.value > 0;\n } else {\n if (offsetY > -maxTy) {\n if (ty === 0) {\n translateY.value = withTiming(Math.min(Math.max(-offsetY, maxTy), 0), {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n } else {\n if (ty === maxTy) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n }\n\n overlapped.value = offsetY > 0;\n\n lastOffsetY.value = offsetY;\n }\n },\n onEndDrag: (event) => {\n lastOffsetY.value = event.contentOffset.y;\n },\n onMomentumEnd: (event) => {\n const offsetY = event.contentOffset.y;\n\n lastOffsetY.value = offsetY;\n\n const ty = translateY.value;\n const maxTy = maxTranslateY.value;\n\n // If toolbar is already positioned on edge, do nothing.\n if (ty <= maxTy || ty >= 0) {\n return;\n }\n\n const threshold = maxTy * 0.5;\n\n const nextTranslateY = (ty > threshold || offsetY < appBarHeight) ? 0 : maxTy;\n\n overlapped.value = offsetY + nextTranslateY > 0;\n\n translateY.value = withTiming(nextTranslateY, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n },\n }, [appBarHeight]);\n\n const hasCollapsible = collapsibleToolbarHeight > 0;\n\n const appBarStyle = [\n animatedStyle,\n { paddingTop: safeAreaInsets.top },\n hasCollapsible ? styles.floating : undefined,\n ];\n\n return {\n appBarStyle,\n vectorY,\n onAppBarLayout,\n onCollapsibleToolbarLayout,\n onScroll: scrollHandler,\n onScrollViewChanged,\n scrollContentInsets: { top: hasCollapsible ? appBarMaxHeight : 0 },\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"names":["useCallback","useRef","Platform","useAnimatedScrollHandler","useAnimatedStyle","useDerivedValue","useSharedValue","withTiming","useSafeAreaInsets","useAppbarStyles","useElevationStyle","useHeight","defaultOptions","shouldTranslateYReset","ANIMATION_DURATION_MILLIS","SUPPORTS_DRAG_DETECTION","OS","useLargerValueOfLastTwoValues","value","refLatestTwoValues","current","shift","push","Math","max","useUnstableCollapsibleAppBar","userOptions","styles","safeAreaInsets","appBarHeight","onAppBarLayout","appBarMaxHeight","collapsibleToolbarHeight","onCollapsibleToolbarLayout","maxTranslateY","translateY","lastTranslateY","lastOffsetY","prevOffsetY","overlapped","vectorY","elevationStyle","animatedStyle","transform","boxShadow","elevation","shadowColor","shadowOffset","shadowRadius","shadowOpacity","indexRef","offsetsRef","onScrollViewChanged","nextIndex","prevIndex","duration","savedOffsetY","scrollHandler","onBeginDrag","onMomentumBegin","onScroll","event","offsetY","contentOffset","y","ty","maxTy","deltaY","dy","min","onEndDrag","onMomentumEnd","threshold","nextTranslateY","hasCollapsible","appBarStyle","paddingTop","top","floating","undefined","scrollContentInsets"],"sources":["useUnstableCollapsibleAppBar.ts"],"sourcesContent":["import { useCallback, useRef } from 'react';\nimport { Falsy, Platform, RegisteredStyle, ScrollViewProps, ViewProps, ViewStyle } from 'react-native';\nimport type { SharedValue } from 'react-native-reanimated';\nimport {\n useAnimatedScrollHandler,\n useAnimatedStyle,\n useDerivedValue,\n useSharedValue,\n withTiming,\n} from 'react-native-reanimated';\nimport { useSafeAreaInsets } from 'react-native-safe-area-context';\nimport useAppbarStyles from './useAppbarStyles';\nimport useElevationStyle from './useElevationStyle';\nimport useHeight from './useHeight';\n\ntype WebOnlyStyle = { boxShadow: any };\n\ntype ViewStyleProp = Array<ViewStyle | RegisteredStyle<ViewStyle> | WebOnlyStyle | Falsy>;\n\ntype OnScroll = ScrollViewProps['onScroll'];\n\ntype OnLayoutCallback = ViewProps['onLayout'];\n\nexport interface ContentInsets {\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n}\n\nexport interface Options {\n shouldTranslateYReset?: boolean;\n}\n\nexport interface CollapsibleAppBar {\n appBarStyle: ViewStyleProp;\n vectorY: SharedValue<number>;\n onAppBarLayout: OnLayoutCallback;\n onCollapsibleToolbarLayout: OnLayoutCallback;\n onScroll: OnScroll;\n onScrollViewChanged: (index: number) => void;\n scrollContentInsets: ContentInsets;\n}\n\nconst defaultOptions: Required<Options> = {\n shouldTranslateYReset: false,\n};\n\nconst ANIMATION_DURATION_MILLIS = 100;\n\nconst SUPPORTS_DRAG_DETECTION = Platform.OS !== 'web';\n\nfunction useLargerValueOfLastTwoValues(value: number) {\n const refLatestTwoValues = useRef([0, 0]);\n\n refLatestTwoValues.current.shift();\n refLatestTwoValues.current.push(value);\n\n return Math.max(...refLatestTwoValues.current);\n}\n\nexport default function useUnstableCollapsibleAppBar(userOptions: Options = defaultOptions): CollapsibleAppBar {\n const { shouldTranslateYReset }: Required<Options> = {\n ...defaultOptions,\n ...userOptions,\n };\n\n const styles = useAppbarStyles();\n\n const safeAreaInsets = useSafeAreaInsets();\n\n const [appBarHeight, onAppBarLayout] = useHeight();\n const appBarMaxHeight = useLargerValueOfLastTwoValues(appBarHeight);\n const [collapsibleToolbarHeight, onCollapsibleToolbarLayout] = useHeight();\n\n const maxTranslateY = useDerivedValue(() => -collapsibleToolbarHeight, [collapsibleToolbarHeight]);\n\n const translateY = useSharedValue<number>(0);\n const lastTranslateY = useSharedValue<number>(0);\n const lastOffsetY = useSharedValue<number>(0);\n const prevOffsetY = useSharedValue<number>(0);\n const overlapped = useSharedValue<boolean>(false);\n const vectorY = useSharedValue<number>(0);\n\n const elevationStyle = useElevationStyle(4);\n const animatedStyle = useAnimatedStyle(() => {\n const transform = [{ translateY: translateY.value }];\n\n if (Platform.OS === 'web') {\n return {\n transform,\n boxShadow: overlapped.value ? elevationStyle?.boxShadow : 0,\n };\n }\n if (Platform.OS === 'android') {\n return {\n transform,\n elevation: overlapped.value ? elevationStyle?.elevation : 0,\n };\n }\n if (Platform.OS === 'ios') {\n return {\n transform,\n shadowColor: elevationStyle?.shadowColor,\n shadowOffset: elevationStyle?.shadowOffset,\n shadowRadius: elevationStyle?.shadowRadius,\n shadowOpacity: overlapped.value ? elevationStyle?.shadowOpacity : 0,\n };\n }\n return {};\n }, [translateY, overlapped, elevationStyle]);\n\n const indexRef = useRef<number>(0);\n const offsetsRef = useRef<Array<number>>([]);\n\n const onScrollViewChanged = useCallback((nextIndex: number) => {\n const prevIndex = indexRef.current;\n if (prevIndex === nextIndex) {\n if (shouldTranslateYReset) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n\n vectorY.value = 0;\n offsetsRef.current = [];\n overlapped.value = false;\n }\n\n return;\n }\n\n offsetsRef.current[prevIndex] = lastOffsetY.value;\n\n const savedOffsetY = offsetsRef.current[nextIndex] ?? 0;\n lastOffsetY.value = savedOffsetY;\n\n indexRef.current = nextIndex;\n\n // Determine whether to overlap every time index is changed.\n overlapped.value = savedOffsetY > 0;\n\n // If next ScrollView's offset is too short, expand app bar.\n if (translateY.value < 0 && savedOffsetY < appBarHeight) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n\n vectorY.value = 0;\n }\n }, [appBarHeight]);\n\n const scrollHandler = useAnimatedScrollHandler({\n onBeginDrag: () => {\n lastTranslateY.value = translateY.value;\n },\n onMomentumBegin: () => {\n lastTranslateY.value = translateY.value;\n },\n onScroll: (event) => {\n const offsetY = event.contentOffset.y;\n\n const ty = translateY.value;\n const maxTy = maxTranslateY.value;\n\n const deltaY = offsetY - prevOffsetY.value;\n vectorY.value = (vectorY.value * deltaY >= 0 && offsetY > 0) ? vectorY.value + deltaY : deltaY;\n prevOffsetY.value = offsetY;\n\n if (SUPPORTS_DRAG_DETECTION) {\n const dy = offsetY - lastOffsetY.value;\n\n translateY.value = offsetY <= 0 ? 0 : Math.min(Math.max(lastTranslateY.value - dy, maxTy), 0);\n\n overlapped.value = offsetY + translateY.value > 0;\n } else {\n if (offsetY > -maxTy) {\n if (ty === 0) {\n translateY.value = withTiming(Math.min(Math.max(-offsetY, maxTy), 0), {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n } else {\n if (ty === maxTy) {\n translateY.value = withTiming(0, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n }\n }\n\n overlapped.value = offsetY > 0;\n\n lastOffsetY.value = offsetY;\n }\n },\n onEndDrag: (event) => {\n lastOffsetY.value = event.contentOffset.y;\n },\n onMomentumEnd: (event) => {\n const offsetY = event.contentOffset.y;\n\n lastOffsetY.value = offsetY;\n\n const ty = translateY.value;\n const maxTy = maxTranslateY.value;\n\n // If toolbar is already positioned on edge, do nothing.\n if (ty <= maxTy || ty >= 0) {\n return;\n }\n\n const threshold = maxTy * 0.5;\n\n const nextTranslateY = (ty > threshold || offsetY < appBarHeight) ? 0 : maxTy;\n\n overlapped.value = offsetY + nextTranslateY > 0;\n\n translateY.value = withTiming(nextTranslateY, {\n duration: ANIMATION_DURATION_MILLIS,\n });\n },\n });\n\n const hasCollapsible = collapsibleToolbarHeight > 0;\n\n const appBarStyle = [\n animatedStyle,\n { paddingTop: safeAreaInsets.top },\n hasCollapsible ? styles.floating : undefined,\n ];\n\n return {\n appBarStyle,\n vectorY,\n onAppBarLayout,\n onCollapsibleToolbarLayout,\n onScroll: scrollHandler,\n onScrollViewChanged,\n scrollContentInsets: { top: hasCollapsible ? appBarMaxHeight : 0 },\n };\n};\n"],"mappings":"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"}
@@ -12,7 +12,7 @@ export default function useAnimatedDisplayStyle(vectorY) {
12
12
  }, [threshold]);
13
13
  return useAnimatedStyle(() => ({
14
14
  display: display.value
15
- }), []);
15
+ }), [display]);
16
16
  }
17
17
  ;
18
18
  //# sourceMappingURL=useUnstableToggleDisplayStyle.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["useAnimatedReaction","useAnimatedStyle","useSharedValue","useAnimatedDisplayStyle","vectorY","threshold","defaultDisplay","display","value","vy"],"sources":["useUnstableToggleDisplayStyle.ts"],"sourcesContent":["import type { SharedValue } from 'react-native-reanimated';\nimport { useAnimatedReaction, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';\n\nexport default function useAnimatedDisplayStyle(\n vectorY: SharedValue<number>,\n threshold: number = 200,\n defaultDisplay: 'flex' | 'none' = 'flex',\n) {\n const display = useSharedValue(defaultDisplay);\n\n useAnimatedReaction(\n () => vectorY.value,\n (vy) => {\n if (vy >= threshold) {\n display.value = 'none';\n } else if (vy < threshold) {\n display.value = 'flex';\n }\n },\n [threshold],\n );\n\n return useAnimatedStyle(() => ({\n display: display.value,\n }), []);\n};\n"],"mappings":"AACA,SAASA,mBAAT,EAA8BC,gBAA9B,EAAgDC,cAAhD,QAAsE,yBAAtE;AAEA,eAAe,SAASC,uBAAT,CACXC,OADW,EAIb;EAAA,IAFEC,SAEF,uEAFsB,GAEtB;EAAA,IADEC,cACF,uEADoC,MACpC;EACE,MAAMC,OAAO,GAAGL,cAAc,CAACI,cAAD,CAA9B;EAEAN,mBAAmB,CACf,MAAMI,OAAO,CAACI,KADC,EAEdC,EAAD,IAAQ;IACJ,IAAIA,EAAE,IAAIJ,SAAV,EAAqB;MACjBE,OAAO,CAACC,KAAR,GAAgB,MAAhB;IACH,CAFD,MAEO,IAAIC,EAAE,GAAGJ,SAAT,EAAoB;MACvBE,OAAO,CAACC,KAAR,GAAgB,MAAhB;IACH;EACJ,CARc,EASf,CAACH,SAAD,CATe,CAAnB;EAYA,OAAOJ,gBAAgB,CAAC,OAAO;IAC3BM,OAAO,EAAEA,OAAO,CAACC;EADU,CAAP,CAAD,EAEnB,EAFmB,CAAvB;AAGH;AAAA"}
1
+ {"version":3,"names":["useAnimatedReaction","useAnimatedStyle","useSharedValue","useAnimatedDisplayStyle","vectorY","threshold","defaultDisplay","display","value","vy"],"sources":["useUnstableToggleDisplayStyle.ts"],"sourcesContent":["import type { SharedValue } from 'react-native-reanimated';\nimport { useAnimatedReaction, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';\n\nexport default function useAnimatedDisplayStyle(\n vectorY: SharedValue<number>,\n threshold: number = 200,\n defaultDisplay: 'flex' | 'none' = 'flex',\n) {\n const display = useSharedValue(defaultDisplay);\n\n useAnimatedReaction(\n () => vectorY.value,\n (vy) => {\n if (vy >= threshold) {\n display.value = 'none';\n } else if (vy < threshold) {\n display.value = 'flex';\n }\n },\n [threshold],\n );\n\n return useAnimatedStyle(() => ({\n display: display.value,\n }), [display]);\n};\n"],"mappings":"AACA,SAASA,mBAAT,EAA8BC,gBAA9B,EAAgDC,cAAhD,QAAsE,yBAAtE;AAEA,eAAe,SAASC,uBAAT,CACXC,OADW,EAIb;EAAA,IAFEC,SAEF,uEAFsB,GAEtB;EAAA,IADEC,cACF,uEADoC,MACpC;EACE,MAAMC,OAAO,GAAGL,cAAc,CAACI,cAAD,CAA9B;EAEAN,mBAAmB,CACf,MAAMI,OAAO,CAACI,KADC,EAEdC,EAAD,IAAQ;IACJ,IAAIA,EAAE,IAAIJ,SAAV,EAAqB;MACjBE,OAAO,CAACC,KAAR,GAAgB,MAAhB;IACH,CAFD,MAEO,IAAIC,EAAE,GAAGJ,SAAT,EAAoB;MACvBE,OAAO,CAACC,KAAR,GAAgB,MAAhB;IACH;EACJ,CARc,EASf,CAACH,SAAD,CATe,CAAnB;EAYA,OAAOJ,gBAAgB,CAAC,OAAO;IAC3BM,OAAO,EAAEA,OAAO,CAACC;EADU,CAAP,CAAD,EAEnB,CAACD,OAAD,CAFmB,CAAvB;AAGH;AAAA"}
@@ -1,11 +1,15 @@
1
1
  import React from 'react';
2
- import type { ComponentProps } from '@fountain-ui/core';
2
+ import type { ComponentProps, ExtendedStyle } from '@fountain-ui/core';
3
3
  export default interface BottomSheetProps extends ComponentProps<{
4
4
  /**
5
5
  * Opacity for BackdropComponent
6
6
  * @default 0.5
7
7
  */
8
8
  backdropOpacity?: number;
9
+ /**
10
+ * View style to be applied to the background component. (only native)
11
+ */
12
+ backgroundStyle?: ExtendedStyle | ExtendedStyle[];
9
13
  /**
10
14
  * Border radius for bottom sheet
11
15
  */
@@ -45,5 +49,9 @@ export default interface BottomSheetProps extends ComponentProps<{
45
49
  * @default []
46
50
  */
47
51
  snapPoints?: Array<number | string>;
52
+ /**
53
+ * View style to be applied to the content area.
54
+ */
55
+ style?: ExtendedStyle | ExtendedStyle[];
48
56
  }> {
49
57
  }
@@ -0,0 +1,21 @@
1
+ /// <reference types="react-native-reanimated" />
2
+ import type BottomSheetProps from './BottomSheetProps';
3
+ export default function useDynamicSnapPoints(snapPoints: BottomSheetProps['snapPoints']): {
4
+ animatedSnapPoints: Readonly<{
5
+ value: (string | number)[];
6
+ }>;
7
+ animatedHandleHeight: import("react-native-reanimated").SharedValue<number>;
8
+ animatedContentHeight: import("react-native-reanimated").SharedValue<number>;
9
+ handleContentLayout: ({ nativeEvent: { layout: { height }, }, }: {
10
+ nativeEvent: {
11
+ layout: {
12
+ height: number;
13
+ };
14
+ };
15
+ }) => void;
16
+ } | {
17
+ animatedHandleHeight: undefined;
18
+ animatedSnapPoints: (string | number)[] | undefined;
19
+ animatedContentHeight: undefined;
20
+ handleContentLayout: undefined;
21
+ };
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
2
  import type CarouselProps from './CarouselProps';
3
3
  import type { CarouselInstance } from './types';
4
- declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<Pick<CarouselProps<any>, "style" | "data" | "autoplay" | "autoplayInterval" | "createItemStyle" | "createScrollAnimation" | "disableSmartAutoplay" | "initialIndex" | "itemHeight" | "itemWidth" | "loop" | "onIndexChange" | "renderItem" | "scrollEnabled" | "windowSize"> & React.RefAttributes<CarouselInstance>>>;
4
+ declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<Pick<CarouselProps<any>, "style" | "data" | "autoplay" | "autoplayInterval" | "createItemStyle" | "createScrollAnimation" | "disableSmartAutoplay" | "initialIndex" | "itemHeight" | "itemWidth" | "loop" | "onIndexChange" | "renderItem" | "scrollEnabled" | "windowSize" | "needsOffscreenAlphaCompositingOnItem"> & React.RefAttributes<CarouselInstance>>>;
5
5
  export default _default;
@@ -71,5 +71,12 @@ export default interface CarouselProps<ItemT = any> extends ComponentProps<{
71
71
  * @default 5
72
72
  */
73
73
  windowSize?: number;
74
+ /**
75
+ * Whether item views need to be rendered offscreen and composited with an alpha
76
+ * in order to preserve 100% correct colors and blending behavior.
77
+ * Use this when items have opacity animations and multiple overlapping elements.
78
+ * @default false
79
+ */
80
+ needsOffscreenAlphaCompositingOnItem?: boolean;
74
81
  }> {
75
82
  }
@@ -9,6 +9,7 @@ export interface InternalContextValue<ItemT> {
9
9
  itemWidth: number;
10
10
  itemVisibilityStore: ItemVisibilityStore;
11
11
  loop: boolean;
12
+ needsOffscreenAlphaCompositingOnItem: boolean;
12
13
  }
13
14
  declare const InternalContext: import("react").Context<InternalContextValue<any>>;
14
15
  export default InternalContext;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fountain-ui/lab",
3
- "version": "3.0.0-alpha.2",
3
+ "version": "3.0.0-alpha.21",
4
4
  "private": false,
5
5
  "author": "Fountain-UI Team",
6
6
  "description": "Incubator for Fountain-UI React components.",
@@ -17,7 +17,7 @@
17
17
  "dependencies": {
18
18
  "@emotion/react": "^11.10.0",
19
19
  "@emotion/styled": "^11.10.0",
20
- "@fountain-ui/icons": "3.0.0-alpha.1",
20
+ "@fountain-ui/icons": "3.0.0-alpha.12",
21
21
  "@fountain-ui/utils": "^3.0.0-alpha.1",
22
22
  "react-native-calendars": "1.1267.0"
23
23
  },
@@ -29,7 +29,8 @@
29
29
  "react-dom": "^16.8.0 || ^17.0.0",
30
30
  "react-native": "^0.63.0",
31
31
  "react-native-gesture-handler": "^2.0.0",
32
- "react-native-pager-view": "^4.0.0"
32
+ "react-native-pager-view": "^4.0.0",
33
+ "react-native-safe-area-context": "^4.0.0"
33
34
  },
34
35
  "peerDependenciesMeta": {
35
36
  "@gorhom/bottom-sheet": {
@@ -70,5 +71,5 @@
70
71
  "publishConfig": {
71
72
  "access": "public"
72
73
  },
73
- "gitHead": "28005225fc7de910f1946bf35cab98be3f53094c"
74
+ "gitHead": "a14becb14e77ed3a206bd22a0e0c1a5026878e6f"
74
75
  }
@@ -18,7 +18,7 @@ export default function AnimatedY(props: AnimatedYProps) {
18
18
  const animatedY = useSharedValue(translateY);
19
19
  const animatedStyle = useAnimatedStyle(() => ({
20
20
  transform: [{ translateY: animatedY.value }],
21
- }), []);
21
+ }), [animatedY]);
22
22
 
23
23
  useEffect(() => {
24
24
  if (translateY >= 0) {
@@ -1,5 +1,6 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { Animated, LayoutChangeEvent, useWindowDimensions, ViewStyle } from 'react-native';
3
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
3
4
  import {
4
5
  BottomSheetBackdrop,
5
6
  BottomSheetBackdropProps,
@@ -7,16 +8,22 @@ import {
7
8
  BottomSheetModalProvider,
8
9
  BottomSheetView,
9
10
  } from '@gorhom/bottom-sheet';
10
- import { Column, ExtendedStyle, isNotAndroid12, useAnimatedValue } from '@fountain-ui/core';
11
+ import { Column, css, ExtendedStyle, isNotAndroid12, useAnimatedValue } from '@fountain-ui/core';
11
12
  import { useTheme } from '@fountain-ui/styles';
12
13
  import type BottomSheetProps from './BottomSheetProps';
13
14
  import TransparentBackdrop from './TransparentBackdrop';
15
+ import useDynamicSnapPoints from './useDynamicSnapPoints.native';
14
16
 
15
17
  const NoHandle = () => null;
16
18
 
19
+ const DEFAULT_PADDING_BOTTOM = 24;
20
+ const DEFAULT_PADDING_TOP = 22;
21
+ const TOP_ELEMENT_HIDDEN_OFFSET = 16;
22
+
17
23
  export default function BottomSheet(props: BottomSheetProps) {
18
24
  const {
19
25
  backdropOpacity = 0.5,
26
+ backgroundStyle: backgroundStyleProp,
20
27
  borderRadius: borderRadiusProp,
21
28
  children,
22
29
  enableDynamicSizing = true,
@@ -25,6 +32,7 @@ export default function BottomSheet(props: BottomSheetProps) {
25
32
  maxHeightNormalizedRatio = 0.8,
26
33
  onChange,
27
34
  snapPoints = [],
35
+ style: styleProp,
28
36
  } = props;
29
37
 
30
38
  const indexRef = useRef<number>(-1);
@@ -33,7 +41,8 @@ export default function BottomSheet(props: BottomSheetProps) {
33
41
  const { height: windowHeight } = useWindowDimensions();
34
42
  const [topElementHeight, setTopElementHeight] = useState(0);
35
43
 
36
- const maxDynamicContentSize = Math.round(windowHeight * maxHeightNormalizedRatio) - topElementHeight;
44
+ const topElementHeightWithoutOffset = Math.max(0, topElementHeight - TOP_ELEMENT_HIDDEN_OFFSET);
45
+ const maxDynamicContentSize = Math.round(windowHeight * maxHeightNormalizedRatio) - topElementHeightWithoutOffset;
37
46
 
38
47
  const handleTopElementLayout = (event: LayoutChangeEvent) => {
39
48
  const { height } = event.nativeEvent.layout;
@@ -70,20 +79,31 @@ export default function BottomSheet(props: BottomSheetProps) {
70
79
  const theme = useTheme();
71
80
 
72
81
  const borderRadius = borderRadiusProp ?? theme.shape.radius.xxl;
73
- const backgroundStyle = {
74
- backgroundColor: theme.palette.surface.base,
75
- borderTopLeftRadius: borderRadius,
76
- borderTopRightRadius: borderRadius,
77
- };
78
-
79
- const contentWrapperStyle: ViewStyle = {
80
- flex: 1,
81
- maxHeight: maxDynamicContentSize,
82
- minHeight: 300,
83
- overflow: 'hidden',
84
- paddingBottom: theme.spacing(6),
85
- paddingTop: theme.spacing(5.5),
86
- };
82
+ const backgroundStyle = css([
83
+ {
84
+ backgroundColor: theme.palette.surface.base,
85
+ borderTopLeftRadius: borderRadius,
86
+ borderTopRightRadius: borderRadius,
87
+ },
88
+ backgroundStyleProp,
89
+ ]);
90
+
91
+ const { bottom: bottomSafeInset } = useSafeAreaInsets();
92
+
93
+ const contentWrapperStyle: ViewStyle = css([
94
+ {
95
+ backgroundColor: theme.palette.surface.base,
96
+ borderTopLeftRadius: borderRadius,
97
+ borderTopRightRadius: borderRadius,
98
+ flexShrink: 1,
99
+ maxHeight: maxDynamicContentSize,
100
+ minHeight: 325,
101
+ overflow: 'hidden',
102
+ paddingBottom: DEFAULT_PADDING_BOTTOM + bottomSafeInset,
103
+ paddingTop: DEFAULT_PADDING_TOP,
104
+ },
105
+ styleProp,
106
+ ]);
87
107
 
88
108
  const isBackdropTransparent = backdropOpacity <= 0;
89
109
 
@@ -114,23 +134,33 @@ export default function BottomSheet(props: BottomSheetProps) {
114
134
  }).start();
115
135
  };
116
136
 
137
+ const {
138
+ animatedHandleHeight,
139
+ animatedSnapPoints,
140
+ animatedContentHeight,
141
+ handleContentLayout,
142
+ } = useDynamicSnapPoints(snapPoints);
143
+
117
144
  return (
118
145
  <BottomSheetModalProvider>
119
146
  <BottomSheetModal
120
147
  backdropComponent={isBackdropTransparent ? TransparentBackdrop : OpacityAwareBackdrop}
121
148
  // @ts-ignore
122
149
  backgroundStyle={backgroundStyle}
150
+ enableOverDrag={false}
123
151
  index={index}
124
152
  handleComponent={NoHandle}
125
153
  onChange={handleChange}
126
154
  onDismiss={handleDismiss}
127
155
  ref={bottomSheetRef}
128
- snapPoints={snapPoints}
129
156
  enablePanDownToClose={Boolean(onChange)}
130
157
  enableDynamicSizing={enableDynamicSizing}
131
158
  maxDynamicContentSize={maxDynamicContentSize}
132
159
  detached={Boolean(topElement)}
133
160
  onAnimate={topElement ? onAnimate : undefined}
161
+ snapPoints={animatedSnapPoints}
162
+ handleHeight={animatedHandleHeight}
163
+ contentHeight={animatedContentHeight}
134
164
  >
135
165
  {topElement ? (
136
166
  <Animated.View style={topElementAnimationStyle}>
@@ -143,7 +173,10 @@ export default function BottomSheet(props: BottomSheetProps) {
143
173
  </Animated.View>
144
174
  ) : null}
145
175
 
146
- <BottomSheetView style={contentWrapperStyle}>
176
+ <BottomSheetView
177
+ onLayout={handleContentLayout}
178
+ style={contentWrapperStyle}
179
+ >
147
180
  {children}
148
181
  </BottomSheetView>
149
182
  </BottomSheetModal>
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { ComponentProps } from '@fountain-ui/core';
2
+ import type { ComponentProps, ExtendedStyle } from '@fountain-ui/core';
3
3
 
4
4
  export default interface BottomSheetProps extends ComponentProps<{
5
5
  /**
@@ -8,6 +8,11 @@ export default interface BottomSheetProps extends ComponentProps<{
8
8
  */
9
9
  backdropOpacity?: number;
10
10
 
11
+ /**
12
+ * View style to be applied to the background component. (only native)
13
+ */
14
+ backgroundStyle?: ExtendedStyle | ExtendedStyle[];
15
+
11
16
  /**
12
17
  * Border radius for bottom sheet
13
18
  */
@@ -54,4 +59,9 @@ export default interface BottomSheetProps extends ComponentProps<{
54
59
  * @default []
55
60
  */
56
61
  snapPoints?: Array<number | string>;
62
+
63
+ /**
64
+ * View style to be applied to the content area.
65
+ */
66
+ style?: ExtendedStyle | ExtendedStyle[];
57
67
  }> {}
@@ -26,19 +26,20 @@ const useStyles: UseStyles<BottomSheetStyles> = function (): BottomSheetStyles {
26
26
  borderTopLeftRadius: theme.shape.radius.xxl,
27
27
  borderTopRightRadius: theme.shape.radius.xxl,
28
28
  flexGrow: 1,
29
- minHeight: 300,
29
+ minHeight: 325,
30
30
  overflow: 'hidden',
31
31
  paddingBottom: theme.spacing(6),
32
32
  paddingTop: theme.spacing(5.5),
33
33
  },
34
34
  topElementLocation: {
35
35
  position: 'absolute',
36
- bottom: 0,
37
36
  width: '100%',
38
37
  },
39
38
  };
40
39
  };
41
40
 
41
+ const TOP_ELEMENT_HIDDEN_OFFSET = 16;
42
+
42
43
  export default function BottomSheet(props: BottomSheetProps) {
43
44
  const {
44
45
  backdropOpacity,
@@ -50,6 +51,7 @@ export default function BottomSheet(props: BottomSheetProps) {
50
51
  maxHeightNormalizedRatio = 0.8,
51
52
  onChange,
52
53
  snapPoints = [],
54
+ style: styleProp,
53
55
  } = props;
54
56
 
55
57
  const styles = useStyles();
@@ -58,7 +60,8 @@ export default function BottomSheet(props: BottomSheetProps) {
58
60
 
59
61
  const [topElementHeight, setTopElementHeight] = useState(0);
60
62
 
61
- const maxDynamicContentSize = Math.round(windowHeight * maxHeightNormalizedRatio) - topElementHeight;
63
+ const topElementHeightWithoutOffset = Math.max(0, topElementHeight - TOP_ELEMENT_HIDDEN_OFFSET);
64
+ const maxDynamicContentSize = Math.round(windowHeight * maxHeightNormalizedRatio) - topElementHeightWithoutOffset;
62
65
 
63
66
  const handleTopElementLayout = (event: LayoutChangeEvent) => {
64
67
  const { height } = event.nativeEvent.layout;
@@ -71,6 +74,8 @@ export default function BottomSheet(props: BottomSheetProps) {
71
74
  }
72
75
  };
73
76
 
77
+ const filteredSnapPoints = snapPoints.filter(point => point !== 'CONTENT_HEIGHT');
78
+
74
79
  const {
75
80
  convertedSnapPoints,
76
81
  handleLayout,
@@ -78,18 +83,21 @@ export default function BottomSheet(props: BottomSheetProps) {
78
83
  } = useDynamicSnapPoints({
79
84
  enableDynamicSizing,
80
85
  maxDynamicContentSize,
81
- snapPoints,
86
+ snapPoints: filteredSnapPoints,
82
87
  });
83
88
 
84
- const translateY = highestSnapPoint - (convertedSnapPoints[index] ?? 0);
89
+ const translateY = convertedSnapPoints.length > 0
90
+ ? highestSnapPoint - (convertedSnapPoints[index] ?? 0)
91
+ : 0;
85
92
 
86
93
  const contentStyles = css([
87
94
  styles.paper,
88
95
  {
89
96
  ...(borderRadius ? { borderTopLeftRadius: borderRadius, borderTopRightRadius: borderRadius } : {}),
90
- ...(highestSnapPoint !== maxDynamicContentSize ? { height: highestSnapPoint } : {}),
97
+ ...(!enableDynamicSizing && highestSnapPoint !== maxDynamicContentSize ? { height: highestSnapPoint } : {}),
91
98
  maxHeight: maxDynamicContentSize,
92
99
  },
100
+ styleProp,
93
101
  ]);
94
102
 
95
103
  return (
@@ -103,7 +111,7 @@ export default function BottomSheet(props: BottomSheetProps) {
103
111
  {topElement ? (
104
112
  <Column
105
113
  onLayout={handleTopElementLayout}
106
- style={styles.topElementLocation}
114
+ style={[styles.topElementLocation, { top: -topElementHeight }]}
107
115
  >
108
116
  {topElement}
109
117
  </Column>
@@ -0,0 +1,15 @@
1
+ import { useBottomSheetDynamicSnapPoints } from '@gorhom/bottom-sheet';
2
+ import type BottomSheetProps from './BottomSheetProps';
3
+
4
+ export default function useDynamicSnapPoints(snapPoints: BottomSheetProps['snapPoints']) {
5
+ if (snapPoints?.includes('CONTENT_HEIGHT')) {
6
+ return useBottomSheetDynamicSnapPoints(snapPoints);
7
+ }
8
+
9
+ return {
10
+ animatedHandleHeight: undefined,
11
+ animatedSnapPoints: snapPoints,
12
+ animatedContentHeight: undefined,
13
+ handleContentLayout: undefined,
14
+ };
15
+ }
@@ -1,4 +1,4 @@
1
- import { useCallback, useMemo, useRef, useState } from 'react';
1
+ import { useCallback, useMemo, useState } from 'react';
2
2
  import { LayoutChangeEvent, useWindowDimensions } from 'react-native';
3
3
  import * as R from 'ramda';
4
4
 
@@ -41,8 +41,6 @@ export default function useDynamicSnapPoints(params: UseDynamicSnapPointsParams)
41
41
 
42
42
  const [contentHeight, setContentHeight] = useState<number>(INITIAL_CONTAINER_HEIGHT);
43
43
 
44
- const hasMeasureRef = useRef<boolean>(false);
45
-
46
44
  const convertedSnapPoints = useMemo(() => {
47
45
  if (contentHeight === INITIAL_CONTAINER_HEIGHT) {
48
46
  return [];
@@ -70,13 +68,8 @@ export default function useDynamicSnapPoints(params: UseDynamicSnapPointsParams)
70
68
  const highestSnapPoint = R.last(convertedSnapPoints) ?? maxDynamicContentSize;
71
69
 
72
70
  const handleLayout = useCallback((event: LayoutChangeEvent) => {
73
- if (hasMeasureRef.current) {
74
- return;
75
- }
76
-
77
- hasMeasureRef.current = true;
78
71
  const { height } = event.nativeEvent.layout;
79
- setContentHeight(height);
72
+ setContentHeight(prev => (Math.abs(prev - height) > 1 ? height : prev));
80
73
  }, []);
81
74
 
82
75
  return {
@@ -24,6 +24,7 @@ const Carousel = forwardRef<CarouselInstance, CarouselProps>(function Carousel(p
24
24
  itemHeight,
25
25
  itemWidth,
26
26
  loop = false,
27
+ needsOffscreenAlphaCompositingOnItem = false,
27
28
  onIndexChange,
28
29
  renderItem,
29
30
  scrollEnabled = true,
@@ -89,6 +90,7 @@ const Carousel = forwardRef<CarouselInstance, CarouselProps>(function Carousel(p
89
90
  itemWidth,
90
91
  itemVisibilityStore,
91
92
  loop,
93
+ needsOffscreenAlphaCompositingOnItem,
92
94
  }), [
93
95
  createItemStyle,
94
96
  data,
@@ -97,6 +99,7 @@ const Carousel = forwardRef<CarouselInstance, CarouselProps>(function Carousel(p
97
99
  itemWidth,
98
100
  itemVisibilityStore,
99
101
  loop,
102
+ needsOffscreenAlphaCompositingOnItem,
100
103
  ]);
101
104
 
102
105
  return (
@@ -93,4 +93,12 @@ export default interface CarouselProps<ItemT = any> extends ComponentProps<{
93
93
  * @default 5
94
94
  */
95
95
  windowSize?: number;
96
+
97
+ /**
98
+ * Whether item views need to be rendered offscreen and composited with an alpha
99
+ * in order to preserve 100% correct colors and blending behavior.
100
+ * Use this when items have opacity animations and multiple overlapping elements.
101
+ * @default false
102
+ */
103
+ needsOffscreenAlphaCompositingOnItem?: boolean;
96
104
  }> {}
@@ -10,6 +10,7 @@ export interface InternalContextValue<ItemT> {
10
10
  itemWidth: number;
11
11
  itemVisibilityStore: ItemVisibilityStore;
12
12
  loop: boolean;
13
+ needsOffscreenAlphaCompositingOnItem: boolean;
13
14
  }
14
15
 
15
16
  const mockItemVisibilityStore: ItemVisibilityStore = {
@@ -26,6 +27,7 @@ const initialValue: Readonly<InternalContextValue<any>> = {
26
27
  itemWidth: 0,
27
28
  itemVisibilityStore: mockItemVisibilityStore,
28
29
  loop: false,
30
+ needsOffscreenAlphaCompositingOnItem: false,
29
31
  };
30
32
 
31
33
  const InternalContext = createContext<InternalContextValue<any>>(initialValue);
@@ -24,6 +24,7 @@ export default function ItemView(props: ItemViewProps) {
24
24
  itemHeight,
25
25
  itemWidth,
26
26
  itemVisibilityStore,
27
+ needsOffscreenAlphaCompositingOnItem,
27
28
  } = useContext(InternalContext);
28
29
 
29
30
  const [visible, setVisible] = useState(false);
@@ -44,6 +45,7 @@ export default function ItemView(props: ItemViewProps) {
44
45
 
45
46
  return (
46
47
  <Animated.View
48
+ needsOffscreenAlphaCompositing={needsOffscreenAlphaCompositingOnItem}
47
49
  children={visible ? children(interpolation) : null}
48
50
  onLayout={onLayout}
49
51
  style={[
@@ -3,8 +3,9 @@ import * as R from 'ramda';
3
3
  import { NativeScrollEvent, NativeSyntheticEvent, View } from 'react-native';
4
4
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
5
5
  import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withDelay, withTiming } from 'react-native-reanimated';
6
- import { ChevronDown, ChevronUp } from '@fountain-ui/icons';
6
+ import { ChevronDown, ChevronUp } from '@fountain-ui/icons/src/v2Icons';
7
7
  import { StyleSheet } from '@fountain-ui/core';
8
+ import { baseColors, commonColors } from '@fountain-ui/styles';
8
9
  import FastScrollProps from './FastScrollProps';
9
10
  import { offsetToPercentage, percentageToOffset } from './util';
10
11
 
@@ -14,7 +15,7 @@ const styles = StyleSheet.create({
14
15
  indicator: {
15
16
  width: INDICATOR_WIDTH,
16
17
  height: 48,
17
- backgroundColor: '#767676',
18
+ backgroundColor: baseColors.gray['650'],
18
19
  flexDirection: 'column',
19
20
  alignItems: 'center',
20
21
  justifyContent: 'center',
@@ -54,7 +55,7 @@ const FastScroll = React.forwardRef((props: FastScrollProps, ref) => {
54
55
  const animatedStyle = useAnimatedStyle(() => ({
55
56
  transform: [{ translateY: indicatorOffset.value }],
56
57
  opacity: indicatorOpacity.value,
57
- }));
58
+ }), [indicatorOffset, indicatorOpacity]);
58
59
 
59
60
  const position = {
60
61
  ...absolutePosition,
@@ -157,16 +158,9 @@ const FastScroll = React.forwardRef((props: FastScrollProps, ref) => {
157
158
  animatedStyle,
158
159
  styles.indicator,
159
160
  ]}>
160
- <ChevronUp
161
- fill={'#ededed'}
162
- height={20}
163
- width={20}
164
- />
165
- <ChevronDown
166
- fill={'#ededed'}
167
- height={20}
168
- width={20}
169
- />
161
+ <ChevronUp fill={commonColors.static.strongInverse}/>
162
+
163
+ <ChevronDown fill={commonColors.static.strongInverse}/>
170
164
  </Animated.View>
171
165
  </GestureDetector>
172
166
  </View>