From 9d11c29c3b4bd8fe06ad6a4bce2f3d9cd6531ffe Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Fri, 22 Oct 2021 06:23:23 +0900
Subject: [PATCH] :art:

---
 src/client/components/form/input.vue    |  2 +-
 src/client/components/form/select.vue   | 65 ++++++++++++++++++++++---
 src/client/components/form/textarea.vue |  2 +-
 src/client/components/ui/menu.vue       |  5 ++
 src/client/components/ui/popup-menu.vue |  6 ++-
 src/client/os.ts                        |  7 ++-
 6 files changed, 75 insertions(+), 12 deletions(-)

diff --git a/src/client/components/form/input.vue b/src/client/components/form/input.vue
index d7b6f77519..591eda9ed5 100644
--- a/src/client/components/form/input.vue
+++ b/src/client/components/form/input.vue
@@ -33,7 +33,7 @@
 
 <script lang="ts">
 import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
-import MkButton from '../ui/button.vue';
+import MkButton from '@client/components/ui/button.vue';
 import { debounce } from 'throttle-debounce';
 
 export default defineComponent({
diff --git a/src/client/components/form/select.vue b/src/client/components/form/select.vue
index 257e2cc990..30ccfd312b 100644
--- a/src/client/components/form/select.vue
+++ b/src/client/components/form/select.vue
@@ -1,9 +1,9 @@
 <template>
 <div class="vblkjoeq">
 	<div class="label" @click="focus"><slot name="label"></slot></div>
-	<div class="input" :class="{ inline, disabled, focused }">
+	<div class="input" :class="{ inline, disabled, focused }" @click.prevent="onClick" ref="container">
 		<div class="prefix" ref="prefixEl"><slot name="prefix"></slot></div>
-		<select ref="inputEl"
+		<select class="select" ref="inputEl"
 			v-model="v"
 			:disabled="disabled"
 			:required="required"
@@ -25,7 +25,8 @@
 
 <script lang="ts">
 import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
-import MkButton from '../ui/button.vue';
+import MkButton from '@client/components/ui/button.vue';
+import * as os from '@client/os';
 
 export default defineComponent({
 	components: {
@@ -81,6 +82,7 @@ export default defineComponent({
 		const inputEl = ref(null);
 		const prefixEl = ref(null);
 		const suffixEl = ref(null);
+		const container = ref(null);
 
 		const focus = () => inputEl.value.focus();
 		const onInput = (ev) => {
@@ -132,6 +134,47 @@ export default defineComponent({
 			});
 		});
 
+		const onClick = (ev: MouseEvent) => {
+			focused.value = true;
+
+			const menu = [];
+			let options = context.slots.default();
+
+			for (const optionOrOptgroup of options) {
+				if (optionOrOptgroup.type === 'optgroup') {
+					const optgroup = optionOrOptgroup;
+					menu.push({
+						type: 'label',
+						text: optgroup.props.label,
+					});
+					for (const option of optgroup.children) {
+						menu.push({
+							text: option.children,
+							active: v.value === option.props.value,
+							action: () => {
+								v.value = option.props.value;
+							},
+						});
+					}
+				} else {
+					const option = optionOrOptgroup;
+					menu.push({
+						text: option.children,
+						active: v.value === option.props.value,
+						action: () => {
+							v.value = option.props.value;
+						},
+					});
+				}
+			}
+
+			os.popupMenu(menu, container.value, {
+				width: container.value.offsetWidth,
+			}).then(() => {
+				focused.value = false;
+			});
+		};
+
 		return {
 			v,
 			focused,
@@ -141,8 +184,10 @@ export default defineComponent({
 			inputEl,
 			prefixEl,
 			suffixEl,
+			container,
 			focus,
 			onInput,
+			onClick,
 			updated,
 		};
 	},
@@ -174,8 +219,15 @@ export default defineComponent({
 	> .input {
 		$height: 42px;
 		position: relative;
+		cursor: pointer;
 
-		> select {
+		&:hover {
+			> .select {
+				border-color: var(--inputBorderHover);
+			}
+		}
+
+		> .select {
 			appearance: none;
 			-webkit-appearance: none;
 			display: block;
@@ -195,10 +247,7 @@ export default defineComponent({
 			box-sizing: border-box;
 			cursor: pointer;
 			transition: border-color 0.1s ease-out;
-
-			&:hover {
-				border-color: var(--inputBorderHover);
-			}
+			pointer-events: none;
 		}
 
 		> .prefix,
diff --git a/src/client/components/form/textarea.vue b/src/client/components/form/textarea.vue
index 50be69f930..048e9032df 100644
--- a/src/client/components/form/textarea.vue
+++ b/src/client/components/form/textarea.vue
@@ -26,7 +26,7 @@
 
 <script lang="ts">
 import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
-import MkButton from '../ui/button.vue';
+import MkButton from '@client/components/ui/button.vue';
 import { debounce } from 'throttle-debounce';
 
 export default defineComponent({
diff --git a/src/client/components/ui/menu.vue b/src/client/components/ui/menu.vue
index da24d90170..aaef527f1a 100644
--- a/src/client/components/ui/menu.vue
+++ b/src/client/components/ui/menu.vue
@@ -1,5 +1,6 @@
 <template>
 <div class="rrevdjwt" :class="{ center: align === 'center' }"
+	:style="{ width: width ? width + 'px' : null }"
 	ref="items"
 	@contextmenu.self="e => e.preventDefault()"
 	v-hotkey="keymap"
@@ -59,6 +60,10 @@ export default defineComponent({
 			type: String,
 			requried: false
 		},
+		width: {
+			type: Number,
+			required: false
+		},
 	},
 	emits: ['close'],
 	data() {
diff --git a/src/client/components/ui/popup-menu.vue b/src/client/components/ui/popup-menu.vue
index 23f7c89f3b..3ff4c658b1 100644
--- a/src/client/components/ui/popup-menu.vue
+++ b/src/client/components/ui/popup-menu.vue
@@ -1,6 +1,6 @@
 <template>
 <MkPopup ref="popup" :src="src" @closed="$emit('closed')">
-	<MkMenu :items="items" :align="align" @close="$refs.popup.close()" class="_popup _shadow"/>
+	<MkMenu :items="items" :align="align" :width="width" @close="$refs.popup.close()" class="_popup _shadow"/>
 </MkPopup>
 </template>
 
@@ -24,6 +24,10 @@ export default defineComponent({
 			type: String,
 			required: false
 		},
+		width: {
+			type: Number,
+			required: false
+		},
 		viaKeyboard: {
 			type: Boolean,
 			required: false
diff --git a/src/client/os.ts b/src/client/os.ts
index 7ae774dd92..743d2d131f 100644
--- a/src/client/os.ts
+++ b/src/client/os.ts
@@ -372,12 +372,17 @@ export async function openEmojiPicker(src?: HTMLElement, opts, initialTextarea:
 	});
 }
 
-export function popupMenu(items: any[] | Ref<any[]>, src?: HTMLElement, options?: { align?: string; viaKeyboard?: boolean }) {
+export function popupMenu(items: any[] | Ref<any[]>, src?: HTMLElement, options?: {
+	align?: string;
+	width?: number;
+	viaKeyboard?: boolean;
+}) {
 	return new Promise((resolve, reject) => {
 		let dispose;
 		popup(import('@client/components/ui/popup-menu.vue'), {
 			items,
 			src,
+			width: options?.width,
 			align: options?.align,
 			viaKeyboard: options?.viaKeyboard
 		}, {