@pocketprep/ui-kit 3.1.0 → 3.1.1

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.
@@ -52,24 +52,30 @@ export default class ModalContainer extends Vue {
52
52
 
53
53
  focusListener: Parameters<typeof addEventListener>[1] | null = null
54
54
  savedYPosition = 0
55
+ modalNumber = 0
56
+
57
+ numberOfModals () {
58
+ return document.querySelectorAll('.uikit-modal-container').length
59
+ }
55
60
 
56
61
  mounted () {
62
+ this.modalNumber = this.numberOfModals()
57
63
  // Prevent an error where multiple modals trigger a loop
58
64
  // TODO: Find a way to have only the latest modal's focusListener active
59
- const openModals = document.querySelectorAll('.uikit-modal-container')
60
- if (openModals.length === 1) {
61
- const focusableSelectors = 'button, [href], input, select, textarea, [tabindex]'
65
+
66
+ const focusableSelectors = 'button, [href], input, select, textarea, [tabindex]'
62
67
 
63
- // Reset focus to last element in modal so next tab will move it to top
64
- const modalContainerEl = this.$refs['modalContainer'] as HTMLElement
65
- const modalFocusableEls = Array.from<HTMLElement>(modalContainerEl.querySelectorAll(focusableSelectors))
66
- if (modalFocusableEls.length) {
67
- modalFocusableEls[modalFocusableEls.length - 1]?.focus()
68
- modalFocusableEls[modalFocusableEls.length - 1]?.blur()
69
- }
68
+ // Reset focus to last element in modal so next tab will move it to top
69
+ const modalContainerEl = this.$refs['modalContainer'] as HTMLElement
70
+ const modalFocusableEls = Array.from<HTMLElement>(modalContainerEl.querySelectorAll(focusableSelectors))
71
+ if (modalFocusableEls.length) {
72
+ modalFocusableEls[modalFocusableEls.length - 1]?.focus()
73
+ modalFocusableEls[modalFocusableEls.length - 1]?.blur()
74
+ }
70
75
 
71
- // Trap the user's focus within the modal - don't allow focusing elements behind the overlay
72
- this.focusListener = event => {
76
+ // Trap the user's focus within the modal - don't allow focusing elements behind the overlay
77
+ this.focusListener = event => {
78
+ if (this.modalNumber === this.numberOfModals()) { // Only focus on the last open panel
73
79
  const target = (event as FocusEvent).target as HTMLElement // The element receiving focus
74
80
  const isFocusOutside = target && modalContainerEl && !modalContainerEl.contains(target)
75
81
  const hasCalendarClass = target
@@ -90,20 +96,20 @@ export default class ModalContainer extends Vue {
90
96
  if (firstFocusableModalChild) {
91
97
  const relatedTarget = (event as FocusEvent).relatedTarget // The element last focused
92
98
  if (relatedTarget === firstFocusableModalChild && lastFocusableModalChild) {
93
- // If focus moves from first element -> outside modal, focus the last element instead
99
+ // If focus moves from first element -> outside modal, focus the last element instead
94
100
  lastFocusableModalChild.focus()
95
101
  } else if (relatedTarget === lastFocusableModalChild && firstFocusableModalChild) {
96
- // If focus moves from last element -> outside modal, focus the first element instead
102
+ // If focus moves from last element -> outside modal, focus the first element instead
97
103
  firstFocusableModalChild.focus()
98
104
  } else if (relatedTarget && relatedTarget instanceof HTMLElement) {
99
- // If focus goes outside in a different way, return focus to where it came from if possible
105
+ // If focus goes outside in a different way, return focus to where it came from if possible
100
106
  relatedTarget.focus()
101
107
  } else {
102
- // Otherwise, just return focus to the first element
108
+ // Otherwise, just return focus to the first element
103
109
  firstFocusableModalChild.focus()
104
110
  }
105
111
  } else {
106
- // If the modal doesn't have any focusable children, focus the container instead
112
+ // If the modal doesn't have any focusable children, focus the container instead
107
113
  if (modalContainerEl.tabIndex === -1) {
108
114
  modalContainerEl.tabIndex = 0
109
115
  }
@@ -111,8 +117,8 @@ export default class ModalContainer extends Vue {
111
117
  }
112
118
  }
113
119
  }
114
- document.addEventListener('focusin', this.focusListener)
115
120
  }
121
+ document.addEventListener('focusin', this.focusListener)
116
122
 
117
123
  // prevent scrolling outside of modal
118
124
  const openModalCount = Number(document.body.getAttribute('data-openModalCount'))
@@ -142,6 +142,7 @@ export default class SidePanel extends Vue {
142
142
  notContentHeight = this.tabs && this.tabs.length ? 262 : 218
143
143
  focusListener: Parameters<typeof addEventListener>[1] | null = null
144
144
  savedYPosition = 0
145
+ sidePanelNumber = 0
145
146
 
146
147
  get sidePanelWidth () {
147
148
  return this.width === 'large'
@@ -151,57 +152,67 @@ export default class SidePanel extends Vue {
151
152
  : this.width
152
153
  }
153
154
 
155
+ numberOfSidepanels () {
156
+ return document.querySelectorAll('.uikit-side-panel').length
157
+ }
158
+
154
159
  mounted () {
155
- // Focus title after opening transition
156
- const sidePanelEl = this.$refs['uikit-side-panel'] as HTMLElement | undefined
157
- sidePanelEl?.addEventListener('transitionend', () => {
158
- const titleEl = this.$refs['uikit-side-panel__title'] as HTMLElement | undefined
159
- titleEl?.focus()
160
- })
160
+ this.sidePanelNumber = this.numberOfSidepanels()
161
161
 
162
162
  // delay opening to show animation
163
163
  setTimeout(() => {
164
164
  this.openSidePanel = true
165
165
  }, 1)
166
166
 
167
+
168
+ // Focus title after opening transition
169
+ const sidePanelEl = this.$refs['uikit-side-panel'] as HTMLElement | undefined
170
+ sidePanelEl?.addEventListener('transitionend', () => {
171
+ const titleEl = this.$refs['uikit-side-panel__title'] as HTMLElement | undefined
172
+ titleEl?.focus()
173
+ })
174
+
167
175
  // Trap the user's focus within the side panel - don't allow focusing elements behind the overlay
168
176
  this.focusListener = event => {
169
- const target = (event as FocusEvent).target as HTMLElement // The element receiving focus
170
- const sidePanelContainerEl = this.$refs['sidepanelContainer'] as HTMLElement
171
- const isFocusOutside = target && sidePanelContainerEl && !sidePanelContainerEl.contains(target)
172
- const hasCalendarClass = target
173
- && Array.from(target.classList).find(
174
- c => c === 'button-next-month' || c === 'button-previous-month' || c === 'day-item'
175
- )
176
- if (isFocusOutside && !hasCalendarClass) {
177
- const focusableSidePanelChildren = Array.from<HTMLElement>(sidePanelContainerEl.querySelectorAll(
178
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
179
- ))
180
- const firstFocusableSidePanelChild = focusableSidePanelChildren.find(
181
- el => !!el.getBoundingClientRect().width
182
- )
183
- const reversedSidePanelChildren = [ ...focusableSidePanelChildren ].reverse()
184
- const lastFocusableSidePanelChild = reversedSidePanelChildren.find(
185
- el => !!el.getBoundingClientRect().width
186
- )
187
- if (firstFocusableSidePanelChild) {
188
- const relatedTarget = (event as FocusEvent).relatedTarget // The element last focused
189
- if (relatedTarget === firstFocusableSidePanelChild && lastFocusableSidePanelChild) {
190
- // If focus moves from first element -> outside side panel, focus the last element instead
191
- lastFocusableSidePanelChild.focus()
177
+ if (this.sidePanelNumber === this.numberOfSidepanels()) { // Only focus on the last open panel
178
+ const target = (event as FocusEvent).target as HTMLElement // The element receiving focus
179
+ const sidePanelContainerEl = this.$refs['sidepanelContainer'] as HTMLElement
180
+ const isFocusOutside = target && sidePanelContainerEl && !sidePanelContainerEl.contains(target)
181
+ const hasCalendarClass = target
182
+ && Array.from(target.classList).find(
183
+ c => c === 'button-next-month' || c === 'button-previous-month' || c === 'day-item'
184
+ )
185
+ if (isFocusOutside && !hasCalendarClass) {
186
+ const focusableSidePanelChildren = Array.from<HTMLElement>(sidePanelContainerEl.querySelectorAll(
187
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
188
+ ))
189
+ const firstFocusableSidePanelChild = focusableSidePanelChildren.find(
190
+ el => !!el.getBoundingClientRect().width
191
+ )
192
+ const reversedSidePanelChildren = [ ...focusableSidePanelChildren ].reverse()
193
+ const lastFocusableSidePanelChild = reversedSidePanelChildren.find(
194
+ el => !!el.getBoundingClientRect().width
195
+ )
196
+ if (firstFocusableSidePanelChild) {
197
+ const relatedTarget = (event as FocusEvent).relatedTarget // The element last focused
198
+ if (relatedTarget === firstFocusableSidePanelChild && lastFocusableSidePanelChild) {
199
+ // If focus moves from first element -> outside side panel, focus the last element instead
200
+ lastFocusableSidePanelChild.focus()
201
+ } else {
202
+ // If focus goes outside the side panel in any other way, focus the first element
203
+ firstFocusableSidePanelChild.focus()
204
+ }
192
205
  } else {
193
- // If focus goes outside the side panel in any other way, focus the first element
194
- firstFocusableSidePanelChild.focus()
206
+ // If the side panel doesn't have any focusable children, focus the container instead
207
+ if (sidePanelContainerEl.tabIndex === -1) {
208
+ sidePanelContainerEl.tabIndex = 0
209
+ }
210
+ sidePanelContainerEl.focus()
195
211
  }
196
- } else {
197
- // If the side panel doesn't have any focusable children, focus the container instead
198
- if (sidePanelContainerEl.tabIndex === -1) {
199
- sidePanelContainerEl.tabIndex = 0
200
- }
201
- sidePanelContainerEl.focus()
202
212
  }
203
213
  }
204
214
  }
215
+
205
216
  document.addEventListener('focusin', this.focusListener)
206
217
 
207
218
  // prevent scrolling outside of modal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pocketprep/ui-kit",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Pocket Prep UI Kit",
5
5
  "author": "pocketprep",
6
6
  "scripts": {