inertia-bootstrap-forms 1.0.101 → 1.0.102
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.md +836 -39
- package/index.d.ts +29 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,46 +1,843 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{ id: 'draft', name: 'Draft' }
|
|
24
|
-
]"/>
|
|
25
|
-
</div>
|
|
26
|
-
<div class="col-12 col-sm-6">
|
|
27
|
-
<FormLabel>New Image</FormLabel>
|
|
28
|
-
<FileInput name="new_thumbnail" />
|
|
29
|
-
</div>
|
|
30
|
-
<div class="col-12">
|
|
31
|
-
<FormLabel>Description</FormLabel>
|
|
32
|
-
<EditorInput name="description" />
|
|
33
|
-
</div>
|
|
34
|
-
<div class="col-12 text-end">
|
|
35
|
-
<SubmitButton />
|
|
36
|
-
</div>
|
|
1
|
+
# inertia-bootstrap-forms
|
|
2
|
+
|
|
3
|
+
A Vue 3 component library for building Bootstrap‑styled forms inside **Laravel + Inertia.js** applications. Every input component binds itself automatically to an [Inertia `useForm`](https://inertiajs.com/forms) instance through a `<FormContainer>` wrapper, so you stop wiring up `v-model`, error classes, and field names by hand for every form.
|
|
4
|
+
|
|
5
|
+
```vue
|
|
6
|
+
<FormContainer v-model="formData" url="/products">
|
|
7
|
+
<div class="row g-3">
|
|
8
|
+
<div class="col-12 col-sm-6">
|
|
9
|
+
<FormLabel>Name</FormLabel>
|
|
10
|
+
<TextInput name="name" />
|
|
11
|
+
</div>
|
|
12
|
+
<div class="col-12 col-sm-3">
|
|
13
|
+
<FormLabel>Alias</FormLabel>
|
|
14
|
+
<TextInput name="slug" />
|
|
15
|
+
</div>
|
|
16
|
+
<div class="col-12 col-sm-3">
|
|
17
|
+
<FormLabel>Status</FormLabel>
|
|
18
|
+
<Select2Input name="status" :options="[
|
|
19
|
+
{ id: 'active', name: 'Active' },
|
|
20
|
+
{ id: 'disable', name: 'Disabled' },
|
|
21
|
+
{ id: 'draft', name: 'Draft' }
|
|
22
|
+
]" />
|
|
37
23
|
</div>
|
|
24
|
+
<div class="col-12 col-sm-6">
|
|
25
|
+
<FormLabel>New Image</FormLabel>
|
|
26
|
+
<FileInput name="new_thumbnail" />
|
|
27
|
+
</div>
|
|
28
|
+
<div class="col-12">
|
|
29
|
+
<FormLabel>Description</FormLabel>
|
|
30
|
+
<EditorInput name="description" />
|
|
31
|
+
</div>
|
|
32
|
+
<div class="col-12 text-end">
|
|
33
|
+
<SubmitButton />
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</FormContainer>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Table of Contents
|
|
42
|
+
|
|
43
|
+
1. [Requirements](#requirements)
|
|
44
|
+
2. [Installation](#installation)
|
|
45
|
+
3. [Global Setup (required helpers)](#global-setup-required-helpers)
|
|
46
|
+
4. [Core Concepts](#core-concepts)
|
|
47
|
+
5. [Component Reference](#component-reference)
|
|
48
|
+
- [FormContainer](#formcontainer)
|
|
49
|
+
- [FormLabel](#formlabel)
|
|
50
|
+
- [GroupControl](#groupcontrol)
|
|
51
|
+
- [TextInput](#textinput)
|
|
52
|
+
- [TextAreaInput](#textareainput)
|
|
53
|
+
- [EmailInput](#emailinput)
|
|
54
|
+
- [PasswordInput](#passwordinput)
|
|
55
|
+
- [MobileInput](#mobileinput)
|
|
56
|
+
- [TelInput](#telinput)
|
|
57
|
+
- [AmountInput](#amountinput)
|
|
58
|
+
- [QuantityInput](#quantityinput)
|
|
59
|
+
- [MultiQuantityInput](#multiquantityinput)
|
|
60
|
+
- [CheckboxInput](#checkboxinput)
|
|
61
|
+
- [CheckboxButtonInput](#checkboxbuttoninput)
|
|
62
|
+
- [CheckboxToggle](#checkboxtoggle)
|
|
63
|
+
- [Select2Input](#select2input)
|
|
64
|
+
- [PersianDatePickerInput](#persiandatepickerinput)
|
|
65
|
+
- [RangeSliderInput](#rangesliderinput)
|
|
66
|
+
- [StarRatingInput](#starratinginput)
|
|
67
|
+
- [CaptchaInput](#captchainput)
|
|
68
|
+
- [EditorInput](#editorinput)
|
|
69
|
+
- [LocationInput](#locationinput)
|
|
70
|
+
- [FileInput](#fileinput)
|
|
71
|
+
- [SimpleUploader](#simpleuploader)
|
|
72
|
+
- [DropzoneInput](#dropzoneinput)
|
|
73
|
+
- [UppyInput](#uppyinput)
|
|
74
|
+
- [SubmitButton](#submitbutton)
|
|
75
|
+
6. [Upload Endpoint Contract (backend)](#upload-endpoint-contract-backend)
|
|
76
|
+
7. [Styling & Theming](#styling--theming)
|
|
77
|
+
8. [TypeScript](#typescript)
|
|
78
|
+
9. [Known Limitations](#known-limitations)
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Requirements
|
|
83
|
+
|
|
84
|
+
The package itself only ships the Vue components (plus a few smaller libraries that are already bundled into `dist/`). The following must exist in the **host** application:
|
|
85
|
+
|
|
86
|
+
| Requirement | Why |
|
|
87
|
+
|---|---|
|
|
88
|
+
| Vue `^3.0` | The components are plain Vue 3 SFCs. |
|
|
89
|
+
| `@inertiajs/vue3` `>2.0` | `FormContainer` calls Inertia's `useForm()` internally. |
|
|
90
|
+
| Bootstrap 5 CSS (`.form-control`, `.btn`, `.input-group`, `.form-check`, CSS variables like `--bs-*`, etc.) | All markup/classes assume Bootstrap 5 is loaded. |
|
|
91
|
+
| `dropzone` `^6.0.0-beta.2` | Only needed if you use `<DropzoneInput>`. |
|
|
92
|
+
| `@tinymce/tinymce-vue` | Only needed if you use `<EditorInput>` (TinyMCE). |
|
|
93
|
+
| `@vue-leaflet/vue-leaflet` + `leaflet` | Only needed if you use `<LocationInput>`. |
|
|
94
|
+
| `vue-tel-input` | Only needed if you use `<TelInput>`. |
|
|
95
|
+
| `vue3-persian-datetime-picker` | Only needed if you use `<PersianDatePickerInput>`. |
|
|
96
|
+
| `maska` | Only needed if you use `<AmountInput>` or `<QuantityInput>` (number masking). |
|
|
97
|
+
| `axios` available globally as `window.axios` | Used internally by `<FileInput>`. Laravel's default `resources/js/bootstrap.js` already does this (`window.axios = require('axios')`). |
|
|
98
|
+
|
|
99
|
+
The following libraries are **already bundled inside `dist/`** and do **not** need to be installed separately: `vue3-bootstrap-components`, `choices.js`, `svelte-range-slider-pips`, `@uppy/core`, `@uppy/vue`, `@uppy/xhr-upload`.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Installation
|
|
104
|
+
|
|
105
|
+
### 1. Install the package
|
|
106
|
+
|
|
107
|
+
This package isn't necessarily on the public npm registry, so install it however it was distributed to you:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# from a private/internal npm registry
|
|
111
|
+
npm install inertia-bootstrap-forms
|
|
112
|
+
|
|
113
|
+
# from a Git repository
|
|
114
|
+
npm install git+https://github.com/novinvision/inertia-bootstrap-forms.git
|
|
115
|
+
|
|
116
|
+
# from a local folder or tarball
|
|
117
|
+
npm install file:../path/to/inertia-bootstrap-forms
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 2. Install the peer libraries you actually need
|
|
121
|
+
|
|
122
|
+
You don't have to install all of them — only the ones backing the components you use:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npm install @inertiajs/vue3 dropzone @tinymce/tinymce-vue \
|
|
126
|
+
@vue-leaflet/vue-leaflet leaflet vue-tel-input \
|
|
127
|
+
vue3-persian-datetime-picker maska
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 3. Import the package styles
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
// resources/js/app.js
|
|
134
|
+
import 'inertia-bootstrap-forms/dist/style.css';
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 4. Register the components
|
|
138
|
+
|
|
139
|
+
You can either import components individually (recommended, keeps the bundle small):
|
|
140
|
+
|
|
141
|
+
```vue
|
|
142
|
+
<script setup>
|
|
143
|
+
import { FormContainer, FormLabel, TextInput, SubmitButton } from 'inertia-bootstrap-forms';
|
|
144
|
+
</script>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
…or register everything globally once, in `app.js`:
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
import { createApp, h } from 'vue';
|
|
151
|
+
import { createInertiaApp } from '@inertiajs/vue3';
|
|
152
|
+
import * as InertiaBootstrapForms from 'inertia-bootstrap-forms';
|
|
153
|
+
import 'inertia-bootstrap-forms/dist/style.css';
|
|
154
|
+
|
|
155
|
+
createInertiaApp({
|
|
156
|
+
resolve: name => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
|
|
157
|
+
setup({ el, App, props, plugin }) {
|
|
158
|
+
const app = createApp({ render: () => h(App, props) }).use(plugin);
|
|
159
|
+
|
|
160
|
+
Object.entries(InertiaBootstrapForms).forEach(([name, component]) => {
|
|
161
|
+
if (name !== 'default') app.component(name, component);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
app.mount(el);
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Global Setup (required helpers)
|
|
172
|
+
|
|
173
|
+
Two components (`AmountInput`, `QuantityInput`) rely on globals that this package does **not** provide. You need to register them yourself in `app.js` before those components will work.
|
|
174
|
+
|
|
175
|
+
### `v-maska` directive
|
|
176
|
+
|
|
177
|
+
`AmountInput` and `QuantityInput` use `v-maska` (from the [`maska`](https://www.npmjs.com/package/maska) package) to format numbers with thousand separators while typing.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
npm install maska
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
import { vMaska } from 'maska/vue';
|
|
185
|
+
|
|
186
|
+
app.directive('maska', vMaska);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
You can use any version/config of `maska` you like — the components only depend on the directive name (`v-maska`) and the `@maska` event payload (`event.detail.unmasked`), so feel free to follow Maska's own documentation for advanced masking options.
|
|
190
|
+
|
|
191
|
+
### `$number` global helper
|
|
192
|
+
|
|
193
|
+
The same two components call `this.$number.toEnglish(...)` to convert localized (Persian/Arabic-Indic) digits typed by the user into plain English digits before storing them in the form. This helper is **not bundled** — you need to provide it as a global property. A minimal implementation that mirrors the digit conversion already used internally by `FormContainer` on submit:
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
// resources/js/plugins/number.js
|
|
197
|
+
const persianDigits = ['۰','۱','۲','۳','۴','۵','۶','۷','۸','۹'];
|
|
198
|
+
const arabicDigits = ['٠','١','٢','٣','٤','٥','٦','٧','٨','٩'];
|
|
199
|
+
|
|
200
|
+
export default {
|
|
201
|
+
install(app) {
|
|
202
|
+
app.config.globalProperties.$number = {
|
|
203
|
+
toEnglish(value) {
|
|
204
|
+
if (value === null || value === undefined) return value;
|
|
205
|
+
let str = value.toString();
|
|
206
|
+
persianDigits.forEach((d, i) => { str = str.replaceAll(d, i); });
|
|
207
|
+
arabicDigits.forEach((d, i) => { str = str.replaceAll(d, i); });
|
|
208
|
+
return str.replaceAll(',', '');
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
import NumberPlugin from './plugins/number';
|
|
217
|
+
app.use(NumberPlugin);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
If you don't use `AmountInput` or `QuantityInput`, you can skip this section entirely.
|
|
221
|
+
|
|
222
|
+
### Optional: Font Awesome
|
|
223
|
+
|
|
224
|
+
`CaptchaInput` renders a refresh icon using a Font Awesome class (`fal fa-sync-alt`, Pro "light" style). If you don't load Font Awesome Pro, the button still works — you just won't see the icon. Swap in your own icon via the component's markup if needed.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Core Concepts
|
|
229
|
+
|
|
230
|
+
### `FormContainer` and the injected `form`
|
|
231
|
+
|
|
232
|
+
`<FormContainer>` wraps Inertia's `useForm()` and `provide()`s it to every descendant via Vue's `provide`/`inject`. All the field components below `inject` this `form` object and read/write `form[name]` automatically — that's the entire trick behind not having to wire `v-model` on every field yourself.
|
|
233
|
+
|
|
234
|
+
```vue
|
|
235
|
+
<FormContainer v-model="formData" url="/login" method="post" reset-on-success>
|
|
236
|
+
<TextInput name="email" />
|
|
237
|
+
<PasswordInput name="password" />
|
|
238
|
+
<SubmitButton />
|
|
38
239
|
</FormContainer>
|
|
39
240
|
```
|
|
40
241
|
|
|
41
|
-
|
|
242
|
+
`FormContainer` props:
|
|
243
|
+
|
|
244
|
+
| Prop | Type | Default | Description |
|
|
245
|
+
|---|---|---|---|
|
|
246
|
+
| `url` | String | `''` | Endpoint the form submits to. |
|
|
247
|
+
| `method` | String | `'post'` | HTTP method passed to Inertia's `form.submit()`. |
|
|
248
|
+
| `only` | Array | `[]` | Inertia partial-reload `only` option. |
|
|
249
|
+
| `modelValue` | Object | `{}` | Initial data for the form (also works with `v-model`). |
|
|
250
|
+
| `options` | Object | `{}` | Extra fields merged into the Inertia form state (e.g. defaults that aren't real inputs). |
|
|
251
|
+
| `resetOnSuccess` | Boolean | `false` | Calls `form.reset()` automatically after a successful submit. |
|
|
252
|
+
| `submitHandler` | Function | `null` | If provided, this function is called instead of the default Inertia submit flow — useful for custom submit logic (e.g. confirmation modals). |
|
|
253
|
+
|
|
254
|
+
Events: `submit`, `reset`, `onStart`, `onFinish`, `onSuccess`, `onError`, `change`, `update:modelValue`.
|
|
255
|
+
|
|
256
|
+
Slots:
|
|
257
|
+
- default — scoped with `{ form, submit }`, the actual form fields.
|
|
258
|
+
- `errors` — override the default error `<Alert>` block.
|
|
259
|
+
- `message` — override the default success `<Alert>` block (shown when the backend response includes a `message` prop).
|
|
260
|
+
|
|
261
|
+
Exposed methods (via template ref): `submit()`, `reset()`.
|
|
262
|
+
|
|
263
|
+
Notable built-in behavior: on submit, `FormContainer` converts any Persian/Arabic-Indic digits present in the form's values to plain English digits before sending the request — handy for numeric fields typed with a Persian keyboard.
|
|
264
|
+
|
|
265
|
+
### Field naming & binding
|
|
266
|
+
|
|
267
|
+
Every field component takes a `name` prop. As long as it lives inside a `<FormContainer>` (or any component that injects a `form`), it automatically reads/writes `form[name]` — no manual `v-model` needed:
|
|
268
|
+
|
|
269
|
+
```vue
|
|
270
|
+
<TextInput name="title" />
|
|
271
|
+
<!-- equivalent to manually doing -->
|
|
272
|
+
<input v-model="form.title" name="title" class="form-control">
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Validation errors are read from `form.errors[name]` and applied as Bootstrap's `is-invalid` class automatically.
|
|
276
|
+
|
|
277
|
+
### Grouped / repeated fields — `GroupControl`
|
|
278
|
+
|
|
279
|
+
`<GroupControl name="...">` lets a *block* of fields write into a nested/indexed slice of the form data instead of the top level — useful for repeating rows (e.g. multiple bid items, multiple contacts, etc.).
|
|
280
|
+
|
|
281
|
+
Each `<GroupControl>` instance figures out its own index (`groupID`) based on its position among sibling `.form-control-group` blocks, so the typical pattern is to repeat the **whole** `<GroupControl>` with `v-for`:
|
|
282
|
+
|
|
283
|
+
```vue
|
|
284
|
+
<div v-for="(row, index) in rows" :key="index">
|
|
285
|
+
<GroupControl name="bids">
|
|
286
|
+
<TextInput name="title" />
|
|
287
|
+
<AmountInput name="price" />
|
|
288
|
+
</GroupControl>
|
|
289
|
+
</div>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
This produces `form.bids[0].title`, `form.bids[0].price`, `form.bids[1].title`, etc.
|
|
293
|
+
|
|
294
|
+
`MultiQuantityInput` (documented below) uses a single `GroupControl` to collect a *map* of quantities (`form.tickets.adult`, `form.tickets.child`, …) instead of a repeated list — see its own example for that variant.
|
|
295
|
+
|
|
296
|
+
### Validation & error display
|
|
297
|
+
|
|
298
|
+
`FormContainer` renders a default Bootstrap `Alert` listing every message in `form.errors` (replaceable via the `errors` slot), and every field adds `is-invalid` automatically when `form.errors[name]` exists. You don't need to render error text per-field unless you want to — Bootstrap will show `.invalid-feedback` siblings if you add them yourself.
|
|
299
|
+
|
|
300
|
+
### Element IDs
|
|
301
|
+
|
|
302
|
+
`form.getID(field)` (available on the injected `form`) builds a unique, collision-free `id` attribute for fields, taking the surrounding `<FormContainer>` id and any `GroupControl` into account. Components that render a real `<label for="">`/`<input id="">` pair (e.g. `TextInput`, `CheckboxInput`) use this automatically.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Component Reference
|
|
307
|
+
|
|
308
|
+
### FormContainer
|
|
309
|
+
|
|
310
|
+
See [Core Concepts](#formcontainer-and-the-injected-form) above for the full prop/event/slot table.
|
|
311
|
+
|
|
312
|
+
### FormLabel
|
|
313
|
+
|
|
314
|
+
Simple `<label>` wrapper that appends a red `*` when `required` is set.
|
|
315
|
+
|
|
316
|
+
```vue
|
|
317
|
+
<FormLabel required>Email address</FormLabel>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
| Prop | Type | Default |
|
|
321
|
+
|---|---|---|
|
|
322
|
+
| `required` | Boolean | `false` |
|
|
323
|
+
|
|
324
|
+
Slot: default — label text.
|
|
325
|
+
|
|
326
|
+
### GroupControl
|
|
327
|
+
|
|
328
|
+
See [Grouped / repeated fields](#grouped--repeated-fields--groupcontrol) above.
|
|
329
|
+
|
|
330
|
+
| Prop | Type | Required |
|
|
331
|
+
|---|---|---|
|
|
332
|
+
| `name` | String | yes |
|
|
333
|
+
|
|
334
|
+
### TextInput
|
|
335
|
+
|
|
336
|
+
The base text field. Most other "shortcut" inputs (`EmailInput`, `PasswordInput`, `MobileInput`) are thin wrappers around this component.
|
|
337
|
+
|
|
338
|
+
```vue
|
|
339
|
+
<TextInput name="full_name" />
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
| Prop | Type | Required |
|
|
343
|
+
|---|---|---|
|
|
344
|
+
| `name` | String | yes |
|
|
345
|
+
|
|
346
|
+
Renders a plain `<input type="text" class="form-control">` bound to `form[name]`.
|
|
347
|
+
|
|
348
|
+
### TextAreaInput
|
|
349
|
+
|
|
350
|
+
Same binding pattern as `TextInput`, renders a `<textarea class="form-control">`.
|
|
351
|
+
|
|
352
|
+
```vue
|
|
353
|
+
<TextAreaInput name="description" />
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
| Prop | Type | Required |
|
|
357
|
+
|---|---|---|
|
|
358
|
+
| `name` | String | yes |
|
|
359
|
+
|
|
360
|
+
### EmailInput
|
|
361
|
+
|
|
362
|
+
Thin wrapper around `TextInput` (`type="email"`, Persian placeholder "ایمیل خود را وارد کنید").
|
|
363
|
+
|
|
364
|
+
```vue
|
|
365
|
+
<EmailInput name="email" />
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
> **Note:** see [Known Limitations](#known-limitations) — the `name` prop on this specific wrapper is not declared correctly in the current source, so passing a custom `name` may not bind to the form data as expected. If that affects you, use `<TextInput name="..." type="email" />` directly instead.
|
|
369
|
+
|
|
370
|
+
### PasswordInput
|
|
371
|
+
|
|
372
|
+
Thin wrapper around `TextInput` (`type="password"`, Persian placeholder "گذرواژه خود را وارد کنید").
|
|
373
|
+
|
|
374
|
+
```vue
|
|
375
|
+
<PasswordInput name="password" />
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
| Prop | Type | Default |
|
|
379
|
+
|---|---|---|
|
|
380
|
+
| `name` | String | `'password'` |
|
|
381
|
+
|
|
382
|
+
### MobileInput
|
|
383
|
+
|
|
384
|
+
Thin wrapper around `TextInput` (`type="tel"`, Persian placeholder "موبایل خود را وارد کنید").
|
|
385
|
+
|
|
386
|
+
```vue
|
|
387
|
+
<MobileInput name="mobile" />
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
| Prop | Type | Default |
|
|
391
|
+
|---|---|---|
|
|
392
|
+
| `name` | String | `'mobile'` |
|
|
393
|
+
|
|
394
|
+
### TelInput
|
|
395
|
+
|
|
396
|
+
Full international phone input powered by the **external package `vue-tel-input`**. Defaults to Iran (`ir`) with a preferred-country list (`ir`, `us`, `tr`, `ca`) and a searchable country dropdown.
|
|
397
|
+
|
|
398
|
+
```vue
|
|
399
|
+
<TelInput name="phone" placeholder="912 345 6789" />
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
| Prop | Type | Default |
|
|
403
|
+
|---|---|---|
|
|
404
|
+
| `name` | String | `'email'` (see [Known Limitations](#known-limitations)) |
|
|
405
|
+
| `placeHolder` | String | `'000 000 0000'` |
|
|
406
|
+
|
|
407
|
+
Since this wraps `vue-tel-input`, all of that package's own configuration (locales, validation rules, dial-code formatting, flags, styling, etc.) can be controlled by following [vue-tel-input's documentation](https://www.npmjs.com/package/vue-tel-input) and adjusting the source if you need options beyond what's hard-coded here (`mode`, `defaultCountry`, `preferredCountries`, `dropdownOptions`).
|
|
408
|
+
|
|
409
|
+
### AmountInput
|
|
410
|
+
|
|
411
|
+
Numeric input with thousands-separator masking (via **external package `maska`** — see [Global Setup](#v-maska-directive)) and a trailing unit label.
|
|
412
|
+
|
|
413
|
+
```vue
|
|
414
|
+
<AmountInput name="price" unit="تومان" />
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
| Prop | Type | Default |
|
|
418
|
+
|---|---|---|
|
|
419
|
+
| `name` | String | required |
|
|
420
|
+
| `required` | Boolean | `false` |
|
|
421
|
+
| `disabled` | Boolean | `false` |
|
|
422
|
+
| `readonly` | Boolean | `false` |
|
|
423
|
+
| `placeholder` | String | `'عدد را وارد کنید'` |
|
|
424
|
+
| `unit` | String | `'عدد'` |
|
|
425
|
+
|
|
426
|
+
Slot: `suffix` — extra content appended after the unit label (inside the Bootstrap `InputGroup`).
|
|
427
|
+
|
|
428
|
+
Requires the `v-maska` directive and `$number.toEnglish()` global helper — see [Global Setup](#global-setup-required-helpers).
|
|
429
|
+
|
|
430
|
+
### QuantityInput
|
|
431
|
+
|
|
432
|
+
Stepper-style numeric input (`+` / `-` buttons) with the same masking as `AmountInput`.
|
|
433
|
+
|
|
434
|
+
```vue
|
|
435
|
+
<QuantityInput name="qty" :min="1" :max="10" unit="عدد" />
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
| Prop | Type | Default |
|
|
439
|
+
|---|---|---|
|
|
440
|
+
| `name` | String | required |
|
|
441
|
+
| `required` | Boolean | `false` |
|
|
442
|
+
| `disabled` | Boolean | `false` |
|
|
443
|
+
| `readonly` | Boolean | `false` |
|
|
444
|
+
| `unit` | String | `'عدد'` |
|
|
445
|
+
| `min` | Number | `0` |
|
|
446
|
+
| `max` | Number | `null` |
|
|
447
|
+
|
|
448
|
+
Slot: `suffix`.
|
|
449
|
+
|
|
450
|
+
Also requires the `v-maska` directive and `$number.toEnglish()` — see [Global Setup](#global-setup-required-helpers).
|
|
451
|
+
|
|
452
|
+
### MultiQuantityInput
|
|
453
|
+
|
|
454
|
+
A dropdown of multiple `QuantityInput` rows (e.g. "2 adults, 1 child") that collapses into a single summary button. Internally wraps its options in one `GroupControl`, so the result is stored as a map: `form[name][optionKey]`.
|
|
455
|
+
|
|
456
|
+
```vue
|
|
457
|
+
<MultiQuantityInput
|
|
458
|
+
name="tickets"
|
|
459
|
+
unit="نفر"
|
|
460
|
+
:options="[
|
|
461
|
+
{ name: 'بزرگسال', min: 1, max: 10 }, // key: 0
|
|
462
|
+
{ name: 'کودک', min: 0, max: 10 }, // key: 1
|
|
463
|
+
]"
|
|
464
|
+
/>
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
| Prop | Type | Default | Description |
|
|
468
|
+
|---|---|---|---|
|
|
469
|
+
| `name` | String | required | |
|
|
470
|
+
| `options` | Array | required | Each item can be a plain string or `{ name, min, max }`. The array index becomes the data key. |
|
|
471
|
+
| `required` | Boolean | `false` | |
|
|
472
|
+
| `disabled` | Boolean | `false` | |
|
|
473
|
+
| `readonly` | Boolean | `false` | |
|
|
474
|
+
| `max` | Number | `null` | Fallback max applied to options without their own `max`. |
|
|
475
|
+
| `totalMax` | Number | `null` | (declared, not currently enforced in the template logic) |
|
|
476
|
+
| `min` | Number | `0` | Fallback min applied to options without their own `min`. |
|
|
477
|
+
| `totalMin` | Number | `null` | (declared, not currently enforced in the template logic) |
|
|
478
|
+
| `unit` | String | `'Number'` | Label shown on the collapsed summary button. |
|
|
479
|
+
|
|
480
|
+
### CheckboxInput
|
|
481
|
+
|
|
482
|
+
Single checkbox/radio bound through the same `form`/`group` injection pattern as text fields.
|
|
483
|
+
|
|
484
|
+
```vue
|
|
485
|
+
<CheckboxInput name="accept_terms" value="yes">I agree to the terms</CheckboxInput>
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
| Prop | Type | Default |
|
|
489
|
+
|---|---|---|
|
|
490
|
+
| `name` | String | required |
|
|
491
|
+
| `id` | String | `''` |
|
|
492
|
+
| `value` | String / Number | `'yes'` |
|
|
493
|
+
| `type` | String | `'checkbox'` (can be set to `'radio'`) |
|
|
494
|
+
|
|
495
|
+
Event: `change`. Slot: default — label text.
|
|
496
|
+
|
|
497
|
+
To build a checkbox/radio **group**, repeat the component with the same `name` and different `value`s; bind the initial form value to an array for multi-select checkboxes, or a scalar for radios.
|
|
498
|
+
|
|
499
|
+
### CheckboxButtonInput
|
|
500
|
+
|
|
501
|
+
Same idea as `CheckboxInput` but styled as a Bootstrap "button checkbox/radio" (`.btn-check` + label) instead of a native checkbox UI.
|
|
502
|
+
|
|
503
|
+
```vue
|
|
504
|
+
<CheckboxButtonInput name="plan" value="monthly">Monthly</CheckboxButtonInput>
|
|
505
|
+
<CheckboxButtonInput name="plan" value="yearly">Yearly</CheckboxButtonInput>
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
| Prop | Type | Default |
|
|
509
|
+
|---|---|---|
|
|
510
|
+
| `name` | String | required |
|
|
511
|
+
| `id` | String | `''` |
|
|
512
|
+
| `value` | String | `'yes'` |
|
|
513
|
+
| `type` | String | `'radio'` |
|
|
514
|
+
|
|
515
|
+
Event: `change`. Wrap the rendered `<label>` in your own `.btn-group`/`.btn` classes for the typical Bootstrap button-group look.
|
|
516
|
+
|
|
517
|
+
### CheckboxToggle
|
|
518
|
+
|
|
519
|
+
A larger, card-style toggle (background highlight when checked) — good for plan pickers, add-on selectors, etc.
|
|
520
|
+
|
|
521
|
+
```vue
|
|
522
|
+
<CheckboxToggle name="addons" value="extra_luggage">Extra luggage</CheckboxToggle>
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
| Prop | Type | Default |
|
|
526
|
+
|---|---|---|
|
|
527
|
+
| `name` | String | required |
|
|
528
|
+
| `id` | String | `''` |
|
|
529
|
+
| `value` | String / Number | `'yes'` |
|
|
530
|
+
| `type` | String | `'checkbox'` |
|
|
531
|
+
| `hideInput` | Boolean | `false` — visually hides the native input while keeping the toggle clickable. |
|
|
532
|
+
|
|
533
|
+
Event: `change`.
|
|
534
|
+
|
|
535
|
+
### Select2Input
|
|
536
|
+
|
|
537
|
+
Searchable dropdown powered by the **external package `choices.js`**, with optional remote/async search.
|
|
538
|
+
|
|
539
|
+
```vue
|
|
540
|
+
<Select2Input
|
|
541
|
+
name="category_id"
|
|
542
|
+
:options="categories"
|
|
543
|
+
label="title"
|
|
544
|
+
placeholder="Select a category"
|
|
545
|
+
search-enabled
|
|
546
|
+
/>
|
|
547
|
+
|
|
548
|
+
<!-- Remote search -->
|
|
549
|
+
<Select2Input
|
|
550
|
+
name="user_id"
|
|
551
|
+
:search="{ url: '/api/users/search' }"
|
|
552
|
+
placeholder="Search a user..."
|
|
553
|
+
/>
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
| Prop | Type | Default | Description |
|
|
557
|
+
|---|---|---|---|
|
|
558
|
+
| `name` | String | required | |
|
|
559
|
+
| `options` | Array | — | Array of objects (or plain strings/numbers). |
|
|
560
|
+
| `label` | String | `null` | Object field used as the display label. Falls back to `name` / `label` / `value`. |
|
|
561
|
+
| `placeholder` | String | `'Click to choice'` | |
|
|
562
|
+
| `searchPlaceholder` | String | `'Type for search...'` | |
|
|
563
|
+
| `multiple` | Boolean | `false` | |
|
|
564
|
+
| `required` | Boolean | `false` | |
|
|
565
|
+
| `config` | Object | `{}` | Merged into `choices.js`'s own config — use this for any Choices.js option not exposed above. |
|
|
566
|
+
| `locale` | String | `'en'` | Set to `'fa'` (or rely on auto-detection from `document.dir === 'rtl'`) for built-in Persian UI strings. |
|
|
567
|
+
| `searchEnabled` | Boolean | `false` | Enables local in-list searching. Automatically `true` when `search.url` is set. |
|
|
568
|
+
| `hideDropdown` | Boolean | `false` | |
|
|
569
|
+
| `search` | Object | `{ url: null }` | When `url` is set, typing triggers a debounced `POST` request (`?query=...`) and replaces the option list with the JSON response. |
|
|
570
|
+
|
|
571
|
+
Events: `update:modelValue`, `search`, `searching`, `change`, `selected`.
|
|
572
|
+
|
|
573
|
+
> **Note:** the prop named `key` (meant to pick which object field is used as the option *value*) cannot actually be set from a template, because Vue reserves `:key` for its own list-rendering mechanism. The default value-resolution (`id` → `name` → `label` → `value`) is used instead. See [Known Limitations](#known-limitations).
|
|
574
|
+
|
|
575
|
+
Since this wraps Choices.js, any configuration option supported by that library can be passed through the `config` prop — see [Choices.js documentation](https://github.com/Choices-js/Choices) for the full list (custom templates, callback hooks, RTL, etc.).
|
|
576
|
+
|
|
577
|
+
### PersianDatePickerInput
|
|
578
|
+
|
|
579
|
+
Persian (Jalali) date/time picker powered by the **external package `vue3-persian-datetime-picker`**.
|
|
580
|
+
|
|
581
|
+
```vue
|
|
582
|
+
<PersianDatePickerInput name="birth_date" />
|
|
583
|
+
<PersianDatePickerInput name="appointment" calendar="datetime" view="datetime" range />
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
| Prop | Type | Default |
|
|
587
|
+
|---|---|---|
|
|
588
|
+
| `name` | String | required |
|
|
589
|
+
| `calendar` | String | `'date'` |
|
|
590
|
+
| `view` | String | `'date'` |
|
|
591
|
+
| `min` | String | — |
|
|
592
|
+
| `max` | String | — |
|
|
593
|
+
| `range` | Boolean | `false` |
|
|
594
|
+
| `locale` | String | `'fa'` |
|
|
595
|
+
| `format` | String | `'jYYYY-jMM-jDD'` |
|
|
596
|
+
| `inputFormat` | String | `null` (falls back to `format`) |
|
|
597
|
+
| `placeholder` | String | `'انتخاب تاریخ'` |
|
|
598
|
+
|
|
599
|
+
Event: `change`. Method exposed: `clear()`.
|
|
600
|
+
|
|
601
|
+
Any option supported by `vue3-persian-datetime-picker` itself (Gregorian mode, time steps, custom themes, etc.) can be used by following [that package's own documentation](https://www.npmjs.com/package/vue3-persian-datetime-picker) and extending the source where needed.
|
|
602
|
+
|
|
603
|
+
### RangeSliderInput
|
|
604
|
+
|
|
605
|
+
Slider input powered by the **external package `svelte-range-slider-pips`**.
|
|
606
|
+
|
|
607
|
+
```vue
|
|
608
|
+
<RangeSliderInput name="budget" :min="0" :max="1000" :step="10" />
|
|
609
|
+
<RangeSliderInput name="price_range" :min="0" :max="1000" range />
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
| Prop | Type | Default |
|
|
613
|
+
|---|---|---|
|
|
614
|
+
| `name` | String | `null` |
|
|
615
|
+
| `modelValue` | Number | `0` |
|
|
616
|
+
| `min` | Number | `1` |
|
|
617
|
+
| `max` | Number | `100` |
|
|
618
|
+
| `step` | Number | `1` |
|
|
619
|
+
| `readonly` | Boolean | `false` |
|
|
620
|
+
| `range` | Boolean | `false` — emits `[min, max]` instead of a single value. |
|
|
621
|
+
| `options` | Object | `{}` | Passed straight through to `svelte-range-slider-pips` — use this for pips formatting, colors, springs, etc. See [that package's docs](https://github.com/simeydotme/svelte-range-slider-pips) for everything it supports. |
|
|
622
|
+
|
|
623
|
+
Events: `update:modelValue`, `change`.
|
|
624
|
+
|
|
625
|
+
### StarRatingInput
|
|
626
|
+
|
|
627
|
+
Hover/click star rating, no external dependency.
|
|
628
|
+
|
|
629
|
+
```vue
|
|
630
|
+
<StarRatingInput name="rating" :max-stars="5" />
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
| Prop | Type | Default |
|
|
634
|
+
|---|---|---|
|
|
635
|
+
| `name` | String | `null` |
|
|
636
|
+
| `modelValue` | Number | `0` |
|
|
637
|
+
| `maxStars` | Number | `5` |
|
|
638
|
+
| `precision` | Number | `2` |
|
|
639
|
+
| `showValue` | Boolean | `true` |
|
|
640
|
+
| `readonly` | Boolean | `false` |
|
|
641
|
+
|
|
642
|
+
Event: `update:modelValue`.
|
|
643
|
+
|
|
644
|
+
### CaptchaInput
|
|
645
|
+
|
|
646
|
+
Image captcha field with a refresh button. Expects a backend endpoint that returns a captcha **image** for `GET` and re-rolls automatically whenever the form finishes processing (e.g. after a failed submit).
|
|
647
|
+
|
|
648
|
+
```vue
|
|
649
|
+
<CaptchaInput url="/captcha/default" />
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
| Prop | Type | Default |
|
|
653
|
+
|---|---|---|
|
|
654
|
+
| `name` | String | `'captcha'` |
|
|
655
|
+
| `url` | String | `'/captcha/default'` |
|
|
656
|
+
| `required` | Boolean | `false` |
|
|
657
|
+
| `placeholder` | String | `'کد امنیتی روبرو را وارد کنید'` |
|
|
658
|
+
|
|
659
|
+
Must be used inside a `<FormContainer>` (it injects `form` directly, without a fallback). A Persian comment in the source notes a ready-to-pair Laravel captcha endpoint is expected at `url`.
|
|
660
|
+
|
|
661
|
+
### EditorInput
|
|
662
|
+
|
|
663
|
+
Rich-text editor powered by the **external package `@tinymce/tinymce-vue`** (TinyMCE).
|
|
664
|
+
|
|
665
|
+
```vue
|
|
666
|
+
<EditorInput name="body" :options="{ height: 400 }" />
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
| Prop | Type | Default |
|
|
670
|
+
|---|---|---|
|
|
671
|
+
| `name` | String | required |
|
|
672
|
+
| `placeholder` | String | `''` |
|
|
673
|
+
| `disabled` | Boolean | `false` |
|
|
674
|
+
| `options` | Object | `{}` — merged into TinyMCE's own `init` config. |
|
|
675
|
+
|
|
676
|
+
Event: `update:modelValue`. Exposed: `editor()` — returns the underlying TinyMCE editor instance.
|
|
677
|
+
|
|
678
|
+
TinyMCE typically needs either a hosted script/API key or a self-hosted bundle — refer to [TinyMCE's Vue integration docs](https://www.tiny.cloud/docs/tinymce/latest/vue-cloud/) for licensing/configuration details and pass any extra option (toolbar, plugins, content_css, license_key, etc.) through the `options` prop.
|
|
679
|
+
|
|
680
|
+
### LocationInput
|
|
681
|
+
|
|
682
|
+
Interactive map picker (click or drag a marker) powered by **external packages `@vue-leaflet/vue-leaflet` and `leaflet`**, using OpenStreetMap tiles.
|
|
683
|
+
|
|
684
|
+
```vue
|
|
685
|
+
<LocationInput name="location" />
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
| Prop | Type | Default |
|
|
689
|
+
|---|---|---|
|
|
690
|
+
| `name` | String | `'location'` |
|
|
691
|
+
| `disabled` | Boolean / String | `false` |
|
|
692
|
+
| `readonly` | Boolean / String | `false` |
|
|
693
|
+
| `modelValue` | Object | `{ lat, lng }` |
|
|
694
|
+
|
|
695
|
+
Event: `update:modelValue`. Stores `{ lat, lng }` into `form[name]`.
|
|
696
|
+
|
|
697
|
+
Since this wraps Vue-Leaflet, any Leaflet/Vue-Leaflet feature (custom tile providers, zoom controls, extra layers) can be added by following [Vue-Leaflet's documentation](https://vue-leaflet.github.io/vue-leaflet/) and extending the component's `<l-map>` template if you need more than a single draggable marker.
|
|
698
|
+
|
|
699
|
+
### FileInput
|
|
700
|
+
|
|
701
|
+
Single/multiple file uploader using `axios` (global `window.axios`) with a per-file progress bar, retry, and delete.
|
|
702
|
+
|
|
703
|
+
```vue
|
|
704
|
+
<FileInput name="avatar" endpoint="/upload" />
|
|
705
|
+
<FileInput name="gallery" endpoint="/upload" multiple />
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
| Prop | Type | Default |
|
|
709
|
+
|---|---|---|
|
|
710
|
+
| `name` | String | required |
|
|
711
|
+
| `multiple` | Boolean | `false` |
|
|
712
|
+
| `endpoint` | String | `'/upload'` |
|
|
713
|
+
|
|
714
|
+
Event: `update:modelValue`. See [Upload Endpoint Contract](#upload-endpoint-contract-backend).
|
|
715
|
+
|
|
716
|
+
### SimpleUploader
|
|
717
|
+
|
|
718
|
+
Functionally identical to `FileInput`, but uses the native `fetch` API instead of `axios` — use this one if you don't have `window.axios` configured globally.
|
|
719
|
+
|
|
720
|
+
```vue
|
|
721
|
+
<SimpleUploader name="avatar" endpoint="/upload" />
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
| Prop | Type | Default |
|
|
725
|
+
|---|---|---|
|
|
726
|
+
| `name` | String | required |
|
|
727
|
+
| `multiple` | Boolean | `false` |
|
|
728
|
+
| `endpoint` | String | `'/upload'` |
|
|
729
|
+
|
|
730
|
+
### DropzoneInput
|
|
731
|
+
|
|
732
|
+
Drag-and-drop uploader powered by the **external package `dropzone`** (Dropzone.js).
|
|
733
|
+
|
|
734
|
+
```vue
|
|
735
|
+
<DropzoneInput name="documents" url="/upload" multiple :options="{ maxFiles: 5 }" />
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
| Prop | Type | Default |
|
|
739
|
+
|---|---|---|
|
|
740
|
+
| `name` | String | required |
|
|
741
|
+
| `multiple` | Boolean | `false` |
|
|
742
|
+
| `url` | String | `'/upload'` |
|
|
743
|
+
| `options` | Object | `{}` — merged into Dropzone's own constructor options. |
|
|
744
|
+
|
|
745
|
+
Event: `update:modelValue`.
|
|
746
|
+
|
|
747
|
+
Since this wraps Dropzone.js directly, any Dropzone option (`acceptedFiles`, `maxFilesize`, `dictDefaultMessage`, thumbnails, custom previews, etc.) can be passed through the `options` prop — see [Dropzone.js's documentation](https://docs.dropzone.dev/) for the full list.
|
|
748
|
+
|
|
749
|
+
### UppyInput
|
|
750
|
+
|
|
751
|
+
The most feature-rich uploader, powered by the **external package family `@uppy/core`, `@uppy/vue`, `@uppy/xhr-upload`** (the latter two are bundled; `@uppy/audio`, `@uppy/dashboard`, `@uppy/drag-drop`, and `@uppy/locales` are listed as dependencies for you to opt into via the slot below).
|
|
752
|
+
|
|
753
|
+
Default usage renders Uppy's built-in `Dropzone` + `FilesList`:
|
|
754
|
+
|
|
755
|
+
```vue
|
|
756
|
+
<UppyInput
|
|
757
|
+
name="attachments"
|
|
758
|
+
url="/upload"
|
|
759
|
+
multiple
|
|
760
|
+
:config="{ restrictions: { maxFileSize: 5 * 1024 * 1024, allowedFileTypes: ['.jpg', '.png', '.pdf'] } }"
|
|
761
|
+
/>
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
| Prop | Type | Default | Description |
|
|
765
|
+
|---|---|---|---|
|
|
766
|
+
| `name` | String | required | |
|
|
767
|
+
| `multiple` | Boolean | `false` | |
|
|
768
|
+
| `useXHR` | Boolean | `true` | Automatically registers `@uppy/xhr-upload` pointed at `url`. Set `false` if you want to register your own uploader plugin (e.g. AWS S3, Tus) on the exposed `uppy` instance instead. |
|
|
769
|
+
| `XHRConfig` | Object | `{}` | Merged into `@uppy/xhr-upload`'s own config (headers, formData, fieldName, etc.). |
|
|
770
|
+
| `url` | String | `'/upload'` | |
|
|
771
|
+
| `config` | Object | `{}` | Merged into Uppy's core constructor options (`id`, `autoProceed`, `restrictions`, `locale`, etc.). |
|
|
772
|
+
| `errorHandler` | Function | `null` | Custom error display/handling instead of the built-in inline error banner. |
|
|
773
|
+
| `showRestrictionCaption` | Boolean | `true` | Shows an auto-generated Persian caption describing the configured file-size/type/count restrictions. |
|
|
774
|
+
|
|
775
|
+
Events: `update:modelValue`, `file-added`, `file-removed`, `beforeUpload`, `progress`, `upload`, `upload-progress`, `upload-error`, `upload-success`, `upload-pause`, `complete`, `error`, `upload-retry`, `upload-stalled`, `retry-all`, `cancel-all`, `restriction-failed`.
|
|
776
|
+
|
|
777
|
+
Slot: default — scoped with `{ uppy }`, the raw Uppy instance, letting you completely replace the default Dropzone/FilesList UI with your own, or register extra Uppy plugins:
|
|
778
|
+
|
|
779
|
+
```vue
|
|
780
|
+
<UppyInput name="cover" url="/upload" v-slot="{ uppy }">
|
|
781
|
+
<!-- bring your own plugins, e.g. @uppy/dashboard, @uppy/audio, @uppy/drag-drop -->
|
|
782
|
+
</UppyInput>
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
Because the file restriction caption, error banners, and the `Dropzone`/`FilesList` building blocks all come straight from Uppy, refer to [Uppy's documentation](https://uppy.io/docs/uppy/) for every available core/plugin option (restrictions, locales, custom plugins like Dashboard/Audio/Webcam/DragDrop, etc.) — anything supported there can be passed through `config`, `XHRConfig`, or registered manually on the exposed `uppy` instance.
|
|
786
|
+
|
|
787
|
+
### SubmitButton
|
|
788
|
+
|
|
789
|
+
Submit button wired to the injected `form`'s `processing`/`uploading` state, showing a spinner automatically.
|
|
790
|
+
|
|
791
|
+
```vue
|
|
792
|
+
<SubmitButton />
|
|
793
|
+
<SubmitButton>Save changes</SubmitButton>
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
| Prop | Type | Default |
|
|
797
|
+
|---|---|---|
|
|
798
|
+
| `disabled` | Boolean | `false` |
|
|
799
|
+
|
|
800
|
+
Slots:
|
|
801
|
+
- default — scoped with `{ form }`. Defaults to "تایید و ثبت اطلاعات" (Persian for "Confirm and submit").
|
|
802
|
+
- `progress` — scoped, defaults to an upload percentage (`form.uploading`%) while a file upload is in progress.
|
|
803
|
+
|
|
804
|
+
Must be used inside a `<FormContainer>` (injects `form` directly).
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
## Upload Endpoint Contract (backend)
|
|
809
|
+
|
|
810
|
+
`FileInput`, `SimpleUploader`, `DropzoneInput`, and `UppyInput` all expect a similar JSON contract from your backend:
|
|
811
|
+
|
|
812
|
+
- **Upload (`POST` to the configured endpoint/url):** respond with JSON describing the stored file. At minimum a `path` field, e.g. `{ "path": "uploads/abc123.jpg" }`. (`DropzoneInput` also accepts the raw response if there's no `.data` wrapper; `UppyInput` reads from `response.body`.)
|
|
813
|
+
- **Delete (`DELETE` to the same endpoint/url):** the components send the stored file's data (e.g. `{ "path": "..." }`) as the request body so the backend can remove it from storage.
|
|
814
|
+
|
|
815
|
+
The original package README points to a companion Laravel package, **`novinvision/simple-uploader`**, for implementing this endpoint server-side — use it if it's available to you, or implement an equivalent controller.
|
|
816
|
+
|
|
817
|
+
---
|
|
818
|
+
|
|
819
|
+
## Styling & Theming
|
|
820
|
+
|
|
821
|
+
All components are plain Bootstrap 5 markup/classes (`.form-control`, `.input-group`, `.form-check`, `.btn`, etc.) plus a handful of custom classes (`.form-check-toggle`, `.star-rating`, `.multi-quantity-input`, `.file-input-uploader`, `.uppy-input-area`, …) shipped in `dist/style.css`. Most custom styling reads Bootstrap CSS variables (`--bs-primary`, `--bs-border-radius`, `--bs-body-bg`, etc.), so if your project already themes Bootstrap via CSS variables, these components will inherit that theme automatically. Persian/Farsi numeral display uses a `.fanum` utility class throughout — make sure your global stylesheet defines the font-feature/font-family rules you want for it (it's used as a styling hook, not generated by this package).
|
|
822
|
+
|
|
823
|
+
---
|
|
824
|
+
|
|
825
|
+
## TypeScript
|
|
826
|
+
|
|
827
|
+
Type declarations are provided in `index.d.ts` (most components are typed loosely as `DefineComponent<{}, {}, any>` except for the ones with richer prop/event typing: `CheckboxButtonInput`, `EditorInput`, `UppyInput`, `FormContainer`, `LocationInput`, `Select2Input`, `SubmitButton`, `RangeSliderInput`). Import as usual:
|
|
828
|
+
|
|
829
|
+
```ts
|
|
830
|
+
import { TextInput, FormContainer } from 'inertia-bootstrap-forms';
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
---
|
|
42
834
|
|
|
43
|
-
|
|
835
|
+
## Known Limitations
|
|
44
836
|
|
|
45
|
-
|
|
837
|
+
A few quirks in the current source worth knowing about before you rely on certain props:
|
|
46
838
|
|
|
839
|
+
- **`EmailInput`'s `name` prop:** the component's `props` block doesn't actually declare a `name` prop (it declares an unrelated `FileInput` prop instead), so passing a custom `name="..."` may not bind correctly to the form. If you need a non-default field name for an email field, use `<TextInput name="..." type="email" placeholder="..." />` directly.
|
|
840
|
+
- **`TelInput`'s default `name`:** defaults to `'email'` rather than something like `'mobile'`/`'phone'` — always pass an explicit `name` prop to avoid surprises.
|
|
841
|
+
- **`Select2Input`'s `key` prop:** intended to let you choose which object field is used as an option's value, but it can't actually be set from a template, since Vue reserves `:key` for its own list-rendering/diffing mechanism. In practice, value resolution always falls back to `id` → `name` → `label` → `value` (or the `label` prop, for the display text).
|
|
842
|
+
- **`MultiQuantityInput`'s `totalMax`/`totalMin` props:** declared, but not currently enforced anywhere in the component's logic — treat them as reserved for future use rather than working constraints.
|
|
843
|
+
- Several components are typed `DefineComponent<{}, {}, any>` in `index.d.ts`, i.e. without real prop typing — rely on this README (or the `.vue` source) rather than IDE autocomplete for the full prop list of those components.
|
package/index.d.ts
CHANGED
|
@@ -269,7 +269,35 @@ export const LocationInput: DefineComponent<{
|
|
|
269
269
|
export const MobileInput: DefineComponent<{}, {}, any>;
|
|
270
270
|
export const MultiQuantityInput: DefineComponent<{}, {}, any>;
|
|
271
271
|
export const PasswordInput: DefineComponent<{}, {}, any>;
|
|
272
|
-
export const PersianDatePickerInput: DefineComponent<{
|
|
272
|
+
export const PersianDatePickerInput: DefineComponent<{
|
|
273
|
+
name: {
|
|
274
|
+
type: String,
|
|
275
|
+
required: true,
|
|
276
|
+
},
|
|
277
|
+
calendar: {
|
|
278
|
+
type: String,
|
|
279
|
+
default: 'date',
|
|
280
|
+
},
|
|
281
|
+
view: {
|
|
282
|
+
type: String,
|
|
283
|
+
default: 'date',
|
|
284
|
+
},
|
|
285
|
+
min: String,
|
|
286
|
+
max: String,
|
|
287
|
+
range: Boolean,
|
|
288
|
+
locale: {
|
|
289
|
+
default: 'fa',
|
|
290
|
+
},
|
|
291
|
+
format: {
|
|
292
|
+
type: String,
|
|
293
|
+
default: 'jYYYY-jMM-jDD',
|
|
294
|
+
},
|
|
295
|
+
inputFormat: {
|
|
296
|
+
type: String,
|
|
297
|
+
default: null,
|
|
298
|
+
},
|
|
299
|
+
placeholder: String,
|
|
300
|
+
}, {}, any>;
|
|
273
301
|
export const QuantityInput: DefineComponent<{}, {}, any>;
|
|
274
302
|
export const Select2Input: DefineComponent<{
|
|
275
303
|
name: {
|
package/package.json
CHANGED