@asd20/ui-next 2.2.2 → 2.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.3.1](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.3.0...ui-next-v2.3.1) (2026-04-14)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * fix gallery zoom; harden accordion clicks ([da17e1e](https://github.com/academydistrict20/asd20-ui-next/commit/da17e1e82cdaf73a0468e630810f2c79dfaf2d26))
9
+
10
+ # [2.3.0](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.2.2...ui-next-v2.3.0) (2026-04-13)
11
+
12
+
13
+ ### Features
14
+
15
+ * harden search functions for events, page, messages, etc. ([5c9893b](https://github.com/academydistrict20/asd20-ui-next/commit/5c9893b1c943ce1df54c35c97fc0d14b42c72221))
16
+
3
17
  ## [2.2.2](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.2.1...ui-next-v2.2.2) (2026-04-13)
4
18
 
5
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asd20/ui-next",
3
- "version": "2.2.2",
3
+ "version": "2.3.1",
4
4
  "private": false,
5
5
  "description": "ASD20 UI component library for Vue 3.",
6
6
  "license": "MIT",
@@ -23,7 +23,7 @@
23
23
  <slot name="indicator">
24
24
  <div class="asd20-swipe__indicator__list">
25
25
  <span
26
- v-for="n in $children.length"
26
+ v-for="n in slideCount"
27
27
  :key="n - 1"
28
28
  class="asd20-swipe__indicator__item"
29
29
  :style="{
@@ -43,7 +43,7 @@
43
43
  </slot>
44
44
  </div>
45
45
  <div
46
- v-if="showArrows && childLen > 1"
46
+ v-if="showArrows && slideCount > 1"
47
47
  class="asd20-swipe__arrows"
48
48
  >
49
49
  <button
@@ -116,6 +116,7 @@ export default {
116
116
  lastDiff: 0,
117
117
  cur: 0,
118
118
  index: 0,
119
+ slideCount: 0,
119
120
  childLen: 0,
120
121
  leftBorder: 0,
121
122
  rightBorder: 0,
@@ -140,6 +141,7 @@ export default {
140
141
  this.init()
141
142
  },
142
143
  beforeUnmount() {
144
+ this.unbindEvents()
143
145
  this.clearAutoplayTimer()
144
146
  },
145
147
 
@@ -151,13 +153,15 @@ export default {
151
153
  this.wrapper = this.$refs['asd20-swipe__wrapper']
152
154
  this.container = this.$refs['asd20-swipe__container']
153
155
  this.wrapWidth = this.wrapper.clientWidth
154
- this.childLen = this.$children.length
156
+ this.slideCount = this.getSlideElements().length
157
+ this.childLen = this.slideCount
155
158
 
156
159
  if (this.isLoopNeeded && this.childLen > 1) {
157
- const firstChild = this.$children[0].$el.cloneNode(true)
158
- const lastChild = this.$children[this.childLen - 1].$el.cloneNode(true)
160
+ const slideElements = this.getSlideElements()
161
+ const firstChild = slideElements[0].cloneNode(true)
162
+ const lastChild = slideElements[this.childLen - 1].cloneNode(true)
159
163
  this.container.appendChild(firstChild)
160
- this.container.insertBefore(lastChild, this.$children[0].$el)
164
+ this.container.insertBefore(lastChild, slideElements[0])
161
165
  this.childLen += 2
162
166
  this.cur = 1
163
167
  this.diff = -this.wrapWidth
@@ -172,6 +176,9 @@ export default {
172
176
  this.autoSwipe()
173
177
  }
174
178
  },
179
+ getSlideElements() {
180
+ return Array.from(this.container?.children || [])
181
+ },
175
182
 
176
183
  bindEvents() {
177
184
  this.wrapper.addEventListener('touchstart', this.handleTouchStart)
@@ -182,25 +189,44 @@ export default {
182
189
  this.wrapper.addEventListener('mousemove', this.handleMouseMove)
183
190
  this.wrapper.addEventListener('mouseup', this.handleMouseUp)
184
191
  }
185
- this.container.addEventListener('transitionend', () => {
186
- this.dur = 0
187
- if (this.isLoopNeeded) {
188
- if (this.cur === 0) {
189
- this.cur = this.childLen - 2
190
- this.diff = -this.wrapWidth * this.cur
191
- } else if (this.cur === this.childLen - 1) {
192
- this.cur = 1
193
- this.diff = -this.wrapWidth
194
- }
195
- }
196
- this.index = this.isLoopNeeded ? this.cur - 1 : this.cur
197
- this.$emit('change', this.index)
198
- this.lastDiff = this.diff
199
- this.lock = false
200
- if (this.isAutoPlayNeeded) {
201
- this.autoSwipe()
192
+ this.container.addEventListener('transitionend', this.handleTransitionEnd)
193
+ },
194
+
195
+ unbindEvents() {
196
+ if (!this.wrapper || !this.container) {
197
+ return
198
+ }
199
+
200
+ this.wrapper.removeEventListener('touchstart', this.handleTouchStart)
201
+ this.wrapper.removeEventListener('touchmove', this.handleTouchMove)
202
+ this.wrapper.removeEventListener('touchend', this.handleTouchEnd)
203
+ this.wrapper.removeEventListener('mousedown', this.handleMouseDown)
204
+ this.wrapper.removeEventListener('mousemove', this.handleMouseMove)
205
+ this.wrapper.removeEventListener('mouseup', this.handleMouseUp)
206
+ this.container.removeEventListener(
207
+ 'transitionend',
208
+ this.handleTransitionEnd
209
+ )
210
+ },
211
+
212
+ handleTransitionEnd() {
213
+ this.dur = 0
214
+ if (this.isLoopNeeded) {
215
+ if (this.cur === 0) {
216
+ this.cur = this.childLen - 2
217
+ this.diff = -this.wrapWidth * this.cur
218
+ } else if (this.cur === this.childLen - 1) {
219
+ this.cur = 1
220
+ this.diff = -this.wrapWidth
202
221
  }
203
- })
222
+ }
223
+ this.index = this.isLoopNeeded ? this.cur - 1 : this.cur
224
+ this.$emit('change', this.index)
225
+ this.lastDiff = this.diff
226
+ this.lock = false
227
+ if (this.isAutoPlayNeeded) {
228
+ this.autoSwipe()
229
+ }
204
230
  },
205
231
 
206
232
  handleTouchStart(event) {
@@ -264,7 +290,6 @@ export default {
264
290
  },
265
291
 
266
292
  handleMouseDown(event) {
267
- console.log(event)
268
293
  if (this.lock) {
269
294
  return
270
295
  }
@@ -351,6 +376,8 @@ export default {
351
376
  this.dur = this.duration
352
377
  this.diff = -this.wrapWidth * this.cur
353
378
  }
379
+ this.index = this.isLoopNeeded ? this.cur - 1 : this.cur
380
+ this.lastDiff = this.diff
354
381
  },
355
382
  download() {
356
383
  window.open(this.imageThumbnails[this.index].url, '_blank')
@@ -157,6 +157,9 @@ export default {
157
157
  this.handleResize()
158
158
  window.addEventListener('resize', this.handleResize)
159
159
  },
160
+ beforeUnmount() {
161
+ window.removeEventListener('resize', this.handleResize)
162
+ },
160
163
 
161
164
  methods: {
162
165
  handleResize() {
@@ -157,6 +157,9 @@ export default {
157
157
  this.handleResize()
158
158
  window.addEventListener('resize', this.handleResize)
159
159
  },
160
+ beforeUnmount() {
161
+ window.removeEventListener('resize', this.handleResize)
162
+ },
160
163
 
161
164
  methods: {
162
165
  handleResize() {
@@ -86,6 +86,50 @@ import pageTemplateMixin from '../../../mixins/pageTemplateMixin'
86
86
 
87
87
  // import Asd20PageContent from '../../../components/organisms/Asd20PageContent'
88
88
 
89
+ const MAX_SUGGESTED_PAGES = 10
90
+ const NO_PAGE_RESULTS_FALLBACKS = [
91
+ {
92
+ id: 'calendar',
93
+ slug: 'calendar',
94
+ title: 'Calendar',
95
+ url: '/calendar',
96
+ isNoResultsFallback: true,
97
+ categories: ['App'],
98
+ pageTypeId: 'application',
99
+ metaDescription: 'View district and school calendars.',
100
+ },
101
+ {
102
+ id: 'directory',
103
+ slug: 'directory',
104
+ title: 'Directory',
105
+ url: '/directory',
106
+ isNoResultsFallback: true,
107
+ categories: ['App'],
108
+ pageTypeId: 'application',
109
+ metaDescription: 'Find staff and department contacts.',
110
+ },
111
+ {
112
+ id: 'school-directory',
113
+ slug: 'schools',
114
+ title: 'Schools',
115
+ url: '/schools',
116
+ isNoResultsFallback: true,
117
+ categories: ['App'],
118
+ pageTypeId: 'application',
119
+ metaDescription: 'Browse all Academy District 20 schools.',
120
+ },
121
+ {
122
+ id: 'help-desk',
123
+ slug: 'help-desk',
124
+ title: 'Help Desk',
125
+ url: 'https://www.asd20.org/help-desk/',
126
+ isNoResultsFallback: true,
127
+ categories: ['Support'],
128
+ pageTypeId: 'detail-page',
129
+ metaDescription: 'Get support from the Academy District 20 Help Desk.',
130
+ },
131
+ ]
132
+
89
133
  export default {
90
134
  components: {
91
135
  Asd20List,
@@ -108,6 +152,83 @@ export default {
108
152
  },
109
153
 
110
154
  methods: {
155
+ cloneFallbackPages() {
156
+ return NO_PAGE_RESULTS_FALLBACKS.map(page => ({
157
+ ...page,
158
+ categories: Array.isArray(page.categories) ? [...page.categories] : [],
159
+ }))
160
+ },
161
+ normalizeSearchText(value = '') {
162
+ return String(value)
163
+ .toLowerCase()
164
+ .replace(/[^a-z0-9]+/g, ' ')
165
+ .trim()
166
+ },
167
+ getKeywordTokens(keywords = '') {
168
+ return Array.from(
169
+ new Set(
170
+ this.normalizeSearchText(keywords)
171
+ .split(' ')
172
+ .filter(token => token.length >= 3)
173
+ )
174
+ )
175
+ },
176
+ getSuggestedPageDedupKey(page = {}) {
177
+ const normalizedUrl = this.normalizeSearchText(page.url || '')
178
+
179
+ if (normalizedUrl) return `url:${normalizedUrl}`
180
+
181
+ const normalizedTitle = this.normalizeSearchText(page.title || '')
182
+ const normalizedSlug = this.normalizeSearchText(page.slug || '')
183
+
184
+ return `title:${normalizedTitle}|slug:${normalizedSlug}`
185
+ },
186
+ dedupeSuggestedPages(pages = []) {
187
+ const seen = new Set()
188
+
189
+ return pages.filter(page => {
190
+ const dedupKey = this.getSuggestedPageDedupKey(page)
191
+
192
+ if (!dedupKey || seen.has(dedupKey)) return false
193
+
194
+ seen.add(dedupKey)
195
+ return true
196
+ })
197
+ },
198
+ isRelevantSuggestedPage(page = {}, keywords = '') {
199
+ if (page.isNoResultsFallback) return true
200
+
201
+ const normalizedKeywords = this.normalizeSearchText(keywords)
202
+ const keywordTokens = this.getKeywordTokens(keywords)
203
+
204
+ if (!normalizedKeywords || keywordTokens.length === 0) return false
205
+
206
+ const haystack = this.normalizeSearchText([
207
+ page.title,
208
+ page.slug,
209
+ page.url,
210
+ page.metaDescription,
211
+ ...(Array.isArray(page.categories) ? page.categories : []),
212
+ ].join(' '))
213
+
214
+ if (!haystack) return false
215
+ if (haystack.includes(normalizedKeywords)) return true
216
+
217
+ return keywordTokens.some(token => haystack.includes(token))
218
+ },
219
+ sanitizeSuggestedPages(pages = [], keywords = '') {
220
+ const dedupedPages = this.dedupeSuggestedPages(
221
+ Array.isArray(pages) ? pages : []
222
+ )
223
+ const relevantPages = dedupedPages.filter(page =>
224
+ this.isRelevantSuggestedPage(page, keywords)
225
+ )
226
+ const resolvedPages = relevantPages.length
227
+ ? relevantPages
228
+ : this.cloneFallbackPages()
229
+
230
+ return resolvedPages.slice(0, MAX_SUGGESTED_PAGES)
231
+ },
111
232
  async findSuggestedPages() {
112
233
  if (typeof window !== 'undefined') {
113
234
  const keywords = window.location.pathname
@@ -115,17 +236,16 @@ export default {
115
236
  .trim()
116
237
  .toLowerCase()
117
238
  try {
118
- const { pages } = await queryPages({ keywords, top: 4 })
119
-
120
- if (Array.isArray(pages) && pages.length > 0) {
121
- this.suggestedPagesListItems = mapPagesToListItems(pages)
122
- } else {
123
- // console.warn('No pages found or pages is not an array')
124
- this.suggestedPagesListItems = []
125
- }
239
+ const { pages } = await queryPages({ keywords, top: MAX_SUGGESTED_PAGES })
240
+
241
+ this.suggestedPagesListItems = mapPagesToListItems(
242
+ this.sanitizeSuggestedPages(pages, keywords)
243
+ )
126
244
  } catch (error) {
127
245
  console.error('Error fetching suggested pages:', error)
128
- this.suggestedPagesListItems = []
246
+ this.suggestedPagesListItems = mapPagesToListItems(
247
+ this.cloneFallbackPages()
248
+ )
129
249
  }
130
250
  }
131
251
  },
@@ -217,6 +217,9 @@ export default {
217
217
  this.zoomed = window.innerHeight <= 500
218
218
  window.addEventListener('resize', this.handleResize)
219
219
  },
220
+ beforeUnmount() {
221
+ window.removeEventListener('resize', this.handleResize)
222
+ },
220
223
  methods: {
221
224
  handleResize() {
222
225
  this.zoomed = window.innerHeight <= 500
@@ -164,6 +164,7 @@ import Asd20NotificationGroup from '../../../components/organisms/Asd20Notificat
164
164
 
165
165
  // Mixins
166
166
  import pageTemplateMixin from '../../../mixins/pageTemplateMixin'
167
+ import { bindInjectedAccordionInteractions } from '../../../helpers/injectedContentInteractions'
167
168
 
168
169
  export default {
169
170
  name: 'Asd20DetailTemplate',
@@ -181,54 +182,12 @@ export default {
181
182
  },
182
183
  mixins: [pageTemplateMixin],
183
184
  mounted() {
184
- // Allow accordions to be injected into the DOM via the SuperEditor in the CommCenter
185
- this.$nextTick(() => {
186
- const accordionButtons = document.querySelectorAll('.accordion-button')
187
-
188
- accordionButtons.forEach(button => {
189
- button.addEventListener('click', () => {
190
- const contentId = button.getAttribute('aria-controls')
191
- const content = document.getElementById(contentId)
192
- const expanded = button.getAttribute('aria-expanded') === 'true'
193
-
194
- button.setAttribute('aria-expanded', !expanded)
195
- button.querySelector('.toggle-icon').textContent = expanded
196
- ? '+'
197
- : '-'
198
-
199
- if (!expanded) {
200
- content.style.display = 'block'
201
-
202
- // Reset maxHeight before calculating scrollHeight (force reflow)
203
- content.style.maxHeight = '0'
204
- content.style.padding = '0 var(--space-1, 1em)'
205
-
206
- requestAnimationFrame(() => {
207
- content.style.transition =
208
- 'max-height 0.4s ease, padding 0.4s ease'
209
- content.style.maxHeight = content.scrollHeight + 'px'
210
- content.style.padding = 'var(--space-1, 1em)'
211
- })
212
- } else {
213
- content.style.maxHeight = content.scrollHeight + 'px' // Set to current height for smooth transition
214
-
215
- requestAnimationFrame(() => {
216
- content.style.transition =
217
- 'max-height 0.4s ease, padding 0.4s ease'
218
- content.style.maxHeight = '0'
219
- content.style.padding = '0 var(--space-1, 1em)'
220
- })
221
-
222
- // Optionally hide the content after animation
223
- setTimeout(() => {
224
- if (content.style.maxHeight === '0px') {
225
- content.style.display = 'none'
226
- }
227
- }, 400) // Match transition duration
228
- }
229
- })
230
- })
231
- })
185
+ this.removeInjectedAccordionInteractions = bindInjectedAccordionInteractions(
186
+ this.$el
187
+ )
188
+ },
189
+ beforeUnmount() {
190
+ this.removeInjectedAccordionInteractions?.()
232
191
  },
233
192
  }
234
193
  </script>
@@ -156,6 +156,7 @@ import Asd20NotificationGroup from '../../../components/organisms/Asd20Notificat
156
156
 
157
157
  // Mixins
158
158
  import pageTemplateMixin from '../../../mixins/pageTemplateMixin'
159
+ import { bindInjectedAccordionInteractions } from '../../../helpers/injectedContentInteractions'
159
160
 
160
161
  export default {
161
162
  name: 'Asd20DetailImageFullTemplate',
@@ -173,54 +174,12 @@ export default {
173
174
  },
174
175
  mixins: [pageTemplateMixin],
175
176
  mounted() {
176
- // Allow accordions to be injected into the DOM via the SuperEditor in the CommCenter
177
- this.$nextTick(() => {
178
- const accordionButtons = document.querySelectorAll('.accordion-button')
179
-
180
- accordionButtons.forEach(button => {
181
- button.addEventListener('click', () => {
182
- const contentId = button.getAttribute('aria-controls')
183
- const content = document.getElementById(contentId)
184
- const expanded = button.getAttribute('aria-expanded') === 'true'
185
-
186
- button.setAttribute('aria-expanded', !expanded)
187
- button.querySelector('.toggle-icon').textContent = expanded
188
- ? '+'
189
- : '-'
190
-
191
- if (!expanded) {
192
- content.style.display = 'block'
193
-
194
- // Reset maxHeight before calculating scrollHeight (force reflow)
195
- content.style.maxHeight = '0'
196
- content.style.padding = '0 var(--space-1, 1em)'
197
-
198
- requestAnimationFrame(() => {
199
- content.style.transition =
200
- 'max-height 0.4s ease, padding 0.4s ease'
201
- content.style.maxHeight = content.scrollHeight + 'px'
202
- content.style.padding = 'var(--space-1, 1em)'
203
- })
204
- } else {
205
- content.style.maxHeight = content.scrollHeight + 'px' // Set to current height for smooth transition
206
-
207
- requestAnimationFrame(() => {
208
- content.style.transition =
209
- 'max-height 0.4s ease, padding 0.4s ease'
210
- content.style.maxHeight = '0'
211
- content.style.padding = '0 var(--space-1, 1em)'
212
- })
213
-
214
- // Optionally hide the content after animation
215
- setTimeout(() => {
216
- if (content.style.maxHeight === '0px') {
217
- content.style.display = 'none'
218
- }
219
- }, 400) // Match transition duration
220
- }
221
- })
222
- })
223
- })
177
+ this.removeInjectedAccordionInteractions = bindInjectedAccordionInteractions(
178
+ this.$el
179
+ )
180
+ },
181
+ beforeUnmount() {
182
+ this.removeInjectedAccordionInteractions?.()
224
183
  },
225
184
  }
226
185
  </script>
@@ -149,6 +149,7 @@ import Asd20NotificationGroup from '../../../components/organisms/Asd20Notificat
149
149
 
150
150
  // Mixins
151
151
  import pageTemplateMixin from '../../../mixins/pageTemplateMixin'
152
+ import { bindInjectedAccordionInteractions } from '../../../helpers/injectedContentInteractions'
152
153
 
153
154
  export default {
154
155
  name: 'Asd20DetailImageTemplate',
@@ -166,54 +167,12 @@ export default {
166
167
  },
167
168
  mixins: [pageTemplateMixin],
168
169
  mounted() {
169
- // Allow accordions to be injected into the DOM via the SuperEditor in the CommCenter
170
- this.$nextTick(() => {
171
- const accordionButtons = document.querySelectorAll('.accordion-button')
172
-
173
- accordionButtons.forEach(button => {
174
- button.addEventListener('click', () => {
175
- const contentId = button.getAttribute('aria-controls')
176
- const content = document.getElementById(contentId)
177
- const expanded = button.getAttribute('aria-expanded') === 'true'
178
-
179
- button.setAttribute('aria-expanded', !expanded)
180
- button.querySelector('.toggle-icon').textContent = expanded
181
- ? '+'
182
- : '-'
183
-
184
- if (!expanded) {
185
- content.style.display = 'block'
186
-
187
- // Reset maxHeight before calculating scrollHeight (force reflow)
188
- content.style.maxHeight = '0'
189
- content.style.padding = '0 var(--space-1, 1em)'
190
-
191
- requestAnimationFrame(() => {
192
- content.style.transition =
193
- 'max-height 0.4s ease, padding 0.4s ease'
194
- content.style.maxHeight = content.scrollHeight + 'px'
195
- content.style.padding = 'var(--space-1, 1em)'
196
- })
197
- } else {
198
- content.style.maxHeight = content.scrollHeight + 'px' // Set to current height for smooth transition
199
-
200
- requestAnimationFrame(() => {
201
- content.style.transition =
202
- 'max-height 0.4s ease, padding 0.4s ease'
203
- content.style.maxHeight = '0'
204
- content.style.padding = '0 var(--space-1, 1em)'
205
- })
206
-
207
- // Optionally hide the content after animation
208
- setTimeout(() => {
209
- if (content.style.maxHeight === '0px') {
210
- content.style.display = 'none'
211
- }
212
- }, 400) // Match transition duration
213
- }
214
- })
215
- })
216
- })
170
+ this.removeInjectedAccordionInteractions = bindInjectedAccordionInteractions(
171
+ this.$el
172
+ )
173
+ },
174
+ beforeUnmount() {
175
+ this.removeInjectedAccordionInteractions?.()
217
176
  },
218
177
  }
219
178
  </script>
@@ -149,6 +149,7 @@ import Asd20NotificationGroup from '../../../components/organisms/Asd20Notificat
149
149
 
150
150
  // Mixins
151
151
  import pageTemplateMixin from '../../../mixins/pageTemplateMixin'
152
+ import { bindInjectedAccordionInteractions } from '../../../helpers/injectedContentInteractions'
152
153
 
153
154
  export default {
154
155
  name: 'Asd20DetailTemplate',
@@ -169,54 +170,12 @@ export default {
169
170
  languageCode: { type: String, default: 'en' },
170
171
  },
171
172
  mounted() {
172
- // Allow accordions to be injected into the DOM via the SuperEditor in the CommCenter
173
- this.$nextTick(() => {
174
- const accordionButtons = document.querySelectorAll('.accordion-button')
175
-
176
- accordionButtons.forEach(button => {
177
- button.addEventListener('click', () => {
178
- const contentId = button.getAttribute('aria-controls')
179
- const content = document.getElementById(contentId)
180
- const expanded = button.getAttribute('aria-expanded') === 'true'
181
-
182
- button.setAttribute('aria-expanded', !expanded)
183
- button.querySelector('.toggle-icon').textContent = expanded
184
- ? '+'
185
- : '-'
186
-
187
- if (!expanded) {
188
- content.style.display = 'block'
189
-
190
- // Reset maxHeight before calculating scrollHeight (force reflow)
191
- content.style.maxHeight = '0'
192
- content.style.padding = '0 var(--space-1, 1em)'
193
-
194
- requestAnimationFrame(() => {
195
- content.style.transition =
196
- 'max-height 0.4s ease, padding 0.4s ease'
197
- content.style.maxHeight = content.scrollHeight + 'px'
198
- content.style.padding = 'var(--space-1, 1em)'
199
- })
200
- } else {
201
- content.style.maxHeight = content.scrollHeight + 'px' // Set to current height for smooth transition
202
-
203
- requestAnimationFrame(() => {
204
- content.style.transition =
205
- 'max-height 0.4s ease, padding 0.4s ease'
206
- content.style.maxHeight = '0'
207
- content.style.padding = '0 var(--space-1, 1em)'
208
- })
209
-
210
- // Optionally hide the content after animation
211
- setTimeout(() => {
212
- if (content.style.maxHeight === '0px') {
213
- content.style.display = 'none'
214
- }
215
- }, 400) // Match transition duration
216
- }
217
- })
218
- })
219
- })
173
+ this.removeInjectedAccordionInteractions = bindInjectedAccordionInteractions(
174
+ this.$el
175
+ )
176
+ },
177
+ beforeUnmount() {
178
+ this.removeInjectedAccordionInteractions?.()
220
179
  },
221
180
  }
222
181
  </script>
@@ -303,6 +303,9 @@ export default {
303
303
  this.$emit('events-in-view')
304
304
  }
305
305
  },
306
+ beforeUnmount() {
307
+ window.removeEventListener('resize', this.handleResize)
308
+ },
306
309
  methods: {
307
310
  handleResize() {
308
311
  this.showLogo = window.innerWidth >= 1350