@gsa-tts/graymatter-ui 0.2.8 → 0.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 (37) hide show
  1. package/README.md +81 -0
  2. package/assets/images/favicon-dark.ico +0 -0
  3. package/assets/images/favicon-dark.svg +7 -0
  4. package/assets/images/favicon-light.svg +7 -0
  5. package/assets/images/favicon.ico +0 -0
  6. package/assets/images/favicon.svg +5 -6
  7. package/dist/graymatter-ui.js +910 -898
  8. package/dist/graymatter-ui.umd.cjs +36 -32
  9. package/package.json +4 -4
  10. package/src/components/Button.svelte +27 -31
  11. package/src/components/Button.webcomponent.svelte +13 -11
  12. package/src/components/DesktopHeader.svelte +70 -53
  13. package/src/components/DesktopHeader.webcomponent.svelte +13 -9
  14. package/src/components/DesktopSideNav.svelte +200 -158
  15. package/src/components/DesktopSideNav.webcomponent.svelte +7 -5
  16. package/src/components/Head.astro +24 -2
  17. package/src/components/Logo.svelte +48 -41
  18. package/src/components/Logo.webcomponent.svelte +16 -16
  19. package/src/components/MobileBottomNav.svelte +102 -69
  20. package/src/components/MobileBottomNav.webcomponent.svelte +13 -4
  21. package/src/components/MobileSideMenu.svelte +70 -42
  22. package/src/components/MobileSideMenu.webcomponent.svelte +6 -4
  23. package/src/components/MobileTopNav.svelte +24 -19
  24. package/src/components/MobileTopNav.webcomponent.svelte +6 -6
  25. package/src/components/NavigationInitializer.svelte +10 -2
  26. package/src/components/ProfileMenu.svelte +116 -27
  27. package/src/components/UsaSkipNav.svelte +23 -0
  28. package/src/components/icons/ApiIcon.svelte +182 -33
  29. package/src/components/icons/ChatIcon.svelte +10 -10
  30. package/src/components/icons/CloseIcon.svelte +10 -10
  31. package/src/components/icons/ConsoleIcon.svelte +68 -13
  32. package/src/components/icons/DiscoverIcon.svelte +14 -14
  33. package/src/components/icons/HelpIcon.svelte +2 -1
  34. package/src/components/icons/MenuIcon.svelte +47 -7
  35. package/src/components/index.ts +1 -1
  36. package/src/layouts/BaseLayout.astro +1 -1
  37. package/src/components/UsaSkipNav.astro +0 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsa-tts/graymatter-ui",
3
- "version": "0.2.8",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -56,15 +56,15 @@
56
56
  "vitest": "^3.0.7",
57
57
  "vite": "^6.3.5",
58
58
  "@gsa-tts/graymatter-eslint": "0.0.1",
59
- "@gsa-tts/graymatter-typescript-config": "0.0.1",
60
- "@gsa-tts/graymatter-vitest-config": "0.0.1"
59
+ "@gsa-tts/graymatter-vitest-config": "0.0.1",
60
+ "@gsa-tts/graymatter-typescript-config": "0.0.1"
61
61
  },
62
62
  "dependencies": {
63
63
  "@fontsource-variable/archivo": "^5.2.6",
64
64
  "@uswds/uswds": "3.12.0",
65
65
  "astro": "^5.11.0",
66
66
  "slugify": "^1.6.6",
67
- "@gsa-tts/graymatter-style-tokens": "0.2.3"
67
+ "@gsa-tts/graymatter-style-tokens": "0.3.0"
68
68
  },
69
69
  "scripts": {
70
70
  "build": "gulp update && vite build",
@@ -32,8 +32,12 @@
32
32
  'usa-button',
33
33
  'ai-button',
34
34
  size === 'small' ? 'ai-button--small' : '',
35
- theme === 'inverted' && variant === 'primary' ? 'ai-button--inverted' : '',
36
- theme === 'inverted' && variant === 'secondary' ? 'ai-button--outline-inverted' : '',
35
+ theme === 'inverted' && variant === 'primary'
36
+ ? 'ai-button--inverted'
37
+ : '',
38
+ theme === 'inverted' && variant === 'secondary'
39
+ ? 'ai-button--outline-inverted'
40
+ : '',
37
41
  variant === 'primary' ? 'usa-button--primary' : '',
38
42
  variant === 'secondary' ? 'usa-button--outline ai-button--outline' : '',
39
43
  variant === 'unstyled' ? 'ai-button--unstyled' : '',
@@ -46,29 +50,18 @@
46
50
  </script>
47
51
 
48
52
  {#if href}
49
- <a
50
- class={mergedClasses()}
51
- {href}
52
- class:disabled
53
- {onclick}
54
- {...props}
55
- >
53
+ <a class={mergedClasses()} {href} class:disabled {onclick} {...props}>
56
54
  {@render children?.()}
57
55
  </a>
58
56
  {:else}
59
- <button
60
- class={mergedClasses()}
61
- {type}
62
- {disabled}
63
- {onclick}
64
- {...props}
65
- >
57
+ <button class={mergedClasses()} {type} {disabled} {onclick} {...props}>
66
58
  {@render children?.()}
67
59
  </button>
68
60
  {/if}
69
61
 
70
62
  <style>
71
- :root, :host {
63
+ :root,
64
+ :host {
72
65
  /* global button */
73
66
  --ai-button-radius: var(--ai-radius-round);
74
67
  --ai-button-padding-x: 2rem;
@@ -78,12 +71,8 @@
78
71
 
79
72
  /* primary button */
80
73
  --ai-button-background-primary-rest: var(--ai-color-black);
81
- --ai-button-background-primary-hover: var(
82
- --ai-color-neutral-900
83
- );
84
- --ai-button-background-primary-disabled: var(
85
- --ai-color-neutral-200
86
- );
74
+ --ai-button-background-primary-hover: var(--ai-color-neutral-900);
75
+ --ai-button-background-primary-disabled: var(--ai-color-neutral-200);
87
76
  --ai-button-text-primary-rest: var(--ai-color-white);
88
77
  --ai-button-text-primary-hover: var(--ai-button-text-primary-rest);
89
78
  --ai-button-text-primary-disabled: var(--ai-color-neutral-800);
@@ -148,19 +137,22 @@
148
137
 
149
138
  .ai-button--outline:is(:hover, :focus) {
150
139
  background-color: var(--ai-button-background-outline-hover);
151
- box-shadow: var(--ai-button-box-shadow) var(--ai-button-border-outline-hover);
140
+ box-shadow: var(--ai-button-box-shadow)
141
+ var(--ai-button-border-outline-hover);
152
142
  color: var(--ai-button-text-outline-hover);
153
143
  }
154
144
 
155
145
  .ai-button--outline-inverted {
156
146
  background-color: transparent;
157
- box-shadow: var(--ai-button-box-shadow) var(--ai-button-border-outline-inverted-rest);
147
+ box-shadow: var(--ai-button-box-shadow)
148
+ var(--ai-button-border-outline-inverted-rest);
158
149
  color: var(--ai-button-text-outline-inverted-rest);
159
150
  }
160
151
 
161
152
  .ai-button--outline-inverted:is(:hover, :focus) {
162
153
  background-color: var(--ai-button-background-outline-inverted-hover);
163
- box-shadow: var(--ai-button-box-shadow) var(--ai-button-border-outline-inverted-hover);
154
+ box-shadow: var(--ai-button-box-shadow)
155
+ var(--ai-button-border-outline-inverted-hover);
164
156
  color: var(--ai-button-text-outline-inverted-hover);
165
157
  }
166
158
 
@@ -203,29 +195,33 @@
203
195
  }
204
196
 
205
197
  /* disabled button styles */
206
- :is(.disabled, [disabled], [aria-disabled=true]) {
198
+ :is(.disabled, [disabled], [aria-disabled='true']) {
207
199
  background: var(--ai-button-background-primary-disabled);
208
200
  color: var(--ai-button-text-primary-disabled);
209
201
  cursor: not-allowed;
210
202
  }
211
203
 
212
- .ai-button--inverted:is(.disabled, [disabled], [aria-disabled=true]) {
204
+ .ai-button--inverted:is(.disabled, [disabled], [aria-disabled='true']) {
213
205
  background: var(--ai-button-background-inverted-disabled);
214
206
  color: var(--ai-button-text-inverted-disabled);
215
207
  }
216
208
 
217
- .ai-button--outline:is(.disabled, [disabled], [aria-disabled=true]) {
209
+ .ai-button--outline:is(.disabled, [disabled], [aria-disabled='true']) {
218
210
  background: transparent;
219
211
  box-shadow: var(--ai-button-box-shadow) var(--ai-color-neutral-700);
220
212
  color: var(--ai-color-neutral-700);
221
213
  }
222
214
 
223
- .ai-button--outline-inverted:is(.disabled, [disabled], [aria-disabled=true]) {
215
+ .ai-button--outline-inverted:is(
216
+ .disabled,
217
+ [disabled],
218
+ [aria-disabled='true']
219
+ ) {
224
220
  box-shadow: var(--ai-button-box-shadow) var(--ai-color-neutral-200);
225
221
  color: var(--ai-color-neutral-600);
226
222
  }
227
223
 
228
- .ai-button--unstyled:is(.disabled, [disabled], [aria-disabled=true]) {
224
+ .ai-button--unstyled:is(.disabled, [disabled], [aria-disabled='true']) {
229
225
  background: none;
230
226
  color: inherit;
231
227
  opacity: 0.75;
@@ -1,14 +1,16 @@
1
- <svelte:options customElement={{
2
- tag: 'graymatter-button',
3
- props: {
4
- variant: { reflect: true, type: 'String', attribute: 'variant' },
5
- theme: { reflect: true, type: 'String', attribute: 'theme' },
6
- href: { reflect: true, type: 'String', attribute: 'href' },
7
- disabled: { reflect: true, type: 'Boolean', attribute: 'disabled' },
8
- size: { reflect: true, type: 'String', attribute: 'size' },
9
- type: { reflect: true, type: 'String', attribute: 'type' }
10
- }
11
- }} />
1
+ <svelte:options
2
+ customElement={{
3
+ tag: 'graymatter-button',
4
+ props: {
5
+ variant: { reflect: true, type: 'String', attribute: 'variant' },
6
+ theme: { reflect: true, type: 'String', attribute: 'theme' },
7
+ href: { reflect: true, type: 'String', attribute: 'href' },
8
+ disabled: { reflect: true, type: 'Boolean', attribute: 'disabled' },
9
+ size: { reflect: true, type: 'String', attribute: 'size' },
10
+ type: { reflect: true, type: 'String', attribute: 'type' },
11
+ },
12
+ }}
13
+ />
12
14
 
13
15
  <script lang="ts">
14
16
  import Button from './Button.svelte';
@@ -1,64 +1,81 @@
1
1
  <script lang="ts">
2
- import { selectedItem, isExpanded, selectedSubNavItemTitle } from '../stores/navigationStore.js';
3
- import { onMount } from 'svelte';
4
- import { subNavReady } from '../stores/subNavReadyStore';
2
+ import {
3
+ selectedItem,
4
+ isExpanded,
5
+ selectedSubNavItemTitle,
6
+ } from '../stores/navigationStore.js';
7
+ import { onMount } from 'svelte';
8
+ import { subNavReady } from '../stores/subNavReadyStore';
5
9
 
6
- const { customHeaderText = '' } = $props();
10
+ const { customHeaderText = '' } = $props();
7
11
 
8
- let isLayoutTransitioning = false;
12
+ let isLayoutTransitioning = false;
9
13
 
10
- const showHeader = $derived(() =>
11
- $selectedItem && $selectedItem !== 'discover' && !$isExpanded && !isLayoutTransitioning && $subNavReady
12
- );
13
- const headerText = $derived(() =>
14
- customHeaderText || $selectedSubNavItemTitle
15
- );
14
+ const showHeader = $derived(
15
+ () =>
16
+ $selectedItem &&
17
+ $selectedItem !== 'discover' &&
18
+ !$isExpanded &&
19
+ !isLayoutTransitioning &&
20
+ $subNavReady
21
+ );
22
+ const headerText = $derived(
23
+ () => customHeaderText || $selectedSubNavItemTitle
24
+ );
16
25
 
17
- onMount(() => {
18
- const handleSectionVisible = (event: Event) => {
19
- if (typeof window !== 'undefined' && window.innerWidth <= 640) {
20
- return;
21
- }
22
- let topLevelTitle = null;
23
- if (typeof window !== 'undefined') {
24
- topLevelTitle = sessionStorage.getItem('subNav-topLevelTitle');
25
- if (topLevelTitle) {
26
- try {
27
- topLevelTitle = JSON.parse(topLevelTitle);
28
- } catch {/* ignore parse error */}
26
+ onMount(() => {
27
+ const handleSectionVisible = (event: Event) => {
28
+ if (typeof window !== 'undefined' && window.innerWidth <= 640) {
29
+ return;
29
30
  }
30
- }
31
- if (typeof topLevelTitle === 'string' && topLevelTitle.trim() !== '') {
32
- selectedSubNavItemTitle.set(topLevelTitle);
33
- sessionStorage.setItem('subNav-selectedTitle', JSON.stringify(topLevelTitle));
34
- } else {
35
- const customEvent = event as CustomEvent;
36
- if (customEvent.detail && customEvent.detail.title) {
37
- selectedSubNavItemTitle.set(customEvent.detail.title);
38
- sessionStorage.setItem('subNav-selectedTitle', JSON.stringify(customEvent.detail.title));
31
+ let topLevelTitle = null;
32
+ if (typeof window !== 'undefined') {
33
+ topLevelTitle = sessionStorage.getItem('subNav-topLevelTitle');
34
+ if (topLevelTitle) {
35
+ try {
36
+ topLevelTitle = JSON.parse(topLevelTitle);
37
+ } catch {
38
+ /* ignore parse error */
39
+ }
40
+ }
41
+ }
42
+ if (typeof topLevelTitle === 'string' && topLevelTitle.trim() !== '') {
43
+ selectedSubNavItemTitle.set(topLevelTitle);
44
+ sessionStorage.setItem(
45
+ 'subNav-selectedTitle',
46
+ JSON.stringify(topLevelTitle)
47
+ );
48
+ } else {
49
+ const customEvent = event as CustomEvent;
50
+ if (customEvent.detail && customEvent.detail.title) {
51
+ selectedSubNavItemTitle.set(customEvent.detail.title);
52
+ sessionStorage.setItem(
53
+ 'subNav-selectedTitle',
54
+ JSON.stringify(customEvent.detail.title)
55
+ );
56
+ }
39
57
  }
40
- }
41
- };
58
+ };
42
59
 
43
- const handleLayoutTransition = (event: Event) => {
44
- const customEvent = event as CustomEvent;
45
- const { isMobile } = customEvent.detail;
46
- if (!isMobile) {
47
- isLayoutTransitioning = true;
48
- setTimeout(() => {
49
- isLayoutTransitioning = false;
50
- }, 300);
51
- }
52
- };
60
+ const handleLayoutTransition = (event: Event) => {
61
+ const customEvent = event as CustomEvent;
62
+ const { isMobile } = customEvent.detail;
63
+ if (!isMobile) {
64
+ isLayoutTransitioning = true;
65
+ setTimeout(() => {
66
+ isLayoutTransitioning = false;
67
+ }, 300);
68
+ }
69
+ };
53
70
 
54
- window.addEventListener('sectionVisible', handleSectionVisible);
55
- window.addEventListener('layoutTransition', handleLayoutTransition);
71
+ window.addEventListener('sectionVisible', handleSectionVisible);
72
+ window.addEventListener('layoutTransition', handleLayoutTransition);
56
73
 
57
- return () => {
58
- window.removeEventListener('sectionVisible', handleSectionVisible);
59
- window.removeEventListener('layoutTransition', handleLayoutTransition);
60
- };
61
- });
74
+ return () => {
75
+ window.removeEventListener('sectionVisible', handleSectionVisible);
76
+ window.removeEventListener('layoutTransition', handleLayoutTransition);
77
+ };
78
+ });
62
79
  </script>
63
80
 
64
81
  <div class="global-header" class:visible={showHeader()} part="global-header">
@@ -70,11 +87,11 @@ onMount(() => {
70
87
  <style>
71
88
  .global-header {
72
89
  opacity: 0;
73
- transition: opacity 0.2s;
90
+ transition: opacity var(--ai-duration-fast);
74
91
  }
75
92
  .global-header.visible {
76
93
  opacity: 1;
77
- transition: opacity 0.2s;
94
+ transition: opacity var(--ai-duration-fast);
78
95
  }
79
96
  .header-content {
80
97
  display: flex;
@@ -1,9 +1,15 @@
1
- <svelte:options customElement={{
2
- tag: 'graymatter-desktop-header',
3
- props: {
4
- customHeaderText: { reflect: true, type: 'String', attribute: 'custom-header-text' }
5
- }
6
- }} />
1
+ <svelte:options
2
+ customElement={{
3
+ tag: 'graymatter-desktop-header',
4
+ props: {
5
+ customHeaderText: {
6
+ reflect: true,
7
+ type: 'String',
8
+ attribute: 'custom-header-text',
9
+ },
10
+ },
11
+ }}
12
+ />
7
13
 
8
14
  <script lang="ts">
9
15
  import DesktopHeader from './DesktopHeader.svelte';
@@ -12,6 +18,4 @@
12
18
  let { customHeaderText = '' } = $props();
13
19
  </script>
14
20
 
15
- <DesktopHeader
16
- {customHeaderText}
17
- />
21
+ <DesktopHeader {customHeaderText} />