Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e8a8c23
style(badge): clean up code styles (#6125)
rise-erpelding Apr 3, 2026
358c06b
docs(divider): follows a11y rec for real content in stories (#6123)
marissahuysentruyt Apr 3, 2026
7906a05
feat(badge): ensure visual s2 fidelity (#6114)
marissahuysentruyt Apr 3, 2026
d6e1fac
style(divider): clean up code styles (#6135)
rise-erpelding Apr 6, 2026
029939f
fix(badge): use correct line-height tokens (#6153)
marissahuysentruyt Apr 8, 2026
06a2855
feat(statuslight): ensure visual fidelity for status light (#6133)
marissahuysentruyt Apr 8, 2026
2f9f150
style(progress-circle): clean up code styles (#6146)
rise-erpelding Apr 9, 2026
ccf57d7
feat(progresscircle): export progress circle size type
marissahuysentruyt Apr 7, 2026
678b0ad
docs(progresscircle): use types in stories
marissahuysentruyt Apr 7, 2026
6a9f7a2
docs(progresscircle): update story args with defaults
marissahuysentruyt Apr 7, 2026
0f8e569
fix(progresscircle): typo fixed in force-colors variables
marissahuysentruyt Apr 7, 2026
c19f13a
docs(progresscircle): add todo for chromatic captures
marissahuysentruyt Apr 7, 2026
d244f7d
fix(progresscircle): remove canvas whcm track color
marissahuysentruyt Apr 7, 2026
c2d35e5
fix(progresscircle): remove sizing antipattern in render
marissahuysentruyt Apr 7, 2026
c19ea8c
feat(progresscircle): support reduced-motion
marissahuysentruyt Apr 7, 2026
6f864c4
feat(progresscircle): dashOffset a11y fix
marissahuysentruyt Apr 7, 2026
b524d1f
docs(progresscircle): progress circles are not focusable guidance
marissahuysentruyt Apr 8, 2026
4b48a54
chore: attempt to avoid conflict
caseyisonit Apr 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 6 additions & 33 deletions 2nd-gen/packages/core/components/badge/Badge.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,58 +102,30 @@ export abstract class BadgeBase extends SizedMixin(

/**
* The fixed position of the badge.
*
* @todo The purpose of the bespoke getter and setter is unclear, as it
* looks like they may be behaving just like a standard Lit reactive
* property. Explore replacing after milestone 2.
*/
@property({ reflect: true })
public get fixed(): FixedValues | undefined {
return this._fixed;
}

public set fixed(fixed: FixedValues | undefined) {
if (fixed === this.fixed) {
return;
}
const oldValue = this.fixed;
this._fixed = fixed;
if (fixed) {
this.setAttribute('fixed', fixed);
} else {
this.removeAttribute('fixed');
}
this.requestUpdate('fixed', oldValue);
}

private _fixed?: FixedValues;
@property({ type: String, reflect: true })
public fixed?: FixedValues;

// ──────────────────────
// IMPLEMENTATION
// ──────────────────────

/**
* Used for rendering gap when the badge has an icon.
*
* @internal
*
* Used for rendering gap when the badge has an icon.
*/
protected get hasIcon(): boolean {
return this.slotContentIsPresent;
}

/**
* @todo Migrate from update() to updated() for consistency with other
* components. The standard pattern is to use updated() for post-render
* validation (debug warnings).
*/
protected override update(changedProperties: PropertyValues): void {
super.update(changedProperties);
if (window.__swc?.DEBUG) {
const constructor = this.constructor as typeof BadgeBase;
if (!constructor.VARIANTS.includes(this.variant)) {
window.__swc.warn(
this,
`<${this.localName}> element expect the "variant" attribute to be one of the following:`,
`<${this.localName}> element expects the "variant" attribute to be one of the following:`,
'https://opensource.adobe.com/spectrum-web-components/components/badge/#variants',
{
issues: [...constructor.VARIANTS],
Expand All @@ -176,5 +148,6 @@ export abstract class BadgeBase extends SizedMixin(
);
}
}
super.update(changedProperties);
}
}
28 changes: 22 additions & 6 deletions 2nd-gen/packages/core/components/divider/Divider.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
*/
export abstract class DividerBase extends SizedMixin(SpectrumElement, {
validSizes: DIVIDER_VALID_SIZES,
/**@todo the design spec says the default size is small but we declare no default size */
/** @todo Size `s` is noted as the default in Spectrum design documentation, so be aware there is a discrepancy between the t-shirt API, which supports `m` as the default, and this component's use of `noDefaultSize` (visual default via CSS). SWC-1847 */
noDefaultSize: true,
}) {
// ──────────────────
Expand All @@ -51,18 +51,34 @@ export abstract class DividerBase extends SizedMixin(SpectrumElement, {

/**
* The static color variant to use for the divider.
*
* @todo Add runtime validation separately. When implementing,
* access STATIC_COLORS from this.constructor.STATIC_COLORS to ensure
* correct values are used.
*/
@property({ reflect: true, attribute: 'static-color' })
@property({ type: String, reflect: true, attribute: 'static-color' })
public staticColor?: DividerStaticColor;

// ──────────────────────
// IMPLEMENTATION
// ──────────────────────

protected override update(changedProperties: PropertyValues): void {
if (window.__swc?.DEBUG) {
const constructor = this.constructor as typeof DividerBase;
if (
typeof this.staticColor !== 'undefined' &&
!constructor.STATIC_COLORS.includes(this.staticColor)
) {
window.__swc.warn(
this,
`<${this.localName}> element expects the "static-color" attribute to be one of the following:`,
'https://opensource.adobe.com/spectrum-web-components/components/divider/',
{
issues: [...constructor.STATIC_COLORS],
}
);
}
}
super.update(changedProperties);
}

protected override firstUpdated(changed: PropertyValues<this>): void {
super.firstUpdated(changed);
this.setAttribute('role', 'separator');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
* governing permissions and limitations under the License.
*/
import { PropertyValues } from 'lit';
import { property, query } from 'lit/decorators.js';
import { property } from 'lit/decorators.js';

import {
LanguageResolutionController,
languageResolverUpdatedSymbol,
} from '@spectrum-web-components/core/controllers/language-resolution.js';
import { SpectrumElement } from '@spectrum-web-components/core/element/index.js';
import { SizedMixin } from '@spectrum-web-components/core/mixins/index.js';
import { getLabelFromSlot } from '@spectrum-web-components/core/utils/get-label-from-slot.js';

import {
PROGRESS_CIRCLE_VALID_SIZES,
Expand All @@ -30,14 +29,6 @@ import {
* Can be used in both determinate (with specific progress value) and indeterminate (loading) states.
*
* @attribute {ElementSize} size - The size of the progress circle.
*
* @todo Why do we support both the slot and the label attribute? Should we deprecate the slot?
*
* @todo Figure out why our tool chain doesn't respect the line breaks in this slot description.
*
* @slot - Accessible label for the progress circle.
*
* Used to provide context about what is loading or progressing.
*/
export abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, {
validSizes: PROGRESS_CIRCLE_VALID_SIZES,
Expand Down Expand Up @@ -78,6 +69,8 @@ export abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, {
// ──────────────────

/**
* @todo Revisit the default API for `indeterminate` and `progress`. SWC-1891
*
* Whether the progress circle shows indeterminate progress (loading state).
*
* When true, displays an animated loading indicator instead of a specific progress value.
Expand All @@ -96,7 +89,8 @@ export abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, {
/**
* Progress value from 0 to 100.
*
* Only relevant when indeterminate is false.
* Only relevant when indeterminate is false. Values outside that range or
* non-finite numbers are clamped to 0–100 (non-finite becomes 0).
*/
@property({ type: Number })
public progress = 0;
Expand All @@ -107,23 +101,49 @@ export abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, {
// IMPLEMENTATION
// ──────────────────────

/**
* @internal
*/
@query('slot')
private slotEl!: HTMLSlotElement;
/** True when light DOM has element nodes or non-whitespace text (no default slot). */
private static hasMeaningfulLightDomChildren(host: HTMLElement): boolean {
for (const node of host.childNodes) {
if (
node.nodeType === Node.ELEMENT_NODE ||
(node.nodeType === Node.TEXT_NODE && node.textContent?.trim())
) {
return true;
}
}
return false;
}

private warnDeprecatedLightDomChildren(): void {
if (!window.__swc?.DEBUG) {
return;
}
if (!ProgressCircleBase.hasMeaningfulLightDomChildren(this)) {
return;
}
window.__swc.warn(
this,
`<${this.localName}> no longer has a default slot. Light DOM children are not rendered and are not used for an accessible name. Use the "label" attribute or property, or "aria-label" / "aria-labelledby" on the host instead.`,
'https://opensource.adobe.com/spectrum-web-components/second-gen/?path=/docs/components-progress-circle--docs',
{ level: 'deprecation' }
);
}

protected makeRotation(rotation: number): string | undefined {
return this.indeterminate
? undefined
: `transform: rotate(${rotation}deg);`;
private static clampProgress(value: number): number {
if (!Number.isFinite(value)) {
return 0;
}
return Math.min(100, Math.max(0, value));
}

protected handleSlotchange(): void {
const labelFromSlot = getLabelFromSlot(this.label, this.slotEl);
if (labelFromSlot) {
this.label = labelFromSlot;
protected override willUpdate(changes: PropertyValues): void {
if (changes.has('progress')) {
const clamped = ProgressCircleBase.clampProgress(this.progress);
if (clamped !== this.progress) {
this.progress = clamped;
}
}
super.willUpdate(changes);
}

protected override firstUpdated(changes: PropertyValues): void {
Expand Down Expand Up @@ -151,12 +171,12 @@ export abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, {
} else {
this.setAttribute('aria-valuemin', '0');
this.setAttribute('aria-valuemax', '100');
this.setAttribute('aria-valuenow', '' + this.progress);
this.setAttribute('aria-valuenow', String(this.progress));
this.setAttribute('aria-valuetext', this.formatProgress());
}
}
if (!this.indeterminate && changes.has('progress')) {
this.setAttribute('aria-valuenow', '' + this.progress);
this.setAttribute('aria-valuenow', String(this.progress));
this.setAttribute('aria-valuetext', this.formatProgress());
}
if (!this.indeterminate && changes.has(languageResolverUpdatedSymbol)) {
Expand All @@ -174,22 +194,21 @@ export abstract class ProgressCircleBase extends SizedMixin(SpectrumElement, {
return Boolean(
this.label ||
this.getAttribute('aria-label') ||
this.getAttribute('aria-labelledby') ||
this.slotEl.assignedNodes().length
this.getAttribute('aria-labelledby')
);
};

if (window.__swc?.DEBUG) {
this.warnDeprecatedLightDomChildren();
if (!hasAccessibleName() && this.getAttribute('role') === 'progressbar') {
window.__swc?.warn(
this,
'<sp-progress-circle> elements need one of the following to be accessible:',
'https://opensource.adobe.com/spectrum-web-components/components/progress-circle/#accessibility',
`<${this.localName}> elements need one of the following to be accessible:`,
'https://opensource.adobe.com/spectrum-web-components/second-gen/?path=/docs/components-progress-circle--docs',
{
type: 'accessibility',
issues: [
'value supplied to the "label" attribute, which will be displayed visually as part of the element, or',
'text content supplied directly to the <sp-progress-circle> element, or',
'value supplied to the "aria-label" attribute, which will only be provided to screen readers, or',
'an element ID reference supplied to the "aria-labelledby" attribute, which will be provided by screen readers and will need to be managed manually by the parent application.',
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ export type ProgressCircleStaticColorS2 =
export type ProgressCircleStaticColor =
| ProgressCircleStaticColorS1
| ProgressCircleStaticColorS2;
export type ProgressCircleSize = (typeof PROGRESS_CIRCLE_VALID_SIZES)[number];
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,5 @@ export type StatusLightColorVariant =
export type StatusLightVariantS1 = (typeof STATUSLIGHT_VARIANTS_S1)[number];
export type StatusLightVariantS2 = (typeof STATUSLIGHT_VARIANTS_S2)[number];
export type StatusLightVariant = StatusLightVariantS1 | StatusLightVariantS2;

export type StatusLightSize = (typeof STATUSLIGHT_VALID_SIZES)[number];
11 changes: 7 additions & 4 deletions 2nd-gen/packages/swc/components/badge/Badge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ export class Badge extends BadgeBase {

/**
* The variant of the badge.
*
* @todo - Implement new badge variants (notification, indicator) introduced in S2. Jira ticket: SWC-1831
*/
@property({ type: String, reflect: true })
public override variant: BadgeVariant = 'informative';
public override variant: BadgeVariant = 'neutral';

// ───────────────────
// API ADDITIONS
Expand Down Expand Up @@ -104,17 +106,18 @@ export class Badge extends BadgeBase {
class=${classMap({
['swc-Badge']: true,
[`swc-Badge--${this.variant}`]: typeof this.variant !== 'undefined',
[`swc-Badge--subtle`]: this.subtle,
[`swc-Badge--outline`]: this.outline,
['swc-Badge--subtle']: this.subtle,
['swc-Badge--outline']: this.outline,
[`swc-Badge--fixed-${this.fixed}`]: typeof this.fixed !== 'undefined',
[`swc-Badge--no-label`]: !this.slotHasContent,
})}
>
${when(
this.hasIcon,
() => html`
<div
class=${classMap({
[`swc-Badge-icon`]: true,
['swc-Badge-icon']: true,
})}
>
<slot name="icon"></slot>
Expand Down
Loading