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

refactor: dialog #945

Merged
merged 26 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
545731c
refactor: dialog
xiaoyatong Apr 24, 2023
9cd5c91
refactor: dialog
xiaoyatong Apr 24, 2023
fb71a41
feat: 文档
xiaoyatong Apr 24, 2023
6a08882
fix: 文档
xiaoyatong Apr 26, 2023
89098cc
feat: 增加demo,支持函数式调用下 关闭对话框。
xiaoyatong Apr 26, 2023
a0108d9
fix: overlay 组件 显示声明 onclick,修订lockScroll 使用等。
xiaoyatong Apr 27, 2023
241d242
Merge branch 'jdf2e:next' into next
xiaoyatong Apr 27, 2023
5f107ad
fix: popup组件集成overlay 属性,修改taro的分类目录。
xiaoyatong Apr 27, 2023
26400c5
Merge branch 'jdf2e:next' into next
xiaoyatong Apr 27, 2023
092dc4d
fix: 修改popup demo
xiaoyatong Apr 27, 2023
e1451ba
Merge branch 'jdf2e:next' into next
xiaoyatong Apr 28, 2023
1feaabb
Merge branch 'next' into next-dialog
xiaoyatong Apr 28, 2023
7c21279
fix: 删 onclick,继承overlay
xiaoyatong Apr 28, 2023
d3f493d
fix: 适配taro
xiaoyatong Apr 28, 2023
84e66be
fix: 调整demo和文档。
xiaoyatong Apr 28, 2023
4f20de1
fix: 使用dialog 的标签时,会默认把页面锁住。已修改,只有弹出时才可以锁。
xiaoyatong Apr 28, 2023
a8d859c
feat: 增加关闭或取消前的方法调用。
xiaoyatong Apr 28, 2023
782ed2e
docs: 文档修改。
xiaoyatong Apr 28, 2023
bfe36e8
fix: 增加 默认值为true,文件命名为 小写。
xiaoyatong Apr 28, 2023
46d458a
feat: change case
xiaoyatong Apr 28, 2023
bc4931e
Delete Confirm.tsx
xiaoyatong Apr 28, 2023
7178bd7
Delete Content.taro.tsx
xiaoyatong Apr 28, 2023
de892a7
Delete Content.tsx
xiaoyatong Apr 28, 2023
14f81b3
Delete DialogWrap.taro.tsx
xiaoyatong Apr 28, 2023
4a8a2da
Delete DialogWrap.tsx
xiaoyatong Apr 28, 2023
c7fce58
docs: 修改文档
xiaoyatong Apr 28, 2023
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
15 changes: 15 additions & 0 deletions migrate-from-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,21 @@
- distance 重命名为 threshold
- 移除 isAnimation,通过 duration 设置 0 实现无动画效果
#### Dialog
- 修改 okText 为 confirmText,规范命名。
- 修改 mask 为 overlay,组件库中统一使用 Overlay 组件作为遮罩层,并使用 overlay 作为是否展示遮罩层的属性值。
- 修改 closeOnClickOverlay 为 closeOnOverlayClick,组件库统一到该属性。
- 修改 noOkBtn 为 hideConfirmButton,初始值不变,依然表示是否隐藏确认按钮,主要是为了语义化更强。
- 修改 noCancelBtn 为 hideCancelButton,初始值不变,依然表示是否隐藏取消按钮,主要是为了语义化更强。
- 修改 okBtnDisabled 为 disableConfirmButton,初始值不变,依然表示是否禁用确认按钮,主要是为了语义化更强。
- 删除 noFooter,使用 footer 统一处理,当 footer 为空时,及可替代该值。目前 noFooter 也需要手动声明是否为 noFooter;修改后需手动指出 footer={null}
- 删除 textAlign,改用样式变量 --nutui-dialog-content-text-align 或 SCSS 变量 $dialog-content-text-align 控制,默认值为 center。
- 删除 `cancelAutoClose`,改为 `beforeCancel` 和 `beforeClose` 来实现,在点击关闭或取消时,可先触发这两个方法,以确定是否要关闭弹框,如返回true,则关闭;否则不关闭。
- 修改 onOk 为 onConfirm,规范命名。
- 修改 onClosed 为 onClose,规范命名,关闭时触发。
- 修改 onClickSelf 为 onClick,语义不变,仍表示点击弹框自身时触发事件。
- 增加 overlayStyle 和 overlayClassName,用来配置 Overlay 组件样式。
- 增加 onClickOverlay,支持点击overlay时,触发事件。

#### Drag
#### Infiniteloading
#### Notify
Expand Down
64 changes: 31 additions & 33 deletions src/packages/dialog/Confirm.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,52 @@
import React from 'react'
import { Dialog } from './dialog'
import { destroyList, ConfirmProps } from './config'

import { destroyList, ConfirmProps, DialogReturnProps } from './config'
import { render as reactRender, unmount } from '@/utils/render'

function ConfirmDialog(props: ConfirmProps) {
return <Dialog {...props}>{props.content}</Dialog>
}

// 如果是消息提示型弹出框,那么只有确认按钮
export const normalizeConfig = (_config: ConfirmProps): ConfirmProps => {
if (_config.isNotice) {
let { icon } = _config
export const normalizeConfig = (config: ConfirmProps): ConfirmProps => {
if (config.isNotice) {
let { icon } = config
if (!icon && icon !== null) {
switch (_config.noticeType) {
switch (config.noticeType) {
case 'alert':
icon = ''
break
default:
break
}
}
_config.noCancelBtn = true
config.hideCancelButton = true
}
return _config
return config
}

function confirm(
const confirm = (
config: ConfirmProps,
renderFunc?: (props: ConfirmProps) => void
) {
): DialogReturnProps => {
const div = document.createElement('div')
document.body.appendChild(div)
function render(props: ConfirmProps, callback?: () => any) {
reactRender(<ConfirmDialog {...props} onCancel={onCancel} />, div)
callback && callback()
}

const renderFunction = renderFunc || render

let dialogConfig: ConfirmProps = {
...config,
visible: false,
}
const onOk = () => {
let ret
const _onOk = config.onOk || config.onConfirm
if (_onOk) {
ret = _onOk()
}

const render = (props: ConfirmProps, callback?: () => any) => {
reactRender(<ConfirmDialog {...props} onCancel={() => onCancel()} />, div)
callback && callback()
}

const renderFunction = renderFunc || render

const onConfirm = () => {
const _onConfirm = config.onConfirm || config.onConfirm
const ret = _onConfirm?.()
if (ret && ret.then) {
renderFunction(dialogConfig)
ret.then(
Expand All @@ -65,14 +63,14 @@ function confirm(
onCancel(true)
}
}

// 如果是promise,那么处理loading和加载完成关闭
dialogConfig.onOk = onOk
dialogConfig.onConfirm = onConfirm
dialogConfig = normalizeConfig(dialogConfig)

dialogConfig.visible = true
renderFunction(dialogConfig)

function destroy() {
const destroy = () => {
unmount(div)
if (div?.parentNode) {
div.parentNode.removeChild(div)
Expand All @@ -86,18 +84,18 @@ function confirm(
}
}

function onCancel(isOnOk?: boolean) {
!isOnOk && config.onCancel && config.onCancel()
const onCancel = (confirm?: boolean) => {
!confirm && config.onCancel && config.onCancel()
dialogConfig.visible = false
dialogConfig.onClosed = () => {
config.onClosed && config.onClosed()
dialogConfig.onClose = () => {
config.onClose && config.onClose()
}
renderFunction(dialogConfig, () => {
destroy()
})
}

function update(newConfig: ConfirmProps) {
const update = (newConfig: ConfirmProps) => {
dialogConfig = {
...dialogConfig,
title: config.title, // 避免 newConfig 未传递 title 时,icon 出现多个的问题
Expand All @@ -108,10 +106,10 @@ function confirm(
renderFunction(dialogConfig)
}

function close() {
const close = () => {
dialogConfig.visible = false
dialogConfig.onClosed = () => {
config.onClosed && config.onClosed()
dialogConfig.onClose = () => {
config.onClose && config.onClose()
destroy()
}
renderFunction(dialogConfig)
Expand Down
58 changes: 58 additions & 0 deletions src/packages/dialog/Content.taro.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { FunctionComponent, ReactNode, HTMLAttributes } from 'react'
import classNames from 'classnames'
import { ITouchEvent } from '@tarojs/components'

interface ContentProps {
visible: boolean
title: ReactNode
footer: ReactNode
footerDirection: string
onClick: (event: ITouchEvent) => void
}

export const Content: FunctionComponent<
Partial<ContentProps> & Omit<HTMLAttributes<HTMLDivElement>, 'onClick'>
> = (props) => {
const { visible, title, footer, footerDirection, onClick, children } = props

const classPrefix = 'nut-dialog'

const renderHeader = () => {
return title ? (
<div className={`${classPrefix}__header`}>{title}</div>
) : null
}

const renderFooter = () => {
return footer ? (
<div
className={classNames(`${classPrefix}__footer`, {
[footerDirection as any]: footerDirection,
})}
>
{footer}
</div>
) : null
}

const handleClick = (e: any) => {
onClick && onClick(e)
}

return (
<div className={`${classPrefix}__outer`} onClick={(e) => handleClick(e)}>
<div
className={classPrefix}
style={{ display: visible ? 'flex' : 'none' }}
>
{renderHeader()}
<div className={`${classPrefix}__content`}>
<>{children}</>
</div>
{renderFooter()}
</div>
</div>
)
}

Content.displayName = 'NutContent'
57 changes: 23 additions & 34 deletions src/packages/dialog/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,52 @@ import React, { FunctionComponent, ReactNode, HTMLAttributes } from 'react'
import classNames from 'classnames'

interface ContentProps {
visible?: boolean
title?: ReactNode
footer?: ReactNode
textAlign?: string
footerDirection?: string
onClickSelf?: () => void
visible: boolean
title: ReactNode
footer: ReactNode
footerDirection: string
}

export const Content: FunctionComponent<
Partial<ContentProps> & HTMLAttributes<HTMLDivElement>
> = (props) => {
const {
visible,
title,
footer,
textAlign,
footerDirection,
onClickSelf,
children,
} = props
const { visible, title, footer, footerDirection, onClick, children } = props

let headerNode: ReactNode
if (title) {
headerNode = <div className="nut-dialog__header">{title}</div>
const classPrefix = 'nut-dialog'

const renderHeader = () => {
return title ? (
<div className={`${classPrefix}__header`}>{title}</div>
) : null
}

let footerNode: ReactNode
if (footer) {
footerNode = (
const renderFooter = () => {
return footer ? (
<div
className={classNames('nut-dialog__footer', {
className={classNames(`${classPrefix}__footer`, {
[footerDirection as any]: footerDirection,
})}
>
{footer}
</div>
)
) : null
}

const handleClick = () => {
onClickSelf && onClickSelf()
const handleClick = (e: any) => {
onClick && onClick(e)
}

return (
<div className="nut-dialog__outer" onClick={handleClick}>
<div className={`${classPrefix}__outer`} onClick={(e) => handleClick(e)}>
<div
className="nut-dialog"
className={classPrefix}
style={{ display: visible ? 'flex' : 'none' }}
>
{headerNode}
<div
className="nut-dialog__content"
style={{ textAlign } as React.CSSProperties}
>
<div>{children}</div>
{renderHeader()}
<div className={`${classPrefix}__content`}>
<>{children}</>
</div>
{footerNode}
{renderFooter()}
</div>
</div>
)
Expand Down
89 changes: 89 additions & 0 deletions src/packages/dialog/DialogWrap.taro.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { FunctionComponent, HTMLAttributes } from 'react'
import { CSSTransition } from 'react-transition-group'
import { Content } from './Content.taro'
import {
OverlayProps,
defaultOverlayProps,
} from '@/packages/overlay/overlay.taro'
import { ComponentDefaults } from '@/utils/typings'
import Overlay from '@/packages/overlay/index.taro'

interface DialogWrapProps extends OverlayProps {
visible: boolean
overlay: boolean
overlayStyle: React.CSSProperties
overlayClassName: string
footer: React.ReactNode
onCancel: () => void
onClose: () => void
onClickOverlay: (e: MouseEvent) => boolean | void
}

const defaultDialogProps = {
...ComponentDefaults,
overlay: true,
overlayStyle: {},
overlayClassName: '',
onCancel: () => {},
onClose: () => {},
onClickOverlay: (e: MouseEvent) => true,
...defaultOverlayProps,
} as DialogWrapProps

export const DialogWrap: FunctionComponent<
Partial<DialogWrapProps> &
Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'content' | 'onClick'>
> = (props) => {
const {
visible,
overlay,
overlayStyle,
overlayClassName,
closeOnOverlayClick,
lockScroll,
onClose,
onCancel,
onClickOverlay,
} = props

const overlayStyles = {
...overlayStyle,
}

const onHandleClickOverlay = (e: any) => {
console.log('onClose?.()', closeOnOverlayClick)
if (closeOnOverlayClick && visible && e.target === e.currentTarget) {
const closed = onClickOverlay && onClickOverlay(e)
closed && onClose?.()
closed && onCancel?.()
}
}

return (
<>
{overlay ? (
<Overlay
style={overlayStyles}
className={overlayClassName}
visible
closeOnOverlayClick={closeOnOverlayClick}
lockScroll={lockScroll}
onClick={onHandleClickOverlay}
/>
) : null}

<CSSTransition
in={visible}
timeout={300}
classNames="fadeDialog"
unmountOnExit
appear
>
<Content {...props} visible={visible} />
</CSSTransition>
</>
)
}

DialogWrap.defaultProps = defaultDialogProps
DialogWrap.displayName = 'NutDialogWrap'
Loading