@grampro/kit 2.7.1 → 2.7.3
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/.gbs/skills/gbs-components/SKILL.md +233 -207
- package/.gbs/skills/gbs-components/references/data-grid.md +9 -0
- package/.gbs/skills/gbs-components/references/forms.md +12 -0
- package/.gbs/skills/gbs-components/references/install.md +42 -5
- package/CHANGELOG.md +963 -798
- package/README.md +13 -4
- package/index.cjs +250 -138
- package/package.json +1 -1
- package/source/components/accordion/passport.json +1 -1
- package/source/components/alert/passport.json +1 -1
- package/source/components/avatar/passport.json +1 -1
- package/source/components/badge/passport.json +1 -1
- package/source/components/breadcrumb/passport.json +1 -1
- package/source/components/button/passport.json +1 -1
- package/source/components/card/passport.json +1 -1
- package/source/components/checkbox/passport.json +2 -2
- package/source/components/checkbox/passport.manual.json +1 -1
- package/source/components/checkbox/react/Checkbox.tsx +14 -0
- package/source/components/combobox/passport.json +3 -2
- package/source/components/combobox/passport.manual.json +1 -1
- package/source/components/combobox/react/MultiSelect.tsx +13 -0
- package/source/components/combobox/react/Select.tsx +13 -0
- package/source/components/combobox/react/surface.ts +70 -0
- package/source/components/data-grid/passport.json +6 -6
- package/source/components/data-grid/react/DataGrid.tsx +353 -351
- package/source/components/date-picker/passport.json +3 -2
- package/source/components/date-picker/passport.manual.json +1 -1
- package/source/components/date-picker/react/DatePicker.tsx +16 -2
- package/source/components/date-picker/react/DateRangePicker.tsx +16 -2
- package/source/components/date-picker/react/surface.ts +68 -0
- package/source/components/dialog/passport.json +1 -1
- package/source/components/file-uploader/passport.json +1 -1
- package/source/components/input/passport.json +2 -2
- package/source/components/input/passport.manual.json +1 -1
- package/source/components/input/react/Input.tsx +21 -0
- package/source/components/menu/passport.json +1 -1
- package/source/components/modal/passport.json +1 -1
- package/source/components/number-input/passport.json +2 -2
- package/source/components/number-input/passport.manual.json +1 -1
- package/source/components/number-input/react/NumberInput.tsx +30 -0
- package/source/components/popover/passport.json +1 -1
- package/source/components/progress/passport.json +1 -1
- package/source/components/radio-group/passport.json +2 -2
- package/source/components/radio-group/passport.manual.json +1 -1
- package/source/components/radio-group/react/RadioGroup.tsx +33 -0
- package/source/components/shared/core/agent/field-executors.ts +173 -137
- package/source/components/shared/core/agent/index.ts +21 -0
- package/source/components/shared/core/agent/surface.ts +437 -0
- package/source/components/shared/core/agent/webmcp.ts +332 -328
- package/source/components/shared/core/agent/write.ts +62 -58
- package/source/components/shared/index.ts +7 -0
- package/source/components/shared/react/AgentSurface.tsx +145 -0
- package/source/components/shared/react/agentSurfaceContext.ts +92 -0
- package/source/components/shared/react/useFieldAgent.ts +62 -88
- package/source/components/shared/version.json +4 -4
- package/source/components/shared/version.ts +6 -6
- package/source/components/skeleton/passport.json +1 -1
- package/source/components/spinner/passport.json +1 -1
- package/source/components/switch/passport.json +2 -2
- package/source/components/switch/passport.manual.json +1 -1
- package/source/components/switch/react/Switch.tsx +16 -0
- package/source/components/tabs/passport.json +1 -1
- package/source/components/textarea/passport.json +2 -2
- package/source/components/textarea/passport.manual.json +1 -1
- package/source/components/textarea/react/Textarea.tsx +16 -0
- package/source/components/toaster/passport.json +1 -1
- package/source/components/tooltip/passport.json +1 -1
- package/tools/doctor/baseline.cjs +228 -0
- package/tools/doctor/contract.cjs +252 -0
- package/tools/doctor/format.cjs +160 -0
- package/tools/doctor/index.cjs +246 -0
- package/tools/doctor/usage.cjs +95 -0
- package/tools/jsx-tags.cjs +120 -0
- package/tools/mcp/server.cjs +60 -41
- package/tools/passport/extract.cjs +22 -40
- package/tools/passport/hash.cjs +56 -0
- package/tools/passport/index.cjs +4 -2
- package/tools/passport/typescript.cjs +220 -0
- package/tools/prompt.cjs +205 -0
- package/tools/ui.cjs +67 -0
|
@@ -1,207 +1,233 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: gbs-components
|
|
3
|
-
description: Builds UI with the GramproKit component library (@grampro/kit). Use when adding or changing UI in apps that have a component-lib/ folder.
|
|
4
|
-
autoAttach: ["src/**/*.tsx", "src/**/*.jsx", "app/**/*.tsx", "components/**/*.tsx"]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# GBS components (2.x)
|
|
8
|
-
|
|
9
|
-
## If the MCP server is connected
|
|
10
|
-
|
|
11
|
-
This file is a summary. The `grampro` MCP server answers from passports
|
|
12
|
-
generated from the component source, so where the two differ it is right
|
|
13
|
-
and this is stale. When its tools are available:
|
|
14
|
-
|
|
15
|
-
- **`get_component <Name>`** before writing a component — every prop with
|
|
16
|
-
its type, the values a union accepts, which props are required, handler
|
|
17
|
-
signatures. Do not write a prop you have not read there.
|
|
18
|
-
- **`validate_usage`** on the JSX before reporting back. It catches props
|
|
19
|
-
invented from memory, which is the one failure a passport cannot prevent.
|
|
20
|
-
- **`figma_frame`** to read a design, from a `designFile` path or a Figma
|
|
21
|
-
URL, when building from one.
|
|
22
|
-
|
|
23
|
-
Neither needs the other installed. Without the server this file is what
|
|
24
|
-
you have, and everything below still applies.
|
|
25
|
-
## Install before you import
|
|
26
|
-
|
|
27
|
-
Not an npm dependency — the CLI **copies source into the repo**:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
npx @grampro/kit add Button,Input,Modal
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Writes `component-lib/<folder>/` plus `component-lib/shared/`. No flag is
|
|
34
|
-
needed: the 2.x components are the default.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
`
|
|
70
|
-
|
|
71
|
-
`
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
`
|
|
75
|
-
|
|
76
|
-
`
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
`
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
import {
|
|
116
|
-
import {
|
|
117
|
-
import {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
import {
|
|
157
|
-
|
|
158
|
-
<
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
1
|
+
---
|
|
2
|
+
name: gbs-components
|
|
3
|
+
description: Builds UI with the GramproKit component library (@grampro/kit). Use when adding or changing UI in apps that have a component-lib/ folder.
|
|
4
|
+
autoAttach: ["src/**/*.tsx", "src/**/*.jsx", "app/**/*.tsx", "components/**/*.tsx"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# GBS components (2.x)
|
|
8
|
+
|
|
9
|
+
## If the MCP server is connected
|
|
10
|
+
|
|
11
|
+
This file is a summary. The `grampro` MCP server answers from passports
|
|
12
|
+
generated from the component source, so where the two differ it is right
|
|
13
|
+
and this is stale. When its tools are available:
|
|
14
|
+
|
|
15
|
+
- **`get_component <Name>`** before writing a component — every prop with
|
|
16
|
+
its type, the values a union accepts, which props are required, handler
|
|
17
|
+
signatures. Do not write a prop you have not read there.
|
|
18
|
+
- **`validate_usage`** on the JSX before reporting back. It catches props
|
|
19
|
+
invented from memory, which is the one failure a passport cannot prevent.
|
|
20
|
+
- **`figma_frame`** to read a design, from a `designFile` path or a Figma
|
|
21
|
+
URL, when building from one.
|
|
22
|
+
|
|
23
|
+
Neither needs the other installed. Without the server this file is what
|
|
24
|
+
you have, and everything below still applies.
|
|
25
|
+
## Install before you import
|
|
26
|
+
|
|
27
|
+
Not an npm dependency — the CLI **copies source into the repo**:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx @grampro/kit add Button,Input,Modal
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Writes `component-lib/<folder>/` plus `component-lib/shared/`. No flag is
|
|
34
|
+
needed: the 2.x components are the default. A component the project has
|
|
35
|
+
edited is never overwritten — if `add` says it kept one, tell the user and
|
|
36
|
+
suggest `npx @grampro/kit doctor <Component>`; **never retry with `--force`**,
|
|
37
|
+
which discards their work. Import the barrel in your component:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { Button } from "component-lib/button";
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Styles are **one line** in the global CSS (Vite: `src/index.css`), never in a
|
|
44
|
+
component file. The CLI generates `component-lib/gbs.css` listing every
|
|
45
|
+
stylesheet you installed, and rewrites it on each install:
|
|
46
|
+
|
|
47
|
+
```css
|
|
48
|
+
@import "./component-lib/gbs.css";
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
With **Tailwind v4 only**, import it after the framework and into Tailwind's
|
|
52
|
+
components layer, or utilities stop overriding component rules:
|
|
53
|
+
|
|
54
|
+
```css
|
|
55
|
+
@import "tailwindcss";
|
|
56
|
+
@import "./component-lib/gbs.css" layer(components);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The installer prints whichever line applies. Component CSS is unlayered, so
|
|
60
|
+
Tailwind v3, Bootstrap and no-framework projects need nothing extra.
|
|
61
|
+
|
|
62
|
+
Folder = lowercased name, except `data-grid`, `date-picker`, `file-uploader`,
|
|
63
|
+
`number-input`, `radio-group`.
|
|
64
|
+
|
|
65
|
+
## Rules most often missed
|
|
66
|
+
|
|
67
|
+
1. **Change handlers are named per component.** `onValueChange`: Input,
|
|
68
|
+
OtpInput, Textarea, NumberInput, CheckboxGroup, RadioGroup, Tabs, Accordion,
|
|
69
|
+
MenuRadioGroup. `onCheckedChange`: Checkbox, Switch, MenuCheckboxItem.
|
|
70
|
+
`onChange`: Select, MultiSelect, DatePicker, DateRangePicker, FileUploader.
|
|
71
|
+
`onOpenChange`: Modal, Popover, Menu.
|
|
72
|
+
2. **Never hand-roll `<label>`, hint or error markup.** Fields take `label`,
|
|
73
|
+
`description` and `error`; `error` also marks the control invalid and wires
|
|
74
|
+
`aria-describedby`. A `<label>` wrapper breaks it.
|
|
75
|
+
3. **Style via `classNames` slots** (`classNames={{ root, label }}`);
|
|
76
|
+
`className` hits the root only. Theme globally with `--gbs-*` on `:root`.
|
|
77
|
+
4. **Mount `<Toaster />` and `<DialogHost />` once at the app root**, or
|
|
78
|
+
`toast()` and `dialog.confirm()` do nothing.
|
|
79
|
+
5. **All are client components** (`"use client"`); a Next.js Server Component
|
|
80
|
+
can render them but not pass function props.
|
|
81
|
+
6. **Compound families throw outside their parent**: Tab/TabList/TabPanel need
|
|
82
|
+
Tabs, AccordionItem needs Accordion, MenuItem needs Menu.
|
|
83
|
+
|
|
84
|
+
## Inventory (required props in parens)
|
|
85
|
+
|
|
86
|
+
**Forms** — Input, Textarea, NumberInput (locale-aware), OtpInput; Checkbox +
|
|
87
|
+
CheckboxGroup; Radio (`value`) + RadioGroup; Switch (applies immediately);
|
|
88
|
+
Select and MultiSelect (`options`; searchable, client or server); DatePicker and
|
|
89
|
+
DateRangePicker; FileUploader (chunked).
|
|
90
|
+
|
|
91
|
+
**Actions** — Button: variants, sizes, icons, auto-loading from a returned
|
|
92
|
+
promise; `render` draws a router link.
|
|
93
|
+
|
|
94
|
+
**Overlays** — Modal (native `<dialog>`, also drawers); `dialog` + DialogHost
|
|
95
|
+
(`await dialog.confirm/alert/prompt`); Popover (`trigger`); Menu (`trigger`) with
|
|
96
|
+
MenuItem, MenuCheckboxItem, MenuRadioGroup, MenuRadioItem, MenuGroup,
|
|
97
|
+
MenuSeparator, MenuSub; Tooltip (`content`); `toast` + Toaster.
|
|
98
|
+
|
|
99
|
+
**Data** — DataGrid (`data`, `columns`) + createColumnHelper: virtualized;
|
|
100
|
+
sort, filter, edit, CSV/Excel/PDF export. Optional agent surface: `ai` renders a
|
|
101
|
+
natural-language box, and `registerGridTool` exposes the grid to a browser agent
|
|
102
|
+
over WebMCP (see "Agent surface"). Inside an `<AgentSurface>` the grid joins the
|
|
103
|
+
page's one tool instead (see "Page surface").
|
|
104
|
+
|
|
105
|
+
**Display** — Tabs/TabList/Tab (`value`)/TabPanel (`value`); Accordion +
|
|
106
|
+
AccordionItem (`value`); Card/CardHeader/CardBody/CardFooter/Stat; Alert; Badge
|
|
107
|
+
and Tag; Avatar and AvatarGroup; Progress and CircularProgress (`value={null}`
|
|
108
|
+
is indeterminate); Skeleton and Empty; Spinner; Breadcrumb (`items`,
|
|
109
|
+
`renderLink`).
|
|
110
|
+
|
|
111
|
+
## Example
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
"use client";
|
|
115
|
+
import { useState } from "react";
|
|
116
|
+
import { Button } from "component-lib/button";
|
|
117
|
+
import { Input } from "component-lib/input";
|
|
118
|
+
import { Select } from "component-lib/combobox";
|
|
119
|
+
import { Modal } from "component-lib/modal";
|
|
120
|
+
import { toast } from "component-lib/toaster";
|
|
121
|
+
|
|
122
|
+
const ROLES = [{ value: "admin", label: "Admin" }, { value: "dev", label: "Dev" }];
|
|
123
|
+
|
|
124
|
+
export function InviteButton() {
|
|
125
|
+
const [open, setOpen] = useState(false);
|
|
126
|
+
const [email, setEmail] = useState("");
|
|
127
|
+
const [role, setRole] = useState<string | null>(null);
|
|
128
|
+
const invalid = !!email && !email.includes("@");
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<>
|
|
132
|
+
<Button onClick={() => setOpen(true)}>Invite</Button>
|
|
133
|
+
<Modal open={open} onOpenChange={setOpen} title="Invite a teammate"
|
|
134
|
+
footer={({ close }) => (
|
|
135
|
+
<Button disabled={!email || invalid} onClick={async () => {
|
|
136
|
+
await invite({ email, role });
|
|
137
|
+
toast.success("Invitation sent");
|
|
138
|
+
close();
|
|
139
|
+
}}>Send</Button>
|
|
140
|
+
)}>
|
|
141
|
+
<Input label="Email" type="email" value={email} onValueChange={setEmail}
|
|
142
|
+
required error={invalid ? "Enter a valid email" : undefined} />
|
|
143
|
+
<Select label="Role" options={ROLES} value={role} onChange={setRole} />
|
|
144
|
+
</Modal>
|
|
145
|
+
</>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Page surface (optional): `<AgentSurface>`
|
|
151
|
+
|
|
152
|
+
To make a page operable by a browser agent, wrap it — do not write WebMCP tools
|
|
153
|
+
by hand:
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { AgentSurface } from "component-lib/shared";
|
|
157
|
+
|
|
158
|
+
<AgentSurface>
|
|
159
|
+
<Input label="Name" maxLength={80} />
|
|
160
|
+
<Select label="Team" options={teams} />
|
|
161
|
+
<DataGrid aria-label="Customers" data={rows} columns={cols} />
|
|
162
|
+
</AgentSurface>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Input, Textarea, NumberInput, Checkbox, Switch, RadioGroup, Select,
|
|
166
|
+
MultiSelect, DatePicker, DateRangePicker and DataGrid register themselves, with
|
|
167
|
+
what they accept, and one tool `operate_page` (`describe`, then `operate` by
|
|
168
|
+
id) is registered when WebMCP exists. Ids come from the label, so give every
|
|
169
|
+
field a text `label` (a grid an `aria-label`). Every action goes through the
|
|
170
|
+
component's own validator; password, hidden and file inputs are never offered.
|
|
171
|
+
`useAgentSurface()` returns the same surface for an app's own agent loop.
|
|
172
|
+
|
|
173
|
+
## Agent surface (DataGrid, optional)
|
|
174
|
+
|
|
175
|
+
Entirely opt-in. Without it, nothing changes and nothing is downloaded.
|
|
176
|
+
|
|
177
|
+
**A person typing.** `ai` renders a box above the grid. It needs a provider
|
|
178
|
+
supplying an adapter; with no provider it renders nothing at all.
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
import { GramproAIProvider } from "component-lib/shared";
|
|
182
|
+
import { DataGrid } from "component-lib/data-grid";
|
|
183
|
+
|
|
184
|
+
<GramproAIProvider adapter={myAdapter}>
|
|
185
|
+
<DataGrid data={rows} columns={cols} ai semantics={SEMANTICS} />
|
|
186
|
+
</GramproAIProvider>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`adapter` is one function — `(utterance, contract, responseSchema) => envelope`.
|
|
190
|
+
No model is bundled, downloaded or named; the app brings its own, and the key
|
|
191
|
+
belongs on the app's server, never in client JavaScript.
|
|
192
|
+
|
|
193
|
+
**A browser agent.** `registerGridTool(agent)` registers one WebMCP tool,
|
|
194
|
+
`operate_grid`, whose schema is generated from the live grid. Requires no model
|
|
195
|
+
at all.
|
|
196
|
+
|
|
197
|
+
**Both go through the same validator**, which refuses an unknown column, an
|
|
198
|
+
operator the type lacks, a policy-denied column, or an irreversible operation
|
|
199
|
+
with no confirmation — and returns the reason. A producer proposes; it never
|
|
200
|
+
acts. Do not add repair, retries or a second execution path.
|
|
201
|
+
|
|
202
|
+
**Data leaves the page with a remote adapter.** The contract carries real
|
|
203
|
+
values from low-cardinality columns, so the model can map "Kerala" to `region`.
|
|
204
|
+
Mark personal columns `semantics: { email: { pii: true } }` — a PII column is
|
|
205
|
+
denied *and* never summarised — or pass `stats: false` to summarise nothing.
|
|
206
|
+
`policy.denyFilter` does **not** stop a column being described.
|
|
207
|
+
|
|
208
|
+
**`semantics` is where most quality comes from**: per column, give `synonyms`,
|
|
209
|
+
`description`, `unit`, `higherIsBetter`, `pii`. Reach for it before reaching for
|
|
210
|
+
a bigger model.
|
|
211
|
+
|
|
212
|
+
## Don't
|
|
213
|
+
|
|
214
|
+
- Raw `<button>`, `<input>`, `<select>`, `<table>`, `<dialog>`, or a hand-built
|
|
215
|
+
modal/menu/tooltip, when a component exists.
|
|
216
|
+
- Deep imports (`.../input/react/Input`); import the barrel. Only `<name>/core`
|
|
217
|
+
is also public.
|
|
218
|
+
- Editing `component-lib/shared/`; the CLI replaces it on update.
|
|
219
|
+
- Invented props: no `asChild`, no `variant` on Input, no `onChange` on Switch.
|
|
220
|
+
- `!important` or internal class selectors; set `--gbs-*` or pass `classNames`.
|
|
221
|
+
- A Tooltip as a name; icon buttons need `aria-label`.
|
|
222
|
+
|
|
223
|
+
## Details (in `references/`)
|
|
224
|
+
|
|
225
|
+
- `install.md` — CLI flags, folders, 1.x vs 2.x.
|
|
226
|
+
- `forms.md` — fields, controlled state, form posting.
|
|
227
|
+
- `pickers.md` — Select, MultiSelect, DatePicker, Uploader.
|
|
228
|
+
- `overlays.md` — Modal, dialog, Popover, Menu, Tooltip.
|
|
229
|
+
- `toaster.md` — `toast()` and `<Toaster />`.
|
|
230
|
+
- `data-grid.md` — columns, API, export.
|
|
231
|
+
- `data-display.md` — Card, Tabs, Accordion, Badge, Avatar.
|
|
232
|
+
- `styling.md` — tokens, layers, slots, `data-*`, dark.
|
|
233
|
+
- `accessibility.md` — what is supplied, what you add.
|
|
@@ -114,3 +114,12 @@ use `print()` for those.
|
|
|
114
114
|
|
|
115
115
|
Set `mode="server"`, pass the current page as `data` and the total as
|
|
116
116
|
`rowCount`, and fetch in `onQueryChange`.
|
|
117
|
+
|
|
118
|
+
## Inside an AgentSurface
|
|
119
|
+
|
|
120
|
+
A DataGrid inside `<AgentSurface>` builds its agent and joins the page's one
|
|
121
|
+
WebMCP tool (`operate_page`) by itself, with its columns and operations; there
|
|
122
|
+
is no need to call `createGridAgent` or `registerGridTool`. Give it an
|
|
123
|
+
`aria-label` — it becomes the grid's id there. `semantics` and `agentPolicy`
|
|
124
|
+
apply exactly as with `ai`. Outside a surface and without `ai`, no agent is
|
|
125
|
+
built.
|
|
@@ -200,3 +200,15 @@ There is no form library here. Compute the message yourself and pass it as
|
|
|
200
200
|
`error`; the component handles `aria-invalid`, `aria-describedby` and the
|
|
201
201
|
styling. With React Hook Form or similar, wire `value` and the component's own
|
|
202
202
|
handler name, and pass `error={errors.field?.message}`.
|
|
203
|
+
|
|
204
|
+
## Operable by a browser agent
|
|
205
|
+
|
|
206
|
+
Wrap the form in `<AgentSurface>` (from `shared`) and every field in it joins
|
|
207
|
+
one WebMCP tool, `operate_page`, describing what it accepts from its own props:
|
|
208
|
+
`maxLength`, `min`/`max`, options and which are disabled. Nothing else to
|
|
209
|
+
write. Give each field a text `label`: the label becomes its id
|
|
210
|
+
(`"Due date"` → `due-date`), and a field labelled only by a ReactNode falls
|
|
211
|
+
back to `aria-label`, then `name`, then `placeholder`. Password, hidden and file inputs are never
|
|
212
|
+
offered. Writes fire the same handlers a person's input does, so controlled
|
|
213
|
+
state updates as usual. Without WebMCP, `useAgentSurface()` returns the same
|
|
214
|
+
surface for the app's own agent loop.
|
|
@@ -18,9 +18,10 @@ other runtime dependencies.
|
|
|
18
18
|
```bash
|
|
19
19
|
npx @grampro/kit add Button # one component
|
|
20
20
|
npx @grampro/kit add Button,Input,Modal # several
|
|
21
|
-
npx @grampro/kit
|
|
21
|
+
npx @grampro/kit add # interactive picker (a person at a terminal)
|
|
22
22
|
npx @grampro/kit -l # list available
|
|
23
|
-
npx @grampro/kit
|
|
23
|
+
npx @grampro/kit doctor # what changed locally and upstream
|
|
24
|
+
npx @grampro/kit doctor Button --json # one component, for reading programmatically
|
|
24
25
|
npx @grampro/kit skill # install this skill
|
|
25
26
|
npx @grampro/kit skill --for claude # only the Claude Code copy
|
|
26
27
|
```
|
|
@@ -28,12 +29,42 @@ npx @grampro/kit skill --for claude # only the Claude Code copy
|
|
|
28
29
|
| Flag | Alias | Meaning |
|
|
29
30
|
| --- | --- | --- |
|
|
30
31
|
| `--add` | `-a` | Component, or comma-separated list. Case-insensitive. |
|
|
31
|
-
| `--interactive` | `-i` | Pick from a menu. |
|
|
32
|
+
| `--interactive` | `-i` | Pick from a menu; same as `add` with no names. Needs a terminal. |
|
|
32
33
|
| `--list` | `-l` | Print available components. |
|
|
33
34
|
| `--legacy` | — | Install from the 1.x set instead. Unmaintained; see below. |
|
|
34
35
|
| `--skill` | — | Install this skill at the project root. `-skill` and `-a skill` also work. |
|
|
35
36
|
| `--for` | — | With `--skill`: which agents to write adapters for (`claude`, `codex`, `antigravity`, or `none`). Default: all. |
|
|
36
|
-
| `--force` | — | Replace
|
|
37
|
+
| `--force` | — | Replace a component, `shared/` or `.gbs/` even though the project has edited it. Never pass it on the user's behalf. |
|
|
38
|
+
| `--json` | — | With `doctor`: print the report as JSON. |
|
|
39
|
+
|
|
40
|
+
**An agent always names the components.** The picker needs a real terminal:
|
|
41
|
+
run without one, `add` with no names only prints a hint and `-i` exits with an
|
|
42
|
+
error, so neither installs anything. Output is in colour only on a terminal,
|
|
43
|
+
and never with `NO_COLOR` set — read it piped and it is plain text.
|
|
44
|
+
|
|
45
|
+
## Components the project has changed
|
|
46
|
+
|
|
47
|
+
Copied components are meant to be edited, so `add` treats an edited one as
|
|
48
|
+
the project's code, not the kit's:
|
|
49
|
+
|
|
50
|
+
- **Untouched** — `add` updates it in place.
|
|
51
|
+
- **Edited** since it was installed — `add` leaves it alone, prints which
|
|
52
|
+
files changed, and exits 1. The component is still installed and usable.
|
|
53
|
+
|
|
54
|
+
When that happens, **stop and tell the user.** Do not rerun with `--force`:
|
|
55
|
+
it discards their changes, and replacing their code is their decision, not
|
|
56
|
+
yours. Show them `npx @grampro/kit doctor <Component>`, which reports:
|
|
57
|
+
|
|
58
|
+
- which files they changed;
|
|
59
|
+
- what they changed in the component's contract (props, values, handlers);
|
|
60
|
+
- what the new version changes, and where the two conflict or merge;
|
|
61
|
+
- the exact call sites in their code an update would break.
|
|
62
|
+
|
|
63
|
+
Run `doctor` yourself before proposing an update. `doctor --json` gives the
|
|
64
|
+
same report in a form you can read; it never writes anything.
|
|
65
|
+
|
|
66
|
+
The MCP server's `install_component` follows the same rule and returns the
|
|
67
|
+
components it kept under `kept`, with the reason.
|
|
37
68
|
|
|
38
69
|
**Pass no flag.** The 2.x components are what `add` installs. `--beta` used
|
|
39
70
|
to opt in to them and now does nothing but print a notice, so do not pass it.
|
|
@@ -142,6 +173,10 @@ Rules the installer enforces:
|
|
|
142
173
|
|
|
143
174
|
- `shared/` only moves forward. If the project has a newer version than the CLI
|
|
144
175
|
carries, the install aborts rather than downgrading it.
|
|
176
|
+
- The same version is updated anyway when its files differ from the CLI's, so a
|
|
177
|
+
release that changed `shared/` without a version bump still reaches the
|
|
178
|
+
project. (2.7.0 did; projects that had shared 1.3.0 kept the old files until
|
|
179
|
+
2.7.3, which is shared 1.4.0.)
|
|
145
180
|
- A file you edited since the CLI wrote it is never replaced without `--force`.
|
|
146
181
|
It tracks this with sha256 hashes in `component-lib/shared/.install-manifest.json`.
|
|
147
182
|
|
|
@@ -150,7 +185,9 @@ is replaced on update. Put your changes in your own module instead.
|
|
|
150
185
|
|
|
151
186
|
`shared` exports `cx`, `countCharacters`, `describeField`,
|
|
152
187
|
`useControllableState`, `AnchoredPopover`, `placePopover`, `icons` and
|
|
153
|
-
`sharedVersion
|
|
188
|
+
`sharedVersion`; the agent runtime (`createFieldAgent`, `useFieldAgent`,
|
|
189
|
+
`GramproAIProvider`); and `AgentSurface` with `useAgentSurface`, which make a
|
|
190
|
+
page operable by a browser agent (see SKILL.md, "Page surface").
|
|
154
191
|
|
|
155
192
|
## Importing
|
|
156
193
|
|