@3cr/viewer-browser 0.0.161 → 0.0.194

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 (229) hide show
  1. package/.circleci/config.yml +53 -0
  2. package/__tests__/index.spec.ts +31 -24
  3. package/components.d.ts +32 -0
  4. package/dist/Viewer3CR.js +44 -27
  5. package/dist/Viewer3CR.mjs +22734 -17747
  6. package/dist/Viewer3CR.umd.js +44 -27
  7. package/index.html +6 -8
  8. package/index.ts +9 -5
  9. package/package.json +5 -2
  10. package/playground/index.html +7 -10
  11. package/src/App.vue +12 -4
  12. package/src/__tests__/app.spec.ts +2 -13
  13. package/src/assets/magic_wand.svg +24 -0
  14. package/src/components/WebGL3DR.vue +53 -92
  15. package/src/components/__tests__/webgl3dr.spec.ts +29 -48
  16. package/src/{demo → components/demo}/DemoModal.vue +1 -1
  17. package/src/{demo → components/demo}/DemoPatientModal.vue +4 -1
  18. package/src/components/demo/__tests__/DemoModal.spec.ts +25 -0
  19. package/src/components/demo/__tests__/DemoPatientModal.spec.ts +37 -0
  20. package/src/components/demo/__tests__/options.spec.ts +25 -0
  21. package/src/components/demo/licence/DemoLicenceEnableCloudStorageModal.vue +64 -0
  22. package/src/{demo → components/demo}/licence/DemoLicenceInfoModal.vue +5 -4
  23. package/src/{demo → components/demo}/licence/DemoLicenceSendToPartyModal.vue +6 -4
  24. package/src/{demo → components/demo}/licence/DemoLicenceShareToMobileModal.vue +8 -6
  25. package/src/components/demo/licence/__tests__/DemoLicenceEnableCloudStorageModal.spec.ts +37 -0
  26. package/src/components/demo/licence/__tests__/DemoLicenceInfoModal.spec.ts +37 -0
  27. package/src/components/demo/licence/__tests__/DemoLicenceSendToPartyModal.spec.ts +36 -0
  28. package/src/components/demo/licence/__tests__/DemoLicenceShareToMobileModal.spec.ts +51 -0
  29. package/src/{demo → components/demo}/options.ts +18 -20
  30. package/src/components/demo/patient/DemoPatientEnableCloudStorageModal.vue +64 -0
  31. package/src/{demo → components/demo}/patient/DemoPatientInfoModal.vue +5 -4
  32. package/src/{demo → components/demo}/patient/DemoPatientSendToPartyModal.vue +4 -3
  33. package/src/{demo → components/demo}/patient/DemoPatientShareToMobileModal.vue +8 -6
  34. package/src/components/demo/patient/__tests__/DemoPatientEnableCloudStorageModal.spec.ts +37 -0
  35. package/src/components/demo/patient/__tests__/DemoPatientInfoModal.spec.ts +37 -0
  36. package/src/components/demo/patient/__tests__/DemoPatientSendToPartyModal.spec.ts +36 -0
  37. package/src/components/demo/patient/__tests__/DemoPatientShareToMobileModal.spec.ts +51 -0
  38. package/src/components/loading/LoadingSpinner.vue +1 -1
  39. package/src/components/modal/ActionRail.vue +96 -0
  40. package/src/components/modal/AskAI.vue +250 -0
  41. package/src/components/modal/CloseViewerModal.vue +104 -0
  42. package/src/components/modal/MftpWebGL3DRModal.vue +415 -834
  43. package/src/components/modal/ViewerActionRail.vue +123 -0
  44. package/src/components/modal/ViewerAnnotationModal.vue +115 -0
  45. package/src/components/modal/ViewerAnnotations.vue +283 -0
  46. package/src/components/modal/ViewerDisplaySettings.vue +102 -0
  47. package/src/components/modal/ViewerNavigationDrawer.vue +90 -0
  48. package/src/components/modal/ViewerNavigationDrawerContent.vue +126 -0
  49. package/src/components/modal/ViewerNavigationDrawerFooter.vue +111 -0
  50. package/src/components/modal/ViewerNavigationDrawerHeader.vue +63 -0
  51. package/src/components/modal/__tests__/CloseViewerModal.spec.ts +60 -0
  52. package/src/components/modal/__tests__/{mftp-webgl-3dr-modal.spec.ts → MftpWebGL3DRModal.spec.ts} +47 -298
  53. package/src/components/modal/__tests__/ViewerAnnotationModal.spec.ts +79 -0
  54. package/src/components/modal/__tests__/ViewerDisplaySettings.spec.ts +61 -0
  55. package/src/components/modal/__tests__/ViewerNavigationDrawer.spec.ts +32 -0
  56. package/src/components/modal/__tests__/ViewerNavigationDrawerContent.spec.ts +29 -0
  57. package/src/components/modal/__tests__/ViewerNavigationDrawerFooter.spec.ts +43 -0
  58. package/src/components/modal/__tests__/ViewerNavigationDrawerHeader.spec.ts +37 -0
  59. package/src/components/modal/actions/Action.vue +40 -0
  60. package/src/components/modal/actions/Flip3dAction.vue +79 -0
  61. package/src/components/modal/actions/FlipHorizontalAction.vue +36 -0
  62. package/src/components/modal/actions/FlipVerticalAction.vue +36 -0
  63. package/src/components/modal/actions/FullscreenAction.vue +47 -0
  64. package/src/components/modal/actions/NavigationCubeAction.vue +33 -0
  65. package/src/components/modal/actions/PanAction.vue +78 -0
  66. package/src/components/modal/actions/ResetViewAction.vue +29 -0
  67. package/src/components/modal/actions/Rotate2dAction.vue +78 -0
  68. package/src/components/modal/actions/Slice3dAction.vue +71 -0
  69. package/src/components/modal/actions/ZoomAction.vue +70 -0
  70. package/src/components/modal/actions/__tests__/Action.spec.ts +29 -0
  71. package/src/components/modal/actions/__tests__/Flip3dAction.spec.ts +48 -0
  72. package/src/components/modal/actions/__tests__/FlipHorizontalAction.spec.ts +17 -0
  73. package/src/components/modal/actions/__tests__/FlipVerticalAction.spec.ts +17 -0
  74. package/src/components/modal/actions/__tests__/FullscreenAction.spec.ts +28 -0
  75. package/src/components/modal/actions/__tests__/NavigationCubeAction.spec.ts +25 -0
  76. package/src/components/modal/actions/__tests__/PanAction.spec.ts +46 -0
  77. package/src/components/modal/actions/__tests__/ResetViewAction.spec.ts +17 -0
  78. package/src/components/modal/actions/__tests__/Rotate2dAction.spec.ts +23 -0
  79. package/src/components/modal/actions/__tests__/Slice3dAction.spec.ts +14 -0
  80. package/src/components/modal/actions/__tests__/ZoomAction.spec.ts +34 -0
  81. package/src/components/modal/composables/__tests__/useNavigationCubeObserver.spec.ts +56 -0
  82. package/src/components/modal/composables/useEventListener.ts +22 -0
  83. package/src/components/modal/composables/useNavigationCubeObserver.ts +104 -0
  84. package/src/components/selectors/ValueSelector.vue +30 -33
  85. package/src/components/selectors/__tests__/value-selector.spec.ts +1 -1
  86. package/src/components/sliders/DoubleSliderSelector.vue +79 -71
  87. package/src/components/sliders/VerticalSliderSelector.vue +12 -17
  88. package/src/components/sliders/__tests__/double-slider-selector.spec.ts +1 -1
  89. package/src/components/sliders/__tests__/vertical-slider-selector.spec.ts +1 -1
  90. package/src/dataLayer/__tests__/clamp.spec.ts +16 -0
  91. package/src/dataLayer/__tests__/eventHandlers.spec.ts +38 -0
  92. package/src/dataLayer/__tests__/getIconForPreset.spec.ts +40 -0
  93. package/src/dataLayer/__tests__/patchDataOverlay.spec.ts +88 -0
  94. package/src/dataLayer/__tests__/scanState.spec.ts +93 -0
  95. package/src/dataLayer/__tests__/useViewer3cr.spec.ts +10 -0
  96. package/src/dataLayer/__tests__/viewer3cr.spec.ts +331 -0
  97. package/src/dataLayer/clamp.ts +9 -0
  98. package/src/dataLayer/eventHandlers.ts +26 -0
  99. package/src/dataLayer/patchDataOverlay.ts +101 -0
  100. package/src/dataLayer/scanState.ts +105 -26
  101. package/src/dataLayer/useViewer3cr.ts +7 -0
  102. package/src/dataLayer/viewer3cr.ts +410 -0
  103. package/src/helpers/__tests__/layout-overlay-style.spec.ts +24 -22
  104. package/src/helpers/__tests__/model-helper.spec.ts +44 -13
  105. package/src/helpers/layoutOverlayStyle.ts +16 -27
  106. package/src/helpers/modelHelper.ts +62 -10
  107. package/src/models/Callbacks.ts +2 -2
  108. package/src/models/LoadViewerOptions.ts +2 -0
  109. package/src/models/LoadViewerPayload.ts +1 -0
  110. package/src/notifications/notification.ts +3 -4
  111. package/src/plugins/vuetify.ts +5 -0
  112. package/src/services/gpt/__tests__/gpt.service.spec.ts +27 -0
  113. package/src/services/gpt/gpt.service.ts +27 -0
  114. package/static/3cr-types-browser/index.ts +74 -0
  115. package/static/3cr-types-browser/types/Action.ts +6 -0
  116. package/static/3cr-types-browser/types/ActionData.ts +4 -0
  117. package/static/3cr-types-browser/types/AlphaKeys.ts +5 -0
  118. package/static/3cr-types-browser/types/AnchorPoint.ts +12 -0
  119. package/static/3cr-types-browser/types/CallToAction.ts +5 -0
  120. package/static/3cr-types-browser/types/ColourData.ts +7 -0
  121. package/static/3cr-types-browser/types/ColourPresetData.ts +9 -0
  122. package/static/3cr-types-browser/types/CurrentDataOverlayState.ts +6 -0
  123. package/static/3cr-types-browser/types/CurrentScanState.ts +22 -0
  124. package/static/3cr-types-browser/types/DataOverlay.ts +22 -0
  125. package/static/3cr-types-browser/types/DataOverlayActions.ts +14 -0
  126. package/static/3cr-types-browser/types/DataOverlayData.ts +8 -0
  127. package/static/3cr-types-browser/types/DataOverlayEvent.ts +8 -0
  128. package/static/3cr-types-browser/types/DecryptionKey.ts +4 -0
  129. package/static/3cr-types-browser/types/DisplaySettings.ts +10 -0
  130. package/static/3cr-types-browser/types/EmptyPayload.ts +3 -0
  131. package/static/3cr-types-browser/types/EnumPayload.ts +4 -0
  132. package/static/3cr-types-browser/types/FileManagementActions.ts +11 -0
  133. package/static/3cr-types-browser/types/FlipValue.ts +7 -0
  134. package/static/3cr-types-browser/types/FrontEndInterfaces.ts +14 -0
  135. package/static/3cr-types-browser/types/GradientKeys.ts +7 -0
  136. package/static/3cr-types-browser/types/GreyscalePresetData.ts +6 -0
  137. package/static/3cr-types-browser/types/InitialDataOverlayState.ts +6 -0
  138. package/static/3cr-types-browser/types/InitialScanState.ts +19 -0
  139. package/static/3cr-types-browser/types/InteractionType.ts +8 -0
  140. package/static/3cr-types-browser/types/InteractivityActions.ts +6 -0
  141. package/static/3cr-types-browser/types/InteractivityState.ts +4 -0
  142. package/static/3cr-types-browser/types/InvertTransformData.ts +6 -0
  143. package/static/3cr-types-browser/types/LayoutActions.ts +6 -0
  144. package/static/3cr-types-browser/types/LayoutData.ts +7 -0
  145. package/static/3cr-types-browser/types/LoadDataSet.ts +6 -0
  146. package/static/3cr-types-browser/types/LoadSessionState.ts +4 -0
  147. package/static/3cr-types-browser/types/LocalLoadDataset.ts +3 -0
  148. package/static/3cr-types-browser/types/MovementData.ts +7 -0
  149. package/static/3cr-types-browser/types/NavigationCubeActions.ts +8 -0
  150. package/static/3cr-types-browser/types/NavigationCubeData.ts +12 -0
  151. package/static/3cr-types-browser/types/NavigationCubeTransform.ts +9 -0
  152. package/static/3cr-types-browser/types/NotificationPayload.ts +7 -0
  153. package/static/3cr-types-browser/types/NotificationsActions.ts +6 -0
  154. package/static/3cr-types-browser/types/Object.ts +1 -0
  155. package/static/3cr-types-browser/types/ObjectColour.ts +7 -0
  156. package/static/3cr-types-browser/types/ObjectIcon.ts +5 -0
  157. package/static/3cr-types-browser/types/ObjectInvert.ts +7 -0
  158. package/static/3cr-types-browser/types/ObjectSize.ts +7 -0
  159. package/static/3cr-types-browser/types/ObjectSize2D.ts +7 -0
  160. package/static/3cr-types-browser/types/ObjectVisible.ts +5 -0
  161. package/static/3cr-types-browser/types/PositionData.ts +14 -0
  162. package/static/3cr-types-browser/types/PresetsActions.ts +4 -0
  163. package/static/3cr-types-browser/types/RotationValue.ts +7 -0
  164. package/static/3cr-types-browser/types/ScanMovementActions.ts +27 -0
  165. package/static/3cr-types-browser/types/ScanMovementData.ts +3 -0
  166. package/static/3cr-types-browser/types/ScanOrientationActions.ts +6 -0
  167. package/static/3cr-types-browser/types/ScanStateActions.ts +4 -0
  168. package/static/3cr-types-browser/types/ScanView.ts +6 -0
  169. package/static/3cr-types-browser/types/SettingsData.ts +12 -0
  170. package/static/3cr-types-browser/types/SlicerData.ts +9 -0
  171. package/static/3cr-types-browser/types/SliderValue.ts +4 -0
  172. package/static/3cr-types-browser/types/SlidersActions.ts +18 -0
  173. package/static/3cr-types-browser/types/Vector2Data.ts +5 -0
  174. package/static/3cr-types-browser/types/Vector3Data.ts +6 -0
  175. package/static/3cr-types-browser/types/VectorMovementData.ts +8 -0
  176. package/static/3cr-types-browser/types/ViewInteractiveMode.ts +5 -0
  177. package/static/3cr-types-browser/types/ViewOrientation.ts +8 -0
  178. package/static/3cr-types-browser/types/ViewOrientations.ts +10 -0
  179. package/static/3cr-types-browser/types/ViewSelectionActions.ts +9 -0
  180. package/static/3cr-types-browser/types/ViewToggleData.ts +7 -0
  181. package/static/3cr-types-browser/types/VolumeOrientation.ts +7 -0
  182. package/test/helper.ts +10 -1
  183. package/test/setup.ts +13 -0
  184. package/tsconfig.json +1 -0
  185. package/vite.config.mts +1 -0
  186. package/coverage/3cr-viewer-browser/index.html +0 -116
  187. package/coverage/3cr-viewer-browser/index.ts.html +0 -199
  188. package/coverage/3cr-viewer-browser/src/App.vue.html +0 -316
  189. package/coverage/3cr-viewer-browser/src/components/WebGL3DR.vue.html +0 -442
  190. package/coverage/3cr-viewer-browser/src/components/icons/index.html +0 -116
  191. package/coverage/3cr-viewer-browser/src/components/icons/liver.vue.html +0 -148
  192. package/coverage/3cr-viewer-browser/src/components/index.html +0 -116
  193. package/coverage/3cr-viewer-browser/src/components/loading/LoadingSpinner.vue.html +0 -622
  194. package/coverage/3cr-viewer-browser/src/components/loading/index.html +0 -116
  195. package/coverage/3cr-viewer-browser/src/components/modal/MftpWebGL3DRModal.vue.html +0 -3118
  196. package/coverage/3cr-viewer-browser/src/components/modal/index.html +0 -116
  197. package/coverage/3cr-viewer-browser/src/components/selectors/ValueSelector.vue.html +0 -358
  198. package/coverage/3cr-viewer-browser/src/components/selectors/index.html +0 -116
  199. package/coverage/3cr-viewer-browser/src/components/sliders/DoubleSliderSelector.vue.html +0 -487
  200. package/coverage/3cr-viewer-browser/src/components/sliders/VerticalSliderSelector.vue.html +0 -358
  201. package/coverage/3cr-viewer-browser/src/components/sliders/index.html +0 -131
  202. package/coverage/3cr-viewer-browser/src/dataLayer/iconData.ts.html +0 -118
  203. package/coverage/3cr-viewer-browser/src/dataLayer/index.html +0 -146
  204. package/coverage/3cr-viewer-browser/src/dataLayer/payloadHandler.ts.html +0 -463
  205. package/coverage/3cr-viewer-browser/src/dataLayer/scanState.ts.html +0 -598
  206. package/coverage/3cr-viewer-browser/src/helpers/index.html +0 -146
  207. package/coverage/3cr-viewer-browser/src/helpers/layoutOverlayStyle.ts.html +0 -406
  208. package/coverage/3cr-viewer-browser/src/helpers/modelHelper.ts.html +0 -412
  209. package/coverage/3cr-viewer-browser/src/helpers/utils.ts.html +0 -133
  210. package/coverage/3cr-viewer-browser/src/index.html +0 -131
  211. package/coverage/3cr-viewer-browser/src/main.ts.html +0 -124
  212. package/coverage/3cr-viewer-browser/src/models/LoadViewerOptions.ts.html +0 -166
  213. package/coverage/3cr-viewer-browser/src/models/index.html +0 -116
  214. package/coverage/3cr-viewer-browser/src/notifications/index.html +0 -116
  215. package/coverage/3cr-viewer-browser/src/notifications/notification.ts.html +0 -238
  216. package/coverage/3cr-viewer-browser/src/plugins/index.html +0 -131
  217. package/coverage/3cr-viewer-browser/src/plugins/index.ts.html +0 -136
  218. package/coverage/3cr-viewer-browser/src/plugins/vuetify.ts.html +0 -220
  219. package/coverage/base.css +0 -224
  220. package/coverage/block-navigation.js +0 -87
  221. package/coverage/favicon.png +0 -0
  222. package/coverage/index.html +0 -296
  223. package/coverage/prettify.css +0 -1
  224. package/coverage/prettify.js +0 -2
  225. package/coverage/sort-arrow-sprite.png +0 -0
  226. package/coverage/sorter.js +0 -196
  227. package/src/dataLayer/__tests__/payload-handler.spec.ts +0 -214
  228. package/src/dataLayer/payloadHandler.ts +0 -138
  229. /package/src/dataLayer/{iconData.ts → getIconForPreset.ts} +0 -0
@@ -0,0 +1,70 @@
1
+ <template>
2
+ <v-menu data-testid="menu" v-model="menuState" :close-on-content-click="false">
3
+ <template #activator="{ props: menu }">
4
+ <Action
5
+ v-bind="menu"
6
+ text="Zoom"
7
+ icon="search"
8
+ :variant="variant"
9
+ />
10
+ </template>
11
+ <v-list>
12
+ <v-list-item data-testid="zoom-in" prepend-icon="zoom_in" @click.stop="zoomIn">
13
+ <v-list-item-title>Zoom In</v-list-item-title>
14
+ </v-list-item>
15
+ <v-list-item data-testid="zoom-out" prepend-icon="zoom_out" @click.stop="zoomOut">
16
+ <v-list-item-title>Zoom Out</v-list-item-title>
17
+ </v-list-item>
18
+ </v-list>
19
+ </v-menu>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { ScanView } from "@3cr/types-ts";
24
+ import { computed, ref } from "vue";
25
+ import { useViewer3cr } from "@/dataLayer/useViewer3cr";
26
+
27
+ interface Props {
28
+ view: ScanView;
29
+ variant?: 'button' | 'menu-item';
30
+ percentage?: number;
31
+ }
32
+
33
+ type Emits = {
34
+ 'update:modal': [value: boolean];
35
+ };
36
+
37
+ const props = withDefaults(defineProps<Props>(), {
38
+ variant: 'button',
39
+ percentage: 10
40
+ });
41
+
42
+ const emit = defineEmits<Emits>();
43
+
44
+ const viewer3cr = useViewer3cr();
45
+ const menu = ref<boolean>(false);
46
+
47
+ const menuState = computed({
48
+ get(): boolean {
49
+ return menu.value;
50
+ },
51
+ set(value: boolean): void {
52
+ menu.value = value;
53
+ emit('update:modal', value);
54
+ }
55
+ });
56
+
57
+ async function zoomOut(): Promise<void> {
58
+ await viewer3cr.zoomOut(props.view, props.percentage);
59
+ }
60
+
61
+ async function zoomIn(): Promise<void> {
62
+ await viewer3cr.zoomIn(props.view, props.percentage);
63
+ }
64
+ </script>
65
+
66
+ <style scoped lang="scss">
67
+ .v-list-item {
68
+ user-select: none;
69
+ }
70
+ </style>
@@ -0,0 +1,29 @@
1
+ import { expect, describe, it, vi } from "vitest";
2
+ import { mountVuetify } from "~/helper";
3
+ import Action from "@/components/modal/actions/Action.vue";
4
+
5
+ describe('Action tests', () => {
6
+ it('should render as button', async () => {
7
+ const props = { text: '', icon: '', variant: 'button', onClick: vi.fn() };
8
+ const wrapper = mountVuetify(Action, props);
9
+ const button = wrapper.findComponent('[data-testid="button"]');
10
+ expect(button).toBeTruthy();
11
+ await button.trigger('click');
12
+ expect(props.onClick).toHaveBeenCalled();
13
+ });
14
+
15
+ it('should render as menu-item', async () => {
16
+ const props = { text: '', icon: '', variant: 'menu-item', onClick: vi.fn() };
17
+ const wrapper = mountVuetify(Action, props);
18
+ const menuItem = wrapper.findComponent('[data-testid="menu-item"]');
19
+ expect(menuItem).toBeTruthy();
20
+ await menuItem.trigger('click');
21
+ expect(props.onClick).toHaveBeenCalled();
22
+ });
23
+
24
+ it('should render nothing', async () => {
25
+ const props = { text: '', icon: '', variant: 'invalid', onClick: vi.fn() };
26
+ const wrapper = mountVuetify(Action, props);
27
+ expect(wrapper.text()).toBe('');
28
+ });
29
+ });
@@ -0,0 +1,48 @@
1
+ import {describe, expect, it, vi} from "vitest";
2
+ import {ScanView} from "@3cr/types-ts";
3
+ import {mountVuetify} from "~/helper";
4
+ import {DOMWrapper} from "@vue/test-utils";
5
+ import Flip3dAction from "@/components/modal/actions/Flip3dAction.vue";
6
+ import {Viewer3cr} from "@/dataLayer/viewer3cr";
7
+
8
+ describe('Flip3dAction tests', () => {
9
+ const spy = vi.spyOn(Viewer3cr.prototype, 'invertTransform').mockResolvedValue();
10
+ const props = { view: ScanView.Volume };
11
+ const wrapper = mountVuetify(Flip3dAction, props);
12
+
13
+ it('should flip sagittal', async () => {
14
+ const activator = wrapper.findComponent('[data-testid="activator"]');
15
+ await activator.trigger('click');
16
+ const menu = new DOMWrapper(document.querySelector('[data-testid="menu"]'));
17
+ const sagittal = menu.findComponent('[data-testid="sagittal"]');
18
+ await sagittal.trigger('click');
19
+ expect(spy).toHaveBeenCalledWith(true, false, false);
20
+ await activator.trigger('click');
21
+ await sagittal.trigger('click');
22
+ expect(spy).toHaveBeenCalledWith(false, false, false);
23
+ });
24
+
25
+ it('should flip coronal', async () => {
26
+ const activator = wrapper.findComponent('[data-testid="activator"]');
27
+ await activator.trigger('click');
28
+ const menu = new DOMWrapper(document.querySelector('[data-testid="menu"]'));
29
+ const coronal = menu.findComponent('[data-testid="coronal"]');
30
+ await coronal.trigger('click');
31
+ expect(spy).toHaveBeenCalledWith(false, true, false);
32
+ await activator.trigger('click');
33
+ await coronal.trigger('click');
34
+ expect(spy).toHaveBeenCalledWith(false, false, false);
35
+ });
36
+
37
+ it('should flip transverse', async () => {
38
+ const activator = wrapper.findComponent('[data-testid="activator"]');
39
+ await activator.trigger('click');
40
+ const menu = new DOMWrapper(document.querySelector('[data-testid="menu"]'));
41
+ const transverse = menu.findComponent('[data-testid="transverse"]');
42
+ await transverse.trigger('click');
43
+ expect(spy).toHaveBeenCalledWith(false, false, true);
44
+ await activator.trigger('click');
45
+ await transverse.trigger('click');
46
+ expect(spy).toHaveBeenCalledWith(false, false, false);
47
+ });
48
+ });
@@ -0,0 +1,17 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { mountVuetify } from "~/helper";
3
+ import { ScanView } from "@3cr/types-ts";
4
+ import FlipHorizontalAction from "@/components/modal/actions/FlipHorizontalAction.vue";
5
+ import {Viewer3cr} from "@/dataLayer/viewer3cr";
6
+
7
+ describe('FlipHorizontalAction tests', () => {
8
+ const spy = vi.spyOn(Viewer3cr.prototype, 'flipHorizontally').mockResolvedValue();
9
+ const props = { view: ScanView.Sagittal };
10
+
11
+ it('should flip horizontally', async () => {
12
+ const wrapper = mountVuetify(FlipHorizontalAction, props);
13
+ const action = wrapper.findComponent('[data-testid="button"]');
14
+ await action.trigger('click');
15
+ expect(spy).toHaveBeenCalledWith(props.view, true);
16
+ });
17
+ });
@@ -0,0 +1,17 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { mountVuetify } from "~/helper";
3
+ import { ScanView } from "@3cr/types-ts";
4
+ import FlipVerticalAction from "@/components/modal/actions/FlipVerticalAction.vue";
5
+ import {Viewer3cr} from "@/dataLayer/viewer3cr";
6
+
7
+ describe('FlipVerticalAction tests', () => {
8
+ const spy = vi.spyOn(Viewer3cr.prototype, 'flipVertically').mockResolvedValue();
9
+ const props = { view: ScanView.Sagittal };
10
+
11
+ it('should flip horizontally', async () => {
12
+ const wrapper = mountVuetify(FlipVerticalAction, props);
13
+ const action = wrapper.findComponent('[data-testid="button"]');
14
+ await action.trigger('click');
15
+ expect(spy).toHaveBeenCalledWith(props.view, true);
16
+ });
17
+ });
@@ -0,0 +1,28 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { mountVuetify } from "~/helper";
3
+ import { CurrentScanState, LayoutActions, ScanView } from "@3cr/types-ts";
4
+ import { Viewer3cr } from "@/dataLayer/viewer3cr";
5
+ import { previousLayout, scanState } from "@/dataLayer/scanState";
6
+ import FullscreenAction from "../FullscreenAction.vue";
7
+
8
+ describe('FullscreenAction tests', () => {
9
+ const props = { view: ScanView.Coronal };
10
+ const layoutsSpy = vi.spyOn(Viewer3cr.prototype, 'layouts').mockResolvedValue();
11
+ const viewSpy = vi.spyOn(Viewer3cr.prototype, 'viewSelection').mockResolvedValue();
12
+
13
+ it('should fullscreen', async () => {
14
+ const wrapper = mountVuetify(FullscreenAction, props);
15
+ const button = wrapper.find('[data-testid="button"]');
16
+ await button.trigger('click');
17
+ expect(layoutsSpy).toHaveBeenCalledWith(LayoutActions.lo01);
18
+ expect(viewSpy).toHaveBeenCalledWith(`vs_0${props.view + 1}`);
19
+ });
20
+
21
+ it('should exit fullscreen', async () => {
22
+ scanState.value = { Layout: { PositionData: [{}] } } as CurrentScanState;
23
+ const wrapper = mountVuetify(FullscreenAction, props);
24
+ const button = wrapper.find('[data-testid="button"]');
25
+ await button.trigger('click');
26
+ expect(layoutsSpy).toHaveBeenCalledWith(previousLayout.value);
27
+ });
28
+ });
@@ -0,0 +1,25 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { Viewer3cr } from "@/dataLayer/viewer3cr";
3
+ import { mountVuetify } from "~/helper";
4
+ import { scanState } from "@/dataLayer/scanState";
5
+ import { CurrentScanState } from "@3cr/types-ts";
6
+ import NavigationCubeAction from "@/components/modal/actions/NavigationCubeAction.vue";
7
+
8
+ describe('NavigationCubeAction tests', () => {
9
+ const navCubeInteractivitySpy = vi.spyOn(Viewer3cr.prototype, 'setNavCubeInteractivity').mockResolvedValue();
10
+
11
+ it('should show navigation cube', async () => {
12
+ const wrapper = mountVuetify(NavigationCubeAction);
13
+ const switchCmp = wrapper.findComponent('[data-testid="switch"]');
14
+ await switchCmp.trigger('click');
15
+ expect(navCubeInteractivitySpy).toHaveBeenCalledWith(true);
16
+ });
17
+
18
+ it('should hide navigation cube', async () => {
19
+ scanState.value = { NavigationCube: { Interactivity: { Value: true } } } as CurrentScanState;
20
+ const wrapper = mountVuetify(NavigationCubeAction);
21
+ const switchWrapper = wrapper.findComponent('[data-testid="switch"]');
22
+ await switchWrapper.trigger('click');
23
+ expect(navCubeInteractivitySpy).toHaveBeenCalledWith(false);
24
+ });
25
+ });
@@ -0,0 +1,46 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { mountVuetify } from "~/helper";
3
+ import { ScanView } from "@3cr/types-ts";
4
+ import { Viewer3cr } from "@/dataLayer/viewer3cr";
5
+ import PanAction from "@/components/modal/actions/PanAction.vue";
6
+
7
+ describe('PanAction tests', () => {
8
+ const spy = vi.spyOn(Viewer3cr.prototype, 'hoverOverCanvas').mockResolvedValue();
9
+ const element = { addEventListener: vi.fn(), removeEventListener: vi.fn() };
10
+ const windowAddSpy = vi.spyOn(window, 'addEventListener');
11
+ // const windowRemoveSpy = vi.spyOn(window, 'removeEventListener');
12
+
13
+ it('should setup event listeners', async () => {
14
+ const props = { view: ScanView.Volume, element };
15
+ mountVuetify(PanAction, props);
16
+ expect(element.addEventListener).toHaveBeenCalledWith('mousedown', expect.anything());
17
+ expect(element.addEventListener).toHaveBeenCalledWith('mouseenter', expect.anything());
18
+ expect(element.addEventListener).toHaveBeenCalledWith('mouseleave', expect.anything());
19
+ expect(windowAddSpy).toHaveBeenCalledWith('mousemove', expect.anything());
20
+ expect(windowAddSpy).toHaveBeenCalledWith('mouseup', expect.anything());
21
+ });
22
+
23
+ it('should disable unity input while active', async () => {
24
+ const props = { view: ScanView.Volume, element };
25
+ const wrapper = mountVuetify(PanAction, props);
26
+ const button = wrapper.findComponent('[data-testid="button"]');
27
+ await button.trigger('click');
28
+ expect(spy).toHaveBeenCalledWith(false);
29
+ });
30
+
31
+ it('should call event handlers', async () => {
32
+ const element = document.createElement('div');
33
+ document.body.appendChild(element);
34
+ const props = { view: ScanView.Volume, element };
35
+ const wrapper = mountVuetify(PanAction, props);
36
+ const button = wrapper.findComponent('[data-testid="button"]');
37
+ await button.trigger('click');
38
+ element.dispatchEvent(new MouseEvent('mousedown', { clientX: 0, clientY: 0 }));
39
+ window.dispatchEvent(new MouseEvent('mousemove', { clientX: 0, clientY: 0 }));
40
+ window.dispatchEvent(new MouseEvent('mouseup', { clientX: 0, clientY: 0 }));
41
+ element.dispatchEvent(new MouseEvent('mouseenter', { clientX: 0, clientY: 0 }));
42
+ element.dispatchEvent(new MouseEvent('mouseleave', { clientX: 0, clientY: 0 }));
43
+ expect(spy).toHaveBeenCalledWith(false);
44
+ expect(spy).toHaveBeenCalledWith(true);
45
+ });
46
+ });
@@ -0,0 +1,17 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { Viewer3cr } from "@/dataLayer/viewer3cr";
3
+ import { mountVuetify } from "~/helper";
4
+ import { ViewSelectionActions } from "@3cr/types-ts";
5
+ import ResetViewAction from "@/components/modal/actions/ResetViewAction.vue";
6
+
7
+ describe('ResetViewAction tests', () => {
8
+ const viewSelectionSpy = vi.spyOn(Viewer3cr.prototype, 'viewSelection').mockResolvedValue();
9
+
10
+ it('should reset view', async () => {
11
+ const wrapper = mountVuetify(ResetViewAction);
12
+ const button = wrapper.findComponent('[data-testid="button"]');
13
+ await button.trigger('click');
14
+ expect(viewSelectionSpy).toHaveBeenCalledWith(ViewSelectionActions.vs06);
15
+ expect(viewSelectionSpy).toHaveBeenCalledWith(ViewSelectionActions.vs05);
16
+ });
17
+ });
@@ -0,0 +1,23 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { mountVuetify } from "~/helper";
3
+ import { ScanView } from "@3cr/types-ts";
4
+ import { DOMWrapper } from "@vue/test-utils";
5
+ import { Viewer3cr } from "@/dataLayer/viewer3cr";
6
+ import Rotate2dAction from "@/components/modal/actions/Rotate2dAction.vue";
7
+
8
+ describe('Rotate2dAction tests', () => {
9
+ it('should apply rotation', async () => {
10
+ const props = { view: ScanView.Sagittal };
11
+ const spy = vi.spyOn(Viewer3cr.prototype, 'rotateByDeg').mockResolvedValue();
12
+ const wrapper = mountVuetify(Rotate2dAction, props);
13
+ const button = wrapper.findComponent('[data-testid="button"]');
14
+ await button.trigger('click');
15
+
16
+ const menu = new DOMWrapper(document.querySelector('[data-testid="menu"]'));
17
+ const textField = menu.findComponent('[data-testid="rotation"]');
18
+ await textField.setValue(10);
19
+ const rotate = menu.findComponent('[data-testid="rotate"]');
20
+ await rotate.trigger('click');
21
+ expect(spy).toHaveBeenCalledWith(props.view, 10);
22
+ });
23
+ });
@@ -0,0 +1,14 @@
1
+ import {describe, expect, it} from "vitest";
2
+ import {mountVuetify} from "~/helper";
3
+ import Slice3dAction from "@/components/modal/actions/Slice3dAction.vue";
4
+ import {DOMWrapper} from "@vue/test-utils";
5
+
6
+ describe('Slice3dAction tests', () => {
7
+ it('should open slice menu', async () => {
8
+ const wrapper = mountVuetify(Slice3dAction);
9
+ const button = wrapper.findComponent('[data-testid="button"]');
10
+ await button.trigger('click');
11
+ const menu = new DOMWrapper(document.querySelector('[data-testid="menu"]'));
12
+ expect(menu.exists()).toBeTruthy();
13
+ });
14
+ });
@@ -0,0 +1,34 @@
1
+ import {describe, expect, it, vi} from "vitest";
2
+ import { ScanView } from "@3cr/types-ts";
3
+ import { mountVuetify } from "~/helper";
4
+ import { Viewer3cr } from "@/dataLayer/viewer3cr";
5
+ import ZoomAction from "@/components/modal/actions/ZoomAction.vue";
6
+ import {DOMWrapper} from "@vue/test-utils";
7
+
8
+ describe('ZoomAction tests', () => {
9
+ const props = { view: ScanView.Sagittal, percentage: 25 };
10
+ const zoomInSpy = vi.spyOn(Viewer3cr.prototype, 'zoomIn');
11
+ const zoomOutSpy = vi.spyOn(Viewer3cr.prototype, 'zoomOut');
12
+
13
+ it('should zoom in', async () => {
14
+ const wrapper = mountVuetify(ZoomAction, props);
15
+ const button = wrapper.findComponent('[data-testid="button"]');
16
+ await button.trigger('click');
17
+
18
+ const menu = new DOMWrapper(document.querySelector('[data-testid="menu"]'));
19
+ const zoomIn = menu.findComponent('[data-testid="zoom-in"]');
20
+ await zoomIn.trigger('click');
21
+ expect(zoomInSpy).toHaveBeenCalledWith(props.view, props.percentage);
22
+ });
23
+
24
+ it('should zoom out', async () => {
25
+ const wrapper = mountVuetify(ZoomAction, props);
26
+ const button = wrapper.findComponent('[data-testid="button"]');
27
+ await button.trigger('click');
28
+
29
+ const menu = new DOMWrapper(document.querySelector('[data-testid="menu"]'));
30
+ const zoomOut = menu.findComponent('[data-testid="zoom-out"]');
31
+ await zoomOut.trigger('click');
32
+ expect(zoomOutSpy).toHaveBeenCalledWith(props.view, props.percentage);
33
+ });
34
+ });
@@ -0,0 +1,56 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { useNavigationCubeObserver } from "@/components/modal/composables/useNavigationCubeObserver";
3
+ import { isFullscreen, isLayout1x3, isLayout2x2, scanState } from "@/dataLayer/scanState";
4
+ import { Viewer3cr } from "@/dataLayer/viewer3cr";
5
+ import { AnchorPoint, CurrentScanState, ScanView } from "@3cr/types-ts";
6
+ import { flushPromises } from "@vue/test-utils";
7
+
8
+ function setupMocks(state: CurrentScanState, fullscreen: boolean, layout1x3: boolean, layout2x2: boolean): void {
9
+ vi.spyOn(scanState, 'value', 'get').mockReturnValue(state);
10
+ vi.spyOn(isFullscreen, 'value', 'get').mockReturnValue(fullscreen);
11
+ vi.spyOn(isLayout1x3, 'value', 'get').mockReturnValue(layout1x3);
12
+ vi.spyOn(isLayout2x2, 'value', 'get').mockReturnValue(layout2x2);
13
+ }
14
+
15
+ describe('useNavigationCubeObserver tests', () => {
16
+ vi.spyOn(ResizeObserver.prototype, 'observe').mockReturnValue()
17
+ vi.spyOn(ResizeObserver.prototype, 'unobserve').mockReturnValue();
18
+
19
+ const canvas = { clientWidth: 100, clientHeight: 100 } as HTMLCanvasElement;
20
+ const fullscreen2d = { CurrentView: ScanView.Sagittal, NavigationCube: { Interactivity: { Value: true } } } as CurrentScanState;
21
+ const fullscreen3d = { CurrentView: ScanView.Volume, NavigationCube: { Interactivity: { Value: true } } } as CurrentScanState;
22
+
23
+ const visibilitySpy = vi.spyOn(Viewer3cr.prototype, 'setNavCubeVisibility');
24
+ const positionSizeSpy = vi.spyOn(Viewer3cr.prototype, 'setNavCubePositionSize');
25
+
26
+ it('should update on 3d fullscreen changes', async () => {
27
+ setupMocks(fullscreen3d, true, false, false);
28
+ useNavigationCubeObserver(canvas);
29
+ await flushPromises();
30
+ expect(visibilitySpy).toBeCalledWith(true);
31
+ expect(positionSizeSpy).toBeCalledWith(AnchorPoint.TOP_LEFT, 90, 90, 10, 10);
32
+ });
33
+
34
+ it('should update on 2d fullscreen changes', async () => {
35
+ setupMocks(fullscreen2d, true, false, false);
36
+ useNavigationCubeObserver(canvas);
37
+ await flushPromises();
38
+ expect(visibilitySpy).toBeCalledWith(false);
39
+ });
40
+
41
+ it('should update on 1x3 layout changes', async () => {
42
+ setupMocks(fullscreen3d, false, true, false);
43
+ useNavigationCubeObserver(canvas);
44
+ await flushPromises();
45
+ expect(visibilitySpy).toBeCalledWith(true);
46
+ expect(positionSizeSpy).toBeCalledWith(AnchorPoint.TOP_LEFT, 56, 90, 10, 10);
47
+ });
48
+
49
+ it('should update on 2x2 layout changes', async () => {
50
+ setupMocks(fullscreen3d, false, false, true);
51
+ useNavigationCubeObserver(canvas);
52
+ await flushPromises();
53
+ expect(visibilitySpy).toBeCalledWith(true);
54
+ expect(positionSizeSpy).toBeCalledWith(AnchorPoint.TOP_LEFT, 40, 40, 10, 10);
55
+ });
56
+ });
@@ -0,0 +1,22 @@
1
+ import { isRef, onBeforeUnmount, onMounted, Ref, unref, watch } from 'vue';
2
+
3
+ type Target = Ref<EventTarget> | EventTarget;
4
+ type EventType = keyof HTMLElementEventMap;
5
+ type Handler = (e: Event) => void | Promise<void>;
6
+
7
+ export function useEventListener(target: Target, event: EventType, handler: Handler) {
8
+ if (isRef(target)) {
9
+ watch(target, (value, oldValue) => {
10
+ oldValue?.removeEventListener(event, handler);
11
+ value?.addEventListener(event, handler);
12
+ });
13
+ } else {
14
+ onMounted(() => {
15
+ target.addEventListener(event, handler);
16
+ });
17
+ }
18
+
19
+ onBeforeUnmount(() => {
20
+ unref(target)?.removeEventListener(event, handler);
21
+ });
22
+ }
@@ -0,0 +1,104 @@
1
+ import { isFullscreen, isLayout1x3, isLayout2x2, scanState } from "@/dataLayer/scanState";
2
+ import { AnchorPoint, ScanView } from "@3cr/types-ts";
3
+ import { useViewer3cr } from "@/dataLayer/useViewer3cr";
4
+ import { ComputedRef, WatchStopHandle, computed, watch } from "vue";
5
+
6
+ const isNavigationCubeEnabled = computed(() => {
7
+ return scanState.value.NavigationCube.Interactivity.Value;
8
+ });
9
+
10
+ function getCanvasDimensions(canvas: HTMLCanvasElement): [number, number] {
11
+ const width = canvas.clientWidth * window.devicePixelRatio;
12
+ const height = canvas.clientHeight * window.devicePixelRatio;
13
+ return [width, height];
14
+ }
15
+
16
+ function getNavigationCubeSize(canvas: HTMLCanvasElement): number {
17
+ const [width] = getCanvasDimensions(canvas);
18
+ return Math.floor(width * 0.1);
19
+ }
20
+
21
+ export function useNavigationCubeObserver(canvas: HTMLCanvasElement): ResizeObserver {
22
+ const viewer3cr = useViewer3cr();
23
+
24
+ let refresh: (() => Promise<void>) | undefined;
25
+ let handles: WatchStopHandle[] = [];
26
+
27
+ async function onFullscreen(): Promise<void> {
28
+ const [width, height] = getCanvasDimensions(canvas);
29
+ const navCubeSize = getNavigationCubeSize(canvas);
30
+ if (scanState.value.CurrentView === ScanView.Volume) {
31
+ const xOffset = width - navCubeSize;
32
+ const yOffset = height - navCubeSize;
33
+ await viewer3cr.setNavCubeVisibility(true);
34
+ await viewer3cr.setNavCubePositionSize(AnchorPoint.TOP_LEFT, xOffset, yOffset, navCubeSize, navCubeSize);
35
+ } else {
36
+ await viewer3cr.setNavCubeVisibility(false);
37
+ }
38
+ }
39
+
40
+ async function onLayout1x3(): Promise<void> {
41
+ const [width, height] = getCanvasDimensions(canvas);
42
+ const navCubeSize = getNavigationCubeSize(canvas);
43
+ const xOffset = Math.floor(width - (height / 3) - navCubeSize);
44
+ const yOffset = height - navCubeSize;
45
+ await viewer3cr.setNavCubeVisibility(true);
46
+ await viewer3cr.setNavCubePositionSize(AnchorPoint.TOP_LEFT, xOffset, yOffset, navCubeSize, navCubeSize);
47
+ }
48
+
49
+ async function onLayout2x2(): Promise<void> {
50
+ const [width, height] = getCanvasDimensions(canvas);
51
+ const navCubeSize = getNavigationCubeSize(canvas);
52
+ const xOffset = Math.floor((width / 2) - navCubeSize);
53
+ const yOffset = Math.floor((height / 2) - navCubeSize);
54
+ await viewer3cr.setNavCubeVisibility(true);
55
+ await viewer3cr.setNavCubePositionSize(AnchorPoint.TOP_LEFT, xOffset, yOffset, navCubeSize, navCubeSize);
56
+ }
57
+
58
+ function createWatch(ref: ComputedRef<boolean>, callback: () => Promise<void>): WatchStopHandle {
59
+ return watch(ref, async (value: boolean) => {
60
+ if (value) {
61
+ refresh = callback;
62
+ await refresh();
63
+ }
64
+ }, { immediate: true });
65
+ }
66
+
67
+ function enable(): void {
68
+ if (handles.length === 0) {
69
+ handles.push(createWatch(isFullscreen, onFullscreen));
70
+ handles.push(createWatch(isLayout1x3, onLayout1x3));
71
+ handles.push(createWatch(isLayout2x2, onLayout2x2));
72
+ handles.push(watch([
73
+ () => scanState.value.CurrentView,
74
+ () => scanState.value.NavigationCube.Interactivity.Value
75
+ ], async () => {
76
+ if (refresh) {
77
+ await refresh();
78
+ }
79
+ }));
80
+ observer.observe(canvas);
81
+ }
82
+ }
83
+
84
+ async function disable(): Promise<void> {
85
+ if (handles.length > 0) {
86
+ handles.forEach(handle => handle());
87
+ handles = [];
88
+ observer.unobserve(canvas);
89
+ await viewer3cr.setNavCubeVisibility(false);
90
+ }
91
+ }
92
+
93
+ const observer = new ResizeObserver(async () => {
94
+ if (refresh) {
95
+ await refresh();
96
+ }
97
+ });
98
+
99
+ watch(isNavigationCubeEnabled, (value: boolean) => {
100
+ value ? enable() : disable();
101
+ }, { immediate: true });
102
+
103
+ return observer;
104
+ }
@@ -1,6 +1,31 @@
1
+ <template>
2
+ <div class="single-slider-selector">
3
+ <v-row no-gutters align="center" justify="space-between">
4
+ <v-col>
5
+ <span class="text-caption">
6
+ {{ label }}
7
+ </span>
8
+ </v-col>
9
+ <v-col cols="4">
10
+ <v-text-field
11
+ :model-value="sliderValue"
12
+ @update:modelValue="sliderValue = toNumber($event)"
13
+ class="mt-0 pt-0"
14
+ hide-details
15
+ variant="outlined"
16
+ density="compact"
17
+ type="number"
18
+ :append-inner-icon="prepend"
19
+ ></v-text-field>
20
+ </v-col>
21
+ </v-row>
22
+ </div>
23
+ </template>
24
+
1
25
  <script setup lang="ts">
2
- import { computed, defineEmits } from "vue";
26
+ import { computed } from "vue";
3
27
  import { toNumber } from "@/helpers/utils";
28
+ import { clamp } from "@/dataLayer/clamp";
4
29
 
5
30
  export interface Props {
6
31
  value: number;
@@ -21,52 +46,24 @@ const props = withDefaults(defineProps<Props>(), {
21
46
  step: 1,
22
47
  prepend: "",
23
48
  });
49
+
24
50
  const emit = defineEmits<{
25
51
  "update:value": [number];
26
52
  }>();
53
+
27
54
  const sliderValue = computed({
28
55
  get() {
29
56
  return Math.floor(props.value);
30
57
  },
31
58
  set(value: number) {
32
- let val = value;
33
- if (value > props.max) val = props.max;
34
- if (value < props.min) val = props.min;
59
+ const val = clamp(value, props.min, props.max);
35
60
  emit("update:value", val);
36
61
  },
37
62
  });
38
63
 
39
- defineExpose({
40
- sliderValue,
41
- });
64
+ defineExpose({ sliderValue });
42
65
  </script>
43
66
 
44
- <template>
45
- <div class="single-slider-selector">
46
- <v-row no-gutters align="center" justify="space-between">
47
- <v-col>
48
- <span class="text-caption">
49
- {{ label }}
50
- </span>
51
- </v-col>
52
- <v-col cols="4">
53
- <v-text-field
54
- :model-value="sliderValue"
55
- @update:modelValue="sliderValue = toNumber($event)"
56
- outlined
57
- dense
58
- class="mt-0 pt-0"
59
- hide-details
60
- variant="outlined"
61
- density="compact"
62
- type="number"
63
- :append-inner-icon="prepend"
64
- ></v-text-field>
65
- </v-col>
66
- </v-row>
67
- </div>
68
- </template>
69
-
70
67
  <style>
71
68
  .single-slider-selector
72
69
  .v-text-field.v-text-field--enclosed:not(.v-text-field--rounded)
@@ -13,7 +13,7 @@ describe("ValueSelector.vue", () => {
13
13
 
14
14
  beforeEach(() => {
15
15
  wrapper = mountVuetify(ValueSelector, {
16
- value: [0, 0],
16
+ value: 0,
17
17
  min: 0,
18
18
  max: 100,
19
19
  });