Skip to content

Commit

Permalink
feat(pro:search): add mutiSegment field (#1574)
Browse files Browse the repository at this point in the history
feat(pro:search): add visible and extends for custom field config
  • Loading branch information
sallerli1 committed Jul 6, 2023
1 parent 9df3f1b commit 90a1a8a
Show file tree
Hide file tree
Showing 26 changed files with 827 additions and 495 deletions.
15 changes: 7 additions & 8 deletions packages/pro/search/demo/Custom.vue
Expand Up @@ -63,16 +63,15 @@ const searchFields: SearchField[] = [
type: 'custom',
key: 'custom_input',
label: 'IP Input',
operators: ['=', '!=', 'isEmpty'],
fieldConfig: {
parse: input => {
return input.split(',').map(ip => ip.trim())
extends: 'input',
config: {
trim: false,
},
format: value => {
if (!value) {
return ''
}
return (value as string[]).join(', ')
visible: states => {
const operatorState = states.find(state => state.name === 'operator')
return operatorState?.value !== 'isEmpty'
},
},
},
Expand Down
14 changes: 14 additions & 0 deletions packages/pro/search/demo/MultiSegment.md
@@ -0,0 +1,14 @@
---
order: 31
title:
zh: 多段搜索项
en: Multi-Segment search field
---

## zh

通过 `'multiSegment'` 类型的searchField自定义搜索项。

## en

Create multi-segment custom searchField using field with type `'multiSegment'`.
85 changes: 85 additions & 0 deletions packages/pro/search/demo/MultiSegment.vue
@@ -0,0 +1,85 @@
<template>
<IxProSearch
v-model:value="searchValue"
style="width: 100%"
:searchFields="searchFields"
:onChange="onChange"
:onSearch="onSearch"
overlayContainer="demo-pro-search-custom"
/>
</template>

<script setup lang="ts">
import type { SearchField, SearchValue } from '@idux/pro/search'
import { ref } from 'vue'
const searchValue = ref<SearchValue[]>([])
const searchFields: SearchField[] = [
{
type: 'multiSegment',
key: 'multi_segment_field',
label: 'User',
defaultValue: ['is', 'evil', 'designer'],
fieldConfig: {
segments: [
{
name: 'custom:operator',
extends: 'select',
config: {
dataSource: [
{
key: 'is',
label: 'is',
},
{
key: 'is_not',
label: 'is not',
},
],
},
},
{
name: 'segment1',
extends: 'select',
config: {
dataSource: [
{
key: 'righteous',
label: 'righteous',
},
{
key: 'evil',
label: 'evil',
},
],
},
},
{
name: 'segment2',
extends: 'select',
config: {
dataSource: [
{
key: 'designer',
label: 'designer',
},
{
key: 'developer',
label: 'developer',
},
],
},
},
],
},
},
]
const onChange = (value: SearchValue[] | undefined, oldValue: SearchValue[] | undefined) => {
console.log(value, oldValue)
}
const onSearch = () => {
console.log('onSearch')
}
</script>
14 changes: 14 additions & 0 deletions packages/pro/search/docs/Api.zh.md
Expand Up @@ -247,14 +247,28 @@ CustomSearchFieldConfig

| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `name` | 自定义的段名称 | `string` | - | - | - |
| `extends` | 继承已有的类型 | `string` | - | - | 上述所有的field类型 |
| `customPanel` | 自定义面板渲染 | `string \| (context: PanelRenderContext) => VNodeChild` | - | - | 如果有面板则需要提供,类型为`string`时指代插槽名称 |
| `format` | 数据格式化函数 | `(value: unknown) => string` | - | - | 必填,用于将指定的类型转换成字符串输入 |
| `parse` | 输入解析函数 | `(input: string) => unknown | null` | - | - | 必填,用于将输入的字符串解析到指定的类型 |
| `placeholder` | 段占位符 | `string` | - | - | - |
| `visible` | 段显示隐藏控制 | `(states: SegmentState[]) => boolean` | - | - | 当前搜索项全部段的状态,返回`true`或者`false`控制段的显示隐藏 |

#### MultiSegmentSearchField

多段输入类型搜索项

| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `type` | 类型 | `'multiSegment'` | - | - | 固定为 `'multiSegment'` |
| `fieldConfig` | 配置 | `{ segments: CustomSearchFieldConfig[] }` | - | - | - |

```typescript
interface PanelRenderContext<V = unknown> {
input: string // 输入的字符串
value: V // 值
slots: Slots // 组件插槽
ok: () => void // 确认
cancel: () => void // 取消
setValue: (value: V) => void // 设置搜索值
Expand Down
37 changes: 18 additions & 19 deletions packages/pro/search/src/ProSearch.tsx
Expand Up @@ -36,9 +36,7 @@ import { useFocusedState } from './composables/useFocusedState'
import { useResolvedSearchFields } from './composables/useResolvedSearchFields'
import { useSearchItems } from './composables/useSearchItem'
import { useSearchItemErrors } from './composables/useSearchItemErrors'
import { useSearchStateWatcher } from './composables/useSearchStateWatcher'
import { useSearchStates } from './composables/useSearchStates'
import { useSearchTrigger } from './composables/useSearchTrigger'
import { useSearchValues } from './composables/useSearchValues'
import { proSearchContext } from './token'
import { type SearchItem, proSearchProps } from './types'
Expand Down Expand Up @@ -67,16 +65,22 @@ export default defineComponent({

const searchValueContext = useSearchValues(props)
const { searchValues, searchValueEmpty } = searchValueContext
const searchStateWatcherContext = useSearchStateWatcher()
const searchStateContext = useSearchStates(props, dateConfig, searchValueContext, searchStateWatcherContext)
const resolvedSearchFieldsContext = useResolvedSearchFields(props, mergedPrefixCls, dateConfig)
const { fieldKeyMap } = resolvedSearchFieldsContext
const searchStateContext = useSearchStates(props, fieldKeyMap, searchValueContext)
const { initSearchStates, clearSearchState, updateSearchValues, isSegmentVisible } = searchStateContext

const resolvedSearchFields = useResolvedSearchFields(props, slots, mergedPrefixCls, dateConfig)
const errors = useSearchItemErrors(props, searchValues)
const searchItems = useSearchItems(resolvedSearchFields, searchStateContext.searchStates, errors)
const searchTriggerContext = useSearchTrigger()
const searchItems = useSearchItems(fieldKeyMap, searchStateContext.searchStates, errors)
const elementWidth = useElementWidthMeasure(elementRef)

const activeSegmentContext = useActiveSegment(props, tempSegmentInputRef, searchItems, enableQuickSelect)
const activeSegmentContext = useActiveSegment(
props,
tempSegmentInputRef,
searchItems,
enableQuickSelect,
isSegmentVisible,
)
const commonOverlayProps = useCommonOverlayProps(props, config, componentCommon, mergedPrefixCls)
const focusStateContext = useFocusedState(props)
const { focused, bindMonitor, bindOverlayMonitor, focusVia, blurVia } = focusStateContext
Expand All @@ -95,9 +99,7 @@ export default defineComponent({
useControl(elementRef, activeSegmentContext, searchStateContext, focusStateContext)

const currentZIndex = useZIndex(toRef(props, 'zIndex'), toRef(componentCommon, 'overlayZIndex'), focused)

const { initSearchStates, clearSearchState } = searchStateContext
const { isActive, overlayOpened, quickSelectActive } = activeSegmentContext
const { isActive, overlayOpened, quickSelectActive, setTempActive, setOverlayOpened } = activeSegmentContext

watch(
() => props.value,
Expand Down Expand Up @@ -130,13 +132,12 @@ export default defineComponent({

expose({ focus, blur })

const { onSearchTrigger, triggerSearch } = searchTriggerContext
onSearchTrigger(() => {
const handleSearchBtnClick = () => {
updateSearchValues()
callEmit(props.onSearch, searchValues.value)
}, 'post')

const handleSearchBtnClick = () => {
triggerSearch()
setTempActive()
setOverlayOpened(false)
}
const handleClearBtnClick = () => {
clearSearchState()
Expand All @@ -158,13 +159,11 @@ export default defineComponent({
mergedPrefixCls,
enableQuickSelect,
commonOverlayProps,
resolvedSearchFields,

...focusStateContext,
...searchStateContext,
...searchStateWatcherContext,
...resolvedSearchFieldsContext,
...activeSegmentContext,
...searchTriggerContext,
})

return () => {
Expand Down
6 changes: 3 additions & 3 deletions packages/pro/search/src/components/NameSelectOverlay.tsx
Expand Up @@ -32,7 +32,7 @@ export default defineComponent({
setActiveSegment,
createSearchState,
convertStateToValue,
updateSearchState,
updateSearchValues,
} = context

const overlayRef = ref<ɵOverlayInstance>()
Expand Down Expand Up @@ -81,10 +81,10 @@ export default defineComponent({
return
}

updateSearchState(searchState.key)
updateSearchValues()
setActiveSegment({
itemKey: searchState.key,
name: searchState.segmentValues[0].name,
name: searchState.segmentStates[0].name,
})

callEmit(proSearchProps.onItemCreate, {
Expand Down
4 changes: 3 additions & 1 deletion packages/pro/search/src/components/SearchItem.tsx
Expand Up @@ -49,7 +49,7 @@ export default defineComponent({

const segmentStateContext = useSegmentStates(props, proSearchProps, context, isActive)
const segmentOverlayUpdateContext = useSegmentOverlayUpdate()
const { segmentStates } = segmentStateContext
const { searchState, segmentStates } = segmentStateContext

const classes = computed(() => {
const prefixCls = itemPrefixCls.value
Expand All @@ -74,6 +74,7 @@ export default defineComponent({
input: segmentState?.input,
value: segmentState?.value,
selectionStart: segmentState?.selectionStart,
segmentVisible: segment.visible ? segment.visible(searchState.value?.segmentStates ?? []) : true,
}
})
})
Expand Down Expand Up @@ -148,6 +149,7 @@ export default defineComponent({
<Segment
key={segment.name}
v-slots={slots}
v-show={segment.segmentVisible}
itemKey={props.searchItem!.key}
input={segment.input}
value={segment.value}
Expand Down
Expand Up @@ -26,8 +26,8 @@ export default defineComponent({
createSearchState,
getSearchStatesByFieldKey,
updateSegmentValue,
updateSearchValues,
tempSegmentInputRef,
updateSearchState,
} = inject(proSearchContext)!

const searchInputRef = ref<HTMLInputElement>()
Expand Down Expand Up @@ -56,12 +56,12 @@ export default defineComponent({
const searchDataSegment = computed(() =>
props.searchField.segments.find(seg => searchDataTypes.includes(seg.name as SearchDataTypes)),
)
const searchDataSegmentValue = computed(() =>
searchState.value?.segmentValues.find(seg => searchDataTypes.includes(seg.name as SearchDataTypes)),
const searchDataSegmentState = computed(() =>
searchState.value?.segmentStates.find(seg => searchDataTypes.includes(seg.name as SearchDataTypes)),
)

const [itemValue, setItemValue] = useState<unknown>(searchDataSegmentValue.value?.value)
watch(() => searchDataSegmentValue.value?.value, setItemValue)
const [itemValue, setItemValue] = useState<unknown>(searchDataSegmentState.value?.value)
watch(() => searchDataSegmentState.value?.value, setItemValue)

const confirmValue = (value: unknown) => {
let searchStateKey = searchState.value?.key
Expand All @@ -74,17 +74,17 @@ export default defineComponent({
nameInput: props.searchField.label,
})
} else if (searchDataSegment.value?.name) {
updateSegmentValue(value, searchDataSegment.value.name, searchState.value.key)
updateSegmentValue(searchState.value.key, searchDataSegment.value.name, value)
}

updateSearchState(searchStateKey!)
updateSearchValues()
}
const setValue = (value: unknown) => {
setItemValue(value)
}
const ok = () => confirmValue(itemValue.value)
const cancel = () => {
setItemValue(searchDataSegmentValue.value?.value)
setItemValue(searchDataSegmentState.value?.value)
}
const setOnKeyDown = () => {}

Expand Down Expand Up @@ -132,6 +132,7 @@ export default defineComponent({
slots,
input: searchInput.value,
value: itemValue.value,
states: searchState.value?.segmentStates ?? [],
renderLocation: 'quick-select-panel',
ok,
cancel,
Expand Down
Expand Up @@ -21,7 +21,7 @@ export default defineComponent({
mergedPrefixCls,
convertStateToValue,
createSearchState,
updateSearchState,
updateSearchValues,
getSearchStatesByFieldKey,
setActiveSegment,
} = inject(proSearchContext)!
Expand All @@ -35,14 +35,14 @@ export default defineComponent({
const state = createSearchState(props.searchField.key)

if (state) {
updateSearchState(state.key)
updateSearchValues()
callEmit(proSearchProps.onItemCreate, {
...convertStateToValue(state.key),
nameInput: props.searchField.label,
})
setActiveSegment({
itemKey: state.key,
name: state.segmentValues[0]?.name,
name: state.segmentStates[0]?.name,
})
}
}
Expand Down

0 comments on commit 90a1a8a

Please sign in to comment.