From 4ae1042b1a91bb38f84bd8315d4362a9cbf0fd78 Mon Sep 17 00:00:00 2001 From: "Charles Graham, SWT" Date: Sun, 12 Jul 2026 00:50:29 -0500 Subject: [PATCH 1/2] Document status marker mapping utilities --- package-lock.json | 81 +++++++---- package.json | 1 + src/app-bundles/routes-bundle.js | 2 + .../mapping/status-marker-layer.jsx | 132 ++++++++++++++++++ src/nav-links.js | 5 + 5 files changed, 191 insertions(+), 30 deletions(-) create mode 100644 src/app-pages/documentation/mapping/status-marker-layer.jsx diff --git a/package-lock.json b/package-lock.json index b3e12492..f8a278d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "redux-bundler-react": "^1.2.0" }, "devDependencies": { + "@babel/parser": "^7.29.7", "@lhci/cli": "^0.15.1", "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", @@ -53,6 +54,56 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@emnapi/core": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", @@ -894,9 +945,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -914,9 +962,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -934,9 +979,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -954,9 +996,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -974,9 +1013,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -994,9 +1030,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -5499,9 +5532,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5523,9 +5553,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5547,9 +5574,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5571,9 +5595,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ diff --git a/package.json b/package.json index dccf85e2..460b89bd 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "react-dom": "^18.2.0 || ^19.0.0" }, "devDependencies": { + "@babel/parser": "^7.29.7", "@lhci/cli": "^0.15.1", "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", diff --git a/src/app-bundles/routes-bundle.js b/src/app-bundles/routes-bundle.js index 32a607fd..9bd3d0a7 100644 --- a/src/app-bundles/routes-bundle.js +++ b/src/app-bundles/routes-bundle.js @@ -49,6 +49,7 @@ import PackageMaintenance from "../app-pages/documentation/getting-started/packa import Mapping from "../app-pages/documentation/mapping"; import MapDocs from "../app-pages/documentation/mapping/map"; import LayerDocs from "../app-pages/documentation/mapping/layer"; +import StatusMarkerLayerDocs from "../app-pages/documentation/mapping/status-marker-layer"; import GeoJSONLayerDocs from "../app-pages/documentation/mapping/geojson-layer"; import MapServerDocs from "../app-pages/documentation/mapping/map-server"; import FeatureServerDocs from "../app-pages/documentation/mapping/feature-server"; @@ -118,6 +119,7 @@ export default createRouteBundle( "/docs/mapping/map-layout": MapLayoutDocs, "/docs/mapping/map": MapDocs, "/docs/mapping/layer": LayerDocs, + "/docs/mapping/status-marker-layer": StatusMarkerLayerDocs, "/docs/mapping/geojson-layer": GeoJSONLayerDocs, "/docs/mapping/map-server": MapServerDocs, "/docs/mapping/feature-server": FeatureServerDocs, diff --git a/src/app-pages/documentation/mapping/status-marker-layer.jsx b/src/app-pages/documentation/mapping/status-marker-layer.jsx new file mode 100644 index 00000000..f4943168 --- /dev/null +++ b/src/app-pages/documentation/mapping/status-marker-layer.jsx @@ -0,0 +1,132 @@ +import { UsaceBox, Code, Text } from "../../../../lib"; +import { CodeExample } from "../../../app-components/code-example"; +import PropsTable from "../../../app-components/props-table"; +import DocsPage from "../_docs-page"; + +const BASE_URL = import.meta.env.BASE_URL; + +const pageBreadcrumbs = [ + { + text: "Documentation", + href: `${BASE_URL}#/docs`, + }, + { + text: "Mapping", + href: `${BASE_URL}#/docs/mapping`, + }, + { + text: "Status Marker Layer", + href: `${BASE_URL}#/docs/mapping/status-marker-layer`, + }, +]; + +const componentProps = [ + { + name: "source", + type: "array or GeoJSON FeatureCollection", + default: "[]", + desc: "Point records to render. GeoJSON coordinates must be longitude, latitude.", + }, + { + name: "statusAccessor", + type: "function", + default: "threshold status from statusValue or value", + desc: "Returns the status bucket used to choose the marker color. Use a numeric bucket, missing, or transparent.", + }, + { + name: "shapeAccessor", + type: "function", + default: "reservoir/project triangle, lock square, other diamond", + desc: "Returns circle, triangle, square, or diamond for each marker.", + }, + { + name: "labelAccessor", + type: "function", + default: "mapLabel, publicName, name, or id", + desc: "Returns the text label drawn above the marker.", + }, + { + name: "fit", + type: "boolean", + default: "false", + desc: "Fits the map view to the marker extent after the layer is added.", + }, + { + name: "onClick", + type: "function", + default: "undefined", + desc: "Receives the clicked OpenLayers feature and map coordinate.", + }, +]; + +function StatusMarkerLayerDocs() { + return ( + + + + StatusMarkerLayer renders point datasets with configurable status + colors, marker shapes, labels, and click handling. It is intended for + office-neutral status maps where the application owns the data query + and domain-specific grouping. + + + location.statusValue == null + ? "missing" + : getThresholdStatus(location.statusValue), + onClick: (feature) => console.log(feature.getProperties()) + }) +]; + +function Component() { + return ( +
+ + + + +
+ ); +}`} + /> +
+ Class API - {`StatusMarkerLayer`} +
+ +
+
+ ); +} + +export default StatusMarkerLayerDocs; +export { StatusMarkerLayerDocs }; diff --git a/src/nav-links.js b/src/nav-links.js index 60b5887b..20fc6988 100644 --- a/src/nav-links.js +++ b/src/nav-links.js @@ -277,6 +277,11 @@ export default [ text: "Layer", href: `${BASE_URL}#/docs/mapping/layer`, }, + { + id: "status-marker-layer", + text: "Status Marker Layer", + href: `${BASE_URL}#/docs/mapping/status-marker-layer`, + }, { id: "geojson-layer", text: "GeoJSON Layer", From e0b9a3f31157ce9f8ae1b15252b780e0c82ad93d Mon Sep 17 00:00:00 2001 From: Charles Graham Date: Mon, 13 Jul 2026 07:19:11 -0700 Subject: [PATCH 2/2] Support controlled tab selection --- lib/components/navigation/tabs.jsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/components/navigation/tabs.jsx b/lib/components/navigation/tabs.jsx index 4a4c1d09..a2329250 100644 --- a/lib/components/navigation/tabs.jsx +++ b/lib/components/navigation/tabs.jsx @@ -1,9 +1,18 @@ import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@headlessui/react"; import gwMerge from "../../gw-merge"; -function Tabs({ tabs, fill = false, defaultIndex = 0 }) { +function Tabs({ + tabs, + fill = false, + defaultIndex = 0, + selectedIndex, + onChange, +}) { + const controlledProps = + selectedIndex === undefined ? {} : { selectedIndex, onChange }; + return ( - + {tabs.map((tab, idx) => (