Skip to content

Conversation

marissahuysentruyt
Copy link
Collaborator

@marissahuysentruyt marissahuysentruyt commented Oct 10, 2025

Description

This PR migrates the status-light component to the second-generation architecture, creating a shared base class that both first-gen and second-gen implementations extend. This enables the component to work in both Spectrum 1 and Spectrum 2 contexts while sharing common logic.

Key changes

  • Created shared base class (@swc/core/components/status-light/StatusLight.base.ts) that contains common logic for both generations
  • Created shared types file (StatusLight.types.ts) defining variants for S1 and S2:
    • S1 variants: semantic (neutral, info, positive, negative, notice, accent) + color (fuchsia, indigo, magenta, purple, seafoam, yellow, chartreuse, celery, cyan)
    • S2 variants: semantic (neutral, info, positive, negative, notice) + color (all S1 colors plus pink, turquoise, brown, cinnamon, silver)
  • Refactored first-gen (first-gen/packages/status-light/src/StatusLight.ts) to extend the shared base class
    • Maintains S1-specific disabled property (deprecated in S2)
    • Uses S1-specific variant types
    • Added deprecation warnings for S1 types/exports
  • Implemented second-gen (second-gen/packages/swc/components/status-light/StatusLight.ts) extending the shared base class
    • Uses S2-specific variant types
    • Removed disabled property (not supported in Spectrum 2)
    • Added S2 Spectrum CSS styles
  • Enhanced stories with comprehensive examples for all variants and sizes
  • Fixed variant selectors for accent and cyan variants
  • Added size support with sizeMap decorator for consistent sizing across scales
  • Added tests for second-gen status light and a test for deprecation warnings in first-gen

Motivation and context

This migration is part of the broader effort to support Spectrum 2 design system while maintaining backward compatibility with Spectrum 1. By creating a shared base class, we reduce code duplication and ensure consistent behavior across both generations while allowing each to have generation-specific features and styling.

Related issue(s)

  • SWC-1260

Screenshots (if appropriate)

New stories for S2/second-gen:
Screenshot 2025-10-13 at 2 32 45 PM
Screenshot 2025-10-13 at 2 32 38 PM
Screenshot 2025-10-13 at 2 32 17 PM


Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed at the Accessibility Practices for this feature, see: Aria Practices
  • I have added automated tests to cover my changes.
  • I have included a well-written changeset if my change needs to be published.
  • I have included updated documentation if my change required it.

Reviewer's checklist

  • Includes a Github Issue with appropriate flag or Jira ticket number without a link
  • Includes thoughtfully written changeset if changes suggested include patch, minor, or major features
  • Automated tests cover all use cases and follow best practices for writing
  • Validated on all supported browsers
  • All VRTs are approved before the author can update Golden Hash

Manual review test cases

  • Pull down the repo to run locally.

First-gen status-light functionality

  1. Navigate to the first-gen status-light Storybook
  2. Verify all S1 variants render correctly:
    • semantic: neutral, info, positive, negative, notice
    • color: fuchsia, indigo, magenta, purple, seafoam, yellow, chartreuse, celery
  3. Verify the missing S2 variants have been added
  4. Verify disabled state still works correctly and properly adds or removes aria-disabled
  5. There should be no VRT diffs for the status light examples that were originally supported in Storybook. The only VRT diffs would include the missing accent and cyan variants.

Second-gen status-light functionality

  1. Navigate to the second-gen status-light Storybook
  2. Verify all S2 variants render correctly:
    • semantic: neutral, info, positive, negative, notice (accent was deprecated)
    • color: fuchsia, indigo, magenta, purple, seafoam, yellow, chartreuse, celery, cyan, pink, turquoise, brown, cinnamon, silver (5 new non-semantic colors)
  3. Expect visual appearance matches Spectrum 2 design specifications

Shared base class validation

  1. Verify both implementations properly extend the shared base class
  2. Expect no TypeScript errors and proper type narrowing for each generation
  3. Verify variant validation warnings appear in dev mode for invalid variants
    • First-gen: Try adding an extra S2-only story to the S1 storybook. For example, add: <sp-status-light size="s" variant="brown">brown</sp-status-light>
    • Confirm that a browser warning appears in the console:
Screenshot 2025-10-13 at 2 24 48 PM

Second-gen: Try adding an extra S1-only story to the S2 storybook. For example, add:

export const Disabled: Story = {
    render: () => html`
      <swc-status-light variant="accent" disabled>disabled</swc-status-light>`
};

Confirm that a browser warning appears in the console:

Screenshot 2025-10-13 at 2 44 11 PM

Replace the variant value with something valid for S2, then reconfirm the new disabled console warning appears in the browser:

Screenshot 2025-10-13 at 2 28 27 PM

Device review

  • Did it pass in Desktop?
  • Did it pass in (emulated) Mobile?
  • Did it pass in (emulated) iPad?

Copy link

changeset-bot bot commented Oct 10, 2025

⚠️ No Changeset found

Latest commit: 4d57a9b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@marissahuysentruyt marissahuysentruyt self-assigned this Oct 10, 2025
@marissahuysentruyt marissahuysentruyt added WIP Component: Status light S2 2nd gen These issues or PRs map to our 2nd generation work to modernizing infrastructure. Spectrum CSS Spectrum 2 Issues related to Spectrum 2 labels Oct 10, 2025
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1260-status-light-s2-migration branch 2 times, most recently from faba5c8 to f32d35c Compare October 13, 2025 16:45
Copy link
Contributor

github-actions bot commented Oct 13, 2025

📚 Branch Preview

🔍 Visual Regression Test Results

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

Deployed to Azure Blob Storage: pr-5800

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

Copy link
Contributor

Tachometer results

Currently, no packages are changed by this PR...

@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1260-status-light-s2-migration branch from f32d35c to a22afc0 Compare October 13, 2025 18:14
@marissahuysentruyt marissahuysentruyt changed the title Marissahuysentruyt/swc 1260 status light s2 migration feat(status-light)!: migrate status-light to s2 styles and second-gen architecture Oct 13, 2025
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1260-status-light-s2-migration branch from a22afc0 to 888651e Compare October 14, 2025 19:36
// ───────────────────────

/**
* @todo This property is deprecated in S2, and can be removed once we are no longer maintaining S1.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops- should this be @deprecated instead?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think we should just go ahead and deprecate this, with an appropriate customer-facing message, similar to the ones for the other deprecations in this file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should now be updated 👍

6528bc6

}

.spectrum-StatusLight--accent:before {
:host([variant="accent"]):before {
Copy link
Collaborator Author

@marissahuysentruyt marissahuysentruyt Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 2 updates in the first-gen CSS correspond to the gaps that were identified in the component docs. Is it still in scope for me to correct these missing variants? It obviously introduces VRT diffs, so I'm not sure where or if or when we want to introduce those diffs.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! Without digging too deeply, it looks to me like these were just cases where our (now-retired) automatic conversion of Spectrum CSS styles to SWC styles was failing—i.e., these were just bugs. Does that seem right to you?

As a matter of principle, my preference would be to split these fixes out into a separate PR, with a changeset describing the fixes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense personally but maybe we can also open PRs to fix it on main?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were 2 commits related to the implementation gaps that are now reverted (one for the CSS and then one for the first-gen stories).

I pulled those 2 commits into a separate branch based on main. I haven't pushed the new branch up yet, but can if we think that's where the work should merge- just let me know!

expect(el.getAttribute('aria-disabled')).to.equal('true');
});

describe('dev mode warnings', () => {
Copy link
Collaborator Author

@marissahuysentruyt marissahuysentruyt Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had Cursor help me with this- do we want tests for the dev warnings at all? Feedback on this is appreciated either way!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a good idea to me, but open to dissenting opinions (cc @rubencarvalho).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we do test for dev mode on other components so I think that makes a lot of sense to add here too. Check out this reference for an example:

it('should log dev warning when given invalid variant', async () => {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine! We’ll probably want to create a dedicated test helper to remove some boilerplate from these dev warnings tests, but this looks good for now 😃

Comment on lines 27 to 31
argTypes.variant = {
...argTypes.variant,
name: 'Variant',
description:
'Changes the color of the status dot. The variant list includes both semantic and non-semantic options.',
type: { name: 'string', required: true },
table: {
type: { summary: 'string' },
defaultValue: { summary: 'info' },
category: 'Component',
},
control: { type: 'select' },
options: StatusLight.VARIANTS,
};
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to tell me to remove this and just follow what Badge is doing! This was the way I found that worked to populate more of the control table, but maybe that's not something we want to dive into right now. (and also this approach didn't really work with the default slot arg, sooo...it's not fool-proof 😆)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our vision for where this is going is that pretty much everything populating the table will flow from our code (including JSDocs) all the way through to Storybook, with little to no need for manual intervention in the *.stories.ts files.

To the extent that's not happening yet, I'd like to see if we can diagnose and fix issues in our tooling pipeline.

Meanwhile, I'd like to see us take a light touch, making minor tweaks as needed to unblock / ease testing during development, but otherwise not striving to manually fill gaps between what's currently showing and where we'd eventually like to get.

Since we're not expecting customers to be referring to the 2nd-gen Storybook for some time yet, the rough edges shouldn't hurt anyone, and their continued presence should help incentivize us to address the root-cause issues in the tool chain! 😁

If I look at what you've done here and compare it to the equivalent of what's being done in Badge:

argTypes.variant = {
    ...argTypes.variant,
    control: { type: 'select' },
    options: StatusLight.VARIANTS,
};

...they seem essentially equivalent in terms of behavior, and your improvement to the description can be achieved by editing the JSDoc in component implementation, so I'd like to see us fall back to the lighter version. Does that make sense? Let me know if I'm missing anything significant.

(Ultimately, I'm hoping we don't even have to do this much augmentation—I think we should be able to dial in our tooling to the point where it all "just works.")

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see- thanks for this explanation. This will be something I need to keep in the back of my mind going forward, so thank you!

I updated the JSDoc for the variant prop, and then refactored the argTypes.variant definition to match badge in this commit: f5ed8fd

};

// ────────────────────────
// HELPER FUNCTIONS
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pulled capitalize() and CONTAINER() from the other migrations, and then created a size map function for the labels in the size stories. This was totally personal preference, so I'm not offended if we don't like it and want to drop it.

Screenshot 2025-10-14 at 3 50 23 PM

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! 👍 We’ll definitely find a place for these utils post-barebones.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor pulled in the badge test patterns and created this status light test file. Is this something appropriate for the migration, or would you like me to separate this out into a different PR?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically speaking, tests weren't required for these Barebones component migrations.

I am neutral on whether we take these as part of this PR or pull them out and consider testing more holistically across the Barebones components.

@rubencarvalho, thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly created the tests for Badge to have something to run the infrastructure on. I tried to keep them as simple and focused as possible, and I think these are also pretty straightforward. This seems fine as a starting point, but we’ll almost certainly revisit it post-barebones.

@marissahuysentruyt marissahuysentruyt marked this pull request as ready for review October 14, 2025 19:56
@marissahuysentruyt marissahuysentruyt requested a review from a team as a code owner October 14, 2025 19:56
@adobe adobe deleted a comment from cursor bot Oct 14, 2025
Comment on lines +46 to +43
* We may have to explicitly bind the args to the component (particularly
* helpful for the size property) so the Storybook controls work as expected.
*
* i.e. render: (args) =>
html`<swc-status-light .size=${args.size} variant=${args.variant}
>${args['default-slot']}</swc-status-light
>`,
Copy link
Collaborator Author

@marissahuysentruyt marissahuysentruyt Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this comment is too much/overkill, let me know. I did document this idea in #5798, as well.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getStorybookHelpers function is supposed to automatically handle the bindings, but it's not working as expected for certain properties; in the case of size, I think it's probably because properties from mixins are not propagating as they should through the Custom Element Manifest generation process.

I see this falling into the same category I was discussing in my previous comment—our preferred option is to see if we can make our tooling "just work", so we don't have to manually bind templates in our stories. If we try that and fail, then I think we can fall back to something like this.

Copy link
Collaborator Author

@marissahuysentruyt marissahuysentruyt Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't removed the comment yet, but certainly can if you'd rather we don't muddy up the file with too many random thoughts/ideas!

I did, however, change the commented out section for argTypes.size to remove all of the extra args I had so that it matched Badge once more. 282eb11

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes... at the risk of repeating what was said above - this is one of those things that should just work™. We’ll probably want to prioritize researching it, as it may also be masking other issues beyond template binding (like attribute, property, or type propagation).

args: {
['default-slot']: 'Status light',
variant: 'info',
size: 'm',
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this conflict with the noDefaultSize arg in StatusLightBase (for SizedMixin)? I don't have a good handle on the SizedMixin, but there is a default size defined in the design specs.

Maybe I need to do a Cursor dive into SizedMixin!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good question! SizedMixin is not too complex, so the implications of noDefaultSize should be easy enough to reason about. Not having thought through the nuances, and without knowing the history, it's hard to say why SWC would be applying noDefaultSize if the design does, in fact, call for a default size, but I'm hopeful we'll be able to make sense of it.

Meanwhile, I would guess that there's no issue with having a default size from a Storybook perspective, even if there are legitimate technical reasons why noDefaultSize is the right choice from a SizedMixin point of view.

That said, for the sake of consistency in the way we're overriding args in our Barebones stories, I'd prefer that we insert these lines above the declaration of meta:

args['default-slot'] = 'Status light';
args.size = 'm';

...and then just refer to args in the meta declaration, rather than define it inline, e.g.:

const meta: Meta = {
    /* other props... */
    args,
};

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it- changes were made here! a4e459a

Would you like me to make a ticket to look into this noDefaultSize? I can also create one to investigate why the size attribute isn't getting bound to the template properly.

Out of curiosity, what's the reason for having the arg overrides (like the args.size = "m") outside of the meta declaration? Is there less risk of overriding something on accident when things are more separated? Just trying to add to my understanding for second-gen! 😊

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, what's the reason for having the arg overrides (like the args.size = "m") outside of the meta declaration?

TBH, there's not any one super compelling reason—either way works fine, of course. I hadn't really explicitly thought through my rationale, but I think it's something like this:

  • My mental model for 2nd-gen Storybook meta info is as described in a couple of earlier comments—I would ultimately like to get our tool chain humming to the point where we just get call getStorybookHelpers to get argTypes and args and plop them into the meta declaration without any need to modify them at all—so I think that's why my preference is to reference them that way for now...all of the current overrides / additions are self-contained and can just be deleted if/when we don't need them.
  • Whatever we do, it would just be nice to be as consistent as we can across components. I foresee us incrementally evolving our best practices for story authoring (and everything else, for that matter) as 2nd-gen progresses, so imagine us coming back and making multiple refinement passes over each component, and I just think that will be easier to do if we try to minimize arbitrary differences from component to component as we go.

Does that make sense?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like me to make a ticket to look into this noDefaultSize? I can also create one to investigate why the size attribute isn't getting bound to the template properly.

Yes, that would be awesome—thank you!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it- yeah, makes sense! Thank you! I can make those tickets, as well. 🙌

Copy link
Contributor

@castastrophe castastrophe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really great to me. Thanks for tackling this!

}

.spectrum-StatusLight--accent:before {
:host([variant="accent"]):before {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense personally but maybe we can also open PRs to fix it on main?

expect(el.getAttribute('aria-disabled')).to.equal('true');
});

describe('dev mode warnings', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we do test for dev mode on other components so I think that makes a lot of sense to add here too. Check out this reference for an example:

it('should log dev warning when given invalid variant', async () => {

Comment on lines 27 to 31
argTypes.variant = {
...argTypes.variant,
name: 'Variant',
description:
'Changes the color of the status dot. The variant list includes both semantic and non-semantic options.',
type: { name: 'string', required: true },
table: {
type: { summary: 'string' },
defaultValue: { summary: 'info' },
category: 'Component',
},
control: { type: 'select' },
options: StatusLight.VARIANTS,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it!

Copy link
Collaborator

@graynorton graynorton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really good—nice work! 😊

Most of my comments are about places where you've gone above and beyond Barebones requirements in ways that I think we may either want to pull out into separate PRs or just hold off on for right now—let's discuss in the comment threads.

}

.spectrum-StatusLight--accent:before {
:host([variant="accent"]):before {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! Without digging too deeply, it looks to me like these were just cases where our (now-retired) automatic conversion of Spectrum CSS styles to SWC styles was failing—i.e., these were just bugs. Does that seem right to you?

As a matter of principle, my preference would be to split these fixes out into a separate PR, with a changeset describing the fixes.

// ───────────────────────

/**
* @todo This property is deprecated in S2, and can be removed once we are no longer maintaining S1.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think we should just go ahead and deprecate this, with an appropriate customer-facing message, similar to the ones for the other deprecations in this file.

expect(el.getAttribute('aria-disabled')).to.equal('true');
});

describe('dev mode warnings', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a good idea to me, but open to dissenting opinions (cc @rubencarvalho).

Comment on lines 102 to 114
// Check disabled property if it exists (S1 only)
if (this.hasAttribute('disabled') && !('disabled' in this)) {
window.__swc.warn(
this,
`<${this.localName}> element does not support the disabled state.`,
'https://opensource.adobe.com/spectrum-web-components/components/status-light/#states',
{
issues: [
'disabled is not a supported property in Spectrum 2',
],
}
);
} else if (this.hasAttribute('disabled') && 'disabled' in this) {
// Set aria-disabled when no warning is shown
if (!this.hasAttribute('aria-disabled')) {
this.setAttribute('aria-disabled', 'true');
} else {
this.removeAttribute('aria-disabled');
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is interestingly different from the similar case in Badge, and I think we should do something slightly different here.

In Badge, we're doing validation of a feature introduced in S2 (outline), which is expected to carry on into the foreseeable future, so it seemed to make sense to put that validation logic in the base class rather than in the 2nd-gen SWC subclass.

In this case, we have two bits of logic related to a feature being removed in S2 (disabled):

  • Validation to warn when customers try to apply disabled in an S2 context
  • S1-specific logic for managing state related to the disabled feature

I'd argue that the latter should just live in the S1-specific subclass, where it will eventually fade away into oblivion without further action from us.

The former can stay here, at least for now. @rubencarvalho and I have been discussing the fact that, before going much further, we should decide on an overall philosophy regarding runtime validation of 1st-gen-to-2nd-gen changes (how much of it we want to do, and in what cases).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, ok now I understand. Let me know if this is what you were thinking for now. The disabled logic has been removed from the base class and moved into the S1 component instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can’t see the referenced commits in your comment, @marissahuysentruyt, but my initial thought (and I think this probably warrants a focused discussion around these dev warnings holistically post-barebones) is that we shouldn’t let 1st-gen, soon-to-be-removed properties leak into 2nd-gen. That way, when we phase out 1st-gen, there’s no technical debt lingering in 2nd-gen code that needs cleanup.

Comment on lines 27 to 31
argTypes.variant = {
...argTypes.variant,
name: 'Variant',
description:
'Changes the color of the status dot. The variant list includes both semantic and non-semantic options.',
type: { name: 'string', required: true },
table: {
type: { summary: 'string' },
defaultValue: { summary: 'info' },
category: 'Component',
},
control: { type: 'select' },
options: StatusLight.VARIANTS,
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our vision for where this is going is that pretty much everything populating the table will flow from our code (including JSDocs) all the way through to Storybook, with little to no need for manual intervention in the *.stories.ts files.

To the extent that's not happening yet, I'd like to see if we can diagnose and fix issues in our tooling pipeline.

Meanwhile, I'd like to see us take a light touch, making minor tweaks as needed to unblock / ease testing during development, but otherwise not striving to manually fill gaps between what's currently showing and where we'd eventually like to get.

Since we're not expecting customers to be referring to the 2nd-gen Storybook for some time yet, the rough edges shouldn't hurt anyone, and their continued presence should help incentivize us to address the root-cause issues in the tool chain! 😁

If I look at what you've done here and compare it to the equivalent of what's being done in Badge:

argTypes.variant = {
    ...argTypes.variant,
    control: { type: 'select' },
    options: StatusLight.VARIANTS,
};

...they seem essentially equivalent in terms of behavior, and your improvement to the description can be achieved by editing the JSDoc in component implementation, so I'd like to see us fall back to the lighter version. Does that make sense? Let me know if I'm missing anything significant.

(Ultimately, I'm hoping we don't even have to do this much augmentation—I think we should be able to dial in our tooling to the point where it all "just works.")

Comment on lines +46 to +43
* We may have to explicitly bind the args to the component (particularly
* helpful for the size property) so the Storybook controls work as expected.
*
* i.e. render: (args) =>
html`<swc-status-light .size=${args.size} variant=${args.variant}
>${args['default-slot']}</swc-status-light
>`,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getStorybookHelpers function is supposed to automatically handle the bindings, but it's not working as expected for certain properties; in the case of size, I think it's probably because properties from mixins are not propagating as they should through the Custom Element Manifest generation process.

I see this falling into the same category I was discussing in my previous comment—our preferred option is to see if we can make our tooling "just work", so we don't have to manually bind templates in our stories. If we try that and fail, then I think we can fall back to something like this.

args: {
['default-slot']: 'Status light',
variant: 'info',
size: 'm',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good question! SizedMixin is not too complex, so the implications of noDefaultSize should be easy enough to reason about. Not having thought through the nuances, and without knowing the history, it's hard to say why SWC would be applying noDefaultSize if the design does, in fact, call for a default size, but I'm hopeful we'll be able to make sense of it.

Meanwhile, I would guess that there's no issue with having a default size from a Storybook perspective, even if there are legitimate technical reasons why noDefaultSize is the right choice from a SizedMixin point of view.

That said, for the sake of consistency in the way we're overriding args in our Barebones stories, I'd prefer that we insert these lines above the declaration of meta:

args['default-slot'] = 'Status light';
args.size = 'm';

...and then just refer to args in the meta declaration, rather than define it inline, e.g.:

const meta: Meta = {
    /* other props... */
    args,
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically speaking, tests weren't required for these Barebones component migrations.

I am neutral on whether we take these as part of this PR or pull them out and consider testing more holistically across the Barebones components.

@rubencarvalho, thoughts?

Copy link
Collaborator

@graynorton graynorton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Awesome work on this, @marissahuysentruyt! 👏 🙌

- imports new types
- adds the api overrides for color and semantic variants
- adds documentation
- ensures the disabled state is not supported in S2 and throws a warning
- ensures the disabled property still adds the aria-disabled attribute
for S1
- ensures the variants values are validated and throws a warning if not
- imports new S2 types for colors and semantic variants
- adds the api overrides
- adds documentation and example usage
- refactors template render to use CSS classes and classMap()
- imports new S1 types for colors and semantic variants
- adds the api overrides and extra disabled property
- adds documentation, deprecation notices, and example usage
we'll open up a new PR to address the missing variants.
we'll open up a new PR to address the missing variants.
- moves the disabled logic to the StatusLight subclass in first-gen
@marissahuysentruyt marissahuysentruyt force-pushed the marissahuysentruyt/swc-1260-status-light-s2-migration branch from 155e58b to 4d57a9b Compare October 17, 2025 18:06
@marissahuysentruyt marissahuysentruyt added ready-for-merge Will auto-update until merged and removed ready-for-review WIP labels Oct 17, 2025
Copy link
Contributor

@rubencarvalho rubencarvalho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replied to some comments! This is really good 👍 Thank you for the PR!
More data to help us prioritize work post-barebones as well.

};

// ────────────────────────
// HELPER FUNCTIONS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! 👍 We’ll definitely find a place for these utils post-barebones.

Comment on lines +46 to +43
* We may have to explicitly bind the args to the component (particularly
* helpful for the size property) so the Storybook controls work as expected.
*
* i.e. render: (args) =>
html`<swc-status-light .size=${args.size} variant=${args.variant}
>${args['default-slot']}</swc-status-light
>`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes... at the risk of repeating what was said above - this is one of those things that should just work™. We’ll probably want to prioritize researching it, as it may also be masking other issues beyond template binding (like attribute, property, or type propagation).

Comment on lines 102 to 114
// Check disabled property if it exists (S1 only)
if (this.hasAttribute('disabled') && !('disabled' in this)) {
window.__swc.warn(
this,
`<${this.localName}> element does not support the disabled state.`,
'https://opensource.adobe.com/spectrum-web-components/components/status-light/#states',
{
issues: [
'disabled is not a supported property in Spectrum 2',
],
}
);
} else if (this.hasAttribute('disabled') && 'disabled' in this) {
// Set aria-disabled when no warning is shown
if (!this.hasAttribute('aria-disabled')) {
this.setAttribute('aria-disabled', 'true');
} else {
this.removeAttribute('aria-disabled');
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can’t see the referenced commits in your comment, @marissahuysentruyt, but my initial thought (and I think this probably warrants a focused discussion around these dev warnings holistically post-barebones) is that we shouldn’t let 1st-gen, soon-to-be-removed properties leak into 2nd-gen. That way, when we phase out 1st-gen, there’s no technical debt lingering in 2nd-gen code that needs cleanup.

expect(el.getAttribute('aria-disabled')).to.equal('true');
});

describe('dev mode warnings', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine! We’ll probably want to create a dedicated test helper to remove some boilerplate from these dev warnings tests, but this looks good for now 😃

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly created the tests for Badge to have something to run the infrastructure on. I tried to keep them as simple and focused as possible, and I think these are also pretty straightforward. This seems fine as a starting point, but we’ll almost certainly revisit it post-barebones.

@marissahuysentruyt marissahuysentruyt merged commit 7898655 into barebones Oct 20, 2025
14 of 22 checks passed
@marissahuysentruyt marissahuysentruyt deleted the marissahuysentruyt/swc-1260-status-light-s2-migration branch October 20, 2025 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2nd gen These issues or PRs map to our 2nd generation work to modernizing infrastructure. Component: Status light ready-for-merge Will auto-update until merged Spectrum CSS Spectrum 2 Issues related to Spectrum 2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants