# zidane-ui/workspace

Import: `import { … } from 'zidane-ui/workspace'`. Source: [ui/src/workspace/index.ts](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/index.ts).

## Components

### `LayoutBudgetProvider`

Component.

Provides the resolved horizontal budget to the columns below.

```ts
function LayoutBudgetProvider(props: LayoutBudgetProviderProps): Element
```

**Parameters**

- `props` (`LayoutBudgetProviderProps`): The sidebar's and the panel's wanted widths and bounds.

**Returns** `Element`

**Props**

- `children` (`ReactNode`): The columns.
- `panel` (`Omit<BudgetColumn, 'width'> & { share: number | null; width: number | null }`): The side panel. `width: null`: never dragged, the 50/50 split beside the chat. `share`: a width kept as a share of the room.
- `resetKey?` (`string | null`): What the panel belongs to (the scope's key): a change brings a slid-away panel back.
- `sidebar` (`BudgetColumn`): The sidebar.

Source: [ui/src/workspace/LayoutBudget.tsx:73](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/LayoutBudget.tsx#L73)

### `PanelContentView`

Component.

Paints an extension panel's declarative content: sections of rows, prose and key / value facts, and the footer actions.
Memoised: its host re-renders on every panel content or badge change, for any tab.

```ts
const PanelContentView: MemoExoticComponent<(__namedParameters: PanelContentViewProps) => Element>
```

Source: [ui/src/workspace/PanelContentView.tsx:168](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelContentView.tsx#L168)

### `PanelCorner`

Component.

Renders the corner cluster: pop out and full screen (while open), then the toggle.

```ts
function PanelCorner(props: PanelCornerProps): Element
```

**Parameters**

- `props` (`PanelCornerProps`): The [`PanelCornerProps`](https://zidane.si/docs/reference/ui-workspace.md#PanelCornerProps).

**Returns** `Element`

**Props**

- `className?` (`string`): Positioning and drag-region classes.
- `count?` (`number`): A count on the toggle while the panel is closed (the session's artifacts). 0 or absent: none.
- `expanded?` (`boolean`): The panel fills the window's content area.
- `onExpand?` (`() => void`): Enters or leaves full screen. Absent: no full-screen button.
- `onPopOut?` (`() => void`): Moves the panels to their own window. Absent: no button.
- `onToggle` (`() => void`): Shows or hides the panel.
- `open` (`boolean`): The panel shows.
- `style?` (`CSSProperties`): Inline positioning.

Source: [ui/src/workspace/PanelCorner.tsx:56](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelCorner.tsx#L56)

### `PanelGlyph`

Component.

Renders a panel's icon, or its extension's mark.

```ts
function PanelGlyph(props: PanelGlyphProps): Element | null
```

**Parameters**

- `props` (`PanelGlyphProps`): The [`PanelGlyphProps`](https://zidane.si/docs/reference/ui-workspace.md#PanelGlyphProps).

**Returns** `Element | null`

**Props**

- `className?` (`string`): Extra classes on the glyph (its size and colour).
- `fallback?` (`string`): An icon class for a panel with neither an icon nor an extension. Absent: nothing is drawn.
- `tab` (`PanelTabMarkSource & { label: string }`): The panel: its icon, and the extension that added it.

Source: [ui/src/workspace/PanelGlyph.tsx:24](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelGlyph.tsx#L24)

### `PanelSessionRowProvider`

Component.

Panel rows below that stand for a session are drawn with `row`: the app's
own session row, so they look and move like its session list.

```ts
function PanelSessionRowProvider(props: PanelSessionRowProviderProps): Element
```

**Parameters**

- `props` (`PanelSessionRowProviderProps`): The `row` component and the `children`.

**Returns** `Element`

**Props**

- `children?` (`ReactNode`): The panels that may show session rows.
- `row` (`ComponentType<PanelSessionRowProps>`): Draws a row that stands for a session (the app's session list row).

Source: [ui/src/workspace/PanelContentView.tsx:84](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelContentView.tsx#L84)

### `SidePanel`

Component.

The side panel for the scope on screen: its tab groups, their bodies, the resize edge and, when it floats and slid
away, the edge tab.

```ts
const SidePanel: MemoExoticComponent<(__namedParameters: SidePanelProps) => Element | null>
```

Source: [ui/src/workspace/SidePanel.tsx:82](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/SidePanel.tsx#L82)

### `WorkspaceHostProvider`

Component.

Puts a [`WorkspaceHost`](https://zidane.si/docs/reference/ui-workspace-headless.md#WorkspaceHost) in context for the `WorkspaceProvider`s below (what `AppHostProvider` does with
`host.workspace`).

```ts
function WorkspaceHostProvider(props: WorkspaceHostProviderProps): Element
```

**Parameters**

- `props` (`WorkspaceHostProviderProps`): The `host` and the `children`.

**Returns** `Element`

**Props**

- `children` (`ReactNode`): The app.
- `host` (`WorkspaceHost`): The host the `WorkspaceProvider`s below read when they are given none.

Source: [ui/src/workspace/WorkspaceProvider.tsx:163](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L163)

### `WorkspaceProvider`

Component.

Provides the side panel's state for `scope` to the components below.

```ts
function WorkspaceProvider<S extends WorkspaceScope = WorkspaceScope>(
  props: WorkspaceProviderProps<S>,
): Element
```

**Type parameters**

- `S` (`extends WorkspaceScope`, default `WorkspaceScope`)

**Parameters**

- `props` (`WorkspaceProviderProps<S>`): The host, the scope on screen, the tabs offered and where extension panels load.

**Returns** `Element`

**Props**

- `children` (`ReactNode`): The components that read the panel.
- `content?` (`WorkspaceContentTarget | null`): Where extension panels load. Absent: they don't load.
- `fillEmpty?` (`boolean`): When no stored tab is offered here, show the first offered one instead (not stored until picked).
- `host?` (`WorkspaceHost<S>`): Where layouts live and extension panels come from. Default: the `WorkspaceHostProvider`'s, else in memory.
- `labels?` (`Partial<{ panelAdd: string; panelChartLabel: string; panelClose: string; panelCloseTab: (label: string) => string; panelContentEmpty: string; panelContentNone: string; panelExpand: (expanded: boolean) => 'Exit full screen panels' | 'Full screen panels'; panelFilterClear: string; panelFiltersClear: string; panelFilterSummary: (label: string, picked: readonly string[]) => string; panelGroupTabs: (index: number) => string; panelHeatmapDay: (day: string) => string; panelHeatmapLabel: string; panelHomeLabel: string; panelLoadingMore: string; panelLoadMore: string; panelPopOut: string; panelRegion: string; panelResizeGroups: string; panelRowActions: (row: string) => string; panelRowCollapse: string; panelRowExpand: string; panelRowShowMore: string; panelSearch: string; panelSearchClear: string; panelShow: string; panelShowWaiting: (count: number) => string; panelTabInUse: string; panelTabs: string; panelTabUpdated: string; panelToggle: (open: boolean) => 'Hide side panel' | 'Show side panel'; panelToggleCount: (count: number) => string; panelUnavailable: string }>`): Overrides for the built-in strings. Keys you leave out keep the default English label.
- `loadContext?` (`(panelId: string) => PanelLoadContextInput | undefined`): Extra context for one extension panel's load and actions (what it was opened on).
- `scope` (`S | null`): The scope on screen (a session, a folder), or null: no panel.
- `tabs` (`readonly WorkspaceTab[]`): The tabs offered here, in catalog order: the app's own kinds and the extension panels.

Source: [ui/src/workspace/WorkspaceProvider.tsx:210](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L210)

## Functions

### `detailsPreview`

Function.

The first prose detail, flattened to plain text for the collapsed preview.

```ts
function detailsPreview(details: readonly PanelItem[] | undefined): string | undefined
```

**Parameters**

- `details` (`readonly PanelItem[] | undefined`): A row's details.

**Returns** `string | undefined`

Source: [ui/src/workspace/PanelContentView.tsx:410](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelContentView.tsx#L410)

### `focusedTabScope`

Function.

The scope holding focus: from the focused element (or `from`) up to the first registered one.
None when that scope is hidden: focus left behind in a kept-alive tab the user switched away
from (browsers keep it on a `display: none` element) must not take ctrl+w from the shown tab.

```ts
function focusedTabScope(from?: Element | null): TabScope | null
```

**Parameters**

- `from?` (`Element | null`, default `document.activeElement`): Where to start. Default: the focused element.

**Returns** `TabScope | null`

Source: [ui/src/workspace/tab-scopes.ts:81](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L81)

### `hoveredTabScope`

Function.

The scope under the pointer (the innermost hovered element up).

```ts
function hoveredTabScope(): TabScope | null
```

**Returns** `TabScope | null`

Source: [ui/src/workspace/tab-scopes.ts:191](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L191)

### `keepFocusIn`

Function.

After a tab key acted in `region`: whenever the element holding focus goes
away with what it showed (a closed file's editor, a stepped-away tab, even
a beat later), focus lands back on the region instead of the page, so the
next key and the next arrow stay there. Stops once the user is elsewhere.

```ts
function keepFocusIn(region: HTMLElement | null): void
```

**Parameters**

- `region` (`HTMLElement | null`): The region the key acted in; `null` does nothing.

Source: [ui/src/workspace/tab-scopes.ts:167](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L167)

### `panelCornerWidth`

Function.

The width the cluster covers at the end of the band, in px: what the strip or header under it reserves.

```ts
function panelCornerWidth(buttons: number): number
```

**Parameters**

- `buttons` (`number`): The buttons showing (the toggle alone: 1).

**Returns** `number`

Source: [ui/src/workspace/PanelCorner.tsx:47](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelCorner.tsx#L47)

### `panelTabScope`

Function.

The scope of the side panel's visible tab (`SidePanel` marks its root
`data-side-panel`), if it has one. Hidden kept-alive tabs have no boxes.

```ts
function panelTabScope(): TabScope | null
```

**Returns** `TabScope | null`

Source: [ui/src/workspace/tab-scopes.ts:183](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L183)

### `registerTabScope`

Function.

Register `scope` on `el` (marks it `data-tab-scope`). Returns the unregister.

```ts
function registerTabScope(el: HTMLElement, scope: TabScope): () => void
```

**Parameters**

- `el` (`HTMLElement`): The surface's root element.
- `scope` (`TabScope`): What the tab keys do there.

**Returns** `() => void`

Source: [ui/src/workspace/tab-scopes.ts:58](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L58)

### `steppedIndex`

Function.

The index a step lands on in a list, wrapping; -1 when the list is empty.

```ts
function steppedIndex(current: number, length: number, direction: -1 | 1): number
```

**Parameters**

- `current` (`number`): The index now (-1: none).
- `length` (`number`): The list's length.
- `direction` (`-1 | 1`): `1` next, `-1` previous.

**Returns** `number`

Source: [ui/src/workspace/tab-scopes.ts:203](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L203)

### `tabTarget`

Function.

Where ⌥⌘← / ⌥⌘→ act, from what holds focus (or `from`). Focus on the
page itself (it fell there): the region the user was in, if still shown.

```ts
function tabTarget(from?: Element | null): TabTarget
```

**Parameters**

- `from?` (`Element | null`, default `document.activeElement`): Where focus is. Default: the focused element.

**Returns** `TabTarget`

Source: [ui/src/workspace/tab-scopes.ts:148](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L148)

### `touchRecent`

Function.

Most recent first, deduplicated, capped at `max`. Returns `list` itself when nothing changes.

```ts
function touchRecent(
  list: readonly string[],
  id: string,
  max: number,
): readonly string[]
```

**Parameters**

- `list` (`readonly string[]`): The ids, most recent first.
- `id` (`string`): The id just used.
- `max` (`number`): How many to keep.

**Returns** `readonly string[]`

Source: [ui/src/workspace/panel-visibility.ts:25](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/panel-visibility.ts#L25)

### `trackTabRegions`

Function.

Follow where the user is (pointer down, focus in). Install once per window; returns the uninstall.

```ts
function trackTabRegions(): () => void
```

**Returns** `() => void`

Source: [ui/src/workspace/tab-scopes.ts:127](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L127)

### `useExtensionPanels`

Function.

The extension panels offered in `cwd`, kept per folder: switching back to a
folder shows its tabs at once, and a slow list for a folder left behind
never lands on the one shown. A folder not listed yet keeps the last list
until its own arrives, so the strip does not drop its tabs for a frame.
Re-lists when the host says the catalog changed.

```ts
function useExtensionPanels(
  panels: WorkspacePanels | undefined,
  cwd: string | null,
): readonly WorkspacePanelSummary[]
```

**Parameters**

- `panels` (`WorkspacePanels | undefined`): The host's extension panels (`host.panels`), or nothing.
- `cwd` (`string | null`): The folder (`''`: the home of no project, the host's choice of folder), or null (no extension panels).

**Returns** `readonly WorkspacePanelSummary[]`

Source: [ui/src/workspace/WorkspaceProvider.tsx:531](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L531)

### `useLayoutBudget`

Function.

The budget from the nearest [`LayoutBudgetProvider`](https://zidane.si/docs/reference/ui-workspace.md#LayoutBudgetProvider). Throws outside one.

```ts
function useLayoutBudget(): LayoutBudget
```

**Returns** `LayoutBudget`

Source: [ui/src/workspace/LayoutBudget.tsx:129](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/LayoutBudget.tsx#L129)

### `useLayoutBudgetOptional`

Function.

The budget from the nearest [`LayoutBudgetProvider`](https://zidane.si/docs/reference/ui-workspace.md#LayoutBudgetProvider), or `null` (chrome that may render outside one).

```ts
function useLayoutBudgetOptional(): LayoutBudget | null
```

**Returns** `LayoutBudget | null`

Source: [ui/src/workspace/LayoutBudget.tsx:124](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/LayoutBudget.tsx#L124)

### `useOptionalWorkspaceActions`

Function.

[`useWorkspaceActions`](https://zidane.si/docs/reference/ui-workspace.md#useWorkspaceActions), or `null` outside a `WorkspaceProvider`.

```ts
function useOptionalWorkspaceActions(): WorkspaceActions | null
```

**Returns** `WorkspaceActions | null`

Source: [ui/src/workspace/WorkspaceProvider.tsx:483](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L483)

### `useOptionalWorkspaceView`

Function.

[`useWorkspaceView`](https://zidane.si/docs/reference/ui-workspace.md#useWorkspaceView), or `null` outside a `WorkspaceProvider`.

```ts
function useOptionalWorkspaceView(): WorkspaceView<WorkspaceTab> | null
```

**Returns** `WorkspaceView<WorkspaceTab> | null`

Source: [ui/src/workspace/WorkspaceProvider.tsx:493](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L493)

### `usePanelGroupHandlers`

Function.

The `splitTabRight` / `splitTabDown` handlers for the [`WorkspaceProvider`](https://zidane.si/docs/reference/ui-workspace.md#WorkspaceProvider) above, or none while they cannot act.

```ts
function usePanelGroupHandlers(enabled: boolean): KeybindingHandlers
```

**Parameters**

- `enabled` (`boolean`): The panel is this window's to drive (false: offer nothing).

**Returns** `KeybindingHandlers`

Source: [ui/src/workspace/panel-group-keys.ts:18](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/panel-group-keys.ts#L18)

### `usePanelVisible`

Function.

Whether the tab body calling it is on screen (true outside a side panel).

```ts
function usePanelVisible(): boolean
```

**Returns** `boolean`

Source: [ui/src/workspace/panel-visibility.ts:14](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/panel-visibility.ts#L14)

### `useScopeLayout`

Function.

Live layout for a scope (`EMPTY_LAYOUT` without one). A scope on screen owns its layout from then on
(`adoptScopeLayout`; the draft excepted): what it shows stays put while other sessions of its project
change theirs.

```ts
function useScopeLayout(memory: LayoutMemory, scope: LayoutScope | null): SessionLayout
```

**Parameters**

- `memory` (`LayoutMemory`): The window's layout memory.
- `scope` (`LayoutScope | null`): The scope; keyed by its identity, not its object (callers may rebuild it per render).

**Returns** `SessionLayout`

Source: [ui/src/workspace/useScopeLayout.ts:17](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/useScopeLayout.ts#L17)

### `useTabScope`

Function.

Register a tab scope on the element `ref` points at, with handlers that always see the latest render.

```ts
function useTabScope<T extends HTMLElement>(
  ref: RefObject<T | null>,
  scope: TabScope,
): void
```

**Type parameters**

- `T` (`extends HTMLElement`)

**Parameters**

- `ref` (`RefObject<T | null>`): The surface's root element.
- `scope` (`TabScope`): What the tab keys do there.

Source: [ui/src/workspace/tab-scopes.ts:215](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L215)

### `useWorkspace`

Function.

Everything at once (re-renders on any panel change); prefer the narrower hooks above.

```ts
function useWorkspace(): WorkspaceApi
```

**Returns** `WorkspaceApi`

Source: [ui/src/workspace/WorkspaceProvider.tsx:508](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L508)

### `useWorkspaceActions`

Function.

Stable actions only: never re-renders on panel state changes. Throws outside a `WorkspaceProvider`.

```ts
function useWorkspaceActions(): WorkspaceActions
```

**Returns** `WorkspaceActions`

Source: [ui/src/workspace/WorkspaceProvider.tsx:478](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L478)

### `useWorkspaceContent`

Function.

Extension content and badges. Re-renders on every content load and badge change.

```ts
function useWorkspaceContent(): WorkspaceContent
```

**Returns** `WorkspaceContent`

Source: [ui/src/workspace/WorkspaceProvider.tsx:503](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L503)

### `useWorkspaceHost`

Function.

The [`WorkspaceHost`](https://zidane.si/docs/reference/ui-workspace-headless.md#WorkspaceHost) from the nearest [`WorkspaceHostProvider`](https://zidane.si/docs/reference/ui-workspace.md#WorkspaceHostProvider), or `null`.

```ts
function useWorkspaceHost(): WorkspaceHost<WorkspaceScope> | null
```

**Returns** `WorkspaceHost<WorkspaceScope> | null`

Source: [ui/src/workspace/WorkspaceProvider.tsx:168](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L168)

### `useWorkspaceKeyCommands`

Function.

The side panel's key commands for the [`WorkspaceProvider`](https://zidane.si/docs/reference/ui-workspace.md#WorkspaceProvider) above. Each is present only while it can act.

```ts
function useWorkspaceKeyCommands(options: WorkspaceKeyCommandsOptions): KeyCommands
```

**Parameters**

- `options` (`WorkspaceKeyCommandsOptions`): What is on screen, and the app's hooks.

**Returns** `KeyCommands`

Source: [ui/src/workspace/workspace-key-commands.ts:47](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/workspace-key-commands.ts#L47)

### `useWorkspaceLabels`

Function.

Returns the side panel's strings: the defaults merged with any overrides given to `WorkspaceProvider` or `LabelsProvider`.

```ts
function useWorkspaceLabels(): { panelAdd: string; panelChartLabel: string; panelClose: string; panelCloseTab: (label: string) => string; panelContentEmpty: string; panelContentNone: string; panelExpand: (expanded: boolean) => 'Exit full screen panels' | 'Full screen panels'; panelFilterClear: string; panelFiltersClear: string; panelFilterSummary: (label: string, picked: readonly string[]) => string; panelGroupTabs: (index: number) => string; panelHeatmapDay: (day: string) => string; panelHeatmapLabel: string; panelHomeLabel: string; panelLoadingMore: string; panelLoadMore: string; panelPopOut: string; panelRegion: string; panelResizeGroups: string; panelRowActions: (row: string) => string; panelRowCollapse: string; panelRowExpand: string; panelRowShowMore: string; panelSearch: string; panelSearchClear: string; panelShow: string; panelShowWaiting: (count: number) => string; panelTabInUse: string; panelTabs: string; panelTabUpdated: string; panelToggle: (open: boolean) => 'Hide side panel' | 'Show side panel'; panelToggleCount: (count: number) => string; panelUnavailable: string }
```

**Returns** `{ panelAdd: string; panelChartLabel: string; panelClose: string; panelCloseTab: (label: string) => string; panelContentEmpty: string; panelContentNone: string; panelExpand: (expanded: boolean) => 'Exit full screen panels' | 'Full screen panels'; panelFilterClear: string; panelFiltersClear: string; panelFilterSummary: (label: string, picked: readonly string[]) => string; panelGroupTabs: (index: number) => string; panelHeatmapDay: (day: string) => string; panelHeatmapLabel: string; panelHomeLabel: string; panelLoadingMore: string; panelLoadMore: string; panelPopOut: string; panelRegion: string; panelResizeGroups: string; panelRowActions: (row: string) => string; panelRowCollapse: string; panelRowExpand: string; panelRowShowMore: string; panelSearch: string; panelSearchClear: string; panelShow: string; panelShowWaiting: (count: number) => string; panelTabInUse: string; panelTabs: string; panelTabUpdated: string; panelToggle: (open: boolean) => 'Hide side panel' | 'Show side panel'; panelToggleCount: (count: number) => string; panelUnavailable: string }`

Source: [ui/src/workspace/useWorkspaceLabels.ts:11](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/useWorkspaceLabels.ts#L11)

### `useWorkspaceRequests`

Function.

The one-shot requests to tab bodies.

```ts
function useWorkspaceRequests(): WorkspaceRequests
```

**Returns** `WorkspaceRequests`

Source: [ui/src/workspace/WorkspaceProvider.tsx:498](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L498)

### `useWorkspaceView`

Function.

The catalog, strips and open state. Re-renders on navigation, not on content loads.

```ts
function useWorkspaceView(): WorkspaceView
```

**Returns** `WorkspaceView`

Source: [ui/src/workspace/WorkspaceProvider.tsx:488](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L488)

## Constants

### `PanelVisibilityContext`

Constant.

Whether the tab body below is on screen; `TabParking` provides it per body. Default: visible.

```ts
const PanelVisibilityContext: Context<boolean>
```

Source: [ui/src/workspace/panel-visibility.ts:11](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/panel-visibility.ts#L11)

### `TAB_REGION_PROPS`

Constant.

Props for a focus region's root: marked, and focusable by a click (not by Tab).

```ts
const TAB_REGION_PROPS: { readonly 'data-tab-region': ''; readonly tabIndex: -1 }
```

Source: [ui/src/workspace/tab-scopes.ts:49](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L49)

## Interfaces

### `BudgetColumn`

Interface.

A column's wanted width and its bounds.

```ts
interface BudgetColumn
```

**Properties**

- `max` (`number`): The widest a drag makes it (px).
- `min` (`number`): The narrowest it gets (px).
- `open` (`boolean`): It is shown.
- `width` (`number`): Its wanted width (px).

Source: [ui/src/workspace/LayoutBudget.tsx:43](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/LayoutBudget.tsx#L43)

### `LayoutBudget`

Interface.

The resolved widths and modes, the slid-away flag and the drag caps.

```ts
interface LayoutBudget extends LayoutResolved
```

**Properties**

- `chatMin` (`number`, from `LayoutResolved`): The floor the chat was held to (`chatFloor`).
- `chatWidth` (`number`, from `LayoutResolved`): The room left to the chat (px).
- `getCaps` (`() => { panelMax: number; sidebarMax: number }`): Drag caps that keep the chat at its floor, read at drag time. A getter,
  not a value: they change on every resized pixel and must not re-render
  every consumer of this context while the window is being resized.
- `hidePanel` (`() => void`): Slide the floating panel away (a pointer-down in the chat).
- `panelHidden` (`boolean`): Overlay panel hidden by a click in the chat; `revealPanel` brings it back.
- `panelMode` (`'overlay' | 'docked'`, from `LayoutResolved`): `overlay`: drawn over the chat at its wanted width instead of taking room.
- `panelWidth` (`number`, from `LayoutResolved`): The panel's width (px): the room it takes docked, its drawn width floating; 0 when closed.
- `revealPanel` (`() => void`): Bring the slid-away panel back.
- `sidebarForcedCollapsed` (`boolean`, from `LayoutResolved`): The sidebar had to close for the chat to fit.
- `sidebarWidth` (`number`, from `LayoutResolved`): The sidebar's width (px); 0 when closed.

Source: [ui/src/workspace/LayoutBudget.tsx:27](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/LayoutBudget.tsx#L27)

### `LayoutBudgetProviderProps`

Interface.

Props for [`LayoutBudgetProvider`](https://zidane.si/docs/reference/ui-workspace.md#LayoutBudgetProvider).

```ts
interface LayoutBudgetProviderProps
```

**Properties**

- `children` (`ReactNode`): The columns.
- `panel` (`Omit<BudgetColumn, 'width'> & { share: number | null; width: number | null }`): The side panel. `width: null`: never dragged, the 50/50 split beside the chat. `share`: a width kept as a share of the room.
- `resetKey?` (`string | null`): What the panel belongs to (the scope's key): a change brings a slid-away panel back.
- `sidebar` (`BudgetColumn`): The sidebar.

Source: [ui/src/workspace/LayoutBudget.tsx:55](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/LayoutBudget.tsx#L55)

### `PanelContentViewProps`

Interface.

Props for [`PanelContentView`](https://zidane.si/docs/reference/ui-workspace.md#PanelContentView).

```ts
interface PanelContentViewProps
```

**Properties**

- `className?` (`string`): Extra class names for the root.
- `content` (`PanelContent | null`): The panel's content, or `null` before the first load.
- `error` (`string | null`): Why the last load failed, or `null`.
- `loading` (`boolean`): A load is in flight.
- `loadingMore?` (`boolean`): The next page is loading.
- `onAction` (`(actionId: string, payload?: unknown) => void`): Runs one of the panel's actions (a row's `actionId`, a footer action). Keep it stable: the view is memoised.
- `onControl?` (`(id: string, value: string | readonly string[]) => void`): A control was picked: keep `value` (a `multi` control's options: a list) as the panel's `view[id]` and
  reload. Absent: no controls, no filters.
- `onMore?` (`() => void`): Show more was pressed: load the next page (`PanelContent.more`). Absent: no Show more.
- `onOpenPath?` (`(path: string, event?: PanelOpenEvent) => void`): Opens a row's `href` that is a path (not a web link). Absent: such rows are not clickable.
- `onOpenSession?` (`(sessionId: string) => void`): Opens a row's `session`. Absent: such rows fall back to their action or link.
- `onSearch?` (`(text: string) => void`): The search text changed: keep it and reload. Absent: no search field.
- `onStart?` (`(start: PanelStartSession, row: PanelRowItem) => void | Promise<void>`): A row action that starts a session (`PanelRowAction.start`). Absent: such actions are not shown. A rejection
  is the owner's to show.
- `search?` (`string`): The text in the panel's search field.
- `style?` (`CSSProperties`): Inline styles on the root element.
- `variant?` (`'side' | 'block'`): `side` (default): a scrolling tab with a footer. `block`: as tall as its content.
- `view?` (`Readonly<Record<string, string | readonly string[]>>`): What the user picked, by control id: the controls show it before the content for it lands.

Source: [ui/src/workspace/PanelContentView.tsx:103](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelContentView.tsx#L103)

### `PanelCornerProps`

Interface.

Props of [`PanelCorner`](https://zidane.si/docs/reference/ui-workspace.md#PanelCorner).

```ts
interface PanelCornerProps
```

**Properties**

- `className?` (`string`): Positioning and drag-region classes.
- `count?` (`number`): A count on the toggle while the panel is closed (the session's artifacts). 0 or absent: none.
- `expanded?` (`boolean`): The panel fills the window's content area.
- `onExpand?` (`() => void`): Enters or leaves full screen. Absent: no full-screen button.
- `onPopOut?` (`() => void`): Moves the panels to their own window. Absent: no button.
- `onToggle` (`() => void`): Shows or hides the panel.
- `open` (`boolean`): The panel shows.
- `style?` (`CSSProperties`): Inline positioning.

Source: [ui/src/workspace/PanelCorner.tsx:20](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelCorner.tsx#L20)

### `PanelGlyphProps`

Interface.

Props for [`PanelGlyph`](https://zidane.si/docs/reference/ui-workspace.md#PanelGlyph).

```ts
interface PanelGlyphProps
```

**Properties**

- `className?` (`string`): Extra classes on the glyph (its size and colour).
- `fallback?` (`string`): An icon class for a panel with neither an icon nor an extension. Absent: nothing is drawn.
- `tab` (`PanelTabMarkSource & { label: string }`): The panel: its icon, and the extension that added it.

Source: [ui/src/workspace/PanelGlyph.tsx:10](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelGlyph.tsx#L10)

### `PanelOpenEvent`

Interface.

A click's modifiers, as `onOpenPath` receives them.

```ts
interface PanelOpenEvent
```

**Properties**

- `ctrlKey?` (`boolean`): Ctrl was held.
- `metaKey?` (`boolean`): ⌘ was held.

Source: [ui/src/workspace/PanelContentView.tsx:95](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelContentView.tsx#L95)

### `PanelSessionRowProps`

Interface.

Props of a [`PanelSessionRowProvider`](https://zidane.si/docs/reference/ui-workspace.md#PanelSessionRowProvider)'s row.

```ts
interface PanelSessionRowProps
```

**Properties**

- `fallback` (`ReactNode`): The kit's own row for it: draw this when the app doesn't know the session.
- `item` (`PanelRowItem`): The panel's row.
- `session` (`string`): The session it stands for (`item.session`).

Source: [ui/src/workspace/PanelContentView.tsx:59](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelContentView.tsx#L59)

### `PanelSessionRowProviderProps`

Interface.

Props of [`PanelSessionRowProvider`](https://zidane.si/docs/reference/ui-workspace.md#PanelSessionRowProvider).

```ts
interface PanelSessionRowProviderProps
```

**Properties**

- `children?` (`ReactNode`): The panels that may show session rows.
- `row` (`ComponentType<PanelSessionRowProps>`): Draws a row that stands for a session (the app's session list row).

Source: [ui/src/workspace/PanelContentView.tsx:71](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelContentView.tsx#L71)

### `SidePanelProps`

Interface.

Props for [`SidePanel`](https://zidane.si/docs/reference/ui-workspace.md#SidePanel).

```ts
interface SidePanelProps extends Omit<ComponentPropsWithoutRef<'aside'>, 'children'>
```

**Properties**

- `bodyKey?` (`string`): What the tab bodies render for: a change re-renders every body. Default: the scope's key.
- `controls?` (`StripControls`): The panel's own buttons (close, pop out), on the top-right strip. Absent: the app draws them (`endInset`).
- `counts?` (`Readonly<Record<string, number>>`): A count per tab id on its start-screen card (the session's artifacts).
- `defaultWidth?` (`number`): The width a double-click on the edge restores (px). Default: `width`.
- `endInset?` (`string`): Room the top-right strip keeps for what the app draws over its end (a CSS length, `PanelCorner`).
- `expanded?` (`boolean`): Full screen: the panel covers its whole parent (the content beside it stays laid out underneath).
- `fill?` (`boolean`): The whole window (a panels-only window): full width, always shown, no resize; the top-left strip clears the window controls.
- `maxWidth` (`number`): The widest a drag makes it (px).
- `minWidth` (`number`): The narrowest a drag makes it (px).
- `onReveal?` (`() => void`): Shows the edge tab that brings a slid-away floating panel back.
- `onWidthCommit?` (`(width: number) => void`): A drag on the edge ended at `width`. Absent: no resize handle.
- `overlay?` (`boolean`): Floating over the content instead of beside it.
- `registry` (`WorkspaceTabRegistry`): The app's tab kinds: what each tab renders.
- `scopeKey?` (`string`): The scope the panel draws (its key): tabs drop only into its strips, a change starts its frames afresh. Default: the provider's scope.
- `slidAway?` (`boolean`): Hidden though open (a floating panel slid away); `onReveal` brings it back.
- `startInset?` (`string`): Room the top-left strip keeps for the window's controls (a CSS length).
- `width` (`number`): The panel's width (px), as the app resolved it.

Source: [ui/src/workspace/SidePanel.tsx:39](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/SidePanel.tsx#L39)

### `StripControls`

Interface.

The panel's own buttons, on one strip only.

```ts
interface StripControls
```

**Properties**

- `closeLabel?` (`string`): The close button's label. Default: the `closePanel` label.
- `onClose` (`() => void`): Close the panel (or the window it fills).
- `onPopOut?` (`() => void`): Move the panels to their own window.

Source: [ui/src/workspace/PanelStrip.tsx:36](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/PanelStrip.tsx#L36)

### `TabScope`

Interface.

What a surface does with the tab keys: step, close, find.

```ts
interface TabScope
```

**Properties**

- `close` (`() => boolean`): Close one thing inside the scope. False when nothing is left to close:
  ctrl+w then closes the side-panel tab holding it.
- `find?` (`(mode: 'files' | 'file') => boolean`): ⌘F (`file`: find in the open file or diff) or ⌘⇧F (`files`: search
  across files). False when the scope has nothing to search: the app's
  own find takes the key.
- `step` (`(direction: -1 | 1) => boolean`): `1` next, `-1` previous. Returns false when there was nothing to move to.

Source: [ui/src/workspace/tab-scopes.ts:29](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L29)

### `TabTarget`

Interface.

Where the tab keys act: a scope, and the focus region holding focus.

```ts
interface TabTarget
```

**Properties**

- `region` (`HTMLElement | null`): The focus region holding focus (side panel, terminal drawer); `null` = the app.
- `scope` (`TabScope | null`): Where the tab keys step: the scope holding focus, else the one shown in its region.

Source: [ui/src/workspace/tab-scopes.ts:101](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/tab-scopes.ts#L101)

### `WorkspaceActions`

Interface.

Every panel action; one object whose identity never changes for the provider's lifetime.

```ts
interface WorkspaceActions extends Omit<WorkspaceOps, 'requestAttention'>
```

**Properties**

- `act` (`(id: string, actionId: string, payload?: unknown) => Promise<void>`): Run an extension panel's action; its content reloads after.
- `close` (`() => void`, from `Omit`): Close the panel.
- `closeTab` (`(id: string) => void`, from `Omit`): Remove a tab from the strip; closing the last one closes the panel.
- `cycle` (`(direction: -1 | 1) => void`, from `Omit`): Show the next (1) or previous (-1) tab of the focused group.
- `dropTab` (`(id: string, to: TabDrop) => void`, from `Omit`): A dragged tab dropped on a strip (before a tab, null: at its end) or on a group's body (a zone).
- `focusTab` (`(id: string) => void`): The user asked for a tab (a bar, an indicator): pin, open as a pick, hand focus to its body.
- `moveTab` (`(id: string, delta: number) => void`, from `Omit`): Move one tab left (-1) or right (+1) in its strip (keyboard reorder).
- `open` (`() => void`, from `Omit`): Open the panel.
- `openProactive` (`(id: string) => void`, from `Omit`): Agent or extension driven open; refused while the user owns the tab choice.
- `pick` (`(id: string, groupId?: string) => void`, from `Omit`): Show a tab; one not in the strip yet joins `groupId` (default: the focused group).
- `refresh` (`(id: string) => void`): Reload an extension panel's content.
- `requestAttention` (`(id: string, opts?: { focus?: boolean; open?: boolean }) => void`): The agent is waiting on the user in `id`: pin the tab into the strip
  and, unless `open` is false, show it (regardless of earlier user picks:
  a blocked run outranks a badge). `focus` asks the tab body to move
  keyboard focus to its first control once shown (`takeFocusRequest`);
  it is only recorded when the tab is being shown.
- `resizeSplit` (`(splitId: string, sizes: readonly number[]) => void`, from `Omit`): New shares for a split's children as shown (a divider drag); hidden ones keep theirs.
- `revealFile` (`(absPath: string) => void`): Show `absPath` in the Files tab (opens the panel on Files, a user pick): a file opens in a tab, a folder (a path
  ending in `/`) is selected and expanded in the tree. The tab takes it with `takeRevealRequest`; a tab not
  mounted yet picks it up when it mounts.
- `setAttention` (`(scopeKey: string, id: string, value: TabAttention | null) => void`): Set or clear (`null`) a tab's attention for a scope (by its key). Idempotent.
- `showWorkingTree` (`() => void`): Open the panel on Diffs, showing the working tree. Taken like the reveal request.
- `splitTab` (`(id: string, side: 'right' | 'down') => void`, from `Omit`): Take a tab out into a new group below (`down`) or beside (`right`) its own.
- `takeFocusRequest` (`() => void`): The tab body took the focus request.
- `takeRevealRequest` (`() => void`): The Files tab took the reveal request.
- `takeWorkingTreeRequest` (`() => void`): The Diffs tab took the working-tree request.
- `toggle` (`() => void`, from `Omit`): Open the panel when closed, close it when open.

Source: [ui/src/workspace/WorkspaceProvider.tsx:67](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L67)

### `WorkspaceContent`

Interface.

Extension content and badges: the fast-changing part.

```ts
interface WorkspaceContent
```

**Properties**

- `attention` (`Readonly<Record<string, TabAttention>>`): Attention for the scope on screen's tabs, by tab id.
- `contentFor` (`(id: string) => PanelContentEntry`): An extension panel's content for the scope on screen.

Source: [ui/src/workspace/WorkspaceProvider.tsx:133](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L133)

### `WorkspaceContentTarget`

Interface.

Where extension panels load: the folder, and the session they show beside.

```ts
interface WorkspaceContentTarget
```

**Properties**

- `cwd` (`string`): The folder.
- `sessionId?` (`string | null`): The session, or none (a folder alone).

Source: [ui/src/workspace/WorkspaceProvider.tsx:173](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L173)

### `WorkspaceHostProviderProps`

Interface.

Props for [`WorkspaceHostProvider`](https://zidane.si/docs/reference/ui-workspace.md#WorkspaceHostProvider).

```ts
interface WorkspaceHostProviderProps
```

**Properties**

- `children` (`ReactNode`): The app.
- `host` (`WorkspaceHost`): The host the `WorkspaceProvider`s below read when they are given none.

Source: [ui/src/workspace/WorkspaceProvider.tsx:150](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L150)

### `WorkspaceKeyCommandsOptions`

Interface.

Options for [`useWorkspaceKeyCommands`](https://zidane.si/docs/reference/ui-workspace.md#useWorkspaceKeyCommands).

```ts
interface WorkspaceKeyCommandsOptions
```

**Properties**

- `actions?` (`WorkspaceActions`): The actions to run. Default: the `WorkspaceProvider`'s (an app may wrap them, relaying to another window).
- `scope` (`boolean`): A scope is on screen (a session or a folder): the panel keys act.
- `session` (`boolean`): A session is on screen: the Todos tab, the tab keys.
- `spaces?` (`{ on: boolean; step(direction: -1 | 1): void }`): The spaces the tab keys step through outside the panel, while `on`.
- `toggle?` (`boolean`): Offer `openArtifacts` (toggling the panel). Default: with a scope.
- `closeOutside?` (`() => boolean`): `closeTab` with nothing to close in the focused scope: return `true` when the app closed something itself (a
  standalone window), before the panel's visible tab closes.

Source: [ui/src/workspace/workspace-key-commands.ts:24](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/workspace-key-commands.ts#L24)

### `WorkspaceProviderProps`

Interface.

Props for [`WorkspaceProvider`](https://zidane.si/docs/reference/ui-workspace.md#WorkspaceProvider).

```ts
interface WorkspaceProviderProps<S extends WorkspaceScope = WorkspaceScope>
```

**Type parameters**

- `S` (`extends WorkspaceScope`, default `WorkspaceScope`)

**Properties**

- `children` (`ReactNode`): The components that read the panel.
- `content?` (`WorkspaceContentTarget | null`): Where extension panels load. Absent: they don't load.
- `fillEmpty?` (`boolean`): When no stored tab is offered here, show the first offered one instead (not stored until picked).
- `host?` (`WorkspaceHost<S>`): Where layouts live and extension panels come from. Default: the `WorkspaceHostProvider`'s, else in memory.
- `labels?` (`Partial<{ panelAdd: string; panelChartLabel: string; panelClose: string; panelCloseTab: (label: string) => string; panelContentEmpty: string; panelContentNone: string; panelExpand: (expanded: boolean) => 'Exit full screen panels' | 'Full screen panels'; panelFilterClear: string; panelFiltersClear: string; panelFilterSummary: (label: string, picked: readonly string[]) => string; panelGroupTabs: (index: number) => string; panelHeatmapDay: (day: string) => string; panelHeatmapLabel: string; panelHomeLabel: string; panelLoadingMore: string; panelLoadMore: string; panelPopOut: string; panelRegion: string; panelResizeGroups: string; panelRowActions: (row: string) => string; panelRowCollapse: string; panelRowExpand: string; panelRowShowMore: string; panelSearch: string; panelSearchClear: string; panelShow: string; panelShowWaiting: (count: number) => string; panelTabInUse: string; panelTabs: string; panelTabUpdated: string; panelToggle: (open: boolean) => 'Hide side panel' | 'Show side panel'; panelToggleCount: (count: number) => string; panelUnavailable: string }>`): Overrides for the built-in strings. Keys you leave out keep the default English label.
- `loadContext?` (`(panelId: string) => PanelLoadContextInput | undefined`): Extra context for one extension panel's load and actions (what it was opened on).
- `scope` (`S | null`): The scope on screen (a session, a folder), or null: no panel.
- `tabs` (`readonly WorkspaceTab[]`): The tabs offered here, in catalog order: the app's own kinds and the extension panels.

Source: [ui/src/workspace/WorkspaceProvider.tsx:181](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L181)

### `WorkspaceRequests`

Interface.

One-shot hand-overs to tab bodies (consumed with the matching `take*` action).

```ts
interface WorkspaceRequests
```

**Properties**

- `focusRequest` (`string | null`): The tab whose body should take keyboard focus.
- `revealRequest` (`string | null`): The path the Files tab should show (`revealFile`), or `null`.
- `workingTreeRequest` (`number`): Bumped by each `showWorkingTree` (a counter: a second ask while Diffs is up still lands); `0` once taken.

Source: [ui/src/workspace/WorkspaceProvider.tsx:123](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L123)

### `WorkspaceTabRegistry`

Interface.

The tab kinds an app offers: how each tab renders, and how the panel
treats it. Read at render; a body re-renders when its tab or the
panel's `bodyKey` changes.

```ts
interface WorkspaceTabRegistry
```

**Properties**

- `describe?` (`(tab: WorkspaceTab) => string | undefined`): One short line about the tab, on the panel's start screen (`PanelHome`). Absent or empty: none.
- `keepAlive?` (`(tab: WorkspaceTab) => boolean`): Keep the body mounted behind `hidden` once visited (among the 3 most
  recent). Leave out a body that claims something on mount (a terminal
  view): a hidden copy would keep claiming it. Default: none.
- `render` (`(tab: WorkspaceTab) => ReactNode`): The tab's body: any React node.
- `snap?` (`(tab: WorkspaceTab) => boolean`): The group frame showing this tab snaps instead of animating (a native view drawn over its slot).
- `wrap?` (`(tab: WorkspaceTab, body: ReactNode) => ReactNode`): Wraps each body, such as in an error boundary of the app's, so one failing tab leaves the others usable.

Source: [ui/src/workspace/TabParking.tsx:27](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/TabParking.tsx#L27)

### `WorkspaceView`

Interface.

Catalog, strip and open/active state: changes on user navigation, not on content loads.

```ts
interface WorkspaceView<T extends WorkspaceTab = WorkspaceTab>
```

**Type parameters**

- `T` (`extends WorkspaceTab`, default `WorkspaceTab`)

**Properties**

- `activeTab` (`T | null`): The focused group's tab, `null` for an empty catalog.
- `closedTabs` (`readonly T[]`): Catalog entries not in a strip (what the `+` menu offers).
- `cwd` (`string | null`): The folder extension panels load against (`content.cwd`), or null.
- `focusedGroupId` (`string | null`): The focused group: where new tabs go, what cycling walks; it shows `activeTab`.
- `openTabs` (`readonly T[]`): Tabs in the strips, in order: what the strips show.
- `scopeKey` (`string | null`): The scope these tabs belong to (its key): what a conversation switch changes.
- `state` (`Pick<PanelState, 'open' | 'activeId'>`): The panel is open, and its stored active tab.
- `tabs` (`readonly T[]`): Every tab offered here (the catalog).
- `tree` (`PanelViewNode<T> | null`): The groups as laid out, restricted to tabs on screen; `null` when none is.

Source: [ui/src/workspace/WorkspaceProvider.tsx:101](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L101)

## Types

### `WorkspaceApi`

Type.

Everything [`useWorkspace`](https://zidane.si/docs/reference/ui-workspace.md#useWorkspace) returns.

```ts
type WorkspaceApi = WorkspaceActions & WorkspaceView & WorkspaceRequests & WorkspaceContent
```

Source: [ui/src/workspace/WorkspaceProvider.tsx:141](https://github.com/Tahul/zidane/blob/main/ui/src/workspace/WorkspaceProvider.tsx#L141)
