> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lodemc.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing style

> Top-level, class, object or function; React class components

The SDK does not impose a style. The start file can register at the top level, or export something the app starts for you, and UI can be function or class components.

## The start file

All four of these are equally supported.

<Tabs>
  <Tab title="Top level">
    ```ts theme={null}
    import sdk from 'sdk'
    import Home from './pages/Home'

    sdk.pages.register('home', Home)
    sdk.sidebar.add({ id: 'home', page: 'home' })

    export function onUnload() {
      // optional
    }
    ```
  </Tab>

  <Tab title="A class">
    ```ts theme={null}
    import { Expansion } from 'sdk'
    import Home from './pages/Home'

    export default class MyExpansion extends Expansion {
      async onLoad() {
        this.opened = 0
        this.sdk.pages.register('home', Home)
        this.sdk.events.on('item:open', () => this.opened++)
      }

      onUnload() {
        this.sdk.log.info(`${this.opened} item(s) were opened`)
      }
    }
    ```

    Extending `Expansion` is optional: the app calls `new` on whatever class you export and passes the sdk to the constructor, so this works too:

    ```js theme={null}
    export default class {
      constructor(sdk) { this.sdk = sdk }
      onLoad() { this.sdk.pages.register('home', Home) }
    }
    ```
  </Tab>

  <Tab title="An object">
    ```ts theme={null}
    import sdk from 'sdk'

    export default {
      onLoad() { sdk.pages.register('home', Home) },
      onUnload() {}
    }
    ```
  </Tab>

  <Tab title="A function">
    ```ts theme={null}
    export default (sdk) => {
      sdk.pages.register('home', Home)
      return { onUnload() {} } // optional
    }
    ```
  </Tab>
</Tabs>

### Rules that apply to all of them

* `onLoad` may be async. The expansion counts as started once it resolves.
* If the start file or `onLoad` throws, everything already registered is removed, so nothing is left half-installed. The error and its location show on the Expansions page.
* `onUnload` on an instance takes priority over an exported `onUnload`.
* You rarely need `onUnload`: everything registered through `sdk` is removed automatically. Use it for things the SDK does not know about, such as flushing your own buffer.

## Components

<CodeGroup>
  ```tsx Function component theme={null}
  import { useProjectState, PrimaryButton } from 'sdk/ui'

  export default function Home() {
    const [count, setCount] = useProjectState('count', 0)
    return <PrimaryButton onClick={() => setCount(count + 1)}>{count}</PrimaryButton>
  }
  ```

  ```jsx Class component theme={null}
  import { Component } from 'react'
  import { PrimaryButton } from 'sdk/ui'

  export default class Home extends Component {
    state = { count: 0 }

    render() {
      return (
        <PrimaryButton onClick={() => this.setState(({ count }) => ({ count: count + 1 }))}>
          {this.state.count}
        </PrimaryButton>
      )
    }
  }
  ```
</CodeGroup>

Both work anywhere a component is accepted: pages, editors, creators, injections and item-editor modules. As in React generally, hooks such as `useProjectState` only work inside function components; a class component keeps its own state, or reads and writes through `sdk`.

## JavaScript or TypeScript

Both are first class, and you can mix them in one expansion. TypeScript gets you autocomplete and type checking in the editor; at load the types are stripped without being checked, so a type error never stops your expansion from running.
