Skip to content

Commit 775d645

Browse files
authored
chore(docs): create migration guide for Spectrum CSS to barebones [SWC-1247] (#5772)
1 parent 80814bc commit 775d645

File tree

8 files changed

+293
-6
lines changed

8 files changed

+293
-6
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Adobe Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as
6+
contributors and maintainers pledge to make participation in our project and
7+
our community a harassment-free experience for everyone, regardless of age, body
8+
size, disability, ethnicity, gender identity and expression, level of experience,
9+
nationality, personal appearance, race, religion, or sexual identity and
10+
orientation.
11+
12+
## Our Standards
13+
14+
Examples of behavior that contributes to creating a positive environment
15+
include:
16+
17+
- Using welcoming and inclusive language
18+
- Being respectful of differing viewpoints and experiences
19+
- Gracefully accepting constructive criticism
20+
- Focusing on what is best for the community
21+
- Showing empathy towards other community members
22+
23+
Examples of unacceptable behavior by participants include:
24+
25+
- The use of sexualized language or imagery and unwelcome sexual attention or
26+
advances
27+
- Trolling, insulting/derogatory comments, and personal or political attacks
28+
- Public or private harassment
29+
- Publishing others' private information, such as a physical or electronic
30+
address, without explicit permission
31+
- Other conduct which could reasonably be considered inappropriate in a
32+
professional setting
33+
34+
## Our Responsibilities
35+
36+
Project maintainers are responsible for clarifying the standards of acceptable
37+
behavior and are expected to take appropriate and fair corrective action in
38+
response to any instances of unacceptable behavior.
39+
40+
Project maintainers have the right and responsibility to remove, edit, or
41+
reject comments, commits, code, wiki edits, issues, and other contributions
42+
that are not aligned to this Code of Conduct, or to ban temporarily or
43+
permanently any contributor for other behaviors that they deem inappropriate,
44+
threatening, offensive, or harmful.
45+
46+
## Scope
47+
48+
This Code of Conduct applies both within project spaces and in public spaces
49+
when an individual is representing the project or its community. Examples of
50+
representing a project or community include using an official project e-mail
51+
address, posting via an official social media account, or acting as an appointed
52+
representative at an online or offline event. Representation of a project may be
53+
further defined and clarified by project maintainers.
54+
55+
## Enforcement
56+
57+
Instances of abusive, harassing, or otherwise, unacceptable behavior may be
58+
reported by contacting the project team at Grp-opensourceoffice@adobe.com. All
59+
complaints will be reviewed and investigated and will result in a response that
60+
is deemed necessary and appropriate to the circumstances. The project team is
61+
obligated to maintain confidentiality concerning the reporter of an incident.
62+
Further details of specific enforcement policies may be posted separately.
63+
64+
Project maintainers who do not follow or enforce the Code of Conduct in good
65+
faith may face temporary or permanent repercussions as determined by other
66+
members of the project's leadership.
67+
68+
## Attribution
69+
70+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71+
available at [http://contributor-covenant.org/version/1/4][version]
72+
73+
[homepage]: http://contributor-covenant.org
74+
[version]: http://contributor-covenant.org/version/1/4/
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
# Migration guide
2+
3+
When migrating a component from the 1st generation to the 2nd generation, there are a few things to keep in mind.
4+
5+
## Component structure
6+
7+
Components in 1st and 2nd generation share a common base class. These base classes are located in the `second-gen/packages/core/components/` directory.
8+
9+
- 1st generation components are located in the `first-gen/packages/components/` directory.
10+
- 2nd generation components are located in the `second-gen/packages/swc/components/` directory.
11+
12+
Keep in mind that all the code in the core package is shared between the 1st and 2nd generation components and should avoid any breaking changes being introduced here that could alter the 1st generation API.
13+
14+
Relevant files in the 1st generation components:
15+
16+
- `src/<component-name>-overrides.css` - Theme switching system; do not delete this file, even if it is empty
17+
- `src/<component-name>.css` - Component styles; this file is used to import the styles from the Spectrum CSS project and the component styles and adds web component-specific styles
18+
- `src/spectrum-<component-name>.css` - Styles imported and transformed by the build process from the Spectrum CSS project
19+
- `src/<component-name>.ts` - Component implementation; this contains the attributes and properties for the component as well as the rendering logic
20+
- `stories/` - Stories
21+
- `test/` - Tests
22+
- `README.md` - Component documentation
23+
24+
Relevant files in the 2nd generation components:
25+
26+
- `<component-name>.css` - Component styles; all styles should be added to this file
27+
- `<component-name>.ts` - Component implementation; this contains the attributes and properties for the component as well as the rendering logic
28+
- `stories/` - Stories will also serve as the documentation for the component; the story file should be named `<component-name>.stories.ts`. Use JSDoc to document a story in more detail.
29+
- `test/` - Tests
30+
31+
## Getting started
32+
33+
### Create the base class
34+
35+
If the component folder does not yet exist in the core package, you will need to create it. It might be easiest to copy the existing component file from the 1st generation component and remove the render and styling logic as well as anything that is S1-specific.
36+
37+
For example, if you are migrating the `sp-accordion` component, you can copy the `first-gen/packages/accordion/src/Accordion.ts` to `second-gen/packages/core/components/accordion/Accordion.base.ts` and remove the render and styling logic as well as anything that is S1-specific.
38+
39+
### Implement the component class
40+
41+
Once the base class is created, you can start to implement the component in the `second-gen/packages/swc/components/` directory. The implementation file should be named `<component-name>.ts` and should extend the base class.
42+
43+
```ts
44+
import { AccordionBase } from '@swc/core/components/accordion';
45+
46+
export class Accordion extends AccordionBase {
47+
// ...
48+
}
49+
```
50+
51+
### Bring over styles from Spectrum CSS
52+
53+
Now we can bring over styles from the `spectrum-two` package in Spectrum CSS. Start by checking out the `@adobe/spectrum-css` repository and pulling down the `spectrum-two` branch.
54+
55+
Identify the component you need to migrate by searching the `components` directory for the component name.
56+
57+
Inside the CSS directory, you can expect to find the following files:
58+
59+
- `index.css` - This is the source of truth for the component Styles
60+
- `dist/index.css` - This is the processed version of the component styles; for now, this is the best place to source styles for SWC. When copying files from Spectrum CSS into the 2nd-generation component, using this file will ensure you get the benefits of the CSS build tooling.
61+
- `stories/<component-name>.stories.js` - This is a great source-of-truth for the SWC storybook. These stories are organized into logic groups with API defined in a customer-friendly fashion with typing and human-readable labels. These files also include migration notes and guidance specific to the S2-specific implementation of the component.
62+
- `stories/template.js` - This is a great source-of-truth for the SWC render function; these templates already include property and class mappings. When bringing this file over to SWC, be sure to remove the `id` and `customStyles` attributes as they do not translate to the web component APIs.
63+
64+
Next, we need to copy the styles from the Spectrum CSS component to the 2nd-generation component.
65+
66+
```bash
67+
cp -r spectrum-css/components/<component-name>/dist/index.css spectrum-web-components/second-gen/packages/swc/components/<component-name>/<component-name>.css
68+
```
69+
70+
### Update styles in the 2nd-generation component
71+
72+
Now that we have the base styles in place, we need to check the first-gen implementation for any unique web component-specific styles that would not exist in the vanilla CSS implementation. This information will most likely be found in the `first-gen/packages/components/<component-name>/<component-name>.css` file.
73+
74+
For example, look for styles specific to slots, such as `::slotted([name="icon"]) {}`.
75+
76+
If these styles are found, we need to confirm if they are needed in the 2nd-generation component. Not all first-gen overrides or component-specific styles are needed in the 2nd-generation components and sometimes there are other ways to source those styles using the original classes provided by the Spectrum CSS asset.
77+
78+
It might be helpful, at this point, to define the render function for the second-gen component so you can spin up Storybook and start seeing these new styles in action. A quick way to kick this off is to copy the `spectrum-css/components/<component-name>/stories/template.js` file into a render function on your new 2nd-generation component.
79+
80+
Let's use the `Badge` component as an example. First, we need to add the styles to the component.
81+
82+
Start by importing the CSS file:
83+
84+
```ts
85+
import styles from './badge.css';
86+
```
87+
88+
Next, we import those styles into the component:
89+
90+
```ts
91+
public static override get styles(): CSSResultArray {
92+
return [styles];
93+
}
94+
```
95+
96+
Finally, we can start to implement the render function:
97+
98+
```ts
99+
protected override render(): TemplateResult {
100+
return html`
101+
<div
102+
class=${classMap({
103+
['spectrum-Badge']: true,
104+
[`spectrum-Badge--size${this.size?.toUpperCase()}`]: typeof this.size !== 'undefined',
105+
[`spectrum-Badge--${this.variant}`]: typeof this.variant !== 'undefined',
106+
[`spectrum-Badge--subtle`]: this.subtle,
107+
[`spectrum-Badge--outline`]: this.outline,
108+
[`spectrum-Badge--fixed-${this.fixed}`]: typeof this.fixed !== 'undefined',
109+
})}
110+
>
111+
${when(
112+
this.hasIcon,
113+
() => html`
114+
<div
115+
class=${classMap({
116+
[`spectrum-Badge-icon`]: true,
117+
[`spectrum-Badge-icon--no-label`]:
118+
!this.slotHasContent,
119+
})}
120+
>
121+
<slot name="icon"></slot>
122+
</div>
123+
`
124+
)}
125+
<div class="spectrum-Badge-label">
126+
<slot></slot>
127+
</div>
128+
</div>
129+
`;
130+
}
131+
```
132+
133+
Let's compare this to the 1st-generation implementation:
134+
135+
```ts
136+
protected override render(): TemplateResult {
137+
return html`
138+
${this.hasIcon
139+
? html`
140+
<slot
141+
name="icon"
142+
?icon-only=${!this.slotHasContent}
143+
></slot>
144+
`
145+
: nothing}
146+
<div class="label">
147+
<slot></slot>
148+
</div>
149+
`;
150+
}
151+
```
152+
153+
As you can see, the 2nd-generation implementation leverages the `classMap` function to conditionally apply classes to the component based on the component's properties. This is a common pattern in the 2nd-generation components. This approach has several benefits:
154+
155+
- It separates the styling application from the properties and states of the component
156+
- It creates a container inside the Shadow DOM which provides stronger encapsulation
157+
- It allows for more efficient rendering by only applying the necessary classes to the component
158+
159+
In our 2nd-generation version, we will likely want to maintain any slots available in the 1st-generation component unless design changes from S2 provide a compelling reason to change or remove them.
160+
161+
Once your render function is in place, you can spin up Storybook and start seeing these new styles in action.
162+
163+
```bash
164+
yarn workspace @swc/components storybook
165+
```
166+
167+
_Note_: Run all commands provided in this guide from the root of the Spectrum Web Components monorepo.
168+
169+
_Tip_: If you want to run S1 Storybook alongside S2 Storybook, you can use the following command:
170+
171+
```bash
172+
yarn start
173+
```
174+
175+
## Implementing the API
176+
177+
Now that we have the base styles and render function in place, we can start to adjust styling and API to match the 2nd-generation design language.
178+
179+
Start by determining what display property your component's host should use. All components should have at least the following style added to the top of their 2nd-generation CSS.
180+
181+
```css
182+
:host {
183+
display: inline-flex;
184+
}
185+
```
186+
187+
Use the `display` property most aligned with the component's semantic role or purpose in the document.
188+
189+
### Properties
190+
191+
The 2nd-generation components may have changes to the properties and attributes of the component. These changes are typically due to design changes from S2 or to align with the 2nd-generation design language.
192+
193+
There are several resources you can use to help you understand the design changes from S2.
194+
195+
- [Migration roadmap](https://github.com/adobe/spectrum-web-components/tree/2nd-gen-component-analysis/migration-roadmap) - SWC branch name: `2nd-gen-component-analysis`
196+
- [S2 design assets](https://www.figma.com/design/Mngz9H7WZLbrCvGQf3GnsY/S2---Desktop?m=auto) - Figma file
197+
198+
You can also use the `CHANGELOG.md` file in the Spectrum CSS repository to see the migration notes for the component.
199+
200+
```bash
201+
cat spectrum-css/components/<component-name>/CHANGELOG.md
202+
```

second-gen/packages/swc/.storybook/main.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@ import { resolve } from 'path';
22

33
/** @type { import('@storybook/web-components-vite').StorybookConfig } */
44
const config = {
5-
stories: ['../components/**/*.stories.@(js|ts|md|mdx)'],
5+
stories: [
6+
{
7+
directory: 'guides',
8+
files: '*.@(md|mdx)',
9+
titlePrefix: 'Guides',
10+
},
11+
{
12+
directory: '../components',
13+
files: '*/stories/*.stories.ts',
14+
titlePrefix: 'Components',
15+
},
16+
],
617
framework: '@storybook/web-components-vite',
718
core: {
819
disableTelemetry: true,

second-gen/packages/swc/components/asset/stories/asset.stories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type { Meta, StoryObj } from '@storybook/web-components';
1616
import '@swc/components/asset';
1717

1818
const meta: Meta = {
19-
title: 'Components/Asset',
19+
title: 'Asset',
2020
component: 'swc-asset',
2121
argTypes: {
2222
variant: {

second-gen/packages/swc/components/badge/stories/badge.stories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ args['default-slot'] = 'Badge';
5656
* Because outline and subtle fill styles draw a similar level of attention, choose only one to use consistently within a single product. Bold fill can be paired with either style, and is reserved for high-attention badging only.
5757
*/
5858
const meta: Meta = {
59-
title: 'Components/Badge',
59+
title: 'Badge',
6060
component: 'swc-badge',
6161
args,
6262
argTypes,

second-gen/packages/swc/components/divider/stories/divider.stories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type { Meta, StoryObj } from '@storybook/web-components';
1616
import '@swc/components/divider';
1717

1818
const meta: Meta = {
19-
title: 'Components/Divider',
19+
title: 'Divider',
2020
component: 'swc-divider',
2121
};
2222

second-gen/packages/swc/components/progress-circle/stories/progress-circle.stories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ argTypes['static-color'] = {
5656
* Can be used in both determinate (with specific progress value) and indeterminate (loading) states.
5757
*/
5858
const meta: Meta = {
59-
title: 'Components/Progress Circle',
59+
title: 'Progress circle',
6060
component: 'swc-progress-circle',
6161
args,
6262
argTypes,

second-gen/packages/swc/components/status-light/stories/status-light.stories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import '@swc/components/status-light';
1515

1616
export default {
1717
component: 'swc-status-light',
18-
title: 'Components/StatusLight',
18+
title: 'Status light',
1919
};
2020

2121
export const s = (): TemplateResult => html`

0 commit comments

Comments
 (0)