Skip to content

Commit

Permalink
Docs: Add abstruct styles and componentization
Browse files Browse the repository at this point in the history
  • Loading branch information
1aron committed Jun 1, 2024
1 parent 883e37a commit 0bf2977
Showing 1 changed file with 115 additions and 41 deletions.
156 changes: 115 additions & 41 deletions website/app/[locale]/guide/reusing-styles/content.mdx
Original file line number Diff line number Diff line change
@@ -1,29 +1,45 @@
import { buttonSizes } from '~/styles/btn'

## Foreword [sr-only]
As the styles grow, you will notice similar class name combinations and the same design patterns repeatedly appearing in your code. To improve development efficiency and maintain design consistency, you will need to reuse or access them in some way.
## Motivation [sr-only]
As the styles grow, the class name combinations and the same design patterns appear over and over again in the code. To improve development efficiency and maintain design consistency, you should reuse or access them in some way.

In addition to offering some general methods, this guide also provides specialized solutions tailored for frameworks.

The UI is gradually composed of 1 to 4:

1. [Variables](/reference/variables) / [Animations](/reference/animations) / [Functions](/reference/functions) / [Selectors](/reference/selectors) / [At](/reference/at) / [Utilities](/reference/utilities)
1. [Rules](/reference/styles)
1. [Styles](/reference/styles)
1. [Components](#componentization)
This guide also provides specialized solutions tailored for frameworks.

---

## Abstract styles
Traditionally, we define styles like `.btn` or `.card` by writing CSS rules. In Master CSS, we abstract them using [styles](/reference/styles), which is similar to [Figma's Styles](https://help.figma.com/hc/en-us/articles/360039238753-Styles-in-Figma).

To design a scalable style, you should ensure the single responsibility of class composition; otherwise, you may end up using a lot of `!important` to override rules or the `@preset` layer to lower default styles, ultimately leading to chaotic styles.
The UI is composed of 1 to 4:

1. [Variables](/reference/variables) / [Animations](/reference/animations) / [Functions](/reference/functions) / [Selectors](/reference/selectors) / [At](/reference/at) / [Utilities](/reference/utilities)
1. [Rules](/reference/styles)
1. [Styles](/reference/styles)
1. [Components](#componentization)

### Create button styles
Let's implement a rich button as an example.
As usual, you can split the styles into multiple files for management. When the project is small in scale, you don't necessarily have to insist on splitting style files.
```treeview
🗂️ styles
|-- 📄 btn.ts
`-- 📄 card.ts
📄 master.css.ts
```
Let's implement a rich button.
<Code lang="ts" name="styles/btn.ts">
{require('!!raw-loader!~/styles/btn').default}
</Code>
[Extend](/reference/configuration#extends) them uniformly in the __master.css.ts__ entry file.
```js name=master.css.js
import type { Config } from '@master/css'

export default {
extends: [
require('./styles/btn')
]
} as Config
```

To apply the button sizes.
<Demo className="gap:8x">
<button className="btn btn-xs yellow touch-yellow">Submit</button>
Expand All @@ -41,11 +57,11 @@ To apply the button sizes.
```
To apply the button sizes that are finely tuned for rounded styles.
<Demo className="gap:8x">
<button className="btn btn-xs rounded yellow touch-yellow">Submit</button>
<button className="btn btn-sm rounded yellow touch-yellow">Submit</button>
<button className="btn btn-md rounded yellow touch-yellow">Submit</button>
<button className="btn btn-lg rounded yellow touch-yellow">Submit</button>
<button className="btn btn-xl rounded yellow touch-yellow">Submit</button>
<button className="btn btn-xs rounded! yellow touch-yellow">Submit</button>
<button className="btn btn-sm rounded! yellow touch-yellow">Submit</button>
<button className="btn btn-md rounded! yellow touch-yellow">Submit</button>
<button className="btn btn-lg rounded! yellow touch-yellow">Submit</button>
<button className="btn btn-xl rounded! yellow touch-yellow">Submit</button>
</Demo>
```html
<button class="btn btn-xs **rounded** …">Submit</button>
Expand All @@ -54,6 +70,7 @@ To apply the button sizes that are finely tuned for rounded styles.
<button class="btn btn-lg **rounded** …">Submit</button>
<button class="btn btn-xl **rounded** …">Submit</button>
```
To design a scalable style, you should ensure the single responsibility of class composition; otherwise, you may end up using a lot of `!important` to override rules or the `@preset` layer to lower default styles, ultimately leading to chaotic styles.

### Create common variables and styles
We pre-use [variables and modes](/guide/variables-and-modes) to create tokens supporting light/dark modes. This not only simplifies template markup but also reduces CSS rule output.
Expand All @@ -64,6 +81,9 @@ We pre-use [variables and modes](/guide/variables-and-modes) to create tokens su
- `yellow-ring` is an outline color that complements a yellow background.
- `touch-yellow` is a background color on hover.
- `text-yellow-contrast` is a contrasting color fine-tuned against a yellow background.
- Styles
- `.yellow` sets a background, foreground and outline style for a yellow theme.
- `.yellow-touch` sets a background, foreground and outline style for a yellow theme interaction.

<Demo className="gap:8x">
<button className="btn btn-md yellow touch-yellow">Submit</button>
Expand All @@ -72,37 +92,91 @@ We pre-use [variables and modes](/guide/variables-and-modes) to create tokens su
<button class="btn btn-md **yellow** **touch-yellow**">Submit</button>
```

---

## Componentization
In addition to [styles](#abstract-styles), we provide a CSS-in-JS style utility, [Master Styled](https://github.com/master-co/styled), to help you create a component with classes in one line. It supports Vanilla js, React, and Vue.

### Manage style files
As usual, you can split the styles into multiple files for management.
```treeview
🗂️ styles
|-- 📄 btn.ts
`-- 📄 card.ts
🗂️ components
|-- 📄 Button.tsx
`-- 📄 Card.tsx
📄 master.css.ts
```
This is a standard button style file, which is exported in configuration form.
```js name=styles/btn.ts
import type { Config } from '@master/css'

export default {
styles: {
btn: ''
}
} as Config
### Create a button component
You can define type-safe styles and corresponding classes for style properties.
```tsx name=components/Button.tsx
import styled from '@master/styled.react'

const sizes = {
xs: 'font:12 h:6x …',
sm: 'font:12 h:8x …',
md: 'font:14 h:10x …',
lg: 'font:16 h:12x …',
xl: 'font:16 h:14x …'
}

declare type Props = {
$size: keyof typeof sizes
disabled?: boolean
}

const Button = styled.button<Props>('inline-flex font:semibold', {
$size: sizes,
disabled: 'opacity:.5'
})

Button.defaultProps = {
$size: 'md'
}

export default Button
```
[Extend](/reference/configuration#extends) them uniformly in the __master.css.ts__ entry file.
```js name=master.css.js
import type { Config } from '@master/css'

export default {
extends: [
require('./styles/btn')
]
} as Config
To use the button component.
```tsx
<Button $size="sm" disabled>Submit</Button>
```
Rendered as:
```html
<button class="inline-flex font:semibold font:12 h:8x … opacity:.5">Submit</button>
```
When the project is small in scale, you don't necessarily have to insist on splitting stylesheet files. Sometimes a single __master.css.ts__ configuration is sufficient.
However, if the component involves richer implementations such as `loading`, you should wrap it with a functional component.

### Create a block-scoped component
`styled` operates on an element basis, unlike global [styles](#abstract-styles) mentioned above, and you can declare it within a functional component or at the top level.

(i) Create a reusable section component specific to a marketing page.
```tsx name=page.tsx
import styled from '@master/styled.react'

export default function Page() {
const Section = styled.section`bg:slate-90 text:white p:15x|20x`
return (
<>
- <section className="bg:slate-90 text:white p:15x|20x">...</section>
+ <Section>...</Section>
- <section className="bg:slate-90 text:white p:15x|20x">...</section>
+ <Section>...</Section>
...
</>
)
}
```
This is useful for block-specific style reuse, rather than creating `styles['home-section']` which may pollute global styles or cause name collisions.

---

## Componentization
## Summary

- Moderately abstracting styles make design easier to manage and maintain consistency, but it doesn't mean that all styles should be abstracted.
- Only abstract styles that have the potential for reuse, rather than naming them simply for brevity or naming's sake.
- A good CSS structure combines abstract classes and utility classes — don’t get hung up on specific approaches.








0 comments on commit 0bf2977

Please sign in to comment.