diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2022-06-28 15:59:49 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2022-06-28 15:59:49 +0900 |
| commit | 270e1212aca2931f8c01d43c187106b988fa2c49 (patch) | |
| tree | c95c503e3279c9771f181441ab086efdbcd92741 /packages/client/src/components/form | |
| parent | refactor(client): use setup syntax (diff) | |
| download | misskey-270e1212aca2931f8c01d43c187106b988fa2c49.tar.gz misskey-270e1212aca2931f8c01d43c187106b988fa2c49.tar.bz2 misskey-270e1212aca2931f8c01d43c187106b988fa2c49.zip | |
chore(client): refactor and style tweaks
Diffstat (limited to 'packages/client/src/components/form')
| -rw-r--r-- | packages/client/src/components/form/input.vue | 257 | ||||
| -rw-r--r-- | packages/client/src/components/form/select.vue | 268 |
2 files changed, 213 insertions, 312 deletions
diff --git a/packages/client/src/components/form/input.vue b/packages/client/src/components/form/input.vue index 5065e28892..ec1ad20de3 100644 --- a/packages/client/src/components/form/input.vue +++ b/packages/client/src/components/form/input.vue @@ -33,176 +33,118 @@ </div> </template> -<script lang="ts"> -import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue'; +<script lang="ts" setup> +import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue'; import { debounce } from 'throttle-debounce'; import MkButton from '@/components/ui/button.vue'; import { useInterval } from '@/scripts/use-interval'; -export default defineComponent({ - components: { - MkButton, - }, +const props = defineProps<{ + modelValue: string | number; + type?: 'text' | 'number' | 'password' | 'email' | 'url' | 'date' | 'time'; + required?: boolean; + readonly?: boolean; + disabled?: boolean; + pattern?: string; + placeholder?: string; + autofocus?: boolean; + autocomplete?: boolean; + spellcheck?: boolean; + step?: any; + datalist?: string[]; + inline?: boolean; + debounce?: boolean; + manualSave?: boolean; + small?: boolean; + large?: boolean; +}>(); - props: { - modelValue: { - required: true, - }, - type: { - type: String, - required: false, - }, - required: { - type: Boolean, - required: false, - }, - readonly: { - type: Boolean, - required: false, - }, - disabled: { - type: Boolean, - required: false, - }, - pattern: { - type: String, - required: false, - }, - placeholder: { - type: String, - required: false, - }, - autofocus: { - type: Boolean, - required: false, - default: false, - }, - autocomplete: { - required: false, - }, - spellcheck: { - required: false, - }, - step: { - required: false, - }, - datalist: { - type: Array, - required: false, - }, - inline: { - type: Boolean, - required: false, - default: false, - }, - debounce: { - type: Boolean, - required: false, - default: false, - }, - manualSave: { - type: Boolean, - required: false, - default: false, - }, - }, +const emit = defineEmits<{ + (ev: 'change', _ev: KeyboardEvent): void; + (ev: 'keydown', _ev: KeyboardEvent): void; + (ev: 'enter'): void; + (ev: 'update:modelValue', value: string | number): void; +}>(); - emits: ['change', 'keydown', 'enter', 'update:modelValue'], +const { modelValue, type, autofocus } = toRefs(props); +const v = ref(modelValue.value); +const id = Math.random().toString(); // TODO: uuid? +const focused = ref(false); +const changed = ref(false); +const invalid = ref(false); +const filled = computed(() => v.value !== '' && v.value != null); +const inputEl = ref<HTMLElement>(); +const prefixEl = ref<HTMLElement>(); +const suffixEl = ref<HTMLElement>(); +const height = + props.small ? 38 : + props.large ? 42 : + 40; - setup(props, context) { - const { modelValue, type, autofocus } = toRefs(props); - const v = ref(modelValue.value); - const id = Math.random().toString(); // TODO: uuid? - const focused = ref(false); - const changed = ref(false); - const invalid = ref(false); - const filled = computed(() => v.value !== '' && v.value != null); - const inputEl = ref<HTMLElement>(); - const prefixEl = ref<HTMLElement>(); - const suffixEl = ref<HTMLElement>(); +const focus = () => inputEl.value.focus(); +const onInput = (ev: KeyboardEvent) => { + changed.value = true; + emit('change', ev); +}; +const onKeydown = (ev: KeyboardEvent) => { + emit('keydown', ev); - const focus = () => inputEl.value.focus(); - const onInput = (ev) => { - changed.value = true; - context.emit('change', ev); - }; - const onKeydown = (ev: KeyboardEvent) => { - context.emit('keydown', ev); - - if (ev.code === 'Enter') { - context.emit('enter'); - } - }; - - const updated = () => { - changed.value = false; - if (type.value === 'number') { - context.emit('update:modelValue', parseFloat(v.value)); - } else { - context.emit('update:modelValue', v.value); - } - }; + if (ev.code === 'Enter') { + emit('enter'); + } +}; - const debouncedUpdated = debounce(1000, updated); +const updated = () => { + changed.value = false; + if (type.value === 'number') { + emit('update:modelValue', parseFloat(v.value)); + } else { + emit('update:modelValue', v.value); + } +}; - watch(modelValue, newValue => { - v.value = newValue; - }); +const debouncedUpdated = debounce(1000, updated); - watch(v, newValue => { - if (!props.manualSave) { - if (props.debounce) { - debouncedUpdated(); - } else { - updated(); - } - } +watch(modelValue, newValue => { + v.value = newValue; +}); - invalid.value = inputEl.value.validity.badInput; - }); +watch(v, newValue => { + if (!props.manualSave) { + if (props.debounce) { + debouncedUpdated(); + } else { + updated(); + } + } - // このコンポーネントが作成された時、非表示状態である場合がある - // 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する - useInterval(() => { - if (prefixEl.value) { - if (prefixEl.value.offsetWidth) { - inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px'; - } - } - if (suffixEl.value) { - if (suffixEl.value.offsetWidth) { - inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px'; - } - } - }, 100, { - immediate: true, - afterMounted: true, - }); + invalid.value = inputEl.value.validity.badInput; +}); - onMounted(() => { - nextTick(() => { - if (autofocus.value) { - focus(); - } - }); - }); +// このコンポーネントが作成された時、非表示状態である場合がある +// 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する +useInterval(() => { + if (prefixEl.value) { + if (prefixEl.value.offsetWidth) { + inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px'; + } + } + if (suffixEl.value) { + if (suffixEl.value.offsetWidth) { + inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px'; + } + } +}, 100, { + immediate: true, + afterMounted: true, +}); - return { - id, - v, - focused, - invalid, - changed, - filled, - inputEl, - prefixEl, - suffixEl, - focus, - onInput, - onKeydown, - updated, - }; - }, +onMounted(() => { + nextTick(() => { + if (autofocus.value) { + focus(); + } + }); }); </script> @@ -229,14 +171,13 @@ export default defineComponent({ } > .input { - $height: 42px; position: relative; > input { appearance: none; -webkit-appearance: none; display: block; - height: $height; + height: v-bind("height + 'px'"); width: 100%; margin: 0; padding: 0 12px; @@ -266,7 +207,7 @@ export default defineComponent({ top: 0; padding: 0 12px; font-size: 1em; - height: $height; + height: v-bind("height + 'px'"); pointer-events: none; &:empty { diff --git a/packages/client/src/components/form/select.vue b/packages/client/src/components/form/select.vue index 7f5f8784b6..05e95a0917 100644 --- a/packages/client/src/components/form/select.vue +++ b/packages/client/src/components/form/select.vue @@ -26,178 +26,139 @@ </div> </template> -<script lang="ts"> -import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, VNode } from 'vue'; +<script lang="ts" setup> +import { onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, VNode, useSlots } from 'vue'; import MkButton from '@/components/ui/button.vue'; import * as os from '@/os'; import { useInterval } from '@/scripts/use-interval'; -export default defineComponent({ - components: { - MkButton, - }, +const props = defineProps<{ + modelValue: string; + required?: boolean; + readonly?: boolean; + disabled?: boolean; + placeholder?: string; + autofocus?: boolean; + inline?: boolean; + manualSave?: boolean; + small?: boolean; + large?: boolean; +}>(); - props: { - modelValue: { - required: true, - }, - required: { - type: Boolean, - required: false, - }, - readonly: { - type: Boolean, - required: false, - }, - disabled: { - type: Boolean, - required: false, - }, - placeholder: { - type: String, - required: false, - }, - autofocus: { - type: Boolean, - required: false, - default: false, - }, - inline: { - type: Boolean, - required: false, - default: false, - }, - manualSave: { - type: Boolean, - required: false, - default: false, - }, - }, +const emit = defineEmits<{ + (ev: 'change', _ev: KeyboardEvent): void; + (ev: 'update:modelValue', value: string): void; +}>(); - emits: ['change', 'update:modelValue'], +const slots = useSlots(); - setup(props, context) { - const { modelValue, autofocus } = toRefs(props); - const v = ref(modelValue.value); - const focused = ref(false); - const changed = ref(false); - const invalid = ref(false); - const filled = computed(() => v.value !== '' && v.value != null); - const inputEl = ref(null); - const prefixEl = ref(null); - const suffixEl = ref(null); - const container = ref(null); +const { modelValue, autofocus } = toRefs(props); +const v = ref(modelValue.value); +const focused = ref(false); +const changed = ref(false); +const invalid = ref(false); +const filled = computed(() => v.value !== '' && v.value != null); +const inputEl = ref(null); +const prefixEl = ref(null); +const suffixEl = ref(null); +const container = ref(null); +const height = + props.small ? 38 : + props.large ? 42 : + 40; - const focus = () => inputEl.value.focus(); - const onInput = (ev) => { - changed.value = true; - context.emit('change', ev); - }; +const focus = () => inputEl.value.focus(); +const onInput = (ev) => { + changed.value = true; + emit('change', ev); +}; - const updated = () => { - changed.value = false; - context.emit('update:modelValue', v.value); - }; +const updated = () => { + changed.value = false; + emit('update:modelValue', v.value); +}; - watch(modelValue, newValue => { - v.value = newValue; - }); +watch(modelValue, newValue => { + v.value = newValue; +}); - watch(v, newValue => { - if (!props.manualSave) { - updated(); - } +watch(v, newValue => { + if (!props.manualSave) { + updated(); + } - invalid.value = inputEl.value.validity.badInput; - }); + invalid.value = inputEl.value.validity.badInput; +}); - // このコンポーネントが作成された時、非表示状態である場合がある - // 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する - useInterval(() => { - if (prefixEl.value) { - if (prefixEl.value.offsetWidth) { - inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px'; - } - } - if (suffixEl.value) { - if (suffixEl.value.offsetWidth) { - inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px'; - } - } - }, 100, { - immediate: true, - afterMounted: true, - }); +// このコンポーネントが作成された時、非表示状態である場合がある +// 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する +useInterval(() => { + if (prefixEl.value) { + if (prefixEl.value.offsetWidth) { + inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px'; + } + } + if (suffixEl.value) { + if (suffixEl.value.offsetWidth) { + inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px'; + } + } +}, 100, { + immediate: true, + afterMounted: true, +}); - onMounted(() => { - nextTick(() => { - if (autofocus.value) { - focus(); - } - }); - }); +onMounted(() => { + nextTick(() => { + if (autofocus.value) { + focus(); + } + }); +}); + +const onClick = (ev: MouseEvent) => { + focused.value = true; - const onClick = (ev: MouseEvent) => { - focused.value = true; + const menu = []; + let options = slots.default!(); - const menu = []; - let options = context.slots.default(); + const pushOption = (option: VNode) => { + menu.push({ + text: option.children, + active: v.value === option.props.value, + action: () => { + v.value = option.props.value; + }, + }); + }; - const pushOption = (option: VNode) => { + const scanOptions = (options: VNode[]) => { + for (const vnode of options) { + if (vnode.type === 'optgroup') { + const optgroup = vnode; menu.push({ - text: option.children, - active: v.value === option.props.value, - action: () => { - v.value = option.props.value; - }, + type: 'label', + text: optgroup.props.label, }); - }; - - const scanOptions = (options: VNode[]) => { - for (const vnode of options) { - if (vnode.type === 'optgroup') { - const optgroup = vnode; - menu.push({ - type: 'label', - text: optgroup.props.label, - }); - scanOptions(optgroup.children); - } else if (Array.isArray(vnode.children)) { // 何故かフラグメントになってくることがある - const fragment = vnode; - scanOptions(fragment.children); - } else { - const option = vnode; - pushOption(option); - } - } - }; - - scanOptions(options); + scanOptions(optgroup.children); + } else if (Array.isArray(vnode.children)) { // 何故かフラグメントになってくることがある + const fragment = vnode; + scanOptions(fragment.children); + } else { + const option = vnode; + pushOption(option); + } + } + }; - os.popupMenu(menu, container.value, { - width: container.value.offsetWidth, - }).then(() => { - focused.value = false; - }); - }; + scanOptions(options); - return { - v, - focused, - invalid, - changed, - filled, - inputEl, - prefixEl, - suffixEl, - container, - focus, - onInput, - onClick, - updated, - }; - }, -}); + os.popupMenu(menu, container.value, { + width: container.value.offsetWidth, + }).then(() => { + focused.value = false; + }); +}; </script> <style lang="scss" scoped> @@ -223,7 +184,6 @@ export default defineComponent({ } > .input { - $height: 42px; position: relative; cursor: pointer; @@ -237,7 +197,7 @@ export default defineComponent({ appearance: none; -webkit-appearance: none; display: block; - height: $height; + height: v-bind("height + 'px'"); width: 100%; margin: 0; padding: 0 12px; @@ -265,7 +225,7 @@ export default defineComponent({ top: 0; padding: 0 12px; font-size: 1em; - height: $height; + height: v-bind("height + 'px'"); pointer-events: none; &:empty { |