@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,355 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/context-menu.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Context Menu
|
|
4
|
+
|
|
5
|
+
Open a menu at the pointer position on right-click. The `useContextMenu` composable manages open/close state and cursor coordinates, while `CoarContextMenu` renders the menu as a floating overlay with automatic viewport clamping.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { useContextMenu, CoarContextMenu } from '@cocoar/vue-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
Call `useContextMenu()` to get a controller, bind `menu.open` to `@contextmenu`, and place your menu items inside `<CoarContextMenu>`. The menu closes automatically when an item is clicked, when clicking outside, pressing Escape, or scrolling.
|
|
14
|
+
|
|
15
|
+
**Demo — `context-menu/demos/ContextMenuBasic.vue`**
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<template>
|
|
19
|
+
<div>
|
|
20
|
+
<div
|
|
21
|
+
class="target-area"
|
|
22
|
+
@contextmenu="menu.open"
|
|
23
|
+
>
|
|
24
|
+
Right-click anywhere in this area
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<CoarContextMenu :menu="menu">
|
|
28
|
+
<CoarMenuItem icon="copy" label="Copy" @clicked="onAction('Copy')" />
|
|
29
|
+
<CoarMenuItem icon="clipboard" label="Paste" @clicked="onAction('Paste')" />
|
|
30
|
+
<CoarMenuDivider />
|
|
31
|
+
<CoarMenuItem icon="pencil" label="Rename" @clicked="onAction('Rename')" />
|
|
32
|
+
<CoarMenuItem icon="trash-2" label="Delete" @clicked="onAction('Delete')" />
|
|
33
|
+
</CoarContextMenu>
|
|
34
|
+
|
|
35
|
+
<p class="status">Last action: {{ lastAction || 'none' }}</p>
|
|
36
|
+
</div>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup lang="ts">
|
|
40
|
+
import { ref } from 'vue';
|
|
41
|
+
import { useContextMenu, CoarContextMenu, CoarMenuItem, CoarMenuDivider } from '@cocoar/vue-ui';
|
|
42
|
+
|
|
43
|
+
const menu = useContextMenu();
|
|
44
|
+
const lastAction = ref('');
|
|
45
|
+
|
|
46
|
+
function onAction(action: string) {
|
|
47
|
+
lastAction.value = action;
|
|
48
|
+
}
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<style scoped>
|
|
52
|
+
.target-area {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
height: 160px;
|
|
57
|
+
border: 2px dashed var(--coar-border-neutral-tertiary);
|
|
58
|
+
border-radius: var(--coar-radius-m);
|
|
59
|
+
color: var(--coar-text-neutral-secondary);
|
|
60
|
+
font-size: var(--coar-font-size-s);
|
|
61
|
+
user-select: none;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.status {
|
|
65
|
+
margin-top: 8px;
|
|
66
|
+
font-size: 13px;
|
|
67
|
+
color: var(--coar-text-neutral-secondary);
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## With Headings & Submenus
|
|
73
|
+
|
|
74
|
+
All standard menu features work inside context menus — headings, dividers, icons, and inline submenus via `CoarSubExpand`.
|
|
75
|
+
|
|
76
|
+
**Demo — `context-menu/demos/ContextMenuSubmenus.vue`**
|
|
77
|
+
|
|
78
|
+
```vue
|
|
79
|
+
<template>
|
|
80
|
+
<div>
|
|
81
|
+
<div
|
|
82
|
+
class="target-area"
|
|
83
|
+
@contextmenu="menu.open"
|
|
84
|
+
>
|
|
85
|
+
Right-click for a menu with headings and submenus
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<CoarContextMenu :menu="menu">
|
|
89
|
+
<CoarMenuHeading label="Edit" />
|
|
90
|
+
<CoarMenuItem icon="scissors" label="Cut" @clicked="onAction('Cut')" />
|
|
91
|
+
<CoarMenuItem icon="copy" label="Copy" @clicked="onAction('Copy')" />
|
|
92
|
+
<CoarMenuItem icon="clipboard" label="Paste" @clicked="onAction('Paste')" />
|
|
93
|
+
<CoarMenuDivider />
|
|
94
|
+
<CoarSubExpand label="Sort by" icon="arrow-up-down">
|
|
95
|
+
<CoarMenuItem label="Name" @clicked="onAction('Sort by Name')" />
|
|
96
|
+
<CoarMenuItem label="Date" @clicked="onAction('Sort by Date')" />
|
|
97
|
+
<CoarMenuItem label="Size" @clicked="onAction('Sort by Size')" />
|
|
98
|
+
</CoarSubExpand>
|
|
99
|
+
<CoarMenuDivider />
|
|
100
|
+
<CoarMenuItem icon="settings" label="Preferences" @clicked="onAction('Preferences')" />
|
|
101
|
+
</CoarContextMenu>
|
|
102
|
+
|
|
103
|
+
<p class="status">Last action: {{ lastAction || 'none' }}</p>
|
|
104
|
+
</div>
|
|
105
|
+
</template>
|
|
106
|
+
|
|
107
|
+
<script setup lang="ts">
|
|
108
|
+
import { ref } from 'vue';
|
|
109
|
+
import {
|
|
110
|
+
useContextMenu,
|
|
111
|
+
CoarContextMenu,
|
|
112
|
+
CoarMenuItem,
|
|
113
|
+
CoarMenuDivider,
|
|
114
|
+
CoarMenuHeading,
|
|
115
|
+
CoarSubExpand,
|
|
116
|
+
} from '@cocoar/vue-ui';
|
|
117
|
+
|
|
118
|
+
const menu = useContextMenu();
|
|
119
|
+
const lastAction = ref('');
|
|
120
|
+
|
|
121
|
+
function onAction(action: string) {
|
|
122
|
+
lastAction.value = action;
|
|
123
|
+
}
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<style scoped>
|
|
127
|
+
.target-area {
|
|
128
|
+
display: flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
justify-content: center;
|
|
131
|
+
height: 160px;
|
|
132
|
+
border: 2px dashed var(--coar-border-neutral-tertiary);
|
|
133
|
+
border-radius: var(--coar-radius-m);
|
|
134
|
+
color: var(--coar-text-neutral-secondary);
|
|
135
|
+
font-size: var(--coar-font-size-s);
|
|
136
|
+
user-select: none;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.status {
|
|
140
|
+
margin-top: 8px;
|
|
141
|
+
font-size: 13px;
|
|
142
|
+
color: var(--coar-text-neutral-secondary);
|
|
143
|
+
}
|
|
144
|
+
</style>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Flyout Submenus
|
|
148
|
+
|
|
149
|
+
Use `CoarSubFlyout` inside a context menu for nested flyout panels — useful for status changes, priority selectors, etc.
|
|
150
|
+
|
|
151
|
+
**Demo — `context-menu/demos/ContextMenuFlyout.vue`**
|
|
152
|
+
|
|
153
|
+
```vue
|
|
154
|
+
<template>
|
|
155
|
+
<div>
|
|
156
|
+
<div class="target-area" @contextmenu="menu.open">
|
|
157
|
+
Right-click for a menu with flyout submenus
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<CoarContextMenu :menu="menu">
|
|
161
|
+
<CoarMenuItem icon="pencil" label="Edit" @clicked="onAction('Edit')" />
|
|
162
|
+
<CoarMenuDivider />
|
|
163
|
+
<CoarSubFlyout label="Set Status" icon="circle-alert">
|
|
164
|
+
<CoarMenu>
|
|
165
|
+
<CoarMenuItem label="New" @clicked="onAction('Status: New')" />
|
|
166
|
+
<CoarMenuItem label="In Progress" @clicked="onAction('Status: In Progress')" />
|
|
167
|
+
<CoarMenuItem label="Done" @clicked="onAction('Status: Done')" />
|
|
168
|
+
</CoarMenu>
|
|
169
|
+
</CoarSubFlyout>
|
|
170
|
+
<CoarSubFlyout label="Priority" icon="flag">
|
|
171
|
+
<CoarMenu>
|
|
172
|
+
<CoarMenuItem label="Low" @clicked="onAction('Priority: Low')" />
|
|
173
|
+
<CoarMenuItem label="Medium" @clicked="onAction('Priority: Medium')" />
|
|
174
|
+
<CoarMenuItem label="High" @clicked="onAction('Priority: High')" />
|
|
175
|
+
</CoarMenu>
|
|
176
|
+
</CoarSubFlyout>
|
|
177
|
+
<CoarMenuDivider />
|
|
178
|
+
<CoarMenuItem icon="trash-2" label="Delete" @clicked="onAction('Delete')" />
|
|
179
|
+
</CoarContextMenu>
|
|
180
|
+
|
|
181
|
+
<p class="status">Last action: {{ lastAction || 'none' }}</p>
|
|
182
|
+
</div>
|
|
183
|
+
</template>
|
|
184
|
+
|
|
185
|
+
<script setup lang="ts">
|
|
186
|
+
import { ref } from 'vue';
|
|
187
|
+
import {
|
|
188
|
+
useContextMenu,
|
|
189
|
+
CoarContextMenu,
|
|
190
|
+
CoarMenu,
|
|
191
|
+
CoarMenuItem,
|
|
192
|
+
CoarMenuDivider,
|
|
193
|
+
CoarSubFlyout,
|
|
194
|
+
} from '@cocoar/vue-ui';
|
|
195
|
+
|
|
196
|
+
const menu = useContextMenu();
|
|
197
|
+
const lastAction = ref('');
|
|
198
|
+
|
|
199
|
+
function onAction(action: string) {
|
|
200
|
+
lastAction.value = action;
|
|
201
|
+
}
|
|
202
|
+
</script>
|
|
203
|
+
|
|
204
|
+
<style scoped>
|
|
205
|
+
.target-area {
|
|
206
|
+
display: flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
justify-content: center;
|
|
209
|
+
height: 160px;
|
|
210
|
+
border: 2px dashed var(--coar-border-neutral-tertiary);
|
|
211
|
+
border-radius: var(--coar-radius-m);
|
|
212
|
+
color: var(--coar-text-neutral-secondary);
|
|
213
|
+
font-size: var(--coar-font-size-s);
|
|
214
|
+
user-select: none;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.status {
|
|
218
|
+
margin-top: 8px;
|
|
219
|
+
font-size: 13px;
|
|
220
|
+
color: var(--coar-text-neutral-secondary);
|
|
221
|
+
}
|
|
222
|
+
</style>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Data Grid Integration
|
|
226
|
+
|
|
227
|
+
Use separate `useContextMenu()` instances for cell and viewport right-clicks. The data grid builder provides `onCellContextMenu` and `onViewportContextMenu` handlers that give you the mouse event to pass into `menu.open()`.
|
|
228
|
+
|
|
229
|
+
**Demo — `context-menu/demos/ContextMenuDataGrid.vue`**
|
|
230
|
+
|
|
231
|
+
```vue
|
|
232
|
+
<template>
|
|
233
|
+
<div>
|
|
234
|
+
<div style="height: 300px;">
|
|
235
|
+
<CoarDataGrid :builder="builder" />
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<!-- Cell context menu (right-click on a row) -->
|
|
239
|
+
<CoarContextMenu :menu="cellMenu">
|
|
240
|
+
<CoarMenuItem icon="pencil" label="Edit" @clicked="onCellAction('Edit', selectedUser)" />
|
|
241
|
+
<CoarMenuItem icon="copy" label="Duplicate" @clicked="onCellAction('Duplicate', selectedUser)" />
|
|
242
|
+
<CoarMenuDivider />
|
|
243
|
+
<CoarMenuItem icon="trash-2" label="Delete" @clicked="onCellAction('Delete', selectedUser)" />
|
|
244
|
+
</CoarContextMenu>
|
|
245
|
+
|
|
246
|
+
<!-- Viewport context menu (right-click on empty area) -->
|
|
247
|
+
<CoarContextMenu :menu="viewportMenu">
|
|
248
|
+
<CoarMenuItem icon="plus" label="Add user" @clicked="onViewportAction('Add user')" />
|
|
249
|
+
<CoarMenuItem icon="refresh-cw" label="Refresh" @clicked="onViewportAction('Refresh')" />
|
|
250
|
+
</CoarContextMenu>
|
|
251
|
+
|
|
252
|
+
<p class="status">Last action: {{ lastAction || 'none' }}</p>
|
|
253
|
+
</div>
|
|
254
|
+
</template>
|
|
255
|
+
|
|
256
|
+
<script setup lang="ts">
|
|
257
|
+
import { ref } from 'vue';
|
|
258
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
259
|
+
import type { CellContextMenuEvent } from '@cocoar/vue-data-grid';
|
|
260
|
+
import { useContextMenu, CoarContextMenu, CoarMenuItem, CoarMenuDivider } from '@cocoar/vue-ui';
|
|
261
|
+
|
|
262
|
+
interface User {
|
|
263
|
+
name: string;
|
|
264
|
+
email: string;
|
|
265
|
+
role: string;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const data: User[] = [
|
|
269
|
+
{ name: 'Alice Johnson', email: 'alice@example.com', role: 'Engineer' },
|
|
270
|
+
{ name: 'Bob Smith', email: 'bob@example.com', role: 'Designer' },
|
|
271
|
+
{ name: 'Carol Williams', email: 'carol@example.com', role: 'Manager' },
|
|
272
|
+
{ name: 'David Brown', email: 'david@example.com', role: 'Engineer' },
|
|
273
|
+
{ name: 'Eve Davis', email: 'eve@example.com', role: 'Designer' },
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
const cellMenu = useContextMenu();
|
|
277
|
+
const viewportMenu = useContextMenu();
|
|
278
|
+
const selectedUser = ref<User | null>(null);
|
|
279
|
+
const lastAction = ref('');
|
|
280
|
+
|
|
281
|
+
const builder = CoarGridBuilder.create<User>()
|
|
282
|
+
.columns([
|
|
283
|
+
(col) => col.field('name').header('Name').flex(1),
|
|
284
|
+
(col) => col.field('email').header('Email').flex(1),
|
|
285
|
+
(col) => col.field('role').header('Role').width(120),
|
|
286
|
+
])
|
|
287
|
+
.rowData(data)
|
|
288
|
+
.onCellContextMenu((event: CellContextMenuEvent<User>) => {
|
|
289
|
+
selectedUser.value = event.data ?? null;
|
|
290
|
+
if (event.event) {
|
|
291
|
+
cellMenu.open(event.event as MouseEvent);
|
|
292
|
+
}
|
|
293
|
+
})
|
|
294
|
+
.onViewportContextMenu((event: MouseEvent) => {
|
|
295
|
+
viewportMenu.open(event);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
function onCellAction(action: string, user: User | null) {
|
|
299
|
+
lastAction.value = `${action}: ${user?.name ?? 'unknown'}`;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function onViewportAction(action: string) {
|
|
303
|
+
lastAction.value = action;
|
|
304
|
+
}
|
|
305
|
+
</script>
|
|
306
|
+
|
|
307
|
+
<style scoped>
|
|
308
|
+
.status {
|
|
309
|
+
margin-top: 8px;
|
|
310
|
+
font-size: 13px;
|
|
311
|
+
color: var(--coar-text-neutral-secondary);
|
|
312
|
+
}
|
|
313
|
+
</style>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Keeping the Menu Open
|
|
317
|
+
|
|
318
|
+
By default, clicking a `CoarMenuItem` closes the entire context menu. Call `keepMenuOpen()` on the click event to prevent this — useful for toggles or multi-select actions.
|
|
319
|
+
|
|
320
|
+
```vue
|
|
321
|
+
<CoarMenuItem
|
|
322
|
+
label="Toggle dark mode"
|
|
323
|
+
icon="moon"
|
|
324
|
+
@clicked="(e) => { e.keepMenuOpen(); toggleDarkMode(); }"
|
|
325
|
+
/>
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## API
|
|
329
|
+
|
|
330
|
+
### `useContextMenu()`
|
|
331
|
+
|
|
332
|
+
Returns a `ContextMenuContext` object:
|
|
333
|
+
|
|
334
|
+
| Property | Type | Description |
|
|
335
|
+
|------------|-------------------------------|------------------------------------------------|
|
|
336
|
+
| `isOpen` | `Readonly<Ref<boolean>>` | Whether the menu is currently visible |
|
|
337
|
+
| `position` | `Readonly<Ref<{x, y}>>` | Cursor position where the menu was opened |
|
|
338
|
+
| `open` | `(event: MouseEvent) => void` | Open at the event's cursor position |
|
|
339
|
+
| `close` | `() => void` | Close the menu |
|
|
340
|
+
|
|
341
|
+
### `<CoarContextMenu>`
|
|
342
|
+
|
|
343
|
+
| Prop | Type | Required | Description |
|
|
344
|
+
|--------|----------------------|----------|------------------------------------------|
|
|
345
|
+
| `menu` | `ContextMenuContext` | Yes | Controller returned by `useContextMenu()` |
|
|
346
|
+
|
|
347
|
+
**Slot:** `default` — menu items (`CoarMenuItem`, `CoarMenuDivider`, `CoarMenuHeading`, `CoarSubExpand`, etc.)
|
|
348
|
+
|
|
349
|
+
### Behavior
|
|
350
|
+
|
|
351
|
+
- **Viewport clamping** — the menu repositions to stay within the window
|
|
352
|
+
- **Click outside** — closes the menu
|
|
353
|
+
- **Escape** — closes the menu
|
|
354
|
+
- **Scroll** — closes the menu
|
|
355
|
+
- **Auto-close on item click** — unless `keepMenuOpen()` is called
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/data-grid/checkbox.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Checkbox Column
|
|
4
|
+
|
|
5
|
+
`col.checkbox(field, configurator?)` renders a `<CoarCheckbox>` in each cell — same visual language as forms, just sized to fit the row. The renderer is **always read-only**; interactivity comes from edit-mode, exactly like text/number/select columns.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
9
|
+
|
|
10
|
+
CoarGridBuilder.create<Task>().columns([
|
|
11
|
+
(col) => col.checkbox('done').editable(true),
|
|
12
|
+
(col) => col.field('title').flex(1),
|
|
13
|
+
])
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Edit-mode flow
|
|
17
|
+
|
|
18
|
+
Without `.editable()` the checkbox is a read-only indicator. Adding `.editable(true)` (or a row-predicate) opts the column into AG Grid's standard edit-mode flow:
|
|
19
|
+
|
|
20
|
+
| Action | Result |
|
|
21
|
+
|--------|--------|
|
|
22
|
+
| Double-click cell (or Enter / F2) | Opens `CoarCheckboxCellEditor` — interactive `<CoarCheckbox>` with focus on the input |
|
|
23
|
+
| Space | Toggles the checkbox |
|
|
24
|
+
| Tab | Commits + moves focus to the next editable cell, **opening its editor automatically** |
|
|
25
|
+
| Enter | Commits + stays |
|
|
26
|
+
| Escape | Cancels |
|
|
27
|
+
|
|
28
|
+
The Tab-through-edit-mode pattern is AG Grid's native data-entry workflow — keyboard users can fly through editable cells without ever touching the mouse. Pair with `gridBuilder.stopEditingWhenCellsLoseFocus()` so clicking outside also commits.
|
|
29
|
+
|
|
30
|
+
Toggles fire `cellValueChanged` like any other editor commit, so a single `gridBuilder.onCellValueChanged()` handler covers all column types — checkbox, text, number, custom editors.
|
|
31
|
+
|
|
32
|
+
## Editable + per-row gating
|
|
33
|
+
|
|
34
|
+
Pass a row-predicate to `.editable()` to disable the editor for individual rows. Locked rows render a read-only checkbox and can't be entered.
|
|
35
|
+
|
|
36
|
+
**Demo — `data-grid/demos/GridCheckbox.vue`**
|
|
37
|
+
|
|
38
|
+
```vue
|
|
39
|
+
<template>
|
|
40
|
+
<div>
|
|
41
|
+
<div style="height: 320px;">
|
|
42
|
+
<CoarDataGrid :builder="builder" />
|
|
43
|
+
</div>
|
|
44
|
+
<div style="margin-top: 12px; font-size: 13px; color: var(--coar-text-neutral-secondary);">
|
|
45
|
+
Double-click any "done" cell to enter edit mode. <strong>Space</strong> toggles, <strong>Tab</strong> commits and moves to the next editable cell, <strong>Escape</strong> cancels. Locked rows can't be entered.
|
|
46
|
+
</div>
|
|
47
|
+
<div
|
|
48
|
+
v-if="lastChange"
|
|
49
|
+
style="margin-top: 8px; padding: 8px 12px; border-radius: 6px; background: var(--coar-surface-neutral-subtle); font-size: 13px;"
|
|
50
|
+
>
|
|
51
|
+
Last change: <strong>{{ lastChange.task }}</strong> —
|
|
52
|
+
<code>done</code> →
|
|
53
|
+
<strong>{{ lastChange.value ? 'true' : 'false' }}</strong>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<script setup lang="ts">
|
|
59
|
+
import { ref, shallowRef } from 'vue';
|
|
60
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
61
|
+
|
|
62
|
+
interface Task {
|
|
63
|
+
id: number;
|
|
64
|
+
task: string;
|
|
65
|
+
done: boolean;
|
|
66
|
+
locked: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const data = ref<Task[]>([
|
|
70
|
+
{ id: 1, task: 'Write specification', done: true, locked: false },
|
|
71
|
+
{ id: 2, task: 'Implement renderer', done: false, locked: false },
|
|
72
|
+
{ id: 3, task: 'Ship to production', done: false, locked: true },
|
|
73
|
+
{ id: 4, task: 'Update changelog', done: true, locked: false },
|
|
74
|
+
{ id: 5, task: 'Archive (legacy)', done: true, locked: true },
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
const lastChange = shallowRef<{ task: string; value: boolean } | null>(null);
|
|
78
|
+
|
|
79
|
+
const builder = CoarGridBuilder.create<Task>()
|
|
80
|
+
.columns([
|
|
81
|
+
(col) => col.checkbox('done').width(70).editable((row) => !row.locked),
|
|
82
|
+
(col) => col.field('task').header('Task').flex(1),
|
|
83
|
+
(col) => col.checkbox('locked').width(90),
|
|
84
|
+
])
|
|
85
|
+
.rowDataRef(data)
|
|
86
|
+
.stopEditingWhenCellsLoseFocus()
|
|
87
|
+
.onCellValueChanged((event) => {
|
|
88
|
+
if (event.colDef.field !== 'done' || !event.data) return;
|
|
89
|
+
lastChange.value = { task: event.data.task, value: event.newValue };
|
|
90
|
+
});
|
|
91
|
+
</script>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
CoarGridBuilder.create<Task>().columns([
|
|
96
|
+
(col) => col.checkbox('done').editable(row => !row.locked),
|
|
97
|
+
(col) => col.field('task').flex(1),
|
|
98
|
+
(col) => col.checkbox('locked'), // read-only indicator
|
|
99
|
+
])
|
|
100
|
+
.stopEditingWhenCellsLoseFocus()
|
|
101
|
+
.onCellValueChanged((event) => {
|
|
102
|
+
if (event.colDef.field === 'done') save(event.data);
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## States — read-only, editable, indeterminate
|
|
107
|
+
|
|
108
|
+
Three independent states, all using the same `col.checkbox()` shortcut:
|
|
109
|
+
|
|
110
|
+
- **Read-only:** omit `.editable()` — checkbox is rendered, edit-mode never opens.
|
|
111
|
+
- **Editable:** add `.editable(true)` or `.editable(row => …)`.
|
|
112
|
+
- **Indeterminate (tri-state):** pass `c.indeterminate(row => …)` in the configurator. Useful for "partial" or "in-progress" states where the row's value isn't a clean true/false. The indeterminate state is shown in both renderer and editor.
|
|
113
|
+
|
|
114
|
+
**Demo — `data-grid/demos/GridCheckboxStates.vue`**
|
|
115
|
+
|
|
116
|
+
```vue
|
|
117
|
+
<template>
|
|
118
|
+
<div style="height: 320px;">
|
|
119
|
+
<CoarDataGrid :builder="builder" />
|
|
120
|
+
</div>
|
|
121
|
+
</template>
|
|
122
|
+
|
|
123
|
+
<script setup lang="ts">
|
|
124
|
+
import { ref } from 'vue';
|
|
125
|
+
import { CoarDataGrid, CoarGridBuilder } from '@cocoar/vue-data-grid';
|
|
126
|
+
|
|
127
|
+
interface Feature {
|
|
128
|
+
id: number;
|
|
129
|
+
name: string;
|
|
130
|
+
enabled: boolean;
|
|
131
|
+
rolloutComplete: boolean;
|
|
132
|
+
partial: boolean;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const data = ref<Feature[]>([
|
|
136
|
+
{ id: 1, name: 'Dark mode', enabled: true, rolloutComplete: true, partial: false },
|
|
137
|
+
{ id: 2, name: 'Calendar view', enabled: true, rolloutComplete: false, partial: true },
|
|
138
|
+
{ id: 3, name: 'Bulk export', enabled: false, rolloutComplete: false, partial: false },
|
|
139
|
+
{ id: 4, name: 'Beta dashboard', enabled: true, rolloutComplete: false, partial: true },
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
const builder = CoarGridBuilder.create<Feature>()
|
|
143
|
+
.columns([
|
|
144
|
+
(col) => col.field('name').header('Feature').flex(1),
|
|
145
|
+
// editable, no label
|
|
146
|
+
(col) =>
|
|
147
|
+
col
|
|
148
|
+
.checkbox('enabled')
|
|
149
|
+
.header('Enabled')
|
|
150
|
+
.width(110)
|
|
151
|
+
.editable(true),
|
|
152
|
+
// editable + tri-state indeterminate when partial rollout
|
|
153
|
+
(col) =>
|
|
154
|
+
col
|
|
155
|
+
.checkbox('rolloutComplete', (c) => c.indeterminate((row) => row.partial && !row.rolloutComplete))
|
|
156
|
+
.header('Rollout')
|
|
157
|
+
.width(110)
|
|
158
|
+
.editable(true),
|
|
159
|
+
// read-only indicator (no .editable())
|
|
160
|
+
(col) =>
|
|
161
|
+
col
|
|
162
|
+
.checkbox('partial')
|
|
163
|
+
.header('Partial')
|
|
164
|
+
.width(110),
|
|
165
|
+
])
|
|
166
|
+
.rowDataRef(data)
|
|
167
|
+
.stopEditingWhenCellsLoseFocus();
|
|
168
|
+
</script>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
col.checkbox('rolloutComplete', c => c
|
|
173
|
+
.indeterminate(row => row.partial && !row.rolloutComplete)
|
|
174
|
+
).editable(true)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Layered overrides
|
|
178
|
+
|
|
179
|
+
The shortcut bundles renderer + editor with the configurator's options. Subsequent calls on the chain override (last-write-wins):
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
// Replace the renderer entirely (drops the configurator)
|
|
183
|
+
col.checkbox('done').cellRenderer(MyOwnCheckbox)
|
|
184
|
+
|
|
185
|
+
// Replace just the editor (e.g. a select-style "yes/no/maybe" widget)
|
|
186
|
+
col.checkbox('done').editable(true).cellEditorConfig(MyTriStateEditor, { ... })
|
|
187
|
+
|
|
188
|
+
// Keep the bundled renderer + editor, override editable
|
|
189
|
+
col.checkbox('done').editable(false)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## API
|
|
193
|
+
|
|
194
|
+
### `col.checkbox(field, configurator?)`
|
|
195
|
+
|
|
196
|
+
| Configurator method | Type | Description |
|
|
197
|
+
|--------|------|-------------|
|
|
198
|
+
| `.label(value)` | `string \| (row) => string` | Optional label rendered next to the checkbox (in both renderer and editor) |
|
|
199
|
+
| `.indeterminate(predicate)` | `(row) => boolean` | Tri-state indicator per row |
|
|
200
|
+
| `.size(value)` | `'xs' \| 's' \| 'm' \| 'l'` | Checkbox size (default: `'s'`) |
|
|
201
|
+
|
|
202
|
+
The configurator config is passed identically to both `CoarCheckboxCellRenderer` and `CoarCheckboxCellEditor`, so display and edit look the same — only behavior changes.
|
|
203
|
+
|
|
204
|
+
Interactive state comes from the outer chain:
|
|
205
|
+
|
|
206
|
+
| Outer chain | Result |
|
|
207
|
+
|-------------|--------|
|
|
208
|
+
| no `.editable()` | Read-only — edit-mode never opens |
|
|
209
|
+
| `.editable(true)` | Edit-mode opens on double-click / Enter / F2 |
|
|
210
|
+
| `.editable(false)` | Read-only |
|
|
211
|
+
| `.editable(row => …)` | Per-row predicate — edit-mode opens only when `true` |
|
|
212
|
+
|
|
213
|
+
Commit behavior: the editor exposes `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 the editor also commits.
|