From a7f5a628b196b6e1d336dfd15272a715aa6befa4 Mon Sep 17 00:00:00 2001 From: Dustin Nielsen Date: Tue, 25 Aug 2026 14:16:09 -0600 Subject: [PATCH 1/7] feat!: make version 2 the permanent version BREAKING CHANGE: Remove version selection and standardize web components and React and Angular wrappers --- apps/prs/angular/project.json | 12 +---- apps/prs/angular/src/app/app.component.html | 9 +--- apps/prs/angular/src/app/app.component.ts | 15 ------ .../src/app/token-version/token-version.ts | 50 ------------------- apps/prs/angular/src/main.ts | 13 ----- apps/prs/angular/src/styles.css | 3 +- apps/prs/react/src/app/app.tsx | 24 --------- apps/prs/react/src/app/tokenVersion.ts | 47 ----------------- .../react/src/routes/features/feat3636.tsx | 13 ----- apps/prs/react/src/styles.css | 3 +- apps/prs/web/src/app/App.svelte | 1 - docs/astro.config.mjs | 8 --- docs/package-lock.json | 11 ++-- docs/package.json | 2 +- docs/src/layouts/BaseLayout.astro | 4 +- docs/src/layouts/PreviewLayout.astro | 2 +- docs/src/lib/tokens.ts | 2 +- package-lock.json | 10 +--- package.json | 3 +- 19 files changed, 18 insertions(+), 214 deletions(-) delete mode 100644 apps/prs/angular/src/app/token-version/token-version.ts delete mode 100644 apps/prs/react/src/app/tokenVersion.ts diff --git a/apps/prs/angular/project.json b/apps/prs/angular/project.json index 0616e2eac4..a2d65563a1 100644 --- a/apps/prs/angular/project.json +++ b/apps/prs/angular/project.json @@ -25,17 +25,9 @@ "tsConfig": "apps/prs/angular/tsconfig.app.json", "assets": [ "apps/prs/angular/src/favicon.ico", - "apps/prs/angular/src/assets", - { - "glob": "**/*", - "input": "node_modules/@abgov/design-tokens-v2/dist", - "output": "/v2-tokens" - } - ], - "styles": [ - "apps/prs/angular/src/styles.css", - "node_modules/@abgov/design-tokens-v2/dist/tokens.css" + "apps/prs/angular/src/assets" ], + "styles": ["apps/prs/angular/src/styles.css"], "scripts": [] }, "configurations": { diff --git a/apps/prs/angular/src/app/app.component.html b/apps/prs/angular/src/app/app.component.html index 258080a3b2..e2a115caed 100644 --- a/apps/prs/angular/src/app/app.component.html +++ b/apps/prs/angular/src/app/app.component.html @@ -8,16 +8,11 @@ userSecondaryText="edna.mode@gov.ab.ca" (onNavigate)="handleNavigate($event)" [primaryContent]="primaryTemplate" - [secondaryContent]="tokenToggleTemplate" + [secondaryContent]="secondaryTemplate" [accountContent]="accountTemplate" /> - - + i + 1); // Sample notifications for the work-side-menu notification panel (#4110 test). @@ -168,11 +158,6 @@ export class AppComponent { } handleNavigate(path: string): void { - if (path === TOKEN_TOGGLE_URL) { - this.tokenMode = this.tokenMode === "v1" ? "v2" : "v1"; - applyTokenVersion(this.tokenMode); - return; - } if (path === "#toggle-theme") { this.theme.toggle(); return; diff --git a/apps/prs/angular/src/app/token-version/token-version.ts b/apps/prs/angular/src/app/token-version/token-version.ts deleted file mode 100644 index 2a5e66a6db..0000000000 --- a/apps/prs/angular/src/app/token-version/token-version.ts +++ /dev/null @@ -1,50 +0,0 @@ -export type TokenVersion = "v1" | "v2"; - -const STORAGE_KEY = "goa-token-version"; -const LINK_ID = "goa-tokens-v2"; -const URL_PARAM = "tokens"; - -// Served at this path via the asset copy configured in project.json. -// Relative URL so it resolves against document.baseURI, which respects -// the deploy base on PR preview builds (an absolute /v2-tokens/... would -// 404 against the host root instead of the app's deploy path). -const V2_TOKENS_URL = "v2-tokens/tokens.css"; - -export function resolveTokenVersion(): TokenVersion { - const params = new URLSearchParams(window.location.search); - const fromUrl = params.get(URL_PARAM); - if (fromUrl === "v1" || fromUrl === "v2") return fromUrl; - - const fromSession = sessionStorage.getItem(STORAGE_KEY); - if (fromSession === "v1" || fromSession === "v2") return fromSession; - - return "v2"; -} - -export function applyTokenVersion(mode: TokenVersion): void { - // Link-ordering invariant: V2 stylesheet must be the LAST stylesheet in - // so cascade resolves V2 over V1 unambiguously. Remove any existing - // node first, then append so the fresh node lands last. - document.getElementById(LINK_ID)?.remove(); - - if (mode === "v2") { - const link = document.createElement("link"); - link.id = LINK_ID; - link.rel = "stylesheet"; - link.href = V2_TOKENS_URL; - document.head.appendChild(link); - } - - sessionStorage.setItem(STORAGE_KEY, mode); - - // Only sync URL param if already present; don't add clutter on first toggle. - const url = new URL(window.location.href); - if (url.searchParams.has(URL_PARAM)) { - url.searchParams.set(URL_PARAM, mode); - window.history.replaceState({}, "", url); - } -} - -// Eager side effect: resolve and apply at module load so V2 is in -// before Angular bootstraps. Import this module once from main.ts. -applyTokenVersion(resolveTokenVersion()); diff --git a/apps/prs/angular/src/main.ts b/apps/prs/angular/src/main.ts index 91e46900ae..c8de31031e 100644 --- a/apps/prs/angular/src/main.ts +++ b/apps/prs/angular/src/main.ts @@ -1,19 +1,6 @@ import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; import { AppModule } from "./app/app.module"; -// This import has a side effect: token-version.ts calls applyTokenVersion at -// module load, which puts the V2 stylesheet link in before Angular -// bootstraps. Without this, the page would flash V1 on first paint. -import { - applyTokenVersion, - resolveTokenVersion, -} from "./app/token-version/token-version"; platformBrowserDynamic() .bootstrapModule(AppModule) - .then(() => { - // Re-apply after Angular's bundled styles.css is in , so the V2 - // link lands last in the cascade. Without this, the bundled V1 @import - // overrides V2 and the toggle appears to do nothing. - applyTokenVersion(resolveTokenVersion()); - }) .catch((err) => console.error(err)); diff --git a/apps/prs/angular/src/styles.css b/apps/prs/angular/src/styles.css index 8078d0e064..6dc88586b8 100644 --- a/apps/prs/angular/src/styles.css +++ b/apps/prs/angular/src/styles.css @@ -1,7 +1,6 @@ /* You can add global styles to this file, and also import other style files */ @import "../../../../dist/libs/web-components/index.css"; -@import "@abgov/design-tokens-v2/dist/tokens.css"; -@import "@abgov/design-tokens-v2/dist/dark-theme.css"; +@import "@abgov/design-tokens/dist/dark-theme.css"; :root { --goa-space-fill: 32ch; diff --git a/apps/prs/react/src/app/app.tsx b/apps/prs/react/src/app/app.tsx index 9467aac0d1..34ec735db5 100644 --- a/apps/prs/react/src/app/app.tsx +++ b/apps/prs/react/src/app/app.tsx @@ -22,15 +22,6 @@ import { featureRouteDefinitions, } from "./route-manifest"; import "@abgov/style"; -// Runtime V1/V2 token switching. Importing this module applies the currently -// selected token set (default V2) to before the app renders. The -// playground's work-side-menu exposes a secondary item that flips between -// V1 and V2 at runtime without editing source or restarting the dev server. -import { - applyTokenVersion, - resolveTokenVersion, - type TokenVersion, -} from "./tokenVersion"; const PUSH_DRAWER_ROUTE_PATH = "/features/3347-push"; const pushDrawerTestParagraphs = Array.from({ length: 30 }, (_, i) => i + 1); @@ -93,9 +84,6 @@ export interface AppOutletContext { openPushDrawer: () => void; } -// Sentinel URL handled by onNavigate below to toggle tokens instead of routing. -const TOKEN_TOGGLE_URL = "#tokens"; - // Demo: a slotted page-header that shrinks its heading once content scrolls // under the pinned header. It reads the layout's scroll state via the context // hook (no prop drilling), using the same middle / at-bottom states that drive @@ -139,7 +127,6 @@ export function App() { const isDark = mode === "dark"; const location = useLocation(); const baseUrl = import.meta.env.BASE_URL; - const [tokenMode, setTokenMode] = useState(() => resolveTokenVersion()); const isPushDrawerRoute = location.pathname === PUSH_DRAWER_ROUTE_PATH || @@ -165,12 +152,6 @@ export function App() { ); const handleSideMenuNavigate = (path: string) => { - if (path === TOKEN_TOGGLE_URL) { - const next: TokenVersion = tokenMode === "v1" ? "v2" : "v1"; - setTokenMode(next); - applyTokenVersion(next); - return; - } if (path === "#toggle-theme") { toggle(); return; @@ -214,11 +195,6 @@ export function App() { onNavigate={handleSideMenuNavigate} secondaryContent={ <> - so cascade resolves V2 over V1 unambiguously. Remove any existing - // node first, then append so the fresh node lands last. - document.getElementById(LINK_ID)?.remove(); - - if (mode === "v2") { - const link = document.createElement("link"); - link.id = LINK_ID; - link.rel = "stylesheet"; - link.href = v2TokensUrl; - document.head.appendChild(link); - } - - sessionStorage.setItem(STORAGE_KEY, mode); - - // Only sync URL param if it's already in the URL; don't add clutter on first toggle. - const url = new URL(window.location.href); - if (url.searchParams.has(URL_PARAM)) { - url.searchParams.set(URL_PARAM, mode); - window.history.replaceState({}, "", url); - } -} - -// Eager side effect: resolve and apply at module load so V2 is in -// before React's first paint. Importing this module once from app.tsx runs this. -applyTokenVersion(resolveTokenVersion()); diff --git a/apps/prs/react/src/routes/features/feat3636.tsx b/apps/prs/react/src/routes/features/feat3636.tsx index 21d46d62e1..3c41cf2504 100644 --- a/apps/prs/react/src/routes/features/feat3636.tsx +++ b/apps/prs/react/src/routes/features/feat3636.tsx @@ -1,19 +1,6 @@ import { GoabAccordion, GoabBadge, GoabButton, GoabText } from "@abgov/react-components"; -import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; -import { useEffect } from "react"; export function Feat3636Route() { - // Inject the v2 design tokens - useEffect(() => { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = v2TokensUrl; - document.head.appendChild(link); - return () => { - document.head.removeChild(link); - }; - }, []); - return (
import "@abgov/style"; - import "@abgov/design-tokens-v2/dist/tokens.css"; // Production tokens. Comment out to test with legacy V1 token values. import { Router, Route } from "svelte-routing"; import Issue2333 from "../routes/2333.svelte"; import Issue3279 from "../routes/3279.svelte"; diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index aa1846f165..8102332492 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -99,14 +99,6 @@ export default defineConfig({ find: "@abgov/style", replacement: path.resolve(workspaceRoot, "dist/libs/web-components/index.css"), }, - // Design tokens V2 for docs styling (via npm alias) - { - find: "@design-tokens", - replacement: path.resolve( - workspaceRoot, - "node_modules/@abgov/design-tokens-v2/dist", - ), - }, // @astrojs/react registers its SSR renderer via the bare specifier // "@astrojs/react/server.js", which Vite then externalizes for the // prerender build instead of bundling it. Externalizing leaves the diff --git a/docs/package-lock.json b/docs/package-lock.json index da48fe4981..bc8a926923 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -8,7 +8,7 @@ "name": "docs", "version": "0.0.1", "dependencies": { - "@abgov/design-tokens-v2": "npm:@abgov/design-tokens@^2.9.0", + "@abgov/design-tokens": "^2.12.7", "@abgov/react-components": "*", "@abgov/ui-components-common": "*", "@abgov/web-components": "*", @@ -18,11 +18,10 @@ "tsx": "^4.22.4" } }, - "node_modules/@abgov/design-tokens-v2": { - "name": "@abgov/design-tokens", - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/@abgov/design-tokens/-/design-tokens-2.9.0.tgz", - "integrity": "sha512-Z3+wHUhLHCKJDXUBR0KpGBod5k5Jk+ehRNUC9J2OJZ0jcK3jF2/Ggeqhhze7+haiS0FdC1cikqT9vCnKZItU8Q==" + "node_modules/@abgov/design-tokens": { + "version": "2.12.7", + "resolved": "https://registry.npmjs.org/@abgov/design-tokens/-/design-tokens-2.12.7.tgz", + "integrity": "sha512-pnYI/G3598FYOVHISalV1CkJaa1e1GB1wmiV6wtjXRWwyozH/NsEbMJoP9tebYWE25pi61prCcUMkmx8tWcC7g==" }, "node_modules/@abgov/react-components": { "version": "6.9.3", diff --git a/docs/package.json b/docs/package.json index b4e815b28f..41869fa720 100644 --- a/docs/package.json +++ b/docs/package.json @@ -15,7 +15,7 @@ "verify-bundle": "npx tsx src/scripts/content-generators/verify-bundle.ts" }, "dependencies": { - "@abgov/design-tokens-v2": "npm:@abgov/design-tokens@^2.9.0", + "@abgov/design-tokens": "^2.12.7", "@abgov/react-components": "*", "@abgov/ui-components-common": "*", "@abgov/web-components": "*", diff --git a/docs/src/layouts/BaseLayout.astro b/docs/src/layouts/BaseLayout.astro index e189f7d9bc..f3aa98b5d3 100644 --- a/docs/src/layouts/BaseLayout.astro +++ b/docs/src/layouts/BaseLayout.astro @@ -1,8 +1,8 @@ --- // Import v2 design tokens and web component styles import '@abgov/web-components/index.css'; -import '@design-tokens/tokens.css'; -import '@design-tokens/dark-theme.css'; +import "@abgov/design-tokens/dist/tokens.css"; +import "@abgov/design-tokens/dist/dark-theme.css"; // Import search styles eagerly so inline search inputs don't flash unstyled import '../components/search/search.css'; diff --git a/docs/src/layouts/PreviewLayout.astro b/docs/src/layouts/PreviewLayout.astro index 9d1c9b1abd..7d81789b25 100644 --- a/docs/src/layouts/PreviewLayout.astro +++ b/docs/src/layouts/PreviewLayout.astro @@ -13,7 +13,7 @@ * this layout. */ import "@abgov/web-components/index.css"; -import "@design-tokens/tokens.css"; +import "@abgov/design-tokens/dist/tokens.css"; import { withBase } from "@/lib/base-url"; interface Props { diff --git a/docs/src/lib/tokens.ts b/docs/src/lib/tokens.ts index ce244064dd..b1ffc8a5b5 100644 --- a/docs/src/lib/tokens.ts +++ b/docs/src/lib/tokens.ts @@ -7,7 +7,7 @@ // Import the global design tokens JSON // Note: This will be resolved at build time by Astro/Vite -import globalTokens from "@abgov/design-tokens-v2/data/goa-global-design-tokens.json"; +import globalTokens from "@abgov/design-tokens/data/goa-global-design-tokens.json"; /** * Flattened token structure for grid display diff --git a/package-lock.json b/package-lock.json index c3ffca18d4..8e6ee45d61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,8 +37,7 @@ "zone.js": "0.16.1" }, "devDependencies": { - "@abgov/design-tokens": "1.10.0", - "@abgov/design-tokens-v2": "npm:@abgov/design-tokens@2.12.7", + "@abgov/design-tokens": "2.12.7", "@abgov/nx-release": "12.0.0", "@angular-devkit/build-angular": "21.2.16", "@angular-devkit/core": "21.2.6", @@ -127,13 +126,6 @@ } }, "node_modules/@abgov/design-tokens": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@abgov/design-tokens/-/design-tokens-1.10.0.tgz", - "integrity": "sha512-RkecyvF1hloYTcGXUdofK0eSlj8pWM2brycbwDdt2n/tL9XtL93rD/OH6YlnN5RVTGfu2HPjE/QWJX39YfXiMg==", - "dev": true - }, - "node_modules/@abgov/design-tokens-v2": { - "name": "@abgov/design-tokens", "version": "2.12.7", "resolved": "https://registry.npmjs.org/@abgov/design-tokens/-/design-tokens-2.12.7.tgz", "integrity": "sha512-pnYI/G3598FYOVHISalV1CkJaa1e1GB1wmiV6wtjXRWwyozH/NsEbMJoP9tebYWE25pi61prCcUMkmx8tWcC7g==", diff --git a/package.json b/package.json index 20642b675b..8e38ca62b2 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,7 @@ "validate": "npm run build && npm run lint && vitest --run" }, "devDependencies": { - "@abgov/design-tokens": "1.10.0", - "@abgov/design-tokens-v2": "npm:@abgov/design-tokens@2.12.7", + "@abgov/design-tokens": "2.12.7", "@abgov/nx-release": "12.0.0", "@angular-devkit/build-angular": "21.2.16", "@angular-devkit/core": "21.2.6", From e85ec31f50af19194c80501763599bfb083b0d04 Mon Sep 17 00:00:00 2001 From: Dustin Nielsen Date: Tue, 25 Aug 2026 17:56:54 -0600 Subject: [PATCH 2/7] feat!: Updated dark mode usage Updated dark mode theming to be included by default in web-components. Also updated a couple browser tests that were testing using old v1 tokens. And updated documentation around developer setup and dark mode setup. --- README.md | 16 +- apps/prs/angular/src/styles.css | 1 - apps/prs/react/src/styles.css | 1 - docs/src/content/get-started/developers.mdx | 7 +- .../developers/dark-mode-theme.mdx | 48 +- .../content/get-started/developers/setup.mdx | 26 +- docs/src/layouts/BaseLayout.astro | 1 - libs/angular-components/README.md | 5 +- libs/react-components/README.md | 6 +- .../specs/dropdown.browser.spec.tsx | 16 +- .../specs/scroll-panel.browser.spec.tsx | 16 +- libs/web-components/src/index.svelte | 1 + scripts/indexdocs.ts | 554 ------------------ 13 files changed, 55 insertions(+), 643 deletions(-) delete mode 100644 scripts/indexdocs.ts diff --git a/README.md b/README.md index cc331c3606..752f92210e 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ This repository contains the Government of Alberta Design System component libra | `@abgov/react-components` | You are building a React application. | [npm](https://www.npmjs.com/package/@abgov/react-components) | | `@abgov/angular-components` | You are building an Angular application. | [npm](https://www.npmjs.com/package/@abgov/angular-components) | | `@abgov/ui-components-common` | You need shared types, event detail interfaces, or common utilities used by the component packages. | [npm](https://www.npmjs.com/package/@abgov/ui-components-common) | -| `@abgov/design-tokens` | You need the design tokens used by the components. | [npm](https://www.npmjs.com/package/@abgov/design-tokens) | `@abgov/styles` is deprecated. Import `@abgov/web-components/index.css` instead. @@ -28,7 +27,7 @@ This repository contains the Government of Alberta Design System component libra Install the packages: ```bash -npm i @abgov/web-components @abgov/design-tokens +npm i @abgov/web-components ``` Register the custom elements in your app entry point, for example `src/main.js`: @@ -37,11 +36,10 @@ Register the custom elements in your app entry point, for example `src/main.js`: import "@abgov/web-components"; ``` -Import the component styles and tokens in your main stylesheet: +Import the component styles in your main stylesheet. This stylesheet includes the design tokens and dark theme overrides: ```css @import "@abgov/web-components/index.css"; -@import "@abgov/design-tokens/dist/tokens.css"; ``` Add Ionicons to your `index.html` ``: @@ -64,7 +62,7 @@ Supported React versions: `17`, `18`, `19`. Install the packages: ```bash -npm i @abgov/react-components @abgov/web-components @abgov/ui-components-common @abgov/design-tokens +npm i @abgov/react-components @abgov/web-components @abgov/ui-components-common ``` Register the underlying web components in your app entry point, for example `src/main.tsx`: @@ -73,11 +71,10 @@ Register the underlying web components in your app entry point, for example `src import "@abgov/web-components"; ``` -Import the styles in your main stylesheet: +Import the component styles in your main stylesheet. This stylesheet includes the design tokens and dark theme overrides: ```css @import "@abgov/web-components/index.css"; -@import "@abgov/design-tokens/dist/tokens.css"; ``` Add Ionicons to your `index.html` ``: @@ -104,7 +101,7 @@ Supported Angular versions in the current docs: `18`, `19`, `20`, `21`. Install the packages: ```bash -npm i @abgov/web-components @abgov/angular-components @abgov/ui-components-common @abgov/design-tokens +npm i @abgov/web-components @abgov/angular-components @abgov/ui-components-common ``` Add Ionicons to `src/index.html`: @@ -135,11 +132,10 @@ export class AppModule {} If your Angular app uses standalone bootstrapping instead of `AppModule`, use the same package installs, web component import, styles, and Ionicons setup, then adapt the module example to your bootstrap configuration. -Import the styles in `src/styles.css`: +Import the component styles in `src/styles.css`. This stylesheet includes the design tokens and dark theme overrides: ```css @import "@abgov/web-components/index.css"; -@import "@abgov/design-tokens/dist/tokens.css"; ``` ## Local development diff --git a/apps/prs/angular/src/styles.css b/apps/prs/angular/src/styles.css index 6dc88586b8..963ef40b19 100644 --- a/apps/prs/angular/src/styles.css +++ b/apps/prs/angular/src/styles.css @@ -1,6 +1,5 @@ /* You can add global styles to this file, and also import other style files */ @import "../../../../dist/libs/web-components/index.css"; -@import "@abgov/design-tokens/dist/dark-theme.css"; :root { --goa-space-fill: 32ch; diff --git a/apps/prs/react/src/styles.css b/apps/prs/react/src/styles.css index 97411b4ba9..491af4bd3c 100644 --- a/apps/prs/react/src/styles.css +++ b/apps/prs/react/src/styles.css @@ -1,3 +1,2 @@ /* You can add global styles to this file, and also import other style files */ @import "../../../../dist/libs/web-components/index.css"; -@import "@abgov/design-tokens/dist/dark-theme.css"; diff --git a/docs/src/content/get-started/developers.mdx b/docs/src/content/get-started/developers.mdx index f6330b62e2..3baf059692 100644 --- a/docs/src/content/get-started/developers.mdx +++ b/docs/src/content/get-started/developers.mdx @@ -34,11 +34,8 @@ import DropInCallout from "../../components/DropInCallout.astro";

Tokens

- Access the tokens as an - NPM package. -

-

- Import the SCSS or CSS file into your project. Replace hard-coded values with Design System token variables. + The Web Components stylesheet includes the Design System tokens. Import the stylesheet once, + then replace hard-coded values in your CSS with Design System token variables.

Designers reference the same tokens in their tools. This keeps design and development aligned during handoff. diff --git a/docs/src/content/get-started/developers/dark-mode-theme.mdx b/docs/src/content/get-started/developers/dark-mode-theme.mdx index a8caf821d1..0e128763d2 100644 --- a/docs/src/content/get-started/developers/dark-mode-theme.mdx +++ b/docs/src/content/get-started/developers/dark-mode-theme.mdx @@ -22,9 +22,9 @@ import { withBase } from "@/lib/base-url"; - Theme switching requires @abgov/design-tokens version 2.8.0 or - higher with the dark theme stylesheet imported. See Setup - for installation steps. + Dark theme styles are included in @abgov/web-components/index.css. If you + completed the developer setup, + you do not need another package or stylesheet. @@ -61,8 +61,7 @@ import { withBase } from "@/lib/base-url";

{`// main.tsx
 import { GoabThemeProvider } from "@abgov/react-components";
 import { BrowserRouter } from "react-router-dom";
-import "@abgov/design-tokens/dist/tokens.css";
-import "@abgov/design-tokens/dist/dark-theme.css";
+import "@abgov/web-components/index.css";
 
 ReactDOM.createRoot(document.getElementById("root")!).render(
   
@@ -123,13 +122,12 @@ interface GoabThemeProviderProps {
   The Angular package exposes a root-provided service backed by a Signal.
 
 
-

1. Import the dark theme stylesheet

+

1. Add the component stylesheet

- Add the import to your global stylesheet (typically src/styles.css): + The component stylesheet includes the dark theme styles. If you completed the developer + setup, you already have this import in your global stylesheet: -
@import "@abgov/web-components/index.css";
-@import "@abgov/design-tokens/dist/tokens.css";
-@import "@abgov/design-tokens/dist/dark-theme.css";
+
@import "@abgov/web-components/index.css";

2. Inject GoabThemeService

@@ -223,37 +221,13 @@ class GoabThemeService { - The simplest setup imports only tokens.css and uses - {`var(--goa-*)`} everywhere — every token automatically participates - in theme switching, and there is one syntax to remember. + The Web Components stylesheet provides CSS custom properties. Use + {`var(--goa-*)`} for values that should respond to theme switching. -
{`@import "@abgov/web-components/index.css";
-@import "@abgov/design-tokens/dist/tokens.css";
-@import "@abgov/design-tokens/dist/dark-theme.css";`}
+
@import "@abgov/web-components/index.css";
{`.my-card {
   background: var(--goa-color-surface-card);
   font-family: var(--goa-font-family-sans);
   padding: var(--goa-space-m);
   transition-duration: var(--goa-motion-duration-medium-2);
 }`}
- -

When you need Sass variables

- - Some workflows need Sass arithmetic, mixins, or functions over token values - (for example {`$goa-space-m * 2`}). In that case, import - tokens.scss alongside the CSS files and use {`$goa-*`} - for compile-time values only — never for colors, surfaces, or anything that - should flip with theme. - -
{`@import "@abgov/web-components/index.css";
-@import "@abgov/design-tokens/dist/tokens.css";
-@import "@abgov/design-tokens/dist/dark-theme.css";
-@import "@abgov/design-tokens/dist/tokens.scss";`}
-
{`.my-card {
-  // Theme-responsive — must use var()
-  background: var(--goa-color-surface-card);
-
-  // Compile-time only — Sass arithmetic OK
-  padding: $goa-space-m * 2;
-  border-radius: $goa-border-radius-m;
-}`}
diff --git a/docs/src/content/get-started/developers/setup.mdx b/docs/src/content/get-started/developers/setup.mdx index 4ddbd116de..43787380e8 100644 --- a/docs/src/content/get-started/developers/setup.mdx +++ b/docs/src/content/get-started/developers/setup.mdx @@ -24,8 +24,7 @@ import DropInCallout from "../../../components/DropInCallout.astro";

1. Add dependencies

{`npm i @abgov/web-components
 npm i @abgov/angular-components
-npm i @abgov/ui-components-common
-npm i @abgov/design-tokens`}
+npm i @abgov/ui-components-common`}

2. Register the web components

@@ -65,10 +64,10 @@ export class App {}`}

4. Add styles

- Import the component styles and design tokens in src/styles.css: + Import the component styles in src/styles.css. This stylesheet includes the + design tokens and dark theme overrides: -
{`@import "@abgov/web-components/index.css";
-@import "@abgov/design-tokens/dist/tokens.css";`}
+
@import "@abgov/web-components/index.css";

5. Add icons

@@ -91,8 +90,7 @@ export class App {}`}

1. Add dependencies

npm i @abgov/react-components
 npm i @abgov/web-components
-npm i @abgov/ui-components-common
-npm i @abgov/design-tokens
+npm i @abgov/ui-components-common

2. Link ionicons in app/index.html

@@ -105,8 +103,10 @@ npm i @abgov/design-tokens
import "@abgov/web-components";

4. Import the styles in src/index.css

-
@import "@abgov/web-components/index.css";
-@import "@abgov/design-tokens/dist/tokens.css";
+ + This stylesheet includes the design tokens and dark theme overrides: + +
@import "@abgov/web-components/index.css";
@@ -116,8 +116,7 @@ npm i @abgov/design-tokens

1. Add dependencies

-
npm i @abgov/web-components
-npm i @abgov/design-tokens
+
npm i @abgov/web-components

2. Link ionicons in index.html

@@ -132,10 +131,9 @@ npm i @abgov/design-tokens

4. Add the styles link in your main CSS file

Add the following in src/assets/main.css or wherever your main CSS file is - located: + located. This stylesheet includes the design tokens and dark theme overrides: -
@import "@abgov/web-components/index.css";
-@import "@abgov/design-tokens/dist/tokens.css";
+
@import "@abgov/web-components/index.css";
diff --git a/docs/src/layouts/BaseLayout.astro b/docs/src/layouts/BaseLayout.astro index f3aa98b5d3..b83f246aab 100644 --- a/docs/src/layouts/BaseLayout.astro +++ b/docs/src/layouts/BaseLayout.astro @@ -2,7 +2,6 @@ // Import v2 design tokens and web component styles import '@abgov/web-components/index.css'; import "@abgov/design-tokens/dist/tokens.css"; -import "@abgov/design-tokens/dist/dark-theme.css"; // Import search styles eagerly so inline search inputs don't flash unstyled import '../components/search/search.css'; diff --git a/libs/angular-components/README.md b/libs/angular-components/README.md index 7dd4531c3b..b4551f5c1b 100644 --- a/libs/angular-components/README.md +++ b/libs/angular-components/README.md @@ -9,7 +9,7 @@ Supported Angular versions: 18, 19, 20, and 21. ## Install ```bash -npm i @abgov/angular-components @abgov/web-components @abgov/ui-components-common @abgov/design-tokens +npm i @abgov/angular-components @abgov/web-components @abgov/ui-components-common ``` ## Register the web components @@ -52,11 +52,10 @@ still use the legacy `goaValue`, `goaValueList`, or `goaChecked` form directives ## Add styles -Import the component styles and design tokens in `src/styles.css`: +Import the component styles in `src/styles.css`. This stylesheet includes the design tokens and dark theme overrides: ```css @import "@abgov/web-components/index.css"; -@import "@abgov/design-tokens/dist/tokens.css"; ``` ## Add icons diff --git a/libs/react-components/README.md b/libs/react-components/README.md index e2f16c6219..58eea80f8d 100644 --- a/libs/react-components/README.md +++ b/libs/react-components/README.md @@ -9,7 +9,7 @@ Supported React versions: 17, 18, and 19. ## Install ```bash -npm i @abgov/react-components @abgov/web-components @abgov/ui-components-common @abgov/design-tokens +npm i @abgov/react-components @abgov/web-components @abgov/ui-components-common ``` ## Register the web components @@ -23,12 +23,10 @@ import "@abgov/web-components"; ## Add styles -Import the component styles and design tokens in your main stylesheet, such as -`src/index.css`: +Import the component styles in your main stylesheet, such as `src/index.css`. This stylesheet includes the design tokens and dark theme overrides: ```css @import "@abgov/web-components/index.css"; -@import "@abgov/design-tokens/dist/tokens.css"; ``` ## Add icons diff --git a/libs/react-components/specs/dropdown.browser.spec.tsx b/libs/react-components/specs/dropdown.browser.spec.tsx index 7f106d33a3..b593e297d3 100644 --- a/libs/react-components/specs/dropdown.browser.spec.tsx +++ b/libs/react-components/specs/dropdown.browser.spec.tsx @@ -589,17 +589,16 @@ describe("Dropdown", () => { const result = render(); const dropdown = result.getByTestId("dropdown"); + const popoverContent = result.getByTestId("popover-content"); await dropdown.click(); await vi.waitFor(async () => { - const dropdownOption = result.getByText("Green"); - expect(dropdownOption).toBeDefined(); const dropdownRect = dropdown.element().getBoundingClientRect(); - const dropdownOptionRect = dropdownOption.element().getBoundingClientRect(); - expect(Math.abs(dropdownOptionRect.width - dropdownRect.width)).toBeLessThanOrEqual(1); + const popoverRect = popoverContent.element().getBoundingClientRect(); + expect(Math.abs(popoverRect.width - dropdownRect.width)).toBeLessThanOrEqual(2); }); }); - it("should maintain dropdown option width equal to input width in narrow viewport", async () => { + it("should keep the option list aligned with the input in a narrow viewport", async () => { // Set viewport to narrow width - bug 2441 await page.viewport(250, 800); const Component = () => { @@ -614,12 +613,13 @@ describe("Dropdown", () => { const result = render(); const dropdown = result.getByTestId("dropdown"); + const popoverContent = result.getByTestId("popover-content"); await dropdown.click(); await vi.waitFor(async () => { - const dropdownOption = result.getByText("Green"); const dropdownRect = dropdown.element().getBoundingClientRect(); - const dropdownOptionRect = dropdownOption.element().getBoundingClientRect(); - expect(Math.abs(dropdownOptionRect.width - dropdownRect.width)).toBeLessThanOrEqual(1); + const popoverRect = popoverContent.element().getBoundingClientRect(); + expect(Math.abs(popoverRect.left - dropdownRect.left)).toBeLessThanOrEqual(1); + expect(Math.abs(popoverRect.width - dropdownRect.width)).toBeLessThanOrEqual(2); }); }); diff --git a/libs/react-components/specs/scroll-panel.browser.spec.tsx b/libs/react-components/specs/scroll-panel.browser.spec.tsx index f85e6f24e1..27f7267708 100644 --- a/libs/react-components/specs/scroll-panel.browser.spec.tsx +++ b/libs/react-components/specs/scroll-panel.browser.spec.tsx @@ -50,13 +50,19 @@ describe("ScrollPanel", () => { const footerBottomBefore = footer.element().getBoundingClientRect().bottom; const paraTopBefore = firstPara.element().getBoundingClientRect().top; - // Scroll the body down. - scrollEl.scrollTop = 200; + // Scroll the body down by as much as the rendered content allows. Token changes + // can affect content height, so the assertion should not rely on a fixed distance. + const scrollDistance = Math.min( + 200, + scrollEl.scrollHeight - scrollEl.clientHeight, + ); + expect(scrollDistance).toBeGreaterThan(0); + scrollEl.scrollTop = scrollDistance; await vi.waitFor(() => { - expect(scrollEl.scrollTop).toBeCloseTo(200, 0); + expect(scrollEl.scrollTop).toBeCloseTo(scrollDistance, 0); // Body content moved up by the scrolled amount. expect(firstPara.element().getBoundingClientRect().top).toBeCloseTo( - paraTopBefore - 200, + paraTopBefore - scrollDistance, 0, ); }); @@ -196,4 +202,4 @@ describe("ScrollPanel", () => { // The panel did not collapse to content height; it is bounded by the parent. expect(host.getBoundingClientRect().height).toBeLessThanOrEqual(400); }); -}); \ No newline at end of file +}); diff --git a/libs/web-components/src/index.svelte b/libs/web-components/src/index.svelte index 37e7180a30..5f82a00701 100644 --- a/libs/web-components/src/index.svelte +++ b/libs/web-components/src/index.svelte @@ -6,4 +6,5 @@ import "./assets/css/variables.css"; import "./assets/css/components.css"; import "@abgov/design-tokens/dist/tokens.css"; + import "@abgov/design-tokens/dist/dark-theme.css"; diff --git a/scripts/indexdocs.ts b/scripts/indexdocs.ts deleted file mode 100644 index fc920a6ee2..0000000000 --- a/scripts/indexdocs.ts +++ /dev/null @@ -1,554 +0,0 @@ -import * as fs from "fs"; -import * as path from "path"; -import { glob } from "glob"; - -interface DocIndex { - id: string; - title: string; - name?: string; // For components - useSearch expects this - description: string; - content: string; - component: string; - filePath: string; - urlPath: string; - tags: string[]; - /** Entry type - must match what useSearch.ts expects */ - type: "component" | "example" | "token" | "page"; - /** URL slug for building links */ - slug: string; - /** Status for sorting (stable, beta, etc.) */ - status?: string; - /** Category for components */ - category?: string; - /** Categories array for examples */ - categories?: string[]; -} - -interface FrontMatter { - title?: string; - tags?: string[]; - description?: string; - [key: string]: any; -} - -/** - * Token category metadata for search entries - */ -interface TokenCategoryMeta { - title: string; - description: string; - tags: string[]; -} - -/** - * Metadata for each token category - */ -const TOKEN_CATEGORY_META: Record = { - color: { - title: "Color Tokens", - description: "Color design tokens for text, backgrounds, borders, interactive elements, and status indicators", - tags: ["token", "color", "design token", "palette", "theme"], - }, - opacity: { - title: "Opacity Tokens", - description: "Opacity values for overlays, disabled states, and transparency effects", - tags: ["token", "opacity", "transparency", "design token"], - }, - borderRadius: { - title: "Border Radius Tokens", - description: "Border radius values for rounded corners on cards, buttons, and containers", - tags: ["token", "border", "radius", "corners", "design token"], - }, - borderWidth: { - title: "Border Width Tokens", - description: "Border width values for outlines, dividers, and component borders", - tags: ["token", "border", "width", "stroke", "design token"], - }, - space: { - title: "Spacing Tokens", - description: "Spacing values for margins, padding, and gaps between elements", - tags: ["token", "space", "spacing", "margin", "padding", "gap", "design token"], - }, - iconSize: { - title: "Icon Size Tokens", - description: "Standard icon sizes for consistent iconography across the design system", - tags: ["token", "icon", "size", "design token"], - }, - shadow: { - title: "Shadow Tokens", - description: "Box shadow values for elevation and depth effects on cards and modals", - tags: ["token", "shadow", "elevation", "depth", "design token"], - }, - typography: { - title: "Typography Tokens", - description: "Typography presets combining font family, size, weight, and line height", - tags: ["token", "typography", "font", "text", "heading", "body", "design token"], - }, - fontFamily: { - title: "Font Family Tokens", - description: "Font family values for the design system typefaces", - tags: ["token", "font", "family", "typeface", "design token"], - }, - fontSize: { - title: "Font Size Tokens", - description: "Font size values for text hierarchy and responsive typography", - tags: ["token", "font", "size", "typography", "design token"], - }, - fontWeight: { - title: "Font Weight Tokens", - description: "Font weight values for text emphasis and hierarchy", - tags: ["token", "font", "weight", "bold", "design token"], - }, - lineHeight: { - title: "Line Height Tokens", - description: "Line height values for readable text and proper vertical rhythm", - tags: ["token", "line", "height", "leading", "typography", "design token"], - }, - letterSpacing: { - title: "Letter Spacing Tokens", - description: "Letter spacing values for text tracking adjustments", - tags: ["token", "letter", "spacing", "tracking", "typography", "design token"], - }, -}; - -/** - * Categories to exclude from search (internal implementation details) - */ -const EXCLUDED_TOKEN_CATEGORIES = [ - "input", - "border-none", - "fontVariationSettings", - "translate", - "motionCurve", - "motionDuration", - "transition", -]; - -/** - * Static page entries for docs pages (Get Started, Foundations, etc.) - * These are manually defined since Astro pages don't have easily parseable metadata. - */ -interface PageMeta { - id: string; - title: string; - description: string; - urlPath: string; - tags: string[]; - category: string; -} - -const PAGE_ENTRIES: PageMeta[] = [ - // Get Started pages - { - id: "get-started", - title: "Get started", - description: "Introduction to the GoA Design System early adopters program", - urlPath: "get-started", - tags: ["get started", "introduction", "onboarding"], - category: "get started", - }, - { - id: "get-started-developers", - title: "Get started as a developer", - description: "Developer onboarding: package setup, template repo, branches, and compatibility", - urlPath: "get-started/developers", - tags: ["get started", "developer", "setup", "installation", "packages", "npm"], - category: "get started", - }, - { - id: "get-started-designers", - title: "Get started as a designer", - description: "Designer onboarding: Figma libraries, BETA components, and illustration requests", - urlPath: "get-started/designers", - tags: ["get started", "designer", "figma", "libraries", "illustrations"], - category: "get started", - }, -]; - -/** - * Generate search index entries for static pages - */ -function generatePageEntries(): DocIndex[] { - console.log("\nIndexing static pages..."); - - const entries: DocIndex[] = PAGE_ENTRIES.map(page => ({ - id: page.id, - title: page.title, - name: page.title, - description: page.description, - content: "", - component: "", - filePath: `docs/src/pages/${page.urlPath}`, - urlPath: page.urlPath, - tags: page.tags, - type: "page" as const, - slug: page.urlPath, - status: "stable", - category: page.category, - })); - - entries.forEach(e => console.log(` ✓ Indexed: ${e.title}`)); - return entries; -} - -/** - * Convert a token path to CSS variable format - */ -function pathToCssVar(pathParts: string[]): string { - return `--goa-${pathParts.join("-")}`; -} - -/** - * Check if an object is a token value (has a 'value' property) - */ -function isTokenValue(obj: unknown): obj is { value: unknown } { - return typeof obj === "object" && obj !== null && "value" in obj; -} - -/** - * Recursively extract all token names from a category - */ -function extractTokenNames( - obj: Record, - pathParts: string[] = [], -): string[] { - const names: string[] = []; - - for (const [key, value] of Object.entries(obj)) { - const currentPath = [...pathParts, key]; - - if (isTokenValue(value)) { - names.push(pathToCssVar(currentPath)); - } else if (typeof value === "object" && value !== null) { - names.push(...extractTokenNames(value as Record, currentPath)); - } - } - - return names; -} - -/** - * Generate a human-readable description for a token based on its name - */ -function generateTokenDescription(tokenName: string, category: string): string { - // Remove --goa- prefix and category for cleaner description - const shortName = tokenName.replace(/^--goa-/, "").replace(new RegExp(`^${category}-?`), ""); - const categoryMeta = TOKEN_CATEGORY_META[category]; - const categoryLabel = categoryMeta?.title.replace(" Tokens", "").toLowerCase() || category; - - if (!shortName) { - return `${categoryMeta?.title || category} design token`; - } - - // Convert kebab-case to readable format - const readable = shortName.replace(/-/g, " "); - return `${categoryLabel} token: ${readable}`; -} - -/** - * Generate search index entries for design tokens - * Creates both category entries (for browsing) and individual token entries (for direct search) - */ -function generateTokenEntries(): DocIndex[] { - const tokenPath = path.join( - process.cwd(), - "node_modules", - "@abgov", - "design-tokens-v2", - "data", - "goa-global-design-tokens.json", - ); - - if (!fs.existsSync(tokenPath)) { - console.warn(" ⚠ Design tokens not found, skipping token indexing"); - return []; - } - - const tokens = JSON.parse(fs.readFileSync(tokenPath, "utf-8")); - const entries: DocIndex[] = []; - - console.log("\nIndexing design tokens..."); - - let totalIndividualTokens = 0; - - for (const [category, categoryTokens] of Object.entries(tokens)) { - // Skip excluded categories - if (EXCLUDED_TOKEN_CATEGORIES.includes(category)) { - continue; - } - - const meta = TOKEN_CATEGORY_META[category]; - if (!meta) { - // Skip categories without metadata (likely internal) - continue; - } - - // Extract all token names in this category - const tokenNames = extractTokenNames( - { [category]: categoryTokens }, - [], - ); - - // Add category entry (for browsing by category) - const categoryEntry: DocIndex = { - id: `tokens-${category}`, - title: meta.title, - description: meta.description, - content: tokenNames.join(" "), - component: "", - filePath: "design-tokens", - urlPath: "tokens", - tags: meta.tags, - type: "token", - slug: category, // e.g., "color", "space" - used for building URL - status: "stable", - category: category, - }; - entries.push(categoryEntry); - - // Add individual token entries (for direct search) - for (const tokenName of tokenNames) { - // Convert --goa-color-greyscale-100 to color-greyscale-100 for URL slug - const tokenSlug = tokenName.replace(/^--goa-/, ""); - - const tokenEntry: DocIndex = { - id: `token-${tokenSlug}`, - title: tokenName, // Full CSS variable name: --goa-color-greyscale-100 - name: tokenName, - description: generateTokenDescription(tokenName, category), - content: "", // Individual tokens don't need searchable content - component: "", - filePath: "design-tokens", - urlPath: "tokens", - tags: ["token", "design token", category], - type: "token", - slug: tokenSlug, // Used for URL: /tokens?search=color-greyscale-100 - status: "stable", - category: category, - }; - entries.push(tokenEntry); - totalIndividualTokens++; - } - - console.log(` ✓ Indexed: ${meta.title} (${tokenNames.length} tokens)`); - } - - console.log(` → Total individual tokens indexed: ${totalIndividualTokens}`); - - return entries; -} - -async function generateSearchIndex() { - // Index component documentation from content folder - const componentsPattern = "docs/src/content/components/*.mdx"; - const componentFiles = await glob(componentsPattern, { - cwd: process.cwd(), - nodir: true, - }); - - console.log(`Found ${componentFiles.length} component documentation files`); - - const index: DocIndex[] = []; - - for (const filePath of componentFiles) { - try { - const fullPath = path.join(process.cwd(), filePath); - const content = fs.readFileSync(fullPath, "utf-8"); - - const componentName = extractComponentName(filePath); - const { frontMatter, bodyContent } = parseFrontMatter(content); - const title = frontMatter.name || frontMatter.title || extractTitle(bodyContent); - const tags = frontMatter.tags || []; - const description = frontMatter.description || extractDescription(bodyContent); - - const docEntry: DocIndex = { - id: componentName, - title: title || componentName, - name: title || componentName, // useSearch expects 'name' for components - description, - content: bodyContent, - component: componentName, - filePath: filePath, - urlPath: `components/${componentName}`, - tags: tags, - type: "component", - slug: componentName, - status: frontMatter.status || "stable", - category: frontMatter.category || "general", - }; - - index.push(docEntry); - console.log(` ✓ Indexed: ${componentName}`); - } catch (error) { - console.error(` ✗ Error processing ${filePath}:`, error); - } - } - - // Index examples from content folder - const examplesPattern = "docs/src/content/examples/*/index.mdx"; - const exampleFiles = await glob(examplesPattern, { - cwd: process.cwd(), - nodir: true, - }); - - console.log(`\nFound ${exampleFiles.length} example documentation files`); - - for (const filePath of exampleFiles) { - try { - const fullPath = path.join(process.cwd(), filePath); - const content = fs.readFileSync(fullPath, "utf-8"); - - // Extract slug from path (e.g., "add-a-filter-chip" from "docs/src/content/examples/add-a-filter-chip/index.mdx") - const pathParts = filePath.split(path.sep); - const exampleSlug = pathParts[pathParts.length - 2]; - - const { frontMatter, bodyContent } = parseFrontMatter(content); - const title = frontMatter.title || exampleSlug; - const tags = frontMatter.tags || []; - const description = frontMatter.description || extractDescription(bodyContent); - - // Handle components field - could be array or undefined - const components = Array.isArray(frontMatter.components) - ? frontMatter.components.join(", ") - : ""; - - const docEntry: DocIndex = { - id: `example-${exampleSlug}`, - title: title, - description, - content: bodyContent, - component: components, - filePath: filePath, - urlPath: `examples/${exampleSlug}`, - tags: [...tags, "example", "pattern"], - type: "example", - slug: exampleSlug, - status: frontMatter.status || "published", - categories: Array.isArray(frontMatter.categories) ? frontMatter.categories : [], - }; - - index.push(docEntry); - console.log(` ✓ Indexed: ${title}`); - } catch (error) { - console.error(` ✗ Error processing ${filePath}:`, error); - } - } - - // Add design token entries - const tokenEntries = generateTokenEntries(); - index.push(...tokenEntries); - - // Add static page entries (Get Started, etc.) - const pageEntries = generatePageEntries(); - index.push(...pageEntries); - - const outputPath = path.join(process.cwd(), "docs", "search-index.json"); - const publicOutputPath = path.join( - process.cwd(), - "docs", - "public", - "search-index.json", - ); - - const indexJson = JSON.stringify(index, null, 2); - fs.writeFileSync(outputPath, indexJson, "utf-8"); - - if (!fs.existsSync(path.join(process.cwd(), "docs", "public"))) { - fs.mkdirSync(path.join(process.cwd(), "docs", "public"), { recursive: true }); - } - fs.writeFileSync(publicOutputPath, indexJson, "utf-8"); - - console.log(`\n✓ Search index generated successfully!`); - console.log(` Location: ${outputPath}`); - console.log(` Public location: ${publicOutputPath}`); - console.log(` Total entries: ${index.length}`); -} - -function extractComponentName(filePath: string): string { - const parts = filePath.split(path.sep); - const fileName = parts[parts.length - 1]; - - return fileName.replace(".mdx", ""); -} - -function extractTitle(content: string): string { - const lines = content.split("\n"); - - for (const line of lines) { - const trimmed = line.trim(); - if (trimmed.startsWith("# ")) { - return trimmed.substring(2).trim(); - } - } - - return ""; -} - -// extract out the content between the h1 and first h2 tag -function extractDescription(content: string): string { - const lines = content.split("\n"); - const desc: string[] = []; - - for (const line of lines) { - const trimmed = line.trim(); - if (trimmed.startsWith("# ")) { - continue; - } - if (trimmed.startsWith("## ")) { - break; - } - desc.push(trimmed); - } - - return desc.join(" "); -} - -function parseFrontMatter(content: string): { - frontMatter: FrontMatter; - bodyContent: string; -} { - const frontMatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/; - const match = content.match(frontMatterRegex); - - if (!match) { - return { frontMatter: {}, bodyContent: content }; - } - - const [, frontMatterText, bodyContent] = match; - const frontMatter: FrontMatter = {}; - - const lines = frontMatterText.split("\n"); - for (const line of lines) { - const trimmed = line.trim(); - if (!trimmed) continue; - - const colonIndex = trimmed.indexOf(":"); - if (colonIndex === -1) continue; - - const key = trimmed.substring(0, colonIndex).trim(); - const value = trimmed.substring(colonIndex + 1).trim(); - - if (key === "tags") { - try { - const tagsMatch = value.match(/\[(.*?)\]/); - if (tagsMatch) { - frontMatter.tags = tagsMatch[1] - .split(",") - .map((tag) => tag.trim().replace(/['"]/g, "")) - .filter((tag) => tag.length > 0); - } - } catch (error) { - console.warn(`Failed to parse tags for line: ${line}`); - } - } else { - frontMatter[key] = value.replace(/^['"]|['"]$/g, ""); - } - } - - return { frontMatter, bodyContent }; -} - -generateSearchIndex().catch((error) => { - console.error("Failed to generate search index:", error); - process.exit(1); -}); From 90b5fa5694cc674f46280b5c20130ac2526dbb92 Mon Sep 17 00:00:00 2001 From: Dustin Nielsen Date: Thu, 27 Aug 2026 12:14:16 -0600 Subject: [PATCH 3/7] feat!: Updated Badge, Button, Checkbox, Filter Chip, and Menu Button --- docs/generated/component-apis/badge.json | 14 +- docs/generated/component-apis/button.json | 12 -- docs/generated/component-apis/checkbox.json | 11 -- .../generated/component-apis/filter-chip.json | 11 -- .../generated/component-apis/menu-button.json | 11 -- docs/src/components/CardLite.astro | 2 +- docs/src/components/ComponentsGrid.tsx | 5 - docs/src/components/ExampleListingCard.astro | 6 +- docs/src/components/ExamplesGrid.tsx | 8 - docs/src/components/PreviewContainer.astro | 6 +- docs/src/components/PropsTable.astro | 6 - docs/src/components/StaticMethods.astro | 2 +- docs/src/components/TokensGrid.tsx | 2 - .../web-components.html | 2 +- .../add-a-filter-chip/web-components.html | 2 +- .../web-components.html | 7 +- .../web-components.html | 16 +- .../web-components.html | 6 +- .../web-components.html | 4 +- .../web-components.html | 2 +- .../button-with-icon/web-components.html | 6 +- .../web-components.html | 12 +- .../confirm-a-change/web-components.html | 6 +- .../web-components.html | 5 +- .../web-components.html | 6 +- .../web-components.html | 4 +- .../web-components.html | 1 - .../web-components.html | 4 +- .../error-pages/401/web-components.html | 2 +- .../error-pages/404/web-components.html | 2 +- .../error-pages/500/web-components.html | 2 +- .../web-components.html | 1 - .../web-components.html | 14 +- .../web-components.html | 10 +- .../web-components.html | 4 +- .../web-components.html | 1 - .../web-components.html | 2 +- .../web-components.html | 2 +- .../web-components.html | 6 +- .../background-radio/web-components.html | 2 +- .../background-textarea/web-components.html | 2 +- .../variants/grouped/web-components.html | 2 +- .../variants/help-details/web-components.html | 2 +- .../variants/one-question/web-components.html | 2 +- .../web-components.html | 2 +- .../progress-indicator/web-components.html | 2 +- .../section-title/web-components.html | 2 +- .../web-components.html | 6 +- .../web-components.html | 4 +- .../web-components.html | 6 +- .../review-and-action/web-components.html | 2 +- .../examples/review-page/web-components.html | 4 +- .../examples/search/web-components.html | 2 +- .../web-components.html | 6 +- .../web-components.html | 26 ++- .../web-components.html | 4 +- .../web-components.html | 2 +- .../show-a-notification/web-components.html | 2 +- .../web-components.html | 2 +- .../show-a-user-progress/web-components.html | 2 +- .../web-components.html | 22 +-- .../web-components.html | 9 +- .../web-components.html | 6 +- .../web-components.html | 4 +- .../show-status-on-a-card/web-components.html | 2 +- .../examples/start-page/web-components.html | 2 +- .../task-list-page/web-components.html | 6 - .../web-components.html | 2 +- .../web-components.html | 4 +- .../get-started/ai-tools-and-resources.mdx | 6 +- .../developers/dark-mode-theme.mdx | 25 --- .../content/get-started/developers/setup.mdx | 28 +++ .../content/get-started/migration-guide.mdx | 2 +- .../button-destructive-for-irreversible.mdx | 2 +- .../guidance/button-one-primary-per-page.mdx | 6 +- .../button-use-clear-action-labels.mdx | 6 +- docs/src/content/guidance/button-vs-link.mdx | 2 +- .../guidance/button-when-not-to-use.mdx | 2 +- .../content/guidance/button-when-to-use.mdx | 2 +- .../productTypes/public-form/index.mdx | 2 +- .../content/productTypes/workspace/index.mdx | 6 +- docs/src/data/configurations/app-header.ts | 8 +- docs/src/data/configurations/badge.ts | 94 +++++----- docs/src/data/configurations/button-group.ts | 30 ++-- docs/src/data/configurations/button.ts | 36 ++-- docs/src/data/configurations/checkbox-list.ts | 56 +++--- docs/src/data/configurations/checkbox.ts | 18 +- docs/src/data/configurations/container.ts | 2 +- docs/src/data/configurations/data-grid.ts | 28 +-- docs/src/data/configurations/drawer.ts | 16 +- docs/src/data/configurations/dropdown.ts | 8 +- docs/src/data/configurations/filter-chip.ts | 20 +-- docs/src/data/configurations/hero-banner.ts | 4 +- docs/src/data/configurations/menu-button.ts | 22 +-- docs/src/data/configurations/modal.ts | 24 +-- docs/src/data/configurations/popover.ts | 14 +- docs/src/data/configurations/push-drawer.ts | 28 +-- docs/src/data/configurations/scroll-panel.ts | 6 +- docs/src/data/configurations/tabs.ts | 2 +- .../configurations/temporary-notification.ts | 14 +- docs/src/data/configurations/tooltip.ts | 16 +- .../data/configurations/workspace-layout.ts | 10 +- docs/src/pages/components/[slug].astro | 4 +- .../examples/[family]/[page]/index.astro | 4 +- docs/src/pages/examples/[slug].astro | 4 +- .../examples/error-pages/401/preview.astro | 2 +- .../examples/error-pages/404/preview.astro | 2 +- .../examples/error-pages/500/preview.astro | 2 +- .../foundations/style-guide/motion.astro | 5 +- docs/src/pages/support.astro | 4 +- .../src/lib/components/badge/badge.spec.ts | 2 +- .../src/lib/components/badge/badge.ts | 2 - .../src/lib/components/button/button.ts | 2 - .../src/lib/components/checkbox/checkbox.ts | 2 - .../filter-chip/filter-chip.spec.ts | 2 +- .../lib/components/filter-chip/filter-chip.ts | 2 - .../menu-button/menu-button.spec.ts | 1 - .../lib/components/menu-button/menu-button.ts | 1 - .../specs/badge.browser.spec.tsx | 6 +- .../specs/dropdown.browser.spec.tsx | 2 +- .../src/lib/badge/badge.spec.tsx | 2 +- libs/react-components/src/lib/badge/badge.tsx | 2 - .../src/lib/button/button.tsx | 2 - .../src/lib/checkbox/checkbox.tsx | 2 - .../src/lib/filter-chip/filter-chip.spec.tsx | 2 +- .../src/lib/filter-chip/filter-chip.tsx | 2 - .../src/lib/menu-button/menu-button.tsx | 3 +- .../src/components/badge/Badge.spec.ts | 13 +- .../src/components/badge/Badge.svelte | 69 ++++---- .../src/components/button/Button.svelte | 77 ++++----- .../src/components/checkbox/Checkbox.svelte | 77 +++------ .../components/filter-chip/FilterChip.spec.ts | 54 ++---- .../components/filter-chip/FilterChip.svelte | 163 +++++------------- .../components/menu-button/MenuButton.svelte | 4 - package-lock.json | 8 +- package.json | 2 +- 136 files changed, 568 insertions(+), 874 deletions(-) diff --git a/docs/generated/component-apis/badge.json b/docs/generated/component-apis/badge.json index 5e321a9a84..f7a2c189bf 100644 --- a/docs/generated/component-apis/badge.json +++ b/docs/generated/component-apis/badge.json @@ -193,7 +193,7 @@ "type": "string", "required": false, "default": "", - "description": "Content displayed in the badge. Use the content slot for custom HTML in version 2." + "description": "Content displayed in the badge. Use the content slot for custom HTML." }, { "name": "emphasis", @@ -324,18 +324,6 @@ "required": true, "default": null, "description": "Defines the context and colour of the badge." - }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "typeLabel": "GoabBadgeVersion", - "values": [ - "1", - "2" - ], - "required": false, - "default": "1", - "description": "Design system version for styling." } ], "events": [], diff --git a/docs/generated/component-apis/button.json b/docs/generated/component-apis/button.json index acf2086066..b9f64ed5d1 100644 --- a/docs/generated/component-apis/button.json +++ b/docs/generated/component-apis/button.json @@ -390,18 +390,6 @@ "default": "normal", "description": "Sets the color variant for semantic meaning. Use \"destructive\" for delete or irreversible actions, \"inverse\" for light-colored text on dark backgrounds, and \"dark\" for dark text color on text buttons only. Note: \"dark\" has no effect on non-text button types." }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "typeLabel": "GoabButtonVersion", - "values": [ - "1", - "2" - ], - "required": false, - "default": "1", - "description": "Design system version for styling." - }, { "name": "width", "type": "string", diff --git a/docs/generated/component-apis/checkbox.json b/docs/generated/component-apis/checkbox.json index d937c690ca..c960c8b91f 100644 --- a/docs/generated/component-apis/checkbox.json +++ b/docs/generated/component-apis/checkbox.json @@ -488,17 +488,6 @@ "required": false, "default": "", "description": "The value binding." - }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" - ], - "required": false, - "default": "1", - "description": "Design system version for styling." } ], "events": [ diff --git a/docs/generated/component-apis/filter-chip.json b/docs/generated/component-apis/filter-chip.json index 0834929b6c..23269a71e8 100644 --- a/docs/generated/component-apis/filter-chip.json +++ b/docs/generated/component-apis/filter-chip.json @@ -283,17 +283,6 @@ "required": false, "default": "", "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" - ], - "required": false, - "default": "1", - "description": "Design system version for styling." } ], "events": [ diff --git a/docs/generated/component-apis/menu-button.json b/docs/generated/component-apis/menu-button.json index 19afcb6b89..e7ca81f90d 100644 --- a/docs/generated/component-apis/menu-button.json +++ b/docs/generated/component-apis/menu-button.json @@ -215,17 +215,6 @@ "required": false, "default": "normal", "description": "Sets the color variant for semantic meaning." - }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" - ], - "required": false, - "default": "1", - "description": "Design system version for styling." } ], "events": [ diff --git a/docs/src/components/CardLite.astro b/docs/src/components/CardLite.astro index 59bb46a21e..506b309313 100644 --- a/docs/src/components/CardLite.astro +++ b/docs/src/components/CardLite.astro @@ -28,7 +28,7 @@ const isDisabled = !linkTo; {description} - +
) : ( diff --git a/docs/src/components/ComponentsGrid.tsx b/docs/src/components/ComponentsGrid.tsx index fba586356a..a5e8519d3a 100644 --- a/docs/src/components/ComponentsGrid.tsx +++ b/docs/src/components/ComponentsGrid.tsx @@ -566,7 +566,6 @@ export function ComponentsGrid({ components }: ComponentsGridProps) { {/* Category badge only - status shown in table view */}
{group.label} {group.label}
- + {data.productType && ( - + )} {userGoal && ( - + )}
diff --git a/docs/src/components/ExamplesGrid.tsx b/docs/src/components/ExamplesGrid.tsx index 61da18b83e..7db2fdb875 100644 --- a/docs/src/components/ExamplesGrid.tsx +++ b/docs/src/components/ExamplesGrid.tsx @@ -574,7 +574,6 @@ export function ExamplesGrid({ examples }: ExamplesGridProps) { {/* Metadata badges */}
{example.data.productType && ( ( {example.data.productType && ( ( {group.label} {group.label}
{moreUrl && ( - + More info )} {demoUrl && ( - + View demo )} {previewUrl && ( - + Live preview )} diff --git a/docs/src/components/PropsTable.astro b/docs/src/components/PropsTable.astro index 825e590549..f8d87ef496 100644 --- a/docs/src/components/PropsTable.astro +++ b/docs/src/components/PropsTable.astro @@ -189,7 +189,6 @@ const initialVisibleFramework =

{prefix}Props

{badge && ( {prop.name} {prop.required && ( {prefix}Events {badge && ( {badge && ( {slot.name} {slot.required && ( {param.name} {param.required && ( - + )}
diff --git a/docs/src/components/TokensGrid.tsx b/docs/src/components/TokensGrid.tsx index 7bd2c59108..b96b05c609 100644 --- a/docs/src/components/TokensGrid.tsx +++ b/docs/src/components/TokensGrid.tsx @@ -757,7 +757,6 @@ export function TokensGrid({ tokens, filterGroups }: TokensGridProps) { />
+ Open details diff --git a/docs/src/content/examples/add-a-filter-chip/web-components.html b/docs/src/content/examples/add-a-filter-chip/web-components.html index 330bf5c5af..ff4db0d05c 100644 --- a/docs/src/content/examples/add-a-filter-chip/web-components.html +++ b/docs/src/content/examples/add-a-filter-chip/web-components.html @@ -1,5 +1,5 @@
-Add Random Filter +Add Random Filter `, @@ -159,7 +159,7 @@ export const modalConfigurations: ComponentConfigurations = {

You can close this modal with the X button or by clicking the backdrop.

`, }, - webComponents: `Open modal + webComponents: `Open modal

You can close this modal with the X button or by clicking the backdrop.

@@ -191,12 +191,12 @@ export const modalConfigurations: ComponentConfigurations = { `, }, - webComponents: `Open modal + webComponents: `Open modal

This action cannot be undone. The item will be permanently removed.

- Cancel - Delete + Cancel + Delete
`, @@ -225,11 +225,11 @@ export const modalConfigurations: ComponentConfigurations = { `, }, - webComponents: `Open modal + webComponents: `Open modal

You will be logged out in 5 minutes due to inactivity.

- Stay logged in + Stay logged in
`, @@ -252,7 +252,7 @@ export const modalConfigurations: ComponentConfigurations = {

We have updated the application with new features. Review the changes to get started.

`, }, - webComponents: `Open modal + webComponents: `Open modal

We have updated the application with new features. Review the changes to get started.

@@ -276,7 +276,7 @@ export const modalConfigurations: ComponentConfigurations = {

Your application has been successfully submitted. You will receive a confirmation email shortly.

`, }, - webComponents: `Open modal + webComponents: `Open modal

Your application has been successfully submitted. You will receive a confirmation email shortly.

@@ -300,7 +300,7 @@ export const modalConfigurations: ComponentConfigurations = {

This modal has a wider maximum width for more content.

`, }, - webComponents: `Open modal + webComponents: `Open modal

This modal has a wider maximum width for more content.

diff --git a/docs/src/data/configurations/popover.ts b/docs/src/data/configurations/popover.ts index ddb24f7734..a458dc412d 100644 --- a/docs/src/data/configurations/popover.ts +++ b/docs/src/data/configurations/popover.ts @@ -27,7 +27,7 @@ export const popoverConfigurations: ComponentConfigurations = { Popover content goes here. It can contain any content. `, webComponents: ` - Open popover + Open popover Popover content goes here. It can contain any content. `, }, @@ -59,15 +59,15 @@ export const popoverConfigurations: ComponentConfigurations = { Automatically positions based on available space. `, webComponents: ` - Above + Above Content positioned above the trigger. - Below + Below Content positioned below the trigger. - Auto + Auto Automatically positions based on available space. `, }, @@ -92,11 +92,11 @@ export const popoverConfigurations: ComponentConfigurations = { Content flush with popover boundaries. `, webComponents: ` - Padded + Padded Content with padding applied. - No padding + No padding Content flush with popover boundaries. `, }, @@ -114,7 +114,7 @@ export const popoverConfigurations: ComponentConfigurations = { This popover has a maximum width of 300 pixels to control content width. `, webComponents: ` - More info + More info This popover has a maximum width of 300 pixels to control content width. `, }, diff --git a/docs/src/data/configurations/push-drawer.ts b/docs/src/data/configurations/push-drawer.ts index eb918de384..6eda0e732e 100644 --- a/docs/src/data/configurations/push-drawer.ts +++ b/docs/src/data/configurations/push-drawer.ts @@ -97,7 +97,7 @@ export const pushDrawerConfigurations: ComponentConfigurations = { }, webComponents: `
- Open push drawer + Open push drawer
Applicant name @@ -105,7 +105,7 @@ export const pushDrawerConfigurations: ComponentConfigurations = { File number 24567-9876 Status - + Submitted January 15, 2025 @@ -166,12 +166,12 @@ export const pushDrawerConfigurations: ComponentConfigurations = { }, webComponents: `
- Open push drawer + Open push drawer
Cases - + Applicant name Jane Smith @@ -219,7 +219,7 @@ export const pushDrawerConfigurations: ComponentConfigurations = { }, webComponents: `
- Open push drawer + Open push drawer
Officer @@ -298,19 +298,19 @@ export const pushDrawerConfigurations: ComponentConfigurations = { }, webComponents: `
- Open push drawer + Open push drawer
- - - + + + - Save - Cancel + Save + Cancel
@@ -393,7 +393,7 @@ export const pushDrawerConfigurations: ComponentConfigurations = { }, webComponents: `
- Open push drawer + Open push drawer
Jan 15, 2025 @@ -409,8 +409,8 @@ export const pushDrawerConfigurations: ComponentConfigurations = { Mar 12, 2025 Approval letter sent to applicant via registered mail. Case marked as complete. - Export - Close + Export + Close
diff --git a/docs/src/data/configurations/scroll-panel.ts b/docs/src/data/configurations/scroll-panel.ts index 8b3dd02efa..680735cfdd 100644 --- a/docs/src/data/configurations/scroll-panel.ts +++ b/docs/src/data/configurations/scroll-panel.ts @@ -91,8 +91,8 @@ export const scrollPanelConfigurations: ComponentConfigurations = {
- Cancel - Save changes + Cancel + Save changes
@@ -211,7 +211,7 @@ export const scrollPanelConfigurations: ComponentConfigurations = {
- Submit + Submit
diff --git a/docs/src/data/configurations/tabs.ts b/docs/src/data/configurations/tabs.ts index 2983f96485..1deed9b53c 100644 --- a/docs/src/data/configurations/tabs.ts +++ b/docs/src/data/configurations/tabs.ts @@ -129,7 +129,7 @@ export const tabsConfigurations: ComponentConfigurations = { Your messages will appear here. - Notifications + Notifications You have 3 unread notifications. diff --git a/docs/src/data/configurations/temporary-notification.ts b/docs/src/data/configurations/temporary-notification.ts index 23b64478c5..91a23f079a 100644 --- a/docs/src/data/configurations/temporary-notification.ts +++ b/docs/src/data/configurations/temporary-notification.ts @@ -44,7 +44,7 @@ export class SomeOtherComponent { }, webComponents: ` -Notification +Notification -{#if version === "2"} -