Skip to content

Commit

Permalink
Merge pull request #2684 from XiaoMi/feature/2677(popover)
Browse files Browse the repository at this point in the history
feat(popover): #2677
  • Loading branch information
solarjoker authored Dec 1, 2023
2 parents 0f0c985 + 1c61a19 commit ce60cf7
Show file tree
Hide file tree
Showing 15 changed files with 429 additions and 13 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-socks-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hi-ui/hiui": patch
---

feat(popover): 1.气泡卡片支持 API 的方式调用;2.气泡卡片增加分割线标题
5 changes: 5 additions & 0 deletions .changeset/clean-kids-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hi-ui/container": minor
---

feat: getContainer 方法增加 customWrapper 参数,用于自定义容器节点
5 changes: 5 additions & 0 deletions .changeset/late-cars-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hi-ui/popper": patch
---

chore: 扩充 PopperOverlayProps 参数, 'closeOnOutsideClick' | 'onExited' | 'crossGap' | 'arrow' | 'disabledPortal' | 'zIndex'
5 changes: 5 additions & 0 deletions .changeset/smooth-waves-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hi-ui/popover": minor
---

feat: 1.增加 showTitleDivider api,设置后会是另外一种更紧凑的具有分割线的标题布局;2.增加以 API 的方式调用组件的能力
38 changes: 33 additions & 5 deletions packages/ui/popover/src/Popover.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { cloneElement, isValidElement, forwardRef, useMemo } from 'react'
import React, {
cloneElement,
isValidElement,
forwardRef,
useMemo,
useImperativeHandle,
} from 'react'
import { cx, getPrefixCls } from '@hi-ui/classname'
import { __DEV__, invariant } from '@hi-ui/env'
import { HiBaseHTMLProps } from '@hi-ui/core'
Expand All @@ -7,27 +13,40 @@ import { usePopover, UsePopoverProps } from './use-popover'
import { isString } from '@hi-ui/type-assertion'

const _role = 'popover'
const _prefix = getPrefixCls(_role)
export const prefix = getPrefixCls(_role)

/**
* 气泡卡片
*/
export const Popover = forwardRef<HTMLDivElement | null, PopoverProps>(
(
{
prefixCls = _prefix,
prefixCls = prefix,
innerRef,
className,
children,
title,
content,
shouldWrapChildren = false,
autoWrapChildren = true,
wrapTagName = 'span',
showTitleDivider = false,
...rest
},
ref
) => {
const { rootProps, getTriggerProps, getPopperProps, getOverlayProps } = usePopover(rest)
const {
rootProps,
getTriggerProps,
getPopperProps,
getOverlayProps,
visibleAction,
} = usePopover(rest)

useImperativeHandle(innerRef, () => ({
open: visibleAction.on,
close: visibleAction.off,
}))

const triggerMemo = useMemo(() => {
let trigger: React.ReactElement | null | undefined
Expand Down Expand Up @@ -62,7 +81,7 @@ export const Popover = forwardRef<HTMLDivElement | null, PopoverProps>(
return trigger
}, [children, getTriggerProps, autoWrapChildren, shouldWrapChildren, wrapTagName])

const cls = cx(prefixCls, className)
const cls = cx(prefixCls, showTitleDivider && `${prefixCls}--divided`, className)

return (
<>
Expand All @@ -79,6 +98,7 @@ export const Popover = forwardRef<HTMLDivElement | null, PopoverProps>(
)

export interface PopoverProps extends HiBaseHTMLProps<'div'>, UsePopoverProps {
innerRef?: React.Ref<{ open: () => void; close: () => void }>
/**
* 气泡卡片标题
*/
Expand All @@ -99,6 +119,14 @@ export interface PopoverProps extends HiBaseHTMLProps<'div'>, UsePopoverProps {
* 指定包裹 children 的标签
*/
wrapTagName?: React.ElementType<any>
/**
* 吸附的元素
*/
attachEl?: HTMLElement
/**
* 显示标题分割线
*/
showTitleDivider?: boolean
}

if (__DEV__) {
Expand Down
7 changes: 6 additions & 1 deletion packages/ui/popover/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import './styles/index.scss'

import { Popover as PurePopover } from './Popover'
import { withPopover } from './with-api'

export * from './Popover'
export { Popover as default } from './Popover'

export const Popover = withPopover(PurePopover)
export default Popover

export * from './types'
13 changes: 12 additions & 1 deletion packages/ui/popover/src/styles/popover.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ $prefix: '#{$component-prefix}-popover' !default;
padding: use-spacing(10);
border-radius: use-border-radius('lg');

&--divided {
padding-top: use-spacing(7);
}

&__title {
box-sizing: border-box;
padding-bottom: use-spacing(8);
margin-bottom: use-spacing(8);
color: use-color('gray', 700);
font-size: use-text-size('lg');
font-weight: use-text-weight('medium');
line-height: use-text-lineheight('lg');

.#{$prefix}--divided > & {
padding-bottom: use-spacing(7);
font-size: use-text-size('normal');
line-height: use-text-lineheight('normal');
border-bottom: use-border-size('normal') use-color('gray', 200);
}
}

&__content {
Expand Down
11 changes: 8 additions & 3 deletions packages/ui/popover/src/use-popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const usePopover = ({
trigger: triggerProp = 'click',
mouseEnterDelay = 100,
mouseLeaveDelay = 100,
attachEl,
...restProps
}: UsePopoverProps) => {
// TODO: 移除 popper,使用 hook 重写
Expand Down Expand Up @@ -148,12 +149,12 @@ export const usePopover = ({
return {
...popperProps,
visible,
attachEl: triggerEl,
attachEl: attachEl ?? triggerEl,
onClose: visibleAction.off,
}
}, [visible, popper, visibleAction, triggerEl])
}, [popper, visible, attachEl, triggerEl, visibleAction.off])

return { rootProps: rest, getOverlayProps, getTriggerProps, getPopperProps }
return { rootProps: rest, getOverlayProps, getTriggerProps, getPopperProps, visibleAction }
}

export interface UsePopoverProps extends PopperOverlayProps {
Expand Down Expand Up @@ -185,6 +186,10 @@ export interface UsePopoverProps extends PopperOverlayProps {
* 设置基于 reference 元素的间隙偏移量
*/
gutterGap?: number
/**
* 吸附的元素
*/
attachEl?: HTMLElement
}

export type UsePopoverReturn = ReturnType<typeof usePopover>
74 changes: 74 additions & 0 deletions packages/ui/popover/src/with-api.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { createRef, createElement } from 'react'
import { render, unmountComponentAtNode } from 'react-dom'
import * as Container from '@hi-ui/container'
import { uuid } from '@hi-ui/use-id'

import { prefix as popoverPrefix, Popover, PopoverProps } from './Popover'

const prefixCls = popoverPrefix
const selector = `.${prefixCls}-wrapper`

const popoverInstanceCache: {
[key: string]: () => void
} = {}

const open = (target: HTMLElement, { key, disabledPortal, ...rest }: PopoverApiProps) => {
if (!key) {
key = uuid()
}

const selectId = `${selector}__${key}`
let container: any = Container.getContainer(
selectId,
undefined,
(disabledPortal ? target.parentNode : undefined) as Element
)

const popoverRef = createRef<any>()

const ClonedPopover = createElement(Popover, {
innerRef: popoverRef,
container,
attachEl: target,
closeOnOutsideClick: false,
shouldWrapChildren: true,
onExited: () => {
// 卸载
if (container) {
unmountComponentAtNode(container)
Container.removeContainer(selectId)
}
container = undefined
},
...rest,
})

requestAnimationFrame(() => {
render(ClonedPopover, container)
popoverRef.current.open()
})

const close = () => {
popoverRef.current?.close()
}

if (key) {
popoverInstanceCache[key] = close
}

return key
}

const close = (key: string) => {
if (typeof popoverInstanceCache[key] === 'function') {
popoverInstanceCache[key]()
}

delete popoverInstanceCache[key]
}

export interface PopoverApiProps extends PopoverProps {}

export function withPopover(instance: typeof Popover) {
return Object.assign(instance, { open, close })
}
2 changes: 1 addition & 1 deletion packages/ui/popover/stories/basic.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const Basic = () => {
<>
<h1>Basic</h1>
<div className="popover-basic__wrap">
<Popover title={title} content={content} trigger="click">
<Popover title={title} content={content} trigger="click" onExited={() => console.log(33)}>
<Button>trigger</Button>
</Popover>
</div>
Expand Down
Loading

0 comments on commit ce60cf7

Please sign in to comment.