refactor(studio): extract shared layerOrdering module from LayersPanel

This commit is contained in:
Miguel Angel Simon Sierra
2026-07-08 23:46:24 -04:00
parent 0ac000181e
commit dae26e72b2
3 changed files with 164 additions and 22 deletions
@@ -0,0 +1,85 @@
export interface StackingContextDescriptor {
parentCompositionId: string | null;
compositionAncestors: readonly string[];
stackingContextId?: string | null;
}
export interface ContextOrderItem extends StackingContextDescriptor {
zIndex: number;
}
// fallow-ignore-next-line complexity
export function getElementZIndex(element: HTMLElement): number {
try {
const inline = element.style?.zIndex;
if (inline && inline !== "auto") {
const parsed = parseInt(inline, 10);
if (Number.isFinite(parsed)) return parsed;
}
const win = element.ownerDocument?.defaultView;
if (!win) return 0;
const value = win.getComputedStyle(element).zIndex;
if (value === "auto" || value === "") return 0;
const parsed = parseInt(value, 10);
return Number.isFinite(parsed) ? parsed : 0;
} catch {
return 0;
}
}
export function computeReorderZValues(
existingValues: readonly number[],
fromIndex: number,
toIndex: number,
): number[] {
const reordered = [...existingValues];
const [moved] = reordered.splice(fromIndex, 1);
reordered.splice(toIndex, 0, moved);
const sorted = [...existingValues].sort((a, b) => b - a);
const hasDupes = sorted.some((v, i) => i > 0 && v === sorted[i - 1]);
return hasDupes ? reordered.map((_, i) => reordered.length - i) : sorted;
}
// Exported in a later unit when the timeline consumes it; internal-only for now.
function resolveStackingContextKey(item: StackingContextDescriptor): string {
return item.stackingContextId ?? item.parentCompositionId ?? item.compositionAncestors[0] ?? "";
}
function resolveStackingContextDepth(item: StackingContextDescriptor): number {
const contextKey = resolveStackingContextKey(item);
if (!contextKey) return 0;
const index = item.compositionAncestors.indexOf(contextKey);
return index >= 0 ? index : 0;
}
export function resolveContextOrder<T extends ContextOrderItem>(items: readonly T[]): T[] {
if (items.length === 0) return [];
const groups = new Map<
string,
{ firstIndex: number; depth: number; entries: Array<{ item: T; index: number }> }
>();
items.forEach((item, index) => {
const key = resolveStackingContextKey(item);
const group = groups.get(key);
if (group) {
group.entries.push({ item, index });
return;
}
groups.set(key, {
firstIndex: index,
depth: resolveStackingContextDepth(item),
entries: [{ item, index }],
});
});
return [...groups.values()]
.sort((a, b) => a.depth - b.depth || a.firstIndex - b.firstIndex)
.flatMap((group) =>
group.entries
.sort((a, b) => b.item.zIndex - a.item.zIndex || a.index - b.index)
.map((entry) => entry.item),
);
}