Skip to content

Commit

Permalink
docs: iterate on recipes section
Browse files Browse the repository at this point in the history
  • Loading branch information
nmn committed Dec 22, 2024
1 parent 9aea4b4 commit 125dc90
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sidebar_position: 6
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Conditional styles based on context
# Context-driven styles

StyleX lets you apply styles conditionally. Any condition can be used to do so, `Props`, `State` or `Context`.

Expand All @@ -35,7 +35,9 @@ import * as stylex from '@stylexjs/stylex';

export default createContext(false);
```

## Building the sidebar component

The `Sidebar` component uses the `SidebarContext` to determine its open or closed state
and conditionally applies the appropriate styles.

Expand Down Expand Up @@ -80,7 +82,7 @@ export default function App() {

return (
<SidebarContext.Provider value={isSidebarOpen}>
<button onClick={() => setIsSidebarOpen(!isSidebarOpen)}>
<button onClick={() => setIsSidebarOpen(open => !open)}>
Toggle Sidebar
</button>
<Sidebar>
Expand Down
201 changes: 193 additions & 8 deletions apps/docs/docs/learn/06-recipes/02-variants.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ import TabItem from '@theme/TabItem';

# Variants

The "variants" pattern allows you to conditionally apply one of several predefined styles based on a value. This is especially useful for theming or dynamic component behavior.
The "variants" pattern allows you to conditionally apply one of several predefined styles based on a value.
This is especially useful for theming or dynamic component behavior.

### Example: Button Variants
It is common to have different styles for different "variants" of a component. Some other styling solutions provide
an explicit API for defining variants. In StyleX, you can define variants with a simple pattern instead.

Here’s how you can create a button component with different visual styles based on a `variant` prop:
## Example: Button Variants

Here’s how you can create a button component with different visual styles based on `variant` props:

```tsx
import * as stylex from '@stylexjs/stylex';
Expand All @@ -26,7 +30,150 @@ const styles = stylex.create({
borderWidth: 0,
},
});
const variants = stylex.create({
const colorVariants = stylex.create({
primary: {
backgroundColor: {
default: 'blue',
':hover': 'darkblue',
},
color: 'white',
},
secondary: {
backgroundColor: {
default: 'gray',
':hover': 'darkgray',
},
color: 'white',
},
});
const sizeVariants = stylex.create({
small: {
fontSize: '1rem',
paddingBlock: 4,
paddingInline: 8
},
medium: {
fontSize: '1.2rem',
paddingBlock: 8,
paddingInline: 16
},
});

type Props = {
color: keyof typeof colorVariants,
size: keyof typeof sizeVariants,
...
};

function Button({
color = 'primary',
size = 'small',
...props
}: Props) {
return (
<button
{...props}
{...stylex.props(
styles.base,
colorVariants[color],
sizeVariants[size],
props.style
)}
/
>);
}

// Usage
<Button color="primary" size="medium">Primary</Button>
<Button color="secondary">Secondary</Button>
```
## Compound Variants

Sometimes variants are dependent on a combination of variants props.

In most cases, it's simpler to leverage StyleX’s deterministic style merging to simplify this
behaviour.

### Example: A `disabled` prop

```tsx
import * as stylex from '@stylexjs/stylex';

const styles = stylex.create({
base: {...},
disabled: {
backgroundColor: 'grey',
color: 'rgb(204, 204, 204)',
cursor: 'not-allowed',
},
});
const colorVariants = stylex.create({
primary: {
backgroundColor: {
default: 'blue',
':hover': 'darkblue',
},
color: 'white',
},
secondary: {
backgroundColor: {
default: 'gray',
':hover': 'darkgray',
},
color: 'white',
},
});
const sizeVariants = stylex.create({...});

type Props = {
color?: keyof typeof colorVariants,
size?: keyof typeof sizeVariants,
disabled?: boolean,
...
};

function Button({
color = 'primary',
size = 'small',
disabled = false,
...props,
}: Props) {
return (
<button
{...props}
{...stylex.props(
styles.base,
colorVariants[color],
sizeVariants[size],
disabled && styles.disabled,
disabled && {
backgroundColor: 'grey',
color: 'rgb(204, 204, 204)',
cursor: 'not-allowed',
props.style
)}
/>
);
}

// Usage
<Button color="primary" size="medium">Primary</Button>
<Button color="secondary">Secondary</Button>
```
There may be other scenarios where you need to be more explicit about the styles
that should applied under various condition. You can do this by declaring multiple
style definitions for a particular variant.
### Example: Two definitions for `color` variant styles
```tsx
import * as stylex from '@stylexjs/stylex';

const styles = stylex.create({
base: {...},
});
const colorVariantsEnabled = stylex.create({
primary: {
backgroundColor: {
default: 'blue',
Expand All @@ -42,11 +189,49 @@ const variants = stylex.create({
color: 'white',
},
});
function Button({ variant = 'primary', ...props }) {
return <button {...props} {...stylex.props(styles.base, variants[variant], props.style)} />;
const colorVariantsDisabled = stylex.create({
primary: {
backgroundColor: 'blue',
color: 'white',
},
secondary: {
backgroundColor: 'gray',
color: 'white',
},
});
const sizeVariants = stylex.create({...});

type Props = {
color?: keyof typeof colorVariants,
size?: keyof typeof sizeVariants,
disabled?: boolean,
...
};

function Button({
color = 'primary',
size = 'small',
disabled = false,
...props,
}: Props) {
const colorVariants = disabled
? colorVariantsDisabled
: colorVariantsEnabled;

return (
<button
{...props}
{...stylex.props(
styles.base,
colorVariants[color],
sizeVariants[size],
props.style
)}
/>
);
}

// Usage
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button color="primary" size="medium">Primary</Button>
<Button color="secondary">Secondary</Button>
```
14 changes: 13 additions & 1 deletion apps/docs/docs/learn/06-recipes/03-descendant styles.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ sidebar_position: 7
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Descendant styles dependent on ancestor state
# Variables for descendant styles

It is not uncommon to define styles on an element that are dependent on a parent element's state,
such as applying some styles conditionally when the parent element is hovered.

StyleX doesn't allow arbitrary selectors or "styling at a distance". However, variables can be
used to achieve the same results in a safe and composable way.

## Example: Sidebar

Expand All @@ -19,6 +25,7 @@ when the sidebar as whole is hovered.
Using CSS variables, you can style descendants based on a parent's state, such as `:hover`.

### Step 1

Define one or more variables using `stylex.defineVars`:

```tsx variables.stylex.ts
Expand All @@ -31,6 +38,7 @@ export const vars = stylex.defineVars({
```

### Step 2

Define conditional styles setting the value for the variable in the ancestor component.

```tsx
Expand All @@ -56,6 +64,7 @@ function ParentWithHover({children}) {
```

### Step 3

Use the variable to style the child component

```tsx
Expand All @@ -74,3 +83,6 @@ function ParentWithHover() {
);
}
```

This pattern makes it explicit what styles are being defined on an ancestor element, while leaving
the child element in control to use those styles explicitly and to override it as needed.

0 comments on commit 125dc90

Please sign in to comment.