From d6cae6a5835639e01164477a5e256ad92d6b4f46 Mon Sep 17 00:00:00 2001 From: KMS-Bismarck <50952954+KMS-Bismarck@users.noreply.github.com> Date: Thu, 19 Sep 2024 19:52:45 +0800 Subject: [PATCH] feat: 3.4.0 (#677) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐞 BugFix - 修复 `Carousel` 组件点击箭头切换后,鼠标悬停时没有禁用切换的现象 (#674) - 修复 `Rate` 组件在 Safari 浏览器下对齐样式异常的问题(#670) - 修复 `TableRef` 的 `scrollToIndex` 的回调方法不生效问题 (#651) - 修复 `Tabs` 组件的 Tabs.Panel 是异常动态长度时,需要 resize 页面才会出现左右的滚动箭头 (#668) - 修复 `TreeSelect` 组件 `filterDelay` 属性失效的问题 (#672) - 修复 `Modal` 组件使用方法调用方式时,点击确定或取消按钮没有关闭动画 (#675) - 修复 `Modal` 组件下存在多个 Form 组件时,Modal.Submit 提交无效的问题 (#625) 🆕 Feature - 新增 `Link` 组件 - 新增 `Badge` 组件 - `Datepicker` 新增 `needConfirm` 属性: 是否开启手动确认按钮,开启后只有点击确认按钮才会提交选择的值 (#650) - `Datepicker` 新增 `clearToUndefined`,点击清除后返回 undefined (#644) - `Dropdown` 组件新增 `zIndex` 属性 (#660) - `Menu` 组件新增父节点激活状态下的文字颜色 token (#659) - `Select` 组件支持动态虚拟列表行高(#646) - `Select` 组件新增 `onLoadMore` 属性,支持滚动加载 (#610) - `Select` 组件新增 `threshold` 属性,支持设置滚动加载阈值 (#610) - `Select` 组件新增 `trigger` 属性,支持更改展开下拉面板的触发方式 (#610) - `Table` 组件新增属性 `showTopScrollbar`,开启顶部滚动条 (#671) - `Table` 组件 `onScroll` 事件新增 top 参数 (#658) - `Table` 组件 `Ref` 支持 `getRenderIndexByData` 方法,用于获取指定数据在渲染列表中的索引 - `Textarea` 组件 `info` 属性新增配置模式,支持配置定位 (#676) - `Tree` 组件新增 `setActive` 属性,与active组成高亮的受控功能 (#665) 💎 Enhancement - 优化 `Select` 组件在同时使用 `emptyText` 和 `renderOptionList` 时的渲染顺序 (#627) - 优化 `Table` 初始化加载性能 (#673) --------- Co-authored-by: 翟胜佳 Co-authored-by: 颜宇浩 Co-authored-by: saint <122591154@qq.com> Co-authored-by: 利浩 --- docs/api/shineout/badge.ts | 2 + docs/api/shineout/cascader.ts | 2 +- docs/api/shineout/date-picker.ts | 2 +- docs/api/shineout/link.ts | 2 + docs/api/shineout/menu.ts | 2 +- docs/api/shineout/popover.ts | 2 +- docs/api/shineout/spin.ts | 2 +- docs/api/shineout/table.ts | 2 +- docs/api/shineout/tree-select.ts | 2 +- docs/markdown/shineout/changelog-common.md | 11 + docs/theme/components/example/style.ts | 4 +- package.json | 2 +- .../src/animation-list/animation-list.tsx | 4 +- .../src/animation-list/animation-list.type.ts | 1 + packages/base/src/badge/__doc__/index.md | 16 + .../base/src/badge/__example__/01-base.tsx | 21 + packages/base/src/badge/badge.tsx | 112 ++ packages/base/src/badge/badge.type.ts | 83 ++ packages/base/src/badge/index.ts | 2 + packages/base/src/carousel/carousel.tsx | 20 +- .../base/src/checkbox/simple-checkbox.tsx | 2 +- packages/base/src/date-picker/confirm.tsx | 28 + packages/base/src/date-picker/confirm.type.ts | 5 + packages/base/src/date-picker/date-picker.tsx | 30 +- .../base/src/date-picker/date-picker.type.ts | 27 +- packages/base/src/date-picker/day.tsx | 64 +- packages/base/src/date-picker/month.tsx | 6 +- packages/base/src/date-picker/picker.tsx | 29 +- packages/base/src/date-picker/picker.type.ts | 8 +- packages/base/src/date-picker/quarter.tsx | 7 +- packages/base/src/date-picker/time.tsx | 16 +- packages/base/src/date-picker/year.tsx | 7 +- packages/base/src/dropdown/dropdown.type.ts | 7 + packages/base/src/dropdown/dropdownIn.tsx | 14 +- packages/base/src/icons/config.tsx | 3 + packages/base/src/icons/icons.tsx | 6 + packages/base/src/index.ts | 2 + packages/base/src/link/__doc__/index.md | 16 + .../base/src/link/__example__/01-base.tsx | 21 + packages/base/src/link/index.ts | 2 + packages/base/src/link/link.tsx | 57 + packages/base/src/link/link.type.ts | 65 + packages/base/src/modal/modal-content.tsx | 6 + packages/base/src/modal/modal-content.type.ts | 1 + packages/base/src/modal/modal-func.tsx | 9 +- packages/base/src/select/list-columns.tsx | 2 +- packages/base/src/select/list-option.tsx | 31 +- packages/base/src/select/list-option.type.ts | 3 + packages/base/src/select/list.tsx | 36 +- packages/base/src/select/select.tsx | 27 +- packages/base/src/select/select.type.ts | 37 +- packages/base/src/sticky/index.ts | 2 +- packages/base/src/sticky/sticky.tsx | 2 +- packages/base/src/table/table.tsx | 184 ++- packages/base/src/table/table.type.ts | 27 +- packages/base/src/tabs/tabs-header.tsx | 29 + packages/base/src/tabs/tabs.type.ts | 1 + packages/base/src/textarea/textarea.tsx | 25 +- packages/base/src/textarea/textarea.type.ts | 20 +- packages/base/src/transfer/transfer.tsx | 2 + packages/base/src/transfer/transfer.type.ts | 6 + packages/base/src/tree-select/tree-select.tsx | 1 + .../base/src/tree-select/tree-select.type.ts | 7 + packages/base/src/tree/tree.tsx | 24 +- packages/base/src/tree/tree.type.ts | 5 + packages/base/src/virtual-scroll/scroll.tsx | 35 +- .../virtual-scroll/virtual-scroll-list.tsx | 176 ++- .../virtual-scroll-list.type.ts | 2 + .../src/common/use-scrollbar-width/index.ts | 46 + .../src/components/use-datepicker/use-date.ts | 4 +- .../use-datepicker/use-date.type.ts | 2 +- .../use-datepicker/use-datepicker-format.ts | 8 +- .../use-datepicker-format.type.ts | 1 + .../components/use-datepicker/use-month.ts | 4 +- .../use-datepicker/use-month.type.ts | 2 +- .../components/use-datepicker/use-quarter.ts | 4 +- .../src/components/use-datepicker/use-year.ts | 4 +- .../use-datepicker/use-year.type.ts | 2 +- .../use-table/use-table-virtual.tsx | 93 +- packages/hooks/src/index.ts | 1 + packages/shineout-style/src/badge/badge.ts | 157 +++ packages/shineout-style/src/badge/index.ts | 6 + .../src/date-picker/date-picker.ts | 22 +- packages/shineout-style/src/index.ts | 2 + packages/shineout-style/src/link/index.ts | 6 + packages/shineout-style/src/link/link.ts | 108 ++ packages/shineout-style/src/menu/menu.ts | 4 +- packages/shineout-style/src/rate/rate.ts | 8 + packages/shineout-style/src/select/select.ts | 15 + packages/shineout-style/src/table/table.ts | 6 +- packages/shineout-style/src/tabs/tabs.ts | 76 +- .../shineout-style/src/textarea/textarea.ts | 16 + .../shineout-style/src/transfer/transfer.ts | 14 +- packages/shineout-style/src/version.ts | 2 +- .../shineout/src/badge/__doc__/guide.cn.md | 15 + .../shineout/src/badge/__doc__/guide.en.md | 17 + packages/shineout/src/badge/__doc__/index.md | 17 + .../src/badge/__example__/01-base.tsx | 23 + .../src/badge/__example__/02-nochildren.tsx | 17 + .../badge/__example__/03-overflowcount.tsx | 28 + .../shineout/src/badge/__example__/04-dot.tsx | 19 + .../src/badge/__example__/05-status.tsx | 29 + .../src/badge/__example__/static/avatar.tsx | 22 + packages/shineout/src/badge/badge.tsx | 11 + packages/shineout/src/badge/badge.type.ts | 6 + packages/shineout/src/badge/index.ts | 14 + packages/shineout/src/badge/interface.ts | 1 + .../__snapshots__/cardGroup.spec.tsx.snap | 1 + .../src/carousel/__doc__/changelog.cn.md | 6 + .../__snapshots__/checkbox.spec.tsx.snap | 13 + .../__snapshots__/checkboxGroup.spec.tsx.snap | 35 + .../__snapshots__/collapse.spec.tsx.snap | 1 + .../src/date-picker/__doc__/changelog.cn.md | 8 + .../__example__/09-select-confirm.tsx | 46 + .../date-picker/__test__/datePicker.spec.tsx | 16 +- .../shineout/src/date-picker/date-picker.tsx | 2 + .../__snapshots__/drawer.spec.tsx.snap | 4 + .../src/dropdown/__doc__/changelog.cn.md | 7 + .../src/form/__example__/006-validate-01.tsx | 24 +- packages/shineout/src/index.ts | 4 +- .../shineout/src/link/__doc__/guide.cn.md | 15 + .../shineout/src/link/__doc__/guide.en.md | 17 + packages/shineout/src/link/__doc__/index.md | 21 + .../shineout/src/link/__example__/01-base.tsx | 10 + .../shineout/src/link/__example__/02-type.tsx | 20 + .../src/link/__example__/03-disabled.tsx | 20 + .../src/link/__example__/04-underline.tsx | 52 + .../shineout/src/link/__example__/05-icon.tsx | 32 + .../shineout/src/link/__example__/06-size.tsx | 42 + packages/shineout/src/link/index.ts | 14 + packages/shineout/src/link/interface.ts | 1 + packages/shineout/src/link/link.tsx | 17 + packages/shineout/src/link/link.type.ts | 6 + .../shineout/src/menu/__doc__/changelog.cn.md | 6 + packages/shineout/src/menu/menu.type.ts | 2 +- .../src/modal/__doc__/changelog.cn.md | 9 +- .../src/modal/__test__/modal.spec.tsx | 4 +- .../shineout/src/rate/__doc__/changelog.cn.md | 10 + .../src/select/__doc__/changelog.cn.md | 20 + .../src/select/__example__/01-01-base.tsx | 14 +- .../src/select/__example__/04-bigdata.tsx | 30 +- .../select/__example__/16-custom-render.tsx | 4 +- .../src/select/__example__/16-loading.tsx | 17 - .../src/select/__example__/19-loadmore.tsx | 76 + .../src/select/__example__/20-trigger.tsx | 24 + .../__snapshots__/select.spec.tsx.snap | 50 +- .../src/table/__doc__/changelog.cn.md | 19 +- .../table/__example__/06-double-scrollbar.tsx | 60 + .../__example__/07-02-virtual-scroll.tsx | 2 +- .../__example__/07-02-virtual-scroll2.tsx | 113 ++ .../__example__/test-006-table-scroll-y.tsx | 7 +- .../table/__example__/test-007-table-tabs.tsx | 37 +- .../shineout/src/tabs/__doc__/changelog.cn.md | 11 +- .../__test__/__snapshots__/tabs.spec.tsx.snap | 32 + .../src/textarea/__doc__/changelog.cn.md | 7 + .../src/transfer/__doc__/changelog.cn.md | 11 + .../src/transfer/__example__/01-base.tsx | 6 +- .../__snapshots__/transfer.spec.tsx.snap | 1232 +++++++++-------- .../src/tree-select/__doc__/changelog.cn.md | 6 + .../shineout/src/tree/__doc__/changelog.cn.md | 8 + .../tree/__example__/11-highlight-control.tsx | 47 + .../__test__/__snapshots__/tree.spec.tsx.snap | 269 ++++ .../shineout/src/tree/__test__/tree.spec.tsx | 6 +- packages/shineout/src/type.ts | 2 + packages/theme/src/alert/token.ts | 5 +- packages/theme/src/badge/badge.ts | 24 + packages/theme/src/badge/index.ts | 5 + packages/theme/src/badge/rule.ts | 15 + packages/theme/src/badge/token.ts | 80 ++ packages/theme/src/badge/type.ts | 95 ++ packages/theme/src/index.ts | 12 + packages/theme/src/link/index.ts | 5 + packages/theme/src/link/link.ts | 32 + packages/theme/src/link/rule.ts | 21 + packages/theme/src/link/token.ts | 61 + packages/theme/src/link/type.ts | 143 ++ packages/theme/src/menu/menu.ts | 1 + packages/theme/src/menu/token.ts | 6 + packages/theme/src/menu/type.ts | 6 + packages/theme/src/spin/token.ts | 4 +- packages/theme/src/tabs/token.ts | 17 +- packages/theme/src/token/token.ts | 3 + packages/theme/src/token/type.ts | 21 + packages/theme/src/transfer/token.ts | 4 +- 184 files changed, 4442 insertions(+), 941 deletions(-) create mode 100644 docs/api/shineout/badge.ts create mode 100644 docs/api/shineout/link.ts create mode 100644 packages/base/src/badge/__doc__/index.md create mode 100644 packages/base/src/badge/__example__/01-base.tsx create mode 100644 packages/base/src/badge/badge.tsx create mode 100644 packages/base/src/badge/badge.type.ts create mode 100644 packages/base/src/badge/index.ts create mode 100644 packages/base/src/date-picker/confirm.tsx create mode 100644 packages/base/src/date-picker/confirm.type.ts create mode 100644 packages/base/src/link/__doc__/index.md create mode 100644 packages/base/src/link/__example__/01-base.tsx create mode 100644 packages/base/src/link/index.ts create mode 100644 packages/base/src/link/link.tsx create mode 100644 packages/base/src/link/link.type.ts create mode 100644 packages/hooks/src/common/use-scrollbar-width/index.ts create mode 100644 packages/shineout-style/src/badge/badge.ts create mode 100644 packages/shineout-style/src/badge/index.ts create mode 100644 packages/shineout-style/src/link/index.ts create mode 100644 packages/shineout-style/src/link/link.ts create mode 100644 packages/shineout/src/badge/__doc__/guide.cn.md create mode 100644 packages/shineout/src/badge/__doc__/guide.en.md create mode 100644 packages/shineout/src/badge/__doc__/index.md create mode 100644 packages/shineout/src/badge/__example__/01-base.tsx create mode 100644 packages/shineout/src/badge/__example__/02-nochildren.tsx create mode 100644 packages/shineout/src/badge/__example__/03-overflowcount.tsx create mode 100644 packages/shineout/src/badge/__example__/04-dot.tsx create mode 100644 packages/shineout/src/badge/__example__/05-status.tsx create mode 100644 packages/shineout/src/badge/__example__/static/avatar.tsx create mode 100644 packages/shineout/src/badge/badge.tsx create mode 100644 packages/shineout/src/badge/badge.type.ts create mode 100644 packages/shineout/src/badge/index.ts create mode 100644 packages/shineout/src/badge/interface.ts create mode 100644 packages/shineout/src/carousel/__doc__/changelog.cn.md create mode 100644 packages/shineout/src/date-picker/__example__/09-select-confirm.tsx create mode 100644 packages/shineout/src/link/__doc__/guide.cn.md create mode 100644 packages/shineout/src/link/__doc__/guide.en.md create mode 100644 packages/shineout/src/link/__doc__/index.md create mode 100644 packages/shineout/src/link/__example__/01-base.tsx create mode 100644 packages/shineout/src/link/__example__/02-type.tsx create mode 100644 packages/shineout/src/link/__example__/03-disabled.tsx create mode 100644 packages/shineout/src/link/__example__/04-underline.tsx create mode 100644 packages/shineout/src/link/__example__/05-icon.tsx create mode 100644 packages/shineout/src/link/__example__/06-size.tsx create mode 100644 packages/shineout/src/link/index.ts create mode 100644 packages/shineout/src/link/interface.ts create mode 100644 packages/shineout/src/link/link.tsx create mode 100644 packages/shineout/src/link/link.type.ts create mode 100644 packages/shineout/src/rate/__doc__/changelog.cn.md delete mode 100644 packages/shineout/src/select/__example__/16-loading.tsx create mode 100644 packages/shineout/src/select/__example__/19-loadmore.tsx create mode 100644 packages/shineout/src/select/__example__/20-trigger.tsx create mode 100644 packages/shineout/src/table/__example__/06-double-scrollbar.tsx create mode 100644 packages/shineout/src/table/__example__/07-02-virtual-scroll2.tsx create mode 100644 packages/shineout/src/tree/__example__/11-highlight-control.tsx create mode 100644 packages/theme/src/badge/badge.ts create mode 100644 packages/theme/src/badge/index.ts create mode 100644 packages/theme/src/badge/rule.ts create mode 100644 packages/theme/src/badge/token.ts create mode 100644 packages/theme/src/badge/type.ts create mode 100644 packages/theme/src/link/index.ts create mode 100644 packages/theme/src/link/link.ts create mode 100644 packages/theme/src/link/rule.ts create mode 100644 packages/theme/src/link/token.ts create mode 100644 packages/theme/src/link/type.ts diff --git a/docs/api/shineout/badge.ts b/docs/api/shineout/badge.ts new file mode 100644 index 000000000..aa206bdc2 --- /dev/null +++ b/docs/api/shineout/badge.ts @@ -0,0 +1,2 @@ +const api = JSON.parse('[{"title":"Badge","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"children","tag":{"cn":"内容","en":"Content","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"color","tag":{"cn":"自定义徽标颜色","en":"Custom badge color","default":"","version":""},"required":false,"type":"string "},{"name":"count","tag":{"cn":"展示的数字,大于 overflowCount 时显示 ${overflowCount}+,为 0 时隐藏","en":"Number to show, show ${overflowCount}+ when it is greater than overflowCount, hide when it is 0","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"dot","tag":{"cn":"小点模式,开启后不展示数字","en":"Dot mode","default":"false","version":""},"required":false,"type":"boolean "},{"name":"offset","tag":{"cn":"偏移量","en":"Offset of the badge","default":"","version":""},"required":false,"type":"[number, number] "},{"name":"overflowCount","tag":{"cn":"封顶数值","en":"Offset of the badge","default":"","version":""},"required":false,"type":"number "},{"name":"showZero","tag":{"cn":"当数值为 0 时,是否展示 Badge","en":"Whether to show Badge when the number is 0","default":"","version":""},"required":false,"type":"boolean "},{"name":"status","tag":{"cn":"徽标状态","en":"Whether to show Badge when the number is 0","default":"","version":""},"required":false,"type":"\\\"success\\\" | \\\"processing\\\" | \\\"default\\\" | \\\"error\\\" | \\\"warning\\\" "},{"name":"text","tag":{"cn":"状态点文本,仅在配置了 status 属性后生效","en":"Status point text, only valid after configuring the status property","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"size","tag":{"cn":"尺寸,仅在非 dot 模式下生效,支持 small 和 default 两种尺寸","en":"Size, only valid in non-dot mode, supports two sizes: small and default","default":"","version":""},"required":false,"type":"\\\"default\\\" | \\\"small\\\" "}],"cn":"","en":"","sort":"0"}]'); +export default api; diff --git a/docs/api/shineout/cascader.ts b/docs/api/shineout/cascader.ts index 9790f72a1..5534e6801 100644 --- a/docs/api/shineout/cascader.ts +++ b/docs/api/shineout/cascader.ts @@ -1,2 +1,2 @@ -const api = JSON.parse('[{"title":"Cascader","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"size","tag":{"cn":"不同尺寸","en":"There are three built-in size: small、default、large.","default":"\\\"default\\\"","version":""},"required":false,"type":"\\\"small\\\" | \\\"large\\\" | \\\"default\\\""},{"name":"status","tag":{"cn":"组件状态","en":"The status of the component","default":"","version":""},"required":false,"type":"\\\"error\\\" "},{"name":"innerTitle","tag":{"cn":"内嵌标题","en":"inner title","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"filterSameChange","tag":{"cn":"当两次选择的值相同时不触发 onChange","en":"onChange is not triggered when two selected values are the same","default":"false","version":""},"required":false,"type":"boolean "},{"name":"absolute","tag":{"cn":"为 true 时,选项弹出层在 DOM 中独立 render; 为函数时,返回值作为弹出层容器","en":"When it is true, the pop-up layer of option append into document.body; When it is a function, the return value is used as the popup layer container","default":"false","version":""},"required":false,"type":"boolean | (() => HTMLElement | null) "},{"name":"zIndex","tag":{"cn":"选项列表 z-index 值, 需要配合 absolute","en":"options z-index should use with absolute","default":"1000","version":""},"required":false,"type":"number "},{"name":"multiple","tag":{"cn":"开启多选","en":"Open multiple selection","default":"false","version":""},"required":false,"type":"boolean "},{"name":"mode","tag":{"cn":"选中值模式,未设置值为单选 0: 只返回完全选中的节点,包含父节点 1: 返回全部选中的节点和半选中的父节点 2: 只返回选中的子节点 3: 如果父节点选中,只返回父节点 4: 所选即所得","en":"Mode 0: Returns only the fully selected node including the parent node. 1: Returns all selected nodes and semi-selected nodes. 2: Return only the selected child nodes. 3: If the parent node is full selected, only return the parent node. 4: What you choose is what you get","default":"","version":""},"required":false,"type":"0 | 1 | 2 | 3 | 4 "},{"name":"width","tag":{"cn":"输入框宽度","en":"Input width","default":"","version":""},"required":false,"type":"string | number "},{"name":"open","tag":{"cn":"控制浮层显隐","en":"Set visible of cascader popup","default":"","version":""},"required":false,"type":"boolean "},{"name":"value","tag":{"cn":"选中的 key (受控)","en":"Selected key (controlled)","default":"","version":""},"required":false,"type":"Value "},{"name":"defaultValue","tag":{"cn":"默认选中的 key","en":"Selected key","default":"","version":""},"required":false,"type":"Value "},{"name":"data","tag":{"cn":"数据,子节点为children,如果 children 值为 null 或 长度为 0 时,视为叶子节点","en":"data. The child node is children. If the children value is null or its length is 0, it is render as a leaf node","default":"","version":""},"required":false,"type":"any[]"},{"name":"childrenKey","tag":{"cn":"指定子数据的属性名","en":"the key of the children data name","default":"\\\"children\\\"","version":""},"required":false,"type":"ObjectKey "},{"name":"final","tag":{"cn":"单选只支持选末级节点","en":"Only the last node can be selected","default":"","version":""},"required":false,"type":"boolean "},{"name":"filterDelay","tag":{"cn":"用户输入触发 fitler 事件的延时,单位为毫秒。","en":"The delay in milliseconds before the filter event is triggered by user input.","default":"\\\"children\\\"","version":""},"required":false,"type":"number "},{"name":"renderOptionList","tag":{"cn":"自定义渲染下拉列表","en":"Custom render dropdown","default":"","version":""},"required":false,"type":"((list: ReactElement, info: { loading: boolean; }) => ReactElement) "},{"name":"renderUnmatched","tag":{"cn":"渲染未匹配值的方式","en":"Custom rendering unmatched values","default":"","version":""},"required":false,"type":"((data: any) => ReactNode) "},{"name":"height","tag":{"cn":"下拉列表高度","en":"height of dropdown options","default":"300","version":""},"required":false,"type":"number "},{"name":"unmatch","tag":{"cn":"是否展示data中不存在的值","en":"render unmatch value","default":"true","version":""},"required":false,"type":"boolean "},{"name":"clearable","tag":{"cn":"是否显示清除数据图标","en":"If clearable is true, show clear value icon","default":"true","version":""},"required":false,"type":"boolean "},{"name":"wideMatch","tag":{"cn":"开启 wideMatch 后,将筛选出所有可能的匹配项目","en":"Allows all possible matching options to be choosed","default":"false","version":""},"required":false,"type":"boolean "},{"name":"showArrow","tag":{"cn":"是否显示下拉箭头,仅针对单选情况","en":"show dropdown arrow, only single select","default":"true","version":""},"required":false,"type":"boolean "},{"name":"finalDismiss","tag":{"cn":"选择末级节点后是否关闭选项列表","en":"close options after chose the final node","default":"false","version":""},"required":false,"type":"boolean "},{"name":"singleRemove","tag":{"cn":"支持单个节点删除","en":"Support single node deletion","default":"","version":""},"required":false,"type":"boolean "},{"name":"compressedBound","tag":{"cn":"开启多选后,指定允许展示标签数量,超过后将折叠","en":"when compressed is True,the comptessedBound can limit the numbers of multiple selected item\\\"s label","default":"","version":""},"required":false,"type":"number "},{"name":"loading","tag":{"cn":"下拉列表加载状态","en":"dropdown list loading state","default":"","version":""},"required":false,"type":"boolean | ReactNode"},{"name":"compressed","tag":{"cn":"将选中值合并。为\\\"no-repeat\\\"时弹出框中不重复展示值","en":"Merges selected values; the repeat value will not appear in the Popover when it is\\\"no-repeat\\\"","default":"false","version":""},"required":false,"type":"boolean | \\\"no-repeat\\\" "},{"name":"onCollapse","tag":{"cn":"下拉列表展开/收起回调","en":"options collapse callback","default":"","version":""},"required":false,"type":"((collapse: boolean) => void) "},{"name":"loader","tag":{"cn":"设置 loader 属性后,未定义 children 的节点视为动态加载节点,点击展开触发 loader 事件,children 为 null 或者长度为 0 视为叶子节点","en":"If the loader attribute is a function, the node with no children is regarded as dynamically loaded node. Click expanded button to trigger the loader event. The children property is null or its length is 0 will be regarded as a leaf node.","default":"","version":""},"required":false,"type":"((key: string | number, data: DataItem) => void) "},{"name":"disabled","tag":{"cn":"当 disabled 为 true 时,禁用整个选择框。如果 disabled 为函数,根据函数反回结果禁用选项","en":"When it is true, all nodes disable the selection; when it is a function, it determines whether it is disabled according to the return result of the function.","default":"false","version":""},"required":false,"type":"boolean | ((data: DataItem) => boolean) "},{"name":"expandTrigger","tag":{"cn":"节点展开触发方式","en":"Expand mode","default":"\\\"click\\\"","version":""},"required":false,"type":"\\\"click\\\" | \\\"hover\\\" | \\\"hover-only\\\" "},{"name":"onChange","tag":{"cn":"设置 onChange 属性时,显示 选择框。参数为当前选中值,和 mode 属性相关","en":"When the onChange property is set, the selection box is displayed. The parameter is the current selected value, which is related to the mode property.","default":"","version":""},"required":false,"type":"((value: Value, selected?: DataItem ) => void) "},{"name":"onFilter","tag":{"cn":"onFilter 不为空时,可以输入过滤数据;onFilter 如果返回一个函数,使用这个函数做前端过滤;如果不返回,可以自行做后端过滤;单选状态下支持","en":"When the onFilter is not empty, you can filter data by input.If the onFilter returns a function, use this function as a front-end filter.If return undefined, you can do your own backend filtering.support in single selection state.","default":"","version":""},"required":false,"type":"((text: string) => void | ((data: DataItem) => boolean) ) "},{"name":"keygen","tag":{"cn":"生成 key 的辅助方法, 为函数时,使用此函数返回值, 为 string 时,使用这个 string 对应的数据值。如 \\\"id\\\",相当于 (d) => d.id","en":"Auxiliary method for generating key. When it is a function, use the return value of this function. When it is a string, use the data value corresponding to this string. For example, \\\"id\\\" is the same thing as (d) => d.id.","default":"index","version":""},"required":true,"type":"ObjectKey | ((data: DataItem, parentKey?: string | number ) => string | number)"},{"name":"renderItem","tag":{"cn":"当 renderItem 为 string 时,返回 DataItem\\\\[string]。 若为函数时,则返回函数结果","en":"When \\\"renderItem\\\" is a string, it returns DataItem[string]. If it\\\"s a function, it returns the result of the function.","default":"d => d","version":""},"required":true,"type":"ObjectKey | ((data: DataItem, active?: boolean , id?: string | number ) => ReactNode)"},{"name":"renderResult","tag":{"cn":"选中后在结果中显示的内容,默认和 renderItem 相同","en":"The content displayed in the result after selecting, if not set, use renderItem. not show while return null, result is current selected","default":"renderItem","version":""},"required":false,"type":"ObjectKey | ((data: DataItem, row: DataItem[]) => ReactNode) "},{"name":"onBlur","tag":{"cn":"失焦事件","en":"blur event","default":"","version":""},"required":false,"type":"((e?: KeyboardEvent ) => void) "},{"name":"onFocus","tag":{"cn":"聚焦事件","en":"focus event","default":"","version":""},"required":false,"type":"((e?: KeyboardEvent ) => void) "},{"name":"placeholder","tag":{"cn":"占位符","en":"placeholder","default":"","version":""},"required":false,"type":"string "},{"name":"emptyAfterSelect","tag":{"cn":"选中后是否清空输入框内容","en":"empty input after select value","default":"true","version":""},"required":false,"type":"boolean "},{"name":"border","tag":{"cn":"是否展示边框","en":"Whether to display border","default":"true","version":""},"required":false,"type":"boolean "},{"name":"underline","tag":{"cn":"是否只展示下边框","en":"Only display border bottom","default":"","version":""},"required":false,"type":"boolean "},{"name":"resultClassName","tag":{"cn":"选中结果内容容器的className","en":"The className of the selected result content container","default":"","version":""},"required":false,"type":"string | ((value: DataItem) => string) "},{"name":"compressedClassName","tag":{"cn":"多选合并展示弹出框的类名","en":"Compressed popover classname","default":"","version":""},"required":false,"type":"string "},{"name":"focusSelected","tag":{"cn":"onFilter 在多选情况下点击选项后是否选中过滤文本","en":"onFilter Whether to select filter text after clicking the option in multi-selection situation","default":"true","version":""},"required":false,"type":"boolean "},{"name":"hideTag","tag":{"cn":"隐藏标签样式,默认情况下展示结果以标签模式分割,隐藏标签样式后可通过自定义 renderResult 渲染分割结果","en":"Hide tag style, by default, the result is displayed in tag mode. After hiding the tag style, the result can be rendered by custom renderResult","default":"false","version":""},"required":false,"type":"boolean "},{"name":"getComponentRef","tag":{"cn":"绑定组件的引用, 可以调用某些组件的方法","en":"A reference to the binding component, you can call some component methods","default":"","version":""},"required":false,"type":"((comp: CascaderRef) => void) | { current: CascaderRef ; } "},{"name":"adjust","tag":{"cn":"是否开启自动调整面板位置功能。当面板被窗口遮挡时,自动调整位置","en":"Whether to adjust the position of the panel automatically. When the panel is blocked by the window, the position is adjusted automatically","default":"true","version":""},"required":false,"type":"boolean "},{"name":"popover","tag":{"cn":"校验信息弹出位置","en":"The position where the validation info pop up","default":"","version":""},"required":false,"type":"PopoverProps[\\\"position\\\"]"},{"name":"popoverProps","tag":{"cn":"校验或者tip弹框接受的属性","en":"Vilidate popup properties","default":"","version":""},"required":false,"type":"PopoverProps "},{"name":"name","tag":{"cn":"Form 内存取数据的 key","en":"The key access data in the Form","default":"","version":""},"required":false,"type":"Name "},{"name":"beforeChange","tag":{"cn":"值改变前的回调,当返回值不为空时将作为组件的新值","en":"The callback before the value is changed, when the return value is not empty, it will be used as the new value of the component","default":"","version":""},"required":false,"type":"((value: T) => void | T ) "},{"name":"reserveAble","tag":{"cn":"设置为 true 组件卸载后表单不自动删除数据","en":"If set to true, the form will not automatically delete the data after the component is uninstalled","default":"","version":""},"required":false,"type":"boolean "},{"name":"rules","tag":{"cn":"校验规则 详见 [Rule](/components/rule)","en":"Validation rules, see [Rule](/components/rule) usage for details","default":"","version":""},"required":false,"type":"RuleItem[]"},{"name":"onError","tag":{"cn":"rules 校验回调","en":"rules validation callback","default":"","version":""},"required":false,"type":"((error?: Error ) => void) "},{"name":"bind","tag":{"cn":"当值改变是会联动校验 bind 中的字段, 需要配合 Form 使用","en":"When the value changes, it will link to verify the fields in the bind, which needs to be used with Form","default":"","version":""},"required":false,"type":"string[] "}],"cn":"","en":"","sort":"0"},{"title":"CascaderRef","properties":[{"name":"close","tag":{"cn":"关闭下拉框","en":"Close the drop-down box","default":"","version":""},"required":true,"type":"(e?: MouseEvent ) => void"}],"cn":"","en":"","sort":"0"}]'); +const api = JSON.parse('[{"title":"Cascader","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"size","tag":{"cn":"不同尺寸","en":"There are three built-in size: small、default、large.","default":"\\\"default\\\"","version":""},"required":false,"type":"\\\"small\\\" | \\\"large\\\" | \\\"default\\\""},{"name":"status","tag":{"cn":"组件状态","en":"The status of the component","default":"","version":""},"required":false,"type":"\\\"error\\\" "},{"name":"innerTitle","tag":{"cn":"内嵌标题","en":"inner title","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"filterSameChange","tag":{"cn":"当两次选择的值相同时不触发 onChange","en":"onChange is not triggered when two selected values are the same","default":"false","version":""},"required":false,"type":"boolean "},{"name":"absolute","tag":{"cn":"为 true 时,选项弹出层在 DOM 中独立 render; 为函数时,返回值作为弹出层容器","en":"When it is true, the pop-up layer of option append into document.body; When it is a function, the return value is used as the popup layer container","default":"false","version":""},"required":false,"type":"boolean | (() => HTMLElement | null) "},{"name":"zIndex","tag":{"cn":"选项列表 z-index 值, 需要配合 absolute","en":"options z-index should use with absolute","default":"1000","version":""},"required":false,"type":"number "},{"name":"multiple","tag":{"cn":"开启多选","en":"Open multiple selection","default":"false","version":""},"required":false,"type":"boolean "},{"name":"mode","tag":{"cn":"选中值模式,未设置值为单选 0: 只返回完全选中的节点,包含父节点 1: 返回全部选中的节点和半选中的父节点 2: 只返回选中的子节点 3: 如果父节点选中,只返回父节点 4: 所选即所得","en":"Mode 0: Returns only the fully selected node including the parent node. 1: Returns all selected nodes and semi-selected nodes. 2: Return only the selected child nodes. 3: If the parent node is full selected, only return the parent node. 4: What you choose is what you get","default":"","version":""},"required":false,"type":"0 | 1 | 2 | 3 | 4 "},{"name":"width","tag":{"cn":"输入框宽度","en":"Input width","default":"","version":""},"required":false,"type":"string | number "},{"name":"open","tag":{"cn":"控制浮层显隐","en":"Set visible of cascader popup","default":"","version":""},"required":false,"type":"boolean "},{"name":"value","tag":{"cn":"选中的 key (受控)。注意,请勿将 undefined 和 null 作为有意义的选项值,当 value 类型为 undefined 和 null 时,组件将不处理数据和渲染","en":"Selected key (controlled). Note: Do not use undefined and null as meaningful option values. When the value type is undefined and null, the component will not process data and rendering","default":"","version":""},"required":false,"type":"Value "},{"name":"defaultValue","tag":{"cn":"默认选中的 key","en":"Selected key","default":"","version":""},"required":false,"type":"Value "},{"name":"data","tag":{"cn":"数据,子节点为children,如果 children 值为 null 或 长度为 0 时,视为叶子节点","en":"data. The child node is children. If the children value is null or its length is 0, it is render as a leaf node","default":"","version":""},"required":false,"type":"any[]"},{"name":"childrenKey","tag":{"cn":"指定子数据的属性名","en":"the key of the children data name","default":"\\\"children\\\"","version":""},"required":false,"type":"ObjectKey "},{"name":"final","tag":{"cn":"单选只支持选末级节点","en":"Only the last node can be selected","default":"","version":""},"required":false,"type":"boolean "},{"name":"filterDelay","tag":{"cn":"用户输入触发 fitler 事件的延时,单位为毫秒。","en":"The delay in milliseconds before the filter event is triggered by user input.","default":"\\\"children\\\"","version":""},"required":false,"type":"number "},{"name":"renderOptionList","tag":{"cn":"自定义渲染下拉列表","en":"Custom render dropdown","default":"","version":""},"required":false,"type":"((list: ReactElement, info: { loading: boolean; }) => ReactElement) "},{"name":"renderUnmatched","tag":{"cn":"渲染未匹配值的方式","en":"Custom rendering unmatched values","default":"","version":""},"required":false,"type":"((data: any) => ReactNode) "},{"name":"height","tag":{"cn":"下拉列表高度","en":"height of dropdown options","default":"300","version":""},"required":false,"type":"number "},{"name":"unmatch","tag":{"cn":"是否展示data中不存在的值","en":"render unmatch value","default":"true","version":""},"required":false,"type":"boolean "},{"name":"clearable","tag":{"cn":"是否显示清除数据图标","en":"If clearable is true, show clear value icon","default":"true","version":""},"required":false,"type":"boolean "},{"name":"wideMatch","tag":{"cn":"开启 wideMatch 后,将筛选出所有可能的匹配项目","en":"Allows all possible matching options to be choosed","default":"false","version":""},"required":false,"type":"boolean "},{"name":"showArrow","tag":{"cn":"是否显示下拉箭头,仅针对单选情况","en":"show dropdown arrow, only single select","default":"true","version":""},"required":false,"type":"boolean "},{"name":"finalDismiss","tag":{"cn":"选择末级节点后是否关闭选项列表","en":"close options after chose the final node","default":"false","version":""},"required":false,"type":"boolean "},{"name":"singleRemove","tag":{"cn":"支持单个节点删除","en":"Support single node deletion","default":"","version":""},"required":false,"type":"boolean "},{"name":"compressedBound","tag":{"cn":"开启多选后,指定允许展示标签数量,超过后将折叠","en":"when compressed is True,the comptessedBound can limit the numbers of multiple selected item\\\"s label","default":"","version":""},"required":false,"type":"number "},{"name":"loading","tag":{"cn":"下拉列表加载状态","en":"dropdown list loading state","default":"","version":""},"required":false,"type":"boolean | ReactNode"},{"name":"compressed","tag":{"cn":"将选中值合并。为\\\"no-repeat\\\"时弹出框中不重复展示值","en":"Merges selected values; the repeat value will not appear in the Popover when it is\\\"no-repeat\\\"","default":"false","version":""},"required":false,"type":"boolean | \\\"no-repeat\\\" "},{"name":"onCollapse","tag":{"cn":"下拉列表展开/收起回调","en":"options collapse callback","default":"","version":""},"required":false,"type":"((collapse: boolean) => void) "},{"name":"loader","tag":{"cn":"设置 loader 属性后,未定义 children 的节点视为动态加载节点,点击展开触发 loader 事件,children 为 null 或者长度为 0 视为叶子节点","en":"If the loader attribute is a function, the node with no children is regarded as dynamically loaded node. Click expanded button to trigger the loader event. The children property is null or its length is 0 will be regarded as a leaf node.","default":"","version":""},"required":false,"type":"((key: string | number, data: DataItem) => void) "},{"name":"disabled","tag":{"cn":"当 disabled 为 true 时,禁用整个选择框。如果 disabled 为函数,根据函数反回结果禁用选项","en":"When it is true, all nodes disable the selection; when it is a function, it determines whether it is disabled according to the return result of the function.","default":"false","version":""},"required":false,"type":"boolean | ((data: DataItem) => boolean) "},{"name":"expandTrigger","tag":{"cn":"节点展开触发方式","en":"Expand mode","default":"\\\"click\\\"","version":""},"required":false,"type":"\\\"click\\\" | \\\"hover\\\" | \\\"hover-only\\\" "},{"name":"onChange","tag":{"cn":"设置 onChange 属性时,显示 选择框。参数为当前选中值,和 mode 属性相关","en":"When the onChange property is set, the selection box is displayed. The parameter is the current selected value, which is related to the mode property.","default":"","version":""},"required":false,"type":"((value: Value, selected?: DataItem ) => void) "},{"name":"onFilter","tag":{"cn":"onFilter 不为空时,可以输入过滤数据;onFilter 如果返回一个函数,使用这个函数做前端过滤;如果不返回,可以自行做后端过滤;单选状态下支持","en":"When the onFilter is not empty, you can filter data by input.If the onFilter returns a function, use this function as a front-end filter.If return undefined, you can do your own backend filtering.support in single selection state.","default":"","version":""},"required":false,"type":"((text: string) => void | ((data: DataItem) => boolean) ) "},{"name":"keygen","tag":{"cn":"生成 key 的辅助方法, 为函数时,使用此函数返回值, 为 string 时,使用这个 string 对应的数据值。如 \\\"id\\\",相当于 (d) => d.id","en":"Auxiliary method for generating key. When it is a function, use the return value of this function. When it is a string, use the data value corresponding to this string. For example, \\\"id\\\" is the same thing as (d) => d.id.","default":"index","version":""},"required":true,"type":"ObjectKey | ((data: DataItem, parentKey?: string | number ) => string | number)"},{"name":"renderItem","tag":{"cn":"当 renderItem 为 string 时,返回 DataItem\\\\[string]。 若为函数时,则返回函数结果","en":"When \\\"renderItem\\\" is a string, it returns DataItem[string]. If it\\\"s a function, it returns the result of the function.","default":"d => d","version":""},"required":true,"type":"ObjectKey | ((data: DataItem, active?: boolean , id?: string | number ) => ReactNode)"},{"name":"renderResult","tag":{"cn":"选中后在结果中显示的内容,默认和 renderItem 相同","en":"The content displayed in the result after selecting, if not set, use renderItem. not show while return null, result is current selected","default":"renderItem","version":""},"required":false,"type":"ObjectKey | ((data: DataItem, row: DataItem[]) => ReactNode) "},{"name":"onBlur","tag":{"cn":"失焦事件","en":"blur event","default":"","version":""},"required":false,"type":"((e?: KeyboardEvent ) => void) "},{"name":"onFocus","tag":{"cn":"聚焦事件","en":"focus event","default":"","version":""},"required":false,"type":"((e?: KeyboardEvent ) => void) "},{"name":"placeholder","tag":{"cn":"占位符","en":"placeholder","default":"","version":""},"required":false,"type":"string "},{"name":"emptyAfterSelect","tag":{"cn":"选中后是否清空输入框内容","en":"empty input after select value","default":"true","version":""},"required":false,"type":"boolean "},{"name":"border","tag":{"cn":"是否展示边框","en":"Whether to display border","default":"true","version":""},"required":false,"type":"boolean "},{"name":"underline","tag":{"cn":"是否只展示下边框","en":"Only display border bottom","default":"","version":""},"required":false,"type":"boolean "},{"name":"resultClassName","tag":{"cn":"选中结果内容容器的className","en":"The className of the selected result content container","default":"","version":""},"required":false,"type":"string | ((value: DataItem) => string) "},{"name":"compressedClassName","tag":{"cn":"多选合并展示弹出框的类名","en":"Compressed popover classname","default":"","version":""},"required":false,"type":"string "},{"name":"focusSelected","tag":{"cn":"onFilter 在多选情况下点击选项后是否选中过滤文本","en":"onFilter Whether to select filter text after clicking the option in multi-selection situation","default":"true","version":""},"required":false,"type":"boolean "},{"name":"hideTag","tag":{"cn":"隐藏标签样式,默认情况下展示结果以标签模式分割,隐藏标签样式后可通过自定义 renderResult 渲染分割结果","en":"Hide tag style, by default, the result is displayed in tag mode. After hiding the tag style, the result can be rendered by custom renderResult","default":"false","version":""},"required":false,"type":"boolean "},{"name":"getComponentRef","tag":{"cn":"绑定组件的引用, 可以调用某些组件的方法","en":"A reference to the binding component, you can call some component methods","default":"","version":""},"required":false,"type":"((comp: CascaderRef) => void) | { current: CascaderRef ; } "},{"name":"adjust","tag":{"cn":"是否开启自动调整面板位置功能。当面板被窗口遮挡时,自动调整位置","en":"Whether to adjust the position of the panel automatically. When the panel is blocked by the window, the position is adjusted automatically","default":"true","version":""},"required":false,"type":"boolean "},{"name":"popover","tag":{"cn":"校验信息弹出位置","en":"The position where the validation info pop up","default":"","version":""},"required":false,"type":"PopoverProps[\\\"position\\\"]"},{"name":"popoverProps","tag":{"cn":"校验或者tip弹框接受的属性","en":"Vilidate popup properties","default":"","version":""},"required":false,"type":"PopoverProps "},{"name":"name","tag":{"cn":"Form 内存取数据的 key","en":"The key access data in the Form","default":"","version":""},"required":false,"type":"Name "},{"name":"beforeChange","tag":{"cn":"值改变前的回调,当返回值不为空时将作为组件的新值","en":"The callback before the value is changed, when the return value is not empty, it will be used as the new value of the component","default":"","version":""},"required":false,"type":"((value: T) => void | T ) "},{"name":"reserveAble","tag":{"cn":"设置为 true 组件卸载后表单不自动删除数据","en":"If set to true, the form will not automatically delete the data after the component is uninstalled","default":"","version":""},"required":false,"type":"boolean "},{"name":"rules","tag":{"cn":"校验规则 详见 [Rule](/components/rule)","en":"Validation rules, see [Rule](/components/rule) usage for details","default":"","version":""},"required":false,"type":"RuleItem[]"},{"name":"onError","tag":{"cn":"rules 校验回调","en":"rules validation callback","default":"","version":""},"required":false,"type":"((error?: Error ) => void) "},{"name":"bind","tag":{"cn":"当值改变是会联动校验 bind 中的字段, 需要配合 Form 使用","en":"When the value changes, it will link to verify the fields in the bind, which needs to be used with Form","default":"","version":""},"required":false,"type":"string[] "}],"cn":"","en":"","sort":"0"},{"title":"CascaderRef","properties":[{"name":"close","tag":{"cn":"关闭下拉框","en":"Close the drop-down box","default":"","version":""},"required":true,"type":"(e?: MouseEvent ) => void"}],"cn":"","en":"","sort":"0"}]'); export default api; diff --git a/docs/api/shineout/date-picker.ts b/docs/api/shineout/date-picker.ts index 616fedae2..13eb0bfeb 100644 --- a/docs/api/shineout/date-picker.ts +++ b/docs/api/shineout/date-picker.ts @@ -1,2 +1,2 @@ -const api = JSON.parse('[{"title":"DatePicker","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"size","tag":{"cn":"不同尺寸","en":"There are three built-in size: small、default、large.","default":"\\\"default\\\"","version":""},"required":false,"type":"\\\"small\\\" | \\\"large\\\" | \\\"default\\\""},{"name":"status","tag":{"cn":"组件状态","en":"The status of the component","default":"","version":""},"required":false,"type":"\\\"error\\\" "},{"name":"innerTitle","tag":{"cn":"内嵌标题","en":"inner title","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"placeTitle","tag":{"cn":"占位标题,需要配合 innerTitle 一起使用","en":"Placeholder title, which needs to be used together with innerTitle","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"absolute","tag":{"cn":"为 true 时,选项弹出层在 DOM 中独立 render; 为函数时,返回值作为弹出层容器","en":"When it is true, the pop-up layer of option append into document.body; When it is a function, the return value is used as the popup layer container","default":"false","version":""},"required":false,"type":"boolean | (() => HTMLElement | null) "},{"name":"zIndex","tag":{"cn":"选项列表 z-index 值, 需要配合 absolute","en":"options z-index should use with absolute","default":"1000","version":""},"required":false,"type":"number "},{"name":"children","tag":{"cn":"额外渲染的节点","en":"extra children","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"disabled","tag":{"cn":"如果 disabled 为 true,禁用全部选项,如果 disabled 为函数,根据函数反回结果禁用选项","en":"When the value is true, disabled all options; When the value is function, disable the options that this function returns true.","default":"false","version":""},"required":false,"type":"boolean | ((date: Date, type?: \\\"start\\\" | \\\"end\\\" , value0?: Date , value1?: Date ) => boolean) | (boolean | ((date: Date) => boolean))[] "},{"name":"disabledTime","tag":{"cn":"禁用指定 Time。","en":"Disable the specified Time.","default":"","version":""},"required":false,"type":"string | ((time: string) => boolean) "},{"name":"open","tag":{"cn":"控制浮层显隐","en":"Set visible of datepicker popup","default":"","version":""},"required":false,"type":"boolean "},{"name":"onCollapse","tag":{"cn":"下拉列表展开/收起回调","en":"option list collapse callback","default":"","version":""},"required":false,"type":"((collapse: boolean) => void) "},{"name":"align","tag":{"cn":"值水平排布方式","en":"Horizontal align of the value","default":"\\\"center\\\"","version":""},"required":false,"type":"\\\"left\\\" | \\\"right\\\" | \\\"center\\\" "},{"name":"timeZone","tag":{"cn":"设置默认时区,格式为/^([+-]\\\\d{2})$/ 支持 \\\"-12\\\" 到 \\\"+13\\\"","en":"Set the default time zone, the format is /^([+-]\\\\d{2})$/ Support \\\"-12\\\" to \\\"+13\\\"","default":"","version":""},"required":false,"type":"string "},{"name":"position","tag":{"cn":"弹出框位置","en":"Set Position can control the different position of DatePicker","default":"","version":"1.1.1"},"required":false,"type":"\\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\" "},{"name":"type","tag":{"cn":"时间类型","en":"type of datepicker","default":"\\\"date\\\"","version":""},"required":false,"type":"\\\"date\\\" | \\\"time\\\" | \\\"datetime\\\" | \\\"month\\\" | \\\"week\\\" | \\\"quarter\\\" | \\\"year\\\" "},{"name":"format","tag":{"cn":"不同type对应的默认值。\\\"date\\\": \\\"YYYY-MM-DD\\\"; \\\"time\\\": \\\"HH:mm:ss\\\"; \\\"week\\\": \\\"GGGG WW\\\"; \\\"month\\\": \\\"YYYY-MM\\\"; \\\"quarter\\\": \\\"YYYY-\\\\[Q]Q\\\"; \\\"year\\\": \\\"YYYY\\\"; \\\"datetime\\\": \\\"YYYY-MM-DD HH:mm:ss\\\"","en":"default values for different types: \\\"date\\\": \\\"YYYY-MM-DD\\\"; \\\"time\\\": \\\"HH:mm:ss\\\"; \\\"week\\\": \\\"GGGG WW\\\"; \\\"month\\\": \\\"YYYY-MM\\\"; \\\"week\\\": \\\"GGGG WW\\\"; \\\"quarter\\\": \\\"YYYY-\\\\[Q]Q\\\"; \\\"year\\\": \\\"YYYY\\\"; \\\"datetime\\\": \\\"YYYY-MM-DD HH:mm:ss\\\"","default":"","version":""},"required":false,"type":"string "},{"name":"formatResult","tag":{"cn":"对选中时间进行格式化","en":"Format the selected time","default":"props.format","version":""},"required":false,"type":"string | ((date: Date) => string) "},{"name":"range","tag":{"cn":"范围跨度,单位 秒,为 true 时表示不限制选择范围","en":"Range span,unit: second,When it is true, selection scope is not limited","default":"","version":""},"required":false,"type":"number | boolean "},{"name":"value","tag":{"cn":"值为 string 时,需要和 format 属性匹配。非 string 会格式化为 string。range 属性为 true 时,值为长度为2的数组","en":"When the value is string, it needs to match the format attribute.When the range property is true, the value is an array of length 2","default":"","version":""},"required":false,"type":"Value "},{"name":"defaultValue","tag":{"cn":"默认值 和 value 类型相同","en":"Default value","default":"","version":""},"required":false,"type":"Value "},{"name":"onChange","tag":{"cn":"值改变回调函数","en":"A callback when the value is changing","default":"","version":""},"required":false,"type":"((value: Value extends any[] ? string[] : string) => void) "},{"name":"clearable","tag":{"cn":"是否显示清除数据图标","en":"If clearable is true, show clear value icon","default":"true","version":""},"required":false,"type":"boolean "},{"name":"clearWithUndefined","tag":{"cn":"清空值时抛出 undefined","en":"onChange get undefined while clear","default":"false","version":""},"required":false,"type":"boolean "},{"name":"allowSingle","tag":{"cn":"是否允许单选, 仅在 range 模式下有效","en":"allow single select, only in range can set","default":"false","version":""},"required":false,"type":"boolean "},{"name":"border","tag":{"cn":"是否展示边框","en":"Whether to display border","default":"true","version":""},"required":false,"type":"boolean "},{"name":"defaultRangeMonth","tag":{"cn":"使用 defaultPickerValue 代替","en":"use defaultPickerValue instead","default":"","version":""},"required":false,"type":"(Date | number | string )[] "},{"name":"defaultPickerValue","tag":{"cn":"面板默认时间,在未选择日期时生效","en":"default date of panel,work under has no value","default":"","version":""},"required":false,"type":"Date | number | string | (Date | number | string )[]"},{"name":"placeholder","tag":{"cn":"占位文字。range 属性不为空时,为长度为2的数组","en":"placeholder text. When the range property is not empty, it is an array of length 2.","default":"","version":""},"required":false,"type":"string | string[] "},{"name":"defaultTime","tag":{"cn":"选择日期时默认的时间, 格式为: \\\"HH:mm:ss\\\"","en":"Default time when selecting a date, the format is: \\\"HH:mm:ss\\\"","default":"","version":""},"required":false,"type":"DateTimeType | DateTimeType[]"},{"name":"min","tag":{"cn":"可选最小值","en":"option min value","default":"","version":""},"required":false,"type":"Date | number | string "},{"name":"max","tag":{"cn":"可选最大值","en":"option max value","default":"","version":""},"required":false,"type":"Date | number | string "},{"name":"hourStep","tag":{"cn":"小时选项步长","en":"hour step","default":"","version":""},"required":false,"type":"number "},{"name":"minuteStep","tag":{"cn":"分钟选项步长","en":"minute step","default":"","version":""},"required":false,"type":"number "},{"name":"secondStep","tag":{"cn":"秒选项步长","en":"second step","default":"","version":""},"required":false,"type":"number "},{"name":"quickSelect","tag":{"cn":"快速选择, 仅在 range 模式下有效, name: 文字提示, value: 时间范围","en":"quick select, only in range can set, name: tip, value: range date","default":"","version":""},"required":false,"type":"{name: string, value: Value}[]"},{"name":"showSelNow","tag":{"cn":"是否展示今天或者此刻按钮","en":"quick select, only in range can set, name: tip, value: range date","default":"","version":""},"required":false,"type":"boolean "},{"name":"inputable","tag":{"cn":"可输入","en":"Allow enter something into DatePicker","default":"false","version":""},"required":false,"type":"boolean "},{"name":"onPickerChange","tag":{"cn":"值改变回调,有别于 onChange, onPickerChange会在每项值改变的时候执行","en":"value onchange callback (every type of date)","default":"","version":""},"required":false,"type":"((value: DateTimeType | DateTimeType[], quickSelectItem: void | { name: ReactNode, value: DateTimeType | DateTimeType[] | (() => DateTimeType | DateTimeType[]) } , areaType: \\\"year\\\" | \\\"month\\\" | \\\"week\\\" | \\\"day\\\" | \\\"time\\\" | \\\"quick\\\" | \\\"quarter\\\") => void) "},{"name":"onBlur","tag":{"cn":"blur 事件回调","en":"blur event callback","default":"","version":""},"required":false,"type":"((e: any) => void) "},{"name":"onFocus","tag":{"cn":"focus 事件回调","en":"focus event callback","default":"","version":""},"required":false,"type":"((e: any) => void) "},{"name":"underline","tag":{"cn":"是否只展示下边框","en":"only display border bottom","default":"false","version":""},"required":false,"type":"boolean "},{"name":"width","tag":{"cn":"自定义宽度","en":"custom width","default":"","version":""},"required":false,"type":"string | number "},{"name":"adjust","tag":{"cn":"是否开启自动调整面板位置功能。当面板被窗口遮挡时,自动调整位置","en":"Whether to adjust the position of the panel automatically. When the panel is blocked by the window, the position is adjusted automatically","default":"true","version":""},"required":false,"type":"boolean "},{"name":"popover","tag":{"cn":"校验信息弹出位置","en":"The position where the validation info pop up","default":"","version":""},"required":false,"type":"PopoverProps[\\\"position\\\"]"},{"name":"popoverProps","tag":{"cn":"校验或者tip弹框接受的属性","en":"Vilidate popup properties","default":"","version":""},"required":false,"type":"PopoverProps "},{"name":"name","tag":{"cn":"Form 内存取数据的 key","en":"The key access data in the Form","default":"","version":""},"required":false,"type":"Name "},{"name":"beforeChange","tag":{"cn":"值改变前的回调,当返回值不为空时将作为组件的新值","en":"The callback before the value is changed, when the return value is not empty, it will be used as the new value of the component","default":"","version":""},"required":false,"type":"((value: T) => void | T ) "},{"name":"reserveAble","tag":{"cn":"设置为 true 组件卸载后表单不自动删除数据","en":"If set to true, the form will not automatically delete the data after the component is uninstalled","default":"","version":""},"required":false,"type":"boolean "},{"name":"rules","tag":{"cn":"校验规则 详见 [Rule](/components/rule)","en":"Validation rules, see [Rule](/components/rule) usage for details","default":"","version":""},"required":false,"type":"RuleItem[]"},{"name":"onError","tag":{"cn":"rules 校验回调","en":"rules validation callback","default":"","version":""},"required":false,"type":"((error?: Error ) => void) "},{"name":"bind","tag":{"cn":"当值改变是会联动校验 bind 中的字段, 需要配合 Form 使用","en":"When the value changes, it will link to verify the fields in the bind, which needs to be used with Form","default":"","version":""},"required":false,"type":"string[] "}],"cn":"","en":"","sort":"0"}]'); +const api = JSON.parse('[{"title":"DatePicker","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"size","tag":{"cn":"不同尺寸","en":"There are three built-in size: small、default、large.","default":"\\\"default\\\"","version":""},"required":false,"type":"\\\"small\\\" | \\\"large\\\" | \\\"default\\\""},{"name":"status","tag":{"cn":"组件状态","en":"The status of the component","default":"","version":""},"required":false,"type":"\\\"error\\\" "},{"name":"innerTitle","tag":{"cn":"内嵌标题","en":"inner title","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"placeTitle","tag":{"cn":"占位标题,需要配合 innerTitle 一起使用","en":"Placeholder title, which needs to be used together with innerTitle","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"absolute","tag":{"cn":"为 true 时,选项弹出层在 DOM 中独立 render; 为函数时,返回值作为弹出层容器","en":"When it is true, the pop-up layer of option append into document.body; When it is a function, the return value is used as the popup layer container","default":"false","version":""},"required":false,"type":"boolean | (() => HTMLElement | null) "},{"name":"zIndex","tag":{"cn":"选项列表 z-index 值, 需要配合 absolute","en":"options z-index should use with absolute","default":"1000","version":""},"required":false,"type":"number "},{"name":"children","tag":{"cn":"额外渲染的节点","en":"extra children","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"disabled","tag":{"cn":"如果 disabled 为 true,禁用全部选项,如果 disabled 为函数,根据函数反回结果禁用选项","en":"When the value is true, disabled all options; When the value is function, disable the options that this function returns true.","default":"false","version":""},"required":false,"type":"boolean | ((date: Date, type?: \\\"start\\\" | \\\"end\\\" , value0?: Date , value1?: Date ) => boolean) | (boolean | ((date: Date) => boolean))[] "},{"name":"disabledTime","tag":{"cn":"禁用指定 Time。","en":"Disable the specified Time.","default":"","version":""},"required":false,"type":"string | ((time: string) => boolean) "},{"name":"open","tag":{"cn":"控制浮层显隐","en":"Set visible of datepicker popup","default":"","version":""},"required":false,"type":"boolean "},{"name":"onCollapse","tag":{"cn":"下拉列表展开/收起回调","en":"option list collapse callback","default":"","version":""},"required":false,"type":"((collapse: boolean) => void) "},{"name":"align","tag":{"cn":"值水平排布方式","en":"Horizontal align of the value","default":"\\\"center\\\"","version":""},"required":false,"type":"\\\"left\\\" | \\\"right\\\" | \\\"center\\\" "},{"name":"timeZone","tag":{"cn":"设置默认时区,格式为/^([+-]\\\\d{2})$/ 支持 \\\"-12\\\" 到 \\\"+13\\\"","en":"Set the default time zone, the format is /^([+-]\\\\d{2})$/ Support \\\"-12\\\" to \\\"+13\\\"","default":"","version":""},"required":false,"type":"string "},{"name":"position","tag":{"cn":"弹出框位置","en":"Set Position can control the different position of DatePicker","default":"","version":""},"required":false,"type":"\\\"top-left\\\" | \\\"top-right\\\" | \\\"bottom-left\\\" | \\\"bottom-right\\\" "},{"name":"type","tag":{"cn":"时间类型","en":"type of datepicker","default":"\\\"date\\\"","version":""},"required":false,"type":"\\\"date\\\" | \\\"time\\\" | \\\"datetime\\\" | \\\"month\\\" | \\\"week\\\" | \\\"quarter\\\" | \\\"year\\\" "},{"name":"format","tag":{"cn":"不同type对应的默认值。\\\"date\\\": \\\"YYYY-MM-DD\\\"; \\\"time\\\": \\\"HH:mm:ss\\\"; \\\"week\\\": \\\"GGGG WW\\\"; \\\"month\\\": \\\"YYYY-MM\\\"; \\\"quarter\\\": \\\"YYYY-\\\\[Q]Q\\\"; \\\"year\\\": \\\"YYYY\\\"; \\\"datetime\\\": \\\"YYYY-MM-DD HH:mm:ss\\\"","en":"default values for different types: \\\"date\\\": \\\"YYYY-MM-DD\\\"; \\\"time\\\": \\\"HH:mm:ss\\\"; \\\"week\\\": \\\"GGGG WW\\\"; \\\"month\\\": \\\"YYYY-MM\\\"; \\\"week\\\": \\\"GGGG WW\\\"; \\\"quarter\\\": \\\"YYYY-\\\\[Q]Q\\\"; \\\"year\\\": \\\"YYYY\\\"; \\\"datetime\\\": \\\"YYYY-MM-DD HH:mm:ss\\\"","default":"","version":""},"required":false,"type":"string "},{"name":"formatResult","tag":{"cn":"对选中时间进行格式化","en":"Format the selected time","default":"props.format","version":""},"required":false,"type":"string | ((date: Date) => string) "},{"name":"range","tag":{"cn":"范围跨度,单位 秒,为 true 时表示不限制选择范围","en":"Range span,unit: second,When it is true, selection scope is not limited","default":"","version":""},"required":false,"type":"number | boolean "},{"name":"value","tag":{"cn":"值为 string 时,需要和 format 属性匹配。非 string 会格式化为 string。range 属性为 true 时,值为长度为2的数组","en":"When the value is string, it needs to match the format attribute.When the range property is true, the value is an array of length 2","default":"","version":""},"required":false,"type":"Value "},{"name":"defaultValue","tag":{"cn":"默认值 和 value 类型相同","en":"Default value","default":"","version":""},"required":false,"type":"Value "},{"name":"onChange","tag":{"cn":"值改变回调函数","en":"A callback when the value is changing","default":"","version":""},"required":false,"type":"((value: Value extends any[] ? string[] : string) => void) "},{"name":"clearable","tag":{"cn":"是否显示清除数据图标","en":"If clearable is true, show clear value icon","default":"true","version":""},"required":false,"type":"boolean "},{"name":"clearWithUndefined","tag":{"cn":"清空值时抛出 undefined","en":"onChange get undefined while clear","default":"false","version":""},"required":false,"type":"boolean "},{"name":"clearToUndefined","tag":{"cn":"点击清除按钮后数据变为 undefined","en":"After clicking the clear button, the data becomes undefined","default":"false","version":"3.4.0"},"required":false,"type":"boolean "},{"name":"allowSingle","tag":{"cn":"是否允许单选, 仅在 range 模式下有效","en":"allow single select, only in range can set","default":"false","version":""},"required":false,"type":"boolean "},{"name":"border","tag":{"cn":"是否展示边框","en":"Whether to display border","default":"true","version":""},"required":false,"type":"boolean "},{"name":"defaultRangeMonth","tag":{"cn":"使用 defaultPickerValue 代替","en":"use defaultPickerValue instead","default":"","version":""},"required":false,"type":"(Date | number | string )[] "},{"name":"defaultPickerValue","tag":{"cn":"面板默认时间,在未选择日期时生效","en":"default date of panel,work under has no value","default":"","version":""},"required":false,"type":"Date | number | string | (Date | number | string )[]"},{"name":"placeholder","tag":{"cn":"占位文字。range 属性不为空时,为长度为2的数组","en":"placeholder text. When the range property is not empty, it is an array of length 2.","default":"","version":""},"required":false,"type":"string | string[] "},{"name":"defaultTime","tag":{"cn":"选择日期时默认的时间, 格式为: \\\"HH:mm:ss\\\"","en":"Default time when selecting a date, the format is: \\\"HH:mm:ss\\\"","default":"","version":""},"required":false,"type":"DateTimeType | DateTimeType[]"},{"name":"min","tag":{"cn":"可选最小值","en":"option min value","default":"","version":""},"required":false,"type":"Date | number | string "},{"name":"max","tag":{"cn":"可选最大值","en":"option max value","default":"","version":""},"required":false,"type":"Date | number | string "},{"name":"hourStep","tag":{"cn":"小时选项步长","en":"hour step","default":"","version":""},"required":false,"type":"number "},{"name":"minuteStep","tag":{"cn":"分钟选项步长","en":"minute step","default":"","version":""},"required":false,"type":"number "},{"name":"secondStep","tag":{"cn":"秒选项步长","en":"second step","default":"","version":""},"required":false,"type":"number "},{"name":"quickSelect","tag":{"cn":"快速选择, 仅在 range 模式下有效, name: 文字提示, value: 时间范围","en":"quick select, only in range can set, name: tip, value: range date","default":"","version":""},"required":false,"type":"{name: string, value: Value}[]"},{"name":"showSelNow","tag":{"cn":"是否展示今天或者此刻按钮","en":"quick select, only in range can set, name: tip, value: range date","default":"","version":""},"required":false,"type":"boolean "},{"name":"inputable","tag":{"cn":"可输入","en":"Allow enter something into DatePicker","default":"false","version":""},"required":false,"type":"boolean "},{"name":"onPickerChange","tag":{"cn":"值改变回调,有别于 onChange, onPickerChange会在每项值改变的时候执行","en":"value onchange callback (every type of date)","default":"","version":""},"required":false,"type":"((value: DateTimeType | DateTimeType[], quickSelectItem: void | { name: ReactNode, value: DateTimeType | DateTimeType[] | (() => DateTimeType | DateTimeType[]) } , areaType: \\\"year\\\" | \\\"month\\\" | \\\"week\\\" | \\\"day\\\" | \\\"time\\\" | \\\"quick\\\" | \\\"quarter\\\") => void) "},{"name":"onBlur","tag":{"cn":"blur 事件回调","en":"blur event callback","default":"","version":""},"required":false,"type":"((e: any) => void) "},{"name":"onFocus","tag":{"cn":"focus 事件回调","en":"focus event callback","default":"","version":""},"required":false,"type":"((e: any) => void) "},{"name":"underline","tag":{"cn":"是否只展示下边框","en":"only display border bottom","default":"false","version":""},"required":false,"type":"boolean "},{"name":"width","tag":{"cn":"自定义宽度","en":"custom width","default":"","version":""},"required":false,"type":"string | number "},{"name":"adjust","tag":{"cn":"是否开启自动调整面板位置功能。当面板被窗口遮挡时,自动调整位置","en":"Whether to adjust the position of the panel automatically. When the panel is blocked by the window, the position is adjusted automatically","default":"true","version":""},"required":false,"type":"boolean "},{"name":"needConfirm","tag":{"cn":"是否开启手动确认按钮,开启后只有点击确认按钮才会提交选择的值。","en":"Whether to open the manual confirmation button. After opening, only clicking the confirmation button will submit the selected value.","default":"false","version":"3.4.0"},"required":false,"type":"boolean "},{"name":"popover","tag":{"cn":"校验信息弹出位置","en":"The position where the validation info pop up","default":"","version":""},"required":false,"type":"PopoverProps[\\\"position\\\"]"},{"name":"popoverProps","tag":{"cn":"校验或者tip弹框接受的属性","en":"Vilidate popup properties","default":"","version":""},"required":false,"type":"PopoverProps "},{"name":"name","tag":{"cn":"Form 内存取数据的 key","en":"The key access data in the Form","default":"","version":""},"required":false,"type":"Name "},{"name":"beforeChange","tag":{"cn":"值改变前的回调,当返回值不为空时将作为组件的新值","en":"The callback before the value is changed, when the return value is not empty, it will be used as the new value of the component","default":"","version":""},"required":false,"type":"((value: T) => void | T ) "},{"name":"reserveAble","tag":{"cn":"设置为 true 组件卸载后表单不自动删除数据","en":"If set to true, the form will not automatically delete the data after the component is uninstalled","default":"","version":""},"required":false,"type":"boolean "},{"name":"rules","tag":{"cn":"校验规则 详见 [Rule](/components/rule)","en":"Validation rules, see [Rule](/components/rule) usage for details","default":"","version":""},"required":false,"type":"RuleItem[]"},{"name":"onError","tag":{"cn":"rules 校验回调","en":"rules validation callback","default":"","version":""},"required":false,"type":"((error?: Error ) => void) "},{"name":"bind","tag":{"cn":"当值改变是会联动校验 bind 中的字段, 需要配合 Form 使用","en":"When the value changes, it will link to verify the fields in the bind, which needs to be used with Form","default":"","version":""},"required":false,"type":"string[] "}],"cn":"","en":"","sort":"0"}]'); export default api; diff --git a/docs/api/shineout/link.ts b/docs/api/shineout/link.ts new file mode 100644 index 000000000..407fd805d --- /dev/null +++ b/docs/api/shineout/link.ts @@ -0,0 +1,2 @@ +const api = JSON.parse('[{"title":"Link","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"disabled","tag":{"cn":"是否禁用","en":"Whether the link is disabled","default":"","version":""},"required":false,"type":"boolean "},{"name":"underline","tag":{"cn":"是否常驻显示下划线, 设置为 \\\"hover\\\" 时鼠标悬浮时显示下划线","en":"Whether to always show the underline, set to \\\"hover\\\" to show the underline when the mouse is hovered","default":"","version":""},"required":false,"type":"boolean | \\\"hover\\\" "},{"name":"type","tag":{"cn":"链接类型","en":"Link type","default":"primary","version":""},"required":false,"type":"\\\"primary\\\" | \\\"secondary\\\" | \\\"danger\\\" | \\\"warning\\\" | \\\"success\\\" "},{"name":"size","tag":{"cn":"链接图标大小","en":"Link icon size","default":"default","version":""},"required":false,"type":"\\\"small\\\" | \\\"default\\\" | \\\"large\\\" "},{"name":"icon","tag":{"cn":"显示图标,设置为 true 时展示默认图标","en":"Show icon, set to true to show default icon","default":"","version":""},"required":false,"type":"ReactNode"}],"cn":"","en":"","sort":"0"}]'); +export default api; diff --git a/docs/api/shineout/menu.ts b/docs/api/shineout/menu.ts index 32412a74e..e08bbcae0 100644 --- a/docs/api/shineout/menu.ts +++ b/docs/api/shineout/menu.ts @@ -1,2 +1,2 @@ -const api = JSON.parse('[{"title":"menu","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"mode","tag":{"cn":"菜单样式","en":"style of menu","default":"\\\"inline\\\"","version":""},"required":false,"type":"\\\"inline\\\" | \\\"vertical\\\" | \\\"horizontal\\\" | \\\"vertical-auto\\\" "},{"name":"data","tag":{"cn":"需要渲染成菜单的数据","en":"Menu items data","default":"[]","version":""},"required":false,"type":"object[]"},{"name":"theme","tag":{"cn":"主题","en":"theme of menu","default":"","version":""},"required":false,"type":"\\\"dark\\\" | \\\"light\\\" "},{"name":"height","tag":{"cn":"菜单高度","en":"menu height","default":"","version":""},"required":false,"type":"string | number "},{"name":"openKeys","tag":{"cn":"展开的菜单(受控)","en":"expended menu","default":"[]","version":""},"required":false,"type":"(string | number)[]"},{"name":"caretColor","tag":{"cn":"三角展开符颜色","en":"triangle expansion color","default":"","version":""},"required":false,"type":"string "},{"name":"frontCaret","tag":{"cn":"前置实心三角展开符","en":"Front solid triangle expansion","default":"","version":""},"required":false,"type":"boolean "},{"name":"inlineIndent","tag":{"cn":"每一层缩进宽度","en":"indent of each level","default":"24","version":""},"required":false,"type":"number "},{"name":"looseChildren","tag":{"cn":"如果 children 有设置则菜单项可展开","en":"menu item expandable if has children","default":"false","version":""},"required":false,"type":"boolean "},{"name":"keygen","tag":{"cn":"生成每一项key的辅助方法。为 true 时,以数据项本身作为key,相当于 (d => d)。为函数时,使用此函数返回值。为string时,使用这个string对应的数据值。如 \\\"id\\\",相当于 (d => d.id)","en":"Key generator. When it is true, the data itself is used as the key equivalent to (d => d). When it is a function, use its return value. When it is a string,ues the value of the string. For example, \\\"id\\\" is the same thing as (d) => d.id.","default":"true","version":""},"required":true,"type":"| ObjectKey | ((data: DataItem, index?: number) => string | number) | true"},{"name":"defaultOpenKeys","tag":{"cn":"初始展开的菜单;如果需要设置此值,则需要设置keygen,此值为一个包含key的数组","en":"Initial expanded menu","default":"[]","version":""},"required":false,"type":"(string | number)[]"},{"name":"parentSelectable","tag":{"cn":"父级菜单是否可选中","en":"parent menu Selectable","default":"false","version":""},"required":false,"type":"boolean "},{"name":"onClick","tag":{"cn":"子菜单点击事件,参数为当条数据","en":"The function will be called when the user clicks the menu item.","default":"","version":""},"required":false,"type":"((data: DataItem) => void) "},{"name":"active","tag":{"cn":"验证是否激活,参数为对应的数据对象,返回true则代表该菜单激活","en":"The item is actived when the active function return true.","default":"","version":""},"required":false,"type":"((data: DataItem) => boolean) "},{"name":"disabled","tag":{"cn":"是否禁用选项","en":"Whether to be disabled","default":"d => d.disabled","version":""},"required":false,"type":"((data: DataItem) => boolean) "},{"name":"frontCaretType","tag":{"cn":"前置三角展开符类型","en":"front triangle expansion symbol type","default":"\\\"solid\\\"","version":""},"required":false,"type":"\\\"hollow\\\" | \\\"solid\\\" "},{"name":"onOpenChange","tag":{"cn":"菜单展开/收起回调","en":"menu open change callback","default":"","version":""},"required":false,"type":"((keys: Key[]) => void) "},{"name":"linkKey","tag":{"cn":"需要注入子菜单的链接键值","en":"the key of inject the link value of the submenu","default":"","version":""},"required":false,"type":"((d: DataItem) => string) | ObjectKey "},{"name":"renderItem","tag":{"cn":"元素渲染方式,如果为字符串,则会以对应的值作为显示内容;如果为函数,则以函数返回的结果作为显示内容,函数参数为对应的数据对象","en":"Element render mode. If it is a string, the corresponding value is taken as the display content; If it is a function, the result returned by the function is taken as the display content.","default":"\\\"title\\\"","version":""},"required":false,"type":"ObjectKey | ((data: DataItem, index: number) => ReactNode) "},{"name":"renderIcon","tag":{"cn":"渲染Icon","en":"Render Icon","default":"","version":""},"required":false,"type":"((data: DataItem) => ReactNode) "},{"name":"collapse","tag":{"cn":"是否折叠","en":"Whether to collapse","default":"false","version":""},"required":false,"type":"boolean "},{"name":"header","tag":{"cn":"头部内容, 仅在 mode为 \\\"inline\\\" 时生效","en":"","default":"","version":""},"required":false,"type":"ReactNode"}],"cn":"","en":"","sort":"0"}]'); +const api = JSON.parse('[{"title":"Menu","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"mode","tag":{"cn":"菜单样式","en":"style of menu","default":"\\\"inline\\\"","version":""},"required":false,"type":"\\\"inline\\\" | \\\"vertical\\\" | \\\"horizontal\\\" | \\\"vertical-auto\\\" "},{"name":"data","tag":{"cn":"需要渲染成菜单的数据","en":"Menu items data","default":"[]","version":""},"required":false,"type":"object[]"},{"name":"theme","tag":{"cn":"主题","en":"theme of menu","default":"","version":""},"required":false,"type":"\\\"dark\\\" | \\\"light\\\" "},{"name":"height","tag":{"cn":"菜单高度","en":"menu height","default":"","version":""},"required":false,"type":"string | number "},{"name":"openKeys","tag":{"cn":"展开的菜单(受控)","en":"expended menu","default":"[]","version":""},"required":false,"type":"(string | number)[]"},{"name":"caretColor","tag":{"cn":"三角展开符颜色","en":"triangle expansion color","default":"","version":""},"required":false,"type":"string "},{"name":"frontCaret","tag":{"cn":"前置实心三角展开符","en":"Front solid triangle expansion","default":"","version":""},"required":false,"type":"boolean "},{"name":"inlineIndent","tag":{"cn":"每一层缩进宽度","en":"indent of each level","default":"24","version":""},"required":false,"type":"number "},{"name":"looseChildren","tag":{"cn":"如果 children 有设置则菜单项可展开","en":"menu item expandable if has children","default":"false","version":""},"required":false,"type":"boolean "},{"name":"keygen","tag":{"cn":"生成每一项key的辅助方法。为 true 时,以数据项本身作为key,相当于 (d => d)。为函数时,使用此函数返回值。为string时,使用这个string对应的数据值。如 \\\"id\\\",相当于 (d => d.id)","en":"Key generator. When it is true, the data itself is used as the key equivalent to (d => d). When it is a function, use its return value. When it is a string,ues the value of the string. For example, \\\"id\\\" is the same thing as (d) => d.id.","default":"true","version":""},"required":true,"type":"| ObjectKey | ((data: DataItem, index?: number) => string | number) | true"},{"name":"defaultOpenKeys","tag":{"cn":"初始展开的菜单;如果需要设置此值,则需要设置keygen,此值为一个包含key的数组","en":"Initial expanded menu","default":"[]","version":""},"required":false,"type":"(string | number)[]"},{"name":"parentSelectable","tag":{"cn":"父级菜单是否可选中","en":"parent menu Selectable","default":"false","version":""},"required":false,"type":"boolean "},{"name":"onClick","tag":{"cn":"子菜单点击事件,参数为当条数据","en":"The function will be called when the user clicks the menu item.","default":"","version":""},"required":false,"type":"((data: DataItem) => void) "},{"name":"active","tag":{"cn":"验证是否激活,参数为对应的数据对象,返回true则代表该菜单激活","en":"The item is actived when the active function return true.","default":"","version":""},"required":false,"type":"((data: DataItem) => boolean) "},{"name":"disabled","tag":{"cn":"是否禁用选项","en":"Whether to be disabled","default":"d => d.disabled","version":""},"required":false,"type":"((data: DataItem) => boolean) "},{"name":"frontCaretType","tag":{"cn":"前置三角展开符类型","en":"front triangle expansion symbol type","default":"\\\"solid\\\"","version":""},"required":false,"type":"\\\"hollow\\\" | \\\"solid\\\" "},{"name":"onOpenChange","tag":{"cn":"菜单展开/收起回调","en":"menu open change callback","default":"","version":""},"required":false,"type":"((keys: Key[]) => void) "},{"name":"linkKey","tag":{"cn":"需要注入子菜单的链接键值","en":"the key of inject the link value of the submenu","default":"","version":""},"required":false,"type":"((d: DataItem) => string) | ObjectKey "},{"name":"renderItem","tag":{"cn":"元素渲染方式,如果为字符串,则会以对应的值作为显示内容;如果为函数,则以函数返回的结果作为显示内容,函数参数为对应的数据对象","en":"Element render mode. If it is a string, the corresponding value is taken as the display content; If it is a function, the result returned by the function is taken as the display content.","default":"\\\"title\\\"","version":""},"required":false,"type":"ObjectKey | ((data: DataItem, index: number) => ReactNode) "},{"name":"renderIcon","tag":{"cn":"渲染Icon","en":"Render Icon","default":"","version":""},"required":false,"type":"((data: DataItem) => ReactNode) "},{"name":"collapse","tag":{"cn":"是否折叠","en":"Whether to collapse","default":"false","version":""},"required":false,"type":"boolean "},{"name":"header","tag":{"cn":"头部内容, 仅在 mode为 \\\"inline\\\" 时生效","en":"","default":"","version":""},"required":false,"type":"ReactNode"}],"cn":"","en":"","sort":"0"}]'); export default api; diff --git a/docs/api/shineout/popover.ts b/docs/api/shineout/popover.ts index 0e8ea0af4..e077c66e7 100644 --- a/docs/api/shineout/popover.ts +++ b/docs/api/shineout/popover.ts @@ -1,2 +1,2 @@ -const api = JSON.parse('[{"title":"Popover","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"position","tag":{"cn":"弹出层位置。若不设置,则默认为 auto","en":"The position of pop-up layer. Default auto","default":"","version":""},"required":false,"type":"| \\\"left-top\\\" | \\\"left-bottom\\\" | \\\"right-top\\\" | \\\"right-bottom\\\" | \\\"top-right\\\" | \\\"top-left\\\" | \\\"bottom-right\\\" | \\\"bottom-left\\\" | \\\"left\\\" | \\\"right\\\" | \\\"top\\\" | \\\"bottom\\\" | \\\"auto\\\" "},{"name":"priorityDirection","tag":{"cn":"弹出位置优先级, 默认为左右优先, 只在未设置 position 时生效","en":"Popup location priority, default is top and bottom priority, only valid when position is not set, Options: [\\\"vertical\\\", \\\"horizontal\\\", \\\"auto\\\"]","default":"\\\"vertical\\\"","version":""},"required":false,"type":"\\\"auto\\\" | \\\"vertical\\\" | \\\"horizontal\\\" "},{"name":"mouseEnterDelay","tag":{"cn":"移入显示延迟(毫秒)","en":"The show delay of mouseenter(ms)","default":"0","version":""},"required":false,"type":"number "},{"name":"mouseLeaveDelay","tag":{"cn":"移除隐藏延迟(毫秒)","en":"The hidden delay of mouseleave (ms)","default":"0","version":""},"required":false,"type":"number "},{"name":"trigger","tag":{"cn":"触发方式","en":"Trigger mode","default":"\\\"hover\\\"","version":""},"required":false,"type":"\\\"click\\\" | \\\"hover\\\" "},{"name":"destroy","tag":{"cn":"关闭 Popover 后销毁内容 dom","en":"Delete dom when close","default":"false","version":""},"required":false,"type":"boolean "},{"name":"visible","tag":{"cn":"是否可见(受控)","en":"Is visible (controlled)","default":"","version":""},"required":false,"type":"boolean "},{"name":"onVisibleChange","tag":{"cn":"The event of visible change","en":"显示隐藏改变时事件","default":"","version":""},"required":false,"type":"((open: boolean) => void) "},{"name":"onOpen","tag":{"cn":"Popover 弹出回调事件","en":"Callback event when open","default":"","version":""},"required":false,"type":"(() => void) "},{"name":"onClose","tag":{"cn":"Popover 关闭时回调事件","en":"Callback event when close","default":"","version":""},"required":false,"type":"(() => void) "},{"name":"children","tag":{"cn":"弹出显示内容,如果内容为函数,则参数是主动关闭操作","en":"Pop-up content","default":"index","version":""},"required":false,"type":"ReactNode | ((close: () => void) => ReactNode)"},{"name":"getPopupContainer","tag":{"cn":"自定义 Popover 容器,覆盖默认渲染在 body 下的行为, () => DOMElement","en":"Custom Popover container, override the default behavior which is rendering under the body, () => DOMElement","default":"","version":""},"required":false,"type":"(() => HTMLElement | null) "},{"name":"useTextStyle","tag":{"cn":"使用内置文本样式","en":"Using inner styles","default":"","version":""},"required":false,"type":"boolean "},{"name":"type","tag":{"cn":"Type of popover","en":"类型","default":"","version":""},"required":false,"type":"\\\"info\\\" | \\\"success\\\" | \\\"warning\\\" | \\\"danger\\\" | \\\"error\\\" "},{"name":"border","tag":{"cn":"弹出层边框颜色(含箭头)","en":"The color of pop-up border(with arrows)","default":"","version":""},"required":false,"type":"string "},{"name":"background","tag":{"cn":"弹出层背景色(含箭头)","en":"Pop-up background-color(with arrows)","default":"","version":""},"required":false,"type":"string "},{"name":"zIndex","tag":{"cn":"Popover 层级","en":"Z-index of popover","default":"1060","version":""},"required":false,"type":"number "},{"name":"showArrow","tag":{"cn":"是否显示箭头","en":"Show arrow","default":"true","version":""},"required":false,"type":"boolean "},{"name":"defaultVisible","tag":{"cn":"默认是否显示","en":"Whether to display by default","default":"","version":""},"required":false,"type":"boolean "},{"name":"clickToCancelDelay","tag":{"cn":"MouseEnterDelay 内点击元素后取消弹出","en":"Cancel the popup after clicking the element in mouseEnterDelay","default":"false","version":""},"required":false,"type":"boolean "},{"name":"scrollDismiss","tag":{"cn":"滚动来关闭气泡框,如果需要指定滚动元素,则通过函数返回","en":"Scroll to dismiss, return el to order scroller","default":"false","version":""},"required":false,"type":"boolean | (() => HTMLElement | null) "},{"name":"arrowClass","tag":{"cn":"箭头的 class 名称","en":"The class name of the arrow","default":"","version":""},"required":false,"type":"string "}],"cn":"","en":"","sort":"1"},{"title":"Popover.Confirm & Popover.Content","properties":[{"name":"type","tag":{"cn":"类型同 [Alert](/components/Alert) type 属性","en":"same with [Alert](/components/Alert) type","default":"\\\"confirmwarning\\\"","version":""},"required":false,"type":"\\\"success\\\" | \\\"info\\\" | \\\"warning\\\" | \\\"danger\\\" | \\\"confirmwarning\\\" | \\\"error\\\" "},{"name":"children","tag":{"cn":"弹出显示内容","en":"Pop-up content.","default":"","version":""},"required":true,"type":"ReactNode"},{"name":"text","tag":{"cn":"按钮文字","en":"button text","default":"{ ok: \\\"Ok\\\", cancel: \\\"Cancel\\\" }","version":""},"required":false,"type":"{ ok?: string ; cancel?: string ; } "},{"name":"onOk","tag":{"cn":"点击确定按钮时触发事件,返回 Promise 时,会在 Promise resolve 后关闭 Tooltip","en":"ok button click callback, will close tooltip while returned promise resolve","default":"","version":""},"required":false,"type":"(() => void | Promise) "},{"name":"onCancel","tag":{"cn":"点击取消按钮时触发事件,返回 Promise 时,会在 Promise resolve 后关闭 Tooltip","en":"cancel button click callback, will close tooltip while returned promise resolve","default":"","version":""},"required":false,"type":"(() => void | Promise) "},{"name":"okType","tag":{"cn":"确认按钮的类型,与 [Button](/components/Button) 类型相同","en":"ok button\\\"s type, same with [Button](/components/Button) type","default":"\\\"danger\\\"","version":""},"required":false,"type":"| \\\"default\\\" | \\\"primary\\\" | \\\"secondary\\\" | \\\"danger\\\" | \\\"warning\\\" | \\\"success\\\" | \\\"link\\\" "},{"name":"icon","tag":{"cn":"自定义Icon","en":"custom icon","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"title","tag":{"cn":"标题","en":"title","default":"","version":""},"required":false,"type":"ReactNode"}],"cn":"基本API 和 Popover 一致,特定API如下","en":"The basic API is consistent with Popover, and the specific API is as follows","sort":"2"}]'); +const api = JSON.parse('[{"title":"Popover","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"position","tag":{"cn":"弹出层位置。若不设置,则默认为 auto","en":"The position of pop-up layer. Default auto","default":"","version":""},"required":false,"type":"| \\\"left-top\\\" | \\\"left-bottom\\\" | \\\"right-top\\\" | \\\"right-bottom\\\" | \\\"top-right\\\" | \\\"top-left\\\" | \\\"bottom-right\\\" | \\\"bottom-left\\\" | \\\"left\\\" | \\\"right\\\" | \\\"top\\\" | \\\"bottom\\\" | \\\"auto\\\" "},{"name":"priorityDirection","tag":{"cn":"弹出位置优先级, 默认为左右优先, 只在未设置 position 时生效","en":"Popup location priority, default is top and bottom priority, only valid when position is not set, Options: [\\\"vertical\\\", \\\"horizontal\\\", \\\"auto\\\"]","default":"\\\"vertical\\\"","version":""},"required":false,"type":"\\\"auto\\\" | \\\"vertical\\\" | \\\"horizontal\\\" "},{"name":"mouseEnterDelay","tag":{"cn":"移入显示延迟(毫秒)","en":"The show delay of mouseenter(ms)","default":"0","version":""},"required":false,"type":"number "},{"name":"mouseLeaveDelay","tag":{"cn":"移除隐藏延迟(毫秒)","en":"The hidden delay of mouseleave (ms)","default":"0","version":""},"required":false,"type":"number "},{"name":"trigger","tag":{"cn":"触发方式","en":"Trigger mode","default":"\\\"hover\\\"","version":""},"required":false,"type":"\\\"click\\\" | \\\"hover\\\" "},{"name":"destroy","tag":{"cn":"关闭 Popover 后销毁内容 dom","en":"Delete dom when close","default":"false","version":""},"required":false,"type":"boolean "},{"name":"visible","tag":{"cn":"是否可见(受控)","en":"Is visible (controlled)","default":"","version":""},"required":false,"type":"boolean "},{"name":"onVisibleChange","tag":{"cn":"The event of visible change","en":"显示隐藏改变时事件","default":"","version":""},"required":false,"type":"((open: boolean) => void) "},{"name":"onOpen","tag":{"cn":"Popover 弹出回调事件","en":"Callback event when open","default":"","version":""},"required":false,"type":"(() => void) "},{"name":"onClose","tag":{"cn":"Popover 关闭时回调事件","en":"Callback event when close","default":"","version":""},"required":false,"type":"(() => void) "},{"name":"children","tag":{"cn":"弹出显示内容,如果内容为函数,则参数是主动关闭操作","en":"Pop-up content","default":"index","version":""},"required":false,"type":"ReactNode | ((close: () => void) => ReactNode)"},{"name":"getPopupContainer","tag":{"cn":"自定义 Popover 容器,覆盖默认渲染在 body 下的行为, () => DOMElement","en":"Custom Popover container, override the default behavior which is rendering under the body, () => DOMElement","default":"","version":""},"required":false,"type":"(() => HTMLElement | null) "},{"name":"useTextStyle","tag":{"cn":"使用内置文本样式","en":"Using inner styles","default":"","version":""},"required":false,"type":"boolean "},{"name":"type","tag":{"cn":"Type of popover","en":"类型","default":"","version":""},"required":false,"type":"\\\"info\\\" | \\\"success\\\" | \\\"warning\\\" | \\\"danger\\\" | \\\"error\\\" "},{"name":"border","tag":{"cn":"弹出层边框颜色(含箭头)","en":"The color of pop-up border(with arrows)","default":"","version":""},"required":false,"type":"string "},{"name":"background","tag":{"cn":"弹出层背景色(含箭头)","en":"Pop-up background-color(with arrows)","default":"","version":""},"required":false,"type":"string "},{"name":"zIndex","tag":{"cn":"Popover 层级","en":"Z-index of popover","default":"1060","version":""},"required":false,"type":"number "},{"name":"showArrow","tag":{"cn":"是否显示箭头","en":"Show arrow","default":"true","version":""},"required":false,"type":"boolean "},{"name":"defaultVisible","tag":{"cn":"默认是否显示","en":"Whether to display by default","default":"","version":""},"required":false,"type":"boolean "},{"name":"clickToCancelDelay","tag":{"cn":"MouseEnterDelay 内点击元素后取消弹出","en":"Cancel the popup after clicking the element in mouseEnterDelay","default":"false","version":""},"required":false,"type":"boolean "},{"name":"scrollDismiss","tag":{"cn":"滚动来关闭气泡框,如果需要指定滚动元素,则通过函数返回","en":"Scroll to dismiss, return el to order scroller","default":"false","version":""},"required":false,"type":"boolean | (() => HTMLElement | null) "},{"name":"arrowClass","tag":{"cn":"箭头的 class 名称","en":"The class name of the arrow","default":"","version":""},"required":false,"type":"string "}],"cn":"","en":"","sort":"1"},{"title":"Popover.Confirm","properties":[{"name":"type","tag":{"cn":"类型同 [Alert](/components/Alert) type 属性","en":"same with [Alert](/components/Alert) type","default":"\\\"confirmwarning\\\"","version":""},"required":false,"type":"\\\"success\\\" | \\\"info\\\" | \\\"warning\\\" | \\\"danger\\\" | \\\"confirmwarning\\\" | \\\"error\\\" "},{"name":"children","tag":{"cn":"弹出显示内容","en":"Pop-up content.","default":"","version":""},"required":true,"type":"ReactNode"},{"name":"text","tag":{"cn":"按钮文字","en":"button text","default":"{ ok: \\\"Ok\\\", cancel: \\\"Cancel\\\" }","version":""},"required":false,"type":"{ ok?: string ; cancel?: string ; } "},{"name":"onOk","tag":{"cn":"点击确定按钮时触发事件,返回 Promise 时,会在 Promise resolve 后关闭 Tooltip","en":"ok button click callback, will close tooltip while returned promise resolve","default":"","version":""},"required":false,"type":"(() => void | Promise) "},{"name":"onCancel","tag":{"cn":"点击取消按钮时触发事件,返回 Promise 时,会在 Promise resolve 后关闭 Tooltip","en":"cancel button click callback, will close tooltip while returned promise resolve","default":"","version":""},"required":false,"type":"(() => void | Promise) "},{"name":"okType","tag":{"cn":"确认按钮的类型,与 [Button](/components/Button) 类型相同","en":"ok button\\\"s type, same with [Button](/components/Button) type","default":"\\\"danger\\\"","version":""},"required":false,"type":"| \\\"default\\\" | \\\"primary\\\" | \\\"secondary\\\" | \\\"danger\\\" | \\\"warning\\\" | \\\"success\\\" | \\\"link\\\" "},{"name":"icon","tag":{"cn":"自定义Icon","en":"custom icon","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"title","tag":{"cn":"标题","en":"title","default":"","version":""},"required":false,"type":"ReactNode"}],"cn":"基本API 和 Popover 一致,特定API如下","en":"The basic API is consistent with Popover, and the specific API is as follows","sort":"2"}]'); export default api; diff --git a/docs/api/shineout/spin.ts b/docs/api/shineout/spin.ts index 3f4bdc15a..b9e73ed9a 100644 --- a/docs/api/shineout/spin.ts +++ b/docs/api/shineout/spin.ts @@ -1,2 +1,2 @@ -const api = JSON.parse('[{"title":"Spin","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"children","tag":{"cn":"作为包裹元素使用","en":"Spin has children","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"tip","tag":{"cn":"提示文案","en":"Custom tip","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"size","tag":{"cn":"尺寸","en":"Size","default":"40","version":""},"required":false,"type":"string | number "},{"name":"name","tag":{"cn":"类型","en":"Type","default":"","version":""},"required":false,"type":"| \\\"default\\\" | \\\"chasing-dots\\\" | \\\"cube-grid\\\" | \\\"double-bounce\\\" | \\\"fading-circle\\\" | \\\"four-dots\\\" | \\\"plane\\\" | \\\"pulse\\\" | \\\"ring\\\" | \\\"scale-circle\\\" | \\\"three-bounce\\\" | \\\"wave\\\" | \\\"chasing-ring\\\" "},{"name":"color","tag":{"cn":"颜色","en":"Color","default":"","version":""},"required":false,"type":"string "},{"name":"mode","tag":{"cn":"布局模式","en":"Layout mode","default":"\\\"vertical\\\"","version":""},"required":false,"type":"\\\"vertical\\\" | \\\"horizontal\\\" "},{"name":"loading","tag":{"cn":"是否为加载中","en":"Loading","default":"false","version":""},"required":false,"type":"boolean "}],"cn":"","en":"","sort":"0"}]'); +const api = JSON.parse('[{"title":"Spin","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"tipClassName","tag":{"cn":"tip 文案上的 className","en":"Tip className","default":"","version":""},"required":false,"type":"string "},{"name":"children","tag":{"cn":"作为包裹元素使用","en":"Spin has children","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"tip","tag":{"cn":"提示文案","en":"Custom tip","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"size","tag":{"cn":"尺寸","en":"Size","default":"40","version":""},"required":false,"type":"string | number "},{"name":"name","tag":{"cn":"类型","en":"Type","default":"","version":""},"required":false,"type":"| \\\"default\\\" | \\\"chasing-dots\\\" | \\\"cube-grid\\\" | \\\"double-bounce\\\" | \\\"fading-circle\\\" | \\\"four-dots\\\" | \\\"plane\\\" | \\\"pulse\\\" | \\\"ring\\\" | \\\"scale-circle\\\" | \\\"three-bounce\\\" | \\\"wave\\\" | \\\"chasing-ring\\\" "},{"name":"color","tag":{"cn":"颜色","en":"Color","default":"","version":""},"required":false,"type":"string "},{"name":"mode","tag":{"cn":"布局模式","en":"Layout mode","default":"\\\"vertical\\\"","version":""},"required":false,"type":"\\\"vertical\\\" | \\\"horizontal\\\" "},{"name":"loading","tag":{"cn":"是否为加载中","en":"Loading","default":"false","version":""},"required":false,"type":"boolean "}],"cn":"","en":"","sort":"0"}]'); export default api; diff --git a/docs/api/shineout/table.ts b/docs/api/shineout/table.ts index 14ed9c4c0..203d9ce7f 100644 --- a/docs/api/shineout/table.ts +++ b/docs/api/shineout/table.ts @@ -1,2 +1,2 @@ -const api = JSON.parse('[{"title":"Table","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"onCellClick","tag":{"cn":"单元格点击事件","en":"Cell click event","default":"","version":""},"required":false,"type":"((data: DataItem, info: { rowIndex: number; columnIndex: number; columnKey: string | number; }) => void) "},{"name":"scrollLeft","tag":{"cn":"当开启虚拟列表时生效","en":"which takes effect when the virtual list is enabled","default":"","version":""},"required":false,"type":"number "},{"name":"rowHeight","tag":{"cn":"单行表格的预期高度,只是一个大概的估值,用来展示滚动条","en":"The expected height of a one-line table is just a rough estimate to show the scroll bar.","default":"40","version":""},"required":false,"type":"number "},{"name":"hover","tag":{"cn":"数据行鼠标悬浮高亮效果","en":"row hover highlight","default":"true","version":""},"required":false,"type":"boolean "},{"name":"empty","tag":{"cn":"空数据文案","en":"empty text","default":"getLocale(\\\"Data not found\\\")","version":""},"required":false,"type":"ReactNode"},{"name":"cellSelectable","tag":{"cn":"是否启用 ctrl/cmd + click 选中单元格","en":"whether to enable ctrl/cmd + click check","default":"false","version":""},"required":false,"type":"boolean "},{"name":"height","tag":{"cn":"表格高度,与 style.height 作用相同","en":"height of table, same with style.height","default":"","version":""},"required":false,"type":"number "},{"name":"onScroll","tag":{"cn":"滚动条滚动后回调函数;\\nx: 横向滚动比(0 <= x <= 1)\\ny: 纵向滚动比(0 <= y <= 1)","en":"The callback function after scrolling.\\nx: Horizontal rolling ratio(0 <= x <= 1)\\ny: Vertical scroll ratio(0 <= y <= 1)","default":"","version":""},"required":false,"type":"((x: number, y: number, left: number) => void) "},{"name":"pagination","tag":{"cn":"展示分页 详见 [Pagination](/components/Pagination)","en":"Show pagination See [Pagination](/components/Pagination) for details","default":"","version":""},"required":false,"type":"PaginationProps "},{"name":"loading","tag":{"cn":"数据加载中,为true时会展示一个默认的 [Spin](/components/Spin) 组件,可以传入一个自定义的Spin代替","en":"When it is true, a default [Spin](/components/Spin) component will be displayed, a custom loading icon can be passed in to replace.","default":"false","version":""},"required":false,"type":"ReactNode"},{"name":"virtual","tag":{"cn":"是否使用虚拟列表","en":"Whether to use virtual list","default":"","version":""},"required":false,"type":"boolean "},{"name":"rowsInView","tag":{"cn":"单次 render的 最大行数。Table 采用了 lazy render 的方式来优化在大量数据下的性能,如果你的表格显示的高度超出了20条,可以调整 rowsInView 的值。为 0 表示单次 render 所有数据。","en":"The maximum number of rows for a single render. Table uses lazy render to optimize performance under large amounts of data. If your table displays more than 20 rows, you can change the value of rowsInView. Value of 0 render all data.","default":"20","version":""},"required":false,"type":"number "},{"name":"size","tag":{"cn":"表格尺寸","en":"size of table","default":"\\\"default\\\"","version":""},"required":false,"type":"\\\"small\\\" | \\\"large\\\" | \\\"default\\\" "},{"name":"radio","tag":{"cn":"是否为单选","en":"is Radio","default":"false","version":""},"required":false,"type":"boolean "},{"name":"verticalAlign","tag":{"cn":"单元格内容垂直对齐方式","en":"vertical align with content","default":"\\\"top\\\"","version":""},"required":false,"type":"\\\"top\\\" | \\\"middle\\\" "},{"name":"children","tag":{"cn":"传入原生 tr td, 只使用样式","en":"Pass in the native tr td, using styles only","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"width","tag":{"cn":"表格总宽度,默认为容器宽度,不可小于 columns 中设置的 width 之和","en":"TThe total width of the table, which defaults to the container width, must not be less than the sum of width set in columns","default":"","version":""},"required":false,"type":"number "},{"name":"columns","tag":{"cn":"数组,见 TableColumn","en":"array,see TableColumn","default":"[]","version":""},"required":false,"type":"TableColumn[]"},{"name":"disabled","tag":{"cn":"如果 disabled 为 true,禁用全部选项,如果 disabled 为函数,根据函数反回结果禁用选项","en":"When the value is true, disabled all checkboxes; When the value is function, disable the checkbox that this function returns true.","default":"","version":""},"required":false,"type":"boolean | ((d: DataItem) => boolean) "},{"name":"treeEmptyExpand","tag":{"cn":"树形表格子数据为空时依然展示展开按钮","en":"show expand button while children data is empty","default":"false","version":""},"required":false,"type":"boolean "},{"name":"rowClickAttr","tag":{"cn":"设置行内元素的 attribute 来按需触发 onRowClick, \\\"*\\\"表示接受行点击触发","en":"Sets the attribute of inner element to trigger onRowClick as needed, and \\\"*\\\" to accept the row click","default":"[\\\"*\\\"]","version":""},"required":false,"type":"string | boolean | string[] "},{"name":"onRowClick","tag":{"cn":"行点击事件; data: 当前行数据; index: 当前行索引","en":"Callback when row click. data: current row data; index: current row index","default":"","version":""},"required":false,"type":"((rowData: DataItem, index: number, fireAttr?: string | boolean ) => void) "},{"name":"striped","tag":{"cn":"是否显示交错斑马底纹","en":"Whether to display zebra shading.","default":"","version":""},"required":false,"type":"boolean "},{"name":"rowClassName","tag":{"cn":"指定单行className","en":"Specify row className","default":"","version":""},"required":false,"type":"(rowData: DataItem, index: number) => string | undefined"},{"name":"rowEvents","tag":{"cn":"tr 事件监听器集合","en":"tr events","default":"","version":""},"required":false,"type":"object"},{"name":"data","tag":{"cn":"数据","en":"data","default":"","version":""},"required":false,"type":"object[]"},{"name":"showSelectAll","tag":{"cn":"是否显示全选","en":"Whether to show being fully selected.","default":"true","version":""},"required":false,"type":"boolean "},{"name":"bordered","tag":{"cn":"是否显示外边框","en":"Whether to display the border","default":"false","version":""},"required":false,"type":"boolean "},{"name":"treeCheckAll","tag":{"cn":"全选时是否将子孙数据选中","en":"check children data while select all","default":"false","version":""},"required":false,"type":"boolean "},{"name":"renderSorter","tag":{"cn":"自定义排序图标","en":"customize sort icons","default":"","version":""},"required":false,"type":"((params: { status?: \\\"asc\\\" | \\\"desc\\\" | null , triggerAsc: () => void, triggerDesc: () => void }) => ReactNode) "},{"name":"hideHeader","tag":{"cn":"是否隐藏表头","en":"whether hide thead","default":"false","version":""},"required":false,"type":"boolean "},{"name":"summary","tag":{"cn":"底部信息可用于总结","en":"Footer information can be used to summarize","default":"","version":""},"required":false,"type":"({ render: () => ReactNode, colSpan?: number , rowSpan?: number })[] | ({ render: () => ReactNode, colSpan?: number , rowSpan?: number })[][] "},{"name":"sticky","tag":{"cn":"表头是否附着顶部,为 true 时距离顶部为0","en":"sticky header, When it is true, the distance from the top is 0","default":"","version":""},"required":false,"type":"boolean | { top?: number ; css?: boolean ; } "},{"name":"tableRef","tag":{"cn":"Table 实例(请谨慎使用:仅虚拟列表支持)","en":"Table instance (please use with caution: only fixed Table)","default":"","version":""},"required":false,"type":"((table: TableRef) => void) "},{"name":"onRowSelect","tag":{"cn":"选择行。rows为选中的数据。如果需要数据需要格式化的处理,建议配置 format 和 prediction","en":"Select row. Rows is the selected data.","default":"","version":""},"required":false,"type":"((rows: Value) => void) "},{"name":"defaultTreeExpandKeys","tag":{"cn":"默认展开行(非受控)","en":"Default expanded row keys","default":"","version":""},"required":false,"type":"(string | number)[] "},{"name":"onTreeExpand","tag":{"cn":"当设置 treeExpandKeys 后,展开行时会触发该回调,keys 为展开的行","en":"When treeExpandKeys is set, the callback is triggered when the row is expanded. Keys is expanded row key","default":"","version":""},"required":false,"type":"((openKeys: (string | number)[], data: Item, expand: boolean, index: number) => void) "},{"name":"treeExpandKeys","tag":{"cn":"树形数据展开行,受控","en":"Tree Table expanded row keys","default":"","version":""},"required":false,"type":"(string | number)[] "},{"name":"sorter","tag":{"cn":"表格统一排序函数,参数分别为 Column.sorter 和 排序方式;\\n支持多列排序,sorter传入对象{ rule: string | function, weight: number }, rule为排序规则,为字符串时参考单列排序的用法, weight 为权重,指明排序的优先级。\\n多列排序时,sortedList 返回所有参与排序的字段信息","en":"the method of table sort,args are Column.sorter and order\\nMulti-column sorting is supported. The sorter passes in the object {rule: string | function, weight: number}, where rule is a sorting rule, which refers to the use of single-column sorting when it is a string, weight is the weight, indicating the priority of the order\\nWhen sorting on multiple columns, sortedList returns information about all fields involved in sorting","default":"alphaSort(Column.sorter, sorter)","version":""},"required":false,"type":"((sortName: string, sorter: \\\"asc\\\" | \\\"desc\\\", sortedList: ({ order: \\\"asc\\\" | \\\"desc\\\", manual: boolean, key: string | number, weight?: number })[]) => void | ((a: Item, b: Item) => number) ) "},{"name":"onSortCancel","tag":{"cn":"排序取消事件","en":"sort cancel event","default":"","version":""},"required":false,"type":"((preType: \\\"asc\\\" | \\\"desc\\\", key: string | number, orders: ({ order: \\\"asc\\\" | \\\"desc\\\", weight?: number , key: string | number, manual: boolean })[], sorter: string) => void) "},{"name":"columnResizable","tag":{"cn":"设置 columnResizable 为 true,使所有列可伸缩","en":"Set columnResizable to true to make all columns scalable","default":"","version":""},"required":false,"type":"boolean "},{"name":"onColumnResize","tag":{"cn":"列宽伸缩后的回调","en":"columns resize callback","default":"","version":""},"required":false,"type":"(columns: TableColumn[]) => void"},{"name":"dataChangeResize","tag":{"cn":"数据发生变化后是否重新计算列宽","en":"Recalculate columns width while data change","default":"false","version":""},"required":false,"type":"boolean "},{"name":"expandKeys","tag":{"cn":"展开行受控","en":"controlled expand rows","default":"","version":""},"required":false,"type":"(string | number)[] "},{"name":"keygen","tag":{"cn":"生成每一项key的辅助方法\\n为函数时,使用此函数返回值\\n为string时,使用这个string对应的数据值。如 \\\"id\\\",相当于 (d => d.id)","en":"Generate a auxiliary method for each key\\nIf not filled, index will be used (not recommended, in some cases there may be problems)\\nWhen it is a function, use its return value.\\nWhen it is a string,ues the value of the string.For example, \\\"id\\\" is the same thing as (d) => d.id .","default":"","version":""},"required":true,"type":"| ObjectKey | ((data: DataItem, index?: number) => string | number)"},{"name":"value","tag":{"cn":"当前选中值,格式和 onRowSelect 返回值一致","en":"The current selected value.","default":"","version":""},"required":false,"type":"any"},{"name":"format","tag":{"cn":"格式化 value, 默认值,返回原始数据。 为 string 时,会作为 key 从原始数据中获取值,相当于 (d) => d\\\\[format]; 为函数时,以函数返回结果作为 value。","en":"Format value. The defaule value is return the original data. When it is a string, the value is fetched from the original data as a key equivalent to (d) => d\\\\[format] When it is a function, use its return value.","default":"d => d","version":""},"required":false,"type":"ObjectKey | ((data: DataItem) => Value extends (infer U)[] ? U : Value) "},{"name":"prediction","tag":{"cn":"默认使用 format 函数执行的结果来比较是否匹配,在某些情况下(例如返回原始数据的对象,更新数据时,生成了一个值相同,非同一个对象的选项),需要借助 prediction 函数来判断是否匹配","en":"By default, the result of the format function is used to compare whether it matches. In some cases (for example, whe an object that returns the original data is updated, an different option with the same value is generated), the prediction function needs to be used to determine whether match","default":"(val, d) => val===format(d)","version":""},"required":false,"type":"((value: Value extends (infer U)[] ? U : Value, data: DataItem) => boolean) "}],"cn":"","en":"","sort":"0"},{"title":"columns","properties":[{"name":"align","tag":{"cn":"单元格内容排布方式","en":"cell align","default":"\\\"left\\\"","version":""},"required":false,"type":"\\\"left\\\" | \\\"center\\\" | \\\"right\\\""},{"name":"colSpan","tag":{"cn":"合并列控制函数,row为单行数据,返回值一个整数,标明需要合并的列数","en":"The function for controlling to merge columns. The return value is an integer indicating the number of columns that need to be merged。","default":"","version":""},"required":false,"type":"((row: DataItem, index: number) => number) "},{"name":"defaultOrder","tag":{"cn":"默认排序规则","en":"default sort","default":"","version":""},"required":false,"type":"\\\"asc\\\" | \\\"desc\\\" "},{"name":"fixed","tag":{"cn":"固定列,如果相邻的多列需要锁定,只需指定最外侧的 column 即可","en":"Fixed columns. If multiple adjacent columns need to be locked, specify only the outermost column","default":"","version":""},"required":false,"type":"\\\"left\\\" | \\\"right\\\" "},{"name":"group","tag":{"cn":"表头分组,相邻的相同 group 会生成一个新的表头","en":"The group of header column.","default":"","version":""},"required":false,"type":"ReactNode | ReactNode[]"},{"name":"hide","tag":{"cn":"只针对行展开列有效,表示是否隐藏该列","en":"hide the column, only work on row-expand column","default":"","version":""},"required":false,"type":"boolean "},{"name":"key","tag":{"cn":"列的key,默认使用 index","en":"The key of the column","default":"","version":""},"required":false,"type":"string | number "},{"name":"minWidth","tag":{"cn":"最小列宽","en":"min width","default":"","version":""},"required":false,"type":"number "},{"name":"maxWidth","tag":{"cn":"最大可拖动列宽","en":"max width","default":"","version":""},"required":false,"type":"number "},{"name":"filterAll","tag":{"cn":"全选时用来筛除数据,仅当 type=\\\"checkbox\\\" 时有效","en":"Select All to screen data. Valid only if type=\\\"checkbox\\\"","default":"","version":""},"required":false,"type":"((data: DataItem[]) => DataItem[]) "},{"name":"render","tag":{"cn":"表格内容生成函数,返回渲染的内容, data 当前行的数据,index 当前索引,instance 当 type=\\\"checkbox\\\" 时会传入 Checkbox 实例\\n为了使用方便,可以传入一个数据的key,如 \\\"id\\\",相当于 (d) => { return d.id }","en":"The generation function for Table content.d: the data of the current row. i: the index of the current row .For ease of use, you can pass in the key of a data, such as \\\"id\\\", which is equivalent to (d) => { return d.id }","default":"","version":""},"required":false,"type":"ObjectKey | function(d, id, instance)"},{"name":"rowSpan","tag":{"cn":"根据函数返回的结果(boolean)判断是否合并行,a、b为相邻的两行数据。","en":"According to the result (boolean) returned by the function to determine whether to merge rows, a and b are two adjacent rows of data","default":"","version":""},"required":false,"type":"((prevRowData: DataItem, nextRowData: DataItem) => boolean) "},{"name":"sorter","tag":{"cn":"sorter 不为空时,这一列会出现排序 icon。order的值为[\\\"asc\\\", \\\"desc\\\"]\\n字符串表示排序依据字段,作为第一个参数传入Table.sorter\\n为 Sorter 对象\\n前端排序,返回一个排序函数,参考 Array.sort。(旧用法)\\n服务端排序,不要返回值,自行处理即可。(旧用法)","en":"When the sorter is not empty, the sort icon appears in this column. the value of order: [\\\"asc\\\", \\\"desc\\\"]\\nIndicate the sort key string, will pass to table sorter method.\\nFront-end sorting returns a sort function, refer to Array.sort.\\nServer-side sorting, do not return values and handle it itself.","default":"","version":""},"required":false,"type":"string | ((order: \\\"asc\\\" | \\\"desc\\\") => void | ((prevRowData: DataItem, nextRowData: DataItem) => number)) | { rule: string | ((sorter: ({ order: \\\"asc\\\" | \\\"desc\\\", manual: boolean, key: string | number, weight?: number })[]) => void), weight: number } "},{"name":"title","tag":{"cn":"表头显示内容","en":"The content of the header","default":"","version":""},"required":false,"type":"ReactNode | ((rowData: DataItem[]) => ReactNode)"},{"name":"treeColumnsName","tag":{"cn":"树形表格子数据字段名","en":"tree table children-data name","default":"","version":""},"required":false,"type":"ObjectKey "},{"name":"treeIndent","tag":{"cn":"每一层缩进宽度","en":"indent of each level","default":"25","version":""},"required":false,"type":"number "},{"name":"type","tag":{"cn":"特殊用途列\\nexpand: 行展开列,render 函数返回函数时,表示此行可以展开,内容为此函数返回结果。\\nrow-expand: 同 expand。不同为点击行内空白区域也可以折叠/展开行。\\ncheckbox: 选择列,仅用于固定选择列的场景","en":"Special column\\nexpand: Expand the column. When the render function returns a function, it means that the row can be expanded and the content is the result returned by this function.\\nrow-expand: Similar to expand. The difference is that clicking on the entire row triggers the expand event.\\ncheckbox: Select column for scenes with only fixed selection columns","default":"","version":""},"required":false,"type":"\\\"expand\\\" | \\\"row-expand\\\" | \\\"checkbox\\\" "},{"name":"width","tag":{"cn":"列宽","en":"width","default":"","version":""},"required":false,"type":"number "},{"name":"className","tag":{"cn":"列对应的类名","en":"classname of column","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"td 样式","en":"style of td","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"onClick","tag":{"cn":"可展开元素点击事件仅当(仅该列为行展开列,并且传入 expandKeys 的时候生效)","en":"Click event of expandable element only when (only this column is row-expand column and expandKeys is passed in)","default":"","version":""},"required":false,"type":"((d: DataItem, isExpand: boolean) => void) "},{"name":"columnResizable","tag":{"cn":"单独设置某一列不可拖动","en":"Separately set a column not to be draggable","default":"","version":""},"required":false,"type":"false "}],"cn":"","en":"","sort":"0"}]'); +const api = JSON.parse('[{"title":"Table","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"onCellClick","tag":{"cn":"单元格点击事件","en":"Cell click event","default":"","version":""},"required":false,"type":"((data: DataItem, info: { rowIndex: number; columnIndex: number; columnKey: string | number; }) => void) "},{"name":"scrollLeft","tag":{"cn":"当开启虚拟列表时生效","en":"which takes effect when the virtual list is enabled","default":"","version":""},"required":false,"type":"number "},{"name":"rowHeight","tag":{"cn":"单行表格的预期高度,只是一个大概的估值,用来展示滚动条","en":"The expected height of a one-line table is just a rough estimate to show the scroll bar.","default":"40","version":""},"required":false,"type":"number "},{"name":"hover","tag":{"cn":"数据行鼠标悬浮高亮效果","en":"row hover highlight","default":"true","version":""},"required":false,"type":"boolean "},{"name":"empty","tag":{"cn":"空数据文案","en":"empty text","default":"getLocale(\\\"Data not found\\\")","version":""},"required":false,"type":"ReactNode"},{"name":"cellSelectable","tag":{"cn":"是否启用 ctrl/cmd + click 选中单元格","en":"whether to enable ctrl/cmd + click check","default":"false","version":""},"required":false,"type":"boolean "},{"name":"height","tag":{"cn":"表格高度,与 style.height 作用相同","en":"height of table, same with style.height","default":"","version":""},"required":false,"type":"string | number "},{"name":"onScroll","tag":{"cn":"滚动条滚动后回调函数;\\nx: 横向滚动比(0 <= x <= 1)\\ny: 纵向滚动比(0 <= y <= 1)","en":"The callback function after scrolling.\\nx: Horizontal rolling ratio(0 <= x <= 1)\\ny: Vertical scroll ratio(0 <= y <= 1)","default":"","version":""},"required":false,"type":"((x: number, y: number, left: number, top: number) => void) "},{"name":"pagination","tag":{"cn":"展示分页 详见 [Pagination](/components/Pagination)","en":"Show pagination See [Pagination](/components/Pagination) for details","default":"","version":""},"required":false,"type":"PaginationProps "},{"name":"loading","tag":{"cn":"数据加载中,为true时会展示一个默认的 [Spin](/components/Spin) 组件,可以传入一个自定义的Spin代替","en":"When it is true, a default [Spin](/components/Spin) component will be displayed, a custom loading icon can be passed in to replace.","default":"false","version":""},"required":false,"type":"ReactNode"},{"name":"virtual","tag":{"cn":"是否使用虚拟列表","en":"Whether to use virtual list","default":"","version":""},"required":false,"type":"boolean "},{"name":"rowsInView","tag":{"cn":"单次 render的 最大行数。Table 采用了 lazy render 的方式来优化在大量数据下的性能,如果你的表格显示的高度超出了20条,可以调整 rowsInView 的值。为 0 表示单次 render 所有数据。","en":"The maximum number of rows for a single render. Table uses lazy render to optimize performance under large amounts of data. If your table displays more than 20 rows, you can change the value of rowsInView. Value of 0 render all data.","default":"20","version":""},"required":false,"type":"number "},{"name":"size","tag":{"cn":"表格尺寸","en":"size of table","default":"\\\"default\\\"","version":""},"required":false,"type":"\\\"small\\\" | \\\"large\\\" | \\\"default\\\" "},{"name":"radio","tag":{"cn":"是否为单选","en":"is Radio","default":"false","version":""},"required":false,"type":"boolean "},{"name":"verticalAlign","tag":{"cn":"单元格内容垂直对齐方式","en":"vertical align with content","default":"\\\"top\\\"","version":""},"required":false,"type":"\\\"top\\\" | \\\"middle\\\" "},{"name":"children","tag":{"cn":"传入原生 tr td, 只使用样式","en":"Pass in the native tr td, using styles only","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"width","tag":{"cn":"表格总宽度,默认为容器宽度,不可小于 columns 中设置的 width 之和","en":"TThe total width of the table, which defaults to the container width, must not be less than the sum of width set in columns","default":"","version":""},"required":false,"type":"number "},{"name":"columns","tag":{"cn":"数组,见 TableColumn","en":"array,see TableColumn","default":"[]","version":""},"required":false,"type":"TableColumn[]"},{"name":"disabled","tag":{"cn":"如果 disabled 为 true,禁用全部选项,如果 disabled 为函数,根据函数反回结果禁用选项","en":"When the value is true, disabled all checkboxes; When the value is function, disable the checkbox that this function returns true.","default":"","version":""},"required":false,"type":"boolean | ((d: DataItem) => boolean) "},{"name":"treeEmptyExpand","tag":{"cn":"树形表格子数据为空时依然展示展开按钮","en":"show expand button while children data is empty","default":"false","version":""},"required":false,"type":"boolean "},{"name":"rowClickAttr","tag":{"cn":"设置行内元素的 attribute 来按需触发 onRowClick, \\\"*\\\"表示接受行点击触发","en":"Sets the attribute of inner element to trigger onRowClick as needed, and \\\"*\\\" to accept the row click","default":"[\\\"*\\\"]","version":""},"required":false,"type":"string | boolean | string[] "},{"name":"onRowClick","tag":{"cn":"行点击事件; data: 当前行数据; index: 当前行索引","en":"Callback when row click. data: current row data; index: current row index","default":"","version":""},"required":false,"type":"((rowData: DataItem, index: number, fireAttr?: string | boolean ) => void) "},{"name":"striped","tag":{"cn":"是否显示交错斑马底纹","en":"Whether to display zebra shading.","default":"","version":""},"required":false,"type":"boolean "},{"name":"rowClassName","tag":{"cn":"指定单行className","en":"Specify row className","default":"","version":""},"required":false,"type":"(rowData: DataItem, index: number) => string | undefined"},{"name":"rowEvents","tag":{"cn":"tr 事件监听器集合","en":"tr events","default":"","version":""},"required":false,"type":"object"},{"name":"data","tag":{"cn":"数据","en":"data","default":"","version":""},"required":false,"type":"object[]"},{"name":"showSelectAll","tag":{"cn":"是否显示全选","en":"Whether to show being fully selected.","default":"true","version":""},"required":false,"type":"boolean "},{"name":"bordered","tag":{"cn":"是否显示外边框","en":"Whether to display the border","default":"false","version":""},"required":false,"type":"boolean "},{"name":"treeCheckAll","tag":{"cn":"全选时是否将子孙数据选中","en":"check children data while select all","default":"false","version":""},"required":false,"type":"boolean "},{"name":"renderSorter","tag":{"cn":"自定义排序图标","en":"customize sort icons","default":"","version":""},"required":false,"type":"((params: { status?: \\\"asc\\\" | \\\"desc\\\" | null , triggerAsc: () => void, triggerDesc: () => void }) => ReactNode) "},{"name":"hideHeader","tag":{"cn":"是否隐藏表头","en":"whether hide thead","default":"false","version":""},"required":false,"type":"boolean "},{"name":"summary","tag":{"cn":"底部信息可用于总结","en":"Footer information can be used to summarize","default":"","version":""},"required":false,"type":"({ render: () => ReactNode, colSpan?: number , rowSpan?: number })[] | ({ render: () => ReactNode, colSpan?: number , rowSpan?: number })[][] "},{"name":"sticky","tag":{"cn":"表头是否附着顶部,为 true 时距离顶部为0","en":"sticky header, When it is true, the distance from the top is 0","default":"","version":""},"required":false,"type":"boolean | { top?: number ; css?: boolean ; } "},{"name":"showTopScrollbar","tag":{"cn":"是否开启顶部滚动条","en":"Whether to show the top scroller","default":"false","version":"3.4.0"},"required":false,"type":"boolean "},{"name":"tableRef","tag":{"cn":"Table 实例(请谨慎使用:仅虚拟列表支持)","en":"Table instance (please use with caution: only fixed Table)","default":"","version":""},"required":false,"type":"((table: TableRef) => void) "},{"name":"onRowSelect","tag":{"cn":"选择行。rows为选中的数据。如果需要数据需要格式化的处理,建议配置 format 和 prediction","en":"Select row. Rows is the selected data.","default":"","version":""},"required":false,"type":"((rows: Value) => void) "},{"name":"defaultTreeExpandKeys","tag":{"cn":"默认展开行(非受控)","en":"Default expanded row keys","default":"","version":""},"required":false,"type":"(string | number)[] "},{"name":"onTreeExpand","tag":{"cn":"当设置 treeExpandKeys 后,展开行时会触发该回调,keys 为展开的行","en":"When treeExpandKeys is set, the callback is triggered when the row is expanded. Keys is expanded row key","default":"","version":""},"required":false,"type":"((openKeys: (string | number)[], data: Item, expand: boolean, index: number) => void) "},{"name":"treeExpandKeys","tag":{"cn":"树形数据展开行,受控","en":"Tree Table expanded row keys","default":"","version":""},"required":false,"type":"(string | number)[] "},{"name":"sorter","tag":{"cn":"表格统一排序函数,参数分别为 Column.sorter 和 排序方式;\\n支持多列排序,sorter传入对象{ rule: string | function, weight: number }, rule为排序规则,为字符串时参考单列排序的用法, weight 为权重,指明排序的优先级。\\n多列排序时,sortedList 返回所有参与排序的字段信息","en":"the method of table sort,args are Column.sorter and order\\nMulti-column sorting is supported. The sorter passes in the object {rule: string | function, weight: number}, where rule is a sorting rule, which refers to the use of single-column sorting when it is a string, weight is the weight, indicating the priority of the order\\nWhen sorting on multiple columns, sortedList returns information about all fields involved in sorting","default":"alphaSort(Column.sorter, sorter)","version":""},"required":false,"type":"((sortName: string, sorter: \\\"asc\\\" | \\\"desc\\\", sortedList: ({ order: \\\"asc\\\" | \\\"desc\\\", manual: boolean, key: string | number, weight?: number })[]) => void | ((a: Item, b: Item) => number) ) "},{"name":"onSortCancel","tag":{"cn":"排序取消事件","en":"sort cancel event","default":"","version":""},"required":false,"type":"((preType: \\\"asc\\\" | \\\"desc\\\", key: string | number, orders: ({ order: \\\"asc\\\" | \\\"desc\\\", weight?: number , key: string | number, manual: boolean })[], sorter: string) => void) "},{"name":"columnResizable","tag":{"cn":"设置 columnResizable 为 true,使所有列可伸缩","en":"Set columnResizable to true to make all columns scalable","default":"","version":""},"required":false,"type":"boolean "},{"name":"onColumnResize","tag":{"cn":"列宽伸缩后的回调","en":"columns resize callback","default":"","version":""},"required":false,"type":"(columns: TableColumn[]) => void"},{"name":"dataChangeResize","tag":{"cn":"数据发生变化后是否重新计算列宽","en":"Recalculate columns width while data change","default":"false","version":""},"required":false,"type":"boolean "},{"name":"expandKeys","tag":{"cn":"展开行受控","en":"controlled expand rows","default":"","version":""},"required":false,"type":"(string | number)[] "},{"name":"keygen","tag":{"cn":"生成每一项key的辅助方法\\n为函数时,使用此函数返回值\\n为string时,使用这个string对应的数据值。如 \\\"id\\\",相当于 (d => d.id)","en":"Generate a auxiliary method for each key\\nIf not filled, index will be used (not recommended, in some cases there may be problems)\\nWhen it is a function, use its return value.\\nWhen it is a string,ues the value of the string.For example, \\\"id\\\" is the same thing as (d) => d.id .","default":"","version":""},"required":true,"type":"| ObjectKey | ((data: DataItem, index?: number) => string | number)"},{"name":"value","tag":{"cn":"当前选中值,格式和 onRowSelect 返回值一致","en":"The current selected value.","default":"","version":""},"required":false,"type":"any"},{"name":"format","tag":{"cn":"格式化 value, 默认值,返回原始数据。 为 string 时,会作为 key 从原始数据中获取值,相当于 (d) => d\\\\[format]; 为函数时,以函数返回结果作为 value。","en":"Format value. The defaule value is return the original data. When it is a string, the value is fetched from the original data as a key equivalent to (d) => d\\\\[format] When it is a function, use its return value.","default":"d => d","version":""},"required":false,"type":"ObjectKey | ((data: DataItem) => Value extends (infer U)[] ? U : Value) "},{"name":"prediction","tag":{"cn":"默认使用 format 函数执行的结果来比较是否匹配,在某些情况下(例如返回原始数据的对象,更新数据时,生成了一个值相同,非同一个对象的选项),需要借助 prediction 函数来判断是否匹配","en":"By default, the result of the format function is used to compare whether it matches. In some cases (for example, whe an object that returns the original data is updated, an different option with the same value is generated), the prediction function needs to be used to determine whether match","default":"(val, d) => val===format(d)","version":""},"required":false,"type":"((value: Value extends (infer U)[] ? U : Value, data: DataItem) => boolean) "}],"cn":"","en":"","sort":"0"},{"title":"columns","properties":[{"name":"align","tag":{"cn":"单元格内容排布方式","en":"cell align","default":"\\\"left\\\"","version":""},"required":false,"type":"\\\"left\\\" | \\\"center\\\" | \\\"right\\\""},{"name":"colSpan","tag":{"cn":"合并列控制函数,row为单行数据,返回值一个整数,标明需要合并的列数","en":"The function for controlling to merge columns. The return value is an integer indicating the number of columns that need to be merged。","default":"","version":""},"required":false,"type":"((row: DataItem, index: number) => number) "},{"name":"defaultOrder","tag":{"cn":"默认排序规则","en":"default sort","default":"","version":""},"required":false,"type":"\\\"asc\\\" | \\\"desc\\\" "},{"name":"fixed","tag":{"cn":"固定列,如果相邻的多列需要锁定,只需指定最外侧的 column 即可","en":"Fixed columns. If multiple adjacent columns need to be locked, specify only the outermost column","default":"","version":""},"required":false,"type":"\\\"left\\\" | \\\"right\\\" "},{"name":"group","tag":{"cn":"表头分组,相邻的相同 group 会生成一个新的表头","en":"The group of header column.","default":"","version":""},"required":false,"type":"ReactNode | ReactNode[]"},{"name":"hide","tag":{"cn":"只针对行展开列有效,表示是否隐藏该列","en":"hide the column, only work on row-expand column","default":"","version":""},"required":false,"type":"boolean "},{"name":"key","tag":{"cn":"列的key,默认使用 index","en":"The key of the column","default":"","version":""},"required":false,"type":"string | number "},{"name":"minWidth","tag":{"cn":"最小列宽","en":"min width","default":"","version":""},"required":false,"type":"number "},{"name":"maxWidth","tag":{"cn":"最大可拖动列宽","en":"max width","default":"","version":""},"required":false,"type":"number "},{"name":"filterAll","tag":{"cn":"全选时用来筛除数据,仅当 type=\\\"checkbox\\\" 时有效","en":"Select All to screen data. Valid only if type=\\\"checkbox\\\"","default":"","version":""},"required":false,"type":"((data: DataItem[]) => DataItem[]) "},{"name":"render","tag":{"cn":"表格内容生成函数,返回渲染的内容, data 当前行的数据,index 当前索引,instance 当 type=\\\"checkbox\\\" 时会传入 Checkbox 实例\\n为了使用方便,可以传入一个数据的key,如 \\\"id\\\",相当于 (d) => { return d.id }","en":"The generation function for Table content.d: the data of the current row. i: the index of the current row .For ease of use, you can pass in the key of a data, such as \\\"id\\\", which is equivalent to (d) => { return d.id }","default":"","version":""},"required":false,"type":"ObjectKey | function(d, id, instance)"},{"name":"rowSpan","tag":{"cn":"根据函数返回的结果(boolean)判断是否合并行,a、b为相邻的两行数据。","en":"According to the result (boolean) returned by the function to determine whether to merge rows, a and b are two adjacent rows of data","default":"","version":""},"required":false,"type":"((prevRowData: DataItem, nextRowData: DataItem) => boolean) "},{"name":"sorter","tag":{"cn":"sorter 不为空时,这一列会出现排序 icon。order的值为[\\\"asc\\\", \\\"desc\\\"]\\n字符串表示排序依据字段,作为第一个参数传入Table.sorter\\n为 Sorter 对象\\n前端排序,返回一个排序函数,参考 Array.sort。(旧用法)\\n服务端排序,不要返回值,自行处理即可。(旧用法)","en":"When the sorter is not empty, the sort icon appears in this column. the value of order: [\\\"asc\\\", \\\"desc\\\"]\\nIndicate the sort key string, will pass to table sorter method.\\nFront-end sorting returns a sort function, refer to Array.sort.\\nServer-side sorting, do not return values and handle it itself.","default":"","version":""},"required":false,"type":"string | ((order: \\\"asc\\\" | \\\"desc\\\") => void | ((prevRowData: DataItem, nextRowData: DataItem) => number)) | { rule: string | ((sorter: ({ order: \\\"asc\\\" | \\\"desc\\\", manual: boolean, key: string | number, weight?: number })[]) => void), weight: number } "},{"name":"title","tag":{"cn":"表头显示内容","en":"The content of the header","default":"","version":""},"required":false,"type":"ReactNode | ((rowData: DataItem[]) => ReactNode)"},{"name":"treeColumnsName","tag":{"cn":"树形表格子数据字段名","en":"tree table children-data name","default":"","version":""},"required":false,"type":"ObjectKey "},{"name":"treeIndent","tag":{"cn":"每一层缩进宽度","en":"indent of each level","default":"25","version":""},"required":false,"type":"number "},{"name":"type","tag":{"cn":"特殊用途列\\nexpand: 行展开列,render 函数返回函数时,表示此行可以展开,内容为此函数返回结果。\\nrow-expand: 同 expand。不同为点击行内空白区域也可以折叠/展开行。\\ncheckbox: 选择列,仅用于固定选择列的场景","en":"Special column\\nexpand: Expand the column. When the render function returns a function, it means that the row can be expanded and the content is the result returned by this function.\\nrow-expand: Similar to expand. The difference is that clicking on the entire row triggers the expand event.\\ncheckbox: Select column for scenes with only fixed selection columns","default":"","version":""},"required":false,"type":"\\\"expand\\\" | \\\"row-expand\\\" | \\\"checkbox\\\" "},{"name":"width","tag":{"cn":"列宽","en":"width","default":"","version":""},"required":false,"type":"number "},{"name":"className","tag":{"cn":"列对应的类名","en":"classname of column","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"td 样式","en":"style of td","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"onClick","tag":{"cn":"可展开元素点击事件仅当(仅该列为行展开列,并且传入 expandKeys 的时候生效)","en":"Click event of expandable element only when (only this column is row-expand column and expandKeys is passed in)","default":"","version":""},"required":false,"type":"((d: DataItem, isExpand: boolean) => void) "},{"name":"columnResizable","tag":{"cn":"单独设置某一列不可拖动","en":"Separately set a column not to be draggable","default":"","version":""},"required":false,"type":"false "}],"cn":"","en":"","sort":"0"}]'); export default api; diff --git a/docs/api/shineout/tree-select.ts b/docs/api/shineout/tree-select.ts index 91ffa729b..55cd7622b 100644 --- a/docs/api/shineout/tree-select.ts +++ b/docs/api/shineout/tree-select.ts @@ -1,2 +1,2 @@ -const api = JSON.parse('[{"title":"TreeSelect","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"size","tag":{"cn":"不同尺寸","en":"There are three built-in size: small、default、large.","default":"\\\"default\\\"","version":""},"required":false,"type":"\\\"small\\\" | \\\"large\\\" | \\\"default\\\""},{"name":"status","tag":{"cn":"组件状态","en":"The status of the component","default":"","version":""},"required":false,"type":"\\\"error\\\" "},{"name":"innerTitle","tag":{"cn":"内嵌标题","en":"inner title","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"filterSameChange","tag":{"cn":"当两次选择的值相同时不触发 onChange","en":"onChange is not triggered when two selected values are the same","default":"false","version":""},"required":false,"type":"boolean "},{"name":"absolute","tag":{"cn":"为 true 时,选项弹出层在 DOM 中独立 render; 为函数时,返回值作为弹出层容器","en":"When it is true, the pop-up layer of option append into document.body; When it is a function, the return value is used as the popup layer container","default":"false","version":""},"required":false,"type":"boolean | (() => HTMLElement | null) "},{"name":"zIndex","tag":{"cn":"选项列表 z-index 值, 需要配合 absolute","en":"options z-index should use with absolute","default":"1000","version":""},"required":false,"type":"number "},{"name":"noCache","tag":{"cn":"是否开启数据缓存,如果数据存在动态更新的情况建议开启","en":"Data cache, if data change asynchronously, better set true","default":"false","version":""},"required":false,"type":"boolean "},{"name":"emptyText","tag":{"cn":"自定义 empty 文案","en":"custom empty copy","default":"","version":""},"required":false,"type":"string "},{"name":"loading","tag":{"cn":"数据加载中,为true时会展示一个默认的 [Spin](/components/Spin) 组件,可以传入一个自定义的Spin代替","en":"When it is true, a default [Spin](/components/Spin) component will be displayed, a custom loading icon can be passed in to replace.","default":"false","version":""},"required":false,"type":"boolean | ReactNode"},{"name":"placeholder","tag":{"cn":"value 为空时的占位符","en":"placeholder when value is empty","default":"","version":""},"required":false,"type":"string "},{"name":"compressedBound","tag":{"cn":"开启多选后,指定允许展示标签数量,超过后将折叠","en":"when compressed is True,the comptessedBound can limit the numbers of multiple selected item\\\"s label","default":"","version":""},"required":false,"type":"number "},{"name":"compressedClassName","tag":{"cn":"多选合并展示弹出框的类名","en":"Compressed popover classname","default":"","version":""},"required":false,"type":"string "},{"name":"clearable","tag":{"cn":"是否可清除值","en":"If clearable is true, show clear value icon","default":"false","version":""},"required":false,"type":"boolean "},{"name":"renderUnmatched","tag":{"cn":"渲染未匹配值的方式","en":"ender unmatched value","default":"","version":""},"required":false,"type":"((data: Value extends (infer U)[] ? U : Value) => ReactNode) "},{"name":"data","tag":{"cn":"数据源","en":"data source","default":"[]","version":""},"required":false,"type":"DataItem[] "},{"name":"keygen","tag":{"cn":"生成 key 的辅助方法, 为函数时,使用此函数返回值, 为 string 时,使用这个 string 对应的数据值。如 \\\"id\\\",相当于 (d) => d.id","en":"Auxiliary method for generating key. When it is a function, use the return value of this function. When it is a string, use the data value corresponding to this string. For example, \\\"id\\\" is the same thing as (d) => d.id","default":"","version":""},"required":true,"type":"ObjectKey | ((data: DataItem, parentKey: string | number) => string | number)"},{"name":"getComponentRef","tag":{"cn":"获取组件的一些方法 目前只支持 getDataByValues","en":"Some methods of getting components Currently only support getDataByValue","default":"","version":""},"required":false,"type":"((ref: ComponentRef) => void) | { current?: ComponentRef ; } "},{"name":"onFilter","tag":{"cn":"onFilter 不为空时,可以输入过滤数据。 onFilter 如果返回一个函数,使用这个函数做前端过滤。 如果不返回,可以自行做后端过滤","en":"When the onFilter is not empty, you can filter data by input. If the onFilter returns a function, use this function as a front-end filter. If return undefined, you can do your own backend filtering","default":"","version":""},"required":false,"type":"((text: string) => void) "},{"name":"empty","tag":{"cn":"无数据时的占位内容","en":"Placeholder content when there is no data","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"multiple","tag":{"cn":"是否是多选","en":"if it is true, it will be multiple selection","default":"false","version":""},"required":false,"type":"boolean "},{"name":"onBlur","tag":{"cn":"blur 事件回调函数","en":"callback function of blur event","default":"","version":""},"required":false,"type":"((e?: any) => void) "},{"name":"onFocus","tag":{"cn":"focus 事件回调函数","en":"callback function of focus event","default":"","version":""},"required":false,"type":"((e?: any) => void) "},{"name":"disabled","tag":{"cn":"为 true 时,所有节点禁用选择,为函数时,根据函数返回结果确定是否禁用","en":"When it is true, all nodes disable the selection; when it is a function, it determines whether it is disabled according to the return result of the function.","default":"false","version":""},"required":false,"type":"boolean | ((data: DataItem) => boolean) "},{"name":"renderResult","tag":{"cn":"选中后在结果中显示的内容,默认和 renderItem 相同","en":"The content displayed in the result after selecting, if not set, use renderItem. not show while return null, result is current selected","default":"renderItem","version":""},"required":false,"type":"((data: DataItem) => ReactNode) "},{"name":"mode","tag":{"cn":"选中值模式,未设置值为单选 0: 只返回完全选中的节点,包含父节点 1: 返回全部选中的节点和半选中的父节点 2: 只返回选中的子节点 3: 如果父节点选中,只返回父节点 4: 所选即所得","en":"mode 0: Returns only the fully selected node including the parent node. 1: Returns all selected nodes and semi-selected nodes. 2: Return only the selected child nodes. 3: If the parent node is full selected, only return the parent node. 4: What you choose is what you get.","default":"1","version":""},"required":false,"type":"0 | 1 | 2 | 3 | 4 "},{"name":"height","tag":{"cn":"列表高度","en":"The height of list","default":"300","version":""},"required":false,"type":"number "},{"name":"onCollapse","tag":{"cn":"下拉列表展开/收起回调","en":"option collapse callback","default":"","version":""},"required":false,"type":"((collapse: boolean) => void) "},{"name":"showHitDescendants","tag":{"cn":"筛选后是否展示命中节点的后代节点","en":"Whether to show the descendant nodes of the hit node after filtering","default":"false","version":""},"required":false,"type":"boolean "},{"name":"position","tag":{"cn":"弹出位置","en":"Popup Position","default":"","version":""},"required":false,"type":"\\\"auto\\\" | \\\"bottom-left\\\" | \\\"top-left\\\" "},{"name":"onEnterExpand","tag":{"cn":"回车触发下拉框展开的时候调用","en":"Expand option list while enter press","default":"","version":""},"required":false,"type":"((e: KeyboardEvent) => boolean) "},{"name":"onChange","tag":{"cn":"参数 为 当前选中值","en":"value is your picker now","default":"","version":""},"required":false,"type":"((value: Value, selected?: DataItem | { IS_NOT_MATCHED_VALUE: boolean, value: any } , path?: (string | number)[] ) => void) "},{"name":"onChangeAddition","tag":{"cn":"onChange 额外参数 (current 为点击的节点的数据, data 为当前选中的数据, checked 为多选状态下是选中还是取消)","en":"onChange additional parameters (current is the data of the clicked node, data is the currently selected data, checked is whether it is selected or canceled in the multi-select state)","default":"","version":""},"required":false,"type":"((params: { current?: DataItem | UnMatchedData | (DataItem | UnMatchedData)[] ; checked?: 0 | 1 | 2 ; data?: DataItem | UnMatchedData | (DataItem | UnMatchedData)[] | null ; }) => void) "},{"name":"value","tag":{"cn":"选中的 key (受控),多选时必须为array","en":"In the Form, the value will be taken over by the form and the value will be invalid.","default":"","version":""},"required":false,"type":"Value "},{"name":"defaultValue","tag":{"cn":"默认值 和 value 类型相同","en":"Initial value","default":"","version":""},"required":false,"type":"Value "},{"name":"compressed","tag":{"cn":"将选中值合并,只在多选模式下有效;为 \\\"no-repeat\\\" 时弹出框中不重复展示值","en":"Merges selected values; the repeat value will not appear in the Popover when it is\\\"no-repeat\\\".","default":"false","version":""},"required":false,"type":"boolean | \\\"no-repeat\\\" "},{"name":"open","tag":{"cn":"控制浮层显隐","en":"Set visible of datepicker popup","default":"","version":""},"required":false,"type":"boolean "},{"name":"line","tag":{"cn":"是否显示连接线","en":"Whether show line","default":"false","version":""},"required":false,"type":"boolean "},{"name":"width","tag":{"cn":"输入框宽度","en":"Input width","default":"","version":""},"required":false,"type":"string | number "},{"name":"underline","tag":{"cn":"是否只展示下边框","en":"Only display border bottom","default":"false","version":""},"required":false,"type":"boolean "},{"name":"border","tag":{"cn":"是否展示边框","en":"Whether to display border","default":"false","version":""},"required":false,"type":"boolean "},{"name":"showArrow","tag":{"cn":"是否展示箭头","en":"Whether to display arrow","default":"true","version":""},"required":false,"type":"boolean "},{"name":"childrenKey","tag":{"cn":"指定子数据的属性名","en":"specify the name of the subdata","default":"\\\"children\\\"","version":""},"required":false,"type":"ObjectKey "},{"name":"focusSelected","tag":{"cn":"onFilter 在多选情况下点击选项后是否选中过滤文本","en":"onFilter Whether to select filter text after clicking the option in multi-selection situation","default":"true","version":""},"required":false,"type":"boolean "},{"name":"resultClassName","tag":{"cn":"选中结果内容容器的className","en":"The className of the selected result content container","default":"","version":""},"required":false,"type":"string | ((value: DataItem) => string) "},{"name":"loader","tag":{"cn":"设置 loader 属性后,未定义 children 的节点视为动态加载节点,点击展开触发 loader事件,children 为 null 或者长度为 0 视为叶子节点","en":"Dynamically load nodes","default":"","version":""},"required":false,"type":"((key: string | number, data: DataItem) => void) "},{"name":"defaultExpanded","tag":{"cn":"默认展开的节点 key(非受控)","en":"default expanded nodes","default":"","version":""},"required":false,"type":"(string | number)[]"},{"name":"defaultExpandAll","tag":{"cn":"默认展开全部子节点, 仅树形数据下有效","en":"Expand all node, only in can be use in treeData","default":"false","version":""},"required":false,"type":"boolean "},{"name":"parentClickExpand","tag":{"cn":"点击父节点展开","en":"Expand by click parent node","default":"false","version":""},"required":false,"type":"boolean "},{"name":"expanded","tag":{"cn":"展开的节点 key(受控)","en":"Expanded node","default":"","version":""},"required":false,"type":"(string | number)[]"},{"name":"trim","tag":{"cn":"trim 为 true 时,失去焦点时会自动删除空白字符","en":"When trim is true, blank characters are automatically deleted when lose focus","default":"false","version":""},"required":false,"type":"boolean "},{"name":"unmatch","tag":{"cn":"是否展示data中不存在的值","en":"Render unmatch value","default":"true","version":""},"required":false,"type":"boolean "},{"name":"renderItem","tag":{"cn":"为 string 时,返回 d[string]。 为 function 时,返回函数结果","en":"When it is a string, return d[string]. When it is a function, return the result of the function","default":"index","version":""},"required":true,"type":"ObjectKey | ((data: DataItem, expanded: boolean, active: boolean, id: string | number) => ReactNode)"},{"name":"onAdvancedFilter","tag":{"cn":"高级筛选模式,可针对当前层级在筛选结果和原始数据间切换","en":"In the advanced filter mode, you can switch between the filter results and the original data for the current level by pressing the button","default":"","version":""},"required":false,"type":"((text: string) => (data: DataItem) => boolean) "},{"name":"onExpand","tag":{"cn":"节点展开回调,参数为当前展开节点 key 数组","en":"Expand event","default":"","version":""},"required":false,"type":"((value: (string | number)[]) => void) "},{"name":"adjust","tag":{"cn":"是否开启自动调整面板位置功能。当面板被窗口遮挡时,自动调整位置","en":"Whether to adjust the position of the panel automatically. When the panel is blocked by the window, the position is adjusted automatically","default":"true","version":""},"required":false,"type":"boolean "},{"name":"popover","tag":{"cn":"校验信息弹出位置","en":"The position where the validation info pop up","default":"","version":""},"required":false,"type":"PopoverProps[\\\"position\\\"]"},{"name":"popoverProps","tag":{"cn":"校验或者tip弹框接受的属性","en":"Vilidate popup properties","default":"","version":""},"required":false,"type":"PopoverProps "},{"name":"name","tag":{"cn":"Form 内存取数据的 key","en":"The key access data in the Form","default":"","version":""},"required":false,"type":"Name "},{"name":"beforeChange","tag":{"cn":"值改变前的回调,当返回值不为空时将作为组件的新值","en":"The callback before the value is changed, when the return value is not empty, it will be used as the new value of the component","default":"","version":""},"required":false,"type":"((value: T) => void | T ) "},{"name":"reserveAble","tag":{"cn":"设置为 true 组件卸载后表单不自动删除数据","en":"If set to true, the form will not automatically delete the data after the component is uninstalled","default":"","version":""},"required":false,"type":"boolean "},{"name":"rules","tag":{"cn":"校验规则 详见 [Rule](/components/rule)","en":"Validation rules, see [Rule](/components/rule) usage for details","default":"","version":""},"required":false,"type":"RuleItem[]"},{"name":"onError","tag":{"cn":"rules 校验回调","en":"rules validation callback","default":"","version":""},"required":false,"type":"((error?: Error ) => void) "},{"name":"bind","tag":{"cn":"当值改变是会联动校验 bind 中的字段, 需要配合 Form 使用","en":"When the value changes, it will link to verify the fields in the bind, which needs to be used with Form","default":"","version":""},"required":false,"type":"string[] "}],"cn":"","en":"","sort":"0"},{"title":"TreeSelectRef","properties":[{"name":"getDataByValues","tag":{"cn":"获取 value 对应的 data","en":"Get the data corresponding to the value","default":"","version":""},"required":true,"type":"(values: Value) => Value extends any[] ? (DataItem | UnMatchedData)[] : DataItem | UnMatchedData"}],"cn":"","en":"","sort":"0"}]'); +const api = JSON.parse('[{"title":"TreeSelect","properties":[{"name":"className","tag":{"cn":"自定义类名","en":"Custom class name","default":"","version":""},"required":false,"type":"string "},{"name":"style","tag":{"cn":"自定义样式","en":"Custom style","default":"","version":""},"required":false,"type":"CSSProperties "},{"name":"size","tag":{"cn":"不同尺寸","en":"There are three built-in size: small、default、large.","default":"\\\"default\\\"","version":""},"required":false,"type":"\\\"small\\\" | \\\"large\\\" | \\\"default\\\""},{"name":"status","tag":{"cn":"组件状态","en":"The status of the component","default":"","version":""},"required":false,"type":"\\\"error\\\" "},{"name":"innerTitle","tag":{"cn":"内嵌标题","en":"inner title","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"filterSameChange","tag":{"cn":"当两次选择的值相同时不触发 onChange","en":"onChange is not triggered when two selected values are the same","default":"false","version":""},"required":false,"type":"boolean "},{"name":"absolute","tag":{"cn":"为 true 时,选项弹出层在 DOM 中独立 render; 为函数时,返回值作为弹出层容器","en":"When it is true, the pop-up layer of option append into document.body; When it is a function, the return value is used as the popup layer container","default":"false","version":""},"required":false,"type":"boolean | (() => HTMLElement | null) "},{"name":"zIndex","tag":{"cn":"选项列表 z-index 值, 需要配合 absolute","en":"options z-index should use with absolute","default":"1000","version":""},"required":false,"type":"number "},{"name":"noCache","tag":{"cn":"是否开启数据缓存,如果数据存在动态更新的情况建议开启","en":"Data cache, if data change asynchronously, better set true","default":"false","version":""},"required":false,"type":"boolean "},{"name":"emptyText","tag":{"cn":"自定义 empty 文案","en":"custom empty copy","default":"","version":""},"required":false,"type":"string "},{"name":"loading","tag":{"cn":"数据加载中,为true时会展示一个默认的 [Spin](/components/Spin) 组件,可以传入一个自定义的Spin代替","en":"When it is true, a default [Spin](/components/Spin) component will be displayed, a custom loading icon can be passed in to replace.","default":"false","version":""},"required":false,"type":"boolean | ReactNode"},{"name":"placeholder","tag":{"cn":"value 为空时的占位符","en":"placeholder when value is empty","default":"","version":""},"required":false,"type":"string "},{"name":"compressedBound","tag":{"cn":"开启多选后,指定允许展示标签数量,超过后将折叠","en":"when compressed is True,the comptessedBound can limit the numbers of multiple selected item\\\"s label","default":"","version":""},"required":false,"type":"number "},{"name":"compressedClassName","tag":{"cn":"多选合并展示弹出框的类名","en":"Compressed popover classname","default":"","version":""},"required":false,"type":"string "},{"name":"clearable","tag":{"cn":"是否可清除值","en":"If clearable is true, show clear value icon","default":"false","version":""},"required":false,"type":"boolean "},{"name":"renderUnmatched","tag":{"cn":"渲染未匹配值的方式","en":"ender unmatched value","default":"","version":""},"required":false,"type":"((data: Value extends (infer U)[] ? U : Value) => ReactNode) "},{"name":"data","tag":{"cn":"数据源","en":"data source","default":"[]","version":""},"required":false,"type":"DataItem[] "},{"name":"keygen","tag":{"cn":"生成 key 的辅助方法, 为函数时,使用此函数返回值, 为 string 时,使用这个 string 对应的数据值。如 \\\"id\\\",相当于 (d) => d.id","en":"Auxiliary method for generating key. When it is a function, use the return value of this function. When it is a string, use the data value corresponding to this string. For example, \\\"id\\\" is the same thing as (d) => d.id","default":"","version":""},"required":true,"type":"ObjectKey | ((data: DataItem, parentKey: string | number) => string | number)"},{"name":"getComponentRef","tag":{"cn":"获取组件的一些方法 目前只支持 getDataByValues","en":"Some methods of getting components Currently only support getDataByValue","default":"","version":""},"required":false,"type":"((ref: ComponentRef) => void) | { current?: ComponentRef ; } "},{"name":"onFilter","tag":{"cn":"onFilter 不为空时,可以输入过滤数据。 onFilter 如果返回一个函数,使用这个函数做前端过滤。 如果不返回,可以自行做后端过滤","en":"When the onFilter is not empty, you can filter data by input. If the onFilter returns a function, use this function as a front-end filter. If return undefined, you can do your own backend filtering","default":"","version":""},"required":false,"type":"((text: string) => void) "},{"name":"empty","tag":{"cn":"无数据时的占位内容","en":"Placeholder content when there is no data","default":"","version":""},"required":false,"type":"ReactNode"},{"name":"multiple","tag":{"cn":"是否是多选","en":"if it is true, it will be multiple selection","default":"false","version":""},"required":false,"type":"boolean "},{"name":"onBlur","tag":{"cn":"blur 事件回调函数","en":"callback function of blur event","default":"","version":""},"required":false,"type":"((e?: any) => void) "},{"name":"onFocus","tag":{"cn":"focus 事件回调函数","en":"callback function of focus event","default":"","version":""},"required":false,"type":"((e?: any) => void) "},{"name":"disabled","tag":{"cn":"为 true 时,所有节点禁用选择,为函数时,根据函数返回结果确定是否禁用","en":"When it is true, all nodes disable the selection; when it is a function, it determines whether it is disabled according to the return result of the function.","default":"false","version":""},"required":false,"type":"boolean | ((data: DataItem) => boolean) "},{"name":"renderResult","tag":{"cn":"选中后在结果中显示的内容,默认和 renderItem 相同","en":"The content displayed in the result after selecting, if not set, use renderItem. not show while return null, result is current selected","default":"renderItem","version":""},"required":false,"type":"((data: DataItem) => ReactNode) "},{"name":"mode","tag":{"cn":"选中值模式,未设置值为单选 0: 只返回完全选中的节点,包含父节点 1: 返回全部选中的节点和半选中的父节点 2: 只返回选中的子节点 3: 如果父节点选中,只返回父节点 4: 所选即所得","en":"mode 0: Returns only the fully selected node including the parent node. 1: Returns all selected nodes and semi-selected nodes. 2: Return only the selected child nodes. 3: If the parent node is full selected, only return the parent node. 4: What you choose is what you get.","default":"1","version":""},"required":false,"type":"0 | 1 | 2 | 3 | 4 "},{"name":"height","tag":{"cn":"列表高度","en":"The height of list","default":"300","version":""},"required":false,"type":"number "},{"name":"onCollapse","tag":{"cn":"下拉列表展开/收起回调","en":"option collapse callback","default":"","version":""},"required":false,"type":"((collapse: boolean) => void) "},{"name":"showHitDescendants","tag":{"cn":"筛选后是否展示命中节点的后代节点","en":"Whether to show the descendant nodes of the hit node after filtering","default":"false","version":""},"required":false,"type":"boolean "},{"name":"position","tag":{"cn":"弹出位置","en":"Popup Position","default":"","version":""},"required":false,"type":"\\\"auto\\\" | \\\"bottom-left\\\" | \\\"top-left\\\" "},{"name":"onEnterExpand","tag":{"cn":"回车触发下拉框展开的时候调用","en":"Expand option list while enter press","default":"","version":""},"required":false,"type":"((e: KeyboardEvent) => boolean) "},{"name":"onChange","tag":{"cn":"参数 为 当前选中值","en":"value is your picker now","default":"","version":""},"required":false,"type":"((value: Value, selected?: DataItem | { IS_NOT_MATCHED_VALUE: boolean, value: any } , path?: (string | number)[] ) => void) "},{"name":"onChangeAddition","tag":{"cn":"onChange 额外参数 (current 为点击的节点的数据, data 为当前选中的数据, checked 为多选状态下是选中还是取消)","en":"onChange additional parameters (current is the data of the clicked node, data is the currently selected data, checked is whether it is selected or canceled in the multi-select state)","default":"","version":""},"required":false,"type":"((params: { current?: DataItem | UnMatchedData | (DataItem | UnMatchedData)[] ; checked?: 0 | 1 | 2 ; data?: DataItem | UnMatchedData | (DataItem | UnMatchedData)[] | null ; }) => void) "},{"name":"value","tag":{"cn":"选中的 key (受控),多选时必须为array。注意,请勿将 undefined 和 null 作为有意义的选项值,当 value 类型为 undefined 和 null 时,组件将不处理数据和渲染","en":"Selected key (controlled), must be an array in multiple selection. Note: Do not use undefined and null as meaningful option values. When the value type is undefined and null, the component will not process data and rendering","default":"","version":""},"required":false,"type":"Value "},{"name":"defaultValue","tag":{"cn":"默认值 和 value 类型相同","en":"Initial value","default":"","version":""},"required":false,"type":"Value "},{"name":"compressed","tag":{"cn":"将选中值合并,只在多选模式下有效;为 \\\"no-repeat\\\" 时弹出框中不重复展示值","en":"Merges selected values; the repeat value will not appear in the Popover when it is\\\"no-repeat\\\".","default":"false","version":""},"required":false,"type":"boolean | \\\"no-repeat\\\" "},{"name":"open","tag":{"cn":"控制浮层显隐","en":"Set visible of datepicker popup","default":"","version":""},"required":false,"type":"boolean "},{"name":"line","tag":{"cn":"是否显示连接线","en":"Whether show line","default":"false","version":""},"required":false,"type":"boolean "},{"name":"width","tag":{"cn":"输入框宽度","en":"Input width","default":"","version":""},"required":false,"type":"string | number "},{"name":"underline","tag":{"cn":"是否只展示下边框","en":"Only display border bottom","default":"false","version":""},"required":false,"type":"boolean "},{"name":"border","tag":{"cn":"是否展示边框","en":"Whether to display border","default":"false","version":""},"required":false,"type":"boolean "},{"name":"showArrow","tag":{"cn":"是否展示箭头","en":"Whether to display arrow","default":"true","version":""},"required":false,"type":"boolean "},{"name":"childrenKey","tag":{"cn":"指定子数据的属性名","en":"specify the name of the subdata","default":"\\\"children\\\"","version":""},"required":false,"type":"ObjectKey "},{"name":"focusSelected","tag":{"cn":"onFilter 在多选情况下点击选项后是否选中过滤文本","en":"onFilter Whether to select filter text after clicking the option in multi-selection situation","default":"true","version":""},"required":false,"type":"boolean "},{"name":"resultClassName","tag":{"cn":"选中结果内容容器的className","en":"The className of the selected result content container","default":"","version":""},"required":false,"type":"string | ((value: DataItem) => string) "},{"name":"loader","tag":{"cn":"设置 loader 属性后,未定义 children 的节点视为动态加载节点,点击展开触发 loader事件,children 为 null 或者长度为 0 视为叶子节点","en":"Dynamically load nodes","default":"","version":""},"required":false,"type":"((key: string | number, data: DataItem) => void) "},{"name":"defaultExpanded","tag":{"cn":"默认展开的节点 key(非受控)","en":"default expanded nodes","default":"","version":""},"required":false,"type":"(string | number)[]"},{"name":"defaultExpandAll","tag":{"cn":"默认展开全部子节点, 仅树形数据下有效","en":"Expand all node, only in can be use in treeData","default":"false","version":""},"required":false,"type":"boolean "},{"name":"parentClickExpand","tag":{"cn":"点击父节点展开","en":"Expand by click parent node","default":"false","version":""},"required":false,"type":"boolean "},{"name":"expanded","tag":{"cn":"展开的节点 key(受控)","en":"Expanded node","default":"","version":""},"required":false,"type":"(string | number)[]"},{"name":"trim","tag":{"cn":"trim 为 true 时,失去焦点时会自动删除空白字符","en":"When trim is true, blank characters are automatically deleted when lose focus","default":"false","version":""},"required":false,"type":"boolean "},{"name":"unmatch","tag":{"cn":"是否展示data中不存在的值","en":"Render unmatch value","default":"true","version":""},"required":false,"type":"boolean "},{"name":"renderItem","tag":{"cn":"为 string 时,返回 d[string]。 为 function 时,返回函数结果","en":"When it is a string, return d[string]. When it is a function, return the result of the function","default":"index","version":""},"required":true,"type":"ObjectKey | ((data: DataItem, expanded: boolean, active: boolean, id: string | number) => ReactNode)"},{"name":"onAdvancedFilter","tag":{"cn":"高级筛选模式,可针对当前层级在筛选结果和原始数据间切换","en":"In the advanced filter mode, you can switch between the filter results and the original data for the current level by pressing the button","default":"","version":""},"required":false,"type":"((text: string) => (data: DataItem) => boolean) "},{"name":"onExpand","tag":{"cn":"节点展开回调,参数为当前展开节点 key 数组","en":"Expand event","default":"","version":""},"required":false,"type":"((value: (string | number)[]) => void) "},{"name":"adjust","tag":{"cn":"是否开启自动调整面板位置功能。当面板被窗口遮挡时,自动调整位置","en":"Whether to adjust the position of the panel automatically. When the panel is blocked by the window, the position is adjusted automatically","default":"true","version":""},"required":false,"type":"boolean "},{"name":"popover","tag":{"cn":"校验信息弹出位置","en":"The position where the validation info pop up","default":"","version":""},"required":false,"type":"PopoverProps[\\\"position\\\"]"},{"name":"popoverProps","tag":{"cn":"校验或者tip弹框接受的属性","en":"Vilidate popup properties","default":"","version":""},"required":false,"type":"PopoverProps "},{"name":"name","tag":{"cn":"Form 内存取数据的 key","en":"The key access data in the Form","default":"","version":""},"required":false,"type":"Name "},{"name":"beforeChange","tag":{"cn":"值改变前的回调,当返回值不为空时将作为组件的新值","en":"The callback before the value is changed, when the return value is not empty, it will be used as the new value of the component","default":"","version":""},"required":false,"type":"((value: T) => void | T ) "},{"name":"reserveAble","tag":{"cn":"设置为 true 组件卸载后表单不自动删除数据","en":"If set to true, the form will not automatically delete the data after the component is uninstalled","default":"","version":""},"required":false,"type":"boolean "},{"name":"rules","tag":{"cn":"校验规则 详见 [Rule](/components/rule)","en":"Validation rules, see [Rule](/components/rule) usage for details","default":"","version":""},"required":false,"type":"RuleItem[]"},{"name":"onError","tag":{"cn":"rules 校验回调","en":"rules validation callback","default":"","version":""},"required":false,"type":"((error?: Error ) => void) "},{"name":"bind","tag":{"cn":"当值改变是会联动校验 bind 中的字段, 需要配合 Form 使用","en":"When the value changes, it will link to verify the fields in the bind, which needs to be used with Form","default":"","version":""},"required":false,"type":"string[] "}],"cn":"","en":"","sort":"0"},{"title":"TreeSelectRef","properties":[{"name":"getDataByValues","tag":{"cn":"获取 value 对应的 data","en":"Get the data corresponding to the value","default":"","version":""},"required":true,"type":"(values: Value) => Value extends any[] ? (DataItem | UnMatchedData)[] : DataItem | UnMatchedData"}],"cn":"","en":"","sort":"0"}]'); export default api; diff --git a/docs/markdown/shineout/changelog-common.md b/docs/markdown/shineout/changelog-common.md index b3546d3bc..35b589d9f 100644 --- a/docs/markdown/shineout/changelog-common.md +++ b/docs/markdown/shineout/changelog-common.md @@ -1,3 +1,14 @@ +## 3.4.0 +2024-09-19 + +### 🆕 Feature +- 新增 `Badge` 组件 + +## 3.4.0 +2024-08-20 +### 🆕 Feature +- 新增`Link` 组件 + ## 3.2.0 2024-06-14 ### 🎨 Theme diff --git a/docs/theme/components/example/style.ts b/docs/theme/components/example/style.ts index ee0826607..b7d590277 100644 --- a/docs/theme/components/example/style.ts +++ b/docs/theme/components/example/style.ts @@ -120,7 +120,9 @@ export default createUseStyles( boxSizing: 'border-box', borderTop: 'none', padding: '14px 16px', - border: '1px solid rgba(232, 235, 240, 1)', + borderLeft: '1px solid rgba(232, 235, 240, 1)', + borderRight: '1px solid rgba(232, 235, 240, 1)', + borderBottom: '1px solid rgba(232, 235, 240, 1)', fontSize: 12, color: 'rgba(20, 23, 55, 1)', }, diff --git a/package.json b/package.json index ca125e9ff..13e3fdd63 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sheinx", "private": true, - "version": "3.3.7-beta.7", + "version": "3.4.0", "description": "A react library developed with sheinx", "module": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/base/src/animation-list/animation-list.tsx b/packages/base/src/animation-list/animation-list.tsx index 88a29fae5..b943f99ef 100644 --- a/packages/base/src/animation-list/animation-list.tsx +++ b/packages/base/src/animation-list/animation-list.tsx @@ -25,6 +25,7 @@ const AnimationList = (props: AnimationListProps) => { type: typePo, className: classNamePo, animation = true, + onAnimationAfterEnter, ...forwardProps } = props; @@ -131,6 +132,7 @@ const AnimationList = (props: AnimationListProps) => { } setStyle((s) => ({ ...s, ...newStyle })); setStatus('afterEnter'); + onAnimationAfterEnter?.(); }; const beforeLeave = () => { @@ -214,7 +216,7 @@ const AnimationList = (props: AnimationListProps) => { cleanTimer(); context.timer = setTimeout(() => { afterEnter(); - }, durationNum); + }, durationNum + mm); } if (status === 'beforeLeave') { cleanTimer(); diff --git a/packages/base/src/animation-list/animation-list.type.ts b/packages/base/src/animation-list/animation-list.type.ts index e40743bb5..3466ab09d 100644 --- a/packages/base/src/animation-list/animation-list.type.ts +++ b/packages/base/src/animation-list/animation-list.type.ts @@ -12,4 +12,5 @@ export interface AnimationListProps extends React.HTMLAttributes style?: React.CSSProperties; onRef?: React.Ref; animation?: boolean; + onAnimationAfterEnter?: () => void; } diff --git a/packages/base/src/badge/__doc__/index.md b/packages/base/src/badge/__doc__/index.md new file mode 100644 index 000000000..b734d6a91 --- /dev/null +++ b/packages/base/src/badge/__doc__/index.md @@ -0,0 +1,16 @@ +--- +name: Badge +group: Other +--- + +# Title + +Badge 标题 +Badge + +# Describe + +Badge 描述 +Badge Describe + +# Example diff --git a/packages/base/src/badge/__example__/01-base.tsx b/packages/base/src/badge/__example__/01-base.tsx new file mode 100644 index 000000000..442549dc8 --- /dev/null +++ b/packages/base/src/badge/__example__/01-base.tsx @@ -0,0 +1,21 @@ +/** +* cn - 基本用法 +* -- +* en - Basic +* -- + */ +import React from 'react'; +import { Badge } from '@sheinx/base'; +import { useBadgeStyle } from '@sheinx/shineout-style'; + +const jssStyle = { + badge: useBadgeStyle +} + +export default () => { + return ( +
+ +
+ ); +}; diff --git a/packages/base/src/badge/badge.tsx b/packages/base/src/badge/badge.tsx new file mode 100644 index 000000000..a22b35e81 --- /dev/null +++ b/packages/base/src/badge/badge.tsx @@ -0,0 +1,112 @@ +import { util } from '@sheinx/hooks'; +import React from 'react'; +import classNames from 'classnames'; +import { BadgeProps, BadgeClasses } from './badge.type'; + +const Badge = (props: BadgeProps) => { + const { + jssStyle, + style, + children, + className, + size, + dot, + count, + overflowCount, + status, + showZero, + color, + text, + } = props; + const badgeStyle = jssStyle?.badge?.() || ({} as BadgeClasses); + console.log('children', children); + const isTextBadge = text !== undefined || (dot && children === undefined); + const rootClass = classNames(className, badgeStyle.badge, isTextBadge && badgeStyle.textBadge); + const isOverflowCount = overflowCount !== undefined && Number(count) > overflowCount; + + const renderCount = () => { + if (isOverflowCount) { + return `${overflowCount}+`; + } + return count; + }; + + const renderCustomCount = () => { + return {count}; + }; + + const renderSup = () => { + let countNode: React.ReactNode = null; + let supClass: { [className: string]: boolean } = {}; + + if (util.isNumber(count)) { + if (count === 0 && !showZero) return null; + countNode = renderCount(); + supClass[badgeStyle.number] = true; + if (count.toString().length === 1 && !isOverflowCount) { + supClass[badgeStyle.singleWord] = true; + } + if (count.toString().length > 1 || isOverflowCount) { + supClass[badgeStyle.multipleWords] = true; + } + } + + if (util.isString(count)) { + if (Number(count) === 0 && !showZero) return null; + countNode = isNaN(Number(count)) ? renderCustomCount() : renderCount(); + } + + if (React.isValidElement(count)) { + countNode = renderCustomCount(); + + return ( + + {countNode} + + ); + } + + return ( + + {dot !== true && countNode} + + ); + }; + + const renderText = () => { + return ( + <> + + {text !== undefined && {text}} + + ); + }; + + return ( + + {!isTextBadge && children} + {!isTextBadge && renderSup()} + {isTextBadge && renderText()} + + ); +}; + +export default Badge; diff --git a/packages/base/src/badge/badge.type.ts b/packages/base/src/badge/badge.type.ts new file mode 100644 index 000000000..6f736dfc6 --- /dev/null +++ b/packages/base/src/badge/badge.type.ts @@ -0,0 +1,83 @@ +import React from 'react'; +// import { BaseBadgeProps } from '@sheinx/hooks'; +import { CommonType } from '../common/type'; + +export interface BadgeClasses { + badge: string; + textBadge: string; + count: string; + custom: string; + number: string; + small: string; + dot: string; + textDot: string; + zoom: string; + status: string; + text: string; + singleWord: string; + multipleWords: string; + warning: string; + success: string; + error: string; + default: string; + processing: string; +} + +export interface BadgeProps extends Pick { + jssStyle?: { + badge: () => BadgeClasses; + }; + /** + * @en Content + * @cn 内容 + */ + children?: React.ReactNode; + /** + * @en Custom badge color + * @cn 自定义徽标颜色 + */ + color?: string; + /** + * @en Number to show, show ${overflowCount}+ when it is greater than overflowCount, hide when it is 0 + * @cn 展示的数字,大于 overflowCount 时显示 ${overflowCount}+,为 0 时隐藏 + */ + count?: React.ReactNode; + /** + * @en Dot mode + * @cn 小点模式,开启后不展示数字 + * @default false + */ + dot?: boolean; + /** + * @en Offset of the badge + * @cn 偏移量 + */ + offset?: [number, number]; + /** + * @en Offset of the badge + * @cn 封顶数值 + */ + overflowCount?: number; + /** + * @en Whether to show Badge when the number is 0 + * @cn 当数值为 0 时,是否展示 Badge + * + */ + showZero?: boolean; + /** + * @en Whether to show Badge when the number is 0 + * @cn 徽标状态 + * + */ + status?: 'success' | 'processing' | 'default' | 'error' | 'warning'; + /** + * @en Status point text, only valid after configuring the status property + * @cn 状态点文本,仅在配置了 status 属性后生效 + */ + text?: React.ReactNode; + /** + * @en Size, only valid in non-dot mode, supports two sizes: small and default + * @cn 尺寸,仅在非 dot 模式下生效,支持 small 和 default 两种尺寸 + */ + size?: 'small' | 'default'; +} diff --git a/packages/base/src/badge/index.ts b/packages/base/src/badge/index.ts new file mode 100644 index 000000000..e4d884cf8 --- /dev/null +++ b/packages/base/src/badge/index.ts @@ -0,0 +1,2 @@ +export { default, default as Badge } from './badge'; +export type { BadgeProps } from './badge.type'; diff --git a/packages/base/src/carousel/carousel.tsx b/packages/base/src/carousel/carousel.tsx index ab5bda519..d312d7cc8 100644 --- a/packages/base/src/carousel/carousel.tsx +++ b/packages/base/src/carousel/carousel.tsx @@ -44,6 +44,22 @@ const Carousel = (props: CarouselProps) => { }; const renderArrow = () => { if (!props.showArrow) return null; + const handlePrev = () => { + if(config.direction === 'ltr') { + func.backward() + }else { + func.forward() + } + func.stop() + } + const handleNext = () => { + if(config.direction === 'ltr') { + func.forward() + }else { + func.backward() + } + func.stop() + } return (
{
{Icons.carousel.Backward}
{Icons.carousel.Forward}
diff --git a/packages/base/src/checkbox/simple-checkbox.tsx b/packages/base/src/checkbox/simple-checkbox.tsx index 180433707..2baddeb05 100644 --- a/packages/base/src/checkbox/simple-checkbox.tsx +++ b/packages/base/src/checkbox/simple-checkbox.tsx @@ -58,7 +58,7 @@ const Checkbox = (props: SimpleCheckboxProps) => { {children !== undefined && children !== null && ( - {children} + {children} )} {typeof renderFooter === 'function' ? renderFooter(checked) : null}
diff --git a/packages/base/src/date-picker/confirm.tsx b/packages/base/src/date-picker/confirm.tsx new file mode 100644 index 000000000..3cb969b97 --- /dev/null +++ b/packages/base/src/date-picker/confirm.tsx @@ -0,0 +1,28 @@ + +import React from 'react'; +import { getLocale, useConfig } from '../config'; +import Button from '../button'; + +import type { ConfirmProps } from './confirm.type'; + +const Confirm = (props: ConfirmProps) => { + const { jssStyle, closeByConfirm } = props; + const styles = jssStyle?.datePicker?.(); + const { locale } = useConfig(); + + return ( +
+ +
+ ); +}; + +export default Confirm; diff --git a/packages/base/src/date-picker/confirm.type.ts b/packages/base/src/date-picker/confirm.type.ts new file mode 100644 index 000000000..2124a6165 --- /dev/null +++ b/packages/base/src/date-picker/confirm.type.ts @@ -0,0 +1,5 @@ +import type { CommonPickerProps } from './picker.type'; + +export interface ConfirmProps extends Pick { + closeByConfirm?: () => void; +} diff --git a/packages/base/src/date-picker/date-picker.tsx b/packages/base/src/date-picker/date-picker.tsx index 4b15f21ee..50ecd2d35 100644 --- a/packages/base/src/date-picker/date-picker.tsx +++ b/packages/base/src/date-picker/date-picker.tsx @@ -33,6 +33,9 @@ const DatePicker = (props0: DatePickerProps([]); const inputRef = useRef<{ inputRef: HTMLInputElement | null; }>({ @@ -84,6 +87,7 @@ const DatePicker = (props0: DatePickerProps(props0: DatePickerProps { if (isOpen) { + setOldDateArr(dateArr) func.startEdit(); } else { - func.finishEdit(); + setClickTimes(0) + + + if(props.needConfirm){ + if(!isCloseFromConfirm){ + func.handleClear(); + // 点击空白处关闭面板时,还原到上次的值 + func.setDateArr(oldDateArr); + } + }else{ + func.finishEdit(); + } + + setIsCloseFromConfirm(false); } props.onCollapse?.(isOpen); }); @@ -140,8 +158,13 @@ const DatePicker = (props0: DatePickerProps { + const handleClose = (isFromConfirm?: boolean) => { + setIsCloseFromConfirm(isFromConfirm || false); closePop(); + + if(isFromConfirm){ + func.finishEdit(); + } inputRef.current.inputRef?.blur(); }; @@ -292,12 +315,15 @@ const DatePicker = (props0: DatePickerProps {props.children} diff --git a/packages/base/src/date-picker/date-picker.type.ts b/packages/base/src/date-picker/date-picker.type.ts index 3f33d02d4..ce62189bb 100644 --- a/packages/base/src/date-picker/date-picker.type.ts +++ b/packages/base/src/date-picker/date-picker.type.ts @@ -5,6 +5,7 @@ import { ButtonClasses } from '../button/button.type'; import { InnerTitleClasses } from '../common/use-inner-title'; import { BaseTipProps } from '../common/use-tip'; import { PopoverClasses } from '../popover/popover.type'; +import { LinkClasses } from '../link/link.type'; import type { DatePickerValueType, DateTimeType } from '@sheinx/hooks'; @@ -69,10 +70,15 @@ export interface DatePickerClasses { pickerCellInRangeStart: string; pickerCellInRangeEnd: string; + pickerRange: string; + pickerRangeBody: string; + pickerRangeFooter: string; + pickerFooter: string; pickerFooterBtn: string; - pickerFooterLeft: string; - pickerFooterRight: string; + pickerFooterTime: string; + pickerFooterNow: string; + pickerFooterConfirm: string; // 日 dayPicker: string; @@ -107,6 +113,7 @@ export type DisabledType = 'start' | 'end'; interface DatePickerJssStyle { datePicker?: () => DatePickerClasses; button?: () => ButtonClasses; + link?: () => LinkClasses; innerTitle?: () => InnerTitleClasses; popover?: () => PopoverClasses; } @@ -222,6 +229,14 @@ export interface DatePickerProps * @default false */ clearWithUndefined?: boolean; + + /** + * @en After clicking the clear button, the data becomes undefined + * @cn 点击清除按钮后数据变为 undefined + * @default false + * @version 3.4.0 + */ + clearToUndefined?: boolean; /** * @en allow single select, only in range can set * @cn 是否允许单选, 仅在 range 模式下有效 @@ -339,6 +354,14 @@ export interface DatePickerProps * @default true */ adjust?: boolean; + + /** + * @en Whether to open the manual confirmation button. After opening, only clicking the confirmation button will submit the selected value. + * @cn 是否开启手动确认按钮,开启后只有点击确认按钮才会提交选择的值。 + * @default false + * @version 3.4.0 + */ + needConfirm?: boolean; } export interface QuickSelectType { name: React.ReactNode; diff --git a/packages/base/src/date-picker/day.tsx b/packages/base/src/date-picker/day.tsx index cd2657ad1..7193f2d4c 100644 --- a/packages/base/src/date-picker/day.tsx +++ b/packages/base/src/date-picker/day.tsx @@ -4,10 +4,11 @@ import classNames from 'classnames'; import Icons from '../icons'; import { getLocale, useConfig } from '../config'; import TimePicker from './time'; -import Button from '../button'; +import Link from '../link'; import type { DayProps } from './day.type'; import PickerTitle from './pickerTitle'; +import Confirm from './confirm'; const Day = (props: DayProps) => { const { jssStyle } = props; @@ -17,8 +18,8 @@ const Day = (props: DayProps) => { const areaType = props.type === 'week' ? 'week' : 'day'; - const onChange = usePersistFn((date) => { - props.onChange(date, props.type === 'datetime'); + const onChange = usePersistFn((date, noClose?: boolean) => { + props.onChange(date, noClose || props.type === 'datetime'); props.setTarget(undefined); }); @@ -48,7 +49,10 @@ const Day = (props: DayProps) => { let now = new Date(); if (func.isDisabled(now)) return; props.setCurrent(new Date(), areaType); - props.onChange(new Date(), props.type === 'datetime'); + props.onChange(new Date(), props.needConfirm || props.type === 'datetime'); + setTimeout(() => { + if(props.closeByConfirm && !props.range) props.closeByConfirm(); + }, 0); }; const renderDay = (item: Date, index: number) => { @@ -75,7 +79,14 @@ const Day = (props: DayProps) => { styles?.pickerCellInRangeEnd, )} key={index} - onClick={() => func.handleDayClick(item)} + onClick={() => { + if(props.range){ + func.handleDayClick(item, props.needConfirm || props.clickTimes < 1) + props.setClickTimes(props.clickTimes + 1) + }else{ + func.handleDayClick(item, props.needConfirm) + } + }} onDoubleClick={() => { props.onDoubleClick?.(item, areaType); }} @@ -124,7 +135,6 @@ const Day = (props: DayProps) => { const renderFooter = () => { const showLeft = props.type === 'datetime' && (props.rangeDate?.[0] || props.rangeDate?.[1]); - const showRight = props.showSelNow; const timeStr = func.getTimeStr(); if (!showLeft && !props.showSelNow) return null; @@ -136,15 +146,25 @@ const Day = (props: DayProps) => { // eslint-disable-next-line if (match) format = match[0]; } + + const showNeedConfirm = props.needConfirm && !props.range; return ( -
+
{props.type === 'datetime' && (
{ <> @@ -155,34 +175,42 @@ const Day = (props: DayProps) => { }
)} - {showRight && ( -
+ {props.showSelNow && ( +
{props.showSelNow && props.type === 'date' && ( - + )} {props.showSelNow && props.type === 'datetime' && ( - + )}
)} + + {showNeedConfirm && ( + + )}
); }; diff --git a/packages/base/src/date-picker/month.tsx b/packages/base/src/date-picker/month.tsx index 91d6faa75..b4914ea27 100644 --- a/packages/base/src/date-picker/month.tsx +++ b/packages/base/src/date-picker/month.tsx @@ -5,6 +5,7 @@ import Icons from '../icons'; import React from 'react'; import { useConfig } from '../config'; import PickerTitle from './pickerTitle'; +import Confirm from './confirm'; const Month = (props: MonthProps) => { const { jssStyle } = props; @@ -71,7 +72,7 @@ const Month = (props: MonthProps) => { } } onClick={() => { - func.handleMonthClick(item); + func.handleMonthClick(item, props.needConfirm); }} >
@@ -125,6 +126,9 @@ const Month = (props: MonthProps) => {
+ {props.needConfirm && !props.range && ( + + )}
); }; diff --git a/packages/base/src/date-picker/picker.tsx b/packages/base/src/date-picker/picker.tsx index 65037ce73..b96ad1b54 100644 --- a/packages/base/src/date-picker/picker.tsx +++ b/packages/base/src/date-picker/picker.tsx @@ -7,6 +7,7 @@ import Quarter from './quarter'; import Time from './time'; import Quick from './quick'; import { useDatePickerRange, usePersistFn } from '@sheinx/hooks'; +import Confirm from './confirm'; const Picker = (props: PickerProps) => { const { range, currentArr, dateArr, options, jssStyle, isDisabledDate, type } = props; @@ -39,6 +40,8 @@ const Picker = (props: PickerProps) => { props.setActiveIndex(-1); }); + const closeByConfirm = () => props.closePop(true); + const renderPicker = (position?: 'start' | 'end') => { const index = position === 'end' ? 1 : 0; const mode = props.mode[index]; @@ -64,6 +67,11 @@ const Picker = (props: PickerProps) => { registerModeDisabled: props.registerModeDisabled, onMouseEnter: () => {}, onMouseLeave: () => {}, + range, + setClickTimes: props.setClickTimes, + clickTimes: props.clickTimes, + needConfirm: props.needConfirm, + closeByConfirm, }; if (range) { commonProps['onMouseEnter'] = position === 'end' ? handleEnterEnd : handleEnterStart; @@ -135,11 +143,22 @@ const Picker = (props: PickerProps) => { {props.children} } - {range - ? ['start', 'end'].map((item) => { - return renderPicker(item as 'start' | 'end'); - }) - : renderPicker()} + {range ? ( +
+
+ { + ['start', 'end'].map((item) => renderPicker(item as 'start' | 'end')) + } +
+ { + props.needConfirm && ( +
+ +
+ ) + } +
+ ) : renderPicker()}
); }; diff --git a/packages/base/src/date-picker/picker.type.ts b/packages/base/src/date-picker/picker.type.ts index 17ee0d5f5..00bebbad8 100644 --- a/packages/base/src/date-picker/picker.type.ts +++ b/packages/base/src/date-picker/picker.type.ts @@ -35,7 +35,7 @@ export interface PickerProps { timeZone?: string; weekStartsOn: number; }; - closePop: () => void; + closePop: (isFromConfirm?: boolean) => void; min?: DateTimeType; max?: DateTimeType; setActiveIndex: (index: number) => void; @@ -45,12 +45,15 @@ export interface PickerProps { disabled: (d: Date) => boolean, ) => void; isDisabledDate: (date: Date, position: 'start' | 'end' | undefined) => boolean; + clickTimes: number; + setClickTimes: Dispatch>; + needConfirm?: boolean; } export interface CommonPickerProps extends Pick< PickerProps, - 'jssStyle' | 'options' | 'format' | 'type' | 'showSelNow' | 'registerModeDisabled' | 'children' + 'jssStyle' | 'options' | 'format' | 'type' | 'showSelNow' | 'range' | 'setClickTimes' | 'clickTimes' | 'needConfirm' | 'registerModeDisabled' | 'children' > { rangeDate: Array; current: Date; @@ -65,6 +68,7 @@ export interface CommonPickerProps position?: 'start' | 'end'; onMouseEnter?: () => void; onMouseLeave?: () => void; + closeByConfirm?: () => void; } export interface CommonTimeProps diff --git a/packages/base/src/date-picker/quarter.tsx b/packages/base/src/date-picker/quarter.tsx index 3e1685b1d..e2d40a133 100644 --- a/packages/base/src/date-picker/quarter.tsx +++ b/packages/base/src/date-picker/quarter.tsx @@ -5,6 +5,7 @@ import Icons from '../icons'; import React from 'react'; import PickerTitle from './pickerTitle'; import { useConfig } from '../config'; +import Confirm from './confirm'; const Quarter = (props: QuarterProps) => { const { jssStyle } = props; @@ -54,7 +55,7 @@ const Quarter = (props: QuarterProps) => { )} key={index} onClick={() => { - func.handleQuarterClick(item); + func.handleQuarterClick(item, props.needConfirm); }} onMouseEnter={ isDisabled @@ -130,6 +131,10 @@ const Quarter = (props: QuarterProps) => { + + {props.needConfirm && !props.range && ( + + )} ); }; diff --git a/packages/base/src/date-picker/time.tsx b/packages/base/src/date-picker/time.tsx index aa9a142f8..f24e14819 100644 --- a/packages/base/src/date-picker/time.tsx +++ b/packages/base/src/date-picker/time.tsx @@ -2,9 +2,10 @@ import React, { useEffect, useRef } from 'react'; import { TimeProps } from './time.type'; import { usePersistFn, useResize, useTimePick } from '@sheinx/hooks'; import classNames from 'classnames'; -import Button from '../button'; +import Link from '../link'; import { getLocale, useConfig } from '../config'; import PickerTitle from './pickerTitle'; +import Confirm from './confirm'; const TimeScroll = (props: { mode: string; @@ -142,21 +143,24 @@ const Time = (props: TimeProps) => { if (!showRight) return null; return ( -
+
{showRight && ( -
- +
)} + + {props.needConfirm && !props.range && ( + + )}
); }; diff --git a/packages/base/src/date-picker/year.tsx b/packages/base/src/date-picker/year.tsx index 833182c0b..350404fcc 100644 --- a/packages/base/src/date-picker/year.tsx +++ b/packages/base/src/date-picker/year.tsx @@ -5,6 +5,7 @@ import Icons from '../icons'; import React from 'react'; import PickerTitle from './pickerTitle'; import { useConfig } from '../config'; +import Confirm from './confirm'; const Year = (props: YearProps) => { const { jssStyle } = props; @@ -58,7 +59,7 @@ const Year = (props: YearProps) => { )} key={index} onClick={() => { - func.handleYearClick(item); + func.handleYearClick(item, props.needConfirm); }} onMouseEnter={ isDisabled @@ -129,6 +130,10 @@ const Year = (props: YearProps) => {
+ + {props.needConfirm && !props.range && ( + + )} ); }; diff --git a/packages/base/src/dropdown/dropdown.type.ts b/packages/base/src/dropdown/dropdown.type.ts index 01ac216be..bbd8be1be 100644 --- a/packages/base/src/dropdown/dropdown.type.ts +++ b/packages/base/src/dropdown/dropdown.type.ts @@ -209,6 +209,13 @@ export interface SimpleDropdownProps * @cn 隐藏箭头 */ hideArrow?: boolean; + + /** + * @en The z-index value of the panel, the default value is 1051 + * @cn 面板的 zIndex 值,默认为 1051 + * @version 3.4.0 + */ + zIndex?: number; } /** diff --git a/packages/base/src/dropdown/dropdownIn.tsx b/packages/base/src/dropdown/dropdownIn.tsx index c2f6679ef..5cc38b757 100644 --- a/packages/base/src/dropdown/dropdownIn.tsx +++ b/packages/base/src/dropdown/dropdownIn.tsx @@ -28,6 +28,7 @@ const Dropdown = (props: SimpleDropdownProps) => { size, animation, hideArrow, + zIndex, } = props; const dropdownClasses = jssStyle?.dropdown?.(); const config = useConfig(); @@ -80,11 +81,13 @@ const Dropdown = (props: SimpleDropdownProps) => { {Icons.dropdown.DropdownArrow} ); - const child = placeholder ? [ - - {placeholder} - , - ] : []; + const child = placeholder + ? [ + + {placeholder} + , + ] + : []; if (!hideArrow) { child.push(caret); } @@ -209,6 +212,7 @@ const Dropdown = (props: SimpleDropdownProps) => { focus={open} parentElRef={targetRef} absolute={absolute} + zIndex={zIndex} fixedWidth={'min'} popupGap={4} popupElRef={popupRef} diff --git a/packages/base/src/icons/config.tsx b/packages/base/src/icons/config.tsx index ca795d6e0..f690027de 100644 --- a/packages/base/src/icons/config.tsx +++ b/packages/base/src/icons/config.tsx @@ -58,6 +58,9 @@ const config = { Show: Icons.Display, Close: Icons.PcCloseCircleFill, }, + link: { + prefixIcon: Icons.Link, + }, menu: { CollapseArrow: Icons.ArrowDown, FrontSolidArrowDown: Icons.PcArrowFillDown, diff --git a/packages/base/src/icons/icons.tsx b/packages/base/src/icons/icons.tsx index c7da85ebe..eecba9644 100644 --- a/packages/base/src/icons/icons.tsx +++ b/packages/base/src/icons/icons.tsx @@ -265,6 +265,10 @@ const search = [ 'M11 2C15.9706 2 20 6.02944 20 11C20 13.1248 19.2637 15.0776 18.0323 16.6172L21.1213 19.7071C21.5118 20.0976 21.5118 20.7308 21.1213 21.1213C20.7308 21.5118 20.0976 21.5118 19.7071 21.1213L16.6172 18.0323C15.0776 19.2637 13.1248 20 11 20C6.02944 20 2 15.9706 2 11C2 6.02944 6.02944 2 11 2ZM11 4C7.13401 4 4 7.13401 4 11C4 14.866 7.13401 18 11 18C14.866 18 18 14.866 18 11C18 7.13401 14.866 4 11 4Z', ]; +const link = [ + 'M8.83231 20.7322C7.27024 22.2943 4.73759 22.2943 3.17546 20.7322C1.66545 19.2222 1.61512 16.8053 3.02446 15.2347L3.17546 15.0754L12.6109 3.70711C14.7588 1.55923 18.2412 1.55923 20.3891 3.70711C22.4773 5.79532 22.5353 9.14496 20.5631 11.3032L20.3891 11.4853L12.3679 21.4393C11.9773 21.8299 11.3442 21.8299 10.9536 21.4394C10.5932 21.0789 10.5654 20.5116 10.8705 20.1193L10.9536 20.0251L18.9749 10.0711C20.3417 8.70423 20.3417 6.48814 18.9749 5.12132C17.6569 3.8033 15.5492 3.75623 14.1747 4.9801L14.0251 5.12132L4.58968 16.4896C3.80864 17.2706 3.80864 18.537 4.58966 19.318C5.32963 20.058 6.5051 20.0969 7.29088 19.4348L7.41809 19.318L16.8535 7.94978C17.0488 7.7545 17.0488 7.43787 16.8536 7.24262C16.68 7.06904 16.4106 7.04975 16.2157 7.18476L16.1464 7.24261L8.12521 17.1967C7.73468 17.5873 7.10152 17.5873 6.71099 17.1967C6.35051 16.8362 6.32277 16.269 6.6278 15.8767L6.71099 15.7825L14.7322 5.8284C15.7085 4.85208 17.2915 4.85208 18.2678 5.82843C19.2016 6.7623 19.2422 8.25112 18.3896 9.23328L18.2678 9.36397L8.83231 20.7322Z' +] + const Icons = { TableSortIconUp, TableSortIconDown, @@ -313,6 +317,8 @@ const Icons = { TreeArrow: icon(treeArrow), TreePlus: icon(treePlus), TreeMinus: icon(treeMinus), + + Link: icon(link), }; export default Icons; diff --git a/packages/base/src/index.ts b/packages/base/src/index.ts index 665ead138..d79a11b8f 100644 --- a/packages/base/src/index.ts +++ b/packages/base/src/index.ts @@ -1,4 +1,5 @@ export * from './alert'; +export * from './badge'; export * from './breadcrumb'; export * from './button'; export * from './card'; @@ -20,6 +21,7 @@ export * from './grid'; export * from './icon'; export * from './image'; export * from './input'; +export * from './link'; export * from './list'; export * from './menu'; export * from './message'; diff --git a/packages/base/src/link/__doc__/index.md b/packages/base/src/link/__doc__/index.md new file mode 100644 index 000000000..a9a755eb7 --- /dev/null +++ b/packages/base/src/link/__doc__/index.md @@ -0,0 +1,16 @@ +--- +name: Link +group: Other +--- + +# Title + +Link 标题 +Link + +# Describe + +Link 描述 +Link Describe + +# Example diff --git a/packages/base/src/link/__example__/01-base.tsx b/packages/base/src/link/__example__/01-base.tsx new file mode 100644 index 000000000..a4f435a7d --- /dev/null +++ b/packages/base/src/link/__example__/01-base.tsx @@ -0,0 +1,21 @@ +/** +* cn - 基本用法 +* -- +* en - Basic +* -- + */ +import React from 'react'; +import { Link } from '@sheinx/base'; +import { useLinkStyle } from '@sheinx/shineout-style'; + +const jssStyle = { + link: useLinkStyle +} + +export default () => { + return ( +
+ +
+ ); +}; diff --git a/packages/base/src/link/index.ts b/packages/base/src/link/index.ts new file mode 100644 index 000000000..5ab3bf68c --- /dev/null +++ b/packages/base/src/link/index.ts @@ -0,0 +1,2 @@ +export { default, default as Link } from './link'; +export type { LinkProps, LinkClasses } from './link.type'; diff --git a/packages/base/src/link/link.tsx b/packages/base/src/link/link.tsx new file mode 100644 index 000000000..97f3ee02f --- /dev/null +++ b/packages/base/src/link/link.tsx @@ -0,0 +1,57 @@ +// import { } from '@sheinx/hooks'; +import classNames from 'classnames'; +import React from 'react'; +import { LinkProps, LinkClasses } from './link.type'; +// import from icons +import Icons from '../icons'; + + +const Link = (props: LinkProps) => { + const { + jssStyle, + className, + type = 'primary', + underline, + disabled, + size, + icon, + + + href, + target, + children, + ...restProps + } = props + + const linkClasses = jssStyle?.link?.() || ({} as LinkClasses); + + const rootClass = classNames(className, linkClasses.wrapper, { + [linkClasses.underline]: underline === true, + [linkClasses.underlineHover]: underline === 'hover', + [linkClasses.disabled]: disabled, + + [linkClasses.sizeSmall]: size === 'small', + [linkClasses.sizeLarge]: size === 'large', + + [linkClasses.primary]: type === 'primary', + [linkClasses.secondary]: type === 'secondary', + [linkClasses.danger]: type === 'danger', + [linkClasses.warning]: type === 'warning', + [linkClasses.success]: type === 'success', + }); + + return ( + + {typeof icon === 'boolean' && icon && {Icons.link.prefixIcon}} + {React.isValidElement(icon) && {icon}} + {children} + + ); +} + +export default Link; diff --git a/packages/base/src/link/link.type.ts b/packages/base/src/link/link.type.ts new file mode 100644 index 000000000..0a310e609 --- /dev/null +++ b/packages/base/src/link/link.type.ts @@ -0,0 +1,65 @@ +// import React from 'react'; +// import { BaseLinkProps } from '@sheinx/hooks'; +import { CommonType } from '../common/type'; + + +export type LinkType = 'primary' | 'secondary' | 'danger' | 'warning' | 'success' + +export interface LinkClasses { + wrapper: string; + underline: string; + underlineHover: string; + + sizeSmall: string; + sizeLarge: string; + + disabled: string; + + icon: string; + + primary: string; + secondary: string; + danger: string; + warning: string; + success: string; +} + +export interface LinkProps + extends Pick, + React.AnchorHTMLAttributes { + jssStyle?: { + link?: () => LinkClasses; + }; + + /** + * @cn 是否禁用 + * @en Whether the link is disabled + */ + disabled?: boolean; + + /** + * @cn 是否常驻显示下划线, 设置为 'hover' 时鼠标悬浮时显示下划线 + * @en Whether to always show the underline, set to 'hover' to show the underline when the mouse is hovered + */ + underline?: boolean | 'hover'; + + /** + * @cn 链接类型 + * @en Link type + * @default primary + */ + type?: LinkType + + /** + * @cn 链接图标大小 + * @en Link icon size + * @default default + */ + size?: 'small' | 'default' | 'large'; + + /** + * @cn 显示图标,设置为 true 时展示默认图标 + * @en Show icon, set to true to show default icon + */ + icon?: boolean | React.ReactNode; +} diff --git a/packages/base/src/modal/modal-content.tsx b/packages/base/src/modal/modal-content.tsx index d4101f31a..c85e4d480 100644 --- a/packages/base/src/modal/modal-content.tsx +++ b/packages/base/src/modal/modal-content.tsx @@ -187,6 +187,12 @@ const Modal = (props: ModalContentProps) => { }; }, []); + useEffect(() => { + if(props.setInnerClose){ + props.setInnerClose(handleClose) + } + }, [props.setInnerClose]) + // render const renderIcon = (isEmptyTitle?: boolean) => { const iconRoot = classNames(modalClasses?.headerIcon, isEmptyTitle && modalClasses?.emptyIcon); diff --git a/packages/base/src/modal/modal-content.type.ts b/packages/base/src/modal/modal-content.type.ts index 816a2d4a8..291a57e52 100644 --- a/packages/base/src/modal/modal-content.type.ts +++ b/packages/base/src/modal/modal-content.type.ts @@ -3,4 +3,5 @@ import { ModalProps } from './modal.type'; export interface ModalContentProps extends ModalProps { shouldDestroy: (state: boolean) => void; autoShow: boolean; + setInnerClose?: (close: () => void) => void; } diff --git a/packages/base/src/modal/modal-func.tsx b/packages/base/src/modal/modal-func.tsx index 68040f32c..38db29d31 100644 --- a/packages/base/src/modal/modal-func.tsx +++ b/packages/base/src/modal/modal-func.tsx @@ -90,10 +90,14 @@ const BtnCancel = (option: FooterBtnOptions) => { const method = (type: MethodType, jssStyle: ModalJssStyle) => (options: Omit) => { const id = util.getUidStr(); + let innerClose: () => void; const root = getRoot({ container: options.container }); if (!root) return; const destroyModal = () => { - destroy(root); + innerClose(); + setTimeout(() => { + destroy(root); + }, 300); }; modals.add(root); const btnOptions = { @@ -128,6 +132,9 @@ const method = shouldDestroy={(can) => { if (can) destroyModal(); }} + setInnerClose={(close) => { + innerClose = close; + }} > {options.content || options.children} diff --git a/packages/base/src/select/list-columns.tsx b/packages/base/src/select/list-columns.tsx index cedf4e76c..49bd2753e 100644 --- a/packages/base/src/select/list-columns.tsx +++ b/packages/base/src/select/list-columns.tsx @@ -32,7 +32,7 @@ const ColumnsList = (props: BaseListProps) => // columns 模式无上下边距,故而 lineHeight 需要调整 const getLineHeight = () => { - if (lineHeightProp) return lineHeightProp; + if (lineHeightProp && lineHeightProp !== 'auto') return lineHeightProp; if (size === 'small') return 24; if (size === 'default') return 32; if (size === 'large') return 40; diff --git a/packages/base/src/select/list-option.tsx b/packages/base/src/select/list-option.tsx index 3eb095b25..4b0c92c80 100644 --- a/packages/base/src/select/list-option.tsx +++ b/packages/base/src/select/list-option.tsx @@ -1,4 +1,6 @@ +import { useEffect, useRef } from 'react'; import classNames from 'classnames'; +import { addResizeObserver, usePersistFn } from '@sheinx/hooks'; import { SelectClasses } from './select.type'; import { ListOptionProps } from './list-option.type'; import Icons from '../icons'; @@ -14,9 +16,12 @@ const ListOption = (props: ListOptionProps) => multiple, isHover, renderItem, + dynamicVirtual, + isAnimationFinish, onHover, onOptionClick, } = props; + const optionRef = useRef(null); const config = useConfig(); const styles = jssStyle?.select?.() as SelectClasses; const isChecked = datum.check(data); @@ -44,6 +49,14 @@ const ListOption = (props: ListOptionProps) => onOptionClick(data, index); }; + const setVirtualRowHeight = usePersistFn(() => { + if (!props.setRowHeight || !optionRef.current) return; + const optionHeight = optionRef.current.getBoundingClientRect().height; + if (optionHeight !== 0) { + props.setRowHeight(index, optionHeight); + } + }); + const renderCheckedIcon = () => { return ( @@ -55,12 +68,28 @@ const ListOption = (props: ListOptionProps) => const result = renderItem(data); const title = typeof result === 'string' ? result : ''; + useEffect(() => { + if (!isAnimationFinish) return; + setVirtualRowHeight(); + }, [isAnimationFinish]); + + useEffect(() => { + if (!optionRef.current) return; + const cancelObserver = addResizeObserver(optionRef.current, setVirtualRowHeight, { + direction: 'y', + }); + + return () => { + cancelObserver(); + }; + }, []); return (
  • diff --git a/packages/base/src/select/list-option.type.ts b/packages/base/src/select/list-option.type.ts index 2f6d772c8..4b0bafd1d 100644 --- a/packages/base/src/select/list-option.type.ts +++ b/packages/base/src/select/list-option.type.ts @@ -9,7 +9,10 @@ export interface ListOptionProps isHover: boolean; lineHeight: number; closePop: () => void; + dynamicVirtual?: boolean; renderItem: (data: DataItem, index?: number) => React.ReactNode; onHover: (index: number, force?: boolean) => void; onOptionClick: (data: DataItem, index: number) => void; + setRowHeight?: (index: number, height: number) => void; + isAnimationFinish: boolean; } diff --git a/packages/base/src/select/list.tsx b/packages/base/src/select/list.tsx index 52eac8b3c..1a1133289 100644 --- a/packages/base/src/select/list.tsx +++ b/packages/base/src/select/list.tsx @@ -1,8 +1,7 @@ import React, { useRef, useState, useEffect } from 'react'; import classNames from 'classnames'; import { KeygenResult, usePersistFn } from '@sheinx/hooks'; -import { SelectClasses } from './select.type'; -import { BaseListProps } from './select.type'; +import { SelectClasses, BaseListProps } from './select.type'; import { VirtualScrollList } from '../virtual-scroll'; import ListOption from './list-option'; import { VirtualListType } from '../virtual-scroll/virtual-scroll-list.type'; @@ -18,19 +17,23 @@ const List = (props: BaseListProps) => { groupKey, itemsInView = 10, lineHeight: lineHeightProp, + threshold, controlType, hideCreateOption, optionListRef, + isAnimationFinish, renderItem: renderItemProp = (d) => d as React.ReactNode, closePop, onControlTypeChange, onOptionClick, } = props; + const dynamicVirtual = lineHeightProp === 'auto'; const styles = jssStyle?.select?.() as SelectClasses; const rootClass = classNames(styles.list, { [styles.controlMouse]: controlType === 'mouse', [styles.controlKeyboard]: controlType === 'keyboard', + [styles.dynamicList]: dynamicVirtual, }); const [hoverIndex, setHoverIndex] = useState(hideCreateOption ? -1 : 0); const virtualRef = useRef({ @@ -44,7 +47,7 @@ const List = (props: BaseListProps) => { }); const getLineHeight = () => { - if (lineHeightProp) return lineHeightProp; + if (lineHeightProp && lineHeightProp !== 'auto') return lineHeightProp; if (size === 'small') return 26; if (size === 'default') return 34; if (size === 'large') return 42; @@ -133,7 +136,21 @@ const List = (props: BaseListProps) => { } }); - const renderItem = (item: DataItem, index: number, key: KeygenResult) => { + const handleVirtualScroll = usePersistFn(async (info: { y: number }) => { + const { onLoadMore } = props; + if (typeof onLoadMore !== 'function') return; + if (!onLoadMore) return; + if (info.y >= threshold) { + await onLoadMore(); + } + }); + + const renderItem = ( + item: DataItem, + index: number, + key: KeygenResult, + setRowHeight: (index: number, height: number) => void, + ) => { return ( (props: BaseListProps) => { jssStyle={jssStyle} index={index} data={item} + isAnimationFinish={isAnimationFinish} + setRowHeight={setRowHeight} lineHeight={lineHeight} isHover={hoverIndex === index} multiple={multiple} + dynamicVirtual={dynamicVirtual} renderItem={renderItemProp} onHover={handleHover} onOptionClick={onOptionClick} @@ -170,8 +190,10 @@ const List = (props: BaseListProps) => { keygen={keygen} tag={'ul'} groupKey={groupKey} + dynamicVirtual={dynamicVirtual} tagClassName={styles.virtualList} height={height} + onScroll={handleVirtualScroll} lineHeight={lineHeight} rowsInView={itemsInView} renderItem={renderItem} @@ -191,11 +213,7 @@ const List = (props: BaseListProps) => { } }, []); - return ( -
    - {renderList()} -
    - ); + return
    {renderList()}
    ; }; export default List; diff --git a/packages/base/src/select/select.tsx b/packages/base/src/select/select.tsx index 60f549cd1..c22510563 100644 --- a/packages/base/src/select/select.tsx +++ b/packages/base/src/select/select.tsx @@ -90,6 +90,8 @@ function Select(props0: SelectPropsBase) { defaultExpanded, defaultExpandAll, showHitDescendants, + onLoadMore, + threshold = 1, renderOptionList, // onAdvancedFilter, onExpand, @@ -103,6 +105,7 @@ function Select(props0: SelectPropsBase) { // onFilterWidthCreate, filterSameChange, noCache, + trigger = 'click', } = props; const hasFilter = util.isFunc(props.onAdvancedFilter || onFilterProp); @@ -115,6 +118,7 @@ function Select(props0: SelectPropsBase) { const [controlType, setControlType] = useState<'mouse' | 'keyboard'>('keyboard'); const [focused, setFocused] = useState(false); + const [isAnimationFinish, setIsAnimationFinish] = useState(false); const inputRef = useRef(); const optionListRef = useRef(); @@ -179,13 +183,14 @@ function Select(props0: SelectPropsBase) { popupRef, openPop, closePop, + getTargetProps, Provider: PopupProvider, providerValue: popupProviderValue, } = usePopup({ open: openProp, onCollapse: onCollapse, disabled: false, - trigger: 'click', + trigger: trigger, position: positionProp, }); @@ -279,6 +284,7 @@ function Select(props0: SelectPropsBase) { isEmpty && styles.wrapperEmpty, styles?.wrapper, open && styles?.wrapperOpen, + open && trigger === 'hover' && styles?.triggerHover, disabled === true && styles?.wrapperDisabled, disabled !== true && focused && styles?.wrapperFocus, innerTitle && styles?.wrapperInnerTitle, @@ -471,6 +477,10 @@ function Select(props0: SelectPropsBase) { return datum.remove(item); }; + const onAnimationAfterEnter = () => { + setIsAnimationFinish(true); + }; + // innerTitle 模式 const renderInnerTitle = useInnerTitle({ open: open || !isEmpty, @@ -603,6 +613,9 @@ function Select(props0: SelectPropsBase) { emptyAfterSelect, renderItem, controlType, + onLoadMore, + isAnimationFinish, + threshold, onControlTypeChange: setControlType, closePop, optionListRef, @@ -622,7 +635,7 @@ function Select(props0: SelectPropsBase) { const onExpandWrap = usePersistFn((value: KeygenResult[]) => { onExpand?.(value); setAbsoluteListUpdateKey(value?.join(',')); - }) + }); const renderTreeList = () => { return ( @@ -671,7 +684,7 @@ function Select(props0: SelectPropsBase) { if (loading) return renderLoading(); const isEmpty = !filterData?.length; - if (isEmpty) return renderEmpty(); + if (isEmpty && props.emptyText !== false) return renderEmpty(); const options = 'treeData' in props ? renderTreeList() : renderList(); if (renderOptionList) { @@ -703,6 +716,10 @@ function Select(props0: SelectPropsBase) { return style; }; + + const targetProps = getTargetProps(); + const { onMouseEnter, onMouseLeave } = targetProps; + return (
    (props0: SelectPropsBase) { e.preventDefault(); } }} + onMouseEnter={onMouseEnter} + onMouseLeave={onMouseLeave} > {tipNode} {renderResult()} @@ -742,9 +761,11 @@ function Select(props0: SelectPropsBase) { size === 'small' && styles?.pickerSmall, size === 'large' && styles?.pickerLarge, )} + onAnimationAfterEnter={onAnimationAfterEnter} onMouseDown={preventDefault} display={'block'} type='scale-y' + // type='fade' duration={'fast'} style={getListStyle()} > diff --git a/packages/base/src/select/select.type.ts b/packages/base/src/select/select.type.ts index 0beeac722..78380e1c6 100644 --- a/packages/base/src/select/select.type.ts +++ b/packages/base/src/select/select.type.ts @@ -37,6 +37,7 @@ export type SelectClasses = { resultTextDisabled: string; resultTextWrapper: string; multipleResultWrapper: string; + triggerHover: string; resultTextPadding: string; compressedWrapper: string; multipleCompressedWrapper: string; @@ -52,6 +53,7 @@ export type SelectClasses = { arrowIcon: string; ellipsis: string; multiple: string; + dynamicList: string; loading: string; checkedIcon: string; list: string; @@ -123,6 +125,7 @@ export interface BaseListProps | 'columnWidth' | 'columnsTitle' | 'hideCreateOption' + | 'onLoadMore' > { customHeader?: React.ReactNode; height?: number | string; @@ -130,10 +133,13 @@ export interface BaseListProps datum: any; renderItem: (data: DataItem, index?: number) => React.ReactNode; closePop: () => void; + threshold: number; originalData: any; groupKey?: string; + dynamicVirtual?: boolean; controlType?: 'mouse' | 'keyboard'; optionListRef: React.MutableRefObject; + isAnimationFinish: boolean; onControlTypeChange: React.Dispatch>; onOptionClick: (data: DataItem, index: number) => void; } @@ -146,9 +152,9 @@ export interface SelectPropsBase jssStyle?: JssStyleType; /** * @en custom empty copy - * @cn 自定义 empty 文案 + * @cn 自定义 empty 文案。与 renderOptionList 搭配使用时,emptyText 设置为 false 后将忽略该功能,如需渲染空内容可在 renderOptionList 中处理 */ - emptyText?: string; + emptyText?: React.ReactNode; /** * @en Options data @@ -275,11 +281,12 @@ export interface SelectPropsBase itemsInView?: number; /** - * @en Option height. List items are rendered using virtual lists, and when the option height changes, the correct height should be specified via lineHeight - * @cn 选项高度。列表项使用虚拟列表渲染,当选项高度改变时,应该通过 lineHeight 来指定正确高度 + * @en The height of each option. For performance reasons, Select uses a virtual list to render the options. If the option is a fixed height content, such as a fixed size ReactNode, you can adjust the lineHeight to redistribute the height of each item. When lineHeight is set to auto, dynamic virtual list will be enabled, and the actual height will be adaptive according to the content, and each item will be given a minimum height, which will follow the option height corresponding to the size property. This mode will have a certain performance overhead, please choose different modes according to the actual situation. + * @cn 每一条选项的高度。出于默认性能考虑,Select 采用了虚拟列表的方式渲染列表项,如果选项为高度固定内容,比如一个固定尺寸的 ReactNode,可以通过调整 lineHeight 来重新分配每一项的高度。当 lineHeight 设置为 auto 时,将开启动态虚拟列表,实际高度将根据内容自适应,并赋予每一项最小高度,最小高度跟随 size 属性对应的选项高度,该模式将有一定的性能开销,请根据实际情况选择不同的模式。 * @default 32 + * @version 3.4.0 新增 auto 模式 */ - lineHeight?: number; + lineHeight?: number | 'auto'; /** * @en Set Position can control the different position of DatePicker @@ -533,6 +540,26 @@ export interface SelectPropsBase * @default true */ adjust?: boolean; + + /** + * @en Whether to adjust the position of the panel automatically. When the panel is blocked by the window, the position is adjusted automatically + * @cn 滚动加载回的调函数。当配置该属性后,下拉列表滚动到底部时触发该函数 + */ + onLoadMore?: () => void | Promise; + + /** + * @en The threshold for triggering the callback function of the scroll load. When the current scroll progress reaches this value, the callback is triggered, and the maximum value is 1, that is, the scroll progress is 100% + * @cn 触发滚动加载回的调函数的阈值。当前滚动进度达到该值时触发,最大值为 1,即滚动进度 100% + * @default 1 + */ + threshold?: number; + + /** + * @cn 触发打开选择面板的方式,默认为点击打开 + * @en Trigger the way to open the selection panel, default is click to open + * @default 'click' + */ + trigger?: 'click' | 'hover'; } export interface SelectPropsA diff --git a/packages/base/src/sticky/index.ts b/packages/base/src/sticky/index.ts index 9db8b41a1..e89eb7357 100644 --- a/packages/base/src/sticky/index.ts +++ b/packages/base/src/sticky/index.ts @@ -1,2 +1,2 @@ -export { default, default as Sticky } from './sticky'; +export { default, default as Sticky, defaultZIndex } from './sticky'; export type { StickyProps, StickyClasses } from './sticky.type'; diff --git a/packages/base/src/sticky/sticky.tsx b/packages/base/src/sticky/sticky.tsx index dcf6b2c36..d2bc65ca6 100644 --- a/packages/base/src/sticky/sticky.tsx +++ b/packages/base/src/sticky/sticky.tsx @@ -5,7 +5,7 @@ import { StickyProps } from './sticky.type'; const { cssSupport } = util; const supportSticky = cssSupport('position', 'sticky'); -const defaultZIndex = 900; +export const defaultZIndex = 900; const events = ['scroll', 'pageshow', 'load', 'resize']; // const getFirstScrollParent = (el: HTMLElement) => { diff --git a/packages/base/src/table/table.tsx b/packages/base/src/table/table.tsx index a569c48e1..5b230b232 100644 --- a/packages/base/src/table/table.tsx +++ b/packages/base/src/table/table.tsx @@ -5,7 +5,7 @@ import Spin from '../spin'; import Pagination, { PaginationProps } from '../pagination'; import AbsoluteContext from '../absolute-list/absolute-context'; import Empty from '../empty'; -import Sticky from '../sticky'; +import Sticky, {defaultZIndex} from '../sticky'; import { useConfig } from '../config'; import { useTableLayout, @@ -19,6 +19,8 @@ import { usePaginationList, useLatestObj, useResize, + useScrollbarWidth, + util } from '@sheinx/hooks'; import { TableProps } from './table.type'; import useTableSelect from './use-table-select'; @@ -55,8 +57,11 @@ export default (props: TableProps) => { const theadRef = useRef(null); const tfootRef = useRef(null); const scrollRef = useRef(null); + const mirrorScrollRef = useRef(null); const tableRef = useRef(null); + const browserScrollbarWidth = useScrollbarWidth(); + const { current: context } = useRef({ emptyHeight: 0, }); @@ -214,12 +219,15 @@ export default (props: TableProps) => { const target = e.currentTarget; if (!target) return; layoutFunc.checkFloat(); + if(mirrorScrollRef.current){ + mirrorScrollRef.current.scrollLeft = target.scrollLeft + } if (props.onScroll && typeof props.onScroll === 'function') { const maxWidth = target.scrollWidth - target.clientWidth; const maxHeight = target.scrollHeight - target.clientHeight; const x = Math.min(target.scrollLeft / maxWidth, 1); const y = Math.min(target.scrollTop / maxHeight, 1); - props.onScroll(x, y, target.scrollLeft); + props.onScroll(x, y, target.scrollLeft, target.scrollTop); } }); @@ -235,8 +243,11 @@ export default (props: TableProps) => { }) => { virtualInfo.handleScroll(info); layoutFunc.checkFloat(); + if(mirrorScrollRef.current){ + mirrorScrollRef.current.scrollLeft = info.scrollLeft + } if (props.onScroll && typeof props.onScroll === 'function') { - props.onScroll(info.x, info.y, info.scrollLeft); + props.onScroll(info.x, info.y, info.scrollLeft, info.scrollTop); } }, ); @@ -319,7 +330,7 @@ export default (props: TableProps) => { }; const fixRightNum = (isRtl ? -1 * maxScrollLeft : maxScrollLeft) - virtualInfo.innerLeft; - const Wrapper = props.sticky ? Sticky : React.Fragment; + const StickyWrapper = props.sticky ? Sticky : React.Fragment; const sticky = typeof props.sticky === 'object' ? props.sticky : { top: 0 }; const stickyProps = { // @ts-ignore @@ -329,7 +340,7 @@ export default (props: TableProps) => { parent: tableRef?.current, }; - const isRenderBaseTable = !isScrollY && !props.sticky && props.data?.length && !props.style?.height && !props.height + const isRenderVirtualTable = virtual || props.sticky || props.style?.height || props.height const headWrapperClass = classNames( tableClasses?.headWrapper, @@ -341,76 +352,118 @@ export default (props: TableProps) => { isScrollY && scrollBarWidth && tableClasses?.scrollY, ); - if (isRenderBaseTable) { + const renderHeadMirrorScroller = () => { + if(!props.showTopScrollbar) return null + + const scrollRefWidth = scrollRef?.current?.clientWidth || 0 + const scrollRefScrollWidth = scrollRef?.current?.scrollWidth || 0 + const mirrorScrollRefWidth = scrollRefWidth + scrollBarWidth + const showScroll = scrollRefScrollWidth > scrollRefWidth + // 开启了双滚,但是没有滚动条,不显示 + if(!scrollRefWidth || !mirrorScrollRefWidth || !showScroll) return null + + const scrollerStickyProps = { + ...stickyProps, + top: ((sticky?.top || browserScrollbarWidth) - browserScrollbarWidth), + } return ( -
    - - {Group} - {!props.hideHeader && } - {} - {} -
    -
    - ); + +
    { + const target = e.currentTarget; + if(scrollRef?.current && scrollRef.current.scrollLeft !== target.scrollLeft){ + scrollRef.current.scrollLeft = target.scrollLeft + } + }} + ref={mirrorScrollRef} + > +
    +
    +
    + ) } - return ( - <> - {!props.hideHeader && ( - -
    + + if(isRenderVirtualTable){ + return ( + <> + {renderHeadMirrorScroller()} + {!props.hideHeader && ( + +
    + + {Group} + +
    +
    +
    + )} + + + + {Group} + +
    +
    + {renderEmpty()} + {showFoot ? ( +
    {Group} -
    - - )} + ) : null} + + ); + } - - + return ( + <> + {renderHeadMirrorScroller()} +
    +
    {Group} - + {!props.hideHeader && } + {} + {}
    -
    - {renderEmpty()} - {showFoot ? ( -
    - - {Group} - -
    -
    - ) : null} + {renderEmpty()} +
    ); }; @@ -460,8 +513,15 @@ export default (props: TableProps) => { }; }, [theadRef.current, isScrollY]); + const getRenderIndexByData = (data: Item | string) => { + const originKey = typeof data === 'string' ? data : util.getKey(props.keygen, data); + const index = treeData.findIndex((item) => util.getKey(props.keygen, item) === originKey); + return index + }; + const tableFunc = useLatestObj({ scrollToIndex: virtualInfo.scrollToIndex, + getRenderIndexByData: getRenderIndexByData }); useEffect(() => { diff --git a/packages/base/src/table/table.type.ts b/packages/base/src/table/table.type.ts index 2c6d406f9..9a70444f2 100644 --- a/packages/base/src/table/table.type.ts +++ b/packages/base/src/table/table.type.ts @@ -32,6 +32,7 @@ export interface TableClasses { loading: string; + headMirrorScroller: string; headWrapper: string; bodyWrapper: string; footWrapper: string; @@ -76,6 +77,7 @@ export interface TableClasses { export interface TableRef { scrollToIndex: (index: number, cb?: () => void) => void; + getRenderIndexByData: (data: any) => number; [key: string]: any; } @@ -120,18 +122,19 @@ export interface TableProps input?: () => InputClasses; empty?: () => EmptyClasses; }; - /** + /** * * @cn 单元格点击事件 * @en Cell click event */ - onCellClick?: ( + onCellClick?: ( data: DataItem, - info:{ - rowIndex: number, - columnIndex: number, - columnKey: string | number, - }) => void; + info: { + rowIndex: number; + columnIndex: number; + columnKey: string | number; + }, + ) => void; /** * @en which takes effect when the virtual list is enabled * @cn 当开启虚拟列表时生效 @@ -170,7 +173,7 @@ export interface TableProps * @en The callback function after scrolling.\nx: Horizontal rolling ratio(0 <= x <= 1)\ny: Vertical scroll ratio(0 <= y <= 1) * @cn 滚动条滚动后回调函数;\nx: 横向滚动比(0 <= x <= 1)\ny: 纵向滚动比(0 <= y <= 1) */ - onScroll?: (x: number, y: number, left: number) => void; + onScroll?: (x: number, y: number, left: number, top: number) => void; /** * @en Show pagination See [Pagination](/components/Pagination) for details * @cn 展示分页 详见 [Pagination](/components/Pagination) @@ -317,6 +320,14 @@ export interface TableProps * */ sticky?: boolean | { top?: number; css?: boolean }; + + /** + * @en Whether to show the top scroller + * @cn 是否开启顶部滚动条 + * @default false + * @version 3.4.0 + */ + showTopScrollbar?: boolean; /** * @en Table instance (please use with caution: only fixed Table) * @cn Table 实例(请谨慎使用:仅虚拟列表支持) diff --git a/packages/base/src/tabs/tabs-header.tsx b/packages/base/src/tabs/tabs-header.tsx index b3de6c79c..2570ca054 100644 --- a/packages/base/src/tabs/tabs-header.tsx +++ b/packages/base/src/tabs/tabs-header.tsx @@ -151,6 +151,33 @@ const TabsHeader = (props: TabsHeaderProps) => { setTransform(delta + headerRef.current.clientWidth * single); }; + const renderHeaderScrollBar = () => { + if(shape !=='line' && shape !== 'dash') return; + + const currentTab = tabRef.current[active!]; + if(!currentTab) return; + + const currentTabRect = currentTab.getBoundingClientRect(); + + const scrollBarStyle = isVertical ? { + right: getPosition?.startsWith('left') ? 0 : 'auto', + left: getPosition?.startsWith('right') ? 0 : 'auto', + top: currentTab.offsetTop + (currentTabRect.height / 2), + height: shape === 'line' ? currentTabRect.height : 24, + width: 2, + transform: 'translateY(-50%)', + } : { + bottom: getPosition?.startsWith('top') ? 0 : 'auto', + top: getPosition?.startsWith('bottom') ? 0 : 'auto', + left: currentTab.offsetLeft + (currentTabRect.width / 2), + width: shape === 'line' ? currentTabRect.width : 24, + height: 2, + transform: 'translateX(-50%)', + } + + return
    + } + const renderTab = () => { return (
    @@ -183,6 +210,8 @@ const TabsHeader = (props: TabsHeaderProps) => { > ); })} + + {renderHeaderScrollBar()}
    ); diff --git a/packages/base/src/tabs/tabs.type.ts b/packages/base/src/tabs/tabs.type.ts index 099d8e17b..8d8fa1ad2 100644 --- a/packages/base/src/tabs/tabs.type.ts +++ b/packages/base/src/tabs/tabs.type.ts @@ -11,6 +11,7 @@ export interface TabsClasses { panelWrapper: string; headerWrapper: string; headerScroll: string; + headerScrollBar: string header: string; hr: string; button: string; diff --git a/packages/base/src/textarea/textarea.tsx b/packages/base/src/textarea/textarea.tsx index 7e386b95d..1aa7e9fc8 100644 --- a/packages/base/src/textarea/textarea.tsx +++ b/packages/base/src/textarea/textarea.tsx @@ -129,20 +129,37 @@ const Textarea = (props0: TextareaProps) => { const getInfo = () => { const notNumber = typeof info !== 'number'; - if (typeof info !== 'function' && notNumber) return null; - const textInfo = notNumber ? info : defaultInfo.bind(null, info); - const res = textInfo(inputAbleProps.value); + if (typeof info !== 'function' && typeof info !== 'object' && notNumber) return null; + let infoContent: number | ((value: string) => React.ReactNode | Error); + let infoPosition; + if (typeof info === 'object') { + infoContent = info.content; + infoPosition = info.position; + } else { + infoContent = info; + } + const notContentNumber = typeof infoContent !== 'number'; + const textInfo = notContentNumber + ? (infoContent as (value: string) => React.ReactNode | Error) + : defaultInfo.bind(null, infoContent as number); + const res = textInfo(inputAbleProps.value!); // empty if (!res) return null; const isError = res instanceof Error; const text = isError ? res.message : res; if (!isError && !focused) return null; + return (
    {text}
    diff --git a/packages/base/src/textarea/textarea.type.ts b/packages/base/src/textarea/textarea.type.ts index 086cc8bc2..4d9579edd 100644 --- a/packages/base/src/textarea/textarea.type.ts +++ b/packages/base/src/textarea/textarea.type.ts @@ -35,6 +35,8 @@ export interface TextareaClasses { shadow: string; info: string; infoError: string; + bottomLeft:string; + bottomRight:string; footer: string; } @@ -89,6 +91,21 @@ export interface SimpleTextareaProps type TextareaValueType = string; +export type TextareaInfo = number | ((value: string) => React.ReactNode | Error); + +export interface TextareaInfoOption { + /** + * @en The content of the prompt information, the same function and type as the original info attribute + * @cn 提示信息内容,同原 info 属性的功能和类型 + */ + content: TextareaInfo; + /** + * @en The position where the validation info pop up + * @cn 提示信息的弹出位置 + */ + position?: 'bottom-left' | 'bottom-right'; +} + export interface TextareaProps extends BaseTipProps, Omit< @@ -127,8 +144,9 @@ export interface TextareaProps /** * @en Information * @cn 提示信息 + * @version 3.4.0 支持 TextareaInfoOption 配置更多内容 */ - info?: number | ((value: string | undefined) => React.ReactNode | Error); + info?: TextareaInfo | TextareaInfoOption; /** * @en DefaultValue and value can be set at the same time and defaultValue will be overridden by value. * @cn defaultValue 和 value 可以同时设置,defaultValue 会被value覆盖 diff --git a/packages/base/src/transfer/transfer.tsx b/packages/base/src/transfer/transfer.tsx index 3ff0cd02d..ef6def1fe 100644 --- a/packages/base/src/transfer/transfer.tsx +++ b/packages/base/src/transfer/transfer.tsx @@ -40,6 +40,7 @@ const Transfer = ( listHeight = 186, operationIcon = true, searchPlaceholder, + equalPanelWidth, beforeChange, renderFilter, onSearch, @@ -89,6 +90,7 @@ const Transfer = ( [styles.simple]: simple, [styles.small]: size === 'small', [styles.large]: size === 'large', + [styles.equalPanelWidth]: equalPanelWidth, }); const renderOperations = () => { diff --git a/packages/base/src/transfer/transfer.type.ts b/packages/base/src/transfer/transfer.type.ts index 565b40116..c717f9f4d 100644 --- a/packages/base/src/transfer/transfer.type.ts +++ b/packages/base/src/transfer/transfer.type.ts @@ -39,6 +39,7 @@ export interface TransferClasses { itemWrapper: string; checkbox: string; empty: string; + equalPanelWidth: string; } export type JssStyleType = { @@ -176,4 +177,9 @@ export interface TransferProps * @override ((props: { onSelected: ((string | number)[]) => void; direction: "left" | "right"; selectedKeys: (string | number)[]; value: Value; filterText: string; }) => ReactNode) */ children?: (props: CustomRenderProps) => React.ReactNode; + /** + * @en Panel equal distribution container width + * @cn 面板均等分配容器宽度 + */ + equalPanelWidth?: boolean; } diff --git a/packages/base/src/tree-select/tree-select.tsx b/packages/base/src/tree-select/tree-select.tsx index ee2a96f04..3afa67ce1 100644 --- a/packages/base/src/tree-select/tree-select.tsx +++ b/packages/base/src/tree-select/tree-select.tsx @@ -137,6 +137,7 @@ const TreeSelect = ( childrenKey, expanded: expandedProp, showHitDescendants, + filterDelay: props.filterDelay, onAdvancedFilter: 'onAdvancedFilter' in props, onFilter: onAdvancedFilter || onFilterProp, }); diff --git a/packages/base/src/tree-select/tree-select.type.ts b/packages/base/src/tree-select/tree-select.type.ts index ac5707fc1..b95efe37d 100644 --- a/packages/base/src/tree-select/tree-select.type.ts +++ b/packages/base/src/tree-select/tree-select.type.ts @@ -405,4 +405,11 @@ export interface TreeSelectProps * @default true */ adjust?: boolean; + + /** + * @en ms. The delay of user input triggering filter events + * @cn 毫秒。用户输入触发 fitler 事件的延时 + * @default 400 + */ + filterDelay?: number; } diff --git a/packages/base/src/tree/tree.tsx b/packages/base/src/tree/tree.tsx index 0bb699015..ae6d82571 100644 --- a/packages/base/src/tree/tree.tsx +++ b/packages/base/src/tree/tree.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef } from 'react'; +import { useEffect, useRef, useState } from 'react'; import classNames from 'classnames'; import { KeygenResult, useTree, util, ObjectKey } from '@sheinx/hooks'; import { TreeClasses } from './tree.type'; @@ -36,10 +36,11 @@ const Tree = (props: TreeProps(props: TreeProps { + if (isActiveControlled && propActive !== active) { + setActive(propActive); + } + }, [active, propActive]); + const { current: context } = useRef({ mounted: false }); const { datum, expanded, onExpand } = useTree({ @@ -95,15 +106,16 @@ const Tree = (props: TreeProps { + setActive(active); + propSetActive?.(active); + datum.updateMap.forEach((update, id) => { update('active', id === active); }); }; const handleNodeClick = (node: DataItem, id: KeygenResult) => { - if (active === undefined) { - handleUpdateActive(id); - } + handleUpdateActive(id); if (onClick) { onClick(node, id, datum.getPath(id)); diff --git a/packages/base/src/tree/tree.type.ts b/packages/base/src/tree/tree.type.ts index cd051422a..90abfc9c3 100644 --- a/packages/base/src/tree/tree.type.ts +++ b/packages/base/src/tree/tree.type.ts @@ -93,6 +93,11 @@ export interface TreeProps * @cn 激活节点的key */ active?: KeygenResult; + /** + * @en Set active node key + * @cn 设置激活节点的key + */ + setActive?: (key?: KeygenResult) => void; /** * @en If need to double-click to expand * @cn 双击是否展开节点 diff --git a/packages/base/src/virtual-scroll/scroll.tsx b/packages/base/src/virtual-scroll/scroll.tsx index 2bff1602d..5d5dbc6b1 100644 --- a/packages/base/src/virtual-scroll/scroll.tsx +++ b/packages/base/src/virtual-scroll/scroll.tsx @@ -1,10 +1,11 @@ -import React, { useRef } from 'react'; +import React, { useMemo, useRef } from 'react'; import { useForkRef, usePersistFn, useResize, util } from '@sheinx/hooks'; import { useConfig } from '../config'; interface scrollProps { scrollHeight: number; scrollWidth: number; + height?: number | string; children: React.ReactNode; childrenStyle?: React.CSSProperties; wrapperRef?: React.RefObject; @@ -17,6 +18,7 @@ interface scrollProps { height: number; width: number; }) => void; + onScrollToBottom?: (options?: any) => void; className?: string; style?: React.CSSProperties; scrollerStyle?: React.CSSProperties; @@ -33,7 +35,6 @@ const Scroll = (props: scrollProps) => { const { current: context } = useRef({ timer: null as any, isMouseDown: false, - lastPaddingTop: 0, }); const { scrollHeight = 0, scrollWidth = 0, defaultHeight = 0 } = props; const { width, height: h } = useResize({ targetRef: containerRef }); @@ -56,23 +57,39 @@ const Scroll = (props: scrollProps) => { top: 0, } as React.CSSProperties; - let pd = context.lastPaddingTop; - if (height > 0 && scrollHeight > 0) { - pd = Math.max(0, Math.floor(scrollHeight - height)); - context.lastPaddingTop = pd; - } + const paddingTop = useMemo(() => Math.max(0, Math.floor(scrollHeight - height)), [scrollHeight, height]); const placeStyle = { - paddingTop: pd, + paddingTop, width: scrollWidth, - overflow: props.isScrollY ? 'hidden' :'auto hidden', + overflow: props.isScrollY ? 'hidden' : 'auto hidden', height: props.isScrollY ? 0 : 1, marginTop: props.isScrollY ? 0 : -1, lineHeight: 0, }; + const extractHeightValue = (num: number | string) => { + if (util.isNumber(num)) return num; + const match = num.match(/(\d+)/); + if (match) { + return parseInt(match[0], 10); + } + return undefined; + }; + const handleScroll = usePersistFn((e: React.UIEvent) => { + const { onScrollToBottom } = props; + const target = e.currentTarget as HTMLDivElement; let { scrollLeft, scrollTop } = target; + + if (props.height && onScrollToBottom) { + const realHeight = extractHeightValue(props.height); + if (realHeight !== undefined) { + const touchBottom = target.scrollHeight === scrollTop + realHeight; + if (touchBottom) onScrollToBottom(); + } + } + const maxY = target.scrollHeight - target.clientHeight; const maxX = target.scrollWidth - target.clientWidth; diff --git a/packages/base/src/virtual-scroll/virtual-scroll-list.tsx b/packages/base/src/virtual-scroll/virtual-scroll-list.tsx index 64d42be84..7f428369b 100644 --- a/packages/base/src/virtual-scroll/virtual-scroll-list.tsx +++ b/packages/base/src/virtual-scroll/virtual-scroll-list.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useLayoutEffect, useRef } from 'react'; import { usePersistFn } from '@sheinx/hooks'; import Scroll from './scroll'; import { VirtualListProps } from './virtual-scroll-list.type'; @@ -16,31 +16,116 @@ const VirtualList = (props: VirtualListProps) => { customRenderItem, tag = 'div', tagClassName, + dynamicVirtual, virtualRef, // childrenStyle, // wrapperRef, onControlTypeChange, } = props; - const [currentIndex, setCurrentIndex] = useState(0); const [top, setTop] = useState(0); + const [offsetY, setOffsetY] = useState(0); + const [scrollHeight, setHeight] = useState(props.data.length * lineHeight); + const [startIndex, setStartIndex] = useState(0); const wrapperRef = useRef(null); - const getScrollHeight = () => { - const rows = Math.ceil(data.length); - return rows * lineHeight; + const { current: context } = useRef<{ + cachedHeight: number[]; + controlScrollRate: null | number; + preIndex: null | number; + topTimer: any; + rateTimer: any; + shouldUpdateHeight: boolean; + heightCallback: null | (() => void); + }>({ + cachedHeight: [], + controlScrollRate: null, + heightCallback: null, + preIndex: null, + topTimer: null, + rateTimer: null, + shouldUpdateHeight: true, + }); + + const getContentHeight = (index: number) => { + let sum = 0; + for (let i = 0; i <= index; i++) { + sum += context.cachedHeight[i] || lineHeight; + } + return sum; }; const getCurrentIndex = usePersistFn(() => { - return currentIndex; + return startIndex; }); const getTop = usePersistFn(() => { return top; }); + const setRowHeight = usePersistFn((index: number, height: number) => { + const beforeHeight = context.cachedHeight[index]; + if (beforeHeight && beforeHeight === height) return; + + context.cachedHeight[index] = height; + if (context.shouldUpdateHeight) { + setHeight(getContentHeight(props.data.length - 1)); + } + const { preIndex } = context; + // 解决: 从下往上滚 由于高度变化会导致滚动条跳动 + if (preIndex && preIndex > startIndex && startIndex === index) { + // 发生在顶部 + if (context.heightCallback) return; + const offset = height - (beforeHeight || lineHeight); + setOffsetY((s) => s + offset); + } + }); + + const updateRateScroll = usePersistFn((rate: number) => { + const sumHeight = getContentHeight(props.data.length - 1); + if (sumHeight === scrollHeight) return; + context.shouldUpdateHeight = true; + context.heightCallback = () => { + if (wrapperRef && wrapperRef.current) { + const scrollHeight = wrapperRef.current!.scrollHeight; + const clientHeight = wrapperRef.current!.clientHeight; + const nowTop = wrapperRef.current!.scrollTop; + const max = scrollHeight - clientHeight; + const top = rate * max; + if (Math.abs(nowTop - top) < 1) { + context.controlScrollRate = null; + } else { + context.controlScrollRate = rate; + wrapperRef.current!.scrollTop = top; + } + } + }; + setHeight(sumHeight); + }); + + const updateIndexAndTopFromTop = (scrollTop: number) => { + let sum = 0; + let nextCurrentIndex = 0; + let top = 0; + + const maxIndex = Math.max(props.data.length - rowsInView, 0); + for (let i = 0; i <= maxIndex; i++) { + sum += context.cachedHeight[i] || lineHeight; + if (scrollTop < sum || i === maxIndex) { + nextCurrentIndex = i; + const beforeHeight = i === 0 ? 0 : sum - (context.cachedHeight[i] || lineHeight); + top = scrollTop - beforeHeight; + break; + } + } + if (nextCurrentIndex !== startIndex) { + setStartIndex(nextCurrentIndex); + } + setTop(top); + }; + const handleScrollByStep = usePersistFn((step: number, top?: number) => { - const next = currentIndex + step; + const next = startIndex + step; wrapperRef.current?.scrollTo({ top: next * lineHeight + (top || 0) }); }); @@ -57,30 +142,42 @@ const VirtualList = (props: VirtualListProps) => { height: number; width: number; }) => { - const current = Math.floor(info.scrollTop / lineHeight); - const top = info.scrollTop - current * lineHeight; + const { height, y, fromDrag } = info; + let { scrollTop } = info; + context.shouldUpdateHeight = !fromDrag; + const sumHeight = getContentHeight(props.data.length - 1); + const max = sumHeight - height; + if (scrollTop > max) { + scrollTop = max; + } + if (fromDrag) { + const top = y * max; + updateIndexAndTopFromTop(top); + if (context.rateTimer) clearTimeout(context.rateTimer); + context.rateTimer = setTimeout(() => { + updateRateScroll(y); + }, 120); + } else { + updateIndexAndTopFromTop(scrollTop); + } props.onScroll?.(info); - setTop(top); - setCurrentIndex(current); }; - const scrollHeight = getScrollHeight(); - const renderList = () => { - const start = currentIndex; - const end = currentIndex + rowsInView; - let items = data.slice(start, end); + let items = data.slice(startIndex, startIndex + rowsInView); const Tag = tag; - const shouldScroll = data.length * lineHeight > (height as number); + const shouldScroll = getContentHeight(data.length - 1) > (height as number); const nextStyle = { ...style, }; if (shouldScroll) nextStyle.height = height; + const scrollHeight = getContentHeight(data.length - 1); return ( (props: VirtualListProps) => { {items.map((d: DataItem, i: number) => { if (d[groupKey as keyof DataItem]) { return ( - {customRenderItem(d, currentIndex + i, i)} + {customRenderItem(d, startIndex + i, i)} ); } - return {renderItem(d, currentIndex + i, i)}; + return ( + + {renderItem(d, startIndex + i, i, setRowHeight)} + + ); })} ); }; + useEffect(() => { + // 记录preIndex + context.preIndex = startIndex; + }, [startIndex]); + + useLayoutEffect(() => { + // 数据变化的时候清空掉 preIndex, 如果之前有缓存的index, setRowHeight 会有问题 + setTop(0); + setStartIndex(0); + return () => { + context.preIndex = null; + }; + }, [data.length]); + + useEffect(() => { + if (offsetY) { + if (wrapperRef.current) { + setOffsetY(0); + setTop((s) => s + offsetY); + wrapperRef.current.scrollTop += offsetY; + } + } + }, [offsetY, startIndex]); + + useEffect(() => { + setHeight(getContentHeight(props.data.length - 1)); + }, [data.length]); + + useEffect(() => { + if (context.heightCallback) { + const cb = context.heightCallback; + context.heightCallback = null; + cb(); + } + }, [scrollHeight]); + useEffect(() => { if (virtualRef?.current) { virtualRef.current.scrollByStep = handleScrollByStep; @@ -109,7 +246,6 @@ const VirtualList = (props: VirtualListProps) => { virtualRef.current.getTop = getTop; } }, []); - return renderList(); }; diff --git a/packages/base/src/virtual-scroll/virtual-scroll-list.type.ts b/packages/base/src/virtual-scroll/virtual-scroll-list.type.ts index 07271bae1..edac1ff79 100644 --- a/packages/base/src/virtual-scroll/virtual-scroll-list.type.ts +++ b/packages/base/src/virtual-scroll/virtual-scroll-list.type.ts @@ -6,6 +6,7 @@ export type VirtualListType = { getCurrentIndex?: () => number; getTop?: () => number; getHoverIndex?: () => number; + setStartIndex?: (index: number) => void; }; export interface VirtualListProps extends Pick { @@ -24,6 +25,7 @@ export interface VirtualListProps extends Pick; scrollerStyle?: React.CSSProperties; // childrenStyle?: React.CSSProperties; + dynamicVirtual?: boolean; onControlTypeChange?: React.Dispatch>; onScroll?: (info: { scrollLeft: number; diff --git a/packages/hooks/src/common/use-scrollbar-width/index.ts b/packages/hooks/src/common/use-scrollbar-width/index.ts new file mode 100644 index 000000000..7c900955e --- /dev/null +++ b/packages/hooks/src/common/use-scrollbar-width/index.ts @@ -0,0 +1,46 @@ +import { useState, useEffect } from 'react'; + +let scrollbarWidthCache: number | undefined; +function getScrollbarWidth() { + // 检查是否在服务器端运行 + if (typeof window === 'undefined' || typeof document === 'undefined') { + return 0; + } + + // 如果我们的缓存变量已经存在,则直接返回该值 + if (scrollbarWidthCache !== undefined) { + return scrollbarWidthCache; + } + + // 客户端环境,计算滚动条宽度 + const outer = document.createElement("div"); + outer.style.visibility = "hidden"; + outer.style.overflow = "scroll"; + document.body.appendChild(outer); + + const inner = document.createElement("div"); + outer.appendChild(inner); + const scrollbarWidth = outer.offsetWidth - inner.offsetWidth; + if(outer.parentNode) outer.parentNode.removeChild(outer); + + // 缓存并返回计算结果 + scrollbarWidthCache = scrollbarWidth; + return scrollbarWidth; +} + + +export function useScrollbarWidth() { + const [scrollbarWidth, setScrollbarWidth] = useState(0); + + useEffect(() => { + // 只有在客户端时才计算滚动条宽度 + if (typeof window !== 'undefined') { + setScrollbarWidth(getScrollbarWidth()); + } + }, []); + + return scrollbarWidth; +} + + +export default useScrollbarWidth; diff --git a/packages/hooks/src/components/use-datepicker/use-date.ts b/packages/hooks/src/components/use-datepicker/use-date.ts index 9f6e3ca88..eb2ecf092 100644 --- a/packages/hooks/src/components/use-datepicker/use-date.ts +++ b/packages/hooks/src/components/use-datepicker/use-date.ts @@ -117,11 +117,11 @@ const useDate = (props: UseDateProps) => { ); }; - const handleDayClick = (date: Date) => { + const handleDayClick = (date: Date, noClose?: boolean) => { if (isDisabled(date)) return; let newDate = getDateWithTime(date); - props.onChange?.(newDate); + props.onChange?.(newDate, noClose); setCurrent(newDate); }; diff --git a/packages/hooks/src/components/use-datepicker/use-date.type.ts b/packages/hooks/src/components/use-datepicker/use-date.type.ts index e34d365bc..06c48bf2d 100644 --- a/packages/hooks/src/components/use-datepicker/use-date.type.ts +++ b/packages/hooks/src/components/use-datepicker/use-date.type.ts @@ -4,7 +4,7 @@ export interface UseDateProps { defaultCurrent?: Date; onCurrentChange?: (date: Date) => void; value?: Date; - onChange?: (date: Date) => void; + onChange?: (date: Date, noClose?: boolean) => void; min?: Date; max?: Date; type?: 'date' | 'week' | 'datetime'; diff --git a/packages/hooks/src/components/use-datepicker/use-datepicker-format.ts b/packages/hooks/src/components/use-datepicker/use-datepicker-format.ts index d0e4cfea2..b3534f1d6 100644 --- a/packages/hooks/src/components/use-datepicker/use-datepicker-format.ts +++ b/packages/hooks/src/components/use-datepicker/use-datepicker-format.ts @@ -215,9 +215,9 @@ const useDatePickerFormat = ( } }; - const handleClear = usePersistFn((e: React.MouseEvent) => { + const handleClear = usePersistFn((e?: React.MouseEvent) => { if (!clearable) return; - e.stopPropagation(); + e?.stopPropagation(); if (disabledStatus === 'all') return; if (edit) { if (range) { @@ -228,7 +228,7 @@ const useDatePickerFormat = ( setStateDate([undefined]); } } else { - const emptyValue = props.clearWithUndefined ? undefined : ''; + const emptyValue = (props.clearWithUndefined || props.clearToUndefined) ? undefined : ''; let v: string | undefined | Array = emptyValue; if (range) { v = [emptyValue, emptyValue]; @@ -237,6 +237,8 @@ const useDatePickerFormat = ( v = [props.value[0] as string, emptyValue]; } else if (props.value[1] && disabledStatus === 'right') { v = [emptyValue, props.value[1] as string]; + } else if(props.clearToUndefined) { + v = undefined; } } } diff --git a/packages/hooks/src/components/use-datepicker/use-datepicker-format.type.ts b/packages/hooks/src/components/use-datepicker/use-datepicker-format.type.ts index 7084a2ebf..544d6f559 100644 --- a/packages/hooks/src/components/use-datepicker/use-datepicker-format.type.ts +++ b/packages/hooks/src/components/use-datepicker/use-datepicker-format.type.ts @@ -17,6 +17,7 @@ export interface UseDatePickerFormatProps { | undefined; clearable: boolean | undefined; clearWithUndefined: boolean | undefined; + clearToUndefined?: boolean; onClear: (() => void) | undefined; allowSingle: boolean | undefined; defaultCurrent: DatePickerValueType; diff --git a/packages/hooks/src/components/use-datepicker/use-month.ts b/packages/hooks/src/components/use-datepicker/use-month.ts index cce7825a4..074364a40 100644 --- a/packages/hooks/src/components/use-datepicker/use-month.ts +++ b/packages/hooks/src/components/use-datepicker/use-month.ts @@ -87,10 +87,10 @@ const useMonth = (props: UseMonthProps) => { return utils.getDateInfo(date, 'month', options) + 1; }; - const handleMonthClick = (date: Date) => { + const handleMonthClick = (date: Date, onClose?:boolean) => { if (isDisabled(date)) return; let newDate = utils.toDate(date); - props.onChange?.(newDate); + props.onChange?.(newDate, onClose); setCurrent(newDate); }; diff --git a/packages/hooks/src/components/use-datepicker/use-month.type.ts b/packages/hooks/src/components/use-datepicker/use-month.type.ts index 8fc1bf490..81695bcff 100644 --- a/packages/hooks/src/components/use-datepicker/use-month.type.ts +++ b/packages/hooks/src/components/use-datepicker/use-month.type.ts @@ -4,7 +4,7 @@ export interface UseMonthProps { defaultCurrent?: Date; onCurrentChange?: (date: Date) => void; value?: Date; - onChange?: (date: Date) => void; + onChange?: (date: Date, onClose?: boolean) => void; min?: Date; max?: Date; disabled?: boolean | ((date: Date) => boolean); diff --git a/packages/hooks/src/components/use-datepicker/use-quarter.ts b/packages/hooks/src/components/use-datepicker/use-quarter.ts index a1f36b009..3cbc831ba 100644 --- a/packages/hooks/src/components/use-datepicker/use-quarter.ts +++ b/packages/hooks/src/components/use-datepicker/use-quarter.ts @@ -86,10 +86,10 @@ const useQuarter = (props: UseMonthProps) => { return utils.getDateInfo(date, 'quarter', options); }; - const handleQuarterClick = (date: Date) => { + const handleQuarterClick = (date: Date, noClose?: boolean) => { if (isDisabled(date)) return; let newDate = utils.toDate(date); - props.onChange?.(newDate); + props.onChange?.(newDate, noClose); setCurrent(newDate); }; diff --git a/packages/hooks/src/components/use-datepicker/use-year.ts b/packages/hooks/src/components/use-datepicker/use-year.ts index fcf5e4b96..51f739f38 100644 --- a/packages/hooks/src/components/use-datepicker/use-year.ts +++ b/packages/hooks/src/components/use-datepicker/use-year.ts @@ -80,10 +80,10 @@ const useYear = (props: UseYearProps) => { return utils.getDateInfo(date, 'year', options); }; - const handleYearClick = (date: Date) => { + const handleYearClick = (date: Date, noClose?: boolean) => { if (isDisabled(date)) return; let newDate = utils.toDate(date); - props.onChange?.(newDate); + props.onChange?.(newDate, noClose); setCurrent(newDate); }; diff --git a/packages/hooks/src/components/use-datepicker/use-year.type.ts b/packages/hooks/src/components/use-datepicker/use-year.type.ts index 27332a419..3f403df10 100644 --- a/packages/hooks/src/components/use-datepicker/use-year.type.ts +++ b/packages/hooks/src/components/use-datepicker/use-year.type.ts @@ -4,7 +4,7 @@ export interface UseYearProps { defaultCurrent?: Date; onCurrentChange?: (date: Date) => void; value?: Date; - onChange?: (date: Date) => void; + onChange?: (date: Date, noClose?: boolean) => void; min?: Date; max?: Date; // type?: string; diff --git a/packages/hooks/src/components/use-table/use-table-virtual.tsx b/packages/hooks/src/components/use-table/use-table-virtual.tsx index 451378d6c..6146c39fb 100644 --- a/packages/hooks/src/components/use-table/use-table-virtual.tsx +++ b/packages/hooks/src/components/use-table/use-table-virtual.tsx @@ -2,7 +2,7 @@ import { usePersistFn } from '../../common/use-persist-fn'; import { useState, useRef, useEffect, useMemo } from 'react'; import { TableFormatColumn } from './use-table.type'; -const MAX_ROW_SPAN = 200 +const MAX_ROW_SPAN = 200; interface UseTableVirtualProps { data: any[]; rowsInView: number; @@ -27,8 +27,7 @@ const useTableVirtual = (props: UseTableVirtualProps) => { const rowSpanInfos = useMemo(() => { const rowSpanColumns = props.columns.filter((col) => typeof col.rowSpan === 'function'); - if(rowSpanColumns.length === 0) return; - + if (rowSpanColumns.length === 0) return; const _rowSpanInfos = []; const totalLength = props.data.length; @@ -39,10 +38,10 @@ const useTableVirtual = (props: UseTableVirtualProps) => { function getRowSpanCount(index: number, _count: number) { let count = _count; - if(index === totalLength - 1) return count; + if (index === totalLength - 1) return count; let prevRowData = props.data[index]; let nextRowData = props.data[index + 1]; - if(rowSpan!(prevRowData, nextRowData)){ + if (rowSpan!(prevRowData, nextRowData)) { count = count + 1; getRowSpanCount(index + 1, count); } @@ -52,30 +51,27 @@ const useTableVirtual = (props: UseTableVirtualProps) => { const count = getRowSpanCount(i, 1); return [startIndex, startIndex + count - 1]; - }); _rowSpanInfos.push(rowSpanInfo); } - for(let i = 0; i < _rowSpanInfos.length; i++) { - if(i === _rowSpanInfos.length - 1) break; - const spans1 = _rowSpanInfos[i] - const spans2 = _rowSpanInfos[i+1] - for(let j=0; j < spans1.length; j++) { - const [startIndex1, endIndex1] = spans1[j] - const [startIndex2] = spans2[j] - if(endIndex1 === startIndex2){ + for (let i = 0; i < _rowSpanInfos.length; i++) { + if (i === _rowSpanInfos.length - 1) break; + const spans1 = _rowSpanInfos[i]; + const spans2 = _rowSpanInfos[i + 1]; + for (let j = 0; j < spans1.length; j++) { + const [startIndex1, endIndex1] = spans1[j]; + const [startIndex2] = spans2[j]; + if (endIndex1 === startIndex2) { spans2[j][0] = startIndex1; } } } - - return _rowSpanInfos.map(_rowSpanInfo => { - const startIndexs = _rowSpanInfo.map(arr => arr[0]); - return Math.min(...startIndexs) + return _rowSpanInfos.map((_rowSpanInfo) => { + const startIndexs = _rowSpanInfo.map((arr) => arr[0]); + return Math.min(...startIndexs); }); - }, [props.data, props.columns]); const { current: context } = useRef({ @@ -141,20 +137,23 @@ const useTableVirtual = (props: UseTableVirtualProps) => { let top = 0; const maxIndex = Math.max(props.data.length - rowsInView, 0); for (let i = 0; i <= maxIndex; i++) { - context.rowSpanRows = 0 + context.rowSpanRows = 0; sum += context.cachedHeight[i] || props.rowHeight; - let rowSpanHeight = 0 - if(rowSpanInfos){ - const maxRowSpanLenth = Math.min(rowSpanInfos.length, props.rowsInView > MAX_ROW_SPAN ? props.rowsInView : props.rowsInView || MAX_ROW_SPAN) - const siblingsIndexs = [] - for(let k=0; k i){ - siblingsIndexs.push(k) + let rowSpanHeight = 0; + if (rowSpanInfos) { + const maxRowSpanLenth = Math.min( + rowSpanInfos.length, + props.rowsInView > MAX_ROW_SPAN ? props.rowsInView : props.rowsInView || MAX_ROW_SPAN, + ); + const siblingsIndexs = []; + for (let k = 0; k < maxRowSpanLenth; k++) { + if (rowSpanInfos[k] <= i && k > i) { + siblingsIndexs.push(k); } } - for(let j=0; j { } }; - const scrollToIndex = usePersistFn((index: number) => { + const scrollToIndex = usePersistFn((index: number, callback?: () => void) => { if (props.disabled) return; if (props.scrollRef.current) { context.shouldUpdateHeight = true; @@ -247,30 +246,33 @@ const useTableVirtual = (props: UseTableVirtualProps) => { if (beforeHeight2 !== beforeHeight) { scrollToIndex(index); } + + if(callback && typeof callback === 'function'){ + callback() + } }; props.scrollRef.current.scrollTop = beforeHeight; } }); - useEffect(() => { const scrollRefHeight = props.scrollRef.current ? props.scrollRef.current.clientHeight : 0; const tableRefHeight = props.innerRef.current ? props.innerRef.current.clientHeight : 0; - const remainHeight = scrollRefHeight - tableRefHeight - if(remainHeight > 0){ - let addonHeight = 0 - let addonCount = 0 - for(let i=startIndex+rowsInView; i= remainHeight + context.cachedHeight[0]) break; + const remainHeight = scrollRefHeight - tableRefHeight; + if (remainHeight > 0) { + let addonHeight = 0; + let addonCount = 0; + for (let i = startIndex + rowsInView; i < props.data.length; i++) { + const height = context.cachedHeight[i] || props.rowHeight; + addonHeight += height; + addonCount += 1; + if (addonHeight >= remainHeight + context.cachedHeight[0]) break; } - if(addonCount > 0){ - context.autoAddRows = addonCount + if (addonCount > 0) { + context.autoAddRows = addonCount; } } - }, []) + }, []); useEffect(() => { // 记录preIndex @@ -279,6 +281,8 @@ const useTableVirtual = (props: UseTableVirtualProps) => { useEffect(() => { // 数据变化的时候清空掉 preIndex, 如果之前有缓存的index, setRowHeight 会有问题 + setTop(0); + setStartIndex(0); return () => { context.preIndex = null; }; @@ -313,6 +317,7 @@ const useTableVirtual = (props: UseTableVirtualProps) => { const renderData = props.disabled ? props.data : [...props.data].slice(startIndex, startIndex + finalRowsInView); + return { scrollHeight, startIndex, diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index f7d09b2ee..d056be17e 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -26,6 +26,7 @@ export * from './common/use-transform'; export * from './common/use-drag-mock'; export * from './common/use-pagination-list'; export * from './common/use-filter'; +export * from './common/use-scrollbar-width'; //components export * from './components/use-input'; diff --git a/packages/shineout-style/src/badge/badge.ts b/packages/shineout-style/src/badge/badge.ts new file mode 100644 index 000000000..c5d4c1014 --- /dev/null +++ b/packages/shineout-style/src/badge/badge.ts @@ -0,0 +1,157 @@ +import token from '@sheinx/theme'; +import { JsStyles } from '../jss-style'; + +export type BadgeClasses = { + badge: string; + count: string; + dot: string; + textDot: string; + custom: string; + number: string; + singleWord: string; + multipleWords: string; + zoom: string; + status: string; + textBadge: string; + text: string; + + warning: string; + success: string; + error: string; + default: string; + processing: string; + + small: string; + + '@keyframes animationZoom': string; + '@keyframes animationProgressing': string; +}; +export type BadgeClassType = keyof BadgeClasses; + +const badgeStyle: JsStyles = { + badge: { + boxSizing: 'border-box', + width: 'fit-content', + margin: 0, + padding: 0, + lineHeight: 1, + listStyle: 'none', + position: 'relative', + display: 'inline-block', + '& $count,$custom,$dot': { + position: 'absolute', + top: 0, + insetInlineEnd: 0, + transform: 'translate(50%, -50%)', + transformOrigin: '100% 0', + boxShadow: `0 0 0 1px #fff`, + }, + }, + textBadge: { + display: 'block', + lineHeight: 'inherit', + verticalAlign: 'baseline', + }, + count: { + textAlign: 'center', + display: 'inline-flex', + justifyContent: 'center', + minWidth: token.badgeCountHeight, + height: token.badgeCountHeight, + verticalAlign: 'super', + lineHeight: token.lineHeightDynamic, + background: token.badgeBadgeBackgroundColor, + borderRadius: token.badgeBadgeBorderRadius, + fontSize: token.badgeBadgeFontSize, + color: token.badgeBadgeFontColor, + }, + small: { + lineHeight: 'initial', + height: token.badgeSmallCountHeight, + minWidth: token.badgeSmallCountHeight, + }, + dot: { + borderRadius: '50%', + width: token.badgeDotWidth, + height: token.badgeDotWidth, + background: token.badgeBadgeBackgroundColor, + }, + textDot: { + position: 'relative', + top: -1, + display: 'inline-block', + borderRadius: '50%', + lineHeight: 'inherit', + verticalAlign: 'middle', + width: token.badgeDotWidth, + height: token.badgeDotWidth, + background: token.badgeBadgeBackgroundColor, + }, + number: {}, + singleWord: {}, + multipleWords: { + padding: `0 ${token.badgeCountPaddingX}`, + }, + custom: {}, + zoom: { + animationName: '$animationZoom', + animationDirection: '0.3', + animationFillMode: 'both', + animationTimingFunction: 'cubic-bezier(0.12, 0.4, 0.29, 1.46)', + }, + status: {}, + text: { + lineHeight: 'inherit', + color: token.badgeTextFontColor, + marginLeft: token.badgeTextMarginLeft, + }, + default: { background: token.badgeDefaultBackgroundColor }, + warning: { background: token.badgeWarningBackgroundColor }, + success: { background: token.badgeSuccessBackgroundColor }, + error: { background: token.badgeErrorBackgroundColor }, + processing: { + borderColor: 'currentcolor', + color: token.badgeProcessingBackgroundColor, + background: token.badgeProcessingBackgroundColor, + '&::after': { + position: 'absolute', + content: '""', + top: 0, + insetInlineStart: 0, + width: '100%', + height: '100%', + borderWidth: 1, + borderStyle: 'solid', + borderColor: 'inherit', + borderRadius: '50%', + animationName: '$animationProgressing', + animationDuration: '1.2s', + animationIterationCount: 'infinite', + animationTimingFunction: 'ease-in-out', + }, + }, + + '@keyframes animationProgressing': { + '0%': { + transform: 'scale(0.8)', + opacity: 0.5, + }, + '100%': { + transform: 'scale(2.4)', + opacity: 0, + }, + }, + + '@keyframes animationZoom': { + '0%': { + transform: 'scale(0) translate(50%, -50%)', + opacity: 0, + }, + '100%': { + transform: 'scale(1) translate(50%, -50%)', + opacity: 1, + }, + }, +}; + +export default badgeStyle; diff --git a/packages/shineout-style/src/badge/index.ts b/packages/shineout-style/src/badge/index.ts new file mode 100644 index 000000000..a0c743d64 --- /dev/null +++ b/packages/shineout-style/src/badge/index.ts @@ -0,0 +1,6 @@ +import { styled } from '../jss-style'; +import badgeStyle from './badge'; + +const useBadgeStyle = styled(badgeStyle, 'badge'); +export { badgeStyle, useBadgeStyle }; +export default useBadgeStyle; diff --git a/packages/shineout-style/src/date-picker/date-picker.ts b/packages/shineout-style/src/date-picker/date-picker.ts index a4879d4c6..efdab56a4 100644 --- a/packages/shineout-style/src/date-picker/date-picker.ts +++ b/packages/shineout-style/src/date-picker/date-picker.ts @@ -348,16 +348,30 @@ const datePickerStyle: JsStyles = { display: 'flex', justifyContent: 'space-between', }, - pickerFooterLeft: { + pickerFooterTime: { padding: `${token.datePickerPanelFooterPaddingY} ${token.datePickerPanelFooterPaddingX}`, }, - pickerFooterRight: { + pickerFooterNow: { padding: `${token.datePickerPanelFooterPaddingY} ${token.datePickerPanelFooterPaddingX}`, '&:only-child': { width: '100%', textAlign: 'center', }, }, + pickerFooterConfirm: { + textAlign: 'right', + padding: `${token.datePickerPanelFooterPaddingY} ${token.datePickerPanelFooterPaddingX}`, + }, + pickerRange: { + }, + pickerRangeBody: { + display: 'flex', + }, + pickerRangeFooter: { + borderTop: `1px solid ${token.datePickerPanelHeaderBorderColor}`, + display: 'flex', + justifyContent: 'flex-end', + }, pickerRow: {}, pickerRowWeek: { '& $pickerCell:nth-child(2)': { @@ -659,6 +673,10 @@ const datePickerStyle: JsStyles = { datetimeHide: { opacity: '0', pointerEvents: 'none', + + '& > span': { + display: 'none', + }, }, quickPicker: { padding: `${token.datePickerQuickPanelPaddingY} ${token.datePickerQuickPanelPaddingX}`, diff --git a/packages/shineout-style/src/index.ts b/packages/shineout-style/src/index.ts index dbcc916d9..dac68c964 100644 --- a/packages/shineout-style/src/index.ts +++ b/packages/shineout-style/src/index.ts @@ -1,4 +1,5 @@ export * from './alert'; +export * from './badge'; export * from './breadcrumb'; export * from './button'; export * from './card'; @@ -19,6 +20,7 @@ export * from './icon'; export * from './image'; export * from './inner-title'; export * from './input'; +export * from './link'; export * from './list'; export * from './menu'; export * from './message'; diff --git a/packages/shineout-style/src/link/index.ts b/packages/shineout-style/src/link/index.ts new file mode 100644 index 000000000..34a875618 --- /dev/null +++ b/packages/shineout-style/src/link/index.ts @@ -0,0 +1,6 @@ +import { styled } from '../jss-style'; +import linkStyle from './link'; + +const useLinkStyle = styled(linkStyle, 'link'); +export { linkStyle, useLinkStyle }; +export default useLinkStyle; diff --git a/packages/shineout-style/src/link/link.ts b/packages/shineout-style/src/link/link.ts new file mode 100644 index 000000000..feb51a393 --- /dev/null +++ b/packages/shineout-style/src/link/link.ts @@ -0,0 +1,108 @@ +import token from '@sheinx/theme'; +import { JsStyles } from '../jss-style'; + +import { LinkClasses } from '@sheinx/base' + +export type LinkClassType = keyof LinkClasses; + +const linkStyle: JsStyles = { + wrapper: { + fontSize: token.linkDefaultFontSize, + }, + sizeSmall: { + fontSize: token.linkSmallFontSize, + }, + sizeLarge: { + fontSize: token.linkLargeFontSize, + }, + underline: { + textDecoration: 'underline', + '&:hover': { + textDecoration: 'underline', + }, + }, + underlineHover: { + textDecoration: 'none', + '&:hover': { + textDecoration: 'underline', + }, + }, + disabled: { + color: token.linkPrimaryDisabledFontColor, + cursor: 'not-allowed', + '&:hover': { + color: token.linkPrimaryDisabledFontColor, + }, + }, + primary: { + color: token.linkPrimaryFontColor, + '&:hover': { + color: token.linkPrimaryHoverFontColor, + }, + '&:active': { + color: token.linkPrimaryActiveFontColor, + }, + '&$disabled': { + color: token.linkPrimaryDisabledFontColor, + } + }, + secondary: { + color: token.linkSecondaryFontColor, + '&:hover': { + color: token.linkSecondaryHoverFontColor, + }, + '&:active': { + color: token.linkSecondaryActiveFontColor, + }, + '&$disabled': { + color: token.linkSecondaryDisabledFontColor, + } + }, + danger: { + color: token.linkDangerFontColor, + '&:hover': { + color: token.linkDangerHoverFontColor, + }, + '&:active': { + color: token.linkDangerActiveFontColor, + }, + '&$disabled': { + color: token.linkDangerDisabledFontColor, + } + }, + warning: { + color: token.linkWarningFontColor, + '&:hover': { + color: token.linkWarningHoverFontColor, + }, + '&:active': { + color: token.linkWarningActiveFontColor, + }, + '&$disabled': { + color: token.linkWarningDisabledFontColor, + } + }, + success: { + color: token.linkSuccessFontColor, + '&:hover': { + color: token.linkSuccessHoverFontColor, + }, + '&:active': { + color: token.linkSuccessActiveFontColor, + }, + '&$disabled': { + color: token.linkSuccessDisabledFontColor, + } + }, + icon: { + display: 'inline-block', + width: '1em', + verticalAlign: 'middle', + marginRight: 6, + '& > svg': { + fill: 'currentcolor', + } + } +}; + +export default linkStyle; diff --git a/packages/shineout-style/src/menu/menu.ts b/packages/shineout-style/src/menu/menu.ts index 0ed3583ce..e0430d6c9 100644 --- a/packages/shineout-style/src/menu/menu.ts +++ b/packages/shineout-style/src/menu/menu.ts @@ -212,9 +212,9 @@ const menuStyle: JsStyles = { '$itemInPath > &&': { '[data-soui-theme=light] &': { - color: token.menuItemActiveFontColor, + color: token.menuItemInpathActiveFontColor, '& $icon': { - color: token.menuItemActiveFontColor, + color: token.menuItemInpathActiveFontColor, }, }, diff --git a/packages/shineout-style/src/rate/rate.ts b/packages/shineout-style/src/rate/rate.ts index 08fd8d8df..5b1b7de8e 100644 --- a/packages/shineout-style/src/rate/rate.ts +++ b/packages/shineout-style/src/rate/rate.ts @@ -58,6 +58,10 @@ const rateStyle: JsStyles = { height: '100%', transition: 'none', color: token.rateBackgroundColor, + '& > svg': { + width: '1em', + height: '1em', + }, }, itemFront: { position: 'absolute', @@ -67,6 +71,10 @@ const rateStyle: JsStyles = { bottom: 0, opacity: 0, color: token.rateFrontBackgroundColor, + '& > svg': { + width: '1em', + height: '1em', + }, }, itemHalf: { position: 'absolute', diff --git a/packages/shineout-style/src/select/select.ts b/packages/shineout-style/src/select/select.ts index ad1045018..f7b71bffd 100644 --- a/packages/shineout-style/src/select/select.ts +++ b/packages/shineout-style/src/select/select.ts @@ -136,6 +136,16 @@ const selectStyle: JsStyles = { color: token.selectDisabledPlaceholderColor, }, }, + triggerHover: { + '&::after': { + content: '""', + position: 'absolute', + right: 0, + left: 0, + height: 4, + bottom: -4, + }, + }, popover: {}, ...resetWrapper, resultWrapper: { @@ -434,6 +444,11 @@ const selectStyle: JsStyles = { padding: 0, width: '100%', }, + dynamicList: { + '& $optionInner': { + textWrap: 'wrap', + }, + }, option: { listStyle: 'none', lineHeight: token.lineHeightDynamic, diff --git a/packages/shineout-style/src/table/table.ts b/packages/shineout-style/src/table/table.ts index fa3015c89..c21060231 100644 --- a/packages/shineout-style/src/table/table.ts +++ b/packages/shineout-style/src/table/table.ts @@ -141,7 +141,8 @@ const tableStyle: JsStyles = { }, }, bordered: { - border: `1px solid ${token.tableCellBorderColor}`, + borderLeft: `1px solid ${token.tableCellBorderColor}`, + borderRight: `1px solid ${token.tableCellBorderColor}`, borderBottom: 'none', borderTop: 'none', '&::before': { @@ -164,6 +165,9 @@ const tableStyle: JsStyles = { borderTop: `1px solid ${token.tableCellBorderColor}`, }, }, + headMirrorScroller: { + overflow: 'scroll hidden', + }, headWrapper: { flex: '0 0 auto', overflow: 'hidden', diff --git a/packages/shineout-style/src/tabs/tabs.ts b/packages/shineout-style/src/tabs/tabs.ts index 9ea325f61..f5e6fbae3 100644 --- a/packages/shineout-style/src/tabs/tabs.ts +++ b/packages/shineout-style/src/tabs/tabs.ts @@ -1,4 +1,4 @@ -import Token from '@sheinx/theme'; +import Token, {CommonToken} from '@sheinx/theme'; import { TabsClasses } from '@sheinx/base'; import { JsStyles } from '../jss-style'; @@ -133,39 +133,33 @@ const getCardStyle = () => { const getLineStyle = () => { return { + '$tab': { + '&:after': { + display: 'none', + }, + }, '&[data-soui-position^="left-"][data-soui-shape="line"]': { '&[dir=ltr]': { '& $hr': { right: 0, width: 1, height: '100%' }, - ...active({ top: 0, bottom: 0, right: 0, width: 2 }), }, '&[dir=rtl]': { '& $hr': { left: 0, width: 1, height: '100%' }, - ...active({ top: 0, bottom: 0, left: 0, width: 2 }), }, - // '& :not([data-soui-state="active"])$tab': { - // '&:after': { - // display: 'none', - // }, - // }, }, '&[data-soui-position^="right-"][data-soui-shape="line"]': { '&[dir=ltr]': { '& $hr': { left: 0, width: 1, height: '100%' }, - ...active({ top: 0, bottom: 0, left: 0, width: 2 }), }, '&[dir=rtl]': { '& $hr': { right: 0, width: 1, height: '100%' }, - ...active({ top: 0, bottom: 0, right: 0, width: 2 }), }, }, '&[data-soui-position^="top-"][data-soui-shape="line"]': { - '& $hr': { bottom: 0, left: 0, height: 1, width: '100%' }, - ...active({ bottom: 0, left: 0, right: 0, height: 2 }), + '& $hr': { bottom: 0, height: 1, width: '100%' }, }, '&[data-soui-position^="bottom-"][data-soui-shape="line"]': { - '& $hr': { top: 0, left: 0, height: 1, width: '100%' }, - ...active({ top: 0, left: 0, right: 0, height: 2 }), - '& :not([data-soui-state="active"])$tab': { + '& $hr': { top: 0, height: 1, width: '100%' }, + '& $tab': { '&:after': { position: 'absolute', content: '""', @@ -182,28 +176,11 @@ const getLineStyle = () => { const getDashStyle = () => { return { - '&[data-soui-position^="left-"][data-soui-shape="dash"]': { - '&[dir=ltr]': { - ...active({ top: `calc(50% - 12px)`, width: 2, height: 24, right: 0 }), - }, - '&[dir=rtl]': { - ...active({ top: `calc(50% - 12px)`, width: 2, height: 24, left: 0 }), - }, - }, - '&[data-soui-position^="right-"][data-soui-shape="dash"]': { - '&[dir=ltr]': { - ...active({ top: `calc(50% - 12px)`, width: 2, height: 24, left: 0 }), - }, - '&[dir=rtl]': { - ...active({ top: `calc(50% - 12px)`, width: 2, height: 24, right: 0 }), + '$tab': { + '&:after': { + display: 'none', }, }, - '&[data-soui-position^="top-"][data-soui-shape="dash"]': { - ...active({ bottom: 0, left: `calc(50% - 12px)`, width: 24, height: 2 }), - }, - '&[data-soui-position^="bottom-"][data-soui-shape="dash"]': { - ...active({ top: 0, left: `calc(50% - 12px)`, width: 24, height: 2 }), - }, }; }; @@ -541,6 +518,11 @@ const tabsStyle: JsStyles = { headerScroll: { transition: 'all .2s cubic-bezier(.34,.69,.1,1)', }, + headerScrollBar: { + position: 'absolute', + background: Token.tabsActiveFontColor, + transition: `left ${CommonToken['Animation-duration-2']} ease-in-out, top ${CommonToken['Animation-duration-2']} ease-in-out, width ${CommonToken['Animation-duration-2']} ease-in-out, height ${CommonToken['Animation-duration-2']} ease-in-out`, + }, header: { flex: 1, display: 'flex', @@ -591,9 +573,6 @@ const tabsStyle: JsStyles = { fontSize: Token.tabsLineCheckedFontSize, background: Token.tabsLineCheckedBackgroundColor, fontWeight: Token.tabsLineCheckedFontWeight, - '&:after': { - background: Token.tabsLineAfterBackgroundColor, - }, }, '&[data-soui-state="disabled"]': { @@ -601,6 +580,16 @@ const tabsStyle: JsStyles = { cursor: 'not-allowed', }, + '&:after': { + position: 'absolute', + content: '""', + bottom: 0, + left: 0, + width: '100%', + height: 1, + background: Token.tabsLineHrBackgroundColor, + }, + '[data-soui-position^="left-"] &': { '&:after': { width: 1, @@ -617,17 +606,6 @@ const tabsStyle: JsStyles = { background: Token.tabsLineHrBackgroundColor, }, }, - '&:not([data-soui-state="active"])': { - '&:after': { - position: 'absolute', - content: '""', - bottom: 0, - left: 0, - width: '100%', - height: 1, - background: Token.tabsLineHrBackgroundColor, - }, - }, '&:not([data-soui-state="active"]):not([data-soui-state="disabled"]):hover $lineInner': { background: Token.tabsLineHoverBackgroundColor, diff --git a/packages/shineout-style/src/textarea/textarea.ts b/packages/shineout-style/src/textarea/textarea.ts index 4a438b6db..611032af2 100644 --- a/packages/shineout-style/src/textarea/textarea.ts +++ b/packages/shineout-style/src/textarea/textarea.ts @@ -98,6 +98,8 @@ const input: JsStyles = { zIndex: 1000, '&[dir=ltr]': { right: '0' }, '&[dir=rtl]': { left: '0' }, + '&$bottomLeft': { right: 'auto' }, + '&$bottomRight': { left: 'auto' }, top: '100%', transformOrigin: '100% 0', marginTop: '10px', @@ -128,6 +130,20 @@ const input: JsStyles = { '&[dir=rtl]::before': { left: '8px', }, + '&$bottomLeft::before': { + left: '8px', + right: 'auto', + }, + '&$bottomRight::before': { + right: '4px', + left: 'auto', + }, + }, + bottomLeft: { + left: 0, + }, + bottomRight: { + right: 0, }, infoError: { boxShadow: `0 0 0 1px ${token.textareaInfoErrorBorderColor}`, diff --git a/packages/shineout-style/src/transfer/transfer.ts b/packages/shineout-style/src/transfer/transfer.ts index dd4acc10f..fe753c627 100644 --- a/packages/shineout-style/src/transfer/transfer.ts +++ b/packages/shineout-style/src/transfer/transfer.ts @@ -11,6 +11,11 @@ const TransferStyle: JsStyles = { color: Token.transferFontColor, fontSize: Token.transferFontSize, }, + equalPanelWidth: { + '& $view': { + flex: 1, + }, + }, small: { '& $operations': { '& svg': { width: 12 } }, '& $header': { @@ -187,7 +192,14 @@ const TransferStyle: JsStyles = { marginRight: 0, }, }, - checkbox: {}, + checkbox: { + '&>[data-soui-role="desc"]': { + flex: 1, + overflow: 'hidden', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + }, + }, empty: { height: '100%', display: 'flex', diff --git a/packages/shineout-style/src/version.ts b/packages/shineout-style/src/version.ts index 05ee5159e..0127534e4 100644 --- a/packages/shineout-style/src/version.ts +++ b/packages/shineout-style/src/version.ts @@ -1 +1 @@ -export default '3.3.7'; +export default '3.4.0'; \ No newline at end of file diff --git a/packages/shineout/src/badge/__doc__/guide.cn.md b/packages/shineout/src/badge/__doc__/guide.cn.md new file mode 100644 index 000000000..4adf6ad92 --- /dev/null +++ b/packages/shineout/src/badge/__doc__/guide.cn.md @@ -0,0 +1,15 @@ +## 何时使用 + +当操作命令需要用户点击,触发相应业务逻辑时 + +## 与布局相关 + +![在页面、表单、对话框等场景中按钮一般会处于用户浏览路径上,便于用户发现,高效引导行动](01) + +## 组件搭配使用 + +![不同类型按钮搭配使用,可以用来表达不同的强调级别](02) + +## 推荐/慎用示例 + +![多个按钮组合使用时,每个按钮之间需存在一定间隔,不建议连在一起](03) diff --git a/packages/shineout/src/badge/__doc__/guide.en.md b/packages/shineout/src/badge/__doc__/guide.en.md new file mode 100644 index 000000000..7c122d7c6 --- /dev/null +++ b/packages/shineout/src/badge/__doc__/guide.en.md @@ -0,0 +1,17 @@ +## When to use + +When the operation command requires user clicks to trigger corresponding business logic. + +## Related to layout + +![ Buttons in webpages, forms, and dialog boxes are usually placed on the user's browsing path, making them easy to discover and efficiently guide actions.](01) + + +## Component combination + +![ Buttons in webpages, forms, and dialog boxes are usually placed on the user's browsing path, making them easy to discover and efficiently guide actions.](02) + + +## Recommended/Use with caution examples + +![ When multiple buttons are used together, there should be a certain distance between each button, and it is not recommended to connect them together.](03) diff --git a/packages/shineout/src/badge/__doc__/index.md b/packages/shineout/src/badge/__doc__/index.md new file mode 100644 index 000000000..3abd04e59 --- /dev/null +++ b/packages/shineout/src/badge/__doc__/index.md @@ -0,0 +1,17 @@ +--- +name: Badge +group: Feedback +version: 3.4.0 +--- + +# Title + +Badge 徽标 +Badge + +# Describe + +Badge 描述 +Badge Describe + +# Example diff --git a/packages/shineout/src/badge/__example__/01-base.tsx b/packages/shineout/src/badge/__example__/01-base.tsx new file mode 100644 index 000000000..32209271d --- /dev/null +++ b/packages/shineout/src/badge/__example__/01-base.tsx @@ -0,0 +1,23 @@ +/** + * cn - 基本用法 + * -- 基础的徽标展示,当 `count` 为0时默认不展示。可以通过配置 `showZero` 修改为展示 + * en - Basic + * -- The basic badge display, the badge is not displayed by default when `count` is 0. You can modify it to display by configuring `showZero` + */ +import React, { useState } from 'react'; +import { Badge, Switch } from 'shineout'; +import Avatar from './static/avatar'; + +export default () => { + const [showZero, setShowZero] = useState(false); + return ( +
    + + + + + + +
    + ); +}; diff --git a/packages/shineout/src/badge/__example__/02-nochildren.tsx b/packages/shineout/src/badge/__example__/02-nochildren.tsx new file mode 100644 index 000000000..7f3741e8a --- /dev/null +++ b/packages/shineout/src/badge/__example__/02-nochildren.tsx @@ -0,0 +1,17 @@ +/** + * cn - 独立使用 + * -- 不包裹任何元素即是独立使用,可自定样式展现 + * en - No children + * -- Independent use, no wrapping elements is independent use, you can customize the style + */ +import React from 'react'; +import { Badge } from 'shineout'; + +export default () => { + return ( +
    + + +
    + ); +}; diff --git a/packages/shineout/src/badge/__example__/03-overflowcount.tsx b/packages/shineout/src/badge/__example__/03-overflowcount.tsx new file mode 100644 index 000000000..99e3a1178 --- /dev/null +++ b/packages/shineout/src/badge/__example__/03-overflowcount.tsx @@ -0,0 +1,28 @@ +/** + * cn - 封顶数字 + * -- 设置`overflowCount`属性,当数字大于该值时显示 $\{overflowCount\}+ + * en - Overflow count + * -- Set the `overflowCount` property, when the number is greater than this value, display $\{overflowCount\}+ + */ +import React from 'react'; +import { Badge } from 'shineout'; +import Avatar from './static/avatar'; + +export default () => { + return ( +
    + + + + + + + + + + + + +
    + ); +}; diff --git a/packages/shineout/src/badge/__example__/04-dot.tsx b/packages/shineout/src/badge/__example__/04-dot.tsx new file mode 100644 index 000000000..f9e62624f --- /dev/null +++ b/packages/shineout/src/badge/__example__/04-dot.tsx @@ -0,0 +1,19 @@ +/** + * cn - 小点模式 + * -- 开启 `dot` 小点模式,不展示数字 + * en - Dot + * -- Open `dot` dot mode, do not display numbers + */ +import React from 'react'; +import { Badge } from 'shineout'; +import Avatar from './static/avatar'; + +export default () => { + return ( +
    + + + +
    + ); +}; diff --git a/packages/shineout/src/badge/__example__/05-status.tsx b/packages/shineout/src/badge/__example__/05-status.tsx new file mode 100644 index 000000000..14b9702de --- /dev/null +++ b/packages/shineout/src/badge/__example__/05-status.tsx @@ -0,0 +1,29 @@ +/** + * cn - 带状态的小点 + * -- 配置`status`更改徽标的状态 + * en - Basic + * -- The basic badge display, the badge is not displayed by default when `count` is 0. You can modify it to display by configuring `showZero` + */ +import React from 'react'; +import { Badge } from 'shineout'; + +export default () => { + return ( +
    +
    + + + + + +
    +
    + + + + + +
    +
    + ); +}; diff --git a/packages/shineout/src/badge/__example__/static/avatar.tsx b/packages/shineout/src/badge/__example__/static/avatar.tsx new file mode 100644 index 000000000..b61166891 --- /dev/null +++ b/packages/shineout/src/badge/__example__/static/avatar.tsx @@ -0,0 +1,22 @@ +const Avatar = () => { + return ( +
    + + + + +
    + ); +}; + +export default Avatar; diff --git a/packages/shineout/src/badge/badge.tsx b/packages/shineout/src/badge/badge.tsx new file mode 100644 index 000000000..66fc981d9 --- /dev/null +++ b/packages/shineout/src/badge/badge.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { Badge } from '@sheinx/base'; +import { useBadgeStyle } from '@sheinx/shineout-style'; +import { BadgeProps } from './badge.type'; + +const jssStyle = { + badge: useBadgeStyle, +}; +export default (props: BadgeProps) => { + return ; +}; diff --git a/packages/shineout/src/badge/badge.type.ts b/packages/shineout/src/badge/badge.type.ts new file mode 100644 index 000000000..546a4322c --- /dev/null +++ b/packages/shineout/src/badge/badge.type.ts @@ -0,0 +1,6 @@ +import { BadgeProps as UnStyledBadgeProps } from '@sheinx/base'; + +/** + * @title Badge + */ +export type BadgeProps = Omit; diff --git a/packages/shineout/src/badge/index.ts b/packages/shineout/src/badge/index.ts new file mode 100644 index 000000000..1adb72aea --- /dev/null +++ b/packages/shineout/src/badge/index.ts @@ -0,0 +1,14 @@ +import Badge from './badge'; + + +type RefBadge = typeof Badge; + +export interface BadgeComponent extends RefBadge { + displayName: string; +} + +const BadgeComp: BadgeComponent = Badge as BadgeComponent; + +BadgeComp.displayName = 'ShineoutBadge'; + +export default BadgeComp; diff --git a/packages/shineout/src/badge/interface.ts b/packages/shineout/src/badge/interface.ts new file mode 100644 index 000000000..0e6cf0e31 --- /dev/null +++ b/packages/shineout/src/badge/interface.ts @@ -0,0 +1 @@ +export type { BadgeProps as Props } from './badge.type'; diff --git a/packages/shineout/src/card-group/__test__/__snapshots__/cardGroup.spec.tsx.snap b/packages/shineout/src/card-group/__test__/__snapshots__/cardGroup.spec.tsx.snap index 8f983d418..f6d357a42 100644 --- a/packages/shineout/src/card-group/__test__/__snapshots__/cardGroup.spec.tsx.snap +++ b/packages/shineout/src/card-group/__test__/__snapshots__/cardGroup.spec.tsx.snap @@ -401,6 +401,7 @@ exports[`CardGroup[Base] should render correctly about checkbox 1`] = ` 全选 diff --git a/packages/shineout/src/carousel/__doc__/changelog.cn.md b/packages/shineout/src/carousel/__doc__/changelog.cn.md new file mode 100644 index 000000000..2e0a10dd6 --- /dev/null +++ b/packages/shineout/src/carousel/__doc__/changelog.cn.md @@ -0,0 +1,6 @@ +## 3.4.0 +2024-09-19 + +### 🐞 BugFix + +- 修复`Carousel`组件点击箭头切换后,鼠标悬停时没有禁用切换的现象 ([#674](https://github.com/sheinsight/shineout-next/pull/674)) diff --git a/packages/shineout/src/checkbox/__test__/__snapshots__/checkbox.spec.tsx.snap b/packages/shineout/src/checkbox/__test__/__snapshots__/checkbox.spec.tsx.snap index 8c2cb039b..21dbea81e 100644 --- a/packages/shineout/src/checkbox/__test__/__snapshots__/checkbox.spec.tsx.snap +++ b/packages/shineout/src/checkbox/__test__/__snapshots__/checkbox.spec.tsx.snap @@ -20,6 +20,7 @@ exports[`Checkbox[Base] should render correctly 1`] = ` Checkbox @@ -50,6 +51,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked 1`] = not checked @@ -86,6 +88,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked 1`] = checked @@ -119,6 +122,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked 1`] = indeterminate @@ -147,6 +151,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked 1`] = not checked @@ -184,6 +189,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked 1`] = checked @@ -218,6 +224,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked 1`] = indeterminate @@ -247,6 +254,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked is in CheckAll @@ -274,6 +282,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked is in Option1 @@ -297,6 +306,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked is in Option2 @@ -320,6 +330,7 @@ exports[`Checkbox[Checked, disabled] should render correctly about checked is in Option3 @@ -349,6 +360,7 @@ exports[`Checkbox[Click] should render correctly about click 1`] = ` Click Me 0 Times! @@ -377,6 +389,7 @@ exports[`Checkbox[HtmlValue] should render correctly about htmlValue 1`] = ` value is "ok" diff --git a/packages/shineout/src/checkbox/__test__/__snapshots__/checkboxGroup.spec.tsx.snap b/packages/shineout/src/checkbox/__test__/__snapshots__/checkboxGroup.spec.tsx.snap index bf7546fa6..3de934630 100644 --- a/packages/shineout/src/checkbox/__test__/__snapshots__/checkboxGroup.spec.tsx.snap +++ b/packages/shineout/src/checkbox/__test__/__snapshots__/checkboxGroup.spec.tsx.snap @@ -23,6 +23,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxBlock 1`] = ` red @@ -46,6 +47,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxBlock 1`] = ` orange @@ -69,6 +71,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxBlock 1`] = ` yellow @@ -92,6 +95,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxBlock 1`] = ` green @@ -128,6 +132,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxBlock 1`] = ` cyan @@ -164,6 +169,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxBlock 1`] = ` blue @@ -187,6 +193,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxBlock 1`] = ` violet @@ -217,6 +224,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxGroup 1`] = ` red @@ -462,6 +477,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxRawgroup 1`] = ` cyan @@ -498,6 +514,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxRawgroup 1`] = ` blue @@ -521,6 +538,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxRawgroup 1`] = ` green @@ -557,6 +575,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxRawgroup 1`] = ` yellow @@ -580,6 +599,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxRawgroup 1`] = ` orange @@ -603,6 +623,7 @@ exports[`CheckboxGroup[Base] should render correctly by CheckboxRawgroup 1`] = ` violet @@ -634,6 +655,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-A 1`] = ` red @@ -658,6 +680,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-A 1`] = ` orange @@ -682,6 +705,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-A 1`] = ` yellow @@ -706,6 +730,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-A 1`] = ` green @@ -743,6 +768,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-A 1`] = ` cyan @@ -780,6 +806,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-A 1`] = ` blue @@ -804,6 +831,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-A 1`] = ` violet @@ -834,6 +862,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-B 1`] = ` red @@ -857,6 +886,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-B 1`] = ` orange @@ -881,6 +911,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-B 1`] = ` yellow @@ -904,6 +935,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-B 1`] = ` green @@ -940,6 +972,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-B 1`] = ` cyan @@ -976,6 +1009,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-B 1`] = ` blue @@ -999,6 +1033,7 @@ exports[`CheckboxGroup[Disabled] should render correctly by disabled-B 1`] = ` violet diff --git a/packages/shineout/src/collapse/__test__/__snapshots__/collapse.spec.tsx.snap b/packages/shineout/src/collapse/__test__/__snapshots__/collapse.spec.tsx.snap index db10e7811..71e4cd363 100644 --- a/packages/shineout/src/collapse/__test__/__snapshots__/collapse.spec.tsx.snap +++ b/packages/shineout/src/collapse/__test__/__snapshots__/collapse.spec.tsx.snap @@ -622,6 +622,7 @@ exports[`Collapse[Base] should render correctly about extra 1`] = ` checkbox diff --git a/packages/shineout/src/date-picker/__doc__/changelog.cn.md b/packages/shineout/src/date-picker/__doc__/changelog.cn.md index e874fec39..cd759f23b 100644 --- a/packages/shineout/src/date-picker/__doc__/changelog.cn.md +++ b/packages/shineout/src/date-picker/__doc__/changelog.cn.md @@ -1,3 +1,11 @@ +## 3.4.0 +2024-09-19 + +### 🆕 Feature +- `Datepicker` 新增needConfirm属性: 是否开启手动确认按钮,开启后只有点击确认按钮才会提交选择的值。 ([#650](https://github.com/sheinsight/shineout-next/pull/650)) +- `Datepicker` 新增clearToUndefined,点击清除后返回undefined ([#644](https://github.com/sheinsight/shineout-next/pull/644)) + + ## 3.3.7 2024-09-11 diff --git a/packages/shineout/src/date-picker/__example__/09-select-confirm.tsx b/packages/shineout/src/date-picker/__example__/09-select-confirm.tsx new file mode 100644 index 000000000..18ccb34fc --- /dev/null +++ b/packages/shineout/src/date-picker/__example__/09-select-confirm.tsx @@ -0,0 +1,46 @@ +/** + * cn - 确认选择 + * -- 设置`needConfirm`属性后开启手动确认按钮。默认会在选择值或者失去焦点时提交。 + * en - Select confirm + * -- Select confirm + */ +import React from 'react'; +import { Checkbox, DatePicker, Radio, TYPE } from 'shineout'; + +type DateType = TYPE.DatePicker.Props['type']; +const types: DateType[] = ['date', 'week', 'month', 'quarter', 'year', 'time', 'datetime']; + +const App: React.FC = () => { + const [dateValue, setDateValue] = React.useState(); + const [type, setType] = React.useState('date'); + const [isRange, setIsRange] = React.useState(true); + return ( +
    +
    + + 范围选择 +
    +
    + { + console.log('外部的onChange: ', v); + setDateValue(v); + }} + clearable + needConfirm + /> +
    + ); +}; +export default App; diff --git a/packages/shineout/src/date-picker/__test__/datePicker.spec.tsx b/packages/shineout/src/date-picker/__test__/datePicker.spec.tsx index 4d869ecb2..6bc1cd859 100644 --- a/packages/shineout/src/date-picker/__test__/datePicker.spec.tsx +++ b/packages/shineout/src/date-picker/__test__/datePicker.spec.tsx @@ -60,7 +60,7 @@ const originClasses = [ 'pickerHeaderRight', 'pickerHeaderMid', 'clear', - 'pickerFooterLeft', + 'pickerFooterTime', 'timePicker', 'timeList', 'timeItem', @@ -109,7 +109,7 @@ const { wrapperNoBorder, wrapperUnderline, clear, - pickerFooterLeft, + pickerFooterTime, timePicker, timeList, timeItem, @@ -342,21 +342,21 @@ describe('Alert[Base]', () => { const datePickerPickerWrapper = container.querySelector(pickerWrapper)!; const datePickerPickerFooter = datePickerPickerWrapper.querySelector(pickerFooter)!; expect(datePickerPickerFooter).toBeInTheDocument(); - classLengthTest(datePickerPickerFooter, 'button', 1); + classLengthTest(datePickerPickerFooter, 'a', 1); textContentTest(datePickerPickerFooter, 'Today'); fireEvent.focus(datePickerResultWrapper); fireEvent.click(datePickerResultWrapper); await waitFor(async () => { await delay(300); }); - fireEvent.click(datePickerPickerFooter.querySelector('button')!); + fireEvent.click(datePickerPickerFooter.querySelector('a')!); await waitFor(async () => { await delay(300); expect(datePickerResultWrapper.querySelector(result)?.textContent).not.toBe('Please select date'); }); rerender(); textContentTest( - container.querySelector(pickerFooter)?.querySelector('button') as Element, + container.querySelector(pickerFooter)?.querySelector('a') as Element, 'Current', ); }); @@ -630,9 +630,9 @@ describe('DatePicker[Type]', () => { textContentTest(datePickerResult, `${year}-${month}-${cell.textContent} 00:00:00`); expect(datePickerWrapper.querySelector(pickerFooter)).toBeInTheDocument(); }); - const datePickerFooterLeft = datePickerWrapper.querySelector(pickerFooterLeft)!; - const datePickerTimePicker = datePickerFooterLeft.querySelector(timePicker)!; - fireEvent.mouseDown(datePickerFooterLeft); + const datepickerFooterTime = datePickerWrapper.querySelector(pickerFooterTime)!; + const datePickerTimePicker = datepickerFooterTime.querySelector(timePicker)!; + fireEvent.mouseDown(datepickerFooterTime); await waitFor(async () => [await delay(300)]); classLengthTest(datePickerTimePicker, timeList, 3); classLengthTest(datePickerTimePicker.querySelectorAll(timeList)[0], timeItem, 24); diff --git a/packages/shineout/src/date-picker/date-picker.tsx b/packages/shineout/src/date-picker/date-picker.tsx index c87356895..83bb92e05 100644 --- a/packages/shineout/src/date-picker/date-picker.tsx +++ b/packages/shineout/src/date-picker/date-picker.tsx @@ -4,6 +4,7 @@ import { useDatePickerStyle, useInnerTitleStyle, usePopoverStyle, + useLinkStyle, } from '@sheinx/shineout-style'; import type { BaseDatePickerProps, DatePickerProps, DatePickerValueType } from './date-picker.type'; @@ -14,6 +15,7 @@ const jssStyle = { button: useButtonStyle, innerTitle: useInnerTitleStyle, popover: usePopoverStyle, + link: useLinkStyle, }; const BaseDatePicker = (props: BaseDatePickerProps) => { return ; diff --git a/packages/shineout/src/drawer/__test__/__snapshots__/drawer.spec.tsx.snap b/packages/shineout/src/drawer/__test__/__snapshots__/drawer.spec.tsx.snap index 4cbf2ee6b..e39e7daa3 100644 --- a/packages/shineout/src/drawer/__test__/__snapshots__/drawer.spec.tsx.snap +++ b/packages/shineout/src/drawer/__test__/__snapshots__/drawer.spec.tsx.snap @@ -573,6 +573,7 @@ exports[`Drawer[Base] should render correctly about full screen 1`] = ` chinese @@ -596,6 +597,7 @@ exports[`Drawer[Base] should render correctly about full screen 1`] = ` maths @@ -619,6 +621,7 @@ exports[`Drawer[Base] should render correctly about full screen 1`] = ` english @@ -642,6 +645,7 @@ exports[`Drawer[Base] should render correctly about full screen 1`] = ` physics diff --git a/packages/shineout/src/dropdown/__doc__/changelog.cn.md b/packages/shineout/src/dropdown/__doc__/changelog.cn.md index 14d0bf907..708913f03 100644 --- a/packages/shineout/src/dropdown/__doc__/changelog.cn.md +++ b/packages/shineout/src/dropdown/__doc__/changelog.cn.md @@ -1,3 +1,10 @@ +## 3.4.0 +2024-09-19 + +### 🆕 Feature + +- `Dropdown` 组件新增 `zIndex` 属性 ([#660](https://github.com/sheinsight/shineout-next/pull/660)) + ## 3.3.3 2024-08-15 diff --git a/packages/shineout/src/form/__example__/006-validate-01.tsx b/packages/shineout/src/form/__example__/006-validate-01.tsx index 7affef822..277fb7c96 100644 --- a/packages/shineout/src/form/__example__/006-validate-01.tsx +++ b/packages/shineout/src/form/__example__/006-validate-01.tsx @@ -6,7 +6,7 @@ */ import React, { useState, useCallback } from 'react'; -import { Form, Input, Checkbox, Rule, Button, TYPE } from 'shineout'; +import { Form, Input, Checkbox, Rule, Button, TYPE, DatePicker, Select } from 'shineout'; interface Value { age?: string; @@ -63,6 +63,7 @@ const App: React.FC = () => { } }, [ref]); + console.log('form value: >>', value) return (
    { /> + + + + + + Link; diff --git a/packages/shineout/src/link/__example__/02-type.tsx b/packages/shineout/src/link/__example__/02-type.tsx new file mode 100644 index 000000000..6f1861222 --- /dev/null +++ b/packages/shineout/src/link/__example__/02-type.tsx @@ -0,0 +1,20 @@ +/** +* cn - 链接状态 +* -- 设置`type`属性可以改变链接的状态,包括 primary, secondary, danger, warning, success。 +* en - Link type +* -- Set the `type` property to change the style of the link, including primary, secondary, danger, warning, success. + */ +import React from 'react'; +import { Gap, Link } from 'shineout'; + +export default () => { + return ( + + Link + Link + Link + Link + Link + + ); +}; diff --git a/packages/shineout/src/link/__example__/03-disabled.tsx b/packages/shineout/src/link/__example__/03-disabled.tsx new file mode 100644 index 000000000..c7745667b --- /dev/null +++ b/packages/shineout/src/link/__example__/03-disabled.tsx @@ -0,0 +1,20 @@ +/** +* cn - 禁用状态 +* -- 设置 `disabled` 属性可以禁用链接。 +* en - Disabled +* -- Set the disabled property to disable the link. + */ +import React from 'react'; +import { Gap, Link } from 'shineout'; + +export default () => { + return ( + + Link + Link + Link + Link + Link + + ); +}; diff --git a/packages/shineout/src/link/__example__/04-underline.tsx b/packages/shineout/src/link/__example__/04-underline.tsx new file mode 100644 index 000000000..197494bc2 --- /dev/null +++ b/packages/shineout/src/link/__example__/04-underline.tsx @@ -0,0 +1,52 @@ +/** +* cn - 链接样式 +* -- 链接样式包含三种,无下划线、常驻下划线、鼠标悬停显示下划线。 +* en - Link style +* -- Link style includes two types, text link and underline link. + */ +import React from 'react'; +import { Gap, Link } from 'shineout'; + +export default () => { + return ( +
    + + Link + Link + Link + + + {/*
    + + + Link + Link + Link + + +
    + + + Link + Link + Link + + +
    + + + Link + Link + Link + + +
    + + + Link + Link + Link + */} +
    + ); +}; diff --git a/packages/shineout/src/link/__example__/05-icon.tsx b/packages/shineout/src/link/__example__/05-icon.tsx new file mode 100644 index 000000000..267f1b814 --- /dev/null +++ b/packages/shineout/src/link/__example__/05-icon.tsx @@ -0,0 +1,32 @@ +/** +* cn - 图标 +* -- 通过 `Icon` 属性设置带图标的链接,设置为 true时候显示默认图标。 +* en - Icon +* -- Set the link with an icon by the Icon property. Set to true to display the default icon. + */ +import React from 'react'; +import { Gap, Link } from 'shineout'; + +const customIcon = ( + + + +) + +const customIcon2 = ( + + + + + +) + +export default () => { + return ( + + Link + + Link{customIcon2} + + ); +}; diff --git a/packages/shineout/src/link/__example__/06-size.tsx b/packages/shineout/src/link/__example__/06-size.tsx new file mode 100644 index 000000000..48b187fb9 --- /dev/null +++ b/packages/shineout/src/link/__example__/06-size.tsx @@ -0,0 +1,42 @@ +/** +* cn - 不同尺寸 +* -- 链接分为小、中、大,三种尺寸,推荐及默认为尺寸「中」,可在不同场景及不同业务需求选择适合尺寸。 +* en - Size +* -- Link has three sizes: small, default, and large. The default size is recommended. You can choose the appropriate size according to different scenarios and business needs. + */ +import React from 'react'; +import { Gap, Link } from 'shineout'; + +export default () => { + return ( +
    + + Link + Link + Link + Link + Link + + +
    + + + Link + Link + Link + Link + Link + + +
    + + + Link + Link + Link + Link + Link + +
    + ); +}; diff --git a/packages/shineout/src/link/index.ts b/packages/shineout/src/link/index.ts new file mode 100644 index 000000000..d57b96257 --- /dev/null +++ b/packages/shineout/src/link/index.ts @@ -0,0 +1,14 @@ +import Link from './link'; + + +type RefLink = typeof Link; + +export interface LinkComponent extends RefLink { + displayName: string; +} + +const LinkComp: LinkComponent = Link as LinkComponent; + +LinkComp.displayName = 'ShineoutLink'; + +export default LinkComp; diff --git a/packages/shineout/src/link/interface.ts b/packages/shineout/src/link/interface.ts new file mode 100644 index 000000000..61a8745ea --- /dev/null +++ b/packages/shineout/src/link/interface.ts @@ -0,0 +1 @@ +export type { LinkProps as Props } from './link.type'; diff --git a/packages/shineout/src/link/link.tsx b/packages/shineout/src/link/link.tsx new file mode 100644 index 000000000..f3e62b402 --- /dev/null +++ b/packages/shineout/src/link/link.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { Link } from '@sheinx/base'; +import { useLinkStyle } from '@sheinx/shineout-style'; +import { LinkProps } from './link.type'; + + +const jssStyle = { + link: useLinkStyle +} +export default (props: LinkProps) => { + return ( + + ); +} diff --git a/packages/shineout/src/link/link.type.ts b/packages/shineout/src/link/link.type.ts new file mode 100644 index 000000000..bcaf020de --- /dev/null +++ b/packages/shineout/src/link/link.type.ts @@ -0,0 +1,6 @@ +import { LinkProps as UnStyledLinkProps } from '@sheinx/base'; + +/** + * @title Link + */ +export type LinkProps = Omit; diff --git a/packages/shineout/src/menu/__doc__/changelog.cn.md b/packages/shineout/src/menu/__doc__/changelog.cn.md index f5fc1830d..f644163ef 100644 --- a/packages/shineout/src/menu/__doc__/changelog.cn.md +++ b/packages/shineout/src/menu/__doc__/changelog.cn.md @@ -1,3 +1,9 @@ +## 3.4.0 +2024-09-19 + +### 🆕 Feature +- `Menu` 组件新增父节点激活状态下的文字颜色 token ([#659](https://github.com/sheinsight/shineout-next/pull/659)) + ## 3.3.3 2024-08-07 diff --git a/packages/shineout/src/menu/menu.type.ts b/packages/shineout/src/menu/menu.type.ts index 8d6ec2284..bbfdfe7a1 100644 --- a/packages/shineout/src/menu/menu.type.ts +++ b/packages/shineout/src/menu/menu.type.ts @@ -2,7 +2,7 @@ import { MenuProps as UnStyledMenuProps } from '@sheinx/base'; import { KeygenResult } from '@sheinx/hooks'; /** - * @title menu + * @title Menu */ export type MenuProps = Omit< UnStyledMenuProps, diff --git a/packages/shineout/src/modal/__doc__/changelog.cn.md b/packages/shineout/src/modal/__doc__/changelog.cn.md index a373fe4b7..0568d14d6 100644 --- a/packages/shineout/src/modal/__doc__/changelog.cn.md +++ b/packages/shineout/src/modal/__doc__/changelog.cn.md @@ -1,4 +1,11 @@ -## 3.3.3 +## 3.4.0-beta.13 +2024-09-19 + +### 🐞 BugFix + +- 修复 `Modal` 方法调用方式时,点击确定或取消按钮没有关闭动画 ([#675](https://github.com/sheinsight/shineout-next/pull/675)) + + 2024-08-29 ### 🐞 BugFix diff --git a/packages/shineout/src/modal/__test__/modal.spec.tsx b/packages/shineout/src/modal/__test__/modal.spec.tsx index f36df53e5..f0a041991 100644 --- a/packages/shineout/src/modal/__test__/modal.spec.tsx +++ b/packages/shineout/src/modal/__test__/modal.spec.tsx @@ -656,7 +656,9 @@ describe('Modal[Confirm]', () => { fireEvent.click(container.querySelector('button')!); const modalWrapper = document.querySelector(wrapper)!; const tableButtons = modalWrapper.querySelectorAll('button'); - expect(tableButtons[1]).toHaveFocus(); + setTimeout(() => { + expect(tableButtons[1]).toHaveFocus(); + }, 300); }); }); describe('Modal[Function(Type)]', () => { diff --git a/packages/shineout/src/rate/__doc__/changelog.cn.md b/packages/shineout/src/rate/__doc__/changelog.cn.md new file mode 100644 index 000000000..2d3a97da9 --- /dev/null +++ b/packages/shineout/src/rate/__doc__/changelog.cn.md @@ -0,0 +1,10 @@ +## 3.4.0 +2024-09-19 + +### 🐞 BugFix +- 修复 `Rate` 组件在 Safari 浏览器下对齐样式异常的问题([#670](https://github.com/sheinsight/shineout-next/pull/670)) + + + + + diff --git a/packages/shineout/src/select/__doc__/changelog.cn.md b/packages/shineout/src/select/__doc__/changelog.cn.md index 97c048f3f..7c7550e94 100644 --- a/packages/shineout/src/select/__doc__/changelog.cn.md +++ b/packages/shineout/src/select/__doc__/changelog.cn.md @@ -1,13 +1,33 @@ +## 3.4.0 +2024-09-19 + +### 🆕 Feature +- `Select` 组件支持动态虚拟列表行高([#646](https://github.com/sheinsight/shineout-next/pull/646)) +- `Select` 组件新增 `onLoadMore` 属性,支持滚动加载 ([#610](https://github.com/sheinsight/shineout-next/pull/594)) +- `Select` 组件新增 `threshold` 属性,支持设置滚动加载阈值 ([#610](https://github.com/sheinsight/shineout-next/pull/594)) +- `Select` 组件新增 `trigger` 属性,支持更改展开下拉面板的触发方式 ([#610](https://github.com/sheinsight/shineout-next/pull/594)) + +### 💎 Enhancement +- 优化 `Select` 组件在同时使用 `emptyText` 和 `renderOptionList` 时的渲染顺序([#627](https://github.com/sheinsight/shineout-next/pull/627)) + ## 3.3.4 2024-08-21 ### 🆕 Feature - 支持 `Select` 的树形数据展开时,弹出层的位置自适应([#614](https://github.com/sheinsight/shineout-next/pull/614)) + ### 🐞 BugFix - 修复 `Select` 的树形数据展开时,设置的autoAdapt(下拉列表宽度根据内容自由展开)不生效的问题([#614](https://github.com/sheinsight/shineout-next/pull/614)) +## 3.3.3 +2024-08-15 + +### 🆕 Feature +- 支持 `Select` 单选搜索时,展示非string类型的值(renderItem返回的结果) ([#605](https://github.com/sheinsight/shineout-next/pull/605)) + + ## 3.3.3 2024-08-15 diff --git a/packages/shineout/src/select/__example__/01-01-base.tsx b/packages/shineout/src/select/__example__/01-01-base.tsx index cd79ad7dc..aa6491b7f 100644 --- a/packages/shineout/src/select/__example__/01-01-base.tsx +++ b/packages/shineout/src/select/__example__/01-01-base.tsx @@ -8,16 +8,16 @@ import React from 'react'; import { Select } from 'shineout'; import { primitiveData } from './static/mock'; +const data: number[] = []; + +for (let i = 0; i < 20; i++) { + data.push(i); +} + export default () => { return (
    -
    ); }; diff --git a/packages/shineout/src/select/__example__/04-bigdata.tsx b/packages/shineout/src/select/__example__/04-bigdata.tsx index df30589fb..37be375b6 100644 --- a/packages/shineout/src/select/__example__/04-bigdata.tsx +++ b/packages/shineout/src/select/__example__/04-bigdata.tsx @@ -1,7 +1,11 @@ /** - * cn - 大数据性能 + * cn - 虚拟列表 * -- 内置虚拟列表,支持大数据渲染,本例展示10万条数据 - * en - Big data + * -- 出于默认的性能考虑,每条选项的高度默认为统一高度值,可以通过调整 `lineHeight` 属性来调整每一条选项的固定高度 + * -- 如果需要根据内容自适应高度,通过设置 `lineHeight='auto'` 开启动态虚拟列表功能,组件将对渲染的条目预先测绘并动态计算高度 + * -- 开启`lineHeight='auto'`将不再限制选项换行行为 + * -- 注意,开启动态虚拟列表功能会带来额外的性能开销,请根据实际情况选择使用。此外,如果选项内容为动态的,例如选项中包含异步内容,出于性能考虑组件不自动处理尺寸的变化。 + * en - Virtual List * -- Select has built-in virtual list to support big data rendering, this example shows 100,000 pieces of data */ import React from 'react'; @@ -12,6 +16,7 @@ type SelectProps = TYPE.Select.Props; interface DataItem { id: string; name: string; + height: number; } const data: DataItem[] = []; @@ -20,22 +25,35 @@ for (let i = 0; i < 100000; i++) { data.push({ id: `id-${i}`, name: `标签 ${i}`, + height: Math.floor(Math.random() * 100) + 34, }); } -const renderItem: SelectProps['renderItem'] = (d) => d.name; - export default () => { + const renderItem: SelectProps['renderItem'] = (d) => d.name; + const renderDynamicHeightItem: SelectProps['renderItem'] = (d) => ( +
    {d.name}
    + ); return ( -
    +
    d.name} + placeholder='Auto lineHeight' + renderItem={renderDynamicHeightItem} + clearable + />
    ); }; diff --git a/packages/shineout/src/select/__example__/16-custom-render.tsx b/packages/shineout/src/select/__example__/16-custom-render.tsx index eda2a94a3..ae3f2abbf 100644 --- a/packages/shineout/src/select/__example__/16-custom-render.tsx +++ b/packages/shineout/src/select/__example__/16-custom-render.tsx @@ -2,7 +2,8 @@ * cn - 自定义列表布局 * -- 通过设置`header`属性可以自定义列表头部区域内容 * -- 通过设置`footer`属性可以自定义列表底部区域内容 - * -- `renderOptionList`可以自定义列表内容,并将列表实例抛出 + * -- 通过设置`renderOptionList`可以自定义列表内容,并将列表实例抛出 + * -- 注意,与`emptyText`属性搭配使用时,`emptyText`渲染优先级高于`renderOptionList`,可将`emptyText`设置为 false 忽略空内容渲染,如需渲染空内容,请在`renderOptionList`中自行处理 * en - Header * -- Set `header` to customize the content of the header area */ @@ -53,6 +54,7 @@ export default () => { /> -
    - ); -}; diff --git a/packages/shineout/src/select/__example__/19-loadmore.tsx b/packages/shineout/src/select/__example__/19-loadmore.tsx new file mode 100644 index 000000000..19965ecfb --- /dev/null +++ b/packages/shineout/src/select/__example__/19-loadmore.tsx @@ -0,0 +1,76 @@ +/** + * cn - 滚动加载 + * -- 通过配置`onLoadMore`方法,当下拉面板内容滚动至一定程度时,会触发该方法,实现滚动加载的效果 + * -- 通过配置`threshold`属性控制触发加载的阈值,默认为 1 即滚动至底部时触发加载,范围为 0 ~ 1 + * -- 注意,加载中样式及效果需自行设置,`onLoadMore`方法需自行设置触发频率,避免高频调用 + * en - Basic + * -- + */ +import React, { useState, useEffect } from 'react'; +import { Select, Spin } from 'shineout'; +import { user } from '@sheinx/mock'; + +interface ListItem { + id: number; + time: string; + start: string; + height: number; + salary: number; + office: string; + country: string; + office5: string; + position: string; + lastName: string; + firstName: string; +} + +export default () => { + const [current, setCurrent] = useState(1); + const [loading, setLoading] = useState(false); + const [data, setData] = useState([]); + + const fetchData = (c: number) => { + setLoading(true); + user.fetch + .get('List', { current: c, pageSize: 10, sorter: {}, username: '' }) + .then((_data: { data: ListItem[] }) => { + setData([...data, ..._data.data]); + setCurrent(c); + setLoading(false); + }); + }; + + const onLoadMore = async () => { + if (current >= 10) return; + // 避免高频调用 + if (loading) return; + await fetchData(current + 1); + }; + + useEffect(() => { + fetchData(1); + }, []); + + return ( +
    + +
    + ); +}; diff --git a/packages/shineout/src/select/__test__/__snapshots__/select.spec.tsx.snap b/packages/shineout/src/select/__test__/__snapshots__/select.spec.tsx.snap index 178293f40..966e74f65 100644 --- a/packages/shineout/src/select/__test__/__snapshots__/select.spec.tsx.snap +++ b/packages/shineout/src/select/__test__/__snapshots__/select.spec.tsx.snap @@ -194,7 +194,53 @@ exports[`Select[Base] should render correctly about autoAdapt 1`] = ` `; exports[`Select[Base] should render correctly about big data 1`] = ` -
    +
    +
    +
    +
    +
    + + + Static lineHeight + + +
    +
    +
    + + + +
    +
    +
    - Select Tag + Auto lineHeight
    diff --git a/packages/shineout/src/table/__doc__/changelog.cn.md b/packages/shineout/src/table/__doc__/changelog.cn.md index 047282d4a..c76952a60 100644 --- a/packages/shineout/src/table/__doc__/changelog.cn.md +++ b/packages/shineout/src/table/__doc__/changelog.cn.md @@ -1,16 +1,26 @@ +## 3.4.0 +2024-09-19 + +### 🐞 BugFix + +- 修复TableRef的`scrollToIndex`的回调方法不生效问题 ([#651](https://github.com/sheinsight/shineout-next/pull/651)) + +### 🆕 Feature + +- `Table` 组件新增属性 `showTopScrollbar`,开启顶部滚动条 ([#671](https://github.com/sheinsight/shineout-next/pull/671)) +- `Table` 组件 `onScroll` 事件新增 top 参数 ([#658](https://github.com/sheinsight/shineout-next/pull/658)) +- `Table` 组件 `Ref` 支持 `getRenderIndexByData` 方法,用于获取指定数据在渲染列表中的索引 + ## 3.3.7 2024-09-14 ### 🐞 BugFix - 修复`Table` 在`Tabs`组件中切换时的滚动条抖动一下的问题 ([#667](https://github.com/sheinsight/shineout-next/pull/667)) - -## 3.3.6 -2024-08-30 - ### 🐞 BugFix - 修复`Table` 虚拟滚动时,默认的rowsInView渲染结果不够撑满一屏导致的滚动空白问题 ([#628](https://github.com/sheinsight/shineout-next/pull/628)) - 修复`Table` 虚拟滚动的内部元素被执行scrollIntoView导致的页面偏移的问题 ([#624](https://github.com/sheinsight/shineout-next/pull/624)) + ## 3.3.3 2024-08-15 @@ -36,7 +46,6 @@ - `Table` 新增属性 `onCellClick` 支持单元格点击后的回调 ([#550](https://github.com/sheinsight/shineout-next/pull/550)) - ## 3.2.6 2024-07-05 diff --git a/packages/shineout/src/table/__example__/06-double-scrollbar.tsx b/packages/shineout/src/table/__example__/06-double-scrollbar.tsx new file mode 100644 index 000000000..65841b9de --- /dev/null +++ b/packages/shineout/src/table/__example__/06-double-scrollbar.tsx @@ -0,0 +1,60 @@ +/** + * cn - 顶部滚动 + * -- 设置`showTopScrollbar`开启顶部滚动条 + * en - Double scrollbar + * -- Set `showTopScrollbar` to enable double scrollbar + */ +import React from 'react'; +import { Table, TYPE } from 'shineout'; +import { user } from '@sheinx/mock'; + +interface TableRowData { + id: number; + time: string; + start: string; + height: number; + salary: number; + office: string; + country: string; + office5: string; + position: string; + lastName: string; + firstName: string; +} +type TableColumnItem = TYPE.Table.ColumnItem; + +const data: TableRowData[] = user.fetchSync(20); + +const columns: TableColumnItem[] = [ + { title: 'id', render: 'id', width: 50 }, + { + title: 'First Name', + group: 'Name', + render: 'firstName', + width: 120, + }, + { + title: 'Last Name', + fixed: 'left', + group: 'Name', + render: 'lastName', + width: 120, + }, + { title: 'Country', render: 'country' }, + { title: 'Position', render: 'position' }, + { title: 'Office', render: 'office' }, + { title: 'Start Date', render: 'start' }, + { + title: 'Salary($)', + fixed: 'right', + align: 'right', + width: 100, + render: (d) => `${d.salary.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,')}`, + }, +]; + +const App: React.FC = () => ( + +); + +export default App; diff --git a/packages/shineout/src/table/__example__/07-02-virtual-scroll.tsx b/packages/shineout/src/table/__example__/07-02-virtual-scroll.tsx index 05a41d642..87b4c9fb3 100644 --- a/packages/shineout/src/table/__example__/07-02-virtual-scroll.tsx +++ b/packages/shineout/src/table/__example__/07-02-virtual-scroll.tsx @@ -1,6 +1,6 @@ /** * cn - 虚拟滚动 - * -- 虚拟列表提供了一个 scrollToIndex 方法滚动到指定行 + * -- 虚拟列表提供了一个`scrollToIndex`方法滚动到指定行 * en - scrollToIndex * -- The virtual list table provides a scrollToIndex method to scroll to the specified row */ diff --git a/packages/shineout/src/table/__example__/07-02-virtual-scroll2.tsx b/packages/shineout/src/table/__example__/07-02-virtual-scroll2.tsx new file mode 100644 index 000000000..8f73b1894 --- /dev/null +++ b/packages/shineout/src/table/__example__/07-02-virtual-scroll2.tsx @@ -0,0 +1,113 @@ +/** + * cn - + * -- 虚拟列表提供了`getRenderIndexByData`方法获取数据实际的index,然后再调用`scrollToIndex`方法滚动到指定行 + * en - scrollToIndex + * -- The virtual list table provides a getRenderIndexByData method to get the actual index of the data, and then call the `scrollToIndex` method to scroll to the specified row + */ +import React, { useState, useEffect } from 'react'; +import { Input, Table, Form, TYPE, Button } from 'shineout'; + +interface TableRowData { + id: string; + office: string; + country: string; + position: string; + children?: TableRowData[]; +} + +type TableColumnItem = TYPE.Table.ColumnItem; + + +let defaultTreeExpandKeys:string[] = [] +function generateMockTreeData(depth: number, count: number, parentId?: string): TableRowData[] { + const data: TableRowData[] = []; + for (let i = 0; i < count; i++) { + const currentId = parentId ? `${parentId}__${depth}_${i}` : `${depth}_${i}` + const children = depth > 1 ? generateMockTreeData(depth - 1, count, currentId) : undefined; + defaultTreeExpandKeys.push(currentId) + data.push({ + id: currentId, + position: `position_${i}`, + country: `country_${i}`, + office: `office_${i}`, + children, + }); + } + return data; +} + +const mockData = generateMockTreeData(4, 20); + +const columns: TableColumnItem[] = [ + { + title: 'ID', + render: (d) => ( + + {d.id} + + ), + width: 300, + treeIndent: 22, + treeColumnsName: 'children', + }, + { title: 'Country', render: 'country' }, + { title: 'Position', render: 'position' }, + { title: 'Office', render: 'office' }, +]; + +const App: React.FC = () => { + const [tableRef, setTableRef] = useState(); + + const [state, setState] = useState({ + id: '4_0__3_0__2_5__1_0', + }); + + const handleScroll = () => { + if (tableRef){ + const index = tableRef.getRenderIndexByData({id: state.id}); + // 或者这样使用也可以: + // const index = tableRef.getRenderIndexByData(state.id) + if(index === -1) return; + tableRef.scrollToIndex(index, () => { + const el: HTMLElement = document.querySelector(`#name_${state.id}`)!; + if (el) { + el.style.color = 'red'; + } + }); + } + }; + + const handleIndexChange = ({ id }: { id: string }) => { + setState({ id }); + }; + + useEffect(() => { + setTimeout(handleScroll); + }, [state]); + + return ( +
    + + + + + +
    setTableRef(t)} + defaultTreeExpandKeys={defaultTreeExpandKeys} + /> + + ); +}; + +export default App; diff --git a/packages/shineout/src/table/__example__/test-006-table-scroll-y.tsx b/packages/shineout/src/table/__example__/test-006-table-scroll-y.tsx index 98590fb31..885a0ccd2 100644 --- a/packages/shineout/src/table/__example__/test-006-table-scroll-y.tsx +++ b/packages/shineout/src/table/__example__/test-006-table-scroll-y.tsx @@ -3913,7 +3913,7 @@ const columns = [{ const App: React.FC = () => ( <>
    @@ -3926,9 +3926,10 @@ const App: React.FC = () => ( bordered columnResizable verticalAlign="middle" - virtual + // showTopScrollbar + // virtual // rowsInView={0} - // sticky={{ top: 0, css: true }} + sticky={{ top: 0, css: true }} defaultTreeExpandKeys={flattenArray(data).map((d) => d.uuid)} /> {/*

    占位内容……

    diff --git a/packages/shineout/src/table/__example__/test-007-table-tabs.tsx b/packages/shineout/src/table/__example__/test-007-table-tabs.tsx index 13b8bc6c2..32ba24edf 100644 --- a/packages/shineout/src/table/__example__/test-007-table-tabs.tsx +++ b/packages/shineout/src/table/__example__/test-007-table-tabs.tsx @@ -23,7 +23,7 @@ interface TableRowData { } type TableColumnItem = TYPE.Table.ColumnItem; -const data: TableRowData[] = user.fetchSync(20); +const data: TableRowData[] = user.fetchSync(1000); const columns: TableColumnItem[] = [ { title: 'id', render: 'id', width: 50 }, @@ -46,7 +46,7 @@ const columns: TableColumnItem[] = [ { title: 'Start Date', render: 'start' }, { title: 'Salary($)', - fixed: 'right', + // fixed: 'right', align: 'right', width: 100, render: (d) => `${d.salary.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,')}`, @@ -77,15 +77,30 @@ const App: React.FC = () => {

    Tab1

    -
    +
    + + +