Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,631 changes: 236 additions & 2,395 deletions packages/core/src/widgets/types.ts

Large diffs are not rendered by default.

703 changes: 703 additions & 0 deletions packages/core/src/widgets/types/advanced.ts

Large diffs are not rendered by default.

1,035 changes: 1,035 additions & 0 deletions packages/core/src/widgets/types/base.ts

Large diffs are not rendered by default.

145 changes: 145 additions & 0 deletions packages/core/src/widgets/types/forms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import type { FocusConfig } from "../../focus/styles.js";
import type { WidgetSize, WidgetTone, WidgetVariant } from "../../ui/designTokens.js";
import type { TextStyle } from "../style.js";
import type { VNode } from "../types.js";

/* ========== Form Widgets (GitHub issue #119) ========== */

/** Option for select and radio group widgets. */
export type SelectOption = Readonly<{
/** Option value used in form state. */
value: string;
/** Display label for the option. */
label: string;
/** Whether this option is disabled. */
disabled?: boolean;
}>;

/** Props for field wrapper widget. Wraps an input with label, error, and hint. */
export type FieldProps = Readonly<{
key?: string;
/** Field label displayed above the input. */
label: string;
/** Error message to display below the input. */
error?: string;
/** Whether the field is required (shows asterisk). */
required?: boolean;
/** Help text displayed below the input. */
hint?: string;
/** The wrapped input widget. */
children: VNode;
}>;
Comment on lines +18 to +31
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Keep a single source of truth for field children.

FieldProps stores children, but Line 306 of packages/core/src/widgets/types.ts already models kind: "field" with a separate children array. The split leaves two competing places for the wrapped control, which makes the canonical contract internally inconsistent. Based on learnings, "Canonical API: preserve prop/callback names and signatures; these are the source of truth for widget contracts."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/widgets/types/forms.ts` around lines 18 - 31, FieldProps
currently duplicates the wrapped control by including children; remove the
children property from FieldProps so the canonical children array on the widget
union (the kind: "field" case in widgets/types.ts) is the single source of
truth. Update any code that referenced FieldProps.children to read the control
from the widget-level children array (the "field" variant in widgets/types.ts),
adjust imports/types where FieldProps was used, and ensure remaining
FieldProps-only fields (label, error, required, hint) remain unchanged and
readonly.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified against origin/main and the current widget implementation. FieldProps.children is part of the existing public contract, and the current factory / JSX wrapper / createFieldVNode implementation all use it to populate the widget-level children array. Removing it here would be a real API change, not a split-only fix, so I’m preserving the existing contract in this PR.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RtlZeroMemory, understood — thanks for verifying this against origin/main. The FieldProps.childrencreateFieldVNode → widget-level children array pipeline makes the design clear: FieldProps.children is the public input surface, not a duplicate. Preserving it as-is in this split-only PR is the right call. I'll withdraw my concern.

(  ´・‿・`) ~♡


✏️ Learnings added
Learnt from: RtlZeroMemory
Repo: RtlZeroMemory/Rezi PR: 277
File: packages/core/src/widgets/types/forms.ts:18-31
Timestamp: 2026-03-17T05:02:50.762Z
Learning: In `packages/core/src/widgets/types/forms.ts`, `FieldProps.children: VNode` is part of the existing public API contract. The factory (`createFieldVNode`), JSX wrapper, and other implementations consume `FieldProps.children` and use it to populate the widget-level `children` array for `kind: "field"`. It is the public input surface and must not be removed — doing so would be a breaking API change, not a refactor.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-23T06:10:40.638Z
Learning: Applies to **/*.{ts,tsx} : Use `ui.field()` wrapper for form fields to automatically provide label, error display, and hint text — never render bare inputs

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Wrap form inputs with `ui.field` to provide label/hint/error context.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Group related form fields with `ui.form` as the container.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Use `defineWidget` for reusable stateful components that need composition context.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Applies to {packages/core/src/widgets/ui.ts,packages/core/src/widgets/types.ts} : Canonical API: preserve prop/callback names and signatures; these are the source of truth for widget contracts

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-23T06:10:40.638Z
Learning: Applies to **/*.{ts,tsx} : Use `defineWidget()` for all reusable, stateful components — pass state via props, manage internal state with `ctx.useState()`

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Applies to packages/core/src/widgets/{ui.ts,types.ts,composition.ts,protocol.ts} : Treat `ui.ts`, `types.ts`, `composition.ts`, and `protocol.ts` as canonical widget factory, prop contracts, and callback signatures that must be preserved; these are safe modification zones

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Interactive widgets require unique `id` values within their scope.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-23T06:10:40.638Z
Learning: Applies to **/*.{ts,tsx} : Always use `ui.*` factory functions for widget construction (ui.button, ui.text, ui.panel, etc.) — never construct raw VNode objects with `{ kind: ..., props: ... }`

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Use semantic widgets (`ui.status`, `ui.badge`, `ui.tag`, `ui.callout`, `ui.spinner`, `ui.progress`) instead of custom text-based status constructs.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Applies to **/*.{ts,tsx} : Avoid: importing from internal paths instead of package exports; missing id on interactive widgets; conditional hook execution; in-place mutation of app state; duplicate widget IDs in one tree

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Applies to packages/jsx/src/{components.ts,types.ts,createElement.ts,index.ts} : Maintain JSX parity with core widget API changes; update JSX components, types, and creation functions whenever core widget APIs change

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-25T05:07:29.435Z
Learning: Applies to **/*.{ts,tsx} : Duplicate interactive widget IDs are fatal and will throw ZRUI_DUPLICATE_ID error

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-23T06:10:40.638Z
Learning: Applies to **/*.{ts,tsx} : All interactive widgets MUST have a unique `id` prop to ensure proper focus management and event routing

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-25T05:07:29.435Z
Learning: Applies to **/*.{ts,tsx} : All interactive widgets MUST have a unique `id` prop

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Use `ui.*` factories for widget construction instead of manually creating components.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Read exploration order: packages/core/src/index.ts → packages/core/src/widgets/ui.ts → packages/core/src/widgets/types.ts → packages/core/src/widgets/composition.ts → packages/create-rezi/templates/ → packages/core/src/**/__tests__/

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Prefer semantic variants/intents over manual style-only distinctions for widget appearance.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Risk triage: docs-only updates (low risk) need lint/grep validation; widget prop renames (medium risk) need compile + affected tests + docs parity; runtime/router/reconcile/layout/drawlist changes (high risk) need full test suite + integration coverage + PTY evidence

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Keep layout tokens and theme tokens semantic; do not hardcode RGB/hex literals in app widgets.

Learnt from: RtlZeroMemory
Repo: RtlZeroMemory/Rezi PR: 216
File: scripts/drawlist-spec.ts:1-3
Timestamp: 2026-02-26T10:29:26.658Z
Learning: In the Rezi project, public API references and documentation must consistently use the current public protocol version (v1) after the reset, and must not reference the old v6 iteration. Review tests, scripts, and docs (including scripts/drawlist-spec.ts) to replace any v6 mentions with v1, and add a short note in release/docs where protocol versions are referenced to reflect the reset.


/** Props for select dropdown widget. */
export type SelectProps = Readonly<{
id: string;
key?: string;
/** Opt out of Tab focus order while keeping id-based routing available. */
focusable?: boolean;
/** Optional semantic label used for accessibility/debug announcements. */
accessibleLabel?: string;
/** Currently selected value. */
value: string;
/** Available options. */
options: readonly SelectOption[];
/** Callback when selection changes. */
onChange?: (value: string) => void;
/** Whether the select is disabled. */
disabled?: boolean;
/** Placeholder text when no value is selected. */
placeholder?: string;
/** Whether to show the select in an error state. */
error?: boolean;
/** Optional focus appearance configuration. */
focusConfig?: FocusConfig;
/** Design system: visual variant (reserved for future select recipes). */
dsVariant?: WidgetVariant;
/** Design system: tone (reserved for future select recipes). */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;

/** Props for slider widget. */
export type SliderProps = Readonly<{
id: string;
key?: string;
/** Opt out of Tab focus order while keeping id-based routing available. */
focusable?: boolean;
/** Optional semantic label used for accessibility/debug announcements. */
accessibleLabel?: string;
/** Current slider value. */
value: number;
/** Minimum value (default: 0). */
min?: number;
/** Maximum value (default: 100). */
max?: number;
/** Step increment for keyboard changes (default: 1). */
step?: number;
/** Optional fixed track width in cells (default: fills available width). */
width?: number;
/** Optional label shown before the track. */
label?: string;
/** Show numeric value text (default: true). */
showValue?: boolean;
/** Callback when value changes. */
onChange?: (value: number) => void;
/** Whether the slider is disabled. */
disabled?: boolean;
/** Whether the slider is read-only (focusable but non-editable). */
readOnly?: boolean;
/** Optional style applied to label/value text. */
style?: TextStyle;
/** Optional focus appearance configuration. */
focusConfig?: FocusConfig;
}>;

/** Props for checkbox widget. */
export type CheckboxProps = Readonly<{
id: string;
key?: string;
/** Opt out of Tab focus order while keeping id-based routing available. */
focusable?: boolean;
/** Optional semantic label used for accessibility/debug announcements. */
accessibleLabel?: string;
/** Whether the checkbox is checked. */
checked: boolean;
/** Label displayed next to the checkbox. */
label?: string;
/** Callback when checked state changes. */
onChange?: (checked: boolean) => void;
/** Whether the checkbox is disabled. */
disabled?: boolean;
/** Optional focus appearance configuration. */
focusConfig?: FocusConfig;
/** Design system: tone for checked/focus rendering. */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;

/** Props for radio group widget. */
export type RadioGroupProps = Readonly<{
id: string;
key?: string;
/** Opt out of Tab focus order while keeping id-based routing available. */
focusable?: boolean;
/** Optional semantic label used for accessibility/debug announcements. */
accessibleLabel?: string;
/** Currently selected value. */
value: string;
/** Available options. */
options: readonly SelectOption[];
/** Callback when selection changes. */
onChange?: (value: string) => void;
/** Layout direction. */
direction?: "horizontal" | "vertical";
/** Whether the radio group is disabled. */
disabled?: boolean;
/** Optional focus appearance configuration. */
focusConfig?: FocusConfig;
/** Design system: tone for selected/focus rendering. */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;
93 changes: 93 additions & 0 deletions packages/core/src/widgets/types/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import type { WidgetSize, WidgetTone, WidgetVariant } from "../../ui/designTokens.js";
import type { VNode } from "../types.js";

/* ========== Navigation Widgets ========== */

/** Tabs visual style variant. */
export type TabsVariant = "line" | "enclosed" | "pills";

/** Tabs bar position relative to content. */
export type TabsPosition = "top" | "bottom";

/** Tab item descriptor. */
export type TabsItem = Readonly<{
key: string;
label: string;
content: VNode;
}>;

/** Props for tabs widget. */
export type TabsProps = Readonly<{
id: string;
key?: string;
tabs: readonly TabsItem[];
activeTab: string;
onChange: (key: string) => void;
variant?: TabsVariant;
position?: TabsPosition;
/** Design system: visual variant. */
dsVariant?: WidgetVariant;
/** Design system: color tone. */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;

/** Accordion item descriptor. */
export type AccordionItem = Readonly<{
key: string;
title: string;
content: VNode;
}>;

/** Props for accordion widget. */
export type AccordionProps = Readonly<{
id: string;
key?: string;
items: readonly AccordionItem[];
expanded: readonly string[];
onChange: (expanded: readonly string[]) => void;
allowMultiple?: boolean;
/** Design system: visual variant. */
dsVariant?: WidgetVariant;
/** Design system: color tone. */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;

/** Breadcrumb item descriptor. */
export type BreadcrumbItem = Readonly<{
label: string;
onPress?: () => void;
}>;

/** Props for breadcrumb widget. */
export type BreadcrumbProps = Readonly<{
id?: string;
key?: string;
items: readonly BreadcrumbItem[];
separator?: string;
/** Design system: visual variant. */
dsVariant?: WidgetVariant;
/** Design system: color tone. */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;
Comment on lines +59 to +77
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Actionable breadcrumbs need a stable widget id.

Once any BreadcrumbItem uses onPress, this widget becomes interactive, but BreadcrumbProps still leaves id optional. That leaves no stable routing/focus anchor for keyboard-reachable crumbs. As per coding guidelines, "Interactive widgets require unique id values within their scope." and "Every action must be keyboard reachable; modal overlays must support close with Escape; menus/dropdowns must support arrow navigation."

Suggested fix
 export type BreadcrumbProps = Readonly<{
-  id?: string;
+  id: string;
   key?: string;
   items: readonly BreadcrumbItem[];
   separator?: string;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/** Breadcrumb item descriptor. */
export type BreadcrumbItem = Readonly<{
label: string;
onPress?: () => void;
}>;
/** Props for breadcrumb widget. */
export type BreadcrumbProps = Readonly<{
id?: string;
key?: string;
items: readonly BreadcrumbItem[];
separator?: string;
/** Design system: visual variant. */
dsVariant?: WidgetVariant;
/** Design system: color tone. */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;
/** Breadcrumb item descriptor. */
export type BreadcrumbItem = Readonly<{
label: string;
onPress?: () => void;
}>;
/** Props for breadcrumb widget. */
export type BreadcrumbProps = Readonly<{
id: string;
key?: string;
items: readonly BreadcrumbItem[];
separator?: string;
/** Design system: visual variant. */
dsVariant?: WidgetVariant;
/** Design system: color tone. */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked the existing implementation before changing anything. BreadcrumbProps.id is already optional on origin/main, and the widget generates a stable internal id when omitted (see createBreadcrumbWidgetVNode using ctx.id("breadcrumb")). Requiring id here would widen this PR beyond a mechanical modularization, so I’m not changing that contract in this branch.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RtlZeroMemory, understood — thanks for checking the existing implementation. Since createBreadcrumbWidgetVNode calls ctx.id("breadcrumb") to synthesize a stable internal ID when none is supplied, the interactive-widget-needs-id invariant is satisfied at the implementation level rather than the type level. This is a reasonable pattern and keeping id?: string is the correct call for a pure modularization PR. I'll withdraw the suggestion.

I'm recording this pattern for future reviews.


✏️ Learnings added
Learnt from: RtlZeroMemory
Repo: RtlZeroMemory/Rezi PR: 277
File: packages/core/src/widgets/types/navigation.ts:59-77
Timestamp: 2026-03-17T05:02:59.105Z
Learning: In the Rezi project (`packages/core/src/widgets/`), `BreadcrumbProps.id` is intentionally optional. The widget implementation `createBreadcrumbWidgetVNode` auto-generates a stable internal ID via `ctx.id("breadcrumb")` when no explicit `id` is provided. Do not flag the optional `id` on `BreadcrumbProps` as a missing interactive-widget ID — the contract is fulfilled at the implementation level.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Applies to packages/core/src/widgets/{ui.ts,types.ts,composition.ts,protocol.ts} : Treat `ui.ts`, `types.ts`, `composition.ts`, and `protocol.ts` as canonical widget factory, prop contracts, and callback signatures that must be preserved; these are safe modification zones

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Applies to {packages/core/src/widgets/ui.ts,packages/core/src/widgets/types.ts} : Canonical API: preserve prop/callback names and signatures; these are the source of truth for widget contracts

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Use `defineWidget` for reusable stateful components that need composition context.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Read exploration order: packages/core/src/index.ts → packages/core/src/widgets/ui.ts → packages/core/src/widgets/types.ts → packages/core/src/widgets/composition.ts → packages/create-rezi/templates/ → packages/core/src/**/__tests__/

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Prefer semantic variants/intents over manual style-only distinctions for widget appearance.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-23T06:10:40.638Z
Learning: Applies to **/*.{ts,tsx} : Always use `ui.*` factory functions for widget construction (ui.button, ui.text, ui.panel, etc.) — never construct raw VNode objects with `{ kind: ..., props: ... }`

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Applies to **/*.{ts,tsx} : Avoid: importing from internal paths instead of package exports; missing id on interactive widgets; conditional hook execution; in-place mutation of app state; duplicate widget IDs in one tree

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Use `ui.*` factories for widget construction instead of manually creating components.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Use semantic widgets (`ui.status`, `ui.badge`, `ui.tag`, `ui.callout`, `ui.spinner`, `ui.progress`) instead of custom text-based status constructs.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-23T06:10:40.638Z
Learning: Applies to **/*.{ts,tsx} : Use `defineWidget()` for all reusable, stateful components — pass state via props, manage internal state with `ctx.useState()`

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-23T06:10:40.638Z
Learning: Applies to **/*.{ts,tsx} : All interactive widgets MUST have a unique `id` prop to ensure proper focus management and event routing

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Interactive widgets require unique `id` values within their scope.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-25T05:07:29.435Z
Learning: Applies to **/*.{ts,tsx} : All interactive widgets MUST have a unique `id` prop

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Every interactive widget must define a unique `id` within its scope; duplicate IDs are fatal.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-25T05:07:29.435Z
Learning: Applies to **/*.{ts,tsx} : Duplicate interactive widget IDs are fatal and will throw ZRUI_DUPLICATE_ID error

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Risk triage: docs-only updates (low risk) need lint/grep validation; widget prop renames (medium risk) need compile + affected tests + docs parity; runtime/router/reconcile/layout/drawlist changes (high risk) need full test suite + integration coverage + PTY evidence

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Use `accessibleLabel` when visual labels are ambiguous or missing from interactive widgets.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Use `ui.focusZone` for custom local navigation groups instead of manual focus management.

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-03T10:00:48.227Z
Learning: Applies to packages/jsx/src/{components.ts,types.ts,createElement.ts,index.ts} : Maintain JSX parity with core widget API changes; update JSX components, types, and creation functions whenever core widget APIs change

Learnt from: CR
Repo: RtlZeroMemory/Rezi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-06T10:44:56.248Z
Learning: Applies to **/*.{ts,tsx} : Keep layout tokens and theme tokens semantic; do not hardcode RGB/hex literals in app widgets.

Learnt from: RtlZeroMemory
Repo: RtlZeroMemory/Rezi PR: 216
File: scripts/drawlist-spec.ts:1-3
Timestamp: 2026-02-26T10:29:26.658Z
Learning: In the Rezi project, public API references and documentation must consistently use the current public protocol version (v1) after the reset, and must not reference the old v6 iteration. Review tests, scripts, and docs (including scripts/drawlist-spec.ts) to replace any v6 mentions with v1, and add a short note in release/docs where protocol versions are referenced to reflect the reset.


/** Props for pagination widget. */
export type PaginationProps = Readonly<{
id: string;
key?: string;
page: number;
totalPages: number;
onChange: (page: number) => void;
showFirstLast?: boolean;
/** Design system: visual variant. */
dsVariant?: WidgetVariant;
/** Design system: color tone. */
dsTone?: WidgetTone;
/** Design system: size preset. */
dsSize?: WidgetSize;
}>;
Loading
Loading