@birdycom/omniaui-vue 0.12.4 → 0.12.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.
- package/dist/blocks/OcBlockDataTable.vue.d.ts +1 -1
- package/dist/blocks/OcBlockProfileHeader.vue.d.ts +4 -2
- package/dist/components/OcAvatarPicker.vue.d.ts +21 -0
- package/dist/components/OcBarcode.vue.d.ts +12 -0
- package/dist/components/OcBreadcrumb.vue.d.ts +7 -1
- package/dist/components/OcButton.vue.d.ts +6 -3
- package/dist/components/OcDataTable.vue.d.ts +68 -1
- package/dist/components/OcDataTableName.vue.d.ts +20 -0
- package/dist/components/OcDateField.vue.d.ts +19 -0
- package/dist/components/OcEmojiPicker.vue.d.ts +1 -1
- package/dist/components/OcFormSection.vue.d.ts +25 -0
- package/dist/components/OcGallery.vue.d.ts +17 -0
- package/dist/components/OcGlass.vue.d.ts +2 -1
- package/dist/components/OcGlassBar.vue.d.ts +32 -0
- package/dist/components/OcLazyImage.vue.d.ts +24 -0
- package/dist/components/OcMeterRow.vue.d.ts +9 -0
- package/dist/components/{OcColumnMenu.vue.d.ts → OcNameCard.vue.d.ts} +15 -16
- package/dist/components/OcPrice.vue.d.ts +20 -0
- package/dist/components/OcQuantity.vue.d.ts +24 -0
- package/dist/components/OcRating.vue.d.ts +11 -0
- package/dist/components/OcRatingInput.vue.d.ts +18 -0
- package/dist/components/OcRibbon.vue.d.ts +22 -0
- package/dist/components/OcSpecList.vue.d.ts +15 -0
- package/dist/components/OcStock.vue.d.ts +20 -0
- package/dist/components/OcUser.vue.d.ts +0 -1
- package/dist/index.d.ts +22 -3
- package/dist/omniaui-vue.js +5271 -4107
- package/dist/omniaui-vue.js.map +1 -1
- package/manifest.json +102 -6
- package/package.json +1 -1
- package/src/blocks/OcBlockAppHeader.vue +1 -1
- package/src/blocks/OcBlockDataTable.vue +1 -1
- package/src/blocks/OcBlockProfileHeader.vue +15 -4
- package/src/components/OcAttachmentList.vue +1 -1
- package/src/components/OcAvatarPicker.vue +34 -0
- package/src/components/OcBarcode.vue +23 -0
- package/src/components/OcBreadcrumb.vue +14 -5
- package/src/components/OcButton.vue +10 -2
- package/src/components/OcChatComposer.vue +1 -1
- package/src/components/OcDataTable.vue +100 -25
- package/src/components/OcDataTableName.vue +18 -0
- package/src/components/OcDateField.vue +23 -0
- package/src/components/OcEmojiPicker.vue +2 -2
- package/src/components/OcFormSection.vue +19 -0
- package/src/components/OcGallery.vue +27 -0
- package/src/components/OcGlass.vue +4 -4
- package/src/components/OcGlassBar.vue +17 -0
- package/src/components/OcLanguageSelect.vue +1 -1
- package/src/components/OcLazyImage.vue +17 -0
- package/src/components/OcListToolbar.vue +5 -5
- package/src/components/OcMessage.vue +4 -4
- package/src/components/OcMessageList.vue +6 -6
- package/src/components/OcMessageThread.vue +12 -12
- package/src/components/OcMeterRow.vue +18 -0
- package/src/components/OcNameCard.vue +28 -0
- package/src/components/OcPrice.vue +30 -0
- package/src/components/OcProse.vue +3 -3
- package/src/components/OcQuantity.vue +21 -0
- package/src/components/OcRating.vue +17 -0
- package/src/components/OcRatingInput.vue +17 -0
- package/src/components/OcRibbon.vue +9 -0
- package/src/components/OcSpecList.vue +17 -0
- package/src/components/OcStock.vue +13 -0
- package/src/components/OcUser.vue +7 -3
- package/src/index.ts +55 -4
- package/src/components/OcColumnMenu.vue +0 -50
package/manifest.json
CHANGED
|
@@ -84,6 +84,12 @@
|
|
|
84
84
|
"file": "src/components/OcAvatarGroup.vue",
|
|
85
85
|
"snippet": "@birdycom/omniaui/snippets/avatar.html"
|
|
86
86
|
},
|
|
87
|
+
{
|
|
88
|
+
"name": "OcAvatarPicker",
|
|
89
|
+
"kind": "component",
|
|
90
|
+
"file": "src/components/OcAvatarPicker.vue",
|
|
91
|
+
"snippet": "@birdycom/omniaui/snippets/avatar-picker.html"
|
|
92
|
+
},
|
|
87
93
|
{
|
|
88
94
|
"name": "OcBackLink",
|
|
89
95
|
"kind": "component",
|
|
@@ -96,6 +102,12 @@
|
|
|
96
102
|
"file": "src/components/OcBadge.vue",
|
|
97
103
|
"snippet": "@birdycom/omniaui/snippets/badge.html"
|
|
98
104
|
},
|
|
105
|
+
{
|
|
106
|
+
"name": "OcBarcode",
|
|
107
|
+
"kind": "component",
|
|
108
|
+
"file": "src/components/OcBarcode.vue",
|
|
109
|
+
"snippet": "@birdycom/omniaui/snippets/barcode.html"
|
|
110
|
+
},
|
|
99
111
|
{
|
|
100
112
|
"name": "OcBarcodeInput",
|
|
101
113
|
"kind": "component",
|
|
@@ -192,12 +204,6 @@
|
|
|
192
204
|
"file": "src/components/OcColorSelect.vue",
|
|
193
205
|
"snippet": "@birdycom/omniaui/snippets/color-select.html"
|
|
194
206
|
},
|
|
195
|
-
{
|
|
196
|
-
"name": "OcColumnMenu",
|
|
197
|
-
"kind": "component",
|
|
198
|
-
"file": "src/components/OcColumnMenu.vue",
|
|
199
|
-
"snippet": "@birdycom/omniaui/snippets/column-menu.html"
|
|
200
|
-
},
|
|
201
207
|
{
|
|
202
208
|
"name": "OcCommand",
|
|
203
209
|
"kind": "component",
|
|
@@ -234,6 +240,18 @@
|
|
|
234
240
|
"file": "src/components/OcDataTable.vue",
|
|
235
241
|
"snippet": "@birdycom/omniaui/snippets/data-table.html"
|
|
236
242
|
},
|
|
243
|
+
{
|
|
244
|
+
"name": "OcDataTableName",
|
|
245
|
+
"kind": "component",
|
|
246
|
+
"file": "src/components/OcDataTableName.vue",
|
|
247
|
+
"snippet": null
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"name": "OcDateField",
|
|
251
|
+
"kind": "component",
|
|
252
|
+
"file": "src/components/OcDateField.vue",
|
|
253
|
+
"snippet": "@birdycom/omniaui/snippets/date-field.html"
|
|
254
|
+
},
|
|
237
255
|
{
|
|
238
256
|
"name": "OcDecimalInput",
|
|
239
257
|
"kind": "component",
|
|
@@ -324,12 +342,30 @@
|
|
|
324
342
|
"file": "src/components/OcFormField.vue",
|
|
325
343
|
"snippet": "@birdycom/omniaui/snippets/form-field.html"
|
|
326
344
|
},
|
|
345
|
+
{
|
|
346
|
+
"name": "OcFormSection",
|
|
347
|
+
"kind": "component",
|
|
348
|
+
"file": "src/components/OcFormSection.vue",
|
|
349
|
+
"snippet": "@birdycom/omniaui/snippets/form-section.html"
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
"name": "OcGallery",
|
|
353
|
+
"kind": "component",
|
|
354
|
+
"file": "src/components/OcGallery.vue",
|
|
355
|
+
"snippet": "@birdycom/omniaui/snippets/gallery.html"
|
|
356
|
+
},
|
|
327
357
|
{
|
|
328
358
|
"name": "OcGlass",
|
|
329
359
|
"kind": "component",
|
|
330
360
|
"file": "src/components/OcGlass.vue",
|
|
331
361
|
"snippet": "@birdycom/omniaui/snippets/glass.html"
|
|
332
362
|
},
|
|
363
|
+
{
|
|
364
|
+
"name": "OcGlassBar",
|
|
365
|
+
"kind": "component",
|
|
366
|
+
"file": "src/components/OcGlassBar.vue",
|
|
367
|
+
"snippet": null
|
|
368
|
+
},
|
|
333
369
|
{
|
|
334
370
|
"name": "OcGlassPanel",
|
|
335
371
|
"kind": "component",
|
|
@@ -420,6 +456,12 @@
|
|
|
420
456
|
"file": "src/components/OcLauncherCard.vue",
|
|
421
457
|
"snippet": "@birdycom/omniaui/snippets/launcher-card.html"
|
|
422
458
|
},
|
|
459
|
+
{
|
|
460
|
+
"name": "OcLazyImage",
|
|
461
|
+
"kind": "component",
|
|
462
|
+
"file": "src/components/OcLazyImage.vue",
|
|
463
|
+
"snippet": null
|
|
464
|
+
},
|
|
423
465
|
{
|
|
424
466
|
"name": "OcLightbox",
|
|
425
467
|
"kind": "component",
|
|
@@ -492,12 +534,24 @@
|
|
|
492
534
|
"file": "src/components/OcMessageThread.vue",
|
|
493
535
|
"snippet": "@birdycom/omniaui/snippets/message-thread.html"
|
|
494
536
|
},
|
|
537
|
+
{
|
|
538
|
+
"name": "OcMeterRow",
|
|
539
|
+
"kind": "component",
|
|
540
|
+
"file": "src/components/OcMeterRow.vue",
|
|
541
|
+
"snippet": "@birdycom/omniaui/snippets/meter-row.html"
|
|
542
|
+
},
|
|
495
543
|
{
|
|
496
544
|
"name": "OcModal",
|
|
497
545
|
"kind": "component",
|
|
498
546
|
"file": "src/components/OcModal.vue",
|
|
499
547
|
"snippet": "@birdycom/omniaui/snippets/modal.html"
|
|
500
548
|
},
|
|
549
|
+
{
|
|
550
|
+
"name": "OcNameCard",
|
|
551
|
+
"kind": "component",
|
|
552
|
+
"file": "src/components/OcNameCard.vue",
|
|
553
|
+
"snippet": "@birdycom/omniaui/snippets/name-card.html"
|
|
554
|
+
},
|
|
501
555
|
{
|
|
502
556
|
"name": "OcNavmenu",
|
|
503
557
|
"kind": "component",
|
|
@@ -564,6 +618,12 @@
|
|
|
564
618
|
"file": "src/components/OcPopover.vue",
|
|
565
619
|
"snippet": "@birdycom/omniaui/snippets/popover.html"
|
|
566
620
|
},
|
|
621
|
+
{
|
|
622
|
+
"name": "OcPrice",
|
|
623
|
+
"kind": "component",
|
|
624
|
+
"file": "src/components/OcPrice.vue",
|
|
625
|
+
"snippet": "@birdycom/omniaui/snippets/price.html"
|
|
626
|
+
},
|
|
567
627
|
{
|
|
568
628
|
"name": "OcPriceCard",
|
|
569
629
|
"kind": "component",
|
|
@@ -594,6 +654,12 @@
|
|
|
594
654
|
"file": "src/components/OcProse.vue",
|
|
595
655
|
"snippet": "@birdycom/omniaui/snippets/prose.html"
|
|
596
656
|
},
|
|
657
|
+
{
|
|
658
|
+
"name": "OcQuantity",
|
|
659
|
+
"kind": "component",
|
|
660
|
+
"file": "src/components/OcQuantity.vue",
|
|
661
|
+
"snippet": "@birdycom/omniaui/snippets/quantity.html"
|
|
662
|
+
},
|
|
597
663
|
{
|
|
598
664
|
"name": "OcRadio",
|
|
599
665
|
"kind": "component",
|
|
@@ -606,12 +672,30 @@
|
|
|
606
672
|
"file": "src/components/OcRadioGroup.vue",
|
|
607
673
|
"snippet": null
|
|
608
674
|
},
|
|
675
|
+
{
|
|
676
|
+
"name": "OcRating",
|
|
677
|
+
"kind": "component",
|
|
678
|
+
"file": "src/components/OcRating.vue",
|
|
679
|
+
"snippet": "@birdycom/omniaui/snippets/rating.html"
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
"name": "OcRatingInput",
|
|
683
|
+
"kind": "component",
|
|
684
|
+
"file": "src/components/OcRatingInput.vue",
|
|
685
|
+
"snippet": "@birdycom/omniaui/snippets/rating.html"
|
|
686
|
+
},
|
|
609
687
|
{
|
|
610
688
|
"name": "OcRecoveryCodes",
|
|
611
689
|
"kind": "component",
|
|
612
690
|
"file": "src/components/OcRecoveryCodes.vue",
|
|
613
691
|
"snippet": "@birdycom/omniaui/snippets/recovery-codes.html"
|
|
614
692
|
},
|
|
693
|
+
{
|
|
694
|
+
"name": "OcRibbon",
|
|
695
|
+
"kind": "component",
|
|
696
|
+
"file": "src/components/OcRibbon.vue",
|
|
697
|
+
"snippet": "@birdycom/omniaui/snippets/ribbon.html"
|
|
698
|
+
},
|
|
615
699
|
{
|
|
616
700
|
"name": "OcScrollArea",
|
|
617
701
|
"kind": "component",
|
|
@@ -702,6 +786,12 @@
|
|
|
702
786
|
"file": "src/components/OcSortableRow.vue",
|
|
703
787
|
"snippet": "@birdycom/omniaui/snippets/sortable-row.html"
|
|
704
788
|
},
|
|
789
|
+
{
|
|
790
|
+
"name": "OcSpecList",
|
|
791
|
+
"kind": "component",
|
|
792
|
+
"file": "src/components/OcSpecList.vue",
|
|
793
|
+
"snippet": "@birdycom/omniaui/snippets/spec-list.html"
|
|
794
|
+
},
|
|
705
795
|
{
|
|
706
796
|
"name": "OcSpinner",
|
|
707
797
|
"kind": "component",
|
|
@@ -744,6 +834,12 @@
|
|
|
744
834
|
"file": "src/components/OcStepper.vue",
|
|
745
835
|
"snippet": "@birdycom/omniaui/snippets/stepper.html"
|
|
746
836
|
},
|
|
837
|
+
{
|
|
838
|
+
"name": "OcStock",
|
|
839
|
+
"kind": "component",
|
|
840
|
+
"file": "src/components/OcStock.vue",
|
|
841
|
+
"snippet": "@birdycom/omniaui/snippets/stock.html"
|
|
842
|
+
},
|
|
747
843
|
{
|
|
748
844
|
"name": "OcSwitch",
|
|
749
845
|
"kind": "component",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@birdycom/omniaui-vue",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.6",
|
|
4
4
|
"description": "OmniaUI for Vue 3: one single-file component per OmniaUI component and block, rendering the exact markup of the CSS packages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,7 @@ withDefaults(
|
|
|
23
23
|
<header class="oc-block-appbar">
|
|
24
24
|
<slot name="toggle">
|
|
25
25
|
<label v-if="toggleFor" class="oc-btn oc-btn--ghost oc-btn--icon" :for="toggleFor" :title="toggleLabel">
|
|
26
|
-
<svg viewBox="0 0 24 24" fill="
|
|
26
|
+
<svg data-icon="mdi:menu" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
|
|
27
27
|
<span class="oc-visually-hidden">{{ toggleLabel }}</span>
|
|
28
28
|
</label>
|
|
29
29
|
</slot>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/**
|
|
3
3
|
* Card with title, actions, toolbar, table, bulk bar and footer. Put an <OcTable> in the default slot.
|
|
4
|
-
* Slots: actions (header buttons), toolbar (.oc-table-toolbar content: search, filter pills
|
|
4
|
+
* Slots: actions (header buttons), toolbar (.oc-table-toolbar content: search, filter pills),
|
|
5
5
|
* bulk (selection bar, shown when `selectedCount` > 0), default (table), footer (.oc-table-footer: entries text, page size, pagination).
|
|
6
6
|
* Classes: .oc-card.oc-block-datatable, -head, -title, -description, -body, -bulk, .oc-table-toolbar, .oc-table-footer
|
|
7
7
|
*/
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
<script setup lang="ts">
|
|
3
3
|
/**
|
|
4
4
|
* Profile / channel header: banner, overhanging avatar, name, meta, bio, actions and link tabs.
|
|
5
|
-
* Slots: avatar (initials or <img>), actions, bio
|
|
5
|
+
* Slots: avatar (initials or <img>), actions, bio, panel-0, panel-1 … (with panel slots the tabs switch on the page
|
|
6
|
+
* itself: radios + panels, CSS only; without them the tabs are links). Classes: .oc-block-profile (--compact), -banner, -bar, -avatar,
|
|
6
7
|
* -info, -name, -meta, -bio, -actions, -tabs, -tab (aria-current="page")
|
|
7
8
|
*/
|
|
8
|
-
import { computed } from 'vue'
|
|
9
|
+
import { computed, useSlots } from 'vue'
|
|
9
10
|
import { useUid } from '../composables/useUid'
|
|
10
11
|
|
|
11
12
|
export interface ProfileHeaderTab {
|
|
12
13
|
label: string
|
|
13
|
-
href
|
|
14
|
+
href?: string
|
|
14
15
|
current?: boolean
|
|
15
16
|
}
|
|
16
17
|
const props = withDefaults(
|
|
@@ -28,6 +29,8 @@ const props = withDefaults(
|
|
|
28
29
|
{ tabs: () => [], tabsLabel: 'Profile sections', headingLevel: 1 },
|
|
29
30
|
)
|
|
30
31
|
const nameId = useUid('oc-profile-name')
|
|
32
|
+
const slots = useSlots()
|
|
33
|
+
const panels = computed(() => props.tabs.some((_, i) => Boolean(slots[`panel-${i}`])))
|
|
31
34
|
const bannerStyle = computed(() => (props.banner ? `--oc-profile-banner: url("${props.banner}")` : undefined))
|
|
32
35
|
</script>
|
|
33
36
|
|
|
@@ -43,7 +46,15 @@ const bannerStyle = computed(() => (props.banner ? `--oc-profile-banner: url("${
|
|
|
43
46
|
</div>
|
|
44
47
|
<div v-if="$slots.actions" class="oc-block-profile-actions"><slot name="actions" /></div>
|
|
45
48
|
</div>
|
|
46
|
-
<
|
|
49
|
+
<template v-if="tabs.length && panels">
|
|
50
|
+
<div class="oc-block-profile-tabs" role="radiogroup" :aria-label="tabsLabel">
|
|
51
|
+
<label v-for="(tab, i) in tabs" :key="i" class="oc-block-profile-tab"><input type="radio" :name="`${nameId}-tab`" :checked="tab.current ?? i === 0">{{ tab.label }}</label>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="oc-block-profile-panels">
|
|
54
|
+
<div v-for="(tab, i) in tabs" :key="i" class="oc-block-profile-panel"><slot :name="`panel-${i}`" /></div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
<nav v-else-if="tabs.length" class="oc-block-profile-tabs" :aria-label="tabsLabel">
|
|
47
58
|
<a v-for="(tab, i) in tabs" :key="i" class="oc-block-profile-tab" :href="tab.href" :aria-current="tab.current ? 'page' : undefined">{{ tab.label }}</a>
|
|
48
59
|
</nav>
|
|
49
60
|
</section>
|
|
@@ -10,7 +10,7 @@ withDefaults(defineProps<{ items?: AttachmentFile[]; stack?: boolean; as?: 'ul'
|
|
|
10
10
|
as: 'ul',
|
|
11
11
|
label: 'Files in this message',
|
|
12
12
|
items: () => [
|
|
13
|
-
{ name: 'Quote kitchen
|
|
13
|
+
{ name: 'Quote kitchen Project 1 v2.pdf', size: '1.2 MB', href: '#quote.pdf' },
|
|
14
14
|
{ name: 'Measurements ground floor.xlsx', size: '86 KB', href: '#measurements.xlsx' },
|
|
15
15
|
{ name: 'Contract addendum.docx', size: '240 KB', href: '#contract.docx' },
|
|
16
16
|
{ name: 'Plans architect.zip', size: '14.8 MB', href: '#plans.zip' },
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!-- File: packages/vue/src/components/OcAvatarPicker.vue | Map: props -> preview + file input -> text and buttons -> change event on mount -->
|
|
2
|
+
<script setup lang="ts">
|
|
3
|
+
/** Avatar or logo picker with a preview, Upload and Remove, and drag and drop. Emits change (File or null) and invalid (File, reason) for a wrong type or a file over maxKb. */
|
|
4
|
+
import { onMounted, useId, useTemplateRef } from 'vue'
|
|
5
|
+
import { bindAvatarPicker } from '../../../ui/src/form-extras.js'
|
|
6
|
+
|
|
7
|
+
withDefaults(defineProps<{ initials: string; label?: string; hint?: string; logo?: boolean; name?: string; accept?: string; maxKb?: number }>(), { label: 'Profile picture', logo: false, accept: 'image/*' })
|
|
8
|
+
const emit = defineEmits<{ change: [file: File | null]; invalid: [file: File, reason: string] }>()
|
|
9
|
+
const id = useId()
|
|
10
|
+
const root = useTemplateRef<HTMLDivElement>('root')
|
|
11
|
+
onMounted(() => {
|
|
12
|
+
if (!root.value) return
|
|
13
|
+
bindAvatarPicker(root.value)
|
|
14
|
+
root.value.addEventListener('oc-avatar-change', (e) => emit('change', (e as CustomEvent<{ file: File | null }>).detail.file))
|
|
15
|
+
root.value.addEventListener('oc-avatar-invalid', (e) => { const d = (e as CustomEvent<{ file: File; reason: string }>).detail; emit('invalid', d.file, d.reason) })
|
|
16
|
+
})
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<div ref="root" :class="['oc-avatar-picker', logo && 'oc-avatar-picker--square oc-avatar-picker--logo']" :data-oc-max-kb="maxKb">
|
|
21
|
+
<label class="oc-avatar-picker__preview" :for="id" title="Choose an image">
|
|
22
|
+
<span data-oc-initials>{{ initials }}</span>
|
|
23
|
+
<input :id="id" class="oc-avatar-picker__file" type="file" :accept="accept" :name="name">
|
|
24
|
+
</label>
|
|
25
|
+
<div class="oc-avatar-picker__text">
|
|
26
|
+
<span class="oc-avatar-picker__label">{{ label }}</span>
|
|
27
|
+
<span v-if="hint" class="oc-avatar-picker__hint">{{ hint }}</span>
|
|
28
|
+
<div class="oc-avatar-picker__actions">
|
|
29
|
+
<button type="button" class="oc-btn oc-btn--outline oc-btn--sm" data-oc-avatar-upload><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M9 16v-6H5l7-7l7 7h-4v6zm-4 4v-2h14v2z" /></svg>Upload</button>
|
|
30
|
+
<button type="button" class="oc-btn oc-btn--ghost oc-btn--sm" data-oc-avatar-remove><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12z" /></svg>Remove</button>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!-- File: packages/vue/src/components/OcBarcode.vue | Map: props -> encode -> svg + digits -->
|
|
2
|
+
<script setup lang="ts">
|
|
3
|
+
/** EAN-13, EAN-8, UPC-A or Code 128 as SVG; shows the reason when the value cannot be encoded. */
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
import { barsToSvg, encodeBarcode } from '../../../ui/src/barcode.js'
|
|
6
|
+
|
|
7
|
+
const props = withDefaults(defineProps<{ value: string; format?: 'auto' | 'EAN13' | 'EAN8' | 'UPC' | 'CODE128'; digits?: boolean; size?: 'md' | 'hero' | 'compact' }>(), { format: 'auto', digits: true, size: 'md' })
|
|
8
|
+
const result = computed(() => {
|
|
9
|
+
try {
|
|
10
|
+
const { bits, text } = encodeBarcode(props.value, props.format)
|
|
11
|
+
return { svg: barsToSvg(bits, `Barcode ${text}`), text, error: '' }
|
|
12
|
+
} catch (err) {
|
|
13
|
+
return { svg: '', text: props.value, error: (err as Error).message }
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<figure :class="['oc-barcode', size !== 'md' && `oc-barcode--${size}`]" :data-error="result.error ? '' : undefined">
|
|
20
|
+
<span v-if="result.svg" style="display: contents" v-html="result.svg"></span>
|
|
21
|
+
<figcaption v-if="digits || result.error" class="oc-barcode__digits">{{ result.error ? `${value}: ${result.error}` : result.text }}</figcaption>
|
|
22
|
+
</figure>
|
|
23
|
+
</template>
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Breadcrumb. Pass `items` (the last one is the current page) or use the default slot.
|
|
4
|
+
* `icon` per item is a webicon name (mdi:home-outline …), drawn with <iconify-icon>; separator="chevron" puts › between.
|
|
5
|
+
*/
|
|
3
6
|
export interface BreadcrumbItem {
|
|
4
7
|
label: string
|
|
5
8
|
href?: string
|
|
9
|
+
icon?: string
|
|
6
10
|
}
|
|
7
|
-
withDefaults(defineProps<{ items?: BreadcrumbItem[]; label?: string }>(), {
|
|
11
|
+
withDefaults(defineProps<{ items?: BreadcrumbItem[]; label?: string; separator?: 'slash' | 'chevron' }>(), {
|
|
8
12
|
items: () => [],
|
|
9
13
|
label: 'Breadcrumb',
|
|
14
|
+
separator: 'slash',
|
|
10
15
|
})
|
|
11
16
|
</script>
|
|
12
17
|
|
|
13
18
|
<template>
|
|
14
|
-
<nav class="oc-breadcrumb" :aria-label="label">
|
|
19
|
+
<nav :class="['oc-breadcrumb', separator === 'chevron' && 'oc-breadcrumb--chevron']" :aria-label="label">
|
|
15
20
|
<slot>
|
|
16
21
|
<template v-for="(item, i) in items" :key="i">
|
|
17
|
-
<a v-if="item.href && i < items.length - 1" class="oc-breadcrumb-item" :href="item.href"
|
|
18
|
-
|
|
22
|
+
<a v-if="item.href && i < items.length - 1" class="oc-breadcrumb-item" :href="item.href"
|
|
23
|
+
><iconify-icon v-if="item.icon" :icon="item.icon" aria-hidden="true" />{{ item.label }}</a
|
|
24
|
+
>
|
|
25
|
+
<span v-else class="oc-breadcrumb-item" aria-current="page"
|
|
26
|
+
><iconify-icon v-if="item.icon" :icon="item.icon" aria-hidden="true" />{{ item.label }}</span
|
|
27
|
+
>
|
|
19
28
|
</template>
|
|
20
29
|
</slot>
|
|
21
30
|
</nav>
|
|
@@ -2,15 +2,20 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Button. Renders <a> when `href` is set, otherwise <button>.
|
|
4
4
|
* Classes: .oc-btn + --secondary/--outline/--ghost/--link/--destructive/--success/--gradient/--glass,
|
|
5
|
-
* --
|
|
5
|
+
* --soft-primary/-success/-warning/-destructive/-info (row actions), --plain (icon only, no surface),
|
|
6
|
+
* --xs/--sm/--lg, --icon, --pill, --inline (link button inside running text). `loading` sets aria-busy (spinner).
|
|
6
7
|
*/
|
|
7
8
|
withDefaults(
|
|
8
9
|
defineProps<{
|
|
9
|
-
variant?:
|
|
10
|
+
variant?:
|
|
11
|
+
| 'default' | 'secondary' | 'outline' | 'ghost' | 'link' | 'destructive' | 'success' | 'gradient' | 'glass'
|
|
12
|
+
| 'soft-primary' | 'soft-success' | 'soft-warning' | 'soft-destructive' | 'soft-info' | 'plain'
|
|
10
13
|
size?: 'xs' | 'sm' | 'md' | 'lg'
|
|
11
14
|
icon?: boolean
|
|
12
15
|
pill?: boolean
|
|
13
16
|
inline?: boolean
|
|
17
|
+
loading?: boolean
|
|
18
|
+
disabled?: boolean
|
|
14
19
|
href?: string
|
|
15
20
|
type?: 'button' | 'submit' | 'reset'
|
|
16
21
|
}>(),
|
|
@@ -22,6 +27,7 @@ withDefaults(
|
|
|
22
27
|
<a
|
|
23
28
|
v-if="href"
|
|
24
29
|
:href="href"
|
|
30
|
+
:aria-busy="loading || undefined"
|
|
25
31
|
:class="[
|
|
26
32
|
'oc-btn',
|
|
27
33
|
variant !== 'default' && `oc-btn--${variant}`,
|
|
@@ -36,6 +42,8 @@ withDefaults(
|
|
|
36
42
|
<button
|
|
37
43
|
v-else
|
|
38
44
|
:type="type"
|
|
45
|
+
:aria-busy="loading || undefined"
|
|
46
|
+
:disabled="disabled || loading"
|
|
39
47
|
:class="[
|
|
40
48
|
'oc-btn',
|
|
41
49
|
variant !== 'default' && `oc-btn--${variant}`,
|
|
@@ -36,7 +36,7 @@ function onKeydown(e: KeyboardEvent) {
|
|
|
36
36
|
<div class="oc-chat-composer__bar">
|
|
37
37
|
<div v-if="$slots.tools" class="oc-chat-composer__tools"><slot name="tools" /></div>
|
|
38
38
|
<span v-if="hint" class="oc-chat-composer__hint">{{ hint }}</span>
|
|
39
|
-
<button type="submit" class="oc-chat-composer__send" aria-label="Send" :disabled="disabled"
|
|
39
|
+
<button type="submit" class="oc-chat-composer__send" aria-label="Send" :disabled="disabled"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M2 21l21-9L2 3v7l15 2l-15 2z"/></svg></button>
|
|
40
40
|
</div>
|
|
41
41
|
</form>
|
|
42
42
|
</template>
|