Skip to content

Commit

Permalink
feat(comp: select): maxLabelCount support responsive (#756)
Browse files Browse the repository at this point in the history
  • Loading branch information
hangboss1761 committed Mar 20, 2022
1 parent fcc8437 commit 189d803
Show file tree
Hide file tree
Showing 18 changed files with 335 additions and 195 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Overflow maxLabelCount responsive work 1`] = `
exports[`Overflow maxLabel responsive work 1`] = `
"<div class=\\"ix-overflow ix-test-overflow\\">
<div class=\\"ix-overflow-item\\">0</div>
<div class=\\"ix-overflow-item\\">1</div>
Expand All @@ -27,7 +27,7 @@ exports[`Overflow maxLabelCount responsive work 1`] = `
</div>"
`;
exports[`Overflow maxLabelCount responsive work 2`] = `
exports[`Overflow maxLabel responsive work 2`] = `
"<div class=\\"ix-overflow ix-test-overflow\\">
<div class=\\"ix-overflow-item\\">0</div>
<div class=\\"ix-overflow-item\\" style=\\"display: none;\\">1</div>
Expand All @@ -49,7 +49,7 @@ exports[`Overflow maxLabelCount responsive work 2`] = `
<div class=\\"ix-overflow-item\\" style=\\"display: none;\\">17</div>
<div class=\\"ix-overflow-item\\" style=\\"display: none;\\">18</div>
<div class=\\"ix-overflow-item\\" style=\\"display: none;\\">19</div>
<div class=\\"ix-overflow-item ix-overflow-rest\\" style=\\"display: none;\\">+ 19 ...</div>
<div class=\\"ix-overflow-item ix-overflow-rest\\" style=\\"\\">+ 19 ...</div>
<!---->
</div>"
`;
Expand Down
21 changes: 11 additions & 10 deletions packages/components/_private/overflow/__tests__/overflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Overflow', () => {
...(merge(
{
props: {
itemKey: 'key',
getKey: (item: OverflowData) => item.key,
prefixCls: 'ix-test',
dataSource: overfolwData,
},
Expand All @@ -33,39 +33,40 @@ describe('Overflow', () => {
}

renderWork<OverflowProps>(Overflow, {
props: { maxLabelCount: 4 },
props: { maxLabel: 4 },
})

renderWork<OverflowData>(Overflow, {
props: { maxLabelCount: 'responsive' },
props: { maxLabel: 'responsive' },
})

test('maxLabelCount work', async () => {
test('maxLabel work', async () => {
const wrapper = OverflowMount()

let items = wrapper.findAll('.ix-overflow-item')

expect(items.length).toBe(totalLen)

await wrapper.setProps({ maxLabelCount: 3 })
await wrapper.setProps({ maxLabel: 3 })

// [0, 1, 2, + 17 ...]
items = wrapper.findAll('.ix-overflow-item')

expect(items.length).toBe(4)
expect(items[3].text()).toBe('+ 17 ...')
expect(items[3].attributes('style')).toEqual(expect.not.stringContaining('display: none'))
})
test('maxLabelCount responsive work', async () => {
test('maxLabel responsive work', async () => {
const wrapper = OverflowMount()

expect(wrapper.html()).toMatchSnapshot()

await wrapper.setProps({ maxLabelCount: 'responsive' })
await wrapper.setProps({ maxLabel: 'responsive' })

expect(wrapper.html()).toMatchSnapshot()
})
test('item slot work', async () => {
const wrapper = OverflowMount({ props: { maxLabelCount: 2 } })
const wrapper = OverflowMount({ props: { maxLabel: 2 } })

const items = wrapper.findAll('.ix-overflow-item')

Expand All @@ -74,7 +75,7 @@ describe('Overflow', () => {
})
test('rest slot work', async () => {
const wrapper = OverflowMount({
props: { maxLabelCount: 2 },
props: { maxLabel: 2 },
slots: { rest: `<template #rest="rest">+ {{ rest.length }} more</template>` },
})

Expand All @@ -84,7 +85,7 @@ describe('Overflow', () => {
})
test('suffix slot work', async () => {
const wrapper = OverflowMount({
props: { maxLabelCount: 2 },
props: { maxLabel: 2 },
slots: { suffix: `x` },
})

Expand Down
10 changes: 7 additions & 3 deletions packages/components/_private/overflow/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import type { OverflowComponent } from './src/types'

import Overflow from './src/Overflow'

const IxOverflow = Overflow as unknown as OverflowComponent
const ɵOverflow = Overflow as unknown as OverflowComponent

export { IxOverflow }
export { ɵOverflow }

export type { OverflowInstance, OverflowComponent, OverflowPublicProps as OverflowProps } from './src/types'
export type {
OverflowInstance as ɵOverflowInstance,
OverflowComponent as ɵOverflowComponent,
OverflowPublicProps as ɵOverflowProps,
} from './src/types'
8 changes: 3 additions & 5 deletions packages/components/_private/overflow/src/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@

import { defineComponent, onBeforeUnmount, onMounted, ref } from 'vue'

import { offResize, onResize } from '@idux/cdk/utils'
import { callEmit, offResize, onResize } from '@idux/cdk/utils'

import { overflowItemProps } from './itemTypes'
import { overflowItemProps } from './types'

export default defineComponent({
name: 'IxOverflowItem',
props: overflowItemProps,
setup(props, { slots }) {
const itemElRef = ref<HTMLElement | undefined>()
const handleResize = (entry: ResizeObserverEntry) => {
props.onSizeChange?.(entry.target, props.itemKey ?? '')
}
const handleResize = (entry: ResizeObserverEntry) => callEmit(props.onSizeChange, entry.target, props.itemKey ?? '')

onMounted(() => onResize(itemElRef.value, handleResize))
onBeforeUnmount(() => {
Expand Down
91 changes: 37 additions & 54 deletions packages/components/_private/overflow/src/Overflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { OverflowProps } from './types'
import type { VKey } from '@idux/cdk/utils'

import { ComputedRef, Ref, computed, defineComponent, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { Ref, computed, defineComponent, onBeforeUnmount, onMounted, ref, watch } from 'vue'

import { isNumber, isString } from 'lodash-es'
import { isNumber } from 'lodash-es'

import { offResize, onResize, throwError } from '@idux/cdk/utils'
import { useGlobalConfig } from '@idux/components/config'
Expand All @@ -25,50 +24,6 @@ const restNodeKey = '__IDUX_OVERFLOW_REST'
const suffixNodeKey = '__IDUX_OVERFLOW_SUFFIX' as VKey
const responsive = 'responsive'

const useContainerSize = (containerElRef: Ref<HTMLElement | undefined>) => {
const containerWidth = ref(0)
const setContainerWidth = () => {
containerWidth.value = containerElRef.value?.clientWidth ?? 0
}

return {
containerWidth,
setContainerWidth,
}
}

const useItemSize = () => {
const itemsWidthMap = ref<Map<VKey, number>>(new Map())
const setItemWidth = (key: VKey, itemEl?: Element) => {
if (!itemEl && itemsWidthMap.value.get(key)) {
itemsWidthMap.value.delete(key)
} else {
itemEl?.clientWidth && itemsWidthMap.value.set(key, itemEl?.clientWidth ?? 0)
}
}

return {
itemsWidthMap,
setItemWidth,
}
}

export type GetKey = (item: unknown) => VKey

const useGetKeys = (props: OverflowProps): ComputedRef<GetKey> => {
return computed(() => {
const itemKey = props.itemKey
if (isString(itemKey)) {
return (item: unknown) => {
const key = (item as SafeAny)[itemKey]

return key
}
}
return itemKey
})
}

export default defineComponent({
name: 'IxOverflow',
props: overflowProps,
Expand All @@ -82,17 +37,16 @@ export default defineComponent({
const restWidth = ref(0)
const suffixWidth = ref(0)

const getKey = useGetKeys(props)
const displayCount = ref(props.dataSource.length)
const isResposive = computed(() => props.maxLabelCount === responsive)
const isResposive = computed(() => props.maxLabel === responsive)
const restReady = ref(false)
const showRest = computed(
() => isResposive.value || (isNumber(props.maxLabelCount) && props.dataSource.length > props.maxLabelCount),
() => isResposive.value || (isNumber(props.maxLabel) && props.dataSource.length > props.maxLabel),
)

const mergedData = computed(() => {
if (!isResposive.value) {
return props.dataSource.slice(0, props.maxLabelCount as number)
return props.dataSource.slice(0, props.maxLabel as number)
}
return props.dataSource
})
Expand All @@ -113,12 +67,13 @@ export default defineComponent({
}

if (!isResposive.value) {
displayCount.value = Math.min(props.maxLabelCount as number, len)
displayCount.value = Math.min(props.maxLabel as number, len)
restReady.value = true
return
}

for (let i = 0; i < len; i++) {
const getItemWidth = (index: number) => itemsWidthMap.value.get(getKey.value(data[index])) ?? 0
const getItemWidth = (index: number) => itemsWidthMap.value.get(props.getKey(data[index])) ?? 0
const internalContainerWidth = containerWidth.value - suffixWidth.value
const curItemWidth = getItemWidth(i)

Expand Down Expand Up @@ -168,7 +123,7 @@ export default defineComponent({
return (
<Item
{...itemSharedProps}
itemKey={getKey.value(item)}
itemKey={props.getKey(item)}
display={index < displayCount.value}
onSizeChange={(itemEl: Element, key?: VKey) => setItemWidth(key!, itemEl)}
>
Expand Down Expand Up @@ -216,3 +171,31 @@ export default defineComponent({
}
},
})

const useContainerSize = (containerElRef: Ref<HTMLElement | undefined>) => {
const containerWidth = ref(0)
const setContainerWidth = () => {
containerWidth.value = containerElRef.value?.clientWidth ?? 0
}

return {
containerWidth,
setContainerWidth,
}
}

const useItemSize = () => {
const itemsWidthMap = ref<Map<VKey, number>>(new Map())
const setItemWidth = (key: VKey, itemEl?: Element) => {
if (!itemEl && itemsWidthMap.value.get(key)) {
itemsWidthMap.value.delete(key)
} else {
itemEl?.clientWidth && itemsWidthMap.value.set(key, itemEl?.clientWidth ?? 0)
}
}

return {
itemsWidthMap,
setItemWidth,
}
}
34 changes: 0 additions & 34 deletions packages/components/_private/overflow/src/itemTypes.ts

This file was deleted.

31 changes: 23 additions & 8 deletions packages/components/_private/overflow/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,36 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import type { IxInnerPropTypes, IxPublicPropTypes } from '@idux/cdk/utils'
import type { ExtractInnerPropTypes, ExtractPublicPropTypes, VKey } from '@idux/cdk/utils'
import type { DefineComponent, HTMLAttributes } from 'vue'

import { IxPropTypes } from '@idux/cdk/utils'
import { IxPropTypes, vKeyPropDef } from '@idux/cdk/utils'

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type SafeAny = any

export interface ItemData {
key: VKey
[propName: string]: SafeAny
}

export const overflowItemProps = {
prefixCls: IxPropTypes.string.isRequired,
display: IxPropTypes.bool.def(true),
itemKey: vKeyPropDef.isRequired,
data: IxPropTypes.object<ItemData>(),
onSizeChange: IxPropTypes.func<(itemEl: Element, key?: VKey) => void>(),
}

export const overflowProps = {
maxLabelCount: IxPropTypes.oneOfType([IxPropTypes.number, IxPropTypes.oneOf(['responsive'])]).def(
Number.MAX_SAFE_INTEGER,
),
itemKey: IxPropTypes.string.isRequired,
maxLabel: IxPropTypes.oneOfType([IxPropTypes.number, IxPropTypes.oneOf(['responsive'])]).def(Number.MAX_SAFE_INTEGER),
getKey: IxPropTypes.func<(item: SafeAny) => VKey>().isRequired,
prefixCls: IxPropTypes.string.isRequired,
dataSource: IxPropTypes.array().def(() => []),
}

export type OverflowProps = IxInnerPropTypes<typeof overflowProps>
export type OverflowPublicProps = IxPublicPropTypes<typeof overflowProps>
export type OverflowProps = ExtractInnerPropTypes<typeof overflowProps>
export type OverflowItemProps = ExtractInnerPropTypes<typeof overflowItemProps>
export type OverflowPublicProps = ExtractPublicPropTypes<typeof overflowProps>
export type OverflowComponent = DefineComponent<Omit<HTMLAttributes, keyof OverflowPublicProps> & OverflowPublicProps>
export type OverflowInstance = InstanceType<DefineComponent<OverflowProps>>
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,18 @@ exports[`Pagination render work 3`] = `
<div class=\\"ix-select ix-select-single ix-select-with-suffix ix-select-md\\">
<!---->
<div class=\\"ix-select-selector\\">
<div class=\\"ix-select-selector-item\\"><span class=\\"ix-select-selector-item-label\\">10 条/页</span>
<!---->
</div>
<div class=\\"ix-select-selector-input\\"><input class=\\"ix-select-selector-input-inner\\" style=\\"opacity: 0;\\" autocomplete=\\"off\\">
<div class=\\"ix-overflow ix-select-selector-overflow\\">
<div class=\\"ix-overflow-item\\">
<div class=\\"ix-select-selector-item\\"><span class=\\"ix-select-selector-item-label\\">10 条/页</span>
<!---->
</div>
</div>
<!---->
<div class=\\"ix-overflow-item ix-overflow-suffix\\">
<div class=\\"ix-select-selector-input\\"><input class=\\"ix-select-selector-input-inner\\" style=\\"opacity: 0;\\" autocomplete=\\"off\\">
<!---->
</div>
</div>
</div>
<!---->
<div class=\\"ix-select-selector-suffix\\"><i class=\\"ix-icon ix-icon-down\\" role=\\"img\\" aria-label=\\"down\\"></i></div>
Expand Down
Loading

0 comments on commit 189d803

Please sign in to comment.