diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 40272f8e43..7344d508ec 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -38,6 +38,7 @@ jobs: run: | git config --global user.name 'semi-bot' git config --global user.email 'semi-bot@users.noreply.github.com' + node scripts/sitemap_update.js if [ -n "$(git status --porcelain)" ]; then echo "there are changes"; git add . diff --git a/content/input/slider/index-en-US.md b/content/input/slider/index-en-US.md index db2e19fe42..3c98d6cdce 100644 --- a/content/input/slider/index-en-US.md +++ b/content/input/slider/index-en-US.md @@ -241,17 +241,17 @@ import { Slider } from '@douyinfe/semi-ui'; ## API Reference | Property | Instructions | type | Default | Version | -| -------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------- | ------- |------ | -| aria-label| [aria-label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label) used to define a string that labels the current element. Use it in cases where a text label is not visible on the screen | string |-|-| -| aria-labelledby | [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby) attribute establishes relationships between objects and their label(s), and its value should be one or more element IDs, which refer to elements that have the text needed for labeling | string |-|-| -| aria-valuetext| [aria-valuetext](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-valuetext) used to provide a user-friendly name for the current value of the slider | string |-|-| +| -------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------- |---------|------ | +| aria-label| [aria-label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label) used to define a string that labels the current element. Use it in cases where a text label is not visible on the screen | string | - |-| +| aria-labelledby | [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby) attribute establishes relationships between objects and their label(s), and its value should be one or more element IDs, which refer to elements that have the text needed for labeling | string | - |-| +| aria-valuetext| [aria-valuetext](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-valuetext) used to provide a user-friendly name for the current value of the slider | string | - |-| | defaultValue | Default value | number \| number[] | 0 |- | | disabled | Disable slider | boolean | false |- | | included | Takes effect when `marks` is not null, true means containment and false means coordination | boolean | true |- | | marks | Tick mark of Slider, type of key must be number, and must in closed interval [min, max] | Record | - |- | | max | Maximum value of the slider. | number | 100 |- | | min | Minimum value of the slider. | number | 0 |- | -| railStyle | Style for slide rail | CSSProperties | - |0.31.0| +| railStyle | Style for slide rail | CSSProperties | - |0.31.0| | range | Toggle whether it is allow to move slider from both sides | boolean | false |- | | showBoundary | Toggle whether show max/min value when hover | boolean | false |- | | step | Increment between successive values | number | 1 |- | @@ -259,10 +259,11 @@ import { Slider } from '@douyinfe/semi-ui'; | tooltipVisible | Toggle whether to display tooltip all the time | boolean | - |- | | value | Set current value, used in controlled component | number \| number[] | |- | | vertical | Toggle whether to display slider vertically | boolean | false |- | -| verticalReverse | Vertical but reverse direction >=1.29.0 | boolean | false |-| +| verticalReverse | Vertical but reverse direction >=1.29.0 | boolean | false |-| | onAfterChange | Triggered when slider changed, passed in current value as params | (value: number \| number[]) => void | - |- | | onChange | Callback function when slider value changes | (value: number \| number[]) => void | - |- | -| getAriaValueText | Used to provide a user-friendly name for the current value of the slider, important for screen reader users, The parameters value and index are the current slider value, order | (value: number, index?: number) => string |-|-| +| onMouseUp | Trigged when mouse up on handle | (e: React.MouseEvent) => void | - | 2.41.0 | +| getAriaValueText | Used to provide a user-friendly name for the current value of the slider, important for screen reader users, The parameters value and index are the current slider value, order | (value: number, index?: number) => string | - |-| ## Accessibility ### ARIA diff --git a/content/input/slider/index.md b/content/input/slider/index.md index 543dd76a3f..0fc71df58c 100644 --- a/content/input/slider/index.md +++ b/content/input/slider/index.md @@ -227,29 +227,30 @@ import { Slider } from '@douyinfe/semi-ui'; ``` ## API参考 -| 属性 | 说明 | 类型 | 默认值 | 版本 | -|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|--------|-------| -| aria-label| [aria-label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label)属性,用来给当前元素加上的标签描述, 提升可访问性 | string |-|-| -| aria-labelledby | [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby)属性,表明某些元素的 id 是某一对象的标签。它被用来确定控件或控件组与它们标签之间的联系, 提升可访问性 | string |-|-| -| aria-valuetext| [aria-valuetext](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-valuetext)属性,为滑块的当前值提供用户友好的名称。 | string |-|-| -| defaultValue | 设置初始取值 | number \| number[] | 0 |-| -| disabled | 滑块是否禁用 | boolean | false |-| -| included | `marks` 不为空对象时有效,值为 true 时表示值为包含关系,false 表示并列 | boolean | true |-| -| marks | 刻度,key 的类型必须为 `number` 且取值在闭区间 \[min, max] 内 | Record | 无 |-| -| max | 最大值 | number | 100 |-| -| min | 最小值 | number | 0 |-| -| railStyle | 滑块轨道的样式 | CSSProperties | - |0.31.0| -| range | 是否支持两边同时可滑动 | boolean | false |-| -| showBoundary | 是否在 hover 时展示最大值最小值 | boolean | false |-| -| step | 步长 | number | 1 |-| -| tipFormatter | 设置Tooltip的展示格式,默认显示当前选值 | (value: string \| number \| boolean \| (string \| number \| boolean)[]) => any | v => v |-| -| tooltipVisible | 是否始终显示Tooltip | boolean | 无 |-| -| value | 设置当前取值 | number \| number[] | |-| -| vertical | 是否设置方向为垂直 | boolean | false |-| -| verticalReverse | 反转垂直方向,即上大下小 >=1.29.0 | boolean | false |-| -| onAfterChange | 值变化后触发,把当前值作为参数传入 | (value: number \| number[]) => void | 无 |-| -| onChange | 当 Slider 的值发生改变时的回调 | (value: number \| number[]) => void | 无 |-| -| getAriaValueText | 用于给滑块的当前值提供一个用户友好的名称,对屏幕阅读器用户很重要,参数value为当前滑块的值,index为当前滑块的顺序 | (value: number, index?: number) => string |-|-| +| 属性 | 说明 | 类型 | 默认值 | 版本 | +|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|--------|--------| +| aria-label| [aria-label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label)属性,用来给当前元素加上的标签描述, 提升可访问性 | string |-| - | +| aria-labelledby | [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby)属性,表明某些元素的 id 是某一对象的标签。它被用来确定控件或控件组与它们标签之间的联系, 提升可访问性 | string |-| - | +| aria-valuetext| [aria-valuetext](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-valuetext)属性,为滑块的当前值提供用户友好的名称。 | string |-| - | +| defaultValue | 设置初始取值 | number \| number[] | 0 | - | +| disabled | 滑块是否禁用 | boolean | false | - | +| included | `marks` 不为空对象时有效,值为 true 时表示值为包含关系,false 表示并列 | boolean | true | - | +| marks | 刻度,key 的类型必须为 `number` 且取值在闭区间 \[min, max] 内 | Record | 无 | - | +| max | 最大值 | number | 100 | - | +| min | 最小值 | number | 0 | - | +| railStyle | 滑块轨道的样式 | CSSProperties | - | 0.31.0 | +| range | 是否支持两边同时可滑动 | boolean | false | - | +| showBoundary | 是否在 hover 时展示最大值最小值 | boolean | false | - | +| step | 步长 | number | 1 | - | +| tipFormatter | 设置Tooltip的展示格式,默认显示当前选值 | (value: string \| number \| boolean \| (string \| number \| boolean)[]) => any | v => v | - | +| tooltipVisible | 是否始终显示Tooltip | boolean | 无 | - | +| value | 设置当前取值 | number \| number[] | | - | +| vertical | 是否设置方向为垂直 | boolean | false | - | +| verticalReverse | 反转垂直方向,即上大下小 >=1.29.0 | boolean | false | - | +| onAfterChange | 值变化后触发,把当前值作为参数传入 | (value: number \| number[]) => void | 无 | - | +| onChange | 当 Slider 的值发生改变时的回调 | (value: number \| number[]) => void | 无 | - | +| onMouseUp | 鼠标松开滑块时触发 | (e: React.MouseEvent) => void | 无 | 2.41.0 | +| getAriaValueText | 用于给滑块的当前值提供一个用户友好的名称,对屏幕阅读器用户很重要,参数value为当前滑块的值,index为当前滑块的顺序 | (value: number, index?: number) => string |-| - | ## Accessibility diff --git a/content/input/transfer/index-en-US.md b/content/input/transfer/index-en-US.md index 176f626b72..87ee398c85 100644 --- a/content/input/transfer/index-en-US.md +++ b/content/input/transfer/index-en-US.md @@ -710,8 +710,15 @@ class CustomRenderDemo extends React.Component { ### Fully custom rendering, drag and drop sorting In a completely custom rendering scene, since the rendering of the drag area has also been completely taken over by you, you do not need to declare draggable. -But you need to implement the drag and drop logic yourself, we recommend using `react-sortable-hoc` directly -To support drag sorting, you need to call onSortEnd with oldIndex and newIndex as the input parameters after the drag sorting is over +But you need to implement the drag and drop logic yourself, You can use the drag-and-drop tool library [dnd-kit](https://github.com/clauderic/dnd-kit) or [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc), quickly realize the function. Regarding the selection of the two, here are some of our suggestions. + +- Both are maintained by the same author, dnd-kit is the successor of react-sortable-hoc +- The API design of react-sortable-hoc is more cohesive, and the code is more concise in simple scenarios. But it strongly relies on the findDOMNode API, which will be deprecated in future React versions. At the same time, the library has not been maintained for the past two years. +- Relatively speaking, dnd-kit has a certain threshold for getting started, but it has a higher degree of freedom, stronger scalability, and is still under maintenance. we recommend it. + +Besides, To support drag sorting, you need to call onSortEnd with oldIndex and newIndex as the input parameters after the drag sorting is over + +Example using react-sortable-hoc: ```jsx live=true dir="column" import React from 'react'; @@ -874,6 +881,280 @@ class CustomRenderDragDemo extends React.Component { } ``` +Example using dnd-kit,The core dependencies that need to be used are @dnd-kit/sortable, @dnd-kit/core. The core hooks are useSortable, and the usage instructions of useSortable are as follows + +``` +1. Function: Obtain the necessary information during the drag and drop process through the unique id +2. Core input parameters: + - id: unique identifier, which can be a number or a string, but cannot be a number 0 +3. Core return value description: + - setNodeRef: Associate the dom node to make it a draggable item + - listeners: Contains onKeyDown, onPointerDown and other methods, mainly to allow nodes to be dragged + - transform: the movement change value when the node is dragged + - transition: transition effect + - active: information about the dragged node, including id +``` + +```jsx live=true dir="column" noInline=true +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Transfer, Input, Spin, Button } from '@douyinfe/semi-ui'; +import { IconSearch, IconHandle } from '@douyinfe/semi-icons'; +import { useSortable, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from '@dnd-kit/sortable'; +import { CSS as cssDndKit } from '@dnd-kit/utilities'; +import { closestCenter, DragOverlay, DndContext, MouseSensor, TouchSensor, useSensor, useSensors, KeyboardSensor, TraversalOrder } from '@dnd-kit/core'; + +function SortableList({ + items, + onSortEnd, + renderItem, +}) { + const [activeId, setActiveId] = useState(null); + // sensors determine which external input is affected by the drag operation (such as mouse, keyboard, touchpad) + const sensors = useSensors( + useSensor(MouseSensor), + useSensor(TouchSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + const getIndex = useCallback((id) => items.indexOf(id), [items]); + const activeIndex = useMemo(() => activeId ? getIndex(activeId) : -1, [getIndex, activeId]); + + const onDragStart = useCallback(({ active }) => { + if (!active) { return; } + setActiveId(active.id); + }, []); + + // Drag end callback + const onDragEnd = useCallback(({ over }) => { + setActiveId(null); + if (over) { + const overIndex = getIndex(over.id); + if (activeIndex !== overIndex) { + onSortEnd({ oldIndex: activeIndex, newIndex: overIndex }); + } + } + }, [activeIndex, getIndex, onSortEnd]); + + const onDragCancel = useCallback(() => { + setActiveId(null); + }, []); + + return ( + + +
+ {items.map((value, index) => ( + + ))} +
+ {ReactDOM.createPortal( + + {activeId ? ( + renderItem({ + id: activeId, + sortableHandle: (WrapperComponent) => WrapperComponent + }) + ) : null} + , + document.body + )} +
+
+ ); +} + +function SortableItem({ id, renderItem }) { + const { + listeners, + setNodeRef, + transform, + transition, + active, + } = useSortable({ + id, + }); + + const sortableHandle = useCallback((WrapperComponent) => { + return () => ; + }, [listeners]); + + const wrapperStyle = { + transform: cssDndKit.Transform.toString({ + ...transform, + scaleX: 1, + scaleY: 1, + }), + transition: transition, + opacity: active && active.id === id ? 0 : undefined, + }; + + return
+ {renderItem({ id, sortableHandle })} +
; +} + +class CustomRenderDragDemo extends React.Component { + constructor(props) { + super(props); + this.state = { + dataSource: Array.from({ length: 100 }, (v, i) => ({ + label: `Hdl Store ${i}`, + value: i, + disabled: false, + key: `key-${i}`, + })), + }; + this.renderSourcePanel = this.renderSourcePanel.bind(this); + this.renderSelectedPanel = this.renderSelectedPanel.bind(this); + this.renderItem = this.renderItem.bind(this); + } + + renderItem(type, item, onItemAction, selectedItems, sortableHandle) { + let buttonText = 'delete'; + + if (type === 'source') { + let checked = selectedItems.has(item.key); + buttonText = checked ? 'delete' : 'add'; + } + + const DragHandle = (sortableHandle && sortableHandle(() => )); + + return ( +
+ {type === 'source' ? null : ( DragHandle ? : null) } +
+

{item.label}

+ +
+
+ ); + } + + renderSourcePanel(props) { + const { + loading, + noMatch, + filterData, + selectedItems, + allChecked, + onAllClick, + inputValue, + onSearch, + onSelectOrRemove, + } = props; + let content; + switch (true) { + case loading: + content = ; + break; + case noMatch: + content =
{inputValue ? 'No search results' : 'No content yet'}
; + break; + case !noMatch: + content = filterData.map(item => this.renderItem('source', item, onSelectOrRemove, selectedItems)); + break; + default: + content = null; + break; + } + return ( +
+
Store list
+
+ } + onChange={onSearch} + showClear + /> +
+ Store to be selected: {filterData.length} + +
+
{content}
+
+
+ ); + } + + renderSelectedPanel(props) { + const { selectedData, onClear, clearText, onRemove, onSortEnd } = props; + let mainContent = null; + + if (!selectedData.length) { + mainContent =
No data, please filter from the left
; + } + + const renderSelectItem = ({ id, sortableHandle }) => { + const item = selectedData.find(item => id === item.key); + return this.renderItem('selected', item, onRemove, null, sortableHandle); + }; + + const sortData = selectedData.map(item => item.key); + + mainContent =
+ +
; + + return ( +
+
+
Selected: {selectedData.length}
+ +
+ {mainContent} +
+ ); + } + + render() { + const { dataSource } = this.state; + return ( + console.log(values)} + className="component-transfer-demo-custom-panel" + renderSourcePanel={this.renderSourcePanel} + renderSelectedPanel={this.renderSelectedPanel} + dataSource={dataSource} + /> + ); + } +} + +render(CustomRenderDragDemo); +``` + ### Tree Transfer The input type is `treeList`, and the [`Tree`](/en-US/navigation/tree) component is used as a custom rendering list. **v1.20.0 available** diff --git a/content/input/transfer/index.md b/content/input/transfer/index.md index 60268fb8b2..4f7b5182ae 100644 --- a/content/input/transfer/index.md +++ b/content/input/transfer/index.md @@ -711,9 +711,18 @@ class CustomRenderDemo extends React.Component { ### 完全自定义渲染 、 拖拽排序 -在完全自定义渲染的场景下,由于拖拽区的渲染也已由你完全接管,因此你不声明 draggable 亦可。 -但你需要自行实现拖拽逻辑,我们推荐直接使用`react-sortable-hoc` -要支持拖拽排序,你需要在拖拽排序结束后,将 oldIndex、newIndex 作为入参,调用 onSortEnd +在完全自定义渲染的场景下,由于拖拽区的渲染也已由你完全接管,因此你不声明 draggable 亦可。 +但你需要自行实现拖拽逻辑,你可以借助社区中拖拽类工具库 [dnd-kit](https://github.com/clauderic/dnd-kit) 或者 [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc),快速实现功能。关于两者选型,这是我们的一些建议 + +- 两者均由同一作者维护, dnd-kit 是 react-sortable-hoc 的接任产品 +- react-sortable-hoc 的 API 设计更加高内聚,在简单场景上代码更加简洁。但它强依赖了 findDOMNode API,在未来的 React 版本中会被废弃。同时该库最近两年已经处于不维护的状态。 +- dnd-kit 相对而言,有一定上手门槛,但它的自由度更高,扩展性更强,并且仍处于维护状态。我们更推荐使用 + +更多 DIff 信息可查阅 [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc) 的 Github 主页 + +另外,要支持拖拽排序,你需要在拖拽排序结束后,将 oldIndex、newIndex 作为入参,调用 onSortEnd + +使用 react-sortable-hoc 的示例: ```jsx live=true dir="column" import React from 'react'; @@ -876,6 +885,280 @@ class CustomRenderDragDemo extends React.Component { } ``` +使用 dnd-kit 的示例如下,需要用到的核心依赖有 @dnd-kit/sortable, @dnd-kit/core,其中核心 hooks 为 useSortable,使用说明如下 + +``` +1. 作用:通过唯一标志 id 获取拖拽过程中必要信息 +2. 核心输入参数: + - id: 唯一标识, 以为数字或者字符串,但是不能为数字 0 +3. 核心返回值说明: + - setNodeRef: 关联 dom 节点,使其成为一个可拖拽的项 + - listeners: 包含 onKeyDown,onPointerDown 等方法,主要让节点可以进行拖拽 + - transform:该节点被拖动时候的移动变化值 + - transition:过渡效果 + - active: 被拖拽节点的相关信息,包括 id +``` + +```jsx live=true dir="column" noInline=true +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Transfer, Input, Spin, Button } from '@douyinfe/semi-ui'; +import { IconSearch, IconHandle } from '@douyinfe/semi-icons'; +import { useSortable, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from '@dnd-kit/sortable'; +import { CSS as cssDndKit } from '@dnd-kit/utilities'; +import { closestCenter, DragOverlay, DndContext, MouseSensor, TouchSensor, useSensor, useSensors, KeyboardSensor, TraversalOrder } from '@dnd-kit/core'; + +function SortableList({ + items, + onSortEnd, + renderItem, +}) { + const [activeId, setActiveId] = useState(null); + // sensors 确定拖拽操作受哪些外部输入影响(如鼠标,键盘,触摸板) + const sensors = useSensors( + useSensor(MouseSensor), + useSensor(TouchSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + const getIndex = useCallback((id) => items.indexOf(id), [items]); + const activeIndex = useMemo(() => activeId ? getIndex(activeId) : -1, [getIndex, activeId]); + + const onDragStart = useCallback(({ active }) => { + if (!active) { return; } + setActiveId(active.id); + }, []); + + // 拖拽结束回调 + const onDragEnd = useCallback(({ over }) => { + setActiveId(null); + if (over) { + const overIndex = getIndex(over.id); + if (activeIndex !== overIndex) { + onSortEnd({ oldIndex: activeIndex, newIndex: overIndex }); + } + } + }, [activeIndex, getIndex, onSortEnd]); + + const onDragCancel = useCallback(() => { + setActiveId(null); + }, []); + + return ( + + +
+ {items.map((value, index) => ( + + ))} +
+ {ReactDOM.createPortal( + + {activeId ? ( + renderItem({ + id: activeId, + sortableHandle: (WrapperComponent) => WrapperComponent + }) + ) : null} + , + document.body + )} +
+
+ ); +} + +function SortableItem({ id, renderItem }) { + const { + listeners, + setNodeRef, + transform, + transition, + active, + } = useSortable({ + id, + }); + + const sortableHandle = useCallback((WrapperComponent) => { + return () => ; + }, [listeners]); + + const wrapperStyle = { + transform: cssDndKit.Transform.toString({ + ...transform, + scaleX: 1, + scaleY: 1, + }), + transition: transition, + opacity: active && active.id === id ? 0 : undefined, + }; + + return
+ {renderItem({ id, sortableHandle })} +
; +} + +class CustomRenderDragDemo extends React.Component { + constructor(props) { + super(props); + this.state = { + dataSource: Array.from({ length: 100 }, (v, i) => ({ + label: `海底捞门店 ${i}`, + value: i, + disabled: false, + key: `key-${i}`, + })), + }; + this.renderSourcePanel = this.renderSourcePanel.bind(this); + this.renderSelectedPanel = this.renderSelectedPanel.bind(this); + this.renderItem = this.renderItem.bind(this); + } + + renderItem(type, item, onItemAction, selectedItems, sortableHandle) { + let buttonText = '删除'; + + if (type === 'source') { + let checked = selectedItems.has(item.key); + buttonText = checked ? '删除' : '添加'; + } + + const DragHandle = (sortableHandle && sortableHandle(() => )); + + return ( +
+ {type === 'source' ? null : ( DragHandle ? : null) } +
+

{item.label}

+ +
+
+ ); + } + + renderSourcePanel(props) { + const { + loading, + noMatch, + filterData, + selectedItems, + allChecked, + onAllClick, + inputValue, + onSearch, + onSelectOrRemove, + } = props; + let content; + switch (true) { + case loading: + content = ; + break; + case noMatch: + content =
{inputValue ? '无搜索结果' : '暂无内容'}
; + break; + case !noMatch: + content = filterData.map(item => this.renderItem('source', item, onSelectOrRemove, selectedItems)); + break; + default: + content = null; + break; + } + return ( +
+
门店列表
+
+ } + onChange={onSearch} + showClear + /> +
+ 待选门店: {filterData.length} + +
+
{content}
+
+
+ ); + } + + renderSelectedPanel(props) { + const { selectedData, onClear, clearText, onRemove, onSortEnd } = props; + let mainContent = null; + + if (!selectedData.length) { + mainContent =
暂无数据,请从左侧筛选
; + } + + const renderSelectItem = ({ id, sortableHandle }) => { + const item = selectedData.find(item => id === item.key); + return this.renderItem('selected', item, onRemove, null, sortableHandle); + }; + + const sortData = selectedData.map(item => item.key); + + mainContent =
+ +
; + + return ( +
+
+
已选同步门店: {selectedData.length}
+ +
+ {mainContent} +
+ ); + } + + render() { + const { dataSource } = this.state; + return ( + console.log(values)} + className="component-transfer-demo-custom-panel" + renderSourcePanel={this.renderSourcePanel} + renderSelectedPanel={this.renderSelectedPanel} + dataSource={dataSource} + /> + ); + } +} + +render(CustomRenderDragDemo); +``` + ### 树穿梭框 传入 type 为`treeList`,使用[`Tree`](/zh-CN/navigation/tree)组件作为自定义渲染列表。**v1.20.0 提供** diff --git a/content/show/list/index-en-US.md b/content/show/list/index-en-US.md index c20281ff5f..3de0edb4af 100644 --- a/content/show/list/index-en-US.md +++ b/content/show/list/index-en-US.md @@ -916,84 +916,6 @@ class DraggableList extends React.Component { render(DraggableList); ``` - -If you use [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc), here is also an example - -```jsx live=true dir="column" hideInDSM -import React, { useState } from 'react'; -import { List } from '@douyinfe/semi-ui'; -import { IconHandle } from '@douyinfe/semi-icons'; -import { SortableContainer, SortableElement, sortableHandle } from 'react-sortable-hoc'; - -() => { - const data = [ - 'Siege', - 'The ordinary world', - 'Three Body', - 'Snow in the Snow', - 'Saharan story', - 'Those things', - 'A little monk of Zen', - 'Dune', - 'The courage to be hated', - 'Crime and Punishment', - 'Moon and sixpence', - 'The silent majority', - 'First person singular', - ]; - - const [list, setList] = useState(data.slice(0, 6)); - - const renderItem = (props) => { - const { item } = props; - const DragHandle = sortableHandle(() => ); - return ( - - - {item} - - ); - }; - - const arrayMove = (array, from, to) => { - let newArray = array.slice(); - newArray.splice(to < 0 ? newArray.length + to : to, 0, newArray.splice(from, 1)[0]); - return newArray; - }; - - const onSortEnd = (callbackProps) => { - let { oldIndex, newIndex } = callbackProps; - let newList = arrayMove(list, oldIndex, newIndex); - setList(newList); - }; - - const SortableItem = SortableElement(props => renderItem(props)); - const SortableList = SortableContainer( - ({ items }) => { - return ( -
- {items.map((item, index) => ( - - ))} -
- ); - }, - { distance: 10 } - ); - - return ( -
-
- - - -
- -
- ); -}; -``` - ### With Pagination You can use Pagination in combination to achieve a paged List diff --git a/content/show/list/index.md b/content/show/list/index.md index 8fd6c89c0b..82d0b0b80d 100644 --- a/content/show/list/index.md +++ b/content/show/list/index.md @@ -919,83 +919,6 @@ class DraggableList extends React.Component { render(DraggableList); ``` -如果你使用 [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc),这里也有一个例子 - -```jsx live=true dir="column" hideInDSM -import React, { useState } from 'react'; -import { List } from '@douyinfe/semi-ui'; -import { IconHandle } from '@douyinfe/semi-icons'; -import { SortableContainer, SortableElement, sortableHandle } from 'react-sortable-hoc'; - - -() => { - const data = [ - '围城', - '平凡的世界(全三册)', - '三体(全集)', - '雪中悍刀行(全集)', - '撒哈拉的故事', - '明朝那些事', - '一禅小和尚', - '沙丘', - '被讨厌的勇气', - '罪与罚', - '月亮与六便士', - '沉默的大多数', - '第一人称单数', - ]; - - const [list, setList] = useState(data.slice(0, 6)); - - const renderItem = (props) => { - const { item } = props; - const DragHandle = sortableHandle(() => ); - return ( - - - {item} - - ); - }; - - const arrayMove = (array, from, to) => { - let newArray = array.slice(); - newArray.splice(to < 0 ? newArray.length + to : to, 0, newArray.splice(from, 1)[0]); - return newArray; - }; - - const onSortEnd = (callbackProps) => { - let { oldIndex, newIndex } = callbackProps; - let newList = arrayMove(list, oldIndex, newIndex); - setList(newList); - }; - - const SortableItem = SortableElement(props => renderItem(props)); - const SortableList = SortableContainer( - ({ items }) => { - return ( -
- {items.map((item, index) => ( - - ))} -
- ); - }, - { distance: 10 } - ); - - return ( -
-
- - - -
- -
- ); -}; -``` ### 带分页器 diff --git a/content/start/changelog/index-en-US.md b/content/start/changelog/index-en-US.md index 1a9dcdc232..fb6b909385 100644 --- a/content/start/changelog/index-en-US.md +++ b/content/start/changelog/index-en-US.md @@ -16,6 +16,23 @@ Version:Major.Minor.Patch (follow the **Semver** specification) --- +#### 🎉 2.41.1 (2023-08-11) +- 【Feat】 + - Slider Add onMouseUp API +- 【Fix】 + - Fix the problem that the handle always follows the mouse in the scene where the Slider mouse moves out of the window and then lets go and then moves back [#1412](https://github.com/DouyinFE/semi-design/issues/1412) + - SideSheet adds automatic calculation of scroll bar width logic to prevent the content behind the mask from shaking when it pops up + - Fix the incorrect case of Input and TextArea autoFoucs + +#### 🎉 2.41.0-beta.0 (2023-08-07) +- 【Refactor】 + - change react-sortable-hoc to @dnd-kit/sortable for Transfer/Taginput drag & drop [#1683](https://github.com/DouyinFE/semi-design/issues/1683) +- 【Style】 + - The interaction of the Taginput dragging process has been modified, from the change of the tag position in the original dragging to the vertical line in front of the tag to mark the position where the tag in the dragging can be dropped. TagInput adds drag-related tokens, $width-tagInput_sortable_item_over, $color-tagInput_sortable_item_over-bg [#1738](https://github.com/DouyinFE/semi-design/pull/1738) +- 【Fix】 + - fix wrong type definition for defaultCurrentIndex in ImagePreview + - fix document is not defined error [@nekocode](https://github.com/nekocode) + #### 🎉 2.40.0 (2023-07-28) - 【Style】 - Remove unnecessary margin in button component [#1732](https://github.com/DouyinFE/semi-design/pull/1732) diff --git a/content/start/changelog/index.md b/content/start/changelog/index.md index 7b430e1592..2cc972ffcb 100644 --- a/content/start/changelog/index.md +++ b/content/start/changelog/index.md @@ -13,6 +13,25 @@ Semi 版本号遵循 **Semver** 规范(主版本号-次版本号-修订版本 - 修订版本号(patch):仅会进行 bugfix,发布时间不限 - 不同版本间的详细关系,可查阅 [FAQ](/zh-CN/start/faq) + +#### 🎉 2.41.1 (2023-08-11) +- 【Feat】 + - Slider 新增 onMouseUp API +- 【Fix】 + - 修复 Slider 鼠标移出窗口后松手再移回的场景下,handle 一直跟随鼠标的问题, [#1412](https://github.com/DouyinFE/semi-design/issues/1412) + - SideSheet 新增自动计算滚动条宽度逻辑防止弹出时 mask 背后内容抖动 + - 修复 Input 和 TextArea autoFoucs 大小写不正确的问题 + + +#### 🎉 2.41.0-beta.0 (2023-08-07) +- 【Refactor】 + - 使用 @dnd-kit/sortable 替换 react-sortable-hoc 实现 Transfer/Taginput 中拖拽 [#1683](https://github.com/DouyinFE/semi-design/issues/1683) +- 【Style】 + - Taginput 拖拽过程交互有修改,从原来的拖拽中 tag 位置发生变化修改为通过 tag 前的竖线标识拖拽中的 tag 可被放下的位置。TagInput 新增和拖拽相关的 token,$width-tagInput_sortable_item_over,$color-tagInput_sortable_item_over-bg [#1738](https://github.com/DouyinFE/semi-design/pull/1738) +- 【Fix】 + - 修复 ImagePreview 中 defaultCurrentIndex 错误的类型定义 + - 修复 document is not defined 错误 [@nekocode](https://github.com/nekocode) + #### 🎉 2.40.0 (2023-07-28) - 【Style】 - 删除 Button 组件中的不必要的 margin [#1732](https://github.com/DouyinFE/semi-design/pull/1732) diff --git a/lerna.json b/lerna.json index f4ca41f2b6..9720117d40 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { "useWorkspaces": true, "npmClient": "yarn", - "version": "2.40.0" + "version": "2.41.1" } diff --git a/package.json b/package.json index 9f0cf421f7..b9780c689e 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "dependencies": { "@douyinfe/semi-site-banner": "^0.1.0", "@douyinfe/semi-site-doc-style": "0.0.1", - "@douyinfe/semi-site-header": "^0.0.27", + "@douyinfe/semi-site-header": "^0.0.28", "@douyinfe/semi-site-markdown-blocks": "^0.0.9", "@mdx-js/mdx": "1.6.22", "@mdx-js/react": "^1.6.22", @@ -101,7 +101,9 @@ "unist-util-remove": "^1.0.3", "unist-util-visit": "^2.0.3", "wait-on": "^6.0.1", - "wcag-color": "^1.1.1" + "wcag-color": "^1.1.1", + "fast-xml-parser": "^4.2.7", + "execa": "5" }, "devDependencies": { "@actions/core": "^1.6.0", diff --git a/packages/semi-animation-react/package.json b/packages/semi-animation-react/package.json index 795dbc162f..0f424589cc 100644 --- a/packages/semi-animation-react/package.json +++ b/packages/semi-animation-react/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-animation-react", - "version": "2.40.0", + "version": "2.41.1", "description": "motion library for semi-ui-react", "keywords": [ "motion", @@ -25,8 +25,8 @@ "prepublishOnly": "npm run build:lib" }, "dependencies": { - "@douyinfe/semi-animation": "2.40.0", - "@douyinfe/semi-animation-styled": "2.40.0", + "@douyinfe/semi-animation": "2.41.1", + "@douyinfe/semi-animation-styled": "2.41.1", "classnames": "^2.2.6" }, "devDependencies": { diff --git a/packages/semi-animation-styled/package.json b/packages/semi-animation-styled/package.json index 4b98b1c447..b6807249cb 100644 --- a/packages/semi-animation-styled/package.json +++ b/packages/semi-animation-styled/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-animation-styled", - "version": "2.40.0", + "version": "2.41.1", "description": "semi styled animation", "keywords": [ "semi", diff --git a/packages/semi-animation/package.json b/packages/semi-animation/package.json index 42d84ab8d5..1e34a20b8e 100644 --- a/packages/semi-animation/package.json +++ b/packages/semi-animation/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-animation", - "version": "2.40.0", + "version": "2.41.1", "description": "animation base library for semi-ui", "keywords": [ "animation", diff --git a/packages/semi-eslint-plugin/package.json b/packages/semi-eslint-plugin/package.json index a6d9424cfe..121bf09ce1 100644 --- a/packages/semi-eslint-plugin/package.json +++ b/packages/semi-eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-semi-design", - "version": "2.40.0", + "version": "2.41.1", "description": "semi ui eslint plugin", "keywords": [ "semi", diff --git a/packages/semi-foundation/carousel/foundation.ts b/packages/semi-foundation/carousel/foundation.ts index 37bc641965..544afb483d 100644 --- a/packages/semi-foundation/carousel/foundation.ts +++ b/packages/semi-foundation/carousel/foundation.ts @@ -1,7 +1,6 @@ import { isObject, get } from 'lodash'; import BaseFoundation, { DefaultAdapter } from '../base/foundation'; import { numbers } from './constants'; -import { throttle } from 'lodash'; export interface CarouselAdapter

, S = Record> extends DefaultAdapter { notifyChange: (activeIndex: number, preIndex: number) => void; @@ -34,7 +33,7 @@ class CarouselFoundation

, S = Record> exten } stop(): void { - if (this._interval){ + if (this._interval) { clearInterval(this._interval); } } @@ -93,7 +92,7 @@ class CarouselFoundation

, S = Record> exten _notifyChange(activeIndex: number): void { const { activeIndex: stateActiveIndex, isInit } = this.getStates(); - if (isInit){ + if (isInit) { this._adapter.setIsInit(false); } if (stateActiveIndex !== activeIndex) { @@ -110,10 +109,10 @@ class CarouselFoundation

, S = Record> exten getSwitchingTime(): number { const { autoPlay, speed } = this.getProps(); const autoPlayType = typeof autoPlay; - if (autoPlayType === 'boolean'){ + if (autoPlayType === 'boolean') { return numbers.DEFAULT_INTERVAL + speed; } - if (isObject(autoPlay)){ + if (isObject(autoPlay)) { return get(autoPlay, 'interval', numbers.DEFAULT_INTERVAL) + speed; } return speed; @@ -127,12 +126,12 @@ class CarouselFoundation

, S = Record> exten const { autoPlay } = this.getProps(); const autoPlayType = typeof autoPlay; // when user manually call the play function, force play - if ((autoPlayType === 'boolean' && autoPlay) || isObject(autoPlay) || this._forcePlay){ + if ((autoPlayType === 'boolean' && autoPlay) || isObject(autoPlay) || this._forcePlay) { this.play(this.getSwitchingTime()); } } - handleKeyDown(event: any): void{ + handleKeyDown(event: any): void { if (event.key === 'ArrowLeft') { this.prev(); } diff --git a/packages/semi-foundation/dropdown/menuFoundation.ts b/packages/semi-foundation/dropdown/menuFoundation.ts index 80fef8a46d..3515081d87 100644 --- a/packages/semi-foundation/dropdown/menuFoundation.ts +++ b/packages/semi-foundation/dropdown/menuFoundation.ts @@ -8,7 +8,7 @@ export default class DropdownMenuFoundation extends BaseFoundation item.ariaDisabled !== "true"); } - if (this.firstChars.length === 0){ + if (this.firstChars.length === 0) { this.menuItemNodes.forEach((item: Element) => { // the menuItemNodes can be an component and not exit textContent this.firstChars.push(item.textContent.trim()[0]?.toLowerCase()); diff --git a/packages/semi-foundation/image/previewFoundation.ts b/packages/semi-foundation/image/previewFoundation.ts index 6d8e165e7f..454e8e293c 100644 --- a/packages/semi-foundation/image/previewFoundation.ts +++ b/packages/semi-foundation/image/previewFoundation.ts @@ -2,7 +2,7 @@ import BaseFoundation, { DefaultAdapter } from "../base/foundation"; export default class PreviewFoundation

, S = Record> extends BaseFoundation> { - handleVisibleChange = (newVisible : boolean) => { + handleVisibleChange = (newVisible: boolean) => { const { visible, onVisibleChange } = this.getProps(); if (!(visible in this.getProps())) { this.setState({ diff --git a/packages/semi-foundation/modal/modalContentFoundation.ts b/packages/semi-foundation/modal/modalContentFoundation.ts index 3977caa12e..744e46f660 100644 --- a/packages/semi-foundation/modal/modalContentFoundation.ts +++ b/packages/semi-foundation/modal/modalContentFoundation.ts @@ -8,9 +8,9 @@ export interface ModalContentProps extends ModalProps { isFullScreen?: boolean; contentClassName?: string; maskClassName?: string; - onAnimationEnd?: (e:any) => void; - maskExtraProps?:Record; - contentExtraProps?:Record + onAnimationEnd?: (e: any) => void; + maskExtraProps?: Record; + contentExtraProps?: Record } export interface ModalContentState { diff --git a/packages/semi-foundation/package.json b/packages/semi-foundation/package.json index 75e1b2f41d..c5cd196065 100644 --- a/packages/semi-foundation/package.json +++ b/packages/semi-foundation/package.json @@ -1,13 +1,13 @@ { "name": "@douyinfe/semi-foundation", - "version": "2.40.0", + "version": "2.41.1", "description": "", "scripts": { "build:lib": "node ./scripts/compileLib.js", "prepublishOnly": "npm run build:lib" }, "dependencies": { - "@douyinfe/semi-animation": "2.40.0", + "@douyinfe/semi-animation": "2.41.1", "async-validator": "^3.5.0", "classnames": "^2.2.6", "date-fns": "^2.29.3", diff --git a/packages/semi-foundation/sideSheet/sideSheetFoundation.ts b/packages/semi-foundation/sideSheet/sideSheetFoundation.ts index c502df0df1..208899bf5a 100644 --- a/packages/semi-foundation/sideSheet/sideSheetFoundation.ts +++ b/packages/semi-foundation/sideSheet/sideSheetFoundation.ts @@ -1,5 +1,5 @@ import BaseFoundation, { DefaultAdapter } from '../base/foundation'; -import { get, noop } from 'lodash'; +import { noop } from 'lodash'; import KeyCode from '../utils/keyCode'; @@ -95,7 +95,7 @@ export default class SideSheetFoundation extends BaseFoundation{ + toggleDisplayNone = (displayNone: boolean)=>{ this._adapter.toggleDisplayNone(displayNone); } diff --git a/packages/semi-foundation/slider/foundation.ts b/packages/semi-foundation/slider/foundation.ts index 33449d3314..64d4c4b45c 100644 --- a/packages/semi-foundation/slider/foundation.ts +++ b/packages/semi-foundation/slider/foundation.ts @@ -23,6 +23,7 @@ export interface SliderProps{ vertical?: boolean; onAfterChange?: (value: SliderProps['value']) => void; // triggered when mouse up and clicked onChange?: (value: SliderProps['value']) => void; + onMouseUp?: (e: any) => void; tooltipVisible?: boolean; style?: Record; className?: string; diff --git a/packages/semi-foundation/tabs/foundation.ts b/packages/semi-foundation/tabs/foundation.ts index a3d8d6b04d..010ab4e9bf 100644 --- a/packages/semi-foundation/tabs/foundation.ts +++ b/packages/semi-foundation/tabs/foundation.ts @@ -128,14 +128,14 @@ class TabsFoundation

, S = Record> extends B } } - handleDeleteKeyDown(event:any, tabs: HTMLElement[], itemKey: string, closable: boolean): void { + handleDeleteKeyDown(event: any, tabs: HTMLElement[], itemKey: string, closable: boolean): void { const { preventScroll } = this.getProps(); if (closable) { this.handleTabDelete(itemKey); const index = tabs.indexOf(event.target); // Move focus to next element after deletion // If the element is the last removable tab, focus to its previous tab - if (tabs.length !== 1 ){ + if (tabs.length !== 1 ) { tabs[index + 1 >= tabs.length ? index - 1 : index + 1].focus({ preventScroll }); } } diff --git a/packages/semi-foundation/tagInput/tagInput.scss b/packages/semi-foundation/tagInput/tagInput.scss index d98e3a42db..191d5f3115 100644 --- a/packages/semi-foundation/tagInput/tagInput.scss +++ b/packages/semi-foundation/tagInput/tagInput.scss @@ -42,6 +42,27 @@ $module: #{$prefix}-tagInput; } } + &-sortable-item { + position: relative; + &-over { + overflow: visible; + &::before { + content: ""; + display: block; + height: 100%; + width: $width-tagInput_sortable_item_over; + background-color: $color-tagInput_sortable_item_over-bg; + position: absolute; + left: -$width-tagInput_sortable_item_over; + top: 0; + } + } + + &-active { + opacity: 0.5; + } + } + &-hover { background-color: $color-tagInput_default-bg-hover; border: $width-tagInput-border-hover $color-tagInput-border-hover solid; diff --git a/packages/semi-foundation/tagInput/variables.scss b/packages/semi-foundation/tagInput/variables.scss index ba345388d8..bf5196bdbb 100644 --- a/packages/semi-foundation/tagInput/variables.scss +++ b/packages/semi-foundation/tagInput/variables.scss @@ -27,6 +27,7 @@ $color-tagInput_danger-bg-hover: var(--semi-color-danger-light-hover); // 危险 $color-tagInput_danger-border-hover: var(--semi-color-danger-light-hover); // 危险标签输入框描边颜色 - 悬浮 $color-tagInput_danger-bg-focus: var(--semi-color-danger-light-default); // 危险标签输入框背景颜色 - 选中 $color-tagInput_danger-border-focus: var(--semi-color-danger); // 危险标签输入框描边颜色 - 选中 +$color-tagInput_sortable_item_over-bg: var(--semi-color-primary); // 拖拽经过的元素前竖线背景色 $color-tagInput_handler-icon-default: var(--semi-color-text-2); // 可拖拽的标签拖拽按钮颜色 @@ -48,6 +49,7 @@ $width-tagInput-clear-medium: $width-icon-medium * 2; // 标签输入框清空 $width-tagInput-border-default: $border-thickness-control; // 标签输入框描边描边宽度 - 默认 $width-tagInput-border-hover: $width-tagInput-border-default; // 标签输入框描边描边宽度 - 悬浮 $width-tagInput-border-focus: $border-thickness-control-focus; // 标签输入框描边宽度 - 选中态 +$width-tagInput_sortable_item_over: 2px; // 拖拽经过的元素前竖线宽度 $radius-tagInput: var(--semi-border-radius-small); // 标签输入框圆角 diff --git a/packages/semi-foundation/transfer/transfer.scss b/packages/semi-foundation/transfer/transfer.scss index 25f4c8fc6a..13c7f08ec3 100644 --- a/packages/semi-foundation/transfer/transfer.scss +++ b/packages/semi-foundation/transfer/transfer.scss @@ -169,12 +169,19 @@ $module: #{$prefix}-transfer; &-handler { margin-right: $spacing-transfer_right_item_drag_handler-marginRight; flex-shrink: 0; + cursor: move; } &-item-move { z-index: $z-transfer_right_item_drag_item_move; } } + + &-sortable-item { + &-active { + opacity: 0; + } + } } &-empty { diff --git a/packages/semi-foundation/utils/a11y.ts b/packages/semi-foundation/utils/a11y.ts index 22491ac2a3..5b6081ee1b 100644 --- a/packages/semi-foundation/utils/a11y.ts +++ b/packages/semi-foundation/utils/a11y.ts @@ -35,7 +35,7 @@ export function setFocusToLastItem(itemNodes: HTMLElement[]): void { export function setFocusToPreviousMenuItem (itemNodes: HTMLElement[], currentItem: HTMLElement): void { let newMenuItem: HTMLElement, index: number; - if (itemNodes.length > 0){ + if (itemNodes.length > 0) { if (currentItem === itemNodes[0]) { newMenuItem = itemNodes[itemNodes.length-1]; } else { @@ -50,7 +50,7 @@ export function setFocusToPreviousMenuItem (itemNodes: HTMLElement[], currentIte export function setFocusToNextMenuitem (itemNodes: HTMLElement[], currentItem: HTMLElement): void { let newMenuItem: HTMLElement, index: number; - if (itemNodes.length > 0){ + if (itemNodes.length > 0) { if (currentItem === itemNodes[itemNodes.length-1]) { newMenuItem = itemNodes[0]; } else { @@ -91,17 +91,17 @@ export function getAncestorNodeByRole(curElement: Element, role: string): Elemen if (!curElement) { return null; } - while (curElement.parentElement && get(curElement.parentElement, 'attributes.role.value', '') !== role){ + while (curElement.parentElement && get(curElement.parentElement, 'attributes.role.value', '') !== role) { curElement = curElement.parentElement; } return curElement.parentElement; } // According to the Id, find the corresponding data-popupid element -export function getMenuButton(focusableEle: NodeListOf, Id: string): HTMLElement{ - for (let i = 0; i < focusableEle.length; i++){ +export function getMenuButton(focusableEle: NodeListOf, Id: string): HTMLElement { + for (let i = 0; i < focusableEle.length; i++) { const curAriDescribedby = focusableEle[i].attributes['data-popupid']; - if (curAriDescribedby && curAriDescribedby.value === Id){ + if (curAriDescribedby && curAriDescribedby.value === Id) { return focusableEle[i]; } } diff --git a/packages/semi-icons/package.json b/packages/semi-icons/package.json index 280a0ec6d7..71b5209df4 100644 --- a/packages/semi-icons/package.json +++ b/packages/semi-icons/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-icons", - "version": "2.40.0", + "version": "2.41.1", "description": "semi icons", "keywords": [ "semi", diff --git a/packages/semi-icons/webpack.config.js b/packages/semi-icons/webpack.config.js index 3e2622bf2c..a143713759 100644 --- a/packages/semi-icons/webpack.config.js +++ b/packages/semi-icons/webpack.config.js @@ -4,7 +4,7 @@ const TerserPlugin = require('terser-webpack-plugin'); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); -module.exports = function getWebpackConfig({ minimize }){ +module.exports = function getWebpackConfig({ minimize }) { return { mode: 'production', bail: true, diff --git a/packages/semi-illustrations/package.json b/packages/semi-illustrations/package.json index 154c7c7ed1..24bfd9ccbc 100644 --- a/packages/semi-illustrations/package.json +++ b/packages/semi-illustrations/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-illustrations", - "version": "2.40.0", + "version": "2.41.1", "description": "semi illustrations", "keywords": [ "semi", diff --git a/packages/semi-illustrations/webpack.config.js b/packages/semi-illustrations/webpack.config.js index acf59af175..f6fe274167 100644 --- a/packages/semi-illustrations/webpack.config.js +++ b/packages/semi-illustrations/webpack.config.js @@ -3,7 +3,7 @@ const webpack = require('webpack'); const TerserPlugin = require('terser-webpack-plugin'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); -module.exports = function getWebpackConfig({ minimize }){ +module.exports = function getWebpackConfig({ minimize }) { return { mode: 'production', bail: true, diff --git a/packages/semi-next/package.json b/packages/semi-next/package.json index cfde877b79..cefe20cc91 100644 --- a/packages/semi-next/package.json +++ b/packages/semi-next/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-next", - "version": "2.40.0", + "version": "2.41.1", "description": "Plugin that support Semi Design in Next.js", "author": "伍浩威 ", "homepage": "", @@ -23,7 +23,7 @@ "typescript": "^4" }, "dependencies": { - "@douyinfe/semi-webpack-plugin": "2.40.0" + "@douyinfe/semi-webpack-plugin": "2.41.1" }, "gitHead": "eb34a4f25f002bb4cbcfa51f3df93bed868c831a" } diff --git a/packages/semi-rspack/package.json b/packages/semi-rspack/package.json index ce99565fcd..99287fdb84 100644 --- a/packages/semi-rspack/package.json +++ b/packages/semi-rspack/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-rspack-plugin", - "version": "2.40.0", + "version": "2.41.1", "description": "", "homepage": "", "license": "MIT", diff --git a/packages/semi-scss-compile/package.json b/packages/semi-scss-compile/package.json index 624b38cb55..183027848e 100644 --- a/packages/semi-scss-compile/package.json +++ b/packages/semi-scss-compile/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-scss-compile", - "version": "2.40.0", + "version": "2.41.1", "description": "compile semi scss to css", "author": "daiqiang@bytedance.com", "license": "MIT", diff --git a/packages/semi-theme-default/package.json b/packages/semi-theme-default/package.json index 5621991b9b..b45b167bf7 100644 --- a/packages/semi-theme-default/package.json +++ b/packages/semi-theme-default/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-theme-default", - "version": "2.40.0", + "version": "2.41.1", "description": "semi-theme-default", "keywords": [ "semi-theme", diff --git a/packages/semi-ui/_sortable/index.tsx b/packages/semi-ui/_sortable/index.tsx new file mode 100644 index 0000000000..6bbdbc0a47 --- /dev/null +++ b/packages/semi-ui/_sortable/index.tsx @@ -0,0 +1,255 @@ +import React, { ReactNode, useState, useCallback, useMemo } from 'react'; +import { createPortal } from 'react-dom'; +import { CSS as cssDndKit } from '@dnd-kit/utilities'; +import cls from 'classnames'; + +import { + closestCenter, + DragOverlay, + DndContext, + MouseSensor, + TouchSensor, + useSensor, + useSensors, + KeyboardSensor, + TraversalOrder, +} from '@dnd-kit/core'; +import type { + UniqueIdentifier, + PointerActivationConstraint, + CollisionDetection, +} from '@dnd-kit/core'; +import { + useSortable, + SortableContext, + rectSortingStrategy, + sortableKeyboardCoordinates, +} from '@dnd-kit/sortable'; +import type { + SortingStrategy, + AnimateLayoutChanges, + NewIndexGetter, +} from '@dnd-kit/sortable'; +import type { SortableTransition } from '@dnd-kit/sortable/dist/hooks/types'; +import { isNull } from 'lodash'; + +const defaultPrefix = 'semi-sortable'; +const defaultConstraint = { + delay: 150, + tolerance: 5, +}; + +interface OnSortEndProps { + oldIndex: number; + newIndex: number +} +export type OnSortEnd = (props: OnSortEndProps) => void; + +export interface RenderItemProps { + id?: string | number; + sortableHandle?: any; + [x: string]: any +} +export interface SortableProps { + onSortEnd?: OnSortEnd; + // Set drag and drop trigger conditions + activationConstraint?: PointerActivationConstraint; + // Collision detection algorithm, for drag and drop sorting, use closestCenter to meet most scenarios + collisionDetection?: CollisionDetection; + // the dragged items,The content in items cannot be the number 0 + items?: any[]; + // Function that renders the item that is allowed to be dragged + renderItem?: (props: RenderItemProps) => React.ReactNode; + // Drag and drop strategy + strategy?: SortingStrategy; + // Whether to use a separate drag layer for items that move with the mouse + useDragOverlay?: boolean; + // A container for all elements that are allowed to be dragged + container?: any; + // Whether to change the size of the item being dragged + adjustScale?: boolean; + // Whether to use animation during dragging + transition?: SortableTransition | null; + // prefix + prefix?: string; + // The className of the item that moves with the mouse during the drag + dragOverlayCls?: string +} + +interface SortableItemProps { + animateLayoutChanges?: AnimateLayoutChanges; + getNewIndex?: NewIndexGetter; + id: UniqueIdentifier; + index: number; + useDragOverlay?: boolean; + renderItem?: (props: RenderItemProps) => ReactNode; + prefix?: string; + transition?: SortableTransition | null +} + +function DefaultContainer(props) { + return

; +} + +export function Sortable({ + items, + onSortEnd, + adjustScale, + renderItem, + transition, + activationConstraint = defaultConstraint, + collisionDetection = closestCenter, + strategy = rectSortingStrategy, + useDragOverlay = true, + dragOverlayCls, + container: Container = DefaultContainer, + prefix = defaultPrefix, +}: SortableProps) { + + const [activeId, setActiveId] = useState(null); + const sensors = useSensors( + useSensor(MouseSensor, { + activationConstraint, + }), + useSensor(TouchSensor, { + activationConstraint, + }), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + const getIndex = useCallback((id: UniqueIdentifier) => items.indexOf(id), [items]); + const activeIndex = useMemo(() => activeId ? getIndex(activeId) : -1, [getIndex, activeId]); + + const onDragStart = useCallback(({ active }) => { + if (!active) { return; } + setActiveId(active.id); + }, []); + + const onDragEnd = useCallback(({ over }) => { + setActiveId(null); + if (over) { + const overIndex = getIndex(over.id); + if (activeIndex !== overIndex) { + onSortEnd({ oldIndex: activeIndex, newIndex: overIndex }); + } + } + }, [activeIndex, getIndex, onSortEnd]); + + const onDragCancel = useCallback(() => { + setActiveId(null); + }, []); + + return ( + + + + {items.map((value, index) => ( + + ))} + + + {useDragOverlay + ? createPortal( + + {activeId ? ( + renderItem({ + id: activeId, + sortableHandle: (WrapperComponent) => WrapperComponent + }) + ) : null} + , + document.body + ) + : null} + + ); +} + +export function SortableItem({ + animateLayoutChanges, + id, + renderItem, + prefix, + transition: animation, +}: SortableItemProps) { + const { + listeners, + setNodeRef, + transform, + transition, + active, + isOver, + attributes, + } = useSortable({ + id, + animateLayoutChanges, + transition: animation, + }); + + const sortableHandle = useCallback((WrapperComponent) => { + // console.log('listeners', listeners); + // 保证给出的接口的一致性,使用 span 包一层,保证用户能够通过同样的方式使用 handler + // To ensure the consistency of the given interface + // use a span package layer to ensure that users can use the handler in the same way + // eslint-disable-next-line jsx-a11y/no-static-element-interactions + return () => { + listeners.onMouseDown(e); + // 阻止onMousedown的事件传递, + // 防止元素在点击后被卸载导致tooltip/popover的弹出层意外关闭 + // Prevent the onMousedown event from being delivered, + // preventing the element from being unloaded after being clicked, + // causing the tooltip/popover pop-up layer to close unexpectedly + e.preventDefault(); + e.stopPropagation(); + }} + >; + }, [listeners]); + + const itemCls = cls( + `${prefix}-sortable-item`, + { + [`${prefix}-sortable-item-over`]: isOver, + [`${prefix}-sortable-item-active`]: active?.id === id, + } + ); + + const wrapperStyle = (!isNull(animation)) ? { + transform: cssDndKit.Transform.toString({ + ...transform, + scaleX: 1, + scaleY: 1, + }), + transition: transition, + } : undefined; + + return
+ {renderItem({ id, sortableHandle }) as JSX.Element} +
; +} diff --git a/packages/semi-ui/_utils/index.tsx b/packages/semi-ui/_utils/index.tsx index 161f639c4d..0dc411d61c 100644 --- a/packages/semi-ui/_utils/index.tsx +++ b/packages/semi-ui/_utils/index.tsx @@ -195,3 +195,11 @@ export function getFocusableElements(node: HTMLElement) { return focusableElements; } +export function getScrollbarWidth() { + if (globalThis && Object.prototype.toString.call(globalThis) === '[object Window]') { + return window.innerWidth - document.documentElement.clientWidth; + } + return 0; +} + + diff --git a/packages/semi-ui/carousel/interface.ts b/packages/semi-ui/carousel/interface.ts index ae2fcb3ed9..14224f3e27 100644 --- a/packages/semi-ui/carousel/interface.ts +++ b/packages/semi-ui/carousel/interface.ts @@ -37,7 +37,7 @@ export interface CarouselIndicatorProps { defaultActiveIndex?: number; position?: typeof strings.POSITION_MAP[number]; size?: typeof strings.SIZE[number]; - total?:number; + total?: number; theme?: typeof strings.THEME_MAP[number]; type?: typeof strings.TYPE_MAP[number]; onIndicatorChange?: (activeIndex: number) => void; diff --git a/packages/semi-ui/datePicker/dateInput.tsx b/packages/semi-ui/datePicker/dateInput.tsx index 055d853f14..6c83303f44 100644 --- a/packages/semi-ui/datePicker/dateInput.tsx +++ b/packages/semi-ui/datePicker/dateInput.tsx @@ -281,7 +281,7 @@ export default class DateInput extends BaseComponent { onChange={(rangeStartValue, e) => this.handleRangeInputChange(rangeStartValue, rangeEnd, e)} onEnterPress={e => this.handleRangeInputEnterPress(e, rangeStart, rangeEnd)} onFocus={e => this.handleRangeInputFocus(e as any, 'rangeStart')} - autofocus={autofocus} // autofocus moved to range start + autoFocus={autofocus} // autofocus moved to range start ref={rangeInputStartRef} /> @@ -462,7 +462,7 @@ export default class DateInput extends BaseComponent { value={text} validateStatus={validateStatus} prefix={prefix} - autofocus={autofocus} + autoFocus={autofocus} size={size} onBlur={onBlur as any} onFocus={onFocus as any} diff --git a/packages/semi-ui/datePicker/quickControl.tsx b/packages/semi-ui/datePicker/quickControl.tsx index 361206de95..979b7be9d4 100644 --- a/packages/semi-ui/datePicker/quickControl.tsx +++ b/packages/semi-ui/datePicker/quickControl.tsx @@ -17,7 +17,7 @@ export interface QuickControlProps { presetPosition: typeof strings.PRESET_POSITION_SET[number]; onPresetClick: (preset: PresetType, e: React.MouseEvent) => void; type: string; - insetInput: DateInputFoundationProps['insetInput'] + insetInput: DateInputFoundationProps['insetInput']; locale: any } diff --git a/packages/semi-ui/form/_story/DynamicField/nestArrayField.jsx b/packages/semi-ui/form/_story/DynamicField/nestArrayField.jsx index 49d84f8b1e..26a00890fd 100644 --- a/packages/semi-ui/form/_story/DynamicField/nestArrayField.jsx +++ b/packages/semi-ui/form/_story/DynamicField/nestArrayField.jsx @@ -10,9 +10,6 @@ import { Button, Modal, TreeSelect, Row, Col, Avatar, Select as BasicSelect, withFormApi, withField, ArrayField, - AutoComplete, - Collapse, - Icon, } from '../../../index'; import { format } from 'date-fns'; import { ComponentUsingFormState } from '../Hook/hookDemo'; @@ -120,7 +117,7 @@ class NestArrayField extends React.Component { class Child extends React.Component { - constructor(props){ + constructor(props) { super(props); this.state = { ts: format(new Date(), 'yyyy-MM-dd HH:mm:ss') @@ -134,7 +131,7 @@ class Child extends React.Component { } class Parent extends React.Component { - constructor(props){ + constructor(props) { super(props); this.click = this.click.bind(this); } diff --git a/packages/semi-ui/image/previewInner.tsx b/packages/semi-ui/image/previewInner.tsx index ee4355a15f..7bd4388fea 100644 --- a/packages/semi-ui/image/previewInner.tsx +++ b/packages/semi-ui/image/previewInner.tsx @@ -12,6 +12,7 @@ import Footer from "./previewFooter"; import PreviewImage from "./previewImage"; import PreviewInnerFoundation, { PreviewInnerAdapter, RatioType } from "@douyinfe/semi-foundation/image/previewInnerFoundation"; import { PreviewContext, PreviewContextProps } from "./previewContext"; +import { getScrollbarWidth } from "../_utils"; const prefixCls = cssClasses.PREFIX; @@ -220,15 +221,8 @@ export default class PreviewInner extends BaseComponent {visible && - // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events,jsx-a11y/no-static-element-interactions -
this.handleMouseEvent(e.nativeEvent, "over")} - onMouseOut={(e): void => this.handleMouseEvent(e.nativeEvent, "out")} - > -
- - {showPrev && ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions -
this.handleSwitchImage("prev")} - > - -
- )} - {showNext && ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions -
this.handleSwitchImage("next")} - > - -
- )} -
this.handleSwitchImage("prev")} - onNext={(): void => this.handleSwitchImage("next")} - onZoomIn={this.handleZoomImage} - onZoomOut={this.handleZoomImage} - onDownload={this.handleDownload} - onRotate={this.handleRotateImage} - onAdjustRatio={this.handleAdjustRatio} - renderPreviewMenu={renderPreviewMenu} - /> -
} + // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events,jsx-a11y/no-static-element-interactions +
this.handleMouseEvent(e.nativeEvent, "over")} + onMouseOut={(e): void => this.handleMouseEvent(e.nativeEvent, "out")} + > +
+ + {showPrev && ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions +
this.handleSwitchImage("prev")} + > + +
+ )} + {showNext && ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions +
this.handleSwitchImage("next")} + > + +
+ )} +
this.handleSwitchImage("prev")} + onNext={(): void => this.handleSwitchImage("next")} + onZoomIn={this.handleZoomImage} + onZoomOut={this.handleZoomImage} + onDownload={this.handleDownload} + onRotate={this.handleRotateImage} + onAdjustRatio={this.handleAdjustRatio} + renderPreviewMenu={renderPreviewMenu} + /> +
} ); } diff --git a/packages/semi-ui/input/index.tsx b/packages/semi-ui/input/index.tsx index 170a540245..15a4a68952 100644 --- a/packages/semi-ui/input/index.tsx +++ b/packages/semi-ui/input/index.tsx @@ -24,7 +24,7 @@ export type InputMode = 'password'; export type ValidateStatus = "default" | "error" | "warning" | "success"; export interface InputProps extends - Omit, 'onChange' | 'prefix' | 'size' | 'autoFocus' | 'placeholder' | 'onFocus' | 'onBlur'> { + Omit, 'onChange' | 'prefix' | 'size' | 'placeholder' | 'onFocus' | 'onBlur'> { 'aria-label'?: React.AriaAttributes['aria-label']; 'aria-describedby'?: React.AriaAttributes['aria-describedby']; 'aria-errormessage'?: React.AriaAttributes['aria-errormessage']; @@ -41,7 +41,6 @@ export interface InputProps extends defaultValue?: React.ReactText; disabled?: boolean; readonly?: boolean; - autofocus?: boolean; type?: string; showClear?: boolean; hideSuffix?: boolean; @@ -99,7 +98,7 @@ class Input extends BaseComponent { defaultValue: PropTypes.any, disabled: PropTypes.bool, readonly: PropTypes.bool, - autofocus: PropTypes.bool, + autoFocus: PropTypes.bool, type: PropTypes.string, showClear: PropTypes.bool, hideSuffix: PropTypes.bool, @@ -224,8 +223,8 @@ class Input extends BaseComponent { // autofocus is changed from the original support of input to the support of manually calling the focus method, // so that preventScroll can still take effect under the setting of autofocus this.foundation.init(); - const { disabled, autofocus, preventScroll } = this.props; - if (!disabled && autofocus) { + const { disabled, autoFocus, preventScroll } = this.props; + if (!disabled && (autoFocus || this.props['autofocus'])) { this.inputRef.current.focus({ preventScroll }); } } @@ -425,7 +424,7 @@ class Input extends BaseComponent { const { addonAfter, addonBefore, - autofocus, + autoFocus, clearIcon, className, disabled, diff --git a/packages/semi-ui/input/textarea.tsx b/packages/semi-ui/input/textarea.tsx index 5a833e2218..d5fca8a9b5 100644 --- a/packages/semi-ui/input/textarea.tsx +++ b/packages/semi-ui/input/textarea.tsx @@ -35,7 +35,7 @@ export interface TextAreaProps extends defaultValue?: string; disabled?: boolean; readonly?: boolean; - autofocus?: boolean; + autoFocus?: boolean; showCounter?: boolean; showClear?: boolean; onClear?: (e: React.MouseEvent) => void; @@ -280,6 +280,7 @@ class TextArea extends BaseComponent { minLength, showClear, borderless, + autoFocus, ...rest } = this.props; const { isFocus, value, minLength: stateMinLength } = this.state; @@ -307,6 +308,7 @@ class TextArea extends BaseComponent { ); const itemProps = { ...omit(rest, 'insetLabel', 'insetLabelId', 'getValueLength', 'onClear', 'showClear'), + autoFocus: autoFocus || this.props['autofocus'], className: itemCls, disabled, readOnly: readonly, diff --git a/packages/semi-ui/layout/Sider.tsx b/packages/semi-ui/layout/Sider.tsx index 653f5e1aa1..7e55bd0fb5 100644 --- a/packages/semi-ui/layout/Sider.tsx +++ b/packages/semi-ui/layout/Sider.tsx @@ -42,7 +42,7 @@ export interface SiderProps { breakpoint?: Array; onBreakpoint?: (screen: keyof ResponsiveMap, match: boolean) => void; 'aria-label'?: React.AriaAttributes['aria-label']; - 'role'?:React.AriaRole + 'role'?: React.AriaRole } class Sider extends React.PureComponent { diff --git a/packages/semi-ui/modal/Modal.tsx b/packages/semi-ui/modal/Modal.tsx index 66c7ceffc3..957921c492 100644 --- a/packages/semi-ui/modal/Modal.tsx +++ b/packages/semi-ui/modal/Modal.tsx @@ -15,6 +15,7 @@ import { Locale } from '../locale/interface'; import useModal from './useModal'; import { ButtonProps } from '../button/Button'; import CSSAnimation from "../_cssAnimation"; +import { getScrollbarWidth } from '../_utils'; export const destroyFns: any[] = []; export type ConfirmType = 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom'; @@ -188,14 +189,6 @@ class Modal extends BaseComponent { return newState; } - static getScrollbarWidth() { - if (globalThis && Object.prototype.toString.call(globalThis) === '[object Window]') { - return window.innerWidth - document.documentElement.clientWidth; - } - return 0; - } - - static info = function (props: ModalReactProps) { return confirm>(withInfo(props)); }; @@ -228,7 +221,7 @@ class Modal extends BaseComponent { componentDidMount() { - this.scrollBarWidth = Modal.getScrollbarWidth(); + this.scrollBarWidth = getScrollbarWidth(); this.originBodyWidth = document.body.style.width; if (this.props.visible) { this.foundation.beforeShow(); @@ -368,22 +361,22 @@ class Modal extends BaseComponent { return ( { + animationState={visible ? 'enter' : 'leave'} + startClassName={visible ? `${cssClasses.DIALOG}-content-animate-show` : `${cssClasses.DIALOG}-content-animate-hide`} + onAnimationEnd={() => { this.updateState(); }} > { - ({ animationClassName, animationEventsNeedBind })=>{ - return { + ({ animationClassName, animationEventsNeedBind }) => { + return { this.updateState(); }} > { - ({ animationClassName: maskAnimationClassName, animationEventsNeedBind: maskAnimationEventsNeedBind })=>{ + ({ animationClassName: maskAnimationClassName, animationEventsNeedBind: maskAnimationEventsNeedBind }) => { return shouldRender ? { footer={renderFooter} onClose={this.handleCancel} - />:<>; + /> : <>; } } ; diff --git a/packages/semi-ui/package.json b/packages/semi-ui/package.json index 3ccf6ff9ee..ad0e87af03 100644 --- a/packages/semi-ui/package.json +++ b/packages/semi-ui/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-ui", - "version": "2.40.0", + "version": "2.41.1", "description": "", "main": "lib/cjs/index.js", "module": "lib/es/index.js", @@ -17,12 +17,15 @@ "lib/*" ], "dependencies": { - "@douyinfe/semi-animation": "2.40.0", - "@douyinfe/semi-animation-react": "2.40.0", - "@douyinfe/semi-foundation": "2.40.0", - "@douyinfe/semi-icons": "2.40.0", - "@douyinfe/semi-illustrations": "2.40.0", - "@douyinfe/semi-theme-default": "2.40.0", + "@dnd-kit/core": "^6.0.8", + "@dnd-kit/sortable": "^7.0.2", + "@dnd-kit/utilities": "^3.2.1", + "@douyinfe/semi-animation": "2.40.0-beta.0", + "@douyinfe/semi-animation-react": "2.40.0-beta.0", + "@douyinfe/semi-foundation": "2.40.0-beta.0", + "@douyinfe/semi-icons": "2.40.0-beta.0", + "@douyinfe/semi-illustrations": "2.40.0-beta.0", + "@douyinfe/semi-theme-default": "2.40.0-beta.0", "async-validator": "^3.5.0", "classnames": "^2.2.6", "copy-text-to-clipboard": "^2.1.1", @@ -31,7 +34,6 @@ "lodash": "^4.17.21", "prop-types": "^15.7.2", "react-resizable": "^1.8.0", - "react-sortable-hoc": "^2.0.0", "react-window": "^1.8.2", "resize-observer-polyfill": "^1.5.1", "scroll-into-view-if-needed": "^2.2.24", diff --git a/packages/semi-ui/sideSheet/index.tsx b/packages/semi-ui/sideSheet/index.tsx index feeeb432b4..43198eb846 100644 --- a/packages/semi-ui/sideSheet/index.tsx +++ b/packages/semi-ui/sideSheet/index.tsx @@ -14,6 +14,7 @@ import SideSheetFoundation, { } from '@douyinfe/semi-foundation/sideSheet/sideSheetFoundation'; import '@douyinfe/semi-foundation/sideSheet/sideSheet.scss'; import CSSAnimation from "../_cssAnimation"; +import { getScrollbarWidth } from '../_utils'; const prefixCls = cssClasses.PREFIX; const defaultWidthList = strings.WIDTH; @@ -87,23 +88,32 @@ export default class SideSheet extends BaseComponent { const { getPopupContainer } = this.props; - if (!getPopupContainer && document) { + this.bodyOverflow = document.body.style.overflow || ''; + if (!getPopupContainer && this.bodyOverflow !== 'hidden') { document.body.style.overflow = 'hidden'; + document.body.style.width = `calc(${this.originBodyWidth || '100%'} - ${this.scrollBarWidth}px)`; } }, enabledBodyScroll: () => { const { getPopupContainer } = this.props; - if (!getPopupContainer && document) { - document.body.style.overflow = ''; + if (!getPopupContainer && this.bodyOverflow !== 'hidden') { + document.body.style.overflow = this.bodyOverflow; + document.body.style.width = this.originBodyWidth; } }, notifyCancel: (e: React.MouseEvent | React.KeyboardEvent) => { @@ -144,6 +154,8 @@ export default class SideSheet extends BaseComponent {
tipFormatter
- `=====${val}=====` }> + `=====${val}=====` }>


diff --git a/packages/semi-ui/slider/index.tsx b/packages/semi-ui/slider/index.tsx index 82d06e7230..8e3111fa85 100644 --- a/packages/semi-ui/slider/index.tsx +++ b/packages/semi-ui/slider/index.tsx @@ -43,6 +43,7 @@ export default class Slider extends BaseComponent { vertical: PropTypes.bool, onAfterChange: PropTypes.func, // OnmouseUp and triggered when clicked onChange: PropTypes.func, + onMouseUp: PropTypes.func, tooltipVisible: PropTypes.bool, style: PropTypes.object, className: PropTypes.string, @@ -186,7 +187,7 @@ export default class Slider extends BaseComponent { getMaxHandleEl: () => this.maxHanleEl.current, onHandleDown: (e: React.MouseEvent) => { this._addEventListener(document.body, 'mousemove', this.foundation.onHandleMove, false); - this._addEventListener(document.body, 'mouseup', this.foundation.onHandleUp, false); + this._addEventListener(window, 'mouseup', this.foundation.onHandleUp, false); this._addEventListener(document.body, 'touchmove', this.foundation.onHandleTouchMove, false); }, onHandleMove: (mousePos: number, isMin: boolean, stateChangeCallback = noop, clickTrack = false, outPutValue): boolean | void => { @@ -240,6 +241,7 @@ export default class Slider extends BaseComponent { this.setState({ focusPos: '' }); }, onHandleUpBefore: (e: React.MouseEvent) => { + this.props.onMouseUp?.(e); e.stopPropagation(); e.preventDefault(); document.body.removeEventListener('mousemove', this.foundation.onHandleMove, false); @@ -613,7 +615,7 @@ export default class Slider extends BaseComponent { return slider; } - private _addEventListener(target: HTMLElement, eventName: T, callback: (e: HTMLElementEventMap[T]) => void, ...rests: any) { + private _addEventListener(target: HTMLElement | Window, eventName: T, callback: EventListenerOrEventListenerObject, ...rests: any) { if (target.addEventListener) { target.addEventListener(eventName, callback, ...rests); const clearSelf = () => { diff --git a/packages/semi-ui/table/Table.tsx b/packages/semi-ui/table/Table.tsx index 2ca64fc266..e099f770c0 100644 --- a/packages/semi-ui/table/Table.tsx +++ b/packages/semi-ui/table/Table.tsx @@ -288,6 +288,10 @@ class Table> extends BaseComponent (Boolean(column.ellipsis) || Boolean(column.fixed))); } + if (this.adapter.useFixedHeader()) { + isFixed = true; + } + return isFixed ? 'fixed' : 'auto'; }, setHeadWidths: (headWidths: Array, index = 0) => { diff --git a/packages/semi-ui/table/_story/table.stories.jsx b/packages/semi-ui/table/_story/table.stories.jsx index 8a9c3aa594..c212fe8d28 100644 --- a/packages/semi-ui/table/_story/table.stories.jsx +++ b/packages/semi-ui/table/_story/table.stories.jsx @@ -98,7 +98,8 @@ export { EllipsisNormalTable, EllipsisFixedTable, ShowTitleTable, Fixed1556, FixedColumnAlign, - FixOnChange + FixOnChange, + FixedSticky } from './v2'; export { default as FixSelectAll325 } from './Demos/rowSelection'; diff --git a/packages/semi-ui/table/_story/v2/FixedSticky/index.tsx b/packages/semi-ui/table/_story/v2/FixedSticky/index.tsx new file mode 100644 index 0000000000..b04fb2527c --- /dev/null +++ b/packages/semi-ui/table/_story/v2/FixedSticky/index.tsx @@ -0,0 +1,48 @@ +import React, { useState, useMemo, useEffect } from 'react'; +import { Table } from '@douyinfe/semi-ui'; + +function App() { + const DAY = 24 * 60 * 60 * 1000; + const [dataSource, setData] = useState([]); + + const getData = () => { + const data = []; + for (let i = 0; i < 46; i++) { + const isSemiDesign = i % 2 === 0; + const randomNumber = (i * 1000) % 199; + data.push({ + key: '' + i, + name: isSemiDesign ? `Semi Design 设计稿${i}.fig` : `Semi Pro 设计稿${i}.fig`, + owner: isSemiDesign ? '姜鹏志' : '郝宣', + size: randomNumber, + updateTime: new Date('2023-01-31').valueOf() + randomNumber * DAY, + avatarBg: isSemiDesign ? 'grey' : 'red', + }); + } + return data; + }; + + useEffect(() => { + const data = getData(); + setData(data); + }, []); + + return ( +
+
+

top = 100 + no fixed column + no scroll

+
+ + + + + + +
+
+
+
+ ); +} + +export default App; diff --git a/packages/semi-ui/table/_story/v2/index.js b/packages/semi-ui/table/_story/v2/index.js index 86682f6258..df992e101e 100644 --- a/packages/semi-ui/table/_story/v2/index.js +++ b/packages/semi-ui/table/_story/v2/index.js @@ -20,3 +20,4 @@ export { EllipsisNormalTable, EllipsisFixedTable, ShowTitleTable } from './FeatE export { default as Fixed1556 } from './Fixed1556'; export { default as FixedColumnAlign } from './FixedColumnAlign'; export { default as FixOnChange } from './FixOnChange'; +export { default as FixedSticky } from './FixedSticky'; diff --git a/packages/semi-ui/tagInput/_story/tagInput.stories.jsx b/packages/semi-ui/tagInput/_story/tagInput.stories.jsx index 774a6cc6c7..223988aa82 100644 --- a/packages/semi-ui/tagInput/_story/tagInput.stories.jsx +++ b/packages/semi-ui/tagInput/_story/tagInput.stories.jsx @@ -77,19 +77,44 @@ ShowClear.story = { name: 'showClear', }; -export const Draggable = () => ( - <> - -
- - -); +export const Draggable = () => { + const renderTagItem = useCallback((value, index, onClose) => ( +
+ + {`${value}`} + + { + onClose(e); + e.stopPropagation(); + e.nativeEvent.stopImmediatePropagation(); + }} /> +
), []); + + return ( + <> + +
+ +
+ + ); +}; Draggable.story = { name: 'draggable', diff --git a/packages/semi-ui/tagInput/index.tsx b/packages/semi-ui/tagInput/index.tsx index f693829a3f..bf1e673b6b 100644 --- a/packages/semi-ui/tagInput/index.tsx +++ b/packages/semi-ui/tagInput/index.tsx @@ -20,8 +20,8 @@ import Input from '../input'; import Popover, { PopoverProps } from '../popover'; import Paragraph from '../typography/paragraph'; import { IconClear, IconHandle } from '@douyinfe/semi-icons'; -import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import { ShowTooltip } from '../typography'; +import { RenderItemProps, Sortable } from '../_sortable'; const prefixCls = cssClasses.PREFIX; @@ -29,19 +29,9 @@ export type Size = ArrayElement; export type RestTagsPopoverProps = PopoverProps; type ValidateStatus = "default" | "error" | "warning"; -const SortableItem = SortableElement(props => props.item); - -const SortableList = SortableContainer( - ({ items }) => { - return ( -
- {items.map((item, index) => ( - // @ts-ignore skip SortableItem type check - - ))} -
- ); - }); +function SortContainer(props) { + return
; +} export interface TagInputProps { className?: string; @@ -406,6 +396,11 @@ class TagInput extends BaseComponent { } getAllTags = () => { + const { tagsArray } = this.state; + return tagsArray.map((value, index) => this.renderTag(value, index)); + } + + renderTag = (value: any, index: number, sortableHandle?: any) => { const { size, disabled, @@ -413,7 +408,7 @@ class TagInput extends BaseComponent { showContentTooltip, draggable, } = this.props; - const { tagsArray, active } = this.state; + const { active } = this.state; const showIconHandler = active && draggable; const tagCls = cls(`${prefixCls}-wrapper-tag`, { [`${prefixCls}-wrapper-tag-size-${size}`]: size, @@ -426,41 +421,46 @@ class TagInput extends BaseComponent { [`${prefixCls}-drag-item`]: showIconHandler, [`${prefixCls}-wrapper-tag-icon`]: showIconHandler, }); - const DragHandle = SortableHandle(() => ); - return tagsArray.map((value, index) => { - const elementKey = showIconHandler ? value : `${index}${value}`; - const onClose = () => { - !disabled && this.handleTagClose(index); - }; - if (isFunction(renderTagItem)) { - return showIconHandler? (
- - {renderTagItem(value, index, onClose)} -
) : renderTagItem(value, index, onClose); - } else { - return ( - ); + const elementKey = showIconHandler ? value : `${index}${value}`; + const onClose = () => { + !disabled && this.handleTagClose(index); + }; + if (isFunction(renderTagItem)) { + return (
+ {showIconHandler && sortableHandle ? : null} + {renderTagItem(value, index, onClose)} +
); + } else { + return ( + + {showIconHandler && sortableHandle ? : null} + - {showIconHandler && } - - {value} - - - ); - } - }); + {value} + +
+ ); + } + } + + renderSortTag = (props: RenderItemProps) => { + const { id: item, sortableHandle } = props; + const { tagsArray } = this.state; + const index = tagsArray.indexOf(item as string); + return this.renderTag(item, index, sortableHandle); } onSortEnd = (callbackProps: OnSortEndProps) => { @@ -498,9 +498,15 @@ class TagInput extends BaseComponent { })); if (active && draggable && sortableListItems.length > 0) { - // helperClass:add styles to the helper(item being dragged) https://github.com/clauderic/react-sortable-hoc/issues/87 - // @ts-ignore skip SortableItem type check - return ; + return ; } return ( <> diff --git a/packages/semi-ui/transfer/_story/transfer.stories.jsx b/packages/semi-ui/transfer/_story/transfer.stories.jsx index e426d69f61..8e4e208e45 100644 --- a/packages/semi-ui/transfer/_story/transfer.stories.jsx +++ b/packages/semi-ui/transfer/_story/transfer.stories.jsx @@ -1,9 +1,29 @@ -import React, { useState, useRef } from 'react'; +import React, { useState, useRef, useCallback, useEffect, useMemo } from 'react'; +import { createPortal } from 'react-dom'; import { Transfer, Button, Popover, SideSheet, Avatar, Checkbox, Tree, Input, Tag } from '../../index'; -import { omit, values } from 'lodash'; +import { omit, values, isNull } from 'lodash'; import './transfer.scss'; -import { SortableContainer, SortableElement, sortableHandle } from 'react-sortable-hoc'; import { IconClose, IconSearch, IconHandle } from '@douyinfe/semi-icons'; +import { + useSortable, + SortableContext, + sortableKeyboardCoordinates, + verticalListSortingStrategy, +} from '@dnd-kit/sortable'; + +import { CSS as cssDndKit } from '@dnd-kit/utilities'; + +import { + closestCenter, + DragOverlay, + DndContext, + MouseSensor, + TouchSensor, + useSensor, + useSensors, + KeyboardSensor, + TraversalOrder +} from '@dnd-kit/core'; export default { title: 'Transfer' @@ -28,12 +48,12 @@ const commonProps = { }, }; -const data = Array.from({ length: 100 }, (v, i) => { +const data = Array.from({ length: 20 }, (v, i) => { return { label: `选项名称${i}`, value: i, disabled: false, - key: i, + key: `key-${i}`, }; }); @@ -165,7 +185,7 @@ export const TransferDraggableAndDisabled = () => { return { label: `选项名称 ${i}`, value: i, - key: i, + key: `key-${i}`, disabled: true, }; }); @@ -306,8 +326,11 @@ export const CustomFilterRenderSourceItemRenderSelectedItem = () => { ); }; const renderSelectedItem = item => { + const { sortableHandle } = item; + const DragHandle = sortableHandle(() => ); return (
+ {item.abbr} @@ -322,6 +345,7 @@ export const CustomFilterRenderSourceItemRenderSelectedItem = () => { return (
items.indexOf(id), [items]); + const activeIndex = useMemo(() => activeId ? getIndex(activeId) : -1, [getIndex, activeId]); + + const onDragStart = useCallback(({ active }) => { + if (!active) { return; } + setActiveId(active.id); + }, []); + + const onDragEnd = useCallback(({ over }) => { + setActiveId(null); + if (over) { + const overIndex = getIndex(over.id); + if (activeIndex !== overIndex) { + onSortEnd({ oldIndex: activeIndex, newIndex: overIndex }); + } + } + }, [activeIndex, getIndex, onSortEnd]); + + const onDragCancel = useCallback(() => { + setActiveId(null); + }, []); + + return ( + + +
+ {items.map((value, index) => ( + + ))} +
+ {createPortal( + + {activeId ? ( + renderItem({ + id: activeId, + sortableHandle: (WrapperComponent) => WrapperComponent + }) + ) : null} + , + document.body + )} +
+
+ ); +} + +function SortableItem({ getNewIndex, id, renderItem }) { + const { + listeners, + setNodeRef, + transform, + transition, + active, + isOver, + attributes, + } = useSortable({ + id, + getNewIndex, + }); + + const sortableHandle = useCallback((WrapperComponent) => { + return () => ; + }, [listeners]); + + const wrapperStyle = { + transform: cssDndKit.Transform.toString({ + ...transform, + scaleX: 1, + scaleY: 1, + }), + transition: transition, + opacity: active && active.id === id ? 0 : undefined, + }; + + return
+ {renderItem({ id, sortableHandle })} +
; +} + class CustomRenderDragDemo extends React.Component { constructor(props) { - super(props); - this.state = { - dataSource: Array.from({ length: 100 }, (v, i) => ({ - label: `海底捞门店 ${i}`, - value: i, - disabled: false, - key: i, - })), - }; - this.renderSourcePanel = this.renderSourcePanel.bind(this); - this.renderSelectedPanel = this.renderSelectedPanel.bind(this); - this.renderItem = this.renderItem.bind(this); + super(props); + this.state = { + dataSource: Array.from({ length: 10 }, (v, i) => ({ + label: `海底捞门店 ${i}`, + value: i, + disabled: false, + key: `key-${i}`, + })), + }; + this.renderSourcePanel = this.renderSourcePanel.bind(this); + this.renderSelectedPanel = this.renderSelectedPanel.bind(this); + this.renderItem = this.renderItem.bind(this); } - renderItem(type, item, onItemAction, selectedItems) { - let buttonText = '删除'; - let newItem = item; + renderItem(type, item, onItemAction, selectedItems, sortableHandle) { + let buttonText = '删除'; - if (type === 'source') { - let checked = selectedItems.has(item.key); - buttonText = checked ? '删除' : '添加'; - } else { - // delete newItem._optionKey; - newItem = { ...item, key: item._optionKey }; - delete newItem._optionKey; - } - - const DragHandle = sortableHandle(() => ); + if (type === 'source') { + let checked = selectedItems.has(item.key); + buttonText = checked ? '删除' : '添加'; + } - return ( -
- {type === 'source' ? null : } -
-

{item.label}

- -
-
- ); + const DragHandle = (sortableHandle && sortableHandle(() => )); + + return ( +
+ {type === 'source' ? null : ( DragHandle ? : null) } +
+

{item.label}

+ +
+
+ ); } renderSourcePanel(props) { - const { - loading, - noMatch, - filterData, - selectedItems, - allChecked, - onAllClick, - inputValue, - onSearch, - onSelectOrRemove, - } = props; - let content; - switch (true) { - case loading: - content = ; - break; - case noMatch: - content =
{inputValue ? '无搜索结果' : '暂无内容'}
; - break; - case !noMatch: - content = filterData.map(item => - this.renderItem('source', item, onSelectOrRemove, selectedItems) - ); - break; - default: - content = null; - break; - } - return ( -
-
门店列表
-
- } - onChange={onSearch} - showClear - /> -
- 待选门店: {filterData.length} - -
-
{content}
-
-
- ); + const { + loading, + noMatch, + filterData, + selectedItems, + allChecked, + onAllClick, + inputValue, + onSearch, + onSelectOrRemove, + } = props; + let content; + switch (true) { + case loading: + content = ; + break; + case noMatch: + content =
{inputValue ? '无搜索结果' : '暂无内容'}
; + break; + case !noMatch: + content = filterData.map(item => this.renderItem('source', item, onSelectOrRemove, selectedItems)); + break; + default: + content = null; + break; + } + return ( +
+
门店列表
+
+ } + onChange={onSearch} + showClear + /> +
+ 待选门店: {filterData.length} + +
+
{content}
+
+
+ ); } renderSelectedPanel(props) { - const { selectedData, onClear, clearText, onRemove, onSortEnd } = props; - - let mainContent = null; - - if (!selectedData.length) { - mainContent =
暂无数据,请从左侧筛选
; - } + const { selectedData, onClear, clearText, onRemove, onSortEnd } = props; + let mainContent = null; - const SortableItem = SortableElement(item => this.renderItem('selected', item, onRemove)); - const SortableList = SortableContainer( - ({ items }) => { - return ( -
- {items.map((item, index) => ( - // sortableElement will take over the property 'key', so use another '_optionKey' to pass - // otherwise you can't get `key` property in this.renderItem - - ))} -
- ); - }, - { distance: 10 } - ); + if (!selectedData.length) { + mainContent =
暂无数据,请从左侧筛选
; + } - mainContent = ( - - ); + const renderSelectItem = ({ id, sortableHandle }) => { + const item = selectedData.find(item => id === item.key); + return this.renderItem('selected', item, onRemove, null, sortableHandle); + }; - return ( -
-
-
已选同步门店: {selectedData.length}
- -
- {mainContent} -
- ); + const sortData = selectedData.map(item => item.key); + + mainContent =
+ +
; + + return ( +
+
+
已选同步门店: {selectedData.length}
+ +
+ {mainContent} +
+ ); } render() { - const { dataSource } = this.state; - return ( - console.log(values)} - className="component-transfer-demo-custom-panel" - renderSourcePanel={this.renderSourcePanel} - renderSelectedPanel={this.renderSelectedPanel} - dataSource={dataSource} - /> - ); + const { dataSource } = this.state; + return ( + console.log(values)} + className="component-transfer-demo-custom-panel" + renderSourcePanel={this.renderSourcePanel} + renderSelectedPanel={this.renderSelectedPanel} + dataSource={dataSource} + /> + ); } } diff --git a/packages/semi-ui/transfer/index.tsx b/packages/semi-ui/transfer/index.tsx index ee1dc2bf46..46dc2f79d6 100644 --- a/packages/semi-ui/transfer/index.tsx +++ b/packages/semi-ui/transfer/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; import cls from 'classnames'; -import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import PropTypes from 'prop-types'; import { isEqual, noop, omit, isEmpty, isArray, pick } from 'lodash'; import TransferFoundation, { TransferAdapter, BasicDataItem, OnSortEndProps } from '@douyinfe/semi-foundation/transfer/foundation'; @@ -17,6 +16,8 @@ import Button from '../button'; import Tree from '../tree'; import { IconClose, IconSearch, IconHandle } from '@douyinfe/semi-icons'; import { Value as TreeValue, TreeProps } from '../tree/interface'; +import { RenderItemProps, Sortable } from '../_sortable'; +import { verticalListSortingStrategy } from '@dnd-kit/sortable'; export interface DataItem extends BasicDataItem { label?: React.ReactNode; @@ -39,7 +40,7 @@ export interface RenderSourceItemProps extends DataItem { export interface RenderSelectedItemProps extends DataItem { onRemove?: () => void; - sortableHandle?: typeof SortableHandle + sortableHandle?: any } export interface EmptyContent { @@ -168,22 +169,6 @@ export interface TransferProps { } const prefixCls = cssClasses.PREFIX; - -// SortableItem & SortableList should not be assigned inside of the render function -const SortableItem = SortableElement(( - (props: DraggableResolvedDataItem) => (props.item.node as React.FC) -)); - -const SortableList = SortableContainer(({ items }: { items: Array }) => ( -
- {items.map((item, index: number) => ( - // @ts-ignore skip SortableItem type check - - ))} -
- // @ts-ignore see reasons: https://github.com/clauderic/react-sortable-hoc/issues/206 -), { distance: 10 }); - class Transfer extends BaseComponent { static propTypes = { style: PropTypes.object, @@ -569,7 +554,7 @@ class Transfer extends BaseComponent { return
{content}
; } - renderRightItem(item: ResolvedDataItem): React.ReactNode { + renderRightItem = (item: ResolvedDataItem, sortableHandle?: any): React.ReactNode => { const { renderSelectedItem, draggable, type, showPath } = this.props; const onRemove = () => this.foundation.handleSelectOrRemove(item); const rightItemCls = cls({ @@ -582,17 +567,17 @@ class Transfer extends BaseComponent { const label = shouldShowPath ? this.foundation._generatePath(item) : item.label; if (renderSelectedItem) { - return renderSelectedItem({ ...item, onRemove, sortableHandle: SortableHandle }); + return renderSelectedItem({ ...item, onRemove, sortableHandle }); } - const DragHandle = SortableHandle(() => ( + const DragHandle = sortableHandle && sortableHandle(() => ( )); return ( // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
- {draggable ? : null} + {draggable && sortableHandle ? : null}
{label}
{ ); } + renderSortItem = (props: RenderItemProps): React.ReactNode => { + const { id, sortableHandle } = props; + const { selectedItems } = this.state; + const selectedData = [...selectedItems.values()]; + const item = selectedData.find(item => item.key === id); + return this.renderRightItem(item, sortableHandle); + } + renderEmpty(type: string, emptyText: React.ReactNode) { const emptyCls = cls({ [`${prefixCls}-empty`]: true, @@ -615,14 +608,15 @@ class Transfer extends BaseComponent { } renderRightSortableList(selectedData: Array) { - const sortableListItems = selectedData.map(item => ({ - ...item, - node: this.renderRightItem(item) - })); - - // helperClass:add styles to the helper(item being dragged) https://github.com/clauderic/react-sortable-hoc/issues/87 - // @ts-ignore skip SortableItem type check - const sortList = ; + const sortItems = selectedData.map(item => item.key); + const sortList = ; return sortList; } diff --git a/packages/semi-ui/typography/numeral.tsx b/packages/semi-ui/typography/numeral.tsx index e3ed83e9de..cafc051fa0 100644 --- a/packages/semi-ui/typography/numeral.tsx +++ b/packages/semi-ui/typography/numeral.tsx @@ -33,7 +33,7 @@ export interface NumeralProps extends Omit strong?: boolean; style?: React.CSSProperties; type?: TypographyBaseType; - underline?: boolean; + underline?: boolean } export default class Numeral extends PureComponent { diff --git a/packages/semi-webpack/package.json b/packages/semi-webpack/package.json index ed1d266eba..90b8f753e7 100644 --- a/packages/semi-webpack/package.json +++ b/packages/semi-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@douyinfe/semi-webpack-plugin", - "version": "2.40.0", + "version": "2.41.1", "description": "", "author": "伍浩威 ", "homepage": "", diff --git a/scripts/sitemap_update.js b/scripts/sitemap_update.js new file mode 100644 index 0000000000..1544bf10d2 --- /dev/null +++ b/scripts/sitemap_update.js @@ -0,0 +1,77 @@ +const axios = require("axios"); +const fastXML = require("fast-xml-parser"); +const fs = require("fs/promises"); +const execa = require("execa"); +const xmlPath = "./sitemap.xml"; + + +const getData = async ()=>{ + const xmlRaw = await fs.readFile(xmlPath, "utf8"); + const { XMLParser, XMLBuilder, XMLValidator } = fastXML; + const parser = new XMLParser({ + ignoreAttributes: false, + ignoreNameSpace: false, + }); + let jsObj = parser.parse(xmlRaw); + + return jsObj; +}; + +const writeData = async (jsObj)=>{ + const { XMLBuilder } = fastXML; + const builder = new XMLBuilder({ + indentBy: " ", + format: true, + ignoreAttributes: false, + ignoreNameSpace: false, + }); + const xmlContent = builder.build(jsObj); + await fs.writeFile(xmlPath, xmlContent); +}; + + +const main = async ()=>{ + const data = await getData(); + const urlMap = {}; + data['urlset'].url.forEach(item=>{ + urlMap[item.loc] = item; + }); + const promiseList = []; + let count = 0; + const urls = Object.keys(urlMap); + const updatedArr = []; + urls.forEach((url)=>{ + const item = urlMap[url]; + promiseList.push(new Promise(async resolve=>{ + const res = await axios.get(url); + if (url.startsWith("https://semi.design/zh-CN") || url.startsWith("https://semi.design/en-US")) { + const lang = url.startsWith("https://semi.design/zh-CN") ? "zh-CN" : "en-US"; + const mdRelativePath = url.replace(`https://semi.design/${lang}/`, ""); + const mdPath = `./content/${mdRelativePath}/${lang==="zh-CN"?"index.md":"index-en-US.md"}`; + const seconds = execa.commandSync(`echo $(git log -1 --pretty="format:%ct" ${mdPath})`, { shell: true }).stdout; + item.lastmod = new Date(seconds * 1000).toISOString(); + } else { + const scm = res.headers['X-Deploy-Scm-Version'] || res.headers['X-Deploy-Scm-Version'.toLowerCase()] || res.headers['X-Deploy-Scm-Version'.toUpperCase()]; + if (item['scm'] && item['scm']!==scm || !item['scm']) { + item['scm'] = scm; + item.lastmod = new Date().toISOString(); + } + } + count++; + console.log(`SiteMap processed ${url} ${count}/${urls.length}`); + resolve(); + }).catch(e=>{ + console.log("error", e, url); + }).finally(()=>{ + updatedArr.push(item); + })); + }); + await Promise.all(promiseList); + updatedArr.sort((itemA, itemB)=>{ + return itemA.loc.localeCompare(itemB.loc); + }); + data['urlset'].url = updatedArr; + await writeData(data); +}; + +main(); diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000000..4233c04ea2 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,1501 @@ + + + + https://semi.design/code/en-US + 2023-08-11T11:08:53.926Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/about/contact + 2023-08-11T11:08:53.913Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/about/known-issues + 2023-08-11T11:08:53.948Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/about/roadmap + 2023-08-11T11:08:53.923Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/about/schema + 2023-08-11T11:08:54.748Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/inspect + 2023-08-11T11:08:54.662Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/mark + 2023-08-11T11:08:54.996Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/mark-icon + 2023-08-11T11:08:54.851Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/mark-library + 2023-08-11T11:08:55.532Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/mark-table + 2023-08-11T11:08:55.341Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/settings + 2023-08-11T11:08:55.193Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/support-list + 2023-08-11T11:08:55.237Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/transform-plugin + 2023-08-11T11:08:55.495Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/translate-logic + 2023-08-11T11:08:55.442Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/d2c/translate-page + 2023-08-11T11:08:55.624Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/start/changelog + 2023-08-11T11:08:55.608Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/start/faq + 2023-08-11T11:08:55.957Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/start/introduction + 2023-08-11T11:08:55.919Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/start/quick-start + 2023-08-11T11:08:55.986Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/start/terms + 2023-08-11T11:08:56.150Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/uikit/create + 2023-08-11T11:08:56.114Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/uikit/figma-usage + 2023-08-11T11:08:56.310Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/uikit/form-usage + 2023-08-11T11:08:56.438Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/uikit/migrate + 2023-08-11T11:08:56.638Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/uikit/rules + 2023-08-11T11:08:56.718Z + weekly + 1.0.0.79 + + + https://semi.design/code/en-US/uikit/table-usage + 2023-08-11T11:08:56.726Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN + 2023-08-11T11:08:56.976Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/about/contact + 2023-08-11T11:08:57.061Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/about/known-issues + 2023-08-11T11:08:57.183Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/about/roadmap + 2023-08-11T11:08:57.172Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/about/schema + 2023-08-11T11:08:57.230Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/inspect + 2023-08-11T11:08:57.238Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/mark + 2023-08-11T11:08:57.538Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/mark-icon + 2023-08-11T11:08:57.461Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/mark-library + 2023-08-11T11:08:57.552Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/mark-table + 2023-08-11T11:08:57.783Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/settings + 2023-08-11T11:08:57.900Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/support-list + 2023-08-11T11:08:57.920Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/transform-plugin + 2023-08-11T11:08:58.160Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/translate-logic + 2023-08-11T11:08:58.162Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/d2c/translate-page + 2023-08-11T11:08:58.277Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/start/changelog + 2023-08-11T11:08:58.096Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/start/faq + 2023-08-11T11:08:58.292Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/start/introduction + 2023-08-11T11:08:58.378Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/start/quick-start + 2023-08-11T11:08:58.572Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/start/terms + 2023-08-11T11:08:58.563Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/uikit/create + 2023-08-11T11:08:58.823Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/uikit/figma-usage + 2023-08-11T11:08:58.850Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/uikit/form-usage + 2023-08-11T11:08:59.046Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/uikit/migrate + 2023-08-11T11:08:59.131Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/uikit/rules + 2023-08-11T11:08:59.268Z + weekly + 1.0.0.79 + + + https://semi.design/code/zh-CN/uikit/table-usage + 2023-08-11T11:08:59.266Z + weekly + 1.0.0.79 + + + https://semi.design/design/zh-CN/feedback/banner + 2023-08-07T07:46:38.201Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/feedback/notification + 2023-08-07T07:46:38.212Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/feedback/popconfirm + 2023-08-07T07:46:38.186Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/feedback/progress + 2023-08-07T07:46:38.240Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/feedback/skeleton + 2023-08-07T07:46:38.196Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/feedback/spin + 2023-08-07T07:46:38.196Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/feedback/toast + 2023-08-07T07:46:38.213Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/handbook/intro + 2023-08-07T07:46:38.208Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/handbook/tools + 2023-08-07T07:46:38.215Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/button + 2023-08-07T07:46:38.255Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/cascader + 2023-08-07T07:46:38.242Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/checkbox + 2023-08-07T07:46:38.242Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/datepicker + 2023-08-07T07:46:38.227Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/form + 2023-08-07T07:46:38.248Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/input + 2023-08-07T07:46:38.255Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/inputnumber + 2023-08-07T07:46:38.239Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/radio + 2023-08-07T07:46:38.270Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/rating + 2023-08-07T07:46:38.249Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/select + 2023-08-07T07:46:38.272Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/slider + 2023-08-07T07:46:38.254Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/switch + 2023-08-07T07:46:38.274Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/taginput + 2023-08-07T07:46:38.280Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/timepicker + 2023-08-07T07:46:38.275Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/transfer + 2023-08-07T07:46:38.292Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/treeselect + 2023-08-07T07:46:38.282Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/input/upload + 2023-08-07T07:46:38.289Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/navigation/anchor + 2023-08-07T07:46:38.289Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/navigation/breadcrumb + 2023-08-07T07:46:38.323Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/navigation/navigation + 2023-08-07T07:46:38.310Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/navigation/pagination + 2023-08-07T07:46:38.329Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/navigation/steps + 2023-08-07T07:46:38.323Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/navigation/tabs + 2023-08-07T07:46:38.351Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/navigation/tree + 2023-08-07T07:46:38.334Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/avatar + 2023-08-07T07:46:38.332Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/badge + 2023-08-07T07:46:38.341Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/calendar + 2023-08-07T07:46:38.404Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/card + 2023-08-07T07:46:38.367Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/collapse + 2023-08-07T07:46:38.389Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/descriptions + 2023-08-07T07:46:38.406Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/dropdown + 2023-08-07T07:46:38.383Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/list + 2023-08-07T07:46:38.391Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/modal + 2023-08-07T07:46:38.427Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/popover + 2023-08-07T07:46:38.410Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/scrolllist + 2023-08-07T07:46:38.394Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/table + 2023-08-07T07:46:38.435Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/tag + 2023-08-07T07:46:38.395Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/timeline + 2023-08-07T07:46:38.413Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/show/tooltip + 2023-08-07T07:46:38.410Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/visual/colors + 2023-08-07T07:46:38.502Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/visual/dark-mode + 2023-08-07T07:46:38.444Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/visual/data-format + 2023-08-07T07:46:38.417Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/visual/grid + 2023-08-07T07:46:38.486Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/visual/iconography + 2023-08-07T07:46:38.469Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/visual/layout + 2023-08-07T07:46:38.461Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/visual/spacings + 2023-08-07T07:46:38.451Z + weekly + 1.0.0.125 + + + https://semi.design/design/zh-CN/visual/typography + 2023-08-07T07:46:38.473Z + weekly + 1.0.0.125 + + + https://semi.design/dsm_manual/zh-CN/introduction/case + 2023-08-07T07:46:38.495Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/introduction/changelog + 2023-08-07T07:46:38.501Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/introduction/faq + 2023-08-07T07:46:38.992Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/introduction/roadmap + 2023-08-07T07:46:38.503Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/introduction/start + 2023-08-07T07:46:38.516Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/plugin/changeThemeModel + 2023-08-07T07:46:38.855Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/plugin/genDocs + 2023-08-07T07:46:38.531Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/plugin/intallPlugin + 2023-08-07T07:46:38.544Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/plugin/syncInFigma + 2023-08-07T07:46:38.533Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/plugin/writeTheme + 2023-08-07T07:46:38.539Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/themeStore/fork + 2023-08-07T07:46:38.537Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/themeStore/preview + 2023-08-07T07:46:38.551Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/themeStore/publish + 2023-08-07T07:46:38.561Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/web/addPartner + 2023-08-07T07:46:38.579Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/web/componentToken + 2023-08-07T07:46:38.570Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/web/globalToken + 2023-08-07T07:46:38.578Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/web/use + 2023-08-07T07:46:38.585Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/web/web_publish + 2023-08-07T07:46:38.577Z + weekly + 1.0.0.59 + + + https://semi.design/dsm_manual/zh-CN/web/web_start + 2023-08-07T07:46:38.591Z + weekly + 1.0.0.59 + + + https://semi.design/dsm/landing + 2023-08-10T08:46:51.456Z + weekly + 1.0.0.141 + + + https://semi.design/en-US/basic/divider + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/basic/grid + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/basic/icon + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/basic/layout + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/basic/space + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/basic/tokens + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/basic/typography + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/feedback/banner + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/feedback/notification + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/feedback/popconfirm + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/feedback/progress + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/feedback/skeleton + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/feedback/spin + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/feedback/toast + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/autocomplete + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/button + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/cascader + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/checkbox + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/datepicker + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/form + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/input + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/inputnumber + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/radio + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/rating + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/select + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/slider + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/switch + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/taginput + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/timepicker + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/transfer + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/treeselect + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/input/upload + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/navigation/anchor + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/navigation/backtop + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/navigation/breadcrumb + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/navigation/navigation + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/navigation/pagination + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/navigation/steps + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/navigation/tabs + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/navigation/tree + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/other/configprovider + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/other/locale + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/avatar + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/badge + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/calendar + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/card + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/carousel + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/collapse + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/collapsible + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/descriptions + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/dropdown + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/empty + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/highlight + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/image + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/list + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/modal + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/overflowlist + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/popover + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/scrolllist + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/sidesheet + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/table + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/tag + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/timeline + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/show/tooltip + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/accessibility + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/changelog + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/customize-theme + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/dark-mode + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/faq + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/getting-started + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/introduction + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/overview + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/en-US/start/update-to-v2 + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/basic/divider + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/basic/grid + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/basic/icon + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/basic/layout + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/basic/space + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/basic/tokens + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/basic/typography + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/feedback/banner + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/feedback/notification + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/feedback/popconfirm + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/feedback/progress + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/feedback/skeleton + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/feedback/spin + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/feedback/toast + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/autocomplete + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/button + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/cascader + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/checkbox + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/datepicker + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/form + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/input + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/inputnumber + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/radio + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/rating + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/select + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/slider + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/switch + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/taginput + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/timepicker + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/transfer + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/treeselect + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/input/upload + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/navigation/anchor + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/navigation/backtop + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/navigation/breadcrumb + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/navigation/navigation + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/navigation/pagination + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/navigation/steps + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/navigation/tabs + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/navigation/tree + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/other/configprovider + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/other/locale + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/avatar + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/badge + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/calendar + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/card + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/carousel + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/collapse + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/collapsible + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/descriptions + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/dropdown + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/empty + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/highlight + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/image + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/list + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/modal + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/overflowlist + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/popover + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/scrolllist + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/sidesheet + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/table + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/tag + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/timeline + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/show/tooltip + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/accessibility + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/changelog + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/customize-theme + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/dark-mode + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/faq + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/getting-started + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/introduction + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/overview + 2023-08-11T11:05:14.000Z + weekly + + + https://semi.design/zh-CN/start/update-to-v2 + 2023-08-11T11:05:14.000Z + weekly + + diff --git a/src/components/ComponentOverview/index.jsx b/src/components/ComponentOverview/index.jsx index 5a7ba5ec4e..4c0d5190aa 100644 --- a/src/components/ComponentOverview/index.jsx +++ b/src/components/ComponentOverview/index.jsx @@ -4,7 +4,7 @@ import Card from './card'; const ComponentList = props => { const list = props.code.split(','); return ( -
+
{list.map((item, index) => ( ))} diff --git a/src/components/DesignPageAnchor/index.jsx b/src/components/DesignPageAnchor/index.jsx index 4674784ef6..4e295dd063 100644 --- a/src/components/DesignPageAnchor/index.jsx +++ b/src/components/DesignPageAnchor/index.jsx @@ -34,7 +34,7 @@ const PageAnchor = props => { {getAnchorLink(item.items, currentLayer + 1)} - + ; } else { return { @@ -45,7 +45,7 @@ const PageAnchor = props => { dom?.scrollIntoView(); }}> - + ; } } ); diff --git a/src/components/DesignToken/index.tsx b/src/components/DesignToken/index.tsx index 26861f3b96..f3d96d09b5 100644 --- a/src/components/DesignToken/index.tsx +++ b/src/components/DesignToken/index.tsx @@ -15,7 +15,7 @@ interface Token { key: string; value: string; category: string; - raw: string; + raw: string } interface DesignToken { @@ -24,22 +24,22 @@ interface DesignToken { global: { global: { light: Token[]; - dark: Token[]; + dark: Token[] }; palette: { light: Token[]; - dark: Token[]; + dark: Token[] }; normal: Token[]; - animation: Token[]; + animation: Token[] }; - [key: string]: Token[]; + [key: string]: Token[] } interface TokenMayWithColor extends Token { - color?: string; + color?: string } @@ -59,7 +59,7 @@ const JumpLink = ({ value, availableKeySet }: { value: string; availableKeySet: } }; -const TokenTable = ({ tokenList, designToken, currentTab, mode = 'light' }: { mode?: 'light' | 'dark', tokenList: TokenMayWithColor[]; designToken: DesignToken; currentTab?: string; }): React.ReactElement => { +const TokenTable = ({ tokenList, designToken, currentTab, mode = 'light' }: { mode?: 'light' | 'dark'; tokenList: TokenMayWithColor[]; designToken: DesignToken; currentTab?: string }): React.ReactElement => { const intl = useIntl(); const globalTokenJumpAvailableSet = useMemo(() => { const global = designToken?.global; @@ -169,7 +169,7 @@ const GlobalAnimationToken = ({ designToken }: { designToken: DesignToken }) => animationList.forEach(token => { const tab = token['key'].match(/--semi-transition_([\w\W]+)-/)?.[1] ?? "other"; tokenMap[tab] = [...(tokenMap[tab] ?? []), token]; - }) + }); return tokenMap; }, [animationList]); @@ -180,15 +180,15 @@ const GlobalAnimationToken = ({ designToken }: { designToken: DesignToken }) => {Object.entries(tokenMap).map(([category, tokenList]) => { return - + ; })} - + ; -} +}; const DesignToken = (props: Props): React.ReactElement => { diff --git a/src/components/IconList/IconCategory.jsx b/src/components/IconList/IconCategory.jsx index c1f28f7323..e24c98dcfd 100644 --- a/src/components/IconList/IconCategory.jsx +++ b/src/components/IconList/IconCategory.jsx @@ -16,13 +16,13 @@ const IconCategory = props => { const handleToggle = (i) => { $categorySet((c)=>{ - if(c.has(i)){ + if (c.has(i)) { c.delete(i); } else { c.add(i); } return new Set(Array.from(c)); - }) + }); }; return groups.map((g, i) => (
diff --git a/src/components/example.js b/src/components/example.js index 3f35c200dd..ae76aa7a4a 100644 --- a/src/components/example.js +++ b/src/components/example.js @@ -1,7 +1,7 @@ -import React from 'react' +import React from 'react'; const ExampleContainer = ({ children }) => { return
{ children }
; -} +}; -export default ExampleContainer \ No newline at end of file +export default ExampleContainer; \ No newline at end of file diff --git a/src/components/header.js b/src/components/header.js index b7c2ddf050..d1304dca0c 100644 --- a/src/components/header.js +++ b/src/components/header.js @@ -12,7 +12,7 @@ const Header = ({ location, localeCode, style }) => ( const iframeDOM=document.querySelector('iframe'); try { iframeDOM?.contentWindow?.semidoc?.setDarkmode(mode==='dark'); - } catch (e){ + } catch (e) { } }} diff --git a/src/html.js b/src/html.js index fb3a77e7bb..ba1d13c582 100644 --- a/src/html.js +++ b/src/html.js @@ -155,8 +155,33 @@ export default function HTML(props) { + -