Skip to content
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

fix(comp:select): responsive maxLabel size calculation error #1647

Merged
merged 1 commit into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions packages/cdk/utils/src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ export type EventTarget = HTMLElement | Document | Window | null | undefined

export type Dimensions = { [key in 'width' | 'height']: number }

export interface BoxSizingData {
boxSizing: 'border-box' | 'padding-box' | 'content-box'
paddingTop: number
paddingBottom: number
paddingLeft: number
paddingRight: number
borderTop: number
borderBottom: number
borderLeft: number
borderRight: number
}

export function on<K extends keyof HTMLElementEventMap>(
el: EventTarget,
type: K | undefined,
Expand Down Expand Up @@ -155,10 +167,16 @@ export function getMouseClientXY(evt: MouseEvent | TouchEvent): { clientX: numbe
return { clientX, clientY }
}

function parseSize(size: string): number {
const parsedSize = parseFloat(size)

return Number.isNaN(parsedSize) ? 0 : parsedSize
}

export function getCssDimensions(element: HTMLElement): Dimensions & { fallback: boolean } {
const css = getComputedStyle(element)
let width = parseFloat(css.width)
let height = parseFloat(css.height)
let width = parseSize(css.width)
let height = parseSize(css.height)
const offsetWidth = element.offsetWidth
const offsetHeight = element.offsetHeight
const shouldFallback = Math.round(width) !== offsetWidth || Math.round(height) !== offsetHeight
Expand All @@ -174,3 +192,27 @@ export function getCssDimensions(element: HTMLElement): Dimensions & { fallback:
fallback: shouldFallback,
}
}

export function getBoxSizingData(node: HTMLElement): BoxSizingData {
const css = window.getComputedStyle(node)

return (
[
'paddingTop',
'paddingBottom',
'paddingLeft',
'paddingRight',
'borderTop',
'borderBottom',
'borderLeft',
'borderRight',
] as const
).reduce(
(data, key) => {
data[key] = parseSize(css[key])

return data
},
{ boxSizing: css.boxSizing } as BoxSizingData,
)
}
2 changes: 1 addition & 1 deletion packages/components/_private/overflow/src/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default defineComponent({
props: overflowItemProps,
setup(props, { slots }) {
const itemElRef = ref<HTMLElement | undefined>()
const handleResize = (entry: ResizeObserverEntry) => callEmit(props.onSizeChange, entry.target, props.itemKey ?? '')
const handleResize = (entry: ResizeObserverEntry) => callEmit(props.onSizeChange, entry, props.itemKey ?? '')
useResizeObserver(itemElRef, handleResize)

return () => {
Expand Down
36 changes: 26 additions & 10 deletions packages/components/_private/overflow/src/Overflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Ref, computed, defineComponent, ref, watch } from 'vue'
import { isNumber } from 'lodash-es'

import { useResizeObserver } from '@idux/cdk/resize'
import { throwError } from '@idux/cdk/utils'
import { getBoxSizingData, throwError } from '@idux/cdk/utils'
import { useGlobalConfig } from '@idux/components/config'

import Item from './Item'
Expand Down Expand Up @@ -73,9 +73,10 @@ export default defineComponent({
return
}

const internalContainerWidth = containerWidth.value - suffixWidth.value

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

// break when item is not ready
Expand Down Expand Up @@ -126,7 +127,7 @@ export default defineComponent({
key={key}
itemKey={key}
display={index < displayCount.value}
onSizeChange={(itemEl: Element, key?: VKey) => setItemWidth(key!, itemEl)}
onSizeChange={(entry, key) => setItemWidth(key!, entry)}
>
{nodeContent}
</Item>
Expand All @@ -141,7 +142,7 @@ export default defineComponent({
class={`${mergedPrefixCls.value}-rest`}
itemKey={restNodeKey}
display={displayRest.value}
onSizeChange={(itemEl: Element) => (restWidth.value = itemEl.clientWidth ?? 0)}
onSizeChange={({ contentRect }) => (restWidth.value = contentRect.width ?? 0)}
>
{nodeContent}
</Item>
Expand All @@ -155,7 +156,7 @@ export default defineComponent({
{...itemSharedProps}
class={`${mergedPrefixCls.value}-suffix`}
itemKey={suffixNodeKey}
onSizeChange={(itemEl: Element) => (suffixWidth.value = itemEl.clientWidth ?? 0)}
onSizeChange={({ contentRect }) => (suffixWidth.value = contentRect.width ?? 0)}
>
{nodeContent}
</Item>
Expand All @@ -175,8 +176,19 @@ export default defineComponent({

const useContainerSize = (containerElRef: Ref<HTMLElement | undefined>) => {
const containerWidth = ref(0)
const _getContainerWidth = () => {
const containerEl = containerElRef.value
if (!containerEl) {
return 0
}

const { width } = containerEl.getBoundingClientRect()
const { paddingLeft, paddingRight } = getBoxSizingData(containerEl)

return width - paddingLeft - paddingRight
}
const setContainerWidth = () => {
containerWidth.value = containerElRef.value?.clientWidth ?? 0
containerWidth.value = _getContainerWidth()
}

return {
Expand All @@ -187,11 +199,15 @@ const useContainerSize = (containerElRef: Ref<HTMLElement | undefined>) => {

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

Expand Down
2 changes: 1 addition & 1 deletion packages/components/_private/overflow/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const overflowItemProps = {
required: true,
},
data: Object as PropType<ItemData>,
onSizeChange: Function as PropType<(itemEl: Element, key?: VKey) => void>,
onSizeChange: Function as PropType<(entry: ResizeObserverEntry, key?: VKey) => void>,
} as const

export const overflowProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function useAutoRows(
const cachedLineHeight = useLineHeight(textareaRef)
const boxSizingData = computed(() => {
if (!textareaRef.value) {
return { paddingSize: 0, borderSize: 0, boxSizing: '' } as BoxSizingData
return { paddingSize: 0, borderSize: 0, boxSizing: '' } as unknown as BoxSizingData
}

return getBoxSizingData(textareaRef.value)
Expand Down
33 changes: 8 additions & 25 deletions packages/components/textarea/src/utils/getBoxSizingData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,20 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

export interface BoxSizingData {
boxSizing: string
import { type BoxSizingData as IBoxSizingData, getBoxSizingData as _getBoxSizingData } from '@idux/cdk/utils'

export interface BoxSizingData extends IBoxSizingData {
paddingSize: number
borderSize: number
paddingTop: number
paddingBottom: number
borderTop: number
borderBottom: number
}

export function getBoxSizingData(node: HTMLElement): BoxSizingData {
const { boxSizing, paddingBottom, paddingTop, borderBottom, borderTop } = window.getComputedStyle(node)

const _paddingTop = parseSize(paddingTop)
const _paddingBottom = parseSize(paddingBottom)
const _borderTop = parseSize(borderTop)
const _borderBottom = parseSize(borderBottom)
const data = _getBoxSizingData(node)
const { paddingBottom, paddingTop, borderBottom, borderTop } = data

return {
boxSizing,
paddingSize: _paddingTop + _paddingBottom,
borderSize: _borderTop + _borderBottom,
paddingTop: _paddingTop,
paddingBottom: _paddingBottom,
borderTop: _borderTop,
borderBottom: _borderBottom,
...data,
paddingSize: paddingTop + paddingBottom,
borderSize: borderTop + borderBottom,
}
}

function parseSize(size: string): number {
const parsedSize = parseFloat(size)

return Number.isNaN(parsedSize) ? 0 : parsedSize
}