Files
hospital-rescue-app-v2/uni_modules/tmx-ui/components/x-float-drawer/setup组合版本截止4.76 sdk不支持底层一些语法.uvue
T
2026-09-24 16:25:22 +08:00

919 lines
24 KiB
Plaintext

<!-- #ifdef MP-WEIXIN -->
<!-- @vue-docgen-ignore-next-line -->
<script module="xfs" lang="wxs" src="./xfs.wxs"></script>
<!-- #endif -->
<script lang="ts" setup>
import { getCurrentInstance, ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from "vue"
import { checkIsCssUnit, rpx2px, getUid } from "../../core/util/xCoreUtil.uts"
import { getDefaultColor, colorAddDeepen } from "../../core/util/xCoreColorUtil.uts"
import { xConfig } from "../../config/xConfig.uts"
type POSITION_TYPE = "bottom" | "top" | "left" | "right"
type POSITION_EVENT = {
x : number,
y : number,
classList : Array<string>
}
/**
* @name 浮动面板 FloatDrawer
* @description 提供流畅的拖拉阻尼效果,回弹丝滑。右滑关闭逻辑已经实现,但在app体验不好,主要是scoll与事件冲突需要官方优化.
* @page /pages/index/float-drawer
* @category 反馈组件
* @constant 平台兼容
* | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
| --- | --- | --- | --- | --- | --- | --- |
| ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.44+ | 1.1.9 |
*/
defineOptions({name:"xFloatDrawer"})
const proxy = getCurrentInstance()?.proxy??null;
defineSlots<{
default(props: { show: boolean, height: number }): any
}>()
const emits = defineEmits([
/**
* 关闭时执行
*/
'close',
/**
* 打开执行的事件
*/
'open',
/**
* 打开前执行
*/
'beforeOpen',
/**
* 关闭前执行
*/
'beforeClose',
/**
* 高度位置变化时触发这个差值.返回参数evt是个百分比,0%是最低下,100%代表是在最顶部.
*/
'heightChange',
/**
* 开始拖动
*/
'movestart',
/**
* 结束拖动
*/
'moveend',
/**
* 等同v-model:show
*/
'update:show'
])
export type xFloatDrawerPropsType = {
/**
* 显示可v-model:show双向绑定
* 默认是打开还是放置在底部。
*/
show: boolean,
/**
* 是否仅允许通过标题栏拖动。
*/
onlyHeader: boolean,
/**
* 动画时间
*/
duration: number,
/**
* 向上的圆角
* 空值时,取全局配置的圆角。
*/
round: string,
/**
* 百分比,数字字符或者带单位,
* 默认露出的内容高度
*/
size: string,
/**
* 弹层最大的高度值,默认为屏幕的可视高
* 提供值时不能为百分比,可以是px,rpx单位数字。如果你不带单位,默认转换为rpx单位。
*/
maxHeight: string,
/**
* 当拖动时,触发打开和关闭时的临界值,单位是px
* 如果没有达到此临界值时,将会回弹至原始位置。
*/
triggerDy: number,
/**
* 当拖动时,如果已经达到了关闭和打开时的临界值时
* 可以继续拖拉时缓动阻尼值
*/
threshold: number,
/**
* 内容层的背景色
*/
bgColor: string,
/**
* 暗黑的背景色,空时,取全局的sheetDarkColor
*/
darkBgColor: string,
/**
* 拖动标题栏的横线背景色
*/
actionColor: string,
/**
* 禁用内部的容器并采用view容器
*/
disabledScroll: boolean,
/**
* 没有禁用disabledScroll生效
* 容器内部使用的类型
* scroll :scroll-view
* list : list-view
*/
containerType: string,
/**
* 是否禁用用户滚动等来触发关闭或者打开。
*/
disabled: boolean,
/**
* 层级
*/
zIndex: number,
/**
* 控制内容的边跑,有时需要自定布局时非常有用.
* 请直接使用style css规则写margin,
*/
contentMargin: string
}
const props = withDefaults(defineProps<xFloatDrawerPropsType>(), {
show: false,
onlyHeader: false,
duration: 350,
round: "",
size: "15%",
maxHeight: "80%",
triggerDy: 180,
threshold: 0.045,
bgColor: "white",
darkBgColor: "",
actionColor: "#888888",
disabledScroll: false,
containerType: 'scroll',
disabled: false,
zIndex: 100,
contentMargin: "0 16px 16px 16px"
})
// 响应式数据
const _width = ref(0)
const _height = ref(0)
const elementWrap = ref<UniElement | null>(null)
//是否动画中
const actioning = ref(false)
const status = ref("")
const wrapId = ref("xFloatDrawerWrap" + getUid())
const _y = ref(0)
const _realY = ref(0)
const _realYDiff = ref(0)
const isHover = ref(false)
const disabledMove = ref(true)
const netId = ref('xFloatDrawerScrollIds-' + getUid())
const tid = ref(0)
const startMoveWEB = ref(false)
const first = ref(true)
const _test_x = ref(0)
const _test_y = ref(0)
const _scrollDetail_y = ref(0)
const moveDy = ref(0)
const endtid = ref(12)
const isClicking = ref(false)
const _heade_x = ref(0)
const _heade_y = ref(0)
const _scrollDetail_y_start = ref(0)
const disabledScolly = ref(false)
const isMoving = ref(false)
const touchmoevIsOver = ref(false)
const tid2 = ref(11)
const nowTouchType = ref('body')
const moveDir = ref("none")
const _reeal_x = ref(0)
const _reeal_y = ref(0)
const scrollTopDiff = ref(0)
// 计算属性
const _contentMargin = computed((): string => props.contentMargin)
const _show = computed((): boolean => props.show)
const _disabled = computed((): boolean => props.disabled)
const _onlyHeader = computed((): boolean => props.onlyHeader)
const _duration = computed((): number => props.duration)
const _round = computed((): string => {
let round = props.round;
if (round == "") {
round = xConfig.drawerRadius
}
let radius = checkIsCssUnit(round, 'rpx');
let _r = `${radius} ${radius} 0px 0px`
return _r
})
const _size = computed((): number => {
if (props.size == "") {
return _height.value * 0.8
}
if (props.size.lastIndexOf('rpx') > -1) {
let sz = rpx2px(parseFloat(props.size))
return _height.value - sz
}
if (props.size.lastIndexOf('px') > -1) {
let sz = parseFloat(props.size)
return _height.value - sz
}
if (props.size.lastIndexOf('%') > -1) {
let sz = parseFloat(props.size) / 100 * _height.value
return _height.value - sz
}
let sz = uni.rpx2px(parseFloat(props.size))
return _height.value - sz
})
const _maxHeight = computed((): number => {
if (props.size == "") {
return _height.value * 0.2
}
if (props.maxHeight.lastIndexOf('rpx') > -1) {
let sz = rpx2px(parseFloat(props.maxHeight))
return _height.value - sz
}
if (props.maxHeight.lastIndexOf('px') > -1) {
let sz = parseFloat(props.maxHeight)
return _height.value - sz
}
if (props.maxHeight.lastIndexOf('%') > -1) {
let sz = parseFloat(props.maxHeight) / 100 * _height.value
return _height.value - sz
}
let sz = rpx2px(parseFloat(props.maxHeight))
return _height.value - sz
})
const _bgColor = computed((): string => {
if (xConfig.dark == 'dark') {
if (props.darkBgColor != '') return getDefaultColor(props.darkBgColor)
return getDefaultColor(xConfig.sheetDarkColor)
}
return getDefaultColor(props.bgColor)
})
const _actionColor = computed((): string => getDefaultColor(props.actionColor))
const _animationFun = computed((): string => xConfig.animationFun)
// 方法
function onEnd() {
if (status.value == 'close') {
/**
* 关闭时执行
*/
emits('close')
/**
* 等同v-model:show
*/
emits('update:show', false)
emits('heightChange', 0)
} else {
/**
* 打开执行的事件
*/
emits('open')
emits('update:show', true)
emits('heightChange', 100)
}
actioning.value = false;
_realYDiff.value = 0
}
function setStyleAni() {
try {
let duration = _duration.value;
if (first.value == true) {
duration = 0
}
if (status.value == 'open') {
clearTimeout(tid.value)
tid.value = setTimeout(function () {
elementWrap.value!.style.setProperty("transition-duration", duration.toString() + 'ms')
elementWrap.value!.style.setProperty('transform', `translate(0%,${_maxHeight.value}px)`)
}, 50);
} else if (status.value == 'close') {
clearTimeout(tid.value)
tid.value = setTimeout(function () {
elementWrap.value!.style.setProperty("transition-duration", duration.toString() + 'ms')
elementWrap.value!.style.setProperty('transform', `translate(0%,${_size.value}px)`)
}, 50);
}
} catch (e) {
//TODO handle the exception
}
first.value = false;
}
function closeAlert() {
if (actioning.value || status.value == 'close') return
actioning.value = true;
status.value = 'close'
/**
* 关闭前执行
*/
emits('beforeClose')
emits('heightChange', 0)
// #ifndef MP-WEIXIN
setStyleAni();
// #endif
}
function showAlert() {
if (actioning.value) return;
if (status.value == 'open') return;
actioning.value = true;
status.value = 'open'
/**
* 打开前执行
*/
emits('beforeOpen')
emits('heightChange', 100)
// #ifndef MP-WEIXIN
setStyleAni();
// #endif
}
function openDrawer() {
showAlert();
}
function headerClickClose() {
if (_disabled.value) return;
if (moveDy.value != 0) return;
actioning.value = false;
if (status.value == 'open') {
closeAlert();
} else {
showAlert();
}
onEnd()
}
// #ifdef MP-WEIXIN
function setOpts(opts: any) {
status.value = opts.status;
}
function callEmits(args: any) {
if(!args.name) return;
if(args.args!=null&&args.args!=undefined){
emits(args.name as any, args.args)
}else{
emits(args.name as any)
}
}
function setDisabledScolly(opts: any) {
disabledScolly.value = opts.disabledScolly
isMoving.value = opts.isMoving
}
// #endif
function scrollTopChange() {
// 空实现
}
function scollChange(evt: UniScrollEvent) {
const stop = Math.max(0,Math.floor(evt.detail.scrollTop));
scrollTopDiff.value = stop
// #ifdef APP-ANDROID||WEB||APP-HARMONY
if(!isMoving.value){
_scrollDetail_y.value = stop
}
disabledScolly.value = _scrollDetail_y.value<=0;
// #endif
// #ifdef APP-IOS
_scrollDetail_y.value = stop
//当手指已经离开了屏幕,再置顶不需要再禁用滚动了。如果手指一直在划动则需要禁用。
if(!touchmoevIsOver.value){
disabledScolly.value = _scrollDetail_y.value<=0;
}else{
disabledScolly.value = false
}
// #endif
}
function eventTransform_start(evt: POSITION_EVENT) {
try {
let ele = elementWrap.value!;
if (status.value == 'open') {
_y.value = evt.y - (_maxHeight.value)
} else if (status.value == 'close') {
_y.value = evt.y - (_size.value)
}
_realY.value = evt.y
ele.style.setProperty("transition-duration", '0ms')
} catch (e) {
//TODO handle the exception
}
}
function eventTransform_move(evt: POSITION_EVENT) {
try {
if (!disabledMove.value) return;
let ele = elementWrap.value! as UniElement
if(moveDir.value == 'v'||status.value=='close'){
let movey = evt.y - _y.value - (nowTouchType.value == 'header'?0:_scrollDetail_y_start.value )
if (movey <= _maxHeight.value) {
movey = _maxHeight.value - (_maxHeight.value - movey) * props.threshold
} else if (movey >= _size.value) {
movey = _size.value + (movey - _size.value) * props.threshold
}
ele.style.setProperty("transform", `translate(0%, ${movey.toString()}px)`)
_realYDiff.value = evt.y - _realY.value
let ratioValue = (movey - _size.value) / (_maxHeight.value - _size.value) * 100;
emits('heightChange',ratioValue )
}else if(moveDir.value == 'h'&&status.value=='open'){
disabledScolly.value = true;
let traslateX = evt.x - _test_x.value
traslateX = Math.max(0,Math.min(traslateX,_width.value))
ele.style.setProperty("transform", `translate(${traslateX.toString()}px,${_maxHeight.value}px)`)
let ratioValue = (1-traslateX / _width.value) * 100
emits('heightChange',ratioValue )
}
} catch (e) {
console.error("floatDrawer出现意外错误:",e,"不用担心,这是兼容性错误,不会影响使用!!仅供参考.")
}
}
function eventTransform_end(evt: POSITION_EVENT) {
const oldStatus = status.value
try {
if (!disabledMove.value) return;
isHover.value = false;
let ele = elementWrap.value! as UniElement
ele.style.setProperty("transition-duration", _duration.value.toString() + 'ms');
if(moveDir.value == 'v'||status.value=='close'){
if (_realYDiff.value >= props.triggerDy) {
ele.style.setProperty("transform", `translate(0%, ${_size.value.toString()}px)`);
status.value = 'close';
emits('beforeClose');
emits('heightChange', 0);
} else if (_realYDiff.value < (props.triggerDy * -1)) {
ele.style.setProperty("transform", `translate(0%, ${_maxHeight.value.toString()}px)`);
status.value = 'open';
emits('heightChange', 100);
} else {
if (status.value === 'open') {
ele.style.setProperty("transform", `translate(0%, ${_maxHeight.value.toString()}px)`);
emits('heightChange', 100);
} else {
ele.style.setProperty("transform", `translate(0%, ${_size.value.toString()}px)`);
emits('heightChange', 0);
}
}
}else if(moveDir.value == 'h'&&status.value=='open'){
let traslateX = evt.x - _test_x.value
traslateX = Math.max(0,Math.min(traslateX,_width.value))
if(traslateX>=50){
status.value = 'close';
emits('heightChange',0 )
ele.style.setProperty("transform", `translate(0px,${_size.value}px)`)
}else{
status.value = 'open';
emits('heightChange',100 )
ele.style.setProperty("transform", `translate(0px,${_maxHeight.value}px)`)
disabledScolly.value = true;
}
}
} catch (e) {
// 处理异常
console.error(e)
}
if(oldStatus != status.value){
onEnd()
}
}
function mStart(evt: UniTouchEvent, type: string) {
if (type == 'header'){
isHover.value = true;
scrollTopDiff.value = -1
// 这里的意思,是让这个值引用界面的变化,这样可以避免可能的界面不渲染。
nextTick((()=>{
scrollTopDiff.value = 0
}))
}
nextTick(()=>{
emits('movestart');
nowTouchType.value = type
touchmoevIsOver.value = true;
if (_disabled.value) return;
if (_onlyHeader.value && type == 'body') return;
moveDy.value = 0;
_test_x.value = evt.changedTouches[0].clientX;
_reeal_x.value = evt.changedTouches[0].clientX
_reeal_y.value = evt.changedTouches[0].clientY
_scrollDetail_y_start.value = _scrollDetail_y.value; // 记录内部滚动的起始位置
disabledScolly.value = false
isMoving.value = false
// 按头拖时,不要记录起始的位置,否则body与头会出现heady的位移。
if (type == 'header'){
disabledScolly.value = true
}else{
_test_y.value = evt.changedTouches[0].clientY;
}
eventTransform_start({
x: evt.changedTouches[0].clientX,
y: evt.changedTouches[0].clientY,
classList: [] as string[],
} as POSITION_EVENT);
})
}
function mMove(evt: UniTouchEvent, type: string) {
if (_disabled.value) return;
if (_onlyHeader.value && nowTouchType.value == 'body') return;
const currentY = evt.changedTouches[0].clientY;
const currentX = evt.changedTouches[0].clientX;
const dy = currentY - _test_y.value;
const dx_real = currentX - _reeal_x.value
const dy_real = currentY - _reeal_y.value
moveDir.value = 'v'
if (_scrollDetail_y.value>0&& nowTouchType.value == 'body'&&moveDir.value=='v') return;
// #ifdef WEB
evt.preventDefault();
// #endif
if(nowTouchType.value == 'body'){
if(dy<0){
disabledScolly.value = false;
isMoving.value = false;
}else{
_scrollDetail_y.value = 0
}
}
let scrollDetail_y_start = nowTouchType.value == 'header'?0:_scrollDetail_y_start.value
if (scrollDetail_y_start > 0 && dy < 0) {
// 如果内部可以向上滚动,并且拖动是向上的
// 计算需要滚动的内部距离
const internalScrollDelta = -dy;
if (_scrollDetail_y.value - internalScrollDelta >= 0) {
// 内部可以滚动,更新内部滚动位置
_scrollDetail_y.value -= internalScrollDelta;
} else {
// 内部已经滚动到顶部,开始拖动整个弹层
const excess = internalScrollDelta - scrollDetail_y_start;
isMoving.value = true;
eventTransform_move({
x: evt.changedTouches[0].clientX,
y: evt.changedTouches[0].clientY - excess,
classList: [] as string[],
} as POSITION_EVENT);
}
} else {
isMoving.value = true;
// 其他情况,允许拖动整个弹层
eventTransform_move({
x: evt.changedTouches[0].clientX,
y: evt.changedTouches[0].clientY,
classList: [] as string[],
} as POSITION_EVENT);
}
}
function mEnd(evt: UniTouchEvent, type: string) {
emits('moveend');
isMoving.value = false;
touchmoevIsOver.value = false;
if (_disabled.value){
return;
}
if (nowTouchType.value == 'header'||_scrollDetail_y.value<0){
disabledScolly.value = false
}
let dy = evt.changedTouches[0].clientY - _test_y.value;
let dx = evt.changedTouches[0].clientX - _test_x.value;
if (dy == dx) return;
moveDy.value = dy;
eventTransform_end({
x: evt.changedTouches[0].clientX,
y: evt.changedTouches[0].clientY,
classList: [] as string[],
});
disabledScolly.value = false;
moveDir.value = 'none'
}
// #ifdef WEB
function mmStart(evt: UniMouseEvent, type: string) {
// @ts-ignore
window.FloatDrawerId = wrapId.value
emits('movestart')
_heade_x.value = evt.clientX
_heade_y.value = evt.clientY
_test_y.value = evt.clientY;
_test_x.value = evt.clientX;
if (_disabled.value) return;
if (type == 'header'){
isHover.value = true;
}
if (_onlyHeader.value && type == 'body') return
startMoveWEB.value = true;
eventTransform_start({
x: evt.clientX,
y: evt.clientY,
classList: [] as string[],
} as POSITION_EVENT)
}
function mmMove(evt: UniMouseEvent, type: string) {
// @ts-ignore
if(window.FloatDrawerId!=wrapId.value) return
if (_onlyHeader.value && type == 'body') return
if (!startMoveWEB.value) return;
const currentY = evt.clientY;
const currentX = evt.clientX;
const dy = currentY - _test_y.value;
const dx = currentX - _test_x.value
if(moveDir.value=='none'&&(Math.abs(dx) - Math.abs(dy))>0){
moveDir.value = 'h'
}else if(moveDir.value=='none'&&(Math.abs(dx) - Math.abs(dy))<=0){
moveDir.value = 'v'
}
eventTransform_move({
x: evt.clientX,
y: evt.clientY,
classList: [] as string[],
} as POSITION_EVENT)
}
function mmEnd(evt: UniMouseEvent, type: string) {
emits('moveend')
let diffx = evt.clientX - _heade_x.value
let diffy = evt.clientY - _heade_y.value
// @ts-ignore
window.FloatDrawerId = ''
if (diffx == diffy) return;
if (_disabled.value) return;
startMoveWEB.value = false;
eventTransform_end({
x: evt.clientX,
y: evt.clientY,
classList: [] as string[],
})
moveDir.value = 'none'
}
// #endif
// 监听器
watch((): boolean => props.show, (newval: boolean) => {
if (newval && status.value == 'close') {
actioning.value = false;
showAlert()
onEnd()
} else if(!newval && status.value == 'open') {
actioning.value = false;
closeAlert()
onEnd()
}
})
// 生命周期
onMounted(() => {
let yachi = 0
// #ifdef APP
yachi = 250
// #endif
tid.value = setTimeout(function () {
let sys = uni.getWindowInfo()
// #ifndef APP
_width.value = sys.windowWidth
_height.value = sys.windowHeight;
// #endif
// #ifdef APP
_width.value = sys.windowWidth
_height.value = sys.windowHeight + 44;
// #endif
if (_show.value) {
showAlert();
actioning.value = false;
status.value = 'open'
} else {
closeAlert()
actioning.value = false;
status.value = 'close'
}
}, yachi);
})
onBeforeUnmount(() => {
clearTimeout(tid.value)
clearTimeout(tid2.value)
})
defineExpose({
/** 打开 **/
open: () => showAlert(),
/** 关闭 **/
close: () => closeAlert()
})
</script>
<template>
<!-- @transitionend="onEnd" -->
<view @click.stop=""
ref="elementWrap"
class="xFloatDrawerWrapContent" :id="wrapId" :style="{
width:'100%',
height:_height+'px',
borderRadius:_round,
backgroundColor:_bgColor,
'transition-timing-function':_animationFun,
zIndex:props.zIndex
}"
<!-- #ifdef MP-WEIXIN -->
@touchstart="xfs.mStart"
@touchend="xfs.mEnd"
@touchmove="xfs.mMove"
:change:prop="xfs.propObserver"
:prop="status"
:data-opts="{
maxHeight:_maxHeight,
size:_size,height:_height,
status:status,
threshold:props.threshold,
duration:_duration,
triggerDy:props.triggerDy,
_scrollDetail_y:_scrollDetail_y
}"
<!-- #endif -->
>
<view
<!-- #ifdef APP||H5 -->
@touchstart="mStart($event as TouchEvent,'header')"
@touchend="mEnd($event as TouchEvent,'header')"
@touchmove="mMove($event as TouchEvent,'header')"
<!-- #endif -->
<!-- #ifdef WEB -->
@mousedown="mmStart($event as MouseEvent,'header')"
@mousemove="mmMove($event as MouseEvent,'header')"
@mouseup="mmEnd($event as MouseEvent,'header')"
@mouseleave="mmEnd"
<!-- #endif -->
class="xFloatDrawerBar"
>
<view @click="headerClickClose" style="height:100%" class="xFloatDrawerBarSop">
<view class="xFloatDrawerBarLine" :style="{'background-color':_actionColor,opacity: isHover?1:0.5}">
</view>
</view>
</view>
<view class="xFLoatViewWrap"
style="flex:1"
<!-- #ifdef APP||H5 -->
@touchstart.stop="mStart($event as TouchEvent,'body')"
@touchend.stop="mEnd($event as TouchEvent,'body')"
@touchmove.stop="mMove($event as TouchEvent,'body')"
<!-- #endif -->
<!-- #ifdef WEB -->
@mousedown="mmStart($event as MouseEvent,'body')"
@mousemove="mmMove($event as MouseEvent,'body')"
@mouseup="mmEnd($event as MouseEvent,'body')"
@mouseleave="mmEnd"
@mousewheel="disabledScolly = false"
<!-- #endif -->
>
<scroll-view
:scroll-top="scrollTopDiff"
v-if="!props.disabledScroll&&props.containerType=='scroll'"
:direction="status=='close'||disabledScolly?'none':'vertical'"
:scroll-y="status=='close'||disabledScolly?false:true"
@scroll="scollChange"
@scrolltoupper="scrollTopChange" :style="{flex:'1',margin:_contentMargin,height:'100px'}"
:bounces="false">
<!--
@slot 默认插槽
@prop {Boolean} show - 当前是否已显示
@prop {Number} height - 容器的高度
-->
<slot name="default" :show="_show" :height="_maxHeight"></slot>
<view :style="{height:_maxHeight+'px'}"></view>
</scroll-view>
<list-view v-else-if="!props.disabledScroll&&props.containerType=='list'"
:scroll-top="scrollTopDiff"
:scroll-y="status=='close'||disabledScolly?'none':'vertical'"
:direction="status=='close'||disabledScolly?'none':'vertical'" @scroll="scollChange"
@scrolltoupper="scrollTopChange" :style="{flex:'1',margin:_contentMargin}" :bounces="false">
<!--
@slot 默认插槽
@prop {Boolean} show - 当前是否已显示
@prop {Number} height - 容器的高度
-->
<slot name="default" :show="_show" :height="_maxHeight"></slot>
<list-item>
<view :style="{height:_maxHeight+'px'}"></view>
</list-item>
</list-view>
<view v-else :style="{flex:'1',margin:_contentMargin}">
<!--
@slot 默认插槽
@prop {Boolean} show - 当前是否已显示
@prop {Number} height - 容器的高度
-->
<slot name="default" :show="_show" :height="_maxHeight"></slot>
</view>
</view>
</view>
</template>
<style>
.xFloatDrawerBarSop {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.xFloatDrawerBar {
height: 44px;
/* #ifdef WEB */
cursor: grab;
/* #endif */
}
/* #ifdef WEB */
.xFloatDrawerBar:active {
cursor: grabbing;
}
/* #endif */
.xFloatDrawerBarLine {
width: 60px;
height: 4px;
border-radius: 8px;
}
.xFloatDrawerWrapContent {
display: flex;
flex-direction: column;
/* #ifndef APP-HARMONY */
transition-duration: 250ms;
/* #endif */
/* #ifdef APP-HARMONY */
transition-duration: 0ms;
/* #endif */
/* transition-timing-function: cubic-bezier(.18,.89,.32,1); */
transition-property: transform;
display: flex;
flex-direction: column;
transform: translate(0%, 100%);
position: fixed;
/* z-index: 100; */
left: 0px;
bottom: 0px;
}
</style>