diff --git a/CHANGELOG.md b/CHANGELOG.md index a2208e28..8a38f875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - Fix missing spec info when clicking next to a property - Fix Firefox open file that stopped working due to react upgrade - Fix issue with missing bottom error panel +- Fixed headers in left panes (Layers list and Layer editor) to remain visible when scrolling - _...Add new stuff here..._ ## 3.0.0 diff --git a/cypress.config.ts b/cypress.config.ts index 0eeb88bf..0314d827 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -16,6 +16,7 @@ export default defineConfig({ return config; }, baseUrl: "http://localhost:8888", + scrollBehavior: "center", retries: { runMode: 2, openMode: 0, diff --git a/cypress/e2e/layer-editor.cy.ts b/cypress/e2e/layer-editor.cy.ts index 1d084027..a855b8e1 100644 --- a/cypress/e2e/layer-editor.cy.ts +++ b/cypress/e2e/layer-editor.cy.ts @@ -257,4 +257,24 @@ describe("layer editor", () => { then(get.element(".cm-lint-marker-error")).shouldExist(); }); }); + + describe("sticky header", () => { + it("should keep layer header visible when scrolling properties", () => { + // Setup: Create a layer with many properties (e.g., symbol layer) + when.modal.fillLayers({ + type: "symbol", + layer: "example", + }); + + when.wait(500); + const header = get.elementByTestId("layer-editor.header"); + then(header).shouldBeVisible(); + + get.element(".maputnik-scroll-container").scrollTo("bottom", { ensureScrollable: false }); + when.wait(200); + + then(header).shouldBeVisible(); + then(get.elementByTestId("skip-target-layer-editor")).shouldBeVisible(); + }); + }); }); diff --git a/cypress/e2e/layers-list.cy.ts b/cypress/e2e/layers-list.cy.ts index 4cad20fe..f8048d90 100644 --- a/cypress/e2e/layers-list.cy.ts +++ b/cypress/e2e/layers-list.cy.ts @@ -515,4 +515,27 @@ describe("layers list", () => { }); }); }); + + describe("sticky header", () => { + it("should keep header visible when scrolling layer list", () => { + // Setup: Create multiple layers to enable scrolling + for (let i = 0; i < 20; i++) { + when.modal.open(); + when.modal.fillLayers({ + id: `layer-${i}`, + type: "background", + }); + } + + when.wait(500); + const header = get.elementByTestId("layer-list.header"); + then(header).shouldBeVisible(); + + // Scroll the layer list container (use ensureScrollable: false to avoid flakiness) + get.elementByTestId("layer-list").scrollTo("bottom", { ensureScrollable: false }); + when.wait(200); + then(header).shouldBeVisible(); + then(get.elementByTestId("layer-list:add-layer")).shouldBeVisible(); + }); + }); }); diff --git a/src/components/LayerEditor.tsx b/src/components/LayerEditor.tsx index 7f0b83e2..50429ddd 100644 --- a/src/components/LayerEditor.tsx +++ b/src/components/LayerEditor.tsx @@ -370,7 +370,7 @@ class LayerEditorInternal extends React.Component -
+

{t("Layer: {{layerId}}", { layerId: formatLayerId(this.props.layer.id) })} diff --git a/src/components/LayerList.tsx b/src/components/LayerList.tsx index 852a8b90..5f1fc664 100644 --- a/src/components/LayerList.tsx +++ b/src/components/LayerList.tsx @@ -289,7 +289,7 @@ class LayerListContainerInternal extends React.Component -
+
{t("Layers")}
diff --git a/src/styles/_layer.scss b/src/styles/_layer.scss index b24afba4..e53f45eb 100644 --- a/src/styles/_layer.scss +++ b/src/styles/_layer.scss @@ -5,15 +5,20 @@ // LAYER LIST .maputnik-layer-list { height: 100%; - overflow: auto; + overflow-y: auto; + overflow-x: hidden; display: flex; flex-direction: column; &-header { padding: vars.$margin-2 vars.$margin-2 vars.$margin-3; + position: sticky; + top: 0; + z-index: 2001; + background-color: vars.$color-black; @include mixins.flex-row; - flex: 0 0; + flex: 0 0 auto; > * { vertical-align: middle; @@ -32,9 +37,9 @@ padding: 0; margin: 0; padding-bottom: vars.$margin-5; - flex: 1; + flex: 1 1 auto; overflow-x: hidden; - overflow-y: auto; + overflow-y: visible; } &-item-handle { @@ -326,6 +331,13 @@ } } +.maputnik-layer-editor > header { + position: sticky; + top: 0; + z-index: 10; + background: vars.$color-black; +} + // Clone of the element which is sorted .sortableHelper { font-family: vars.$font-family;