mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-04-12 14:40:47 +08:00
feat: add n-split
component (#5290)
* feat: add `n-split` component * feat: add disabled * feat: add event * fix: rename * feat: add theme color * feat: support slot * feat: add demo * fix: panel height for demo --------- Co-authored-by: 07akioni <07akioni2@gmail.com>
This commit is contained in:
parent
b1acfe9d8a
commit
320bd7937a
@ -36,6 +36,8 @@
|
||||
- `n-equation` export the `EquationProps` type.
|
||||
- `n-popselect` adds `header` slot.
|
||||
- `n-tree-select` adds `watch-props` prop.
|
||||
- Adds `n-split` component, closes [#3557](https://github.com/tusen-ai/naive-ui/issues/3557).
|
||||
|
||||
|
||||
## 2.35.0
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
- `n-equation` 导出 `EquationProps` 类型
|
||||
- `n-popselect` 新增 `header` 插槽
|
||||
- `n-tree-select` 新增 `watch-props` 属性
|
||||
- 新增 `n-split` 组件,关闭 [#3557](https://github.com/tusen-ai/naive-ui/issues/3557)
|
||||
|
||||
## 2.35.0
|
||||
|
||||
|
@ -534,6 +534,10 @@ export const enComponentRoutes = [
|
||||
{
|
||||
path: 'equation',
|
||||
component: () => import('../../src/equation/demos/enUS/index.demo-entry.md')
|
||||
},
|
||||
{
|
||||
path: 'split',
|
||||
component: () => import('../../src/split/demos/enUS/index.demo-entry.md')
|
||||
}
|
||||
]
|
||||
|
||||
@ -911,6 +915,10 @@ export const zhComponentRoutes = [
|
||||
{
|
||||
path: 'equation',
|
||||
component: () => import('../../src/equation/demos/zhCN/index.demo-entry.md')
|
||||
},
|
||||
{
|
||||
path: 'split',
|
||||
component: () => import('../../src/split/demos/zhCN/index.demo-entry.md')
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -685,6 +685,12 @@ export function createComponentMenuOptions ({ lang, theme, mode }) {
|
||||
zh: '间距',
|
||||
enSuffix: true,
|
||||
path: '/space'
|
||||
},
|
||||
{
|
||||
en: 'Split',
|
||||
zh: '面板分割',
|
||||
enSuffix: true,
|
||||
path: '/split'
|
||||
}
|
||||
]
|
||||
}),
|
||||
|
@ -68,6 +68,7 @@ export * from './skeleton'
|
||||
export * from './slider'
|
||||
export * from './space'
|
||||
export * from './spin'
|
||||
export * from './split'
|
||||
export * from './statistic'
|
||||
export * from './steps'
|
||||
export * from './switch'
|
||||
|
@ -97,6 +97,7 @@ import type { CollapseTransitionTheme } from '../../collapse-transition/styles'
|
||||
import type { ButtonGroupTheme } from '../../button-group/styles/light'
|
||||
import type { RowTheme } from '../../legacy-grid/styles'
|
||||
import type { Katex } from './katex'
|
||||
import type { SplitTheme } from '../../split/styles'
|
||||
|
||||
export interface GlobalThemeWithoutCommon {
|
||||
Alert?: AlertTheme
|
||||
@ -179,6 +180,7 @@ export interface GlobalThemeWithoutCommon {
|
||||
Typography?: TypographyTheme
|
||||
Upload?: UploadTheme
|
||||
Watermark?: WatermarkTheme
|
||||
Split?: SplitTheme
|
||||
Row?: RowTheme
|
||||
// internal
|
||||
InternalSelectMenu?: InternalSelectMenuTheme
|
||||
|
20
src/split/demos/enUS/basic.demo.vue
Normal file
20
src/split/demos/enUS/basic.demo.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<markdown>
|
||||
# Basic
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split direction="horizontal" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '200px' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '200px' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
48
src/split/demos/enUS/event.demo.vue
Normal file
48
src/split/demos/enUS/event.demo.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<markdown>
|
||||
# Event
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split
|
||||
direction="horizontal"
|
||||
style="height: 200px"
|
||||
@move-start="handleOnMoveStart"
|
||||
@moving="handleOnMoving"
|
||||
@move-end="handleOnMoveEnd"
|
||||
>
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
const message = useMessage()
|
||||
return {
|
||||
handleOnMoveStart: () => {
|
||||
message.info('Move Start')
|
||||
},
|
||||
handleOnMoving: () => {
|
||||
message.info('Moving')
|
||||
},
|
||||
handleOnMoveEnd: () => {
|
||||
message.info('Move end')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
34
src/split/demos/enUS/index.demo-entry.md
Normal file
34
src/split/demos/enUS/index.demo-entry.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Panel Split Split
|
||||
|
||||
The flexible layout tool provides the possibility of customizing the interface layout
|
||||
|
||||
## Demos
|
||||
|
||||
```demo
|
||||
basic.vue
|
||||
vertical.vue
|
||||
nest.vue
|
||||
event.vue
|
||||
slot.vue
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Split Props
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| disabled | `Boolean` | `false` | Whether to disable. |
|
||||
| direction | `horizontal \| vertical` | `horizontal` | Split Indicates the direction of the split. |
|
||||
| min | `Number` | `0` | Split Indicates the minimum threshold for splitting, 0-1 is a percentage. |
|
||||
| max | `Number` | `1` | Split Indicates the maximum split threshold, 0-1 is a percentage. |
|
||||
| size | `Number` | `0.5` | Split Indicates the split size, 0-1 is a percentage. |
|
||||
| resize-trigger-size | `Number` | `3` | Split Specifies the size of the separator. |
|
||||
|
||||
### Split Slots
|
||||
|
||||
| Name | Parameters | Description |
|
||||
| -------------- | ---------- | ------------------------- |
|
||||
| first | `()` | The first panel content. |
|
||||
| second | `()` | The Second panel content. |
|
||||
| resize-trigger | `()` | Split bar content. |
|
42
src/split/demos/enUS/nest.demo.vue
Normal file
42
src/split/demos/enUS/nest.demo.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<markdown>
|
||||
# Nested layout
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split direction="horizontal" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
<n-split direction="vertical" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<n-split direction="horizontal" style="height: 100%">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 3
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 4
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
||||
</n-split>
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
48
src/split/demos/enUS/slot.demo.vue
Normal file
48
src/split/demos/enUS/slot.demo.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<markdown>
|
||||
# Slot.
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split direction="horizontal" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #resize-trigger>
|
||||
<div
|
||||
:style="{
|
||||
height: '100%',
|
||||
width: '16px',
|
||||
backgroundColor: '#409eff',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}"
|
||||
>
|
||||
<n-icon color="white" :size="18">
|
||||
<swap-horizontal-icon />
|
||||
</n-icon>
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { SwapHorizontal as SwapHorizontalIcon } from '@vicons/ionicons5'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
SwapHorizontalIcon
|
||||
}
|
||||
})
|
||||
</script>
|
20
src/split/demos/enUS/vertical.demo.vue
Normal file
20
src/split/demos/enUS/vertical.demo.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<markdown>
|
||||
# Vertical layout
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split direction="vertical" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
20
src/split/demos/zhCN/basic.demo.vue
Normal file
20
src/split/demos/zhCN/basic.demo.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<markdown>
|
||||
# 基础用法
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split direction="horizontal" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
48
src/split/demos/zhCN/event.demo.vue
Normal file
48
src/split/demos/zhCN/event.demo.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<markdown>
|
||||
# 事件
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split
|
||||
direction="horizontal"
|
||||
style="height: 200px"
|
||||
@move-start="handleOnMoveStart"
|
||||
@moving="handleOnMoving"
|
||||
@move-end="handleOnMoveEnd"
|
||||
>
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
const message = useMessage()
|
||||
return {
|
||||
handleOnMoveStart: () => {
|
||||
message.info('开始滚动')
|
||||
},
|
||||
handleOnMoving: () => {
|
||||
message.info('滚动中')
|
||||
},
|
||||
handleOnMoveEnd: () => {
|
||||
message.info('滚动结束')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
34
src/split/demos/zhCN/index.demo-entry.md
Normal file
34
src/split/demos/zhCN/index.demo-entry.md
Normal file
@ -0,0 +1,34 @@
|
||||
# 面板分割 Split
|
||||
|
||||
灵活的布局工具,提供了用户自定义界面布局的可能性。
|
||||
|
||||
## 演示
|
||||
|
||||
```demo
|
||||
basic.vue
|
||||
vertical.vue
|
||||
nest.vue
|
||||
event.vue
|
||||
slot.vue
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Split Props
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| disabled | `Boolean` | `false` | 是否禁用 |
|
||||
| direction | `horizontal \| vertical` | `horizontal` | Split 的分割方向 |
|
||||
| min | `Number` | `0` | Split 的分割最小阈值,0-1 代表百分比 |
|
||||
| max | `Number` | `1` | Split 的分割最大阈值,0-1 代表百分比 |
|
||||
| size | `Number` | `0.5` | Split 的分割大小,0-1 代表百分比 |
|
||||
| resize-trigger-size | `Number` | `3` | Split 的分隔条大小 |
|
||||
|
||||
### Split Slots
|
||||
|
||||
| 名称 | 参数 | 说明 |
|
||||
| -------------- | ---- | -------------- |
|
||||
| first | `()` | 第一个面板内容 |
|
||||
| second | `()` | 第二个面板内容 |
|
||||
| resize-trigger | `()` | 分割条内容 |
|
42
src/split/demos/zhCN/nest.demo.vue
Normal file
42
src/split/demos/zhCN/nest.demo.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<markdown>
|
||||
# 嵌套布局
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split direction="horizontal" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
<n-split direction="vertical" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<n-split direction="horizontal" style="height: 100%">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 3
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 4
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
||||
</n-split>
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
48
src/split/demos/zhCN/slot.demo.vue
Normal file
48
src/split/demos/zhCN/slot.demo.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<markdown>
|
||||
# 插槽
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split direction="horizontal" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #resize-trigger>
|
||||
<div
|
||||
:style="{
|
||||
height: '100%',
|
||||
width: '16px',
|
||||
backgroundColor: '#409eff',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}"
|
||||
>
|
||||
<n-icon color="white" :size="18">
|
||||
<swap-horizontal-icon />
|
||||
</n-icon>
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { SwapHorizontal as SwapHorizontalIcon } from '@vicons/ionicons5'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
SwapHorizontalIcon
|
||||
}
|
||||
})
|
||||
</script>
|
20
src/split/demos/zhCN/vertical.demo.vue
Normal file
20
src/split/demos/zhCN/vertical.demo.vue
Normal file
@ -0,0 +1,20 @@
|
||||
<markdown>
|
||||
# 垂直布局
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<n-split direction="vertical" style="height: 200px">
|
||||
<template #first>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 1
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #second>
|
||||
<div :style="{ height: '100%' }">
|
||||
Pane 2
|
||||
</div>
|
||||
</template>
|
||||
</n-split>
|
||||
</template>
|
2
src/split/index.ts
Normal file
2
src/split/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { default as NSplit, splitProps } from './src/Split'
|
||||
export type { SplitProps } from './src/Split'
|
207
src/split/src/Split.tsx
Normal file
207
src/split/src/Split.tsx
Normal file
@ -0,0 +1,207 @@
|
||||
import {
|
||||
h,
|
||||
defineComponent,
|
||||
type PropType,
|
||||
ref,
|
||||
computed,
|
||||
type CSSProperties
|
||||
} from 'vue'
|
||||
import type { ExtractPublicPropTypes } from '../../_utils'
|
||||
import useConfig from '../../_mixins/use-config'
|
||||
import style from './styles/index.cssr'
|
||||
import { type ThemeProps, useTheme } from '../../_mixins'
|
||||
import { type SplitTheme, splitLight } from '../styles'
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
export const splitProps = {
|
||||
...(useTheme.props as ThemeProps<SplitTheme>),
|
||||
direction: {
|
||||
type: String as PropType<'horizontal' | 'vertical'>,
|
||||
default: 'horizontal'
|
||||
},
|
||||
resizeTriggerSize: {
|
||||
type: Number,
|
||||
default: 3
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
size: {
|
||||
type: Number,
|
||||
default: 0.5
|
||||
},
|
||||
min: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
onMoveStart: Function as PropType<(e: Event) => void>,
|
||||
onMoving: Function as PropType<(e: Event) => void>,
|
||||
onMoveEnd: Function as PropType<(e: Event) => void>
|
||||
} as const
|
||||
|
||||
export type SplitProps = ExtractPublicPropTypes<typeof splitProps>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Split',
|
||||
props: splitProps,
|
||||
setup (props) {
|
||||
const { mergedClsPrefixRef, inlineThemeDisabled } = useConfig(props)
|
||||
|
||||
const themeRef = useTheme(
|
||||
'Split',
|
||||
'-split',
|
||||
style,
|
||||
splitLight,
|
||||
props,
|
||||
mergedClsPrefixRef
|
||||
)
|
||||
|
||||
const cssVarsRef = computed(() => {
|
||||
const {
|
||||
self: { resizableTriggerColorHover }
|
||||
} = themeRef.value
|
||||
return {
|
||||
'--n-resize-trigger-color-hover': resizableTriggerColorHover
|
||||
}
|
||||
})
|
||||
|
||||
const dividerRef = ref<HTMLElement | null>(null)
|
||||
const isDraggingRef = ref(false)
|
||||
const currentSize = ref(props.size)
|
||||
const triggerSize = ref(0)
|
||||
|
||||
onMounted(() => {
|
||||
if (!dividerRef.value) return
|
||||
const { width, height } = dividerRef.value.getBoundingClientRect()
|
||||
triggerSize.value = props.direction === 'horizontal' ? width : height
|
||||
})
|
||||
|
||||
const firstPaneStyle = computed(() => {
|
||||
const size = currentSize.value * 100
|
||||
return {
|
||||
flex: `0 0 calc(${size}% - ${triggerSize.value}px)`
|
||||
}
|
||||
})
|
||||
|
||||
const resizeTriggerStyle = computed(() => {
|
||||
return props.direction === 'horizontal'
|
||||
? {
|
||||
width: `${props.resizeTriggerSize}px`,
|
||||
height: '100%'
|
||||
}
|
||||
: {
|
||||
width: '100%',
|
||||
height: `${props.resizeTriggerSize}px`
|
||||
}
|
||||
})
|
||||
|
||||
const resizeTriggerWrapperStyle = computed(() => {
|
||||
return props.direction === 'horizontal'
|
||||
? {
|
||||
cursor: 'col-resize'
|
||||
}
|
||||
: {
|
||||
cursor: 'row-resize'
|
||||
}
|
||||
})
|
||||
|
||||
const handleMouseDown = (e: MouseEvent): void => {
|
||||
e.preventDefault()
|
||||
isDraggingRef.value = true
|
||||
if (props.onMoveStart) props.onMoveStart(e)
|
||||
const mouseMoveEvent = 'mousemove'
|
||||
const mouseUpEvent = 'mouseup'
|
||||
const onMouseMove = (e: MouseEvent): void => {
|
||||
updateSize(e)
|
||||
if (props.onMoving) props.onMoving(e)
|
||||
}
|
||||
const onMouseUp = (): void => {
|
||||
document.removeEventListener(mouseMoveEvent, onMouseMove)
|
||||
document.removeEventListener(mouseUpEvent, onMouseUp)
|
||||
isDraggingRef.value = false
|
||||
if (props.onMoveEnd) props.onMoveEnd(e)
|
||||
}
|
||||
document.addEventListener(mouseMoveEvent, onMouseMove)
|
||||
document.addEventListener(mouseUpEvent, onMouseUp)
|
||||
}
|
||||
|
||||
const updateSize = (event: MouseEvent): void => {
|
||||
const parentRect =
|
||||
dividerRef.value?.parentElement?.getBoundingClientRect()
|
||||
if (!parentRect) return
|
||||
const newSize =
|
||||
props.direction === 'horizontal'
|
||||
? (event.clientX - parentRect.left) / parentRect.width
|
||||
: (event.clientY - parentRect.top) / parentRect.height
|
||||
currentSize.value = newSize
|
||||
if (props.min) {
|
||||
currentSize.value = Math.max(newSize, props.min)
|
||||
}
|
||||
if (props.max) {
|
||||
currentSize.value = Math.min(newSize, props.max)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
cssVars: inlineThemeDisabled ? undefined : cssVarsRef,
|
||||
divider: dividerRef,
|
||||
isDragging: isDraggingRef,
|
||||
mergedClsPrefix: mergedClsPrefixRef,
|
||||
resizeTriggerWrapperStyle,
|
||||
resizeTriggerStyle,
|
||||
handleMouseDown,
|
||||
firstPaneStyle
|
||||
}
|
||||
},
|
||||
render () {
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
`${this.mergedClsPrefix}-split`,
|
||||
`${this.mergedClsPrefix}-split--${this.direction}`
|
||||
]}
|
||||
style={this.cssVars as CSSProperties}
|
||||
>
|
||||
<div
|
||||
class={`${this.mergedClsPrefix}-split-pane`}
|
||||
style={this.firstPaneStyle}
|
||||
>
|
||||
{this.$slots.first?.()}
|
||||
</div>
|
||||
|
||||
{!this.disabled && (
|
||||
<div
|
||||
ref="divider"
|
||||
class={[`${this.mergedClsPrefix}-split__resize-trigger-wrapper`]}
|
||||
style={this.resizeTriggerWrapperStyle}
|
||||
onMousedown={this.handleMouseDown}
|
||||
>
|
||||
{this.$slots['resize-trigger']?.() ?? (
|
||||
<div
|
||||
style={this.resizeTriggerStyle}
|
||||
class={[
|
||||
`${this.mergedClsPrefix}-split__resize-trigger`,
|
||||
this.isDragging &&
|
||||
`${this.mergedClsPrefix}-split__resize-trigger--hover`
|
||||
]}
|
||||
></div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
class={[
|
||||
`${this.mergedClsPrefix}-split-pane`,
|
||||
`${this.mergedClsPrefix}-split-second-pane`
|
||||
]}
|
||||
>
|
||||
{this.$slots.second?.()}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
39
src/split/src/styles/index.cssr.ts
Normal file
39
src/split/src/styles/index.cssr.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { c, cB, cM, cE } from '../../../_utils/cssr'
|
||||
|
||||
// vars:
|
||||
// --n-border-color
|
||||
// --n-color
|
||||
|
||||
export default c([
|
||||
cB('split', `
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
`, [
|
||||
cM('horizontal', `
|
||||
flex-direction: row;
|
||||
`),
|
||||
cM('vertical', `
|
||||
flex-direction: column;
|
||||
`),
|
||||
cB('split-pane', `
|
||||
overflow: hidden;
|
||||
`),
|
||||
cB('split-second-pane', `
|
||||
flex: 1;
|
||||
`),
|
||||
cE('resize-trigger', `
|
||||
background-color: var(--n-border-color);
|
||||
transition: background-color .3s var(--n-bezier);
|
||||
`, [
|
||||
cM('hover', `
|
||||
background-color: var(--n-resize-trigger-color-hover);
|
||||
`),
|
||||
c('&:hover', `
|
||||
background-color: var(--n-resize-trigger-color-hover);
|
||||
`
|
||||
)
|
||||
])
|
||||
]
|
||||
)
|
||||
])
|
9
src/split/styles/dark.ts
Normal file
9
src/split/styles/dark.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { commonDark } from '../../_styles/common'
|
||||
import { type SplitTheme } from './light'
|
||||
|
||||
const splitDark: SplitTheme = {
|
||||
name: 'Split',
|
||||
common: commonDark
|
||||
}
|
||||
|
||||
export default splitDark
|
3
src/split/styles/index.ts
Normal file
3
src/split/styles/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export { default as splitDark } from './dark'
|
||||
export { default as splitLight } from './light'
|
||||
export type { SplitTheme, SplitThemeVars } from './light'
|
21
src/split/styles/light.ts
Normal file
21
src/split/styles/light.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { commonLight } from '../../_styles/common'
|
||||
import type { ThemeCommonVars } from '../../_styles/common'
|
||||
import { type Theme } from '../../_mixins'
|
||||
|
||||
export const self = (vars: ThemeCommonVars) => {
|
||||
const { primaryColorHover } = vars
|
||||
return {
|
||||
resizableTriggerColorHover: primaryColorHover
|
||||
}
|
||||
}
|
||||
|
||||
export type SplitThemeVars = ReturnType<typeof self>
|
||||
|
||||
const themeLight: Theme<'Split', SplitThemeVars> = {
|
||||
name: 'Split',
|
||||
common: commonLight,
|
||||
self
|
||||
}
|
||||
|
||||
export default themeLight
|
||||
export type SplitTheme = typeof themeLight
|
@ -80,6 +80,7 @@ import { typographyDark } from '../typography/styles'
|
||||
import { treeDark } from '../tree/styles'
|
||||
import { uploadDark } from '../upload/styles'
|
||||
import { watermarkDark } from '../watermark/styles'
|
||||
import { splitDark } from '../split/styles'
|
||||
import type { BuiltInGlobalTheme } from './interface'
|
||||
|
||||
export const darkTheme: BuiltInGlobalTheme = {
|
||||
@ -165,5 +166,6 @@ export const darkTheme: BuiltInGlobalTheme = {
|
||||
TreeSelect: treeSelectDark,
|
||||
Typography: typographyDark,
|
||||
Upload: uploadDark,
|
||||
Watermark: watermarkDark
|
||||
Watermark: watermarkDark,
|
||||
Split: splitDark
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ import { treeLight } from '../tree/styles'
|
||||
import { treeSelectLight } from '../tree-select/styles'
|
||||
import { uploadLight } from '../upload/styles'
|
||||
import { watermarkLight } from '../watermark/styles'
|
||||
import { splitLight } from '../split/styles'
|
||||
import type { BuiltInGlobalTheme } from './interface'
|
||||
|
||||
export const lightTheme: BuiltInGlobalTheme = {
|
||||
@ -167,5 +168,6 @@ export const lightTheme: BuiltInGlobalTheme = {
|
||||
TreeSelect: treeSelectLight,
|
||||
Typography: typographyLight,
|
||||
Upload: uploadLight,
|
||||
Watermark: watermarkLight
|
||||
Watermark: watermarkLight,
|
||||
Split: splitLight
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user