@imaginario27/air-ui-ds 1.14.0 → 1.14.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.
- package/CHANGELOG.md +11 -0
- package/components/buttons/toggle/ToggleButton.vue +5 -0
- package/components/buttons/toggle/ToggleButtonGroup.vue +30 -12
- package/components/buttons/toggle/ToggleIconButton.vue +5 -0
- package/components/dropdowns/DropdownMenu.vue +23 -10
- package/components/forms/fields/ToggleButtonsGroupField.vue +5 -0
- package/components/forms/fields/checkbox/CheckboxGroupField.vue +56 -12
- package/components/layouts/headers/CompactHeader.vue +5 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ All notable changes to this package are documented in this file.
|
|
|
5
5
|
Historical releases were reconstructed from git history (GitHub repository) and npm publish dates.
|
|
6
6
|
Future releases will include detailed entries generated with Changesets.
|
|
7
7
|
|
|
8
|
+
## 1.14.0 - 2026-06-16
|
|
9
|
+
|
|
10
|
+
Release type: minor.
|
|
11
|
+
Commits found in range: 1.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
1. add CheckboxGroupField and refactor checkbox components ([da239fc](https://github.com/imaginario27/air-ui/commit/da239fcfb515038233a56089fcee4924081826f5))
|
|
16
|
+
|
|
17
|
+
- Package: @imaginario27/air-ui-ds.
|
|
18
|
+
|
|
8
19
|
## 1.13.13 - 2026-06-16
|
|
9
20
|
|
|
10
21
|
Release type: patch.
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
gapClass,
|
|
14
14
|
disabled ? 'opacity-disabled cursor-not-allowed' : '',
|
|
15
15
|
'self-start',
|
|
16
|
+
!transparent && 'bg-background-container-surface',
|
|
16
17
|
]"
|
|
17
18
|
@click="emitClick"
|
|
18
19
|
>
|
|
@@ -63,6 +64,10 @@ const props = defineProps({
|
|
|
63
64
|
default: false,
|
|
64
65
|
},
|
|
65
66
|
ariaLabel: String as PropType<string>,
|
|
67
|
+
transparent: {
|
|
68
|
+
type: Boolean as PropType<boolean>,
|
|
69
|
+
default: false,
|
|
70
|
+
},
|
|
66
71
|
})
|
|
67
72
|
|
|
68
73
|
// Emits
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
:aria-label="ariaLabel || 'Toggle options'"
|
|
6
6
|
:class="[
|
|
7
7
|
'flex',
|
|
8
|
-
groupStyle === ToggleButtonGroupStyle.GROUPED ? '
|
|
8
|
+
groupStyle === ToggleButtonGroupStyle.GROUPED ? '' : 'flex-wrap gap-3',
|
|
9
9
|
'w-fit',
|
|
10
10
|
'rounded-button'
|
|
11
11
|
]"
|
|
@@ -21,11 +21,8 @@
|
|
|
21
21
|
:icon="button.icon"
|
|
22
22
|
:iconPosition="'iconPosition' in button ? button.iconPosition : undefined"
|
|
23
23
|
:disabled
|
|
24
|
-
:
|
|
25
|
-
|
|
26
|
-
groupStyle === ToggleButtonGroupStyle.SEGMENTED && button.active && '!border-border-primary-brand-active',
|
|
27
|
-
!hasButtonBorder && 'rounded-button',
|
|
28
|
-
]"
|
|
24
|
+
:transparent
|
|
25
|
+
:class="buttonItemClass(button)"
|
|
29
26
|
@click="!disabled && handleButtonClick(button)"
|
|
30
27
|
/>
|
|
31
28
|
</template>
|
|
@@ -38,11 +35,8 @@
|
|
|
38
35
|
:size="button.size"
|
|
39
36
|
:icon="button.icon"
|
|
40
37
|
:disabled
|
|
41
|
-
:
|
|
42
|
-
|
|
43
|
-
groupStyle === ToggleButtonGroupStyle.SEGMENTED && button.active && '!border-border-primary-brand-active',
|
|
44
|
-
!hasButtonBorder && 'rounded-button',
|
|
45
|
-
]"
|
|
38
|
+
:transparent
|
|
39
|
+
:class="buttonItemClass(button)"
|
|
46
40
|
@click="!disabled && handleButtonClick(button)"
|
|
47
41
|
/>
|
|
48
42
|
</template>
|
|
@@ -51,7 +45,7 @@
|
|
|
51
45
|
|
|
52
46
|
<script setup lang="ts">
|
|
53
47
|
// Props
|
|
54
|
-
defineProps({
|
|
48
|
+
const props = defineProps({
|
|
55
49
|
id: String as PropType<string>,
|
|
56
50
|
ariaLabel: String as PropType<string>,
|
|
57
51
|
modelValue: {
|
|
@@ -90,11 +84,35 @@ defineProps({
|
|
|
90
84
|
type: Boolean as PropType<boolean>,
|
|
91
85
|
default: false,
|
|
92
86
|
},
|
|
87
|
+
transparent: {
|
|
88
|
+
type: Boolean as PropType<boolean>,
|
|
89
|
+
default: false,
|
|
90
|
+
},
|
|
93
91
|
})
|
|
94
92
|
|
|
95
93
|
// Emits
|
|
96
94
|
const emit = defineEmits(['update:modelValue'])
|
|
97
95
|
|
|
96
|
+
// Computed classes
|
|
97
|
+
const groupedButtonClass = computed(() =>
|
|
98
|
+
props.groupStyle === ToggleButtonGroupStyle.GROUPED
|
|
99
|
+
? 'border-y border-r border-border-default rounded-none first:border-l first:rounded-l-button last:rounded-r-button'
|
|
100
|
+
: false
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
const segmentedButtonClass = computed(() =>
|
|
104
|
+
props.groupStyle === ToggleButtonGroupStyle.SEGMENTED && props.hasButtonBorder
|
|
105
|
+
? 'border border-border-default rounded-button'
|
|
106
|
+
: false
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
const buttonItemClass = (button: ToggleButtonItem) => [
|
|
110
|
+
groupedButtonClass.value,
|
|
111
|
+
segmentedButtonClass.value,
|
|
112
|
+
props.groupStyle === ToggleButtonGroupStyle.SEGMENTED && button.active && '!border-border-primary-brand-active',
|
|
113
|
+
!props.hasButtonBorder && 'rounded-button',
|
|
114
|
+
]
|
|
115
|
+
|
|
98
116
|
// Handlers
|
|
99
117
|
const handleButtonClick = (button: ToggleButtonItem) => {
|
|
100
118
|
if (button?.action) {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
buttonSizeClass,
|
|
12
12
|
disabled ? 'opacity-disabled cursor-not-allowed' : '',
|
|
13
13
|
'self-start',
|
|
14
|
+
!transparent && 'bg-background-container-surface',
|
|
14
15
|
]"
|
|
15
16
|
@click="emitClick"
|
|
16
17
|
>
|
|
@@ -42,6 +43,10 @@ const props = defineProps({
|
|
|
42
43
|
default: false,
|
|
43
44
|
},
|
|
44
45
|
ariaLabel: String as PropType<string>,
|
|
46
|
+
transparent: {
|
|
47
|
+
type: Boolean as PropType<boolean>,
|
|
48
|
+
default: false,
|
|
49
|
+
},
|
|
45
50
|
})
|
|
46
51
|
|
|
47
52
|
// Emits
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
]"
|
|
46
46
|
:style="{
|
|
47
47
|
...computedTeleportStyle,
|
|
48
|
-
zIndex:
|
|
48
|
+
zIndex: zIndex
|
|
49
49
|
}"
|
|
50
50
|
@mouseenter="onDropdownMouseEnter"
|
|
51
51
|
@mouseleave="onDropdownMouseLeave"
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
]"
|
|
152
152
|
:style="{
|
|
153
153
|
...(!positionClass ? positionOffsetStyle : {}),
|
|
154
|
-
zIndex:
|
|
154
|
+
zIndex: zIndex
|
|
155
155
|
}"
|
|
156
156
|
@mouseenter="onDropdownMouseEnter"
|
|
157
157
|
@mouseleave="onDropdownMouseLeave"
|
|
@@ -304,6 +304,10 @@ const props = defineProps({
|
|
|
304
304
|
type: [String, Object] as PropType<PrefetchOnStrategy>,
|
|
305
305
|
default: PrefetchOn.VISIBILITY,
|
|
306
306
|
},
|
|
307
|
+
isSticky: {
|
|
308
|
+
type: Boolean as PropType<boolean>,
|
|
309
|
+
default: false,
|
|
310
|
+
},
|
|
307
311
|
})
|
|
308
312
|
|
|
309
313
|
// Refs
|
|
@@ -491,14 +495,23 @@ const computedTeleportStyle = computed<CSSProperties>(() => {
|
|
|
491
495
|
if (secondary === 'top') top = a.top
|
|
492
496
|
if (secondary === 'bottom') top = a.bottom - d.height
|
|
493
497
|
|
|
494
|
-
return
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
498
|
+
return props.isSticky
|
|
499
|
+
? {
|
|
500
|
+
position: 'fixed',
|
|
501
|
+
top: `${top}px`,
|
|
502
|
+
left: `${left}px`,
|
|
503
|
+
width: `${a.width}px`,
|
|
504
|
+
visibility: 'visible',
|
|
505
|
+
zIndex: props.zIndex,
|
|
506
|
+
}
|
|
507
|
+
: {
|
|
508
|
+
position: 'absolute',
|
|
509
|
+
top: `${top + window.scrollY}px`,
|
|
510
|
+
left: `${left + window.scrollX}px`,
|
|
511
|
+
width: `${a.width}px`,
|
|
512
|
+
visibility: 'visible',
|
|
513
|
+
zIndex: props.zIndex,
|
|
514
|
+
}
|
|
502
515
|
})
|
|
503
516
|
|
|
504
517
|
// Styles for non-teleported dropdown
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
:groupStyle
|
|
34
34
|
:disabled
|
|
35
35
|
:onlyIcon
|
|
36
|
+
:transparent
|
|
36
37
|
@update:modelValue="emit('update:modelValue', $event)"
|
|
37
38
|
/>
|
|
38
39
|
|
|
@@ -73,6 +74,10 @@ defineProps({
|
|
|
73
74
|
type: Boolean as PropType<boolean>,
|
|
74
75
|
default: false,
|
|
75
76
|
},
|
|
77
|
+
transparent: {
|
|
78
|
+
type: Boolean as PropType<boolean>,
|
|
79
|
+
default: false,
|
|
80
|
+
},
|
|
76
81
|
})
|
|
77
82
|
|
|
78
83
|
// Emits
|
|
@@ -20,17 +20,12 @@
|
|
|
20
20
|
:error="error"
|
|
21
21
|
/>
|
|
22
22
|
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
'grid gap-4',
|
|
30
|
-
'grid-cols-1',
|
|
31
|
-
'sm:grid-cols-2',
|
|
32
|
-
]
|
|
33
|
-
]"
|
|
23
|
+
<Grid
|
|
24
|
+
v-if="layout === ListLayout.GRID"
|
|
25
|
+
:cols="gridCols"
|
|
26
|
+
:tabletCols="gridTabletCols"
|
|
27
|
+
:mobileCols="gridMobileCols"
|
|
28
|
+
:gapClass="gridGapClass"
|
|
34
29
|
>
|
|
35
30
|
<CheckboxField
|
|
36
31
|
v-for="option in options"
|
|
@@ -43,8 +38,35 @@
|
|
|
43
38
|
:disabled="option.disabled ? option.disabled : disabled"
|
|
44
39
|
:helpText="option.helpText"
|
|
45
40
|
:inverse="inverse"
|
|
46
|
-
@update:
|
|
41
|
+
@update:model-value="handleChange(option.value, $event)"
|
|
47
42
|
/>
|
|
43
|
+
</Grid>
|
|
44
|
+
|
|
45
|
+
<div
|
|
46
|
+
v-else
|
|
47
|
+
:class="[
|
|
48
|
+
orientation === Orientation.VERTICAL
|
|
49
|
+
? ['flex flex-col gap-4', listClass]
|
|
50
|
+
: ['flex flex-wrap gap-6', listClass]
|
|
51
|
+
]"
|
|
52
|
+
>
|
|
53
|
+
<div
|
|
54
|
+
v-for="option in options"
|
|
55
|
+
:key="option.id"
|
|
56
|
+
:class="orientation === Orientation.HORIZONTAL ? 'w-fit' : 'w-full'"
|
|
57
|
+
>
|
|
58
|
+
<CheckboxField
|
|
59
|
+
:id="option.id.toString()"
|
|
60
|
+
:modelValue="isChecked(option.value)"
|
|
61
|
+
:label="option.label"
|
|
62
|
+
:ariaLabel="option.ariaLabel"
|
|
63
|
+
:required
|
|
64
|
+
:disabled="option.disabled ? option.disabled : disabled"
|
|
65
|
+
:helpText="option.helpText"
|
|
66
|
+
:inverse="inverse"
|
|
67
|
+
@update:model-value="handleChange(option.value, $event)"
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
48
70
|
</div>
|
|
49
71
|
|
|
50
72
|
<!-- Help Text or Error Message (bottom) -->
|
|
@@ -101,6 +123,28 @@ const props = defineProps({
|
|
|
101
123
|
default: Orientation.VERTICAL,
|
|
102
124
|
validator: (value: Orientation) => Object.values(Orientation).includes(value),
|
|
103
125
|
},
|
|
126
|
+
layout: {
|
|
127
|
+
type: String as PropType<ListLayout>,
|
|
128
|
+
default: ListLayout.LIST,
|
|
129
|
+
validator: (value: ListLayout) => Object.values(ListLayout).includes(value),
|
|
130
|
+
},
|
|
131
|
+
gridCols: {
|
|
132
|
+
type: Number as PropType<number>,
|
|
133
|
+
default: 3,
|
|
134
|
+
},
|
|
135
|
+
gridTabletCols: {
|
|
136
|
+
type: Number as PropType<number>,
|
|
137
|
+
default: 2,
|
|
138
|
+
},
|
|
139
|
+
gridMobileCols: {
|
|
140
|
+
type: Number as PropType<number>,
|
|
141
|
+
default: 1,
|
|
142
|
+
},
|
|
143
|
+
gridGapClass: {
|
|
144
|
+
type: String as PropType<string>,
|
|
145
|
+
default: 'gap-4',
|
|
146
|
+
},
|
|
147
|
+
listClass: String as PropType<string>,
|
|
104
148
|
})
|
|
105
149
|
|
|
106
150
|
// Emits
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<header
|
|
3
3
|
:class="[
|
|
4
|
-
isSticky && 'sticky top-0 z-
|
|
4
|
+
isSticky && 'sticky top-0 z-40',
|
|
5
5
|
]"
|
|
6
6
|
>
|
|
7
7
|
<slot name="top-header" />
|
|
@@ -82,10 +82,11 @@
|
|
|
82
82
|
</div>
|
|
83
83
|
|
|
84
84
|
<!-- User Menu -->
|
|
85
|
-
<DropdownMenu
|
|
85
|
+
<DropdownMenu
|
|
86
86
|
v-if="userMenuItems.length && userFullname"
|
|
87
87
|
class="min-w-[200px]"
|
|
88
88
|
:positionYOffset="submenuYOffset"
|
|
89
|
+
:isSticky
|
|
89
90
|
>
|
|
90
91
|
<template #activator>
|
|
91
92
|
<Avatar
|
|
@@ -114,9 +115,10 @@
|
|
|
114
115
|
|
|
115
116
|
<!-- Mobile menu -->
|
|
116
117
|
<template v-if="isMobile && showMobileMenuToggle">
|
|
117
|
-
<DropdownMenu
|
|
118
|
+
<DropdownMenu
|
|
118
119
|
:class="navMobileMenuClass"
|
|
119
120
|
:positionYOffset="submenuYOffset"
|
|
121
|
+
:isSticky
|
|
120
122
|
>
|
|
121
123
|
<template #activator>
|
|
122
124
|
<ActionIconButton
|