@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,327 @@
1
+ <!-- Generated from apps/docs/components/document-viewer/coar-document-viewer.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
2
+
3
+ # CoarDocumentViewer
4
+
5
+ The all-in-one viewer component. One required prop — `source` — plus a handful of toggles for chrome, panels, and the annotation surface.
6
+
7
+ ```ts
8
+ import { CoarDocumentViewer } from '@cocoar/vue-document-viewer';
9
+ import '@cocoar/vue-document-viewer/styles';
10
+ ```
11
+
12
+ For PDFs, also pull `pdfSource` from the [`/pdf` subpath](./index.md#worker-setup-pdf-consumers-only) and wire the worker once at app bootstrap.
13
+
14
+ ## Minimal usage
15
+
16
+ ```vue
17
+ <script setup lang="ts">
18
+ import { computed } from 'vue';
19
+ import { CoarDocumentViewer, imageSource } from '@cocoar/vue-document-viewer';
20
+ import '@cocoar/vue-document-viewer/styles';
21
+
22
+ const source = computed(() => imageSource({ url: '/attachments/diagram.png' }));
23
+ </script>
24
+
25
+ <template>
26
+ <CoarDocumentViewer :source="source" />
27
+ </template>
28
+ ```
29
+
30
+ That's it. Toolbar on, sidebars and annotations panel off, default 'view' annotation mode. Wrap the viewer in a sized container — the component fills 100% of its parent.
31
+
32
+ ## Props
33
+
34
+ ### Source
35
+
36
+ | Prop | Type | Default | Notes |
37
+ |---|---|---|---|
38
+ | `source` | `DocumentSource` | _required_ | Build via `pdfSource()`, `imageSource()`, or `imageGallerySource()`. Returns a frozen object — build it inside `computed` to avoid unnecessary rebinds. |
39
+
40
+ Switching the `source` keeps the surrounding chrome mounted; only the inner page renderer rebinds, so users see toolbar / panels stay still across document changes.
41
+
42
+ ### Chrome toggles
43
+
44
+ | Prop | Type | Default | Notes |
45
+ |---|---|---|---|
46
+ | `showToolbar` | `boolean` | `true` | Top/side/bottom toolbar — see `toolbarPosition`. |
47
+ | `toolbarPosition` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'top'` | Where the toolbar sits. Horizontal at top/bottom, vertical at sides. |
48
+ | `showThumbnails` | `boolean` | `false` | Left-rail Thumbnails tab. Works for every source (per-page mini canvas). |
49
+ | `showOutline` | `boolean` | `false` | Left-rail Outline (TOC) tab. PDF-only; auto-hides when the doc has no outline. |
50
+ | `showAnnotationsPanel` | `boolean` | `false` | Right-rail panel: Info section + annotation list with filter/sort/search. |
51
+ | `showInfoSection` | `boolean` | `true` | Top section of the annotations panel surfacing source metadata. Only active when the panel is open. |
52
+ | `showSearch` | `boolean` | `true` | Search input (button + bar). Disabled when the source can't search (e.g. images). |
53
+ | `showPrintDownload` | `boolean` | `false` | Print + Download buttons in the toolbar. |
54
+ | `showAnnotationModes` | `boolean` | `true` | The drawing-mode button group (marker / note / draw / text). |
55
+
56
+ Two convenience props — `showThumbnails || showOutline` controls the left-rail toggle button; `showAnnotationsPanel` controls the right-rail toggle. The user can collapse either rail from inside the viewer; these props gate whether the toggle is even present in the toolbar.
57
+
58
+ #### Panel open state (`v-model`)
59
+
60
+ By default, the left and right rails start closed and their open/closed state lives inside the component — fine for stand-alone viewers. If you embed the viewer inside a parent that mounts/unmounts it (e.g. a tab bar in a file explorer where the user switches between a Markdown file and a PDF and back), use `v-model` to hold the state on the parent so it **persists across remounts**.
61
+
62
+ | Prop / Event | Type | Notes |
63
+ |---|---|---|
64
+ | `:sidebar-open` + `@update:sidebar-open` (`v-model:sidebar-open`) | `boolean` | Left rail (thumbnails / outline). Default `false`. |
65
+ | `:annotations-panel-open` + `@update:annotations-panel-open` (`v-model:annotations-panel-open`) | `boolean` | Right rail (info section + annotations list). Default `false`. |
66
+
67
+ ```vue
68
+ <script setup lang="ts">
69
+ import { ref } from 'vue';
70
+ const sidebarOpen = ref(false);
71
+ const panelOpen = ref(false);
72
+ </script>
73
+
74
+ <template>
75
+ <CoarDocumentViewer
76
+ :source="source"
77
+ :show-thumbnails="true"
78
+ :show-annotations-panel="true"
79
+ v-model:sidebar-open="sidebarOpen"
80
+ v-model:annotations-panel-open="panelOpen"
81
+ />
82
+ </template>
83
+ ```
84
+
85
+ Without `v-model`, the state is purely internal — same behavior as before, no breaking change.
86
+
87
+ ### Position memory
88
+
89
+ ```ts
90
+ interface CoarDocumentViewerPosition {
91
+ page: number; // 0-based page index in view
92
+ pageOffset: number; // fractional scroll inside the page, 0..1
93
+ zoom: number; // 1 = 100%
94
+ rotation: 0 | 90 | 180 | 270;
95
+ }
96
+ ```
97
+
98
+ Two compatible mechanisms:
99
+
100
+ | Prop / Event | Use when |
101
+ |---|---|
102
+ | `storageKey: string` | You want the viewer to persist position in `localStorage` automatically. Different keys per document (e.g. include the file ID) so each document remembers its own view. |
103
+ | `:position` + `@update:position` (`v-model:position`) | You own persistence (server, IndexedDB, your existing state manager). Two-way binding — the viewer reads on mount, writes on every change. |
104
+
105
+ Both mechanisms can coexist; when both are present, the bound `position` wins on mount.
106
+
107
+ ### Toolbar layout
108
+
109
+ | Prop | Type | Default | Notes |
110
+ |---|---|---|---|
111
+ | `tools` | `CoarDocumentViewerTool[]` | `undefined` (= `COAR_DOCUMENT_VIEWER_ALL_TOOLS`) | Array drives BOTH the visible set AND the order. See [Toolbar customization](./toolbar.md). |
112
+
113
+ ### Annotations
114
+
115
+ | Prop / Event | Type | Notes |
116
+ |---|---|---|
117
+ | `annotations` | `CoarPdfAnnotation[]` | Consumer-owned. The viewer never mutates this array. |
118
+ | `:annotation-mode` + `@update:annotationMode` (`v-model:annotation-mode`) | `'view' \| 'select' \| 'eraser' \| 'marker' \| 'comment' \| 'ink' \| 'freetext'` | The active pointer mode. `'view'` is read-only (existing annotations clickable, no new ones created). |
119
+ | `annotationColors` | `string[]` | Palette for the color picker. Defaults to a 7-color pastel + neon set. |
120
+ | `@annotation:create` | `(payload: CoarPdfAnnotationCreatePayload) => void` | Consumer assigns `id` + `createdAt` (+ optionally `createdBy`), pushes to `annotations`. |
121
+ | `@annotation:update` | `(payload: { id: string; patch: Partial<CoarPdfAnnotation> }) => void` | Consumer merges the patch into the matching annotation. |
122
+ | `@annotation:delete` | `(id: string) => void` | Consumer removes by id. |
123
+
124
+ See [Annotations](./annotations.md) for the full lifecycle, schema, and a worked example.
125
+
126
+ ### Labels
127
+
128
+ ```ts
129
+ interface CoarDocumentViewerLabels {
130
+ // Loading / error overlays
131
+ loading?: string;
132
+ errorTitle?: string;
133
+ errorRetry?: string;
134
+
135
+ // Page navigation
136
+ pageOf?: string; // "Page {current} of {total}"
137
+ pageJumpAria?: string;
138
+ prevPage?: string;
139
+ nextPage?: string;
140
+
141
+ // Zoom
142
+ zoomIn?: string;
143
+ zoomOut?: string;
144
+ resetZoom?: string;
145
+ zoomLevel?: string;
146
+ fitWidth?: string;
147
+ fitPage?: string;
148
+ resetView?: string;
149
+ pan?: string;
150
+
151
+ // Rotation
152
+ rotateCw?: string;
153
+ rotateCcw?: string;
154
+
155
+ // Search
156
+ search?: string;
157
+ searchNext?: string;
158
+ searchPrev?: string;
159
+ searchMatchOf?: string; // "{current} of {total}"
160
+
161
+ // Panels + sidebar tabs
162
+ thumbnails?: string;
163
+ outline?: string;
164
+ annotationsPanel?: string;
165
+
166
+ // Document actions
167
+ print?: string;
168
+ download?: string;
169
+
170
+ // Annotation modes
171
+ modeView?: string;
172
+ modeSelect?: string;
173
+ modeEraser?: string;
174
+ modeMarker?: string;
175
+ modeNote?: string;
176
+ modeInk?: string;
177
+ modeFreetext?: string;
178
+ strokeWidth?: string;
179
+
180
+ // Annotation panel
181
+ noAnnotations?: string;
182
+ noMatchingAnnotations?: string;
183
+ searchAnnotations?: string;
184
+ filterBy?: string;
185
+ sortBy?: string;
186
+ sortByPage?: string;
187
+ sortChronological?: string;
188
+ pagePrefix?: string;
189
+ justNow?: string;
190
+ moreActions?: string;
191
+ annotationDelete?: string;
192
+ annotationEditComment?: string;
193
+ annotationColor?: string;
194
+
195
+ // Capability tooltip suffix — appended when a tool isn't supported by the source.
196
+ notAvailableForSource?: string;
197
+
198
+ // Info section
199
+ infoSection?: string; // "Info"
200
+ infoFormat?: string;
201
+ infoPages?: string;
202
+ infoPage?: string; // "Page {n}"
203
+ infoSize?: string;
204
+ infoTitle?: string;
205
+ infoAuthor?: string;
206
+ infoSubject?: string;
207
+ infoKeywords?: string;
208
+ infoCreator?: string;
209
+ infoProducer?: string;
210
+ infoCreated?: string;
211
+ infoModified?: string;
212
+ infoPdfVersion?: string;
213
+ }
214
+ ```
215
+
216
+ English defaults are baked in. Pass any subset to override individual strings — keys you omit fall back to the default. `{current}`, `{total}`, `{n}` placeholders are substituted at render time.
217
+
218
+ ## Events
219
+
220
+ | Event | Payload | When |
221
+ |---|---|---|
222
+ | `update:position` | `CoarDocumentViewerPosition` | Page / scroll / zoom / rotation change. Used for `v-model:position`. |
223
+ | `update:annotationMode` | `CoarPdfAnnotationMode` | User picks a different mode in the toolbar. Used for `v-model:annotation-mode`. |
224
+ | `update:sidebarOpen` | `boolean` | User toggles the left rail (thumbnails / outline). Used for `v-model:sidebar-open`. |
225
+ | `update:annotationsPanelOpen` | `boolean` | User toggles the right rail (annotations panel). Used for `v-model:annotations-panel-open`. |
226
+ | `annotation:create` | `CoarPdfAnnotationCreatePayload` | New annotation drawn. Consumer assigns id + timestamp. |
227
+ | `annotation:update` | `{ id, patch }` | Existing annotation edited (color / comment / position). |
228
+ | `annotation:delete` | `string` (id) | Existing annotation removed (via panel menu or eraser tool). |
229
+ | `error` | `CoarDocumentViewerErrorEvent` | Source failed to load. `{ error: unknown, src?: string }`. |
230
+
231
+ ## Slots
232
+
233
+ | Slot | Props | When |
234
+ |---|---|---|
235
+ | `loading` | _none_ | Replaces the default `"Loading…"` text shown while the source is fetching/parsing. |
236
+ | `error` | `{ error: unknown; retry: () => void }` | Replaces the default error overlay. Call `retry()` to re-trigger the load. |
237
+
238
+ ```vue
239
+ <CoarDocumentViewer :source="source">
240
+ <template #loading>
241
+ <CoarSpinner /> Fetching document…
242
+ </template>
243
+ <template #error="{ error, retry }">
244
+ <div>
245
+ <strong>{{ String(error) }}</strong>
246
+ <CoarButton @click="retry">Try again</CoarButton>
247
+ </div>
248
+ </template>
249
+ </CoarDocumentViewer>
250
+ ```
251
+
252
+ ## Sizing
253
+
254
+ The viewer fills 100% of its parent and uses internal flexbox to allocate space across toolbar, panels, and the page area. Put it inside a sized container:
255
+
256
+ ```vue
257
+ <div style="height: 80vh">
258
+ <CoarDocumentViewer :source="source" />
259
+ </div>
260
+ ```
261
+
262
+ Splitters between the columns are draggable — users can resize the left rail (thumbnails) and right rail (annotations panel) on the fly.
263
+
264
+ ## Position memory example
265
+
266
+ ```vue
267
+ <script setup lang="ts">
268
+ import { ref } from 'vue';
269
+ import { CoarDocumentViewer, type CoarDocumentViewerPosition } from '@cocoar/vue-document-viewer';
270
+ import { pdfSource } from '@cocoar/vue-document-viewer/pdf';
271
+
272
+ const source = pdfSource({ url: '/files/manual.pdf' });
273
+
274
+ // v-model:position — server-side persistence
275
+ const position = ref<CoarDocumentViewerPosition>({
276
+ page: 0, pageOffset: 0, zoom: 1, rotation: 0,
277
+ });
278
+ watchDebounced(position, savePositionToServer, { debounce: 300 });
279
+
280
+ // OR — storageKey for automatic localStorage persistence
281
+ </script>
282
+
283
+ <template>
284
+ <CoarDocumentViewer
285
+ :source="source"
286
+ v-model:position="position"
287
+ storage-key="manual.pdf"
288
+ />
289
+ </template>
290
+ ```
291
+
292
+ Use one OR the other in practice — both is fine, just pick the priority. When both are present, the bound `position` wins on mount; afterwards both stay in sync.
293
+
294
+ ## Common configurations
295
+
296
+ ### Read-only PDF viewer with thumbnails
297
+
298
+ ```vue
299
+ <CoarDocumentViewer
300
+ :source="source"
301
+ :show-thumbnails="true"
302
+ :show-outline="true"
303
+ :show-print-download="true"
304
+ :show-annotation-modes="false"
305
+ />
306
+ ```
307
+
308
+ ### Annotation tool with persistence
309
+
310
+ ```vue
311
+ <CoarDocumentViewer
312
+ :source="source"
313
+ :show-annotations-panel="true"
314
+ v-model:annotation-mode="mode"
315
+ :annotations="annotations"
316
+ storage-key="contract-2024"
317
+ @annotation:create="handleCreate"
318
+ @annotation:update="handleUpdate"
319
+ @annotation:delete="handleDelete"
320
+ />
321
+ ```
322
+
323
+ ### Minimal embedded preview (no toolbar)
324
+
325
+ ```vue
326
+ <CoarDocumentViewer :source="source" :show-toolbar="false" />
327
+ ```
@@ -0,0 +1,234 @@
1
+ <!-- Generated from apps/docs/components/document-viewer/index.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
2
+
3
+ # Document Viewer (Preview)
4
+
5
+ `@cocoar/vue-document-viewer` is a generic, source-agnostic document viewer for Vue 3. One component — [`<CoarDocumentViewer>`](./coar-document-viewer.md) — renders **PDFs**, **single images**, and **multi-page image galleries**, with shared toolbar chrome, side panels, and an annotation layer.
6
+
7
+ You pick the source kind with a small factory (`pdfSource(...)`, `imageSource(...)`, `imageGallerySource(...)`); the viewer dispatches internally. The toolbar greys out tools the active source doesn't support — e.g. search and outline are PDF-only — rather than hiding them, so users don't see UI moving around when they switch documents.
8
+
9
+ ```ts
10
+ import {
11
+ CoarDocumentViewer,
12
+ imageSource,
13
+ imageGallerySource,
14
+ } from '@cocoar/vue-document-viewer';
15
+ import { pdfSource } from '@cocoar/vue-document-viewer/pdf';
16
+ import '@cocoar/vue-document-viewer/styles';
17
+ ```
18
+
19
+ `pdfjs-dist` is an **optional peer dependency**. PDF consumers import `pdfSource` from the `/pdf` subpath; image-only consumers never pay the pdfjs bundle cost.
20
+
21
+ ## Three source factories
22
+
23
+ ```ts
24
+ // PDF — pdfjs subpath
25
+ pdfSource({ url, headers?, withCredentials? })
26
+
27
+ // Single-page raster / vector image (JPG / PNG / SVG / WebP / AVIF / GIF / blob: / data:)
28
+ imageSource({ url })
29
+
30
+ // Multi-page image document — pages may mix orientations
31
+ imageGallerySource({ urls })
32
+ ```
33
+
34
+ Each factory returns a frozen `DocumentSource`. Build it inside a `computed` so the viewer rebinds only when something actually changes — switching sources keeps the toolbar, panels, and viewport mounted; only the inner page renderer rebinds.
35
+
36
+ ## Single image
37
+
38
+ **Demo — `document-viewer/demos/ImageSourceDemo.vue`**
39
+
40
+ ```vue
41
+ <template>
42
+ <ClientOnly>
43
+ <div style="height: 520px; border: 1px solid var(--vp-c-divider); border-radius: 8px; overflow: hidden;">
44
+ <component
45
+ :is="Viewer"
46
+ v-if="Viewer && source"
47
+ :source="source"
48
+ :show-thumbnails="true"
49
+ :show-annotations-panel="true"
50
+ />
51
+ <div v-else class="dv-loading">Loading viewer…</div>
52
+ </div>
53
+ </ClientOnly>
54
+ </template>
55
+
56
+ <script setup lang="ts">
57
+ import { computed, onMounted, ref, shallowRef, type Component } from 'vue';
58
+ import { SINGLE_IMAGE_URL } from './_shared';
59
+
60
+ const Viewer = shallowRef<Component | null>(null);
61
+ const imageSource = shallowRef<((opts: { url: string }) => unknown) | null>(null);
62
+
63
+ const source = computed(() => imageSource.value?.({ url: SINGLE_IMAGE_URL }) ?? null);
64
+
65
+ onMounted(async () => {
66
+ const mod = await import('@cocoar/vue-document-viewer');
67
+ await import('@cocoar/vue-document-viewer/styles');
68
+ imageSource.value = mod.imageSource;
69
+ Viewer.value = mod.CoarDocumentViewer;
70
+ });
71
+ </script>
72
+
73
+ <style scoped>
74
+ .dv-loading {
75
+ height: 100%;
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ color: var(--coar-text-neutral-tertiary, #6b7280);
80
+ font-size: 13px;
81
+ }
82
+ </style>
83
+ ```
84
+
85
+ Toolbar tools the source doesn't support stay visible but disabled — e.g. **Search**, **Previous/Next page**, and **Outline** are off for a single-page image. Their tooltips append the `notAvailableForSource` label so the user understands the state.
86
+
87
+ ## Image gallery
88
+
89
+ **Demo — `document-viewer/demos/GallerySourceDemo.vue`**
90
+
91
+ ```vue
92
+ <template>
93
+ <ClientOnly>
94
+ <div style="height: 520px; border: 1px solid var(--vp-c-divider); border-radius: 8px; overflow: hidden;">
95
+ <component
96
+ :is="Viewer"
97
+ v-if="Viewer && source"
98
+ :source="source"
99
+ :show-thumbnails="true"
100
+ :show-annotations-panel="true"
101
+ />
102
+ <div v-else class="dv-loading">Loading viewer…</div>
103
+ </div>
104
+ </ClientOnly>
105
+ </template>
106
+
107
+ <script setup lang="ts">
108
+ import { computed, onMounted, shallowRef, type Component } from 'vue';
109
+ import { GALLERY_URLS } from './_shared';
110
+
111
+ const Viewer = shallowRef<Component | null>(null);
112
+ const galleryFactory = shallowRef<((opts: { urls: readonly string[] }) => unknown) | null>(null);
113
+
114
+ const source = computed(() => galleryFactory.value?.({ urls: GALLERY_URLS }) ?? null);
115
+
116
+ onMounted(async () => {
117
+ const mod = await import('@cocoar/vue-document-viewer');
118
+ await import('@cocoar/vue-document-viewer/styles');
119
+ galleryFactory.value = mod.imageGallerySource;
120
+ Viewer.value = mod.CoarDocumentViewer;
121
+ });
122
+ </script>
123
+
124
+ <style scoped>
125
+ .dv-loading {
126
+ height: 100%;
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ color: var(--coar-text-neutral-tertiary, #6b7280);
131
+ font-size: 13px;
132
+ }
133
+ </style>
134
+ ```
135
+
136
+ Pages can mix orientations (landscape page 1, portrait page 2, wide page 3 above). Every page's intrinsic dimensions are read from its own image, so the viewer never letter-boxes or stretches. Sidebar thumbnails track the active page.
137
+
138
+ ## PDF source
139
+
140
+ The PDF demo runs in the playground at [`localhost:5188/pdf-viewer`](http://localhost:5188/pdf-viewer) — it's omitted here because the pdfjs worker has to be configured by the consumer (one-line setup, below).
141
+
142
+ ```vue
143
+ <script setup lang="ts">
144
+ import { computed } from 'vue';
145
+ import { CoarDocumentViewer } from '@cocoar/vue-document-viewer';
146
+ import { pdfSource } from '@cocoar/vue-document-viewer/pdf';
147
+ import '@cocoar/vue-document-viewer/styles';
148
+
149
+ const source = computed(() => pdfSource({
150
+ url: '/api/files/contract.pdf',
151
+ withCredentials: true, // forward cookies / HTTP auth
152
+ headers: { 'X-Tenant': 'acme' }, // arbitrary request headers
153
+ }));
154
+ </script>
155
+
156
+ <template>
157
+ <CoarDocumentViewer
158
+ :source="source"
159
+ :show-thumbnails="true"
160
+ :show-outline="true"
161
+ :show-annotations-panel="true"
162
+ :show-print-download="true"
163
+ />
164
+ </template>
165
+ ```
166
+
167
+ ### Worker setup (PDF consumers only)
168
+
169
+ pdfjs needs a worker to parse the binary off the main thread. Wire it once at app bootstrap — Vite/webpack/Rollup all support the `?worker` query:
170
+
171
+ ```ts
172
+ // main.ts
173
+ import * as pdfjs from 'pdfjs-dist';
174
+ import PdfWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?worker';
175
+
176
+ pdfjs.GlobalWorkerOptions.workerPort = new PdfWorker();
177
+ ```
178
+
179
+ If you skip this step, pdfjs will try to fetch the worker over the network and fall back to a slow inline mode — both viable, but not what you want in production.
180
+
181
+ ## Source capabilities
182
+
183
+ Every source advertises what it can do. The toolbar reads these flags to enable/disable individual tools; consumers can inspect them too:
184
+
185
+ ```ts
186
+ interface DocumentSourceCapabilities {
187
+ multiPage: boolean; // Prev / Next / page input
188
+ textLayer: boolean; // Text selection, Ctrl+C copy
189
+ search: boolean; // Search button
190
+ outline: boolean; // Outline (TOC) sidebar tab
191
+ print: boolean; // Print button
192
+ }
193
+ ```
194
+
195
+ The factories pre-populate the right values: PDFs get all-true, images get a single-page no-text profile, galleries get the same with `multiPage: true`. Adding a future source kind (e.g. OCR'd images) is a matter of providing a new factory that flips the relevant flags.
196
+
197
+ > **Tip: Why disabled, not hidden?**
198
+ >
199
+ > Tools that vanish when the source changes make the toolbar layout shift — buttons jump positions, muscle memory breaks. Greying out keeps positions stable and surfaces the capability constraint to the user via tooltip.
200
+
201
+ ## Info panel
202
+
203
+ When the right-side annotations panel is open, a collapsible **Info** section at the top surfaces source metadata:
204
+
205
+ - Format string (`"PDF · v1.7"`, `"Image · PNG"`, `"Image gallery · SVG"`)
206
+ - Total page count
207
+ - Current page dimensions (live — updates as the user flips pages)
208
+ - PDF-only fields: title / author / subject / keywords / creator / producer / created / modified / PDF version (empty fields are skipped)
209
+ - File size in bytes (PDFs only — pdfjs exposes `contentLength`)
210
+
211
+ Disable with `:show-info-section="false"` if you want a minimal annotations-only panel.
212
+
213
+ ## Architecture
214
+
215
+ ```
216
+ <CoarDocumentViewer :source="…">
217
+ useDocumentLoader(sourceRef) ← internal dispatcher, watches source.kind
218
+ usePdfDocumentAdapter(pdfSourceRef)
219
+ useImageDocumentAdapter(imgSourceRef)
220
+ useImageGalleryAdapter(gallerySourceRef)
221
+ each publishes { status, pageProviders, info, error, retry, destroy }
222
+ usePageRenderer({ pageProviders, … }) ← source-agnostic, owns canvas + textLayer DOM
223
+ DocumentToolbar, DocumentSidebar, DocumentAnnotationPanel, DocumentSearchBar
224
+ ```
225
+
226
+ The seam between formats is `PageProvider` — every page (PDF page proxy, image element, future kinds) materializes through the same interface (`render(canvas, opts)`, `cancel()`, optional `getTextLayer()`). The renderer never imports `pdfjs-dist`.
227
+
228
+ ## What's next
229
+
230
+ | Page | Covers |
231
+ |------|--------|
232
+ | [CoarDocumentViewer](./coar-document-viewer.md) | Full props / emits / slots reference, labels, position memory |
233
+ | [Toolbar customization](./toolbar.md) | Order-driven `tools` array, separator pseudo-tool, section toggles |
234
+ | [Annotations](./annotations.md) | Modes, types, lifecycle events, schema, color picker |