@vcmap/ui 5.0.0-rc.10 → 5.0.0-rc.13

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.
Files changed (165) hide show
  1. package/README.md +12 -5
  2. package/build/build.js +6 -3
  3. package/build/buildHelpers.js +12 -4
  4. package/build/buildPreview.js +7 -0
  5. package/build/getPluginProxies.js +4 -0
  6. package/config/aerowest.config.json +13 -3
  7. package/config/base.config.json +398 -219
  8. package/config/codes.config.json +397 -0
  9. package/config/dev.config.json +375 -1
  10. package/config/graphFeatureInfo.config.json +100 -0
  11. package/config/www.config.json +1232 -0
  12. package/dist/assets/{cesium.eb5667.js → cesium.21663e.js} +0 -0
  13. package/dist/assets/cesium.js +1 -1
  14. package/dist/assets/core.63242d.js +4 -0
  15. package/dist/assets/core.js +1 -1
  16. package/dist/assets/font/OFL.txt +93 -0
  17. package/dist/assets/font/TitilliumWeb-Regular.woff2 +0 -0
  18. package/dist/assets/{index.4ccd4433.js → index.44b91cfe.js} +1 -1
  19. package/dist/assets/{ol.ef03b1.js → ol.88ba9d.js} +0 -0
  20. package/dist/assets/ol.js +1 -1
  21. package/dist/assets/ui.3c2933.css +1 -0
  22. package/dist/assets/ui.3c2933.js +71 -0
  23. package/dist/assets/ui.js +1 -1
  24. package/dist/assets/vue.c897fc.js +9 -0
  25. package/dist/assets/vue.js +2 -1
  26. package/dist/assets/{vuetify.401a29.css → vuetify.147c3a.css} +1 -1
  27. package/dist/assets/{vuetify.401a29.js → vuetify.147c3a.js} +72 -72
  28. package/dist/assets/vuetify.js +2 -2
  29. package/dist/index.html +1 -5
  30. package/index.js +39 -5
  31. package/lib/vue.js +1 -0
  32. package/map.config.json +15 -6
  33. package/package.json +17 -8
  34. package/plugins/@vcmap/create-link/fallbackCreateLink.vue +71 -0
  35. package/plugins/@vcmap/create-link/index.js +83 -0
  36. package/plugins/@vcmap/create-link/package.json +6 -0
  37. package/plugins/@vcmap/pluginExample/index.js +2 -2
  38. package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +20 -3
  39. package/plugins/@vcmap/project-selector/ProjectSelectorComponent.vue +1 -1
  40. package/plugins/@vcmap/project-selector/index.js +1 -1
  41. package/plugins/@vcmap/project-selector/package.json +1 -2
  42. package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +1 -1
  43. package/plugins/@vcmap/theme-changer/index.js +1 -1
  44. package/plugins/@vcmap/theme-changer/package.json +1 -2
  45. package/plugins/categoryTest/Categories.vue +89 -1
  46. package/plugins/categoryTest/Category.vue +1 -1
  47. package/plugins/example/index.js +10 -23
  48. package/plugins/simple-graph/README.md +51 -0
  49. package/plugins/simple-graph/SimpleGraphComponent.vue +70 -0
  50. package/plugins/simple-graph/index.js +17 -0
  51. package/plugins/simple-graph/package.json +11 -0
  52. package/plugins/simple-graph/simpleGraphView.js +76 -0
  53. package/plugins/test/editor.vue +1 -1
  54. package/plugins/test/index.js +76 -9
  55. package/plugins/test/toolbox-data.js +82 -57
  56. package/plugins/test/windowManagerExample.vue +1 -1
  57. package/src/actions/stateRefAction.js +2 -2
  58. package/src/actions/styleSelector.vue +1 -1
  59. package/src/application/Navbar.vue +13 -2
  60. package/src/application/VcsApp.vue +301 -116
  61. package/src/application/VcsMap.vue +1 -1
  62. package/src/application/VcsSettings.vue +1 -1
  63. package/src/application/vcsAppWrapper.vue +1 -0
  64. package/src/assets/font/OFL.txt +93 -0
  65. package/src/assets/font/TitilliumWeb-Regular.woff2 +0 -0
  66. package/src/components/form-inputs-controls/VcsCheckbox.vue +13 -0
  67. package/src/components/form-inputs-controls/VcsColorPicker.vue +1 -1
  68. package/src/components/form-inputs-controls/VcsRadio.vue +123 -0
  69. package/src/components/form-output/VcsFormattedNumber.vue +1 -1
  70. package/src/components/lists/VcsActionList.vue +22 -7
  71. package/src/components/lists/VcsTreeview.vue +4 -4
  72. package/src/components/lists/VcsTreeviewLeaf.vue +10 -3
  73. package/src/components/lists/VcsTreeviewSearchbar.vue +1 -2
  74. package/src/components/tables/VcsTable.vue +245 -0
  75. package/src/contentTree/LayerTree.vue +1 -1
  76. package/src/contentTree/contentTreeCollection.js +4 -4
  77. package/src/contentTree/contentTreeItem.js +9 -9
  78. package/src/contentTree/groupContentTreeItem.js +1 -1
  79. package/src/contentTree/layerContentTreeItem.js +15 -1
  80. package/src/contentTree/layerGroupContentTreeItem.js +21 -1
  81. package/src/contentTree/nodeContentTreeItem.js +1 -1
  82. package/src/featureInfo/AddressBalloonComponent.vue +47 -0
  83. package/src/featureInfo/BalloonComponent.vue +140 -0
  84. package/src/featureInfo/abstractFeatureInfoView.js +313 -0
  85. package/src/featureInfo/addressBalloonFeatureInfoView.js +118 -0
  86. package/src/featureInfo/balloonFeatureInfoView.js +151 -0
  87. package/src/featureInfo/balloonHelper.js +132 -0
  88. package/src/featureInfo/featureInfo.js +457 -0
  89. package/src/featureInfo/featureInfoInteraction.js +42 -0
  90. package/src/featureInfo/iframeFeatureInfoView.js +95 -0
  91. package/src/featureInfo/tableFeatureInfoView.js +106 -0
  92. package/src/i18n/de.js +26 -0
  93. package/src/i18n/en.js +26 -0
  94. package/src/i18n/i18nCollection.js +17 -0
  95. package/src/icons/+all.js +80 -0
  96. package/src/icons/ClippingHorizontalIcon.vue +7 -0
  97. package/src/icons/ClippingIcon.vue +7 -0
  98. package/src/icons/ClippingVerticalIcon.vue +7 -0
  99. package/src/icons/ColorPickerIcon.vue +7 -0
  100. package/src/icons/ComponentsIcon.vue +2 -2
  101. package/src/icons/DimensionsHouseIcon.vue +11 -9
  102. package/src/icons/EditIcon.vue +7 -0
  103. package/src/icons/GlobalTerrainIcon.vue +9 -0
  104. package/src/icons/GroundIcon.vue +18 -0
  105. package/src/icons/HideIcon.vue +12 -0
  106. package/src/icons/LogoutIcon.vue +7 -0
  107. package/src/icons/ObjectAttributeIcon.vue +2 -13
  108. package/src/icons/PedestrianIcon.vue +2 -3
  109. package/src/icons/PenIcon.vue +2 -9
  110. package/src/icons/PoiIcon.vue +5 -2
  111. package/src/icons/PointSelectIcon.vue +4 -2
  112. package/src/icons/QueryIcon.vue +6 -7
  113. package/src/icons/ScreenshotIcon.vue +16 -0
  114. package/src/icons/ShareIcon.vue +4 -16
  115. package/src/icons/SkipNextIcon.vue +3 -1
  116. package/src/icons/TerrainBoxIcon.vue +9 -0
  117. package/src/icons/ToolsIcon.vue +4 -30
  118. package/src/icons/UploadIcon.vue +2 -9
  119. package/src/icons/UserProfileIcon.vue +7 -0
  120. package/src/icons/UserShareIcon.vue +7 -0
  121. package/src/icons/VideoRecorderIcon.vue +5 -9
  122. package/src/icons/ViewpointFlightIcon.vue +11 -0
  123. package/src/icons/ViewpointIcon.vue +11 -0
  124. package/src/icons/Viewshed360Icon.vue +7 -0
  125. package/src/icons/ViewshedConeIcon.vue +7 -0
  126. package/src/icons/ViewshedIcon.vue +7 -0
  127. package/src/icons/WallIcon.vue +4 -9
  128. package/src/legend/legendHelper.js +193 -0
  129. package/src/legend/styleLegendItem.vue +129 -0
  130. package/src/legend/vcsLegend.vue +92 -0
  131. package/src/manager/buttonManager.js +7 -12
  132. package/src/manager/categoryManager/ComponentsManager.vue +30 -0
  133. package/src/manager/categoryManager/categoryManager.js +500 -0
  134. package/src/manager/contextMenu/contextMenuComponent.vue +43 -0
  135. package/src/manager/contextMenu/contextMenuInteraction.js +42 -0
  136. package/src/manager/contextMenu/contextMenuManager.js +197 -0
  137. package/src/manager/navbarManager.js +9 -9
  138. package/src/manager/toolbox/GroupToolboxComponent.vue +118 -0
  139. package/src/manager/toolbox/SelectToolboxComponent.vue +128 -0
  140. package/src/manager/toolbox/ToolboxManager.vue +116 -98
  141. package/src/manager/toolbox/toolboxManager.js +235 -86
  142. package/src/manager/window/WindowComponent.vue +1 -1
  143. package/src/manager/window/WindowManager.vue +5 -3
  144. package/src/manager/window/windowManager.js +118 -14
  145. package/src/navigation/mapNavigation.vue +3 -5
  146. package/src/navigation/overviewMap.js +28 -5
  147. package/src/navigation/vcsCompass.vue +1 -1
  148. package/src/pluginHelper.js +42 -10
  149. package/src/setup.js +0 -2
  150. package/src/state.js +256 -0
  151. package/src/styles/_theming.scss +0 -5
  152. package/src/styles/variables.scss +7 -0
  153. package/src/styles/vcsFont.scss +17 -0
  154. package/src/uiConfig.js +79 -0
  155. package/src/vcsUiApp.js +213 -22
  156. package/src/vuePlugins/vuetify.js +14 -4
  157. package/config/berlin.config.json +0 -510
  158. package/dist/assets/core.216494.js +0 -4
  159. package/dist/assets/ui.99a1a7.css +0 -1
  160. package/dist/assets/ui.99a1a7.js +0 -70
  161. package/dist/assets/vue-composition-api.c5aca1.js +0 -14
  162. package/dist/assets/vue-composition-api.js +0 -2
  163. package/dist/assets/vue.762edd.js +0 -9
  164. package/lib/vue-composition-api.js +0 -2
  165. package/src/manager/toolbox/ToolboxGroupComponent.vue +0 -128
@@ -0,0 +1,197 @@
1
+ import { CesiumMap, BaseOLMap } from '@vcmap/core';
2
+ import { unByKey } from 'ol/Observable.js';
3
+ import { check } from '@vcsuite/check';
4
+ import ContextMenuInteraction from './contextMenuInteraction.js';
5
+ import { vcsAppSymbol } from '../../pluginHelper.js';
6
+ import { validateAction } from '../../components/lists/VcsActionList.vue';
7
+ import { getFittedWindowPositionOptionsFromMapEvent, WindowSlot } from '../window/windowManager.js';
8
+ import ContextMenuComponent, { contextMenuWindowId } from './contextMenuComponent.vue';
9
+ import { sortByOwner } from '../navbarManager.js';
10
+
11
+ /**
12
+ * @typedef {Object} ContextMenuEventHandler
13
+ * @property {string|symbol} owner
14
+ * @property {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
15
+ */
16
+
17
+ /**
18
+ * @param {import("@vcmap/core").VcsMap} map
19
+ * @param {function():void} clear
20
+ * @returns {function():void} - returns stop listener function.
21
+ */
22
+ function setupViewPointChanged(map, clear) {
23
+ const currentViewpoint = map.getViewPointSync();
24
+ const postRenderHandler = () => {
25
+ if (!currentViewpoint.equals(map.getViewPointSync(), 0.001)) {
26
+ clear();
27
+ }
28
+ };
29
+
30
+ if (map instanceof CesiumMap) {
31
+ return map.getScene().postRender.addEventListener(postRenderHandler);
32
+ } else if (map instanceof BaseOLMap) {
33
+ const key = map.olMap.on('postrender', postRenderHandler);
34
+ return () => {
35
+ unByKey(key);
36
+ };
37
+ }
38
+ return () => {};
39
+ }
40
+
41
+ /**
42
+ * The context menu manager handles right click events in the current map and displays a
43
+ * context menu based on registered action providers.
44
+ * @class
45
+ */
46
+ class ContextMenuManager {
47
+ /**
48
+ * @param {VcsUiApp} app
49
+ */
50
+ constructor(app) {
51
+ /**
52
+ * @type {VcsUiApp}
53
+ * @private
54
+ */
55
+ this._app = app;
56
+ /**
57
+ * @type {ContextMenuInteraction}
58
+ * @private
59
+ */
60
+ this._interaction = new ContextMenuInteraction(
61
+ this._handleRightClick.bind(this),
62
+ async () => {
63
+ this.clear();
64
+ },
65
+ );
66
+ /**
67
+ * @type {Array<ContextMenuEventHandler>}
68
+ * @private
69
+ */
70
+ this._eventHandlers = [];
71
+ /**
72
+ * @type {function():void|null}
73
+ * @private
74
+ */
75
+ this._interactionListener = null;
76
+ /**
77
+ * @type {Array<function():void>}
78
+ * @private
79
+ */
80
+ this._listeners = [];
81
+ }
82
+
83
+ _ensureInteraction() {
84
+ if (!this._interactionListener) {
85
+ this._interactionListener = this._app.maps.eventHandler.addPersistentInteraction(this._interaction);
86
+ }
87
+ }
88
+
89
+ _setupListeners() {
90
+ const clear = this.clear.bind(this);
91
+ this._listeners = [
92
+ this._app.layers.stateChanged.addEventListener(clear),
93
+ this._app.maps.mapActivated.addEventListener(clear),
94
+ setupViewPointChanged(this._app.maps.activeMap, clear),
95
+ ];
96
+ }
97
+
98
+ /**
99
+ * @param {import("@vcmap/core").InteractionEvent} event
100
+ * @private
101
+ */
102
+ async _handleRightClick(event) {
103
+ this.clear();
104
+ const actionArrays = await Promise.all(this._eventHandlers.map(({ handler }) => handler(event)));
105
+ const actions = actionArrays
106
+ .filter(i => Array.isArray(i))
107
+ .flatMap(i => i)
108
+ .filter(validateAction);
109
+
110
+ if (actions.length > 0) {
111
+ const position = getFittedWindowPositionOptionsFromMapEvent(event.windowPosition, 320, actions.length * 32);
112
+ if (position.left) { // ensure we nudge the window, so it does not trigger the default right click.
113
+ position.left += 1;
114
+ } else {
115
+ position.right += 1;
116
+ }
117
+
118
+ this._app.windowManager.add({
119
+ id: contextMenuWindowId,
120
+ component: ContextMenuComponent,
121
+ state: {
122
+ hideHeader: true,
123
+ },
124
+ props: {
125
+ actions,
126
+ showIcon: true,
127
+ },
128
+ position,
129
+ slow: WindowSlot.DETACHED,
130
+ }, vcsAppSymbol);
131
+
132
+ this._setupListeners();
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Adds a handler to the context menu. A handler is called with the interaction event on each right click.
138
+ * If the handler returns an array of valid actions, said actions will be displayed in the context menu
139
+ * @param {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
140
+ * @param {string|symbol} owner
141
+ */
142
+ addEventHandler(handler, owner) {
143
+ check(handler, Function);
144
+ check(owner, [String, vcsAppSymbol]);
145
+
146
+ this._ensureInteraction();
147
+ this._eventHandlers.push({ owner, handler });
148
+ const order = [...this._app.plugins].map(p => p.name);
149
+ this._eventHandlers.sort((a, b) => {
150
+ return sortByOwner(a.owner, b.owner, order);
151
+ });
152
+ }
153
+
154
+ /**
155
+ * Remove a single handler
156
+ * @param {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
157
+ */
158
+ removeHandler(handler) {
159
+ this._eventHandlers = this._eventHandlers.filter(({ handler: itemHandler }) => itemHandler !== handler);
160
+ if (this._eventHandlers.length === 0 && this._interactionListener) {
161
+ this._interactionListener();
162
+ this._interactionListener = null;
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Remove all handlers associated with this owner
168
+ * @param {string|symbol} owner
169
+ */
170
+ removeOwner(owner) {
171
+ this._eventHandlers = this._eventHandlers.filter(({ owner: handlerOwner }) => handlerOwner !== owner);
172
+ if (this._eventHandlers.length === 0 && this._interactionListener) {
173
+ this._interactionListener();
174
+ this._interactionListener = null;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Clear any currently opened context menus
180
+ */
181
+ clear() {
182
+ this._listeners.forEach((cb) => { cb(); });
183
+ this._listeners = [];
184
+ this._app.windowManager.remove(contextMenuWindowId);
185
+ }
186
+
187
+ destroy() {
188
+ this._interaction.destroy();
189
+ if (this._interactionListener) {
190
+ this._interactionListener();
191
+ this._interactionListener = null;
192
+ }
193
+ this._eventHandlers = [];
194
+ }
195
+ }
196
+
197
+ export default ContextMenuManager;
@@ -1,20 +1,20 @@
1
1
  import { check } from '@vcsuite/check';
2
- import { ButtonManager } from './buttonManager.js';
2
+ import ButtonManager from './buttonManager.js';
3
3
  import { vcsAppSymbol } from '../pluginHelper.js';
4
4
 
5
5
  export const locationSymbol = Symbol('location');
6
6
 
7
7
  /**
8
8
  * sorts by owner and optionally plugin order
9
- * @param {ButtonComponent} a
10
- * @param {ButtonComponent} b
9
+ * @param {string | symbol} ownerA
10
+ * @param {string | symbol} ownerB
11
11
  * @param {string[]} [order] order of owners to sort by
12
12
  * @returns {number}
13
13
  */
14
- function sortByOwner(a, b, order = []) {
14
+ export function sortByOwner(ownerA, ownerB, order = []) {
15
15
  const sorted = [vcsAppSymbol, ...order];
16
- const indexA = sorted.indexOf(a.owner);
17
- const indexB = sorted.indexOf(b.owner);
16
+ const indexA = sorted.indexOf(ownerA);
17
+ const indexB = sorted.indexOf(ownerB);
18
18
 
19
19
  if (indexA === indexB) {
20
20
  return 0;
@@ -35,19 +35,19 @@ function sortByOwner(a, b, order = []) {
35
35
  * @param {Array<ButtonComponent>} buttonComponents
36
36
  * @param {ButtonLocation} location Button render position
37
37
  * @param {string[]} [order] optional order to sort by (plugin names)
38
- * @param {function(a: ButtonComponent, b: ButtonComponent, order: string[]):number} [compareFn=sortByOwner] Per default components are sorted by owner: app first, then plugins
38
+ * @param {function(ownerA:string, ownerB:string, order: string[]):number} [compareFn=sortByOwner] Per default components are sorted by owner: app first, then plugins
39
39
  * @returns {Array<VcsAction>}
40
40
  */
41
41
  export function getActionsByLocation(buttonComponents, location, order = [], compareFn = sortByOwner) {
42
42
  return [...buttonComponents]
43
43
  .filter(b => b[locationSymbol] === location)
44
- .sort((a, b) => compareFn(a, b, order))
44
+ .sort((a, b) => compareFn(a.owner, b.owner, order))
45
45
  .map(b => b.action);
46
46
  }
47
47
 
48
48
  /**
49
49
  * Possible render positions of buttons in navbar from left to right
50
- * @enum
50
+ * @enum {number}
51
51
  */
52
52
  export const ButtonLocation = {
53
53
  MAP: 0,
@@ -0,0 +1,118 @@
1
+ <template>
2
+ <div v-if="orderedButtons.length > 0">
3
+ <v-menu
4
+ v-model="open"
5
+ @input="$emit('toggle', open)"
6
+ offset-y
7
+ :nudge-left="nudgeLeft"
8
+ z-index="0"
9
+ >
10
+ <template #activator="{ on, attrs }">
11
+ <VcsButton
12
+ class="vcs-toolbox-toogle-button"
13
+ width="48"
14
+ :icon="group.icon"
15
+ :tooltip="group.title"
16
+ :active="open || hasActiveAction"
17
+ :color="hasActiveAction ? 'primary' : 'basic'"
18
+ v-bind="attrs"
19
+ v-on="on"
20
+ large
21
+ >
22
+ <v-icon v-text="open ? 'mdi-chevron-up' : 'mdi-chevron-down'" color="accent" class="text--darken-3" />
23
+ </VcsButton>
24
+ </template>
25
+
26
+ <v-toolbar
27
+ id="vcs-toolbox-toolbar--secondary"
28
+ class="vcs-toolbox-2 toolbar__secondary mx-auto v-sheet marginToTop"
29
+ :height="40"
30
+ width="fit-content"
31
+ color="basic"
32
+ dense
33
+ >
34
+ <v-toolbar-items class="w-full">
35
+ <div class="d-flex align-center justify-space-between w-full mx-1">
36
+ <VcsButton
37
+ v-for="({id, action}) in orderedButtons"
38
+ :key="id"
39
+ :tooltip="action.title"
40
+ :icon="action.icon"
41
+ :active="action.active"
42
+ @click="action.callback($event)"
43
+ v-bind="{...$attrs}"
44
+ large
45
+ />
46
+ </div>
47
+ </v-toolbar-items>
48
+ </v-toolbar>
49
+ </v-menu>
50
+ </div>
51
+ </template>
52
+ <style lang="scss">
53
+ .vcs-toolbox-2 {
54
+ .v-toolbar__content {
55
+ padding: 0;
56
+ }
57
+ }
58
+
59
+ .marginToTop {
60
+ margin-top: 3px;
61
+ }
62
+ </style>
63
+ <script>
64
+ import { computed, ref } from 'vue';
65
+ import VcsButton from '../../components/buttons/VcsButton.vue';
66
+ import { getComponentsByOrder } from './toolboxManager.js';
67
+
68
+ /**
69
+ * @description
70
+ * A Toolbox Button rendering a menu dropdown with actions using {@link https://vuetifyjs.com/en/api/v-menu/|vuetify v-menu} and {@link VcsButton}.
71
+ * The button is rendered in primary color if at least one action is active.
72
+ * The button is rendered in basic color if menu is open and no action is active.
73
+ * @vue-prop {GroupToolboxComponent} group - A toolbox group of type 'group'.
74
+ * @vue-computed {Array<ButtonComponent>} buttons - Buttons of the group.
75
+ * @vue-computed {Array<ButtonComponent>} orderedButtons - Buttons of the group sorted by owner.
76
+ * @vue-computed {boolean} hasActiveAction - Whether the group has an active action.
77
+ * @vue-computed {number} nudgeLeft - offset of the dropdown toolbar to the left
78
+ */
79
+ export default {
80
+ name: 'ToolboxActionGroup',
81
+ components: { VcsButton },
82
+ props: {
83
+ group: {
84
+ type: Object,
85
+ required: true,
86
+ },
87
+ },
88
+ setup(props) {
89
+ const open = ref(false);
90
+
91
+ const buttons = computed(() => {
92
+ const { buttonManager } = props.group;
93
+ const buttonIds = ref(buttonManager.componentIds);
94
+ return buttonIds.value.map(id => buttonManager.get(id));
95
+ });
96
+ const orderedButtons = computed(() => getComponentsByOrder(buttons.value));
97
+ const hasActiveAction = computed(() => orderedButtons.value.some(a => a.action.active));
98
+
99
+ /**
100
+ * v-menu auto prop is not working as expected.
101
+ * Workaround using hardcoded button sizes and paddings
102
+ * @type {ComputedRef<number>}
103
+ */
104
+ const nudgeLeft = computed(() => {
105
+ const toolboxBtnWidth = 42 + 8; // with padding
106
+ const menuBtnWidth = 48;
107
+ return (buttons.value.length * (toolboxBtnWidth / 2)) - (menuBtnWidth / 2);
108
+ });
109
+
110
+ return {
111
+ open,
112
+ orderedButtons,
113
+ nudgeLeft,
114
+ hasActiveAction,
115
+ };
116
+ },
117
+ };
118
+ </script>
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <div
3
+ v-if="group.action"
4
+ :class="{ 'vcs-toolbox-action-select-button--active': open }"
5
+ style="width:fit-content"
6
+ >
7
+ <VcsButton
8
+ :key="group.action.tools[group.action.currentIndex].name"
9
+ :tooltip="group.action.tools[group.action.currentIndex].title"
10
+ :icon="group.action.tools[group.action.currentIndex].icon"
11
+ :active="group.action.active"
12
+ @click.stop="group.action.callback($event)"
13
+ v-bind="{...$attrs}"
14
+ class="vcs-toolbox-action-selected"
15
+ :min-width="32"
16
+ :width="32"
17
+ large
18
+ />
19
+ <v-menu
20
+ v-model="open"
21
+ @input="$emit('toggle', open)"
22
+ offset-y
23
+ :nudge-left="nudgeLeft"
24
+ z-index="0"
25
+ >
26
+ <template #activator="{ on, attrs }">
27
+ <VcsButton
28
+ :tooltip="group.action.title"
29
+ v-bind="attrs"
30
+ v-on="on"
31
+ class="vcs-toolbox-action-select"
32
+ :min-width="16"
33
+ :width="16"
34
+ large
35
+ >
36
+ <v-icon v-text="open ? 'mdi-chevron-up' : 'mdi-chevron-down'" color="accent" class="text--darken-3" />
37
+ </VcsButton>
38
+ </template>
39
+
40
+ <v-toolbar
41
+ class="vcs-toolbox-2 toolbar__secondary mx-auto v-sheet marginToTop justify-center"
42
+ :height="40"
43
+ width="fit-content"
44
+ color="basic"
45
+ dense
46
+ >
47
+ <v-toolbar-items class="w-full">
48
+ <div class="d-flex align-center justify-space-between w-full mx-1">
49
+ <VcsButton
50
+ v-for="(item, index) in group.action.tools"
51
+ :key="`${item.name}-${index}`"
52
+ :tooltip="item.title"
53
+ :icon="item.icon"
54
+ @click="group.action.selected(index)"
55
+ v-bind="{...$attrs}"
56
+ large
57
+ />
58
+ </div>
59
+ </v-toolbar-items>
60
+ </v-toolbar>
61
+ </v-menu>
62
+ </div>
63
+ </template>
64
+ <style lang="scss">
65
+ .vcs-toolbox-action-selected > .v-btn.vcs-button--large {
66
+ max-width: 40px;
67
+ }
68
+
69
+ .vcs-toolbox-action-select > .v-btn.vcs-button--large {
70
+ max-width: 8px;
71
+ }
72
+
73
+ .vcs-toolbox-action-select-button--active {
74
+ //border: 2px solid var(--v-basic-base);
75
+ border-radius: 5px;
76
+ background: var(--v-basic-base);
77
+ }
78
+
79
+ .vcs-toolbox-2 {
80
+ .v-toolbar__content {
81
+ padding: 0;
82
+ }
83
+ }
84
+
85
+ .marginToTop {
86
+ margin-top: 3px;
87
+ }
88
+ </style>
89
+ <script>
90
+ import { ref, computed } from 'vue';
91
+ import VcsButton from '../../components/buttons/VcsButton.vue';
92
+
93
+ /**
94
+ * @description
95
+ * A dynamic Toolbox Button rendering a selected item and a dropdown to select an item using {@link https://vuetifyjs.com/en/api/v-menu/|vuetify v-menu} and {@link VcsButton}.
96
+ * @vue-prop {SelectToolboxComponent} group - A toolbox group of type 'select'.
97
+ * @vue-computed {number} nudgeLeft - offset of the dropdown toolbar to the left
98
+ */
99
+ export default {
100
+ name: 'ToolboxActionSelect',
101
+ components: { VcsButton },
102
+ props: {
103
+ group: {
104
+ type: Object,
105
+ required: true,
106
+ },
107
+ },
108
+ setup(props) {
109
+ const open = ref(false);
110
+
111
+ /**
112
+ * v-menu auto prop is not working as expected.
113
+ * Workaround using hardcoded button sizes and paddings
114
+ * @type {ComputedRef<number>}
115
+ */
116
+ const nudgeLeft = computed(() => {
117
+ const toolboxBtnWidth = 42 + 8; // with padding
118
+ const menuBtnWidth = 16;
119
+ return (props.group.action.tools.length * (toolboxBtnWidth / 2)) + (menuBtnWidth / 2);
120
+ });
121
+
122
+ return {
123
+ open,
124
+ nudgeLeft,
125
+ };
126
+ },
127
+ };
128
+ </script>