Map children declared with hidden never autoload, because the whole @studiometa/ui-mapbox catalog uses the visible strategy.
Reproduction
<link rel="stylesheet" href="https://esm.sh/mapbox-gl@3.13.0/dist/mapbox-gl.css" />
<script type="module" src="https://esm.sh/@studiometa/ui-mapbox@1.10.0/autoload"></script>
<div
data-component="MapboxMap"
data-option-access-token="…"
data-option-zoom="10"
data-option-center="[2.35, 48.86]"
class="h-96 w-full">
<div data-ref="container" class="h-full w-full"></div>
<div
hidden
data-component="MapboxNavigationControl"
data-option-position="top-right"
data-option-show-compass
data-option-show-zoom></div>
<div
data-component="MapboxGeolocateControl"
data-option-position="top-right"
data-option-track-user-location></div>
<div hidden data-component="MapboxFullscreenControl" data-option-position="top-right"></div>
</div>
Only MapboxGeolocateControl mounts and is added to the map. MapboxNavigationControl and MapboxFullscreenControl never load, and no diagnostic is logged.
Cause
packages/ui-mapbox/src/catalog.ts declares a single strategy for the whole package:
export const catalog: ComponentCatalog = {
packageName: '@studiometa/ui-mapbox',
strategy: 'visible',
…
};
Every one of the 14 generated manifest entries inherits strategy: 'visible'. The js-toolkit loader implements that strategy with an IntersectionObserver on the element itself. An element with the hidden attribute is not rendered, so it can never intersect the viewport, the observer callback never fires, and the dynamic import() never runs.
MapboxGeolocateControl mounts in the example above only because that element carries no hidden attribute.
This is not caught by the manifest children path either: MapboxMap deliberately no longer declares its children (packages/ui-mapbox/src/MapboxMap.ts). Each child is registered globally and resolves its map through $closest('MapboxMap'), so each child must be discovered on its own element.
The hidden attribute is the pattern the package README recommends for declarative-only elements, so the two recommendations contradict each other today.
Proposed fix
Keep visible for the rendered roots and give the declarative map children a strategy that does not depend on rendering:
scripts/manifest-types.ts — add strategy?: ComponentLoadStrategy to CuratedComponentMetadata.
scripts/generate-manifests.ts — serialize component.strategy ?? catalog.strategy.
packages/ui-mapbox/src/catalog.ts — keep the package default visible for MapboxMap and StoreLocator, and set strategy: 'eager' on the 12 map children: MapboxCluster, MapboxClusterItem, MapboxFullscreenControl, MapboxGeocoder, MapboxGeolocateControl, MapboxImage, MapboxImages, MapboxLayer, MapboxMarker, MapboxNavigationControl, MapboxPopup, MapboxSource.
- Regenerate
packages/ui-mapbox/src/manifest.ts.
eager stays cheap here: the loader only schedules tokens that are present in the markup, the child modules are small, and the heavy mapbox-gl import stays gated behind MapboxMap.mounted(). idle would also fix the bug, but it can delay controls and markers up to 2 s after the map appears.
Workaround
Override the strategy per element until this is fixed:
<div hidden data-load="eager" data-component="MapboxFullscreenControl" …></div>
Related
@studiometa/js-toolkit currently stays silent when a visible or interaction component can never receive its signal. A warning in that case would make this class of mistake obvious. That is a separate improvement to open on the js-toolkit repository if wanted.
Map children declared with
hiddennever autoload, because the whole@studiometa/ui-mapboxcatalog uses thevisiblestrategy.Reproduction
Only
MapboxGeolocateControlmounts and is added to the map.MapboxNavigationControlandMapboxFullscreenControlnever load, and no diagnostic is logged.Cause
packages/ui-mapbox/src/catalog.tsdeclares a single strategy for the whole package:Every one of the 14 generated manifest entries inherits
strategy: 'visible'. The js-toolkit loader implements that strategy with anIntersectionObserveron the element itself. An element with thehiddenattribute is not rendered, so it can never intersect the viewport, the observer callback never fires, and the dynamicimport()never runs.MapboxGeolocateControlmounts in the example above only because that element carries nohiddenattribute.This is not caught by the manifest
childrenpath either:MapboxMapdeliberately no longer declares its children (packages/ui-mapbox/src/MapboxMap.ts). Each child is registered globally and resolves its map through$closest('MapboxMap'), so each child must be discovered on its own element.The
hiddenattribute is the pattern the package README recommends for declarative-only elements, so the two recommendations contradict each other today.Proposed fix
Keep
visiblefor the rendered roots and give the declarative map children a strategy that does not depend on rendering:scripts/manifest-types.ts— addstrategy?: ComponentLoadStrategytoCuratedComponentMetadata.scripts/generate-manifests.ts— serializecomponent.strategy ?? catalog.strategy.packages/ui-mapbox/src/catalog.ts— keep the package defaultvisibleforMapboxMapandStoreLocator, and setstrategy: 'eager'on the 12 map children:MapboxCluster,MapboxClusterItem,MapboxFullscreenControl,MapboxGeocoder,MapboxGeolocateControl,MapboxImage,MapboxImages,MapboxLayer,MapboxMarker,MapboxNavigationControl,MapboxPopup,MapboxSource.packages/ui-mapbox/src/manifest.ts.eagerstays cheap here: the loader only schedules tokens that are present in the markup, the child modules are small, and the heavymapbox-glimport stays gated behindMapboxMap.mounted().idlewould also fix the bug, but it can delay controls and markers up to 2 s after the map appears.Workaround
Override the strategy per element until this is fixed:
Related
@studiometa/js-toolkitcurrently stays silent when avisibleorinteractioncomponent can never receive its signal. A warning in that case would make this class of mistake obvious. That is a separate improvement to open on the js-toolkit repository if wanted.