@alaarab/ogrid-mcp 2.14.0 → 2.14.2
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/bundled-docs/api/components-sidebar.mdx +1 -1
- package/bundled-docs/api/headless-hooks.mdx +1 -1
- package/bundled-docs/features/premium-inputs.mdx +2 -2
- package/bundled-docs/getting-started/headless-or-component.mdx +3 -4
- package/bundled-docs/guides/mcp.mdx +2 -2
- package/dist/esm/index.js +83 -44
- package/package.json +2 -1
|
@@ -18,7 +18,7 @@ A collapsible sidebar panel that provides quick access to column visibility cont
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
:::tip
|
|
21
|
-
The `SideBar` component is framework-agnostic and uses inline styles. All React UI packages (Radix, Fluent
|
|
21
|
+
The `SideBar` component is framework-agnostic and uses inline styles. All React UI packages (Radix, Fluent) use the same `SideBar` from `@alaarab/ogrid-react`.
|
|
22
22
|
:::
|
|
23
23
|
|
|
24
24
|
</TabItem>
|
|
@@ -10,7 +10,7 @@ OGrid 2.9 ships seven framework-native hooks that expose grid logic without
|
|
|
10
10
|
imposing any chrome. Pair `useHeadlessGrid` with the spreadsheet hooks to
|
|
11
11
|
add inline edit, range selection, fill handle, clipboard, undo/redo, and
|
|
12
12
|
keyboard navigation to your own table markup (shadcn `<Table>`, plain HTML,
|
|
13
|
-
|
|
13
|
+
Fluent `<DataGrid>`, anything).
|
|
14
14
|
|
|
15
15
|
All seven hooks ship as React hooks:
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ OGrid's premium inputs are optional cell editor components distributed in a sepa
|
|
|
18
18
|
npm install @alaarab/ogrid-react-inputs
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Works with any OGrid React UI package (Radix, Fluent
|
|
21
|
+
Works with any OGrid React UI package (Radix, Fluent).
|
|
22
22
|
|
|
23
23
|
</TabItem>
|
|
24
24
|
</Tabs>
|
|
@@ -213,7 +213,7 @@ OGrid includes built-in cell editors out of the box. The premium input packages
|
|
|
213
213
|
|
|
214
214
|
| | Default (built-in) | Premium (add-on packages) |
|
|
215
215
|
|---|---|---|
|
|
216
|
-
| **Package** | Included in all OGrid packages | `@alaarab/ogrid-
|
|
216
|
+
| **Package** | Included in all OGrid packages | `@alaarab/ogrid-react-inputs` |
|
|
217
217
|
| **Editors** | Text, Select, Rich Select, Checkbox, Date (inline) | DatePicker, Rating, ColorPicker, Slider, Tags |
|
|
218
218
|
| **Bundle cost** | Zero (built-in) | Only added when you `npm install` the package |
|
|
219
219
|
|
|
@@ -15,7 +15,7 @@ fits the page you're building — you can mix them in the same app.
|
|
|
15
15
|
| **What you write** | One JSX element | A handful of hook calls + your own `<table>` markup |
|
|
16
16
|
| **Time to first working grid** | ~5 lines | ~50-100 lines |
|
|
17
17
|
| **Customization ceiling** | High (theme tokens, slots) | Unlimited (you draw the chrome) |
|
|
18
|
-
| **Design-system fit** | Inherits via theme presets (shadcn, Fluent
|
|
18
|
+
| **Design-system fit** | Inherits via theme presets (shadcn, Fluent) | Native — uses your chrome primitives directly |
|
|
19
19
|
| **Spreadsheet features** | Built-in | Composable from hooks |
|
|
20
20
|
| **Best for** | Standard list pages, admin tables, dashboards | Pages where chrome integration matters more than save-time |
|
|
21
21
|
|
|
@@ -23,7 +23,7 @@ fits the page you're building — you can mix them in the same app.
|
|
|
23
23
|
|
|
24
24
|
- You want a complete grid in one element. Sort, filter, paginate, edit,
|
|
25
25
|
range select, fill handle, copy/paste, undo, keyboard nav — all wired.
|
|
26
|
-
- The default chrome (via your chosen UI variant — Radix / Fluent
|
|
26
|
+
- The default chrome (via your chosen UI variant — Radix / Fluent)
|
|
27
27
|
is close enough to your design system that a theme preset (`preset-shadcn.css`)
|
|
28
28
|
can bridge the rest.
|
|
29
29
|
- You're prototyping or building admin pages where shipping fast matters
|
|
@@ -42,8 +42,7 @@ const columns = [
|
|
|
42
42
|
## Use `useHeadlessGrid` + the spreadsheet hooks when…
|
|
43
43
|
|
|
44
44
|
- You want OGrid's logic but rendered with your own table chrome
|
|
45
|
-
(shadcn `<Table>`, Fluent `<DataGrid>`,
|
|
46
|
-
anything).
|
|
45
|
+
(shadcn `<Table>`, Fluent `<DataGrid>`, plain HTML — anything).
|
|
47
46
|
- The chrome integration is non-negotiable: a specific design system,
|
|
48
47
|
custom row layouts, embedded widgets in cells, or shared `<TableRow>`
|
|
49
48
|
components from the rest of the app.
|
|
@@ -90,7 +90,7 @@ search_docs query="server-side data" framework="react"
|
|
|
90
90
|
|
|
91
91
|
Parameters:
|
|
92
92
|
- `query` (required) — what you're looking for
|
|
93
|
-
- `framework` (optional) — `react
|
|
93
|
+
- `framework` (optional) — `react`
|
|
94
94
|
- `category` (optional) — `features`, `getting-started`, `guides`, or `api`
|
|
95
95
|
|
|
96
96
|
### `list_docs`
|
|
@@ -114,7 +114,7 @@ get_docs path="features/filtering"
|
|
|
114
114
|
Pull code snippets from a doc page, optionally filtered by framework.
|
|
115
115
|
|
|
116
116
|
```
|
|
117
|
-
get_code_example path="features/editing" framework="
|
|
117
|
+
get_code_example path="features/editing" framework="react"
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
### `detect_version`
|
package/dist/esm/index.js
CHANGED
|
@@ -93,6 +93,21 @@ function parseDocFile(filePath, docsDir2) {
|
|
|
93
93
|
codeBlocks
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
+
function countOccurrences(haystack, needle, cap) {
|
|
97
|
+
if (!needle) return 0;
|
|
98
|
+
let idx = 0;
|
|
99
|
+
let count = 0;
|
|
100
|
+
while (count < cap) {
|
|
101
|
+
idx = haystack.indexOf(needle, idx);
|
|
102
|
+
if (idx === -1) break;
|
|
103
|
+
count++;
|
|
104
|
+
idx += needle.length;
|
|
105
|
+
}
|
|
106
|
+
return count;
|
|
107
|
+
}
|
|
108
|
+
function tokenize(queryLower) {
|
|
109
|
+
return queryLower.split(/\s+/).filter((t) => t.length > 1);
|
|
110
|
+
}
|
|
96
111
|
function scoreEntry(entry, queryLower) {
|
|
97
112
|
let score = 0;
|
|
98
113
|
const titleLower = entry.title.toLowerCase();
|
|
@@ -108,15 +123,18 @@ function scoreEntry(entry, queryLower) {
|
|
|
108
123
|
}
|
|
109
124
|
if (contentLower.includes(queryLower)) {
|
|
110
125
|
score += 10;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
score += countOccurrences(contentLower, queryLower, 10) * 2;
|
|
127
|
+
}
|
|
128
|
+
const tokens = tokenize(queryLower);
|
|
129
|
+
if (tokens.length > 1) {
|
|
130
|
+
for (const token of tokens) {
|
|
131
|
+
if (titleLower.includes(token)) score += 25;
|
|
132
|
+
if (descLower.includes(token)) score += 12;
|
|
133
|
+
if (contentLower.includes(token)) {
|
|
134
|
+
score += 3;
|
|
135
|
+
score += countOccurrences(contentLower, token, 5);
|
|
136
|
+
}
|
|
118
137
|
}
|
|
119
|
-
score += count * 2;
|
|
120
138
|
}
|
|
121
139
|
if (entry.category === "features") score += 3;
|
|
122
140
|
if (entry.category === "getting-started") score += 2;
|
|
@@ -125,9 +143,20 @@ function scoreEntry(entry, queryLower) {
|
|
|
125
143
|
function scoreCodeBlock(entry, block, queryLower, framework) {
|
|
126
144
|
let score = 0;
|
|
127
145
|
if (framework && block.framework !== framework) return -1;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
146
|
+
const titleLower = entry.title.toLowerCase();
|
|
147
|
+
const descLower = entry.description.toLowerCase();
|
|
148
|
+
const codeLower = block.code.toLowerCase();
|
|
149
|
+
if (titleLower.includes(queryLower)) score += 50;
|
|
150
|
+
if (descLower.includes(queryLower)) score += 25;
|
|
151
|
+
if (codeLower.includes(queryLower)) score += 30;
|
|
152
|
+
const tokens = tokenize(queryLower);
|
|
153
|
+
if (tokens.length > 1) {
|
|
154
|
+
for (const token of tokens) {
|
|
155
|
+
if (titleLower.includes(token)) score += 12;
|
|
156
|
+
if (descLower.includes(token)) score += 6;
|
|
157
|
+
if (codeLower.includes(token)) score += 8;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
131
160
|
return score;
|
|
132
161
|
}
|
|
133
162
|
function loadDocsIndex(docsDir2) {
|
|
@@ -215,15 +244,19 @@ function fromResourcePath(resourcePath, index2) {
|
|
|
215
244
|
return index2.getByPath(resourcePath + ".mdx") ?? index2.getByPath(resourcePath + ".md") ?? index2.getByPath(resourcePath);
|
|
216
245
|
}
|
|
217
246
|
function createOGridMcpServer(index2, bridge) {
|
|
218
|
-
const server2 = new McpServer(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
247
|
+
const server2 = new McpServer(
|
|
248
|
+
{
|
|
249
|
+
name: "ogrid-docs",
|
|
250
|
+
version: "2.3.0"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
instructions: `OGrid documentation server. OGrid is a lightweight, headless data grid for React (Radix and Fluent UI implementations).
|
|
222
254
|
|
|
223
255
|
Tools: search_docs (keyword search), list_docs (browse by category), get_docs (full page), get_code_example (code snippets), detect_version (detect OGrid version in your project).
|
|
224
256
|
Resources: ogrid://quick-reference (key API overview), ogrid://docs/{path} (any doc page by path).
|
|
225
257
|
Categories: features, getting-started, guides, api.`
|
|
226
|
-
|
|
258
|
+
}
|
|
259
|
+
);
|
|
227
260
|
server2.tool(
|
|
228
261
|
"search_docs",
|
|
229
262
|
"Search OGrid documentation by keyword. Returns matching docs with title, description, and content excerpt.",
|
|
@@ -440,12 +473,14 @@ Tip: use \`get_code_example\` with framework="${result.framework}" or \`search_d
|
|
|
440
473
|
{
|
|
441
474
|
uri: uri.href,
|
|
442
475
|
mimeType: "text/markdown",
|
|
476
|
+
// Source of truth: docs/api/ogrid-props.mdx + docs/api/column-def.mdx.
|
|
477
|
+
// Keep this in sync when those API references change.
|
|
443
478
|
text: [
|
|
444
479
|
"# OGrid Quick Reference",
|
|
445
480
|
"",
|
|
446
481
|
"## Install",
|
|
447
482
|
"```bash",
|
|
448
|
-
"# React (choose one)",
|
|
483
|
+
"# React (choose one UI variant)",
|
|
449
484
|
"npm install @alaarab/ogrid-react-radix",
|
|
450
485
|
"npm install @alaarab/ogrid-react-fluent",
|
|
451
486
|
"```",
|
|
@@ -453,34 +488,38 @@ Tip: use \`get_code_example\` with framework="${result.framework}" or \`search_d
|
|
|
453
488
|
"## Core Props (IOGridProps)",
|
|
454
489
|
"| Prop | Type | Description |",
|
|
455
490
|
"|------|------|-------------|",
|
|
456
|
-
"| `data` | `T[]` | Client-side row data |",
|
|
457
|
-
"| `
|
|
458
|
-
"| `
|
|
459
|
-
"| `
|
|
460
|
-
|
|
491
|
+
"| `data` | `T[]` | Client-side row data (mutually exclusive with `dataSource`) |",
|
|
492
|
+
"| `dataSource` | `IDataSource<T>` | Server-side data source (mutually exclusive with `data`) |",
|
|
493
|
+
"| `columns` | `(IColumnDef<T> \\| IColumnGroupDef<T>)[]` | Column definitions (and optional groups) |",
|
|
494
|
+
"| `getRowId` | `(item: T) => RowId` | **Required.** Stable unique id for each row |",
|
|
495
|
+
"| `defaultPageSize` | `number` | Initial page size in uncontrolled mode (default 25) |",
|
|
496
|
+
"| `pageSizeOptions` | `number[]` | Options shown in the page-size dropdown |",
|
|
497
|
+
'| `rowSelection` | `"none" \\| "single" \\| "multiple"` | Row selection mode |',
|
|
498
|
+
"| `editable` | `boolean` | Enable inline cell editing globally |",
|
|
461
499
|
"| `formulas` | `boolean` | Enable formula engine (=SUM, =IF, etc.) |",
|
|
462
500
|
"| `cellReferences` | `boolean` | Excel-style A1 column headers + name box |",
|
|
463
501
|
'| `workerSort` | `boolean \\| "auto"` | Web Worker sort/filter |',
|
|
464
502
|
'| `columnChooser` | `boolean \\| "toolbar" \\| "sidebar"` | Column visibility control |',
|
|
465
503
|
"| `sideBar` | `boolean \\| ISideBarDef` | Sidebar panel |",
|
|
466
504
|
"| `toolbar` | `ReactNode` | Custom toolbar content |",
|
|
467
|
-
"| `
|
|
468
|
-
"| `onCellValueChanged` | `(e: ICellValueChangedEvent) => void` | Cell edit callback |",
|
|
505
|
+
"| `onSelectionChange` | `(e: IRowSelectionChangeEvent<T>) => void` | Row selection callback |",
|
|
506
|
+
"| `onCellValueChanged` | `(e: ICellValueChangedEvent<T>) => void` | Cell edit callback |",
|
|
469
507
|
"",
|
|
470
508
|
"## IColumnDef Key Fields",
|
|
471
509
|
"| Field | Type | Description |",
|
|
472
510
|
"|-------|------|-------------|",
|
|
473
|
-
"| `columnId` | `string` | Unique column
|
|
474
|
-
"| `
|
|
511
|
+
"| `columnId` | `string` | Unique column id (maps to the data key) |",
|
|
512
|
+
"| `name` | `string` | Column header label |",
|
|
475
513
|
'| `type` | `"text" \\| "numeric" \\| "date" \\| "boolean"` | Data type |',
|
|
476
|
-
|
|
477
|
-
"| `editable` | `boolean \\| (
|
|
478
|
-
"| `
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
"| `
|
|
482
|
-
|
|
483
|
-
"| `
|
|
514
|
+
"| `filterable` | `IColumnFilterDef` | Filter config; omit to make the column not filterable |",
|
|
515
|
+
"| `editable` | `boolean \\| ((item: T) => boolean)` | Enable inline editing |",
|
|
516
|
+
"| `sortable` | `boolean` | Enable sorting (default true) |",
|
|
517
|
+
"| `defaultWidth` | `number` | Default column width in pixels |",
|
|
518
|
+
'| `pinned` | `"left" \\| "right"` | Pin column to an edge |',
|
|
519
|
+
"| `defaultVisible` | `boolean` | Show column by default (false = hidden, toggle via chooser) |",
|
|
520
|
+
'| `cellEditor` | `"text" \\| "select" \\| "checkbox" \\| "richSelect" \\| "date" \\| ComponentType` | Cell editor |',
|
|
521
|
+
"| `valueGetter` | `(item: T) => unknown` | Custom value extractor |",
|
|
522
|
+
"| `renderCell` | `(item: T) => ReactNode` | Custom cell renderer |",
|
|
484
523
|
"",
|
|
485
524
|
"## Common Patterns",
|
|
486
525
|
"",
|
|
@@ -488,27 +527,27 @@ Tip: use \`get_code_example\` with framework="${result.framework}" or \`search_d
|
|
|
488
527
|
"```tsx",
|
|
489
528
|
'import { OGrid } from "@alaarab/ogrid-react-radix";',
|
|
490
529
|
"const columns = [",
|
|
491
|
-
' { columnId: "name",
|
|
492
|
-
' { columnId: "age",
|
|
530
|
+
' { columnId: "name", name: "Name", type: "text", filterable: { type: "text" } },',
|
|
531
|
+
' { columnId: "age", name: "Age", type: "numeric", sortable: true },',
|
|
493
532
|
"];",
|
|
494
|
-
"<OGrid data={rows} columns={columns}
|
|
533
|
+
"<OGrid data={rows} columns={columns} getRowId={(r) => r.id} defaultPageSize={50} />",
|
|
495
534
|
"```",
|
|
496
535
|
"",
|
|
497
536
|
"### Server-side data",
|
|
498
537
|
"```tsx",
|
|
499
538
|
"const dataSource = {",
|
|
500
|
-
" fetchPage: async ({ page, pageSize,
|
|
501
|
-
" const res = await fetch(`/api/data?page=${page}&size=${pageSize}
|
|
539
|
+
" fetchPage: async ({ page, pageSize, sort, filters, signal }) => {",
|
|
540
|
+
" const res = await fetch(`/api/data?page=${page}&size=${pageSize}`, { signal });",
|
|
502
541
|
" const json = await res.json();",
|
|
503
|
-
" return {
|
|
504
|
-
" }",
|
|
542
|
+
" return { items: json.data, totalCount: json.total };",
|
|
543
|
+
" },",
|
|
505
544
|
"};",
|
|
506
|
-
"<OGrid dataSource={dataSource} columns={columns}
|
|
545
|
+
"<OGrid dataSource={dataSource} columns={columns} getRowId={(r) => r.id} defaultPageSize={50} />",
|
|
507
546
|
"```",
|
|
508
547
|
"",
|
|
509
548
|
"### Formula support",
|
|
510
549
|
"```tsx",
|
|
511
|
-
"<OGrid data={rows} columns={columns} formulas cellReferences />",
|
|
550
|
+
"<OGrid data={rows} columns={columns} getRowId={(r) => r.id} formulas cellReferences />",
|
|
512
551
|
'// Users can type =SUM(A1:C3), =IF(A1>0,"yes","no"), etc.',
|
|
513
552
|
"```"
|
|
514
553
|
].join("\n")
|
|
@@ -742,7 +781,7 @@ _${state.rowCount - limit} more rows not shown. Increase maxRows to see more._`)
|
|
|
742
781
|
{
|
|
743
782
|
gridId: z.string().describe("Grid ID as registered by connectGridToBridge()"),
|
|
744
783
|
type: z.enum(["update_cell", "set_filter", "clear_filters", "set_sort", "go_to_page"]).describe("Command type"),
|
|
745
|
-
payload: z.record(z.unknown()).describe("Command-specific payload (see tool description for fields per type)"),
|
|
784
|
+
payload: z.record(z.string(), z.unknown()).describe("Command-specific payload (see tool description for fields per type)"),
|
|
746
785
|
timeoutMs: z.number().int().min(100).max(3e4).optional().describe("How long to wait for the app to execute the command (default: 5000ms)")
|
|
747
786
|
},
|
|
748
787
|
async ({ gridId, type, payload, timeoutMs }) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alaarab/ogrid-mcp",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.2",
|
|
4
4
|
"description": "MCP server for OGrid documentation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"prebuild": "node scripts/bundle-docs.mjs",
|
|
26
26
|
"build": "tsup",
|
|
27
27
|
"dev": "tsup --watch",
|
|
28
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
28
29
|
"test": "bun test --preload ../../bun-test.setup.ts"
|
|
29
30
|
},
|
|
30
31
|
"dependencies": {
|