Skip to content

Commit 12c7673

Browse files
dcojgithub-actions[bot]
authored andcommitted
Fixes Style#{get,set,remove}FeatureState with {target: {layerId}} so imported-layer targets resolve against their own fragment's sources instead of the root style's.
GitOrigin-RevId: fb28adb0ca3a17c4e0a49ac917a0d41ae0f27bf0
1 parent d463540 commit 12c7673

2 files changed

Lines changed: 51 additions & 3 deletions

File tree

src/style/style.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3419,7 +3419,10 @@ class Style extends Evented<MapEvents> {
34193419
} else if ('layerId' in target.target) {
34203420
const {layerId} = target.target;
34213421
const layer = this.getLayer(layerId);
3422-
this.setFeatureState({id: target.id, source: layer.source, sourceLayer: layer.sourceLayer}, state);
3422+
if (!layer) return;
3423+
const fragment = this.getFragmentStyle(layer.scope);
3424+
if (!fragment) return;
3425+
fragment.setFeatureState({id: target.id, source: layer.source, sourceLayer: layer.sourceLayer}, state);
34233426
}
34243427

34253428
return;
@@ -3465,7 +3468,10 @@ class Style extends Evented<MapEvents> {
34653468
} else if ('layerId' in target.target) {
34663469
const {layerId} = target.target;
34673470
const layer = this.getLayer(layerId);
3468-
this.removeFeatureState({id: target.id, source: layer.source, sourceLayer: layer.sourceLayer}, key);
3471+
if (!layer) return;
3472+
const fragment = this.getFragmentStyle(layer.scope);
3473+
if (!fragment) return;
3474+
fragment.removeFeatureState({id: target.id, source: layer.source, sourceLayer: layer.sourceLayer}, key);
34693475
}
34703476

34713477
return;
@@ -3519,7 +3525,10 @@ class Style extends Evented<MapEvents> {
35193525
} else if ('layerId' in target.target) {
35203526
const {layerId} = target.target;
35213527
const layer = this.getLayer(layerId);
3522-
finalState = this.getFeatureState({id: target.id, source: layer.source, sourceLayer: layer.sourceLayer});
3528+
if (!layer) return;
3529+
const fragment = this.getFragmentStyle(layer.scope);
3530+
if (!fragment) return;
3531+
finalState = fragment.getFeatureState({id: target.id, source: layer.source, sourceLayer: layer.sourceLayer});
35233532
}
35243533

35253534
return finalState;

test/unit/style/style_imports.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {newStubStyle} from './utils';
1515
import browser from '../../../src/util/browser';
1616
import EvaluationParameters from '../../../src/style/evaluation_parameters';
1717

18+
import type {StyleSpecification} from 'mapbox-gl';
19+
1820
function createStyleJSON(properties) {
1921
return {version: 8,
2022
sources: {},
@@ -3851,3 +3853,40 @@ test('Style#getFragmentStyle', async () => {
38513853
// Fragment should return itself when fragmentId is `undefined`
38523854
expect(basemapFragment2.getFragmentStyle()).toBe(basemapFragment2);
38533855
});
3856+
3857+
describe('feature-state with imported layer targets', () => {
3858+
async function loadCollidingRootAndImport() {
3859+
const {style} = newStubStyle();
3860+
const fragment = createStyleJSON({
3861+
sources: {shared: {type: 'geojson', data: {type: 'FeatureCollection', features: []}}},
3862+
layers: [{id: 'fragment-layer', type: 'circle', source: 'shared'}]
3863+
}) as StyleSpecification;
3864+
const root = createStyleJSON({
3865+
sources: {shared: {type: 'geojson', data: {type: 'FeatureCollection', features: []}}},
3866+
layers: [{id: 'root-layer', type: 'circle', source: 'shared'}],
3867+
imports: [{id: 'fragment', url: '', data: fragment}]
3868+
}) as StyleSpecification;
3869+
style.loadJSON(root);
3870+
await waitFor(style, 'style.load');
3871+
return {style, fragmentStyle: style.getFragmentStyle('fragment')};
3872+
}
3873+
3874+
test('imported-layer setFeatureState writes to the fragment source, not the colliding root source', async () => {
3875+
const {style, fragmentStyle} = await loadCollidingRootAndImport();
3876+
const importedLayerId = makeFQID('fragment-layer', 'fragment');
3877+
3878+
style.setFeatureState({id: 1, target: {layerId: importedLayerId}}, {hover: true});
3879+
3880+
expect(fragmentStyle.getFeatureState({source: 'shared', id: 1})).toEqual({hover: true});
3881+
expect(style.getFeatureState({source: 'shared', id: 1})).toEqual({});
3882+
});
3883+
3884+
test('root-layer setFeatureState still writes to the root source', async () => {
3885+
const {style, fragmentStyle} = await loadCollidingRootAndImport();
3886+
3887+
style.setFeatureState({id: 2, target: {layerId: 'root-layer'}}, {hover: true});
3888+
3889+
expect(style.getFeatureState({source: 'shared', id: 2})).toEqual({hover: true});
3890+
expect(fragmentStyle.getFeatureState({source: 'shared', id: 2})).toEqual({});
3891+
});
3892+
});

0 commit comments

Comments
 (0)