@bagelink/vue 0.0.200 → 0.0.206
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/Btn.vue.d.ts +3 -0
- package/dist/components/Btn.vue.d.ts.map +1 -1
- package/dist/components/TabbedLayout.vue.d.ts +5 -3
- package/dist/components/TabbedLayout.vue.d.ts.map +1 -1
- package/dist/components/form/BglField.vue.d.ts +23 -0
- package/dist/components/form/BglField.vue.d.ts.map +1 -0
- package/dist/components/form/BglForm.vue.d.ts +36 -0
- package/dist/components/form/BglForm.vue.d.ts.map +1 -0
- package/dist/components/form/ItemRef.vue.d.ts +0 -1
- package/dist/components/form/ItemRef.vue.d.ts.map +1 -1
- package/dist/components/form/index.d.ts +2 -0
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/inputs/CheckInput.vue.d.ts +0 -1
- package/dist/components/form/inputs/CheckInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ColorPicker.vue.d.ts +0 -1
- package/dist/components/form/inputs/ColorPicker.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/CurrencyInput.vue.d.ts +0 -1
- package/dist/components/form/inputs/CurrencyInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts +0 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/FileUpload.vue.d.ts +18 -0
- package/dist/components/form/inputs/FileUpload.vue.d.ts.map +1 -0
- package/dist/components/form/inputs/Password.vue.d.ts +0 -1
- package/dist/components/form/inputs/Password.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/PlainText.vue.d.ts +0 -1
- package/dist/components/form/inputs/PlainText.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RadioPillsInput.vue.d.ts +5 -3
- package/dist/components/form/inputs/RadioPillsInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ReadOnlyInput.vue.d.ts +0 -1
- package/dist/components/form/inputs/ReadOnlyInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectField.vue.d.ts +4 -1
- package/dist/components/form/inputs/SelectField.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TextInput.vue.d.ts +13 -0
- package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/index.d.ts +1 -0
- package/dist/components/form/inputs/index.d.ts.map +1 -1
- package/dist/index.cjs +849 -605
- package/dist/index.mjs +849 -605
- package/dist/style.css +146 -74
- package/dist/types/BagelField.d.ts +1 -8
- package/dist/types/BagelField.d.ts.map +1 -1
- package/dist/types/BagelForm.d.ts +23 -0
- package/dist/types/BagelForm.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/materialIcons.d.ts +1 -1
- package/dist/types/materialIcons.d.ts.map +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Btn.vue +8 -7
- package/src/components/TabbedLayout.vue +58 -45
- package/src/components/form/BglField.vue +30 -0
- package/src/components/form/BglForm.vue +75 -0
- package/src/components/form/index.ts +2 -0
- package/src/components/form/inputs/FileUpload.vue +130 -0
- package/src/components/form/inputs/RadioPillsInput.vue +20 -14
- package/src/components/form/inputs/SelectField.vue +2 -0
- package/src/components/form/inputs/TextInput.vue +44 -8
- package/src/components/form/inputs/index.ts +1 -0
- package/src/types/BagelField.ts +1 -6
- package/src/types/BagelForm.ts +24 -0
- package/src/types/index.ts +11 -2
- package/src/types/materialIcons.ts +1 -0
- package/src/utils/index.ts +10 -23
- package/dist/components/FileUploader.vue.d.ts +0 -60
- package/dist/components/FileUploader.vue.d.ts.map +0 -1
package/src/components/Btn.vue
CHANGED
|
@@ -70,19 +70,20 @@ const props = withDefaults(
|
|
|
70
70
|
type: 'button',
|
|
71
71
|
role: 'button',
|
|
72
72
|
is: 'button',
|
|
73
|
+
border: false,
|
|
73
74
|
},
|
|
74
75
|
);
|
|
75
76
|
|
|
76
77
|
const computedTheme = $computed(
|
|
77
|
-
() => (props?.color || props?.theme)
|
|
78
|
+
() => (props?.color || props?.theme),
|
|
78
79
|
);
|
|
79
80
|
|
|
80
81
|
const computedDefaultColors = $computed(
|
|
81
82
|
() => ({
|
|
82
83
|
backgroundColor: 'var(--bgl-primary)',
|
|
83
|
-
color: props.flat ? 'var(--bgl-black)' : 'var(--bgl-white)'
|
|
84
|
-
})
|
|
85
|
-
)
|
|
84
|
+
color: props.flat ? 'var(--bgl-black)' : 'var(--bgl-white)',
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
86
87
|
|
|
87
88
|
function getThemeColors(theme: Partial<typeof computedDefaultColors>): typeof computedDefaultColors {
|
|
88
89
|
return ({
|
|
@@ -91,17 +92,18 @@ function getThemeColors(theme: Partial<typeof computedDefaultColors>): typeof co
|
|
|
91
92
|
color: props.flat
|
|
92
93
|
? theme.backgroundColor as string
|
|
93
94
|
: theme.color as string,
|
|
94
|
-
})
|
|
95
|
+
});
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
const themes: { [key in ThemeType]: typeof computedDefaultColors } = {
|
|
98
99
|
red: getThemeColors({ backgroundColor: 'var(--bgl-red)' }),
|
|
99
100
|
black: getThemeColors({ backgroundColor: 'var(--bgl-black)' }),
|
|
100
101
|
green: getThemeColors({ backgroundColor: 'var(--bgl-green)', color: 'var(--bgl-white)' }),
|
|
101
|
-
|
|
102
|
+
primary: getThemeColors({ backgroundColor: 'var(--bgl-primary)', color: 'var(--bgl-white)' }),
|
|
102
103
|
gray: getThemeColors({ backgroundColor: 'var(--bgl-gray-light)', color: 'var(--bgl-black)' }),
|
|
103
104
|
light: getThemeColors({ backgroundColor: 'var(--bgl-primary-light)', color: 'var(--bgl-primary)' }),
|
|
104
105
|
'gray-light': getThemeColors({ backgroundColor: 'var(--bgl-gray-light)', color: 'var(--bgl-gray)' }),
|
|
106
|
+
blue: getThemeColors({}),
|
|
105
107
|
};
|
|
106
108
|
|
|
107
109
|
const cumputedTextColor = $computed(
|
|
@@ -184,7 +186,6 @@ const computedBackgroundColor = $computed(
|
|
|
184
186
|
filter: var(--bgl-active-filter);
|
|
185
187
|
}
|
|
186
188
|
|
|
187
|
-
|
|
188
189
|
.btn.flatBtn {
|
|
189
190
|
padding-left: var(--btn-padding);
|
|
190
191
|
padding-right: var(--btn-padding);
|
|
@@ -1,65 +1,65 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
</div>
|
|
2
|
+
<div class="h-100 grid list-view gap-3" :class="{'side-tabs': sideTabs}">
|
|
3
|
+
<div class="card tabs-top">
|
|
4
|
+
<slot name="top-section" />
|
|
5
|
+
<div class="tabs grid auto-flow-columns fit-content">
|
|
6
|
+
<div
|
|
7
|
+
v-for="tab in tabs"
|
|
8
|
+
:class="{
|
|
9
|
+
active:
|
|
10
|
+
tab === activeTab ||
|
|
11
|
+
tab === router?.currentRoute.value.path.split('/').slice(-1)[0],
|
|
12
|
+
}"
|
|
13
|
+
class="tab"
|
|
14
|
+
:key="tab"
|
|
15
|
+
@click="changeTab(tab)"
|
|
16
|
+
>
|
|
17
|
+
{{ tab }}
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
<div
|
|
22
|
+
class="list-content"
|
|
23
|
+
v-for="tab in tabs.filter((item) => item === activeTab)"
|
|
24
|
+
:key="tab"
|
|
25
|
+
>
|
|
26
|
+
<slot :name="tab" :key="tab" />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
30
29
|
</template>
|
|
31
30
|
|
|
32
31
|
<script setup lang="ts">
|
|
33
|
-
import { onMounted } from
|
|
34
|
-
import type { Router } from
|
|
32
|
+
import { onMounted } from 'vue';
|
|
33
|
+
import type { Router } from 'vue-router';
|
|
35
34
|
|
|
36
|
-
const emit = defineEmits([
|
|
35
|
+
const emit = defineEmits(['update:modelValue']);
|
|
37
36
|
|
|
38
37
|
let activeTab = $ref<string>();
|
|
39
38
|
const props = defineProps<{
|
|
40
39
|
title?: string;
|
|
41
40
|
tabs: string[];
|
|
42
41
|
modelValue?: string;
|
|
43
|
-
router
|
|
42
|
+
router?: Router;
|
|
43
|
+
sideTabs?: boolean;
|
|
44
44
|
}>();
|
|
45
45
|
|
|
46
46
|
function changeTab(tab: string) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
activeTab = tab;
|
|
48
|
+
emit('update:modelValue', activeTab);
|
|
49
|
+
if (!props.router) return;
|
|
50
|
+
void props.router?.push({
|
|
51
|
+
path: props.router.currentRoute.value.path,
|
|
52
|
+
query: { ...props.router.currentRoute.value.query, t: tab },
|
|
53
|
+
hash: props.router.currentRoute.value.hash,
|
|
54
|
+
});
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
onMounted(() => {
|
|
58
|
-
|
|
58
|
+
const firstTab =
|
|
59
59
|
props.modelValue ||
|
|
60
|
-
props.router
|
|
60
|
+
props.router?.currentRoute.value.query.t ||
|
|
61
61
|
props.tabs[0];
|
|
62
|
-
|
|
62
|
+
activeTab = firstTab as string;
|
|
63
63
|
});
|
|
64
64
|
</script>
|
|
65
65
|
|
|
@@ -68,7 +68,20 @@ onMounted(() => {
|
|
|
68
68
|
text-transform: capitalize;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
.
|
|
72
|
-
|
|
71
|
+
.side-tabs{
|
|
72
|
+
display: flex;
|
|
73
|
+
}
|
|
74
|
+
.side-tabs .tabs-top{
|
|
75
|
+
margin-inline-end: 1rem;
|
|
76
|
+
}
|
|
77
|
+
.side-tabs .tabs{
|
|
78
|
+
display: block;
|
|
79
|
+
padding: 0;
|
|
80
|
+
margin: 0;
|
|
81
|
+
border: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.side-tabs .tab{
|
|
85
|
+
border: none;
|
|
73
86
|
}
|
|
74
87
|
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:required="field.required"
|
|
4
|
+
v-bind="bindAttrs(field?.attrs||{}, props.modelValue[field.id || ''], props.modelValue,)"
|
|
5
|
+
:is="field.$el || 'div'"
|
|
6
|
+
:label="field.label"
|
|
7
|
+
:id="field.id"
|
|
8
|
+
:placeholder="field.placeholder || field.label"
|
|
9
|
+
:modelValue="props.modelValue[field.id || '']"
|
|
10
|
+
@update:modelValue="($event:any)=>emits('update:modelValue', $event)"
|
|
11
|
+
>
|
|
12
|
+
<BglField
|
|
13
|
+
:modelValue="modelValue"
|
|
14
|
+
@update:modelValue="($event:any)=>emits('update:modelValue', $event)"
|
|
15
|
+
v-for="(child,ii) in field.children" :key="child.id||ii"
|
|
16
|
+
:field="child"
|
|
17
|
+
/>
|
|
18
|
+
</component>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script lang="ts" setup>
|
|
22
|
+
import { type Field, bindAttrs } from '@bagelink/vue';
|
|
23
|
+
|
|
24
|
+
const props = defineProps<{
|
|
25
|
+
modelValue: Record<string, any>;
|
|
26
|
+
field: Field
|
|
27
|
+
}>();
|
|
28
|
+
|
|
29
|
+
const emits = defineEmits(['update:modelValue']);
|
|
30
|
+
</script>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<form @submit.prevent="runSubmit">
|
|
3
|
+
<BglField
|
|
4
|
+
v-for="(field, i) in schema" :key="field.id || `${i }p`" :field="field" :modelValue="data"
|
|
5
|
+
@update:modelValue="($event: any) => field.id ? data[field.id] = $event : ''"
|
|
6
|
+
/>
|
|
7
|
+
<Btn
|
|
8
|
+
class="del-top" v-if="modelValue?.id && onDelete" @click="runDelete" value="Delete" flat icon="delete"
|
|
9
|
+
color="red" thin
|
|
10
|
+
/>
|
|
11
|
+
<Btn v-if="!$slots.submit && onSubmit" value="Submit" type="submit" thin />
|
|
12
|
+
<div v-else>
|
|
13
|
+
<slot name="submit"/>
|
|
14
|
+
</div>
|
|
15
|
+
</form>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script lang="ts" setup>
|
|
19
|
+
import { watch } from 'vue';
|
|
20
|
+
import { Btn, useModal, BglField } from '@bagelink/vue';
|
|
21
|
+
import { type BglFormSchemaT } from '@bagelink/vue';
|
|
22
|
+
|
|
23
|
+
const { showModal } = useModal();
|
|
24
|
+
|
|
25
|
+
const props = defineProps<{
|
|
26
|
+
modelValue?: any;
|
|
27
|
+
schema: BglFormSchemaT;
|
|
28
|
+
onDelete?: ((id: string) => void);
|
|
29
|
+
onSubmit?: ((data: any) => void);
|
|
30
|
+
}>();
|
|
31
|
+
|
|
32
|
+
const emits = defineEmits(['update:modelValue', 'submit']);
|
|
33
|
+
const handleEmit = (val: any) => emits('update:modelValue', val);
|
|
34
|
+
let data = $ref({
|
|
35
|
+
...props.modelValue,
|
|
36
|
+
});
|
|
37
|
+
const runSubmit = () => {
|
|
38
|
+
emits('submit', data);
|
|
39
|
+
clearForm();
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const clearForm = () => data = {};
|
|
43
|
+
|
|
44
|
+
const i18nT = (val: string) => val;
|
|
45
|
+
|
|
46
|
+
watch(
|
|
47
|
+
() => data,
|
|
48
|
+
() => handleEmit,
|
|
49
|
+
{ immediate: true },
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const runDelete = () => {
|
|
53
|
+
showModal(
|
|
54
|
+
{
|
|
55
|
+
class: 'small-modal',
|
|
56
|
+
title: i18nT('Are you sure?'),
|
|
57
|
+
actions: [
|
|
58
|
+
{
|
|
59
|
+
value: 'Confirm',
|
|
60
|
+
color: 'red',
|
|
61
|
+
onClick: () => props.onDelete?.(data.id),
|
|
62
|
+
},
|
|
63
|
+
{ value: 'Cancel', color: 'gray' },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{ default: i18nT('form.deleteMessage') },
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<style>
|
|
72
|
+
.del-top {
|
|
73
|
+
transform: translateY(-2.6rem);
|
|
74
|
+
}
|
|
75
|
+
</style>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { default as ItemRef } from './ItemRef.vue';
|
|
2
2
|
export { default as MaterialIcon } from './MaterialIcon.vue';
|
|
3
3
|
export { default as PlainInputField } from './PlainInputField.vue';
|
|
4
|
+
export { default as BglForm } from './BglForm.vue';
|
|
5
|
+
export { default as BglField } from './BglField.vue';
|
|
4
6
|
export * from './inputs';
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="bagel-input">
|
|
3
|
+
<label>
|
|
4
|
+
{{ label }}
|
|
5
|
+
</label>
|
|
6
|
+
<div @click="browse" @dragover="dragenter" @drop="drop" @dragleave="dragleave" class="fileUploadWrap" :class="{fileDropZone: !files.length, dragover: isDragOver}">
|
|
7
|
+
<div v-if="files.length && !multiple">
|
|
8
|
+
<div class="imagePreviewWrap">
|
|
9
|
+
<img class="preview" :src="fileToUrl(files[0])" alt="" >
|
|
10
|
+
</div>
|
|
11
|
+
<div class="previewName">
|
|
12
|
+
<p class="no-margin">
|
|
13
|
+
{{files[0].name}}
|
|
14
|
+
</p>
|
|
15
|
+
<Btn thin @click.stop="removeFile(files[0])" flat icon="delete" color="red"/>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { Btn } from '@bagelink/vue';
|
|
24
|
+
|
|
25
|
+
const props = defineProps<{label:string, multiple?: boolean}>();
|
|
26
|
+
const files = $ref<File[]>([]);
|
|
27
|
+
const fileQueue = $ref<File[]>([]);
|
|
28
|
+
let isDragOver = $ref(false);
|
|
29
|
+
|
|
30
|
+
const preventDefault = (e: Event) => {
|
|
31
|
+
e.preventDefault();
|
|
32
|
+
e.stopPropagation();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const fileToUrl = (file: File) => URL.createObjectURL(file);
|
|
36
|
+
const removeFile = (file:File) => {
|
|
37
|
+
const index = files.indexOf(file);
|
|
38
|
+
files.splice(index, 1);
|
|
39
|
+
};
|
|
40
|
+
const flushQueue = () => {
|
|
41
|
+
fileQueue.forEach((file:File, i) => {
|
|
42
|
+
if (props.multiple) { if (!files.includes(file)) files.push(file); } else files.splice(0, 1, file);
|
|
43
|
+
console.log(files);
|
|
44
|
+
fileQueue.splice(i, 1);
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const browse = () => {
|
|
49
|
+
const input = document.createElement('input');
|
|
50
|
+
input.type = 'file';
|
|
51
|
+
input.multiple = props.multiple;
|
|
52
|
+
input.onchange = (e: Event) => {
|
|
53
|
+
const target = e?.target as HTMLInputElement;
|
|
54
|
+
if (target?.files) fileQueue.push(...Array.from(target.files));
|
|
55
|
+
flushQueue();
|
|
56
|
+
};
|
|
57
|
+
input.click();
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const dragleave = (e: DragEvent) => {
|
|
61
|
+
preventDefault(e);
|
|
62
|
+
if (e.dataTransfer) isDragOver = false;
|
|
63
|
+
else isDragOver = false;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const dragenter = (e: DragEvent) => {
|
|
67
|
+
preventDefault(e);
|
|
68
|
+
if (e.dataTransfer) isDragOver = true;
|
|
69
|
+
else isDragOver = false;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const drop = (e: DragEvent) => {
|
|
73
|
+
preventDefault(e);
|
|
74
|
+
if (e.dataTransfer) fileQueue.push(...Array.from(e.dataTransfer.files));
|
|
75
|
+
isDragOver = false;
|
|
76
|
+
flushQueue();
|
|
77
|
+
};
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<style scoped>
|
|
81
|
+
.bagel-input .fileUploadWrap {
|
|
82
|
+
outline: 1px solid var(--border-color);
|
|
83
|
+
border-radius: var(--input-border-radius);
|
|
84
|
+
text-align: center;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
transition: var(--bgl-transition);
|
|
87
|
+
position: relative;
|
|
88
|
+
height: 132px;
|
|
89
|
+
font-size: var(--input-font-size);
|
|
90
|
+
}
|
|
91
|
+
.previewName{
|
|
92
|
+
padding: 0.5rem;
|
|
93
|
+
text-align: start;
|
|
94
|
+
color: var(--input-color);
|
|
95
|
+
display: grid;
|
|
96
|
+
grid-template-columns: 1fr 22px;
|
|
97
|
+
align-items: center;
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
.previewName p{
|
|
101
|
+
overflow: hidden;
|
|
102
|
+
text-overflow: ellipsis;
|
|
103
|
+
white-space: nowrap;
|
|
104
|
+
}
|
|
105
|
+
.imagePreviewWrap{
|
|
106
|
+
background: var(--input-bg);
|
|
107
|
+
border-radius: var(--input-border-radius);
|
|
108
|
+
height: 90px;
|
|
109
|
+
padding: 5px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
img.preview {
|
|
113
|
+
height: 80px;
|
|
114
|
+
border-radius: var(--input-border-radius);
|
|
115
|
+
object-fit: contain;
|
|
116
|
+
}
|
|
117
|
+
.fileUploadWrap.dragover, .fileUploadWrap:hover{
|
|
118
|
+
box-shadow: inset 0 0 10px #00000012;
|
|
119
|
+
}
|
|
120
|
+
.bagel-input .fileUploadWrap.fileDropZone{
|
|
121
|
+
background: var(--input-bg);
|
|
122
|
+
display: flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
color:var(--bgl-gray);
|
|
126
|
+
}
|
|
127
|
+
.bagel-input .fileUploadWrap.fileDropZone:after {
|
|
128
|
+
content: "Drop files here or click to upload";
|
|
129
|
+
}
|
|
130
|
+
</style>
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
<div class="bagel-input">
|
|
3
|
+
<label class="pb-025" >
|
|
4
|
+
{{ label }}
|
|
5
|
+
</label>
|
|
6
|
+
<div class="flex gap-2 flex-wrap">
|
|
7
|
+
<div class="radio-pill" v-for="({optioId,label,value}, index) in cumputedOptions" :key="index">
|
|
8
|
+
<input
|
|
9
|
+
type="radio"
|
|
10
|
+
:id="optioId"
|
|
11
|
+
:name="id"
|
|
12
|
+
:value="value"
|
|
13
|
+
:checked="selectedValue === value"
|
|
14
|
+
@change="handleSelect"
|
|
15
|
+
>
|
|
16
|
+
<label :for="optioId">{{ label }}</label>
|
|
17
|
+
</div>
|
|
13
18
|
</div>
|
|
14
19
|
</div>
|
|
15
20
|
</template>
|
|
@@ -18,7 +23,7 @@
|
|
|
18
23
|
import { onMounted, watch } from 'vue';
|
|
19
24
|
|
|
20
25
|
interface RadioOption {
|
|
21
|
-
|
|
26
|
+
optioId: string;
|
|
22
27
|
label: string;
|
|
23
28
|
value: any;
|
|
24
29
|
}
|
|
@@ -28,11 +33,12 @@ const props = defineProps<{
|
|
|
28
33
|
options?: RadioOption[],
|
|
29
34
|
stringOptions: string[],
|
|
30
35
|
modelValue: any,
|
|
31
|
-
|
|
36
|
+
id?: string,
|
|
37
|
+
label?: string,
|
|
32
38
|
}>();
|
|
33
39
|
|
|
34
40
|
const cumputedOptions = $computed(() => props.options || props.stringOptions.map((v) => ({
|
|
35
|
-
|
|
41
|
+
optioId: v,
|
|
36
42
|
label: v,
|
|
37
43
|
value: v,
|
|
38
44
|
})));
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="bagel-input"
|
|
4
|
-
:class="{ small, shrink, toggleEdit, editMode, textInputIconWrap: icon, txtInputIconStart: iconStart }"
|
|
3
|
+
class="bagel-input text-input"
|
|
4
|
+
:class="{ small, shrink, toggleEdit, editMode, textInputIconWrap: icon, txtInputIconStart: iconStart, code }"
|
|
5
5
|
:title="title"
|
|
6
6
|
>
|
|
7
7
|
<label :for="id">
|
|
8
8
|
{{ label }}
|
|
9
9
|
<input
|
|
10
|
+
:autocomplete="autocomplete"
|
|
11
|
+
v-if="!multiline && !autoheight && !code"
|
|
10
12
|
:id="id"
|
|
11
13
|
v-model="inputVal"
|
|
12
14
|
:type="type"
|
|
15
|
+
:rows="1"
|
|
13
16
|
ref="input"
|
|
14
17
|
:placeholder="placeholder || label"
|
|
15
18
|
:disabled="!editMode"
|
|
@@ -17,8 +20,21 @@
|
|
|
17
20
|
:pattern="pattern"
|
|
18
21
|
v-bind="nativeInputAttrs"
|
|
19
22
|
@dblclick="toggleEditAction"
|
|
20
|
-
@keydown.enter="toggleEditAction"
|
|
21
23
|
>
|
|
24
|
+
<textarea
|
|
25
|
+
v-else
|
|
26
|
+
:id="id"
|
|
27
|
+
v-model="inputVal"
|
|
28
|
+
:type="type"
|
|
29
|
+
:rows="rows"
|
|
30
|
+
ref="input"
|
|
31
|
+
:placeholder="placeholder || label"
|
|
32
|
+
:disabled="!editMode"
|
|
33
|
+
:required="required"
|
|
34
|
+
:pattern="pattern"
|
|
35
|
+
v-bind="nativeInputAttrs"
|
|
36
|
+
@dblclick="toggleEditAction"
|
|
37
|
+
/>
|
|
22
38
|
</label>
|
|
23
39
|
|
|
24
40
|
<MaterialIcon
|
|
@@ -64,11 +80,17 @@ const props = withDefaults(
|
|
|
64
80
|
nativeInputAttrs?: Record<string, any>;
|
|
65
81
|
icon?: MaterialIcons;
|
|
66
82
|
iconStart?: MaterialIcons;
|
|
83
|
+
multiline?: boolean;
|
|
84
|
+
autoheight?: boolean;
|
|
85
|
+
code?: boolean;
|
|
86
|
+
lines?: number;
|
|
87
|
+
autocomplete?: string;
|
|
67
88
|
}>(),
|
|
68
89
|
{
|
|
69
90
|
type: 'text',
|
|
70
91
|
toggleEdit: false,
|
|
71
92
|
modelValue: '',
|
|
93
|
+
autocomplete: 'off',
|
|
72
94
|
},
|
|
73
95
|
);
|
|
74
96
|
let inputVal = $ref<string | number>();
|
|
@@ -87,6 +109,13 @@ const toggleEditAction = () => {
|
|
|
87
109
|
}
|
|
88
110
|
};
|
|
89
111
|
|
|
112
|
+
const rows = $computed(() => {
|
|
113
|
+
if (props.lines) return props.lines;
|
|
114
|
+
if (props.autoheight) return `${inputVal}`?.split('\n').length || 1;
|
|
115
|
+
if (props.multiline || props.code) return 4;
|
|
116
|
+
return 1;
|
|
117
|
+
});
|
|
118
|
+
|
|
90
119
|
watch(
|
|
91
120
|
() => inputVal,
|
|
92
121
|
(newVal) => {
|
|
@@ -115,10 +144,17 @@ watch(
|
|
|
115
144
|
</style>
|
|
116
145
|
|
|
117
146
|
<style scoped>
|
|
118
|
-
.bagel-input
|
|
119
|
-
|
|
147
|
+
.bagel-input textarea{
|
|
148
|
+
min-height: unset;
|
|
149
|
+
}
|
|
150
|
+
.bagel-input.text-input textarea{
|
|
151
|
+
resize: none;
|
|
152
|
+
}
|
|
153
|
+
.code textarea{
|
|
154
|
+
font-family: 'Inconsolata', monospace;
|
|
155
|
+
background: var(--bgl-black) !important;
|
|
156
|
+
color: var(--bgl-white) !important;
|
|
120
157
|
}
|
|
121
|
-
|
|
122
158
|
.bagel-input.toggleEdit:hover {
|
|
123
159
|
background-color: var(--input-bg);
|
|
124
160
|
}
|
|
@@ -155,7 +191,7 @@ watch(
|
|
|
155
191
|
color: var(--bgl-gray);
|
|
156
192
|
}
|
|
157
193
|
|
|
158
|
-
.txtInputIconStart
|
|
194
|
+
.txtInputIconStart textarea {
|
|
159
195
|
padding-inline-start: 2rem;
|
|
160
196
|
}
|
|
161
197
|
|
|
@@ -164,7 +200,7 @@ watch(
|
|
|
164
200
|
opacity: 1;
|
|
165
201
|
}
|
|
166
202
|
|
|
167
|
-
.bagel-input.small
|
|
203
|
+
.bagel-input.small textarea {
|
|
168
204
|
height: 30px;
|
|
169
205
|
}
|
|
170
206
|
</style>
|
|
@@ -22,3 +22,4 @@ export { default as DynamicLinkField } from './DynamicLinkField.vue';
|
|
|
22
22
|
export { default as PlainText } from './PlainText.vue';
|
|
23
23
|
export { default as DatePicker } from './DatePicker.vue';
|
|
24
24
|
export { default as RadioPillsInput } from './RadioPillsInput.vue';
|
|
25
|
+
export { default as FileUpload } from './FileUpload.vue';
|
package/src/types/BagelField.ts
CHANGED
|
@@ -49,9 +49,4 @@ export interface NestedBagelForm extends BaseBagelField {
|
|
|
49
49
|
fields: NestedBagelFormFields;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export
|
|
53
|
-
inputType: 'SelectField';
|
|
54
|
-
options: string | { label: string; value: string | number }[];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export type BagelField = BaseBagelField | SelectBagelField | NestedBagelForm;
|
|
52
|
+
export type BagelField = BaseBagelField | NestedBagelForm;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type AttributeValue = string | number | boolean | null | undefined | Record<string, any>;
|
|
2
|
+
|
|
3
|
+
export type AttributeFn<T = Record<string, any>> = (field: any, row: T) => AttributeValue;
|
|
4
|
+
|
|
5
|
+
export interface Attributes<T = any> {
|
|
6
|
+
[key: string]: AttributeValue | AttributeFn<T>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type Field<T = Record<string, any>> = {
|
|
10
|
+
$el?: any;
|
|
11
|
+
id?: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
children?: Field<T>[];
|
|
15
|
+
attrs?: Attributes<T>;
|
|
16
|
+
required?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface SelectBagelField {
|
|
20
|
+
inputType: 'SelectField';
|
|
21
|
+
options: string | { label: string; value: string | number }[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type BglFormSchemaT<T = Record<string, any>> = Field<T>[];
|
package/src/types/index.ts
CHANGED
|
@@ -2,7 +2,16 @@ export type { MaterialIcons } from './materialIcons';
|
|
|
2
2
|
export type { BankDetailsInterface, NewPerson, Person } from './Person';
|
|
3
3
|
export type { Tables, TableToTypeMapping } from '@bagelink/sdk';
|
|
4
4
|
export type { StorageFile } from './file';
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
export * from './BtnOptions';
|
|
7
|
+
export * from './BagelForm';
|
|
7
8
|
|
|
8
|
-
export type ThemeType =
|
|
9
|
+
export type ThemeType = |
|
|
10
|
+
'light'
|
|
11
|
+
| 'red'
|
|
12
|
+
| 'gray'
|
|
13
|
+
| 'gray-light'
|
|
14
|
+
| 'black'
|
|
15
|
+
| 'green'
|
|
16
|
+
| 'primary'
|
|
17
|
+
| 'blue' // ! blue does nothing
|