From c3156c6177702dc201fbdbfcf9be3124032c5f8f Mon Sep 17 00:00:00 2001 From: Caroline D <108160931+CarolineDenis@users.noreply.github.com> Date: Thu, 6 Apr 2023 11:09:15 -0700 Subject: [PATCH] Fixes query line being behind dialog Fixes #3279 --- .../lib/components/QueryBuilder/Fields.tsx | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/specifyweb/frontend/js_src/lib/components/QueryBuilder/Fields.tsx b/specifyweb/frontend/js_src/lib/components/QueryBuilder/Fields.tsx index 9f9fb47015d..c6ca930eb06 100644 --- a/specifyweb/frontend/js_src/lib/components/QueryBuilder/Fields.tsx +++ b/specifyweb/frontend/js_src/lib/components/QueryBuilder/Fields.tsx @@ -10,6 +10,7 @@ import { scrollIntoView } from '../TreeView/helpers'; import type { MappingPath } from '../WbPlanView/Mapper'; import type { QueryField } from './helpers'; import { QueryLine } from './Line'; +import { f } from '../../utils/functools'; export function QueryFields({ baseTableName, @@ -67,9 +68,15 @@ export function QueryFields({ }): JSX.Element { const fieldsContainerRef = React.useRef(null); + const fieldsRef = React.useRef(fields); + fieldsRef.current = fields; + + const handleChangeFieldRef = React.useRef(handleChangeFields); + handleChangeFieldRef.current = handleChangeFields; + // Draggable and sortable code React.useEffect(() => { - if (handleChangeFields === undefined) return; + if (handleChangeFieldRef.current === undefined) return; if (fieldsContainerRef.current === null) return; const sortable = new Sortable(fieldsContainerRef.current, { @@ -98,28 +105,41 @@ export function QueryFields({ event.cancel(); }); + sortable.on('mirror:created', (event) => { + const parentZIndex = findClosestZIndex(event.source); + if (parentZIndex !== undefined) + event.mirror.style.zIndex = (parentZIndex + 1).toString(); + }); + sortable.on('sortable:stop', (event) => { const newIndex = event.newIndex; const oldIndex = event.oldIndex; - const newItems = Array.from(fields); + const newItems = Array.from(fieldsRef.current); if (oldIndex < newIndex) { - newItems.splice(newIndex + 1, 0, fields[oldIndex]); + newItems.splice(newIndex + 1, 0, fieldsRef.current[oldIndex]); newItems.splice(oldIndex, 1); } else if (oldIndex > newIndex) { - newItems.splice(newIndex, 0, fields[oldIndex]); + newItems.splice(newIndex, 0, fieldsRef.current[oldIndex]); newItems.splice(oldIndex + 1, 1); } - handleChangeFields(newItems); + handleChangeFieldRef.current?.(newItems); handleLineFocus?.(newIndex); }); + sortable.on('draggable:destroy', () => { + const mirror = ( + sortable as unknown as { readonly mirror: Element | null } + ).mirror; + if (mirror !== null) mirror.parentNode?.removeChild(mirror); + }); + return () => { sortable.destroy(); }; - }, [fields, handleChangeFields]); + }, []); // Scroll to bottom if added a child const oldFieldCount = React.useRef(fields.length); @@ -192,3 +212,10 @@ export function QueryFields({ ); } + +function findClosestZIndex(element: Element): number | undefined { + const zIndex = f.parseInt(getComputedStyle(element).zIndex); + if (typeof zIndex === 'number') return zIndex; + const parent = element.parentElement ?? undefined; + return f.maybe(parent, findClosestZIndex); +}