@toolbox-web/grid-react 0.0.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/README.md +402 -0
- package/index.d.ts +12 -0
- package/index.d.ts.map +1 -0
- package/index.js +541 -0
- package/lib/context-types.d.ts +48 -0
- package/lib/context-types.d.ts.map +1 -0
- package/lib/data-grid.d.ts +155 -0
- package/lib/data-grid.d.ts.map +1 -0
- package/lib/grid-column.d.ts +117 -0
- package/lib/grid-column.d.ts.map +1 -0
- package/lib/grid-detail-panel.d.ts +88 -0
- package/lib/grid-detail-panel.d.ts.map +1 -0
- package/lib/grid-tool-button.d.ts +31 -0
- package/lib/grid-tool-button.d.ts.map +1 -0
- package/lib/grid-tool-panel.d.ts +98 -0
- package/lib/grid-tool-panel.d.ts.map +1 -0
- package/lib/react-column-config.d.ts +71 -0
- package/lib/react-column-config.d.ts.map +1 -0
- package/lib/react-grid-adapter.d.ts +107 -0
- package/lib/react-grid-adapter.d.ts.map +1 -0
- package/lib/use-grid-event.d.ts +73 -0
- package/lib/use-grid-event.d.ts.map +1 -0
- package/lib/use-grid.d.ts +63 -0
- package/lib/use-grid.d.ts.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
# @toolbox-web/grid-react
|
|
2
|
+
|
|
3
|
+
React adapter library for [@toolbox-web/grid](https://www.npmjs.com/package/@toolbox-web/grid) - a high-performance, framework-agnostic data grid web component.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @toolbox-web/grid @toolbox-web/grid-react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { DataGrid, GridColumn } from '@toolbox-web/grid-react';
|
|
15
|
+
|
|
16
|
+
interface Employee {
|
|
17
|
+
id: number;
|
|
18
|
+
name: string;
|
|
19
|
+
department: string;
|
|
20
|
+
salary: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function EmployeeGrid() {
|
|
24
|
+
const [employees, setEmployees] = useState<Employee[]>([
|
|
25
|
+
{ id: 1, name: 'Alice', department: 'Engineering', salary: 95000 },
|
|
26
|
+
{ id: 2, name: 'Bob', department: 'Marketing', salary: 75000 },
|
|
27
|
+
{ id: 3, name: 'Charlie', department: 'Sales', salary: 85000 },
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<DataGrid
|
|
32
|
+
rows={employees}
|
|
33
|
+
columns={[
|
|
34
|
+
{ field: 'id', header: 'ID', width: 60 },
|
|
35
|
+
{ field: 'name', header: 'Name', sortable: true },
|
|
36
|
+
{ field: 'department', header: 'Department', sortable: true },
|
|
37
|
+
{ field: 'salary', header: 'Salary', type: 'number' },
|
|
38
|
+
]}
|
|
39
|
+
onRowsChange={setEmployees}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Custom Cell Renderers
|
|
46
|
+
|
|
47
|
+
There are two ways to define custom renderers: inline in the configuration, or via `GridColumn` components.
|
|
48
|
+
|
|
49
|
+
### Inline Configuration (Recommended)
|
|
50
|
+
|
|
51
|
+
Define renderers directly in your `ReactGridConfig`:
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { DataGrid, type ReactGridConfig } from '@toolbox-web/grid-react';
|
|
55
|
+
|
|
56
|
+
const config: ReactGridConfig<Employee> = {
|
|
57
|
+
columns: [
|
|
58
|
+
{ field: 'name', header: 'Name' },
|
|
59
|
+
{
|
|
60
|
+
field: 'status',
|
|
61
|
+
header: 'Status',
|
|
62
|
+
// Custom React renderer - same property name as vanilla!
|
|
63
|
+
renderer: (ctx) => (
|
|
64
|
+
<span className={`badge badge-${ctx.value.toLowerCase()}`}>
|
|
65
|
+
{ctx.value}
|
|
66
|
+
</span>
|
|
67
|
+
),
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
function EmployeeGrid() {
|
|
73
|
+
return <DataGrid rows={employees} gridConfig={config} />;
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Using GridColumn Components
|
|
78
|
+
|
|
79
|
+
Use the `GridColumn` component with a render prop:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { DataGrid, GridColumn } from '@toolbox-web/grid-react';
|
|
83
|
+
|
|
84
|
+
function StatusBadge({ status }: { status: string }) {
|
|
85
|
+
return <span className={`badge badge-${status.toLowerCase()}`}>{status}</span>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function EmployeeGrid() {
|
|
89
|
+
return (
|
|
90
|
+
<DataGrid rows={employees}>
|
|
91
|
+
<GridColumn field="name" header="Name" />
|
|
92
|
+
<GridColumn field="status">{(ctx) => <StatusBadge status={ctx.value} />}</GridColumn>
|
|
93
|
+
</DataGrid>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Custom Cell Editors
|
|
99
|
+
|
|
100
|
+
Define editors inline in your configuration or via `GridColumn`:
|
|
101
|
+
|
|
102
|
+
### Inline Configuration
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
const config: ReactGridConfig<Employee> = {
|
|
106
|
+
columns: [
|
|
107
|
+
{
|
|
108
|
+
field: 'status',
|
|
109
|
+
header: 'Status',
|
|
110
|
+
editable: true,
|
|
111
|
+
renderer: (ctx) => <StatusBadge status={ctx.value} />,
|
|
112
|
+
editor: (ctx) => (
|
|
113
|
+
<select
|
|
114
|
+
defaultValue={ctx.value}
|
|
115
|
+
autoFocus
|
|
116
|
+
onChange={(e) => ctx.commit(e.target.value)}
|
|
117
|
+
onKeyDown={(e) => e.key === 'Escape' && ctx.cancel()}
|
|
118
|
+
>
|
|
119
|
+
<option value="active">Active</option>
|
|
120
|
+
<option value="inactive">Inactive</option>
|
|
121
|
+
</select>
|
|
122
|
+
),
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Using GridColumn
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
<DataGrid rows={employees}>
|
|
132
|
+
<GridColumn
|
|
133
|
+
field="name"
|
|
134
|
+
editable
|
|
135
|
+
editor={(ctx) => (
|
|
136
|
+
<input
|
|
137
|
+
autoFocus
|
|
138
|
+
defaultValue={ctx.value}
|
|
139
|
+
onBlur={(e) => ctx.commit(e.target.value)}
|
|
140
|
+
onKeyDown={(e) => {
|
|
141
|
+
if (e.key === 'Enter') ctx.commit(e.currentTarget.value);
|
|
142
|
+
if (e.key === 'Escape') ctx.cancel();
|
|
143
|
+
}}
|
|
144
|
+
/>
|
|
145
|
+
)}
|
|
146
|
+
/>
|
|
147
|
+
</DataGrid>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Master-Detail with GridDetailPanel
|
|
151
|
+
|
|
152
|
+
Create expandable row details using the `GridDetailPanel` component:
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { DataGrid, GridDetailPanel } from '@toolbox-web/grid-react';
|
|
156
|
+
import { MasterDetailPlugin } from '@toolbox-web/grid/all';
|
|
157
|
+
|
|
158
|
+
function EmployeeGrid() {
|
|
159
|
+
const config: ReactGridConfig<Employee> = {
|
|
160
|
+
columns: [...],
|
|
161
|
+
plugins: [new MasterDetailPlugin()],
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<DataGrid rows={employees} gridConfig={config}>
|
|
166
|
+
<GridDetailPanel showExpandColumn animation="slide">
|
|
167
|
+
{({ row, rowIndex }) => (
|
|
168
|
+
<div className="detail-panel">
|
|
169
|
+
<h4>{row.name}'s Details</h4>
|
|
170
|
+
<p>Email: {row.email}</p>
|
|
171
|
+
<EmployeeHistory employeeId={row.id} />
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
174
|
+
</GridDetailPanel>
|
|
175
|
+
</DataGrid>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**GridDetailPanel Props:**
|
|
181
|
+
|
|
182
|
+
| Prop | Type | Default | Description |
|
|
183
|
+
| ------------------ | ----------------------------------------- | --------- | ------------------------------------ |
|
|
184
|
+
| `children` | `(ctx: DetailPanelContext) => ReactNode` | Required | Render function for panel content |
|
|
185
|
+
| `showExpandColumn` | `boolean` | `true` | Show expand/collapse chevron column |
|
|
186
|
+
| `animation` | `'slide' \| 'fade' \| false` | `'slide'` | Animation style for expand/collapse |
|
|
187
|
+
|
|
188
|
+
## Custom Tool Panels with GridToolPanel
|
|
189
|
+
|
|
190
|
+
Add custom sidebar panels to the grid shell:
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
import { DataGrid, GridToolPanel, GridToolButtons } from '@toolbox-web/grid-react';
|
|
194
|
+
import { ShellPlugin } from '@toolbox-web/grid/all';
|
|
195
|
+
|
|
196
|
+
function EmployeeGrid() {
|
|
197
|
+
const config: ReactGridConfig<Employee> = {
|
|
198
|
+
columns: [...],
|
|
199
|
+
plugins: [new ShellPlugin()],
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<DataGrid rows={employees} gridConfig={config}>
|
|
204
|
+
{/* Toolbar buttons */}
|
|
205
|
+
<GridToolButtons>
|
|
206
|
+
<button onClick={handleExport}>Export CSV</button>
|
|
207
|
+
<button onClick={handlePrint}>Print</button>
|
|
208
|
+
</GridToolButtons>
|
|
209
|
+
|
|
210
|
+
{/* Custom sidebar panel */}
|
|
211
|
+
<GridToolPanel id="quick-filters" title="Quick Filters" icon="🔍" order={10}>
|
|
212
|
+
{({ grid }) => (
|
|
213
|
+
<div className="filter-panel">
|
|
214
|
+
<label>
|
|
215
|
+
Department:
|
|
216
|
+
<select onChange={(e) => applyFilter(grid, 'department', e.target.value)}>
|
|
217
|
+
<option value="">All</option>
|
|
218
|
+
<option value="Engineering">Engineering</option>
|
|
219
|
+
<option value="Marketing">Marketing</option>
|
|
220
|
+
</select>
|
|
221
|
+
</label>
|
|
222
|
+
</div>
|
|
223
|
+
)}
|
|
224
|
+
</GridToolPanel>
|
|
225
|
+
</DataGrid>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**GridToolPanel Props:**
|
|
231
|
+
|
|
232
|
+
| Prop | Type | Default | Description |
|
|
233
|
+
| ---------- | --------------------------------------- | ---------- | ------------------------------------ |
|
|
234
|
+
| `id` | `string` | Required | Unique panel identifier |
|
|
235
|
+
| `title` | `string` | Required | Panel title in accordion header |
|
|
236
|
+
| `children` | `(ctx: ToolPanelContext) => ReactNode` | Required | Render function for panel content |
|
|
237
|
+
| `icon` | `string` | - | Icon for the accordion header |
|
|
238
|
+
| `tooltip` | `string` | - | Tooltip text for header |
|
|
239
|
+
| `order` | `number` | `100` | Panel sort order (lower = higher) |
|
|
240
|
+
|
|
241
|
+
## Using Refs
|
|
242
|
+
|
|
243
|
+
Access the grid instance for programmatic control:
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
import { DataGrid, DataGridRef } from '@toolbox-web/grid-react';
|
|
247
|
+
import { useRef } from 'react';
|
|
248
|
+
|
|
249
|
+
function MyComponent() {
|
|
250
|
+
const gridRef = useRef<DataGridRef>(null);
|
|
251
|
+
|
|
252
|
+
const handleExport = async () => {
|
|
253
|
+
const config = await gridRef.current?.getConfig();
|
|
254
|
+
console.log('Columns:', config?.columns);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<>
|
|
259
|
+
<button onClick={handleExport}>Export</button>
|
|
260
|
+
<DataGrid ref={gridRef} rows={employees} />
|
|
261
|
+
</>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## useGrid Hook
|
|
267
|
+
|
|
268
|
+
For more complex scenarios, use the `useGrid` hook:
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
import { DataGrid, useGrid } from '@toolbox-web/grid-react';
|
|
272
|
+
|
|
273
|
+
function MyComponent() {
|
|
274
|
+
const { ref, isReady, forceLayout } = useGrid<Employee>();
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<>
|
|
278
|
+
<button onClick={() => forceLayout()}>Refresh Layout</button>
|
|
279
|
+
<DataGrid ref={ref} rows={employees} />
|
|
280
|
+
</>
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Event Handling
|
|
286
|
+
|
|
287
|
+
### Via Props
|
|
288
|
+
|
|
289
|
+
```tsx
|
|
290
|
+
<DataGrid
|
|
291
|
+
rows={employees}
|
|
292
|
+
onCellEdit={(e) => console.log('Edited:', e.detail)}
|
|
293
|
+
onRowClick={(e) => console.log('Clicked:', e.detail.row)}
|
|
294
|
+
onSortChange={(e) => console.log('Sort:', e.detail)}
|
|
295
|
+
/>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Via useGridEvent Hook
|
|
299
|
+
|
|
300
|
+
```tsx
|
|
301
|
+
import { DataGrid, useGridEvent, DataGridRef } from '@toolbox-web/grid-react';
|
|
302
|
+
|
|
303
|
+
function MyComponent() {
|
|
304
|
+
const gridRef = useRef<DataGridRef>(null);
|
|
305
|
+
|
|
306
|
+
useGridEvent(gridRef, 'selection-change', (event) => {
|
|
307
|
+
console.log('Selected:', event.detail.selectedRows);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
return <DataGrid ref={gridRef} rows={employees} />;
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Plugins
|
|
315
|
+
|
|
316
|
+
Use plugins from `@toolbox-web/grid/all`:
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
import { DataGrid } from '@toolbox-web/grid-react';
|
|
320
|
+
import { SelectionPlugin, FilteringPlugin } from '@toolbox-web/grid/all';
|
|
321
|
+
|
|
322
|
+
function MyComponent() {
|
|
323
|
+
return (
|
|
324
|
+
<DataGrid
|
|
325
|
+
rows={employees}
|
|
326
|
+
gridConfig={{
|
|
327
|
+
columns: [...],
|
|
328
|
+
plugins: [
|
|
329
|
+
new SelectionPlugin({ mode: 'row' }),
|
|
330
|
+
new FilteringPlugin({ debounceMs: 200 }),
|
|
331
|
+
],
|
|
332
|
+
}}
|
|
333
|
+
/>
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Custom Styles
|
|
339
|
+
|
|
340
|
+
Inject custom CSS into the grid's shadow DOM:
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
<DataGrid
|
|
344
|
+
rows={employees}
|
|
345
|
+
customStyles={`
|
|
346
|
+
.my-custom-cell {
|
|
347
|
+
background: #f0f0f0;
|
|
348
|
+
padding: 8px;
|
|
349
|
+
}
|
|
350
|
+
`}
|
|
351
|
+
/>
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## API Reference
|
|
355
|
+
|
|
356
|
+
### DataGrid Props
|
|
357
|
+
|
|
358
|
+
| Prop | Type | Description |
|
|
359
|
+
| -------------- | ------------------------------------------ | ----------------------------- |
|
|
360
|
+
| `rows` | `TRow[]` | Row data to display |
|
|
361
|
+
| `columns` | `ColumnConfig[]` | Column definitions |
|
|
362
|
+
| `gridConfig` | `GridConfig` | Full configuration object |
|
|
363
|
+
| `fitMode` | `'stretch' \| 'fit-columns' \| 'auto-fit'` | Column sizing mode |
|
|
364
|
+
| `editOn` | `'click' \| 'dblclick' \| 'none'` | Edit trigger |
|
|
365
|
+
| `customStyles` | `string` | CSS to inject into shadow DOM |
|
|
366
|
+
| `onRowsChange` | `(rows: TRow[]) => void` | Rows changed callback |
|
|
367
|
+
| `onCellEdit` | `(event: CustomEvent) => void` | Cell edited callback |
|
|
368
|
+
| `onRowClick` | `(event: CustomEvent) => void` | Row clicked callback |
|
|
369
|
+
|
|
370
|
+
### GridColumn Props
|
|
371
|
+
|
|
372
|
+
| Prop | Type | Description |
|
|
373
|
+
| ----------- | --------------------------------------------- | ----------------------- |
|
|
374
|
+
| `field` | `string` | Field key in row object |
|
|
375
|
+
| `header` | `string` | Column header text |
|
|
376
|
+
| `type` | `'string' \| 'number' \| 'date' \| 'boolean'` | Data type |
|
|
377
|
+
| `editable` | `boolean` | Enable editing |
|
|
378
|
+
| `sortable` | `boolean` | Enable sorting |
|
|
379
|
+
| `resizable` | `boolean` | Enable column resizing |
|
|
380
|
+
| `width` | `string \| number` | Column width |
|
|
381
|
+
| `children` | `(ctx: CellRenderContext) => ReactNode` | Custom renderer |
|
|
382
|
+
| `editor` | `(ctx: ColumnEditorContext) => ReactNode` | Custom editor |
|
|
383
|
+
|
|
384
|
+
### DataGridRef Methods
|
|
385
|
+
|
|
386
|
+
| Method | Description |
|
|
387
|
+
| ------------------------- | --------------------------- |
|
|
388
|
+
| `getConfig()` | Get effective configuration |
|
|
389
|
+
| `ready()` | Wait for grid ready |
|
|
390
|
+
| `forceLayout()` | Force layout recalculation |
|
|
391
|
+
| `toggleGroup(key)` | Toggle group expansion |
|
|
392
|
+
| `registerStyles(id, css)` | Register custom styles |
|
|
393
|
+
| `unregisterStyles(id)` | Remove custom styles |
|
|
394
|
+
|
|
395
|
+
## Requirements
|
|
396
|
+
|
|
397
|
+
- React 18.0.0 or higher
|
|
398
|
+
- @toolbox-web/grid 0.2.0 or higher
|
|
399
|
+
|
|
400
|
+
## License
|
|
401
|
+
|
|
402
|
+
MIT
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { DataGrid } from './lib/data-grid';
|
|
2
|
+
export { GridColumn } from './lib/grid-column';
|
|
3
|
+
export { GridDetailPanel, type DetailPanelContext, type GridDetailPanelProps } from './lib/grid-detail-panel';
|
|
4
|
+
export { GridToolButtons, type GridToolButtonsProps } from './lib/grid-tool-button';
|
|
5
|
+
export { GridToolPanel, type GridToolPanelProps, type ToolPanelContext } from './lib/grid-tool-panel';
|
|
6
|
+
export type { ReactColumnConfig, ReactGridConfig } from './lib/react-column-config';
|
|
7
|
+
export { useGrid } from './lib/use-grid';
|
|
8
|
+
export { useGridEvent } from './lib/use-grid-event';
|
|
9
|
+
export { ReactGridAdapter, getRegisteredFields } from './lib/react-grid-adapter';
|
|
10
|
+
export type { GridCellContext, GridDetailContext, GridEditorContext, GridToolPanelContext } from './lib/context-types';
|
|
11
|
+
export type { CellRenderContext, ColumnConfig, ColumnEditorContext, GridConfig } from '../../../dist/libs/grid/index.d.ts';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../libs/grid-react/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,YAAY,CAAC;AAGpB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,KAAK,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC9G,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGtG,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGpF,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGjF,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGvH,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
|