apexgrid-skill 1.0.0 → 2.0.0
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/README.md +22 -7
- package/SKILL.md +274 -291
- package/index.js +1 -0
- package/package.json +1 -1
- package/references/columns-and-templates.md +55 -13
- package/references/data-pipeline.md +12 -7
- package/references/framework-integration.md +92 -47
- package/references/vanilla-js.md +154 -0
package/SKILL.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: apex-grid
|
|
3
3
|
description: >
|
|
4
|
-
AI skill for building UIs with the `apex-grid` web component (
|
|
5
|
-
|
|
6
|
-
troubleshoot a sortable / filterable / virtualized data
|
|
7
|
-
`<apex-grid>`. Covers the
|
|
8
|
-
|
|
9
|
-
`
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
AI skill for building UIs with the `apex-grid` web component (a Lit-based
|
|
5
|
+
data grid by ApexCharts). Use whenever the user asks to create, configure, or
|
|
6
|
+
troubleshoot a sortable / filterable / paginated / editable / virtualized data
|
|
7
|
+
table with `<apex-grid>`. Covers the register-and-size setup (no theme import —
|
|
8
|
+
the grid styles itself via `--ag-*` CSS variables), the generic
|
|
9
|
+
`ColumnConfiguration<T>` shape with its 13 column types, Lit `cellTemplate`
|
|
10
|
+
requirements, sorting / filtering / quick-filter, pagination, inline editing,
|
|
11
|
+
row selection, master-detail and tree rows, CSV export, the UI-only event
|
|
12
|
+
model, and the `dataPipelineConfiguration` hooks for server-side data.
|
|
13
13
|
metadata:
|
|
14
14
|
author: ApexCharts
|
|
15
|
-
version: "
|
|
16
|
-
library_version: "
|
|
15
|
+
version: "2.0.0"
|
|
16
|
+
library_version: "3.0.1"
|
|
17
17
|
category: data-visualization
|
|
18
18
|
tags: [grid, data-grid, table, web-component, lit, apex-grid]
|
|
19
19
|
docs: https://github.com/apexcharts/apexgrid
|
|
@@ -23,64 +23,80 @@ metadata:
|
|
|
23
23
|
|
|
24
24
|
# Apex Grid AI Skill
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
## 1. Quickstart — produce a visible, styled grid
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
The grid styles itself out of the box (borders, row separators, sort/filter UI) — there is **no theme CSS to import**. The one real gotcha is host sizing: the grid virtualizes rows, so it needs a bounded height or it collapses and renders nothing. Two setup steps: **register** the element and give it a **bounded height**, then bind `.data` / `.columns`.
|
|
29
29
|
|
|
30
|
-
1.
|
|
31
|
-
2. **Register the element exactly once at app startup**: either `import 'apex-grid/define'` (auto-registers as a side-effect) or `import { ApexGrid } from 'apex-grid'; ApexGrid.register();`. Without this, the tag renders as an empty inert element.
|
|
32
|
-
3. **`columns` and `data` are properties, not attributes.** Always bind with the property syntax (`.columns=${...}` in Lit, `[columns]="..."` in Angular, `:columns=` in Vue, ref-based in plain JS) — never as a stringified `columns="..."` attribute.
|
|
33
|
-
4. **`column.key` must be a real key of `T`** (the data row type). It is what the grid reads from each row, what sort/filter expressions reference, and what's emitted in events. There is no `field` / `dataIndex` / `accessor` alias.
|
|
34
|
-
5. **`type` defaults to `'string'`.** Set it to `'number'` or `'boolean'` to get the right filter operands and comparer. There is no `'date'` type — use `'number'` (timestamps) or `'string'` (ISO) and a custom `comparer` / `cellTemplate`.
|
|
35
|
-
6. **`sort` and `filter` per-column are `boolean | configObject`.** They are `false` by default — no opt-in, no UI. Set `sort: true` / `filter: true` to enable, or pass a config object for fine-grained control.
|
|
36
|
-
7. **`cellTemplate` and `headerTemplate` must return Lit `TemplateResult`s** (`html\`...\``) — not strings, DOM nodes, or framework-specific JSX. Plain HTML strings render as escaped text.
|
|
37
|
-
8. **Sort/filter events fire on UI-initiated operations only.** Programmatic calls (`grid.sort(...)`, `grid.filter(...)`) do not emit `sorting` / `sorted` / `filtering` / `filtered` events.
|
|
38
|
-
9. **`sorting` and `filtering` events are cancellable** (`event.preventDefault()`) and their `event.detail` is mutable so you can rewrite the expression before it runs.
|
|
39
|
-
10. **For server-side data, set `dataPipelineConfiguration.sort` / `.filter`** — async hooks that receive `{ data, grid, type }` and return the new array. The grid skips its built-in pipeline entirely when a hook is provided for that operation.
|
|
40
|
-
11. **`autoGenerate` is ignored when `columns` is non-empty.** To re-trigger auto-generation after a data swap, set `grid.columns = []` first, then assign the new `data`.
|
|
41
|
-
12. **`grid.rows` only returns currently rendered rows.** The grid uses `@lit-labs/virtualizer`, so off-screen rows are not in the DOM.
|
|
42
|
-
13. **`apex-grid` depends on `igniteui-webcomponents`** for filter/sort UI controls. The package lists it as a runtime dependency — don't try to remove it.
|
|
30
|
+
### 1.1 Install
|
|
43
31
|
|
|
44
|
-
|
|
32
|
+
```bash
|
|
33
|
+
npm install apex-grid lit
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`igniteui-webcomponents` is a regular (transitive) dependency — it installs automatically, and you do **not** import any theme CSS from it.
|
|
45
37
|
|
|
46
|
-
|
|
38
|
+
> Confirmed working versions: `apex-grid@3.0.1`, `lit@^3.0.0`.
|
|
47
39
|
|
|
48
|
-
|
|
40
|
+
### 1.2 Register the element + size the host — `setup()` does both
|
|
41
|
+
|
|
42
|
+
The one-call convenience export registers `<apex-grid>` and adopts a default host stylesheet (`height: 100%` with a `min-height: 240px` fallback) so the virtualizer has a bounded height:
|
|
49
43
|
|
|
50
44
|
```ts
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
import { setup } from 'apex-grid';
|
|
46
|
+
setup(); // registers <apex-grid> + adopts host sizing. Idempotent.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Prefer manual control? Register with the side-effect import (or the static method) and size the host yourself:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import 'apex-grid/define'; // side-effect import, idempotent
|
|
53
|
+
// or: import { ApexGrid } from 'apex-grid'; ApexGrid.register();
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```css
|
|
57
|
+
apex-grid { height: 480px; } /* any explicit height; % works if the parent is sized too */
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`setup({ hostStyles: false })` registers the element but skips the injected host CSS, leaving sizing entirely to you. Without a bounded height (from `setup()` or your own CSS) the grid collapses and shows no rows.
|
|
61
|
+
|
|
62
|
+
> **Do not set `display` on `apex-grid`** — the component declares `:host { display: grid }` for its internal track layout; an outer `display` rule overrides it and collapses the virtualizer.
|
|
63
|
+
|
|
64
|
+
### 1.3 Styling — `--ag-*` CSS custom properties (no theme import)
|
|
65
|
+
|
|
66
|
+
The grid is styled out of the box and customized entirely through `--ag-*` CSS custom properties — there is **no theme file to import and no `configureTheme()` call**. Set the variables on `apex-grid` (or an ancestor):
|
|
67
|
+
|
|
68
|
+
```css
|
|
69
|
+
apex-grid {
|
|
70
|
+
height: 480px;
|
|
71
|
+
/* override any --ag-* variables to retheme; see the package README for the full list */
|
|
62
72
|
}
|
|
63
73
|
```
|
|
64
74
|
|
|
65
|
-
|
|
75
|
+
> The deprecated `theme` option (and `igniteui-webcomponents`' `configureTheme()`) does **not** change the grid's appearance — it only forwards to igniteui for apps that embed igniteui components alongside the grid. Omit it; use `--ag-*` variables instead.
|
|
76
|
+
|
|
77
|
+
### 1.4 Minimal example — a styled, sortable, filterable table
|
|
66
78
|
|
|
67
79
|
```ts
|
|
68
80
|
import { html, render } from 'lit';
|
|
69
|
-
import 'apex-grid
|
|
81
|
+
import { setup } from 'apex-grid';
|
|
70
82
|
import type { ColumnConfiguration } from 'apex-grid';
|
|
71
83
|
|
|
84
|
+
setup(); // register + host sizing; no theme import needed
|
|
85
|
+
|
|
72
86
|
type User = { id: number; name: string; age: number; subscribed: boolean };
|
|
73
87
|
|
|
74
88
|
const data: User[] = [
|
|
75
|
-
{ id: 1, name: 'Ada', age: 36, subscribed: true },
|
|
76
|
-
{ id: 2, name: 'Carl',
|
|
89
|
+
{ id: 1, name: 'Ada Lovelace', age: 36, subscribed: true },
|
|
90
|
+
{ id: 2, name: 'Carl Sagan', age: 62, subscribed: false },
|
|
91
|
+
{ id: 3, name: 'Grace Hopper', age: 85, subscribed: true },
|
|
77
92
|
];
|
|
78
93
|
|
|
94
|
+
// Explicit widths prevent the "last column stretches to fill" trap.
|
|
79
95
|
const columns: ColumnConfiguration<User>[] = [
|
|
80
|
-
{ key: 'id', type: 'number',
|
|
81
|
-
{ key: 'name', type: 'string', sort: true, filter: true },
|
|
82
|
-
{ key: 'age', type: 'number', sort: true, filter: true },
|
|
83
|
-
{ key: 'subscribed', type: 'boolean', sort: true, filter: true },
|
|
96
|
+
{ key: 'id', type: 'number', headerText: 'ID', width: '80px', sort: true, filter: true },
|
|
97
|
+
{ key: 'name', type: 'string', headerText: 'Name', width: '240px', sort: true, filter: true },
|
|
98
|
+
{ key: 'age', type: 'number', headerText: 'Age', width: '100px', sort: true, filter: true },
|
|
99
|
+
{ key: 'subscribed', type: 'boolean', headerText: 'Subscribed', width: '140px', sort: true, filter: true },
|
|
84
100
|
];
|
|
85
101
|
|
|
86
102
|
render(
|
|
@@ -89,322 +105,289 @@ render(
|
|
|
89
105
|
);
|
|
90
106
|
```
|
|
91
107
|
|
|
92
|
-
###
|
|
93
|
-
|
|
94
|
-
The `type` field selects which filter operand set is exposed in the filter UI:
|
|
108
|
+
### 1.5 What success looks like
|
|
95
109
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
| `'boolean'` | `all`, `true`, `false`, `empty`, `notEmpty` |
|
|
101
|
-
|
|
102
|
-
Programmatic filter expressions can reference operands by name (`condition: 'contains'`) or by importing them as a function:
|
|
110
|
+
- **Visible borders** between rows and columns, and **hover state** on rows
|
|
111
|
+
- **Sort arrows** (↕) next to each header (because `sort: true`)
|
|
112
|
+
- A **filter row** below the headers with a "Filter" chip per column (because `filter: true`)
|
|
113
|
+
- **Smooth virtualized scrolling** — only ~20 `<apex-grid-row>` elements exist in the DOM at once, even with thousands of rows
|
|
103
114
|
|
|
104
|
-
|
|
105
|
-
import { StringOperands } from 'apex-grid';
|
|
115
|
+
If rows don't render at all, it's almost always the host height (§1.2). If the grid looks bare, you don't need a theme import — check your `--ag-*` overrides aren't fighting the defaults.
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
// or shorthand
|
|
109
|
-
grid.filter({ key: 'name', condition: 'contains', searchTerm: 'ada' });
|
|
110
|
-
```
|
|
117
|
+
> **Dev-server reminder.** ES module imports need an HTTP server — opening via `file://` fails with CORS errors. Use Vite (`npm create vite@latest`), any static server, or your framework's dev server.
|
|
111
118
|
|
|
112
|
-
|
|
119
|
+
---
|
|
113
120
|
|
|
114
|
-
|
|
121
|
+
## 2. Naming — `apex-grid` vs `<apex-grid>` vs `ApexGrid`
|
|
115
122
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<strong style="color:#1f4ed8">${value}</strong>
|
|
122
|
-
`,
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
key: 'subscribed',
|
|
126
|
-
type: 'boolean',
|
|
127
|
-
cellTemplate: ({ value }) => html`
|
|
128
|
-
<input type="checkbox" .checked=${value} disabled />
|
|
129
|
-
`,
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
key: 'age',
|
|
133
|
-
headerTemplate: ({ column }) => html`
|
|
134
|
-
<em>${column.headerText ?? String(column.key)}</em>
|
|
135
|
-
`,
|
|
136
|
-
},
|
|
137
|
-
];
|
|
138
|
-
```
|
|
123
|
+
| Form | What it is |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `apex-grid` | The **npm package name**. `import { ApexGrid } from 'apex-grid'`. With a hyphen. **There is no `apexgrid` package.** |
|
|
126
|
+
| `<apex-grid>` | The **HTML custom-element tag** rendered into the DOM. |
|
|
127
|
+
| `ApexGrid<T>` | The **exported class**. Used for types, the static `register()` method, and `ApexGrid.tagName`. |
|
|
139
128
|
|
|
140
|
-
|
|
129
|
+
AI models trained before the package was published may suggest `apexgrid` (no hyphen) or treat `ApexGrid` as a class constructor — both are wrong.
|
|
141
130
|
|
|
142
|
-
|
|
143
|
-
interface ApexCellContext<T, K extends keyof T> {
|
|
144
|
-
parent: ApexGridCell<T>; // the cell element
|
|
145
|
-
row: ApexGridRow<T>; // the row element
|
|
146
|
-
column: ColumnConfiguration<T, K>;
|
|
147
|
-
value: T[K];
|
|
148
|
-
}
|
|
131
|
+
---
|
|
149
132
|
|
|
150
|
-
|
|
151
|
-
parent: ApexGridHeader<T>;
|
|
152
|
-
column: ColumnConfiguration<T>;
|
|
153
|
-
}
|
|
154
|
-
```
|
|
133
|
+
## 3. Critical Rules
|
|
155
134
|
|
|
156
|
-
|
|
135
|
+
1. **Apex Grid is a Lit web component, not a JS class with a constructor.** You don't `new ApexGrid(...)`. Render `<apex-grid>` in the DOM and set `.data` / `.columns` as properties.
|
|
157
136
|
|
|
158
|
-
|
|
137
|
+
2. **Two setup steps for a visible grid:** register the element and give the host a bounded height — `setup()` does both (§1.2). **No theme CSS import is required** (§1.3); the grid styles itself via `--ag-*` variables. The classic failure is an unsized host → no rows.
|
|
159
138
|
|
|
160
|
-
|
|
161
|
-
grid.columns = []; // reset first
|
|
162
|
-
grid.data = newData; // then replace data — columns are inferred
|
|
163
|
-
```
|
|
139
|
+
3. **`columns` and `data` are properties, not attributes.** Use property binding (`.columns=${...}` in Lit, `[columns]=` in Angular, `:columns.prop=` in Vue, `el.columns = ...` in vanilla JS). A stringified `columns="[...]"` HTML attribute becomes the literal string and the grid renders nothing.
|
|
164
140
|
|
|
165
|
-
|
|
141
|
+
4. **`column.key` must be a real `keyof T`.** No `field` / `dataIndex` / `accessor` aliases. To display a derived value, compute it in `cellTemplate` (which has `row` access).
|
|
166
142
|
|
|
167
|
-
|
|
143
|
+
5. **Set `type` per column.** The primitive types `'string'`, `'number'`, `'boolean'` drive the default sort comparer, filter operands, and editor. The default is `'string'` — leaving a numeric column unset sorts as strings ("10" before "9"). There are also presentation types — `'select'`, `'rating'`, `'date'`, `'image'`, `'currency'`, `'avatar'`, `'badge'`, `'progress'`, `'sparkline'`, `'status'` — that change rendering while sorting/filtering as their underlying value (§4).
|
|
168
144
|
|
|
169
|
-
|
|
145
|
+
6. **`cellTemplate` / `headerTemplate` / `editorTemplate` must return Lit `TemplateResult`s** — values from an `` html`...` `` tagged template. Returning a plain string renders as escaped text.
|
|
170
146
|
|
|
171
|
-
|
|
172
|
-
|---|---|---|---|
|
|
173
|
-
| `data` | `T[]` | `[]` | Row data. Setting it triggers a pipeline run. |
|
|
174
|
-
| `columns` | `ColumnConfiguration<T>[]` | `[]` | Column definitions. Each entry is merged with `DEFAULT_COLUMN_CONFIG`. |
|
|
175
|
-
| `autoGenerate` | `boolean` (attr `auto-generate`) | `false` | Infer columns from data. Ignored when `columns` is non-empty. |
|
|
176
|
-
| `sortConfiguration` | `{ multiple: boolean; triState: boolean }` | `{ true, true }` | Grid-wide sort behaviour. |
|
|
177
|
-
| `dataPipelineConfiguration` | `{ sort?, filter? }` | — | Server-side / async data hooks. |
|
|
178
|
-
| `sortExpressions` | `SortExpression<T>[]` | `[]` | Get/set the active sort state. Setting an empty array is a no-op — use `clearSort()`. |
|
|
179
|
-
| `filterExpressions` | `FilterExpression<T>[]` | `[]` | Get/set the active filter state. Empty-set semantics same as above. |
|
|
180
|
-
| `rows` | `ApexGridRow<T>[]` *(getter)* | — | Currently rendered rows only (virtualized). |
|
|
181
|
-
| `dataView` | `readonly T[]` *(getter)* | — | Data after sort + filter pipeline. |
|
|
182
|
-
| `totalItems` | `number` *(getter)* | — | `dataView.length`. |
|
|
147
|
+
7. **Sort/filter (and the other `*-ing`/`*-ed`) events fire only for UI-initiated operations.** Programmatic `grid.sort(...)` / `grid.filter(...)` calls apply silently. To react to every change regardless of source, watch `grid.dataView`.
|
|
183
148
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
| Method | Description |
|
|
187
|
-
|---|---|
|
|
188
|
-
| `sort(expr \| expr[])` | Apply a sort. Does **not** fire `sorting` / `sorted` events. |
|
|
189
|
-
| `filter(expr \| expr[])` | Apply a filter. Does **not** fire `filtering` / `filtered` events. |
|
|
190
|
-
| `clearSort(key?)` | Clear all sort state, or just the column with `key`. |
|
|
191
|
-
| `clearFilter(key?)` | Clear all filter state, or just the column with `key`. |
|
|
192
|
-
| `getColumn(keyOrIndex)` | Find a column by `key` or numeric index. |
|
|
193
|
-
| `updateColumns(col \| col[])` | Merge new properties into existing columns by `key`. Triggers a pipeline run. |
|
|
194
|
-
|
|
195
|
-
### Static
|
|
196
|
-
|
|
197
|
-
| Member | Description |
|
|
198
|
-
|---|---|
|
|
199
|
-
| `ApexGrid.tagName` | The string `'apex-grid'`. |
|
|
200
|
-
| `ApexGrid.register()` | Registers `<apex-grid>` and all internal sub-components. Idempotent. Either call this once, or import `'apex-grid/define'` for auto-registration. |
|
|
149
|
+
8. **Features are opt-in via config objects.** Sorting/filtering are per-column (`sort`/`filter`); editing, selection, pagination, tree, and master-detail expansion are enabled via the grid-level `editing` / `selection` / `pagination` / `tree` / `expansion` properties (§5).
|
|
201
150
|
|
|
202
151
|
---
|
|
203
152
|
|
|
204
|
-
## 4.
|
|
153
|
+
## 4. Data & Columns
|
|
205
154
|
|
|
206
|
-
|
|
155
|
+
Apex Grid is generic over a row type `T extends object`:
|
|
207
156
|
|
|
208
157
|
```ts
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
//
|
|
229
|
-
|
|
158
|
+
interface ColumnConfiguration<T extends object, K extends keyof T = keyof T> {
|
|
159
|
+
key: K; // REQUIRED — must be a keyof T
|
|
160
|
+
type?: DataType; // default 'string' (see column types below)
|
|
161
|
+
headerText?: string; // default: String(key)
|
|
162
|
+
width?: string; // any CSS width — recommended in practice
|
|
163
|
+
hidden?: boolean; // default false
|
|
164
|
+
resizable?: boolean; // default false
|
|
165
|
+
pinned?: 'start' | 'end' | null; // freeze to a side during horizontal scroll
|
|
166
|
+
reorderable?: boolean; // per-column opt-out of drag reorder
|
|
167
|
+
exportable?: boolean; // default true; false omits from CSV export
|
|
168
|
+
sort?: boolean | { caseSensitive?: boolean; comparer?: (a: T[K], b: T[K]) => number };
|
|
169
|
+
filter?: boolean | { caseSensitive?: boolean };
|
|
170
|
+
editable?: boolean; // requires grid `editing.enabled`
|
|
171
|
+
headerTemplate?: (ctx: ApexHeaderContext<T>) => TemplateResult | unknown;
|
|
172
|
+
cellTemplate?: (ctx: ApexCellContext<T, K>) => TemplateResult | unknown;
|
|
173
|
+
editorTemplate?: (ctx: ApexEditorContext<T, K>) => TemplateResult | unknown;
|
|
174
|
+
// Type-specific options (each is ignored unless `type` matches):
|
|
175
|
+
options?: (V | { value: V; label?: string })[]; // type: 'select'
|
|
176
|
+
max?: number; // 'rating' star count (5) / 'progress' full value (100)
|
|
177
|
+
format?: 'short' | 'medium' | 'long' | 'full'; // 'date' display (default 'medium')
|
|
178
|
+
shape?: 'square' | 'circle'; // 'image' crop (default 'square')
|
|
179
|
+
alt?: string; // 'image' alt text
|
|
180
|
+
currency?: string; // 'currency' ISO 4217 code (default 'USD')
|
|
181
|
+
locale?: string; // 'currency' BCP 47 locale
|
|
182
|
+
badgeVariant?: 'gold' | 'brand' | 'neutral' | 'muted' | ((v) => …); // 'badge'
|
|
183
|
+
statusVariant?: 'active' | 'trial' | 'churn' | ((v) => …); // 'status'
|
|
184
|
+
showDelta?: boolean; // 'sparkline' trailing delta label (default true)
|
|
185
|
+
}
|
|
230
186
|
```
|
|
231
187
|
|
|
232
|
-
|
|
233
|
-
|---|---|---|
|
|
234
|
-
| `sorting` | yes | `SortExpression<T>` (mutable) |
|
|
235
|
-
| `sorted` | no | `SortExpression<T>` |
|
|
236
|
-
| `filtering` | yes | `{ key: keyof T; expressions: FilterExpression<T>[]; type: 'add' \| 'modify' \| 'remove' }` |
|
|
237
|
-
| `filtered` | no | `{ key: keyof T; state: FilterExpression<T>[] }` |
|
|
188
|
+
Applied defaults (`DEFAULT_COLUMN_CONFIG`): `{ type: 'string', resizable: false, hidden: false, sort: false, filter: false }`. Sort and filter are **off** until you opt in. (`exportable` isn't in that object but behaves as `true` unless set to `false`.)
|
|
238
189
|
|
|
239
|
-
|
|
190
|
+
### Column types (`DataType`)
|
|
240
191
|
|
|
241
|
-
|
|
192
|
+
`type` is both the data type and, for the built-ins, the presentation renderer. The three primitive types drive sort/filter/editing; the rest are renderers over a primitive value (and sort/filter as that underlying value):
|
|
242
193
|
|
|
243
|
-
|
|
194
|
+
| `type` | Renders / behaves as |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `'string'` | text (default); text editor |
|
|
197
|
+
| `'number'` | number; number editor |
|
|
198
|
+
| `'boolean'` | check-mark icon (true) / dimmed (false); checkbox editor |
|
|
199
|
+
| `'select'` | label from `options`; `<select>` editor. Sorts/filters as its value |
|
|
200
|
+
| `'rating'` | 0..`max` (default 5) as stars; star-picker editor. Numeric |
|
|
201
|
+
| `'date'` | locale date (`format` preset); `<input type="date">` editor. Accepts `Date`/ISO/timestamp |
|
|
202
|
+
| `'image'` | `<img>` (`shape` `'square'`/`'circle'`, `alt`) |
|
|
203
|
+
| `'currency'` | `Intl.NumberFormat` (`currency`, `locale`). Numeric |
|
|
204
|
+
| `'avatar'` | first letter in a tinted circle |
|
|
205
|
+
| `'badge'` | colored pill (`badgeVariant`) |
|
|
206
|
+
| `'progress'` | health bar, 0..`max` (default 100) |
|
|
207
|
+
| `'sparkline'` | inline trend chart of a `number[]` (`showDelta`) |
|
|
208
|
+
| `'status'` | dot + pill (`statusVariant`, or inferred) |
|
|
209
|
+
|
|
210
|
+
> A `'date'` column **does** exist in 3.x — use `type: 'date'` (it accepts `Date`, ISO strings, or millisecond timestamps), not a string column with a custom comparer.
|
|
211
|
+
|
|
212
|
+
### Column type → filter operands (primitive types)
|
|
213
|
+
|
|
214
|
+
| `type` | Operand keys in the filter UI |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `'string'` | `contains`, `doesNotContain`, `startsWith`, `endsWith`, `equals`, `doesNotEqual`, `empty`, `notEmpty` |
|
|
217
|
+
| `'number'` | `equals`, `doesNotEqual`, `greaterThan`, `lessThan`, `greaterThanOrEqual`, `lessThanOrEqual`, `empty`, `notEmpty` |
|
|
218
|
+
| `'boolean'` | `all`, `true`, `false`, `empty`, `notEmpty` (all **unary** — no `searchTerm`) |
|
|
244
219
|
|
|
245
220
|
```ts
|
|
246
|
-
grid.
|
|
247
|
-
sort: async ({ data, grid }) => {
|
|
248
|
-
const expressions = grid.sortExpressions;
|
|
249
|
-
return fetch('/api/users/sort', {
|
|
250
|
-
method: 'POST',
|
|
251
|
-
body: JSON.stringify(expressions),
|
|
252
|
-
}).then((r) => r.json());
|
|
253
|
-
},
|
|
254
|
-
filter: async ({ data, grid }) => {
|
|
255
|
-
const expressions = grid.filterExpressions;
|
|
256
|
-
return fetch('/api/users/filter', {
|
|
257
|
-
method: 'POST',
|
|
258
|
-
body: JSON.stringify(expressions),
|
|
259
|
-
}).then((r) => r.json());
|
|
260
|
-
},
|
|
261
|
-
};
|
|
221
|
+
grid.filter({ key: 'subscribed', condition: 'true' }); // unary — no searchTerm
|
|
262
222
|
```
|
|
263
223
|
|
|
264
|
-
|
|
224
|
+
### Cell template
|
|
265
225
|
|
|
266
|
-
|
|
226
|
+
Receives `ApexCellContext<T, K>` (`{ parent, row, column, value, commit? }`). Must return a Lit `TemplateResult`:
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
import { html } from 'lit';
|
|
267
230
|
|
|
268
|
-
|
|
231
|
+
{ key: 'name', cellTemplate: ({ value, row }) => html`<strong>${value}</strong>` }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Auto-generated columns — the 3-line demo
|
|
269
235
|
|
|
270
236
|
```ts
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// Single sort
|
|
274
|
-
grid.sort({ key: 'name', direction: 'ascending' });
|
|
275
|
-
|
|
276
|
-
// Multiple (multi-column) sort — works only when sortConfiguration.multiple is true
|
|
277
|
-
grid.sort([
|
|
278
|
-
{ key: 'subscribed', direction: 'descending' },
|
|
279
|
-
{ key: 'age', direction: 'ascending' },
|
|
280
|
-
]);
|
|
281
|
-
|
|
282
|
-
// Filter — by operand name
|
|
283
|
-
grid.filter({ key: 'name', condition: 'contains', searchTerm: 'ad' });
|
|
284
|
-
|
|
285
|
-
// Filter — by operand object (typed)
|
|
286
|
-
grid.filter({ key: 'name', condition: StringOperands.contains, searchTerm: 'ad' });
|
|
287
|
-
|
|
288
|
-
// Multiple filters with AND/OR
|
|
289
|
-
grid.filter([
|
|
290
|
-
{ key: 'age', condition: 'greaterThan', searchTerm: 30 },
|
|
291
|
-
{ key: 'age', condition: 'lessThan', searchTerm: 50, criteria: 'and' },
|
|
292
|
-
]);
|
|
293
|
-
|
|
294
|
-
// Clear
|
|
295
|
-
grid.clearSort(); // all columns
|
|
296
|
-
grid.clearSort('name'); // just `name`
|
|
297
|
-
grid.clearFilter();
|
|
298
|
-
grid.clearFilter('name');
|
|
237
|
+
render(html`<apex-grid auto-generate .data=${data}></apex-grid>`, document.getElementById('app')!);
|
|
299
238
|
```
|
|
300
239
|
|
|
301
|
-
`
|
|
240
|
+
Auto-generates columns from `Object.keys(data[0])` and runtime types. `sort` / `filter` default to `false`, so the auto path is read-only. To re-trigger after a data swap, reset `grid.columns = []` first.
|
|
241
|
+
|
|
242
|
+
For full column patterns — derived columns, header/editor templates, per-column styling — see `references/columns-and-templates.md`.
|
|
302
243
|
|
|
303
244
|
---
|
|
304
245
|
|
|
305
|
-
##
|
|
246
|
+
## 5. Lifecycle & API
|
|
247
|
+
|
|
248
|
+
### Lifecycle pattern
|
|
306
249
|
|
|
307
250
|
```ts
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
// — or —
|
|
311
|
-
import { ApexGrid } from 'apex-grid';
|
|
312
|
-
ApexGrid.register();
|
|
251
|
+
import { setup } from 'apex-grid';
|
|
252
|
+
setup(); // register + host sizing; no theme import
|
|
313
253
|
|
|
314
|
-
// 2. Stamp the element into the DOM
|
|
315
254
|
import { html, render } from 'lit';
|
|
316
255
|
render(html`<apex-grid></apex-grid>`, document.getElementById('app')!);
|
|
317
256
|
|
|
318
|
-
// 3. Set properties (after the element is in the DOM)
|
|
319
257
|
const grid = document.querySelector('apex-grid')!;
|
|
320
|
-
grid.columns =
|
|
321
|
-
grid.data =
|
|
258
|
+
grid.columns = columns; // properties, after element is in DOM
|
|
259
|
+
grid.data = data;
|
|
322
260
|
|
|
323
|
-
|
|
324
|
-
grid.
|
|
261
|
+
grid.addEventListener('sorted', (e) => {}); // UI events
|
|
262
|
+
grid.sort({ key: 'name', direction: 'ascending' }); // programmatic (silent)
|
|
325
263
|
|
|
326
|
-
//
|
|
327
|
-
|
|
264
|
+
// No destroy() — removing the element triggers Lit's disconnectedCallback automatically.
|
|
265
|
+
```
|
|
328
266
|
|
|
329
|
-
|
|
330
|
-
|
|
267
|
+
### Core properties
|
|
268
|
+
|
|
269
|
+
| Property | Type | Notes |
|
|
270
|
+
|---|---|---|
|
|
271
|
+
| `data` | `T[]` | Setting triggers a pipeline run. |
|
|
272
|
+
| `columns` | `ColumnConfiguration<T>[]` | Each entry merged with column defaults. |
|
|
273
|
+
| `autoGenerate` (attr `auto-generate`) | `boolean` | Ignored if `columns` is non-empty. |
|
|
274
|
+
| `sortConfiguration` | `{ multiple, triState }` | Multi-column + tri-state sorting toggles. |
|
|
275
|
+
| `dataPipelineConfiguration` | `{ sort?, filter?, pagination?, quickFilter? }` | Server-side / async hooks (§ data-pipeline). |
|
|
276
|
+
| `quickFilter` (attr `quick-filter`) | `string` | Global substring search across visible columns. |
|
|
277
|
+
| `showQuickFilter` / `showExport` | `boolean` | Toolbar UI toggles for quick-filter input / export menu. |
|
|
278
|
+
| `columnReordering` (attr `column-reordering`) | `boolean` | Drag-reorder headers; per-column opt-out via `reorderable`. |
|
|
279
|
+
| `sortExpressions` / `filterExpressions` | `…[]` (get/set) | Current state. To clear, use `clearSort()` / `clearFilter()`. |
|
|
280
|
+
| `selectedRows` / `expandedRows` | `T[]` (get/set) | Snapshots; set to replace (goes through cancellable events). |
|
|
281
|
+
| `rows` *(getter)* | `ApexGridRow<T>[]` | **Currently rendered only** (virtualized). |
|
|
282
|
+
| `dataView` *(getter)* | `readonly T[]` | Full post-filter/sort data. |
|
|
283
|
+
| `pageItems` *(getter)* | `readonly T[]` | Current page slice (= `dataView` if no pagination). |
|
|
284
|
+
| `totalItems` / `pageCount` *(getters)* | `number` | Row / page totals. |
|
|
285
|
+
| `page` / `pageSize` | `number` (get/set) | Current page (0-based) / page size. |
|
|
286
|
+
|
|
287
|
+
### Feature config properties (opt-in)
|
|
288
|
+
|
|
289
|
+
| Property | Shape |
|
|
290
|
+
|---|---|
|
|
291
|
+
| `editing` | `{ enabled, mode?: 'cell' \| 'row', trigger?: 'click' \| 'doubleClick' }` — plus per-column `editable: true` |
|
|
292
|
+
| `selection` | `{ enabled, mode?: 'single' \| 'multiple', showCheckboxColumn? }` |
|
|
293
|
+
| `pagination` | `{ enabled, mode?: 'local' \| 'remote', page?, pageSize?, pageSizeOptions?, totalItems? }` |
|
|
294
|
+
| `tree` | `{ enabled, getDataPath: (row) => string[], groupColumnKey?, defaultExpanded?, childIndent? }` — flat data, hierarchy derived |
|
|
295
|
+
| `expansion` | `{ enabled, detailTemplate: (ctx) => TemplateResult, isExpandable?, showToggleColumn? }` — master-detail |
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
grid.editing = { enabled: true, mode: 'cell', trigger: 'doubleClick' };
|
|
299
|
+
grid.selection = { enabled: true, mode: 'multiple', showCheckboxColumn: true };
|
|
300
|
+
grid.pagination = { enabled: true, pageSize: 25 };
|
|
331
301
|
```
|
|
332
302
|
|
|
303
|
+
### Methods
|
|
304
|
+
|
|
305
|
+
| Method | Description |
|
|
306
|
+
|---|---|
|
|
307
|
+
| `sort(expr \| expr[])` / `filter(expr \| expr[])` | Programmatic. **No events.** |
|
|
308
|
+
| `clearSort(key?)` / `clearFilter(key?)` | Clear all, or one column's, sort/filter state. |
|
|
309
|
+
| `getColumn(keyOrIndex)` | Find a column. |
|
|
310
|
+
| `updateColumns(col \| col[])` | Merge new fields into existing columns by `key`. Triggers a pipeline run. |
|
|
311
|
+
| `moveColumn(fromKey, toKey, position?)` | Reorder a column (within its pinning group). |
|
|
312
|
+
| `exportToCSV(options?)` / `exportAs(formatId, options?)` | Export the data. CSV is built in. |
|
|
313
|
+
| selection | `selectRow`, `deselectRow`, `toggleRowSelection`, `selectAllRows`, `clearSelection`, `isRowSelected` |
|
|
314
|
+
| expansion | `expandRow`, `collapseRow`, `toggleRowExpansion`, `expandAllRows`, `collapseAllRows`, `isRowExpanded` |
|
|
315
|
+
| tree | `expandTreeRow`, `collapseTreeRow`, `toggleTreeRow`, `expandAllTreeRows`, `collapseAllTreeRows`, `isTreeRowExpanded` |
|
|
316
|
+
| editing | `commitEdit()`, `cancelEdit()` (used with `mode: 'row'`) |
|
|
317
|
+
| `ApexGrid.register()` / `ApexGrid.tagName` | Static element registration / `'apex-grid'`. |
|
|
318
|
+
|
|
319
|
+
### Events — UI-initiated only
|
|
320
|
+
|
|
321
|
+
Every event fires only for operations driven through the grid's own UI; programmatic API calls are silent. The `*-ing` events are **cancellable** (call `event.preventDefault()`); the `*-ed` events are notifications. `event.detail` carries the relevant payload.
|
|
322
|
+
|
|
323
|
+
| Pairs (`-ing` cancellable / `-ed` after) | Triggered by |
|
|
324
|
+
|---|---|
|
|
325
|
+
| `sorting` / `sorted` | header sort |
|
|
326
|
+
| `filtering` / `filtered` | filter-row change |
|
|
327
|
+
| `quickFilterChanging` / `quickFilterChanged` | quick-filter input |
|
|
328
|
+
| `pageChanging` / `pageChanged` | paginator |
|
|
329
|
+
| `columnPinning` / `columnPinned` | pin/unpin |
|
|
330
|
+
| `columnMoving` / `columnMoved` | header drag reorder |
|
|
331
|
+
| `cellValueChanging` / `cellValueChanged` | inline edit commit |
|
|
332
|
+
| `rowEditStarted` / `rowEditEnded` | row-edit session (`mode: 'row'`) |
|
|
333
|
+
| `rowSelecting` / `rowSelected` | row selection |
|
|
334
|
+
| `rowExpanding` / `rowExpanded` | master-detail expand |
|
|
335
|
+
| `treeRowExpanding` / `treeRowExpanded` | tree-row expand |
|
|
336
|
+
|
|
337
|
+
Operand reference, multi-column sort, and server-side hooks: `references/sort-and-filter.md` and `references/data-pipeline.md`.
|
|
338
|
+
|
|
333
339
|
---
|
|
334
340
|
|
|
335
|
-
##
|
|
341
|
+
## 6. Pitfalls — ❌ Wrong vs ✅ Correct
|
|
336
342
|
|
|
337
|
-
### 1. Treating it like a class
|
|
338
|
-
❌ `const grid = new ApexGrid({ container: '#app', columns, data })`
|
|
339
|
-
✅ Render `<apex-grid .data=${data} .columns=${columns}></apex-grid
|
|
343
|
+
### 1. Treating it like a class API
|
|
344
|
+
❌ `const grid = new ApexGrid({ container: '#app', columns, data })`
|
|
345
|
+
✅ Render `<apex-grid .data=${data} .columns=${columns}></apex-grid>`.
|
|
340
346
|
|
|
341
347
|
### 2. Forgetting to register the element
|
|
342
|
-
❌ Importing `ApexGrid` but never
|
|
343
|
-
✅ `import 'apex-grid/define'` once
|
|
348
|
+
❌ Importing `ApexGrid` but never registering.
|
|
349
|
+
✅ `setup()` (or `import 'apex-grid/define'`) once at app startup.
|
|
344
350
|
|
|
345
|
-
### 3.
|
|
346
|
-
❌ `import
|
|
347
|
-
✅
|
|
351
|
+
### 3. Importing a theme CSS that no longer exists
|
|
352
|
+
❌ `import 'igniteui-webcomponents/themes/light/bootstrap.css'` + `configureTheme('bootstrap')` — obsolete; does not affect the grid.
|
|
353
|
+
✅ Nothing to import — the grid styles itself; retheme via `--ag-*` CSS variables. The only required CSS is a host **height**.
|
|
348
354
|
|
|
349
355
|
### 4. Stringified `columns` attribute
|
|
350
|
-
❌ `<apex-grid columns="[...]">` —
|
|
351
|
-
✅ Property binding: `.columns=${columns}`
|
|
356
|
+
❌ `<apex-grid columns="[...]">` — becomes the literal string `"[object Object],..."`.
|
|
357
|
+
✅ Property binding: `.columns=${columns}` / `:columns.prop="columns"` / `[columns]="columns"` / `el.columns = columns`.
|
|
352
358
|
|
|
353
359
|
### 5. `column.key` not a real key of `T`
|
|
354
|
-
❌ `{ key: 'fullName' }` when `User` has only `firstName`
|
|
355
|
-
✅
|
|
360
|
+
❌ `{ key: 'fullName' }` when `User` has only `firstName` + `lastName`.
|
|
361
|
+
✅ Compute via template: `cellTemplate: ({ row }) => html\`${row.firstName} ${row.lastName}\``.
|
|
356
362
|
|
|
357
|
-
### 6.
|
|
363
|
+
### 6. String from `cellTemplate`
|
|
358
364
|
❌ `cellTemplate: ({ value }) => \`<strong>\${value}</strong>\`` — renders as escaped text.
|
|
359
365
|
✅ `cellTemplate: ({ value }) => html\`<strong>\${value}</strong>\``.
|
|
360
366
|
|
|
361
|
-
### 7.
|
|
362
|
-
❌
|
|
363
|
-
✅
|
|
364
|
-
|
|
365
|
-
### 8. `sort: true` without setting `type`
|
|
366
|
-
❌ Sorting numbers as strings: `{ key: 'age', sort: true }` with no `type`.
|
|
367
|
-
✅ `{ key: 'age', type: 'number', sort: true }` — gets the correct comparer and filter operands.
|
|
368
|
-
|
|
369
|
-
### 9. Looking for a `'date'` column type
|
|
370
|
-
❌ `{ key: 'created', type: 'date' }` — there is no `'date'` type.
|
|
371
|
-
✅ Store dates as numbers (timestamps) with `type: 'number'`, or as ISO strings with a custom `sort.comparer` and a `cellTemplate` that formats:
|
|
372
|
-
```ts
|
|
373
|
-
{
|
|
374
|
-
key: 'created',
|
|
375
|
-
type: 'string',
|
|
376
|
-
sort: { comparer: (a, b) => a.localeCompare(b) },
|
|
377
|
-
cellTemplate: ({ value }) => html`${new Date(value).toLocaleDateString()}`,
|
|
378
|
-
}
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
### 10. Calling `clearSort()` to flush an empty array
|
|
382
|
-
❌ `grid.sortExpressions = []` — the setter is a no-op for empty arrays.
|
|
383
|
-
✅ `grid.clearSort()`.
|
|
367
|
+
### 7. Numbers sorted as strings
|
|
368
|
+
❌ `{ key: 'age', sort: true }` (default `type: 'string'`) — "10" sorts before "9".
|
|
369
|
+
✅ `{ key: 'age', type: 'number', sort: true }`.
|
|
384
370
|
|
|
385
|
-
###
|
|
386
|
-
❌ `
|
|
387
|
-
✅
|
|
371
|
+
### 8. Reaching for a custom comparer to display dates
|
|
372
|
+
❌ `{ key: 'created', type: 'string', sort: { comparer: ... } }` to fake date handling.
|
|
373
|
+
✅ `{ key: 'created', type: 'date', format: 'medium' }` — a real type; accepts `Date`, ISO strings, or millisecond timestamps and sorts chronologically.
|
|
388
374
|
|
|
389
|
-
###
|
|
390
|
-
❌
|
|
391
|
-
✅
|
|
375
|
+
### 9. Clearing sort/filter
|
|
376
|
+
❌ Assuming you must rebuild state to clear it.
|
|
377
|
+
✅ `grid.clearSort()` / `grid.clearFilter()` (optionally per `key`).
|
|
392
378
|
|
|
393
|
-
###
|
|
394
|
-
❌
|
|
395
|
-
✅
|
|
396
|
-
|
|
397
|
-
### 14. Rendering before `register()` in the same task
|
|
398
|
-
❌ Stamping `<apex-grid>` before the registration import has resolved — the element is upgraded later but properties set before upgrade may be lost.
|
|
399
|
-
✅ Import `'apex-grid/define'` at the top of your entry file, then render.
|
|
379
|
+
### 10. Expecting events from programmatic operations
|
|
380
|
+
❌ Listening for `sorting` after calling `grid.sort(...)` — never fires.
|
|
381
|
+
✅ Wrap the programmatic call yourself, or watch `grid.dataView` for any state change.
|
|
400
382
|
|
|
401
383
|
---
|
|
402
384
|
|
|
403
|
-
##
|
|
385
|
+
## 7. Reference Routing Table
|
|
404
386
|
|
|
405
387
|
| Topic | Reference File |
|
|
406
388
|
|---|---|
|
|
407
|
-
| Column
|
|
408
|
-
| Sort & filter —
|
|
409
|
-
| Server-side data
|
|
410
|
-
|
|
|
389
|
+
| Column types, templates, auto-generation, per-column styling, header/editor templates | `references/columns-and-templates.md` |
|
|
390
|
+
| Sort & filter — operands, expressions, multi-column, quick-filter, events | `references/sort-and-filter.md` |
|
|
391
|
+
| Server-side data hooks (sort/filter/pagination/quickFilter), virtualization, `dataView` | `references/data-pipeline.md` |
|
|
392
|
+
| End-to-end vanilla JS (no Lit `render`) | `references/vanilla-js.md` |
|
|
393
|
+
| Lit, React, Vue, Angular integration | `references/framework-integration.md` |
|