|
6 | 6 | v-model="localValue"
|
7 | 7 | :class="classes"
|
8 | 8 | :name="name"
|
9 |
| - :form="form || null" |
10 |
| - :multiple="multiple || null" |
| 9 | + :form="form || undefined" |
| 10 | + :multiple="multiple || undefined" |
11 | 11 | :size="computedSelectSize"
|
12 | 12 | :disabled="disabled"
|
13 | 13 | :required="required"
|
14 |
| - :aria-required="required ? 'true' : null" |
| 14 | + :aria-required="required ? true : undefined" |
15 | 15 | :aria-invalid="computedAriaInvalid"
|
16 | 16 | >
|
17 | 17 | <slot name="first" />
|
|
36 | 36 | </select>
|
37 | 37 | </template>
|
38 | 38 |
|
39 |
| -<script lang="ts"> |
40 |
| -import {computed, defineComponent, nextTick, onActivated, onMounted, PropType, ref} from 'vue' |
| 39 | +<script setup lang="ts"> |
| 40 | +// import type {BFormSelectEmits, BFormSelectProps} from '@/types/components' |
| 41 | +import type {Size} from '@/types' |
| 42 | +import {computed, nextTick, onActivated, onMounted, ref} from 'vue' |
41 | 43 | import BFormSelectOption from './BFormSelectOption.vue'
|
42 | 44 | import BFormSelectOptionGroup from './BFormSelectOptionGroup.vue'
|
43 |
| -import useId from '../../composables/useId' |
44 |
| -import {Size} from '../../types' |
45 |
| -import {normalizeOptions} from '../../composables/useFormSelect' |
| 45 | +import useId from '@/composables/useId' |
| 46 | +import {normalizeOptions} from '@/composables/useFormSelect' |
46 | 47 |
|
47 |
| -export default defineComponent({ |
48 |
| - name: 'BFormSelect', |
49 |
| - components: {BFormSelectOption, BFormSelectOptionGroup}, |
50 |
| - props: { |
51 |
| - ariaInvalid: { |
52 |
| - type: [Boolean, String] as PropType<boolean | 'false' | 'true' | 'grammar' | 'spelling'>, |
53 |
| - default: false, |
54 |
| - }, |
55 |
| - autofocus: {type: Boolean, default: false}, |
56 |
| - disabled: {type: Boolean, default: false}, |
57 |
| - disabledField: {type: String, default: 'disabled'}, |
58 |
| - form: {type: String, required: false}, |
59 |
| - htmlField: {type: String, default: 'html'}, |
60 |
| - id: {type: String, required: false}, |
61 |
| - labelField: {type: String, default: 'label'}, |
62 |
| - multiple: {type: Boolean, default: false}, |
63 |
| - name: {type: String, required: false}, |
64 |
| - options: {type: [Array, Object], default: () => []}, |
65 |
| - optionsField: {type: String, default: 'options'}, |
66 |
| - plain: {type: Boolean, default: false}, |
67 |
| - required: {type: Boolean, default: false}, |
68 |
| - selectSize: {type: Number, default: 0}, |
69 |
| - size: {type: String as PropType<Size>, required: false}, |
70 |
| - state: { |
71 |
| - type: Boolean as PropType<boolean | null | undefined>, |
72 |
| - default: null, |
73 |
| - }, |
74 |
| - textField: {type: String, default: 'text'}, |
75 |
| - valueField: {type: String, default: 'value'}, |
76 |
| - modelValue: {type: [String, Array, Object, Number], default: ''}, |
77 |
| - }, |
78 |
| - emits: ['update:modelValue', 'change', 'input'], |
79 |
| - setup(props, {emit}) { |
80 |
| - const input = ref<HTMLElement>() |
81 |
| - const computedId = useId(props.id, 'input') |
82 |
| -
|
83 |
| - // lifecycle events |
84 |
| - const handleAutofocus = () => { |
85 |
| - nextTick(() => { |
86 |
| - if (props.autofocus) input.value?.focus() |
87 |
| - }) |
88 |
| - } |
89 |
| - onMounted(handleAutofocus) |
90 |
| - onActivated(handleAutofocus) |
91 |
| - // /lifecycle events |
| 48 | +interface BFormSelectProps { |
| 49 | + ariaInvalid?: boolean | 'grammar' | 'spelling' |
| 50 | + autofocus?: boolean |
| 51 | + disabled?: boolean |
| 52 | + disabledField?: string |
| 53 | + form?: string |
| 54 | + htmlField?: string |
| 55 | + id?: string |
| 56 | + labelField?: string |
| 57 | + multiple?: boolean |
| 58 | + name?: string |
| 59 | + options?: Array<unknown> | Record<string, unknown> |
| 60 | + optionsField?: string |
| 61 | + plain?: boolean |
| 62 | + required?: boolean |
| 63 | + selectSize?: number |
| 64 | + size?: Size |
| 65 | + state?: boolean |
| 66 | + textField?: string |
| 67 | + valueField?: string |
| 68 | + modelValue?: string | Array<unknown> | Record<string, unknown> | number |
| 69 | +} |
92 | 70 |
|
93 |
| - // computed |
94 |
| - const classes = computed(() => ({ |
95 |
| - 'form-control': props.plain, |
96 |
| - [`form-control-${props.size}`]: props.size && props.plain, |
97 |
| - 'form-select': !props.plain, |
98 |
| - [`form-select-${props.size}`]: props.size && !props.plain, |
99 |
| - 'is-valid': props.state === true, |
100 |
| - 'is-invalid': props.state === false, |
101 |
| - })) |
| 71 | +const props = withDefaults(defineProps<BFormSelectProps>(), { |
| 72 | + ariaInvalid: false, |
| 73 | + autofocus: false, |
| 74 | + disabled: false, |
| 75 | + disabledField: 'disabled', |
| 76 | + htmlField: 'html', |
| 77 | + labelField: 'label', |
| 78 | + multiple: false, |
| 79 | + options: () => [], |
| 80 | + optionsField: 'options', |
| 81 | + plain: false, |
| 82 | + required: false, |
| 83 | + selectSize: 0, |
| 84 | + state: undefined, |
| 85 | + textField: 'text', |
| 86 | + valueField: 'value', |
| 87 | + modelValue: '', |
| 88 | +}) |
102 | 89 |
|
103 |
| - const computedSelectSize = computed(() => { |
104 |
| - if (props.selectSize || props.plain) { |
105 |
| - return props.selectSize |
106 |
| - } |
107 |
| - return null |
108 |
| - }) |
| 90 | +interface BFormSelectEmits { |
| 91 | + (e: 'input', value: unknown): void |
| 92 | + (e: 'update:modelValue', value: unknown): void |
| 93 | + (e: 'change', value: unknown): void |
| 94 | +} |
109 | 95 |
|
110 |
| - const computedAriaInvalid = computed(() => { |
111 |
| - if (props.ariaInvalid) { |
112 |
| - return props.ariaInvalid.toString() |
113 |
| - } |
114 |
| - return props.state === false ? 'true' : null |
115 |
| - }) |
| 96 | +const emit = defineEmits<BFormSelectEmits>() |
116 | 97 |
|
117 |
| - const formOptions = computed(() => normalizeOptions(props.options, 'BFormSelect', props)) |
118 |
| - const localValue = computed({ |
119 |
| - get() { |
120 |
| - return props.modelValue |
121 |
| - }, |
122 |
| - set(newValue: any) { |
123 |
| - emit('change', newValue) |
124 |
| - emit('update:modelValue', newValue) |
125 |
| - emit('input', newValue) |
126 |
| - }, |
127 |
| - }) |
| 98 | +const input = ref<HTMLElement>() |
| 99 | +const computedId = useId(props.id, 'input') |
128 | 100 |
|
129 |
| - // /computed |
| 101 | +// lifecycle events |
| 102 | +const handleAutofocus = () => { |
| 103 | + nextTick(() => { |
| 104 | + if (props.autofocus) input.value?.focus() |
| 105 | + }) |
| 106 | +} |
| 107 | +onMounted(handleAutofocus) |
| 108 | +onActivated(handleAutofocus) |
| 109 | +// /lifecycle events |
130 | 110 |
|
131 |
| - // methods |
| 111 | +// computed |
| 112 | +const classes = computed(() => ({ |
| 113 | + 'form-control': props.plain, |
| 114 | + [`form-control-${props.size}`]: props.size && props.plain, |
| 115 | + 'form-select': !props.plain, |
| 116 | + [`form-select-${props.size}`]: props.size && !props.plain, |
| 117 | + 'is-valid': props.state === true, |
| 118 | + 'is-invalid': props.state === false, |
| 119 | +})) |
132 | 120 |
|
133 |
| - const focus = () => { |
134 |
| - if (!props.disabled) input.value?.focus() |
135 |
| - } |
| 121 | +const computedSelectSize = computed<number | undefined>(() => { |
| 122 | + if (props.selectSize || props.plain) { |
| 123 | + return props.selectSize |
| 124 | + } |
| 125 | + return undefined |
| 126 | +}) |
136 | 127 |
|
137 |
| - const blur = () => { |
138 |
| - if (!props.disabled) { |
139 |
| - input.value?.blur() |
140 |
| - } |
| 128 | +const computedAriaInvalid = computed<'grammar' | 'spelling' | boolean | undefined>(() => { |
| 129 | + if (props.state === false) { |
| 130 | + return true |
| 131 | + } |
| 132 | + if (props.state === true) { |
| 133 | + return undefined |
| 134 | + } |
| 135 | + if (typeof props.ariaInvalid === 'boolean') { |
| 136 | + if (props.ariaInvalid === false) { |
| 137 | + return undefined |
141 | 138 | }
|
142 |
| - // /methods |
| 139 | + return props.ariaInvalid |
| 140 | + } |
| 141 | + return props.ariaInvalid |
| 142 | +}) |
143 | 143 |
|
144 |
| - return { |
145 |
| - input, |
146 |
| - computedId, |
147 |
| - computedSelectSize, |
148 |
| - computedAriaInvalid, |
149 |
| - classes, |
150 |
| - formOptions, |
151 |
| - localValue, |
152 |
| - focus, |
153 |
| - blur, |
154 |
| - } |
| 144 | +const formOptions = computed(() => |
| 145 | + normalizeOptions(props.options as Array<any>, 'BFormSelect', props) |
| 146 | +) |
| 147 | +const localValue = computed({ |
| 148 | + get() { |
| 149 | + return props.modelValue |
| 150 | + }, |
| 151 | + set(newValue: any) { |
| 152 | + emit('change', newValue) |
| 153 | + emit('update:modelValue', newValue) |
| 154 | + emit('input', newValue) |
155 | 155 | },
|
156 | 156 | })
|
| 157 | +
|
| 158 | +// /computed |
| 159 | +
|
| 160 | +// methods |
| 161 | +
|
| 162 | +const focus = () => { |
| 163 | + if (!props.disabled) input.value?.focus() |
| 164 | +} |
| 165 | +
|
| 166 | +const blur = () => { |
| 167 | + if (!props.disabled) { |
| 168 | + input.value?.blur() |
| 169 | + } |
| 170 | +} |
| 171 | +// /methods |
157 | 172 | </script>
|
0 commit comments