@budibase/frontend-core 2.11.33 → 2.11.35

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,17 +1,17 @@
1
1
  {
2
2
  "name": "@budibase/frontend-core",
3
- "version": "2.11.33",
3
+ "version": "2.11.35",
4
4
  "description": "Budibase frontend core libraries used in builder and client",
5
5
  "author": "Budibase",
6
6
  "license": "MPL-2.0",
7
7
  "svelte": "src/index.js",
8
8
  "dependencies": {
9
- "@budibase/bbui": "2.11.33",
10
- "@budibase/shared-core": "2.11.33",
9
+ "@budibase/bbui": "2.11.35",
10
+ "@budibase/shared-core": "2.11.35",
11
11
  "dayjs": "^1.10.8",
12
12
  "lodash": "^4.17.21",
13
13
  "socket.io-client": "^4.6.1",
14
14
  "svelte": "^3.46.2"
15
15
  },
16
- "gitHead": "68771f42f956392fcd330c10fc4ffc13d83aa5e9"
16
+ "gitHead": "04a1a5e9c5a0c2c079fb44d4117d84d98b227e66"
17
17
  }
@@ -17,13 +17,24 @@
17
17
  const { config, dispatch, selectedRows } = getContext("grid")
18
18
  const svelteDispatch = createEventDispatcher()
19
19
 
20
- const select = () => {
20
+ const select = e => {
21
+ e.stopPropagation()
21
22
  svelteDispatch("select")
22
23
  const id = row?._id
23
24
  if (id) {
24
25
  selectedRows.actions.toggleRow(id)
25
26
  }
26
27
  }
28
+
29
+ const bulkDelete = e => {
30
+ e.stopPropagation()
31
+ dispatch("request-bulk-delete")
32
+ }
33
+
34
+ const expand = e => {
35
+ e.stopPropagation()
36
+ svelteDispatch("expand")
37
+ }
27
38
  </script>
28
39
 
29
40
  <GridCell
@@ -56,7 +67,7 @@
56
67
  {/if}
57
68
  {/if}
58
69
  {#if rowSelected && $config.canDeleteRows}
59
- <div class="delete" on:click={() => dispatch("request-bulk-delete")}>
70
+ <div class="delete" on:click={bulkDelete}>
60
71
  <Icon
61
72
  name="Delete"
62
73
  size="S"
@@ -65,12 +76,7 @@
65
76
  </div>
66
77
  {:else}
67
78
  <div class="expand" class:visible={$config.canExpandRows && expandable}>
68
- <Icon
69
- size="S"
70
- name="Maximize"
71
- hoverable
72
- on:click={() => svelteDispatch("expand")}
73
- />
79
+ <Icon size="S" name="Maximize" hoverable on:click={expand} />
74
80
  </div>
75
81
  {/if}
76
82
  </div>
@@ -35,7 +35,7 @@
35
35
  </script>
36
36
 
37
37
  <div bind:this={body} class="grid-body">
38
- <GridScrollWrapper scrollHorizontally scrollVertically wheelInteractive>
38
+ <GridScrollWrapper scrollHorizontally scrollVertically attachHandlers>
39
39
  {#each $renderedRows as row, idx}
40
40
  <GridRow
41
41
  {row}
@@ -17,6 +17,7 @@
17
17
  columnHorizontalInversionIndex,
18
18
  contentLines,
19
19
  isDragging,
20
+ dispatch,
20
21
  } = getContext("grid")
21
22
 
22
23
  $: rowSelected = !!$selectedRows[row._id]
@@ -30,6 +31,7 @@
30
31
  on:focus
31
32
  on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)}
32
33
  on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
34
+ on:click={() => dispatch("rowclick", row)}
33
35
  >
34
36
  {#each $renderedColumns as column, columnIdx (column.name)}
35
37
  {@const cellId = `${row._id}-${column.name}`}
@@ -17,7 +17,11 @@
17
17
 
18
18
  export let scrollVertically = false
19
19
  export let scrollHorizontally = false
20
- export let wheelInteractive = false
20
+ export let attachHandlers = false
21
+
22
+ // Used for tracking touch events
23
+ let initialTouchX
24
+ let initialTouchY
21
25
 
22
26
  $: style = generateStyle($scroll, $rowHeight, $hiddenColumnsWidth)
23
27
 
@@ -27,17 +31,47 @@
27
31
  return `transform: translate3d(${offsetX}px, ${offsetY}px, 0);`
28
32
  }
29
33
 
30
- // Handles a wheel even and updates the scroll offsets
34
+ // Handles a mouse wheel event and updates scroll state
31
35
  const handleWheel = e => {
32
36
  e.preventDefault()
33
- debouncedHandleWheel(e.deltaX, e.deltaY, e.clientY)
37
+ updateScroll(e.deltaX, e.deltaY, e.clientY)
34
38
 
35
39
  // If a context menu was visible, hide it
36
40
  if ($menu.visible) {
37
41
  menu.actions.close()
38
42
  }
39
43
  }
40
- const debouncedHandleWheel = domDebounce((deltaX, deltaY, clientY) => {
44
+
45
+ // Handles touch start events
46
+ const handleTouchStart = e => {
47
+ if (!e.touches?.[0]) return
48
+ initialTouchX = e.touches[0].clientX
49
+ initialTouchY = e.touches[0].clientY
50
+ }
51
+
52
+ // Handles touch move events and updates scroll state
53
+ const handleTouchMove = e => {
54
+ if (!e.touches?.[0]) return
55
+ e.preventDefault()
56
+
57
+ // Compute delta from previous event, and update scroll
58
+ const deltaX = initialTouchX - e.touches[0].clientX
59
+ const deltaY = initialTouchY - e.touches[0].clientY
60
+ updateScroll(deltaX, deltaY)
61
+
62
+ // Store position to reference in next event
63
+ initialTouchX = e.touches[0].clientX
64
+ initialTouchY = e.touches[0].clientY
65
+
66
+ // If a context menu was visible, hide it
67
+ if ($menu.visible) {
68
+ menu.actions.close()
69
+ }
70
+ }
71
+
72
+ // Updates the scroll offset by a certain delta, and ensure scrolling
73
+ // stays within sensible bounds. Debounced for performance.
74
+ const updateScroll = domDebounce((deltaX, deltaY, clientY) => {
41
75
  const { top, left } = $scroll
42
76
 
43
77
  // Calculate new scroll top
@@ -55,15 +89,19 @@
55
89
  })
56
90
 
57
91
  // Hover row under cursor
58
- const y = clientY - $bounds.top + (newScrollTop % $rowHeight)
59
- const hoveredRow = $renderedRows[Math.floor(y / $rowHeight)]
60
- hoveredRowId.set(hoveredRow?._id)
92
+ if (clientY != null) {
93
+ const y = clientY - $bounds.top + (newScrollTop % $rowHeight)
94
+ const hoveredRow = $renderedRows[Math.floor(y / $rowHeight)]
95
+ hoveredRowId.set(hoveredRow?._id)
96
+ }
61
97
  })
62
98
  </script>
63
99
 
64
100
  <div
65
101
  class="outer"
66
- on:wheel={wheelInteractive ? handleWheel : null}
102
+ on:wheel={attachHandlers ? handleWheel : null}
103
+ on:touchstart={attachHandlers ? handleTouchStart : null}
104
+ on:touchmove={attachHandlers ? handleTouchMove : null}
67
105
  on:click|self={() => ($focusedCellId = null)}
68
106
  >
69
107
  <div {style} class="inner">
@@ -205,7 +205,7 @@
205
205
  {/if}
206
206
  </div>
207
207
  <div class="normal-columns" transition:fade|local={{ duration: 130 }}>
208
- <GridScrollWrapper scrollHorizontally wheelInteractive>
208
+ <GridScrollWrapper scrollHorizontally attachHandlers>
209
209
  <div class="row">
210
210
  {#each $renderedColumns as column, columnIdx}
211
211
  {@const cellId = `new-${column.name}`}
@@ -64,7 +64,7 @@
64
64
  </div>
65
65
 
66
66
  <div class="content" on:mouseleave={() => ($hoveredRowId = null)}>
67
- <GridScrollWrapper scrollVertically wheelInteractive>
67
+ <GridScrollWrapper scrollVertically attachHandlers>
68
68
  {#each $renderedRows as row, idx}
69
69
  {@const rowSelected = !!$selectedRows[row._id]}
70
70
  {@const rowHovered = $hoveredRowId === row._id}
@@ -74,6 +74,7 @@
74
74
  class="row"
75
75
  on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)}
76
76
  on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
77
+ on:click={() => dispatch("rowclick", row)}
77
78
  >
78
79
  <GutterCell {row} {rowFocused} {rowHovered} {rowSelected} />
79
80
  {#if $stickyColumn}
@@ -53,18 +53,27 @@
53
53
  }
54
54
  }
55
55
 
56
+ const getLocation = e => {
57
+ return {
58
+ y: e.touches?.[0]?.clientY ?? e.clientY,
59
+ x: e.touches?.[0]?.clientX ?? e.clientX,
60
+ }
61
+ }
62
+
56
63
  // V scrollbar drag handlers
57
64
  const startVDragging = e => {
58
65
  e.preventDefault()
59
- initialMouse = e.clientY
66
+ initialMouse = getLocation(e).y
60
67
  initialScroll = $scrollTop
61
68
  document.addEventListener("mousemove", moveVDragging)
69
+ document.addEventListener("touchmove", moveVDragging)
62
70
  document.addEventListener("mouseup", stopVDragging)
71
+ document.addEventListener("touchend", stopVDragging)
63
72
  isDraggingV = true
64
73
  closeMenu()
65
74
  }
66
75
  const moveVDragging = domDebounce(e => {
67
- const delta = e.clientY - initialMouse
76
+ const delta = getLocation(e).y - initialMouse
68
77
  const weight = delta / availHeight
69
78
  const newScrollTop = initialScroll + weight * $maxScrollTop
70
79
  scroll.update(state => ({
@@ -74,22 +83,26 @@
74
83
  })
75
84
  const stopVDragging = () => {
76
85
  document.removeEventListener("mousemove", moveVDragging)
86
+ document.removeEventListener("touchmove", moveVDragging)
77
87
  document.removeEventListener("mouseup", stopVDragging)
88
+ document.removeEventListener("touchend", stopVDragging)
78
89
  isDraggingV = false
79
90
  }
80
91
 
81
92
  // H scrollbar drag handlers
82
93
  const startHDragging = e => {
83
94
  e.preventDefault()
84
- initialMouse = e.clientX
95
+ initialMouse = getLocation(e).x
85
96
  initialScroll = $scrollLeft
86
97
  document.addEventListener("mousemove", moveHDragging)
98
+ document.addEventListener("touchmove", moveHDragging)
87
99
  document.addEventListener("mouseup", stopHDragging)
100
+ document.addEventListener("touchend", stopHDragging)
88
101
  isDraggingH = true
89
102
  closeMenu()
90
103
  }
91
104
  const moveHDragging = domDebounce(e => {
92
- const delta = e.clientX - initialMouse
105
+ const delta = getLocation(e).x - initialMouse
93
106
  const weight = delta / availWidth
94
107
  const newScrollLeft = initialScroll + weight * $maxScrollLeft
95
108
  scroll.update(state => ({
@@ -99,7 +112,9 @@
99
112
  })
100
113
  const stopHDragging = () => {
101
114
  document.removeEventListener("mousemove", moveHDragging)
115
+ document.removeEventListener("touchmove", moveHDragging)
102
116
  document.removeEventListener("mouseup", stopHDragging)
117
+ document.removeEventListener("touchend", stopHDragging)
103
118
  isDraggingH = false
104
119
  }
105
120
  </script>
@@ -109,6 +124,7 @@
109
124
  class="v-scrollbar"
110
125
  style="--size:{ScrollBarSize}px; top:{barTop}px; height:{barHeight}px;"
111
126
  on:mousedown={startVDragging}
127
+ on:touchstart={startVDragging}
112
128
  class:dragging={isDraggingV}
113
129
  />
114
130
  {/if}
@@ -117,6 +133,7 @@
117
133
  class="h-scrollbar"
118
134
  style="--size:{ScrollBarSize}px; left:{barLeft}px; width:{barWidth}px;"
119
135
  on:mousedown={startHDragging}
136
+ on:touchstart={startHDragging}
120
137
  class:dragging={isDraggingH}
121
138
  />
122
139
  {/if}
@@ -1,4 +1,5 @@
1
1
  import { writable, get } from "svelte/store"
2
+ import { Helpers } from "@budibase/bbui"
2
3
 
3
4
  export const createStores = () => {
4
5
  const copiedCell = writable(null)
@@ -12,7 +13,16 @@ export const createActions = context => {
12
13
  const { copiedCell, focusedCellAPI } = context
13
14
 
14
15
  const copy = () => {
15
- copiedCell.set(get(focusedCellAPI)?.getValue())
16
+ const value = get(focusedCellAPI)?.getValue()
17
+ copiedCell.set(value)
18
+
19
+ // Also copy a stringified version to the clipboard
20
+ let stringified = ""
21
+ if (value != null && value !== "") {
22
+ // Only conditionally stringify to avoid redundant quotes around text
23
+ stringified = typeof value === "object" ? JSON.stringify(value) : value
24
+ }
25
+ Helpers.copyToClipboard(stringified)
16
26
  }
17
27
 
18
28
  const paste = () => {