# Components

> Answer with nodes the shop front draws in its own style.

Source: https://storeware.ai/docs/sdk/components

```ts
import { ... } from '@storeware/plugin-sdk/components';
```

### countComponentNodes

Every node in a tree, children included.

```ts
function countComponentNodes(nodes: readonly ComponentNode[]): number
```

### componentDepth

How deep a tree goes; a stack inside a stack is two.

```ts
function componentDepth(nodes: readonly ComponentNode[]): number
```

### parseComponents

Parses an answer, or says why it cannot be drawn. Storeware runs the same check, so a tree this accepts is a tree the shop front draws.

```ts
function parseComponents(value: unknown): { ok: true; components: ComponentNode[]; } | { ok: false; problems: string[]; }
```

### components

Builds an answer, checked, so a mistake shows in development, not on a shop.

```ts
function components(...nodes: ComponentNode[]): ComponentsAnswer
```

### ComponentNode

```ts
type ComponentNode = {
    type: 'heading';
    text: string;
    level?: 2 | 3 | 4 | undefined;
} | {
    type: 'text';
    text: string;
    emphasis?: 'strong' | 'subdued' | undefined;
} | {
    type: 'list';
    items: string[];
    ordered?: boolean | undefined;
} | {
    type: 'table';
    head?: string[] | undefined;
    rows: string[][];
} | {
    type: 'rating';
    value: number;
    count?: number | undefined;
    label?: string | undefined;
} | {
    type: 'badge';
    text: string;
    tone?: (typeof COMPONENT_TONES)[number] | undefined;
} | {
    type: 'image';
    src: string;
    alt: string;
    width?: number | undefined;
    height?: number | undefined;
} | {
    type: 'link';
    text: string;
    href: string;
} | {
    type: 'button_link';
    text: string;
    href: string;
} | {
    type: 'accordion';
    items: {
        title: string;
        children: ComponentNode[];
    }[];
} | {
    type: 'notice';
    text: string;
    tone?: (typeof COMPONENT_TONES)[number] | undefined;
    title?: string | undefined;
} | {
    type: 'stack';
    children: ComponentNode[];
    direction?: 'row' | 'column' | undefined;
};
```

### ComponentType

```ts
type ComponentType = ComponentNode['type'];
```

### ComponentsAnswer

```ts
type ComponentsAnswer = z.infer<typeof componentsAnswerSchema>;
```

### COMPONENTS_CONTENT_TYPE

```ts
const COMPONENTS_CONTENT_TYPE: 'application/vnd.storeware.components+json'
```

### MAX_COMPONENT_NODES

The most nodes one answer may hold, counting every child.

```ts
const MAX_COMPONENT_NODES: 200
```

### COMPONENT_IMAGE_HOSTS

The one host an image may come from. An app puts an image there with `POST /api/v1/app/assets`, which needs no scope, and uses the URL it gets.

```ts
const COMPONENT_IMAGE_HOSTS: readonly ['cdn.mystoreware.com']
```

### COMPONENT_TONES

The tones a badge or notice can take, drawn from the theme's own colours.

```ts
const COMPONENT_TONES: readonly ['neutral', 'info', 'success', 'warning', 'critical']
```

### COMPONENT_TYPES

```ts
const COMPONENT_TYPES: readonly ['heading', 'text', 'list', 'table', 'rating', 'badge', 'image', 'link', 'button_link', 'accordion', 'notice', 'stack']
```

### componentNodeSchema

```ts
const componentNodeSchema: z.ZodType<ComponentNode, unknown, z.core.$ZodTypeInternals<ComponentNode, unknown>>
```

### MAX_COMPONENT_DEPTH

The deepest a tree may nest. Enough for an accordion of stacks.

```ts
const MAX_COMPONENT_DEPTH: 4
```

### componentsAnswerSchema

What an app answers with: `\{ components: [...] \}`.

```ts
const componentsAnswerSchema: z.ZodObject<{ components: z.ZodArray<z.ZodType<ComponentNode, unknown, z.core.$ZodTypeInternals<ComponentNode, unknown>>>; }, z.core.$strict>
```
