mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
1
.github/workflows/test-coverage.yml
vendored
1
.github/workflows/test-coverage.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
4
.github/workflows/test-ssr.yml
vendored
4
.github/workflows/test-ssr.yml
vendored
@@ -1,6 +1,8 @@
|
||||
name: 🧪 Test SSR
|
||||
|
||||
on: pull_request
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
|
||||
|
||||
4
.github/workflows/test-unit.yml
vendored
4
.github/workflows/test-unit.yml
vendored
@@ -1,6 +1,8 @@
|
||||
name: 🧪 Unit Test
|
||||
|
||||
on: pull_request
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
## Changelog
|
||||
|
||||
### 2.5.4
|
||||
|
||||
_2024-02-02_
|
||||
|
||||
#### Features
|
||||
|
||||
- Components [dialog] Dialog can drag overflow the viewport (#15643 by @kooriookami)
|
||||
- Components [message-box] MessageBox can drag overflow the viewport (#15674 by @kooriookami)
|
||||
- Play custom namespace (#15677 by @btea)
|
||||
- Components [check-tag] add type prop (#15727 by @kooriookami)
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- Components [table] The namespace of the showOverflowTooltip is invalid. (#15627 by @xingyixiang)
|
||||
- Components [select] Remote search does not show menu when it has options and no query (#15683 by @wen403)
|
||||
- Docs overlay error caused by sidebar (#15694 by @heygsc)
|
||||
- Components [select] Fix value with value-key not selected (#15681 by @kooriookami)
|
||||
- Components [tour] buttonProps & isSameProps errors (#15680 by @Fuphoenixes)
|
||||
- Components [select] el-option-group error when el-option in a component (#15703 by @Fuphoenixes)
|
||||
- Components [drawer] click allow focus out (#11965 by @tolking)
|
||||
- Components [menu] Add menu-item margin when calculating `calcSliceIndex` (#15699 by @zhixiaotong)
|
||||
- Components [upload] Add crossorigin property (#15524 by @wkasunsampath)
|
||||
- Components [tabs] slot name use kebab-case style (#15733 by @chenxch)
|
||||
|
||||
### 2.5.3
|
||||
|
||||
_2024-01-22_
|
||||
|
||||
@@ -39,12 +39,26 @@ const onClick = (item: string) => {
|
||||
|
||||
const resourceCards = computed(() => [
|
||||
{
|
||||
key: 'axure',
|
||||
title: resourceLang.value.axure,
|
||||
description: 'Axure RP 9.0',
|
||||
icon: AxureComponentsSvg,
|
||||
intro: resourceLang.value.axureIntro,
|
||||
url: resourceUrl.axure,
|
||||
key: '2023-figma-ui-kit',
|
||||
title: resourceLang.value.figma2023,
|
||||
description: '2023 Figma UI Kit',
|
||||
icon: FigmaUiKitSvg,
|
||||
intro: resourceLang.value.figma2023Intro,
|
||||
url: 'https://www.figma.com/community/file/1305760370797950824/element-plus-design-system-ui-kit',
|
||||
},
|
||||
{
|
||||
key: 'figma-variables',
|
||||
title: resourceLang.value.figmaVariables,
|
||||
icon: FigmaVariablesSvg,
|
||||
intro: resourceLang.value.figmaVariablesIntro,
|
||||
url: 'https://www.figma.com/community/file/1256091634199852065',
|
||||
},
|
||||
{
|
||||
key: 'figma',
|
||||
title: resourceLang.value.figma,
|
||||
icon: FigmaTemplateSvg,
|
||||
intro: resourceLang.value.figmaIntro,
|
||||
url: 'https://www.figma.com/community/file/1021254029764378306',
|
||||
},
|
||||
{
|
||||
key: 'sketch',
|
||||
@@ -55,26 +69,12 @@ const resourceCards = computed(() => [
|
||||
url: resourceUrl.sketch,
|
||||
},
|
||||
{
|
||||
key: 'figma',
|
||||
title: resourceLang.value.figma,
|
||||
icon: FigmaTemplateSvg,
|
||||
intro: resourceLang.value.figmaIntro,
|
||||
url: 'https://www.figma.com/community/file/1021254029764378306',
|
||||
},
|
||||
{
|
||||
key: 'figma-variables',
|
||||
title: resourceLang.value.figmaVariables,
|
||||
icon: FigmaVariablesSvg,
|
||||
intro: resourceLang.value.figmaVariablesIntro,
|
||||
url: 'https://www.figma.com/community/file/1256091634199852065',
|
||||
},
|
||||
{
|
||||
key: '2023-figma-ui-kit',
|
||||
title: resourceLang.value.figma2023,
|
||||
description: '2023 Figma UI Kit',
|
||||
icon: FigmaUiKitSvg,
|
||||
intro: resourceLang.value.figma2023Intro,
|
||||
url: 'https://www.figma.com/community/file/1305760370797950824/element-plus-design-system-ui-kit',
|
||||
key: 'axure',
|
||||
title: resourceLang.value.axure,
|
||||
description: 'Axure RP 9.0',
|
||||
icon: AxureComponentsSvg,
|
||||
intro: resourceLang.value.axureIntro,
|
||||
url: resourceUrl.axure,
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
@include respond-to('md') {
|
||||
width: calc(var(--vp-sidebar-width-small));
|
||||
z-index: var(--sidebar-z-index-mobile);
|
||||
}
|
||||
|
||||
@include respond-to('lg') {
|
||||
|
||||
@@ -99,7 +99,7 @@ dialog/destroy-on-close
|
||||
|
||||
Try to drag the `header` part.
|
||||
|
||||
:::demo Set `draggable` to `true` to drag.
|
||||
:::demo Set `draggable` to `true` to drag. Set `overflow` ^(2.5.4) to `true` can drag overflow the viewport.
|
||||
|
||||
dialog/draggable-dialog
|
||||
|
||||
@@ -116,7 +116,7 @@ When using `modal` = false, please make sure that `append-to-body` was set to **
|
||||
### Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| -------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------- | ------- |
|
||||
|----------------------------|------------------------------------------------------------------------------------------------------| ----------------------------------- | ------- |
|
||||
| model-value / v-model | visibility of Dialog | ^[boolean] | — |
|
||||
| title | title of Dialog. Can also be passed with a named slot (see the following table) | ^[string] | '' |
|
||||
| width | width of Dialog, default is 50% | ^[string] / ^[number] | '' |
|
||||
@@ -135,6 +135,7 @@ When using `modal` = false, please make sure that `append-to-body` was set to **
|
||||
| show-close | whether to show a close button | ^[boolean] | true |
|
||||
| before-close | callback before Dialog closes, and it will prevent Dialog from closing, use done to close the dialog | ^[Function]`(done: DoneFn) => void` | — |
|
||||
| draggable | enable dragging feature for Dialog | ^[boolean] | false |
|
||||
| overflow ^(2.5.4) | draggable Dialog can overflow the viewport | ^[boolean] | false |
|
||||
| center | whether to align the header and footer in center | ^[boolean] | false |
|
||||
| align-center ^(2.2.16) | whether to align the dialog both horizontally and vertically | ^[boolean] | false |
|
||||
| destroy-on-close | destroy elements in Dialog when closed | ^[boolean] | false |
|
||||
|
||||
@@ -115,12 +115,14 @@ Drawer provides an API called `destroyOnClose`, which is a flag variable that in
|
||||
|
||||
### Events
|
||||
|
||||
| Name | Description | Type |
|
||||
| ------ | ------------------------------------------------ | ----------------------- |
|
||||
| open | Triggered before Drawer opening animation begins | ^[Function]`() => void` |
|
||||
| opened | Triggered after Drawer opening animation ended | ^[Function]`() => void` |
|
||||
| close | Triggered before Drawer closing animation begins | ^[Function]`() => void` |
|
||||
| closed | Triggered after Drawer closing animation ended | ^[Function]`() => void` |
|
||||
| Name | Description | Type |
|
||||
| ---------------- | ------------------------------------------------ | ----------------------- |
|
||||
| open | Triggered before Drawer opening animation begins | ^[Function]`() => void` |
|
||||
| opened | Triggered after Drawer opening animation ended | ^[Function]`() => void` |
|
||||
| close | Triggered before Drawer closing animation begins | ^[Function]`() => void` |
|
||||
| closed | Triggered after Drawer closing animation ended | ^[Function]`() => void` |
|
||||
| open-auto-focus | triggers after Drawer opens and content focused | ^[Function]`() => void` |
|
||||
| close-auto-focus | triggers after Drawer closed and content focused | ^[Function]`() => void` |
|
||||
|
||||
### Slots
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ message-box/customized-icon
|
||||
|
||||
MessageBox can be draggable.
|
||||
|
||||
:::demo Setting `draggable` to `true` allows user to drag MessageBox.
|
||||
:::demo Setting `draggable` to `true` allows user to drag MessageBox. Set `overflow` ^(2.5.4) to `true` can drag overflow the viewport.
|
||||
|
||||
message-box/draggable
|
||||
|
||||
@@ -159,7 +159,7 @@ The corresponding methods are: `ElMessageBox`, `ElMessageBox.alert`, `ElMessageB
|
||||
### Options
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------ |
|
||||
|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------| ---------------------------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| autofocus | auto focus when open MessageBox | ^[boolean] | true |
|
||||
| title | title of the MessageBox | ^[string] | '' |
|
||||
| message | content of the MessageBox | ^[string] / ^[VNode] / ^[Function]`() => VNode` ^(2.2.17) | — |
|
||||
@@ -191,6 +191,7 @@ The corresponding methods are: `ElMessageBox`, `ElMessageBox.alert`, `ElMessageB
|
||||
| input-error-message | error message when validation fails | ^[string] | Illegal input |
|
||||
| center | whether to align the content in center | ^[boolean] | false |
|
||||
| draggable | whether MessageBox is draggable | ^[boolean] | false |
|
||||
| overflow ^(2.5.4) | draggable MessageBox can overflow the viewport | ^[boolean] | false |
|
||||
| round-button | whether to use round button | ^[boolean] | false |
|
||||
| button-size | custom size of confirm and cancel buttons | ^[string]`'small' \| 'default' \| 'large'` | default |
|
||||
| append-to ^(2.2.19) | set the root element for the message box | ^[string] / ^[HTMLElement] | — |
|
||||
|
||||
@@ -108,10 +108,11 @@ tabs/customized-trigger
|
||||
|
||||
## Tabs Slots
|
||||
|
||||
| Name | Description | Subtags |
|
||||
| ---------------- | ------------------------- | -------- |
|
||||
| - | customize default content | Tab-pane |
|
||||
| addIcon ^(2.4.0) | customize add button icon | - |
|
||||
| Name | Description | Subtags |
|
||||
| ------------------------------ | ------------------------- | -------- |
|
||||
| - | customize default content | Tab-pane |
|
||||
| addIcon ^(2.4.0) ^(deprecated) | customize add button icon | - |
|
||||
| add-icon ^(2.5.4) | customize add button icon | - |
|
||||
|
||||
## Tab-pane Attributes
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ tag/theme
|
||||
|
||||
:::
|
||||
|
||||
## Rounded <el-tag>> 2.1.7</el-tag>
|
||||
## Rounded
|
||||
|
||||
Tag can also be rounded like button.
|
||||
|
||||
@@ -63,9 +63,9 @@ tag/rounded
|
||||
|
||||
:::
|
||||
|
||||
## Checkable tag
|
||||
## Checkable Tag
|
||||
|
||||
Sometimes because of the business needs, we might need checkbox like tag, but **button like checkbox** cannot meet our needs, here comes `check-tag`
|
||||
Sometimes because of the business needs, we might need checkbox like tag, but **button like checkbox** cannot meet our needs, here comes `check-tag`. You can use `type` prop in ^(2.5.4).
|
||||
|
||||
:::demo basic check-tag usage, the API is rather simple.
|
||||
|
||||
@@ -77,16 +77,16 @@ tag/checkable
|
||||
|
||||
### Tag Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| ------------------- | ------------------------------------ | ----------------------------------------------------------- | ------- |
|
||||
| type | type of Tag | ^[enum]`'success' \| 'info' \| 'warning' \| 'danger' \| ''` | '' |
|
||||
| closable | whether Tag can be removed | ^[boolean] | false |
|
||||
| disable-transitions | whether to disable animations | ^[boolean] | false |
|
||||
| hit | whether Tag has a highlighted border | ^[boolean] | false |
|
||||
| color | background color of the Tag | ^[string] | '' |
|
||||
| size | size of Tag | ^[enum]`'large' \| 'default' \| 'small' \| ''` | '' |
|
||||
| effect | theme of Tag | ^[enum]`'dark' \| 'light' \| 'plain'` | light |
|
||||
| round | whether Tag is rounded | ^[boolean] | false |
|
||||
| Name | Description | Type | Default |
|
||||
|---------------------|--------------------------------------|--------------------------------------------------------------------|---------|
|
||||
| type | type of Tag | ^[enum]`'primary' \| 'success' \| 'info' \| 'warning' \| 'danger'` | primary |
|
||||
| closable | whether Tag can be removed | ^[boolean] | false |
|
||||
| disable-transitions | whether to disable animations | ^[boolean] | false |
|
||||
| hit | whether Tag has a highlighted border | ^[boolean] | false |
|
||||
| color | background color of the Tag | ^[string] | — |
|
||||
| size | size of Tag | ^[enum]`'large' \| 'default' \| 'small'` | — |
|
||||
| effect | theme of Tag | ^[enum]`'dark' \| 'light' \| 'plain'` | light |
|
||||
| round | whether Tag is rounded | ^[boolean] | false |
|
||||
|
||||
### Tag Events
|
||||
|
||||
@@ -105,9 +105,10 @@ tag/checkable
|
||||
|
||||
### CheckTag Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| ------------------------- | ----------- | ---------- | ------- |
|
||||
| checked / v-model:checked | is checked | ^[boolean] | false |
|
||||
| Name | Description | Type | Default |
|
||||
|---------------------------|------------------|--------------------------------------------------------------------|---------|
|
||||
| checked / v-model:checked | is checked | ^[boolean] | false |
|
||||
| type ^(2.5.4) | type of CheckTag | ^[enum]`'primary' \| 'success' \| 'info' \| 'warning' \| 'danger'` | primary |
|
||||
|
||||
### CheckTag Events
|
||||
|
||||
|
||||
@@ -47,33 +47,34 @@ time-picker/range
|
||||
|
||||
### Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| --------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ----------- |
|
||||
| model-value / v-model | binding value, if it is an array, the length should be 2 | ^[number] / ^[string] / ^[object]`Date \| [Date, Date] \| [number, number] \| [string, string]` | '' |
|
||||
| readonly | whether TimePicker is read only | ^[boolean] | false |
|
||||
| disabled | whether TimePicker is disabled | ^[boolean] | false |
|
||||
| editable | whether the input is editable | ^[boolean] | true |
|
||||
| clearable | whether to show clear button | ^[boolean] | true |
|
||||
| size | size of Input | ^[enum]`'large' \| 'default' \| 'small'` | — |
|
||||
| placeholder | placeholder in non-range mode | ^[string] | '' |
|
||||
| start-placeholder | placeholder for the start time in range mode | ^[string] | — |
|
||||
| end-placeholder | placeholder for the end time in range mode | ^[string] | — |
|
||||
| is-range | whether to pick a time range | ^[boolean] | false |
|
||||
| arrow-control | whether to pick time using arrow buttons | ^[boolean] | false |
|
||||
| popper-class | custom class name for TimePicker's dropdown | ^[string] | '' |
|
||||
| range-separator | range separator | ^[string] | '-' |
|
||||
| format | format of the displayed value in the input box | ^[string] see [date formats](/en-US/component/date-picker#date-formats) | — |
|
||||
| default-value | optional, default date of the calendar | ^[Date] / ^[object]`[Date, Date]` | — |
|
||||
| id | same as `id` in native input | ^[string] / ^[object]`[string, string]` | — |
|
||||
| name | same as `name` in native input | ^[string] | '' |
|
||||
| label ^(a11y) | same as `aria-label` in native input | ^[string] | — |
|
||||
| prefix-icon | Custom prefix icon component | ^[string] / ^[Component] | Clock |
|
||||
| clear-icon | Custom clear icon component | ^[string] / ^[Component] | CircleClose |
|
||||
| disabled-hours | To specify the array of hours that cannot be selected | ^[Function]`(role: string, comparingDate?: Dayjs) => number[]` | — |
|
||||
| disabled-minutes | To specify the array of minutes that cannot be selected | ^[Function]`(hour: number, role: string, comparingDate?: Dayjs) => number[]` | — |
|
||||
| disabled-seconds | To specify the array of seconds that cannot be selected | ^[Function]`(hour: number, minute: number, role: string, comparingDate?: Dayjs) => number[]` | — |
|
||||
| teleported | whether time-picker dropdown is teleported to the body | ^[boolean] | true |
|
||||
| tabindex | input tabindex | ^[string] / ^[number] | 0 |
|
||||
| Name | Description | Type | Default |
|
||||
| --------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ----------- |
|
||||
| model-value / v-model | binding value, if it is an array, the length should be 2 | ^[number] / ^[string] / ^[object]`Date \| [Date, Date] \| [number, number] \| [string, string]` | '' |
|
||||
| readonly | whether TimePicker is read only | ^[boolean] | false |
|
||||
| disabled | whether TimePicker is disabled | ^[boolean] | false |
|
||||
| editable | whether the input is editable | ^[boolean] | true |
|
||||
| clearable | whether to show clear button | ^[boolean] | true |
|
||||
| size | size of Input | ^[enum]`'large' \| 'default' \| 'small'` | — |
|
||||
| placeholder | placeholder in non-range mode | ^[string] | '' |
|
||||
| start-placeholder | placeholder for the start time in range mode | ^[string] | — |
|
||||
| end-placeholder | placeholder for the end time in range mode | ^[string] | — |
|
||||
| is-range | whether to pick a time range | ^[boolean] | false |
|
||||
| arrow-control | whether to pick time using arrow buttons | ^[boolean] | false |
|
||||
| popper-class | custom class name for TimePicker's dropdown | ^[string] | '' |
|
||||
| range-separator | range separator | ^[string] | '-' |
|
||||
| format | format of the displayed value in the input box | ^[string] see [date formats](/en-US/component/date-picker#date-formats) | — |
|
||||
| default-value | optional, default date of the calendar | ^[Date] / ^[object]`[Date, Date]` | — |
|
||||
| value-format | optional, format of binding value. If not specified, the binding value will be a Date object | ^[string] see [date formats](/en-US/component/date-picker#date-formats) | — |
|
||||
| id | same as `id` in native input | ^[string] / ^[object]`[string, string]` | — |
|
||||
| name | same as `name` in native input | ^[string] | '' |
|
||||
| label ^(a11y) | same as `aria-label` in native input | ^[string] | — |
|
||||
| prefix-icon | Custom prefix icon component | ^[string] / ^[Component] | Clock |
|
||||
| clear-icon | Custom clear icon component | ^[string] / ^[Component] | CircleClose |
|
||||
| disabled-hours | To specify the array of hours that cannot be selected | ^[Function]`(role: string, comparingDate?: Dayjs) => number[]` | — |
|
||||
| disabled-minutes | To specify the array of minutes that cannot be selected | ^[Function]`(hour: number, role: string, comparingDate?: Dayjs) => number[]` | — |
|
||||
| disabled-seconds | To specify the array of seconds that cannot be selected | ^[Function]`(hour: number, minute: number, role: string, comparingDate?: Dayjs) => number[]` | — |
|
||||
| teleported | whether time-picker dropdown is teleported to the body | ^[boolean] | true |
|
||||
| tabindex | input tabindex | ^[string] / ^[number] | 0 |
|
||||
|
||||
### Events
|
||||
|
||||
|
||||
@@ -126,10 +126,10 @@ tour-step component configuration with the same name has higher priority
|
||||
|
||||
### TourStep slots
|
||||
|
||||
| Name | Description |
|
||||
| ------- | ----------- |
|
||||
| default | description |
|
||||
| title | title |
|
||||
| Name | Description |
|
||||
| -------- | ----------- |
|
||||
| default | description |
|
||||
| header | header |
|
||||
|
||||
### TourStep events
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ upload/manual
|
||||
| show-file-list | whether to show the uploaded file list. | ^[boolean] | true |
|
||||
| drag | whether to activate drag and drop mode. | ^[boolean] | false |
|
||||
| accept | accepted [file types](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept), will not work when `thumbnail-mode === true`. | ^[string] | '' |
|
||||
| crossorigin | native attribute [crossorigin](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin). | ^[enum]`'' \| 'anonymous' \| 'use-credentials'` | — |
|
||||
| on-preview | hook function when clicking the uploaded files. | ^[Function]`(uploadFile: UploadFile) => void` | — |
|
||||
| on-remove | hook function when files are removed. | ^[Function]`(uploadFile: UploadFile, uploadFiles: UploadFiles) => void` | — |
|
||||
| on-success | hook function when uploaded successfully. | ^[Function]`(response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => void` | — |
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<el-button text @click="centerDialogVisible = true">
|
||||
<el-button plain @click="centerDialogVisible = true">
|
||||
Click to open the Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog
|
||||
v-model="centerDialogVisible"
|
||||
title="Warning"
|
||||
width="30%"
|
||||
width="500"
|
||||
align-center
|
||||
>
|
||||
<span>Open the dialog from the center from the screen</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="centerDialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="centerDialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -25,8 +25,3 @@ import { ref } from 'vue'
|
||||
|
||||
const centerDialogVisible = ref(false)
|
||||
</script>
|
||||
<style scoped>
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<el-button text @click="dialogVisible = true">
|
||||
click to open the Dialog
|
||||
<el-button plain @click="dialogVisible = true">
|
||||
Click to open the Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="Tips"
|
||||
width="30%"
|
||||
width="500"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<span>This is a message</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -37,8 +37,3 @@ const handleClose = (done: () => void) => {
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<template>
|
||||
<el-button text @click="centerDialogVisible = true">
|
||||
<el-button plain @click="centerDialogVisible = true">
|
||||
Click to open the Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="centerDialogVisible" title="Warning" width="30%" center>
|
||||
<el-dialog v-model="centerDialogVisible" title="Warning" width="500" center>
|
||||
<span>
|
||||
It should be noted that the content will not be aligned in center by
|
||||
default
|
||||
</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="centerDialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="centerDialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -23,8 +23,3 @@ import { ref } from 'vue'
|
||||
|
||||
const centerDialogVisible = ref(false)
|
||||
</script>
|
||||
<style scoped>
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<template>
|
||||
<el-button text @click="dialogTableVisible = true">
|
||||
open a Table nested Dialog
|
||||
<el-button plain @click="dialogTableVisible = true">
|
||||
Open a Table nested Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="dialogTableVisible" title="Shipping address">
|
||||
<el-button plain @click="dialogFormVisible = true">
|
||||
Open a Form nested Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="dialogTableVisible" title="Shipping address" width="800">
|
||||
<el-table :data="gridData">
|
||||
<el-table-column property="date" label="Date" width="150" />
|
||||
<el-table-column property="name" label="Name" width="200" />
|
||||
@@ -11,12 +15,7 @@
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<!-- Form -->
|
||||
<el-button text @click="dialogFormVisible = true">
|
||||
open a Form nested Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="dialogFormVisible" title="Shipping address">
|
||||
<el-dialog v-model="dialogFormVisible" title="Shipping address" width="500">
|
||||
<el-form :model="form">
|
||||
<el-form-item label="Promotion name" :label-width="formLabelWidth">
|
||||
<el-input v-model="form.name" autocomplete="off" />
|
||||
@@ -29,12 +28,12 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogFormVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -80,17 +79,3 @@ const gridData = [
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<style scoped>
|
||||
.el-button--text {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.el-select {
|
||||
width: 300px;
|
||||
}
|
||||
.el-input {
|
||||
width: 300px;
|
||||
}
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<el-button @click="visible = true">
|
||||
<el-button plain @click="visible = true">
|
||||
Open Dialog with customized header
|
||||
</el-button>
|
||||
<el-dialog v-model="visible" :show-close="false">
|
||||
|
||||
<el-dialog v-model="visible" :show-close="false" width="500">
|
||||
<template #header="{ close, titleId, titleClass }">
|
||||
<div class="my-header">
|
||||
<h4 :id="titleId" :class="titleClass">This is a custom header!</h4>
|
||||
@@ -29,5 +30,6 @@ const visible = ref(false)
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<el-button text @click="centerDialogVisible = true">
|
||||
<el-button plain @click="centerDialogVisible = true">
|
||||
Click to open Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog
|
||||
v-model="centerDialogVisible"
|
||||
title="Notice"
|
||||
width="30%"
|
||||
width="500"
|
||||
destroy-on-close
|
||||
center
|
||||
>
|
||||
@@ -18,12 +18,12 @@
|
||||
<strong>Extra content (Not rendered)</strong>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="centerDialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="centerDialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -33,8 +33,3 @@ import { ref } from 'vue'
|
||||
|
||||
const centerDialogVisible = ref(false)
|
||||
</script>
|
||||
<style scoped>
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,17 +1,39 @@
|
||||
<template>
|
||||
<el-button text @click="dialogVisible = true">
|
||||
Click to open Dialog
|
||||
<el-button plain @click="dialogVisible = true">
|
||||
Open a draggable Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="dialogVisible" title="Tips" width="30%" draggable>
|
||||
<el-button plain @click="dialogOverflowVisible = true">
|
||||
Open a overflow draggable Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="dialogVisible" title="Tips" width="500" draggable>
|
||||
<span>It's a draggable Dialog</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="dialogOverflowVisible"
|
||||
title="Tips"
|
||||
width="500"
|
||||
draggable
|
||||
overflow
|
||||
>
|
||||
<span>It's a overflow draggable Dialog</span>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogOverflowVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogOverflowVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@@ -20,4 +42,5 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const dialogOverflowVisible = ref(false)
|
||||
</script>
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<template>
|
||||
<el-button text @click="dialogVisible = true">
|
||||
click to open the Dialog
|
||||
</el-button>
|
||||
|
||||
<div>
|
||||
<p>Close dialog and the input will be focused</p>
|
||||
<el-input ref="inputRef" placeholder="Please input" />
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
destroy-on-close
|
||||
title="Tips"
|
||||
width="30%"
|
||||
@close-auto-focus="handleCloseAutoFocus"
|
||||
>
|
||||
<span>This is a message</span>
|
||||
<el-divider />
|
||||
<el-input placeholder="Initially focused" />
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { ElInput } from 'element-plus'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const inputRef = ref<InstanceType<typeof ElInput>>()
|
||||
|
||||
const handleCloseAutoFocus = () => {
|
||||
inputRef.value?.focus()
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,22 +1,23 @@
|
||||
<template>
|
||||
<el-button text @click="outerVisible = true">
|
||||
open the outer Dialog
|
||||
<el-button plain @click="outerVisible = true">
|
||||
Open the outer Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="outerVisible" title="Outer Dialog">
|
||||
<template #default>
|
||||
<el-dialog
|
||||
v-model="innerVisible"
|
||||
width="30%"
|
||||
title="Inner Dialog"
|
||||
append-to-body
|
||||
/>
|
||||
</template>
|
||||
<el-dialog v-model="outerVisible" title="Outer Dialog" width="800">
|
||||
<span>This is the outer Dialog</span>
|
||||
<el-dialog
|
||||
v-model="innerVisible"
|
||||
width="500"
|
||||
title="Inner Dialog"
|
||||
append-to-body
|
||||
>
|
||||
<span>This is the inner Dialog</span>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="outerVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="innerVisible = true">
|
||||
open the inner Dialog
|
||||
Open the inner Dialog
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -29,8 +30,3 @@ import { ref } from 'vue'
|
||||
const outerVisible = ref(false)
|
||||
const innerVisible = ref(false)
|
||||
</script>
|
||||
<style scoped>
|
||||
.dialog-footer button:first-child {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -78,4 +78,9 @@ import {
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.block-col-2 .el-dropdown-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open the Message Box</el-button>
|
||||
<el-button plain @click="open">Click to open the Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open Message Box</el-button>
|
||||
<el-button plain @click="open">Click to open Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open the Message Box</el-button>
|
||||
<el-button plain @click="open">Click to open the Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open Message Box</el-button>
|
||||
<el-button plain @click="open">Click to open Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open Message Box</el-button>
|
||||
<el-button plain @click="open">Click to open Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open Message Box</el-button>
|
||||
<el-button plain @click="open">Click to open Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open Message Box</el-button>
|
||||
<el-button plain @click="open">Open a draggable Message Box</el-button>
|
||||
<el-button plain @click="open2">
|
||||
Open a overflow draggable Message Box
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -29,4 +32,30 @@ const open = () => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const open2 = () => {
|
||||
ElMessageBox.confirm(
|
||||
'proxy will permanently delete the file. Continue?',
|
||||
'Warning',
|
||||
{
|
||||
confirmButtonText: 'OK',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'warning',
|
||||
draggable: true,
|
||||
overflow: true,
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: 'Delete completed',
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: 'Delete canceled',
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open Message Box</el-button>
|
||||
<el-button plain @click="open">Click to open Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-button text @click="open">Click to open Message Box</el-button>
|
||||
<el-button plain @click="open">Click to open Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -7,7 +7,7 @@ addIcon
|
||||
editable
|
||||
@edit="handleTabsEdit"
|
||||
>
|
||||
<template #addIcon>
|
||||
<template #add-icon>
|
||||
<el-icon><Select /></el-icon>
|
||||
</template>
|
||||
<el-tab-pane
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<el-tag>Tag 1</el-tag>
|
||||
<el-tag class="ml-2" type="success">Tag 2</el-tag>
|
||||
<el-tag class="ml-2" type="info">Tag 3</el-tag>
|
||||
<el-tag class="ml-2" type="warning">Tag 4</el-tag>
|
||||
<el-tag class="ml-2" type="danger">Tag 5</el-tag>
|
||||
<div class="flex gap-2">
|
||||
<el-tag type="primary">Tag 1</el-tag>
|
||||
<el-tag type="success">Tag 2</el-tag>
|
||||
<el-tag type="info">Tag 3</el-tag>
|
||||
<el-tag type="warning">Tag 4</el-tag>
|
||||
<el-tag type="danger">Tag 5</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
@@ -1,16 +1,58 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-check-tag checked style="margin-right: 8px">Checked</el-check-tag>
|
||||
<div class="flex gap-2">
|
||||
<el-check-tag checked>Checked</el-check-tag>
|
||||
<el-check-tag :checked="checked" @change="onChange">Toggle me</el-check-tag>
|
||||
</div>
|
||||
<div class="flex gap-2 mt-4">
|
||||
<el-check-tag :checked="checked1" type="primary" @change="onChange1">
|
||||
Tag 1
|
||||
</el-check-tag>
|
||||
<el-check-tag :checked="checked2" type="success" @change="onChange2">
|
||||
Tag 2
|
||||
</el-check-tag>
|
||||
<el-check-tag :checked="checked3" type="info" @change="onChange3">
|
||||
Tag 3
|
||||
</el-check-tag>
|
||||
<el-check-tag :checked="checked4" type="warning" @change="onChange4">
|
||||
Tag 4
|
||||
</el-check-tag>
|
||||
<el-check-tag :checked="checked5" type="danger" @change="onChange5">
|
||||
Tag 5
|
||||
</el-check-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const checked = ref(false)
|
||||
const checked1 = ref(true)
|
||||
const checked2 = ref(true)
|
||||
const checked3 = ref(true)
|
||||
const checked4 = ref(true)
|
||||
const checked5 = ref(true)
|
||||
|
||||
const onChange = (status: boolean) => {
|
||||
checked.value = status
|
||||
}
|
||||
|
||||
const onChange1 = (status: boolean) => {
|
||||
checked1.value = status
|
||||
}
|
||||
|
||||
const onChange2 = (status: boolean) => {
|
||||
checked2.value = status
|
||||
}
|
||||
|
||||
const onChange3 = (status: boolean) => {
|
||||
checked3.value = status
|
||||
}
|
||||
|
||||
const onChange4 = (status: boolean) => {
|
||||
checked4.value = status
|
||||
}
|
||||
|
||||
const onChange5 = (status: boolean) => {
|
||||
checked5.value = status
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
<template>
|
||||
<el-tag
|
||||
v-for="tag in dynamicTags"
|
||||
:key="tag"
|
||||
class="mx-1"
|
||||
closable
|
||||
:disable-transitions="false"
|
||||
@close="handleClose(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
<el-input
|
||||
v-if="inputVisible"
|
||||
ref="InputRef"
|
||||
v-model="inputValue"
|
||||
class="ml-1 w-20"
|
||||
size="small"
|
||||
@keyup.enter="handleInputConfirm"
|
||||
@blur="handleInputConfirm"
|
||||
/>
|
||||
<el-button v-else class="button-new-tag ml-1" size="small" @click="showInput">
|
||||
+ New Tag
|
||||
</el-button>
|
||||
<div class="flex gap-2">
|
||||
<el-tag
|
||||
v-for="tag in dynamicTags"
|
||||
:key="tag"
|
||||
closable
|
||||
:disable-transitions="false"
|
||||
@close="handleClose(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
<el-input
|
||||
v-if="inputVisible"
|
||||
ref="InputRef"
|
||||
v-model="inputValue"
|
||||
class="w-20"
|
||||
size="small"
|
||||
@keyup.enter="handleInputConfirm"
|
||||
@blur="handleInputConfirm"
|
||||
/>
|
||||
<el-button v-else class="button-new-tag" size="small" @click="showInput">
|
||||
+ New Tag
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
<template>
|
||||
<el-tag
|
||||
v-for="tag in tags"
|
||||
:key="tag.name"
|
||||
class="mx-1"
|
||||
closable
|
||||
:type="tag.type"
|
||||
>
|
||||
{{ tag.name }}
|
||||
</el-tag>
|
||||
<div class="flex gap-2">
|
||||
<el-tag v-for="tag in tags" :key="tag.name" closable :type="tag.type">
|
||||
{{ tag.name }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const tags = ref([
|
||||
{ name: 'Tag 1', type: '' },
|
||||
{ name: 'Tag 1', type: 'primary' },
|
||||
{ name: 'Tag 2', type: 'success' },
|
||||
{ name: 'Tag 3', type: 'info' },
|
||||
{ name: 'Tag 4', type: 'warning' },
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap gap-2 my-2">
|
||||
<div class="flex gap-2">
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
:type="item.type"
|
||||
class="mx-1"
|
||||
effect="dark"
|
||||
round
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<div class="flex gap-2 mt-4">
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
:type="item.type"
|
||||
class="mx-1"
|
||||
effect="light"
|
||||
round
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 my-2">
|
||||
<div class="flex gap-2 mt-4">
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
:type="item.type"
|
||||
class="mx-1"
|
||||
effect="plain"
|
||||
round
|
||||
>
|
||||
@@ -45,10 +42,10 @@ import type { TagProps } from 'element-plus'
|
||||
type Item = { type: TagProps['type']; label: string }
|
||||
|
||||
const items = ref<Array<Item>>([
|
||||
{ type: '', label: 'Tag 1' },
|
||||
{ type: 'primary', label: 'Tag 1' },
|
||||
{ type: 'success', label: 'Tag 2' },
|
||||
{ type: 'info', label: 'Tag 3' },
|
||||
{ type: 'danger', label: 'Tag 4' },
|
||||
{ type: 'warning', label: 'Tag 5' },
|
||||
{ type: 'warning', label: 'Tag 4' },
|
||||
{ type: 'danger', label: 'Tag 5' },
|
||||
])
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
<template>
|
||||
<el-row>
|
||||
<el-tag class="mx-1" size="large">Large</el-tag>
|
||||
<el-tag class="mx-1">Default</el-tag>
|
||||
<el-tag class="mx-1" size="small">Small</el-tag>
|
||||
</el-row>
|
||||
|
||||
<el-row class="mt-4">
|
||||
<el-tag class="mx-1" size="large" closable>Large</el-tag>
|
||||
<el-tag class="mx-1" closable>Default</el-tag>
|
||||
<el-tag class="mx-1" size="small" closable>Small</el-tag>
|
||||
</el-row>
|
||||
<div class="flex gap-2">
|
||||
<el-tag size="large">Large</el-tag>
|
||||
<el-tag>Default</el-tag>
|
||||
<el-tag size="small">Small</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,69 +1,36 @@
|
||||
<template>
|
||||
<div class="tag-group my-2 flex flex-wrap gap-1 items-center">
|
||||
<span class="tag-group__title m-1 line-height-2">Dark</span>
|
||||
<div class="flex gap-2">
|
||||
<span>Dark</span>
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
:type="item.type"
|
||||
class="mx-1"
|
||||
effect="dark"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
:type="item.type"
|
||||
class="mx-1"
|
||||
effect="dark"
|
||||
closable
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="tag-group my-2 flex flex-wrap gap-1 items-center">
|
||||
<span class="tag-group__title m-1">Light</span>
|
||||
<div class="flex gap-2 mt-4">
|
||||
<span>Light</span>
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
class="mx-1"
|
||||
:type="item.type"
|
||||
effect="light"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
class="mx-1"
|
||||
:type="item.type"
|
||||
effect="light"
|
||||
closable
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="tag-group my-2 flex flex-wrap gap-1 items-center">
|
||||
<span class="tag-group__title m-1">Plain</span>
|
||||
<div class="flex gap-2 mt-4">
|
||||
<span>Plain</span>
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
class="mx-1"
|
||||
:type="item.type"
|
||||
effect="plain"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-for="item in items"
|
||||
:key="item.label"
|
||||
class="mx-1"
|
||||
:type="item.type"
|
||||
effect="plain"
|
||||
closable
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -75,10 +42,10 @@ import type { TagProps } from 'element-plus'
|
||||
type Item = { type: TagProps['type']; label: string }
|
||||
|
||||
const items = ref<Array<Item>>([
|
||||
{ type: '', label: 'Tag 1' },
|
||||
{ type: 'primary', label: 'Tag 1' },
|
||||
{ type: 'success', label: 'Tag 2' },
|
||||
{ type: 'info', label: 'Tag 3' },
|
||||
{ type: 'danger', label: 'Tag 4' },
|
||||
{ type: 'warning', label: 'Tag 5' },
|
||||
{ type: 'warning', label: 'Tag 4' },
|
||||
{ type: 'danger', label: 'Tag 5' },
|
||||
])
|
||||
</script>
|
||||
|
||||
@@ -4,14 +4,15 @@
|
||||
<el-divider />
|
||||
|
||||
<el-space>
|
||||
<el-button ref="ref1">upload</el-button>
|
||||
<el-button ref="ref2" type="primary">save</el-button>
|
||||
<el-button ref="ref1">Upload</el-button>
|
||||
<el-button ref="ref2" type="primary">Save</el-button>
|
||||
<el-button ref="ref3" :icon="MoreFilled" />
|
||||
</el-space>
|
||||
|
||||
<el-tour v-model="open">
|
||||
<el-tour-step :target="ref1?.$el" title="Upload File">
|
||||
<img
|
||||
style="width: 240px"
|
||||
src="https://element-plus.org/images/element-plus-logo.svg"
|
||||
alt="tour.png"
|
||||
/>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<el-divider />
|
||||
|
||||
<el-space>
|
||||
<el-button ref="ref1">upload</el-button>
|
||||
<el-button ref="ref2" type="primary">save</el-button>
|
||||
<el-button ref="ref1">Upload</el-button>
|
||||
<el-button ref="ref2" type="primary">Save</el-button>
|
||||
<el-button ref="ref3" :icon="MoreFilled" />
|
||||
</el-space>
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<el-divider />
|
||||
|
||||
<el-space>
|
||||
<el-button ref="ref1">upload</el-button>
|
||||
<el-button ref="ref2" type="primary">save</el-button>
|
||||
<el-button ref="ref1">Upload</el-button>
|
||||
<el-button ref="ref2" type="primary">Save</el-button>
|
||||
<el-button ref="ref3" :icon="MoreFilled" />
|
||||
</el-space>
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<el-divider />
|
||||
|
||||
<el-space>
|
||||
<el-button ref="ref1">upload</el-button>
|
||||
<el-button ref="ref2" type="primary">save</el-button>
|
||||
<el-button ref="ref1">Upload</el-button>
|
||||
<el-button ref="ref2" type="primary">Save</el-button>
|
||||
<el-button ref="ref3" :icon="MoreFilled" />
|
||||
</el-space>
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<el-divider />
|
||||
|
||||
<el-space>
|
||||
<el-button id="btn1">upload</el-button>
|
||||
<el-button id="btn2" type="primary">save</el-button>
|
||||
<el-button id="btn1">Upload</el-button>
|
||||
<el-button id="btn2" type="primary">Save</el-button>
|
||||
<el-button ref="btnRef" :icon="MoreFilled" />
|
||||
</el-space>
|
||||
|
||||
|
||||
@@ -12,6 +12,14 @@ export const checkTagProps = buildProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* @description type of Tag
|
||||
*/
|
||||
type: {
|
||||
type: String,
|
||||
values: ['primary', 'success', 'info', 'warning', 'danger'],
|
||||
default: 'primary',
|
||||
},
|
||||
} as const)
|
||||
export type CheckTagProps = ExtractPropTypes<typeof checkTagProps>
|
||||
|
||||
|
||||
@@ -17,7 +17,11 @@ const props = defineProps(checkTagProps)
|
||||
const emit = defineEmits(checkTagEmits)
|
||||
|
||||
const ns = useNamespace('check-tag')
|
||||
const containerKls = computed(() => [ns.b(), ns.is('checked', props.checked)])
|
||||
const containerKls = computed(() => [
|
||||
ns.b(),
|
||||
ns.is('checked', props.checked),
|
||||
ns.m(props.type || 'primary'),
|
||||
])
|
||||
|
||||
const handleChange = () => {
|
||||
const checked = !props.checked
|
||||
|
||||
@@ -15,17 +15,14 @@ export const dialogContentProps = buildProps({
|
||||
closeIcon: {
|
||||
type: iconPropType,
|
||||
},
|
||||
/**
|
||||
* @deprecated will be removed in version 2.4.0, please use class
|
||||
*/
|
||||
customClass: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description enable dragging feature for Dialog
|
||||
*/
|
||||
draggable: Boolean,
|
||||
/**
|
||||
* @description draggable Dialog can overflow the viewport
|
||||
*/
|
||||
overflow: Boolean,
|
||||
/**
|
||||
* @description whether the Dialog takes up full screen
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div :ref="composedDialogRef" :class="dialogKls" :style="style" tabindex="-1">
|
||||
<header ref="headerRef" :class="ns.e('header')">
|
||||
<header
|
||||
ref="headerRef"
|
||||
:class="[ns.e('header'), { 'show-close': showClose }]"
|
||||
>
|
||||
<slot name="header">
|
||||
<span role="heading" :aria-level="ariaLevel" :class="ns.e('title')">
|
||||
{{ title }}
|
||||
@@ -52,11 +55,11 @@ const dialogKls = computed(() => [
|
||||
ns.is('draggable', props.draggable),
|
||||
ns.is('align-center', props.alignCenter),
|
||||
{ [ns.m('center')]: props.center },
|
||||
props.customClass,
|
||||
])
|
||||
|
||||
const composedDialogRef = composeRefs(focusTrapRef, dialogRef)
|
||||
|
||||
const draggable = computed(() => props.draggable)
|
||||
useDraggable(dialogRef, headerRef, draggable)
|
||||
const overflow = computed(() => props.overflow)
|
||||
useDraggable(dialogRef, headerRef, draggable, overflow)
|
||||
</script>
|
||||
|
||||
@@ -41,11 +41,11 @@
|
||||
v-if="rendered"
|
||||
ref="dialogContentRef"
|
||||
v-bind="$attrs"
|
||||
:custom-class="customClass"
|
||||
:center="center"
|
||||
:align-center="alignCenter"
|
||||
:close-icon="closeIcon"
|
||||
:draggable="draggable"
|
||||
:overflow="overflow"
|
||||
:fullscreen="fullscreen"
|
||||
:show-close="showClose"
|
||||
:title="title"
|
||||
@@ -104,18 +104,6 @@ useDeprecated(
|
||||
computed(() => !!slots.title)
|
||||
)
|
||||
|
||||
useDeprecated(
|
||||
{
|
||||
scope: 'el-dialog',
|
||||
from: 'custom-class',
|
||||
replacement: 'class',
|
||||
version: '2.3.0',
|
||||
ref: 'https://element-plus.org/en-US/component/dialog.html#attributes',
|
||||
type: 'Attribute',
|
||||
},
|
||||
computed(() => !!props.customClass)
|
||||
)
|
||||
|
||||
const ns = useNamespace('dialog')
|
||||
const dialogRef = ref<HTMLElement>()
|
||||
const headerRef = ref<HTMLElement>()
|
||||
|
||||
@@ -229,23 +229,6 @@ describe('Drawer', () => {
|
||||
expect(wrapper.find('.el-drawer__close-btn').exists()).toBe(false)
|
||||
})
|
||||
|
||||
test('should have custom classes when custom classes were given', async () => {
|
||||
const classes = 'some-custom-class'
|
||||
const wrapper = _mount(
|
||||
`
|
||||
<el-drawer :title='title' v-model='visible' ref='drawer' custom-class='${classes}'>
|
||||
<span>${content}</span>
|
||||
</el-drawer>
|
||||
`,
|
||||
() => ({
|
||||
title,
|
||||
visible: true,
|
||||
})
|
||||
)
|
||||
|
||||
expect(wrapper.find(`.${classes}`).exists()).toBe(true)
|
||||
})
|
||||
|
||||
test('drawer header should have slot props', async () => {
|
||||
const wrapper = _mount(
|
||||
`
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
:trapped="visible"
|
||||
:focus-trap-el="drawerRef"
|
||||
:focus-start-el="focusStartRef"
|
||||
@focus-after-trapped="onOpenAutoFocus"
|
||||
@focus-after-released="onCloseAutoFocus"
|
||||
@focusout-prevented="onFocusoutPrevented"
|
||||
@release-requested="onCloseRequested"
|
||||
>
|
||||
<div
|
||||
@@ -27,7 +30,7 @@
|
||||
:aria-labelledby="!title ? titleId : undefined"
|
||||
:aria-describedby="bodyId"
|
||||
v-bind="$attrs"
|
||||
:class="[ns.b(), direction, visible && 'open', customClass]"
|
||||
:class="[ns.b(), direction, visible && 'open']"
|
||||
:style="
|
||||
isHorizontal ? 'width: ' + drawerSize : 'height: ' + drawerSize
|
||||
"
|
||||
@@ -112,17 +115,6 @@ useDeprecated(
|
||||
},
|
||||
computed(() => !!slots.title)
|
||||
)
|
||||
useDeprecated(
|
||||
{
|
||||
scope: 'el-drawer',
|
||||
from: 'custom-class',
|
||||
replacement: 'class',
|
||||
version: '2.3.0',
|
||||
ref: 'https://element-plus.org/en-US/component/drawer.html#attributes',
|
||||
type: 'Attribute',
|
||||
},
|
||||
computed(() => !!props.customClass)
|
||||
)
|
||||
|
||||
const drawerRef = ref<HTMLElement>()
|
||||
const focusStartRef = ref<HTMLElement>()
|
||||
@@ -137,6 +129,9 @@ const {
|
||||
titleId,
|
||||
bodyId,
|
||||
onModalClick,
|
||||
onOpenAutoFocus,
|
||||
onCloseAutoFocus,
|
||||
onFocusoutPrevented,
|
||||
onCloseRequested,
|
||||
handleClose,
|
||||
} = useDialog(props, drawerRef)
|
||||
|
||||
@@ -255,6 +255,13 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
const calcMenuItemWidth = (menuItem: HTMLElement) => {
|
||||
const computedStyle = getComputedStyle(menuItem)
|
||||
const marginLeft = Number.parseInt(computedStyle.marginLeft, 10)
|
||||
const marginRight = Number.parseInt(computedStyle.marginRight, 10)
|
||||
return menuItem.offsetWidth + marginLeft + marginRight || 0
|
||||
}
|
||||
|
||||
const calcSliceIndex = () => {
|
||||
if (!menu.value) return -1
|
||||
const items = Array.from(menu.value?.childNodes ?? []).filter(
|
||||
@@ -264,19 +271,14 @@ export default defineComponent({
|
||||
(item.nodeName !== '#text' || item.nodeValue)
|
||||
) as HTMLElement[]
|
||||
const moreItemWidth = 64
|
||||
const paddingLeft = Number.parseInt(
|
||||
getComputedStyle(menu.value!).paddingLeft,
|
||||
10
|
||||
)
|
||||
const paddingRight = Number.parseInt(
|
||||
getComputedStyle(menu.value!).paddingRight,
|
||||
10
|
||||
)
|
||||
const computedMenuStyle = getComputedStyle(menu.value!)
|
||||
const paddingLeft = Number.parseInt(computedMenuStyle.paddingLeft, 10)
|
||||
const paddingRight = Number.parseInt(computedMenuStyle.paddingRight, 10)
|
||||
const menuWidth = menu.value!.clientWidth - paddingLeft - paddingRight
|
||||
let calcWidth = 0
|
||||
let sliceIndex = 0
|
||||
items.forEach((item, index) => {
|
||||
calcWidth += item.offsetWidth || 0
|
||||
calcWidth += calcMenuItemWidth(item)
|
||||
if (calcWidth <= menuWidth - moreItemWidth) {
|
||||
sliceIndex = index + 1
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<div
|
||||
v-if="title !== null && title !== undefined"
|
||||
ref="headerRef"
|
||||
:class="ns.e('header')"
|
||||
:class="[ns.e('header'), { 'show-close': showClose }]"
|
||||
>
|
||||
<div :class="ns.e('title')">
|
||||
<el-icon
|
||||
@@ -178,7 +178,7 @@ import { ElIcon } from '@element-plus/components/icon'
|
||||
import ElFocusTrap from '@element-plus/components/focus-trap'
|
||||
import { useGlobalComponentSettings } from '@element-plus/components/config-provider'
|
||||
|
||||
import type { ComponentPublicInstance, DefineComponent, PropType } from 'vue'
|
||||
import type { ComponentPublicInstance, PropType } from 'vue'
|
||||
import type { ComponentSize } from '@element-plus/constants'
|
||||
import type {
|
||||
Action,
|
||||
@@ -231,6 +231,7 @@ export default defineComponent({
|
||||
},
|
||||
center: Boolean,
|
||||
draggable: Boolean,
|
||||
overflow: Boolean,
|
||||
roundButton: {
|
||||
default: false,
|
||||
type: Boolean,
|
||||
@@ -365,7 +366,8 @@ export default defineComponent({
|
||||
)
|
||||
|
||||
const draggable = computed(() => props.draggable)
|
||||
useDraggable(rootRef, headerRef, draggable)
|
||||
const overflow = computed(() => props.overflow)
|
||||
useDraggable(rootRef, headerRef, draggable, overflow)
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
@@ -499,5 +501,5 @@ export default defineComponent({
|
||||
t,
|
||||
}
|
||||
},
|
||||
}) as DefineComponent
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -102,6 +102,9 @@ export interface ElMessageBoxOptions {
|
||||
/** Whether MessageBox can be drag */
|
||||
draggable?: boolean
|
||||
|
||||
/** Draggable MessageBox can overflow the viewport */
|
||||
overflow?: boolean
|
||||
|
||||
/** Content of the MessageBox */
|
||||
message?: string | VNode | (() => VNode)
|
||||
|
||||
|
||||
@@ -358,8 +358,7 @@ const useSelect = (props: ISelectV2Props, emit) => {
|
||||
// methods
|
||||
const toggleMenu = () => {
|
||||
if (selectDisabled.value) return
|
||||
if (props.filterable && props.remote && isFunction(props.remoteMethod))
|
||||
return
|
||||
|
||||
if (states.menuVisibleOnFocus) {
|
||||
// controlled by automaticDropdown
|
||||
states.menuVisibleOnFocus = false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import { markRaw, nextTick } from 'vue'
|
||||
import { defineComponent, markRaw, nextTick } from 'vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { afterEach, describe, expect, it, test, vi } from 'vitest'
|
||||
import { EVENT_CODE } from '@element-plus/constants'
|
||||
@@ -515,6 +515,34 @@ describe('Select', () => {
|
||||
expect(wrapper.find(`.${PLACEHOLDER_CLASS_NAME}`).text()).toBe('Option D')
|
||||
})
|
||||
|
||||
test('set default value to object with value-key', async () => {
|
||||
wrapper = _mount(
|
||||
`
|
||||
<el-select v-model="value" value-key="id">
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.id"
|
||||
:label="item.label"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
`,
|
||||
() => ({
|
||||
options: [
|
||||
{ id: 1, label: 'Option A', desc: 'Option A - 230506' },
|
||||
{ id: 2, label: 'Option B', desc: 'Option B - 230506' },
|
||||
{ id: 3, label: 'Option C', desc: 'Option C - 230506' },
|
||||
{ id: 4, label: 'Option A', desc: 'Option A - 230507' },
|
||||
],
|
||||
value: { id: 3 },
|
||||
})
|
||||
)
|
||||
await nextTick()
|
||||
const options = getOptions()
|
||||
expect(wrapper.find(`.${PLACEHOLDER_CLASS_NAME}`).text()).toBe('Option C')
|
||||
expect(Array.from(options[2].classList)).toContain('is-selected')
|
||||
})
|
||||
|
||||
test('sync set value and options', async () => {
|
||||
wrapper = _mount(
|
||||
`
|
||||
@@ -1850,6 +1878,69 @@ describe('Select', () => {
|
||||
expect(vm.value).toBe('Shanghai')
|
||||
})
|
||||
|
||||
test('el-option-group should visible when el-option in a component', async () => {
|
||||
const Options = defineComponent({
|
||||
components: {
|
||||
'el-option': Option,
|
||||
},
|
||||
props: {
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
`,
|
||||
})
|
||||
|
||||
wrapper = mount({
|
||||
template: `
|
||||
<el-select v-model="value">
|
||||
<el-option-group
|
||||
v-for="group in options"
|
||||
:key="group.label"
|
||||
:label="group.label"
|
||||
>
|
||||
<Options :options="group.options" />
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
`,
|
||||
components: {
|
||||
'el-select': Select,
|
||||
'el-option-group': Group,
|
||||
Options,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
options: [
|
||||
{
|
||||
label: 'Popular cities',
|
||||
options: [
|
||||
{
|
||||
value: 'Shanghai',
|
||||
label: 'Shanghai',
|
||||
},
|
||||
{
|
||||
value: 'Beijing',
|
||||
label: 'Beijing',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.findComponent(Group).vm.visible).toBe(true)
|
||||
})
|
||||
|
||||
test('tag of disabled option is not closable', async () => {
|
||||
wrapper = _mount(
|
||||
`
|
||||
|
||||
@@ -71,6 +71,8 @@ export default defineComponent({
|
||||
children.push(child.component.proxy)
|
||||
} else if (child.children?.length) {
|
||||
children.push(...flattedChildren(child))
|
||||
} else if (child.component?.subTree) {
|
||||
children.push(...flattedChildren(child.component.subTree))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ export function useOption(props, states) {
|
||||
|
||||
// computed
|
||||
const itemSelected = computed(() => {
|
||||
if (!select.props.multiple) {
|
||||
return isEqual(props.value, select.props.modelValue)
|
||||
} else {
|
||||
if (select.props.multiple) {
|
||||
return contains(select.props.modelValue as unknown[], props.value)
|
||||
} else {
|
||||
return contains([select.props.modelValue] as unknown[], props.value)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -687,8 +687,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
|
||||
const toggleMenu = () => {
|
||||
if (selectDisabled.value) return
|
||||
if (props.filterable && props.remote && isFunction(props.remoteMethod))
|
||||
return
|
||||
|
||||
if (states.menuVisibleOnFocus) {
|
||||
// controlled by automaticDropdown
|
||||
states.menuVisibleOnFocus = false
|
||||
|
||||
@@ -362,7 +362,7 @@ export function createTablePopper(
|
||||
removePopper?.()
|
||||
},
|
||||
})
|
||||
vm.appContext = table.appContext
|
||||
vm.appContext = { ...table.appContext, ...table }
|
||||
const container = document.createElement('div')
|
||||
render(vm, container)
|
||||
vm.component!.exposed!.onOpen()
|
||||
|
||||
@@ -151,6 +151,18 @@ const Tabs = defineComponent({
|
||||
computed(() => !!props.activeName)
|
||||
)
|
||||
|
||||
useDeprecated(
|
||||
{
|
||||
from: '"addIcon"',
|
||||
replacement: '"add-icon"',
|
||||
scope: 'ElTabs',
|
||||
version: '2.6.0',
|
||||
ref: 'https://element-plus.org/en-US/component/tabs.html#slots',
|
||||
type: 'Slot',
|
||||
},
|
||||
computed(() => !!slots.addIcon)
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.activeName,
|
||||
(modelValue) => setCurrentName(modelValue)
|
||||
@@ -178,7 +190,8 @@ const Tabs = defineComponent({
|
||||
})
|
||||
|
||||
return () => {
|
||||
const addSlot = slots.addIcon
|
||||
const addSlot = slots['add-icon'] || slots['addIcon']
|
||||
const isCamelCase = addSlot && slots['addIcon']
|
||||
const newButton =
|
||||
props.editable || props.addable ? (
|
||||
<span
|
||||
@@ -190,7 +203,7 @@ const Tabs = defineComponent({
|
||||
}}
|
||||
>
|
||||
{addSlot ? (
|
||||
renderSlot(slots, 'addIcon')
|
||||
renderSlot(slots, isCamelCase ? 'addIcon' : 'add-icon')
|
||||
) : (
|
||||
<ElIcon class={ns.is('icon-plus')}>
|
||||
<Plus />
|
||||
|
||||
@@ -10,8 +10,8 @@ export const tagProps = buildProps({
|
||||
*/
|
||||
type: {
|
||||
type: String,
|
||||
values: ['success', 'info', 'warning', 'danger', ''],
|
||||
default: '',
|
||||
values: ['primary', 'success', 'info', 'warning', 'danger'],
|
||||
default: 'primary',
|
||||
},
|
||||
/**
|
||||
* @description whether Tag can be removed
|
||||
@@ -28,17 +28,13 @@ export const tagProps = buildProps({
|
||||
/**
|
||||
* @description background color of the Tag
|
||||
*/
|
||||
color: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
color: String,
|
||||
/**
|
||||
* @description size of Tag
|
||||
*/
|
||||
size: {
|
||||
type: String,
|
||||
values: componentSizes,
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description theme of Tag
|
||||
|
||||
@@ -50,7 +50,7 @@ const containerKls = computed(() => {
|
||||
return [
|
||||
ns.b(),
|
||||
ns.is('closable', closable),
|
||||
ns.m(type),
|
||||
ns.m(type || 'primary'),
|
||||
ns.m(tagSize.value),
|
||||
ns.m(effect),
|
||||
ns.is('hit', hit),
|
||||
|
||||
@@ -163,4 +163,31 @@ describe('Tour.vue', () => {
|
||||
expect(style.transform).toBe('translate3d(-50%, -50%, 0)')
|
||||
expect(style.maxWidth).toBe('100vw')
|
||||
})
|
||||
|
||||
test('button props', () => {
|
||||
mount({
|
||||
setup() {
|
||||
return () => (
|
||||
<Tour modelValue={true} current={1}>
|
||||
<TourStep title="first" description="cover description." />
|
||||
<TourStep
|
||||
title="second"
|
||||
description="cover description."
|
||||
prevButtonProps={{
|
||||
children: '上一步',
|
||||
class: 'prev-btn',
|
||||
}}
|
||||
nextButtonProps={{
|
||||
children: '下一步',
|
||||
class: 'next-btn',
|
||||
}}
|
||||
/>
|
||||
</Tour>
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
expect(document.querySelector('.prev-btn span')?.innerHTML).toBe('上一步')
|
||||
expect(document.querySelector('.next-btn span')?.innerHTML).toBe('下一步')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import {
|
||||
camelize,
|
||||
computed,
|
||||
isVNode,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
ref,
|
||||
@@ -19,7 +17,6 @@ import {
|
||||
shift,
|
||||
} from '@floating-ui/dom'
|
||||
import {
|
||||
hasOwn,
|
||||
isArray,
|
||||
isClient,
|
||||
isFunction,
|
||||
@@ -30,11 +27,9 @@ import {
|
||||
import type {
|
||||
CSSProperties,
|
||||
Component,
|
||||
ComputedRef,
|
||||
InjectionKey,
|
||||
Ref,
|
||||
SetupContext,
|
||||
VNode,
|
||||
} from 'vue'
|
||||
import type { UseNamespaceReturn } from '@element-plus/hooks'
|
||||
import type { PosInfo, TourGap, TourMask } from './types'
|
||||
@@ -45,6 +40,7 @@ import type {
|
||||
Strategy,
|
||||
VirtualElement,
|
||||
} from '@floating-ui/dom'
|
||||
import type { TourStepProps } from './step'
|
||||
|
||||
export const useTarget = (
|
||||
target: Ref<
|
||||
@@ -150,8 +146,9 @@ export const useTarget = (
|
||||
}
|
||||
|
||||
export interface TourContext {
|
||||
currentStep: Ref<TourStepProps | undefined>
|
||||
current: Ref<number>
|
||||
total: ComputedRef<number>
|
||||
total: Ref<number>
|
||||
showClose: Ref<boolean>
|
||||
closeIcon: Ref<string | Component>
|
||||
mergedType: Ref<'default' | 'primary' | undefined>
|
||||
@@ -173,51 +170,6 @@ function isInViewPort(element: HTMLElement) {
|
||||
return top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight
|
||||
}
|
||||
|
||||
const isSameProps = (a: Record<string, any>, b: Record<string, any>) => {
|
||||
if (Object.keys(a).length !== Object.keys(b).length) return false
|
||||
for (const key in a) {
|
||||
if (a[key] !== b[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export function isSameSteps(a: any[], b: any[]) {
|
||||
if (a.length !== b.length) return false
|
||||
for (const [index] of a.entries()) {
|
||||
if (isSameProps(a[index], b[index])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const getNormalizedProps = (node: VNode, booleanKeys: string[]) => {
|
||||
if (!isVNode(node)) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const raw = node.props || {}
|
||||
const type = (node.type as any)?.props || {}
|
||||
const props: Record<string, any> = {}
|
||||
Object.keys(type).forEach((key) => {
|
||||
if (hasOwn(type[key], 'default')) {
|
||||
props[key] = type[key].default
|
||||
}
|
||||
})
|
||||
|
||||
Object.keys(raw).forEach((key) => {
|
||||
const cameKey = camelize(key)
|
||||
props[cameKey] = raw[key]
|
||||
if (booleanKeys.includes(cameKey) && props[cameKey] === '') {
|
||||
props[cameKey] = true
|
||||
}
|
||||
})
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
export const useFloating = (
|
||||
referenceRef: Ref<HTMLElement | VirtualElement | null>,
|
||||
contentRef: Ref<HTMLElement | null>,
|
||||
|
||||
@@ -25,7 +25,7 @@ export const tourStepProps = buildProps({
|
||||
*/
|
||||
showClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
default: undefined,
|
||||
},
|
||||
/**
|
||||
* @description custom close icon, default is Close
|
||||
@@ -38,7 +38,7 @@ export const tourStepProps = buildProps({
|
||||
*/
|
||||
showArrow: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
default: undefined,
|
||||
},
|
||||
/**
|
||||
* @description position of the guide card relative to the target element
|
||||
@@ -49,6 +49,7 @@ export const tourStepProps = buildProps({
|
||||
*/
|
||||
mask: {
|
||||
type: definePropType<TourMask>([Boolean, Object]),
|
||||
default: undefined,
|
||||
},
|
||||
/**
|
||||
* @description custom style for content
|
||||
@@ -73,6 +74,7 @@ export const tourStepProps = buildProps({
|
||||
*/
|
||||
scrollIntoViewOptions: {
|
||||
type: definePropType<boolean | ScrollIntoViewOptions>([Boolean, Object]),
|
||||
default: undefined,
|
||||
},
|
||||
/**
|
||||
* @description type, affects the background color and text color
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<component :is="mergedCloseIcon" />
|
||||
</el-icon>
|
||||
</button>
|
||||
<header :class="ns.e('header')">
|
||||
<header :class="[ns.e('header'), { 'show-close': showClose }]">
|
||||
<slot name="header">
|
||||
<span role="heading" :class="ns.e('title')">
|
||||
{{ title }}
|
||||
@@ -43,7 +43,7 @@
|
||||
v-if="current > 0"
|
||||
size="small"
|
||||
:type="mergedType"
|
||||
v-bind="prevButtonProps"
|
||||
v-bind="filterButtonProps(prevButtonProps)"
|
||||
@click="onPrev"
|
||||
>
|
||||
{{ prevButtonProps?.children ?? t('el.tour.previous') }}
|
||||
@@ -52,13 +52,12 @@
|
||||
v-if="current <= total - 1"
|
||||
size="small"
|
||||
:type="mergedType === 'primary' ? 'default' : 'primary'"
|
||||
v-bind="nextButtonProps"
|
||||
v-bind="filterButtonProps(nextButtonProps)"
|
||||
@click="onNext"
|
||||
>
|
||||
{{
|
||||
nextButtonProps?.children ?? current === total - 1
|
||||
? t('el.tour.finish')
|
||||
: t('el.tour.next')
|
||||
nextButtonProps?.children ??
|
||||
(current === total - 1 ? t('el.tour.finish') : t('el.tour.next'))
|
||||
}}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -66,7 +65,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject } from 'vue'
|
||||
import { computed, inject, watch } from 'vue'
|
||||
import { omit } from 'lodash-es'
|
||||
import { ElButton } from '@element-plus/components/button'
|
||||
import { ElIcon } from '@element-plus/components/icon'
|
||||
import { CloseComponents } from '@element-plus/utils'
|
||||
@@ -74,6 +74,8 @@ import { useLocale } from '@element-plus/hooks'
|
||||
import { tourStepEmits, tourStepProps } from './step'
|
||||
import { tourKey } from './helper'
|
||||
|
||||
import type { TourBtnProps } from './types'
|
||||
|
||||
defineOptions({
|
||||
name: 'ElTourStep',
|
||||
})
|
||||
@@ -86,6 +88,7 @@ const { Close } = CloseComponents
|
||||
const { t } = useLocale()
|
||||
|
||||
const {
|
||||
currentStep,
|
||||
current,
|
||||
total,
|
||||
showClose,
|
||||
@@ -99,11 +102,26 @@ const {
|
||||
onChange,
|
||||
} = inject(tourKey)!
|
||||
|
||||
watch(
|
||||
props,
|
||||
(val) => {
|
||||
currentStep.value = val
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
)
|
||||
|
||||
const mergedShowClose = computed(() => props.showClose ?? showClose.value)
|
||||
const mergedCloseIcon = computed(
|
||||
() => props.closeIcon ?? closeIcon.value ?? Close
|
||||
)
|
||||
|
||||
const filterButtonProps = (btnProps?: TourBtnProps) => {
|
||||
if (!btnProps) return
|
||||
return omit(btnProps, ['children', 'onClick'])
|
||||
}
|
||||
|
||||
const onPrev = () => {
|
||||
current.value -= 1
|
||||
if (props.prevButtonProps?.onClick) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { defineComponent } from 'vue'
|
||||
import { flattedChildren, isArray } from '@element-plus/utils'
|
||||
import { getNormalizedProps, isSameSteps } from './helper'
|
||||
import type { FlattenVNodes } from '@element-plus/utils'
|
||||
import type { Component, VNode } from 'vue'
|
||||
|
||||
@@ -12,14 +11,14 @@ export default defineComponent({
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
emits: ['update-steps'],
|
||||
emits: ['update-total'],
|
||||
setup(props, { slots, emit }) {
|
||||
let cachedSteps: any[] = []
|
||||
let cacheTotal = 0
|
||||
|
||||
return () => {
|
||||
const children = slots.default?.()!
|
||||
const filteredSteps: any[] = []
|
||||
const result: VNode[] = []
|
||||
let total = 0
|
||||
|
||||
function filterSteps(children?: FlattenVNodes) {
|
||||
if (!isArray(children)) return
|
||||
@@ -27,9 +26,8 @@ export default defineComponent({
|
||||
const name = ((item?.type || {}) as Component)?.name
|
||||
|
||||
if (name === 'ElTourStep') {
|
||||
const booleanKeys = ['showArrow', 'mask', 'scrollIntoViewOptions']
|
||||
filteredSteps.push(getNormalizedProps(item, booleanKeys))
|
||||
result.push(item)
|
||||
total += 1
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -38,9 +36,9 @@ export default defineComponent({
|
||||
filterSteps(flattedChildren(children![0]?.children))
|
||||
}
|
||||
|
||||
if (!isSameSteps(filteredSteps, cachedSteps)) {
|
||||
cachedSteps = filteredSteps
|
||||
emit('update-steps', filteredSteps)
|
||||
if (cacheTotal !== total) {
|
||||
cacheTotal = total
|
||||
emit('update-total', total)
|
||||
}
|
||||
|
||||
if (result.length) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
:style="mergedContentStyle"
|
||||
@close="onEscClose"
|
||||
>
|
||||
<el-tour-steps :current="current" @update-steps="onUpdateSteps">
|
||||
<el-tour-steps :current="current" @update-total="onUpdateTotal">
|
||||
<slot />
|
||||
</el-tour-steps>
|
||||
</el-tour-content>
|
||||
@@ -39,7 +39,7 @@ import ElTourContent from './content.vue'
|
||||
import ElTourSteps from './steps'
|
||||
import { tourEmits, tourProps } from './tour'
|
||||
import { tourKey, useTarget } from './helper'
|
||||
import type { UsedTourStepProps } from './types'
|
||||
import type { TourStepProps } from './step'
|
||||
|
||||
defineOptions({
|
||||
name: 'ElTour',
|
||||
@@ -49,15 +49,14 @@ const props = defineProps(tourProps)
|
||||
const emit = defineEmits(tourEmits)
|
||||
|
||||
const ns = useNamespace('tour')
|
||||
const steps = ref<UsedTourStepProps[]>([])
|
||||
const total = ref(0)
|
||||
const currentStep = ref<TourStepProps>()
|
||||
|
||||
const current = useVModel(props, 'current', emit, {
|
||||
passive: true,
|
||||
})
|
||||
const total = computed(() => steps.value.length)
|
||||
|
||||
const currentStep = computed(() => steps.value[current.value] || {})
|
||||
const currentTarget = computed(() => currentStep.value.target)
|
||||
const currentTarget = computed(() => currentStep.value?.target)
|
||||
|
||||
const kls = computed(() => [
|
||||
ns.b(),
|
||||
@@ -65,14 +64,14 @@ const kls = computed(() => [
|
||||
])
|
||||
|
||||
const mergedPlacement = computed(
|
||||
() => currentStep.value.placement || props.placement
|
||||
() => currentStep.value?.placement || props.placement
|
||||
)
|
||||
|
||||
const mergedContentStyle = computed(
|
||||
() => currentStep.value.contentStyle ?? props.contentStyle
|
||||
() => currentStep.value?.contentStyle ?? props.contentStyle
|
||||
)
|
||||
|
||||
const mergedMask = computed(() => currentStep.value.mask ?? props.mask)
|
||||
const mergedMask = computed(() => currentStep.value?.mask ?? props.mask)
|
||||
const mergedShowMask = computed(() => !!mergedMask.value && props.modelValue)
|
||||
const mergedMaskStyle = computed(() =>
|
||||
isBoolean(mergedMask.value) ? undefined : mergedMask.value
|
||||
@@ -80,13 +79,13 @@ const mergedMaskStyle = computed(() =>
|
||||
|
||||
const mergedShowArrow = computed(
|
||||
() =>
|
||||
!!currentTarget.value && (currentStep.value.showArrow ?? props.showArrow)
|
||||
!!currentTarget.value && (currentStep.value?.showArrow ?? props.showArrow)
|
||||
)
|
||||
|
||||
const mergedScrollIntoViewOptions = computed(
|
||||
() => currentStep.value.scrollIntoViewOptions ?? props.scrollIntoViewOptions
|
||||
() => currentStep.value?.scrollIntoViewOptions ?? props.scrollIntoViewOptions
|
||||
)
|
||||
const mergedType = computed(() => currentStep.value.type ?? props.type)
|
||||
const mergedType = computed(() => currentStep.value?.type ?? props.type)
|
||||
|
||||
const { nextZIndex } = useZIndex()
|
||||
const nowZIndex = nextZIndex()
|
||||
@@ -109,10 +108,6 @@ watch(
|
||||
}
|
||||
)
|
||||
|
||||
const onUpdateSteps = (v: any) => {
|
||||
steps.value = v
|
||||
}
|
||||
|
||||
const onEscClose = () => {
|
||||
if (props.closeOnPressEscape) {
|
||||
emit('update:modelValue', false)
|
||||
@@ -120,9 +115,14 @@ const onEscClose = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const onUpdateTotal = (val: number) => {
|
||||
total.value = val
|
||||
}
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
provide(tourKey, {
|
||||
currentStep,
|
||||
current,
|
||||
total,
|
||||
showClose: toRef(props, 'showClose'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CSSProperties, VNode } from 'vue'
|
||||
import type { Placement } from '@floating-ui/dom'
|
||||
import type { ButtonProps } from '@element-plus/components/button'
|
||||
|
||||
export type TourMask =
|
||||
| boolean
|
||||
@@ -13,12 +13,11 @@ export interface TourGap {
|
||||
radius?: number
|
||||
}
|
||||
|
||||
export interface TourBtnProps {
|
||||
children: VNode | string
|
||||
onClick: () => void
|
||||
className?: string
|
||||
style?: CSSProperties
|
||||
}
|
||||
export type TourBtnProps = {
|
||||
children?: VNode | string
|
||||
onClick?: () => void
|
||||
} & Partial<ButtonProps> &
|
||||
Record<string, any>
|
||||
|
||||
export interface PosInfo {
|
||||
left: number
|
||||
@@ -27,13 +26,3 @@ export interface PosInfo {
|
||||
width: number
|
||||
radius: number
|
||||
}
|
||||
|
||||
export interface UsedTourStepProps {
|
||||
target?: string | HTMLElement | (() => HTMLElement | null) | null
|
||||
showArrow?: boolean
|
||||
placement?: Placement
|
||||
contentStyle?: CSSProperties
|
||||
mask?: TourMask
|
||||
type?: 'default' | 'primary'
|
||||
scrollIntoViewOptions?: boolean | ScrollIntoViewOptions
|
||||
}
|
||||
|
||||
@@ -536,6 +536,100 @@ describe('Tree.vue', () => {
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(0)
|
||||
})
|
||||
|
||||
test('setCheckedNodes with disabled node', async () => {
|
||||
const nodes = [
|
||||
{
|
||||
id: 1,
|
||||
label: 'Level one 1',
|
||||
children: [
|
||||
{
|
||||
id: 4,
|
||||
label: 'Level two 1-1',
|
||||
children: [
|
||||
{
|
||||
id: 9,
|
||||
label: 'Level three 1-1-1',
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
label: 'Level three 1-1-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
label: 'Level one 2',
|
||||
children: [
|
||||
{
|
||||
id: 5,
|
||||
disabled: true,
|
||||
label: 'Level two 2-1',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
label: 'Level two 2-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: 'Level one 3',
|
||||
children: [
|
||||
{
|
||||
id: 7,
|
||||
label: 'Level two 3-1',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
label: 'Level two 3-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
const wrapper = mount(
|
||||
Object.assign({
|
||||
components: {
|
||||
'el-tree': Tree,
|
||||
},
|
||||
template: `
|
||||
<el-tree ref="tree" :data="data" :props="defaultProps" default-expand-all show-checkbox node-key="id"></el-tree>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
data: nodes,
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'label',
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
)
|
||||
const treeWrapper = wrapper.findComponent(Tree)
|
||||
const treeVm = treeWrapper.vm as InstanceType<typeof Tree>
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(0)
|
||||
|
||||
function flattenTree(data) {
|
||||
const result = []
|
||||
|
||||
function flatten(node) {
|
||||
result.push(node)
|
||||
if (node?.children?.length) {
|
||||
node.children.forEach(flatten)
|
||||
}
|
||||
}
|
||||
|
||||
data.forEach(flatten)
|
||||
return result
|
||||
}
|
||||
const list = flattenTree(nodes).filter((item) => !item.disabled)
|
||||
|
||||
treeVm.setCheckedNodes(list)
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(8)
|
||||
})
|
||||
|
||||
test('setCheckedKeys', async () => {
|
||||
const { wrapper } = getTreeVm(
|
||||
`:props="defaultProps" show-checkbox node-key="id"`
|
||||
|
||||
@@ -23,6 +23,12 @@ export const uploadListProps = buildProps({
|
||||
values: uploadListTypes,
|
||||
default: 'text',
|
||||
},
|
||||
/**
|
||||
* @description set HTML attribute: crossorigin.
|
||||
*/
|
||||
crossorigin: {
|
||||
type: definePropType<'anonymous' | 'use-credentials' | ''>(String),
|
||||
},
|
||||
} as const)
|
||||
|
||||
export type UploadListProps = ExtractPropTypes<typeof uploadListProps>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"
|
||||
:class="nsUpload.be('list', 'item-thumbnail')"
|
||||
:src="file.url"
|
||||
:crossorigin="crossorigin"
|
||||
alt=""
|
||||
/>
|
||||
<div
|
||||
|
||||
@@ -253,6 +253,12 @@ export const uploadProps = buildProps({
|
||||
type: definePropType<UploadHooks['onExceed']>(Function),
|
||||
default: NOOP,
|
||||
},
|
||||
/**
|
||||
* @description set HTML attribute: crossorigin.
|
||||
*/
|
||||
crossorigin: {
|
||||
type: definePropType<'anonymous' | 'use-credentials' | ''>(String),
|
||||
},
|
||||
} as const)
|
||||
|
||||
export type UploadProps = ExtractPropTypes<typeof uploadProps>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
:disabled="disabled"
|
||||
:list-type="listType"
|
||||
:files="uploadFiles"
|
||||
:crossorigin="crossorigin"
|
||||
:handle-preview="onPreview"
|
||||
@remove="handleRemove"
|
||||
>
|
||||
@@ -35,6 +36,7 @@
|
||||
:disabled="disabled"
|
||||
:list-type="listType"
|
||||
:files="uploadFiles"
|
||||
:crossorigin="crossorigin"
|
||||
:handle-preview="onPreview"
|
||||
@remove="handleRemove"
|
||||
>
|
||||
|
||||
@@ -5,7 +5,8 @@ import type { ComputedRef, Ref } from 'vue'
|
||||
export const useDraggable = (
|
||||
targetRef: Ref<HTMLElement | undefined>,
|
||||
dragRef: Ref<HTMLElement | undefined>,
|
||||
draggable: ComputedRef<boolean>
|
||||
draggable: ComputedRef<boolean>,
|
||||
overflow?: ComputedRef<boolean>
|
||||
) => {
|
||||
let transform = {
|
||||
offsetX: 0,
|
||||
@@ -32,14 +33,13 @@ export const useDraggable = (
|
||||
const maxTop = clientHeight - targetTop - targetHeight + offsetY
|
||||
|
||||
const onMousemove = (e: MouseEvent) => {
|
||||
const moveX = Math.min(
|
||||
Math.max(offsetX + e.clientX - downX, minLeft),
|
||||
maxLeft
|
||||
)
|
||||
const moveY = Math.min(
|
||||
Math.max(offsetY + e.clientY - downY, minTop),
|
||||
maxTop
|
||||
)
|
||||
let moveX = offsetX + e.clientX - downX
|
||||
let moveY = offsetY + e.clientY - downY
|
||||
|
||||
if (!overflow?.value) {
|
||||
moveX = Math.min(Math.max(moveX, minLeft), maxLeft)
|
||||
moveY = Math.min(Math.max(moveY, minTop), maxTop)
|
||||
}
|
||||
|
||||
transform = {
|
||||
offsetX: moveX,
|
||||
|
||||
@@ -18,10 +18,15 @@
|
||||
}
|
||||
|
||||
@include when(checked) {
|
||||
background-color: getCssVar('color', 'primary', 'light-8');
|
||||
color: getCssVar('color', 'primary');
|
||||
&:hover {
|
||||
background-color: getCssVar('color', 'primary', 'light-7');
|
||||
@each $type in $types {
|
||||
&.#{bem('check-tag', '', $type)} {
|
||||
background-color: getCssVar('color', $type, 'light-8');
|
||||
color: getCssVar('color', $type);
|
||||
|
||||
&:hover {
|
||||
background-color: getCssVar('color', $type, 'light-7');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,11 +516,13 @@ $messagebox: map.merge(
|
||||
'title-color': getCssVar('text-color-primary'),
|
||||
'width': 420px,
|
||||
'border-radius': 4px,
|
||||
'box-shadow': getCssVar('box-shadow'),
|
||||
'font-size': getCssVar('font-size-large'),
|
||||
'content-font-size': getCssVar('font-size-base'),
|
||||
'content-color': getCssVar('text-color-regular'),
|
||||
'error-font-size': 12px,
|
||||
'padding-primary': 15px,
|
||||
'padding-primary': 12px,
|
||||
'font-line-height': getCssVar('font-line-height-primary'),
|
||||
),
|
||||
$messagebox
|
||||
);
|
||||
@@ -786,7 +788,7 @@ $dialog: map.merge(
|
||||
'title-font-size': getCssVar('font-size-large'),
|
||||
'content-font-size': 14px,
|
||||
'font-line-height': getCssVar('font-line-height-primary'),
|
||||
'padding-primary': 20px,
|
||||
'padding-primary': 16px,
|
||||
'border-radius': getCssVar('border-radius-small'),
|
||||
),
|
||||
$dialog
|
||||
@@ -798,16 +800,16 @@ $tour: () !default;
|
||||
$tour: map.merge(
|
||||
(
|
||||
'width': 520px,
|
||||
'padding-primary': 16px,
|
||||
'padding-primary': 12px,
|
||||
'font-line-height': getCssVar('font-line-height-primary'),
|
||||
'title-font-size': 16px,
|
||||
'title-text-color': getCssVar('text-color-primary'),
|
||||
'title-font-weight': 400,
|
||||
'close-color': getCssVar('color-info'),
|
||||
'font-size': 14px,
|
||||
'color': getCssVar('text-color-primary'),
|
||||
'bg-color': getCssVar('bg-color'),
|
||||
'border-radius': 4px,
|
||||
'border-color': getCssVar('border-color-lighter'),
|
||||
),
|
||||
$tour
|
||||
);
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
border-radius: getCssVar('dialog', 'border-radius');
|
||||
box-shadow: getCssVar('dialog', 'box-shadow');
|
||||
box-sizing: border-box;
|
||||
padding: getCssVar('dialog', 'padding-primary');
|
||||
width: var(#{getCssVarName('dialog-width')}, 50%);
|
||||
overflow-wrap: break-word;
|
||||
|
||||
&:focus {
|
||||
outline: none !important;
|
||||
@@ -52,18 +54,23 @@
|
||||
}
|
||||
|
||||
@include e(header) {
|
||||
padding: getCssVar('dialog', 'padding-primary');
|
||||
padding-bottom: 10px;
|
||||
margin-right: 16px;
|
||||
padding-bottom: getCssVar('dialog', 'padding-primary');
|
||||
|
||||
&.show-close {
|
||||
padding-right: calc(getCssVar('dialog', 'padding-primary') + var(
|
||||
#{getCssVarName('message-close-size')},
|
||||
map.get($message, 'close-size')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@include e(headerbtn) {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 0;
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
@@ -93,15 +100,12 @@
|
||||
}
|
||||
|
||||
@include e(body) {
|
||||
padding: calc(#{getCssVar('dialog-padding-primary')} + 10px)
|
||||
getCssVar('dialog-padding-primary');
|
||||
color: getCssVar('text-color', 'regular');
|
||||
font-size: getCssVar('dialog-content-font-size');
|
||||
}
|
||||
|
||||
@include e(footer) {
|
||||
padding: getCssVar('dialog-padding-primary');
|
||||
padding-top: 10px;
|
||||
padding-top: getCssVar('dialog', 'padding-primary');
|
||||
text-align: right;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -112,7 +116,6 @@
|
||||
|
||||
@include e(body) {
|
||||
text-align: initial;
|
||||
padding: 25px calc(#{getCssVar('dialog-padding-primary')} + 5px) 30px;
|
||||
}
|
||||
|
||||
@include e(footer) {
|
||||
|
||||
@@ -11,20 +11,21 @@
|
||||
|
||||
@include b(message-box) {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
max-width: getCssVar('messagebox-width');
|
||||
width: 100%;
|
||||
padding-bottom: 10px;
|
||||
padding: getCssVar('messagebox-padding-primary');
|
||||
vertical-align: middle;
|
||||
background-color: getCssVar('bg-color');
|
||||
border-radius: getCssVar('messagebox-border-radius');
|
||||
border: 1px solid getCssVar('border-color-lighter');
|
||||
font-size: getCssVar('messagebox-font-size');
|
||||
box-shadow: getCssVar('box-shadow-light');
|
||||
box-shadow: getCssVar('messagebox-box-shadow');
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
backface-visibility: hidden;
|
||||
// To avoid small screen overflowing, see #11919
|
||||
box-sizing: border-box;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
&:focus {
|
||||
outline: none !important;
|
||||
@@ -59,24 +60,29 @@
|
||||
}
|
||||
|
||||
@include e(header) {
|
||||
position: relative;
|
||||
padding: getCssVar('messagebox-padding-primary');
|
||||
padding-bottom: 10px;
|
||||
padding-bottom: getCssVar('messagebox-padding-primary');
|
||||
|
||||
&.show-close {
|
||||
padding-right: calc(getCssVar('messagebox-padding-primary') + var(
|
||||
#{getCssVarName('message-close-size')},
|
||||
map.get($message, 'close-size')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@include e(title) {
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
font-size: getCssVar('messagebox-font-size');
|
||||
line-height: 1;
|
||||
line-height: getCssVar('messagebox-font-line-height');
|
||||
color: getCssVar('messagebox-title-color');
|
||||
}
|
||||
|
||||
@include e(headerbtn) {
|
||||
position: absolute;
|
||||
top: getCssVar('messagebox-padding-primary');
|
||||
right: getCssVar('messagebox-padding-primary');
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
@@ -100,17 +106,18 @@
|
||||
}
|
||||
|
||||
@include e(content) {
|
||||
padding: 10px getCssVar('messagebox-padding-primary');
|
||||
color: getCssVar('messagebox-content-color');
|
||||
font-size: getCssVar('messagebox-content-font-size');
|
||||
}
|
||||
|
||||
@include e(container) {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
@include e(input) {
|
||||
padding-top: 15px;
|
||||
padding-top: 12px;
|
||||
|
||||
& div.invalid > input {
|
||||
border-color: getCssVar('color-error');
|
||||
@@ -122,26 +129,7 @@
|
||||
}
|
||||
|
||||
@include e(status) {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 24px !important;
|
||||
|
||||
&::before {
|
||||
// 防止图标切割
|
||||
padding-left: 1px;
|
||||
}
|
||||
|
||||
&.#{$namespace}-icon {
|
||||
// 防止 el-icon 的position样式覆盖
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
+ .#{$namespace}-message-box__message {
|
||||
padding-left: 36px;
|
||||
padding-right: 12px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
font-size: 24px;
|
||||
|
||||
@each $type in (success, info, warning, error) {
|
||||
&.#{$namespace}-message-box-icon--#{$type} {
|
||||
@@ -156,67 +144,43 @@
|
||||
|
||||
& p {
|
||||
margin: 0;
|
||||
line-height: 24px;
|
||||
line-height: getCssVar('messagebox-font-line-height');
|
||||
}
|
||||
}
|
||||
|
||||
@include e(errormsg) {
|
||||
color: getCssVar('color-error');
|
||||
font-size: getCssVar('messagebox-error-font-size');
|
||||
min-height: 18px;
|
||||
margin-top: 2px;
|
||||
line-height: getCssVar('messagebox-font-line-height');
|
||||
}
|
||||
|
||||
@include e(btns) {
|
||||
padding: 5px 15px 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
& button:nth-child(2) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(btns-reverse) {
|
||||
flex-direction: row-reverse;
|
||||
padding-top: getCssVar('messagebox-padding-primary');
|
||||
}
|
||||
|
||||
// centerAlign 布局
|
||||
@include m(center) {
|
||||
@include e(title) {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
@include e(status) {
|
||||
position: relative;
|
||||
top: auto;
|
||||
padding-right: 5px;
|
||||
text-align: center;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
@include e(message) {
|
||||
margin-left: 0;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
@include e(btns) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@include e(content) {
|
||||
$padding-horizontal: calc(
|
||||
#{getCssVar('messagebox', 'padding-primary')} + 12px
|
||||
);
|
||||
|
||||
padding-left: $padding-horizontal;
|
||||
padding-right: $padding-horizontal;
|
||||
|
||||
text-align: center;
|
||||
@include e(container) {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ $tag-icon-span-gap: map.merge(
|
||||
@include b(tag) {
|
||||
@include genTheme('light-9', 'light-8', '');
|
||||
|
||||
@include css-var-from-global(('tag', 'text-color'), ('color', 'primary'));
|
||||
@each $type in $types {
|
||||
&.#{bem('tag', '', $type)} {
|
||||
@include css-var-from-global(('tag', 'text-color'), ('color', $type));
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
}
|
||||
|
||||
@include e(content) {
|
||||
padding: 0;
|
||||
border-radius: getCssVar('tour-border-radius');
|
||||
border: 1px solid getCssVar('tour-border-color');
|
||||
width: var(#{getCssVarName('tour-width')});
|
||||
padding: getCssVar('tour-padding-primary');
|
||||
background: getCssVar('tour-bg-color');
|
||||
box-shadow: getCssVar('box-shadow-light');
|
||||
box-sizing: border-box;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
$content-selector: &;
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
@include e(arrow) {
|
||||
position: absolute;
|
||||
background: getCssVar('tour-bg-color');
|
||||
border: 1px solid getCssVar('tour-border-color');
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
pointer-events: none;
|
||||
@@ -63,11 +62,11 @@
|
||||
|
||||
@include e(closebtn) {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 0;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
@@ -78,7 +77,7 @@
|
||||
);
|
||||
|
||||
.#{$namespace}-tour__close {
|
||||
color: getCssVar('tour-title-text-color');
|
||||
color: getCssVar('tour-close-color');
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
@@ -91,9 +90,14 @@
|
||||
}
|
||||
|
||||
@include e(header) {
|
||||
padding: getCssVar('tour', 'padding-primary');
|
||||
padding-bottom: 10px;
|
||||
margin-right: 16px;
|
||||
padding-bottom: getCssVar('tour-padding-primary');
|
||||
|
||||
&.show-close {
|
||||
padding-right: calc(getCssVar('tour-padding-primary') + var(
|
||||
#{getCssVarName('message-close-size')},
|
||||
map.get($message, 'close-size')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@include e(title) {
|
||||
@@ -104,7 +108,6 @@
|
||||
}
|
||||
|
||||
@include e(body) {
|
||||
padding: 0 getCssVar('tour-padding-primary');
|
||||
color: getCssVar('tour-text-color');
|
||||
font-size: getCssVar('tour-font-size');
|
||||
img,
|
||||
@@ -114,8 +117,7 @@
|
||||
}
|
||||
|
||||
@include e(footer) {
|
||||
padding: getCssVar('tour-padding-primary');
|
||||
padding-top: 10px;
|
||||
padding-top: getCssVar('tour-padding-primary');
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -144,6 +146,7 @@
|
||||
@include set-css-var-value('tour-title-text-color', #fff);
|
||||
@include set-css-var-value('tour-text-color', #fff);
|
||||
@include set-css-var-value('tour-bg-color', getCssVar('color', 'primary'));
|
||||
@include set-css-var-value('tour-close-color', #fff);
|
||||
|
||||
.#{$namespace}-tour__closebtn {
|
||||
&:focus,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<template>
|
||||
<!-- If you want to apply a custom namespace, uncomment the following and apply the css configuration in `vite.config.ts`. -->
|
||||
<!-- <el-config-provider namespace="ep"> -->
|
||||
<div class="play-container">
|
||||
<el-icon color="#409EFC">
|
||||
<el-icon-check />
|
||||
@@ -9,6 +11,7 @@
|
||||
<el-button>test</el-button>
|
||||
<div v-loading="true" />
|
||||
</div>
|
||||
<!-- </el-config-provider> -->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -21,9 +24,11 @@ body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
|
||||
#play {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
.play-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
3
play/styles/custom.scss
Normal file
3
play/styles/custom.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
@forward '@element-plus/theme-chalk/src/mixins/config.scss' with (
|
||||
$namespace: 'ep'
|
||||
);
|
||||
@@ -40,6 +40,13 @@ export default defineConfig(async ({ mode }) => {
|
||||
).map((dep) => dep.replace(/\.js$/, ''))
|
||||
|
||||
return {
|
||||
// css: {
|
||||
// preprocessorOptions: {
|
||||
// scss: {
|
||||
// additionalData: `@use "/styles/custom.scss" as *;`,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
resolve: {
|
||||
alias: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user