@spectrum-web-components/button 1.12.0-next.20260223103045 → 1.12.0-next.20260429090210
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/README.md +74 -11
- package/custom-elements.json +66 -0
- package/package.json +11 -10
- package/src/Button.d.ts +1 -4
- package/src/ButtonBase.d.ts +3 -2
- package/src/ButtonBase.dev.js +21 -4
- package/src/ButtonBase.dev.js.map +2 -2
- package/src/ButtonBase.js +3 -3
- package/src/ButtonBase.js.map +2 -2
- package/src/ClearButton.d.ts +1 -4
- package/src/CloseButton.d.ts +1 -4
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ fulfill the accessibility contract of the button.
|
|
|
90
90
|
<sp-tab-panel value="icon-only">
|
|
91
91
|
|
|
92
92
|
```html demo
|
|
93
|
-
<sp-button variant="primary" label="Icon only">
|
|
93
|
+
<sp-button variant="primary" icon-only label="Icon only">
|
|
94
94
|
<sp-icon-help slot="icon"></sp-icon-help>
|
|
95
95
|
</sp-button>
|
|
96
96
|
```
|
|
@@ -251,7 +251,7 @@ The `treatment` attribute accepts `fill` and `outline` as values, and defaults t
|
|
|
251
251
|
|
|
252
252
|
```html demo
|
|
253
253
|
<sp-button-group
|
|
254
|
-
style="background: var(--spectrum-
|
|
254
|
+
style="background: var(--spectrum-docs-static-black-background-color); padding: 0.5em; min-width: max-content"
|
|
255
255
|
>
|
|
256
256
|
<sp-button treatment="outline" static-color="black">Label only</sp-button>
|
|
257
257
|
<sp-button treatment="outline" static-color="black">
|
|
@@ -275,7 +275,7 @@ The `treatment` attribute accepts `fill` and `outline` as values, and defaults t
|
|
|
275
275
|
|
|
276
276
|
```html demo
|
|
277
277
|
<sp-button-group
|
|
278
|
-
style="background: var(--spectrum-
|
|
278
|
+
style="background: var(--spectrum-docs-static-white-background-color); padding: 0.5em; min-width: max-content"
|
|
279
279
|
>
|
|
280
280
|
<sp-button treatment="outline" static-color="white">Label only</sp-button>
|
|
281
281
|
<sp-button treatment="outline" static-color="white">
|
|
@@ -336,17 +336,39 @@ Events handlers for clicks and other user actions can be registered on a
|
|
|
336
336
|
<sp-button onclick="spAlert(this, '<sp-button> clicked!')">Click me</sp-button>
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
-
|
|
339
|
+
#### Link API deprecation
|
|
340
340
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
341
|
+
> **Deprecated**: The `href`, `target`, `download`, `referrerpolicy`, and `rel` attributes on `<sp-button>` are deprecated and will be removed in a future release. Use a native HTML anchor (`<a>`) element with the `spectrum-Button` class instead.
|
|
342
|
+
|
|
343
|
+
Using `<sp-button href="...">` conflates button and link semantics, which creates accessibility issues: screen reader users navigating by form controls will not find link-styled buttons, and vice versa. Native HTML elements provide correct semantics by default.
|
|
344
|
+
|
|
345
|
+
If you intend to create a link with a `href` attribute, we instead offer CSS classes for creating button-styled links. To migrate, import the global elements stylesheet and apply button classes to native `<a>` elements:
|
|
346
|
+
|
|
347
|
+
```css
|
|
348
|
+
@import '@spectrum-web-components/styles/global-elements.css';
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**Before (deprecated):**
|
|
352
|
+
|
|
353
|
+
```html
|
|
354
|
+
<sp-button href="https://opensource.adobe.com/spectrum-web-components">
|
|
355
|
+
Visit docs
|
|
347
356
|
</sp-button>
|
|
348
357
|
```
|
|
349
358
|
|
|
359
|
+
**After (recommended):**
|
|
360
|
+
|
|
361
|
+
```html
|
|
362
|
+
<a
|
|
363
|
+
class="spectrum-Button spectrum-Button--accent"
|
|
364
|
+
href="https://opensource.adobe.com/spectrum-web-components"
|
|
365
|
+
>
|
|
366
|
+
Visit docs
|
|
367
|
+
</a>
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
See the [accessibility section](#use-a-static-button-styled-native-link-if-including-href) for more details.
|
|
371
|
+
|
|
350
372
|
#### Autofocus
|
|
351
373
|
|
|
352
374
|
The `autofocus` attribute sets focus on the `<sp-button>` when the component
|
|
@@ -374,14 +396,55 @@ or on an `<sp-icon*>` element child.
|
|
|
374
396
|
|
|
375
397
|
Do not use custom colors for buttons. The colors of different button variations have been designed to be consistent and accessible.
|
|
376
398
|
|
|
399
|
+
#### Use a static button-styled native link if including href
|
|
400
|
+
|
|
401
|
+
> **Deprecated**: The `href` attribute and other link-related properties (`target`, `download`, `referrerpolicy`, `rel`) on `<sp-button>` are deprecated and will be removed in a future release.
|
|
402
|
+
|
|
403
|
+
You may use a native link with classes to style it like a button. Refer to [the Storybook examples](https://opensource.adobe.com/spectrum-web-components/storybook/index.html?path=/story/button/) that include `href` for the appropriate classes to use.
|
|
404
|
+
|
|
405
|
+
For styles to be fully available to slotted links, you must include the stylesheet for `@spectrum-web-components/styles/global-elements.css`.
|
|
406
|
+
|
|
407
|
+
To successfully receive button styling, the link must be one of the following:
|
|
408
|
+
|
|
409
|
+
- A direct child of `<sp-theme>`
|
|
410
|
+
- A slotted child of a component within `<sp-theme>`
|
|
411
|
+
|
|
412
|
+
To allow button-styled native links in the shadow DOM of extended components, ensure their stylesheet also imports `@spectrum-web-components/styles/global-elements.css`.
|
|
413
|
+
|
|
414
|
+
**Note**: native button-styled links do not support disabled or pending states.
|
|
415
|
+
|
|
416
|
+
```html
|
|
417
|
+
<!--
|
|
418
|
+
Include in your own application stylesheet and extended component styles:
|
|
419
|
+
@import '@spectrum-web-components/styles/global-elements.css';
|
|
420
|
+
-->
|
|
421
|
+
|
|
422
|
+
<a
|
|
423
|
+
class="spectrum-Button spectrum-Button--accent"
|
|
424
|
+
href="https://github.com/adobe/spectrum-web-components"
|
|
425
|
+
>
|
|
426
|
+
Accent link button
|
|
427
|
+
</a>
|
|
428
|
+
<a
|
|
429
|
+
class="spectrum-Button spectrum-Button--secondary spectrum-Button--outline"
|
|
430
|
+
href="https://github.com/adobe/spectrum-web-components"
|
|
431
|
+
>
|
|
432
|
+
<!-- Use icon components and continue to define slot="icon" for the best styling support -->
|
|
433
|
+
<sp-icon-help slot="icon"></sp-icon-help>
|
|
434
|
+
Secondary outline link button
|
|
435
|
+
</a>
|
|
436
|
+
```
|
|
437
|
+
|
|
377
438
|
#### Don't mix href and non-href buttons in a set of buttons
|
|
378
439
|
|
|
379
|
-
A screen reader user will not encounter href buttons when navigating by buttons or form controls. While they can both be used in the same page problems could occur if mixing the types in close proximity to each other.
|
|
440
|
+
A screen reader user will not encounter href buttons when navigating by buttons or form controls. While they can both be used in the same page, problems could occur if mixing the types in close proximity to each other.
|
|
380
441
|
|
|
381
442
|
#### Use static black or static white to contrast with backgrounds and images
|
|
382
443
|
|
|
383
444
|
To ensure maximum contrast with the background, use static black for light backgrounds and images, and static white for dark backgrounds and images. Avoid placing static components on top of busy images with a lot of variance in contrast.
|
|
384
445
|
|
|
446
|
+
> **Contrast requirement**: When using `treatment="outline"` with `static-color`, the button's text, icons, and border must maintain a minimum **3:1** contrast ratio against the background per [WCAG 1.4.11 Non-text Contrast](https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast). Choose background colors carefully to meet this threshold. For example, `--spectrum-seafoam-600` provides only **2.5:1** contrast with white, which fails the requirement.
|
|
447
|
+
|
|
385
448
|
<sp-tabs selected="black" auto label="Static variants for contrast">
|
|
386
449
|
<sp-tab value="black">Static black on light background</sp-tab>
|
|
387
450
|
<sp-tab-panel value="black">
|
package/custom-elements.json
CHANGED
|
@@ -442,6 +442,20 @@
|
|
|
442
442
|
"name": "ButtonBase",
|
|
443
443
|
"module": "src/ButtonBase.js"
|
|
444
444
|
}
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"kind": "method",
|
|
448
|
+
"name": "warnLinkAPIDeprecation",
|
|
449
|
+
"privacy": "private",
|
|
450
|
+
"return": {
|
|
451
|
+
"type": {
|
|
452
|
+
"text": "void"
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
"inheritedFrom": {
|
|
456
|
+
"name": "ButtonBase",
|
|
457
|
+
"module": "src/ButtonBase.js"
|
|
458
|
+
}
|
|
445
459
|
}
|
|
446
460
|
],
|
|
447
461
|
"attributes": [
|
|
@@ -777,6 +791,16 @@
|
|
|
777
791
|
"text": "void"
|
|
778
792
|
}
|
|
779
793
|
}
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
"kind": "method",
|
|
797
|
+
"name": "warnLinkAPIDeprecation",
|
|
798
|
+
"privacy": "private",
|
|
799
|
+
"return": {
|
|
800
|
+
"type": {
|
|
801
|
+
"text": "void"
|
|
802
|
+
}
|
|
803
|
+
}
|
|
780
804
|
}
|
|
781
805
|
],
|
|
782
806
|
"attributes": [
|
|
@@ -1134,6 +1158,20 @@
|
|
|
1134
1158
|
"name": "ButtonBase",
|
|
1135
1159
|
"module": "src/ButtonBase.js"
|
|
1136
1160
|
}
|
|
1161
|
+
},
|
|
1162
|
+
{
|
|
1163
|
+
"kind": "method",
|
|
1164
|
+
"name": "warnLinkAPIDeprecation",
|
|
1165
|
+
"privacy": "private",
|
|
1166
|
+
"return": {
|
|
1167
|
+
"type": {
|
|
1168
|
+
"text": "void"
|
|
1169
|
+
}
|
|
1170
|
+
},
|
|
1171
|
+
"inheritedFrom": {
|
|
1172
|
+
"name": "ButtonBase",
|
|
1173
|
+
"module": "src/ButtonBase.js"
|
|
1174
|
+
}
|
|
1137
1175
|
}
|
|
1138
1176
|
],
|
|
1139
1177
|
"attributes": [
|
|
@@ -1536,6 +1574,20 @@
|
|
|
1536
1574
|
"name": "ButtonBase",
|
|
1537
1575
|
"module": "src/ButtonBase.js"
|
|
1538
1576
|
}
|
|
1577
|
+
},
|
|
1578
|
+
{
|
|
1579
|
+
"kind": "method",
|
|
1580
|
+
"name": "warnLinkAPIDeprecation",
|
|
1581
|
+
"privacy": "private",
|
|
1582
|
+
"return": {
|
|
1583
|
+
"type": {
|
|
1584
|
+
"text": "void"
|
|
1585
|
+
}
|
|
1586
|
+
},
|
|
1587
|
+
"inheritedFrom": {
|
|
1588
|
+
"name": "ButtonBase",
|
|
1589
|
+
"module": "src/ButtonBase.js"
|
|
1590
|
+
}
|
|
1539
1591
|
}
|
|
1540
1592
|
],
|
|
1541
1593
|
"attributes": [
|
|
@@ -1912,6 +1964,20 @@
|
|
|
1912
1964
|
"name": "ButtonBase",
|
|
1913
1965
|
"module": "src/ButtonBase.js"
|
|
1914
1966
|
}
|
|
1967
|
+
},
|
|
1968
|
+
{
|
|
1969
|
+
"kind": "method",
|
|
1970
|
+
"name": "warnLinkAPIDeprecation",
|
|
1971
|
+
"privacy": "private",
|
|
1972
|
+
"return": {
|
|
1973
|
+
"type": {
|
|
1974
|
+
"text": "void"
|
|
1975
|
+
}
|
|
1976
|
+
},
|
|
1977
|
+
"inheritedFrom": {
|
|
1978
|
+
"name": "ButtonBase",
|
|
1979
|
+
"module": "src/ButtonBase.js"
|
|
1980
|
+
}
|
|
1915
1981
|
}
|
|
1916
1982
|
]
|
|
1917
1983
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spectrum-web-components/button",
|
|
3
|
-
"version": "1.12.0-next.
|
|
3
|
+
"version": "1.12.0-next.20260429090210",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Adobe",
|
|
@@ -79,14 +79,14 @@
|
|
|
79
79
|
],
|
|
80
80
|
"types": "./src/index.d.ts",
|
|
81
81
|
"dependencies": {
|
|
82
|
-
"@spectrum-web-components/base": "1.12.0-next.
|
|
83
|
-
"@spectrum-web-components/clear-button": "1.12.0-next.
|
|
84
|
-
"@spectrum-web-components/close-button": "1.12.0-next.
|
|
85
|
-
"@spectrum-web-components/icon": "1.12.0-next.
|
|
86
|
-
"@spectrum-web-components/icons-ui": "1.12.0-next.
|
|
87
|
-
"@spectrum-web-components/progress-circle": "1.12.0-next.
|
|
88
|
-
"@spectrum-web-components/reactive-controllers": "1.12.0-next.
|
|
89
|
-
"@spectrum-web-components/shared": "1.12.0-next.
|
|
82
|
+
"@spectrum-web-components/base": "1.12.0-next.20260429090210",
|
|
83
|
+
"@spectrum-web-components/clear-button": "1.12.0-next.20260429090210",
|
|
84
|
+
"@spectrum-web-components/close-button": "1.12.0-next.20260429090210",
|
|
85
|
+
"@spectrum-web-components/icon": "1.12.0-next.20260429090210",
|
|
86
|
+
"@spectrum-web-components/icons-ui": "1.12.0-next.20260429090210",
|
|
87
|
+
"@spectrum-web-components/progress-circle": "1.12.0-next.20260429090210",
|
|
88
|
+
"@spectrum-web-components/reactive-controllers": "1.12.0-next.20260429090210",
|
|
89
|
+
"@spectrum-web-components/shared": "1.12.0-next.20260429090210"
|
|
90
90
|
},
|
|
91
91
|
"keywords": [
|
|
92
92
|
"design-system",
|
|
@@ -103,5 +103,6 @@
|
|
|
103
103
|
"publishConfig": {
|
|
104
104
|
"access": "public"
|
|
105
105
|
},
|
|
106
|
-
"customElements": "custom-elements.json"
|
|
106
|
+
"customElements": "custom-elements.json",
|
|
107
|
+
"deprecationNotice": "The link API features (href, target, download, referrerpolicy, rel) in @spectrum-web-components/button are deprecated and will be removed in a future release. Use a native HTML anchor element with the spectrum-Button class and @spectrum-web-components/styles/global-elements.css instead."
|
|
107
108
|
}
|
package/src/Button.d.ts
CHANGED
|
@@ -18,10 +18,7 @@ export type ButtonVariants = 'accent' | 'primary' | 'secondary' | 'negative' | B
|
|
|
18
18
|
export declare const VALID_VARIANTS: string[];
|
|
19
19
|
export declare const VALID_STATIC_COLORS: string[];
|
|
20
20
|
export type ButtonTreatments = 'fill' | 'outline';
|
|
21
|
-
declare const Button_base: typeof ButtonBase &
|
|
22
|
-
new (...args: any[]): import("@spectrum-web-components/base").SizedElementInterface;
|
|
23
|
-
prototype: import("@spectrum-web-components/base").SizedElementInterface;
|
|
24
|
-
} & import("@spectrum-web-components/core/mixins").SizedElementConstructor;
|
|
21
|
+
declare const Button_base: typeof ButtonBase & import("@spectrum-web-components/base").Constructor<import("@spectrum-web-components/base").SizedElementInterface> & import("@spectrum-web-components/base").SizedElementConstructor;
|
|
25
22
|
/**
|
|
26
23
|
* @element sp-button
|
|
27
24
|
*
|
package/src/ButtonBase.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ declare const ButtonBase_base: typeof Focusable & {
|
|
|
15
15
|
new (...args: any[]): import("@spectrum-web-components/shared/src/like-anchor.js").LikeAnchorInterface;
|
|
16
16
|
prototype: import("@spectrum-web-components/shared/src/like-anchor.js").LikeAnchorInterface;
|
|
17
17
|
} & {
|
|
18
|
-
new (...args: any[]): import("@spectrum-web-components/
|
|
19
|
-
prototype: import("@spectrum-web-components/
|
|
18
|
+
new (...args: any[]): import("@spectrum-web-components/shared/src/observe-slot-text.js").SlotTextObservingInterface;
|
|
19
|
+
prototype: import("@spectrum-web-components/shared/src/observe-slot-text.js").SlotTextObservingInterface;
|
|
20
20
|
};
|
|
21
21
|
/**
|
|
22
22
|
* @slot - text content to be displayed in the Button element
|
|
@@ -49,6 +49,7 @@ export declare class ButtonBase extends ButtonBase_base {
|
|
|
49
49
|
protected handleKeyup(event: KeyboardEvent): void;
|
|
50
50
|
private manageAnchor;
|
|
51
51
|
protected firstUpdated(changed: PropertyValues): void;
|
|
52
|
+
private warnLinkAPIDeprecation;
|
|
52
53
|
protected updated(changed: PropertyValues): void;
|
|
53
54
|
}
|
|
54
55
|
export {};
|
package/src/ButtonBase.dev.js
CHANGED
|
@@ -73,8 +73,13 @@ export class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), "", [
|
|
|
73
73
|
return false;
|
|
74
74
|
}
|
|
75
75
|
if (this.anchorElement) {
|
|
76
|
+
const path = (event == null ? void 0 : event.composedPath()) || [];
|
|
77
|
+
if (path.includes(this.anchorElement)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
76
80
|
this.anchorElement.click();
|
|
77
81
|
handled = true;
|
|
82
|
+
return handled;
|
|
78
83
|
} else if (this.type !== "button") {
|
|
79
84
|
const proxy = document.createElement("button");
|
|
80
85
|
proxy.type = this.type;
|
|
@@ -109,10 +114,8 @@ export class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), "", [
|
|
|
109
114
|
switch (code) {
|
|
110
115
|
case "Space":
|
|
111
116
|
event.preventDefault();
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
this.active = true;
|
|
115
|
-
}
|
|
117
|
+
this.addEventListener("keyup", this.handleKeyup);
|
|
118
|
+
this.active = true;
|
|
116
119
|
break;
|
|
117
120
|
default:
|
|
118
121
|
break;
|
|
@@ -161,10 +164,24 @@ export class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), "", [
|
|
|
161
164
|
this.addEventListener("keydown", this.handleKeydown);
|
|
162
165
|
this.addEventListener("keypress", this.handleKeypress);
|
|
163
166
|
}
|
|
167
|
+
warnLinkAPIDeprecation() {
|
|
168
|
+
if (true) {
|
|
169
|
+
const componentSlug = this.localName === "sp-action-button" ? "action-button" : "button";
|
|
170
|
+
window.__swc.warn(
|
|
171
|
+
this,
|
|
172
|
+
`The "href" attribute on <${this.localName}> is deprecated and will be removed in a future release. Use a native HTML anchor (<a>) element with Spectrum global element styling instead. Import "@spectrum-web-components/styles/global-elements.css" to enable button styling on native elements.`,
|
|
173
|
+
`'https://opensource.adobe.com/spectrum-web-components/components/${componentSlug}/#accessibility'`,
|
|
174
|
+
{ level: "deprecation" }
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
164
178
|
updated(changed) {
|
|
165
179
|
super.updated(changed);
|
|
166
180
|
if (changed.has("href")) {
|
|
167
181
|
this.manageAnchor();
|
|
182
|
+
if (this.href && this.href.length > 0) {
|
|
183
|
+
this.warnLinkAPIDeprecation();
|
|
184
|
+
}
|
|
168
185
|
}
|
|
169
186
|
if (changed.has("label")) {
|
|
170
187
|
if (this.label) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["ButtonBase.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CSSResultArray,\n html,\n PropertyValues,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { Focusable } from '@spectrum-web-components/shared/src/focusable.js';\nimport { LikeAnchor } from '@spectrum-web-components/shared/src/like-anchor.js';\nimport { ObserveSlotText } from '@spectrum-web-components/shared/src/observe-slot-text.js';\n\nimport buttonStyles from './button-base.css.js';\n\n/**\n * @slot - text content to be displayed in the Button element\n * @slot icon - icon element(s) to display at the start of the button\n */\nexport class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), '', [\n 'sp-overlay,sp-tooltip',\n]) {\n public static override get styles(): CSSResultArray {\n return [buttonStyles];\n }\n\n // TODO we need to document this property for consumers,\n // as it's not a 1:1 equivalent to active\n @property({ type: Boolean, reflect: true })\n public active = false;\n\n /**\n * The default behavior of the button.\n * Possible values are: `button` (default), `submit`, and `reset`.\n */\n @property({ type: String })\n public type: 'button' | 'submit' | 'reset' = 'button';\n\n /**\n * HTML anchor element that component clicks by proxy\n */\n @query('.anchor')\n private anchorElement!: HTMLAnchorElement;\n\n public override get focusElement(): HTMLElement {\n return this;\n }\n\n protected get hasLabel(): boolean {\n return this.slotHasContent;\n }\n\n protected get buttonContent(): TemplateResult[] {\n const content = [\n html`\n <slot name=\"icon\" ?icon-only=${!this.hasLabel}></slot>\n `,\n html`\n <span id=\"label\">\n <slot @slotchange=${this.manageTextObservedSlot}></slot>\n </span>\n `,\n ];\n return content;\n }\n\n constructor() {\n super();\n this.proxyFocus = this.proxyFocus.bind(this);\n\n this.addEventListener('click', this.handleClickCapture, {\n capture: true,\n });\n }\n\n private handleClickCapture(event: Event): void | boolean {\n if (this.disabled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return false;\n }\n\n if (this.shouldProxyClick(event as MouseEvent)) {\n return;\n }\n }\n\n private proxyFocus(): void {\n this.focus();\n }\n\n private shouldProxyClick(event?: MouseEvent): boolean {\n let handled = false;\n\n // Don't proxy clicks with modifier keys (Command/Meta, Ctrl, Shift, Alt)\n if (\n event &&\n (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)\n ) {\n return false;\n }\n\n if (this.anchorElement) {\n // Click HTML anchor element by proxy, but only for non-modified clicks\n this.anchorElement.click();\n handled = true;\n // if the button type is `submit` or `reset`\n } else if (this.type !== 'button') {\n // create an HTML Button Element by proxy, click it, and remove it\n const proxy = document.createElement('button');\n proxy.type = this.type;\n this.insertAdjacentElement('afterend', proxy);\n proxy.click();\n proxy.remove();\n handled = true;\n }\n return handled;\n }\n\n public override renderAnchor(): TemplateResult {\n return html`\n ${this.buttonContent}\n ${super.renderAnchor({\n id: 'button',\n ariaHidden: true,\n className: 'button anchor',\n tabindex: -1,\n })}\n `;\n }\n\n protected renderButton(): TemplateResult {\n return html`\n ${this.buttonContent}\n `;\n }\n\n protected override render(): TemplateResult {\n return this.href && this.href.length > 0\n ? this.renderAnchor()\n : this.renderButton();\n }\n\n protected handleKeydown(event: KeyboardEvent): void {\n const { code } = event;\n switch (code) {\n case 'Space':\n event.preventDefault();\n // allows button to activate when `Space` is pressed\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;AAYA;AAAA,EAEE;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAC1B,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAEhC,OAAO,kBAAkB;AAMlB,aAAM,mBAAmB,gBAAgB,WAAW,SAAS,GAAG,IAAI;AAAA,EACzE;AACF,CAAC,EAAE;AAAA,EA6CD,cAAc;AACZ,UAAM;AAtCR,SAAO,SAAS;AAOhB,SAAO,OAAsC;AAgC3C,SAAK,aAAa,KAAK,WAAW,KAAK,IAAI;AAE3C,SAAK,iBAAiB,SAAS,KAAK,oBAAoB;AAAA,MACtD,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAnDA,WAA2B,SAAyB;AAClD,WAAO,CAAC,YAAY;AAAA,EACtB;AAAA,EAoBA,IAAoB,eAA4B;AAC9C,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,WAAoB;AAChC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAc,gBAAkC;AAC9C,UAAM,UAAU;AAAA,MACd;AAAA,uCACiC,CAAC,KAAK,QAAQ;AAAA;AAAA,MAE/C;AAAA;AAAA,8BAEwB,KAAK,sBAAsB;AAAA;AAAA;AAAA,IAGrD;AACA,WAAO;AAAA,EACT;AAAA,EAWQ,mBAAmB,OAA8B;AACvD,QAAI,KAAK,UAAU;AACjB,YAAM,eAAe;AACrB,YAAM,yBAAyB;AAC/B,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,iBAAiB,KAAmB,GAAG;AAC9C;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,SAAK,MAAM;AAAA,EACb;AAAA,EAEQ,iBAAiB,OAA6B;AACpD,QAAI,UAAU;AAGd,QACE,UACC,MAAM,WAAW,MAAM,WAAW,MAAM,YAAY,MAAM,SAC3D;AACA,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,eAAe;
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CSSResultArray,\n html,\n PropertyValues,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { Focusable } from '@spectrum-web-components/shared/src/focusable.js';\nimport { LikeAnchor } from '@spectrum-web-components/shared/src/like-anchor.js';\nimport { ObserveSlotText } from '@spectrum-web-components/shared/src/observe-slot-text.js';\n\nimport buttonStyles from './button-base.css.js';\n\n/**\n * @slot - text content to be displayed in the Button element\n * @slot icon - icon element(s) to display at the start of the button\n */\nexport class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), '', [\n 'sp-overlay,sp-tooltip',\n]) {\n public static override get styles(): CSSResultArray {\n return [buttonStyles];\n }\n\n // TODO we need to document this property for consumers,\n // as it's not a 1:1 equivalent to active\n @property({ type: Boolean, reflect: true })\n public active = false;\n\n /**\n * The default behavior of the button.\n * Possible values are: `button` (default), `submit`, and `reset`.\n */\n @property({ type: String })\n public type: 'button' | 'submit' | 'reset' = 'button';\n\n /**\n * HTML anchor element that component clicks by proxy\n */\n @query('.anchor')\n private anchorElement!: HTMLAnchorElement;\n\n public override get focusElement(): HTMLElement {\n return this;\n }\n\n protected get hasLabel(): boolean {\n return this.slotHasContent;\n }\n\n protected get buttonContent(): TemplateResult[] {\n const content = [\n html`\n <slot name=\"icon\" ?icon-only=${!this.hasLabel}></slot>\n `,\n html`\n <span id=\"label\">\n <slot @slotchange=${this.manageTextObservedSlot}></slot>\n </span>\n `,\n ];\n return content;\n }\n\n constructor() {\n super();\n this.proxyFocus = this.proxyFocus.bind(this);\n\n this.addEventListener('click', this.handleClickCapture, {\n capture: true,\n });\n }\n\n private handleClickCapture(event: Event): void | boolean {\n if (this.disabled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return false;\n }\n\n if (this.shouldProxyClick(event as MouseEvent)) {\n return;\n }\n }\n\n private proxyFocus(): void {\n this.focus();\n }\n\n private shouldProxyClick(event?: MouseEvent): boolean {\n let handled = false;\n\n // Don't proxy clicks with modifier keys (Command/Meta, Ctrl, Shift, Alt)\n if (\n event &&\n (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)\n ) {\n return false;\n }\n\n if (this.anchorElement) {\n // Check if the click already went through the anchor element.\n // If so, the browser will handle navigation naturally and we\n // don't need to proxy the click (which would cause double navigation).\n const path = event?.composedPath() || [];\n if (path.includes(this.anchorElement)) {\n return false;\n }\n // Click HTML anchor element by proxy, but only for non-modified clicks\n this.anchorElement.click();\n handled = true;\n return handled;\n // if the button type is `submit` or `reset`\n } else if (this.type !== 'button') {\n // create an HTML Button Element by proxy, click it, and remove it\n const proxy = document.createElement('button');\n proxy.type = this.type;\n this.insertAdjacentElement('afterend', proxy);\n proxy.click();\n proxy.remove();\n handled = true;\n }\n return handled;\n }\n\n public override renderAnchor(): TemplateResult {\n return html`\n ${this.buttonContent}\n ${super.renderAnchor({\n id: 'button',\n ariaHidden: true,\n className: 'button anchor',\n tabindex: -1,\n })}\n `;\n }\n\n protected renderButton(): TemplateResult {\n return html`\n ${this.buttonContent}\n `;\n }\n\n protected override render(): TemplateResult {\n return this.href && this.href.length > 0\n ? this.renderAnchor()\n : this.renderButton();\n }\n\n protected handleKeydown(event: KeyboardEvent): void {\n const { code } = event;\n switch (code) {\n case 'Space':\n event.preventDefault();\n // allows button or link to activate when `Space` is pressed\n this.addEventListener('keyup', this.handleKeyup);\n this.active = true;\n break;\n default:\n break;\n }\n }\n\n private handleKeypress(event: KeyboardEvent): void {\n const { code } = event;\n switch (code) {\n case 'Enter':\n case 'NumpadEnter':\n // allows button or link to be activated with `Enter` and `NumpadEnter`\n this.click();\n break;\n default:\n break;\n }\n }\n\n protected handleKeyup(event: KeyboardEvent): void {\n const { code } = event;\n switch (code) {\n case 'Space':\n this.removeEventListener('keyup', this.handleKeyup);\n this.active = false;\n this.click();\n break;\n default:\n break;\n }\n }\n\n private manageAnchor(): void {\n // for a link\n if (this.href && this.href.length > 0) {\n // if the role is set to button\n if (\n !this.hasAttribute('role') ||\n this.getAttribute('role') === 'button'\n ) {\n // change role to link\n this.setAttribute('role', 'link');\n }\n // else for a button\n } else {\n // if the role is set to link\n if (!this.hasAttribute('role') || this.getAttribute('role') === 'link') {\n // change role to button\n this.setAttribute('role', 'button');\n }\n }\n }\n\n protected override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n if (!this.hasAttribute('tabindex')) {\n this.setAttribute('tabindex', '0');\n }\n\n this.manageAnchor();\n this.addEventListener('keydown', this.handleKeydown);\n this.addEventListener('keypress', this.handleKeypress);\n }\n\n private warnLinkAPIDeprecation(): void {\n if (window.__swc?.DEBUG) {\n const componentSlug =\n this.localName === 'sp-action-button' ? 'action-button' : 'button';\n window.__swc.warn(\n this,\n `The \"href\" attribute on <${this.localName}> is deprecated and will be removed in a future release. Use a native HTML anchor (<a>) element with Spectrum global element styling instead. Import \"@spectrum-web-components/styles/global-elements.css\" to enable button styling on native elements.`,\n `'https://opensource.adobe.com/spectrum-web-components/components/${componentSlug}/#accessibility'`,\n { level: 'deprecation' }\n );\n }\n }\n\n protected override updated(changed: PropertyValues): void {\n super.updated(changed);\n if (changed.has('href')) {\n this.manageAnchor();\n if (this.href && this.href.length > 0) {\n this.warnLinkAPIDeprecation();\n }\n }\n\n if (changed.has('label')) {\n if (this.label) {\n this.setAttribute('aria-label', this.label);\n } else {\n this.removeAttribute('aria-label');\n }\n }\n\n if (this.anchorElement) {\n // Ensure the anchor element is not focusable directly via tab\n this.anchorElement.tabIndex = -1;\n\n // Make sure it has proper ARIA attributes\n if (!this.anchorElement.hasAttribute('aria-hidden')) {\n this.anchorElement.setAttribute('aria-hidden', 'true');\n }\n\n // Set up focus delegation\n this.anchorElement.addEventListener('focus', this.proxyFocus);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/src/ButtonBase.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var c=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var s=(n,i,e,t)=>{for(var r=t>1?void 0:t?u(i,e):i,a=n.length-1,l;a>=0;a--)(l=n[a])&&(r=(t?l(i,e,r):l(r))||r);return t&&r&&c(i,e,r),r};import{html as o}from"@spectrum-web-components/base";import{property as h,query as d}from"@spectrum-web-components/base/src/decorators.js";import{Focusable as p}from"@spectrum-web-components/shared/src/focusable.js";import{LikeAnchor as b}from"@spectrum-web-components/shared/src/like-anchor.js";import{ObserveSlotText as m}from"@spectrum-web-components/shared/src/observe-slot-text.js";import f from"./button-base.css.js";export class ButtonBase extends m(b(p),"",["sp-overlay,sp-tooltip"]){constructor(){super();this.active=!1;this.type="button";this.proxyFocus=this.proxyFocus.bind(this),this.addEventListener("click",this.handleClickCapture,{capture:!0})}static get styles(){return[f]}get focusElement(){return this}get hasLabel(){return this.slotHasContent}get buttonContent(){return[o`
|
|
2
2
|
<slot name="icon" ?icon-only=${!this.hasLabel}></slot>
|
|
3
3
|
`,o`
|
|
4
4
|
<span id="label">
|
|
5
5
|
<slot @slotchange=${this.manageTextObservedSlot}></slot>
|
|
6
6
|
</span>
|
|
7
|
-
`]}handleClickCapture(e){if(this.disabled)return e.preventDefault(),e.stopImmediatePropagation(),!1;this.shouldProxyClick(e)}proxyFocus(){this.focus()}shouldProxyClick(e){let t=!1;if(e&&(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey))return!1;if(this.anchorElement)this.anchorElement.click(),t=!0;
|
|
7
|
+
`]}handleClickCapture(e){if(this.disabled)return e.preventDefault(),e.stopImmediatePropagation(),!1;this.shouldProxyClick(e)}proxyFocus(){this.focus()}shouldProxyClick(e){let t=!1;if(e&&(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey))return!1;if(this.anchorElement)return((e==null?void 0:e.composedPath())||[]).includes(this.anchorElement)?!1:(this.anchorElement.click(),t=!0,t);if(this.type!=="button"){const r=document.createElement("button");r.type=this.type,this.insertAdjacentElement("afterend",r),r.click(),r.remove(),t=!0}return t}renderAnchor(){return o`
|
|
8
8
|
${this.buttonContent}
|
|
9
9
|
${super.renderAnchor({id:"button",ariaHidden:!0,className:"button anchor",tabindex:-1})}
|
|
10
10
|
`}renderButton(){return o`
|
|
11
11
|
${this.buttonContent}
|
|
12
|
-
`}render(){return this.href&&this.href.length>0?this.renderAnchor():this.renderButton()}handleKeydown(e){const{code:t}=e;switch(t){case"Space":e.preventDefault(),
|
|
12
|
+
`}render(){return this.href&&this.href.length>0?this.renderAnchor():this.renderButton()}handleKeydown(e){const{code:t}=e;switch(t){case"Space":e.preventDefault(),this.addEventListener("keyup",this.handleKeyup),this.active=!0;break;default:break}}handleKeypress(e){const{code:t}=e;switch(t){case"Enter":case"NumpadEnter":this.click();break;default:break}}handleKeyup(e){const{code:t}=e;switch(t){case"Space":this.removeEventListener("keyup",this.handleKeyup),this.active=!1,this.click();break;default:break}}manageAnchor(){this.href&&this.href.length>0?(!this.hasAttribute("role")||this.getAttribute("role")==="button")&&this.setAttribute("role","link"):(!this.hasAttribute("role")||this.getAttribute("role")==="link")&&this.setAttribute("role","button")}firstUpdated(e){super.firstUpdated(e),this.hasAttribute("tabindex")||this.setAttribute("tabindex","0"),this.manageAnchor(),this.addEventListener("keydown",this.handleKeydown),this.addEventListener("keypress",this.handleKeypress)}warnLinkAPIDeprecation(){}updated(e){super.updated(e),e.has("href")&&(this.manageAnchor(),this.href&&this.href.length>0&&this.warnLinkAPIDeprecation()),e.has("label")&&(this.label?this.setAttribute("aria-label",this.label):this.removeAttribute("aria-label")),this.anchorElement&&(this.anchorElement.tabIndex=-1,this.anchorElement.hasAttribute("aria-hidden")||this.anchorElement.setAttribute("aria-hidden","true"),this.anchorElement.addEventListener("focus",this.proxyFocus))}}s([h({type:Boolean,reflect:!0})],ButtonBase.prototype,"active",2),s([h({type:String})],ButtonBase.prototype,"type",2),s([d(".anchor")],ButtonBase.prototype,"anchorElement",2);
|
|
13
13
|
//# sourceMappingURL=ButtonBase.js.map
|
package/src/ButtonBase.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["ButtonBase.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CSSResultArray,\n html,\n PropertyValues,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { Focusable } from '@spectrum-web-components/shared/src/focusable.js';\nimport { LikeAnchor } from '@spectrum-web-components/shared/src/like-anchor.js';\nimport { ObserveSlotText } from '@spectrum-web-components/shared/src/observe-slot-text.js';\n\nimport buttonStyles from './button-base.css.js';\n\n/**\n * @slot - text content to be displayed in the Button element\n * @slot icon - icon element(s) to display at the start of the button\n */\nexport class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), '', [\n 'sp-overlay,sp-tooltip',\n]) {\n public static override get styles(): CSSResultArray {\n return [buttonStyles];\n }\n\n // TODO we need to document this property for consumers,\n // as it's not a 1:1 equivalent to active\n @property({ type: Boolean, reflect: true })\n public active = false;\n\n /**\n * The default behavior of the button.\n * Possible values are: `button` (default), `submit`, and `reset`.\n */\n @property({ type: String })\n public type: 'button' | 'submit' | 'reset' = 'button';\n\n /**\n * HTML anchor element that component clicks by proxy\n */\n @query('.anchor')\n private anchorElement!: HTMLAnchorElement;\n\n public override get focusElement(): HTMLElement {\n return this;\n }\n\n protected get hasLabel(): boolean {\n return this.slotHasContent;\n }\n\n protected get buttonContent(): TemplateResult[] {\n const content = [\n html`\n <slot name=\"icon\" ?icon-only=${!this.hasLabel}></slot>\n `,\n html`\n <span id=\"label\">\n <slot @slotchange=${this.manageTextObservedSlot}></slot>\n </span>\n `,\n ];\n return content;\n }\n\n constructor() {\n super();\n this.proxyFocus = this.proxyFocus.bind(this);\n\n this.addEventListener('click', this.handleClickCapture, {\n capture: true,\n });\n }\n\n private handleClickCapture(event: Event): void | boolean {\n if (this.disabled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return false;\n }\n\n if (this.shouldProxyClick(event as MouseEvent)) {\n return;\n }\n }\n\n private proxyFocus(): void {\n this.focus();\n }\n\n private shouldProxyClick(event?: MouseEvent): boolean {\n let handled = false;\n\n // Don't proxy clicks with modifier keys (Command/Meta, Ctrl, Shift, Alt)\n if (\n event &&\n (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)\n ) {\n return false;\n }\n\n if (this.anchorElement) {\n // Click HTML anchor element by proxy, but only for non-modified clicks\n this.anchorElement.click();\n handled = true;\n // if the button type is `submit` or `reset`\n } else if (this.type !== 'button') {\n // create an HTML Button Element by proxy, click it, and remove it\n const proxy = document.createElement('button');\n proxy.type = this.type;\n this.insertAdjacentElement('afterend', proxy);\n proxy.click();\n proxy.remove();\n handled = true;\n }\n return handled;\n }\n\n public override renderAnchor(): TemplateResult {\n return html`\n ${this.buttonContent}\n ${super.renderAnchor({\n id: 'button',\n ariaHidden: true,\n className: 'button anchor',\n tabindex: -1,\n })}\n `;\n }\n\n protected renderButton(): TemplateResult {\n return html`\n ${this.buttonContent}\n `;\n }\n\n protected override render(): TemplateResult {\n return this.href && this.href.length > 0\n ? this.renderAnchor()\n : this.renderButton();\n }\n\n protected handleKeydown(event: KeyboardEvent): void {\n const { code } = event;\n switch (code) {\n case 'Space':\n event.preventDefault();\n // allows button to activate when `Space` is pressed\n
|
|
5
|
-
"mappings": "qNAYA,OAEE,QAAAA,MAGK,gCACP,OACE,YAAAC,EACA,SAAAC,MACK,kDACP,OAAS,aAAAC,MAAiB,mDAC1B,OAAS,cAAAC,MAAkB,qDAC3B,OAAS,mBAAAC,MAAuB,2DAEhC,OAAOC,MAAkB,uBAMlB,aAAM,mBAAmBD,EAAgBD,EAAWD,CAAS,EAAG,GAAI,CACzE,uBACF,CAAC,CAAE,CA6CD,aAAc,CACZ,MAAM,EAtCR,KAAO,OAAS,GAOhB,KAAO,KAAsC,SAgC3C,KAAK,WAAa,KAAK,WAAW,KAAK,IAAI,EAE3C,KAAK,iBAAiB,QAAS,KAAK,mBAAoB,CACtD,QAAS,EACX,CAAC,CACH,CAnDA,WAA2B,QAAyB,CAClD,MAAO,CAACG,CAAY,CACtB,CAoBA,IAAoB,cAA4B,CAC9C,OAAO,IACT,CAEA,IAAc,UAAoB,CAChC,OAAO,KAAK,cACd,CAEA,IAAc,eAAkC,CAW9C,MAVgB,CACdN;AAAA,uCACiC,CAAC,KAAK,QAAQ;AAAA,QAE/CA;AAAA;AAAA,8BAEwB,KAAK,sBAAsB;AAAA;AAAA,OAGrD,CAEF,CAWQ,mBAAmBO,EAA8B,CACvD,GAAI,KAAK,SACP,OAAAA,EAAM,eAAe,EACrBA,EAAM,yBAAyB,EACxB,GAGL,KAAK,iBAAiBA,CAAmB,CAG/C,CAEQ,YAAmB,CACzB,KAAK,MAAM,CACb,CAEQ,iBAAiBA,EAA6B,CACpD,IAAIC,EAAU,GAGd,GACED,IACCA,EAAM,SAAWA,EAAM,SAAWA,EAAM,UAAYA,EAAM,QAE3D,MAAO,GAGT,GAAI,KAAK,
|
|
4
|
+
"sourcesContent": ["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {\n CSSResultArray,\n html,\n PropertyValues,\n TemplateResult,\n} from '@spectrum-web-components/base';\nimport {\n property,\n query,\n} from '@spectrum-web-components/base/src/decorators.js';\nimport { Focusable } from '@spectrum-web-components/shared/src/focusable.js';\nimport { LikeAnchor } from '@spectrum-web-components/shared/src/like-anchor.js';\nimport { ObserveSlotText } from '@spectrum-web-components/shared/src/observe-slot-text.js';\n\nimport buttonStyles from './button-base.css.js';\n\n/**\n * @slot - text content to be displayed in the Button element\n * @slot icon - icon element(s) to display at the start of the button\n */\nexport class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), '', [\n 'sp-overlay,sp-tooltip',\n]) {\n public static override get styles(): CSSResultArray {\n return [buttonStyles];\n }\n\n // TODO we need to document this property for consumers,\n // as it's not a 1:1 equivalent to active\n @property({ type: Boolean, reflect: true })\n public active = false;\n\n /**\n * The default behavior of the button.\n * Possible values are: `button` (default), `submit`, and `reset`.\n */\n @property({ type: String })\n public type: 'button' | 'submit' | 'reset' = 'button';\n\n /**\n * HTML anchor element that component clicks by proxy\n */\n @query('.anchor')\n private anchorElement!: HTMLAnchorElement;\n\n public override get focusElement(): HTMLElement {\n return this;\n }\n\n protected get hasLabel(): boolean {\n return this.slotHasContent;\n }\n\n protected get buttonContent(): TemplateResult[] {\n const content = [\n html`\n <slot name=\"icon\" ?icon-only=${!this.hasLabel}></slot>\n `,\n html`\n <span id=\"label\">\n <slot @slotchange=${this.manageTextObservedSlot}></slot>\n </span>\n `,\n ];\n return content;\n }\n\n constructor() {\n super();\n this.proxyFocus = this.proxyFocus.bind(this);\n\n this.addEventListener('click', this.handleClickCapture, {\n capture: true,\n });\n }\n\n private handleClickCapture(event: Event): void | boolean {\n if (this.disabled) {\n event.preventDefault();\n event.stopImmediatePropagation();\n return false;\n }\n\n if (this.shouldProxyClick(event as MouseEvent)) {\n return;\n }\n }\n\n private proxyFocus(): void {\n this.focus();\n }\n\n private shouldProxyClick(event?: MouseEvent): boolean {\n let handled = false;\n\n // Don't proxy clicks with modifier keys (Command/Meta, Ctrl, Shift, Alt)\n if (\n event &&\n (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)\n ) {\n return false;\n }\n\n if (this.anchorElement) {\n // Check if the click already went through the anchor element.\n // If so, the browser will handle navigation naturally and we\n // don't need to proxy the click (which would cause double navigation).\n const path = event?.composedPath() || [];\n if (path.includes(this.anchorElement)) {\n return false;\n }\n // Click HTML anchor element by proxy, but only for non-modified clicks\n this.anchorElement.click();\n handled = true;\n return handled;\n // if the button type is `submit` or `reset`\n } else if (this.type !== 'button') {\n // create an HTML Button Element by proxy, click it, and remove it\n const proxy = document.createElement('button');\n proxy.type = this.type;\n this.insertAdjacentElement('afterend', proxy);\n proxy.click();\n proxy.remove();\n handled = true;\n }\n return handled;\n }\n\n public override renderAnchor(): TemplateResult {\n return html`\n ${this.buttonContent}\n ${super.renderAnchor({\n id: 'button',\n ariaHidden: true,\n className: 'button anchor',\n tabindex: -1,\n })}\n `;\n }\n\n protected renderButton(): TemplateResult {\n return html`\n ${this.buttonContent}\n `;\n }\n\n protected override render(): TemplateResult {\n return this.href && this.href.length > 0\n ? this.renderAnchor()\n : this.renderButton();\n }\n\n protected handleKeydown(event: KeyboardEvent): void {\n const { code } = event;\n switch (code) {\n case 'Space':\n event.preventDefault();\n // allows button or link to activate when `Space` is pressed\n this.addEventListener('keyup', this.handleKeyup);\n this.active = true;\n break;\n default:\n break;\n }\n }\n\n private handleKeypress(event: KeyboardEvent): void {\n const { code } = event;\n switch (code) {\n case 'Enter':\n case 'NumpadEnter':\n // allows button or link to be activated with `Enter` and `NumpadEnter`\n this.click();\n break;\n default:\n break;\n }\n }\n\n protected handleKeyup(event: KeyboardEvent): void {\n const { code } = event;\n switch (code) {\n case 'Space':\n this.removeEventListener('keyup', this.handleKeyup);\n this.active = false;\n this.click();\n break;\n default:\n break;\n }\n }\n\n private manageAnchor(): void {\n // for a link\n if (this.href && this.href.length > 0) {\n // if the role is set to button\n if (\n !this.hasAttribute('role') ||\n this.getAttribute('role') === 'button'\n ) {\n // change role to link\n this.setAttribute('role', 'link');\n }\n // else for a button\n } else {\n // if the role is set to link\n if (!this.hasAttribute('role') || this.getAttribute('role') === 'link') {\n // change role to button\n this.setAttribute('role', 'button');\n }\n }\n }\n\n protected override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n if (!this.hasAttribute('tabindex')) {\n this.setAttribute('tabindex', '0');\n }\n\n this.manageAnchor();\n this.addEventListener('keydown', this.handleKeydown);\n this.addEventListener('keypress', this.handleKeypress);\n }\n\n private warnLinkAPIDeprecation(): void {\n if (window.__swc?.DEBUG) {\n const componentSlug =\n this.localName === 'sp-action-button' ? 'action-button' : 'button';\n window.__swc.warn(\n this,\n `The \"href\" attribute on <${this.localName}> is deprecated and will be removed in a future release. Use a native HTML anchor (<a>) element with Spectrum global element styling instead. Import \"@spectrum-web-components/styles/global-elements.css\" to enable button styling on native elements.`,\n `'https://opensource.adobe.com/spectrum-web-components/components/${componentSlug}/#accessibility'`,\n { level: 'deprecation' }\n );\n }\n }\n\n protected override updated(changed: PropertyValues): void {\n super.updated(changed);\n if (changed.has('href')) {\n this.manageAnchor();\n if (this.href && this.href.length > 0) {\n this.warnLinkAPIDeprecation();\n }\n }\n\n if (changed.has('label')) {\n if (this.label) {\n this.setAttribute('aria-label', this.label);\n } else {\n this.removeAttribute('aria-label');\n }\n }\n\n if (this.anchorElement) {\n // Ensure the anchor element is not focusable directly via tab\n this.anchorElement.tabIndex = -1;\n\n // Make sure it has proper ARIA attributes\n if (!this.anchorElement.hasAttribute('aria-hidden')) {\n this.anchorElement.setAttribute('aria-hidden', 'true');\n }\n\n // Set up focus delegation\n this.anchorElement.addEventListener('focus', this.proxyFocus);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["html", "property", "query", "Focusable", "LikeAnchor", "ObserveSlotText", "buttonStyles", "event", "handled", "proxy", "code", "changed", "__decorateClass"]
|
|
7
7
|
}
|
package/src/ClearButton.d.ts
CHANGED
|
@@ -15,10 +15,7 @@ import '@spectrum-web-components/icons-ui/icons/sp-icon-cross100.js';
|
|
|
15
15
|
import '@spectrum-web-components/icons-ui/icons/sp-icon-cross200.js';
|
|
16
16
|
import '@spectrum-web-components/icons-ui/icons/sp-icon-cross300.js';
|
|
17
17
|
import { StyledButton } from './StyledButton.js';
|
|
18
|
-
declare const ClearButton_base: typeof StyledButton &
|
|
19
|
-
new (...args: any[]): import("@spectrum-web-components/base").SizedElementInterface;
|
|
20
|
-
prototype: import("@spectrum-web-components/base").SizedElementInterface;
|
|
21
|
-
} & import("@spectrum-web-components/core/mixins").SizedElementConstructor;
|
|
18
|
+
declare const ClearButton_base: typeof StyledButton & import("@spectrum-web-components/base").Constructor<import("@spectrum-web-components/base").SizedElementInterface> & import("@spectrum-web-components/base").SizedElementConstructor;
|
|
22
19
|
/**
|
|
23
20
|
* @element sp-clear-button
|
|
24
21
|
*
|
package/src/CloseButton.d.ts
CHANGED
|
@@ -16,10 +16,7 @@ import '@spectrum-web-components/icons-ui/icons/sp-icon-cross400.js';
|
|
|
16
16
|
import '@spectrum-web-components/icons-ui/icons/sp-icon-cross500.js';
|
|
17
17
|
import type { ButtonStaticColors } from './Button.js';
|
|
18
18
|
import { StyledButton } from './StyledButton.js';
|
|
19
|
-
declare const CloseButton_base: typeof StyledButton &
|
|
20
|
-
new (...args: any[]): import("@spectrum-web-components/base").SizedElementInterface;
|
|
21
|
-
prototype: import("@spectrum-web-components/base").SizedElementInterface;
|
|
22
|
-
} & import("@spectrum-web-components/core/mixins").SizedElementConstructor;
|
|
19
|
+
declare const CloseButton_base: typeof StyledButton & import("@spectrum-web-components/base").Constructor<import("@spectrum-web-components/base").SizedElementInterface> & import("@spectrum-web-components/base").SizedElementConstructor;
|
|
23
20
|
/**
|
|
24
21
|
* @element sp-close-button
|
|
25
22
|
*
|