@cocoar/vue-ui 3.2.0-beta.5 → 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 (110) hide show
  1. package/package.json +5 -3
  2. package/skills/cocoar-vue-ui/SKILL.md +244 -0
  3. package/skills/cocoar-vue-ui/references/components/avatar.md +178 -0
  4. package/skills/cocoar-vue-ui/references/components/badge.md +290 -0
  5. package/skills/cocoar-vue-ui/references/components/breadcrumb.md +238 -0
  6. package/skills/cocoar-vue-ui/references/components/button.md +252 -0
  7. package/skills/cocoar-vue-ui/references/components/calendar/agenda-view.md +353 -0
  8. package/skills/cocoar-vue-ui/references/components/calendar/coar-calendar.md +1645 -0
  9. package/skills/cocoar-vue-ui/references/components/calendar/day-view.md +361 -0
  10. package/skills/cocoar-vue-ui/references/components/calendar/index.md +312 -0
  11. package/skills/cocoar-vue-ui/references/components/calendar/month-view.md +475 -0
  12. package/skills/cocoar-vue-ui/references/components/calendar/performance.md +186 -0
  13. package/skills/cocoar-vue-ui/references/components/calendar/timeline-view.md +301 -0
  14. package/skills/cocoar-vue-ui/references/components/calendar/week-view.md +382 -0
  15. package/skills/cocoar-vue-ui/references/components/calendar/work-week-view.md +145 -0
  16. package/skills/cocoar-vue-ui/references/components/calendar/year-view.md +63 -0
  17. package/skills/cocoar-vue-ui/references/components/card.md +151 -0
  18. package/skills/cocoar-vue-ui/references/components/checkbox-group.md +103 -0
  19. package/skills/cocoar-vue-ui/references/components/checkbox.md +279 -0
  20. package/skills/cocoar-vue-ui/references/components/code-block.md +241 -0
  21. package/skills/cocoar-vue-ui/references/components/context-menu.md +355 -0
  22. package/skills/cocoar-vue-ui/references/components/data-grid/checkbox.md +213 -0
  23. package/skills/cocoar-vue-ui/references/components/data-grid/date-columns.md +272 -0
  24. package/skills/cocoar-vue-ui/references/components/data-grid/editing.md +236 -0
  25. package/skills/cocoar-vue-ui/references/components/data-grid/multi-select.md +193 -0
  26. package/skills/cocoar-vue-ui/references/components/data-grid/number.md +147 -0
  27. package/skills/cocoar-vue-ui/references/components/data-grid/select.md +202 -0
  28. package/skills/cocoar-vue-ui/references/components/data-grid/text.md +127 -0
  29. package/skills/cocoar-vue-ui/references/components/data-grid.md +1225 -0
  30. package/skills/cocoar-vue-ui/references/components/data-list.md +2121 -0
  31. package/skills/cocoar-vue-ui/references/components/date-or-time-picker.md +200 -0
  32. package/skills/cocoar-vue-ui/references/components/date-picker.md +203 -0
  33. package/skills/cocoar-vue-ui/references/components/date-time-picker.md +154 -0
  34. package/skills/cocoar-vue-ui/references/components/date-views.md +212 -0
  35. package/skills/cocoar-vue-ui/references/components/dialog.md +148 -0
  36. package/skills/cocoar-vue-ui/references/components/divider.md +157 -0
  37. package/skills/cocoar-vue-ui/references/components/document-viewer/annotations.md +400 -0
  38. package/skills/cocoar-vue-ui/references/components/document-viewer/coar-document-viewer.md +327 -0
  39. package/skills/cocoar-vue-ui/references/components/document-viewer/index.md +234 -0
  40. package/skills/cocoar-vue-ui/references/components/document-viewer/toolbar.md +221 -0
  41. package/skills/cocoar-vue-ui/references/components/drag-drop.md +267 -0
  42. package/skills/cocoar-vue-ui/references/components/dual-listbox.md +449 -0
  43. package/skills/cocoar-vue-ui/references/components/file-explorer/asset-store.md +327 -0
  44. package/skills/cocoar-vue-ui/references/components/file-explorer/in-memory-store.md +176 -0
  45. package/skills/cocoar-vue-ui/references/components/file-explorer/index.md +311 -0
  46. package/skills/cocoar-vue-ui/references/components/file-explorer/use-file-explorer.md +300 -0
  47. package/skills/cocoar-vue-ui/references/components/form-field.md +1025 -0
  48. package/skills/cocoar-vue-ui/references/components/fragment-parser.md +298 -0
  49. package/skills/cocoar-vue-ui/references/components/link.md +235 -0
  50. package/skills/cocoar-vue-ui/references/components/listbox.md +575 -0
  51. package/skills/cocoar-vue-ui/references/components/map/editor.md +448 -0
  52. package/skills/cocoar-vue-ui/references/components/map/index.md +351 -0
  53. package/skills/cocoar-vue-ui/references/components/markdown-diagrams.md +210 -0
  54. package/skills/cocoar-vue-ui/references/components/markdown-editor.md +1478 -0
  55. package/skills/cocoar-vue-ui/references/components/markdown-embeds.md +387 -0
  56. package/skills/cocoar-vue-ui/references/components/markdown-form.md +447 -0
  57. package/skills/cocoar-vue-ui/references/components/markdown.md +276 -0
  58. package/skills/cocoar-vue-ui/references/components/menu.md +380 -0
  59. package/skills/cocoar-vue-ui/references/components/mermaid.md +172 -0
  60. package/skills/cocoar-vue-ui/references/components/navbar.md +147 -0
  61. package/skills/cocoar-vue-ui/references/components/note.md +96 -0
  62. package/skills/cocoar-vue-ui/references/components/notice.md +131 -0
  63. package/skills/cocoar-vue-ui/references/components/number-input.md +215 -0
  64. package/skills/cocoar-vue-ui/references/components/otp-input.md +324 -0
  65. package/skills/cocoar-vue-ui/references/components/page-builder/authoring-contract.md +271 -0
  66. package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-builder.md +476 -0
  67. package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-renderer.md +677 -0
  68. package/skills/cocoar-vue-ui/references/components/page-builder/custom-elements.md +441 -0
  69. package/skills/cocoar-vue-ui/references/components/page-builder/idp-integration.md +122 -0
  70. package/skills/cocoar-vue-ui/references/components/page-builder/index.md +573 -0
  71. package/skills/cocoar-vue-ui/references/components/pagination.md +150 -0
  72. package/skills/cocoar-vue-ui/references/components/panel-layout.md +372 -0
  73. package/skills/cocoar-vue-ui/references/components/password-input.md +175 -0
  74. package/skills/cocoar-vue-ui/references/components/popconfirm.md +186 -0
  75. package/skills/cocoar-vue-ui/references/components/popover.md +173 -0
  76. package/skills/cocoar-vue-ui/references/components/progress-bar.md +178 -0
  77. package/skills/cocoar-vue-ui/references/components/radio-group.md +225 -0
  78. package/skills/cocoar-vue-ui/references/components/script-editor.md +1271 -0
  79. package/skills/cocoar-vue-ui/references/components/segmented-control.md +238 -0
  80. package/skills/cocoar-vue-ui/references/components/select.md +463 -0
  81. package/skills/cocoar-vue-ui/references/components/sidebar.md +421 -0
  82. package/skills/cocoar-vue-ui/references/components/spinner.md +132 -0
  83. package/skills/cocoar-vue-ui/references/components/switch.md +195 -0
  84. package/skills/cocoar-vue-ui/references/components/table.md +170 -0
  85. package/skills/cocoar-vue-ui/references/components/tabs.md +382 -0
  86. package/skills/cocoar-vue-ui/references/components/tag.md +178 -0
  87. package/skills/cocoar-vue-ui/references/components/text-input.md +256 -0
  88. package/skills/cocoar-vue-ui/references/components/toast.md +160 -0
  89. package/skills/cocoar-vue-ui/references/components/tooltip.md +121 -0
  90. package/skills/cocoar-vue-ui/references/components/transitions.md +193 -0
  91. package/skills/cocoar-vue-ui/references/components/tree.md +2388 -0
  92. package/skills/cocoar-vue-ui/references/components/virtual-list.md +212 -0
  93. package/skills/cocoar-vue-ui/references/components/wizard.md +251 -0
  94. package/skills/cocoar-vue-ui/references/components/zoned-date-time-picker.md +177 -0
  95. package/skills/cocoar-vue-ui/references/foundations/colors.md +708 -0
  96. package/skills/cocoar-vue-ui/references/foundations/design-principles.md +115 -0
  97. package/skills/cocoar-vue-ui/references/foundations/icons.md +381 -0
  98. package/skills/cocoar-vue-ui/references/foundations/localization/formatting.md +530 -0
  99. package/skills/cocoar-vue-ui/references/foundations/localization/setup.md +86 -0
  100. package/skills/cocoar-vue-ui/references/foundations/localization/timezones.md +182 -0
  101. package/skills/cocoar-vue-ui/references/foundations/localization/translations.md +305 -0
  102. package/skills/cocoar-vue-ui/references/foundations/motion.md +549 -0
  103. package/skills/cocoar-vue-ui/references/foundations/spacing.md +330 -0
  104. package/skills/cocoar-vue-ui/references/foundations/theming.md +140 -0
  105. package/skills/cocoar-vue-ui/references/foundations/typography.md +206 -0
  106. package/skills/cocoar-vue-ui/references/guide/error-handling.md +162 -0
  107. package/skills/cocoar-vue-ui/references/guide/getting-started.md +119 -0
  108. package/skills/cocoar-vue-ui/references/guide/migration-page-builder-3.md +207 -0
  109. package/skills/cocoar-vue-ui/references/guide/migration.md +140 -0
  110. package/skills/cocoar-vue-ui/references/guide/theming.md +98 -0
@@ -0,0 +1,150 @@
1
+ <!-- Generated from apps/docs/components/pagination.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
2
+
3
+ # Pagination
4
+
5
+ Split large collections into digestible pages and let users navigate between them. Pagination automatically calculates page count from `totalItems` and `pageSize`, and intelligently truncates the page range with ellipses when there are too many pages to display at once.
6
+
7
+ ```ts
8
+ import { CoarPagination } from '@cocoar/vue-ui';
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ Bind a reactive page number with `v-model`. This example paginates 100 items at 10 per page, yielding 10 pages.
14
+
15
+ **Demo — `pagination/demos/PaginationBasic.vue`**
16
+
17
+ ```vue
18
+ <template>
19
+ <div>
20
+ <CoarPagination v-model="page" :total-items="100" :page-size="10" />
21
+ <p style="margin-top: 8px; font-size: 13px; color: var(--coar-text-neutral-secondary);">Current page: {{ page }}</p>
22
+ </div>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import { ref } from 'vue';
27
+ import { CoarPagination } from '@cocoar/vue-ui';
28
+
29
+ const page = ref(1);
30
+ </script>
31
+ ```
32
+
33
+ ## Different Page Size
34
+
35
+ Adjust `totalItems` and `pageSize` to match your data. Here, 500 items at 25 per page produces 20 pages.
36
+
37
+ **Demo — `pagination/demos/PaginationPageSize.vue`**
38
+
39
+ ```vue
40
+ <template>
41
+ <div>
42
+ <CoarPagination v-model="page" :total-items="500" :page-size="25" />
43
+ <p style="margin-top: 8px; font-size: 13px; color: var(--coar-text-neutral-secondary);">Current page: {{ page }} / 20</p>
44
+ </div>
45
+ </template>
46
+
47
+ <script setup lang="ts">
48
+ import { ref } from 'vue';
49
+ import { CoarPagination } from '@cocoar/vue-ui';
50
+
51
+ const page = ref(3);
52
+ </script>
53
+ ```
54
+
55
+ ## Large Dataset
56
+
57
+ With 10,000 items, the page count reaches 1,000. The component automatically shows ellipsis markers so the control stays compact no matter how many pages exist.
58
+
59
+ **Demo — `pagination/demos/PaginationLarge.vue`**
60
+
61
+ ```vue
62
+ <template>
63
+ <div>
64
+ <CoarPagination v-model="page" :total-items="10000" :page-size="10" />
65
+ <p style="margin-top: 8px; font-size: 13px; color: var(--coar-text-neutral-secondary);">Current page: {{ page }} / 1000</p>
66
+ </div>
67
+ </template>
68
+
69
+ <script setup lang="ts">
70
+ import { ref } from 'vue';
71
+ import { CoarPagination } from '@cocoar/vue-ui';
72
+
73
+ const page = ref(1);
74
+ </script>
75
+ ```
76
+
77
+ ## With Table
78
+
79
+ The most common real-world pattern: pair pagination with a data table. A summary line shows the visible row range, and page controls sit alongside it in the table footer.
80
+
81
+ **Demo — `pagination/demos/PaginationTable.vue`**
82
+
83
+ ```vue
84
+ <template>
85
+ <div style="display: flex; flex-direction: column; gap: 16px;">
86
+ <table style="width: 100%; border-collapse: collapse; font-size: 13px;">
87
+ <thead>
88
+ <tr>
89
+ <th style="padding: 6px 12px; text-align: left; border-bottom: 1px solid var(--coar-border-neutral-secondary); font-weight: 600; color: var(--coar-text-neutral-secondary); background: var(--coar-background-neutral-secondary);">Name</th>
90
+ <th style="padding: 6px 12px; text-align: left; border-bottom: 1px solid var(--coar-border-neutral-secondary); font-weight: 600; color: var(--coar-text-neutral-secondary); background: var(--coar-background-neutral-secondary);">Email</th>
91
+ <th style="padding: 6px 12px; text-align: left; border-bottom: 1px solid var(--coar-border-neutral-secondary); font-weight: 600; color: var(--coar-text-neutral-secondary); background: var(--coar-background-neutral-secondary);">Role</th>
92
+ </tr>
93
+ </thead>
94
+ <tbody>
95
+ <tr v-for="i in 5" :key="i">
96
+ <td style="padding: 6px 12px; border-bottom: 1px solid var(--coar-border-neutral-secondary);">User {{ (page - 1) * 5 + i }}</td>
97
+ <td style="padding: 6px 12px; border-bottom: 1px solid var(--coar-border-neutral-secondary);">user{{ (page - 1) * 5 + i }}@example.com</td>
98
+ <td style="padding: 6px 12px; border-bottom: 1px solid var(--coar-border-neutral-secondary);">{{ i % 2 === 0 ? 'Admin' : 'User' }}</td>
99
+ </tr>
100
+ </tbody>
101
+ </table>
102
+ <div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px;">
103
+ <span style="font-size: 13px; color: var(--coar-text-neutral-secondary);">
104
+ Showing {{ (page - 1) * 5 + 1 }}&ndash;{{ Math.min(page * 5, 100) }} of 100
105
+ </span>
106
+ <CoarPagination v-model="page" :total-items="100" :page-size="5" />
107
+ </div>
108
+ </div>
109
+ </template>
110
+
111
+ <script setup lang="ts">
112
+ import { ref } from 'vue';
113
+ import { CoarPagination } from '@cocoar/vue-ui';
114
+
115
+ const page = ref(1);
116
+ </script>
117
+ ```
118
+
119
+ ## API
120
+
121
+ ### Props
122
+
123
+ | Prop | Type | Default | Description |
124
+ |------|------|---------|-------------|
125
+ | `v-model` | `number` | `1` | Current active page (1-indexed) |
126
+ | `totalItems` | `number` | — | Total number of items (**required**) |
127
+ | `pageSize` | `number` | `10` | Items per page |
128
+ | `maxVisiblePages` | `number` | `5` | Maximum visible page buttons |
129
+ | `showFirstLast` | `boolean` | `true` | Show first/last page nav buttons |
130
+ | `disabled` | `boolean` | `false` | Disable the pagination control |
131
+
132
+ ### Events
133
+
134
+ | Event | Payload | Description |
135
+ |-------|---------|-------------|
136
+ | `pageChanged` | `number` | Emitted when the page changes |
137
+
138
+ ## i18n Keys
139
+
140
+ These keys can be translated via [`@cocoar/vue-localization`](../foundations/localization/translations.md).
141
+
142
+ | Key | Default (English) | Used as |
143
+ |-----|-------------------|---------|
144
+ | `coar.ui.pagination.firstPage` | `'Go to first page'` | First page button `aria-label` |
145
+ | `coar.ui.pagination.previousPage` | `'Go to previous page'` | Previous page button `aria-label` |
146
+ | `coar.ui.pagination.nextPage` | `'Go to next page'` | Next page button `aria-label` |
147
+ | `coar.ui.pagination.lastPage` | `'Go to last page'` | Last page button `aria-label` |
148
+ | `coar.ui.pagination.morePage` | `'More pages'` | Ellipsis separator `aria-label` |
149
+ | `coar.ui.pagination.goToPage` | `'Go to page {page}'` | Page number button `aria-label` — `{page}` is replaced with the page number |
150
+ | `coar.ui.pagination.nav` | `'Pagination'` | Nav element `aria-label` |
@@ -0,0 +1,372 @@
1
+ <!-- Generated from apps/docs/components/panel-layout.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
2
+
3
+ # Panel Layout (Preview)
4
+
5
+ A VS-Code-style workbench: named, resizable regions you fill with whatever you like. Two pieces:
6
+
7
+ - **`CoarSplitPane`** — the primitive: two panes with a draggable divider. Nestable.
8
+ - **`CoarPanelLayout`** — a ready-made shell with `top / left / content / right / bottom / status` regions, built on `CoarSplitPane` so every divider feels identical.
9
+
10
+ ```ts
11
+ import { CoarSplitPane, CoarPanelLayout } from '@cocoar/vue-ui';
12
+ ```
13
+
14
+ The layout owns the arrangement and the drag-to-resize; **you own the contents** of every slot. Resizing works by pointer drag or arrow keys (the dividers are real `role="separator"` widgets).
15
+
16
+ ## Split pane
17
+
18
+ `CoarSplitPane` lays out two slots — `#first` and `#second` — with a divider between them. The `side` pane carries a controlled px `size` (`v-model:size`); the other flexes. `direction="row"` gives a vertical divider (left/right); `direction="column"` gives a horizontal one (top/bottom).
19
+
20
+ **Demo — `panel-layout/demos/SplitPaneBasic.vue`**
21
+
22
+ ```vue
23
+ <template>
24
+ <div class="sp-frame">
25
+ <CoarSplitPane v-model:size="size" :min="120" :max="420">
26
+ <template #first>
27
+ <div class="sp-pane sp-pane--a">
28
+ <strong>Sidebar</strong>
29
+ <span>{{ size }}px — drag the divider →</span>
30
+ </div>
31
+ </template>
32
+ <template #second>
33
+ <div class="sp-pane sp-pane--b">
34
+ <strong>Content</strong>
35
+ <span>flexes to fill the rest</span>
36
+ </div>
37
+ </template>
38
+ </CoarSplitPane>
39
+ </div>
40
+ </template>
41
+
42
+ <script setup lang="ts">
43
+ import { ref } from 'vue';
44
+ import { CoarSplitPane } from '@cocoar/vue-ui';
45
+
46
+ const size = ref(200);
47
+ </script>
48
+
49
+ <style scoped>
50
+ .sp-frame {
51
+ height: 220px;
52
+ border: 1px solid var(--vp-c-divider);
53
+ border-radius: 8px;
54
+ overflow: hidden;
55
+ }
56
+ .sp-pane {
57
+ height: 100%;
58
+ display: flex;
59
+ flex-direction: column;
60
+ gap: 4px;
61
+ align-items: center;
62
+ justify-content: center;
63
+ font-size: 13px;
64
+ }
65
+ .sp-pane span {
66
+ font-size: 12px;
67
+ color: var(--coar-text-neutral-tertiary, #6b7280);
68
+ }
69
+ .sp-pane--a {
70
+ background: var(--vp-c-bg-soft);
71
+ }
72
+ .sp-pane--b {
73
+ background: var(--vp-c-bg);
74
+ }
75
+ </style>
76
+ ```
77
+
78
+ ```vue
79
+ <CoarSplitPane v-model:size="width" :min="120" :max="420">
80
+ <template #first>…sidebar…</template>
81
+ <template #second>…content…</template>
82
+ </CoarSplitPane>
83
+ ```
84
+
85
+ | Prop | Default | Notes |
86
+ |---|---|---|
87
+ | `direction` | `'row'` | `'row'` = side by side (vertical divider); `'column'` = stacked (horizontal divider). |
88
+ | `side` | `'first'` | Which pane carries the controlled `size`. Use `'second'` for a right sidebar or bottom panel. |
89
+ | `size` (`v-model`) | — | Controlled px size of the `side` pane. Omit for uncontrolled (seeded by `defaultSize`). |
90
+ | `defaultSize` | `240` | Initial size when uncontrolled. |
91
+ | `min` / `max` | `0` / `∞` | Clamp for the `side` pane (also clamped to the container). |
92
+ | `resizable` | `true` | `false` hides the divider and fixes the split. |
93
+
94
+ Panes clip overflow (`overflow: hidden`) — put a scroll container inside if the content can exceed the pane.
95
+
96
+ ## Workbench
97
+
98
+ `CoarPanelLayout` arranges the canonical regions. An **empty slot renders no region** (and no divider), so you take only what you need; `#default` (content) always fills the centre. Sidebars and the bottom panel are resizable and collapsible (`:left-open` …). Toggle the buttons and drag the dividers:
99
+
100
+ **Demo — `panel-layout/demos/PanelLayoutWorkbench.vue`**
101
+
102
+ ```vue
103
+ <template>
104
+ <div class="wb-frame">
105
+ <CoarPanelLayout
106
+ v-model:left-width="leftW"
107
+ v-model:right-width="rightW"
108
+ v-model:bottom-height="botH"
109
+ :left-open="leftOpen"
110
+ :right-open="rightOpen"
111
+ :bottom-open="botOpen"
112
+ :left-min="160"
113
+ :left-max="360"
114
+ :right-min="140"
115
+ :right-max="320"
116
+ :bottom-min="60"
117
+ :bottom-max="220"
118
+ >
119
+ <template #top>
120
+ <div class="wb-bar">
121
+ <strong>Workbench</strong>
122
+ <span class="wb-spacer" />
123
+ <button class="wb-btn" :class="{ 'wb-btn--on': leftOpen }" @click="leftOpen = !leftOpen">Left</button>
124
+ <button class="wb-btn" :class="{ 'wb-btn--on': botOpen }" @click="botOpen = !botOpen">Bottom</button>
125
+ <button class="wb-btn" :class="{ 'wb-btn--on': rightOpen }" @click="rightOpen = !rightOpen">Right</button>
126
+ </div>
127
+ </template>
128
+
129
+ <template #left>
130
+ <!-- left sidebar = vertical split: tree (top) + details (bottom) -->
131
+ <CoarSplitPane direction="column" side="second" v-model:size="detailsH" :min="64" :max="220">
132
+ <template #first>
133
+ <section class="wb-pane">
134
+ <header class="wb-title">Explorer</header>
135
+ <div class="wb-body wb-scroll">
136
+ <CoarTree
137
+ :nodes="nodes"
138
+ :get-id="(n) => n.id"
139
+ :get-children="(n) => n.children"
140
+ :get-label="(n) => n.name"
141
+ :is-expandable="(n) => !!n.children"
142
+ v-model:expanded="expanded"
143
+ v-model:selected="selected"
144
+ >
145
+ <template #default="{ node }">
146
+ <CoarTreeNodeLabel :label="node.name" />
147
+ </template>
148
+ </CoarTree>
149
+ </div>
150
+ </section>
151
+ </template>
152
+ <template #second>
153
+ <section class="wb-pane">
154
+ <header class="wb-title">Details</header>
155
+ <div class="wb-body">
156
+ <p class="wb-muted">Selected: <strong>{{ selectedName }}</strong></p>
157
+ </div>
158
+ </section>
159
+ </template>
160
+ </CoarSplitPane>
161
+ </template>
162
+
163
+ <template #default>
164
+ <div class="wb-content">Content / editor area</div>
165
+ </template>
166
+
167
+ <template #right>
168
+ <section class="wb-pane">
169
+ <header class="wb-title">Outline</header>
170
+ <div class="wb-body"><p class="wb-muted">Any panel you like.</p></div>
171
+ </section>
172
+ </template>
173
+
174
+ <template #bottom>
175
+ <section class="wb-pane">
176
+ <header class="wb-title">Problems</header>
177
+ <div class="wb-body"><p class="wb-muted">No problems detected.</p></div>
178
+ </section>
179
+ </template>
180
+
181
+ <template #status>
182
+ <div class="wb-status"><span>Ready</span><span class="wb-spacer" /><span>UTF-8</span></div>
183
+ </template>
184
+ </CoarPanelLayout>
185
+ </div>
186
+ </template>
187
+
188
+ <script setup lang="ts">
189
+ import { computed, ref } from 'vue';
190
+ import { CoarPanelLayout, CoarSplitPane, CoarTree, CoarTreeNodeLabel } from '@cocoar/vue-ui';
191
+
192
+ interface Node {
193
+ id: string;
194
+ name: string;
195
+ children?: Node[];
196
+ }
197
+
198
+ const nodes: Node[] = [
199
+ {
200
+ id: 'src',
201
+ name: 'src',
202
+ children: [
203
+ { id: 'app', name: 'App.vue' },
204
+ { id: 'main', name: 'main.ts' },
205
+ ],
206
+ },
207
+ { id: 'readme', name: 'README.md' },
208
+ ];
209
+
210
+ const expanded = ref(new Set<string>(['src']));
211
+ const selected = ref<string | null>('app');
212
+ const selectedName = computed(() => {
213
+ const find = (list: Node[]): Node | undefined =>
214
+ list.flatMap((n) => [n, ...(n.children ?? [])]).find((n) => n.id === selected.value);
215
+ return find(nodes)?.name ?? 'nothing';
216
+ });
217
+
218
+ // Layout state — consumer-owned.
219
+ const leftW = ref(220);
220
+ const rightW = ref(180);
221
+ const botH = ref(110);
222
+ const detailsH = ref(96);
223
+ const leftOpen = ref(true);
224
+ const rightOpen = ref(true);
225
+ const botOpen = ref(true);
226
+ </script>
227
+
228
+ <style scoped>
229
+ .wb-frame {
230
+ height: 420px;
231
+ border: 1px solid var(--vp-c-divider);
232
+ border-radius: 8px;
233
+ overflow: hidden;
234
+ font-size: 13px;
235
+ }
236
+ .wb-bar,
237
+ .wb-status {
238
+ display: flex;
239
+ align-items: center;
240
+ gap: 8px;
241
+ padding: 0 12px;
242
+ background: var(--vp-c-bg-soft);
243
+ }
244
+ .wb-bar {
245
+ height: 40px;
246
+ border-bottom: 1px solid var(--vp-c-divider);
247
+ }
248
+ .wb-status {
249
+ height: 26px;
250
+ border-top: 1px solid var(--vp-c-divider);
251
+ font-size: 11px;
252
+ color: var(--coar-text-neutral-tertiary, #6b7280);
253
+ }
254
+ .wb-spacer {
255
+ flex: 1;
256
+ }
257
+ .wb-btn {
258
+ height: 24px;
259
+ padding: 0 10px;
260
+ border: 1px solid var(--vp-c-divider);
261
+ border-radius: 4px;
262
+ background: var(--vp-c-bg);
263
+ color: var(--coar-text-neutral-secondary, #475569);
264
+ font-size: 12px;
265
+ cursor: pointer;
266
+ }
267
+ .wb-btn--on {
268
+ background: var(--coar-color-accent, #3b82f6);
269
+ border-color: var(--coar-color-accent, #3b82f6);
270
+ color: #fff;
271
+ }
272
+ .wb-pane {
273
+ display: flex;
274
+ flex-direction: column;
275
+ height: 100%;
276
+ min-height: 0;
277
+ background: var(--vp-c-bg-soft);
278
+ }
279
+ .wb-title {
280
+ flex: 0 0 auto;
281
+ height: 26px;
282
+ display: flex;
283
+ align-items: center;
284
+ padding: 0 12px;
285
+ font-size: 11px;
286
+ font-weight: 700;
287
+ letter-spacing: 0.05em;
288
+ text-transform: uppercase;
289
+ color: var(--coar-text-neutral-tertiary, #6b7280);
290
+ }
291
+ .wb-body {
292
+ flex: 1 1 0;
293
+ min-height: 0;
294
+ padding: 4px 0;
295
+ }
296
+ .wb-scroll {
297
+ overflow: auto;
298
+ }
299
+ .wb-muted {
300
+ margin: 0;
301
+ padding: 4px 12px;
302
+ color: var(--coar-text-neutral-tertiary, #6b7280);
303
+ }
304
+ .wb-content {
305
+ height: 100%;
306
+ display: flex;
307
+ align-items: center;
308
+ justify-content: center;
309
+ background: var(--vp-c-bg);
310
+ color: var(--coar-text-neutral-tertiary, #6b7280);
311
+ }
312
+ </style>
313
+ ```
314
+
315
+ ```vue
316
+ <CoarPanelLayout v-model:left-width="leftW" :left-min="160" :left-max="360">
317
+ <template #top>…toolbar…</template>
318
+ <template #left>…sidebar…</template>
319
+ <template #default>…content…</template>
320
+ <template #right>…inspector…</template>
321
+ <template #bottom>…panel…</template>
322
+ <template #status>…status bar…</template>
323
+ </CoarPanelLayout>
324
+ ```
325
+
326
+ ```
327
+ ┌───────────────────────────────────────┐
328
+ │ #top (fixed, full width) │
329
+ ├────────┬────────────────────┬──────────┤
330
+ │ #left │ #default │ #right │
331
+ │ ├────────────────────┤ │
332
+ │ │ #bottom │ │
333
+ ├────────┴────────────────────┴──────────┤
334
+ │ #status (fixed, full width) │
335
+ └───────────────────────────────────────┘
336
+ ```
337
+
338
+ | Prop | Default | Notes |
339
+ |---|---|---|
340
+ | `leftWidth` / `rightWidth` / `bottomHeight` (`v-model`) | `240` / `280` / `200` | Controlled px sizes. Two-way, so persisting them (localStorage, user prefs) is a one-liner. |
341
+ | `leftOpen` / `rightOpen` / `bottomOpen` | `true` | Collapse a region without unmounting the rest. Render your own toggle button. |
342
+ | `leftMin/Max`, `rightMin/Max`, `bottomMin/Max` | `0` / `∞` | Per-region clamps. |
343
+ | `leftResizable` / `rightResizable` / `bottomResizable` | `true` | `false` fixes that region (no divider). |
344
+ | `contentMinWidth` / `contentMinHeight` | `120` / `80` | Floor the content region keeps — sidebars / the bottom panel can never be dragged (or a shrinking window squeeze them) past it, so **content is never crushed to 0**. Set to `0` to opt out. |
345
+
346
+ The `#bottom` panel sits **under the content, between the sidebars** (VS-Code default). `#top` and `#status` are fixed-height, full-width, and not resizable. Content is **protected by default**: a divider stops before the content region would drop below `contentMinWidth` / `contentMinHeight`, and that floor also holds as the window shrinks (the over-constrained edge clips rather than collapsing the content).
347
+
348
+ ## Nesting — a panel within a region
349
+
350
+ Need a split *inside* a region — say a file tree above a details panel in the left sidebar? Nest a `CoarSplitPane`. Same divider, same behaviour:
351
+
352
+ ```vue
353
+ <CoarPanelLayout :left-width="leftW">
354
+ <template #left>
355
+ <CoarSplitPane direction="column" side="second" v-model:size="detailsHeight" :min="80">
356
+ <template #first><CoarTree … /></template> <!-- tree fills -->
357
+ <template #second>…details panel…</template> <!-- sized, draggable -->
358
+ </CoarSplitPane>
359
+ </template>
360
+ <template #default>…editor…</template>
361
+ </CoarPanelLayout>
362
+ ```
363
+
364
+ This pairs naturally with the [file explorer](./file-explorer/index.md)'s `selectedAsset` + `describeAsset` for a tree-over-details sidebar.
365
+
366
+ ## Accessibility
367
+
368
+ Each divider is a `role="separator"` with `aria-orientation`, `aria-valuenow/valuemin/valuemax`, and an `aria-label`. It's in the tab order — focus it and use **Arrow keys** to resize, **Home/End** to jump to min/max. Clicking a divider focuses it too.
369
+
370
+ ## Scope
371
+
372
+ Resize and collapse are in. Drag-to-rearrange panels, tab docking, and floating panels are intentionally **out** — compose those on top if you need them.
@@ -0,0 +1,175 @@
1
+ <!-- Generated from apps/docs/components/password-input.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
2
+
3
+ # Password Input
4
+
5
+ A text input tailored for passwords. It masks characters by default and provides a built-in eye toggle so users can temporarily reveal what they typed -- reducing frustration without sacrificing security.
6
+
7
+ ```ts
8
+ import { CoarPasswordInput } from '@cocoar/vue-ui';
9
+ ```
10
+
11
+ ## Basic Usage
12
+
13
+ Works just like a text input, but the value is masked. Click the eye icon to peek at the password.
14
+
15
+ **Demo — `password-input/demos/BasicPasswordInput.vue`**
16
+
17
+ ```vue
18
+ <template>
19
+ <div style="display: flex; flex-direction: column; gap: 12px; max-width: 320px;">
20
+ <CoarFormField label="Password">
21
+ <CoarPasswordInput
22
+ v-model="password"
23
+ placeholder="Enter your password"
24
+ />
25
+ </CoarFormField>
26
+ <span style="font-size: 13px; color: #64748b;">Length: {{ password.length }} characters</span>
27
+ </div>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { ref } from 'vue';
32
+ import { CoarPasswordInput, CoarFormField } from '@cocoar/vue-ui';
33
+
34
+ const password = ref('');
35
+ </script>
36
+ ```
37
+
38
+ ## With Validation
39
+
40
+ Wrap in `CoarFormField` to add labels, hints, and error messages. The component reads the error state from the field context automatically.
41
+
42
+ **Demo — `password-input/demos/PasswordInputValidation.vue`**
43
+
44
+ ```vue
45
+ <template>
46
+ <div style="display: flex; flex-direction: column; gap: 12px; max-width: 320px;">
47
+ <CoarFormField
48
+ label="New Password"
49
+ hint="Use a mix of letters, numbers, and symbols"
50
+ :error="password.length > 0 && password.length < 8 ? 'Password must be at least 8 characters' : ''"
51
+ required
52
+ >
53
+ <CoarPasswordInput
54
+ v-model="password"
55
+ placeholder="Min 8 characters"
56
+ :required="true"
57
+ />
58
+ </CoarFormField>
59
+ <CoarFormField
60
+ label="Confirm Password"
61
+ :error="confirm.length > 0 && confirm !== password ? 'Passwords do not match' : ''"
62
+ >
63
+ <CoarPasswordInput
64
+ v-model="confirm"
65
+ placeholder="Repeat your password"
66
+ />
67
+ </CoarFormField>
68
+ </div>
69
+ </template>
70
+
71
+ <script setup lang="ts">
72
+ import { ref } from 'vue';
73
+ import { CoarPasswordInput, CoarFormField } from '@cocoar/vue-ui';
74
+
75
+ const password = ref('');
76
+ const confirm = ref('');
77
+ </script>
78
+ ```
79
+
80
+ ## States
81
+
82
+ Use `disabled` for locked accounts or `readonly` when displaying a masked placeholder that the user cannot modify.
83
+
84
+ **Demo — `password-input/demos/PasswordInputStates.vue`**
85
+
86
+ ```vue
87
+ <template>
88
+ <div style="display: flex; flex-direction: column; gap: 12px; max-width: 320px;">
89
+ <CoarFormField label="Disabled">
90
+ <CoarPasswordInput :model-value="'secret123'" :disabled="true" />
91
+ </CoarFormField>
92
+ <CoarFormField label="Readonly">
93
+ <CoarPasswordInput :model-value="'readonly-pass'" :readonly="true" />
94
+ </CoarFormField>
95
+ </div>
96
+ </template>
97
+
98
+ <script setup lang="ts">
99
+ import { CoarPasswordInput, CoarFormField } from '@cocoar/vue-ui';
100
+ </script>
101
+ ```
102
+
103
+ ## Sizes
104
+
105
+ Four sizes to keep password fields visually consistent with the rest of your form.
106
+
107
+ **Demo — `password-input/demos/PasswordInputSizes.vue`**
108
+
109
+ ```vue
110
+ <template>
111
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px;">
112
+ <CoarFormField label="Extra Small">
113
+ <CoarPasswordInput size="xs" placeholder="xs" />
114
+ </CoarFormField>
115
+ <CoarFormField label="Small">
116
+ <CoarPasswordInput size="s" placeholder="s" />
117
+ </CoarFormField>
118
+ <CoarFormField label="Medium">
119
+ <CoarPasswordInput size="m" placeholder="m" />
120
+ </CoarFormField>
121
+ <CoarFormField label="Large">
122
+ <CoarPasswordInput size="l" placeholder="l" />
123
+ </CoarFormField>
124
+ </div>
125
+ </template>
126
+
127
+ <script setup lang="ts">
128
+ import { CoarPasswordInput, CoarFormField } from '@cocoar/vue-ui';
129
+ </script>
130
+ ```
131
+
132
+ ## Accessibility
133
+
134
+ ### Keyboard Navigation
135
+
136
+ | Key | Action |
137
+ |-----|--------|
138
+ | `Tab` | Move focus to input / toggle button |
139
+ | `Enter` / `Space` | Toggle password visibility (on eye icon) |
140
+
141
+ > **Info**
142
+ >
143
+ > The visibility toggle button has an accessible label that updates based on the current state ("Show password" / "Hide password").
144
+
145
+ ### Screen Reader Support
146
+
147
+ - Label text announces on focus
148
+ - Password visibility toggle state is communicated
149
+ - Error messages linked via `aria-describedby`
150
+ - Input type switches between `password` and `text`
151
+
152
+ ## API
153
+
154
+ ### Props
155
+
156
+ | Prop | Type | Default | Description |
157
+ |------|------|---------|-------------|
158
+ | `v-model` | `string` | `''` | Password value |
159
+ | `placeholder` | `string` | `''` | Placeholder text |
160
+ | `error` | `boolean` | `false` | Error state (auto-injected from `CoarFormField`) |
161
+ | `size` | `'xs' \| 's' \| 'm' \| 'l'` | `'m'` | Input size |
162
+ | `disabled` | `boolean` | `false` | Disable the input |
163
+ | `readonly` | `boolean` | `false` | Make read-only |
164
+ | `required` | `boolean` | `false` | Mark as required |
165
+ | `clearable` | `boolean` | `false` | Show clear button when input has value |
166
+
167
+ ## i18n Keys
168
+
169
+ These keys can be translated via [`@cocoar/vue-localization`](../foundations/localization/translations.md).
170
+
171
+ | Key | Default (English) | Used as |
172
+ |-----|-------------------|---------|
173
+ | `coar.ui.passwordInput.showPassword` | `'Show password'` | Toggle visibility button `aria-label` |
174
+ | `coar.ui.passwordInput.hidePassword` | `'Hide password'` | Toggle visibility button `aria-label` (when visible) |
175
+ | `coar.ui.passwordInput.clear` | `'Clear'` | Clear button `aria-label` |