Skip to content

Commit a65fc8e

Browse files
Add component examples and descriptions for 2025-07
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 097f305 commit a65fc8e

325 files changed

Lines changed: 9135 additions & 1308 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/soft-clowns-turn.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v20.19.6
1+
v20.10.0
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import {reactExtension, useApi, AdminAction, Button, TextField, Select, BlockStack} from '@shopify/ui-extensions-react/admin';
3+
4+
function App() {
5+
const {data, close} = useApi('admin.product-details.action.render');
6+
const productId = data.selected[0]?.id;
7+
8+
return (
9+
<AdminAction
10+
title="Assign warehouse location"
11+
primaryAction={
12+
<Button
13+
onPress={async () => {
14+
await fetch('/api/products/assign-warehouse', {
15+
method: 'POST',
16+
headers: {'Content-Type': 'application/json'},
17+
body: JSON.stringify({productId}),
18+
});
19+
close();
20+
}}
21+
>
22+
Assign to warehouse
23+
</Button>
24+
}
25+
secondaryAction={
26+
<Button onPress={() => close()}>Cancel</Button>
27+
}
28+
>
29+
<BlockStack gap>
30+
<TextField label="Warehouse SKU" name="warehouseSku" required />
31+
<Select
32+
label="Target warehouse"
33+
name="warehouse"
34+
options={[
35+
{label: 'East Coast — New York', value: 'nyc'},
36+
{label: 'West Coast — Los Angeles', value: 'lax'},
37+
{label: 'Central — Chicago', value: 'chi'},
38+
]}
39+
/>
40+
</BlockStack>
41+
</AdminAction>
42+
);
43+
}
44+
45+
export default reactExtension(
46+
'admin.product-details.action.render',
47+
() => <App />,
48+
);
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React, {useState, useEffect} from 'react';
2+
import {reactExtension, useApi, AdminAction, Button, Text, ProgressIndicator, BlockStack} from '@shopify/ui-extensions-react/admin';
3+
4+
function App() {
5+
const {data, close, query} = useApi('admin.product-details.action.render');
6+
const productId = data.selected[0]?.id;
7+
const [product, setProduct] = useState(null);
8+
const [loading, setLoading] = useState(true);
9+
10+
useEffect(() => {
11+
query(
12+
`query Product($id: ID!) {
13+
product(id: $id) { title status totalInventory }
14+
}`,
15+
{variables: {id: productId}},
16+
).then((result) => {
17+
setProduct(result?.data?.product);
18+
setLoading(false);
19+
});
20+
}, [productId, query]);
21+
22+
return (
23+
<AdminAction
24+
title="Product details"
25+
primaryAction={<Button onPress={() => close()}>Done</Button>}
26+
>
27+
<BlockStack gap>
28+
{loading ? (
29+
<ProgressIndicator
30+
size="small-200"
31+
accessibilityLabel="Loading product details"
32+
/>
33+
) : product ? (
34+
<>
35+
<Text fontWeight="bold">{product.title}</Text>
36+
<Text>Status: {product.status}</Text>
37+
<Text>Inventory: {product.totalInventory} units</Text>
38+
</>
39+
) : null}
40+
</BlockStack>
41+
</AdminAction>
42+
);
43+
}
44+
45+
export default reactExtension(
46+
'admin.product-details.action.render',
47+
() => <App />,
48+
);
Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,41 @@
1-
import React from 'react';
2-
import {
3-
reactExtension,
4-
AdminAction,
5-
Button,
6-
Text,
7-
} from '@shopify/ui-extensions-react/admin';
1+
import {reactExtension, useApi, AdminAction, Button, Text, BlockStack} from '@shopify/ui-extensions-react/admin';
82

93
function App() {
4+
const {data, close} = useApi('admin.product-details.action.render');
5+
const productId = data.selected[0]?.id;
6+
107
return (
118
<AdminAction
12-
title="My App Action"
9+
title="Sync to warehouse"
1310
primaryAction={
14-
<Button onPress={() => {}}>Action</Button>
11+
<Button
12+
onPress={async () => {
13+
await fetch('/api/products/sync', {
14+
method: 'POST',
15+
headers: {'Content-Type': 'application/json'},
16+
body: JSON.stringify({productId}),
17+
});
18+
close();
19+
}}
20+
>
21+
Sync product
22+
</Button>
1523
}
1624
secondaryAction={
17-
<Button onPress={() => {}}>
18-
Secondary
19-
</Button>
25+
<Button onPress={() => close()}>Cancel</Button>
2026
}
2127
>
22-
<Text>Modal content</Text>
28+
<BlockStack gap>
29+
<Text>
30+
Sync product {productId} to your warehouse management system. This
31+
will update inventory counts, pricing, and metadata.
32+
</Text>
33+
</BlockStack>
2334
</AdminAction>
2435
);
2536
}
2637

2738
export default reactExtension(
28-
'Playground',
39+
'admin.product-details.action.render',
2940
() => <App />,
3041
);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React, {useState, useEffect} from 'react';
2+
import {reactExtension, useApi, AdminBlock, Text, ProgressIndicator, BlockStack} from '@shopify/ui-extensions-react/admin';
3+
4+
function App() {
5+
const {data, query} = useApi('admin.product-details.block.render');
6+
const productId = data.selected[0]?.id;
7+
const [product, setProduct] = useState(null);
8+
const [loading, setLoading] = useState(true);
9+
10+
useEffect(() => {
11+
query(
12+
`query Product($id: ID!) {
13+
product(id: $id) { title totalInventory totalVariants }
14+
}`,
15+
{variables: {id: productId}},
16+
).then((result) => {
17+
setProduct(result?.data?.product);
18+
setLoading(false);
19+
});
20+
}, [productId, query]);
21+
22+
return (
23+
<AdminBlock title="Product analytics">
24+
<BlockStack gap>
25+
{loading ? (
26+
<ProgressIndicator size="small-200" accessibilityLabel="Loading analytics" />
27+
) : product ? (
28+
<>
29+
<Text fontWeight="bold">{product.title}</Text>
30+
<Text>Variants: {product.totalVariants}</Text>
31+
<Text>Total inventory: {product.totalInventory}</Text>
32+
</>
33+
) : null}
34+
</BlockStack>
35+
</AdminBlock>
36+
);
37+
}
38+
39+
export default reactExtension(
40+
'admin.product-details.block.render',
41+
() => <App />,
42+
);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
import {reactExtension, AdminBlock, Section, Text, Divider, BlockStack} from '@shopify/ui-extensions-react/admin';
3+
4+
function App() {
5+
6+
return (
7+
<AdminBlock title="Product specifications">
8+
<BlockStack gap>
9+
<Section heading="Compliance">
10+
<Text>CE Marking — Approved</Text>
11+
<Text>EU distribution cleared</Text>
12+
</Section>
13+
<Divider />
14+
<Section heading="Shipping">
15+
<Text>Weight: 2.5 kg</Text>
16+
<Text>Dimensions: 30 × 20 × 15 cm</Text>
17+
</Section>
18+
</BlockStack>
19+
</AdminBlock>
20+
);
21+
}
22+
23+
export default reactExtension(
24+
'admin.product-details.block.render',
25+
() => <App />,
26+
);
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
import React from 'react';
2-
import {reactExtension, AdminBlock} from '@shopify/ui-extensions-react/admin';
2+
import {reactExtension, AdminBlock, Text, Badge, InlineStack, BlockStack} from '@shopify/ui-extensions-react/admin';
33

44
function App() {
5+
56
return (
6-
<AdminBlock title="My App Block">
7-
Block content
7+
<AdminBlock title="Warehouse integration">
8+
<BlockStack gap>
9+
<InlineStack gap>
10+
<Text>Sync status:</Text>
11+
<Badge tone="success">Connected</Badge>
12+
</InlineStack>
13+
<Text>Last synced 5 minutes ago</Text>
14+
<Text>Warehouse inventory: 247 units across 3 locations</Text>
15+
</BlockStack>
816
</AdminBlock>
917
);
1018
}
1119

12-
export default reactExtension('Playground', () => <App />);
20+
export default reactExtension(
21+
'admin.product-details.block.render',
22+
() => <App />,
23+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import {reactExtension, useApi, AdminPrintAction, Text, ProgressIndicator, BlockStack} from '@shopify/ui-extensions-react/admin';
3+
4+
function App() {
5+
const {data} = useApi('admin.product-details.action.render');
6+
const productId = data.selected[0]?.id;
7+
8+
return (
9+
<AdminPrintAction
10+
src={`https://your-app.com/print/invoice?product=${productId}&type=wholesale`}
11+
>
12+
<BlockStack gap>
13+
<ProgressIndicator size="small-200" accessibilityLabel="Generating invoice" />
14+
<Text>
15+
Generating wholesale invoice with pricing and tax details...
16+
</Text>
17+
</BlockStack>
18+
</AdminPrintAction>
19+
);
20+
}
21+
22+
export default reactExtension(
23+
'admin.product-details.action.render',
24+
() => <App />,
25+
);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react';
2+
import {reactExtension, useApi, AdminPrintAction, Text, BlockStack} from '@shopify/ui-extensions-react/admin';
3+
4+
function App() {
5+
const {data} = useApi('admin.product-details.action.render');
6+
const productId = data.selected[0]?.id;
7+
const numericId = productId?.split('/').pop();
8+
9+
return (
10+
<AdminPrintAction
11+
src={`https://your-app.com/print/shipping-label?product=${numericId}&format=4x6`}
12+
>
13+
<BlockStack gap>
14+
<Text>Preparing shipping label with warehouse barcode...</Text>
15+
</BlockStack>
16+
</AdminPrintAction>
17+
);
18+
}
19+
20+
export default reactExtension(
21+
'admin.product-details.action.render',
22+
() => <App />,
23+
);

0 commit comments

Comments
 (0)