Fix dashboard modal bugs (#6833)

* Fix rename modal disappearing; scroll context menu into view

* Fix modal not closing when input is selected
This commit is contained in:
somebody1234 2023-05-30 19:57:13 +10:00 committed by GitHub
parent c6cb937c0a
commit aba5e0f18c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 22 deletions

View File

@ -8,6 +8,7 @@ import * as modalProvider from '../../providers/modal'
import * as svg from '../../components/svg'
import * as validation from '../validation'
import Input from './input'
import Modal from './modal'
// ==========================
@ -64,7 +65,7 @@ function ChangePasswordModal() {
{svg.LOCK}
</div>
<input
<Input
autoFocus
required
id="old_password"
@ -72,9 +73,7 @@ function ChangePasswordModal() {
name="old_password"
placeholder="Old Password"
value={oldPassword}
onChange={event => {
setOldPassword(event.target.value)
}}
setValue={setOldPassword}
className="text-sm sm:text-base placeholder-gray-500 pl-10 pr-4 rounded-lg border border-gray-400 w-full py-2 focus:outline-none focus:border-blue-400"
/>
</div>
@ -91,7 +90,7 @@ function ChangePasswordModal() {
{svg.LOCK}
</div>
<input
<Input
required
id="new_password"
type="password"
@ -100,9 +99,7 @@ function ChangePasswordModal() {
pattern={validation.PASSWORD_PATTERN}
title={validation.PASSWORD_TITLE}
value={newPassword}
onChange={event => {
setNewPassword(event.target.value)
}}
setValue={setNewPassword}
className="text-sm sm:text-base placeholder-gray-500 pl-10 pr-4 rounded-lg border border-gray-400 w-full py-2 focus:outline-none focus:border-blue-400"
/>
</div>
@ -119,16 +116,14 @@ function ChangePasswordModal() {
{svg.LOCK}
</div>
<input
<Input
required
id="confirm_new_password"
type="password"
name="confirm_new_password"
placeholder="Confirm New Password"
value={confirmNewPassword}
onChange={event => {
setConfirmNewPassword(event.target.value)
}}
setValue={setConfirmNewPassword}
className="text-sm sm:text-base placeholder-gray-500 pl-10 pr-4 rounded-lg border border-gray-400 w-full py-2 focus:outline-none focus:border-blue-400"
/>
</div>

View File

@ -3,9 +3,16 @@
import * as react from 'react'
// =================
// === Component ===
// === Constants ===
// =================
/** The margin around the context menu, so that it is not at the edge of the screen. */
const SCROLL_MARGIN = 12
// ===================
// === ContextMenu ===
// ===================
/** Props for a {@link ContextMenu}. */
export interface ContextMenuProps {
// `left: number` and `top: number` may be more correct,
@ -17,10 +24,23 @@ export interface ContextMenuProps {
/** A context menu that opens at the current mouse position. */
function ContextMenu(props: react.PropsWithChildren<ContextMenuProps>) {
const { children, event } = props
const contextMenuRef = react.useRef<HTMLDivElement>(null)
react.useEffect(() => {
if (contextMenuRef.current != null) {
const boundingBox = contextMenuRef.current.getBoundingClientRect()
const scrollBy = boundingBox.bottom - innerHeight + SCROLL_MARGIN
if (scrollBy > 0) {
scroll(scrollX, scrollY + scrollBy)
}
}
}, [children])
return (
<div
ref={contextMenuRef}
style={{ left: event.pageX, top: event.pageY }}
className="absolute bg-white rounded-lg shadow-soft flex flex-col flex-nowrap"
className="absolute bg-white rounded-lg shadow-soft flex flex-col flex-nowrap m-2"
>
{children}
</div>

View File

@ -711,9 +711,11 @@ function Dashboard(props: DashboardProps) {
tab === Tab.dashboard ? '' : 'hidden'
}`}
onClick={event => {
unsetModal()
if (!event.shiftKey) {
setSelectedAssets([])
if (getSelection()?.type !== 'Range') {
unsetModal()
if (!event.shiftKey) {
setSelectedAssets([])
}
}
}}
onKeyDown={handleEscapeKey}

View File

@ -0,0 +1,29 @@
/** @file Input element with default event handlers. */
import * as react from 'react'
// =============
// === Input ===
// =============
/** Props for an {@link Input}. */
export interface InputProps extends react.InputHTMLAttributes<HTMLInputElement> {
setValue: (value: string) => void
}
/** A component for authentication from inputs, with preset styles. */
function Input(props: InputProps) {
const { setValue, ...passThrough } = props
return (
<input
{...passThrough}
onChange={event => {
setValue(event.target.value)
}}
onBlur={() => {
getSelection()?.empty()
}}
/>
)
}
export default Input

View File

@ -27,7 +27,8 @@ function Modal(props: ModalProps) {
centered ? 'fixed w-screen h-screen grid place-items-center ' : ''
}${className ?? ''}`}
onClick={event => {
if (event.currentTarget === event.target) {
if (event.currentTarget === event.target && getSelection()?.type !== 'Range') {
event.stopPropagation()
unsetModal()
}
}}

View File

@ -5,6 +5,7 @@ import toast from 'react-hot-toast'
import * as modalProvider from '../../providers/modal'
import * as svg from '../../components/svg'
import Input from './input'
import Modal from './modal'
// ===================
@ -62,7 +63,7 @@ function RenameModal(props: RenameModalProps) {
<label className="w-1/3" htmlFor="renamed_file_name">
File name
</label>
<input
<Input
autoFocus
id="renamed_file_name"
type="text"
@ -70,10 +71,8 @@ function RenameModal(props: RenameModalProps) {
pattern={namePattern}
title={title}
className="border-primary bg-gray-200 rounded-full w-2/3 px-2 mx-2"
onChange={event => {
setNewName(event.target.value)
}}
defaultValue={newName ?? name}
setValue={setNewName}
/>
</div>
<div className="m-1">