mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-04-20 22:50:11 -04:00
[ENG-809] Enter key submits dialog (#1279)
* enter key submit dialog * code test * input focus fix + dialog closes only if form is valid * Update CreateDialog.tsx
This commit is contained in:
@@ -44,6 +44,7 @@ export default function FeedbackDialog(props: UseDialogProps) {
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
invertButtonFocus
|
||||
title="Feedback"
|
||||
dialog={useDialog(props)}
|
||||
form={form}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useQueryClient } from '@tanstack/react-query';
|
||||
import { Check, Trash, X } from 'phosphor-react';
|
||||
import { useJobProgress, useLibraryMutation, useLibraryQuery } from '@sd/client';
|
||||
import { Button, PopoverClose, Tooltip, toast } from '@sd/ui';
|
||||
import { showAlertDialog } from '~/components/AlertDialog';
|
||||
import IsRunningJob from './IsRunningJob';
|
||||
import JobGroup from './JobGroup';
|
||||
import { useState } from 'react';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Pencil, Plus, Trash } from 'phosphor-react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ContextMenu as CM, dialogManager } from '@sd/ui';
|
||||
import CreateDialog from '~/app/$libraryId/settings/library/tags/CreateDialog';
|
||||
import DeleteDialog from '~/app/$libraryId/settings/library/tags/DeleteDialog';
|
||||
@@ -26,21 +27,22 @@ export default ({ children, tagId }: Props) => {
|
||||
onClick={() => navigate(`settings/library/tags/${tagId}`)}
|
||||
/>
|
||||
<CM.Separator />
|
||||
<CM.Item
|
||||
onClick={() => {
|
||||
navigate(`settings/library/tags/${tagId}`);
|
||||
dialogManager.create((dp) => (
|
||||
<DeleteDialog
|
||||
{...dp}
|
||||
tagId={tagId}
|
||||
onSuccess={() => navigate(`settings/library/tags`)}
|
||||
/>
|
||||
));
|
||||
}}
|
||||
icon={Trash}
|
||||
label="Delete"
|
||||
variant="danger"
|
||||
/>
|
||||
<Link to={`settings/library/tags/${tagId}`}>
|
||||
<CM.Item
|
||||
onClick={() => {
|
||||
dialogManager.create((dp) => (
|
||||
<DeleteDialog
|
||||
{...dp}
|
||||
tagId={tagId}
|
||||
onSuccess={() => navigate(`settings/library/tags`)}
|
||||
/>
|
||||
));
|
||||
}}
|
||||
icon={Trash}
|
||||
label="Delete"
|
||||
variant="danger"
|
||||
/>
|
||||
</Link>
|
||||
</CM.Root>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -38,6 +38,7 @@ export default (props: UseDialogProps & { objects?: Object[] }) => {
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
invertButtonFocus
|
||||
form={form}
|
||||
onSubmit={onSubmit}
|
||||
dialog={useDialog(props)}
|
||||
|
||||
@@ -124,6 +124,7 @@ export interface DialogProps<S extends FieldValues>
|
||||
submitDisabled?: boolean;
|
||||
transformOrigin?: string;
|
||||
buttonsSideContent?: ReactNode;
|
||||
invertButtonFocus?: boolean; //this reverses the focus order of submit/cancel buttons
|
||||
}
|
||||
|
||||
export function Dialog<S extends FieldValues>({
|
||||
@@ -131,6 +132,7 @@ export function Dialog<S extends FieldValues>({
|
||||
dialog,
|
||||
onSubmit,
|
||||
onCancelled = true,
|
||||
invertButtonFocus,
|
||||
...props
|
||||
}: DialogProps<S>) {
|
||||
const stateSnap = useSnapshot(dialog.state);
|
||||
@@ -148,6 +150,43 @@ export function Dialog<S extends FieldValues>({
|
||||
|
||||
const setOpen = (v: boolean) => (dialog.state.open = v);
|
||||
|
||||
const cancelButton = (
|
||||
<RDialog.Close asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="gray"
|
||||
onClick={typeof onCancelled === 'function' ? onCancelled : undefined}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</RDialog.Close>
|
||||
);
|
||||
|
||||
const closeButton = (
|
||||
<RDialog.Close asChild>
|
||||
<Button
|
||||
disabled={props.loading}
|
||||
size="sm"
|
||||
variant="gray"
|
||||
onClick={typeof onCancelled === 'function' ? onCancelled : undefined}
|
||||
>
|
||||
{props.closeLabel || 'Close'}
|
||||
</Button>
|
||||
</RDialog.Close>
|
||||
);
|
||||
|
||||
const submitButton = (
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
disabled={form.formState.isSubmitting || props.submitDisabled}
|
||||
variant={props.ctaDanger ? 'colored' : 'accent'}
|
||||
className={clsx(props.ctaDanger && 'border-red-500 bg-red-500')}
|
||||
>
|
||||
{props.ctaLabel}
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<RDialog.Root open={stateSnap.open} onOpenChange={setOpen}>
|
||||
{props.trigger && <RDialog.Trigger asChild>{props.trigger}</RDialog.Trigger>}
|
||||
@@ -171,7 +210,9 @@ export function Dialog<S extends FieldValues>({
|
||||
e?.preventDefault();
|
||||
await onSubmit?.(e);
|
||||
dialog.onSubmit?.();
|
||||
setOpen(false);
|
||||
if (form.formState.isValid) {
|
||||
setOpen(false);
|
||||
}
|
||||
}}
|
||||
className="!pointer-events-auto my-8 min-w-[300px] max-w-[400px] rounded-md border border-app-line bg-app-box text-ink shadow-app-shade"
|
||||
>
|
||||
@@ -188,56 +229,36 @@ export function Dialog<S extends FieldValues>({
|
||||
|
||||
{props.children}
|
||||
</div>
|
||||
<div className="flex flex-row justify-end space-x-2 border-t border-app-line bg-app-selected p-3">
|
||||
<div
|
||||
className={clsx(
|
||||
'flex justify-end space-x-2 border-t border-app-line bg-app-selected p-3'
|
||||
)}
|
||||
>
|
||||
{form.formState.isSubmitting && <Loader />}
|
||||
{props.buttonsSideContent && (
|
||||
<div>{props.buttonsSideContent}</div>
|
||||
)}
|
||||
<div className="grow" />
|
||||
{onCancelled && (
|
||||
<RDialog.Close asChild>
|
||||
<Button
|
||||
disabled={props.loading}
|
||||
size="sm"
|
||||
variant="gray"
|
||||
onClick={
|
||||
typeof onCancelled === 'function'
|
||||
? onCancelled
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{props.closeLabel || 'Close'}
|
||||
</Button>
|
||||
</RDialog.Close>
|
||||
)}
|
||||
{props.cancelBtn && (
|
||||
<RDialog.Close asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="gray"
|
||||
onClick={
|
||||
typeof onCancelled === 'function'
|
||||
? onCancelled
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</RDialog.Close>
|
||||
)}
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
disabled={
|
||||
form.formState.isSubmitting || props.submitDisabled
|
||||
}
|
||||
variant={props.ctaDanger ? 'colored' : 'accent'}
|
||||
<div
|
||||
className={clsx(
|
||||
props.ctaDanger && 'border-red-500 bg-red-500'
|
||||
invertButtonFocus ? 'flex-row-reverse' : ' flex-row',
|
||||
'flex gap-2'
|
||||
)}
|
||||
>
|
||||
{props.ctaLabel}
|
||||
</Button>
|
||||
{invertButtonFocus ? (
|
||||
<>
|
||||
{submitButton}
|
||||
{props.cancelBtn && cancelButton}
|
||||
{onCancelled && closeButton}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{onCancelled && closeButton}
|
||||
{props.cancelBtn && cancelButton}
|
||||
{submitButton}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
<Remover id={dialog.id} />
|
||||
|
||||
Reference in New Issue
Block a user