-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added the ability to move question (#274)
* Part 1 of moving question to another page * Part 2 of moving question to another page * Added the ability to move question to another page * Added the ability to move question to another page * fixing get by role selector to remove ambiguity * removed logging * Removed some console logs * Fixed some bugs and accessibility issues This commit includes a fix for the bug when moving questions back and forth and also a bug with the list of page options. This update also addresses some accessibility issues. * Fixed some bugs and accessibility issues part 2 * Addressed some bugs and feedback reviews In this commit I fixed a couple of bugs and made updates per some reviews in the pull request. * Addressed some bugs and feedback reviews Part 2 * Updated the builder test to account for source page * Made updates per the reviews in my PR * Made updates per the reviews in my PR Part 2 * Ensured that page types can't be moved * A minor update to the store.ts * A minor update to the store.ts Part 2 --------- Co-authored-by: ethangardner <[email protected]>
- Loading branch information
1 parent
ede6349
commit 7e0fd83
Showing
10 changed files
with
754 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
/// <reference path="../.astro/types.d.ts" /> | ||
/// <reference types="astro/client" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
210 changes: 210 additions & 0 deletions
210
packages/design/src/FormManager/FormEdit/components/common/MovePatternDropdown.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
import React, { useState, useRef, useEffect } from 'react'; | ||
import { useFormManagerStore } from '../../../store'; | ||
import styles from '../../formEditStyles.module.css'; | ||
|
||
interface MovePatternDropdownProps { | ||
isFieldset: boolean; | ||
} | ||
|
||
// Define the extended type for pages | ||
interface PageWithLabel { | ||
id: string; | ||
type: string; | ||
data: { | ||
title: string; | ||
patterns: string[]; | ||
}; | ||
specialLabel?: string; | ||
} | ||
|
||
const MovePatternDropdown: React.FC<MovePatternDropdownProps> = ({ | ||
isFieldset, | ||
}) => { | ||
const context = useFormManagerStore(state => state.context); | ||
const [dropdownOpen, setDropdownOpen] = useState(false); | ||
const [targetPage, setTargetPage] = useState(''); | ||
const [moveToPosition, setMoveToPosition] = useState(''); | ||
const dropdownRef = useRef<HTMLDivElement>(null); | ||
const buttonRef = useRef<HTMLButtonElement>(null); | ||
const pages = useFormManagerStore(state => | ||
Object.values(state.session.form.patterns).filter(p => p.type === 'page') | ||
); | ||
const movePatternToPage = useFormManagerStore(state => state.movePattern); | ||
const focusPatternId = useFormManagerStore(state => state.focus?.pattern.id); | ||
const useAvailablePages = () => { | ||
const currentPageIndex = pages.findIndex(page => | ||
page.data.patterns.includes(focusPatternId || '') | ||
); | ||
const page1Count = pages.reduce( | ||
(count, page) => count + (page.data.title === 'Page 1' ? 1 : 0), | ||
0 | ||
); | ||
const availablePages: PageWithLabel[] = | ||
page1Count > 1 | ||
? pages.slice(1).map((page, index) => { | ||
if (index + 1 === currentPageIndex) { | ||
return { ...page, specialLabel: 'Current page' }; | ||
} | ||
return page; | ||
}) | ||
: pages.map((page, index) => { | ||
if (index === currentPageIndex) { | ||
return { ...page, specialLabel: 'Current page' }; | ||
} | ||
return page; | ||
}); | ||
|
||
return availablePages; | ||
}; | ||
const availablePages = useAvailablePages(); | ||
const currentPageIndex = pages.findIndex(page => | ||
page.data.patterns.includes(focusPatternId || '') | ||
); | ||
const sourcePage = pages[currentPageIndex]?.id; | ||
const handleMovePattern = () => { | ||
if (focusPatternId && targetPage) { | ||
movePatternToPage(sourcePage, targetPage, focusPatternId, moveToPosition); | ||
} | ||
setDropdownOpen(false); | ||
}; | ||
const toggleDropdown = () => { | ||
setDropdownOpen(!dropdownOpen); | ||
}; | ||
const handleClickOutside = (event: MouseEvent) => { | ||
if ( | ||
dropdownRef.current && | ||
!dropdownRef.current.contains(event.target as Node) | ||
) { | ||
setDropdownOpen(false); | ||
} | ||
}; | ||
const handleKeyDown = (event: KeyboardEvent) => { | ||
if (event.key === 'Escape') { | ||
setDropdownOpen(false); | ||
buttonRef.current?.focus(); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
if (dropdownOpen) { | ||
document.addEventListener('mousedown', handleClickOutside); | ||
dropdownRef.current?.addEventListener('keydown', handleKeyDown); | ||
} else { | ||
document.removeEventListener('mousedown', handleClickOutside); | ||
dropdownRef.current?.removeEventListener('keydown', handleKeyDown); | ||
} | ||
return () => { | ||
document.removeEventListener('mousedown', handleClickOutside); | ||
dropdownRef.current?.removeEventListener('keydown', handleKeyDown); | ||
}; | ||
}, [dropdownOpen]); | ||
|
||
return ( | ||
<div | ||
className={`${styles.moveToPageWrapper} display-inline-block text-ttop position-relative`} | ||
ref={dropdownRef} | ||
> | ||
<p | ||
className={`${styles.movePatternButton} margin-top-1 display-inline-block text-ttop cursor-pointer`} | ||
> | ||
<button | ||
className="usa-button--outline usa-button--unstyled margin-right-0 padding-top-1 padding-left-05 padding-bottom-05" | ||
type="button" | ||
ref={buttonRef} | ||
aria-haspopup="true" | ||
aria-expanded={dropdownOpen ? 'true' : 'false'} | ||
onClick={event => { | ||
event.preventDefault(); | ||
toggleDropdown(); | ||
}} | ||
> | ||
<span className="display-inline-block text-ttop"> | ||
{isFieldset ? 'Move fieldset' : 'Move question'} | ||
</span> | ||
<svg | ||
className="usa-icon display-inline-block text-ttop" | ||
aria-hidden="true" | ||
focusable="false" | ||
role="img" | ||
> | ||
<use | ||
xlinkHref={`${context.uswdsRoot}img/sprite.svg#expand_more`} | ||
></use> | ||
</svg> | ||
</button> | ||
</p> | ||
{dropdownOpen && ( | ||
<div className={`${styles.dropDown} padding-2`} tabIndex={-1}> | ||
<div className={`${styles.moveToPagePosition} margin-bottom-1`}> | ||
<label | ||
className="usa-label display-inline-block text-ttop margin-right-1" | ||
htmlFor="pagenumbers" | ||
> | ||
Page: | ||
</label> | ||
<select | ||
className="usa-select display-inline-block text-ttop" | ||
name="pagenumbers" | ||
id="pagenumbers" | ||
value={targetPage} | ||
onChange={e => setTargetPage(e.target.value)} | ||
> | ||
<option value="" disabled> | ||
Select page | ||
</option> | ||
{availablePages.map((page, index) => ( | ||
<option key={page.id} value={page.id}> | ||
{page.specialLabel || page.data.title || `Page ${index + 2}`} | ||
</option> | ||
))} | ||
</select> | ||
</div> | ||
<div className={`${styles.moveToPagePosition} margin-bottom-1`}> | ||
<label | ||
className="usa-label margin-right-1 display-inline-block text-ttop" | ||
htmlFor="elementPosition" | ||
> | ||
Position: | ||
</label> | ||
<select | ||
className="usa-select display-inline-block text-ttop" | ||
name="elementPosition" | ||
id="elementPosition" | ||
value={moveToPosition} | ||
onChange={e => | ||
setMoveToPosition(e.target.value as 'top' | 'bottom') | ||
} | ||
> | ||
<option value="" disabled> | ||
Select position | ||
</option> | ||
<option value="top">Top of page</option> | ||
<option value="bottom">Bottom of page</option> | ||
</select> | ||
</div> | ||
<p> | ||
<button | ||
type="button" | ||
aria-label={ | ||
isFieldset | ||
? 'Move fieldset to another page' | ||
: 'Move question to another page' | ||
} | ||
title={ | ||
isFieldset | ||
? 'Move fieldset to another page' | ||
: 'Move question to another page' | ||
} | ||
className="usa-button margin-right-0" | ||
onClick={handleMovePattern} | ||
> | ||
{isFieldset ? 'Move fieldset' : 'Move question'} | ||
</button> | ||
</p> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default MovePatternDropdown; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.