diff --git a/packages/demo/index.tsx b/packages/demo/index.tsx index cb114a5..a9506d7 100644 --- a/packages/demo/index.tsx +++ b/packages/demo/index.tsx @@ -23,5 +23,4 @@ ReactDom.createRoot(document.getElementById('root') as HTMLElement).render( - ); diff --git a/packages/demo/src/components/Card/index.mdx b/packages/demo/src/components/Card/index.mdx index df78168..f9b9c61 100644 --- a/packages/demo/src/components/Card/index.mdx +++ b/packages/demo/src/components/Card/index.mdx @@ -2,8 +2,9 @@ import Actions from './svg/index.tsx'; import More from './svg/tab.tsx'; # Card - -
默认样式
+通用卡片容器 +## 默认样式 +一个简单的卡片用法。 测试} time="19:20 2020-09-15" extra={} actions={}>
@@ -11,7 +12,8 @@ import More from './svg/tab.tsx';
-
带头像
+## 带头像 +通过avatar属性来添加头像。 多余文本} @@ -29,8 +31,8 @@ import More from './svg/tab.tsx'; 梁老师可不可以资助我一点钱钱呢啊? 不多不多的, 球球了!我好想买Airpods但是没有钱,梁老师可 - -
栅格
+## 栅格 +利用Grid属性,实现栅格布局。 } @@ -48,7 +50,8 @@ import More from './svg/tab.tsx';
足球
-
收起与展开长度
+## 收起与展开长度 +通过css变量实现展示内容的长度。 多余文本} @@ -56,7 +59,7 @@ import More from './svg/tab.tsx'; extra={} avatar={} actions={} - style={{ '--card-minLength': '5' }} + style={{ '--card-minLength': 5 }} > 我好想买Airpods但是没有钱,梁老师可不可以资助我 我好想买Airpods但是没有钱,梁老师可不可以资助我一点钱钱呢 啊?不多不多的,球球了!我好想买Airpods但 是没有钱,梁老师可不可以资助我一点钱钱呢啊?不多不多的, @@ -72,7 +75,7 @@ import More from './svg/tab.tsx'; extra={} avatar={} actions={} - style={{ '--card-maxLength': '7' }} + style={{ '--card-maxLength': 7 }} > 我好想买Airpods但是没有钱,梁老师可不可以资助我 我好想买Airpods但是没有钱,梁老师可不可以资助我一点钱钱呢 啊?不多不多的,球球了!我好想买Airpods但 是没有钱,梁老师可不可以资助我一点钱钱呢啊?不多不多的, @@ -83,7 +86,8 @@ import More from './svg/tab.tsx'; 梁老师可不可以资助我一点钱钱呢啊?不多不多的,球球了! 我好想买Airpods但是没有钱,梁老师可 -
自定义背景色和宽度
+## 自定义背景颜色和宽度 +自定义更改卡片的样式。 多余文本} @@ -101,7 +105,8 @@ import More from './svg/tab.tsx'; -
加载中
+## 加载中 +数据读入前会有文本块样式。 diff --git a/packages/demo/src/components/Modal/demo/Common.tsx b/packages/demo/src/components/Modal/demo/Common.tsx new file mode 100644 index 0000000..eaaf4d2 --- /dev/null +++ b/packages/demo/src/components/Modal/demo/Common.tsx @@ -0,0 +1,23 @@ +import { Button, Modal } from 'pivot-design'; +import React, { useState } from 'react'; +const App: React.FC = () => { + const [open, setOpen] = useState(false); + const onchange = () => { + setOpen(true); + }; + const onOk = () => { + setOpen(false); + }; + const onCancel = () => { + setOpen(false); + }; + return ( + <> + + h1这是内容 + + + + ); +}; +export default App; diff --git a/packages/demo/src/components/Modal/demo/FooterRow.tsx b/packages/demo/src/components/Modal/demo/FooterRow.tsx new file mode 100644 index 0000000..bb1ca7d --- /dev/null +++ b/packages/demo/src/components/Modal/demo/FooterRow.tsx @@ -0,0 +1,31 @@ +import { Button, Modal } from 'pivot-design'; +import React, { useState } from 'react'; +const App: React.FC = () => { + const [open, setOpen] = useState(false); + const onchange = () => { + setOpen(true); + }; + const onOk = () => { + setOpen(false); + }; + const onCancel = () => { + setOpen(false); + }; + return ( + <> + +

h1这是内容

+
+ + + ); +}; +export default App; diff --git a/packages/demo/src/components/Modal/demo/Mask.tsx b/packages/demo/src/components/Modal/demo/Mask.tsx new file mode 100644 index 0000000..0c8b671 --- /dev/null +++ b/packages/demo/src/components/Modal/demo/Mask.tsx @@ -0,0 +1,43 @@ +import { Button, Modal } from 'pivot-design'; +import React, { useState } from 'react'; +const App: React.FC = () => { + const [openOne, setOpenOne] = useState(false); + const [openSecond, setOpenSecond] = useState(false); + const onchangeOne = () => { + setOpenOne(true); + }; + const onOkOne = () => { + setOpenOne(false); + }; + const onCancelOne = () => { + setOpenOne(false); + }; + + const onchangeSecond = () => { + setOpenSecond(true); + }; + + const onCancelSecond = () => { + setOpenSecond(false); + }; + return ( + <> + + 没有蒙层 + + + + + 点击蒙层不会消失的模态框 + + + + ); +}; +export default App; diff --git a/packages/demo/src/components/Modal/demo/Position.tsx b/packages/demo/src/components/Modal/demo/Position.tsx new file mode 100644 index 0000000..abb3087 --- /dev/null +++ b/packages/demo/src/components/Modal/demo/Position.tsx @@ -0,0 +1,23 @@ +import { Button, Modal } from 'pivot-design'; +import React, { useState } from 'react'; +const App: React.FC = () => { + const [open, setOpen] = useState(false); + const onchange = () => { + setOpen(true); + }; + const onOk = () => { + setOpen(false); + }; + const onCancel = () => { + setOpen(false); + }; + return ( + <> + +

h1这是内容

+
+ + + ); +}; +export default App; diff --git a/packages/demo/src/components/Modal/demo/UseModal.tsx b/packages/demo/src/components/Modal/demo/UseModal.tsx new file mode 100644 index 0000000..17adfee --- /dev/null +++ b/packages/demo/src/components/Modal/demo/UseModal.tsx @@ -0,0 +1,18 @@ +import { Button, Modal } from 'pivot-design'; +import React from 'react'; + +const App: React.FC = () => { + return ( + + ); +}; +export default App; diff --git a/packages/demo/src/components/Modal/index.mdx b/packages/demo/src/components/Modal/index.mdx new file mode 100644 index 0000000..405b1c1 --- /dev/null +++ b/packages/demo/src/components/Modal/index.mdx @@ -0,0 +1,43 @@ +# Modal + +模态对话框组件,用于展示需要用户确认的重要信息。 + +## 基本用法 + +最基本的模态对话框用法 + + + + + +## 底部按钮组定制 + +提供自定义底部按钮,可以通过 `OkButtonProps`,`cancelButtonProps` 控制 Button,还可以传入 `footer` 来自定义模态框的底部。 + + + + + +## 弹窗出现位置 + +通过 `position` 属性,从而改变模态框的出现位置。 + + + + + +## 蒙层动作自定义 + +你可以通过给 `hasMask` 传入 `false` 来关闭模态框的蒙层。 + + + + + +## 声明式调用 + +你可以使用 `Modal.show(props)` 的方式来调起一个模态框。 + + + + diff --git a/packages/demo/src/components/Skeleton/index.mdx b/packages/demo/src/components/Skeleton/index.mdx index bc0b6fe..1d16cff 100644 --- a/packages/demo/src/components/Skeleton/index.mdx +++ b/packages/demo/src/components/Skeleton/index.mdx @@ -19,4 +19,4 @@
静态
- \ No newline at end of file + diff --git a/packages/demo/src/pages/component/index.tsx b/packages/demo/src/pages/component/index.tsx index 2b79780..ed8a60b 100644 --- a/packages/demo/src/pages/component/index.tsx +++ b/packages/demo/src/pages/component/index.tsx @@ -1,11 +1,13 @@ import { useState } from 'react'; -import { Button, Icon, Input, Skeleton, Card, Popover } from 'pivot-design'; +import { Button, Icon, Input, Skeleton, Card, Popover, Modal } from 'pivot-design'; // import router from '@/routers'; import ButtonMdx from '../../components/Button/index.mdx'; import IconMdx from '../../components/Icon/index.mdx'; import InputMdx from '../../components/Input/index.mdx'; import CardMdx from '../../components/Card/index.mdx'; import SkeletonMdx from '../../components/Skeleton/index.mdx'; +//import PopoverMdx from '@/components/Popover/index.mdx'; +import ModalMdx from '../../components/Modal/index.mdx'; import PopoverMdx from '../../components/Popover/index.mdx'; import './index.scss'; @@ -13,7 +15,7 @@ import Draggable from '@/examples/Draggable/Draggable'; import CodeBlock from '@/components/_CodeBlock/codeBlock'; function Index() { - const [select, setSelect] = useState('Draggable'); + const [select, setSelect] = useState('Modal'); const demoSelect = () => { return (
@@ -38,6 +40,9 @@ function Index() {
setSelect('Popover')}> 气泡
+
setSelect('Modal')}> + 弹窗 +
); }; @@ -53,8 +58,11 @@ function Index() { {select === 'Popover' ? : null} {select === 'Draggable' ? : null} {select === 'Skeleton' ? : null} + {select === 'Modal' ? : null} + +
+ 1
-
1
); } diff --git a/packages/design-icon/Icon/icon-svg/close.tsx b/packages/design-icon/Icon/icon-svg/close.tsx index d2ca665..1b89c87 100644 --- a/packages/design-icon/Icon/icon-svg/close.tsx +++ b/packages/design-icon/Icon/icon-svg/close.tsx @@ -1,18 +1,14 @@ const Close: React.FC = (props) => { return ( - + ); }; diff --git a/packages/design-props/components/modal.ts b/packages/design-props/components/modal.ts new file mode 100644 index 0000000..69da05e --- /dev/null +++ b/packages/design-props/components/modal.ts @@ -0,0 +1,120 @@ +import React, { MouseEvent, MouseEventHandler } from 'react'; +import { PivotDesignProps } from '.'; +import { ButtonProps } from './button'; +interface postion { + x?: number; + y?: number; +} + +interface ModalCssTokens {} +export interface ModalProps extends PivotDesignProps { + /** + * @version 1.0.0 + * @description 自定义样式 + * @default undefined + */ + style?: React.CSSProperties & ModalCssTokens; + /** + * @version 1.0.0 + * @description 自定义蒙层 + * @default undefined + */ + maskstyle?: React.CSSProperties & ModalCssTokens; + /** + * @version 1.0.0 + * @description 卡片内容是否加载 + * @default normal + */ + loading?: boolean; + /** + * @version 1.0.0 + * @description 对话框标题 + * @default undefined + */ + title?: React.ReactNode; + + /** + * @version 1.0.0 + * @description 确定函数 + * @default undefined + */ + onOk?: MouseEventHandler + /** + * @version 1.0.0 + * @description 取消函数 + * @default undefined + */ + onCancel?:MouseEventHandler + /** + * @version 1.0.0 + * @description 对话框是否开启 + * @default false + */ + open?: boolean; + /** + * @version 1.0.0 + * @description 底部内容 + * @default undefined + */ + footer?: React.ReactNode; + /** + * @version 1.0.0 + * @description 底部按钮排列方向 + * @default 'col' + */ + footerButtonDirection?: 'col' | 'row'; + /** + * @version 1.0.0 + * @description 内容 + * @default undefined + */ + children?: React.ReactNode; + /** + * @version 1.0.0 + * @description 是否有关闭图标 + * @default false + */ + isClose?: boolean; + /** + * @version 1.0.0 + * @description 对话框位置 + * @default {x: 0, y: 0} + */ + position?: postion; + /** + * @version 1.0.0 + * @description 关闭图标 + * @default undefined + */ + closeIcon?: React.ReactNode; + /** + * @version 1.0.0 + * @description 是否开启蒙层 + * @default true + */ + hasMask?: boolean; + /** + * @version 1.0.0 + * @description 点击蒙层是否关闭模态框 + * @default true + */ + maskClosable?: boolean; + /** + * @version 1.0.0 + * @description 取消按钮参数 + * @default undefined + */ + cancelButtonProps?: ButtonProps; + /** + * @version 1.0.0 + * @description 确定按钮参数 + * @default undefined + */ + OkButtonProps?: ButtonProps; + /** + * @version 1.0.0 + * @description 自定义对话框 + * @default undefined + */ + modalRender?: (node: React.ReactNode) => React.ReactNode; +} diff --git a/packages/design-props/components/skeleton.ts b/packages/design-props/components/skeleton.ts index 91c5529..dee7af9 100644 --- a/packages/design-props/components/skeleton.ts +++ b/packages/design-props/components/skeleton.ts @@ -7,7 +7,7 @@ export interface SkeletonProps extends PivotDesignProps { * @description 自定义样式 * @default undefined */ - style?: React.CSSProperties & CardCssTokens; + style?: React.CSSProperties & SkeletonCssTokens; /** * @version 1.0.0 * @description 是否展示动画效果 @@ -47,7 +47,7 @@ export interface SkeletonProps extends PivotDesignProps { brick?: boolean; } -interface CardCssTokens { +interface SkeletonCssTokens { /** * @version 1.0.0 * @description 背景颜色 diff --git a/packages/design-props/index.ts b/packages/design-props/index.ts index d485133..b922d18 100644 --- a/packages/design-props/index.ts +++ b/packages/design-props/index.ts @@ -5,3 +5,4 @@ export * from './components/input'; export * from './components/card'; export * from './components/skeleton'; export * from './components/popover'; +export * from './components/modal'; diff --git a/packages/design/components/Button/index.scss b/packages/design/components/Button/index.scss index 918f4cc..84e6839 100644 --- a/packages/design/components/Button/index.scss +++ b/packages/design/components/Button/index.scss @@ -2,25 +2,24 @@ .#{$prefix}-button { display: flex; cursor: pointer; - margin: 10px; color: var(--Brand-1-100); &:not(&-disabled):active { opacity: 0.7; } &-small { font-size: 14px; - padding: 10px 60px; - border-radius: 12px; + padding: 2px 8px; + border-radius: 2px; } &-middle { font-size: 16px; - padding: 15px 100px; - border-radius: 15px; + padding: 4px 12px; + border-radius: 6px; } &-large { font-size: 16px; - padding: 20px 140px; - border-radius: 15px; + padding: 12px 18px; + border-radius: 12px; } &-default { border: 1px solid var(--button-background-color, var(--pivot-button-background-color)); diff --git a/packages/design/components/Button/index.tsx b/packages/design/components/Button/index.tsx index 664d51d..06358bf 100644 --- a/packages/design/components/Button/index.tsx +++ b/packages/design/components/Button/index.tsx @@ -63,6 +63,11 @@ const Button: React.FC = (props) => { e.preventDefault(); return; } + //如果是禁用状态,点击不执行onClick的回调 + if (disabled) { + e.preventDefault(); + return; + } // 节流或防抖 onClick && clickThrottleOrDebounce(e); }; diff --git a/packages/design/components/Card/index.scss b/packages/design/components/Card/index.scss index 16a91f4..e51d911 100644 --- a/packages/design/components/Card/index.scss +++ b/packages/design/components/Card/index.scss @@ -1,6 +1,7 @@ @import '../constants.scss'; -$cardmin: calc(var(--card-minLength, 3) * 20px); -$cardmax: calc(var(--card-maxLength, 100%) * 20px); +@import '../common.scss'; +$cardmin: calc(var(--card-minLength, 3) * 1.8rem); +$cardmax: calc(var(--card-maxLength, 100%) * 1.8rem); .#{$prefix}-card { position: relative; @@ -44,8 +45,8 @@ $cardmax: calc(var(--card-maxLength, 100%) * 20px); min-width: 26px; height: 13px; font-weight: 400; - font-size: 13px; - line-height: 13px; + font-size: 16px; + line-height: 1rem; text-align: left; color: #000000; } @@ -87,6 +88,7 @@ $cardmax: calc(var(--card-maxLength, 100%) * 20px); .#{$prefix}-card-body { padding-top: 5px; width: 100%; + color: $pivot-black; font-size: 14px; line-height: 21px; font-style: normal; @@ -97,8 +99,9 @@ $cardmax: calc(var(--card-maxLength, 100%) * 20px); display: flex; // width: 200px; .#{$prefix}-card-body-text { + font-size: 14px; overflow: hidden; - line-height: 20px; + line-height: 1.8rem; max-height: $cardmin; text-align: justify; position: relative; @@ -124,6 +127,7 @@ $cardmax: calc(var(--card-maxLength, 100%) * 20px); align-items: center; div { + color:$pivot-black;; border: 1px solid #f9e8bd; border-radius: 8px; padding: 0 15px; diff --git a/packages/design/components/Modal/ModalContent.tsx b/packages/design/components/Modal/ModalContent.tsx new file mode 100644 index 0000000..c0a49d4 --- /dev/null +++ b/packages/design/components/Modal/ModalContent.tsx @@ -0,0 +1,82 @@ +import React, { MouseEventHandler } from 'react'; +import { ModalProps } from 'pivot-design-props'; +import Button from '../Button'; +import { prefix } from '../constants'; +import { Close } from 'pivot-design-icon'; +import classnames from 'classnames'; + +const ModalContent: React.FC = (props) => { + const { + title, + style, + className, + footer, + isClose = true, + hasMask, + maskstyle, + maskClosable, + children, + position, + closeIcon, + OkButtonProps, + cancelButtonProps, + footerButtonDirection = 'row', + onOk, + onCancel, + } = props; + + const positionStyle = { left: position?.x, top: position?.y }; + const _onCancel: MouseEventHandler = (e) => { + onCancel?.(e); + }; + const _onOk: MouseEventHandler = (e) => { + onOk?.(e); + }; + return ( +
+ {/* 这里避免蒙层出现后,页面可以滚动 */} + +
{}} + /> + +
+
+ {title} + {isClose && ( +
+ {closeIcon === undefined ? : closeIcon} +
+ )} +
+
{children}
+ +
+ {footer ? ( +
+ + + +
+ ) : ( +
{footer}
+ )} +
+
+
+ ); +}; +export default ModalContent; diff --git a/packages/design/components/Modal/index.scss b/packages/design/components/Modal/index.scss new file mode 100644 index 0000000..a74e9da --- /dev/null +++ b/packages/design/components/Modal/index.scss @@ -0,0 +1,76 @@ +@import '../constants.scss'; +@import '../common.scss'; + +.#{$prefix}-modal { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 999; + + .#{$prefix}-modal-mask { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 999; + background-color: rgba(0, 0, 0, 0.3); + + &__hidden { + background-color: transparent; + } + } + .#{$prefix}-modal-card { + position: relative; + z-index: 1000; + padding: 24px; + margin: 80px auto; + height: auto; + width: 448px; + border-radius: 16px; + color: var(--semi-color-white); + background-color: var(--semi-color-bg-3); + + .#{$prefix}-modal-cancel { + } + .#{$prefix}-modal-title { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 24px; + font-weight: 600; + font-size: 18px; + line-height: 1.5; + word-wrap: break-word; + } + .#{$prefix}-modal-footer { + position: relative; + .#{$prefix}-modal-col-footer { + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; + } + .#{$prefix}-modal-row-footer { + display: flex; + justify-content: flex-end; + flex-wrap: nowrap; + margin-top: 24px; + gap: 16px; + } + } + .#{$prefix}-modal-content { + font-size: 14px; + line-height: 1.6; + white-space: pre-wrap; + word-break: break-all; + overflow: hidden; + } + + .#{$prefix}-modal-cancel { + cursor: pointer; + } + } +} diff --git a/packages/design/components/Modal/index.tsx b/packages/design/components/Modal/index.tsx new file mode 100644 index 0000000..13e1e7f --- /dev/null +++ b/packages/design/components/Modal/index.tsx @@ -0,0 +1,52 @@ +import React, { Component, MouseEventHandler } from 'react'; +import { ModalProps } from 'pivot-design-props'; +import './index.scss'; +import ModalContent from './ModalContent'; +import { createPortal } from 'react-dom'; +import { createRoot } from 'react-dom/client'; + +const ModalFC: React.FC = (props) => { + const { open, children } = props; + return <>{open && createPortal({children}, document.body)}; +}; + +class Modal extends Component { + static defaultProps = { + maskstyle: {}, + open: false, + children: null, + hasMask: true, + maskClosable: true, + onCancel: () => {}, + modalRender: null, + }; + + static show = (props: ModalProps) => { + const modalDiv = document.createElement('div'); + const modalRoot = createRoot(modalDiv); + document.body.appendChild(modalDiv); + + const destory = () => { + modalRoot.unmount(); + modalDiv.parentNode?.removeChild(modalDiv); + }; + const _onCancel: MouseEventHandler = (e) => { + props.onCancel?.(e); + destory(); + }; + const _onOk: MouseEventHandler = (e) => { + props.onOk?.(e); + destory(); + }; + modalRoot.render(); + }; + + constructor(props: ModalProps) { + super(props); + } + render(): React.ReactNode { + return {this.props.children}; + } +} + +export default Modal; diff --git a/packages/design/components/Skeleton/index.scss b/packages/design/components/Skeleton/index.scss index c245f1c..f93319f 100644 --- a/packages/design/components/Skeleton/index.scss +++ b/packages/design/components/Skeleton/index.scss @@ -26,6 +26,21 @@ overflow: hidden; border-radius: 50%; } + li { + border-radius: 4px; + list-style: none; + display: block; + width: 100%; + height: calc(var(--skeleton-paragraph-size, 0.8)* 1rem); + &:first-child { + width: 30%; + } + &:nth-child(2) { + width: 60%; + } + + } + } // li { // border-radius: 4px; @@ -40,7 +55,6 @@ // width: 60%; // } // } - .#{$prefix}-skeleton-loading { background-image: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 37%, #f2f2f2 63%); @@ -50,6 +64,7 @@ animation: var(--skeleton-active, active) 1.4s ease infinite; } + @keyframes active { 0% { background-position: 100% 50%; diff --git a/packages/design/index.ts b/packages/design/index.ts index 013613e..2c29a92 100644 --- a/packages/design/index.ts +++ b/packages/design/index.ts @@ -13,9 +13,11 @@ export { import Icon from './components/Icon'; import Input from './components/Input'; import Card from './components/Card'; +import Modal from './components/Modal'; import Skeleton from './components/Skeleton'; import Popover from './components/Popover/'; -export { Button, Icon, Input, Card, Skeleton, Popover }; +export * from './components/Modal'; +export { Button, Icon, Input, Card, Skeleton, Popover, Modal }; export const arrayMove = (array: any[], from: number, to: number) => { const resArray = array.slice();