@geode/opengeodeweb-front 10.33.0-rc.2 → 10.33.0

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.
@@ -24,6 +24,7 @@ const emit = defineEmits([
24
24
  "update:scrollTop",
25
25
  "hover:enter",
26
26
  "hover:leave",
27
+ "contextmenu",
27
28
  ]);
28
29
 
29
30
  const {
@@ -45,12 +46,13 @@ const {
45
46
  emit,
46
47
  );
47
48
 
48
- const { virtualScrollRef, stickyHeader, handleScroll, scrollToIndex } = useTreeScroll(
49
- computed(() => ({ scrollTop })),
50
- emit,
51
- displayItems,
52
- actualItemProps,
53
- );
49
+ const { virtualScrollRef, stickyHeader, handleScroll, scrollToIndex, getScrollInfo } =
50
+ useTreeScroll(
51
+ computed(() => ({ scrollTop })),
52
+ emit,
53
+ displayItems,
54
+ actualItemProps,
55
+ );
54
56
 
55
57
  const lastActiveIndex = ref(-1);
56
58
  const focusedIndex = ref(-1);
@@ -108,7 +110,6 @@ const { handleKeyDown } = useTreeKeyboardNav(
108
110
  scrollToIndex,
109
111
  toggleOpen,
110
112
  handleItemClick,
111
- focusedIndex,
112
113
  );
113
114
  </script>
114
115
 
@@ -119,6 +120,7 @@ const { handleKeyDown } = useTreeKeyboardNav(
119
120
  tabindex="0"
120
121
  @keydown="handleKeyDown"
121
122
  @mousedown="treeWrapper.focus()"
123
+ @mouseenter="treeWrapper.focus()"
122
124
  >
123
125
  <StickyHeader
124
126
  v-if="stickyHeader"
@@ -160,6 +162,10 @@ const { handleKeyDown } = useTreeKeyboardNav(
160
162
  handleItemClick(item, index, $event);
161
163
  treeWrapper.focus();
162
164
  "
165
+ @contextmenu.prevent.stop="
166
+ emit('contextmenu', { event: $event, item: item.raw });
167
+ treeWrapper.focus();
168
+ "
163
169
  @mouseenter="emit('hover:enter', { item })"
164
170
  @mouseleave="emit('hover:leave', { item })"
165
171
  >
@@ -169,6 +169,7 @@ function expandAll() {
169
169
  @update:scroll-top="treeviewStore.setScrollTop(mainView.id, $event)"
170
170
  @hover:enter="handleHoverEnter"
171
171
  @hover:leave="handleHoverLeave"
172
+ @contextmenu="emit('show-menu', { event: $event.event, itemId: $event.item.id })"
172
173
  >
173
174
  <template #title="{ item, isLeaf }">
174
175
  <ObjectTreeItemLabel
@@ -174,6 +174,7 @@ function getLeafViewerIds(item) {
174
174
  @update:scroll-top="treeviewStore.setScrollTop(actualViewId, $event)"
175
175
  @hover:enter="handleHoverEnter"
176
176
  @hover:leave="handleHoverLeave"
177
+ @contextmenu="showContextMenu($event.event, $event.item)"
177
178
  >
178
179
  <template #title="{ item, isLeaf }">
179
180
  <ObjectTreeItemLabel
@@ -181,7 +182,7 @@ function getLeafViewerIds(item) {
181
182
  :is-leaf="isLeaf"
182
183
  show-tooltip
183
184
  class="text-body-1"
184
- @contextmenu.prevent.stop="showContextMenu($event, item)"
185
+ @contextmenu="showContextMenu($event, item)"
185
186
  />
186
187
  </template>
187
188
 
@@ -169,6 +169,7 @@ function expandAll() {
169
169
  @update:scroll-top="treeviewStore.setScrollTop(actualViewId, $event)"
170
170
  @hover:enter="handleHoverEnter"
171
171
  @hover:leave="handleHoverLeave"
172
+ @contextmenu="showContextMenu($event.event, $event.item)"
172
173
  >
173
174
  <template #title="{ item, isLeaf }">
174
175
  <ObjectTreeItemLabel
@@ -176,7 +177,7 @@ function expandAll() {
176
177
  :is-leaf="isLeaf"
177
178
  show-tooltip
178
179
  class="text-body-1"
179
- @contextmenu.prevent.stop="showContextMenu($event, item)"
180
+ @contextmenu="showContextMenu($event, item)"
180
181
  />
181
182
  </template>
182
183
 
@@ -1,23 +1,84 @@
1
+ function getBaseIndex(currentIndex, lastIndex, bounds, key) {
2
+ if (currentIndex < 0 || currentIndex > lastIndex) {
3
+ if (bounds) {
4
+ return key === "End" ? lastIndex : bounds.firstVisible;
5
+ }
6
+ return key === "End" ? lastIndex : 0;
7
+ }
8
+ if (bounds) {
9
+ if (currentIndex < bounds.firstVisible - 2) {
10
+ return bounds.firstVisible;
11
+ }
12
+ if (currentIndex > bounds.lastVisible + 2) {
13
+ return bounds.lastVisible;
14
+ }
15
+ }
16
+ return currentIndex;
17
+ }
18
+
1
19
  export function useTreeKeyboardNav(
2
20
  displayItems,
3
21
  emit,
4
22
  scrollToIndex,
5
23
  toggleOpen,
6
24
  handleItemClick,
7
- focusedIndex = ref(-1),
25
+ getScrollInfo,
8
26
  ) {
27
+ const focusedIndex = ref(-1);
28
+
9
29
  function findParentIndex(item, currentIndex) {
10
30
  for (let index = currentIndex - 1; index >= 0; index -= 1) {
11
- if (displayItems.value[index].depth < item.depth) {
31
+ if (displayItems.value[index] && displayItems.value[index].depth < item.depth) {
12
32
  return index;
13
33
  }
14
34
  }
15
35
  return -1;
16
36
  }
17
37
 
18
- function getNextIndex(key, item) {
19
- const lastIndex = displayItems.value.length - 1;
20
- const currentIndex = focusedIndex.value;
38
+ function getVisibleBounds() {
39
+ if (!getScrollInfo) {
40
+ return undefined;
41
+ }
42
+ const info = getScrollInfo();
43
+ if (!info || !info.itemHeight || info.itemHeight <= 0) {
44
+ return undefined;
45
+ }
46
+ const firstVisible = Math.max(0, Math.floor(info.scrollTop / info.itemHeight));
47
+ const visibleCount =
48
+ info.containerHeight > 0 ? Math.floor(info.containerHeight / info.itemHeight) : 1;
49
+ const lastVisible = Math.max(firstVisible, firstVisible + visibleCount - 1);
50
+ return { firstVisible, lastVisible };
51
+ }
52
+
53
+ function handleExpandOrNext(item, currentIndex, lastIndex) {
54
+ if (item && !item.isLeaf && !item.isOpen) {
55
+ toggleOpen(item.raw);
56
+ return currentIndex;
57
+ }
58
+ return Math.min(currentIndex + 1, lastIndex);
59
+ }
60
+
61
+ function handleCollapseOrParent(item, currentIndex) {
62
+ if (item && !item.isLeaf && item.isOpen) {
63
+ toggleOpen(item.raw);
64
+ return currentIndex;
65
+ }
66
+ if (item) {
67
+ const parentIndex = findParentIndex(item, currentIndex);
68
+ return parentIndex === -1 ? currentIndex : parentIndex;
69
+ }
70
+ return currentIndex;
71
+ }
72
+
73
+ function getNextIndex(key) {
74
+ const total = displayItems.value.length;
75
+ if (total === 0) {
76
+ return -1;
77
+ }
78
+ const lastIndex = total - 1;
79
+ const rawIndex = getBaseIndex(focusedIndex.value, lastIndex, getVisibleBounds(), key);
80
+ const currentIndex = Math.max(0, Math.min(rawIndex, lastIndex));
81
+ const item = displayItems.value[currentIndex];
21
82
 
22
83
  if (key === "ArrowDown") {
23
84
  return Math.min(currentIndex + 1, lastIndex);
@@ -31,22 +92,11 @@ export function useTreeKeyboardNav(
31
92
  if (key === "End") {
32
93
  return lastIndex;
33
94
  }
34
-
35
95
  if (key === "ArrowRight") {
36
- if (!item.isLeaf && !item.isOpen) {
37
- toggleOpen(item.raw);
38
- return currentIndex;
39
- }
40
- return Math.min(currentIndex + 1, lastIndex);
96
+ return handleExpandOrNext(item, currentIndex, lastIndex);
41
97
  }
42
-
43
98
  if (key === "ArrowLeft") {
44
- if (!item.isLeaf && item.isOpen) {
45
- toggleOpen(item.raw);
46
- return currentIndex;
47
- }
48
- const parentIndex = findParentIndex(item, currentIndex);
49
- return parentIndex === -1 ? currentIndex : parentIndex;
99
+ return handleCollapseOrParent(item, currentIndex);
50
100
  }
51
101
 
52
102
  return currentIndex;
@@ -57,28 +107,29 @@ export function useTreeKeyboardNav(
57
107
  return;
58
108
  }
59
109
 
60
- const prevIndex = focusedIndex.value;
61
- const item = displayItems.value[focusedIndex.value];
62
-
63
110
  if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) {
64
111
  event.preventDefault();
65
- focusedIndex.value = getNextIndex(event.key, item);
112
+ const prevIndex = focusedIndex.value;
113
+ focusedIndex.value = getNextIndex(event.key);
114
+
115
+ if (focusedIndex.value !== prevIndex) {
116
+ if (prevIndex >= 0 && prevIndex < displayItems.value.length) {
117
+ emit("hover:leave", { item: displayItems.value[prevIndex] });
118
+ }
119
+ if (focusedIndex.value >= 0 && focusedIndex.value < displayItems.value.length) {
120
+ emit("hover:enter", {
121
+ immediate: true,
122
+ item: displayItems.value[focusedIndex.value],
123
+ });
124
+ }
125
+ scrollToIndex(focusedIndex.value);
126
+ }
66
127
  } else if (event.key === "Enter" || event.key === " ") {
67
128
  event.preventDefault();
68
- if (focusedIndex.value !== -1) {
69
- handleItemClick(item);
70
- }
71
- }
72
-
73
- if (focusedIndex.value !== prevIndex) {
74
- if (prevIndex !== -1) {
75
- emit("hover:leave", { item: displayItems.value[prevIndex] });
129
+ if (focusedIndex.value >= 0 && focusedIndex.value < displayItems.value.length) {
130
+ const item = displayItems.value[focusedIndex.value];
131
+ handleItemClick(item, focusedIndex.value);
76
132
  }
77
- emit("hover:enter", {
78
- item: displayItems.value[focusedIndex.value],
79
- immediate: true,
80
- });
81
- scrollToIndex(focusedIndex.value);
82
133
  }
83
134
  }
84
135
 
@@ -1,6 +1,6 @@
1
1
  export function useTreeScroll(propsIn, emit, displayItems, actualItemProps) {
2
2
  const SCROLL_STICKY_THRESHOLD = 10;
3
- const DEFAULT_ITEM_HEIGHT = 44;
3
+ const DEFAULT_ITEM_HEIGHT = 28;
4
4
 
5
5
  const props = toRef(propsIn);
6
6
  const internalScrollTop = ref(props.value.scrollTop || 0);
@@ -81,11 +81,23 @@ export function useTreeScroll(propsIn, emit, displayItems, actualItemProps) {
81
81
  }
82
82
  }
83
83
 
84
+ function getScrollInfo() {
85
+ const container = virtualScrollRef.value?.$el;
86
+ const containerHeight = container ? container.clientHeight : 0;
87
+ const itemHeight = actualItemProps.value?.height || DEFAULT_ITEM_HEIGHT;
88
+ return {
89
+ scrollTop: internalScrollTop.value,
90
+ containerHeight,
91
+ itemHeight,
92
+ };
93
+ }
94
+
84
95
  return {
85
96
  internalScrollTop,
86
97
  virtualScrollRef,
87
98
  stickyHeader,
88
99
  handleScroll,
89
100
  scrollToIndex,
101
+ getScrollInfo,
90
102
  };
91
103
  }
@@ -5,7 +5,7 @@ export function useVirtualTree(propsIn, emit) {
5
5
  value: "id",
6
6
  title: "title",
7
7
  children: "children",
8
- height: 44,
8
+ height: 28,
9
9
  ...props.value.itemProps,
10
10
  }));
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geode/opengeodeweb-front",
3
- "version": "10.33.0-rc.2",
3
+ "version": "10.33.0",
4
4
  "description": "OpenSource Vue/Nuxt/Pinia/Vuetify framework for web applications",
5
5
  "homepage": "https://github.com/Geode-solutions/OpenGeodeWeb-Front",
6
6
  "bugs": {
@@ -39,8 +39,8 @@
39
39
  "build": ""
40
40
  },
41
41
  "dependencies": {
42
- "@geode/opengeodeweb-back": "next",
43
- "@geode/opengeodeweb-viewer": "next",
42
+ "@geode/opengeodeweb-back": "latest",
43
+ "@geode/opengeodeweb-viewer": "latest",
44
44
  "@google-cloud/run": "3.2.0",
45
45
  "@kitware/vtk.js": "33.3.0",
46
46
  "@mdi/font": "7.4.47",