@dataloop-ai/components 0.18.53 → 0.18.55
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.
- package/package.json +1 -1
- package/src/components/basic/DlGrid/DlGrid.vue +139 -94
- package/src/components/basic/DlGrid/types.ts +7 -2
- package/src/components/basic/DlGrid/utils.ts +69 -0
- package/src/components/basic/DlWidget/DlWidget.vue +6 -2
- package/src/components/basic/utils.ts +27 -0
- package/src/components/compound/DlTable/DlTable.vue +23 -13
- package/src/demos/DlGridDemo.vue +303 -22
- package/src/demos/DlWidgetDemo.vue +86 -271
- package/src/components/basic/DlWidget/utils.ts +0 -119
package/package.json
CHANGED
|
@@ -9,14 +9,21 @@
|
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
11
|
<script lang="ts">
|
|
12
|
-
import {
|
|
12
|
+
import { Dictionary } from 'lodash'
|
|
13
13
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
computed,
|
|
15
|
+
defineComponent,
|
|
16
|
+
getCurrentInstance,
|
|
17
|
+
nextTick,
|
|
18
|
+
onMounted,
|
|
19
|
+
PropType,
|
|
20
|
+
ref,
|
|
21
|
+
toRefs,
|
|
22
|
+
watch
|
|
23
|
+
} from 'vue-demi'
|
|
24
|
+
import { getGridTemplate, swapElementsInMatrix } from './utils'
|
|
25
|
+
import { isCustomEvent, getElementAbove } from '../utils'
|
|
26
|
+
import { DlGridMode } from './types'
|
|
20
27
|
|
|
21
28
|
export default defineComponent({
|
|
22
29
|
model: {
|
|
@@ -25,7 +32,7 @@ export default defineComponent({
|
|
|
25
32
|
},
|
|
26
33
|
props: {
|
|
27
34
|
modelValue: {
|
|
28
|
-
type: Array as PropType<number[][]>,
|
|
35
|
+
type: Array as PropType<(string | number)[][]>,
|
|
29
36
|
default: null
|
|
30
37
|
},
|
|
31
38
|
rowGap: {
|
|
@@ -39,111 +46,147 @@ export default defineComponent({
|
|
|
39
46
|
maxElementsPerRow: {
|
|
40
47
|
type: Number,
|
|
41
48
|
default: 3
|
|
49
|
+
},
|
|
50
|
+
mode: {
|
|
51
|
+
type: String as PropType<DlGridMode>,
|
|
52
|
+
default: DlGridMode.LAYOUT
|
|
42
53
|
}
|
|
43
54
|
},
|
|
44
55
|
emits: ['update:model-value', 'layout-changed'],
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
setup(props, { emit }) {
|
|
57
|
+
const vm = getCurrentInstance()
|
|
58
|
+
const grid = ref<HTMLElement | null>(null)
|
|
59
|
+
const { modelValue, mode, rowGap, columnGap, maxElementsPerRow } =
|
|
60
|
+
toRefs(props)
|
|
61
|
+
|
|
62
|
+
const isLayoutMode = computed(() => mode.value == DlGridMode.LAYOUT)
|
|
63
|
+
const isGridMode = computed(() => mode.value == DlGridMode.GRID)
|
|
64
|
+
const isFlexMode = computed(() => mode.value == DlGridMode.FLEX)
|
|
65
|
+
|
|
66
|
+
const gridClass = computed(() =>
|
|
67
|
+
modelValue.value || !isFlexMode.value
|
|
54
68
|
? 'dl-grid-wrapper__grid'
|
|
55
69
|
: 'dl-grid-wrapper__flex'
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
const gridStyles = computed(() => {
|
|
73
|
+
const gridStyles: Dictionary<string | number> = {
|
|
74
|
+
'--row-gap': rowGap.value,
|
|
75
|
+
'--column-gap': columnGap.value
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!isGridMode.value) {
|
|
79
|
+
gridStyles['--element-per-row'] = maxElementsPerRow.value
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return gridStyles
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const layoutChanged = () => {
|
|
86
|
+
emit('layout-changed', modelValue.value)
|
|
56
87
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
immediate: true
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
mounted() {
|
|
74
|
-
this.applyIndexesForChildren()
|
|
75
|
-
},
|
|
76
|
-
methods: {
|
|
77
|
-
applyGridElementStyles() {
|
|
78
|
-
if (!this.modelValue) return
|
|
79
|
-
const gridElements = Array.from(
|
|
80
|
-
(this.$refs.grid as HTMLElement).children
|
|
88
|
+
|
|
89
|
+
const changePosition = (e: CustomEvent) => {
|
|
90
|
+
if (!modelValue.value) {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
const className = grid.value.children[0].classList[0]
|
|
94
|
+
const sourceEl = getElementAbove(e.detail.source, className)
|
|
95
|
+
const targetEl = getElementAbove(e.detail.target, className)
|
|
96
|
+
|
|
97
|
+
const newLayout: (string | number)[][] = swapElementsInMatrix(
|
|
98
|
+
modelValue.value,
|
|
99
|
+
sourceEl,
|
|
100
|
+
targetEl
|
|
81
101
|
)
|
|
82
|
-
|
|
83
|
-
|
|
102
|
+
// Update modelValue is required to trigger visualization of the changes
|
|
103
|
+
emit('update:model-value', newLayout)
|
|
84
104
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
105
|
+
// Force update is required to trigger the re-render of the grid
|
|
106
|
+
vm?.proxy?.$forceUpdate()
|
|
107
|
+
|
|
108
|
+
if (e.detail.endDragging) {
|
|
109
|
+
layoutChanged()
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const applyGridElementStyles = () => {
|
|
114
|
+
const childrenElements = Array.from(grid.value.children)
|
|
115
|
+
const layoutOrder = modelValue.value?.flat() ?? []
|
|
116
|
+
|
|
117
|
+
// The check is needed to avoid errors and incorrect behavior
|
|
118
|
+
if (
|
|
119
|
+
!modelValue.value ||
|
|
120
|
+
childrenElements.length > layoutOrder.flat().length ||
|
|
121
|
+
isFlexMode.value
|
|
122
|
+
) {
|
|
123
|
+
for (const element of childrenElements) {
|
|
124
|
+
const htmlElement = element as HTMLElement
|
|
125
|
+
htmlElement.style.flexGrow = '1'
|
|
126
|
+
}
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let gridTemplate: string[]
|
|
131
|
+
if (isGridMode.value) {
|
|
132
|
+
gridTemplate = getGridTemplate(modelValue.value)
|
|
133
|
+
}
|
|
134
|
+
for (const element of childrenElements) {
|
|
89
135
|
const htmlElement = element as HTMLElement
|
|
136
|
+
const orderIndex: number = layoutOrder
|
|
137
|
+
.flat()
|
|
138
|
+
.findIndex((w) => w === htmlElement.dataset.id)
|
|
139
|
+
if (isGridMode.value) {
|
|
140
|
+
htmlElement.style.gridColumn = gridTemplate[orderIndex]
|
|
141
|
+
}
|
|
90
142
|
htmlElement.style.order = `${orderIndex}`
|
|
91
|
-
htmlElement.style.gridColumn = gridTemplate[orderIndex - 1]
|
|
92
143
|
htmlElement.addEventListener('position-changing', (e) => {
|
|
93
144
|
if (!isCustomEvent(e)) return
|
|
94
|
-
|
|
145
|
+
changePosition(e)
|
|
95
146
|
})
|
|
96
|
-
htmlElement.addEventListener(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
)
|
|
100
|
-
})
|
|
101
|
-
},
|
|
102
|
-
changePosition(e: CustomEvent) {
|
|
103
|
-
if (!this.modelValue) return
|
|
104
|
-
const side = e.detail.side
|
|
105
|
-
const className = (this.$refs.grid as HTMLElement).children[0]
|
|
106
|
-
.classList[0]
|
|
107
|
-
const sourceIndex =
|
|
108
|
-
parseInt(
|
|
109
|
-
getElementAbove(e.detail.source, className).dataset.index
|
|
110
|
-
) + 1
|
|
111
|
-
const targetIndex =
|
|
112
|
-
parseInt(
|
|
113
|
-
getElementAbove(e.detail.target, className).dataset.index
|
|
114
|
-
) + 1
|
|
115
|
-
const sourceMatrixIndex = findIndexInMatrix(
|
|
116
|
-
this.modelValue,
|
|
117
|
-
sourceIndex
|
|
118
|
-
)
|
|
119
|
-
const targetMatrixIndex = findIndexInMatrix(
|
|
120
|
-
this.modelValue,
|
|
121
|
-
targetIndex
|
|
122
|
-
)
|
|
147
|
+
htmlElement.addEventListener('position-changed', layoutChanged)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
123
150
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
targetMatrixIndex,
|
|
128
|
-
side,
|
|
129
|
-
this.maxElementsPerRow
|
|
130
|
-
)
|
|
131
|
-
// Update modelValue is required to trigger visualization of the changes
|
|
132
|
-
this.$emit('update:model-value', newLayout)
|
|
133
|
-
if (e.detail.endDragging) {
|
|
134
|
-
this.layoutChanged()
|
|
151
|
+
const applyIndexesForChildren = () => {
|
|
152
|
+
if (!modelValue.value) {
|
|
153
|
+
return
|
|
135
154
|
}
|
|
136
|
-
|
|
137
|
-
layoutChanged() {
|
|
138
|
-
this.$emit('layout-changed', this.modelValue)
|
|
139
|
-
},
|
|
140
|
-
applyIndexesForChildren() {
|
|
141
|
-
Array.from((this.$refs.grid as HTMLElement).children).forEach(
|
|
155
|
+
Array.from(grid.value.children).forEach(
|
|
142
156
|
(element: Element, index: number) => {
|
|
143
|
-
|
|
157
|
+
const el = element as HTMLElement
|
|
158
|
+
el.dataset.id = `${modelValue.value.flat()[index]}`
|
|
144
159
|
}
|
|
145
160
|
)
|
|
146
161
|
}
|
|
162
|
+
|
|
163
|
+
watch(
|
|
164
|
+
modelValue,
|
|
165
|
+
(val, old) => {
|
|
166
|
+
nextTick(() => {
|
|
167
|
+
if (val) {
|
|
168
|
+
if (val.flat().length !== old?.flat().length) {
|
|
169
|
+
applyIndexesForChildren()
|
|
170
|
+
}
|
|
171
|
+
applyGridElementStyles()
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
},
|
|
175
|
+
{ immediate: true }
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
onMounted(() => {
|
|
179
|
+
applyGridElementStyles()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
isLayoutMode,
|
|
184
|
+
isGridMode,
|
|
185
|
+
isFlexMode,
|
|
186
|
+
gridClass,
|
|
187
|
+
gridStyles,
|
|
188
|
+
grid
|
|
189
|
+
}
|
|
147
190
|
}
|
|
148
191
|
})
|
|
149
192
|
</script>
|
|
@@ -154,9 +197,11 @@ export default defineComponent({
|
|
|
154
197
|
display: grid;
|
|
155
198
|
row-gap: var(--row-gap);
|
|
156
199
|
column-gap: var(--column-gap);
|
|
200
|
+
grid-template-columns: repeat(var(--element-per-row), 1fr);
|
|
157
201
|
}
|
|
158
202
|
&__flex {
|
|
159
203
|
display: flex;
|
|
204
|
+
gap: var(--row-gap);
|
|
160
205
|
flex-wrap: wrap;
|
|
161
206
|
}
|
|
162
207
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { cloneDeep } from 'lodash'
|
|
2
|
+
|
|
3
|
+
function leastCommonMultiple(arr: number[]) {
|
|
4
|
+
if (!arr || !arr.length) {
|
|
5
|
+
return
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const gcd = (a: number, b: number): number => (a ? gcd(b % a, a) : b)
|
|
9
|
+
const lcm = (a: number, b: number): number => (a * b) / gcd(a, b)
|
|
10
|
+
return arr.reduce(lcm)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function buildNewLayoutOrder(
|
|
14
|
+
layout: (string | number)[],
|
|
15
|
+
matrix: (string | number)[][]
|
|
16
|
+
) {
|
|
17
|
+
const template: (string | number)[][] = []
|
|
18
|
+
let index = 0
|
|
19
|
+
|
|
20
|
+
for (const row of matrix) {
|
|
21
|
+
const templateRow: (string | number)[] = []
|
|
22
|
+
for (const cell of row) {
|
|
23
|
+
templateRow.push(layout[index])
|
|
24
|
+
index++
|
|
25
|
+
}
|
|
26
|
+
template.push(templateRow)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return template
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function getGridTemplate(layout: (string | number)[][]) {
|
|
33
|
+
if (!layout) {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const flatLayout = layout.map((el) => el.length)
|
|
38
|
+
const template = []
|
|
39
|
+
const lcm = leastCommonMultiple(flatLayout)
|
|
40
|
+
for (let i = 0; i < flatLayout.length; i++) {
|
|
41
|
+
const columns = flatLayout[i]
|
|
42
|
+
let columnTrack = 1
|
|
43
|
+
for (let j = 0; j < columns; j++) {
|
|
44
|
+
let gridSpan = lcm / columns
|
|
45
|
+
template.push(`${columnTrack} / ${gridSpan + columnTrack}`)
|
|
46
|
+
columnTrack += gridSpan
|
|
47
|
+
gridSpan += gridSpan
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return template
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function swapElementsInMatrix(
|
|
54
|
+
oldLayout: (string | number)[][],
|
|
55
|
+
sourceEl: HTMLElement,
|
|
56
|
+
targetEl: HTMLElement
|
|
57
|
+
) {
|
|
58
|
+
if (!sourceEl || !targetEl) {
|
|
59
|
+
return oldLayout
|
|
60
|
+
}
|
|
61
|
+
const newLayout = cloneDeep(oldLayout).flat(1)
|
|
62
|
+
|
|
63
|
+
const sourceIndex = newLayout.indexOf(sourceEl.dataset.id)
|
|
64
|
+
const targetIndex = newLayout.indexOf(targetEl.dataset.id)
|
|
65
|
+
newLayout.splice(sourceIndex, 1)
|
|
66
|
+
newLayout.splice(targetIndex, 0, sourceEl.dataset.id)
|
|
67
|
+
|
|
68
|
+
return buildNewLayoutOrder(newLayout, oldLayout)
|
|
69
|
+
}
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
import { v4 } from 'uuid'
|
|
67
67
|
import { computed, defineComponent, ref, toRef, PropType } from 'vue-demi'
|
|
68
68
|
import { DlIcon } from '../../essential'
|
|
69
|
-
import { getElementAbove, addMouseEnter, removeMouseEnter } from '
|
|
69
|
+
import { getElementAbove, addMouseEnter, removeMouseEnter } from '../utils'
|
|
70
70
|
import { DlEmptyStateProps } from '../DlEmptyState/types'
|
|
71
71
|
import DlEmptyState from '../DlEmptyState/DlEmptyState.vue'
|
|
72
72
|
|
|
@@ -77,7 +77,10 @@ export default defineComponent({
|
|
|
77
77
|
DlEmptyState
|
|
78
78
|
},
|
|
79
79
|
props: {
|
|
80
|
-
isEmpty:
|
|
80
|
+
isEmpty: {
|
|
81
|
+
type: Boolean,
|
|
82
|
+
default: false
|
|
83
|
+
},
|
|
81
84
|
emptyStateProps: {
|
|
82
85
|
type: Object as PropType<DlEmptyStateProps>,
|
|
83
86
|
default: null
|
|
@@ -126,6 +129,7 @@ export default defineComponent({
|
|
|
126
129
|
if (draggedWidget.value && clone.value) {
|
|
127
130
|
clone.value.appendChild(draggedWidget.value.cloneNode(true))
|
|
128
131
|
clone.value.style.visibility = 'visible'
|
|
132
|
+
clone.value.style.position = 'fixed'
|
|
129
133
|
clone.value.style.width = `${draggedWidget.value.offsetWidth}px`
|
|
130
134
|
clone.value.style.height = `${draggedWidget.value.offsetHeight}px`
|
|
131
135
|
clone.value.style.backgroundColor = `var(--dl-color-bg)`
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function getElementAbove(el: HTMLElement, className: string) {
|
|
2
|
+
//@ts-ignore
|
|
3
|
+
for (; el && el !== document; el = el.parentNode) {
|
|
4
|
+
if (el.classList.contains(className)) {
|
|
5
|
+
return el
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function addMouseEnter(className: string, method: EventListenerObject) {
|
|
11
|
+
Array.from(document.getElementsByClassName(className)).forEach((widget) => {
|
|
12
|
+
widget.addEventListener('mouseenter', method)
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function removeMouseEnter(
|
|
17
|
+
className: string,
|
|
18
|
+
method: EventListenerObject
|
|
19
|
+
) {
|
|
20
|
+
Array.from(document.getElementsByClassName(className)).forEach((widget) => {
|
|
21
|
+
widget.removeEventListener('mouseenter', method)
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isCustomEvent(event: Event): event is CustomEvent {
|
|
26
|
+
return 'detail' in event
|
|
27
|
+
}
|
|
@@ -550,7 +550,8 @@ import {
|
|
|
550
550
|
getCurrentInstance,
|
|
551
551
|
ComputedRef,
|
|
552
552
|
onMounted,
|
|
553
|
-
toRef
|
|
553
|
+
toRef,
|
|
554
|
+
toRefs
|
|
554
555
|
} from 'vue-demi'
|
|
555
556
|
import { props } from './utils/props'
|
|
556
557
|
import { emits } from './utils/emits'
|
|
@@ -608,8 +609,16 @@ export default defineComponent({
|
|
|
608
609
|
emits,
|
|
609
610
|
setup(props, { emit, slots }) {
|
|
610
611
|
const vm = getCurrentInstance()
|
|
611
|
-
|
|
612
|
-
|
|
612
|
+
const {
|
|
613
|
+
tableStyle,
|
|
614
|
+
tableClass,
|
|
615
|
+
tableHeaderStyle,
|
|
616
|
+
tableHeaderClass,
|
|
617
|
+
dense,
|
|
618
|
+
draggable
|
|
619
|
+
} = toRefs(props)
|
|
620
|
+
|
|
621
|
+
const rootRef = ref<HTMLDivElement>(null)
|
|
613
622
|
const virtScrollRef = ref(null)
|
|
614
623
|
const hasVirtScroll = computed(() => props.virtualScroll === true)
|
|
615
624
|
|
|
@@ -691,10 +700,10 @@ export default defineComponent({
|
|
|
691
700
|
})
|
|
692
701
|
|
|
693
702
|
const hasDraggableRows = computed(() =>
|
|
694
|
-
['rows', 'both'].includes(
|
|
703
|
+
['rows', 'both'].includes(draggable.value)
|
|
695
704
|
)
|
|
696
705
|
const hasDraggableColumns = computed(() =>
|
|
697
|
-
['columns', 'both'].includes(
|
|
706
|
+
['columns', 'both'].includes(draggable.value)
|
|
698
707
|
)
|
|
699
708
|
|
|
700
709
|
let removeDraggableRows = () => {}
|
|
@@ -808,12 +817,13 @@ export default defineComponent({
|
|
|
808
817
|
)
|
|
809
818
|
|
|
810
819
|
watch(
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
__containerClass
|
|
820
|
+
[
|
|
821
|
+
tableStyle,
|
|
822
|
+
tableClass,
|
|
823
|
+
tableHeaderStyle,
|
|
824
|
+
tableHeaderClass,
|
|
825
|
+
__containerClass
|
|
826
|
+
],
|
|
817
827
|
() => {
|
|
818
828
|
if (
|
|
819
829
|
hasVirtScroll.value === true &&
|
|
@@ -828,7 +838,7 @@ export default defineComponent({
|
|
|
828
838
|
useTablePaginationState(vm, getCellValue)
|
|
829
839
|
|
|
830
840
|
watch(
|
|
831
|
-
[computedPagination,
|
|
841
|
+
[computedPagination, dense],
|
|
832
842
|
() => {
|
|
833
843
|
if (tableEl && props.resizable && resizableManager) {
|
|
834
844
|
const tableHeight = tableEl.offsetHeight || 0
|
|
@@ -1075,7 +1085,7 @@ export default defineComponent({
|
|
|
1075
1085
|
toIndex = parseInt(toIndex as string, 10)
|
|
1076
1086
|
const rowEl = rootRef.value.querySelector(
|
|
1077
1087
|
`tbody tr:nth-of-type(${toIndex + 1})`
|
|
1078
|
-
)
|
|
1088
|
+
) as HTMLElement
|
|
1079
1089
|
|
|
1080
1090
|
if (rowEl !== null) {
|
|
1081
1091
|
const scrollTarget = rootRef.value.querySelector(
|