@teamimpact/veda-ui-blocks 0.1.0-beta.7 → 0.1.0-beta.8
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/README.md +2 -3
- package/dist/default.css +1388 -407
- package/dist/default.css.map +1 -1
- package/dist/disasters.css +1137 -151
- package/dist/disasters.css.map +1 -1
- package/dist/index.d.ts +110 -40
- package/dist/index.js +484 -54
- package/package.json +4 -6
- package/src/styles/components/banner.scss +0 -18
- package/src/styles/components/card-cta.scss +0 -90
- package/src/styles/components/card-detailed.scss +0 -164
- package/src/styles/components/card-mini.scss +0 -81
- package/src/styles/components/card-simple.scss +0 -79
- package/src/styles/components/card.scss +0 -284
- package/src/styles/components/compare-map.scss +0 -15
- package/src/styles/components/footer.scss +0 -256
- package/src/styles/components/header.scss +0 -212
- package/src/styles/components/index.scss +0 -11
- package/src/styles/components/tag.scss +0 -89
- package/src/styles/default/index.scss +0 -10
- package/src/styles/default/theme-tokens.scss +0 -84
- package/src/styles/disasters/card-cta.scss +0 -31
- package/src/styles/disasters/card-mini.scss +0 -4
- package/src/styles/disasters/card-simple.scss +0 -13
- package/src/styles/disasters/card.scss +0 -13
- package/src/styles/disasters/compare-map.scss +0 -3
- package/src/styles/disasters/fonts.scss +0 -29
- package/src/styles/disasters/footer.scss +0 -9
- package/src/styles/disasters/header.scss +0 -10
- package/src/styles/disasters/index.scss +0 -22
- package/src/styles/disasters/tag.scss +0 -6
- package/src/styles/disasters/theme-tokens.scss +0 -150
- package/src/styles/earthgov/footer.scss +0 -15
- package/src/styles/earthgov/index.scss +0 -12
- package/src/styles/earthgov/theme-tokens.scss +0 -104
package/dist/index.js
CHANGED
|
@@ -19,9 +19,13 @@ var isNull = (x) => x === null;
|
|
|
19
19
|
var isUndefined = (x) => x === void 0;
|
|
20
20
|
var isNil = (x) => isNull(x) || isUndefined(x);
|
|
21
21
|
var isDefined = (x) => !isNil(x);
|
|
22
|
+
var isNumber = (x) => typeof x === "number";
|
|
22
23
|
var isObject = (x) => !isNil(x) && typeof x === "object" && x instanceof Object;
|
|
24
|
+
var isEmptyObject = (x) => isObject(x) && isEmptyArray(Object.keys(x));
|
|
23
25
|
var isArray = (as) => Array.isArray(as);
|
|
26
|
+
var isEmptyArray = (as) => isArray(as) && as.length === 0;
|
|
24
27
|
var isNonEmptyArray = (as) => isArray(as) && as.length > 0;
|
|
28
|
+
var getTypedValues = Object.values;
|
|
25
29
|
|
|
26
30
|
// src/utils/component-utils.tsx
|
|
27
31
|
var get_external_anchor_props = (isExternal) => isExternal ? { target: "_blank", rel: "noopener noreferrer" } : {};
|
|
@@ -228,31 +232,32 @@ function CardDetailed({
|
|
|
228
232
|
title,
|
|
229
233
|
description,
|
|
230
234
|
tags = [],
|
|
231
|
-
|
|
235
|
+
callToAction,
|
|
236
|
+
callToActionSecondary,
|
|
237
|
+
tagPrimary,
|
|
232
238
|
image,
|
|
233
|
-
action,
|
|
234
239
|
imagePosition = "top",
|
|
235
|
-
borderAccent = false,
|
|
236
|
-
titleAs = "h2",
|
|
237
240
|
className = ""
|
|
238
241
|
}) {
|
|
239
|
-
const
|
|
240
|
-
const cardClassName = make_class_name("blocks-card-detailed", [
|
|
242
|
+
const rootClassName = make_class_name("blocks-card-detailed", [
|
|
241
243
|
imagePosition !== "top" ? `blocks-card-detailed--image-${imagePosition}` : "",
|
|
242
244
|
className
|
|
243
245
|
]);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
/* @__PURE__ */ jsxs4("div", { className: "blocks-card-
|
|
247
|
-
intro && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__intro", children: intro }),
|
|
248
|
-
/* @__PURE__ */ jsx5(TitleTag, { className: "blocks-card-detailed__title", children: title }),
|
|
249
|
-
description && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__description", children: description }),
|
|
250
|
-
isNonEmptyArray(tags) && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__tags", children: tags }),
|
|
251
|
-
action && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__action", children: action })
|
|
252
|
-
] }),
|
|
253
|
-
/* @__PURE__ */ jsxs4("div", { className: "blocks-card-detailed__image-wrapper", children: [
|
|
246
|
+
const hasContent = intro || title || description || tags.length || callToAction || callToActionSecondary;
|
|
247
|
+
return /* @__PURE__ */ jsxs4("div", { className: rootClassName, children: [
|
|
248
|
+
/* @__PURE__ */ jsxs4("div", { className: "blocks-card-detailed__media", children: [
|
|
254
249
|
image,
|
|
255
|
-
|
|
250
|
+
tagPrimary && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__tag-primary", children: tagPrimary })
|
|
251
|
+
] }),
|
|
252
|
+
hasContent && /* @__PURE__ */ jsxs4("div", { className: "blocks-card-detailed__content-container", children: [
|
|
253
|
+
intro && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__intro", title: intro, children: intro }),
|
|
254
|
+
title && (typeof title === "string" ? /* @__PURE__ */ jsx5("h2", { className: "blocks-card-detailed__title", title, children: title }) : title),
|
|
255
|
+
isNonEmptyArray(tags) && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__tags", children: tags }),
|
|
256
|
+
description && /* @__PURE__ */ jsx5("p", { className: "blocks-card-detailed__description", children: description }),
|
|
257
|
+
(callToAction || callToActionSecondary) && /* @__PURE__ */ jsxs4("div", { className: "blocks-card-detailed__actions", children: [
|
|
258
|
+
callToAction && /* @__PURE__ */ jsx5("a", { href: callToAction.href, className: "usa-button", children: callToAction.label }),
|
|
259
|
+
callToActionSecondary && /* @__PURE__ */ jsx5("a", { href: callToActionSecondary.href, className: "usa-button usa-button--outline", children: callToActionSecondary.label })
|
|
260
|
+
] })
|
|
256
261
|
] })
|
|
257
262
|
] });
|
|
258
263
|
}
|
|
@@ -282,21 +287,19 @@ function CardSimple({
|
|
|
282
287
|
image,
|
|
283
288
|
url,
|
|
284
289
|
tag,
|
|
285
|
-
showOverlay = false,
|
|
286
290
|
size = "default",
|
|
287
291
|
titleAs = "h2",
|
|
288
292
|
className
|
|
289
293
|
}) {
|
|
290
294
|
const TitleTag = titleAs;
|
|
291
295
|
const rootClassName = make_class_name("blocks-card-simple", [
|
|
292
|
-
showOverlay ? "blocks-card-simple--with-overlay" : void 0,
|
|
293
296
|
size === "compact" ? "blocks-card-simple--compact" : void 0,
|
|
294
297
|
className
|
|
295
298
|
]);
|
|
296
299
|
return /* @__PURE__ */ jsxs6("a", { href: url, className: rootClassName, children: [
|
|
297
300
|
/* @__PURE__ */ jsxs6("div", { className: "blocks-card-simple__media", children: [
|
|
298
301
|
image,
|
|
299
|
-
|
|
302
|
+
/* @__PURE__ */ jsx7("div", { className: "blocks-card-simple__overlay", "aria-hidden": "true" })
|
|
300
303
|
] }),
|
|
301
304
|
/* @__PURE__ */ jsxs6("div", { className: "blocks-card-simple__body", children: [
|
|
302
305
|
tag && /* @__PURE__ */ jsx7("div", { className: "blocks-card-simple__tag", children: tag }),
|
|
@@ -321,24 +324,24 @@ function Footer({
|
|
|
321
324
|
{
|
|
322
325
|
className: footerClassName,
|
|
323
326
|
size: "slim",
|
|
324
|
-
primary: /* @__PURE__ */
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
/* @__PURE__ */ jsxs7("div", { className: "blocks-footer__title", children: [
|
|
327
|
+
primary: /* @__PURE__ */ jsx8(GridContainer, { children: /* @__PURE__ */ jsxs7("section", { className: "blocks-footer__primary-section", children: [
|
|
328
|
+
/* @__PURE__ */ jsxs7("div", { className: "blocks-footer__title", children: [
|
|
329
|
+
portalDetails.logo ? /* @__PURE__ */ jsx8("div", { className: "blocks-footer__logo", children: portalDetails.logo }) : null,
|
|
330
|
+
/* @__PURE__ */ jsxs7("div", { className: "blocks-footer__title-text", children: [
|
|
328
331
|
/* @__PURE__ */ jsx8("span", { children: portalDetails.title }),
|
|
329
332
|
portalDetails.tagline ? /* @__PURE__ */ jsx8("p", { children: portalDetails.tagline }) : null
|
|
330
|
-
] })
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
] }),
|
|
333
|
+
] })
|
|
334
|
+
] }),
|
|
335
|
+
primaryNavItems.length > 0 ? /* @__PURE__ */ jsx8("nav", { className: "blocks-footer__primary-nav", "aria-label": "Footer primary navigation", children: /* @__PURE__ */ jsx8("ul", { children: primaryNavItems.map(({ label, href, isExternal }) => /* @__PURE__ */ jsx8("li", { className: "usa-footer__primary-content", children: /* @__PURE__ */ jsx8(
|
|
336
|
+
Link,
|
|
337
|
+
{
|
|
338
|
+
className: "usa-footer__primary-link",
|
|
339
|
+
href,
|
|
340
|
+
...get_external_anchor_props(isExternal),
|
|
341
|
+
children: label
|
|
342
|
+
}
|
|
343
|
+
) }, href)) }) }) : null
|
|
344
|
+
] }) }),
|
|
342
345
|
secondary: /* @__PURE__ */ jsxs7(Fragment, { children: [
|
|
343
346
|
secondaryNavItems.length > 0 ? /* @__PURE__ */ jsx8("section", { className: "blocks-footer__secondary-section-upper", children: /* @__PURE__ */ jsx8(
|
|
344
347
|
"nav",
|
|
@@ -351,6 +354,7 @@ function Footer({
|
|
|
351
354
|
utilityNavItems?.length || portalDetails.updatedDate || portalDetails.contacts?.length ? /* @__PURE__ */ jsxs7("section", { className: "blocks-footer__secondary-section-lower", children: [
|
|
352
355
|
utilityNavItems?.length ? /* @__PURE__ */ jsx8("nav", { className: "blocks-footer__utility-nav", "aria-label": "Site utilities", children: /* @__PURE__ */ jsx8("ul", { children: utilityNavItems.length ? utilityNavItems.map(({ text, label, href, isExternal }) => /* @__PURE__ */ jsxs7("li", { children: [
|
|
353
356
|
text,
|
|
357
|
+
" ",
|
|
354
358
|
/* @__PURE__ */ jsx8(Link, { href, ...get_external_anchor_props(isExternal), children: label })
|
|
355
359
|
] }, href)) : null }) }) : null,
|
|
356
360
|
portalDetails.updatedDate || portalDetails.contacts?.length ? /* @__PURE__ */ jsxs7("div", { className: "blocks-footer__secondary-meta", children: [
|
|
@@ -622,8 +626,185 @@ function Tag({
|
|
|
622
626
|
] });
|
|
623
627
|
}
|
|
624
628
|
|
|
625
|
-
// src/geo/
|
|
626
|
-
import {
|
|
629
|
+
// src/geo/Legend/Legend.tsx
|
|
630
|
+
import { Icon as Icon3 } from "@trussworks/react-uswds";
|
|
631
|
+
import { useState as useState3 } from "react";
|
|
632
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
633
|
+
function Legend({ initialExpanded = false, ...props }) {
|
|
634
|
+
const { title, description, unit, min, max, colorStops, provider, spatialExtent, timeDensity } = props;
|
|
635
|
+
const [isExpanded, setIsExpanded] = useState3(initialExpanded);
|
|
636
|
+
const subtitle = [provider, spatialExtent, timeDensity].some(isDefined) ? [provider, spatialExtent, timeDensity].filter(isDefined).join(" \xB7 ") : void 0;
|
|
637
|
+
return /* @__PURE__ */ jsxs11("div", { className: "blocks-legend", children: [
|
|
638
|
+
/* @__PURE__ */ jsxs11("div", { className: "blocks-legend__header", children: [
|
|
639
|
+
/* @__PURE__ */ jsxs11("div", { className: "blocks-legend__header-text", children: [
|
|
640
|
+
title && /* @__PURE__ */ jsx12("h3", { className: "blocks-legend__title", title, children: title }),
|
|
641
|
+
subtitle && /* @__PURE__ */ jsx12("p", { className: "blocks-legend__subtitle", title: subtitle, children: subtitle })
|
|
642
|
+
] }),
|
|
643
|
+
description && /* @__PURE__ */ jsx12(
|
|
644
|
+
"button",
|
|
645
|
+
{
|
|
646
|
+
type: "button",
|
|
647
|
+
className: "blocks-legend__info-toggle",
|
|
648
|
+
"aria-expanded": isExpanded,
|
|
649
|
+
"aria-label": "Toggle layer description",
|
|
650
|
+
onClick: () => setIsExpanded((v) => !v),
|
|
651
|
+
children: /* @__PURE__ */ jsx12(Icon3.InfoOutline, { "aria-hidden": true, focusable: false, size: 3 })
|
|
652
|
+
}
|
|
653
|
+
)
|
|
654
|
+
] }),
|
|
655
|
+
/* @__PURE__ */ jsx12("div", { className: "blocks-legend__gradient-bar", children: /* @__PURE__ */ jsx12(
|
|
656
|
+
"div",
|
|
657
|
+
{
|
|
658
|
+
className: "blocks-legend__gradient",
|
|
659
|
+
style: {
|
|
660
|
+
background: `linear-gradient(to right, ${colorStops.join(", ")})`
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
) }),
|
|
664
|
+
/* @__PURE__ */ jsxs11("div", { className: "blocks-legend__labels", children: [
|
|
665
|
+
/* @__PURE__ */ jsx12("span", { className: "blocks-legend__min", children: min }),
|
|
666
|
+
/* @__PURE__ */ jsx12("span", { className: "blocks-legend__unit", children: unit }),
|
|
667
|
+
/* @__PURE__ */ jsx12("span", { className: "blocks-legend__max", children: max })
|
|
668
|
+
] }),
|
|
669
|
+
isExpanded && description && /* @__PURE__ */ jsx12("div", { className: "blocks-legend__description", children: /* @__PURE__ */ jsx12("div", { className: "blocks-legend__description-inner", children: description }) })
|
|
670
|
+
] });
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// src/geo/StacCompareMap/StacCompareMap.tsx
|
|
674
|
+
import { useEffect as useEffect3, useId, useRef as useRef3, useState as useState4 } from "react";
|
|
675
|
+
import {
|
|
676
|
+
Layer,
|
|
677
|
+
Map as MapLibreMap,
|
|
678
|
+
NavigationControl,
|
|
679
|
+
Source
|
|
680
|
+
} from "react-map-gl/maplibre";
|
|
681
|
+
|
|
682
|
+
// src/geo/AttributionMapControl.tsx
|
|
683
|
+
import maplibregl from "maplibre-gl";
|
|
684
|
+
import { useControl } from "react-map-gl/maplibre";
|
|
685
|
+
function AttributionMapControl({ position = "top-right" }) {
|
|
686
|
+
useControl(() => new maplibregl.AttributionControl(), { position });
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// src/geo/utils/formatDateRange.ts
|
|
691
|
+
function formatDateRange(dateRange) {
|
|
692
|
+
const from = /* @__PURE__ */ new Date(`${dateRange.from}T00:00:00Z`);
|
|
693
|
+
const to = /* @__PURE__ */ new Date(`${dateRange.to}T00:00:00Z`);
|
|
694
|
+
if (from.getUTCFullYear() === to.getUTCFullYear() && from.getUTCMonth() === to.getUTCMonth()) {
|
|
695
|
+
return from.toLocaleDateString("en-US", {
|
|
696
|
+
month: "short",
|
|
697
|
+
year: "numeric",
|
|
698
|
+
timeZone: "UTC"
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
const fromStr = from.toLocaleDateString("en-US", {
|
|
702
|
+
month: "short",
|
|
703
|
+
day: "numeric",
|
|
704
|
+
year: "numeric",
|
|
705
|
+
timeZone: "UTC"
|
|
706
|
+
});
|
|
707
|
+
const toStr = to.toLocaleDateString("en-US", {
|
|
708
|
+
month: "short",
|
|
709
|
+
day: "numeric",
|
|
710
|
+
year: "numeric",
|
|
711
|
+
timeZone: "UTC"
|
|
712
|
+
});
|
|
713
|
+
return `${fromStr} \u2013 ${toStr}`;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// src/geo/DateChip/DateChip.tsx
|
|
717
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
718
|
+
function DateChip({ left, right }) {
|
|
719
|
+
const label = right === void 0 || left.from === right.from && left.to === right.to ? formatDateRange(left) : `${formatDateRange(left)} vs ${formatDateRange(right)}`;
|
|
720
|
+
return /* @__PURE__ */ jsx13("div", { className: "blocks-date-chip", children: label });
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// src/geo/hooks/useStacRasterLayer.ts
|
|
724
|
+
import { useCollection } from "@developmentseed/stac-react";
|
|
725
|
+
|
|
726
|
+
// src/geo/hooks/useMosaicTiles.ts
|
|
727
|
+
import { useQuery } from "@tanstack/react-query";
|
|
728
|
+
|
|
729
|
+
// src/geo/api/titiler/fetchTilejson.ts
|
|
730
|
+
async function fetchTilejson(tilejsonUrl, queryString) {
|
|
731
|
+
const response = await fetch(`${tilejsonUrl}?${queryString}`);
|
|
732
|
+
if (!response.ok) {
|
|
733
|
+
const error = { detail: `Failed to fetch tilejson: ${response.statusText}` };
|
|
734
|
+
throw error;
|
|
735
|
+
}
|
|
736
|
+
const tilejson = await response.json();
|
|
737
|
+
if (!tilejson.tiles?.[0]) {
|
|
738
|
+
const error = { detail: "No tile URL found in response" };
|
|
739
|
+
throw error;
|
|
740
|
+
}
|
|
741
|
+
return tilejson.tiles[0];
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// src/geo/api/titiler/mosaicLinks.ts
|
|
745
|
+
function findTileLink(links) {
|
|
746
|
+
return links.find((link) => link.rel === "tiles") ?? links.at(1) ?? links.at(0) ?? null;
|
|
747
|
+
}
|
|
748
|
+
function buildTilejsonUrl(tileLinkHref, tileMatrixSet) {
|
|
749
|
+
return tileLinkHref.replace("/{tileMatrixSetId}", `/${tileMatrixSet}`);
|
|
750
|
+
}
|
|
751
|
+
function extractTileUrl(registrationResponse, tileMatrixSet) {
|
|
752
|
+
const tileLink = findTileLink(registrationResponse.links);
|
|
753
|
+
if (!tileLink?.href) {
|
|
754
|
+
const error = { detail: "No tile URL found in registration response" };
|
|
755
|
+
throw error;
|
|
756
|
+
}
|
|
757
|
+
const tilejsonUrl = buildTilejsonUrl(tileLink.href, tileMatrixSet);
|
|
758
|
+
return tilejsonUrl;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/geo/api/titiler/registerMosaic.ts
|
|
762
|
+
async function registerMosaic(request) {
|
|
763
|
+
const { rasterApiUrl, collectionId, datetime } = request;
|
|
764
|
+
const response = await fetch(`${rasterApiUrl}/searches/register`, {
|
|
765
|
+
method: "POST",
|
|
766
|
+
headers: { "Content-Type": "application/json" },
|
|
767
|
+
body: JSON.stringify({
|
|
768
|
+
collections: [collectionId],
|
|
769
|
+
datetime
|
|
770
|
+
})
|
|
771
|
+
});
|
|
772
|
+
if (!response.ok) {
|
|
773
|
+
const error = {
|
|
774
|
+
detail: `Failed to register mosaic: ${response.statusText}`,
|
|
775
|
+
status: response.status
|
|
776
|
+
};
|
|
777
|
+
throw error;
|
|
778
|
+
}
|
|
779
|
+
return response.json();
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// src/geo/api/titiler/fetchMosaicTileUrl.ts
|
|
783
|
+
var TILE_PARAMS = {
|
|
784
|
+
ASSETS: "assets",
|
|
785
|
+
RESCALE: "rescale",
|
|
786
|
+
RESAMPLING: "resampling",
|
|
787
|
+
COLORMAP_NAME: "colormap_name",
|
|
788
|
+
BIDX: "bidx"
|
|
789
|
+
};
|
|
790
|
+
function buildQueryParams(sourceParams) {
|
|
791
|
+
const params = new URLSearchParams();
|
|
792
|
+
if (sourceParams.assets) params.append(TILE_PARAMS.ASSETS, sourceParams.assets.join(","));
|
|
793
|
+
if (sourceParams.rescale) params.append(TILE_PARAMS.RESCALE, sourceParams.rescale);
|
|
794
|
+
if (sourceParams.resampling) params.append(TILE_PARAMS.RESAMPLING, sourceParams.resampling);
|
|
795
|
+
if (sourceParams.colormap_name)
|
|
796
|
+
params.append(TILE_PARAMS.COLORMAP_NAME, sourceParams.colormap_name);
|
|
797
|
+
if (sourceParams.bidx) params.append(TILE_PARAMS.BIDX, sourceParams.bidx.join(","));
|
|
798
|
+
return params;
|
|
799
|
+
}
|
|
800
|
+
async function fetchMosaicTileUrl(request) {
|
|
801
|
+
const { sourceParams, tileMatrixSet } = request;
|
|
802
|
+
const queryParams = buildQueryParams(sourceParams);
|
|
803
|
+
const queryString = queryParams.toString();
|
|
804
|
+
const registrationResponse = await registerMosaic(request);
|
|
805
|
+
const tilejsonUrl = extractTileUrl(registrationResponse, tileMatrixSet);
|
|
806
|
+
return fetchTilejson(tilejsonUrl, queryString);
|
|
807
|
+
}
|
|
627
808
|
|
|
628
809
|
// src/geo/constants.ts
|
|
629
810
|
var NASA_BLUE_MARBLE_BASEMAP_STYLE = {
|
|
@@ -647,25 +828,272 @@ var NASA_BLUE_MARBLE_BASEMAP_STYLE = {
|
|
|
647
828
|
}
|
|
648
829
|
]
|
|
649
830
|
};
|
|
831
|
+
var TITILER_BASE_URL = "https://openveda.cloud/api/raster";
|
|
832
|
+
var DEFAULT_RENDER_PARAMS = {
|
|
833
|
+
assets: ["cog_default"],
|
|
834
|
+
rescale: "0,0.0001",
|
|
835
|
+
resampling: "bilinear",
|
|
836
|
+
colormap_name: "viridis",
|
|
837
|
+
bidx: [1]
|
|
838
|
+
};
|
|
839
|
+
var DEFAULT_TILE_MATRIX_SET = "WebMercatorQuad";
|
|
840
|
+
var STAC_COLORSTOP_RGBA_ARG_COUNT = 4;
|
|
650
841
|
|
|
651
|
-
// src/geo/
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
842
|
+
// src/geo/hooks/useMosaicTiles.ts
|
|
843
|
+
function useMosaicTiles(rasterLayerConfig) {
|
|
844
|
+
const { collectionId, dateRange, tileMatrixSet = DEFAULT_TILE_MATRIX_SET } = rasterLayerConfig;
|
|
845
|
+
const datetime = dateRange.from === dateRange.to ? dateRange.from : `${dateRange.from}/${dateRange.to}`;
|
|
846
|
+
const request = {
|
|
847
|
+
rasterApiUrl: TITILER_BASE_URL,
|
|
848
|
+
collectionId,
|
|
849
|
+
datetime,
|
|
850
|
+
sourceParams: {
|
|
851
|
+
...DEFAULT_RENDER_PARAMS,
|
|
852
|
+
assets: [...DEFAULT_RENDER_PARAMS.assets],
|
|
853
|
+
bidx: [...DEFAULT_RENDER_PARAMS.bidx]
|
|
854
|
+
},
|
|
855
|
+
tileMatrixSet
|
|
856
|
+
};
|
|
857
|
+
return useQuery({
|
|
858
|
+
queryKey: [collectionId, dateRange],
|
|
859
|
+
queryFn: () => fetchMosaicTileUrl(request),
|
|
860
|
+
staleTime: 30 * 60 * 1e3,
|
|
861
|
+
gcTime: 60 * 60 * 1e3,
|
|
862
|
+
enabled: !!collectionId && !!dateRange?.from && !!dateRange?.to
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/geo/hooks/useStacRasterLegend.ts
|
|
867
|
+
import { useQuery as useQuery2 } from "@tanstack/react-query";
|
|
868
|
+
|
|
869
|
+
// src/geo/utils/stac.formatters.ts
|
|
870
|
+
var formatSpatialExtent = (spatialExtent) => {
|
|
871
|
+
const [minX, minY, maxX, maxY] = spatialExtent?.bbox?.[0] ?? [];
|
|
872
|
+
if (minX === void 0 || minY === void 0 || maxX === void 0 || maxY === void 0)
|
|
873
|
+
return void 0;
|
|
874
|
+
return maxX - minX >= 359 && maxY - minY >= 179 ? "global" : "regional";
|
|
875
|
+
};
|
|
876
|
+
|
|
877
|
+
// src/geo/utils/stac.typeguards.ts
|
|
878
|
+
var isRgbaColorStopMap = (value) => {
|
|
879
|
+
return !isNil(value) && isObject(value) && !isEmptyObject(value) && getTypedValues(value).every(
|
|
880
|
+
(rgba) => isArray(rgba) && rgba.length === STAC_COLORSTOP_RGBA_ARG_COUNT && rgba.every(isNumber)
|
|
881
|
+
);
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// src/geo/utils/extractLegendProps.ts
|
|
885
|
+
function extractLegendProps(collection, colorStopMap) {
|
|
886
|
+
const rescale = collection.renders?.dashboard?.rescale?.[0];
|
|
887
|
+
if (!rescale) return null;
|
|
888
|
+
if (!isRgbaColorStopMap(colorStopMap)) return null;
|
|
889
|
+
const colorStops = getTypedValues(colorStopMap).map((rgba) => `rgba(${rgba.join(",")})`);
|
|
890
|
+
const title = collection.title;
|
|
891
|
+
const description = collection.description;
|
|
892
|
+
const provider = collection.providers?.[0]?.name;
|
|
893
|
+
const timeDensity = collection.properties?.["dashboard:time_density"];
|
|
894
|
+
const spatialExtent = formatSpatialExtent(collection.extent?.spatial);
|
|
895
|
+
const unit = collection.item_assets?.cog_default?.["raster:bands"]?.[0]?.unit;
|
|
896
|
+
return {
|
|
897
|
+
type: "gradient",
|
|
898
|
+
...title && { title },
|
|
899
|
+
...description && { description },
|
|
900
|
+
min: rescale[0],
|
|
901
|
+
max: rescale[1],
|
|
902
|
+
colorStops,
|
|
903
|
+
...provider && { provider },
|
|
904
|
+
...timeDensity && { timeDensity },
|
|
905
|
+
...spatialExtent && { spatialExtent },
|
|
906
|
+
...unit && { unit }
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// src/geo/hooks/useStacRasterLegend.ts
|
|
911
|
+
function useStacRasterLegend(collection) {
|
|
912
|
+
const query = useQuery2({
|
|
913
|
+
queryKey: ["legend", collection],
|
|
914
|
+
queryFn: async () => {
|
|
915
|
+
if (!collection) return null;
|
|
916
|
+
const colormapName = collection?.renders?.dashboard?.colormap_name;
|
|
917
|
+
if (!colormapName) return null;
|
|
918
|
+
const response = await fetch(`${TITILER_BASE_URL}/colorMaps/${colormapName}`);
|
|
919
|
+
if (!response.ok) {
|
|
920
|
+
const error = {
|
|
921
|
+
detail: `Colormap "${colormapName}" not found (HTTP ${response.status})`,
|
|
922
|
+
status: response.status
|
|
923
|
+
};
|
|
924
|
+
throw error;
|
|
925
|
+
}
|
|
926
|
+
const colorMap = await response.json();
|
|
927
|
+
return extractLegendProps(collection, colorMap);
|
|
928
|
+
},
|
|
929
|
+
enabled: !!collection
|
|
930
|
+
});
|
|
931
|
+
return {
|
|
932
|
+
legend: query.data ?? null,
|
|
933
|
+
isLoading: query.isLoading,
|
|
934
|
+
error: query.error || null
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// src/geo/hooks/useStacRasterLayer.ts
|
|
939
|
+
function useStacRasterLayer(rasterLayerConfig) {
|
|
940
|
+
const { collectionId } = rasterLayerConfig;
|
|
941
|
+
const {
|
|
942
|
+
collection,
|
|
943
|
+
isLoading: isLoadingCollection,
|
|
944
|
+
error: collectionError
|
|
945
|
+
} = useCollection(collectionId);
|
|
946
|
+
const {
|
|
947
|
+
data: tiles,
|
|
948
|
+
isLoading: tilesetLoading,
|
|
949
|
+
error: tilesetError
|
|
950
|
+
} = useMosaicTiles(rasterLayerConfig);
|
|
951
|
+
const {
|
|
952
|
+
legend,
|
|
953
|
+
isLoading: isLoadingLegend,
|
|
954
|
+
error: legendError
|
|
955
|
+
} = useStacRasterLegend(collection);
|
|
956
|
+
return {
|
|
957
|
+
mapSource: {
|
|
958
|
+
tiles: tiles ?? null
|
|
959
|
+
},
|
|
960
|
+
legend,
|
|
961
|
+
isLoading: isLoadingCollection || tilesetLoading || isLoadingLegend,
|
|
962
|
+
error: collectionError || tilesetError || legendError || null
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// src/geo/StacCompareMap/StacCompareMap.tsx
|
|
967
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
968
|
+
var MAP_PANEL_STYLE = {
|
|
969
|
+
position: "absolute",
|
|
970
|
+
top: 0,
|
|
971
|
+
bottom: 0,
|
|
972
|
+
width: "100%"
|
|
973
|
+
};
|
|
974
|
+
function StacCompareMap({
|
|
975
|
+
baseMapStyle,
|
|
976
|
+
initialViewState,
|
|
977
|
+
leftLayerConfig,
|
|
978
|
+
rightLayerConfig,
|
|
979
|
+
className
|
|
980
|
+
}) {
|
|
981
|
+
const instanceId = useId();
|
|
982
|
+
const leftMapRef = useRef3(null);
|
|
983
|
+
const rightMapRef = useRef3(null);
|
|
984
|
+
const compareRef = useRef3(null);
|
|
985
|
+
const containerRef = useRef3(null);
|
|
986
|
+
const [leftMapLoaded, setLeftMapLoaded] = useState4(false);
|
|
987
|
+
const [rightMapLoaded, setRightMapLoaded] = useState4(false);
|
|
988
|
+
const containerClassName = make_class_name("blocks-stacmap-compare", [className]);
|
|
989
|
+
const left = useStacRasterLayer(leftLayerConfig);
|
|
990
|
+
const right = useStacRasterLayer(rightLayerConfig);
|
|
991
|
+
const isSameCollection = leftLayerConfig.collectionId === rightLayerConfig.collectionId;
|
|
992
|
+
const leftSourceId = `${leftLayerConfig.collectionId}-raster-source-left-${instanceId}`;
|
|
993
|
+
const leftLayerId = `${leftLayerConfig.collectionId}-raster-layer-left-${instanceId}`;
|
|
994
|
+
const rightSourceId = `${rightLayerConfig.collectionId}-raster-source-right-${instanceId}`;
|
|
995
|
+
const rightLayerId = `${rightLayerConfig.collectionId}-raster-layer-right-${instanceId}`;
|
|
996
|
+
useEffect3(() => {
|
|
997
|
+
if (!leftMapLoaded || !rightMapLoaded) return;
|
|
998
|
+
if (compareRef.current) return;
|
|
999
|
+
const leftMap = leftMapRef.current?.getMap();
|
|
1000
|
+
const rightMap = rightMapRef.current?.getMap();
|
|
1001
|
+
const container = containerRef.current;
|
|
1002
|
+
if (!leftMap || !rightMap || !container) return;
|
|
1003
|
+
import("mapbox-gl-compare").then(({ default: MapboxCompare }) => {
|
|
1004
|
+
if (compareRef.current) return;
|
|
1005
|
+
try {
|
|
1006
|
+
compareRef.current = new MapboxCompare(leftMap, rightMap, container, {
|
|
1007
|
+
mousemove: false,
|
|
1008
|
+
orientation: "vertical"
|
|
1009
|
+
});
|
|
1010
|
+
} catch (error) {
|
|
1011
|
+
console.error("Failed to initialize mapbox-gl-compare:", error);
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
1014
|
+
}, [leftMapLoaded, rightMapLoaded]);
|
|
1015
|
+
useEffect3(() => {
|
|
1016
|
+
return () => {
|
|
1017
|
+
compareRef.current?.remove();
|
|
1018
|
+
compareRef.current = null;
|
|
1019
|
+
};
|
|
1020
|
+
}, []);
|
|
1021
|
+
const mapProps = {
|
|
1022
|
+
...baseMapStyle && { mapStyle: baseMapStyle },
|
|
1023
|
+
...initialViewState && { initialViewState },
|
|
1024
|
+
style: MAP_PANEL_STYLE
|
|
1025
|
+
};
|
|
1026
|
+
return /* @__PURE__ */ jsxs12("div", { ref: containerRef, className: containerClassName, children: [
|
|
1027
|
+
/* @__PURE__ */ jsxs12(
|
|
1028
|
+
MapLibreMap,
|
|
1029
|
+
{
|
|
1030
|
+
ref: leftMapRef,
|
|
1031
|
+
...mapProps,
|
|
1032
|
+
attributionControl: false,
|
|
1033
|
+
onLoad: () => setLeftMapLoaded(true),
|
|
1034
|
+
children: [
|
|
1035
|
+
/* @__PURE__ */ jsx14(AttributionMapControl, {}),
|
|
1036
|
+
/* @__PURE__ */ jsx14(NavigationControl, { position: "top-left", showCompass: false }),
|
|
1037
|
+
left.mapSource.tiles && /* @__PURE__ */ jsx14(Source, { id: leftSourceId, type: "raster", tiles: [left.mapSource.tiles], children: /* @__PURE__ */ jsx14(Layer, { id: leftLayerId, type: "raster" }) })
|
|
1038
|
+
]
|
|
1039
|
+
}
|
|
1040
|
+
),
|
|
1041
|
+
/* @__PURE__ */ jsxs12(
|
|
1042
|
+
MapLibreMap,
|
|
1043
|
+
{
|
|
1044
|
+
ref: rightMapRef,
|
|
1045
|
+
...mapProps,
|
|
1046
|
+
attributionControl: false,
|
|
1047
|
+
onLoad: () => setRightMapLoaded(true),
|
|
1048
|
+
children: [
|
|
1049
|
+
/* @__PURE__ */ jsx14(AttributionMapControl, {}),
|
|
1050
|
+
right.mapSource.tiles && /* @__PURE__ */ jsx14(Source, { id: rightSourceId, type: "raster", tiles: [right.mapSource.tiles], children: /* @__PURE__ */ jsx14(Layer, { id: rightLayerId, type: "raster" }) })
|
|
1051
|
+
]
|
|
1052
|
+
}
|
|
1053
|
+
),
|
|
1054
|
+
/* @__PURE__ */ jsx14("div", { className: "blocks-stacmap-compare__date-chip", children: /* @__PURE__ */ jsx14(DateChip, { left: leftLayerConfig.dateRange, right: rightLayerConfig.dateRange }) }),
|
|
1055
|
+
!isSameCollection && left.legend && /* @__PURE__ */ jsx14("div", { className: "blocks-stacmap-compare__legend-left", children: /* @__PURE__ */ jsx14(Legend, { ...left.legend }) }),
|
|
1056
|
+
right.legend && /* @__PURE__ */ jsx14("div", { className: "blocks-stacmap-compare__legend-right", children: /* @__PURE__ */ jsx14(Legend, { ...right.legend }) })
|
|
1057
|
+
] });
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// src/geo/StacSingleLayerMap/StacSingleLayerMap.tsx
|
|
1061
|
+
import { useId as useId2 } from "react";
|
|
1062
|
+
import {
|
|
1063
|
+
Layer as Layer2,
|
|
1064
|
+
Map as MapLibreMap2,
|
|
1065
|
+
NavigationControl as NavigationControl2,
|
|
1066
|
+
Source as Source2
|
|
1067
|
+
} from "react-map-gl/maplibre";
|
|
1068
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1069
|
+
function StacSingleLayerMap({
|
|
655
1070
|
baseMapStyle = NASA_BLUE_MARBLE_BASEMAP_STYLE,
|
|
656
1071
|
initialViewState,
|
|
657
|
-
|
|
1072
|
+
layerConfig
|
|
658
1073
|
}) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
1074
|
+
const instanceId = useId2();
|
|
1075
|
+
const sourceId = `${layerConfig.collectionId}-raster-source-${instanceId}`;
|
|
1076
|
+
const layerId = `${layerConfig.collectionId}-raster-layer-${instanceId}`;
|
|
1077
|
+
const { mapSource, legend } = useStacRasterLayer(layerConfig);
|
|
1078
|
+
return /* @__PURE__ */ jsxs13("div", { className: "blocks-stacmap-singlelayer", children: [
|
|
1079
|
+
/* @__PURE__ */ jsxs13(
|
|
1080
|
+
MapLibreMap2,
|
|
1081
|
+
{
|
|
1082
|
+
mapStyle: baseMapStyle,
|
|
1083
|
+
...initialViewState && { initialViewState },
|
|
1084
|
+
style: { position: "absolute", inset: 0 },
|
|
1085
|
+
attributionControl: false,
|
|
1086
|
+
children: [
|
|
1087
|
+
/* @__PURE__ */ jsx15(AttributionMapControl, {}),
|
|
1088
|
+
/* @__PURE__ */ jsx15(NavigationControl2, { position: "top-left", showCompass: false }),
|
|
1089
|
+
mapSource.tiles && /* @__PURE__ */ jsx15(Source2, { id: sourceId, type: "raster", tiles: [mapSource.tiles], children: /* @__PURE__ */ jsx15(Layer2, { id: layerId, type: "raster" }) })
|
|
1090
|
+
]
|
|
1091
|
+
}
|
|
1092
|
+
),
|
|
1093
|
+
/* @__PURE__ */ jsx15("div", { className: "blocks-stacmap-singlelayer__legend", children: legend && /* @__PURE__ */ jsx15(Legend, { ...legend }) }),
|
|
1094
|
+
/* @__PURE__ */ jsx15("div", { className: "blocks-stacmap-singlelayer__date-chip", children: /* @__PURE__ */ jsx15(DateChip, { left: layerConfig.dateRange }) })
|
|
1095
|
+
] });
|
|
1096
|
+
}
|
|
669
1097
|
export {
|
|
670
1098
|
Banner,
|
|
671
1099
|
Button,
|
|
@@ -676,6 +1104,8 @@ export {
|
|
|
676
1104
|
CardSimple,
|
|
677
1105
|
Footer,
|
|
678
1106
|
Header,
|
|
679
|
-
|
|
1107
|
+
Legend,
|
|
1108
|
+
StacCompareMap,
|
|
1109
|
+
StacSingleLayerMap,
|
|
680
1110
|
Tag
|
|
681
1111
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teamimpact/veda-ui-blocks",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.8",
|
|
4
4
|
"description": "UI component library for VEDA-based portals, built on USWDS and React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,12 +24,10 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts"
|
|
25
25
|
},
|
|
26
26
|
"./default.css": "./dist/default.css",
|
|
27
|
-
"./disasters.css": "./dist/disasters.css"
|
|
28
|
-
"./earthgov.css": "./dist/earthgov.css"
|
|
27
|
+
"./disasters.css": "./dist/disasters.css"
|
|
29
28
|
},
|
|
30
29
|
"files": [
|
|
31
|
-
"dist"
|
|
32
|
-
"src/styles"
|
|
30
|
+
"dist"
|
|
33
31
|
],
|
|
34
32
|
"peerDependencies": {
|
|
35
33
|
"@developmentseed/stac-react": "^1.0.0-alpha.2",
|
|
@@ -72,7 +70,7 @@
|
|
|
72
70
|
"vitest": "^4.0.18"
|
|
73
71
|
},
|
|
74
72
|
"scripts": {
|
|
75
|
-
"build": "tsup src/index.ts --format esm --dts && pnpm run build:
|
|
73
|
+
"build": "tsup src/index.ts --format esm --dts && pnpm run build:css",
|
|
76
74
|
"build:assets": "./scripts/build-assets.sh",
|
|
77
75
|
"build:css": "./scripts/build-css.sh --quiet",
|
|
78
76
|
"build:css:watch": "./scripts/build-css.sh --quiet --watch --load-path=src/styles",
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
@use "uswds-core" as *;
|
|
2
|
-
|
|
3
|
-
.blocks-banner {
|
|
4
|
-
&__row {
|
|
5
|
-
display: flex;
|
|
6
|
-
flex-wrap: wrap;
|
|
7
|
-
gap: units(4);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
&__guidance {
|
|
11
|
-
flex: 1 1 100%;
|
|
12
|
-
min-width: 0;
|
|
13
|
-
@include at-media("tablet") {
|
|
14
|
-
flex: 1 1 0;
|
|
15
|
-
max-width: 50%;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|