@imaginario27/air-ui-ds 1.4.7 → 1.6.0
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 +12 -1
- package/components/forms/Checkbox.vue +90 -0
- package/components/forms/fields/CheckboxField.vue +10 -56
- package/components/forms/fields/SelectField.vue +7 -2
- package/components/forms/fields/SlotField.vue +70 -0
- package/components/icons/ContainedIcon.vue +16 -1
- package/models/enums/formFields.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,18 @@ 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.
|
|
8
|
+
## 1.5.0 - 2026-03-23
|
|
9
|
+
|
|
10
|
+
Release type: minor.
|
|
11
|
+
Commits found in range: 1.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
1. add new standalone checkbox component and fixes style issues ([560de2b](https://github.com/imaginario27/air-ui/commit/560de2b7f700565c087790c1eb3c581c0b782ba9))
|
|
16
|
+
|
|
17
|
+
- Package: @imaginario27/air-ui-ds.
|
|
18
|
+
|
|
19
|
+
## 1.4.7 - 2026-03-21
|
|
9
20
|
|
|
10
21
|
Release type: patch.
|
|
11
22
|
Commits found in range: 1.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<input
|
|
4
|
+
:id="id"
|
|
5
|
+
type="checkbox"
|
|
6
|
+
:checked="modelValue"
|
|
7
|
+
class="hidden"
|
|
8
|
+
:disabled="disabled"
|
|
9
|
+
@change="handleNativeChange"
|
|
10
|
+
>
|
|
11
|
+
|
|
12
|
+
<div
|
|
13
|
+
:class="[
|
|
14
|
+
'flex items-center justify-center',
|
|
15
|
+
controlFieldSizeClass,
|
|
16
|
+
'border',
|
|
17
|
+
'rounded',
|
|
18
|
+
'transition-colors',
|
|
19
|
+
modelValue ? 'bg-background-primary-brand-checked border-border-primary-brand-active' : 'bg-neutral-white border-border-default',
|
|
20
|
+
disabled ? 'bg-background-neutral-disabled cursor-not-allowed' : 'cursor-pointer'
|
|
21
|
+
]"
|
|
22
|
+
@click="toggleCheckbox"
|
|
23
|
+
>
|
|
24
|
+
<Icon
|
|
25
|
+
v-if="modelValue"
|
|
26
|
+
name="mdi:check-bold"
|
|
27
|
+
:iconClass="[
|
|
28
|
+
checkboxIconSizeClass,
|
|
29
|
+
disabled ? '!text-icon-neutral-disabled' : '!text-icon-neutral-on-filled-bg'
|
|
30
|
+
]"
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup lang="ts">
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
id: {
|
|
39
|
+
type: String as PropType<string>,
|
|
40
|
+
required: true,
|
|
41
|
+
},
|
|
42
|
+
modelValue: {
|
|
43
|
+
type: Boolean as PropType<boolean>,
|
|
44
|
+
default: false,
|
|
45
|
+
},
|
|
46
|
+
disabled: {
|
|
47
|
+
type: Boolean as PropType<boolean>,
|
|
48
|
+
default: false,
|
|
49
|
+
},
|
|
50
|
+
size: {
|
|
51
|
+
type: String as PropType<ControlFieldSize>,
|
|
52
|
+
default: ControlFieldSize.MD,
|
|
53
|
+
validator: (value: ControlFieldSize) => Object.values(ControlFieldSize).includes(value),
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
const emit = defineEmits(['update:modelValue'])
|
|
58
|
+
|
|
59
|
+
const controlFieldSizeClass = computed(() => {
|
|
60
|
+
const sizeVariant = {
|
|
61
|
+
[ControlFieldSize.XS]: 'w-[16px] h-[16px] min-w-[16px] min-h-[16px]',
|
|
62
|
+
[ControlFieldSize.SM]: 'w-[20px] h-[20px] min-w-[20px] min-h-[20px]',
|
|
63
|
+
[ControlFieldSize.MD]: 'w-[24px] h-[24px] min-w-[24px] min-h-[24px]',
|
|
64
|
+
[ControlFieldSize.LG]: 'w-[32px] h-[32px] min-w-[32px] min-h-[32px]',
|
|
65
|
+
}
|
|
66
|
+
return sizeVariant[props.size as ControlFieldSize] || 'w-[24px] h-[24px] min-w-[24px] min-h-[24px]'
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const checkboxIconSizeClass = computed(() => {
|
|
70
|
+
const sizeVariant = {
|
|
71
|
+
[ControlFieldSize.XS]: '!w-[12px] !h-[12px] !min-w-[12px] !min-h-[12px]',
|
|
72
|
+
[ControlFieldSize.SM]: '!w-[14px] !h-[14px] !min-w-[14px] !min-h-[14px]',
|
|
73
|
+
[ControlFieldSize.MD]: '!w-[16px] !h-[16px] !min-w-[16px] !min-h-[16px]',
|
|
74
|
+
[ControlFieldSize.LG]: '!w-[20px] !h-[20px] !min-w-[20px] !min-h-[20px]',
|
|
75
|
+
}
|
|
76
|
+
return sizeVariant[props.size as ControlFieldSize] || '!w-[16px] !h-[16px] !min-w-[16px] !min-h-[16px]'
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const toggleCheckbox = () => {
|
|
80
|
+
if (props.disabled) return
|
|
81
|
+
|
|
82
|
+
emit('update:modelValue', !props.modelValue)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const handleNativeChange = () => {
|
|
86
|
+
if (props.disabled) return
|
|
87
|
+
|
|
88
|
+
emit('update:modelValue', !props.modelValue)
|
|
89
|
+
}
|
|
90
|
+
</script>
|
|
@@ -30,39 +30,13 @@
|
|
|
30
30
|
v-html="label"
|
|
31
31
|
/>
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
:
|
|
36
|
-
type="checkbox"
|
|
37
|
-
:checked="modelValue"
|
|
38
|
-
class="hidden"
|
|
33
|
+
<Checkbox
|
|
34
|
+
:id="id"
|
|
35
|
+
:modelValue="modelValue"
|
|
39
36
|
:disabled="disabled"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<!-- Custom Checkbox -->
|
|
44
|
-
<div
|
|
45
|
-
:class="[
|
|
46
|
-
'flex items-center justify-center',
|
|
47
|
-
controlFieldSizeClass,
|
|
48
|
-
'border',
|
|
49
|
-
'rounded',
|
|
50
|
-
'flex items-center justify-center',
|
|
51
|
-
'transition-colors',
|
|
52
|
-
modelValue ? 'bg-background-primary-brand-checked border-border-primary-brand-active' : 'bg-neutral-white border-border-default',
|
|
53
|
-
disabled ? 'bg-background-neutral-disabled cursor-not-allowed' : 'cursor-pointer'
|
|
54
|
-
]"
|
|
55
|
-
@click="toggleCheckbox"
|
|
56
|
-
>
|
|
57
|
-
<Icon
|
|
58
|
-
v-if="modelValue"
|
|
59
|
-
name="mdi:check-bold"
|
|
60
|
-
:iconClass="[
|
|
61
|
-
checkboxIconSizeClass,
|
|
62
|
-
disabled ? '!text-icon-neutral-disabled' : '!text-icon-neutral-on-filled-bg'
|
|
63
|
-
]"
|
|
64
|
-
/>
|
|
65
|
-
</div>
|
|
37
|
+
:size="size"
|
|
38
|
+
@update:modelValue="handleCheckboxUpdate"
|
|
39
|
+
/>
|
|
66
40
|
|
|
67
41
|
<!-- Label (natural position) -->
|
|
68
42
|
<label
|
|
@@ -144,24 +118,10 @@ const validationMode = useInjectedValidationMode()
|
|
|
144
118
|
const hasError = computed(() => props.error !== '')
|
|
145
119
|
|
|
146
120
|
// Computed classes
|
|
147
|
-
const controlFieldSizeClass = computed(() => {
|
|
148
|
-
const sizeVariant = {
|
|
149
|
-
[ControlFieldSize.MD]: 'w-[24px] h-[24px] min-w-[24px] min-h-[24px]',
|
|
150
|
-
[ControlFieldSize.LG]: 'w-[32px] h-[32px] min-w-[32px] min-h-[32px]',
|
|
151
|
-
}
|
|
152
|
-
return sizeVariant[props.size as ControlFieldSize] || 'w-[24px] h-[24px] min-w-[24px] min-h-[24px]'
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
const checkboxIconSizeClass = computed(() => {
|
|
156
|
-
const sizeVariant = {
|
|
157
|
-
[ControlFieldSize.MD]: '!w-[16px] !h-[16px] !min-w-[16px] !min-h-[16px]',
|
|
158
|
-
[ControlFieldSize.LG]: '!w-[20px] !h-[20px] !min-w-[20px] !min-h-[20px]',
|
|
159
|
-
}
|
|
160
|
-
return sizeVariant[props.size as ControlFieldSize] || '!w-[16px] !h-[16px] !min-w-[16px] !min-h-[16px]'
|
|
161
|
-
})
|
|
162
|
-
|
|
163
121
|
const labelSizeClass = computed(() => {
|
|
164
122
|
const sizeVariant = {
|
|
123
|
+
[ControlFieldSize.XS]: 'text-xs',
|
|
124
|
+
[ControlFieldSize.SM]: 'text-sm',
|
|
165
125
|
[ControlFieldSize.MD]: 'text-sm',
|
|
166
126
|
[ControlFieldSize.LG]: 'text-base',
|
|
167
127
|
}
|
|
@@ -169,20 +129,14 @@ const labelSizeClass = computed(() => {
|
|
|
169
129
|
})
|
|
170
130
|
|
|
171
131
|
// Handlers
|
|
172
|
-
const
|
|
173
|
-
if (validationMode.value === FormValidationMode.BLUR) {
|
|
174
|
-
runValidation()
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const toggleCheckbox = () => {
|
|
132
|
+
const handleCheckboxUpdate = (value: boolean) => {
|
|
179
133
|
if (props.disabled) return
|
|
180
134
|
|
|
181
135
|
if (validationMode.value === FormValidationMode.BLUR) {
|
|
182
136
|
runValidation()
|
|
183
137
|
}
|
|
184
138
|
|
|
185
|
-
emit('update:modelValue',
|
|
139
|
+
emit('update:modelValue', value)
|
|
186
140
|
}
|
|
187
141
|
|
|
188
142
|
const runValidation = () => {
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
:modelValue
|
|
34
34
|
:options
|
|
35
35
|
:type
|
|
36
|
-
:borderClass="hasError ? 'border border-border-error text-text-error' : 'border border-border-default'"
|
|
37
36
|
:placeholder="computedPlaceholder"
|
|
38
37
|
:size
|
|
39
38
|
:activeStyle
|
|
@@ -47,7 +46,7 @@
|
|
|
47
46
|
:allowDeselect
|
|
48
47
|
:isLoading="isLoadingOptions"
|
|
49
48
|
:loadingText
|
|
50
|
-
:selectBoxClass
|
|
49
|
+
:selectBoxClass="computedSelectBoxClass"
|
|
51
50
|
@update:modelValue="handleValueUpdate"
|
|
52
51
|
/>
|
|
53
52
|
|
|
@@ -186,6 +185,12 @@ const computedPlaceholder = computed(() => {
|
|
|
186
185
|
return props.placeholder
|
|
187
186
|
})
|
|
188
187
|
|
|
188
|
+
const computedSelectBoxClass = computed(() => {
|
|
189
|
+
const errorClass = hasError.value ? 'border-border-error text-text-error' : ''
|
|
190
|
+
|
|
191
|
+
return [errorClass, props.selectBoxClass].filter(Boolean).join(' ')
|
|
192
|
+
})
|
|
193
|
+
|
|
189
194
|
// Handlers
|
|
190
195
|
const handleValueUpdate = (newValue: string | number | (string | number)[] | null) => {
|
|
191
196
|
if (props.allowDeselect && !props.multiple) {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="['flex flex-col', 'w-full', 'gap-2']">
|
|
3
|
+
<!-- Label -->
|
|
4
|
+
<label
|
|
5
|
+
v-if="label"
|
|
6
|
+
:for="id"
|
|
7
|
+
:class="[
|
|
8
|
+
'text-sm',
|
|
9
|
+
'font-semibold',
|
|
10
|
+
'text-left',
|
|
11
|
+
hasError && 'text-text-error',
|
|
12
|
+
]"
|
|
13
|
+
>
|
|
14
|
+
{{ label }}
|
|
15
|
+
</label>
|
|
16
|
+
|
|
17
|
+
<!-- Slot container -->
|
|
18
|
+
<div
|
|
19
|
+
:id
|
|
20
|
+
:class="[disabled && 'cursor-not-allowed opacity-disabled']"
|
|
21
|
+
>
|
|
22
|
+
<slot
|
|
23
|
+
:id
|
|
24
|
+
:error
|
|
25
|
+
:hasError
|
|
26
|
+
:helpText
|
|
27
|
+
:disabled
|
|
28
|
+
:required
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<!-- Help / Error -->
|
|
33
|
+
<p
|
|
34
|
+
v-if="hasError || helpText"
|
|
35
|
+
:class="[
|
|
36
|
+
'text-xs text-left',
|
|
37
|
+
hasError ? 'text-text-error' : 'text-text-neutral-subtle',
|
|
38
|
+
]"
|
|
39
|
+
>
|
|
40
|
+
{{ hasError ? error : helpText }}
|
|
41
|
+
</p>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
// Props
|
|
47
|
+
const props = defineProps({
|
|
48
|
+
id: {
|
|
49
|
+
type: String as PropType<string>,
|
|
50
|
+
required: true,
|
|
51
|
+
},
|
|
52
|
+
label: String as PropType<string>,
|
|
53
|
+
helpText: String as PropType<string>,
|
|
54
|
+
error: {
|
|
55
|
+
type: String as PropType<string>,
|
|
56
|
+
default: '',
|
|
57
|
+
},
|
|
58
|
+
disabled: {
|
|
59
|
+
type: Boolean as PropType<boolean>,
|
|
60
|
+
default: false,
|
|
61
|
+
},
|
|
62
|
+
required: {
|
|
63
|
+
type: Boolean as PropType<boolean>,
|
|
64
|
+
default: false,
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// Computed
|
|
69
|
+
const hasError = computed(() => props.error !== '')
|
|
70
|
+
</script>
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
<Icon
|
|
15
15
|
:name="icon"
|
|
16
16
|
:mode
|
|
17
|
-
:iconClass="
|
|
17
|
+
:iconClass="finalIconClass"
|
|
18
|
+
v-bind="iconSizeProps"
|
|
18
19
|
/>
|
|
19
20
|
</div>
|
|
20
21
|
</template>
|
|
@@ -50,6 +51,10 @@ const props = defineProps({
|
|
|
50
51
|
default: IconContainerSize.XL,
|
|
51
52
|
validator: (value: IconContainerSize) => Object.values(IconContainerSize).includes(value),
|
|
52
53
|
},
|
|
54
|
+
iconSize: {
|
|
55
|
+
type: String as PropType<IconSize>,
|
|
56
|
+
validator: (value: IconSize) => Object.values(IconSize).includes(value),
|
|
57
|
+
},
|
|
53
58
|
})
|
|
54
59
|
|
|
55
60
|
// Computed classes
|
|
@@ -130,4 +135,14 @@ const iconSizeClass = computed(() => {
|
|
|
130
135
|
|
|
131
136
|
return sizeVariants[props.size as IconContainerSize] || 'w-[24px] h-[24px] min-w-[24px] min-h-[24px]'
|
|
132
137
|
})
|
|
138
|
+
|
|
139
|
+
const finalIconClass = computed(() => props.iconSize
|
|
140
|
+
? [iconColorClass.value]
|
|
141
|
+
: [iconSizeClass.value, iconColorClass.value]
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
const iconSizeProps = computed(() => (props.iconSize
|
|
145
|
+
? { size: props.iconSize }
|
|
146
|
+
: {}
|
|
147
|
+
))
|
|
133
148
|
</script>
|