@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.
Files changed (179) hide show
  1. package/dist/components/checkbox/CoarCheckbox.vue.d.ts +1 -1
  2. package/dist/components/checkbox/CoarCheckbox.vue.d.ts.map +1 -1
  3. package/dist/components/code-block/CoarCodeBlock.vue.d.ts +1 -1
  4. package/dist/components/code-block/CoarCodeBlock.vue.d.ts.map +1 -1
  5. package/dist/components/data-list/CoarDataList.vue.d.ts +158 -0
  6. package/dist/components/data-list/CoarDataList.vue.d.ts.map +1 -0
  7. package/dist/components/data-list/CoarDataListToolbar.vue.d.ts +30 -0
  8. package/dist/components/data-list/CoarDataListToolbar.vue.d.ts.map +1 -0
  9. package/dist/components/data-list/data-list-builder.d.ts +288 -0
  10. package/dist/components/data-list/data-list-builder.d.ts.map +1 -0
  11. package/dist/components/data-list/index.d.ts +12 -0
  12. package/dist/components/data-list/index.d.ts.map +1 -0
  13. package/dist/components/data-list/internal/compare.d.ts +14 -0
  14. package/dist/components/data-list/internal/compare.d.ts.map +1 -0
  15. package/dist/components/data-list/internal/reorder-core.d.ts +46 -0
  16. package/dist/components/data-list/internal/reorder-core.d.ts.map +1 -0
  17. package/dist/components/data-list/internal/search.d.ts +16 -0
  18. package/dist/components/data-list/internal/search.d.ts.map +1 -0
  19. package/dist/components/data-list/internal/useDataListLines.d.ts +92 -0
  20. package/dist/components/data-list/internal/useDataListLines.d.ts.map +1 -0
  21. package/dist/components/data-list/internal/useDataListReorder.d.ts +68 -0
  22. package/dist/components/data-list/internal/useDataListReorder.d.ts.map +1 -0
  23. package/dist/components/data-list/internal/useSearchHighlight.d.ts +19 -0
  24. package/dist/components/data-list/internal/useSearchHighlight.d.ts.map +1 -0
  25. package/dist/components/data-list/types.d.ts +185 -0
  26. package/dist/components/data-list/types.d.ts.map +1 -0
  27. package/dist/components/data-list/useDataListModel.d.ts +79 -0
  28. package/dist/components/data-list/useDataListModel.d.ts.map +1 -0
  29. package/dist/components/date-time/_shared/maskito-config.d.ts +7 -2
  30. package/dist/components/date-time/_shared/maskito-config.d.ts.map +1 -1
  31. package/dist/components/date-time/_shared/time-helpers.d.ts +11 -4
  32. package/dist/components/date-time/_shared/time-helpers.d.ts.map +1 -1
  33. package/dist/components/date-time/_shared/use-date-picker-base.d.ts +1 -1
  34. package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts +1 -1
  35. package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts.map +1 -1
  36. package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts +1 -1
  37. package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts.map +1 -1
  38. package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts +1 -1
  39. package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts.map +1 -1
  40. package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts +3 -0
  41. package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts.map +1 -1
  42. package/dist/components/form-field/CoarFormField.vue.d.ts +1 -1
  43. package/dist/components/form-field/CoarFormField.vue.d.ts.map +1 -1
  44. package/dist/components/icon/CoarIcon.vue.d.ts +2 -2
  45. package/dist/components/icon/CoarIcon.vue.d.ts.map +1 -1
  46. package/dist/components/listbox/CoarListbox.vue.d.ts +7 -0
  47. package/dist/components/listbox/CoarListbox.vue.d.ts.map +1 -1
  48. package/dist/components/number-input/CoarNumberInput.vue.d.ts +1 -1
  49. package/dist/components/number-input/CoarNumberInput.vue.d.ts.map +1 -1
  50. package/dist/components/otp-input/CoarOtpInput.vue.d.ts +1 -1
  51. package/dist/components/otp-input/CoarOtpInput.vue.d.ts.map +1 -1
  52. package/dist/components/password-input/CoarPasswordInput.vue.d.ts +1 -1
  53. package/dist/components/password-input/CoarPasswordInput.vue.d.ts.map +1 -1
  54. package/dist/components/switch/CoarSwitch.vue.d.ts +1 -1
  55. package/dist/components/switch/CoarSwitch.vue.d.ts.map +1 -1
  56. package/dist/components/text-input/CoarTextInput.vue.d.ts +1 -1
  57. package/dist/components/text-input/CoarTextInput.vue.d.ts.map +1 -1
  58. package/dist/composables/dragRegistry.d.ts +12 -0
  59. package/dist/composables/dragRegistry.d.ts.map +1 -1
  60. package/dist/composables/index.d.ts +2 -2
  61. package/dist/composables/index.d.ts.map +1 -1
  62. package/dist/composables/useDragDrop.d.ts +62 -6
  63. package/dist/composables/useDragDrop.d.ts.map +1 -1
  64. package/dist/composables/useVirtualList.d.ts +21 -1
  65. package/dist/composables/useVirtualList.d.ts.map +1 -1
  66. package/dist/index.css +1 -1
  67. package/dist/index.d.ts +4 -2
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +4508 -2039
  70. package/package.json +5 -3
  71. package/skills/cocoar-vue-ui/SKILL.md +244 -0
  72. package/skills/cocoar-vue-ui/references/components/avatar.md +178 -0
  73. package/skills/cocoar-vue-ui/references/components/badge.md +290 -0
  74. package/skills/cocoar-vue-ui/references/components/breadcrumb.md +238 -0
  75. package/skills/cocoar-vue-ui/references/components/button.md +252 -0
  76. package/skills/cocoar-vue-ui/references/components/calendar/agenda-view.md +353 -0
  77. package/skills/cocoar-vue-ui/references/components/calendar/coar-calendar.md +1645 -0
  78. package/skills/cocoar-vue-ui/references/components/calendar/day-view.md +361 -0
  79. package/skills/cocoar-vue-ui/references/components/calendar/index.md +312 -0
  80. package/skills/cocoar-vue-ui/references/components/calendar/month-view.md +475 -0
  81. package/skills/cocoar-vue-ui/references/components/calendar/performance.md +186 -0
  82. package/skills/cocoar-vue-ui/references/components/calendar/timeline-view.md +301 -0
  83. package/skills/cocoar-vue-ui/references/components/calendar/week-view.md +382 -0
  84. package/skills/cocoar-vue-ui/references/components/calendar/work-week-view.md +145 -0
  85. package/skills/cocoar-vue-ui/references/components/calendar/year-view.md +63 -0
  86. package/skills/cocoar-vue-ui/references/components/card.md +151 -0
  87. package/skills/cocoar-vue-ui/references/components/checkbox-group.md +103 -0
  88. package/skills/cocoar-vue-ui/references/components/checkbox.md +279 -0
  89. package/skills/cocoar-vue-ui/references/components/code-block.md +241 -0
  90. package/skills/cocoar-vue-ui/references/components/context-menu.md +355 -0
  91. package/skills/cocoar-vue-ui/references/components/data-grid/checkbox.md +213 -0
  92. package/skills/cocoar-vue-ui/references/components/data-grid/date-columns.md +272 -0
  93. package/skills/cocoar-vue-ui/references/components/data-grid/editing.md +236 -0
  94. package/skills/cocoar-vue-ui/references/components/data-grid/multi-select.md +193 -0
  95. package/skills/cocoar-vue-ui/references/components/data-grid/number.md +147 -0
  96. package/skills/cocoar-vue-ui/references/components/data-grid/select.md +202 -0
  97. package/skills/cocoar-vue-ui/references/components/data-grid/text.md +127 -0
  98. package/skills/cocoar-vue-ui/references/components/data-grid.md +1225 -0
  99. package/skills/cocoar-vue-ui/references/components/data-list.md +2121 -0
  100. package/skills/cocoar-vue-ui/references/components/date-or-time-picker.md +200 -0
  101. package/skills/cocoar-vue-ui/references/components/date-picker.md +203 -0
  102. package/skills/cocoar-vue-ui/references/components/date-time-picker.md +154 -0
  103. package/skills/cocoar-vue-ui/references/components/date-views.md +212 -0
  104. package/skills/cocoar-vue-ui/references/components/dialog.md +148 -0
  105. package/skills/cocoar-vue-ui/references/components/divider.md +157 -0
  106. package/skills/cocoar-vue-ui/references/components/document-viewer/annotations.md +400 -0
  107. package/skills/cocoar-vue-ui/references/components/document-viewer/coar-document-viewer.md +327 -0
  108. package/skills/cocoar-vue-ui/references/components/document-viewer/index.md +234 -0
  109. package/skills/cocoar-vue-ui/references/components/document-viewer/toolbar.md +221 -0
  110. package/skills/cocoar-vue-ui/references/components/drag-drop.md +267 -0
  111. package/skills/cocoar-vue-ui/references/components/dual-listbox.md +449 -0
  112. package/skills/cocoar-vue-ui/references/components/file-explorer/asset-store.md +327 -0
  113. package/skills/cocoar-vue-ui/references/components/file-explorer/in-memory-store.md +176 -0
  114. package/skills/cocoar-vue-ui/references/components/file-explorer/index.md +311 -0
  115. package/skills/cocoar-vue-ui/references/components/file-explorer/use-file-explorer.md +300 -0
  116. package/skills/cocoar-vue-ui/references/components/form-field.md +1025 -0
  117. package/skills/cocoar-vue-ui/references/components/fragment-parser.md +298 -0
  118. package/skills/cocoar-vue-ui/references/components/link.md +235 -0
  119. package/skills/cocoar-vue-ui/references/components/listbox.md +575 -0
  120. package/skills/cocoar-vue-ui/references/components/map/editor.md +448 -0
  121. package/skills/cocoar-vue-ui/references/components/map/index.md +351 -0
  122. package/skills/cocoar-vue-ui/references/components/markdown-diagrams.md +210 -0
  123. package/skills/cocoar-vue-ui/references/components/markdown-editor.md +1478 -0
  124. package/skills/cocoar-vue-ui/references/components/markdown-embeds.md +387 -0
  125. package/skills/cocoar-vue-ui/references/components/markdown-form.md +447 -0
  126. package/skills/cocoar-vue-ui/references/components/markdown.md +276 -0
  127. package/skills/cocoar-vue-ui/references/components/menu.md +380 -0
  128. package/skills/cocoar-vue-ui/references/components/mermaid.md +172 -0
  129. package/skills/cocoar-vue-ui/references/components/navbar.md +147 -0
  130. package/skills/cocoar-vue-ui/references/components/note.md +96 -0
  131. package/skills/cocoar-vue-ui/references/components/notice.md +131 -0
  132. package/skills/cocoar-vue-ui/references/components/number-input.md +215 -0
  133. package/skills/cocoar-vue-ui/references/components/otp-input.md +324 -0
  134. package/skills/cocoar-vue-ui/references/components/page-builder/authoring-contract.md +271 -0
  135. package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-builder.md +476 -0
  136. package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-renderer.md +677 -0
  137. package/skills/cocoar-vue-ui/references/components/page-builder/custom-elements.md +441 -0
  138. package/skills/cocoar-vue-ui/references/components/page-builder/idp-integration.md +122 -0
  139. package/skills/cocoar-vue-ui/references/components/page-builder/index.md +573 -0
  140. package/skills/cocoar-vue-ui/references/components/pagination.md +150 -0
  141. package/skills/cocoar-vue-ui/references/components/panel-layout.md +372 -0
  142. package/skills/cocoar-vue-ui/references/components/password-input.md +175 -0
  143. package/skills/cocoar-vue-ui/references/components/popconfirm.md +186 -0
  144. package/skills/cocoar-vue-ui/references/components/popover.md +173 -0
  145. package/skills/cocoar-vue-ui/references/components/progress-bar.md +178 -0
  146. package/skills/cocoar-vue-ui/references/components/radio-group.md +225 -0
  147. package/skills/cocoar-vue-ui/references/components/script-editor.md +1271 -0
  148. package/skills/cocoar-vue-ui/references/components/segmented-control.md +238 -0
  149. package/skills/cocoar-vue-ui/references/components/select.md +463 -0
  150. package/skills/cocoar-vue-ui/references/components/sidebar.md +421 -0
  151. package/skills/cocoar-vue-ui/references/components/spinner.md +132 -0
  152. package/skills/cocoar-vue-ui/references/components/switch.md +195 -0
  153. package/skills/cocoar-vue-ui/references/components/table.md +170 -0
  154. package/skills/cocoar-vue-ui/references/components/tabs.md +382 -0
  155. package/skills/cocoar-vue-ui/references/components/tag.md +178 -0
  156. package/skills/cocoar-vue-ui/references/components/text-input.md +256 -0
  157. package/skills/cocoar-vue-ui/references/components/toast.md +160 -0
  158. package/skills/cocoar-vue-ui/references/components/tooltip.md +121 -0
  159. package/skills/cocoar-vue-ui/references/components/transitions.md +193 -0
  160. package/skills/cocoar-vue-ui/references/components/tree.md +2388 -0
  161. package/skills/cocoar-vue-ui/references/components/virtual-list.md +212 -0
  162. package/skills/cocoar-vue-ui/references/components/wizard.md +251 -0
  163. package/skills/cocoar-vue-ui/references/components/zoned-date-time-picker.md +177 -0
  164. package/skills/cocoar-vue-ui/references/foundations/colors.md +708 -0
  165. package/skills/cocoar-vue-ui/references/foundations/design-principles.md +115 -0
  166. package/skills/cocoar-vue-ui/references/foundations/icons.md +381 -0
  167. package/skills/cocoar-vue-ui/references/foundations/localization/formatting.md +530 -0
  168. package/skills/cocoar-vue-ui/references/foundations/localization/setup.md +86 -0
  169. package/skills/cocoar-vue-ui/references/foundations/localization/timezones.md +182 -0
  170. package/skills/cocoar-vue-ui/references/foundations/localization/translations.md +305 -0
  171. package/skills/cocoar-vue-ui/references/foundations/motion.md +549 -0
  172. package/skills/cocoar-vue-ui/references/foundations/spacing.md +330 -0
  173. package/skills/cocoar-vue-ui/references/foundations/theming.md +140 -0
  174. package/skills/cocoar-vue-ui/references/foundations/typography.md +206 -0
  175. package/skills/cocoar-vue-ui/references/guide/error-handling.md +162 -0
  176. package/skills/cocoar-vue-ui/references/guide/getting-started.md +119 -0
  177. package/skills/cocoar-vue-ui/references/guide/migration-page-builder-3.md +207 -0
  178. package/skills/cocoar-vue-ui/references/guide/migration.md +140 -0
  179. 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.