diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2024-10-21 19:14:02 +0900 |
|---|---|---|
| committer | syuilo <4439005+syuilo@users.noreply.github.com> | 2024-10-21 19:14:02 +0900 |
| commit | c4f1ca2fd9cb1c9b6035f4efb3fa9e46f7be9d64 (patch) | |
| tree | e9ab297a219d02e6115dd77ffe118a833b62f5f2 /packages/frontend | |
| parent | docs: ActivityPub層の変更を含む場合にやるべきことを明文化... (diff) | |
| download | sharkey-c4f1ca2fd9cb1c9b6035f4efb3fa9e46f7be9d64.tar.gz sharkey-c4f1ca2fd9cb1c9b6035f4efb3fa9e46f7be9d64.tar.bz2 sharkey-c4f1ca2fd9cb1c9b6035f4efb3fa9e46f7be9d64.zip | |
fix(frontend): MkSelectでmodelValueが更新されない限り値を更新しないように
Diffstat (limited to 'packages/frontend')
| -rw-r--r-- | packages/frontend/src/components/MkSelect.vue | 80 |
1 files changed, 38 insertions, 42 deletions
diff --git a/packages/frontend/src/components/MkSelect.vue b/packages/frontend/src/components/MkSelect.vue index a2ec384ac5..8bd02000e6 100644 --- a/packages/frontend/src/components/MkSelect.vue +++ b/packages/frontend/src/components/MkSelect.vue @@ -16,9 +16,8 @@ SPDX-License-Identifier: AGPL-3.0-only @keydown.space.enter="show" > <div ref="prefixEl" :class="$style.prefix"><slot name="prefix"></slot></div> - <select + <div ref="inputEl" - v-model="v" v-adaptive-border tabindex="-1" :class="$style.inputCore" @@ -26,27 +25,25 @@ SPDX-License-Identifier: AGPL-3.0-only :required="required" :readonly="readonly" :placeholder="placeholder" - @input="onInput" @mousedown.prevent="() => {}" @keydown.prevent="() => {}" > - <slot></slot> - </select> + <div style="pointer-events: none;">{{ currentValueText ?? '' }}</div> + <div style="display: none;"> + <slot></slot> + </div> + </div> <div ref="suffixEl" :class="$style.suffix"><i class="ti ti-chevron-down" :class="[$style.chevron, { [$style.chevronOpening]: opening }]"></i></div> </div> <div :class="$style.caption"><slot name="caption"></slot></div> - - <MkButton v-if="manualSave && changed" primary :class="$style.save" @click="updated"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> </div> </template> <script lang="ts" setup> import { onMounted, nextTick, ref, watch, computed, toRefs, VNode, useSlots, VNodeChild } from 'vue'; -import MkButton from '@/components/MkButton.vue'; -import * as os from '@/os.js'; import { useInterval } from '@@/js/use-interval.js'; -import { i18n } from '@/i18n.js'; import type { MenuItem } from '@/types/menu.js'; +import * as os from '@/os.js'; const props = defineProps<{ modelValue: string | null; @@ -56,25 +53,20 @@ const props = defineProps<{ placeholder?: string; autofocus?: boolean; inline?: boolean; - manualSave?: boolean; small?: boolean; large?: boolean; }>(); const emit = defineEmits<{ - (ev: 'changeByUser', value: string | null): void; - (ev: 'update:modelValue', value: string | null): void; + (ev: 'update:modelValue', value: string | number | null): void; }>(); const slots = useSlots(); const { modelValue, autofocus } = toRefs(props); -const v = ref(modelValue.value); const focused = ref(false); const opening = ref(false); -const changed = ref(false); -const invalid = ref(false); -const filled = computed(() => v.value !== '' && v.value != null); +const currentValueText = ref<string | null>(null); const inputEl = ref<HTMLObjectElement | null>(null); const prefixEl = ref<HTMLElement | null>(null); const suffixEl = ref<HTMLElement | null>(null); @@ -85,26 +77,6 @@ const height = 36; const focus = () => container.value?.focus(); -const onInput = (ev) => { - changed.value = true; -}; - -const updated = () => { - changed.value = false; - emit('update:modelValue', v.value); -}; - -watch(modelValue, newValue => { - v.value = newValue; -}); - -watch(v, () => { - if (!props.manualSave) { - updated(); - } - - invalid.value = inputEl.value?.validity.badInput ?? true; -}); // このコンポーネントが作成された時、非表示状態である場合がある // 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する @@ -134,6 +106,31 @@ onMounted(() => { }); }); +watch(modelValue, () => { + const scanOptions = (options: VNodeChild[]) => { + for (const vnode of options) { + if (typeof vnode !== 'object' || vnode === null || Array.isArray(vnode)) continue; + if (vnode.type === 'optgroup') { + const optgroup = vnode; + if (Array.isArray(optgroup.children)) scanOptions(optgroup.children); + } else if (Array.isArray(vnode.children)) { // 何故かフラグメントになってくることがある + const fragment = vnode; + if (Array.isArray(fragment.children)) scanOptions(fragment.children); + } else if (vnode.props == null) { // v-if で条件が false のときにこうなる + // nop? + } else { + const option = vnode; + if (option.props?.value === modelValue.value) { + currentValueText.value = option.children as string; + break; + } + } + } + }; + + scanOptions(slots.default!()); +}, { immediate: true }); + function show() { if (opening.value) return; focus(); @@ -146,11 +143,9 @@ function show() { const pushOption = (option: VNode) => { menu.push({ text: option.children as string, - active: computed(() => v.value === option.props?.value), + active: computed(() => modelValue.value === option.props?.value), action: () => { - v.value = option.props?.value; - changed.value = true; - emit('changeByUser', v.value); + emit('update:modelValue', option.props?.value); }, }); }; @@ -248,7 +243,8 @@ function show() { .inputCore { appearance: none; -webkit-appearance: none; - display: block; + display: flex; + align-items: center; height: v-bind("height + 'px'"); width: 100%; margin: 0; |