@gsa-tts/graymatter-ui 0.4.11 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsa-tts/graymatter-ui",
3
- "version": "0.4.11",
3
+ "version": "0.4.13",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -5,7 +5,6 @@
5
5
  selectedSubNavItemTitle,
6
6
  } from '../stores/navigationStore.js';
7
7
  import { onMount } from 'svelte';
8
- import { subNavReady } from '../stores/subNavReadyStore';
9
8
 
10
9
  const { customHeaderText = '' } = $props();
11
10
 
@@ -16,8 +15,7 @@
16
15
  $selectedItem &&
17
16
  $selectedItem !== 'discover' &&
18
17
  !$isExpanded &&
19
- !isLayoutTransitioning &&
20
- $subNavReady
18
+ !isLayoutTransitioning
21
19
  );
22
20
  const headerText = $derived(
23
21
  () => customHeaderText || $selectedSubNavItemTitle
@@ -11,10 +11,8 @@
11
11
  selectedItem,
12
12
  isMenuButtonDisabled,
13
13
  navigationStore,
14
- selectedSubNavItemId,
15
14
  type NavigationItem,
16
15
  } from '../stores/navigationStore.js';
17
- import { get } from 'svelte/store';
18
16
  import DiscoverIcon from './icons/DiscoverIcon.svelte';
19
17
  import ChatIcon from './icons/ChatIcon.svelte';
20
18
  import ConsoleIcon from './icons/ConsoleIcon.svelte';
@@ -38,7 +36,31 @@
38
36
  } = $props();
39
37
 
40
38
  const helpUrl = supplementalMenuData?.help?.url?.trim();
41
- const isHelpSelected = $derived(() => get(selectedSubNavItemId) === 'help');
39
+
40
+ // Check if we're on the help page by comparing URLs (help is not a nav/subnav item)
41
+ function getPathname(url: string, baseOrigin: string) {
42
+ try {
43
+ return new URL(url, baseOrigin).pathname;
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
48
+
49
+ function checkIsHelpPage(): boolean {
50
+ if (!helpUrl || helpUrl === '#' || helpUrl.startsWith('#')) {
51
+ return false;
52
+ }
53
+ const location = (
54
+ globalThis as { location?: { pathname?: string; origin?: string } }
55
+ ).location;
56
+ if (location?.origin && location?.pathname) {
57
+ const helpPath = getPathname(helpUrl, location.origin);
58
+ return helpPath !== null && location.pathname === helpPath;
59
+ }
60
+ return false;
61
+ }
62
+
63
+ const isHelpSelected = $derived(checkIsHelpPage());
42
64
 
43
65
  let hydrated = false;
44
66
  let navContainer: HTMLDivElement;
@@ -170,40 +192,19 @@
170
192
  );
171
193
  };
172
194
 
173
- // Detect help page and set selection state
174
- const checkHelpPage = () => {
175
- // Skip check for hash links - they stay on the same page
176
- if (!helpUrl || helpUrl === '#' || helpUrl.startsWith('#')) {
177
- return;
178
- }
179
-
180
- const location = (
181
- globalThis as { location?: { pathname?: string; origin?: string } }
182
- ).location;
183
- if (location?.origin && location?.pathname) {
184
- const helpPath = getPathname(helpUrl, location.origin);
185
- if (helpPath && location.pathname === helpPath) {
186
- selectedSubNavItemId.set('help');
187
- } else if (
188
- get(selectedSubNavItemId) === 'help' &&
189
- helpPath &&
190
- location.pathname !== helpPath
191
- ) {
192
- // Clear help selection if we navigated away from help page
193
- selectedSubNavItemId.set(null);
194
- }
195
- }
195
+ // Listen for navigation changes to update help button state
196
+ const handleNavigationChange = () => {
197
+ // Force reactivity update by accessing the derived value
198
+ // Accessing isHelpSelected triggers reactivity
199
+ void isHelpSelected;
196
200
  };
197
201
 
198
- checkHelpPage();
199
-
200
- // Also listen for popstate events (back/forward navigation)
201
- window.addEventListener('popstate', checkHelpPage);
202
+ window.addEventListener('popstate', handleNavigationChange);
202
203
 
203
204
  return () => {
204
205
  window.removeEventListener('layoutTransition', handleLayoutTransition);
205
206
  window.removeEventListener('keydown', handleEscape);
206
- window.removeEventListener('popstate', checkHelpPage);
207
+ window.removeEventListener('popstate', handleNavigationChange);
207
208
  if (eventListenerCleanup) {
208
209
  eventListenerCleanup();
209
210
  }
@@ -211,22 +212,10 @@
211
212
  }
212
213
  });
213
214
 
214
- function getPathname(url: string, baseOrigin: string) {
215
- try {
216
- return new URL(url, baseOrigin).pathname;
217
- } catch {
218
- return null;
219
- }
220
- }
221
-
222
215
  function handleHelpClick(event: MouseEvent) {
223
- selectedSubNavItemId.set('help');
224
-
225
- // If it's a hash link, prevent default to maintain state on same page
216
+ // If it's a hash link, prevent default to stay on same page
226
217
  if (helpUrl === '#' || helpUrl?.startsWith('#')) {
227
218
  event.preventDefault();
228
- // State is already set above, so it will persist
229
- return;
230
219
  }
231
220
  }
232
221
 
@@ -488,8 +477,8 @@
488
477
  >
489
478
  <a
490
479
  class="help-link"
491
- class:selected={isHelpSelected()}
492
- aria-current={isHelpSelected()}
480
+ class:selected={isHelpSelected}
481
+ aria-current={isHelpSelected ? 'page' : undefined}
493
482
  href={helpUrl}
494
483
  part="help-link"
495
484
  title="Help"
@@ -498,7 +487,7 @@
498
487
  >
499
488
  <div class="icon-container" part="help-icon-container">
500
489
  <div class="icon-wrapper">
501
- <HelpIcon isSelected={isHelpSelected()} />
490
+ <HelpIcon isSelected={isHelpSelected} />
502
491
  </div>
503
492
  </div>
504
493
  </a>
@@ -675,7 +664,8 @@
675
664
  }
676
665
 
677
666
  .menu-button:focus,
678
- .nav-item:focus {
667
+ .nav-item:focus,
668
+ .help-link:focus {
679
669
  outline: none;
680
670
  }
681
671
 
@@ -3,13 +3,11 @@
3
3
  isMenuButtonDisabled,
4
4
  navigationStore,
5
5
  selectedSubNavItemTitle,
6
- selectedSubNavItemId,
7
6
  } from '../stores/navigationStore.js';
8
7
  import Logo from './Logo.svelte';
9
8
  import MenuIcon from './icons/MenuIcon.svelte';
10
9
  import HelpIcon from './icons/HelpIcon.svelte';
11
10
  import { onMount } from 'svelte';
12
- import { get } from 'svelte/store';
13
11
 
14
12
  let { profileMenuData, logoLinkUrl, logoLinkLabel, supplementalMenuData } =
15
13
  $props();
@@ -17,14 +15,37 @@
17
15
  import ProfileMenu from './ProfileMenu.svelte';
18
16
 
19
17
  const helpUrl = supplementalMenuData?.help?.url?.trim();
20
- const isHelpSelected = $derived(() => get(selectedSubNavItemId) === 'help');
18
+
19
+ // Check if we're on the help page by comparing URLs (help is not a nav/subnav item)
20
+ function getPathname(url: string, baseOrigin: string) {
21
+ try {
22
+ return new URL(url, baseOrigin).pathname;
23
+ } catch {
24
+ return null;
25
+ }
26
+ }
27
+
28
+ function checkIsHelpPage(): boolean {
29
+ if (!helpUrl || helpUrl === '#' || helpUrl.startsWith('#')) {
30
+ return false;
31
+ }
32
+ const location = (
33
+ globalThis as {
34
+ location?: { pathname?: string; origin?: string };
35
+ }
36
+ ).location;
37
+ if (location?.origin && location?.pathname) {
38
+ const helpPath = getPathname(helpUrl, location.origin);
39
+ return helpPath !== null && location.pathname === helpPath;
40
+ }
41
+ return false;
42
+ }
43
+
44
+ const isHelpSelected = $derived(checkIsHelpPage());
21
45
 
22
46
  onMount(() => {
23
47
  // Listen for section visibility changes to update header
24
48
  const handleSectionVisible = (event: Event) => {
25
- if (window.innerWidth <= 640) {
26
- return;
27
- }
28
49
  const customEvent = event as CustomEvent;
29
50
  if (customEvent.detail && customEvent.detail.title) {
30
51
  selectedSubNavItemTitle.set(customEvent.detail.title);
@@ -74,64 +95,28 @@
74
95
  }, 100);
75
96
  }
76
97
 
77
- // Detect help page and set selection state (aligned with DesktopSideNav logic)
78
- const checkHelpPage = () => {
79
- // Skip check for hash links - they stay on the same page
80
- if (!helpUrl || helpUrl === '#' || helpUrl.startsWith('#')) {
81
- return;
82
- }
83
-
84
- const location = (
85
- globalThis as {
86
- location?: { pathname?: string; origin?: string };
87
- }
88
- ).location;
89
- if (location?.origin && location?.pathname) {
90
- const helpPath = getPathname(helpUrl, location.origin);
91
- if (helpPath && location.pathname === helpPath) {
92
- selectedSubNavItemId.set('help');
93
- } else if (
94
- get(selectedSubNavItemId) === 'help' &&
95
- helpPath &&
96
- location.pathname !== helpPath
97
- ) {
98
- // Clear help selection if we navigated away from help page
99
- selectedSubNavItemId.set(null);
100
- }
101
- }
98
+ // Listen for navigation changes to update help button state
99
+ const handleNavigationChange = () => {
100
+ // Force reactivity update by accessing the derived value
101
+ void isHelpSelected;
102
102
  };
103
103
 
104
- checkHelpPage();
105
-
106
- // Also listen for popstate events (back/forward navigation)
107
- window.addEventListener('popstate', checkHelpPage);
104
+ window.addEventListener('popstate', handleNavigationChange);
108
105
 
109
106
  return () => {
110
107
  window.removeEventListener('sectionVisible', handleSectionVisible);
111
- window.removeEventListener('popstate', checkHelpPage);
108
+ window.removeEventListener('popstate', handleNavigationChange);
112
109
  };
113
110
  });
114
111
 
115
- function getPathname(url: string, baseOrigin: string) {
116
- try {
117
- return new URL(url, baseOrigin).pathname;
118
- } catch {
119
- return null;
120
- }
121
- }
122
-
123
112
  function toggleMobileNav() {
124
113
  navigationStore.toggleExpanded();
125
114
  }
126
115
 
127
116
  function handleHelpClick(event: MouseEvent) {
128
- selectedSubNavItemId.set('help');
129
-
130
- // If it's a hash link, prevent default to maintain state on same page
117
+ // If it's a hash link, prevent default to stay on same page
131
118
  if (helpUrl === '#' || helpUrl?.startsWith('#')) {
132
119
  event.preventDefault();
133
- // State is already set above, so it will persist
134
- return;
135
120
  }
136
121
  }
137
122
  </script>
@@ -163,15 +148,15 @@
163
148
  {#if helpUrl}
164
149
  <a
165
150
  class="help-button"
166
- class:selected={isHelpSelected()}
167
- aria-current={isHelpSelected()}
151
+ class:selected={isHelpSelected}
152
+ aria-current={isHelpSelected ? 'page' : undefined}
168
153
  href={helpUrl}
169
154
  title="Help"
170
155
  aria-label="Help"
171
156
  onclick={handleHelpClick}
172
157
  >
173
158
  <span class="icon-container">
174
- <HelpIcon isSelected={isHelpSelected()} />
159
+ <HelpIcon isSelected={isHelpSelected} />
175
160
  </span>
176
161
  </a>
177
162
  {/if}
@@ -260,6 +245,19 @@
260
245
  outline: none;
261
246
  }
262
247
 
248
+ .help-button:focus {
249
+ outline: none;
250
+ }
251
+
252
+ .help-button:focus .icon-container {
253
+ outline: var(--ai-size-2) solid var(--ai-color-blue-600);
254
+ outline-offset: var(--ai-size-2);
255
+ }
256
+
257
+ .help-button:focus:not(:focus-visible) .icon-container {
258
+ outline: none;
259
+ }
260
+
263
261
  .help-button {
264
262
  display: flex;
265
263
  align-items: center;