---
# System prepended metadata

title: Converged Theme

---

# Converged Theme

styled helper:

1. rename classNamesMap to classNames
2. write hoc
3. keep in mind recipes pattern
4. tokens

## Vocabulary

**Recipe**: A function which takes a theme (and only a theme) and returns a literal. Recipes can encapsulate complex functions to calculate new colors, fonts, sizes, and other literals. They can chain.

**Token**: A component-specific literal or a recipe which equates to a component specific slot.

**Theme**: An abstract set of knobs which encapsulate the design language and other design system settings.

## Vocabulary Examples

### Recipe

Example of calculating an accessible accent:

```jsx
const accentBackground = (theme) => {
  return accessibleColor(
    theme.colors.accentPalette,  // target
    theme.colors.background, // on this background color
    1.4 // contrast target
  );
}

const accentForeground = (theme) => {
  return accessibleColor(
    theme.colors.textPalette, // target
    accentBackground(theme), // on the accessible background,
    1.4 // constrast target
  )
}



// Font and Space Recipes (and the logic behind them)

const fontSize = (steps) => {
  const {fontSizeBase, fontSizeScale, fontUnit} = theme.fonts; // 1em, 1.2, em
  return baseSize * Math.pow(baseScale, steps) + unit;
}

const theme = { //partial
  fontSizes: {
    sm: fontSize(-1)
  }
}

const fontSizeSm(theme) => {
  return theme.fontSizes.sm;
}
```



### Tokens

A set of flat variables default values. Tokens are `names` that map to a string literal, or a function of `theme` to literal:

Example:

```jsx
{
  tokens: {
    thumbBackground: 'red',
    background: theme => theme.colors.accentBackground
  }
}
```

#### Token Questions/Thoughts

- Should margin/padding/flex be provided inline? (style={{}})
- For 1offs... yes?
- Or, define a css class and use that (className)
- But NOT tokens

### Theme

```jsx
// Theme can contain component tokens as well as colors/typography etc
const theme = {
  // not set on globals name
  globals: {
    typgraphy: {},
    spacing: {},
    colors: {},
    effects: {},
  },
  components: {
    Slider: {
      tokens: {
        thumbBackground: theme => literal
      }
    }
  }
}
```



## Project plan

We plan to have 2 utilities which separate concerns:

In a new package `@uifabric/merge-styles-react`:

### Styled Function


```jsx
 styled(Component)({styles, tokens})
```

#### `styleOptions.tokens`

```jsx
const tokens = (theme) => {
  tokens: {
    thumbBackground: 'red',
    background: theme => theme.colors.accentBackground
  }
}
```

#### `styleOptions.styles`

```jsx
const styles = ({theme, tokens}) => {
  return {
    root: {
      background: theme.background
    },
    label: {IStyle}
  }
}

```
#### Styled Function Definition
 
```jsx
const styled = Component => ({ styles, tokens }) => {
  return p => {
    const theme = useTheme();
    const classNames = resolveClassNames(theme, styles, tokens);
    return <Component {...p} classNames={classNames} />;
  }
}
```

#### Styled Function Examples

Creating a styled Button off of unstyled BaseButton

```jsx
const buttonStyles = ({theme, tokens}) => {
  root: {
    background: tokens.background || accentBackground(theme)
    fontSize: tokens.fontSize || fontSize(2); // root * scale^2
    padding: size(1); // root * scale^1
  } 
}

const Button = styled(BaseButton)({ buttonStyles, tokens });

```

Creating a variant of an existing styled control

```jsx

const FancyButtonTokens = (theme) => {
  return {
    background: theme.background
  }
}

const FancyButton = styled(Button)

```
 

#### Static CSS Example

 If you just want to simply pass classNames to a component, you don't need styled

```jsx
const SimpleComp = p => Component({...p, classNames: styles });
```


#### A Composite Control 


```jsx
const dialogStyles = ({theme, tokens}) => {
  root: {
    background: tokens.background || 
    fontSize: tokens.fontSize || fontSize(2); // root * scale^2
    padding: size(1); // root * scale^1
  }
    
}

const Dialog = styled(BaseDialog)({ dialogStyles, tokens });

const Button = styled(BaseButton({ styles, tokens });

// Composed allows you to combine two styled controls together
const FancyDialog = composed(Dialog: { slots: { button: Button } });
```

## Compose Function

The `styled` function is an opionated helper that takes an unstyled components and passes in classNames to the control via a function called in the context of the theme.


> Need Example

```jsx
DialogBase = composed({
  slots: {
    okButton: 'button',
    cancelButton: 'button'
  }
});

  <Dialog>

    <Dialog.Thing>

      <Button/>

    </Dialog.Thing>

  </Dialog>

composed(CommandBar, {
  slots: {
    item: CommandBarItem
  }
});

```

```jsx
const SliderWithSlotOpinions = composed(SliderBase, { slots: {
  slots: {
    thumb: 'div',
    cancelButton: StyledButton
  }
}});

 

1. extend html attributes
2. tokens inline

 

const SliderStyles: ISliderTokens = {
  root: {
    background: accentBackground,
    backgroundSelected: accent2Background,
    'complex selector': {
      ...
    }
  }
}

```

 
 
### ResolveClassNames
 
```jsx

const resolveClassNames = (theme, styles, tokens) => {

  const classNames = lookup(theme, styles, tokens);
  if (!classNames) {
  const resolvedTokens = resolve(tokens, theme);
    const resolvedStyles =
  }
  return classNames;

}
```
 
```jsx
const resolve = (obj, ...args) = {
  const newObj = {};
  for (let name in obj) {
    newObj[name] = (typeof obj[name] ==='function') ? obj[name].apply(this, args) : obj[name];
  }
  return newObj;
}

```
