# View

> Package `@umriss-ui/schedule`, version 0.40.0. Demo page: <https://romanhaendler.github.io/umriss-ui/schedule/view/>. Every page in one line: [llms.txt](https://romanhaendler.github.io/umriss-ui/schedule/llms.txt); every page in full: [llms-full.txt](https://romanhaendler.github.io/umriss-ui/schedule/llms-full.txt).

How the planner is looking at the plan - the span in view and the folded lane groups - as one value to keep and hand back.

```ts
import { useSchedule } from "@umriss-ui/schedule";
```

Demo page: https://romanhaendler.github.io/umriss-ui/schedule/view/

The schedule keeps its view itself and puts it nowhere, not in the address and not in any storage. `view` on what [`useSchedule`](https://romanhaendler.github.io/umriss-ui/schedule/api/#useSchedule) hands back holds it, and `onViewChange` reports every change the planner makes to it - a pan or zoom at most once per frame; keep it where the application keeps things and go back to it with `setView`.

`initialView` is the start, read once: a different value on a later render is ignored. `setView(view)` goes to a whole view at once, and what it leaves out goes back to its default; the same view again changes nothing, and `onViewChange` does not hear it. Without a span the schedule shows the extent of its subtasks, within `zoomLimits`. A group no `LaneGroup` declares falls out.

`setDomain`, `toggleGroup`, `foldAll` and `unfoldAll` change the view from outside - a button of the application's own that shows the whole plan or folds every team. The selection is not part of the view (`selectedTask`).

## Examples

### Keep and restore a view

`onViewChange` reports the span and the folded groups as one view; keep it - here in the browser's storage, so it outlives a reload - and go back to it with `setView`. Pan, zoom, fold, keep, reload, restore.

```tsx
import { useState } from "react";
import { Button, Stack, Text } from "@umriss-ui/core";
import { useSchedule } from "@umriss-ui/schedule";
import type { ScheduleView, Subtask, Task } from "@umriss-ui/schedule";

const at = (hours: number, minutes = 0) => new Date(2026, 2, 17, hours, minutes).getTime();
const min = (n: number) => n * 60_000;

const START: ScheduleView = { domain: [at(6), at(16)] };
const KEPT = "umriss-schedule-demo-view";

/* Storage can be missing or refuse - a private window, a blocked site. The
   view is then simply not kept. */
function readKept(): ScheduleView | null {
  try {
    const stored = localStorage.getItem(KEPT);
    return stored === null ? null : (JSON.parse(stored) as ScheduleView);
  } catch {
    return null;
  }
}

function keep(view: ScheduleView): void {
  try {
    localStorage.setItem(KEPT, JSON.stringify(view));
  } catch {
    /* Not kept; the schedule works on regardless. */
  }
}

const TEAMS: Task[] = [
  { id: "portal", name: "Member portal", color: "light-dark(#7c3aed, #a98bfa)" },
  { id: "billing", name: "Billing run", color: "light-dark(#0d9488, #3cc7b8)" },
];

const WORK: Subtask[] = [
  { id: "p1", task: "portal", lane: "noah", from: at(7), to: at(9, 30), leadOut: min(15) },
  { id: "p2", task: "portal", lane: "arjun", from: at(10), to: at(13), leadIn: min(30) },
  { id: "b1", task: "billing", lane: "mei", from: at(8), to: at(11) },
  { id: "b2", task: "billing", lane: "lukas", from: at(11, 30), to: at(14, 30), leadIn: min(15) },
];

export default function KeepAndRestore() {
  /* The schedule holds its view; `view` is what it shows now, and `setView`
     restores a kept one. */
  const [kept, setKept] = useState<ScheduleView | null>(readKept);
  const { Schedule, Lane, LaneGroup, Subtasks, view, setView, setDomain } = useSchedule({ initialView: START });

  return (
    <Stack gap={3}>
      <Schedule ariaLabel="Two teams on Tuesday, 17 March" height={290}>
        <LaneGroup id="product" label="Product">
          <Lane id="noah" label="Noah Fischer" />
          <Lane id="arjun" label="Arjun Mehta" />
        </LaneGroup>
        <LaneGroup id="finance" label="Finance">
          <Lane id="mei" label="Mei Tanaka" />
          <Lane id="lukas" label="Lukas Brandt" />
        </LaneGroup>
        <Subtasks data={WORK} tasks={TEAMS} />
      </Schedule>
      <Stack gap={1}>
        <Text as="span" size="sm" tone="secondary">
          What the application would keep
        </Text>
        {/* JSON has no space to break at: without this it ran past a phone's card. */}
        <Text as="code" size="sm" mono data-role="view" style={{ overflowWrap: "anywhere" }}>
          {JSON.stringify(view)}
        </Text>
      </Stack>
      <Stack direction="row" gap={2} wrap>
        <Button
          size="sm"
          onClick={() => {
            keep(view);
            setKept(view);
          }}
          data-keep
        >
          Keep this view
        </Button>
        <Button size="sm" variant="ghost" disabled={kept === null} onClick={() => kept && setView(kept)} data-restore>
          Restore the kept view
        </Button>
        <Button size="sm" variant="ghost" onClick={() => setDomain(null)} data-whole-plan>
          Show the whole plan
        </Button>
      </Stack>
    </Stack>
  );
}
```

## When to use something else

- Two schedules on the same hours → Linked schedules

## Keyboard

The keys of [First schedule](https://romanhaendler.github.io/umriss-ui/schedule/schedule/#keyboard-schedule) apply here.

## API

### `ScheduleOptions`

| Prop | Type | Default | Description |
|---|---|---|---|
| `initialView` | [`ScheduleView`](https://romanhaendler.github.io/umriss-ui/schedule/view/#type-ScheduleView) | — | The view to start from, read once when the hook first runs; a different value on a later render is ignored, as React ignores a changed `defaultValue`. To go to a view later, call `setView`. The schedule remembers none: where a view is kept is the application's decision.<br>Shown in: [Keep and restore a view](https://romanhaendler.github.io/umriss-ui/schedule/view/#keep-and-restore), [The smallest schedule (Installation)](https://romanhaendler.github.io/umriss-ui/schedule/installation/#smallest-schedule), [A day of tours (First schedule)](https://romanhaendler.github.io/umriss-ui/schedule/schedule/#first-schedule) and 78 more |

#### Events

| Prop | Type | Default | Description |
|---|---|---|---|
| `onViewChange` | `(view: `[`ScheduleView`](https://romanhaendler.github.io/umriss-ui/schedule/view/#type-ScheduleView)`) => void` | — | Every change the planner makes, once, always the whole view - the one to keep, or to hand another schedule's `setView`. A pan or zoom is reported at most once per frame. Not called for the view the schedule starts with, nor for one `setView` applies.<br>Shown in: [Keep two schedules in step (Linked schedules)](https://romanhaendler.github.io/umriss-ui/schedule/linked-schedules/#in-step), [Read a rota beside the incidents (Linked schedules)](https://romanhaendler.github.io/umriss-ui/schedule/linked-schedules/#rota-beside-incidents) |

### `ScheduleView`

| Prop | Type | Default | Description |
|---|---|---|---|
| `domain` | `readonly [number, number]` | — | The span in view, as two wall-clock instants. Absent, the schedule shows the extent of its subtasks, within `zoomLimits`.<br>Shown in: [Keep and restore a view](https://romanhaendler.github.io/umriss-ui/schedule/view/#keep-and-restore), [The smallest schedule (Installation)](https://romanhaendler.github.io/umriss-ui/schedule/installation/#smallest-schedule), [A day of tours (First schedule)](https://romanhaendler.github.io/umriss-ui/schedule/schedule/#first-schedule) and 77 more |
| `folded` | `readonly string[]` | — | The **Lane group**s that are folded, by id. An id no group carries falls out. A folded outer group hides the inner ones without their ids leaving the list, so unfolding it gives back the view that was there.<br>Shown in: [Fold groups from outside (Lane groups)](https://romanhaendler.github.io/umriss-ui/schedule/lane-groups/#fold-from-outside), [Read a folded group (Lane groups)](https://romanhaendler.github.io/umriss-ui/schedule/lane-groups/#the-miniature), [Start with groups folded (Lane groups)](https://romanhaendler.github.io/umriss-ui/schedule/lane-groups/#start-with-groups-folded) |
