mirror of
https://github.com/element-plus/element-plus.git
synced 2025-04-12 16:40:36 +08:00
feat(components): segmented support vertical direction (#18653)
* feat(components): segmented support vertical direction * fix(components): improve * fix(components): empty commit * fix(components): update api to direction * chore(components): use n.m * fix(components): improve * fix(components): fix * fix(components): fix * Update docs/examples/segmented/custom-direction.vue Co-authored-by: btea <2356281422@qq.com> * Update docs/examples/segmented/custom-direction.vue Co-authored-by: btea <2356281422@qq.com> * fix(components): lint fix --------- Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
parent
dab6b73040
commit
6b1e951368
@ -17,6 +17,16 @@ segmented/basic
|
||||
|
||||
:::
|
||||
|
||||
## Direction Usage ^(2.8.7)
|
||||
|
||||
Set `vertical` to change direction.
|
||||
|
||||
:::demo
|
||||
|
||||
segmented/custom-direction
|
||||
|
||||
:::
|
||||
|
||||
## Disabled
|
||||
|
||||
Set `disabled` of segmented or option to `true` to disable it.
|
||||
|
96
docs/examples/segmented/custom-direction.vue
Normal file
96
docs/examples/segmented/custom-direction.vue
Normal file
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-segmented
|
||||
v-model="size"
|
||||
:options="sizeOptions"
|
||||
style="margin-bottom: 1rem"
|
||||
/>
|
||||
<br />
|
||||
<el-segmented
|
||||
v-model="direction"
|
||||
:options="directionOptions"
|
||||
style="margin-bottom: 1rem"
|
||||
/>
|
||||
<br />
|
||||
<el-segmented
|
||||
v-model="value"
|
||||
:options="options"
|
||||
:direction="direction"
|
||||
:size="size"
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<div
|
||||
:class="[
|
||||
'flex',
|
||||
'items-center',
|
||||
'gap-2',
|
||||
'flex-col',
|
||||
direction === 'horizontal' && 'p-2',
|
||||
]"
|
||||
>
|
||||
<el-icon size="20">
|
||||
<component :is="item.icon" />
|
||||
</el-icon>
|
||||
<div>{{ item.label }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-segmented>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
Apple,
|
||||
Cherry,
|
||||
Grape,
|
||||
Orange,
|
||||
Pear,
|
||||
Watermelon,
|
||||
} from '@element-plus/icons-vue'
|
||||
import type { SegmentedProps } from 'element-plus'
|
||||
|
||||
const value = ref('Apple')
|
||||
const direction = ref<SegmentedProps['direction']>('horizontal')
|
||||
const size = ref<SegmentedProps['size']>('default')
|
||||
|
||||
const directionOptions = [
|
||||
{ label: 'Horizontal', value: 'horizontal' },
|
||||
{ label: 'Vertical', value: 'vertical' },
|
||||
]
|
||||
|
||||
const sizeOptions = ['large', 'default', 'small']
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: 'Apple',
|
||||
value: 'Apple',
|
||||
icon: Apple,
|
||||
},
|
||||
{
|
||||
label: 'Cherry',
|
||||
value: 'Cherry',
|
||||
icon: Cherry,
|
||||
},
|
||||
{
|
||||
label: 'Grape',
|
||||
value: 'Grape',
|
||||
icon: Grape,
|
||||
},
|
||||
{
|
||||
label: 'Orange',
|
||||
value: 'Orange',
|
||||
icon: Orange,
|
||||
},
|
||||
{
|
||||
label: 'Pear',
|
||||
value: 'Pear',
|
||||
icon: Pear,
|
||||
},
|
||||
{
|
||||
label: 'Watermelon',
|
||||
value: 'Watermelon',
|
||||
icon: Watermelon,
|
||||
disabled: true,
|
||||
},
|
||||
]
|
||||
</script>
|
@ -13,6 +13,10 @@ import type { ExtractPropTypes } from 'vue'
|
||||
import type Segmented from './segmented.vue'
|
||||
|
||||
export const segmentedProps = buildProps({
|
||||
direction: {
|
||||
type: definePropType<'vertical' | 'horizontal'>(String),
|
||||
default: 'horizontal',
|
||||
},
|
||||
/**
|
||||
* @description options of segmented
|
||||
*/
|
||||
|
@ -8,7 +8,7 @@
|
||||
:aria-label="!isLabeledByFormItem ? ariaLabel || 'segmented' : undefined"
|
||||
:aria-labelledby="isLabeledByFormItem ? formItem!.labelId : undefined"
|
||||
>
|
||||
<div :class="ns.e('group')">
|
||||
<div :class="[ns.e('group'), ns.m(props.direction)]">
|
||||
<div :style="selectedStyle" :class="selectedCls" />
|
||||
<label
|
||||
v-for="(item, index) in options"
|
||||
@ -68,7 +68,9 @@ const activeElement = useActiveElement()
|
||||
const state = reactive({
|
||||
isInit: false,
|
||||
width: 0,
|
||||
height: 0,
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
focusVisible: false,
|
||||
})
|
||||
|
||||
@ -117,13 +119,19 @@ const updateSelect = () => {
|
||||
if (!selectedItem || !selectedItemInput) {
|
||||
state.width = 0
|
||||
state.translateX = 0
|
||||
state.translateY = 0
|
||||
state.focusVisible = false
|
||||
return
|
||||
}
|
||||
const rect = selectedItem.getBoundingClientRect()
|
||||
state.isInit = true
|
||||
state.width = rect.width
|
||||
state.translateX = selectedItem.offsetLeft
|
||||
if (props.direction === 'vertical') {
|
||||
state.height = rect.height
|
||||
state.translateY = selectedItem.offsetTop
|
||||
} else {
|
||||
state.width = rect.width
|
||||
state.translateX = selectedItem.offsetLeft
|
||||
}
|
||||
try {
|
||||
// This will failed in test
|
||||
state.focusVisible = selectedItemInput.matches(':focus-visible')
|
||||
@ -137,8 +145,12 @@ const segmentedCls = computed(() => [
|
||||
])
|
||||
|
||||
const selectedStyle = computed(() => ({
|
||||
width: `${state.width}px`,
|
||||
transform: `translateX(${state.translateX}px)`,
|
||||
width: props.direction === 'vertical' ? '100%' : `${state.width}px`,
|
||||
height: props.direction === 'vertical' ? `${state.height}px` : '100%',
|
||||
transform:
|
||||
props.direction === 'vertical'
|
||||
? `translateY(${state.translateY}px)`
|
||||
: `translateX(${state.translateX}px)`,
|
||||
display: state.isInit ? 'block' : 'none',
|
||||
}))
|
||||
|
||||
|
@ -35,6 +35,23 @@ $segmented-item-padding: map.merge(
|
||||
$segmented-item-padding
|
||||
);
|
||||
|
||||
$segmented-item-padding-vertical: () !default;
|
||||
$segmented-item-padding-vertical: map.merge(
|
||||
(
|
||||
'large': 11px 11px,
|
||||
'default':11px 11px,
|
||||
'small': 7px 7px,
|
||||
),
|
||||
$segmented-item-padding-vertical
|
||||
);
|
||||
|
||||
.#{$namespace}-segmented--vertical {
|
||||
flex-direction: column;
|
||||
.#{$namespace}-segmented__item {
|
||||
padding: map.get($segmented-item-padding-vertical, 'default');
|
||||
}
|
||||
}
|
||||
|
||||
@include b(segmented) {
|
||||
@include set-component-css-var('segmented', $segmented);
|
||||
}
|
||||
@ -151,6 +168,12 @@ $segmented-item-padding: map.merge(
|
||||
border-radius: calc(#{map.get($segmented-border-radius, $size)} - 2px);
|
||||
}
|
||||
|
||||
.#{$namespace}-segmented--vertical {
|
||||
@include e(item) {
|
||||
padding: map.get($segmented-item-padding-vertical, $size);
|
||||
}
|
||||
}
|
||||
|
||||
@include e(item) {
|
||||
border-radius: calc(#{map.get($segmented-border-radius, $size)} - 2px);
|
||||
padding: map.get($segmented-item-padding, $size);
|
||||
|
Loading…
x
Reference in New Issue
Block a user