11<template lang="pug">
22div(
33 v-if ="connectedDisclosure" ,
4- :class ="styles.ConnectedDisclosureWrapper"
4+ :key ="generateUpdateKey('connected')" ,
5+ :class ="styles.ConnectedDisclosureWrapper" ,
56)
67 ButtonMarkup(
78 v-bind ="buttonMarkupProps" ,
89 v-on ="listeners" ,
910 )
1011 slot
1112 Popover(
12- :active ="disclosureActive" ,
1313 preferredAlignment ="right" ,
14+ :active ="disclosureActive" ,
1415 @close ="toggleDisclosureActive" ,
1516 )
1617 template( #activator )
1718 button(
1819 type ="button" ,
1920 :class ="connectedDisclosureClassName" ,
2021 :aria-disabled ="connectedDisclosureData.disabled" ,
21- :tabIndex ="connectedDisclosureData.disabled ? -1 : undefined"
22+ :tabIndex ="connectedDisclosureData.disabled ? -1 : undefined" ,
2223 :aria-label ="connectedDisclosureData.disclosureLabel" ,
2324 :aria-describedby ="ariaDescribedBy" ,
2425 :aria-checked ="ariaChecked" ,
@@ -40,6 +41,7 @@ ButtonMarkup(
4041 v-else ,
4142 v-bind ="buttonMarkupProps" ,
4243 v-on ="listeners" ,
44+ :key ="generateUpdateKey('markup')" ,
4345)
4446 slot
4547</template >
@@ -51,9 +53,7 @@ export default {
5153 </script >
5254
5355<script setup lang="ts">
54- import {
55- computed , ref , useAttrs , useSlots ,
56- } from ' vue' ;
56+ import { computed , ref , useAttrs , useSlots } from ' vue' ;
5757import { classNames , variationName } from ' @/utilities/css' ;
5858import CaretDownMinor from ' @icons/CaretDownMinor.svg' ;
5959import { handleMouseUpByBlurring } from ' @/utilities/focus' ;
@@ -154,6 +154,8 @@ interface Props {
154154 dataPrimaryLink? : boolean ;
155155}
156156
157+ const MAX_RANDOM_NUMBER = 99999 ;
158+
157159const props = withDefaults (defineProps <Props >(), {
158160 size: ' medium' ,
159161 disclosure: undefined ,
@@ -164,22 +166,25 @@ const props = withDefaults(defineProps<Props>(), {
164166const slots = useSlots ();
165167const attrs = useAttrs ();
166168
169+ const hasChildren = !! slots .default ;
170+
171+ const disclosureActive = ref <boolean >(false );
172+
167173const listeners = computed (() => {
168174 const events = [' blur' , ' click' , ' focus' , ' keydown' , ' keypress' , ' keyup' , ' mouseover' , ' touchstart' , ' pointerdown' ];
169175 const eventBindings: Record <string , unknown > = {};
176+
170177 for (const event of events ) {
171178 const eventName = ` on${capitalize (event )} ` ;
179+
172180 if (attrs [eventName ]) {
173181 eventBindings [event ] = attrs [eventName ];
174182 }
175183 }
184+
176185 return eventBindings ;
177186});
178187
179- const hasChildren = !! slots .default ;
180-
181- const disclosureActive = ref <boolean >(false );
182-
183188const isDisabled = computed (() => props .disabled || props .loading );
184189
185190const className = computed (() => {
@@ -207,16 +212,16 @@ const className = computed(() => {
207212});
208213
209214const connectedDisclosureClassName = computed (() => {
210- const textAlignVariantion = props .textAlign
215+ const textAlignVariation = props .textAlign
211216 && variationName (' textAlign' , props .textAlign ) as keyof typeof styles ;
212- const sizeVariantion = props .size && variationName (' size' , props .size ) as keyof typeof styles ;
217+ const sizeVariation = props .size && variationName (' size' , props .size ) as keyof typeof styles ;
213218
214219 return classNames (
215220 styles .Button ,
216221 props .primary && styles .primary ,
217222 props .outline && styles .outline ,
218- props .size !== ' medium' && sizeVariantion && styles [sizeVariantion ],
219- textAlignVariantion && styles [textAlignVariantion ],
223+ props .size !== ' medium' && sizeVariation && styles [sizeVariation ],
224+ textAlignVariation && styles [textAlignVariation ],
220225 props .destructive && styles .destructive ,
221226 props .connectedDisclosure && props .connectedDisclosure .disabled && styles .disabled ,
222227 styles .iconOnly ,
@@ -226,9 +231,8 @@ const connectedDisclosureClassName = computed(() => {
226231});
227232
228233const commonProps = computed (() => {
229- const {
230- id, accessibilityLabel, role, ariaDescribedBy,
231- } = props ;
234+ const { id, accessibilityLabel, role, ariaDescribedBy } = props ;
235+
232236 return {
233237 id ,
234238 class: className .value ,
@@ -241,20 +245,23 @@ const commonProps = computed(() => {
241245
242246const linkProps = computed (() => {
243247 const { url, external, download } = props ;
248+
244249 return { url , external , download };
245250});
246251
247252const actionProps = computed (() => {
248253 const { submit, loading, pressed } = props ;
254+
249255 return {
250- submit , loading , pressed , disabled: isDisabled .value ,
256+ submit ,
257+ loading ,
258+ pressed ,
259+ disabled: isDisabled .value ,
251260 };
252261});
253262
254263const buttonMarkupProps = computed (() => {
255- const {
256- removeUnderline, disclosure, loading, icon,
257- } = props ;
264+ const { removeUnderline, disclosure, loading, icon } = props ;
258265
259266 return {
260267 commonProps: commonProps .value ,
@@ -277,6 +284,7 @@ const connectedDisclosureData = computed(() => {
277284
278285 return { disabled , disclosureLabel };
279286 }
287+
280288 return {};
281289});
282290
@@ -285,6 +293,14 @@ const toggleDisclosureActive = () => {
285293};
286294
287295const handleClick = useDisableClick (connectedDisclosureData .value .disabled , toggleDisclosureActive );
296+
297+ const generateUpdateKey = (prefix ? : string ): string => {
298+ return ` ${prefix }-${getRandomInt (MAX_RANDOM_NUMBER )}-${isDisabled .value } ` ;
299+ }
300+
301+ function getRandomInt(max : number ): number {
302+ return Math .floor (Math .random () * max );
303+ }
288304 </script >
289305
290306<style lang="scss">
0 commit comments