@policystudio/policy-studio-ui-vue 1.1.90-access.0 → 1.1.90-access.10

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.
@@ -1,218 +1,134 @@
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="hasDropdownTrigger"
11
+ name="dropdownTrigger"
12
+ :show="show"
28
13
  />
29
- <slot
14
+ <button
30
15
  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>
16
+ type="button"
17
+ :aria-expanded="show"
18
+ >
19
+ <slot
20
+ v-if="show && $slots.buttonLabelOnShow"
21
+ name="buttonLabelOnShow"
22
+ />
23
+ <slot
24
+ v-else
25
+ name="buttonLabel"
26
+ />
27
+ </button>
45
28
  </div>
29
+ <Teleport to="body">
30
+ <Transition name="fade">
31
+ <div
32
+ v-if="show"
33
+ ref="PSDropdownFloating"
34
+ role="menu"
35
+ class="psui-el-dropdown-menu-dialog-wrapper"
36
+ :class="contentCss"
37
+ aria-orientation="vertical"
38
+ :style="floatingStyles"
39
+ v-click-outside="close"
40
+ >
41
+ <slot name="items" />
42
+ </div>
43
+ </Transition>
44
+ </Teleport>
46
45
  </div>
47
46
  </template>
48
47
 
49
48
  <script setup>
50
49
  // 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
- })
50
+ import {
51
+ useFloating,
52
+ autoUpdate,
53
+ offset,
54
+ flip,
55
+ shift,
56
+ size
57
+ } from '@floating-ui/vue'
58
+
59
+ import { ref, defineProps, useSlots, computed } from 'vue'
60
+ import Teleport from 'vue2-teleport'
60
61
 
61
62
  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,
63
+ disabled: {type: Boolean, default: false},
64
+ placement: { type: String, default: 'bottom-start' },
65
+ offsetVal: { type: Number, default: 4 },
66
+ width: {
67
+ type: [Number, String],
68
+ default: null
82
69
  },
83
- /**
84
- * Disable the toogle on click. default: false.
85
- */
86
- disabled: {
87
- type: Boolean,
88
- default: false,
70
+ height: {
71
+ type: [Number, String],
72
+ default: 'auto'
89
73
  },
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: {
74
+ contentCss: {
95
75
  type: String,
96
- validator: (value) => ['custom'].includes(value),
97
- },
76
+ default: 'psui-rounded psui-bg-white psui-shadow-elevation-20'
77
+ }
98
78
  })
99
79
 
100
80
  const emit = defineEmits(['open', 'close'])
101
81
 
102
- 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
-
110
- // const getMaxWidth = computed(() => {
111
- // let bounds = PSDropdown.getBoundingClientRect()
112
- // return document.documentElement.clientWidth - bounds['left'] - 30
113
- // })
82
+ const slots = useSlots()
114
83
 
115
- onBeforeUnmount(() => {
116
- unwatchParentScrolling()
84
+ const hasDropdownTrigger = computed(() => {
85
+ return !!slots.dropdownTrigger
117
86
  })
118
87
 
119
- const toggle = (event) => {
120
- if (props.disabled) return
121
- if (!show.value) {
122
- open()
123
- } else {
124
- close()
125
- }
126
- event.stopPropagation()
127
- }
88
+ const show = ref(false)
128
89
 
129
- const handleEsc = (evt) => {
130
- if (show.value && evt.keyCode === 27) close()
131
- }
90
+ const PSDropdownTrigger = ref(null)
91
+ const PSDropdownFloating = ref(null)
92
+
93
+ const { floatingStyles } = useFloating(PSDropdownTrigger, PSDropdownFloating, {
94
+ placement: props.placement,
95
+ whileElementsMounted: autoUpdate,
96
+ middleware: [
97
+ offset(props.offsetVal),
98
+ flip(),
99
+ shift(),
100
+ size({
101
+ apply({rects, elements}) {
102
+ const customWidth = props.width ?? rects.reference.width
103
+ Object.assign(elements.floating.style, {
104
+ width: `${customWidth}px`,
105
+ ...(typeof height == 'string' ? {maxHeight: props.height} : {maxHeight : `${props.height}px`})
106
+ })
107
+ },
108
+ })
109
+ ],
110
+ })
132
111
 
133
112
  const open = () => {
134
- emit('open')
135
113
  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)
147
- }
148
-
149
- 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)
114
+ emit('open')
162
115
  }
163
116
 
164
- const watchParentScrolling = () => {
165
- scrollableParentEl.value = getParentScrollableEl(PSDropdown.value)
166
- if (scrollableParentEl.value) {
167
- scrollableParentEl.value.addEventListener('scroll', updatePosition)
168
- }
169
- }
117
+ const close = (event) => {
118
+ if(event?.target && PSDropdownTrigger.value.contains(event?.target)) return
170
119
 
171
- const unwatchParentScrolling = () => {
172
- if (scrollableParentEl.value) {
173
- scrollableParentEl.value.removeEventListener('scroll', updatePosition())
174
- }
120
+ show.value = false
121
+ emit('close')
175
122
  }
176
123
 
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
- }
124
+ const toggle = (event) => {
125
+ if (props.disabled) return
198
126
 
199
- if (rectTrigger.top < 10) {
200
- close()
201
- console.warn('The dropdown are too close from the top of the page')
202
- return
203
- }
127
+ if (event) event.stopPropagation()
204
128
 
205
- setTimeout(() => {
206
- if(PSDropdownDialog.value){
207
- PSDropdownDialog.value.style.opacity = 1
208
- }
209
- }, 10)
129
+ show.value = !show.value
130
+
210
131
  }
211
132
 
212
- const clickOutside = (event) => {
213
- if (!show.value) return
214
- if (!PSDropdown.value == event.target || !PSDropdown.value?.contains(event.target)) {
215
- close()
216
- }
217
- }
133
+ defineExpose({ open, close })
218
134
  </script>
@@ -3,7 +3,10 @@
3
3
  class="psui-el-input"
4
4
  :class="[getComponentClass, `layout-${layout}`]"
5
5
  >
6
- <label v-if="label"> {{ label }} </label>
6
+ <label
7
+ v-if="label"
8
+ :for="uniqueId"
9
+ > {{ label }} </label>
7
10
 
8
11
  <div
9
12
  class="psui-el-input-wrapper"
@@ -23,6 +26,7 @@
23
26
  >
24
27
  <template #trigger>
25
28
  <input
29
+ :id="uniqueId"
26
30
  :title="title"
27
31
  :type="type"
28
32
  :placeholder="placeholder"
@@ -71,7 +75,7 @@
71
75
 
72
76
  <script setup>
73
77
  import PsRichTooltip from '../tooltip/PsRichTooltip.vue'
74
- import { ref, computed, useAttrs } from 'vue'
78
+ import { ref, computed, useAttrs, getCurrentInstance } from 'vue'
75
79
 
76
80
  const props = defineProps({
77
81
  /**
@@ -165,13 +169,17 @@ const props = defineProps({
165
169
 
166
170
  const emit = defineEmits(['focus', 'blur', 'mouseenter', 'mouseleave', 'input', 'keydown', 'change'])
167
171
 
172
+ defineOptions({
173
+ inheritAttrs: false
174
+ })
175
+
168
176
  const isFocus = ref(false)
169
177
  const attrs = useAttrs()
170
178
 
171
179
  const getAttrs = computed(() => {
172
180
  const defaultAttrs = {
173
181
  autocapitalize: 'sentences',
174
- autocomplete: 'chrome-off',
182
+ autocomplete: 'off',
175
183
  autocorrect: 'off',
176
184
  spellcheck: 'spellcheck',
177
185
  }
@@ -190,6 +198,10 @@ const getComponentClass = computed(() => {
190
198
  }
191
199
  })
192
200
 
201
+ const instance = getCurrentInstance()
202
+ const uid = instance?.uid || Math.random().toString(36).slice(2)
203
+ const uniqueId = computed(() => `psui-input-${uid}`)
204
+
193
205
  const onInputFocus = ($event) => {
194
206
  isFocus.value = true
195
207
  emit('focus', $event)
@@ -3,7 +3,10 @@
3
3
  class="psui-el-dialog"
4
4
  :class="getComponentClass"
5
5
  >
6
- <div class="psui-el-dialog-icon">
6
+ <div
7
+ v-if="hasIcon"
8
+ class="psui-el-dialog-icon"
9
+ >
7
10
  <i class="material-icons-round">{{ icon }}</i>
8
11
  </div>
9
12
  <div class="psui-el-dialog-wrapper">
@@ -71,6 +74,13 @@ const props = defineProps({
71
74
  type: String,
72
75
  default: 'info',
73
76
  },
77
+ /**
78
+ * It sets whether the icon should be displayed or not.
79
+ */
80
+ hasIcon: {
81
+ type: Boolean,
82
+ default: true,
83
+ },
74
84
  })
75
85
 
76
86
  const emit = defineEmits(['close'])
@@ -2,6 +2,7 @@
2
2
  <div
3
3
  class="psui-el-toast"
4
4
  :class="getComponentClass"
5
+ tabindex="0"
5
6
  >
6
7
  <i class="material-icons-round psui-el-toast-icon">{{ icon }}</i>
7
8
  <p class="psui-el-toast-message">