@ulu/frontend-vue 0.5.16 → 0.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/dist/components/elements/UluButton.vue.d.ts +4 -0
- package/dist/components/elements/UluButton.vue.d.ts.map +1 -1
- package/dist/components/elements/UluButton.vue.js +31 -16
- package/dist/components/elements/UluIcon.vue.js +21 -36
- package/dist/components/forms/UluFormCheckbox.vue.d.ts +3 -19
- package/dist/components/forms/UluFormCheckbox.vue.d.ts.map +1 -1
- package/dist/components/forms/UluFormCheckbox.vue.js +10 -31
- package/dist/components/forms/UluFormFile.vue.d.ts +3 -25
- package/dist/components/forms/UluFormFile.vue.d.ts.map +1 -1
- package/dist/components/forms/UluFormFile.vue.js +11 -49
- package/dist/components/forms/UluFormItem.vue.d.ts +23 -8
- package/dist/components/forms/UluFormItem.vue.d.ts.map +1 -1
- package/dist/components/forms/UluFormItem.vue.js +126 -29
- package/dist/components/forms/UluFormLabel.vue.d.ts +24 -0
- package/dist/components/forms/UluFormLabel.vue.d.ts.map +1 -0
- package/dist/components/forms/UluFormLabel.vue.js +34 -0
- package/dist/components/forms/UluFormRadio.vue.d.ts +7 -25
- package/dist/components/forms/UluFormRadio.vue.d.ts.map +1 -1
- package/dist/components/forms/UluFormRadio.vue.js +11 -37
- package/dist/components/forms/UluFormSelect.vue.d.ts +7 -23
- package/dist/components/forms/UluFormSelect.vue.d.ts.map +1 -1
- package/dist/components/forms/UluFormSelect.vue.js +24 -43
- package/dist/components/forms/UluFormText.vue.d.ts +5 -23
- package/dist/components/forms/UluFormText.vue.d.ts.map +1 -1
- package/dist/components/forms/UluFormText.vue.js +10 -38
- package/dist/components/forms/UluFormTextarea.vue.d.ts +5 -23
- package/dist/components/forms/UluFormTextarea.vue.d.ts.map +1 -1
- package/dist/components/forms/UluFormTextarea.vue.js +10 -37
- package/dist/components/forms/UluSearchForm.vue.d.ts +24 -3
- package/dist/components/forms/UluSearchForm.vue.d.ts.map +1 -1
- package/dist/components/forms/UluSearchForm.vue.js +67 -22
- package/dist/components/index.d.ts +1 -0
- package/dist/components/systems/facets/UluFacetsFilterSelects.vue.d.ts.map +1 -1
- package/dist/components/systems/facets/UluFacetsFilterSelects.vue.js +21 -22
- package/dist/components/utils/UluAction.vue.d.ts +2 -0
- package/dist/components/utils/UluAction.vue.d.ts.map +1 -1
- package/dist/components/utils/UluAction.vue.js +9 -5
- package/dist/components/visualizations/UluProgressBar.vue.d.ts +2 -2
- package/dist/index.js +130 -128
- package/dist/plugins/core/index.d.ts.map +1 -1
- package/dist/plugins/core/index.js +17 -16
- package/dist/utils/props.d.ts +7 -0
- package/dist/utils/props.d.ts.map +1 -1
- package/dist/utils/props.js +8 -2
- package/lib/components/elements/UluButton.vue +18 -3
- package/lib/components/elements/UluIcon.vue +8 -26
- package/lib/components/forms/UluForm.vue +25 -25
- package/lib/components/forms/UluFormCheckbox.vue +11 -25
- package/lib/components/forms/UluFormFieldset.vue +6 -6
- package/lib/components/forms/UluFormFile.vue +10 -40
- package/lib/components/forms/UluFormItem.vue +150 -39
- package/lib/components/forms/UluFormLabel.vue +30 -0
- package/lib/components/forms/UluFormRadio.vue +15 -34
- package/lib/components/forms/UluFormSelect.vue +19 -24
- package/lib/components/forms/UluFormText.vue +7 -25
- package/lib/components/forms/UluFormTextarea.vue +7 -25
- package/lib/components/forms/UluSearchForm.vue +67 -19
- package/lib/components/forms/UluSelectableMenu.vue +62 -62
- package/lib/components/index.js +1 -0
- package/lib/components/systems/facets/UluFacetsFilterSelects.vue +11 -14
- package/lib/components/utils/UluAction.vue +6 -2
- package/lib/plugins/core/index.js +2 -1
- package/lib/utils/props.js +14 -0
- package/package.json +3 -3
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
:href="href"
|
|
5
5
|
:target="target"
|
|
6
6
|
:download="download"
|
|
7
|
+
:type="type"
|
|
7
8
|
class="button"
|
|
8
9
|
:class="[
|
|
9
10
|
{
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
import UluAction from "../utils/UluAction.vue";
|
|
39
40
|
import UluIcon from "./UluIcon.vue";
|
|
40
41
|
import { useModifiers } from "../../composables/useModifiers.js";
|
|
42
|
+
import { checkDeprecatedProps } from "../../utils/props.js";
|
|
41
43
|
|
|
42
44
|
const props = defineProps({
|
|
43
45
|
/**
|
|
@@ -70,9 +72,14 @@
|
|
|
70
72
|
*/
|
|
71
73
|
download: [Boolean, String],
|
|
72
74
|
/**
|
|
73
|
-
*
|
|
75
|
+
* **Deprecated!** Use `ariaLabel` instead.
|
|
76
|
+
* @deprecated Use `ariaLabel` instead.
|
|
74
77
|
*/
|
|
75
78
|
alt: String,
|
|
79
|
+
/**
|
|
80
|
+
* For icon only buttons or buttons that need an explicit aria-label
|
|
81
|
+
*/
|
|
82
|
+
ariaLabel: String,
|
|
76
83
|
/**
|
|
77
84
|
* If not using slot this sets the buttons text via prop
|
|
78
85
|
*/
|
|
@@ -112,7 +119,15 @@
|
|
|
112
119
|
/**
|
|
113
120
|
* Modifiers (to add any modifier classes based on base class [ie. 'tertiary'])
|
|
114
121
|
*/
|
|
115
|
-
modifiers: [String, Array]
|
|
122
|
+
modifiers: [String, Array],
|
|
123
|
+
/**
|
|
124
|
+
* Button type (e.g. 'submit', 'reset', 'button').
|
|
125
|
+
*/
|
|
126
|
+
type: String
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
checkDeprecatedProps(props, ["alt"], (name) => {
|
|
130
|
+
console.warn(`[@ulu/frontend-vue] UluButton: The "${ name }" prop is deprecated. Please use "ariaLabel" instead.`);
|
|
116
131
|
});
|
|
117
132
|
|
|
118
133
|
const { resolvedModifiers } = useModifiers({
|
|
@@ -131,7 +146,7 @@
|
|
|
131
146
|
});
|
|
132
147
|
|
|
133
148
|
const resolvedAriaLabel = computed(() => {
|
|
134
|
-
const label = props.alt || (props.iconOnly && props.text);
|
|
149
|
+
const label = props.ariaLabel || props.alt || (props.iconOnly && props.text);
|
|
135
150
|
return label ? label : null;
|
|
136
151
|
});
|
|
137
152
|
</script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
:class="commonClasses"
|
|
7
7
|
/>
|
|
8
8
|
<component
|
|
9
|
-
v-else-if="!useStaticFa && faIconComponent
|
|
9
|
+
v-else-if="!useStaticFa && faIconComponent"
|
|
10
10
|
:is="faIconComponent"
|
|
11
11
|
v-bind="iconProps"
|
|
12
12
|
:class="commonClasses"
|
|
@@ -19,19 +19,19 @@
|
|
|
19
19
|
</template>
|
|
20
20
|
|
|
21
21
|
<script setup>
|
|
22
|
-
import {
|
|
22
|
+
import { defineAsyncComponent, computed, inject } from "vue";
|
|
23
23
|
import { useIcon } from "../../composables/useIcon.js";
|
|
24
24
|
|
|
25
25
|
const uluCore = inject('uluCore');
|
|
26
|
-
const faIconComponent = ref(null);
|
|
27
26
|
const { getIconProps, getClassesFromDefinition } = useIcon();
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
const AsyncFontAwesomeIcon = defineAsyncComponent(() =>
|
|
29
|
+
import("@fortawesome/vue-fontawesome").then(m => m.FontAwesomeIcon)
|
|
30
|
+
);
|
|
30
31
|
|
|
31
32
|
const props = defineProps({
|
|
32
33
|
/**
|
|
33
34
|
* Icon definition can be string (fa classes), or array or object (any prop format FaIcon accepts)
|
|
34
|
-
* - This will override the 'type' prop if both are provided
|
|
35
35
|
*/
|
|
36
36
|
icon: [String, Array, Object, Boolean],
|
|
37
37
|
/**
|
|
@@ -86,28 +86,10 @@
|
|
|
86
86
|
'flow-inline': props.spaced
|
|
87
87
|
}));
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
// - Use watchEffect because we are watching reactive object property access (props)
|
|
91
|
-
// - Load FA if needed (so it's not included if it's unneeded)
|
|
92
|
-
// - Replace the empty component after load or if value changes
|
|
93
|
-
watchEffect(async () => {
|
|
94
|
-
// Only attempt to load the component if we are NOT using the static version
|
|
89
|
+
const faIconComponent = computed(() => {
|
|
95
90
|
if (!useStaticFa.value && resolvedDefinition.value) {
|
|
96
|
-
|
|
97
|
-
if (FaModule) {
|
|
98
|
-
faIconComponent.value = markRaw(FaModule.FontAwesomeIcon);
|
|
99
|
-
} else {
|
|
100
|
-
const componentPromise = defineAsyncComponent(async () => {
|
|
101
|
-
const module = await import("@fortawesome/vue-fontawesome");
|
|
102
|
-
FaModule = module;
|
|
103
|
-
return module.FontAwesomeIcon;
|
|
104
|
-
});
|
|
105
|
-
faIconComponent.value = markRaw(componentPromise);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
} else {
|
|
109
|
-
// If using static FA or no definition, ensure component is null
|
|
110
|
-
faIconComponent.value = null;
|
|
91
|
+
return AsyncFontAwesomeIcon;
|
|
111
92
|
}
|
|
93
|
+
return null;
|
|
112
94
|
});
|
|
113
95
|
</script>
|
|
@@ -14,29 +14,29 @@
|
|
|
14
14
|
</template>
|
|
15
15
|
|
|
16
16
|
<script setup>
|
|
17
|
-
defineProps({
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
17
|
+
defineProps({
|
|
18
|
+
/**
|
|
19
|
+
* The HTML element to use for the form.
|
|
20
|
+
*/
|
|
21
|
+
element: {
|
|
22
|
+
type: String,
|
|
23
|
+
default: 'form'
|
|
24
|
+
},
|
|
25
|
+
/**
|
|
26
|
+
* If true, applies the full-width styles to text inputs.
|
|
27
|
+
*/
|
|
28
|
+
fullWidth: Boolean,
|
|
29
|
+
/**
|
|
30
|
+
* If true, applies the full-width styles to select inputs.
|
|
31
|
+
*/
|
|
32
|
+
fullWidthSelect: Boolean,
|
|
33
|
+
/**
|
|
34
|
+
* If true, hides all labels in the form.
|
|
35
|
+
*/
|
|
36
|
+
hideLabels: Boolean,
|
|
37
|
+
/**
|
|
38
|
+
* If true, right-aligns the form actions.
|
|
39
|
+
*/
|
|
40
|
+
actionsRight: Boolean
|
|
41
|
+
});
|
|
42
42
|
</script>
|
|
@@ -1,38 +1,24 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<input
|
|
3
3
|
type="checkbox"
|
|
4
|
-
|
|
4
|
+
v-bind="fieldAttrs"
|
|
5
5
|
:checked="modelValue"
|
|
6
6
|
@change="$emit('update:modelValue', $event.target.checked)"
|
|
7
|
-
:required="required"
|
|
8
7
|
>
|
|
9
|
-
<label :for="id">
|
|
10
|
-
<slot>
|
|
11
|
-
{{ label }}<UluFormRequiredChar v-if="required" />
|
|
12
|
-
</slot>
|
|
13
|
-
</label>
|
|
14
8
|
</template>
|
|
15
9
|
|
|
16
10
|
<script setup>
|
|
17
|
-
import {
|
|
18
|
-
import UluFormRequiredChar from "./UluFormRequiredChar.vue";
|
|
11
|
+
import { inject, computed } from "vue";
|
|
19
12
|
|
|
20
|
-
defineProps({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* The value of the checkbox (for v-model).
|
|
27
|
-
*/
|
|
28
|
-
modelValue: Boolean,
|
|
29
|
-
/**
|
|
30
|
-
* If true, the field will be required.
|
|
31
|
-
*/
|
|
32
|
-
required: Boolean
|
|
33
|
-
});
|
|
13
|
+
const props = defineProps({
|
|
14
|
+
/**
|
|
15
|
+
* The value of the checkbox (for v-model).
|
|
16
|
+
*/
|
|
17
|
+
modelValue: Boolean
|
|
18
|
+
});
|
|
34
19
|
|
|
35
|
-
defineEmits([
|
|
20
|
+
defineEmits(["update:modelValue"]);
|
|
36
21
|
|
|
37
|
-
const
|
|
22
|
+
const injectedAttrs = inject("uluFormFieldAttrs", null);
|
|
23
|
+
const fieldAttrs = computed(() => injectedAttrs ? injectedAttrs.value : {});
|
|
38
24
|
</script>
|
|
@@ -1,59 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<label
|
|
3
|
-
:class="{ 'hidden-visually' : labelHidden }"
|
|
4
|
-
:for="id"
|
|
5
|
-
>
|
|
6
|
-
<slot name="label">
|
|
7
|
-
{{ label }}<UluFormRequiredChar v-if="required" />
|
|
8
|
-
</slot>
|
|
9
|
-
</label>
|
|
10
2
|
<input
|
|
11
3
|
type="file"
|
|
12
|
-
|
|
4
|
+
v-bind="fieldAttrs"
|
|
13
5
|
:multiple="multiple"
|
|
14
|
-
|
|
15
|
-
v-bind="inputAttrs"
|
|
16
|
-
:required="required"
|
|
6
|
+
@change="onChangeFile"
|
|
17
7
|
/>
|
|
18
8
|
</template>
|
|
19
9
|
|
|
20
10
|
<script setup>
|
|
21
|
-
import {
|
|
22
|
-
import UluFormRequiredChar from "./UluFormRequiredChar.vue";
|
|
11
|
+
import { inject, computed } from "vue";
|
|
23
12
|
|
|
24
|
-
defineProps({
|
|
25
|
-
/**
|
|
26
|
-
* The label for the file input.
|
|
27
|
-
*/
|
|
28
|
-
label: {
|
|
29
|
-
type: String,
|
|
30
|
-
default: "Select File"
|
|
31
|
-
},
|
|
32
|
-
/**
|
|
33
|
-
* If true, the label will be visually hidden.
|
|
34
|
-
*/
|
|
35
|
-
labelHidden: Boolean,
|
|
36
|
-
/**
|
|
37
|
-
* If true, default classes will not be applied.
|
|
38
|
-
*/
|
|
39
|
-
noClasses: Boolean,
|
|
13
|
+
const props = defineProps({
|
|
40
14
|
/**
|
|
41
15
|
* If true, allows multiple file selection.
|
|
42
16
|
*/
|
|
43
|
-
multiple: Boolean
|
|
44
|
-
/**
|
|
45
|
-
* Additional attributes to bind to the input element.
|
|
46
|
-
*/
|
|
47
|
-
inputAttrs: Object,
|
|
48
|
-
/**
|
|
49
|
-
* If true, the field will be required.
|
|
50
|
-
*/
|
|
51
|
-
required: Boolean
|
|
17
|
+
multiple: Boolean
|
|
52
18
|
});
|
|
53
19
|
|
|
54
20
|
const emit = defineEmits(["file-change"]);
|
|
55
21
|
|
|
56
|
-
const
|
|
22
|
+
const injectedAttrs = inject("uluFormFieldAttrs", null);
|
|
23
|
+
const fieldAttrs = computed(() => {
|
|
24
|
+
const attrs = injectedAttrs ? { ...injectedAttrs.value } : {};
|
|
25
|
+
return attrs;
|
|
26
|
+
});
|
|
57
27
|
|
|
58
28
|
const onChangeFile = (event) => {
|
|
59
29
|
emit("file-change", event.target.files);
|
|
@@ -1,49 +1,160 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
class="form-theme__item"
|
|
4
|
-
:class="[
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
'form-theme__item--textarea': textarea
|
|
12
|
-
}]"
|
|
4
|
+
:class="[
|
|
5
|
+
resolvedModifiers,
|
|
6
|
+
{
|
|
7
|
+
'is-danger': hasError,
|
|
8
|
+
'is-warning': hasWarning
|
|
9
|
+
}
|
|
10
|
+
]"
|
|
13
11
|
>
|
|
12
|
+
<UluFormLabel
|
|
13
|
+
v-if="!isLabelAfter && hasLabel"
|
|
14
|
+
:id="internalId"
|
|
15
|
+
:labelHidden="labelHidden"
|
|
16
|
+
:required="required"
|
|
17
|
+
>
|
|
18
|
+
<slot name="label">{{ label }}</slot>
|
|
19
|
+
</UluFormLabel>
|
|
20
|
+
|
|
14
21
|
<slot />
|
|
22
|
+
|
|
23
|
+
<UluFormLabel
|
|
24
|
+
v-if="isLabelAfter && hasLabel"
|
|
25
|
+
:id="internalId"
|
|
26
|
+
:labelHidden="labelHidden"
|
|
27
|
+
:required="required"
|
|
28
|
+
>
|
|
29
|
+
<slot name="label">{{ label }}</slot>
|
|
30
|
+
</UluFormLabel>
|
|
31
|
+
|
|
32
|
+
<UluFormMessage
|
|
33
|
+
v-if="description || $slots.description"
|
|
34
|
+
:id="descriptionId"
|
|
35
|
+
>
|
|
36
|
+
<slot name="description">{{ description }}</slot>
|
|
37
|
+
</UluFormMessage>
|
|
38
|
+
|
|
39
|
+
<UluFormMessage
|
|
40
|
+
v-if="errorMessage || $slots.errorMessage"
|
|
41
|
+
:id="errorId"
|
|
42
|
+
error
|
|
43
|
+
>
|
|
44
|
+
<slot name="errorMessage">{{ errorMessage }}</slot>
|
|
45
|
+
</UluFormMessage>
|
|
46
|
+
|
|
47
|
+
<UluFormMessage
|
|
48
|
+
v-if="warningMessage || $slots.warningMessage"
|
|
49
|
+
:id="warningId"
|
|
50
|
+
warning
|
|
51
|
+
>
|
|
52
|
+
<slot name="warningMessage">{{ warningMessage }}</slot>
|
|
53
|
+
</UluFormMessage>
|
|
15
54
|
</div>
|
|
16
55
|
</template>
|
|
17
56
|
|
|
18
57
|
<script setup>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
import { provide, computed, useSlots } from "vue";
|
|
59
|
+
import { newId } from "../../utils/dom.js";
|
|
60
|
+
import { useModifiers } from "../../composables/useModifiers.js";
|
|
61
|
+
import UluFormMessage from "./UluFormMessage.vue";
|
|
62
|
+
import UluFormLabel from "./UluFormLabel.vue";
|
|
63
|
+
|
|
64
|
+
const props = defineProps({
|
|
65
|
+
/**
|
|
66
|
+
* The layout variant for this form item (e.g., 'text', 'select', 'textarea', 'checkbox', 'radio', 'file').
|
|
67
|
+
* This determines the layout and BEM styling of the item container.
|
|
68
|
+
*/
|
|
69
|
+
layout: String,
|
|
70
|
+
/**
|
|
71
|
+
* The ID to use for the form field. If not provided, a unique ID is generated.
|
|
72
|
+
*/
|
|
73
|
+
fieldId: String,
|
|
74
|
+
/**
|
|
75
|
+
* The label for the form field.
|
|
76
|
+
*/
|
|
77
|
+
label: String,
|
|
78
|
+
/**
|
|
79
|
+
* If true, the label will be visually hidden.
|
|
80
|
+
*/
|
|
81
|
+
labelHidden: Boolean,
|
|
82
|
+
/**
|
|
83
|
+
* The description text for the form field.
|
|
84
|
+
*/
|
|
85
|
+
description: String,
|
|
86
|
+
/**
|
|
87
|
+
* The error message text.
|
|
88
|
+
*/
|
|
89
|
+
errorMessage: String,
|
|
90
|
+
/**
|
|
91
|
+
* The warning message text.
|
|
92
|
+
*/
|
|
93
|
+
warningMessage: String,
|
|
94
|
+
/**
|
|
95
|
+
* If true, the field will be marked as required.
|
|
96
|
+
*/
|
|
97
|
+
required: Boolean,
|
|
98
|
+
/**
|
|
99
|
+
* If true, applies the error state styles.
|
|
100
|
+
*/
|
|
101
|
+
error: Boolean,
|
|
102
|
+
/**
|
|
103
|
+
* If true, applies the warning state styles.
|
|
104
|
+
*/
|
|
105
|
+
warning: Boolean,
|
|
106
|
+
/**
|
|
107
|
+
* If true, aligns the item to the top.
|
|
108
|
+
*/
|
|
109
|
+
alignTop: Boolean,
|
|
110
|
+
/**
|
|
111
|
+
* Additional BEM modifiers for the form item.
|
|
112
|
+
*/
|
|
113
|
+
modifiers: [String, Array]
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const slots = useSlots();
|
|
117
|
+
|
|
118
|
+
const { resolvedModifiers } = useModifiers({
|
|
119
|
+
props,
|
|
120
|
+
baseClass: "form-theme__item",
|
|
121
|
+
internal: computed(() => ({
|
|
122
|
+
[props.layout]: props.layout,
|
|
123
|
+
"align-top": props.alignTop
|
|
124
|
+
}))
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const internalId = computed(() => props.fieldId || newId());
|
|
128
|
+
const descriptionId = computed(() => `${ internalId.value }-desc`);
|
|
129
|
+
const errorId = computed(() => `${ internalId.value }-error`);
|
|
130
|
+
const warningId = computed(() => `${ internalId.value }-warn`);
|
|
131
|
+
|
|
132
|
+
const hasLabel = computed(() => !!props.label || !!slots.label);
|
|
133
|
+
const hasError = computed(() => props.error || !!props.errorMessage || !!slots.errorMessage);
|
|
134
|
+
const hasWarning = computed(() => props.warning || !!props.warningMessage || !!slots.warningMessage);
|
|
135
|
+
|
|
136
|
+
const isLabelAfter = computed(() => ["checkbox", "radio"].includes(props.layout));
|
|
137
|
+
|
|
138
|
+
const fieldAttrs = computed(() => {
|
|
139
|
+
const attrs = {
|
|
140
|
+
id: internalId.value
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const describedBy = [];
|
|
144
|
+
if (props.description || slots.description) describedBy.push(descriptionId.value);
|
|
145
|
+
if (props.errorMessage || slots.errorMessage) describedBy.push(errorId.value);
|
|
146
|
+
if (props.warningMessage || slots.warningMessage) describedBy.push(warningId.value);
|
|
147
|
+
|
|
148
|
+
if (describedBy.length > 0) {
|
|
149
|
+
attrs["aria-describedby"] = describedBy.join(" ");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (hasError.value) {
|
|
153
|
+
attrs["aria-invalid"] = "true";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return attrs;
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
provide("uluFormFieldAttrs", fieldAttrs);
|
|
49
160
|
</script>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<label
|
|
3
|
+
:for="id"
|
|
4
|
+
:class="{ 'hidden-visually': labelHidden }"
|
|
5
|
+
>
|
|
6
|
+
<slot></slot><UluFormRequiredChar v-if="required" />
|
|
7
|
+
</label>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup>
|
|
11
|
+
import UluFormRequiredChar from "./UluFormRequiredChar.vue";
|
|
12
|
+
|
|
13
|
+
defineProps({
|
|
14
|
+
/**
|
|
15
|
+
* The ID of the input this label is associated with.
|
|
16
|
+
*/
|
|
17
|
+
id: {
|
|
18
|
+
type: String,
|
|
19
|
+
required: true
|
|
20
|
+
},
|
|
21
|
+
/**
|
|
22
|
+
* If true, the label will be visually hidden.
|
|
23
|
+
*/
|
|
24
|
+
labelHidden: Boolean,
|
|
25
|
+
/**
|
|
26
|
+
* If true, appends the required character.
|
|
27
|
+
*/
|
|
28
|
+
required: Boolean
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
@@ -1,48 +1,29 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<input
|
|
3
3
|
type="radio"
|
|
4
|
-
|
|
5
|
-
:name="name"
|
|
4
|
+
v-bind="fieldAttrs"
|
|
6
5
|
:value="value"
|
|
7
6
|
:checked="modelValue === value"
|
|
8
7
|
@change="$emit('update:modelValue', value)"
|
|
9
|
-
:required="required"
|
|
10
8
|
>
|
|
11
|
-
<label :for="id">
|
|
12
|
-
<slot>
|
|
13
|
-
{{ label }}<UluFormRequiredChar v-if="required" />
|
|
14
|
-
</slot>
|
|
15
|
-
</label>
|
|
16
9
|
</template>
|
|
17
10
|
|
|
18
11
|
<script setup>
|
|
19
|
-
import {
|
|
20
|
-
import UluFormRequiredChar from "./UluFormRequiredChar.vue";
|
|
12
|
+
import { inject, computed } from "vue";
|
|
21
13
|
|
|
22
|
-
defineProps({
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* The value of this radio button.
|
|
33
|
-
*/
|
|
34
|
-
value: [String, Number],
|
|
35
|
-
/**
|
|
36
|
-
* The name of the radio button group.
|
|
37
|
-
*/
|
|
38
|
-
name: String,
|
|
39
|
-
/**
|
|
40
|
-
* If true, the field will be required.
|
|
41
|
-
*/
|
|
42
|
-
required: Boolean
|
|
43
|
-
});
|
|
14
|
+
const props = defineProps({
|
|
15
|
+
/**
|
|
16
|
+
* The value of the selected radio button in the group (for v-model).
|
|
17
|
+
*/
|
|
18
|
+
modelValue: [String, Number, Boolean],
|
|
19
|
+
/**
|
|
20
|
+
* The value of this radio button.
|
|
21
|
+
*/
|
|
22
|
+
value: [String, Number, Boolean]
|
|
23
|
+
});
|
|
44
24
|
|
|
45
|
-
defineEmits([
|
|
25
|
+
defineEmits(["update:modelValue"]);
|
|
46
26
|
|
|
47
|
-
const
|
|
27
|
+
const injectedAttrs = inject("uluFormFieldAttrs", null);
|
|
28
|
+
const fieldAttrs = computed(() => injectedAttrs ? injectedAttrs.value : {});
|
|
48
29
|
</script>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<label :class="{ 'hidden-visually' : labelHidden }" :for="id">
|
|
3
|
-
<slot name="label">
|
|
4
|
-
{{ label }}<UluFormRequiredChar v-if="required" />
|
|
5
|
-
</slot>
|
|
6
|
-
</label>
|
|
7
2
|
<select
|
|
8
|
-
|
|
3
|
+
v-bind="fieldAttrs"
|
|
9
4
|
:value="modelValue"
|
|
10
5
|
@input="$emit('update:modelValue', $event.target.value)"
|
|
11
|
-
:required="required"
|
|
12
6
|
>
|
|
13
|
-
<option
|
|
7
|
+
<option
|
|
8
|
+
v-if="placeholder !== false"
|
|
9
|
+
disabled
|
|
10
|
+
value=""
|
|
11
|
+
>
|
|
12
|
+
{{ placeholder || "Please select one" }}
|
|
13
|
+
</option>
|
|
14
14
|
<option v-for="(option, index) in options" :key="index" :value="option.value">
|
|
15
15
|
{{ option.text }}
|
|
16
16
|
</option>
|
|
@@ -18,33 +18,28 @@
|
|
|
18
18
|
</template>
|
|
19
19
|
|
|
20
20
|
<script setup>
|
|
21
|
-
import {
|
|
22
|
-
import UluFormRequiredChar from "./UluFormRequiredChar.vue";
|
|
21
|
+
import { inject, computed } from "vue";
|
|
23
22
|
|
|
24
|
-
defineProps({
|
|
25
|
-
/**
|
|
26
|
-
* The label for the select input.
|
|
27
|
-
*/
|
|
28
|
-
label: String,
|
|
23
|
+
const props = defineProps({
|
|
29
24
|
/**
|
|
30
25
|
* The value of the select input (for v-model).
|
|
31
26
|
*/
|
|
32
|
-
modelValue: String,
|
|
27
|
+
modelValue: [String, Number, Array],
|
|
33
28
|
/**
|
|
34
29
|
* An array of options for the select input. Each option should be an object with `value` and `text` properties.
|
|
35
30
|
*/
|
|
36
31
|
options: Array,
|
|
37
32
|
/**
|
|
38
|
-
*
|
|
39
|
-
*/
|
|
40
|
-
labelHidden: Boolean,
|
|
41
|
-
/**
|
|
42
|
-
* If true, the field will be required.
|
|
33
|
+
* The text for the default disabled option. Pass false to hide it.
|
|
43
34
|
*/
|
|
44
|
-
|
|
35
|
+
placeholder: {
|
|
36
|
+
type: [String, Boolean],
|
|
37
|
+
default: "Please select one"
|
|
38
|
+
}
|
|
45
39
|
});
|
|
46
40
|
|
|
47
|
-
defineEmits([
|
|
41
|
+
defineEmits(["update:modelValue"]);
|
|
48
42
|
|
|
49
|
-
const
|
|
43
|
+
const injectedAttrs = inject("uluFormFieldAttrs", null);
|
|
44
|
+
const fieldAttrs = computed(() => injectedAttrs ? injectedAttrs.value : {});
|
|
50
45
|
</script>
|