@gsa-tts/graymatter-ui 1.2.1 → 2.0.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 (35) hide show
  1. package/README.md +59 -91
  2. package/assets/uswds/components/usa-banner.js.mjs +805 -0
  3. package/assets/uswds/components/usa-banner.js.umd.js +127 -0
  4. package/package.json +18 -34
  5. package/src/components/DesktopSideNav.svelte +17 -15
  6. package/src/components/MobileTopNav.svelte +15 -13
  7. package/src/components/ProfileMenu.svelte +22 -15
  8. package/src/components/Tooltip.svelte +288 -0
  9. package/src/components/UsaBanner.svelte +2 -2
  10. package/src/components/index.ts +1 -0
  11. package/src/utils/index.ts +0 -4
  12. package/static/uswds/js/uswds.js +37 -3
  13. package/static/uswds/js/uswds.min.js +1 -1
  14. package/static/uswds/js/uswds.min.js.map +1 -1
  15. package/static/uswds/styles/styles.css +3 -3
  16. package/static/uswds/styles/styles.css.map +1 -1
  17. package/dist/graymatter-ui.js +0 -6025
  18. package/dist/graymatter-ui.umd.cjs +0 -78
  19. package/src/astro-config/index.ts +0 -139
  20. package/src/components/Button.webcomponent.svelte +0 -58
  21. package/src/components/DesktopHeader.webcomponent.svelte +0 -21
  22. package/src/components/DesktopSideNav.webcomponent.svelte +0 -42
  23. package/src/components/Logo.webcomponent.svelte +0 -29
  24. package/src/components/MobileBottomNav.webcomponent.svelte +0 -32
  25. package/src/components/MobileSideMenu.webcomponent.svelte +0 -13
  26. package/src/components/MobileTopNav.webcomponent.svelte +0 -20
  27. package/src/index.ts +0 -19
  28. package/src/layouts/BaseLayout.astro +0 -37
  29. package/src/layouts/DocsLayout.astro +0 -342
  30. package/src/layouts/GlobalAppLayout.astro +0 -536
  31. package/src/layouts/GoogleTagManager.astro +0 -17
  32. package/src/layouts/Head.astro +0 -101
  33. package/src/layouts/fonts.ts +0 -17
  34. package/src/pages/.gitkeep +0 -0
  35. package/src/utils/remarkPlugins.ts +0 -55
@@ -1,21 +0,0 @@
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
- />
13
-
14
- <script lang="ts">
15
- import DesktopHeader from './DesktopHeader.svelte';
16
-
17
- // Props for the web component
18
- let { customHeaderText = '' } = $props();
19
- </script>
20
-
21
- <DesktopHeader {customHeaderText} />
@@ -1,42 +0,0 @@
1
- <svelte:options
2
- customElement={{
3
- tag: 'graymatter-desktop-side-nav',
4
- }}
5
- />
6
-
7
- <script lang="ts">
8
- import DesktopSideNav from './DesktopSideNav.svelte';
9
-
10
- // Props for the web component
11
- let {
12
- ssrSelectedItem,
13
- controlledSelectedItem,
14
- onNavToggle,
15
- onNavItemClick,
16
- showAppIcons = true,
17
- hideDiscover = true,
18
- profileMenuData,
19
- apiUrl,
20
- chatUrl,
21
- consoleUrl,
22
- discoverUrl,
23
- supplementalMenuData,
24
- children,
25
- } = $props();
26
- </script>
27
-
28
- <DesktopSideNav
29
- {ssrSelectedItem}
30
- {controlledSelectedItem}
31
- {onNavToggle}
32
- {onNavItemClick}
33
- {showAppIcons}
34
- {hideDiscover}
35
- {profileMenuData}
36
- {apiUrl}
37
- {chatUrl}
38
- {consoleUrl}
39
- {discoverUrl}
40
- {supplementalMenuData}
41
- {children}
42
- />
@@ -1,29 +0,0 @@
1
- <svelte:options
2
- customElement={{
3
- tag: 'graymatter-logo',
4
- props: {
5
- isInverted: { reflect: true, type: 'Boolean', attribute: 'is-inverted' },
6
- width: { reflect: true, type: 'Number', attribute: 'width' },
7
- height: { reflect: true, type: 'Number', attribute: 'height' },
8
- showServiceMark: {
9
- reflect: true,
10
- type: 'Boolean',
11
- attribute: 'show-service-mark',
12
- },
13
- },
14
- }}
15
- />
16
-
17
- <script lang="ts">
18
- import Logo from './Logo.svelte';
19
-
20
- let {
21
- isInverted = false,
22
- width = undefined,
23
- height = undefined,
24
- showServiceMark = false,
25
- ...props
26
- } = $props();
27
- </script>
28
-
29
- <Logo {isInverted} {width} {height} {showServiceMark} {...props} />
@@ -1,32 +0,0 @@
1
- <svelte:options
2
- customElement={{
3
- tag: 'graymatter-mobile-bottom-nav',
4
- }}
5
- />
6
-
7
- <script lang="ts">
8
- import MobileBottomNav from './MobileBottomNav.svelte';
9
-
10
- // Props for the web component
11
- let {
12
- onNavItemClick,
13
- showAppIcons = true,
14
- hideDiscover = true,
15
- apiUrl,
16
- chatUrl,
17
- consoleUrl,
18
- discoverUrl,
19
- controlledSelectedItem,
20
- } = $props();
21
- </script>
22
-
23
- <MobileBottomNav
24
- {onNavItemClick}
25
- {showAppIcons}
26
- {hideDiscover}
27
- {apiUrl}
28
- {chatUrl}
29
- {consoleUrl}
30
- {discoverUrl}
31
- {controlledSelectedItem}
32
- />
@@ -1,13 +0,0 @@
1
- <svelte:options
2
- customElement={{
3
- tag: 'graymatter-mobile-side-menu',
4
- }}
5
- />
6
-
7
- <script lang="ts">
8
- import MobileSideMenu from './MobileSideMenu.svelte';
9
-
10
- let { logoLinkUrl, logoLinkLabel, children } = $props();
11
- </script>
12
-
13
- <MobileSideMenu {logoLinkUrl} {logoLinkLabel} {children} />
@@ -1,20 +0,0 @@
1
- <svelte:options
2
- customElement={{
3
- tag: 'graymatter-mobile-top-nav',
4
- }}
5
- />
6
-
7
- <script lang="ts">
8
- import MobileTopNav from './MobileTopNav.svelte';
9
-
10
- // Props for the web component
11
- let { profileMenuData, logoLinkUrl, logoLinkLabel, supplementalMenuData } =
12
- $props();
13
- </script>
14
-
15
- <MobileTopNav
16
- {profileMenuData}
17
- {logoLinkUrl}
18
- {logoLinkLabel}
19
- {supplementalMenuData}
20
- />
package/src/index.ts DELETED
@@ -1,19 +0,0 @@
1
- import Button from './components/Button.webcomponent.svelte';
2
- import DesktopHeader from './components/DesktopHeader.webcomponent.svelte';
3
- import DesktopSideNav from './components/DesktopSideNav.webcomponent.svelte';
4
- import Logo from './components/Logo.webcomponent.svelte';
5
- import MobileBottomNav from './components/MobileBottomNav.webcomponent.svelte';
6
- import MobileSideMenu from './components/MobileSideMenu.webcomponent.svelte';
7
- import MobileTopNav from './components/MobileTopNav.webcomponent.svelte';
8
-
9
- export * from './utils/navigationControl';
10
-
11
- export {
12
- Button,
13
- DesktopHeader,
14
- DesktopSideNav,
15
- Logo,
16
- MobileBottomNav,
17
- MobileSideMenu,
18
- MobileTopNav,
19
- };
@@ -1,37 +0,0 @@
1
- ---
2
- import '../styles/base/global.css';
3
- import Head from './Head.astro';
4
- import UsaSkipNav from '../components/UsaSkipNav.svelte';
5
- const { title, description, openGraphImage, gtmID } = Astro.props;
6
- ---
7
-
8
- <!doctype html>
9
- <html lang="en">
10
- <head>
11
- <meta charset="UTF-8" />
12
- <Head {title} {gtmID} {openGraphImage} {description} />
13
- </head>
14
- <body>
15
- <slot name="skip-nav">
16
- <UsaSkipNav mainContentId="#main-content" />
17
- </slot>
18
- <slot />
19
- </body>
20
- </html>
21
-
22
- <script>
23
- // Enhanced mobile focus handling - centralized for all layouts
24
- if (typeof window !== 'undefined') {
25
- const handleKeyDown = (e: KeyboardEvent) => {
26
- if (e.key === 'Tab') {
27
- document.body.classList.add('keyboard-user');
28
- document.body.classList.remove('touch-user');
29
- }
30
- };
31
-
32
- document.addEventListener('keydown', handleKeyDown);
33
-
34
- // Initial state - assume touch user until Tab is pressed
35
- document.body.classList.add('touch-user');
36
- }
37
- </script>
@@ -1,342 +0,0 @@
1
- ---
2
- import GlobalAppLayout from './GlobalAppLayout.astro';
3
- import ApiDocSubNavMenu from '../components/ApiDocSubNavMenu.svelte';
4
- import NavigationInitializer from '../components/NavigationInitializer.svelte';
5
- import { getCollection } from 'astro:content';
6
- import { render } from 'astro:content';
7
- import { generateApiDocumentationNavData } from '../utils/generateApiNavData.js';
8
-
9
- const gtmID = import.meta.env.PUBLIC_GTM_ID;
10
- const {
11
- navigationItem = 'api',
12
- title,
13
- description,
14
- openGraphImage,
15
- showAppIcons = false,
16
- disableCodeCopyButtons = false,
17
- profileMenuData = null,
18
- supplementalMenuData = undefined,
19
- hideDiscover = true,
20
- contentCustomization = undefined,
21
- logoLinkUrl,
22
- logoLinkLabel,
23
- } = Astro.props;
24
-
25
- // Handle ALL logic internally
26
- // Get collection
27
- const rawPosts = await getCollection('apiDocumentation');
28
-
29
- // Sort by sortOrder
30
- const sortedPosts = [...rawPosts].sort(
31
- (a, b) => a.data.sortOrder - b.data.sortOrder
32
- );
33
-
34
- // Render posts
35
- const postItems = await Promise.all(
36
- sortedPosts.map(async post => {
37
- const { Content } = await render(post);
38
- return {
39
- ...post,
40
- ContentComponent: Content,
41
- };
42
- })
43
- );
44
-
45
- // Generate navigation data
46
- const apiDocsMetadata = sortedPosts.map(doc => ({
47
- id: doc.id,
48
- slug: doc.id,
49
- title: doc.data.title,
50
- description: doc.data.description,
51
- sortOrder: doc.data.sortOrder,
52
- content: doc.body || '',
53
- }));
54
-
55
- const subNavData = generateApiDocumentationNavData(apiDocsMetadata);
56
- ---
57
-
58
- <GlobalAppLayout
59
- ssrSelectedItem={navigationItem}
60
- gtmID={gtmID}
61
- {showAppIcons}
62
- {profileMenuData}
63
- {logoLinkUrl}
64
- {logoLinkLabel}
65
- title={title}
66
- {description}
67
- {openGraphImage}
68
- {hideDiscover}
69
- {supplementalMenuData}
70
- >
71
- <!-- Initialize navigation state and auto-expand submenu for section pages -->
72
- <NavigationInitializer
73
- item={navigationItem}
74
- autoExpand={true}
75
- client:only="svelte"
76
- />
77
-
78
- <!-- Documentation Sub Navigation -->
79
- {
80
- subNavData && (
81
- <ApiDocSubNavMenu
82
- data={subNavData}
83
- selectedId={null}
84
- slot="sub-nav"
85
- client:load
86
- />
87
- )
88
- }
89
-
90
- <!-- Main content area -->
91
- <div class="docs-content">
92
- <article class="article-body">
93
- <h1 class="page-title">API Documentation</h1>
94
-
95
- <!-- Render postItems -->
96
- {
97
- postItems &&
98
- postItems.map((post: any) => (
99
- <div>
100
- <h2 class="title" id={post.id}>
101
- {post.data.title}
102
- </h2>
103
- <post.ContentComponent />
104
- </div>
105
- ))
106
- }
107
- </article>
108
- </div>
109
- </GlobalAppLayout>
110
-
111
- <!-- Add copy button to all code blocks -->
112
- {
113
- !disableCodeCopyButtons && (
114
- <script>
115
- import {setupCopyButtons} from '../utils/copyButtonScript.js';
116
- setupCopyButtons();
117
- </script>
118
- )
119
- }
120
- <!-- Client-side content replacement -->
121
- <script is:inline define:vars={{ contentCustomization }}>
122
- if (!contentCustomization) {
123
- // no customization provided
124
- } else {
125
- const customization = contentCustomization;
126
- function escapeHtml(input) {
127
- return String(input)
128
- .replace(/&/g, '&amp;')
129
- .replace(/</g, '&lt;')
130
- .replace(/>/g, '&gt;')
131
- .replace(/"/g, '&quot;')
132
- .replace(/'/g, '&#39;');
133
- }
134
- function linkify(input) {
135
- // Handle array input - convert to paragraphs
136
- if (Array.isArray(input)) {
137
- return input
138
- .map(paragraph => {
139
- const processed = linkifySingle(String(paragraph));
140
- return `<p>${processed}</p>`;
141
- })
142
- .join('');
143
- }
144
-
145
- // Handle string input
146
- return linkifySingle(String(input));
147
- }
148
-
149
- function linkifySingle(input) {
150
- // Preserve markdown links [label](url) using placeholders
151
- const placeholders = [];
152
- const withPlaceholders = input.replace(
153
- /\[([^\]]+)\]\(((https?:\/\/|www\.)[^\s)]+)\)/gi,
154
- (m, label, href) => {
155
- const safeLabel = escapeHtml(label);
156
- const normalizedHref = href.startsWith('http')
157
- ? href
158
- : `https://${href}`;
159
- const safeHref = escapeHtml(normalizedHref);
160
- const html = `<a href="${safeHref}" target="_blank" rel="noopener noreferrer">${safeLabel}</a>`;
161
- const token = `__LINK_PLACEHOLDER_${placeholders.length}__`;
162
- placeholders.push(html);
163
- return token;
164
- }
165
- );
166
-
167
- // Escape remaining content
168
- const escaped = escapeHtml(withPlaceholders);
169
-
170
- // Linkify emails
171
- const withEmails = escaped.replace(
172
- /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi,
173
- email => {
174
- return `<a href="mailto:${email}">${email}</a>`;
175
- }
176
- );
177
- // Linkify bare URLs (http/https and www.)
178
- const urlRegex = /\b((https?:\/\/)[^\s)]+|www\.[^\s)]+)\b/gi;
179
- const withUrls = withEmails.replace(urlRegex, raw => {
180
- const href = raw.startsWith('http') ? raw : `https://${raw}`;
181
- return `<a href="${href}" target="_blank" rel="noopener noreferrer">${raw}</a>`;
182
- });
183
-
184
- // Restore placeholders
185
- return withUrls.replace(
186
- /__LINK_PLACEHOLDER_(\d+)__/g,
187
- (m, idx) => placeholders[Number(idx)]
188
- );
189
- }
190
-
191
- function replaceContent() {
192
- // For endpoints
193
- if (customization.endpointsMessage) {
194
- const heading = document.getElementById('endpoints');
195
- if (heading) {
196
- const section = heading.closest('div');
197
- if (section) {
198
- const paragraphs = section.querySelectorAll('p');
199
- paragraphs.forEach(p => {
200
- if (
201
- p.textContent?.includes(
202
- 'API endpoints will be available when you login'
203
- )
204
- ) {
205
- p.innerHTML = linkify(customization.endpointsMessage);
206
- }
207
- });
208
- }
209
- }
210
- }
211
-
212
- // For getting-started
213
- if (customization.authMessage) {
214
- const heading = document.getElementById('getting-started');
215
- if (heading) {
216
- const section = heading.closest('div');
217
- if (section) {
218
- const paragraphs = section.querySelectorAll('p');
219
- paragraphs.forEach(p => {
220
- const text = p.textContent || '';
221
- if (text.includes('All API requests require an API key')) {
222
- const authPattern =
223
- /All API requests require an API key\. Upon authentication,.*?available\./s;
224
- if (authPattern.test(text)) {
225
- p.innerHTML = linkify(customization.authMessage);
226
- }
227
- }
228
- });
229
- }
230
- }
231
- }
232
- }
233
-
234
- // Run synchronously before paint
235
- if (document.readyState === 'loading') {
236
- document.addEventListener('DOMContentLoaded', replaceContent, {
237
- once: true,
238
- });
239
- } else {
240
- replaceContent();
241
- }
242
- setTimeout(replaceContent, 0);
243
- }
244
- </script>
245
-
246
- <style>
247
- body {
248
- color: var(--ai-color-steel-900);
249
- line-height: var(--ai-font-lineheight-prose);
250
- }
251
-
252
- :is(h1, h2, h3, h4, h5, h6) {
253
- color: var(--ai-color-black);
254
- }
255
-
256
- .docs-content {
257
- padding: 0;
258
- }
259
-
260
- .article-body {
261
- max-width: 84ch;
262
- }
263
-
264
- :global(.ai-copy-btn) {
265
- width: var(--ai-size-32);
266
- height: var(--ai-size-32);
267
- position: absolute;
268
- top: var(--ai-size-8);
269
- right: var(--ai-size-8);
270
- background: none;
271
- border-radius: var(--ai-size-4);
272
- border: none;
273
- padding: 0;
274
- cursor: pointer;
275
- box-shadow: 0 var(--ai-size-2) var(--ai-size-8) rgba(0, 0, 0, 0.08);
276
- display: flex;
277
- align-items: center;
278
- justify-content: center;
279
- transition:
280
- background var(--ai-duration-fast),
281
- border var(--ai-duration-fast);
282
- z-index: var(--ai-layer-2);
283
- overflow: hidden;
284
- }
285
- :global(.ai-copy-btn:hover),
286
- :global(.ai-copy-btn:focus) {
287
- background: var(--ai-color-steel-800);
288
- }
289
- :global(.ai-copy-btn svg) {
290
- display: block;
291
- position: relative;
292
- }
293
- :global(.ai-code-block-wrapper) {
294
- position: relative;
295
- display: block;
296
- }
297
- :global(pre) {
298
- font-family: var(--ai-font-family-monospace);
299
- font-size: var(--ai-size-13);
300
- font-weight: var(--ai-font-weight-normal);
301
- }
302
-
303
- /* Table styling - only for documentation pages */
304
- :global(.docs-content table) {
305
- width: 100%;
306
- border-collapse: collapse;
307
- margin: var(--ai-size-24) 0;
308
- }
309
-
310
- :global(.docs-content table th),
311
- :global(.docs-content table td) {
312
- padding: var(--ai-size-12) var(--ai-size-16);
313
- text-align: left;
314
- border-bottom: 1px solid var(--ai-color-neutral-200);
315
- }
316
-
317
- :global(.docs-content table th) {
318
- background-color: var(--ai-color-neutral-50);
319
- font-weight: var(--ai-font-weight-semibold);
320
- color: var(--ai-color-black);
321
- }
322
-
323
- :global(.docs-content table tbody tr:hover) {
324
- background-color: var(--ai-color-neutral-25);
325
- }
326
-
327
- :global(.docs-content table tbody tr:last-child td) {
328
- border-bottom: none;
329
- }
330
-
331
- @media (--ai-size-breakpoint-tablet) {
332
- .docs-content {
333
- padding: 2rem 0;
334
- }
335
- }
336
-
337
- @media (--ai-size-breakpoint-desktop) {
338
- .docs-content {
339
- padding: 2rem;
340
- }
341
- }
342
- </style>