@grampro/kit 2.7.2 → 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 -209
- 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 +14 -3
- package/CHANGELOG.md +963 -861
- package/README.md +11 -3
- package/index.cjs +108 -123
- 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 +5 -4
- package/tools/mcp/server.cjs +13 -1
- package/tools/passport/extract.cjs +20 -65
- package/tools/passport/hash.cjs +18 -1
- 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,209 +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. 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").
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
`
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
import {
|
|
116
|
-
import {
|
|
117
|
-
import {
|
|
118
|
-
import {
|
|
119
|
-
import {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const [
|
|
126
|
-
const [
|
|
127
|
-
const
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
<
|
|
161
|
-
<DataGrid data={rows} columns={cols}
|
|
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
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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,7 +18,7 @@ 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
23
|
npx @grampro/kit doctor # what changed locally and upstream
|
|
24
24
|
npx @grampro/kit doctor Button --json # one component, for reading programmatically
|
|
@@ -29,7 +29,7 @@ npx @grampro/kit skill --for claude # only the Claude Code copy
|
|
|
29
29
|
| Flag | Alias | Meaning |
|
|
30
30
|
| --- | --- | --- |
|
|
31
31
|
| `--add` | `-a` | Component, or comma-separated list. Case-insensitive. |
|
|
32
|
-
| `--interactive` | `-i` | Pick from a menu. |
|
|
32
|
+
| `--interactive` | `-i` | Pick from a menu; same as `add` with no names. Needs a terminal. |
|
|
33
33
|
| `--list` | `-l` | Print available components. |
|
|
34
34
|
| `--legacy` | — | Install from the 1.x set instead. Unmaintained; see below. |
|
|
35
35
|
| `--skill` | — | Install this skill at the project root. `-skill` and `-a skill` also work. |
|
|
@@ -37,6 +37,11 @@ npx @grampro/kit skill --for claude # only the Claude Code copy
|
|
|
37
37
|
| `--force` | — | Replace a component, `shared/` or `.gbs/` even though the project has edited it. Never pass it on the user's behalf. |
|
|
38
38
|
| `--json` | — | With `doctor`: print the report as JSON. |
|
|
39
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
|
+
|
|
40
45
|
## Components the project has changed
|
|
41
46
|
|
|
42
47
|
Copied components are meant to be edited, so `add` treats an edited one as
|
|
@@ -168,6 +173,10 @@ Rules the installer enforces:
|
|
|
168
173
|
|
|
169
174
|
- `shared/` only moves forward. If the project has a newer version than the CLI
|
|
170
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.)
|
|
171
180
|
- A file you edited since the CLI wrote it is never replaced without `--force`.
|
|
172
181
|
It tracks this with sha256 hashes in `component-lib/shared/.install-manifest.json`.
|
|
173
182
|
|
|
@@ -176,7 +185,9 @@ is replaced on update. Put your changes in your own module instead.
|
|
|
176
185
|
|
|
177
186
|
`shared` exports `cx`, `countCharacters`, `describeField`,
|
|
178
187
|
`useControllableState`, `AnchoredPopover`, `placePopover`, `icons` and
|
|
179
|
-
`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").
|
|
180
191
|
|
|
181
192
|
## Importing
|
|
182
193
|
|