@policystudio/policy-studio-ui-vue 1.1.90-beta.74 → 1.1.90-beta.76

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.
@@ -4013,25 +4013,9 @@ video {
4013
4013
  min-height: 27px;
4014
4014
  font-size: 0.875rem;
4015
4015
  }
4016
- .psui-el-dropdown-menu button:focus {
4017
- outline: none;
4018
- box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
4019
- }
4020
- .psui-el-dropdown-menu-dialog-wrapper {
4021
- position: fixed;
4022
- }
4023
4016
  .psui-el-dropdown-menu-dialog-wrapper {
4024
4017
  z-index: 50;
4025
4018
  }
4026
- .psui-el-dropdown-menu-dialog-wrapper {
4027
- display: none;
4028
- }
4029
- .psui-el-dropdown-menu-dialog-wrapper {
4030
- width: auto;
4031
- }
4032
- .psui-el-dropdown-menu-dialog-wrapper {
4033
- transform-origin: top right;
4034
- }
4035
4019
  .psui-el-dropdown-menu-dialog-wrapper {
4036
4020
  overflow: auto;
4037
4021
  }
@@ -4042,28 +4026,11 @@ video {
4042
4026
  --tw-bg-opacity: 1;
4043
4027
  background-color: rgb(255, 255, 255, var(--tw-bg-opacity, 1));
4044
4028
  }
4045
- .psui-el-dropdown-menu-dialog-wrapper {
4046
- opacity: 0;
4047
- }
4048
4029
  .psui-el-dropdown-menu-dialog-wrapper {
4049
4030
  --tw-shadow: 0px 0px 8px rgba(0, 0, 0, 0.04), 0px 5px 6px rgba(0, 0, 0, 0.1);
4050
4031
  --tw-shadow-colored: 0px 0px 8px var(--tw-shadow-color), 0px 5px 6px var(--tw-shadow-color);
4051
4032
  box-shadow: var(--tw-ring-offset-shadow, 0 0 rgba(0, 0, 0, 0)), var(--tw-ring-shadow, 0 0 rgba(0, 0, 0, 0)), var(--tw-shadow);
4052
4033
  }
4053
- .psui-el-dropdown-menu-dialog-wrapper {
4054
- transition-property: all;
4055
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
4056
- transition-duration: 150ms;
4057
- }
4058
- .psui-el-dropdown-menu-dialog-wrapper {
4059
- transition-duration: 100ms;
4060
- }
4061
- .psui-el-dropdown-menu-dialog-wrapper {
4062
- transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
4063
- }
4064
- .psui-el-dropdown-menu-dialog-wrapper-dialog {
4065
- width: 100%;
4066
- }
4067
4034
 
4068
4035
  .psui-el-dropdown-menu-list {
4069
4036
  margin-top: 1rem;
@@ -6560,10 +6527,6 @@ video {
6560
6527
  transition-duration: 150ms;
6561
6528
  }
6562
6529
 
6563
- .psui-duration-300 {
6564
- transition-duration: 300ms;
6565
- }
6566
-
6567
6530
  *:focus {
6568
6531
  outline: none;
6569
6532
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@policystudio/policy-studio-ui-vue",
3
- "version": "1.1.90-beta.74",
3
+ "version": "1.1.90-beta.76",
4
4
  "description": "Policy Studio UI",
5
5
  "author": "Policy Studio Team",
6
6
  "scripts": {
@@ -15,10 +15,12 @@
15
15
  "main": "dist/index.js",
16
16
  "types": "src/types/index.d.ts",
17
17
  "dependencies": {
18
+ "@floating-ui/vue": "^1.1.9",
18
19
  "@vue/compat": "^3.4.5",
19
20
  "core-js": "^3.6.5",
20
21
  "v-tooltip": "^2.1.3",
21
- "vue": "^3.4.5"
22
+ "vue": "^3.4.5",
23
+ "vue2-teleport": "^1.1.4"
22
24
  },
23
25
  "devDependencies": {
24
26
  "@typescript-eslint/eslint-plugin": "^5.4.0",
@@ -10,19 +10,10 @@
10
10
  min-height: 27px;
11
11
  font-size: 0.875rem;
12
12
 
13
-
14
- &:focus {
15
- outline: none;
16
- box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
17
- }
18
13
  }
19
14
 
20
15
  &-dialog-wrapper {
21
- @apply psui-hidden psui-origin-top-right psui-bg-white psui-fixed psui-w-auto psui-rounded-md psui-z-50 psui-opacity-0 psui-shadow-elevation-20 psui-transition-all psui-duration-100 psui-ease-in psui-overflow-auto;
22
-
23
- &-dialog {
24
- @apply psui-w-full;
25
- }
16
+ @apply psui-bg-white psui-rounded-md psui-z-50 psui-shadow-elevation-20 psui-overflow-auto;
26
17
  }
27
18
  }
28
19
  }
@@ -1,218 +1,120 @@
1
1
  <template>
2
2
  <div
3
- ref="PSDropdown"
4
3
  class="psui-el-dropdown-menu"
5
- :class="{ 'is-open': show.value }"
6
- v-click-outside="close"
7
4
  >
8
5
  <div
9
6
  ref="PSDropdownTrigger"
10
- v-if="$slots.dropdownTrigger"
11
- @click="show && !toggleWhenActive ? '' : toggle($event)"
12
- >
13
- <slot name="dropdownTrigger" />
14
- </div>
15
-
16
- <button
17
- v-else
18
- @click="show && !toggleWhenActive ? '' : toggle($event)"
19
- type="button"
20
- :id="id.value"
21
- aria-haspopup="true"
22
- aria-expanded="true"
23
- ref="PSDropdownTrigger"
7
+ @click="toggle"
24
8
  >
25
9
  <slot
26
- v-if="show.value && $slots.buttonLabelOnShow"
27
- name="buttonLabelOnShow"
10
+ v-if="$slots.dropdownTrigger"
11
+ name="dropdownTrigger"
28
12
  />
29
- <slot
13
+ <button
30
14
  v-else
31
- name="buttonLabel"
32
- />
33
- </button>
34
- <div
35
- ref="PSDropdownDialog"
36
- role="menu"
37
- class="psui-el-dropdown-menu-dialog-wrapper psui-duration-300"
38
- aria-orientation="vertical"
39
- :aria-labelledby="id.value"
40
- :style="{ minWidth: minWidthDropDown }"
41
- >
42
- <div class="psui-el-dropdown-menu-dialog">
43
- <slot name="items" />
44
- </div>
15
+ type="button"
16
+ :aria-expanded="show"
17
+ >
18
+ <slot
19
+ v-if="show && $slots.buttonLabelOnShow"
20
+ name="buttonLabelOnShow"
21
+ />
22
+ <slot
23
+ v-else
24
+ name="buttonLabel"
25
+ />
26
+ </button>
45
27
  </div>
28
+
29
+
30
+ <Teleport to="body">
31
+ <Transition name="fade">
32
+ <div
33
+ v-if="show"
34
+ ref="PSDropdownFloating"
35
+ role="menu"
36
+ class="psui-el-dropdown-menu-dialog-wrapper"
37
+ aria-orientation="vertical"
38
+ :style="floatingStyles"
39
+ v-click-outside="close"
40
+ >
41
+ <div class="psui-el-dropdown-menu-dialog">
42
+ <slot name="items" />
43
+ </div>
44
+ </div>
45
+ </Transition>
46
+ </Teleport>
46
47
  </div>
47
48
  </template>
48
49
 
49
50
  <script setup>
50
51
  // Figma - 2.3 Dropdown with category divider https://www.figma.com/file/Tto8hrNlSfuPcwd1pfqogF/%E2%9A%A1%EF%B8%8F-Design-System?node-id=1768%3A64886
51
-
52
- import { randomString, getParentScrollableEl } from '../../util/GeneralFunctions.js'
53
-
54
- import { ref, onBeforeUnmount } from 'vue'
55
-
56
- defineExpose({
57
- close:() => close(),
58
- open:() => open(),
59
- })
52
+ import {
53
+ useFloating,
54
+ autoUpdate,
55
+ offset,
56
+ flip,
57
+ shift,
58
+ size
59
+ } from '@floating-ui/vue'
60
+
61
+ import { ref, defineProps } from 'vue'
62
+ import Teleport from 'vue2-teleport'
60
63
 
61
64
  const props = defineProps({
62
- /**
63
- * It sets a minimun width for the dropdown menu.
64
- */
65
- minWidthDropDown: {
66
- type: String,
67
- default: '240px',
68
- },
69
- /**
70
- * It's a boolean responsible for showing a slot within the html tag button.
71
- */
72
- buttonLabelOnShow: {
73
- type: Boolean,
74
- default: false,
75
- },
76
- /**
77
- * It's a property responsible for toggling the dropdown menu. default: true.
78
- */
79
- toggleWhenActive: {
80
- type: Boolean,
81
- default: true,
82
- },
83
- /**
84
- * Disable the toogle on click. default: false.
85
- */
86
- disabled: {
87
- type: Boolean,
88
- default: false,
89
- },
90
- /**
91
- * It sets the vertical and horizontal position.
92
- */
93
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment, vue/require-default-prop
94
- position: {
95
- type: String,
96
- validator: (value) => ['custom'].includes(value),
97
- },
65
+ disabled: {type: Boolean, default: false},
66
+ placement: { type: String, default: 'bottom-start' },
67
+ offsetVal: { type: Number, default: 4 },
68
+ dropdownWidth: {
69
+ type: Number,
70
+ default: null
71
+ }
98
72
  })
99
73
 
100
74
  const emit = defineEmits(['open', 'close'])
101
75
 
102
76
  const show = ref(false)
103
- const id = ref(randomString(8))
104
- // const marginLeft = ref('-0px')
105
- const scrollableParentEl = ref(null)
106
- const PSDropdown = ref(null)
107
- const PSDropdownDialog = ref(null)
108
- const PSDropdownTrigger = ref(null)
109
77
 
110
- // const getMaxWidth = computed(() => {
111
- // let bounds = PSDropdown.getBoundingClientRect()
112
- // return document.documentElement.clientWidth - bounds['left'] - 30
113
- // })
114
-
115
- onBeforeUnmount(() => {
116
- unwatchParentScrolling()
78
+ const PSDropdownTrigger = ref(null)
79
+ const PSDropdownFloating = ref(null)
80
+
81
+ const { floatingStyles } = useFloating(PSDropdownTrigger, PSDropdownFloating, {
82
+ placement: props.placement,
83
+ whileElementsMounted: autoUpdate,
84
+ middleware: [
85
+ offset(props.offsetVal),
86
+ flip(),
87
+ shift(),
88
+ size({
89
+ apply({rects, elements}) {
90
+ const customWidth = props.dropdownWidth ?? rects.reference.width
91
+ Object.assign(elements.floating.style, {
92
+ width: `${customWidth}px`,
93
+ minWidth: 'fit-content'
94
+ })
95
+ },
96
+ })
97
+ ],
117
98
  })
118
99
 
119
- const toggle = (event) => {
120
- if (props.disabled) return
121
- if (!show.value) {
122
- open()
123
- } else {
124
- close()
125
- }
126
- event.stopPropagation()
127
- }
128
-
129
- const handleEsc = (evt) => {
130
- if (show.value && evt.keyCode === 27) close()
131
- }
132
-
133
100
  const open = () => {
134
- emit('open')
135
101
  show.value = true
136
- if (PSDropdownDialog.value) {
137
- PSDropdownDialog.value.style.opacity = 0
138
- PSDropdownDialog.value.style.display = 'block'
139
- }
140
- setTimeout(() => {
141
- updatePosition()
142
- watchParentScrolling()
143
- document.addEventListener('keyup', handleEsc)
144
- window.addEventListener('resize', updatePosition)
145
- // window.addEventListener('click', clickOutside)
146
- }, 10)
102
+ emit('open')
147
103
  }
148
104
 
149
105
  const close = () => {
150
- if (show.value == true) {
151
- emit('close')
152
- if (PSDropdownDialog.value !== null) {
153
- PSDropdownDialog.value.style.display = 'none'
154
- PSDropdownDialog.value.style.opacity = 0
155
- }
156
- show.value = false
157
- unwatchParentScrolling()
158
- }
159
- document.removeEventListener('keyup', handleEsc)
160
- document.removeEventListener('resize', updatePosition)
161
- // document.removeEventListener('click', clickOutside)
162
- }
163
-
164
- const watchParentScrolling = () => {
165
- scrollableParentEl.value = getParentScrollableEl(PSDropdown.value)
166
- if (scrollableParentEl.value) {
167
- scrollableParentEl.value.addEventListener('scroll', updatePosition)
168
- }
169
- }
170
-
171
- const unwatchParentScrolling = () => {
172
- if (scrollableParentEl.value) {
173
- scrollableParentEl.value.removeEventListener('scroll', updatePosition())
174
- }
106
+ show.value = false
107
+ emit('close')
175
108
  }
176
109
 
177
- const updatePosition = () => {
178
- if (PSDropdownDialog.value === null || PSDropdownTrigger.value === null) return
179
-
180
- const rectTrigger = PSDropdownTrigger.value.getBoundingClientRect()
181
- const rectDialog = PSDropdownDialog.value.getBoundingClientRect()
182
- const windowWidth = document.documentElement.clientWidth
183
-
184
- PSDropdownDialog.value.style.position = 'fixed'
185
- PSDropdownDialog.value.style.top = `${rectTrigger.y + rectTrigger.height}px`
186
- PSDropdownDialog.value.style.minWidth = `${rectTrigger.width}px`
187
-
188
- if (rectTrigger.x + rectDialog.width + 20 > windowWidth) {
189
- PSDropdownDialog.value.style.left = `${windowWidth - rectDialog.width - 30}px`
190
- } else {
191
- PSDropdownDialog.value.style.left = `${rectTrigger.x}px`
192
- }
193
-
194
- if (props.position == 'custom') {
195
- PSDropdownDialog.value.style.top = `${rectTrigger.y}px`
196
- PSDropdownDialog.value.style.left = `${rectTrigger.x + 100}px`
197
- }
110
+ const toggle = (event) => {
111
+ if (props.disabled) return
198
112
 
199
- if (rectTrigger.top < 10) {
200
- close()
201
- console.warn('The dropdown are too close from the top of the page')
202
- return
203
- }
113
+ if (event) event.stopPropagation()
204
114
 
205
- setTimeout(() => {
206
- if(PSDropdownDialog.value){
207
- PSDropdownDialog.value.style.opacity = 1
208
- }
209
- }, 10)
115
+ show.value ? close() : open()
116
+
210
117
  }
211
118
 
212
- const clickOutside = (event) => {
213
- if (!show.value) return
214
- if (!PSDropdown.value == event.target || !PSDropdown.value?.contains(event.target)) {
215
- close()
216
- }
217
- }
119
+ defineExpose({ open, close })
218
120
  </script>