@gsa-tts/graymatter-ui 0.4.8 → 0.4.10
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/dist/graymatter-ui.js +2063 -1956
- package/dist/graymatter-ui.umd.cjs +27 -22
- package/package.json +3 -3
- package/src/components/DesktopSideNav.svelte +47 -19
- package/src/components/MobileTopNav.svelte +74 -1
- package/src/components/MobileTopNav.webcomponent.svelte +8 -2
- package/src/components/icons/HelpIcon.svelte +2 -2
- package/src/layouts/DocsLayout.astro +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gsa-tts/graymatter-ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
"typescript": "5.7.3",
|
|
62
62
|
"vite": "^6.3.5",
|
|
63
63
|
"vitest": "^3.0.7",
|
|
64
|
+
"@gsa-tts/graymatter-eslint": "0.0.2",
|
|
64
65
|
"@gsa-tts/graymatter-typescript-config": "0.0.2",
|
|
65
|
-
"@gsa-tts/graymatter-vitest-config": "0.0.1"
|
|
66
|
-
"@gsa-tts/graymatter-eslint": "0.0.2"
|
|
66
|
+
"@gsa-tts/graymatter-vitest-config": "0.0.1"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@fontsource-variable/archivo": "^5.2.6",
|
|
@@ -37,6 +37,9 @@
|
|
|
37
37
|
supplementalMenuData,
|
|
38
38
|
} = $props();
|
|
39
39
|
|
|
40
|
+
const helpUrl = supplementalMenuData?.help?.url?.trim();
|
|
41
|
+
const isHelpSelected = $derived(() => get(selectedSubNavItemId) === 'help');
|
|
42
|
+
|
|
40
43
|
let hydrated = false;
|
|
41
44
|
let navContainer: HTMLDivElement;
|
|
42
45
|
let hoveredItem = $state<string | null>(null);
|
|
@@ -175,8 +178,30 @@
|
|
|
175
178
|
}
|
|
176
179
|
};
|
|
177
180
|
}
|
|
181
|
+
|
|
182
|
+
const location = (
|
|
183
|
+
globalThis as { location?: { pathname?: string; origin?: string } }
|
|
184
|
+
).location;
|
|
185
|
+
if (helpUrl && location?.origin && location?.pathname) {
|
|
186
|
+
const helpPath = getPathname(helpUrl, location.origin);
|
|
187
|
+
if (helpPath && location.pathname === helpPath) {
|
|
188
|
+
selectedSubNavItemId.set('help');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
178
191
|
});
|
|
179
192
|
|
|
193
|
+
function getPathname(url: string, baseOrigin: string) {
|
|
194
|
+
try {
|
|
195
|
+
return new URL(url, baseOrigin).pathname;
|
|
196
|
+
} catch {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function handleHelpClick() {
|
|
202
|
+
selectedSubNavItemId.set('help');
|
|
203
|
+
}
|
|
204
|
+
|
|
180
205
|
function toggleNav() {
|
|
181
206
|
if ($isMenuButtonDisabled) return;
|
|
182
207
|
navigationStore.toggleExpanded();
|
|
@@ -428,21 +453,26 @@
|
|
|
428
453
|
|
|
429
454
|
{#if profileMenuData}
|
|
430
455
|
<div class="nav-footer" part="nav-footer">
|
|
431
|
-
{#if
|
|
456
|
+
{#if helpUrl}
|
|
432
457
|
<div
|
|
433
458
|
class="nav-footer-icon-container"
|
|
434
459
|
part="nav-footer-icon-container"
|
|
435
460
|
>
|
|
436
461
|
<a
|
|
437
462
|
class="help-link"
|
|
438
|
-
class:selected={
|
|
439
|
-
aria-current={
|
|
440
|
-
href={
|
|
463
|
+
class:selected={isHelpSelected()}
|
|
464
|
+
aria-current={isHelpSelected()}
|
|
465
|
+
href={helpUrl}
|
|
441
466
|
part="help-link"
|
|
442
467
|
title="Help"
|
|
443
468
|
aria-label="Help"
|
|
469
|
+
onclick={handleHelpClick}
|
|
444
470
|
>
|
|
445
|
-
<
|
|
471
|
+
<div class="icon-container" part="help-icon-container">
|
|
472
|
+
<div class="icon-wrapper">
|
|
473
|
+
<HelpIcon isSelected={isHelpSelected()} />
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
446
476
|
</a>
|
|
447
477
|
</div>
|
|
448
478
|
{/if}
|
|
@@ -622,7 +652,8 @@
|
|
|
622
652
|
}
|
|
623
653
|
|
|
624
654
|
.menu-button:focus .icon-container,
|
|
625
|
-
.nav-item:focus .icon-container
|
|
655
|
+
.nav-item:focus .icon-container,
|
|
656
|
+
.help-link:focus .icon-container {
|
|
626
657
|
outline: var(--ai-size-2) solid var(--ai-color-blue-600);
|
|
627
658
|
outline-offset: var(--ai-size-2);
|
|
628
659
|
border-radius: var(--ai-size-4);
|
|
@@ -630,7 +661,8 @@
|
|
|
630
661
|
|
|
631
662
|
/* Hide focus outline on click */
|
|
632
663
|
.menu-button:focus:not(:focus-visible) .icon-container,
|
|
633
|
-
.nav-item:focus:not(:focus-visible) .icon-container
|
|
664
|
+
.nav-item:focus:not(:focus-visible) .icon-container,
|
|
665
|
+
.help-link:focus:not(:focus-visible) .icon-container {
|
|
634
666
|
outline: none;
|
|
635
667
|
}
|
|
636
668
|
|
|
@@ -724,7 +756,9 @@
|
|
|
724
756
|
.nav-item.selected .icon-container,
|
|
725
757
|
.nav-item.selected.hovered .icon-container,
|
|
726
758
|
.menu-button:hover .icon-container,
|
|
727
|
-
.menu-button:active .icon-container
|
|
759
|
+
.menu-button:active .icon-container,
|
|
760
|
+
.help-link:hover .icon-container,
|
|
761
|
+
.help-link.selected .icon-container {
|
|
728
762
|
background-color: var(--ai-color-steel-300);
|
|
729
763
|
border-radius: var(--ai-size-4);
|
|
730
764
|
}
|
|
@@ -765,20 +799,14 @@
|
|
|
765
799
|
}
|
|
766
800
|
|
|
767
801
|
.help-link {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
802
|
+
display: flex;
|
|
803
|
+
align-items: center;
|
|
804
|
+
justify-content: center;
|
|
805
|
+
text-decoration: none;
|
|
806
|
+
color: inherit;
|
|
771
807
|
}
|
|
772
808
|
|
|
773
809
|
.help-link :global(svg) {
|
|
774
810
|
display: block;
|
|
775
811
|
}
|
|
776
|
-
|
|
777
|
-
.help-link:hover {
|
|
778
|
-
background: var(--ai-color-steel-300);
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
.help-link:is(.selected) {
|
|
782
|
-
background-color: var(--ai-color-steel-300);
|
|
783
|
-
}
|
|
784
812
|
</style>
|
|
@@ -3,15 +3,22 @@
|
|
|
3
3
|
isMenuButtonDisabled,
|
|
4
4
|
navigationStore,
|
|
5
5
|
selectedSubNavItemTitle,
|
|
6
|
+
selectedSubNavItemId,
|
|
6
7
|
} from '../stores/navigationStore.js';
|
|
7
8
|
import Logo from './Logo.svelte';
|
|
8
9
|
import MenuIcon from './icons/MenuIcon.svelte';
|
|
10
|
+
import HelpIcon from './icons/HelpIcon.svelte';
|
|
9
11
|
import { onMount } from 'svelte';
|
|
12
|
+
import { get } from 'svelte/store';
|
|
10
13
|
|
|
11
|
-
let { profileMenuData, logoLinkUrl, logoLinkLabel } =
|
|
14
|
+
let { profileMenuData, logoLinkUrl, logoLinkLabel, supplementalMenuData } =
|
|
15
|
+
$props();
|
|
12
16
|
|
|
13
17
|
import ProfileMenu from './ProfileMenu.svelte';
|
|
14
18
|
|
|
19
|
+
const helpUrl = supplementalMenuData?.help?.url?.trim();
|
|
20
|
+
const isHelpSelected = $derived(() => get(selectedSubNavItemId) === 'help');
|
|
21
|
+
|
|
15
22
|
onMount(() => {
|
|
16
23
|
// Listen for section visibility changes to update header
|
|
17
24
|
const handleSectionVisible = (event: Event) => {
|
|
@@ -72,9 +79,35 @@
|
|
|
72
79
|
};
|
|
73
80
|
});
|
|
74
81
|
|
|
82
|
+
onMount(() => {
|
|
83
|
+
const location = (
|
|
84
|
+
globalThis as {
|
|
85
|
+
location?: { pathname?: string; origin?: string };
|
|
86
|
+
}
|
|
87
|
+
).location;
|
|
88
|
+
if (helpUrl && location?.origin && location?.pathname) {
|
|
89
|
+
const helpPath = getPathname(helpUrl, location.origin);
|
|
90
|
+
if (helpPath && location.pathname === helpPath) {
|
|
91
|
+
selectedSubNavItemId.set('help');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
function getPathname(url: string, baseOrigin: string) {
|
|
97
|
+
try {
|
|
98
|
+
return new URL(url, baseOrigin).pathname;
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
75
104
|
function toggleMobileNav() {
|
|
76
105
|
navigationStore.toggleExpanded();
|
|
77
106
|
}
|
|
107
|
+
|
|
108
|
+
function handleHelpClick() {
|
|
109
|
+
selectedSubNavItemId.set('help');
|
|
110
|
+
}
|
|
78
111
|
</script>
|
|
79
112
|
|
|
80
113
|
<nav class="mobile-top-nav" part="mobile-top-nav">
|
|
@@ -101,6 +134,22 @@
|
|
|
101
134
|
<span class="brand-text">{$selectedSubNavItemTitle || ''}</span>
|
|
102
135
|
</div>
|
|
103
136
|
|
|
137
|
+
{#if helpUrl}
|
|
138
|
+
<a
|
|
139
|
+
class="help-button"
|
|
140
|
+
class:selected={isHelpSelected()}
|
|
141
|
+
aria-current={isHelpSelected()}
|
|
142
|
+
href={helpUrl}
|
|
143
|
+
title="Help"
|
|
144
|
+
aria-label="Help"
|
|
145
|
+
onclick={handleHelpClick}
|
|
146
|
+
>
|
|
147
|
+
<span class="icon-container">
|
|
148
|
+
<HelpIcon isSelected={isHelpSelected()} />
|
|
149
|
+
</span>
|
|
150
|
+
</a>
|
|
151
|
+
{/if}
|
|
152
|
+
|
|
104
153
|
{#if profileMenuData}
|
|
105
154
|
<ProfileMenu
|
|
106
155
|
userMeta={profileMenuData?.userMeta}
|
|
@@ -184,4 +233,28 @@
|
|
|
184
233
|
.menu-button:focus {
|
|
185
234
|
outline: none;
|
|
186
235
|
}
|
|
236
|
+
|
|
237
|
+
.help-button {
|
|
238
|
+
display: flex;
|
|
239
|
+
align-items: center;
|
|
240
|
+
justify-content: center;
|
|
241
|
+
margin-right: var(--ai-size-4);
|
|
242
|
+
text-decoration: none;
|
|
243
|
+
color: inherit;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.help-button .icon-container {
|
|
247
|
+
display: flex;
|
|
248
|
+
align-items: center;
|
|
249
|
+
justify-content: center;
|
|
250
|
+
width: var(--ai-size-40);
|
|
251
|
+
height: var(--ai-size-40);
|
|
252
|
+
border-radius: var(--ai-size-4);
|
|
253
|
+
transition: background-color var(--ai-transition-ease-fast);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.help-button:hover .icon-container,
|
|
257
|
+
.help-button.selected .icon-container {
|
|
258
|
+
background-color: var(--ai-color-steel-300);
|
|
259
|
+
}
|
|
187
260
|
</style>
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
import MobileTopNav from './MobileTopNav.svelte';
|
|
9
9
|
|
|
10
10
|
// Props for the web component
|
|
11
|
-
let { profileMenuData, logoLinkUrl, logoLinkLabel } =
|
|
11
|
+
let { profileMenuData, logoLinkUrl, logoLinkLabel, supplementalMenuData } =
|
|
12
|
+
$props();
|
|
12
13
|
</script>
|
|
13
14
|
|
|
14
|
-
<MobileTopNav
|
|
15
|
+
<MobileTopNav
|
|
16
|
+
{profileMenuData}
|
|
17
|
+
{logoLinkUrl}
|
|
18
|
+
{logoLinkLabel}
|
|
19
|
+
{supplementalMenuData}
|
|
20
|
+
/>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
export let
|
|
2
|
+
export let isSelected = false;
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<svg
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
>
|
|
12
12
|
<path
|
|
13
13
|
d="M9.87891 7.51884C11.0505 6.49372 12.95 6.49372 14.1215 7.51884C15.2931 8.54397 15.2931 10.206 14.1215 11.2312C13.9176 11.4096 13.6917 11.5569 13.4513 11.6733C12.7056 12.0341 12.0002 12.6716 12.0002 13.5V14.25M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12ZM12 17.25H12.0075V17.2575H12V17.25Z"
|
|
14
|
-
stroke={
|
|
14
|
+
stroke={isSelected ? '#000' : '#585C63'}
|
|
15
15
|
stroke-width="1.5"
|
|
16
16
|
stroke-linecap="round"
|
|
17
17
|
stroke-linejoin="round"
|
|
@@ -15,6 +15,7 @@ const {
|
|
|
15
15
|
showAppIcons = false,
|
|
16
16
|
disableCodeCopyButtons = false,
|
|
17
17
|
profileMenuData = null,
|
|
18
|
+
supplementalMenuData = undefined,
|
|
18
19
|
hideDiscover = true,
|
|
19
20
|
contentCustomization = undefined,
|
|
20
21
|
logoLinkUrl,
|
|
@@ -65,6 +66,7 @@ const subNavData = generateApiDocumentationNavData(apiDocsMetadata);
|
|
|
65
66
|
{description}
|
|
66
67
|
{openGraphImage}
|
|
67
68
|
{hideDiscover}
|
|
69
|
+
{supplementalMenuData}
|
|
68
70
|
>
|
|
69
71
|
<!-- Initialize navigation state and auto-expand submenu for section pages -->
|
|
70
72
|
<NavigationInitializer
|