fix: Open and highlight correct workflow form section on tab click (#2463)
Fixes https://github.com/webrecorder/browsertrix/issues/2461 ## Changes Opens workflow form section when clicking on section navigation link, fixing issue with scroll position impacting unopened panels.
This commit is contained in:
parent
03fa00df45
commit
fa05d68292
@ -419,6 +419,8 @@ export class WorkflowEditor extends BtrixElement {
|
||||
}
|
||||
|
||||
private renderFormSections() {
|
||||
const activeTab = this.progressState?.activeTab;
|
||||
|
||||
const panelBody = ({
|
||||
name,
|
||||
desc,
|
||||
@ -439,21 +441,27 @@ export class WorkflowEditor extends BtrixElement {
|
||||
)}
|
||||
?open=${required || hasError || tabProgress?.completed}
|
||||
@sl-focus=${() => {
|
||||
this.updateProgressState({
|
||||
activeTab: name,
|
||||
});
|
||||
if (activeTab !== name) {
|
||||
this.updateProgressState({
|
||||
activeTab: name,
|
||||
});
|
||||
}
|
||||
}}
|
||||
@sl-show=${this.handleCurrentTarget(() => {
|
||||
this.pauseObserve();
|
||||
this.updateProgressState({
|
||||
activeTab: name,
|
||||
});
|
||||
if (activeTab !== name) {
|
||||
this.pauseHandlePanelIntersect(name);
|
||||
this.updateProgressState({
|
||||
activeTab: name,
|
||||
});
|
||||
}
|
||||
|
||||
track(AnalyticsTrackEvent.ExpandWorkflowFormSection, {
|
||||
section: name,
|
||||
});
|
||||
})}
|
||||
@sl-hide=${this.handleCurrentTarget((e: SlHideEvent) => {
|
||||
this.pauseHandlePanelIntersect(name);
|
||||
|
||||
const el = e.currentTarget as SlDetails;
|
||||
|
||||
// Check if there's any invalid elements before hiding
|
||||
@ -473,8 +481,12 @@ export class WorkflowEditor extends BtrixElement {
|
||||
invalidEl.checkValidity();
|
||||
}
|
||||
})}
|
||||
@sl-after-show=${this.handleCurrentTarget(this.resumeObserve)}
|
||||
@sl-after-hide=${this.handleCurrentTarget(this.resumeObserve)}
|
||||
@sl-after-show=${this.handleCurrentTarget(
|
||||
this.resumeHandlePanelIntersect,
|
||||
)}
|
||||
@sl-after-hide=${this.handleCurrentTarget(
|
||||
this.resumeHandlePanelIntersect,
|
||||
)}
|
||||
>
|
||||
<div slot="expand-icon" class="flex items-center">
|
||||
<sl-tooltip
|
||||
@ -1652,25 +1664,22 @@ https://archiveweb.page/images/${"logo.svg"}`}
|
||||
this.updateFormState(formState);
|
||||
}
|
||||
|
||||
// Use to skip updates on intersect changes, like when scrolling
|
||||
// an element into view on click
|
||||
private skipIntersectUpdate = false;
|
||||
// Store the panel to focus or scroll to temporarily
|
||||
// so that the intersection observer doesn't update
|
||||
// the active tab on scroll
|
||||
private scrollTargetTab: StepName | null = null;
|
||||
|
||||
private pauseObserve() {
|
||||
private pauseHandlePanelIntersect(targetActiveTab: StepName) {
|
||||
this.onPanelIntersect.flush();
|
||||
this.skipIntersectUpdate = true;
|
||||
this.scrollTargetTab = targetActiveTab;
|
||||
}
|
||||
|
||||
private resumeObserve() {
|
||||
this.skipIntersectUpdate = false;
|
||||
private resumeHandlePanelIntersect() {
|
||||
// Reset scroll target tab to indicate that scroll handling should continue
|
||||
this.scrollTargetTab = null;
|
||||
}
|
||||
|
||||
private readonly onPanelIntersect = throttle(10)((e: Event) => {
|
||||
if (this.skipIntersectUpdate) {
|
||||
this.resumeObserve();
|
||||
return;
|
||||
}
|
||||
|
||||
const { entries } = (e as IntersectEvent).detail;
|
||||
|
||||
entries.forEach((entry) => {
|
||||
@ -1681,17 +1690,27 @@ https://archiveweb.page/images/${"logo.svg"}`}
|
||||
}
|
||||
});
|
||||
|
||||
const panels = [...(this.panels ?? [])];
|
||||
const activeTab = panels
|
||||
.find((panel) => this.visiblePanels.has(panel.id))
|
||||
?.id.split(panelSuffix)[0] as StepName | undefined;
|
||||
if (!this.scrollTargetTab) {
|
||||
// Make first visible tab active
|
||||
const panels = [...(this.panels ?? [])];
|
||||
const targetActiveTab = panels
|
||||
.find((panel) => this.visiblePanels.has(panel.id))
|
||||
?.id.split(panelSuffix)[0] as StepName | undefined;
|
||||
|
||||
if (!STEPS.includes(activeTab!)) {
|
||||
console.debug("tab not in steps:", activeTab, this.visiblePanels);
|
||||
return;
|
||||
if (!targetActiveTab || !STEPS.includes(targetActiveTab)) {
|
||||
if (targetActiveTab) {
|
||||
console.debug(
|
||||
"tab not in steps:",
|
||||
targetActiveTab,
|
||||
this.visiblePanels,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateProgressState({ activeTab: targetActiveTab });
|
||||
}
|
||||
|
||||
this.updateProgressState({ activeTab });
|
||||
});
|
||||
|
||||
private hasRequiredFields(): boolean {
|
||||
@ -1709,15 +1728,22 @@ https://archiveweb.page/images/${"logo.svg"}`}
|
||||
return;
|
||||
}
|
||||
|
||||
this.pauseObserve();
|
||||
if (this.progressState?.activeTab) {
|
||||
this.pauseHandlePanelIntersect(this.progressState.activeTab);
|
||||
}
|
||||
|
||||
// Focus on focusable element, if found, to highlight the section
|
||||
const summary = activeTabPanel
|
||||
.querySelector("sl-details")
|
||||
?.shadowRoot?.querySelector<HTMLElement>("summary[aria-controls]");
|
||||
const details = activeTabPanel.querySelector("sl-details")!;
|
||||
const summary = details.shadowRoot?.querySelector<HTMLElement>(
|
||||
"summary[aria-controls]",
|
||||
);
|
||||
|
||||
activeTabPanel.scrollIntoView({ block: "start" });
|
||||
|
||||
if (summary) {
|
||||
summary.focus({
|
||||
// Handle scrolling into view separately
|
||||
preventScroll: true,
|
||||
// Prevent firefox from applying own focus styles
|
||||
focusVisible: false,
|
||||
} as FocusOptions & {
|
||||
@ -1726,7 +1752,12 @@ https://archiveweb.page/images/${"logo.svg"}`}
|
||||
} else {
|
||||
console.debug("summary not found in sl-details");
|
||||
}
|
||||
activeTabPanel.scrollIntoView({ block: "start" });
|
||||
|
||||
if (details.open) {
|
||||
this.resumeHandlePanelIntersect();
|
||||
} else {
|
||||
void details.show();
|
||||
}
|
||||
}
|
||||
|
||||
private async handleRemoveRegex(e: CustomEvent) {
|
||||
|
Loading…
Reference in New Issue
Block a user