@utahdts/utah-design-system-header 1.2.1 → 1.3.0

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 (96) hide show
  1. package/dist/index.d.ts +576 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/style.css +1 -1
  4. package/dist/utah-design-system-header.es.js +5 -5
  5. package/dist/utah-design-system-header.umd.js +4 -4
  6. package/package.json +5 -4
  7. package/src/index.js +11 -0
  8. package/src/js/enumerations/childrenMenuTypes.js +13 -0
  9. package/src/js/enumerations/domConstants.js +149 -0
  10. package/src/js/enumerations/environments.js +16 -0
  11. package/src/js/enumerations/events.js +14 -0
  12. package/src/js/enumerations/popupPlacement.js +32 -0
  13. package/src/js/enumerations/sizes.js +12 -0
  14. package/src/js/enumerations/utahIdUrls.js +10 -0
  15. package/src/js/lifecycle/globalEvents.js +81 -0
  16. package/src/js/lifecycle/hookupMobileActionItemKeyboarding.js +114 -0
  17. package/src/js/lifecycle/lifecycle.js +180 -0
  18. package/src/js/misc/checkForError.js +16 -0
  19. package/src/js/misc/findRecursive.js +39 -0
  20. package/src/js/misc/isString.js +8 -0
  21. package/src/js/misc/isTouchDevice.js +9 -0
  22. package/src/js/misc/jsDocTypes.js +235 -0
  23. package/src/js/misc/notNull.js +15 -0
  24. package/src/js/misc/popupFocusHandler.js +209 -0
  25. package/src/js/misc/renderDOMSingle.js +61 -0
  26. package/src/js/misc/showHideElement.js +15 -0
  27. package/src/js/misc/toHash.js +18 -0
  28. package/src/js/misc/uuidv4.js +8 -0
  29. package/src/js/misc/valueOrFunctionValue.js +13 -0
  30. package/src/js/renderables/_html/NewTabAccessibility.html +4 -0
  31. package/src/js/renderables/actionItems/ActionItems.js +29 -0
  32. package/src/js/renderables/actionItems/html/ActionItem.html +5 -0
  33. package/src/js/renderables/actionItems/html/ActionItemMenuContent.html +3 -0
  34. package/src/js/renderables/actionItems/html/ActionItemsWrapper.html +1 -0
  35. package/src/js/renderables/actionItems/html/BadgeWrapperHtml.html +4 -0
  36. package/src/js/renderables/actionItems/html/MobileActionItem.html +7 -0
  37. package/src/js/renderables/actionItems/renderActionItem.js +103 -0
  38. package/src/js/renderables/actionItems/renderActionItemBadge.js +50 -0
  39. package/src/js/renderables/actionItems/renderMobileActionItem.js +97 -0
  40. package/src/js/renderables/actionItems/renderMobileActionItems.js +83 -0
  41. package/src/js/renderables/citizenExperience/CitizenExperience.js +24 -0
  42. package/src/js/renderables/citizenExperience/html/CitizenExperienceWrapper.html +1 -0
  43. package/src/js/renderables/citizenExperience/html/CitizenExperienceWrapperMobile.html +1 -0
  44. package/src/js/renderables/footer/html/Footer.html +41 -0
  45. package/src/js/renderables/footer/renderFooter.js +111 -0
  46. package/src/js/renderables/headerWrapper/HeaderWrapper.js +46 -0
  47. package/src/js/renderables/headerWrapper/html/HeaderLogoWrapper.html +1 -0
  48. package/src/js/renderables/headerWrapper/html/HeaderWrapper.html +1 -0
  49. package/src/js/renderables/headerWrapper/html/VerticalLine.html +1 -0
  50. package/src/js/renderables/icons/html/AlertIcon.html +1 -0
  51. package/src/js/renderables/icons/html/ChevronIcon.html +1 -0
  52. package/src/js/renderables/icons/html/ExternalLinkIcon.html +7 -0
  53. package/src/js/renderables/icons/html/GearIcon.html +1 -0
  54. package/src/js/renderables/icons/html/QuestionIcon.html +1 -0
  55. package/src/js/renderables/icons/html/WaffleIcon.html +1 -0
  56. package/src/js/renderables/logoTitle/LogoTitle.js +63 -0
  57. package/src/js/renderables/logoTitle/html/LogoTitleWrapper.html +4 -0
  58. package/src/js/renderables/logoTitle/html/LogoTitleWrapperLink.html +4 -0
  59. package/src/js/renderables/mainMenu/html/MainMenuItem.html +13 -0
  60. package/src/js/renderables/mainMenu/html/MainMenuWrapper.html +26 -0
  61. package/src/js/renderables/mainMenu/renderMainMenu.js +258 -0
  62. package/src/js/renderables/menu/html/MenuWithTitle.html +3 -0
  63. package/src/js/renderables/menu/renderMenuWithTitle.js +24 -0
  64. package/src/js/renderables/mobile/addMobileMenuContentItem.js +37 -0
  65. package/src/js/renderables/mobile/hookupHamburger.js +112 -0
  66. package/src/js/renderables/mobile/hookupUtahIdInMobileMenu.js +79 -0
  67. package/src/js/renderables/mobile/html/MobileMenuContentItemWrapper.html +2 -0
  68. package/src/js/renderables/mobile/html/MobileMenuWrapper.html +32 -0
  69. package/src/js/renderables/mobile/mobileMenuInteractionHandler.js +155 -0
  70. package/src/js/renderables/mobile/renderMobileMenuHomeMenu.js +15 -0
  71. package/src/js/renderables/mobile/util/getHamburgerElements.js +22 -0
  72. package/src/js/renderables/mobile/util/showHideHamburgerElements.js +32 -0
  73. package/src/js/renderables/popup/html/Popup.html +5 -0
  74. package/src/js/renderables/popup/renderPopup.js +41 -0
  75. package/src/js/renderables/popupMenu/html/PopupMenu.html +1 -0
  76. package/src/js/renderables/popupMenu/html/PopupMenuItem.html +12 -0
  77. package/src/js/renderables/popupMenu/renderPopupMenu.js +341 -0
  78. package/src/js/renderables/search/html/SearchModal.html +25 -0
  79. package/src/js/renderables/search/showSearchModal.js +132 -0
  80. package/src/js/renderables/tooltip/hookupTooltip.js +82 -0
  81. package/src/js/renderables/tooltip/html/Tooltip.html +5 -0
  82. package/src/js/renderables/utahId/UtahId.js +227 -0
  83. package/src/js/renderables/utahId/html/UtahIdButton.html +1 -0
  84. package/src/js/renderables/utahId/html/UtahIdWrapper.html +1 -0
  85. package/src/js/renderables/utahLogo/UtahLogo.js +48 -0
  86. package/src/js/renderables/utahLogo/html/UtahLogoLarge.html +17 -0
  87. package/src/js/renderables/utahLogo/html/UtahLogoMedium.html +17 -0
  88. package/src/js/renderables/utahLogo/html/UtahOfficialWebsiteHoverContent.html +4 -0
  89. package/src/js/renderables/utahLogo/html/UtahOfficialWebsitePopupContent.html +41 -0
  90. package/src/js/renderables/utahLogo/renderOfficialWebsite.js +139 -0
  91. package/src/js/settings/defaultSettings.js +31 -0
  92. package/src/js/settings/getUtahHeaderSettings.js +16 -0
  93. package/src/js/settings/settings.js +69 -0
  94. package/src/js/settings/settingsKeeper.js +47 -0
  95. package/src/js/utahId/httpRequest.js +42 -0
  96. package/src/js/utahId/utahIdData.js +165 -0
@@ -0,0 +1,7 @@
1
+ <div class="utds-header-mobile-menu__action-item" role="tab">
2
+ <button type="button" class="icon-button icon-button--borderless utds-header-action-item__icon-button">
3
+ <div class="utds-header-action-item__title visually-hidden"></div>
4
+ <span aria-hidden="true" role="presentation">
5
+ </button>
6
+ <span class="menu-chiclet"></span>
7
+ </div>
@@ -0,0 +1,103 @@
1
+ // @ts-check
2
+ // @ts-ignore
3
+ // eslint-disable-next-line import/no-unresolved
4
+ import ActionItemHtml from './html/ActionItem.html?raw';
5
+
6
+ import childrenMenuTypes from '../../enumerations/childrenMenuTypes';
7
+ import domConstants, { getCssClassSelector } from '../../enumerations/domConstants';
8
+ import popupFocusHandler from '../../misc/popupFocusHandler';
9
+ import renderDOMSingle from '../../misc/renderDOMSingle';
10
+ import uuidv4 from '../../misc/uuidv4';
11
+ import renderPopup from '../popup/renderPopup';
12
+ import renderPopupMenu from '../popupMenu/renderPopupMenu';
13
+ import hookupTooltip from '../tooltip/hookupTooltip';
14
+ import renderActionItemBadge from './renderActionItemBadge';
15
+
16
+ /**
17
+ * @typedef {import('../../misc/jsDocTypes').ActionItem} ActionItem
18
+ * @typedef {import('../../misc/jsDocTypes').PopupMenu} PopupMenu
19
+ */
20
+
21
+ /**
22
+ * Renders an Action Item for the action bar area.
23
+ * @param {ActionItem} actionItem - the action item to add
24
+ * @returns {Element}
25
+ */
26
+ export default function renderActionItem(actionItem) {
27
+ const actionItemElement = renderDOMSingle(ActionItemHtml);
28
+ const titleElement = document.createTextNode(actionItem.title);
29
+
30
+ const actionItemWrapper = /** @type {HTMLElement} */(actionItemElement instanceof HTMLCollection ? actionItemElement[0] : actionItemElement);
31
+ if (actionItem.showTitle) {
32
+ actionItemWrapper.classList.add(domConstants.ACTION_ITEM__ICON_BUTTON_TITLE);
33
+ }
34
+
35
+ const titleDiv = actionItemWrapper.querySelector(getCssClassSelector(domConstants.ACTION_ITEM__TITLE));
36
+ if (!titleDiv) {
37
+ throw new Error('renderActionItem: titleDiv not found');
38
+ }
39
+ titleDiv.appendChild(titleElement);
40
+ if (actionItem.showTitle) {
41
+ titleDiv.classList.remove(domConstants.VISUALLY_HIDDEN);
42
+ } else {
43
+ titleDiv.classList.add(domConstants.VISUALLY_HIDDEN);
44
+ }
45
+
46
+ const iconButton = actionItemElement.querySelector(getCssClassSelector(domConstants.ACTION_ITEM__ICON_BUTTON));
47
+ if (!iconButton) {
48
+ throw new Error('renderActionItem: iconButton not found');
49
+ }
50
+ if (actionItem.className) {
51
+ iconButton.classList.add(actionItem.className);
52
+ }
53
+
54
+ const badge = renderActionItemBadge(actionItem.badge);
55
+ if (badge) {
56
+ iconButton.appendChild(badge);
57
+ }
58
+
59
+ const actionItemIcon = renderDOMSingle(actionItem.icon);
60
+ actionItemIcon.setAttribute('role', 'presentation');
61
+ iconButton.appendChild(actionItemIcon);
62
+
63
+ if (!(iconButton instanceof HTMLElement)) {
64
+ throw new Error('renderActionItem: iconButton is not an HTMLElement');
65
+ }
66
+
67
+ if (actionItem.actionFunction) {
68
+ iconButton.onclick = actionItem.actionFunction;
69
+ } else if (actionItem.actionDom) {
70
+ // create popup content and make it visually-hidden
71
+ const iconButtonId = uuidv4();
72
+ iconButton.setAttribute('id', iconButtonId);
73
+
74
+ const popupWrapper = renderPopup(iconButton);
75
+ const popupContentWrapper = /** @type {HTMLElement} */(popupWrapper.querySelector(getCssClassSelector(domConstants.POPUP_CONTENT_WRAPPER)));
76
+ if (!popupContentWrapper) {
77
+ throw new Error('renderPopupMenu: contentWrapper not found');
78
+ }
79
+ popupContentWrapper.appendChild(renderDOMSingle(typeof actionItem.actionDom === 'function' ? actionItem.actionDom() : actionItem.actionDom));
80
+ actionItemElement.appendChild(popupWrapper);
81
+ popupFocusHandler(actionItemWrapper, iconButton, popupWrapper, 'dialog', undefined);
82
+ } else if (actionItem.actionPopupMenu) {
83
+ // content is a menu
84
+ const iconButtonId = uuidv4();
85
+ iconButton.setAttribute('id', iconButtonId);
86
+ const popupMenu = renderPopupMenu(
87
+ (/** @type {PopupMenu} */ (actionItem.actionPopupMenu)),
88
+ iconButton,
89
+ { childrenMenuType: childrenMenuTypes.INLINE }
90
+ );
91
+ actionItemElement.appendChild(popupMenu);
92
+
93
+ popupFocusHandler(actionItemWrapper, iconButton, popupMenu, 'menu', undefined);
94
+ } else {
95
+ // eslint-disable-next-line no-console
96
+ console.error(actionItem);
97
+ throw new Error('Action Item: no defined action; must have either actionFunction, actionDom, or actionPopupMenu');
98
+ }
99
+
100
+ hookupTooltip(actionItemElement, document.createTextNode(actionItem.title));
101
+
102
+ return actionItemElement;
103
+ }
@@ -0,0 +1,50 @@
1
+ // @ts-check
2
+ import domConstants, { getCssClassSelector } from '../../enumerations/domConstants';
3
+ import renderDOMSingle from '../../misc/renderDOMSingle';
4
+ // @ts-ignore
5
+ // eslint-disable-next-line import/no-unresolved
6
+ import BadgeWrapperHtml from './html/BadgeWrapperHtml.html?raw';
7
+
8
+ /**
9
+ * @typedef {import('../../misc/jsDocTypes').Badge} Badge
10
+ */
11
+
12
+ /**
13
+ * renders a badge on an action item
14
+ * @param {Badge | undefined} badge - the action's badge information
15
+ * @return {HTMLElement | null}
16
+ */
17
+ export default function renderActionItemBadge(badge) {
18
+ let badgeWrapper = null;
19
+ if (badge) {
20
+ /** @type HTMLElement */
21
+ badgeWrapper = /** @type {HTMLElement} */(renderDOMSingle(BadgeWrapperHtml));
22
+ badgeWrapper.classList.add(domConstants.BADGE_WRAPPER__ACTION_ITEM);
23
+
24
+ // add badge label to badge
25
+ const badgeLabel = badgeWrapper.querySelector(getCssClassSelector(domConstants.BADGE__LABEL));
26
+ if (!badgeLabel) {
27
+ throw new Error('renderActionItemBadge: badgeLabel not found');
28
+ }
29
+ badgeLabel.appendChild(document.createTextNode(badge.label));
30
+
31
+ // show value in badge if there is one
32
+ if ((badge.value || badge.value === 0)) {
33
+ const badgeValue = badgeWrapper.querySelector(getCssClassSelector(domConstants.BADGE__VALUE));
34
+ if (!badgeValue) {
35
+ throw new Error('renderActionItemBadge: badgeValue not found');
36
+ }
37
+ badgeValue.appendChild(document.createTextNode(`${badge.value}`));
38
+ } else {
39
+ // no value so make it smaller
40
+ badgeWrapper.classList.add(domConstants.BADGE_WRAPPER__SMALL);
41
+ }
42
+
43
+ // apply class name
44
+ if (badge.className) {
45
+ badgeWrapper.classList.add(badge.className);
46
+ }
47
+ }
48
+
49
+ return badgeWrapper;
50
+ }
@@ -0,0 +1,97 @@
1
+ // @ts-check
2
+ // @ts-ignore
3
+ // eslint-disable-next-line import/no-unresolved
4
+ import MobileActionItemHtml from './html/MobileActionItem.html?raw';
5
+ // @ts-ignore
6
+ // eslint-disable-next-line import/no-unresolved
7
+ import ActionItemMenuContentHtml from './html/ActionItemMenuContent.html?raw';
8
+
9
+ import childrenMenuTypes from '../../enumerations/childrenMenuTypes';
10
+ import domConstants, { getCssClassSelector } from '../../enumerations/domConstants';
11
+ import renderDOMSingle from '../../misc/renderDOMSingle';
12
+ import uuidv4 from '../../misc/uuidv4';
13
+ import { renderMenu } from '../popupMenu/renderPopupMenu';
14
+ import renderActionItemBadge from './renderActionItemBadge';
15
+
16
+ /**
17
+ * @typedef {import('../../misc/jsDocTypes').ActionItem} ActionItem
18
+ * @typedef {import('../../misc/jsDocTypes').PopupMenu} PopupMenu
19
+ */
20
+
21
+ /**
22
+ * Renders an Action Item for the action bar area.
23
+ * @param {ActionItem} actionItem - the action item to add
24
+ * @returns {{actionItemElement: HTMLElement, actionItemContent: HTMLElement | null}}
25
+ */
26
+ export default function renderMobileActionItem(actionItem) {
27
+ const actionItemElement = renderDOMSingle(MobileActionItemHtml);
28
+ if (!actionItemElement.getAttribute('id')) {
29
+ actionItemElement.setAttribute('id', uuidv4());
30
+ }
31
+ const titleElement = document.createTextNode(actionItem.title);
32
+
33
+ const actionItemWrapper = /** @type {HTMLElement} */(actionItemElement instanceof HTMLCollection ? actionItemElement[0] : actionItemElement);
34
+ if (actionItem.showTitle) {
35
+ actionItemWrapper.classList.add(domConstants.ACTION_ITEM__ICON_BUTTON_TITLE);
36
+ }
37
+ actionItemWrapper.classList.add(domConstants.MOBILE_MENU_ACTION_BAR__ACTION_ITEM_WRAPPER);
38
+ actionItemWrapper.classList.remove(domConstants.ACTION_ITEM);
39
+
40
+ const titleDiv = actionItemWrapper.querySelector(getCssClassSelector(domConstants.ACTION_ITEM__TITLE));
41
+ if (!titleDiv) {
42
+ throw new Error('renderActionItem: titleDiv not found');
43
+ }
44
+ titleDiv.appendChild(titleElement);
45
+ if (actionItem.showTitle) {
46
+ titleDiv.classList.remove(domConstants.VISUALLY_HIDDEN);
47
+ } else {
48
+ titleDiv.classList.add(domConstants.VISUALLY_HIDDEN);
49
+ }
50
+
51
+ const iconButton = /** @type {HTMLElement} */ (actionItemElement.querySelector(getCssClassSelector(domConstants.ACTION_ITEM__ICON_BUTTON)));
52
+ if (!iconButton) {
53
+ throw new Error('renderActionItem: iconButton not found');
54
+ }
55
+ if (actionItem.className) {
56
+ iconButton.classList.add(actionItem.className);
57
+ }
58
+
59
+ const badge = renderActionItemBadge(actionItem.badge);
60
+ if (badge) {
61
+ iconButton.appendChild(badge);
62
+ }
63
+
64
+ const actionItemIcon = renderDOMSingle(actionItem.icon);
65
+ actionItemIcon.setAttribute('role', 'presentation');
66
+ iconButton.appendChild(actionItemIcon);
67
+
68
+ /** @type {HTMLElement | null} */
69
+ let actionItemContent = null;
70
+ if (actionItem.actionFunction) {
71
+ iconButton.onclick = actionItem.actionFunction;
72
+ } else if (actionItem.actionDom) {
73
+ const iconButtonId = uuidv4();
74
+ iconButton.setAttribute('id', iconButtonId);
75
+ actionItemContent = renderDOMSingle(typeof actionItem.actionDom === 'function' ? actionItem.actionDom() : actionItem.actionDom);
76
+ } else if (actionItem.actionPopupMenu) {
77
+ // content is a menu
78
+ const iconButtonId = uuidv4();
79
+ iconButton.setAttribute('id', iconButtonId);
80
+
81
+ actionItemContent = renderDOMSingle(ActionItemMenuContentHtml);
82
+ const actionItemContentTitle = actionItemContent.querySelector(getCssClassSelector(domConstants.POPUP_MENU_WRAPPER__WRAPPER_TITLE));
83
+ if (!actionItemContentTitle) {
84
+ throw new Error('renderMobileActionItem: actionItemContentTitle not found');
85
+ }
86
+ actionItemContentTitle.appendChild(document.createTextNode(actionItem.actionPopupMenu.title));
87
+
88
+ const actionItemMenu = renderMenu(actionItem.actionPopupMenu.menuItems, { childrenMenuType: childrenMenuTypes.INLINE });
89
+ actionItemContent.appendChild(actionItemMenu);
90
+ } else {
91
+ // eslint-disable-next-line no-console
92
+ console.error(actionItem);
93
+ throw new Error('Action Item: no defined action; must have either actionFunction, actionDom, or actionPopupMenu');
94
+ }
95
+
96
+ return { actionItemElement, actionItemContent };
97
+ }
@@ -0,0 +1,83 @@
1
+ // @ts-check
2
+ import domConstants, { getCssClassSelector } from '../../enumerations/domConstants';
3
+ import getUtahHeaderSettings from '../../settings/getUtahHeaderSettings';
4
+ import addMobileMenuContentItem from '../mobile/addMobileMenuContentItem';
5
+ import mobileMenuInteractionHandler from '../mobile/mobileMenuInteractionHandler';
6
+ import renderMobileActionItem from './renderMobileActionItem';
7
+
8
+ /**
9
+ * @typedef {import('../../misc/jsDocTypes').ActionItem} ActionItem
10
+ * @typedef {import('../../misc/jsDocTypes').AriaHasPopupType} AriaHasPopupType
11
+ */
12
+
13
+ export default function renderMobileActionItems() {
14
+ const homeActionItem = document.getElementById(domConstants.MOBILE_MENU_ACTON_BAR__HOME_ID);
15
+ if (!homeActionItem) {
16
+ throw new Error('renderMobileActionItems: homeActionItem not found');
17
+ }
18
+ const homeActionItemWrapper = (
19
+ /** @type {HTMLElement} */ (homeActionItem.closest(getCssClassSelector(domConstants.MOBILE_MENU_ACTION_BAR__ACTION_ITEM_WRAPPER)))
20
+ );
21
+ if (!homeActionItemWrapper) {
22
+ throw new Error('renderMobileActionItems: homeActionItemWrapper not found');
23
+ }
24
+ const hasUtahId = !!getUtahHeaderSettings().utahId;
25
+ const profileActionItem = hasUtahId ? document.getElementById(domConstants.MOBILE_MENU_ACTON_BAR__PROFILE_ID) : null;
26
+ const profileActionItemWrapper = (
27
+ /** @type {HTMLElement} */ (profileActionItem?.closest?.(getCssClassSelector(domConstants.MOBILE_MENU_ACTION_BAR__ACTION_ITEM_WRAPPER)))
28
+ );
29
+
30
+ [...(getUtahHeaderSettings().actionItems || [])]
31
+ ?.reverse()
32
+ ?.map((actionItemToRender) => ({ actionItem: actionItemToRender, ...renderMobileActionItem(actionItemToRender) }))
33
+ ?.forEach(({ actionItem, actionItemContent, actionItemElement }) => {
34
+ /** @type {HTMLElement | null} */
35
+ let actionItemsWrapper;
36
+ switch (actionItem.mobileMenuLocation) {
37
+ case 'left':
38
+ actionItemsWrapper = homeActionItemWrapper;
39
+ break;
40
+
41
+ case 'none':
42
+ actionItemsWrapper = null;
43
+ break;
44
+
45
+ case 'right':
46
+ default:
47
+ // if right, but no admin button, just put on left with the rest of them (there is no right/left)
48
+ // default to right if not specified
49
+ actionItemsWrapper = profileActionItemWrapper || homeActionItemWrapper;
50
+ break;
51
+ }
52
+ if (actionItemsWrapper) {
53
+ actionItemsWrapper.after(actionItemElement);
54
+
55
+ // render content item and hook up exposing it
56
+ if (actionItemContent) {
57
+ const mobileContentItem = addMobileMenuContentItem(actionItemContent);
58
+
59
+ /** @type {AriaHasPopupType | null} */
60
+ let ariaHasPopupType = null;
61
+ if (actionItem.actionDom) {
62
+ ariaHasPopupType = 'dialog';
63
+ } else if (actionItem.actionPopupMenu) {
64
+ ariaHasPopupType = 'menu';
65
+ }
66
+
67
+ mobileMenuInteractionHandler(
68
+ actionItemElement,
69
+ mobileContentItem,
70
+ actionItemElement,
71
+ { ariaHasPopupType, shouldOnClickCloseMenu: false }
72
+ );
73
+ }
74
+ }
75
+ });
76
+
77
+ // no menu, no item. EOL.
78
+ const settings = getUtahHeaderSettings();
79
+ if (!settings.mainMenu) {
80
+ homeActionItem.remove();
81
+ homeActionItemWrapper.remove();
82
+ }
83
+ }
@@ -0,0 +1,24 @@
1
+ // @ts-check
2
+ // @ts-ignore
3
+ // eslint-disable-next-line import/no-unresolved
4
+ import CitizenExperienceWrapper from './html/CitizenExperienceWrapper.html?raw';
5
+
6
+ import renderDOMSingle from '../../misc/renderDOMSingle';
7
+ import getUtahHeaderSettings from '../../settings/getUtahHeaderSettings';
8
+ import ActionItems from '../actionItems/ActionItems';
9
+ import { renderUtahIdForDesktop } from '../utahId/UtahId';
10
+
11
+ export default function CitizenExperience() {
12
+ const citizenExperienceWrapper = renderDOMSingle(CitizenExperienceWrapper);
13
+
14
+ const actionItems = ActionItems();
15
+ if (actionItems) {
16
+ citizenExperienceWrapper.appendChild(actionItems);
17
+ }
18
+
19
+ if (getUtahHeaderSettings().utahId !== false) {
20
+ citizenExperienceWrapper.appendChild(renderUtahIdForDesktop());
21
+ }
22
+
23
+ return citizenExperienceWrapper;
24
+ }
@@ -0,0 +1 @@
1
+ <div class="utds-citizen-experience-wrapper"></div>
@@ -0,0 +1 @@
1
+ <div class="utds-citizen-experience-wrapper--mobile"></div>
@@ -0,0 +1,41 @@
1
+ <div class="utds-footer utah-design-system">
2
+ <div class="utds-footer__horizontal-divider">
3
+ <hr />
4
+ </div>
5
+ <div class="utds-footer__utah-logo-wrapper">
6
+ <div class="utah-logo-svg" id="utah-logo-svg">
7
+ <svg viewBox="0 0 107 30.51" role="img">
8
+ <g>
9
+ <path
10
+ d="m12.44,30.51c-4.21,0-7.33-1.22-9.38-3.66C1.02,24.4,0,20.61,0,15.48V0h7.93v16.4c0,2.67.36,4.55,1.08,5.65.77,1.12,2.08,1.74,3.43,1.64,1.36.1,2.68-.52,3.48-1.63.75-1.09,1.13-2.97,1.13-5.65V0h7.65v15.48c0,5.13-1,8.92-3,11.36-2,2.44-5.09,3.66-9.26,3.66Zm24.42-.56V6.64h-7.93V0h23.78v6.64h-7.93v23.31h-7.92Zm26.17-14.56l-.51,2.07h5.53l-.51-2.07c-.37-1.44-.74-3.01-1.11-4.7-.37-1.69-.74-3.29-1.11-4.79h-.18c-.34,1.53-.68,3.14-1.04,4.82-.35,1.68-.71,3.24-1.08,4.68Zm-11.52,14.56L60.64,0h9.58l9.12,29.95h-8.39l-1.48-6.36h-8.38l-1.47,6.36h-8.11Zm30.69,0V0h7.93v11.15h8.94V0h7.93v29.95h-7.93v-11.89h-8.94v11.89h-7.93Z" />
11
+ </g>
12
+ </svg>
13
+ </div>
14
+ <div class="utds-footer__vertical-divider" role="separator" aria-orientation="vertical"></div>
15
+ <div class="utds-footer__official-site-wrapper">
16
+ <div class="utds-footer__official-site">An official website of the <span class="whitespace-no-wrap">State of
17
+ Utah</span></div>
18
+ <div class="utds-footer__copyright">©2023 State of Utah</div>
19
+ </div>
20
+ </div>
21
+ <div class="utds-footer__links">
22
+ <ul>
23
+ <li>
24
+ <a href="https://www.utah.gov/index.html" target="__blank" rel="noreferrer">Utah.gov Home</a>
25
+ </li>
26
+ <li>
27
+ <a href="https://www.utah.gov/support/disclaimer.html" target="__blank" rel="noreferrer">Terms of Use</a>
28
+ </li>
29
+ <li>
30
+ <a href="https://www.utah.gov/support/privacypolicy.html" target="__blank" rel="noreferrer">Privacy
31
+ Policy</a>
32
+ </li>
33
+ <li>
34
+ <a href="https://www.utah.gov/support/accessibility.html" target="__blank" rel="noreferrer">Accessibility</a>
35
+ </li>
36
+ <li>
37
+ <a href="https://www.utah.gov/support/translate.html" target="__blank" rel="noreferrer">Translate</a>
38
+ </li>
39
+ </ul>
40
+ </div>
41
+ </div>
@@ -0,0 +1,111 @@
1
+ // @ts-check
2
+ // @ts-ignore
3
+ // eslint-disable-next-line import/no-unresolved
4
+ import footerHTML from './html/Footer.html?raw';
5
+ // @ts-ignore
6
+ // eslint-disable-next-line import/no-unresolved
7
+ import newTabAccessibilityHTML from '../_html/NewTabAccessibility.html?raw';
8
+
9
+ import domConstants, { getCssClassSelector } from '../../enumerations/domConstants';
10
+ import checkForError from '../../misc/checkForError';
11
+ import notNull from '../../misc/notNull';
12
+ import renderDOMSingle from '../../misc/renderDOMSingle';
13
+ import getUtahHeaderSettings from '../../settings/getUtahHeaderSettings';
14
+
15
+ /** @typedef {import('../../misc/jsDocTypes').DomLocationTarget} DomLocationTarget */
16
+ /** @typedef {import('../../misc/jsDocTypes').Settings} Settings */
17
+
18
+ /**
19
+ * track last known settings for future comparison to see if something changed
20
+ * make sure that shallow copying doesn't allow changing things outside of this function that
21
+ * then change this "previous" data making it seem like a change did not occur.
22
+ * @type {{domLocationTarget: DomLocationTarget, showHorizontalRule: boolean | undefined}}
23
+ */
24
+ const previousFooterSettings = {
25
+ domLocationTarget: {
26
+ cssSelector: undefined,
27
+ element: undefined,
28
+ elementFunction: undefined,
29
+ },
30
+ showHorizontalRule: false,
31
+ };
32
+
33
+ /**
34
+ * @returns {Element | null}
35
+ */
36
+ export default function renderFooter() {
37
+ const settings = getUtahHeaderSettings();
38
+ const previousFooter = document.querySelector(getCssClassSelector(domConstants.FOOTER));
39
+ let footer = previousFooter;
40
+
41
+ if (settings.footer === null) {
42
+ previousFooter?.remove();
43
+ } else {
44
+ const settingsChanged = (
45
+ previousFooterSettings.domLocationTarget.cssSelector !== settings?.footer?.domLocationTarget?.cssSelector
46
+ || previousFooterSettings.domLocationTarget.element !== settings?.footer?.domLocationTarget?.element
47
+ || previousFooterSettings.domLocationTarget.elementFunction !== settings?.footer?.domLocationTarget?.elementFunction
48
+ || previousFooterSettings.showHorizontalRule !== settings?.footer?.showHorizontalRule
49
+ );
50
+
51
+ if (settingsChanged || !previousFooter) {
52
+ // kill old footer
53
+ if (previousFooter) {
54
+ previousFooter.remove();
55
+ }
56
+
57
+ // render footer in domLocationTarget (default body)
58
+ footer = renderDOMSingle(footerHTML);
59
+ /** @type {HTMLElement | null} */
60
+ let domTarget = document.body;
61
+ if (settings?.footer?.domLocationTarget) {
62
+ const targets = (
63
+ [
64
+ settings?.footer?.domLocationTarget.cssSelector,
65
+ settings?.footer?.domLocationTarget.element,
66
+ settings?.footer?.domLocationTarget.elementFunction,
67
+ ]
68
+ .filter((setting) => setting)
69
+ );
70
+ checkForError(targets.length < 1, 'renderFooter: footer.domLocationTarget must either have a value for one of its properties or not be specified at all');
71
+ checkForError(targets.length > 1, 'renderFooter: footer.domLocationTarget must only have one target specified');
72
+
73
+ if (settings?.footer?.domLocationTarget.cssSelector) {
74
+ domTarget = document.querySelector(settings?.footer?.domLocationTarget.cssSelector);
75
+ checkForError(!domTarget, `renderFooter: element not found for domLocationTarget.cssSelector ${settings?.footer?.domLocationTarget.cssSelector}`);
76
+ } else if (settings?.footer?.domLocationTarget.element) {
77
+ domTarget = settings?.footer?.domLocationTarget.element;
78
+ } else if (settings?.footer?.domLocationTarget.elementFunction) {
79
+ domTarget = settings?.footer?.domLocationTarget.elementFunction();
80
+ checkForError(!domTarget, 'renderFooter: element not returned from domLocationTarget.elementFunction');
81
+ } else {
82
+ throw new Error('renderFooter: domLocationTarget must have at least one field set');
83
+ }
84
+ }
85
+ domTarget?.appendChild(footer);
86
+
87
+ // remove horizontal rule if not wanted
88
+ if (!settings?.footer?.showHorizontalRule) {
89
+ const footerHr = document.querySelector(getCssClassSelector(domConstants.FOOTER_HORIZONTAL_DIVIDER));
90
+ checkForError(!footerHr, 'renderFooter: cannot remove horizontal rule; not found');
91
+ footerHr?.remove();
92
+ }
93
+
94
+ // make links external links
95
+ const footerLinks = notNull(document.querySelector(getCssClassSelector(domConstants.FOOTER_LINKS)), 'renderFooter: footer links not found');
96
+ const lis = footerLinks.querySelectorAll('a');
97
+ lis.forEach((link) => {
98
+ link.appendChild(renderDOMSingle(newTabAccessibilityHTML));
99
+ });
100
+
101
+ // make a copy for future comparison
102
+ // this is not a shallow copy of the settings, so that external changes don't update internal values
103
+ previousFooterSettings.domLocationTarget.cssSelector = settings?.footer?.domLocationTarget?.cssSelector;
104
+ previousFooterSettings.domLocationTarget.element = settings?.footer?.domLocationTarget?.element;
105
+ previousFooterSettings.domLocationTarget.elementFunction = settings?.footer?.domLocationTarget?.elementFunction;
106
+ previousFooterSettings.showHorizontalRule = settings?.footer?.showHorizontalRule;
107
+ }
108
+ }
109
+
110
+ return footer;
111
+ }
@@ -0,0 +1,46 @@
1
+ // @ts-check
2
+ // @ts-ignore
3
+ // eslint-disable-next-line import/no-unresolved
4
+ import CitizenExperienceWrapperMobile from '../citizenExperience/html/CitizenExperienceWrapperMobile.html?raw';
5
+ // @ts-ignore
6
+ // eslint-disable-next-line import/no-unresolved
7
+ import headerLogoWrapper from './html/HeaderLogoWrapper.html?raw';
8
+ // @ts-ignore
9
+ // eslint-disable-next-line import/no-unresolved
10
+ import headerWrapper from './html/HeaderWrapper.html?raw';
11
+ // @ts-ignore
12
+ // eslint-disable-next-line import/no-unresolved
13
+ import verticalLineHtml from './html/VerticalLine.html?raw';
14
+
15
+ import sizes from '../../enumerations/sizes';
16
+ import renderDOMSingle from '../../misc/renderDOMSingle';
17
+ import getUtahHeaderSettings from '../../settings/getUtahHeaderSettings';
18
+ import CitizenExperience from '../citizenExperience/CitizenExperience';
19
+ import LogoTitle from '../logoTitle/LogoTitle';
20
+ import UtahLogo from '../utahLogo/UtahLogo';
21
+
22
+ /**
23
+ * Creates the header wrapper DOM and appends the:
24
+ * Utah logo, flexible space, Agency Logo, and citizen experience (action items, utah id button) to it.
25
+ *
26
+ * @returns {Element}
27
+ */
28
+ export default function HeaderWrapper() {
29
+ const header = renderDOMSingle(headerWrapper);
30
+
31
+ header.classList.add(`utds-header--${getUtahHeaderSettings().size?.toLowerCase() || sizes.MEDIUM}`);
32
+
33
+ const logoWrapper = renderDOMSingle(headerLogoWrapper);
34
+ header.appendChild(logoWrapper);
35
+
36
+ logoWrapper.appendChild(UtahLogo());
37
+
38
+ logoWrapper.appendChild(renderDOMSingle(verticalLineHtml));
39
+
40
+ logoWrapper.appendChild(LogoTitle());
41
+
42
+ header.appendChild(CitizenExperience());
43
+ header.appendChild(renderDOMSingle(CitizenExperienceWrapperMobile));
44
+
45
+ return header;
46
+ }
@@ -0,0 +1 @@
1
+ <h1 class="utds-logo-wrapper"></h1>
@@ -0,0 +1 @@
1
+ <header class="utah-design-system utds-header" aria-label="Utah.gov Header"></header>
@@ -0,0 +1 @@
1
+ <span class="utds-logo-vert-line"></span>
@@ -0,0 +1 @@
1
+ <span class="utds-icon-before-alert" aria-hidden="true" />
@@ -0,0 +1 @@
1
+ <span class="utds-icon-before-chevron-right vertical-menu__chevron" aria-hidden="true"></span>
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.1143 18.1138">
2
+ <g>
3
+ <path d="m15.0996,18.1138H1c-.5527,0-1-.4478-1-1V3.0142c0-.5522.4473-1,1-1h7.043v2H2v12.0996h12.0996v-6.043h2v7.043c0,.5522-.4473,1-1,1Z"/>
4
+ <rect x="6.5977" y="4.5318" width="11.9697" height="1.9998" transform="translate(-.2262 10.5174) rotate(-45)"/>
5
+ <polygon points="18.1143 8.0425 16.1143 8.0425 16.1143 2 10.0713 2 10.0713 0 18.1143 0 18.1143 8.0425"/>
6
+ </g>
7
+ </svg>
@@ -0,0 +1 @@
1
+ <span class="utds-icon-before-gear" aria-hidden="true" />
@@ -0,0 +1 @@
1
+ <span class="utds-icon-before-help" aria-hidden="true" />
@@ -0,0 +1 @@
1
+ <span class="utds-icon-before-waffle" aria-hidden="true" />