inertia-bootstrap-forms 2.1.20 → 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.
Files changed (59) hide show
  1. package/README.fa.md +468 -0
  2. package/README.md +322 -714
  3. package/dist/inertia-bootstrap-forms.cjs.js +1 -0
  4. package/dist/inertia-bootstrap-forms.es.js +3524 -30
  5. package/index.d.ts +143 -507
  6. package/package.json +89 -70
  7. package/src/AmountInput.vue +81 -76
  8. package/src/CaptchaInput.vue +87 -88
  9. package/src/CheckboxButtonInput.vue +56 -69
  10. package/src/CheckboxInput.vue +60 -79
  11. package/src/CheckboxToggle.vue +53 -136
  12. package/src/ChipsInput.vue +157 -0
  13. package/src/ComboboxInput.vue +556 -0
  14. package/src/DropzoneInput.vue +125 -103
  15. package/src/EditorInput.vue +47 -106
  16. package/src/EmailInput.vue +16 -15
  17. package/src/FileInput.vue +189 -179
  18. package/src/FormAdornInput.vue +75 -0
  19. package/src/FormContainer.vue +288 -251
  20. package/src/FormField.vue +59 -0
  21. package/src/FormLabel.vue +27 -27
  22. package/src/GroupControl.vue +55 -53
  23. package/src/LocationInput.vue +79 -72
  24. package/src/MobileInput.vue +21 -13
  25. package/src/MultiQuantityInput.vue +109 -181
  26. package/src/OTPInput.vue +144 -76
  27. package/src/PasswordInput.vue +151 -17
  28. package/src/PersianDatePickerInput.vue +63 -166
  29. package/src/QuantityInput.vue +100 -119
  30. package/src/RangeInput.vue +96 -0
  31. package/src/SimpleUploader.vue +8 -143
  32. package/src/StarRatingInput.vue +114 -138
  33. package/src/SubmitButton.vue +39 -24
  34. package/src/SwitchInput.vue +58 -83
  35. package/src/TelInput.vue +86 -120
  36. package/src/TextAreaInput.vue +29 -33
  37. package/src/TextInput.vue +42 -51
  38. package/src/UppyInput.vue +237 -324
  39. package/src/composables/useBsInstance.js +66 -0
  40. package/src/composables/useChoice.js +34 -0
  41. package/src/composables/useDisposables.js +59 -0
  42. package/src/composables/useField.js +121 -0
  43. package/src/composables/useFormApi.js +12 -0
  44. package/src/i18n.js +120 -0
  45. package/src/index.js +123 -42
  46. package/src/utils/bootstrap.js +48 -0
  47. package/src/utils/digits.js +21 -0
  48. package/src/utils/http.js +15 -0
  49. package/dist/choices-KiM-I_0P.js +0 -2955
  50. package/dist/dropdown-yh2aQrbw-XuCU1v1F.js +0 -1543
  51. package/dist/index-BRtKc2RA.js +0 -604
  52. package/dist/index-_x4UqcXz.js +0 -4938
  53. package/dist/inertia-bootstrap-forms.umd.js +0 -19
  54. package/dist/range-slider-pips-DTDOg3Q9.js +0 -3506
  55. package/dist/style.css +0 -1
  56. package/src/css/from-select.scss +0 -384
  57. package/src/css/loader.gif +0 -0
  58. package/src/css/location.scss +0 -44
  59. package/src/css/simple-upload.scss +0 -54
@@ -1,83 +1,58 @@
1
- <script>
2
- import {computed, defineComponent, inject} from "vue";
3
-
4
- export default defineComponent({
5
- props: {
6
- name: {
7
- type: String,
8
- required: true,
9
- },
10
- id: {
11
- type: String,
12
- default: '',
13
- required: false,
14
- },
15
- value: {
16
- type: [String, Number],
17
- default: null,
18
- required: false,
19
- },
20
- disabled: {
21
- type: Boolean,
22
- default: false,
23
- },
24
- type: {
25
- type: String,
26
- default: 'checkbox',
27
- required: false,
28
- },
29
- },
30
- computed: {
31
- inputID() {
32
- return this.form.getID(this);
33
- }
34
- },
35
- setup(props) {
36
- let form = inject('form', {
37
- errors: {},
38
- getID(name) {
39
- return name;
40
- }
41
- });
42
- let group = inject('group', {});
43
-
44
- const modelValue = computed({
45
- get() {
46
- return (group.value && form.value[group.value.name]) ? group.value?.getData(props.name) : form.value[props.name];
47
- },
48
- set(value) {
49
- if (group?.value?.name) {
50
- group.value.setData(props.name, value);
51
- } else {
52
- form.value[props.name] = value;
53
- }
54
- }
55
- });
56
-
57
- return {modelValue, form, group};
58
- },
59
- })
60
- </script>
61
- <template>
62
- <div class="form-check form-switch" :class="{'disabled': disabled}">
63
- <input
64
- :name="name"
65
- :id="inputID"
66
- v-model="modelValue"
67
- :class="{'is-invalid': form?.errors[name]}"
68
- :disabled="form?.processing || disabled"
69
- :type="type"
70
- :value="value"
71
- @change="e => $emit('change', e)"
72
- class="form-check-input">
73
- <label class="form-check-label" :for="inputID">
74
- <slot/>
75
- </label>
76
- </div>
77
- </template>
78
- <style>
79
- .form-check,
80
- .form-check label {
81
- cursor: pointer;
82
- }
83
- </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
+ /** Bootstrap 6 switch: `.switch` wrapper around `<input type="checkbox" role="switch" switch>`. */
7
+ export default defineComponent({
8
+ name: 'SwitchInput',
9
+ emits: ['update:modelValue', 'change', 'focus', 'blur'],
10
+ props: {
11
+ ...fieldProps,
12
+ value: { type: [String, Number, Boolean, Object], default: null },
13
+ trueValue: { type: null, default: true },
14
+ falseValue: { type: null, default: false },
15
+ checked: { type: Boolean, default: false },
16
+ label: { type: String, default: null },
17
+ },
18
+ setup(props, { emit }) {
19
+ const input = ref(null);
20
+ const field = useField(props, emit, { valued: () => props.value });
21
+ useChoice(props, field, input, { type: () => 'checkbox' });
22
+
23
+ return {
24
+ ...field,
25
+ input,
26
+ onChange: (event) => field.emitChange(field.model.value, event),
27
+ };
28
+ },
29
+ expose: ['input'],
30
+ });
31
+ </script>
32
+
33
+ <template>
34
+ <div class="form-field">
35
+ <div class="switch">
36
+ <input
37
+ ref="input"
38
+ v-model="model"
39
+ :name="name"
40
+ :id="inputId"
41
+ type="checkbox"
42
+ role="switch"
43
+ switch
44
+ :value="value ?? undefined"
45
+ :true-value="trueValue"
46
+ :false-value="falseValue"
47
+ :required="required"
48
+ :disabled="isDisabled"
49
+ :aria-invalid="isInvalid || undefined"
50
+ :class="{ 'is-invalid': isInvalid }"
51
+ @change="onChange"
52
+ @focus="$emit('focus', $event)"
53
+ @blur="$emit('blur', $event)"
54
+ />
55
+ </div>
56
+ <label :for="inputId"><slot>{{ label }}</slot></label>
57
+ </div>
58
+ </template>
package/src/TelInput.vue CHANGED
@@ -1,130 +1,96 @@
1
1
  <script>
2
- import {VueTelInput} from 'vue-tel-input';
3
- import 'vue-tel-input/vue-tel-input.css';
4
- import {defineComponent, inject} from "vue";
2
+ import { computed, defineAsyncComponent, defineComponent, ref, watch } from 'vue';
3
+ import { fieldProps, useField } from './composables/useField.js';
5
4
 
5
+ const VueTelInput = defineAsyncComponent(() => import('vue-tel-input').then((m) => m.VueTelInput));
6
+
7
+ /**
8
+ * International phone input (vue-tel-input). The stored value is the international number (E.164 style).
9
+ * Remember to import `vue-tel-input/vue-tel-input.css` in your application.
10
+ */
6
11
  export default defineComponent({
7
- components: {
8
- VueTelInput
9
- },
10
- props: {
11
- name: {
12
- type: String,
13
- default: 'email',
14
- required: true,
15
- },
16
- placeHolder: {
17
- type: String,
18
- default: '000 000 0000',
12
+ name: 'TelInput',
13
+ components: { VueTelInput },
14
+ emits: ['update:modelValue', 'change', 'validate', 'country-changed', 'focus', 'blur'],
15
+ props: {
16
+ ...fieldProps,
17
+ placeholder: { type: String, default: '000 000 0000' },
18
+ /** Legacy alias of `placeholder`. */
19
+ placeHolder: { type: String, default: null },
20
+ defaultCountry: { type: String, default: 'ir' },
21
+ preferredCountries: { type: Array, default: () => ['ir', 'us', 'tr', 'ca'] },
22
+ mode: { type: String, default: 'national' },
23
+ validCharactersOnly: { type: Boolean, default: true },
24
+ /** Mark the field invalid as soon as the typed number is not valid. */
25
+ validate: { type: Boolean, default: true },
26
+ searchPlaceholder: { type: String, default: 'Search…' },
27
+ dropdownOptions: { type: Object, default: () => ({}) },
28
+ inputOptions: { type: Object, default: () => ({}) },
19
29
  },
20
- },
21
- setup(props) {
22
- let form = inject('form');
30
+ setup(props, { emit }) {
31
+ const field = useField(props, emit);
32
+ const text = ref(field.model.value ?? '');
33
+ const valid = ref(null);
34
+ let lastEmitted = field.model.value ?? '';
23
35
 
24
- if (form === undefined) {
25
- form = {
26
- errors: {},
27
- getID(name) {
36
+ // External changes (form reset, server data) → refresh the visible text
37
+ watch(
38
+ () => field.model.value,
39
+ (v) => {
40
+ if ((v ?? '') !== lastEmitted) text.value = v ?? '';
41
+ }
42
+ );
43
+
44
+ function onInput(number, phone) {
45
+ lastEmitted = phone?.number ?? '';
46
+ field.model.value = lastEmitted;
47
+ valid.value = phone?.valid ?? null;
48
+ emit('validate', valid.value, phone);
49
+ field.emitChange(lastEmitted);
28
50
  }
29
- };
30
- }
31
51
 
32
- return {form};
33
- },
34
- methods: {
35
- inputEvent(number, phone) {
36
- this.form[this.name] = phone.number;
37
- this.valid = phone.valid;
38
- // console.log('input', number, phone);
39
- }
40
- },
41
- data() {
42
- return {
43
- defaultValue: this.form[this.name],
44
- valid: null,
45
- }
46
- }
47
- })
52
+ return {
53
+ ...field,
54
+ text,
55
+ valid,
56
+ onInput,
57
+ dropdown: computed(() => ({
58
+ showDialCodeInList: true,
59
+ showDialCodeInSelection: true,
60
+ showSearchBox: true,
61
+ searchBoxPlaceholder: props.searchPlaceholder,
62
+ showFlags: false,
63
+ ...props.dropdownOptions,
64
+ })),
65
+ inputOpts: computed(() => ({
66
+ placeholder: props.placeHolder ?? props.placeholder,
67
+ id: field.inputId.value,
68
+ name: props.name,
69
+ readonly: props.readonly,
70
+ ...props.inputOptions,
71
+ })),
72
+ invalidClass: computed(() => field.isInvalid.value || (props.validate && valid.value === false)),
73
+ };
74
+ },
75
+ });
48
76
  </script>
77
+
49
78
  <template>
50
- <div class="telephone-input input-group fanum" dir="ltr">
51
- <vue-tel-input
52
- mode="national"
53
- :validCharactersOnly="true"
54
- defaultCountry="ir"
55
- :preferredCountries="['ir', 'us', 'tr', 'ca']"
56
- :dropdownOptions="{
57
- showDialCodeInList:true,
58
- showDialCodeInSelection:true,
59
- showSearchBox:true,
60
- searchBoxPlaceholder:'Search...',
61
- showFlags:false,
62
- }"
63
- @on-input="inputEvent"
64
- :inputOptions="{
65
- placeholder: placeHolder
66
- }"
67
- v-model="defaultValue"
68
- :styleClasses="'form-control form-control-tel fanum ' + ((valid === false || form?.errors[name] !== undefined) ? ' is-invalid' : '')"/>
69
- </div>
79
+ <div class="telephone-input input-group fanum" dir="ltr">
80
+ <VueTelInput
81
+ v-model="text"
82
+ :mode="mode"
83
+ :valid-characters-only="validCharactersOnly"
84
+ :default-country="defaultCountry"
85
+ :preferred-countries="preferredCountries"
86
+ :disabled="isDisabled"
87
+ :dropdown-options="dropdown"
88
+ :input-options="inputOpts"
89
+ :style-classes="'form-control form-control-tel fanum' + (invalidClass ? ' is-invalid' : '')"
90
+ @on-input="onInput"
91
+ @country-changed="$emit('country-changed', $event)"
92
+ @focus="$emit('focus', $event)"
93
+ @blur="$emit('blur', $event)"
94
+ />
95
+ </div>
70
96
  </template>
71
- <style>
72
- .telephone-input .vue-tel-input {
73
- border-color: var(--bs-border-color, #ccc);
74
- border-width: var(--bs-border-width, 1px);
75
- border-radius: var(--bs-border-radius, .5rem);
76
- }
77
-
78
- .telephone-input .vti__input.vti__search_box {
79
- border: 0;
80
- font-size: var(--bs-body-font-size, .9rem);
81
- background: var(--bs-tertiary-bg, #eee);
82
- border-radius: var(--bs-border-radius, .5rem);
83
- }
84
-
85
- .telephone-input .vti__search_box_container {
86
- display: flex;
87
- }
88
-
89
- .telephone-input .vti__dropdown {
90
- position: absolute;
91
- top: 0;
92
- right: 0;
93
- bottom: 0;
94
- border-radius: 0 var(--bs-border-radius) var(--bs-border-radius) 0;
95
- padding: 7px 7px 7px 0;
96
- }
97
-
98
- .telephone-input .vti__input.vti__phone {
99
- padding-right: 3rem;
100
- }
101
-
102
- .telephone-input .vti__dropdown-list {
103
- padding: 0 !important;
104
- left: auto;
105
- right: 0;
106
- }
107
-
108
- .telephone-input .vti__dropdown-list .vti__dropdown-item {
109
- direction: rtl;
110
- text-align: right;
111
- }
112
-
113
- .telephone-input .vti__dropdown-list .vti__dropdown-item strong {
114
- font-weight: normal;
115
- }
116
-
117
- .telephone-input .vti__selection {
118
- font-size: inherit;
119
- }
120
-
121
- .telephone-input .form-control.is-invalid {
122
- padding-right: 0.75rem;
123
- background-position: left calc(0.425em + 0.25rem) center;
124
- }
125
-
126
- .telephone-input .vti__dropdown-arrow {
127
- margin: 0 4px;
128
- }
129
-
130
- </style>
@@ -1,44 +1,40 @@
1
1
  <script>
2
- import {computed, defineComponent, inject} from "vue";
2
+ import { computed, defineComponent } from 'vue';
3
+ import { fieldProps, useField } from './composables/useField.js';
3
4
 
4
5
  export default defineComponent({
6
+ name: 'TextAreaInput',
7
+ emits: ['update:modelValue', 'change', 'input', 'focus', 'blur'],
5
8
  props: {
6
- name: {
7
- type: String,
8
- required: true,
9
- },
9
+ ...fieldProps,
10
+ rows: { type: [Number, String], default: 3 },
11
+ placeholder: { type: String, default: null },
12
+ size: { type: String, default: null },
10
13
  },
11
- setup(props) {
12
- let form = inject('form', {
13
- errors: {},
14
- getID(name) {
15
- return name;
16
- }
17
- });
18
- let group = inject('group', {});
19
-
20
- const modelValue = computed({
21
- get() {
22
- return (group.value && form.value[group.value.name]) ? group.value?.getData(props.name) : form.value[props.name];
23
- },
24
- set(value) {
25
- if (group?.value?.name) {
26
- group.value.setData(props.name, value);
27
- } else {
28
- form.value[props.name] = value;
29
- }
30
- }
31
- });
32
-
33
- return {modelValue, form, group};
14
+ setup(props, { emit }) {
15
+ const field = useField(props, emit);
16
+ const sizeClass = computed(() => (props.size ? `form-control-${props.size}` : null));
17
+ return { ...field, sizeClass, emit };
34
18
  },
35
- })
19
+ });
36
20
  </script>
21
+
37
22
  <template>
38
23
  <textarea
24
+ v-model="model"
39
25
  :name="name"
40
- v-model="modelValue"
41
- :class="{'is-invalid': form?.errors[name] !== undefined}"
42
- :disabled="form?.processing"
43
- class="form-control"></textarea>
26
+ :id="inputId"
27
+ :rows="rows"
28
+ :placeholder="placeholder"
29
+ :required="required"
30
+ :readonly="readonly"
31
+ :disabled="isDisabled"
32
+ :aria-invalid="isInvalid || undefined"
33
+ class="form-control"
34
+ :class="[sizeClass, { 'is-invalid': isInvalid }]"
35
+ @input="emit('input', model, $event)"
36
+ @change="emitChange(model, $event)"
37
+ @focus="$emit('focus', $event)"
38
+ @blur="$emit('blur', $event)"
39
+ ></textarea>
44
40
  </template>
package/src/TextInput.vue CHANGED
@@ -1,51 +1,42 @@
1
- <script>
2
- import {computed, inject, defineComponent} from "vue";
3
-
4
- export default defineComponent({
5
- props: {
6
- name: {
7
- type: String,
8
- required: true,
9
- },
10
- },
11
- computed: {
12
- inputID() {
13
- return this.form.getID(this);
14
- }
15
- },
16
- setup(props) {
17
- let form = inject('form', {
18
- errors: {},
19
- getID(name) {
20
- return name;
21
- }
22
- });
23
- let group = inject('group', {});
24
-
25
- const modelValue = computed({
26
- get() {
27
- return (group.value && form.value[group.value.name]) ? group.value?.getData(props.name) : form.value[props.name];
28
- },
29
- set(value) {
30
- if (group?.value?.name) {
31
- group.value.setData(props.name, value);
32
- } else {
33
- form.value[props.name] = value;
34
- }
35
- }
36
- });
37
-
38
- return {modelValue, form, group};
39
- },
40
- })
41
- </script>
42
- <template>
43
- <input
44
- :name="name"
45
- :id="inputID"
46
- v-model="modelValue"
47
- :class="{'is-invalid': form?.errors[name] !== undefined}"
48
- :disabled="form?.processing"
49
- type="text"
50
- class="form-control">
51
- </template>
1
+ <script>
2
+ import { computed, defineComponent } from 'vue';
3
+ import { fieldProps, useField } from './composables/useField.js';
4
+
5
+ export default defineComponent({
6
+ name: 'TextInput',
7
+ emits: ['update:modelValue', 'change', 'input', 'focus', 'blur'],
8
+ props: {
9
+ ...fieldProps,
10
+ type: { type: String, default: 'text' },
11
+ placeholder: { type: String, default: null },
12
+ /** sm | lg */
13
+ size: { type: String, default: null },
14
+ },
15
+ setup(props, { emit }) {
16
+ const field = useField(props, emit);
17
+ const sizeClass = computed(() => (props.size ? `form-control-${props.size}` : null));
18
+
19
+ return { ...field, sizeClass, emit };
20
+ },
21
+ });
22
+ </script>
23
+
24
+ <template>
25
+ <input
26
+ v-model="model"
27
+ :name="name"
28
+ :id="inputId"
29
+ :type="type"
30
+ :placeholder="placeholder"
31
+ :required="required"
32
+ :readonly="readonly"
33
+ :disabled="isDisabled"
34
+ :aria-invalid="isInvalid || undefined"
35
+ class="form-control"
36
+ :class="[sizeClass, { 'is-invalid': isInvalid }]"
37
+ @input="emit('input', model, $event)"
38
+ @change="emitChange(model, $event)"
39
+ @focus="$emit('focus', $event)"
40
+ @blur="$emit('blur', $event)"
41
+ />
42
+ </template>