@toolbox-web/grid-vue 0.0.0 → 0.1.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.
Files changed (140) hide show
  1. package/README.md +489 -1
  2. package/chunks/feature-registry-BgEOysSJ.js +38 -0
  3. package/chunks/feature-registry-BgEOysSJ.js.map +1 -0
  4. package/features/clipboard.d.ts +20 -0
  5. package/features/clipboard.d.ts.map +1 -0
  6. package/features/clipboard.js +4 -0
  7. package/features/clipboard.js.map +1 -0
  8. package/features/column-virtualization.d.ts +20 -0
  9. package/features/column-virtualization.d.ts.map +1 -0
  10. package/features/column-virtualization.js +4 -0
  11. package/features/column-virtualization.js.map +1 -0
  12. package/features/context-menu.d.ts +20 -0
  13. package/features/context-menu.d.ts.map +1 -0
  14. package/features/context-menu.js +4 -0
  15. package/features/context-menu.js.map +1 -0
  16. package/features/editing.d.ts +20 -0
  17. package/features/editing.d.ts.map +1 -0
  18. package/features/editing.js +4 -0
  19. package/features/editing.js.map +1 -0
  20. package/features/export.d.ts +20 -0
  21. package/features/export.d.ts.map +1 -0
  22. package/features/export.js +4 -0
  23. package/features/export.js.map +1 -0
  24. package/features/filtering.d.ts +20 -0
  25. package/features/filtering.d.ts.map +1 -0
  26. package/features/filtering.js +4 -0
  27. package/features/filtering.js.map +1 -0
  28. package/features/grouping-columns.d.ts +24 -0
  29. package/features/grouping-columns.d.ts.map +1 -0
  30. package/features/grouping-columns.js +4 -0
  31. package/features/grouping-columns.js.map +1 -0
  32. package/features/grouping-rows.d.ts +23 -0
  33. package/features/grouping-rows.d.ts.map +1 -0
  34. package/features/grouping-rows.js +4 -0
  35. package/features/grouping-rows.js.map +1 -0
  36. package/features/index.d.ts +1 -0
  37. package/features/index.d.ts.map +1 -0
  38. package/features/index.js +23 -0
  39. package/features/index.js.map +1 -0
  40. package/features/master-detail.d.ts +23 -0
  41. package/features/master-detail.d.ts.map +1 -0
  42. package/features/master-detail.js +4 -0
  43. package/features/master-detail.js.map +1 -0
  44. package/features/multi-sort.d.ts +20 -0
  45. package/features/multi-sort.d.ts.map +1 -0
  46. package/features/multi-sort.js +5 -0
  47. package/features/multi-sort.js.map +1 -0
  48. package/features/pinned-columns.d.ts +23 -0
  49. package/features/pinned-columns.d.ts.map +1 -0
  50. package/features/pinned-columns.js +4 -0
  51. package/features/pinned-columns.js.map +1 -0
  52. package/features/pinned-rows.d.ts +22 -0
  53. package/features/pinned-rows.d.ts.map +1 -0
  54. package/features/pinned-rows.js +4 -0
  55. package/features/pinned-rows.js.map +1 -0
  56. package/features/pivot.d.ts +24 -0
  57. package/features/pivot.d.ts.map +1 -0
  58. package/features/pivot.js +4 -0
  59. package/features/pivot.js.map +1 -0
  60. package/features/print.d.ts +20 -0
  61. package/features/print.d.ts.map +1 -0
  62. package/features/print.js +4 -0
  63. package/features/print.js.map +1 -0
  64. package/features/reorder.d.ts +20 -0
  65. package/features/reorder.d.ts.map +1 -0
  66. package/features/reorder.js +4 -0
  67. package/features/reorder.js.map +1 -0
  68. package/features/responsive.d.ts +24 -0
  69. package/features/responsive.d.ts.map +1 -0
  70. package/features/responsive.js +4 -0
  71. package/features/responsive.js.map +1 -0
  72. package/features/row-reorder.d.ts +20 -0
  73. package/features/row-reorder.d.ts.map +1 -0
  74. package/features/row-reorder.js +4 -0
  75. package/features/row-reorder.js.map +1 -0
  76. package/features/selection.d.ts +20 -0
  77. package/features/selection.d.ts.map +1 -0
  78. package/features/selection.js +4 -0
  79. package/features/selection.js.map +1 -0
  80. package/features/server-side.d.ts +22 -0
  81. package/features/server-side.d.ts.map +1 -0
  82. package/features/server-side.js +4 -0
  83. package/features/server-side.js.map +1 -0
  84. package/features/tree.d.ts +23 -0
  85. package/features/tree.d.ts.map +1 -0
  86. package/features/tree.js +4 -0
  87. package/features/tree.js.map +1 -0
  88. package/features/undo-redo.d.ts +20 -0
  89. package/features/undo-redo.d.ts.map +1 -0
  90. package/features/undo-redo.js +4 -0
  91. package/features/undo-redo.js.map +1 -0
  92. package/features/visibility.d.ts +20 -0
  93. package/features/visibility.d.ts.map +1 -0
  94. package/features/visibility.js +4 -0
  95. package/features/visibility.js.map +1 -0
  96. package/index.d.ts +67 -0
  97. package/index.d.ts.map +1 -0
  98. package/index.js +673 -0
  99. package/index.js.map +1 -0
  100. package/lib/TbwGrid.vue.d.ts +98 -0
  101. package/lib/TbwGrid.vue.d.ts.map +1 -0
  102. package/lib/TbwGridColumn.vue.d.ts +183 -0
  103. package/lib/TbwGridColumn.vue.d.ts.map +1 -0
  104. package/lib/TbwGridDetailPanel.vue.d.ts +36 -0
  105. package/lib/TbwGridDetailPanel.vue.d.ts.map +1 -0
  106. package/lib/TbwGridResponsiveCard.vue.d.ts +22 -0
  107. package/lib/TbwGridResponsiveCard.vue.d.ts.map +1 -0
  108. package/lib/TbwGridToolButtons.vue.d.ts +27 -0
  109. package/lib/TbwGridToolButtons.vue.d.ts.map +1 -0
  110. package/lib/TbwGridToolPanel.vue.d.ts +178 -0
  111. package/lib/TbwGridToolPanel.vue.d.ts.map +1 -0
  112. package/lib/detail-panel-registry.d.ts +20 -0
  113. package/lib/detail-panel-registry.d.ts.map +1 -0
  114. package/lib/feature-props.d.ts +317 -0
  115. package/lib/feature-props.d.ts.map +1 -0
  116. package/lib/feature-registry.d.ts +69 -0
  117. package/lib/feature-registry.d.ts.map +1 -0
  118. package/lib/grid-icon-registry.d.ts +66 -0
  119. package/lib/grid-icon-registry.d.ts.map +1 -0
  120. package/lib/grid-provider.d.ts +66 -0
  121. package/lib/grid-provider.d.ts.map +1 -0
  122. package/lib/grid-type-registry.d.ts +98 -0
  123. package/lib/grid-type-registry.d.ts.map +1 -0
  124. package/lib/responsive-card-registry.d.ts +20 -0
  125. package/lib/responsive-card-registry.d.ts.map +1 -0
  126. package/lib/slot-types.d.ts +50 -0
  127. package/lib/slot-types.d.ts.map +1 -0
  128. package/lib/tool-panel-registry.d.ts +18 -0
  129. package/lib/tool-panel-registry.d.ts.map +1 -0
  130. package/lib/use-grid-event.d.ts +68 -0
  131. package/lib/use-grid-event.d.ts.map +1 -0
  132. package/lib/use-grid.d.ts +39 -0
  133. package/lib/use-grid.d.ts.map +1 -0
  134. package/lib/vue-column-config.d.ts +69 -0
  135. package/lib/vue-column-config.d.ts.map +1 -0
  136. package/lib/vue-grid-adapter.d.ts +94 -0
  137. package/lib/vue-grid-adapter.d.ts.map +1 -0
  138. package/package.json +52 -3
  139. package/typedoc-entry.d.ts +31 -0
  140. package/typedoc-entry.d.ts.map +1 -0
package/README.md CHANGED
@@ -1 +1,489 @@
1
- # @toolbox-web/grid-vue\n\nPlaceholder release. Real package coming soon.
1
+ # @toolbox-web/grid-vue
2
+
3
+ [![npm](https://img.shields.io/npm/v/@toolbox-web/grid-vue.svg)](https://www.npmjs.com/package/@toolbox-web/grid-vue)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](../../LICENSE)
5
+ [![GitHub Sponsors](https://img.shields.io/badge/Sponsor-❤-ea4aaa?logo=github)](https://github.com/sponsors/OysteinAmundsen)
6
+
7
+ Vue 3 adapter for `@toolbox-web/grid` data grid component. Provides components and composables for declarative Vue integration with custom cell renderers and editors.
8
+
9
+ ## Features
10
+
11
+ - ✅ **Full Vue 3 integration** - Use Vue components for cell renderers and editors
12
+ - ✅ **Composition API** - Built with `<script setup>` and TypeScript generics
13
+ - ✅ **Declarative feature props** - Enable plugins with simple props like `selection="range"`
14
+ - ✅ **Tree-shakeable features** - Only import the features you use
15
+ - ✅ **Slot-based customization** - `#cell` and `#editor` slots for custom rendering
16
+ - ✅ **Type-level defaults** - App-wide renderers/editors via `GridTypeProvider`
17
+ - ✅ **Icon configuration** - App-wide icon overrides via `GridProvider` or `GridIconProvider`
18
+ - ✅ **Composables** - `useGrid` and `useGridEvent` for programmatic access
19
+ - ✅ **Master-detail** - `TbwGridDetailPanel` for expandable rows
20
+ - ✅ **Tool panels** - `TbwGridToolPanel` for custom sidebar content
21
+ - ✅ **Responsive cards** - `TbwGridResponsiveCard` for mobile layouts
22
+ - ✅ **Full type safety** - TypeScript generics support
23
+ - ✅ **Vue 3.4+** - Supports `defineModel` and improved generics
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ # npm
29
+ npm install @toolbox-web/grid @toolbox-web/grid-vue
30
+
31
+ # yarn
32
+ yarn add @toolbox-web/grid @toolbox-web/grid-vue
33
+
34
+ # pnpm
35
+ pnpm add @toolbox-web/grid @toolbox-web/grid-vue
36
+
37
+ # bun
38
+ bun add @toolbox-web/grid @toolbox-web/grid-vue
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ### 1. Register the Grid Component
44
+
45
+ In your application entry point, import the grid registration:
46
+
47
+ ```typescript
48
+ // main.ts
49
+ import '@toolbox-web/grid';
50
+ ```
51
+
52
+ ### 2. Use in Components
53
+
54
+ ```vue
55
+ <script setup lang="ts">
56
+ import { TbwGrid, TbwGridColumn } from '@toolbox-web/grid-vue';
57
+ import { ref } from 'vue';
58
+
59
+ interface Employee {
60
+ id: number;
61
+ name: string;
62
+ department: string;
63
+ salary: number;
64
+ }
65
+
66
+ const employees = ref<Employee[]>([
67
+ { id: 1, name: 'Alice', department: 'Engineering', salary: 95000 },
68
+ { id: 2, name: 'Bob', department: 'Marketing', salary: 75000 },
69
+ { id: 3, name: 'Charlie', department: 'Sales', salary: 85000 },
70
+ ]);
71
+ </script>
72
+
73
+ <template>
74
+ <TbwGrid :rows="employees">
75
+ <TbwGridColumn field="id" header="ID" :width="60" />
76
+ <TbwGridColumn field="name" header="Name" :sortable="true" />
77
+ <TbwGridColumn field="department" header="Department" :sortable="true" />
78
+ <TbwGridColumn field="salary" header="Salary" type="number" />
79
+ </TbwGrid>
80
+ </template>
81
+ ```
82
+
83
+ ## Enabling Features
84
+
85
+ Features are enabled using **declarative props** with **side-effect imports**. This gives you the best of both worlds: clean, intuitive templates and tree-shakeable bundles.
86
+
87
+ ### How It Works
88
+
89
+ 1. **Import the feature** - A side-effect import registers the feature factory
90
+ 2. **Use the prop** - TbwGrid detects the prop and creates the plugin instance
91
+
92
+ ```vue
93
+ <script setup lang="ts">
94
+ import { TbwGrid } from '@toolbox-web/grid-vue';
95
+
96
+ // 1. Import features you need (once, typically in main.ts or the component file)
97
+ import '@toolbox-web/grid-vue/features/selection';
98
+ import '@toolbox-web/grid-vue/features/multi-sort';
99
+ import '@toolbox-web/grid-vue/features/filtering';
100
+ </script>
101
+
102
+ <template>
103
+ <!-- 2. Use declarative props - no manual plugin instantiation! -->
104
+ <TbwGrid :rows="employees" :columns="columns" selection="range" multi-sort filtering />
105
+ </template>
106
+ ```
107
+
108
+ ### Why Side-Effect Imports?
109
+
110
+ - **Tree-shakeable** - Only the features you import are bundled
111
+ - **Synchronous** - No loading states, no HTTP requests, no spinners
112
+ - **Type-safe** - Full TypeScript support for feature props
113
+ - **Clean templates** - No `plugins: [new SelectionPlugin({ mode: 'range' })]` boilerplate
114
+
115
+ ### Available Features
116
+
117
+ Import from `@toolbox-web/grid-vue/features/<name>`:
118
+
119
+ | Feature | Prop | Example |
120
+ | ----------------------- | ----------------------- | --------------------------------------------------------------------- |
121
+ | `selection` | `selection` | `selection="range"` or `:selection="{ mode: 'row', checkbox: true }"` |
122
+ | `multi-sort` | `multi-sort` | `multi-sort` or `:multi-sort="{ maxSortLevels: 3 }"` |
123
+ | `filtering` | `filtering` | `filtering` or `:filtering="{ debounceMs: 200 }"` |
124
+ | `editing` | `editing` | `editing="dblclick"` or `editing="click"` |
125
+ | `clipboard` | `clipboard` | `clipboard` (requires selection) |
126
+ | `undo-redo` | `undo-redo` | `undo-redo` (requires editing) |
127
+ | `context-menu` | `context-menu` | `context-menu` |
128
+ | `reorder` | `reorder` | `reorder` (column drag-to-reorder) |
129
+ | `row-reorder` | `row-reorder` | `row-reorder` (row drag-to-reorder) |
130
+ | `visibility` | `visibility` | `visibility` (column visibility panel) |
131
+ | `pinned-columns` | `pinned-columns` | `pinned-columns` |
132
+ | `pinned-rows` | `pinned-rows` | `pinned-rows` |
133
+ | `grouping-columns` | `grouping-columns` | `grouping-columns` |
134
+ | `grouping-rows` | `grouping-rows` | `:grouping-rows="{ groupBy: 'department' }"` |
135
+ | `tree` | `tree` | `:tree="{ childrenField: 'children' }"` |
136
+ | `column-virtualization` | `column-virtualization` | `column-virtualization` |
137
+ | `export` | `export` | `export` |
138
+ | `print` | `print` | `print` |
139
+ | `responsive` | `responsive` | `responsive` (card layout on mobile) |
140
+ | `master-detail` | `master-detail` | `master-detail` (use with `<TbwGridDetailPanel>`) |
141
+ | `pivot` | `pivot` | `:pivot="{ rowFields: [...], columnFields: [...] }"` |
142
+ | `server-side` | `server-side` | `:server-side="{ ... }"` |
143
+
144
+ ### Import All Features
145
+
146
+ For prototyping or when bundle size isn't critical, import all features at once:
147
+
148
+ ```typescript
149
+ // Import all features (larger bundle)
150
+ import '@toolbox-web/grid-vue/features';
151
+ ```
152
+
153
+ ## Custom Cell Renderers
154
+
155
+ Use the `#cell` slot on `TbwGridColumn` for custom rendering:
156
+
157
+ ```vue
158
+ <script setup lang="ts">
159
+ import { TbwGrid, TbwGridColumn, type CellSlotProps } from '@toolbox-web/grid-vue';
160
+ import StatusBadge from './StatusBadge.vue';
161
+ </script>
162
+
163
+ <template>
164
+ <TbwGrid :rows="employees">
165
+ <TbwGridColumn field="name" header="Name" />
166
+ <TbwGridColumn field="status" header="Status">
167
+ <template #cell="{ value, row }: CellSlotProps<Employee, string>">
168
+ <StatusBadge :status="value" :employee="row" />
169
+ </template>
170
+ </TbwGridColumn>
171
+ </TbwGrid>
172
+ </template>
173
+ ```
174
+
175
+ ### Slot Props
176
+
177
+ The `#cell` slot receives:
178
+
179
+ | Prop | Type | Description |
180
+ | ---------- | -------- | -------------------- |
181
+ | `value` | `TValue` | Cell value |
182
+ | `row` | `TRow` | Row data |
183
+ | `column` | `object` | Column configuration |
184
+ | `rowIndex` | `number` | Row index |
185
+ | `colIndex` | `number` | Column index |
186
+
187
+ ## Custom Cell Editors
188
+
189
+ Use the `#editor` slot for inline editing:
190
+
191
+ ```vue
192
+ <script setup lang="ts">
193
+ import { TbwGrid, TbwGridColumn, type EditorSlotProps } from '@toolbox-web/grid-vue';
194
+ import '@toolbox-web/grid-vue/features/editing';
195
+ </script>
196
+
197
+ <template>
198
+ <TbwGrid :rows="employees" editing="dblclick">
199
+ <TbwGridColumn field="status" header="Status" :editable="true">
200
+ <template #editor="{ value, commit, cancel }: EditorSlotProps<Employee, string>">
201
+ <select :value="value" @change="(e) => commit((e.target as HTMLSelectElement).value)">
202
+ <option value="active">Active</option>
203
+ <option value="inactive">Inactive</option>
204
+ </select>
205
+ </template>
206
+ </TbwGridColumn>
207
+ </TbwGrid>
208
+ </template>
209
+ ```
210
+
211
+ ### Editor Slot Props
212
+
213
+ | Prop | Type | Description |
214
+ | -------- | ---------------------- | ------------------ |
215
+ | `value` | `TValue` | Current cell value |
216
+ | `row` | `TRow` | Row data |
217
+ | `commit` | `(value: any) => void` | Save the new value |
218
+ | `cancel` | `() => void` | Cancel editing |
219
+
220
+ ## Composables
221
+
222
+ ### useGrid
223
+
224
+ Access grid methods programmatically:
225
+
226
+ ```vue
227
+ <script setup lang="ts">
228
+ import { useGrid } from '@toolbox-web/grid-vue';
229
+
230
+ const { forceLayout, getConfig, ready, getPlugin } = useGrid();
231
+
232
+ async function handleResize() {
233
+ await forceLayout();
234
+ }
235
+
236
+ async function logConfig() {
237
+ await ready();
238
+ console.log(getConfig());
239
+ }
240
+ </script>
241
+ ```
242
+
243
+ ### useGridEvent
244
+
245
+ Subscribe to grid events with automatic cleanup:
246
+
247
+ ```vue
248
+ <script setup lang="ts">
249
+ import { useGridEvent } from '@toolbox-web/grid-vue';
250
+
251
+ useGridEvent('cell-commit', (event) => {
252
+ console.log('Cell committed:', event.detail);
253
+ });
254
+
255
+ useGridEvent('selection-change', (event) => {
256
+ console.log('Selection:', event.detail.selectedRows);
257
+ });
258
+ </script>
259
+ ```
260
+
261
+ ## Providers
262
+
263
+ ### GridTypeProvider
264
+
265
+ Define app-wide type renderers:
266
+
267
+ ```vue
268
+ <script setup lang="ts">
269
+ import { GridTypeProvider, type TypeDefaultsMap } from '@toolbox-web/grid-vue';
270
+ import { h } from 'vue';
271
+ import CurrencyCell from './CurrencyCell.vue';
272
+
273
+ const typeDefaults: TypeDefaultsMap = {
274
+ currency: {
275
+ renderer: (ctx) => h(CurrencyCell, { value: ctx.value }),
276
+ },
277
+ percentage: {
278
+ renderer: (ctx) => h('span', `${(ctx.value * 100).toFixed(1)}%`),
279
+ },
280
+ };
281
+ </script>
282
+
283
+ <template>
284
+ <GridTypeProvider :defaults="typeDefaults">
285
+ <App />
286
+ </GridTypeProvider>
287
+ </template>
288
+ ```
289
+
290
+ Then use in columns:
291
+
292
+ ```vue
293
+ <TbwGridColumn field="salary" header="Salary" type="currency" />
294
+ ```
295
+
296
+ ### GridIconProvider
297
+
298
+ Override grid icons app-wide:
299
+
300
+ ```vue
301
+ <script setup lang="ts">
302
+ import { GridIconProvider } from '@toolbox-web/grid-vue';
303
+
304
+ const icons = {
305
+ sortAsc: '↑',
306
+ sortDesc: '↓',
307
+ expand: '+',
308
+ collapse: '−',
309
+ filter: '🔍',
310
+ };
311
+ </script>
312
+
313
+ <template>
314
+ <GridIconProvider :icons="icons">
315
+ <App />
316
+ </GridIconProvider>
317
+ </template>
318
+ ```
319
+
320
+ ### GridProvider
321
+
322
+ Combined provider for both types and icons:
323
+
324
+ ```vue
325
+ <script setup lang="ts">
326
+ import { GridProvider } from '@toolbox-web/grid-vue';
327
+ </script>
328
+
329
+ <template>
330
+ <GridProvider :type-defaults="typeDefaults" :icons="icons">
331
+ <App />
332
+ </GridProvider>
333
+ </template>
334
+ ```
335
+
336
+ ## Master-Detail
337
+
338
+ Expandable row details:
339
+
340
+ ```vue
341
+ <script setup lang="ts">
342
+ import { TbwGrid, TbwGridDetailPanel, type DetailPanelContext } from '@toolbox-web/grid-vue';
343
+ import '@toolbox-web/grid-vue/features/master-detail';
344
+ </script>
345
+
346
+ <template>
347
+ <TbwGrid :rows="employees" master-detail>
348
+ <TbwGridColumn field="name" header="Name" />
349
+ <TbwGridColumn field="department" header="Department" />
350
+
351
+ <TbwGridDetailPanel v-slot="{ row }: DetailPanelContext<Employee>">
352
+ <div class="detail-content">
353
+ <h4>{{ row.name }}</h4>
354
+ <p>Department: {{ row.department }}</p>
355
+ <p>Email: {{ row.email }}</p>
356
+ </div>
357
+ </TbwGridDetailPanel>
358
+ </TbwGrid>
359
+ </template>
360
+ ```
361
+
362
+ ## Tool Panels
363
+
364
+ Custom sidebar panels:
365
+
366
+ ```vue
367
+ <script setup lang="ts">
368
+ import { TbwGrid, TbwGridToolPanel, type ToolPanelContext } from '@toolbox-web/grid-vue';
369
+ </script>
370
+
371
+ <template>
372
+ <TbwGrid :rows="employees">
373
+ <TbwGridColumn field="name" header="Name" />
374
+
375
+ <TbwGridToolPanel id="stats" label="Statistics" v-slot="{ rows }: ToolPanelContext<Employee>">
376
+ <div class="stats-panel">
377
+ <p>Total: {{ rows.length }}</p>
378
+ <p>Avg Salary: {{ averageSalary(rows) }}</p>
379
+ </div>
380
+ </TbwGridToolPanel>
381
+ </TbwGrid>
382
+ </template>
383
+ ```
384
+
385
+ ## Responsive Cards
386
+
387
+ Mobile-friendly card layout:
388
+
389
+ ```vue
390
+ <script setup lang="ts">
391
+ import { TbwGrid, TbwGridResponsiveCard, type ResponsiveCardContext } from '@toolbox-web/grid-vue';
392
+ import '@toolbox-web/grid-vue/features/responsive';
393
+ </script>
394
+
395
+ <template>
396
+ <TbwGrid :rows="employees" responsive>
397
+ <TbwGridColumn field="name" header="Name" />
398
+ <TbwGridColumn field="department" header="Department" />
399
+
400
+ <TbwGridResponsiveCard v-slot="{ row }: ResponsiveCardContext<Employee>">
401
+ <div class="employee-card">
402
+ <h3>{{ row.name }}</h3>
403
+ <p>{{ row.department }}</p>
404
+ </div>
405
+ </TbwGridResponsiveCard>
406
+ </TbwGrid>
407
+ </template>
408
+ ```
409
+
410
+ ## TypeScript Support
411
+
412
+ Full generic support for row types:
413
+
414
+ ```vue
415
+ <script setup lang="ts" generic="T extends Employee">
416
+ import { TbwGrid, TbwGridColumn } from '@toolbox-web/grid-vue';
417
+
418
+ interface Employee {
419
+ id: number;
420
+ name: string;
421
+ salary: number;
422
+ }
423
+
424
+ const props = defineProps<{
425
+ employees: T[];
426
+ }>();
427
+ </script>
428
+
429
+ <template>
430
+ <TbwGrid :rows="props.employees">
431
+ <TbwGridColumn field="name" header="Name" />
432
+ <TbwGridColumn field="salary" header="Salary">
433
+ <template #cell="{ value }"> ${{ value.toLocaleString() }} </template>
434
+ </TbwGridColumn>
435
+ </TbwGrid>
436
+ </template>
437
+ ```
438
+
439
+ ## API Reference
440
+
441
+ ### Components
442
+
443
+ | Component | Description |
444
+ | ----------------------- | ----------------------------- |
445
+ | `TbwGrid` | Main grid wrapper component |
446
+ | `TbwGridColumn` | Declarative column definition |
447
+ | `TbwGridDetailPanel` | Master-detail row content |
448
+ | `TbwGridToolPanel` | Custom sidebar panel |
449
+ | `TbwGridToolButtons` | Toolbar button container |
450
+ | `TbwGridResponsiveCard` | Mobile card layout template |
451
+ | `GridTypeProvider` | App-wide type defaults |
452
+ | `GridIconProvider` | App-wide icon overrides |
453
+ | `GridProvider` | Combined type + icon provider |
454
+
455
+ ### Composables
456
+
457
+ | Composable | Description |
458
+ | -------------- | ------------------------ |
459
+ | `useGrid` | Access grid methods |
460
+ | `useGridEvent` | Subscribe to grid events |
461
+
462
+ ### Types
463
+
464
+ | Type | Description |
465
+ | ----------------------- | ------------------------------ |
466
+ | `CellSlotProps` | Props for `#cell` slot |
467
+ | `EditorSlotProps` | Props for `#editor` slot |
468
+ | `DetailPanelContext` | Props for detail panel slot |
469
+ | `ToolPanelContext` | Props for tool panel slot |
470
+ | `ResponsiveCardContext` | Props for responsive card slot |
471
+ | `VueColumnConfig` | Column configuration type |
472
+ | `VueGridConfig` | Grid configuration type |
473
+ | `TypeDefaultsMap` | Type defaults registry type |
474
+
475
+ ## Building
476
+
477
+ ```bash
478
+ bun nx build grid-vue
479
+ ```
480
+
481
+ ## Running Tests
482
+
483
+ ```bash
484
+ bun nx test grid-vue
485
+ ```
486
+
487
+ ## License
488
+
489
+ MIT © [Øystein Amundsen](https://github.com/OysteinAmundsen)
@@ -0,0 +1,38 @@
1
+ const r = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set();
2
+ function n(e, t) {
3
+ r.set(e, {
4
+ factory: t,
5
+ name: e
6
+ });
7
+ }
8
+ function o(e) {
9
+ return r.has(e);
10
+ }
11
+ function u() {
12
+ return Array.from(r.keys());
13
+ }
14
+ function i(e) {
15
+ return r.get(e)?.factory;
16
+ }
17
+ function c(e, t) {
18
+ const s = r.get(e);
19
+ if (!s) {
20
+ a.has(e) || (a.add(e), console.warn(
21
+ `[TbwGrid] Feature "${e}" is not registered. Import '@toolbox-web/grid-vue/features/${e}' to enable it.`
22
+ ));
23
+ return;
24
+ }
25
+ return s.factory(t);
26
+ }
27
+ function f() {
28
+ r.clear(), a.clear();
29
+ }
30
+ export {
31
+ f as a,
32
+ u as b,
33
+ c,
34
+ i as g,
35
+ o as i,
36
+ n as r
37
+ };
38
+ //# sourceMappingURL=feature-registry-BgEOysSJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature-registry-BgEOysSJ.js","sources":["../../../../libs/grid-vue/src/lib/feature-registry.ts"],"sourcesContent":["/**\n * Feature Registry for @toolbox-web/grid-vue\n *\n * This module provides a synchronous registry for plugin factories.\n * Features are registered via side-effect imports, enabling tree-shaking\n * while maintaining the clean prop-based API.\n *\n * @example\n * ```typescript\n * // Import features you need (side-effect imports)\n * import '@toolbox-web/grid-vue/features/selection';\n * import '@toolbox-web/grid-vue/features/filtering';\n *\n * // Props work automatically - no async loading, no HTTP requests\n * <TbwGrid :selection=\"'range'\" :filtering=\"{ debounceMs: 200 }\" />\n * ```\n */\n\n/**\n * Feature names supported by the TbwGrid component.\n */\nexport type FeatureName =\n | 'selection'\n | 'editing'\n | 'clipboard'\n | 'contextMenu'\n | 'multiSort'\n | 'sorting' // @deprecated - use 'multiSort' instead\n | 'filtering'\n | 'reorder'\n | 'visibility'\n | 'pinnedColumns'\n | 'groupingColumns'\n | 'columnVirtualization'\n | 'rowReorder'\n | 'groupingRows'\n | 'pinnedRows'\n | 'tree'\n | 'masterDetail'\n | 'responsive'\n | 'undoRedo'\n | 'export'\n | 'print'\n | 'pivot'\n | 'serverSide';\n\n/**\n * Plugin factory function type.\n * Takes configuration and returns a plugin instance.\n */\nexport type PluginFactory<TConfig = unknown> = (config: TConfig) => unknown;\n\n/**\n * Registry entry containing the factory and metadata.\n */\ninterface RegistryEntry {\n factory: PluginFactory;\n /** Feature name for debugging */\n name: string;\n}\n\n/**\n * Central registry mapping feature names to their plugin factories.\n * Populated by side-effect feature imports.\n */\nconst featureRegistry = new Map<FeatureName, RegistryEntry>();\n\n/**\n * Set of features that have been used without being registered.\n * Used to show helpful warnings only once per feature.\n */\nconst warnedFeatures = new Set<string>();\n\n/**\n * Register a feature's plugin factory.\n * Called by side-effect feature imports.\n *\n * @param name - The feature name (matches the prop name on TbwGrid)\n * @param factory - Function that creates the plugin instance\n *\n * @example\n * ```ts\n * // features/selection.ts\n * import { SelectionPlugin } from '@toolbox-web/grid/plugins/selection';\n * import { registerFeature } from '../lib/feature-registry';\n *\n * registerFeature('selection', (config) => new SelectionPlugin(config));\n * ```\n */\nexport function registerFeature<TConfig = unknown>(name: FeatureName, factory: PluginFactory<TConfig>): void {\n featureRegistry.set(name, {\n factory: factory as PluginFactory,\n name,\n });\n}\n\n/**\n * Check if a feature is registered.\n */\nexport function isFeatureRegistered(name: FeatureName): boolean {\n return featureRegistry.has(name);\n}\n\n/**\n * Get all registered feature names.\n */\nexport function getRegisteredFeatures(): FeatureName[] {\n return Array.from(featureRegistry.keys());\n}\n\n/**\n * Get the factory for a feature, if registered.\n */\nexport function getFeatureFactory(name: FeatureName): PluginFactory | undefined {\n return featureRegistry.get(name)?.factory;\n}\n\n/**\n * Create a plugin from a feature prop.\n * Returns undefined if the feature is not registered (with a console warning).\n *\n * @param name - Feature name\n * @param config - Configuration value from the prop\n */\nexport function createPluginFromFeature(name: FeatureName, config: unknown): unknown | undefined {\n const entry = featureRegistry.get(name);\n\n if (!entry) {\n // Only warn once per feature\n if (!warnedFeatures.has(name)) {\n warnedFeatures.add(name);\n console.warn(\n `[TbwGrid] Feature \"${name}\" is not registered. ` +\n `Import '@toolbox-web/grid-vue/features/${name}' to enable it.`,\n );\n }\n return undefined;\n }\n\n return entry.factory(config);\n}\n\n/**\n * Clear the feature registry.\n * @internal - for testing only\n */\nexport function clearFeatureRegistry(): void {\n featureRegistry.clear();\n warnedFeatures.clear();\n}\n"],"names":["featureRegistry","warnedFeatures","registerFeature","name","factory","isFeatureRegistered","getRegisteredFeatures","getFeatureFactory","createPluginFromFeature","config","entry","clearFeatureRegistry"],"mappings":"AAiEA,MAAMA,wBAAsB,IAAA,GAMtBC,wBAAqB,IAAA;AAkBpB,SAASC,EAAmCC,GAAmBC,GAAuC;AAC3G,EAAAJ,EAAgB,IAAIG,GAAM;AAAA,IACxB,SAAAC;AAAA,IACA,MAAAD;AAAA,EAAA,CACD;AACH;AAKO,SAASE,EAAoBF,GAA4B;AAC9D,SAAOH,EAAgB,IAAIG,CAAI;AACjC;AAKO,SAASG,IAAuC;AACrD,SAAO,MAAM,KAAKN,EAAgB,KAAA,CAAM;AAC1C;AAKO,SAASO,EAAkBJ,GAA8C;AAC9E,SAAOH,EAAgB,IAAIG,CAAI,GAAG;AACpC;AASO,SAASK,EAAwBL,GAAmBM,GAAsC;AAC/F,QAAMC,IAAQV,EAAgB,IAAIG,CAAI;AAEtC,MAAI,CAACO,GAAO;AAEV,IAAKT,EAAe,IAAIE,CAAI,MAC1BF,EAAe,IAAIE,CAAI,GACvB,QAAQ;AAAA,MACN,sBAAsBA,CAAI,+DACkBA,CAAI;AAAA,IAAA;AAGpD;AAAA,EACF;AAEA,SAAOO,EAAM,QAAQD,CAAM;AAC7B;AAMO,SAASE,IAA6B;AAC3C,EAAAX,EAAgB,MAAA,GAChBC,EAAe,MAAA;AACjB;"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Clipboard feature for @toolbox-web/grid-vue
3
+ *
4
+ * Import this module to enable the `clipboard` prop on TbwGrid.
5
+ *
6
+ * @example
7
+ * ```vue
8
+ * <script setup>
9
+ * import '@toolbox-web/grid-vue/features/clipboard';
10
+ * </script>
11
+ *
12
+ * <template>
13
+ * <TbwGrid selection="range" clipboard />
14
+ * </template>
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=clipboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../../../libs/grid-vue/src/features/clipboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
@@ -0,0 +1,4 @@
1
+ import { ClipboardPlugin as e } from "@toolbox-web/grid/plugins/clipboard";
2
+ import { r as i } from "../chunks/feature-registry-BgEOysSJ.js";
3
+ i("clipboard", (r) => r === !0 ? new e() : new e(r ?? void 0));
4
+ //# sourceMappingURL=clipboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clipboard.js","sources":["../../../../libs/grid-vue/src/features/clipboard.ts"],"sourcesContent":["/**\n * Clipboard feature for @toolbox-web/grid-vue\n *\n * Import this module to enable the `clipboard` prop on TbwGrid.\n *\n * @example\n * ```vue\n * <script setup>\n * import '@toolbox-web/grid-vue/features/clipboard';\n * </script>\n *\n * <template>\n * <TbwGrid selection=\"range\" clipboard />\n * </template>\n * ```\n *\n * @packageDocumentation\n */\n\nimport { ClipboardPlugin } from '@toolbox-web/grid/plugins/clipboard';\nimport { registerFeature } from '../lib/feature-registry';\n\nregisterFeature('clipboard', (config) => {\n if (config === true) {\n return new ClipboardPlugin();\n }\n return new ClipboardPlugin(config ?? undefined);\n});\n"],"names":["registerFeature","config","ClipboardPlugin"],"mappings":";;AAsBAA,EAAgB,aAAa,CAACC,MACxBA,MAAW,KACN,IAAIC,EAAA,IAEN,IAAIA,EAAgBD,KAAU,MAAS,CAC/C;"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Column virtualization feature for @toolbox-web/grid-vue
3
+ *
4
+ * Import this module to enable the `columnVirtualization` prop on TbwGrid.
5
+ *
6
+ * @example
7
+ * ```vue
8
+ * <script setup>
9
+ * import '@toolbox-web/grid-vue/features/column-virtualization';
10
+ * </script>
11
+ *
12
+ * <template>
13
+ * <TbwGrid columnVirtualization />
14
+ * </template>
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=column-virtualization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-virtualization.d.ts","sourceRoot":"","sources":["../../../../libs/grid-vue/src/features/column-virtualization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
@@ -0,0 +1,4 @@
1
+ import { ColumnVirtualizationPlugin as i } from "@toolbox-web/grid/plugins/column-virtualization";
2
+ import { r as t } from "../chunks/feature-registry-BgEOysSJ.js";
3
+ t("columnVirtualization", (r) => r === !0 ? new i() : new i(r ?? void 0));
4
+ //# sourceMappingURL=column-virtualization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-virtualization.js","sources":["../../../../libs/grid-vue/src/features/column-virtualization.ts"],"sourcesContent":["/**\n * Column virtualization feature for @toolbox-web/grid-vue\n *\n * Import this module to enable the `columnVirtualization` prop on TbwGrid.\n *\n * @example\n * ```vue\n * <script setup>\n * import '@toolbox-web/grid-vue/features/column-virtualization';\n * </script>\n *\n * <template>\n * <TbwGrid columnVirtualization />\n * </template>\n * ```\n *\n * @packageDocumentation\n */\n\nimport { ColumnVirtualizationPlugin } from '@toolbox-web/grid/plugins/column-virtualization';\nimport { registerFeature } from '../lib/feature-registry';\n\nregisterFeature('columnVirtualization', (config) => {\n if (config === true) {\n return new ColumnVirtualizationPlugin();\n }\n return new ColumnVirtualizationPlugin(config ?? undefined);\n});\n"],"names":["registerFeature","config","ColumnVirtualizationPlugin"],"mappings":";;AAsBAA,EAAgB,wBAAwB,CAACC,MACnCA,MAAW,KACN,IAAIC,EAAA,IAEN,IAAIA,EAA2BD,KAAU,MAAS,CAC1D;"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Context menu feature for @toolbox-web/grid-vue
3
+ *
4
+ * Import this module to enable the `contextMenu` prop on TbwGrid.
5
+ *
6
+ * @example
7
+ * ```vue
8
+ * <script setup>
9
+ * import '@toolbox-web/grid-vue/features/context-menu';
10
+ * </script>
11
+ *
12
+ * <template>
13
+ * <TbwGrid contextMenu />
14
+ * </template>
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=context-menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-menu.d.ts","sourceRoot":"","sources":["../../../../libs/grid-vue/src/features/context-menu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
@@ -0,0 +1,4 @@
1
+ import { ContextMenuPlugin as r } from "@toolbox-web/grid/plugins/context-menu";
2
+ import { r as t } from "../chunks/feature-registry-BgEOysSJ.js";
3
+ t("contextMenu", (e) => e === !0 ? new r() : new r(e ?? void 0));
4
+ //# sourceMappingURL=context-menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-menu.js","sources":["../../../../libs/grid-vue/src/features/context-menu.ts"],"sourcesContent":["/**\n * Context menu feature for @toolbox-web/grid-vue\n *\n * Import this module to enable the `contextMenu` prop on TbwGrid.\n *\n * @example\n * ```vue\n * <script setup>\n * import '@toolbox-web/grid-vue/features/context-menu';\n * </script>\n *\n * <template>\n * <TbwGrid contextMenu />\n * </template>\n * ```\n *\n * @packageDocumentation\n */\n\nimport { ContextMenuPlugin } from '@toolbox-web/grid/plugins/context-menu';\nimport { registerFeature } from '../lib/feature-registry';\n\nregisterFeature('contextMenu', (config) => {\n if (config === true) {\n return new ContextMenuPlugin();\n }\n return new ContextMenuPlugin(config ?? undefined);\n});\n"],"names":["registerFeature","config","ContextMenuPlugin"],"mappings":";;AAsBAA,EAAgB,eAAe,CAACC,MAC1BA,MAAW,KACN,IAAIC,EAAA,IAEN,IAAIA,EAAkBD,KAAU,MAAS,CACjD;"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Editing feature for @toolbox-web/grid-vue
3
+ *
4
+ * Import this module to enable the `editing` prop on TbwGrid.
5
+ *
6
+ * @example
7
+ * ```vue
8
+ * <script setup>
9
+ * import '@toolbox-web/grid-vue/features/editing';
10
+ * </script>
11
+ *
12
+ * <template>
13
+ * <TbwGrid editing="dblclick" />
14
+ * </template>
15
+ * ```
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=editing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editing.d.ts","sourceRoot":"","sources":["../../../../libs/grid-vue/src/features/editing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
@@ -0,0 +1,4 @@
1
+ import { EditingPlugin as e } from "@toolbox-web/grid/plugins/editing";
2
+ import { r as t } from "../chunks/feature-registry-BgEOysSJ.js";
3
+ t("editing", (r) => r === !0 ? new e() : r === "click" || r === "dblclick" || r === "manual" ? new e({ editOn: r }) : new e(r ?? void 0));
4
+ //# sourceMappingURL=editing.js.map