@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,382 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/tabs.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Tabs
|
|
4
|
+
|
|
5
|
+
Organize related content into separate panels that users switch between without leaving the page. Tabs are ideal for settings screens, detail views, and any layout where showing everything at once would feel overwhelming. The active tab is controlled via `v-model`, so you can read or set it programmatically.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Tabs
|
|
12
|
+
|
|
13
|
+
Define your tabs inside a `CoarTabGroup` and render the matching panel content with `v-if` on the active tab ID. Users can click tabs or use the keyboard to switch between them.
|
|
14
|
+
|
|
15
|
+
**Demo — `tabs/demos/TabsBasic.vue`**
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<template>
|
|
19
|
+
<div>
|
|
20
|
+
<CoarTabGroup v-model="activeTab">
|
|
21
|
+
<CoarTab id="overview">Overview</CoarTab>
|
|
22
|
+
<CoarTab id="features">Features</CoarTab>
|
|
23
|
+
<CoarTab id="api">API</CoarTab>
|
|
24
|
+
<CoarTab id="examples">Examples</CoarTab>
|
|
25
|
+
</CoarTabGroup>
|
|
26
|
+
<div style="padding: 16px; border: 1px solid var(--coar-border-neutral-secondary); border-top: none; border-radius: 0 0 8px 8px; min-height: 100px;">
|
|
27
|
+
<div v-if="activeTab === 'overview'">
|
|
28
|
+
<h4 style="margin: 0 0 8px;">Overview</h4>
|
|
29
|
+
<p style="font-size: 13px;">This is the overview content. It provides a high-level introduction to the component.</p>
|
|
30
|
+
</div>
|
|
31
|
+
<div v-else-if="activeTab === 'features'">
|
|
32
|
+
<h4 style="margin: 0 0 8px;">Features</h4>
|
|
33
|
+
<ul style="padding-left: 16px; display: flex; flex-direction: column; gap: 4px; font-size: 13px;">
|
|
34
|
+
<li>Keyboard navigation (Arrow keys, Home, End)</li>
|
|
35
|
+
<li>ARIA tab panel pattern</li>
|
|
36
|
+
<li>Controlled and uncontrolled modes</li>
|
|
37
|
+
<li>Custom content in each panel</li>
|
|
38
|
+
</ul>
|
|
39
|
+
</div>
|
|
40
|
+
<div v-else-if="activeTab === 'api'">
|
|
41
|
+
<h4 style="margin: 0 0 8px;">API</h4>
|
|
42
|
+
<p style="font-size: 13px;">Use <code>v-model</code> on <code>CoarTabGroup</code> to control the active tab programmatically.</p>
|
|
43
|
+
</div>
|
|
44
|
+
<div v-else-if="activeTab === 'examples'">
|
|
45
|
+
<h4 style="margin: 0 0 8px;">Examples</h4>
|
|
46
|
+
<p style="font-size: 13px;">See the demos below for more usage patterns.</p>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script setup lang="ts">
|
|
53
|
+
import { ref } from 'vue';
|
|
54
|
+
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';
|
|
55
|
+
|
|
56
|
+
const activeTab = ref('overview');
|
|
57
|
+
</script>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Settings Pattern
|
|
61
|
+
|
|
62
|
+
Tabs shine in settings pages where each category has its own form section. This pattern keeps the page compact and scannable while giving each section room to breathe.
|
|
63
|
+
|
|
64
|
+
**Demo — `tabs/demos/TabsSettings.vue`**
|
|
65
|
+
|
|
66
|
+
```vue
|
|
67
|
+
<template>
|
|
68
|
+
<div>
|
|
69
|
+
<CoarTabGroup v-model="settingsTab">
|
|
70
|
+
<CoarTab id="general">General</CoarTab>
|
|
71
|
+
<CoarTab id="security">Security</CoarTab>
|
|
72
|
+
<CoarTab id="notifications">Notifications</CoarTab>
|
|
73
|
+
<CoarTab id="billing">Billing</CoarTab>
|
|
74
|
+
</CoarTabGroup>
|
|
75
|
+
<div style="padding: 16px; border: 1px solid var(--coar-border-neutral-secondary); border-top: none; border-radius: 0 0 8px 8px; min-height: 100px;">
|
|
76
|
+
<div v-if="settingsTab === 'general'">
|
|
77
|
+
<h4 style="margin: 0 0 8px;">General Settings</h4>
|
|
78
|
+
<div style="display: flex; flex-direction: column; gap: 8px;">
|
|
79
|
+
<div style="display: flex; align-items: center; justify-content: space-between; gap: 16px;">
|
|
80
|
+
<span style="font-size: 13px;">Display name</span>
|
|
81
|
+
<input type="text" value="John Doe" style="padding: 4px 8px; border: 1px solid var(--coar-border-neutral-secondary); border-radius: 6px; background: var(--coar-background-neutral-primary); color: var(--coar-text-neutral-primary); font-size: 13px; min-width: 160px;" />
|
|
82
|
+
</div>
|
|
83
|
+
<div style="display: flex; align-items: center; justify-content: space-between; gap: 16px;">
|
|
84
|
+
<span style="font-size: 13px;">Email</span>
|
|
85
|
+
<input type="email" value="john@example.com" style="padding: 4px 8px; border: 1px solid var(--coar-border-neutral-secondary); border-radius: 6px; background: var(--coar-background-neutral-primary); color: var(--coar-text-neutral-primary); font-size: 13px; min-width: 160px;" />
|
|
86
|
+
</div>
|
|
87
|
+
<div style="display: flex; align-items: center; justify-content: space-between; gap: 16px;">
|
|
88
|
+
<span style="font-size: 13px;">Language</span>
|
|
89
|
+
<select style="padding: 4px 8px; border: 1px solid var(--coar-border-neutral-secondary); border-radius: 6px; background: var(--coar-background-neutral-primary); color: var(--coar-text-neutral-primary); font-size: 13px; min-width: 160px;">
|
|
90
|
+
<option>English</option>
|
|
91
|
+
<option>German</option>
|
|
92
|
+
</select>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
<div v-else-if="settingsTab === 'security'">
|
|
97
|
+
<h4 style="margin: 0 0 8px;">Security Settings</h4>
|
|
98
|
+
<p style="font-size: 13px; color: var(--coar-text-neutral-secondary);">Manage your password and two-factor authentication settings.</p>
|
|
99
|
+
</div>
|
|
100
|
+
<div v-else-if="settingsTab === 'notifications'">
|
|
101
|
+
<h4 style="margin: 0 0 8px;">Notification Preferences</h4>
|
|
102
|
+
<p style="font-size: 13px; color: var(--coar-text-neutral-secondary);">Choose how you want to be notified about account activity.</p>
|
|
103
|
+
</div>
|
|
104
|
+
<div v-else-if="settingsTab === 'billing'">
|
|
105
|
+
<h4 style="margin: 0 0 8px;">Billing & Plans</h4>
|
|
106
|
+
<p style="font-size: 13px; color: var(--coar-text-neutral-secondary);">Manage your subscription and payment methods.</p>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</template>
|
|
111
|
+
|
|
112
|
+
<script setup lang="ts">
|
|
113
|
+
import { ref } from 'vue';
|
|
114
|
+
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';
|
|
115
|
+
|
|
116
|
+
const settingsTab = ref('general');
|
|
117
|
+
</script>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Disabled Tabs
|
|
121
|
+
|
|
122
|
+
Disable individual tabs to prevent access to sections that are not yet available, require a higher permission level, or depend on completing a previous step first.
|
|
123
|
+
|
|
124
|
+
**Demo — `tabs/demos/TabsDisabled.vue`**
|
|
125
|
+
|
|
126
|
+
```vue
|
|
127
|
+
<template>
|
|
128
|
+
<CoarTabGroup>
|
|
129
|
+
<CoarTab id="active1">Active</CoarTab>
|
|
130
|
+
<CoarTab id="disabled1" :disabled="true">Disabled</CoarTab>
|
|
131
|
+
<CoarTab id="active2">Active</CoarTab>
|
|
132
|
+
<CoarTab id="disabled2" :disabled="true">Disabled</CoarTab>
|
|
133
|
+
</CoarTabGroup>
|
|
134
|
+
</template>
|
|
135
|
+
|
|
136
|
+
<script setup lang="ts">
|
|
137
|
+
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';
|
|
138
|
+
</script>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Actions in the Tab Bar
|
|
142
|
+
|
|
143
|
+
Use the `#actions` slot to put right-aligned controls on the same row as the tab labels — typical uses include undo/redo buttons, a refresh icon, filter toggles, or an overflow menu. The slot stays out of the way when unused: consumers that never populate it get the exact same layout as before.
|
|
144
|
+
|
|
145
|
+
**Demo — `tabs/demos/TabsWithActions.vue`**
|
|
146
|
+
|
|
147
|
+
```vue
|
|
148
|
+
<template>
|
|
149
|
+
<div>
|
|
150
|
+
<CoarTabGroup v-model="activeTab">
|
|
151
|
+
<CoarTab id="daily">Daily</CoarTab>
|
|
152
|
+
<CoarTab id="weekly">Weekly</CoarTab>
|
|
153
|
+
<CoarTab id="monthly">Monthly</CoarTab>
|
|
154
|
+
|
|
155
|
+
<template #actions>
|
|
156
|
+
<button type="button" class="demo-action" title="Refresh" @click="refresh">
|
|
157
|
+
<CoarIcon name="refresh-cw" size="s" />
|
|
158
|
+
</button>
|
|
159
|
+
<button type="button" class="demo-action" title="Export" @click="lastAction = 'Export clicked'">
|
|
160
|
+
<CoarIcon name="download" size="s" />
|
|
161
|
+
</button>
|
|
162
|
+
</template>
|
|
163
|
+
</CoarTabGroup>
|
|
164
|
+
<div class="demo-panel">
|
|
165
|
+
<p style="font-size: 13px; margin: 0 0 8px;">
|
|
166
|
+
Viewing <strong>{{ activeTab }}</strong> report.
|
|
167
|
+
</p>
|
|
168
|
+
<p style="font-size: 12px; color: var(--coar-text-neutral-secondary); margin: 0;">
|
|
169
|
+
Last action: {{ lastAction }}
|
|
170
|
+
</p>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<script setup lang="ts">
|
|
176
|
+
import { ref } from 'vue';
|
|
177
|
+
import { CoarTabGroup, CoarTab, CoarIcon } from '@cocoar/vue-ui';
|
|
178
|
+
|
|
179
|
+
const activeTab = ref('daily');
|
|
180
|
+
const lastAction = ref('(none)');
|
|
181
|
+
|
|
182
|
+
function refresh() {
|
|
183
|
+
lastAction.value = `Refreshed ${activeTab.value} at ${new Date().toLocaleTimeString()}`;
|
|
184
|
+
}
|
|
185
|
+
</script>
|
|
186
|
+
|
|
187
|
+
<style scoped>
|
|
188
|
+
.demo-action {
|
|
189
|
+
display: inline-flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
justify-content: center;
|
|
192
|
+
width: 26px;
|
|
193
|
+
height: 26px;
|
|
194
|
+
padding: 0;
|
|
195
|
+
border: 1px solid transparent;
|
|
196
|
+
background: transparent;
|
|
197
|
+
color: var(--coar-icon-neutral-secondary);
|
|
198
|
+
cursor: pointer;
|
|
199
|
+
border-radius: 4px;
|
|
200
|
+
transition: background-color 0.12s, border-color 0.12s, color 0.12s;
|
|
201
|
+
}
|
|
202
|
+
.demo-action:hover {
|
|
203
|
+
background: var(--coar-surface-neutral-subtle);
|
|
204
|
+
border-color: var(--coar-border-neutral);
|
|
205
|
+
color: var(--coar-icon-neutral-primary);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.demo-panel {
|
|
209
|
+
padding: 16px;
|
|
210
|
+
border: 1px solid var(--coar-border-neutral-secondary);
|
|
211
|
+
border-top: none;
|
|
212
|
+
border-radius: 0 0 8px 8px;
|
|
213
|
+
min-height: 60px;
|
|
214
|
+
}
|
|
215
|
+
</style>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Fill-Height Tabs
|
|
219
|
+
|
|
220
|
+
By default `CoarTabGroup` is content-sized — the panel grows to fit whatever you put inside it. Settings panes, form sections, anything documentation-shaped wants that. For **editor / viewer / file-explorer** tabs, where the content is expected to stretch (Monaco, PDF viewer, anything VSCode-shaped), opt in with the `fill` prop.
|
|
221
|
+
|
|
222
|
+
**Demo — `tabs/demos/TabsFill.vue`**
|
|
223
|
+
|
|
224
|
+
```vue
|
|
225
|
+
<template>
|
|
226
|
+
<!-- 320 px frame so the fill effect is visible. In a real app this is your
|
|
227
|
+
grid row / flex column / view-router outlet — the tab-group fills
|
|
228
|
+
whatever its parent gives it. -->
|
|
229
|
+
<div class="fill-frame">
|
|
230
|
+
<CoarTabGroup v-model="activeTab" fill>
|
|
231
|
+
<CoarTab id="editor">
|
|
232
|
+
<template #default>Editor</template>
|
|
233
|
+
<template #content>
|
|
234
|
+
<div class="filling">
|
|
235
|
+
Active panel fills <strong>{{ panelHeight }} px</strong> of vertical space —
|
|
236
|
+
the entire frame minus the tab bar. Try removing the
|
|
237
|
+
<code>fill</code> prop on <code>CoarTabGroup</code> to see this
|
|
238
|
+
collapse back to content size.
|
|
239
|
+
</div>
|
|
240
|
+
</template>
|
|
241
|
+
</CoarTab>
|
|
242
|
+
<CoarTab id="preview">
|
|
243
|
+
<template #default>Preview</template>
|
|
244
|
+
<template #content>
|
|
245
|
+
<div class="filling alt">
|
|
246
|
+
Same fill behaviour, different content. Switching tabs is free —
|
|
247
|
+
the fill semantics are on the panel, not the content.
|
|
248
|
+
</div>
|
|
249
|
+
</template>
|
|
250
|
+
</CoarTab>
|
|
251
|
+
</CoarTabGroup>
|
|
252
|
+
</div>
|
|
253
|
+
</template>
|
|
254
|
+
|
|
255
|
+
<script setup lang="ts">
|
|
256
|
+
import { onMounted, onUnmounted, ref } from 'vue';
|
|
257
|
+
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';
|
|
258
|
+
|
|
259
|
+
const activeTab = ref('editor');
|
|
260
|
+
const panelHeight = ref(0);
|
|
261
|
+
|
|
262
|
+
let raf: number | null = null;
|
|
263
|
+
const measure = () => {
|
|
264
|
+
const panel = document.querySelector('.fill-frame .coar-tab-panel.active');
|
|
265
|
+
if (panel) panelHeight.value = Math.round(panel.getBoundingClientRect().height);
|
|
266
|
+
raf = requestAnimationFrame(measure);
|
|
267
|
+
};
|
|
268
|
+
onMounted(() => {
|
|
269
|
+
raf = requestAnimationFrame(measure);
|
|
270
|
+
});
|
|
271
|
+
onUnmounted(() => {
|
|
272
|
+
if (raf) cancelAnimationFrame(raf);
|
|
273
|
+
});
|
|
274
|
+
</script>
|
|
275
|
+
|
|
276
|
+
<style scoped>
|
|
277
|
+
/* The frame plays the role the consumer's parent layout plays — a sized
|
|
278
|
+
ancestor (here: explicit height). The tab-group itself is `flex: 1; min-height: 0`
|
|
279
|
+
so it fills the frame, then `fill` mode propagates the height down through
|
|
280
|
+
the internal wrappers. */
|
|
281
|
+
.fill-frame {
|
|
282
|
+
display: flex;
|
|
283
|
+
flex-direction: column;
|
|
284
|
+
height: 320px;
|
|
285
|
+
border: 1px solid var(--coar-border-neutral-secondary);
|
|
286
|
+
border-radius: 8px;
|
|
287
|
+
overflow: hidden;
|
|
288
|
+
}
|
|
289
|
+
.fill-frame :deep(.coar-tab-group) {
|
|
290
|
+
flex: 1;
|
|
291
|
+
min-height: 0;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.filling {
|
|
295
|
+
flex: 1;
|
|
296
|
+
min-height: 0;
|
|
297
|
+
display: flex;
|
|
298
|
+
align-items: center;
|
|
299
|
+
justify-content: center;
|
|
300
|
+
text-align: center;
|
|
301
|
+
padding: 16px;
|
|
302
|
+
font-size: 13px;
|
|
303
|
+
color: var(--coar-text-neutral-secondary);
|
|
304
|
+
background: var(--coar-bg-neutral-secondary);
|
|
305
|
+
}
|
|
306
|
+
.filling.alt {
|
|
307
|
+
background: var(--coar-bg-accent-subtle, var(--coar-bg-neutral-secondary));
|
|
308
|
+
}
|
|
309
|
+
.filling code {
|
|
310
|
+
background: var(--coar-bg-neutral-tertiary);
|
|
311
|
+
padding: 1px 4px;
|
|
312
|
+
border-radius: 3px;
|
|
313
|
+
font-size: 12px;
|
|
314
|
+
}
|
|
315
|
+
</style>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
The consumer is still responsible for sizing the tab-group root — `fill` only propagates the height **down** through the internal wrappers. Typical wiring:
|
|
319
|
+
|
|
320
|
+
```vue
|
|
321
|
+
<!-- Your view -->
|
|
322
|
+
<div class="my-view">
|
|
323
|
+
<CoarTabGroup fill>
|
|
324
|
+
<CoarTab id="editor">
|
|
325
|
+
<template #content>
|
|
326
|
+
<MonacoEditor /> <!-- now sees a flex parent that fills -->
|
|
327
|
+
</template>
|
|
328
|
+
</CoarTab>
|
|
329
|
+
</CoarTabGroup>
|
|
330
|
+
</div>
|
|
331
|
+
|
|
332
|
+
<style scoped>
|
|
333
|
+
.my-view {
|
|
334
|
+
display: flex;
|
|
335
|
+
flex-direction: column;
|
|
336
|
+
height: 100%;
|
|
337
|
+
}
|
|
338
|
+
.my-view :deep(.coar-tab-group) {
|
|
339
|
+
flex: 1;
|
|
340
|
+
min-height: 0;
|
|
341
|
+
}
|
|
342
|
+
</style>
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
> **Tip: Why opt-in?**
|
|
346
|
+
>
|
|
347
|
+
> Without `fill`, the content wrapper is `display: block` — the active panel sizes to its children. That's the right default for the common case (form tabs, settings). Auto-fill would silently break every existing consumer whose tabs sit inside a taller container. Flipping it via a typed prop keeps the change additive and discoverable.
|
|
348
|
+
|
|
349
|
+
## Accessibility
|
|
350
|
+
|
|
351
|
+
### Keyboard Navigation
|
|
352
|
+
|
|
353
|
+
| Key | Action |
|
|
354
|
+
|-----|--------|
|
|
355
|
+
| `Left Arrow` / `Right Arrow` | Move between tabs |
|
|
356
|
+
| `Home` | First tab |
|
|
357
|
+
| `End` | Last tab |
|
|
358
|
+
| `Tab` | Move to panel content |
|
|
359
|
+
|
|
360
|
+
## API
|
|
361
|
+
|
|
362
|
+
### CoarTabGroup Props
|
|
363
|
+
|
|
364
|
+
| Prop | Type | Default | Description |
|
|
365
|
+
|------|------|---------|-------------|
|
|
366
|
+
| `v-model` | `string` | first tab id | ID of the active tab |
|
|
367
|
+
| `fill` | `boolean` | `false` | Make the active panel fill the remaining vertical space below the tab bar. Opt-in for editor / viewer / file-explorer tabs. See [Fill-Height Tabs](#fill-height-tabs). |
|
|
368
|
+
|
|
369
|
+
### CoarTabGroup Slots
|
|
370
|
+
|
|
371
|
+
| Slot | Description |
|
|
372
|
+
|------|-------------|
|
|
373
|
+
| `default` | Contains one or more `CoarTab` children defining tabs and their panels. |
|
|
374
|
+
| `actions` | Optional right-aligned controls in the tab-list row. Rendered only when populated; empty-slot consumers see the standard layout. |
|
|
375
|
+
|
|
376
|
+
### CoarTab Props
|
|
377
|
+
|
|
378
|
+
| Prop | Type | Default | Description |
|
|
379
|
+
|------|------|---------|-------------|
|
|
380
|
+
| `id` | `string` | — | Unique tab identifier (**required**) |
|
|
381
|
+
| `disabled` | `boolean` | `false` | Disable this tab |
|
|
382
|
+
| `loadingStrategy` | `'lazy' \| 'eager'` | `'lazy'` | `lazy`: content only rendered when active; `eager`: always in DOM |
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/tag.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Tag
|
|
4
|
+
|
|
5
|
+
Tags label, categorize, and organize content. Use them for metadata (status labels, technology stacks), filter chips, or user-driven selections. Unlike badges, which show counts and status dots, tags convey descriptive information that users can read and often interact with.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CoarTag } from '@cocoar/vue-ui';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Color Variants
|
|
12
|
+
|
|
13
|
+
Six semantic variants let you color-code categories, statuses, or priority levels consistently across your application.
|
|
14
|
+
|
|
15
|
+
**Demo — `tag/demos/TagVariants.vue`**
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<template>
|
|
19
|
+
<div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: center;">
|
|
20
|
+
<CoarTag variant="neutral">Neutral</CoarTag>
|
|
21
|
+
<CoarTag variant="info">Info</CoarTag>
|
|
22
|
+
<CoarTag variant="success">Success</CoarTag>
|
|
23
|
+
<CoarTag variant="warning">Warning</CoarTag>
|
|
24
|
+
<CoarTag variant="error">Error</CoarTag>
|
|
25
|
+
<CoarTag variant="accent">Accent</CoarTag>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
import { CoarTag } from '@cocoar/vue-ui';
|
|
31
|
+
</script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Sizes
|
|
35
|
+
|
|
36
|
+
Three sizes to match the surrounding context -- `s` for data tables, `m` for general use, and `l` for prominent labels.
|
|
37
|
+
|
|
38
|
+
**Demo — `tag/demos/TagSizes.vue`**
|
|
39
|
+
|
|
40
|
+
```vue
|
|
41
|
+
<template>
|
|
42
|
+
<div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end;">
|
|
43
|
+
<CoarTag variant="info" size="s">Small</CoarTag>
|
|
44
|
+
<CoarTag variant="info" size="m">Medium</CoarTag>
|
|
45
|
+
<CoarTag variant="info" size="l">Large</CoarTag>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script setup lang="ts">
|
|
50
|
+
import { CoarTag } from '@cocoar/vue-ui';
|
|
51
|
+
</script>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Closable Tags
|
|
55
|
+
|
|
56
|
+
Enable the `closable` prop to let users remove tags. Listen to the `@closed` event to update your data. Ideal for filter bars, selected options, and editable tag lists.
|
|
57
|
+
|
|
58
|
+
**Demo — `tag/demos/TagClosable.vue`**
|
|
59
|
+
|
|
60
|
+
```vue
|
|
61
|
+
<template>
|
|
62
|
+
<div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: center;">
|
|
63
|
+
<CoarTag
|
|
64
|
+
v-for="tag in tags"
|
|
65
|
+
:key="tag"
|
|
66
|
+
variant="info"
|
|
67
|
+
closable
|
|
68
|
+
@closed="removeTag(tag)"
|
|
69
|
+
>{{ tag }}</CoarTag>
|
|
70
|
+
<span v-if="tags.length === 0" style="font-size: 14px; color: #94a3b8;">All tags removed</span>
|
|
71
|
+
</div>
|
|
72
|
+
</template>
|
|
73
|
+
|
|
74
|
+
<script setup lang="ts">
|
|
75
|
+
import { ref } from 'vue';
|
|
76
|
+
import { CoarTag } from '@cocoar/vue-ui';
|
|
77
|
+
|
|
78
|
+
const tags = ref(['Vue 3', 'TypeScript', 'Vite', 'Pinia', 'TailwindCSS']);
|
|
79
|
+
|
|
80
|
+
function removeTag(tag: string) {
|
|
81
|
+
tags.value = tags.value.filter(t => t !== tag);
|
|
82
|
+
}
|
|
83
|
+
</script>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Selectable Tags
|
|
87
|
+
|
|
88
|
+
Make tags toggleable for selection interfaces -- filter panels, interest pickers, or any multi-choice input that benefits from a visual, chip-style UI.
|
|
89
|
+
|
|
90
|
+
**Demo — `tag/demos/TagSelectable.vue`**
|
|
91
|
+
|
|
92
|
+
```vue
|
|
93
|
+
<template>
|
|
94
|
+
<div>
|
|
95
|
+
<div style="display: flex; flex-wrap: wrap; gap: 8px; align-items: center;">
|
|
96
|
+
<CoarTag
|
|
97
|
+
v-for="tech in options"
|
|
98
|
+
:key="tech"
|
|
99
|
+
:variant="activeTags.includes(tech) ? 'info' : 'neutral'"
|
|
100
|
+
style="cursor: pointer;"
|
|
101
|
+
@click="toggleTag(tech)"
|
|
102
|
+
>{{ tech }}</CoarTag>
|
|
103
|
+
</div>
|
|
104
|
+
<p style="margin: 8px 0 0; font-size: 13px; color: #64748b;">Active: {{ activeTags.join(', ') || 'none' }}</p>
|
|
105
|
+
</div>
|
|
106
|
+
</template>
|
|
107
|
+
|
|
108
|
+
<script setup lang="ts">
|
|
109
|
+
import { ref } from 'vue';
|
|
110
|
+
import { CoarTag } from '@cocoar/vue-ui';
|
|
111
|
+
|
|
112
|
+
const options = ['vue', 'typescript', 'vite', 'pinia'];
|
|
113
|
+
const activeTags = ref(['vue', 'typescript']);
|
|
114
|
+
|
|
115
|
+
function toggleTag(tag: string) {
|
|
116
|
+
const i = activeTags.value.indexOf(tag);
|
|
117
|
+
if (i >= 0) activeTags.value.splice(i, 1);
|
|
118
|
+
else activeTags.value.push(tag);
|
|
119
|
+
}
|
|
120
|
+
</script>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Tag Groups
|
|
124
|
+
|
|
125
|
+
Cluster related tags together to label content. This pattern works well for article metadata, skill sets, and category breakdowns.
|
|
126
|
+
|
|
127
|
+
**Demo — `tag/demos/TagGroups.vue`**
|
|
128
|
+
|
|
129
|
+
```vue
|
|
130
|
+
<template>
|
|
131
|
+
<div style="display: flex; flex-direction: column; gap: 12px;">
|
|
132
|
+
<div>
|
|
133
|
+
<p style="font-size: 13px; color: #64748b; margin: 0 0 4px;">Status</p>
|
|
134
|
+
<div style="display: flex; flex-wrap: wrap; gap: 8px;">
|
|
135
|
+
<CoarTag variant="success">Active</CoarTag>
|
|
136
|
+
<CoarTag variant="warning">Pending</CoarTag>
|
|
137
|
+
<CoarTag variant="error">Expired</CoarTag>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
<div>
|
|
141
|
+
<p style="font-size: 13px; color: #64748b; margin: 0 0 4px;">Technologies</p>
|
|
142
|
+
<div style="display: flex; flex-wrap: wrap; gap: 8px;">
|
|
143
|
+
<CoarTag variant="accent">Vue 3</CoarTag>
|
|
144
|
+
<CoarTag variant="accent">TypeScript</CoarTag>
|
|
145
|
+
<CoarTag variant="accent">Vite</CoarTag>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</template>
|
|
150
|
+
|
|
151
|
+
<script setup lang="ts">
|
|
152
|
+
import { CoarTag } from '@cocoar/vue-ui';
|
|
153
|
+
</script>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## API
|
|
157
|
+
|
|
158
|
+
### Props
|
|
159
|
+
|
|
160
|
+
| Prop | Type | Default | Description |
|
|
161
|
+
|------|------|---------|-------------|
|
|
162
|
+
| `variant` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'error' \| 'accent'` | `'neutral'` | Tag color variant |
|
|
163
|
+
| `size` | `'s' \| 'm' \| 'l'` | `'m'` | Tag size |
|
|
164
|
+
| `closable` | `boolean` | `false` | Show close button |
|
|
165
|
+
|
|
166
|
+
### Events
|
|
167
|
+
|
|
168
|
+
| Event | Payload | Description |
|
|
169
|
+
|-------|---------|-------------|
|
|
170
|
+
| `closed` | — | Emitted when the close button is clicked |
|
|
171
|
+
|
|
172
|
+
## i18n Keys
|
|
173
|
+
|
|
174
|
+
These keys can be translated via [`@cocoar/vue-localization`](../foundations/localization/translations.md).
|
|
175
|
+
|
|
176
|
+
| Key | Default (English) | Used as |
|
|
177
|
+
|-----|-------------------|---------|
|
|
178
|
+
| `coar.ui.tag.remove` | `'Remove tag'` | Close button `aria-label` (when `closable` is true) |
|