feat: add submit button component to support shortcut keys for form submission

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/621/head^2
Ryan Wang 2022-09-26 15:48:55 +08:00
parent f3958ba53a
commit 2c7d8551fb
11 changed files with 122 additions and 150 deletions

View File

@ -0,0 +1,40 @@
<script lang="ts" setup>
import { VButton } from "@halo-dev/components";
import { useMagicKeys } from "@vueuse/core";
import { computed, useAttrs, watchEffect } from "vue";
const props = withDefaults(
defineProps<{
text?: string;
}>(),
{
text: "提交",
}
);
const emit = defineEmits<{
(event: "submit"): void;
}>();
const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
const attrs = useAttrs();
const buttonText = computed(() => {
return `${props.text} ${isMac ? "⌘" : "Ctrl"} + ↵`;
});
const { Command_Enter, Ctrl_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value || Ctrl_Enter.value) {
emit("submit");
}
});
</script>
<template>
<VButton v-bind="attrs" @click="emit('submit')">
{{ buttonText }}
</VButton>
</template>

View File

@ -1,12 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { VButton, VModal, VSpace } from "@halo-dev/components"; import { VButton, VModal, VSpace } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue";
import type { Group } from "@halo-dev/api-client"; import type { Group } from "@halo-dev/api-client";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { computed, ref, watch, watchEffect } from "vue"; import { computed, ref, watch } from "vue";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { reset, submitForm } from "@formkit/core"; import { reset } from "@formkit/core";
import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
@ -85,14 +85,6 @@ const handleResetForm = () => {
reset("attachment-group-form"); reset("attachment-group-form");
}; };
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("attachment-group-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
@ -140,13 +132,13 @@ watch(
</FormKit> </FormKit>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton <SubmitButton
v-if="visible"
:loading="saving" :loading="saving"
type="secondary" type="secondary"
@click="$formkit.submit('attachment-group-form')" @submit="$formkit.submit('attachment-group-form')"
> >
保存 + </SubmitButton>
</VButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,5 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { VButton, VModal, VSpace } from "@halo-dev/components"; import { VButton, VModal, VSpace } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue";
import type { Policy, PolicyTemplate } from "@halo-dev/api-client"; import type { Policy, PolicyTemplate } from "@halo-dev/api-client";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { computed, ref, watch, watchEffect } from "vue"; import { computed, ref, watch, watchEffect } from "vue";
@ -8,11 +9,9 @@ import { apiClient } from "@/utils/api-client";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { import {
reset, reset,
submitForm,
type FormKitSchemaCondition, type FormKitSchemaCondition,
type FormKitSchemaNode, type FormKitSchemaNode,
} from "@formkit/core"; } from "@formkit/core";
import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
@ -131,17 +130,9 @@ const handleSave = async () => {
const handleResetForm = () => { const handleResetForm = () => {
formState.value = cloneDeep(initialFormState); formState.value = cloneDeep(initialFormState);
formState.value.metadata.name = uuid(); formState.value.metadata.name = uuid();
reset("local-policy-form"); reset("attachment-policy-form");
}; };
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("local-policy-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
@ -200,9 +191,9 @@ const onVisibleChange = (visible: boolean) => {
> >
<FormKit <FormKit
v-if="formSchema && configMapFormData" v-if="formSchema && configMapFormData"
id="local-policy-form" id="attachment-policy-form"
v-model="configMapFormData['default']" v-model="configMapFormData['default']"
name="local-policy-form" name="attachment-policy-form"
:actions="false" :actions="false"
:preserve="true" :preserve="true"
type="form" type="form"
@ -221,13 +212,13 @@ const onVisibleChange = (visible: boolean) => {
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton <SubmitButton
v-if="visible"
:loading="saving" :loading="saving"
type="secondary" type="secondary"
@click="$formkit.submit('local-policy-form')" @submit="$formkit.submit('attachment-policy-form')"
> >
保存 + </SubmitButton>
</VButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,5 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { VModal, VSpace, VButton, IconMotionLine } from "@halo-dev/components"; import { VModal, VSpace, VButton, IconMotionLine } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue";
import type { import type {
ListedComment, ListedComment,
ListedReply, ListedReply,
@ -10,9 +11,8 @@ import { Picker } from "emoji-mart";
import data from "@emoji-mart/data"; import data from "@emoji-mart/data";
import i18n from "@emoji-mart/data/i18n/zh.json"; import i18n from "@emoji-mart/data/i18n/zh.json";
import { computed, nextTick, ref, watch, watchEffect } from "vue"; import { computed, nextTick, ref, watch, watchEffect } from "vue";
import { reset, submitForm } from "@formkit/core"; import { reset } from "@formkit/core";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
@ -77,14 +77,6 @@ const handleResetForm = () => {
reset(formId.value); reset(formId.value);
}; };
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm(formId.value);
}
});
watch( watch(
() => props.visible, () => props.visible,
async (visible) => { async (visible) => {
@ -175,9 +167,13 @@ watchEffect(() => {
</div> </div>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton type="secondary" :loading="saving" @click="submitForm(formId)"> <SubmitButton
保存 + v-if="visible"
</VButton> :loading="saving"
type="secondary"
@submit="$formkit.submit(formId)"
>
</SubmitButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,19 +1,19 @@
<script lang="ts" setup> <script lang="ts" setup>
// core libs // core libs
import { computed, ref, watch, watchEffect } from "vue"; import { computed, ref, watch } from "vue";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
// components // components
import { VButton, VModal, VSpace } from "@halo-dev/components"; import { VButton, VModal, VSpace } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue";
// types // types
import type { Category } from "@halo-dev/api-client"; import type { Category } from "@halo-dev/api-client";
// libs // libs
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { reset, submitForm } from "@formkit/core"; import { reset } from "@formkit/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
import { useMagicKeys } from "@vueuse/core";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
const props = withDefaults( const props = withDefaults(
@ -95,14 +95,6 @@ const handleResetForm = () => {
reset("category-form"); reset("category-form");
}; };
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("category-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
@ -169,9 +161,13 @@ watch(
</FormKit> </FormKit>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton type="secondary" @click="$formkit.submit('category-form')"> <SubmitButton
保存 + v-if="visible"
</VButton> :loading="saving"
type="secondary"
@submit="$formkit.submit('category-form')"
>
</SubmitButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
// core libs // core libs
import { computed, ref, watch, watchEffect } from "vue"; import { computed, ref, watch } from "vue";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
// components // components
@ -11,15 +11,15 @@ import {
VModal, VModal,
VSpace, VSpace,
} from "@halo-dev/components"; } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue";
// types // types
import type { Tag } from "@halo-dev/api-client"; import type { Tag } from "@halo-dev/api-client";
// libs // libs
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { reset, submitForm } from "@formkit/core"; import { reset } from "@formkit/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
import { useMagicKeys } from "@vueuse/core";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
const props = withDefaults( const props = withDefaults(
@ -99,14 +99,6 @@ const handleResetForm = () => {
reset("tag-form"); reset("tag-form");
}; };
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("tag-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
@ -180,13 +172,13 @@ watch(
</FormKit> </FormKit>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton <SubmitButton
v-if="visible"
:loading="saving" :loading="saving"
type="secondary" type="secondary"
@click="$formkit.submit('tag-form')" @submit="$formkit.submit('tag-form')"
> >
保存 </SubmitButton>
</VButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,12 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { VButton, VModal, VSpace } from "@halo-dev/components"; import { VButton, VModal, VSpace } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue";
import type { Menu } from "@halo-dev/api-client"; import type { Menu } from "@halo-dev/api-client";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { computed, ref, watch, watchEffect } from "vue"; import { computed, ref, watch } from "vue";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { reset, submitForm } from "@formkit/core"; import { reset } from "@formkit/core";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
@ -80,19 +80,11 @@ const handleResetForm = () => {
reset("menu-form"); reset("menu-form");
}; };
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("menu-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
if (visible) { if (visible) {
setFocus("displayNameInput"); setFocus("menuDisplayNameInput");
} else { } else {
handleResetForm(); handleResetForm();
} }
@ -120,13 +112,12 @@ watch(
<FormKit <FormKit
id="menu-form" id="menu-form"
name="menu-form" name="menu-form"
:classes="{ form: 'w-full' }"
type="form" type="form"
:config="{ validationVisibility: 'submit' }" :config="{ validationVisibility: 'submit' }"
@submit="handleCreateMenu" @submit="handleCreateMenu"
> >
<FormKit <FormKit
id="displayNameInput" id="menuDisplayNameInput"
v-model="formState.spec.displayName" v-model="formState.spec.displayName"
help="可根据此名称查询菜单项" help="可根据此名称查询菜单项"
label="菜单名称" label="菜单名称"
@ -136,9 +127,12 @@ watch(
</FormKit> </FormKit>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton type="secondary" @click="$formkit.submit('menu-form')"> <SubmitButton
提交 + v-if="visible"
</VButton> type="secondary"
@submit="$formkit.submit('menu-form')"
>
</SubmitButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,12 +1,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { VButton, VModal, VSpace } from "@halo-dev/components"; import { VButton, VModal, VSpace } from "@halo-dev/components";
import { computed, ref, watch, watchEffect } from "vue"; import SubmitButton from "@/components/button/SubmitButton.vue";
import { computed, ref, watch } from "vue";
import type { MenuItem, Post, SinglePage } from "@halo-dev/api-client"; import type { MenuItem, Post, SinglePage } from "@halo-dev/api-client";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import { reset, submitForm } from "@formkit/core"; import { reset } from "@formkit/core";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { useMagicKeys } from "@vueuse/core";
import { usePostCategory } from "@/modules/contents/posts/categories/composables/use-post-category"; import { usePostCategory } from "@/modules/contents/posts/categories/composables/use-post-category";
import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag"; import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
@ -104,14 +104,6 @@ const handleResetForm = () => {
reset("menuitem-form"); reset("menuitem-form");
}; };
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("menuitem-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
@ -375,9 +367,12 @@ watch(
</FormKit> </FormKit>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton type="secondary" @click="$formkit.submit('menuitem-form')"> <SubmitButton
提交 + v-if="visible"
</VButton> type="secondary"
@submit="$formkit.submit('menuitem-form')"
>
</SubmitButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,6 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { VButton, VModal, VSpace, VTabItem, VTabs } from "@halo-dev/components"; import { VButton, VModal, VSpace, VTabItem, VTabs } from "@halo-dev/components";
import { computed, ref, watch, watchEffect } from "vue"; import SubmitButton from "@/components/button/SubmitButton.vue";
import { computed, ref, watch } from "vue";
import { rbacAnnotations } from "@/constants/annotations"; import { rbacAnnotations } from "@/constants/annotations";
import type { Role } from "@halo-dev/api-client"; import type { Role } from "@halo-dev/api-client";
import { import {
@ -8,8 +9,7 @@ import {
useRoleTemplateSelection, useRoleTemplateSelection,
} from "@/modules/system/roles/composables/use-role"; } from "@/modules/system/roles/composables/use-role";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { reset, submitForm } from "@formkit/core"; import { reset } from "@formkit/core";
import { useMagicKeys } from "@vueuse/core";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
@ -50,14 +50,6 @@ watch(
} }
); );
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("role-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
@ -211,13 +203,13 @@ const handleResetForm = () => {
</VTabs> </VTabs>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton <SubmitButton
v-if="visible"
:loading="saving" :loading="saving"
type="secondary" type="secondary"
@click="$formkit.submit('role-form')" @submit="$formkit.submit('role-form')"
> >
提交 + </SubmitButton>
</VButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
// core libs // core libs
import { computed, ref, watch, watchEffect } from "vue"; import { computed, ref, watch } from "vue";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import type { User } from "@halo-dev/api-client"; import type { User } from "@halo-dev/api-client";
@ -13,12 +13,12 @@ import {
VModal, VModal,
VSpace, VSpace,
} from "@halo-dev/components"; } from "@halo-dev/components";
import SubmitButton from "@/components/button/SubmitButton.vue";
// libs // libs
import YAML from "yaml"; import YAML from "yaml";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { useMagicKeys } from "@vueuse/core"; import { reset } from "@formkit/core";
import { reset, submitForm } from "@formkit/core";
// constants // constants
import { rbacAnnotations } from "@/constants/annotations"; import { rbacAnnotations } from "@/constants/annotations";
@ -92,14 +92,6 @@ const rolesMap = computed<FormKitOptionsList>(() => {
}); });
}); });
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("user-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
@ -249,13 +241,13 @@ const handleRawModeChange = () => {
</div> </div>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton <SubmitButton
v-if="visible"
:loading="saving" :loading="saving"
type="secondary" type="secondary"
@click="$formkit.submit('user-form')" @submit="$formkit.submit('user-form')"
> >
保存 + </SubmitButton>
</VButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>

View File

@ -1,11 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { VButton, VModal, VSpace } from "@halo-dev/components"; import { VButton, VModal, VSpace } from "@halo-dev/components";
import { inject, ref, watch, watchEffect } from "vue"; import SubmitButton from "@/components/button/SubmitButton.vue";
import { inject, ref, watch } from "vue";
import type { User } from "@halo-dev/api-client"; import type { User } from "@halo-dev/api-client";
import { apiClient } from "@/utils/api-client"; import { apiClient } from "@/utils/api-client";
import cloneDeep from "lodash.clonedeep"; import cloneDeep from "lodash.clonedeep";
import { reset, submitForm } from "@formkit/core"; import { reset } from "@formkit/core";
import { useMagicKeys } from "@vueuse/core";
import { setFocus } from "@/formkit/utils/focus"; import { setFocus } from "@/formkit/utils/focus";
const props = withDefaults( const props = withDefaults(
@ -39,14 +39,6 @@ const initialFormState: PasswordChangeFormState = {
const formState = ref<PasswordChangeFormState>(cloneDeep(initialFormState)); const formState = ref<PasswordChangeFormState>(cloneDeep(initialFormState));
const saving = ref(false); const saving = ref(false);
const { Command_Enter } = useMagicKeys();
watchEffect(() => {
if (Command_Enter.value && props.visible) {
submitForm("password-form");
}
});
watch( watch(
() => props.visible, () => props.visible,
(visible) => { (visible) => {
@ -130,13 +122,13 @@ const handleChangePassword = async () => {
</FormKit> </FormKit>
<template #footer> <template #footer>
<VSpace> <VSpace>
<VButton <SubmitButton
v-if="visible"
:loading="saving" :loading="saving"
type="secondary" type="secondary"
@click="$formkit.submit('password-form')" @submit="$formkit.submit('password-form')"
> >
提交 + </SubmitButton>
</VButton>
<VButton @click="onVisibleChange(false)"> Esc</VButton> <VButton @click="onVisibleChange(false)"> Esc</VButton>
</VSpace> </VSpace>
</template> </template>