@salesforce/webapp-template-feature-react-global-search-experimental 1.112.5 → 1.112.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.a4drules/webapp-data.md +5 -5
- package/dist/.a4drules/webapp-ui.md +2 -2
- package/dist/AGENT.md +6 -10
- package/dist/CHANGELOG.md +16 -0
- package/dist/force-app/main/default/webapplications/feature-react-global-search/package.json +3 -3
- package/dist/force-app/main/default/webapplications/feature-react-global-search/src/api/graphqlClient.ts +25 -0
- package/dist/package-lock.json +2 -2
- package/dist/package.json +1 -1
- package/dist/{.a4drules/skills/using-salesforce-data → scripts}/graphql-search.sh +4 -4
- package/package.json +1 -1
- package/dist/.a4drules/skills/building-data-visualization/SKILL.md +0 -72
- package/dist/.a4drules/skills/building-data-visualization/implementation/bar-line-chart.md +0 -316
- package/dist/.a4drules/skills/building-data-visualization/implementation/dashboard-layout.md +0 -189
- package/dist/.a4drules/skills/building-data-visualization/implementation/donut-chart.md +0 -181
- package/dist/.a4drules/skills/building-data-visualization/implementation/stat-card.md +0 -150
- package/dist/.a4drules/skills/building-react-components/SKILL.md +0 -96
- package/dist/.a4drules/skills/building-react-components/implementation/component.md +0 -78
- package/dist/.a4drules/skills/building-react-components/implementation/header-footer.md +0 -132
- package/dist/.a4drules/skills/building-react-components/implementation/page.md +0 -93
- package/dist/.a4drules/skills/configuring-csp-trusted-sites/SKILL.md +0 -90
- package/dist/.a4drules/skills/configuring-csp-trusted-sites/implementation/metadata-format.md +0 -281
- package/dist/.a4drules/skills/configuring-webapp-metadata/SKILL.md +0 -158
- package/dist/.a4drules/skills/creating-webapp/SKILL.md +0 -140
- package/dist/.a4drules/skills/deploying-to-salesforce/SKILL.md +0 -226
- package/dist/.a4drules/skills/implementing-file-upload/SKILL.md +0 -396
- package/dist/.a4drules/skills/installing-webapp-features/SKILL.md +0 -210
- package/dist/.a4drules/skills/managing-agentforce-conversation-client/SKILL.md +0 -186
- package/dist/.a4drules/skills/managing-agentforce-conversation-client/references/constraints.md +0 -134
- package/dist/.a4drules/skills/managing-agentforce-conversation-client/references/examples.md +0 -132
- package/dist/.a4drules/skills/managing-agentforce-conversation-client/references/style-tokens.md +0 -101
- package/dist/.a4drules/skills/managing-agentforce-conversation-client/references/troubleshooting.md +0 -57
- package/dist/.a4drules/skills/using-salesforce-data/SKILL.md +0 -363
|
@@ -74,10 +74,10 @@ Map user intent to PascalCase names ("accounts" → `Account`), then **run the s
|
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
76
|
# From project root — look up all relevant schema info for one or more entities
|
|
77
|
-
bash
|
|
77
|
+
bash scripts/graphql-search.sh Account
|
|
78
78
|
|
|
79
79
|
# Multiple entities at once
|
|
80
|
-
bash
|
|
80
|
+
bash scripts/graphql-search.sh Account Contact Opportunity
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
The script outputs five sections per entity:
|
|
@@ -213,7 +213,7 @@ const fields = response?.data?.uiapi?.objectInfos?.[0]?.fields ?? [];
|
|
|
213
213
|
|
|
214
214
|
```bash
|
|
215
215
|
# From project root — re-check the entity that caused the error
|
|
216
|
-
bash
|
|
216
|
+
bash scripts/graphql-search.sh <EntityName>
|
|
217
217
|
```
|
|
218
218
|
|
|
219
219
|
Then fix the query using the exact names from the script output.
|
|
@@ -310,7 +310,7 @@ const response = await sdk.graphql?.(GET_CURRENT_USER);
|
|
|
310
310
|
|---------|----------|-----|
|
|
311
311
|
| `npm run graphql:schema` | webapp dir | Script in webapp's package.json |
|
|
312
312
|
| `npx eslint <file>` | webapp dir | Reads eslint.config.js |
|
|
313
|
-
| `bash
|
|
313
|
+
| `bash scripts/graphql-search.sh <Entity>` | project root | Schema lookup |
|
|
314
314
|
| `sf api request rest` | project root | Needs sfdx-project.json |
|
|
315
315
|
|
|
316
316
|
---
|
|
@@ -322,7 +322,7 @@ const response = await sdk.graphql?.(GET_CURRENT_USER);
|
|
|
322
322
|
Run the search script to get all relevant schema info in one step:
|
|
323
323
|
|
|
324
324
|
```bash
|
|
325
|
-
bash
|
|
325
|
+
bash scripts/graphql-search.sh <EntityName>
|
|
326
326
|
```
|
|
327
327
|
|
|
328
328
|
| Script Output Section | Used For |
|
|
@@ -8,9 +8,9 @@ When any task involves creating a new UI, frontend, page, dashboard, form, or us
|
|
|
8
8
|
2. The app must live under `<sfdx-source>/webapplications/<AppName>/` as a WebApplication bundle.
|
|
9
9
|
3. Do not build new UIs as LWC components, Aura components, or Visualforce pages.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
For setup from the project root, use `node scripts/setup-cli.mjs --help` and the options documented there.
|
|
12
12
|
|
|
13
13
|
## Data Access (MUST FOLLOW)
|
|
14
14
|
|
|
15
15
|
- **Never hardcode data in the app.** All data displayed in the UI must come from live Salesforce data fetching — no static arrays, mock objects, or placeholder values in production code.
|
|
16
|
-
- **
|
|
16
|
+
- **Follow `.a4drules/webapp-data.md`** before writing any data access code. All implementation must match those rules (Data SDK, supported APIs, GraphQL workflow).
|
package/dist/AGENT.md
CHANGED
|
@@ -54,22 +54,18 @@ cd <sfdx-source>/webapplications/<appName>
|
|
|
54
54
|
|
|
55
55
|
**Before finishing changes:** run `npm run build` and `npm run lint` from the web app directory; both must succeed.
|
|
56
56
|
|
|
57
|
-
## Agent
|
|
57
|
+
## Agent rules (.a4drules/)
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Markdown rules at the project root under **.a4drules/** define platform constraints:
|
|
60
60
|
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
- **Accessing Data** (`.a4drules/skills/accessing-data/`): Use for all Salesforce data fetches. Enforces Data SDK usage (`createDataSDK()` + `sdk.graphql` or `sdk.fetch`); GraphQL preferred, fetch when GraphQL is not sufficient.
|
|
64
|
-
- **Fetching REST API** (`.a4drules/skills/fetching-rest-api/`): Use when implementing Chatter, Connect REST, Apex REST, UI API REST, or Einstein LLM calls via `sdk.fetch`.
|
|
65
|
-
- **Using GraphQL** (`.a4drules/skills/using-graphql/`): Use when implementing Salesforce GraphQL queries or mutations. Sub-skills: `exploring-graphql-schema`, `generating-graphql-read-query`, `generating-graphql-mutation-query`.
|
|
66
|
-
- **Deploying to Salesforce** (`.a4drules/skills/deploying-to-salesforce/`): Use when deploying metadata, fetching GraphQL schema, or generating deploy/setup commands. Enforces deploy → permset → schema → codegen order; schema refetch after metadata deployment.
|
|
61
|
+
- **`.a4drules/webapp-ui.md`** — Salesforce Web Application UI (scaffold with `sf webapp generate`, no LWC/Aura for new UI).
|
|
62
|
+
- **`.a4drules/webapp-data.md`** — Salesforce data access (Data SDK only, supported APIs, GraphQL workflow, `scripts/graphql-search.sh` for schema lookup).
|
|
67
63
|
|
|
68
64
|
When rules refer to "web app directory" or `<sfdx-source>/webapplications/<appName>/`, resolve `<sfdx-source>` from `sfdx-project.json` and use the **actual app folder name** for this project.
|
|
69
65
|
|
|
70
66
|
## Deploying
|
|
71
67
|
|
|
72
|
-
**Deployment order:** Metadata (objects, permission sets) must be deployed before GraphQL schema fetch. After any metadata deployment, re-run `npm run graphql:schema` and `npm run graphql:codegen` from the webapp dir. **One-command setup:** `node scripts/setup-cli.mjs --target-org <alias>` runs deploy → permset → schema → codegen in the correct order.
|
|
68
|
+
**Deployment order:** Metadata (objects, permission sets) must be deployed before GraphQL schema fetch. After any metadata deployment, re-run `npm run graphql:schema` and `npm run graphql:codegen` from the webapp dir. **One-command setup:** `node scripts/setup-cli.mjs --target-org <alias>` runs deploy → permset → schema → codegen in the correct order.
|
|
73
69
|
|
|
74
70
|
From **this project root** (resolve the actual SFDX source path from `sfdx-project.json`):
|
|
75
71
|
|
|
@@ -88,4 +84,4 @@ sf project deploy start --source-dir <packageDir> --target-org <alias>
|
|
|
88
84
|
|
|
89
85
|
- **UI**: shadcn/ui + Tailwind. Import from `@/components/ui/...`.
|
|
90
86
|
- **Entry**: Keep `App.tsx` and routes in `src/`; add features as new routes or sections, don't replace the app shell but you may modify it to match the requested design.
|
|
91
|
-
- **Data (Salesforce)**:
|
|
87
|
+
- **Data (Salesforce)**: Follow `.a4drules/webapp-data.md` for all Salesforce data access. Use the Data SDK (`createDataSDK()` + `sdk.graphql` or `sdk.fetch`) — never use `fetch` or `axios` directly. GraphQL is preferred; use `sdk.fetch` when GraphQL is not sufficient.
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.112.7](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.112.6...v1.112.7) (2026-03-23)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [1.112.6](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.112.5...v1.112.6) (2026-03-23)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
## [1.112.5](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.112.4...v1.112.5) (2026-03-21)
|
|
7
23
|
|
|
8
24
|
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
package/dist/force-app/main/default/webapplications/feature-react-global-search/package.json
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@salesforce/sdk-data": "^1.112.
|
|
19
|
-
"@salesforce/webapp-experimental": "^1.112.
|
|
18
|
+
"@salesforce/sdk-data": "^1.112.7",
|
|
19
|
+
"@salesforce/webapp-experimental": "^1.112.7",
|
|
20
20
|
"@tailwindcss/vite": "^4.1.17",
|
|
21
21
|
"class-variance-authority": "^0.7.1",
|
|
22
22
|
"clsx": "^2.1.1",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@graphql-eslint/eslint-plugin": "^4.1.0",
|
|
44
44
|
"@graphql-tools/utils": "^11.0.0",
|
|
45
45
|
"@playwright/test": "^1.49.0",
|
|
46
|
-
"@salesforce/vite-plugin-webapp-experimental": "^1.112.
|
|
46
|
+
"@salesforce/vite-plugin-webapp-experimental": "^1.112.7",
|
|
47
47
|
"@testing-library/jest-dom": "^6.6.3",
|
|
48
48
|
"@testing-library/react": "^16.1.0",
|
|
49
49
|
"@testing-library/user-event": "^14.5.2",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin GraphQL client: createDataSDK + data.graphql with centralized error handling.
|
|
3
|
+
* Use with gql-tagged queries and generated operation types for type-safe calls.
|
|
4
|
+
*/
|
|
5
|
+
import { createDataSDK } from '@salesforce/sdk-data';
|
|
6
|
+
|
|
7
|
+
export async function executeGraphQL<TData, TVariables>(
|
|
8
|
+
query: string,
|
|
9
|
+
variables?: TVariables
|
|
10
|
+
): Promise<TData> {
|
|
11
|
+
const data = await createDataSDK();
|
|
12
|
+
// SDK types graphql() first param as string; at runtime it may accept gql DocumentNode too
|
|
13
|
+
const response = await data.graphql?.<TData, TVariables>(query, variables);
|
|
14
|
+
|
|
15
|
+
if (!response) {
|
|
16
|
+
throw new Error('GraphQL response is undefined');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (response?.errors?.length) {
|
|
20
|
+
const msg = response.errors.map(e => e.message).join('; ');
|
|
21
|
+
throw new Error(`GraphQL Error: ${msg}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return response.data;
|
|
25
|
+
}
|
package/dist/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
3
|
-
"version": "1.112.
|
|
3
|
+
"version": "1.112.7",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
9
|
-
"version": "1.112.
|
|
9
|
+
"version": "1.112.7",
|
|
10
10
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@lwc/eslint-plugin-lwc": "^3.3.0",
|
package/dist/package.json
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
# graphql-search.sh — Look up one or more Salesforce entities in schema.graphql.
|
|
3
3
|
#
|
|
4
4
|
# Run from the SFDX project root (where schema.graphql lives):
|
|
5
|
-
# bash
|
|
6
|
-
# bash
|
|
5
|
+
# bash scripts/graphql-search.sh Account
|
|
6
|
+
# bash scripts/graphql-search.sh Account Contact Opportunity
|
|
7
7
|
#
|
|
8
8
|
# Pass a custom schema path with -s / --schema:
|
|
9
|
-
# bash
|
|
10
|
-
# bash
|
|
9
|
+
# bash scripts/graphql-search.sh -s /path/to/schema.graphql Account
|
|
10
|
+
# bash scripts/graphql-search.sh --schema ./other/schema.graphql Account Contact
|
|
11
11
|
#
|
|
12
12
|
# Output sections per entity:
|
|
13
13
|
# 1. Type definition — all fields and relationships
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/webapp-template-feature-react-global-search-experimental",
|
|
3
|
-
"version": "1.112.
|
|
3
|
+
"version": "1.112.7",
|
|
4
4
|
"description": "Global search feature for Salesforce objects with filtering and pagination",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"author": "",
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: building-data-visualization
|
|
3
|
-
description: Adds data visualization components (charts, stat cards, KPI metrics) to React pages using Recharts. Use when the user asks to add a chart, graph, donut chart, pie chart, bar chart, stat card, KPI metric, dashboard visualization, or analytics component to the web application.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Data Visualization
|
|
7
|
-
|
|
8
|
-
## When to Use
|
|
9
|
-
|
|
10
|
-
Use this skill when:
|
|
11
|
-
- Adding charts (donut, pie, bar, line, area) to a dashboard or analytics page
|
|
12
|
-
- Displaying KPI/metric stat cards with trend indicators
|
|
13
|
-
- Building a dashboard layout with mixed chart types and summary cards
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Step 1 — Determine the visualization type
|
|
18
|
-
|
|
19
|
-
Identify what the user needs:
|
|
20
|
-
|
|
21
|
-
- **Donut / pie chart** — categorical breakdown (e.g. issue types, status distribution)
|
|
22
|
-
- **Bar chart** — comparison across categories or time periods
|
|
23
|
-
- **Line / area chart** — trends over time
|
|
24
|
-
- **Stat card** — single KPI metric with optional trend indicator
|
|
25
|
-
- **Combined dashboard** — stat cards + one or more charts
|
|
26
|
-
|
|
27
|
-
If unclear, ask:
|
|
28
|
-
|
|
29
|
-
> "What data should the chart display, and would a donut chart, bar chart, line chart, or stat cards work best?"
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Step 2 — Install dependencies
|
|
34
|
-
|
|
35
|
-
All chart types in this skill use **recharts**. Install once from the web app directory:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npm install recharts
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Recharts is built on D3 and provides declarative React components. No additional CSS is needed.
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## Step 3 — Choose implementation path
|
|
46
|
-
|
|
47
|
-
Read the corresponding guide:
|
|
48
|
-
|
|
49
|
-
- **Bar chart** — read `implementation/bar-line-chart.md` (categorical data)
|
|
50
|
-
- **Line / area chart** — read `implementation/bar-line-chart.md` (time-series data)
|
|
51
|
-
- **Donut / pie chart** — read `implementation/donut-chart.md`
|
|
52
|
-
- **Stat card with trend** — read `implementation/stat-card.md`
|
|
53
|
-
- **Dashboard layout** — read `implementation/dashboard-layout.md`
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## Verification
|
|
58
|
-
|
|
59
|
-
Before completing:
|
|
60
|
-
|
|
61
|
-
1. Chart renders with correct data and colors.
|
|
62
|
-
2. Chart is responsive (resizes with container).
|
|
63
|
-
3. Legend labels match the data categories.
|
|
64
|
-
4. Stat card trends display correct positive/negative indicators.
|
|
65
|
-
5. Run from the web app directory:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
cd force-app/main/default/webapplications/<appName> && npm run lint && npm run build
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
- **Lint:** MUST result in 0 errors.
|
|
72
|
-
- **Build:** MUST succeed.
|
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
# Bar & Line / Area Chart — Implementation Guide
|
|
2
|
-
|
|
3
|
-
Requires **recharts** (install from the web app directory; see SKILL.md Step 2).
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Data shapes
|
|
8
|
-
|
|
9
|
-
### Time-series (line / area chart)
|
|
10
|
-
|
|
11
|
-
Use when data represents a trend over time or ordered sequence.
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
interface TimeSeriesDataPoint {
|
|
15
|
-
x: string; // date or label on the x-axis
|
|
16
|
-
y: number; // numeric value
|
|
17
|
-
}
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Map raw fields to this shape: e.g. `date` → `x`, `revenue` → `y`.
|
|
21
|
-
|
|
22
|
-
### Categorical (bar chart)
|
|
23
|
-
|
|
24
|
-
Use when data compares discrete categories.
|
|
25
|
-
|
|
26
|
-
```ts
|
|
27
|
-
interface CategoricalDataPoint {
|
|
28
|
-
name: string; // category label
|
|
29
|
-
value: number; // numeric value
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Map raw fields to this shape: e.g. `product` → `name`, `sales` → `value`.
|
|
34
|
-
|
|
35
|
-
### How to decide
|
|
36
|
-
|
|
37
|
-
| Signal | Type |
|
|
38
|
-
|--------|------|
|
|
39
|
-
| "over time", "trend", date-like keys | Time-series → line chart |
|
|
40
|
-
| "by category", "by X", label-like keys | Categorical → bar chart |
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Theme colors
|
|
45
|
-
|
|
46
|
-
Pick a theme based on the data's sentiment:
|
|
47
|
-
|
|
48
|
-
| Theme | Stroke / Fill | When to use |
|
|
49
|
-
|-------|---------------|-------------|
|
|
50
|
-
| `green` | `#22c55e` | Growth, gain, positive trend |
|
|
51
|
-
| `red` | `#ef4444` | Decline, loss, negative trend |
|
|
52
|
-
| `neutral` | `#6366f1` | Default or mixed data |
|
|
53
|
-
|
|
54
|
-
Define colors as constants — do not use inline hex values.
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
const THEME_COLORS = {
|
|
58
|
-
red: "#ef4444",
|
|
59
|
-
green: "#22c55e",
|
|
60
|
-
neutral: "#6366f1",
|
|
61
|
-
} as const;
|
|
62
|
-
|
|
63
|
-
type ChartTheme = keyof typeof THEME_COLORS;
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## Line chart component
|
|
69
|
-
|
|
70
|
-
Create at `components/LineChart.tsx` (or colocate with the page):
|
|
71
|
-
|
|
72
|
-
```tsx
|
|
73
|
-
import React from "react";
|
|
74
|
-
import {
|
|
75
|
-
LineChart as RechartsLineChart,
|
|
76
|
-
Line,
|
|
77
|
-
XAxis,
|
|
78
|
-
YAxis,
|
|
79
|
-
CartesianGrid,
|
|
80
|
-
Tooltip,
|
|
81
|
-
Legend,
|
|
82
|
-
ResponsiveContainer,
|
|
83
|
-
} from "recharts";
|
|
84
|
-
|
|
85
|
-
const THEME_COLORS = {
|
|
86
|
-
red: "#ef4444",
|
|
87
|
-
green: "#22c55e",
|
|
88
|
-
neutral: "#6366f1",
|
|
89
|
-
} as const;
|
|
90
|
-
|
|
91
|
-
type ChartTheme = keyof typeof THEME_COLORS;
|
|
92
|
-
|
|
93
|
-
interface TimeSeriesDataPoint {
|
|
94
|
-
x: string;
|
|
95
|
-
y: number;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
interface TimeSeriesChartProps {
|
|
99
|
-
data: TimeSeriesDataPoint[];
|
|
100
|
-
theme?: ChartTheme;
|
|
101
|
-
title?: string;
|
|
102
|
-
className?: string;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export function TimeSeriesChart({
|
|
106
|
-
data,
|
|
107
|
-
theme = "neutral",
|
|
108
|
-
title,
|
|
109
|
-
className = "",
|
|
110
|
-
}: TimeSeriesChartProps) {
|
|
111
|
-
if (data.length === 0) {
|
|
112
|
-
return <p className="text-muted-foreground text-center py-8">No data to display</p>;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const color = THEME_COLORS[theme];
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
<div className={className}>
|
|
119
|
-
{title && (
|
|
120
|
-
<h3 className="text-sm font-medium text-primary mb-2 uppercase tracking-wide">
|
|
121
|
-
{title}
|
|
122
|
-
</h3>
|
|
123
|
-
)}
|
|
124
|
-
<ResponsiveContainer width="100%" height={300}>
|
|
125
|
-
<RechartsLineChart data={data}>
|
|
126
|
-
<CartesianGrid strokeDasharray="3 3" />
|
|
127
|
-
<XAxis dataKey="x" />
|
|
128
|
-
<YAxis />
|
|
129
|
-
<Tooltip />
|
|
130
|
-
<Legend />
|
|
131
|
-
<Line type="monotone" dataKey="y" stroke={color} strokeWidth={2} dot={false} />
|
|
132
|
-
</RechartsLineChart>
|
|
133
|
-
</ResponsiveContainer>
|
|
134
|
-
</div>
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## Bar chart component
|
|
142
|
-
|
|
143
|
-
Create at `components/BarChart.tsx` (or colocate with the page):
|
|
144
|
-
|
|
145
|
-
```tsx
|
|
146
|
-
import React from "react";
|
|
147
|
-
import {
|
|
148
|
-
BarChart as RechartsBarChart,
|
|
149
|
-
Bar,
|
|
150
|
-
XAxis,
|
|
151
|
-
YAxis,
|
|
152
|
-
CartesianGrid,
|
|
153
|
-
Tooltip,
|
|
154
|
-
Legend,
|
|
155
|
-
ResponsiveContainer,
|
|
156
|
-
} from "recharts";
|
|
157
|
-
|
|
158
|
-
const THEME_COLORS = {
|
|
159
|
-
red: "#ef4444",
|
|
160
|
-
green: "#22c55e",
|
|
161
|
-
neutral: "#6366f1",
|
|
162
|
-
} as const;
|
|
163
|
-
|
|
164
|
-
type ChartTheme = keyof typeof THEME_COLORS;
|
|
165
|
-
|
|
166
|
-
interface CategoricalDataPoint {
|
|
167
|
-
name: string;
|
|
168
|
-
value: number;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
interface CategoricalChartProps {
|
|
172
|
-
data: CategoricalDataPoint[];
|
|
173
|
-
theme?: ChartTheme;
|
|
174
|
-
title?: string;
|
|
175
|
-
className?: string;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export function CategoricalChart({
|
|
179
|
-
data,
|
|
180
|
-
theme = "neutral",
|
|
181
|
-
title,
|
|
182
|
-
className = "",
|
|
183
|
-
}: CategoricalChartProps) {
|
|
184
|
-
if (data.length === 0) {
|
|
185
|
-
return <p className="text-muted-foreground text-center py-8">No data to display</p>;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const color = THEME_COLORS[theme];
|
|
189
|
-
|
|
190
|
-
return (
|
|
191
|
-
<div className={className}>
|
|
192
|
-
{title && (
|
|
193
|
-
<h3 className="text-sm font-medium text-primary mb-2 uppercase tracking-wide">
|
|
194
|
-
{title}
|
|
195
|
-
</h3>
|
|
196
|
-
)}
|
|
197
|
-
<ResponsiveContainer width="100%" height={300}>
|
|
198
|
-
<RechartsBarChart data={data}>
|
|
199
|
-
<CartesianGrid strokeDasharray="3 3" />
|
|
200
|
-
<XAxis dataKey="name" />
|
|
201
|
-
<YAxis />
|
|
202
|
-
<Tooltip />
|
|
203
|
-
<Legend />
|
|
204
|
-
<Bar dataKey="value" fill={color} radius={[4, 4, 0, 0]} />
|
|
205
|
-
</RechartsBarChart>
|
|
206
|
-
</ResponsiveContainer>
|
|
207
|
-
</div>
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## Area chart variant
|
|
215
|
-
|
|
216
|
-
For a filled area chart (useful for volume-over-time), swap `Line` for `Area`:
|
|
217
|
-
|
|
218
|
-
```tsx
|
|
219
|
-
import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from "recharts";
|
|
220
|
-
|
|
221
|
-
<ResponsiveContainer width="100%" height={300}>
|
|
222
|
-
<AreaChart data={data}>
|
|
223
|
-
<CartesianGrid strokeDasharray="3 3" />
|
|
224
|
-
<XAxis dataKey="x" />
|
|
225
|
-
<YAxis />
|
|
226
|
-
<Tooltip />
|
|
227
|
-
<Area type="monotone" dataKey="y" stroke={color} fill={color} fillOpacity={0.2} />
|
|
228
|
-
</AreaChart>
|
|
229
|
-
</ResponsiveContainer>
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
---
|
|
233
|
-
|
|
234
|
-
## Chart container wrapper
|
|
235
|
-
|
|
236
|
-
Wrap any chart in a styled card for consistent spacing:
|
|
237
|
-
|
|
238
|
-
```tsx
|
|
239
|
-
import { Card } from "@/components/ui/card";
|
|
240
|
-
|
|
241
|
-
interface ChartContainerProps {
|
|
242
|
-
children: React.ReactNode;
|
|
243
|
-
className?: string;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export function ChartContainer({ children, className = "" }: ChartContainerProps) {
|
|
247
|
-
return (
|
|
248
|
-
<Card className={`p-4 border-gray-200 shadow-sm ${className}`}>
|
|
249
|
-
{children}
|
|
250
|
-
</Card>
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
Usage:
|
|
256
|
-
|
|
257
|
-
```tsx
|
|
258
|
-
<ChartContainer>
|
|
259
|
-
<TimeSeriesChart data={monthlyData} theme="green" title="Monthly Revenue" />
|
|
260
|
-
</ChartContainer>
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
---
|
|
264
|
-
|
|
265
|
-
## Preparing raw data
|
|
266
|
-
|
|
267
|
-
Map API responses to the expected shape before passing to the chart:
|
|
268
|
-
|
|
269
|
-
```tsx
|
|
270
|
-
const timeSeriesData = useMemo(
|
|
271
|
-
() => apiRecords.map((r) => ({ x: r.date, y: r.revenue })),
|
|
272
|
-
[apiRecords],
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
const categoricalData = useMemo(
|
|
276
|
-
() => apiRecords.map((r) => ({ name: r.product, value: r.sales })),
|
|
277
|
-
[apiRecords],
|
|
278
|
-
);
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
## Key Recharts concepts
|
|
284
|
-
|
|
285
|
-
| Component | Purpose |
|
|
286
|
-
|-----------|---------|
|
|
287
|
-
| `ResponsiveContainer` | Wraps chart to fill parent width |
|
|
288
|
-
| `CartesianGrid` | Background grid lines |
|
|
289
|
-
| `XAxis` / `YAxis` | Axis labels; `dataKey` maps to the data field |
|
|
290
|
-
| `Tooltip` | Hover info |
|
|
291
|
-
| `Legend` | Series labels |
|
|
292
|
-
| `Line` | Line series; `type="monotone"` for smooth curves |
|
|
293
|
-
| `Bar` | Bar series; `radius` rounds top corners |
|
|
294
|
-
| `Area` | Filled area; `fillOpacity` controls transparency |
|
|
295
|
-
|
|
296
|
-
---
|
|
297
|
-
|
|
298
|
-
## Accessibility
|
|
299
|
-
|
|
300
|
-
- Always include a text legend (not just colors).
|
|
301
|
-
- Chart should be wrapped in a section with a visible heading.
|
|
302
|
-
- For critical data, provide a text summary or table alternative.
|
|
303
|
-
- Use sufficient color contrast between the chart stroke/fill and background.
|
|
304
|
-
- Consider `prefers-reduced-motion` for chart animations.
|
|
305
|
-
|
|
306
|
-
---
|
|
307
|
-
|
|
308
|
-
## Common mistakes
|
|
309
|
-
|
|
310
|
-
| Mistake | Fix |
|
|
311
|
-
|---------|-----|
|
|
312
|
-
| Missing `ResponsiveContainer` | Chart won't resize; always wrap |
|
|
313
|
-
| Fixed width/height on chart | Let `ResponsiveContainer` control sizing |
|
|
314
|
-
| No empty-data handling | Show "No data" message when `data.length === 0` |
|
|
315
|
-
| Inline colors | Extract to `THEME_COLORS` constant |
|
|
316
|
-
| Using raw Recharts for every chart type | Use `DonutChart` (see `donut-chart.md`) for pie/donut |
|