diff --git a/app/docs/[[...slug]]/page.tsx b/app/docs/[[...slug]]/page.tsx index 0fdd824..ddfa878 100644 --- a/app/docs/[[...slug]]/page.tsx +++ b/app/docs/[[...slug]]/page.tsx @@ -26,6 +26,15 @@ import { ReferendumSelectorDemo, TrackSelectorDemo, BountySelectorDemo, + MomentDemo, + VoteThresholdDemo, + KeyValueDemo, + VectorFixedDemo, + BTreeMapDemo, + StructDemo, + TupleDemo, + VoteDemo, + CallDemo, } from "@/components/docs/demos"; import { Tab, Tabs } from "fumadocs-ui/components/tabs"; @@ -64,6 +73,15 @@ export default async function Page(props: { ReferendumSelectorDemo, TrackSelectorDemo, BountySelectorDemo, + MomentDemo, + VoteThresholdDemo, + KeyValueDemo, + VectorFixedDemo, + BTreeMapDemo, + StructDemo, + TupleDemo, + VoteDemo, + CallDemo, Tab, Tabs, }} diff --git a/components/docs/demos/advanced-demos.tsx b/components/docs/demos/advanced-demos.tsx new file mode 100644 index 0000000..2e63f66 --- /dev/null +++ b/components/docs/demos/advanced-demos.tsx @@ -0,0 +1,190 @@ +"use client"; + +import React from "react"; +import { VectorFixed } from "@/components/params/inputs/vector-fixed"; +import { BTreeMap } from "@/components/params/inputs/btree-map"; +import { Struct } from "@/components/params/inputs/struct"; +import { Text } from "@/components/params/inputs/text"; +import { Boolean } from "@/components/params/inputs/boolean"; +import { Vote } from "@/components/params/inputs/vote"; +import { Amount } from "@/components/params/inputs/amount"; +import { Card, CardContent } from "@/components/ui/card"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import Link from "next/link"; + +export function VectorFixedDemo() { + return ( +
+ {}} + /> +
+ ); +} + +export function BTreeMapDemo() { + return ( +
+ {}} + /> +
+ ); +} + +export function StructDemo() { + return ( +
+ {}} + fields={[ + { + name: "display", + label: "Display Name", + typeName: "Text", + component: ( + {}} + /> + ), + required: true, + }, + { + name: "email", + label: "Email", + typeName: "Text", + component: ( + {}} + /> + ), + }, + { + name: "verified", + label: "Verified", + typeName: "bool", + component: ( + {}} + /> + ), + }, + ]} + /> +
+ ); +} + +export function TupleDemo() { + const [values, setValues] = React.useState<[string, string]>(["", ""]); + + return ( +
+ + + + setValues((prev) => [v as string, prev[1]])} + /> + setValues((prev) => [prev[0], v as string])} + /> + + +

+ Simulated tuple layout. The actual Tuple component resolves field types from chain metadata. +

+
+ ); +} + +export function VoteDemo() { + return ( +
+ {}} + /> +
+ ); +} + +export function CallDemo() { + return ( +
+
+ + + +
+ + +
+
+ + +
+

+ The Call input requires a chain connection to populate pallets and methods.{" "} + + Visit the Builder + {" "} + to try it live. +

+
+
+
+
+ ); +} diff --git a/components/docs/demos/index.ts b/components/docs/demos/index.ts index 640eb20..3f41335 100644 --- a/components/docs/demos/index.ts +++ b/components/docs/demos/index.ts @@ -1,8 +1,9 @@ export { AccountDemo } from "./account-demo"; export { BalanceDemo } from "./balance-demo"; export { EnumDemo } from "./enum-demo"; -export { BoolDemo, TextDemo, HashDemo, BytesDemo, AmountDemo } from "./simple-demos"; +export { BoolDemo, TextDemo, HashDemo, BytesDemo, AmountDemo, MomentDemo, VoteThresholdDemo, KeyValueDemo } from "./simple-demos"; export { OptionDemo, VectorDemo } from "./composite-demos"; +export { VectorFixedDemo, BTreeMapDemo, StructDemo, TupleDemo, VoteDemo, CallDemo } from "./advanced-demos"; export { ValidatorSelectorDemo, ValidatorMultiSelectorDemo, diff --git a/components/docs/demos/simple-demos.tsx b/components/docs/demos/simple-demos.tsx index 3a2963f..0931aaa 100644 --- a/components/docs/demos/simple-demos.tsx +++ b/components/docs/demos/simple-demos.tsx @@ -1,20 +1,26 @@ "use client"; -import React from "react"; +import React, { useState } from "react"; import { Boolean } from "@/components/params/inputs/boolean"; import { Text } from "@/components/params/inputs/text"; import { Hash256 } from "@/components/params/inputs/hash"; import { Bytes } from "@/components/params/inputs/bytes"; import { Amount } from "@/components/params/inputs/amount"; +import { Moment } from "@/components/params/inputs/moment"; +import { VoteThreshold } from "@/components/params/inputs/vote-threshold"; +import { KeyValue } from "@/components/params/inputs/key-value"; export function BoolDemo() { + const [value, setValue] = useState(false); + return (
{}} + onChange={(v) => setValue(v as boolean)} />
); @@ -72,3 +78,42 @@ export function AmountDemo() { ); } + +export function MomentDemo() { + return ( +
+ {}} + /> +
+ ); +} + +export function VoteThresholdDemo() { + return ( +
+ {}} + /> +
+ ); +} + +export function KeyValueDemo() { + return ( +
+ {}} + /> +
+ ); +} diff --git a/content/docs/api/input-map.mdx b/content/docs/api/input-map.mdx index 397051d..a73d02d 100644 --- a/content/docs/api/input-map.mdx +++ b/content/docs/api/input-map.mdx @@ -54,28 +54,28 @@ The system uses a priority-based registry to match types. Higher priority patter | Priority | Component | Patterns | |----------|-----------|----------| -| 100 | Account | `AccountId`, `AccountId32`, `AccountId20`, `MultiAddress`, `Address`, `LookupSource`, `/^AccountId/`, `/^MultiAddress/` | -| 95 | Balance | `Balance`, `BalanceOf`, `Compact`, `Compact`, `/^Balance/` | -| 90 | Amount | `Compact`, `Compact`, `u128`, `u64`, `u32`, `u16`, `u8`, `i128`, `i64`, `i32`, `i16`, `i8`, `/Compact`, `/Bytes/` | -| 70 | Call | `Call`, `RuntimeCall`, `/Call$/`, `/RuntimeCall>/` | -| 65 | Moment | `Moment`, `/Moment/` | -| 60 | Vote | `Vote`, `/^Vote$/` | -| 55 | VoteThreshold | `VoteThreshold`, `/VoteThreshold/` | -| 50 | KeyValue | `KeyValue`, `/KeyValue/` | -| 45 | Option | `/^Option`, `Compact`, `/^Balance/` | +| 90 | [Amount](/docs/components/amount-input) | `Compact`, `Compact`, `u128`, `u64`, `u32`, `u16`, `u8`, `i128`, `i64`, `i32`, `i16`, `i8`, `/Compact`, `/Bytes/` | +| 70 | [Call](/docs/components/call-input) | `Call`, `RuntimeCall`, `/Call$/`, `/RuntimeCall>/` | +| 65 | [Moment](/docs/components/moment-input) | `Moment`, `/Moment/` | +| 60 | [Vote](/docs/components/vote-input) | `Vote`, `/^Vote$/` | +| 55 | [VoteThreshold](/docs/components/vote-threshold-input) | `VoteThreshold`, `/VoteThreshold/` | +| 50 | [KeyValue](/docs/components/key-value-input) | `KeyValue`, `/KeyValue/` | +| 45 | [Option](/docs/components/option-input) | `/^Option` | Balance | With denomination selector | -| `Compact`, `Compact` | Balance | Compact-wrapped balances get denomination support | -| `Compact` | Amount | Integer input | -| `u32`, `u64`, `u128` | Amount | Unsigned integers | -| `bool` | Boolean | Toggle switch | -| `H160` | Hash160 | 20-byte hex input | -| `H256`, `BlockHash` | Hash256 | 32-byte hex input | -| `H512` | Hash512 | 64-byte hex input | -| `Vec`, `Bytes` | Bytes | Hex byte array | -| `[T; N]` | VectorFixed | Fixed-length array (e.g., `[u8; 32]`) | -| `BTreeMap` | BTreeMap | Key-value pair list | -| `BTreeSet` | BTreeSet | Unique value set | -| `Vec` | Vector | Dynamic array | -| `Option` | Option | Optional with toggle | -| `(T1, T2, ...)` | Tuple | Positional elements | -| `{ field: T }` | Struct | Named fields | -| `enum { A, B }` | Enum | Variant selector | -| `Call`, `RuntimeCall` | Call | Nested extrinsic | +| `AccountId`, `AccountId32` | [Account](/docs/components/account-input) | SS58 address input | +| `MultiAddress` | [Account](/docs/components/account-input) | Supports Id, Index, Raw variants | +| `Balance`, `BalanceOf` | [Balance](/docs/components/balance-input) | With denomination selector | +| `Compact`, `Compact` | [Balance](/docs/components/balance-input) | Compact-wrapped balances get denomination support | +| `Compact` | [Amount](/docs/components/amount-input) | Integer input | +| `u32`, `u64`, `u128` | [Amount](/docs/components/amount-input) | Unsigned integers | +| `bool` | [Boolean](/docs/components/bool-input) | Toggle switch | +| `H160` | [Hash160](/docs/components/hash-input) | 20-byte hex input | +| `H256`, `BlockHash` | [Hash256](/docs/components/hash-input) | 32-byte hex input | +| `H512` | [Hash512](/docs/components/hash-input) | 64-byte hex input | +| `Vec`, `Bytes` | [Bytes](/docs/components/bytes-input) | Hex byte array | +| `[T; N]` | [VectorFixed](/docs/components/vector-fixed-input) | Fixed-length array (e.g., `[u8; 32]`) | +| `BTreeMap` | [BTreeMap](/docs/components/btree-map-input) | Key-value pair list | +| `BTreeSet` | [BTreeSet](/docs/components/vector-input) | Unique value set | +| `Vec` | [Vector](/docs/components/vector-input) | Dynamic array | +| `Option` | [Option](/docs/components/option-input) | Optional with toggle | +| `(T1, T2, ...)` | [Tuple](/docs/components/tuple-input) | Positional elements | +| `{ field: T }` | [Struct](/docs/components/struct-input) | Named fields | +| `enum { A, B }` | [Enum](/docs/components/enum-input) | Variant selector | +| `Call`, `RuntimeCall` | [Call](/docs/components/call-input) | Nested extrinsic | diff --git a/content/docs/components/btree-map-input.mdx b/content/docs/components/btree-map-input.mdx index 2f1213d..9fb4913 100644 --- a/content/docs/components/btree-map-input.mdx +++ b/content/docs/components/btree-map-input.mdx @@ -3,6 +3,28 @@ title: BTreeMap Input description: Key-value pair editor for Substrate BTreeMap types with JSON bulk entry --- + + + + + + + +```tsx +import { BTreeMap } from "@/components/params/inputs/btree-map"; + + console.log("Map:", val)} +/> +``` + + + # BTreeMap Input The BTreeMap input handles Substrate `BTreeMap` types by rendering a list of key-value pair editors. Each pair has its key and value types resolved from the chain metadata and rendered with the appropriate sub-input components. It supports both form mode for individual pair editing and a JSON mode for bulk entry. BTreeMaps appear in Substrate for configuration maps, storage deposits, and any parameter that expects an ordered key-value collection. diff --git a/content/docs/components/call-input.mdx b/content/docs/components/call-input.mdx index 1d0a586..3c2bae9 100644 --- a/content/docs/components/call-input.mdx +++ b/content/docs/components/call-input.mdx @@ -3,6 +3,27 @@ title: Call Input description: Nested extrinsic call builder for Substrate RuntimeCall parameters --- + + + + + + + +```tsx +import { Call } from "@/components/params/inputs/call"; + + console.log("Call:", val)} +/> +``` + + + # Call Input The Call input provides a nested extrinsic call builder for parameters that expect a `RuntimeCall` value. It presents pallet and method selectors followed by dynamic parameter inputs, effectively embedding a mini extrinsic builder inside a parameter field. Call inputs appear in Substrate for utility batch calls, proxy executions, multisig approvals, scheduler dispatches, and any extrinsic that wraps another call. diff --git a/content/docs/components/index.mdx b/content/docs/components/index.mdx index 6192a48..b55f3b5 100644 --- a/content/docs/components/index.mdx +++ b/content/docs/components/index.mdx @@ -1,27 +1,13 @@ --- -title: Components +title: Overview description: Substrate-aware input components for the Polkadot ecosystem --- -# Component Library +# Component Overview Relaycode ships a library of **22 input components** and **10 contextual selectors** that map directly to Substrate runtime types. Each component understands the SCALE type it represents, validates input accordingly, and emits values ready for SCALE encoding. -## Type Resolution - -Components are resolved automatically from chain metadata through a **priority-based registry**. When the extrinsic builder encounters a parameter, the `findComponent` function walks the registry from highest to lowest priority, matching the parameter's type name against registered string literals and regular expressions. - -```ts -import { findComponent } from "@/lib/input-map"; - -// Returns { component: Account, schema, typeId } -const resolved = findComponent("AccountId32", typeId, client); - -// Returns { component: Balance, schema, typeId } -const resolved = findComponent("Compact", typeId, client); -``` - -If no pattern matches, the system falls back to metadata introspection: it reads the `TypeDef` from the chain registry and routes `Enum` types to `EnumInput` and `Struct` types to `StructInput`. Any remaining unknown type falls back to a plain `TextInput`. +Components are resolved automatically through a [priority-based type resolution system](/docs/api/input-map#type-resolution). ## Available Components @@ -47,33 +33,7 @@ If no pattern matches, the system falls back to metadata introspection: it reads | [VoteThresholdInput](/docs/components/vote-threshold-input) | `VoteThreshold` | Threshold selector (SuperMajorityApprove/Against/SimpleMajority) | | [KeyValueInput](/docs/components/key-value-input) | `KeyValue` | Single key-value pair input | -## Priority System - -The registry assigns each component a numeric priority. When a type name matches multiple patterns, the highest-priority component wins. This prevents ambiguity -- for example, `Compact` (priority 95) is caught by the Balance component before the generic Amount component's `Compact<` regex (priority 90). - -| Priority | Component | -|---|---| -| 100 | AccountInput | -| 95 | BalanceInput | -| 90 | AmountInput | -| 85 | BoolInput | -| 82 | HashInput (H160) | -| 80 | HashInput (H256) | -| 78 | HashInput (H512) | -| 75 | BytesInput | -| 70 | CallInput | -| 65 | MomentInput | -| 60 | VoteInput | -| 55 | VoteThresholdInput | -| 50 | KeyValueInput | -| 45 | OptionInput | -| 43 | VectorFixedInput | -| 42 | BTreeMapInput | -| 41 | BTreeSetInput | -| 40 | VectorInput | -| 38 | TupleInput | -| 35 | StructInput | -| 30 | EnumInput | +For the full priority ordering and pattern matching details, see the [Input Map API reference](/docs/api/input-map#priority-order). ## Shared Props diff --git a/content/docs/components/key-value-input.mdx b/content/docs/components/key-value-input.mdx index bfea96f..2147917 100644 --- a/content/docs/components/key-value-input.mdx +++ b/content/docs/components/key-value-input.mdx @@ -3,6 +3,29 @@ title: KeyValue Input description: Two-field key/value pair input with automatic type resolution --- + + + + + + + +```tsx +import { KeyValue } from "@/components/params/inputs/key-value"; + + console.log("Key-Value:", pair)} +/> +``` + + + # KeyValue Input The KeyValue input renders a side-by-side key and value pair within a card. It resolves the types of both fields from chain metadata when available, falling back to plain text inputs. This component is used for `KeyValue` storage items and similar two-field structures. diff --git a/content/docs/components/moment-input.mdx b/content/docs/components/moment-input.mdx index f991658..f076548 100644 --- a/content/docs/components/moment-input.mdx +++ b/content/docs/components/moment-input.mdx @@ -3,6 +3,29 @@ title: Moment Input description: Date-time picker with quick presets for timestamp parameters --- + + + + + + + +```tsx +import { Moment } from "@/components/params/inputs/moment"; + + console.log("Timestamp:", timestamp)} +/> +``` + + + # Moment Input The Moment input provides a date-time picker for Substrate `Moment` parameters. It uses the browser's native `datetime-local` input and offers quick preset buttons for common time offsets. The selected date-time is converted to a Unix timestamp in milliseconds. diff --git a/content/docs/components/struct-input.mdx b/content/docs/components/struct-input.mdx index f4a161e..28b8885 100644 --- a/content/docs/components/struct-input.mdx +++ b/content/docs/components/struct-input.mdx @@ -3,6 +3,42 @@ title: Struct Input description: Composite field group for Substrate struct types with per-field validation --- + + + + + + + +```tsx +import { Struct } from "@/components/params/inputs/struct"; + +, + required: true, + }, + { + name: "email", + label: "Email", + typeName: "Data", + component: , + }, + ]} + onChange={(val) => console.log("Struct:", val)} +/> +``` + + + # Struct Input The Struct input renders a group of named fields inside a card, where each field has its own resolved sub-input component. Structs are Substrate's equivalent of named record types -- they appear in extrinsic parameters for multi-field configurations like `IdentityInfo`, `ProxyDefinition`, and any call argument that the metadata defines as a `Struct` TypeDef. diff --git a/content/docs/components/tuple-input.mdx b/content/docs/components/tuple-input.mdx index 093fed1..26f2aad 100644 --- a/content/docs/components/tuple-input.mdx +++ b/content/docs/components/tuple-input.mdx @@ -3,6 +3,27 @@ title: Tuple Input description: Positional element group for Substrate tuple types with auto-resolved sub-inputs --- + + + + + + + +```tsx +import { Tuple } from "@/components/params/inputs/tuple"; + + console.log("Tuple:", val)} +/> +``` + + + # Tuple Input The Tuple input handles Substrate tuple types by rendering a fixed-length group of positional sub-inputs inside a card. Each element's type is resolved from the chain metadata and rendered with the appropriate component. Tuples appear in Substrate when a parameter combines multiple values without named fields -- for example `(AccountId, Balance)` or `(u32, u32)`. diff --git a/content/docs/components/vector-fixed-input.mdx b/content/docs/components/vector-fixed-input.mdx index 6fbbeeb..58ce542 100644 --- a/content/docs/components/vector-fixed-input.mdx +++ b/content/docs/components/vector-fixed-input.mdx @@ -3,6 +3,29 @@ title: VectorFixed Input description: Fixed-length array input for Substrate [T; N] types with specialized byte array handling --- + + + + + + + +```tsx +import { VectorFixed } from "@/components/params/inputs/vector-fixed"; + + console.log("Bytes:", val)} +/> +``` + + + # VectorFixed Input The VectorFixed input handles Substrate fixed-length array types (`[T; N]`) with two rendering strategies: byte arrays (`[u8; N]`) get a specialized hex/base64 text input, while other element types render N individual sub-inputs. Fixed-length arrays appear in Substrate for cryptographic data (signatures, public keys), fixed-size identifiers, and any parameter with a compile-time known length. diff --git a/content/docs/components/vote-input.mdx b/content/docs/components/vote-input.mdx index 9637b6d..7380861 100644 --- a/content/docs/components/vote-input.mdx +++ b/content/docs/components/vote-input.mdx @@ -3,6 +3,28 @@ title: Vote Input description: Conviction voting input with Standard, Split, and SplitAbstain modes --- + + + + + + + +```tsx +import { Vote } from "@/components/params/inputs/vote"; + + console.log("Vote:", vote)} +/> +``` + + + # Vote Input The Vote input provides a full conviction voting interface for OpenGov referenda. It supports three voting modes -- Standard (single direction with conviction), Split (aye/nay balances), and SplitAbstain (aye/nay/abstain balances). It emits a properly formatted `AccountVote` enum value used by the `ConvictionVoting` pallet. diff --git a/content/docs/components/vote-threshold-input.mdx b/content/docs/components/vote-threshold-input.mdx index 611fd1a..1fe11ee 100644 --- a/content/docs/components/vote-threshold-input.mdx +++ b/content/docs/components/vote-threshold-input.mdx @@ -3,6 +3,27 @@ title: VoteThreshold Input description: Dropdown selector for referendum vote threshold types --- + + + + + + + +```tsx +import { VoteThreshold } from "@/components/params/inputs/vote-threshold"; + + console.log("Threshold:", threshold)} +/> +``` + + + # VoteThreshold Input The VoteThreshold input provides a dropdown for selecting the vote threshold type used in legacy (pre-OpenGov) referendum mechanics. It presents three options -- SuperMajorityApprove, SuperMajorityAgainst, and SimpleMajority -- as a simple select menu. diff --git a/content/docs/getting-started.mdx b/content/docs/getting-started.mdx index fedfeda..37400ed 100644 --- a/content/docs/getting-started.mdx +++ b/content/docs/getting-started.mdx @@ -18,15 +18,15 @@ Relaycode is an extrinsic builder for the Polkadot ecosystem. It provides a user ## Prerequisites -- A Polkadot-compatible wallet (Polkadot.js extension, Talisman, SubWallet, etc.) +- A Polkadot-compatible wallet ([Polkadot.js extension](https://polkadot.js.org/extension/), [Talisman](https://www.talisman.xyz/), [SubWallet](https://www.subwallet.app/), etc.) - Some DOT or testnet tokens for transaction fees ## Selecting a Chain Before connecting, choose which chain to interact with using the **Chain Selector** dropdown in the navbar: -- **Polkadot** - Mainnet (real DOT) -- **Kusama** - Canary network (real KSM) +- **Polkadot** - Mainnet (DOT) +- **Kusama** - Canary network (KSM) - **Westend** - Testnet (free test tokens, marked with "testnet" badge) For your first time, we recommend selecting **Westend** so you can experiment without spending real tokens. @@ -46,18 +46,7 @@ Once connected, you'll see your account balance and be able to select accounts f Relaycode uses a dual-pane interface: -``` -┌─────────────────────────────────┬─────────────────────────────────┐ -│ │ │ -│ FORM PANE │ HEX PANE │ -│ │ │ -│ Human-readable inputs │ SCALE-encoded call data │ -│ - Pallet selector │ - Live hex preview │ -│ - Method selector │ - Editable hex input │ -│ - Parameter inputs │ - Auto-decode on edit │ -│ │ │ -└─────────────────────────────────┴─────────────────────────────────┘ -``` +![Bidirectional editing in action](/docs/bidirectional-editing.gif) **Left Pane (Form):** Select pallets, methods, and fill in parameters using friendly input components. @@ -113,58 +102,11 @@ This hex represents your complete extrinsic call: You'll see a success message with the transaction hash once it's included in a block. -## Input Types Explained - -Relaycode provides specialized inputs for different Substrate types: - -### Account Input -For addresses and account IDs: -- Dropdown with connected accounts -- Recent address history -- Paste any valid SS58 address -- Automatic format validation - -### Balance Input -For token amounts: -- Human-readable input (e.g., "1.5") -- Denomination selector (DOT/mDOT/planck) -- Automatic conversion to planck -- Available balance display -- Existential deposit warning - -### Amount Input -For plain integers (u32, u64, u128): -- Simple numeric input -- Supports large numbers (BigInt) - -### Boolean Input -For true/false values: -- Toggle switch - -### Hash Input -For block hashes, extrinsic hashes: -- H160 (20-byte), H256 (32-byte), H512 (64-byte) -- Format and length validation - -### Vector Input -For arrays (Vec\): -- Add/remove items -- Dynamic length - -### Fixed Array Input -For fixed-length arrays (`[T; N]`): -- Fixed number of elements — no add/remove -- Each element uses the appropriate typed input - -### BTreeMap Input -For key-value maps (BTreeMap\): -- Add/remove key-value pairs -- Typed inputs for keys and values - -### Option Input -For optional values (Option\): -- Toggle to enable/disable -- Inner input when enabled +## Input Types + +Relaycode provides specialized inputs for every Substrate type. Instead of generic text fields, you get purpose-built components: account inputs with wallet integration and identicons, balance inputs with denomination switching, nested call builders for batch transactions, and more. + +See the [Component Library](/docs/components) for the full list of 22 input components and 10 contextual selectors. ## Common Extrinsics diff --git a/content/docs/guide/architecture.mdx b/content/docs/guide/architecture.mdx index 43a0033..e3d7de9 100644 --- a/content/docs/guide/architecture.mdx +++ b/content/docs/guide/architecture.mdx @@ -14,25 +14,17 @@ Relaycode is built on a layered architecture designed to cleanly separate concer The infrastructure layer handles all blockchain connectivity, client management, and wallet integration. - **Dedot Client** — Relaycode uses [Dedot](https://github.com/dedotdev/dedot) as its Polkadot client (not the deprecated `@polkadot/api`). Dedot provides type-safe chain interactions via `DedotClient`. -- **Wallet Connection** — LunoKit handles wallet integration, supporting Polkadot.js extension, Talisman, SubWallet, and other compatible wallets. -- **Chain Switching** — LunoKit's `useSwitchChain()` hook enables switching between Polkadot, Kusama, Westend, and other supported chains using genesis hash as the chain identifier. -- **React Context** — Providers expose the Dedot client, wallet state, and chain metadata to the component tree via React Context API. +- **Wallet Connection** — [LunoKit](https://lunokit.xyz) handles wallet integration, supporting [Polkadot.js extension](https://polkadot.js.org/extension/), [Talisman](https://www.talisman.xyz/), [SubWallet](https://www.subwallet.app/), and other compatible wallets. +- **Chain Switching** — [LunoKit](https://lunokit.xyz)'s `useSwitchChain()` hook enables switching between Polkadot, Kusama, Westend, and other supported chains using genesis hash as the chain identifier. +- **React Context** — Providers expose the [Dedot](https://docs.dedot.dev) client, wallet state, and chain metadata to the component tree via React Context API. ### 2. Components Layer The components layer provides reusable UI building blocks. -- **Parameter Inputs** (`components/params/inputs/`) — Specialized input components for each Substrate type (Account, Balance, Amount, Hash, Vector, etc.). +- **Parameter Inputs** — [Specialized input components](/docs/components) for each Substrate type (Account, Balance, Amount, Hash, Vector, etc.). - **Builder Components** (`components/builder/`) — The extrinsic builder panes, pallet/method selectors, and encoding controls. -- **Base UI** (`components/ui/`) — shadcn/ui components providing consistent styling and behavior. These are generated via `npx shadcn-ui add ` and should not be modified directly. - -### 3. App Layer - -The app layer handles routing, page layouts, and top-level composition. - -- **Next.js App Router** — Pages live under `app/` using Next.js 14 App Router conventions (`page.tsx`, `layout.tsx`). -- **Builder Page** (`app/builder/`) — The main extrinsic builder tool. -- **Marketing Pages** (`app/(marketing)/`) — Landing and informational pages. +- **Base UI** (`components/ui/`) — [shadcn/ui](https://ui.shadcn.com/) components providing consistent styling and behavior. These are generated via `npx shadcn-ui add ` and should not be modified directly. ## Dedot Client Integration @@ -44,7 +36,7 @@ Relaycode connects to Substrate chains exclusively through Dedot. The client pro ## Input Component Registry -The input component registry (`lib/input-map.ts`) uses a priority-based pattern matching system to map Substrate type names to the appropriate React input component. +The [input component registry](/docs/api/input-map) (`lib/input-map.ts`) uses a priority-based pattern matching system to map Substrate type names to the appropriate React input component. ### How It Works @@ -65,6 +57,8 @@ Higher priority values are checked first, ensuring more specific types take prec This ordering ensures that `Compact` matches the Balance component (priority 95) rather than the Amount component's `/Compact