@utahdts/utah-design-system
Version:
Utah Design System React Library
1,388 lines • 296 kB
JavaScript
import { childrenMenuTypes, events, getUtahHeaderSettings, popupFocusHandler, renderDOMSingle, setUtahHeaderSettings } from "@utahdts/utah-design-system-header";
import React, { createContext, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
import { arrow, autoUpdate, flip, offset, shift, useFloating } from "@floating-ui/react-dom";
import { castArray, cloneDeep, identity, isArray, isEmpty, isEqual, isFunction, isObject, split, trim, uniq } from "lodash-es";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { useImmer } from "use-immer";
import { add, format, isValid, parse } from "date-fns";
import { v4 } from "uuid";
var package_default = {
name: "@utahdts/utah-design-system",
description: "Utah Design System React Library",
displayName: "Utah Design System React Library",
version: "5.1.0",
exports: {
".": {
"development-local": "./index.js",
"development": "./dist/utah-design-system.es.js",
"production": "./dist/utah-design-system.es.js",
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/utah-design-system.es.js"
},
"types": "./dist/index.d.ts",
"require": "./dist/utah-design-system.umd.js",
"default": [
"./dist/utah-design-system.es.js",
"./dist/utah-design-system.umd.js",
"./index.js"
]
},
"./css": "./dist/style.css",
"./dist/*": "./dist/*",
"./src/css/": "./src/css/",
"./css/index.scss": "./css/index.scss"
},
main: "index.js",
types: "./dist/index.d.ts",
files: [
"css",
"dist",
"react"
],
scripts: {
"build": "vite build",
"buildw": "vite build --watch",
"buildTypes": "mkdir -p dist && cp ./artifacts/index.d.ts ./dist/",
"generateTypes": "npx tsc",
"preview": "vite preview",
"publishLibrary": "npm publish --access public",
"test:ci": "vitest run --coverage --mode development-local",
"test-publish": "npm publish --dry-run",
"test": "vitest",
"testOnce": "vitest run",
"tsc": "tsc",
"tscw": "tsc --watch --skipLibCheck",
"watch": "vite build --watch"
},
repository: {
"type": "git",
"url": "https://github.com:utahdts/utah-design-system.git",
"directory": "library"
},
keywords: [
"design system",
"dts",
"utah",
"components"
],
author: "DTS Digital Experience <dxp@utah.gov>",
license: "Apache 2.0",
bugs: { "url": "https://github.com/utahdts/utah-design-system/issues" },
homepage: "https://github.com/utahdts/utah-design-system",
peerDependencies: { "react": "^18.0.0 || ^19.0.0" },
dependencies: {
"@floating-ui/react-dom": "^2.1.8",
"@utahdts/utah-design-system-header": "5.1.0",
"date-fns": "4.1.0",
"immer": "11.1.4",
"lodash-es": "4.18.1",
"use-immer": "0.11.0",
"uuid": "14.0.0"
},
devDependencies: {
"@types/lodash-es": "4.17.12",
"@types/react": "^19.2.14",
"@vitejs/plugin-react": "^6.0.1",
"@vitest/coverage-istanbul": "^4.1.5",
"@vitest/ui": "^4.1.5",
"jsdom": "^29.1.1",
"prop-types": "15.8.1",
"sass": "^1.99.0",
"typescript": "^6.0.3",
"vite": "^8.0.10",
"vitest": "^4.1.5"
},
type: "module"
};
//#endregion
//#region react/enums/popupPlacement.js
/** @typedef {import('@utahdts/utah-design-system-header').PopupPlacement} PopupPlacement */
/** @enum {PopupPlacement} */
var popupPlacement = {
BOTTOM: "bottom",
BOTTOM_START: "bottom-start",
BOTTOM_END: "bottom-end",
LEFT: "left",
LEFT_START: "left-start",
LEFT_END: "left-end",
RIGHT: "right",
RIGHT_START: "right-start",
RIGHT_END: "right-end",
TOP: "top",
TOP_START: "top-start",
TOP_END: "top-end"
};
//#endregion
//#region react/hooks/usePopupDelay.js
var NO_POP_UP_TIMEOUT_MS = 350;
var POP_UP_TIMEOUT_MS = 350;
var PopupDelay = class {
#popupTimeoutId = NaN;
#noPopupTimeoutId = NaN;
#isImmediatePopup = false;
/** wait a little while after a popup closes before turning off immediate popup flag */
startNoPopupTimer = () => {
clearTimeout(this.#noPopupTimeoutId);
clearTimeout(this.#popupTimeoutId);
if (this.#isImmediatePopup) this.#noPopupTimeoutId = window.setTimeout(() => {
this.#isImmediatePopup = false;
}, NO_POP_UP_TIMEOUT_MS);
};
/**
* wait to pop unless the popping period has already lapsed
* Make sure to call startNoPopupTimer when the popup goes away
* @param {() => void} callback function to call when waiting is done
*/
startPopupTimer = (callback) => {
clearTimeout(this.#noPopupTimeoutId);
clearTimeout(this.#popupTimeoutId);
if (this.#isImmediatePopup) callback();
else this.#popupTimeoutId = window.setTimeout(() => {
this.#isImmediatePopup = true;
callback();
}, POP_UP_TIMEOUT_MS);
};
};
var POPUP_DELAY = new PopupDelay();
/**
* This could easily have been a context, BUT trying to avoid requiring global contexts for the Design System library
* plus this doesn't have to be a context because changing the isImmediatePopup state doesn't need to trigger a rerender (locally nor globally)
* @returns {{startNoPopupTimer: () => void, startPopupTimer: (callback: () => void) => void}}
*/
function usePopupDelay() {
return POPUP_DELAY;
}
//#endregion
//#region react/util/joinClassNames.js
/**
* pass in comma separated list of class name strings to be trimmed, filtered, and joined together with a space
* @param {(string | boolean | any[] | null | undefined)[]} classNames really can be anything, but should be string if truey
* @returns {string}
*/
function joinClassNames(...classNames) {
return castArray(Array.from(classNames)).flat(Infinity).map((className) => typeof className === "string" ? trim(className) : className).filter(identity).join(" ");
}
//#endregion
//#region react/components/tooltip/Tooltip.jsx
/** @typedef {import('@utahdts/utah-design-system-header').PopupPlacement} PopupPlacement */
/**
* A ToolTip is only in charge of positioning and rendering a tooltip.
* Pass in a "referenceElement" to have "zero-config" for onMouseEnter and onMouseLeave triggering
* Pass in a isPopupVisible and setIsPopupVisible to have it be a controlled component
* @param {object} props
* @param {import('react').ReactNode} props.children The content of the tool tip
* @param {string} [props.className] CSS class to apply to the popup
* @param {import('react').RefObject<HTMLDivElement | null>} [props.innerRef] ref of the popup wrapper
* @param {boolean} [props.isPopupVisible] controlled value for telling if tool tip is visible
* @param {number | {mainAxis: number, crossAxis: number, alignmentAxis?: number}} [props.offset] default offset is 5 (see popup documentation
* for details)
* @param {PopupPlacement} [props.placement] where to put the tooltip in reference to the referenceElement
* @param {HTMLElement | null} props.referenceElement the referenceElement from which the tool tip will toggle (first render will most likely be null)
* @returns {import('react').JSX.Element}
*/
function Tooltip({ children, className, innerRef: draftInnerRef, isPopupVisible, offset: offset$2 = 5, placement = popupPlacement.BOTTOM, referenceElement: draftReferenceElement }) {
const [isPopupVisibleInternal, setIsPopupVisibleInternal] = useState(false);
const [popupElement, setPopupElement] = useState(null);
const [arrowElement, setArrowElement] = useState(null);
const { floatingStyles, middlewareData } = useFloating({
elements: {
reference: draftReferenceElement,
floating: popupElement
},
middleware: [
offset(offset$2),
flip(),
shift(),
arrow({ element: arrowElement })
],
open: !(isPopupVisible ?? isPopupVisibleInternal),
placement,
whileElementsMounted: autoUpdate
});
const { startNoPopupTimer, startPopupTimer } = usePopupDelay();
const onEscape = (e) => {
if (e.code === "Escape" || e.key === "Escape") {
setIsPopupVisibleInternal(false);
document.removeEventListener("keyup", onEscape);
}
};
useEffect(() => {
if (draftReferenceElement && isPopupVisible === void 0) {
if (draftReferenceElement.onmouseenter) throw new Error("ToolTip: onMouseEnter previously set");
if (draftReferenceElement.onmouseleave) throw new Error("ToolTip: onMouseLeave previously set");
if (draftReferenceElement.onfocus) throw new Error("ToolTip: onfocus previously set");
if (draftReferenceElement.onblur) throw new Error("ToolTip: onblur previously set");
draftReferenceElement.onmouseenter = () => startPopupTimer(() => {
setIsPopupVisibleInternal(true);
});
draftReferenceElement.onfocus = () => {
setIsPopupVisibleInternal(true);
};
draftReferenceElement.onmouseleave = () => {
startNoPopupTimer();
setIsPopupVisibleInternal(false);
};
draftReferenceElement.onblur = () => setIsPopupVisibleInternal(false);
document.addEventListener("keyup", onEscape);
}
return (() => {
if (draftReferenceElement) {
draftReferenceElement.onmouseenter = null;
draftReferenceElement.onmouseleave = null;
draftReferenceElement.onfocus = null;
draftReferenceElement.onblur = null;
}
});
}, [
draftReferenceElement,
isPopupVisible,
startNoPopupTimer,
startPopupTimer,
onEscape
]);
return /* @__PURE__ */ jsx("div", {
ref: (refValue) => {
setPopupElement(refValue);
if (draftInnerRef) draftInnerRef.current = refValue;
},
style: floatingStyles,
className: joinClassNames(className, "tooltip__wrapper", !(isPopupVisible ?? isPopupVisibleInternal) && "tooltip__wrapper--hidden"),
"aria-hidden": "true",
"data-popup-placement": middlewareData?.offset?.placement || placement,
children: /* @__PURE__ */ jsxs("div", {
className: "tooltip__content",
children: [children, /* @__PURE__ */ jsx("div", {
ref: setArrowElement,
style: {
left: middlewareData.arrow?.x,
top: middlewareData.arrow?.y
},
className: "tooltip__arrow"
})]
})
});
}
//#endregion
//#region react/enums/buttonEnums.js
/** @typedef {import('@utahdts/utah-design-system').ButtonAppearance} ButtonAppearance */
/** @typedef {import('@utahdts/utah-design-system').ButtonTypes} ButtonTypes */
/** @typedef {import('@utahdts/utah-design-system').IconButtonAppearance} IconButtonAppearance */
/** @enum {ButtonAppearance} */
var BUTTON_APPEARANCE = {
SOLID: "solid",
OUTLINED: "outlined"
};
/** @enum {ButtonTypes} */
var BUTTON_TYPES = {
BUTTON: "button",
RESET: "reset",
SUBMIT: "submit"
};
/** @enum {IconButtonAppearance} */
var ICON_BUTTON_APPEARANCE = {
SOLID: "solid",
OUTLINED: "outlined",
BORDERLESS: "borderless"
};
//#endregion
//#region react/enums/componentColors.js
/** @typedef {import('@utahdts/utah-design-system').ComponentColors} ComponentColors */
/** @enum {ComponentColors} */
var componentColors = {
PRIMARY: "primary",
SECONDARY: "secondary",
ACCENT: "accent",
NONE: "none"
};
//#endregion
//#region react/enums/formElementSizesEnum.js
/** @typedef {import('@utahdts/utah-design-system').FormElementSizes} FormElementSizes */
/** @enum {FormElementSizes} */
var formElementSizesEnum = {
SMALL3X: "small3x",
SMALL2X: "small2x",
SMALL1X: "small1x",
SMALL: "small",
MEDIUM: "medium",
LARGE: "large",
LARGE1X: "large1x"
};
//#endregion
//#region react/util/handleEvent.js
/**
* A function used as a callback often needs to the triggering event
* from triggering other events. Wrapping the function in this handleEvent function
* automatically stops the event propagation. ie handleEvent(() => { ... do something ... })
* @param {import('react').MouseEventHandler<HTMLButtonElement>} func The function to run
* @returns {import('react').MouseEventHandler<HTMLButtonElement>}
*/
function handleEvent(func) {
return (e) => {
if (e.preventDefault) e.preventDefault();
if (e.stopPropagation) e.stopPropagation();
if (e?.nativeEvent?.stopImmediatePropagation) e.nativeEvent.stopImmediatePropagation();
func.call(e.target, e);
};
}
//#endregion
//#region react/components/widgetsIndicators/Spinner.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} [props.children]
* @param {string} [props.className]
* @param {string} [props.id]
* @param {import('react').RefObject<HTMLDivElement>} [props.innerRef]
* @param {number} [props.size]
* @param {number} [props.strokeWidth]
* @param {number} [props.value]
* @returns {import('react').JSX.Element}
*/
function Spinner({ children, className, id, innerRef, size = 60, strokeWidth = 10, value = NaN, ...rest }) {
const strokeWidthUse = Number.isNaN(strokeWidth) ? 10 : strokeWidth;
const strokeWidthPlus1Use = Number.isNaN(strokeWidth) ? 10 : (strokeWidth ?? 0) + 1;
const widthUse = Number.isNaN(size) ? void 0 : size;
return /* @__PURE__ */ jsxs("div", {
"aria-valuemax": 100,
"aria-valuemin": 0,
"aria-valuenow": Number.isNaN(value) ? void 0 : (value ?? 0) * 100,
className: joinClassNames(className, "spinner", Number.isNaN(value) ? "spinner--indeterminate" : "spinner--determinate"),
id: id ?? void 0,
ref: innerRef,
role: "progressbar",
"aria-label": Number.isNaN(value) ? "Loading..." : `Loading ${(value ?? 0) * 100}% complete`,
...rest,
children: [/* @__PURE__ */ jsx("div", {
className: "spinner__animation",
children: /* @__PURE__ */ jsxs("svg", {
height: widthUse,
role: "presentation",
viewBox: "-10.00 -10.00 120.00 120.00",
width: widthUse,
children: [/* @__PURE__ */ jsx("path", {
strokeWidth: strokeWidthUse,
className: "spinner__track",
d: "M 50,50 m 0,-45 a 45,45 0 1 1 0,90 a 45,45 0 1 1 0,-90"
}), /* @__PURE__ */ jsx("path", {
className: "spinner__value",
d: "M 50,50 m 0,-45 a 45,45 0 1 1 0,90 a 45,45 0 1 1 0,-90",
pathLength: "360",
strokeDasharray: "360 360",
strokeDashoffset: 360 * (1 - (Number.isNaN(value) ? .25 : value ?? 0)),
strokeWidth: strokeWidthPlus1Use
})]
})
}), /* @__PURE__ */ jsx("div", {
className: "spinner__children",
children
})]
});
}
//#endregion
//#region react/components/buttons/Button.jsx
/** @typedef {import('@utahdts/utah-design-system').ButtonAppearance} ButtonAppearance */
/** @typedef {import('@utahdts/utah-design-system').ButtonTypes} ButtonTypes */
/** @typedef {import('@utahdts/utah-design-system').ComponentColors} ComponentColors */
/** @typedef {import('@utahdts/utah-design-system').FormElementSizes} FormElementSizes */
/**
* @param {object} props
* @param {ButtonAppearance} [props.appearance]
* @param {import('react').ReactNode} props.children most often is the title of the button, but can also contain most anything
* @param {string} [props.className] modify your button via className like 'button--primary' and other modifiers found in the button.scss
* @param {ComponentColors} [props.color] the base color of the button
* @param {import('react').RefObject<HTMLButtonElement | null>} [props.innerRef] a ref to attach to the actual DOM <button> element
* @param {import('react').ReactNode} [props.iconLeft]
* @param {import('react').ReactNode} [props.iconRight]
* @param {string} [props.id]
* @param {boolean} [props.isBusy] if the button is busy then it shows a spinner indicator on it and disables the button
* @param {boolean} [props.isDisabled]
* @param {import('react').MouseEventHandler<HTMLButtonElement>} props.onClick
* @param {FormElementSizes} [props.size]
* @param {ButtonTypes} [props.type]
* @returns {import('react').JSX.Element}
*/
function Button({ appearance = BUTTON_APPEARANCE.OUTLINED, children, className, color = componentColors.NONE, innerRef, isBusy, iconLeft, iconRight, isDisabled, id, onClick, size = "medium", type = BUTTON_TYPES.BUTTON, ...rest }) {
return /* @__PURE__ */ jsxs("button", {
className: joinClassNames("button", className, `button--${appearance}`, color && color !== componentColors.NONE ? `button--${color}-color` : null, size && size !== formElementSizesEnum.MEDIUM ? `button--${size}` : null),
disabled: isDisabled || isBusy,
id,
onClick: handleEvent((e) => onClick?.(e)),
ref: innerRef,
type,
...rest,
children: [
iconLeft ? /* @__PURE__ */ jsx("span", {
className: "button--icon button--icon-left",
children: iconLeft
}) : null,
children,
isBusy ? /* @__PURE__ */ jsx(Spinner, {
className: "ml-spacing-xs",
size: size === formElementSizesEnum.LARGE1X ? 24 : 22,
strokeWidth: size === formElementSizesEnum.LARGE1X ? 14 : 12
}) : null,
iconRight ? /* @__PURE__ */ jsx("span", {
className: "button--icon button--icon-right",
children: iconRight
}) : null
]
});
}
//#endregion
//#region react/components/buttons/ClickableTag.jsx
/** @typedef {import('@utahdts/utah-design-system').FormElementSizes} FormElementSizes */
/**
* @param {object} props
* @param {import('react').ReactNode} props.children most often is the title of the tag, but can also contain most anything
* @param {string} [props.className] modify your tag via className like 'tag--primary' and other modifiers found in the tag.scss
* @param {string} [props.id]
* @param {import('react').RefObject<HTMLDivElement>} [props.innerRef] a ref to attach to the wrapper <div>
* @param {import('react').ReactNode} [props.iconLeft] an icon for the left side of props.children
* @param {import('react').ReactNode} [props.iconRight] an icon for the right side of props.children
* @param {boolean} [props.isDisabled]
* @param {boolean} [props.isSelected]
* @param {import('react').MouseEventHandler<HTMLButtonElement>} [props.onClick]
* @param {FormElementSizes} [props.size]
* @returns {import('react').JSX.Element}
*/
function ClickableTag({ children, className, id, iconLeft, iconRight, innerRef, isDisabled, isSelected, onClick, size = formElementSizesEnum.MEDIUM, ...rest }) {
return /* @__PURE__ */ jsx("div", {
className: "tag__wrapper",
ref: innerRef,
children: /* @__PURE__ */ jsxs("button", {
"aria-pressed": isSelected,
className: joinClassNames("tag", "tag__button", `tag--${size}`, className, isSelected ? "tag--selected" : ""),
disabled: isDisabled,
id,
onClick: onClick && handleEvent((e) => onClick(e)),
type: "button",
...rest,
children: [
iconLeft ? /* @__PURE__ */ jsx("span", {
className: "tag--icon tag--icon-left",
children: iconLeft
}) : null,
children,
iconRight ? /* @__PURE__ */ jsx("span", {
className: "tag--icon tag--icon-right",
children: iconRight
}) : null
]
})
});
}
//#endregion
//#region react/components/buttons/ConfirmationButton/context/ConfirmationButtonContext.js
var ConfirmationButtonContext = createContext(false);
//#endregion
//#region react/components/buttons/ConfirmationButton/context/ConfirmationButtonContextProvider.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {boolean} props.isClicked
* @returns {import('react').JSX.Element}
*/
function ConfirmationButtonContextProvider({ children, isClicked }) {
return /* @__PURE__ */ jsx(ConfirmationButtonContext.Provider, {
value: isClicked,
children
});
}
//#endregion
//#region react/components/buttons/ConfirmationButton/ConfirmationButton.jsx
/** @typedef {import('@utahdts/utah-design-system').ButtonAppearance} ButtonAppearance */
/** @typedef {import('@utahdts/utah-design-system').ButtonTypes} ButtonTypes */
/** @typedef {import('@utahdts/utah-design-system').ComponentColors} ComponentColors */
/** @typedef {import('@utahdts/utah-design-system').FormElementSizes} FormElementSizes */
/** @typedef {import('@utahdts/utah-design-system').WrapInElement} WrapInElement */
/**
* @param {object} props
* @param {ButtonAppearance} [props.appearance]
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {ComponentColors} [props.color]
* @param {ComponentColors} [props.confirmationColor]
* @param {import('react').RefObject<HTMLButtonElement>} [props.innerRef]
* @param {boolean} [props.isBusy]
* @param {boolean} [props.isDisabled]
* @param {string} [props.id]
* @param {import('react').MouseEventHandler} props.onClick
* @param {FormElementSizes} [props.size]
* @param {ButtonTypes} [props.type]
* @returns {import('react').JSX.Element}
*/
function ConfirmationButton({ appearance = BUTTON_APPEARANCE.OUTLINED, children, className, color = componentColors.NONE, confirmationColor, id, innerRef, isBusy, isDisabled, onClick, size = "medium", type = BUTTON_TYPES.BUTTON, ...rest }) {
const [isClicked, setIsClicked] = useState(false);
const resetButton = useCallback(() => {
setIsClicked(false);
}, []);
const handleOnClick = handleEvent((e) => {
if (!isBusy) if (isClicked) {
onClick?.(e);
resetButton();
} else setIsClicked(true);
});
const onClickCallback = useCallback(handleOnClick, [handleOnClick]);
return /* @__PURE__ */ jsxs("button", {
className: joinClassNames("button", className, `button--${appearance}`, color && color !== "none" && !(isClicked && confirmationColor) ? `button--${color}-color` : null, size && size !== formElementSizesEnum.MEDIUM ? `button--${size}` : null, isClicked ? "button--confirm" : null, isClicked && confirmationColor ? `button--${confirmationColor}-color` : null),
disabled: isDisabled || isBusy,
id,
ref: innerRef,
onClick: onClickCallback,
onBlur: resetButton,
onKeyUp: handleKeyPress("Escape", resetButton),
type,
...rest,
children: [/* @__PURE__ */ jsx(ConfirmationButtonContextProvider, {
isClicked,
children
}), isBusy ? /* @__PURE__ */ jsx(Spinner, {
className: "ml-spacing-xs",
size: size === formElementSizesEnum.LARGE1X ? 24 : 22,
strokeWidth: size === formElementSizesEnum.LARGE1X ? 14 : 12
}) : null]
});
}
//#endregion
//#region react/components/buttons/ConfirmationButton/context/useConfirmationButtonContext.js
/** @returns {boolean} */
function useConfirmationButtonContext() {
return useContext(ConfirmationButtonContext);
}
//#endregion
//#region react/components/buttons/ConfirmationButton/ConfirmationChildren.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @returns {import('react').JSX.Element | null}
*/
function ConfirmationChildren({ children }) {
return useConfirmationButtonContext() ? /* @__PURE__ */ jsx(Fragment, { children }) : null;
}
//#endregion
//#region react/components/buttons/ConfirmationButton/InitialChildren.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @returns {import('react').JSX.Element | null}
*/
function InitialChildren({ children }) {
return useConfirmationButtonContext() ? null : /* @__PURE__ */ jsx(Fragment, { children });
}
//#endregion
//#region react/components/buttons/IconButton.jsx
/** @typedef {import('@utahdts/utah-design-system').IconButtonAppearance} IconButtonAppearance */
/**
* @param {object} props
* @param {IconButtonAppearance} [props.appearance]
* @param {import('react').ReactNode} [props.children]
* @param {string} [props.className]
* @param {'primary' | 'secondary' | 'accent' | 'none'} [props.color]
* @param {import('react').ReactNode} props.icon
* @param {string} [props.id]
* @param {import('react').MutableRefObject<HTMLButtonElement | null>} [props.innerRef]
* @param {boolean} [props.isDisabled]
* @param {boolean} [props.isTitleVisible]
* @param {import('react').MouseEventHandler<HTMLButtonElement>} [props.onClick] what to do when the button is clicked
* @param {'small1x' | 'small' | 'medium' | 'large' | 'large1x'} [props.size]
* @param {string} props.title A title is used for accessibility purposes to describe the button for screen readers
* @param {string | null} [props.tooltipText]
* @returns {import('react').JSX.Element}
*/
function IconButton({ appearance = ICON_BUTTON_APPEARANCE.OUTLINED, children, className, color = componentColors.NONE, icon, id, innerRef: draftInnerRef, isDisabled, isTitleVisible, onClick, size = "medium", title, tooltipText, ...rest }) {
const [referenceElement, setReferenceElement] = useState(null);
if (draftInnerRef && referenceElement) draftInnerRef.current = referenceElement;
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("button", {
className: joinClassNames("button icon-button", className, `${appearance === ICON_BUTTON_APPEARANCE.BORDERLESS ? "icon-button--" : "button--"}${appearance}`, color && color !== "none" ? `button--${color}-color` : null, isTitleVisible ? "icon-button--visible-title" : null, size && size !== formElementSizesEnum.MEDIUM ? `icon-button--${size}` : null),
disabled: isDisabled,
id: id || void 0,
onClick,
ref: setReferenceElement,
type: "button",
...rest,
children: [
icon,
/* @__PURE__ */ jsx("span", {
className: isTitleVisible ? void 0 : "visually-hidden",
children: title
}),
children
]
}), referenceElement ? /* @__PURE__ */ jsx(Tooltip, {
referenceElement,
children: tooltipText ?? title
}) : null] });
}
//#endregion
//#region react/components/buttons/Tag.jsx
/** @typedef {import('@utahdts/utah-design-system').FormElementSizes} FormElementSizes */
/**
* @param {object} props
* @param {import('react').ReactNode} props.children most often is the title of the tag, but can also contain most anything
* @param {string} [props.className]
* @param {string} [props.clearMessage] the message to show when hover the "x" icon
* @param {string} [props.id] the tag id
* @param {object} [props.iconButtonProps] props for the icon button
* @param {import('react').RefObject<HTMLDivElement>} [props.innerRef] a ref to attach to the actual DOM <button> or <span> element
* @param {import('react').ReactNode} [props.iconLeft] an icon for the left side
* @param {import('react').ReactNode} [props.iconRight] an icon for the right side
* @param {boolean} [props.isDisabled] tag isDisabled state
* @param {import('react').MouseEventHandler<HTMLButtonElement>} [props.onClear]
* @param {FormElementSizes} [props.size]
* @returns {import('react').JSX.Element}
*/
function Tag({ children, className, clearMessage = "Clear Tag", iconButtonProps = {}, innerRef, iconLeft, iconRight, isDisabled, id, onClear, size = formElementSizesEnum.MEDIUM, ...rest }) {
return /* @__PURE__ */ jsxs("div", {
className: joinClassNames("tag__wrapper", onClear && "tag--clearable"),
ref: innerRef,
...rest,
children: [/* @__PURE__ */ jsxs("span", {
className: joinClassNames("tag", className, `tag--${size}`),
id,
children: [
iconLeft ? /* @__PURE__ */ jsx("span", {
className: "tag--icon tag--icon-left",
children: iconLeft
}) : null,
children,
iconRight ? /* @__PURE__ */ jsx("span", {
className: "tag--icon tag--icon-right",
children: iconRight
}) : null
]
}), onClear ? /* @__PURE__ */ jsx(IconButton, {
className: "tag__clear-button icon-button--borderless icon-button--small1x",
icon: /* @__PURE__ */ jsx("span", {
className: "utds-icon-before-x-icon",
"aria-hidden": true
}),
onClick: onClear,
title: clearMessage,
isDisabled,
...iconButtonProps
}) : null]
});
}
//#endregion
//#region react/components/containers/accordion/Accordion.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {string} [props.contentClassName]
* @param {number} [props.headingLevel]
* @param {string} [props.headerClassName]
* @param {import('react').ReactNode} props.headerContent
* @param {string} props.id
* @param {boolean} [props.isOpen]
* @param {(previousIsOpen: boolean) => void} [props.onToggle]
* @returns {import('react').JSX.Element}
*/
function Accordion({ children, className, contentClassName, headingLevel = 2, headerClassName, headerContent, id, isOpen, onToggle }) {
const [stateIsOpen, setStateIsOpen] = useState(isOpen || false);
useEffect(() => {
setStateIsOpen(!!isOpen);
}, [isOpen]);
function toggleAccordion() {
if (onToggle) onToggle(stateIsOpen);
else setStateIsOpen(!stateIsOpen);
}
const HeadingTag = `h${headingLevel}`;
return /* @__PURE__ */ jsxs("div", {
className: joinClassNames(["accordion", className]),
id,
children: [/* @__PURE__ */ jsxs("button", {
"aria-expanded": stateIsOpen,
"aria-controls": `accordion-content__${id}`,
className: joinClassNames([
"accordion__header",
headerClassName,
stateIsOpen ? "accordion__header--open" : ""
]),
id: `accordion-button__${id}`,
onClick: handleEvent(toggleAccordion),
type: "button",
children: [/* @__PURE__ */ jsx(HeadingTag, {
id: `accordion-heading__${id}`,
children: headerContent
}), /* @__PURE__ */ jsx("span", {
className: `utds-icon-before-circle-chevron-up icon-button__icon ${stateIsOpen ? "" : "icon-button__icon--rotate180"}`,
"aria-hidden": "true"
})]
}), /* @__PURE__ */ jsx("div", {
"aria-hidden": !stateIsOpen,
"aria-labelledby": `accordion-button__${id}`,
inert: !stateIsOpen,
className: joinClassNames([
"accordion__content",
contentClassName,
stateIsOpen ? "accordion__content--open" : ""
]),
id: `accordion-content__${id}`,
role: "region",
children
})]
});
}
//#endregion
//#region react/contexts/UtahDesignSystemContext/UtahDesignSystemContext.js
/** @typedef {import('@utahdts/utah-design-system').UtahDesignSystemContextValue} UtahDesignSystemContextValue */
/** @typedef {import('use-immer').ImmerHook<UtahDesignSystemContextValue>} ImmerHookUtahDesignSystemContext */
var UtahDesignSystemContext = createContext([{
ariaLive: {
assertiveMessages: [],
politeMessages: []
},
banners: []
}, () => {}]);
//#endregion
//#region react/contexts/UtahDesignSystemContext/useUtahDesignSystemContext.js
/** @typedef {import('@utahdts/utah-design-system').UtahDesignSystemContextValue} UtahDesignSystemContextValue */
/** @typedef {import('use-immer').ImmerHook<UtahDesignSystemContextValue>} ImmerHookUtahDesignSystemContext */
/** @returns {ImmerHookUtahDesignSystemContext} */
function useUtahDesignSystemContext() {
return useContext(UtahDesignSystemContext);
}
//#endregion
//#region react/contexts/UtahDesignSystemContext/hooks/useAriaMessaging.js
/** @returns {{addAssertiveMessage: (message: string) => void, addPoliteMessage: (message: string) => void}} */
function useAriaMessaging() {
const [, setState] = useUtahDesignSystemContext();
const addPoliteMessage = useCallback(
/**
* @param {string} message
* @returns {void}
*/
(message) => {
setState((draftState) => {
draftState.ariaLive.politeMessages.push(message);
});
},
[setState]
);
const addAssertiveMessage = useCallback(
/**
* @param {string} message
* @returns {void}
*/
(message) => {
setState((draftState) => {
draftState.ariaLive.assertiveMessages.push(message);
});
},
[setState]
);
return useMemo(() => ({
addAssertiveMessage,
addPoliteMessage
}), [addAssertiveMessage, addPoliteMessage]);
}
//#endregion
//#region react/util/getFocusableElements.js
/**
* Based on the list from https://api.jqueryui.com/tabbable-selector/
* Used to get a list of focusable elements within a modal component
* @param {HTMLDialogElement} element
* @returns {HTMLElement[]}
*/
function getFocusableElements(element) {
return [...element.querySelectorAll("a[href], area[href], button, input, textarea, select, object, [tabindex]:not([tabindex=\"-1\"])")].filter((item) => !item.hasAttribute("disabled"));
}
//#endregion
//#region react/hooks/useHandleEscape.js
/**
* @param {import('react').KeyboardEventHandler} [onEscape]
* @returns {(...args: any[]) => void} func
*/
function useHandleEscape(onEscape) {
return useCallback((e) => {
if (e.code === "Escape" || e.key === "Escape") {
e.preventDefault();
e.stopPropagation();
if (onEscape) onEscape(e);
}
}, [onEscape]);
}
//#endregion
//#region react/hooks/useHandleTab.js
/**
* @param {HTMLElement | undefined} firstTabElement
* @param {HTMLElement | undefined} lastTabElement
* @returns {(...args: any[]) => void} func
*/
function useHandleTab(firstTabElement, lastTabElement) {
return useCallback((e) => {
if (e.code === "Tab" || e.key === "Tab") {
if (e.shiftKey) {
if (document.activeElement === firstTabElement) {
lastTabElement?.focus();
e.preventDefault();
}
} else if (document.activeElement === lastTabElement) {
firstTabElement?.focus();
e.preventDefault();
}
}
}, [firstTabElement, lastTabElement]);
}
//#endregion
//#region react/enums/drawerPlacement.js
/** @typedef {import('@utahdts/utah-design-system').DrawerPlacement} DrawerPlacement */
/**
* Positions for banners
* @enum {DrawerPlacement}
*/
var DRAWER_PLACEMENT = {
RIGHT: "drawer--right",
LEFT: "drawer--left"
};
//#endregion
//#region react/components/containers/drawer/Drawer.jsx
/** @typedef {import('@utahdts/utah-design-system').DrawerPlacement} DrawerPlacement */
/**
* @param {object} props
* @param {string} props.ariaLabelledBy Must match the id of the title of the drawer
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {string} props.id
* @param {import('react').Ref<HTMLDivElement>} [props.innerRef]
* @param {import('react').KeyboardEventHandler} [props.onEscape]
* @param {import('react').MouseEventHandler} [props.onClose]
* @param {DrawerPlacement} [props.position]
* @returns {React.JSX.Element}
*/
function Drawer({ ariaLabelledBy, children, className, id, innerRef, onClose, onEscape, position = DRAWER_PLACEMENT.RIGHT }) {
const ref = useRef(null);
const [lastActiveElement] = useImmer(
/** @type {HTMLElement | undefined} */
document.activeElement
);
const [firstTabElement, setFirstTabElement] = useImmer(
/** @type {HTMLElement | undefined} */
void 0
);
const [lastTabElement, setLastTabElement] = useImmer(
/** @type {HTMLElement | undefined} */
void 0
);
const { addAssertiveMessage } = useAriaMessaging();
const handleEscape = useHandleEscape(onEscape);
const handleTab = useHandleTab(firstTabElement, lastTabElement);
useEffect(() => {
if (ref.current) {
const list = getFocusableElements(ref.current);
if (list.length) {
const firstElement = list[0];
setFirstTabElement(firstElement);
const lastElement = list[list.length - 1];
setLastTabElement(lastElement);
firstElement?.focus();
} else console.warn("No focusable element found. Make sure to include a way to close the drawer.");
}
}, []);
useEffect(() => () => {
addAssertiveMessage("Closing drawer.");
lastActiveElement?.focus();
}, []);
return /* @__PURE__ */ jsx("div", {
className: "drawer-wrapper",
ref: innerRef,
children: /* @__PURE__ */ jsx("div", {
className: "drawer__backdrop backdrop-dark",
onClick: onClose,
children: /* @__PURE__ */ jsxs("dialog", {
"aria-labelledby": ariaLabelledBy,
className: joinClassNames("drawer__inner", position, className),
id,
onClick: (e) => e.stopPropagation(),
onKeyDown: handleTab,
onKeyUp: handleEscape,
ref,
children: [children, onClose ? /* @__PURE__ */ jsx(IconButton, {
appearance: ICON_BUTTON_APPEARANCE.BORDERLESS,
className: "drawer__close-button",
icon: /* @__PURE__ */ jsx("span", {
className: "utds-icon-before-x-icon",
"aria-hidden": "true"
}),
onClick: onClose,
size: "small",
title: "Close"
}) : void 0]
})
})
});
}
//#endregion
//#region react/components/containers/drawer/DrawerContent.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {string} [props.id]
* @returns {import('react').JSX.Element}
*/
function DrawerContent({ children, className, id }) {
return /* @__PURE__ */ jsx("div", {
className: joinClassNames("drawer__content", className),
id,
children
});
}
//#endregion
//#region react/components/containers/drawer/DrawerFooter.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {string} [props.id]
* @returns {import('react').JSX.Element}
*/
function DrawerFooter({ children, className, id }) {
return /* @__PURE__ */ jsx("div", {
className: joinClassNames("drawer__footer", className),
id,
children
});
}
//#endregion
//#region react/components/containers/drawer/DrawerTitle.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {string} props.id Make sure to match the ariaLabelledBy of the drawer
* @param {string} [props.tagName]
* @returns {import('react').JSX.Element}
*/
function DrawerTitle({ children, className, id, tagName: TagName = "div" }) {
return /* @__PURE__ */ jsx(TagName, {
className: joinClassNames("drawer__title", className),
id,
children
});
}
//#endregion
//#region react/components/containers/tabs/context/TabGroupContext.jsx
/** @typedef {import('@utahdts/utah-design-system').TabGroupContextValue} TabGroupContextValue */
var TabGroupContext = createContext({
isVertical: false,
navigateNext: () => {},
navigatePrevious: () => {},
registerTab: () => {},
selectedTabId: "",
setSelectedTabId: () => {},
tabGroupId: "",
unRegisterTab: () => {}
});
//#endregion
//#region react/components/containers/tabs/context/useTabGroupContext.js
/** @typedef { import('@utahdts/utah-design-system').TabGroupContextValue} TabGroupContextType */
/** @returns {TabGroupContextType} */
function useTabGroupContext() {
return useContext(TabGroupContext);
}
//#endregion
//#region react/components/containers/tabs/functions/generateTabId.js
/**
* @param {string} tabGroupId
* @param {string} tabId
* @returns {string}
*/
function generateTabId(tabGroupId, tabId) {
return `tab__${tabGroupId}__${tabId}`;
}
//#endregion
//#region react/components/containers/tabs/Tab.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} props.id
* @returns {import('react').JSX.Element}
*/
function Tab({ children, id }) {
const tabRef = useRef(
/** @type {HTMLButtonElement | null} */
null
);
const { isVertical, navigateNext, navigatePrevious, registerTab, selectedTabId, setSelectedTabId, tabGroupId, unRegisterTab } = useTabGroupContext();
const onKeyChange = (event) => {
if ([
"ArrowLeft",
"ArrowRight",
"ArrowUp",
"ArrowDown"
].includes(event.key)) event.preventDefault();
switch (event.key) {
case "ArrowLeft":
if (!isVertical) navigatePrevious();
break;
case "ArrowRight":
if (!isVertical) navigateNext();
break;
case "ArrowUp":
if (isVertical) navigatePrevious();
break;
case "ArrowDown":
if (isVertical) navigateNext();
break;
default: break;
}
};
useEffect(() => {
if (tabRef) registerTab(tabRef);
}, []);
useEffect(() => (() => {
unRegisterTab(tabRef);
}), []);
return /* @__PURE__ */ jsx("div", {
className: joinClassNames(selectedTabId === id && "tab-group__tab--selected", "tab-group__tab"),
role: "presentation",
children: /* @__PURE__ */ jsx("button", {
"aria-controls": `tabpanel__${tabGroupId}__${id}`,
"aria-selected": selectedTabId === id,
className: joinClassNames(selectedTabId === id && "tab-group__tab-button--selected", "tab-group__tab-button"),
id: generateTabId(tabGroupId, id),
onClick: handleEvent(() => setSelectedTabId(id)),
onKeyDown: onKeyChange,
ref: tabRef,
role: "tab",
tabIndex: selectedTabId === id ? 0 : -1,
type: "button",
children
})
});
}
//#endregion
//#region react/components/containers/tabs/TabGroup.jsx
/** @typedef {import('@utahdts/utah-design-system').TabGroupContextValue} TabGroupContextValue */
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {string} [props.defaultValue]
* @param {boolean} [props.isVertical]
* @param {(newTabId: string) => void} [props.onChange]
* @param {string} [props.value]
* @returns {import('react').JSX.Element}
*/
function TabGroup({ children, className, defaultValue, isVertical, onChange, value }) {
const tabGroupId = useId();
const tabGroupRef = useRef(
/** @type {HTMLDivElement | null} */
null
);
const [tabGroupState, setTabGroupState] = useImmer(() => ({
selectedTabId: defaultValue || "",
tabGroupId,
tabs: []
}));
const navigateTab = useCallback((tab) => {
if (tab) {
tab?.focus();
tab?.click();
}
}, []);
const findCurrentTabIndex = useCallback(() => tabGroupState.tabs.findIndex((tab) => tab?.id === generateTabId(tabGroupState.tabGroupId, tabGroupState.selectedTabId)), [tabGroupState]);
const registerTab = useCallback((tab) => {
setTabGroupState((draftState) => {
const checkTab = draftState.tabs.find((tabSearch) => tabSearch?.id === tab?.current?.id);
if (checkTab) Object.assign(checkTab, tab?.current);
else draftState.tabs.push(tab?.current);
});
}, [tabGroupState, setTabGroupState]);
const unRegisterTab = useCallback((tab) => {
setTabGroupState((draftState) => {
draftState.tabs = draftState.tabs.filter((filterTab) => filterTab?.id !== tab?.current?.id);
});
}, []);
useEffect(() => {
if (value !== void 0) setTabGroupState((draftState) => {
draftState.selectedTabId = value;
});
}, [value]);
/** @type {TabGroupContextValue} */
const contextValue = useMemo(() => ({
isVertical: !!isVertical,
navigateNext() {
const nextIndex = (findCurrentTabIndex() + 1) % tabGroupState.tabs.length;
navigateTab(tabGroupState?.tabs?.[nextIndex] || null);
},
navigatePrevious() {
const nextIndex = (findCurrentTabIndex() + tabGroupState.tabs.length - 1) % tabGroupState.tabs.length;
navigateTab(tabGroupState?.tabs?.[nextIndex] || null);
},
registerTab,
selectedTabId: value || tabGroupState.selectedTabId || "",
setSelectedTabId(tabId) {
if (onChange) onChange(tabId);
else setTabGroupState((draftState) => {
draftState.selectedTabId = tabId;
});
},
tabGroupId: tabGroupState.tabGroupId,
unRegisterTab
}), [tabGroupState, isVertical]);
return /* @__PURE__ */ jsx(TabGroupContext.Provider, {
value: contextValue,
children: /* @__PURE__ */ jsx("div", {
className: joinClassNames("tab-group", className, isVertical && "tab-group--vertical"),
id: `tab-group__${tabGroupState.tabGroupId}`,
ref: tabGroupRef,
children
})
});
}
//#endregion
//#region react/components/containers/tabs/TabGroupTitle.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {string} [props.tagName]
* @returns {import('react').JSX.Element}
*/
function TabGroupTitle({ children, className, tagName: TagName = "div" }) {
const { tabGroupId } = useTabGroupContext();
return /* @__PURE__ */ jsx(TagName, {
id: `tab-group__${tabGroupId}`,
className: joinClassNames("tag-group__title", className),
children
});
}
//#endregion
//#region react/components/containers/tabs/TabList.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @returns {import('react').JSX.Element}
*/
function TabList({ children, className }) {
const { isVertical } = useTabGroupContext();
return /* @__PURE__ */ jsx("div", {
className: joinClassNames(className, "tab-group__list"),
role: "tablist",
"aria-orientation": isVertical ? "vertical" : "horizontal",
children
});
}
//#endregion
//#region react/components/containers/tabs/TabPanel.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string} [props.className]
* @param {string} props.tabId
* @returns {import('react').JSX.Element}
*/
function TabPanel({ children, className, tabId }) {
const { selectedTabId, tabGroupId } = useTabGroupContext();
return /* @__PURE__ */ jsx("div", {
"aria-labelledby": `tab__${tabGroupId}__${tabId}`,
className: joinClassNames(className, selectedTabId !== tabId && "visually-hidden", "tab-group__panel"),
id: `tabpanel__${tabGroupId}__${tabId}`,
role: "tabpanel",
tabIndex: selectedTabId === tabId ? 0 : -1,
inert: selectedTabId !== tabId,
children
});
}
//#endregion
//#region react/components/containers/tabs/TabPanels.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @returns {import('react').JSX.Element}
*/
function TabPanels({ children }) {
return /* @__PURE__ */ jsx("div", {
className: "tab-group__panels",
role: "presentation",
children
});
}
//#endregion
//#region react/components/footer/FooterAgencyInformation.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @returns {import('react').JSX.Element}
*/
function FooterAgencyInformation({ children }) {
return /* @__PURE__ */ jsx("div", {
className: "utah-design-system",
children: /* @__PURE__ */ jsx("div", {
className: "footer-agency-information",
children
})
});
}
//#endregion
//#region react/components/footer/FooterAgencyInformationColumn.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @returns {import('react').JSX.Element}
*/
function FooterAgencyInformationColumn({ children }) {
return /* @__PURE__ */ jsx("div", {
className: "footer-agency-information__column",
children
});
}
//#endregion
//#region react/components/footer/FooterAgencyInformationInfo.jsx
/** @typedef {import('@utahdts/utah-design-system').Address} Address */
/**
* @param {object} props
* @param {string} props.agencyTitleFirstLine ie Utah Department of (smaller font above main title)
* @param {string} [props.agencyTitleSecondLine] ie Government Operations (larger font below firstLine)
* @param {Address} props.address
* @param {string} props.email
* @param {import('react').ReactNode} props.logo
* @param {string} [props.phone]
* @returns {import('react').JSX.Element}
*/
function FooterAgencyInformationInfo({ agencyTitleFirstLine, agencyTitleSecondLine, address, email, logo, phone }) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsxs("div", {
className: "footer-agency-information__title-wrapper",
children: [/* @__PURE__ */ jsx("div", {
className: "footer-agency-information__title-image",
children: logo
}), /* @__PURE__ */ jsxs("div", {
className: "footer-agency-information__title",
children: [/* @__PURE__ */ jsx("div", {
className: "footer-agency-information__first-line",
children: agencyTitleFirstLine
}), /* @__PURE__ */ jsx("div", {
className: "footer-agency-information__second-line",
children: agencyTitleSecondLine
})]
})]
}),
/* @__PURE__ */ jsxs("div", {
className: "footer-agency-information__address",
children: [
/* @__PURE__ */ jsx("span", {
className: "footer-agency-information__address-street-address-1",
children: address.streetAddress1
}),
/* @__PURE__ */ jsx("br", {}),
address.streetAddress2 ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
className: "footer-agency-information__address-street-address-2",
children: address.streetAddress2
}), /* @__PURE__ */ jsx("br", {})] }) : void 0,
/* @__PURE__ */ jsxs("span", {
className: "footer-agency-information__address-city-state-zip",
children: [
address.city,
", ",
address.state,
" ",
address.zipCode
]
})
]
}),
/* @__PURE__ */ jsx("div", {
className: "footer-agency-information__email",
children: /* @__PURE__ */ jsx("a", {
href: `mailto:${email}`,
children: email
})
}),
phone && /* @__PURE__ */ jsx("div", {
className: "footer-agency-information__phone",
children: /* @__PURE__ */ jsx("a", {
href: `tel:${phone}`,
children: phone
})
})
] });
}
//#endregion
//#region react/components/footer/FooterSocialMediaBar.jsx
/**
* @param {object} props
* @param {import('react').ReactNode} props.children
* @param {string | null} props.title
* @returns {import('react').JSX.Element}
*/
function FooterSocialMediaBar({ children, title = "Follow us online" }) {
return /* @__PURE__ */ jsx("div", {
className: "utah-design-system",
children: /* @__PURE__ */ jsxs("div", {
className: "footer-social-media-bar",
children: [/* @__PURE__ */ jsx("div", {
className: "footer-social-media-bar__follow-us",
children: title
}), /* @__PURE__ */ jsx("div", {
className: "footer-social-media-bar__icon-bar",
children
})]
})
});
}
//#endregion
//#region react/util/useOnKeyUp.js
/**
* @template KeyboardEventElementT
* @param {string} targetKey which key to watch for (ie 'Enter') https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values
* @param {import('react').KeyboardEventHandler<KeyboardEventElementT>} func the function to call when the given key is pressed
* @param {boolean} [stopPropagation]
* @returns {(event: React.KeyboardEvent<KeyboardEventElementT>) => boolean} function that checks for the keypress and fires function when pressed
*/
function useOnKeyUp(targetKey, func, stopPropagation) {
return useCallback((e) => {
const isMatchingKey = e.key === targetKey;
if (isMatchingKey) {
if (stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
func(e);
}
return isMatchingKey;
}, [
func,
stopPropagation,
targetKey
]);
}
//#endregion
//#region react/components/forms/ErrorMessage.jsx
/**
* @param {object} props
* @param {string} [props.errorMessage]
* @param {string} props.id
* @returns {import('react').JSX.Element | null}
*/
function ErrorMessage({ errorMessage, id }) {
return errorMessage ? /* @__PURE__ */ jsx("div", {
className: "input-wrapper__error-message",
id: `error__${id}`,
children: errorMessage
}) : null;
}
//#endregion
//#region react/components/forms/RequiredStar.jsx
function RequiredStar() {
return /* @__PURE__ */ jsx("span", {
className: "required-star",
"aria-hidden": true,
children: "*"
});
}
//#endregion
//#region react/components/forms/CalendarInput/calendarGrid.js
/** @typedef {import('@utahdts/utah-design-system').CalendarGridValue} CalendarGridValue */
/** @typedef {import('@utahdts/utah-design-system').CalendarGridMonth} CalendarGridMonth */
/**
* @param {Date} dateA
* @param {Date} dateB
* @returns {number} negative, 0, or positive indicative of sort order
*/
function dateIsEqualYM(dateA, dateB) {
return dateA.getFullY