@cocoar/vue-ui 3.1.0 → 3.2.0-beta.6
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/dist/components/checkbox/CoarCheckbox.vue.d.ts +1 -1
- package/dist/components/checkbox/CoarCheckbox.vue.d.ts.map +1 -1
- package/dist/components/code-block/CoarCodeBlock.vue.d.ts +1 -1
- package/dist/components/code-block/CoarCodeBlock.vue.d.ts.map +1 -1
- package/dist/components/data-list/CoarDataList.vue.d.ts +158 -0
- package/dist/components/data-list/CoarDataList.vue.d.ts.map +1 -0
- package/dist/components/data-list/CoarDataListToolbar.vue.d.ts +30 -0
- package/dist/components/data-list/CoarDataListToolbar.vue.d.ts.map +1 -0
- package/dist/components/data-list/data-list-builder.d.ts +288 -0
- package/dist/components/data-list/data-list-builder.d.ts.map +1 -0
- package/dist/components/data-list/index.d.ts +12 -0
- package/dist/components/data-list/index.d.ts.map +1 -0
- package/dist/components/data-list/internal/compare.d.ts +14 -0
- package/dist/components/data-list/internal/compare.d.ts.map +1 -0
- package/dist/components/data-list/internal/reorder-core.d.ts +46 -0
- package/dist/components/data-list/internal/reorder-core.d.ts.map +1 -0
- package/dist/components/data-list/internal/search.d.ts +16 -0
- package/dist/components/data-list/internal/search.d.ts.map +1 -0
- package/dist/components/data-list/internal/useDataListLines.d.ts +92 -0
- package/dist/components/data-list/internal/useDataListLines.d.ts.map +1 -0
- package/dist/components/data-list/internal/useDataListReorder.d.ts +68 -0
- package/dist/components/data-list/internal/useDataListReorder.d.ts.map +1 -0
- package/dist/components/data-list/internal/useSearchHighlight.d.ts +19 -0
- package/dist/components/data-list/internal/useSearchHighlight.d.ts.map +1 -0
- package/dist/components/data-list/types.d.ts +185 -0
- package/dist/components/data-list/types.d.ts.map +1 -0
- package/dist/components/data-list/useDataListModel.d.ts +79 -0
- package/dist/components/data-list/useDataListModel.d.ts.map +1 -0
- package/dist/components/date-time/_shared/maskito-config.d.ts +7 -2
- package/dist/components/date-time/_shared/maskito-config.d.ts.map +1 -1
- package/dist/components/date-time/_shared/time-helpers.d.ts +11 -4
- package/dist/components/date-time/_shared/time-helpers.d.ts.map +1 -1
- package/dist/components/date-time/_shared/use-date-picker-base.d.ts +1 -1
- package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts +1 -1
- package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts.map +1 -1
- package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts +1 -1
- package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts.map +1 -1
- package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts +1 -1
- package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts.map +1 -1
- package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts +3 -0
- package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts.map +1 -1
- package/dist/components/form-field/CoarFormField.vue.d.ts +1 -1
- package/dist/components/form-field/CoarFormField.vue.d.ts.map +1 -1
- package/dist/components/icon/CoarIcon.vue.d.ts +2 -2
- package/dist/components/icon/CoarIcon.vue.d.ts.map +1 -1
- package/dist/components/listbox/CoarListbox.vue.d.ts +7 -0
- package/dist/components/listbox/CoarListbox.vue.d.ts.map +1 -1
- package/dist/components/number-input/CoarNumberInput.vue.d.ts +1 -1
- package/dist/components/number-input/CoarNumberInput.vue.d.ts.map +1 -1
- package/dist/components/otp-input/CoarOtpInput.vue.d.ts +1 -1
- package/dist/components/otp-input/CoarOtpInput.vue.d.ts.map +1 -1
- package/dist/components/password-input/CoarPasswordInput.vue.d.ts +1 -1
- package/dist/components/password-input/CoarPasswordInput.vue.d.ts.map +1 -1
- package/dist/components/switch/CoarSwitch.vue.d.ts +1 -1
- package/dist/components/switch/CoarSwitch.vue.d.ts.map +1 -1
- package/dist/components/text-input/CoarTextInput.vue.d.ts +1 -1
- package/dist/components/text-input/CoarTextInput.vue.d.ts.map +1 -1
- package/dist/composables/dragRegistry.d.ts +12 -0
- package/dist/composables/dragRegistry.d.ts.map +1 -1
- package/dist/composables/index.d.ts +2 -2
- package/dist/composables/index.d.ts.map +1 -1
- package/dist/composables/useDragDrop.d.ts +62 -6
- package/dist/composables/useDragDrop.d.ts.map +1 -1
- package/dist/composables/useVirtualList.d.ts +21 -1
- package/dist/composables/useVirtualList.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4508 -2039
- package/package.json +5 -3
- package/skills/cocoar-vue-ui/SKILL.md +244 -0
- package/skills/cocoar-vue-ui/references/components/avatar.md +178 -0
- package/skills/cocoar-vue-ui/references/components/badge.md +290 -0
- package/skills/cocoar-vue-ui/references/components/breadcrumb.md +238 -0
- package/skills/cocoar-vue-ui/references/components/button.md +252 -0
- package/skills/cocoar-vue-ui/references/components/calendar/agenda-view.md +353 -0
- package/skills/cocoar-vue-ui/references/components/calendar/coar-calendar.md +1645 -0
- package/skills/cocoar-vue-ui/references/components/calendar/day-view.md +361 -0
- package/skills/cocoar-vue-ui/references/components/calendar/index.md +312 -0
- package/skills/cocoar-vue-ui/references/components/calendar/month-view.md +475 -0
- package/skills/cocoar-vue-ui/references/components/calendar/performance.md +186 -0
- package/skills/cocoar-vue-ui/references/components/calendar/timeline-view.md +301 -0
- package/skills/cocoar-vue-ui/references/components/calendar/week-view.md +382 -0
- package/skills/cocoar-vue-ui/references/components/calendar/work-week-view.md +145 -0
- package/skills/cocoar-vue-ui/references/components/calendar/year-view.md +63 -0
- package/skills/cocoar-vue-ui/references/components/card.md +151 -0
- package/skills/cocoar-vue-ui/references/components/checkbox-group.md +103 -0
- package/skills/cocoar-vue-ui/references/components/checkbox.md +279 -0
- package/skills/cocoar-vue-ui/references/components/code-block.md +241 -0
- package/skills/cocoar-vue-ui/references/components/context-menu.md +355 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/checkbox.md +213 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/date-columns.md +272 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/editing.md +236 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/multi-select.md +193 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/number.md +147 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/select.md +202 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/text.md +127 -0
- package/skills/cocoar-vue-ui/references/components/data-grid.md +1225 -0
- package/skills/cocoar-vue-ui/references/components/data-list.md +2121 -0
- package/skills/cocoar-vue-ui/references/components/date-or-time-picker.md +200 -0
- package/skills/cocoar-vue-ui/references/components/date-picker.md +203 -0
- package/skills/cocoar-vue-ui/references/components/date-time-picker.md +154 -0
- package/skills/cocoar-vue-ui/references/components/date-views.md +212 -0
- package/skills/cocoar-vue-ui/references/components/dialog.md +148 -0
- package/skills/cocoar-vue-ui/references/components/divider.md +157 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/annotations.md +400 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/coar-document-viewer.md +327 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/index.md +234 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/toolbar.md +221 -0
- package/skills/cocoar-vue-ui/references/components/drag-drop.md +267 -0
- package/skills/cocoar-vue-ui/references/components/dual-listbox.md +449 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/asset-store.md +327 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/in-memory-store.md +176 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/index.md +311 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/use-file-explorer.md +300 -0
- package/skills/cocoar-vue-ui/references/components/form-field.md +1025 -0
- package/skills/cocoar-vue-ui/references/components/fragment-parser.md +298 -0
- package/skills/cocoar-vue-ui/references/components/link.md +235 -0
- package/skills/cocoar-vue-ui/references/components/listbox.md +575 -0
- package/skills/cocoar-vue-ui/references/components/map/editor.md +448 -0
- package/skills/cocoar-vue-ui/references/components/map/index.md +351 -0
- package/skills/cocoar-vue-ui/references/components/markdown-diagrams.md +210 -0
- package/skills/cocoar-vue-ui/references/components/markdown-editor.md +1478 -0
- package/skills/cocoar-vue-ui/references/components/markdown-embeds.md +387 -0
- package/skills/cocoar-vue-ui/references/components/markdown-form.md +447 -0
- package/skills/cocoar-vue-ui/references/components/markdown.md +276 -0
- package/skills/cocoar-vue-ui/references/components/menu.md +380 -0
- package/skills/cocoar-vue-ui/references/components/mermaid.md +172 -0
- package/skills/cocoar-vue-ui/references/components/navbar.md +147 -0
- package/skills/cocoar-vue-ui/references/components/note.md +96 -0
- package/skills/cocoar-vue-ui/references/components/notice.md +131 -0
- package/skills/cocoar-vue-ui/references/components/number-input.md +215 -0
- package/skills/cocoar-vue-ui/references/components/otp-input.md +324 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/authoring-contract.md +271 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-builder.md +476 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-renderer.md +677 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/custom-elements.md +441 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/idp-integration.md +122 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/index.md +573 -0
- package/skills/cocoar-vue-ui/references/components/pagination.md +150 -0
- package/skills/cocoar-vue-ui/references/components/panel-layout.md +372 -0
- package/skills/cocoar-vue-ui/references/components/password-input.md +175 -0
- package/skills/cocoar-vue-ui/references/components/popconfirm.md +186 -0
- package/skills/cocoar-vue-ui/references/components/popover.md +173 -0
- package/skills/cocoar-vue-ui/references/components/progress-bar.md +178 -0
- package/skills/cocoar-vue-ui/references/components/radio-group.md +225 -0
- package/skills/cocoar-vue-ui/references/components/script-editor.md +1271 -0
- package/skills/cocoar-vue-ui/references/components/segmented-control.md +238 -0
- package/skills/cocoar-vue-ui/references/components/select.md +463 -0
- package/skills/cocoar-vue-ui/references/components/sidebar.md +421 -0
- package/skills/cocoar-vue-ui/references/components/spinner.md +132 -0
- package/skills/cocoar-vue-ui/references/components/switch.md +195 -0
- package/skills/cocoar-vue-ui/references/components/table.md +170 -0
- package/skills/cocoar-vue-ui/references/components/tabs.md +382 -0
- package/skills/cocoar-vue-ui/references/components/tag.md +178 -0
- package/skills/cocoar-vue-ui/references/components/text-input.md +256 -0
- package/skills/cocoar-vue-ui/references/components/toast.md +160 -0
- package/skills/cocoar-vue-ui/references/components/tooltip.md +121 -0
- package/skills/cocoar-vue-ui/references/components/transitions.md +193 -0
- package/skills/cocoar-vue-ui/references/components/tree.md +2388 -0
- package/skills/cocoar-vue-ui/references/components/virtual-list.md +212 -0
- package/skills/cocoar-vue-ui/references/components/wizard.md +251 -0
- package/skills/cocoar-vue-ui/references/components/zoned-date-time-picker.md +177 -0
- package/skills/cocoar-vue-ui/references/foundations/colors.md +708 -0
- package/skills/cocoar-vue-ui/references/foundations/design-principles.md +115 -0
- package/skills/cocoar-vue-ui/references/foundations/icons.md +381 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/formatting.md +530 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/setup.md +86 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/timezones.md +182 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/translations.md +305 -0
- package/skills/cocoar-vue-ui/references/foundations/motion.md +549 -0
- package/skills/cocoar-vue-ui/references/foundations/spacing.md +330 -0
- package/skills/cocoar-vue-ui/references/foundations/theming.md +140 -0
- package/skills/cocoar-vue-ui/references/foundations/typography.md +206 -0
- package/skills/cocoar-vue-ui/references/guide/error-handling.md +162 -0
- package/skills/cocoar-vue-ui/references/guide/getting-started.md +119 -0
- package/skills/cocoar-vue-ui/references/guide/migration-page-builder-3.md +207 -0
- package/skills/cocoar-vue-ui/references/guide/migration.md +140 -0
- package/skills/cocoar-vue-ui/references/guide/theming.md +98 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/data-grid/multi-select.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Multi-Select & Tag-Select Columns (New in 2.0)
|
|
4
|
+
|
|
5
|
+
Two column shortcuts for multi-value cells. Both store the cell value as `T[]` and share the same renderer — they differ only in the editor surface and which configurator options are available.
|
|
6
|
+
|
|
7
|
+
| | Editor | When to use |
|
|
8
|
+
|--|--|--|
|
|
9
|
+
| **`col.multiSelect()`** | `<CoarMultiSelect>` — standard trigger, dropdown shows all options with checkboxes | Curated option lists where the user picks N of M known values. Supports search, "Select all". |
|
|
10
|
+
| **`col.tagSelect()`** | `<CoarTagSelect>` — trigger renders selected values as removable chips inline; dropdown shows only not-yet-selected options | When the visual identity of selected values matters at-a-glance, or when you want `.allowCreate()` to let users add free-form values. |
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
14
|
+
|
|
15
|
+
CoarGridBuilder.create<Person>().columns([
|
|
16
|
+
(col) => col.field('name').flex(1),
|
|
17
|
+
|
|
18
|
+
(col) => col.multiSelect('tags', s => s.options(TAGS).searchable().showSelectAll())
|
|
19
|
+
.editable(true),
|
|
20
|
+
|
|
21
|
+
(col) => col.tagSelect('skills', s => s.options(SKILLS).allowCreate().display('chips'))
|
|
22
|
+
.editable(true),
|
|
23
|
+
])
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Edit-mode flow
|
|
27
|
+
|
|
28
|
+
| Action | Result |
|
|
29
|
+
|--------|--------|
|
|
30
|
+
| Double-click cell (or Enter / F2) | Opens the editor and **auto-opens the dropdown** via `afterGuiAttached` |
|
|
31
|
+
| Toggle a checkbox (multiSelect) / pick an option (tagSelect) | Updates the editor's working array. Dropdown stays open. |
|
|
32
|
+
| Click outside the dropdown / Tab / Enter | Commits — AG Grid pulls the final array via `getValue()` |
|
|
33
|
+
| Escape | Cancels (no commit) |
|
|
34
|
+
|
|
35
|
+
Unlike `col.select()` (which auto-commits on every pick because the single-value edit is *one* click), multi-value editors deliberately keep the dropdown open so the user can complete the selection. Focus-preservation prevents AG Grid's `stopEditingWhenCellsLoseFocus` from committing the array prematurely when the user clicks options in the body-teleported dropdown.
|
|
36
|
+
|
|
37
|
+
## Rendering
|
|
38
|
+
|
|
39
|
+
Both columns default to a comma-separated label list. Switch to chips via the configurator:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
col.multiSelect('tags', s => s.options(TAGS).display('chips'))
|
|
43
|
+
col.tagSelect('skills', s => s.options(SKILLS).display('chips'))
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The shared renderer (`CoarMultiSelectCellRenderer`) looks up labels from `options` — values that aren't in the option list (only possible via `col.tagSelect().allowCreate()`) fall back to `String(value)`.
|
|
47
|
+
|
|
48
|
+
## Example
|
|
49
|
+
|
|
50
|
+
**Demo — `data-grid/demos/GridMultiSelect.vue`**
|
|
51
|
+
|
|
52
|
+
```vue
|
|
53
|
+
<template>
|
|
54
|
+
<div>
|
|
55
|
+
<div style="height: 380px;">
|
|
56
|
+
<CoarDataGrid :builder="builder" />
|
|
57
|
+
</div>
|
|
58
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
59
|
+
Double-click <code>tags</code> for a checkbox-list dropdown (multi-select). Double-click <code>skills</code> for a chip-style trigger (tag-select). Both cells store <code>T[]</code>; commit happens on click-outside / Tab / Enter.
|
|
60
|
+
</div>
|
|
61
|
+
<div
|
|
62
|
+
v-if="lastChange"
|
|
63
|
+
style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; background: var(--coar-surface-neutral-subtle); font-size: 13px;"
|
|
64
|
+
>
|
|
65
|
+
Last change: <strong>{{ lastChange.row }}</strong> —
|
|
66
|
+
<code>{{ lastChange.field }}</code> →
|
|
67
|
+
<strong>{{ lastChange.newValue }}</strong>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</template>
|
|
71
|
+
|
|
72
|
+
<script setup lang="ts">
|
|
73
|
+
import { ref, shallowRef } from 'vue';
|
|
74
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
75
|
+
|
|
76
|
+
interface Person {
|
|
77
|
+
id: number;
|
|
78
|
+
name: string;
|
|
79
|
+
tags: string[];
|
|
80
|
+
skills: string[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const TAGS = [
|
|
84
|
+
{ value: 'priority', label: 'Priority' },
|
|
85
|
+
{ value: 'remote', label: 'Remote' },
|
|
86
|
+
{ value: 'onsite', label: 'Onsite' },
|
|
87
|
+
{ value: 'lead', label: 'Lead' },
|
|
88
|
+
{ value: 'intern', label: 'Intern' },
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const SKILLS = [
|
|
92
|
+
{ value: 'ts', label: 'TypeScript' },
|
|
93
|
+
{ value: 'vue', label: 'Vue' },
|
|
94
|
+
{ value: 'go', label: 'Go' },
|
|
95
|
+
{ value: 'sql', label: 'SQL' },
|
|
96
|
+
{ value: 'k8s', label: 'Kubernetes' },
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
const data = ref<Person[]>([
|
|
100
|
+
{ id: 1, name: 'Alice Johnson', tags: ['priority', 'remote'], skills: ['ts', 'vue'] },
|
|
101
|
+
{ id: 2, name: 'Bob Smith', tags: ['onsite'], skills: ['go', 'sql'] },
|
|
102
|
+
{ id: 3, name: 'Carol Williams', tags: ['lead', 'priority'], skills: ['ts', 'k8s'] },
|
|
103
|
+
{ id: 4, name: 'David Brown', tags: [], skills: ['vue'] },
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
const lastChange = shallowRef<{ row: string; field: string; newValue: string } | null>(null);
|
|
107
|
+
|
|
108
|
+
const builder = CoarGridBuilder.create<Person>()
|
|
109
|
+
.columns([
|
|
110
|
+
(col) => col.field('name').header('Name').flex(1),
|
|
111
|
+
|
|
112
|
+
// col.multiSelect — checkbox-list dropdown, chips renderer
|
|
113
|
+
(col) =>
|
|
114
|
+
col
|
|
115
|
+
.multiSelect('tags', (s) =>
|
|
116
|
+
s.options(TAGS).searchable().showSelectAll().display('chips'),
|
|
117
|
+
)
|
|
118
|
+
.header('Tags (multiSelect)')
|
|
119
|
+
.width(260)
|
|
120
|
+
.editable(true),
|
|
121
|
+
|
|
122
|
+
// col.tagSelect — chip-style trigger, allow-create, text renderer (default)
|
|
123
|
+
(col) =>
|
|
124
|
+
col
|
|
125
|
+
.tagSelect('skills', (s) => s.options(SKILLS).allowCreate())
|
|
126
|
+
.header('Skills (tagSelect)')
|
|
127
|
+
.width(260)
|
|
128
|
+
.editable(true),
|
|
129
|
+
])
|
|
130
|
+
.rowDataRef(data)
|
|
131
|
+
.stopEditingWhenCellsLoseFocus()
|
|
132
|
+
.onCellValueChanged((event) => {
|
|
133
|
+
if (!event.data || !event.colDef.field) return;
|
|
134
|
+
const next = event.newValue;
|
|
135
|
+
lastChange.value = {
|
|
136
|
+
row: event.data.name,
|
|
137
|
+
field: event.colDef.field,
|
|
138
|
+
newValue: Array.isArray(next) ? `[${next.join(', ')}]` : String(next),
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
</script>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Row-aware options
|
|
145
|
+
|
|
146
|
+
Pass a function for per-row option lists — both renderer (label lookup) and editor (dropdown) call it with the current row:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
col.multiSelect('perms', s => s.options(row => permsFor(row.role)))
|
|
150
|
+
.editable(true)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## API
|
|
154
|
+
|
|
155
|
+
### `col.multiSelect(field, configurator)`
|
|
156
|
+
|
|
157
|
+
Cell value type: `T[]`.
|
|
158
|
+
|
|
159
|
+
| Configurator method | Type | Description |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| `.options(value)` | `CoarSelectOption<T>[] \| (row) => CoarSelectOption<T>[]` | **Required.** Static array or per-row function. |
|
|
162
|
+
| `.clearable(value?)` | `boolean = true` | Show a clear button in the editor |
|
|
163
|
+
| `.searchable(value?)` | `boolean = true` | Enable search/filter in the dropdown |
|
|
164
|
+
| `.showSelectAll(value?)` | `boolean = true` | Show a "Select all" row at the top of the dropdown |
|
|
165
|
+
| `.placeholder(value)` | `string` | Placeholder shown when no values are selected |
|
|
166
|
+
| `.searchPlaceholder(value)` | `string` | Search-input placeholder (used with `.searchable()`) |
|
|
167
|
+
| `.size(value)` | `'xs' \| 's' \| 'm' \| 'l'` | Trigger size (default: `'s'`) |
|
|
168
|
+
| `.display(value)` | `'text' \| 'chips'` | Renderer display mode (default: `'text'`) |
|
|
169
|
+
|
|
170
|
+
### `col.tagSelect(field, configurator)`
|
|
171
|
+
|
|
172
|
+
Cell value type: `T[]`. The cell renderer is shared with `col.multiSelect()`; only the editor differs.
|
|
173
|
+
|
|
174
|
+
| Configurator method | Type | Description |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| `.options(value)` | `CoarSelectOption<T>[] \| (row) => CoarSelectOption<T>[]` | **Required.** Static array or per-row function. |
|
|
177
|
+
| `.placeholder(value)` | `string` | Placeholder shown when no values are selected |
|
|
178
|
+
| `.searchPlaceholder(value)` | `string` | Search-input placeholder |
|
|
179
|
+
| `.size(value)` | `'xs' \| 's' \| 'm' \| 'l'` | Trigger size (default: `'s'`) |
|
|
180
|
+
| `.allowCreate(value?)` | `boolean = true` | Let the user type free-form values not in `options` |
|
|
181
|
+
| `.display(value)` | `'text' \| 'chips'` | Renderer display mode (default: `'text'`) |
|
|
182
|
+
|
|
183
|
+
`CoarSelectOption<T>` is `{ value: T, label: string, disabled?: boolean, group?: string, icon?: string }`.
|
|
184
|
+
|
|
185
|
+
## Layered overrides
|
|
186
|
+
|
|
187
|
+
Same escape-hatches as the other column shortcuts — chain `.cellEditorConfig(...)` or `.cellRendererConfig(...)` after the factory call to swap in custom components while keeping the rest of the column setup.
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
col.multiSelect('tags', s => s.options(TAGS))
|
|
191
|
+
.editable(true)
|
|
192
|
+
.cellEditorConfig(MyCustomMultiEditor, { /* ... */ })
|
|
193
|
+
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/data-grid/number.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Number Column
|
|
4
|
+
|
|
5
|
+
`col.number(field, …)` is locale-aware in both display and editing. Two forms — pick by need:
|
|
6
|
+
|
|
7
|
+
| Form | Effect |
|
|
8
|
+
|------|--------|
|
|
9
|
+
| `col.number('amount')` or `col.number('amount', { decimals: 2 })` | **Renderer only** — locale-formatted number, no editor (legacy / display-only) |
|
|
10
|
+
| `col.number('amount', n => n.decimals(2).min(0).max(100))` | **Renderer + editor** — same formatting plus `CoarNumberCellEditor` for in-cell editing |
|
|
11
|
+
|
|
12
|
+
The callback form bundles `CoarNumberCellEditor` automatically. Adding `.editable(true)` on the outer chain enables it.
|
|
13
|
+
|
|
14
|
+
## Example
|
|
15
|
+
|
|
16
|
+
**Demo — `data-grid/demos/GridNumber.vue`**
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<template>
|
|
20
|
+
<div>
|
|
21
|
+
<div style="height: 320px;">
|
|
22
|
+
<CoarDataGrid :builder="builder" />
|
|
23
|
+
</div>
|
|
24
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
25
|
+
Double-click any quantity or price cell. Locale-aware parsing — try <code>1.234,56</code> in German or <code>1,234.56</code> in English.
|
|
26
|
+
</div>
|
|
27
|
+
<div
|
|
28
|
+
v-if="lastChange"
|
|
29
|
+
style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; background: var(--coar-surface-neutral-subtle); font-size: 13px;"
|
|
30
|
+
>
|
|
31
|
+
Last change: <strong>{{ lastChange.field }}</strong> on
|
|
32
|
+
<strong>{{ lastChange.row }}</strong> →
|
|
33
|
+
<code>{{ lastChange.newValue }}</code>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script setup lang="ts">
|
|
39
|
+
import { ref, shallowRef } from 'vue';
|
|
40
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
41
|
+
|
|
42
|
+
interface Item {
|
|
43
|
+
id: number;
|
|
44
|
+
product: string;
|
|
45
|
+
qty: number;
|
|
46
|
+
price: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const data = ref<Item[]>([
|
|
50
|
+
{ id: 1, product: 'Widget A', qty: 12, price: 49.95 },
|
|
51
|
+
{ id: 2, product: 'Widget B', qty: 0, price: 19.50 },
|
|
52
|
+
{ id: 3, product: 'Widget C', qty: 5, price: 199.00 },
|
|
53
|
+
{ id: 4, product: 'Widget D', qty: 28, price: 7.25 },
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
const lastChange = shallowRef<{ row: string; field: string; newValue: number } | null>(null);
|
|
57
|
+
|
|
58
|
+
const builder = CoarGridBuilder.create<Item>()
|
|
59
|
+
.columns([
|
|
60
|
+
(col) => col.field('product').header('Product').flex(1),
|
|
61
|
+
(col) =>
|
|
62
|
+
col
|
|
63
|
+
.number('qty', (n) => n.decimals(0).min(0).max(9999).step(1).stepperButtons('both').size('s'))
|
|
64
|
+
.header('Qty')
|
|
65
|
+
.width(140)
|
|
66
|
+
.editable(true),
|
|
67
|
+
(col) =>
|
|
68
|
+
col
|
|
69
|
+
.number('price', (n) => n.decimals(2).min(0).step(0.01))
|
|
70
|
+
.header('Price')
|
|
71
|
+
.width(140)
|
|
72
|
+
.editable(true),
|
|
73
|
+
])
|
|
74
|
+
.rowDataRef(data)
|
|
75
|
+
.stopEditingWhenCellsLoseFocus()
|
|
76
|
+
.onCellValueChanged((event) => {
|
|
77
|
+
if (!event.data || !event.colDef.field) return;
|
|
78
|
+
lastChange.value = {
|
|
79
|
+
row: event.data.product,
|
|
80
|
+
field: event.colDef.field,
|
|
81
|
+
newValue: event.newValue,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
</script>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
CoarGridBuilder.create<Item>().columns([
|
|
89
|
+
(col) => col.field('product').flex(1),
|
|
90
|
+
(col) =>
|
|
91
|
+
col
|
|
92
|
+
.number('qty', n => n.min(0).max(9999).step(1).stepperButtons('both'))
|
|
93
|
+
.editable(true),
|
|
94
|
+
(col) =>
|
|
95
|
+
col
|
|
96
|
+
.number('price', n => n.decimals(2).min(0).step(0.01))
|
|
97
|
+
.editable(true),
|
|
98
|
+
])
|
|
99
|
+
.stopEditingWhenCellsLoseFocus()
|
|
100
|
+
.onCellValueChanged(event => save(event.data, event.colDef.field, event.newValue));
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The renderer uses `useL10n().fmtNumber()` so the display reactively follows the active locale (try the locale switcher in the docs nav). The editor uses Maskito for locale-aware parsing — `1.234,56` in `de-AT` and `1,234.56` in `en-US` both yield the same numeric value.
|
|
104
|
+
|
|
105
|
+
## Edit-mode flow
|
|
106
|
+
|
|
107
|
+
| Action | Result |
|
|
108
|
+
|--------|--------|
|
|
109
|
+
| Double-click cell (or Enter / F2) | Opens `CoarNumberCellEditor` with focus, existing value selected |
|
|
110
|
+
| Type a digit / `.` / `,` / `-` on a focused cell | Opens editor seeded with that key |
|
|
111
|
+
| Tab | Commits + moves to the next editable cell |
|
|
112
|
+
| Enter | Commits + stays |
|
|
113
|
+
| Escape | Cancels |
|
|
114
|
+
|
|
115
|
+
## Layered overrides
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// Override editor (e.g. add custom validation)
|
|
119
|
+
col.number('qty', n => n.min(0)).editable(true).cellEditorConfig(MyOwnEditor, { ... })
|
|
120
|
+
|
|
121
|
+
// Override editable per-row
|
|
122
|
+
col.number('qty', n => n.min(0)).editable(row => !row.archived)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## API
|
|
126
|
+
|
|
127
|
+
### `col.number(field, configOrCallback?)`
|
|
128
|
+
|
|
129
|
+
**Config-object form** (legacy — renderer only):
|
|
130
|
+
|
|
131
|
+
| Property | Type | Description |
|
|
132
|
+
|----------|------|-------------|
|
|
133
|
+
| `decimals` | `number` | Number of decimal places |
|
|
134
|
+
|
|
135
|
+
**Callback form** (renderer + editor — `NumberColumnConfigurator`):
|
|
136
|
+
|
|
137
|
+
| Method | Type | Renderer / Editor | Description |
|
|
138
|
+
|--------|------|-------------------|-------------|
|
|
139
|
+
| `.decimals(value)` | `number` | both | Decimal places |
|
|
140
|
+
| `.min(value)` | `number` | editor | Minimum allowed value |
|
|
141
|
+
| `.max(value)` | `number` | editor | Maximum allowed value |
|
|
142
|
+
| `.step(value)` | `number` | editor | Step increment for arrows / stepper |
|
|
143
|
+
| `.stepperButtons(value)` | `'none' \| 'increment' \| 'decrement' \| 'both'` | editor | Stepper button mode |
|
|
144
|
+
| `.placeholder(value)` | `string` | editor | Placeholder text |
|
|
145
|
+
| `.size(value)` | `'xs' \| 's' \| 'm' \| 'l'` | editor | Input size (default: `'s'`) |
|
|
146
|
+
|
|
147
|
+
Editor commits via `getValue()` returning a `number | null`. Combine with `gridBuilder.stopEditingWhenCellsLoseFocus()` so clicking outside also commits.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/data-grid/select.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Select Column
|
|
4
|
+
|
|
5
|
+
`col.select(field, configurator)` declares a select column whose renderer shows the **label** of the matched option and whose editor is `<CoarSelect>` — same visual language as forms, with the dropdown teleported to `<body>` so it can overflow the cell freely.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
9
|
+
|
|
10
|
+
const ROLES = [
|
|
11
|
+
{ value: 'eng', label: 'Engineer' },
|
|
12
|
+
{ value: 'des', label: 'Designer' },
|
|
13
|
+
{ value: 'mgr', label: 'Manager' },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
CoarGridBuilder.create<Person>().columns([
|
|
17
|
+
(col) => col.field('name').flex(1),
|
|
18
|
+
(col) => col.select('role', s => s.options(ROLES)).editable(true),
|
|
19
|
+
])
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The configurator's `options` is required — there's no useful "select column without options".
|
|
23
|
+
|
|
24
|
+
## Edit-mode flow
|
|
25
|
+
|
|
26
|
+
| Action | Result |
|
|
27
|
+
|--------|--------|
|
|
28
|
+
| Double-click cell (or Enter / F2) | Opens `CoarSelectCellEditor` and **auto-opens the dropdown** via `afterGuiAttached` |
|
|
29
|
+
| Click an option (or Enter on highlighted) | Auto-commits + exits edit mode in one step |
|
|
30
|
+
| Up / Down | Highlight previous / next option |
|
|
31
|
+
| Type a character (when `searchable: true`) | Filters the option list |
|
|
32
|
+
| Escape | Closes dropdown; pressing again cancels edit |
|
|
33
|
+
|
|
34
|
+
The auto-commit is intentional — for a select, picking an option **is** the edit. Tab-through-edit-mode still works on the surrounding cells; the select cell just commits faster than free-form text would.
|
|
35
|
+
|
|
36
|
+
## Example
|
|
37
|
+
|
|
38
|
+
**Demo — `data-grid/demos/GridSelect.vue`**
|
|
39
|
+
|
|
40
|
+
```vue
|
|
41
|
+
<template>
|
|
42
|
+
<div>
|
|
43
|
+
<div style="height: 320px;">
|
|
44
|
+
<CoarDataGrid :builder="builder" />
|
|
45
|
+
</div>
|
|
46
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
47
|
+
Double-click any role / status / country cell to open the dropdown. Selecting an option auto-commits.
|
|
48
|
+
</div>
|
|
49
|
+
<div
|
|
50
|
+
v-if="lastChange"
|
|
51
|
+
style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; background: var(--coar-surface-neutral-subtle); font-size: 13px;"
|
|
52
|
+
>
|
|
53
|
+
Last change: <strong>{{ lastChange.row }}</strong> —
|
|
54
|
+
<code>{{ lastChange.field }}</code> →
|
|
55
|
+
<strong>{{ lastChange.newValue }}</strong>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<script setup lang="ts">
|
|
61
|
+
import { ref, shallowRef } from 'vue';
|
|
62
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
63
|
+
|
|
64
|
+
interface Person {
|
|
65
|
+
id: number;
|
|
66
|
+
name: string;
|
|
67
|
+
role: 'eng' | 'des' | 'mgr';
|
|
68
|
+
status: 'active' | 'pending' | 'archived';
|
|
69
|
+
country: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const ROLES = [
|
|
73
|
+
{ value: 'eng', label: 'Engineer' },
|
|
74
|
+
{ value: 'des', label: 'Designer' },
|
|
75
|
+
{ value: 'mgr', label: 'Manager' },
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
const STATUSES = [
|
|
79
|
+
{ value: 'active', label: 'Active' },
|
|
80
|
+
{ value: 'pending', label: 'Pending' },
|
|
81
|
+
{ value: 'archived', label: 'Archived' },
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
const COUNTRIES = [
|
|
85
|
+
{ value: 'AT', label: 'Austria' },
|
|
86
|
+
{ value: 'DE', label: 'Germany' },
|
|
87
|
+
{ value: 'CH', label: 'Switzerland' },
|
|
88
|
+
{ value: 'IT', label: 'Italy' },
|
|
89
|
+
{ value: 'FR', label: 'France' },
|
|
90
|
+
{ value: 'ES', label: 'Spain' },
|
|
91
|
+
{ value: 'PT', label: 'Portugal' },
|
|
92
|
+
{ value: 'NL', label: 'Netherlands' },
|
|
93
|
+
{ value: 'BE', label: 'Belgium' },
|
|
94
|
+
{ value: 'SE', label: 'Sweden' },
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
const data = ref<Person[]>([
|
|
98
|
+
{ id: 1, name: 'Alice Johnson', role: 'eng', status: 'active', country: 'AT' },
|
|
99
|
+
{ id: 2, name: 'Bob Smith', role: 'des', status: 'pending', country: 'DE' },
|
|
100
|
+
{ id: 3, name: 'Carol Williams', role: 'mgr', status: 'active', country: 'CH' },
|
|
101
|
+
{ id: 4, name: 'David Brown', role: 'eng', status: 'archived', country: 'FR' },
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
const lastChange = shallowRef<{ row: string; field: string; newValue: string } | null>(null);
|
|
105
|
+
|
|
106
|
+
const builder = CoarGridBuilder.create<Person>()
|
|
107
|
+
.columns([
|
|
108
|
+
(col) => col.field('name').header('Name').flex(1),
|
|
109
|
+
(col) =>
|
|
110
|
+
col
|
|
111
|
+
.select('role', (s) => s.options(ROLES))
|
|
112
|
+
.header('Role')
|
|
113
|
+
.width(140)
|
|
114
|
+
.editable(true),
|
|
115
|
+
(col) =>
|
|
116
|
+
col
|
|
117
|
+
.select('status', (s) => s.options(STATUSES).clearable())
|
|
118
|
+
.header('Status')
|
|
119
|
+
.width(140)
|
|
120
|
+
.editable((row) => row.status !== 'archived'),
|
|
121
|
+
(col) =>
|
|
122
|
+
col
|
|
123
|
+
.select('country', (s) =>
|
|
124
|
+
s.options(COUNTRIES).searchable().searchPlaceholder('Filter countries…'),
|
|
125
|
+
)
|
|
126
|
+
.header('Country')
|
|
127
|
+
.width(160)
|
|
128
|
+
.editable(true),
|
|
129
|
+
])
|
|
130
|
+
.rowDataRef(data)
|
|
131
|
+
.stopEditingWhenCellsLoseFocus()
|
|
132
|
+
.onCellValueChanged((event) => {
|
|
133
|
+
if (!event.data || !event.colDef.field) return;
|
|
134
|
+
lastChange.value = {
|
|
135
|
+
row: event.data.name,
|
|
136
|
+
field: event.colDef.field,
|
|
137
|
+
newValue: String(event.newValue),
|
|
138
|
+
};
|
|
139
|
+
});
|
|
140
|
+
</script>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
CoarGridBuilder.create<Person>().columns([
|
|
145
|
+
(col) => col.field('name').flex(1),
|
|
146
|
+
|
|
147
|
+
// simple
|
|
148
|
+
(col) => col.select('role', s => s.options(ROLES)).editable(true),
|
|
149
|
+
|
|
150
|
+
// clearable + per-row gating (archived rows are read-only)
|
|
151
|
+
(col) =>
|
|
152
|
+
col.select('status', s => s.options(STATUSES).clearable())
|
|
153
|
+
.editable(row => row.status !== 'archived'),
|
|
154
|
+
|
|
155
|
+
// searchable for long lists
|
|
156
|
+
(col) =>
|
|
157
|
+
col.select('country', s => s.options(COUNTRIES).searchable())
|
|
158
|
+
.editable(true),
|
|
159
|
+
])
|
|
160
|
+
.stopEditingWhenCellsLoseFocus();
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Row-aware options
|
|
164
|
+
|
|
165
|
+
Pass a function instead of a static array to compute options per row:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
col.select('parent', s =>
|
|
169
|
+
s.options(row => allowedParents(row.type))
|
|
170
|
+
).editable(true)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Both renderer (label lookup) and editor (dropdown options) call the function with the current row, so display and edit stay consistent.
|
|
174
|
+
|
|
175
|
+
## Layered overrides
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// Replace the editor entirely (drops the configurator)
|
|
179
|
+
col.select('role', s => s.options(ROLES))
|
|
180
|
+
.editable(true)
|
|
181
|
+
.cellEditorConfig(MyCustomSelect, { … })
|
|
182
|
+
|
|
183
|
+
// Keep the bundled renderer + editor, override editable
|
|
184
|
+
col.select('role', s => s.options(ROLES)).editable(false)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## API
|
|
188
|
+
|
|
189
|
+
### `col.select(field, configurator)`
|
|
190
|
+
|
|
191
|
+
| Configurator method | Type | Description |
|
|
192
|
+
|--------|------|-------------|
|
|
193
|
+
| `.options(value)` | `CoarSelectOption<T>[] \| (row) => CoarSelectOption<T>[]` | **Required.** Static array or per-row function. |
|
|
194
|
+
| `.clearable(value?)` | `boolean = true` | Show a clear button in the editor |
|
|
195
|
+
| `.searchable(value?)` | `boolean = true` | Enable search/filter in the dropdown |
|
|
196
|
+
| `.placeholder(value)` | `string` | Placeholder shown when no value is selected |
|
|
197
|
+
| `.searchPlaceholder(value)` | `string` | Search-input placeholder (used with `.searchable()`) |
|
|
198
|
+
| `.size(value)` | `'xs' \| 's' \| 'm' \| 'l'` | Trigger size (default: `'s'`) |
|
|
199
|
+
|
|
200
|
+
`CoarSelectOption<T>` is `{ value: T, label: string, disabled?: boolean, group?: string, icon?: string }`.
|
|
201
|
+
|
|
202
|
+
Editor commits via `getValue()` returning the option `value`. The dropdown panel is teleported to `<body>` (Coar overlay-host) so it can extend past the cell / grid boundaries without clipping.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/data-grid/text.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Text Column
|
|
4
|
+
|
|
5
|
+
`col.text(field, configurator?)` declares a text column whose editor is `<CoarTextInput>` — same visual language as forms, fitted into the cell.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
9
|
+
|
|
10
|
+
CoarGridBuilder.create<Person>().columns([
|
|
11
|
+
(col) => col.text('name').editable(true),
|
|
12
|
+
(col) => col.text('email', t => t.placeholder('user@example.com').maxLength(120)).editable(true),
|
|
13
|
+
])
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Read-only display uses AG Grid's default text rendering — same as plain `.field()`. The shortcut adds:
|
|
17
|
+
- A configurable `CoarTextCellEditor` that opens on double-click / Enter / F2
|
|
18
|
+
- `sortable: true` by default
|
|
19
|
+
|
|
20
|
+
## Edit-mode flow
|
|
21
|
+
|
|
22
|
+
| Action | Result |
|
|
23
|
+
|--------|--------|
|
|
24
|
+
| Double-click cell (or Enter / F2) | Opens `CoarTextCellEditor` with focus on the input, existing value selected |
|
|
25
|
+
| Type a printable key on a focused cell | Opens editor seeded with that key (replace mode) |
|
|
26
|
+
| Tab | Commits + moves focus to the next editable cell, opening its editor automatically |
|
|
27
|
+
| Enter | Commits + stays |
|
|
28
|
+
| Escape | Cancels |
|
|
29
|
+
|
|
30
|
+
Toggles fire `cellValueChanged` like any other commit, so a single grid-level handler covers all column types.
|
|
31
|
+
|
|
32
|
+
## Example
|
|
33
|
+
|
|
34
|
+
**Demo — `data-grid/demos/GridText.vue`**
|
|
35
|
+
|
|
36
|
+
```vue
|
|
37
|
+
<template>
|
|
38
|
+
<div>
|
|
39
|
+
<div style="height: 320px;">
|
|
40
|
+
<CoarDataGrid :builder="builder" />
|
|
41
|
+
</div>
|
|
42
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
43
|
+
Double-click any name or email cell. <strong>Tab</strong> commits and moves to the next editable cell, <strong>Enter</strong> commits, <strong>Escape</strong> cancels.
|
|
44
|
+
</div>
|
|
45
|
+
<div
|
|
46
|
+
v-if="lastChange"
|
|
47
|
+
style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; background: var(--coar-surface-neutral-subtle); font-size: 13px;"
|
|
48
|
+
>
|
|
49
|
+
Last change: <strong>{{ lastChange.field }}</strong> on
|
|
50
|
+
<strong>{{ lastChange.row }}</strong> →
|
|
51
|
+
<code>{{ lastChange.newValue }}</code>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<script setup lang="ts">
|
|
57
|
+
import { ref, shallowRef } from 'vue';
|
|
58
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
59
|
+
|
|
60
|
+
interface Person {
|
|
61
|
+
id: number;
|
|
62
|
+
name: string;
|
|
63
|
+
email: string;
|
|
64
|
+
role: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const data = ref<Person[]>([
|
|
68
|
+
{ id: 1, name: 'Alice Johnson', email: 'alice@example.com', role: 'Engineer' },
|
|
69
|
+
{ id: 2, name: 'Bob Smith', email: 'bob@example.com', role: 'Designer' },
|
|
70
|
+
{ id: 3, name: 'Carol Williams', email: 'carol@example.com', role: 'Manager' },
|
|
71
|
+
{ id: 4, name: 'David Brown', email: 'david@example.com', role: 'Engineer' },
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
const lastChange = shallowRef<{ row: string; field: string; newValue: string } | null>(null);
|
|
75
|
+
|
|
76
|
+
const builder = CoarGridBuilder.create<Person>()
|
|
77
|
+
.columns([
|
|
78
|
+
(col) => col.text('name', (t) => t.placeholder('Name').maxLength(80)).header('Name').flex(1).editable(true),
|
|
79
|
+
(col) => col.text('email', (t) => t.placeholder('user@example.com').maxLength(120)).header('Email').flex(1).editable(true),
|
|
80
|
+
(col) => col.field('role').header('Role').width(140), // not editable
|
|
81
|
+
])
|
|
82
|
+
.rowDataRef(data)
|
|
83
|
+
.stopEditingWhenCellsLoseFocus()
|
|
84
|
+
.onCellValueChanged((event) => {
|
|
85
|
+
if (!event.data || !event.colDef.field) return;
|
|
86
|
+
lastChange.value = {
|
|
87
|
+
row: event.data.name,
|
|
88
|
+
field: event.colDef.field,
|
|
89
|
+
newValue: String(event.newValue),
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
</script>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
CoarGridBuilder.create<Person>().columns([
|
|
97
|
+
(col) => col.text('name', t => t.placeholder('Name').maxLength(80)).editable(true),
|
|
98
|
+
(col) => col.text('email', t => t.placeholder('user@example.com').maxLength(120)).editable(true),
|
|
99
|
+
(col) => col.field('role'), // not editable
|
|
100
|
+
])
|
|
101
|
+
.stopEditingWhenCellsLoseFocus()
|
|
102
|
+
.onCellValueChanged(event => save(event.data, event.colDef.field, event.newValue));
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Layered overrides
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
// Replace the editor (drops the configurator)
|
|
109
|
+
col.text('name').editable(true).cellEditorConfig(MyCustomEditor, { ... })
|
|
110
|
+
|
|
111
|
+
// Keep the bundled editor, override editable
|
|
112
|
+
col.text('name').editable(row => !row.locked)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## API
|
|
116
|
+
|
|
117
|
+
### `col.text(field, configurator?)`
|
|
118
|
+
|
|
119
|
+
| Configurator method | Type | Description |
|
|
120
|
+
|--------|------|-------------|
|
|
121
|
+
| `.placeholder(value)` | `string` | Placeholder shown when input is empty |
|
|
122
|
+
| `.maxLength(value)` | `number` | Max input length |
|
|
123
|
+
| `.size(value)` | `'xs' \| 's' \| 'm' \| 'l'` | Input size (default: `'s'`) |
|
|
124
|
+
| `.prefix(value)` | `string` | Text shown before the input value |
|
|
125
|
+
| `.suffix(value)` | `string` | Text shown after the input value |
|
|
126
|
+
|
|
127
|
+
Editor commits via `getValue()` per AG Grid's contract — Tab / Enter / Escape are handled by AG Grid's native edit-mode logic. Combine with `gridBuilder.stopEditingWhenCellsLoseFocus()` so clicking outside also commits.
|