# Layout Management

Layouts in Vellum determine how content is displayed within the application’s shadow DOM. Vellum provides a minimal, flexible foundation for layout management: it renders content using a configurable renderer and offers a single built-in action, `'layout:get-active'`, to retrieve the current content. Beyond this, layout management—such as registering layouts, pushing new content, or organizing structure—is left to the consuming project’s mods. This document explains Vellum’s core layout capabilities and how consumers can extend them.

For dispatching actions like `'layout:get-active'`, see [Toolkit API](./toolkit.md). For more on the action system, check out [Action System](./actions.md).

---

## Introduction to Layouts

In Vellum, a "layout" is simply the content rendered into its shadow DOM at any given time. Vellum doesn’t impose a predefined structure or management system for layouts. Instead, it:
- Renders content provided by mods.
- Updates that content when instructed via actions.
- Delegates the logic of what content to display to the consuming application.

This lightweight approach makes Vellum adaptable to any layout strategy a project chooses to implement.

---

## Default Rendering

Vellum renders content into its shadow DOM using a renderer function, defaulting to `defaultRenderer` from `src/utils/rendering.mjs`. This function:
- Clears the shadow root of existing content.
- Handles:
  - **Strings**: Sets `innerHTML`.
  - **DOM Nodes**: Appends directly.
  - **Other Types**: Displays `<div>Invalid content</div>`.

### How It Works
Vellum’s `update` method triggers rendering by:
1. Dispatching `'layout:get-active'` with a callback.
2. Receiving the current content (or a loading message if none exists).
3. Passing it to the renderer.

If no content is provided during initialization, Vellum displays:
```html
<div style="padding: 16px;">Loading mods...</div>
```

### Customizing the Renderer
Consumers can override the renderer with `setRenderer` to support custom content types:
```javascript
vellumInstance.setRenderer((content, container) => {
  // Custom rendering logic
  container.innerHTML = content;
});
```
This allows integration with frameworks like Lit, React, or Vue, depending on the project’s needs.

---

## The `'layout:get-active'` Action

Vellum’s only built-in layout-related action is `'layout:get-active'`, handled in its core:
- **Purpose**: Retrieves the current content to be rendered.
- **Detail**: `{ callback: (layout) => void }`
- **Behavior**: Calls the callback with `{ content: any }`, where `content` is either the last rendered content (`currentContent`) or the loading message if none exists.

### Example Usage
A mod might handle this action to provide content:
```javascript
export async function init(toolkit) {
  const getLayout = (detail) => {
    detail.callback({ content: '<div>My Layout</div>' });
  };
  toolkit.dispatchAction({
    type: 'action:register',
    detail: { actionType: 'layout:get-active', modName: 'my-layout', handler: getLayout },
  });
}
```
- **Explanation**: This mod registers a handler for `'layout:get-active'`, supplying content when Vellum queries it.

Vellum calls this action internally in `update` to refresh the display.

---

## Consumer-Driven Layout Management

Vellum itself doesn’t manage layout structure or dynamics beyond rendering what’s provided via `'layout:get-active'`. Actions like `'layout:register'`, `'layout:push'`, `'layout:content:append'`, or `'layout:content:remove'` are not part of Vellum’s core—they are conventions a consuming project can implement. This means:
- **Layout Logic**: Mods must define how layouts are structured, stored, and updated.
- **Flexibility**: Consumers can adopt any model (e.g., stack, tree, flat content) by registering custom action handlers.

### Conceptual Framework
Vellum’s layout system is a blank slate:
- **Content Source**: Mods provide content via `'layout:get-active'`.
- **Rendering**: Vellum displays it in the shadow DOM.
- **Management**: Everything else (e.g., stacking, appending) is up to the project.

#### Simple Diagram
```
[Mod] --> ['layout:get-active'] --> [Vellum] --> [Rendered Content]
```

---

## Styling Considerations

Vellum renders into a shadow DOM, encapsulating styles:
- **Default**: Content styles are isolated from the global scope.
- **Customization**: Consumers must include styles with the content provided to `'layout:get-active'` (e.g., inline styles or framework-specific styling).
- **Limitations**: Vellum doesn’t expose CSS parts or variables natively; styling control lies with the content mods supply.

### Example
```javascript
const getLayout = (detail) => {
  detail.callback({ content: '<div style="color: blue;">Styled Content</div>' });
};
```

---

## Extending Layout Management

To create a robust layout system, consumers can:
1. **Register Handlers**: Add custom actions (e.g., `'layout:push'`) via `'action:register'`.
2. **Track State**: Maintain layout state in a mod (e.g., a stack or map of content).
3. **Update Content**: Respond to `'layout:get-active'` with the current state.

### Minimal Extension Example
```javascript
export async function init(toolkit) {
  let currentContent = '<div>Initial</div>';
  toolkit.dispatchAction({
    type: 'action:register',
    detail: {
      actionType: 'layout:get-active',
      modName: 'layout-manager',
      handler: (detail) => detail.callback({ content: currentContent }),
    },
  });
  toolkit.dispatchAction({
    type: 'action:register',
    detail: {
      actionType: 'layout:update',
      modName: 'layout-manager',
      handler: (detail) => { currentContent = detail.content; },
    },
  });
}
```
- **Explanation**: This mod tracks content and updates it via a custom `'layout:update'` action.

---

## Practical Tips
- **Renderer Match**: Ensure your renderer matches the content type returned by `'layout:get-active'`.
- **Single Source**: Designate one mod to handle `'layout:get-active'` to avoid conflicts.
- **Dynamic Updates**: Use custom actions to signal content changes, triggering Vellum’s `update`.

---

## Next Steps
- **Learn Actions**: Explore custom action creation in [Action System](./actions.md).
- **Customize Rendering**: See [Toolkit API](./toolkit.md) for renderer setup.
- **Build Layouts**: Check [Examples and Tutorials](./examples/) for consumer-driven examples.