inertia-bootstrap-forms 2.1.21 → 3.0.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/README.fa.md +468 -0
- package/README.md +322 -714
- package/dist/inertia-bootstrap-forms.cjs.js +1 -0
- package/dist/inertia-bootstrap-forms.es.js +3524 -30
- package/index.d.ts +143 -507
- package/package.json +89 -70
- package/src/AmountInput.vue +81 -76
- package/src/CaptchaInput.vue +87 -88
- package/src/CheckboxButtonInput.vue +56 -69
- package/src/CheckboxInput.vue +60 -79
- package/src/CheckboxToggle.vue +53 -136
- package/src/ChipsInput.vue +157 -0
- package/src/ComboboxInput.vue +556 -0
- package/src/DropzoneInput.vue +125 -103
- package/src/EditorInput.vue +47 -106
- package/src/EmailInput.vue +16 -15
- package/src/FileInput.vue +189 -179
- package/src/FormAdornInput.vue +75 -0
- package/src/FormContainer.vue +288 -251
- package/src/FormField.vue +59 -0
- package/src/FormLabel.vue +27 -27
- package/src/GroupControl.vue +55 -53
- package/src/LocationInput.vue +79 -72
- package/src/MobileInput.vue +21 -13
- package/src/MultiQuantityInput.vue +109 -181
- package/src/OTPInput.vue +144 -76
- package/src/PasswordInput.vue +151 -17
- package/src/PersianDatePickerInput.vue +63 -166
- package/src/QuantityInput.vue +100 -119
- package/src/RangeInput.vue +96 -0
- package/src/SimpleUploader.vue +8 -143
- package/src/StarRatingInput.vue +114 -138
- package/src/SubmitButton.vue +39 -24
- package/src/SwitchInput.vue +58 -83
- package/src/TelInput.vue +86 -120
- package/src/TextAreaInput.vue +29 -33
- package/src/TextInput.vue +42 -51
- package/src/UppyInput.vue +237 -324
- package/src/composables/useBsInstance.js +66 -0
- package/src/composables/useChoice.js +34 -0
- package/src/composables/useDisposables.js +59 -0
- package/src/composables/useField.js +121 -0
- package/src/composables/useFormApi.js +12 -0
- package/src/i18n.js +120 -0
- package/src/index.js +123 -42
- package/src/utils/bootstrap.js +48 -0
- package/src/utils/digits.js +21 -0
- package/src/utils/http.js +15 -0
- package/dist/choices-KiM-I_0P.js +0 -2955
- package/dist/dropdown-yh2aQrbw-XuCU1v1F.js +0 -1543
- package/dist/index-BRtKc2RA.js +0 -604
- package/dist/index-_x4UqcXz.js +0 -4938
- package/dist/inertia-bootstrap-forms.umd.js +0 -19
- package/dist/range-slider-pips-DTDOg3Q9.js +0 -3506
- package/dist/style.css +0 -1
- package/src/css/from-select.scss +0 -384
- package/src/css/loader.gif +0 -0
- package/src/css/location.scss +0 -44
- package/src/css/simple-upload.scss +0 -54
package/package.json
CHANGED
|
@@ -1,70 +1,89 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "inertia-bootstrap-forms",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"types": "./index.d.ts",
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
49
|
-
"@
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "inertia-bootstrap-forms",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Bootstrap 6 form components for Vue 3 + Inertia.js (Laravel). Every field is bound to a single FormContainer v-model.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/inertia-bootstrap-forms.cjs.js",
|
|
7
|
+
"module": "dist/inertia-bootstrap-forms.es.js",
|
|
8
|
+
"types": "./index.d.ts",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "vite build --watch",
|
|
12
|
+
"build": "vite build",
|
|
13
|
+
"test": "vitest run"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"src",
|
|
18
|
+
"index.d.ts",
|
|
19
|
+
"README.md",
|
|
20
|
+
"README.fa.md"
|
|
21
|
+
],
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./index.d.ts",
|
|
25
|
+
"import": "./dist/inertia-bootstrap-forms.es.js",
|
|
26
|
+
"require": "./dist/inertia-bootstrap-forms.cjs.js"
|
|
27
|
+
},
|
|
28
|
+
"./src/*": "./src/*",
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"author": "NovinVision",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/novinvision/inertia-bootstrap-forms.git"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"inertia",
|
|
39
|
+
"vue",
|
|
40
|
+
"laravel",
|
|
41
|
+
"bootstrap",
|
|
42
|
+
"bootstrap6",
|
|
43
|
+
"forms",
|
|
44
|
+
"combobox",
|
|
45
|
+
"chips",
|
|
46
|
+
"otp"
|
|
47
|
+
],
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@tinymce/tinymce-vue": "^6.1.0",
|
|
50
|
+
"@uppy/core": "^5.2.0",
|
|
51
|
+
"@uppy/vue": "^3.2.0",
|
|
52
|
+
"@uppy/xhr-upload": "^5.1.1",
|
|
53
|
+
"@vue-leaflet/vue-leaflet": "^0.10.1",
|
|
54
|
+
"vue-tel-input": "^9.3.0",
|
|
55
|
+
"vue3-persian-datetime-picker": "^1.2.2"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"@floating-ui/dom": "^1.7.6",
|
|
59
|
+
"@inertiajs/vue3": ">=2.0.0",
|
|
60
|
+
"bootstrap": "^6.0.0-alpha.1",
|
|
61
|
+
"dropzone": "^6.0.0-beta.2",
|
|
62
|
+
"leaflet": "^1.9.0",
|
|
63
|
+
"vue": "^3.3.0"
|
|
64
|
+
},
|
|
65
|
+
"peerDependenciesMeta": {
|
|
66
|
+
"dropzone": {
|
|
67
|
+
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"leaflet": {
|
|
70
|
+
"optional": true
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@floating-ui/dom": "^1.7.6",
|
|
75
|
+
"@inertiajs/vue3": "^2.0.0",
|
|
76
|
+
"@vitejs/plugin-vue": "^5.2.4",
|
|
77
|
+
"@vue/test-utils": "^2.4.6",
|
|
78
|
+
"bootstrap": "6.0.0-alpha.1",
|
|
79
|
+
"dropzone": "^6.0.0-beta.2",
|
|
80
|
+
"jsdom": "^25.0.0",
|
|
81
|
+
"vite": "^5",
|
|
82
|
+
"vitest": "^2.1.0",
|
|
83
|
+
"vue": "^3.5.0"
|
|
84
|
+
},
|
|
85
|
+
"bugs": {
|
|
86
|
+
"url": "https://github.com/novinvision/inertia-bootstrap-forms/issues"
|
|
87
|
+
},
|
|
88
|
+
"homepage": "https://github.com/novinvision/inertia-bootstrap-forms#readme"
|
|
89
|
+
}
|
package/src/AmountInput.vue
CHANGED
|
@@ -1,86 +1,91 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { computed, defineComponent } from 'vue';
|
|
3
|
+
import { fieldProps, useField } from './composables/useField.js';
|
|
4
|
+
import { useI18n } from './i18n.js';
|
|
5
|
+
import { formatNumber, parseDigits, toEnglishDigits } from './utils/digits.js';
|
|
4
6
|
|
|
7
|
+
/** Integer input with thousands separators and a unit (Bootstrap 6 `.input-group`). */
|
|
5
8
|
export default defineComponent({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
name: 'AmountInput',
|
|
10
|
+
emits: ['update:modelValue', 'change', 'input', 'focus', 'blur'],
|
|
11
|
+
props: {
|
|
12
|
+
...fieldProps,
|
|
13
|
+
placeholder: { type: String, default: null },
|
|
14
|
+
unit: { type: String, default: null },
|
|
15
|
+
min: { type: Number, default: null },
|
|
16
|
+
max: { type: Number, default: null },
|
|
17
|
+
inputClass: { type: [String, Array, Object], default: null },
|
|
18
|
+
size: { type: String, default: null },
|
|
19
|
+
locale: { type: String, default: null },
|
|
11
20
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
inputClass: String,
|
|
16
|
-
placeholder: {
|
|
17
|
-
type: String,
|
|
18
|
-
default: 'عدد را وارد کنید'
|
|
19
|
-
},
|
|
20
|
-
unit: {
|
|
21
|
-
type: String,
|
|
22
|
-
default: 'عدد'
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
setup(props) {
|
|
26
|
-
let form = inject('form', {
|
|
27
|
-
errors: {},
|
|
28
|
-
getID(name) {
|
|
29
|
-
return name;
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
let group = inject('group', {});
|
|
21
|
+
setup(props, { emit }) {
|
|
22
|
+
const field = useField(props, emit);
|
|
23
|
+
const { t } = useI18n(() => props.locale);
|
|
33
24
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
});
|
|
25
|
+
const displayValue = computed(() => formatNumber(field.model.value));
|
|
26
|
+
const unitText = computed(() => props.unit ?? t('amount.unit'));
|
|
27
|
+
const sizeClass = computed(() => (props.size ? `form-control-${props.size}` : null));
|
|
28
|
+
|
|
29
|
+
function onInput(event) {
|
|
30
|
+
const el = event.target;
|
|
31
|
+
const before = el.value.slice(0, el.selectionStart ?? 0);
|
|
32
|
+
const digitsBefore = toEnglishDigits(before).replace(/\D/g, '').length;
|
|
33
|
+
|
|
34
|
+
const parsed = parseDigits(el.value);
|
|
35
|
+
field.model.value = parsed;
|
|
46
36
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
37
|
+
// Re-format immediately and keep the caret after the same number of digits
|
|
38
|
+
const formatted = formatNumber(parsed);
|
|
39
|
+
el.value = formatted;
|
|
40
|
+
let pos = 0;
|
|
41
|
+
let seen = 0;
|
|
42
|
+
while (pos < formatted.length && seen < digitsBefore) {
|
|
43
|
+
if (/\d/.test(formatted[pos])) seen++;
|
|
44
|
+
pos++;
|
|
45
|
+
}
|
|
46
|
+
if (document.activeElement === el) el.setSelectionRange(pos, pos);
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
48
|
+
emit('input', parsed, event);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function clamp(event) {
|
|
52
|
+
let v = field.model.value;
|
|
53
|
+
if (v !== null && v !== undefined) {
|
|
54
|
+
if (props.max !== null && v > props.max) v = props.max;
|
|
55
|
+
if (props.min !== null && v < props.min) v = props.min;
|
|
56
|
+
if (v !== field.model.value) field.model.value = v;
|
|
57
|
+
}
|
|
58
|
+
field.emitChange(v, event);
|
|
59
|
+
}
|
|
68
60
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
})
|
|
61
|
+
return { ...field, displayValue, unitText, sizeClass, onInput, clamp, t };
|
|
62
|
+
},
|
|
63
|
+
});
|
|
72
64
|
</script>
|
|
65
|
+
|
|
73
66
|
<template>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
67
|
+
<div class="input-group" :class="{ 'is-invalid': isInvalid }">
|
|
68
|
+
<slot name="prefix" />
|
|
69
|
+
<input
|
|
70
|
+
:name="name"
|
|
71
|
+
:id="inputId"
|
|
72
|
+
:value="displayValue"
|
|
73
|
+
:placeholder="placeholder ?? t('amount.placeholder')"
|
|
74
|
+
:required="required"
|
|
75
|
+
:readonly="readonly"
|
|
76
|
+
:disabled="isDisabled"
|
|
77
|
+
:aria-invalid="isInvalid || undefined"
|
|
78
|
+
type="tel"
|
|
79
|
+
inputmode="numeric"
|
|
80
|
+
autocomplete="off"
|
|
81
|
+
class="form-control fanum"
|
|
82
|
+
:class="[sizeClass, inputClass, { 'is-invalid': isInvalid }]"
|
|
83
|
+
@input="onInput"
|
|
84
|
+
@change="clamp"
|
|
85
|
+
@focus="$emit('focus', $event)"
|
|
86
|
+
@blur="$emit('blur', $event)"
|
|
87
|
+
/>
|
|
88
|
+
<span v-if="unitText" class="input-group-text fanum">{{ unitText }}</span>
|
|
89
|
+
<slot name="suffix" />
|
|
90
|
+
</div>
|
|
91
|
+
</template>
|
package/src/CaptchaInput.vue
CHANGED
|
@@ -1,106 +1,105 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { defineComponent, onMounted, ref, watch } from 'vue';
|
|
3
|
+
import { fieldProps, useField } from './composables/useField.js';
|
|
4
|
+
import { useDisposables } from './composables/useDisposables.js';
|
|
5
|
+
import { useI18n } from './i18n.js';
|
|
4
6
|
|
|
7
|
+
/** Captcha image + input + refresh button. The image is refreshed after every finished submit. */
|
|
5
8
|
export default defineComponent({
|
|
6
|
-
|
|
9
|
+
name: 'CaptchaInput',
|
|
10
|
+
emits: ['update:modelValue', 'change', 'input', 'refresh'],
|
|
7
11
|
props: {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
},
|
|
18
|
-
modelValue: '',
|
|
19
|
-
required: Boolean,
|
|
20
|
-
placeholder: {
|
|
21
|
-
default: 'کد امنیتی روبرو را وارد کنید',
|
|
22
|
-
},
|
|
12
|
+
...fieldProps,
|
|
13
|
+
name: { type: String, default: 'captcha' },
|
|
14
|
+
/** Endpoint that returns the captcha image. */
|
|
15
|
+
url: { type: String, default: '/captcha/default' },
|
|
16
|
+
placeholder: { type: String, default: null },
|
|
17
|
+
/** Reload the image (and clear the input) when a submit finishes. */
|
|
18
|
+
refreshOnSubmit: { type: Boolean, default: true },
|
|
19
|
+
imageWidth: { type: [Number, String], default: 82 },
|
|
20
|
+
imageHeight: { type: [Number, String], default: 38 },
|
|
21
|
+
locale: { type: String, default: null },
|
|
23
22
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
setup(props, { emit, expose }) {
|
|
24
|
+
const field = useField(props, emit);
|
|
25
|
+
const { t } = useI18n(() => props.locale);
|
|
26
|
+
const d = useDisposables();
|
|
27
|
+
|
|
28
|
+
const src = ref(null);
|
|
29
|
+
const loading = ref(true);
|
|
30
|
+
|
|
31
|
+
function refresh() {
|
|
32
|
+
loading.value = true;
|
|
33
|
+
src.value = `${props.url}${props.url.includes('?') ? '&' : '?'}t=${Date.now()}`;
|
|
34
|
+
d.timeout(() => {
|
|
35
|
+
loading.value = false;
|
|
36
|
+
}, 500);
|
|
37
|
+
emit('refresh');
|
|
36
38
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
|
|
40
|
+
onMounted(refresh);
|
|
41
|
+
|
|
42
|
+
watch(
|
|
43
|
+
() => field.form.value?.processing,
|
|
44
|
+
(now, before) => {
|
|
45
|
+
if (props.refreshOnSubmit && before && !now) {
|
|
46
|
+
field.model.value = null;
|
|
47
|
+
refresh();
|
|
48
|
+
}
|
|
42
49
|
}
|
|
43
|
-
|
|
44
|
-
async getSrc() {
|
|
45
|
-
this.loading = true;
|
|
46
|
-
this.src = this.url + '?t=' + Math.random();
|
|
50
|
+
);
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}, 500)
|
|
52
|
-
}
|
|
52
|
+
expose({ refresh });
|
|
53
|
+
|
|
54
|
+
return { ...field, t, src, loading, refresh };
|
|
53
55
|
},
|
|
54
|
-
data() {
|
|
55
|
-
return {
|
|
56
|
-
loading: false,
|
|
57
|
-
src: this.url + Math.random(),
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
56
|
});
|
|
61
|
-
|
|
62
57
|
</script>
|
|
58
|
+
|
|
63
59
|
<template>
|
|
64
|
-
<div class="input-group captcha">
|
|
65
|
-
<
|
|
60
|
+
<div class="input-group captcha" :class="{ 'is-invalid': isInvalid }">
|
|
61
|
+
<input
|
|
62
|
+
v-model="model"
|
|
66
63
|
:name="name"
|
|
67
|
-
|
|
68
|
-
type="
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
64
|
+
:id="inputId"
|
|
65
|
+
type="text"
|
|
66
|
+
inputmode="numeric"
|
|
67
|
+
autocomplete="off"
|
|
68
|
+
:placeholder="placeholder ?? t('captcha.placeholder')"
|
|
69
|
+
:required="required"
|
|
70
|
+
:readonly="readonly"
|
|
71
|
+
:disabled="isDisabled"
|
|
72
|
+
:aria-invalid="isInvalid || undefined"
|
|
73
|
+
class="form-control text-start"
|
|
74
|
+
:class="{ 'is-invalid': isInvalid }"
|
|
75
|
+
@input="$emit('input', model, $event)"
|
|
76
|
+
@change="emitChange(model, $event)"
|
|
77
|
+
/>
|
|
78
|
+
<span class="input-group-text p-0 overflow-hidden" :style="{ width: imageWidth + 'px', height: 'auto' }">
|
|
79
|
+
<img
|
|
80
|
+
v-if="src && !loading"
|
|
81
|
+
:src="src"
|
|
82
|
+
:alt="t('captcha.alt')"
|
|
83
|
+
:width="imageWidth"
|
|
84
|
+
:height="imageHeight"
|
|
85
|
+
class="captcha-holder"
|
|
86
|
+
:style="{ cursor: 'pointer', objectFit: 'contain' }"
|
|
87
|
+
@click="refresh"
|
|
88
|
+
/>
|
|
89
|
+
<span v-else class="placeholder-wave w-100" aria-hidden="true">
|
|
90
|
+
<span class="placeholder w-100" :style="{ height: imageHeight + 'px' }"></span>
|
|
91
|
+
</span>
|
|
92
|
+
</span>
|
|
78
93
|
<button
|
|
79
94
|
type="button"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
95
|
+
class="btn-outline theme-secondary btn-icon"
|
|
96
|
+
:disabled="isDisabled || loading"
|
|
97
|
+
:aria-label="t('captcha.refresh')"
|
|
98
|
+
@click="refresh"
|
|
99
|
+
>
|
|
100
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
101
|
+
<path d="M13.5 3v3.5H10M2.5 13V9.5H6" /><path d="M3.2 6.5A5.5 5.5 0 0 1 13 6.5M12.8 9.5A5.5 5.5 0 0 1 3 9.5" />
|
|
102
|
+
</svg>
|
|
84
103
|
</button>
|
|
85
104
|
</div>
|
|
86
105
|
</template>
|
|
87
|
-
<style>
|
|
88
|
-
.captcha .captcha-holder {
|
|
89
|
-
cursor: pointer;
|
|
90
|
-
width: 82px;
|
|
91
|
-
height: 43px;
|
|
92
|
-
object-fit: contain;
|
|
93
|
-
border-top: 1px solid var(--bs-border-color, #eeeeee);
|
|
94
|
-
border-bottom: 1px solid var(--bs-border-color, #eeeeee);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.input-group-lg.captcha .captcha-holder {
|
|
98
|
-
width: 100px;
|
|
99
|
-
height: auto;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.captcha .btn-refresh {
|
|
103
|
-
background-color: var(--bs-body-bg, #ffffff);
|
|
104
|
-
border-color: var(--bs-border-color, #eeeeee) !important;
|
|
105
|
-
}
|
|
106
|
-
</style>
|
|
@@ -1,69 +1,56 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import {defineComponent,
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
:value="value"
|
|
58
|
-
@change="change"
|
|
59
|
-
autocomplete="off"
|
|
60
|
-
class="btn-check">
|
|
61
|
-
<slot/>
|
|
62
|
-
</label>
|
|
63
|
-
</template>
|
|
64
|
-
<style>
|
|
65
|
-
.btn-label:not(.active){
|
|
66
|
-
--bs-bg-opacity: .3;
|
|
67
|
-
opacity: .6;
|
|
68
|
-
}
|
|
69
|
-
</style>
|
|
1
|
+
<script>
|
|
2
|
+
import { defineComponent, ref } from 'vue';
|
|
3
|
+
import { fieldProps, useField } from './composables/useField.js';
|
|
4
|
+
import { useChoice } from './composables/useChoice.js';
|
|
5
|
+
|
|
6
|
+
/** Toggle button (Bootstrap 6 `.btn-check`): the input is nested inside the label. */
|
|
7
|
+
export default defineComponent({
|
|
8
|
+
name: 'CheckboxButtonInput',
|
|
9
|
+
emits: ['update:modelValue', 'change', 'focus', 'blur'],
|
|
10
|
+
props: {
|
|
11
|
+
...fieldProps,
|
|
12
|
+
type: { type: String, default: 'radio', validator: (v) => ['checkbox', 'radio'].includes(v) },
|
|
13
|
+
value: { type: [String, Number, Boolean, Object], default: 'yes' },
|
|
14
|
+
trueValue: { type: null, default: true },
|
|
15
|
+
falseValue: { type: null, default: false },
|
|
16
|
+
checked: { type: Boolean, default: false },
|
|
17
|
+
/** solid | outline | subtle | text | styled */
|
|
18
|
+
variant: { type: String, default: 'outline' },
|
|
19
|
+
theme: { type: String, default: 'primary' },
|
|
20
|
+
},
|
|
21
|
+
setup(props, { emit }) {
|
|
22
|
+
const input = ref(null);
|
|
23
|
+
const field = useField(props, emit, { valued: () => props.value });
|
|
24
|
+
useChoice(props, field, input);
|
|
25
|
+
|
|
26
|
+
return { ...field, input, onChange: (event) => field.emitChange(field.model.value, event) };
|
|
27
|
+
},
|
|
28
|
+
expose: ['input'],
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<label
|
|
34
|
+
class="btn-check"
|
|
35
|
+
:class="[`btn-${variant}`, `theme-${theme}`, { 'is-invalid': isInvalid, disabled: isDisabled }]"
|
|
36
|
+
>
|
|
37
|
+
<input
|
|
38
|
+
ref="input"
|
|
39
|
+
v-model="model"
|
|
40
|
+
:name="name"
|
|
41
|
+
:type="type"
|
|
42
|
+
:value="value"
|
|
43
|
+
:true-value="trueValue"
|
|
44
|
+
:false-value="falseValue"
|
|
45
|
+
:required="required"
|
|
46
|
+
:disabled="isDisabled"
|
|
47
|
+
:aria-invalid="isInvalid || undefined"
|
|
48
|
+
autocomplete="off"
|
|
49
|
+
:class="{ 'is-invalid': isInvalid }"
|
|
50
|
+
@change="onChange"
|
|
51
|
+
@focus="$emit('focus', $event)"
|
|
52
|
+
@blur="$emit('blur', $event)"
|
|
53
|
+
/>
|
|
54
|
+
<slot />
|
|
55
|
+
</label>
|
|
56
|
+
</template>
|