feat: add elevation prop for Android and Web (#355)
* feat(android): add elevation prop * feat(web): add elevation prop support
This commit is contained in:
parent
dee02e15ea
commit
917775ee07
@ -222,6 +222,10 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
||||
viewController.grabberOptions = options
|
||||
}
|
||||
|
||||
fun setSheetElevation(elevation: Float) {
|
||||
viewController.sheetElevation = elevation
|
||||
}
|
||||
|
||||
fun setDetents(newDetents: MutableList<Double>) {
|
||||
viewController.detents = newDetents
|
||||
}
|
||||
|
||||
@ -178,6 +178,12 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
||||
if (isPresented) sheetView?.setupBackground()
|
||||
}
|
||||
|
||||
override var sheetElevation: Float = -1f
|
||||
set(value) {
|
||||
field = value
|
||||
if (isPresented) sheetView?.setupElevation()
|
||||
}
|
||||
|
||||
var dismissible: Boolean = true
|
||||
set(value) {
|
||||
field = value
|
||||
@ -647,6 +653,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
||||
setupDimmedBackground(currentDetentIndex)
|
||||
setupKeyboardObserver()
|
||||
sheet.setupBackground()
|
||||
sheet.setupElevation()
|
||||
sheet.setupGrabber()
|
||||
|
||||
if (shouldAnimatePresent) {
|
||||
|
||||
@ -198,6 +198,11 @@ class TrueSheetViewManager :
|
||||
// iOS-specific prop - no-op on Android
|
||||
}
|
||||
|
||||
@ReactProp(name = "elevation", defaultDouble = -1.0)
|
||||
override fun setElevation(view: TrueSheetView, elevation: Double) {
|
||||
view.setSheetElevation(elevation.toFloat())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REACT_CLASS = "TrueSheetView"
|
||||
const val TAG_NAME = "TrueSheet"
|
||||
|
||||
@ -18,6 +18,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
interface TrueSheetBottomSheetViewDelegate {
|
||||
val isTopmostSheet: Boolean
|
||||
val sheetCornerRadius: Float
|
||||
val sheetElevation: Float
|
||||
val sheetBackgroundColor: Int?
|
||||
val grabber: Boolean
|
||||
val grabberOptions: GrabberOptions?
|
||||
@ -37,6 +38,7 @@ class TrueSheetBottomSheetView(private val reactContext: ThemedReactContext) : F
|
||||
private const val GRABBER_TAG = "TrueSheetGrabber"
|
||||
private const val DEFAULT_CORNER_RADIUS = 16f // dp
|
||||
private const val DEFAULT_MAX_WIDTH = 640 // dp
|
||||
private const val DEFAULT_ELEVATION = 4f // dp
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@ -138,6 +140,12 @@ class TrueSheetBottomSheetView(private val reactContext: ThemedReactContext) : F
|
||||
}
|
||||
}
|
||||
|
||||
fun setupElevation() {
|
||||
val value = delegate?.sheetElevation ?: DEFAULT_ELEVATION
|
||||
val effectiveElevation = if (value < 0) DEFAULT_ELEVATION else value
|
||||
elevation = effectiveElevation.dpToPx()
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// MARK: - Grabber
|
||||
// =============================================================================
|
||||
|
||||
@ -66,9 +66,17 @@ The sheet corner radius.
|
||||
| `number` | _system default_ | ✅ | ✅ | ✅ |
|
||||
|
||||
:::info
|
||||
When not provided, iOS uses the device's native corner radius automatically, while Android defaults to `28` (following Material Design 3 guidelines).
|
||||
When not provided, iOS uses the device's native corner radius automatically, while Android defaults to `16` (following Material Design 3 guidelines).
|
||||
:::
|
||||
|
||||
## `elevation`
|
||||
|
||||
The elevation (shadow depth) of the sheet.
|
||||
|
||||
| Type | Default | 🍎 | 🤖 | 🌐 |
|
||||
| - | - | - | - | - |
|
||||
| `number` | `4` | | ✅ | ✅ |
|
||||
|
||||
## `maxHeight`
|
||||
|
||||
Overrides `"large"` or `"100%"` height.
|
||||
|
||||
@ -399,6 +399,15 @@ export interface TrueSheetProps extends ViewProps {
|
||||
*/
|
||||
insetAdjustment?: InsetAdjustment;
|
||||
|
||||
/**
|
||||
* The elevation (shadow depth) of the sheet.
|
||||
*
|
||||
* @platform android
|
||||
* @platform web
|
||||
* @default 4
|
||||
*/
|
||||
elevation?: number;
|
||||
|
||||
/**
|
||||
* A component that is fixed at the top of the Sheet content.
|
||||
* Useful for search bars, titles, or other header content.
|
||||
|
||||
@ -48,11 +48,30 @@ import type {
|
||||
} from './TrueSheet.types';
|
||||
|
||||
const DEFAULT_CORNER_RADIUS = 16;
|
||||
const DEFAULT_ELEVATION = 4;
|
||||
|
||||
const DEFAULT_GRABBER_COLOR = 'rgba(0, 0, 0, 0.3)';
|
||||
const DEFAULT_GRABBER_WIDTH = 32;
|
||||
const DEFAULT_GRABBER_HEIGHT = 4;
|
||||
|
||||
/**
|
||||
* Converts elevation to CSS box-shadow based on Material Design 3 elevation system.
|
||||
* Uses a combination of ambient and key shadows for realistic depth.
|
||||
*/
|
||||
const getElevationShadow = (elevation: number): string => {
|
||||
if (elevation <= 0) return 'none';
|
||||
|
||||
const ambientY = elevation * 0.5;
|
||||
const ambientBlur = elevation * 1.5;
|
||||
const ambientOpacity = 0.08 + elevation * 0.01;
|
||||
|
||||
const keyY = elevation;
|
||||
const keyBlur = elevation * 2;
|
||||
const keyOpacity = 0.12 + elevation * 0.02;
|
||||
|
||||
return `0px ${ambientY}px ${ambientBlur}px rgba(0, 0, 0, ${ambientOpacity}), 0px ${keyY}px ${keyBlur}px rgba(0, 0, 0, ${keyOpacity})`;
|
||||
};
|
||||
|
||||
const renderSlot = (slot: TrueSheetProps['header'] | TrueSheetProps['footer']) => {
|
||||
if (!slot) return null;
|
||||
if (isValidElement(slot)) return slot;
|
||||
@ -72,6 +91,7 @@ export const TrueSheet = forwardRef<TrueSheetRef, TrueSheetProps>((props, ref) =
|
||||
initialDetentIndex = -1,
|
||||
backgroundColor = '#ffffff',
|
||||
cornerRadius = DEFAULT_CORNER_RADIUS,
|
||||
elevation = DEFAULT_ELEVATION,
|
||||
grabber = true,
|
||||
grabberOptions,
|
||||
maxHeight,
|
||||
@ -425,7 +445,12 @@ export const TrueSheet = forwardRef<TrueSheetRef, TrueSheetProps>((props, ref) =
|
||||
const sharedProps = {
|
||||
style: [
|
||||
styles.root,
|
||||
{ backgroundColor, borderTopLeftRadius: cornerRadius, borderTopRightRadius: cornerRadius },
|
||||
{
|
||||
backgroundColor,
|
||||
borderTopLeftRadius: cornerRadius,
|
||||
borderTopRightRadius: cornerRadius,
|
||||
boxShadow: getElevationShadow(elevation),
|
||||
},
|
||||
],
|
||||
index: snapIndex,
|
||||
enablePanDownToClose: dismissible,
|
||||
@ -469,7 +494,6 @@ export const TrueSheet = forwardRef<TrueSheetRef, TrueSheetProps>((props, ref) =
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
overflow: 'hidden',
|
||||
boxShadow: '0px -2px 16px 0px rgba(9, 10, 9, 0.08)',
|
||||
},
|
||||
handle: {
|
||||
position: 'absolute',
|
||||
|
||||
@ -41,6 +41,7 @@ export interface NativeProps extends ViewProps {
|
||||
// Number properties - use 0 as default to avoid nil insertion
|
||||
maxHeight?: WithDefault<Double, 0>;
|
||||
cornerRadius?: WithDefault<Double, -1>;
|
||||
elevation?: WithDefault<Double, -1>;
|
||||
|
||||
// Color properties
|
||||
backgroundColor?: ColorValue;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user