Skip to content

Commit

Permalink
keyboard fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
pegahvaezi committed Nov 29, 2023
1 parent 62c42d0 commit ec827c0
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 17 deletions.
3 changes: 3 additions & 0 deletions web/src/components/ButtonClose/ButtonClose.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
border-radius: 50%;
width: fit-content;
transition: 0.2s all ease;
border: none;
background: none;
padding: 0;

&:hover {
background-color: var(--bg-color-hover);
Expand Down
7 changes: 4 additions & 3 deletions web/src/components/ButtonClose/ButtonClose.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@ import './ButtonClose.scss'
export type ButtonCloseProps = {
size: 'small' | 'medium' | 'large'
onClick: () => void
disabled?: boolean
}

const ButtonClose: React.FC<ButtonCloseProps> = ({
size = 'medium',
onClick,
disabled,
}) => {
return (
<div className="button-close-wrapper">
<button className="button-close-wrapper" onClick={onClick} disabled={disabled}>
{/* @ts-ignore */}
<Icon
onClick={onClick}
name="x.svg"
size="small-close"
className={`light-grey ${size == 'small' ? 'small' : ''}`}
/>
</div>
</button>
)
}

Expand Down
4 changes: 3 additions & 1 deletion web/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type FooterProps = {
hiddenAchievedOutcomes: CellIdString[]
hiddenSmallOutcomes: CellIdString[]
selectedLayeringAlgo: string
unselectAll: () => void
showSmallOutcomes: (projectCellId: CellIdString) => void
hideSmallOutcomes: (projectCellId: CellIdString) => void
showAchievedOutcomes: (projectCellId: CellIdString) => void
Expand All @@ -29,6 +30,7 @@ const Footer: React.FC<FooterProps> = ({
hiddenAchievedOutcomes,
hiddenSmallOutcomes,
selectedLayeringAlgo,
unselectAll,
showSmallOutcomes,
hideSmallOutcomes,
showAchievedOutcomes,
Expand Down Expand Up @@ -115,7 +117,7 @@ const Footer: React.FC<FooterProps> = ({
<div className={bottomRightPanelClassName}>
{isSyncing && <SyncingIndicator />}
{mapPage && (
<div className="map-viewing-options-button-wrapper">
<div className="map-viewing-options-button-wrapper" onClick={() => unselectAll()}>
{/* If map viewing options is open */}
<MapViewingOptions
isOpen={openMapViewingOptions}
Expand Down
13 changes: 7 additions & 6 deletions web/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,24 @@ export type HeaderProps = {
presentMembers: AgentPubKeyB64[]
setModalState: React.Dispatch<React.SetStateAction<ModalState>>
goToOutcome: (outcomeActionHash: ActionHashB64) => void
unselectAll: () => void
// holochain
updateStatus: (statusString: Profile['status']) => Promise<void>
}

const Header: React.FC<HeaderProps> = ({
// for update bar
showUpdateBar,
setShowUpdateBar,
hasMigratedSharedProject,
whoami,
setModalState,
updateStatus,
activeEntryPoints,
project,
goToOutcome,
members,
presentMembers,
unselectAll,
setShowUpdateBar,
setModalState,
updateStatus,
goToOutcome,
}) => {
const [status, setStatus] = useState<Status>(
// @ts-ignore
Expand Down Expand Up @@ -80,7 +81,7 @@ const Header: React.FC<HeaderProps> = ({
}

return (
<div className={`header-wrapper`}>
<div className={`header-wrapper`} onClick={() => unselectAll()}>
{/* Update Bar */}
<div className="header-update-bar-wrapper">
<UpdateBar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ const MapViewCreateOutcome: React.FC<MapViewCreateOutcomeProps> = ({
isChecked={isSmallScopeChecked}
onChange={(newState) => setIsSmallScopeChecked(newState)}
icon={<Icon name="leaf.svg" className="not-hoverable" />}
text={'This Outcome is Small Scope'}
text={'Small Scope'}
/>
</div>
</div>
Expand Down
52 changes: 47 additions & 5 deletions web/src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useEffect, useRef } from 'react'
import { CSSTransition } from 'react-transition-group'

import Icon from '../Icon/Icon'
Expand Down Expand Up @@ -102,9 +102,53 @@ const Modal: React.FC<ModalProps> = ({
onClose,
children,
}) => {
const modalRef = useRef<HTMLDivElement>(null)

const trapFocus = (event: KeyboardEvent) => {
if (!modalRef.current || event.key !== 'Tab') {
return
}

const focusableModalElements = modalRef.current.querySelectorAll(
'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
) as NodeListOf<HTMLElement>

const firstElement = focusableModalElements[0]
const lastElement =
focusableModalElements[focusableModalElements.length - 1]

if (event.shiftKey && document.activeElement === firstElement) {
lastElement.focus()
event.preventDefault()
} else if (!event.shiftKey && document.activeElement === lastElement) {
firstElement.focus()
event.preventDefault()
}
}

useEffect(() => {
if (active) {
document.addEventListener('keydown', trapFocus)

// Focus the first focusable element
// const focusableModalElements = modalRef.current?.querySelectorAll(
// 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
// )
// ;(focusableModalElements?.[0] as HTMLElement)?.focus()
}

return () => {
document.removeEventListener('keydown', trapFocus)
}
}, [active])

if (!active) {
return null
}

return (
<CSSTransition in={active} timeout={100} unmountOnExit classNames="modal">
<div className={`modal ${white ? 'modal-white' : ''}`}>
<div ref={modalRef} className={`modal ${white ? 'modal-white' : ''}`}>
{/* TODO: figure out how to implement onclickoutside */}
{/* without imapcting the styling for the modal */}
{/* problem seen on Profile Setting after implementation */}
Expand All @@ -115,9 +159,7 @@ const Modal: React.FC<ModalProps> = ({
<ButtonClose onClick={onClose} size="medium" />
</div>
)}
<div className='modal-scrollable-content'>
{children}
</div>
<div className="modal-scrollable-content">{children}</div>
</div>
{/* </OnClickOutside> */}
</div>
Expand Down
1 change: 1 addition & 0 deletions web/src/components/Toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const Toast: React.FC<ToastProps> = ({ toastState, setToastState }) => {
<div className="toast-text">{recentText}</div>
<div className="toast-close">
<ButtonClose
disabled={!isVisible}
size={'small'}
onClick={() => setToastState({ id: ShowToast.No })}
/>
Expand Down
12 changes: 12 additions & 0 deletions web/src/routes/App.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export type AppDispatchProps = {
hideSmallOutcomes: (projectCellId: CellIdString) => void
showAchievedOutcomes: (projectCellId: CellIdString) => void
hideAchievedOutcomes: (projectCellId: CellIdString) => void
unselectAll: () => void
}

export type AppMergeProps = {
Expand Down Expand Up @@ -139,6 +140,7 @@ const App: React.FC<AppProps> = ({
hideAchievedOutcomes,
setSelectedLayeringAlgo,
uninstallProject,
unselectAll,
}) => {
const [networkInfoOpen, setNetworkInfoOpen] = useState(false)

Expand Down Expand Up @@ -182,6 +184,14 @@ const App: React.FC<AppProps> = ({
}
}, [updateVersionInfo.newReleaseVersion])

// when opening a modal, unselect any Outcomes that are selected
useEffect(() => {
if (modalState.id !== OpenModal.None) {
// unselect any selected outcomes
unselectAll()
}
}, [modalState])

useEffect(() => {
// add event listener for pressing the 'i' key with the ctrl key
// to open the network info modal
Expand Down Expand Up @@ -276,6 +286,7 @@ const App: React.FC<AppProps> = ({
showUpdateBar,
setShowUpdateBar,
hasMigratedSharedProject,
unselectAll,
}}
/>
)}
Expand Down Expand Up @@ -353,6 +364,7 @@ const App: React.FC<AppProps> = ({
hideAchievedOutcomes={hideAchievedOutcomes}
selectedLayeringAlgo={selectedLayeringAlgo}
setSelectedLayeringAlgo={setSelectedLayeringAlgo}
unselectAll={unselectAll}
/>
)}
</Router>
Expand Down
4 changes: 4 additions & 0 deletions web/src/routes/App.connector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
import ProjectsZomeApi from '../api/projectsApi'
import { updateProjectMeta } from '../redux/persistent/projects/project-meta/actions'
import { uninstallProject } from '../projects/uninstallProject'
import { unselectAll } from '../redux/ephemeral/selection/actions'

function mapStateToProps(state: RootState): AppStateProps {
const {
Expand Down Expand Up @@ -120,6 +121,9 @@ function mapDispatchToProps(dispatch): AppDispatchProps {
hideAchievedOutcomes: (projectCellId) => {
return dispatch(hideAchievedOutcomes(projectCellId))
},
unselectAll: () => {
return dispatch(unselectAll())
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion web/src/routes/ProjectView/MapView/MapView.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ const MapView: React.FC<MapViewProps> = ({
)
// don't bother with outcome statement tooltips if the zoom level is >= 0.7
// because it displays the full Outcome statement
const outcomeStatementTooltipVisible = hoveredOutcome && zoomLevel < 0.7
const outcomeStatementTooltipVisible = hoveredOutcome && zoomLevel < 0.5

// don't display the 'collapse/expand' contextmenu item if
// the Outcome doesn't have children
Expand Down

0 comments on commit ec827c0

Please sign in to comment.