Skip to content

Commit 0e75738

Browse files
committed
chore(docs): 2nd gen CSS migration [SWC-1247]
1 parent 7084912 commit 0e75738

File tree

8 files changed

+301
-6
lines changed

8 files changed

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

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
@@ -52,7 +52,7 @@ const CONTAINER = (content: TemplateResult<1>[]) =>
5252
* 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.
5353
*/
5454
const meta: Meta = {
55-
title: 'Components/Badge',
55+
title: 'Badge',
5656
component: 'swc-badge',
5757
argTypes: {
5858
size: {

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
@@ -17,7 +17,7 @@ import type { Meta, StoryObj } from '@storybook/web-components';
1717
import '@swc/components/progress-circle';
1818

1919
const meta: Meta = {
20-
title: 'Components/Progress Circle',
20+
title: 'Progress Circle',
2121
component: 'swc-progress-circle',
2222
argTypes: {
2323
indeterminate: {

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: 'StatusLight',
1919
};
2020

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

0 commit comments

Comments
 (0)