import type { ReactNode } from 'react';
/** Valid built-in icon names (69 icons, Lucide-based). */
export type CxIconName = 'chevron-down' | 'chevron-right' | 'chevron-left' | 'chevron-up' | 'arrow-right' | 'arrow-left' | 'menu' | 'x' | 'plus' | 'minus' | 'check' | 'search' | 'edit' | 'trash' | 'copy' | 'download' | 'upload' | 'share' | 'external-link' | 'save' | 'refresh-cw' | 'link-2' | 'more-horizontal' | 'book-open' | 'wrench' | 'pen-line' | 'info' | 'warning' | 'error' | 'success' | 'loading' | 'bold' | 'italic' | 'underline' | 'align-left' | 'align-center' | 'align-right' | 'credit-card' | 'shopping-cart' | 'bar-chart-2' | 'bar-chart' | 'users' | 'layout-dashboard' | 'globe' | 'github' | 'eye' | 'eye-off' | 'settings' | 'user' | 'mail' | 'bell' | 'star' | 'heart' | 'home' | 'filter' | 'sun' | 'moon' | 'panel-left' | 'log-in' | 'log-out' | 'lock' | 'unlock' | 'more-vertical' | 'calendar' | 'file-text' | 'file' | 'image' | 'file-spreadsheet' | 'user-plus' | 'shield';
/**
* Icon prop type — accepts built-in icon name OR custom SVG HTML.
*
* @example Built-in
* ```tsx
*
* ```
*
* @example Custom SVG (inherits Collet size, color, a11y)
* ```tsx
*
* ```
*/
export type CxIconProp = CxIconName | (string & {});
export interface SelectOption {
value: string;
label: string;
icon?: string;
description?: string;
disabled?: boolean;
}
export interface OptionGroup {
label: string;
options: SelectOption[];
}
export interface TabItem {
value: string;
label: string;
content?: string | ReactNode;
/**
* Name of a slot to project into this panel instead of `content`.
* Put your own element in light DOM with a matching `slot` attribute — it
* keeps its event listeners and framework state. Takes precedence over
* `content`.
*/
content_slot?: string;
icon?: string;
disabled?: boolean;
}
export interface TableColumn {
id: string;
header: string;
sortable?: boolean;
width?: string;
align?: 'left' | 'center' | 'right';
visible?: boolean;
pinned?: 'left' | 'right';
resizable?: boolean;
sr_only?: boolean;
min_width?: string;
max_width?: string;
}
export interface TableCell {
text?: string;
html?: string | ReactNode;
number?: number;
/**
* Name of a slot to project into this cell. Put your own element in light DOM
* with a matching `slot` attribute — a real button with a real click handler,
* not a serialized copy of one. Takes precedence over the other fields.
*/
slot?: string;
}
export interface TableRow {
id: string;
cells: TableCell[] | Record;
disabled?: boolean;
detail?: string | ReactNode;
/** Name of a slot to project into the expansion row. Takes precedence over `detail`. */
detail_slot?: string;
expanded?: boolean;
}
export interface SortState {
column_id: string;
direction: 'asc' | 'desc' | 'ascending' | 'descending';
}
export interface PaginationConfig {
current_page: number;
page_size: number;
total_items: number;
page_size_options?: number[];
}
export interface FooterRow {
cells: Record;
}
export interface EmptyStateConfig {
title?: string;
icon?: string;
description?: string;
}
export interface AccordionItem {
id: string;
trigger_label: string;
panel_content: string | ReactNode;
/**
* Name of a slot to project into this panel instead of `panel_content`.
* Put your own element in light DOM with a matching `slot` attribute — it
* keeps its event listeners and framework state. Takes precedence over
* `panel_content`.
*/
panel_slot?: string;
icon?: string;
description?: string;
disabled?: boolean;
}
export interface MenuRadioItem {
value: string;
label: string;
icon?: string;
disabled?: boolean;
}
export interface MenuEntry {
type: 'item' | 'checkbox' | 'radio-group' | 'separator' | 'label';
id?: string;
label?: string;
icon?: string;
shortcut?: string;
disabled?: boolean;
danger?: boolean;
intent?: string;
checked?: boolean;
value?: string;
items?: MenuRadioItem[];
}
export interface SidebarNavItem {
id: string;
label: string;
href?: string;
icon?: string;
badge?: string;
active?: boolean;
disabled?: boolean;
}
export interface SidebarGroup {
label?: string;
icon?: string;
items: SidebarNavItem[];
collapsible?: boolean;
expanded?: boolean;
}
export interface BreadcrumbItem {
label: string;
href?: string;
icon?: string;
current?: boolean;
ellipsis?: boolean;
}
export interface RadioOption {
value: string;
label: string;
description?: string;
disabled?: boolean;
icon?: string;
}
export interface ToggleItem {
id: string;
label: string;
icon?: string;
icon_only?: boolean;
pressed?: boolean;
disabled?: boolean;
}
export interface SplitMenuEntry {
type: 'item' | 'separator';
id?: string;
label?: string;
icon?: string;
shortcut?: string;
intent?: string;
disabled?: boolean;
}
export interface CarouselSlide {
image_url?: string;
title: string;
badge?: string;
badge_color?: string;
subtitle?: string;
href?: string;
}
export interface CarouselDetail {
index: number;
total: number;
}
export interface SpeedDialAction {
id: string;
icon: string;
label: string;
intent?: string;
disabled?: boolean;
handler?: string;
}
/**
* A part inside a . Connections are auto-computed from array
* position. Mirrors `MessagePartConfig` in crates/wasm-api/src/message_part.rs
* field for field — the two are rendered from one table (MESSAGE_PART_FIELDS).
*/
export interface MessageGroupPart {
/** Unique part ID. Auto-generated as `{groupId}-part-{index}` if omitted. */
id?: string;
/** Part kind. Selects which renderer the part uses. */
kind: 'text' | 'tool-call' | 'tool-result' | 'thinking' | 'code-block' | 'error' | 'preview' | 'attachment';
/** Override the auto-computed connection to neighbouring parts. Usually omit this. */
connection?: 'standalone' | 'first' | 'middle' | 'last';
/** Text/code/error content. */
content?: string;
/** Pre-rendered HTML content. */
html_content?: string;
/** Tool/function name (for `tool-call` and `tool-result` kinds). */
tool_name?: string;
/** Tool arguments as a JSON string (for `tool-call` kind). */
tool_arguments?: string;
/** Tool execution status. */
tool_status?: 'pending' | 'success' | 'error';
/** Tool action type — selects the status icon. Omit for a generic tool. */
tool_action?: 'read' | 'write' | 'edit' | 'delete' | 'search';
/** Secondary description line, shown under the tool name. */
description?: string;
/** Whether a tool result renders inside a collapsible disclosure. */
collapsible?: boolean;
/** Whether the tool call has finished — drives the completed styling. */
completed?: boolean;
/** Border treatment. Accepts `auto` (default), `none`, or `subtle`. */
border?: string;
/** Label for the thinking indicator. */
thinking_label?: string;
/** Code language hint (for `code-block` kind). */
language?: string;
/** Filename shown in the `code-block` header. */
filename?: string;
/** Render `content` as GFM markdown. Requires the markdown WASM chunk. */
markdown?: boolean;
/** Size override for this part (inherits the group size if omitted). */
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
/** File name for `attachment` kind. */
attachment_name?: string;
/** File size in bytes for `attachment` kind. */
attachment_size?: number;
/** MIME type for `attachment` kind. */
attachment_type?: string;
/** Thumbnail URL (data URL or remote) for `attachment` kind. */
attachment_thumbnail?: string;
}
/** Step configuration for Stepper component. */
export interface StepperStep {
/** Unique step ID. */
id: string;
/** Step label text. */
label: string;
/** Optional description text below the label. */
description?: string;
/** Override auto-computed status (pending/active/completed/error/loading). */
status?: 'pending' | 'active' | 'completed' | 'error' | 'loading';
/** Whether this step is disabled (non-interactive). */
disabled?: boolean;
/** Whether this step is optional. */
optional?: boolean;
}
/** A single color stop in a gradient. */
export interface GradientStop {
/** CSS color value (e.g., "oklch(0.7 0.15 250)"). */
color: string;
/** Position as a fraction 0.0–1.0. */
position: number;
}
/** Gradient layer configuration. */
export interface GradientConfig {
/** Gradient shape: "linear" | "radial" | "conic" | "mesh". */
kind?: 'linear' | 'radial' | 'conic' | 'mesh';
/** Angle in degrees (used by linear and conic). */
angle?: number;
/** Color stops. At least 2 required for a visible gradient. */
stops: GradientStop[];
}
/** Noise/grain layer configuration. */
export interface NoiseConfig {
/** SVG feTurbulence baseFrequency (default 0.65). */
frequency?: number;
/** SVG feTurbulence numOctaves (default 4). */
octaves?: number;
/** SVG feTurbulence seed (default 0). */
seed?: number;
/** Layer opacity 0.0–1.0 (default 0.12). */
opacity?: number;
/** CSS mix-blend-mode for compositing. */
blend?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'soft-light' | 'color-dodge' | 'color-burn';
}
/** Texture pattern layer configuration. */
export interface TextureConfig {
/** Which texture pattern to render. */
kind?: 'paper' | 'linen' | 'halftone' | 'hatch' | 'grid' | 'scanlines' | 'checker';
/** Layer opacity 0.0–1.0 (default 0.1). */
opacity?: number;
/** Pattern repeat scale multiplier (default 1.0). */
scale?: number;
/** CSS mix-blend-mode for compositing. */
blend?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'soft-light' | 'color-dodge' | 'color-burn';
}
/** Solid color overlay with blend mode. */
export interface OverlayConfig {
/** CSS color value for the tint. */
color: string;
/** Layer opacity 0.0–1.0. */
opacity: number;
/** CSS mix-blend-mode for compositing. */
blend?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'soft-light' | 'color-dodge' | 'color-burn';
}
/** Edge-darkening vignette via radial gradient. */
export interface VignetteConfig {
/** Darkness strength 0.0–1.0 (default 0.3). */
strength?: number;
/** Inner clear-zone radius as a fraction 0.0–1.0 (default 0.5). */
radius?: number;
}
/** Detail for `cx-input` on TextInput, ChatInput, Autocomplete. */
export interface InputDetail {
value: string;
}
/** Detail for `cx-change` on Select, Autocomplete, Listbox, RadioGroup, Tabs. */
export interface SelectDetail {
value: string;
}
/** Detail for `cx-input`/`cx-change` on Checkbox, Switch. */
export interface CheckedDetail {
checked: boolean;
}
/** Detail for `cx-input` on Slider. */
export interface SliderDetail {
value: number;
}
/** Detail for `cx-change` on ToggleGroup. */
export interface ToggleDetail {
pressed: string[];
}
/** Detail for `cx-change` on Accordion. */
export interface AccordionDetail {
expanded: string[];
}
/** Detail for `cx-change` on Collapsible. */
export interface CollapsibleDetail {
open: boolean;
}
/** Detail for `cx-action` on Menu. */
export interface MenuActionDetail {
id: string;
label?: string;
}
/** Detail for `cx-change` on Menu (checkbox/radio state changes). */
export interface MenuChangeDetail {
id: string;
checked?: boolean;
value?: string;
}
/** Filter comparison operator. */
export type FilterOperator = 'contains' | 'equals' | 'starts_with' | 'ends_with' | 'gt' | 'lt' | 'gte' | 'lte' | 'is_empty' | 'is_not_empty';
/** Active filter state for a column. */
export interface FilterState {
column_id: string;
operator: FilterOperator;
value: string;
}
/** Virtual scroll configuration. */
export interface VirtualScrollConfig {
total_count: number;
render_count: number;
start_index: number;
}
/** Detail for `cx-sort` on Table. */
export interface SortDetail {
column_id: string;
direction: 'asc' | 'desc' | 'none';
/** Full multi-column sort stack (present when multi-sort is active). */
sorts?: Array<{
column_id: string;
direction: 'asc' | 'desc';
}>;
}
/** Detail for `cx-select` on Table. */
export interface TableSelectDetail {
selected: string[];
/** The row that triggered the selection change (undefined for select-all). */
row_id?: string;
}
/** Detail for `cx-expand` on Table. */
export interface TableExpandDetail {
row_id: string;
expanded: boolean;
}
/** Detail for `cx-page` on Table, Pagination. */
export interface PageDetail {
page: number;
page_size?: number;
}
/** Detail for `cx-resize` on Table. */
export interface ResizeDetail {
column_id: string;
width: number;
}
/** Detail for `cx-scroll` on Table. */
export interface ScrollDetail {
scrollTop: number;
firstVisibleRow: number;
visibleCount: number;
}
/** Detail for `cx-crush` on TopBar. Emitted when the bar enters/leaves crushed (compact) layout. */
export interface CrushDetail {
crushed: boolean;
}
/** Detail for `cx-move` on TopBar. Emitted while dragging a movable bar. */
export interface MoveDetail {
left: number;
top: number;
}
/** Detail for `cx-navigate` on Breadcrumb, Sidebar. */
export interface NavigateDetail {
href: string;
label: string;
}
/** Detail for `cx-submit` on ChatInput. Carries message value and role for MessageBubble alignment. */
export interface ChatSubmitDetail {
value: string;
role: 'user';
attachments?: FileInfo[];
}
/** Detail for `cx-file-add` on ChatInput/Chat. Emitted when files are added to the attachment tray. */
export interface FileAddDetail {
files: FileInfo[];
}
/** Detail for `cx-file-remove` on ChatInput/Chat. Emitted when files are removed. Contains remaining files. */
export interface FileRemoveDetail {
files: FileInfo[];
}
/** Detail for `cx-file-reject` on ChatInput/Chat. Emitted when a file fails validation. */
export interface FileRejectDetail {
name: string;
reason: 'size' | 'type';
}
/** Detail for `cx-scroll-end` on ScrollArea, Chat. Emitted when user scrolls to the top (load-more trigger). */
export interface ScrollEndDetail {
}
/**
* Detail for `cx-stream-end` on MessagePart. Fires when a streamed part
* finalizes. static/_behaviors/message-stream.js dispatches it with no payload,
* so this is an empty marker — typed explicitly rather than left as a bare
* CustomEvent (invariant #22).
*/
export interface StreamEndDetail {
}
/** A pre-rendered conversation turn for the Chat component. */
export interface ChatTurn {
/** Pre-rendered HTML string for the message turn. */
html: string;
}
/** Options for addUserMessage / addAssistantMessage on Chat ref. */
export interface BubbleOptions {
/** Unique ID (auto-generated if omitted). */
id?: string;
/** Render content as GFM markdown. */
markdown?: boolean;
/** Sender display name. */
senderName?: string;
/** Timestamp string (e.g. "2:34 PM"). */
timestamp?: string;
/** Visual variant. */
variant?: 'filled' | 'ghost';
/** Corner shape. */
shape?: 'rounded' | 'sharp';
/** Horizontal alignment (defaults to auto: user=end, assistant=start). */
alignment?: 'auto' | 'start' | 'end';
/** Border style. */
border?: 'auto' | 'none';
/** Size override. */
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
/** Enable entrance animation. */
animated?: boolean;
}
/**
* A part config for addGroupMessage() and ActivityOptions.items.
*
* Structurally identical to `MessageGroupPart`: chat-builders.js forwards both
* to the same Rust config, so both are rendered from MESSAGE_PART_FIELDS.
*/
export interface GroupPart {
/** Unique part ID. Auto-generated as `{groupId}-part-{index}` if omitted. */
id?: string;
/** Part kind. Selects which renderer the part uses. */
kind: 'text' | 'tool-call' | 'tool-result' | 'thinking' | 'code-block' | 'error' | 'preview' | 'attachment';
/** Override the auto-computed connection to neighbouring parts. Usually omit this. */
connection?: 'standalone' | 'first' | 'middle' | 'last';
/** Text/code/error content. */
content?: string;
/** Pre-rendered HTML content. */
html_content?: string;
/** Tool/function name (for `tool-call` and `tool-result` kinds). */
tool_name?: string;
/** Tool arguments as a JSON string (for `tool-call` kind). */
tool_arguments?: string;
/** Tool execution status. */
tool_status?: 'pending' | 'success' | 'error';
/** Tool action type — selects the status icon. Omit for a generic tool. */
tool_action?: 'read' | 'write' | 'edit' | 'delete' | 'search';
/** Secondary description line, shown under the tool name. */
description?: string;
/** Whether a tool result renders inside a collapsible disclosure. */
collapsible?: boolean;
/** Whether the tool call has finished — drives the completed styling. */
completed?: boolean;
/** Border treatment. Accepts `auto` (default), `none`, or `subtle`. */
border?: string;
/** Label for the thinking indicator. */
thinking_label?: string;
/** Code language hint (for `code-block` kind). */
language?: string;
/** Filename shown in the `code-block` header. */
filename?: string;
/** Render `content` as GFM markdown. Requires the markdown WASM chunk. */
markdown?: boolean;
/** Size override for this part (inherits the group size if omitted). */
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
/** File name for `attachment` kind. */
attachment_name?: string;
/** File size in bytes for `attachment` kind. */
attachment_size?: number;
/** MIME type for `attachment` kind. */
attachment_type?: string;
/** Thumbnail URL (data URL or remote) for `attachment` kind. */
attachment_thumbnail?: string;
}
/** Options for addGroupMessage on Chat ref. */
export interface GroupOptions {
/** Unique group ID (auto-generated if omitted). */
id?: string;
/** Sender display name. */
senderName?: string;
/** Horizontal alignment (defaults to auto: user=end, assistant=start). */
alignment?: 'auto' | 'start' | 'end';
/** Size override. */
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
/** Enable entrance animation. */
animated?: boolean;
}
/** Options for addActivity on Chat ref. */
export interface ActivityOptions {
/** Unique ID (auto-generated if omitted). */
id?: string;
/** Activity summary text. */
summary?: string;
/** Activity status. */
status?: 'running' | 'done' | 'error';
/** Tool action type. */
action?: 'read' | 'write' | 'edit' | 'delete' | 'search';
/** Size override. */
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
/** Border style. */
border?: string;
/** Start expanded. */
expanded?: boolean;
/** Pre-rendered activity part HTML strings (low-level). */
parts?: string[];
/** Structured activity sub-items — rendered through WASM automatically.
* Mutually exclusive with `parts`. When both are provided, `items` takes precedence. */
items?: GroupPart[];
}
/** Handle returned by startStreamingTurn() for incremental token streaming. */
export interface StreamHandle {
/** The turn ID. */
id: string;
/** Append streaming tokens to the turn. */
appendTokens(text: string): void;
/** End the stream. Triggers WASM re-sanitization and removes cursor. */
end(): void;
}
/** A timeline event for the MessageTimeline reducer. Each event type uses a subset of fields. */
export interface TimelineEvent {
type: 'text-delta' | 'text-done' | 'thinking-start' | 'thinking-delta' | 'thinking-done' | 'tool-call-start' | 'tool-call-done' | 'tool-result' | 'code-block' | 'error';
id?: string;
delta?: string;
content?: string;
html?: string;
label?: string;
markdown?: boolean;
group_id?: string;
call_id?: string;
result_id?: string;
tool_name?: string;
description?: string;
arguments?: string;
action?: 'generic' | 'read' | 'write' | 'edit' | 'delete' | 'search';
summary?: string;
collapsible?: boolean;
status?: 'pending' | 'success' | 'error';
code?: string;
language?: string;
filename?: string;
show_line_numbers?: boolean;
message?: string;
}
/** Detail for `cx-clear` on SearchBar. Carries the value before clear. */
export interface ClearDetail {
previousValue: string;
}
/** Detail for `cx-click` on Button, Card. */
export interface ClickDetail {
/** Original mouse event coordinates, if applicable. */
x?: number;
y?: number;
}
/** Detail for `cx-change` on FileUpload. */
export interface FileChangeDetail {
/**
* The selected files as real `File` objects — readable via
* `.text()`, `.arrayBuffer()`, or `.stream()`.
*
* `File` structurally satisfies the older `FileInfo` shape
* (`name`/`size`/`type`), so code written against that keeps compiling.
*/
files: File[];
}
/** Metadata for a selected file. */
export interface FileInfo {
name: string;
size: number;
type: string;
}
/** Detail for `cx-close` on Dialog, Drawer. */
export interface CloseDetail {
reason?: 'escape' | 'backdrop' | 'close-button';
}
/** Detail for `cx-toggle` on Sidebar. */
export interface SidebarToggleDetail {
state: 'expanded' | 'narrow';
}
/** Detail for `cx-dismiss` on Alert, Toast. */
export interface DismissDetail {
reason?: 'user' | 'timeout';
}
/** Detail for `cx-focus` / `cx-blur` on form/interactive components. */
export interface FocusDetail {
relatedTarget: EventTarget | null;
}
/** Detail for `cx-keydown` / `cx-keyup` on form/interactive components. */
export interface KeyboardDetail {
key: string;
code: string;
shiftKey: boolean;
ctrlKey: boolean;
altKey: boolean;
metaKey: boolean;
}
/**
* A single tag for TagInput.
*
* Exactly the two fields `parse_tags_from_array` reads in
* crates/wasm-api/src/tag_input.rs. There is no `id`, `icon` or `disabled` on
* the wire; a tag whose `value` is empty renders nothing at all.
*/
export interface CxTagData {
/** Unique tag value. Required — a tag with an empty value is dropped by WASM. */
value: string;
/** Display label. Falls back to `value` when empty. */
label: string;
}
/** Detail for `cx-change` on TagInput. Emitted when the tag list changes. */
export interface TagInputChangeDetail {
tags: CxTagData[];
}
/**
* Detail for `cx-dismiss` on TagInput.
*
* `removeTag()` in packages/core/src/elements/tag_input.js dispatches exactly
* `{ value }`. There is no tag object and no index on the wire — look the tag
* up in your own list by `value`.
*/
export interface TagDismissDetail {
/** The `value` of the tag that was removed. */
value: string;
}
/** A single command item inside a CommandPalette group. */
export interface CxCommandItem {
/** Unique command identifier — returned in `cx-select` detail. */
id: string;
/** Display label. */
label: string;
/** Optional icon name. */
icon?: string;
/** Optional keyboard shortcut hint. */
shortcut?: string;
/** Optional description text shown below the label. */
description?: string;
/** Whether this command is disabled. */
disabled?: boolean;
/** Navigation target — renders the item as a link. */
href?: string;
}
/** A group of commands for CommandPalette. */
export interface CxCommandGroup {
/** Group heading label. Required: it is the group's accessible name. */
label: string;
/** Command items in this group. */
items: CxCommandItem[];
}
/** Detail for `cx-select` on CommandPalette. Emitted when a command is activated. */
export interface CommandSelectDetail {
id: string;
label: string;
}
/** A node in the TreeView hierarchy. */
export interface CxTreeNode {
/** Unique node identifier — returned in selection/expand events. */
id: string;
/** Display label. */
label: string;
/** Optional icon name. */
icon?: string;
/** Whether the node is initially expanded. */
expanded?: boolean;
/** Whether the node is selected. */
selected?: boolean;
/** Whether the node is disabled (non-interactive). */
disabled?: boolean;
/** Child nodes (renders as a subtree). */
children?: CxTreeNode[];
}
/** Detail for `cx-select` on TreeView. Emitted when a node is selected or deselected. */
export interface TreeSelectDetail {
id: string;
label: string;
selected: boolean;
}
/** Detail for `cx-change` on TreeView. Emitted when a node is expanded or collapsed. */
export interface TreeChangeDetail {
id: string;
expanded: boolean;
}
/** Recursive node data for the Treemap component. */
export interface TreemapNode {
id: string;
label: string;
value: number;
intent?: 'neutral' | 'primary' | 'info' | 'success' | 'warning' | 'danger';
children?: TreemapNode[];
disabled?: boolean;
}
/** Detail for `cx-change` on Treemap. Emitted when the zoom level changes. */
export interface TreemapChangeDetail {
nodeId: string;
path: string[];
depth: number;
}
/** Detail for `cx-select` on Treemap. Emitted when a leaf cell is clicked. */
export interface TreemapSelectDetail {
id: string;
label: string;
value: number;
}
/** Detail for `cx-hover` on Treemap. Emitted on cell hover enter/leave. */
export interface TreemapHoverDetail {
id: string;
label: string;
value: number;
hasChildren: boolean;
rect?: {
x: number;
y: number;
width: number;
height: number;
};
enter: boolean;
}