@birdycom/omniaui-vue 0.11.0 → 0.11.1

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,13 +1,13 @@
1
- <script setup lang="ts">
2
- /** Icon, title, text and actions for lists without data. Slots: icon, title, default (text), actions. */
3
- defineProps<{ icon?: string; title?: string; text?: string }>()
4
- </script>
5
-
6
- <template>
7
- <div class="oc-empty">
8
- <span v-if="icon || $slots.icon" class="oc-empty-icon" aria-hidden="true"><slot name="icon">{{ icon }}</slot></span>
9
- <h3 v-if="title || $slots.title" class="oc-empty-title"><slot name="title">{{ title }}</slot></h3>
10
- <p v-if="text || $slots.default" class="oc-empty-text"><slot>{{ text }}</slot></p>
11
- <div v-if="$slots.actions" class="oc-empty-actions"><slot name="actions" /></div>
12
- </div>
13
- </template>
1
+ <script setup lang="ts">
2
+ /** Icon, title, text and actions for lists without data. Slots: icon, title, default (text), actions. */
3
+ defineProps<{ icon?: string; title?: string; text?: string }>()
4
+ </script>
5
+
6
+ <template>
7
+ <div class="oc-empty">
8
+ <span v-if="icon || $slots.icon" class="oc-empty-icon" aria-hidden="true"><slot name="icon">{{ icon }}</slot></span>
9
+ <h3 v-if="title || $slots.title" class="oc-empty-title"><slot name="title">{{ title }}</slot></h3>
10
+ <p v-if="text || $slots.default" class="oc-empty-text"><slot>{{ text }}</slot></p>
11
+ <div v-if="$slots.actions" class="oc-empty-actions"><slot name="actions" /></div>
12
+ </div>
13
+ </template>
@@ -1,47 +1,47 @@
1
- <!-- File: packages/vue/src/components/OcEntityCard.vue | Map: props -> article -> grid (frame | body: eyebrow, title, description, facts) -> footer -->
2
- <script setup lang="ts">
3
- /**
4
- * Framed media cell + detail column (same markup as snippets/entity-card.html).
5
- * Props: title, eyebrow, description, src / alt or glyph (frame content), contain, facts ([key, value][]), stacked, size (sm|md).
6
- * Slots: media (frame content), default (extra body content), footer. Classes: .oc-entity-card(--stacked/--sm), __grid,
7
- * __frame(--contain), __glyph, __body, __eyebrow, __title, __description, __facts, __footer
8
- */
9
- withDefaults(
10
- defineProps<{
11
- title: string
12
- eyebrow?: string
13
- description?: string
14
- src?: string
15
- alt?: string
16
- glyph?: string
17
- contain?: boolean
18
- facts?: [string, string][]
19
- stacked?: boolean
20
- size?: 'sm' | 'md'
21
- }>(),
22
- { alt: '', size: 'md' },
23
- )
24
- </script>
25
-
26
- <template>
27
- <article :class="['oc-entity-card', stacked && 'oc-entity-card--stacked', size === 'sm' && 'oc-entity-card--sm']">
28
- <div class="oc-entity-card__grid">
29
- <div :class="['oc-entity-card__frame', contain && 'oc-entity-card__frame--contain']">
30
- <slot name="media">
31
- <img v-if="src" :src="src" :alt="alt" />
32
- <span v-else-if="glyph" class="oc-entity-card__glyph" aria-hidden="true">{{ glyph }}</span>
33
- </slot>
34
- </div>
35
- <div class="oc-entity-card__body">
36
- <p v-if="eyebrow" class="oc-entity-card__eyebrow">{{ eyebrow }}</p>
37
- <h3 class="oc-entity-card__title">{{ title }}</h3>
38
- <p v-if="description" class="oc-entity-card__description">{{ description }}</p>
39
- <dl v-if="facts?.length" class="oc-entity-card__facts">
40
- <template v-for="([k, v], i) in facts" :key="i"><dt>{{ k }}</dt><dd>{{ v }}</dd></template>
41
- </dl>
42
- <slot />
43
- </div>
44
- </div>
45
- <div v-if="$slots.footer" class="oc-entity-card__footer"><slot name="footer" /></div>
46
- </article>
47
- </template>
1
+ <!-- File: packages/vue/src/components/OcEntityCard.vue | Map: props -> article -> grid (frame | body: eyebrow, title, description, facts) -> footer -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Framed media cell + detail column (same markup as snippets/entity-card.html).
5
+ * Props: title, eyebrow, description, src / alt or glyph (frame content), contain, facts ([key, value][]), stacked, size (sm|md).
6
+ * Slots: media (frame content), default (extra body content), footer. Classes: .oc-entity-card(--stacked/--sm), __grid,
7
+ * __frame(--contain), __glyph, __body, __eyebrow, __title, __description, __facts, __footer
8
+ */
9
+ withDefaults(
10
+ defineProps<{
11
+ title: string
12
+ eyebrow?: string
13
+ description?: string
14
+ src?: string
15
+ alt?: string
16
+ glyph?: string
17
+ contain?: boolean
18
+ facts?: [string, string][]
19
+ stacked?: boolean
20
+ size?: 'sm' | 'md'
21
+ }>(),
22
+ { alt: '', size: 'md' },
23
+ )
24
+ </script>
25
+
26
+ <template>
27
+ <article :class="['oc-entity-card', stacked && 'oc-entity-card--stacked', size === 'sm' && 'oc-entity-card--sm']">
28
+ <div class="oc-entity-card__grid">
29
+ <div :class="['oc-entity-card__frame', contain && 'oc-entity-card__frame--contain']">
30
+ <slot name="media">
31
+ <img v-if="src" :src="src" :alt="alt" />
32
+ <span v-else-if="glyph" class="oc-entity-card__glyph" aria-hidden="true">{{ glyph }}</span>
33
+ </slot>
34
+ </div>
35
+ <div class="oc-entity-card__body">
36
+ <p v-if="eyebrow" class="oc-entity-card__eyebrow">{{ eyebrow }}</p>
37
+ <h3 class="oc-entity-card__title">{{ title }}</h3>
38
+ <p v-if="description" class="oc-entity-card__description">{{ description }}</p>
39
+ <dl v-if="facts?.length" class="oc-entity-card__facts">
40
+ <template v-for="([k, v], i) in facts" :key="i"><dt>{{ k }}</dt><dd>{{ v }}</dd></template>
41
+ </dl>
42
+ <slot />
43
+ </div>
44
+ </div>
45
+ <div v-if="$slots.footer" class="oc-entity-card__footer"><slot name="footer" /></div>
46
+ </article>
47
+ </template>
@@ -1,37 +1,37 @@
1
- <!-- File: packages/vue/src/components/OcFactList.vue | Map: props (items + modifiers) -> dl.oc-fact-list -> div > dt + dd -->
2
- <script setup lang="ts">
3
- /**
4
- * Key / value product facts (variant of the definition list). Pass `items`, or your own <div><dt><dd> rows in the slot.
5
- * Classes: .oc-fact-list (--plain, --compact, --stacked, --accent)
6
- */
7
- export interface FactListRow {
8
- label: string
9
- value: string
10
- }
11
- withDefaults(
12
- defineProps<{
13
- items?: FactListRow[]
14
- plain?: boolean
15
- compact?: boolean
16
- stacked?: boolean
17
- accent?: boolean
18
- }>(),
19
- { items: () => [] },
20
- )
21
- </script>
22
-
23
- <template>
24
- <dl
25
- :class="[
26
- 'oc-fact-list',
27
- plain && 'oc-fact-list--plain',
28
- compact && 'oc-fact-list--compact',
29
- stacked && 'oc-fact-list--stacked',
30
- accent && 'oc-fact-list--accent',
31
- ]"
32
- >
33
- <slot>
34
- <div v-for="(row, i) in items" :key="i"><dt>{{ row.label }}</dt><dd>{{ row.value }}</dd></div>
35
- </slot>
36
- </dl>
37
- </template>
1
+ <!-- File: packages/vue/src/components/OcFactList.vue | Map: props (items + modifiers) -> dl.oc-fact-list -> div > dt + dd -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Key / value product facts (variant of the definition list). Pass `items`, or your own <div><dt><dd> rows in the slot.
5
+ * Classes: .oc-fact-list (--plain, --compact, --stacked, --accent)
6
+ */
7
+ export interface FactListRow {
8
+ label: string
9
+ value: string
10
+ }
11
+ withDefaults(
12
+ defineProps<{
13
+ items?: FactListRow[]
14
+ plain?: boolean
15
+ compact?: boolean
16
+ stacked?: boolean
17
+ accent?: boolean
18
+ }>(),
19
+ { items: () => [] },
20
+ )
21
+ </script>
22
+
23
+ <template>
24
+ <dl
25
+ :class="[
26
+ 'oc-fact-list',
27
+ plain && 'oc-fact-list--plain',
28
+ compact && 'oc-fact-list--compact',
29
+ stacked && 'oc-fact-list--stacked',
30
+ accent && 'oc-fact-list--accent',
31
+ ]"
32
+ >
33
+ <slot>
34
+ <div v-for="(row, i) in items" :key="i"><dt>{{ row.label }}</dt><dd>{{ row.value }}</dd></div>
35
+ </slot>
36
+ </dl>
37
+ </template>
@@ -1,38 +1,38 @@
1
- <!-- File: packages/vue/src/components/OcFilterCounts.vue | Map: types + props -> template (fieldset radiogroup -> tile per view) -->
2
- <script setup lang="ts">
3
- /**
4
- * View filter tiles with counts (Active / Deleted / All). v-model = selected value.
5
- * Same markup as packages/ui/snippets/filter-counts.html. Classes: .oc-filter-counts(--compact), -item(--success/--destructive/--muted), -value, -label, -hint
6
- */
7
- import { useUid } from '../composables/useUid'
8
-
9
- export interface FilterCountsItem {
10
- value: string
11
- label: string
12
- count: number | string
13
- hint?: string
14
- /** Accent color of the tile; default primary. */
15
- tone?: 'primary' | 'success' | 'destructive' | 'muted'
16
- disabled?: boolean
17
- }
18
- defineProps<{
19
- options: FilterCountsItem[]
20
- /** aria-label of the group */
21
- label?: string
22
- compact?: boolean
23
- name?: string
24
- }>()
25
- const model = defineModel<string>()
26
- const uid = useUid('oc-filter')
27
- </script>
28
-
29
- <template>
30
- <fieldset :class="['oc-filter-counts', compact && 'oc-filter-counts--compact']" role="radiogroup" :aria-label="label">
31
- <label v-for="option in options" :key="option.value" :class="['oc-filter-counts-item', option.tone && option.tone !== 'primary' && `oc-filter-counts-item--${option.tone}`]">
32
- <input v-model="model" type="radio" :name="name ?? uid" :value="option.value" :disabled="option.disabled" />
33
- <span class="oc-filter-counts-value">{{ option.count }}</span>
34
- <span class="oc-filter-counts-label">{{ option.label }}</span>
35
- <span v-if="option.hint" class="oc-filter-counts-hint">{{ option.hint }}</span>
36
- </label>
37
- </fieldset>
38
- </template>
1
+ <!-- File: packages/vue/src/components/OcFilterCounts.vue | Map: types + props -> template (fieldset radiogroup -> tile per view) -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * View filter tiles with counts (Active / Deleted / All). v-model = selected value.
5
+ * Same markup as packages/ui/snippets/filter-counts.html. Classes: .oc-filter-counts(--compact), -item(--success/--destructive/--muted), -value, -label, -hint
6
+ */
7
+ import { useUid } from '../composables/useUid'
8
+
9
+ export interface FilterCountsItem {
10
+ value: string
11
+ label: string
12
+ count: number | string
13
+ hint?: string
14
+ /** Accent color of the tile; default primary. */
15
+ tone?: 'primary' | 'success' | 'destructive' | 'muted'
16
+ disabled?: boolean
17
+ }
18
+ defineProps<{
19
+ options: FilterCountsItem[]
20
+ /** aria-label of the group */
21
+ label?: string
22
+ compact?: boolean
23
+ name?: string
24
+ }>()
25
+ const model = defineModel<string>()
26
+ const uid = useUid('oc-filter')
27
+ </script>
28
+
29
+ <template>
30
+ <fieldset :class="['oc-filter-counts', compact && 'oc-filter-counts--compact']" role="radiogroup" :aria-label="label">
31
+ <label v-for="option in options" :key="option.value" :class="['oc-filter-counts-item', option.tone && option.tone !== 'primary' && `oc-filter-counts-item--${option.tone}`]">
32
+ <input v-model="model" type="radio" :name="name ?? uid" :value="option.value" :disabled="option.disabled" />
33
+ <span class="oc-filter-counts-value">{{ option.count }}</span>
34
+ <span class="oc-filter-counts-label">{{ option.label }}</span>
35
+ <span v-if="option.hint" class="oc-filter-counts-hint">{{ option.hint }}</span>
36
+ </label>
37
+ </fieldset>
38
+ </template>
@@ -1,36 +1,36 @@
1
- <!-- File: packages/vue/src/components/OcFlipCard.vue | Map: props + v-model:flipped -> card -> checkbox (toggle) -> inner -> front / back faces -->
2
- <script setup lang="ts">
3
- /**
4
- * 3D flip card (same markup as snippets/flip-card.html). v-model:flipped. trigger: toggle (checkbox, default) |
5
- * hover (--hover, tabindex 0) | manual (.is-flipped from the model only). Props: vertical, frontLabel, backLabel.
6
- * Slots: front, back. Classes: .oc-flip-card(--hover/--vertical, .is-flipped), __toggle, __inner, __face(--front/--back),
7
- * __title, __text, __flip
8
- */
9
- import { useUid } from '../composables/useUid'
10
-
11
- withDefaults(
12
- defineProps<{ trigger?: 'toggle' | 'hover' | 'manual'; vertical?: boolean; frontLabel?: string; backLabel?: string }>(),
13
- { trigger: 'toggle', frontLabel: 'Show answer', backLabel: 'Back' },
14
- )
15
- const flipped = defineModel<boolean>('flipped', { default: false })
16
- const id = useUid('oc-flip')
17
- </script>
18
-
19
- <template>
20
- <div
21
- :class="['oc-flip-card', trigger === 'hover' && 'oc-flip-card--hover', vertical && 'oc-flip-card--vertical', trigger !== 'toggle' && flipped && 'is-flipped']"
22
- :tabindex="trigger === 'hover' ? 0 : undefined"
23
- >
24
- <input v-if="trigger === 'toggle'" :id="id" v-model="flipped" type="checkbox" class="oc-flip-card__toggle" />
25
- <div class="oc-flip-card__inner">
26
- <div class="oc-flip-card__face oc-flip-card__face--front">
27
- <slot name="front" />
28
- <label v-if="trigger === 'toggle'" class="oc-flip-card__flip" :for="id">{{ frontLabel }}</label>
29
- </div>
30
- <div class="oc-flip-card__face oc-flip-card__face--back">
31
- <slot name="back" />
32
- <label v-if="trigger === 'toggle'" class="oc-flip-card__flip" :for="id">{{ backLabel }}</label>
33
- </div>
34
- </div>
35
- </div>
36
- </template>
1
+ <!-- File: packages/vue/src/components/OcFlipCard.vue | Map: props + v-model:flipped -> card -> checkbox (toggle) -> inner -> front / back faces -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * 3D flip card (same markup as snippets/flip-card.html). v-model:flipped. trigger: toggle (checkbox, default) |
5
+ * hover (--hover, tabindex 0) | manual (.is-flipped from the model only). Props: vertical, frontLabel, backLabel.
6
+ * Slots: front, back. Classes: .oc-flip-card(--hover/--vertical, .is-flipped), __toggle, __inner, __face(--front/--back),
7
+ * __title, __text, __flip
8
+ */
9
+ import { useUid } from '../composables/useUid'
10
+
11
+ withDefaults(
12
+ defineProps<{ trigger?: 'toggle' | 'hover' | 'manual'; vertical?: boolean; frontLabel?: string; backLabel?: string }>(),
13
+ { trigger: 'toggle', frontLabel: 'Show answer', backLabel: 'Back' },
14
+ )
15
+ const flipped = defineModel<boolean>('flipped', { default: false })
16
+ const id = useUid('oc-flip')
17
+ </script>
18
+
19
+ <template>
20
+ <div
21
+ :class="['oc-flip-card', trigger === 'hover' && 'oc-flip-card--hover', vertical && 'oc-flip-card--vertical', trigger !== 'toggle' && flipped && 'is-flipped']"
22
+ :tabindex="trigger === 'hover' ? 0 : undefined"
23
+ >
24
+ <input v-if="trigger === 'toggle'" :id="id" v-model="flipped" type="checkbox" class="oc-flip-card__toggle" />
25
+ <div class="oc-flip-card__inner">
26
+ <div class="oc-flip-card__face oc-flip-card__face--front">
27
+ <slot name="front" />
28
+ <label v-if="trigger === 'toggle'" class="oc-flip-card__flip" :for="id">{{ frontLabel }}</label>
29
+ </div>
30
+ <div class="oc-flip-card__face oc-flip-card__face--back">
31
+ <slot name="back" />
32
+ <label v-if="trigger === 'toggle'" class="oc-flip-card__flip" :for="id">{{ backLabel }}</label>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ </template>
@@ -1,36 +1,36 @@
1
- <script setup lang="ts">
2
- /**
3
- * Form field: label, control (default slot), description and error.
4
- * The slot receives { id, describedBy, invalid } so the control can be wired:
5
- * <OcFormField label="Email" description="..." v-slot="f"><OcInput :id="f.id" :aria-describedby="f.describedBy" /></OcFormField>
6
- * Classes: .oc-field(--horizontal), .oc-field-label, .oc-field-description, .oc-field-error
7
- */
8
- import { computed } from 'vue'
9
- import { useUid } from '../composables/useUid'
10
-
11
- const props = defineProps<{
12
- label?: string
13
- description?: string
14
- error?: string
15
- /** id of the control; generated when omitted */
16
- for?: string
17
- horizontal?: boolean
18
- }>()
19
- const generated = useUid('oc-field')
20
- const id = computed(() => props.for ?? generated)
21
- const helpId = computed(() => `${id.value}-help`)
22
- const errorId = computed(() => `${id.value}-error`)
23
- const describedBy = computed(() => {
24
- const ids = [props.description && helpId.value, props.error && errorId.value].filter(Boolean)
25
- return ids.length ? ids.join(' ') : undefined
26
- })
27
- </script>
28
-
29
- <template>
30
- <div :class="['oc-field', horizontal && 'oc-field--horizontal']">
31
- <label v-if="label || $slots.label" class="oc-field-label" :for="id"><slot name="label">{{ label }}</slot></label>
32
- <slot :id="id" :described-by="describedBy" :invalid="!!error" />
33
- <p v-if="description" :id="helpId" class="oc-field-description">{{ description }}</p>
34
- <p v-if="error" :id="errorId" class="oc-field-error" role="alert">{{ error }}</p>
35
- </div>
36
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Form field: label, control (default slot), description and error.
4
+ * The slot receives { id, describedBy, invalid } so the control can be wired:
5
+ * <OcFormField label="Email" description="..." v-slot="f"><OcInput :id="f.id" :aria-describedby="f.describedBy" /></OcFormField>
6
+ * Classes: .oc-field(--horizontal), .oc-field-label, .oc-field-description, .oc-field-error
7
+ */
8
+ import { computed } from 'vue'
9
+ import { useUid } from '../composables/useUid'
10
+
11
+ const props = defineProps<{
12
+ label?: string
13
+ description?: string
14
+ error?: string
15
+ /** id of the control; generated when omitted */
16
+ for?: string
17
+ horizontal?: boolean
18
+ }>()
19
+ const generated = useUid('oc-field')
20
+ const id = computed(() => props.for ?? generated)
21
+ const helpId = computed(() => `${id.value}-help`)
22
+ const errorId = computed(() => `${id.value}-error`)
23
+ const describedBy = computed(() => {
24
+ const ids = [props.description && helpId.value, props.error && errorId.value].filter(Boolean)
25
+ return ids.length ? ids.join(' ') : undefined
26
+ })
27
+ </script>
28
+
29
+ <template>
30
+ <div :class="['oc-field', horizontal && 'oc-field--horizontal']">
31
+ <label v-if="label || $slots.label" class="oc-field-label" :for="id"><slot name="label">{{ label }}</slot></label>
32
+ <slot :id="id" :described-by="describedBy" :invalid="!!error" />
33
+ <p v-if="description" :id="helpId" class="oc-field-description">{{ description }}</p>
34
+ <p v-if="error" :id="errorId" class="oc-field-error" role="alert">{{ error }}</p>
35
+ </div>
36
+ </template>
@@ -1,52 +1,52 @@
1
- <!-- File: packages/vue/src/components/OcGreeting.vue | Map: time-of-day logic -> header -> icon slot -> body (eyebrow, title + name, date) -> actions slot -->
2
- <script setup lang="ts">
3
- /**
4
- * Dashboard greeting. The time of day comes from `date` (default now): morning 05-12, afternoon 12-18, evening otherwise.
5
- * Slots: icon, actions. Classes: .oc-greeting(--morning/--afternoon/--evening/--lg), -icon, -body, -eyebrow, -title, -name, -date, -actions
6
- */
7
- import { computed } from 'vue'
8
-
9
- type TimeOfDay = 'morning' | 'afternoon' | 'evening'
10
-
11
- const props = defineProps<{
12
- name?: string
13
- date?: Date
14
- timeOfDay?: TimeOfDay
15
- /** Translated greetings, e.g. { morning: 'Goedemorgen' }. */
16
- words?: Partial<Record<TimeOfDay, string>>
17
- locale?: string
18
- hideDate?: boolean
19
- eyebrow?: string
20
- size?: 'lg'
21
- }>()
22
-
23
- const WORDS: Record<TimeOfDay, string> = { morning: 'Good morning', afternoon: 'Good afternoon', evening: 'Good evening' }
24
-
25
- const when = computed(() => props.date ?? new Date())
26
- const tod = computed<TimeOfDay>(() => {
27
- if (props.timeOfDay) return props.timeOfDay
28
- const h = when.value.getHours()
29
- return h >= 5 && h < 12 ? 'morning' : h >= 12 && h < 18 ? 'afternoon' : 'evening'
30
- })
31
- const word = computed(() => props.words?.[tod.value] ?? WORDS[tod.value])
32
- const dateText = computed(() =>
33
- new Intl.DateTimeFormat(props.locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }).format(when.value),
34
- )
35
- // Local YYYY-MM-DD for datetime (toISOString would use UTC).
36
- const iso = computed(() => {
37
- const d = when.value
38
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
39
- })
40
- </script>
41
-
42
- <template>
43
- <header :class="['oc-greeting', `oc-greeting--${tod}`, size && `oc-greeting--${size}`]">
44
- <span v-if="$slots.icon" class="oc-greeting-icon" aria-hidden="true"><slot name="icon" /></span>
45
- <div class="oc-greeting-body">
46
- <p v-if="eyebrow" class="oc-greeting-eyebrow">{{ eyebrow }}</p>
47
- <h2 class="oc-greeting-title">{{ word }}<template v-if="name">, <span class="oc-greeting-name">{{ name }}</span></template></h2>
48
- <time v-if="!hideDate" class="oc-greeting-date" :datetime="iso">{{ dateText }}</time>
49
- </div>
50
- <div v-if="$slots.actions" class="oc-greeting-actions"><slot name="actions" /></div>
51
- </header>
52
- </template>
1
+ <!-- File: packages/vue/src/components/OcGreeting.vue | Map: time-of-day logic -> header -> icon slot -> body (eyebrow, title + name, date) -> actions slot -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Dashboard greeting. The time of day comes from `date` (default now): morning 05-12, afternoon 12-18, evening otherwise.
5
+ * Slots: icon, actions. Classes: .oc-greeting(--morning/--afternoon/--evening/--lg), -icon, -body, -eyebrow, -title, -name, -date, -actions
6
+ */
7
+ import { computed } from 'vue'
8
+
9
+ type TimeOfDay = 'morning' | 'afternoon' | 'evening'
10
+
11
+ const props = defineProps<{
12
+ name?: string
13
+ date?: Date
14
+ timeOfDay?: TimeOfDay
15
+ /** Translated greetings, e.g. { morning: 'Goedemorgen' }. */
16
+ words?: Partial<Record<TimeOfDay, string>>
17
+ locale?: string
18
+ hideDate?: boolean
19
+ eyebrow?: string
20
+ size?: 'lg'
21
+ }>()
22
+
23
+ const WORDS: Record<TimeOfDay, string> = { morning: 'Good morning', afternoon: 'Good afternoon', evening: 'Good evening' }
24
+
25
+ const when = computed(() => props.date ?? new Date())
26
+ const tod = computed<TimeOfDay>(() => {
27
+ if (props.timeOfDay) return props.timeOfDay
28
+ const h = when.value.getHours()
29
+ return h >= 5 && h < 12 ? 'morning' : h >= 12 && h < 18 ? 'afternoon' : 'evening'
30
+ })
31
+ const word = computed(() => props.words?.[tod.value] ?? WORDS[tod.value])
32
+ const dateText = computed(() =>
33
+ new Intl.DateTimeFormat(props.locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }).format(when.value),
34
+ )
35
+ // Local YYYY-MM-DD for datetime (toISOString would use UTC).
36
+ const iso = computed(() => {
37
+ const d = when.value
38
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
39
+ })
40
+ </script>
41
+
42
+ <template>
43
+ <header :class="['oc-greeting', `oc-greeting--${tod}`, size && `oc-greeting--${size}`]">
44
+ <span v-if="$slots.icon" class="oc-greeting-icon" aria-hidden="true"><slot name="icon" /></span>
45
+ <div class="oc-greeting-body">
46
+ <p v-if="eyebrow" class="oc-greeting-eyebrow">{{ eyebrow }}</p>
47
+ <h2 class="oc-greeting-title">{{ word }}<template v-if="name">, <span class="oc-greeting-name">{{ name }}</span></template></h2>
48
+ <time v-if="!hideDate" class="oc-greeting-date" :datetime="iso">{{ dateText }}</time>
49
+ </div>
50
+ <div v-if="$slots.actions" class="oc-greeting-actions"><slot name="actions" /></div>
51
+ </header>
52
+ </template>
@@ -1,19 +1,19 @@
1
- <script setup lang="ts">
2
- /** Page or section title with a muted description. Classes: .oc-heading(--sm). `as` picks the title tag. */
3
- withDefaults(
4
- defineProps<{
5
- title?: string
6
- description?: string
7
- size?: 'sm' | 'md'
8
- as?: 'h1' | 'h2' | 'h3' | 'h4'
9
- }>(),
10
- { size: 'md', as: 'h2' },
11
- )
12
- </script>
13
-
14
- <template>
15
- <div :class="['oc-heading', size === 'sm' && 'oc-heading--sm']">
16
- <component :is="as" class="oc-heading-title"><slot name="title">{{ title }}</slot></component>
17
- <p v-if="description || $slots.default" class="oc-heading-description"><slot>{{ description }}</slot></p>
18
- </div>
19
- </template>
1
+ <script setup lang="ts">
2
+ /** Page or section title with a muted description. Classes: .oc-heading(--sm). `as` picks the title tag. */
3
+ withDefaults(
4
+ defineProps<{
5
+ title?: string
6
+ description?: string
7
+ size?: 'sm' | 'md'
8
+ as?: 'h1' | 'h2' | 'h3' | 'h4'
9
+ }>(),
10
+ { size: 'md', as: 'h2' },
11
+ )
12
+ </script>
13
+
14
+ <template>
15
+ <div :class="['oc-heading', size === 'sm' && 'oc-heading--sm']">
16
+ <component :is="as" class="oc-heading-title"><slot name="title">{{ title }}</slot></component>
17
+ <p v-if="description || $slots.default" class="oc-heading-description"><slot>{{ description }}</slot></p>
18
+ </div>
19
+ </template>
@@ -1,25 +1,25 @@
1
- <script setup lang="ts">
2
- /**
3
- * Preview on hover/focus (interestfor + popover, CSS hover fallback). The trigger is the `trigger` slot
4
- * (scoped: { id }) or a link with `label` and `href`; default slot = card content.
5
- * Classes: .oc-hover-card(--top), -trigger, -content(--sm). Attributes land on the content element.
6
- */
7
- import { useAttrs } from 'vue'
8
- import { useUid } from '../composables/useUid'
9
-
10
- defineOptions({ inheritAttrs: false })
11
- defineProps<{ label?: string; href?: string; top?: boolean; small?: boolean }>()
12
- const attrs = useAttrs()
13
- const id = (attrs.id as string | undefined) ?? useUid('oc-hover-card')
14
- </script>
15
-
16
- <template>
17
- <span :class="['oc-hover-card', top && 'oc-hover-card--top']">
18
- <slot name="trigger" :id="id">
19
- <a class="oc-hover-card-trigger" :href="href ?? '#'" :interestfor="id">{{ label }}</a>
20
- </slot>
21
- <div v-bind="attrs" :id="id" :class="['oc-hover-card-content', small && 'oc-hover-card-content--sm']" popover>
22
- <slot />
23
- </div>
24
- </span>
25
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Preview on hover/focus (interestfor + popover, CSS hover fallback). The trigger is the `trigger` slot
4
+ * (scoped: { id }) or a link with `label` and `href`; default slot = card content.
5
+ * Classes: .oc-hover-card(--top), -trigger, -content(--sm). Attributes land on the content element.
6
+ */
7
+ import { useAttrs } from 'vue'
8
+ import { useUid } from '../composables/useUid'
9
+
10
+ defineOptions({ inheritAttrs: false })
11
+ defineProps<{ label?: string; href?: string; top?: boolean; small?: boolean }>()
12
+ const attrs = useAttrs()
13
+ const id = (attrs.id as string | undefined) ?? useUid('oc-hover-card')
14
+ </script>
15
+
16
+ <template>
17
+ <span :class="['oc-hover-card', top && 'oc-hover-card--top']">
18
+ <slot name="trigger" :id="id">
19
+ <a class="oc-hover-card-trigger" :href="href ?? '#'" :interestfor="id">{{ label }}</a>
20
+ </slot>
21
+ <div v-bind="attrs" :id="id" :class="['oc-hover-card-content', small && 'oc-hover-card-content--sm']" popover>
22
+ <slot />
23
+ </div>
24
+ </span>
25
+ </template>