@cocoar/vue-ui 3.1.0 → 3.2.0-beta.6

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