@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataloop-ai/components",
3
- "version": "0.18.53",
3
+ "version": "0.18.55",
4
4
  "exports": {
5
5
  ".": "./index.ts",
6
6
  "./models": "./models.ts",
@@ -9,14 +9,21 @@
9
9
  </template>
10
10
 
11
11
  <script lang="ts">
12
- import { defineComponent, PropType } from 'vue-demi'
12
+ import { Dictionary } from 'lodash'
13
13
  import {
14
- getGridTemplate,
15
- getElementAbove,
16
- findIndexInMatrix,
17
- swapElemensInMatrix,
18
- isCustomEvent
19
- } from '../DlWidget/utils'
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
- computed: {
46
- gridStyles(): object {
47
- return {
48
- '--row-gap': this.rowGap,
49
- '--column-gap': this.columnGap
50
- }
51
- },
52
- gridClass(): string {
53
- return this.modelValue
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
- watch: {
59
- modelValue: {
60
- handler(val, oldVal) {
61
- this.$nextTick(() => {
62
- if (val) {
63
- if (val.length !== oldVal?.length) {
64
- this.applyIndexesForChildren()
65
- }
66
- this.applyGridElementStyles()
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
- const gridTemplate = getGridTemplate(this.modelValue)
83
- if (gridElements.length > gridTemplate.length) return
102
+ // Update modelValue is required to trigger visualization of the changes
103
+ emit('update:model-value', newLayout)
84
104
 
85
- const order = this.modelValue.flat()
86
- gridElements.forEach((element: Element, index: number) => {
87
- const orderIndex =
88
- order.findIndex((nr: number) => nr === index + 1) + 1
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
- this.changePosition(e)
145
+ changePosition(e)
95
146
  })
96
- htmlElement.addEventListener(
97
- 'position-changed',
98
- this.layoutChanged.bind(this)
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
- const newLayout = swapElemensInMatrix(
125
- this.modelValue,
126
- sourceMatrixIndex,
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
- (element as HTMLElement).dataset.index = `${index}`
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
  }
@@ -1,5 +1,10 @@
1
1
  export interface DlGridLayout {
2
2
  name: string
3
- value: number[][]
3
+ value: (number | string)[][]
4
+ }
5
+
6
+ export enum DlGridMode {
7
+ GRID = 'grid',
8
+ FLEX = 'flex',
9
+ LAYOUT = 'layout'
4
10
  }
5
- export type DlGridSideType = 'left' | 'right'
@@ -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 './utils'
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: Boolean,
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
- const rootRef = ref(null)
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(props.draggable)
703
+ ['rows', 'both'].includes(draggable.value)
695
704
  )
696
705
  const hasDraggableColumns = computed(() =>
697
- ['columns', 'both'].includes(props.draggable)
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
- (props.tableStyle as string) +
813
- props.tableClass +
814
- props.tableHeaderStyle +
815
- props.tableHeaderClass +
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, () => props.dense],
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(