@@ -16,7 +16,7 @@ import {
16
16
TemplateResult ,
17
17
CSSResultArray ,
18
18
query ,
19
- ifDefined ,
19
+ PropertyValues ,
20
20
} from '@spectrum-web-components/base' ;
21
21
import { LikeAnchor } from '@spectrum-web-components/shared/src/like-anchor.js' ;
22
22
import { Focusable } from '@spectrum-web-components/shared/src/focusable.js' ;
@@ -37,18 +37,24 @@ export class ButtonBase extends LikeAnchor(
37
37
return this . slotContentIsPresent ;
38
38
}
39
39
40
+ @property ( { type : Boolean , reflect : true } )
41
+ public active = false ;
42
+
43
+ @property ( { type : String } )
44
+ public type : 'button' | 'submit' | 'reset' = 'button' ;
45
+
40
46
@property ( { type : Boolean , reflect : true , attribute : 'icon-right' } )
41
47
protected iconRight = false ;
42
48
43
- private get hasLabel ( ) : boolean {
49
+ protected get hasLabel ( ) : boolean {
44
50
return this . slotHasContent ;
45
51
}
46
52
47
53
@query ( '.button' )
48
54
private buttonElement ! : HTMLButtonElement ;
49
55
50
56
public get focusElement ( ) : HTMLElement {
51
- return this . buttonElement ;
57
+ return this . buttonElement || this ;
52
58
}
53
59
54
60
protected get buttonContent ( ) : TemplateResult [ ] {
@@ -72,15 +78,33 @@ export class ButtonBase extends LikeAnchor(
72
78
return content ;
73
79
}
74
80
81
+ public click ( ) : void {
82
+ if ( this . disabled ) {
83
+ return ;
84
+ }
85
+
86
+ if ( this . shouldProxyClick ( ) ) {
87
+ return ;
88
+ }
89
+
90
+ super . click ( ) ;
91
+ }
92
+
93
+ private shouldProxyClick ( ) : boolean {
94
+ if ( this . type !== 'button' ) {
95
+ const proxy = document . createElement ( 'button' ) ;
96
+ proxy . type = this . type ;
97
+ this . insertAdjacentElement ( 'afterend' , proxy ) ;
98
+ proxy . click ( ) ;
99
+ proxy . remove ( ) ;
100
+ return true ;
101
+ }
102
+ return false ;
103
+ }
104
+
75
105
protected renderButton ( ) : TemplateResult {
76
106
return html `
77
- < button
78
- id ="button "
79
- class ="button "
80
- aria-label =${ ifDefined ( this . label ) }
81
- >
82
- ${ this . buttonContent }
83
- </ button >
107
+ ${ this . buttonContent }
84
108
` ;
85
109
}
86
110
@@ -93,4 +117,82 @@ export class ButtonBase extends LikeAnchor(
93
117
} )
94
118
: this . renderButton ( ) ;
95
119
}
120
+
121
+ private handleKeydown ( event : KeyboardEvent ) : void {
122
+ const { code } = event ;
123
+ switch ( code ) {
124
+ case 'Space' :
125
+ this . addEventListener ( 'keyup' , this . handleKeyup ) ;
126
+ this . active = true ;
127
+ break ;
128
+ default :
129
+ break ;
130
+ }
131
+ }
132
+
133
+ private handleKeypress ( event : KeyboardEvent ) : void {
134
+ const { code } = event ;
135
+ switch ( code ) {
136
+ case 'Enter' :
137
+ this . click ( ) ;
138
+ break ;
139
+ default :
140
+ break ;
141
+ }
142
+ }
143
+
144
+ private handleKeyup ( event : KeyboardEvent ) : void {
145
+ const { code } = event ;
146
+ switch ( code ) {
147
+ case 'Space' :
148
+ this . removeEventListener ( 'keyup' , this . handleKeyup ) ;
149
+ this . active = false ;
150
+ this . click ( ) ;
151
+ break ;
152
+ default :
153
+ break ;
154
+ }
155
+ }
156
+
157
+ private handleFocusout ( ) : void {
158
+ this . active = false ;
159
+ }
160
+
161
+ private manageRole ( ) : void {
162
+ if ( this . href && this . href . length > 0 ) {
163
+ this . removeAttribute ( 'role' ) ;
164
+ this . removeEventListener ( 'keydown' , this . handleKeydown ) ;
165
+ this . removeEventListener ( 'keypress' , this . handleKeypress ) ;
166
+ } else if ( ! this . hasAttribute ( 'role' ) ) {
167
+ this . setAttribute ( 'role' , 'button' ) ;
168
+ this . addEventListener ( 'keydown' , this . handleKeydown ) ;
169
+ this . addEventListener ( 'keypress' , this . handleKeypress ) ;
170
+ }
171
+ }
172
+
173
+ protected firstUpdated ( changed : PropertyValues ) : void {
174
+ super . firstUpdated ( changed ) ;
175
+ if ( ! this . hasAttribute ( 'tabindex' ) ) {
176
+ this . tabIndex = 0 ;
177
+ }
178
+ this . manageRole ( ) ;
179
+ this . addEventListener ( 'click' , this . shouldProxyClick ) ;
180
+ }
181
+
182
+ protected updated ( changed : PropertyValues ) : void {
183
+ super . updated ( changed ) ;
184
+ if ( changed . has ( 'href' ) ) {
185
+ this . manageRole ( ) ;
186
+ }
187
+ if ( changed . has ( 'label' ) ) {
188
+ this . setAttribute ( 'aria-label' , this . label || '' ) ;
189
+ }
190
+ if ( changed . has ( 'active' ) ) {
191
+ if ( this . active ) {
192
+ this . addEventListener ( 'focusout' , this . handleFocusout ) ;
193
+ } else {
194
+ this . removeEventListener ( 'focusout' , this . handleFocusout ) ;
195
+ }
196
+ }
197
+ }
96
198
}
0 commit comments