@policystudio/policy-studio-ui-vue 1.2.0-access.50 → 1.2.0-access.52
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,7 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="psui-el-dropdown-menu"
|
|
4
|
-
>
|
|
2
|
+
<div class="psui-el-dropdown-menu">
|
|
5
3
|
<div
|
|
6
4
|
ref="PSDropdownTrigger"
|
|
7
5
|
@click="toggle"
|
|
@@ -32,8 +30,11 @@
|
|
|
32
30
|
v-if="show"
|
|
33
31
|
ref="PSDropdownFloating"
|
|
34
32
|
role="menu"
|
|
35
|
-
tabindex="
|
|
33
|
+
tabindex="-1"
|
|
36
34
|
class="psui-el-dropdown-menu-dialog-wrapper"
|
|
35
|
+
@keydown.esc="closeWithFocus"
|
|
36
|
+
@keydown.down.prevent="moveFocus(1)"
|
|
37
|
+
@keydown.up.prevent="moveFocus(-1)"
|
|
37
38
|
:class="contentCss"
|
|
38
39
|
aria-orientation="vertical"
|
|
39
40
|
:style="floatingStyles"
|
|
@@ -48,34 +49,35 @@
|
|
|
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
|
-
import {
|
|
52
|
-
useFloating,
|
|
53
|
-
autoUpdate,
|
|
54
|
-
offset,
|
|
55
|
-
flip,
|
|
52
|
+
import {
|
|
53
|
+
useFloating,
|
|
54
|
+
autoUpdate,
|
|
55
|
+
offset,
|
|
56
|
+
flip,
|
|
56
57
|
shift,
|
|
57
|
-
size
|
|
58
|
+
size,
|
|
58
59
|
} from '@floating-ui/vue'
|
|
59
60
|
|
|
60
61
|
import { ref, defineProps, useSlots, computed } from 'vue'
|
|
61
62
|
import Teleport from 'vue2-teleport'
|
|
63
|
+
import { nextTick } from 'vue'
|
|
62
64
|
|
|
63
65
|
const props = defineProps({
|
|
64
|
-
disabled: {type: Boolean, default: false},
|
|
66
|
+
disabled: { type: Boolean, default: false },
|
|
65
67
|
placement: { type: String, default: 'bottom-start' },
|
|
66
68
|
offsetVal: { type: Number, default: 4 },
|
|
67
69
|
width: {
|
|
68
70
|
type: [Number, String],
|
|
69
|
-
default: null
|
|
71
|
+
default: null,
|
|
70
72
|
},
|
|
71
73
|
height: {
|
|
72
74
|
type: [Number, String],
|
|
73
|
-
default: 'auto'
|
|
75
|
+
default: 'auto',
|
|
74
76
|
},
|
|
75
77
|
contentCss: {
|
|
76
78
|
type: String,
|
|
77
|
-
default: 'psui-rounded psui-bg-white psui-shadow-elevation-20'
|
|
78
|
-
}
|
|
79
|
+
default: 'psui-rounded psui-bg-white psui-shadow-elevation-20',
|
|
80
|
+
},
|
|
79
81
|
})
|
|
80
82
|
|
|
81
83
|
const emit = defineEmits(['open', 'close'])
|
|
@@ -96,39 +98,85 @@ const { floatingStyles } = useFloating(PSDropdownTrigger, PSDropdownFloating, {
|
|
|
96
98
|
whileElementsMounted: autoUpdate,
|
|
97
99
|
middleware: [
|
|
98
100
|
offset(props.offsetVal),
|
|
99
|
-
flip(),
|
|
101
|
+
flip(),
|
|
100
102
|
shift(),
|
|
101
103
|
size({
|
|
102
|
-
apply({rects, elements}) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
apply({ rects, elements }) {
|
|
105
|
+
const customWidth = props.width ?? rects.reference.width
|
|
106
|
+
Object.assign(elements.floating.style, {
|
|
107
|
+
width: `${customWidth}px`,
|
|
108
|
+
...(typeof height == 'string'
|
|
109
|
+
? { maxHeight: props.height }
|
|
110
|
+
: { maxHeight: `${props.height}px` }),
|
|
111
|
+
})
|
|
108
112
|
},
|
|
109
|
-
})
|
|
113
|
+
}),
|
|
110
114
|
],
|
|
111
115
|
})
|
|
112
116
|
|
|
117
|
+
const closeWithFocus = () => {
|
|
118
|
+
show.value = false
|
|
119
|
+
emit('close')
|
|
120
|
+
PSDropdownTrigger.value?.querySelector('button')?.focus()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const focusFirstElement = async () => {
|
|
124
|
+
await nextTick()
|
|
125
|
+
if (PSDropdownFloating.value) {
|
|
126
|
+
const focusable = PSDropdownFloating.value.querySelector(
|
|
127
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
|
|
128
|
+
)
|
|
129
|
+
focusable?.focus()
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const moveFocus = (offset) => {
|
|
134
|
+
if (!PSDropdownFloating.value) return
|
|
135
|
+
|
|
136
|
+
const focusableElements = PSDropdownFloating.value.querySelectorAll(
|
|
137
|
+
'button:not([disabled]), [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
const focusable = Array.from(focusableElements)
|
|
141
|
+
if (focusable.length === 0) return
|
|
142
|
+
|
|
143
|
+
const currentIndex = focusable.indexOf(document.activeElement)
|
|
144
|
+
|
|
145
|
+
let nextIndex = currentIndex + offset
|
|
146
|
+
|
|
147
|
+
if (nextIndex < 0) {
|
|
148
|
+
nextIndex = focusable.length - 1
|
|
149
|
+
} else if (nextIndex >= focusable.length) {
|
|
150
|
+
nextIndex = 0
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
focusable[nextIndex].focus()
|
|
154
|
+
}
|
|
155
|
+
|
|
113
156
|
const open = () => {
|
|
114
157
|
show.value = true
|
|
115
158
|
emit('open')
|
|
116
159
|
}
|
|
117
160
|
|
|
118
161
|
const close = (event) => {
|
|
119
|
-
if(event?.target && PSDropdownTrigger.value.contains(event?.target)) return
|
|
162
|
+
if (event?.target && PSDropdownTrigger.value.contains(event?.target)) return
|
|
120
163
|
|
|
121
164
|
show.value = false
|
|
122
165
|
emit('close')
|
|
123
166
|
}
|
|
124
167
|
|
|
125
|
-
const toggle = (event) => {
|
|
168
|
+
const toggle = async (event) => {
|
|
126
169
|
if (props.disabled) return
|
|
127
170
|
|
|
128
171
|
if (event) event.stopPropagation()
|
|
129
172
|
|
|
130
173
|
show.value = !show.value
|
|
131
|
-
|
|
174
|
+
|
|
175
|
+
if (show.value) {
|
|
176
|
+
await focusFirstElement()
|
|
177
|
+
} else {
|
|
178
|
+
emit('close')
|
|
179
|
+
}
|
|
132
180
|
}
|
|
133
181
|
|
|
134
182
|
defineExpose({ open, close })
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
class="psui-el-dialog"
|
|
4
|
+
v-bind="$attrs"
|
|
4
5
|
:class="getComponentClass"
|
|
6
|
+
@keydown.esc="onClose"
|
|
5
7
|
>
|
|
6
8
|
<div
|
|
7
9
|
v-if="hasIcon"
|
|
@@ -30,6 +32,7 @@
|
|
|
30
32
|
<button
|
|
31
33
|
class="psui-el-dialog-close"
|
|
32
34
|
v-if="hasClose"
|
|
35
|
+
aria-label="Close dialog"
|
|
33
36
|
@click="onClose"
|
|
34
37
|
>
|
|
35
38
|
<i class="material-icons-round">close</i>
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
v-if="item.icon"
|
|
23
23
|
:icon="item.icon"
|
|
24
24
|
display="flex"
|
|
25
|
+
tabindex="-1"
|
|
26
|
+
aria-hidden="true"
|
|
25
27
|
size="18"
|
|
26
28
|
/>
|
|
27
29
|
<span>{{ item[keyLabel] }}</span>
|
|
@@ -39,6 +41,8 @@
|
|
|
39
41
|
v-if="item.icon"
|
|
40
42
|
:icon="item.icon"
|
|
41
43
|
display="flex"
|
|
44
|
+
tabindex="-1"
|
|
45
|
+
aria-hidden="true"
|
|
42
46
|
size="18"
|
|
43
47
|
/>
|
|
44
48
|
<span>{{ item[keyLabel] }}</span>
|