@vue-interface/select-field 2.0.2 → 2.0.4

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 (2) hide show
  1. package/package.json +4 -3
  2. package/src/SelectField.vue +160 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue-interface/select-field",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "A Vue select field component.",
5
5
  "type": "module",
6
6
  "main": "./dist/select-field.umd.js",
@@ -35,6 +35,7 @@
35
35
  "homepage": "https://vue-interface.github.io/packages/select-field",
36
36
  "readme": "README.md",
37
37
  "files": [
38
+ "src",
38
39
  "dist",
39
40
  "index.css",
40
41
  "README.md",
@@ -42,8 +43,8 @@
42
43
  ],
43
44
  "peerDependencies": {
44
45
  "vue": "^3.3.4",
45
- "@vue-interface/activity-indicator": "3.0.2",
46
- "@vue-interface/form-control": "2.0.2"
46
+ "@vue-interface/activity-indicator": "3.0.3",
47
+ "@vue-interface/form-control": "2.0.4"
47
48
  },
48
49
  "scripts": {
49
50
  "dev": "vite",
@@ -0,0 +1,160 @@
1
+ <script setup lang="ts" generic="ModelValue, Value">
2
+ import { ActivityIndicator } from '@vue-interface/activity-indicator';
3
+ import type { FormControlEvents, FormControlProps, FormControlSlots } from '@vue-interface/form-control';
4
+ import { FormControlErrors, FormControlFeedback, useFormControl } from '@vue-interface/form-control';
5
+ import { InputHTMLAttributes, onMounted, ref, SelectHTMLAttributes, useSlots } from 'vue';
6
+
7
+ const props = withDefaults(defineProps<SelectFieldProps<ModelValue,Value>>(), {
8
+ formControlClass: 'form-select',
9
+ labelClass: 'form-label'
10
+ });
11
+
12
+ defineOptions({
13
+ inheritAttrs: false
14
+ });
15
+
16
+ const model = defineModel<ModelValue>();
17
+
18
+ defineSlots<FormControlSlots<SelectFieldControlSizePrefix,ModelValue> & {
19
+ default: () => unknown
20
+ }>();
21
+
22
+ const emit = defineEmits<FormControlEvents<ModelValue>>();
23
+
24
+ const {
25
+ controlAttributes,
26
+ formGroupClasses,
27
+ listeners,
28
+ } = useFormControl<InputHTMLAttributes, SelectFieldControlSizePrefix, ModelValue, Value>({ model, props, emit });
29
+
30
+ const field = ref<HTMLSelectElement>();
31
+
32
+ function onMousedownLabel(e: MouseEvent) {
33
+ listeners.onClick(e);
34
+
35
+ field.value?.focus();
36
+ }
37
+
38
+ // Check the option slots for selected options. If the field has hardcoded
39
+ // selected options, this will ensure the value of the field is always set to
40
+ // the property. This will ensure the model is updated to the selected value.
41
+ onMounted(() => {
42
+ const slot = useSlots().default;
43
+
44
+ if(!slot) {
45
+ return;
46
+ }
47
+
48
+ for(const child of slot()) {
49
+ if(!child.props) {
50
+ return;
51
+ }
52
+
53
+ if('selected' in child.props && (child.props.value ?? child.children)) {
54
+ model.value = child.props.value ?? child.children;
55
+ }
56
+ }
57
+ });
58
+ </script>
59
+
60
+ <script lang="ts">
61
+ export type SelectFieldControlSizePrefix = 'form-select';
62
+
63
+ export type SelectFieldProps<ModelValue, Value> = FormControlProps<
64
+ SelectHTMLAttributes,
65
+ SelectFieldControlSizePrefix,
66
+ ModelValue,
67
+ Value
68
+ >;
69
+ </script>
70
+
71
+ <template>
72
+ <div
73
+ class="select-field"
74
+ :class="formGroupClasses">
75
+ <slot name="label">
76
+ <label
77
+ v-if="label"
78
+ ref="label"
79
+ :for="controlAttributes.id"
80
+ :class="labelClass"
81
+ @mousedown="onMousedownLabel">
82
+ {{ label }}
83
+ </label>
84
+ </slot>
85
+
86
+ <div class="form-control-inner">
87
+ <slot
88
+ name="control"
89
+ v-bind="{ controlAttributes, listeners }">
90
+ <div
91
+ v-if="$slots.icon"
92
+ class="form-control-inner-icon"
93
+ @click="field?.focus()">
94
+ <slot name="icon" />
95
+ </div>
96
+ <select
97
+ ref="field"
98
+ v-model="model"
99
+ v-bind="{...controlAttributes, ...listeners}">
100
+ <slot />
101
+ </select>
102
+ </slot>
103
+
104
+ <div class="form-control-activity-indicator">
105
+ <slot name="activity">
106
+ <Transition name="select-field-fade">
107
+ <ActivityIndicator
108
+ v-if="activity && indicator"
109
+ key="activity"
110
+ ref="activity"
111
+ :type="indicator"
112
+ :size="indicatorSize" />
113
+ </Transition>
114
+ </slot>
115
+ </div>
116
+ </div>
117
+
118
+ <slot
119
+ name="errors"
120
+ v-bind="{ error, errors, id, name }">
121
+ <FormControlErrors
122
+ v-if="!!(error || errors)"
123
+ :id="id && String(id)"
124
+ v-slot="{ error }"
125
+ :name="name && String(name)"
126
+ :error="error"
127
+ :errors="errors">
128
+ <div
129
+ invalid
130
+ class="invalid-feedback">
131
+ {{ error }}<br>
132
+ </div>
133
+ </FormControlErrors>
134
+ </slot>
135
+
136
+ <slot
137
+ name="feedback"
138
+ v-bind="{ feedback }">
139
+ <FormControlFeedback
140
+ v-slot="{ feedback }"
141
+ :feedback="feedback">
142
+ <div
143
+ valid
144
+ class="valid-feedback">
145
+ {{ feedback }}
146
+ </div>
147
+ </FormControlFeedback>
148
+ </slot>
149
+
150
+ <slot
151
+ name="help"
152
+ v-bind="{ helpText }">
153
+ <small
154
+ v-if="helpText"
155
+ ref="help">
156
+ {{ helpText }}
157
+ </small>
158
+ </slot>
159
+ </div>
160
+ </template>