@electerm/electerm-react 3.7.16 → 3.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
1
 
2
2
  .tree-control-btn
3
- display none
3
+ display inline-flex
4
+ align-items center
5
+ justify-content center
4
6
  margin-left 3px
5
7
  width 16px
6
8
  line-height 30px
@@ -27,11 +29,6 @@
27
29
  background #000
28
30
  color #eee
29
31
  cursor pointer
30
- &:hover
31
- .tree-control-btn
32
- display inline-block
33
- vertical-align middle
34
- line-height 26px
35
32
  &.item-dragover-top
36
33
  border 2px solid var(--primary)
37
34
  .tree-item-title
@@ -102,3 +99,49 @@
102
99
  flex 1
103
100
  overflow-y auto
104
101
  min-height 0
102
+ position relative
103
+
104
+ .tree-list-virtual-spacer
105
+ position relative
106
+ width 100%
107
+
108
+ .tree-list-virtual-row
109
+ position absolute
110
+ left 0
111
+ right 0
112
+
113
+ .tree-list-row
114
+ box-sizing border-box
115
+ width 100%
116
+ position relative
117
+ &.is-hidden
118
+ visibility hidden
119
+ &:hover
120
+ .tree-item-title
121
+ padding-right 120px
122
+ .tree-item-op-wrap
123
+ opacity 1
124
+ pointer-events auto
125
+
126
+ .tree-list-row-group
127
+ position relative
128
+ padding-left 12px
129
+
130
+ .tree-list-editor-overlay
131
+ position absolute
132
+ right 4px
133
+ z-index 4
134
+
135
+ .tree-item-op-wrap
136
+ position absolute
137
+ top 0
138
+ bottom 0
139
+ right 4px
140
+ display flex
141
+ align-items center
142
+ z-index 3
143
+ opacity 0
144
+ pointer-events none
145
+ &.is-active
146
+ opacity 1
147
+ pointer-events auto
@@ -0,0 +1,112 @@
1
+ import { useEffect, useRef, useState } from 'react'
2
+
3
+ function getMetrics (container, rowHeight) {
4
+ return {
5
+ scrollTop: container?.scrollTop || 0,
6
+ viewportHeight: container?.clientHeight || rowHeight * 12
7
+ }
8
+ }
9
+
10
+ export default function VirtualTreeList (props) {
11
+ const {
12
+ items,
13
+ rowHeight,
14
+ containerRef,
15
+ overscan = 8,
16
+ renderItem,
17
+ insertionGap
18
+ } = props
19
+ const frameRef = useRef(0)
20
+ const [metrics, setMetrics] = useState(() => {
21
+ return getMetrics(containerRef.current, rowHeight)
22
+ })
23
+
24
+ useEffect(() => {
25
+ const container = containerRef.current
26
+ if (!container) {
27
+ return
28
+ }
29
+
30
+ const update = () => {
31
+ setMetrics(prev => {
32
+ const next = getMetrics(container, rowHeight)
33
+ return prev.scrollTop === next.scrollTop &&
34
+ prev.viewportHeight === next.viewportHeight
35
+ ? prev
36
+ : next
37
+ })
38
+ }
39
+
40
+ const scheduleUpdate = () => {
41
+ window.cancelAnimationFrame(frameRef.current)
42
+ frameRef.current = window.requestAnimationFrame(update)
43
+ }
44
+
45
+ update()
46
+ container.addEventListener('scroll', scheduleUpdate, { passive: true })
47
+
48
+ let resizeObserver
49
+ if (window.ResizeObserver) {
50
+ resizeObserver = new window.ResizeObserver(scheduleUpdate)
51
+ resizeObserver.observe(container)
52
+ }
53
+ window.addEventListener('resize', scheduleUpdate)
54
+
55
+ return () => {
56
+ window.cancelAnimationFrame(frameRef.current)
57
+ container.removeEventListener('scroll', scheduleUpdate)
58
+ resizeObserver?.disconnect()
59
+ window.removeEventListener('resize', scheduleUpdate)
60
+ }
61
+ }, [containerRef, rowHeight])
62
+
63
+ const gapIndex = insertionGap?.index ?? Number.POSITIVE_INFINITY
64
+ const gapHeight = insertionGap?.height || 0
65
+ const gapTop = Number.isFinite(gapIndex)
66
+ ? gapIndex * rowHeight
67
+ : Number.POSITIVE_INFINITY
68
+ const { scrollTop, viewportHeight } = metrics
69
+ const adjustedScrollTop = scrollTop > gapTop
70
+ ? scrollTop - gapHeight
71
+ : scrollTop
72
+ const adjustedViewportBottom = scrollTop + viewportHeight > gapTop
73
+ ? scrollTop + viewportHeight - gapHeight
74
+ : scrollTop + viewportHeight
75
+ const startIndex = Math.max(0, Math.floor(adjustedScrollTop / rowHeight) - overscan)
76
+ const endIndex = Math.min(
77
+ items.length,
78
+ Math.ceil(adjustedViewportBottom / rowHeight) + overscan
79
+ )
80
+ const visibleItems = items.slice(startIndex, endIndex)
81
+ const totalHeight = items.length * rowHeight + gapHeight
82
+
83
+ if (!items.length && !gapHeight) {
84
+ return null
85
+ }
86
+
87
+ return (
88
+ <div
89
+ className='tree-list-virtual-spacer'
90
+ style={{ height: totalHeight }}
91
+ >
92
+ {
93
+ visibleItems.map((item, offset) => {
94
+ const index = startIndex + offset
95
+ const top = index * rowHeight + (index >= gapIndex ? gapHeight : 0)
96
+ return (
97
+ <div
98
+ key={item.key}
99
+ className='tree-list-virtual-row'
100
+ style={{
101
+ top,
102
+ height: rowHeight
103
+ }}
104
+ >
105
+ {renderItem(item, index)}
106
+ </div>
107
+ )
108
+ })
109
+ }
110
+ </div>
111
+ )
112
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "3.7.16",
3
+ "version": "3.8.6",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",