Skip to main content

Extension Components

Built-in components for building extension UI. These render natively within the extension target context.

AdminBlock

A container for admin-area extensions with an optional title.

import { reactExtension, ExtensionTarget } from "@qumra/riwaq";
import { AdminBlock, TextBlock, Heading } from "@qumra/riwaq";

export default reactExtension(
ExtensionTarget.AdminProductDetails,
(api) => (
<AdminBlock title="Product Analytics">
<Heading>Performance</Heading>
<TextBlock>Views this week: 142</TextBlock>
<TextBlock>Conversion rate: 3.2%</TextBlock>
</AdminBlock>
)
);

Props

PropTypeDescription
titlestringBlock title displayed in the header.
childrenReactNodeBlock content.

AdminAction

A component for admin action extensions (buttons, panels).

import { reactExtension, ExtensionTarget } from "@qumra/riwaq";
import { AdminAction, TextBlock } from "@qumra/riwaq";

export default reactExtension(
ExtensionTarget.AdminAction,
(api) => (
<AdminAction title="Quick Edit">
<TextBlock>Edit product details inline.</TextBlock>
</AdminAction>
)
);

Props

PropTypeDescription
titlestringAction title.
childrenReactNodeAction content.

TextBlock

Render a block of text content.

import { TextBlock } from "@qumra/riwaq";

<TextBlock>This is a paragraph of text content.</TextBlock>
<TextBlock emphasis="bold">Bold text</TextBlock>
<TextBlock emphasis="italic">Italic text</TextBlock>

Props

PropTypeDefaultDescription
emphasis"bold" | "italic"--Text emphasis style.
childrenReactNode--Text content.

Heading

A heading element for section titles.

import { Heading } from "@qumra/riwaq";

<Heading>Section Title</Heading>
<Heading level={2}>Subsection Title</Heading>

Props

PropTypeDefaultDescription
level1 | 2 | 31Heading level.
childrenReactNode--Heading text.

InlineLayout

Arrange items horizontally within an extension.

import { InlineLayout, TextBlock } from "@qumra/riwaq";

<InlineLayout columns={["fill", "fill"]}>
<TextBlock>Left column</TextBlock>
<TextBlock>Right column</TextBlock>
</InlineLayout>

<InlineLayout columns={["1fr", "2fr"]}>
<TextBlock>Sidebar</TextBlock>
<TextBlock>Main content</TextBlock>
</InlineLayout>

Props

PropTypeDescription
columnsstring[]Column definitions (CSS grid values).
childrenReactNodeColumn content.

BlockSpacer

Add vertical spacing between elements.

import { BlockSpacer, TextBlock } from "@qumra/riwaq";

<TextBlock>First paragraph</TextBlock>
<BlockSpacer size="large" />
<TextBlock>Second paragraph</TextBlock>

Props

PropTypeDefaultDescription
size"small" | "medium" | "large""medium"Space size.

Divider

A horizontal line separator.

import { Divider, TextBlock } from "@qumra/riwaq";

<TextBlock>Section 1</TextBlock>
<Divider />
<TextBlock>Section 2</TextBlock>

Full Example

extensions/product-insights/src/index.tsx
import {
reactExtension,
ExtensionTarget,
useApi,
useSettings,
useSessionToken,
} from "@qumra/riwaq";
import {
AdminBlock,
Heading,
TextBlock,
InlineLayout,
Divider,
BlockSpacer,
} from "@qumra/riwaq";
import { useState, useEffect } from "react";

export default reactExtension(
ExtensionTarget.AdminProductDetails,
() => <ProductInsights />
);

function ProductInsights() {
const api = useApi();
const settings = useSettings();
const sessionToken = useSessionToken();
const [stats, setStats] = useState(null);

useEffect(() => {
async function loadStats() {
const token = await sessionToken.get();
const res = await fetch(
`https://my-app.com/api/stats/${api.resource?.id}`,
{ headers: { Authorization: `Bearer ${token}` } }
);
setStats(await res.json());
}
if (api.resource?.id) loadStats();
}, [api.resource?.id]);

return (
<AdminBlock title={settings.blockTitle as string || "Product Insights"}>
<Heading level={2}>Performance</Heading>
<InlineLayout columns={["fill", "fill", "fill"]}>
<TextBlock>Views: {stats?.views ?? "..."}</TextBlock>
<TextBlock>Orders: {stats?.orders ?? "..."}</TextBlock>
<TextBlock>Revenue: {stats?.revenue ?? "..."}</TextBlock>
</InlineLayout>
<BlockSpacer size="large" />
<Divider />
<BlockSpacer size="small" />
<TextBlock>Store: {api.store.domain}</TextBlock>
</AdminBlock>
);
}