-
Notifications
You must be signed in to change notification settings - Fork 332
feat(select-wrapper, base-select, tree-select, grid-select):select-wrapper mobile-first development #3881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
feat(select-wrapper, base-select, tree-select, grid-select):select-wrapper mobile-first development #3881
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| import { iconChevronDown } from '@opentiny/vue-icon' | ||
|
|
||
| export default { | ||
| // 虚拟滚动的默认options不一致 | ||
| baseOpts: { optionHeight: 34, limit: 20 }, | ||
| icons: { | ||
| dropdownIcon: iconChevronDown() | ||
| }, | ||
| state: { | ||
| sizeMap: { | ||
| default: 30, | ||
| mini: 24, | ||
| small: 36, | ||
| medium: 42 | ||
| }, | ||
| spacingHeight: 2, | ||
| initialInputHeight: 30, | ||
| // 显示清除等图标时,不隐藏下拉箭头时 | ||
| autoHideDownIcon: false, | ||
| delayBlur: true | ||
| }, | ||
| props: { | ||
| tagType: 'info', | ||
| stopPropagation: true | ||
| }, | ||
| renderless: (props, hooks, { emit }, api) => { | ||
| const state = api.state | ||
|
|
||
| return { | ||
| // 兼容不同主题输入框尺寸对应标签尺寸不一致 | ||
| computedCollapseTagSize: () => { | ||
| let size = 'small' | ||
|
|
||
| if (~['small', 'mini'].indexOf(state.selectSize)) { | ||
| size = state.selectSize | ||
| } else if (~['medium', 'default'].indexOf(state.selectSize)) { | ||
| size = 'small' | ||
| } | ||
|
|
||
| return size | ||
| }, | ||
| // 兼容显示清除图标时,是否同时显示下拉图标 | ||
| computedShowDropdownIcon: () => { | ||
| return !(props.remote && props.filterable && !props.remoteConfig.showIcon) | ||
| }, | ||
|
|
||
| // aui 的勾选未处理disabled的选项,故此放这里。 | ||
| toggleCheckAll: (filtered) => { | ||
| const getEnabledValues = (options) => { | ||
| let values = [] | ||
|
|
||
| for (let i = 0; i < options.length; i++) { | ||
| if (!options[i].state.disabled && !options[i].state.groupDisabled && options[i].state.visible) { | ||
| values.push(options[i].value) | ||
| } | ||
| } | ||
|
|
||
| return values | ||
| } | ||
|
|
||
| let value | ||
| const enabledValues = getEnabledValues(state.options) | ||
|
|
||
| if (filtered) { | ||
| if (state.filteredSelectCls === 'check' || state.filteredSelectCls === 'halfselect') { | ||
| value = Array.from(new Set([...state.modelValue, ...enabledValues])) | ||
| } else { | ||
| value = state.modelValue.filter((val) => !enabledValues.includes(val)) | ||
| } | ||
| } else { | ||
| if (state.selectCls === 'check') { | ||
| value = enabledValues | ||
| } else if (state.selectCls === 'halfselect') { | ||
| const unchecked = state.options.filter((item) => !item.state.disabled && item.state.selectCls === 'check') | ||
|
|
||
| unchecked.length ? (value = enabledValues) : (value = []) | ||
| } else if (state.selectCls === 'checked-sur') { | ||
| value = [] | ||
| } | ||
| } | ||
|
|
||
| const requiredValue = [] | ||
| if (props.multiple) { | ||
| state.options.forEach((opt) => { | ||
| if (opt.required) requiredValue.push(opt.value) | ||
| }) | ||
| } | ||
|
|
||
| if (Array.isArray(value)) { | ||
| value = requiredValue.concat(value.filter((val) => !requiredValue.find((requireVal) => requireVal === val))) | ||
| } | ||
|
|
||
| api.setSoftFocus() | ||
|
|
||
| state.isSilentBlur = true | ||
| api.updateModelValue(value) | ||
| api.directEmitChange(value) | ||
| }, | ||
| // aurora 禁用和只展示的时候都是tagText,默认主题是 isDisplayOnly 才显示tagText | ||
| computedShowTagText: () => { | ||
| return state.isDisabled || state.isDisplayOnly | ||
| }, | ||
| // aurora 禁用已选项无效果,必选不显示关闭图标 | ||
| isTagClosable: (item) => { | ||
| return !item.required | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| import { iconChevronDown, iconPlus } from '@opentiny/vue-icon' | ||
| import loadingIcon from './icon-loading.svg' | ||
|
|
||
| export default { | ||
| // 虚拟滚动的默认options不一致 | ||
| baseOpts: { optionHeight: 34, limit: 20 }, | ||
| icons: { | ||
| dropdownIcon: iconChevronDown(), | ||
| addIcon: iconPlus(), | ||
| loadingIcon | ||
| }, | ||
| state: { | ||
| sizeMap: { | ||
| default: 28, | ||
| mini: 24, | ||
| small: 28, | ||
| medium: 32 | ||
| }, | ||
| spacingHeight: 4, | ||
| initialInputHeight: 28, | ||
| // 显示清除等图标时,不隐藏下拉箭头时 | ||
| autoHideDownIcon: false, | ||
| delayBlur: true | ||
| }, | ||
| props: { | ||
| tagType: 'info', | ||
| stopPropagation: true | ||
| }, | ||
| renderless: (props, hooks, { emit }, api) => { | ||
| const state = api.state | ||
|
|
||
| return { | ||
| computedCollapseTagSize: () => { | ||
| let size = 'small' | ||
|
|
||
| if (~['small', 'mini'].indexOf(state.selectSize)) { | ||
| size = state.selectSize | ||
| } else if (~['medium', 'default'].indexOf(state.selectSize)) { | ||
| size = 'small' | ||
| } | ||
|
|
||
| return size | ||
| }, | ||
| // aui 的勾选未处理disabled的选项,故此放这里。 | ||
| toggleCheckAll: (filtered) => { | ||
| const getEnabledValues = (options) => { | ||
| let values = [] | ||
|
|
||
| for (let i = 0; i < options.length; i++) { | ||
| if (!options[i].state.disabled && !options[i].state.groupDisabled && options[i].state.visible) { | ||
| values.push(options[i].value) | ||
| } | ||
| } | ||
|
|
||
| return values | ||
| } | ||
|
|
||
| let value | ||
| const enabledValues = getEnabledValues(state.options) | ||
|
|
||
| if (filtered) { | ||
| if (state.filteredSelectCls === 'check' || state.filteredSelectCls === 'halfselect') { | ||
| value = Array.from(new Set([...state.modelValue, ...enabledValues])) | ||
| } else { | ||
| value = state.modelValue.filter((val) => !enabledValues.includes(val)) | ||
| } | ||
| } else { | ||
| if (state.selectCls === 'check') { | ||
| value = enabledValues | ||
| } else if (state.selectCls === 'halfselect') { | ||
| const unchecked = state.options.filter((item) => !item.state.disabled && item.state.selectCls === 'check') | ||
|
|
||
| unchecked.length ? (value = enabledValues) : (value = []) | ||
| } else if (state.selectCls === 'checked-sur') { | ||
| value = [] | ||
| } | ||
| } | ||
|
|
||
| const requiredValue = [] | ||
| if (props.multiple) { | ||
| state.options.forEach((opt) => { | ||
| if (opt.required) requiredValue.push(opt.value) | ||
| }) | ||
| } | ||
|
|
||
| if (Array.isArray(value)) { | ||
| value = requiredValue.concat(value.filter((val) => !requiredValue.find((requireVal) => requireVal === val))) | ||
| } | ||
|
|
||
| api.setSoftFocus() | ||
|
|
||
| state.isSilentBlur = true | ||
| api.updateModelValue(value) | ||
| api.directEmitChange(value) | ||
| }, | ||
| // aurora 禁用和只展示的时候都是tagText,默认主题是 isDisplayOnly 才显示tagText | ||
| computedShowTagText: () => { | ||
| return state.isDisabled || state.isDisplayOnly | ||
| }, | ||
| // aurora 禁用已选项无效果,必选不显示关闭图标 | ||
| isTagClosable: (item) => { | ||
| return !item.required | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,7 +12,7 @@ | |||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| import { $props, $prefix, $setup, defineComponent } from '@opentiny/vue-common' | ||||||||||||||||||||||||
| import { t } from '@opentiny/vue-locale' | ||||||||||||||||||||||||
| import template from 'virtual-template?pc' | ||||||||||||||||||||||||
| import template from 'virtual-template?pc|mobile-first' | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const $constants = { | ||||||||||||||||||||||||
| CLASS: { | ||||||||||||||||||||||||
|
|
@@ -326,9 +326,9 @@ export default defineComponent({ | |||||||||||||||||||||||
| type: Boolean, | ||||||||||||||||||||||||
| default: false | ||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||
| InputBoxType: { | ||||||||||||||||||||||||
| inputBoxType: { | ||||||||||||||||||||||||
| type: String, | ||||||||||||||||||||||||
| default: 'input', | ||||||||||||||||||||||||
| default: 'normal', | ||||||||||||||||||||||||
| validator: (value: string) => ['input', 'underline'].includes(value) | ||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||
|
Comment on lines
+329
to
333
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Default value fails prop validation. The Apply this diff to fix the validation: inputBoxType: {
type: String,
default: 'normal',
- validator: (value: string) => ['input', 'underline'].includes(value)
+ validator: (value: string) => ['normal', 'input', 'underline'].includes(value)
},Alternatively, if 'normal' should not be a valid value, change the default back to 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||
| tagType: { | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Code duplication detected between Aurora and Saas implementations.
This file is nearly identical to
packages/design/aurora/src/select-wrapper/index.ts, with only minor differences instate.sizeMapvalues and additional icons. ThetoggleCheckAllfunction (lines 45-95) is duplicated verbatim.Consider refactoring to reduce duplication:
toggleCheckAllimplementation to the shared renderless layerExample structure:
Then each theme file would only define its specific configuration values.