@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,272 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/data-grid/date-columns.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Date Columns (New in 2.0)
|
|
4
|
+
|
|
5
|
+
Three Temporal-typed column shortcuts for date / date-time / zoned-date-time cells. All three follow the same pattern: a renderer that formats locale-aware via `toLocaleString`, an editor that wraps the matching `<CoarPlainDatePicker>` / `<CoarPlainDateTimePicker>` / `<CoarZonedDateTimePicker>` component.
|
|
6
|
+
|
|
7
|
+
| | Cell value | Renderer format | Editor |
|
|
8
|
+
|--|--|--|--|
|
|
9
|
+
| **`col.plainDate()`** | `Temporal.PlainDate \| null` | `15. Mai 2026` (date-style: medium) | `CoarPlainDatePicker` |
|
|
10
|
+
| **`col.plainDateTime()`** | `Temporal.PlainDateTime \| null` | `15. Mai 2026, 14:30` (date-style: medium + time-style: short) | `CoarPlainDateTimePicker` |
|
|
11
|
+
| **`col.zonedDateTime()`** | `Temporal.ZonedDateTime \| null` | `15. Mai 2026, 14:30 GMT+2` (+ short zone-name suffix) | `CoarZonedDateTimePicker` |
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
15
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
16
|
+
|
|
17
|
+
CoarGridBuilder.create<Task>().columns([
|
|
18
|
+
(col) => col.plainDate('startsOn', d => d.highlightWeekends())
|
|
19
|
+
.editable(true),
|
|
20
|
+
|
|
21
|
+
(col) => col.plainDateTime('reminderAt')
|
|
22
|
+
.editable(true),
|
|
23
|
+
|
|
24
|
+
(col) => col.zonedDateTime('eventAt', d => d.timeZone('Europe/Vienna'))
|
|
25
|
+
.editable(true),
|
|
26
|
+
])
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> **Info: Temporal-only contract**
|
|
30
|
+
>
|
|
31
|
+
> All three column shortcuts require the cell value to be the matching `Temporal` type (or `null`). ISO strings, native `Date`, floating `Temporal.PlainDateTime` in a `zonedDateTime` column — all rejected: the renderer shows empty, the editor falls back to `null`. Convert at the data layer (typically in the row mapper that turns API responses into grid rows). This matches `@cocoar/vue-calendar`'s Temporal-only contract — when a row's date round-trips between the grid and the calendar, both sides agree on the type.
|
|
32
|
+
>
|
|
33
|
+
> The legacy `col.date(field, config?)` shortcut (display-only, accepts `Date | string`) is unchanged for back-compat with existing consumer columns.
|
|
34
|
+
|
|
35
|
+
## Edit-mode flow
|
|
36
|
+
|
|
37
|
+
| Action | Result |
|
|
38
|
+
|--------|--------|
|
|
39
|
+
| Double-click cell (or Enter / F2) | Opens the editor and focuses the picker's trigger. The picker handles its own open / navigate / select keystrokes. |
|
|
40
|
+
| Click outside / Tab / Enter (after selection) | AG Grid commits via `getValue()` — `Temporal.PlainDate` / `PlainDateTime` / `ZonedDateTime` (or `null` if cleared). |
|
|
41
|
+
| Escape | Cancels (no commit). |
|
|
42
|
+
|
|
43
|
+
Focus-preservation (capture-phase `mousedown` listener that `preventDefault`s on `.coar-overlay-host` targets) prevents AG Grid from committing prematurely while the user navigates the body-teleported picker panel.
|
|
44
|
+
|
|
45
|
+
## `col.plainDate(field, configurator?)`
|
|
46
|
+
|
|
47
|
+
**Demo — `data-grid/demos/GridPlainDate.vue`**
|
|
48
|
+
|
|
49
|
+
```vue
|
|
50
|
+
<template>
|
|
51
|
+
<div>
|
|
52
|
+
<div style="height: 320px;">
|
|
53
|
+
<CoarDataGrid :builder="builder" />
|
|
54
|
+
</div>
|
|
55
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
56
|
+
Double-click any date cell. Cell value is <code>Temporal.PlainDate</code> — the renderer formats locale-aware, the editor opens <code>CoarPlainDatePicker</code>.
|
|
57
|
+
</div>
|
|
58
|
+
<div
|
|
59
|
+
v-if="lastChange"
|
|
60
|
+
style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; background: var(--coar-surface-neutral-subtle); font-size: 13px;"
|
|
61
|
+
>
|
|
62
|
+
Last change: <strong>{{ lastChange.row }}</strong> —
|
|
63
|
+
<code>{{ lastChange.field }}</code> →
|
|
64
|
+
<strong>{{ lastChange.newValue }}</strong>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<script setup lang="ts">
|
|
70
|
+
import { ref, shallowRef } from 'vue';
|
|
71
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
72
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
73
|
+
|
|
74
|
+
interface Task {
|
|
75
|
+
id: number;
|
|
76
|
+
title: string;
|
|
77
|
+
startsOn: Temporal.PlainDate | null;
|
|
78
|
+
dueOn: Temporal.PlainDate | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const data = ref<Task[]>([
|
|
82
|
+
{ id: 1, title: 'Write spec', startsOn: Temporal.PlainDate.from('2026-05-12'), dueOn: Temporal.PlainDate.from('2026-05-15') },
|
|
83
|
+
{ id: 2, title: 'Implement', startsOn: Temporal.PlainDate.from('2026-05-16'), dueOn: Temporal.PlainDate.from('2026-05-22') },
|
|
84
|
+
{ id: 3, title: 'Review', startsOn: null, dueOn: Temporal.PlainDate.from('2026-05-25') },
|
|
85
|
+
{ id: 4, title: 'Deploy', startsOn: Temporal.PlainDate.from('2026-05-26'), dueOn: null },
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const lastChange = shallowRef<{ row: string; field: string; newValue: string } | null>(null);
|
|
89
|
+
|
|
90
|
+
const builder = CoarGridBuilder.create<Task>()
|
|
91
|
+
.columns([
|
|
92
|
+
(col) => col.field('title').header('Title').flex(1),
|
|
93
|
+
(col) =>
|
|
94
|
+
col
|
|
95
|
+
.plainDate('startsOn', (d) => d.size('s').highlightWeekends())
|
|
96
|
+
.header('Starts')
|
|
97
|
+
.width(160)
|
|
98
|
+
.editable(true),
|
|
99
|
+
(col) =>
|
|
100
|
+
col
|
|
101
|
+
.plainDate('dueOn', (d) =>
|
|
102
|
+
d.size('s').showWeekNumbers().min(Temporal.PlainDate.from('2026-01-01')),
|
|
103
|
+
)
|
|
104
|
+
.header('Due')
|
|
105
|
+
.width(160)
|
|
106
|
+
.editable(true),
|
|
107
|
+
])
|
|
108
|
+
.rowDataRef(data)
|
|
109
|
+
.stopEditingWhenCellsLoseFocus()
|
|
110
|
+
.onCellValueChanged((event) => {
|
|
111
|
+
if (!event.data || !event.colDef.field) return;
|
|
112
|
+
const v = event.newValue as Temporal.PlainDate | null;
|
|
113
|
+
lastChange.value = {
|
|
114
|
+
row: event.data.title,
|
|
115
|
+
field: event.colDef.field,
|
|
116
|
+
newValue: v?.toString() ?? '∅',
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
</script>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
| Configurator method | Type | Description |
|
|
123
|
+
|---|---|---|
|
|
124
|
+
| `.size(value)` | `'xs' \| 's' \| 'm' \| 'l'` | Trigger size (default: `'s'`) |
|
|
125
|
+
| `.clearable(value?)` | `boolean = true` | Show a clear button inside the picker (default: `true`) |
|
|
126
|
+
| `.min(value)` | `Temporal.PlainDate \| null` | Minimum selectable date |
|
|
127
|
+
| `.max(value)` | `Temporal.PlainDate \| null` | Maximum selectable date |
|
|
128
|
+
| `.showWeekNumbers(value?)` | `boolean = true` | Show ISO week numbers in the calendar panel |
|
|
129
|
+
| `.highlightWeekends(value?)` | `boolean = true` | Visually highlight Saturday + Sunday |
|
|
130
|
+
| `.markers(value)` | `CoarDateMarker[] \| (row) => CoarDateMarker[]` | Date markers (dot / ring / underline) |
|
|
131
|
+
| `.locale(value)` | `string` | Locale override (defaults to consumer-app locale via `useL10n()`) |
|
|
132
|
+
|
|
133
|
+
## `col.plainDateTime(field, configurator?)`
|
|
134
|
+
|
|
135
|
+
**Demo — `data-grid/demos/GridPlainDateTime.vue`**
|
|
136
|
+
|
|
137
|
+
```vue
|
|
138
|
+
<template>
|
|
139
|
+
<div>
|
|
140
|
+
<div style="height: 280px;">
|
|
141
|
+
<CoarDataGrid :builder="builder" />
|
|
142
|
+
</div>
|
|
143
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
144
|
+
Double-click any cell. Cell value is <code>Temporal.PlainDateTime</code> — a floating wallclock (no zone).
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</template>
|
|
148
|
+
|
|
149
|
+
<script setup lang="ts">
|
|
150
|
+
import { ref } from 'vue';
|
|
151
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
152
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
153
|
+
|
|
154
|
+
interface Reminder {
|
|
155
|
+
id: number;
|
|
156
|
+
title: string;
|
|
157
|
+
at: Temporal.PlainDateTime | null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const data = ref<Reminder[]>([
|
|
161
|
+
{ id: 1, title: 'Morning standup', at: Temporal.PlainDateTime.from('2026-05-13T09:00:00') },
|
|
162
|
+
{ id: 2, title: 'Code review', at: Temporal.PlainDateTime.from('2026-05-13T14:30:00') },
|
|
163
|
+
{ id: 3, title: 'No reminder yet', at: null },
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
const builder = CoarGridBuilder.create<Reminder>()
|
|
167
|
+
.columns([
|
|
168
|
+
(col) => col.field('title').header('Title').flex(1),
|
|
169
|
+
(col) =>
|
|
170
|
+
col
|
|
171
|
+
.plainDateTime('at', (d) => d.size('s'))
|
|
172
|
+
.header('When')
|
|
173
|
+
.width(220)
|
|
174
|
+
.editable(true),
|
|
175
|
+
])
|
|
176
|
+
.rowDataRef(data)
|
|
177
|
+
.stopEditingWhenCellsLoseFocus();
|
|
178
|
+
</script>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Same configurator surface as `col.plainDate()`, but `min` / `max` accept `Temporal.PlainDateTime`.
|
|
182
|
+
|
|
183
|
+
Use this when the time-of-day matters but the event has no fixed zone (calendar-local reminders, scheduled-locally tasks). For cross-zone events, use `col.zonedDateTime()`.
|
|
184
|
+
|
|
185
|
+
## `col.zonedDateTime(field, configurator?)`
|
|
186
|
+
|
|
187
|
+
**Demo — `data-grid/demos/GridZonedDateTime.vue`**
|
|
188
|
+
|
|
189
|
+
```vue
|
|
190
|
+
<template>
|
|
191
|
+
<div>
|
|
192
|
+
<div style="height: 320px;">
|
|
193
|
+
<CoarDataGrid :builder="builder" />
|
|
194
|
+
</div>
|
|
195
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
196
|
+
Double-click <code>startsAt</code>. Cell value is <code>Temporal.ZonedDateTime</code> — same instant displayed in each event's own zone. Each row's zone is preserved through editing unless the user explicitly changes it via the picker.
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
</template>
|
|
200
|
+
|
|
201
|
+
<script setup lang="ts">
|
|
202
|
+
import { ref } from 'vue';
|
|
203
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
204
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
205
|
+
|
|
206
|
+
interface Meeting {
|
|
207
|
+
id: number;
|
|
208
|
+
title: string;
|
|
209
|
+
startsAt: Temporal.ZonedDateTime | null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const data = ref<Meeting[]>([
|
|
213
|
+
{ id: 1, title: 'EU sync', startsAt: Temporal.ZonedDateTime.from('2026-05-13T10:00:00[Europe/Vienna]') },
|
|
214
|
+
{ id: 2, title: 'US sync', startsAt: Temporal.ZonedDateTime.from('2026-05-13T15:00:00[America/New_York]') },
|
|
215
|
+
{ id: 3, title: 'AP sync', startsAt: Temporal.ZonedDateTime.from('2026-05-14T09:00:00[Asia/Tokyo]') },
|
|
216
|
+
{ id: 4, title: 'No slot', startsAt: null },
|
|
217
|
+
]);
|
|
218
|
+
|
|
219
|
+
const builder = CoarGridBuilder.create<Meeting>()
|
|
220
|
+
.columns([
|
|
221
|
+
(col) => col.field('title').header('Meeting').flex(1),
|
|
222
|
+
(col) =>
|
|
223
|
+
col
|
|
224
|
+
.zonedDateTime('startsAt', (d) =>
|
|
225
|
+
d.size('s').timeZone('Europe/Vienna').timezoneFilter(['Europe/*', 'America/*', 'Asia/*']),
|
|
226
|
+
)
|
|
227
|
+
.header('Starts at')
|
|
228
|
+
.width(280)
|
|
229
|
+
.editable(true),
|
|
230
|
+
])
|
|
231
|
+
.rowDataRef(data)
|
|
232
|
+
.stopEditingWhenCellsLoseFocus();
|
|
233
|
+
</script>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
| Configurator method | Type | Description |
|
|
237
|
+
|---|---|---|
|
|
238
|
+
| `.size(value)` | `'xs' \| 's' \| 'm' \| 'l'` | Trigger size (default: `'s'`) |
|
|
239
|
+
| `.clearable(value?)` | `boolean = true` | Show a clear button inside the picker (default: `true`) |
|
|
240
|
+
| `.min(value)` | `Temporal.ZonedDateTime \| null` | Minimum selectable instant |
|
|
241
|
+
| `.max(value)` | `Temporal.ZonedDateTime \| null` | Maximum selectable instant |
|
|
242
|
+
| `.showWeekNumbers(value?)` | `boolean = true` | Show ISO week numbers |
|
|
243
|
+
| `.highlightWeekends(value?)` | `boolean = true` | Highlight Saturday + Sunday |
|
|
244
|
+
| `.markers(value)` | `CoarDateMarker[] \| (row) => CoarDateMarker[]` | Date markers |
|
|
245
|
+
| `.locale(value)` | `string` | Locale override |
|
|
246
|
+
| `.timeZone(value)` | `string` | **Default IANA zone** for newly-created values (cell was empty before the edit). Existing values keep their own zone. |
|
|
247
|
+
| `.timezoneFilter(value)` | `string[]` | Wildcard filter patterns for the zone selector (e.g. `['Europe/*', 'America/*']`) |
|
|
248
|
+
| `.displayTimeZone(value)` | `string` | **Renderer-only.** Project every row's instant into this zone for display (e.g. `'Europe/Vienna'` to render every event in Vienna time for cross-zone coordination views). When omitted, each row renders in its own value's zone. |
|
|
249
|
+
|
|
250
|
+
The renderer formats each cell in its own zone — a row whose value lives in `America/New_York` displays the New York wallclock + a `GMT-5` (or `GMT-4` in summer) suffix, regardless of the user's browser zone. Cross-zone columns stay unambiguous at a glance.
|
|
251
|
+
|
|
252
|
+
## Row-aware markers
|
|
253
|
+
|
|
254
|
+
`markers` accepts a function for per-row decorations — useful when the calendar should highlight different dates depending on the row:
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
col.plainDate('startsOn', d =>
|
|
258
|
+
d.markers(row => [
|
|
259
|
+
{ date: row.deadline, variant: 'underline', color: 'var(--coar-color-warning-bold)' },
|
|
260
|
+
])
|
|
261
|
+
).editable(true)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Layered overrides
|
|
265
|
+
|
|
266
|
+
Same escape-hatches as the other column shortcuts:
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
col.plainDate('startsOn', d => d.size('s'))
|
|
270
|
+
.editable(true)
|
|
271
|
+
.cellEditorConfig(MyCustomDateEditor, { /* ... */ })
|
|
272
|
+
```
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/data-grid/editing.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Editing
|
|
4
|
+
|
|
5
|
+
In-cell editing is exposed through three builder methods that map directly onto AG Grid's editor lifecycle:
|
|
6
|
+
|
|
7
|
+
| Method | Level | Purpose |
|
|
8
|
+
|--------|-------|---------|
|
|
9
|
+
| `column.editable(value)` | column | Enable editing — `boolean` or `(row) => boolean` predicate |
|
|
10
|
+
| `column.cellEditorConfig(component, config)` | column | Plug in a custom Vue editor component (mirrors `cellRendererConfig`) |
|
|
11
|
+
| `gridBuilder.onCellValueChanged(handler)` | grid | React to a committed cell edit |
|
|
12
|
+
|
|
13
|
+
`editable()` and `cellEditorConfig()` are **orthogonal** — set both, otherwise the editor never opens. If you only set `editable(true)`, the cell uses AG Grid's built-in text editor.
|
|
14
|
+
|
|
15
|
+
## Default Editor
|
|
16
|
+
|
|
17
|
+
`.editable(true)` enables the default text editor. Editing starts on **double-click** (or pressing Enter / F2 with a cell focused). Enter commits, Escape cancels.
|
|
18
|
+
|
|
19
|
+
A row predicate gates editing per-row — locked items in the demo below skip the editor entirely:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
(col) => col.field('name').editable(row => !row.locked)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`onCellValueChanged` fires once per committed edit and surfaces both the previous and new value. The demo updates a status line below the grid:
|
|
26
|
+
|
|
27
|
+
**Demo — `data-grid/demos/GridEditing.vue`**
|
|
28
|
+
|
|
29
|
+
```vue
|
|
30
|
+
<template>
|
|
31
|
+
<div>
|
|
32
|
+
<div style="height: 320px;">
|
|
33
|
+
<CoarDataGrid :builder="builder" />
|
|
34
|
+
</div>
|
|
35
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
36
|
+
Double-click any cell to edit. Enter commits, Escape cancels. Locked rows can't be edited.
|
|
37
|
+
</div>
|
|
38
|
+
<div
|
|
39
|
+
v-if="lastChange"
|
|
40
|
+
style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; background: var(--coar-surface-neutral-subtle); font-size: 13px;"
|
|
41
|
+
>
|
|
42
|
+
Last change: <strong>{{ lastChange.name }}</strong>'s
|
|
43
|
+
<strong>{{ lastChange.field }}</strong> —
|
|
44
|
+
<code>{{ lastChange.oldValue }}</code> → <code>{{ lastChange.newValue }}</code>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script setup lang="ts">
|
|
50
|
+
import { ref, shallowRef } from 'vue';
|
|
51
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
52
|
+
|
|
53
|
+
interface Person {
|
|
54
|
+
id: number;
|
|
55
|
+
name: string;
|
|
56
|
+
email: string;
|
|
57
|
+
amount: number;
|
|
58
|
+
locked: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const data = ref<Person[]>([
|
|
62
|
+
{ id: 1, name: 'Alice Johnson', email: 'alice@example.com', amount: 1200, locked: false },
|
|
63
|
+
{ id: 2, name: 'Bob Smith', email: 'bob@example.com', amount: 800, locked: true },
|
|
64
|
+
{ id: 3, name: 'Carol Williams', email: 'carol@example.com', amount: 1750, locked: false },
|
|
65
|
+
{ id: 4, name: 'David Brown', email: 'david@example.com', amount: 450, locked: false },
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
interface Change {
|
|
69
|
+
name: string;
|
|
70
|
+
field: string;
|
|
71
|
+
oldValue: unknown;
|
|
72
|
+
newValue: unknown;
|
|
73
|
+
}
|
|
74
|
+
const lastChange = shallowRef<Change | null>(null);
|
|
75
|
+
|
|
76
|
+
const builder = CoarGridBuilder.create<Person>()
|
|
77
|
+
.columns([
|
|
78
|
+
(col) => col.field('name').header('Name').flex(1).editable((row) => !row.locked),
|
|
79
|
+
(col) => col.field('email').header('Email').flex(1).editable((row) => !row.locked),
|
|
80
|
+
(col) => col.number('amount').header('Amount').width(120).editable((row) => !row.locked),
|
|
81
|
+
(col) => col.field('locked').header('Locked').width(100),
|
|
82
|
+
])
|
|
83
|
+
.rowDataRef(data)
|
|
84
|
+
.onCellValueChanged((event) => {
|
|
85
|
+
if (!event.data || !event.colDef.field) return;
|
|
86
|
+
lastChange.value = {
|
|
87
|
+
name: event.data.name,
|
|
88
|
+
field: event.colDef.field,
|
|
89
|
+
oldValue: event.oldValue,
|
|
90
|
+
newValue: event.newValue,
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
</script>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
CoarGridBuilder.create<Person>()
|
|
98
|
+
.columns([
|
|
99
|
+
(col) => col.field('name').editable(row => !row.locked),
|
|
100
|
+
(col) => col.number('amount').editable(row => !row.locked),
|
|
101
|
+
])
|
|
102
|
+
.rowDataRef(data)
|
|
103
|
+
.onCellValueChanged((event) => {
|
|
104
|
+
saveField(event.data, event.colDef.field, event.newValue);
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Custom Cell Editor
|
|
109
|
+
|
|
110
|
+
`cellEditorConfig(component, config)` accepts any Vue component and wraps your `config` object under `params.config` — the exact same convention as `cellRendererConfig`.
|
|
111
|
+
|
|
112
|
+
The component must follow AG Grid's [editor contract](https://www.ag-grid.com/vue-data-grid/component-cell-editor/): receive a single `params` prop and expose a `getValue()` method via `defineExpose`. Cocoar does not ship editor wrappers — building them is consumer territory, since the appropriate input control (text, select, autocomplete, date picker, custom widget) is application-specific.
|
|
113
|
+
|
|
114
|
+
**Demo — `data-grid/demos/GridEditingCustom.vue`**
|
|
115
|
+
|
|
116
|
+
```vue
|
|
117
|
+
<template>
|
|
118
|
+
<div>
|
|
119
|
+
<div style="height: 280px;">
|
|
120
|
+
<CoarDataGrid :builder="builder" />
|
|
121
|
+
</div>
|
|
122
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
123
|
+
Double-click the <strong>Role</strong> cell to open a select-based editor. Other columns use the default text editor.
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</template>
|
|
127
|
+
|
|
128
|
+
<script setup lang="ts">
|
|
129
|
+
import { ref } from 'vue';
|
|
130
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
131
|
+
import SelectCellEditor from './SelectCellEditor.vue';
|
|
132
|
+
|
|
133
|
+
interface User {
|
|
134
|
+
id: number;
|
|
135
|
+
name: string;
|
|
136
|
+
role: 'Engineer' | 'Designer' | 'Manager';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const data = ref<User[]>([
|
|
140
|
+
{ id: 1, name: 'Alice Johnson', role: 'Engineer' },
|
|
141
|
+
{ id: 2, name: 'Bob Smith', role: 'Designer' },
|
|
142
|
+
{ id: 3, name: 'Carol Williams', role: 'Manager' },
|
|
143
|
+
{ id: 4, name: 'David Brown', role: 'Engineer' },
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
const builder = CoarGridBuilder.create<User>()
|
|
147
|
+
.columns([
|
|
148
|
+
(col) => col.field('name').header('Name').flex(1).editable(true),
|
|
149
|
+
(col) =>
|
|
150
|
+
col
|
|
151
|
+
.field('role')
|
|
152
|
+
.header('Role')
|
|
153
|
+
.width(160)
|
|
154
|
+
.editable(true)
|
|
155
|
+
.cellEditorConfig(SelectCellEditor, {
|
|
156
|
+
options: ['Engineer', 'Designer', 'Manager'],
|
|
157
|
+
}),
|
|
158
|
+
])
|
|
159
|
+
.rowDataRef(data);
|
|
160
|
+
</script>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The minimal `SelectCellEditor.vue` used above:
|
|
164
|
+
|
|
165
|
+
```vue
|
|
166
|
+
<template>
|
|
167
|
+
<select ref="selectRef" v-model="value" style="width:100%;height:100%;">
|
|
168
|
+
<option v-for="opt in options" :key="opt" :value="opt">{{ opt }}</option>
|
|
169
|
+
</select>
|
|
170
|
+
</template>
|
|
171
|
+
|
|
172
|
+
<script setup lang="ts">
|
|
173
|
+
import { ref, onMounted } from 'vue';
|
|
174
|
+
import type { ICellEditorParams } from 'ag-grid-community';
|
|
175
|
+
|
|
176
|
+
const props = defineProps<{
|
|
177
|
+
params: ICellEditorParams<unknown, string> & { config: { options: string[] } };
|
|
178
|
+
}>();
|
|
179
|
+
|
|
180
|
+
const selectRef = ref<HTMLSelectElement | null>(null);
|
|
181
|
+
const value = ref(props.params.value ?? '');
|
|
182
|
+
const options = props.params.config.options;
|
|
183
|
+
|
|
184
|
+
onMounted(() => selectRef.value?.focus());
|
|
185
|
+
|
|
186
|
+
defineExpose({ getValue: () => value.value });
|
|
187
|
+
</script>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Wire it into a column:
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
(col) =>
|
|
194
|
+
col.field('role')
|
|
195
|
+
.editable(true)
|
|
196
|
+
.cellEditorConfig(SelectCellEditor, {
|
|
197
|
+
options: ['Engineer', 'Designer', 'Manager'],
|
|
198
|
+
})
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Tips
|
|
202
|
+
|
|
203
|
+
**Single-click edit.** AG Grid's default is double-click. To enter edit on a single click, pass through the native option:
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
gridBuilder.option('singleClickEdit', true);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Stop editing on focus loss.** Useful for forms where clicking outside should commit:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
gridBuilder.stopEditingWhenCellsLoseFocus();
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Full-row editing.** Edit every cell in a row at once:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
gridBuilder.fullRowEdit();
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## API
|
|
222
|
+
|
|
223
|
+
### Column-level
|
|
224
|
+
|
|
225
|
+
| Method | Parameters | Description |
|
|
226
|
+
|--------|-----------|-------------|
|
|
227
|
+
| `.editable(value)` | `boolean \| (row: T) => boolean` | Enable editing statically or via row predicate. The predicate receives row data; rows without data (group rows etc.) return `false`. |
|
|
228
|
+
| `.cellEditorConfig(component, config)` | `Component, object` | Set custom cell editor. `config` is wrapped under `cellEditorParams.config`. |
|
|
229
|
+
|
|
230
|
+
### Grid-level
|
|
231
|
+
|
|
232
|
+
| Method | Parameters | Description |
|
|
233
|
+
|--------|-----------|-------------|
|
|
234
|
+
| `.onCellValueChanged(handler)` | `(event: CellValueChangedEvent<T>) => void` | Fires once per committed cell edit. `event.oldValue`, `event.newValue`, `event.data`, `event.colDef.field`. |
|
|
235
|
+
| `.fullRowEdit(value?)` | `boolean` | Enable full-row editing mode. |
|
|
236
|
+
| `.stopEditingWhenCellsLoseFocus(value?)` | `boolean` | Commit the edit when focus leaves the cell. |
|