@birdycom/omniaui-vue 0.11.0 → 0.11.2

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 (178) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +49 -49
  3. package/dist/omniaui-vue.js.map +1 -1
  4. package/package.json +69 -69
  5. package/src/blocks/OcBlockAboutTimeline.vue +44 -44
  6. package/src/blocks/OcBlockAppHeader.vue +36 -36
  7. package/src/blocks/OcBlockAppShell.vue +29 -29
  8. package/src/blocks/OcBlockAuth.vue +24 -24
  9. package/src/blocks/OcBlockAuthSplit.vue +47 -47
  10. package/src/blocks/OcBlockContactGrid.vue +53 -53
  11. package/src/blocks/OcBlockCta.vue +12 -12
  12. package/src/blocks/OcBlockDataTable.vue +27 -27
  13. package/src/blocks/OcBlockFaq.vue +49 -49
  14. package/src/blocks/OcBlockFeatures.vue +23 -23
  15. package/src/blocks/OcBlockFooter.vue +25 -25
  16. package/src/blocks/OcBlockFormPage.vue +24 -24
  17. package/src/blocks/OcBlockHero.vue +13 -13
  18. package/src/blocks/OcBlockHeroCode.vue +42 -42
  19. package/src/blocks/OcBlockHeroOrbit.vue +69 -69
  20. package/src/blocks/OcBlockHeroSplit.vue +15 -15
  21. package/src/blocks/OcBlockModuleHeader.vue +21 -21
  22. package/src/blocks/OcBlockPageHero.vue +13 -13
  23. package/src/blocks/OcBlockPortfolioGrid.vue +63 -63
  24. package/src/blocks/OcBlockPricing.vue +39 -39
  25. package/src/blocks/OcBlockProcess.vue +39 -39
  26. package/src/blocks/OcBlockProductGrid.vue +41 -41
  27. package/src/blocks/OcBlockProfileHeader.vue +50 -50
  28. package/src/blocks/OcBlockShowcase.vue +43 -43
  29. package/src/blocks/OcBlockSiteFooter.vue +54 -54
  30. package/src/blocks/OcBlockSiteHeader.vue +34 -34
  31. package/src/blocks/OcBlockSpotlight.vue +47 -47
  32. package/src/blocks/OcBlockStats.vue +17 -17
  33. package/src/blocks/OcBlockStatsCounter.vue +20 -20
  34. package/src/blocks/OcBlockTeamList.vue +53 -53
  35. package/src/blocks/OcBlockTwoFactor.vue +61 -61
  36. package/src/blocks/OcBlockWizardDialog.vue +67 -67
  37. package/src/components/OcAccordion.vue +12 -12
  38. package/src/components/OcAccordionAccent.vue +27 -27
  39. package/src/components/OcAccordionItem.vue +19 -19
  40. package/src/components/OcAffixInput.vue +40 -40
  41. package/src/components/OcAlert.vue +17 -17
  42. package/src/components/OcAlertDialog.vue +66 -66
  43. package/src/components/OcAlphaTabs.vue +54 -54
  44. package/src/components/OcAspectRatio.vue +21 -21
  45. package/src/components/OcAttachment.vue +59 -59
  46. package/src/components/OcAttachmentImage.vue +13 -13
  47. package/src/components/OcAttachmentList.vue +31 -31
  48. package/src/components/OcAttachmentThumb.vue +14 -14
  49. package/src/components/OcAvatar.vue +18 -18
  50. package/src/components/OcAvatarGroup.vue +7 -7
  51. package/src/components/OcBackLink.vue +8 -8
  52. package/src/components/OcBadge.vue +13 -13
  53. package/src/components/OcBarcodeInput.vue +51 -51
  54. package/src/components/OcBreadcrumb.vue +22 -22
  55. package/src/components/OcBrowserFrame.vue +33 -33
  56. package/src/components/OcBusyOverlay.vue +32 -32
  57. package/src/components/OcButton.vue +47 -47
  58. package/src/components/OcButtonGroup.vue +10 -10
  59. package/src/components/OcButtonGroupText.vue +7 -7
  60. package/src/components/OcCard.vue +20 -20
  61. package/src/components/OcChartLine.vue +80 -80
  62. package/src/components/OcChatComposer.vue +42 -42
  63. package/src/components/OcCheckbox.vue +26 -26
  64. package/src/components/OcChecklist.vue +29 -29
  65. package/src/components/OcCollapsible.vue +19 -19
  66. package/src/components/OcColorField.vue +15 -15
  67. package/src/components/OcColorSelect.vue +33 -33
  68. package/src/components/OcColumnMenu.vue +50 -50
  69. package/src/components/OcCommand.vue +119 -119
  70. package/src/components/OcConfirmDialog.vue +65 -65
  71. package/src/components/OcCookieConsent.vue +119 -119
  72. package/src/components/OcCopyField.vue +37 -37
  73. package/src/components/OcCounter.vue +15 -15
  74. package/src/components/OcDataTable.vue +144 -144
  75. package/src/components/OcDefinitionList.vue +35 -35
  76. package/src/components/OcDropdown.vue +23 -23
  77. package/src/components/OcDropdownItem.vue +9 -9
  78. package/src/components/OcDropdownLabel.vue +7 -7
  79. package/src/components/OcDropdownSeparator.vue +7 -7
  80. package/src/components/OcDropzone.vue +36 -36
  81. package/src/components/OcEmojiPicker.vue +45 -45
  82. package/src/components/OcEmptyState.vue +13 -13
  83. package/src/components/OcEntityCard.vue +47 -47
  84. package/src/components/OcFactList.vue +37 -37
  85. package/src/components/OcFilterCounts.vue +38 -38
  86. package/src/components/OcFlipCard.vue +36 -36
  87. package/src/components/OcFormField.vue +36 -36
  88. package/src/components/OcGreeting.vue +52 -52
  89. package/src/components/OcHeading.vue +19 -19
  90. package/src/components/OcHoverCard.vue +25 -25
  91. package/src/components/OcImageZoom.vue +39 -39
  92. package/src/components/OcInput.vue +9 -9
  93. package/src/components/OcInputGroup.vue +12 -12
  94. package/src/components/OcItem.vue +40 -40
  95. package/src/components/OcItemGroup.vue +7 -7
  96. package/src/components/OcItemSeparator.vue +7 -7
  97. package/src/components/OcKbd.vue +7 -7
  98. package/src/components/OcKbdGroup.vue +15 -15
  99. package/src/components/OcLabel.vue +10 -10
  100. package/src/components/OcLanguageSelect.vue +40 -40
  101. package/src/components/OcLauncherCard.vue +34 -34
  102. package/src/components/OcLightbox.vue +63 -63
  103. package/src/components/OcLinkArrow.vue +25 -25
  104. package/src/components/OcListToolbar.vue +44 -44
  105. package/src/components/OcMarquee.vue +36 -36
  106. package/src/components/OcMediaCard.vue +28 -28
  107. package/src/components/OcMediaRow.vue +28 -28
  108. package/src/components/OcMediaThumb.vue +38 -38
  109. package/src/components/OcMessage.vue +91 -91
  110. package/src/components/OcMessageList.vue +43 -43
  111. package/src/components/OcMessageThread.vue +155 -155
  112. package/src/components/OcModal.vue +42 -42
  113. package/src/components/OcNavmenu.vue +18 -18
  114. package/src/components/OcNavmenuList.vue +38 -38
  115. package/src/components/OcNextTeaser.vue +25 -25
  116. package/src/components/OcNumberInput.vue +47 -47
  117. package/src/components/OcOtpInput.vue +34 -34
  118. package/src/components/OcPageHeader.vue +34 -34
  119. package/src/components/OcPagination.vue +33 -33
  120. package/src/components/OcPasswordInput.vue +27 -27
  121. package/src/components/OcPasswordRequirements.vue +28 -28
  122. package/src/components/OcPhoneInput.vue +72 -72
  123. package/src/components/OcPopover.vue +25 -25
  124. package/src/components/OcPriceCard.vue +69 -69
  125. package/src/components/OcProductMark.vue +31 -31
  126. package/src/components/OcProgress.vue +21 -21
  127. package/src/components/OcProjectCard.vue +36 -36
  128. package/src/components/OcProse.vue +57 -57
  129. package/src/components/OcRadio.vue +40 -40
  130. package/src/components/OcRadioGroup.vue +32 -32
  131. package/src/components/OcRecoveryCodes.vue +55 -55
  132. package/src/components/OcScrollArea.vue +15 -15
  133. package/src/components/OcSegmented.vue +28 -28
  134. package/src/components/OcSelect.vue +21 -21
  135. package/src/components/OcSeparator.vue +18 -18
  136. package/src/components/OcSeverityCard.vue +46 -46
  137. package/src/components/OcSheet.vue +49 -49
  138. package/src/components/OcSidebarCollapsible.vue +19 -19
  139. package/src/components/OcSidebarGroup.vue +11 -11
  140. package/src/components/OcSidebarMenu.vue +7 -7
  141. package/src/components/OcSidebarMenuButton.vue +31 -31
  142. package/src/components/OcSidebarSeparator.vue +7 -7
  143. package/src/components/OcSkeleton.vue +8 -8
  144. package/src/components/OcSlider.vue +27 -27
  145. package/src/components/OcSortableRow.vue +40 -40
  146. package/src/components/OcSpinner.vue +13 -13
  147. package/src/components/OcStackCard.vue +24 -24
  148. package/src/components/OcStackList.vue +31 -31
  149. package/src/components/OcStatCard.vue +39 -39
  150. package/src/components/OcStepper.vue +34 -34
  151. package/src/components/OcSwitch.vue +15 -15
  152. package/src/components/OcTable.vue +115 -115
  153. package/src/components/OcTableActions.vue +26 -26
  154. package/src/components/OcTableCompact.vue +46 -46
  155. package/src/components/OcTabs.vue +37 -37
  156. package/src/components/OcTagInput.vue +50 -50
  157. package/src/components/OcTerminalLog.vue +50 -50
  158. package/src/components/OcTextarea.vue +9 -9
  159. package/src/components/OcThemeSwitch.vue +31 -31
  160. package/src/components/OcTimeInput.vue +50 -50
  161. package/src/components/OcTimeline.vue +36 -36
  162. package/src/components/OcToast.vue +31 -31
  163. package/src/components/OcToastContainer.vue +21 -21
  164. package/src/components/OcToggle.vue +63 -63
  165. package/src/components/OcToggleField.vue +28 -28
  166. package/src/components/OcToggleGroup.vue +40 -40
  167. package/src/components/OcTooltip.vue +8 -8
  168. package/src/components/OcTopProgress.vue +54 -54
  169. package/src/components/OcTree.vue +70 -70
  170. package/src/components/OcUpgradeBanner.vue +42 -42
  171. package/src/components/OcUser.vue +25 -25
  172. package/src/components/OcVersionBanner.vue +34 -34
  173. package/src/composables/chartLine.ts +28 -28
  174. package/src/composables/keys.ts +22 -22
  175. package/src/composables/useAttrsSplit.ts +16 -16
  176. package/src/composables/useDialog.ts +21 -21
  177. package/src/composables/useToast.ts +66 -66
  178. package/src/composables/useUid.ts +12 -12
@@ -1,115 +1,115 @@
1
- <script setup lang="ts">
2
- /**
3
- * Data table: sortable header (v-model:sort), row selection (v-model:selected), row actions, empty state,
4
- * density modifiers. Slots: `cell-<key>` (scoped: { row, value }), `actions` (scoped: { row }), `empty`.
5
- * Classes: .oc-table-wrap > .oc-table(--striped/--compact/--borderless/--sticky), .oc-table-sort,
6
- * .oc-table-actions, .oc-table-empty; aria-sort / aria-selected / data-numeric attributes.
7
- */
8
- import { computed, useSlots } from 'vue'
9
-
10
- export interface TableColumn {
11
- key: string
12
- label: string
13
- sortable?: boolean
14
- numeric?: boolean
15
- width?: string
16
- }
17
- export interface TableSort {
18
- key: string
19
- direction: 'ascending' | 'descending'
20
- }
21
-
22
- const props = withDefaults(
23
- defineProps<{
24
- columns: TableColumn[]
25
- rows: Record<string, any>[]
26
- rowKey?: string
27
- caption?: string
28
- striped?: boolean
29
- compact?: boolean
30
- borderless?: boolean
31
- sticky?: boolean
32
- selectable?: boolean
33
- actionsLabel?: string
34
- selectAllLabel?: string
35
- }>(),
36
- { rowKey: 'id', actionsLabel: 'Actions', selectAllLabel: 'Select all' },
37
- )
38
- const selected = defineModel<(string | number)[]>('selected', { default: () => [] })
39
- const sort = defineModel<TableSort | null>('sort', { default: null })
40
- const slots = useSlots()
41
-
42
- const hasActions = computed(() => !!slots.actions)
43
- const colspan = computed(() => props.columns.length + (props.selectable ? 1 : 0) + (hasActions.value ? 1 : 0))
44
- const allSelected = computed(() => props.rows.length > 0 && props.rows.every((r) => selected.value.includes(r[props.rowKey])))
45
-
46
- function toggleAll(e: Event) {
47
- selected.value = (e.target as HTMLInputElement).checked ? props.rows.map((r) => r[props.rowKey]) : []
48
- }
49
- function toggleRow(id: string | number, checked: boolean) {
50
- selected.value = checked ? [...selected.value, id] : selected.value.filter((x) => x !== id)
51
- }
52
- function ariaSort(key: string) {
53
- return sort.value?.key === key ? sort.value.direction : undefined
54
- }
55
- function toggleSort(e: Event, key: string) {
56
- e.preventDefault()
57
- const next = sort.value?.key === key && sort.value.direction === 'ascending' ? 'descending' : 'ascending'
58
- sort.value = { key, direction: next }
59
- }
60
- function rowLabel(row: Record<string, any>) {
61
- return `Select ${String(row[props.columns[0]?.key] ?? '')}`.trim()
62
- }
63
- </script>
64
-
65
- <template>
66
- <div class="oc-table-wrap">
67
- <table
68
- :class="['oc-table', striped && 'oc-table--striped', compact && 'oc-table--compact', borderless && 'oc-table--borderless', sticky && 'oc-table--sticky']"
69
- >
70
- <caption v-if="caption">{{ caption }}</caption>
71
- <thead>
72
- <tr>
73
- <th v-if="selectable" style="width: 2.5rem">
74
- <input class="oc-checkbox" type="checkbox" :checked="allSelected" :aria-label="selectAllLabel" @change="toggleAll" />
75
- </th>
76
- <th
77
- v-for="col in columns"
78
- :key="col.key"
79
- :aria-sort="ariaSort(col.key)"
80
- :data-numeric="col.numeric ? '' : undefined"
81
- :style="col.width ? { width: col.width } : undefined"
82
- >
83
- <a v-if="col.sortable" class="oc-table-sort" :href="`?sort=${col.key}`" @click="toggleSort($event, col.key)">{{ col.label }}</a>
84
- <template v-else>{{ col.label }}</template>
85
- </th>
86
- <th v-if="hasActions"><span class="oc-visually-hidden">{{ actionsLabel }}</span></th>
87
- </tr>
88
- </thead>
89
- <tbody>
90
- <tr
91
- v-for="row in rows"
92
- :key="row[rowKey]"
93
- :aria-selected="selected.includes(row[rowKey]) ? 'true' : undefined"
94
- >
95
- <td v-if="selectable">
96
- <input
97
- class="oc-checkbox"
98
- type="checkbox"
99
- :checked="selected.includes(row[rowKey])"
100
- :aria-label="rowLabel(row)"
101
- @change="toggleRow(row[rowKey], ($event.target as HTMLInputElement).checked)"
102
- />
103
- </td>
104
- <td v-for="col in columns" :key="col.key" :data-numeric="col.numeric ? '' : undefined">
105
- <slot :name="`cell-${col.key}`" :row="row" :value="row[col.key]">{{ row[col.key] }}</slot>
106
- </td>
107
- <td v-if="hasActions" class="oc-table-actions"><slot name="actions" :row="row" /></td>
108
- </tr>
109
- <tr v-if="rows.length === 0 && $slots.empty" class="oc-table-empty">
110
- <td :colspan="colspan"><slot name="empty" :row="{}" /></td>
111
- </tr>
112
- </tbody>
113
- </table>
114
- </div>
115
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Data table: sortable header (v-model:sort), row selection (v-model:selected), row actions, empty state,
4
+ * density modifiers. Slots: `cell-<key>` (scoped: { row, value }), `actions` (scoped: { row }), `empty`.
5
+ * Classes: .oc-table-wrap > .oc-table(--striped/--compact/--borderless/--sticky), .oc-table-sort,
6
+ * .oc-table-actions, .oc-table-empty; aria-sort / aria-selected / data-numeric attributes.
7
+ */
8
+ import { computed, useSlots } from 'vue'
9
+
10
+ export interface TableColumn {
11
+ key: string
12
+ label: string
13
+ sortable?: boolean
14
+ numeric?: boolean
15
+ width?: string
16
+ }
17
+ export interface TableSort {
18
+ key: string
19
+ direction: 'ascending' | 'descending'
20
+ }
21
+
22
+ const props = withDefaults(
23
+ defineProps<{
24
+ columns: TableColumn[]
25
+ rows: Record<string, any>[]
26
+ rowKey?: string
27
+ caption?: string
28
+ striped?: boolean
29
+ compact?: boolean
30
+ borderless?: boolean
31
+ sticky?: boolean
32
+ selectable?: boolean
33
+ actionsLabel?: string
34
+ selectAllLabel?: string
35
+ }>(),
36
+ { rowKey: 'id', actionsLabel: 'Actions', selectAllLabel: 'Select all' },
37
+ )
38
+ const selected = defineModel<(string | number)[]>('selected', { default: () => [] })
39
+ const sort = defineModel<TableSort | null>('sort', { default: null })
40
+ const slots = useSlots()
41
+
42
+ const hasActions = computed(() => !!slots.actions)
43
+ const colspan = computed(() => props.columns.length + (props.selectable ? 1 : 0) + (hasActions.value ? 1 : 0))
44
+ const allSelected = computed(() => props.rows.length > 0 && props.rows.every((r) => selected.value.includes(r[props.rowKey])))
45
+
46
+ function toggleAll(e: Event) {
47
+ selected.value = (e.target as HTMLInputElement).checked ? props.rows.map((r) => r[props.rowKey]) : []
48
+ }
49
+ function toggleRow(id: string | number, checked: boolean) {
50
+ selected.value = checked ? [...selected.value, id] : selected.value.filter((x) => x !== id)
51
+ }
52
+ function ariaSort(key: string) {
53
+ return sort.value?.key === key ? sort.value.direction : undefined
54
+ }
55
+ function toggleSort(e: Event, key: string) {
56
+ e.preventDefault()
57
+ const next = sort.value?.key === key && sort.value.direction === 'ascending' ? 'descending' : 'ascending'
58
+ sort.value = { key, direction: next }
59
+ }
60
+ function rowLabel(row: Record<string, any>) {
61
+ return `Select ${String(row[props.columns[0]?.key] ?? '')}`.trim()
62
+ }
63
+ </script>
64
+
65
+ <template>
66
+ <div class="oc-table-wrap">
67
+ <table
68
+ :class="['oc-table', striped && 'oc-table--striped', compact && 'oc-table--compact', borderless && 'oc-table--borderless', sticky && 'oc-table--sticky']"
69
+ >
70
+ <caption v-if="caption">{{ caption }}</caption>
71
+ <thead>
72
+ <tr>
73
+ <th v-if="selectable" style="width: 2.5rem">
74
+ <input class="oc-checkbox" type="checkbox" :checked="allSelected" :aria-label="selectAllLabel" @change="toggleAll" />
75
+ </th>
76
+ <th
77
+ v-for="col in columns"
78
+ :key="col.key"
79
+ :aria-sort="ariaSort(col.key)"
80
+ :data-numeric="col.numeric ? '' : undefined"
81
+ :style="col.width ? { width: col.width } : undefined"
82
+ >
83
+ <a v-if="col.sortable" class="oc-table-sort" :href="`?sort=${col.key}`" @click="toggleSort($event, col.key)">{{ col.label }}</a>
84
+ <template v-else>{{ col.label }}</template>
85
+ </th>
86
+ <th v-if="hasActions"><span class="oc-visually-hidden">{{ actionsLabel }}</span></th>
87
+ </tr>
88
+ </thead>
89
+ <tbody>
90
+ <tr
91
+ v-for="row in rows"
92
+ :key="row[rowKey]"
93
+ :aria-selected="selected.includes(row[rowKey]) ? 'true' : undefined"
94
+ >
95
+ <td v-if="selectable">
96
+ <input
97
+ class="oc-checkbox"
98
+ type="checkbox"
99
+ :checked="selected.includes(row[rowKey])"
100
+ :aria-label="rowLabel(row)"
101
+ @change="toggleRow(row[rowKey], ($event.target as HTMLInputElement).checked)"
102
+ />
103
+ </td>
104
+ <td v-for="col in columns" :key="col.key" :data-numeric="col.numeric ? '' : undefined">
105
+ <slot :name="`cell-${col.key}`" :row="row" :value="row[col.key]">{{ row[col.key] }}</slot>
106
+ </td>
107
+ <td v-if="hasActions" class="oc-table-actions"><slot name="actions" :row="row" /></td>
108
+ </tr>
109
+ <tr v-if="rows.length === 0 && $slots.empty" class="oc-table-empty">
110
+ <td :colspan="colspan"><slot name="empty" :row="{}" /></td>
111
+ </tr>
112
+ </tbody>
113
+ </table>
114
+ </div>
115
+ </template>
@@ -1,26 +1,26 @@
1
- <!-- File: packages/vue/src/components/OcTableActions.vue | Map: td.oc-table-actions -> icon actions (default slot) OR overflow trigger + popover menu (default slot = menu items) -->
2
- <script setup lang="ts">
3
- /**
4
- * Row actions cell. Two modes:
5
- * - no `menuLabel`: the default slot holds icon actions (`a` / `button` with class oc-table-actions-icon(--primary/--success/--destructive)).
6
- * - with `menuLabel`: a three dots trigger opens a native popover; the default slot holds `.oc-dropdown-item`s.
7
- * Classes: td.oc-table-actions(--icons), .oc-table-actions-icon, .oc-table-actions-more, .oc-dropdown-menu[popover]
8
- */
9
- import { useUid } from '../composables/useUid'
10
-
11
- defineProps<{
12
- /** Accessible name of the overflow trigger, e.g. "Actions for Ada". Turns on menu mode. */
13
- menuLabel?: string
14
- }>()
15
- const menuId = useUid('oc-table-actions-menu')
16
- </script>
17
-
18
- <template>
19
- <td :class="['oc-table-actions', !menuLabel && 'oc-table-actions--icons']">
20
- <template v-if="menuLabel">
21
- <button class="oc-table-actions-more" type="button" :popovertarget="menuId" :aria-label="menuLabel"></button>
22
- <div :id="menuId" class="oc-dropdown-menu" popover><slot /></div>
23
- </template>
24
- <slot v-else />
25
- </td>
26
- </template>
1
+ <!-- File: packages/vue/src/components/OcTableActions.vue | Map: td.oc-table-actions -> icon actions (default slot) OR overflow trigger + popover menu (default slot = menu items) -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Row actions cell. Two modes:
5
+ * - no `menuLabel`: the default slot holds icon actions (`a` / `button` with class oc-table-actions-icon(--primary/--success/--destructive)).
6
+ * - with `menuLabel`: a three dots trigger opens a native popover; the default slot holds `.oc-dropdown-item`s.
7
+ * Classes: td.oc-table-actions(--icons), .oc-table-actions-icon, .oc-table-actions-more, .oc-dropdown-menu[popover]
8
+ */
9
+ import { useUid } from '../composables/useUid'
10
+
11
+ defineProps<{
12
+ /** Accessible name of the overflow trigger, e.g. "Actions for Ada". Turns on menu mode. */
13
+ menuLabel?: string
14
+ }>()
15
+ const menuId = useUid('oc-table-actions-menu')
16
+ </script>
17
+
18
+ <template>
19
+ <td :class="['oc-table-actions', !menuLabel && 'oc-table-actions--icons']">
20
+ <template v-if="menuLabel">
21
+ <button class="oc-table-actions-more" type="button" :popovertarget="menuId" :aria-label="menuLabel"></button>
22
+ <div :id="menuId" class="oc-dropdown-menu" popover><slot /></div>
23
+ </template>
24
+ <slot v-else />
25
+ </td>
26
+ </template>
@@ -1,46 +1,46 @@
1
- <!-- File: packages/vue/src/components/OcTableCompact.vue | Map: wrapper div -> table.oc-table (thead from columns, tbody from rows, tfoot from footer) OR default slot -->
2
- <script setup lang="ts">
3
- /**
4
- * Small striped table for inside cards. Pass `columns` + `rows` (+ `footer` total row), or put your own
5
- * <table class="oc-table"> in the default slot. Scoped slot `cell` ({ row, column }) customises body cells.
6
- * Classes: .oc-table-compact(--bordered/--plain), .oc-table-compact-muted, [data-numeric], [data-wrap]
7
- */
8
- export interface TableCompactColumn {
9
- key: string
10
- label: string
11
- numeric?: boolean
12
- wrap?: boolean
13
- }
14
-
15
- withDefaults(
16
- defineProps<{
17
- columns?: TableCompactColumn[]
18
- rows?: Array<Record<string, unknown>>
19
- footer?: Record<string, unknown>
20
- bordered?: boolean
21
- plain?: boolean
22
- }>(),
23
- { rows: () => [] },
24
- )
25
- // data-* attributes only when switched on (an empty string means "present").
26
- const cellAttrs = (c: TableCompactColumn) => ({ 'data-numeric': c.numeric ? '' : undefined, 'data-wrap': c.wrap ? '' : undefined })
27
- </script>
28
-
29
- <template>
30
- <div :class="['oc-table-compact', bordered && 'oc-table-compact--bordered', plain && 'oc-table-compact--plain']">
31
- <table v-if="columns" class="oc-table">
32
- <thead>
33
- <tr><th v-for="c in columns" :key="c.key" v-bind="cellAttrs(c)">{{ c.label }}</th></tr>
34
- </thead>
35
- <tbody>
36
- <tr v-for="(row, i) in rows" :key="i">
37
- <td v-for="c in columns" :key="c.key" v-bind="cellAttrs(c)"><slot name="cell" :row="row" :column="c">{{ row[c.key] }}</slot></td>
38
- </tr>
39
- </tbody>
40
- <tfoot v-if="footer">
41
- <tr><td v-for="c in columns" :key="c.key" v-bind="cellAttrs(c)">{{ footer[c.key] }}</td></tr>
42
- </tfoot>
43
- </table>
44
- <slot v-else />
45
- </div>
46
- </template>
1
+ <!-- File: packages/vue/src/components/OcTableCompact.vue | Map: wrapper div -> table.oc-table (thead from columns, tbody from rows, tfoot from footer) OR default slot -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Small striped table for inside cards. Pass `columns` + `rows` (+ `footer` total row), or put your own
5
+ * <table class="oc-table"> in the default slot. Scoped slot `cell` ({ row, column }) customises body cells.
6
+ * Classes: .oc-table-compact(--bordered/--plain), .oc-table-compact-muted, [data-numeric], [data-wrap]
7
+ */
8
+ export interface TableCompactColumn {
9
+ key: string
10
+ label: string
11
+ numeric?: boolean
12
+ wrap?: boolean
13
+ }
14
+
15
+ withDefaults(
16
+ defineProps<{
17
+ columns?: TableCompactColumn[]
18
+ rows?: Array<Record<string, unknown>>
19
+ footer?: Record<string, unknown>
20
+ bordered?: boolean
21
+ plain?: boolean
22
+ }>(),
23
+ { rows: () => [] },
24
+ )
25
+ // data-* attributes only when switched on (an empty string means "present").
26
+ const cellAttrs = (c: TableCompactColumn) => ({ 'data-numeric': c.numeric ? '' : undefined, 'data-wrap': c.wrap ? '' : undefined })
27
+ </script>
28
+
29
+ <template>
30
+ <div :class="['oc-table-compact', bordered && 'oc-table-compact--bordered', plain && 'oc-table-compact--plain']">
31
+ <table v-if="columns" class="oc-table">
32
+ <thead>
33
+ <tr><th v-for="c in columns" :key="c.key" v-bind="cellAttrs(c)">{{ c.label }}</th></tr>
34
+ </thead>
35
+ <tbody>
36
+ <tr v-for="(row, i) in rows" :key="i">
37
+ <td v-for="c in columns" :key="c.key" v-bind="cellAttrs(c)"><slot name="cell" :row="row" :column="c">{{ row[c.key] }}</slot></td>
38
+ </tr>
39
+ </tbody>
40
+ <tfoot v-if="footer">
41
+ <tr><td v-for="c in columns" :key="c.key" v-bind="cellAttrs(c)">{{ footer[c.key] }}</td></tr>
42
+ </tfoot>
43
+ </table>
44
+ <slot v-else />
45
+ </div>
46
+ </template>
@@ -1,37 +1,37 @@
1
- <script setup lang="ts">
2
- /**
3
- * Tabs with radio inputs and :has() (the CSS switches the panels). v-model = value of the active tab.
4
- * One named slot per tab value renders its panel: <template #account>...</template>.
5
- * Classes: .oc-tabset, .oc-tab-list, .oc-tab-trigger, .oc-tab-panel
6
- */
7
- import { useUid } from '../composables/useUid'
8
-
9
- export interface TabItem {
10
- label: string
11
- /** Slot name and model value; defaults to the label. */
12
- value?: string
13
- }
14
- defineProps<{ tabs: TabItem[]; name?: string }>()
15
- const model = defineModel<string>()
16
- const uid = useUid('oc-tabs')
17
- </script>
18
-
19
- <template>
20
- <div class="oc-tabset">
21
- <div class="oc-tab-list" role="tablist">
22
- <label v-for="(tab, i) in tabs" :key="tab.value ?? tab.label" class="oc-tab-trigger">
23
- <input
24
- v-model="model"
25
- type="radio"
26
- :name="name ?? uid"
27
- :value="tab.value ?? tab.label"
28
- :checked="model === undefined && i === 0"
29
- />
30
- {{ tab.label }}
31
- </label>
32
- </div>
33
- <div v-for="tab in tabs" :key="tab.value ?? tab.label" class="oc-tab-panel">
34
- <slot :name="tab.value ?? tab.label" />
35
- </div>
36
- </div>
37
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Tabs with radio inputs and :has() (the CSS switches the panels). v-model = value of the active tab.
4
+ * One named slot per tab value renders its panel: <template #account>...</template>.
5
+ * Classes: .oc-tabset, .oc-tab-list, .oc-tab-trigger, .oc-tab-panel
6
+ */
7
+ import { useUid } from '../composables/useUid'
8
+
9
+ export interface TabItem {
10
+ label: string
11
+ /** Slot name and model value; defaults to the label. */
12
+ value?: string
13
+ }
14
+ defineProps<{ tabs: TabItem[]; name?: string }>()
15
+ const model = defineModel<string>()
16
+ const uid = useUid('oc-tabs')
17
+ </script>
18
+
19
+ <template>
20
+ <div class="oc-tabset">
21
+ <div class="oc-tab-list" role="tablist">
22
+ <label v-for="(tab, i) in tabs" :key="tab.value ?? tab.label" class="oc-tab-trigger">
23
+ <input
24
+ v-model="model"
25
+ type="radio"
26
+ :name="name ?? uid"
27
+ :value="tab.value ?? tab.label"
28
+ :checked="model === undefined && i === 0"
29
+ />
30
+ {{ tab.label }}
31
+ </label>
32
+ </div>
33
+ <div v-for="tab in tabs" :key="tab.value ?? tab.label" class="oc-tab-panel">
34
+ <slot :name="tab.value ?? tab.label" />
35
+ </div>
36
+ </div>
37
+ </template>
@@ -1,50 +1,50 @@
1
- <script setup lang="ts">
2
- /**
3
- * Chips with remove buttons and a free-text input with suggestions. v-model: string[].
4
- * Enter or comma adds the typed tag, Backspace on an empty input removes the last one.
5
- * Classes: .oc-tag, .oc-tag-remove, .oc-tag-input, .oc-tag-suggestions
6
- */
7
- import { computed, ref } from 'vue'
8
-
9
- const props = withDefaults(
10
- defineProps<{
11
- suggestions?: string[]
12
- placeholder?: string
13
- label?: string
14
- }>(),
15
- { suggestions: () => [], placeholder: 'Add tag...', label: 'Add tag' },
16
- )
17
- const tags = defineModel<string[]>({ default: () => [] })
18
- const draft = ref('')
19
- const available = computed(() => props.suggestions.filter((s) => !tags.value.includes(s)))
20
-
21
- function add(value: string) {
22
- const tag = value.trim()
23
- if (tag && !tags.value.includes(tag)) tags.value = [...tags.value, tag]
24
- draft.value = ''
25
- }
26
- function remove(tag: string) {
27
- tags.value = tags.value.filter((t) => t !== tag)
28
- }
29
- function onKeydown(e: KeyboardEvent) {
30
- if (e.key === 'Enter' || e.key === ',') {
31
- e.preventDefault()
32
- add(draft.value)
33
- } else if (e.key === 'Backspace' && !draft.value && tags.value.length) {
34
- tags.value = tags.value.slice(0, -1)
35
- }
36
- }
37
- </script>
38
-
39
- <template>
40
- <div class="oc-tag-input">
41
- <span v-for="tag in tags" :key="tag" class="oc-tag">
42
- {{ tag }}
43
- <button class="oc-tag-remove" type="button" :aria-label="`Remove ${tag}`" @click="remove(tag)">&times;</button>
44
- </span>
45
- <input v-model="draft" type="text" :placeholder="placeholder" :aria-label="label" @keydown="onKeydown" />
46
- </div>
47
- <div v-if="available.length" class="oc-tag-suggestions">
48
- <button v-for="s in available" :key="s" type="button" @click="add(s)">{{ s }}</button>
49
- </div>
50
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Chips with remove buttons and a free-text input with suggestions. v-model: string[].
4
+ * Enter or comma adds the typed tag, Backspace on an empty input removes the last one.
5
+ * Classes: .oc-tag, .oc-tag-remove, .oc-tag-input, .oc-tag-suggestions
6
+ */
7
+ import { computed, ref } from 'vue'
8
+
9
+ const props = withDefaults(
10
+ defineProps<{
11
+ suggestions?: string[]
12
+ placeholder?: string
13
+ label?: string
14
+ }>(),
15
+ { suggestions: () => [], placeholder: 'Add tag...', label: 'Add tag' },
16
+ )
17
+ const tags = defineModel<string[]>({ default: () => [] })
18
+ const draft = ref('')
19
+ const available = computed(() => props.suggestions.filter((s) => !tags.value.includes(s)))
20
+
21
+ function add(value: string) {
22
+ const tag = value.trim()
23
+ if (tag && !tags.value.includes(tag)) tags.value = [...tags.value, tag]
24
+ draft.value = ''
25
+ }
26
+ function remove(tag: string) {
27
+ tags.value = tags.value.filter((t) => t !== tag)
28
+ }
29
+ function onKeydown(e: KeyboardEvent) {
30
+ if (e.key === 'Enter' || e.key === ',') {
31
+ e.preventDefault()
32
+ add(draft.value)
33
+ } else if (e.key === 'Backspace' && !draft.value && tags.value.length) {
34
+ tags.value = tags.value.slice(0, -1)
35
+ }
36
+ }
37
+ </script>
38
+
39
+ <template>
40
+ <div class="oc-tag-input">
41
+ <span v-for="tag in tags" :key="tag" class="oc-tag">
42
+ {{ tag }}
43
+ <button class="oc-tag-remove" type="button" :aria-label="`Remove ${tag}`" @click="remove(tag)">&times;</button>
44
+ </span>
45
+ <input v-model="draft" type="text" :placeholder="placeholder" :aria-label="label" @keydown="onKeydown" />
46
+ </div>
47
+ <div v-if="available.length" class="oc-tag-suggestions">
48
+ <button v-for="s in available" :key="s" type="button" @click="add(s)">{{ s }}</button>
49
+ </div>
50
+ </template>