@konoma-development/vue-components 0.1.0 → 0.1.2
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/.playground/app.vue +1 -1
- package/components/defaults/radioButtonGroup.ts +1 -1
- package/components/defaults/select.ts +13 -15
- package/components/defaults/textarea.ts +1 -1
- package/components/form/KonomaForm.vue +2 -4
- package/components/form/KonomaFormField.vue +35 -4
- package/components/form/KonomaInput.vue +3 -0
- package/components/form/KonomaSelect.vue +87 -3
- package/components/form/KonomaTagList.vue +1 -1
- package/components/form/KonomaTextarea.vue +25 -23
- package/components/form/injectionKeys.ts +2 -2
- package/components/table/KonomaTableActions.vue +1 -1
- package/eslint.config.ts +5 -8
- package/nuxt.config.ts +8 -2
- package/package.json +8 -6
- package/types/form.ts +3 -1
- package/unocss.config.ts +27 -33
- /package/components/{KonomaTheme.vue → ui/KonomaTheme.vue} +0 -0
package/.playground/app.vue
CHANGED
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
</template>
|
|
29
29
|
|
|
30
30
|
<script setup lang="ts">
|
|
31
|
-
import KonomaTheme from '../components/KonomaTheme.vue';
|
|
32
31
|
import KonomaButton from '../components/ui/KonomaButton.vue';
|
|
33
32
|
import KonomaTabs from '../components/ui/KonomaTabs.vue';
|
|
34
33
|
import KonomaTag from '../components/ui/KonomaTag.vue';
|
|
34
|
+
import KonomaTheme from '../components/ui/KonomaTheme.vue';
|
|
35
35
|
import unocss from '../unocss.config';
|
|
36
36
|
|
|
37
37
|
const activeTab = ref(0);
|
|
@@ -2,7 +2,7 @@ import type { Classes } from '../../types/form';
|
|
|
2
2
|
|
|
3
3
|
export const baseClasses: { [key in keyof Classes]?: string } = {
|
|
4
4
|
classes: 'absolute left-[5px] top-[5px] h-1.5 w-1.5 rounded-full bg-white',
|
|
5
|
-
controlClasses: 'h-4 w-4 min-w-4 rounded-
|
|
5
|
+
controlClasses: 'h-4 w-4 min-w-4 rounded-kvc-radioButtonGroup relative',
|
|
6
6
|
wrapperClasses: 'flex flex-col gap-2',
|
|
7
7
|
classesFilled: 'bg-primary-600',
|
|
8
8
|
labelClasses: 'text-sm font-medium text-secondary-900',
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import type { Classes } from '../../types/form';
|
|
2
2
|
|
|
3
3
|
export const baseClasses: { [key in keyof Classes]: string } = {
|
|
4
|
-
classes: 'rounded-kvc-select h-10 py-0 border shadow-none',
|
|
5
|
-
errorClasses: 'text-sm text-error-500',
|
|
6
|
-
labelClasses: 'text-sm font-medium text-secondary-900',
|
|
7
|
-
labelWrapperClasses: 'group flex flex-col gap-1',
|
|
8
|
-
classesNeutral: 'border-secondary-300 group-hover:border-secondary-400',
|
|
9
|
-
classesError: 'ring-error-500 ring-2',
|
|
10
|
-
focusClasses: 'ring-2 ring-primary-900',
|
|
11
|
-
controlClasses: 'h-8 rounded-kvc-select py-0 text-secondary-900 text-sm border-none outline-hidden',
|
|
12
|
-
optionClasses: 'bg-white text-sm',
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
wrapperClasses: 'w-full h-auto',
|
|
18
|
-
indicatorClasses: 'text-secondary-500',
|
|
4
|
+
classes: 'rounded-kvc-select! h-10! py-0! border! border-secondary-400! shadow-none! text-sm!',
|
|
5
|
+
errorClasses: 'text-sm! text-error-500!',
|
|
6
|
+
labelClasses: 'text-sm! font-medium! text-secondary-900!',
|
|
7
|
+
labelWrapperClasses: 'group! flex! flex-col! gap-1!',
|
|
8
|
+
classesNeutral: 'border-secondary-300! group-hover:border-secondary-400!',
|
|
9
|
+
classesError: 'ring-error-500! ring-2!',
|
|
10
|
+
focusClasses: 'ring-2! ring-primary-900!',
|
|
11
|
+
controlClasses: 'h-8! rounded-kvc-select! py-0! text-secondary-900! text-sm! border-none! outline-hidden!',
|
|
12
|
+
optionClasses: 'bg-white! text-sm! hover:bg-primary-200! [&.selected]:bg-primary-500!',
|
|
13
|
+
valueClasses: 'text-secondary-900! text-sm!',
|
|
14
|
+
placeholderClasses: 'text-secondary-500! text-sm!',
|
|
15
|
+
wrapperClasses: 'w-full! h-auto!',
|
|
16
|
+
indicatorClasses: 'text-secondary-500!',
|
|
19
17
|
valueContainerClasses: '',
|
|
20
18
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Classes } from '../../types/form';
|
|
2
2
|
|
|
3
3
|
export const baseClasses: { [key in keyof Classes]?: string } = {
|
|
4
|
-
classes: 'w-full bg-
|
|
4
|
+
classes: 'w-full bg-base-100 text-sm cursor-text rounded-kvc-textarea p-4 text-secondary-900',
|
|
5
5
|
classesNeutral: 'border border-secondary-300 has-focus:ring-2 hover:border-secondary-400 has-[:focus]:ring-primary-900',
|
|
6
6
|
classesError: 'ring-error-500 ring-2',
|
|
7
7
|
errorClasses: 'text-sm text-error-500',
|
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
</form>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
|
-
<script lang="ts" setup generic="DataType
|
|
8
|
-
[key: string]: string | number | boolean | null
|
|
9
|
-
}"
|
|
7
|
+
<script lang="ts" setup generic="DataType"
|
|
10
8
|
>
|
|
11
9
|
import { formInjectionKeys } from './injectionKeys';
|
|
12
10
|
|
|
@@ -27,7 +25,7 @@ function validate() {
|
|
|
27
25
|
let invalid = false;
|
|
28
26
|
const newErrors: Record<keyof DataType, string[]> = {} as Record<keyof DataType, string[]>;
|
|
29
27
|
|
|
30
|
-
Object.entries(props.data).forEach(([name, value]) => {
|
|
28
|
+
Object.entries(props.data as Record<string, (string | number | boolean) | null>).forEach(([name, value]) => {
|
|
31
29
|
if (!props.validators[name as keyof DataType]) {
|
|
32
30
|
return;
|
|
33
31
|
}
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<!-- TODO: The cast for errors[props.name] should not be neccessary -->
|
|
3
3
|
<component
|
|
4
|
-
:is="
|
|
5
|
-
v-bind="
|
|
4
|
+
:is="resolvedComponent"
|
|
5
|
+
v-bind="props"
|
|
6
6
|
:error="errors && props.name ? errors[props.name as keyof typeof errors] : undefined"
|
|
7
|
-
|
|
7
|
+
v-on="emit"
|
|
8
|
+
@change="emit('change', $event)"
|
|
9
|
+
>
|
|
10
|
+
<template #label>
|
|
11
|
+
<slot name="label" />
|
|
12
|
+
</template>
|
|
13
|
+
</component>
|
|
8
14
|
</template>
|
|
9
15
|
|
|
10
16
|
<script lang="ts" setup generic="DataType extends FormDataType">
|
|
11
|
-
import type { FormDataType, FormFieldProps } from '../../types/form';
|
|
17
|
+
import type { FormDataType, FormFieldEmits, FormFieldProps } from '../../types/form';
|
|
12
18
|
import type KonomaCheckbox from './KonomaCheckbox.vue';
|
|
13
19
|
import type KonomaCheckboxList from './KonomaCheckboxList.vue';
|
|
14
20
|
import type KonomaInput from './KonomaInput.vue';
|
|
@@ -21,6 +27,8 @@ import { formInjectionKeys } from './injectionKeys';
|
|
|
21
27
|
|
|
22
28
|
const props = defineProps<FormFieldProps<DataType> & { component: keyof FormFieldComponents }>()
|
|
23
29
|
|
|
30
|
+
const emit = defineEmits<FormFieldEmits>()
|
|
31
|
+
|
|
24
32
|
interface FormFieldComponents {
|
|
25
33
|
checkbox: typeof KonomaCheckbox
|
|
26
34
|
checkboxList: typeof KonomaCheckboxList
|
|
@@ -32,5 +40,28 @@ interface FormFieldComponents {
|
|
|
32
40
|
phoneInput: typeof KonomaPhoneInput
|
|
33
41
|
};
|
|
34
42
|
|
|
43
|
+
const resolvedComponent = computed(() => {
|
|
44
|
+
switch (props.component) {
|
|
45
|
+
case 'checkbox':
|
|
46
|
+
return 'KonomaCheckbox';
|
|
47
|
+
case 'checkboxList':
|
|
48
|
+
return 'KonomaCheckboxList';
|
|
49
|
+
case 'input':
|
|
50
|
+
return 'KonomaInput';
|
|
51
|
+
case 'radioButtonGroup':
|
|
52
|
+
return 'KonomaRadioButtonGroup';
|
|
53
|
+
case 'select':
|
|
54
|
+
return 'KonomaSelect';
|
|
55
|
+
case 'textarea':
|
|
56
|
+
return 'KonomaTextarea';
|
|
57
|
+
case 'tagList':
|
|
58
|
+
return 'KonomaTagList';
|
|
59
|
+
case 'phoneInput':
|
|
60
|
+
return 'KonomaPhoneInput';
|
|
61
|
+
default:
|
|
62
|
+
throw new Error(`Unsupported component type: ${props.component}`);
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
35
66
|
const errors = inject(formInjectionKeys<DataType>().errors)
|
|
36
67
|
</script>
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
v-else
|
|
12
12
|
:class="combinedClasses"
|
|
13
13
|
:placeholder="placeholder"
|
|
14
|
+
:type="type"
|
|
15
|
+
:data-testid="dataTestId"
|
|
14
16
|
:value="value"
|
|
15
17
|
:step="step"
|
|
16
18
|
:name="name?.toString()"
|
|
@@ -63,6 +65,7 @@ const props = withDefaults(defineProps<FormFieldProps<DataType> & { class?: stri
|
|
|
63
65
|
additionalClassesIconLeft: baseClasses.additionalClassesIconLeft,
|
|
64
66
|
additionalClassesIconRight: baseClasses.additionalClassesIconRight,
|
|
65
67
|
wrapperRightClasses: baseClasses.wrapperRightClasses,
|
|
68
|
+
type: 'text',
|
|
66
69
|
})
|
|
67
70
|
|
|
68
71
|
defineEmits<FormFieldEmits>()
|
|
@@ -1,9 +1,93 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div :class="labelWrapperClasses">
|
|
3
|
+
<div :class="labelClasses">
|
|
4
|
+
<slot name="label" />
|
|
5
|
+
</div>
|
|
6
|
+
<ClientOnly>
|
|
7
|
+
<VueSelect
|
|
8
|
+
:options="typedOptions || []" :model-value="value" :classes="{
|
|
9
|
+
control: classesFull.join(' '),
|
|
10
|
+
// (state) => {
|
|
11
|
+
// if (state.isFocused) {
|
|
12
|
+
// return [...classesFull, focusClasses].join(' ');
|
|
13
|
+
// }
|
|
14
|
+
// return classesFull.join(' ');
|
|
15
|
+
// },
|
|
16
|
+
valueContainer: noValue && valueContainerClasses ? ['hidden', valueContainerClasses].join(' ') : noValue ? 'hidden' : valueContainerClasses || '',
|
|
17
|
+
// input: () => controlClasses || '',
|
|
18
|
+
// indicatorSeparator: () => 'hidden',
|
|
19
|
+
menuOption: optionClasses || '',
|
|
20
|
+
singleValue: valueClasses || '',
|
|
21
|
+
placeholder: placeholderClasses || '',
|
|
22
|
+
inputContainer: controlClasses || '',
|
|
23
|
+
searchInput: controlClasses || '',
|
|
24
|
+
}"
|
|
25
|
+
:placeholder="placeholder || 'Bitte auswählen'"
|
|
26
|
+
:is-searchable="searchable"
|
|
27
|
+
:is-clearable="isClearable"
|
|
28
|
+
:data-testid="dataTestId"
|
|
29
|
+
v-on="emit"
|
|
30
|
+
@option-selected="(option) => {
|
|
31
|
+
if (!option) {
|
|
32
|
+
// Needed to handle clearing the select
|
|
33
|
+
emit('change', false);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (isMulti) {
|
|
37
|
+
emit('change', option);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const properOption = option as OptionType;
|
|
42
|
+
const cleanOption = {
|
|
43
|
+
...properOption,
|
|
44
|
+
value: properOption.value || CUSTOM_ENTRY_VALUE,
|
|
45
|
+
label: properOption.value ? properOption.label : ' ',
|
|
46
|
+
};
|
|
47
|
+
emit('change', cleanOption);
|
|
48
|
+
}
|
|
49
|
+
}"
|
|
50
|
+
/>
|
|
51
|
+
</ClientOnly>
|
|
52
|
+
<template v-if="error && error.length > 0">
|
|
53
|
+
<span v-for="(e, i) in error" :key="i" :class="errorClasses">
|
|
54
|
+
{{ e }}
|
|
55
|
+
</span>
|
|
56
|
+
</template>
|
|
57
|
+
</div>
|
|
3
58
|
</template>
|
|
4
59
|
|
|
5
60
|
<script lang="ts" setup generic="DataType extends FormDataType">
|
|
6
|
-
import type {
|
|
61
|
+
import type { Option } from 'vue3-select-component';
|
|
62
|
+
import type { FormDataType, FormFieldEmits, FormFieldProps, FormValue } from '../../types/form';
|
|
63
|
+
import VueSelect from 'vue3-select-component';
|
|
64
|
+
import { baseClasses } from '../defaults/select';
|
|
65
|
+
import 'vue3-select-component/styles';
|
|
7
66
|
|
|
8
|
-
|
|
67
|
+
const props = withDefaults(defineProps<FormFieldProps<DataType> & { class?: string }>(), {
|
|
68
|
+
classes: baseClasses.classes,
|
|
69
|
+
controlClasses: baseClasses.controlClasses,
|
|
70
|
+
optionClasses: baseClasses.optionClasses,
|
|
71
|
+
labelClasses: baseClasses.labelClasses,
|
|
72
|
+
classesFilled: baseClasses.classesFilled,
|
|
73
|
+
classesEmpty: baseClasses.classesEmpty,
|
|
74
|
+
wrapperClasses: baseClasses.wrapperClasses,
|
|
75
|
+
labelWrapperClasses: baseClasses.labelWrapperClasses,
|
|
76
|
+
errorClasses: baseClasses.errorClasses,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const emit = defineEmits<FormFieldEmits>()
|
|
80
|
+
|
|
81
|
+
const CUSTOM_ENTRY_VALUE = 'CUSTOM_ENTRY_VALUE';
|
|
82
|
+
|
|
83
|
+
type OptionType = Option<FormValue>
|
|
84
|
+
|
|
85
|
+
const typedOptions = computed(() => {
|
|
86
|
+
if (!props.options) {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
return props.options as OptionType[];
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
const classesFull = [baseClasses.classes, baseClasses.class];
|
|
9
93
|
</script>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<KonomaTag
|
|
15
15
|
:title="addTagTitle"
|
|
16
16
|
icon-left-name="heroicons:plus-16-solid"
|
|
17
|
-
wrapper-classes="flex flex-row h-6 cursor-pointer items-center justify-center gap-1 rounded-
|
|
17
|
+
wrapper-classes="flex flex-row h-6 cursor-pointer items-center justify-center gap-1 rounded-kvc-tag-list-add border border-secondary-300 px-3 py-1 bg-white"
|
|
18
18
|
@click="$emit('change', '')"
|
|
19
19
|
/>
|
|
20
20
|
</div>
|
|
@@ -4,19 +4,22 @@
|
|
|
4
4
|
<span :class="labelClasses">
|
|
5
5
|
<slot name="label" /><template v-if="required">*</template>
|
|
6
6
|
</span>
|
|
7
|
-
<span v-if="maxLength" :class="hintClasses">{{ maxLengthLabel }}</span>
|
|
7
|
+
<span v-if="maxLength" :class="hintClasses">{{ maxLengthLabel || `Max. ${maxLength} Zeichen` }}</span>
|
|
8
8
|
</div>
|
|
9
|
-
<div
|
|
10
|
-
|
|
9
|
+
<div
|
|
10
|
+
class="relative"
|
|
11
|
+
>
|
|
11
12
|
<textarea
|
|
12
|
-
ref="textareaRef"
|
|
13
13
|
:maxlength="maxLength"
|
|
14
14
|
:value="text"
|
|
15
15
|
:disabled="disabled"
|
|
16
16
|
:name="name?.toString()"
|
|
17
17
|
v-bind="$attrs"
|
|
18
|
-
:class="
|
|
19
|
-
|
|
18
|
+
:class="combinedClasses"
|
|
19
|
+
:style="{
|
|
20
|
+
height: `${initialHeight}px`,
|
|
21
|
+
}"
|
|
22
|
+
@input="$event => emit('change', ($event.target as HTMLTextAreaElement).value, $event)"
|
|
20
23
|
@focus="isFocused = true"
|
|
21
24
|
@blur="isFocused = false"
|
|
22
25
|
/>
|
|
@@ -45,26 +48,25 @@ const props = withDefaults(defineProps<FormFieldProps<DataType>>(), {
|
|
|
45
48
|
maxLength: 150,
|
|
46
49
|
})
|
|
47
50
|
|
|
48
|
-
defineEmits<FormFieldEmits>()
|
|
49
|
-
|
|
51
|
+
const emit = defineEmits<FormFieldEmits>()
|
|
52
|
+
const initialHeight = ref(props.initialHeight)
|
|
50
53
|
const isFocused = ref(false)
|
|
51
|
-
const textareaRef = useTemplateRef('textareaRef')
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
const combinedClasses = computed(() => {
|
|
56
|
+
const classesFull = [];
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
if (props.disabled) {
|
|
59
|
+
classesFull.push(props.classesDisabled);
|
|
60
|
+
} else {
|
|
61
|
+
classesFull.push(props.classes);
|
|
62
|
+
}
|
|
63
|
+
if (props.error && props.error.length > 0) {
|
|
64
|
+
classesFull.push(props.classesError);
|
|
65
|
+
} else {
|
|
66
|
+
classesFull.push(props.classesNeutral);
|
|
67
|
+
}
|
|
68
|
+
return classesFull;
|
|
69
|
+
})
|
|
68
70
|
|
|
69
71
|
const text = computed(() => {
|
|
70
72
|
let t = props.value?.toString() || '';
|
|
@@ -2,7 +2,7 @@ import type { InjectionKey } from 'vue';
|
|
|
2
2
|
|
|
3
3
|
export function formInjectionKeys<DataType>() {
|
|
4
4
|
return {
|
|
5
|
-
errors: Symbol('errors') as InjectionKey<Record<keyof DataType, string[]>>,
|
|
6
|
-
updateErrors: Symbol('updateErrors') as InjectionKey<(newErrors: Partial<Record<keyof DataType, string[]>>) => void>,
|
|
5
|
+
errors: Symbol.for('errors') as InjectionKey<Record<keyof DataType, string[]>>,
|
|
6
|
+
updateErrors: Symbol.for('updateErrors') as InjectionKey<(newErrors: Partial<Record<keyof DataType, string[]>>) => void>,
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</div>
|
|
11
11
|
</div>
|
|
12
12
|
<template #popper>
|
|
13
|
-
<div class="
|
|
13
|
+
<div class="text-sm font-medium py-2 border border-secondary-200 rounded-md bg-white flex flex-col w-48 shadow-sm">
|
|
14
14
|
<slot />
|
|
15
15
|
</div>
|
|
16
16
|
</template>
|
package/eslint.config.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import antfu from '@antfu/eslint-config';
|
|
2
2
|
import * as eslint from '@eslint/js';
|
|
3
3
|
import * as globals from 'globals';
|
|
4
|
-
import * as vueParser from 'vue-eslint-parser'
|
|
4
|
+
import * as vueParser from 'vue-eslint-parser'
|
|
5
5
|
import withNuxt from './.playground/.nuxt/eslint.config.mjs';
|
|
6
6
|
|
|
7
7
|
export default withNuxt(
|
|
@@ -11,12 +11,9 @@ export default withNuxt(
|
|
|
11
11
|
rules: {
|
|
12
12
|
'style/semi': 'off',
|
|
13
13
|
'style/brace-style': ['error', '1tbs'],
|
|
14
|
-
'vue/block-order': [
|
|
15
|
-
'
|
|
16
|
-
|
|
17
|
-
order: [['template', 'script'], 'style'],
|
|
18
|
-
},
|
|
19
|
-
],
|
|
14
|
+
'vue/block-order': ['error', {
|
|
15
|
+
order: [['template', 'script'], 'style'],
|
|
16
|
+
}],
|
|
20
17
|
},
|
|
21
18
|
}),
|
|
22
19
|
{
|
|
@@ -38,6 +35,6 @@ export default withNuxt(
|
|
|
38
35
|
'vue/multi-word-component-names': 'off',
|
|
39
36
|
'no-case-declarations': 'off',
|
|
40
37
|
},
|
|
41
|
-
ignores: ['.nuxt/*'],
|
|
38
|
+
ignores: ['.nuxt/*', 'shared/openapi/*', 'node_modules/*'],
|
|
42
39
|
},
|
|
43
40
|
);
|
package/nuxt.config.ts
CHANGED
|
@@ -7,9 +7,15 @@ export default defineNuxtConfig({
|
|
|
7
7
|
experimental: {
|
|
8
8
|
asyncContext: true,
|
|
9
9
|
},
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
unocss: {
|
|
11
|
+
nuxtLayers: true,
|
|
12
12
|
},
|
|
13
|
+
components: [
|
|
14
|
+
{ path: 'components/ui', pathPrefix: false, global: true },
|
|
15
|
+
{ path: 'components/form', pathPrefix: false, global: true },
|
|
16
|
+
{ path: 'components/table', pathPrefix: false, global: true },
|
|
17
|
+
'components',
|
|
18
|
+
],
|
|
13
19
|
compatibilityDate: '2024-07-06',
|
|
14
20
|
hooks: {},
|
|
15
21
|
eslint: {
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konoma-development/vue-components",
|
|
3
|
-
"version": "0.1.0",
|
|
4
3
|
"publishConfig": {
|
|
5
4
|
"access": "public"
|
|
6
5
|
},
|
|
6
|
+
"type": "module",
|
|
7
|
+
"version": "0.1.2",
|
|
7
8
|
"packageManager": "yarn@4.12.0",
|
|
8
9
|
"main": "./nuxt.config.ts",
|
|
9
10
|
"scripts": {
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
"@babel/eslint-parser": "7.28.6",
|
|
22
23
|
"@babel/plugin-transform-typescript": "7.28.6",
|
|
23
24
|
"@babel/preset-typescript": "7.28.5",
|
|
24
|
-
"@iconify-json/carbon": "1.2.
|
|
25
|
+
"@iconify-json/carbon": "1.2.19",
|
|
25
26
|
"@nuxt/devtools": "3.2.2",
|
|
26
27
|
"@nuxt/eslint": "1.15.2",
|
|
27
28
|
"@nuxt/eslint-config": "1.15.2",
|
|
@@ -31,12 +32,12 @@
|
|
|
31
32
|
"@nuxtjs/eslint-config-typescript": "12.1.0",
|
|
32
33
|
"@pinia/nuxt": "0.11.3",
|
|
33
34
|
"@sentry/nuxt": "10.40.0",
|
|
34
|
-
"@types/node": "22.19.
|
|
35
|
+
"@types/node": "22.19.13",
|
|
35
36
|
"@typescript-eslint/eslint-plugin": "8.56.1",
|
|
36
37
|
"@typescript-eslint/parser": "8.56.1",
|
|
37
|
-
"@unocss/eslint-config": "66.6.
|
|
38
|
+
"@unocss/eslint-config": "66.6.3",
|
|
38
39
|
"@unocss/nuxt": "66.6.2",
|
|
39
|
-
"@unocss/reset": "66.6.
|
|
40
|
+
"@unocss/reset": "66.6.3",
|
|
40
41
|
"@vitejs/plugin-vue": "6.0.4",
|
|
41
42
|
"@vueuse/nuxt": "14.2.1",
|
|
42
43
|
"babel-preset-vue": "2.0.2",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"unocss-preset-scrollbar": "3.2.0",
|
|
56
57
|
"vite": "7.3.1",
|
|
57
58
|
"vue-eslint-parser": "10.4.0",
|
|
58
|
-
"vue-tsc": "3.2.5"
|
|
59
|
+
"vue-tsc": "3.2.5",
|
|
60
|
+
"vue3-select-component": "^0.16.0"
|
|
59
61
|
}
|
|
60
62
|
}
|
package/types/form.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type FormValue = string | number | boolean | Option;
|
|
|
8
8
|
|
|
9
9
|
export interface Option {
|
|
10
10
|
value: FormValue
|
|
11
|
-
label: string
|
|
11
|
+
label: string
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/** Classes for the form components. Not all classes have effects in all components. Properties that start with 'class-' apply to the component in general, other properties apply to specific parts of the component */
|
|
@@ -90,6 +90,8 @@ export interface FormFieldProps<DataType extends {
|
|
|
90
90
|
}> extends Classes {
|
|
91
91
|
allowCustomValues?: boolean
|
|
92
92
|
customValueLabel?: string
|
|
93
|
+
autoComplete?: string
|
|
94
|
+
dataTestId?: string
|
|
93
95
|
arrangement?: 'horizontal' | 'vertical'
|
|
94
96
|
centered?: boolean
|
|
95
97
|
autoFocus?: boolean
|
package/unocss.config.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { defineConfig, presetWind3, transformerDirectives } from 'unocss';
|
|
1
|
+
import { defineConfig, presetWind4, transformerDirectives } from 'unocss';
|
|
3
2
|
import { presetScrollbar } from 'unocss-preset-scrollbar';
|
|
4
3
|
|
|
5
4
|
type ColorValue = string | Colors;
|
|
@@ -15,43 +14,38 @@ export default defineConfig({
|
|
|
15
14
|
rules: [],
|
|
16
15
|
content: { pipeline: { include: [/\.(vue|svelte|[jt]sx|vine.ts|mdx?|astro|elm|php|phtml|html|ts)($|\?)/] } },
|
|
17
16
|
presets: [
|
|
18
|
-
|
|
17
|
+
presetWind4(),
|
|
19
18
|
presetScrollbar({
|
|
20
19
|
// config
|
|
21
20
|
}),
|
|
22
21
|
],
|
|
23
|
-
extendTheme: (theme: PresetWind3Theme) => {
|
|
24
|
-
if (!theme.borderRadius) {
|
|
25
|
-
theme.borderRadius = {};
|
|
26
|
-
}
|
|
27
|
-
theme.borderRadius['kvc-button'] = 'var(--kvc-button-borderRadius)'
|
|
28
|
-
theme.borderRadius['kvc-tag'] = 'var(--kvc-tag-borderRadius)'
|
|
29
|
-
theme.borderRadius['kvc-table'] = 'var(--kvc-table-borderRadius)'
|
|
30
|
-
theme.borderRadius['kvc-select'] = 'var(--kvc-select-borderRadius)'
|
|
31
|
-
theme.borderRadius['kvc-modal'] = 'var(--kvc-modal-borderRadius)'
|
|
32
|
-
theme.borderRadius['kvc-tagList'] = 'var(--kvc-tagList-borderRadius)'
|
|
33
|
-
theme.borderRadius['kvc-tagListAdd'] = 'var(--kvc-tagListAdd-borderRadius)'
|
|
34
|
-
theme.borderRadius['kvc-input'] = 'var(--kvc-input-borderRadius)'
|
|
35
|
-
theme.borderRadius['kvc-phoneInput'] = 'var(--kvc-phoneInput-borderRadius)'
|
|
36
|
-
theme.borderRadius['kvc-checkbox'] = 'var(--kvc-checkbox-borderRadius)'
|
|
37
|
-
theme.borderRadius['kvc-textarea'] = 'var(--kvc-textarea-borderRadius)'
|
|
38
|
-
theme.borderRadius['kvc-radioButtonGroup'] = 'var(--kvc-radioButtonGroup-borderRadius)'
|
|
39
|
-
theme.borderRadius['kvc-table'] = 'var(--kvc-table-borderRadius)'
|
|
40
|
-
theme.borderRadius['kvc-tableColumnChooser'] = 'var(--kvc-tableColumnChooser-borderRadius)'
|
|
41
|
-
theme.borderRadius['kvc-tableActions'] = 'var(--kvc-tableActions-borderRadius)'
|
|
42
|
-
},
|
|
43
22
|
theme: {
|
|
23
|
+
radius: {
|
|
24
|
+
'kvc-button': 'var(--kvc-button-borderRadius)',
|
|
25
|
+
'kvc-tag': 'var(--kvc-tag-borderRadius)',
|
|
26
|
+
'kvc-table': 'var(--kvc-table-borderRadius)',
|
|
27
|
+
'kvc-select': 'var(--kvc-select-borderRadius)',
|
|
28
|
+
'kvc-modal': 'var(--kvc-modal-borderRadius)',
|
|
29
|
+
'kvc-tagList': 'var(--kvc-tagList-borderRadius)',
|
|
30
|
+
'kvc-tagListAdd': 'var(--kvc-tagListAdd-borderRadius)',
|
|
31
|
+
'kvc-input': 'var(--kvc-input-borderRadius)',
|
|
32
|
+
'kvc-phoneInput': 'var(--kvc-phoneInput-borderRadius)',
|
|
33
|
+
'kvc-checkbox': 'var(--kvc-checkbox-borderRadius)',
|
|
34
|
+
'kvc-textarea': 'var(--kvc-textarea-borderRadius)',
|
|
35
|
+
'kvc-radioButtonGroup': 'var(--kvc-radiobuttonGroup-borderRadius)',
|
|
36
|
+
'kvc-tableColumnChooser': 'var(--kvc-tableColumnChooser-borderRadius)',
|
|
37
|
+
'kvc-tableActions': 'var(--kvc-tableActions-borderRadius)',
|
|
38
|
+
},
|
|
44
39
|
colors: {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
'kvc-table-header': 'var(--kvc-table-header)',
|
|
40
|
+
primary: buildHues('primary'),
|
|
41
|
+
secondary: buildHues('secondary'),
|
|
42
|
+
tertiary: buildHues('tertiary'),
|
|
43
|
+
gray: buildHues('gray'),
|
|
44
|
+
success: buildHues('success'),
|
|
45
|
+
info: buildHues('info'),
|
|
46
|
+
alert: buildHues('alert'),
|
|
47
|
+
error: buildHues('error'),
|
|
48
|
+
extra: buildHues('extra'),
|
|
55
49
|
},
|
|
56
50
|
},
|
|
57
51
|
transformers: [transformerDirectives()],
|
|
File without changes
|