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

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 (180) hide show
  1. package/bin/cli.mjs +53 -0
  2. package/dist/components/checkbox/CoarCheckbox.vue.d.ts +1 -1
  3. package/dist/components/checkbox/CoarCheckbox.vue.d.ts.map +1 -1
  4. package/dist/components/code-block/CoarCodeBlock.vue.d.ts +1 -1
  5. package/dist/components/code-block/CoarCodeBlock.vue.d.ts.map +1 -1
  6. package/dist/components/data-list/CoarDataList.vue.d.ts +158 -0
  7. package/dist/components/data-list/CoarDataList.vue.d.ts.map +1 -0
  8. package/dist/components/data-list/CoarDataListToolbar.vue.d.ts +30 -0
  9. package/dist/components/data-list/CoarDataListToolbar.vue.d.ts.map +1 -0
  10. package/dist/components/data-list/data-list-builder.d.ts +288 -0
  11. package/dist/components/data-list/data-list-builder.d.ts.map +1 -0
  12. package/dist/components/data-list/index.d.ts +12 -0
  13. package/dist/components/data-list/index.d.ts.map +1 -0
  14. package/dist/components/data-list/internal/compare.d.ts +14 -0
  15. package/dist/components/data-list/internal/compare.d.ts.map +1 -0
  16. package/dist/components/data-list/internal/reorder-core.d.ts +46 -0
  17. package/dist/components/data-list/internal/reorder-core.d.ts.map +1 -0
  18. package/dist/components/data-list/internal/search.d.ts +16 -0
  19. package/dist/components/data-list/internal/search.d.ts.map +1 -0
  20. package/dist/components/data-list/internal/useDataListLines.d.ts +92 -0
  21. package/dist/components/data-list/internal/useDataListLines.d.ts.map +1 -0
  22. package/dist/components/data-list/internal/useDataListReorder.d.ts +68 -0
  23. package/dist/components/data-list/internal/useDataListReorder.d.ts.map +1 -0
  24. package/dist/components/data-list/internal/useSearchHighlight.d.ts +19 -0
  25. package/dist/components/data-list/internal/useSearchHighlight.d.ts.map +1 -0
  26. package/dist/components/data-list/types.d.ts +185 -0
  27. package/dist/components/data-list/types.d.ts.map +1 -0
  28. package/dist/components/data-list/useDataListModel.d.ts +79 -0
  29. package/dist/components/data-list/useDataListModel.d.ts.map +1 -0
  30. package/dist/components/date-time/_shared/maskito-config.d.ts +7 -2
  31. package/dist/components/date-time/_shared/maskito-config.d.ts.map +1 -1
  32. package/dist/components/date-time/_shared/time-helpers.d.ts +11 -4
  33. package/dist/components/date-time/_shared/time-helpers.d.ts.map +1 -1
  34. package/dist/components/date-time/_shared/use-date-picker-base.d.ts +1 -1
  35. package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts +1 -1
  36. package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts.map +1 -1
  37. package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts +1 -1
  38. package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts.map +1 -1
  39. package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts +1 -1
  40. package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts.map +1 -1
  41. package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts +3 -0
  42. package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts.map +1 -1
  43. package/dist/components/form-field/CoarFormField.vue.d.ts +1 -1
  44. package/dist/components/form-field/CoarFormField.vue.d.ts.map +1 -1
  45. package/dist/components/icon/CoarIcon.vue.d.ts +2 -2
  46. package/dist/components/icon/CoarIcon.vue.d.ts.map +1 -1
  47. package/dist/components/listbox/CoarListbox.vue.d.ts +7 -0
  48. package/dist/components/listbox/CoarListbox.vue.d.ts.map +1 -1
  49. package/dist/components/number-input/CoarNumberInput.vue.d.ts +1 -1
  50. package/dist/components/number-input/CoarNumberInput.vue.d.ts.map +1 -1
  51. package/dist/components/otp-input/CoarOtpInput.vue.d.ts +1 -1
  52. package/dist/components/otp-input/CoarOtpInput.vue.d.ts.map +1 -1
  53. package/dist/components/password-input/CoarPasswordInput.vue.d.ts +1 -1
  54. package/dist/components/password-input/CoarPasswordInput.vue.d.ts.map +1 -1
  55. package/dist/components/switch/CoarSwitch.vue.d.ts +1 -1
  56. package/dist/components/switch/CoarSwitch.vue.d.ts.map +1 -1
  57. package/dist/components/text-input/CoarTextInput.vue.d.ts +1 -1
  58. package/dist/components/text-input/CoarTextInput.vue.d.ts.map +1 -1
  59. package/dist/composables/dragRegistry.d.ts +12 -0
  60. package/dist/composables/dragRegistry.d.ts.map +1 -1
  61. package/dist/composables/index.d.ts +2 -2
  62. package/dist/composables/index.d.ts.map +1 -1
  63. package/dist/composables/useDragDrop.d.ts +62 -6
  64. package/dist/composables/useDragDrop.d.ts.map +1 -1
  65. package/dist/composables/useVirtualList.d.ts +21 -1
  66. package/dist/composables/useVirtualList.d.ts.map +1 -1
  67. package/dist/index.css +1 -1
  68. package/dist/index.d.ts +4 -2
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +4508 -2039
  71. package/package.json +9 -3
  72. package/skills/cocoar-vue-ui/SKILL.md +244 -0
  73. package/skills/cocoar-vue-ui/references/components/avatar.md +178 -0
  74. package/skills/cocoar-vue-ui/references/components/badge.md +290 -0
  75. package/skills/cocoar-vue-ui/references/components/breadcrumb.md +238 -0
  76. package/skills/cocoar-vue-ui/references/components/button.md +252 -0
  77. package/skills/cocoar-vue-ui/references/components/calendar/agenda-view.md +372 -0
  78. package/skills/cocoar-vue-ui/references/components/calendar/coar-calendar.md +1647 -0
  79. package/skills/cocoar-vue-ui/references/components/calendar/day-view.md +361 -0
  80. package/skills/cocoar-vue-ui/references/components/calendar/index.md +312 -0
  81. package/skills/cocoar-vue-ui/references/components/calendar/month-view.md +486 -0
  82. package/skills/cocoar-vue-ui/references/components/calendar/performance.md +186 -0
  83. package/skills/cocoar-vue-ui/references/components/calendar/timeline-view.md +301 -0
  84. package/skills/cocoar-vue-ui/references/components/calendar/week-view.md +382 -0
  85. package/skills/cocoar-vue-ui/references/components/calendar/work-week-view.md +145 -0
  86. package/skills/cocoar-vue-ui/references/components/calendar/year-view.md +63 -0
  87. package/skills/cocoar-vue-ui/references/components/card.md +151 -0
  88. package/skills/cocoar-vue-ui/references/components/checkbox-group.md +103 -0
  89. package/skills/cocoar-vue-ui/references/components/checkbox.md +279 -0
  90. package/skills/cocoar-vue-ui/references/components/code-block.md +241 -0
  91. package/skills/cocoar-vue-ui/references/components/context-menu.md +355 -0
  92. package/skills/cocoar-vue-ui/references/components/data-grid/checkbox.md +213 -0
  93. package/skills/cocoar-vue-ui/references/components/data-grid/date-columns.md +272 -0
  94. package/skills/cocoar-vue-ui/references/components/data-grid/editing.md +236 -0
  95. package/skills/cocoar-vue-ui/references/components/data-grid/multi-select.md +193 -0
  96. package/skills/cocoar-vue-ui/references/components/data-grid/number.md +147 -0
  97. package/skills/cocoar-vue-ui/references/components/data-grid/select.md +202 -0
  98. package/skills/cocoar-vue-ui/references/components/data-grid/text.md +127 -0
  99. package/skills/cocoar-vue-ui/references/components/data-grid.md +1225 -0
  100. package/skills/cocoar-vue-ui/references/components/data-list.md +2121 -0
  101. package/skills/cocoar-vue-ui/references/components/date-or-time-picker.md +200 -0
  102. package/skills/cocoar-vue-ui/references/components/date-picker.md +203 -0
  103. package/skills/cocoar-vue-ui/references/components/date-time-picker.md +154 -0
  104. package/skills/cocoar-vue-ui/references/components/date-views.md +212 -0
  105. package/skills/cocoar-vue-ui/references/components/dialog.md +148 -0
  106. package/skills/cocoar-vue-ui/references/components/divider.md +157 -0
  107. package/skills/cocoar-vue-ui/references/components/document-viewer/annotations.md +400 -0
  108. package/skills/cocoar-vue-ui/references/components/document-viewer/coar-document-viewer.md +327 -0
  109. package/skills/cocoar-vue-ui/references/components/document-viewer/index.md +234 -0
  110. package/skills/cocoar-vue-ui/references/components/document-viewer/toolbar.md +221 -0
  111. package/skills/cocoar-vue-ui/references/components/drag-drop.md +267 -0
  112. package/skills/cocoar-vue-ui/references/components/dual-listbox.md +449 -0
  113. package/skills/cocoar-vue-ui/references/components/file-explorer/asset-store.md +327 -0
  114. package/skills/cocoar-vue-ui/references/components/file-explorer/in-memory-store.md +176 -0
  115. package/skills/cocoar-vue-ui/references/components/file-explorer/index.md +311 -0
  116. package/skills/cocoar-vue-ui/references/components/file-explorer/use-file-explorer.md +300 -0
  117. package/skills/cocoar-vue-ui/references/components/form-field.md +1025 -0
  118. package/skills/cocoar-vue-ui/references/components/fragment-parser.md +298 -0
  119. package/skills/cocoar-vue-ui/references/components/link.md +235 -0
  120. package/skills/cocoar-vue-ui/references/components/listbox.md +575 -0
  121. package/skills/cocoar-vue-ui/references/components/map/editor.md +448 -0
  122. package/skills/cocoar-vue-ui/references/components/map/index.md +351 -0
  123. package/skills/cocoar-vue-ui/references/components/markdown-diagrams.md +210 -0
  124. package/skills/cocoar-vue-ui/references/components/markdown-editor.md +1478 -0
  125. package/skills/cocoar-vue-ui/references/components/markdown-embeds.md +387 -0
  126. package/skills/cocoar-vue-ui/references/components/markdown-form.md +447 -0
  127. package/skills/cocoar-vue-ui/references/components/markdown.md +276 -0
  128. package/skills/cocoar-vue-ui/references/components/menu.md +380 -0
  129. package/skills/cocoar-vue-ui/references/components/mermaid.md +172 -0
  130. package/skills/cocoar-vue-ui/references/components/navbar.md +147 -0
  131. package/skills/cocoar-vue-ui/references/components/note.md +96 -0
  132. package/skills/cocoar-vue-ui/references/components/notice.md +131 -0
  133. package/skills/cocoar-vue-ui/references/components/number-input.md +215 -0
  134. package/skills/cocoar-vue-ui/references/components/otp-input.md +324 -0
  135. package/skills/cocoar-vue-ui/references/components/page-builder/authoring-contract.md +271 -0
  136. package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-builder.md +476 -0
  137. package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-renderer.md +677 -0
  138. package/skills/cocoar-vue-ui/references/components/page-builder/custom-elements.md +441 -0
  139. package/skills/cocoar-vue-ui/references/components/page-builder/idp-integration.md +122 -0
  140. package/skills/cocoar-vue-ui/references/components/page-builder/index.md +573 -0
  141. package/skills/cocoar-vue-ui/references/components/pagination.md +150 -0
  142. package/skills/cocoar-vue-ui/references/components/panel-layout.md +372 -0
  143. package/skills/cocoar-vue-ui/references/components/password-input.md +175 -0
  144. package/skills/cocoar-vue-ui/references/components/popconfirm.md +186 -0
  145. package/skills/cocoar-vue-ui/references/components/popover.md +173 -0
  146. package/skills/cocoar-vue-ui/references/components/progress-bar.md +178 -0
  147. package/skills/cocoar-vue-ui/references/components/radio-group.md +225 -0
  148. package/skills/cocoar-vue-ui/references/components/script-editor.md +1271 -0
  149. package/skills/cocoar-vue-ui/references/components/segmented-control.md +238 -0
  150. package/skills/cocoar-vue-ui/references/components/select.md +463 -0
  151. package/skills/cocoar-vue-ui/references/components/sidebar.md +421 -0
  152. package/skills/cocoar-vue-ui/references/components/spinner.md +132 -0
  153. package/skills/cocoar-vue-ui/references/components/switch.md +195 -0
  154. package/skills/cocoar-vue-ui/references/components/table.md +170 -0
  155. package/skills/cocoar-vue-ui/references/components/tabs.md +382 -0
  156. package/skills/cocoar-vue-ui/references/components/tag.md +178 -0
  157. package/skills/cocoar-vue-ui/references/components/text-input.md +256 -0
  158. package/skills/cocoar-vue-ui/references/components/toast.md +160 -0
  159. package/skills/cocoar-vue-ui/references/components/tooltip.md +121 -0
  160. package/skills/cocoar-vue-ui/references/components/transitions.md +193 -0
  161. package/skills/cocoar-vue-ui/references/components/tree.md +2388 -0
  162. package/skills/cocoar-vue-ui/references/components/virtual-list.md +212 -0
  163. package/skills/cocoar-vue-ui/references/components/wizard.md +251 -0
  164. package/skills/cocoar-vue-ui/references/components/zoned-date-time-picker.md +177 -0
  165. package/skills/cocoar-vue-ui/references/foundations/colors.md +708 -0
  166. package/skills/cocoar-vue-ui/references/foundations/design-principles.md +115 -0
  167. package/skills/cocoar-vue-ui/references/foundations/icons.md +381 -0
  168. package/skills/cocoar-vue-ui/references/foundations/localization/formatting.md +530 -0
  169. package/skills/cocoar-vue-ui/references/foundations/localization/setup.md +86 -0
  170. package/skills/cocoar-vue-ui/references/foundations/localization/timezones.md +182 -0
  171. package/skills/cocoar-vue-ui/references/foundations/localization/translations.md +305 -0
  172. package/skills/cocoar-vue-ui/references/foundations/motion.md +549 -0
  173. package/skills/cocoar-vue-ui/references/foundations/spacing.md +330 -0
  174. package/skills/cocoar-vue-ui/references/foundations/theming.md +140 -0
  175. package/skills/cocoar-vue-ui/references/foundations/typography.md +206 -0
  176. package/skills/cocoar-vue-ui/references/guide/error-handling.md +162 -0
  177. package/skills/cocoar-vue-ui/references/guide/getting-started.md +116 -0
  178. package/skills/cocoar-vue-ui/references/guide/migration-page-builder-3.md +207 -0
  179. package/skills/cocoar-vue-ui/references/guide/migration.md +140 -0
  180. package/skills/cocoar-vue-ui/references/guide/theming.md +98 -0
@@ -0,0 +1,298 @@
1
+ <!-- Generated from apps/docs/components/fragment-parser.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
2
+
3
+ # Fragment Parser & Modal Routing
4
+
5
+ Parse URL fragments (hash portion) into structured routes with parameters. Combined with composables, this enables **deep-linkable modals** — open modals via URL, share links, and use browser back to close them.
6
+
7
+ > **Info: Separate Package**
8
+ >
9
+ ```bash
10
+ pnpm add @cocoar/vue-fragment-parser
11
+ ```
12
+
13
+ ```ts
14
+ import {
15
+ parseFragment, // Core parser
16
+ useFragmentNavigation, // navigateToModal(), closeModal()
17
+ useRoutedFragments, // Reactive fragment parsing
18
+ useRoutedModals, // Auto dialog/modal from URL
19
+ type DialogFragment, // type: 'dialog' route config
20
+ type ModalFragment, // type: 'modal' route config
21
+ } from '@cocoar/vue-fragment-parser';
22
+ ```
23
+
24
+ ## Basic Usage
25
+
26
+ Define routes with path patterns and parse the current URL fragment:
27
+
28
+ ```ts
29
+ import { parseFragment, type RoutedFragmentBase } from '@cocoar/vue-fragment-parser';
30
+
31
+ interface AppRoute extends RoutedFragmentBase {
32
+ type: string;
33
+ path: string | string[];
34
+ options?: { requiresAuth?: boolean };
35
+ }
36
+
37
+ const routes: AppRoute[] = [
38
+ { type: 'overview', path: 'overview' },
39
+ { type: 'details', path: 'details/:id' },
40
+ { type: 'edit', path: 'details/:id/edit' },
41
+ ];
42
+
43
+ // URL: https://app.com/#details/42?tab=comments
44
+ const result = parseFragment('#details/42?tab=comments', routes);
45
+ // → [{ route: { type: 'details', ... }, params: { id: '42', tab: 'comments' }, fragment: '...' }]
46
+ ```
47
+
48
+ ## Path Parameters
49
+
50
+ Use `:param` syntax for dynamic segments (powered by `path-to-regexp`):
51
+
52
+ ```ts
53
+ const routes = [
54
+ { type: 'user', path: 'user/:userId' },
55
+ { type: 'project', path: 'project/:projectId/task/:taskId' },
56
+ ];
57
+
58
+ // #user/abc → params: { userId: 'abc' }
59
+ // #project/1/task/42 → params: { projectId: '1', taskId: '42' }
60
+ ```
61
+
62
+ ## Query Parameters
63
+
64
+ Query parameters are parsed automatically with JSON type coercion:
65
+
66
+ ```ts
67
+ // #details/5?edit=true&count=3
68
+ // → params: { id: '5', edit: true, count: 3 }
69
+
70
+ // #overview?tags=["a","b"]
71
+ // → params: { tags: ['a', 'b'] }
72
+ ```
73
+
74
+ ## Multiple Fragments
75
+
76
+ Chain multiple fragments with `#` for composable routing:
77
+
78
+ ```ts
79
+ // #details/5#confirm?force=true
80
+ const results = parseFragment('#details/5#confirm?force=true', routes);
81
+ // → Two parsed routes: details + confirm
82
+ ```
83
+
84
+ ## Array Paths
85
+
86
+ A single route can match multiple paths:
87
+
88
+ ```ts
89
+ const routes = [
90
+ { type: 'docs', path: ['overview', 'usage', 'examples'] },
91
+ ];
92
+
93
+ // #overview → matches docs route
94
+ // #usage → matches docs route
95
+ // #examples → matches docs route
96
+ ```
97
+
98
+ ## Modal Routing
99
+
100
+ The fragment parser's main use case: **deep-linkable modals**. When a user double-clicks a grid row, the modal opens AND the URL updates. Copy-pasting that URL opens the same modal. Browser back closes it.
101
+
102
+ ```
103
+ /todos → just the list
104
+ /todos#todo-42 → list + detail modal for todo-42
105
+ /todos#todo-42?tab=2 → list + detail modal, comments tab selected
106
+ ```
107
+
108
+ ### How It Works
109
+
110
+ Three composables work together:
111
+
112
+ ```
113
+ User clicks row
114
+
115
+ navigateToModal('todo-42') ← useFragmentNavigation
116
+
117
+ URL changes to /todos#todo-42
118
+
119
+ useRoutedFragments detects change ← useRoutedFragments
120
+
121
+ Parses fragment against routes
122
+
123
+ useRoutedModals opens dialog ← useRoutedModals
124
+
125
+ User closes dialog (or browser back)
126
+
127
+ Fragment removed from URL
128
+ ```
129
+
130
+ ### Step 1: Define Fragment Routes
131
+
132
+ Register which fragments should open components in your Vue Router config. Two types are supported:
133
+
134
+ - **`type: 'dialog'`** — Opens inside a `CoarDialog` shell (header, title, close button)
135
+ - **`type: 'modal'`** — Opens as a raw overlay (no shell, your component IS the entire modal)
136
+
137
+ ```ts
138
+ // routes.ts
139
+ import type { RoutedOverlayFragment } from '@cocoar/vue-fragment-parser';
140
+
141
+ const routes = [
142
+ {
143
+ path: '/todos',
144
+ component: () => import('./TodoList.vue'),
145
+ meta: {
146
+ routedFragments: [
147
+ {
148
+ type: 'dialog',
149
+ path: ':todoId',
150
+ component: () => import('./TodoDetail.vue'),
151
+ dialogOptions: { title: 'Todo Details', size: 'l' },
152
+ },
153
+ ] satisfies RoutedOverlayFragment[],
154
+ },
155
+ },
156
+ ];
157
+ ```
158
+
159
+ ### Step 2: Wire Up the List View
160
+
161
+ ```vue
162
+ <!-- TodoList.vue -->
163
+ <script setup lang="ts">
164
+ import { useFragmentNavigation, useRoutedModals } from '@cocoar/vue-fragment-parser';
165
+
166
+ // Auto-open/close modals based on URL fragments
167
+ useRoutedModals();
168
+
169
+ // Navigate to modal on interaction
170
+ const { navigateToModal } = useFragmentNavigation();
171
+
172
+ builder.onRowDoubleClicked((event) => {
173
+ navigateToModal(event.data.id);
174
+ });
175
+
176
+ // With query params:
177
+ // navigateToModal(event.data.id, { tab: 0 })
178
+ // → URL: #todo-42?tab=0
179
+ </script>
180
+ ```
181
+
182
+ ### Step 3: Build the Modal Content
183
+
184
+ The modal component receives fragment params as props, plus a `close` function:
185
+
186
+ ```vue
187
+ <!-- TodoDetail.vue -->
188
+ <script setup lang="ts">
189
+ const props = defineProps<{
190
+ todoId: string; // from fragment path ':todoId'
191
+ tab?: number; // from query params '?tab=2'
192
+ close: (result?: unknown) => void;
193
+ }>();
194
+ </script>
195
+
196
+ <template>
197
+ <div>
198
+ <h3>Todo: {{ todoId }}</h3>
199
+ <button @click="close()">Done</button>
200
+ </div>
201
+ </template>
202
+ ```
203
+
204
+ ### Deep-Linking
205
+
206
+ Copy the URL `https://app.com/todos#todo-42?tab=2` and paste it in a new browser tab. The page loads, the fragment is parsed, and the modal opens automatically with `todoId: 'todo-42'` and `tab: 2`.
207
+
208
+ ### Browser Back & History
209
+
210
+ The modal system integrates with browser history:
211
+
212
+ - **Modal open** → creates a history entry (`/todos` → `/todos#todo-42`)
213
+ - **Modal close** (X button) → creates another entry (`/todos#todo-42` → `/todos`)
214
+ - **Browser Back** after close → goes back to `/todos#todo-42` → modal reopens
215
+ - **Browser Back** while modal is open → goes back to `/todos` → modal closes
216
+
217
+ This means users can navigate modal state with the browser's back/forward buttons, just like regular pages.
218
+
219
+ ### Multiple Modals
220
+
221
+ By default, `navigateToModal` **replaces** the current fragment. Use `append: true` to open multiple modals at once:
222
+
223
+ ```ts
224
+ // Opens modal, replaces any existing fragment
225
+ navigateToModal('todo-42');
226
+ // URL: /todos#todo-42
227
+
228
+ // Opens second modal alongside the first
229
+ navigateToModal('confirm', undefined, { append: true });
230
+ // URL: /todos#todo-42#confirm
231
+ ```
232
+
233
+ Each fragment is matched independently. Closing one modal removes only its fragment.
234
+
235
+ ## Composable API
236
+
237
+ ### `useFragmentNavigation()`
238
+
239
+ ```ts
240
+ const { navigateToModal, closeModal } = useFragmentNavigation();
241
+ ```
242
+
243
+ | Method | Parameters | Description |
244
+ |--------|-----------|-------------|
245
+ | `navigateToModal(path, params?, options?)` | `string, Record<string, ...>?, { append?: boolean }?` | Set fragment in URL, opens modal. `append: true` for multi-modal. |
246
+ | `closeModal(path)` | `string` | Remove fragment from URL, closes modal |
247
+
248
+ ### `useRoutedFragments(routes?)`
249
+
250
+ ```ts
251
+ const { fragments } = useRoutedFragments();
252
+ ```
253
+
254
+ Reactively parses `route.hash` against routes from `route.meta.routedFragments`. Returns `computed<ParsedRoute[]>`.
255
+
256
+ ### `useRoutedModals()`
257
+
258
+ ```ts
259
+ useRoutedModals();
260
+ ```
261
+
262
+ Fire-and-forget composable. Watches fragments and manages the overlay lifecycle:
263
+
264
+ - **`type: 'dialog'`** → opens via `useDialog().open()` with `DialogConfig` (shell with header/title)
265
+ - **`type: 'modal'`** → opens via `getOverlayService().open()` with `OverlaySpec` (raw overlay, no shell)
266
+
267
+ Handles:
268
+ - Fragment appears → lazy-load component → open dialog/modal
269
+ - Fragment removed (close button, browser back) → close
270
+ - Closed by user → remove fragment from URL
271
+ - Page load with fragment → deep-link: opens immediately
272
+
273
+ ## API
274
+
275
+ ### `parseFragment<T>(fragment, routes)`
276
+
277
+ | Parameter | Type | Description |
278
+ |-----------|------|-------------|
279
+ | `fragment` | `string` | URL fragment string (with or without leading `#`) |
280
+ | `routes` | `T[]` | Array of route definitions |
281
+
282
+ **Returns:** `ParsedRoute<T>[]` — array of matched routes
283
+
284
+ ### Types
285
+
286
+ ```ts
287
+ interface RoutedFragmentBase<TOptions = unknown> {
288
+ type: string;
289
+ path: string | string[];
290
+ options?: TOptions;
291
+ }
292
+
293
+ interface ParsedRoute<T extends RoutedFragmentBase> {
294
+ params: Record<string, unknown>; // Path + query parameters
295
+ route: T; // Matched route config
296
+ fragment: string; // Original fragment string
297
+ }
298
+ ```
@@ -0,0 +1,235 @@
1
+ <!-- Generated from apps/docs/components/link.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
2
+
3
+ # Link
4
+
5
+ Styled anchor elements for in-page navigation, external references, and any clickable text that isn't a button action. Two equivalent APIs:
6
+
7
+ - **`<CoarLink>` SFC** (recommended) — `to` for router navigation, `href` for external links, automatic `rel="noopener"` for new-tab safety, disabled handling.
8
+ - **CSS classes** — `<a class="coar-link">` with hand-written `href` / `<RouterLink>` for consumers who want zero abstraction.
9
+
10
+ Both layers share the same CSS in `@cocoar/vue-ui/styles`. Mix them freely.
11
+
12
+ ```ts
13
+ import { CoarLink } from '@cocoar/vue-ui';
14
+ ```
15
+
16
+ ## Basic usage
17
+
18
+ ```vue
19
+ <!-- Router navigation (when vue-router is installed) -->
20
+ <CoarLink to="/docs">Documentation</CoarLink>
21
+
22
+ <!-- External link with safe new-tab default -->
23
+ <CoarLink href="https://docs.cocoar.dev" target="_blank">
24
+ Cocoar Docs
25
+ </CoarLink>
26
+
27
+ <!-- mailto / tel still works via href -->
28
+ <CoarLink href="mailto:hi@example.com">hi@example.com</CoarLink>
29
+ ```
30
+
31
+ The default style applies an accent color with an underline on hover, making links instantly recognizable in any context.
32
+
33
+ **Demo — `link/demos/LinkBasic.vue`**
34
+
35
+ ```vue
36
+ <template>
37
+ <CoarLink to="/getting-started">Default link</CoarLink>
38
+ </template>
39
+
40
+ <script setup lang="ts">
41
+ import { CoarLink } from '@cocoar/vue-ui';
42
+ </script>
43
+ ```
44
+
45
+ ## Variants
46
+
47
+ Use the `accent` variant (default) for primary navigation and calls to action. Switch to `subtle` when the link should blend into surrounding body text.
48
+
49
+ ```vue
50
+ <CoarLink to="/docs" variant="subtle">Read the docs</CoarLink>
51
+ ```
52
+
53
+ **Demo — `link/demos/LinkVariants.vue`**
54
+
55
+ ```vue
56
+ <template>
57
+ <div style="display: flex; flex-direction: column; gap: 8px;">
58
+ <div><CoarLink to="/getting-started">Accent link (default)</CoarLink> — Primary interactive text</div>
59
+ <div><CoarLink to="/changelog" variant="subtle">Subtle link</CoarLink> — Secondary actions, less emphasis</div>
60
+ </div>
61
+ </template>
62
+
63
+ <script setup lang="ts">
64
+ import { CoarLink } from '@cocoar/vue-ui';
65
+ </script>
66
+ ```
67
+
68
+ ## Sizes
69
+
70
+ Three size modifiers align with the typography scale, so links stay proportional whether they appear in footnotes or headings.
71
+
72
+ ```vue
73
+ <CoarLink href="#" size="s">Small</CoarLink>
74
+ <CoarLink href="#" size="m">Medium (default)</CoarLink>
75
+ <CoarLink href="#" size="l">Large</CoarLink>
76
+ ```
77
+
78
+ **Demo — `link/demos/LinkSizes.vue`**
79
+
80
+ ```vue
81
+ <template>
82
+ <div style="display: flex; flex-direction: column; gap: 8px;">
83
+ <div><CoarLink to="/changelog" size="s">Small link</CoarLink> — Compact contexts</div>
84
+ <div><CoarLink to="/getting-started" size="m">Default link</CoarLink> — Body text size</div>
85
+ <div><CoarLink to="/components/button" size="l">Large link</CoarLink> — Prominent CTAs</div>
86
+ </div>
87
+ </template>
88
+
89
+ <script setup lang="ts">
90
+ import { CoarLink } from '@cocoar/vue-ui';
91
+ </script>
92
+ ```
93
+
94
+ ## Disabled state
95
+
96
+ Pass `disabled` to deactivate the link visually and semantically. The component sets `aria-disabled="true"`, `tabindex="-1"`, and intercepts clicks — navigation and `@click` emit are both suppressed.
97
+
98
+ ```vue
99
+ <CoarLink to="/admin" disabled>Admin (insufficient permissions)</CoarLink>
100
+ ```
101
+
102
+ **Demo — `link/demos/LinkDisabled.vue`**
103
+
104
+ ```vue
105
+ <template>
106
+ <div style="display: flex; flex-direction: column; gap: 8px;">
107
+ <div><CoarLink to="/getting-started">Active link</CoarLink></div>
108
+ <div><CoarLink to="/components/button" disabled>Disabled link</CoarLink></div>
109
+ </div>
110
+ </template>
111
+
112
+ <script setup lang="ts">
113
+ import { CoarLink } from '@cocoar/vue-ui';
114
+ </script>
115
+ ```
116
+
117
+ ## Inline usage
118
+
119
+ Links are designed to sit naturally inside running prose without disrupting line height or text flow.
120
+
121
+ **Demo — `link/demos/LinkInline.vue`**
122
+
123
+ ```vue
124
+ <template>
125
+ <p style="margin: 0; font-size: 14px; line-height: 1.6;">
126
+ The COAR Design System is built on top of
127
+ <CoarLink href="https://vuejs.org" target="_blank">Vue 3</CoarLink> and uses the
128
+ <CoarLink href="https://tc39.es/proposal-temporal/docs/" target="_blank">Temporal API</CoarLink> for date/time handling.
129
+ See the <CoarLink to="/getting-started">Getting Started guide</CoarLink> or
130
+ browse the <CoarLink to="/components/button" variant="subtle">full component reference</CoarLink>
131
+ for more details.
132
+ </p>
133
+ </template>
134
+
135
+ <script setup lang="ts">
136
+ import { CoarLink } from '@cocoar/vue-ui';
137
+ </script>
138
+ ```
139
+
140
+ ## Router Integration
141
+
142
+ When `to` is set, the link renders via `<RouterLink>` (if `vue-router` is installed and `app.use(router)` has registered the plugin) for SPA navigation. Without a router, it falls back to a plain `<a href={String(to)}>` that works for absolute URLs. The router detection uses `resolveDynamicComponent('RouterLink')` — no hard dependency, no peerDependency requirement.
143
+
144
+ ```vue
145
+ <!-- SPA navigation when router available -->
146
+ <CoarLink to="/docs">Documentation</CoarLink>
147
+
148
+ <!-- Object-shaped routes work too (with router) -->
149
+ <CoarLink :to="{ name: 'docs', params: { section: 'intro' } }">
150
+ Intro
151
+ </CoarLink>
152
+ ```
153
+
154
+ `aria-current="page"` is applied automatically when the current route matches `to` (via `RouterLink.isActive`).
155
+
156
+ > **Warning: Object `to` without router**
157
+ >
158
+ > Passing an object literal (`{ name: 'docs' }`) when no router is installed falls back to `String(to)`, producing `href="[object Object]"` — a broken link. The component logs a DEV-only `console.warn` once per call site to make this loud. Pass a string path for the no-router case.
159
+
160
+ ## External Links
161
+
162
+ For absolute URLs and `mailto:` / `tel:` schemes, use `href` instead of `to`. The component skips the router entirely and renders a plain `<a>`. When `target="_blank"` is set, `rel="noopener"` is added automatically as a tab-nabbing defence (browsers do this by default since 2021, but the explicit attribute documents intent and works in older browsers).
163
+
164
+ ```vue
165
+ <CoarLink href="https://github.com/cocoar-dev" target="_blank">
166
+ GitHub
167
+ </CoarLink>
168
+ <!-- Renders: <a href="..." target="_blank" rel="noopener" class="coar-link"> -->
169
+ ```
170
+
171
+ You can override the auto-rel by passing your own:
172
+
173
+ ```vue
174
+ <CoarLink
175
+ href="https://untrusted.example.com"
176
+ target="_blank"
177
+ rel="noopener noreferrer external"
178
+ >
179
+ External (extra-cautious)
180
+ </CoarLink>
181
+ ```
182
+
183
+ ## CSS-only usage (no SFC)
184
+
185
+ If you only need the styling and want to wire the link element yourself (typically inside a `<RouterLink>` slot, breadcrumb, or templated context), apply the CSS classes directly to a native `<a>`:
186
+
187
+ ```vue
188
+ <RouterLink to="/docs" custom v-slot="{ href, navigate, isActive }">
189
+ <a
190
+ :href="href"
191
+ class="coar-link"
192
+ :class="{ 'coar-link--disabled': !canVisit }"
193
+ @click="navigate"
194
+ >
195
+ Documentation
196
+ </a>
197
+ </RouterLink>
198
+ ```
199
+
200
+ This is the original API and stays supported indefinitely — the SFC is purely additive.
201
+
202
+ ## API
203
+
204
+ ### Props
205
+
206
+ | Prop | Type | Default | Description |
207
+ |------|------|---------|-------------|
208
+ | `to` | `RouteLocationRaw \| string` | `undefined` | Vue Router target. Takes precedence over `href`. Renders via `<RouterLink>` if installed, else falls back to plain `<a href={String(to)}>`. |
209
+ | `href` | `string` | `undefined` | External URL. Used when `to` is not set. Works for `https:`, `mailto:`, `tel:`, etc. |
210
+ | `variant` | `'accent' \| 'subtle'` | `'accent'` | Visual variant. `accent` for primary links, `subtle` for blending into body text. |
211
+ | `size` | `'s' \| 'm' \| 'l'` | `'m'` | Typography size. |
212
+ | `disabled` | `boolean` | `false` | Disabled state (aria-disabled, tabindex=-1, click suppressed). |
213
+ | `target` | `string` | `undefined` | Anchor target attribute. Only applied to the plain `<a>` branches (not via `<RouterLink>`). |
214
+ | `rel` | `string` | *(see below)* | Anchor rel attribute. Auto-fills to `noopener` when `target="_blank"` is set and no explicit `rel` is provided. |
215
+
216
+ ### Events
217
+
218
+ | Event | Payload | Description |
219
+ |-------|---------|-------------|
220
+ | `click` | `MouseEvent` | Emitted on every plain click (not when disabled). Modifier-clicks (Ctrl/Cmd/Middle) pass through to the browser. |
221
+
222
+ ### Slots
223
+
224
+ | Slot | Description |
225
+ |------|-------------|
226
+ | `default` | Link content (text, icons, anything inline). |
227
+
228
+ ### CSS Classes (legacy / advanced)
229
+
230
+ | Class | Description |
231
+ |-------|-------------|
232
+ | `.coar-link` | Base link style — accent color, underline on hover |
233
+ | `.coar-link--subtle` | Subtle variant with less color emphasis |
234
+ | `.coar-link--s` / `--m` / `--l` | Typography size |
235
+ | `.coar-link--disabled` | Disabled appearance (combine with `aria-disabled="true"`) |