@bagelink/vue 0.0.25 → 0.0.32

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.
Files changed (82) hide show
  1. package/package.json +32 -9
  2. package/src/components/Btn.vue +221 -0
  3. package/src/components/Comments.vue +265 -0
  4. package/src/components/ContactArray.vue +127 -0
  5. package/src/components/ContactSubmissions.vue +42 -0
  6. package/src/components/DataPreview.vue +72 -0
  7. package/src/components/DropDown.vue +122 -0
  8. package/src/components/FileUploader.vue +344 -0
  9. package/src/components/FormKitTable.vue +250 -0
  10. package/src/components/FormSchema.vue +65 -0
  11. package/src/components/LangText.vue +30 -0
  12. package/src/components/ListItem.vue +16 -0
  13. package/src/components/ListView.vue +39 -0
  14. package/src/components/MaterialIcon.vue +16 -0
  15. package/src/components/Modal.vue +50 -0
  16. package/src/components/ModalForm.vue +94 -0
  17. package/src/components/NavBar.vue +343 -0
  18. package/src/components/PageTitle.vue +17 -0
  19. package/src/components/PersonPreview.vue +205 -0
  20. package/src/components/PersonPreviewFormkit.vue +205 -0
  21. package/src/components/RTXEditor.vue +147 -0
  22. package/src/components/RouterWrapper.vue +9 -0
  23. package/src/components/TabbedLayout.vue +80 -0
  24. package/src/components/TableSchema.vue +213 -0
  25. package/src/components/TopBar.vue +5 -0
  26. package/src/components/charts/BarChart.vue +290 -0
  27. package/src/components/dashboard/Lineart.vue +165 -0
  28. package/src/components/form/ItemRef.vue +38 -0
  29. package/src/components/form/MaterialIcon.vue +19 -0
  30. package/src/components/form/PlainInputField.vue +80 -0
  31. package/src/components/form/inputs/CheckInput.vue +143 -0
  32. package/src/components/form/inputs/Checkbox.vue +69 -0
  33. package/src/components/form/inputs/ColorPicker.vue +37 -0
  34. package/src/components/form/inputs/CurrencyInput.vue +133 -0
  35. package/src/components/form/inputs/DateInput.vue +49 -0
  36. package/src/components/form/inputs/DatetimeInput.vue +46 -0
  37. package/src/components/form/inputs/DurationInput.vue +51 -0
  38. package/src/components/form/inputs/DynamicLinkField.vue +140 -0
  39. package/src/components/form/inputs/EmailInput.vue +53 -0
  40. package/src/components/form/inputs/FloatInput.vue +48 -0
  41. package/src/components/form/inputs/IntInput.vue +49 -0
  42. package/src/components/form/inputs/JSONInput.vue +51 -0
  43. package/src/components/form/inputs/LinkField.vue +293 -0
  44. package/src/components/form/inputs/Password.vue +89 -0
  45. package/src/components/form/inputs/PasswordInput.vue +89 -0
  46. package/src/components/form/inputs/PlainText.vue +52 -0
  47. package/src/components/form/inputs/ReadOnlyInput.vue +24 -0
  48. package/src/components/form/inputs/RichTextEditor.vue +54 -0
  49. package/src/components/form/inputs/SelectField.vue +253 -0
  50. package/src/components/form/inputs/TableField.vue +321 -0
  51. package/src/components/form/inputs/TextArea.vue +70 -0
  52. package/src/components/form/inputs/TextInput.vue +53 -0
  53. package/src/components/form/inputs/index.ts +17 -0
  54. package/src/components/formkit/AddressArray.vue +240 -0
  55. package/src/components/formkit/BankDetailsArray.vue +265 -0
  56. package/src/components/formkit/ContactArrayFormKit.vue +151 -0
  57. package/src/components/formkit/FileUploader.vue +391 -0
  58. package/src/components/formkit/MiscFields.vue +69 -0
  59. package/src/components/formkit/Toggle.vue +160 -0
  60. package/src/components/formkit/index.ts +29 -0
  61. package/src/components/index.ts +20 -0
  62. package/src/components/whatsapp/form/MsgTemplate.vue +220 -0
  63. package/src/components/whatsapp/form/TextVariableExamples.vue +74 -0
  64. package/src/components/whatsapp/interfaces.ts +58 -0
  65. package/src/index.ts +1 -26
  66. package/src/plugins/bagel.ts +26 -0
  67. package/src/styles/modal.css +90 -0
  68. package/src/types/BagelField.ts +57 -0
  69. package/src/types/BtnOptions.ts +14 -0
  70. package/src/types/Person.ts +51 -0
  71. package/src/types/file.ts +12 -0
  72. package/src/types/index.ts +4 -0
  73. package/src/types/materialIcons.d.ts +3005 -0
  74. package/src/utils/index.ts +57 -0
  75. package/src/utils/modal.ts +95 -0
  76. package/src/utils/objects.ts +81 -0
  77. package/src/utils/strings.ts +29 -0
  78. package/dist/index.cjs +0 -23
  79. package/dist/index.d.cts +0 -12
  80. package/dist/index.d.mts +0 -12
  81. package/dist/index.d.ts +0 -12
  82. package/dist/index.mjs +0 -19
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <div
3
+ class="bagel-input checkbox"
4
+ :title="field.description"
5
+ :class="{ small: small, 'no-edit': !editMode }"
6
+ >
7
+ <label :for="field.id">
8
+ {{ field.label }}
9
+ </label>
10
+ <label class="switch">
11
+ <input
12
+ :id="field.id"
13
+ type="checkbox"
14
+ v-model="inputVal"
15
+ :class="{ 'no-edit': !editMode }"
16
+ >
17
+ <span class="slider round" />
18
+ </label>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { watch, ref, onMounted } from 'vue';
24
+ import { BagelField } from '@/types';
25
+
26
+ const emits = defineEmits(['update:modelValue']);
27
+ const props = withDefaults(
28
+ defineProps<{
29
+ field: BagelField;
30
+ modelValue: any;
31
+ editMode?: boolean;
32
+ small?: boolean;
33
+ }>(),
34
+ {
35
+ editMode: true,
36
+ },
37
+ );
38
+
39
+ const inputVal = ref(false);
40
+ watch(inputVal, (newVal) => {
41
+ if (newVal === undefined) return;
42
+ emits('update:modelValue', newVal);
43
+ });
44
+ watch(
45
+ () => props.modelValue,
46
+ (newVal) => {
47
+ if (inputVal.value !== newVal) inputVal.value = newVal;
48
+ },
49
+ );
50
+ onMounted(() => (inputVal.value = !!props.modelValue));
51
+ </script>
52
+
53
+ <style scoped>
54
+ .no-edit {
55
+ pointer-events: none;
56
+ }
57
+
58
+ .radio-wrap p {
59
+ display: inline-block;
60
+ color: var(--input-bg);
61
+ font-size: var(--input-font-size);
62
+ margin-inline-end: 10px;
63
+ }
64
+
65
+ .radio-wrap label {
66
+ padding: 3px 5px;
67
+ display: inline-block;
68
+ border-radius: var(--input-border-radius);
69
+ font-size: var(--input-font-size);
70
+ background: var(--input-bg);
71
+ color: var(--bgl-black);
72
+ text-align: center;
73
+ margin: 8px 5px;
74
+ cursor: pointer;
75
+ user-select: none;
76
+ }
77
+
78
+ .bagel-input .radio-wrap label::after {
79
+ background: transparent;
80
+ }
81
+
82
+ .radio-wrap input {
83
+ display: none;
84
+ }
85
+
86
+ .radio-wrap input:checked:checked + label {
87
+ background: var(--bgl-blue);
88
+ color: var(--bgl-white);
89
+ }
90
+
91
+ .checkbox {
92
+ position: relative;
93
+ }
94
+
95
+ .switch {
96
+ position: relative;
97
+ display: inline-block;
98
+ height: calc(var(--input-height) / 2);
99
+ width: var(--input-height);
100
+ border-radius: var(--input-height);
101
+ }
102
+
103
+ .switch input {
104
+ opacity: 0;
105
+ width: 0;
106
+ height: 0;
107
+ }
108
+
109
+ .slider {
110
+ position: absolute;
111
+ cursor: pointer;
112
+ top: 0;
113
+ left: 0;
114
+ right: 0;
115
+ bottom: 0;
116
+ background: var(--input-bg);
117
+ -webkit-transition: 0.4s;
118
+ transition: 0.4s;
119
+ border-radius: calc(var(--input-height) / 2);
120
+ box-shadow: inset 0 0 10px #00000020;
121
+ }
122
+
123
+ .slider:before {
124
+ position: absolute;
125
+ content: '';
126
+ height: calc(var(--input-height) / 2 - 4px);
127
+ width: calc(var(--input-height) / 2 - 4px);
128
+ left: 2px;
129
+ bottom: 2px;
130
+ border-radius: 50%;
131
+ background: var(--bgl-white);
132
+ -webkit-transition: 0.4s;
133
+ transition: 0.4s;
134
+ }
135
+
136
+ input:checked + .slider {
137
+ background: var(--bgl-blue);
138
+ }
139
+
140
+ input:checked + .slider:before {
141
+ transform: translateX(calc(var(--input-height) / 2));
142
+ }
143
+ </style>
@@ -0,0 +1,69 @@
1
+ <template>
2
+ <label class="primary-checkbox">
3
+ <input type="checkbox" v-model="val" >
4
+ <span>
5
+ <MaterialIcon icon="check" />
6
+ </span>
7
+ </label>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { watch } from 'vue';
12
+ import { MaterialIcon } from '@/components';
13
+
14
+ const props = defineProps({
15
+ modelValue: Boolean,
16
+ });
17
+
18
+ const emits = defineEmits(['update:modelValue']);
19
+
20
+ let val = $ref<boolean>();
21
+
22
+ watch(
23
+ () => props.modelValue,
24
+ (v: boolean) => {
25
+ if (v === undefined || v === val) return;
26
+ val = v;
27
+ },
28
+ { immediate: true },
29
+ );
30
+
31
+ watch(
32
+ () => val,
33
+ (v) => emits('update:modelValue', v),
34
+ );
35
+ </script>
36
+
37
+ <style scoped>
38
+ .primary-checkbox input {
39
+ display: none;
40
+ }
41
+ .primary-checkbox {
42
+ margin-top: 8px;
43
+ }
44
+ .primary-checkbox span {
45
+ display: flex;
46
+ padding-top: 1px;
47
+ align-items: center;
48
+ justify-content: center;
49
+ color: var(--bgl-white);
50
+ border-radius: 100%;
51
+ width: 26px;
52
+ height: 26px;
53
+ background: white;
54
+ border: 4px solid var(--bgl-gray-light);
55
+ cursor: pointer;
56
+ transition: var(--bgl-transition);
57
+ user-select: none;
58
+ }
59
+ .primary-checkbox span:hover {
60
+ filter: brightness(90%);
61
+ }
62
+ .primary-checkbox span:active {
63
+ filter: brightness(80%);
64
+ }
65
+ .primary-checkbox input:checked + span {
66
+ background: var(--bgl-blue);
67
+ border: none;
68
+ }
69
+ </style>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <div class="bagel-input" :class="{ small }" :title="field.description" v-if="field.id">
3
+ <label :for="field.id">
4
+ {{ field.label }}
5
+ <input
6
+ :id="field.id" v-model="inputVal" type="color" :placeholder="field.placeholder || field.label"
7
+ :class="{ 'no-edit': !editMode }" :required="required" v-bind="nativeInputAttrs"
8
+ >
9
+ </label>
10
+ </div>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import { watch } from 'vue';
15
+ import { type BagelField } from '@/types';
16
+
17
+ const emits = defineEmits(['update:modelValue']);
18
+ const props = withDefaults(
19
+ defineProps<{
20
+ field: BagelField;
21
+ modelValue: any;
22
+ editMode?: boolean;
23
+ small?: boolean;
24
+ required?: boolean;
25
+ nativeInputAttrs?: Record<string, any>;
26
+ }>(),
27
+ {
28
+ editMode: true,
29
+ },
30
+ );
31
+ const inputVal = $ref<string>(props.modelValue);
32
+
33
+ watch(
34
+ () => inputVal,
35
+ (newVal) => emits('update:modelValue', newVal),
36
+ );
37
+ </script>
@@ -0,0 +1,133 @@
1
+ <template>
2
+ <div class="bagel-input" :title="field.description" :class="{ small: small }">
3
+ <label v-if="field.label">
4
+ {{ field.label }}
5
+ </label>
6
+ <div class="flex gap-3">
7
+ <input
8
+ :value="modelValue"
9
+ type="number"
10
+ @input="handleInput"
11
+ :placeholder="placeholder"
12
+ :class="{ 'no-edit': !editMode }"
13
+ >
14
+ <p class="currency">
15
+ {{
16
+ currencies.find((c) => c.symbol === field.currency)?.character ||
17
+ field.currency
18
+ }}
19
+ </p>
20
+ </div>
21
+ </div>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { BagelField } from '@/types';
26
+
27
+ const emits = defineEmits(['update:modelValue']);
28
+ withDefaults(
29
+ defineProps<{
30
+ field: BagelField;
31
+ modelValue: any;
32
+
33
+ placeholder?: string;
34
+ editMode?: boolean;
35
+ small?: boolean;
36
+ }>(),
37
+ {
38
+ editMode: true,
39
+ },
40
+ );
41
+ const handleInput = (e: Event) => {
42
+ const el = e.target as HTMLInputElement;
43
+ let value = parseFloat(el.value);
44
+ if (Number.isNaN(value)) {
45
+ value = 0;
46
+ }
47
+ emits('update:modelValue', value);
48
+ };
49
+
50
+ const currencies = [
51
+ { name: 'United Arab Emirates Dirham', symbol: 'AED', character: 'د.إ' },
52
+ { name: 'Afghan Afghani', symbol: 'AFN', character: '؋' },
53
+ { name: 'Albanian Lek', symbol: 'ALL', character: 'L' },
54
+ { name: 'Armenian Dram', symbol: 'AMD', character: '֏' },
55
+ { name: 'Netherlands Antillean Guilder', symbol: 'ANG', character: 'ƒ' },
56
+ { name: 'Angolan Kwanza', symbol: 'AOA', character: 'Kz' },
57
+ { name: 'Argentine Peso', symbol: 'ARS', character: '$' },
58
+ { name: 'Australian Dollar', symbol: 'AUD', character: '$' },
59
+ { name: 'Aruban Florin', symbol: 'AWG', character: 'ƒ' },
60
+ { name: 'Azerbaijani Manat', symbol: 'AZN', character: '₼' },
61
+ {
62
+ name: 'Bosnia-Herzegovina Convertible Mark',
63
+ symbol: 'BAM',
64
+ character: 'KM',
65
+ },
66
+ { name: 'Barbadian Dollar', symbol: 'BBD', character: '$' },
67
+ { name: 'Bangladeshi Taka', symbol: 'BDT', character: '৳' },
68
+ { name: 'Bulgarian Lev', symbol: 'BGN', character: 'лв' },
69
+ { name: 'Bahraini Dinar', symbol: 'BHD', character: 'ب.د' },
70
+ { name: 'Burundian Franc', symbol: 'BIF', character: 'FBu' },
71
+ { name: 'Bermudan Dollar', symbol: 'BMD', character: '$' },
72
+ { name: 'Brunei Dollar', symbol: 'BND', character: '$' },
73
+ { name: 'Bolivian Boliviano', symbol: 'BOB', character: 'Bs.' },
74
+ { name: 'Brazilian Real', symbol: 'BRL', character: 'R$' },
75
+ { name: 'Bahamian Dollar', symbol: 'BSD', character: '$' },
76
+ { name: 'Bitcoin', symbol: '₿', character: '₿' },
77
+ { name: 'Bhutanese Ngultrum', symbol: 'BTN', character: 'Nu.' },
78
+ { name: 'Botswanan Pula', symbol: 'BWP', character: 'P' },
79
+ { name: 'Belarusian Ruble', symbol: 'BYN', character: 'Br' },
80
+ { name: 'Belize Dollar', symbol: 'BZD', character: '$' },
81
+ { name: 'Canadian Dollar', symbol: 'CAD', character: '$' },
82
+ { name: 'Congolese Franc', symbol: 'CDF', character: 'FC' },
83
+ { name: 'Swiss Franc', symbol: 'CHF', character: 'Fr' },
84
+ { name: 'Chilean Peso', symbol: 'CLP', character: '$' },
85
+ { name: 'Chinese Yuan', symbol: 'CNY', character: '¥' },
86
+ { name: 'Colombian Peso', symbol: 'COP', character: '$' },
87
+ { name: 'Costa Rican Colón', symbol: 'CRC', character: '₡' },
88
+ { name: 'Cuban Convertible Peso', symbol: 'CUC', character: '$' },
89
+ { name: 'Cuban Peso', symbol: 'CUP', character: '$' },
90
+ { name: 'Cape Verdean Escudo', symbol: 'CVE', character: '$' },
91
+ { name: 'Czech Republic Koruna', symbol: 'CZK', character: 'Kč' },
92
+ { name: 'Djiboutian Franc', symbol: 'DJF', character: 'Fdj' },
93
+ { name: 'Danish Krone', symbol: 'DKK', character: 'kr' },
94
+ { name: 'Dominican Peso', symbol: 'DOP', character: '$' },
95
+ { name: 'Algerian Dinar', symbol: 'DZD', character: 'د.ج' },
96
+ { name: 'Egyptian Pound', symbol: 'EGP', character: '£' },
97
+ { name: 'Eritrean Nakfa', symbol: 'ERN', character: 'Nfk' },
98
+ { name: 'Ethiopian Birr', symbol: 'ETB', character: 'Br' },
99
+ { name: 'Euro', symbol: 'EUR', character: '€' },
100
+ { name: 'Fijian Dollar', symbol: 'FJD', character: '$' },
101
+ { name: 'Falkland Islands Pound', symbol: 'FKP', character: '£' },
102
+ { name: 'British Pound Sterling', symbol: 'GBP', character: '£' },
103
+ { name: 'Georgian Lari', symbol: 'GEL', character: 'ლ' },
104
+ { name: 'Guernsey Pound', symbol: 'GGP', character: '£' },
105
+ { name: 'Ghanaian Cedi', symbol: 'GHS', character: '₵' },
106
+ { name: 'Gibraltar Pound', symbol: 'GIP', character: '£' },
107
+ { name: 'Gambian Dalasi', symbol: 'GMD', character: 'D' },
108
+ { name: 'Guinean Franc', symbol: 'GNF', character: 'FG' },
109
+ { name: 'Guatemalan Quetzal', symbol: 'GTQ', character: 'Q' },
110
+ { name: 'Guyanaese Dollar', symbol: 'GYD', character: '$' },
111
+ { name: 'Hong Kong Dollar', symbol: 'HKD', character: '$' },
112
+ { name: 'Honduran Lempira', symbol: 'HNL', character: 'L' },
113
+ { name: 'Croatian Kuna', symbol: 'HRK', character: 'kn' },
114
+ { name: 'Haitian Gourde', symbol: 'HTG', character: 'G' },
115
+ { name: 'Hungarian Forint', symbol: 'HUF', character: 'Ft' },
116
+ { name: 'Indonesian Rupiah', symbol: 'IDR', character: 'Rp' },
117
+ { name: 'Israeli New Shekel', symbol: 'ILS', character: '₪' },
118
+ { name: 'Manx pound', symbol: 'IMP', character: '£' },
119
+ { name: 'Indian Rupee', symbol: 'INR', character: '₹' },
120
+ { name: 'Iraqi Dinar', symbol: 'IQD', character: 'ع.د' },
121
+ { name: 'Iranian Rial', symbol: 'IRR', character: '﷼' },
122
+ { name: 'Icelandic Króna', symbol: 'ISK', character: 'kr' },
123
+ { name: 'Jersey Pound', symbol: 'JEP', character: '£' },
124
+ ];
125
+ </script>
126
+
127
+ <style scoped>
128
+ .currency {
129
+ font-size: calc(var(--input-font-size) * 1.4);
130
+ margin-inline-start: -50px;
131
+ line-height: 0px;
132
+ }
133
+ </style>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <div class="bagel-input" :title="field.description" :class="{ small: small }">
3
+ <label v-if="field.label">
4
+ {{ field.label }}
5
+ </label>
6
+ <input
7
+ type="date"
8
+ v-model="date"
9
+ @update:modelValue="handleInput"
10
+ :placeholder="field.placeholder || field.label"
11
+ class="date-picker"
12
+ :disabled="!editMode"
13
+ :enableTimePicker="false"
14
+ :textInputOptions="{ format: 'yyyy-MM-dd' }"
15
+ >
16
+ </div>
17
+ </template>
18
+
19
+ <script setup lang="ts">
20
+ import { ref } from 'vue';
21
+ import type { BagelField } from '@/types/BagelField';
22
+
23
+ const props = withDefaults(
24
+ defineProps<{
25
+ field: BagelField;
26
+ modelValue: any;
27
+ editMode?: boolean;
28
+ small?: boolean;
29
+ }>(),
30
+ {
31
+ editMode: true,
32
+ small: false,
33
+ },
34
+ );
35
+
36
+ const date = ref(props.modelValue);
37
+
38
+ const emit = defineEmits(['update:modelValue']);
39
+
40
+ const handleInput = () => {
41
+ emit('update:modelValue', date.value.toISOString().split('T').shift());
42
+ };
43
+ </script>
44
+
45
+ <style scoped>
46
+ .date-picker {
47
+ /* padding-inline-start: 10px; */
48
+ }
49
+ </style>
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <div class="bagel-input" :title="description" :class="{ small: small }">
3
+ <label v-if="label">
4
+ <LangText :input="label" />
5
+ </label>
6
+ <input
7
+ :value="modelValue?.split('.')[0] || ''"
8
+ type="datetime-local"
9
+ @input="handleInput"
10
+ :placeholder="bagelApp.translate(placeholder, true)"
11
+ :class="{ 'no-edit': !editMode }"
12
+ >
13
+ </div>
14
+ </template>
15
+
16
+ <script setup lang="ts">
17
+ import { onMounted } from 'vue';
18
+ // @ts-ignore TODO: remove this
19
+ import { bagelApp } from '../../../index';
20
+
21
+ const emits = defineEmits(['update:modelValue']);
22
+ // @ts-ignore TODO: remove this
23
+ const props = withDefaults(
24
+ defineProps<{
25
+ description?: string;
26
+ label?: string;
27
+ modelValue: any;
28
+ placeholder?: string;
29
+ editMode?: boolean;
30
+ small?: boolean;
31
+ }>(),
32
+ {
33
+ description: '',
34
+ editMode: true,
35
+ placeholder: '',
36
+ label: '',
37
+ },
38
+ );
39
+ const handleInput = (e: Event) => {
40
+ const el = e.target as HTMLInputElement;
41
+ emits('update:modelValue', el.value);
42
+ };
43
+ onMounted(() => {});
44
+ </script>
45
+
46
+ <style scoped></style>
@@ -0,0 +1,51 @@
1
+ <template>
2
+ <div class="bagel-input" :title="description" :class="{ small: small }">
3
+ <label v-if="label">
4
+ <LangText :input="label" />
5
+ </label>
6
+ <input
7
+ :value="modelValue"
8
+ :title="formatDuration(modelValue)"
9
+ type="number"
10
+ @input="handleInput"
11
+ :placeholder="bagelApp.translate(placeholder, true)"
12
+ :class="{ 'no-edit': !editMode }"
13
+ >
14
+ </div>
15
+ </template>
16
+
17
+ <script setup lang="ts">
18
+ // @ts-ignore TODO: remove this
19
+ import { bagelApp } from '../../../index';
20
+ // @ts-ignore TODO: remove this
21
+ import { formatDuration } from '../../../composables';
22
+
23
+ const emits = defineEmits(['update:modelValue']);
24
+ // @ts-ignore TODO: remove this
25
+ const props = withDefaults(
26
+ defineProps<{
27
+ description?: string;
28
+ label?: string;
29
+ modelValue: any;
30
+ placeholder?: string;
31
+ editMode?: boolean;
32
+ small?: boolean;
33
+ }>(),
34
+ {
35
+ description: '',
36
+ editMode: true,
37
+ placeholder: '',
38
+ label: '',
39
+ },
40
+ );
41
+ const handleInput = (e: Event) => {
42
+ const el = e.target as HTMLInputElement;
43
+ let value = parseInt(el.value);
44
+ if (isNaN(value)) {
45
+ value = 0;
46
+ }
47
+ emits('update:modelValue', value);
48
+ };
49
+ </script>
50
+
51
+ <style scoped></style>
@@ -0,0 +1,140 @@
1
+ <template>
2
+ <div class="bagel-input" :class="{ small: small }">
3
+ <label v-if="label">
4
+ <LangText :input="label" />
5
+ </label>
6
+
7
+ <input
8
+ @keydown.enter="handleEnter"
9
+ autocomplete="off"
10
+ @click="showList = true"
11
+ name="link-input"
12
+ v-model="selectedItem"
13
+ @focus="initList"
14
+ @input="handleInput"
15
+ :disabled="!editMode"
16
+ >
17
+
18
+ <div
19
+ class="custom-select"
20
+ name="link-input"
21
+ :class="{ 'open-select': showList && linkOptions.length > 0 }"
22
+ >
23
+ <div class="custom-select-drop">
24
+ <div
25
+ v-for="item in linkOptions"
26
+ :key="formatString(item.value, 'pascal')"
27
+ @click.stop="handleSelect(item)"
28
+ >
29
+ {{
30
+ useId || entity === 'Entity'
31
+ ? item.value
32
+ : item.label || item.description || item.value
33
+ }}
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <script lang="ts" setup>
41
+ import { onMounted, ref } from 'vue';
42
+ // @ts-ignore TODO: remove this
43
+ import { formatString } from '../../../composables';
44
+ // @ts-ignore TODO: remove this
45
+ import { bagelApp } from '../../../index';
46
+
47
+ const props = withDefaults(
48
+ defineProps<{
49
+ label?: string;
50
+ modelValue: any;
51
+ useId?: false;
52
+ bagelApp?: any;
53
+ entity: string;
54
+ editMode: boolean;
55
+ filters?: any;
56
+ small?: boolean;
57
+ }>(),
58
+ {
59
+ label: '',
60
+ useId: false,
61
+ filters: {},
62
+ bagelApp,
63
+ },
64
+ );
65
+ const showList = ref(false);
66
+ const linkOptions = ref<any>([]);
67
+ const item = ref<ListItem>();
68
+ const emits = defineEmits(['update:modelValue', 'selected']);
69
+ const selectedItem = ref<any>();
70
+
71
+ function handleSelect(item: ListItem) {
72
+ showList.value = false;
73
+ selectedItem.value = item;
74
+ if (props.useId) {
75
+ selectedItem.value = item.value;
76
+ } else {
77
+ selectedItem.value = item.label || item.description || item.value;
78
+ }
79
+
80
+ emits('update:modelValue', item.value);
81
+ emits('selected');
82
+ }
83
+
84
+ async function getLinkOptions(inputString: string) {
85
+ linkOptions.value = await props.bagelApp.entity.getLinkedFieldList({
86
+ entity: props.entity,
87
+ txt: inputString,
88
+ reference_entity: '',
89
+ filters: props.filters,
90
+ });
91
+ }
92
+
93
+ interface ListItem {
94
+ value: string;
95
+ label?: string;
96
+ description?: string;
97
+ }
98
+
99
+ // @ts-ignore TODO: remove this
100
+ const initialized = ref(false);
101
+
102
+ async function initList(e: Event) {
103
+ await getLinkOptions(getElValue(e));
104
+ showList.value = true;
105
+ }
106
+
107
+ function getElValue(e: Event) {
108
+ const el = e.target as HTMLInputElement;
109
+ return el.value.trim();
110
+ }
111
+
112
+ function handleEnter(e: Event) {
113
+ emits('update:modelValue', getElValue(e));
114
+ emits('selected');
115
+ showList.value = false;
116
+ }
117
+
118
+ function handleClick(e: any) {
119
+ const { target } = e;
120
+ if (target.name != 'link-input' && showList.value == true) {
121
+ showList.value = false;
122
+ emits('update:modelValue', item.value);
123
+ emits('selected');
124
+ }
125
+ // showList.value = false
126
+ }
127
+
128
+ const handleInput = async (e: Event) => {
129
+ showList.value = true;
130
+ const el = e.target as HTMLInputElement;
131
+ emits('update:modelValue', el.value);
132
+ await getLinkOptions(el.value);
133
+ };
134
+ onMounted(() => {
135
+ selectedItem.value = props.modelValue;
136
+ document.addEventListener('click', handleClick);
137
+ });
138
+ </script>
139
+
140
+ <style scoped></style>