@classic-homes/theme-mcp 0.1.21 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +121 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.js +121 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -18114,7 +18114,7 @@ var maps_catalog_default = {
|
|
|
18114
18114
|
},
|
|
18115
18115
|
{
|
|
18116
18116
|
name: "MarkerProps",
|
|
18117
|
-
description: "Props for map markers",
|
|
18117
|
+
description: "Props for map markers. NOTE: DOM-based markers (maplibregl.Marker) are susceptible to CSS framework interference that can cause visual sliding during map pan/rotate operations. For production use cases requiring markers, consider using SymbolLayer instead, which renders on the GPU canvas and is immune to CSS interference.",
|
|
18118
18118
|
properties: [
|
|
18119
18119
|
{ name: "id", type: "string", required: false, description: "Unique marker ID" },
|
|
18120
18120
|
{ name: "coordinates", type: "[number, number]", required: true, description: "Marker position [lng, lat]" },
|
|
@@ -18898,6 +18898,126 @@ var maps_catalog_default = {
|
|
|
18898
18898
|
"Consider `maxWidth` prop for content-heavy popups"
|
|
18899
18899
|
]
|
|
18900
18900
|
},
|
|
18901
|
+
markers: {
|
|
18902
|
+
title: "Markers",
|
|
18903
|
+
guidelines: [
|
|
18904
|
+
"DOM-based Marker components use maplibregl.Marker which renders in the DOM",
|
|
18905
|
+
"DOM markers are susceptible to CSS framework interference (e.g., Tailwind) that can cause visual sliding during pan/rotate",
|
|
18906
|
+
"For production use with many markers or when CSS conflicts occur, prefer SymbolLayer which renders on the GPU canvas",
|
|
18907
|
+
"SymbolLayer is immune to CSS interference and generally performs better at scale",
|
|
18908
|
+
"Use Marker component only for simple cases or when you need custom HTML content that can't be achieved with icons",
|
|
18909
|
+
"If using DOM markers, the component applies CSS protection but this may not fully prevent sliding in all CSS environments"
|
|
18910
|
+
]
|
|
18911
|
+
},
|
|
18912
|
+
dynamicData: {
|
|
18913
|
+
title: "Dynamic Data Loading",
|
|
18914
|
+
description: "Patterns for loading and updating map data dynamically (async fetching, user interactions, etc.)",
|
|
18915
|
+
guidelines: [
|
|
18916
|
+
"For dynamic marker-like points, use Source + CircleLayer/SymbolLayer instead of individual Marker components",
|
|
18917
|
+
"When Source data prop changes, the component automatically calls source.setData() to update layers efficiently",
|
|
18918
|
+
"Convert your data array to GeoJSON FeatureCollection format using useMemo/derived to avoid unnecessary re-renders",
|
|
18919
|
+
"Layers automatically re-render when their source data changes - no need to recreate layers",
|
|
18920
|
+
"Use generateId prop on Source to enable feature state (hover effects, selection)",
|
|
18921
|
+
"For popups with SymbolLayer, use onClick handler to get feature coordinates and properties",
|
|
18922
|
+
"This approach is more performant than DOM markers: single GPU draw call vs O(n) DOM operations",
|
|
18923
|
+
"DOM Markers also support dynamic loading - they appear immediately when added after map initialization"
|
|
18924
|
+
],
|
|
18925
|
+
recommendedPattern: {
|
|
18926
|
+
name: "Dynamic SymbolLayer with Popup",
|
|
18927
|
+
description: "Recommended pattern for dynamic points with popups - GPU-based, efficient, and immune to CSS conflicts",
|
|
18928
|
+
react: `const [points, setPoints] = useState([]);
|
|
18929
|
+
|
|
18930
|
+
const geojson = useMemo(() => ({
|
|
18931
|
+
type: 'FeatureCollection',
|
|
18932
|
+
features: points.map(p => ({
|
|
18933
|
+
type: 'Feature',
|
|
18934
|
+
properties: { name: p.name, id: p.id },
|
|
18935
|
+
geometry: { type: 'Point', coordinates: p.coordinates }
|
|
18936
|
+
}))
|
|
18937
|
+
}), [points]);
|
|
18938
|
+
|
|
18939
|
+
const [selected, setSelected] = useState(null);
|
|
18940
|
+
|
|
18941
|
+
return (
|
|
18942
|
+
<Map title="Dynamic Points">
|
|
18943
|
+
<Source id="points" type="geojson" data={geojson} generateId>
|
|
18944
|
+
<CircleLayer
|
|
18945
|
+
id="circles"
|
|
18946
|
+
source="points"
|
|
18947
|
+
circleRadius={10}
|
|
18948
|
+
circleColor="#3ba4a7"
|
|
18949
|
+
onClick={(e) => setSelected({ ...e.feature.properties, coordinates: e.lngLat })}
|
|
18950
|
+
onHover={() => {}}
|
|
18951
|
+
/>
|
|
18952
|
+
<SymbolLayer
|
|
18953
|
+
id="labels"
|
|
18954
|
+
source="points"
|
|
18955
|
+
textField={['get', 'name']}
|
|
18956
|
+
textOffset={[0, 1.5]}
|
|
18957
|
+
/>
|
|
18958
|
+
</Source>
|
|
18959
|
+
{selected && (
|
|
18960
|
+
<Popup coordinates={selected.coordinates} onClose={() => setSelected(null)} closeButton>
|
|
18961
|
+
<PopupCard>
|
|
18962
|
+
<PopupHeader title={selected.name} />
|
|
18963
|
+
</PopupCard>
|
|
18964
|
+
</Popup>
|
|
18965
|
+
)}
|
|
18966
|
+
</Map>
|
|
18967
|
+
);`,
|
|
18968
|
+
svelte: `<script>
|
|
18969
|
+
let points = $state([]);
|
|
18970
|
+
let selected = $state(null);
|
|
18971
|
+
|
|
18972
|
+
const geojson = $derived({
|
|
18973
|
+
type: 'FeatureCollection',
|
|
18974
|
+
features: points.map(p => ({
|
|
18975
|
+
type: 'Feature',
|
|
18976
|
+
properties: { name: p.name, id: p.id },
|
|
18977
|
+
geometry: { type: 'Point', coordinates: p.coordinates }
|
|
18978
|
+
}))
|
|
18979
|
+
});
|
|
18980
|
+
</script>
|
|
18981
|
+
|
|
18982
|
+
<Map title="Dynamic Points">
|
|
18983
|
+
<Source id="points" type="geojson" data={geojson} generateId>
|
|
18984
|
+
<CircleLayer
|
|
18985
|
+
id="circles"
|
|
18986
|
+
source="points"
|
|
18987
|
+
circleRadius={10}
|
|
18988
|
+
circleColor="#3ba4a7"
|
|
18989
|
+
onClick={(e) => selected = { ...e.feature.properties, coordinates: e.lngLat }}
|
|
18990
|
+
onHover={() => {}}
|
|
18991
|
+
/>
|
|
18992
|
+
<SymbolLayer id="labels" source="points" textField={['get', 'name']} textOffset={[0, 1.5]} />
|
|
18993
|
+
</Source>
|
|
18994
|
+
{#if selected}
|
|
18995
|
+
<Popup coordinates={selected.coordinates} onClose={() => selected = null} closeButton>
|
|
18996
|
+
<PopupCard><PopupHeader title={selected.name} /></PopupCard>
|
|
18997
|
+
</Popup>
|
|
18998
|
+
{/if}
|
|
18999
|
+
</Map>`
|
|
19000
|
+
},
|
|
19001
|
+
comparisonTable: {
|
|
19002
|
+
description: "Comparison of dynamic data approaches",
|
|
19003
|
+
approaches: [
|
|
19004
|
+
{
|
|
19005
|
+
name: "Source + SymbolLayer (Recommended)",
|
|
19006
|
+
updateMechanism: "source.setData() on existing source",
|
|
19007
|
+
performance: "Single GPU draw call",
|
|
19008
|
+
cssImmunity: "Yes - rendered on canvas",
|
|
19009
|
+
useCase: "Most marker-like use cases, especially with many points"
|
|
19010
|
+
},
|
|
19011
|
+
{
|
|
19012
|
+
name: "DOM Markers",
|
|
19013
|
+
updateMechanism: "Create/destroy marker instances",
|
|
19014
|
+
performance: "O(n) DOM operations",
|
|
19015
|
+
cssImmunity: "No - CSS protection applied but not guaranteed",
|
|
19016
|
+
useCase: "Custom HTML content that can't be achieved with icons"
|
|
19017
|
+
}
|
|
19018
|
+
]
|
|
19019
|
+
}
|
|
19020
|
+
},
|
|
18901
19021
|
mapboxMigration: {
|
|
18902
19022
|
title: "Migrating from Mapbox GL",
|
|
18903
19023
|
differences: [
|