mirror of
https://github.com/element-plus/element-plus.git
synced 2025-04-06 16:30:35 +08:00
commit
46abc4f6d1
11
.github/workflows/publish-pr-commit-pkg.yml
vendored
11
.github/workflows/publish-pr-commit-pkg.yml
vendored
@ -1,11 +1,11 @@
|
||||
name: Publish PR Commit Pkg
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
tags:
|
||||
- '!**'
|
||||
# push:
|
||||
# branches:
|
||||
# - dev
|
||||
# tags:
|
||||
# - '!**'
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
@ -13,6 +13,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'element-plus/element-plus' }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
@ -1,5 +1,34 @@
|
||||
## Changelog
|
||||
|
||||
|
||||
### 2.9.2
|
||||
|
||||
_2025-01-03_
|
||||
|
||||
#### Features
|
||||
|
||||
- Components [select-v2] add `fit-input-width` prop (#18834 by @YiMo1)
|
||||
- Components [select, select-v2] add loading class to validateIcon (#19379 by @LoTwT)
|
||||
- Components [table] add allow-drag-last-column prop (#19374 by @btea)
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- Components [select] resolve 'false' display issue when dropdown hides on search clear (#19244 by @DDDDD12138)
|
||||
- Components [date-picker] model-value unexpected changes when type is week (#16795 by @FrontEndDog)
|
||||
- Components [menu] fix `sliceIndex` calculation error (#19164 by @wen-lun)
|
||||
- Components [anchor] scroll whether link is selected at the top (#18047 by @k983551019)
|
||||
- Components [focus-trap] tryFocus is invalid for document.body (#19272 by @tolking)
|
||||
- Components [inputnumber, input] resolve styling issues caused by using `prefix` and `suffix` (#19042 by @DDDDD12138)
|
||||
- Components [color-picker] optimize the flickering issue (#18872 by @momei-LJM)
|
||||
- Theme-chalk [input-tag] correct input-tag placeholder color (#19386 by @DDDDD12138)
|
||||
- Components prevent blur event when is disabled (#19320 by @DDDDD12138)
|
||||
- Types packing unexpected types (#19419 by @btea)
|
||||
- Components [table] the overflowTooltip cannot be refreshed (#19440 by @xingyixiang)
|
||||
- Components [upload] unable to delete files in removeFile (#19437 by @ly-yewu)
|
||||
- Components [page-header] use `$slots` instead of `useSlots` (#19455 by @Dsaquel)
|
||||
- Components [select] input width fills the remaining width (#19292 by @tolking)
|
||||
- Style(components): [notification] word wrap (#17052 by @Liao-js)
|
||||
- Perf(components): [table] prioritize use rowKey to determine whether it is selected (#19451 by @tolking)
|
||||
|
||||
### 2.9.1
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { isExternal } from 'vitepress/dist/client/shared'
|
||||
import { ensureLang } from '../utils/lang'
|
||||
import navLocale from '../i18n/pages/sidebar.json'
|
||||
|
||||
@ -12,7 +13,7 @@ function getNav() {
|
||||
activeMatch?: string
|
||||
}[] = Object.values(locales).map((item) => ({
|
||||
...item,
|
||||
link: `${ensureLang(lang)}${item.link}`,
|
||||
link: `${isExternal(item.link) ? '' : ensureLang(lang)}${item.link}`,
|
||||
}))
|
||||
|
||||
return [lang, item]
|
||||
|
@ -13,5 +13,9 @@
|
||||
"text": "Resource",
|
||||
"link": "/resource/index",
|
||||
"activeMatch": "/resource/"
|
||||
},
|
||||
{
|
||||
"text": "Playground",
|
||||
"link": "https://element-plus.run"
|
||||
}
|
||||
]
|
||||
|
@ -10,7 +10,7 @@ const sponsor = computed(() => sponsorLocale[lang.value])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page-sidebar-table">
|
||||
<div class="page-sidebar-panel">
|
||||
<p class="title">{{ sponsor.sponsoredBy }}</p>
|
||||
<VPSponsorLarge />
|
||||
<VPSponsorSmall />
|
||||
@ -18,7 +18,7 @@ const sponsor = computed(() => sponsorLocale[lang.value])
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-sidebar-table {
|
||||
.page-sidebar-panel {
|
||||
padding-bottom: 10px;
|
||||
padding-top: 0;
|
||||
.title {
|
||||
|
@ -77,15 +77,16 @@ anchor/affix
|
||||
|
||||
### Anchor Attributes
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| --------- | ---------------------------------------------------------- | -------------------------------------- | ---------- |
|
||||
| container | scroll container. | `string` \| `HTMLElement` \| `Window ` | — |
|
||||
| offset | set the offset of the anchor scroll. | `number` | 0 |
|
||||
| bound | the offset of the element starting to trigger the anchor. | `number` | 15 |
|
||||
| duration | set the scroll duration of the container, in milliseconds. | `number` | 300 |
|
||||
| marker | whether to show the marker. | ^[boolean] | true |
|
||||
| type | set Anchor type. | ^[enum]`'default' \| 'underline'` | `default` |
|
||||
| direction | Set Anchor direction. | ^[enum]`'vertical' \| 'horizontal'` | `vertical` |
|
||||
| Property | Description | Type | Default |
|
||||
| -------------------------- | ---------------------------------------------------------- | -------------------------------------- | ---------- |
|
||||
| container | scroll container. | `string` \| `HTMLElement` \| `Window ` | — |
|
||||
| offset | set the offset of the anchor scroll. | `number` | 0 |
|
||||
| bound | the offset of the element starting to trigger the anchor. | `number` | 15 |
|
||||
| duration | set the scroll duration of the container, in milliseconds. | `number` | 300 |
|
||||
| marker | whether to show the marker. | ^[boolean] | true |
|
||||
| type | set Anchor type. | ^[enum]`'default' \| 'underline'` | `default` |
|
||||
| direction | Set Anchor direction. | ^[enum]`'vertical' \| 'horizontal'` | `vertical` |
|
||||
| select-scroll-top ^(2.9.2) | scroll whether link is selected at the top | ^[boolean] | false |
|
||||
|
||||
### Anchor Events
|
||||
|
||||
|
@ -105,6 +105,42 @@ When using `modal` = false, please make sure that `append-to-body` was set to **
|
||||
|
||||
:::
|
||||
|
||||
## Fullscreen
|
||||
|
||||
Set the `fullscreen` attribute to open fullscreen dialog.
|
||||
|
||||
:::demo
|
||||
|
||||
dialog/fullscreen
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
If `fullscreen` is true, `width` `top` `draggable` attributes don't work.
|
||||
|
||||
:::
|
||||
|
||||
## Modal
|
||||
|
||||
Setting `modal` to `false` will hide modal (overlay) of dialog.
|
||||
|
||||
:::demo
|
||||
|
||||
dialog/modal
|
||||
|
||||
:::
|
||||
|
||||
## Events
|
||||
|
||||
Open developer console (ctrl + shift + J), to see order of events.
|
||||
|
||||
:::demo
|
||||
|
||||
dialog/events
|
||||
|
||||
:::
|
||||
|
||||
## API
|
||||
|
||||
### Attributes
|
||||
@ -147,7 +183,7 @@ When using `modal` = false, please make sure that `append-to-body` was set to **
|
||||
|
||||
| Name | Description |
|
||||
| ------------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| — | content of Dialog |
|
||||
| default | default content of Dialog |
|
||||
| header | content of the Dialog header; Replacing this removes the title, but does not remove the close button. |
|
||||
| footer | content of the Dialog footer |
|
||||
| title ^(deprecated) | works the same as the header slot. Use that instead. |
|
||||
|
@ -168,6 +168,7 @@ The corresponding methods are: `ElMessageBox`, `ElMessageBox.alert`, `ElMessageB
|
||||
| icon | custom icon component, overrides `type` | ^[string] / ^[Component] | '' |
|
||||
| customClass | custom class name for MessageBox | ^[string] | '' |
|
||||
| customStyle | custom inline style for MessageBox | ^[CSSProperties] | {} |
|
||||
| modalClass | custom class names for mask | string | — |
|
||||
| callback | MessageBox closing callback if you don't prefer Promise | ^[Function]`(value: string, action: Action) => any \| (action: Action) => any` | null |
|
||||
| showClose | whether to show close icon of MessageBox | ^[boolean] | true |
|
||||
| beforeClose | callback before MessageBox closes, and it will prevent MessageBox from closing | ^[Function]`(action: Action, instance: MessageBoxState, done: () => void) => void` | null |
|
||||
|
@ -213,6 +213,16 @@ select-v2/custom-label
|
||||
|
||||
:::
|
||||
|
||||
## Custom Width ^(2.9.2)
|
||||
|
||||
The width of dropdown box is calculated by default based on the value of `label`. If you customize the dropdown box options through the `default slot`, it is likely that the text displayed in the options is not equal to the value of `label`, resulting in calculation errors. In this case, you can set the `fit-input-width` attribute to a number to fix its width.
|
||||
|
||||
:::demo
|
||||
|
||||
select-v2/custom-width
|
||||
|
||||
:::
|
||||
|
||||
## API
|
||||
|
||||
### Attributes
|
||||
@ -248,6 +258,7 @@ select-v2/custom-label
|
||||
| persistent | when select dropdown is inactive and `persistent` is `false`, select dropdown will be destroyed | ^[boolean] | true |
|
||||
| popper-options | [popper.js](https://popper.js.org/docs/v2/) parameters | ^[object]refer to [popper.js](https://popper.js.org/docs/v2/) doc | {} |
|
||||
| automatic-dropdown | for non-filterable Select, this prop decides if the option menu pops up when the input is focused | ^[boolean] | false |
|
||||
| fit-input-width ^(2.9.2) | whether the width of the dropdown is the same as the input, if the value is `number`, then the width is fixed | ^[boolean] / ^[number] | true |
|
||||
| height | The height of the dropdown panel, 34px for each item | ^[number] | 274 |
|
||||
| item-height | The height of the dropdown item | ^[number] | 34 |
|
||||
| scrollbar-always-on | Controls whether the scrollbar is always displayed | ^[boolean] | false |
|
||||
|
@ -289,6 +289,7 @@ table/table-layout
|
||||
| show-overflow-tooltip | whether to hide extra content and show them in a tooltip when hovering on the cell.It will affect all the table columns, refer to table [tooltip-options](#table-attributes) | ^[boolean] / [`object`](#table-attributes) ^(2.3.7) | — |
|
||||
| flexible ^(2.2.1) | ensure main axis minimum-size doesn't follow the content | ^[boolean] | false |
|
||||
| scrollbar-tabindex ^(2.8.3) | body scrollbar's wrap container tabindex | ^[string] / ^[number] | — |
|
||||
| allow-drag-last-column ^(2.9.2) | whether to allow drag the last column | ^[boolean] | true |
|
||||
|
||||
### Table Events
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<el-config-provider :value-on-clear="null" :empty-values="[undefined, null]">
|
||||
<el-config-provider
|
||||
:value-on-clear="() => null"
|
||||
:empty-values="[undefined, null]"
|
||||
>
|
||||
<div class="flex flex-wrap gap-4 items-center">
|
||||
<el-select
|
||||
v-model="value1"
|
||||
|
37
docs/examples/dialog/events.vue
Normal file
37
docs/examples/dialog/events.vue
Normal file
@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<el-button plain @click="dialogVisible = true">
|
||||
Open the event Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
modal-class="overide-animation"
|
||||
:before-close="
|
||||
(doneFn) => {
|
||||
console.log('before-close'), doneFn()
|
||||
}
|
||||
"
|
||||
@open="console.log('open')"
|
||||
@open-auto-focus="console.log('open-auto-focus')"
|
||||
@opened="console.log('opened')"
|
||||
@close="console.log('close')"
|
||||
@close-auto-focus="console.log('close-auto-focus')"
|
||||
@closed="console.log('closed')"
|
||||
>
|
||||
<span>It's a event Dialog</span>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
</script>
|
29
docs/examples/dialog/fullscreen.vue
Normal file
29
docs/examples/dialog/fullscreen.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<el-button plain @click="dialogVisible = true">
|
||||
Open the fullscreen Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
fullscreen
|
||||
top="40vh"
|
||||
width="70%"
|
||||
draggable
|
||||
>
|
||||
<span>It's a fullscreen Dialog</span>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
</script>
|
23
docs/examples/dialog/modal.vue
Normal file
23
docs/examples/dialog/modal.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<el-button plain @click="dialogVisible = true">
|
||||
Open the modal Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :modal="false">
|
||||
<span>It's a modal Dialog</span>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false">
|
||||
Confirm
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
</script>
|
@ -1,39 +1,73 @@
|
||||
<template>
|
||||
<el-row>
|
||||
<el-col :span="24"><div class="grid-content ep-bg-purple-dark" /></el-col>
|
||||
<el-col :span="24">
|
||||
<div class="grid-content ep-bg-purple-dark" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12"><div class="grid-content ep-bg-purple" /></el-col>
|
||||
<el-col :span="12"><div class="grid-content ep-bg-purple-light" /></el-col>
|
||||
<el-col :span="12">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="grid-content ep-bg-purple-light" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="8"><div class="grid-content ep-bg-purple" /></el-col>
|
||||
<el-col :span="8"><div class="grid-content ep-bg-purple-light" /></el-col>
|
||||
<el-col :span="8"><div class="grid-content ep-bg-purple" /></el-col>
|
||||
<el-col :span="8">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="grid-content ep-bg-purple-light" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="6"><div class="grid-content ep-bg-purple" /></el-col>
|
||||
<el-col :span="6"><div class="grid-content ep-bg-purple-light" /></el-col>
|
||||
<el-col :span="6"><div class="grid-content ep-bg-purple" /></el-col>
|
||||
<el-col :span="6"><div class="grid-content ep-bg-purple-light" /></el-col>
|
||||
<el-col :span="6">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="grid-content ep-bg-purple-light" />
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="grid-content ep-bg-purple-light" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="4"><div class="grid-content ep-bg-purple" /></el-col>
|
||||
<el-col :span="4"><div class="grid-content ep-bg-purple-light" /></el-col>
|
||||
<el-col :span="4"><div class="grid-content ep-bg-purple" /></el-col>
|
||||
<el-col :span="4"><div class="grid-content ep-bg-purple-light" /></el-col>
|
||||
<el-col :span="4"><div class="grid-content ep-bg-purple" /></el-col>
|
||||
<el-col :span="4"><div class="grid-content ep-bg-purple-light" /></el-col>
|
||||
<el-col :span="4">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="grid-content ep-bg-purple-light" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="grid-content ep-bg-purple-light" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="grid-content ep-bg-purple" />
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="grid-content ep-bg-purple-light" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
<style>
|
||||
.el-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.el-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.el-col {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-segmented v-model="value" :options="options">
|
||||
<template #default="{ item }">
|
||||
<template #default="scope">
|
||||
<div class="flex flex-col items-center gap-2 p-2">
|
||||
<el-icon size="20">
|
||||
<component :is="item.icon" />
|
||||
<component :is="scope.item.icon" />
|
||||
</el-icon>
|
||||
<div>{{ item.label }}</div>
|
||||
<div>{{ scope.item.label }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-segmented>
|
||||
|
@ -18,7 +18,7 @@
|
||||
:direction="direction"
|
||||
:size="size"
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<template #default="scope">
|
||||
<div
|
||||
:class="[
|
||||
'flex',
|
||||
@ -29,9 +29,9 @@
|
||||
]"
|
||||
>
|
||||
<el-icon size="20">
|
||||
<component :is="item.icon" />
|
||||
<component :is="scope.item.icon" />
|
||||
</el-icon>
|
||||
<div>{{ item.label }}</div>
|
||||
<div>{{ scope.item.label }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-segmented>
|
||||
|
@ -68,7 +68,7 @@ const clear = () => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style>
|
||||
.select-footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -60,7 +60,7 @@ const handleCheckAll = (val: CheckboxValueType) => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style>
|
||||
.custom-header {
|
||||
.el-checkbox {
|
||||
display: flex;
|
||||
|
43
docs/examples/select-v2/custom-width.vue
Normal file
43
docs/examples/select-v2/custom-width.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap gap-4 items-center">
|
||||
<el-select-v2
|
||||
v-model="value"
|
||||
:options="options"
|
||||
placeholder="Please select"
|
||||
style="width: 240px"
|
||||
:fit-input-width="false"
|
||||
/>
|
||||
|
||||
<el-select-v2
|
||||
v-model="value"
|
||||
:options="options"
|
||||
placeholder="Please select"
|
||||
style="width: 240px"
|
||||
fit-input-width
|
||||
/>
|
||||
|
||||
<el-select-v2
|
||||
v-model="value"
|
||||
:options="options"
|
||||
placeholder="Please select"
|
||||
style="width: 240px"
|
||||
:fit-input-width="440"
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<span>{{ item.value + item.label }}</span>
|
||||
</template>
|
||||
</el-select-v2>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const initials = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
|
||||
|
||||
const value = ref()
|
||||
const options = Array.from({ length: 1000 }).map((_, idx) => ({
|
||||
value: `Option ${idx + 1}`,
|
||||
label: `${initials[idx % 10]}${idx}${'-'.repeat(Math.ceil(idx / 25))}`,
|
||||
}))
|
||||
</script>
|
@ -81,7 +81,7 @@ const clear = () => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style>
|
||||
.option-input {
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
|
@ -84,7 +84,7 @@ const handleCheckAll = (val: CheckboxValueType) => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
<style>
|
||||
.custom-header {
|
||||
.el-checkbox {
|
||||
display: flex;
|
||||
|
@ -2,6 +2,7 @@
|
||||
<el-table
|
||||
ref="multipleTableRef"
|
||||
:data="tableData"
|
||||
row-key="id"
|
||||
style="width: 100%"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
|
@ -20,7 +20,7 @@
|
||||
"nprogress": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@crowdin/cli": "^3.7.10",
|
||||
"@crowdin/cli": "^4.5.0",
|
||||
"@docsearch/react": "^3.1.0",
|
||||
"@element-plus/build": "workspace:*",
|
||||
"@element-plus/build-constants": "workspace:*",
|
||||
|
@ -60,6 +60,13 @@ export const anchorProps = buildProps({
|
||||
type: definePropType<'vertical' | 'horizontal'>(String),
|
||||
default: 'vertical',
|
||||
},
|
||||
/**
|
||||
* @description Scroll whether link is selected at the top
|
||||
*/
|
||||
selectScrollTop: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
export type AnchorProps = ExtractPropTypes<typeof anchorProps>
|
||||
|
@ -134,13 +134,12 @@ const getCurrentHref = () => {
|
||||
})
|
||||
}
|
||||
anchorTopList.sort((prev, next) => prev.top - next.top)
|
||||
|
||||
for (let i = 0; i < anchorTopList.length; i++) {
|
||||
const item = anchorTopList[i]
|
||||
const next = anchorTopList[i + 1]
|
||||
|
||||
if (i === 0 && scrollTop === 0) {
|
||||
return ''
|
||||
return props.selectScrollTop ? item.href : ''
|
||||
}
|
||||
if (item.top <= scrollTop && (!next || next.top > scrollTop)) {
|
||||
return item.href
|
||||
|
@ -129,7 +129,7 @@ import { useFormDisabled } from '@element-plus/components/form'
|
||||
import { autocompleteEmits, autocompleteProps } from './autocomplete'
|
||||
import type { AutocompleteData } from './autocomplete'
|
||||
|
||||
import type { StyleValue } from 'vue'
|
||||
import type { Ref, StyleValue } from 'vue'
|
||||
import type { TooltipInstance } from '@element-plus/components/tooltip'
|
||||
import type { InputInstance } from '@element-plus/components/input'
|
||||
|
||||
@ -377,7 +377,21 @@ onMounted(() => {
|
||||
readonly = (inputRef.value as any).ref!.hasAttribute('readonly')
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
defineExpose<{
|
||||
highlightedIndex: Ref<number>
|
||||
activated: Ref<boolean>
|
||||
loading: Ref<boolean>
|
||||
inputRef: Ref<InputInstance | undefined>
|
||||
popperRef: Ref<TooltipInstance | undefined>
|
||||
suggestions: Ref<AutocompleteData>
|
||||
handleSelect: (item: any) => void
|
||||
handleKeyEnter: () => void
|
||||
focus: () => void
|
||||
blur: () => void
|
||||
close: () => void
|
||||
highlight: (index: number) => void
|
||||
getData: (queryString: string) => void
|
||||
}>({
|
||||
/** @description the index of the currently highlighted item */
|
||||
highlightedIndex,
|
||||
/** @description autocomplete whether activated */
|
||||
|
@ -16,7 +16,10 @@
|
||||
@hide="setShowPicker(false)"
|
||||
>
|
||||
<template #content>
|
||||
<div v-click-outside="handleClickOutside" @keydown.esc="handleEsc">
|
||||
<div
|
||||
v-click-outside:[triggerRef]="handleClickOutside"
|
||||
@keydown.esc="handleEsc"
|
||||
>
|
||||
<div :class="ns.be('dropdown', 'main-wrapper')">
|
||||
<hue-slider ref="hue" class="hue-slider" :color="color" vertical />
|
||||
<sv-panel ref="sv" :color="color" />
|
||||
@ -245,7 +248,6 @@ function setShowPicker(value: boolean) {
|
||||
}
|
||||
|
||||
const debounceSetShowPicker = debounce(setShowPicker, 100, { leading: true })
|
||||
|
||||
function show() {
|
||||
if (colorDisabled.value) return
|
||||
setShowPicker(true)
|
||||
@ -271,6 +273,9 @@ function resetColor() {
|
||||
|
||||
function handleTrigger() {
|
||||
if (colorDisabled.value) return
|
||||
if (showPicker.value) {
|
||||
resetColor()
|
||||
}
|
||||
debounceSetShowPicker(!showPicker.value)
|
||||
}
|
||||
|
||||
|
@ -659,12 +659,17 @@ const getDefaultValue = () => {
|
||||
return parseDate
|
||||
}
|
||||
|
||||
const handleFocusPicker = async () => {
|
||||
const handleFocusPicker = () => {
|
||||
if (['week', 'month', 'year', 'date'].includes(selectionMode.value)) {
|
||||
currentViewRef.value?.focus()
|
||||
if (selectionMode.value === 'week') {
|
||||
handleKeyControl(EVENT_CODE.down)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const _handleFocusPicker = () => {
|
||||
handleFocusPicker()
|
||||
// TODO: After focus the date input, the first time you use the ArrowDown keys, you cannot focus on the date cell
|
||||
if (selectionMode.value === 'week') {
|
||||
handleKeyControl(EVENT_CODE.down)
|
||||
}
|
||||
}
|
||||
|
||||
@ -827,5 +832,5 @@ watch(
|
||||
contextEmit('set-picker-option', ['isValidValue', isValidValue])
|
||||
contextEmit('set-picker-option', ['formatToString', formatToString])
|
||||
contextEmit('set-picker-option', ['parseUserInput', parseUserInput])
|
||||
contextEmit('set-picker-option', ['handleFocusPicker', handleFocusPicker])
|
||||
contextEmit('set-picker-option', ['handleFocusPicker', _handleFocusPicker])
|
||||
</script>
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
focusFirstDescendant,
|
||||
getEdges,
|
||||
obtainAllFocusableElements,
|
||||
tryFocus,
|
||||
} from '../src/utils'
|
||||
|
||||
describe('focus-trap utils', () => {
|
||||
@ -53,4 +54,38 @@ describe('focus-trap utils', () => {
|
||||
focusFirstDescendant(focusable)
|
||||
expect(document.activeElement).toBe(focusable[0])
|
||||
})
|
||||
|
||||
describe('tryFocus', () => {
|
||||
it('should be focus the input element', () => {
|
||||
const input = document.querySelector('.focusable-input') as HTMLElement
|
||||
tryFocus(input)
|
||||
expect(document.activeElement).toBe(input)
|
||||
})
|
||||
|
||||
it('should be focus the span element', () => {
|
||||
const span = document.querySelector('.focusable-span') as HTMLElement
|
||||
tryFocus(span)
|
||||
expect(document.activeElement).toBe(span)
|
||||
})
|
||||
|
||||
it('should be focus the disabled input element', () => {
|
||||
const input = document.querySelector('[disabled]') as HTMLElement
|
||||
tryFocus(input)
|
||||
expect(document.activeElement).toBe(input)
|
||||
})
|
||||
|
||||
it('should be focus the document body', () => {
|
||||
const input = document.querySelector('.focusable-input') as HTMLElement
|
||||
tryFocus(input)
|
||||
expect(document.activeElement).not.toBe(document.body)
|
||||
tryFocus(document.body)
|
||||
expect(document.activeElement).toBe(document.body)
|
||||
})
|
||||
|
||||
it('should be focus the null element', () => {
|
||||
const activeElement = document.activeElement
|
||||
tryFocus(null)
|
||||
expect(document.activeElement).toBe(activeElement)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { isElement, isFocusable } from '@element-plus/utils'
|
||||
import { FOCUSOUT_PREVENTED, FOCUSOUT_PREVENTED_OPTS } from './tokens'
|
||||
|
||||
const focusReason = ref<'pointer' | 'keyboard'>()
|
||||
@ -81,8 +82,20 @@ export const tryFocus = (
|
||||
) => {
|
||||
if (element && element.focus) {
|
||||
const prevFocusedElement = document.activeElement
|
||||
let cleanup: boolean = false
|
||||
|
||||
if (
|
||||
isElement(element) &&
|
||||
!isFocusable(element) &&
|
||||
!element.getAttribute('tabindex')
|
||||
) {
|
||||
element.setAttribute('tabindex', '-1')
|
||||
cleanup = true
|
||||
}
|
||||
|
||||
element.focus({ preventScroll: true })
|
||||
lastAutomatedFocusTimestamp.value = window.performance.now()
|
||||
|
||||
if (
|
||||
element !== prevFocusedElement &&
|
||||
isSelectable(element) &&
|
||||
@ -90,6 +103,9 @@ export const tryFocus = (
|
||||
) {
|
||||
element.select()
|
||||
}
|
||||
if (isElement(element) && cleanup) {
|
||||
element.removeAttribute('tabindex')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div ref="wrapperRef" :class="ns.b()">
|
||||
<div ref="wrapperRef" :class="[ns.b(), ns.is('disabled', disabled)]">
|
||||
<el-input
|
||||
v-bind="mergeProps(passInputProps, $attrs)"
|
||||
ref="elInputRef"
|
||||
@ -69,7 +69,7 @@ import { getCursorPosition, getMentionCtx } from './helper'
|
||||
import ElMentionDropdown from './mention-dropdown.vue'
|
||||
|
||||
import type { Placement } from '@popperjs/core'
|
||||
import type { CSSProperties } from 'vue'
|
||||
import type { CSSProperties, ComputedRef, Ref } from 'vue'
|
||||
import type { InputInstance } from '@element-plus/components/input'
|
||||
import type { TooltipInstance } from '@element-plus/components/tooltip'
|
||||
import type { MentionCtx, MentionOption } from './types'
|
||||
@ -280,7 +280,11 @@ const syncDropdownVisible = () => {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
defineExpose<{
|
||||
input: Ref<InputInstance | undefined>
|
||||
tooltip: Ref<TooltipInstance | undefined>
|
||||
dropdownVisible: ComputedRef<boolean>
|
||||
}>({
|
||||
input: elInputRef,
|
||||
tooltip: tooltipRef,
|
||||
dropdownVisible,
|
||||
|
@ -326,10 +326,7 @@ export default defineComponent({
|
||||
const calcSliceIndex = () => {
|
||||
if (!menu.value) return -1
|
||||
const items = Array.from(menu.value?.childNodes ?? []).filter(
|
||||
(item) =>
|
||||
// remove comment type node #12634
|
||||
item.nodeName !== '#comment' &&
|
||||
(item.nodeName !== '#text' || item.nodeValue)
|
||||
(item) => item.nodeName !== '#text' || item.nodeValue
|
||||
) as HTMLElement[]
|
||||
const moreItemWidth = 64
|
||||
const computedMenuStyle = getComputedStyle(menu.value!)
|
||||
@ -339,6 +336,7 @@ export default defineComponent({
|
||||
let calcWidth = 0
|
||||
let sliceIndex = 0
|
||||
items.forEach((item, index) => {
|
||||
if (item.nodeName === '#comment') return
|
||||
calcWidth += calcMenuItemWidth(item)
|
||||
if (calcWidth <= menuWidth - moreItemWidth) {
|
||||
sliceIndex = index + 1
|
||||
|
@ -94,6 +94,44 @@ describe('PageHeader.vue', () => {
|
||||
expect(wrapper.find('.el-page-header__title').text()).toEqual(AXIOM)
|
||||
})
|
||||
|
||||
test('conditional slots rendering', async () => {
|
||||
const wrapper = mount(
|
||||
(props: {
|
||||
showDefault: boolean
|
||||
showBreadcrumb: boolean
|
||||
showExtra: boolean
|
||||
}) => (
|
||||
<PageHeader
|
||||
v-slots={{
|
||||
default: props.showDefault ? () => AXIOM : undefined,
|
||||
breadcrumb: props.showBreadcrumb ? () => AXIOM : undefined,
|
||||
extra: props.showExtra ? () => AXIOM : undefined,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
{
|
||||
props: {
|
||||
showDefault: false,
|
||||
showBreadcrumb: false,
|
||||
showExtra: false,
|
||||
},
|
||||
}
|
||||
)
|
||||
expect(wrapper.classes()).not.toContain('is-contentful')
|
||||
expect(wrapper.classes()).not.toContain('el-page-header--has-breadcrumb')
|
||||
expect(wrapper.classes()).not.toContain('el-page-header--has-extra')
|
||||
|
||||
await wrapper.setProps({
|
||||
showDefault: true,
|
||||
showBreadcrumb: true,
|
||||
showExtra: true,
|
||||
})
|
||||
|
||||
expect(wrapper.classes()).toContain('is-contentful')
|
||||
expect(wrapper.classes()).toContain('el-page-header--has-breadcrumb')
|
||||
expect(wrapper.classes()).toContain('el-page-header--has-extra')
|
||||
})
|
||||
|
||||
test('event back', async () => {
|
||||
const wrapper = mount(() => <PageHeader content={AXIOM} />)
|
||||
const pageHeader = wrapper.findComponent(PageHeader)
|
||||
|
@ -1,5 +1,14 @@
|
||||
<template>
|
||||
<div :class="kls">
|
||||
<div
|
||||
:class="[
|
||||
ns.b(),
|
||||
{
|
||||
[ns.m('has-breadcrumb')]: !!$slots.breadcrumb,
|
||||
[ns.m('has-extra')]: !!$slots.extra,
|
||||
[ns.is('contentful')]: !!$slots.default,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<div v-if="$slots.breadcrumb" :class="ns.e('breadcrumb')">
|
||||
<slot name="breadcrumb" />
|
||||
</div>
|
||||
@ -43,7 +52,6 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, useSlots } from 'vue'
|
||||
import { ElIcon } from '@element-plus/components/icon'
|
||||
import { ElDivider } from '@element-plus/components/divider'
|
||||
|
||||
@ -56,20 +64,9 @@ defineOptions({
|
||||
|
||||
defineProps(pageHeaderProps)
|
||||
const emit = defineEmits(pageHeaderEmits)
|
||||
const slots = useSlots()
|
||||
|
||||
const { t } = useLocale()
|
||||
const ns = useNamespace('page-header')
|
||||
const kls = computed(() => {
|
||||
return [
|
||||
ns.b(),
|
||||
{
|
||||
[ns.m('has-breadcrumb')]: !!slots.breadcrumb,
|
||||
[ns.m('has-extra')]: !!slots.extra,
|
||||
[ns.is('contentful')]: !!slots.default,
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
function handleClick() {
|
||||
emit('back')
|
||||
|
@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest'
|
||||
import { NOOP, hasClass } from '@element-plus/utils'
|
||||
import { EVENT_CODE } from '@element-plus/constants'
|
||||
import { makeMountFunc } from '@element-plus/test-utils/make-mount'
|
||||
@ -195,6 +195,10 @@ const PLACEHOLDER_CLASS_NAME = 'el-select__placeholder'
|
||||
const DEFAULT_PLACEHOLDER = 'Select'
|
||||
|
||||
describe('Select', () => {
|
||||
beforeAll(() => {
|
||||
HTMLCanvasElement.prototype.getContext = vi.fn(() => null)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = ''
|
||||
})
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
buildProps,
|
||||
definePropType,
|
||||
iconPropType,
|
||||
isBoolean,
|
||||
isNumber,
|
||||
} from '@element-plus/utils'
|
||||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@element-plus/constants'
|
||||
@ -180,7 +181,7 @@ export const SelectProps = buildProps({
|
||||
type: String,
|
||||
},
|
||||
/**
|
||||
* @description whether select dropdown is teleported to the body
|
||||
* @description whether select dropdown is teleported, if `true` it will be teleported to where `append-to` sets
|
||||
*/
|
||||
teleported: useTooltipContentProps.teleported,
|
||||
/**
|
||||
@ -285,6 +286,18 @@ export const SelectProps = buildProps({
|
||||
* @description which element the select dropdown appends to
|
||||
*/
|
||||
appendTo: String,
|
||||
/**
|
||||
* @description if it is `true`, the width of the dropdown panel is the same as the input box.
|
||||
* if it is `false`, the width is automatically calculated based on the value of `label`,
|
||||
* or it can be set to a number to make it a fixed width
|
||||
*/
|
||||
fitInputWidth: {
|
||||
type: [Boolean, Number],
|
||||
default: true,
|
||||
validator(val) {
|
||||
return isBoolean(val) || isNumber(val)
|
||||
},
|
||||
},
|
||||
...useEmptyValuesProps,
|
||||
...useAriaProps(['ariaLabel']),
|
||||
} as const)
|
||||
|
@ -20,7 +20,6 @@ export type SelectStates = {
|
||||
hoveringIndex: number
|
||||
inputHovering: boolean
|
||||
selectionWidth: number
|
||||
calculatorWidth: number
|
||||
collapseItemWidth: number
|
||||
previousQuery: string | null
|
||||
previousValue: unknown
|
||||
|
@ -230,7 +230,11 @@
|
||||
</el-icon>
|
||||
<el-icon
|
||||
v-if="validateState && validateIcon && needStatusIcon"
|
||||
:class="[nsInput.e('icon'), nsInput.e('validateIcon')]"
|
||||
:class="[
|
||||
nsInput.e('icon'),
|
||||
nsInput.e('validateIcon'),
|
||||
nsInput.is('loading', validateState === 'validating'),
|
||||
]"
|
||||
>
|
||||
<component :is="validateIcon" />
|
||||
</el-icon>
|
||||
@ -283,6 +287,7 @@ import { ClickOutside } from '@element-plus/directives'
|
||||
import ElTooltip from '@element-plus/components/tooltip'
|
||||
import ElTag from '@element-plus/components/tag'
|
||||
import ElIcon from '@element-plus/components/icon'
|
||||
import { useCalcInputWidth } from '@element-plus/hooks'
|
||||
import ElSelectMenu from './select-dropdown'
|
||||
import useSelect from './useSelect'
|
||||
import { SelectProps, selectEmits } from './defaults'
|
||||
@ -318,6 +323,8 @@ export default defineComponent({
|
||||
}),
|
||||
emit
|
||||
)
|
||||
const { calculatorRef, inputStyle } = useCalcInputWidth()
|
||||
|
||||
provide(selectV2InjectionKey, {
|
||||
props: reactive({
|
||||
...toRefs(props),
|
||||
@ -343,6 +350,8 @@ export default defineComponent({
|
||||
...API,
|
||||
modelValue,
|
||||
selectedLabel,
|
||||
calculatorRef,
|
||||
inputStyle,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
escapeStringRegexp,
|
||||
isArray,
|
||||
isFunction,
|
||||
isNumber,
|
||||
isObject,
|
||||
} from '@element-plus/utils'
|
||||
import {
|
||||
@ -49,10 +50,90 @@ import type { ISelectV2Props } from './token'
|
||||
import type { SelectEmitFn } from './defaults'
|
||||
import type { TooltipInstance } from '@element-plus/components/tooltip'
|
||||
import type { SelectDropdownInstance } from './select-dropdown'
|
||||
import type { Component, ComputedRef, Ref, WritableComputedRef } from 'vue'
|
||||
|
||||
const MINIMUM_INPUT_WIDTH = 11
|
||||
type useSelectReturnType = (
|
||||
props: ISelectV2Props,
|
||||
emit: SelectEmitFn
|
||||
) => {
|
||||
inputId: Ref<string | undefined>
|
||||
collapseTagSize: ComputedRef<'default' | 'small'>
|
||||
currentPlaceholder: ComputedRef<string>
|
||||
expanded: Ref<boolean>
|
||||
emptyText: ComputedRef<string | false | null>
|
||||
popupHeight: ComputedRef<number>
|
||||
debounce: ComputedRef<0 | 300>
|
||||
allOptions: Ref<OptionType[]>
|
||||
filteredOptions: Ref<OptionType[]>
|
||||
iconComponent: ComputedRef<any>
|
||||
iconReverse: ComputedRef<any>
|
||||
tagStyle: ComputedRef<{ maxWidth: string }>
|
||||
collapseTagStyle: ComputedRef<{ maxWidth: string }>
|
||||
popperSize: Ref<number>
|
||||
dropdownMenuVisible: WritableComputedRef<boolean>
|
||||
hasModelValue: ComputedRef<boolean>
|
||||
shouldShowPlaceholder: ComputedRef<boolean>
|
||||
selectDisabled: ComputedRef<boolean | undefined>
|
||||
selectSize: ComputedRef<string>
|
||||
needStatusIcon: ComputedRef<boolean>
|
||||
showClearBtn: ComputedRef<boolean>
|
||||
states: SelectStates
|
||||
isFocused: Ref<boolean>
|
||||
nsSelect: ReturnType<typeof useNamespace>
|
||||
nsInput: ReturnType<typeof useNamespace>
|
||||
inputRef: Ref<HTMLElement | undefined>
|
||||
menuRef: Ref<SelectDropdownInstance | undefined>
|
||||
tagMenuRef: Ref<HTMLElement | undefined>
|
||||
tooltipRef: Ref<TooltipInstance | undefined>
|
||||
tagTooltipRef: Ref<TooltipInstance | undefined>
|
||||
selectRef: Ref<HTMLElement | undefined>
|
||||
wrapperRef: Ref<HTMLElement | undefined>
|
||||
selectionRef: Ref<HTMLElement | undefined>
|
||||
prefixRef: Ref<HTMLElement | undefined>
|
||||
suffixRef: Ref<HTMLElement | undefined>
|
||||
collapseItemRef: Ref<HTMLElement | undefined>
|
||||
popperRef: ComputedRef<HTMLElement | undefined>
|
||||
validateState: ComputedRef<string>
|
||||
validateIcon: ComputedRef<Component | undefined>
|
||||
showTagList: ComputedRef<Option[]>
|
||||
collapseTagList: ComputedRef<Option[]>
|
||||
debouncedOnInputChange: () => void
|
||||
deleteTag: (event: MouseEvent, option: Option) => void
|
||||
getLabel: (option: Option) => string
|
||||
getValue: (option: Option) => unknown
|
||||
getDisabled: (option: Option) => boolean
|
||||
getValueKey: (item: unknown) => any
|
||||
handleClear: () => void
|
||||
handleClickOutside: (event: Event) => void
|
||||
handleDel: (e: KeyboardEvent) => void
|
||||
handleEsc: () => void
|
||||
focus: () => void
|
||||
blur: () => void
|
||||
handleMenuEnter: () => void
|
||||
handleResize: () => void
|
||||
resetSelectionWidth: () => void
|
||||
updateTooltip: () => void
|
||||
updateTagTooltip: () => void
|
||||
updateOptions: () => void
|
||||
toggleMenu: () => void
|
||||
scrollTo: (index: number) => void
|
||||
onInput: (event: Event) => void
|
||||
onKeyboardNavigate: (
|
||||
direction: 'forward' | 'backward',
|
||||
hoveringIndex?: number
|
||||
) => void
|
||||
onKeyboardSelect: () => void
|
||||
onSelect: (option: Option) => void
|
||||
onHover: (idx?: number) => void
|
||||
handleCompositionStart: (event: CompositionEvent) => void
|
||||
handleCompositionEnd: (event: CompositionEvent) => void
|
||||
handleCompositionUpdate: (event: CompositionEvent) => void
|
||||
}
|
||||
|
||||
const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
const useSelect: useSelectReturnType = (
|
||||
props: ISelectV2Props,
|
||||
emit: SelectEmitFn
|
||||
) => {
|
||||
// inject
|
||||
const { t } = useLocale()
|
||||
const nsSelect = useNamespace('select')
|
||||
@ -72,7 +153,6 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
hoveringIndex: -1,
|
||||
inputHovering: false,
|
||||
selectionWidth: 0,
|
||||
calculatorWidth: 0,
|
||||
collapseItemWidth: 0,
|
||||
previousQuery: null,
|
||||
previousValue: undefined,
|
||||
@ -90,7 +170,6 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
const tooltipRef = ref<TooltipInstance>()
|
||||
const tagTooltipRef = ref<TooltipInstance>()
|
||||
const inputRef = ref<HTMLElement>()
|
||||
const calculatorRef = ref<HTMLElement>()
|
||||
const prefixRef = ref<HTMLElement>()
|
||||
const suffixRef = ref<HTMLElement>()
|
||||
const menuRef = ref<SelectDropdownInstance>()
|
||||
@ -268,7 +347,40 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
)
|
||||
|
||||
const calculatePopperSize = () => {
|
||||
popperSize.value = selectRef.value?.offsetWidth || 200
|
||||
if (isNumber(props.fitInputWidth)) {
|
||||
popperSize.value = props.fitInputWidth
|
||||
return
|
||||
}
|
||||
const width = selectRef.value?.offsetWidth || 200
|
||||
if (!props.fitInputWidth && allOptions.value.length > 0) {
|
||||
nextTick(() => {
|
||||
popperSize.value = Math.max(width, calculateLabelMaxWidth())
|
||||
})
|
||||
} else {
|
||||
popperSize.value = width
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Caching implementation
|
||||
// 1. There is no need to calculate options that have already been calculated
|
||||
// 2. Repeatedly expand and close when persistent is set to false, no need for repeated calculations
|
||||
const calculateLabelMaxWidth = () => {
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
const selector = nsSelect.be('dropdown', 'item')
|
||||
const dom = menuRef.value?.listRef?.innerRef || document
|
||||
const dropdownItemEl = dom.querySelector(`.${selector}`)
|
||||
if (dropdownItemEl === null || ctx === null) return 0
|
||||
const style = getComputedStyle(dropdownItemEl)
|
||||
const padding =
|
||||
Number.parseFloat(style.paddingLeft) +
|
||||
Number.parseFloat(style.paddingRight)
|
||||
ctx.font = style.font
|
||||
const maxWidth = filteredOptions.value.reduce((max, option) => {
|
||||
const metrics = ctx.measureText(getLabel(option))
|
||||
return Math.max(metrics.width, max)
|
||||
}, 0)
|
||||
return maxWidth + padding
|
||||
}
|
||||
|
||||
const getGapWidth = () => {
|
||||
@ -291,10 +403,6 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
return { maxWidth: `${states.selectionWidth}px` }
|
||||
})
|
||||
|
||||
const inputStyle = computed(() => ({
|
||||
width: `${Math.max(states.calculatorWidth, MINIMUM_INPUT_WIDTH)}px`,
|
||||
}))
|
||||
|
||||
const shouldShowPlaceholder = computed(() => {
|
||||
if (isArray(props.modelValue)) {
|
||||
return props.modelValue.length === 0 && !states.inputValue
|
||||
@ -484,10 +592,6 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
states.selectionWidth = selectionRef.value!.getBoundingClientRect().width
|
||||
}
|
||||
|
||||
const resetCalculatorWidth = () => {
|
||||
states.calculatorWidth = calculatorRef.value!.getBoundingClientRect().width
|
||||
}
|
||||
|
||||
const resetCollapseItemWidth = () => {
|
||||
states.collapseItemWidth =
|
||||
collapseItemRef.value!.getBoundingClientRect().width
|
||||
@ -795,12 +899,22 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
calculatePopperSize()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.fitInputWidth,
|
||||
() => {
|
||||
calculatePopperSize()
|
||||
}
|
||||
)
|
||||
|
||||
// in order to track these individually, we need to turn them into refs instead of watching the entire
|
||||
// reactive object which could cause perf penalty when unnecessary field gets changed the watch method will
|
||||
// be invoked.
|
||||
|
||||
watch(expanded, (val) => {
|
||||
if (val) {
|
||||
if (!props.persistent) {
|
||||
calculatePopperSize()
|
||||
}
|
||||
handleQueryChange('')
|
||||
} else {
|
||||
states.inputValue = ''
|
||||
@ -852,6 +966,7 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
watch(
|
||||
() => filteredOptions.value,
|
||||
() => {
|
||||
calculatePopperSize()
|
||||
return menuRef.value && nextTick(menuRef.value.resetScrollTop)
|
||||
}
|
||||
)
|
||||
@ -889,7 +1004,6 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
})
|
||||
useResizeObserver(selectRef, handleResize)
|
||||
useResizeObserver(selectionRef, resetSelectionWidth)
|
||||
useResizeObserver(calculatorRef, resetCalculatorWidth)
|
||||
useResizeObserver(menuRef, updateTooltip)
|
||||
useResizeObserver(wrapperRef, updateTooltip)
|
||||
useResizeObserver(tagMenuRef, updateTagTooltip)
|
||||
@ -910,7 +1024,6 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
iconReverse,
|
||||
tagStyle,
|
||||
collapseTagStyle,
|
||||
inputStyle,
|
||||
popperSize,
|
||||
dropdownMenuVisible,
|
||||
hasModelValue,
|
||||
@ -925,7 +1038,6 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
nsInput,
|
||||
|
||||
// refs items exports
|
||||
calculatorRef,
|
||||
inputRef,
|
||||
menuRef,
|
||||
tagMenuRef,
|
||||
@ -961,7 +1073,6 @@ const useSelect = (props: ISelectV2Props, emit: SelectEmitFn) => {
|
||||
handleMenuEnter,
|
||||
handleResize,
|
||||
resetSelectionWidth,
|
||||
resetCalculatorWidth,
|
||||
updateTooltip,
|
||||
updateTagTooltip,
|
||||
updateOptions,
|
||||
|
@ -161,7 +161,7 @@ export const SelectProps = buildProps({
|
||||
default: 1,
|
||||
},
|
||||
/**
|
||||
* @description whether select dropdown is teleported to the body
|
||||
* @description whether select dropdown is teleported, if `true` it will be teleported to where `append-to` sets
|
||||
*/
|
||||
teleported: useTooltipContentProps.teleported,
|
||||
/**
|
||||
|
@ -230,7 +230,11 @@
|
||||
</el-icon>
|
||||
<el-icon
|
||||
v-if="validateState && validateIcon && needStatusIcon"
|
||||
:class="[nsInput.e('icon'), nsInput.e('validateIcon')]"
|
||||
:class="[
|
||||
nsInput.e('icon'),
|
||||
nsInput.e('validateIcon'),
|
||||
nsInput.is('loading', validateState === 'validating'),
|
||||
]"
|
||||
>
|
||||
<component :is="validateIcon" />
|
||||
</el-icon>
|
||||
@ -303,6 +307,7 @@ import ElTag from '@element-plus/components/tag'
|
||||
import ElIcon from '@element-plus/components/icon'
|
||||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@element-plus/constants'
|
||||
import { isArray } from '@element-plus/utils'
|
||||
import { useCalcInputWidth } from '@element-plus/hooks'
|
||||
import ElOption from './option.vue'
|
||||
import ElSelectMenu from './select-dropdown.vue'
|
||||
import { useSelect } from './useSelect'
|
||||
@ -356,6 +361,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const API = useSelect(_props, emit)
|
||||
const { calculatorRef, inputStyle } = useCalcInputWidth()
|
||||
|
||||
provide(
|
||||
selectKey,
|
||||
@ -375,13 +381,15 @@ export default defineComponent({
|
||||
if (!props.multiple) {
|
||||
return API.states.selectedLabel
|
||||
}
|
||||
return API.states.selected.map((i) => i.currentLabel as string)
|
||||
return API.states.selected.map((i: any) => i.currentLabel as string)
|
||||
})
|
||||
|
||||
return {
|
||||
...API,
|
||||
modelValue,
|
||||
selectedLabel,
|
||||
calculatorRef,
|
||||
inputStyle,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -51,9 +51,88 @@ import {
|
||||
import type ElTooltip from '@element-plus/components/tooltip'
|
||||
import type { ISelectProps, SelectOptionProxy } from './token'
|
||||
|
||||
const MINIMUM_INPUT_WIDTH = 11
|
||||
type useSelectType = (
|
||||
props: ISelectProps,
|
||||
emit: any
|
||||
) => {
|
||||
inputId: Ref<string | undefined>
|
||||
contentId: Ref<string | undefined>
|
||||
nsSelect: Ref<string | undefined>
|
||||
nsInput: Ref<string | undefined>
|
||||
states: Reactive<Record<string, any>>
|
||||
isFocused: Ref<boolean>
|
||||
expanded: Ref<boolean>
|
||||
optionsArray: ComputedRef<any[]>
|
||||
hoverOption: Ref<unknown>
|
||||
selectSize: ComputedRef<'' | 'default' | 'small' | 'large'>
|
||||
filteredOptionsCount: ComputedRef<number>
|
||||
resetCalculatorWidth: () => void
|
||||
updateTooltip: () => void
|
||||
updateTagTooltip: () => void
|
||||
debouncedOnInputChange: DebouncedFunc<() => void>
|
||||
onInput: (event: Event) => void
|
||||
deletePrevTag: (event: Event) => void
|
||||
deleteTag: (event: Event, tag: any) => void
|
||||
deleteSelected: (event: Event) => void
|
||||
handleOptionSelect: (option: any) => void
|
||||
scrollToOption: (option: any) => void
|
||||
hasModelValue: ComputedRef<boolean>
|
||||
shouldShowPlaceholder: ComputedRef<boolean>
|
||||
currentPlaceholder: ComputedRef<string>
|
||||
mouseEnterEventName: Ref<string | null>
|
||||
needStatusIcon: ComputedRef<boolean>
|
||||
showClose: ComputedRef<boolean>
|
||||
iconComponent: ComputedRef<string>
|
||||
iconReverse: ComputedRef<boolean>
|
||||
validateState: ComputedRef<string>
|
||||
|
||||
export const useSelect = (props: ISelectProps, emit) => {
|
||||
validateIcon: ComputedRef<unknown>
|
||||
showNewOption: ComputedRef<boolean>
|
||||
updateOptions: () => void
|
||||
collapseTagSize: ComputedRef<'default' | 'small'>
|
||||
setSelected: () => void
|
||||
selectDisabled: ComputedRef<boolean>
|
||||
emptyText: ComputedRef<string | null>
|
||||
handleCompositionStart: (e: Event) => void
|
||||
handleCompositionUpdate: (e: Event) => void
|
||||
handleCompositionEnd: (e: Event) => void
|
||||
onOptionCreate: (vm: SelectOptionProxy) => void
|
||||
onOptionDestroy: (key: any, vm: SelectOptionProxy) => void
|
||||
handleMenuEnter: () => void
|
||||
focus: () => void
|
||||
blur: () => void
|
||||
handleClearClick: (event: Event) => void
|
||||
handleClickOutside: (event: Event) => void
|
||||
handleEsc: () => void
|
||||
toggleMenu: () => void
|
||||
selectOption: () => void
|
||||
getValueKey: (item: any) => any
|
||||
navigateOptions: (direction: string) => void
|
||||
dropdownMenuVisible: WritableComputedRef<boolean>
|
||||
showTagList: ComputedRef<unknown[]>
|
||||
collapseTagList: ComputedRef<unknown[]>
|
||||
tagStyle: ComputedRef<unknown>
|
||||
collapseTagStyle: ComputedRef<unknown>
|
||||
inputStyle: ComputedRef<unknown>
|
||||
popperRef: ComputedRef<unknown>
|
||||
inputRef: Ref<HTMLInputElement | null>
|
||||
tooltipRef: Ref<InstanceType<typeof ElTooltip> | null>
|
||||
tagTooltipRef: Ref<InstanceType<typeof ElTooltip> | null>
|
||||
calculatorRef: Ref<HTMLElement>
|
||||
prefixRef: Ref<HTMLElement>
|
||||
suffixRef: Ref<HTMLElement>
|
||||
selectRef: Ref<HTMLElement>
|
||||
wrapperRef: Ref<HTMLElement>
|
||||
selectionRef: Ref<HTMLElement>
|
||||
scrollbarRef: Ref<{
|
||||
handleScroll: () => void
|
||||
} | null>
|
||||
menuRef: Ref<HTMLElement>
|
||||
tagMenuRef: Ref<HTMLElement>
|
||||
collapseItemRef: Ref<HTMLElement>
|
||||
}
|
||||
|
||||
export const useSelect: useSelectType = (props: ISelectProps, emit) => {
|
||||
const { t } = useLocale()
|
||||
const contentId = useId()
|
||||
const nsSelect = useNamespace('select')
|
||||
@ -66,7 +145,6 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
optionValues: [] as any[], // sorted value of options
|
||||
selected: [] as any[],
|
||||
selectionWidth: 0,
|
||||
calculatorWidth: 0,
|
||||
collapseItemWidth: 0,
|
||||
selectedLabel: '',
|
||||
hoveringIndex: -1,
|
||||
@ -82,7 +160,6 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
const tooltipRef = ref<InstanceType<typeof ElTooltip> | null>(null)
|
||||
const tagTooltipRef = ref<InstanceType<typeof ElTooltip> | null>(null)
|
||||
const inputRef = ref<HTMLInputElement | null>(null)
|
||||
const calculatorRef = ref<HTMLElement>(null)
|
||||
const prefixRef = ref<HTMLElement>(null)
|
||||
const suffixRef = ref<HTMLElement>(null)
|
||||
const menuRef = ref<HTMLElement>(null)
|
||||
@ -167,12 +244,14 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
|
||||
const debounce = computed(() => (props.remote ? 300 : 0))
|
||||
|
||||
const isRemoteSearchEmpty = computed(
|
||||
() => props.remote && !states.inputValue && states.options.size === 0
|
||||
)
|
||||
|
||||
const emptyText = computed(() => {
|
||||
if (props.loading) {
|
||||
return props.loadingText || t('el.select.loading')
|
||||
} else {
|
||||
if (props.remote && !states.inputValue && states.options.size === 0)
|
||||
return false
|
||||
if (
|
||||
props.filterable &&
|
||||
states.inputValue &&
|
||||
@ -241,7 +320,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
|
||||
const dropdownMenuVisible = computed({
|
||||
get() {
|
||||
return expanded.value && emptyText.value !== false
|
||||
return expanded.value && !isRemoteSearchEmpty.value
|
||||
},
|
||||
set(val: boolean) {
|
||||
expanded.value = val
|
||||
@ -457,10 +536,6 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
states.selectionWidth = selectionRef.value.getBoundingClientRect().width
|
||||
}
|
||||
|
||||
const resetCalculatorWidth = () => {
|
||||
states.calculatorWidth = calculatorRef.value.getBoundingClientRect().width
|
||||
}
|
||||
|
||||
const resetCollapseItemWidth = () => {
|
||||
states.collapseItemWidth =
|
||||
collapseItemRef.value.getBoundingClientRect().width
|
||||
@ -775,12 +850,7 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
return { maxWidth: `${states.selectionWidth}px` }
|
||||
})
|
||||
|
||||
const inputStyle = computed(() => ({
|
||||
width: `${Math.max(states.calculatorWidth, MINIMUM_INPUT_WIDTH)}px`,
|
||||
}))
|
||||
|
||||
useResizeObserver(selectionRef, resetSelectionWidth)
|
||||
useResizeObserver(calculatorRef, resetCalculatorWidth)
|
||||
useResizeObserver(menuRef, updateTooltip)
|
||||
useResizeObserver(wrapperRef, updateTooltip)
|
||||
useResizeObserver(tagMenuRef, updateTagTooltip)
|
||||
@ -802,7 +872,6 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
hoverOption,
|
||||
selectSize,
|
||||
filteredOptionsCount,
|
||||
resetCalculatorWidth,
|
||||
updateTooltip,
|
||||
updateTagTooltip,
|
||||
debouncedOnInputChange,
|
||||
@ -850,14 +919,12 @@ export const useSelect = (props: ISelectProps, emit) => {
|
||||
// computed style
|
||||
tagStyle,
|
||||
collapseTagStyle,
|
||||
inputStyle,
|
||||
|
||||
// DOM ref
|
||||
popperRef,
|
||||
inputRef,
|
||||
tooltipRef,
|
||||
tagTooltipRef,
|
||||
calculatorRef,
|
||||
prefixRef,
|
||||
suffixRef,
|
||||
selectRef,
|
||||
|
@ -50,7 +50,27 @@ const useTooltip = (
|
||||
}
|
||||
}
|
||||
|
||||
export const useSliderButton = (
|
||||
type HTMLType = HTMLDivElement | undefined
|
||||
type useSliderButtonType = (
|
||||
props: SliderButtonProps,
|
||||
initData: SliderButtonInitData,
|
||||
emit: SetupContext<SliderButtonEmits>['emit']
|
||||
) => {
|
||||
disabled: Ref<boolean>
|
||||
button: Ref<HTMLType>
|
||||
tooltip: Ref<TooltipInstance | undefined>
|
||||
tooltipVisible: Ref<boolean>
|
||||
showTooltip: Ref<SliderProps['showTooltip']>
|
||||
wrapperStyle: ComputedRef<CSSProperties>
|
||||
formatValue: ComputedRef<number | string>
|
||||
handleMouseEnter: () => void
|
||||
handleMouseLeave: () => void
|
||||
onButtonDown: (event: MouseEvent | TouchEvent) => void
|
||||
onKeyDown: (event: KeyboardEvent) => void
|
||||
setPosition: (newPosition: number) => Promise<void>
|
||||
}
|
||||
|
||||
export const useSliderButton: useSliderButtonType = (
|
||||
props: SliderButtonProps,
|
||||
initData: SliderButtonInitData,
|
||||
emit: SetupContext<SliderButtonEmits>['emit']
|
||||
|
@ -1822,7 +1822,7 @@ describe('Table.vue', () => {
|
||||
ElTableColumn,
|
||||
},
|
||||
template: `
|
||||
<el-table :data="testData" :tree-props="treeProps" @selection-change="change">
|
||||
<el-table :data="testData" :tree-props="treeProps" row-key="id" @selection-change="change">
|
||||
<el-table-column type="selection" />
|
||||
<el-table-column prop="name" label="name" />
|
||||
<el-table-column prop="release" label="release" />
|
||||
|
@ -50,8 +50,7 @@
|
||||
:class="[
|
||||
ns.e('list-item'),
|
||||
{
|
||||
[ns.is('active')]:
|
||||
filterValue === undefined || filterValue === null,
|
||||
[ns.is('active')]: isPropAbsent(filterValue),
|
||||
},
|
||||
]"
|
||||
@click="handleSelect(null)"
|
||||
@ -99,8 +98,9 @@ import { ClickOutside } from '@element-plus/directives'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import ElTooltip from '@element-plus/components/tooltip'
|
||||
import ElScrollbar from '@element-plus/components/scrollbar'
|
||||
import type { Placement } from '@element-plus/components/popper'
|
||||
import { isPropAbsent } from '@element-plus/utils'
|
||||
|
||||
import type { Placement } from '@element-plus/components/popper'
|
||||
import type { PropType, WritableComputedRef } from 'vue'
|
||||
import type { TableColumnCtx } from './table-column/defaults'
|
||||
import type { TableHeader } from './table-header'
|
||||
@ -161,7 +161,7 @@ export default defineComponent({
|
||||
get: () => (props.column?.filteredValue || [])[0],
|
||||
set: (value: string) => {
|
||||
if (filteredValue.value) {
|
||||
if (typeof value !== 'undefined' && value !== null) {
|
||||
if (!isPropAbsent(value)) {
|
||||
filteredValue.value.splice(0, 1, value)
|
||||
} else {
|
||||
filteredValue.value.splice(0, 1)
|
||||
@ -212,7 +212,7 @@ export default defineComponent({
|
||||
}
|
||||
const handleSelect = (_filterValue?: string) => {
|
||||
filterValue.value = _filterValue
|
||||
if (typeof _filterValue !== 'undefined' && _filterValue !== null) {
|
||||
if (!isPropAbsent(_filterValue)) {
|
||||
confirmFilter(filteredValue.value)
|
||||
} else {
|
||||
confirmFilter([])
|
||||
@ -253,6 +253,7 @@ export default defineComponent({
|
||||
handleConfirm,
|
||||
handleReset,
|
||||
handleSelect,
|
||||
isPropAbsent,
|
||||
isActive,
|
||||
t,
|
||||
ns,
|
||||
|
@ -1,10 +1,12 @@
|
||||
// @ts-nocheck
|
||||
import { h } from 'vue'
|
||||
import { isUndefined } from '@element-plus/utils'
|
||||
|
||||
export function hColgroup(props) {
|
||||
const isAuto = props.tableLayout === 'auto'
|
||||
let columns = props.columns || []
|
||||
if (isAuto) {
|
||||
if (columns.every((column) => column.width === undefined)) {
|
||||
if (columns.every(({ width }) => isUndefined(width))) {
|
||||
columns = []
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { getCurrentInstance, ref, unref } from 'vue'
|
||||
import { isNull } from 'lodash-unified'
|
||||
import { getRowIdentity } from '../util'
|
||||
|
||||
import type { Ref } from 'vue'
|
||||
@ -59,7 +60,7 @@ function useCurrent<T>(watcherData: WatcherPropsData<T>) {
|
||||
} else {
|
||||
currentRow.value = null
|
||||
}
|
||||
if (currentRow.value === null) {
|
||||
if (isNull(currentRow.value)) {
|
||||
instance.emit('current-change', null, oldCurrentRow)
|
||||
}
|
||||
} else if (_currentRowKey.value) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import { watch } from 'vue'
|
||||
import { debounce } from 'lodash-unified'
|
||||
import { isObject } from '@element-plus/utils'
|
||||
import useStore from '.'
|
||||
|
||||
import type { Store } from '.'
|
||||
@ -57,7 +58,7 @@ function proxyTableProps<T>(store: Store<T>, props: TableProps<T>) {
|
||||
function handleValue<T>(value, propsKey: string, store: Store<T>) {
|
||||
let newVal = value
|
||||
let storeKey = InitialStateMap[propsKey]
|
||||
if (typeof InitialStateMap[propsKey] === 'object') {
|
||||
if (isObject(InitialStateMap[propsKey])) {
|
||||
storeKey = storeKey.key
|
||||
newVal = newVal || InitialStateMap[propsKey].default
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { getCurrentInstance, nextTick, unref } from 'vue'
|
||||
import { isNull } from 'lodash-unified'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import useWatcher from './watcher'
|
||||
|
||||
@ -169,7 +170,7 @@ function useStore<T>() {
|
||||
const columnValue = unref(sortingColumn),
|
||||
propValue = unref(sortProp),
|
||||
orderValue = unref(sortOrder)
|
||||
if (orderValue === null) {
|
||||
if (isNull(orderValue)) {
|
||||
states.sortingColumn.value = null
|
||||
states.sortProp.value = null
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import { getCurrentInstance, ref, toRefs, unref, watch } from 'vue'
|
||||
import { isEqual } from 'lodash-unified'
|
||||
import { computed, getCurrentInstance, ref, toRefs, unref, watch } from 'vue'
|
||||
import { hasOwn, isArray, isString, isUndefined } from '@element-plus/utils'
|
||||
import {
|
||||
getColumnById,
|
||||
@ -77,6 +76,10 @@ function useWatcher<T>() {
|
||||
const sortOrder = ref(null)
|
||||
const hoverRow = ref(null)
|
||||
|
||||
const selectedMap = computed(() => {
|
||||
return rowKey.value ? getKeysMap(selection.value, rowKey.value) : undefined
|
||||
})
|
||||
|
||||
watch(
|
||||
data,
|
||||
() => {
|
||||
@ -184,8 +187,12 @@ function useWatcher<T>() {
|
||||
}
|
||||
|
||||
// 选择
|
||||
const isSelected = (row) => {
|
||||
return selection.value.some((item) => isEqual(item, row))
|
||||
const isSelected = (row: DefaultRow) => {
|
||||
if (selectedMap.value) {
|
||||
return !!selectedMap.value[getRowIdentity(row, rowKey.value)]
|
||||
} else {
|
||||
return selection.value.includes(row)
|
||||
}
|
||||
}
|
||||
|
||||
const clearSelection = () => {
|
||||
@ -201,11 +208,10 @@ function useWatcher<T>() {
|
||||
let deleted
|
||||
if (rowKey.value) {
|
||||
deleted = []
|
||||
const selectedMap = getKeysMap(selection.value, rowKey.value)
|
||||
const dataMap = getKeysMap(data.value, rowKey.value)
|
||||
for (const key in selectedMap) {
|
||||
if (hasOwn(selectedMap, key) && !dataMap[key]) {
|
||||
deleted.push(selectedMap[key].row)
|
||||
for (const key in selectedMap.value) {
|
||||
if (hasOwn(selectedMap.value, key) && !dataMap[key]) {
|
||||
deleted.push(selectedMap.value[key].row)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -295,10 +301,9 @@ function useWatcher<T>() {
|
||||
}
|
||||
|
||||
const updateSelectionByRowKey = () => {
|
||||
const selectedMap = getKeysMap(selection.value, rowKey.value)
|
||||
data.value.forEach((row) => {
|
||||
const rowId = getRowIdentity(row, rowKey.value)
|
||||
const rowInfo = selectedMap[rowId]
|
||||
const rowInfo = selectedMap.value![rowId]
|
||||
if (rowInfo) {
|
||||
selection.value[rowInfo.index] = row
|
||||
}
|
||||
@ -313,20 +318,9 @@ function useWatcher<T>() {
|
||||
}
|
||||
|
||||
const { childrenColumnName } = instance.store.states
|
||||
const selectedMap = rowKey.value
|
||||
? getKeysMap(selection.value, rowKey.value)
|
||||
: undefined
|
||||
|
||||
let rowIndex = 0
|
||||
let selectedCount = 0
|
||||
|
||||
const isSelected = (row: DefaultRow) => {
|
||||
if (selectedMap) {
|
||||
return !!selectedMap[getRowIdentity(row, rowKey.value)]
|
||||
} else {
|
||||
return selection.value.includes(row)
|
||||
}
|
||||
}
|
||||
const checkSelectedStatus = (data: DefaultRow[]) => {
|
||||
for (const row of data) {
|
||||
const isRowSelectable =
|
||||
|
@ -2,7 +2,12 @@
|
||||
import { h, inject, ref } from 'vue'
|
||||
import { debounce } from 'lodash-unified'
|
||||
import { addClass, hasClass, removeClass } from '@element-plus/utils'
|
||||
import { createTablePopper, getCell, getColumnByCell } from '../util'
|
||||
import {
|
||||
createTablePopper,
|
||||
getCell,
|
||||
getColumnByCell,
|
||||
removePopper,
|
||||
} from '../util'
|
||||
import { TABLE_INJECTION_KEY } from '../tokens'
|
||||
import type { TableColumnCtx } from '../table-column/defaults'
|
||||
import type { TableBodyProps } from './defaults'
|
||||
@ -156,6 +161,8 @@ function useEvents<T>(props: Partial<TableBodyProps<T>>) {
|
||||
cell,
|
||||
table
|
||||
)
|
||||
} else if (removePopper?.trigger === cell) {
|
||||
removePopper?.()
|
||||
}
|
||||
}
|
||||
const handleCellMouseLeave = (event) => {
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { computed, h, inject } from 'vue'
|
||||
import { merge } from 'lodash-unified'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { isBoolean } from '@element-plus/utils'
|
||||
import { isBoolean, isPropAbsent } from '@element-plus/utils'
|
||||
import { getRowIdentity } from '../util'
|
||||
import { TABLE_INJECTION_KEY } from '../tokens'
|
||||
import useEvents from './events-helper'
|
||||
@ -227,7 +227,7 @@ function useRender<T>(props: Partial<TableBodyProps<T>>) {
|
||||
loading: false,
|
||||
}
|
||||
const childKey = getRowIdentity(node, rowKey.value)
|
||||
if (childKey === undefined || childKey === null) {
|
||||
if (isPropAbsent(childKey)) {
|
||||
throw new Error('For nested data item, row-key is required.')
|
||||
}
|
||||
cur = { ...treeData.value[childKey] }
|
||||
|
@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import { inject } from 'vue'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { isArray, isFunction, isString } from '@element-plus/utils'
|
||||
import { isArray, isFunction, isObject, isString } from '@element-plus/utils'
|
||||
import {
|
||||
ensurePosition,
|
||||
getFixedColumnOffset,
|
||||
@ -129,7 +129,7 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
|
||||
if (isArray(result)) {
|
||||
rowspan = result[0]
|
||||
colspan = result[1]
|
||||
} else if (typeof result === 'object') {
|
||||
} else if (isObject(result)) {
|
||||
rowspan = result.rowspan
|
||||
colspan = result.colspan
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
unref,
|
||||
watchEffect,
|
||||
} from 'vue'
|
||||
import { debugWarn, isArray } from '@element-plus/utils'
|
||||
import { debugWarn, isArray, isUndefined } from '@element-plus/utils'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import {
|
||||
cellForced,
|
||||
@ -73,7 +73,7 @@ function useRender<T>(
|
||||
column.minWidth = 80
|
||||
}
|
||||
column.realWidth = Number(
|
||||
column.width === undefined ? column.minWidth : column.width
|
||||
isUndefined(column.width) ? column.minWidth : column.width
|
||||
)
|
||||
return column
|
||||
}
|
||||
@ -83,7 +83,7 @@ function useRender<T>(
|
||||
const source = cellForced[type] || {}
|
||||
Object.keys(source).forEach((prop) => {
|
||||
const value = source[prop]
|
||||
if (prop !== 'className' && value !== undefined) {
|
||||
if (prop !== 'className' && !isUndefined(value)) {
|
||||
column[prop] = value
|
||||
}
|
||||
})
|
||||
|
@ -1,5 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { getCurrentInstance, inject, ref } from 'vue'
|
||||
import { isNull } from 'lodash-unified'
|
||||
import {
|
||||
addClass,
|
||||
hasClass,
|
||||
@ -128,7 +129,8 @@ function useEvent<T>(props: TableHeaderProps<T>, emit) {
|
||||
|
||||
const bodyStyle = document.body.style
|
||||
const isLastTh = target.parentNode?.lastElementChild === target
|
||||
if (rect.width > 12 && rect.right - event.pageX < 8 && !isLastTh) {
|
||||
const allowDarg = props.allowDragLastColumn || !isLastTh
|
||||
if (rect.width > 12 && rect.right - event.pageX < 8 && allowDarg) {
|
||||
bodyStyle.cursor = 'col-resize'
|
||||
if (hasClass(target, 'is-sortable')) {
|
||||
target.style.cursor = 'col-resize'
|
||||
@ -189,7 +191,7 @@ function useEvent<T>(props: TableHeaderProps<T>, emit) {
|
||||
|
||||
if (
|
||||
sortingColumn !== column ||
|
||||
(sortingColumn === column && sortingColumn.order === null)
|
||||
(sortingColumn === column && isNull(sortingColumn.order))
|
||||
) {
|
||||
if (sortingColumn) {
|
||||
sortingColumn.order = null
|
||||
|
@ -33,6 +33,7 @@ export interface TableHeaderProps<T> {
|
||||
store: Store<T>
|
||||
border: boolean
|
||||
defaultSort: Sort
|
||||
allowDragLastColumn: boolean
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
@ -62,6 +63,9 @@ export default defineComponent({
|
||||
appendFilterPanelTo: {
|
||||
type: String,
|
||||
},
|
||||
allowDragLastColumn: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const instance = getCurrentInstance() as TableHeader
|
||||
|
@ -1,9 +1,10 @@
|
||||
// @ts-nocheck
|
||||
import { isRef, nextTick, ref } from 'vue'
|
||||
import { isNull } from 'lodash-unified'
|
||||
import { hasOwn, isClient, isNumber, isString } from '@element-plus/utils'
|
||||
import { parseHeight } from './util'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
import type { Ref } from 'vue'
|
||||
import type { TableColumnCtx } from './table-column/defaults'
|
||||
import type { TableHeader } from './table-header'
|
||||
import type { Table } from './table/defaults'
|
||||
@ -64,7 +65,7 @@ class TableLayout<T> {
|
||||
* When the height is not initialized, it is null.
|
||||
* After the table is initialized, when the height is not configured, the height is 0.
|
||||
*/
|
||||
if (height === null) return false
|
||||
if (isNull(height)) return false
|
||||
const scrollBarRef = this.table.refs.scrollBarRef
|
||||
if (this.table.vnode.el && scrollBarRef?.wrapRef) {
|
||||
let scrollY = true
|
||||
|
@ -54,6 +54,7 @@
|
||||
:default-sort="defaultSort"
|
||||
:store="store"
|
||||
:append-filter-panel-to="appendFilterPanelTo"
|
||||
:allow-drag-last-column="allowDragLastColumn"
|
||||
@set-drag-visible="setDragVisible"
|
||||
/>
|
||||
</table>
|
||||
@ -401,6 +402,10 @@ export default defineComponent({
|
||||
* @description set vertical scroll position
|
||||
*/
|
||||
setScrollTop,
|
||||
/**
|
||||
* @description whether to allow drag the last column
|
||||
*/
|
||||
allowDragLastColumn: props.allowDragLastColumn,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -395,6 +395,13 @@ export default {
|
||||
type: [Number, String],
|
||||
default: undefined,
|
||||
},
|
||||
/**
|
||||
* @description whether to allow drag the last column
|
||||
*/
|
||||
allowDragLastColumn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
}
|
||||
export type {
|
||||
SummaryMethod,
|
||||
|
@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { createVNode, render } from 'vue'
|
||||
import { flatMap, get, merge } from 'lodash-unified'
|
||||
import { flatMap, get, isNull, merge } from 'lodash-unified'
|
||||
import {
|
||||
hasOwn,
|
||||
isArray,
|
||||
@ -9,6 +9,7 @@ import {
|
||||
isNumber,
|
||||
isObject,
|
||||
isString,
|
||||
isUndefined,
|
||||
throwError,
|
||||
} from '@element-plus/utils'
|
||||
import ElTooltip, {
|
||||
@ -206,7 +207,7 @@ export function mergeOptions<T, K>(defaults: T, config: K): T & K {
|
||||
for (key in config) {
|
||||
if (hasOwn(config as unknown as Record<string, any>, key)) {
|
||||
const value = config[key]
|
||||
if (typeof value !== 'undefined') {
|
||||
if (!isUndefined(value)) {
|
||||
options[key] = value
|
||||
}
|
||||
}
|
||||
@ -216,7 +217,7 @@ export function mergeOptions<T, K>(defaults: T, config: K): T & K {
|
||||
|
||||
export function parseWidth(width: number | string): number | string {
|
||||
if (width === '') return width
|
||||
if (width !== undefined) {
|
||||
if (!isUndefined(width)) {
|
||||
width = Number.parseInt(width as string, 10)
|
||||
if (Number.isNaN(width)) {
|
||||
width = ''
|
||||
@ -227,7 +228,7 @@ export function parseWidth(width: number | string): number | string {
|
||||
|
||||
export function parseMinWidth(minWidth: number | string): number | string {
|
||||
if (minWidth === '') return minWidth
|
||||
if (minWidth !== undefined) {
|
||||
if (!isUndefined(minWidth)) {
|
||||
minWidth = parseWidth(minWidth)
|
||||
if (Number.isNaN(minWidth)) {
|
||||
minWidth = 80
|
||||
@ -525,7 +526,7 @@ export const getFixedColumnsClass = <T>(
|
||||
function getOffset<T>(offset: number, column: TableColumnCtx<T>) {
|
||||
return (
|
||||
offset +
|
||||
(column.realWidth === null || Number.isNaN(column.realWidth)
|
||||
(isNull(column.realWidth) || Number.isNaN(column.realWidth)
|
||||
? Number(column.width)
|
||||
: column.realWidth)
|
||||
)
|
||||
|
@ -49,6 +49,7 @@ import { useNamespace, usePopperContainerId } from '@element-plus/hooks'
|
||||
import { composeEventHandlers } from '@element-plus/utils'
|
||||
import { ElPopperContent } from '@element-plus/components/popper'
|
||||
import ElTeleport from '@element-plus/components/teleport'
|
||||
import { tryFocus } from '@element-plus/components/focus-trap'
|
||||
import { TOOLTIP_INJECTION_KEY } from './constants'
|
||||
import { useTooltipContentProps } from './content'
|
||||
import type { PopperContentInstance } from '@element-plus/components/popper'
|
||||
@ -111,6 +112,7 @@ const ariaHidden = ref(true)
|
||||
|
||||
const onTransitionLeave = () => {
|
||||
onHide()
|
||||
isFocusInsideContent() && tryFocus(document.body)
|
||||
ariaHidden.value = true
|
||||
}
|
||||
|
||||
@ -161,6 +163,14 @@ const onBlur = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const isFocusInsideContent = (event?: FocusEvent) => {
|
||||
const popperContent: HTMLElement | undefined =
|
||||
contentRef.value?.popperContentRef
|
||||
const activeElement = (event?.relatedTarget as Node) || document.activeElement
|
||||
|
||||
return popperContent?.contains(activeElement)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => unref(open),
|
||||
(val) => {
|
||||
@ -187,5 +197,9 @@ defineExpose({
|
||||
* @description el-popper-content component instance
|
||||
*/
|
||||
contentRef,
|
||||
/**
|
||||
* @description validate current focus event is trigger inside el-popper-content
|
||||
*/
|
||||
isFocusInsideContent,
|
||||
})
|
||||
</script>
|
||||
|
@ -72,6 +72,7 @@ import ElTooltipTrigger from './trigger.vue'
|
||||
import ElTooltipContent from './content.vue'
|
||||
import type { TooltipContentInstance } from './content'
|
||||
import type { PopperInstance } from '@element-plus/components/popper'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'ElTooltip',
|
||||
@ -155,16 +156,20 @@ watch(
|
||||
)
|
||||
|
||||
const isFocusInsideContent = (event?: FocusEvent) => {
|
||||
const popperContent: HTMLElement | undefined =
|
||||
contentRef.value?.contentRef?.popperContentRef
|
||||
const activeElement = (event?.relatedTarget as Node) || document.activeElement
|
||||
|
||||
return popperContent && popperContent.contains(activeElement)
|
||||
return contentRef.value?.isFocusInsideContent(event)
|
||||
}
|
||||
|
||||
onDeactivated(() => open.value && hide())
|
||||
|
||||
defineExpose({
|
||||
defineExpose<{
|
||||
popperRef: Ref<PopperInstance | undefined>
|
||||
contentRef: Ref<TooltipContentInstance | undefined>
|
||||
isFocusInsideContent: (event?: FocusEvent) => boolean | undefined
|
||||
updatePopper: () => void
|
||||
onOpen: (event?: Event) => void
|
||||
onClose: (event?: Event) => void
|
||||
hide: () => void
|
||||
}>({
|
||||
/**
|
||||
* @description el-popper component instance
|
||||
*/
|
||||
|
@ -82,6 +82,7 @@ import type {
|
||||
TransferDirection,
|
||||
} from './transfer'
|
||||
import type { TransferPanelInstance } from './transfer-panel'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'ElTransfer',
|
||||
@ -164,7 +165,11 @@ const optionRender = computed(() => (option: TransferDataItem) => {
|
||||
)
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
defineExpose<{
|
||||
clearQuery: (which: TransferDirection) => void
|
||||
leftPanel: Ref<TransferPanelInstance | undefined>
|
||||
rightPanel: Ref<TransferPanelInstance | undefined>
|
||||
}>({
|
||||
/** @description clear the filter keyword of a certain panel */
|
||||
clearQuery,
|
||||
/** @description left panel ref */
|
||||
|
@ -53,7 +53,7 @@ export const useHandlers = (
|
||||
|
||||
function removeFile(file: UploadFile) {
|
||||
uploadFiles.value = uploadFiles.value.filter(
|
||||
(uploadFile) => uploadFile !== file
|
||||
(uploadFile) => uploadFile.uid !== file.uid
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -271,6 +271,7 @@ $color-picker-size: map.merge($common-component-size, $color-picker-size);
|
||||
}
|
||||
|
||||
@include when(disabled) {
|
||||
pointer-events: none;
|
||||
.#{$namespace}-color-picker__trigger {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
@ -924,6 +924,7 @@ $input-tag: () !default;
|
||||
$input-tag: map.merge(
|
||||
(
|
||||
'border-color-hover': getCssVar('border-color-hover'),
|
||||
'placeholder-color': getCssVar('text-color-placeholder'),
|
||||
'disabled-color': getCssVar('disabled-text-color'),
|
||||
'disabled-border': getCssVar('disabled-border-color'),
|
||||
'font-size': getCssVar('font-size-base'),
|
||||
|
@ -189,6 +189,7 @@
|
||||
border-color: map.get($input-disabled, 'border');
|
||||
color: map.get($input-disabled, 'text-color');
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
|
@ -103,6 +103,14 @@
|
||||
font-size: map.get($input-font-size, $size);
|
||||
}
|
||||
|
||||
@include when(controls-right) {
|
||||
.#{$namespace}-input--#{$size} {
|
||||
.#{$namespace}-input__wrapper {
|
||||
padding-right: #{map.get($input-height, $size) + 7};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.#{$namespace}-input--#{$size} {
|
||||
.#{$namespace}-input__wrapper {
|
||||
padding-left: #{map.get($input-height, $size) + 7};
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
@include when(disabled) {
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
background-color: getCssVar('fill-color', 'light');
|
||||
@include mixed-input-border(#{getCssVar('input-tag-disabled-border')});
|
||||
|
||||
@ -169,6 +170,10 @@
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
|
||||
&::placeholder {
|
||||
color: getCssVar('input-tag-placeholder-color');
|
||||
}
|
||||
}
|
||||
|
||||
@include e(input-calculator) {
|
||||
|
@ -199,7 +199,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include e(inner) {
|
||||
& {
|
||||
// use map.get as default value for date picker range
|
||||
@include set-css-var-value(
|
||||
'input-inner-height',
|
||||
@ -210,7 +210,9 @@
|
||||
) - $border-width * 2
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@include e(inner) {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
-webkit-appearance: none;
|
||||
@ -255,6 +257,7 @@
|
||||
flex-shrink: 0;
|
||||
flex-wrap: nowrap;
|
||||
height: 100%;
|
||||
line-height: getCssVar('input-inner-height');
|
||||
text-align: center;
|
||||
color: var(
|
||||
#{getCssVarName('input-icon-color')},
|
||||
@ -320,6 +323,7 @@
|
||||
.#{$namespace}-input__wrapper {
|
||||
background-color: map.get($input-disabled, 'fill');
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
@include mixed-input-border(map.get($input-disabled, 'border'));
|
||||
}
|
||||
|
||||
@ -359,8 +363,7 @@
|
||||
@include e(wrapper) {
|
||||
padding: $border-width map.get($input-padding-horizontal, $size)-$border-width;
|
||||
}
|
||||
|
||||
@include e(inner) {
|
||||
& {
|
||||
@include set-css-var-value(
|
||||
'input-inner-height',
|
||||
calc(
|
||||
|
@ -15,6 +15,10 @@
|
||||
map.get($mention, 'shadow')
|
||||
);
|
||||
}
|
||||
|
||||
@include when(disabled) {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include b(mention-dropdown) {
|
||||
|
@ -34,6 +34,8 @@
|
||||
}
|
||||
|
||||
@include e(group) {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: getCssVar('notification-group-margin-left');
|
||||
margin-right: getCssVar('notification-group-margin-right');
|
||||
}
|
||||
@ -58,6 +60,7 @@
|
||||
}
|
||||
|
||||
& .#{$namespace}-notification__icon {
|
||||
flex-shrink: 0;
|
||||
height: getCssVar('notification-icon-size');
|
||||
width: getCssVar('notification-icon-size');
|
||||
font-size: getCssVar('notification-icon-size');
|
||||
|
@ -56,6 +56,7 @@
|
||||
|
||||
@include when(disabled) {
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
|
||||
background-color: getCssVar('fill-color', 'light');
|
||||
color: getCssVar('text-color', 'placeholder');
|
||||
@ -158,6 +159,7 @@
|
||||
|
||||
@include e(placeholder) {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
display: block;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
@ -183,7 +185,7 @@
|
||||
}
|
||||
|
||||
@include e(input-wrapper) {
|
||||
max-width: 100%;
|
||||
flex: 1;
|
||||
|
||||
@include when(hidden) {
|
||||
// Out of the document flow
|
||||
@ -201,7 +203,7 @@
|
||||
font-family: inherit;
|
||||
appearance: none;
|
||||
height: map.get($select-item-height, 'default');
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
|
||||
@include when(disabled) {
|
||||
|
109
pnpm-lock.yaml
generated
109
pnpm-lock.yaml
generated
@ -256,8 +256,8 @@ importers:
|
||||
version: 0.2.0
|
||||
devDependencies:
|
||||
'@crowdin/cli':
|
||||
specifier: ^3.7.10
|
||||
version: 3.14.0
|
||||
specifier: ^4.5.0
|
||||
version: 4.5.0
|
||||
'@docsearch/react':
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@ -1183,8 +1183,8 @@ packages:
|
||||
resolution: {integrity: sha512-gwRLBLra/Dozj2OywopeuHj2ac26gjGkz2cZ+86cTJOdtWfiRRr4+e77ZDAGc6MDWxaWheI+mAV5TLWWRwqrFg==}
|
||||
engines: {node: '>=v18'}
|
||||
|
||||
'@crowdin/cli@3.14.0':
|
||||
resolution: {integrity: sha512-8MnJvGPkrLprrpLT+jPgBn7aKdv/8eyxLXMN929qYadDy7ZjZiB2CzlTvdGh4DUBoMOr/anoYWDhn9kxP0fn/Q==}
|
||||
'@crowdin/cli@4.5.0':
|
||||
resolution: {integrity: sha512-faj84fCXT8GcM0CwZ6KuXQ6ckwRHj2OKFFib048RobykRoMFJxXJnu6P/OBjWpcqFFbxWJB0QL0VkS42hqdMng==}
|
||||
hasBin: true
|
||||
|
||||
'@ctrl/tinycolor@3.4.1':
|
||||
@ -3635,6 +3635,10 @@ packages:
|
||||
chownr@1.1.4:
|
||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||
|
||||
chownr@2.0.0:
|
||||
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
ci-info@3.3.2:
|
||||
resolution: {integrity: sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==}
|
||||
|
||||
@ -4792,8 +4796,9 @@ packages:
|
||||
resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==}
|
||||
engines: {node: '>=14.14'}
|
||||
|
||||
fs-minipass@1.2.7:
|
||||
resolution: {integrity: sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==}
|
||||
fs-minipass@2.1.0:
|
||||
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
fs-mkdirp-stream@1.0.0:
|
||||
resolution: {integrity: sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==}
|
||||
@ -5972,8 +5977,13 @@ packages:
|
||||
minimist@1.2.6:
|
||||
resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==}
|
||||
|
||||
minipass@2.9.0:
|
||||
resolution: {integrity: sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==}
|
||||
minipass@3.3.6:
|
||||
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
minipass@5.0.0:
|
||||
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
minipass@7.1.2:
|
||||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||
@ -5982,8 +5992,9 @@ packages:
|
||||
minisearch@6.3.0:
|
||||
resolution: {integrity: sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==}
|
||||
|
||||
minizlib@1.3.3:
|
||||
resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==}
|
||||
minizlib@2.1.2:
|
||||
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
mitt@3.0.1:
|
||||
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
|
||||
@ -5995,8 +6006,9 @@ packages:
|
||||
mkdirp-classic@0.5.3:
|
||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||
|
||||
mkdirp@0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
mkdirp@1.0.4:
|
||||
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
mkdist@1.5.3:
|
||||
@ -6076,6 +6088,15 @@ packages:
|
||||
encoding:
|
||||
optional: true
|
||||
|
||||
node-fetch@2.7.0:
|
||||
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
|
||||
node-releases@2.0.14:
|
||||
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
|
||||
|
||||
@ -7530,9 +7551,9 @@ packages:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
tar@4.4.19:
|
||||
resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==}
|
||||
engines: {node: '>=4.5'}
|
||||
tar@6.2.1:
|
||||
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
terser@5.36.0:
|
||||
resolution: {integrity: sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==}
|
||||
@ -8389,6 +8410,10 @@ packages:
|
||||
yauzl@2.10.0:
|
||||
resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
|
||||
|
||||
yauzl@3.2.0:
|
||||
resolution: {integrity: sha512-Ow9nuGZE+qp1u4JIPvg+uCiUr7xGQWdff7JQSk5VGYTAZMDe2q8lxJ10ygv10qmSj031Ty/6FNJpLO4o1Sgc+w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yocto-queue@0.1.0:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
@ -9190,13 +9215,13 @@ snapshots:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
|
||||
'@crowdin/cli@3.14.0':
|
||||
'@crowdin/cli@4.5.0':
|
||||
dependencies:
|
||||
command-exists-promise: 2.0.2
|
||||
node-fetch: 2.6.7
|
||||
node-fetch: 2.7.0
|
||||
shelljs: 0.8.5
|
||||
tar: 4.4.19
|
||||
yauzl: 2.10.0
|
||||
tar: 6.2.1
|
||||
yauzl: 3.2.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
@ -12141,6 +12166,8 @@ snapshots:
|
||||
|
||||
chownr@1.1.4: {}
|
||||
|
||||
chownr@2.0.0: {}
|
||||
|
||||
ci-info@3.3.2: {}
|
||||
|
||||
citty@0.1.6:
|
||||
@ -13484,9 +13511,9 @@ snapshots:
|
||||
jsonfile: 6.1.0
|
||||
universalify: 2.0.1
|
||||
|
||||
fs-minipass@1.2.7:
|
||||
fs-minipass@2.1.0:
|
||||
dependencies:
|
||||
minipass: 2.9.0
|
||||
minipass: 3.3.6
|
||||
|
||||
fs-mkdirp-stream@1.0.0:
|
||||
dependencies:
|
||||
@ -14714,18 +14741,20 @@ snapshots:
|
||||
|
||||
minimist@1.2.6: {}
|
||||
|
||||
minipass@2.9.0:
|
||||
minipass@3.3.6:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
yallist: 3.1.1
|
||||
yallist: 4.0.0
|
||||
|
||||
minipass@5.0.0: {}
|
||||
|
||||
minipass@7.1.2: {}
|
||||
|
||||
minisearch@6.3.0: {}
|
||||
|
||||
minizlib@1.3.3:
|
||||
minizlib@2.1.2:
|
||||
dependencies:
|
||||
minipass: 2.9.0
|
||||
minipass: 3.3.6
|
||||
yallist: 4.0.0
|
||||
|
||||
mitt@3.0.1: {}
|
||||
|
||||
@ -14736,9 +14765,7 @@ snapshots:
|
||||
|
||||
mkdirp-classic@0.5.3: {}
|
||||
|
||||
mkdirp@0.5.6:
|
||||
dependencies:
|
||||
minimist: 1.2.6
|
||||
mkdirp@1.0.4: {}
|
||||
|
||||
mkdist@1.5.3(sass@1.79.3)(typescript@5.5.4)(vue-tsc@2.1.6(typescript@5.5.4)):
|
||||
dependencies:
|
||||
@ -14822,6 +14849,10 @@ snapshots:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
node-fetch@2.7.0:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
node-releases@2.0.14: {}
|
||||
|
||||
node-releases@2.0.18: {}
|
||||
@ -16299,15 +16330,14 @@ snapshots:
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.0
|
||||
|
||||
tar@4.4.19:
|
||||
tar@6.2.1:
|
||||
dependencies:
|
||||
chownr: 1.1.4
|
||||
fs-minipass: 1.2.7
|
||||
minipass: 2.9.0
|
||||
minizlib: 1.3.3
|
||||
mkdirp: 0.5.6
|
||||
safe-buffer: 5.2.1
|
||||
yallist: 3.1.1
|
||||
chownr: 2.0.0
|
||||
fs-minipass: 2.1.0
|
||||
minipass: 5.0.0
|
||||
minizlib: 2.1.2
|
||||
mkdirp: 1.0.4
|
||||
yallist: 4.0.0
|
||||
|
||||
terser@5.36.0:
|
||||
dependencies:
|
||||
@ -17368,4 +17398,9 @@ snapshots:
|
||||
buffer-crc32: 0.2.13
|
||||
fd-slicer: 1.1.0
|
||||
|
||||
yauzl@3.2.0:
|
||||
dependencies:
|
||||
buffer-crc32: 0.2.13
|
||||
pend: 1.2.0
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
@ -14,11 +14,15 @@ const demoRoot = path.resolve(testRoot, 'cases')
|
||||
describe('Cypress Button', () => {
|
||||
let browser: Browser
|
||||
beforeAll(async () => {
|
||||
browser = await puppeteer.launch()
|
||||
browser = await puppeteer.launch({
|
||||
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
browser.close()
|
||||
if (browser) {
|
||||
browser.close()
|
||||
}
|
||||
})
|
||||
|
||||
describe('when initialized', () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user