Extract StatusManager, dedupe ColumnChange type, add useDialog composable
- Pull the status-management feature (drag reorder, add, delete with reassignment) out of ProjectConfigureView into its own StatusManager component. It fetches its own status list independently, so the view is left with just page chrome and the rename form (316 -> 106 lines). - Define ColumnChange once in lib/cardOrder.ts instead of duplicating the same type in AppSidebar.vue and ProjectView.vue. - Add composables/useDialog.ts for the Escape-to-close + focus-on-open behaviour shared by every confirm/reassign modal (and, without a focus target, plain dropdown menus). Used by ProjectManageMenu's delete-confirmation modal + its own menu, and StatusManager's reassignment modal.
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import { nextTick, onBeforeUnmount, onMounted, watch, type Ref } from 'vue'
|
||||
|
||||
/**
|
||||
* Shared "dialog" behaviour: Escape closes it, and -- when a focus target is
|
||||
* given -- opening it moves focus there (matches our confirm/reassign
|
||||
* modals, which follow the WAI-ARIA dialog pattern). Omit focusTarget to use
|
||||
* just the Escape-to-close half, e.g. for a plain dropdown menu.
|
||||
*/
|
||||
export function useDialog<T extends HTMLElement>(
|
||||
isOpen: Ref<boolean>,
|
||||
close: () => void,
|
||||
focusTarget?: Ref<T | undefined>,
|
||||
): void {
|
||||
if (focusTarget) {
|
||||
watch(isOpen, async (open) => {
|
||||
if (open) {
|
||||
await nextTick()
|
||||
focusTarget.value?.focus()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape' && isOpen.value) close()
|
||||
}
|
||||
onMounted(() => window.addEventListener('keydown', onKeydown))
|
||||
onBeforeUnmount(() => window.removeEventListener('keydown', onKeydown))
|
||||
}
|
||||
Reference in New Issue
Block a user