@gorse/shards-vue 1.0.8
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/.editorconfig +13 -0
- package/CHANGELOG.md +49 -0
- package/CONTRIBUTING.md +92 -0
- package/ISSUE_TEMPLATE.md +19 -0
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/build/optimize.js +49 -0
- package/build/paths.js +12 -0
- package/build/rollup.config.js +106 -0
- package/dist/shards-vue.common.js +13994 -0
- package/dist/shards-vue.common.js.map +1 -0
- package/dist/shards-vue.common.min.js +1 -0
- package/dist/shards-vue.common.min.map +1 -0
- package/dist/shards-vue.esm.js +13990 -0
- package/dist/shards-vue.esm.js.map +1 -0
- package/dist/shards-vue.esm.min.js +1 -0
- package/dist/shards-vue.esm.min.map +1 -0
- package/dist/shards-vue.umd.js +13997 -0
- package/dist/shards-vue.umd.js.map +1 -0
- package/dist/shards-vue.umd.min.js +1 -0
- package/dist/shards-vue.umd.min.map +1 -0
- package/logo.jpg +0 -0
- package/package.json +121 -0
- package/sandbox/Sandbox.vue +45 -0
- package/src/components/alert/Alert.vue +156 -0
- package/src/components/alert/README.md +86 -0
- package/src/components/alert/index.js +17 -0
- package/src/components/badge/Badge.vue +62 -0
- package/src/components/badge/README.md +112 -0
- package/src/components/badge/index.js +17 -0
- package/src/components/breadcrumb/Breadcrumb.vue +55 -0
- package/src/components/breadcrumb/BreadcrumbItem.vue +42 -0
- package/src/components/breadcrumb/BreadcrumbLink.vue +56 -0
- package/src/components/breadcrumb/README.md +53 -0
- package/src/components/breadcrumb/index.js +23 -0
- package/src/components/button/Button.vue +107 -0
- package/src/components/button/ButtonClose.vue +47 -0
- package/src/components/button/README.md +197 -0
- package/src/components/button/index.js +21 -0
- package/src/components/button-group/ButtonGroup.vue +66 -0
- package/src/components/button-group/README.md +72 -0
- package/src/components/button-group/index.js +18 -0
- package/src/components/button-toolbar/ButtonToolbar.vue +29 -0
- package/src/components/button-toolbar/README.md +24 -0
- package/src/components/button-toolbar/index.js +18 -0
- package/src/components/card/Card.vue +57 -0
- package/src/components/card/CardBody.vue +92 -0
- package/src/components/card/CardFooter.vue +61 -0
- package/src/components/card/CardGroup.vue +47 -0
- package/src/components/card/CardHeader.vue +61 -0
- package/src/components/card/CardImg.vue +64 -0
- package/src/components/card/README.md +96 -0
- package/src/components/card/index.js +27 -0
- package/src/components/collapse/Collapse.vue +209 -0
- package/src/components/collapse/README.md +86 -0
- package/src/components/collapse/index.js +17 -0
- package/src/components/container/Col.vue +125 -0
- package/src/components/container/Container.vue +31 -0
- package/src/components/container/README.md +91 -0
- package/src/components/container/Row.vue +64 -0
- package/src/components/container/index.js +21 -0
- package/src/components/datepicker/Datepicker.vue +391 -0
- package/src/components/datepicker/README.md +185 -0
- package/src/components/datepicker/index.js +17 -0
- package/src/components/dropdown/Dropdown.vue +442 -0
- package/src/components/dropdown/DropdownDivider.vue +22 -0
- package/src/components/dropdown/DropdownHeader.vue +29 -0
- package/src/components/dropdown/DropdownItem.vue +25 -0
- package/src/components/dropdown/README.md +177 -0
- package/src/components/dropdown/index.js +23 -0
- package/src/components/embed/Embed.vue +47 -0
- package/src/components/embed/README.md +23 -0
- package/src/components/embed/index.js +17 -0
- package/src/components/form/Form.vue +40 -0
- package/src/components/form/FormFeedback.vue +39 -0
- package/src/components/form/FormInvalidFeedback.vue +39 -0
- package/src/components/form/FormRow.vue +21 -0
- package/src/components/form/FormText.vue +41 -0
- package/src/components/form/FormValidFeedback.vue +39 -0
- package/src/components/form/README.md +84 -0
- package/src/components/form/index.js +29 -0
- package/src/components/form-checkbox/FormCheckbox.vue +200 -0
- package/src/components/form-checkbox/README.md +131 -0
- package/src/components/form-checkbox/index.js +18 -0
- package/src/components/form-input/FormInput.vue +176 -0
- package/src/components/form-input/README.md +110 -0
- package/src/components/form-input/index.js +18 -0
- package/src/components/form-radio/FormRadio.vue +155 -0
- package/src/components/form-radio/README.md +61 -0
- package/src/components/form-radio/index.js +18 -0
- package/src/components/form-select/FormSelect.vue +246 -0
- package/src/components/form-select/README.md +180 -0
- package/src/components/form-select/index.js +18 -0
- package/src/components/form-textarea/FormTextarea.vue +250 -0
- package/src/components/form-textarea/README.md +74 -0
- package/src/components/form-textarea/index.js +18 -0
- package/src/components/image/Image.vue +123 -0
- package/src/components/image/README.md +32 -0
- package/src/components/image/index.js +18 -0
- package/src/components/index.js +63 -0
- package/src/components/input-group/InputGroup.vue +125 -0
- package/src/components/input-group/InputGroupAddon.vue +58 -0
- package/src/components/input-group/InputGroupText.vue +20 -0
- package/src/components/input-group/README.md +188 -0
- package/src/components/input-group/index.js +21 -0
- package/src/components/link/Link.vue +157 -0
- package/src/components/link/README.md +27 -0
- package/src/components/link/create-link-props.js +54 -0
- package/src/components/link/index.js +17 -0
- package/src/components/list-group/ListGroup.vue +30 -0
- package/src/components/list-group/ListGroupItem.vue +90 -0
- package/src/components/list-group/README.md +23 -0
- package/src/components/list-group/index.js +19 -0
- package/src/components/modal/Modal.vue +121 -0
- package/src/components/modal/ModalBody.vue +20 -0
- package/src/components/modal/ModalFooter.vue +21 -0
- package/src/components/modal/ModalHeader.vue +39 -0
- package/src/components/modal/ModalTitle.vue +21 -0
- package/src/components/modal/README.md +74 -0
- package/src/components/modal/index.js +25 -0
- package/src/components/nav/Nav.vue +62 -0
- package/src/components/nav/NavItem.vue +23 -0
- package/src/components/nav/NavText.vue +21 -0
- package/src/components/nav/README.md +94 -0
- package/src/components/nav/index.js +19 -0
- package/src/components/navbar/Navbar.vue +63 -0
- package/src/components/navbar/NavbarBrand.vue +41 -0
- package/src/components/navbar/NavbarNav.vue +38 -0
- package/src/components/navbar/NavbarToggle.vue +55 -0
- package/src/components/navbar/README.md +51 -0
- package/src/components/navbar/index.js +23 -0
- package/src/components/popover/Popover.vue +126 -0
- package/src/components/popover/README.md +73 -0
- package/src/components/popover/index.js +17 -0
- package/src/components/progress/Progress.vue +93 -0
- package/src/components/progress/ProgressBar.vue +123 -0
- package/src/components/progress/README.md +95 -0
- package/src/components/progress/index.js +19 -0
- package/src/components/slider/README.md +120 -0
- package/src/components/slider/Slider.vue +103 -0
- package/src/components/slider/index.js +17 -0
- package/src/components/tabs/README.md +111 -0
- package/src/components/tabs/Tab.vue +132 -0
- package/src/components/tabs/Tabs.vue +290 -0
- package/src/components/tabs/_TabButton.vue +130 -0
- package/src/components/tabs/index.js +19 -0
- package/src/components/tooltip/README.md +70 -0
- package/src/components/tooltip/Tooltip.vue +115 -0
- package/src/components/tooltip/index.js +17 -0
- package/src/directives/index.js +7 -0
- package/src/directives/toggle/index.js +16 -0
- package/src/directives/toggle/toggle.js +45 -0
- package/src/directives/tooltip/README.md +42 -0
- package/src/directives/tooltip/index.js +16 -0
- package/src/directives/tooltip/meta.json +5 -0
- package/src/directives/tooltip/tooltip.js +145 -0
- package/src/index.js +27 -0
- package/src/markdown/getting-started/README.md +80 -0
- package/src/markdown/getting-started/meta.json +4 -0
- package/src/markdown/roadmap/README.md +3 -0
- package/src/markdown/roadmap/meta.json +4 -0
- package/src/mixins/checkbox-radio.mixin.js +73 -0
- package/src/mixins/root-listener.mixin.js +32 -0
- package/src/mixins/tooltip-popover.mixin.js +292 -0
- package/src/scripts/utils.js +18 -0
- package/src/utils/constants.js +191 -0
- package/src/utils/events.js +48 -0
- package/src/utils/index.js +251 -0
- package/src/utils/observer.js +56 -0
- package/src/utils/popover.class.js +91 -0
- package/src/utils/target.js +50 -0
- package/src/utils/tooltip.class.js +60 -0
- package/src/utils/tpmanager.class.js +730 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<select ref="input"
|
|
3
|
+
:class="[
|
|
4
|
+
'form-control',
|
|
5
|
+
stateClass,
|
|
6
|
+
size ? `form-control-${size}` : null,
|
|
7
|
+
!multiple && selectSize > 1 ? null : 'custom-select'
|
|
8
|
+
]"
|
|
9
|
+
v-model="localValue"
|
|
10
|
+
:id="computedID"
|
|
11
|
+
:name="name"
|
|
12
|
+
:multiple="multiple || null"
|
|
13
|
+
:size="(multiple || selectSize > 1) ? selectSize : null"
|
|
14
|
+
:disabled="disabled"
|
|
15
|
+
:required="required"
|
|
16
|
+
:aria-required="required ? true : null"
|
|
17
|
+
:aria-invalid="computedAriaInvalid"
|
|
18
|
+
@change="handleChange" >
|
|
19
|
+
<option v-for="(option, idx) in formOptions"
|
|
20
|
+
:key="`dr-opt-${idx}`"
|
|
21
|
+
:value="option.value"
|
|
22
|
+
:disabled="Boolean(option.disabled)">
|
|
23
|
+
{{ option.text }}
|
|
24
|
+
</option>
|
|
25
|
+
<slot />
|
|
26
|
+
</select>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script>
|
|
30
|
+
import { guid } from '../../utils'
|
|
31
|
+
|
|
32
|
+
export default {
|
|
33
|
+
name: 'd-form-select',
|
|
34
|
+
props: {
|
|
35
|
+
/**
|
|
36
|
+
* The element ID.
|
|
37
|
+
*/
|
|
38
|
+
id: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: null
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* The element name.
|
|
44
|
+
*/
|
|
45
|
+
name: {
|
|
46
|
+
type: String
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* The select options.
|
|
50
|
+
*/
|
|
51
|
+
options: {
|
|
52
|
+
type: [Array, Object],
|
|
53
|
+
default() {
|
|
54
|
+
return []
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
/**
|
|
58
|
+
* The select value.
|
|
59
|
+
*/
|
|
60
|
+
value: {},
|
|
61
|
+
/**
|
|
62
|
+
* Whether it should allow multiple selections, or not.
|
|
63
|
+
*/
|
|
64
|
+
multiple: {
|
|
65
|
+
type: Boolean,
|
|
66
|
+
default: false
|
|
67
|
+
},
|
|
68
|
+
/**
|
|
69
|
+
* How many options should be visible.
|
|
70
|
+
*/
|
|
71
|
+
selectSize: {
|
|
72
|
+
type: Number,
|
|
73
|
+
default: 0
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* Controls the `aria-invalid` attribute.
|
|
77
|
+
*/
|
|
78
|
+
ariaInvalid: {
|
|
79
|
+
type: [Boolean, String],
|
|
80
|
+
default: false
|
|
81
|
+
},
|
|
82
|
+
/**
|
|
83
|
+
* The value field.
|
|
84
|
+
*/
|
|
85
|
+
valueField: {
|
|
86
|
+
type: String,
|
|
87
|
+
default: 'value'
|
|
88
|
+
},
|
|
89
|
+
/**
|
|
90
|
+
* The disabled field.
|
|
91
|
+
*/
|
|
92
|
+
disabledField: {
|
|
93
|
+
type: String,
|
|
94
|
+
default: 'disabled'
|
|
95
|
+
},
|
|
96
|
+
/**
|
|
97
|
+
* The text field.
|
|
98
|
+
*/
|
|
99
|
+
textField: {
|
|
100
|
+
type: String,
|
|
101
|
+
default: 'text'
|
|
102
|
+
},
|
|
103
|
+
/**
|
|
104
|
+
* The disabled state.
|
|
105
|
+
*/
|
|
106
|
+
disabled: {
|
|
107
|
+
type: Boolean,
|
|
108
|
+
default: false
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* The required state.
|
|
112
|
+
*/
|
|
113
|
+
required: {
|
|
114
|
+
type: Boolean,
|
|
115
|
+
default: false
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* The validity state (invalid, valid, true, false).
|
|
119
|
+
*/
|
|
120
|
+
state: {
|
|
121
|
+
type: [Boolean, String],
|
|
122
|
+
default: null,
|
|
123
|
+
validator: v => ['valid', 'invalid', true, false, null].includes(v)
|
|
124
|
+
},
|
|
125
|
+
/**
|
|
126
|
+
* The form control size (sm, lg).
|
|
127
|
+
*/
|
|
128
|
+
size: {
|
|
129
|
+
type: String,
|
|
130
|
+
default: null,
|
|
131
|
+
validator: v => ['sm', 'lg', null].includes(v)
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
data() {
|
|
135
|
+
return {
|
|
136
|
+
localValue: this.value
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
watch: {
|
|
140
|
+
value(newVal) {
|
|
141
|
+
this.localValue = newVal
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
localValue() {
|
|
145
|
+
this.$emit('input', this.localValue)
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
computed: {
|
|
149
|
+
computedID() {
|
|
150
|
+
return this.id || `dr-select-${guid()}`
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
computedState() {
|
|
154
|
+
if (this.state === true || this.state === 'valid') {
|
|
155
|
+
return true
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (this.state === false || this.state === 'invalid') {
|
|
159
|
+
return false
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return null
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
stateClass() {
|
|
166
|
+
if (this.computedState === true) {
|
|
167
|
+
return 'is-valid'
|
|
168
|
+
} else if (this.computedState === false) {
|
|
169
|
+
return 'is-invalid'
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return null
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
computedAriaInvalid() {
|
|
176
|
+
if (this.ariaInvalid === true || this.ariaInvalid === 'true') {
|
|
177
|
+
return 'true';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return this.stateClass == 'is-invalid' ? 'true' : null;
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
formOptions() {
|
|
184
|
+
let options = this.options || {}
|
|
185
|
+
const valueField = this.valueField || 'value'
|
|
186
|
+
const textField = this.textField || 'text'
|
|
187
|
+
const disabledField = this.disabledField || 'disabled'
|
|
188
|
+
|
|
189
|
+
// Parse array options
|
|
190
|
+
if (Array.isArray(options)) {
|
|
191
|
+
return options.map(option => {
|
|
192
|
+
if (typeof option === 'object') {
|
|
193
|
+
return {
|
|
194
|
+
value: option[valueField],
|
|
195
|
+
text: String(option[textField]),
|
|
196
|
+
disabled: option[disabledField] || false
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return { text: String(option), value: option, disabled: false }
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// Parse object options
|
|
204
|
+
} else if (typeof options === 'object') {
|
|
205
|
+
return Object.keys(options).map(key => {
|
|
206
|
+
let option = options[key] || {}
|
|
207
|
+
|
|
208
|
+
if (typeof option === 'object') {
|
|
209
|
+
const value = option[valueField]
|
|
210
|
+
const text = option[textField]
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
text: typeof text === 'undefined' ? key : String(text),
|
|
214
|
+
value: typeof value === 'undefined' ? key : value,
|
|
215
|
+
disabled: option[disabledField] || false
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return { text: String(option), value: key, disabled: false }
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return []
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
methods: {
|
|
227
|
+
handleChange(evt) {
|
|
228
|
+
const target = evt.target;
|
|
229
|
+
const selectedVal = Array.from(target.options)
|
|
230
|
+
.filter(opt => opt.selected)
|
|
231
|
+
.map(opt => '_value' in opt ? opt._value : opt.value)
|
|
232
|
+
|
|
233
|
+
this.localValue = target.multiple ? selectedVal : selectedVal[0];
|
|
234
|
+
this.$emit('change', this.localValue);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
</script>
|
|
239
|
+
|
|
240
|
+
<style scoped>
|
|
241
|
+
.custom-select {
|
|
242
|
+
-webkit-appearance: none;
|
|
243
|
+
-moz-appearance: none;
|
|
244
|
+
appearance: none;
|
|
245
|
+
}
|
|
246
|
+
</style>
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Form Select
|
|
2
|
+
|
|
3
|
+
The `<d-form-select>` component is a wrapper over Bootstrap's [custom select component](https://getbootstrap.com/docs/4.1/components/forms/#select-menu).
|
|
4
|
+
|
|
5
|
+
## Alias
|
|
6
|
+
|
|
7
|
+
The `<d-form-select>` component is also available as `<d-select>`.
|
|
8
|
+
|
|
9
|
+
## Basic Examples
|
|
10
|
+
|
|
11
|
+
The easiest way of using the `<d-form-select>` component would be by using the `options` prop to pass an `Array` or `Object` for the options.
|
|
12
|
+
|
|
13
|
+
:::demo
|
|
14
|
+
```html
|
|
15
|
+
<template>
|
|
16
|
+
<d-form-select v-model="selected" :options="options" />
|
|
17
|
+
Selected: {{ selected }}
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script>
|
|
21
|
+
export default {
|
|
22
|
+
data() {
|
|
23
|
+
return {
|
|
24
|
+
selected: null,
|
|
25
|
+
options: [
|
|
26
|
+
{ value: null, text: 'Please select an option' },
|
|
27
|
+
{ value: 'first', text: 'This is the first option' },
|
|
28
|
+
{ value: 'second', text: 'This is the second option' },
|
|
29
|
+
{ value: 'disabled', text: 'This one is disabled', disabled: true }
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<!-- select-1.vue -->
|
|
37
|
+
```
|
|
38
|
+
:::
|
|
39
|
+
|
|
40
|
+
## Sizing
|
|
41
|
+
|
|
42
|
+
You can control the form-control's size using the `size` prop which accepts `sm` for small or `lg` for large.
|
|
43
|
+
|
|
44
|
+
## Manual Options
|
|
45
|
+
|
|
46
|
+
You can also define your options manually:
|
|
47
|
+
|
|
48
|
+
:::demo
|
|
49
|
+
```html
|
|
50
|
+
<template>
|
|
51
|
+
<div>
|
|
52
|
+
<d-form-select v-model="selected" class="mb-3">
|
|
53
|
+
<option :value="null">Select an option</option>
|
|
54
|
+
<option value="pizza">🍕Pizza</option>
|
|
55
|
+
<option value="pasta" disabled>🍝 Pasta (disabled)</option>
|
|
56
|
+
<optgroup label="Breakfast">
|
|
57
|
+
<option value="eggs">🍳 Eggs</option>
|
|
58
|
+
<option value="bacon">🥓 Bacon</option>
|
|
59
|
+
<option value="tea">🍵 Tea</option>
|
|
60
|
+
</optgroup>
|
|
61
|
+
</d-form-select>
|
|
62
|
+
<div>Selected: {{ selected }}</div>
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<script>
|
|
67
|
+
export default {
|
|
68
|
+
data () {
|
|
69
|
+
return {
|
|
70
|
+
selected: null
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<!-- select-2.vue -->
|
|
77
|
+
```
|
|
78
|
+
:::
|
|
79
|
+
|
|
80
|
+
## Mixed Options
|
|
81
|
+
|
|
82
|
+
You can also mix both using the `options` prop and usin manual options.
|
|
83
|
+
|
|
84
|
+
:::demo
|
|
85
|
+
```html
|
|
86
|
+
<template>
|
|
87
|
+
<div>
|
|
88
|
+
<d-form-select v-model="selected" :options="options" class="mb-3">
|
|
89
|
+
<optgroup label="Breakfast">
|
|
90
|
+
<option value="eggs">🍳 Eggs</option>
|
|
91
|
+
<option value="bacon">🥓 Bacon</option>
|
|
92
|
+
</optgroup>
|
|
93
|
+
</d-form-select>
|
|
94
|
+
<div>Selected: {{ selected }}</div>
|
|
95
|
+
</div>
|
|
96
|
+
</template>
|
|
97
|
+
|
|
98
|
+
<script>
|
|
99
|
+
export default {
|
|
100
|
+
data () {
|
|
101
|
+
return {
|
|
102
|
+
selected: null,
|
|
103
|
+
options: [
|
|
104
|
+
{ value: null, text: 'Select an option' },
|
|
105
|
+
{ value: 'pizza', text: '🍕 Pizza' },
|
|
106
|
+
{ value: 'pasta', text: '🍝 Pasta', disabled: true },
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
</script>
|
|
112
|
+
|
|
113
|
+
<!-- select-3.vue -->
|
|
114
|
+
```
|
|
115
|
+
:::
|
|
116
|
+
|
|
117
|
+
## Select Sizing
|
|
118
|
+
|
|
119
|
+
Using the `select-size` prop you can switch the custom select into a select list box. The prop accepts a number larger than 1 to control how many options are visible.
|
|
120
|
+
|
|
121
|
+
:::demo
|
|
122
|
+
```html
|
|
123
|
+
<template>
|
|
124
|
+
<d-form-select v-model="selected" :options="options" :select-size="2" />
|
|
125
|
+
Selected: {{ selected }}
|
|
126
|
+
</template>
|
|
127
|
+
|
|
128
|
+
<script>
|
|
129
|
+
export default {
|
|
130
|
+
data() {
|
|
131
|
+
return {
|
|
132
|
+
selected: null,
|
|
133
|
+
options: [
|
|
134
|
+
{ value: null, text: 'Please select an option' },
|
|
135
|
+
{ value: 'first', text: 'This is the first option' },
|
|
136
|
+
{ value: 'second', text: 'This is the second option' },
|
|
137
|
+
{ value: 'disabled', text: 'This one is disabled', disabled: true }
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
</script>
|
|
143
|
+
|
|
144
|
+
<!-- select-4.vue -->
|
|
145
|
+
```
|
|
146
|
+
:::
|
|
147
|
+
|
|
148
|
+
## Multiple Selections
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
Using the `multiple` prop you can allow users to select multiple values from the `<d-form-select>` component.
|
|
152
|
+
|
|
153
|
+
> Note: Using the `multiple` mode requires an `Array` reference for your `v-model`.
|
|
154
|
+
|
|
155
|
+
:::demo
|
|
156
|
+
```html
|
|
157
|
+
<template>
|
|
158
|
+
<d-form-select multiple :select-size="4" v-model="selected" :options="options" />
|
|
159
|
+
Selected: {{ selected }}
|
|
160
|
+
</template>
|
|
161
|
+
|
|
162
|
+
<script>
|
|
163
|
+
export default {
|
|
164
|
+
data() {
|
|
165
|
+
return {
|
|
166
|
+
selected: [],
|
|
167
|
+
options: [
|
|
168
|
+
{ value: 'first', text: 'This is the first option' },
|
|
169
|
+
{ value: 'second', text: 'This is the second option' },
|
|
170
|
+
{ value: 'third', text: 'This is the third option' },
|
|
171
|
+
{ value: 'fourth', text: 'This is the fourth option' }
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
</script>
|
|
177
|
+
|
|
178
|
+
<!-- select-5.vue -->
|
|
179
|
+
```
|
|
180
|
+
:::
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { registerComponents, vueUse } from './../../utils'
|
|
2
|
+
|
|
3
|
+
import dFormSelect from './FormSelect.vue'
|
|
4
|
+
|
|
5
|
+
const components = {
|
|
6
|
+
dFormSelect,
|
|
7
|
+
dSelect: dFormSelect
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const VuePlugin = {
|
|
11
|
+
install (Vue) {
|
|
12
|
+
registerComponents(Vue, components)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
vueUse(VuePlugin)
|
|
17
|
+
|
|
18
|
+
export default VuePlugin
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<textarea
|
|
3
|
+
ref="input"
|
|
4
|
+
:class="[
|
|
5
|
+
plaintext ? 'form-control-plaintext' : 'form-control',
|
|
6
|
+
plaintext ? 'w-100' : '',
|
|
7
|
+
size ? `form-control-${this.size}` : null,
|
|
8
|
+
stateClass
|
|
9
|
+
]"
|
|
10
|
+
:style="computedStyle"
|
|
11
|
+
:name="name"
|
|
12
|
+
:id="computedID"
|
|
13
|
+
:disabled="disabled"
|
|
14
|
+
:required="required"
|
|
15
|
+
:placeholder="placeholder"
|
|
16
|
+
:autocomplete="autocomplete"
|
|
17
|
+
:readonly="readonly || plaintext"
|
|
18
|
+
:rows="rows"
|
|
19
|
+
:wrap="wrap"
|
|
20
|
+
:aria-required="required ? 'true' : null"
|
|
21
|
+
:aria-invalid="computedAriaInvalid"
|
|
22
|
+
@input="handleInput"
|
|
23
|
+
></textarea>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script>
|
|
27
|
+
import { guid, getComputedStyles, isVisible } from "../../utils";
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
name: "d-form-textarea",
|
|
31
|
+
data() {
|
|
32
|
+
return {
|
|
33
|
+
localValue: this.value
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
props: {
|
|
37
|
+
/**
|
|
38
|
+
* The element name.
|
|
39
|
+
*/
|
|
40
|
+
name: {
|
|
41
|
+
type: String,
|
|
42
|
+
default: null
|
|
43
|
+
},
|
|
44
|
+
/**
|
|
45
|
+
* The element ID.
|
|
46
|
+
*/
|
|
47
|
+
id: {
|
|
48
|
+
type: String,
|
|
49
|
+
default: null
|
|
50
|
+
},
|
|
51
|
+
/**
|
|
52
|
+
* The disabled state.
|
|
53
|
+
*/
|
|
54
|
+
disabled: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
required: false
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* The required state.
|
|
60
|
+
*/
|
|
61
|
+
required: {
|
|
62
|
+
type: Boolean,
|
|
63
|
+
required: false
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* The validity state.
|
|
67
|
+
*/
|
|
68
|
+
state: {
|
|
69
|
+
type: [Boolean, String],
|
|
70
|
+
default: null,
|
|
71
|
+
validator: v => ["valid", "invalid", true, false, null].includes(v)
|
|
72
|
+
},
|
|
73
|
+
/**
|
|
74
|
+
* The element's size.
|
|
75
|
+
*/
|
|
76
|
+
size: {
|
|
77
|
+
type: String,
|
|
78
|
+
default: null,
|
|
79
|
+
validator: v => ["sm", "lg", null].includes(v)
|
|
80
|
+
},
|
|
81
|
+
/**
|
|
82
|
+
* The placeholder value.
|
|
83
|
+
*/
|
|
84
|
+
placeholder: {
|
|
85
|
+
type: String,
|
|
86
|
+
default: null
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* The autocomplete status.
|
|
90
|
+
*/
|
|
91
|
+
autocomplete: {
|
|
92
|
+
type: String,
|
|
93
|
+
default: null
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* Whether the textarea should be read-only, or not.
|
|
97
|
+
*/
|
|
98
|
+
readonly: {
|
|
99
|
+
type: Boolean,
|
|
100
|
+
default: false
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* Whether the textarea should be plain-text, or not.
|
|
104
|
+
*/
|
|
105
|
+
plaintext: {
|
|
106
|
+
type: Boolean,
|
|
107
|
+
default: false
|
|
108
|
+
},
|
|
109
|
+
/**
|
|
110
|
+
* The number of text rows.
|
|
111
|
+
*/
|
|
112
|
+
rows: {
|
|
113
|
+
type: [Number, String],
|
|
114
|
+
default: null
|
|
115
|
+
},
|
|
116
|
+
/**
|
|
117
|
+
* The textarea wrap style.
|
|
118
|
+
*/
|
|
119
|
+
wrap: {
|
|
120
|
+
type: String,
|
|
121
|
+
default: "soft",
|
|
122
|
+
validator: v => ["soft", "hard", "off"].includes(v)
|
|
123
|
+
},
|
|
124
|
+
/**
|
|
125
|
+
* Whether resizing should be disabled, or not.
|
|
126
|
+
*/
|
|
127
|
+
noResize: {
|
|
128
|
+
type: Boolean,
|
|
129
|
+
default: false
|
|
130
|
+
},
|
|
131
|
+
/**
|
|
132
|
+
* The maximum number of rows allowed.
|
|
133
|
+
*/
|
|
134
|
+
maxRows: {
|
|
135
|
+
type: [Number, String],
|
|
136
|
+
default: null
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
mounted() {
|
|
140
|
+
this.el = this.$el;
|
|
141
|
+
},
|
|
142
|
+
computed: {
|
|
143
|
+
computedID() {
|
|
144
|
+
return this.id || `dr-textarea-${guid()}`;
|
|
145
|
+
},
|
|
146
|
+
computedStyle() {
|
|
147
|
+
return {
|
|
148
|
+
width: this.plaintext ? "100%" : null,
|
|
149
|
+
height: this.computedHeight,
|
|
150
|
+
resize: this.noResize ? "none" : null
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
computedMinRows() {
|
|
154
|
+
return Math.max(parseInt(this.rows, 10) || 2, 2);
|
|
155
|
+
},
|
|
156
|
+
computedMaxRows() {
|
|
157
|
+
return Math.max(this.computedMinRows, parseInt(this.maxRows, 10) || 0);
|
|
158
|
+
},
|
|
159
|
+
computedHeight() {
|
|
160
|
+
if (this.localValue === null || !isVisible(this.el)) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const _height = this.el.style.height;
|
|
165
|
+
|
|
166
|
+
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
|
167
|
+
this.el.style.height = "inherit";
|
|
168
|
+
|
|
169
|
+
const computed = getComputedStyles(this.el);
|
|
170
|
+
const minHeight =
|
|
171
|
+
parseInt(computed.height, 10) || lineHeight * this.computedMinRows;
|
|
172
|
+
|
|
173
|
+
const lineHeight = parseFloat(computed.lineHeight);
|
|
174
|
+
const offset =
|
|
175
|
+
parseInt(computed.borderTopWidth, 10) +
|
|
176
|
+
parseInt(computed.paddingTop, 10) +
|
|
177
|
+
parseInt(computed.paddingBottom, 10) +
|
|
178
|
+
parseInt(computed.borderBottomWidth, 10);
|
|
179
|
+
|
|
180
|
+
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
|
181
|
+
this.el.style.height = _height;
|
|
182
|
+
|
|
183
|
+
const rows = Math.min(
|
|
184
|
+
Math.max(
|
|
185
|
+
(this.el.scrollHeight - offset) / lineHeight,
|
|
186
|
+
this.computedMinRows
|
|
187
|
+
),
|
|
188
|
+
this.computedMaxRows - 1
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
if (!this.localValue.trim()) {
|
|
192
|
+
return `${minHeight}px`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return `${Math.max(Math.ceil(rows * lineHeight + offset), minHeight)}px`;
|
|
196
|
+
},
|
|
197
|
+
computedAriaInvalid() {
|
|
198
|
+
// eslint-disable-next-line
|
|
199
|
+
if (!Boolean(this.ariaInvalid) || this.ariaInvalid === "false") {
|
|
200
|
+
return this.computedState === false ? "true" : null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (this.ariaInvalid === true) {
|
|
204
|
+
return "true";
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return this.ariaInvalid;
|
|
208
|
+
},
|
|
209
|
+
computedState() {
|
|
210
|
+
if (this.state === true || this.state === "valid") {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (this.state === false || this.state === "invalid") {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return null;
|
|
219
|
+
},
|
|
220
|
+
stateClass() {
|
|
221
|
+
if (this.computedState === true) {
|
|
222
|
+
return "is-valid";
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (this.computedState === false) {
|
|
226
|
+
return "is-invalid";
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
watch: {
|
|
233
|
+
value(newVal, oldVal) {
|
|
234
|
+
if (newVal !== oldVal) {
|
|
235
|
+
this.localValue = newVal;
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
localValue(newVal, oldVal) {
|
|
239
|
+
if (newVal !== oldVal) {
|
|
240
|
+
this.$emit("input", newVal);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
methods: {
|
|
245
|
+
handleInput(e) {
|
|
246
|
+
this.localValue = e.target.value;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
</script>
|