@teamimpact/veda-ui-blocks 0.1.0-beta.7 → 0.1.0-beta.9

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.
Files changed (35) hide show
  1. package/README.md +6 -3
  2. package/dist/default.css +11280 -10085
  3. package/dist/default.css.map +1 -1
  4. package/dist/disasters.css +11278 -10083
  5. package/dist/disasters.css.map +1 -1
  6. package/dist/index.d.ts +169 -68
  7. package/dist/index.js +713 -152
  8. package/package.json +5 -7
  9. package/src/styles/components/banner.scss +0 -18
  10. package/src/styles/components/card-cta.scss +0 -90
  11. package/src/styles/components/card-detailed.scss +0 -164
  12. package/src/styles/components/card-mini.scss +0 -81
  13. package/src/styles/components/card-simple.scss +0 -79
  14. package/src/styles/components/card.scss +0 -284
  15. package/src/styles/components/compare-map.scss +0 -15
  16. package/src/styles/components/footer.scss +0 -256
  17. package/src/styles/components/header.scss +0 -212
  18. package/src/styles/components/index.scss +0 -11
  19. package/src/styles/components/tag.scss +0 -89
  20. package/src/styles/default/index.scss +0 -10
  21. package/src/styles/default/theme-tokens.scss +0 -84
  22. package/src/styles/disasters/card-cta.scss +0 -31
  23. package/src/styles/disasters/card-mini.scss +0 -4
  24. package/src/styles/disasters/card-simple.scss +0 -13
  25. package/src/styles/disasters/card.scss +0 -13
  26. package/src/styles/disasters/compare-map.scss +0 -3
  27. package/src/styles/disasters/fonts.scss +0 -29
  28. package/src/styles/disasters/footer.scss +0 -9
  29. package/src/styles/disasters/header.scss +0 -10
  30. package/src/styles/disasters/index.scss +0 -22
  31. package/src/styles/disasters/tag.scss +0 -6
  32. package/src/styles/disasters/theme-tokens.scss +0 -150
  33. package/src/styles/earthgov/footer.scss +0 -15
  34. package/src/styles/earthgov/index.scss +0 -12
  35. 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" } : {};
@@ -98,40 +102,8 @@ var DEFAULT_EXPANDED_CONTENT_JSX = /* @__PURE__ */ jsxs("div", { className: "blo
98
102
  ] })
99
103
  ] });
100
104
 
101
- // src/components/Button/Button.tsx
102
- import { Button as USWDSButton } from "@trussworks/react-uswds";
103
- import { jsx as jsx2 } from "react/jsx-runtime";
104
- function Button({
105
- type = "button",
106
- secondary = false,
107
- base = false,
108
- accentStyle,
109
- outline = false,
110
- inverse = false,
111
- size,
112
- unstyled = false,
113
- children,
114
- className,
115
- ...rest
116
- }) {
117
- const uswdsButtonProps = {
118
- secondary,
119
- base,
120
- outline,
121
- inverse,
122
- unstyled,
123
- className,
124
- type,
125
- // Only add accentStyle and size if defined, to avoid passing undefined
126
- ...accentStyle ? { accentStyle } : {},
127
- ...size ? { size } : {},
128
- children
129
- };
130
- return /* @__PURE__ */ jsx2(USWDSButton, { ...rest, ...uswdsButtonProps });
131
- }
132
-
133
105
  // src/components/Cards/Card/Card.tsx
134
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
106
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
135
107
  function Card({
136
108
  tag,
137
109
  title,
@@ -154,26 +126,52 @@ function Card({
154
126
  ]);
155
127
  const hasContent = tag || title || subtitle || description || callToAction || callToActionSecondary;
156
128
  return /* @__PURE__ */ jsxs2("div", { className: rootClassName, children: [
157
- imagePosition === "cover" && /* @__PURE__ */ jsx3("div", { className: "blocks-card__media", children: image }),
129
+ imagePosition === "cover" && /* @__PURE__ */ jsx2("div", { className: "blocks-card__media", children: image }),
158
130
  /* @__PURE__ */ jsxs2("div", { className: "blocks-card__content-container", children: [
159
- imagePosition !== "cover" && /* @__PURE__ */ jsx3("div", { className: "blocks-card__media", children: image }),
131
+ imagePosition !== "cover" && /* @__PURE__ */ jsx2("div", { className: "blocks-card__media", children: image }),
160
132
  hasContent && /* @__PURE__ */ jsxs2("div", { className: "blocks-card__content", children: [
161
- tag && /* @__PURE__ */ jsx3("div", { className: "blocks-card__tag", children: tag }),
162
- title && (typeof title === "string" ? /* @__PURE__ */ jsx3("h2", { className: "blocks-card__title", children: title }) : title),
163
- subtitle && /* @__PURE__ */ jsx3("div", { className: "blocks-card__subtitle", children: subtitle }),
164
- description && /* @__PURE__ */ jsx3("p", { className: "blocks-card__description", children: description }),
133
+ tag && /* @__PURE__ */ jsx2("div", { className: "blocks-card__tag", children: tag }),
134
+ title && (typeof title === "string" ? /* @__PURE__ */ jsx2("h2", { className: "blocks-card__title", children: title }) : title),
135
+ subtitle && /* @__PURE__ */ jsx2("div", { className: "blocks-card__subtitle", children: subtitle }),
136
+ description && /* @__PURE__ */ jsx2("p", { className: "blocks-card__description", children: description }),
165
137
  (callToAction || callToActionSecondary) && /* @__PURE__ */ jsxs2("div", { className: "blocks-card__actions", children: [
166
- callToAction && /* @__PURE__ */ jsx3("a", { href: callToAction.href, className: "usa-button", children: callToAction.label }),
167
- callToActionSecondary && /* @__PURE__ */ jsx3("a", { href: callToActionSecondary.href, className: "usa-button usa-button--outline", children: callToActionSecondary.label })
138
+ callToAction && /* @__PURE__ */ jsx2("a", { href: callToAction.href, className: "usa-button", children: callToAction.label }),
139
+ callToActionSecondary && /* @__PURE__ */ jsx2("a", { href: callToActionSecondary.href, className: "usa-button usa-button--outline", children: callToActionSecondary.label })
168
140
  ] })
169
141
  ] })
170
142
  ] }),
171
- children && /* @__PURE__ */ jsx3("div", { className: "blocks-card__children", children })
143
+ children && /* @__PURE__ */ jsx2("div", { className: "blocks-card__children", children })
172
144
  ] });
173
145
  }
174
146
 
147
+ // src/components/icons/ArrowIcon.tsx
148
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
149
+ var ArrowIcon = () => /* @__PURE__ */ jsxs3(
150
+ "svg",
151
+ {
152
+ width: "20",
153
+ height: "20",
154
+ viewBox: "0 0 20 20",
155
+ xmlns: "http://www.w3.org/2000/svg",
156
+ preserveAspectRatio: "xMidYMid meet",
157
+ "aria-hidden": "true",
158
+ children: [
159
+ /* @__PURE__ */ jsx3("circle", { cx: "10", cy: "10", r: "10", fill: "currentColor" }),
160
+ /* @__PURE__ */ jsx3("g", { transform: "translate(5.333, 5.333)", children: /* @__PURE__ */ jsx3(
161
+ "path",
162
+ {
163
+ fillRule: "evenodd",
164
+ clipRule: "evenodd",
165
+ d: "M4.66667 0L3.84417 0.8225L7.09917 4.08333H0V5.25H7.09917L3.84417 8.51083L4.66667 9.33333L9.33333 4.66667L4.66667 0Z",
166
+ fill: "white"
167
+ }
168
+ ) })
169
+ ]
170
+ }
171
+ );
172
+
175
173
  // src/components/Cards/CardCTA/CardCTA.tsx
176
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
174
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
177
175
  function CardCTA({
178
176
  title,
179
177
  url,
@@ -190,75 +188,54 @@ function CardCTA({
190
188
  className
191
189
  ]);
192
190
  const accentColorStyle = accentColor ? { "--blocks-card-cta-custom-accent-color": accentColor } : void 0;
193
- return /* @__PURE__ */ jsx4("a", { href: url, className: rootClassName, style: { ...accentColorStyle, ...style }, ...rest, children: /* @__PURE__ */ jsxs3("div", { className: "blocks-card-cta__body", children: [
194
- /* @__PURE__ */ jsxs3(TitleTag, { className: "blocks-card-cta__title", title, children: [
191
+ return /* @__PURE__ */ jsx4("a", { href: url, className: rootClassName, style: { ...accentColorStyle, ...style }, ...rest, children: /* @__PURE__ */ jsxs4("div", { className: "blocks-card-cta__body", children: [
192
+ /* @__PURE__ */ jsxs4(TitleTag, { className: "blocks-card-cta__title", title, children: [
195
193
  title,
196
- /* @__PURE__ */ jsx4("span", { className: "blocks-card-cta__icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxs3(
197
- "svg",
198
- {
199
- width: "20",
200
- height: "20",
201
- viewBox: "0 0 20 20",
202
- xmlns: "http://www.w3.org/2000/svg",
203
- preserveAspectRatio: "xMidYMid meet",
204
- "aria-hidden": "true",
205
- children: [
206
- /* @__PURE__ */ jsx4("circle", { cx: "10", cy: "10", r: "10", fill: "currentColor" }),
207
- /* @__PURE__ */ jsx4("g", { transform: "translate(5.333, 5.333)", children: /* @__PURE__ */ jsx4(
208
- "path",
209
- {
210
- fillRule: "evenodd",
211
- clipRule: "evenodd",
212
- d: "M4.66667 0L3.84417 0.8225L7.09917 4.08333H0V5.25H7.09917L3.84417 8.51083L4.66667 9.33333L9.33333 4.66667L4.66667 0Z",
213
- fill: "white"
214
- }
215
- ) })
216
- ]
217
- }
218
- ) })
194
+ /* @__PURE__ */ jsx4("span", { className: "blocks-card-cta__icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(ArrowIcon, {}) })
219
195
  ] }),
220
196
  description && /* @__PURE__ */ jsx4("p", { className: "blocks-card-cta__description", children: description })
221
197
  ] }) });
222
198
  }
223
199
 
224
200
  // src/components/Cards/CardDetailed/CardDetailed.tsx
225
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
201
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
226
202
  function CardDetailed({
227
203
  intro,
228
204
  title,
229
205
  description,
230
206
  tags = [],
231
- contentTypeTag,
207
+ callToAction,
208
+ callToActionSecondary,
209
+ tagPrimary,
232
210
  image,
233
- action,
234
211
  imagePosition = "top",
235
- borderAccent = false,
236
- titleAs = "h2",
237
212
  className = ""
238
213
  }) {
239
- const TitleTag = titleAs;
240
- const cardClassName = make_class_name("blocks-card-detailed", [
214
+ const rootClassName = make_class_name("blocks-card-detailed", [
241
215
  imagePosition !== "top" ? `blocks-card-detailed--image-${imagePosition}` : "",
242
216
  className
243
217
  ]);
244
- return /* @__PURE__ */ jsxs4("div", { className: cardClassName, children: [
245
- borderAccent && /* @__PURE__ */ jsx5("div", { "aria-hidden": "true", className: "blocks-card-detailed__accent-bar" }),
246
- /* @__PURE__ */ jsxs4("div", { className: "blocks-card-detailed__content", children: [
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: [
218
+ const hasContent = intro || title || description || tags.length || callToAction || callToActionSecondary;
219
+ return /* @__PURE__ */ jsxs5("div", { className: rootClassName, children: [
220
+ /* @__PURE__ */ jsxs5("div", { className: "blocks-card-detailed__media", children: [
254
221
  image,
255
- contentTypeTag && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__content-type-tag", children: contentTypeTag })
222
+ tagPrimary && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__tag-primary", children: tagPrimary })
223
+ ] }),
224
+ hasContent && /* @__PURE__ */ jsxs5("div", { className: "blocks-card-detailed__content-container", children: [
225
+ intro && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__intro", title: intro, children: intro }),
226
+ title && (typeof title === "string" ? /* @__PURE__ */ jsx5("h2", { className: "blocks-card-detailed__title", title, children: title }) : title),
227
+ isNonEmptyArray(tags) && /* @__PURE__ */ jsx5("div", { className: "blocks-card-detailed__tags", children: tags }),
228
+ description && /* @__PURE__ */ jsx5("p", { className: "blocks-card-detailed__description", children: description }),
229
+ (callToAction || callToActionSecondary) && /* @__PURE__ */ jsxs5("div", { className: "blocks-card-detailed__actions", children: [
230
+ callToAction && /* @__PURE__ */ jsx5("a", { href: callToAction.href, className: "usa-button", children: callToAction.label }),
231
+ callToActionSecondary && /* @__PURE__ */ jsx5("a", { href: callToActionSecondary.href, className: "usa-button usa-button--outline", children: callToActionSecondary.label })
232
+ ] })
256
233
  ] })
257
234
  ] });
258
235
  }
259
236
 
260
237
  // src/components/Cards/CardMini/CardMini.tsx
261
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
238
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
262
239
  function CardMini({ image, title, url, tag, titleAs = "h2", className }) {
263
240
  const TitleTag = titleAs;
264
241
  const hasTag = Boolean(tag);
@@ -266,9 +243,9 @@ function CardMini({ image, title, url, tag, titleAs = "h2", className }) {
266
243
  hasTag ? "blocks-card-mini--with-tag" : void 0,
267
244
  className
268
245
  ]);
269
- return /* @__PURE__ */ jsxs5("a", { href: url, className: rootClassName, children: [
246
+ return /* @__PURE__ */ jsxs6("a", { href: url, className: rootClassName, children: [
270
247
  /* @__PURE__ */ jsx6("div", { className: "blocks-card-mini__image", children: image }),
271
- /* @__PURE__ */ jsxs5("div", { className: "blocks-card-mini__body", children: [
248
+ /* @__PURE__ */ jsxs6("div", { className: "blocks-card-mini__body", children: [
272
249
  /* @__PURE__ */ jsx6(TitleTag, { className: "blocks-card-mini__title", title, children: title }),
273
250
  tag && /* @__PURE__ */ jsx6("div", { className: "blocks-card-mini__tag", children: tag })
274
251
  ] })
@@ -276,29 +253,27 @@ function CardMini({ image, title, url, tag, titleAs = "h2", className }) {
276
253
  }
277
254
 
278
255
  // src/components/Cards/CardSimple/CardSimple.tsx
279
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
256
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
280
257
  function CardSimple({
281
258
  title,
282
259
  image,
283
260
  url,
284
261
  tag,
285
- showOverlay = false,
286
262
  size = "default",
287
263
  titleAs = "h2",
288
264
  className
289
265
  }) {
290
266
  const TitleTag = titleAs;
291
267
  const rootClassName = make_class_name("blocks-card-simple", [
292
- showOverlay ? "blocks-card-simple--with-overlay" : void 0,
293
268
  size === "compact" ? "blocks-card-simple--compact" : void 0,
294
269
  className
295
270
  ]);
296
- return /* @__PURE__ */ jsxs6("a", { href: url, className: rootClassName, children: [
297
- /* @__PURE__ */ jsxs6("div", { className: "blocks-card-simple__media", children: [
271
+ return /* @__PURE__ */ jsxs7("a", { href: url, className: rootClassName, children: [
272
+ /* @__PURE__ */ jsxs7("div", { className: "blocks-card-simple__media", children: [
298
273
  image,
299
- showOverlay && /* @__PURE__ */ jsx7("div", { className: "blocks-card-simple__overlay", "aria-hidden": "true" })
274
+ /* @__PURE__ */ jsx7("div", { className: "blocks-card-simple__overlay", "aria-hidden": "true" })
300
275
  ] }),
301
- /* @__PURE__ */ jsxs6("div", { className: "blocks-card-simple__body", children: [
276
+ /* @__PURE__ */ jsxs7("div", { className: "blocks-card-simple__body", children: [
302
277
  tag && /* @__PURE__ */ jsx7("div", { className: "blocks-card-simple__tag", children: tag }),
303
278
  /* @__PURE__ */ jsx7(TitleTag, { className: "blocks-card-simple__title", children: title })
304
279
  ] })
@@ -307,7 +282,7 @@ function CardSimple({
307
282
 
308
283
  // src/components/Footer/Footer.tsx
309
284
  import { GridContainer, Icon as Icon2, Link, Footer as USWDSFooter } from "@trussworks/react-uswds";
310
- import { Fragment, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
285
+ import { Fragment, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
311
286
  function Footer({
312
287
  portalDetails,
313
288
  primaryNavItems,
@@ -321,25 +296,25 @@ function Footer({
321
296
  {
322
297
  className: footerClassName,
323
298
  size: "slim",
324
- primary: /* @__PURE__ */ jsxs7(GridContainer, { children: [
325
- portalDetails.logo ? /* @__PURE__ */ jsx8("section", { className: "blocks-footer__primary-section-upper", children: portalDetails.logo }) : null,
326
- /* @__PURE__ */ jsxs7("section", { className: "blocks-footer__primary-section-lower", children: [
327
- /* @__PURE__ */ jsxs7("div", { className: "blocks-footer__title", children: [
299
+ primary: /* @__PURE__ */ jsx8(GridContainer, { children: /* @__PURE__ */ jsxs8("section", { className: "blocks-footer__primary-section", children: [
300
+ /* @__PURE__ */ jsxs8("div", { className: "blocks-footer__title", children: [
301
+ portalDetails.logo ? /* @__PURE__ */ jsx8("div", { className: "blocks-footer__logo", children: portalDetails.logo }) : null,
302
+ /* @__PURE__ */ jsxs8("div", { className: "blocks-footer__title-text", children: [
328
303
  /* @__PURE__ */ jsx8("span", { children: portalDetails.title }),
329
304
  portalDetails.tagline ? /* @__PURE__ */ jsx8("p", { children: portalDetails.tagline }) : null
330
- ] }),
331
- 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(
332
- Link,
333
- {
334
- className: "usa-footer__primary-link",
335
- href,
336
- ...get_external_anchor_props(isExternal),
337
- children: label
338
- }
339
- ) }, href)) }) }) : null
340
- ] })
341
- ] }),
342
- secondary: /* @__PURE__ */ jsxs7(Fragment, { children: [
305
+ ] })
306
+ ] }),
307
+ 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(
308
+ Link,
309
+ {
310
+ className: "usa-footer__primary-link",
311
+ href,
312
+ ...get_external_anchor_props(isExternal),
313
+ children: label
314
+ }
315
+ ) }, href)) }) }) : null
316
+ ] }) }),
317
+ secondary: /* @__PURE__ */ jsxs8(Fragment, { children: [
343
318
  secondaryNavItems.length > 0 ? /* @__PURE__ */ jsx8("section", { className: "blocks-footer__secondary-section-upper", children: /* @__PURE__ */ jsx8(
344
319
  "nav",
345
320
  {
@@ -348,19 +323,20 @@ function Footer({
348
323
  children: /* @__PURE__ */ jsx8("ul", { children: secondaryNavItems.map(({ label, href, isExternal }) => /* @__PURE__ */ jsx8("li", { className: "usa-footer__secondary-link", children: /* @__PURE__ */ jsx8(Link, { href, ...get_external_anchor_props(isExternal), children: label }) }, href)) })
349
324
  }
350
325
  ) }) : null,
351
- utilityNavItems?.length || portalDetails.updatedDate || portalDetails.contacts?.length ? /* @__PURE__ */ jsxs7("section", { className: "blocks-footer__secondary-section-lower", children: [
352
- 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: [
326
+ utilityNavItems?.length || portalDetails.updatedDate || portalDetails.contacts?.length ? /* @__PURE__ */ jsxs8("section", { className: "blocks-footer__secondary-section-lower", children: [
327
+ 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__ */ jsxs8("li", { children: [
353
328
  text,
329
+ " ",
354
330
  /* @__PURE__ */ jsx8(Link, { href, ...get_external_anchor_props(isExternal), children: label })
355
331
  ] }, href)) : null }) }) : null,
356
- portalDetails.updatedDate || portalDetails.contacts?.length ? /* @__PURE__ */ jsxs7("div", { className: "blocks-footer__secondary-meta", children: [
357
- portalDetails.updatedDate ? /* @__PURE__ */ jsxs7("p", { children: [
332
+ portalDetails.updatedDate || portalDetails.contacts?.length ? /* @__PURE__ */ jsxs8("div", { className: "blocks-footer__secondary-meta", children: [
333
+ portalDetails.updatedDate ? /* @__PURE__ */ jsxs8("p", { children: [
358
334
  "Site last updated: ",
359
335
  portalDetails.updatedDate
360
336
  ] }) : null,
361
- portalDetails.contacts?.length ? /* @__PURE__ */ jsx8("nav", { className: "blocks-footer__contacts-nav", "aria-label": "Site contacts", children: /* @__PURE__ */ jsx8("ul", { children: portalDetails.contacts.map(({ label, name, email }) => /* @__PURE__ */ jsxs7("li", { children: [
337
+ portalDetails.contacts?.length ? /* @__PURE__ */ jsx8("nav", { className: "blocks-footer__contacts-nav", "aria-label": "Site contacts", children: /* @__PURE__ */ jsx8("ul", { children: portalDetails.contacts.map(({ label, name, email }) => /* @__PURE__ */ jsxs8("li", { children: [
362
338
  /* @__PURE__ */ jsx8("span", { children: label }),
363
- /* @__PURE__ */ jsxs7(Link, { href: `mailto:${email}`, ...get_external_anchor_props(), children: [
339
+ /* @__PURE__ */ jsxs8(Link, { href: `mailto:${email}`, ...get_external_anchor_props(), children: [
364
340
  /* @__PURE__ */ jsx8(Icon2.Mail, { "aria-hidden": "true", focusable: false }),
365
341
  /* @__PURE__ */ jsx8("span", { children: name })
366
342
  ] })
@@ -420,7 +396,7 @@ function useWindowResize(handleResize) {
420
396
 
421
397
  // src/components/Header/Header.helpers.tsx
422
398
  import { Link as Link2, Menu, NavDropDownButton } from "@trussworks/react-uswds";
423
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
399
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
424
400
  var make_nav_items_initial_state = (navItems) => {
425
401
  const initialState = {};
426
402
  const initialProps = navItems.map((item) => {
@@ -467,7 +443,7 @@ var make_menu_link_jsx = ({ label, href, isExternal, isPrimary }, options) => {
467
443
  var make_menu_link_with_dropdown_jsx = ({ label, menuId, subItems }, options) => {
468
444
  const { navDropDownOpenState, handleToggleDropdown, currentPath } = options;
469
445
  const sublinks = subItems.map((item) => make_menu_link_jsx(item, { currentPath }));
470
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
446
+ return /* @__PURE__ */ jsxs9(Fragment2, { children: [
471
447
  /* @__PURE__ */ jsx9(
472
448
  NavDropDownButton,
473
449
  {
@@ -493,7 +469,7 @@ var make_custom_nav_item_jsx = (customNavItem) => isNavItem(customNavItem) ? /*
493
469
  ) : customNavItem;
494
470
 
495
471
  // src/components/Header/Header.tsx
496
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
472
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
497
473
  function Header(props) {
498
474
  const {
499
475
  portalDetails: { logo, title, url },
@@ -561,9 +537,9 @@ function Header(props) {
561
537
  currentPath
562
538
  }) : make_menu_link_jsx(item, { currentPath })
563
539
  );
564
- return /* @__PURE__ */ jsx10(USWDSHeader, { className: headerClassName, basic: true, showMobileOverlay: isMobileNavExpanded, children: /* @__PURE__ */ jsxs9("div", { className: "usa-nav-container", children: [
565
- /* @__PURE__ */ jsxs9("div", { className: "usa-navbar", children: [
566
- /* @__PURE__ */ jsxs9("div", { className: "blocks-header__portal-details", children: [
540
+ return /* @__PURE__ */ jsx10(USWDSHeader, { className: headerClassName, basic: true, showMobileOverlay: isMobileNavExpanded, children: /* @__PURE__ */ jsxs10("div", { className: "usa-nav-container", children: [
541
+ /* @__PURE__ */ jsxs10("div", { className: "usa-navbar", children: [
542
+ /* @__PURE__ */ jsxs10("div", { className: "blocks-header__portal-details", children: [
567
543
  /* @__PURE__ */ jsx10("a", { className: "blocks-header__portal-logo", href: url ?? "/", children: logo }),
568
544
  title ? /* @__PURE__ */ jsx10(Title, { children: /* @__PURE__ */ jsx10("a", { href: url ?? "/", children: title }) }) : null
569
545
  ] }),
@@ -582,12 +558,145 @@ function Header(props) {
582
558
  ] }) });
583
559
  }
584
560
 
561
+ // src/components/Link/Link.tsx
562
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
563
+ function Link3({
564
+ variant = "text",
565
+ size = "md",
566
+ isExternal,
567
+ className,
568
+ as,
569
+ children,
570
+ ...rest
571
+ }) {
572
+ const Component = isExternal ? "a" : as ?? "a";
573
+ const rootClassName = make_class_name("blocks-link", [
574
+ `blocks-link--${variant}`,
575
+ variant === "button" || variant === "button-outline" ? "usa-button" : void 0,
576
+ variant === "button-outline" ? "usa-button--outline" : void 0,
577
+ variant === "text" ? "usa-button--unstyled" : void 0,
578
+ `blocks-link--${size}`,
579
+ isExternal ? "blocks-link--external usa-link--external" : void 0,
580
+ className
581
+ ]);
582
+ return /* @__PURE__ */ jsxs11(Component, { className: rootClassName, ...get_external_anchor_props(isExternal), ...rest, children: [
583
+ children,
584
+ variant === "arrow" && /* @__PURE__ */ jsx11(ArrowIcon, {})
585
+ ] });
586
+ }
587
+
588
+ // src/foundations/theme-token-bridge.helpers.ts
589
+ var BASE_COLOR_TOKENS = [
590
+ "base-lightest",
591
+ "base-lighter",
592
+ "base-light",
593
+ "base",
594
+ "base-dark",
595
+ "base-darker",
596
+ "base-darkest",
597
+ "ink"
598
+ ];
599
+ var PRIMARY_COLOR_TOKENS = [
600
+ "primary-lightest",
601
+ "primary-lighter",
602
+ "primary-light",
603
+ "primary",
604
+ "primary-vivid",
605
+ "primary-dark",
606
+ "primary-darker",
607
+ "primary-darkest"
608
+ ];
609
+ var SECONDARY_COLOR_TOKENS = [
610
+ "secondary-lightest",
611
+ "secondary-lighter",
612
+ "secondary-light",
613
+ "secondary",
614
+ "secondary-vivid",
615
+ "secondary-dark",
616
+ "secondary-darker",
617
+ "secondary-darkest"
618
+ ];
619
+ var ACCENT_COOL_COLOR_TOKENS = [
620
+ "accent-cool-lightest",
621
+ "accent-cool-lighter",
622
+ "accent-cool-light",
623
+ "accent-cool",
624
+ "accent-cool-dark",
625
+ "accent-cool-darker",
626
+ "accent-cool-darkest"
627
+ ];
628
+ var ACCENT_WARM_COLOR_TOKENS = [
629
+ "accent-warm-lightest",
630
+ "accent-warm-lighter",
631
+ "accent-warm-light",
632
+ "accent-warm",
633
+ "accent-warm-dark",
634
+ "accent-warm-darker",
635
+ "accent-warm-darkest"
636
+ ];
637
+ var INFO_COLOR_TOKENS = [
638
+ "info-lighter",
639
+ "info-light",
640
+ "info",
641
+ "info-dark",
642
+ "info-darker"
643
+ ];
644
+ var WARNING_COLOR_TOKENS = [
645
+ "warning-lighter",
646
+ "warning-light",
647
+ "warning",
648
+ "warning-dark",
649
+ "warning-darker"
650
+ ];
651
+ var ERROR_COLOR_TOKENS = [
652
+ "error-lighter",
653
+ "error-light",
654
+ "error",
655
+ "error-dark",
656
+ "error-darker"
657
+ ];
658
+ var SUCCESS_COLOR_TOKENS = [
659
+ "success-lighter",
660
+ "success-light",
661
+ "success",
662
+ "success-dark",
663
+ "success-darker"
664
+ ];
665
+ var DISABLED_COLOR_TOKENS = [
666
+ "disabled-lighter",
667
+ "disabled-light",
668
+ "disabled",
669
+ "disabled-dark",
670
+ "disabled-darker"
671
+ ];
672
+ var EMERGENCY_COLOR_TOKENS = ["emergency", "emergency-dark"];
673
+ var COLOR_TOKENS = [
674
+ ...BASE_COLOR_TOKENS,
675
+ ...PRIMARY_COLOR_TOKENS,
676
+ ...SECONDARY_COLOR_TOKENS,
677
+ ...ACCENT_COOL_COLOR_TOKENS,
678
+ ...ACCENT_WARM_COLOR_TOKENS,
679
+ ...INFO_COLOR_TOKENS,
680
+ ...WARNING_COLOR_TOKENS,
681
+ ...ERROR_COLOR_TOKENS,
682
+ ...SUCCESS_COLOR_TOKENS,
683
+ ...EMERGENCY_COLOR_TOKENS,
684
+ ...DISABLED_COLOR_TOKENS
685
+ ];
686
+ var resolveColorToken = (color) => COLOR_TOKENS.includes(color) ? `var(--color-${color})` : color;
687
+
688
+ // src/components/icons/CloseIcon.tsx
689
+ import { jsx as jsx12 } from "react/jsx-runtime";
690
+ var CloseIcon = () => /* @__PURE__ */ jsx12("svg", { height: "24", width: "24", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx12("path", { d: "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) });
691
+
585
692
  // src/components/Tag/Tag.tsx
586
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
693
+ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
587
694
  function Tag({
588
695
  variant = "solid",
589
696
  size = "default",
590
697
  color,
698
+ bgColor,
699
+ borderColor,
591
700
  textColor,
592
701
  icon,
593
702
  onClose,
@@ -601,14 +710,16 @@ function Tag({
601
710
  onClose ? "blocks-tag--x-close" : void 0,
602
711
  className
603
712
  ]);
604
- const customStyle = color || textColor ? {
605
- ...color ? { "--blocks-tag-custom-color": color } : void 0,
606
- ...textColor ? { "--blocks-tag-custom-text-color": textColor } : void 0
713
+ const customStyle = color || textColor || bgColor || borderColor ? {
714
+ ...color ? { "--blocks-tag-custom-color": resolveColorToken(color) } : void 0,
715
+ ...textColor ? { "--blocks-tag-custom-text-color": resolveColorToken(textColor) } : void 0,
716
+ ...bgColor ? { "--blocks-tag-custom-bg-color": resolveColorToken(bgColor) } : void 0,
717
+ ...borderColor ? { "--blocks-tag-custom-border-color": resolveColorToken(borderColor) } : void 0
607
718
  } : void 0;
608
- return /* @__PURE__ */ jsxs10("span", { className: rootClassName, style: customStyle, children: [
609
- icon && /* @__PURE__ */ jsx11("span", { className: "blocks-tag__icon", children: icon }),
719
+ return /* @__PURE__ */ jsxs12("span", { className: rootClassName, style: customStyle, children: [
720
+ icon && /* @__PURE__ */ jsx13("span", { className: "blocks-tag__icon", children: icon }),
610
721
  children,
611
- onClose && /* @__PURE__ */ jsx11(
722
+ onClose && /* @__PURE__ */ jsx13(
612
723
  "button",
613
724
  {
614
725
  type: "button",
@@ -616,14 +727,15 @@ function Tag({
616
727
  "aria-label": "Remove tag",
617
728
  tabIndex: 0,
618
729
  onClick: onClose,
619
- children: /* @__PURE__ */ jsx11("svg", { height: "24", width: "24", viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx11("path", { d: "M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }) })
730
+ children: /* @__PURE__ */ jsx13(CloseIcon, {})
620
731
  }
621
732
  )
622
733
  ] });
623
734
  }
624
735
 
625
- // src/geo/SingleLayerMap/SingleLayerMap.tsx
626
- import { Map as MapLibreMap } from "react-map-gl/maplibre";
736
+ // src/geo/GeoConfigProvider.tsx
737
+ import { StacApiProvider } from "@developmentseed/stac-react";
738
+ import { createContext, useContext } from "react";
627
739
 
628
740
  // src/geo/constants.ts
629
741
  var NASA_BLUE_MARBLE_BASEMAP_STYLE = {
@@ -647,35 +759,484 @@ var NASA_BLUE_MARBLE_BASEMAP_STYLE = {
647
759
  }
648
760
  ]
649
761
  };
762
+ var STAC_API_URL = "https://openveda.cloud/api/stac";
763
+ var TITILER_BASE_URL = "https://openveda.cloud/api/raster";
764
+ var DEFAULT_RENDER_PARAMS = {
765
+ assets: ["cog_default"],
766
+ rescale: "0,0.0001",
767
+ resampling: "bilinear",
768
+ colormap_name: "viridis",
769
+ bidx: [1]
770
+ };
771
+ var DEFAULT_TILE_MATRIX_SET = "WebMercatorQuad";
772
+ var STAC_COLORSTOP_RGBA_ARG_COUNT = 4;
650
773
 
651
- // src/geo/SingleLayerMap/SingleLayerMap.tsx
652
- import "maplibre-gl/dist/maplibre-gl.css";
653
- import { jsx as jsx12 } from "react/jsx-runtime";
654
- var SingleLayerMap = function SingleLayerMap2({
655
- baseMapStyle = NASA_BLUE_MARBLE_BASEMAP_STYLE,
656
- initialViewState,
774
+ // src/geo/GeoConfigProvider.tsx
775
+ import { jsx as jsx14 } from "react/jsx-runtime";
776
+ var GeoConfigContext = createContext(null);
777
+ function useGeoConfig() {
778
+ const ctx = useContext(GeoConfigContext);
779
+ if (!ctx) throw new Error("Geo components require a GeoConfigProvider ancestor");
780
+ return ctx;
781
+ }
782
+ function GeoConfigProvider({
783
+ stacApiUrl = STAC_API_URL,
784
+ titilerBaseUrl = TITILER_BASE_URL,
657
785
  children
658
786
  }) {
659
- return /* @__PURE__ */ jsx12(
660
- MapLibreMap,
661
- {
662
- mapStyle: baseMapStyle,
663
- ...initialViewState && { initialViewState },
664
- style: { width: "100%", flex: 1, minHeight: 0 },
665
- children
666
- }
787
+ return /* @__PURE__ */ jsx14(GeoConfigContext.Provider, { value: { titilerBaseUrl }, children: /* @__PURE__ */ jsx14(StacApiProvider, { apiUrl: stacApiUrl, children }) });
788
+ }
789
+
790
+ // src/geo/Legend/Legend.tsx
791
+ import { Icon as Icon3 } from "@trussworks/react-uswds";
792
+ import { useState as useState3 } from "react";
793
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
794
+ function Legend({ initialExpanded = false, ...props }) {
795
+ const { title, description, unit, min, max, colorStops, provider, spatialExtent, timeDensity } = props;
796
+ const [isExpanded, setIsExpanded] = useState3(initialExpanded);
797
+ const subtitle = [provider, spatialExtent, timeDensity].some(isDefined) ? [provider, spatialExtent, timeDensity].filter(isDefined).join(" \xB7 ") : void 0;
798
+ return /* @__PURE__ */ jsxs13("div", { className: "blocks-legend", children: [
799
+ /* @__PURE__ */ jsxs13("div", { className: "blocks-legend__header", children: [
800
+ /* @__PURE__ */ jsxs13("div", { className: "blocks-legend__header-text", children: [
801
+ title && /* @__PURE__ */ jsx15("h3", { className: "blocks-legend__title", title, children: title }),
802
+ subtitle && /* @__PURE__ */ jsx15("p", { className: "blocks-legend__subtitle", title: subtitle, children: subtitle })
803
+ ] }),
804
+ description && /* @__PURE__ */ jsx15(
805
+ "button",
806
+ {
807
+ type: "button",
808
+ className: "blocks-legend__info-toggle",
809
+ "aria-expanded": isExpanded,
810
+ "aria-label": "Toggle layer description",
811
+ onClick: () => setIsExpanded((v) => !v),
812
+ children: /* @__PURE__ */ jsx15(Icon3.InfoOutline, { "aria-hidden": true, focusable: false, size: 3 })
813
+ }
814
+ )
815
+ ] }),
816
+ /* @__PURE__ */ jsx15("div", { className: "blocks-legend__gradient-bar", children: /* @__PURE__ */ jsx15(
817
+ "div",
818
+ {
819
+ className: "blocks-legend__gradient",
820
+ style: {
821
+ background: `linear-gradient(to right, ${colorStops.join(", ")})`
822
+ }
823
+ }
824
+ ) }),
825
+ /* @__PURE__ */ jsxs13("div", { className: "blocks-legend__labels", children: [
826
+ /* @__PURE__ */ jsx15("span", { className: "blocks-legend__min", children: min }),
827
+ /* @__PURE__ */ jsx15("span", { className: "blocks-legend__unit", children: unit }),
828
+ /* @__PURE__ */ jsx15("span", { className: "blocks-legend__max", children: max })
829
+ ] }),
830
+ isExpanded && description && /* @__PURE__ */ jsx15("div", { className: "blocks-legend__description", children: /* @__PURE__ */ jsx15("div", { className: "blocks-legend__description-inner", children: description }) })
831
+ ] });
832
+ }
833
+
834
+ // src/geo/StacCompareMap/StacCompareMap.tsx
835
+ import { useEffect as useEffect3, useId, useRef as useRef3, useState as useState4 } from "react";
836
+ import {
837
+ Layer,
838
+ Map as MapLibreMap,
839
+ NavigationControl,
840
+ Source
841
+ } from "react-map-gl/maplibre";
842
+
843
+ // src/geo/AttributionMapControl.tsx
844
+ import maplibregl from "maplibre-gl";
845
+ import { useControl } from "react-map-gl/maplibre";
846
+ function AttributionMapControl({ position = "top-right" }) {
847
+ useControl(() => new maplibregl.AttributionControl(), { position });
848
+ return null;
849
+ }
850
+
851
+ // src/geo/utils/formatDateRange.ts
852
+ function formatDateRange(dateRange) {
853
+ const from = /* @__PURE__ */ new Date(`${dateRange.from}T00:00:00Z`);
854
+ const to = /* @__PURE__ */ new Date(`${dateRange.to}T00:00:00Z`);
855
+ if (from.getUTCFullYear() === to.getUTCFullYear() && from.getUTCMonth() === to.getUTCMonth()) {
856
+ return from.toLocaleDateString("en-US", {
857
+ month: "short",
858
+ year: "numeric",
859
+ timeZone: "UTC"
860
+ });
861
+ }
862
+ const fromStr = from.toLocaleDateString("en-US", {
863
+ month: "short",
864
+ day: "numeric",
865
+ year: "numeric",
866
+ timeZone: "UTC"
867
+ });
868
+ const toStr = to.toLocaleDateString("en-US", {
869
+ month: "short",
870
+ day: "numeric",
871
+ year: "numeric",
872
+ timeZone: "UTC"
873
+ });
874
+ return `${fromStr} \u2013 ${toStr}`;
875
+ }
876
+
877
+ // src/geo/DateChip/DateChip.tsx
878
+ import { jsx as jsx16 } from "react/jsx-runtime";
879
+ function DateChip({ left, right }) {
880
+ const label = right === void 0 || left.from === right.from && left.to === right.to ? formatDateRange(left) : `${formatDateRange(left)} vs ${formatDateRange(right)}`;
881
+ return /* @__PURE__ */ jsx16("div", { className: "blocks-date-chip", children: label });
882
+ }
883
+
884
+ // src/geo/hooks/useStacRasterLayer.ts
885
+ import { useCollection } from "@developmentseed/stac-react";
886
+
887
+ // src/geo/hooks/useMosaicTiles.ts
888
+ import { useQuery } from "@tanstack/react-query";
889
+
890
+ // src/geo/api/titiler/fetchTilejson.ts
891
+ async function fetchTilejson(tilejsonUrl, queryString) {
892
+ const response = await fetch(`${tilejsonUrl}?${queryString}`);
893
+ if (!response.ok) {
894
+ const error = { detail: `Failed to fetch tilejson: ${response.statusText}` };
895
+ throw error;
896
+ }
897
+ const tilejson = await response.json();
898
+ if (!tilejson.tiles?.[0]) {
899
+ const error = { detail: "No tile URL found in response" };
900
+ throw error;
901
+ }
902
+ return tilejson.tiles[0];
903
+ }
904
+
905
+ // src/geo/api/titiler/mosaicLinks.ts
906
+ function findTileLink(links) {
907
+ return links.find((link) => link.rel === "tiles") ?? links.at(1) ?? links.at(0) ?? null;
908
+ }
909
+ function buildTilejsonUrl(tileLinkHref, tileMatrixSet) {
910
+ return tileLinkHref.replace("/{tileMatrixSetId}", `/${tileMatrixSet}`);
911
+ }
912
+ function extractTileUrl(registrationResponse, tileMatrixSet) {
913
+ const tileLink = findTileLink(registrationResponse.links);
914
+ if (!tileLink?.href) {
915
+ const error = { detail: "No tile URL found in registration response" };
916
+ throw error;
917
+ }
918
+ const tilejsonUrl = buildTilejsonUrl(tileLink.href, tileMatrixSet);
919
+ return tilejsonUrl;
920
+ }
921
+
922
+ // src/geo/api/titiler/registerMosaic.ts
923
+ async function registerMosaic(request) {
924
+ const { rasterApiUrl, collectionId, datetime } = request;
925
+ const response = await fetch(`${rasterApiUrl}/searches/register`, {
926
+ method: "POST",
927
+ headers: { "Content-Type": "application/json" },
928
+ body: JSON.stringify({
929
+ collections: [collectionId],
930
+ datetime
931
+ })
932
+ });
933
+ if (!response.ok) {
934
+ const error = {
935
+ detail: `Failed to register mosaic: ${response.statusText}`,
936
+ status: response.status
937
+ };
938
+ throw error;
939
+ }
940
+ return response.json();
941
+ }
942
+
943
+ // src/geo/api/titiler/fetchMosaicTileUrl.ts
944
+ var TILE_PARAMS = {
945
+ ASSETS: "assets",
946
+ RESCALE: "rescale",
947
+ RESAMPLING: "resampling",
948
+ COLORMAP_NAME: "colormap_name",
949
+ BIDX: "bidx"
950
+ };
951
+ function buildQueryParams(sourceParams) {
952
+ const params = new URLSearchParams();
953
+ if (sourceParams.assets) params.append(TILE_PARAMS.ASSETS, sourceParams.assets.join(","));
954
+ if (sourceParams.rescale) params.append(TILE_PARAMS.RESCALE, sourceParams.rescale);
955
+ if (sourceParams.resampling) params.append(TILE_PARAMS.RESAMPLING, sourceParams.resampling);
956
+ if (sourceParams.colormap_name)
957
+ params.append(TILE_PARAMS.COLORMAP_NAME, sourceParams.colormap_name);
958
+ if (sourceParams.bidx) params.append(TILE_PARAMS.BIDX, sourceParams.bidx.join(","));
959
+ return params;
960
+ }
961
+ async function fetchMosaicTileUrl(request) {
962
+ const { sourceParams, tileMatrixSet } = request;
963
+ const queryParams = buildQueryParams(sourceParams);
964
+ const queryString = queryParams.toString();
965
+ const registrationResponse = await registerMosaic(request);
966
+ const tilejsonUrl = extractTileUrl(registrationResponse, tileMatrixSet);
967
+ return fetchTilejson(tilejsonUrl, queryString);
968
+ }
969
+
970
+ // src/geo/hooks/useMosaicTiles.ts
971
+ function useMosaicTiles(rasterLayerConfig) {
972
+ const { titilerBaseUrl } = useGeoConfig();
973
+ const { collectionId, dateRange, tileMatrixSet = DEFAULT_TILE_MATRIX_SET } = rasterLayerConfig;
974
+ const datetime = dateRange.from === dateRange.to ? dateRange.from : `${dateRange.from}/${dateRange.to}`;
975
+ const request = {
976
+ rasterApiUrl: titilerBaseUrl,
977
+ collectionId,
978
+ datetime,
979
+ sourceParams: {
980
+ ...DEFAULT_RENDER_PARAMS,
981
+ assets: [...DEFAULT_RENDER_PARAMS.assets],
982
+ bidx: [...DEFAULT_RENDER_PARAMS.bidx]
983
+ },
984
+ tileMatrixSet
985
+ };
986
+ return useQuery({
987
+ queryKey: [collectionId, dateRange, titilerBaseUrl],
988
+ queryFn: () => fetchMosaicTileUrl(request),
989
+ staleTime: 30 * 60 * 1e3,
990
+ gcTime: 60 * 60 * 1e3,
991
+ enabled: !!collectionId && !!dateRange?.from && !!dateRange?.to
992
+ });
993
+ }
994
+
995
+ // src/geo/hooks/useStacRasterLegend.ts
996
+ import { useQuery as useQuery2 } from "@tanstack/react-query";
997
+
998
+ // src/geo/utils/stac.formatters.ts
999
+ var formatSpatialExtent = (spatialExtent) => {
1000
+ const [minX, minY, maxX, maxY] = spatialExtent?.bbox?.[0] ?? [];
1001
+ if (minX === void 0 || minY === void 0 || maxX === void 0 || maxY === void 0)
1002
+ return void 0;
1003
+ return maxX - minX >= 359 && maxY - minY >= 179 ? "global" : "regional";
1004
+ };
1005
+
1006
+ // src/geo/utils/stac.typeguards.ts
1007
+ var isRgbaColorStopMap = (value) => {
1008
+ return !isNil(value) && isObject(value) && !isEmptyObject(value) && getTypedValues(value).every(
1009
+ (rgba) => isArray(rgba) && rgba.length === STAC_COLORSTOP_RGBA_ARG_COUNT && rgba.every(isNumber)
667
1010
  );
668
1011
  };
1012
+
1013
+ // src/geo/utils/extractLegendProps.ts
1014
+ function extractLegendProps(collection, colorStopMap) {
1015
+ const rescale = collection.renders?.dashboard?.rescale?.[0];
1016
+ if (!rescale) return null;
1017
+ if (!isRgbaColorStopMap(colorStopMap)) return null;
1018
+ const colorStops = getTypedValues(colorStopMap).map((rgba) => `rgba(${rgba.join(",")})`);
1019
+ const title = collection.title;
1020
+ const description = collection.description;
1021
+ const provider = collection.providers?.[0]?.name;
1022
+ const timeDensity = collection.properties?.["dashboard:time_density"];
1023
+ const spatialExtent = formatSpatialExtent(collection.extent?.spatial);
1024
+ const unit = collection.item_assets?.cog_default?.["raster:bands"]?.[0]?.unit;
1025
+ return {
1026
+ type: "gradient",
1027
+ ...title && { title },
1028
+ ...description && { description },
1029
+ min: rescale[0],
1030
+ max: rescale[1],
1031
+ colorStops,
1032
+ ...provider && { provider },
1033
+ ...timeDensity && { timeDensity },
1034
+ ...spatialExtent && { spatialExtent },
1035
+ ...unit && { unit }
1036
+ };
1037
+ }
1038
+
1039
+ // src/geo/hooks/useStacRasterLegend.ts
1040
+ function useStacRasterLegend(collection) {
1041
+ const { titilerBaseUrl } = useGeoConfig();
1042
+ const query = useQuery2({
1043
+ queryKey: ["legend", collection, titilerBaseUrl],
1044
+ queryFn: async () => {
1045
+ if (!collection) return null;
1046
+ const colormapName = collection?.renders?.dashboard?.colormap_name;
1047
+ if (!colormapName) return null;
1048
+ const response = await fetch(`${titilerBaseUrl}/colorMaps/${colormapName}`);
1049
+ if (!response.ok) {
1050
+ const error = {
1051
+ detail: `Colormap "${colormapName}" not found (HTTP ${response.status})`,
1052
+ status: response.status
1053
+ };
1054
+ throw error;
1055
+ }
1056
+ const colorMap = await response.json();
1057
+ return extractLegendProps(collection, colorMap);
1058
+ },
1059
+ enabled: !!collection
1060
+ });
1061
+ return {
1062
+ legend: query.data ?? null,
1063
+ isLoading: query.isLoading,
1064
+ error: query.error || null
1065
+ };
1066
+ }
1067
+
1068
+ // src/geo/hooks/useStacRasterLayer.ts
1069
+ function useStacRasterLayer(rasterLayerConfig) {
1070
+ const { collectionId } = rasterLayerConfig;
1071
+ const {
1072
+ collection,
1073
+ isLoading: isLoadingCollection,
1074
+ error: collectionError
1075
+ } = useCollection(collectionId);
1076
+ const {
1077
+ data: tiles,
1078
+ isLoading: tilesetLoading,
1079
+ error: tilesetError
1080
+ } = useMosaicTiles(rasterLayerConfig);
1081
+ const {
1082
+ legend,
1083
+ isLoading: isLoadingLegend,
1084
+ error: legendError
1085
+ } = useStacRasterLegend(collection);
1086
+ return {
1087
+ mapSource: {
1088
+ tiles: tiles ?? null
1089
+ },
1090
+ legend,
1091
+ isLoading: isLoadingCollection || tilesetLoading || isLoadingLegend,
1092
+ error: collectionError || tilesetError || legendError || null
1093
+ };
1094
+ }
1095
+
1096
+ // src/geo/StacCompareMap/StacCompareMap.tsx
1097
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1098
+ var MAP_PANEL_STYLE = {
1099
+ position: "absolute",
1100
+ top: 0,
1101
+ bottom: 0,
1102
+ width: "100%"
1103
+ };
1104
+ function StacCompareMap({
1105
+ baseMapStyle,
1106
+ initialViewState,
1107
+ leftLayerConfig,
1108
+ rightLayerConfig,
1109
+ className
1110
+ }) {
1111
+ const instanceId = useId();
1112
+ const leftMapRef = useRef3(null);
1113
+ const rightMapRef = useRef3(null);
1114
+ const compareRef = useRef3(null);
1115
+ const containerRef = useRef3(null);
1116
+ const [leftMapLoaded, setLeftMapLoaded] = useState4(false);
1117
+ const [rightMapLoaded, setRightMapLoaded] = useState4(false);
1118
+ const containerClassName = make_class_name("blocks-stacmap-compare", [className]);
1119
+ const left = useStacRasterLayer(leftLayerConfig);
1120
+ const right = useStacRasterLayer(rightLayerConfig);
1121
+ const isSameCollection = leftLayerConfig.collectionId === rightLayerConfig.collectionId;
1122
+ const leftSourceId = `${leftLayerConfig.collectionId}-raster-source-left-${instanceId}`;
1123
+ const leftLayerId = `${leftLayerConfig.collectionId}-raster-layer-left-${instanceId}`;
1124
+ const rightSourceId = `${rightLayerConfig.collectionId}-raster-source-right-${instanceId}`;
1125
+ const rightLayerId = `${rightLayerConfig.collectionId}-raster-layer-right-${instanceId}`;
1126
+ useEffect3(() => {
1127
+ if (!leftMapLoaded || !rightMapLoaded) return;
1128
+ if (compareRef.current) return;
1129
+ const leftMap = leftMapRef.current?.getMap();
1130
+ const rightMap = rightMapRef.current?.getMap();
1131
+ const container = containerRef.current;
1132
+ if (!leftMap || !rightMap || !container) return;
1133
+ import("mapbox-gl-compare").then(({ default: MapboxCompare }) => {
1134
+ if (compareRef.current) return;
1135
+ try {
1136
+ compareRef.current = new MapboxCompare(leftMap, rightMap, container, {
1137
+ mousemove: false,
1138
+ orientation: "vertical"
1139
+ });
1140
+ } catch (error) {
1141
+ console.error("Failed to initialize mapbox-gl-compare:", error);
1142
+ }
1143
+ });
1144
+ }, [leftMapLoaded, rightMapLoaded]);
1145
+ useEffect3(() => {
1146
+ return () => {
1147
+ compareRef.current?.remove();
1148
+ compareRef.current = null;
1149
+ };
1150
+ }, []);
1151
+ const mapProps = {
1152
+ ...baseMapStyle && { mapStyle: baseMapStyle },
1153
+ ...initialViewState && { initialViewState },
1154
+ style: MAP_PANEL_STYLE
1155
+ };
1156
+ return /* @__PURE__ */ jsxs14("div", { ref: containerRef, className: containerClassName, children: [
1157
+ /* @__PURE__ */ jsxs14(
1158
+ MapLibreMap,
1159
+ {
1160
+ ref: leftMapRef,
1161
+ ...mapProps,
1162
+ attributionControl: false,
1163
+ onLoad: () => setLeftMapLoaded(true),
1164
+ children: [
1165
+ /* @__PURE__ */ jsx17(AttributionMapControl, {}),
1166
+ /* @__PURE__ */ jsx17(NavigationControl, { position: "top-left", showCompass: false }),
1167
+ left.mapSource.tiles && /* @__PURE__ */ jsx17(Source, { id: leftSourceId, type: "raster", tiles: [left.mapSource.tiles], children: /* @__PURE__ */ jsx17(Layer, { id: leftLayerId, type: "raster" }) })
1168
+ ]
1169
+ }
1170
+ ),
1171
+ /* @__PURE__ */ jsxs14(
1172
+ MapLibreMap,
1173
+ {
1174
+ ref: rightMapRef,
1175
+ ...mapProps,
1176
+ attributionControl: false,
1177
+ onLoad: () => setRightMapLoaded(true),
1178
+ children: [
1179
+ /* @__PURE__ */ jsx17(AttributionMapControl, {}),
1180
+ right.mapSource.tiles && /* @__PURE__ */ jsx17(Source, { id: rightSourceId, type: "raster", tiles: [right.mapSource.tiles], children: /* @__PURE__ */ jsx17(Layer, { id: rightLayerId, type: "raster" }) })
1181
+ ]
1182
+ }
1183
+ ),
1184
+ /* @__PURE__ */ jsx17("div", { className: "blocks-stacmap-compare__date-chip", children: /* @__PURE__ */ jsx17(DateChip, { left: leftLayerConfig.dateRange, right: rightLayerConfig.dateRange }) }),
1185
+ !isSameCollection && left.legend && /* @__PURE__ */ jsx17("div", { className: "blocks-stacmap-compare__legend-left", children: /* @__PURE__ */ jsx17(Legend, { ...left.legend }) }),
1186
+ right.legend && /* @__PURE__ */ jsx17("div", { className: "blocks-stacmap-compare__legend-right", children: /* @__PURE__ */ jsx17(Legend, { ...right.legend }) })
1187
+ ] });
1188
+ }
1189
+
1190
+ // src/geo/StacSingleLayerMap/StacSingleLayerMap.tsx
1191
+ import { useId as useId2 } from "react";
1192
+ import {
1193
+ Layer as Layer2,
1194
+ Map as MapLibreMap2,
1195
+ NavigationControl as NavigationControl2,
1196
+ Source as Source2
1197
+ } from "react-map-gl/maplibre";
1198
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1199
+ function StacSingleLayerMap({
1200
+ baseMapStyle = NASA_BLUE_MARBLE_BASEMAP_STYLE,
1201
+ initialViewState,
1202
+ layerConfig
1203
+ }) {
1204
+ const instanceId = useId2();
1205
+ const sourceId = `${layerConfig.collectionId}-raster-source-${instanceId}`;
1206
+ const layerId = `${layerConfig.collectionId}-raster-layer-${instanceId}`;
1207
+ const { mapSource, legend } = useStacRasterLayer(layerConfig);
1208
+ return /* @__PURE__ */ jsxs15("div", { className: "blocks-stacmap-singlelayer", children: [
1209
+ /* @__PURE__ */ jsxs15(
1210
+ MapLibreMap2,
1211
+ {
1212
+ mapStyle: baseMapStyle,
1213
+ ...initialViewState && { initialViewState },
1214
+ style: { position: "absolute", inset: 0 },
1215
+ attributionControl: false,
1216
+ children: [
1217
+ /* @__PURE__ */ jsx18(AttributionMapControl, {}),
1218
+ /* @__PURE__ */ jsx18(NavigationControl2, { position: "top-left", showCompass: false }),
1219
+ mapSource.tiles && /* @__PURE__ */ jsx18(Source2, { id: sourceId, type: "raster", tiles: [mapSource.tiles], children: /* @__PURE__ */ jsx18(Layer2, { id: layerId, type: "raster" }) })
1220
+ ]
1221
+ }
1222
+ ),
1223
+ /* @__PURE__ */ jsx18("div", { className: "blocks-stacmap-singlelayer__legend", children: legend && /* @__PURE__ */ jsx18(Legend, { ...legend }) }),
1224
+ /* @__PURE__ */ jsx18("div", { className: "blocks-stacmap-singlelayer__date-chip", children: /* @__PURE__ */ jsx18(DateChip, { left: layerConfig.dateRange }) })
1225
+ ] });
1226
+ }
669
1227
  export {
670
1228
  Banner,
671
- Button,
672
1229
  Card,
673
1230
  CardCTA,
674
1231
  CardDetailed,
675
1232
  CardMini,
676
1233
  CardSimple,
677
1234
  Footer,
1235
+ GeoConfigProvider,
678
1236
  Header,
679
- SingleLayerMap,
1237
+ Legend,
1238
+ Link3 as Link,
1239
+ StacCompareMap,
1240
+ StacSingleLayerMap,
680
1241
  Tag
681
1242
  };