diff --git a/packages/pro/index.ts b/packages/pro/index.ts index a58f51e25..1fe30f822 100644 --- a/packages/pro/index.ts +++ b/packages/pro/index.ts @@ -9,7 +9,7 @@ import type { App, Directive } from 'vue' import { IxProForm } from '@idux/pro/form' import { IxProLayout, IxProLayoutSiderTrigger } from '@idux/pro/layout' -import { IxProSearch } from '@idux/pro/search' +import { IxProSearch, IxProSearchShortcut } from '@idux/pro/search' import { IxProTable, IxProTableLayoutTool } from '@idux/pro/table' import { IxProTextarea } from '@idux/pro/textarea' import { IxProTransfer } from '@idux/pro/transfer' @@ -28,6 +28,7 @@ const components = [ IxProTree, IxProTextarea, IxProSearch, + IxProSearchShortcut, ] const install = (app: App): void => { diff --git a/packages/pro/search/demo/CustomShortcuts.md b/packages/pro/search/demo/CustomShortcuts.md new file mode 100644 index 000000000..0ed9d6874 --- /dev/null +++ b/packages/pro/search/demo/CustomShortcuts.md @@ -0,0 +1,14 @@ +--- +order: 12 +title: + zh: 自定义快捷面板Shortcuts + en: Quick select panel shortcuts customization +--- + +## zh + +通过 `shortcuts` 插槽配合 `IxProSearchShortcut` 自定义快捷栏。 + +## en + +Customize shortcuts via slot `shortcuts` using `IxProSearchShortcut`. diff --git a/packages/pro/search/demo/CustomShortcuts.vue b/packages/pro/search/demo/CustomShortcuts.vue new file mode 100644 index 000000000..44e4d4d53 --- /dev/null +++ b/packages/pro/search/demo/CustomShortcuts.vue @@ -0,0 +1,495 @@ + + + + diff --git a/packages/pro/search/demo/QuickSelect.md b/packages/pro/search/demo/QuickSelect.md index e248f4fc2..2a65738af 100644 --- a/packages/pro/search/demo/QuickSelect.md +++ b/packages/pro/search/demo/QuickSelect.md @@ -1,5 +1,5 @@ --- -order: 0 +order: 11 title: zh: 快捷面板 en: Quick select panel diff --git a/packages/pro/search/docs/Api.zh.md b/packages/pro/search/docs/Api.zh.md index 4a3124596..121c0f965 100644 --- a/packages/pro/search/docs/Api.zh.md +++ b/packages/pro/search/docs/Api.zh.md @@ -35,6 +35,10 @@ | 名称 | 说明 | 参数类型 | 备注 | | --- | --- | --- | --- | | `clearIcon` | 清除图标 | - | - | +| `shortcuts` | 快捷面板快捷栏 | `SearchField[]` | 参数为默认可支持快捷创建搜索项的field数组 | +| `shortcut` | 快捷标签 | `SearchField` | 自定义单个快捷标签 | +| `shortcutLabel` | 快捷标签文字 | `SearchField` | 自定义单个快捷标签文字 | +| `shortcutIcon` | 快捷标签图标 | `SearchField` | 自定义单个快捷标签图标 | ```typescript interface SearchValue { @@ -275,3 +279,22 @@ interface PanelRenderContext { setOnKeyDown: (onKeyDown: ((evt: KeyboardEvent) => boolean) | undefined) => void // 设置 `keydown` 回调函数 } ``` + +### IxProSearchShortcut + +快捷标签组件,用于自定义快捷栏的展示,但仅可以在 `IxProSearch` 下使用。 + +#### ProSearchShortcutProps + +| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 | +| --- | --- | --- | --- | --- | --- | +| `fieldKey` | 快捷标签对应的fieldKey | `VKey` | - | - | - | +| `icon` | 快捷标签图标 | `string` | - | - | 默认为field中的`icon`属性 | + +#### ProSearchShortcutSlots + +| 名称 | 说明 | 参数类型 | 备注 | +| --- | --- | --- | --- | +| `default` | 快捷标签 | `SearchField` | 自定义单个快捷标签 | +| `label` | 快捷标签文字 | `SearchField` | 自定义单个快捷标签文字 | +| `icon` | 快捷标签图标 | `SearchField` | 自定义单个快捷标签图标 | diff --git a/packages/pro/search/index.ts b/packages/pro/search/index.ts index a92736d0e..b02d3187a 100644 --- a/packages/pro/search/index.ts +++ b/packages/pro/search/index.ts @@ -5,18 +5,23 @@ * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE */ -import type { ProSearchComponent } from './src/types' +import type { ProSearchComponent, ProSearchShortcutComponent } from './src/types' import ProSearch from './src/ProSearch' +import ProSearchShortcut from './src/components/quickSelect/QuickSelectShortcut' const IxProSearch = ProSearch as unknown as ProSearchComponent +const IxProSearchShortcut = ProSearchShortcut as unknown as ProSearchShortcutComponent -export { IxProSearch } +export { IxProSearch, IxProSearchShortcut } export type { ProSearchInstance, ProSearchComponent, ProSearchPublicProps as ProSearchProps, + ProSearchShortcutInstance, + ProSearchShortcutComponent, + ProSearchShortcutPublicProps as ProSearchShortcutProps, SearchField, SearchValue, SearchItemError, diff --git a/packages/pro/search/src/components/quickSelect/QuickSelectPanel.tsx b/packages/pro/search/src/components/quickSelect/QuickSelectPanel.tsx index ace340d1e..f6c47537a 100644 --- a/packages/pro/search/src/components/quickSelect/QuickSelectPanel.tsx +++ b/packages/pro/search/src/components/quickSelect/QuickSelectPanel.tsx @@ -7,7 +7,9 @@ import type { ResolvedSearchField } from '../../types' -import { computed, defineComponent, inject } from 'vue' +import { type VNodeChild, computed, defineComponent, inject } from 'vue' + +import { isEmptyNode } from '@idux/cdk/utils' import QuickSelectPanelItem from './QuickSelectItem' import QuickSelectPanelShortcut from './QuickSelectShortcut' @@ -42,18 +44,30 @@ export default defineComponent({ } } + const renderShortcuts = (prefixCls: string) => { + let content: VNodeChild + if (slots.shortcuts) { + content = slots.shortcuts?.(separatedFields.value.shortcutFields) + } else if (separatedFields.value.shortcutFields.length) { + const shortcutSlots = { + default: slots.shortcut, + label: slots.shortcutLabel, + icon: slots.shortcutIcon, + } + content = separatedFields.value.shortcutFields.map(field => ( + + )) + } + + return !isEmptyNode(content) ?
{content}
: null + } + return () => { const prefixCls = `${mergedPrefixCls.value}-quick-select-panel` return (
- {separatedFields.value.shortcutFields.length && ( -
- {separatedFields.value.shortcutFields.map(field => ( - - ))} -
- )} + {renderShortcuts(prefixCls)} {separatedFields.value.quickSelectFields.length && (
{separatedFields.value.quickSelectFields.map((field, idx) => { diff --git a/packages/pro/search/src/components/quickSelect/QuickSelectShortcut.tsx b/packages/pro/search/src/components/quickSelect/QuickSelectShortcut.tsx index 5ba8b6019..cf6eb3934 100644 --- a/packages/pro/search/src/components/quickSelect/QuickSelectShortcut.tsx +++ b/packages/pro/search/src/components/quickSelect/QuickSelectShortcut.tsx @@ -5,20 +5,21 @@ * found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE */ -import { defineComponent, inject } from 'vue' +import { type Slot, computed, defineComponent, inject } from 'vue' -import { callEmit } from '@idux/cdk/utils' +import { callEmit, isEmptyNode } from '@idux/cdk/utils' import { IxIcon } from '@idux/components/icon' import { proSearchContext } from '../../token' -import { quickSelectPanelShortcutProps } from '../../types' +import { type SearchField, quickSelectPanelShortcutProps } from '../../types' export default defineComponent({ props: quickSelectPanelShortcutProps, - setup(props) { + setup(props, { slots }) { const { props: proSearchProps, mergedPrefixCls, + resolvedSearchFields, convertStateToValue, createSearchState, updateSearchValues, @@ -26,19 +27,20 @@ export default defineComponent({ setActiveSegment, } = inject(proSearchContext)! + const searchField = computed(() => resolvedSearchFields.value.find(field => field.key === props.fieldKey)) + const handleClick = () => { - const fieldKey = props.searchField.key - if (!props.searchField.multiple && getSearchStatesByFieldKey(fieldKey).length) { + if (!searchField.value?.multiple && getSearchStatesByFieldKey(props.fieldKey).length) { return } - const state = createSearchState(props.searchField.key) + const state = createSearchState(props.fieldKey) if (state) { updateSearchValues() callEmit(proSearchProps.onItemCreate, { ...convertStateToValue(state.key), - nameInput: props.searchField.label, + nameInput: searchField.value?.label, }) setActiveSegment({ itemKey: state.key, @@ -49,12 +51,29 @@ export default defineComponent({ return () => { const prefixCls = `${mergedPrefixCls.value}-quick-select-shortcut` + return ( - {props.searchField.icon && } - {props.searchField.label} + {slots.default?.() ?? [ + renderIcon(prefixCls, props.icon ?? searchField.value?.icon, slots.icon, searchField.value), + renderLabel(slots.label, searchField.value), + ]} ) } }, }) + +function renderIcon(prefixCls: string, icon: string | undefined, iconSlot: Slot | undefined, field?: SearchField) { + const content = iconSlot ? iconSlot(field) : icon ? : null + + return !isEmptyNode(content) ? {content} : null +} + +function renderLabel(labelSlot: Slot | undefined, field?: SearchField) { + if (labelSlot) { + return labelSlot(field) + } + + return field?.label +} diff --git a/packages/pro/search/src/types/quickSelectPanel.ts b/packages/pro/search/src/types/quickSelectPanel.ts index 60f1ef94c..98061bbc3 100644 --- a/packages/pro/search/src/types/quickSelectPanel.ts +++ b/packages/pro/search/src/types/quickSelectPanel.ts @@ -6,12 +6,21 @@ */ import type { ResolvedSearchField } from './searchFields' -import type { PropType } from 'vue' +import type { ExtractInnerPropTypes, ExtractPublicPropTypes, VKey } from '@idux/cdk/utils' +import type { DefineComponent, HTMLAttributes, PropType } from 'vue' export const quickSelectPanelItemProps = { searchField: { type: Object as PropType, required: true }, } as const export const quickSelectPanelShortcutProps = { - searchField: { type: Object as PropType, required: true }, + fieldKey: { type: [String, Number, Symbol] as PropType, required: true }, + icon: String, } as const + +export type ProSearchShortcutProps = ExtractInnerPropTypes +export type ProSearchShortcutPublicProps = ExtractPublicPropTypes +export type ProSearchShortcutComponent = DefineComponent< + Omit & ProSearchShortcutPublicProps +> +export type ProSearchShortcutInstance = InstanceType> diff --git a/packages/pro/search/style/quick-select.less b/packages/pro/search/style/quick-select.less index bfe80ede4..8f460db54 100644 --- a/packages/pro/search/style/quick-select.less +++ b/packages/pro/search/style/quick-select.less @@ -39,11 +39,16 @@ align-items: center; background-color: @color-graphite-l40; border-radius: 2px; + cursor: pointer; &:not(&:last-child) { margin-right: 8px; } - cursor: pointer; + &-icon { + font-size: 16px; + margin-right: 4px; + color: @color-graphite; + } } &-item { min-width: 220px; diff --git a/packages/pro/types.d.ts b/packages/pro/types.d.ts index 953d94c48..e59d1fd25 100644 --- a/packages/pro/types.d.ts +++ b/packages/pro/types.d.ts @@ -8,7 +8,7 @@ import type { LayoutSiderTriggerComponent } from '@idux/components/layout' import type { ProFormComponent } from '@idux/pro/form' import type { ProLayoutComponent } from '@idux/pro/layout' -import type { ProSearchComponent } from '@idux/pro/search' +import type { ProSearchComponent, ProSearchShortcutComponent } from '@idux/pro/search' import type { ProTableComponent, ProTableLayoutToolComponent } from '@idux/pro/table' import type { ProTextareaComponent } from '@idux/pro/textarea' import type { ProTransferComponent } from '@idux/pro/transfer' @@ -28,6 +28,7 @@ declare module 'vue' { IxProTransfer: ProTransferComponent IxProTree: ProTreeComponent IxProSearch: ProSearchComponent + IxProSearchShortcut: ProSearchShortcutComponent } }