import { Meta } from "@storybook/addon-docs";
import { Table } from "@stories/components";
import { ThemeSpecificationTable } from "./ThemeSpecificationTable";
import { GithubLink } from "@stories/components";

<Meta
    title="Features/Theming"
    id="theming"
/>

# Theming

Orbit styled system is powered by the values of a *theme object* provided by the application. The Orbit theme object specification have been inspired by the [Styled System Theme Specification](https://styled-system.com/theme-specification).

## Theme object

A theme object is a combination of *design values* and *design scales* ([spacing](?path=/story/tokens--page#spacings), [sizing](?path=/story/tokens--page#sizings), [colors](?path=/story/tokens--page#text-colors), etc..).

Some scales are defined in Orbit as arrays for ordinal values like `space` or as plain objects for named values like `colors`. Some are even a mix of both, such as `fontSizes`.

An Orbit theme object is composed of the following *8 keys*:

<ThemeSpecificationTable
    rows={[
        ["space", "margin, margin-top, margin-bottom, margin-right, margin-left, padding, padding-left, padding-right, padding-bottom, gap, column-gap, row-gap", "spacing-scale"],
        ["sizing", "width, height, min-width, max-width, min-height, max-height, grid-auto-columns, grid-auto-rows", "sizing-scale"],
        ["boxShadows", "box-shadow", "box-shadow-scale"],
        ["fontSizes", "font-size", "font-sizes-scale"],
        ["colors", "color, background-color, border-color", "color-scale"],
        ["fontWeights", "font-weights", "font-weights-scale"],
        ["lineHeights", "line-heights", "line-heights-scale"],
        ["borderRadii", "border-radius", "border-radius-scale"]
    ]}
    style={{
        marginTop: "24px",
        marginBottom: "24px"
    }}
/>

### Output

When rendered with the `createThemeVars` function, the following CSS variables will be outputted from the theme object values.

<Table
    columns={[
        { title: "Theme key", headerStyle: { width: "150px" }, rowClassName: "code" },
        { title: "CSS variables", headerStyle: { width: "200px" }, rowClassName: "code"}
    ]}
    rows={[
        ["space", "--o-ui-sp-{x}"],
        ["sizing", "--o-ui-sz-{x}"],
        ["boxShadows", "--o-ui-bs-{x}"],
        ["fontSizes", "--o-ui-fs-{x}"],
        ["colors", "--o-ui-{x}"],
        ["fontWeights", "--o-ui-fw-{x}"],
        ["lineHeights", "--o-ui-lh-{x}"],
        ["borderRadii", "--o-ui-br-{x}"]
    ]}
    style={{
        marginTop: "24px",
        marginBottom: "24px"
    }}
/>

## Apply a theme

Orbit components and Orbit [style props](?path=/docs/style-props--page) doesn't render any styles until a theme is applied.

To apply a theme:

1. [Select a theme object](#select-a-theme-object)
2. Render the CSS variables of the theme object with the `createThemeVars` function
3. [Define a `<ThemeProvider>` component with the theme object](?path=/docs/theme-provider--page)

```jsx
import { createThemeVars, ThemeProvider } from "@sharegate/orbit-ui";

createThemeVars([theme]);

<ThemeProvider theme={theme} colorScheme="light">
    <Button>Launch</Button>
</ThemeProvider>
```

### Select a theme object

Any object can be used as an Orbit theme object as long as it extends the <GithubLink path="/packages/components/src/styling/src/theming/orbitTheme.ts">`OrbitTheme`</GithubLink> TypeScript type. A few options are available.

#### Option 1: Define your own theme from scratch

Make sure you provide the right definition by extending the <GithubLink path="/packages/components/src/styling/src/theming/orbitTheme.ts">`OrbitTheme`</GithubLink> type.

```jsx
import { OrbitTheme, createThemeVars, ThemeProvider } from "@sharegate/orbit-ui";

const SpaceTheme: OrbitTheme = {
    name: "space-theme",
    space: [],
    sizing: [],
    fontSizes: {}
    // ...
};

createThemeVars([theme]);

<ThemeProvider theme={theme} colorScheme="light">
    <Button>Launch</Button>
</ThemeProvider>
```

#### Option 2: Create a new theme from Orbit defaults

With `createTheme`, you only have to provide a subset of <GithubLink path="/packages/components/src/styling/src/theming/orbitTheme.ts">`OrbitTheme`</GithubLink> values. The remaining values will fallback to Orbit defaults.

```jsx
import { createTheme, createThemeVars, ThemeProvider } from "@sharegate/orbit-ui";

const SpaceTheme = createTheme({
    name: "space-theme",
    colors: {
        white: "#fff",
        black: "#000",
        accent: [
            "hsla(174, 61%, 94%, 1)",
            "hsla(173, 63%, 85%, 1)",
            "hsla(173, 63%, 75%, 1)",
            "hsla(173, 64%, 65%, 1)",
            "hsla(173, 64%, 50%, 1)",
            "hsla(172, 65%, 48%, 1)",
            "hsla(173, 65%, 46%, 1)",
            "hsla(172, 63%, 45%, 1)",
            "hsla(172, 64%, 43%, 1)",
            "hsla(172, 62%, 41%, 1)"
        ]
        // ...
    },
    // ...
});

createThemeVars([theme]);

<ThemeProvider theme={theme} colorScheme="light">
    <Button>Launch</Button>
</ThemeProvider>
```

#### Option 3: Retrieve a pre-constructed theme from Orbit

The only theme available at the moment is <GithubLink path="/packages/components/src/styling/src/theming/sharegateTheme.ts">`ShareGateTheme`</GithubLink>.

```jsx
import { ShareGateTheme, createThemeVars, ThemeProvider } from "@sharegate/orbit-ui";

createThemeVars([ShareGateTheme]);

<ThemeProvider theme={ShareGateTheme} colorScheme="light">
    <Button>Launch</Button>
</ThemeProvider>
```

## Use a theme object in code

Theme objects are primarily used to boostrap Orbit styled system but they can also be used directly in JavaScript code when you need to fetch a value.

If you have access to the theme object, use the object directly.

```jsx
<Div padding={SpaceTheme.spacing[2]}>
    Hello world!
</Div>
```

If you don't have access to the theme object, retrieve a `ThemeAccessor` instance from the `ThemeContext` by using the `useThemeContext` hook and access the theme values from the instance.

```jsx
import { useThemeContext } from "sharegate/orbit-ui";

const { themeAccessor } = useThemeContext();

return (
   <Div padding={themeAccessor.getSizing(3)}>
       Hello world!
   </Div>
)
```
