diff --git a/apps/prs/angular/src/app/app.component.html b/apps/prs/angular/src/app/app.component.html index 780a3016ff..280b854410 100644 --- a/apps/prs/angular/src/app/app.component.html +++ b/apps/prs/angular/src/app/app.component.html @@ -15,9 +15,23 @@ [open]="true" (onNavigate)="handleNavigate($event)" [primaryContent]="primaryTemplate" + [secondaryContent]="secondaryTemplate" > + + + + + 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 c8de31031e..91e46900ae 100644 --- a/apps/prs/angular/src/main.ts +++ b/apps/prs/angular/src/main.ts @@ -1,6 +1,19 @@ 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/routes/bugs/3602/bug3602.component.html b/apps/prs/angular/src/routes/bugs/3602/bug3602.component.html new file mode 100644 index 0000000000..ebf54acc57 --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3602/bug3602.component.html @@ -0,0 +1,39 @@ +

3602 FileUploadInput and FileUploadCard Improvements

+ + + + + +
+ @for (f of smallFiles; track f.id) { + + } +
+ + + + + +
+ @for (f of largeFiles; track f.id) { + + } +
diff --git a/apps/prs/angular/src/routes/bugs/3602/bug3602.component.ts b/apps/prs/angular/src/routes/bugs/3602/bug3602.component.ts new file mode 100644 index 0000000000..c88e1ae6b4 --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3602/bug3602.component.ts @@ -0,0 +1,76 @@ +import { Component } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { + GoabFileUploadInputOnSelectFileDetail, + GoabFileUploadOnDeleteDetail, +} from "@abgov/ui-components-common"; +import { + GoabFileUploadCard, + GoabFileUploadInput, + GoabFormItem, +} from "@abgov/angular-components"; + +type UploadedFile = { + id: string; + filename: string; + size: number; + type?: string; + progress: number; +}; + +@Component({ + standalone: true, + selector: "abgov-bug3602", + templateUrl: "./bug3602.component.html", + imports: [CommonModule, GoabFileUploadInput, GoabFileUploadCard, GoabFormItem], +}) +export class Bug3602Component { + smallFiles: UploadedFile[] = []; + largeFiles: UploadedFile[] = []; + + onSmallFileSelect(detail: GoabFileUploadInputOnSelectFileDetail) { + const file = detail.file; + this.smallFiles = [ + ...this.smallFiles, + { + id: `${file.name}-${Date.now()}`, + filename: file.name, + size: file.size, + type: file.type, + progress: -1, + }, + ]; + } + + onLargeFileSelect(detail: GoabFileUploadInputOnSelectFileDetail) { + const file = detail.file; + this.largeFiles = [ + ...this.largeFiles, + { + id: `${file.name}-${Date.now()}`, + filename: file.name, + size: file.size, + type: file.type, + progress: -1, + }, + ]; + } + + private removeFirstMatchingFile(files: UploadedFile[], id: string): UploadedFile[] { + const index = files.findIndex((f) => f.id === id); + if (index === -1) { + return files; + } + return [...files.slice(0, index), ...files.slice(index + 1)]; + } + + onSmallFileDelete(detail: GoabFileUploadOnDeleteDetail, id: string) { + console.log("Deleting file with id:", id); + this.smallFiles = this.removeFirstMatchingFile(this.smallFiles, id); + } + + onLargeFileDelete(detail: GoabFileUploadOnDeleteDetail, id: string) { + console.log("Deleting file with id:", id); + this.largeFiles = this.removeFirstMatchingFile(this.largeFiles, id); + } +} diff --git a/apps/prs/angular/src/routes/bugs/3602/bug3602.route.json b/apps/prs/angular/src/routes/bugs/3602/bug3602.route.json new file mode 100644 index 0000000000..bfbd38665a --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3602/bug3602.route.json @@ -0,0 +1,6 @@ +{ + "title": "FileUploadInput and FileUploadCard Improvements", + "path": "bugs/3602", + "id": "3602", + "type": "bug" +} diff --git a/apps/prs/angular/src/routes/bugs/3605/bug3605.component.html b/apps/prs/angular/src/routes/bugs/3605/bug3605.component.html new file mode 100644 index 0000000000..0a11c5877d --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3605/bug3605.component.html @@ -0,0 +1,447 @@ +
+ Issue 3605 + + Use :focus-visible across interactive components + + + + + + View on GitHub + + + + + + For every section: Tab should show the focus ring with the correct gap/offset. + Click should not leave a lingering ring. Mouse-down (:active) + on buttons should still show the pressed/focused look. + + + + + +
+ MicrositeHeader + Tab through the links inside the header. Click any link. + +
+ + + + +
+ Chip and FilterChip + Chip (deprecated) + + + + + + + FilterChip + + + + + +
+ + + + +
+ Plain link reset + Unstyled anchors pick up the global reset from assets/css/reset.css. +
+ First link + Second link + Third link +
+
+ + + + +
+ TextArea error state + + Tab into the error text area. Click into it. The focus-within container pattern + applies on focus, which is correct for text inputs. + + +
+ + + + +
+ Button + + Click and Tab each variant. Watch for lingering rings after mouse-up. + + + Default + + Primary + Secondary + Tertiary + + + Destructive + + Primary destructive + Secondary destructive + Tertiary destructive + + + Inverse (on dark bg) +
+ Primary inverse + Secondary inverse + Tertiary inverse +
+
+ + + + +
+ Checkbox + Tab to each. Click each. No ring on mouse click. + + + + + +
+ +
+
+ + + + +
+ + 7. Link — outer-container ring gated by JS modality check + + + Ring sits on the outer container so it wraps icon + text together. The component + listens for focusin on the slotted anchor and checks + .matches(':focus-visible') to keep keyboard-only semantics across the + slot boundary. + + + Plain links + + First link + Second link + Third link + + + Links with leading icons + + Download file + Learn more + Open in new tab + + + Links with trailing icons + + Continue + See more + External resource + + + Links with both icons + + Download and continue + +
+ + + + +
+ Notification + + Slotted anchors in notifications now use focus-visible. Keyboard only. + + + + Info notification with a link inside. + +
+ + Important notification with a link inside. + +
+
+ + Emergency notification with a link inside. + +
+
+ + + + +
+ + 9. Tooltip — .tooltip:focus .tooltip-text:focus-visible + + + Previously mouse-clicking the tooltip trigger revealed the tooltip. Now hover for mouse, + keyboard focus for keyboard. + + + + Hover or Tab me + + +
+ + + + +
+ + 10. Details — summary:focus:focus-visible + + + Previously clicking the summary left a hover-ish style. Now click just toggles open; + keyboard focus shows the focused look. + + + Content inside the details component. + +
+ + + + +
+ + 11. DataGrid — realistic table usage + + + Typical pattern: goab-data-grid wrapping a goab-table. Focus styling + is JS-driven, now guarded with a keyboard-input tracker so mouse click doesn't show the ring. + + + + + + Name + Role + Status + Actions + + + + + Alice Johnson + Developer + + View + + + Bob Smith + Designer + + View + + + Carol White + Manager + + View + + + David Brown + Analyst + + View + + + + + + DataGrid around a table with row checkboxes + + Adds a select-all checkbox to the header row and per-row checkboxes. When focus + lands on a cell whose only focusable child is the checkbox, focus delegates to + the checkbox itself. The corner cells should still show the rounded focus + treatment. + + + + + + + Name + Role + Status + Actions + + + + + + Alice Johnson + Developer + + View + + + + Bob Smith + Designer + + View + + + + Carol White + Manager + + View + + + + David Brown + Analyst + + View + + + + + + DataGrid around a sortable table + + goab-table with onSort handler and goab-table-sort-header on each column. Age + column starts ascending. Tab into a sort header, press Enter or Space to + toggle. Click a sort header with mouse should sort but not leave a lingering + ring. Arrow keys still navigate cells. + + + + + + + Name + + + Role + + + Age + + + + + @for (p of sortablePeople; track p.name) { + + {{ p.name }} + {{ p.role }} + {{ p.age }} + + } + + + + + DataGrid around cards (layout mode) + + keyboardNav="layout". Each card is a row, cells include the checkbox, name, + badge, stat blocks, and menu button. + + + +
+ +
+ + Mike Zwei + + + + +
+ + Updated + Jun 30, 2022 at 2:30 PM + + + Email + mike.zwei@gmail.com + + + Program + Wee Wild Ones Curry + +
+
+ + Program ID + 74528567 + + + Service access + Claims Adjustments + +
+
+ + + + +
+
+ + +
+ +
+ + Emma Stroman + + + + +
+ + Updated + Nov 28, 2021 at 1:30 PM + + + Email + emma.stroman@gmail.com + + + Program + Fort McMurray + +
+
+ + Program ID + 74522643 + + + Service access + Claims Adjustments + +
+
+ + + + +
+
+
+
+
diff --git a/apps/prs/angular/src/routes/bugs/3605/bug3605.component.ts b/apps/prs/angular/src/routes/bugs/3605/bug3605.component.ts new file mode 100644 index 0000000000..295ad455ad --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3605/bug3605.component.ts @@ -0,0 +1,72 @@ +import { Component } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { + GoabBadge, + GoabBlock, + GoabButton, + GoabCheckbox, + GoabChip, + GoabContainer, + GoabDataGrid, + GoabDetails, + GoabDivider, + GoabFilterChip, + GoabLink, + GoabMenuAction, + GoabMenuButton, + GoabMicrositeHeader, + GoabNotification, + GoabTable, + GoabTableSortHeader, + GoabText, + GoabTextArea, + GoabTooltip, +} from "@abgov/angular-components"; +import { GoabTableOnSortDetail } from "@abgov/ui-components-common"; + +@Component({ + standalone: true, + selector: "abgov-bug3605", + templateUrl: "./bug3605.component.html", + imports: [ + CommonModule, + GoabBadge, + GoabBlock, + GoabButton, + GoabCheckbox, + GoabChip, + GoabContainer, + GoabDataGrid, + GoabDetails, + GoabDivider, + GoabFilterChip, + GoabLink, + GoabMenuAction, + GoabMenuButton, + GoabMicrositeHeader, + GoabNotification, + GoabTable, + GoabTableSortHeader, + GoabText, + GoabTextArea, + GoabTooltip, + ], +}) +export class Bug3605Component { + sortablePeople = [ + { name: "Alice Johnson", role: "Developer", age: 32 }, + { name: "Bob Smith", role: "Designer", age: 28 }, + { name: "Carol White", role: "Manager", age: 45 }, + { name: "David Brown", role: "Analyst", age: 38 }, + ]; + + onSort(detail: GoabTableOnSortDetail) { + const by = detail.sortBy as "name" | "role" | "age"; + const dir = detail.sortDir; + this.sortablePeople = [...this.sortablePeople].sort((a, b) => { + if (a[by] < b[by]) return dir === 1 ? -1 : 1; + if (a[by] > b[by]) return dir === 1 ? 1 : -1; + return 0; + }); + } +} diff --git a/apps/prs/angular/src/routes/bugs/3605/bug3605.route.json b/apps/prs/angular/src/routes/bugs/3605/bug3605.route.json new file mode 100644 index 0000000000..1c9f9257e0 --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3605/bug3605.route.json @@ -0,0 +1,6 @@ +{ + "title": "Focus visible across interactive components", + "path": "bugs/3605", + "id": "3605", + "type": "bug" +} diff --git a/apps/prs/angular/src/routes/bugs/3668/bug3668.component.html b/apps/prs/angular/src/routes/bugs/3668/bug3668.component.html new file mode 100644 index 0000000000..3c6d55d43c --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3668/bug3668.component.html @@ -0,0 +1,117 @@ +
+ + + Bug #3668: Temporary notification refinements + + + + + View on GitHub + + + + + + 1. Indeterminate and progress variants should not have a dark grey border, and + should have a raised-heavy shadow. 2. Action button should be a tertiary + button, not a text button. 3. Below 360px, message and action button stack + vertically with button right-aligned. + + + + + + + Test Cases + + + Test 1: Indeterminate and progress variants (border + shadow) + + + Click each to trigger. Inspect the notification surface. Indeterminate and + progress should NOT have a dark grey border and SHOULD have a raised-heavy shadow + (matching basic/success/failure). + + + + Basic (reference) + + + Success (reference) + + + Failure (reference) + + Indeterminate + Progress + + + + + Test 2: Action button style + + The action button should render as a tertiary button, not a text button. Inspect + the button element. + + Show with action button + + + + Test 3: Stacking below 360px + + Resize your browser below 360px width and trigger a notification with an action. + Message and action button should stack vertically with button right-aligned. + + + + Show with action (then resize to 360px) + + + Show with long content + action + + + + + + + Test 4: Centered controller overlay blocks underlying UI + + + Click the button below to show a centered notification, then try clicking the + fixed Underlying target button at the bottom-right while the notification is + visible. If the count does not increase until the notification disappears, the + full-width controller overlay is blocking pointer events outside the snackbar. + + + + Show centered notification + + + Reset target count + + + + Underlying target clicks: {{ underlyingTargetClicks }} +
+ + diff --git a/apps/prs/angular/src/routes/bugs/3668/bug3668.component.ts b/apps/prs/angular/src/routes/bugs/3668/bug3668.component.ts new file mode 100644 index 0000000000..ed8b351b7f --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3668/bug3668.component.ts @@ -0,0 +1,100 @@ +import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core"; +import { + GoabBlock, + GoabButton, + GoabDetails, + GoabDivider, + GoabLink, + GoabTemporaryNotificationCtrl, + GoabText, +} from "@abgov/angular-components"; +import { TemporaryNotification } from "@abgov/ui-components-common"; + +@Component({ + standalone: true, + selector: "abgov-bug3668", + templateUrl: "./bug3668.component.html", + imports: [ + GoabBlock, + GoabButton, + GoabDetails, + GoabDivider, + GoabLink, + GoabTemporaryNotificationCtrl, + GoabText, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], +}) +export class Bug3668Component { + underlyingTargetClicks = 0; + + showBasic() { + TemporaryNotification.show("Basic notification for comparison", { + type: "basic", + duration: 8000, + }); + } + + showSuccess() { + TemporaryNotification.show("Successfully saved", { + type: "success", + duration: 8000, + }); + } + + showFailure() { + TemporaryNotification.show("Something went wrong", { + type: "failure", + duration: 8000, + }); + } + + showIndeterminate() { + const uuid = TemporaryNotification.show("Loading something indeterminate...", { + type: "indeterminate", + }); + setTimeout(() => TemporaryNotification.dismiss(uuid), 5000); + } + + showProgress() { + const uuid = TemporaryNotification.show("Uploading file...", { + type: "progress", + }); + let value = 0; + const interval = setInterval(() => { + value += 10; + TemporaryNotification.setProgress(uuid, value); + if (value >= 100) clearInterval(interval); + }, 500); + } + + showWithAction() { + TemporaryNotification.show("Item deleted", { + type: "basic", + duration: 8000, + actionText: "Undo", + }); + } + + showLongContent() { + TemporaryNotification.show( + "Your application for the Alberta Works program has been successfully submitted and is now being reviewed by our team. You will receive a confirmation email shortly.", + { type: "basic", duration: 15000, actionText: "View details" }, + ); + } + + showControllerOverlayIssue() { + TemporaryNotification.show( + "Overlay repro: while this centered notification is visible, try clicking the underlying target button at the bottom-right.", + { type: "basic", duration: 12000 }, + ); + } + + incrementUnderlyingTargetClicks() { + this.underlyingTargetClicks += 1; + } + + resetUnderlyingTargetClicks() { + this.underlyingTargetClicks = 0; + } +} diff --git a/apps/prs/angular/src/routes/bugs/3668/bug3668.route.json b/apps/prs/angular/src/routes/bugs/3668/bug3668.route.json new file mode 100644 index 0000000000..0562f9ca27 --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3668/bug3668.route.json @@ -0,0 +1,6 @@ +{ + "title": "Temporary Notification Refinements", + "path": "bugs/3668", + "id": "3668", + "type": "bug" +} diff --git a/apps/prs/angular/src/routes/bugs/3892/bug3892.component.html b/apps/prs/angular/src/routes/bugs/3892/bug3892.component.html new file mode 100644 index 0000000000..3b8653f10d --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3892/bug3892.component.html @@ -0,0 +1,187 @@ +
+
+

3892 - Nested close propagation

+

+ This page tests the issue where popover close events are propegating to parent + drawers and modals. +

+
+ + +
+

Popover

+

Open the popover and interact with all controls.

+
+ + + Open popover + + + +
+

+ Expected: using the date picker, dropdown, and menu button updates values + and leaves the popover open. +

+ + + + + + + + + + + + + +
+
+
+ + +
+

Drawer

+

Open the drawer and interact with all controls.

+
+ + Open drawer + + +
+

+ Expected: using the date picker, dropdown, and menu button updates values + and leaves the drawer open. +

+ + + + + + + + + + + + + +
+
+
+ + +

Push drawer

+

Open the push drawer and interact with all controls.

+ +
+ Open push drawer + + +
+

+ Expected: using the date picker, dropdown, and menu button updates values + and leaves the push drawer open. +

+ + + + + + + + + + + + + +
+
+
+
+ + +
+

Modal

+

Open the modal and interact with all controls.

+
+ + Open modal + + +
+

+ Expected: using the date picker, dropdown, and menu button updates values + and leaves the modal open. +

+ + + + + + + + + + + + + +
+
+
+
\ No newline at end of file diff --git a/apps/prs/angular/src/routes/bugs/3892/bug3892.component.ts b/apps/prs/angular/src/routes/bugs/3892/bug3892.component.ts new file mode 100644 index 0000000000..5caa5dab5d --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3892/bug3892.component.ts @@ -0,0 +1,111 @@ +import { CommonModule } from "@angular/common"; +import { Component } from "@angular/core"; +import { + GoabButton, + GoabContainer, + GoabDatePicker, + GoabDrawer, + GoabDropdown, + GoabDropdownItem, + GoabMenuAction, + GoabMenuButton, + GoabModal, + GoabPopover, + GoabPushDrawer, +} from "@abgov/angular-components"; +import type { + GoabDatePickerOnChangeDetail, + GoabDropdownOnChangeDetail, +} from "@abgov/ui-components-common"; + +@Component({ + standalone: true, + selector: "abgov-bug3892", + templateUrl: "./bug3892.component.html", + imports: [ + CommonModule, + GoabButton, + GoabContainer, + GoabDatePicker, + GoabDrawer, + GoabDropdown, + GoabDropdownItem, + GoabMenuAction, + GoabMenuButton, + GoabModal, + GoabPopover, + GoabPushDrawer, + ], +}) +export class Bug3892Component { + popoverDate = ""; + popoverProvince = ""; + + drawerOpen = false; + drawerDate = ""; + drawerProvince = ""; + + pushDrawerOpen = false; + pushDrawerDate = ""; + pushDrawerProvince = ""; + + modalOpen = false; + modalDate = ""; + modalProvince = ""; + + handlePopoverDateChange(detail: GoabDatePickerOnChangeDetail): void { + this.popoverDate = detail.valueStr || ""; + } + + handlePopoverProvinceChange(detail: GoabDropdownOnChangeDetail): void { + this.popoverProvince = detail.value || ""; + } + + openDrawer(): void { + this.drawerOpen = true; + } + + handleDrawerClose(): void { + this.drawerOpen = false; + } + + handleDrawerDateChange(detail: GoabDatePickerOnChangeDetail): void { + this.drawerDate = detail.valueStr || ""; + } + + handleDrawerProvinceChange(detail: GoabDropdownOnChangeDetail): void { + this.drawerProvince = detail.value || ""; + } + + openPushDrawer(): void { + this.pushDrawerOpen = true; + } + + handlePushDrawerClose(): void { + this.pushDrawerOpen = false; + } + + handlePushDrawerDateChange(detail: GoabDatePickerOnChangeDetail): void { + this.pushDrawerDate = detail.valueStr || ""; + } + + handlePushDrawerProvinceChange(detail: GoabDropdownOnChangeDetail): void { + this.pushDrawerProvince = detail.value || ""; + } + + openModal(): void { + this.modalOpen = true; + } + + handleModalClose(): void { + this.modalOpen = false; + } + + handleModalDateChange(detail: GoabDatePickerOnChangeDetail): void { + this.modalDate = detail.valueStr || ""; + } + + handleModalProvinceChange(detail: GoabDropdownOnChangeDetail): void { + this.modalProvince = detail.value || ""; + } +} \ No newline at end of file diff --git a/apps/prs/angular/src/routes/bugs/3892/bug3892.route.json b/apps/prs/angular/src/routes/bugs/3892/bug3892.route.json new file mode 100644 index 0000000000..68606580b6 --- /dev/null +++ b/apps/prs/angular/src/routes/bugs/3892/bug3892.route.json @@ -0,0 +1,6 @@ +{ + "type": "bug", + "id": "3892", + "path": "bugs/3892", + "title": "Nested close propagation" +} \ No newline at end of file diff --git a/apps/prs/angular/src/routes/docs/accordion/accordion.component.html b/apps/prs/angular/src/routes/docs/accordion/accordion.component.html index d0226905a1..ed3794ba8b 100644 --- a/apps/prs/angular/src/routes/docs/accordion/accordion.component.html +++ b/apps/prs/angular/src/routes/docs/accordion/accordion.component.html @@ -2,8 +2,8 @@

Accordion

Basic

- You will need to provide proof of identity, proof of address, - and any relevant supporting documentation. + You will need to provide proof of identity, proof of address, and any relevant + supporting documentation.

Open by default

@@ -82,7 +82,8 @@

Hide and show many sections of information

heading="How do I create an account?" headingSize="medium" [open]="expandedList[0]" - (onChange)="toggleAccordion(0, $event)"> + (onChange)="toggleAccordion(0, $event)" +> To create an account you will need to contact your office admin. @@ -90,22 +91,50 @@

Hide and show many sections of information

heading="What verification is needed to sign documents digitally?" headingSize="medium" [open]="expandedList[1]" - (onChange)="toggleAccordion(1, $event)"> - You will need to verify your identity through our two factor authentication in addition to the digital signature. + (onChange)="toggleAccordion(1, $event)" +> + You will need to verify your identity through our two factor authentication in addition + to the digital signature. - Yes, you can see the status of your application on the main service dashboard when you login. You will receive updates and notifications in your email as your request progresses. + (onChange)="toggleAccordion(2, $event)" +> + Yes, you can see the status of your application on the main service dashboard when you + login. You will receive updates and notifications in your email as your request + progresses. - Yes, our digital service is designed with accessibility in mind. More information on accessibility. + (onChange)="toggleAccordion(3, $event)" +> + Yes, our digital service is designed with accessibility in mind. + More information on accessibility. + + + You will need to provide proof of identity, proof of address, and any relevant + supporting documentation. + + + + This example mixes badges and controls inside the actions slot. + + + +
+ + View all +
+
diff --git a/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.html b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.html new file mode 100644 index 0000000000..f95b4c8ad4 --- /dev/null +++ b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.html @@ -0,0 +1,132 @@ +

Notification panel

+ +

Basic notification panel

+ + + + + + + + + + + + + + + + @for (item of basicItems; track item.id) { + + + } + + + +

With urgent notifications

+ + + + + + + + + + + + + + + + @for (item of urgentItems; track item.id) { + + + } + + + +

Notification type badges

+ + + + + + + + + + + + + + + @for (item of allTypeItems; track item.id) { + + + } + + diff --git a/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.ts b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.ts new file mode 100644 index 0000000000..be1994aede --- /dev/null +++ b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.component.ts @@ -0,0 +1,192 @@ +import { Component } from "@angular/core"; +import { + GoabWorkSideMenu, + GoabWorkSideMenuItem, + GoabWorkSideNotificationItem, + GoabWorkSideNotificationPanel, +} from "@abgov/angular-components"; +import type { + GoabWorkSideNotificationItemType, + GoabWorkSideNotificationPriority, + GoabWorkSideNotificationReadStatus, +} from "@abgov/ui-components-common"; + +interface NotificationItem { + id: string; + title: string; + description: string; + timestamp: string; + type: GoabWorkSideNotificationItemType; + readStatus: GoabWorkSideNotificationReadStatus; + priority: GoabWorkSideNotificationPriority; +} + +@Component({ + standalone: true, + selector: "abgov-docs-work-side-notification-panel", + templateUrl: "./work-side-notification-panel.component.html", + imports: [ + GoabWorkSideMenu, + GoabWorkSideMenuItem, + GoabWorkSideNotificationItem, + GoabWorkSideNotificationPanel, + ], +}) +export class DocsWorkSideNotificationPanelComponent { + basicItems: NotificationItem[] = [ + { + id: "1", + title: "New case assigned", + description: "Case #12345 has been assigned to you for review.", + timestamp: "2025-03-15T10:30:00Z", + type: "info", + readStatus: "unread", + priority: "normal", + }, + { + id: "2", + title: "Document uploaded", + description: "A new document was uploaded to Case #12340.", + timestamp: "2025-03-15T09:15:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + { + id: "3", + title: "Case resolved", + description: "Case #12330 has been marked as resolved.", + timestamp: "2025-03-14T16:00:00Z", + type: "success", + readStatus: "read", + priority: "normal", + }, + ]; + + urgentItems: NotificationItem[] = [ + { + id: "1", + title: "System maintenance", + description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.", + timestamp: "2025-03-15T14:00:00Z", + type: "critical", + readStatus: "unread", + priority: "urgent", + }, + { + id: "2", + title: "Deadline approaching", + description: "Case #12345 response is due in 2 hours.", + timestamp: "2025-03-15T12:00:00Z", + type: "warning", + readStatus: "unread", + priority: "urgent", + }, + { + id: "3", + title: "New comment on case", + description: "A team member commented on Case #12340.", + timestamp: "2025-03-15T11:00:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + ]; + + allTypeItems: NotificationItem[] = [ + { + id: "1", + title: "New comment on case", + description: "A team member commented on Case #12340.", + timestamp: "2025-03-15T10:00:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + { + id: "2", + title: "Case #12345 assigned", + description: "Case #12345 has been assigned to you for review.", + timestamp: "2025-03-15T09:00:00Z", + type: "info", + readStatus: "unread", + priority: "normal", + }, + { + id: "3", + title: "Case resolved", + description: "Case #12330 has been marked as resolved.", + timestamp: "2025-03-15T08:00:00Z", + type: "success", + readStatus: "unread", + priority: "normal", + }, + { + id: "4", + title: "Deadline approaching", + description: "Case #12345 response is due in 2 hours.", + timestamp: "2025-03-15T07:00:00Z", + type: "warning", + readStatus: "unread", + priority: "normal", + }, + { + id: "5", + title: "System maintenance", + description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.", + timestamp: "2025-03-15T06:00:00Z", + type: "critical", + readStatus: "unread", + priority: "normal", + }, + ]; + + handleNavigate(path: string): void { + console.log("navigate", path); + } + + // --- Basic notification panel handlers --- + handleMarkAllBasicNotificationsRead(): void { + this.basicItems = this.basicItems.map((item) => ({ ...item, readStatus: "read" })); + } + + handleViewAllBasicNotifications(): void { + console.log("view all basic notifications"); + } + + handleClickBasicNotification(id: string): void { + this.basicItems = this.basicItems.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ); + } + + // --- Urgent notification panel handlers --- + handleMarkAllUrgentNotificationsRead(): void { + this.urgentItems = this.urgentItems.map((item) => ({ ...item, readStatus: "read" })); + } + + handleViewAllUrgentNotifications(): void { + console.log("view all urgent notifications"); + } + + handleClickUrgentNotification(id: string): void { + this.urgentItems = this.urgentItems.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ); + } + + // --- Notification type badges panel handlers --- + handleMarkAllNotificationTypesRead(): void { + this.allTypeItems = this.allTypeItems.map((item) => ({ ...item, readStatus: "read" })); + } + + handleViewAllNotificationTypes(): void { + console.log("view all notification types"); + } + + handleClickNotificationType(id: string): void { + this.allTypeItems = this.allTypeItems.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ); + } +} diff --git a/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.route.json b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.route.json new file mode 100644 index 0000000000..0d8549afe6 --- /dev/null +++ b/apps/prs/angular/src/routes/docs/work-side-notification-panel/work-side-notification-panel.route.json @@ -0,0 +1,6 @@ +{ + "type": "docs", + "id": "work-side-notification-panel", + "path": "docs/work-side-notification-panel", + "title": "Notification Panel" +} diff --git a/apps/prs/angular/src/routes/features/feat2885/feat2885.component.ts b/apps/prs/angular/src/routes/features/feat2885/feat2885.component.ts index 7701daffc0..de047f5bdb 100644 --- a/apps/prs/angular/src/routes/features/feat2885/feat2885.component.ts +++ b/apps/prs/angular/src/routes/features/feat2885/feat2885.component.ts @@ -1,4 +1,4 @@ -import { Component, CUSTOM_ELEMENTS_SCHEMA, OnInit, OnDestroy } from "@angular/core"; +import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core"; import { GoabIconButton, GoabWorkSideMenu, @@ -46,25 +46,8 @@ type Notification = { ], schemas: [CUSTOM_ELEMENTS_SCHEMA], }) -export class Feat2885Component implements OnInit, OnDestroy { +export class Feat2885Component { menuOpen = true; - private v2TokensLink: HTMLLinkElement | null = null; - - ngOnInit() { - // Dynamically load v2 design tokens only while this page is mounted, - // so they don't leak into other routes in the SPA. - this.v2TokensLink = document.createElement("link"); - this.v2TokensLink.rel = "stylesheet"; - this.v2TokensLink.href = "/v2-tokens/tokens.css"; - document.head.appendChild(this.v2TokensLink); - } - - ngOnDestroy() { - if (this.v2TokensLink) { - document.head.removeChild(this.v2TokensLink); - this.v2TokensLink = null; - } - } notifications: Notification[] = [ { diff --git a/apps/prs/angular/src/routes/features/feat3229/feat3229.component.ts b/apps/prs/angular/src/routes/features/feat3229/feat3229.component.ts index 7886af2d9d..a712e5d823 100644 --- a/apps/prs/angular/src/routes/features/feat3229/feat3229.component.ts +++ b/apps/prs/angular/src/routes/features/feat3229/feat3229.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy } from "@angular/core"; +import { Component } from "@angular/core"; import { GoabBlock, GoabDivider, @@ -22,24 +22,9 @@ import { GoabMenuButtonOnActionDetail } from "@abgov/ui-components-common"; GoabText, ], }) -export class Feat3229Component implements OnInit, OnDestroy { - private v2TokensLink: HTMLLinkElement | null = null; +export class Feat3229Component { lastAction = ""; - ngOnInit() { - this.v2TokensLink = document.createElement("link"); - this.v2TokensLink.rel = "stylesheet"; - this.v2TokensLink.href = "/v2-tokens/tokens.css"; - document.head.appendChild(this.v2TokensLink); - } - - ngOnDestroy() { - if (this.v2TokensLink) { - document.head.removeChild(this.v2TokensLink); - this.v2TokensLink = null; - } - } - handleAction(detail: GoabMenuButtonOnActionDetail, label?: string) { const source = label ? ` (${label})` : ""; this.lastAction = `Action "${detail.action}"${source}`; diff --git a/apps/prs/angular/src/routes/features/feat3344/feat3344.component.ts b/apps/prs/angular/src/routes/features/feat3344/feat3344.component.ts index a9c12eb34d..bf2f531072 100644 --- a/apps/prs/angular/src/routes/features/feat3344/feat3344.component.ts +++ b/apps/prs/angular/src/routes/features/feat3344/feat3344.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy } from "@angular/core"; +import { Component } from "@angular/core"; import { GoabBlock, GoabDivider, @@ -20,9 +20,7 @@ import { GoabTableOnSortDetail, GoabTableOnMultiSortDetail, GoabTableSortEntry } GoabTableSortHeader, ], }) -export class Feat3344Component implements OnInit, OnDestroy { - private v2TokensLink: HTMLLinkElement | null = null; - +export class Feat3344Component { currentSorts: GoabTableSortEntry[] = []; multiSorts: GoabTableSortEntry[] = []; test3Sorts: GoabTableSortEntry[] = []; @@ -39,20 +37,6 @@ export class Feat3344Component implements OnInit, OnDestroy { multiSorted = [...this.data]; test3Sorted = [...this.data]; - ngOnInit() { - this.v2TokensLink = document.createElement("link"); - this.v2TokensLink.rel = "stylesheet"; - this.v2TokensLink.href = "/v2-tokens/tokens.css"; - document.head.appendChild(this.v2TokensLink); - } - - ngOnDestroy() { - if (this.v2TokensLink) { - document.head.removeChild(this.v2TokensLink); - this.v2TokensLink = null; - } - } - onSingleSortChange(detail: GoabTableOnSortDetail) { this.currentSorts = [{ column: detail.sortBy, direction: detail.sortDir === 1 ? "asc" : "desc" }]; this.singleSorted = this.sortData(this.data, this.currentSorts); diff --git a/apps/prs/angular/src/routes/features/feat3636/feat3636.component.html b/apps/prs/angular/src/routes/features/feat3636/feat3636.component.html new file mode 100644 index 0000000000..5ab4452598 --- /dev/null +++ b/apps/prs/angular/src/routes/features/feat3636/feat3636.component.html @@ -0,0 +1,453 @@ +
+ Feature 3636: Accordion actions slot and list view variant + + The GoAAccordion component now includes an optional slot for action buttons in the + header, as well as a new "list view" variant that features a filled header background + and hover state. + + +
+ Actions slot examples + + + + This example places a button in the actions slot while keeping heading text and + content as standard body copy. + + + + + Edit + + + + + This example mixes badges and controls inside the actions slot. + + + + +
+ + View all +
+
+
+ +
+ Heading content examples + + + + The heading content slot can display status indicators such as badges. + + + + + + + + + Preview + + + + + Multiple indicators can be grouped in heading content when more context is needed. + + + + +
+ + +
+
+ + +
+ + Manage +
+
+
+ +
+ Icon position and fixed width examples + +
+ + + A narrow fixed-width accordion using the default icon position. + + + + + Open + + + + + A wider fixed-width accordion with the icon moved to the right side. + + + + +
+ + Details +
+
+
+
+ +
+ Filled/List View Style + + + stuff goes in here + + + + + + + +
+ 1 Comment(s) + View +
+
+ + + stuff goes in here + + + + + + + +
+ 4 Comment(s) + View +
+
+ + + stuff goes in here + + + + + + + +
+ 3 Comment(s) + View +
+
+ + + stuff goes in here + + + + + + + +
+ 8 Comment(s) + View +
+
+ +

Multi-line Heading with Centered Chevron

+
+ +

+ 👀The chevron should be centered here +

+
+ + + + + + +
+ 1 Comment(s) + View +
+
+ + +

+ 👀The chevron should be centered here +

+
+ + + + + + +
+ 1 Comment(s) + View +
+
+ + +

+ 👀The chevron should be centered here +

+
+ + + + + + +
+ 1 Comment(s) + View +
+
+ + +

+ 👀The chevron should be centered here +

+
+ + +
+ 1 Comment(s) + View +
+
+ + +

+ 👀The chevron should be centered here +

+
+ + +
+ 1 Comment(s) + View +
+
+ + +

+ 👀The chevron should be centered here +

+
+ + + + + + +

+ 👀The chevron should be centered here +

+
+ + + + + + + + + + +

+ 👀The chevron should be centered here +

+
+ + + + + + +

+ 👀The chevron should be centered here +

+
+ + + + + + +

+ 👀The chevron should be centered here +

+
+ + + + + + +
+ 1 Comment(s) + View +
+
+ + +

+ 👀The chevron should be centered here +

+
+ + + + + + +
+ 1 Comment(s) + View +
+
+
+
+
diff --git a/apps/prs/angular/src/routes/features/feat3636/feat3636.component.ts b/apps/prs/angular/src/routes/features/feat3636/feat3636.component.ts new file mode 100644 index 0000000000..264448f2f3 --- /dev/null +++ b/apps/prs/angular/src/routes/features/feat3636/feat3636.component.ts @@ -0,0 +1,15 @@ +import { Component } from "@angular/core"; +import { + GoabAccordion, + GoabBadge, + GoabButton, + GoabText, +} from "@abgov/angular-components"; + +@Component({ + standalone: true, + selector: "abgov-feat3636", + templateUrl: "./feat3636.component.html", + imports: [GoabAccordion, GoabBadge, GoabButton, GoabText], +}) +export class Feat3636Component {} diff --git a/apps/prs/angular/src/routes/features/feat3636/feat3636.route.json b/apps/prs/angular/src/routes/features/feat3636/feat3636.route.json new file mode 100644 index 0000000000..3f0882b1c3 --- /dev/null +++ b/apps/prs/angular/src/routes/features/feat3636/feat3636.route.json @@ -0,0 +1,6 @@ +{ + "title": "Accordion actions slot and list view variant", + "path": "features/3636", + "id": "3636", + "type": "feature" +} diff --git a/apps/prs/angular/src/routes/features/feat3814/feat3814.component.css b/apps/prs/angular/src/routes/features/feat3814/feat3814.component.css new file mode 100644 index 0000000000..b57a6b5cf6 --- /dev/null +++ b/apps/prs/angular/src/routes/features/feat3814/feat3814.component.css @@ -0,0 +1,19 @@ +:host { + display: block; +} + +.search-menu-badge { + color: var(--goa-color-greyscale-600); + height: 1.25rem; + min-width: 1.25rem; + line-height: 1; + text-align: center; + font-size: var(--goa-font-size-2); + background-color: var(--goa-color-greyscale-100); + border: 1px solid var(--goa-color-greyscale-200); + border-radius: var(--goa-border-radius-s); + padding: var(--goa-space-3xs) var(--goa-space-xs); + display: inline-block; + vertical-align: top; + margin-top: var(--goa-space-3xs); +} diff --git a/apps/prs/angular/src/routes/features/feat3814/feat3814.component.html b/apps/prs/angular/src/routes/features/feat3814/feat3814.component.html new file mode 100644 index 0000000000..6506ccaaf3 --- /dev/null +++ b/apps/prs/angular/src/routes/features/feat3814/feat3814.component.html @@ -0,0 +1,47 @@ +
+ Feature 3814: Work Side Menu trailingContent slot + + + This page demonstrates the new trailingContent slot on Work Side Menu Item. + The first item shows a keyboard shortcut hint and the second item shows a badge. + + + +
+ +
+
+
+ + + + + + + + + Ctrl K + + + + + diff --git a/apps/prs/angular/src/routes/features/feat3814/feat3814.component.ts b/apps/prs/angular/src/routes/features/feat3814/feat3814.component.ts new file mode 100644 index 0000000000..c18880f93a --- /dev/null +++ b/apps/prs/angular/src/routes/features/feat3814/feat3814.component.ts @@ -0,0 +1,17 @@ +import { Component } from "@angular/core"; +import { + GoabBadge, + GoabContainer, + GoabText, + GoabWorkSideMenu, + GoabWorkSideMenuItem, +} from "@abgov/angular-components"; + +@Component({ + standalone: true, + selector: "abgov-feat3814", + templateUrl: "./feat3814.component.html", + styleUrls: ["./feat3814.component.css"], + imports: [GoabBadge, GoabContainer, GoabText, GoabWorkSideMenu, GoabWorkSideMenuItem], +}) +export class Feat3814Component {} diff --git a/apps/prs/angular/src/routes/features/feat3814/feat3814.route.json b/apps/prs/angular/src/routes/features/feat3814/feat3814.route.json new file mode 100644 index 0000000000..5395c36c0c --- /dev/null +++ b/apps/prs/angular/src/routes/features/feat3814/feat3814.route.json @@ -0,0 +1,6 @@ +{ + "title": "Work Side Menu Trailing Slot", + "path": "features/3814", + "id": "3814", + "type": "feature" +} diff --git a/apps/prs/angular/src/styles.css b/apps/prs/angular/src/styles.css index 33cd2fa85e..8078d0e064 100644 --- a/apps/prs/angular/src/styles.css +++ b/apps/prs/angular/src/styles.css @@ -1,6 +1,7 @@ /* 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"; :root { --goa-space-fill: 32ch; diff --git a/apps/prs/react/src/app/app.tsx b/apps/prs/react/src/app/app.tsx index af954286b6..04a769a9bf 100644 --- a/apps/prs/react/src/app/app.tsx +++ b/apps/prs/react/src/app/app.tsx @@ -1,4 +1,4 @@ -import type { CSSProperties } from "react"; +import { useState, type CSSProperties } from "react"; import { Outlet, useNavigate } from "react-router-dom"; import { GoabAppFooter, @@ -8,13 +8,27 @@ import { GoabWorkSideMenu, GoabWorkSideMenuGroup, GoabWorkSideMenuItem, + useTheme, } from "@abgov/react-components"; import { bugRouteDefinitions, docsRouteDefinitions, featureRouteDefinitions, } from "./route-manifest"; -import "@abgov/design-tokens-v2/dist/tokens.css"; // Production tokens. Comment out to test with legacy V1 token values. + +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"; + +// Sentinel URL handled by onNavigate below to toggle tokens instead of routing. +const TOKEN_TOGGLE_URL = "#tokens"; const appContentStyle: CSSProperties = { display: "flex", @@ -24,9 +38,22 @@ const appContentStyle: CSSProperties = { export function App() { const navigate = useNavigate(); + const { mode, toggle } = useTheme(); + const isDark = mode === "dark"; const baseUrl = import.meta.env.BASE_URL; + const [tokenMode, setTokenMode] = useState(() => resolveTokenVersion()); - const handleNavigate = (path: string) => { + 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; + } const internal = path.startsWith(baseUrl) ? "/" + path.slice(baseUrl.length) : path; navigate(internal); }; @@ -42,7 +69,21 @@ export function App() { heading="Testing Playground" url={baseUrl} open={true} - onNavigate={handleNavigate} + onNavigate={handleSideMenuNavigate} + secondaryContent={ + <> + + + + } primaryContent={ <> @@ -73,7 +114,11 @@ export function App() { /> ))} - + } /> diff --git a/apps/prs/react/src/app/routes/bugs/bug3602.route.ts b/apps/prs/react/src/app/routes/bugs/bug3602.route.ts new file mode 100644 index 0000000000..4909c43e38 --- /dev/null +++ b/apps/prs/react/src/app/routes/bugs/bug3602.route.ts @@ -0,0 +1,9 @@ +import { Bug3602Route } from "../../../routes/bugs/bug3602"; +import type { PrRouteDefinition } from "../../route-manifest"; +export default { + type: "bug", + id: "3602", + path: "bugs/3602", + title: "FileUploadInput and FileUploadCard Improvements", + component: Bug3602Route, +} satisfies PrRouteDefinition; diff --git a/apps/prs/react/src/app/routes/bugs/bug3605.route.ts b/apps/prs/react/src/app/routes/bugs/bug3605.route.ts new file mode 100644 index 0000000000..bc0695cbe3 --- /dev/null +++ b/apps/prs/react/src/app/routes/bugs/bug3605.route.ts @@ -0,0 +1,9 @@ +import { Bug3605Route } from "../../../routes/bugs/bug3605"; +import type { PrRouteDefinition } from "../../route-manifest"; +export default { + type: "bug", + id: "3605", + path: "bugs/3605", + title: "Focus visible across interactive components", + component: Bug3605Route, +} satisfies PrRouteDefinition; diff --git a/apps/prs/react/src/app/routes/bugs/bug3668.route.ts b/apps/prs/react/src/app/routes/bugs/bug3668.route.ts new file mode 100644 index 0000000000..c66d06d625 --- /dev/null +++ b/apps/prs/react/src/app/routes/bugs/bug3668.route.ts @@ -0,0 +1,10 @@ +import { Bug3668Route } from "../../../routes/bugs/bug3668"; +import type { PrRouteDefinition } from "../../route-manifest"; + +export default { + type: "bug", + id: "3668", + path: "bugs/3668", + title: "Temporary Notification Refinements", + component: Bug3668Route, +} satisfies PrRouteDefinition; diff --git a/apps/prs/react/src/app/routes/bugs/bug3892.route.ts b/apps/prs/react/src/app/routes/bugs/bug3892.route.ts new file mode 100644 index 0000000000..58f65a1412 --- /dev/null +++ b/apps/prs/react/src/app/routes/bugs/bug3892.route.ts @@ -0,0 +1,10 @@ +import { Bug3892Route } from "../../../routes/bugs/bug3892"; +import type { PrRouteDefinition } from "../../route-manifest"; + +export default { + type: "bug", + id: "3892", + path: "bugs/3892", + title: "Nested close propagation", + component: Bug3892Route, +} satisfies PrRouteDefinition; \ No newline at end of file diff --git a/apps/prs/react/src/app/routes/docs/work-side-notification-panel.route.ts b/apps/prs/react/src/app/routes/docs/work-side-notification-panel.route.ts new file mode 100644 index 0000000000..909d1dfce3 --- /dev/null +++ b/apps/prs/react/src/app/routes/docs/work-side-notification-panel.route.ts @@ -0,0 +1,10 @@ +import { DocsWorkSideNotificationPanelRoute } from "../../../routes/docs/work-side-notification-panel/work-side-notification-panel"; +import type { PrRouteDefinition } from "../../route-manifest"; + +export default { + type: "docs", + id: "work-side-notification-panel", + path: "docs/work-side-notification-panel", + title: "Notification Panel", + component: DocsWorkSideNotificationPanelRoute, +} satisfies PrRouteDefinition; diff --git a/apps/prs/react/src/app/routes/features/feat3636.route.ts b/apps/prs/react/src/app/routes/features/feat3636.route.ts new file mode 100644 index 0000000000..62c0c29351 --- /dev/null +++ b/apps/prs/react/src/app/routes/features/feat3636.route.ts @@ -0,0 +1,9 @@ +import { Feat3636Route } from "../../../routes/features/feat3636"; +import type { PrRouteDefinition } from "../../route-manifest"; +export default { + type: "feature", + id: "3636", + path: "features/3636", + title: "Accordion actions slot and list view variant", + component: Feat3636Route, +} satisfies PrRouteDefinition; diff --git a/apps/prs/react/src/app/routes/features/feat3814.route.ts b/apps/prs/react/src/app/routes/features/feat3814.route.ts new file mode 100644 index 0000000000..57753d145b --- /dev/null +++ b/apps/prs/react/src/app/routes/features/feat3814.route.ts @@ -0,0 +1,10 @@ +import { Feat3814Route } from "../../../routes/features/feat3814"; +import type { PrRouteDefinition } from "../../route-manifest"; + +export default { + type: "feature", + id: "3814", + path: "features/3814", + title: "Work Side Menu Trailing Slot", + component: Feat3814Route, +} satisfies PrRouteDefinition; diff --git a/apps/prs/react/src/app/tokenVersion.ts b/apps/prs/react/src/app/tokenVersion.ts new file mode 100644 index 0000000000..942685c6af --- /dev/null +++ b/apps/prs/react/src/app/tokenVersion.ts @@ -0,0 +1,47 @@ +// ?url tells Vite to resolve the asset path without injecting the CSS. +import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; + +export type TokenVersion = "v1" | "v2"; + +const STORAGE_KEY = "goa-token-version"; +const LINK_ID = "goa-tokens-v2"; +const URL_PARAM = "tokens"; + +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 = 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/main.tsx b/apps/prs/react/src/main.tsx index 83464a9fb6..7cc14365be 100644 --- a/apps/prs/react/src/main.tsx +++ b/apps/prs/react/src/main.tsx @@ -2,6 +2,7 @@ import { StrictMode } from "react"; import * as ReactDOM from "react-dom/client"; import { BrowserRouter, Route, Routes } from "react-router-dom"; +import { GoabThemeProvider } from "@abgov/react-components"; import "@abgov/web-components"; import App from "./app/app"; import { EverythingRoute } from "./routes/everything"; @@ -12,17 +13,19 @@ const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement) root.render( - - } /> - }> - } /> - {prRouteDefinitions.map((route) => { - const Component = route.component; + + + } /> + }> + } /> + {prRouteDefinitions.map((route) => { + const Component = route.component; - return } />; - })} - - + return } />; + })} + + + , ); diff --git a/apps/prs/react/src/routes/bugs/bug3548.tsx b/apps/prs/react/src/routes/bugs/bug3548.tsx index 810d6e15b9..25ff92ab80 100644 --- a/apps/prs/react/src/routes/bugs/bug3548.tsx +++ b/apps/prs/react/src/routes/bugs/bug3548.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState } from "react"; import { GoabBlock, GoabText, @@ -10,21 +10,9 @@ import { GoabWorkSideMenuItem, } from "@abgov/react-components"; -import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; - export function Bug3548Route() { const [open, setOpen] = useState(true); - useEffect(() => { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = v2TokensUrl; - document.head.appendChild(link); - return () => { - document.head.removeChild(link); - }; - }, []); - function onToggle() { setOpen((prev) => !prev); } diff --git a/apps/prs/react/src/routes/bugs/bug3602.tsx b/apps/prs/react/src/routes/bugs/bug3602.tsx new file mode 100644 index 0000000000..1b38632f71 --- /dev/null +++ b/apps/prs/react/src/routes/bugs/bug3602.tsx @@ -0,0 +1,81 @@ +import { useState, type Dispatch, type SetStateAction } from "react"; +import { GoabFileUploadInputOnSelectFileDetail } from "@abgov/ui-components-common"; +import { + GoabFileUploadCard, + GoabFileUploadInput, + GoabFormItem, +} from "@abgov/react-components"; + +type UploadedFile = { + id: string; + filename: string; + size: number; + type?: string; + progress: number; +}; + +export function Bug3602Route() { + const [smallFiles, setSmallFiles] = useState([]); + const [largeFiles, setLargeFiles] = useState([]); + + function handleFileChange( + detail: GoabFileUploadInputOnSelectFileDetail, + setFiles: Dispatch>, + ) { + const file = detail.file; + setFiles((prev) => [ + ...prev, + { + id: `${file.name}-${Date.now()}`, + filename: file.name, + size: file.size, + type: file.type, + progress: -1, + }, + ]); + } + + return ( + <> +

3602 FileUploadInput and FileUploadCard Improvements

+
+ + handleFileChange(detail, setSmallFiles)} + /> + +
+ {smallFiles.map((f) => ( + setSmallFiles((prev) => prev.filter((item) => item.id !== f.id))} + /> + ))} +
+ + handleFileChange(detail, setLargeFiles)} + /> + +
+ {largeFiles.map((f) => ( + setLargeFiles((prev) => prev.filter((item) => item.id !== f.id))} + /> + ))} +
+
+ + ); +} diff --git a/apps/prs/react/src/routes/bugs/bug3605.tsx b/apps/prs/react/src/routes/bugs/bug3605.tsx new file mode 100644 index 0000000000..939769f373 --- /dev/null +++ b/apps/prs/react/src/routes/bugs/bug3605.tsx @@ -0,0 +1,485 @@ +import "@abgov/style"; +import { useState } from "react"; +import { + GoabBadge, + GoabBlock, + GoabButton, + GoabCheckbox, + GoabChip, + GoabContainer, + GoabDataGrid, + GoabDetails, + GoabDivider, + GoabFilterChip, + GoabLink, + GoabMenuAction, + GoabMenuButton, + GoabMicrositeHeader, + GoabNotification, + GoabTable, + GoabTableSortHeader, + GoabText, + GoabTextarea, + GoabTooltip, +} from "@abgov/react-components"; + +export function Bug3605Route() { + const [sortablePeople, setSortablePeople] = useState([ + { name: "Alice Johnson", role: "Developer", age: 32 }, + { name: "Bob Smith", role: "Designer", age: 28 }, + { name: "Carol White", role: "Manager", age: 45 }, + { name: "David Brown", role: "Analyst", age: 38 }, + ]); + + return ( +
+ + Issue 3605 + + + Use focus-visible across interactive components + + + + + + View on GitHub + + + + + + For every section: Tab should show the focus ring with the correct gap and offset. + Click should not leave a lingering ring. Mouse-down on buttons should still show the + pressed state. + + + + + {/* MicrositeHeader */} +
+ MicrositeHeader + Tab through the links inside the header. Click any link. + +
+ + + + {/* Chip + FilterChip */} +
+ Chip and FilterChip + Chip (deprecated) + + + + + + + FilterChip + + + + + +
+ + + + {/* Plain link reset */} +
+ Plain link reset + Unstyled anchors pick up the global reset from assets/css/reset.css. + +
+ + + + {/* TextArea error */} +
+ TextArea error state + + Tab into the error text area. Click into it. The focus-within container pattern + applies on focus, which is correct for text inputs. + + +
+ + + + {/* Button variants */} +
+ Button + + Click and Tab each variant. Watch for lingering rings after mouse-up. + + + Default + + Primary + Secondary + Tertiary + + + Destructive + + Primary destructive + Secondary destructive + Tertiary destructive + + + Inverse (on dark bg) +
+ Primary inverse + Secondary inverse + Tertiary inverse +
+
+ + + + {/* Checkbox */} +
+ Checkbox + Tab to each. Click each. No ring on mouse click. + + + + + +
+ +
+
+ + + + {/* Link */} +
+ Link + + Ring sits on the outer container so it wraps icon + text together. The component + listens for focusin on the slotted anchor and checks{" "} + .matches(':focus-visible') to keep keyboard-only semantics across the + slot boundary. + + + Plain links + + First link + Second link + Third link + + + Links with leading icons + + Download file + Learn more + Open in new tab + + + Links with trailing icons + + Continue + See more + External resource + +
+ + + + {/* Notification */} +
+ Notification + + Slotted anchors in notifications now use focus-visible. Keyboard only. + + + + Info notification with a link inside. + +
+ + Important notification with a link inside. + +
+
+ + Emergency notification with a link inside. + +
+
+ + + + {/* Tooltip */} +
+ Tooltip + + Hover for mouse, keyboard focus for keyboard. Mouse click on the trigger does + not reveal the tooltip. + + + + Hover or Tab me + + +
+ + + + {/* Details */} +
+ Details + + Click just toggles open. Keyboard focus shows the focused look. + + + Content inside the details component. + +
+ + + + {/* DataGrid */} +
+ DataGrid around a table + + Typical pattern: GoabDataGrid wrapping a GoabTable. Focus styling is JS-driven, + now guarded with a keyboard-input tracker so mouse click does not show the ring. + Arrow keys navigate cells. + + + + + + Name + Role + Status + Actions + + + + + Alice Johnson + Developer + + View + + + Bob Smith + Designer + + View + + + Carol White + Manager + + View + + + David Brown + Analyst + + View + + + + + + DataGrid around a table with row checkboxes + + Adds a select-all checkbox to the header row and per-row checkboxes. + When focus lands on a cell whose only focusable child is the checkbox, + focus delegates to the checkbox itself. The corner cells should still + show the rounded focus treatment. + + + + + + + Name + Role + Status + Actions + + + + + + Alice Johnson + Developer + + View + + + + Bob Smith + Designer + + View + + + + Carol White + Manager + + View + + + + David Brown + Analyst + + View + + + + + + DataGrid around a sortable table + + GoabTable with onSort handler and GoabTableSortHeader on each column. Age + column starts ascending. Tab into a sort header, press Enter or Space to + toggle. Click a sort header with mouse should sort but not leave a + lingering ring. Arrow keys still navigate cells. + + + { + const by = e.sortBy as "name" | "role" | "age"; + const dir = e.sortDir; + setSortablePeople([...sortablePeople].sort((a, b) => { + if (a[by] < b[by]) return dir === 1 ? -1 : 1; + if (a[by] > b[by]) return dir === 1 ? 1 : -1; + return 0; + })); + }} + > + + + + Name + + + Role + + + Age + + + + + {sortablePeople.map((p) => ( + + {p.name} + {p.role} + {p.age} + + ))} + + + + + DataGrid around cards (layout mode) + + keyboardNav="layout". Each card is a row, cells include the checkbox, + name, badge, stat blocks, and menu button. + + + +
+ +
+ + Mike Zwei + + + + +
+ + Updated + Jun 30, 2022 at 2:30 PM + + + Email + mike.zwei@gmail.com + + + Program + Wee Wild Ones Curry + +
+
+ + Program ID + 74528567 + + + Service access + Claims Adjustments + +
+
+ + + + +
+
+ + +
+ +
+ + Emma Stroman + + + + +
+ + Updated + Nov 28, 2021 at 1:30 PM + + + Email + emma.stroman@gmail.com + + + Program + Fort McMurray + +
+
+ + Program ID + 74522643 + + + Service access + Claims Adjustments + +
+
+ + + + +
+
+
+
+
+ ); +} + +export default Bug3605Route; diff --git a/apps/prs/react/src/routes/bugs/bug3625.tsx b/apps/prs/react/src/routes/bugs/bug3625.tsx index 3ae0b9667c..a66d88fa88 100644 --- a/apps/prs/react/src/routes/bugs/bug3625.tsx +++ b/apps/prs/react/src/routes/bugs/bug3625.tsx @@ -8,23 +8,11 @@ import { GoabFormItem, GoabText, } from "@abgov/react-components"; -import { useEffect, useState } from "react"; -import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; +import { useState } from "react"; export function Bug3625Route() { const [controlledOpen, setControlledOpen] = useState(false); - // 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 (

Bug 3625: Accordion Refinement

diff --git a/apps/prs/react/src/routes/bugs/bug3668.tsx b/apps/prs/react/src/routes/bugs/bug3668.tsx new file mode 100644 index 0000000000..858c184dbc --- /dev/null +++ b/apps/prs/react/src/routes/bugs/bug3668.tsx @@ -0,0 +1,212 @@ +import { + GoabBlock, + GoabText, + GoabDivider, + GoabDetails, + GoabLink, + GoabButton, + GoabTemporaryNotificationCtrl, +} from "@abgov/react-components"; +import { TemporaryNotification } from "@abgov/ui-components-common"; +import { useState } from "react"; + +export function Bug3668Route() { + const [underlyingTargetClicks, setUnderlyingTargetClicks] = useState(0); + + const showBasic = () => { + TemporaryNotification.show("Basic notification for comparison", { + type: "basic", + duration: 8000, + }); + }; + + const showIndeterminate = () => { + const uuid = TemporaryNotification.show("Loading something indeterminate...", { + type: "indeterminate", + }); + setTimeout(() => TemporaryNotification.dismiss(uuid), 5000); + }; + + const showProgress = () => { + const uuid = TemporaryNotification.show("Uploading file...", { + type: "progress", + }); + let value = 0; + const interval = setInterval(() => { + value += 10; + TemporaryNotification.setProgress(uuid, value); + if (value >= 100) clearInterval(interval); + }, 500); + }; + + const showWithAction = () => { + TemporaryNotification.show("Item deleted", { + type: "basic", + duration: 8000, + actionText: "Undo", + }); + }; + + const showSuccess = () => { + TemporaryNotification.show("Successfully saved", { + type: "success", + duration: 8000, + }); + }; + + const showFailure = () => { + TemporaryNotification.show("Something went wrong", { + type: "failure", + duration: 8000, + }); + }; + + const showControllerOverlayIssue = () => { + TemporaryNotification.show( + "Overlay repro: while this centered notification is visible, try clicking the underlying target button at the bottom-right.", + { + type: "basic", + duration: 12000, + }, + ); + }; + + return ( +
+ + + + Bug #3668: Temporary notification refinements + + + + + + View on GitHub + + + + + + 1. Indeterminate and progress variants should not have a dark grey border, and + should have a raised-heavy shadow. 2. Action button should be a tertiary + button, not a text button. 3. Below 360px, message and action button stack + vertically with button right-aligned. + + + + + + + Test Cases + + + Test 1: Indeterminate and progress variants (border + shadow) + + + Click each to trigger. Inspect the notification surface. Indeterminate and + progress should NOT have a dark grey border and SHOULD have a raised-heavy shadow + (matching basic/success/failure). + + + + Basic (reference) + + + Success (reference) + + + Failure (reference) + + Indeterminate + Progress + + + + + Test 2: Action button style + + The action button should render as a tertiary button, not a text button. Inspect + the button element. + + Show with action button + + + + Test 3: Stacking below 360px + + Resize your browser below 360px width and trigger a notification with an action. + Message and action button should stack vertically with button right-aligned. + + + + Show with action (then resize to 360px) + + { + TemporaryNotification.show( + "Your application for the Alberta Works program has been successfully submitted and is now being reviewed by our team. You will receive a confirmation email shortly.", + { type: "basic", duration: 15000, actionText: "View details" }, + ); + }} + > + Show with long content + action + + + + + + + Test 4: Centered controller overlay blocks underlying UI + + + Click the button below to show a centered notification, then try clicking the + fixed Underlying target button at the bottom-right while the notification is + visible. If the count does not increase until the notification disappears, the + full-width controller overlay is blocking pointer events outside the snackbar. + + + + Show centered notification + + { + setUnderlyingTargetClicks(0); + }} + > + Reset target count + + + + Underlying target clicks: {underlyingTargetClicks} + + +
+ ); +} + +export default Bug3668Route; diff --git a/apps/prs/react/src/routes/bugs/bug3892.tsx b/apps/prs/react/src/routes/bugs/bug3892.tsx new file mode 100644 index 0000000000..0ade0fbe87 --- /dev/null +++ b/apps/prs/react/src/routes/bugs/bug3892.tsx @@ -0,0 +1,280 @@ +import { useState } from "react"; +import { + GoabButton, + GoabDatePicker, + GoabDrawer, + GoabDropdown, + GoabDropdownItem, + GoabMenuAction, + GoabMenuButton, + GoabModal, + GoabPopover, + GoabPushDrawer, + GoabText, + GoabContainer, +} from "@abgov/react-components"; +import type { + GoabDatePickerOnChangeDetail, + GoabDropdownOnChangeDetail, +} from "@abgov/ui-components-common"; + +const stackStyle = { + display: "grid", + gap: "1.5rem", +}; + +export function Bug3892Route() { + const [popoverDate, setPopoverDate] = useState(""); + const [popoverProvince, setPopoverProvince] = useState(""); + + const [drawerOpen, setDrawerOpen] = useState(false); + const [drawerDate, setDrawerDate] = useState(""); + const [drawerProvince, setDrawerProvince] = useState(""); + + const [pushDrawerOpen, setPushDrawerOpen] = useState(false); + const [pushDrawerDate, setPushDrawerDate] = useState(""); + const [pushDrawerProvince, setPushDrawerProvince] = useState(""); + + const [modalOpen, setModalOpen] = useState(false); + const [modalDate, setModalDate] = useState(""); + const [modalProvince, setModalProvince] = useState(""); + + const handlePopoverDateChange = (detail: GoabDatePickerOnChangeDetail) => { + setPopoverDate(detail.valueStr || ""); + }; + + const handlePopoverProvinceChange = (detail: GoabDropdownOnChangeDetail) => { + setPopoverProvince(detail.value || ""); + }; + + const handleDrawerDateChange = (detail: GoabDatePickerOnChangeDetail) => { + setDrawerDate(detail.valueStr || ""); + }; + + const handleDrawerClose = () => { + setDrawerOpen(false); + }; + + const handleDrawerProvinceChange = (detail: GoabDropdownOnChangeDetail) => { + setDrawerProvince(detail.value || ""); + }; + + const handlePushDrawerDateChange = (detail: GoabDatePickerOnChangeDetail) => { + setPushDrawerDate(detail.valueStr || ""); + }; + + const handlePushDrawerProvinceChange = (detail: GoabDropdownOnChangeDetail) => { + setPushDrawerProvince(detail.value || ""); + }; + + const handlePushDrawerClose = () => { + setPushDrawerOpen(false); + }; + + const handleModalDateChange = (detail: GoabDatePickerOnChangeDetail) => { + setModalDate(detail.valueStr || ""); + }; + + const handleModalProvinceChange = (detail: GoabDropdownOnChangeDetail) => { + setModalProvince(detail.value || ""); + }; + + const handleModalClose = () => { + setModalOpen(false); + }; + + return ( +
+
+ 3892 - Nested close propagation + + This page tests the issue where popover close events are propegating to parent + drawers and modals. + +
+ + +
+ + Popover + + Open the popover and interact with all controls. +
+ + Open popover}> +
+ + Expected: using the date picker, dropdown, and menu button updates values + and leaves the popover open. + + + + + + + + + + + + + + +
+
+
+ + +
+ + Drawer + + Open the drawer and interact with all controls. +
+ + setDrawerOpen(true)}>Open drawer + + +
+ + Expected: using the date picker, dropdown, and menu button updates values + and leaves the drawer open. + + + + + + + + + + + + + + +
+
+
+ + + + Push drawer + + Open the push drawer and interact with all controls. + +
+ setPushDrawerOpen(true)}> + Open push drawer + + + +
+ + Expected: using the date picker, dropdown, and menu button updates values + and leaves the push drawer open. + + + + + + + + + + + + + + +
+
+
+
+ + +
+ + Modal + + Open the modal and interact with all controls. +
+ + setModalOpen(true)}>Open modal + + +
+ + Expected: using the date picker, dropdown, and menu button updates values + and leaves the modal open. + + + + + + + + + + + + + + +
+
+
+
+ ); +} \ No newline at end of file diff --git a/apps/prs/react/src/routes/docs/accordion/accordion.tsx b/apps/prs/react/src/routes/docs/accordion/accordion.tsx index 72ba82a9f7..cd3ad438c0 100644 --- a/apps/prs/react/src/routes/docs/accordion/accordion.tsx +++ b/apps/prs/react/src/routes/docs/accordion/accordion.tsx @@ -33,8 +33,8 @@ export function DocsAccordionRoute() {

Basic

- You will need to provide proof of identity, proof of address, - and any relevant supporting documentation. + You will need to provide proof of identity, proof of address, and any relevant + supporting documentation.

Open by default

@@ -77,11 +77,14 @@ export function DocsAccordionRoute() {

Examples

Expand or collapse part of a form

- Review your application + + Review your application + }> + headingContent={} + >
Date of referral
January 27, 2021
@@ -104,7 +107,12 @@ export function DocsAccordionRoute() {

Hide and show many sections of information

- expandOrCollapseAll()}> + expandOrCollapseAll()} + > {expandedAll ? "Hide all sections" : "Show all sections"} @@ -123,8 +131,8 @@ export function DocsAccordionRoute() { headingSize="medium" onChange={(open) => updateAccordion(2, open)} > - You will need to verify your identity through our two factor - authentication in addition to the digital signature. + You will need to verify your identity through our two factor authentication in + addition to the digital signature. updateAccordion(3, open)} > - Yes, you can see the status of your application on the main service - dashboard when you login. You will receive updates and notifications in - your email as your request progresses. + Yes, you can see the status of your application on the main service dashboard when + you login. You will receive updates and notifications in your email as your + request progresses. More information on accessibility. + + + You will need to provide proof of identity, proof of address, and any relevant + supporting documentation. + + + + + + View all + +
+ } + > + + This example mixes badges and controls inside the actions slot. + + + +
+

Benji

+ } + actions={ +
+ + 1 Comment(s) + + + View + +
+ } + > +
+
Date of referral
+
January 27, 2021
+
Work safety concerns
+
None
+
Type of referral
+
Word of mouth, internet search
+
Intake received from another site
+
Yes
+
+
+
); } diff --git a/apps/prs/react/src/routes/docs/work-side-notification-panel/work-side-notification-panel.tsx b/apps/prs/react/src/routes/docs/work-side-notification-panel/work-side-notification-panel.tsx new file mode 100644 index 0000000000..610e067253 --- /dev/null +++ b/apps/prs/react/src/routes/docs/work-side-notification-panel/work-side-notification-panel.tsx @@ -0,0 +1,299 @@ +import { useState } from "react"; +import { + GoabWorkSideMenu, + GoabWorkSideMenuItem, + GoabWorkSideNotificationItem, + GoabWorkSideNotificationPanel, + type GoabWorkSideNotificationItemProps, +} from "@abgov/react-components"; + +type NotificationItem = GoabWorkSideNotificationItemProps & { id: string }; + +const initialBasicItems: NotificationItem[] = [ + { + id: "1", + title: "New case assigned", + description: "Case #12345 has been assigned to you for review.", + timestamp: "2025-03-15T10:30:00Z", + type: "info", + readStatus: "unread", + priority: "normal", + }, + { + id: "2", + title: "Document uploaded", + description: "A new document was uploaded to Case #12340.", + timestamp: "2025-03-15T09:15:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + { + id: "3", + title: "Case resolved", + description: "Case #12330 has been marked as resolved.", + timestamp: "2025-03-14T16:00:00Z", + type: "success", + readStatus: "read", + priority: "normal", + }, +]; + +const initialUrgentItems: NotificationItem[] = [ + { + id: "1", + title: "System maintenance", + description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.", + timestamp: "2025-03-15T14:00:00Z", + type: "critical", + readStatus: "unread", + priority: "urgent", + }, + { + id: "2", + title: "Deadline approaching", + description: "Case #12345 response is due in 2 hours.", + timestamp: "2025-03-15T12:00:00Z", + type: "warning", + readStatus: "unread", + priority: "urgent", + }, + { + id: "3", + title: "New comment on case", + description: "A team member commented on Case #12340.", + timestamp: "2025-03-15T11:00:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, +]; + +const initialAllTypeItems: NotificationItem[] = [ + { + id: "1", + title: "New comment on case", + description: "A team member commented on Case #12340.", + timestamp: "2025-03-15T10:00:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + { + id: "2", + title: "Case #12345 assigned", + description: "Case #12345 has been assigned to you for review.", + timestamp: "2025-03-15T09:00:00Z", + type: "info", + readStatus: "unread", + priority: "normal", + }, + { + id: "3", + title: "Case resolved", + description: "Case #12330 has been marked as resolved.", + timestamp: "2025-03-15T08:00:00Z", + type: "success", + readStatus: "unread", + priority: "normal", + }, + { + id: "4", + title: "Deadline approaching", + description: "Case #12345 response is due in 2 hours.", + timestamp: "2025-03-15T07:00:00Z", + type: "warning", + readStatus: "unread", + priority: "normal", + }, + { + id: "5", + title: "System maintenance", + description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.", + timestamp: "2025-03-15T06:00:00Z", + type: "critical", + readStatus: "unread", + priority: "normal", + }, +]; + +export function DocsWorkSideNotificationPanelRoute() { + const [basicItems, setBasicItems] = useState(initialBasicItems); + const [urgentItems, setUrgentItems] = useState(initialUrgentItems); + const [allTypeItems, setAllTypeItems] = useState(initialAllTypeItems); + + function navigate(path: string) { + console.log("navigate", path); + } + + // --- Basic notification panel handlers --- + function handleMarkAllBasicNotificationsRead() { + setBasicItems((items) => + items.map((item) => ({ ...item, readStatus: "read" })), + ); + } + + function handleViewAllBasicNotifications() { + console.log("view all basic notifications"); + } + + function handleClickBasicNotification(id: string) { + setBasicItems((items) => + items.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ), + ); + } + + // --- Urgent notification panel handlers --- + function handleMarkAllUrgentNotificationsRead() { + setUrgentItems((items) => + items.map((item) => ({ ...item, readStatus: "read" })), + ); + } + + function handleViewAllUrgentNotifications() { + console.log("view all urgent notifications"); + } + + function handleClickUrgentNotification(id: string) { + setUrgentItems((items) => + items.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ), + ); + } + + // --- Notification type badges panel handlers --- + function handleMarkAllNotificationTypesRead() { + setAllTypeItems((items) => + items.map((item) => ({ ...item, readStatus: "read" })), + ); + } + + function handleViewAllNotificationTypes() { + console.log("view all notification types"); + } + + function handleClickNotificationType(id: string) { + setAllTypeItems((items) => + items.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ), + ); + } + + return ( +
+

Notification panel

+ +

Basic notification panel

+ navigate(path)} + primaryContent={ + <> + + + + } + secondaryContent={ + handleMarkAllBasicNotificationsRead()} + onViewAll={() => handleViewAllBasicNotifications()} + > + {basicItems.map(({ id, ...item }) => ( + handleClickBasicNotification(id)} + /> + ))} + + } + /> + } + /> + +

With urgent notifications

+ navigate(path)} + primaryContent={ + <> + + + + } + secondaryContent={ + handleMarkAllUrgentNotificationsRead()} + onViewAll={() => handleViewAllUrgentNotifications()} + > + {urgentItems.map(({ id, ...item }) => ( + handleClickUrgentNotification(id)} + /> + ))} + + } + /> + } + /> + +

Notification type badges

+ navigate(path)} + primaryContent={ + + } + secondaryContent={ + handleMarkAllNotificationTypesRead()} + onViewAll={() => handleViewAllNotificationTypes()} + > + {allTypeItems.map(({ id, ...item }) => ( + handleClickNotificationType(id)} + /> + ))} + + } + /> + } + /> +
+ ); +} diff --git a/apps/prs/react/src/routes/everything-b.tsx b/apps/prs/react/src/routes/everything-b.tsx index f8360e2c7b..c8e9f9f747 100644 --- a/apps/prs/react/src/routes/everything-b.tsx +++ b/apps/prs/react/src/routes/everything-b.tsx @@ -38,9 +38,7 @@ import { GoabAppFooterMetaSection, GoabAppFooterNavSection, GoabFileUploadInput, - GoabFileUploadCard, GoabSideMenuHeading, - GoabAccordion, GoabSkeleton, GoabCheckbox, GoabFormStep, @@ -53,11 +51,9 @@ import { GoabTableSortHeader, GoabGrid, } from "@abgov/react-components"; -import "@abgov/style"; import { GoabDropdownOnChangeDetail, GoabInputOnChangeDetail, - GoabSkeletonSize, GoabTextAreaOnChangeDetail, } from "@abgov/ui-components-common"; @@ -81,7 +77,7 @@ export function EverythingBRoute() { const [step, setStep] = useState(-1); const [step2, setStep2] = useState(-1); // eslint-disable-next-line @typescript-eslint/no-empty-function - const noop = () => {}; + const noop = () => { }; // Snackbar states const [snackbarVisible, setSnackbarVisible] = useState< | false @@ -199,8 +195,7 @@ export function EverythingBRoute() {
- - +
{/* Back link after first header */} @@ -3743,7 +3738,7 @@ export function EverythingBRoute() { name="item" value={value} width="20ch" - onChange={function ( + onChange={function( detail: GoabInputOnChangeDetail, ): void { throw new Error("Function not implemented."); @@ -5468,16 +5463,14 @@ export function EverythingBRoute() { { /* noop */ }} + onChange={() => { + /* noop */ + }} /> 001 - + - console.log('Edit 001')} /> - console.log('Delete 001')} /> + console.log("Edit 001")} + /> + console.log("Delete 001")} + /> @@ -5509,16 +5510,14 @@ export function EverythingBRoute() { { /* noop */ }} + onChange={() => { + /* noop */ + }} /> 002 - + - console.log('Edit 002')} /> - console.log('Delete 002')} /> + console.log("Edit 002")} + /> + console.log("Delete 002")} + /> @@ -5550,16 +5557,14 @@ export function EverythingBRoute() { { /* noop */ }} + onChange={() => { + /* noop */ + }} /> 003 - + - console.log('Edit 003')} /> - console.log('Delete 003')} /> + console.log("Edit 003")} + /> + console.log("Delete 003")} + /> @@ -5611,7 +5624,9 @@ export function EverythingBRoute() { { /* noop */ }} + onChange={() => { + /* noop */ + }} /> 001 @@ -5627,8 +5642,16 @@ export function EverythingBRoute() { - console.log('Edit')} /> - console.log('Delete')} /> + console.log("Edit")} + /> + console.log("Delete")} + /> @@ -5637,7 +5660,9 @@ export function EverythingBRoute() { { /* noop */ }} + onChange={() => { + /* noop */ + }} /> 002 @@ -5653,14 +5678,21 @@ export function EverythingBRoute() { - console.log('Edit')} /> - console.log('Delete')} /> + console.log("Edit")} + /> + console.log("Delete")} + /> - @@ -6056,4 +6088,4 @@ export function EverythingBRoute() { ); -} \ No newline at end of file +} diff --git a/apps/prs/react/src/routes/everything.tsx b/apps/prs/react/src/routes/everything.tsx index 838fce95a9..7562239a55 100644 --- a/apps/prs/react/src/routes/everything.tsx +++ b/apps/prs/react/src/routes/everything.tsx @@ -26,7 +26,6 @@ import { GoabDrawer, GoabDropdown, GoabDropdownItem, - GoabFieldset, GoabFileUploadCard, GoabFileUploadInput, GoabFilterChip, @@ -50,13 +49,6 @@ import { GoabPages, GoabPagination, GoabPopover, - GoabPublicForm, - GoabPublicFormPage, - GoabPublicFormSummary, - GoabPublicFormTask, - GoabPublicFormTaskList, - GoabPublicSubform, - GoabPublicSubformIndex, GoabRadioGroup, GoabRadioItem, GoabSideMenu, @@ -657,7 +649,12 @@ export function EverythingRoute(): JSX.Element { ))} - + Type: interactive
@@ -1133,6 +1130,17 @@ export function EverythingRoute(): JSX.Element { ))} + + + + + + +
@@ -1577,7 +1585,8 @@ export function EverythingRoute(): JSX.Element { Data Grid (Keyboard Navigation) - The data grid wraps a table to enable keyboard navigation. Use arrow keys to move between cells. + The data grid wraps a table to enable keyboard navigation. Use arrow keys to + move between cells. @@ -1597,11 +1606,16 @@ export function EverythingRoute(): JSX.Element { {row.name} {row.created} - + {row.progress}% - View + + View + ))} diff --git a/apps/prs/react/src/routes/features/feat2469.tsx b/apps/prs/react/src/routes/features/feat2469.tsx index 2cddee7512..514939e4f7 100644 --- a/apps/prs/react/src/routes/features/feat2469.tsx +++ b/apps/prs/react/src/routes/features/feat2469.tsx @@ -1,4 +1,4 @@ -import { JSX, useState, useEffect } from "react"; +import { JSX, useState } from "react"; import { GoabButton, GoabFormItem, @@ -9,7 +9,6 @@ import { } from "@abgov/react-components"; import { GoabInputOnChangeDetail } from "@abgov/ui-components-common"; -import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; type DataTableFields = { firstName: string; @@ -32,44 +31,6 @@ function generateFakeData(numRows: number): DataTableFields[] { } export function Feat2469Route(): JSX.Element { - useEffect(() => { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = v2TokensUrl; - document.head.appendChild(link); - - const deletedRules: Array<{ sheet: CSSStyleSheet; index: number; cssText: string }> = - []; - - link.onload = () => { - [...document.styleSheets].forEach((ss) => { - if (ss.ownerNode === link) return; - try { - for (let i = ss.cssRules.length - 1; i >= 0; i--) { - const rule = ss.cssRules[i]; - if (rule instanceof CSSStyleRule && rule.selectorText === ":root") { - deletedRules.push({ sheet: ss, index: i, cssText: rule.cssText }); - ss.deleteRule(i); - } - } - } catch (e) { - // skip cross-origin sheets - } - }); - }; - - return () => { - link.remove(); - deletedRules.forEach(({ sheet, index, cssText }) => { - try { - sheet.insertRule(cssText, Math.min(index, sheet.cssRules.length)); - } catch (e) { - // skip if sheet is no longer available - } - }); - }; - }, []); - const smallDrawerControlSet = (

Drawer

diff --git a/apps/prs/react/src/routes/features/feat2885.tsx b/apps/prs/react/src/routes/features/feat2885.tsx index bed09d78b3..c5863f9a5b 100644 --- a/apps/prs/react/src/routes/features/feat2885.tsx +++ b/apps/prs/react/src/routes/features/feat2885.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState } from "react"; import { GoabIconButton, GoabWorkSideMenu, @@ -7,9 +7,6 @@ import { GoabWorkSideNotificationPanel, } from "@abgov/react-components"; -// ?url suffix tells Vite to resolve the path without injecting the CSS -import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; - type Notification = { id: string; title: string; @@ -23,18 +20,6 @@ type Notification = { export function Feat2885Route() { const [menuOpen, setMenuOpen] = useState(true); - // Dynamically load v2 design tokens only while this page is mounted, - // so they don't leak into other routes in the SPA. - useEffect(() => { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = v2TokensUrl; - document.head.appendChild(link); - return () => { - document.head.removeChild(link); - }; - }, []); - // Helper to get date at specific days ago const daysAgo = (days: number, hours = 0) => { const date = new Date(); diff --git a/apps/prs/react/src/routes/features/feat3229.tsx b/apps/prs/react/src/routes/features/feat3229.tsx index a84e8c5285..3d380f26f9 100644 --- a/apps/prs/react/src/routes/features/feat3229.tsx +++ b/apps/prs/react/src/routes/features/feat3229.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState } from "react"; import { GoabBadge, GoabBlock, @@ -9,7 +9,6 @@ import { } from "@abgov/react-components"; import { GoabMenuButtonOnActionDetail } from "@abgov/ui-components-common"; -import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; // Menu actions with icon + text const menuActionsWithIcons = ( @@ -34,49 +33,6 @@ const menuActionsTextOnly = ( export function Feat3229Route() { const [lastAction, setLastAction] = useState(""); - useEffect(() => { - // Load V2 tokens - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = v2TokensUrl; - document.head.appendChild(link); - - // Save deleted rules so we can restore them on cleanup - const deletedRules: Array<{ sheet: CSSStyleSheet; index: number; cssText: string }> = - []; - - // Remove V1 token definitions (:root rules) from all other stylesheets, - // keeping component styles intact - link.onload = () => { - [...document.styleSheets].forEach((ss) => { - if (ss.ownerNode === link) return; // skip V2 stylesheet - try { - for (let i = ss.cssRules.length - 1; i >= 0; i--) { - const rule = ss.cssRules[i]; - if (rule instanceof CSSStyleRule && rule.selectorText === ":root") { - deletedRules.push({ sheet: ss, index: i, cssText: rule.cssText }); - ss.deleteRule(i); - } - } - } catch (e) { - // skip cross-origin sheets - } - }); - }; - - return () => { - document.head.removeChild(link); - // Restore V1 :root rules in reverse order to maintain correct indices - deletedRules.reverse().forEach(({ sheet, index, cssText }) => { - try { - sheet.insertRule(cssText, index); - } catch (e) { - console.log(e); - } - }); - }; - }, []); - const handleAction = (detail: GoabMenuButtonOnActionDetail, label?: string) => { const source = label ? ` (${label})` : ""; setLastAction(`Action "${detail.action}"${source}`); diff --git a/apps/prs/react/src/routes/features/feat3344.tsx b/apps/prs/react/src/routes/features/feat3344.tsx index c39cd44f37..f75a9e7062 100644 --- a/apps/prs/react/src/routes/features/feat3344.tsx +++ b/apps/prs/react/src/routes/features/feat3344.tsx @@ -9,7 +9,7 @@ * - V2 focus ring on icon only (not whole button) */ -import { useEffect, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import { GoabBlock, GoabDetails, @@ -17,8 +17,6 @@ import { GoabTable, GoabTableSortHeader, } from "@abgov/react-components"; -// ?url suffix tells Vite to resolve the path without injecting the CSS -import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; import type { GoabTableSortEntry } from "@abgov/ui-components-common"; @@ -51,16 +49,6 @@ function sortData(data: RowData[], sorts: GoabTableSortEntry[]): RowData[] { } export function Feat3344Route() { - useEffect(() => { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = v2TokensUrl; - document.head.appendChild(link); - return () => { - document.head.removeChild(link); - }; - }, []); - const [currentSorts, setCurrentSorts] = useState([]); const [multiSorts, setMultiSorts] = useState([]); const [test3Sorts, setTest3Sorts] = useState([]); diff --git a/apps/prs/react/src/routes/features/feat3407StackOnMobile.tsx b/apps/prs/react/src/routes/features/feat3407StackOnMobile.tsx index 7065463bcd..004b6c821c 100644 --- a/apps/prs/react/src/routes/features/feat3407StackOnMobile.tsx +++ b/apps/prs/react/src/routes/features/feat3407StackOnMobile.tsx @@ -6,23 +6,9 @@ import { GoabText, } from "@abgov/react-components"; -import { useEffect, type JSX } from "react"; -// ?url suffix tells Vite to resolve the path without injecting the CSS -import v2TokensUrl from "@abgov/design-tokens-v2/dist/tokens.css?url"; +import { type JSX } from "react"; export function Feat3407StackOnMobileRoute(): JSX.Element { - // Dynamically load v2 design tokens only while this page is mounted, - // so they don't leak into other routes in the SPA. - useEffect(() => { - const link = document.createElement("link"); - link.rel = "stylesheet"; - link.href = v2TokensUrl; - document.head.appendChild(link); - return () => { - document.head.removeChild(link); - }; - }, []); - return (
diff --git a/apps/prs/react/src/routes/features/feat3636.tsx b/apps/prs/react/src/routes/features/feat3636.tsx new file mode 100644 index 0000000000..21d46d62e1 --- /dev/null +++ b/apps/prs/react/src/routes/features/feat3636.tsx @@ -0,0 +1,436 @@ +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 ( +
+ + Feature 3636: Accordion actions slot and list view variant + + + The GoAAccordion component now includes an optional slot for action buttons in the + header, as well as a new "list view" variant that features a filled header + background and hover state. + + +
+ Actions slot examples + + + Edit + + } + > + + This example places a button in the actions slot while keeping heading text + and content as standard body copy. + + + + + + + View all + +
+ } + > + + This example mixes badges and controls inside the actions slot. + + +
+ +
+ Heading content examples + + } + actions={ + + Preview + + } + open + > + + The heading content slot can display status indicators such as badges. + + + + + + +
+ } + actions={ +
+ + + Manage + +
+ } + > + + Multiple indicators can be grouped in heading content when more context is + needed. + + +
+ +
+ Icon position and fixed width examples + +
+ + Open + + } + open + > + + A narrow fixed-width accordion using the default icon position. + + + + + + + Details + +
+ } + open + > + + A wider fixed-width accordion with the icon moved to the right side. + + +
+
+ +
+ Filled/List View Style + } + headingType="filled" + actions={ +
+ + 1 Comment(s) + + + View + +
+ } + open + > + stuff goes in here +
+ + } + headingType="filled" + actions={ +
+ + 4 Comment(s) + + + View + +
+ } + open + > + stuff goes in here +
+ } + headingType="filled" + actions={ +
+ + 3 Comment(s) + + + View + +
+ } + open + > + stuff goes in here +
+ } + headingType="filled" + actions={ +
+ + 8 Comment(s) + + + View + +
+ } + open + > + stuff goes in here +
+
+

Multi-line Heading with Centered Chevron

+
+ } + headingType="filled" + actions={ +
+ + 1 Comment(s) + + + View + +
+ } + > +

+ + 👀 + + The chevron should be centered in the heading +

+
+ } + headingType="filled" + actions={ +
+ + 1 Comment(s) + + + View + +
+ } + iconPosition="right" + > +

+ + 👀 + + The chevron should be centered here +

+
+ + + 1 Comment(s) + + + View + +
+ } + > +

+ + 👀 + + The chevron should be centered here +

+ + + + 1 Comment(s) + + + View + + + } + > +

+ + 👀 + + The chevron should be centered here +

+
+ } + headingType="filled" + > +

+ + 👀 + + The chevron should be centered here +

+
+ } + headingType="filled" + iconPosition="right" + > +

+ + 👀 + + The chevron should be centered here +

+
+ } + > +

+ + 👀 + + The chevron should be centered here +

+
+ } + iconPosition="right" + > +

+ + 👀 + + The chevron should be centered here +

+
+ } + headingType="filled" + actions={ +
+ + 1 Comment(s) + + + View + +
+ } + secondaryText="Secondary text that is long enough to wrap onto multiple lines and push the heading content and actions down" + > +

+ + 👀 + + The chevron should be centered here +

+
+ } + headingType="filled" + actions={ +
+ + 1 Comment(s) + + + View + +
+ } + secondaryText="Secondary text that is long enough to wrap onto multiple lines and push the heading content and actions down" + iconPosition="right" + > +

+ + 👀 + + The chevron should be centered here +

+
+ + + ); +} diff --git a/apps/prs/react/src/routes/features/feat3814.tsx b/apps/prs/react/src/routes/features/feat3814.tsx new file mode 100644 index 0000000000..b4d3b6f896 --- /dev/null +++ b/apps/prs/react/src/routes/features/feat3814.tsx @@ -0,0 +1,75 @@ +import { + GoabBadge, + GoabContainer, + GoabText, + GoabWorkSideMenu, + GoabWorkSideMenuItem, +} from "@abgov/react-components"; + +export function Feat3814Route() { + return ( +
+ + Feature 3814: Work Side Menu trailingContent slot + + + + This page demonstrates the new trailingContent slot on Work Side Menu Item. The + first item shows a keyboard shortcut hint and the second item shows a badge. + + + +
+ + + Ctrl K + + } + /> + } + /> + + + } + /> +
+
+
+ ); +} + +export default Feat3814Route; diff --git a/apps/prs/react/src/styles.css b/apps/prs/react/src/styles.css index 90d4ee0072..4b7fecca73 100644 --- a/apps/prs/react/src/styles.css +++ b/apps/prs/react/src/styles.css @@ -1 +1,4 @@ /* 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"; diff --git a/apps/prs/web/src/app/App.svelte b/apps/prs/web/src/app/App.svelte index d26edda9d7..d7be253032 100644 --- a/apps/prs/web/src/app/App.svelte +++ b/apps/prs/web/src/app/App.svelte @@ -1,8 +1,10 @@ @@ -13,5 +15,6 @@ + diff --git a/apps/prs/web/src/routes/3605.svelte b/apps/prs/web/src/routes/3605.svelte new file mode 100644 index 0000000000..566ce8062c --- /dev/null +++ b/apps/prs/web/src/routes/3605.svelte @@ -0,0 +1,481 @@ + + + + Issue 3605 + + +
+ Issue 3605 + Use :focus-visible across interactive components + + For every section: Tab should show the focus ring with the correct gap/offset. + Click should not leave a lingering ring. Mouse-down (:active) + on buttons should still show the pressed/focused look. + + +
+ + +
+ 1. MicrositeHeader — a:focusa:focus-visible + Tab through the links inside the header. Click any link. + + Report a problem + + + Report a problem + +
+ +
+ + +
+ 2. Chip — .chip:focus.chip:focus-visible + V1 Chip (deprecated, still in scope per brief). +
+ + + +
+ + FilterChip V2 (production) + + Chip div is role="presentation"; the close goa-icon-button is + the focusable element. goa-icon-button already uses :focus-visible + (no change needed here). + +
+ + + +
+ + FilterChip V1 (fixed in this PR) + + Whole chip is tabindex="0" role="button". Removed class:focused + binding; outline now on .chip:focus-visible .delete-icon. + +
+ + + +
+
+ +
+ + +
+ 3. Plain link reset — use :focus-visible only + + Unstyled anchors pick up the global reset from assets/css/reset.css. + Dropped both :focus and :focus-within — on plain + <a> they both match on mouse click (HTML doesn't allow focusable + children inside <a>, so :focus-within has no real use + here). + + +
+ +
+ + +
+ 4. TextArea error state — .error:focus + V2 combined selector + + Tab into each error text area. Click into each. The :focus-within container + pattern should still apply on focus (correct). + + V1 error + + V2 error + +
+ +
+ + +
+ 5. Button — drop :focus from combined selectors + + Click and Tab each variant across V1 and V2. Watch for lingering rings after mouse-up. + + + V1 — default +
+ Primary + Secondary + Tertiary +
+ + V1 — destructive +
+ Primary destructive + Secondary destructive + Tertiary destructive +
+ + V1 — inverse (on dark bg) +
+ Primary inverse + Secondary inverse + Tertiary inverse +
+ + V2 — default +
+ Primary + Secondary + Tertiary +
+ + V2 — destructive +
+ Primary destructive + Secondary destructive + Tertiary destructive +
+ + V2 — inverse (on dark bg) +
+ Primary inverse + Secondary inverse + Tertiary inverse +
+
+ +
+ + +
+ 6. Checkbox — drop :has(:focus) duplicates from V1 + + V1 had 10 rules pairing :has(:focus-visible) with :has(:focus). + The :focus duplicate fired on mouse click. V2 already correct. + + + V1 — normal +
+ + + +
+ + V1 — error +
+ +
+ + V2 — normal +
+ + + +
+ + V2 — error +
+ +
+
+ +
+ + +
+ 7. Link — outer-container ring gated by JS modality check + + Ring sits on the outer container so it wraps icon + text together, matching pre-#3605 + visuals. Pure CSS couldn't carry keyboard-only semantics across the slot boundary + (:focus-within matches on click; :has(::slotted(a:focus-visible)) + isn't reliable), so the component listens for focusin on the slotted + anchor and checks .matches(':focus-visible') before flipping a class. + + + Plain links + + + Links with leading icons + + + Links with trailing icons + + + Links with both icons + +
+ +
+ + +
+ 8. Notification — ::slotted(a:focus):focus-visible + + 8 rules (V1 + V2 variants) styled slotted anchors on :focus. Now keyboard only. + + + V1 Notifications + + Info notification with a link inside. + + + Important notification with a link inside. + + + V2 Notifications + + Information high with a link inside. + + + Important high with a link inside. + + + Emergency high with a link inside. + +
+ +
+ + +
+ 9. Tooltip — .tooltip:focus .tooltip-text:focus-visible + + Previously mouse-clicking the tooltip trigger revealed the tooltip. Now hover for mouse, + keyboard focus for keyboard (standard tooltip behavior). + +
+ + Hover or Tab me + +
+
+ +
+ + +
+ 10. Details — summary:focus:focus-visible + + Previously clicking the summary left a hover-ish style. Now click just toggles open; + keyboard focus shows the focused look. + + + Content inside the details component. + +
+ +
+ + +
+ 11. DataGrid — realistic table usage + + Typical pattern: goa-data-grid wrapping a goa-table. Cells contain + badges, buttons, and text. Focus styling is JS-driven via + setFocusedStyle. Describe what looks wrong (mouse click leaving an outline? + UA default ring on a cell? ring jumping?). + + + + + + Name + Role + Status + Actions + + + + + Alice Johnson + Developer + + View + + + Bob Smith + Designer + + View + + + Carol White + Manager + + View + + + David Brown + Analyst + + View + + + + + + DataGrid around cards (layout mode) + + keyboardNav="layout". Each card is a row, cells include the checkbox, name, + badge, stat blocks, and menu button. + + + +
+ +
+ + Mike Zwei + + +
+ + Updated + Jun 30, 2022 at 2:30 PM + + + Email + mike.zwei@gmail.com + + + Program + Wee Wild Ones Curry + +
+
+ + Program ID + 74528567 + + + Service access + Claims Adjustments + +
+
+ + + + +
+
+ + +
+ +
+ + Emma Stroman + + +
+ + Updated + Nov 28, 2021 at 1:30 PM + + + Email + emma.stroman@gmail.com + + + Program + Fort McMurray + +
+
+ + Program ID + 74522643 + + + Service access + Claims Adjustments + +
+
+ + + + +
+
+
+
+
+ + diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 6599ce45c9..57d9c920d4 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -88,10 +88,6 @@ category: inputs-and-actions # determines nav section tags: [action, submit] relatedComponents: [button-group, icon-button] figmaUrl: https://www.figma.com/... -githubUrl: https://github.com/... -webComponentTag: goa-button -reactClassName: GoabButton -angularSelector: goab-button hidden: true # optional — hide from nav (used for subcomponents, deprecated, internal) subcomponent: true # optional — show API on parent component page --- @@ -219,6 +215,13 @@ export const buttonConfigurations: ComponentConfigurations = { This is a common source of errors when writing configuration code since all three are in the same file. +**Preview customization:** Two optional fields on `ComponentConfigurations` let you customize the sandbox preview without affecting the code snippet users see: + +- `previewStyle` — CSS applied to the preview container (e.g. background color, flex layout). Example: workspace components use a grey background with a content card to simulate the app layout. +- `previewWrapper` — HTML template that wraps the component code in the preview only. Use `{{slot}}` as the placeholder for the component code. The code snippet shown to users contains just the component code, not the wrapper. + +See `work-side-notification-panel.ts` or `work-side-menu.ts` for examples. + --- ## How to: common changes @@ -261,7 +264,6 @@ status: stable category: structure-and-navigation relatedComponents: - tab # <-- this is how the parent discovers the subcomponent -webComponentTag: goa-tabs --- ``` @@ -277,7 +279,6 @@ hidden: true # not shown in nav subcomponent: true # API appears on parent page relatedComponents: - tabs -webComponentTag: goa-tab --- ``` @@ -289,19 +290,11 @@ Result: the Tabs page shows "Tab Props", "Tab Slots" (and "Tab Events" if any ex 2. Add its slug to the parent's `relatedComponents` array 3. Ensure API data exists. If the Svelte component has its own directory (`libs/web-components/src/components/my-sub/`), the extraction script handles it automatically. If it's a nested file inside the parent's directory (like `WorkSideMenuGroup.svelte` inside `work-side-menu/`), you need to manually create the API JSON in `generated/component-apis/my-sub.json` -**Current subcomponent mappings:** - -| Parent | Subcomponents | -| -------------- | ----------------------------------------- | -| Header | App Header Menu | -| File uploader | File Upload Card | -| Footer | Footer Meta Section, Footer Nav Section | -| Form stepper | Form Step | -| Menu button | Menu Action | -| Radio | Radio Item | -| Side menu | Side Menu Group, Side Menu Heading | -| Tabs | Tab | -| Work Side Menu | Work Side Menu Group, Work Side Menu Item | +To see all current subcomponent mappings, search for `subcomponent: true` in the MDX files: + +```bash +grep -rl "subcomponent: true" docs/src/content/components/ +``` ### Hide a component from navigation diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 6523a7cc5a..9a7aa8fe73 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -5,6 +5,8 @@ import path from "node:path"; import react from "@astrojs/react"; import mdx from "@astrojs/mdx"; +import { buildAliasRedirects } from "./src/scripts/aliases-to-redirects.mjs"; + const __dirname = path.dirname(fileURLToPath(import.meta.url)); const workspaceRoot = path.resolve(__dirname, ".."); @@ -29,10 +31,25 @@ export default defineConfig({ "/examples/show-multiple-actions-in-a-compact-table", "/examples/communicate-a-future-service-outage": "/examples/notify-the-user-of-a-future-service-outage", + // workspace-product / public-form-product were stub entries that existed + // only to populate the size:product card on /examples/. The grid now + // synthesizes those cards directly from the productTypes collection, so + // these slugs no longer resolve. Redirect to the real overviews in case + // anything cached or bookmarked the old URLs from the PR preview. + "/examples/workspace-product": "/examples/workspace", + "/examples/public-form-product": "/examples/public-form", + // Old "give-{background,context}-..." slugs once redirected to the + // give-more-information-...-{a,b} variants. Those variants have since + // been folded into question-page, so route directly there to avoid + // a two-hop chain through the alias-derived redirects below. "/examples/give-background-information-before-asking-a-question": - "/examples/give-more-information-before-asking-a-question-a", + "/examples/question-page", "/examples/give-context-before-asking-a-long-answer-question": - "/examples/give-more-information-before-asking-a-question-b", + "/examples/question-page", + // Auto-derived redirects from `aliases` frontmatter on examples and + // productTypes entries. Single source of truth lives in MDX; adding + // an alias to an entry creates the redirect on the next build. + ...buildAliasRedirects(), }, build: { chunkSizeWarningLimit: 1000, diff --git a/docs/generated/component-apis/accordion.json b/docs/generated/component-apis/accordion.json index 132e50b852..913aae44d2 100644 --- a/docs/generated/component-apis/accordion.json +++ b/docs/generated/component-apis/accordion.json @@ -1,131 +1,366 @@ { "componentSlug": "accordion", "extractedFrom": "libs/web-components/src/components/accordion/Accordion.svelte", - "props": [ - { - "name": "open", - "type": "boolean", - "required": false, - "default": "false", - "description": "Sets the state of the accordion container open or closed." - }, - { - "name": "heading", - "type": "string", - "required": true, - "default": "", - "description": "Sets the heading text." - }, - { - "name": "secondarytext", - "type": "string", - "required": false, - "default": "", - "description": "Sets secondary text." - }, - { - "name": "headingSize", - "type": "\"small\" | \"medium\"", - "typeLabel": "GoabAccordionHeadingSize", - "values": [ - "small", - "medium" + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "Sets the heading text." + }, + { + "name": "headingSize", + "type": "GoabAccordionHeadingSize", + "required": false, + "default": "small", + "description": "Sets the heading size of the accordion container heading." + }, + { + "name": "headingType", + "type": "GoabAccordionHeadingType", + "required": false, + "default": "normal", + "description": "Sets the accordion style variant." + }, + { + "name": "iconPosition", + "type": "GoabAccordionIconPosition", + "required": false, + "default": "left", + "description": "Sets the position of the expand/collapse icon." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of the accordion." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the state of the accordion container open or closed." + }, + { + "name": "secondaryText", + "type": "string", + "required": false, + "default": null, + "description": "Sets secondary text displayed alongside the heading." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } ], - "required": false, - "default": "small", - "description": "Sets the heading size of the accordion container heading." - }, - { - "name": "id", - "type": "string", - "required": false, - "default": "", - "description": "Unique identifier for the accordion." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "none", - "description": "Sets the maximum width of the accordion." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "xs", - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "iconposition", - "type": "\"left\" | \"right\"", - "values": [ - "left", - "right" + "events": [ + { + "name": "onChange", + "type": "(open: boolean) => void", + "description": "Callback fired when the accordion is opened or closed. Receives the new open state as a boolean.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "left", - "description": "Sets the position of the expand/collapse icon." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "slots": [ + { + "name": "actions", + "type": "ReactNode", + "description": "Sets content rendered in the accordion heading, right-aligned before the expand/collapse icon.", + "required": false + }, + { + "name": "headingContent", + "type": "ReactNode", + "description": "Sets content rendered within the accordion heading, alongside the heading text.", + "required": false + } ] }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "angular": { + "props": [ + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "Sets the heading text." + }, + { + "name": "headingSize", + "type": "GoabAccordionHeadingSize", + "required": false, + "default": null, + "description": "Sets the heading size of the accordion container heading." + }, + { + "name": "headingType", + "type": "GoabAccordionHeadingType", + "required": false, + "default": null, + "description": "Sets the accordion style variant." + }, + { + "name": "iconPosition", + "type": "GoabAccordionIconPosition", + "required": false, + "default": null, + "description": "Sets the position of the expand/collapse icon." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the accordion." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the state of the accordion container open or closed." + }, + { + "name": "secondaryText", + "type": "string", + "required": false, + "default": null, + "description": "Sets secondary text." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [ + { + "name": "onChange", + "type": "(event: boolean) => void", + "description": "Emits when the accordion opens or closes. Emits the new open state as a boolean.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [ + { + "name": "actions", + "type": "TemplateRef", + "description": "Sets content rendered in the accordion heading, right-aligned before the expand/collapse icon.", + "required": false + }, + { + "name": "headingContent", + "type": "TemplateRef", + "description": "Sets content rendered within the accordion heading, alongside the heading text.", + "required": false + } ] - } - ], - "slots": [ - { - "name": "default", - "description": "" }, - { - "name": "headingcontent", - "description": "" + "webComponents": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": "", + "description": "Sets the heading text." + }, + { + "name": "heading-type", + "type": "\"normal\" | \"filled\"", + "typeLabel": "GoabAccordionHeadingType", + "values": [ + "normal", + "filled" + ], + "required": false, + "default": "normal", + "description": "Sets the accordion style variant. @default \"normal\"" + }, + { + "name": "headingsize", + "type": "\"small\" | \"medium\"", + "typeLabel": "GoabAccordionHeadingSize", + "values": [ + "small", + "medium" + ], + "required": false, + "default": "small", + "description": "Sets the heading size of the accordion container heading." + }, + { + "name": "iconposition", + "type": "\"left\" | \"right\"", + "typeLabel": "GoabAccordionIconPosition", + "values": [ + "left", + "right" + ], + "required": false, + "default": "left", + "description": "Sets the position of the expand/collapse icon." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "", + "description": "Unique identifier for the accordion." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of the accordion." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "xs", + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "Sets the state of the accordion container open or closed." + }, + { + "name": "secondarytext", + "type": "string", + "required": false, + "default": "", + "description": "Sets secondary text." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [ + { + "name": "_change", + "type": "CustomEvent<{ open: boolean }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "actions", + "description": "Sets content rendered in the accordion heading, right-aligned before the expand/collapse icon.", + "required": false + }, + { + "name": "headingcontent", + "description": "Sets content rendered within the accordion heading, alongside the heading text.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/app-header-menu.json b/docs/generated/component-apis/app-header-menu.json index 1e8fca8a88..def03aea4c 100644 --- a/docs/generated/component-apis/app-header-menu.json +++ b/docs/generated/component-apis/app-header-menu.json @@ -1,57 +1,124 @@ { "componentSlug": "app-header-menu", "extractedFrom": "libs/web-components/src/components/app-header-menu/AppHeaderMenu.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": true, - "default": null, - "description": "The menu heading text displayed as the dropdown trigger." - }, - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": true, - "default": null, - "description": "Icon displayed before the heading text." - }, - { - "name": "type", - "type": "\"primary\" | \"secondary\"", - "values": [ - "primary", - "secondary" + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The menu heading text displayed as the dropdown trigger." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the heading text." + }, + { + "name": "slotName", + "type": "string", + "required": false, + "default": null, + "description": "Slot name used to place this menu in the correct slot of the parent component." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } ], - "required": false, - "default": "primary", - "description": "The menu style variant. Primary uses bold text, secondary uses regular weight." + "events": [], + "slots": [] }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" + "angular": { + "props": [ + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "The menu heading text displayed as the dropdown trigger." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the heading text." + }, + { + "name": "slotName", + "type": "string", + "required": false, + "default": null, + "description": "Sets the slot name for the component." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } ], - "required": false, - "default": "1", - "description": "The header version this menu is used with." + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "rootEl", - "description": "Sets a data-testid attribute for automated testing." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The menu heading text displayed as the dropdown trigger." + }, + { + "name": "leadingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": true, + "default": null, + "description": "Icon displayed before the heading text." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "rootEl", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"primary\" | \"secondary\"", + "values": [ + "primary", + "secondary" + ], + "required": false, + "default": "primary", + "description": "The menu style variant. Primary uses bold text, secondary uses regular weight." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/app-header-navigation.json b/docs/generated/component-apis/app-header-navigation.json deleted file mode 100644 index 8d8a1251fc..0000000000 --- a/docs/generated/component-apis/app-header-navigation.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "componentSlug": "app-header-navigation", - "extractedFrom": "libs/web-components/src/components/app-header-navigation/AppHeaderNavigation.svelte", - "props": [ - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" - ], - "required": false, - "default": "1", - "description": "" - }, - { - "name": "windowWidth", - "type": "number", - "required": true, - "default": null, - "description": "" - }, - { - "name": "mobile", - "type": "boolean", - "required": false, - "default": "false", - "description": "" - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] -} \ No newline at end of file diff --git a/docs/generated/component-apis/app-header.json b/docs/generated/component-apis/app-header.json index 164f93138c..77e42d64f3 100644 --- a/docs/generated/component-apis/app-header.json +++ b/docs/generated/component-apis/app-header.json @@ -1,106 +1,258 @@ { "componentSlug": "app-header", "extractedFrom": "libs/web-components/src/components/app-header/AppHeader.svelte", - "props": [ - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" + "frameworks": { + "react": { + "props": [ + { + "name": "fullMenuBreakpoint", + "type": "number", + "required": false, + "default": null, + "description": "Sets the breakpoint in px for the full menu to display." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "Set the service name to display in the app header." + }, + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": null, + "description": "Maximum width of the content area." + }, + { + "name": "secondaryText", + "type": "string", + "required": false, + "default": null, + "description": "V2 only: Secondary text displayed under the service name." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": null, + "description": "Set the URL to link from the alberta.ca logo. A full url is required." + } ], - "required": false, - "default": "1", - "description": "" - }, - { - "name": "heading", - "type": "string", - "required": false, - "default": "", - "description": "Set the service name to display in the app header." - }, - { - "name": "secondarytext", - "type": "string", - "required": false, - "default": "", - "description": "V2 only: Secondary text displayed under the service name." - }, - { - "name": "url", - "type": "string", - "required": false, - "default": "", - "description": "Set the URL to link from the alberta.ca logo. A full url is required." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "maxcontentwidth", - "type": "any", - "required": false, - "default": "", - "description": "Maximum width of the content area." - }, - { - "name": "fullmenubreakpoint", - "type": "number", - "required": false, - "default": "TABLET_BP", - "description": "Sets the breakpoint in px for the full menu to display." - }, - { - "name": "hasmenuclickhandler", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, clicking the menu button dispatches _menuClick event instead of toggling the menu. Use for custom menu handling." - } - ], - "events": [ - { - "name": "onMenuClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "events": [ + { + "name": "onMenuClick", + "type": "() => void", + "description": "Callback fired when the menu button is clicked. When provided, clicking the menu button dispatches a custom event instead of toggling the menu.", + "frameworks": [ + "react" + ] + } + ], + "slots": [ + { + "name": "banner", + "description": "", + "required": false + }, + { + "name": "navigation", + "description": "", + "required": false + }, + { + "name": "phase", + "description": "", + "required": false + }, + { + "name": "utilities", + "description": "", + "required": false + } ] }, - { - "name": "_menuClick", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "angular": { + "props": [ + { + "name": "fullMenuBreakpoint", + "type": "number", + "required": false, + "default": null, + "description": "Sets the breakpoint in px for the full menu to display." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "Sets the service name to display in the app header." + }, + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": null, + "description": "Maximum width of the content area." + }, + { + "name": "secondaryText", + "type": "string", + "required": false, + "default": null, + "description": "V2 only: Secondary text displayed under the service name." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": null, + "description": "Sets the URL to link from the alberta.ca logo. A full url is required." + } + ], + "events": [ + { + "name": "onMenuClick", + "type": "() => void", + "description": "Emits when the menu button is clicked. Used for custom menu handling.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [ + { + "name": "banner", + "description": "", + "required": false + }, + { + "name": "navigation", + "description": "", + "required": false + }, + { + "name": "phase", + "description": "", + "required": false + }, + { + "name": "utilities", + "description": "", + "required": false + } ] - } - ], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "banner", - "description": "" - }, - { - "name": "phase", - "description": "" }, - { - "name": "utilities", - "description": "" - }, - { - "name": "navigation", - "description": "" + "webComponents": { + "props": [ + { + "name": "fullmenubreakpoint", + "type": "number", + "required": false, + "default": "TABLET_BP", + "description": "Sets the breakpoint in px for the full menu to display." + }, + { + "name": "hasmenuclickhandler", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, clicking the menu button dispatches _menuClick event instead of toggling the menu. Use for custom menu handling." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": "", + "description": "Set the service name to display in the app header." + }, + { + "name": "maxcontentwidth", + "type": "string", + "required": false, + "default": "", + "description": "Maximum width of the content area." + }, + { + "name": "secondarytext", + "type": "string", + "required": false, + "default": "", + "description": "V2 only: Secondary text displayed under the service name." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": "", + "description": "Set the URL to link from the alberta.ca logo. A full url is required." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_menuClick", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "banner", + "description": "", + "required": false + }, + { + "name": "navigation", + "description": "", + "required": false + }, + { + "name": "phase", + "description": "", + "required": false + }, + { + "name": "utilities", + "description": "", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/badge.json b/docs/generated/component-apis/badge.json index cc16d9e39b..ca313bc451 100644 --- a/docs/generated/component-apis/badge.json +++ b/docs/generated/component-apis/badge.json @@ -1,140 +1,334 @@ { "componentSlug": "badge", "extractedFrom": "libs/web-components/src/components/badge/Badge.svelte", - "props": [ - { - "name": "type", - "type": "\"information\" | \"important\" | \"emergency\" | \"success\" | \"dark\" | \"midtone\" | \"light\" | \"archived\" | \"aqua\" | \"black\" | \"blue\" | \"green\" | \"orange\" | \"pink\" | \"red\" | \"violet\" | \"white\" | \"yellow\" | \"aqua-light\" | \"black-light\" | \"blue-light\" | \"green-light\" | \"orange-light\" | \"pink-light\" | \"red-light\" | \"violet-light\" | \"yellow-light\" | \"sky\" | \"prairie\" | \"lilac\" | \"pasture\" | \"sunset\" | \"dawn\" | \"default\"", - "typeLabel": "GoabBadgeType", - "values": [ - "information", - "important", - "emergency", - "success", - "dark", - "midtone", - "light", - "archived", - "aqua", - "black", - "blue", - "green", - "orange", - "pink", - "red", - "violet", - "white", - "yellow", - "aqua-light", - "black-light", - "blue-light", - "green-light", - "orange-light", - "pink-light", - "red-light", - "violet-light", - "yellow-light", - "sky", - "prairie", - "lilac", - "pasture", - "sunset", - "dawn", - "default" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Accessible label for screen readers." + }, + { + "name": "content", + "type": "string", + "required": false, + "default": null, + "description": "Text label of the badge." + }, + { + "name": "emphasis", + "type": "GoabBadgeEmphasis", + "required": false, + "default": "strong", + "description": "Sets the visual emphasis. 'subtle' for less prominent, 'strong' for more emphasis." + }, + { + "name": "iconType", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon type to display in the badge." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "size", + "type": "GoabBadgeSize", + "required": false, + "default": "medium", + "description": "Sets the size of the badge." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabBadgeType", + "required": true, + "default": null, + "description": "Sets the context and colour of the badge." + } ], - "required": true, - "default": null, - "description": "Defines the context and colour of the badge." + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "content", - "type": "string", - "required": false, - "default": "", - "description": "Text label of the badge." - }, - { - "name": "icon", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated Use icontype instead. Includes an icon in the badge.", - "deprecated": true - }, - { - "name": "icontype", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon type to display in the badge." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Accessible label for screen readers." - }, - { - "name": "size", - "type": "\"medium\" | \"large\"", - "typeLabel": "GoabBadgeSize", - "values": [ - "medium", - "large" + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Sets the accessible label for screen readers." + }, + { + "name": "content", + "type": "string", + "required": false, + "default": null, + "description": "Sets the text label of the badge." + }, + { + "name": "emphasis", + "type": "GoabBadgeEmphasis", + "required": false, + "default": "strong", + "description": "Sets the visual emphasis. 'subtle' for less prominent, 'strong' for more emphasis." + }, + { + "name": "iconType", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Sets the icon type to display in the badge." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "size", + "type": "GoabBadgeSize", + "required": false, + "default": "medium", + "description": "Sets the size of the badge." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabBadgeType", + "required": false, + "default": null, + "description": "Sets the context and colour of the badge." + } ], - "required": false, - "default": "medium", - "description": "Sets the size of the badge." + "events": [], + "slots": [] }, - { - "name": "emphasis", - "type": "", - "required": false, - "default": "strong", - "description": "Sets the visual emphasis. 'subtle' for less prominent, 'strong' for more emphasis." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." + "webComponents": { + "props": [ + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Accessible label for screen readers." + }, + { + "name": "content", + "type": "string", + "required": false, + "default": "", + "description": "Text label of the badge." + }, + { + "name": "emphasis", + "type": "", + "required": false, + "default": "strong", + "description": "Sets the visual emphasis. 'subtle' for less prominent, 'strong' for more emphasis." + }, + { + "name": "icontype", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon type to display in the badge." + }, + { + "name": "justify-content", + "type": "\"center\" | \"flex-start\" | \"flex-end\" | \"space-between\" | \"\"", + "values": [ + "center", + "flex-start", + "flex-end", + "space-between" + ], + "required": false, + "default": "", + "description": "justify-content value for the badge container." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "min-width", + "type": "string", + "required": false, + "default": "", + "description": "min-width value for the badge container (e.g. \"20px\", \"var(--goa-space-m)\")." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "size", + "type": "\"medium\" | \"large\"", + "typeLabel": "GoabBadgeSize", + "values": [ + "medium", + "large" + ], + "required": false, + "default": "medium", + "description": "Sets the size of the badge." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"information\" | \"important\" | \"emergency\" | \"success\" | \"dark\" | \"midtone\" | \"light\" | \"archived\" | \"aqua\" | \"black\" | \"blue\" | \"green\" | \"orange\" | \"pink\" | \"red\" | \"violet\" | \"white\" | \"yellow\" | \"aqua-light\" | \"black-light\" | \"blue-light\" | \"green-light\" | \"orange-light\" | \"pink-light\" | \"red-light\" | \"violet-light\" | \"yellow-light\" | \"sky\" | \"prairie\" | \"lilac\" | \"pasture\" | \"sunset\" | \"dawn\" | \"default\"", + "typeLabel": "GoabBadgeType", + "values": [ + "information", + "important", + "emergency", + "success", + "dark", + "midtone", + "light", + "archived", + "aqua", + "black", + "blue", + "green", + "orange", + "pink", + "red", + "violet", + "white", + "yellow", + "aqua-light", + "black-light", + "blue-light", + "green-light", + "orange-light", + "pink-light", + "red-light", + "violet-light", + "yellow-light", + "sky", + "prairie", + "lilac", + "pasture", + "sunset", + "dawn", + "default" + ], + "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": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/block.json b/docs/generated/component-apis/block.json index 499c8e80e5..7de90b6ce5 100644 --- a/docs/generated/component-apis/block.json +++ b/docs/generated/component-apis/block.json @@ -1,105 +1,270 @@ { "componentSlug": "block", "extractedFrom": "libs/web-components/src/components/block/Block.svelte", - "props": [ - { - "name": "gap", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "m", - "description": "Spacing between items. Uses design system spacing tokens." - }, - { - "name": "direction", - "type": "\"row\" | \"column\"", - "values": [ - "row", - "column" + "frameworks": { + "react": { + "props": [ + { + "name": "alignment", + "type": "GoabBlockAlignment", + "required": false, + "default": "normal", + "description": "Primary axis alignment of child components." + }, + { + "name": "direction", + "type": "GoabBlockDirection", + "required": false, + "default": "row", + "description": "Stacking direction of child components." + }, + { + "name": "gap", + "type": "Spacing", + "required": false, + "default": "m", + "description": "Spacing between items. Uses design system spacing tokens." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the block container." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "minWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the minimum width of the block container." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets the width of the block container." + } ], - "required": false, - "default": "row", - "description": "Stacking direction of child components." + "events": [], + "slots": [] }, - { - "name": "alignment", - "type": "\"center\" | \"start\" | \"end\" | \"normal\"", - "values": [ - "center", - "start", - "end", - "normal" + "angular": { + "props": [ + { + "name": "alignment", + "type": "GoabBlockAlignment", + "required": false, + "default": null, + "description": "Sets the primary axis alignment of child components." + }, + { + "name": "direction", + "type": "GoabBlockDirection", + "required": false, + "default": null, + "description": "Sets the stacking direction of child components." + }, + { + "name": "gap", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the spacing between items. Uses design system spacing tokens." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the block container." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "minWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the minimum width of the block container." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets the width of the block container. Defaults to max-content." + } ], - "required": false, - "default": "normal", - "description": "Primary axis alignment of child components." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "minWidth", - "type": "string", - "required": false, - "default": "", - "description": "Sets the minimum width of the block container." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "", - "description": "Sets the maximum width of the block container." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "", - "description": "Sets the width of the block container. Defaults to max-content." + "events": [], + "slots": [] }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "alignment", + "type": "\"center\" | \"start\" | \"end\" | \"normal\"", + "values": [ + "center", + "start", + "end", + "normal" + ], + "required": false, + "default": "normal", + "description": "Primary axis alignment of child components." + }, + { + "name": "direction", + "type": "\"row\" | \"column\"", + "values": [ + "row", + "column" + ], + "required": false, + "default": "row", + "description": "Stacking direction of child components." + }, + { + "name": "gap", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "m", + "description": "Spacing between items. Uses design system spacing tokens." + }, + { + "name": "max-width", + "type": "string", + "required": false, + "default": "", + "description": "Sets the maximum width of the block container." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "min-width", + "type": "string", + "required": false, + "default": "", + "description": "Sets the minimum width of the block container." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "", + "description": "Sets the width of the block container. Defaults to max-content." + } + ], + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/button-group.json b/docs/generated/component-apis/button-group.json index 8014882d01..948bb7f955 100644 --- a/docs/generated/component-apis/button-group.json +++ b/docs/generated/component-apis/button-group.json @@ -1,77 +1,186 @@ { "componentSlug": "button-group", "extractedFrom": "libs/web-components/src/components/button-group/ButtonGroup.svelte", - "props": [ - { - "name": "alignment", - "type": "\"start\" | \"end\" | \"center\"", - "typeLabel": "GoabButtonGroupButtonAlignment", - "values": [ - "start", - "end", - "center" + "frameworks": { + "react": { + "props": [ + { + "name": "alignment", + "type": "GoabButtonGroupAlignment", + "required": true, + "default": null, + "description": "Positions the button group in the page layout." + }, + { + "name": "gap", + "type": "GoabButtonGroupGap", + "required": false, + "default": "relaxed", + "description": "Sets the spacing between buttons in the button group." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } ], - "required": false, - "default": "start", - "description": "Positions the button group in the page layout." + "events": [], + "slots": [] }, - { - "name": "gap", - "type": "\"relaxed\" | \"compact\"", - "typeLabel": "GoabButtonGroupGap", - "values": [ - "relaxed", - "compact" + "angular": { + "props": [ + { + "name": "alignment", + "type": "GoabButtonGroupAlignment", + "required": false, + "default": null, + "description": "Positions the button group in the page layout." + }, + { + "name": "gap", + "type": "GoabButtonGroupGap", + "required": false, + "default": null, + "description": "Sets the spacing between buttons in the button group." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } ], - "required": false, - "default": "relaxed", - "description": "Sets the spacing between buttons in the button group." + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "alignment", + "type": "\"start\" | \"end\" | \"center\"", + "typeLabel": "GoabButtonGroupButtonAlignment", + "values": [ + "start", + "end", + "center" + ], + "required": false, + "default": "start", + "description": "Positions the button group in the page layout." + }, + { + "name": "gap", + "type": "\"relaxed\" | \"compact\"", + "typeLabel": "GoabButtonGroupGap", + "values": [ + "relaxed", + "compact" + ], + "required": false, + "default": "relaxed", + "description": "Sets the spacing between buttons in the button group." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/button.json b/docs/generated/component-apis/button.json index 3ccbd384e7..3ee01667b2 100644 --- a/docs/generated/component-apis/button.json +++ b/docs/generated/component-apis/button.json @@ -1,141 +1,405 @@ { "componentSlug": "button", "extractedFrom": "libs/web-components/src/components/button/Button.svelte", - "props": [ - { - "name": "type", - "type": "\"primary\" | \"submit\" | \"secondary\" | \"tertiary\" | \"start\" | \"text\"", - "typeLabel": "GoabButtonType", - "values": [ - "primary", - "submit", - "secondary", - "tertiary", - "start", - "text" + "frameworks": { + "react": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": null, + "description": "Action identifier passed in click events for event delegation patterns." + }, + { + "name": "actionArg", + "type": "string", + "required": false, + "default": null, + "description": "Single argument value passed with the action in click events." + }, + { + "name": "actionArgs", + "type": "Record", + "required": false, + "default": null, + "description": "Multiple argument values passed with the action in click events." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, prevents user interaction and applies disabled styling." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the button text." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "size", + "type": "GoabButtonSize", + "required": false, + "default": "normal", + "description": "Controls the size of the button. Use \"compact\" for inline actions or space-constrained layouts." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "trailingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed after the button text." + }, + { + "name": "type", + "type": "GoabButtonType", + "required": false, + "default": "primary", + "description": "Sets the visual style of the button. Use \"primary\" for main actions, \"secondary\" for alternative actions, \"tertiary\" for low-emphasis actions, \"start\" for prominent call-to-action buttons, and \"text\" for text-only buttons." + }, + { + "name": "variant", + "type": "GoabButtonVariant", + "required": false, + "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": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets a custom width for the button (e.g., \"200px\" or \"100%\")." + } ], - "required": false, - "default": "primary", - "description": "Sets the visual style of the button. Use \"primary\" for main actions, \"secondary\" for alternative actions, \"tertiary\" for low-emphasis actions, \"start\" for prominent call-to-action buttons, and \"text\" for text-only buttons." - }, - { - "name": "size", - "type": "\"normal\" | \"compact\"", - "typeLabel": "GoabButtonSize", - "values": [ - "normal", - "compact" + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Callback fired when the button is clicked.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "normal", - "description": "Controls the size of the button. Use \"compact\" for inline actions or space-constrained layouts." + "slots": [] }, - { - "name": "variant", - "type": "\"normal\" | \"destructive\" | \"inverse\" | \"dark\"", - "typeLabel": "GoabButtonVariant", - "values": [ - "normal", - "destructive", - "inverse", - "dark" + "angular": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": null, + "description": "Action identifier passed in click events for event delegation patterns." + }, + { + "name": "actionArg", + "type": "string", + "required": false, + "default": null, + "description": "Single argument value passed with the action in click events." + }, + { + "name": "actionArgs", + "type": "Record", + "required": false, + "default": null, + "description": "Multiple argument values passed with the action in click events." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the disabled state. When true, prevents user interaction and applies disabled styling." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Sets the icon displayed before the button text." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "size", + "type": "GoabButtonSize", + "required": false, + "default": "normal", + "description": "Sets the size of the button. Use \"compact\" for inline actions or space-constrained layouts." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "trailingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed after the button text." + }, + { + "name": "type", + "type": "GoabButtonType", + "required": false, + "default": "primary", + "description": "Sets the visual style of the button. Use \"primary\" for main actions, \"secondary\" for alternative actions, \"tertiary\" for low-emphasis actions, \"start\" for prominent call-to-action buttons, and \"text\" for text-only buttons." + }, + { + "name": "variant", + "type": "GoabButtonVariant", + "required": false, + "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": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets a custom width for the button (e.g., \"200px\" or \"100%\")." + } ], - "required": false, - "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": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, prevents user interaction and applies disabled styling." - }, - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed before the button text." - }, - { - "name": "trailingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed after the button text." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "", - "description": "Sets a custom width for the button (e.g., \"200px\" or \"100%\")." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Sets the top margin using design system spacing tokens." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Sets the right margin using design system spacing tokens." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Sets the bottom margin using design system spacing tokens." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Sets the left margin using design system spacing tokens." - } - ], - "events": [ - { - "name": "onClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Emits when the button is clicked.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_click", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": "", + "description": "Action identifier passed in click events for event delegation patterns." + }, + { + "name": "action-arg", + "type": "string", + "required": false, + "default": "", + "description": "Single argument value passed with the action in click events." + }, + { + "name": "action-args", + "type": "Record", + "required": false, + "default": "{}", + "description": "Multiple argument values passed with the action in click events." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, prevents user interaction and applies disabled styling." + }, + { + "name": "leadingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the button text." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin using design system spacing tokens." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin using design system spacing tokens." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin using design system spacing tokens." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin using design system spacing tokens." + }, + { + "name": "size", + "type": "\"normal\" | \"compact\"", + "typeLabel": "GoabButtonSize", + "values": [ + "normal", + "compact" + ], + "required": false, + "default": "normal", + "description": "Controls the size of the button. Use \"compact\" for inline actions or space-constrained layouts." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "trailingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed after the button text." + }, + { + "name": "type", + "type": "\"primary\" | \"submit\" | \"secondary\" | \"tertiary\" | \"start\" | \"text\"", + "typeLabel": "GoabButtonType", + "values": [ + "primary", + "submit", + "secondary", + "tertiary", + "start", + "text" + ], + "required": false, + "default": "primary", + "description": "Sets the visual style of the button. Use \"primary\" for main actions, \"secondary\" for alternative actions, \"tertiary\" for low-emphasis actions, \"start\" for prominent call-to-action buttons, and \"text\" for text-only buttons." + }, + { + "name": "variant", + "type": "\"normal\" | \"destructive\" | \"inverse\" | \"dark\"", + "typeLabel": "GoabButtonVariant", + "values": [ + "normal", + "destructive", + "inverse", + "dark" + ], + "required": false, + "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", + "required": false, + "default": "", + "description": "Sets a custom width for the button (e.g., \"200px\" or \"100%\")." + } + ], + "events": [ + { + "name": "_click", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/calendar.json b/docs/generated/component-apis/calendar.json index 5a6285f88b..f19a0558bf 100644 --- a/docs/generated/component-apis/calendar.json +++ b/docs/generated/component-apis/calendar.json @@ -1,99 +1,274 @@ { "componentSlug": "calendar", "extractedFrom": "libs/web-components/src/components/calendar/Calendar.svelte", - "props": [ - { - "name": "name", - "type": "string", - "required": false, - "default": "", - "description": "Name identifier for the calendar, included in change events." + "frameworks": { + "react": { + "props": [ + { + "name": "max", + "type": "string", + "required": false, + "default": null, + "description": "The maximum selectable date in YYYY-MM-DD format. Defaults to 5 years in the future." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "min", + "type": "string", + "required": false, + "default": null, + "description": "The minimum selectable date in YYYY-MM-DD format. Defaults to 5 years in the past." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Name identifier for the calendar, included in change events." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "The currently selected date value in YYYY-MM-DD format." + } + ], + "events": [ + { + "name": "onChange", + "type": "(details: GoabCalendarOnChangeDetail) => void", + "description": "Callback fired when the selected date changes.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "value", - "type": "string", - "required": false, - "default": "", - "description": "The currently selected date value in YYYY-MM-DD format." + "angular": { + "props": [ + { + "name": "max", + "type": "Date | string | undefined", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "The maximum selectable date in YYYY-MM-DD format. Defaults to 5 years in the future." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "min", + "type": "Date | string | undefined", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "The minimum selectable date in YYYY-MM-DD format. Defaults to 5 years in the past." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Name identifier for the calendar, included in change events." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "Date | string", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "The currently selected date value in YYYY-MM-DD format." + } + ], + "events": [ + { + "name": "onChange", + "type": "(event: GoabCalendarOnChangeDetail) => void", + "description": "Emits when the selected date changes. Emits the selected date details as GoabCalendarOnChangeDetail.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "min", - "type": "string", - "required": false, - "default": "", - "description": "The minimum selectable date in YYYY-MM-DD format. Defaults to 5 years in the past." - }, - { - "name": "max", - "type": "string", - "required": false, - "default": "", - "description": "The maximum selectable date in YYYY-MM-DD format. Defaults to 5 years in the future." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "bordered", - "type": "boolean", - "required": false, - "default": "true", - "description": "Shows a border around the calendar. Set to false when embedding within another component." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "bordered", + "type": "boolean", + "required": false, + "default": "true", + "description": "Shows a border around the calendar. Set to false when embedding within another component." + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "", + "description": "The maximum selectable date in YYYY-MM-DD format. Defaults to 5 years in the future." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "", + "description": "The minimum selectable date in YYYY-MM-DD format. Defaults to 5 years in the past." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "", + "description": "Name identifier for the calendar, included in change events." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "", + "description": "The currently selected date value in YYYY-MM-DD format." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_change", + "type": "CustomEvent<{ type: string; name: string; value: unknown }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/callout.json b/docs/generated/component-apis/callout.json index bbb0415aca..9783888d0a 100644 --- a/docs/generated/component-apis/callout.json +++ b/docs/generated/component-apis/callout.json @@ -1,126 +1,317 @@ { "componentSlug": "callout", "extractedFrom": "libs/web-components/src/components/callout/Callout.svelte", - "props": [ - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "l", - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "size", - "type": "\"medium\" | \"large\"", - "typeLabel": "GoabCalloutSize", - "values": [ - "medium", - "large" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLive", + "type": "GoabCalloutAriaLive", + "required": false, + "default": "off", + "description": "Indicates how assistive technology should handle updates to the live region." + }, + { + "name": "emphasis", + "type": "GoabCalloutEmphasis", + "required": false, + "default": "medium", + "description": "Sets the visual prominence. 'high' for full background, 'medium' for subtle, 'low' for minimal." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "Callout heading text." + }, + { + "name": "iconTheme", + "type": "GoabCalloutIconTheme", + "required": false, + "default": "outline", + "description": "Sets the icon theme. 'outline' for stroked icons, 'filled' for solid icons." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the callout." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "size", + "type": "GoabCalloutSize", + "required": false, + "default": "large", + "description": "Sets the size of the callout. 'medium' has reduced padding and type size for compact areas." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabCalloutType", + "required": false, + "default": "information", + "description": "Sets the context and colour of the callout." + } ], - "required": false, - "default": "large", - "description": "Sets the size of the callout. 'medium' has reduced padding and type size for compact areas." + "events": [], + "slots": [] }, - { - "name": "type", - "type": "\"emergency\" | \"important\" | \"information\" | \"event\" | \"success\"", - "typeLabel": "GoabCalloutType", - "values": [ - "emergency", - "important", - "information", - "event", - "success" + "angular": { + "props": [ + { + "name": "ariaLive", + "type": "GoabCalloutAriaLive", + "required": false, + "default": "off", + "description": "Indicates how assistive technology should handle updates to the live region." + }, + { + "name": "emphasis", + "type": "GoabCalloutEmphasis", + "required": false, + "default": "medium", + "description": "Sets the visual prominence. 'high' for full background, 'medium' for subtle, 'low' for minimal." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": "", + "description": "Callout heading text." + }, + { + "name": "iconTheme", + "type": "GoabCalloutIconTheme", + "required": false, + "default": "outline", + "description": "Sets the icon theme. 'outline' for stroked icons, 'filled' for solid icons." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the callout." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "size", + "type": "GoabCalloutSize", + "required": false, + "default": "large", + "description": "Sets the size of the callout. 'medium' has reduced padding and type size for compact areas." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabCalloutType", + "required": false, + "default": "information", + "description": "Define the context and colour of the callout." + } ], - "required": true, - "default": null, - "description": "Define the context and colour of the callout." + "events": [], + "slots": [] }, - { - "name": "emphasis", - "type": "\"high\" | \"medium\" | \"low\"", - "typeLabel": "GoabCalloutEmphasisType", - "values": [ - "high", - "medium", - "low" + "webComponents": { + "props": [ + { + "name": "arialive", + "type": "\"off\" | \"assertive\" | \"polite\"", + "typeLabel": "GoabCalloutAriaLiveType", + "values": [ + "off", + "assertive", + "polite" + ], + "required": false, + "default": "off", + "description": "Indicates how assistive technology should handle updates to the live region." + }, + { + "name": "emphasis", + "type": "\"high\" | \"medium\" | \"low\"", + "typeLabel": "GoabCalloutEmphasisType", + "values": [ + "high", + "medium", + "low" + ], + "required": false, + "default": "medium", + "description": "Sets the visual prominence. 'high' for full background, 'medium' for subtle, 'low' for minimal." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": "", + "description": "Callout heading text." + }, + { + "name": "icontheme", + "type": "IconTheme", + "required": false, + "default": "outline", + "description": "Sets the icon theme. 'outline' for stroked icons, 'filled' for solid icons." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of the callout." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "l", + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "size", + "type": "\"medium\" | \"large\"", + "typeLabel": "GoabCalloutSize", + "values": [ + "medium", + "large" + ], + "required": false, + "default": "large", + "description": "Sets the size of the callout. 'medium' has reduced padding and type size for compact areas." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"emergency\" | \"important\" | \"information\" | \"event\" | \"success\"", + "typeLabel": "GoabCalloutType", + "values": [ + "emergency", + "important", + "information", + "event", + "success" + ], + "required": true, + "default": null, + "description": "Define the context and colour of the callout." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "typeLabel": "GoabCalloutVersionType", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } ], - "required": false, - "default": "medium", - "description": "Sets the visual prominence. 'high' for full background, 'medium' for subtle, 'low' for minimal." - }, - { - "name": "heading", - "type": "string", - "required": false, - "default": "", - "description": "Callout heading text." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "none", - "description": "Sets the maximum width of the callout." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "arialive", - "type": "\"off\" | \"assertive\" | \"polite\"", - "typeLabel": "GoabCalloutAriaLiveType", - "values": [ - "off", - "assertive", - "polite" - ], - "required": false, - "default": "off", - "description": "Indicates how assistive technology should handle updates to the live region." - }, - { - "name": "icontheme", - "type": "IconTheme", - "required": false, - "default": "outline", - "description": "Sets the icon theme. 'outline' for stroked icons, 'filled' for solid icons." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/card-actions.json b/docs/generated/component-apis/card-actions.json deleted file mode 100644 index 9efe3cc159..0000000000 --- a/docs/generated/component-apis/card-actions.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "componentSlug": "card-actions", - "extractedFrom": "libs/web-components/src/components/card-actions/CardActions.svelte", - "props": [], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] -} \ No newline at end of file diff --git a/docs/generated/component-apis/card-content.json b/docs/generated/component-apis/card-content.json deleted file mode 100644 index e757b05dbe..0000000000 --- a/docs/generated/component-apis/card-content.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "componentSlug": "card-content", - "extractedFrom": "libs/web-components/src/components/card-content/CardContent.svelte", - "props": [], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] -} \ No newline at end of file diff --git a/docs/generated/component-apis/card-group.json b/docs/generated/component-apis/card-group.json deleted file mode 100644 index 5ca2073983..0000000000 --- a/docs/generated/component-apis/card-group.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "componentSlug": "card-group", - "extractedFrom": "libs/web-components/src/components/card-group/CardGroup.svelte", - "props": [], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] -} \ No newline at end of file diff --git a/docs/generated/component-apis/card-image.json b/docs/generated/component-apis/card-image.json deleted file mode 100644 index 6569d15281..0000000000 --- a/docs/generated/component-apis/card-image.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "componentSlug": "card-image", - "extractedFrom": "libs/web-components/src/components/card-image/CardImage.svelte", - "props": [ - { - "name": "src", - "type": "string", - "required": true, - "default": null, - "description": "The URL of the image to display." - }, - { - "name": "height", - "type": "string", - "required": false, - "default": "100%", - "description": "Height of the image container. Accepts CSS values like \"200px\" or \"100%\"." - } - ], - "events": [], - "slots": [] -} \ No newline at end of file diff --git a/docs/generated/component-apis/card.json b/docs/generated/component-apis/card.json deleted file mode 100644 index bff87bf697..0000000000 --- a/docs/generated/component-apis/card.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "componentSlug": "card", - "extractedFrom": "libs/web-components/src/components/card/Card.svelte", - "props": [ - { - "name": "elevation", - "type": "number", - "required": false, - "default": "0", - "description": "Adds a shadow to the card. 0 shows a border, 1-3 increase shadow intensity." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "100%", - "description": "Sets the width of the card." - }, - { - "name": "height", - "type": "\"auto\" | \"max\"", - "values": [ - "auto", - "max" - ], - "required": false, - "default": "auto", - "description": "Sets the height behavior. 'auto' fits content, 'max' fills available height." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] -} \ No newline at end of file diff --git a/docs/generated/component-apis/checkbox-list.json b/docs/generated/component-apis/checkbox-list.json index 921345b50f..d8c7ea68a7 100644 --- a/docs/generated/component-apis/checkbox-list.json +++ b/docs/generated/component-apis/checkbox-list.json @@ -1,115 +1,312 @@ { "componentSlug": "checkbox-list", "extractedFrom": "libs/web-components/src/components/checkbox-list/CheckboxList.svelte", - "props": [ - { - "name": "name", - "type": "string", - "required": true, - "default": null, - "description": "The name for the checkbox list group. Used as group identifier in change events." - }, - { - "name": "value", - "type": "string[]", - "required": false, - "default": "[]", - "description": "Array of currently selected checkbox values." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disables all checkboxes in the list." - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Shows an error state on all checkboxes in the list." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "none", - "description": "Sets the maximum width of the checkbox list container." - }, - { - "name": "size", - "type": "\"default\" | \"compact\"", - "values": [ - "default", - "compact" + "frameworks": { + "react": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disables all checkboxes in the list." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows an error state on all checkboxes in the list." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the checkbox list container." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "The name for the checkbox list group. Used as group identifier in change events." + }, + { + "name": "size", + "type": "\"default\" | \"compact\"", + "values": [ + "default", + "compact" + ], + "required": false, + "default": "default", + "description": "Sets the size of the checkbox list. 'compact' reduces spacing between items." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string[]", + "required": false, + "default": null, + "description": "Array of currently selected checkbox values." + } ], - "required": false, - "default": "default", - "description": "Sets the size of the checkbox list. 'compact' reduces spacing between items." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." + "events": [ + { + "name": "onChange", + "type": "(detail: GoabCheckboxListOnChangeDetail) => void", + "description": "Callback fired when the selected values change.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the disabled state for the control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the error state for the control." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute of the underlying web component." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the checkbox list container." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "The name for the checkbox list group. Used as group identifier in change events." + }, + { + "name": "size", + "type": "GoabCheckboxSize", + "required": false, + "default": "default", + "description": "Sets the size of the checkbox list. 'compact' reduces spacing between items." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string[]", + "required": false, + "default": null, + "description": "Array of currently selected checkbox values." + } + ], + "events": [ + { + "name": "onChange", + "type": "(event: GoabCheckboxListOnChangeDetail) => void", + "description": "Emits when a checkbox selection changes. Emits the change detail including name, value array, and event.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disables all checkboxes in the list." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Shows an error state on all checkboxes in the list." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of the checkbox list container." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "The name for the checkbox list group. Used as group identifier in change events." + }, + { + "name": "size", + "type": "\"default\" | \"compact\"", + "values": [ + "default", + "compact" + ], + "required": false, + "default": "default", + "description": "Sets the size of the checkbox list. 'compact' reduces spacing between items." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string[]", + "required": false, + "default": "[]", + "description": "Array of currently selected checkbox values." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_change", + "type": "CustomEvent<{ name: string; value: string[]; labels: string[] }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/checkbox.json b/docs/generated/component-apis/checkbox.json index 5e2809db8e..a91f7e1967 100644 --- a/docs/generated/component-apis/checkbox.json +++ b/docs/generated/component-apis/checkbox.json @@ -1,181 +1,496 @@ { "componentSlug": "checkbox", "extractedFrom": "libs/web-components/src/components/checkbox/Checkbox.svelte", - "props": [ - { - "name": "name", - "type": "string", - "required": true, - "default": null, - "description": "Unique name to identify the checkbox." - }, - { - "name": "checked", - "type": "boolean", - "required": false, - "default": "false", - "description": "Marks the checkbox item as selected." - }, - { - "name": "indeterminate", - "type": "boolean", - "required": false, - "default": "false", - "description": "Shows a mixed/partial selection state. Used for 'Select All' checkboxes when some items are selected." - }, - { - "name": "text", - "type": "string", - "required": false, - "default": "", - "description": "Label shown beside the checkbox." - }, - { - "name": "value", - "type": "string", - "required": false, - "default": "", - "description": "The value binding." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disable this control. It will not receive focus or events." - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Shows an error on the checkbox item." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Defines how the text will be translated for the screen reader. If not specified it will fall back to the name." - }, - { - "name": "description", - "type": "string", - "required": false, - "default": "", - "description": "Additional description text displayed below the checkbox label." - }, - { - "name": "revealarialabel", - "type": "string", - "required": false, - "default": "", - "description": "Text announced by screen readers when the reveal slot content is displayed." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "none", - "description": "Sets the maximum width of the checkbox." - }, - { - "name": "size", - "type": "\"default\" | \"compact\"", - "values": [ - "default", - "compact" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the text will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": null, + "description": "Marks the checkbox item as selected." + }, + { + "name": "description", + "type": "string | React.ReactNode", + "values": [ + "string", + "React.ReactNode" + ], + "required": false, + "default": null, + "description": "Additional description text displayed below the checkbox label." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disable this control. It will not receive focus or events." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows an error on the checkbox item." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets a unique id for the checkbox element." + }, + { + "name": "indeterminate", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows a mixed/partial selection state. Used for 'Select All' checkboxes when some items are selected." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the checkbox." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "Unique name to identify the checkbox." + }, + { + "name": "revealAriaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Text announced by screen readers when the reveal slot content is displayed." + }, + { + "name": "size", + "type": "GoabCheckboxSize", + "required": false, + "default": "default", + "description": "Sets the size of the checkbox. 'compact' reduces spacing for dense layouts." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": false, + "default": null, + "description": "Label shown beside the checkbox." + }, + { + "name": "value", + "type": "string | number | boolean", + "values": [ + "string", + "number", + "boolean" + ], + "required": false, + "default": null, + "description": "The value binding." + } ], - "required": false, - "default": "default", - "description": "Sets the size of the checkbox. 'compact' reduces spacing for dense layouts." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "events": [ + { + "name": "onChange", + "type": "(detail: GoabCheckboxOnChangeDetail) => void", + "description": "Callback fired when the checkbox selection changes.", + "frameworks": [ + "react" + ] + } + ], + "slots": [ + { + "name": "description", + "type": "ReactNode", + "description": "Additional description text displayed below the checkbox label.", + "required": false + }, + { + "name": "reveal", + "type": "ReactNode", + "description": "Content revealed when the checkbox is checked.", + "required": false + } ] }, - { - "name": "onRevealChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the text will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": null, + "description": "Marks the checkbox item as selected." + }, + { + "name": "description", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "Sets additional description content displayed below the checkbox label. Accepts plain text or a template." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the disabled state for the control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the error state for the control." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute of the underlying web component." + }, + { + "name": "indeterminate", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows a mixed/partial selection state. Used for 'Select All' checkboxes when some items are selected." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the checkbox." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Sets the name of the checkbox input for form submission." + }, + { + "name": "revealArialLabel", + "type": "string", + "required": false, + "default": null, + "description": "Text announced by screen readers when the reveal slot content is displayed." + }, + { + "name": "size", + "type": "GoabCheckboxSize", + "required": false, + "default": "default", + "description": "Sets the size of the checkbox. 'compact' reduces spacing for dense layouts." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": false, + "default": null, + "description": "Label shown beside the checkbox." + }, + { + "name": "value", + "type": "string | number | boolean | null", + "values": [ + "string", + "number", + "boolean" + ], + "required": false, + "default": null, + "description": "The value binding." + } + ], + "events": [ + { + "name": "onChange", + "type": "(event: GoabCheckboxOnChangeDetail) => void", + "description": "Emits when the checkbox value changes. Emits the new checkbox state as a GoabCheckboxOnChangeDetail object.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [ + { + "name": "description", + "type": "TemplateRef", + "description": "Additional description text displayed below the checkbox label.", + "required": false + }, + { + "name": "reveal", + "type": "TemplateRef", + "description": "Content revealed when the checkbox is checked.", + "required": false + } ] }, - { - "name": "_revealChange", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "webComponents": { + "props": [ + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Defines how the text will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "checked", + "type": "boolean", + "required": false, + "default": "false", + "description": "Marks the checkbox item as selected." + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "", + "description": "Additional description text displayed below the checkbox label." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disable this control. It will not receive focus or events." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Shows an error on the checkbox item." + }, + { + "name": "indeterminate", + "type": "boolean", + "required": false, + "default": "false", + "description": "Shows a mixed/partial selection state. Used for 'Select All' checkboxes when some items are selected." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of the checkbox." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "Unique name to identify the checkbox." + }, + { + "name": "revealarialabel", + "type": "string", + "required": false, + "default": "", + "description": "Text announced by screen readers when the reveal slot content is displayed." + }, + { + "name": "size", + "type": "\"default\" | \"compact\"", + "values": [ + "default", + "compact" + ], + "required": false, + "default": "default", + "description": "Sets the size of the checkbox. 'compact' reduces spacing for dense layouts." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": false, + "default": "", + "description": "Label shown beside the checkbox." + }, + { + "name": "value", + "type": "string", + "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": [ + { + "name": "_change", + "type": "CustomEvent<{ name: string; checked: boolean; value: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "description", + "description": "Additional description text displayed below the checkbox label.", + "required": false + }, + { + "name": "reveal", + "description": "Content revealed when the checkbox is checked.", + "required": false + } ] } - ], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "description", - "description": "" - }, - { - "name": "reveal", - "description": "" - } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/chip.json b/docs/generated/component-apis/chip.json index ed45fe3d41..0ed5102ea7 100644 --- a/docs/generated/component-apis/chip.json +++ b/docs/generated/component-apis/chip.json @@ -1,114 +1,146 @@ { "componentSlug": "chip", "extractedFrom": "libs/web-components/src/components/chip/Chip.svelte", - "props": [ - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." + "frameworks": { + "react": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + } + ], + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Callback fired when the chip is clicked or deleted.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." + "angular": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Emits when the chip is clicked.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "@deprecated Use GoAFilterChip instead. Icon displayed at the start of the chip.", - "deprecated": true - }, - { - "name": "icontheme", - "type": "IconTheme", - "required": false, - "default": "outline", - "description": "@deprecated Use GoAFilterChip instead. The icon theme - outline or filled.", - "deprecated": true - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "@deprecated Use GoAFilterChip instead. Shows an error state on the chip.", - "deprecated": true - }, - { - "name": "deletable", - "type": "boolean", - "required": false, - "default": "false", - "description": "@deprecated Use GoAFilterChip instead. When true, shows a delete icon and makes chip clickable.", - "deprecated": true - }, - { - "name": "content", - "type": "string", - "required": true, - "default": null, - "description": "@deprecated Use GoAFilterChip instead. The text content displayed in the chip.", - "deprecated": true - }, - { - "name": "variant", - "type": "\"filter\"", - "required": true, - "default": null, - "description": "@deprecated Use GoAFilterChip instead. The chip variant style.", - "deprecated": true - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated Use GoAFilterChip instead. Sets a data-testid attribute for automated testing.", - "deprecated": true - } - ], - "events": [ - { - "name": "onClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_click", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + } + ], + "events": [ + { + "name": "_click", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/circular-progress.json b/docs/generated/component-apis/circular-progress.json index 15cdda806d..9e1626e5fe 100644 --- a/docs/generated/component-apis/circular-progress.json +++ b/docs/generated/component-apis/circular-progress.json @@ -1,60 +1,160 @@ { "componentSlug": "circular-progress", "extractedFrom": "libs/web-components/src/components/circular-progress/CircularProgress.svelte", - "props": [ - { - "name": "variant", - "type": "\"fullscreen\" | \"inline\"", - "typeLabel": "GoabCircularProgressVariant", - "values": [ - "fullscreen", - "inline" + "frameworks": { + "react": { + "props": [ + { + "name": "message", + "type": "string", + "required": false, + "default": null, + "description": "Loading message displayed below the progress indicator." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": null, + "description": "Sets the progress value (0–100). When omitted, an infinite spinner is shown." + }, + { + "name": "size", + "type": "GoabCircularProgressSize", + "required": false, + "default": "large", + "description": "Sets the size of the progress indicator." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabCircularProgressVariant", + "required": false, + "default": "inline", + "description": "Controls the display mode. 'fullscreen' stretches across the full screen; 'inline' is used within content." + }, + { + "name": "visible", + "type": "boolean", + "required": false, + "default": null, + "description": "Controls visibility of the progress indicator, allowing a fade transition to be applied." + } ], - "required": false, - "default": "inline", - "description": "Stretch across the full screen or use it inline" + "events": [], + "slots": [] }, - { - "name": "size", - "type": "\"small\" | \"large\"", - "typeLabel": "GoabCircularProgressSize", - "values": [ - "small", - "large" + "angular": { + "props": [ + { + "name": "message", + "type": "string", + "required": false, + "default": null, + "description": "Loading message displayed under the progress indicator." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": null, + "description": "Set the progress value. Setting this value will change the type from infinite to progress." + }, + { + "name": "size", + "type": "GoabCircularProgressSize", + "required": false, + "default": null, + "description": "Size of the progress indicator." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabCircularProgressVariant", + "required": false, + "default": null, + "description": "Stretch across the full screen or use it inline." + }, + { + "name": "visible", + "type": "boolean", + "required": false, + "default": null, + "description": "Show/hide the page loader. This allows for fade transition to be applied in each transition." + } ], - "required": false, - "default": "large", - "description": "Size of the progress indicator" + "events": [], + "slots": [] }, - { - "name": "message", - "type": "string", - "required": false, - "default": "", - "description": "Loading message displayed under the progress indicator" - }, - { - "name": "progress", - "type": "number", - "required": false, - "default": "-1", - "description": "Set the progress value. Setting this value will change the type from infinite to progress" - }, - { - "name": "visible", - "type": "boolean", - "required": false, - "default": "false", - "description": "Show/hide the page loader. This allows for fade transition to be applied in each transition." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "webComponents": { + "props": [ + { + "name": "message", + "type": "string", + "required": false, + "default": "", + "description": "Loading message displayed under the progress indicator" + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": "-1", + "description": "Set the progress value. Setting this value will change the type from infinite to progress" + }, + { + "name": "size", + "type": "\"small\" | \"large\"", + "typeLabel": "GoabCircularProgressSize", + "values": [ + "small", + "large" + ], + "required": false, + "default": "large", + "description": "Size of the progress indicator" + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "\"fullscreen\" | \"inline\"", + "typeLabel": "GoabCircularProgressVariant", + "values": [ + "fullscreen", + "inline" + ], + "required": false, + "default": "inline", + "description": "Stretch across the full screen or use it inline" + }, + { + "name": "visible", + "type": "boolean", + "required": false, + "default": "false", + "description": "Show/hide the page loader. This allows for fade transition to be applied in each transition." + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/container.json b/docs/generated/component-apis/container.json index 6b8be6c90d..528dc0cf68 100644 --- a/docs/generated/component-apis/container.json +++ b/docs/generated/component-apis/container.json @@ -1,130 +1,342 @@ { "componentSlug": "container", "extractedFrom": "libs/web-components/src/components/container/Container.svelte", - "props": [ - { - "name": "type", - "type": "\"interactive\" | \"info\" | \"error\" | \"success\" | \"important\" | \"non-interactive\"", - "typeLabel": "GoabContainerType", - "values": [ - "interactive", - "info", - "error", - "success", - "important", - "non-interactive" + "frameworks": { + "react": { + "props": [ + { + "name": "accent", + "type": "GoabContainerAccent", + "required": false, + "default": "filled", + "description": "Sets the style of accent on the container." + }, + { + "name": "maxHeight", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum height of the container." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the container." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "minHeight", + "type": "string", + "required": false, + "default": null, + "description": "Sets the minimum height of the container." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "padding", + "type": "GoabContainerPadding", + "required": false, + "default": "relaxed", + "description": "Sets the amount of white space in the container." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabContainerType", + "required": false, + "default": "interactive", + "description": "Sets the container and accent bar styling." + }, + { + "name": "width", + "type": "GoabContainerWidth", + "required": false, + "default": "full", + "description": "Sets the width of the container." + } ], - "required": false, - "default": "interactive", - "description": "Sets the container and accent bar styling." + "events": [], + "slots": [ + { + "name": "actions", + "type": "ReactNode", + "description": "Content rendered in the container's actions area, typically buttons or controls.", + "required": false + }, + { + "name": "title", + "type": "ReactNode", + "description": "Content rendered in the container's title/heading area.", + "required": false + } + ] }, - { - "name": "accent", - "type": "\"thick\" | \"thin\" | \"filled\"", - "typeLabel": "GoabContainerAccent", - "values": [ - "thick", - "thin", - "filled" + "angular": { + "props": [ + { + "name": "accent", + "type": "GoabContainerAccent", + "required": false, + "default": "filled", + "description": "Sets the style of accent on the container." + }, + { + "name": "maxHeight", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum height of the container." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the container." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "minHeight", + "type": "string", + "required": false, + "default": null, + "description": "Sets the minimum height of the container." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "padding", + "type": "GoabContainerPadding", + "required": false, + "default": "relaxed", + "description": "Sets the amount of white space in the container." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabContainerType", + "required": false, + "default": "interactive", + "description": "Sets the container and accent bar styling." + }, + { + "name": "width", + "type": "GoabContainerWidth", + "required": false, + "default": "full", + "description": "Sets the width of the container." + } ], - "required": false, - "default": "filled", - "description": "Sets the style of accent on the container." + "events": [], + "slots": [ + { + "name": "actions", + "type": "TemplateRef", + "description": "Content rendered in the container's actions area, typically buttons or controls.", + "required": false + }, + { + "name": "title", + "type": "TemplateRef", + "description": "Content rendered in the container's title/heading area.", + "required": false + } + ] }, - { - "name": "padding", - "type": "\"relaxed\" | \"compact\"", - "typeLabel": "GoabContainerPadding", - "values": [ - "relaxed", - "compact" + "webComponents": { + "props": [ + { + "name": "accent", + "type": "\"thick\" | \"thin\" | \"filled\"", + "typeLabel": "GoabContainerAccent", + "values": [ + "thick", + "thin", + "filled" + ], + "required": false, + "default": "filled", + "description": "Sets the style of accent on the container." + }, + { + "name": "maxheight", + "type": "string", + "required": false, + "default": "", + "description": "Sets the maximum height of the container." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of the container." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "m", + "description": "Bottom margin." + }, + { + "name": "minheight", + "type": "string", + "required": false, + "default": "", + "description": "Sets the minimum height of the container." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "padding", + "type": "\"relaxed\" | \"compact\"", + "typeLabel": "GoabContainerPadding", + "values": [ + "relaxed", + "compact" + ], + "required": false, + "default": "relaxed", + "description": "Sets the amount of white space in the container." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"interactive\" | \"info\" | \"error\" | \"success\" | \"important\" | \"non-interactive\"", + "typeLabel": "GoabContainerType", + "values": [ + "interactive", + "info", + "error", + "success", + "important", + "non-interactive" + ], + "required": false, + "default": "interactive", + "description": "Sets the container and accent bar styling." + }, + { + "name": "width", + "type": "\"full\" | \"content\"", + "typeLabel": "GoabContainerWidth", + "values": [ + "full", + "content" + ], + "required": false, + "default": "full", + "description": "Sets the width of the container." + } ], - "required": false, - "default": "relaxed", - "description": "Sets the amount of white space in the container." - }, - { - "name": "width", - "type": "\"full\" | \"content\"", - "typeLabel": "GoabContainerWidth", - "values": [ - "full", - "content" - ], - "required": false, - "default": "full", - "description": "Sets the width of the container." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "none", - "description": "Sets the maximum width of the container." - }, - { - "name": "minHeight", - "type": "any", - "required": false, - "default": "", - "description": "Sets the minimum height of the container." - }, - { - "name": "maxHeight", - "type": "any", - "required": false, - "default": "", - "description": "Sets the maximum height of the container." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "m", - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [], - "slots": [ - { - "name": "title", - "description": "" - }, - { - "name": "actions", - "description": "" + "events": [], + "slots": [ + { + "name": "actions", + "description": "Content rendered in the container's actions area, typically buttons or controls.", + "required": false + }, + { + "name": "title", + "description": "Content rendered in the container's title/heading area.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/data-grid.json b/docs/generated/component-apis/data-grid.json index bf52986bea..cf8730225b 100644 --- a/docs/generated/component-apis/data-grid.json +++ b/docs/generated/component-apis/data-grid.json @@ -1,46 +1,123 @@ { "componentSlug": "data-grid", "extractedFrom": "libs/web-components/src/components/data-grid/DataGrid.svelte", - "props": [ - { - "name": "keyboardIconVisibility", - "type": "\"visible\" | \"hidden\"", - "values": [ - "visible", - "hidden" + "frameworks": { + "react": { + "props": [ + { + "name": "keyboardIconPosition", + "type": "\"left\" | \"right\"", + "values": [ + "left", + "right" + ], + "required": false, + "default": "left", + "description": "Position of the keyboard navigation indicator icon." + }, + { + "name": "keyboardIconVisibility", + "type": "\"visible\" | \"hidden\"", + "values": [ + "visible", + "hidden" + ], + "required": false, + "default": "visible", + "description": "Controls visibility of the keyboard navigation indicator icon." + }, + { + "name": "keyboardNav", + "type": "\"layout\" | \"table\"", + "values": [ + "layout", + "table" + ], + "required": true, + "default": null, + "description": "Navigation mode. 'table' navigates like a table (up/down between rows), 'layout' allows wrapping between rows with left/right arrows." + } ], - "required": false, - "default": "visible", - "description": "Controls visibility of the keyboard navigation indicator icon. Use \"visible\" to show or \"hidden\" to hide." + "events": [], + "slots": [] }, - { - "name": "keyboardNav", - "type": "\"layout\" | \"table\"", - "values": [ - "layout", - "table" + "angular": { + "props": [ + { + "name": "keyboardIconPosition", + "type": "\"left\" | \"right\"", + "values": [ + "left", + "right" + ], + "required": false, + "default": "left", + "description": "Position of the keyboard navigation indicator icon." + }, + { + "name": "keyboardIconVisibility", + "type": "\"visible\" | \"hidden\"", + "values": [ + "visible", + "hidden" + ], + "required": false, + "default": "visible", + "description": "Controls visibility of the keyboard navigation indicator icon. Use \"visible\" to show or \"hidden\" to hide." + }, + { + "name": "keyboardNav", + "type": "\"layout\" | \"table\"", + "values": [ + "layout", + "table" + ], + "required": true, + "default": null, + "description": "Navigation mode. \"table\" navigates like a table (up/down between rows), \"layout\" allows wrapping between rows with left/right arrows." + } ], - "required": false, - "default": "table", - "description": "Navigation mode. \"table\" navigates like a table (up/down between rows), \"layout\" allows wrapping between rows with left/right arrows." + "events": [], + "slots": [] }, - { - "name": "keyboardIconPosition", - "type": "\"left\" | \"right\"", - "values": [ - "left", - "right" + "webComponents": { + "props": [ + { + "name": "keyboard-icon-position", + "type": "\"left\" | \"right\"", + "values": [ + "left", + "right" + ], + "required": false, + "default": "left", + "description": "Position of the keyboard navigation indicator icon." + }, + { + "name": "keyboard-icon-visibility", + "type": "\"visible\" | \"hidden\"", + "values": [ + "visible", + "hidden" + ], + "required": false, + "default": "visible", + "description": "Controls visibility of the keyboard navigation indicator icon. Use \"visible\" to show or \"hidden\" to hide." + }, + { + "name": "keyboard-nav", + "type": "\"layout\" | \"table\"", + "values": [ + "layout", + "table" + ], + "required": false, + "default": "table", + "description": "Navigation mode. \"table\" navigates like a table (up/down between rows), \"layout\" allows wrapping between rows with left/right arrows." + } ], - "required": false, - "default": "left", - "description": "Position of the keyboard navigation indicator icon." + "events": [], + "slots": [] } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/date-picker.json b/docs/generated/component-apis/date-picker.json index 536705b8ef..c11466d696 100644 --- a/docs/generated/component-apis/date-picker.json +++ b/docs/generated/component-apis/date-picker.json @@ -1,143 +1,385 @@ { "componentSlug": "date-picker", "extractedFrom": "libs/web-components/src/components/date-picker/DatePicker.svelte", - "props": [ - { - "name": "type", - "type": "\"calendar\" | \"input\"", - "values": [ - "calendar", - "input" + "frameworks": { + "react": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disables the date picker." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the input to an error state." + }, + { + "name": "max", + "type": "Date | string", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "Maximum date value allowed." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "min", + "type": "Date | string", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "Minimum date value allowed." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Name of the date field." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabDatePickerInputType", + "required": false, + "default": "calendar", + "description": "Sets the date picker type. 'calendar' shows a calendar popup, 'input' shows just a date input." + }, + { + "name": "value", + "type": "Date | string | undefined", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "Value of the calendar date, as a Date object or an ISO date string (yyyy-mm-dd)." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets the width of the date picker input." + } ], - "required": false, - "default": "calendar", - "description": "Sets the date picker type. 'calendar' shows a calendar popup, 'input' shows just a date input." - }, - { - "name": "name", - "type": "string", - "required": false, - "default": "", - "description": "Name of the date field." - }, - { - "name": "value", - "type": "string", - "required": false, - "default": "", - "description": "Value of the calendar date." - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Sets the input to an error state." - }, - { - "name": "min", - "type": "string", - "required": false, - "default": "", - "description": "Minimum date value allowed." - }, - { - "name": "max", - "type": "string", - "required": false, - "default": "", - "description": "Maximum date value allowed." - }, - { - "name": "relative", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated This property has no effect and will be removed in a future version.", - "deprecated": true - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disables the date picker." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "", - "description": "Sets the width of the date picker input." - }, - { - "name": "size", - "type": "\"default\" | \"compact\"", - "values": [ - "default", - "compact" + "events": [ + { + "name": "onChange", + "type": "(detail: GoabDatePickerOnChangeDetail) => void", + "description": "Callback fired when the selected date changes.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "default", - "description": "Sets the size of the date picker. 'compact' reduces height for dense layouts." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." + "slots": [] }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the disabled state for the control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the error state for the control." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute of the underlying web component." + }, + { + "name": "max", + "type": "Date | string", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "Sets the maximum date value allowed." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "min", + "type": "Date | string", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "Sets the minimum date value allowed." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Sets the name of the date field." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabDatePickerInputType", + "required": false, + "default": "calendar", + "description": "Sets the date picker type. 'calendar' shows a calendar popup, 'input' shows just a date input." + }, + { + "name": "value", + "type": "Date | string | null | undefined", + "values": [ + "Date", + "string" + ], + "required": false, + "default": null, + "description": "Sets the value of the calendar date." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets the width of the date picker input." + } + ], + "events": [ + { + "name": "onChange", + "type": "(event: GoabDatePickerOnChangeDetail) => void", + "description": "Emits when the selected date changes. Emits the date picker change detail including name and value.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disables the date picker." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Sets the input to an error state." + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "", + "description": "Maximum date value allowed." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "", + "description": "Minimum date value allowed." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "", + "description": "Name of the date field." + }, + { + "name": "size", + "type": "\"default\" | \"compact\"", + "values": [ + "default", + "compact" + ], + "required": false, + "default": "default", + "description": "Sets the size of the date picker. 'compact' reduces height for dense layouts." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"calendar\" | \"input\"", + "values": [ + "calendar", + "input" + ], + "required": false, + "default": "calendar", + "description": "Sets the date picker type. 'calendar' shows a calendar popup, 'input' shows just a date input." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "", + "description": "Value of the calendar date." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "", + "description": "Sets the width of the date picker input." + } + ], + "events": [ + { + "name": "_change", + "type": "CustomEvent<{ name: string; value: Date | string | null; valueStr: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/details.json b/docs/generated/component-apis/details.json index 0a698e46db..5407c0ffca 100644 --- a/docs/generated/component-apis/details.json +++ b/docs/generated/component-apis/details.json @@ -1,73 +1,196 @@ { "componentSlug": "details", "extractedFrom": "libs/web-components/src/components/details/Details.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": true, - "default": null, - "description": "The title heading." + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The title heading." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "75ch", + "description": "Sets the maximum width of the details." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Controls if details is expanded or not." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "75ch", - "description": "Sets the maximum width of the details." + "angular": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The title heading." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the details." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Controls if details is expanded or not." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "open", - "type": "boolean", - "required": false, - "default": "false", - "description": "Controls if details is expanded or not." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The title heading." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "75ch", + "description": "Sets the maximum width of the details." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "Controls if details is expanded or not." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/divider.json b/docs/generated/component-apis/divider.json index 4982fd0656..0b23bdda4c 100644 --- a/docs/generated/component-apis/divider.json +++ b/docs/generated/component-apis/divider.json @@ -1,47 +1,133 @@ { "componentSlug": "divider", "extractedFrom": "libs/web-components/src/components/divider/Divider.svelte", - "props": [ - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "frameworks": { + "react": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." + "angular": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." + "webComponents": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/drawer.json b/docs/generated/component-apis/drawer.json index c77e1dc2dd..7220a68442 100644 --- a/docs/generated/component-apis/drawer.json +++ b/docs/generated/component-apis/drawer.json @@ -1,84 +1,223 @@ { "componentSlug": "drawer", "extractedFrom": "libs/web-components/src/components/drawer/Drawer.svelte", - "props": [ - { - "name": "open", - "type": "any", - "required": false, - "default": "false", - "description": "Whether the drawer is open." - }, - { - "name": "position", - "type": "DrawerPosition", - "required": false, - "default": null, - "description": "The position of the drawer." - }, - { - "name": "heading", - "type": "string", - "required": false, - "default": "", - "description": "The heading text displayed at the top of the drawer." - }, - { - "name": "maxsize", - "type": "DrawerSize", - "required": false, - "default": null, - "description": "Sets max height on bottom position, sets width on left and right position." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "drawer", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string | ReactNode", + "values": [ + "string", + "ReactNode" + ], + "required": false, + "default": null, + "description": "The heading text displayed at the top of the drawer. Accepts a string or a ReactNode for custom heading content." + }, + { + "name": "maxSize", + "type": "GoabDrawerSize", + "required": false, + "default": null, + "description": "Sets max height on bottom position, sets width on left and right position." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Whether the drawer is open." + }, + { + "name": "position", + "type": "GoabDrawerPosition", + "required": true, + "default": null, + "description": "The position of the drawer." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } ], - "required": false, - "default": "1", - "description": "" - } - ], - "events": [ - { - "name": "onClose", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "events": [ + { + "name": "onClose", + "type": "() => void", + "description": "Callback fired when the drawer requests to be closed.", + "frameworks": [ + "react" + ] + } + ], + "slots": [ + { + "name": "actions", + "type": "ReactNode", + "description": "Action elements rendered in the drawer footer slot.", + "required": false + }, + { + "name": "heading", + "type": "ReactNode", + "description": "The heading text displayed at the top of the drawer. Accepts a string or a ReactNode for custom heading content.", + "required": false + } ] }, - { - "name": "_close", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "angular": { + "props": [ + { + "name": "heading", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "The heading text displayed at the top of the drawer." + }, + { + "name": "maxSize", + "type": "GoabDrawerSize", + "required": false, + "default": null, + "description": "Sets max height on bottom position, sets width on left and right position." + }, + { + "name": "open", + "type": "boolean", + "required": true, + "default": null, + "description": "Whether the drawer is open." + }, + { + "name": "position", + "type": "GoabDrawerPosition", + "required": true, + "default": null, + "description": "The position of the drawer." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [ + { + "name": "onClose", + "type": "() => void", + "description": "Emits when the drawer is closed.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [ + { + "name": "actions", + "type": "TemplateRef", + "description": "Action elements rendered in the drawer footer slot.", + "required": false + }, + { + "name": "heading", + "type": "TemplateRef", + "description": "The heading text displayed at the top of the drawer. Accepts a string or a ngTemplate for custom heading content.", + "required": false + } ] - } - ], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "heading", - "description": "" }, - { - "name": "actions", - "description": "" + "webComponents": { + "props": [ + { + "name": "close-button-visibility", + "type": "\"visible\" | \"hidden\"", + "values": [ + "visible", + "hidden" + ], + "required": false, + "default": "visible", + "description": "Controls visibility of the close button and header." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": "", + "description": "The heading text displayed at the top of the drawer." + }, + { + "name": "maxsize", + "type": "DrawerSize", + "required": false, + "default": null, + "description": "Sets max height on bottom position, sets width on left and right position." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "Whether the drawer is open." + }, + { + "name": "position", + "type": "DrawerPosition", + "required": false, + "default": null, + "description": "The position of the drawer." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "drawer", + "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": [ + { + "name": "_close", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "actions", + "description": "Action elements rendered in the drawer footer slot.", + "required": false + }, + { + "name": "heading", + "description": "The heading text displayed at the top of the drawer. Accepts a string or a ReactNode for custom heading content.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/dropdown-item.json b/docs/generated/component-apis/dropdown-item.json new file mode 100644 index 0000000000..29836a712a --- /dev/null +++ b/docs/generated/component-apis/dropdown-item.json @@ -0,0 +1,127 @@ +{ + "componentSlug": "dropdown-item", + "extractedFrom": "libs/web-components/src/components/dropdown/DropdownItem.svelte", + "frameworks": { + "react": { + "props": [ + { + "name": "filter", + "type": "string", + "required": false, + "default": null, + "description": "Text used to filter and match this item in typeahead search." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": null, + "description": "Display label for the dropdown item." + }, + { + "name": "mountType", + "type": "GoabDropdownItemMountType", + "required": false, + "default": null, + "description": "Controls how the item is registered with the parent dropdown." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": true, + "default": null, + "description": "The value submitted when this item is selected." + } + ], + "events": [], + "slots": [] + }, + "angular": { + "props": [ + { + "name": "filter", + "type": "string", + "required": false, + "default": null, + "description": "Text used to filter and match this item in typeahead search." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": null, + "description": "Display label for the dropdown item." + }, + { + "name": "mountType", + "type": "GoabDropdownItemMountType", + "required": false, + "default": null, + "description": "Controls how the item is registered with the parent dropdown." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Sets the name attribute of the dropdown item." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "The value submitted when this item is selected." + } + ], + "events": [], + "slots": [] + }, + "webComponents": { + "props": [ + { + "name": "filter", + "type": "string", + "required": false, + "default": "", + "description": "Text used to filter and match this item in typeahead search." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "", + "description": "Display label for the dropdown item." + }, + { + "name": "mount", + "type": "\"append\" | \"prepend\" | \"reset\"", + "values": [ + "append", + "prepend", + "reset" + ], + "required": false, + "default": "reset", + "description": "Controls how the item is registered with the parent dropdown." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "", + "description": "The value submitted when this item is selected." + } + ], + "events": [], + "slots": [] + } + } +} \ No newline at end of file diff --git a/docs/generated/component-apis/dropdown.json b/docs/generated/component-apis/dropdown.json index 76012d4799..54c109c55b 100644 --- a/docs/generated/component-apis/dropdown.json +++ b/docs/generated/component-apis/dropdown.json @@ -1,194 +1,513 @@ { "componentSlug": "dropdown", "extractedFrom": "libs/web-components/src/components/dropdown/Dropdown.svelte", - "props": [ - { - "name": "name", - "type": "string", - "required": true, - "default": null, - "description": "Identifier for the dropdown. Should be unique." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Defines how the selected value will be translated for the screen reader. If not specified it will fall back to the name." - }, - { - "name": "ariaLabelledBy", - "type": "string", - "required": false, - "default": "", - "description": "The aria-labelledby attribute identifies the element(or elements) that labels the dropdown it is applied to. Normally it is the id of the label." - }, - { - "name": "value", - "type": "string", - "required": false, - "default": "", - "description": "Stores the value of the item selected from the dropdown." - }, - { - "name": "filterable", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true the dropdown will have the ability to filter options by typing into the input field." - }, - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon shown to the left of the dropdown input." - }, - { - "name": "maxHeight", - "type": "string", - "required": false, - "default": "276px", - "description": "Maximum height of the dropdown menu. Non-native only." - }, - { - "name": "placeholder", - "type": "string", - "required": false, - "default": "", - "description": "The text displayed for the dropdown before a selection is made. Non-native only." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "", - "description": "Overrides the autosized menu width. Non-native only." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "", - "description": "Sets the maximum width of the dropdown. Use a CSS unit (px, %, ch, rem, em)." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disable this control." - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Show an error state." - }, - { - "name": "native", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true will render the native select HTML element." - }, - { - "name": "size", - "type": "\"default\" | \"compact\"", - "values": [ - "default", - "compact" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the selected value will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "ariaLabelledBy", + "type": "string", + "required": false, + "default": null, + "description": "The aria-labelledby attribute identifies the element that labels the dropdown. Normally it is the id of the label." + }, + { + "name": "autoComplete", + "type": "string", + "required": false, + "default": null, + "description": "Specifies the autocomplete attribute for the dropdown input. Native only." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disables the dropdown control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows an error state on the dropdown." + }, + { + "name": "filterable", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, allows filtering options by typing into the input field." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "The id attribute for the dropdown element." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon shown to the left of the dropdown input." + }, + { + "name": "maxHeight", + "type": "string", + "required": false, + "default": "276px", + "description": "Maximum height of the dropdown menu. Non-native only." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the dropdown. Use a CSS unit (px, %, ch, rem, em)." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Identifier for the dropdown. Should be unique." + }, + { + "name": "native", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, renders the native select HTML element." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": null, + "description": "The text displayed in the dropdown before a selection is made. Non-native only." + }, + { + "name": "size", + "type": "GoabDropdownSize", + "required": false, + "default": null, + "description": "Sets the size of the dropdown. Compact reduces height for dense layouts." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string[] | string", + "values": [ + "string[]", + "string" + ], + "required": false, + "default": null, + "description": "The currently selected value(s) of the dropdown." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Overrides the autosized menu width. Non-native only." + } ], - "required": false, - "default": "default", - "description": "Sets the size of the dropdown. Compact reduces height for dense layouts." - }, - { - "name": "relative", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated This property has no effect and will be removed in a future version.", - "deprecated": true - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "autoComplete", - "type": "string", - "required": false, - "default": "", - "description": "Specifies the autocomplete attribute for the dropdown input. Native only." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "events": [ + { + "name": "onChange", + "type": "(detail: GoabDropdownOnChangeDetail) => void", + "description": "Callback fired when the selected value changes.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "disableGlobalClosePopover", - "type": "boolean", - "required": false, - "default": "false", - "description": "Prevents the popover from closing when clicking outside. Used for nested dropdowns or complex interactions." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the selected value will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "ariaLabelledBy", + "type": "string", + "required": false, + "default": null, + "description": "The aria-labelledby attribute identifies the element(or elements) that labels the dropdown it is applied to. Normally it is the id of the label." + }, + { + "name": "autoComplete", + "type": "string", + "required": false, + "default": null, + "description": "Specifies the autocomplete attribute for the dropdown input. Native only." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the disabled state for the control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the error state for the control." + }, + { + "name": "filterable", + "type": "boolean", + "required": false, + "default": null, + "description": "When true the dropdown will have the ability to filter options by typing into the input field." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute of the underlying web component." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon shown to the left of the dropdown input." + }, + { + "name": "maxHeight", + "type": "string", + "required": false, + "default": null, + "description": "Maximum height of the dropdown menu. Non-native only." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the dropdown. Use a CSS unit (px, %, ch, rem, em)." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Identifier for the dropdown. Should be unique." + }, + { + "name": "native", + "type": "boolean", + "required": false, + "default": null, + "description": "When true will render the native select HTML element." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": null, + "description": "The text displayed for the dropdown before a selection is made. Non-native only." + }, + { + "name": "size", + "type": "GoabDropdownSize", + "required": false, + "default": "default", + "description": "Sets the size of the dropdown. Compact reduces height for dense layouts." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string[] | string", + "values": [ + "string[]", + "string" + ], + "required": false, + "default": null, + "description": "Sets the control value used by Angular forms and one-way binding." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Overrides the autosized menu width. Non-native only." + } + ], + "events": [ + { + "name": "onChange", + "type": "(event: GoabDropdownOnChangeDetail) => void", + "description": "Emits when the user selects a value from the dropdown. Emits a GoabDropdownOnChangeDetail object with the new value.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Defines how the selected value will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "arialabelledby", + "type": "string", + "required": false, + "default": "", + "description": "The aria-labelledby attribute identifies the element(or elements) that labels the dropdown it is applied to. Normally it is the id of the label." + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "", + "description": "Specifies the autocomplete attribute for the dropdown input. Native only." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disable this control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Show an error state." + }, + { + "name": "filterable", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true the dropdown will have the ability to filter options by typing into the input field." + }, + { + "name": "leadingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon shown to the left of the dropdown input." + }, + { + "name": "maxheight", + "type": "string", + "required": false, + "default": "276px", + "description": "Maximum height of the dropdown menu. Non-native only." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "", + "description": "Sets the maximum width of the dropdown. Use a CSS unit (px, %, ch, rem, em)." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "Identifier for the dropdown. Should be unique." + }, + { + "name": "native", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true will render the native select HTML element." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "", + "description": "The text displayed for the dropdown before a selection is made. Non-native only." + }, + { + "name": "size", + "type": "\"default\" | \"compact\"", + "values": [ + "default", + "compact" + ], + "required": false, + "default": "default", + "description": "Sets the size of the dropdown. Compact reduces height for dense layouts." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "", + "description": "Stores the value of the item selected from the dropdown." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "", + "description": "Overrides the autosized menu width. Non-native only." + } + ], + "events": [ + { + "name": "_change", + "type": "CustomEvent<{ name?: string; value?: string; event: Event }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/file-upload-card.json b/docs/generated/component-apis/file-upload-card.json index eef41bd76c..d6ae178059 100644 --- a/docs/generated/component-apis/file-upload-card.json +++ b/docs/generated/component-apis/file-upload-card.json @@ -1,61 +1,212 @@ { "componentSlug": "file-upload-card", "extractedFrom": "libs/web-components/src/components/file-upload-card/FileUploadCard.svelte", - "props": [ - { - "name": "filename", - "type": "string", - "required": true, - "default": null, - "description": "The name of the uploaded file to display." - }, - { - "name": "size", - "type": "number", - "required": true, - "default": null, - "description": "The file size in bytes. Displayed in a human-readable format (KB, MB)." - }, - { - "name": "type", - "type": "string", - "required": false, - "default": "", - "description": "The MIME type of the file. Used to determine the file type icon." - }, - { - "name": "progress", - "type": "number", - "required": false, - "default": "-1", - "description": "Upload progress percentage from 0-100. Use -1 to indicate upload is complete." - }, - { - "name": "error", - "type": "string", - "required": false, - "default": "", - "description": "Error message to display. When set, the card shows an error state with a cancel button." + "frameworks": { + "react": { + "props": [ + { + "name": "error", + "type": "string", + "required": false, + "default": null, + "description": "Error message to display. When set, the card shows an error state with a cancel button." + }, + { + "name": "filename", + "type": "string", + "required": true, + "default": null, + "description": "The name of the uploaded file to display." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": "-1", + "description": "Upload progress percentage from 0-100. Use -1 to indicate upload is complete." + }, + { + "name": "size", + "type": "number", + "required": true, + "default": null, + "description": "The file size in bytes. Displayed in a human-readable format (KB, MB)." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "string", + "required": false, + "default": null, + "description": "The MIME type of the file. Used to determine the file type icon." + } + ], + "events": [ + { + "name": "onCancel", + "type": "(detail: GoabFileUploadOnCancelDetail) => void", + "description": "Callback fired when the user clicks the cancel button during file upload.", + "frameworks": [ + "react" + ] + }, + { + "name": "onDelete", + "type": "(detail: GoabFileUploadOnDeleteDetail) => void", + "description": "Callback fired when the user clicks the remove button on an uploaded file.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "angular": { + "props": [ + { + "name": "error", + "type": "string", + "required": false, + "default": null, + "description": "Error message to display. When set, the card shows an error state with a cancel button." + }, + { + "name": "filename", + "type": "string", + "required": true, + "default": null, + "description": "The name of the uploaded file to display." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": null, + "description": "Upload progress percentage from 0-100. Use -1 to indicate upload is complete." + }, + { + "name": "size", + "type": "number", + "required": true, + "default": null, + "description": "The file size in bytes. Displayed in a human-readable format (KB, MB)." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "string", + "required": false, + "default": null, + "description": "The MIME type of the file. Used to determine the file type icon." + } + ], + "events": [ + { + "name": "onCancel", + "type": "(event: GoabFileUploadOnCancelDetail) => void", + "description": "Emits when the user cancels a file upload. Emits a GoabFileUploadOnCancelDetail object with the filename.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onDelete", + "type": "(event: GoabFileUploadOnDeleteDetail) => void", + "description": "Emits when the user removes an uploaded file. Emits a GoabFileUploadOnDeleteDetail object with the filename.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" + "webComponents": { + "props": [ + { + "name": "error", + "type": "string", + "required": false, + "default": "", + "description": "Error message to display. When set, the card shows an error state with a cancel button." + }, + { + "name": "filename", + "type": "string", + "required": true, + "default": null, + "description": "The name of the uploaded file to display." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": "-1", + "description": "Upload progress percentage from 0-100. Use -1 to indicate upload is complete." + }, + { + "name": "size", + "type": "number", + "required": true, + "default": null, + "description": "The file size in bytes. Displayed in a human-readable format (KB, MB)." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "string", + "required": false, + "default": "", + "description": "The MIME type of the file. Used to determine the file type icon." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_cancel", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_delete", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } ], - "required": false, - "default": "1", - "description": "" + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/file-upload-input.json b/docs/generated/component-apis/file-upload-input.json index 360834b1bb..d8cba4923d 100644 --- a/docs/generated/component-apis/file-upload-input.json +++ b/docs/generated/component-apis/file-upload-input.json @@ -1,68 +1,185 @@ { "componentSlug": "file-upload-input", "extractedFrom": "libs/web-components/src/components/file-upload-input/FileUploadInput.svelte", - "props": [ - { - "name": "variant", - "type": "\"dragdrop\" | \"button\"", - "values": [ - "dragdrop", - "button" + "frameworks": { + "react": { + "props": [ + { + "name": "accept", + "type": "string", + "required": false, + "default": null, + "description": "Accepted file types as a comma-separated list of MIME types or file extensions (e.g., \"image/*,.pdf\")." + }, + { + "name": "maxFileSize", + "type": "string", + "required": false, + "default": "5MB", + "description": "Maximum file size with unit (e.g., \"5MB\", \"100KB\", \"1GB\"). Files exceeding this will be rejected." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabFileUploadInputVariant", + "required": false, + "default": "dragdrop", + "description": "The input display variant. \"dragdrop\" shows a drag-and-drop area, \"button\" shows a simple button." + } ], - "required": false, - "default": "dragdrop", - "description": "The input display variant. \"dragdrop\" shows a drag-and-drop area, \"button\" shows a simple button." - }, - { - "name": "accept", - "type": "string", - "required": false, - "default": "*", - "description": "Accepted file types as a comma-separated list of MIME types or file extensions (e.g., \"image/*,.pdf\")." - }, - { - "name": "maxfilesize", - "type": "string", - "required": false, - "default": "5MB", - "description": "Maximum file size with unit (e.g., \"5MB\", \"100KB\", \"1GB\"). Defaults to 5MB. Files exceeding this will be rejected." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "events": [ + { + "name": "onSelectFile", + "type": "(detail: GoabFileUploadInputOnSelectFileDetail) => void", + "description": "Callback fired when a valid file is selected or dropped.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" + "angular": { + "props": [ + { + "name": "accept", + "type": "string", + "required": false, + "default": null, + "description": "Accepted file types as a comma-separated list of MIME types or file extensions (e.g., \"image/*,.pdf\")." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "", + "description": "Sets the id attribute on the file upload input element." + }, + { + "name": "maxFileSize", + "type": "string", + "required": false, + "default": "5MB", + "description": "Maximum file size with unit (e.g., \"5MB\", \"100KB\", \"1GB\"). Files exceeding this will be rejected." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabFileUploadInputVariant", + "required": false, + "default": "dragdrop", + "description": "The input display variant. \"dragdrop\" shows a drag-and-drop area, \"button\" shows a simple button." + } ], - "required": false, - "default": "1", - "description": "" - } - ], - "events": [ - { - "name": "onSelectFile", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "events": [ + { + "name": "onSelectFile", + "type": "(event: GoabFileUploadInputOnSelectFileDetail) => void", + "description": "Emits when a file is selected. Emits the selected file details.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_selectFile", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "accept", + "type": "string", + "required": false, + "default": "*", + "description": "Accepted file types as a comma-separated list of MIME types or file extensions (e.g., \"image/*,.pdf\")." + }, + { + "name": "maxfilesize", + "type": "string", + "required": false, + "default": "5MB", + "description": "Maximum file size with unit (e.g., \"5MB\", \"100KB\", \"1GB\"). Defaults to 5MB. Files exceeding this will be rejected." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "\"dragdrop\" | \"button\"", + "values": [ + "dragdrop", + "button" + ], + "required": false, + "default": "dragdrop", + "description": "The input display variant. \"dragdrop\" shows a drag-and-drop area, \"button\" shows a simple button." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_selectFile", + "type": "CustomEvent<{ file: File; event: Event }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/filter-chip.json b/docs/generated/component-apis/filter-chip.json index ebe6047613..b95a2e16a6 100644 --- a/docs/generated/component-apis/filter-chip.json +++ b/docs/generated/component-apis/filter-chip.json @@ -1,100 +1,287 @@ { "componentSlug": "filter-chip", "extractedFrom": "libs/web-components/src/components/filter-chip/FilterChip.svelte", - "props": [ - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." + "frameworks": { + "react": { + "props": [ + { + "name": "content", + "type": "string", + "required": true, + "default": null, + "description": "Text label of the chip." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows an error state." + }, + { + "name": "iconTheme", + "type": "GoabFilterChipTheme", + "required": false, + "default": "outline", + "description": "Theme style of the leading icon." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed at the start of the chip." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "secondaryText", + "type": "string", + "required": false, + "default": null, + "description": "Secondary text displayed in a smaller size before the main content." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Callback fired when the filter chip is clicked to remove it.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." + "angular": { + "props": [ + { + "name": "content", + "type": "string", + "required": false, + "default": "", + "description": "Text label of the chip." + }, + { + "name": "deletable", + "type": "boolean", + "required": false, + "default": null, + "description": "Marks the chip as deletable." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows an error state." + }, + { + "name": "iconTheme", + "type": "GoabChipTheme", + "required": false, + "default": null, + "description": "Sets the icon theme style for the filter chip." + }, + { + "name": "leadingIcon", + "type": "GoabIconType | null", + "values": [ + "GoabIconType" + ], + "required": false, + "default": null, + "description": "Icon displayed at the start of the chip." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "secondaryText", + "type": "string", + "required": false, + "default": "", + "description": "Secondary text displayed in a smaller size before the main content." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Emits when the filter chip delete button is clicked.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Shows an error state." - }, - { - "name": "content", - "type": "string", - "required": true, - "default": null, - "description": "Text label of the chip." - }, - { - "name": "secondarytext", - "type": "string", - "required": false, - "default": "", - "description": "Secondary text displayed in a smaller size before the main content." - }, - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed at the start of the chip." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Accessible label for the filter chip. Defaults to content with 'removable' suffix." - } - ], - "events": [ - { - "name": "onClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_click", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Accessible label for the filter chip. Defaults to content with 'removable' suffix." + }, + { + "name": "content", + "type": "string", + "required": true, + "default": null, + "description": "Text label of the chip." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Shows an error state." + }, + { + "name": "leadingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed at the start of the chip." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "secondarytext", + "type": "string", + "required": false, + "default": "", + "description": "Secondary text displayed in a smaller size before the main content." + }, + { + "name": "testid", + "type": "string", + "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": [ + { + "name": "_click", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/focus-trap.json b/docs/generated/component-apis/focus-trap.json deleted file mode 100644 index fdbda8a84b..0000000000 --- a/docs/generated/component-apis/focus-trap.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "componentSlug": "focus-trap", - "extractedFrom": "libs/web-components/src/components/focus-trap/FocusTrap.svelte", - "props": [ - { - "name": "open", - "type": "boolean", - "required": false, - "default": "false", - "description": "Controls whether the focus trap is active. When true, focuses the first focusable element." - }, - { - "name": "preventScrollIntoView", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, prevents automatically scrolling focused elements into view." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] -} \ No newline at end of file diff --git a/docs/generated/component-apis/footer-meta-section.json b/docs/generated/component-apis/footer-meta-section.json index 2fbe01ebb2..194f0037cd 100644 --- a/docs/generated/component-apis/footer-meta-section.json +++ b/docs/generated/component-apis/footer-meta-section.json @@ -1,20 +1,52 @@ { "componentSlug": "footer-meta-section", "extractedFrom": "libs/web-components/src/components/footer-meta-section/FooterMetaSection.svelte", - "props": [ - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "frameworks": { + "react": { + "props": [ + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] + }, + "angular": { + "props": [ + { + "name": "slot", + "type": "\"meta\"", + "required": true, + "default": null, + "description": "Sets the slot to \"meta\" to render the section in the correct footer position." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] + }, + "webComponents": { + "props": [ + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/footer-nav-section.json b/docs/generated/component-apis/footer-nav-section.json index c4016d9b34..d15b5aee3c 100644 --- a/docs/generated/component-apis/footer-nav-section.json +++ b/docs/generated/component-apis/footer-nav-section.json @@ -1,34 +1,94 @@ { "componentSlug": "footer-nav-section", "extractedFrom": "libs/web-components/src/components/footer-nav-section/FooterNavSection.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": false, - "default": "", - "description": "The section heading displayed above the navigation links." + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "The section heading displayed above the navigation links." + }, + { + "name": "maxColumnCount", + "type": "number", + "required": false, + "default": "1", + "description": "Maximum number of columns to display links in on larger screens." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "maxcolumncount", - "type": "number", - "required": false, - "default": "1", - "description": "Maximum number of columns to display links in on larger screens." + "angular": { + "props": [ + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "The section heading displayed above the navigation links." + }, + { + "name": "maxColumnCount", + "type": "number", + "required": false, + "default": "1", + "description": "Maximum number of columns to display links in on larger screens." + }, + { + "name": "slot", + "type": "\"nav\"", + "required": true, + "default": null, + "description": "Sets the slot to \"nav\" to render the section in the correct footer position." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "webComponents": { + "props": [ + { + "name": "heading", + "type": "string", + "required": false, + "default": "", + "description": "The section heading displayed above the navigation links." + }, + { + "name": "maxcolumncount", + "type": "number", + "required": false, + "default": "1", + "description": "Maximum number of columns to display links in on larger screens." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/footer.json b/docs/generated/component-apis/footer.json index fc3313b76e..a5ff3389be 100644 --- a/docs/generated/component-apis/footer.json +++ b/docs/generated/component-apis/footer.json @@ -1,49 +1,137 @@ { "componentSlug": "footer", "extractedFrom": "libs/web-components/src/components/footer/Footer.svelte", - "props": [ - { - "name": "maxcontentwidth", - "type": "string", - "required": false, - "default": "", - "description": "The maximum width of the main content area" - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "url", - "type": "string", - "required": false, - "default": "https://alberta.ca", - "description": "URL for the Government of Alberta logo link. Set to empty string to disable the link." + "frameworks": { + "react": { + "props": [ + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": null, + "description": "The maximum width of the main content area." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": "https://alberta.ca", + "description": "URL for the Government of Alberta logo link. Set to empty string to disable the link." + } + ], + "events": [], + "slots": [ + { + "name": "meta", + "type": "GoabAppFooterMetaSection", + "description": "", + "required": false + }, + { + "name": "nav", + "type": "GoabAppFooterNavSection", + "description": "", + "required": false + } + ] }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" + "angular": { + "props": [ + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": null, + "description": "The maximum width of the main content area." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": null, + "description": "URL for the Government of Alberta logo link. Set to empty string to disable the link." + } ], - "required": false, - "default": "1", - "description": "" - } - ], - "events": [], - "slots": [ - { - "name": "nav", - "description": "" + "events": [], + "slots": [ + { + "name": "meta", + "type": "GoabAppFooterMetaSection", + "description": "", + "required": false + }, + { + "name": "nav", + "type": "GoabAppFooterNavSection", + "description": "", + "required": false + } + ] }, - { - "name": "meta", - "description": "" + "webComponents": { + "props": [ + { + "name": "maxcontentwidth", + "type": "string", + "required": false, + "default": "", + "description": "The maximum width of the main content area" + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": "https://alberta.ca", + "description": "URL for the Government of Alberta logo link. Set to empty string to disable the link." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [], + "slots": [ + { + "name": "meta", + "type": "goa-app-footer-meta-section", + "description": "", + "required": false + }, + { + "name": "nav", + "type": "goa-app-footer-nav-section", + "description": "", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/form-item.json b/docs/generated/component-apis/form-item.json index 2785c75759..ae44734fc8 100644 --- a/docs/generated/component-apis/form-item.json +++ b/docs/generated/component-apis/form-item.json @@ -1,134 +1,398 @@ { "componentSlug": "form-item", "extractedFrom": "libs/web-components/src/components/form-item/FormItem.svelte", - "props": [ - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "label", - "type": "string", - "required": false, - "default": "", - "description": "Creates a label for the form item." - }, - { - "name": "labelSize", - "type": "\"compact\" | \"regular\" | \"large\"", - "typeLabel": "GoabFormItemLabelSizeType", - "values": [ - "compact", - "regular", - "large" + "frameworks": { + "react": { + "props": [ + { + "name": "error", + "type": "string | React.ReactNode", + "values": [ + "string", + "React.ReactNode" + ], + "required": false, + "default": null, + "description": "Error text displayed under the form field. Leave blank to indicate a valid field. Accepts a string or ReactNode for custom error content." + }, + { + "name": "helpText", + "type": "string | React.ReactNode", + "values": [ + "string", + "React.ReactNode" + ], + "required": false, + "default": null, + "description": "Help text displayed under the form field to provide additional explanation. Accepts a string or ReactNode for custom help content." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute on the form item element." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": null, + "description": "Creates a label for the form item." + }, + { + "name": "labelSize", + "type": "GoabFormItemLabelSize", + "required": false, + "default": "regular", + "description": "Sets the label size. 'regular' for standard, 'large' for emphasis." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of the form item." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Overrides the label value within the form-summary to provide a shorter description. For public-form use only." + }, + { + "name": "requirement", + "type": "GoabFormItemRequirement", + "required": false, + "default": null, + "description": "Marks the field with an optional or required label indicator." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabFormItemType", + "required": false, + "default": null, + "description": "Specifies the input type for appropriate message spacing. Used with checkbox-list or radio-group." + } ], - "required": false, - "default": "regular", - "description": "Sets the label size. 'compact' for dense layouts, 'regular' for standard, 'large' for emphasis." - }, - { - "name": "helpText", - "type": "string", - "required": false, - "default": "", - "description": "Help text displayed under the form field to provide additional explanation." + "events": [], + "slots": [ + { + "name": "error", + "type": "ReactNode", + "description": "Error text displayed under the form field. Leave blank to indicate a valid field. Accepts a string or ReactNode for custom error content.", + "required": false + }, + { + "name": "helpText", + "type": "ReactNode", + "description": "Help text displayed under the form field to provide additional explanation. Accepts a string or ReactNode for custom help content.", + "required": false + } + ] }, - { - "name": "error", - "type": "string", - "required": false, - "default": "", - "description": "Error text displayed under the form field. Leave blank to indicate a valid field." - }, - { - "name": "requirement", - "type": "\"optional\" | \"required\"", - "typeLabel": "GoabFormItemRequirementType", - "values": [ - "optional", - "required" + "angular": { + "props": [ + { + "name": "error", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "Error text displayed under the form field. Leave blank to indicate a valid field." + }, + { + "name": "helpText", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "Help text displayed under the form field to provide additional explanation." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute on the form item element." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": null, + "description": "Creates a label for the form item." + }, + { + "name": "labelSize", + "type": "GoabFormItemLabelSize", + "required": false, + "default": null, + "description": "Sets the label size. 'regular' for standard, 'large' for emphasis." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the form item." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Overrides the label value within the form-summary to provide a shorter description. For public-form use only." + }, + { + "name": "requirement", + "type": "GoabFormItemRequirement", + "required": false, + "default": null, + "description": "Marks the field with an optional or required label indicator." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabFormItemType", + "required": false, + "default": "", + "description": "Specifies the input type for appropriate message spacing. Used with checkbox-list or radio-group." + } ], - "required": false, - "default": "", - "description": "Marks the field with an optional or required label indicator." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "none", - "description": "Sets the maximum width of the form item." + "events": [], + "slots": [ + { + "name": "error", + "type": "TemplateRef", + "description": "Error text displayed under the form field. Leave blank to indicate a valid field. Accepts a string or ngTemplate for custom error content.", + "required": false + }, + { + "name": "helpText", + "type": "TemplateRef", + "description": "Help text displayed under the form field to provide additional explanation. Accepts a string or ngTemplate for custom help content.", + "required": false + } + ] }, - { - "name": "type", - "type": "\"text-input\" | \"textarea\" | \"checkbox-list\" | \"radio-group\"", - "typeLabel": "GoabFormItemInputType", - "values": [ - "text-input", - "textarea", - "checkbox-list", - "radio-group" + "webComponents": { + "props": [ + { + "name": "error", + "type": "string", + "required": false, + "default": "", + "description": "Error text displayed under the form field. Leave blank to indicate a valid field." + }, + { + "name": "helptext", + "type": "string", + "required": false, + "default": "", + "description": "Help text displayed under the form field to provide additional explanation." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "", + "description": "Creates a label for the form item." + }, + { + "name": "labelsize", + "type": "\"compact\" | \"regular\" | \"large\"", + "typeLabel": "GoabFormItemLabelSizeType", + "values": [ + "compact", + "regular", + "large" + ], + "required": false, + "default": "regular", + "description": "Sets the label size. 'compact' for dense layouts, 'regular' for standard, 'large' for emphasis." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of the form item." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "blank", + "description": "Overrides the label value within the form-summary. For public-form use only." + }, + { + "name": "requirement", + "type": "\"optional\" | \"required\"", + "typeLabel": "GoabFormItemRequirementType", + "values": [ + "optional", + "required" + ], + "required": false, + "default": "", + "description": "Marks the field with an optional or required label indicator." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"text-input\" | \"textarea\" | \"checkbox-list\" | \"radio-group\"", + "typeLabel": "GoabFormItemInputType", + "values": [ + "text-input", + "textarea", + "checkbox-list", + "radio-group" + ], + "required": false, + "default": "", + "description": "Specifies the input type for appropriate message spacing. Used with checkbox-list or radio-group." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "typeLabel": "GoabFormItemVersionType", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } ], - "required": false, - "default": "", - "description": "Specifies the input type for appropriate message spacing. Used with checkbox-list or radio-group." - }, - { - "name": "name", - "type": "string", - "required": false, - "default": "blank", - "description": "Overrides the label value within the form-summary. For public-form use only." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "error", - "description": "" - }, - { - "name": "helptext", - "description": "" + "events": [], + "slots": [ + { + "name": "error", + "description": "Error text displayed under the form field. Leave blank to indicate a valid field. Accepts a string or ReactNode for custom error content.", + "required": false + }, + { + "name": "helptext", + "description": "Help text displayed under the form field to provide additional explanation. Accepts a string or ReactNode for custom help content.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/form-step.json b/docs/generated/component-apis/form-step.json index d8bfb22ee0..1302d29704 100644 --- a/docs/generated/component-apis/form-step.json +++ b/docs/generated/component-apis/form-step.json @@ -1,51 +1,87 @@ { "componentSlug": "form-step", "extractedFrom": "libs/web-components/src/components/form-step/FormStep.svelte", - "props": [ - { - "name": "text", - "type": "string", - "required": true, - "default": null, - "description": "The step label text displayed to users." - }, - { - "name": "status", - "type": "\"complete\" | \"incomplete\" | \"not-started\"", - "values": [ - "complete", - "incomplete", - "not-started" + "frameworks": { + "react": { + "props": [ + { + "name": "status", + "type": "GoabFormStepStatus", + "required": false, + "default": null, + "description": "The completion status of the step. Affects visual styling and icons." + }, + { + "name": "text", + "type": "string", + "required": true, + "default": null, + "description": "The step label text displayed to users." + } ], - "required": false, - "default": null, - "description": "The completion status of the step. Affects visual styling and icons." + "events": [], + "slots": [] }, - { - "name": "last", - "type": "boolean", - "required": false, - "default": "false", - "description": "Whether this is the last step in the form stepper. Affects styling when complete." - } - ], - "events": [ - { - "name": "onClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "status", + "type": "GoabFormStepStatus", + "required": false, + "default": null, + "description": "The completion status of the step. Affects visual styling and icons." + }, + { + "name": "text", + "type": "string", + "required": false, + "default": null, + "description": "The step label text displayed to users." + } + ], + "events": [], + "slots": [] }, - { - "name": "_click", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "last", + "type": "boolean", + "required": false, + "default": "false", + "description": "Whether this is the last step in the form stepper. Affects styling when complete." + }, + { + "name": "status", + "type": "\"complete\" | \"incomplete\" | \"not-started\"", + "values": [ + "complete", + "incomplete", + "not-started" + ], + "required": false, + "default": null, + "description": "The completion status of the step. Affects visual styling and icons." + }, + { + "name": "text", + "type": "string", + "required": true, + "default": null, + "description": "The step label text displayed to users." + } + ], + "events": [ + { + "name": "_click", + "type": "CustomEvent<{ step: unknown }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/form-stepper.json b/docs/generated/component-apis/form-stepper.json deleted file mode 100644 index 78f1db04e2..0000000000 --- a/docs/generated/component-apis/form-stepper.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "componentSlug": "form-stepper", - "extractedFrom": "libs/web-components/src/components/form-stepper/FormStepper.svelte", - "props": [ - { - "name": "step", - "type": "number", - "required": false, - "default": "-1", - "description": "The current step state value (1-based index). Leaving it blank (-1) will allow any step to be accessed." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" - } - ] -} \ No newline at end of file diff --git a/docs/generated/component-apis/form.json b/docs/generated/component-apis/form.json index f60c7e3fb6..ce55e721d5 100644 --- a/docs/generated/component-apis/form.json +++ b/docs/generated/component-apis/form.json @@ -1,48 +1,129 @@ { "componentSlug": "form", "extractedFrom": "libs/web-components/src/components/form/Form.svelte", - "props": [ - { - "name": "status", - "type": "\"initializing\" | \"complete\"", - "values": [ - "initializing", - "complete" + "frameworks": { + "react": { + "props": [ + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "A name identifier for the form. Useful for debugging complex forms with multiple nested forms." + }, + { + "name": "status", + "type": "GoabPublicFormStatus", + "required": false, + "default": "complete", + "description": "The initialization status of the form. Set to \"initializing\" while loading external state, then \"complete\" when ready." + } ], - "required": false, - "default": "complete", - "description": "The initialization status of the form. Set to \"initializing\" while loading external state, then \"complete\" when ready." + "events": [ + { + "name": "onComplete", + "type": "(event: GoabFormState) => void", + "description": "Callback fired when the form is completed.", + "frameworks": [ + "react" + ] + }, + { + "name": "onInit", + "type": "(event: Event) => void", + "description": "Callback fired when the form is initialized.", + "frameworks": [ + "react" + ] + }, + { + "name": "onStateChange", + "type": "(event: GoabFormState) => void", + "description": "Callback fired when the form state changes.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "name", - "type": "string", - "required": false, - "default": "[name] not set", - "description": "A name identifier for the form. Useful for debugging complex forms with multiple nested forms." - } - ], - "events": [ - { - "name": "onInit", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "A name identifier for the form. Useful for debugging complex forms with multiple nested forms." + }, + { + "name": "status", + "type": "GoabPublicFormStatus", + "required": false, + "default": "complete", + "description": "The initialization status of the form. Set to \"initializing\" while loading external state, then \"complete\" when ready." + } + ], + "events": [ + { + "name": "onComplete", + "type": "(event: GoabFormState) => void", + "description": "Emits when the form is complete. Emits the form state.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onInit", + "type": "(event: Event) => void", + "description": "Emits when the form is initialized.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onStateChange", + "type": "(event: GoabFormState) => void", + "description": "Emits when the form state changes. Emits the updated form state.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_init", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "name", + "type": "string", + "required": false, + "default": "[name] not set", + "description": "A name identifier for the form. Useful for debugging complex forms with multiple nested forms." + }, + { + "name": "status", + "type": "\"initializing\" | \"complete\"", + "values": [ + "initializing", + "complete" + ], + "required": false, + "default": "complete", + "description": "The initialization status of the form. Set to \"initializing\" while loading external state, then \"complete\" when ready." + } + ], + "events": [ + { + "name": "_init", + "type": "CustomEvent<{ el: unknown }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/grid.json b/docs/generated/component-apis/grid.json index 3bad56dd41..fa0c8be0db 100644 --- a/docs/generated/component-apis/grid.json +++ b/docs/generated/component-apis/grid.json @@ -1,67 +1,176 @@ { "componentSlug": "grid", "extractedFrom": "libs/web-components/src/components/grid/Grid.svelte", - "props": [ - { - "name": "gap", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "m", - "description": "Gap between child items." + "frameworks": { + "react": { + "props": [ + { + "name": "gap", + "type": "Spacing", + "required": false, + "default": "m", + "description": "Gap between child items." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "minChildWidth", + "type": "string", + "required": true, + "default": null, + "description": "Minimum width of the child elements." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "minchildwidth", - "type": "string", - "required": true, - "default": "", - "description": "Minimum width of the child elements" + "angular": { + "props": [ + { + "name": "gap", + "type": "Spacing", + "required": false, + "default": null, + "description": "Gap between child items." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "minChildWidth", + "type": "string", + "required": true, + "default": null, + "description": "Minimum width of the child elements." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "gap", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "m", + "description": "Gap between child items." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "minchildwidth", + "type": "string", + "required": true, + "default": "", + "description": "Minimum width of the child elements" + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/hero-banner.json b/docs/generated/component-apis/hero-banner.json index c5185159b6..15d199bf8c 100644 --- a/docs/generated/component-apis/hero-banner.json +++ b/docs/generated/component-apis/hero-banner.json @@ -1,66 +1,191 @@ { "componentSlug": "hero-banner", "extractedFrom": "libs/web-components/src/components/hero-banner/HeroBanner.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": true, - "default": null, - "description": "Main heading text" + "frameworks": { + "react": { + "props": [ + { + "name": "backgroundColor", + "type": "string", + "required": false, + "default": "#f8f8f8", + "description": "Hero Banner background color when no background image is provided." + }, + { + "name": "backgroundUrl", + "type": "string", + "required": false, + "default": null, + "description": "Background image url." + }, + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "Main heading text." + }, + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": "100%", + "description": "Maximum width of the content area." + }, + { + "name": "minHeight", + "type": "string", + "required": false, + "default": null, + "description": "Minimum height of the hero banner. Defaults to 600px when a background image is provided." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "textColor", + "type": "string", + "required": false, + "default": null, + "description": "Text color within the hero banner." + } + ], + "events": [], + "slots": [ + { + "name": "actions", + "type": "ReactNode", + "description": "Content rendered in the actions slot.", + "required": false + } + ] }, - { - "name": "backgroundurl", - "type": "string", - "required": true, - "default": null, - "description": "Background image url" + "angular": { + "props": [ + { + "name": "backgroundColor", + "type": "string", + "required": false, + "default": null, + "description": "Hero Banner background color when no background image is provided." + }, + { + "name": "backgroundUrl", + "type": "string", + "required": false, + "default": null, + "description": "Background image url." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "Main heading text." + }, + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": null, + "description": "Maximum width of the content area." + }, + { + "name": "minHeight", + "type": "string", + "required": false, + "default": null, + "description": "Minimum height of the hero banner. Defaults to 600px when a background image is provided." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "textColor", + "type": "string", + "required": false, + "default": null, + "description": "Text color within the hero banner." + } + ], + "events": [], + "slots": [ + { + "name": "actions", + "type": "TemplateRef", + "description": "Content rendered in the actions slot.", + "required": false + } + ] }, - { - "name": "minheight", - "type": "string", - "required": true, - "default": null, - "description": "Minimum height of the hero banner. Defaults to 600px when a background image is provided." - }, - { - "name": "maxcontentwidth", - "type": "any", - "required": false, - "default": "100%", - "description": "Maximum width of the content area" - }, - { - "name": "backgroundcolor", - "type": "string", - "required": false, - "default": "#f8f8f8", - "description": "Hero Banner background color when no background image is provided" - }, - { - "name": "textcolor", - "type": "string", - "required": false, - "default": "", - "description": "Text color within the hero banner." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "background", - "description": "Sets a data-testid attribute for automated testing." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "actions", - "description": "" + "webComponents": { + "props": [ + { + "name": "backgroundcolor", + "type": "string", + "required": false, + "default": "#f8f8f8", + "description": "Hero Banner background color when no background image is provided" + }, + { + "name": "backgroundurl", + "type": "string", + "required": true, + "default": null, + "description": "Background image url" + }, + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "Main heading text" + }, + { + "name": "maxcontentwidth", + "type": "string", + "required": false, + "default": "100%", + "description": "Maximum width of the content area" + }, + { + "name": "minheight", + "type": "string", + "required": true, + "default": null, + "description": "Minimum height of the hero banner. Defaults to 600px when a background image is provided." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "background", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "textcolor", + "type": "string", + "required": false, + "default": "", + "description": "Text color within the hero banner." + } + ], + "events": [], + "slots": [ + { + "name": "actions", + "description": "Content rendered in the actions slot.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/icon-button.json b/docs/generated/component-apis/icon-button.json index 9b3ca9c4e2..cbabf3ce2f 100644 --- a/docs/generated/component-apis/icon-button.json +++ b/docs/generated/component-apis/icon-button.json @@ -1,129 +1,386 @@ { "componentSlug": "icon-button", "extractedFrom": "libs/web-components/src/components/icon-button/IconButton.svelte", - "props": [ - { - "name": "icon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": true, - "default": null, - "description": "Sets the icon." - }, - { - "name": "size", - "type": "IconSize", - "required": false, - "default": "medium", - "description": "Sets the size of button." - }, - { - "name": "theme", - "type": "IconTheme", - "required": false, - "default": "outline", - "description": "Sets the icon theme. 'outline' for stroked icons, 'filled' for solid icons." - }, - { - "name": "variant", - "type": "\"color\" | \"nocolor\" | \"light\" | \"dark\" | \"destructive\"", - "typeLabel": "GoabIconButtonVariant", - "values": [ - "color", - "nocolor", - "light", - "dark", - "destructive" + "frameworks": { + "react": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": null, + "description": "Action identifier passed in click events for event delegation patterns." + }, + { + "name": "actionArg", + "type": "string", + "required": false, + "default": null, + "description": "Single argument value passed with the action in click events." + }, + { + "name": "actionArgs", + "type": "Record", + "required": false, + "default": null, + "description": "Multiple argument values passed with the action in click events." + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Sets the aria-label of the button." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disables the button." + }, + { + "name": "icon", + "type": "GoabIconType", + "required": true, + "default": null, + "description": "Sets the icon." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "size", + "type": "GoabIconSize", + "required": false, + "default": "medium", + "description": "Sets the size of button." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "theme", + "type": "GoabIconTheme", + "required": false, + "default": "outline", + "description": "Sets the theme of the icon inside the button. \"outline\" for stroked icons, \"filled\" for solid icons." + }, + { + "name": "title", + "type": "string", + "required": false, + "default": null, + "description": "Sets the title of the button." + }, + { + "name": "variant", + "type": "GoabIconButtonVariant", + "required": false, + "default": "color", + "description": "Styles the button to show color, light, dark or destructive action." + } ], - "required": false, - "default": "color", - "description": "Styles the button to show color, light, dark or destructive action." - }, - { - "name": "title", - "type": "string", - "required": false, - "default": "", - "description": "Sets the title of the button." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disables the button." - }, - { - "name": "inverted", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, inverts the icon colors for use on dark backgrounds." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Sets the aria-label of the button." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Callback fired when the icon button is clicked.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": null, + "description": "Action identifier passed in click events for event delegation patterns." + }, + { + "name": "actionArg", + "type": "string", + "required": false, + "default": null, + "description": "Single argument value passed with the action in click events." + }, + { + "name": "actionArgs", + "type": "Record", + "required": false, + "default": null, + "description": "Multiple argument values passed with the action in click events." + }, + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Sets the aria-label of the button." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disables the button." + }, + { + "name": "icon", + "type": "GoabIconType", + "required": true, + "default": null, + "description": "Sets the icon." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "size", + "type": "GoabIconSize", + "required": false, + "default": "medium", + "description": "Sets the size of button." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "theme", + "type": "GoabIconTheme", + "required": false, + "default": "outline", + "description": "Sets the icon theme. \"outline\" for stroked icons, \"filled\" for solid icons." + }, + { + "name": "title", + "type": "string", + "required": false, + "default": null, + "description": "Sets the title of the button." + }, + { + "name": "variant", + "type": "GoabIconButtonVariant", + "required": false, + "default": null, + "description": "Styles the button to show color, light, dark or destructive action." + } + ], + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Emits when the icon button is clicked.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_click", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": "", + "description": "Action identifier passed in click events for event delegation patterns." + }, + { + "name": "action-arg", + "type": "string", + "required": false, + "default": "", + "description": "Single argument value passed with the action in click events." + }, + { + "name": "action-args", + "type": "Record", + "required": false, + "default": "{}", + "description": "Multiple argument values passed with the action in click events." + }, + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Sets the aria-label of the button." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disables the button." + }, + { + "name": "icon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": true, + "default": null, + "description": "Sets the icon." + }, + { + "name": "inverted", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, inverts the icon colors for use on dark backgrounds." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "size", + "type": "IconSize", + "required": false, + "default": "medium", + "description": "Sets the size of button." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "theme", + "type": "IconTheme", + "required": false, + "default": "outline", + "description": "Sets the icon theme. 'outline' for stroked icons, 'filled' for solid icons." + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "", + "description": "Sets the title of the button." + }, + { + "name": "variant", + "type": "\"color\" | \"nocolor\" | \"light\" | \"dark\" | \"destructive\"", + "typeLabel": "GoabIconButtonVariant", + "values": [ + "color", + "nocolor", + "light", + "dark", + "destructive" + ], + "required": false, + "default": "color", + "description": "Styles the button to show color, light, dark or destructive action." + } + ], + "events": [ + { + "name": "_click", + "type": "CustomEvent<{ event: Event }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/icon.json b/docs/generated/component-apis/icon.json index d69598cc20..4f0c4f802f 100644 --- a/docs/generated/component-apis/icon.json +++ b/docs/generated/component-apis/icon.json @@ -1,649 +1,367 @@ { "componentSlug": "icon", "extractedFrom": "libs/web-components/src/components/icon/Icon.svelte", - "props": [ - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "type", - "type": "\"accessibility\" | \"add-circle\" | \"add\" | \"airplane\" | \"alarm\" | \"albums\" | \"alert-circle\" | \"alert\" | \"american-football\" | \"analytics\" | \"aperture\" | \"apps\" | \"archive\" | \"arrow-back-circle\" | \"arrow-back\" | \"arrow-down-circle\" | \"arrow-down\" | \"arrow-forward-circle\" | \"arrow-forward\" | \"arrow-redo-circle\" | \"arrow-redo\" | \"arrow-undo-circle\" | \"arrow-undo\" | \"arrow-up-circle\" | \"arrow-up\" | \"at-circle\" | \"at\" | \"attach\" | \"backspace\" | \"bag-add\" | \"bag-check\" | \"bag-handle\" | \"bag\" | \"bag-remove\" | \"balloon\" | \"ban\" | \"bandage\" | \"bar-chart\" | \"barbell\" | \"barcode\" | \"baseball\" | \"basket\" | \"basketball\" | \"battery-charging\" | \"battery-dead\" | \"battery-full\" | \"battery-half\" | \"beaker\" | \"bed\" | \"beer\" | \"bicycle\" | \"bluetooth\" | \"boat\" | \"body\" | \"bonfire\" | \"book\" | \"bookmark\" | \"bookmarks\" | \"bowling-ball\" | \"briefcase\" | \"browsers\" | \"brush\" | \"bug\" | \"build\" | \"bulb\" | \"bus\" | \"business\" | \"cafe\" | \"calculator\" | \"calendar-clear\" | \"calendar-number\" | \"calendar\" | \"call\" | \"camera\" | \"camera-reverse\" | \"car\" | \"car-sport\" | \"card\" | \"caret-back-circle\" | \"caret-back\" | \"caret-down-circle\" | \"caret-down\" | \"caret-forward-circle\" | \"caret-forward\" | \"caret-up-circle\" | \"caret-up\" | \"cart\" | \"cash\" | \"cellular\" | \"chatbox-ellipses\" | \"chatbox\" | \"chatbubble-ellipses\" | \"chatbubble\" | \"chatbubbles\" | \"checkbox\" | \"checkmark-circle\" | \"checkmark-done-circle\" | \"checkmark-done\" | \"chevron-back-circle\" | \"chevron-back\" | \"chevron-down-circle\" | \"chevron-down\" | \"chevron-expand\" | \"chevron-forward-circle\" | \"chevron-forward\" | \"chevron-up-circle\" | \"chevron-up\" | \"clipboard\" | \"close-circle\" | \"close\" | \"cloud-circle\" | \"cloud-done\" | \"cloud-download\" | \"cloud-offline\" | \"cloud\" | \"cloud-upload\" | \"cloudy-night\" | \"cloudy\" | \"code-download\" | \"code\" | \"code-slash\" | \"code-working\" | \"cog\" | \"color-fill\" | \"color-filter\" | \"color-palette\" | \"color-wand\" | \"compass\" | \"construct\" | \"contract\" | \"contrast\" | \"copy\" | \"create\" | \"crop\" | \"cube\" | \"cut\" | \"desktop\" | \"diamond\" | \"dice\" | \"disc\" | \"document-attach\" | \"document-lock\" | \"document\" | \"document-text\" | \"documents\" | \"download\" | \"duplicate\" | \"ear\" | \"earth\" | \"easel\" | \"egg\" | \"ellipse\" | \"ellipsis-horizontal-circle\" | \"ellipsis-horizontal\" | \"ellipsis-vertical-circle\" | \"ellipsis-vertical\" | \"enter\" | \"exit\" | \"expand\" | \"extension-puzzle\" | \"eye-off\" | \"eye\" | \"eyedrop\" | \"fast-food\" | \"female\" | \"file-tray-full\" | \"file-tray\" | \"file-tray-stacked\" | \"filenames.ps1\" | \"film\" | \"filter-circle\" | \"filter-lines\" | \"filter\" | \"finger-print\" | \"fish\" | \"fitness\" | \"flag\" | \"flame\" | \"flash-off\" | \"flash\" | \"flashlight\" | \"flask\" | \"flower\" | \"folder-open\" | \"folder\" | \"football\" | \"footsteps\" | \"funnel\" | \"game-controller\" | \"gift\" | \"git-branch\" | \"git-commit\" | \"git-compare\" | \"git-merge\" | \"git-network\" | \"git-pull-request\" | \"glasses\" | \"globe\" | \"golf\" | \"grid\" | \"hammer\" | \"hand-left\" | \"hand-right\" | \"happy\" | \"hardware-chip\" | \"headset\" | \"heart-circle\" | \"heart-dislike-circle\" | \"heart-dislike\" | \"heart-half\" | \"heart\" | \"help-buoy\" | \"help-circle\" | \"help\" | \"home\" | \"hourglass\" | \"ice-cream\" | \"id-card\" | \"image\" | \"images\" | \"infinite\" | \"information-circle\" | \"information\" | \"invert-mode\" | \"journal\" | \"key\" | \"keypad\" | \"language\" | \"laptop\" | \"layers\" | \"leaf\" | \"library\" | \"link\" | \"list-circle\" | \"list\" | \"locate\" | \"location\" | \"lock-closed\" | \"lock-open\" | \"log-in\" | \"log-out\" | \"magnet\" | \"mail-open\" | \"mail\" | \"mail-unread\" | \"male-female\" | \"male\" | \"man\" | \"map\" | \"medal\" | \"medical\" | \"medkit\" | \"megaphone\" | \"menu\" | \"mic-circle\" | \"mic-off-circle\" | \"mic-off\" | \"mic\" | \"moon\" | \"move\" | \"musical-note\" | \"musical-notes\" | \"navigate-circle\" | \"navigate\" | \"newspaper\" | \"notifications-circle\" | \"notifications-off-circle\" | \"notifications-off\" | \"notifications\" | \"nuclear\" | \"nutrition\" | \"open\" | \"options\" | \"paper-plane\" | \"partly-sunny\" | \"pause-circle\" | \"pause\" | \"paw\" | \"people-circle\" | \"people\" | \"person-add\" | \"person-circle\" | \"person\" | \"person-remove\" | \"phone-landscape\" | \"phone-portrait\" | \"pie-chart\" | \"pin\" | \"pint\" | \"pizza\" | \"planet\" | \"play-back-circle\" | \"play-back\" | \"play-circle\" | \"play-forward-circle\" | \"play-forward\" | \"play\" | \"play-skip-back-circle\" | \"play-skip-back\" | \"play-skip-forward-circle\" | \"play-skip-forward\" | \"podium\" | \"power\" | \"pricetag\" | \"pricetags\" | \"print\" | \"prism\" | \"pulse\" | \"push\" | \"qr-code\" | \"radio-button-off\" | \"radio-button-on\" | \"radio\" | \"rainy\" | \"reader\" | \"receipt\" | \"recording\" | \"refresh-circle\" | \"refresh\" | \"reload-circle\" | \"reload\" | \"remove-circle\" | \"reorder-four\" | \"reorder-three\" | \"reorder-two\" | \"repeat\" | \"resize\" | \"restaurant\" | \"return-down-back\" | \"return-down-forward\" | \"return-up-back\" | \"return-up-forward\" | \"ribbon\" | \"rocket\" | \"rose\" | \"sad\" | \"save\" | \"scale\" | \"scan-circle\" | \"scan\" | \"school\" | \"search-circle\" | \"search\" | \"send\" | \"server\" | \"settings\" | \"shapes\" | \"share\" | \"share-social\" | \"shield-checkmark\" | \"shield-half\" | \"shield\" | \"shirt\" | \"shuffle\" | \"skull\" | \"snow\" | \"sparkles\" | \"speedometer\" | \"square\" | \"star-half\" | \"star\" | \"stats-chart\" | \"stop-circle\" | \"stop\" | \"stopwatch\" | \"storefront\" | \"subway\" | \"sunny\" | \"swap-horizontal\" | \"swap-vertical\" | \"sync-circle\" | \"sync\" | \"tablet-landscape\" | \"tablet-portrait\" | \"telescope\" | \"tennisball\" | \"terminal\" | \"text\" | \"thermometer\" | \"thumbs-down\" | \"thumbs-up\" | \"thunderstorm\" | \"ticket\" | \"time\" | \"timer\" | \"today\" | \"toggle\" | \"trail-sign\" | \"train\" | \"transgender\" | \"trash-bin\" | \"trash\" | \"trending-down\" | \"trending-up\" | \"triangle\" | \"trophy\" | \"tv\" | \"umbrella\" | \"unlink\" | \"videocam-off\" | \"videocam\" | \"volume-high\" | \"volume-low\" | \"volume-medium\" | \"volume-mute\" | \"volume-off\" | \"walk\" | \"wallet\" | \"warning\" | \"watch\" | \"water\" | \"wifi\" | \"wine\" | \"woman\" | \"logo-alipay\" | \"logo-amazon\" | \"logo-amplify\" | \"logo-android\" | \"logo-angular\" | \"logo-apple\" | \"logo-apple-appstore\" | \"logo-apple-ar\" | \"logo-behance\" | \"logo-bitbucket\" | \"logo-bitcoin\" | \"logo-buffer\" | \"logo-capacitor\" | \"logo-chrome\" | \"logo-closed-captioning\" | \"logo-codepen\" | \"logo-css3\" | \"logo-designernews\" | \"logo-deviantart\" | \"logo-discord\" | \"logo-docker\" | \"logo-dribbble\" | \"logo-dropbox\" | \"logo-edge\" | \"logo-electron\" | \"logo-euro\" | \"logo-facebook\" | \"logo-figma\" | \"logo-firebase\" | \"logo-firefox\" | \"logo-flickr\" | \"logo-foursquare\" | \"logo-github\" | \"logo-gitlab\" | \"logo-google\" | \"logo-google-playstore\" | \"logo-hackernews\" | \"logo-html5\" | \"logo-instagram\" | \"logo-ionic\" | \"logo-ionitron\" | \"logo-javascript\" | \"logo-laravel\" | \"logo-linkedin\" | \"logo-markdown\" | \"logo-mastodon\" | \"logo-medium\" | \"logo-microsoft\" | \"logo-no-smoking\" | \"logo-nodejs\" | \"logo-npm\" | \"logo-octocat\" | \"logo-paypal\" | \"logo-pinterest\" | \"logo-playstation\" | \"logo-pwa\" | \"logo-python\" | \"logo-react\" | \"logo-reddit\" | \"logo-rss\" | \"logo-sass\" | \"logo-skype\" | \"logo-slack\" | \"logo-snapchat\" | \"logo-soundcloud\" | \"logo-stackoverflow\" | \"logo-steam\" | \"logo-stencil\" | \"logo-tableau\" | \"logo-tiktok\" | \"logo-tumblr\" | \"logo-tux\" | \"logo-twitch\" | \"logo-twitter\" | \"logo-usd\" | \"logo-venmo\" | \"logo-vercel\" | \"logo-vimeo\" | \"logo-vk\" | \"logo-vue\" | \"logo-web-component\" | \"logo-wechat\" | \"logo-whatsapp\" | \"logo-windows\" | \"logo-wordpress\" | \"logo-xbox\" | \"logo-xing\" | \"logo-yahoo\" | \"logo-yen\" | \"logo-youtube\"", - "typeLabel": "GoAIconType", - "values": [ - "accessibility", - "add-circle", - "add", - "airplane", - "alarm", - "albums", - "alert-circle", - "alert", - "american-football", - "analytics", - "aperture", - "apps", - "archive", - "arrow-back-circle", - "arrow-back", - "arrow-down-circle", - "arrow-down", - "arrow-forward-circle", - "arrow-forward", - "arrow-redo-circle", - "arrow-redo", - "arrow-undo-circle", - "arrow-undo", - "arrow-up-circle", - "arrow-up", - "at-circle", - "at", - "attach", - "backspace", - "bag-add", - "bag-check", - "bag-handle", - "bag", - "bag-remove", - "balloon", - "ban", - "bandage", - "bar-chart", - "barbell", - "barcode", - "baseball", - "basket", - "basketball", - "battery-charging", - "battery-dead", - "battery-full", - "battery-half", - "beaker", - "bed", - "beer", - "bicycle", - "bluetooth", - "boat", - "body", - "bonfire", - "book", - "bookmark", - "bookmarks", - "bowling-ball", - "briefcase", - "browsers", - "brush", - "bug", - "build", - "bulb", - "bus", - "business", - "cafe", - "calculator", - "calendar-clear", - "calendar-number", - "calendar", - "call", - "camera", - "camera-reverse", - "car", - "car-sport", - "card", - "caret-back-circle", - "caret-back", - "caret-down-circle", - "caret-down", - "caret-forward-circle", - "caret-forward", - "caret-up-circle", - "caret-up", - "cart", - "cash", - "cellular", - "chatbox-ellipses", - "chatbox", - "chatbubble-ellipses", - "chatbubble", - "chatbubbles", - "checkbox", - "checkmark-circle", - "checkmark-done-circle", - "checkmark-done", - "chevron-back-circle", - "chevron-back", - "chevron-down-circle", - "chevron-down", - "chevron-expand", - "chevron-forward-circle", - "chevron-forward", - "chevron-up-circle", - "chevron-up", - "clipboard", - "close-circle", - "close", - "cloud-circle", - "cloud-done", - "cloud-download", - "cloud-offline", - "cloud", - "cloud-upload", - "cloudy-night", - "cloudy", - "code-download", - "code", - "code-slash", - "code-working", - "cog", - "color-fill", - "color-filter", - "color-palette", - "color-wand", - "compass", - "construct", - "contract", - "contrast", - "copy", - "create", - "crop", - "cube", - "cut", - "desktop", - "diamond", - "dice", - "disc", - "document-attach", - "document-lock", - "document", - "document-text", - "documents", - "download", - "duplicate", - "ear", - "earth", - "easel", - "egg", - "ellipse", - "ellipsis-horizontal-circle", - "ellipsis-horizontal", - "ellipsis-vertical-circle", - "ellipsis-vertical", - "enter", - "exit", - "expand", - "extension-puzzle", - "eye-off", - "eye", - "eyedrop", - "fast-food", - "female", - "file-tray-full", - "file-tray", - "file-tray-stacked", - "filenames.ps1", - "film", - "filter-circle", - "filter-lines", - "filter", - "finger-print", - "fish", - "fitness", - "flag", - "flame", - "flash-off", - "flash", - "flashlight", - "flask", - "flower", - "folder-open", - "folder", - "football", - "footsteps", - "funnel", - "game-controller", - "gift", - "git-branch", - "git-commit", - "git-compare", - "git-merge", - "git-network", - "git-pull-request", - "glasses", - "globe", - "golf", - "grid", - "hammer", - "hand-left", - "hand-right", - "happy", - "hardware-chip", - "headset", - "heart-circle", - "heart-dislike-circle", - "heart-dislike", - "heart-half", - "heart", - "help-buoy", - "help-circle", - "help", - "home", - "hourglass", - "ice-cream", - "id-card", - "image", - "images", - "infinite", - "information-circle", - "information", - "invert-mode", - "journal", - "key", - "keypad", - "language", - "laptop", - "layers", - "leaf", - "library", - "link", - "list-circle", - "list", - "locate", - "location", - "lock-closed", - "lock-open", - "log-in", - "log-out", - "magnet", - "mail-open", - "mail", - "mail-unread", - "male-female", - "male", - "man", - "map", - "medal", - "medical", - "medkit", - "megaphone", - "menu", - "mic-circle", - "mic-off-circle", - "mic-off", - "mic", - "moon", - "move", - "musical-note", - "musical-notes", - "navigate-circle", - "navigate", - "newspaper", - "notifications-circle", - "notifications-off-circle", - "notifications-off", - "notifications", - "nuclear", - "nutrition", - "open", - "options", - "paper-plane", - "partly-sunny", - "pause-circle", - "pause", - "paw", - "people-circle", - "people", - "person-add", - "person-circle", - "person", - "person-remove", - "phone-landscape", - "phone-portrait", - "pie-chart", - "pin", - "pint", - "pizza", - "planet", - "play-back-circle", - "play-back", - "play-circle", - "play-forward-circle", - "play-forward", - "play", - "play-skip-back-circle", - "play-skip-back", - "play-skip-forward-circle", - "play-skip-forward", - "podium", - "power", - "pricetag", - "pricetags", - "print", - "prism", - "pulse", - "push", - "qr-code", - "radio-button-off", - "radio-button-on", - "radio", - "rainy", - "reader", - "receipt", - "recording", - "refresh-circle", - "refresh", - "reload-circle", - "reload", - "remove-circle", - "reorder-four", - "reorder-three", - "reorder-two", - "repeat", - "resize", - "restaurant", - "return-down-back", - "return-down-forward", - "return-up-back", - "return-up-forward", - "ribbon", - "rocket", - "rose", - "sad", - "save", - "scale", - "scan-circle", - "scan", - "school", - "search-circle", - "search", - "send", - "server", - "settings", - "shapes", - "share", - "share-social", - "shield-checkmark", - "shield-half", - "shield", - "shirt", - "shuffle", - "skull", - "snow", - "sparkles", - "speedometer", - "square", - "star-half", - "star", - "stats-chart", - "stop-circle", - "stop", - "stopwatch", - "storefront", - "subway", - "sunny", - "swap-horizontal", - "swap-vertical", - "sync-circle", - "sync", - "tablet-landscape", - "tablet-portrait", - "telescope", - "tennisball", - "terminal", - "text", - "thermometer", - "thumbs-down", - "thumbs-up", - "thunderstorm", - "ticket", - "time", - "timer", - "today", - "toggle", - "trail-sign", - "train", - "transgender", - "trash-bin", - "trash", - "trending-down", - "trending-up", - "triangle", - "trophy", - "tv", - "umbrella", - "unlink", - "videocam-off", - "videocam", - "volume-high", - "volume-low", - "volume-medium", - "volume-mute", - "volume-off", - "walk", - "wallet", - "warning", - "watch", - "water", - "wifi", - "wine", - "woman", - "logo-alipay", - "logo-amazon", - "logo-amplify", - "logo-android", - "logo-angular", - "logo-apple", - "logo-apple-appstore", - "logo-apple-ar", - "logo-behance", - "logo-bitbucket", - "logo-bitcoin", - "logo-buffer", - "logo-capacitor", - "logo-chrome", - "logo-closed-captioning", - "logo-codepen", - "logo-css3", - "logo-designernews", - "logo-deviantart", - "logo-discord", - "logo-docker", - "logo-dribbble", - "logo-dropbox", - "logo-edge", - "logo-electron", - "logo-euro", - "logo-facebook", - "logo-figma", - "logo-firebase", - "logo-firefox", - "logo-flickr", - "logo-foursquare", - "logo-github", - "logo-gitlab", - "logo-google", - "logo-google-playstore", - "logo-hackernews", - "logo-html5", - "logo-instagram", - "logo-ionic", - "logo-ionitron", - "logo-javascript", - "logo-laravel", - "logo-linkedin", - "logo-markdown", - "logo-mastodon", - "logo-medium", - "logo-microsoft", - "logo-no-smoking", - "logo-nodejs", - "logo-npm", - "logo-octocat", - "logo-paypal", - "logo-pinterest", - "logo-playstation", - "logo-pwa", - "logo-python", - "logo-react", - "logo-reddit", - "logo-rss", - "logo-sass", - "logo-skype", - "logo-slack", - "logo-snapchat", - "logo-soundcloud", - "logo-stackoverflow", - "logo-steam", - "logo-stencil", - "logo-tableau", - "logo-tiktok", - "logo-tumblr", - "logo-tux", - "logo-twitch", - "logo-twitter", - "logo-usd", - "logo-venmo", - "logo-vercel", - "logo-vimeo", - "logo-vk", - "logo-vue", - "logo-web-component", - "logo-wechat", - "logo-whatsapp", - "logo-windows", - "logo-wordpress", - "logo-xbox", - "logo-xing", - "logo-yahoo", - "logo-yen", - "logo-youtube" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the icon will be announced by screen readers." + }, + { + "name": "fillColor", + "type": "string", + "required": false, + "default": null, + "description": "Sets a custom fill color for the icon. Accepts any valid CSS color value." + }, + { + "name": "inverted", + "type": "string | boolean", + "values": [ + "string", + "boolean" + ], + "required": false, + "default": null, + "description": "When true, inverts the icon colors for use on dark backgrounds." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "opacity", + "type": "number", + "required": false, + "default": "1", + "description": "Sets the opacity of the icon from 0 (transparent) to 1 (opaque)." + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "img", + "description": "Sets the ARIA role for the icon. Use 'presentation' for decorative icons." + }, + { + "name": "size", + "type": "GoabIconSize", + "required": false, + "default": "medium", + "description": "Sets the size of the icon. Accepts numeric (1-6) or named sizes." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "theme", + "type": "GoabIconTheme", + "required": false, + "default": "outline", + "description": "Sets the icon theme. 'outline' shows stroked icons, 'filled' shows solid icons." + }, + { + "name": "title", + "type": "string", + "required": false, + "default": null, + "description": "Adds an accessible title to the icon SVG. Used by screen readers." + }, + { + "name": "type", + "type": "GoabIconType | GoabIconOverridesType", + "values": [ + "GoabIconType", + "GoabIconOverridesType" + ], + "required": true, + "default": null, + "description": "The icon type to display. See GoabIconType for available icons." + } ], - "required": true, - "default": null, - "description": "The icon type to display. See GoAIconType for available icons." + "events": [], + "slots": [] }, - { - "name": "size", - "type": "\"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"2xsmall\" | \"xsmall\" | \"small\" | \"medium\" | \"large\" | \"xlarge\"", - "values": [ - "1", - "2", - "3", - "4", - "5", - "6", - "2xsmall", - "xsmall", - "small", - "medium", - "large", - "xlarge" + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the icon will be announced by screen readers." + }, + { + "name": "fillColor", + "type": "string", + "required": false, + "default": null, + "description": "Sets a custom fill color for the icon. Accepts any valid CSS color value." + }, + { + "name": "inverted", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, inverts the icon colors for use on dark backgrounds." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "opacity", + "type": "number", + "required": false, + "default": null, + "description": "Sets the opacity of the icon from 0 (transparent) to 1 (opaque)." + }, + { + "name": "role", + "type": "string", + "required": false, + "default": null, + "description": "Sets the ARIA role for the icon. Use 'presentation' for decorative icons." + }, + { + "name": "size", + "type": "GoabIconSize", + "required": false, + "default": "medium", + "description": "Sets the size of the icon. Accepts numeric (1-6) or named sizes." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "theme", + "type": "GoabIconTheme", + "required": false, + "default": null, + "description": "Sets the icon theme. 'outline' shows stroked icons, 'filled' shows solid icons." + }, + { + "name": "title", + "type": "string", + "required": false, + "default": null, + "description": "Adds an accessible title to the icon SVG. Used by screen readers." + }, + { + "name": "type", + "type": "GoabIconType | GoabIconOverridesType", + "values": [ + "GoabIconType", + "GoabIconOverridesType" + ], + "required": true, + "default": null, + "description": "The icon type to display. See GoabIconType for available icons." + } ], - "required": false, - "default": "medium", - "description": "Sets the size of the icon. Accepts numeric (1-6) or named sizes." + "events": [], + "slots": [] }, - { - "name": "theme", - "type": "\"outline\" | \"filled\"", - "values": [ - "outline", - "filled" + "webComponents": { + "props": [ + { + "name": "ariacontrols", + "type": "string", + "required": false, + "default": "", + "description": "Identifies the element(s) whose contents or presence are controlled by this icon." + }, + { + "name": "ariaexpanded", + "type": "string", + "required": false, + "default": "", + "description": "Indicates whether the element controlled by this icon is expanded or collapsed." + }, + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Defines how the icon will be announced by screen readers." + }, + { + "name": "fillcolor", + "type": "string", + "required": false, + "default": "", + "description": "Sets a custom fill color for the icon. Accepts any valid CSS color value." + }, + { + "name": "inverted", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, inverts the icon colors for use on dark backgrounds." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "opacity", + "type": "number", + "required": false, + "default": "1", + "description": "Sets the opacity of the icon from 0 (transparent) to 1 (opaque)." + }, + { + "name": "role", + "type": "string", + "required": false, + "default": "img", + "description": "Sets the ARIA role for the icon. Defaults to 'img'. Use 'presentation' for decorative icons." + }, + { + "name": "size", + "type": "\"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"2xsmall\" | \"xsmall\" | \"small\" | \"medium\" | \"large\" | \"xlarge\"", + "values": [ + "1", + "2", + "3", + "4", + "5", + "6", + "2xsmall", + "xsmall", + "small", + "medium", + "large", + "xlarge" + ], + "required": false, + "default": "medium", + "description": "Sets the size of the icon. Accepts numeric (1-6) or named sizes." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "theme", + "type": "\"outline\" | \"filled\"", + "values": [ + "outline", + "filled" + ], + "required": false, + "default": "outline", + "description": "Sets the icon theme. 'outline' shows stroked icons, 'filled' shows solid icons." + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "", + "description": "Adds an accessible title to the icon SVG. Used by screen readers." + }, + { + "name": "type", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": true, + "default": null, + "description": "The icon type to display. See GoAIconType for available icons." + } ], - "required": false, - "default": "outline", - "description": "Sets the icon theme. 'outline' shows stroked icons, 'filled' shows solid icons." - }, - { - "name": "inverted", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, inverts the icon colors for use on dark backgrounds." - }, - { - "name": "fillcolor", - "type": "string", - "required": false, - "default": "", - "description": "Sets a custom fill color for the icon. Accepts any valid CSS color value." - }, - { - "name": "opacity", - "type": "number", - "required": false, - "default": "1", - "description": "Sets the opacity of the icon from 0 (transparent) to 1 (opaque)." - }, - { - "name": "title", - "type": "string", - "required": false, - "default": "", - "description": "Adds an accessible title to the icon SVG. Used by screen readers." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Defines how the icon will be announced by screen readers." - }, - { - "name": "ariacontrols", - "type": "string", - "required": false, - "default": "", - "description": "Identifies the element(s) whose contents or presence are controlled by this icon." - }, - { - "name": "ariaexpanded", - "type": "string", - "required": false, - "default": "", - "description": "Indicates whether the element controlled by this icon is expanded or collapsed." - }, - { - "name": "role", - "type": "string", - "required": false, - "default": "img", - "description": "Sets the ARIA role for the icon. Defaults to 'img'. Use 'presentation' for decorative icons." + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/input.json b/docs/generated/component-apis/input.json index 9faee7dc10..cd970d6efc 100644 --- a/docs/generated/component-apis/input.json +++ b/docs/generated/component-apis/input.json @@ -1,375 +1,919 @@ { "componentSlug": "input", "extractedFrom": "libs/web-components/src/components/input/Input.svelte", - "props": [ - { - "name": "type", - "type": "\"text\" | \"number\" | \"password\" | \"email\" | \"date\" | \"datetime-local\" | \"month\" | \"range\" | \"search\" | \"tel\" | \"time\" | \"url\" | \"week\"", - "typeLabel": "GoabInputType", - "values": [ - "text", - "number", - "password", - "email", - "date", - "datetime-local", - "month", - "range", - "search", - "tel", - "time", - "url", - "week" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Sets the aria-label used by assistive technologies." + }, + { + "name": "autoCapitalize", + "type": "GoabAutoCapitalize", + "required": false, + "default": null, + "description": "Controls automatic capitalization behavior on supported mobile browsers." + }, + { + "name": "autoComplete", + "type": "string", + "required": false, + "default": null, + "description": "Sets the autocomplete attribute for the input element." + }, + { + "name": "debounce", + "type": "number", + "required": false, + "default": null, + "description": "Debounce delay in milliseconds before firing the change event. 0 means no debounce." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the input disabled state." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the error state styling." + }, + { + "name": "focused", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets focus on initial render or controlled updates." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute of the input element." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Sets the icon shown before the value." + }, + { + "name": "max", + "type": "number | string", + "values": [ + "number", + "string" + ], + "required": false, + "default": null, + "description": "Maximum value. Supports any number, or ISO 8601 format for date/datetime types." + }, + { + "name": "maxLength", + "type": "number", + "required": false, + "default": null, + "description": "Sets the maximum number of characters." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "min", + "type": "number | string", + "values": [ + "number", + "string" + ], + "required": false, + "default": null, + "description": "Minimum value. Supports any number, or ISO 8601 format for date/datetime types." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "Name of input value that is received in event detail payloads." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": null, + "description": "Sets placeholder text when the input is empty." + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the readonly state." + }, + { + "name": "size", + "type": "GoabInputSize", + "required": false, + "default": "default", + "description": "Sets the input size." + }, + { + "name": "step", + "type": "number", + "required": false, + "default": "1", + "description": "How much a number or date value should change by." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "textAlign", + "type": "\"left\" | \"right\"", + "values": [ + "left", + "right" + ], + "required": false, + "default": "left", + "description": "Sets text alignment." + }, + { + "name": "trailingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Sets the icon shown after the value." + }, + { + "name": "trailingIconAriaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Sets the aria-label for an interactive trailing icon." + }, + { + "name": "type", + "type": "GoabInputType", + "required": false, + "default": "text", + "description": "Sets the type of the input field." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "Bound to the current value of the input field." + }, + { + "name": "variant", + "type": "\"goa\" | \"bare\"", + "values": [ + "goa", + "bare" + ], + "required": false, + "default": "goa", + "description": "Sets the visual style variant." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets the width of the input field." + } ], - "required": false, - "default": "text", - "description": "Sets the type of the input field." - }, - { - "name": "name", - "type": "string", - "required": false, - "default": "", - "description": "Name of input value that is received in the onChange event." - }, - { - "name": "value", - "type": "string", - "required": false, - "default": "", - "description": "Bound to value." - }, - { - "name": "autoCapitalize", - "type": "\"on\" | \"off\" | \"none\" | \"sentences\" | \"words\" | \"characters\"", - "typeLabel": "GoabInputAutoCapitalize", - "values": [ - "on", - "off", - "none", - "sentences", - "words", - "characters" - ], - "required": false, - "default": "off", - "description": "Controls whether and how text input is automatically capitalized as it is entered/edited by the user. This only works on mobile devices." - }, - { - "name": "autoComplete", - "type": "string", - "required": false, - "default": "", - "description": "Specifies the autocomplete attribute for the input field." - }, - { - "name": "placeholder", - "type": "string", - "required": false, - "default": "", - "description": "Text displayed within the input when no value is set." - }, - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon shown to the left of the text." - }, - { - "name": "trailingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon shown to the right of the text." - }, - { - "name": "variant", - "type": "\"goa\" | \"bare\"", - "values": [ - "goa", - "bare" + "events": [ + { + "name": "onBlur", + "type": "(detail: GoabInputOnBlurDetail) => void", + "description": "Callback fired when the input loses focus. Receives GoabInputOnBlurDetail.", + "frameworks": [ + "react" + ] + }, + { + "name": "onChange", + "type": "(detail: GoabInputOnChangeDetail) => void", + "description": "Callback fired when the input value changes. Receives GoabInputOnChangeDetail.", + "frameworks": [ + "react" + ] + }, + { + "name": "onFocus", + "type": "(detail: GoabInputOnFocusDetail) => void", + "description": "Callback fired when the input receives focus. Receives GoabInputOnFocusDetail.", + "frameworks": [ + "react" + ] + }, + { + "name": "onKeyPress", + "type": "(detail: GoabInputOnKeyPressDetail) => void", + "description": "Callback fired when a key is pressed in the input. Receives GoabInputOnKeyPressDetail.", + "frameworks": [ + "react" + ] + }, + { + "name": "onTrailingIconClick", + "type": "() => void", + "description": "Callback fired when the trailing icon is clicked.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "goa", - "description": "Sets the visual style variant. 'goa' for standard GoA styling, 'bare' for minimal styling." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disables this input. The input will not receive focus or events. Use [attr.disabled] with [formControl]." - }, - { - "name": "handleTrailingIconClick", - "type": "boolean", - "required": false, - "default": "false", - "description": "Flag that will result in an icon button component being rendered instead of an icon." - }, - { - "name": "focused", - "type": "boolean", - "required": false, - "default": "false", - "description": "Sets the cursor focus to the input." - }, - { - "name": "readOnly", - "type": "boolean", - "required": false, - "default": "false", - "description": "Makes the input readonly." - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Sets the input to an error state." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "30ch", - "description": "Sets the width of the text input area." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Defines how the input will be translated for the screen reader. If not specified it will fall back to the name." - }, - { - "name": "ariaLabelledBy", - "type": "string", - "required": false, - "default": "", - "description": "The aria-labelledby attribute identifies the element (or elements) that labels the input." - }, - { - "name": "min", - "type": "string", - "required": false, - "default": "", - "description": "A string value that supports any number, or an ISO 8601 format if using the date or datetime type." - }, - { - "name": "max", - "type": "string", - "required": false, - "default": "", - "description": "A string value that supports any number, or an ISO 8601 format if using the date or datetime type." - }, - { - "name": "step", - "type": "number", - "required": false, - "default": "1", - "description": "How much a number or date should change by." - }, - { - "name": "prefix", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated Use leadingContent slot instead.", - "deprecated": true - }, - { - "name": "suffix", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated Use trailingContent slot instead.", - "deprecated": true - }, - { - "name": "debounce", - "type": "number", - "required": false, - "default": "0", - "description": "Debounce delay in milliseconds before firing the change event. 0 means no debounce." - }, - { - "name": "maxLength", - "type": "number", - "required": false, - "default": null, - "description": "Defines the maximum number of characters (as UTF-16 code units) the user can enter into the input." - }, - { - "name": "id", - "type": "string", - "required": false, - "default": "", - "description": "Unique identifier for the input element. Used for label associations and accessibility." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "trailingIconAriaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Aria label for the trailing icon. Use only when the trailing icon is interactive." + "slots": [ + { + "name": "leadingContent", + "type": "ReactNode", + "description": "Sets content in the leading slot.", + "required": false + }, + { + "name": "trailingContent", + "type": "ReactNode", + "description": "Sets content in the trailing slot.", + "required": false + } + ] }, - { - "name": "textAlign", - "type": "\"left\" | \"right\"", - "typeLabel": "GoabInputTextAlign", - "values": [ - "left", - "right" + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the input will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "ariaLabelledBy", + "type": "string", + "required": false, + "default": null, + "description": "The aria-labelledby attribute identifies the element (or elements) that labels the input." + }, + { + "name": "autoCapitalize", + "type": "GoabInputAutoCapitalize", + "required": false, + "default": null, + "description": "Controls whether and how text input is automatically capitalized as it is entered/edited by the user. This only works on mobile devices." + }, + { + "name": "autoComplete", + "type": "string", + "required": false, + "default": null, + "description": "Specifies the autocomplete attribute for the input field." + }, + { + "name": "debounce", + "type": "number", + "required": false, + "default": null, + "description": "Debounce delay in milliseconds before firing the change event. 0 means no debounce." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the disabled state for the control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the error state for the control." + }, + { + "name": "focused", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the cursor focus to the input." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute of the underlying web component." + }, + { + "name": "leadingContent", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "Sets the leading content slot, accepting a string or template reference." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon shown to the left of the text." + }, + { + "name": "max", + "type": "string | number", + "values": [ + "string", + "number" + ], + "required": false, + "default": null, + "description": "A string value that supports any number, or an ISO 8601 format if using the date or datetime type." + }, + { + "name": "maxLength", + "type": "number", + "required": false, + "default": null, + "description": "Sets the maximum number of characters (as UTF-16 code units) the user can enter into the input." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "min", + "type": "string | number", + "values": [ + "string", + "number" + ], + "required": false, + "default": null, + "description": "A string value that supports any number, or an ISO 8601 format if using the date or datetime type." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Name of input value that is received in the onChange event." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": null, + "description": "Text displayed within the input when no value is set." + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": null, + "description": "Makes the input readonly." + }, + { + "name": "size", + "type": "GoabInputSize", + "required": false, + "default": "default", + "description": "Sets the size of the input. 'compact' reduces height for dense layouts." + }, + { + "name": "step", + "type": "number", + "required": false, + "default": null, + "description": "How much a number or date should change by." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "textAlign", + "type": "\"left\" | \"right\"", + "values": [ + "left", + "right" + ], + "required": false, + "default": "left", + "description": "Sets the text alignment within the input field." + }, + { + "name": "trailingContent", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "Sets the trailing content slot, accepting a string or template reference." + }, + { + "name": "trailingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon shown to the right of the text." + }, + { + "name": "trailingIconAriaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Aria label for the trailing icon. Use only when the trailing icon is interactive." + }, + { + "name": "type", + "type": "GoabInputType", + "required": false, + "default": "text", + "description": "Sets the type of the input field." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "Sets the control value used by Angular forms and one-way binding." + }, + { + "name": "variant", + "type": "string", + "required": false, + "default": null, + "description": "Sets the visual style variant. 'goa' for standard GoA styling, 'bare' for minimal styling." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets the width of the text input area." + } ], - "required": false, - "default": "left", - "description": "Sets the text alignment within the input field." - }, - { - "name": "size", - "type": "\"default\" | \"compact\"", - "values": [ - "default", - "compact" + "events": [ + { + "name": "onBlur", + "type": "(event: GoabInputOnBlurDetail) => void", + "description": "Emits when the input loses focus. Emits blur detail including the current value.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onChange", + "type": "(event: GoabInputOnChangeDetail) => void", + "description": "Emits when the input value changes. Emits change detail including the new value.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onFocus", + "type": "(event: GoabInputOnFocusDetail) => void", + "description": "Emits when the input receives focus. Emits focus detail including the current value.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onKeyPress", + "type": "(event: GoabInputOnKeyPressDetail) => void", + "description": "Emits when a key is pressed in the input. Emits key press detail including the value and key pressed.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onTrailingIconClick", + "type": "() => void", + "description": "Emits when the trailing icon is clicked.", + "frameworks": [ + "angular" + ] + } ], - "required": false, - "default": "default", - "description": "Sets the size of the input. 'compact' reduces height for dense layouts." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "slots": [ + { + "name": "leadingContent", + "type": "TemplateRef", + "description": "Sets content in the leading slot.", + "required": false + }, + { + "name": "trailingContent", + "type": "TemplateRef", + "description": "Sets content in the trailing slot.", + "required": false + } ] }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - }, - { - "name": "onKeyPress", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_keyPress", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - }, - { - "name": "onFocus", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_focus", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - }, - { - "name": "onBlur", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_blur", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - }, - { - "name": "onTrailingIconClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_trailingIconClick", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "webComponents": { + "props": [ + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Defines how the input will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "arialabelledby", + "type": "string", + "required": false, + "default": "", + "description": "The aria-labelledby attribute identifies the element (or elements) that labels the input." + }, + { + "name": "autocapitalize", + "type": "\"on\" | \"off\" | \"none\" | \"sentences\" | \"words\" | \"characters\"", + "typeLabel": "GoabInputAutoCapitalize", + "values": [ + "on", + "off", + "none", + "sentences", + "words", + "characters" + ], + "required": false, + "default": "off", + "description": "Controls whether and how text input is automatically capitalized as it is entered/edited by the user. This only works on mobile devices." + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "", + "description": "Specifies the autocomplete attribute for the input field." + }, + { + "name": "debounce", + "type": "number", + "required": false, + "default": "0", + "description": "Debounce delay in milliseconds before firing the change event. 0 means no debounce." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disables this input. The input will not receive focus or events. Use [attr.disabled] with [formControl]." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Sets the input to an error state." + }, + { + "name": "focused", + "type": "boolean", + "required": false, + "default": "false", + "description": "Sets the cursor focus to the input." + }, + { + "name": "handletrailingiconclick", + "type": "boolean", + "required": false, + "default": "false", + "description": "Flag that will result in an icon button component being rendered instead of an icon." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": "", + "description": "Unique identifier for the input element. Used for label associations and accessibility." + }, + { + "name": "leadingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon shown to the left of the text." + }, + { + "name": "max", + "type": "string", + "required": false, + "default": "", + "description": "A string value that supports any number, or an ISO 8601 format if using the date or datetime type." + }, + { + "name": "maxlength", + "type": "number", + "required": false, + "default": null, + "description": "Defines the maximum number of characters (as UTF-16 code units) the user can enter into the input." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "min", + "type": "string", + "required": false, + "default": "", + "description": "A string value that supports any number, or an ISO 8601 format if using the date or datetime type." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "", + "description": "Name of input value that is received in the onChange event." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "", + "description": "Text displayed within the input when no value is set." + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false", + "description": "Makes the input readonly." + }, + { + "name": "size", + "type": "\"default\" | \"compact\"", + "values": [ + "default", + "compact" + ], + "required": false, + "default": "default", + "description": "Sets the size of the input. 'compact' reduces height for dense layouts." + }, + { + "name": "step", + "type": "number", + "required": false, + "default": "1", + "description": "How much a number or date should change by." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "textalign", + "type": "\"left\" | \"right\"", + "typeLabel": "GoabInputTextAlign", + "values": [ + "left", + "right" + ], + "required": false, + "default": "left", + "description": "Sets the text alignment within the input field." + }, + { + "name": "trailingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon shown to the right of the text." + }, + { + "name": "trailingiconarialabel", + "type": "string", + "required": false, + "default": "", + "description": "Aria label for the trailing icon. Use only when the trailing icon is interactive." + }, + { + "name": "type", + "type": "\"text\" | \"number\" | \"password\" | \"email\" | \"date\" | \"datetime-local\" | \"month\" | \"range\" | \"search\" | \"tel\" | \"time\" | \"url\" | \"week\"", + "typeLabel": "GoabInputType", + "values": [ + "text", + "number", + "password", + "email", + "date", + "datetime-local", + "month", + "range", + "search", + "tel", + "time", + "url", + "week" + ], + "required": false, + "default": "text", + "description": "Sets the type of the input field." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "", + "description": "Bound to value." + }, + { + "name": "variant", + "type": "\"goa\" | \"bare\"", + "values": [ + "goa", + "bare" + ], + "required": false, + "default": "goa", + "description": "Sets the visual style variant. 'goa' for standard GoA styling, 'bare' for minimal styling." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "30ch", + "description": "Sets the width of the text input area." + } + ], + "events": [ + { + "name": "_blur", + "type": "CustomEvent<{ name: string; value: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_change", + "type": "CustomEvent<{ name: string; value: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_focus", + "type": "CustomEvent<{ name: string; value: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_keyPress", + "type": "CustomEvent<{ name: string; value: string; key: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_trailingIconClick", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "leadingContent", + "description": "Sets content in the leading slot.", + "required": false + }, + { + "name": "trailingContent", + "description": "Sets content in the trailing slot.", + "required": false + } ] } - ], - "slots": [ - { - "name": "leadingContent", - "description": "" - }, - { - "name": "trailingContent", - "description": "" - } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/linear-progress.json b/docs/generated/component-apis/linear-progress.json index 22c95b034e..cde8d504ae 100644 --- a/docs/generated/component-apis/linear-progress.json +++ b/docs/generated/component-apis/linear-progress.json @@ -1,47 +1,147 @@ { "componentSlug": "linear-progress", "extractedFrom": "libs/web-components/src/components/linear-progress/LinearProgress.svelte", - "props": [ - { - "name": "testId", - "type": "string", - "required": false, - "default": null, - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "progress", - "type": "number", - "required": false, - "default": null, - "description": "Progress value (0-100). When undefined, shows an indeterminate loading animation." - }, - { - "name": "percentVisibility", - "type": "\"visible\" | \"hidden\"", - "values": [ - "visible", - "hidden" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Accessible label for the progress bar." + }, + { + "name": "ariaLabelledBy", + "type": "string", + "required": false, + "default": null, + "description": "ID of the element that labels this progress bar." + }, + { + "name": "percentVisibility", + "type": "\"visible\" | \"hidden\" | undefined", + "values": [ + "visible", + "hidden" + ], + "required": false, + "default": "visible", + "description": "Controls visibility of the percentage text." + }, + { + "name": "progress", + "type": "number | null", + "values": [ + "number" + ], + "required": false, + "default": null, + "description": "Progress value (0-100). When undefined, shows an indeterminate loading animation." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } ], - "required": false, - "default": "visible", - "description": "Controls visibility of the percentage text." + "events": [], + "slots": [] }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": null, - "description": "Accessible label for the progress bar." + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Accessible label for the progress bar." + }, + { + "name": "ariaLabelledBy", + "type": "string", + "required": false, + "default": null, + "description": "ID of the element that labels this progress bar." + }, + { + "name": "percentVisibility", + "type": "\"visible\" | \"hidden\" | undefined", + "values": [ + "visible", + "hidden" + ], + "required": false, + "default": null, + "description": "Controls visibility of the percentage text." + }, + { + "name": "progress", + "type": "number | null | undefined", + "values": [ + "number" + ], + "required": false, + "default": null, + "description": "Progress value (0-100). When undefined, shows an indeterminate loading animation." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "ariaLabelledBy", - "type": "string", - "required": false, - "default": null, - "description": "ID of the element that labels this progress bar." + "webComponents": { + "props": [ + { + "name": "aria-label", + "type": "string", + "required": false, + "default": null, + "description": "Accessible label for the progress bar." + }, + { + "name": "aria-labelledby", + "type": "string", + "required": false, + "default": null, + "description": "ID of the element that labels this progress bar." + }, + { + "name": "percent-visibility", + "type": "\"visible\" | \"hidden\"", + "values": [ + "visible", + "hidden" + ], + "required": false, + "default": "visible", + "description": "Controls visibility of the percentage text." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": null, + "description": "Progress value (0-100). When undefined, shows an indeterminate loading animation." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/link-button.json b/docs/generated/component-apis/link-button.json index 29e3670db3..0662149eaa 100644 --- a/docs/generated/component-apis/link-button.json +++ b/docs/generated/component-apis/link-button.json @@ -1,112 +1,59 @@ { "componentSlug": "link-button", "extractedFrom": "libs/web-components/src/components/link-button/LinkButton.svelte", - "props": [ - { - "name": "color", - "type": "\"interactive\" | \"light\"", - "values": [ - "interactive", - "light" + "frameworks": { + "react": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + } ], - "required": false, - "default": "interactive", - "description": "@deprecated Use GoabButton instead. Sets the color theme. 'interactive' for blue, 'light' for white on dark backgrounds.", - "deprecated": true - }, - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": true, - "default": null, - "description": "@deprecated Use GoabButton instead. Icon displayed before the button text.", - "deprecated": true - }, - { - "name": "trailingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": true, - "default": null, - "description": "@deprecated Use GoabButton instead. Icon displayed after the button text.", - "deprecated": true - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "@deprecated Use GoabButton instead. When true, prevents user interaction and applies disabled styling.", - "deprecated": true - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated Use GoabButton instead. Sets a data-testid attribute for automated testing.", - "deprecated": true - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "@deprecated Use GoabButton instead. Top margin.", - "deprecated": true - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "@deprecated Use GoabButton instead. Right margin.", - "deprecated": true - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "@deprecated Use GoabButton instead. Bottom margin.", - "deprecated": true - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "@deprecated Use GoabButton instead. Left margin.", - "deprecated": true - } - ], - "events": [ - { - "name": "onClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_click", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "events": [], + "slots": [] + }, + "angular": { + "props": [], + "events": [], + "slots": [] + }, + "webComponents": { + "props": [], + "events": [ + { + "name": "_click", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/link.json b/docs/generated/component-apis/link.json index fbd438df74..6081a67e95 100644 --- a/docs/generated/component-apis/link.json +++ b/docs/generated/component-apis/link.json @@ -1,93 +1,293 @@ { "componentSlug": "link", "extractedFrom": "libs/web-components/src/components/link/Link.svelte", - "props": [ - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed before the link text." - }, - { - "name": "trailingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed after the link text." - }, - { - "name": "color", - "type": "\"interactive\" | \"dark\" | \"light\"", - "values": [ - "interactive", - "dark", - "light" + "frameworks": { + "react": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": null, + "description": "Custom action event name to dispatch when the link is clicked." + }, + { + "name": "actionArg", + "type": "string", + "required": false, + "default": null, + "description": "Single argument to pass with the action event. Deprecated, use actionArgs instead." + }, + { + "name": "actionArgs", + "type": "Record", + "required": false, + "default": null, + "description": "Object of arguments to pass with the action event." + }, + { + "name": "color", + "type": "GoabLinkColor", + "required": false, + "default": "interactive", + "description": "Sets the color theme. 'interactive' for blue, 'dark' for black, 'light' for white text." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the link text." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "size", + "type": "GoabLinkSize", + "required": false, + "default": "medium", + "description": "Sets the text size and corresponding icon size." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "trailingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed after the link text." + } ], - "required": false, - "default": "interactive", - "description": "Sets the color theme. 'interactive' for blue, 'dark' for black, 'light' for white text." + "events": [], + "slots": [] }, - { - "name": "size", - "type": "\"xsmall\" | \"small\" | \"medium\" | \"large\"", - "values": [ - "xsmall", - "small", - "medium", - "large" + "angular": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": null, + "description": "Custom action event name to dispatch when the link is clicked." + }, + { + "name": "actionArg", + "type": "string", + "required": false, + "default": null, + "description": "Single argument to pass with the action event (deprecated, use actionArgs)." + }, + { + "name": "actionArgs", + "type": "Record", + "required": false, + "default": null, + "description": "Object of arguments to pass with the action event." + }, + { + "name": "color", + "type": "GoabLinkColor", + "required": false, + "default": "interactive", + "description": "Sets the color theme. 'interactive' for blue, 'dark' for black, 'light' for white text." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the link text." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "size", + "type": "GoabLinkSize", + "required": false, + "default": "medium", + "description": "Sets the text size and corresponding icon size." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "trailingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed after the link text." + } ], - "required": false, - "default": "medium", - "description": "Sets the text size and corresponding icon size." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." + "events": [], + "slots": [] }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": "", + "description": "Custom action event name to dispatch when the link is clicked." + }, + { + "name": "action-arg", + "type": "string", + "required": false, + "default": "", + "description": "Single argument to pass with the action event (deprecated, use actionArgs)." + }, + { + "name": "action-args", + "type": "Record", + "required": false, + "default": "{}", + "description": "Object of arguments to pass with the action event." + }, + { + "name": "color", + "type": "\"interactive\" | \"dark\" | \"light\"", + "values": [ + "interactive", + "dark", + "light" + ], + "required": false, + "default": "interactive", + "description": "Sets the color theme. 'interactive' for blue, 'dark' for black, 'light' for white text." + }, + { + "name": "leadingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the link text." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "size", + "type": "\"xsmall\" | \"small\" | \"medium\" | \"large\"", + "values": [ + "xsmall", + "small", + "medium", + "large" + ], + "required": false, + "default": "medium", + "description": "Sets the text size and corresponding icon size." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "trailingicon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed after the link text." + } + ], + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/menu-action.json b/docs/generated/component-apis/menu-action.json index be59c631e3..db60330145 100644 --- a/docs/generated/component-apis/menu-action.json +++ b/docs/generated/component-apis/menu-action.json @@ -1,37 +1,109 @@ { "componentSlug": "menu-action", "extractedFrom": "libs/web-components/src/components/menu-button/MenuAction.svelte", - "props": [ - { - "name": "text", - "type": "string", - "required": false, - "default": "", - "description": "Display text for the menu action." + "frameworks": { + "react": { + "props": [ + { + "name": "action", + "type": "string", + "required": true, + "default": null, + "description": "Action identifier included in the click event." + }, + { + "name": "icon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the text." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": true, + "default": null, + "description": "Display text for the menu action." + } + ], + "events": [], + "slots": [] }, - { - "name": "action", - "type": "string", - "required": false, - "default": "default", - "description": "Action identifier included in the click event." + "angular": { + "props": [ + { + "name": "action", + "type": "string", + "required": true, + "default": null, + "description": "Action identifier included in the click event." + }, + { + "name": "icon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the text." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": true, + "default": null, + "description": "Display text for the menu action." + } + ], + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "icon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed before the text." + "webComponents": { + "props": [ + { + "name": "action", + "type": "string", + "required": false, + "default": "default", + "description": "Action identifier included in the click event." + }, + { + "name": "icon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the text." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": false, + "default": "", + "description": "Display text for the menu action." + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] -} + } +} \ No newline at end of file diff --git a/docs/generated/component-apis/menu-button.json b/docs/generated/component-apis/menu-button.json index ac9450c0d9..19afcb6b89 100644 --- a/docs/generated/component-apis/menu-button.json +++ b/docs/generated/component-apis/menu-button.json @@ -1,100 +1,244 @@ { "componentSlug": "menu-button", "extractedFrom": "libs/web-components/src/components/menu-button/MenuButton.svelte", - "props": [ - { - "name": "text", - "type": "string", - "required": false, - "default": "", - "description": "The button label text. When provided, displays as a text button with a dropdown icon." - }, - { - "name": "type", - "type": "\"primary\" | \"secondary\" | \"tertiary\"", - "values": [ - "primary", - "secondary", - "tertiary" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": "Open menu", + "description": "Sets the aria-label for the icon button in icon-only mode." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the button text. When no text is provided, displays as an icon button." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Maximum width of the dropdown menu." + }, + { + "name": "size", + "type": "GoabButtonSize", + "required": false, + "default": "normal", + "description": "Sets the size of the button." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": false, + "default": null, + "description": "The button label text. When provided, displays as a text button with a dropdown icon." + }, + { + "name": "type", + "type": "GoabButtonType", + "required": false, + "default": "primary", + "description": "The button style variant." + }, + { + "name": "variant", + "type": "GoabButtonVariant", + "required": false, + "default": "normal", + "description": "Sets the color variant for semantic meaning." + } ], - "required": false, - "default": "primary", - "description": "The button style variant." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "leadingIcon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed before the button text. When no text is provided, displays as an icon button." - }, - { - "name": "maxWidth", - "type": "string", - "required": true, - "default": null, - "description": "Maximum width of the dropdown menu." - }, - { - "name": "size", - "type": "\"normal\" | \"compact\"", - "values": [ - "normal", - "compact" + "events": [ + { + "name": "onAction", + "type": "(detail: GoabMenuButtonOnActionDetail) => void", + "description": "Callback fired when a menu action is selected.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "normal", - "description": "Sets the size of the button." + "slots": [] }, - { - "name": "variant", - "type": "\"normal\" | \"destructive\"", - "values": [ - "normal", - "destructive" + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Sets the aria-label for the icon button in icon-only mode." + }, + { + "name": "leadingIcon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the button text. When no text is provided, displays as an icon button." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Maximum width of the dropdown menu." + }, + { + "name": "size", + "type": "GoabButtonSize", + "required": false, + "default": null, + "description": "Sets the size of the button." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": false, + "default": null, + "description": "The button label text. When provided, displays as a text button with a dropdown icon." + }, + { + "name": "type", + "type": "GoabButtonType", + "required": false, + "default": null, + "description": "The button style variant." + }, + { + "name": "variant", + "type": "GoabButtonVariant", + "required": false, + "default": null, + "description": "Sets the color variant for semantic meaning." + } ], - "required": false, - "default": "normal", - "description": "Sets the color variant for semantic meaning." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "Open menu", - "description": "Sets the aria-label for the icon button in icon-only mode." - } - ], - "events": [ - { - "name": "onAction", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "events": [ + { + "name": "onAction", + "type": "(event: GoabMenuButtonOnActionDetail) => void", + "description": "Emits when a menu action is clicked. Emits the action detail.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_action", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "aria-label", + "type": "string", + "required": false, + "default": "Open menu", + "description": "Sets the aria-label for the icon button in icon-only mode." + }, + { + "name": "leading-icon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the button text. When no text is provided, displays as an icon button." + }, + { + "name": "max-width", + "type": "string", + "required": true, + "default": null, + "description": "Maximum width of the dropdown menu." + }, + { + "name": "size", + "type": "\"normal\" | \"compact\"", + "values": [ + "normal", + "compact" + ], + "required": false, + "default": "normal", + "description": "Sets the size of the button." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "text", + "type": "string", + "required": false, + "default": "", + "description": "The button label text. When provided, displays as a text button with a dropdown icon." + }, + { + "name": "type", + "type": "\"primary\" | \"secondary\" | \"tertiary\"", + "values": [ + "primary", + "secondary", + "tertiary" + ], + "required": false, + "default": "primary", + "description": "The button style variant." + }, + { + "name": "variant", + "type": "\"normal\" | \"destructive\"", + "values": [ + "normal", + "destructive" + ], + "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": [ + { + "name": "_action", + "type": "CustomEvent<{ action?: string; size?: \"normal\" | \"compact\" }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/microsite-header.json b/docs/generated/component-apis/microsite-header.json index fa93c3147f..344a340926 100644 --- a/docs/generated/component-apis/microsite-header.json +++ b/docs/generated/component-apis/microsite-header.json @@ -1,102 +1,229 @@ { "componentSlug": "microsite-header", "extractedFrom": "libs/web-components/src/components/microsite-header/MicrositeHeader.svelte", - "props": [ - { - "name": "type", - "type": "\"live\" | \"alpha\" | \"beta\"", - "typeLabel": "GoabMicrositeHeaderType", - "values": [ - "live", - "alpha", - "beta" + "frameworks": { + "react": { + "props": [ + { + "name": "feedbackUrl", + "type": "string", + "required": false, + "default": null, + "description": "URL to a feedback page displayed when provided." + }, + { + "name": "feedbackUrlTarget", + "type": "GoabLinkTarget", + "required": false, + "default": "blank", + "description": "Sets the target attribute for the feedback URL link." + }, + { + "name": "headerUrlTarget", + "type": "GoabLinkTarget", + "required": false, + "default": "blank", + "description": "Sets the target attribute for the header link." + }, + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": "100%", + "description": "Maximum width of the content area." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabServiceLevel", + "required": true, + "default": null, + "description": "The service type which determines the badge style. \"live\" shows official government site text, \"alpha\" and \"beta\" show development stage badges." + }, + { + "name": "version", + "type": "string | React.ReactNode", + "values": [ + "string", + "React.ReactNode" + ], + "required": false, + "default": null, + "description": "App or service version displayed on the right side of the header." + } ], - "required": true, - "default": null, - "description": "The service type which determines the badge style. \"live\" shows official government site text, \"alpha\" and \"beta\" show development stage badges." - }, - { - "name": "version", - "type": "string", - "required": false, - "default": "", - "description": "App or service version displayed on the right side of the header." - }, - { - "name": "feedbackurl", - "type": "string", - "required": false, - "default": "", - "description": "Url to feedback page that will be displayed when provided." - }, - { - "name": "maxcontentwidth", - "type": "any", - "required": false, - "default": "100%", - "description": "Maximum width of the content area" - }, - { - "name": "headerurltarget", - "type": "\"self\" | \"blank\"", - "typeLabel": "GoabMicrositeHeaderUrlTargetType", - "values": [ - "self", - "blank" + "events": [ + { + "name": "onFeedbackClick", + "type": "() => void", + "description": "Callback fired when the feedback link is clicked, enables custom feedback handling.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "blank", - "description": "Sets the target attribute for the header link." + "slots": [] }, - { - "name": "feedbackurltarget", - "type": "\"self\" | \"blank\"", - "typeLabel": "GoabMicrositeHeaderUrlTargetType", - "values": [ - "self", - "blank" + "angular": { + "props": [ + { + "name": "feedbackUrl", + "type": "string", + "required": false, + "default": null, + "description": "Url to feedback page that will be displayed when provided." + }, + { + "name": "feedbackUrlTarget", + "type": "GoabLinkTarget", + "required": false, + "default": null, + "description": "For internal feedback urls sets target." + }, + { + "name": "headerUrlTarget", + "type": "GoabLinkTarget", + "required": false, + "default": null, + "description": "Sets the target attribute for the header link." + }, + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": null, + "description": "Maximum width of the content area." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabServiceLevel", + "required": true, + "default": null, + "description": "The service type which determines the badge style. \"live\" shows official government site text, \"alpha\" and \"beta\" show development stage badges." + }, + { + "name": "version", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "App or service version displayed on the right side of the header." + } ], - "required": false, - "default": "blank", - "description": "For internal feedback urls sets target=" - }, - { - "name": "hasfeedbackhandler", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, enables a custom feedback click handler via the _feedbackClick event instead of navigating to feedbackurl." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - } - ], - "events": [ - { - "name": "onFeedbackClick", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "events": [ + { + "name": "onFeedbackClick", + "type": "() => void", + "description": "Emits when the feedback link is clicked.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_feedbackClick", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "version", - "description": "" + "webComponents": { + "props": [ + { + "name": "feedbackurl", + "type": "string", + "required": false, + "default": "", + "description": "Url to feedback page that will be displayed when provided." + }, + { + "name": "feedbackurltarget", + "type": "\"self\" | \"blank\"", + "typeLabel": "GoabMicrositeHeaderUrlTargetType", + "values": [ + "self", + "blank" + ], + "required": false, + "default": "blank", + "description": "For internal feedback urls sets target=" + }, + { + "name": "hasfeedbackhandler", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, enables a custom feedback click handler via the _feedbackClick event instead of navigating to feedbackurl." + }, + { + "name": "headerurltarget", + "type": "\"self\" | \"blank\"", + "typeLabel": "GoabMicrositeHeaderUrlTargetType", + "values": [ + "self", + "blank" + ], + "required": false, + "default": "blank", + "description": "Sets the target attribute for the header link." + }, + { + "name": "maxcontentwidth", + "type": "string", + "required": false, + "default": "100%", + "description": "Maximum width of the content area" + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"live\" | \"alpha\" | \"beta\"", + "typeLabel": "GoabMicrositeHeaderType", + "values": [ + "live", + "alpha", + "beta" + ], + "required": true, + "default": null, + "description": "The service type which determines the badge style. \"live\" shows official government site text, \"alpha\" and \"beta\" show development stage badges." + }, + { + "name": "version", + "type": "string", + "required": false, + "default": "", + "description": "App or service version displayed on the right side of the header." + } + ], + "events": [ + { + "name": "_feedbackClick", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/modal.json b/docs/generated/component-apis/modal.json index 592278d64c..3cf62ec18b 100644 --- a/docs/generated/component-apis/modal.json +++ b/docs/generated/component-apis/modal.json @@ -1,105 +1,243 @@ { "componentSlug": "modal", "extractedFrom": "libs/web-components/src/components/modal/Modal.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": false, - "default": "", - "description": "The heading text displayed at the top of the modal." - }, - { - "name": "closable", - "type": "boolean", - "required": false, - "default": "false", - "description": "Show close icon and allow clicking the background to close the modal." - }, - { - "name": "open", - "type": "boolean", - "required": false, - "default": "false", - "description": "Controls if modal is visible or not." - }, - { - "name": "transition", - "type": "\"fast\" | \"slow\" | \"none\"", - "typeLabel": "GoabModalTransition", - "values": [ - "fast", - "slow", - "none" + "frameworks": { + "react": { + "props": [ + { + "name": "calloutVariant", + "type": "GoabModalCalloutVariant", + "required": false, + "default": null, + "description": "Sets the context and colour of the callout modal. Required when used as a callout type." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "60ch", + "description": "Set the max allowed width of the modal." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Controls if the modal is visible or not." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "transition", + "type": "GoabModalTransition", + "required": false, + "default": null, + "description": "Sets the animation transition when opening/closing. 'fast' or 'slow' for animated, 'none' for instant." + } ], - "required": false, - "default": "none", - "description": "Sets the animation transition when opening/closing. 'fast' or 'slow' for animated, 'none' for instant." - }, - { - "name": "calloutVariant", - "type": "\"\"", - "required": false, - "default": null, - "description": "Define the context and colour of the callout modal. It is required when type is set to callout." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "60ch", - "description": "Set the max allowed width of the modal." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "modal", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated Use maxwidth instead.", - "deprecated": true - } - ], - "events": [ - { - "name": "onClose", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "events": [ + { + "name": "onClose", + "type": "() => void", + "description": "Callback fired when the modal is closed. When provided, enables the close button and backdrop click-to-close behavior.", + "frameworks": [ + "react" + ] + } + ], + "slots": [ + { + "name": "actions", + "type": "ReactNode", + "description": "Content rendered in the modal's actions slot, typically action buttons.", + "required": false + }, + { + "name": "heading", + "type": "ReactNode", + "description": "The heading text displayed at the top of the modal.", + "required": false + } ] }, - { - "name": "_close", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "angular": { + "props": [ + { + "name": "calloutVariant", + "type": "GoabModalCalloutVariant", + "required": false, + "default": null, + "description": "Define the context and colour of the callout modal. It is required when type is set to callout." + }, + { + "name": "closable", + "type": "boolean", + "required": false, + "default": "false", + "description": "Show close icon and allow clicking the background to close the modal." + }, + { + "name": "heading", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "The heading text displayed at the top of the modal." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Set the max allowed width of the modal." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Controls if modal is visible or not." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "transition", + "type": "GoabModalTransition", + "required": false, + "default": null, + "description": "Sets the animation transition when opening/closing. 'fast' or 'slow' for animated, 'none' for instant." + } + ], + "events": [ + { + "name": "onClose", + "type": "() => void", + "description": "Emits when the modal is closed.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [ + { + "name": "actions", + "type": "TemplateRef", + "description": "Content rendered in the modal's actions slot, typically action buttons.", + "required": false + }, + { + "name": "heading", + "type": "TemplateRef", + "description": "The heading text displayed at the top of the modal.", + "required": false + } ] - } - ], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "heading", - "description": "" }, - { - "name": "content", - "description": "" - }, - { - "name": "actions", - "description": "" + "webComponents": { + "props": [ + { + "name": "calloutvariant", + "type": "\"\"", + "required": false, + "default": null, + "description": "Define the context and colour of the callout modal. It is required when type is set to callout." + }, + { + "name": "closable", + "type": "boolean", + "required": false, + "default": "false", + "description": "Show close icon and allow clicking the background to close the modal." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": "", + "description": "The heading text displayed at the top of the modal." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "60ch", + "description": "Set the max allowed width of the modal." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "Controls if modal is visible or not." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "modal", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "transition", + "type": "\"fast\" | \"slow\" | \"none\"", + "typeLabel": "GoabModalTransition", + "values": [ + "fast", + "slow", + "none" + ], + "required": false, + "default": "none", + "description": "Sets the animation transition when opening/closing. 'fast' or 'slow' for animated, 'none' for instant." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "typeLabel": "GoabModalVersionType", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_close", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "actions", + "description": "Content rendered in the modal's actions slot, typically action buttons.", + "required": false + }, + { + "name": "heading", + "description": "The heading text displayed at the top of the modal.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/notification.json b/docs/generated/component-apis/notification.json index 8f6ac51b2a..2a16d6fd14 100644 --- a/docs/generated/component-apis/notification.json +++ b/docs/generated/component-apis/notification.json @@ -1,90 +1,206 @@ { "componentSlug": "notification", "extractedFrom": "libs/web-components/src/components/notification/Notification.svelte", - "props": [ - { - "name": "type", - "type": "\"emergency\" | \"important\" | \"information\" | \"event\"", - "typeLabel": "GoabNotificationType", - "values": [ - "emergency", - "important", - "information", - "event" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLive", + "type": "GoabAriaLiveType", + "required": false, + "default": "polite", + "description": "Indicates how assistive technology should handle updates to the live region." + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, reduces padding for a more compact notification." + }, + { + "name": "emphasis", + "type": "GoabNotificationEmphasis", + "required": false, + "default": "high", + "description": "Sets the visual prominence. 'high' for full background, 'low' for a bordered style." + }, + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": "100%", + "description": "Maximum width of the content area." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabNotificationType", + "required": false, + "default": null, + "description": "Define the context and colour of the notification." + } ], - "required": false, - "default": "", - "description": "Define the context and colour of the notification." - }, - { - "name": "maxcontentwidth", - "type": "any", - "required": false, - "default": "100%", - "description": "Maximum width of the content area." - }, - { - "name": "arialive", - "type": "\"assertive\" | \"off\" | \"polite\"", - "typeLabel": "GoabNotificationAriaLiveType", - "values": [ - "assertive", - "off", - "polite" + "events": [ + { + "name": "onDismiss", + "type": "() => void", + "description": "Callback fired when the notification is dismissed.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "polite", - "description": "Indicates how assistive technology should handle updates to the live region." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "slots": [] }, - { - "name": "emphasis", - "type": "\"high\" | \"low\"", - "typeLabel": "GoabNotificationEmphasisType", - "values": [ - "high", - "low" + "angular": { + "props": [ + { + "name": "ariaLive", + "type": "GoabAriaLiveType", + "required": false, + "default": null, + "description": "Indicates how assistive technology should handle updates to the live region." + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, reduces padding for a more compact notification." + }, + { + "name": "emphasis", + "type": "GoabNotificationEmphasis", + "required": false, + "default": "high", + "description": "Sets the visual prominence. 'high' for full background, 'low' for medium." + }, + { + "name": "maxContentWidth", + "type": "string", + "required": false, + "default": null, + "description": "Maximum width of the content area." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabNotificationType", + "required": false, + "default": "information", + "description": "Define the context and colour of the notification." + } ], - "required": false, - "default": "high", - "description": "Sets the visual prominence. 'high' for full background, 'filled' for medium." - }, - { - "name": "compact", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, reduces padding for a more compact notification." - } - ], - "events": [ - { - "name": "onDismiss", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "events": [ + { + "name": "onDismiss", + "type": "() => void", + "description": "Emits when the notification is dismissed.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_dismiss", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "arialive", + "type": "\"assertive\" | \"off\" | \"polite\"", + "typeLabel": "GoabNotificationAriaLiveType", + "values": [ + "assertive", + "off", + "polite" + ], + "required": false, + "default": "polite", + "description": "Indicates how assistive technology should handle updates to the live region." + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, reduces padding for a more compact notification." + }, + { + "name": "emphasis", + "type": "\"high\" | \"low\"", + "typeLabel": "GoabNotificationEmphasisType", + "values": [ + "high", + "low" + ], + "required": false, + "default": "high", + "description": "Sets the visual prominence. 'high' for full background, 'filled' for medium." + }, + { + "name": "maxcontentwidth", + "type": "string", + "required": false, + "default": "100%", + "description": "Maximum width of the content area." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"emergency\" | \"important\" | \"information\" | \"event\"", + "typeLabel": "GoabNotificationType", + "values": [ + "emergency", + "important", + "information", + "event" + ], + "required": false, + "default": "", + "description": "Define the context and colour of the notification." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_dismiss", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/page-block.json b/docs/generated/component-apis/page-block.json index a38dd13162..f1e3f2c7cc 100644 --- a/docs/generated/component-apis/page-block.json +++ b/docs/generated/component-apis/page-block.json @@ -1,31 +1,70 @@ { "componentSlug": "page-block", "extractedFrom": "libs/web-components/src/components/page-block/PageBlock.svelte", - "props": [ - { - "name": "width", - "type": "\"full\" | string", - "values": [ - "full", - "string" + "frameworks": { + "react": { + "props": [ + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "width", + "type": "GoabPageBlockSize", + "required": false, + "default": "full", + "description": "Maximum width of the content area. Use \"full\" for 100% width or a CSS dimension like \"1200px\"." + } ], - "required": false, - "default": "full", - "description": "Maximum width of the content area. Use \"full\" for 100% width or a CSS dimension like \"1200px\"." + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "angular": { + "props": [ + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "width", + "type": "GoabPageBlockSize", + "required": false, + "default": null, + "description": "Maximum width of the content area. Use \"full\" for 100% width or a CSS dimension like \"1200px\"." + } + ], + "events": [], + "slots": [] + }, + "webComponents": { + "props": [ + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "width", + "type": "\"full\" | string", + "values": [ + "full", + "string" + ], + "required": false, + "default": "full", + "description": "Maximum width of the content area. Use \"full\" for 100% width or a CSS dimension like \"1200px\"." + } + ], + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/pages.json b/docs/generated/component-apis/pages.json index 11a1560d9a..b70b21aa75 100644 --- a/docs/generated/component-apis/pages.json +++ b/docs/generated/component-apis/pages.json @@ -1,52 +1,140 @@ { "componentSlug": "pages", "extractedFrom": "libs/web-components/src/components/pages/Pages.svelte", - "props": [ - { - "name": "current", - "type": "number", - "required": false, - "default": "1", - "description": "The currently visible page (1-based index)." + "frameworks": { + "react": { + "props": [ + { + "name": "current", + "type": "number", + "required": false, + "default": "1", + "description": "The currently visible page (1-based index)." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + } + ], + "events": [], + "slots": [] }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." + "angular": { + "props": [ + { + "name": "current", + "type": "number", + "required": false, + "default": null, + "description": "The currently visible page (1-based index)." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "current", + "type": "number", + "required": false, + "default": "1", + "description": "The currently visible page (1-based index)." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + } + ], + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/pagination.json b/docs/generated/component-apis/pagination.json index fd65d9187c..ea374f7ce4 100644 --- a/docs/generated/component-apis/pagination.json +++ b/docs/generated/component-apis/pagination.json @@ -1,97 +1,264 @@ { "componentSlug": "pagination", "extractedFrom": "libs/web-components/src/components/pagination/Pagination.svelte", - "props": [ - { - "name": "pagenumber", - "type": "number", - "required": true, - "default": null, - "description": "The current page being viewed (non-zero based)." - }, - { - "name": "itemcount", - "type": "number", - "required": true, - "default": null, - "description": "Total number of data items within all pages." - }, - { - "name": "perpagecount", - "type": "number", - "required": false, - "default": "10", - "description": "Number of data items shown per page." - }, - { - "name": "variant", - "type": "\"all\" | \"links-only\"", - "typeLabel": "GoabPaginationVariant", - "values": [ - "all", - "links-only" + "frameworks": { + "react": { + "props": [ + { + "name": "itemCount", + "type": "number", + "required": true, + "default": null, + "description": "Total number of data items within all pages." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "pageNumber", + "type": "number", + "required": true, + "default": null, + "description": "The current page being viewed (non-zero based)." + }, + { + "name": "perPageCount", + "type": "number", + "required": false, + "default": "10", + "description": "Number of data items shown per page." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "\"all\" | \"links-only\"", + "values": [ + "all", + "links-only" + ], + "required": false, + "default": "all", + "description": "Controls which nav controls are visible." + } ], - "required": false, - "default": "all", - "description": "Controls which nav controls are visible." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "none", - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "none", - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "m", - "description": "Bottom margin." + "events": [ + { + "name": "onChange", + "type": "(detail: GoabPaginationOnChangeDetail) => void", + "description": "Callback fired when the user navigates to a different page.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "none", - "description": "Left margin." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "itemCount", + "type": "number", + "required": true, + "default": null, + "description": "Total number of data items within all pages." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "pageNumber", + "type": "number", + "required": true, + "default": null, + "description": "The current page being viewed (non-zero based)." + }, + { + "name": "perPageCount", + "type": "number", + "required": false, + "default": "10", + "description": "Number of data items shown per page." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabPaginationVariant", + "required": false, + "default": "all", + "description": "Controls which nav controls are visible." + } + ], + "events": [ + { + "name": "onChange", + "type": "(event: GoabPaginationOnChangeDetail) => void", + "description": "Emits when the page changes. Emits the new page number as part of the change detail.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "itemcount", + "type": "number", + "required": true, + "default": null, + "description": "Total number of data items within all pages." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "m", + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "none", + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "none", + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "none", + "description": "Top margin." + }, + { + "name": "pagenumber", + "type": "number", + "required": true, + "default": null, + "description": "The current page being viewed (non-zero based)." + }, + { + "name": "perpagecount", + "type": "number", + "required": false, + "default": "10", + "description": "Number of data items shown per page." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "\"all\" | \"links-only\"", + "typeLabel": "GoabPaginationVariant", + "values": [ + "all", + "links-only" + ], + "required": false, + "default": "all", + "description": "Controls which nav controls are visible." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_change", + "type": "CustomEvent<{ page: number }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/popover.json b/docs/generated/component-apis/popover.json index ee57a4dfb6..40fa1637f0 100644 --- a/docs/generated/component-apis/popover.json +++ b/docs/generated/component-apis/popover.json @@ -1,215 +1,331 @@ { "componentSlug": "popover", "extractedFrom": "libs/web-components/src/components/popover/Popover.svelte", - "props": [ - { - "name": "testId", - "type": "string", - "required": false, - "default": "popover", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "position", - "type": "\"above\" | \"below\" | \"auto\"", - "values": [ - "above", - "below", - "auto" - ], - "required": false, - "default": "auto", - "description": "Provides control to where the popover content is positioned." - }, - { - "name": "maxWidth", - "type": "string | \"none\"", - "values": [ - "string", - "none" - ], - "required": false, - "default": "320px", - "description": "Sets the maximum width of the popover container." - }, - { - "name": "minwidth", - "type": "string", - "required": false, - "default": "", - "description": "Sets the minimum width of the popover container." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "", - "description": "Sets a fixed width for the popover container." - }, - { - "name": "height", - "type": "\"full\" | \"wrap-content\"", - "values": [ - "full", - "wrap-content" + "frameworks": { + "react": { + "props": [ + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "320px", + "description": "Sets the maximum width of the popover container." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "minWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the minimum width of the popover container." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "padded", + "type": "boolean", + "required": false, + "default": "true", + "description": "Sets if the popover has padding. Use false when content needs to be flush with boundaries." + }, + { + "name": "position", + "type": "GoabPopoverPosition", + "required": false, + "default": "auto", + "description": "Provides control to where the popover content is positioned." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } ], - "required": false, - "default": "wrap-content", - "description": "Controls the height behavior. 'full' stretches to parent height, 'wrap-content' fits content." - }, - { - "name": "preventScrollIntoView", - "type": "boolean", - "required": false, - "default": "false", - "description": "Prevents scrolling into view when focus trap is activated. Passed to FocusTrap." - }, - { - "name": "padded", - "type": "boolean", - "required": false, - "default": "true", - "description": "Sets if the popover has padding. Use false when content needs to be flush with boundaries." - }, - { - "name": "tabIndex", - "type": "number", - "required": false, - "default": "0", - "description": "Sets the tabindex. Use -1 to skip tabbing when a parent handles keyboard events." - }, - { - "name": "relative", - "type": "string", - "required": false, - "default": "", - "description": "@deprecated This property has no effect and will be removed in a future version.", - "deprecated": true - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - }, - { - "name": "open", - "type": "boolean", - "required": false, - "default": "false", - "description": "Controls whether the popover is open or closed. Used by parent components like AppHeaderMenu." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disables the popover interaction. Used by parent components like Dropdown." - }, - { - "name": "voffset", - "type": "any", - "required": false, - "default": "", - "description": "Additional vertical offset added to the popover's position." - }, - { - "name": "hoffset", - "type": "any", - "required": false, - "default": "", - "description": "Additional horizontal offset added to the popover's position." - }, - { - "name": "focusborderwidth", - "type": "any", - "required": false, - "default": "var(--goa-border-width-l)", - "description": "Width of the focus outline border." - }, - { - "name": "borderradius", - "type": "any", - "required": false, - "default": "var(--goa-border-radius-m)", - "description": "Border radius of the popover window." - }, - { - "name": "filterablecontext", - "type": "boolean", - "required": false, - "default": "false", - "description": "Indicates the popover is used within a filterable context like a combobox." - } - ], - "events": [ - { - "name": "onOpen", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "events": [], + "slots": [ + { + "name": "target", + "type": "ReactNode", + "description": "Sets the element used as the popover trigger.", + "required": true + } ] }, - { - "name": "_open", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - }, - { - "name": "onClose", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "angular": { + "props": [ + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "320px", + "description": "Sets the maximum width of the popover container." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "minWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the minimum width of the popover container." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "padded", + "type": "boolean", + "required": false, + "default": "true", + "description": "Sets if the popover has padding. Use false when content needs to be flush with boundaries." + }, + { + "name": "position", + "type": "GoabPopoverPosition", + "required": false, + "default": null, + "description": "Provides control to where the popover content is positioned." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [ + { + "name": "target", + "type": "TemplateRef", + "description": "Sets the element used as the popover trigger.", + "required": true + } ] }, - { - "name": "_close", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "webComponents": { + "props": [ + { + "name": "borderradius", + "type": "string", + "required": false, + "default": "var(--goa-border-radius-m)", + "description": "Border radius of the popover window." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disables the popover interaction. Used by parent components like Dropdown." + }, + { + "name": "focusborderwidth", + "type": "string", + "required": false, + "default": "var(--goa-border-width-l)", + "description": "Width of the focus outline border." + }, + { + "name": "height", + "type": "\"full\" | \"wrap-content\"", + "values": [ + "full", + "wrap-content" + ], + "required": false, + "default": "wrap-content", + "description": "Controls the height behavior. 'full' stretches to parent height, 'wrap-content' fits content." + }, + { + "name": "hoffset", + "type": "string", + "required": false, + "default": "", + "description": "Additional horizontal offset added to the popover's position." + }, + { + "name": "maxwidth", + "type": "string | \"none\"", + "values": [ + "string", + "none" + ], + "required": false, + "default": "320px", + "description": "Sets the maximum width of the popover container." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "minwidth", + "type": "string", + "required": false, + "default": "", + "description": "Sets the minimum width of the popover container." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "Controls the open state of the popover programmatically. Used by Dropdown, AppHeaderMenu." + }, + { + "name": "padded", + "type": "boolean", + "required": false, + "default": "true", + "description": "Sets if the popover has padding. Use false when content needs to be flush with boundaries." + }, + { + "name": "position", + "type": "\"above\" | \"below\" | \"right\" | \"auto\"", + "values": [ + "above", + "below", + "right", + "auto" + ], + "required": false, + "default": "auto", + "description": "Provides control to where the popover content is positioned." + }, + { + "name": "tabindex", + "type": "number", + "required": false, + "default": "0", + "description": "Sets the tabindex. Use -1 to skip tabbing when a parent handles keyboard events." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "popover", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "voffset", + "type": "string", + "required": false, + "default": "", + "description": "Additional vertical offset added to the popover's position." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "", + "description": "Sets a fixed width for the popover container." + } + ], + "events": [ + { + "name": "_close", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_open", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "target", + "description": "Sets the element used as the popover trigger.", + "required": true + } ] } - ], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "target", - "description": "" - } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/push-drawer.json b/docs/generated/component-apis/push-drawer.json index 41d1a3e8bd..184d4a51f7 100644 --- a/docs/generated/component-apis/push-drawer.json +++ b/docs/generated/component-apis/push-drawer.json @@ -1,45 +1,170 @@ { "componentSlug": "push-drawer", "extractedFrom": "libs/web-components/src/components/push-drawer/PushDrawer.svelte", - "props": [ - { - "name": "testId", - "type": "string", - "required": false, - "default": null, - "description": "" + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string | ReactNode", + "values": [ + "string", + "ReactNode" + ], + "required": false, + "default": null, + "description": "Sets the heading text or custom heading content." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Controls the open/closed state of the push drawer." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "492px", + "description": "Sets the width of the push drawer panel." + } + ], + "events": [ + { + "name": "onClose", + "type": "() => void", + "description": "Callback fired when the push drawer is closed.", + "frameworks": [ + "react" + ] + } + ], + "slots": [ + { + "name": "actions", + "type": "ReactNode", + "description": "Content rendered in the actions slot, typically action buttons.", + "required": false + } + ] }, - { - "name": "open", - "type": "boolean", - "required": false, - "default": "false", - "description": "" + "angular": { + "props": [ + { + "name": "heading", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "Sets the heading text or template for the push drawer." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the open state of the push drawer." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Sets the width of the push drawer panel." + } + ], + "events": [ + { + "name": "onClose", + "type": "() => void", + "description": "Emits when the push drawer closes.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [ + { + "name": "actions", + "type": "TemplateRef", + "description": "Content rendered in the actions slot, typically action buttons.", + "required": false + } + ] }, - { - "name": "heading", - "type": "string", - "required": false, - "default": "", - "description": "" - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "492px", - "description": "" - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "actions", - "description": "" + "webComponents": { + "props": [ + { + "name": "heading", + "type": "string", + "required": false, + "default": "", + "description": "" + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "" + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": null, + "description": "" + }, + { + "name": "version", + "type": "string", + "required": false, + "default": null, + "description": "" + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "492px", + "description": "" + } + ], + "events": [ + { + "name": "_close", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "actions", + "description": "Content rendered in the actions slot, typically action buttons.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/radio-group.json b/docs/generated/component-apis/radio-group.json index 7c04d97a54..024b1ebf0c 100644 --- a/docs/generated/component-apis/radio-group.json +++ b/docs/generated/component-apis/radio-group.json @@ -1,128 +1,343 @@ { "componentSlug": "radio-group", "extractedFrom": "libs/web-components/src/components/radio-group/RadioGroup.svelte", - "props": [ - { - "name": "name", - "type": "string", - "required": true, - "default": null, - "description": "The name for the radio group. Used for accessibility and change events." - }, - { - "name": "value", - "type": "string", - "required": true, - "default": null, - "description": "The currently selected value in the radio group." - }, - { - "name": "orientation", - "type": "\"vertical\" | \"horizontal\"", - "typeLabel": "GoabRadioGroupOrientation", - "values": [ - "vertical", - "horizontal" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the radio group will be announced by screen readers." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disables all radio items in the group." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows an error state on all radio items in the group." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "The identifier for the radio group element." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "The name for the radio group. Used for accessibility and change events." + }, + { + "name": "orientation", + "type": "GoabRadioGroupOrientation", + "required": false, + "default": "vertical", + "description": "Sets the layout direction. 'vertical' stacks items, 'horizontal' places them in a row." + }, + { + "name": "size", + "type": "GoabRadioGroupSize", + "required": false, + "default": "default", + "description": "Sets the size of all radio items. 'compact' reduces spacing for dense layouts." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "The currently selected value in the radio group." + } ], - "required": false, - "default": "vertical", - "description": "Sets the layout direction. 'vertical' stacks items, 'horizontal' places them in a row." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disables all radio items in the group." - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Shows an error state on all radio items in the group." - }, - { - "name": "size", - "type": "\"default\" | \"compact\"", - "typeLabel": "GoabRadioGroupSizeType", - "values": [ - "default", - "compact" + "events": [ + { + "name": "onChange", + "type": "(detail: GoabRadioGroupOnChangeDetail) => void", + "description": "Callback fired when the selected radio item changes.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "default", - "description": "Sets the size of all radio items. 'compact' reduces spacing for dense layouts (V2 only)." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Defines how the radio group will be announced by screen readers." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." + "slots": [] }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the radio group will be announced by screen readers." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the disabled state for the control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the error state for the control." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute of the underlying web component." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "The name for the radio group. Used for accessibility and change events." + }, + { + "name": "orientation", + "type": "GoabRadioGroupOrientation", + "required": false, + "default": null, + "description": "Sets the layout direction. 'vertical' stacks items, 'horizontal' places them in a row." + }, + { + "name": "size", + "type": "GoabRadioGroupSize", + "required": false, + "default": "default", + "description": "Sets the size of all radio items. 'compact' reduces spacing for dense layouts (V2 only)." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "The currently selected value in the radio group." + } + ], + "events": [ + { + "name": "onChange", + "type": "(event: GoabRadioGroupOnChangeDetail) => void", + "description": "Emits when the selected radio item changes. Emits the name, value, and event of the selected item.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Defines how the radio group will be announced by screen readers." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disables all radio items in the group." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Shows an error state on all radio items in the group." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "The name for the radio group. Used for accessibility and change events." + }, + { + "name": "orientation", + "type": "\"vertical\" | \"horizontal\"", + "typeLabel": "GoabRadioGroupOrientation", + "values": [ + "vertical", + "horizontal" + ], + "required": false, + "default": "vertical", + "description": "Sets the layout direction. 'vertical' stacks items, 'horizontal' places them in a row." + }, + { + "name": "size", + "type": "\"default\" | \"compact\"", + "typeLabel": "GoabRadioGroupSizeType", + "values": [ + "default", + "compact" + ], + "required": false, + "default": "default", + "description": "Sets the size of all radio items. 'compact' reduces spacing for dense layouts (V2 only)." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": true, + "default": null, + "description": "The currently selected value in the radio group." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "typeLabel": "GoabRadioGroupVersionType", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_change", + "type": "CustomEvent<{ name: string; value: string; label: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/radio-item.json b/docs/generated/component-apis/radio-item.json index 13e6d1b66c..a308213638 100644 --- a/docs/generated/component-apis/radio-item.json +++ b/docs/generated/component-apis/radio-item.json @@ -1,152 +1,376 @@ { "componentSlug": "radio-item", "extractedFrom": "libs/web-components/src/components/radio-item/RadioItem.svelte", - "props": [ - { - "name": "value", - "type": "string", - "required": true, - "default": null, - "description": "The value of this radio option. Will be emitted when selected." - }, - { - "name": "name", - "type": "string", - "required": false, - "default": "", - "description": "The name of the radio group. Inherited from the parent RadioGroup if not set." - }, - { - "name": "label", - "type": "string", - "required": false, - "default": "", - "description": "The display label for this radio option. Falls back to value if not provided." - }, - { - "name": "description", - "type": "string", - "required": false, - "default": "", - "description": "Additional description text displayed below the label." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Disables this radio option. Also disabled if the parent RadioGroup is disabled." - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Shows an error state on this radio option." - }, - { - "name": "checked", - "type": "boolean", - "required": false, - "default": "false", - "description": "Sets this radio option as checked/selected." - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Defines how this option will be announced by screen readers." - }, - { - "name": "revealarialabel", - "type": "string", - "required": false, - "default": "", - "description": "Text announced by screen readers when the reveal slot content is displayed." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "none", - "description": "Sets the maximum width of this radio item." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onRevealChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how this option will be announced by screen readers." + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": null, + "description": "Reduces spacing for dense layouts." + }, + { + "name": "description", + "type": "string | React.ReactNode", + "values": [ + "string", + "React.ReactNode" + ], + "required": false, + "default": null, + "description": "Additional description text displayed below the label." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disables this radio option. Also disabled if the parent RadioGroup is disabled." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows an error state on this radio option." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": null, + "description": "The display label for this radio option. Falls back to value if not provided." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of this radio item." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "The name of the radio group. Inherited from the parent RadioGroup if not set." + }, + { + "name": "revealAriaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Text announced by screen readers when the reveal content is displayed." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "The value of this radio option. Will be emitted when selected." + } + ], + "events": [], + "slots": [ + { + "name": "description", + "type": "ReactNode", + "description": "Additional description text displayed below the label.", + "required": false + }, + { + "name": "reveal", + "type": "ReactNode", + "description": "Content revealed below the radio option when it is selected.", + "required": false + } ] }, - { - "name": "_revealChange", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how this option will be announced by screen readers." + }, + { + "name": "compact", + "type": "boolean", + "required": false, + "default": null, + "description": "Enables compact layout for the radio item, reducing spacing for dense layouts." + }, + { + "name": "description", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "Additional description text displayed below the label." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Disables this radio option. Also disabled if the parent RadioGroup is disabled." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Shows an error state on this radio option." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": null, + "description": "The display label for this radio option. Falls back to value if not provided." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of this radio item." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "The name of the radio group. Inherited from the parent RadioGroup if not set." + }, + { + "name": "revealAriaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Text announced by screen readers when the reveal slot content is displayed." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "The value of this radio option. Will be emitted when selected." + } + ], + "events": [], + "slots": [ + { + "name": "description", + "type": "TemplateRef", + "description": "Additional description text displayed below the label.", + "required": false + }, + { + "name": "reveal", + "type": "TemplateRef", + "description": "Content revealed below the radio option when it is selected.", + "required": false + } ] }, - { - "name": "onRadioItemChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "webComponents": { + "props": [ + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Defines how this option will be announced by screen readers." + }, + { + "name": "description", + "type": "string", + "required": false, + "default": "", + "description": "Additional description text displayed below the label." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Disables this radio option. Also disabled if the parent RadioGroup is disabled." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Shows an error state on this radio option." + }, + { + "name": "label", + "type": "string", + "required": false, + "default": "", + "description": "The display label for this radio option. Falls back to value if not provided." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "none", + "description": "Sets the maximum width of this radio item." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "", + "description": "The name of the radio group. Inherited from the parent RadioGroup if not set." + }, + { + "name": "revealarialabel", + "type": "string", + "required": false, + "default": "", + "description": "Text announced by screen readers when the reveal slot content is displayed." + }, + { + "name": "value", + "type": "string", + "required": true, + "default": null, + "description": "The value of this radio option. Will be emitted when selected." + } + ], + "events": [ + { + "name": "_radioItemChange", + "type": "CustomEvent<{ value: string; label: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "description", + "description": "Additional description text displayed below the label.", + "required": false + }, + { + "name": "reveal", + "description": "Content revealed below the radio option when it is selected.", + "required": false + } ] - }, - { - "name": "_radioItemChange", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "description", - "description": "" - }, - { - "name": "reveal", - "description": "" } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/scrollable.json b/docs/generated/component-apis/scrollable.json deleted file mode 100644 index 4c2302a60a..0000000000 --- a/docs/generated/component-apis/scrollable.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "componentSlug": "scrollable", - "extractedFrom": "libs/web-components/src/components/scrollable/Scrollable.svelte", - "props": [ - { - "name": "direction", - "type": "\"vertical\" | \"horizontal\"", - "values": [ - "vertical", - "horizontal" - ], - "required": false, - "default": "vertical", - "description": "The scroll direction." - }, - { - "name": "hpadding", - "type": "string", - "required": false, - "default": "", - "description": "Horizontal padding applied to the scrollable content." - }, - { - "name": "vpadding", - "type": "string", - "required": false, - "default": "", - "description": "Vertical padding applied to the scrollable content." - }, - { - "name": "maxHeight", - "type": "string", - "required": false, - "default": "", - "description": "Maximum height of the scrollable container. Defaults to 50vh if not specified." - }, - { - "name": "offsetHeight", - "type": "number", - "required": true, - "default": null, - "description": "The visible height of the scrollable area. Read-only, set by the component." - }, - { - "name": "scrollHeight", - "type": "number", - "required": true, - "default": null, - "description": "The total scrollable height including overflow. Read-only, set by the component." - } - ], - "events": [ - { - "name": "onScroll", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_scroll", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" - } - ] -} \ No newline at end of file diff --git a/docs/generated/component-apis/side-menu-group.json b/docs/generated/component-apis/side-menu-group.json index ff25664e78..62c22fe5a7 100644 --- a/docs/generated/component-apis/side-menu-group.json +++ b/docs/generated/component-apis/side-menu-group.json @@ -1,84 +1,187 @@ { "componentSlug": "side-menu-group", "extractedFrom": "libs/web-components/src/components/side-menu-group/SideMenuGroup.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": true, - "default": null, - "description": "The heading text for the menu group." + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The heading text for the menu group." + }, + { + "name": "icon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed alongside the heading." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "icon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed alongside the heading." + "angular": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The heading text for the menu group." + }, + { + "name": "icon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed alongside the heading." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onOpen", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_open", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The heading text for the menu group." + }, + { + "name": "icon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed alongside the heading." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "testid", + "type": "string", + "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": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/side-menu-heading.json b/docs/generated/component-apis/side-menu-heading.json index b68372cac7..4b704adcaf 100644 --- a/docs/generated/component-apis/side-menu-heading.json +++ b/docs/generated/component-apis/side-menu-heading.json @@ -1,32 +1,98 @@ { "componentSlug": "side-menu-heading", "extractedFrom": "libs/web-components/src/components/side-menu-heading/SideMenuHeading.svelte", - "props": [ - { - "name": "icon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed before the heading text." + "frameworks": { + "react": { + "props": [ + { + "name": "icon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the heading text." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [ + { + "name": "meta", + "type": "ReactNode", + "description": "Content rendered in the meta slot, displayed alongside the heading.", + "required": false + } + ] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "section-heading", - "description": "Sets a data-testid attribute for automated testing." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "angular": { + "props": [ + { + "name": "icon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the heading text." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [ + { + "name": "meta", + "type": "TemplateRef", + "description": "Content rendered in the meta slot, displayed alongside the heading.", + "required": false + } + ] }, - { - "name": "meta", - "description": "" + "webComponents": { + "props": [ + { + "name": "icon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the heading text." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "section-heading", + "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": [], + "slots": [ + { + "name": "meta", + "description": "Content rendered in the meta slot, displayed alongside the heading.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/side-menu.json b/docs/generated/component-apis/side-menu.json index c1abe89ed3..873b802c8c 100644 --- a/docs/generated/component-apis/side-menu.json +++ b/docs/generated/component-apis/side-menu.json @@ -1,20 +1,56 @@ { "componentSlug": "side-menu", "extractedFrom": "libs/web-components/src/components/side-menu/SideMenu.svelte", - "props": [ - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "frameworks": { + "react": { + "props": [ + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] + }, + "angular": { + "props": [ + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] + }, + "webComponents": { + "props": [ + { + "name": "testid", + "type": "string", + "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": [], + "slots": [] } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/skeleton.json b/docs/generated/component-apis/skeleton.json index c65fc48a86..34cf431346 100644 --- a/docs/generated/component-apis/skeleton.json +++ b/docs/generated/component-apis/skeleton.json @@ -1,97 +1,239 @@ { "componentSlug": "skeleton", "extractedFrom": "libs/web-components/src/components/skeleton/Skeleton.svelte", - "props": [ - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "300px", - "description": "Sets the maximum width. Currently only used in card skeleton type." - }, - { - "name": "size", - "type": "\"1\" | \"2\" | \"3\" | \"4\"", - "typeLabel": "GoabSkeletonSize", - "values": [ - "1", - "2", - "3", - "4" + "frameworks": { + "react": { + "props": [ + { + "name": "lineCount", + "type": "number", + "required": false, + "default": "3", + "description": "Used within components that contain multiple lines. Currently only used in card skeleton type." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "300px", + "description": "Sets the maximum width. Currently only used in card skeleton type." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "size", + "type": "GoabSkeletonSize", + "required": false, + "default": "1", + "description": "Size can affect either the height, width or both for different skeleton types." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabSkeletonType", + "required": true, + "default": null, + "description": "Sets the skeleton shape to represent your content." + } ], - "required": false, - "default": "1", - "description": "Size can affect either the height, width or both for different skeleton types." - }, - { - "name": "linecount", - "type": "number", - "required": false, - "default": "3", - "description": "Used within components that contain multiple lines. Currently only used in card skeleton type" + "events": [], + "slots": [] }, - { - "name": "type", - "type": "\"image\" | \"text\" | \"title\" | \"text-small\" | \"avatar\" | \"header\" | \"paragraph\" | \"thumbnail\" | \"card\" | \"lines\" | \"profile\" | \"article\"", - "typeLabel": "GoabSkeletonType", - "values": [ - "image", - "text", - "title", - "text-small", - "avatar", - "header", - "paragraph", - "thumbnail", - "card", - "lines", - "profile", - "article" + "angular": { + "props": [ + { + "name": "lineCount", + "type": "number", + "required": false, + "default": null, + "description": "Used within components that contain multiple lines. Currently only used in card skeleton type." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "300px", + "description": "Sets the maximum width. Currently only used in card skeleton type." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "size", + "type": "GoabSkeletonSize", + "required": false, + "default": null, + "description": "Size can affect either the height, width or both for different skeleton types." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabSkeletonType", + "required": true, + "default": null, + "description": "Sets the skeleton shape to represent your content." + } ], - "required": true, - "default": null, - "description": "Sets the skeleton shape to represent your content." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." + "events": [], + "slots": [] }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." + "webComponents": { + "props": [ + { + "name": "linecount", + "type": "number", + "required": false, + "default": "3", + "description": "Used within components that contain multiple lines. Currently only used in card skeleton type" + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "300px", + "description": "Sets the maximum width. Currently only used in card skeleton type." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "size", + "type": "\"1\" | \"2\" | \"3\" | \"4\"", + "typeLabel": "GoabSkeletonSize", + "values": [ + "1", + "2", + "3", + "4" + ], + "required": false, + "default": "1", + "description": "Size can affect either the height, width or both for different skeleton types." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"image\" | \"text\" | \"title\" | \"text-small\" | \"avatar\" | \"header\" | \"paragraph\" | \"thumbnail\" | \"card\" | \"lines\" | \"profile\" | \"article\"", + "typeLabel": "GoabSkeletonType", + "values": [ + "image", + "text", + "title", + "text-small", + "avatar", + "header", + "paragraph", + "thumbnail", + "card", + "lines", + "profile", + "article" + ], + "required": true, + "default": null, + "description": "Sets the skeleton shape to represent your content." + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/spacer.json b/docs/generated/component-apis/spacer.json index 7c3620b442..50a3cecd05 100644 --- a/docs/generated/component-apis/spacer.json +++ b/docs/generated/component-apis/spacer.json @@ -1,31 +1,89 @@ { "componentSlug": "spacer", "extractedFrom": "libs/web-components/src/components/spacer/Spacer.svelte", - "props": [ - { - "name": "hspacing", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "none", - "description": "Horizontal spacing." + "frameworks": { + "react": { + "props": [ + { + "name": "hSpacing", + "type": "GoabSpacerHorizontalSpacing", + "required": false, + "default": "none", + "description": "Horizontal spacing." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "vSpacing", + "type": "GoabSpacerVerticalSpacing", + "required": false, + "default": "none", + "description": "Vertical spacing." + } + ], + "events": [], + "slots": [] }, - { - "name": "vspacing", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": "none", - "description": "Vertical spacing" + "angular": { + "props": [ + { + "name": "hSpacing", + "type": "GoabSpacerHorizontalSpacing", + "required": false, + "default": null, + "description": "Horizontal spacing." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "vSpacing", + "type": "GoabSpacerVerticalSpacing", + "required": false, + "default": null, + "description": "Vertical spacing." + } + ], + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "webComponents": { + "props": [ + { + "name": "hspacing", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "none", + "description": "Horizontal spacing." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "vspacing", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": "none", + "description": "Vertical spacing" + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/spinner.json b/docs/generated/component-apis/spinner.json index 61580a2564..57d58ec65e 100644 --- a/docs/generated/component-apis/spinner.json +++ b/docs/generated/component-apis/spinner.json @@ -1,42 +1,128 @@ { "componentSlug": "spinner", "extractedFrom": "libs/web-components/src/components/spinner/Spinner.svelte", - "props": [ - { - "name": "size", - "type": "\"small\" | \"medium\" | \"large\" | \"xlarge\"", - "values": [ - "small", - "medium", - "large", - "xlarge" + "frameworks": { + "react": { + "props": [ + { + "name": "invert", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, inverts colors for use on dark backgrounds." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": null, + "description": "Progress value (0-100). When set to 0 or greater, shows a progress spinner instead of infinite." + }, + { + "name": "size", + "type": "GoabSpinnerSize", + "required": true, + "default": null, + "description": "Sets the size of the spinner." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabSpinnerType", + "required": true, + "default": null, + "description": "Sets the spinner animation type." + } ], - "required": true, - "default": null, - "description": "Sets the size of the spinner." + "events": [], + "slots": [] }, - { - "name": "invert", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, inverts colors for use on dark backgrounds." - }, - { - "name": "progress", - "type": "number", - "required": false, - "default": "-1", - "description": "Progress value (0-100). When >= 0, shows a progress spinner instead of infinite." + "angular": { + "props": [ + { + "name": "invert", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, inverts colors for use on dark backgrounds." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": null, + "description": "Progress value (0-100). When >= 0, shows a progress spinner instead of infinite." + }, + { + "name": "size", + "type": "GoabSpinnerSize", + "required": false, + "default": null, + "description": "Sets the size of the spinner." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "GoabSpinnerType", + "required": false, + "default": null, + "description": "Sets the spinner type." + } + ], + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "webComponents": { + "props": [ + { + "name": "invert", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, inverts colors for use on dark backgrounds." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": "-1", + "description": "Progress value (0-100). When >= 0, shows a progress spinner instead of infinite." + }, + { + "name": "size", + "type": "\"small\" | \"medium\" | \"large\" | \"xlarge\"", + "values": [ + "small", + "medium", + "large", + "xlarge" + ], + "required": true, + "default": null, + "description": "Sets the size of the spinner." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/tab.json b/docs/generated/component-apis/tab.json index e65c70fae6..cd6d2fe6ff 100644 --- a/docs/generated/component-apis/tab.json +++ b/docs/generated/component-apis/tab.json @@ -1,45 +1,122 @@ { "componentSlug": "tab", "extractedFrom": "libs/web-components/src/components/tab/Tab.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": false, - "default": "", - "description": "The text label for this tab. Can also use the heading slot for custom content." + "frameworks": { + "react": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, disables the tab so it cannot be selected." + }, + { + "name": "heading", + "type": "string | React.ReactNode", + "values": [ + "string", + "React.ReactNode" + ], + "required": false, + "default": null, + "description": "The text label for this tab. Can also pass React nodes for custom heading content." + }, + { + "name": "slug", + "type": "string", + "required": false, + "default": null, + "description": "URL-friendly identifier for the tab, used for hash-based navigation." + } + ], + "events": [], + "slots": [ + { + "name": "heading", + "type": "ReactNode", + "description": "The text label for this tab. Can also pass React nodes for custom heading content.", + "required": false + } + ] }, - { - "name": "open", - "type": "boolean", - "required": false, - "default": "false", - "description": "Whether this tab is currently selected/active." + "angular": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, disables the tab." + }, + { + "name": "heading", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "The text label for this tab. Can also use the heading slot for custom content." + }, + { + "name": "slug", + "type": "string", + "required": false, + "default": null, + "description": "Sets the URL slug for the tab." + } + ], + "events": [], + "slots": [ + { + "name": "heading", + "type": "TemplateRef", + "description": "The text label for this tab. Can also pass React nodes for custom heading content.", + "required": false + } + ] }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "" - }, - { - "name": "slug", - "type": "string", - "required": false, - "default": "", - "description": "" - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "heading", - "description": "" + "webComponents": { + "props": [ + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "" + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": "", + "description": "The text label for this tab. Can also use the heading slot for custom content." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "Whether this tab is currently selected/active." + }, + { + "name": "slug", + "type": "string", + "required": false, + "default": "", + "description": "" + } + ], + "events": [], + "slots": [ + { + "name": "heading", + "description": "The text label for this tab. Can also pass React nodes for custom heading content.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/table-sort-header.json b/docs/generated/component-apis/table-sort-header.json index dce0360354..3f7e75debe 100644 --- a/docs/generated/component-apis/table-sort-header.json +++ b/docs/generated/component-apis/table-sort-header.json @@ -1,41 +1,108 @@ { "componentSlug": "table-sort-header", "extractedFrom": "libs/web-components/src/components/table/TableSortHeader.svelte", - "extractedAt": "2026-02-26T00:00:00.000Z", - "props": [ - { - "name": "name", - "type": "string", - "required": false, - "default": "", - "description": "Column name identifier for sorting." + "frameworks": { + "react": { + "props": [ + { + "name": "direction", + "type": "GoabTableSortDirection", + "required": false, + "default": "none", + "description": "Sets the sort direction indicator." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Column name identifier for sorting." + }, + { + "name": "sortOrder", + "type": "GoabTableSortOrder", + "required": false, + "default": null, + "description": "Sort order number for multi-column sort display. Used for displaying priority numbers when multiple columns are sorted." + } + ], + "events": [], + "slots": [] }, - { - "name": "direction", - "type": "\"asc\" | \"desc\" | \"none\"", - "typeLabel": "GoabTableSortDirection", - "values": [ - "asc", - "desc", - "none" + "angular": { + "props": [ + { + "name": "direction", + "type": "GoabTableSortDirection", + "required": false, + "default": "none", + "description": "Sets the sort direction indicator." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Column name identifier for sorting." + }, + { + "name": "sortOrder", + "type": "GoabTableSortOrder", + "required": false, + "default": null, + "description": "Sort order number for multi-column sort display (\"1\", \"2\", etc)." + } ], - "required": false, - "default": "none", - "description": "Sets the sort direction indicator." + "events": [], + "slots": [] }, - { - "name": "sortOrder", - "type": "number", - "required": false, - "default": 0, - "description": "Sort order number for multi-column sort display (1, 2, etc)." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "direction", + "type": "\"asc\" | \"desc\" | \"none\"", + "values": [ + "asc", + "desc", + "none" + ], + "required": false, + "default": "none", + "description": "Sets the sort direction indicator." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": "", + "description": "Column name identifier for sorting." + }, + { + "name": "sort-order", + "type": "\"0\" | \"1\" | \"2\"", + "values": [ + "0", + "1", + "2" + ], + "required": false, + "default": "0", + "description": "Sort order number for multi-column sort display (\"1\", \"2\", etc)." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [], + "slots": [] } - ] -} + } +} \ No newline at end of file diff --git a/docs/generated/component-apis/table.json b/docs/generated/component-apis/table.json index 8b86d28407..f8e6aa3915 100644 --- a/docs/generated/component-apis/table.json +++ b/docs/generated/component-apis/table.json @@ -1,130 +1,290 @@ { "componentSlug": "table", "extractedFrom": "libs/web-components/src/components/table/Table.svelte", - "props": [ - { - "name": "width", - "type": "string", - "required": false, - "default": "", - "description": "Width of the table. By default it will fit the enclosed content." - }, - { - "name": "stickyheader", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, the table header sticks to the top when scrolling." - }, - { - "name": "striped", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, alternates row background colors for improved readability." - }, - { - "name": "variant", - "type": "\"normal\" | \"relaxed\"", - "typeLabel": "GoabTableVariant", - "values": [ - "normal", - "relaxed" + "frameworks": { + "react": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "sortMode", + "type": "GoabTableSortMode", + "required": false, + "default": "single", + "description": "Sort mode: \"single\" allows one column, \"multi\" allows up to 2 columns." + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, alternates row background colors for improved readability." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabTableVariant", + "required": false, + "default": "normal", + "description": "A relaxed variant of the table with more vertical padding for the cells." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Width of the table. By default it will fit the enclosed content." + } ], - "required": false, - "default": "normal", - "description": "A relaxed variant of the table with more vertical padding for the cells." - }, - { - "name": "sortMode", - "type": "\"single\" | \"multi\"", - "typeLabel": "GoabTableSortMode", - "values": [ - "single", - "multi" + "events": [ + { + "name": "onMultiSort", + "type": "(detail: GoabTableOnMultiSortDetail) => void", + "description": "Callback fired when multi-column sorting changes.", + "frameworks": [ + "react" + ] + }, + { + "name": "onSort", + "type": "(detail: GoabTableOnSortDetail) => void", + "description": "Callback fired when a single-column sort header is clicked.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "single", - "description": "Sort mode: \"single\" allows one column, \"multi\" allows up to 2 columns." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." + "slots": [] }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onSort", - "type": "(detail: GoabTableOnSortDetail) => void", - "description": "Called when sort state changes in single-sort mode. Receives { sortBy, sortDir }.", - "frameworks": [ - "react" - ] - }, - { - "name": "_sort", - "type": "CustomEvent", - "description": "Dispatched when sort state changes in single-sort mode. Detail contains { sortBy, sortDir }.", - "frameworks": [ - "angular" - ] - }, - { - "name": "onMultiSort", - "type": "(detail: GoabTableOnMultiSortDetail) => void", - "description": "Called when sort state changes in multi-sort mode. Receives { sorts: GoabTableSortEntry[] }.", - "frameworks": [ - "react" - ] + "angular": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "sortMode", + "type": "GoabTableSortMode", + "required": false, + "default": null, + "description": "Sets sort mode: \"single\" allows one column, \"multi\" allows up to 2 columns." + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, alternates row background colors for improved readability." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabTableVariant", + "required": false, + "default": null, + "description": "Sets a relaxed variant of the table with more vertical padding for the cells." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Width of the table. By default it will fit the enclosed content." + } + ], + "events": [ + { + "name": "onMultiSort", + "type": "(event: GoabTableOnMultiSortDetail) => void", + "description": "Emits when multi-column sorting changes. Emits an array of sort entries as GoabTableOnMultiSortDetail.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onSort", + "type": "(event: GoabTableOnSortDetail) => void", + "description": "Emits when a table column is sorted. Emits the sort column and direction as GoabTableOnSortDetail.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_multisort", - "type": "CustomEvent", - "description": "Dispatched when sort state changes in multi-sort mode. Detail contains { sorts: GoabTableSortEntry[] }.", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "sort-mode", + "type": "\"single\" | \"multi\"", + "typeLabel": "GoabTableSortMode", + "values": [ + "single", + "multi" + ], + "required": false, + "default": "single", + "description": "Sort mode: \"single\" allows one column, \"multi\" allows up to 2 columns." + }, + { + "name": "striped", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, alternates row background colors for improved readability." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "\"normal\" | \"relaxed\"", + "typeLabel": "GoabTableVariant", + "values": [ + "normal", + "relaxed" + ], + "required": false, + "default": "normal", + "description": "A relaxed variant of the table with more vertical padding for the cells." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "typeLabel": "GoabTableVersionType", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "", + "description": "Width of the table. By default it will fit the enclosed content." + } + ], + "events": [ + { + "name": "_multisort", + "type": "CustomEvent<{ sorts: { column: string; direction: \"asc\" | \"desc\" }[] }>", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_sort", + "type": "CustomEvent<{ sortBy: string; sortDir: number }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/tabs.json b/docs/generated/component-apis/tabs.json index 41eecf4ab2..2d48620626 100644 --- a/docs/generated/component-apis/tabs.json +++ b/docs/generated/component-apis/tabs.json @@ -1,66 +1,179 @@ { "componentSlug": "tabs", "extractedFrom": "libs/web-components/src/components/tabs/Tabs.svelte", - "props": [ - { - "name": "initialtab", - "type": "number", - "required": false, - "default": "-1", - "description": "The initially active tab (1-based index). If not set, the first tab is active." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "variant", - "type": "\"default\" | \"segmented\"", - "values": [ - "default", - "segmented" + "frameworks": { + "react": { + "props": [ + { + "name": "initialTab", + "type": "number", + "required": false, + "default": null, + "description": "The initially active tab (1-based index). If not set, the first tab is active." + }, + { + "name": "navigation", + "type": "GoabTabsNavigation", + "required": false, + "default": "hash", + "description": "Controls URL navigation mode on tab change." + }, + { + "name": "orientation", + "type": "GoabTabsOrientation", + "required": false, + "default": "auto", + "description": "Tab layout orientation. \"auto\" stacks vertically on mobile, \"horizontal\" keeps horizontal on all screen sizes." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabTabsVariant", + "required": false, + "default": "default", + "description": "Visual style variant. \"segmented\" shows pill-style tabs with animation." + } ], - "required": false, - "default": "default", - "description": "Visual style variant. \"segmented\" shows pill-style tabs with animation." + "events": [ + { + "name": "onChange", + "type": "(detail: GoabTabsOnChangeDetail) => void", + "description": "Callback fired when the active tab changes.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] }, - { - "name": "orientation", - "type": "\"auto\" | \"horizontal\"", - "values": [ - "auto", - "horizontal" + "angular": { + "props": [ + { + "name": "initialTab", + "type": "number", + "required": false, + "default": null, + "description": "The initially active tab (1-based index). If not set, the first tab is active." + }, + { + "name": "navigation", + "type": "GoabTabsNavigation", + "required": false, + "default": null, + "description": "Sets the navigation mode for tab switching. \"hash\" updates the URL hash when switching tabs." + }, + { + "name": "orientation", + "type": "GoabTabsOrientation", + "required": false, + "default": null, + "description": "Tab layout orientation. \"auto\" stacks vertically on mobile (default), \"horizontal\" keeps horizontal on all screen sizes." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "GoabTabsVariant", + "required": false, + "default": null, + "description": "Visual style variant. \"segmented\" shows pill-style tabs with animation." + } ], - "required": false, - "default": "auto", - "description": "Tab layout orientation. \"auto\" stacks vertically on mobile, \"horizontal\" keeps horizontal on all screen sizes." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "events": [ + { + "name": "onChange", + "type": "(event: GoabTabsOnChangeDetail) => void", + "description": "Emits when the active tab changes. Emits the new tab index as GoabTabsOnChangeDetail.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "initialtab", + "type": "number", + "required": false, + "default": "-1", + "description": "The initially active tab (1-based index). If not set, the first tab is active." + }, + { + "name": "navigation", + "type": "\"hash\" | \"none\"", + "values": [ + "hash", + "none" + ], + "required": false, + "default": "hash", + "description": "" + }, + { + "name": "orientation", + "type": "\"auto\" | \"horizontal\"", + "values": [ + "auto", + "horizontal" + ], + "required": false, + "default": "auto", + "description": "Tab layout orientation. \"auto\" stacks vertically on mobile, \"horizontal\" keeps horizontal on all screen sizes." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "variant", + "type": "\"default\" | \"segmented\"", + "values": [ + "default", + "segmented" + ], + "required": false, + "default": "default", + "description": "Visual style variant. \"segmented\" shows pill-style tabs with animation." + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + } + ], + "events": [ + { + "name": "_change", + "type": "CustomEvent<{ tab: number }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/temporary-notification.json b/docs/generated/component-apis/temporary-notification.json index 0b8b15252d..c186f7fa79 100644 --- a/docs/generated/component-apis/temporary-notification.json +++ b/docs/generated/component-apis/temporary-notification.json @@ -1,68 +1,126 @@ { "componentSlug": "temporary-notification", "extractedFrom": "libs/web-components/src/components/temporary-notification/TemporaryNotification.svelte", - "props": [ - { - "name": "message", - "type": "string", - "required": false, - "default": "", - "description": "The notification message text to display." - }, - { - "name": "type", - "type": "\"basic\" | \"success\" | \"failure\" | \"indeterminate\" | \"progress\"", - "values": [ - "basic", - "success", - "failure", - "indeterminate", - "progress" + "frameworks": { + "react": { + "props": [ + { + "name": "horizontalPosition", + "type": "SnackbarHorizontalPosition", + "required": false, + "default": "center", + "description": "Horizontal position of the notification container." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "verticalPosition", + "type": "SnackbarVerticalPosition", + "required": false, + "default": "bottom", + "description": "Vertical position of the notification container." + } ], - "required": false, - "default": "basic", - "description": "The notification type which determines the visual style and icon." - }, - { - "name": "progress", - "type": "number", - "required": false, - "default": "-1", - "description": "Progress value from 0-100. Use -1 to hide the progress bar. Only applies when type is \"progress\"." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." + "events": [], + "slots": [] }, - { - "name": "actionText", - "type": "string", - "required": false, - "default": "", - "description": "Text for the optional action button. When provided, displays a clickable link button." - }, - { - "name": "visible", - "type": "boolean", - "required": false, - "default": "true", - "description": "Controls whether the notification is visible." + "angular": { + "props": [ + { + "name": "horizontalPosition", + "type": "SnackbarHorizontalPosition", + "required": false, + "default": "center", + "description": "Horizontal position of the notification container." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "verticalPosition", + "type": "SnackbarVerticalPosition", + "required": false, + "default": "bottom", + "description": "Vertical position of the notification container." + } + ], + "events": [], + "slots": [] }, - { - "name": "animationDirection", - "type": "\"up\" | \"down\"", - "values": [ - "up", - "down" + "webComponents": { + "props": [ + { + "name": "action-text", + "type": "string", + "required": false, + "default": "", + "description": "Text for the optional action button. When provided, displays a clickable link button." + }, + { + "name": "animation-direction", + "type": "\"up\" | \"down\"", + "values": [ + "up", + "down" + ], + "required": false, + "default": "down", + "description": "Direction the notification animates from when appearing or disappearing." + }, + { + "name": "message", + "type": "string", + "required": false, + "default": "", + "description": "The notification message text to display." + }, + { + "name": "progress", + "type": "number", + "required": false, + "default": "-1", + "description": "Progress value from 0-100. Use -1 to hide the progress bar. Only applies when type is \"progress\"." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "type", + "type": "\"basic\" | \"success\" | \"failure\" | \"indeterminate\" | \"progress\"", + "values": [ + "basic", + "success", + "failure", + "indeterminate", + "progress" + ], + "required": false, + "default": "basic", + "description": "The notification type which determines the visual style and icon." + }, + { + "name": "visible", + "type": "boolean", + "required": false, + "default": "true", + "description": "Controls whether the notification is visible." + } ], - "required": false, - "default": "down", - "description": "Direction the notification animates from when appearing or disappearing." + "events": [], + "slots": [] } - ], - "events": [], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/text-area.json b/docs/generated/component-apis/text-area.json index d3c636bb97..6951478989 100644 --- a/docs/generated/component-apis/text-area.json +++ b/docs/generated/component-apis/text-area.json @@ -1,213 +1,535 @@ { "componentSlug": "text-area", "extractedFrom": "libs/web-components/src/components/text-area/TextArea.svelte", - "props": [ - { - "name": "name", - "type": "string", - "required": true, - "default": null, - "description": "Name of the input value that is received in the _change event." - }, - { - "name": "value", - "type": "string", - "required": false, - "default": "", - "description": "Bound to value" - }, - { - "name": "placeholder", - "type": "string", - "required": false, - "default": "", - "description": "Text displayed within the input when no value is set." - }, - { - "name": "rows", - "type": "number", - "required": false, - "default": "3", - "description": "Set the number of rows." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "width", - "type": "string", - "required": false, - "default": "100%", - "description": "Width of the text area." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "60ch", - "description": "Maximum width of the text area" - }, - { - "name": "error", - "type": "boolean", - "required": false, - "default": "false", - "description": "Sets the input to an error state" - }, - { - "name": "readOnly", - "type": "boolean", - "required": false, - "default": "false", - "description": "Sets the input to a read only state." - }, - { - "name": "disabled", - "type": "boolean", - "required": false, - "default": "false", - "description": "Sets the input to a disabled state. Use [attr.disabled] with [formControl]" - }, - { - "name": "ariaLabel", - "type": "string", - "required": false, - "default": "", - "description": "Defines how the text will be translated for the screen reader. If not specified it will fall back to the name." - }, - { - "name": "countby", - "type": "\"character\" | \"word\" | \"\"", - "values": [ - "character", - "word" + "frameworks": { + "react": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the text will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "autoComplete", + "type": "string", + "required": false, + "default": null, + "description": "Specifies the autocomplete attribute for the textarea input." + }, + { + "name": "countBy", + "type": "GoabTextAreaCountBy", + "required": false, + "default": null, + "description": "Counting interval for characters or words, specifying whether to count every character or word." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the input to a disabled state." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the input to an error state." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute on the textarea element." + }, + { + "name": "maxCount", + "type": "number", + "required": false, + "default": null, + "description": "Maximum number of characters or words allowed." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": "60ch", + "description": "Sets the maximum width of the text area." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "Name of the input value that is received in the change event." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": null, + "description": "Text displayed within the textarea when no value is set." + }, + { + "name": "readOnly", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the input to a read only state." + }, + { + "name": "rows", + "type": "number", + "required": false, + "default": "3", + "description": "Sets the number of visible text rows." + }, + { + "name": "size", + "type": "GoabTextAreaSize", + "required": false, + "default": null, + "description": "Sets the visual size variant of the text area." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "Bound to the current value of the textarea." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "100%", + "description": "Sets the width of the text area." + } ], - "required": false, - "default": "", - "description": "Counting interval for characters or words, specifying whether to count every character or word." - }, - { - "name": "maxCount", - "type": "number", - "required": false, - "default": "-1", - "description": "Maximum number of characters or words allowed" - }, - { - "name": "autoComplete", - "type": "string", - "required": false, - "default": "", - "description": "Specifies the autocomplete attribute for the textarea input." - }, - { - "name": "version", - "type": "\"1\" | \"2\"", - "values": [ - "1", - "2" + "events": [ + { + "name": "onBlur", + "type": "(event: GoabTextAreaOnBlurDetail) => void", + "description": "Callback fired when the textarea loses focus.", + "frameworks": [ + "react" + ] + }, + { + "name": "onChange", + "type": "(event: GoabTextAreaOnChangeDetail) => void", + "description": "Callback fired when the value of the textarea changes.", + "frameworks": [ + "react" + ] + }, + { + "name": "onKeyPress", + "type": "(event: GoabTextAreaOnKeyPressDetail) => void", + "description": "Callback fired when a key is pressed within the textarea.", + "frameworks": [ + "react" + ] + } ], - "required": false, - "default": "1", - "description": "" + "slots": [] }, - { - "name": "size", - "type": "\"default\" | \"compact\"", - "values": [ - "default", - "compact" + "angular": { + "props": [ + { + "name": "ariaLabel", + "type": "string", + "required": false, + "default": null, + "description": "Defines how the text will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "autoComplete", + "type": "string", + "required": false, + "default": "on", + "description": "Specifies the autocomplete attribute for the textarea input." + }, + { + "name": "countBy", + "type": "GoabTextAreaCountBy", + "required": false, + "default": "", + "description": "Counting interval for characters or words, specifying whether to count every character or word." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the disabled state for the control." + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the error state for the control." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute of the underlying web component." + }, + { + "name": "maxCount", + "type": "number", + "required": false, + "default": "-1", + "description": "Maximum number of characters or words allowed." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Maximum width of the text area." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "name", + "type": "string", + "required": false, + "default": null, + "description": "Name of the input value that is received in the _change event." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": null, + "description": "Text displayed within the input when no value is set." + }, + { + "name": "readOnly", + "type": "boolean", + "required": false, + "default": null, + "description": "Sets the input to a read only state." + }, + { + "name": "rows", + "type": "number", + "required": false, + "default": "3", + "description": "Set the number of rows." + }, + { + "name": "size", + "type": "GoabTextAreaSize", + "required": false, + "default": "default", + "description": "Sets the size variant of the textarea." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": null, + "description": "Sets the control value used by Angular forms and one-way binding." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": null, + "description": "Width of the text area." + } ], - "required": false, - "default": "default", - "description": "" - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [ - { - "name": "onChange", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_change", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - }, - { - "name": "onBlur", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] - }, - { - "name": "_blur", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - }, - { - "name": "onKeyPress", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" - ] + "events": [ + { + "name": "onBlur", + "type": "(event: GoabTextAreaOnBlurDetail) => void", + "description": "Emits when the textarea loses focus. Emits the name and current value.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onChange", + "type": "(event: GoabTextAreaOnChangeDetail) => void", + "description": "Emits when the textarea value changes. Emits the name and new value.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onKeyPress", + "type": "(event: GoabTextAreaOnKeyPressDetail) => void", + "description": "Emits when a key is pressed in the textarea. Emits the name, value, and key.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] }, - { - "name": "_keyPress", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] + "webComponents": { + "props": [ + { + "name": "arialabel", + "type": "string", + "required": false, + "default": "", + "description": "Defines how the text will be translated for the screen reader. If not specified it will fall back to the name." + }, + { + "name": "autocomplete", + "type": "string", + "required": false, + "default": "", + "description": "Specifies the autocomplete attribute for the textarea input." + }, + { + "name": "countby", + "type": "\"character\" | \"word\" | \"\"", + "values": [ + "character", + "word" + ], + "required": false, + "default": "", + "description": "Counting interval for characters or words, specifying whether to count every character or word." + }, + { + "name": "disabled", + "type": "boolean", + "required": false, + "default": "false", + "description": "Sets the input to a disabled state. Use [attr.disabled] with [formControl]" + }, + { + "name": "error", + "type": "boolean", + "required": false, + "default": "false", + "description": "Sets the input to an error state" + }, + { + "name": "maxcount", + "type": "number", + "required": false, + "default": "-1", + "description": "Maximum number of characters or words allowed" + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "60ch", + "description": "Maximum width of the text area" + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "name", + "type": "string", + "required": true, + "default": null, + "description": "Name of the input value that is received in the _change event." + }, + { + "name": "placeholder", + "type": "string", + "required": false, + "default": "", + "description": "Text displayed within the input when no value is set." + }, + { + "name": "readonly", + "type": "boolean", + "required": false, + "default": "false", + "description": "Sets the input to a read only state." + }, + { + "name": "rows", + "type": "number", + "required": false, + "default": "3", + "description": "Set the number of rows." + }, + { + "name": "size", + "type": "\"default\" | \"compact\"", + "values": [ + "default", + "compact" + ], + "required": false, + "default": "default", + "description": "" + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "value", + "type": "string", + "required": false, + "default": "", + "description": "Bound to value" + }, + { + "name": "version", + "type": "\"1\" | \"2\"", + "values": [ + "1", + "2" + ], + "required": false, + "default": "1", + "description": "Design system version for styling." + }, + { + "name": "width", + "type": "string", + "required": false, + "default": "100%", + "description": "Width of the text area." + } + ], + "events": [ + { + "name": "_blur", + "type": "CustomEvent<{ name: string; value: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_change", + "type": "CustomEvent<{ name: string; value: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_keyPress", + "type": "CustomEvent<{ name: string; value: string; key: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] } - ], - "slots": [] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/text.json b/docs/generated/component-apis/text.json index 91b7c66f12..7437d8aff7 100644 --- a/docs/generated/component-apis/text.json +++ b/docs/generated/component-apis/text.json @@ -1,103 +1,248 @@ { "componentSlug": "text", "extractedFrom": "libs/web-components/src/components/text/Text.svelte", - "props": [ - { - "name": "as", - "type": "\"span\" | \"div\" | \"p\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\"", - "values": [ - "span", - "div", - "p", - "h1", - "h2", - "h3", - "h4", - "h5" + "frameworks": { + "react": { + "props": [ + { + "name": "color", + "type": "GoabTextColor", + "required": false, + "default": "primary", + "description": "Sets the text colour." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute on the element." + }, + { + "name": "maxWidth", + "type": "GoabTextMaxWidth", + "required": false, + "default": "65ch", + "description": "Sets the max width." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "size", + "type": "GoabTextSize", + "required": false, + "default": null, + "description": "Overrides the text size." + }, + { + "name": "tag", + "type": "GoabTextTextElement | GoabTextHeadingElement", + "values": [ + "GoabTextTextElement", + "GoabTextHeadingElement" + ], + "required": false, + "default": null, + "description": "The HTML element to render. Use semantic elements like 'h1'-'h6' for headings." + } ], - "required": false, - "default": "div", - "description": "The HTML element to render. Use semantic elements like 'h1'-'h6' for headings." + "events": [], + "slots": [] }, - { - "name": "maxWidth", - "type": "string | \"none\"", - "values": [ - "string", - "none" + "angular": { + "props": [ + { + "name": "color", + "type": "GoabTextColor", + "required": false, + "default": null, + "description": "Sets the text colour." + }, + { + "name": "id", + "type": "string", + "required": false, + "default": null, + "description": "Sets the id attribute on the host element." + }, + { + "name": "maxWidth", + "type": "GoabTextMaxWidth", + "required": false, + "default": null, + "description": "Sets the max width." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "size", + "type": "GoabTextSize", + "required": false, + "default": null, + "description": "Overrides the text size." + }, + { + "name": "tag", + "type": "GoabTextTextElement | GoabTextHeadingElement", + "values": [ + "GoabTextTextElement", + "GoabTextHeadingElement" + ], + "required": false, + "default": null, + "description": "The HTML element to render. Use semantic elements like 'h1'-'h6' for headings." + } ], - "required": false, - "default": "65ch", - "description": "Sets the max width." + "events": [], + "slots": [] }, - { - "name": "size", - "type": "\"heading-xl\" | \"heading-l\" | \"heading-m\" | \"heading-s\" | \"heading-xs\" | \"heading-2xs\" | \"body-l\" | \"body-m\" | \"body-s\" | \"body-xs\"", - "values": [ - "heading-xl", - "heading-l", - "heading-m", - "heading-s", - "heading-xs", - "heading-2xs", - "body-l", - "body-m", - "body-s", - "body-xs" + "webComponents": { + "props": [ + { + "name": "as", + "type": "\"span\" | \"div\" | \"p\" | \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\"", + "values": [ + "span", + "div", + "p", + "h1", + "h2", + "h3", + "h4", + "h5" + ], + "required": false, + "default": "div", + "description": "The HTML element to render. Use semantic elements like 'h1'-'h6' for headings." + }, + { + "name": "color", + "type": "\"primary\" | \"secondary\"", + "values": [ + "primary", + "secondary" + ], + "required": false, + "default": "primary", + "description": "Sets the text colour." + }, + { + "name": "maxwidth", + "type": "string | \"none\"", + "values": [ + "string", + "none" + ], + "required": false, + "default": "65ch", + "description": "Sets the max width." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "size", + "type": "\"heading-xl\" | \"heading-l\" | \"heading-m\" | \"heading-s\" | \"heading-xs\" | \"heading-2xs\" | \"body-l\" | \"body-m\" | \"body-s\" | \"body-xs\"", + "values": [ + "heading-xl", + "heading-l", + "heading-m", + "heading-s", + "heading-xs", + "heading-2xs", + "body-l", + "body-m", + "body-s", + "body-xs" + ], + "required": false, + "default": null, + "description": "Overrides the text size." + } ], - "required": false, - "default": null, - "description": "Overrides the text size." - }, - { - "name": "color", - "type": "\"primary\" | \"secondary\"", - "values": [ - "primary", - "secondary" - ], - "required": false, - "default": "primary", - "description": "Sets the text colour." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." - }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "events": [], + "slots": [] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/tooltip.json b/docs/generated/component-apis/tooltip.json index 9464d6c3d7..2cded97112 100644 --- a/docs/generated/component-apis/tooltip.json +++ b/docs/generated/component-apis/tooltip.json @@ -1,97 +1,258 @@ { "componentSlug": "tooltip", "extractedFrom": "libs/web-components/src/components/tooltip/Tooltip.svelte", - "props": [ - { - "name": "content", - "type": "any", - "required": false, - "default": "", - "description": "The content of the tooltip." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "position", - "type": "\"top\" | \"bottom\" | \"left\" | \"right\"", - "typeLabel": "GoabTooltipPosition", - "values": [ - "top", - "bottom", - "left", - "right" + "frameworks": { + "react": { + "props": [ + { + "name": "content", + "type": "string | ReactNode", + "values": [ + "string", + "ReactNode" + ], + "required": false, + "default": null, + "description": "The content of the tooltip. Accepts plain text or rich content." + }, + { + "name": "hAlign", + "type": "GoabTooltipHorizontalAlignment", + "required": false, + "default": "center", + "description": "Horizontal alignment of the tooltip relative to the child element." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the tooltip. Must use 'px' unit." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "" + }, + { + "name": "position", + "type": "GoabTooltipPosition", + "required": false, + "default": "top", + "description": "Position of the tooltip with respect to the child element." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } ], - "required": false, - "default": "top", - "description": "Position with respect to the child element." + "events": [], + "slots": [ + { + "name": "content", + "type": "ReactNode", + "description": "The content of the tooltip. Accepts plain text or rich content.", + "required": false + } + ] }, - { - "name": "halign", - "type": "\"left\" | \"right\" | \"center\"", - "typeLabel": "GoabTooltipAlignment", - "values": [ - "left", - "right", - "center" + "angular": { + "props": [ + { + "name": "content", + "type": "string | TemplateRef", + "values": [ + "string", + "TemplateRef" + ], + "required": false, + "default": null, + "description": "The content of the tooltip." + }, + { + "name": "hAlign", + "type": "GoabTooltipHorizontalAlignment", + "required": false, + "default": "center", + "description": "Horizontal alignment to the child element." + }, + { + "name": "maxWidth", + "type": "string", + "required": false, + "default": null, + "description": "Sets the maximum width of the tooltip. Must use 'px' unit." + }, + { + "name": "mb", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the bottom margin spacing token." + }, + { + "name": "ml", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the left margin spacing token." + }, + { + "name": "mr", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the right margin spacing token." + }, + { + "name": "mt", + "type": "Spacing", + "required": false, + "default": null, + "description": "Sets the top margin spacing token." + }, + { + "name": "position", + "type": "GoabTooltipPosition", + "required": false, + "default": "top", + "description": "Position with respect to the child element." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets the data-testid attribute for automated testing." + } ], - "required": false, - "default": "center", - "description": "Horizontal alignment to the child element." - }, - { - "name": "maxWidth", - "type": "string", - "required": false, - "default": "", - "description": "Sets the maximum width of the tooltip. Must use 'px' unit." - }, - { - "name": "mt", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Top margin." - }, - { - "name": "mr", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Right margin." + "events": [], + "slots": [ + { + "name": "content", + "type": "TemplateRef", + "description": "The content of the tooltip. Accepts plain text or rich content.", + "required": false + } + ] }, - { - "name": "mb", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Bottom margin." - }, - { - "name": "ml", - "type": "Spacing", - "typeLabel": "Spacing", - "required": false, - "default": null, - "description": "Left margin." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" - }, - { - "name": "content", - "description": "" + "webComponents": { + "props": [ + { + "name": "content", + "type": "string", + "required": false, + "default": "", + "description": "The content of the tooltip." + }, + { + "name": "halign", + "type": "\"left\" | \"right\" | \"center\"", + "typeLabel": "GoabTooltipAlignment", + "values": [ + "left", + "right", + "center" + ], + "required": false, + "default": "center", + "description": "Horizontal alignment to the child element." + }, + { + "name": "maxwidth", + "type": "string", + "required": false, + "default": "", + "description": "Sets the maximum width of the tooltip. Must use 'px' unit." + }, + { + "name": "mb", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Bottom margin." + }, + { + "name": "ml", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Left margin." + }, + { + "name": "mr", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Right margin." + }, + { + "name": "mt", + "type": "Spacing", + "typeLabel": "Spacing", + "required": false, + "default": null, + "description": "Top margin." + }, + { + "name": "position", + "type": "\"top\" | \"bottom\" | \"left\" | \"right\"", + "typeLabel": "GoabTooltipPosition", + "values": [ + "top", + "bottom", + "left", + "right" + ], + "required": false, + "default": "top", + "description": "Position with respect to the child element." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [ + { + "name": "content", + "description": "The content of the tooltip. Accepts plain text or rich content.", + "required": false + } + ] } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/work-side-menu-group.json b/docs/generated/component-apis/work-side-menu-group.json index 3ee4a0cea6..84d7de7aea 100644 --- a/docs/generated/component-apis/work-side-menu-group.json +++ b/docs/generated/component-apis/work-side-menu-group.json @@ -1,42 +1,109 @@ { "componentSlug": "work-side-menu-group", "extractedFrom": "libs/web-components/src/components/work-side-menu/WorkSideMenuGroup.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": true, - "default": null, - "description": "The text displayed in the group heading." + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The text displayed in the group heading." + }, + { + "name": "icon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the group label. When omitted, no icon is rendered and no space is reserved." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Whether the group is open." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "icon", - "type": "GoAIconType", - "typeLabel": "GoAIconType", - "required": false, - "default": null, - "description": "Icon displayed before the group label. When omitted, no icon is rendered and no space is reserved." + "angular": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The text displayed in the group heading." + }, + { + "name": "icon", + "type": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the group label. When omitted, no icon is rendered and no space is reserved." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Whether the group is open." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "open", - "type": "boolean", - "required": false, - "default": "false", - "description": "Whether the group is open." - } - ], - "events": [], - "slots": [ - { - "name": "default", - "description": "" + "webComponents": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The text displayed in the group heading." + }, + { + "name": "icon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the group label. When omitted, no icon is rendered and no space is reserved." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "Whether the group is open." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [], + "slots": [] } - ] -} + } +} \ No newline at end of file diff --git a/docs/generated/component-apis/work-side-menu-item.json b/docs/generated/component-apis/work-side-menu-item.json index 302ecd2f0e..c133921506 100644 --- a/docs/generated/component-apis/work-side-menu-item.json +++ b/docs/generated/component-apis/work-side-menu-item.json @@ -1,70 +1,188 @@ { "componentSlug": "work-side-menu-item", "extractedFrom": "libs/web-components/src/components/work-side-menu/WorkSideMenuItem.svelte", - "props": [ - { - "name": "label", - "type": "string", - "required": true, - "default": null, - "description": "The text label displayed for the menu item." + "frameworks": { + "react": { + "props": [ + { + "name": "current", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, indicates this is the currently active menu item." + }, + { + "name": "divider", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, displays a divider line above this menu item." + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": null, + "description": "Icon displayed before the menu item label." + }, + { + "name": "label", + "type": "string", + "required": true, + "default": null, + "description": "The text label displayed for the menu item." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": null, + "description": "The URL the menu item links to. When absent, renders as a button instead of a link." + } + ], + "events": [], + "slots": [ + { + "name": "popoverContent", + "type": "ReactNode", + "description": "Content rendered inside the popover panel attached to this menu item.", + "required": false + }, + { + "name": "trailingContent", + "type": "ReactNode", + "description": "Content rendered after the label in the trailing area of the menu item.", + "required": false + } + ] }, - { - "name": "url", - "type": "string", - "required": false, - "default": "", - "description": "The URL the menu item links to. Optional — when absent, renders as a button instead of a link." + "angular": { + "props": [ + { + "name": "current", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, indicates this is the currently active menu item." + }, + { + "name": "divider", + "type": "boolean", + "required": false, + "default": null, + "description": "When true, displays a divider line above this menu item." + }, + { + "name": "icon", + "type": "string", + "required": false, + "default": null, + "description": "Icon displayed before the menu item label." + }, + { + "name": "label", + "type": "string", + "required": true, + "default": null, + "description": "The text label displayed for the menu item." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": null, + "description": "The URL the menu item links to. Optional — when absent, renders as a button instead of a link." + } + ], + "events": [], + "slots": [ + { + "name": "popoverContent", + "type": "TemplateRef", + "description": "Content rendered inside the popover panel attached to this menu item.", + "required": false + }, + { + "name": "trailingContent", + "type": "TemplateRef", + "description": "Content rendered after the label in the trailing area of the menu item.", + "required": false + } + ] }, - { - "name": "badge", - "type": "string", - "required": false, - "default": "", - "description": "Badge text displayed alongside the menu item (e.g., notification count)." - }, - { - "name": "current", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, indicates this is the currently active menu item." - }, - { - "name": "divider", - "type": "boolean", - "required": false, - "default": "false", - "description": "When true, displays a divider line above this menu item." - }, - { - "name": "icon", - "type": "string", - "required": false, - "default": "", - "description": "Icon displayed before the menu item label." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "type", - "type": "\"normal\" | \"emergency\" | \"success\"", - "values": ["normal", "emergency", "success"], - "required": false, - "default": "normal", - "description": "Sets the visual style of the badge. Use \"emergency\" for urgent items, \"success\" for positive status." - } - ], - "events": [], - "slots": [ - { - "name": "popoverContent", - "description": "Content displayed in a popover panel beside the menu item." + "webComponents": { + "props": [ + { + "name": "current", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, indicates this is the currently active menu item." + }, + { + "name": "divider", + "type": "boolean", + "required": false, + "default": "false", + "description": "When true, displays a divider line above this menu item." + }, + { + "name": "icon", + "type": "GoabIconType", + "typeLabel": "GoabIconType", + "required": false, + "default": null, + "description": "Icon displayed before the menu item label." + }, + { + "name": "label", + "type": "string", + "required": true, + "default": null, + "description": "The text label displayed for the menu item." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": false, + "default": "", + "description": "The URL the menu item links to. Optional — when absent, renders as a button instead of a link." + } + ], + "events": [], + "slots": [ + { + "name": "popoverContent", + "description": "Content rendered inside the popover panel attached to this menu item.", + "required": false + }, + { + "name": "trailingContent", + "description": "Content rendered after the label in the trailing area of the menu item.", + "required": false + } + ] } - ] -} + } +} \ No newline at end of file diff --git a/docs/generated/component-apis/work-side-menu.json b/docs/generated/component-apis/work-side-menu.json index 1c2c51e232..23236db287 100644 --- a/docs/generated/component-apis/work-side-menu.json +++ b/docs/generated/component-apis/work-side-menu.json @@ -1,96 +1,255 @@ { "componentSlug": "work-side-menu", "extractedFrom": "libs/web-components/src/components/work-side-menu/WorkSideMenu.svelte", - "props": [ - { - "name": "heading", - "type": "string", - "required": true, - "default": null, - "description": "The application name displayed in the header." - }, - { - "name": "url", - "type": "string", - "required": true, - "default": null, - "description": "URL for the header link. Clicking the logo/heading navigates to this URL." - }, - { - "name": "open", - "type": "any", - "required": false, - "default": "false", - "description": "Controls whether the side menu is expanded or collapsed." - }, - { - "name": "testId", - "type": "string", - "required": false, - "default": "", - "description": "Sets a data-testid attribute for automated testing." - }, - { - "name": "userName", - "type": "string", - "required": false, - "default": "", - "description": "User's name displayed in the profile section." - }, - { - "name": "userSecondaryText", - "type": "string", - "required": false, - "default": "", - "description": "Secondary text displayed below the user's name, such as role or email." - } - ], - "events": [ - { - "name": "onUpdate", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "frameworks": { + "react": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The application name displayed in the header." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Controls whether the side menu is expanded or collapsed." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": true, + "default": null, + "description": "URL for the header link. Clicking the logo/heading navigates to this URL." + }, + { + "name": "userName", + "type": "string", + "required": false, + "default": null, + "description": "User's name displayed in the profile section." + }, + { + "name": "userSecondaryText", + "type": "string", + "required": false, + "default": null, + "description": "Secondary text displayed below the user's name, such as role or email." + } + ], + "events": [ + { + "name": "onNavigate", + "type": "(path: string) => void", + "description": "Callback fired when a menu item is navigated, providing the target URL path.", + "frameworks": [ + "react" + ] + }, + { + "name": "onToggle", + "type": "() => void", + "description": "Callback fired when the side menu is toggled open or closed.", + "frameworks": [ + "react" + ] + } + ], + "slots": [ + { + "name": "accountContent", + "type": "ReactNode", + "description": "Content rendered in the account/profile slot.", + "required": false + }, + { + "name": "primaryContent", + "type": "ReactNode", + "description": "Content rendered in the primary navigation slot.", + "required": false + }, + { + "name": "secondaryContent", + "type": "ReactNode", + "description": "Content rendered in the secondary navigation slot.", + "required": false + } ] }, - { - "name": "_update", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" + "angular": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The application name displayed in the header." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": null, + "description": "Controls whether the side menu is expanded or collapsed." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": true, + "default": null, + "description": "URL for the header link. Clicking the logo/heading navigates to this URL." + }, + { + "name": "userName", + "type": "string", + "required": false, + "default": null, + "description": "User's name displayed in the profile section." + }, + { + "name": "userSecondaryText", + "type": "string", + "required": false, + "default": null, + "description": "Secondary text displayed below the user's name, such as role or email." + } + ], + "events": [ + { + "name": "onNavigate", + "type": "(event: string) => void", + "description": "Emits when a navigation link is clicked. Emits the URL as a string.", + "frameworks": [ + "angular" + ] + }, + { + "name": "onToggle", + "type": "() => void", + "description": "Emits when the side menu is toggled open or closed.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [ + { + "name": "accountContent", + "type": "TemplateRef", + "description": "Content rendered in the account/profile slot.", + "required": false + }, + { + "name": "primaryContent", + "type": "TemplateRef", + "description": "Content rendered in the primary navigation slot.", + "required": false + }, + { + "name": "secondaryContent", + "type": "TemplateRef", + "description": "Content rendered in the secondary navigation slot.", + "required": false + } ] }, - { - "name": "onToggle", - "type": "(event: Event) => void", - "description": "", - "frameworks": [ - "react" + "webComponents": { + "props": [ + { + "name": "heading", + "type": "string", + "required": true, + "default": null, + "description": "The application name displayed in the header." + }, + { + "name": "open", + "type": "boolean", + "required": false, + "default": "false", + "description": "Controls whether the side menu is expanded or collapsed." + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "url", + "type": "string", + "required": true, + "default": null, + "description": "URL for the header link. Clicking the logo/heading navigates to this URL." + }, + { + "name": "user-name", + "type": "string", + "required": false, + "default": "", + "description": "User's name displayed in the profile section." + }, + { + "name": "user-secondary-text", + "type": "string", + "required": false, + "default": "", + "description": "Secondary text displayed below the user's name, such as role or email." + } + ], + "events": [ + { + "name": "_navigate", + "type": "CustomEvent<{ url: string }>", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_toggle", + "type": "CustomEvent<{ open: boolean }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [ + { + "name": "account", + "description": "Content rendered in the account/profile slot.", + "required": false + }, + { + "name": "primary", + "description": "Content rendered in the primary navigation slot.", + "required": false + }, + { + "name": "secondary", + "description": "Content rendered in the secondary navigation slot.", + "required": false + } ] - }, - { - "name": "_toggle", - "type": "CustomEvent", - "description": "", - "frameworks": [ - "angular" - ] - } - ], - "slots": [ - { - "name": "primary", - "description": "" - }, - { - "name": "secondary", - "description": "" - }, - { - "name": "account", - "description": "" } - ] + } } \ No newline at end of file diff --git a/docs/generated/component-apis/work-side-notification-item.json b/docs/generated/component-apis/work-side-notification-item.json new file mode 100644 index 0000000000..55f9b58184 --- /dev/null +++ b/docs/generated/component-apis/work-side-notification-item.json @@ -0,0 +1,224 @@ +{ + "componentSlug": "work-side-notification-item", + "extractedFrom": "libs/web-components/src/components/work-side-menu/WorkSideNotificationItem.svelte", + "frameworks": { + "react": { + "props": [ + { + "name": "description", + "type": "string", + "required": true, + "default": null, + "description": "The body text content of the notification card." + }, + { + "name": "priority", + "type": "GoabWorkSideNotificationPriority", + "required": false, + "default": "normal", + "description": "Sets the urgency level of the notification." + }, + { + "name": "readStatus", + "type": "GoabWorkSideNotificationReadStatus", + "required": false, + "default": "unread", + "description": "Indicates whether the notification has been read or is unread." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "timestamp", + "type": "string", + "required": false, + "default": null, + "description": "ISO timestamp string representing when the notification occurred." + }, + { + "name": "title", + "type": "string", + "required": false, + "default": null, + "description": "Title text displayed in the notification card header." + }, + { + "name": "type", + "type": "GoabWorkSideNotificationItemType", + "required": false, + "default": "default", + "description": "Sets the visual type/style of the notification item." + } + ], + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Callback fired when the notification item is clicked.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] + }, + "angular": { + "props": [ + { + "name": "description", + "type": "string", + "required": true, + "default": null, + "description": "The description text of the notification item." + }, + { + "name": "priority", + "type": "GoabWorkSideNotificationPriority", + "required": false, + "default": null, + "description": "Sets the priority level of the notification." + }, + { + "name": "readStatus", + "type": "GoabWorkSideNotificationReadStatus", + "required": false, + "default": null, + "description": "Indicates whether the notification is read or unread." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + }, + { + "name": "timestamp", + "type": "string", + "required": false, + "default": null, + "description": "The timestamp for when the notification was created." + }, + { + "name": "title", + "type": "string", + "required": false, + "default": null, + "description": "The title text of the notification item." + }, + { + "name": "type", + "type": "GoabWorkSideNotificationItemType", + "required": false, + "default": null, + "description": "Sets the visual style of the notification item." + } + ], + "events": [ + { + "name": "onClick", + "type": "() => void", + "description": "Emits when the notification item is clicked.", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] + }, + "webComponents": { + "props": [ + { + "name": "description", + "type": "string", + "required": false, + "default": "", + "description": "" + }, + { + "name": "priority", + "type": "\"normal\" | \"urgent\"", + "typeLabel": "GoabWorkSideNotificationItemPriority", + "values": [ + "normal", + "urgent" + ], + "required": false, + "default": "normal", + "description": "" + }, + { + "name": "read-status", + "type": "\"read\" | \"unread\"", + "typeLabel": "GoabWorkSideNotificationItemReadStatu", + "values": [ + "read", + "unread" + ], + "required": false, + "default": "unread", + "description": "" + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "" + }, + { + "name": "timestamp", + "type": "string", + "required": false, + "default": "", + "description": "" + }, + { + "name": "title", + "type": "string", + "required": false, + "default": "", + "description": "" + }, + { + "name": "type", + "type": "\"default\" | \"success\" | \"critical\" | \"warning\" | \"info\"", + "typeLabel": "GoabWorkSideNotificationItemType", + "values": [ + "default", + "success", + "critical", + "warning", + "info" + ], + "required": false, + "default": "default", + "description": "" + } + ], + "events": [ + { + "name": "_click", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_notificationItemRead", + "type": "CustomEvent<{ el: unknown; readStatus: unknown }>", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] + } + } +} \ No newline at end of file diff --git a/docs/generated/component-apis/work-side-notification-panel.json b/docs/generated/component-apis/work-side-notification-panel.json new file mode 100644 index 0000000000..679f4a58e7 --- /dev/null +++ b/docs/generated/component-apis/work-side-notification-panel.json @@ -0,0 +1,144 @@ +{ + "componentSlug": "work-side-notification-panel", + "extractedFrom": "libs/web-components/src/components/work-side-menu/WorkSideNotificationPanel.svelte", + "frameworks": { + "react": { + "props": [ + { + "name": "activeTab", + "type": "GoabWorkSideNotificationActiveTabType", + "required": false, + "default": "unread", + "description": "Sets the initially active tab." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": "Notifications", + "description": "Sets the panel heading text." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [ + { + "name": "onMarkAllRead", + "type": "() => void", + "description": "Callback fired when the \"Mark all as read\" button is clicked.", + "frameworks": [ + "react" + ] + }, + { + "name": "onViewAll", + "type": "() => void", + "description": "Callback fired when the \"View all\" button is clicked.", + "frameworks": [ + "react" + ] + } + ], + "slots": [] + }, + "angular": { + "props": [ + { + "name": "activeTab", + "type": "GoabWorkSideNotificationActiveTabType", + "required": false, + "default": null, + "description": "Sets the initially active tab in the notification panel." + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": null, + "description": "The heading text displayed at the top of the notification panel." + }, + { + "name": "testId", + "type": "string", + "required": false, + "default": null, + "description": "Sets a data-testid attribute for automated testing." + } + ], + "events": [ + { + "name": "onMarkAllRead", + "type": "() => void", + "description": "Emits when the user clicks \"Mark all as read\".", + "frameworks": [ + "angular" + ] + }, + { + "name": "onViewAll", + "type": "() => void", + "description": "Emits when the user clicks \"View all\".", + "frameworks": [ + "angular" + ] + } + ], + "slots": [] + }, + "webComponents": { + "props": [ + { + "name": "active-tab", + "type": "\"unread\" | \"urgent\" | \"all\"", + "typeLabel": "GoabWorkSideNotificationPanelTabType", + "values": [ + "unread", + "urgent", + "all" + ], + "required": false, + "default": "unread", + "description": "" + }, + { + "name": "heading", + "type": "string", + "required": false, + "default": "Notifications", + "description": "" + }, + { + "name": "testid", + "type": "string", + "required": false, + "default": "", + "description": "" + } + ], + "events": [ + { + "name": "_markAllRead", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + }, + { + "name": "_viewAll", + "type": "CustomEvent", + "description": "", + "frameworks": [ + "webComponents" + ] + } + ], + "slots": [] + } + } +} \ No newline at end of file diff --git a/docs/package-lock.json b/docs/package-lock.json index cd512e4c6c..194823a78d 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.1.1", + "@abgov/design-tokens-v2": "npm:@abgov/design-tokens@^2.8.0", "@abgov/react-components": "*", "@abgov/ui-components-common": "*", "@abgov/web-components": "*", @@ -20,9 +20,9 @@ }, "node_modules/@abgov/design-tokens-v2": { "name": "@abgov/design-tokens", - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@abgov/design-tokens/-/design-tokens-2.1.1.tgz", - "integrity": "sha512-JpNFdkgFIkrIQTmQ8h/A91EF4qoaXDK9sL/gN5QE54xCr8LxUCpEtdHpUVDwVhk8cugLrp6klhQMw8yqWLrBoA==" + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@abgov/design-tokens/-/design-tokens-2.8.0.tgz", + "integrity": "sha512-roDjWROKgJkrPuqsWLAapYefIyFI8BwNSTMt3IAX6dwmpZOGfbNrAhaAhF1F8toESXgBUA1SyWMA2VKuKcgSjw==" }, "node_modules/@abgov/react-components": { "version": "6.9.3", @@ -489,23 +489,6 @@ "node": ">=18" } }, - "node_modules/@types/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", - "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", - "license": "MIT", - "peer": true, - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT", - "peer": true - }, "node_modules/esbuild": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", @@ -582,29 +565,6 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", - "license": "MIT", - "peer": true, - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.3" - } - }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -615,13 +575,6 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT", - "peer": true - }, "node_modules/tsx": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", diff --git a/docs/package.json b/docs/package.json index bcd0424b90..01203da05f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -13,7 +13,7 @@ "astro": "astro" }, "dependencies": { - "@abgov/design-tokens-v2": "npm:@abgov/design-tokens@^2.1.1", + "@abgov/design-tokens-v2": "npm:@abgov/design-tokens@^2.8.0", "@abgov/react-components": "*", "@abgov/ui-components-common": "*", "@abgov/web-components": "*", diff --git a/docs/public/images/examples/ask-a-user-one-question-at-a-time.webp b/docs/public/images/examples/ask-a-user-one-question-at-a-time.webp deleted file mode 100644 index 6999f06b1c..0000000000 Binary files a/docs/public/images/examples/ask-a-user-one-question-at-a-time.webp and /dev/null differ diff --git a/docs/public/images/examples/confirm-that-an-application-was-submitted.webp b/docs/public/images/examples/confirm-that-an-application-was-submitted.webp deleted file mode 100644 index b37b6694ab..0000000000 Binary files a/docs/public/images/examples/confirm-that-an-application-was-submitted.webp and /dev/null differ diff --git a/docs/public/images/examples/give-more-information-before-asking-a-question-a.webp b/docs/public/images/examples/give-more-information-before-asking-a-question-a.webp deleted file mode 100644 index 45afa67e11..0000000000 Binary files a/docs/public/images/examples/give-more-information-before-asking-a-question-a.webp and /dev/null differ diff --git a/docs/public/images/examples/give-more-information-before-asking-a-question-b.webp b/docs/public/images/examples/give-more-information-before-asking-a-question-b.webp deleted file mode 100644 index 99f16ba6a9..0000000000 Binary files a/docs/public/images/examples/give-more-information-before-asking-a-question-b.webp and /dev/null differ diff --git a/docs/public/images/examples/group-related-questions-together-on-a-question-page.webp b/docs/public/images/examples/group-related-questions-together-on-a-question-page.webp deleted file mode 100644 index a7c3a08e53..0000000000 Binary files a/docs/public/images/examples/group-related-questions-together-on-a-question-page.webp and /dev/null differ diff --git a/docs/public/images/examples/my-applications-page.png b/docs/public/images/examples/my-applications-page.png new file mode 100644 index 0000000000..7d6e407876 Binary files /dev/null and b/docs/public/images/examples/my-applications-page.png differ diff --git a/docs/public/images/examples/public-form.webp b/docs/public/images/examples/public-form.webp deleted file mode 100644 index c56e904930..0000000000 Binary files a/docs/public/images/examples/public-form.webp and /dev/null differ diff --git a/docs/public/images/examples/question-page-background-radio.png b/docs/public/images/examples/question-page-background-radio.png new file mode 100644 index 0000000000..4722e777d8 Binary files /dev/null and b/docs/public/images/examples/question-page-background-radio.png differ diff --git a/docs/public/images/examples/question-page-grouped.png b/docs/public/images/examples/question-page-grouped.png new file mode 100644 index 0000000000..90e9355e43 Binary files /dev/null and b/docs/public/images/examples/question-page-grouped.png differ diff --git a/docs/public/images/examples/question-page-help-details.png b/docs/public/images/examples/question-page-help-details.png new file mode 100644 index 0000000000..acfdee2809 Binary files /dev/null and b/docs/public/images/examples/question-page-help-details.png differ diff --git a/docs/public/images/examples/question-page-one-question.png b/docs/public/images/examples/question-page-one-question.png new file mode 100644 index 0000000000..075973ca77 Binary files /dev/null and b/docs/public/images/examples/question-page-one-question.png differ diff --git a/docs/public/images/examples/question-page-progress-indicator.png b/docs/public/images/examples/question-page-progress-indicator.png new file mode 100644 index 0000000000..d3e67fe812 Binary files /dev/null and b/docs/public/images/examples/question-page-progress-indicator.png differ diff --git a/docs/public/images/examples/question-page-section-title.png b/docs/public/images/examples/question-page-section-title.png new file mode 100644 index 0000000000..5356646204 Binary files /dev/null and b/docs/public/images/examples/question-page-section-title.png differ diff --git a/docs/public/images/examples/question-page.png b/docs/public/images/examples/question-page.png new file mode 100644 index 0000000000..3ce45f38d0 Binary files /dev/null and b/docs/public/images/examples/question-page.png differ diff --git a/docs/public/images/examples/question-page.webp b/docs/public/images/examples/question-page.webp deleted file mode 100644 index 45592418c1..0000000000 Binary files a/docs/public/images/examples/question-page.webp and /dev/null differ diff --git a/docs/public/images/examples/result-page.png b/docs/public/images/examples/result-page.png new file mode 100644 index 0000000000..55c9ef6ac9 Binary files /dev/null and b/docs/public/images/examples/result-page.png differ diff --git a/docs/public/images/examples/result-page.webp b/docs/public/images/examples/result-page.webp deleted file mode 100644 index aaeead3d27..0000000000 Binary files a/docs/public/images/examples/result-page.webp and /dev/null differ diff --git a/docs/public/images/examples/review-page.png b/docs/public/images/examples/review-page.png new file mode 100644 index 0000000000..a4a655dfca Binary files /dev/null and b/docs/public/images/examples/review-page.png differ diff --git a/docs/public/images/examples/review-page.webp b/docs/public/images/examples/review-page.webp deleted file mode 100644 index ed544bc60a..0000000000 Binary files a/docs/public/images/examples/review-page.webp and /dev/null differ diff --git a/docs/public/images/examples/show-a-list-to-help-answer-a-question.webp b/docs/public/images/examples/show-a-list-to-help-answer-a-question.webp deleted file mode 100644 index c63b3b0e5c..0000000000 Binary files a/docs/public/images/examples/show-a-list-to-help-answer-a-question.webp and /dev/null differ diff --git a/docs/public/images/examples/show-a-section-title-on-a-question-page.webp b/docs/public/images/examples/show-a-section-title-on-a-question-page.webp deleted file mode 100644 index 9eb75e3a49..0000000000 Binary files a/docs/public/images/examples/show-a-section-title-on-a-question-page.webp and /dev/null differ diff --git a/docs/public/images/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.webp b/docs/public/images/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.webp deleted file mode 100644 index f6c96f70f7..0000000000 Binary files a/docs/public/images/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.webp and /dev/null differ diff --git a/docs/public/images/examples/show-a-simple-progress-indicator-on-a-question-page.webp b/docs/public/images/examples/show-a-simple-progress-indicator-on-a-question-page.webp deleted file mode 100644 index e494c970bd..0000000000 Binary files a/docs/public/images/examples/show-a-simple-progress-indicator-on-a-question-page.webp and /dev/null differ diff --git a/docs/public/images/examples/show-more-information-to-help-answer-a-question.webp b/docs/public/images/examples/show-more-information-to-help-answer-a-question.webp deleted file mode 100644 index 81386807c1..0000000000 Binary files a/docs/public/images/examples/show-more-information-to-help-answer-a-question.webp and /dev/null differ diff --git a/docs/public/images/examples/start-page.png b/docs/public/images/examples/start-page.png new file mode 100644 index 0000000000..479cd01db9 Binary files /dev/null and b/docs/public/images/examples/start-page.png differ diff --git a/docs/public/images/examples/start-page.webp b/docs/public/images/examples/start-page.webp deleted file mode 100644 index 7cb04e4f74..0000000000 Binary files a/docs/public/images/examples/start-page.webp and /dev/null differ diff --git a/docs/public/images/examples/task-list-page.png b/docs/public/images/examples/task-list-page.png new file mode 100644 index 0000000000..54699ea39e Binary files /dev/null and b/docs/public/images/examples/task-list-page.png differ diff --git a/docs/public/images/examples/task-list-page.webp b/docs/public/images/examples/task-list-page.webp deleted file mode 100644 index a8d6acfe21..0000000000 Binary files a/docs/public/images/examples/task-list-page.webp and /dev/null differ diff --git a/docs/public/images/home/hero-banner-gradient-dark.svg b/docs/public/images/home/hero-banner-gradient-dark.svg new file mode 100644 index 0000000000..0fd953e0f3 --- /dev/null +++ b/docs/public/images/home/hero-banner-gradient-dark.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/images/home/main-pages-thumb.svg b/docs/public/images/home/main-pages-thumb.svg new file mode 100644 index 0000000000..47d6eda402 --- /dev/null +++ b/docs/public/images/home/main-pages-thumb.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/images/home/primary-users-thumb.svg b/docs/public/images/home/primary-users-thumb.svg new file mode 100644 index 0000000000..cc61e485e0 --- /dev/null +++ b/docs/public/images/home/primary-users-thumb.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/docs/public/images/home/storyboard-thumb.svg b/docs/public/images/home/storyboard-thumb.svg new file mode 100644 index 0000000000..94ac6b1cdd --- /dev/null +++ b/docs/public/images/home/storyboard-thumb.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/public/search-index.json b/docs/public/search-index.json index b8c930df1d..be01a451f5 100644 --- a/docs/public/search-index.json +++ b/docs/public/search-index.json @@ -11,8 +11,7 @@ "blind", "collapse", "content layout", - "expandable panel", - "expand" + "expandable panel" ], "slug": "accordion" }, @@ -179,7 +178,14 @@ "description": "Advanced table with sorting and selection.", "status": "stable", "category": "content-layout", - "tags": [], + "tags": [ + "table", + "grid", + "content layout", + "data table", + "sorting", + "selection" + ], "slug": "data-grid" }, { @@ -246,7 +252,7 @@ "name": "Drawer", "description": "A panel that slides in from the side of the screen to display additional content or actions without navigating away from the current view.", "status": "stable", - "category": "content-layout", + "category": "structure-and-navigation", "tags": [ "sections", "structure and navigation", @@ -325,34 +331,6 @@ ], "slug": "form-item" }, - { - "type": "component", - "id": "form-stepper", - "name": "Form stepper", - "description": "Provides a visual representation of a form through a series of steps.", - "status": "deprecated", - "category": "structure-and-navigation", - "tags": [ - "form stepper", - "horizontal step navigation", - "process overview", - "progress indicator", - "steps", - "structure and navigation", - "wizard" - ], - "slug": "form-stepper" - }, - { - "type": "component", - "id": "form", - "name": "Form", - "description": "Container for form inputs and validation.", - "status": "stable", - "category": "inputs-and-actions", - "tags": [], - "slug": "form" - }, { "type": "component", "id": "grid", @@ -724,15 +702,27 @@ "tags": [], "slug": "work-side-menu" }, + { + "type": "component", + "id": "work-side-notification-panel", + "name": "Notification Panel", + "description": "A notification center panel that displays notification items within a work side menu, with tabs for filtering by unread, urgent, and all notifications.", + "status": "stable", + "category": "structure-and-navigation", + "tags": [ + "notifications", + "work side menu", + "panel" + ], + "slug": "work-side-notification-panel" + }, { "type": "example", "id": "add-a-filter-chip", "title": "Add a filter chip", "description": "Allow users to apply filters using selectable chips, which visually represent active filters and can be removed to update results dynamically.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "filtering", "chips", @@ -742,8 +732,7 @@ "filter-chip", "button" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "add-a-filter-chip" }, { @@ -752,9 +741,8 @@ "title": "Add a record using a drawer", "description": "Add a record using a drawer. The drawer slides in from the side to allow data entry without navigating away from the current view.", "status": "published", - "categories": [ - "structure-and-navigation" - ], + "size": "section", + "productType": "workspace", "tags": [ "drawer", "forms", @@ -771,8 +759,7 @@ "radio-group", "block" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "add-a-record-using-a-drawer" }, { @@ -781,9 +768,8 @@ "title": "Add and edit lots of filters", "description": "Add and edit filters using a drawer. This pattern is useful when you have many filter options that would clutter the main interface.", "status": "published", - "categories": [ - "structure-and-navigation" - ], + "size": "section", + "productType": "workspace", "tags": [ "filtering", "drawer", @@ -800,8 +786,7 @@ "dropdown", "radio-group" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "add-and-edit-lots-of-filters" }, { @@ -810,9 +795,7 @@ "title": "Add another item in a modal", "description": "Add a new item within a modal window without navigating away from the current context.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "section", "tags": [ "modal", "forms", @@ -827,8 +810,7 @@ "input", "text-area" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "add-another-item-in-a-modal" }, { @@ -837,9 +819,8 @@ "title": "Ask a long answer question with a maximum word count", "description": "Restrict a long answer input to a maximum number of words or characters.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", + "productType": "public-form", "tags": [ "forms", "text-area", @@ -850,8 +831,7 @@ "form-item", "text-area" ], - "scale": "task", - "userType": "citizen", + "aliases": [], "slug": "ask-a-long-answer-question-with-a-maximum-word-count" }, { @@ -860,9 +840,8 @@ "title": "Ask a user for a birthday", "description": "Asks for a user's birthday using the date picker component.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", + "productType": "public-form", "tags": [ "forms", "date-input", @@ -872,8 +851,7 @@ "form-item", "date-picker" ], - "scale": "task", - "userType": "citizen", + "aliases": [], "slug": "ask-a-user-for-a-birthday" }, { @@ -882,9 +860,8 @@ "title": "Ask a user for an address", "description": "Collect a complete mailing address from the user, including fields like street, city, and postal code.", "status": "published", - "categories": [ - "forms" - ], + "size": "section", + "productType": "public-form", "tags": [ "forms", "address", @@ -899,8 +876,7 @@ "button-group", "text" ], - "scale": "task", - "userType": "citizen", + "aliases": [], "slug": "ask-a-user-for-an-address" }, { @@ -909,9 +885,8 @@ "title": "Ask a user for an Indian registration number", "description": "Request a user's Indian registration number with appropriate validation and context.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", + "productType": "public-form", "tags": [ "forms", "identity", @@ -922,8 +897,7 @@ "input", "block" ], - "scale": "task", - "userType": "citizen", + "aliases": [], "slug": "ask-a-user-for-an-indian-registration-number" }, { @@ -932,9 +906,8 @@ "title": "Ask a user for direct deposit information", "description": "Gather banking details from users to enable direct deposit, including account number and financial institution information.", "status": "published", - "categories": [ - "forms" - ], + "size": "section", + "productType": "public-form", "tags": [ "forms", "banking", @@ -946,8 +919,7 @@ "details", "text" ], - "scale": "task", - "userType": "citizen", + "aliases": [], "slug": "ask-a-user-for-direct-deposit-information" }, { @@ -956,9 +928,8 @@ "title": "Ask a user for dollar amounts", "description": "Prompt users to enter monetary values using a consistent input format that supports validation and currency symbols.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", + "productType": "public-form", "tags": [ "forms", "currency", @@ -968,43 +939,16 @@ "form-item", "input" ], - "scale": "task", - "userType": "citizen", + "aliases": [], "slug": "ask-a-user-for-dollar-amounts" }, - { - "type": "example", - "id": "ask-a-user-one-question-at-a-time", - "title": "Ask a user one question at a time", - "description": "Ask a user one question at a time.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "forms", - "questions", - "public-form" - ], - "components": [ - "form-item", - "radio-group", - "radio-item", - "button" - ], - "scale": "page", - "userType": "citizen", - "slug": "ask-a-user-one-question-at-a-time" - }, { "type": "example", "id": "basic-page-layout", "title": "Basic page layout", "description": "A basic page template to use as a starting point.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "page", "tags": [ "layout", "page-structure", @@ -1017,8 +961,7 @@ "skeleton", "grid" ], - "scale": "page", - "userType": "both", + "aliases": [], "slug": "basic-page-layout" }, { @@ -1027,9 +970,7 @@ "title": "Button with Icon", "description": "Shows how to add leading or trailing icons to buttons for enhanced visual communication.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "icons", "buttons", @@ -1040,8 +981,7 @@ "button-group", "icon" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "button-with-icon" }, { @@ -1050,9 +990,7 @@ "title": "Card grid", "description": "Display multiple cards in a grid layout, each containing related content or actions.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", "tags": [ "cards", "grid", @@ -1065,8 +1003,7 @@ "link", "text" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "card-grid" }, { @@ -1075,9 +1012,8 @@ "title": "Card view of case files", "description": "Present a visual overview of individual case files in a card format for scanning and access.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", + "productType": "workspace", "tags": [ "cards", "case-management", @@ -1090,41 +1026,16 @@ "badge", "button" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "card-view-of-case-files" }, - { - "type": "example", - "id": "communicate-a-future-service-outage", - "title": "Communicate a future service outage", - "description": "Display a clear message to inform users about an upcoming service outage, including the date, time, and expected impact on service availability.", - "status": "published", - "categories": [ - "feedback-and-alerts" - ], - "tags": [ - "notification", - "maintenance", - "alerts", - "system-status" - ], - "components": [ - "notification" - ], - "scale": "task", - "userType": "both", - "slug": "communicate-a-future-service-outage" - }, { "type": "example", "id": "confirm-a-change", "title": "Confirm a change", "description": "Ask the user to confirm a proposed change before it is applied.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "modal", "confirmation", @@ -1139,8 +1050,7 @@ "form-item", "date-picker" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "confirm-a-change" }, { @@ -1149,9 +1059,7 @@ "title": "Confirm a destructive action", "description": "Confirm a destructive action like deletion to prevent accidental data loss.", "status": "published", - "categories": [ - "feedback-and-alerts" - ], + "size": "interaction", "tags": [ "modal", "confirmation", @@ -1163,8 +1071,7 @@ "button", "button-group" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "confirm-a-destructive-action" }, { @@ -1173,9 +1080,8 @@ "title": "Confirm before navigating away", "description": "Prompt the user in a modal before navigating to a new route to preserve context.", "status": "published", - "categories": [ - "feedback-and-alerts" - ], + "size": "interaction", + "productType": "workspace", "tags": [ "modal", "navigation", @@ -1187,43 +1093,16 @@ "button", "button-group" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "confirm-before-navigating-away" }, - { - "type": "example", - "id": "confirm-that-an-application-was-submitted", - "title": "Confirm that an application was submitted", - "description": "Display a confirmation screen to indicate successful application submission.", - "status": "published", - "categories": [ - "feedback-and-alerts" - ], - "tags": [ - "confirmation", - "success", - "callout", - "application" - ], - "components": [ - "callout", - "button", - "button-group" - ], - "scale": "page", - "userType": "citizen", - "slug": "confirm-that-an-application-was-submitted" - }, { "type": "example", "id": "copy-to-clipboard", "title": "Copy to clipboard", "description": "Allow users to quickly copy text or data to their clipboard with a single click.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "clipboard", "copy", @@ -1235,8 +1114,7 @@ "icon-button", "tooltip" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "copy-to-clipboard" }, { @@ -1245,9 +1123,7 @@ "title": "Disabled button with a required field", "description": "Disable a submit button until required form fields are completed.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "button", "form", @@ -1261,8 +1137,7 @@ "form-item", "input" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "disabled-button-with-a-required-field" }, { @@ -1271,9 +1146,8 @@ "title": "Display numbers in a table so they can be scanned easily", "description": "Right-align numeric columns in tables to make them easier to scan and compare.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", + "productType": "workspace", "tags": [ "table", "numbers", @@ -1284,8 +1158,7 @@ "components": [ "table" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "display-numbers-in-a-table-so-they-can-be-scanned-easily" }, { @@ -1294,9 +1167,8 @@ "title": "Display user information", "description": "Display user contact information and related data using containers with clear visual hierarchy.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", + "productType": "workspace", "tags": [ "container", "user-info", @@ -1311,8 +1183,7 @@ "table", "text" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "display-user-information" }, { @@ -1321,9 +1192,7 @@ "title": "Dynamically add an item to a dropdown list", "description": "Allow users to add new items to a dropdown list dynamically.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "dropdown", "dynamic", @@ -1338,8 +1207,7 @@ "input", "button" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "dynamically-add-an-item-to-a-dropdown-list" }, { @@ -1348,9 +1216,7 @@ "title": "Dynamically change items in a dropdown list", "description": "Update dropdown options based on the selection in another dropdown (cascading/dependent dropdowns).", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "dropdown", "dynamic", @@ -1363,19 +1229,51 @@ "dropdown-item", "form-item" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "dynamically-change-items-in-a-dropdown-list" }, + { + "type": "example", + "id": "error-pages", + "title": "Error pages", + "description": "Standard error screens for Government of Alberta services. Use when a user lands somewhere that is missing, forbidden, or broken so they understand what happened and what to do next.", + "status": "published", + "size": "page", + "tags": [ + "error", + "error page", + "\"401\"", + "\"404\"", + "\"500\"", + "page not found", + "unauthorized", + "restricted access", + "server error", + "server problem", + "page-structure" + ], + "components": [ + "page-block", + "block", + "text", + "icon", + "link", + "button" + ], + "aliases": [ + "401-error-page", + "404-error-page", + "500-error-page" + ], + "slug": "error-pages" + }, { "type": "example", "id": "expand-or-collapse-part-of-a-form", "title": "Expand or collapse part of a form", "description": "Use accordions to organize form review sections that users can expand or collapse.", "status": "published", - "categories": [ - "forms" - ], + "size": "section", "tags": [ "accordion", "form", @@ -1387,8 +1285,7 @@ "accordion", "badge" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "expand-or-collapse-part-of-a-form" }, { @@ -1397,9 +1294,8 @@ "title": "Filter a list using a push drawer", "description": "Use a push drawer to house filters alongside a list of records. The push drawer keeps the filter controls accessible while users can still see and interact with the filtered results.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", + "productType": "workspace", "tags": [ "push-drawer", "filters", @@ -1416,8 +1312,7 @@ "dropdown", "form-item" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "filter-a-list-using-a-push-drawer" }, { @@ -1426,9 +1321,8 @@ "title": "Filter data in a table", "description": "Enable users to filter table data using search input and filter chips.", "status": "published", - "categories": [ - "structure-and-navigation" - ], + "size": "section", + "productType": "workspace", "tags": [ "table", "filter", @@ -1446,127 +1340,16 @@ "badge", "text" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "filter-data-in-a-table" }, - { - "type": "example", - "id": "form-stepper-with-controlled-navigation", - "title": "Form stepper with controlled navigation", - "description": "Create a multi-step form with controlled navigation using Previous/Next buttons.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "stepper", - "form", - "wizard", - "multi-step", - "navigation", - "pages" - ], - "components": [ - "form-stepper", - "form-step", - "pages", - "button", - "skeleton", - "spacer" - ], - "scale": "task", - "userType": "both", - "slug": "form-stepper-with-controlled-navigation" - }, - { - "type": "example", - "id": "give-background-information-before-asking-a-question", - "title": "Give background information before asking a question", - "description": "Provide explanatory context before asking a question to help users understand what is being asked.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "form", - "question", - "context", - "radio", - "citizen-facing" - ], - "components": [ - "form-item", - "radio-group", - "radio-item", - "button" - ], - "scale": "task", - "userType": "citizen", - "slug": "give-background-information-before-asking-a-question" - }, - { - "type": "example", - "id": "give-context-before-asking-a-long-answer-question", - "title": "Give context before asking a long answer question", - "description": "Provide context and guidance before a long-answer text field to help users provide relevant information.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "form", - "text-area", - "question", - "context", - "details", - "citizen-facing" - ], - "components": [ - "text-area", - "form-item", - "details", - "button", - "button-group" - ], - "scale": "task", - "userType": "citizen", - "slug": "give-context-before-asking-a-long-answer-question" - }, - { - "type": "example", - "id": "group-related-questions-together-on-a-question-page", - "title": "Group related questions together on a question page", - "description": "Group related form fields together on a single page to collect address information from users, making it easier to complete logically connected questions at once.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "forms", - "address", - "question-page" - ], - "components": [ - "form-item", - "input", - "dropdown", - "dropdown-item", - "button" - ], - "scale": "page", - "userType": "citizen", - "slug": "group-related-questions-together-on-a-question-page" - }, { "type": "example", "id": "header-with-navigation", "title": "Header with navigation", "description": "An application header with navigation links, grouped menu items, and a user account menu.", "status": "published", - "categories": [ - "structure-and-navigation" - ], + "size": "section", "tags": [ "header", "navigation", @@ -1576,8 +1359,7 @@ "app-header", "app-header-menu" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "header-with-navigation" }, { @@ -1586,9 +1368,7 @@ "title": "Hero banner with actions", "description": "Create a hero banner with a call-to-action button to guide users toward the primary task on a landing page.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", "tags": [ "hero", "banner", @@ -1599,8 +1379,7 @@ "hero-banner", "button" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "hero-banner-with-actions" }, { @@ -1609,9 +1388,7 @@ "title": "Hide and show many sections of information", "description": "Allow users to expand and collapse multiple accordion sections, with a button to show or hide all sections at once.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", "tags": [ "accordion", "expand", @@ -1622,8 +1399,7 @@ "accordion", "button" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "hide-and-show-many-sections-of-information" }, { @@ -1632,9 +1408,7 @@ "title": "Include a link in the helper text of an option", "description": "Add links within the description text of checkbox options to provide additional context or resources while users are making selections.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", "tags": [ "checkbox", "helper-text", @@ -1645,8 +1419,7 @@ "checkbox", "form-item" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "include-a-link-in-the-helper-text-of-an-option" }, { @@ -1655,9 +1428,7 @@ "title": "Include descriptions for items in a checkbox list", "description": "Add descriptive text to radio button options to help users understand the implications of each choice.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", "tags": [ "radio", "descriptions", @@ -1668,8 +1439,7 @@ "radio-group", "radio-item" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "include-descriptions-for-items-in-a-checkbox-list" }, { @@ -1678,9 +1448,7 @@ "title": "Link the user to give feedback to the service", "description": "Use the microsite header's feedback functionality to collect user feedback during alpha or beta phases of a service.", "status": "published", - "categories": [ - "feedback-and-alerts" - ], + "size": "interaction", "tags": [ "feedback", "microsite-header", @@ -1690,8 +1458,7 @@ "components": [ "microsite-header" ], - "scale": "interaction", - "userType": "citizen", + "aliases": [], "slug": "link-the-user-to-give-feedback-to-the-service" }, { @@ -1700,9 +1467,7 @@ "title": "Link to an external page", "description": "Use an external link indicator to show users when a link will take them to a different website.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "link", "external", @@ -1711,53 +1476,74 @@ "components": [ "link" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "link-to-an-external-page" }, { "type": "example", - "id": "public-form", - "title": "Public form", - "description": "The public form pattern provides a structure for citizen-facing form experiences, emphasizing simplicity, accessibility, and low cognitive load.", + "id": "notify-the-user-of-a-future-service-outage", + "title": "Notify the user of a future service outage", + "description": "Display a clear message to inform users about an upcoming service outage, including the date, time, and expected impact on service availability.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", "tags": [ - "form", - "public", - "citizen", - "pattern" + "notification", + "maintenance", + "alerts", + "system-status" ], - "components": [], - "scale": "service", - "userType": "citizen", - "slug": "public-form" + "components": [ + "notification" + ], + "aliases": [], + "slug": "notify-the-user-of-a-future-service-outage" }, { "type": "example", "id": "question-page", "title": "Question page", - "description": "A question page pattern that presents one question at a time to help users focus, reduce cognitive load, and navigate complex forms more easily.", + "description": "A question page presents one focused step in a multi-step form. Several variants adapt the shape: section titles, progress indicators, supporting context, expandable help, and grouped fields.", "status": "published", - "categories": [ - "forms" - ], + "size": "page", + "productType": "public-form", "tags": [ "forms", "question", "wizard", - "one-thing-per-page" + "one-thing-per-page", + "public-form", + "section-title", + "progress", + "context", + "help", + "details", + "grouped-fields", + "address" ], "components": [ "form-item", "input", + "text-area", + "radio-group", + "radio-item", + "dropdown", + "dropdown-item", + "details", + "block", "button", "button-group" ], - "scale": "page", - "userType": "citizen", + "aliases": [ + "ask-a-user-one-question-at-a-time", + "give-more-information-before-asking-a-question-a", + "give-more-information-before-asking-a-question-b", + "show-more-information-to-help-answer-a-question", + "show-a-list-to-help-answer-a-question", + "show-a-section-title-on-a-question-page", + "show-a-simple-progress-indicator-on-a-question-page", + "show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions", + "group-related-questions-together-on-a-question-page" + ], "slug": "question-page" }, { @@ -1766,9 +1552,7 @@ "title": "Remove a filter", "description": "Allow users to remove active filters by clicking on filter chips, providing clear visual feedback and dynamic updates to filtered results.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "filtering", "chips", @@ -1777,8 +1561,7 @@ "components": [ "filter-chip" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "remove-a-filter" }, { @@ -1787,9 +1570,7 @@ "title": "Require user action before continuing", "description": "Use a modal dialog to require users to confirm an action before proceeding, especially for irreversible operations or important decision points.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", "tags": [ "modal", "confirmation", @@ -1801,8 +1582,7 @@ "button", "button-group" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "require-user-action-before-continuing" }, { @@ -1811,9 +1591,7 @@ "title": "Reset date picker field", "description": "Allow users to programmatically set or clear a date picker field value, useful for reset functionality or setting default dates.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "date-picker", "form", @@ -1826,31 +1604,33 @@ "button", "button-group" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "reset-date-picker-field" }, { "type": "example", "id": "result-page", "title": "Result page", - "description": "A result page shown after form submission to confirm success, provide next steps, and offer relevant contact information.", + "description": "A result page shown after a citizen has submitted a form, application, or task. Confirms success, explains what happens next, and points the user at any follow-up actions.", "status": "published", - "categories": [ - "forms" - ], + "size": "page", + "productType": "public-form", "tags": [ "confirmation", "success", "completion", - "forms" + "forms", + "application" ], "components": [ "block", - "callout" + "callout", + "button", + "button-group" + ], + "aliases": [ + "confirm-that-an-application-was-submitted" ], - "scale": "page", - "userType": "citizen", "slug": "result-page" }, { @@ -1859,9 +1639,7 @@ "title": "Reveal input based on a selection", "description": "Progressively reveal additional form fields based on user selections, reducing visual complexity while gathering necessary information.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", "tags": [ "conditional", "reveal", @@ -1876,8 +1654,7 @@ "form-item", "input" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "reveal-input-based-on-a-selection" }, { @@ -1886,9 +1663,8 @@ "title": "Review and action", "description": "A side-by-side layout for workers to review case details while taking an action, commonly used in case management and approval workflows.", "status": "published", - "categories": [ - "structure-and-navigation" - ], + "size": "section", + "productType": "workspace", "tags": [ "review", "action", @@ -1906,19 +1682,17 @@ "text-area", "button" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "review-and-action" }, { "type": "example", "id": "review-page", "title": "Review page", - "description": "A review page where users can check their answers before submitting a form, with options to change individual responses.", + "description": "A review page lets a user check their answers at the end of a form or section before submitting. Each answer has a \"change\" link so the user can revise without starting over.", "status": "published", - "categories": [ - "forms" - ], + "size": "page", + "productType": "public-form", "tags": [ "review", "check-answers", @@ -1930,8 +1704,7 @@ "button", "button-group" ], - "scale": "page", - "userType": "citizen", + "aliases": [], "slug": "review-page" }, { @@ -1940,9 +1713,7 @@ "title": "Search", "description": "A search input pattern with a search icon and button for users to find content or filter results.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "search", "input", @@ -1954,8 +1725,7 @@ "block", "form-item" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "search" }, { @@ -1964,9 +1734,7 @@ "title": "Select one or more from a list of options", "description": "Use checkboxes to let users select one or more options from a list when multiple selections are valid.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", "tags": [ "checkbox", "selection", @@ -1977,8 +1745,7 @@ "checkbox", "form-item" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "select-one-or-more-from-a-list-of-options" }, { @@ -1987,9 +1754,7 @@ "title": "Set a max width on a long radio item", "description": "Set a max width on a long radio item to control line wrapping.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "radio", "forms", @@ -2000,8 +1765,7 @@ "radio-group", "radio-item" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "set-a-max-width-on-a-long-radio-item" }, { @@ -2010,9 +1774,7 @@ "title": "Set a specific tab to be active", "description": "Set a specific tab to be active on page load using the initialTab property.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "tabs", "navigation", @@ -2025,44 +1787,16 @@ "badge", "button" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "set-a-specific-tab-to-be-active" }, - { - "type": "example", - "id": "set-the-status-of-step-on-a-form-stepper", - "title": "Set the status of step on a form stepper", - "description": "Set the status of each step on a form stepper to indicate completion progress.", - "status": "published", - "categories": [ - "inputs-and-actions" - ], - "tags": [ - "forms", - "stepper", - "multi-step", - "navigation" - ], - "components": [ - "form-stepper", - "form-step", - "pages", - "button" - ], - "scale": "task", - "userType": "both", - "slug": "set-the-status-of-step-on-a-form-stepper" - }, { "type": "example", "id": "show-a-label-on-an-icon-only-button", "title": "Show a label on an icon only button", "description": "Show a label on an icon-only button using a tooltip to improve discoverability.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "buttons", "icons", @@ -2074,45 +1808,16 @@ "tooltip", "button-group" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "show-a-label-on-an-icon-only-button" }, - { - "type": "example", - "id": "show-a-list-to-help-answer-a-question", - "title": "Show a list to help answer a question", - "description": "Show a list to help answer a question using an expandable details component.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "forms", - "details", - "guidance", - "help" - ], - "components": [ - "form-item", - "radio-group", - "radio-item", - "details", - "block" - ], - "scale": "task", - "userType": "citizen", - "slug": "show-a-list-to-help-answer-a-question" - }, { "type": "example", "id": "show-a-notification", "title": "Show a notification", "description": "Show a temporary notification to confirm an action was completed successfully.", "status": "published", - "categories": [ - "feedback-and-alerts" - ], + "size": "interaction", "tags": [ "notification", "feedback", @@ -2123,8 +1828,7 @@ "temporary-notification", "button" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "show-a-notification" }, { @@ -2133,9 +1837,7 @@ "title": "Show a notification with an action", "description": "Show a temporary notification with an action button for user interaction.", "status": "published", - "categories": [ - "feedback-and-alerts" - ], + "size": "interaction", "tags": [ "notification", "feedback", @@ -2146,94 +1848,16 @@ "temporary-notification", "button" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "show-a-notification-with-an-action" }, - { - "type": "example", - "id": "show-a-section-title-on-a-question-page", - "title": "Show a section title on a question page", - "description": "Show a section title on a question page to help users understand which part of the form they are completing.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "forms", - "questions", - "navigation", - "section" - ], - "components": [ - "form-item", - "radio-group", - "radio-item", - "button" - ], - "scale": "task", - "userType": "citizen", - "slug": "show-a-section-title-on-a-question-page" - }, - { - "type": "example", - "id": "show-a-simple-progress-indicator-on-a-question-page", - "title": "Show a simple progress indicator on a question page", - "description": "Show a simple progress indicator on a question page to help users understand their progress through the form.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "forms", - "questions", - "progress", - "navigation" - ], - "components": [ - "form-item", - "radio-group", - "radio-item", - "button" - ], - "scale": "task", - "userType": "citizen", - "slug": "show-a-simple-progress-indicator-on-a-question-page" - }, - { - "type": "example", - "id": "show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions", - "title": "Show a simple progress indicator on a question page with multiple questions", - "description": "Show a simple progress indicator on a question page when grouping multiple related questions together.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "forms", - "questions", - "progress", - "navigation", - "multi-question" - ], - "components": [ - "form-item", - "input", - "button" - ], - "scale": "task", - "userType": "citizen", - "slug": "show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions" - }, { "type": "example", "id": "show-a-user-progress", "title": "Show a user progress", "description": "Display progress feedback during long-running operations like downloads, showing percentage completion with the ability to cancel and receive success confirmation.", "status": "published", - "categories": [ - "feedback-and-alerts" - ], + "size": "interaction", "tags": [ "progress", "notification", @@ -2244,8 +1868,7 @@ "temporary-notification", "button" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "show-a-user-progress" }, { @@ -2254,9 +1877,7 @@ "title": "Show a user progress when the time is unknown", "description": "Display indeterminate progress for operations where completion time cannot be estimated, such as complex searches or external system queries.", "status": "published", - "categories": [ - "feedback-and-alerts" - ], + "size": "interaction", "tags": [ "progress", "notification", @@ -2268,8 +1889,7 @@ "temporary-notification", "button" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "show-a-user-progress-when-the-time-is-unknown" }, { @@ -2278,9 +1898,8 @@ "title": "Show different views of data in a table", "description": "Use tabs to organize table data into different views based on status or category, showing counts in each tab to help workers quickly navigate to relevant items.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", + "productType": "workspace", "tags": [ "table", "tabs", @@ -2295,8 +1914,7 @@ "badge", "button" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "show-different-views-of-data-in-a-table" }, { @@ -2305,9 +1923,7 @@ "title": "Show full date in a tooltip", "description": "Display relative time (like \"4 hours ago\") while providing the full date and time on hover via tooltip for users who need exact timestamps.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "tooltip", "date", @@ -2318,8 +1934,7 @@ "tooltip", "container" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "show-full-date-in-a-tooltip" }, { @@ -2328,9 +1943,7 @@ "title": "Show links to navigation items", "description": "Use the app footer to display comprehensive navigation links organized into sections, along with meta links for common utilities like privacy and accessibility.", "status": "published", - "categories": [ - "structure-and-navigation" - ], + "size": "section", "tags": [ "footer", "navigation", @@ -2342,46 +1955,17 @@ "footer-nav-section", "footer-meta-section" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "show-links-to-navigation-items" }, - { - "type": "example", - "id": "show-more-information-to-help-answer-a-question", - "title": "Show more information to help answer a question", - "description": "Use the Details component to provide optional contextual help that explains why a question is being asked, helping users understand the purpose without cluttering the main form.", - "status": "published", - "categories": [ - "forms" - ], - "tags": [ - "form", - "details", - "help", - "question-page", - "expandable" - ], - "components": [ - "details", - "form-item", - "radio-group", - "radio-item", - "button" - ], - "scale": "task", - "userType": "citizen", - "slug": "show-more-information-to-help-answer-a-question" - }, { "type": "example", "id": "show-multiple-actions-in-a-compact-table", "title": "Show multiple actions in a compact table", "description": "Use icon buttons to provide multiple row actions in tables where space is limited, keeping the interface compact while maintaining accessibility through aria labels.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", + "productType": "workspace", "tags": [ "table", "icon-button", @@ -2395,8 +1979,7 @@ "badge", "block" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "show-multiple-actions-in-a-compact-table" }, { @@ -2405,9 +1988,7 @@ "title": "Show multiple tags together", "description": "Display multiple badges together using GoabBlock with tight spacing to show multiple statuses or categories for a single item.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "badge", "tags", @@ -2418,8 +1999,7 @@ "badge", "block" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "show-multiple-tags-together" }, { @@ -2428,9 +2008,7 @@ "title": "Show number of results per page", "description": "Combine pagination with a dropdown selector to let users control how many results appear per page, improving data browsing for different use cases.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", "tags": [ "pagination", "table", @@ -2446,8 +2024,7 @@ "block", "spacer" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "show-number-of-results-per-page" }, { @@ -2456,9 +2033,7 @@ "title": "Show quick links", "description": "Use the app footer meta section to display essential quick links like feedback, accessibility, privacy, and contact information without the full navigation structure.", "status": "published", - "categories": [ - "structure-and-navigation" - ], + "size": "section", "tags": [ "footer", "navigation", @@ -2469,8 +2044,7 @@ "footer", "footer-meta-section" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "show-quick-links" }, { @@ -2479,9 +2053,8 @@ "title": "Show status in a table", "description": "Display status information within table rows using badges to provide clear visual indicators of item states like pending, complete, failed, or in progress.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", + "productType": "workspace", "tags": [ "table", "badge", @@ -2492,8 +2065,7 @@ "badge", "button" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "show-status-in-a-table" }, { @@ -2502,9 +2074,8 @@ "title": "Show status on a card", "description": "Display status indicators on cards using badges in the actions slot, allowing workers to quickly see the priority or state of each item.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "interaction", + "productType": "workspace", "tags": [ "card", "container", @@ -2515,8 +2086,7 @@ "container", "badge" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "show-status-on-a-card" }, { @@ -2525,9 +2095,7 @@ "title": "Show version number", "description": "Display version information in the microsite header using the version slot, allowing custom formatting and styling of version text.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "microsite-header", "version", @@ -2537,8 +2105,7 @@ "components": [ "microsite-header" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "show-version-number" }, { @@ -2547,9 +2114,7 @@ "title": "Slotted error text in a form item", "description": "Use the error slot in a form item to display formatted error messages with custom styling like bold or italic text.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", "tags": [ "form", "form-item", @@ -2561,8 +2126,7 @@ "form-item", "input" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "slotted-error-text-in-a-form-item" }, { @@ -2571,9 +2135,7 @@ "title": "Slotted helper text in a form item", "description": "Use the helpText slot in a form item to display formatted helper text with custom styling like bold, italic, or links.", "status": "published", - "categories": [ - "forms" - ], + "size": "interaction", "tags": [ "form", "form-item", @@ -2584,8 +2146,7 @@ "form-item", "input" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "slotted-helper-text-in-a-form-item" }, { @@ -2594,9 +2155,8 @@ "title": "Sort data in a table", "description": "Enable column sorting in tables using sort headers, allowing workers to organize data by clicking column headers to toggle ascending/descending order.", "status": "published", - "categories": [ - "content-layout" - ], + "size": "section", + "productType": "workspace", "tags": [ "table", "sorting", @@ -2606,19 +2166,17 @@ "table", "table-sort-header" ], - "scale": "task", - "userType": "worker", + "aliases": [], "slug": "sort-data-in-a-table" }, { "type": "example", "id": "start-page", "title": "Start page", - "description": "A start page is the front door to a government service for citizens. It provides essential information about the service and a clear call to action to begin.", + "description": "The front door to a government service for a citizen. It is the way into the service and how citizens access it. Each government service has a start page on Alberta.ca.", "status": "published", - "categories": [ - "forms" - ], + "size": "page", + "productType": "public-form", "tags": [ "page", "service", @@ -2628,19 +2186,17 @@ "components": [ "button" ], - "scale": "page", - "userType": "citizen", + "aliases": [], "slug": "start-page" }, { "type": "example", "id": "task-list-page", "title": "Task list page", - "description": "A task list page provides a structure for multi-step services, showing users their progress through a series of tasks with clear status indicators.", + "description": "A page that provides structure for multiple steps in a service. Use a task list to outline the entire process and show the status of each task as users move through it.", "status": "published", - "categories": [ - "forms" - ], + "size": "page", + "productType": "public-form", "tags": [ "page", "task-list", @@ -2652,8 +2208,7 @@ "badge", "callout" ], - "scale": "page", - "userType": "both", + "aliases": [], "slug": "task-list-page" }, { @@ -2662,9 +2217,7 @@ "title": "Type to create a new filter", "description": "Allow users to type custom filter values and create filter chips by pressing Enter, with the ability to remove chips using Backspace or by clicking them.", "status": "published", - "categories": [ - "inputs-and-actions" - ], + "size": "interaction", "tags": [ "filter-chip", "input", @@ -2677,8 +2230,7 @@ "form-item", "container" ], - "scale": "interaction", - "userType": "both", + "aliases": [], "slug": "type-to-create-a-new-filter" }, { @@ -2687,9 +2239,7 @@ "title": "Warn a user of a deadline", "description": "Use a modal with important callout styling to warn users about time-sensitive deadlines that could affect their submission or action.", "status": "published", - "categories": [ - "feedback-and-alerts" - ], + "size": "section", "tags": [ "modal", "warning", @@ -2701,8 +2251,358 @@ "button", "button-group" ], - "scale": "task", - "userType": "both", + "aliases": [], "slug": "warn-a-user-of-a-deadline" + }, + { + "type": "example", + "id": "workspace-case-detail", + "title": "Case detail", + "description": "A single-record view for reviewing and acting on one case. Uses accordion sections, a table-of-contents sidebar, badges for status, and header actions for quick operations.", + "status": "published", + "size": "page", + "productType": "workspace", + "tags": [ + "workspace", + "case-detail", + "worker" + ], + "components": [ + "accordion", + "badge", + "button", + "drawer" + ], + "aliases": [], + "slug": "workspace/case-detail" + }, + { + "type": "example", + "id": "workspace-dashboard", + "title": "Dashboard", + "description": "Gives staff an overview of their work with counts, trends, and assigned items.", + "status": "published", + "size": "page", + "productType": "workspace", + "tags": [ + "workspace", + "dashboard", + "worker" + ], + "components": [ + "container", + "block", + "badge" + ], + "aliases": [], + "slug": "workspace/dashboard" + }, + { + "type": "example", + "id": "workspace-index-page", + "title": "Index page", + "description": "The page staff land on to scan, filter, sort, and pick records to work on. The home of the workspace's daily queue.", + "status": "published", + "size": "page", + "productType": "workspace", + "tags": [ + "workspace", + "index", + "worker" + ], + "components": [ + "work-side-menu", + "data-grid", + "tabs", + "filter-chip", + "badge" + ], + "aliases": [], + "slug": "workspace/index-page" + }, + { + "type": "page", + "id": "automated-accessibility", + "title": "Automated accessibility", + "description": "Guidance on using automated accessibility testing tools effectively", + "status": "published", + "category": "get started", + "tags": [ + "intro" + ], + "slug": "get-started/automated-accessibility" + }, + { + "type": "page", + "id": "component-lifecycle", + "title": "Component lifecycle", + "description": "The stages each Design System component moves through", + "status": "published", + "category": "get started", + "tags": [ + "intro" + ], + "slug": "get-started/component-lifecycle" + }, + { + "type": "page", + "id": "contribute", + "title": "Contribute", + "description": "How to contribute to the GoA Design System", + "status": "published", + "category": "get started", + "tags": [ + "appendix" + ], + "slug": "get-started/contribute" + }, + { + "type": "page", + "id": "designers/designing-for-dark-mode", + "title": "Designing for dark mode", + "description": "How dark mode works for designers", + "status": "published", + "category": "get started", + "tags": [ + "designers", + "designer" + ], + "slug": "get-started/designers/designing-for-dark-mode" + }, + { + "type": "page", + "id": "designers/designing-with-ds", + "title": "Designing with Design System 2.0", + "description": "How to start new designs and update existing projects to Design System 2.0", + "status": "published", + "category": "get started", + "tags": [ + "designers", + "designer" + ], + "slug": "get-started/designers/designing-with-ds" + }, + { + "type": "page", + "id": "designers/ux-guidelines", + "title": "User experience guidelines", + "description": "User experience guidelines for Government of Alberta digital products", + "status": "published", + "category": "get started", + "tags": [ + "designers", + "designer" + ], + "slug": "get-started/designers/ux-guidelines" + }, + { + "type": "page", + "id": "designers", + "title": "Designers overview", + "description": "How designers use the design system through Figma", + "status": "published", + "category": "get started", + "tags": [ + "designers", + "designer" + ], + "slug": "get-started/designers" + }, + { + "type": "page", + "id": "developers/browsers", + "title": "Supported browsers", + "description": "Browser and operating system support for Design System components", + "status": "published", + "category": "get started", + "tags": [ + "developers", + "developer" + ], + "slug": "get-started/developers/browsers" + }, + { + "type": "page", + "id": "developers/bug", + "title": "Verify a bug", + "description": "How to verify and report a bug in a Design System component", + "status": "published", + "category": "get started", + "tags": [ + "developers", + "developer" + ], + "slug": "get-started/developers/bug" + }, + { + "type": "page", + "id": "developers/dark-mode-theme", + "title": "Dark mode theme", + "description": "Switch between light and dark mode using the React useTheme hook or Angular GoabThemeService", + "status": "published", + "category": "get started", + "tags": [ + "developers", + "developer" + ], + "slug": "get-started/developers/dark-mode-theme" + }, + { + "type": "page", + "id": "developers/setup", + "title": "Developer setup", + "description": "Set up Angular, React, or Web Components to use the GoA Design System", + "status": "published", + "category": "get started", + "tags": [ + "developers", + "developer" + ], + "slug": "get-started/developers/setup" + }, + { + "type": "page", + "id": "developers/technologies", + "title": "Technologies", + "description": "An overview of the technologies used in the Design System", + "status": "published", + "category": "get started", + "tags": [ + "developers", + "developer" + ], + "slug": "get-started/developers/technologies" + }, + { + "type": "page", + "id": "developers/updating-your-product", + "title": "Updating your product", + "description": "The rationale and practical steps for updating your GoA product to Design System 2.0 using the developer-first approach.", + "status": "published", + "category": "get started", + "tags": [ + "developers", + "developer" + ], + "slug": "get-started/developers/updating-your-product" + }, + { + "type": "page", + "id": "developers", + "title": "Developers overview", + "description": "How developers use the design system through tokens, components, examples, and templates", + "status": "published", + "category": "get started", + "tags": [ + "developers", + "developer" + ], + "slug": "get-started/developers" + }, + { + "type": "page", + "id": "index", + "title": "Start with the design system", + "description": "Start with the design system to build on the research and experience of other service teams", + "status": "published", + "category": "get started", + "tags": [ + "intro" + ], + "slug": "get-started" + }, + { + "type": "page", + "id": "migration-guide", + "title": "Migration guide", + "description": "Choose the right Design System 2.0 migration pathway for your product", + "status": "published", + "category": "get started", + "tags": [ + "intro" + ], + "slug": "get-started/migration-guide" + }, + { + "type": "page", + "id": "out-of-support", + "title": "Out of support versions", + "description": "Design System versions that are no longer supported", + "status": "published", + "category": "get started", + "tags": [ + "appendix" + ], + "slug": "get-started/out-of-support" + }, + { + "type": "page", + "id": "qa-testing", + "title": "QA testing", + "description": "Testing process for Design System components", + "status": "published", + "category": "get started", + "tags": [ + "appendix" + ], + "slug": "get-started/qa-testing" + }, + { + "type": "page", + "id": "roadmap", + "title": "Roadmap", + "description": "High-level roadmap for the design system team's 2026-27 fiscal year", + "status": "published", + "category": "get started", + "tags": [ + "intro" + ], + "slug": "get-started/roadmap" + }, + { + "type": "example", + "id": "public-form", + "title": "Public form", + "description": "For citizen-facing services where users apply for a benefit, request a service, or submit information. Designed around simplicity and low cognitive load, with plain-language questions, focused pages that ask one thing at a time, save-and-resume, and a clear confirmation of what happens next.", + "status": "published", + "size": "product", + "tags": [ + "form", + "public", + "citizen", + "pattern" + ], + "components": [], + "aliases": [], + "slug": "public-form" + }, + { + "type": "example", + "id": "workspace", + "title": "Workspace", + "description": "The workspace is for productivity-focused services used by service delivery staff as a daily tool to review information, manage records, and complete tasks. The design prioritizes productivity, efficiency, and accuracy so staff can move through their work quickly while ensuring the best outcome for citizens and government.", + "status": "published", + "size": "product", + "tags": [ + "workspace", + "worker", + "service", + "case-management", + "dashboard", + "pattern" + ], + "components": [ + "work-side-menu", + "table", + "badge", + "tabs", + "container", + "accordion", + "drawer", + "button", + "block" + ], + "aliases": [], + "slug": "workspace" } ] \ No newline at end of file diff --git a/docs/public/thumbnails/error-pages-401.png b/docs/public/thumbnails/error-pages-401.png new file mode 100644 index 0000000000..440acb7512 Binary files /dev/null and b/docs/public/thumbnails/error-pages-401.png differ diff --git a/docs/public/thumbnails/error-pages-404.png b/docs/public/thumbnails/error-pages-404.png new file mode 100644 index 0000000000..d380995b1a Binary files /dev/null and b/docs/public/thumbnails/error-pages-404.png differ diff --git a/docs/public/thumbnails/error-pages-500.png b/docs/public/thumbnails/error-pages-500.png new file mode 100644 index 0000000000..1291a72b14 Binary files /dev/null and b/docs/public/thumbnails/error-pages-500.png differ diff --git a/docs/public/thumbnails/workspace-notification-panel.png b/docs/public/thumbnails/workspace-notification-panel.png new file mode 100644 index 0000000000..b0bb9762d4 Binary files /dev/null and b/docs/public/thumbnails/workspace-notification-panel.png differ diff --git a/docs/public/thumbnails/workspace-sticky-action-bar.png b/docs/public/thumbnails/workspace-sticky-action-bar.png index 6e9e528067..3b1879875c 100644 Binary files a/docs/public/thumbnails/workspace-sticky-action-bar.png and b/docs/public/thumbnails/workspace-sticky-action-bar.png differ diff --git a/docs/src/components/Breadcrumbs.astro b/docs/src/components/Breadcrumbs.astro index ef9fda790c..0d668720f9 100644 --- a/docs/src/components/Breadcrumbs.astro +++ b/docs/src/components/Breadcrumbs.astro @@ -22,7 +22,9 @@ const segments = pathname.split('/').filter(Boolean); // Show on any page within a section const showBreadcrumbs = segments.length >= 1; -// Build set of valid page routes from the pages directory +// Build set of valid page routes from the pages directory. Dynamic segments +// like `[family]` are kept as `*` so we can later test crumb paths against +// them as patterns (e.g. `/examples/workspace` matches `/examples/*`). const pageFiles = import.meta.glob('/src/pages/**/*.{astro,md,mdx}', { eager: false }); const validPaths = new Set( Object.keys(pageFiles).map(file => @@ -30,10 +32,20 @@ const validPaths = new Set( .replace('/src/pages', '') .replace(/\/index\.(astro|md|mdx)$/, '') .replace(/\.(astro|md|mdx)$/, '') - .replace(/\[.*?\]/g, '*') // dynamic routes aren't valid intermediate targets + .replace(/\[.*?\]/g, '*') ) ); +function isValidPath(path: string): boolean { + if (validPaths.has(path)) return true; + for (const vp of validPaths) { + if (!vp.includes('*')) continue; + const pattern = '^' + vp.replace(/\*/g, '[^/]+') + '$'; + if (new RegExp(pattern).test(path)) return true; + } + return false; +} + // Known labels for path segments const SEGMENT_LABELS: Record = { "get-started": "Get Started", @@ -59,7 +71,7 @@ let path = ''; const crumbCount = Math.max(1, segments.length - 1); for (let i = 0; i < crumbCount; i++) { path += '/' + segments[i]; - crumbs.push({ label: segmentToLabel(segments[i]), url: path, hasPage: validPaths.has(path) }); + crumbs.push({ label: segmentToLabel(segments[i]), url: path, hasPage: isValidPath(path) }); } --- diff --git a/docs/src/components/CardLite.astro b/docs/src/components/CardLite.astro index 7f9f718854..59bb46a21e 100644 --- a/docs/src/components/CardLite.astro +++ b/docs/src/components/CardLite.astro @@ -5,6 +5,8 @@ * A lightweight card component for homepage grids. * Displays an image, title, and description with a link. */ +import { withBase } from '@/lib/base-url'; + interface Props { title: string; description: string; @@ -19,7 +21,7 @@ const isDisabled = !linkTo; {isDisabled ? (
- {imageUrl &&
} + {imageUrl &&
} {title} @@ -30,7 +32,7 @@ const isDisabled = !linkTo;
) : ( - {imageUrl &&
} + {imageUrl &&
} {title} diff --git a/docs/src/components/CodeCopy.tsx b/docs/src/components/CodeCopy.tsx index 0993e9ca56..2783c9c0ce 100644 --- a/docs/src/components/CodeCopy.tsx +++ b/docs/src/components/CodeCopy.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; -import { GoabIconButton } from "@abgov/react-components"; +import { GoabIconButton, GoabTooltip } from "@abgov/react-components"; interface Props { code: string; @@ -21,7 +21,9 @@ export const CodeCopy: React.FC = ({ code, className }) => { return ( <>
- + + +
); diff --git a/docs/src/components/CodeSnippet.css b/docs/src/components/CodeSnippet.css index d24afe3361..d8916fd894 100644 --- a/docs/src/components/CodeSnippet.css +++ b/docs/src/components/CodeSnippet.css @@ -170,3 +170,15 @@ code { .hljs-built_in { color: #6639ba; } .hljs-title { color: #6639ba; } .hljs-params { color: #953800; } + +/* Dark mode: lighter hue-preserved variants for readability on dark code bg */ +:root[data-theme="dark"] .hljs-keyword { color: #79c0ff; } +:root[data-theme="dark"] .hljs-string { color: #7ee787; } +:root[data-theme="dark"] .hljs-number { color: #79c0ff; } +:root[data-theme="dark"] .hljs-comment { color: #8b949e; } +:root[data-theme="dark"] .hljs-tag { color: #79c0ff; } +:root[data-theme="dark"] .hljs-attr { color: #79c0ff; } +:root[data-theme="dark"] .hljs-name { color: #7ce38b; } +:root[data-theme="dark"] .hljs-built_in { color: #d2a8ff; } +:root[data-theme="dark"] .hljs-title { color: #d2a8ff; } +:root[data-theme="dark"] .hljs-params { color: #ffa657; } diff --git a/docs/src/components/CodeSnippet.tsx b/docs/src/components/CodeSnippet.tsx index 376c95bfc4..daef55060b 100644 --- a/docs/src/components/CodeSnippet.tsx +++ b/docs/src/components/CodeSnippet.tsx @@ -219,44 +219,50 @@ export function CodeSnippet({ ? VALID_FRAMEWORKS.filter((k) => Boolean(frameworkCode[k])) : []; + const syncGoaTabsSelection = (framework: Framework) => { + if (!tabsRef.current || availableFrameworks.length === 0 || !availableFrameworks.includes(framework)) { + return; + } + + const goaTabs = tabsRef.current.querySelector("goa-tabs"); + if (!goaTabs) return; + + const targetIndex = availableFrameworks.indexOf(framework); + const tabs = goaTabs.querySelectorAll('[role="tab"]'); + const targetTab = tabs[targetIndex] as HTMLElement | undefined; + if (!targetTab) return; + + tabs.forEach((tab, i) => { + tab.setAttribute("aria-selected", i === targetIndex ? "true" : "false"); + tab.setAttribute("tabindex", i === targetIndex ? "0" : "-1"); + }); + + const tabContents = goaTabs.querySelectorAll("goa-tab"); + tabContents.forEach((content, i) => { + content.dispatchEvent( + new CustomEvent("tabs:set-open", { + composed: true, + detail: { open: i === targetIndex }, + }), + ); + }); + }; + + useEffect(() => { + const stored = getFrameworkPreference(); + if (availableFrameworks.length > 0 && availableFrameworks.includes(stored)) { + setSelectedFramework(stored); + syncGoaTabsSelection(stored); + } + }, [availableFrameworks]); + // Subscribe to global framework preference changes from other components. // Directly manipulate the tab DOM state without triggering focus or hash changes. useEffect(() => { return subscribeToFrameworkPreference((framework) => { if (availableFrameworks.length === 0 || availableFrameworks.includes(framework)) { setSelectedFramework(framework); - - // Directly switch goa-tabs without triggering focus - if (tabsRef.current) { - const goaTabs = tabsRef.current.querySelector("goa-tabs"); - if (goaTabs) { - const targetIndex = availableFrameworks.indexOf(framework); - const tabs = goaTabs.querySelectorAll('[role="tab"]'); - - // Check if already on the correct tab - const targetTab = tabs[targetIndex] as HTMLElement; - if (targetTab && targetTab.getAttribute("aria-selected") === "true") { - return; // Already selected, nothing to do - } - - // Update tab button states (aria-selected, tabindex) - tabs.forEach((tab, i) => { - tab.setAttribute("aria-selected", i === targetIndex ? "true" : "false"); - tab.setAttribute("tabindex", i === targetIndex ? "0" : "-1"); - }); - - // Tell each goa-tab content whether it should be open - const tabContents = goaTabs.querySelectorAll("goa-tab"); - tabContents.forEach((content, i) => { - content.dispatchEvent( - new CustomEvent("tabs:set-open", { - composed: true, - detail: { open: i === targetIndex }, - }), - ); - }); - } - } + syncGoaTabsSelection(framework); } }); }, [availableFrameworks]); diff --git a/docs/src/components/ComponentSandbox.tsx b/docs/src/components/ComponentSandbox.tsx index 8cd0b38c95..32a5849472 100644 --- a/docs/src/components/ComponentSandbox.tsx +++ b/docs/src/components/ComponentSandbox.tsx @@ -51,6 +51,11 @@ export function ComponentSandbox({ return stored === 'angular' ? 'angular' : 'react'; }); + useEffect(() => { + const stored = getFrameworkPreference(); + setActiveTab(stored === 'angular' ? 'angular' : 'react'); + }, []); + // Subscribe to global framework preference changes useEffect(() => { return subscribeToFrameworkPreference((framework) => { diff --git a/docs/src/components/ComponentsGrid.tsx b/docs/src/components/ComponentsGrid.tsx index cdf07f2a7b..fba586356a 100644 --- a/docs/src/components/ComponentsGrid.tsx +++ b/docs/src/components/ComponentsGrid.tsx @@ -49,9 +49,6 @@ export interface Component { | "utilities"; tags?: string[]; relatedComponents?: string[]; - webComponentTag?: string; - reactClassName?: string; - angularSelector?: string; }; } diff --git a/docs/src/components/ConfigurationPreview.tsx b/docs/src/components/ConfigurationPreview.tsx index 612ba5e6be..71b4303f86 100644 --- a/docs/src/components/ConfigurationPreview.tsx +++ b/docs/src/components/ConfigurationPreview.tsx @@ -10,11 +10,12 @@ * Code snippet changes based on selected framework preference. */ -import { useState, useEffect, useRef, useCallback } from "react"; +import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"; // Note: Using web component directly for v2 styling (React wrapper doesn't pass version prop) +import { GoabTooltip } from "@abgov/react-components"; import { CodeSnippet } from "./CodeSnippet"; import { useGitHubIssueCount } from "../hooks/useGitHubIssueCount"; -import type { ComponentConfigurations } from "../data/configurations/types"; +import type { ComponentConfigurations } from "@/data/configurations"; import DOMPurify from "dompurify"; // Allow GoA web component custom elements through DOMPurify. @@ -65,21 +66,23 @@ export function ConfigurationPreview({ webComponentCode.js ? `` : "", ].join(""); + const previewHtml = configurations.previewWrapper + ? configurations.previewWrapper.replace("{{slot}}", rawCode) + : rawCode; + // Extract script content before sanitization - const scriptMatch = rawCode.match(/ diff --git a/docs/src/components/SiteNav.tsx b/docs/src/components/SiteNav.tsx index ab38664798..cd89579beb 100644 --- a/docs/src/components/SiteNav.tsx +++ b/docs/src/components/SiteNav.tsx @@ -21,6 +21,7 @@ import { FoundationsSubMenu, type MenuSection, type NavCategory, + type GetStartedNav, } from "./nav"; interface SiteNavProps { @@ -32,6 +33,8 @@ interface SiteNavProps { initialSection?: MenuSection; /** Component nav categories (from content collection, passed by Astro layout) */ categories?: NavCategory[]; + /** Get Started submenu structure (from content collection, passed by Astro layout) */ + getStartedNav?: GetStartedNav; } // Sections that have submenus (show submenu when navigated to) @@ -90,11 +93,18 @@ function getInitialMenuState(): boolean { return true; } +const EMPTY_GET_STARTED_NAV: GetStartedNav = { + topPages: [], + groups: [], + bottomPages: [], +}; + export function SiteNav({ currentSlug, currentCategory, initialSection, categories = [], + getStartedNav = EMPTY_GET_STARTED_NAV, }: SiteNavProps) { // Menu state - persisted on desktop, always closed on mobile const [isOpen, setIsOpen] = useState(getInitialMenuState); @@ -216,6 +226,7 @@ export function SiteNav({ onBack={handleBack} onExpandMenu={handleExpandMenu} currentUrl={currentUrl} + items={getStartedNav} /> ); diff --git a/docs/src/components/TokensGrid.tsx b/docs/src/components/TokensGrid.tsx index d7ea0b00af..7bd2c59108 100644 --- a/docs/src/components/TokensGrid.tsx +++ b/docs/src/components/TokensGrid.tsx @@ -30,6 +30,7 @@ import { import { useTwoLevelSort } from "../hooks/useTwoLevelSort"; import { useContainerNarrow } from "../hooks/useContainerWidth"; +import { useIsDarkMode } from "../hooks/useIsDarkMode"; import type { FlatToken } from "../lib/tokens"; import { InlineSearch, type SlashCommand } from "./search/InlineSearch"; @@ -100,7 +101,22 @@ function toScssSyntax(cssName: string): string { return cssName.replace(/^--/, "$"); } +/** + * Pick the active-theme variant of a token's display values. Returns light values + * when not in dark mode, or when the token has no dark variant. + */ +function activeOf(token: FlatToken, isDark: boolean): { value: string; resolvedValue: string } { + if (isDark && token.darkValue) { + return { + value: token.darkValue, + resolvedValue: token.darkResolvedValue ?? token.resolvedValue, + }; + } + return { value: token.value, resolvedValue: token.resolvedValue }; +} + export function TokensGrid({ tokens, filterGroups }: TokensGridProps) { + const isDark = useIsDarkMode(); // State const [filterDrawerOpen, setFilterDrawerOpen] = useState(false); const [isSticky, setIsSticky] = useState(false); @@ -343,7 +359,8 @@ export function TokensGrid({ tokens, filterGroups }: TokensGridProps) { // Render token preview (color, opacity, etc.) const renderPreview = (token: FlatToken) => { - const value = token.resolvedValue || token.value; + const active = activeOf(token, isDark); + const value = active.resolvedValue || active.value; if (token.isColor) { return (
); } @@ -578,18 +595,16 @@ export function TokensGrid({ tokens, filterGroups }: TokensGridProps) { display: "flex", alignItems: "center", justifyContent: "center", - backgroundColor: "white", - borderRadius: 4, }} - title={token.value} + title={active.value} >
@@ -731,7 +746,7 @@ export function TokensGrid({ tokens, filterGroups }: TokensGridProps) { {renderPreview(token)}
{getFormattedTokenName(token.name)} - {token.value} + {activeOf(token, isDark).value}
), - [copiedToken, copyToClipboard, getFormattedTokenName], + [copiedToken, copyToClipboard, getFormattedTokenName, isDark], ); // Render table row (list view) @@ -764,7 +779,7 @@ export function TokensGrid({ tokens, filterGroups }: TokensGridProps) { {getFormattedTokenName(token.name)} - {token.value} + {activeOf(token, isDark).value} ), - [copiedToken, copyToClipboard, getFormattedTokenName], + [copiedToken, copyToClipboard, getFormattedTokenName, isDark], ); const hasActiveFilters = appliedFilters.length > 0 || sortConfig.primary; diff --git a/docs/src/components/nav/GetStartedSubMenu.tsx b/docs/src/components/nav/GetStartedSubMenu.tsx index abd94eccd2..1ae70ad26d 100644 --- a/docs/src/components/nav/GetStartedSubMenu.tsx +++ b/docs/src/components/nav/GetStartedSubMenu.tsx @@ -3,6 +3,9 @@ * * Sub-menu for Get Started section showing grouped pages. * Uses GoabWorkSideMenuGroup for expandable Designers/Developers sections. + * + * Nav structure is sourced from the get-started content collection via + * `getGetStartedNav()` in lib/get-started-nav.ts. */ import { type MouseEvent } from "react"; @@ -13,59 +16,7 @@ import { } from "@abgov/react-components"; import { MenuSecondaryContent } from "./MenuSecondaryContent"; import { withBase } from "@/lib/base-url"; - -// Top-level pages (not in a group) -const TOP_PAGES = [ - { label: "Starting with the design system", url: "/get-started" }, - { label: "Automated accessibility", url: "/get-started/automated-accessibility" }, - { label: "Component lifecycle", url: "/get-started/component-lifecycle" }, - { label: "Roadmap", url: "/get-started/roadmap" }, - { label: "Migration guide", url: "/get-started/migration-guide" }, -]; - -// Grouped sections with sub-pages -const PAGE_GROUPS = [ - { - name: "Designers", - slug: "designers", - pages: [ - { label: "Overview", url: "/get-started/designers" }, - { - label: "Designing with Design System 2.0", - url: "/get-started/designers/designing-with-ds", - }, - { - label: "User Experience Guidelines", - url: "/get-started/designers/ux-guidelines", - }, - ], - }, - { - name: "Developers", - slug: "developers", - pages: [ - { label: "Overview", url: "/get-started/developers" }, - { label: "Setup", url: "/get-started/developers/setup" }, - { label: "Verify a bug", url: "/get-started/developers/bug" }, - { label: "Technologies", url: "/get-started/developers/technologies" }, - { label: "Supported browsers", url: "/get-started/developers/browsers" }, - ], - }, -]; - -// Bottom pages (after groups) -const BOTTOM_PAGES = [ - { label: "QA testing", url: "/get-started/qa-testing" }, - { label: "Contribute", url: "/get-started/contribute" }, - { label: "Out of support versions", url: "/get-started/out-of-support" }, -]; - -// All URLs for matching current page -const ALL_URLS = [ - ...TOP_PAGES.map((p) => p.url), - ...PAGE_GROUPS.flatMap((g) => g.pages.map((p) => p.url)), - ...BOTTOM_PAGES.map((p) => p.url), -]; +import type { GetStartedNav } from "@/lib/get-started-nav"; interface GetStartedSubMenuProps { isOpen: boolean; @@ -73,6 +24,7 @@ interface GetStartedSubMenuProps { onBack: () => void; onExpandMenu?: () => void; currentUrl?: string; + items: GetStartedNav; } export function GetStartedSubMenu({ @@ -81,6 +33,7 @@ export function GetStartedSubMenu({ onBack, onExpandMenu, currentUrl, + items, }: GetStartedSubMenuProps) { const handleBackClick = (e: MouseEvent) => { e.preventDefault(); @@ -96,13 +49,17 @@ export function GetStartedSubMenu({
{/* Top-level pages */} - {TOP_PAGES.map((page) => ( - + {items.topPages.map((page) => ( + ))} {/* Grouped sections */}
- {PAGE_GROUPS.map((group) => { + {items.groups.map((group) => { const containsCurrentPage = group.pages.some((p) => p.url === currentUrl); const handleGroupClickCapture = () => { @@ -128,8 +85,12 @@ export function GetStartedSubMenu({
{/* Bottom pages */} - {BOTTOM_PAGES.map((page) => ( - + {items.bottomPages.map((page) => ( + ))} ); diff --git a/docs/src/components/nav/MenuSecondaryContent.tsx b/docs/src/components/nav/MenuSecondaryContent.tsx index 51dd0b9808..f91b27719e 100644 --- a/docs/src/components/nav/MenuSecondaryContent.tsx +++ b/docs/src/components/nav/MenuSecondaryContent.tsx @@ -8,11 +8,19 @@ */ import { useCallback, useState, useEffect } from "react"; -import { GoabIcon, GoabSpacer, GoabWorkSideMenuItem } from "@abgov/react-components"; +import { GoabBadge, GoabIcon, GoabSpacer, GoabWorkSideMenuItem } from "@abgov/react-components"; import { withBase } from "@/lib/base-url"; import "./menu-secondary.css"; +const THEME_STORAGE_KEY = "goab-theme"; + +function readInitialTheme(): "light" | "dark" { + if (typeof document === "undefined") return "light"; + const attr = document.documentElement.getAttribute("data-theme"); + return attr === "dark" ? "dark" : "light"; +} + interface MenuSecondaryContentProps { /** Whether the side menu is expanded (controls label/badge visibility) */ isOpen: boolean; @@ -26,6 +34,23 @@ export function MenuSecondaryContent({ isOpen }: MenuSecondaryContentProps) { setShortcutKey(isMac ? "⌘K" : "Ctrl K"); }, []); + // Theme state — synced with attribute set by pre-paint script + const [themeMode, setThemeMode] = useState<"light" | "dark">(readInitialTheme); + const isDark = themeMode === "dark"; + + const toggleTheme = useCallback(() => { + setThemeMode((prev) => { + const next = prev === "light" ? "dark" : "light"; + document.documentElement.setAttribute("data-theme", next); + try { + localStorage.setItem(THEME_STORAGE_KEY, next); + } catch { + // localStorage blocked: fail silently + } + return next; + }); + }, []); + // Open search modal (workaround until #3340 adds onClick to WorkSideMenuItem) const openSearch = useCallback(() => { window.dispatchEvent(new CustomEvent("goa-search-open")); @@ -83,12 +108,23 @@ export function MenuSecondaryContent({ isOpen }: MenuSecondaryContentProps) { )} + - ); diff --git a/docs/src/components/nav/index.ts b/docs/src/components/nav/index.ts index fc8ccd08c8..ee574f8b25 100644 --- a/docs/src/components/nav/index.ts +++ b/docs/src/components/nav/index.ts @@ -12,5 +12,6 @@ export { ParentMenu, type MenuSection } from "./ParentMenu"; export { ComponentsSubMenu } from "./ComponentsSubMenu"; export { GetStartedSubMenu } from "./GetStartedSubMenu"; +export type { GetStartedNav } from "../../lib/get-started-nav"; export { FoundationsSubMenu } from "./FoundationsSubMenu"; export type { NavCategory } from "../../lib/nav-categories"; diff --git a/docs/src/components/search/SearchResultItem.tsx b/docs/src/components/search/SearchResultItem.tsx index 6d0147753c..eec94245c8 100644 --- a/docs/src/components/search/SearchResultItem.tsx +++ b/docs/src/components/search/SearchResultItem.tsx @@ -91,8 +91,10 @@ function getBreadcrumb(result: SearchResult): string { return "Design Tokens"; } const example = result as ExampleEntry; - const category = example.categories?.[0] || "General"; - return `Examples > ${formatCategory(category)}`; + if (example.productType) { + return `Examples > ${formatCategory(example.productType)}`; + } + return `Examples > ${formatCategory(example.size)}`; } /** diff --git a/docs/src/components/search/quick-links.ts b/docs/src/components/search/quick-links.ts index 5c318f8bd3..930be504f6 100644 --- a/docs/src/components/search/quick-links.ts +++ b/docs/src/components/search/quick-links.ts @@ -21,6 +21,8 @@ export const quickLinks: QuickLink[] = [ { label: "Examples", href: "/examples", icon: "browsers" }, { label: "Components", href: "/components", icon: "shapes" }, { label: "Design tokens", href: "/tokens", icon: "code-slash" }, + { label: "Get support", href: "/support", icon: "help-circle" }, + { label: "Release notes", href: "https://github.com/GovAlta/ui-components/releases", icon: "open" }, ]; /** diff --git a/docs/src/components/search/search.css b/docs/src/components/search/search.css index 8953fd2991..81fdb5cca2 100644 --- a/docs/src/components/search/search.css +++ b/docs/src/components/search/search.css @@ -764,6 +764,7 @@ /* Give the input a full border and compact padding when used inline */ .inline-search .search-input-container { + background: var(--goa-input-color-background-default); border: 1px solid var(--goa-color-greyscale-300, #ccc); border-radius: var(--goa-border-radius-m); border-bottom: 1px solid var(--goa-color-greyscale-300, #ccc); @@ -795,7 +796,7 @@ left: 0; right: 0; z-index: 100; - background: white; + background: var(--goa-color-greyscale-white); border: 1px solid var(--goa-color-greyscale-200, #e0e0e0); border-radius: var(--goa-border-radius-m); box-shadow: diff --git a/docs/src/components/search/useSearch.ts b/docs/src/components/search/useSearch.ts index 48ddf29e3b..1894ee96e8 100644 --- a/docs/src/components/search/useSearch.ts +++ b/docs/src/components/search/useSearch.ts @@ -34,11 +34,17 @@ export interface ExampleEntry { title: string; description?: string; status: string; - categories: string[]; + size: "interaction" | "section" | "page" | "task" | "product"; + productType?: "workspace" | "public-form"; tags: string[]; components: string[]; - scale: string; - userType: string; + /** + * Alternate slugs for this entry. Each alias becomes a separate search + * result that points at this entry's canonical slug, and a build-time + * `/examples/[alias]` -> canonical redirect via + * `src/scripts/aliases-to-redirects.mjs`. + */ + aliases: string[]; slug: string; } @@ -185,8 +191,19 @@ function createSearchIndex() { resolution: 4, }, { - field: "categories", + field: "size", + tokenize: "strict", + resolution: 4, + }, + { + field: "productType", tokenize: "strict", + resolution: 4, + }, + { + field: "aliases", + tokenize: "forward", + resolution: 9, }, // Content field - includes token names for token entries { @@ -205,11 +222,11 @@ function createSearchIndex() { "description", "status", "category", - "categories", + "size", + "productType", "tags", "components", - "scale", - "userType", + "aliases", "slug", ], }, @@ -288,8 +305,11 @@ async function loadSearchIndex(): Promise { : entry.type === "page" ? (entry as PageEntry).title : "", - categories: entry.type === "example" ? (entry as ExampleEntry).categories : [], + size: entry.type === "example" ? (entry as ExampleEntry).size : "", + productType: + entry.type === "example" ? (entry as ExampleEntry).productType ?? "" : "", components: entry.type === "example" ? (entry as ExampleEntry).components : [], + aliases: entry.type === "example" ? (entry as ExampleEntry).aliases : [], // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any); } diff --git a/docs/src/content/components/accordion.mdx b/docs/src/content/components/accordion.mdx index 0351f61b3d..b3304de052 100644 --- a/docs/src/content/components/accordion.mdx +++ b/docs/src/content/components/accordion.mdx @@ -12,8 +12,4 @@ tags: relatedComponents: - details figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=15932-570754 -githubUrl: https://github.com/GovAlta/ui-components/issues?q=is%3Aopen%20label%3AAccordion -webComponentTag: goa-accordion -reactClassName: GoabAccordion -angularSelector: goab-accordion --- diff --git a/docs/src/content/components/app-header-menu.mdx b/docs/src/content/components/app-header-menu.mdx index abec9f7d42..98bd94b8b0 100644 --- a/docs/src/content/components/app-header-menu.mdx +++ b/docs/src/content/components/app-header-menu.mdx @@ -7,7 +7,4 @@ hidden: true subcomponent: true relatedComponents: - app-header -webComponentTag: goa-app-header-menu -reactClassName: GoabAppHeaderMenu -angularSelector: goab-app-header-menu --- diff --git a/docs/src/content/components/app-header.mdx b/docs/src/content/components/app-header.mdx index 0109bf8dee..b0ebd10e03 100644 --- a/docs/src/content/components/app-header.mdx +++ b/docs/src/content/components/app-header.mdx @@ -19,8 +19,4 @@ relatedComponents: - app-header-menu - microsite-header figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=58757-186832 -githubUrl: https://github.com/GovAlta/ui-components/labels/Header -webComponentTag: goa-app-header -reactClassName: GoabAppHeader -angularSelector: goab-app-header --- diff --git a/docs/src/content/components/badge.mdx b/docs/src/content/components/badge.mdx index 2e619e2a00..4630cbff6f 100644 --- a/docs/src/content/components/badge.mdx +++ b/docs/src/content/components/badge.mdx @@ -14,8 +14,4 @@ relatedComponents: - chip - callout figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56969-153280 -githubUrl: https://github.com/GovAlta/ui-components/issues?q=is%3Aissue+is%3Aopen+label%3A%22Badge%22 -webComponentTag: goa-badge -reactClassName: GoabBadge -angularSelector: goab-badge --- diff --git a/docs/src/content/components/block.mdx b/docs/src/content/components/block.mdx index 1a635da418..b9ab0037ca 100644 --- a/docs/src/content/components/block.mdx +++ b/docs/src/content/components/block.mdx @@ -8,8 +8,4 @@ tags: relatedComponents: - container - page-block -githubUrl: https://github.com/GovAlta/ui-components/labels/Block -webComponentTag: goa-block -reactClassName: GoabBlock -angularSelector: goab-block --- diff --git a/docs/src/content/components/button-group.mdx b/docs/src/content/components/button-group.mdx index cb45649e6d..07286f64cb 100644 --- a/docs/src/content/components/button-group.mdx +++ b/docs/src/content/components/button-group.mdx @@ -10,8 +10,4 @@ tags: relatedComponents: - button figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=13541-388737 -githubUrl: https://github.com/GovAlta/ui-components/issues?q=is%3Aissue+is%3Aopen+label%3A%22Button%20group%22 -webComponentTag: goa-button-group -reactClassName: GoabButtonGroup -angularSelector: goab-button-group --- diff --git a/docs/src/content/components/button.mdx b/docs/src/content/components/button.mdx index a64f856638..b0e137d6b7 100644 --- a/docs/src/content/components/button.mdx +++ b/docs/src/content/components/button.mdx @@ -11,8 +11,4 @@ relatedComponents: - button-group - icon-button figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=57138-300030 -githubUrl: https://github.com/GovAlta/ui-components/issues?q=is%3Aissue+is%3Aopen+label%3AButton -webComponentTag: goa-button -reactClassName: GoabButton -angularSelector: goab-button --- diff --git a/docs/src/content/components/calendar.mdx b/docs/src/content/components/calendar.mdx index c36584a559..b0698b8418 100644 --- a/docs/src/content/components/calendar.mdx +++ b/docs/src/content/components/calendar.mdx @@ -6,7 +6,4 @@ category: utilities hidden: true relatedComponents: - date-picker -webComponentTag: goa-calendar -reactClassName: GoabCalendar -angularSelector: goab-calendar --- diff --git a/docs/src/content/components/callout.mdx b/docs/src/content/components/callout.mdx index 3240a5afb0..c7a04e350e 100644 --- a/docs/src/content/components/callout.mdx +++ b/docs/src/content/components/callout.mdx @@ -11,8 +11,4 @@ relatedComponents: - notification - badge figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56969-453927 -githubUrl: https://github.com/GovAlta/ui-components/labels/Callout -webComponentTag: goa-callout -reactClassName: GoabCallout -angularSelector: goab-callout --- diff --git a/docs/src/content/components/checkbox-list.mdx b/docs/src/content/components/checkbox-list.mdx index 37ff245708..5496d38f5b 100644 --- a/docs/src/content/components/checkbox-list.mdx +++ b/docs/src/content/components/checkbox-list.mdx @@ -11,7 +11,4 @@ relatedComponents: - checkbox - form-item figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56969-469340 -webComponentTag: goa-checkbox-list -reactClassName: GoabCheckboxList -angularSelector: goab-checkbox-list --- diff --git a/docs/src/content/components/checkbox.mdx b/docs/src/content/components/checkbox.mdx index 575b1484bf..7d5e0aef4d 100644 --- a/docs/src/content/components/checkbox.mdx +++ b/docs/src/content/components/checkbox.mdx @@ -13,8 +13,4 @@ relatedComponents: - form-item - radio-group figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56969-469737 -githubUrl: https://github.com/GovAlta/ui-components/labels/Checkbox -webComponentTag: goa-checkbox -reactClassName: GoabCheckbox -angularSelector: goab-checkbox --- diff --git a/docs/src/content/components/chip.mdx b/docs/src/content/components/chip.mdx index 51792fea09..89c0ab3c46 100644 --- a/docs/src/content/components/chip.mdx +++ b/docs/src/content/components/chip.mdx @@ -7,7 +7,4 @@ hidden: true relatedComponents: - filter-chip - badge -webComponentTag: goa-chip -reactClassName: GoabChip -angularSelector: goab-chip --- diff --git a/docs/src/content/components/circular-progress.mdx b/docs/src/content/components/circular-progress.mdx index 11dc4992bd..341dae2098 100644 --- a/docs/src/content/components/circular-progress.mdx +++ b/docs/src/content/components/circular-progress.mdx @@ -15,8 +15,4 @@ relatedComponents: - linear-progress - spinner figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=633-12563 -githubUrl: https://github.com/GovAlta/ui-components/issues?q=is%3Aissue+is%3Aopen+label%3A%22Progress%20indicator%22 -webComponentTag: goa-circular-progress -reactClassName: GoabCircularProgress -angularSelector: goab-circular-progress --- diff --git a/docs/src/content/components/container.mdx b/docs/src/content/components/container.mdx index c9efe290fc..acfdec7524 100644 --- a/docs/src/content/components/container.mdx +++ b/docs/src/content/components/container.mdx @@ -13,8 +13,4 @@ relatedComponents: - block - grid figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=1791-19104 -githubUrl: https://github.com/GovAlta/ui-components/labels/Container -webComponentTag: goa-container -reactClassName: GoabContainer -angularSelector: goab-container --- diff --git a/docs/src/content/components/data-grid.mdx b/docs/src/content/components/data-grid.mdx index db24d6e22d..285dcba70c 100644 --- a/docs/src/content/components/data-grid.mdx +++ b/docs/src/content/components/data-grid.mdx @@ -13,7 +13,4 @@ tags: relatedComponents: - table - pagination -webComponentTag: goa-data-grid -reactClassName: GoabDataGrid -angularSelector: goab-data-grid --- diff --git a/docs/src/content/components/date-picker.mdx b/docs/src/content/components/date-picker.mdx index 7481d69550..a8ffdbdafe 100644 --- a/docs/src/content/components/date-picker.mdx +++ b/docs/src/content/components/date-picker.mdx @@ -14,8 +14,4 @@ relatedComponents: - input - calendar figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=61102-130736 -githubUrl: https://github.com/GovAlta/ui-components/labels/Date%20picker -webComponentTag: goa-date-picker -reactClassName: GoabDatePicker -angularSelector: goab-date-picker --- diff --git a/docs/src/content/components/details.mdx b/docs/src/content/components/details.mdx index 21efc3d2ef..4cbebe7b19 100644 --- a/docs/src/content/components/details.mdx +++ b/docs/src/content/components/details.mdx @@ -24,8 +24,4 @@ tags: relatedComponents: - accordion figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=15932-569233 -githubUrl: https://github.com/GovAlta/ui-components/labels/Accordion %2B Detail -webComponentTag: goa-details -reactClassName: GoabDetails -angularSelector: goab-details --- diff --git a/docs/src/content/components/divider.mdx b/docs/src/content/components/divider.mdx index d1824180f3..1272640194 100644 --- a/docs/src/content/components/divider.mdx +++ b/docs/src/content/components/divider.mdx @@ -10,8 +10,4 @@ tags: relatedComponents: - spacer figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=550-5137 -githubUrl: https://github.com/GovAlta/ui-components/labels/Divider -webComponentTag: goa-divider -reactClassName: GoabDivider -angularSelector: goab-divider --- diff --git a/docs/src/content/components/drawer.mdx b/docs/src/content/components/drawer.mdx index 2750d7e2ef..c3d3ad8be6 100644 --- a/docs/src/content/components/drawer.mdx +++ b/docs/src/content/components/drawer.mdx @@ -13,8 +13,4 @@ relatedComponents: - modal - push-drawer figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=60158-687174 -githubUrl: https://github.com/GovAlta/ui-components/labels/Drawer -webComponentTag: goa-drawer -reactClassName: GoabDrawer -angularSelector: goab-drawer --- diff --git a/docs/src/content/components/dropdown-item.mdx b/docs/src/content/components/dropdown-item.mdx new file mode 100644 index 0000000000..7c00c2cb98 --- /dev/null +++ b/docs/src/content/components/dropdown-item.mdx @@ -0,0 +1,13 @@ +--- +name: Dropdown Item +description: An individual option within a dropdown. +status: stable +category: inputs-and-actions +hidden: true +subcomponent: true +relatedComponents: + - dropdown +webComponentTag: goa-dropdown-item +reactClassName: GoabDropdownItem +angularSelector: goab-dropdown-item +--- diff --git a/docs/src/content/components/dropdown.mdx b/docs/src/content/components/dropdown.mdx index f1f986122f..f1e532ec78 100644 --- a/docs/src/content/components/dropdown.mdx +++ b/docs/src/content/components/dropdown.mdx @@ -8,11 +8,8 @@ tags: - select - single select dropdown relatedComponents: + - dropdown-item - form-item - input figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=28478-241608 -githubUrl: https://github.com/GovAlta/ui-components/labels/Dropdown -webComponentTag: goa-dropdown -reactClassName: GoabDropdown -angularSelector: goab-dropdown --- diff --git a/docs/src/content/components/file-upload-card.mdx b/docs/src/content/components/file-upload-card.mdx index c0cffe42a5..7500d227d5 100644 --- a/docs/src/content/components/file-upload-card.mdx +++ b/docs/src/content/components/file-upload-card.mdx @@ -7,7 +7,4 @@ hidden: true subcomponent: true relatedComponents: - file-upload-input -webComponentTag: goa-file-upload-card -reactClassName: GoabFileUploadCard -angularSelector: goab-file-upload-card --- diff --git a/docs/src/content/components/file-upload-input.mdx b/docs/src/content/components/file-upload-input.mdx index 8f68492c61..57648a9bb1 100644 --- a/docs/src/content/components/file-upload-input.mdx +++ b/docs/src/content/components/file-upload-input.mdx @@ -12,8 +12,4 @@ relatedComponents: - file-upload-card - form-item figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=14458-398119 -githubUrl: https://github.com/GovAlta/ui-components/labels/File%20uploader -webComponentTag: goa-file-upload-input -reactClassName: GoabFileUploadInput -angularSelector: goab-file-upload-input --- diff --git a/docs/src/content/components/filter-chip.mdx b/docs/src/content/components/filter-chip.mdx index 7035315007..cddd9ca0c6 100644 --- a/docs/src/content/components/filter-chip.mdx +++ b/docs/src/content/components/filter-chip.mdx @@ -9,8 +9,4 @@ tags: relatedComponents: - chip figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56969-516598 -githubUrl: https://github.com/GovAlta/ui-components/labels/Filter%20chip -webComponentTag: goa-filter-chip -reactClassName: GoabFilterChip -angularSelector: goab-filter-chip --- diff --git a/docs/src/content/components/focus-trap.mdx b/docs/src/content/components/focus-trap.mdx index c2a8a9047c..9dc6932975 100644 --- a/docs/src/content/components/focus-trap.mdx +++ b/docs/src/content/components/focus-trap.mdx @@ -5,7 +5,4 @@ status: stable category: utilities hidden: true -webComponentTag: goa-focus-trap -reactClassName: GoabFocusTrap -angularSelector: goab-focus-trap --- diff --git a/docs/src/content/components/footer-meta-section.mdx b/docs/src/content/components/footer-meta-section.mdx index 68d316a1c8..756e7c2423 100644 --- a/docs/src/content/components/footer-meta-section.mdx +++ b/docs/src/content/components/footer-meta-section.mdx @@ -7,7 +7,4 @@ hidden: true subcomponent: true relatedComponents: - footer -webComponentTag: goa-footer-meta-section -reactClassName: GoabFooterMetaSection -angularSelector: goab-footer-meta-section --- diff --git a/docs/src/content/components/footer-nav-section.mdx b/docs/src/content/components/footer-nav-section.mdx index ead7071350..12e2240dfa 100644 --- a/docs/src/content/components/footer-nav-section.mdx +++ b/docs/src/content/components/footer-nav-section.mdx @@ -8,7 +8,4 @@ subcomponent: true relatedComponents: - footer - link -webComponentTag: goa-footer-nav-section -reactClassName: GoabFooterNavSection -angularSelector: goab-footer-nav-section --- diff --git a/docs/src/content/components/footer.mdx b/docs/src/content/components/footer.mdx index 5b88d66449..81b07cb427 100644 --- a/docs/src/content/components/footer.mdx +++ b/docs/src/content/components/footer.mdx @@ -10,8 +10,4 @@ relatedComponents: - footer-meta-section - footer-nav-section figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=5652-228863 -githubUrl: https://github.com/GovAlta/ui-components/issues?q=is%3Aissue+is%3Aopen+label%3A%22Footer%22 -webComponentTag: goa-footer -reactClassName: GoabFooter -angularSelector: goab-footer --- diff --git a/docs/src/content/components/form-item.mdx b/docs/src/content/components/form-item.mdx index 3559081d90..ee5a5fe7ee 100644 --- a/docs/src/content/components/form-item.mdx +++ b/docs/src/content/components/form-item.mdx @@ -17,8 +17,4 @@ relatedComponents: - radio-group - text-area figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56969-535065 -githubUrl: https://github.com/GovAlta/ui-components/labels/Form%20item -webComponentTag: goa-form-item -reactClassName: GoabFormItem -angularSelector: goab-form-item --- diff --git a/docs/src/content/components/form-step.mdx b/docs/src/content/components/form-step.mdx index 291c22b23d..3c4468c200 100644 --- a/docs/src/content/components/form-step.mdx +++ b/docs/src/content/components/form-step.mdx @@ -7,7 +7,4 @@ hidden: true subcomponent: true relatedComponents: - form-stepper -webComponentTag: goa-form-step -reactClassName: GoabFormStep -angularSelector: goab-form-step --- diff --git a/docs/src/content/components/form-stepper.mdx b/docs/src/content/components/form-stepper.mdx index 6bb432b9d2..6ef2a83234 100644 --- a/docs/src/content/components/form-stepper.mdx +++ b/docs/src/content/components/form-stepper.mdx @@ -3,6 +3,7 @@ name: Form stepper description: Provides a visual representation of a form through a series of steps. status: deprecated category: structure-and-navigation +hidden: true tags: - form stepper - horizontal step navigation @@ -15,8 +16,4 @@ relatedComponents: - form-step - form figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=27335-606356 -githubUrl: https://github.com/GovAlta/ui-components/labels/Form%20stepper -webComponentTag: goa-form-stepper -reactClassName: GoabFormStepper -angularSelector: goab-form-stepper --- diff --git a/docs/src/content/components/form.mdx b/docs/src/content/components/form.mdx index f0fde6e36f..684288a22d 100644 --- a/docs/src/content/components/form.mdx +++ b/docs/src/content/components/form.mdx @@ -3,10 +3,8 @@ name: Form description: Container for form inputs and validation. status: stable category: inputs-and-actions +hidden: true relatedComponents: - form-item - form-stepper -webComponentTag: goa-form -reactClassName: GoabForm -angularSelector: goab-form --- diff --git a/docs/src/content/components/grid.mdx b/docs/src/content/components/grid.mdx index ad785f6305..f29ee73eb5 100644 --- a/docs/src/content/components/grid.mdx +++ b/docs/src/content/components/grid.mdx @@ -8,8 +8,4 @@ tags: relatedComponents: - container - spacer -githubUrl: https://github.com/GovAlta/ui-components/labels/Grid -webComponentTag: goa-grid -reactClassName: GoabGrid -angularSelector: goab-grid --- diff --git a/docs/src/content/components/hero-banner.mdx b/docs/src/content/components/hero-banner.mdx index de764ea2ec..4213812de1 100644 --- a/docs/src/content/components/hero-banner.mdx +++ b/docs/src/content/components/hero-banner.mdx @@ -8,8 +8,4 @@ tags: - hero panel - structure and navigation figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=633-10280 -githubUrl: https://github.com/GovAlta/ui-components/labels/Hero banner -webComponentTag: goa-hero-banner -reactClassName: GoabHeroBanner -angularSelector: goab-hero-banner --- diff --git a/docs/src/content/components/icon-button.mdx b/docs/src/content/components/icon-button.mdx index 54c8a75229..77fc1b2436 100644 --- a/docs/src/content/components/icon-button.mdx +++ b/docs/src/content/components/icon-button.mdx @@ -11,8 +11,4 @@ relatedComponents: - button - icon figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56969-757260 -githubUrl: https://github.com/GovAlta/ui-components/labels/Icon%20button -webComponentTag: goa-icon-button -reactClassName: GoabIconButton -angularSelector: goab-icon-button --- diff --git a/docs/src/content/components/icon.mdx b/docs/src/content/components/icon.mdx index 71c81f402c..bdce50915f 100644 --- a/docs/src/content/components/icon.mdx +++ b/docs/src/content/components/icon.mdx @@ -8,8 +8,4 @@ tags: relatedComponents: - icon-button figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=24019-474002 -githubUrl: https://github.com/GovAlta/ui-components/labels/Icons -webComponentTag: goa-icon -reactClassName: GoabIcon -angularSelector: goab-icon --- diff --git a/docs/src/content/components/input.mdx b/docs/src/content/components/input.mdx index afa8303904..39800ea7fa 100644 --- a/docs/src/content/components/input.mdx +++ b/docs/src/content/components/input.mdx @@ -14,10 +14,6 @@ relatedComponents: - text-area - dropdown figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56970-136310 -githubUrl: https://github.com/GovAlta/ui-components/labels/Input -webComponentTag: goa-input -reactClassName: GoabInput -angularSelector: goab-input --- Capture text input from users in forms. diff --git a/docs/src/content/components/linear-progress.mdx b/docs/src/content/components/linear-progress.mdx index e4b81efd43..7774602b7c 100644 --- a/docs/src/content/components/linear-progress.mdx +++ b/docs/src/content/components/linear-progress.mdx @@ -14,8 +14,4 @@ relatedComponents: - circular-progress - spinner figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=14458-398386 -githubUrl: https://github.com/GovAlta/ui-components/issues?q=sort%3Aupdated-desc+is%3Aopen+label%3A%22Linear+progress+indicator%22 -webComponentTag: goa-linear-progress -reactClassName: GoabLinearProgress -angularSelector: goab-linear-progress --- diff --git a/docs/src/content/components/link-button.mdx b/docs/src/content/components/link-button.mdx index c6625ff2d1..5fdbf59b60 100644 --- a/docs/src/content/components/link-button.mdx +++ b/docs/src/content/components/link-button.mdx @@ -7,7 +7,4 @@ hidden: true relatedComponents: - button - link -webComponentTag: goa-link-button -reactClassName: GoabLinkButton -angularSelector: goab-link-button --- diff --git a/docs/src/content/components/link.mdx b/docs/src/content/components/link.mdx index 486a6ec668..8415e1633e 100644 --- a/docs/src/content/components/link.mdx +++ b/docs/src/content/components/link.mdx @@ -9,8 +9,4 @@ tags: relatedComponents: - link-button figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56970-352878 -githubUrl: https://github.com/GovAlta/ui-components/issues?q=is%3Aissue+is%3Aopen+label%3A%22Link%22 -webComponentTag: goa-link -reactClassName: GoabLink -angularSelector: goab-link --- diff --git a/docs/src/content/components/menu-action.mdx b/docs/src/content/components/menu-action.mdx index 741523f2da..c6bafc0c81 100644 --- a/docs/src/content/components/menu-action.mdx +++ b/docs/src/content/components/menu-action.mdx @@ -7,5 +7,4 @@ hidden: true subcomponent: true relatedComponents: - menu-button -webComponentTag: goa-menu-action --- diff --git a/docs/src/content/components/menu-button.mdx b/docs/src/content/components/menu-button.mdx index c5031324f9..d9ce95df69 100644 --- a/docs/src/content/components/menu-button.mdx +++ b/docs/src/content/components/menu-button.mdx @@ -11,8 +11,4 @@ relatedComponents: - menu-action - popover figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=57138-308450 -githubUrl: https://github.com/GovAlta/ui-components/labels/Multi%20action%20button -webComponentTag: goa-menu-button -reactClassName: GoabMenuButton -angularSelector: goab-menu-button --- diff --git a/docs/src/content/components/microsite-header.mdx b/docs/src/content/components/microsite-header.mdx index b020130105..712d7dc5a2 100644 --- a/docs/src/content/components/microsite-header.mdx +++ b/docs/src/content/components/microsite-header.mdx @@ -17,8 +17,4 @@ tags: - structure and navigation relatedComponents: - app-header -githubUrl: https://github.com/GovAlta/ui-components/labels/Microsite%20header -webComponentTag: goa-microsite-header -reactClassName: GoabMicrositeHeader -angularSelector: goab-microsite-header --- diff --git a/docs/src/content/components/modal.mdx b/docs/src/content/components/modal.mdx index 25f18b0b80..777a22b51e 100644 --- a/docs/src/content/components/modal.mdx +++ b/docs/src/content/components/modal.mdx @@ -12,8 +12,4 @@ tags: relatedComponents: - drawer figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56970-444330 -githubUrl: https://github.com/GovAlta/ui-components/labels/Modal -webComponentTag: goa-modal -reactClassName: GoabModal -angularSelector: goab-modal --- diff --git a/docs/src/content/components/notification.mdx b/docs/src/content/components/notification.mdx index 46705eb691..c61dcdd9ff 100644 --- a/docs/src/content/components/notification.mdx +++ b/docs/src/content/components/notification.mdx @@ -11,8 +11,4 @@ relatedComponents: - callout - temporary-notification figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56970-485993 -githubUrl: https://github.com/GovAlta/ui-components/labels/Notification%20banner -webComponentTag: goa-notification -reactClassName: GoabNotification -angularSelector: goab-notification --- diff --git a/docs/src/content/components/page-block.mdx b/docs/src/content/components/page-block.mdx index f6ebefea66..27cb495fb3 100644 --- a/docs/src/content/components/page-block.mdx +++ b/docs/src/content/components/page-block.mdx @@ -6,7 +6,4 @@ category: content-layout relatedComponents: - block - container -webComponentTag: goa-page-block -reactClassName: GoabPageBlock -angularSelector: goab-page-block --- diff --git a/docs/src/content/components/pages.mdx b/docs/src/content/components/pages.mdx index c829c41f5b..0e7959d3e8 100644 --- a/docs/src/content/components/pages.mdx +++ b/docs/src/content/components/pages.mdx @@ -5,7 +5,4 @@ status: stable category: structure-and-navigation hidden: true -webComponentTag: goa-pages -reactClassName: GoabPages -angularSelector: goab-pages --- diff --git a/docs/src/content/components/pagination.mdx b/docs/src/content/components/pagination.mdx index 2d5ae0838f..ca7790808f 100644 --- a/docs/src/content/components/pagination.mdx +++ b/docs/src/content/components/pagination.mdx @@ -11,8 +11,4 @@ relatedComponents: - data-grid - table figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=26318-193264 -githubUrl: https://github.com/GovAlta/ui-components/labels/Pagination -webComponentTag: goa-pagination -reactClassName: GoabPagination -angularSelector: goab-pagination --- diff --git a/docs/src/content/components/popover.mdx b/docs/src/content/components/popover.mdx index b44dedd3fe..05e4c86342 100644 --- a/docs/src/content/components/popover.mdx +++ b/docs/src/content/components/popover.mdx @@ -10,8 +10,4 @@ relatedComponents: - tooltip - menu-button figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=32486-707969 -githubUrl: https://github.com/GovAlta/ui-components/labels/Popover -webComponentTag: goa-popover -reactClassName: GoabPopover -angularSelector: goab-popover --- diff --git a/docs/src/content/components/push-drawer.mdx b/docs/src/content/components/push-drawer.mdx index 871fba2829..372d03f9b9 100644 --- a/docs/src/content/components/push-drawer.mdx +++ b/docs/src/content/components/push-drawer.mdx @@ -12,8 +12,6 @@ tags: relatedComponents: - drawer figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=60151-367783 -githubUrl: https://github.com/GovAlta/ui-components/labels/Push%20Drawer -webComponentTag: goa-push-drawer -reactClassName: GoabPushDrawer -angularSelector: goab-push-drawer --- + +See it used in context in the [Workspace](/examples/workspace#push-drawer) for case-action drawers that keep the user on the page while completing a focused task. diff --git a/docs/src/content/components/radio-group.mdx b/docs/src/content/components/radio-group.mdx index 5605e8ce51..b37a0219dc 100644 --- a/docs/src/content/components/radio-group.mdx +++ b/docs/src/content/components/radio-group.mdx @@ -13,8 +13,4 @@ relatedComponents: - form-item - checkbox figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=56970-509527 -githubUrl: https://github.com/GovAlta/ui-components/labels/Radio -webComponentTag: goa-radio-group -reactClassName: GoabRadioGroup -angularSelector: goab-radio-group --- diff --git a/docs/src/content/components/radio-item.mdx b/docs/src/content/components/radio-item.mdx index a7e8bf13d5..979efe223b 100644 --- a/docs/src/content/components/radio-item.mdx +++ b/docs/src/content/components/radio-item.mdx @@ -7,7 +7,4 @@ hidden: true subcomponent: true relatedComponents: - radio-group -webComponentTag: goa-radio-item -reactClassName: GoabRadioItem -angularSelector: goab-radio-item --- diff --git a/docs/src/content/components/scrollable.mdx b/docs/src/content/components/scrollable.mdx index eef1bb977f..2fe5ea0034 100644 --- a/docs/src/content/components/scrollable.mdx +++ b/docs/src/content/components/scrollable.mdx @@ -5,7 +5,4 @@ status: stable category: utilities hidden: true -webComponentTag: goa-scrollable -reactClassName: GoabScrollable -angularSelector: goab-scrollable --- diff --git a/docs/src/content/components/side-menu-group.mdx b/docs/src/content/components/side-menu-group.mdx index c4a3df750f..46b9c08e93 100644 --- a/docs/src/content/components/side-menu-group.mdx +++ b/docs/src/content/components/side-menu-group.mdx @@ -8,7 +8,4 @@ subcomponent: true relatedComponents: - side-menu - side-menu-heading -webComponentTag: goa-side-menu-group -reactClassName: GoabSideMenuGroup -angularSelector: goab-side-menu-group --- diff --git a/docs/src/content/components/side-menu-heading.mdx b/docs/src/content/components/side-menu-heading.mdx index 20acf4763e..4c33cfe827 100644 --- a/docs/src/content/components/side-menu-heading.mdx +++ b/docs/src/content/components/side-menu-heading.mdx @@ -8,7 +8,4 @@ subcomponent: true relatedComponents: - side-menu - side-menu-group -webComponentTag: goa-side-menu-heading -reactClassName: GoabSideMenuHeading -angularSelector: goab-side-menu-heading --- diff --git a/docs/src/content/components/side-menu.mdx b/docs/src/content/components/side-menu.mdx index 1d6f85a2b4..a2768c6ab3 100644 --- a/docs/src/content/components/side-menu.mdx +++ b/docs/src/content/components/side-menu.mdx @@ -13,8 +13,4 @@ relatedComponents: - side-menu-heading - work-side-menu figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=58780-485596 -githubUrl: https://github.com/GovAlta/ui-components/labels/Side%20menu -webComponentTag: goa-side-menu -reactClassName: GoabSideMenu -angularSelector: goab-side-menu --- diff --git a/docs/src/content/components/skeleton.mdx b/docs/src/content/components/skeleton.mdx index 2e1c9d49fd..940fa51081 100644 --- a/docs/src/content/components/skeleton.mdx +++ b/docs/src/content/components/skeleton.mdx @@ -6,8 +6,4 @@ category: feedback-and-alerts tags: - content layout - loading -githubUrl: https://github.com/GovAlta/ui-components/labels/Skeleton%20loading -webComponentTag: goa-skeleton -reactClassName: GoabSkeleton -angularSelector: goab-skeleton --- diff --git a/docs/src/content/components/spacer.mdx b/docs/src/content/components/spacer.mdx index cade29d729..09a3810c56 100644 --- a/docs/src/content/components/spacer.mdx +++ b/docs/src/content/components/spacer.mdx @@ -13,8 +13,4 @@ relatedComponents: - divider - grid figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=21567-616073 -githubUrl: https://github.com/GovAlta/ui-components/labels/Spacer -webComponentTag: goa-spacer -reactClassName: GoabSpacer -angularSelector: goab-spacer --- diff --git a/docs/src/content/components/spinner.mdx b/docs/src/content/components/spinner.mdx index b9cb2c72c8..2a215c660a 100644 --- a/docs/src/content/components/spinner.mdx +++ b/docs/src/content/components/spinner.mdx @@ -7,7 +7,4 @@ hidden: true relatedComponents: - circular-progress - linear-progress -webComponentTag: goa-spinner -reactClassName: GoabSpinner -angularSelector: goab-spinner --- diff --git a/docs/src/content/components/tab.mdx b/docs/src/content/components/tab.mdx index 21e9c9a3ab..61c81f2b20 100644 --- a/docs/src/content/components/tab.mdx +++ b/docs/src/content/components/tab.mdx @@ -7,7 +7,4 @@ hidden: true subcomponent: true relatedComponents: - tabs -webComponentTag: goa-tab -reactClassName: GoabTab -angularSelector: goab-tab --- diff --git a/docs/src/content/components/table.mdx b/docs/src/content/components/table.mdx index eb91419940..aa4aeb23c0 100644 --- a/docs/src/content/components/table.mdx +++ b/docs/src/content/components/table.mdx @@ -12,8 +12,4 @@ relatedComponents: - data-grid - pagination figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=27343-613386 -githubUrl: https://github.com/GovAlta/ui-components/labels/Table -webComponentTag: goa-table -reactClassName: GoabTable -angularSelector: goab-table --- diff --git a/docs/src/content/components/tabs.mdx b/docs/src/content/components/tabs.mdx index ada8af20d4..20f9efa3bc 100644 --- a/docs/src/content/components/tabs.mdx +++ b/docs/src/content/components/tabs.mdx @@ -10,8 +10,4 @@ tags: relatedComponents: - tab figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=25293-550667 -githubUrl: https://github.com/GovAlta/ui-components/labels/Tabs -webComponentTag: goa-tabs -reactClassName: GoabTabs -angularSelector: goab-tabs --- diff --git a/docs/src/content/components/temporary-notification.mdx b/docs/src/content/components/temporary-notification.mdx index ae233a6dbb..96050f2cb4 100644 --- a/docs/src/content/components/temporary-notification.mdx +++ b/docs/src/content/components/temporary-notification.mdx @@ -10,8 +10,4 @@ tags: relatedComponents: - notification figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=33183-290309 -githubUrl: https://github.com/GovAlta/ui-components/labels/Temporary%20notification -webComponentTag: goa-temporary-notification -reactClassName: GoabTemporaryNotification -angularSelector: goab-temporary-notification --- diff --git a/docs/src/content/components/text-area.mdx b/docs/src/content/components/text-area.mdx index 1e72220cb9..88db458e0d 100644 --- a/docs/src/content/components/text-area.mdx +++ b/docs/src/content/components/text-area.mdx @@ -14,8 +14,4 @@ relatedComponents: - form-item - input figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=12711-380735 -githubUrl: https://github.com/GovAlta/ui-components/labels/Text%20area -webComponentTag: goa-text-area -reactClassName: GoabTextArea -angularSelector: goab-text-area --- diff --git a/docs/src/content/components/text.mdx b/docs/src/content/components/text.mdx index 380fd5bfbd..c7f6357ed1 100644 --- a/docs/src/content/components/text.mdx +++ b/docs/src/content/components/text.mdx @@ -8,8 +8,4 @@ tags: - body - copy figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=21567-615910 -githubUrl: https://github.com/GovAlta/ui-components/labels/Text -webComponentTag: goa-text -reactClassName: GoabText -angularSelector: goab-text --- diff --git a/docs/src/content/components/tooltip.mdx b/docs/src/content/components/tooltip.mdx index bc88af4799..36c666da9b 100644 --- a/docs/src/content/components/tooltip.mdx +++ b/docs/src/content/components/tooltip.mdx @@ -8,8 +8,4 @@ tags: relatedComponents: - popover figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=21932-557085 -githubUrl: https://github.com/GovAlta/ui-components/labels/Tooltip -webComponentTag: goa-tooltip -reactClassName: GoabTooltip -angularSelector: goab-tooltip --- diff --git a/docs/src/content/components/work-side-menu-group.mdx b/docs/src/content/components/work-side-menu-group.mdx index a756bd750c..25d0e0abad 100644 --- a/docs/src/content/components/work-side-menu-group.mdx +++ b/docs/src/content/components/work-side-menu-group.mdx @@ -7,5 +7,4 @@ hidden: true subcomponent: true relatedComponents: - work-side-menu -webComponentTag: goa-work-side-menu-group --- diff --git a/docs/src/content/components/work-side-menu-item.mdx b/docs/src/content/components/work-side-menu-item.mdx index 17db534b6f..97aac145dd 100644 --- a/docs/src/content/components/work-side-menu-item.mdx +++ b/docs/src/content/components/work-side-menu-item.mdx @@ -7,5 +7,4 @@ hidden: true subcomponent: true relatedComponents: - work-side-menu -webComponentTag: goa-work-side-menu-item --- diff --git a/docs/src/content/components/work-side-menu.mdx b/docs/src/content/components/work-side-menu.mdx index 983763d518..bd3ee17b97 100644 --- a/docs/src/content/components/work-side-menu.mdx +++ b/docs/src/content/components/work-side-menu.mdx @@ -7,8 +7,6 @@ relatedComponents: - side-menu - work-side-menu-group - work-side-menu-item + - work-side-notification-panel figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/Component-library?node-id=57622-159377 -webComponentTag: goa-work-side-menu -reactClassName: GoabWorkSideMenu -angularSelector: goab-work-side-menu --- diff --git a/docs/src/content/components/work-side-notification-item.mdx b/docs/src/content/components/work-side-notification-item.mdx new file mode 100644 index 0000000000..796b995f50 --- /dev/null +++ b/docs/src/content/components/work-side-notification-item.mdx @@ -0,0 +1,13 @@ +--- +name: Notification Item +description: Individual notification card within a notification panel, with read/unread states, priority levels, and type badges. +status: stable +category: structure-and-navigation +hidden: true +subcomponent: true +relatedComponents: + - work-side-notification-panel +webComponentTag: goa-work-side-notification-item +reactClassName: GoabWorkSideNotificationItem +angularSelector: goab-work-side-notification-item +--- diff --git a/docs/src/content/components/work-side-notification-panel.mdx b/docs/src/content/components/work-side-notification-panel.mdx new file mode 100644 index 0000000000..30bea1997e --- /dev/null +++ b/docs/src/content/components/work-side-notification-panel.mdx @@ -0,0 +1,16 @@ +--- +name: Notification Panel +description: A notification center panel that displays notification items within a work side menu, with tabs for filtering by unread, urgent, and all notifications. +status: stable +category: structure-and-navigation +tags: + - notifications + - work side menu + - panel +relatedComponents: + - work-side-menu + - work-side-notification-item +webComponentTag: goa-work-side-notification-panel +reactClassName: GoabWorkSideNotificationPanel +angularSelector: goab-work-side-notification-panel +--- diff --git a/docs/src/content/config.ts b/docs/src/content/config.ts index ce9ee40f4c..24c1a69adc 100644 --- a/docs/src/content/config.ts +++ b/docs/src/content/config.ts @@ -29,12 +29,6 @@ const components = defineCollection({ // External links figmaUrl: z.string().url().optional(), - githubUrl: z.string().optional(), - - // Framework identifiers (for cross-referencing) - webComponentTag: z.string().optional(), - reactClassName: z.string().optional(), - angularSelector: z.string().optional(), // Visibility hidden: z.boolean().optional(), // Hide from navigation and public views @@ -102,58 +96,141 @@ const guidance = defineCollection({ /** * Examples Collection - * Code examples showing components in context - * From small configurations to full services + * Working examples at every scale. The `size` field tells you how big a + * chunk of UI an entry documents, smallest to biggest: + * interaction — a single control or affordance behaving correctly + * section — a composed region of a page, smaller than a full page + * page — full-page composition + * task — a complete user job, often spanning multiple pages (e.g. a multi-step form) + * product — end-to-end digital product (e.g. the whole workspace demo) + * + * Product-type membership is expressed via the optional `productType` + * field, which links an example to a product type documented in the + * `productTypes` collection. */ -const examples = defineCollection({ - type: "content", - schema: z.object({ - // Identity - id: z.string(), - title: z.string(), - description: z.string().optional(), - slug: z.string().optional(), +const examplesBase = z.object({ + // Identity + id: z.string(), + title: z.string(), + description: z.string().optional(), + slug: z.string().optional(), - // Classification - categories: z.array( - z.enum([ - "content-layout", - "feedback-and-alerts", - "inputs-and-actions", - "forms", - "structure-and-navigation", - "technical", - ]), - ), - scale: z.enum(["interaction", "task", "page", "product"]), - userType: z.enum(["citizen", "worker", "both"]), + // Product shape this example belongs to (if any) + productType: z.enum(["workspace", "public-form"]).optional(), - tags: z.array(z.string()).optional(), + tags: z.array(z.string()).optional(), - // Components used (for relationship queries) - components: z.array(z.string()), + // Components used (structural query: "what's in it") + components: z.array(z.string()), - // Related examples - relatedExamples: z.array(z.string()).optional(), + // Related examples (editorial cross-link) + relatedExamples: z.array(z.string()).optional(), - // Accessibility notes (shown in collapsible on example card) - accessibilityNotes: z.string().optional(), + // Secondary names for search and URL redirects + aliases: z.array(z.string()).optional(), - // External links - figmaUrl: z.string().url().optional(), + // Accessibility notes (shown in collapsible on example card) + accessibilityNotes: z.string().optional(), - // Status - status: z.enum(["published", "draft", "deprecated"]).default("published"), + // External links + figmaUrl: z.string().url().optional(), + + // Status + status: z.enum(["published", "draft", "deprecated"]).default("published"), + + // Preview image (optional). Used as the card thumbnail in /examples/ and + // as a hero image at the top of the entry's docs page (unless hideHero is set). + previewImage: z.string().optional(), + + // Suppress the hero image on the docs page when previewImage is set. Use + // this for entries with multiple inline variant PreviewContainers (e.g. + // question-page, error-pages) where a single hero is not representative. + // The thumbnail still renders on the card in /examples/. + hideHero: z.boolean().optional(), + + // Render the live preview at full viewport width (no narrow column). + // Default is a centred 41.5rem column suited to single-form compositions + // (start-page, question-page, etc). Set true for layout-scale entries + // like basic-page-layout where the component manages its own width. + previewFullWidth: z.boolean().optional(), + + // Shared CSS file reference (relative to _shared folder) + styles: z.string().optional(), + + // Display options + fullWidth: z.boolean().optional(), // Remove side padding in preview (for callouts, notifications) + previewStyle: z.string().optional(), // Inline CSS override for preview container (e.g. "padding: 0; max-height: 600px") + + // Visibility + hidden: z.boolean().optional(), // Hide from examples listing, routes, and search +}); + +const interactionExample = examplesBase.extend({ + size: z.literal("interaction"), +}); + +const sectionExample = examplesBase.extend({ + size: z.literal("section"), +}); + +const pageLikeFields = { + // Page-scale source and preview links + previewUrl: z.string().url().optional(), + reactSourceUrl: z.string().url().optional(), + angularSourceUrl: z.string().url().optional(), + sourceUrl: z.string().url().optional(), + stackblitzUrl: z.string().url().optional(), + frameworks: z.array(z.enum(["react", "angular", "web-components"])).optional(), +}; + +const pageExample = examplesBase.extend({ + size: z.literal("page"), + ...pageLikeFields, +}); - // Preview image (optional) - previewImage: z.string().optional(), +const taskExample = examplesBase.extend({ + size: z.literal("task"), + ...pageLikeFields, +}); - // Shared CSS file reference (relative to _shared folder) - styles: z.string().optional(), +const productExample = examplesBase.extend({ + size: z.literal("product"), + ...pageLikeFields, +}); + +const examples = defineCollection({ + type: "content", + schema: z.discriminatedUnion("size", [ + interactionExample, + sectionExample, + pageExample, + taskExample, + productExample, + ]), +}); - // Display options - fullWidth: z.boolean().optional(), // Remove side padding in preview (for callouts, notifications) - previewStyle: z.string().optional(), // Inline CSS override for preview container (e.g. "padding: 0; max-height: 600px") +/** + * ProductTypes Collection + * Documentation pages for each kind of digital product the design system + * supports (workspace, public-form, etc). Each entry is the introductory + * narrative for one product type. The `/examples/[productType]/` route + * reads from this collection and queries the examples collection for + * entries with a matching `productType` field. + * + * Brief 110 will surface this collection at `/product-types/[slug]/`. + */ +const productTypes = defineCollection({ + type: "content", + schema: z.object({ + id: z.string(), + title: z.string(), + summary: z.string(), + heroImage: z.string().optional(), + demoUrl: z.string().url().optional(), + sourceUrl: z.string().url().optional(), + tags: z.array(z.string()).optional(), + components: z.array(z.string()).optional(), + status: z.enum(["published", "draft", "deprecated"]).default("published"), }), }); @@ -174,9 +251,34 @@ const foundations = defineCollection({ }), }); +/** + * Get Started Collection + * Onboarding pages for designers, developers, QA, and contributors. + * Entries flow to the docs site, MCP generator, and MD bundle. + */ +const getStarted = defineCollection({ + type: "content", + schema: z.object({ + id: z.string(), + title: z.string(), + // Optional shorter label for the submenu when the page title would read + // redundantly under its group heading (e.g. "Overview" vs "Designers overview"). + navLabel: z.string().optional(), + description: z.string().optional(), + // Submenu placement. "intro" and "appendix" are top-level (above and below + // the grouped sections); "designers" and "developers" are grouped. + section: z.enum(["intro", "designers", "developers", "appendix"]), + // Sort order within section. + order: z.number(), + status: z.enum(["published", "draft", "deprecated"]).default("published"), + }), +}); + export const collections = { components, guidance, examples, foundations, + productTypes, + "get-started": getStarted, }; diff --git a/docs/src/content/examples/401-error-page/index.mdx b/docs/src/content/examples/401-error-page/index.mdx deleted file mode 100644 index e2c1abf34f..0000000000 --- a/docs/src/content/examples/401-error-page/index.mdx +++ /dev/null @@ -1,38 +0,0 @@ ---- -id: 401-error-page -title: Restricted access (401) -categories: - - content-layout -scale: page -userType: both -tags: - - error - - page-structure - - "401" -components: - - page-block - - block - - text - - icon - - link - - button -status: published -fullWidth: true -previewStyle: "padding: 0" -accessibilityNotes: 'Uses a plain h1 as the page landmark. The decorative icon and accent bar are aria-hidden. The support email is a real mailto link inside GoabLink so keyboard users can activate it. No role="alert" is applied because the ARIA alert role is reserved for dynamically inserted messages.' ---- - -A full page that tells the user they cannot access the requested resource, with a clear next step and a way to contact support. - -## When to use - -- A user lands on a page that requires authentication they don't have. -- A user's session has expired and you need to prompt them to sign in again. -- A user is signed in but lacks the role or permission for the requested resource. - -## Considerations - -- Keep the message short and give the user one clear next step (usually sign in or go home). -- Include a support contact when the user may not be able to self-serve (for example, a role they need to be granted). -- A small amount of custom CSS covers the icon-in-circle treatment, the brand-color accent bar, centred text, and the icon scaled beyond `xlarge`. Each is a pattern the design system doesn't yet cover and is tracked as a gap for the library to absorb over time. -- The `

` uses `heading-l` (not the default `heading-xl`) to match the Figma spec for page-scale error states. diff --git a/docs/src/content/examples/404-error-page/index.mdx b/docs/src/content/examples/404-error-page/index.mdx deleted file mode 100644 index ab54a3a44c..0000000000 --- a/docs/src/content/examples/404-error-page/index.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -id: 404-error-page -title: Page not found (404) -categories: - - content-layout -scale: page -userType: both -tags: - - error - - page-structure - - "404" -components: - - page-block - - block - - text - - icon - - button -status: published -fullWidth: true -previewStyle: "padding: 0" -accessibilityNotes: 'Uses a plain h1 as the page landmark. The decorative icon and accent bar are aria-hidden. No role="alert" is applied because the ARIA alert role is reserved for dynamically inserted messages; a static error route does not meet that criterion.' ---- - -A full page that tells the user a page can't be found, with an action to get them back on track. - -## When to use - -- A user navigates to a URL that doesn't exist in your service. -- A resource has been moved or deleted and you need a catch-all route. -- As the fallback route rendered by your router's outlet. - -## Considerations - -- Keep the message short and give the user one clear next step. -- Render the pattern inside your existing layout (e.g. as the route in a `GoabOneColumnLayout` outlet) so it sits below your service's header and above its footer. -- A small amount of custom CSS covers the icon-in-circle treatment, the brand-color accent bar, centred text, and the icon scaled beyond `xlarge`. Each is a pattern the design system doesn't yet cover and is tracked as a gap for the library to absorb over time. -- The `

` uses `heading-l` (not the default `heading-xl`) to match the Figma spec for page-scale error states. diff --git a/docs/src/content/examples/500-error-page/index.mdx b/docs/src/content/examples/500-error-page/index.mdx deleted file mode 100644 index 5c2194a473..0000000000 --- a/docs/src/content/examples/500-error-page/index.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -id: 500-error-page -title: Server problem (500) -categories: - - content-layout -scale: page -userType: both -tags: - - error - - page-structure - - "500" -components: - - page-block - - block - - text - - icon - - button -status: published -fullWidth: true -previewStyle: "padding: 0" -accessibilityNotes: 'Uses a plain h1 as the page landmark. The decorative icon and accent bar are aria-hidden. No role="alert" is applied because the ARIA alert role is reserved for dynamically inserted messages; a static error route does not meet that criterion.' ---- - -A full page that tells the user the service is temporarily unable to respond, with an action to try again or return home. - -## When to use - -- A server-side error interrupted the user's request and there is nothing they can do to fix it themselves. -- A background dependency of your service is down. -- As a fallback for uncaught errors that reach the outer error boundary of your app. - -## Considerations - -- Take responsibility in the copy. The user did not cause this; acknowledge that and give them one clear action. -- This example uses "Go to home page" as the safe fallback action. If the failure is likely transient and the user can recover by retrying, swap the button's `onClick` for your retry handler and change the label to "Try again". -- A small amount of custom CSS covers the icon-in-circle treatment, the brand-color accent bar, centred text, and the icon scaled beyond `xlarge`. Each is a pattern the design system doesn't yet cover and is tracked as a gap for the library to absorb over time. -- The `

` uses `heading-l` (not the default `heading-xl`) to match the Figma spec for page-scale error states. diff --git a/docs/src/content/examples/add-a-filter-chip/index.mdx b/docs/src/content/examples/add-a-filter-chip/index.mdx index 77217bdd26..7e9173fb2b 100644 --- a/docs/src/content/examples/add-a-filter-chip/index.mdx +++ b/docs/src/content/examples/add-a-filter-chip/index.mdx @@ -1,10 +1,7 @@ --- id: add-a-filter-chip title: Add a filter chip -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - filtering - chips diff --git a/docs/src/content/examples/add-a-record-using-a-drawer/index.mdx b/docs/src/content/examples/add-a-record-using-a-drawer/index.mdx index cd07b09ac4..c9d2e654c5 100644 --- a/docs/src/content/examples/add-a-record-using-a-drawer/index.mdx +++ b/docs/src/content/examples/add-a-record-using-a-drawer/index.mdx @@ -1,10 +1,8 @@ --- id: add-a-record-using-a-drawer title: Add a record using a drawer -categories: - - structure-and-navigation -scale: task -userType: worker +size: section +productType: workspace tags: - drawer - forms diff --git a/docs/src/content/examples/add-and-edit-lots-of-filters/index.mdx b/docs/src/content/examples/add-and-edit-lots-of-filters/index.mdx index 615118ea61..df5951f2ca 100644 --- a/docs/src/content/examples/add-and-edit-lots-of-filters/index.mdx +++ b/docs/src/content/examples/add-and-edit-lots-of-filters/index.mdx @@ -1,10 +1,8 @@ --- id: add-and-edit-lots-of-filters title: Add and edit lots of filters -categories: - - structure-and-navigation -scale: task -userType: worker +size: section +productType: workspace tags: - filtering - drawer diff --git a/docs/src/content/examples/add-another-item-in-a-modal/index.mdx b/docs/src/content/examples/add-another-item-in-a-modal/index.mdx index 8e7232bf28..794c7611e1 100644 --- a/docs/src/content/examples/add-another-item-in-a-modal/index.mdx +++ b/docs/src/content/examples/add-another-item-in-a-modal/index.mdx @@ -1,10 +1,7 @@ --- id: add-another-item-in-a-modal title: Add another item in a modal -categories: - - inputs-and-actions -scale: task -userType: both +size: section tags: - modal - forms diff --git a/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/index.mdx b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/index.mdx index 0e507e54ad..4c9b078f35 100644 --- a/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/index.mdx +++ b/docs/src/content/examples/ask-a-long-answer-question-with-a-maximum-word-count/index.mdx @@ -1,10 +1,8 @@ --- id: ask-a-long-answer-question-with-a-maximum-word-count title: Ask a long answer question with a maximum word count -categories: - - forms -scale: task -userType: citizen +size: interaction +productType: public-form tags: - forms - text-area diff --git a/docs/src/content/examples/ask-a-user-for-a-birthday/index.mdx b/docs/src/content/examples/ask-a-user-for-a-birthday/index.mdx index c461ae3dea..5069834fa7 100644 --- a/docs/src/content/examples/ask-a-user-for-a-birthday/index.mdx +++ b/docs/src/content/examples/ask-a-user-for-a-birthday/index.mdx @@ -1,10 +1,8 @@ --- id: ask-a-user-for-a-birthday title: Ask a user for a birthday -categories: - - forms -scale: task -userType: citizen +size: interaction +productType: public-form tags: - forms - date-input diff --git a/docs/src/content/examples/ask-a-user-for-an-address/index.mdx b/docs/src/content/examples/ask-a-user-for-an-address/index.mdx index 5180a342cd..9f1959e1c0 100644 --- a/docs/src/content/examples/ask-a-user-for-an-address/index.mdx +++ b/docs/src/content/examples/ask-a-user-for-an-address/index.mdx @@ -1,10 +1,8 @@ --- id: ask-a-user-for-an-address title: Ask a user for an address -categories: - - forms -scale: task -userType: citizen +size: section +productType: public-form tags: - forms - address diff --git a/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/index.mdx b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/index.mdx index 58b355be21..aa67ee504c 100644 --- a/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/index.mdx +++ b/docs/src/content/examples/ask-a-user-for-an-indian-registration-number/index.mdx @@ -1,10 +1,8 @@ --- id: ask-a-user-for-an-indian-registration-number title: Ask a user for an Indian registration number -categories: - - forms -scale: task -userType: citizen +size: interaction +productType: public-form tags: - forms - identity diff --git a/docs/src/content/examples/ask-a-user-for-direct-deposit-information/index.mdx b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/index.mdx index 2dc73560b1..79413ea5f7 100644 --- a/docs/src/content/examples/ask-a-user-for-direct-deposit-information/index.mdx +++ b/docs/src/content/examples/ask-a-user-for-direct-deposit-information/index.mdx @@ -1,10 +1,8 @@ --- id: ask-a-user-for-direct-deposit-information title: Ask a user for direct deposit information -categories: - - forms -scale: task -userType: citizen +size: section +productType: public-form tags: - forms - banking diff --git a/docs/src/content/examples/ask-a-user-for-dollar-amounts/index.mdx b/docs/src/content/examples/ask-a-user-for-dollar-amounts/index.mdx index 51eeae7f6c..9198b22e01 100644 --- a/docs/src/content/examples/ask-a-user-for-dollar-amounts/index.mdx +++ b/docs/src/content/examples/ask-a-user-for-dollar-amounts/index.mdx @@ -1,10 +1,8 @@ --- id: ask-a-user-for-dollar-amounts title: Ask a user for dollar amounts -categories: - - forms -scale: task -userType: citizen +size: interaction +productType: public-form tags: - forms - currency diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.html b/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.html deleted file mode 100644 index 84c106cdae..0000000000 --- a/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.html +++ /dev/null @@ -1,19 +0,0 @@ - - Back - - - - - - - - Save and continue diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.ts b/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.ts deleted file mode 100644 index a46a1b448b..0000000000 --- a/docs/src/content/examples/ask-a-user-one-question-at-a-time/angular.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component } from "@angular/core"; -import { GoabRadioGroupOnChangeDetail } from "@abgov/ui-components-common"; - -@Component({ - selector: "app-ask-a-user-one-question-at-a-time", - templateUrl: "./angular.html", - styles: [ - ` - a.back-link::before { - content: ""; - display: inline-block; - width: 42px; - height: 24px; - vertical-align: middle; - background: url('data:image/svg+xml,') - center center no-repeat; - } - - a.back-link:visited::before, - a.back-link:hover::before { - background: url('data:image/svg+xml,') - center center no-repeat; - } - - a.back-link { - margin-top: var(--goa-space-m); - } - `, - ], -}) -export class AskAUserOneQuestionAtATimeComponent { - selectedValue = ""; - - onSchoolChange(event: GoabRadioGroupOnChangeDetail): void { - this.selectedValue = event.value as string; - } -} diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/index.mdx b/docs/src/content/examples/ask-a-user-one-question-at-a-time/index.mdx deleted file mode 100644 index 16add605d0..0000000000 --- a/docs/src/content/examples/ask-a-user-one-question-at-a-time/index.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -id: ask-a-user-one-question-at-a-time -title: Ask a user one question at a time -categories: - - forms -scale: page -userType: citizen -tags: - - forms - - questions - - public-form -components: - - form-item - - radio-group - - radio-item - - button -status: published -previewImage: /images/examples/ask-a-user-one-question-at-a-time.webp ---- - -Ask a user one question at a time. - -## When to use - -Use this pattern when: - -- Building a public-facing form for citizens -- You want to reduce cognitive load by focusing on one question -- The question requires careful consideration from the user -- Following the one-question-per-page pattern for government services - -## Considerations - -- Include a back link to allow users to navigate to previous questions -- Use a large label size to make the question prominent -- Provide help text when the question may need clarification -- Use a clear call-to-action button to progress diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/react.tsx b/docs/src/content/examples/ask-a-user-one-question-at-a-time/react.tsx deleted file mode 100644 index 0615ad3f04..0000000000 --- a/docs/src/content/examples/ask-a-user-one-question-at-a-time/react.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { - GoabButton, - GoabFormItem, - GoabLink, - GoabRadioGroup, - GoabRadioItem, -} from "@abgov/react-components"; - -export function AskAUserOneQuestionAtATime() { - return ( - <> - - Back - - - {}} - > - - - - - - Save and continue - - - ); -} diff --git a/docs/src/content/examples/ask-a-user-one-question-at-a-time/web-components.html b/docs/src/content/examples/ask-a-user-one-question-at-a-time/web-components.html deleted file mode 100644 index b788d88fc4..0000000000 --- a/docs/src/content/examples/ask-a-user-one-question-at-a-time/web-components.html +++ /dev/null @@ -1,22 +0,0 @@ - - Back - - - - - - - - Save and continue - - diff --git a/docs/src/content/examples/basic-page-layout/index.mdx b/docs/src/content/examples/basic-page-layout/index.mdx index 7c74326203..b7e2b019b6 100644 --- a/docs/src/content/examples/basic-page-layout/index.mdx +++ b/docs/src/content/examples/basic-page-layout/index.mdx @@ -1,10 +1,7 @@ --- id: basic-page-layout title: Basic page layout -categories: - - content-layout -scale: page -userType: both +size: page tags: - layout - page-structure @@ -19,6 +16,7 @@ status: published fullWidth: true previewStyle: "padding: 0; max-height: 600px" previewImage: /images/examples/basic-page-layout.webp +previewFullWidth: true --- A basic page template to use as a starting point. diff --git a/docs/src/content/examples/basic-page-layout/react.tsx b/docs/src/content/examples/basic-page-layout/react.tsx index b91d797d11..1d7c1db36e 100644 --- a/docs/src/content/examples/basic-page-layout/react.tsx +++ b/docs/src/content/examples/basic-page-layout/react.tsx @@ -15,7 +15,7 @@ export function BasicPageLayout() { Sign in - +

diff --git a/docs/src/content/examples/button-with-icon/index.mdx b/docs/src/content/examples/button-with-icon/index.mdx index a4fdb99952..7348b53deb 100644 --- a/docs/src/content/examples/button-with-icon/index.mdx +++ b/docs/src/content/examples/button-with-icon/index.mdx @@ -1,10 +1,7 @@ --- id: button-with-icon title: Button with Icon -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - icons - buttons diff --git a/docs/src/content/examples/card-grid/index.mdx b/docs/src/content/examples/card-grid/index.mdx index 191d3c4b91..432c23ee4d 100644 --- a/docs/src/content/examples/card-grid/index.mdx +++ b/docs/src/content/examples/card-grid/index.mdx @@ -1,10 +1,7 @@ --- id: card-grid title: Card grid -categories: - - content-layout -scale: task -userType: both +size: section tags: - cards - grid diff --git a/docs/src/content/examples/card-view-of-case-files/index.mdx b/docs/src/content/examples/card-view-of-case-files/index.mdx index bd5315ffed..05c3e1585d 100644 --- a/docs/src/content/examples/card-view-of-case-files/index.mdx +++ b/docs/src/content/examples/card-view-of-case-files/index.mdx @@ -1,10 +1,8 @@ --- id: card-view-of-case-files title: Card view of case files -categories: - - content-layout -scale: task -userType: worker +size: section +productType: workspace tags: - cards - case-management diff --git a/docs/src/content/examples/confirm-a-change/index.mdx b/docs/src/content/examples/confirm-a-change/index.mdx index 0b23ced98b..a37fdb914f 100644 --- a/docs/src/content/examples/confirm-a-change/index.mdx +++ b/docs/src/content/examples/confirm-a-change/index.mdx @@ -1,10 +1,7 @@ --- id: confirm-a-change title: Confirm a change -categories: - - inputs-and-actions -scale: task -userType: both +size: interaction tags: - modal - confirmation diff --git a/docs/src/content/examples/confirm-a-destructive-action/index.mdx b/docs/src/content/examples/confirm-a-destructive-action/index.mdx index 8a50858892..71ace15f4d 100644 --- a/docs/src/content/examples/confirm-a-destructive-action/index.mdx +++ b/docs/src/content/examples/confirm-a-destructive-action/index.mdx @@ -1,10 +1,7 @@ --- id: confirm-a-destructive-action title: Confirm a destructive action -categories: - - feedback-and-alerts -scale: task -userType: both +size: interaction tags: - modal - confirmation diff --git a/docs/src/content/examples/confirm-before-navigating-away/index.mdx b/docs/src/content/examples/confirm-before-navigating-away/index.mdx index de334716c2..9581a48eae 100644 --- a/docs/src/content/examples/confirm-before-navigating-away/index.mdx +++ b/docs/src/content/examples/confirm-before-navigating-away/index.mdx @@ -1,10 +1,8 @@ --- id: confirm-before-navigating-away title: Confirm before navigating away -categories: - - feedback-and-alerts -scale: task -userType: worker +size: interaction +productType: workspace tags: - modal - navigation diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.html b/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.html deleted file mode 100644 index 08cd9b6def..0000000000 --- a/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.html +++ /dev/null @@ -1,26 +0,0 @@ -You have completed the application - - - You will receive a copy of the confirmation to the email - person@email.com - Confirmation number: 1234ABC - - -Go back to the dashboard, or direct your user somewhere else useful. -Other information about what was just completed, other tertiary information, and/or - contact information. -
- Phone: 780 123 4567 -
- Email: information@gov.ab.ca -
- - - Go to application - Back to dashboard - diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.ts b/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.ts deleted file mode 100644 index 817bed0c4c..0000000000 --- a/docs/src/content/examples/confirm-that-an-application-was-submitted/angular.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Component } from "@angular/core"; - -@Component({ - selector: "app-confirm-that-an-application-was-submitted", - templateUrl: "./angular.html", -}) -export class ConfirmThatAnApplicationWasSubmittedComponent {} diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/index.mdx b/docs/src/content/examples/confirm-that-an-application-was-submitted/index.mdx deleted file mode 100644 index 6aa9364d72..0000000000 --- a/docs/src/content/examples/confirm-that-an-application-was-submitted/index.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -id: confirm-that-an-application-was-submitted -title: Confirm that an application was submitted -categories: - - feedback-and-alerts -scale: page -userType: citizen -tags: - - confirmation - - success - - callout - - application -components: - - callout - - button - - button-group -figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/%E2%9D%96-Component-library-%7C-DDD?node-id=63353-169579 -status: published -previewImage: /images/examples/confirm-that-an-application-was-submitted.webp ---- - -Display a confirmation screen to indicate successful application submission. - -## When to use - -Use this pattern when: - -- A user has successfully completed an application or form -- You need to confirm the submission was received -- Users need a confirmation number for their records -- You want to provide next steps after submission - -## Considerations - -- Use a success callout to clearly indicate success -- Include a confirmation number users can reference later -- Mention where a confirmation email will be sent -- Provide clear next steps and navigation options -- Include contact information for questions diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/react.tsx b/docs/src/content/examples/confirm-that-an-application-was-submitted/react.tsx deleted file mode 100644 index 5a6d308496..0000000000 --- a/docs/src/content/examples/confirm-that-an-application-was-submitted/react.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - GoabButton, - GoabButtonGroup, - GoabCallout, - GoabText, -} from "@abgov/react-components"; - -export function ConfirmThatAnApplicationWasSubmitted() { - return ( - <> - - You have completed the application - - - - - You will receive a copy of the confirmation to the email person@email.com - - - Confirmation number: 1234ABC - - - - - Go back to the dashboard, or direct your user somewhere else useful. - - - Other information about what was just completed, other tertiary information, - and/or contact information. -
- Phone: 780 123 4567 -
- Email: information@gov.ab.ca -
- - - Go to application - Back to dashboard - - - ); -} diff --git a/docs/src/content/examples/confirm-that-an-application-was-submitted/web-components.html b/docs/src/content/examples/confirm-that-an-application-was-submitted/web-components.html deleted file mode 100644 index ccdbdb6f19..0000000000 --- a/docs/src/content/examples/confirm-that-an-application-was-submitted/web-components.html +++ /dev/null @@ -1,25 +0,0 @@ -You have completed the application - - - You will receive a copy of the confirmation to the email person@email.com - Confirmation number: 1234ABC - - -Go back to the dashboard, or direct your user somewhere else useful. -Other information about what was just completed, other tertiary information, and/or - contact information. -
- Phone: 780 123 4567 -
- Email: information@gov.ab.ca -
- - - Go to application - Back to dashboard - diff --git a/docs/src/content/examples/copy-to-clipboard/index.mdx b/docs/src/content/examples/copy-to-clipboard/index.mdx index 439cc4a776..6b9f5dc34d 100644 --- a/docs/src/content/examples/copy-to-clipboard/index.mdx +++ b/docs/src/content/examples/copy-to-clipboard/index.mdx @@ -1,10 +1,7 @@ --- id: copy-to-clipboard title: Copy to clipboard -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - clipboard - copy diff --git a/docs/src/content/examples/disabled-button-with-a-required-field/index.mdx b/docs/src/content/examples/disabled-button-with-a-required-field/index.mdx index ee961c2bc4..db920cbfb7 100644 --- a/docs/src/content/examples/disabled-button-with-a-required-field/index.mdx +++ b/docs/src/content/examples/disabled-button-with-a-required-field/index.mdx @@ -1,10 +1,7 @@ --- id: disabled-button-with-a-required-field title: Disabled button with a required field -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - button - form diff --git a/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/index.mdx b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/index.mdx index ba920ccf82..ab1bc725cb 100644 --- a/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/index.mdx +++ b/docs/src/content/examples/display-numbers-in-a-table-so-they-can-be-scanned-easily/index.mdx @@ -1,10 +1,8 @@ --- id: display-numbers-in-a-table-so-they-can-be-scanned-easily title: Display numbers in a table so they can be scanned easily -categories: - - content-layout -scale: task -userType: worker +size: section +productType: workspace tags: - table - numbers diff --git a/docs/src/content/examples/display-user-information/index.mdx b/docs/src/content/examples/display-user-information/index.mdx index 6fc54f492b..ba97c6141a 100644 --- a/docs/src/content/examples/display-user-information/index.mdx +++ b/docs/src/content/examples/display-user-information/index.mdx @@ -1,10 +1,8 @@ --- id: display-user-information title: Display user information -categories: - - content-layout -scale: task -userType: worker +size: section +productType: workspace tags: - container - user-info diff --git a/docs/src/content/examples/dynamically-add-an-item-to-a-dropdown-list/index.mdx b/docs/src/content/examples/dynamically-add-an-item-to-a-dropdown-list/index.mdx index 00d5cb5551..96f1f8d3d2 100644 --- a/docs/src/content/examples/dynamically-add-an-item-to-a-dropdown-list/index.mdx +++ b/docs/src/content/examples/dynamically-add-an-item-to-a-dropdown-list/index.mdx @@ -1,10 +1,7 @@ --- id: dynamically-add-an-item-to-a-dropdown-list title: Dynamically add an item to a dropdown list -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - dropdown - dynamic diff --git a/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/index.mdx b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/index.mdx index 2483250d66..faa2b79321 100644 --- a/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/index.mdx +++ b/docs/src/content/examples/dynamically-change-items-in-a-dropdown-list/index.mdx @@ -1,10 +1,7 @@ --- id: dynamically-change-items-in-a-dropdown-list title: Dynamically change items in a dropdown list -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - dropdown - dynamic diff --git a/docs/src/content/examples/401-error-page/angular.html b/docs/src/content/examples/error-pages/401/angular.html similarity index 100% rename from docs/src/content/examples/401-error-page/angular.html rename to docs/src/content/examples/error-pages/401/angular.html diff --git a/docs/src/content/examples/401-error-page/angular.ts b/docs/src/content/examples/error-pages/401/angular.ts similarity index 100% rename from docs/src/content/examples/401-error-page/angular.ts rename to docs/src/content/examples/error-pages/401/angular.ts diff --git a/docs/src/content/examples/401-error-page/react.tsx b/docs/src/content/examples/error-pages/401/react.tsx similarity index 100% rename from docs/src/content/examples/401-error-page/react.tsx rename to docs/src/content/examples/error-pages/401/react.tsx diff --git a/docs/src/content/examples/401-error-page/web-components.html b/docs/src/content/examples/error-pages/401/web-components.html similarity index 100% rename from docs/src/content/examples/401-error-page/web-components.html rename to docs/src/content/examples/error-pages/401/web-components.html diff --git a/docs/src/content/examples/404-error-page/angular.html b/docs/src/content/examples/error-pages/404/angular.html similarity index 100% rename from docs/src/content/examples/404-error-page/angular.html rename to docs/src/content/examples/error-pages/404/angular.html diff --git a/docs/src/content/examples/404-error-page/angular.ts b/docs/src/content/examples/error-pages/404/angular.ts similarity index 100% rename from docs/src/content/examples/404-error-page/angular.ts rename to docs/src/content/examples/error-pages/404/angular.ts diff --git a/docs/src/content/examples/404-error-page/react.tsx b/docs/src/content/examples/error-pages/404/react.tsx similarity index 100% rename from docs/src/content/examples/404-error-page/react.tsx rename to docs/src/content/examples/error-pages/404/react.tsx diff --git a/docs/src/content/examples/404-error-page/web-components.html b/docs/src/content/examples/error-pages/404/web-components.html similarity index 100% rename from docs/src/content/examples/404-error-page/web-components.html rename to docs/src/content/examples/error-pages/404/web-components.html diff --git a/docs/src/content/examples/500-error-page/angular.html b/docs/src/content/examples/error-pages/500/angular.html similarity index 100% rename from docs/src/content/examples/500-error-page/angular.html rename to docs/src/content/examples/error-pages/500/angular.html diff --git a/docs/src/content/examples/500-error-page/angular.ts b/docs/src/content/examples/error-pages/500/angular.ts similarity index 100% rename from docs/src/content/examples/500-error-page/angular.ts rename to docs/src/content/examples/error-pages/500/angular.ts diff --git a/docs/src/content/examples/500-error-page/react.tsx b/docs/src/content/examples/error-pages/500/react.tsx similarity index 100% rename from docs/src/content/examples/500-error-page/react.tsx rename to docs/src/content/examples/error-pages/500/react.tsx diff --git a/docs/src/content/examples/500-error-page/web-components.html b/docs/src/content/examples/error-pages/500/web-components.html similarity index 100% rename from docs/src/content/examples/500-error-page/web-components.html rename to docs/src/content/examples/error-pages/500/web-components.html diff --git a/docs/src/content/examples/error-pages/index.mdx b/docs/src/content/examples/error-pages/index.mdx new file mode 100644 index 0000000000..f63761dab3 --- /dev/null +++ b/docs/src/content/examples/error-pages/index.mdx @@ -0,0 +1,90 @@ +--- +id: error-pages +title: Error pages +size: page +description: Standard error screens for Government of Alberta services. Use when a user lands somewhere that is missing, forbidden, or broken so they understand what happened and what to do next. +previewImage: /thumbnails/error-pages-404.png +hideHero: true +components: + - page-block + - block + - text + - icon + - link + - button +tags: + - error + - error page + - "401" + - "404" + - "500" + - page not found + - unauthorized + - restricted access + - server error + - server problem + - page-structure +aliases: + - 401-error-page + - 404-error-page + - 500-error-page +status: published +--- + +import PreviewContainer from "../../../components/PreviewContainer.astro"; + +## Types of error pages + +### Restricted access (401) + +The user is not authorized, either because they need to sign in or because they lack the right permission. + + + +### Page not found (404) + +The page does not exist, usually because of a typo, a stale bookmark, or a deleted resource. + + + +### Server problem (500) + +A server-side error has interrupted the request, and there is nothing the user can do to fix it. + + + +## When to use + +Every service needs a story for the moments where something has gone wrong. These pages are the baseline. Each one is a small, self-contained page composition you drop into an existing service as a single route, no starter repo needed. Use them as the routes behind your router's catch-all outlets, or as the fallback view your outer error boundary renders when nothing else caught the failure. + +## Considerations + +- **Use plain language.** Explain what happened in one short sentence. "Page not found" beats "HTTP 404 resource unavailable". +- **Offer a way back.** A home link is the usual fallback. Add a contact link when the user may need help. +- **Keep the tone helpful, not accusatory.** Do not blame the user for the error, especially for 500-level failures the user could not have caused. +- **Avoid exposing technical detail** like raw error codes, stack traces, or correlation IDs. Log them instead. If support needs a correlation id, give the user only what is useful. +- **Do not render the service's navigation** on the error page. The error page is its own context. + +## How these pages are built + +Each error page is a composition of GoA components: `goa-page-block`, `goa-block`, `goa-text`, `goa-icon`, `goa-button`, and `goa-link` (on 401). A small amount of custom CSS covers the icon-in-circle treatment, accent bar, centred text, and icon scaling. Those are gaps the design system has not absorbed yet and are tracked for follow-up. + +Framework variants for React, Angular, and Web Components live alongside each preview route as sibling files. Click the React or Angular icon on a preview to open the folder on GitHub and copy the framework file you need. diff --git a/docs/src/content/examples/expand-or-collapse-part-of-a-form/index.mdx b/docs/src/content/examples/expand-or-collapse-part-of-a-form/index.mdx index 45de6c5213..1000f44979 100644 --- a/docs/src/content/examples/expand-or-collapse-part-of-a-form/index.mdx +++ b/docs/src/content/examples/expand-or-collapse-part-of-a-form/index.mdx @@ -1,10 +1,7 @@ --- id: expand-or-collapse-part-of-a-form title: Expand or collapse part of a form -categories: - - forms -scale: task -userType: both +size: section tags: - accordion - form diff --git a/docs/src/content/examples/filter-a-list-using-a-push-drawer/index.mdx b/docs/src/content/examples/filter-a-list-using-a-push-drawer/index.mdx index 849448de0b..bd47c8df1f 100644 --- a/docs/src/content/examples/filter-a-list-using-a-push-drawer/index.mdx +++ b/docs/src/content/examples/filter-a-list-using-a-push-drawer/index.mdx @@ -1,10 +1,8 @@ --- id: filter-a-list-using-a-push-drawer title: Filter a list using a push drawer -categories: - - content-layout -scale: task -userType: worker +size: section +productType: workspace tags: - push-drawer - filters diff --git a/docs/src/content/examples/filter-data-in-a-table/index.mdx b/docs/src/content/examples/filter-data-in-a-table/index.mdx index eba9122846..87c18fc8c5 100644 --- a/docs/src/content/examples/filter-data-in-a-table/index.mdx +++ b/docs/src/content/examples/filter-data-in-a-table/index.mdx @@ -1,10 +1,8 @@ --- id: filter-data-in-a-table title: Filter data in a table -categories: - - structure-and-navigation -scale: task -userType: worker +size: section +productType: workspace tags: - table - filter diff --git a/docs/src/content/examples/form-stepper-with-controlled-navigation/index.mdx b/docs/src/content/examples/form-stepper-with-controlled-navigation/index.mdx index c4fbd42920..828af8de86 100644 --- a/docs/src/content/examples/form-stepper-with-controlled-navigation/index.mdx +++ b/docs/src/content/examples/form-stepper-with-controlled-navigation/index.mdx @@ -1,10 +1,7 @@ --- id: form-stepper-with-controlled-navigation title: Form stepper with controlled navigation -categories: - - forms -scale: task -userType: both +size: section tags: - stepper - form @@ -20,6 +17,7 @@ components: - skeleton - spacer status: published +hidden: true previewImage: /images/examples/form-stepper-with-controlled-navigation.webp --- diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-a/index.mdx b/docs/src/content/examples/give-more-information-before-asking-a-question-a/index.mdx deleted file mode 100644 index d8148b2215..0000000000 --- a/docs/src/content/examples/give-more-information-before-asking-a-question-a/index.mdx +++ /dev/null @@ -1,41 +0,0 @@ ---- -id: give-more-information-before-asking-a-question-a -title: Give more information before asking a question (a) -categories: - - forms -scale: task -userType: citizen -tags: - - form - - question - - context - - radio - - citizen-facing -components: - - form-item - - radio-group - - radio-item - - button -figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/%E2%9D%96-Component-library-%7C-DDD?node-id=63353-114502 -status: published -previewImage: /images/examples/give-more-information-before-asking-a-question-a.webp ---- - -Provide explanatory context before asking a question to help users understand what is being asked. - -## When to use - -Use this pattern when: - -- The question requires domain knowledge to answer correctly -- Terms need clarification for users unfamiliar with the subject -- Providing context will reduce confusion and incorrect answers -- Building citizen-facing forms where accessibility of information is important - -## Considerations - -- Place context information before the question, not after -- Use clear, plain language that citizens can understand -- Suggest where users can get additional help if needed -- Keep explanatory text focused and relevant to the question -- Use appropriate heading hierarchy for screen reader accessibility diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-b/index.mdx b/docs/src/content/examples/give-more-information-before-asking-a-question-b/index.mdx deleted file mode 100644 index 5bac4b1a12..0000000000 --- a/docs/src/content/examples/give-more-information-before-asking-a-question-b/index.mdx +++ /dev/null @@ -1,42 +0,0 @@ ---- -id: give-more-information-before-asking-a-question-b -title: Give more information before asking a question (b) -categories: - - forms -scale: task -userType: citizen -tags: - - form - - text-area - - question - - context - - details - - citizen-facing -components: - - text-area - - form-item - - details - - button - - button-group -figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/%E2%9D%96-Component-library-%7C-DDD?node-id=63353-124277 -status: published -previewImage: /images/examples/give-more-information-before-asking-a-question-b.webp ---- - -Provide context and guidance before a long-answer text field to help users provide relevant information. - -## When to use - -Use this pattern when: - -- Asking open-ended questions that require detailed responses -- Users may not know what information is most helpful to provide -- You want to encourage more useful and complete answers -- Building citizen-facing forms with benefit inquiries or support requests - -## Considerations - -- Explain the purpose of the question briefly -- Use a Details component to provide additional guidance without cluttering the form -- Set appropriate character limits with `maxCount` and `countBy` props -- Keep instructions focused on what will help process their request diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/index.mdx b/docs/src/content/examples/group-related-questions-together-on-a-question-page/index.mdx deleted file mode 100644 index 2ef206a635..0000000000 --- a/docs/src/content/examples/group-related-questions-together-on-a-question-page/index.mdx +++ /dev/null @@ -1,38 +0,0 @@ ---- -id: group-related-questions-together-on-a-question-page -title: Group related questions together on a question page -categories: - - forms -scale: page -userType: citizen -tags: - - forms - - address - - question-page -components: - - form-item - - input - - dropdown - - dropdown-item - - button -status: published -previewImage: /images/examples/group-related-questions-together-on-a-question-page.webp ---- - -Group related form fields together on a single page to collect address information from users, making it easier to complete logically connected questions at once. - -## When to use - -Use this pattern when: - -- Collecting address or contact information -- Form fields are logically related and should be completed together -- Users need context between related fields -- Following a question page pattern in a multi-step form - -## Considerations - -- Use clear, descriptive labels for each form field -- Include a back link for navigation in multi-step forms -- Consider adding a section title and subtitle to provide context -- Use appropriate input widths based on expected content length diff --git a/docs/src/content/examples/header-with-navigation/index.mdx b/docs/src/content/examples/header-with-navigation/index.mdx index 9e74923314..fab1cfb61e 100644 --- a/docs/src/content/examples/header-with-navigation/index.mdx +++ b/docs/src/content/examples/header-with-navigation/index.mdx @@ -1,10 +1,7 @@ --- id: header-with-navigation title: Header with navigation -categories: - - structure-and-navigation -scale: task -userType: both +size: section tags: - header - navigation diff --git a/docs/src/content/examples/hero-banner-with-actions/index.mdx b/docs/src/content/examples/hero-banner-with-actions/index.mdx index 7ffbec3a29..198631f2cc 100644 --- a/docs/src/content/examples/hero-banner-with-actions/index.mdx +++ b/docs/src/content/examples/hero-banner-with-actions/index.mdx @@ -1,10 +1,7 @@ --- id: hero-banner-with-actions title: Hero banner with actions -categories: - - content-layout -scale: task -userType: both +size: section tags: - hero - banner diff --git a/docs/src/content/examples/hide-and-show-many-sections-of-information/index.mdx b/docs/src/content/examples/hide-and-show-many-sections-of-information/index.mdx index 38f18d8ec3..c8711b025d 100644 --- a/docs/src/content/examples/hide-and-show-many-sections-of-information/index.mdx +++ b/docs/src/content/examples/hide-and-show-many-sections-of-information/index.mdx @@ -1,10 +1,7 @@ --- id: hide-and-show-many-sections-of-information title: Hide and show many sections of information -categories: - - content-layout -scale: task -userType: both +size: section tags: - accordion - expand diff --git a/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/index.mdx b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/index.mdx index 0780b6cc89..8f62fd102a 100644 --- a/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/index.mdx +++ b/docs/src/content/examples/include-a-link-in-the-helper-text-of-an-option/index.mdx @@ -1,10 +1,7 @@ --- id: include-a-link-in-the-helper-text-of-an-option title: Include a link in the helper text of an option -categories: - - forms -scale: interaction -userType: both +size: interaction tags: - checkbox - helper-text diff --git a/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/index.mdx b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/index.mdx index a11ec10c91..bc7279bf16 100644 --- a/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/index.mdx +++ b/docs/src/content/examples/include-descriptions-for-items-in-a-checkbox-list/index.mdx @@ -1,10 +1,7 @@ --- id: include-descriptions-for-items-in-a-checkbox-list title: Include descriptions for items in a checkbox list -categories: - - forms -scale: task -userType: both +size: interaction tags: - radio - descriptions diff --git a/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/index.mdx b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/index.mdx index 3ab774ec01..9bde96ed10 100644 --- a/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/index.mdx +++ b/docs/src/content/examples/link-the-user-to-give-feedback-to-the-service/index.mdx @@ -1,10 +1,7 @@ --- id: link-the-user-to-give-feedback-to-the-service title: Link the user to give feedback to the service -categories: - - feedback-and-alerts -scale: interaction -userType: citizen +size: interaction tags: - feedback - microsite-header diff --git a/docs/src/content/examples/link-to-an-external-page/index.mdx b/docs/src/content/examples/link-to-an-external-page/index.mdx index e4d40ddb4a..aae56271e6 100644 --- a/docs/src/content/examples/link-to-an-external-page/index.mdx +++ b/docs/src/content/examples/link-to-an-external-page/index.mdx @@ -1,10 +1,7 @@ --- id: link-to-an-external-page title: Link to an external page -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - link - external diff --git a/docs/src/content/examples/notify-the-user-of-a-future-service-outage/index.mdx b/docs/src/content/examples/notify-the-user-of-a-future-service-outage/index.mdx index caca42817f..bc55fd54ca 100644 --- a/docs/src/content/examples/notify-the-user-of-a-future-service-outage/index.mdx +++ b/docs/src/content/examples/notify-the-user-of-a-future-service-outage/index.mdx @@ -1,10 +1,7 @@ --- id: notify-the-user-of-a-future-service-outage title: Notify the user of a future service outage -categories: - - feedback-and-alerts -scale: task -userType: both +size: interaction tags: - notification - maintenance diff --git a/docs/src/content/examples/public-form/angular.html b/docs/src/content/examples/public-form/angular.html deleted file mode 100644 index 1849c5cc42..0000000000 --- a/docs/src/content/examples/public-form/angular.html +++ /dev/null @@ -1,45 +0,0 @@ - - - Primary users: citizens, public, external

- You are designing a public service for citizens. It should be designed to be as simple - and intuitive as possible, while ensuring citizens can make complete and informed - decisions for themselves using the service. -

- There is an emphasis on an accessible experience with a low cognitive load for users - who use the service infrequently. -
-
- -Pages - - -

- 1. Start page - - This is the starting point for a citizen to begin your form from within your service - or from Alberta.ca. - - - 2. Task list page (optional) - - Outline the entire process for the user and help them through the process by - breaking down an experience into individual tasks. - - - 3. Question pages - - Ask a user a question or a small set of related questions. - - - 4. Review page - - Let users check answers before submitting information to a service. - - - 5. Results page - - Let users know that they've completed a form, application, or task and tell them - what to do next. - -
- diff --git a/docs/src/content/examples/public-form/angular.ts b/docs/src/content/examples/public-form/angular.ts deleted file mode 100644 index fb2b7a40ae..0000000000 --- a/docs/src/content/examples/public-form/angular.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Component } from "@angular/core"; - -@Component({ - selector: "app-public-form", - templateUrl: "./angular.html", -}) -export class PublicFormComponent {} diff --git a/docs/src/content/examples/public-form/index.mdx b/docs/src/content/examples/public-form/index.mdx deleted file mode 100644 index 969e089442..0000000000 --- a/docs/src/content/examples/public-form/index.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -id: public-form -title: Public form -categories: - - forms -scale: product -userType: citizen -tags: - - form - - public - - citizen - - pattern -components: [] -status: published -previewImage: /images/examples/public-form.webp ---- - -The public form pattern provides a structure for citizen-facing form experiences, emphasizing simplicity, accessibility, and low cognitive load. - -## When to use - -Use this pattern when: - -- Designing a public service for citizens -- Building forms that should be simple and intuitive -- Users need to make informed decisions while completing the form -- The service should accommodate users who use it infrequently - -## Considerations - -- Follow the "one idea per page" principle to reduce cognitive load -- Break complex forms into multiple pages with single questions -- Use task list pages for longer processes with multiple sections -- Consider using simple progress indicators rather than horizontal steppers -- Ensure all form elements meet WCAG 2.2 AA accessibility standards diff --git a/docs/src/content/examples/public-form/react.tsx b/docs/src/content/examples/public-form/react.tsx deleted file mode 100644 index bc97714020..0000000000 --- a/docs/src/content/examples/public-form/react.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { GoabDetails, GoabGrid, GoabText } from "@abgov/react-components"; - -export function PublicForm() { - return ( - <> - - - Primary users: citizens, public, external -
-
- You are designing a public service for citizens. It should be designed to be as - simple and intuitive as possible, while ensuring citizens can make complete and - informed decisions for themselves using the service. -
-
- There is an emphasis on an accessible experience with a low cognitive load for - users who use the service infrequently. -
-
- - - Pages - - - -
- - 1. Start page - - - This is the starting point for a citizen to begin your form from within your - service or from Alberta.ca. - - - - 2. Task list page (optional) - - - Outline the entire process for the user and help them through the process by - breaking down an experience into individual tasks. - - - - 3. Question pages - - - Ask a user a question or a small set of related questions. - - - - 4. Review page - - - Let users check answers before submitting information to a service. - - - - 5. Results page - - - Let users know that they've completed a form, application, or task and tell - them what to do next. - -
-
- - ); -} diff --git a/docs/src/content/examples/public-form/web-components.html b/docs/src/content/examples/public-form/web-components.html deleted file mode 100644 index fa147357d0..0000000000 --- a/docs/src/content/examples/public-form/web-components.html +++ /dev/null @@ -1,45 +0,0 @@ - - - Primary users: citizens, public, external

- You are designing a public service for citizens. It should be designed to be as simple - and intuitive as possible, while ensuring citizens can make complete and informed - decisions for themselves using the service. -

- There is an emphasis on an accessible experience with a low cognitive load for users - who use the service infrequently. -
-
- -Pages - - -
- 1. Start page - - This is the starting point for a citizen to begin your form from within your service - or from Alberta.ca. - - - 2. Task list page (optional) - - Outline the entire process for the user and help them through the process by - breaking down an experience into individual tasks. - - - 3. Question pages - - Ask a user a question or a small set of related questions. - - - 4. Review page - - Let users check answers before submitting information to a service. - - - 5. Results page - - Let users know that they've completed a form, application, or task and tell them - what to do next. - -
-
diff --git a/docs/src/content/examples/question-page/index.mdx b/docs/src/content/examples/question-page/index.mdx index d23077989a..ab95516c23 100644 --- a/docs/src/content/examples/question-page/index.mdx +++ b/docs/src/content/examples/question-page/index.mdx @@ -1,39 +1,172 @@ --- id: question-page title: Question page -categories: - - forms -scale: page -userType: citizen +size: page +productType: public-form +description: "A question page presents one focused step in a multi-step form. Several variants adapt the shape: section titles, progress indicators, supporting context, expandable help, and grouped fields." tags: - forms - question - wizard - one-thing-per-page + - public-form + - section-title + - progress + - context + - help + - details + - grouped-fields + - address components: - form-item - input + - text-area + - radio-group + - radio-item + - dropdown + - dropdown-item + - details + - block - button - button-group +aliases: + - ask-a-user-one-question-at-a-time + - give-more-information-before-asking-a-question-a + - give-more-information-before-asking-a-question-b + - show-more-information-to-help-answer-a-question + - show-a-list-to-help-answer-a-question + - show-a-section-title-on-a-question-page + - show-a-simple-progress-indicator-on-a-question-page + - show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions + - group-related-questions-together-on-a-question-page status: published -previewImage: /images/examples/question-page.webp +previewImage: /images/examples/question-page.png +hideHero: true --- -A question page pattern that presents one question at a time to help users focus, reduce cognitive load, and navigate complex forms more easily. +import PreviewContainer from "../../../components/PreviewContainer.astro"; + +## Types of question pages + +### Ask one question at a time + +The default question page. One idea per page reduces cognitive load and keeps users moving through the flow. + + + +- Lead with a clear, plain-language question. +- Use a large label size to make the question prominent. +- Provide help text when the question could be ambiguous. +- Pair a primary action button with a back link. + +### Show a section title + +Add a section title above the question to tell users which part of the form they are completing. Useful in multi-section forms divided into logical groups like "Personal information" or "Employment history." + + + +- Use a subdued text color so the section title sits above the question without competing with it. +- Keep the title concise and descriptive. +- Maintain consistent spacing between back link, section title, and question across the form. + +### Show a progress indicator + +Show progress to help users understand how far they are through the form. Use "Question X of Y" for single-question pages, or "Step X of Y" when grouping multiple related questions into sections. + + + +- Display progress consistently across the form ("Question X of Y" for single-question pages, "Step X of Y" for multi-question sections). +- Use a subdued text color so the indicator sits above the question. +- Position above the question, below the back link. + +For step-based progress when grouping multiple questions into sections, see the [progress-indicator-multi variant on GitHub](https://github.com/GovAlta/ui-components/tree/dev/docs/src/content/examples/question-page/variants/progress-indicator-multi). + +### Give background information before asking + +Provide explanatory context before a question when the question requires domain knowledge or terms that may need clarification. + + + +- Place context information before the question, not after. +- Use plain language citizens can understand. +- Suggest where users can get additional help if needed. + +For an open-ended question with a long-answer textarea, the same pattern applies with a Details component for additional guidance. See the [background-textarea variant on GitHub](https://github.com/GovAlta/ui-components/tree/dev/docs/src/content/examples/question-page/variants/background-textarea). + +### Reveal more information to help answer + +Use the Details component to provide optional context that explains why a question is being asked, or that lists examples of qualifying items. The expandable shape keeps the form uncluttered for users who do not need the help. + + + +- Place the Details component after the question input. +- Phrase the Details heading as a question (e.g. "Why are we asking this question?") so users know it provides clarification. +- Keep the expanded content concise, scannable, and easy to act on. + +When the help content is a list of examples (what to include, what to exclude), structure the expanded content with clear headings. See the [help-list variant on GitHub](https://github.com/GovAlta/ui-components/tree/dev/docs/src/content/examples/question-page/variants/help-list). + +### Group related questions on one page + +When fields are tightly related and harder to answer in isolation, group them on one page. The typical case is collecting an address, where street, town, province, and postal code naturally belong together. + + + +- Group fields only when the whole group answers one logical question. Do not group unrelated questions just to fit them on one page. +- Use clear, descriptive labels per field. +- Add a section title above the group to provide context. +- Use input widths appropriate to the expected content (postal code narrower than street). ## When to use Use this pattern when: -- Building multi-step forms or wizards -- Asking users for information that requires focused attention -- The form has branching logic based on user responses -- You want to reduce cognitive load and errors +- Building multi-step forms or wizards where users complete one decision at a time +- Asking for information that requires focused attention or careful consideration +- The form has branching logic based on previous answers +- You want to reduce errors and improve mobile and accessibility outcomes ## Considerations -- Each page should contain one idea: one question, one decision, or one piece of information -- Progress indicators are optional - test without one first -- The pattern helps with mobile responsiveness and accessibility -- Enables automatic saving and better error handling +- Each page should contain one idea: one question, one decision, or one logically grouped set of fields +- Include a back link so users can revise previous answers +- Use a large label size to make the question prominent +- Provide help text when wording could be ambiguous +- A clear primary action progresses the user; a back link returns them +- Progress indicators are optional. Test the form without one before adding one. - Consider adaptive questioning where subsequent questions depend on previous answers diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-a/angular.html b/docs/src/content/examples/question-page/variants/background-radio/angular.html similarity index 100% rename from docs/src/content/examples/give-more-information-before-asking-a-question-a/angular.html rename to docs/src/content/examples/question-page/variants/background-radio/angular.html diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-a/angular.ts b/docs/src/content/examples/question-page/variants/background-radio/angular.ts similarity index 100% rename from docs/src/content/examples/give-more-information-before-asking-a-question-a/angular.ts rename to docs/src/content/examples/question-page/variants/background-radio/angular.ts diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-a/react.tsx b/docs/src/content/examples/question-page/variants/background-radio/react.tsx similarity index 100% rename from docs/src/content/examples/give-more-information-before-asking-a-question-a/react.tsx rename to docs/src/content/examples/question-page/variants/background-radio/react.tsx diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-a/web-components.html b/docs/src/content/examples/question-page/variants/background-radio/web-components.html similarity index 100% rename from docs/src/content/examples/give-more-information-before-asking-a-question-a/web-components.html rename to docs/src/content/examples/question-page/variants/background-radio/web-components.html diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-b/angular.html b/docs/src/content/examples/question-page/variants/background-textarea/angular.html similarity index 100% rename from docs/src/content/examples/give-more-information-before-asking-a-question-b/angular.html rename to docs/src/content/examples/question-page/variants/background-textarea/angular.html diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-b/angular.ts b/docs/src/content/examples/question-page/variants/background-textarea/angular.ts similarity index 100% rename from docs/src/content/examples/give-more-information-before-asking-a-question-b/angular.ts rename to docs/src/content/examples/question-page/variants/background-textarea/angular.ts diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-b/react.tsx b/docs/src/content/examples/question-page/variants/background-textarea/react.tsx similarity index 100% rename from docs/src/content/examples/give-more-information-before-asking-a-question-b/react.tsx rename to docs/src/content/examples/question-page/variants/background-textarea/react.tsx diff --git a/docs/src/content/examples/give-more-information-before-asking-a-question-b/web-components.html b/docs/src/content/examples/question-page/variants/background-textarea/web-components.html similarity index 100% rename from docs/src/content/examples/give-more-information-before-asking-a-question-b/web-components.html rename to docs/src/content/examples/question-page/variants/background-textarea/web-components.html diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.html b/docs/src/content/examples/question-page/variants/grouped/angular.html similarity index 100% rename from docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.html rename to docs/src/content/examples/question-page/variants/grouped/angular.html diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.ts b/docs/src/content/examples/question-page/variants/grouped/angular.ts similarity index 100% rename from docs/src/content/examples/group-related-questions-together-on-a-question-page/angular.ts rename to docs/src/content/examples/question-page/variants/grouped/angular.ts diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/react.tsx b/docs/src/content/examples/question-page/variants/grouped/react.tsx similarity index 100% rename from docs/src/content/examples/group-related-questions-together-on-a-question-page/react.tsx rename to docs/src/content/examples/question-page/variants/grouped/react.tsx diff --git a/docs/src/content/examples/group-related-questions-together-on-a-question-page/web-components.html b/docs/src/content/examples/question-page/variants/grouped/web-components.html similarity index 100% rename from docs/src/content/examples/group-related-questions-together-on-a-question-page/web-components.html rename to docs/src/content/examples/question-page/variants/grouped/web-components.html diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.html b/docs/src/content/examples/question-page/variants/help-details/angular.html similarity index 100% rename from docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.html rename to docs/src/content/examples/question-page/variants/help-details/angular.html diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.ts b/docs/src/content/examples/question-page/variants/help-details/angular.ts similarity index 100% rename from docs/src/content/examples/show-more-information-to-help-answer-a-question/angular.ts rename to docs/src/content/examples/question-page/variants/help-details/angular.ts diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/react.tsx b/docs/src/content/examples/question-page/variants/help-details/react.tsx similarity index 100% rename from docs/src/content/examples/show-more-information-to-help-answer-a-question/react.tsx rename to docs/src/content/examples/question-page/variants/help-details/react.tsx diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/web-components.html b/docs/src/content/examples/question-page/variants/help-details/web-components.html similarity index 100% rename from docs/src/content/examples/show-more-information-to-help-answer-a-question/web-components.html rename to docs/src/content/examples/question-page/variants/help-details/web-components.html diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.html b/docs/src/content/examples/question-page/variants/help-list/angular.html similarity index 100% rename from docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.html rename to docs/src/content/examples/question-page/variants/help-list/angular.html diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.ts b/docs/src/content/examples/question-page/variants/help-list/angular.ts similarity index 100% rename from docs/src/content/examples/show-a-list-to-help-answer-a-question/angular.ts rename to docs/src/content/examples/question-page/variants/help-list/angular.ts diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/react.tsx b/docs/src/content/examples/question-page/variants/help-list/react.tsx similarity index 100% rename from docs/src/content/examples/show-a-list-to-help-answer-a-question/react.tsx rename to docs/src/content/examples/question-page/variants/help-list/react.tsx diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/web-components.html b/docs/src/content/examples/question-page/variants/help-list/web-components.html similarity index 100% rename from docs/src/content/examples/show-a-list-to-help-answer-a-question/web-components.html rename to docs/src/content/examples/question-page/variants/help-list/web-components.html diff --git a/docs/src/content/examples/question-page/angular.html b/docs/src/content/examples/question-page/variants/one-question/angular.html similarity index 100% rename from docs/src/content/examples/question-page/angular.html rename to docs/src/content/examples/question-page/variants/one-question/angular.html diff --git a/docs/src/content/examples/question-page/angular.ts b/docs/src/content/examples/question-page/variants/one-question/angular.ts similarity index 100% rename from docs/src/content/examples/question-page/angular.ts rename to docs/src/content/examples/question-page/variants/one-question/angular.ts diff --git a/docs/src/content/examples/question-page/react.tsx b/docs/src/content/examples/question-page/variants/one-question/react.tsx similarity index 100% rename from docs/src/content/examples/question-page/react.tsx rename to docs/src/content/examples/question-page/variants/one-question/react.tsx diff --git a/docs/src/content/examples/question-page/web-components.html b/docs/src/content/examples/question-page/variants/one-question/web-components.html similarity index 100% rename from docs/src/content/examples/question-page/web-components.html rename to docs/src/content/examples/question-page/variants/one-question/web-components.html diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.html b/docs/src/content/examples/question-page/variants/progress-indicator-multi/angular.html similarity index 100% rename from docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.html rename to docs/src/content/examples/question-page/variants/progress-indicator-multi/angular.html diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.ts b/docs/src/content/examples/question-page/variants/progress-indicator-multi/angular.ts similarity index 100% rename from docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/angular.ts rename to docs/src/content/examples/question-page/variants/progress-indicator-multi/angular.ts diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/react.tsx b/docs/src/content/examples/question-page/variants/progress-indicator-multi/react.tsx similarity index 100% rename from docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/react.tsx rename to docs/src/content/examples/question-page/variants/progress-indicator-multi/react.tsx diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/web-components.html b/docs/src/content/examples/question-page/variants/progress-indicator-multi/web-components.html similarity index 100% rename from docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/web-components.html rename to docs/src/content/examples/question-page/variants/progress-indicator-multi/web-components.html diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.html b/docs/src/content/examples/question-page/variants/progress-indicator/angular.html similarity index 100% rename from docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.html rename to docs/src/content/examples/question-page/variants/progress-indicator/angular.html diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.ts b/docs/src/content/examples/question-page/variants/progress-indicator/angular.ts similarity index 100% rename from docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/angular.ts rename to docs/src/content/examples/question-page/variants/progress-indicator/angular.ts diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/react.tsx b/docs/src/content/examples/question-page/variants/progress-indicator/react.tsx similarity index 100% rename from docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/react.tsx rename to docs/src/content/examples/question-page/variants/progress-indicator/react.tsx diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/web-components.html b/docs/src/content/examples/question-page/variants/progress-indicator/web-components.html similarity index 100% rename from docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/web-components.html rename to docs/src/content/examples/question-page/variants/progress-indicator/web-components.html diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/angular.html b/docs/src/content/examples/question-page/variants/section-title/angular.html similarity index 100% rename from docs/src/content/examples/show-a-section-title-on-a-question-page/angular.html rename to docs/src/content/examples/question-page/variants/section-title/angular.html diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/angular.ts b/docs/src/content/examples/question-page/variants/section-title/angular.ts similarity index 100% rename from docs/src/content/examples/show-a-section-title-on-a-question-page/angular.ts rename to docs/src/content/examples/question-page/variants/section-title/angular.ts diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/react.tsx b/docs/src/content/examples/question-page/variants/section-title/react.tsx similarity index 100% rename from docs/src/content/examples/show-a-section-title-on-a-question-page/react.tsx rename to docs/src/content/examples/question-page/variants/section-title/react.tsx diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/web-components.html b/docs/src/content/examples/question-page/variants/section-title/web-components.html similarity index 100% rename from docs/src/content/examples/show-a-section-title-on-a-question-page/web-components.html rename to docs/src/content/examples/question-page/variants/section-title/web-components.html diff --git a/docs/src/content/examples/remove-a-filter/index.mdx b/docs/src/content/examples/remove-a-filter/index.mdx index c1e7603a90..7b8f0e3f21 100644 --- a/docs/src/content/examples/remove-a-filter/index.mdx +++ b/docs/src/content/examples/remove-a-filter/index.mdx @@ -1,10 +1,7 @@ --- id: remove-a-filter title: Remove a filter -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - filtering - chips diff --git a/docs/src/content/examples/require-user-action-before-continuing/index.mdx b/docs/src/content/examples/require-user-action-before-continuing/index.mdx index 432bbf909a..4ca615f207 100644 --- a/docs/src/content/examples/require-user-action-before-continuing/index.mdx +++ b/docs/src/content/examples/require-user-action-before-continuing/index.mdx @@ -1,10 +1,7 @@ --- id: require-user-action-before-continuing title: Require user action before continuing -categories: - - forms -scale: task -userType: both +size: interaction tags: - modal - confirmation diff --git a/docs/src/content/examples/reset-date-picker-field/index.mdx b/docs/src/content/examples/reset-date-picker-field/index.mdx index c8e25f1b3d..cc0efda327 100644 --- a/docs/src/content/examples/reset-date-picker-field/index.mdx +++ b/docs/src/content/examples/reset-date-picker-field/index.mdx @@ -1,10 +1,7 @@ --- id: reset-date-picker-field title: Reset date picker field -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - date-picker - form diff --git a/docs/src/content/examples/result-page/index.mdx b/docs/src/content/examples/result-page/index.mdx index 7f4187c23d..32aff76624 100644 --- a/docs/src/content/examples/result-page/index.mdx +++ b/docs/src/content/examples/result-page/index.mdx @@ -1,38 +1,42 @@ --- id: result-page title: Result page -categories: - - forms -scale: page -userType: citizen +size: page +productType: public-form +description: A result page shown after a citizen has submitted a form, application, or task. Confirms success, explains what happens next, and points the user at any follow-up actions. tags: - confirmation - success - completion - forms + - application components: - block - callout + - button + - button-group +aliases: + - confirm-that-an-application-was-submitted status: published -previewImage: /images/examples/result-page.webp +previewImage: /images/examples/result-page.png --- -A result page shown after form submission to confirm success, provide next steps, and offer relevant contact information. +## When to use a result page -## When to use +Use a result page when a user has submitted a form, application, or task, and there is a result to show them. -Use this pattern when: +## What content to include -- A user has submitted a form or application -- You need to confirm successful completion of a process -- There is important follow-up information to communicate -- Users need reference numbers or confirmation details +- details of what happens next, and when +- a reference number, if applicable +- a link to save a record of the confirmation, for example as a PDF +- a link to give feedback on the service +- contact details for the service +- links to information or services that users are likely to need next ## Considerations -- Include a reference number if applicable -- Clearly explain what happens next and when -- Provide a way to save or print the confirmation -- Include service contact information for questions -- Link to feedback forms and related services -- Keep the success message clear and reassuring +- Use a success callout to clearly indicate the submission was received +- Mention where a confirmation email will be sent, if applicable +- Keep the success message clear, reassuring, and short +- Surface contact information so users can reach out if something is wrong diff --git a/docs/src/content/examples/reveal-input-based-on-a-selection/index.mdx b/docs/src/content/examples/reveal-input-based-on-a-selection/index.mdx index 3db92fe75c..6ea6be06c8 100644 --- a/docs/src/content/examples/reveal-input-based-on-a-selection/index.mdx +++ b/docs/src/content/examples/reveal-input-based-on-a-selection/index.mdx @@ -1,10 +1,7 @@ --- id: reveal-input-based-on-a-selection title: Reveal input based on a selection -categories: - - forms -scale: task -userType: both +size: interaction tags: - conditional - reveal diff --git a/docs/src/content/examples/review-and-action/index.mdx b/docs/src/content/examples/review-and-action/index.mdx index 10644516e9..6deea2648f 100644 --- a/docs/src/content/examples/review-and-action/index.mdx +++ b/docs/src/content/examples/review-and-action/index.mdx @@ -1,10 +1,8 @@ --- id: review-and-action title: Review and action -categories: - - structure-and-navigation -scale: task -userType: worker +size: section +productType: workspace tags: - review - action diff --git a/docs/src/content/examples/review-page/index.mdx b/docs/src/content/examples/review-page/index.mdx index e17cdd3ef5..46cf94c768 100644 --- a/docs/src/content/examples/review-page/index.mdx +++ b/docs/src/content/examples/review-page/index.mdx @@ -1,10 +1,9 @@ --- id: review-page title: Review page -categories: - - forms -scale: page -userType: citizen +size: page +productType: public-form +description: A review page lets a user check their answers at the end of a form or section before submitting. Each answer has a "change" link so the user can revise without starting over. tags: - review - check-answers @@ -15,25 +14,19 @@ components: - button - button-group status: published -previewImage: /images/examples/review-page.webp +previewImage: /images/examples/review-page.png --- -A review page where users can check their answers before submitting a form, with options to change individual responses. +## When to use a review page + +Review and submit your answers at the end of a form or section. -## When to use +When designing a very large transaction with multiple sections, it may help to include a check-answers page at the end of each section. -Use this pattern when: +## Let users go back and change their answers -- Users need to review their form answers before submission -- At the end of a multi-step form or wizard -- Before finalizing applications or important submissions -- When accuracy of submitted information is critical +Provide a "change" link next to each section so that users can add or change the information they are submitting. -## Considerations +If you have questions that are optional, let users know that they have skipped them without giving an answer by showing their response as "Not provided". -- Display all answered questions with current values -- Provide "Change" links for each answer -- Show "Not provided" for skipped optional questions -- Include visually hidden text in change links for accessibility -- Consider grouping related answers under section headings -- For large forms, consider review pages at the end of each section +Include the full question name again in the change button as visually hidden text so that the screen reader reads out "change [question]" instead of just "change". This gives context to a user using assistive technologies while keeping the link simple for most users. diff --git a/docs/src/content/examples/search/index.mdx b/docs/src/content/examples/search/index.mdx index 8b677bebb9..ae597aed14 100644 --- a/docs/src/content/examples/search/index.mdx +++ b/docs/src/content/examples/search/index.mdx @@ -1,10 +1,7 @@ --- id: search title: Search -categories: - - inputs-and-actions -scale: task -userType: both +size: interaction tags: - search - input diff --git a/docs/src/content/examples/select-one-or-more-from-a-list-of-options/index.mdx b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/index.mdx index cda106545a..f37710f3ad 100644 --- a/docs/src/content/examples/select-one-or-more-from-a-list-of-options/index.mdx +++ b/docs/src/content/examples/select-one-or-more-from-a-list-of-options/index.mdx @@ -1,10 +1,7 @@ --- id: select-one-or-more-from-a-list-of-options title: Select one or more from a list of options -categories: - - forms -scale: task -userType: both +size: interaction tags: - checkbox - selection diff --git a/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/index.mdx b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/index.mdx index 80a1aa605a..8945d9bf77 100644 --- a/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/index.mdx +++ b/docs/src/content/examples/set-a-max-width-on-a-long-radio-item/index.mdx @@ -1,10 +1,7 @@ --- id: set-a-max-width-on-a-long-radio-item title: Set a max width on a long radio item -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - radio - forms diff --git a/docs/src/content/examples/set-a-specific-tab-to-be-active/index.mdx b/docs/src/content/examples/set-a-specific-tab-to-be-active/index.mdx index cfe782b02a..24f7126376 100644 --- a/docs/src/content/examples/set-a-specific-tab-to-be-active/index.mdx +++ b/docs/src/content/examples/set-a-specific-tab-to-be-active/index.mdx @@ -1,10 +1,7 @@ --- id: set-a-specific-tab-to-be-active title: Set a specific tab to be active -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - tabs - navigation diff --git a/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/index.mdx b/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/index.mdx index bb5d6c4ef9..080a79efc8 100644 --- a/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/index.mdx +++ b/docs/src/content/examples/set-the-status-of-step-on-a-form-stepper/index.mdx @@ -1,10 +1,7 @@ --- id: set-the-status-of-step-on-a-form-stepper title: Set the status of step on a form stepper -categories: - - inputs-and-actions -scale: task -userType: both +size: interaction tags: - forms - stepper @@ -16,6 +13,7 @@ components: - pages - button status: published +hidden: true previewImage: /images/examples/set-the-status-of-step-on-a-form-stepper.webp --- diff --git a/docs/src/content/examples/show-a-label-on-an-icon-only-button/index.mdx b/docs/src/content/examples/show-a-label-on-an-icon-only-button/index.mdx index 28ebc57a57..ffba97c535 100644 --- a/docs/src/content/examples/show-a-label-on-an-icon-only-button/index.mdx +++ b/docs/src/content/examples/show-a-label-on-an-icon-only-button/index.mdx @@ -1,10 +1,7 @@ --- id: show-a-label-on-an-icon-only-button title: Show a label on an icon only button -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - buttons - icons diff --git a/docs/src/content/examples/show-a-list-to-help-answer-a-question/index.mdx b/docs/src/content/examples/show-a-list-to-help-answer-a-question/index.mdx deleted file mode 100644 index 08dc3bfd31..0000000000 --- a/docs/src/content/examples/show-a-list-to-help-answer-a-question/index.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: show-a-list-to-help-answer-a-question -title: Show a list to help answer a question -categories: - - forms -scale: task -userType: citizen -tags: - - forms - - details - - guidance - - help -components: - - form-item - - radio-group - - radio-item - - details - - block -status: published -previewImage: /images/examples/show-a-list-to-help-answer-a-question.webp ---- - -Show a list to help answer a question using an expandable details component. - -## When to use - -Use this pattern when: - -- Users need clarification about what items qualify for a question -- You want to provide examples of what to include or exclude -- The guidance content would clutter the form if always visible -- Users can make better decisions with reference information - -## Considerations - -- Place the details component after the form question it relates to -- Use clear headings within the details to organize content -- Include both "examples of" and "do not include" lists when relevant -- Keep the details heading phrased as a question to indicate it provides clarification -- Ensure the expanded content is easy to scan with clear formatting diff --git a/docs/src/content/examples/show-a-notification-with-an-action/index.mdx b/docs/src/content/examples/show-a-notification-with-an-action/index.mdx index de8947d9c4..a151ed152c 100644 --- a/docs/src/content/examples/show-a-notification-with-an-action/index.mdx +++ b/docs/src/content/examples/show-a-notification-with-an-action/index.mdx @@ -1,10 +1,7 @@ --- id: show-a-notification-with-an-action title: Show a notification with an action -categories: - - feedback-and-alerts -scale: interaction -userType: both +size: interaction tags: - notification - feedback diff --git a/docs/src/content/examples/show-a-notification/index.mdx b/docs/src/content/examples/show-a-notification/index.mdx index 51a848f758..f0648d0a19 100644 --- a/docs/src/content/examples/show-a-notification/index.mdx +++ b/docs/src/content/examples/show-a-notification/index.mdx @@ -1,10 +1,7 @@ --- id: show-a-notification title: Show a notification -categories: - - feedback-and-alerts -scale: interaction -userType: both +size: interaction tags: - notification - feedback diff --git a/docs/src/content/examples/show-a-section-title-on-a-question-page/index.mdx b/docs/src/content/examples/show-a-section-title-on-a-question-page/index.mdx deleted file mode 100644 index 283f82ec47..0000000000 --- a/docs/src/content/examples/show-a-section-title-on-a-question-page/index.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -id: show-a-section-title-on-a-question-page -title: Show a section title on a question page -categories: - - forms -scale: task -userType: citizen -tags: - - forms - - questions - - navigation - - section -components: - - form-item - - radio-group - - radio-item - - button -status: published -previewImage: /images/examples/show-a-section-title-on-a-question-page.webp ---- - -Show a section title on a question page to help users understand which part of the form they are completing. - -## When to use - -Use this pattern when: - -- Building multi-section forms where context helps users -- Users need to know which category of questions they are answering -- The form is divided into logical sections like "Personal information" -- Following the one-question-per-page pattern for government services - -## Considerations - -- Use a subdued text color for the section title to differentiate from the question -- Include a back link for navigation to previous questions -- The section title should appear above the question -- Use consistent spacing between the back link, section title, and question -- Keep section titles concise and descriptive diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/index.mdx b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/index.mdx deleted file mode 100644 index b5817324da..0000000000 --- a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions/index.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions -title: Show a simple progress indicator on a question page with multiple questions -categories: - - forms -scale: task -userType: citizen -tags: - - forms - - questions - - progress - - navigation - - multi-question -components: - - form-item - - input - - button -status: published -previewImage: /images/examples/show-a-simple-progress-indicator-on-a-question-page-with-multiple-questions.webp ---- - -Show a simple progress indicator on a question page when grouping multiple related questions together. - -## When to use - -Use this pattern when: - -- Grouping multiple related questions on a single page improves the user experience -- The questions form a logical unit (e.g., personal information fields) -- Users benefit from progress tracking across the form -- A step-based indicator shows progress through form sections - -## Considerations - -- Display progress as "Step X of Y" when grouping questions into sections -- Include a clear section heading that describes the group of questions -- Use a subdued text color for the progress indicator -- Include a back link for navigation to previous sections -- Position related questions close together with consistent spacing -- The `leadingContent` prop on inputs can add prefixes like country codes diff --git a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/index.mdx b/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/index.mdx deleted file mode 100644 index c978a41b35..0000000000 --- a/docs/src/content/examples/show-a-simple-progress-indicator-on-a-question-page/index.mdx +++ /dev/null @@ -1,39 +0,0 @@ ---- -id: show-a-simple-progress-indicator-on-a-question-page -title: Show a simple progress indicator on a question page -categories: - - forms -scale: task -userType: citizen -tags: - - forms - - questions - - progress - - navigation -components: - - form-item - - radio-group - - radio-item - - button -status: published -previewImage: /images/examples/show-a-simple-progress-indicator-on-a-question-page.webp ---- - -Show a simple progress indicator on a question page to help users understand their progress through the form. - -## When to use - -Use this pattern when: - -- Building a multi-question form where progress tracking helps users -- Users benefit from knowing how many questions remain -- The form has a linear flow with a known number of questions -- Following the one-question-per-page pattern for government services - -## Considerations - -- Display progress as "Question X of Y" for clarity -- Use a subdued text color for the progress indicator -- Include a back link for navigation to previous questions -- Position the progress indicator above the question -- Keep the format consistent throughout the form diff --git a/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/index.mdx b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/index.mdx index 83f7f392fa..d825ddcda0 100644 --- a/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/index.mdx +++ b/docs/src/content/examples/show-a-user-progress-when-the-time-is-unknown/index.mdx @@ -1,10 +1,7 @@ --- id: show-a-user-progress-when-the-time-is-unknown title: Show a user progress when the time is unknown -categories: - - feedback-and-alerts -scale: task -userType: both +size: interaction tags: - progress - notification diff --git a/docs/src/content/examples/show-a-user-progress/index.mdx b/docs/src/content/examples/show-a-user-progress/index.mdx index 4ecd7c7f54..e51005aaca 100644 --- a/docs/src/content/examples/show-a-user-progress/index.mdx +++ b/docs/src/content/examples/show-a-user-progress/index.mdx @@ -1,10 +1,7 @@ --- id: show-a-user-progress title: Show a user progress -categories: - - feedback-and-alerts -scale: task -userType: both +size: interaction tags: - progress - notification diff --git a/docs/src/content/examples/show-different-views-of-data-in-a-table/index.mdx b/docs/src/content/examples/show-different-views-of-data-in-a-table/index.mdx index 1b65965c59..26769993b9 100644 --- a/docs/src/content/examples/show-different-views-of-data-in-a-table/index.mdx +++ b/docs/src/content/examples/show-different-views-of-data-in-a-table/index.mdx @@ -1,10 +1,8 @@ --- id: show-different-views-of-data-in-a-table title: Show different views of data in a table -categories: - - content-layout -scale: task -userType: worker +size: section +productType: workspace tags: - table - tabs diff --git a/docs/src/content/examples/show-full-date-in-a-tooltip/index.mdx b/docs/src/content/examples/show-full-date-in-a-tooltip/index.mdx index d578104746..f97c267218 100644 --- a/docs/src/content/examples/show-full-date-in-a-tooltip/index.mdx +++ b/docs/src/content/examples/show-full-date-in-a-tooltip/index.mdx @@ -1,10 +1,7 @@ --- id: show-full-date-in-a-tooltip title: Show full date in a tooltip -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - tooltip - date diff --git a/docs/src/content/examples/show-links-to-navigation-items/index.mdx b/docs/src/content/examples/show-links-to-navigation-items/index.mdx index 51901b1a64..f00f26a007 100644 --- a/docs/src/content/examples/show-links-to-navigation-items/index.mdx +++ b/docs/src/content/examples/show-links-to-navigation-items/index.mdx @@ -1,10 +1,7 @@ --- id: show-links-to-navigation-items title: Show links to navigation items -categories: - - structure-and-navigation -scale: task -userType: both +size: section tags: - footer - navigation diff --git a/docs/src/content/examples/show-more-information-to-help-answer-a-question/index.mdx b/docs/src/content/examples/show-more-information-to-help-answer-a-question/index.mdx deleted file mode 100644 index 7476c80530..0000000000 --- a/docs/src/content/examples/show-more-information-to-help-answer-a-question/index.mdx +++ /dev/null @@ -1,41 +0,0 @@ ---- -id: show-more-information-to-help-answer-a-question -title: Show more information to help answer a question -categories: - - forms -scale: task -userType: citizen -tags: - - form - - details - - help - - question-page - - expandable -components: - - details - - form-item - - radio-group - - radio-item - - button -figmaUrl: https://www.figma.com/design/Jpy1Ea5qglwnp1SgGnagY9/%E2%9D%96-Component-library-%7C-DDD?node-id=63353-123863 -status: published -previewImage: /images/examples/show-more-information-to-help-answer-a-question.webp ---- - -Use the Details component to provide optional contextual help that explains why a question is being asked, helping users understand the purpose without cluttering the main form. - -## When to use - -Use this pattern when: - -- Users may wonder why a question is being asked -- Additional context helps users answer correctly -- The information is optional and shouldn't distract -- Following question page patterns for citizen services - -## Considerations - -- Place the details component after the question input -- Use a clear heading like "Why are we asking this question?" -- Keep the expanded content concise and helpful -- Include helper text for the main question when appropriate diff --git a/docs/src/content/examples/show-multiple-actions-in-a-compact-table/index.mdx b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/index.mdx index ba326e5c44..5d1f100848 100644 --- a/docs/src/content/examples/show-multiple-actions-in-a-compact-table/index.mdx +++ b/docs/src/content/examples/show-multiple-actions-in-a-compact-table/index.mdx @@ -1,10 +1,8 @@ --- id: show-multiple-actions-in-a-compact-table title: Show multiple actions in a compact table -categories: - - content-layout -scale: task -userType: worker +size: section +productType: workspace tags: - table - icon-button diff --git a/docs/src/content/examples/show-multiple-tags-together/index.mdx b/docs/src/content/examples/show-multiple-tags-together/index.mdx index f559c4f25f..2a08a2ca4d 100644 --- a/docs/src/content/examples/show-multiple-tags-together/index.mdx +++ b/docs/src/content/examples/show-multiple-tags-together/index.mdx @@ -1,10 +1,7 @@ --- id: show-multiple-tags-together title: Show multiple tags together -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - badge - tags diff --git a/docs/src/content/examples/show-number-of-results-per-page/index.mdx b/docs/src/content/examples/show-number-of-results-per-page/index.mdx index ed45a48c97..759ebf725c 100644 --- a/docs/src/content/examples/show-number-of-results-per-page/index.mdx +++ b/docs/src/content/examples/show-number-of-results-per-page/index.mdx @@ -1,10 +1,7 @@ --- id: show-number-of-results-per-page title: Show number of results per page -categories: - - content-layout -scale: task -userType: both +size: section tags: - pagination - table diff --git a/docs/src/content/examples/show-quick-links/index.mdx b/docs/src/content/examples/show-quick-links/index.mdx index 3e85fc456d..86bbe9ee8f 100644 --- a/docs/src/content/examples/show-quick-links/index.mdx +++ b/docs/src/content/examples/show-quick-links/index.mdx @@ -1,10 +1,7 @@ --- id: show-quick-links title: Show quick links -categories: - - structure-and-navigation -scale: task -userType: both +size: section tags: - footer - navigation diff --git a/docs/src/content/examples/show-status-in-a-table/index.mdx b/docs/src/content/examples/show-status-in-a-table/index.mdx index 1e1ecc216a..05bb69758f 100644 --- a/docs/src/content/examples/show-status-in-a-table/index.mdx +++ b/docs/src/content/examples/show-status-in-a-table/index.mdx @@ -1,10 +1,8 @@ --- id: show-status-in-a-table title: Show status in a table -categories: - - content-layout -scale: task -userType: worker +size: section +productType: workspace tags: - table - badge diff --git a/docs/src/content/examples/show-status-on-a-card/index.mdx b/docs/src/content/examples/show-status-on-a-card/index.mdx index 1298d12e0b..45fa3c2b83 100644 --- a/docs/src/content/examples/show-status-on-a-card/index.mdx +++ b/docs/src/content/examples/show-status-on-a-card/index.mdx @@ -1,10 +1,8 @@ --- id: show-status-on-a-card title: Show status on a card -categories: - - content-layout -scale: task -userType: worker +size: interaction +productType: workspace tags: - card - container diff --git a/docs/src/content/examples/show-version-number/index.mdx b/docs/src/content/examples/show-version-number/index.mdx index e99e6fe382..0d7747b978 100644 --- a/docs/src/content/examples/show-version-number/index.mdx +++ b/docs/src/content/examples/show-version-number/index.mdx @@ -1,10 +1,7 @@ --- id: show-version-number title: Show version number -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - microsite-header - version diff --git a/docs/src/content/examples/slotted-error-text-in-a-form-item/index.mdx b/docs/src/content/examples/slotted-error-text-in-a-form-item/index.mdx index 7f437b6786..196392c3f6 100644 --- a/docs/src/content/examples/slotted-error-text-in-a-form-item/index.mdx +++ b/docs/src/content/examples/slotted-error-text-in-a-form-item/index.mdx @@ -1,10 +1,7 @@ --- id: slotted-error-text-in-a-form-item title: Slotted error text in a form item -categories: - - forms -scale: interaction -userType: both +size: interaction tags: - form - form-item diff --git a/docs/src/content/examples/slotted-helper-text-in-a-form-item/index.mdx b/docs/src/content/examples/slotted-helper-text-in-a-form-item/index.mdx index bb9035b364..d8727a1fae 100644 --- a/docs/src/content/examples/slotted-helper-text-in-a-form-item/index.mdx +++ b/docs/src/content/examples/slotted-helper-text-in-a-form-item/index.mdx @@ -1,10 +1,7 @@ --- id: slotted-helper-text-in-a-form-item title: Slotted helper text in a form item -categories: - - forms -scale: interaction -userType: both +size: interaction tags: - form - form-item diff --git a/docs/src/content/examples/sort-data-in-a-table/index.mdx b/docs/src/content/examples/sort-data-in-a-table/index.mdx index 922ad704a3..a850c691f3 100644 --- a/docs/src/content/examples/sort-data-in-a-table/index.mdx +++ b/docs/src/content/examples/sort-data-in-a-table/index.mdx @@ -1,10 +1,8 @@ --- id: sort-data-in-a-table title: Sort data in a table -categories: - - content-layout -scale: task -userType: worker +size: section +productType: workspace tags: - table - sorting diff --git a/docs/src/content/examples/start-page/index.mdx b/docs/src/content/examples/start-page/index.mdx index 72fdfe44a8..053a1fb58d 100644 --- a/docs/src/content/examples/start-page/index.mdx +++ b/docs/src/content/examples/start-page/index.mdx @@ -1,10 +1,9 @@ --- id: start-page title: Start page -categories: - - forms -scale: page -userType: citizen +size: page +productType: public-form +description: The front door to a government service for a citizen. It is the way into the service and how citizens access it. Each government service has a start page on Alberta.ca. tags: - page - service @@ -13,23 +12,44 @@ tags: components: - button status: published -previewImage: /images/examples/start-page.webp +previewImage: /images/examples/start-page.png --- -A start page is the front door to a government service for citizens. It provides essential information about the service and a clear call to action to begin. +## When to use a start page -## When to use +A start page is the front door to a government service for a citizen. It is the way into the service, how they access the service. Each government service has a start page on Alberta.ca. Contact the relevant person at Alberta.ca to make changes to the start page for your service. -Use this pattern when: +This is the starting point for a citizen to begin your form from within your service or from Alberta.ca. -- Creating the entry point for a citizen-facing government service -- Citizens need to understand what the service does before starting -- You need to communicate prerequisites, time estimates, or required documents +Provide the user with any information that is important before starting the form, such as how long it should take, a list of documents or information they may need to complete the form, any costs involved, or alternative ways to access the service. -## Considerations +## A service's start page should -- Keep the overview concise and focused on what users can do -- List what documents or information users will need -- Include an estimated completion time -- Use a prominent "Get started" or "Start now" button -- Provide contact information and alternative ways to access the service below the main call to action +- give the user just enough information to help them understand what the service does and whether it will meet their need +- have a service name that reflects the problem it solves for users +- be written in plain language. See the [GoA web writing style guide](https://www.alberta.ca/web-writing-style-guide). +- include a "start" button linking into the service, with text consistent with the action you are asking users to take. For example: "Start now", "Sign in", or "Register or update your details". +- include any other information that most users are likely to need before they start using the service online. For example: how much it costs to use the service and roughly how long it will take. +- include additional information about the service, such as other ways to access it (e.g. by telephone or by completing a paper form). This should be included after the main call to action to start the digital service. + +## Page content + +Consider the primary information that the user needs to know before entering into the service. Provide that information clearly, then provide a link to start using the service. Provide additional secondary information below the call to action. + +### Overview + +What the user needs to know before they enter the service. A high-level description of what the service is and what they can use it to do. + +### Before you begin + +- how long it will take +- what they will need to complete the service (e.g. specific documents) +- other important information + +### Call to action + +Below the primary information, include an obvious call to action to get started with the service. + +### Other information + +Below the call to action, include any additional information as applicable, such as customer support, frequently asked questions, or related links. diff --git a/docs/src/content/examples/task-list-page/index.mdx b/docs/src/content/examples/task-list-page/index.mdx index 4d1c48e09e..9ed787dca6 100644 --- a/docs/src/content/examples/task-list-page/index.mdx +++ b/docs/src/content/examples/task-list-page/index.mdx @@ -1,10 +1,9 @@ --- id: task-list-page title: Task list page -categories: - - forms -scale: page -userType: both +size: page +productType: public-form +description: A page that provides structure for multiple steps in a service. Use a task list to outline the entire process and show the status of each task as users move through it. tags: - page - task-list @@ -15,24 +14,55 @@ components: - badge - callout status: published -previewImage: /images/examples/task-list-page.webp +previewImage: /images/examples/task-list-page.png --- -A task list page provides a structure for multi-step services, showing users their progress through a series of tasks with clear status indicators. +## When to use a task list page -## When to use +Use a task list page to provide a structure for multiple steps in a service. Show a task list page when a citizen begins a service, and when they return to the service. -Use this pattern when: +When using a task list, group related actions into tasks and show the status of the tasks. -- A service has multiple distinct tasks or sections to complete -- Users need to see their overall progress -- Tasks can potentially be completed in different orders -- Users may return to complete tasks over multiple sessions +## How to define a task -## Considerations +The size and complexity of a task is determined by the service and content. A task can be defined as small as a single action, such as "sign a document" or "upload a file", or it can be as big as an entire section of a form with multiple question pages and a review page. -- Group related actions into logical tasks -- Show status badges for each task (Completed, In progress, Not started, Cannot start yet) -- Include a summary callout showing how many sections are complete -- Allow users to complete tasks in any order when possible -- Clearly indicate when tasks have dependencies +Use tasks to break down the steps in a service in an understandable way. + +## Show status of tasks + +Make it clear which tasks a user has completed and which they still need to complete. + +### Suggested statuses + +- **Completed** — success +- **In progress** — dark grey +- **Not started** — information +- **Cannot start yet** — light grey + +Include a summary above the task list to say how many tasks have been completed. This also makes it clearer to the user that there are still tasks left to complete. + +### How is a task list different from a stepper? + +**Stepper:** + +- a visual navigation within a form +- shown at the top of every page in a form +- scope: sections of a form + +**Task list:** + +- can be used to outline more than just sections of a form +- not shown on every page + +### Completing tasks in order + +When possible, allow users to complete tasks in any order. This will help them plan their time and complete sections as and when they can. + +## Anatomy + +1. **Page title** — heading-large +2. **Status of completed sections** — `goa-callout` +3. **Section** — task-list-section +4. **Section heading** — heading-medium +5. **Task** — `goa-table` diff --git a/docs/src/content/examples/type-to-create-a-new-filter/index.mdx b/docs/src/content/examples/type-to-create-a-new-filter/index.mdx index 74c567a50b..31db30217b 100644 --- a/docs/src/content/examples/type-to-create-a-new-filter/index.mdx +++ b/docs/src/content/examples/type-to-create-a-new-filter/index.mdx @@ -1,10 +1,7 @@ --- id: type-to-create-a-new-filter title: Type to create a new filter -categories: - - inputs-and-actions -scale: interaction -userType: both +size: interaction tags: - filter-chip - input diff --git a/docs/src/content/examples/warn-a-user-of-a-deadline/index.mdx b/docs/src/content/examples/warn-a-user-of-a-deadline/index.mdx index 150862da76..e8dea0506d 100644 --- a/docs/src/content/examples/warn-a-user-of-a-deadline/index.mdx +++ b/docs/src/content/examples/warn-a-user-of-a-deadline/index.mdx @@ -1,10 +1,7 @@ --- id: warn-a-user-of-a-deadline title: Warn a user of a deadline -categories: - - feedback-and-alerts -scale: task -userType: both +size: section tags: - modal - warning diff --git a/docs/src/content/examples/workspace/case-detail/index.mdx b/docs/src/content/examples/workspace/case-detail/index.mdx new file mode 100644 index 0000000000..ef0a7d6ad5 --- /dev/null +++ b/docs/src/content/examples/workspace/case-detail/index.mdx @@ -0,0 +1,37 @@ +--- +id: workspace-case-detail +title: Case detail +size: page +productType: workspace +description: A single-record view for reviewing and acting on one case. Uses accordion sections, a table-of-contents sidebar, badges for status, and header actions for quick operations. +previewUrl: https://digital-service-demo-v2.netlify.app/workspace/application/ef12df7d-74e7-4a82-9495-51589a0498ae +previewImage: /thumbnails/workspace-case-detail.png +reactSourceUrl: https://github.com/GovAlta/goa-workspace-playground/tree/main/src/routes/cases +angularSourceUrl: https://github.com/GovAlta/goa-workspace-angular/tree/main/src/app/pages/cases +components: + - accordion + - badge + - button + - drawer +tags: + - workspace + - case-detail + - worker +status: published +--- + +## When to use + +Use the case detail view when staff need to review and act on a single record. + +## Structure + +Break long content into sections using [accordions](/components/accordion) to organize submitted data into collapsible sections. A table-of-contents sidebar helps users navigate long case content. [Badges](/components/badge) show case status, and action buttons in the header provide quick access to review, assign, and comment actions. + +## Actions + +For focused work that should happen without leaving the page, pair case detail with a [push drawer](/components/push-drawer). + +## Considerations + +Keep the accordion section headings short and consistent. When the list of sections is long, the TOC sidebar becomes essential. diff --git a/docs/src/content/examples/workspace/dashboard/index.mdx b/docs/src/content/examples/workspace/dashboard/index.mdx new file mode 100644 index 0000000000..dedc429277 --- /dev/null +++ b/docs/src/content/examples/workspace/dashboard/index.mdx @@ -0,0 +1,40 @@ +--- +id: workspace-dashboard +title: Dashboard +size: page +productType: workspace +description: Gives staff an overview of their work with counts, trends, and assigned items. +previewUrl: https://digital-service-demo-v2.netlify.app/workspace +previewImage: /thumbnails/workspace-dashboard.png +reactSourceUrl: https://github.com/GovAlta/goa-workspace-playground/tree/main/src/routes/dashboard +angularSourceUrl: https://github.com/GovAlta/goa-workspace-angular/tree/main/src/app/pages/dashboard +components: + - container + - block + - badge +tags: + - workspace + - dashboard + - worker +status: published +--- + +## When to use + +Use a dashboard as the landing view of a workspace when staff need to see priorities and act quickly. + +## What to include + +Include the information that helps staff understand priorities and act quickly, such as: + +- counts or status summaries +- trends or workload charts +- links to assigned or high-priority work + +## Layout + +The layout uses [containers](/components/container) and [blocks](/components/block) to organize content into scannable sections. + +## Considerations + +Prioritize the two or three things staff need to see on arrival. Surface everything else from deeper navigation rather than crowding the dashboard. diff --git a/docs/src/content/examples/workspace/index-page/index.mdx b/docs/src/content/examples/workspace/index-page/index.mdx new file mode 100644 index 0000000000..6980db1f85 --- /dev/null +++ b/docs/src/content/examples/workspace/index-page/index.mdx @@ -0,0 +1,36 @@ +--- +id: workspace-index-page +title: Index page +size: page +productType: workspace +description: The page staff land on to scan, filter, sort, and pick records to work on. The home of the workspace's daily queue. +previewUrl: https://digital-service-demo-v2.netlify.app/workspace/applications +previewImage: /thumbnails/workspace-table-view.png +reactSourceUrl: https://github.com/GovAlta/goa-workspace-playground/tree/main/src/routes/search +angularSourceUrl: https://github.com/GovAlta/goa-workspace-angular/tree/main/src/app/pages/search +components: + - work-side-menu + - data-grid + - tabs + - filter-chip + - badge +tags: + - workspace + - index + - worker +status: published +--- + +## When to use + +Use the index page as the workspace's main listing surface. Most workspaces have one or more, organized by record type (applications, cases, claims, requests). + +## Structure + +The index page is built around a [data view](/examples/workspace#data-views) showing the records the user is responsible for. Tabs filter by status. Search and filter chips narrow further. A primary action button (often "New record") lives in the page header. + +## Considerations + +- Surface what staff need to act on first. The default sort and filter should reflect a typical worker's queue, not the database's order. +- Keep the action bar slim. Filters and search go inside the table region; high-level actions sit in the page header. +- Pair with [sidebar navigation](/examples/workspace#sidebar-navigation) so staff can jump between index pages for different record types. diff --git a/docs/src/content/examples/workspace/index.mdx b/docs/src/content/examples/workspace/index.mdx deleted file mode 100644 index 403a88644d..0000000000 --- a/docs/src/content/examples/workspace/index.mdx +++ /dev/null @@ -1,263 +0,0 @@ ---- -id: workspace -title: Workspace -description: The workspace is for productivity-focused services used by service delivery staff as a daily tool to review information, manage records, and complete tasks. The design prioritizes productivity, efficiency, and accuracy so staff can move through their work quickly while ensuring the best outcome for citizens and government.
Workspaces should be adapted to fit each service's context and user needs. The reference example is a starting point to expand on, not a rigid template. -categories: [] -scale: product -userType: worker -tags: - - workspace - - worker - - service - - case-management - - dashboard - - pattern -components: - - work-side-menu - - table - - badge - - tabs - - container - - accordion - - drawer - - button - - block -previewImage: /thumbnails/workspace-preview.png -status: published ---- - -View demo - -import LinkCard from "../../../components/LinkCard.astro"; - -
- - -
- -**Primary user:** Service delivery staff - -## When to use - -Use the workspace when your service needs to support regular, task-based work, such as: - -- Reviewing and processing submissions -- Managing case files, applications, or requests -- Moving between dashboards, lists, and detail views -- Taking actions such as approve, deny, assign, or request more information - -## When not to use - -- Citizen-facing services — use the [public form](/examples/public-form) pattern instead -- Content-only pages that don't involve case management -- Simple internal tools that don't need structured case processing - ---- - -## Sidebar navigation - -Use the [work side menu](/components/work-side-menu) as the primary navigation for a workspace. - -Keep top-level navigation focused on the main areas of work. When a user opens a record or case, switch to contextual navigation that supports that task. This puts the user into a focused mode with relevant navigation items (like sections of an application, comments, reminders) and a back link to return to the main view. The sidebar can adapt to what the user is doing, it doesn't have to show everything at once. - -

- Main workspace navigation -

-Workspace main sidebar navigation with Dashboard and Applications items - -

- Contextual case navigation -

-Workspace contextual sidebar showing case-specific navigation items - -View demo - ---- - -## Dashboard - -The dashboard gives staff an overview of their work. - -Include the information that helps them understand priorities and act quickly, such as: - -- counts or status summaries -- trends or workload charts -- links to assigned or high-priority work - -The layout uses [containers](/components/container) and [blocks](/components/block) to organize content into scannable sections. - -Workspace dashboard - -View demo - ---- - -## Data views - -Workers need different ways to view, scan, and act on records depending on the task. Choose the data view that best supports the task. - -- **Table view** — Dense, scannable rows with sortable columns. Best for users who need to compare fields across many records at once. -- **Card view** — Each record as a card showing key details grouped into sections. Useful when records have more complex data that doesn't fit neatly into columns. -- **Expandable list view** — Compact rows that expand inline to reveal detail. A middle ground between the density of a table and the richness of cards. - -Any view can be combined with grouping (for example, group by priority or status) to organize records into collapsible sections. Users can also search, filter by status using [tabs](/components/tabs), sort with multi-level sorting, and manage active filters with [filter chips](/components/filter-chip). - -

- Table view -

-Table view with sortable columns - -

- Card view -

-Card view of case files - -

- Expandable list view -

-Expandable list view with grouping - -View demo - ---- - -## Case detail - -Use the case detail view to help users review and act on a single record. - -Break long content into sections using [accordions](/components/accordion) to organize submitted data into collapsible sections. A table-of-contents sidebar helps users navigate long case content. [Badges](/components/badge) show case status, and action buttons in the header provide quick access to review, assign, and comment actions. - -Workspace case detail - -View demo - ---- - -## Sticky action bar - -A scroll-aware header that pins to the top of the content area as the user scrolls. Use it to keep the most important tools visible. - -Set the content for each page based on the task: - -- On a cases list page, keep tools such as search and key actions visible. -- On a detail page, keep the case name and key actions visible. - -Do not pin everything. Keep only the information and actions people need to continue their work without losing context. - -Workspace sticky action bar - -View demo - ---- - -## Push drawer - -Use a [push drawer](/components/drawer) for focused work that should happen without leaving the current page. - -This works well for actions such as: - -- approving or denying a record -- requesting more information -- completing a short decision form -- reviewing supporting details while taking action - -Use it when users need to keep the main record in view while completing the task. - -Workspace push drawer - -View demo - ---- - -## Keyboard-accessible data views - -Workspace data views use the [data grid](/components/data-grid) to make table and card layouts fully keyboard navigable. Users can use arrow keys to move between cells and rows, making it possible to scan and act on records without a mouse. This is especially important in workspace contexts where staff are processing high volumes of cases and keyboard navigation is significantly faster than clicking. For assistive technology users, screen readers announce cell content and position as the user navigates. - ---- - -## Components built for workspace - -Workspace patterns are supported by component features designed for denser, more productive interfaces: - -- **Compact inputs** — Every input component now has a `compact` variant that reduces height and spacing. This lets you build tighter forms and toolbars without sacrificing usability. -- **Compact badges and notifications** — [Badges](/components/badge) and [notification banners](/components/notification) also have compact sizing to fit within dense data views and action bars. -- **Badge variants** — [Badges](/components/badge) now include `strong` and `subtle` emphasis options, giving you control over visual weight depending on context. -- **Data grid** — The [data grid](/components/data-grid) works with the table component to support accessible, keyboard-navigable data views. Use them together when the user needs to move through records efficiently without relying on a mouse. -- **Segmented tabs** — A new [tab](/components/tab) variant that works as a segmented toggle for switching between views or modes within a workspace, rather than navigating between pages. -- **Enhanced filter chips** — [Filter chips](/components/filter-chip) now support secondary text and secondary icons, making them more useful for richer filtering in workspace data views. - ---- - -## Get started - -Use one of the workspace templates as a starting point for your service. Each template includes the sidebar navigation, dashboard, data views, and case detail patterns described above. - -
- - -
- ---- - -## Considerations - -- The reference demo is a spike — component customizations haven't gone through the production pipeline yet -- There should be significant variability within a workspace to meet each service's specific context and user needs -- The demo is a starting point to expand on and adapt, not a rigid template to copy exactly -- Desktop uses a card container pattern for the main content area; this is removed on mobile for space diff --git a/docs/src/content/get-started/automated-accessibility.mdx b/docs/src/content/get-started/automated-accessibility.mdx new file mode 100644 index 0000000000..07bae83e0b --- /dev/null +++ b/docs/src/content/get-started/automated-accessibility.mdx @@ -0,0 +1,83 @@ +--- +id: automated-accessibility +title: Automated accessibility +description: Guidance on using automated accessibility testing tools effectively +section: intro +order: 2 +status: published +--- +import DropInCallout from "../../components/DropInCallout.astro"; + +Automated accessibility +Automated accessibility testing tools help you identify potential accessibility issues. Use them as a starting point. + +

+ However, these tools are not a complete solution. They can produce: +

+
    +
  • False positives – flagging issues that are not actual problems
  • +
  • False negatives – missing real accessibility barriers
  • +
+

+ To ensure your digital product is accessible, combine automated testing with manual testing and apply + human judgment. +

+Why automated tools alone are not enough + +False positives +

+ Automated tools may flag elements as non-compliant even when they work correctly for users. For + example, a tool may report that an input is "missing an id" even though it is correctly associated with a + label using a valid method, such as wrapping the input inside a <label> element. +

+ +False negatives +

+ Automated tools cannot detect nuanced or context-specific issues. For example, all interactive + elements may be tabbable, but the order jumps around the page. Tools often don't judge whether the + tab order is logical for completing the task. +

+ +Real user experience +

+ Accessibility ensures real people can use a product effectively. Automated tools cannot fully simulate + how users interact with your product. +

+Steps for effective accessibility testing + +
    +
  1. + Run automated tools to get an initial assessment. +
  2. +
  3. + Manually verify flagged issues and review the element's intent and context. +
  4. +
  5. + Do additional manual testing for issues automated tools cannot detect: +
      +
    • Test with a screen reader, such as VoiceOver (macOS) or NVDA (Windows)
    • +
    • Test keyboard navigation by checking focus visibility and order
    • +
    +
  6. +
  7. + Report findings +
      +
    • Record what you tested, what failed, and how to reproduce it
    • +
    • If the issue relates to a design system component, submit it using the design system bug report form
    • +
    +
  8. +
+Why this process matters +

+ Automated tools provide helpful insight. Relying only on automation can result in: +

+
    +
  • Time spent fixing issues that are not real barriers
  • +
  • Missed opportunities to address genuine accessibility issues
  • +
  • A false sense of compliance without meaningful usability improvements
  • +
+

+ Combine automated and manual testing to identify real barriers. This approach improves accessibility + and overall product quality. +

+ diff --git a/docs/src/content/get-started/component-lifecycle.mdx b/docs/src/content/get-started/component-lifecycle.mdx new file mode 100644 index 0000000000..c7e881c163 --- /dev/null +++ b/docs/src/content/get-started/component-lifecycle.mdx @@ -0,0 +1,57 @@ +--- +id: component-lifecycle +title: Component lifecycle +description: The stages each Design System component moves through +section: intro +order: 3 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../components/DropInCallout.astro"; + +Component lifecycle +The component lifecycle defines the stages each Design System component moves through, from Experimental to Production to Legacy. + +

+ To request a new component or propose an enhancement, follow the + design contribution process. +

+Experimental +

+ Experimental components are new or significantly updated. They are available for testing and feedback + before public release. +

+ +Characteristics +
    +
  • Feedback is gathered from selected teams
  • +
  • May be unstable or include breaking changes
  • +
  • Limited documentation
  • +
+Production +

+ Production components are stable and ready for broader adoption. +

+ +Characteristics +
    +
  • Fully documented, including design guidelines, properties, and examples
  • +
  • Meet accessibility and design system standards
  • +
  • Optimized for mobile use
  • +
  • Actively maintained with updates and bug fixes
  • +
  • Publicly available documentation
  • +
+Legacy +

+ Legacy components are older components maintained primarily to support older implementations. If + possible, transition to production is recommended. +

+ +Characteristics +
    +
  • No active maintenance or updates
  • +
  • Critical issues may remain unresolved
  • +
  • Recommended alternative clearly identified
  • +
  • Marked as "Legacy" in official documentation
  • +
+ diff --git a/docs/src/content/get-started/contribute.mdx b/docs/src/content/get-started/contribute.mdx new file mode 100644 index 0000000000..8e6f4e0437 --- /dev/null +++ b/docs/src/content/get-started/contribute.mdx @@ -0,0 +1,177 @@ +--- +id: contribute +title: Contribute +description: How to contribute to the GoA Design System +section: appendix +order: 2 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../components/DropInCallout.astro"; + +Contribute +The Design System is a shared resource used and improved by service teams. All roles are encouraged to contribute. + +

+ Start by using existing Design System components and patterns. If a component or pattern does not + meet your needs, follow the contribution process below. +

+Design contribution process +

+ If a required component or example does not exist in production, + contact the Design System team. We will review the request together and determine next steps. +

+ +1. Contact the team +

+ Book a design system drop-in hours session. +

+

Be prepared to:

+
    +
  • Describe the component or pattern and its purpose
  • +
  • Explain your user needs and service goals
  • +
  • Share iterations explored with and without the Design System
  • +
+ + + There are open contribution files in Figma for every component and pattern in the design system, including unpublished ideas and experiments. + + +2. Contribution criteria +

A proposed component or pattern must meet the following criteria.

+ +Proposal criteria +

Useful

+

+ Evidence shows it supports multiple teams or services. Provide screenshots or links to demonstrate usage. +

+ +

Unique

+

+ It does not duplicate an existing component or pattern. If replacing an existing component, provide + evidence that the new approach improves usability or accessibility. +

+ +Publication standards +

To be published, the solution must be:

+ +

Usable

+

+ Improves clarity, usability, and accessibility for users. Is informed by research and addresses a + validated user need. +

+ +

Universal

+

+ Inclusive and accessible. Meets or exceeds accessibility standards. + WCAG 2.2 AA is the minimum requirement. +

+ +3. Backlog and collaboration +

+ If approved, the item is added to the + Design System's backlog. +

+

+ When development begins, the Design System team will collaborate with you to confirm detailed requirements. +

+Code contribution process +

+ The Design System supports multiple development frameworks through Web Components. Contributing full + components can be complex. Smaller contributions are encouraged. +

+ +Recommended contribution types +
    +
  • Bug fixes
  • +
  • Documentation updates
  • +
  • Enhancements to existing components
  • +
+

+ Start by contacting the team in the #design-system-support Slack channel. +

+

+ Select an issue tagged ready-for-contribution from the + backlog. + Confirm which issue you will work on. +

+ + + Since the repository is public, use a personal GitHub account instead of your Enterprise Managed User (EMU) account. + + +Set up your contribution environment +
    +
  1. Clone the ui-components repository.
  2. +
  3. Open the repository in your IDE.
  4. +
  5. Create a branch named: contributions/story-number
  6. +
  7. + Run the following commands: +
    npm i
    +npm run build
    +
  8. +
  9. + The playgrounds for local testing are located in: +
    /apps/dev/angular
    +/apps/dev/react
    +
  10. +
+ +Run playground environments +

Angular

+
npm run dev:watch
+npm run serve:dev:angular
+ +

React

+
npm run dev:watch
+npm run serve:dev:react
+ +Repository structure + +

React wrappers

+

/libs/react-components/src/lib

+

Each folder represents a single component with its associated unit tests and wrapper code.

+ +

Angular wrappers

+

/libs/angular-components/src/lib/components

+

Each folder represents a single component with its associated unit tests and wrapper code.

+ +

Web Components

+

/libs/web-components/src/components

+
    +
  • Unit tests as {"*.spec.ts"}
  • +
  • Component code as {"*.svelte"}
  • +
+ +Testing requirements +
    +
  • Write all unit tests in Svelte.
  • +
  • If updating React or Angular wrappers, write unit tests in those respective frameworks.
  • +
  • + Add browser testing using Jest for React wrappers and Svelte components when appropriate. + These can be found in: libs/react-components/specs +
  • +
  • Manually test components in both React and Angular.
  • +
  • + Create test files that others can use to manually test the PR. These can be created in: +
    /apps/prs/angular
    +/apps/prs/react
    +
  • +
  • Follow the conventions already used in those files to create your test files.
  • +
+

A Design System developer will also manually test the pull request.

+ +Submit your contribution +

Use the following commit message format:

+ +

Bug fix

+
fix(#storyNumber): short description (7 words max)
+ +

Feature request

+
feat(#storyNumber): short description (7 words max)
+ +
    +
  • Create a pull request from your branch to the dev branch.
  • +
  • Notify the design system team of the PR.
  • +
+ diff --git a/docs/src/content/get-started/designers.mdx b/docs/src/content/get-started/designers.mdx new file mode 100644 index 0000000000..fcf79c98bd --- /dev/null +++ b/docs/src/content/get-started/designers.mdx @@ -0,0 +1,86 @@ +--- +id: designers +title: Designers overview +navLabel: Overview +description: How designers use the design system through Figma +section: designers +order: 1 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../components/DropInCallout.astro"; + +Overview +As a designer, you use the design system through Figma. +

In Figma, you can access:

+ + + +

+ The design system library in Figma aligns with coded components used by developers. Start with + design system components for common parts of your service. This helps developers use the matching + coded components and reduces custom work. +

+

+ Start with the design system. Validate your design through user testing. If usability issues arise, + or the problem cannot be solved within the system, consider creating a custom solution. +

+Design with development in mind +

+ When selecting components, prioritize those with a "goa-" prefix, such as + goa-input. These components exist in both design and development. Using them reduces + the need for custom development. +

+

Choose shared components whenever possible to maintain consistency and efficiency.

+ +Design tokens +

Design system components in Figma and code are built using design tokens.

+

+ Use tokens to communicate design decisions clearly. Developers can reference the same tokens in code. +

+

Instead of sharing hex values or pixel adjustments, reference semantic tokens.

+

For example:

+
    +
  • Colour: --goa-color-info-default
  • +
  • Spacing: --goa-spacing-m
  • +
+

Using tokens reduces back-and-forth and keeps design and development aligned.

+ +Components +

All design system components are available in Figma and in code.

+

+ These components are designed to meet + WCAG 2.2 accessibility standards. +

+

Avoid detaching components. Instead:

+
    +
  • Use variants
  • +
  • Show or hide layers within the component
  • +
+

+ Use #figma for Figma-related issues, including library updates, missing components, + broken instances, or component behaviour in Figma. +

+

+ Use #design-system-support for design system guidance, component usage questions, + standards, and implementation support. +

+

Keep your components up to date. Figma will notify you when library updates are available.

+ +Figma file templates and helper components +

Each digital service project folder includes a starter Figma template.

+

Use this template to:

+
    +
  • Organize your design file
  • +
  • Support developer handoff
  • +
  • Help team members navigate files
  • +
+

+ Helper components are also available. Use them to clearly communicate intent when sharing designs + with developers and other team members. +

+ diff --git a/docs/src/content/get-started/designers/designing-for-dark-mode.mdx b/docs/src/content/get-started/designers/designing-for-dark-mode.mdx new file mode 100644 index 0000000000..57cbb5820c --- /dev/null +++ b/docs/src/content/get-started/designers/designing-for-dark-mode.mdx @@ -0,0 +1,56 @@ +--- +id: designers/designing-for-dark-mode +title: Designing for dark mode +description: How dark mode works for designers +section: designers +order: 3 +status: published +--- +import { withBase } from "@/lib/base-url"; + +Designing for dark mode + + Dark mode is handled by the design system. Here's what that means for your designs. + + + + + Available in code now, not in Figma yet. Design in light mode and work with a developer to see your designs in dark mode. + + + +How it works +

+ We have an experimental version of dark mode you can try out in your service. It's handled automatically in code, so designers don't need to do anything different. The Figma library doesn't have a dark mode yet, so keep designing in light mode like you always have. Your designs will translate to dark mode when developers add the dark mode theme to your service. +

+ +Custom components and styles +

+ If you're using design system components, they all work with dark mode automatically. +

+

+ If you have custom components that use our design tokens, they'll switch to dark mode along with the rest of the system. Always worth testing to make sure things look right in both modes. +

+

+ If your custom components don't use our design tokens, they won't switch on their own. You'll need to handle dark mode for those yourself. We recommend using design tokens where you can so most of this happens automatically. +

+

+ Either way, you can extend dark mode for custom needs by working with developers to add custom dark mode styles to your service. +

+

+ The same goes for illustrations and images with set colors. These look the same in both modes, so check whether they read well on a dark background or whether you need a dark version. +

+ +Try it and share feedback +

+ Dark mode is still being tested. Try it out in your service and let the design system team know what works, what doesn't, and what's missing. +

+ +Ways to apply dark mode in your service +

+ Two ways users end up in dark mode. Use either, or both: +

+
    +
  • System settings. If their operating system is in dark mode, your service follows automatically.
  • +
  • A toggle in your service. Let users switch modes themselves through a preferences or settings screen.
  • +
diff --git a/docs/src/content/get-started/designers/designing-with-ds.mdx b/docs/src/content/get-started/designers/designing-with-ds.mdx new file mode 100644 index 0000000000..3be1641e5b --- /dev/null +++ b/docs/src/content/get-started/designers/designing-with-ds.mdx @@ -0,0 +1,71 @@ +--- +id: designers/designing-with-ds +title: Designing with Design System 2.0 +description: How to start new designs and update existing projects to Design System 2.0 +section: designers +order: 2 +status: published +--- +import DropInCallout from "../../../components/DropInCallout.astro"; + +Designing with Design System 2.0 +What's new in DS 2.0 and how to start using it in your designs. +

+ The Digital Design and Delivery (DDD) Design System has evolved to better support how service teams + design and build digital government services. Design System 2.0 includes an updated design + language, new tokens, refreshed components, and ready-to-use templates. +

+Starting a new design +

+ Use DS 2.0 templates as your starting point. Templates package layout, navigation, spacing, and + example content that you can adapt to your service. Some templates are built for specific service types + (for example, public-facing forms and workspace applications), and others are more general-purpose + starting points you can use across many kinds of pages and flows. +

+ +Starting from an existing design + +Library swap +

+ Use a library swap if + your goal is to convert most of the file to DS 2.0 in one pass. +

+
    +
  • Make a copy of your file before you start.
  • +
  • Expect mixed results. Some screens may need cleanup after the swap.
  • +
+ +Manual rebuild +

Use a manual rebuild if you need more control.

+
    +
  • Rebuild your highest value screens first.
  • +
  • Consider using DS 2.0 templates as a base to speed things up.
  • +
+Update an existing project to the new design library + +Approach 1: Developer-first +

Use this approach in most cases.

+
    +
  1. A developer creates a new branch and completes the upgrade steps.
  2. +
  3. The team runs the upgraded application to see what changed.
  4. +
  5. Designers review the upgraded screens and identify what needs design updates.
  6. +
+

When reviewing the upgraded branch, watch for:

+
    +
  • Spacing and layout rhythm
  • +
  • Typography scale and weight usage
  • +
  • Dense or constrained screens (these often have the highest risk during an update)
  • +
+ +Approach 2: Design-first +

Use this approach when you want design work to move ahead of development work.

+
    +
  1. Identify custom elements that support your users' needs.
  2. +
  3. Create an inventory and prioritize items by importance and effort.
  4. +
  5. Redesign the highest priority items using the visual design values in the Styles library.
  6. +
+ + + In most cases, start with the developer-first approach. It helps you quickly see what changed in your real product, so you can focus design effort where it matters most. + + diff --git a/docs/src/content/get-started/designers/ux-guidelines.mdx b/docs/src/content/get-started/designers/ux-guidelines.mdx new file mode 100644 index 0000000000..8af7b905f9 --- /dev/null +++ b/docs/src/content/get-started/designers/ux-guidelines.mdx @@ -0,0 +1,45 @@ +--- +id: designers/ux-guidelines +title: User experience guidelines +description: User experience guidelines for Government of Alberta digital products +section: designers +order: 4 +status: published +--- +import DropInCallout from "../../../components/DropInCallout.astro"; + +User experience guidelines +Digital products built for the Government of Alberta should comply with these guidelines to ensure a quality user experience for Albertans. + +
    +
  • User-centered: Designed with a clear understanding of users, their goals, tasks, environments, and context of use, using user-centered design methods.
  • +
  • Usable: Interfaces will be easy to use, enabling users to find the information they need and complete tasks successfully.
  • +
  • Accessible: Digital products will be inclusive, ensuring usability for everyone, regardless of physical or cognitive ability.
  • +
  • Trustworthy: Experiences will feel familiar and recognizable as a Government of Alberta product, ensuring users' security and privacy.
  • +
  • Modern: Digital experiences will meet present-day user expectations and preferences for aesthetics and interaction.
  • +
+ +

+ For more details on the process of assessing compliance to each guideline, refer to our + User Experience Guidelines and Design System Checklist. +

+Usability testing +

+ Usability testing is our preferred method to understand user needs as they relate to each guideline. +

+

Suitable usability testing includes:

+
    +
  • Diverse user group: Real users from different demographic, behavioural backgrounds, and geographical regions within Alberta that will experience the problem or benefit of the product.
  • +
  • Inclusive testing: Users with various physical and/or cognitive abilities, literacy levels, and tech savviness.
  • +
  • Device variety: A diverse range of devices that reflect users' preferred choice when interacting with government services.
  • +
  • Tasks: Activities that cover tasks and service process from end-to-end.
  • +
+

+ Frequent usability testing should be conducted to maintain product usability, effectiveness and + alignment to the user needs as they evolve over time. +

+

+ For guidance on the process of usability testing, refer to our + Understanding Usability documentation. +

+ diff --git a/docs/src/content/get-started/developers.mdx b/docs/src/content/get-started/developers.mdx new file mode 100644 index 0000000000..f6330b62e2 --- /dev/null +++ b/docs/src/content/get-started/developers.mdx @@ -0,0 +1,96 @@ +--- +id: developers +title: Developers overview +navLabel: Overview +description: How developers use the design system through tokens, components, examples, and templates +section: developers +order: 1 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../components/DropInCallout.astro"; + +Overview +As a developer, you use the Design System through tokens, components, examples, and templates. + +

+ The DDD Design System is built using Web Components. Web Components are framework-agnostic. + You can use them with Angular, React, or other front-end frameworks. +

+

The Design System includes:

+ +

+ Designers use equivalent resources in Figma. When they design with Design System components, you + can build with the matching coded components. This reduces custom development and rework. +

+

+ All Design System components are designed and built to meet + WCAG 2.2 accessibility standards. +

+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. +

+

+ Designers reference the same tokens in their tools. This keeps design and development aligned during handoff. +

+ +Components +

Components are reusable user interface elements built for use across services.

+

You can:

+
    +
  • Use components individually
  • +
  • Combine them into patterns
  • +
  • Apply them in different contexts
  • +
+

Components are available:

+ +

+ Refer to the Design System technologies documentation + for implementation details. +

+ +Examples +

+ Examples are multiple components assembled in realistic service contexts. They help you understand + how to apply Design System guidance in a working interface. +

+

You can use examples to:

+
    +
  • Understand how components work together
  • +
  • Use them as a starting point for building parts of your interface
  • +
  • Use proven approaches to meet user needs
  • +
+

+ Examples help you build with more consistency and less rework. Use them to guide implementation, + then adjust them to meet the needs of your product. +

+ +Templates +

+ Templates are opinionated starting points for common service types. They package layout, navigation, + spacing, and example content so you can start with a proven structure instead of building from scratch. +

+

You can use templates to:

+
    +
  • Start a new product with a proven structure
  • +
  • Learn how components work together in a real layout
  • +
  • Adapt a proven starting point to fit your service needs
  • +
+

+ Templates help teams move faster, reduce rework, and stay aligned with Design System guidance. +

+ diff --git a/docs/src/content/get-started/developers/browsers.mdx b/docs/src/content/get-started/developers/browsers.mdx new file mode 100644 index 0000000000..44a09a61b3 --- /dev/null +++ b/docs/src/content/get-started/developers/browsers.mdx @@ -0,0 +1,78 @@ +--- +id: developers/browsers +title: Supported browsers +description: Browser and operating system support for Design System components +section: developers +order: 7 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../../components/DropInCallout.astro"; + +Supported browsers +Design System components are tested across supported browsers and devices. + +

+ We support the latest version of each browser listed on this page. Support applies to the browser and + operating system combinations shown in the table below. On mobile, support is limited to the browser + and operating system combinations listed for Android and iOS. +

+ +Browser and operating system support + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BrowserWindowsMac OSAndroidiOS
Google ChromeYesYesYesYes
Microsoft EdgeYesYes
Mozilla FirefoxYesYesYes
Apple SafariN/AYesN/AYes
+
+ +Representative mobile OS used in testing +
    +
  • Android OS: 10+
  • +
  • iOS: 15+
  • +
+Testing guidance +

+ Use supported browsers and operating system versions when developing and testing services. If you + encounter a browser-specific issue, follow the + Verify a bug process. +

+ diff --git a/docs/src/content/get-started/developers/bug.mdx b/docs/src/content/get-started/developers/bug.mdx new file mode 100644 index 0000000000..48d6836b6d --- /dev/null +++ b/docs/src/content/get-started/developers/bug.mdx @@ -0,0 +1,56 @@ +--- +id: developers/bug +title: Verify a bug +description: How to verify and report a bug in a Design System component +section: developers +order: 5 +status: published +--- +import DropInCallout from "../../../components/DropInCallout.astro"; + +Verify a bug +Follow this process when you encounter an issue with a Design System component. + +

+ These steps help confirm whether the issue is caused by the Design System, your product setup, or + custom code. This process applies to Angular and React implementations. +

+ +1. Check versions +

Confirm you are using the latest version of:

+
    +
  • Web Components
  • +
  • Angular or React
  • +
+

+ If you are not using the latest version, upgrade and retest. If the issue remains, continue to the next step. +

+ +2. Test with product templates +

Use the official Angular or React product templates to isolate the issue.

+ +

This helps determine whether the issue exists outside your project configuration.

+ +3. Recreate the issue +

Create a minimal test environment.

+
    +
  • Use only the code required for the example to function
  • +
  • Include only the component experiencing the issue
  • +
  • Remove unrelated dependencies or custom logic
  • +
+

Confirm whether the issue can be replicated.

+ +4. Share and report +

If you can reproduce the issue:

+
    +
  • Share the template application link in the #design-system-support Slack channel
  • +
  • Provide a link to your repository so the team can review and replicate the issue
  • +
+

+ Following these steps will help to ensure efficient investigation and quicker resolution of + design system component issues. +

+ diff --git a/docs/src/content/get-started/developers/dark-mode-theme.mdx b/docs/src/content/get-started/developers/dark-mode-theme.mdx new file mode 100644 index 0000000000..a8caf821d1 --- /dev/null +++ b/docs/src/content/get-started/developers/dark-mode-theme.mdx @@ -0,0 +1,259 @@ +--- +id: developers/dark-mode-theme +title: Dark mode theme +description: Switch between light and dark mode using the React useTheme hook or Angular GoabThemeService +section: developers +order: 3 +status: published +--- +import { withBase } from "@/lib/base-url"; + +Dark mode theme + + Toggle light and dark mode using the React useTheme hook or the Angular + GoabThemeService. The user's choice persists across sessions. + + + + + Dark mode is still being tested. The CSS API and tokens may evolve as we iterate. + + + + + + Theme switching requires @abgov/design-tokens version 2.8.0 or + higher with the dark theme stylesheet imported. See Setup + for installation steps. + + + +

How it works

+ + Both the React provider and the Angular service write a data-theme + attribute on the document root (<html>). Design tokens scoped + to :root[data-theme="dark"] activate via CSS cascade, + automatically applying dark colors to every component without re-rendering. + + +

Initial mode priority

+ + On first load, the active mode is resolved in this order: + +
    +
  1. The user's previously chosen mode, read from local storage
  2. +
  3. The operating system preference (light or dark)
  4. +
  5. The framework default (light)
  6. +
+ + + +

React

+ + The React package exposes a context provider and a hook. + + +

1. Wrap your app with GoabThemeProvider

+ + Place the provider near the top of your app, alongside other framework + providers such as BrowserRouter: + +
{`// 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";
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+  
+    
+      
+    
+  ,
+);`}
+ +

2. Read and toggle theme with useTheme

+ + Inside any component below the provider, call useTheme() to read + the current mode and switch theme: + +
{`import { GoabButton, useTheme } from "@abgov/react-components";
+
+function ThemeToggle() {
+  const { mode, toggle } = useTheme();
+  const isDark = mode === "dark";
+
+  return (
+    
+      {isDark ? "Light mode" : "Dark mode"}
+    
+  );
+}`}
+ +

API

+
{`interface GoabThemeContextValue {
+  /** Current theme mode. */
+  mode: "light" | "dark";
+  /** Set theme to a specific mode. */
+  setMode: (next: "light" | "dark") => void;
+  /** Flip between light and dark. */
+  toggle: () => void;
+}
+
+interface GoabThemeProviderProps {
+  children: ReactNode;
+  /** Initial mode used when no stored or system preference is found. @default "light" */
+  defaultMode?: "light" | "dark";
+}`}
+ + + + useTheme throws if called outside of GoabThemeProvider. + + + + + +

Angular

+ + The Angular package exposes a root-provided service backed by a Signal. + + +

1. Import the dark theme stylesheet

+ + Add the import to your global stylesheet (typically src/styles.css): + +
@import "@abgov/web-components/index.css";
+@import "@abgov/design-tokens/dist/tokens.css";
+@import "@abgov/design-tokens/dist/dark-theme.css";
+ +

2. Inject GoabThemeService

+ + The service is provided in root, so inject it from any component or service: + +
{`// app.component.ts
+import { Component, inject } from "@angular/core";
+import { GoabThemeService } from "@abgov/angular-components";
+
+@Component({
+  selector: "app-root",
+  templateUrl: "./app.component.html",
+})
+export class AppComponent {
+  readonly theme = inject(GoabThemeService);
+
+  toggleTheme() {
+    this.theme.toggle();
+  }
+}`}
+ +

3. Bind to the signal in templates

+ + Read theme.mode() as a signal — Angular tracks the dependency + automatically and re-renders when the mode changes: + +
{`
+
+  {{ theme.mode() === "dark" ? "Light mode" : "Dark mode" }}
+`}
+ +

API

+
{`@Injectable({ providedIn: "root" })
+class GoabThemeService {
+  /** Read-only signal — use in templates: theme.mode() === "dark". */
+  readonly mode: Signal<"light" | "dark">;
+  /** Set theme to a specific mode. */
+  setMode(next: "light" | "dark"): void;
+  /** Flip between light and dark. */
+  toggle(): void;
+}`}
+ + + +

Custom styling for dark mode

+ + If you're using design system components, they handle dark mode automatically. + + + If your custom CSS uses design system tokens, dark mode is handled too. The tokens cascade to their dark values when data-theme="dark" is active. + +
{`.my-card {
+  background-color: var(--goa-color-surface-card);
+}`}
+ + Always verify in both modes. + + + If your custom CSS uses values that aren't from our design tokens (specific colors, backgrounds, hardcoded styles), those won't switch on their own. You can either swap them out for design tokens where possible, or extend dark mode by setting up your own custom property and overriding it under :root[data-theme="dark"]: + +
{`/* Default (light) value */
+:root {
+  --my-card-background: #f9f9f9;
+}
+
+/* Dark mode value */
+:root[data-theme="dark"] {
+  --my-card-background: #1a1a1a;
+}
+
+/* Use it in your component */
+.my-card {
+  background-color: var(--my-card-background);
+}`}
+ + + +

Using design tokens in SCSS

+ + + + Dark theme support requires CSS custom properties. Sass variables + ({`$goa-*`}) are inlined at compile time and cannot flip when the + theme changes. Reference tokens via {`var(--goa-*)`} wherever a + value should respond to theme switching. + + + + + 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. + +
{`@import "@abgov/web-components/index.css";
+@import "@abgov/design-tokens/dist/tokens.css";
+@import "@abgov/design-tokens/dist/dark-theme.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 new file mode 100644 index 0000000000..3eda4feeca --- /dev/null +++ b/docs/src/content/get-started/developers/setup.mdx @@ -0,0 +1,128 @@ +--- +id: developers/setup +title: Developer setup +navLabel: Setup +description: Set up Angular, React, or Web Components to use the GoA Design System +section: developers +order: 2 +status: published +--- +import DropInCallout from "../../../components/DropInCallout.astro"; + +Developer setup +Set up the Government of Alberta Design System in Angular, React, or directly with Web Components. + +

Angular UI components

+ + Supported versions: 18, 19, 20, 21 + + + This is the web component library and utilizes Angular's web component + integration. + + +

1. Add dependencies

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

2. Link ionicons in app/index.html

+ + Add the following in the head element: + +
{`
+`}
+ +

3. Update src/app/app.module.ts

+ + Update src/app/app.module.ts as per the four steps below: + +
{`// 1. Import the CUSTOM_ELEMENTS_SCHEMA
+import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
+
+// 2. Import the libs
+import "@abgov/web-components";
+import { AngularComponentsModule } from "@abgov/angular-components";
+
+@NgModule({
+	declarations: [AppComponent],
+	imports: [
+		// 3. Add the needed imports
+		BrowserModule,
+		AngularComponentsModule,
+	],
+	providers: [],
+	bootstrap: [AppComponent],
+	// 4. Add the CUSTOM_ELEMENTS_SCHEMA to the NgModule
+	schemas: [CUSTOM_ELEMENTS_SCHEMA],
+	})
+export class AppModule {}`}
+ +

4. Add the styles link in src/styles.css

+
@import "@abgov/web-components/index.css";
+@import "@abgov/design-tokens/dist/tokens.css";
+ + + +

React UI components

+ + Supported versions: 17, 18, 19 + + + This library contains React components which wrap the Government of Alberta Web + Components. + + +

1. Add dependencies

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

2. Link ionicons in app/index.html

+ + Add the following to the head element: + +
{`
+`}
+ +

3. Import the web components in src/main.tsx

+
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";
+ + + +

Web components

+ + This library contains web components from the Government of Alberta. + + +

1. Add dependencies

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

2. Link ionicons in index.html

+ + Add the following in the head element: + +
{`
+`}
+ +

3. Import the web components into src/main.js

+
import "@abgov/web-components";
+ +

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: + +
@import "@abgov/web-components/index.css";
+@import "@abgov/design-tokens/dist/tokens.css";
+ + + + diff --git a/docs/src/content/get-started/developers/technologies.mdx b/docs/src/content/get-started/developers/technologies.mdx new file mode 100644 index 0000000000..8078fa92a5 --- /dev/null +++ b/docs/src/content/get-started/developers/technologies.mdx @@ -0,0 +1,101 @@ +--- +id: developers/technologies +title: Technologies +description: An overview of the technologies used in the Design System +section: developers +order: 6 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../../components/DropInCallout.astro"; + +Technologies +An overview of the technologies used in the Design System. + +How the technologies fit together +

+ The Design System is built on Web Components. Most component functionality lives in the core Web + Components layer. Angular and React wrappers sit on top of that layer to make the components easier + to use in those frameworks. +

+

+ We use Svelte to author the components that are compiled to custom elements. You can use the Design + System through the core Web Components or through Angular and React wrappers. +

+Diagram showing the technology layers: Svelte compiles to Web Components, which are wrapped by Angular and React +Web Components +

+ Web Components + are a set of standard web technologies that allow you to create reusable custom elements. Each component + includes its own structure, styling, and behaviour. This keeps it independent from the rest of your code. +

+

+ In the Design System, Web Components are the core library. They are framework-agnostic, so teams + can use them in different front-end environments. +

+ +Benefits of using Web Components +
    +
  • Reuse: Build once and use across pages, applications, and frameworks
  • +
  • Browser support: Work in modern browsers without additional libraries
  • +
  • Maintenance: Modular and self-contained structure simplifies updates
  • +
  • Encapsulation: Structure, style, and behaviour remain isolated from other page elements
  • +
  • Reliability: Code is not spread across HTML and JS files, thereby avoiding inconsistencies
  • +
  • Flexibility: Use inline, import, or compile components as needed
  • +
  • Composability: Combine components or integrate them with other components
  • +
+ + + Do not use Web Components directly unless there is a specific reason to do so. Using wrappers provides type checking and developer helpers that are not available when working with the core Web Components alone. + +Svelte +

+ Svelte is the framework used to generate the + Design System Web Components. Svelte combines JavaScript (logic), HTML (structure), and CSS (style) + within a single file. It compiles these into efficient, reusable components. +

+Why Svelte +

We use Svelte to:

+
    +
  • Build reusable Web Components
  • +
  • Keep component logic, structure, and styling together
  • +
  • Support integration with multiple front-end frameworks
  • +
+Angular + + + Supported versions: 18, 19, 20, 21 + + +

+ Angular is a TypeScript-based framework for building + web applications. The Design System supports Angular through Angular wrappers around the core Web Components. +

+ +How Web Components and Angular work together +

Angular wrappers are created around the Web Components. These wrappers:

+
    +
  • Manage component properties and events
  • +
  • Support form binding (Reactive and Template-driven)
  • +
  • Allow integration within Angular applications
  • +
+

The Angular application interacts with the wrapper, which renders the underlying Web Component.

+React + + + Supported versions: 17, 18, 19 + + +

+ React is an open-source JavaScript library used to + build user interfaces from reusable components. +

+ +How Web Components and React work together +

React wrappers are created around the Web Components. These wrappers:

+
    +
  • Manage properties and events
  • +
  • Enable integration within React applications
  • +
+

The React application interacts with the wrapper, which renders the underlying Web Component.

+ diff --git a/docs/src/content/get-started/developers/updating-your-product.mdx b/docs/src/content/get-started/developers/updating-your-product.mdx new file mode 100644 index 0000000000..8e810c3758 --- /dev/null +++ b/docs/src/content/get-started/developers/updating-your-product.mdx @@ -0,0 +1,162 @@ +--- +id: developers/updating-your-product +title: Updating your product +description: The rationale and practical steps for updating your GoA product to Design System 2.0 using the developer-first approach. +section: developers +order: 4 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../../components/DropInCallout.astro"; + +Updating your product +The updated design system includes a new design language, updated design tokens and components, and new templates. For your product, updating means: +
    +
  • Your service stays aligned with the current GoA standard as more services update and users move between them
  • +
  • You get access to new component properties, examples, and templates that reduce build time for common service types
  • +
  • Your product remains supported — the legacy design system stops receiving fixes after September 2026
  • +
+

+ Most of the update applies automatically. Most of the work will be reviewing what changed in + your product and deciding where design follow-up is needed. These steps help you work through + the process. +

+ +Use the developer-first approach +

+ The developer-first approach lets you see what actually changed in your product before + committing to design work. +

+

+ When you run the update first, spacing, typography, and token changes apply automatically. You + can then review the result with your team and focus design and development effort on the screens + that need it most. This avoids redesigning screens based on assumptions about what will change + before you update. +

+ +Migration walkthrough +

+ The migration walkthrough steps through four stages — legacy design system, upgrade applied, + layout and styling fixes, and custom component updates — and shows the visual impact on your + interface at each stage. The walkthrough covers both public form and workspace product types. + Review it with your team before you start: it helps designers and developers see where changes + occur, and gives product owners a clearer picture of the scope for planning. +

+ + Explore the migration walkthrough + + +Why we recommend updating all at once +

+ Applying the update to some parts of your product but not others tends to cause the update to + stall. Teams focus on a few components then deprioritize the rest, leaving the product in a + mixed state that becomes harder to resolve over time. Reviewing your updated application + together in step 3 is designed to address this. Reviewing the full update in a branch before + committing gives your team a clear picture of the actual work involved. Use that branch to plan + your migration window — you are not committing to proceeding until you are ready. +

+ +Migration steps + +Step 1: Create a branch +

+ Create a dedicated branch for the update. Keeping it separate from your regular development + work lets your team review the changes before merging. +

+
git checkout -b ds-migration
+

Use a branch name that works for your team — this is just an example.

+ +Step 2: Run the version update +

+ Follow the steps in Setup to install the + updated packages. Run your application after installing the updates. Do this before making any + other changes. +

+ +Step 3: Review the updated application as a team +

+ Walk through your application with your product team. At this stage, the team will identify + what needs attention and decide what to prioritize. +

+

What to look for:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
AreaWhat to look for
Spacing and layoutScreens that feel too tight or unbalanced
TypographyHeadings or body text that look off in size or weight
Dense or data-heavy screensThese carry the most risk during an update and often need the most follow-up
Custom componentsAnything built outside the design system that needs manual alignment
+
+ +

+ Record what you find. A list of screens and issues is enough at this stage. Your designers and + product owner can use that output to plan and prioritize work. +

+ +Understanding the effort +

+ There is no single estimate for how long a migration takes. It varies depending on your + product. The main factors are: +

+ + + + + + + + + + + + + + + + + + + + + + + +
FactorImpact on migration effort
App sizeMore screens means more to test and review after the update
Design system utilizationProducts with more custom code need more manual alignment
Developer familiarityDevelopers with more design system experience move faster through the migration steps
+
+ +

+ Use the team review of your updated application in step 3 to build a realistic estimate for + your own product before committing to a timeline. +

+ +Getting help +
    +
  • Bring what you find when reviewing your updated application to drop-in hours to get feedback on what to prioritize
  • +
  • If you find a problem with the design system itself, reach out on the support channel rather than working around it
  • +
+ + diff --git a/docs/src/content/get-started/index.mdx b/docs/src/content/get-started/index.mdx new file mode 100644 index 0000000000..3c989ccc42 --- /dev/null +++ b/docs/src/content/get-started/index.mdx @@ -0,0 +1,97 @@ +--- +id: index +title: Start with the design system +description: Start with the design system to build on the research and experience of other service teams +section: intro +order: 1 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../components/DropInCallout.astro"; + +Start with the design system +Start with the design system to build on the research and experience of other service teams. This helps you avoid repeating work that has already been done. + + + The design system gives you a strong foundation for common service needs. It allows your team to focus on the specific challenges of your product. + Build on it. Do not start from scratch. + + +Design system by role + + + +Why start with the design system? + +Streamline collaboration +

+ Designers and developers work from shared components and guidance. This reduces rework and misalignment. +

+ +Improve accessibility +

Accessibility is built into both the design and coded components.

+ +Reduce testing effort +

Components are tested across devices, browsers, and service contexts.

+ +Maintain consistency +

+ Components align with the broader system to create a cohesive user experience across government services. +

+ +Spend more time on high-value work +

Using existing components saves time. You can focus on work that improves service quality, including:

+
    +
  • Usability testing
  • +
  • User research
  • +
  • Content design
  • +
  • Accessibility reviews
  • +
  • Design quality checks
  • +
  • Low-fidelity prototyping and testing
  • +
+

This leads to better outcomes for users.

+How to use the design system in your service +

Follow these steps when designing and building your service.

+ +Use system components first +

Start with existing components and patterns. These meet most user needs.

+ +Identify gaps through user testing +

Test your service with users. Identify needs that are not covered by current components.

+ +Before you design something new +

+ Check what's already available and what's in progress. The team can point you to existing components, + solutions other teams have built, and planned work that may meet your need. +

+ +Design and test new solutions when you need them +

+ If you still have a gap, design a new solution and test it with users. Move forward only when + testing shows clear user value. +

+ +Share what you learn +

+ Share your findings with the design system team. Your solution may become part of the design system. +

+ + + Do not create custom components without a clear user need. + Unnecessary customization: +
    +
  • Increases maintenance effort
  • +
  • Slows delivery
  • +
  • Reduces consistency
  • +
+ Always confirm the need through research and testing. +
+ + + View the design system governance process + + diff --git a/docs/src/content/get-started/migration-guide.mdx b/docs/src/content/get-started/migration-guide.mdx new file mode 100644 index 0000000000..27692407b0 --- /dev/null +++ b/docs/src/content/get-started/migration-guide.mdx @@ -0,0 +1,107 @@ +--- +id: migration-guide +title: Migration guide +description: Choose the right Design System 2.0 migration pathway for your product +section: intro +order: 5 +status: published +--- +import { withBase } from "@/lib/base-url"; + +Migration guide +Design System 2.0 (DS 2.0) becomes the Government of Alberta standard in March 2026. New products starting after launch should use DS 2.0. Existing active products should plan their move to DS 2.0 during the recommended migration window, which runs from March 2026 to September 2026. + + + +

Migration pathways

+The right migration path depends on your product's context, including team funding and capacity, other delivery obligations, product lifecycle, and the effort required to update. The three pathways are standard migration, late migration, and no migration. + +

Starting a new product

+If your product starts after March 2026, start with DS 2.0. Migration pathways apply to existing products moving from DS 1.x to DS 2.0. + +

Compare the pathways

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
PathwayUse it whenRecommendation
Standard migrationYour product has an active funded team and can migrate by September 2026Recommended default
Late migrationYour team cannot meet the standard window because of delivery timelines, dependencies, or capacity constraintsOnly when necessary
No migrationYour product does not have an active funded team and/or is not in a position to upgradeOnly in specific cases
+
+
+ +

Standard migration

+Standard migration is the default pathway for active products. +Choose this path if your product has an active funded team and can schedule migration work between March 2026 and September 2026. This is the recommended path for most teams because it keeps your product aligned with the current standard and gives you the best support. +Use this pathway when: +
    +
  • your product is actively maintained
  • +
  • your team can reserve time to migrate by September 2026
  • +
  • you want access to the latest templates, components, tokens, and guidance
  • +
+Plan for work across the product team. Typical upgrade tasks include the library updates, adjusting spacing and typography, and updating custom code to align with the DS 2.0 visual design. This is a significant update and will usually involve design, development, and testing. + +

Late migration

+Late migration is a last-resort pathway for active products. +Choose this path only when delivery deadlines, dependencies, or capacity constraints make the standard migration window unrealistic. This path gives your team more time, but it also increases risk and reduces your ongoing support. +Use this pathway when: +
    +
  • a major delivery deadline blocks migration work
  • +
  • critical dependencies prevent the upgrade during the standard window
  • +
  • capacity or funding makes the standard window unrealistic
  • +
+Delaying migration means your product will wait longer to benefit from DS 2.0 improvements. Over time, unresolved issues will accumulate and your product will be inconsistent with the new standard for longer. + +

No migration

+No migration is an opt-out pathway for specific situations. +Choose this path only when your product does not have an active funded team and/or is not in a position to upgrade. In these cases, the product may remain on DS 1.x. +Teams on this path should understand that the product will not receive DS 2.0 improvements and will not align with the current standard. Support for DS 1.x is limited from March to September and ends after September 2026. + + + +

What changes after launch

+After the DS 2.0 launch in March 2026: +
    +
  • New products should use DS 2.0
  • +
  • Active products should aim to migrate by September 2026
  • +
  • After launch, web components will move to version 2.x. Although this is a major version update, it does not include breaking changes.
  • +
  • Angular 4.x and React 6.x receive limited fixes or features from March to September
  • +
  • Support for DS 1.0 ends after September 2026
  • +
  • Web components will update to a new major version after September 2026
  • +
+ +

How to choose a pathway

+Use these questions to guide your decision: +
    +
  • Is this a new product starting after March 2026?
  • +
  • Does the product have an active funded team?
  • +
  • Can the team schedule migration work before September 2026?
  • +
  • Are there delivery deadlines or dependencies that block the standard window?
  • +
  • Is the team prepared to accept reduced support and higher maintenance risk if migration is delayed?
  • +
+ + + + Review the setup steps for developers + diff --git a/docs/src/content/get-started/out-of-support.mdx b/docs/src/content/get-started/out-of-support.mdx new file mode 100644 index 0000000000..fa61fea200 --- /dev/null +++ b/docs/src/content/get-started/out-of-support.mdx @@ -0,0 +1,43 @@ +--- +id: out-of-support +title: Out of support versions +description: Design System versions that are no longer supported +section: appendix +order: 3 +status: published +--- +import { withBase } from "@/lib/base-url"; +import DropInCallout from "../../components/DropInCallout.astro"; + +Out-of-support versions +With the launch of the new Design System, support for Angular v4 and lower, and React v6 and lower is significantly reduced. + +What this means + +Fewer fixes or patches +

Bug fixes and security updates are no longer prioritized for these versions.

+ +No new features +

All new features and enhancements are released only in the current major version.

+ +Use at your own risk +

Existing projects may continue to run. However:

+
    +
  • Compatibility with new browsers or operating systems is not guaranteed
  • +
  • Compatibility with future framework updates is not guaranteed
  • +
  • Issues discovered in these versions will not be resolved
  • +
+ + + Projects using Angular v4 and lower, and React v6 and lower will continue to function. New issues or defects identified in these versions may not be fixed. + +What to do next +

+ Upgrade to the latest supported version. Refer to the + Developer setup page. +

+

+ If you need support planning your upgrade, + book time in drop-in hours. +

+ diff --git a/docs/src/content/get-started/qa-testing.mdx b/docs/src/content/get-started/qa-testing.mdx new file mode 100644 index 0000000000..edb2d726e1 --- /dev/null +++ b/docs/src/content/get-started/qa-testing.mdx @@ -0,0 +1,67 @@ +--- +id: qa-testing +title: QA testing +description: Testing process for Design System components +section: appendix +order: 1 +status: published +--- +import DropInCallout from "../../components/DropInCallout.astro"; + +QA testing +This page outlines the testing process for the Design System. The process ensures components function correctly and integrate within products. + +Testing objectives +

QA testing ensures that:

+
    +
  • Coded components match the design specifications
  • +
  • Components work in both React and Angular implementations
  • +
  • Components are responsive across screen sizes
  • +
  • Components meet accessibility requirements
  • +
  • Mobile behaviour is validated
  • +
  • Documentation on the Design System website is accurate
  • +
+Test cases + +Component testing +
    +
  • Confirm the rendered component matches design and styling guidelines
  • +
  • Confirm configured properties display correctly
  • +
  • Confirm the expected event triggers when interacting with the component
  • +
+ +Responsiveness testing +
    +
  • Test components on mobile, tablet, and desktop screen sizes
  • +
  • Use browser developer tools to simulate devices
  • +
+ +Accessibility testing +
    +
  • Run Lighthouse audits to review accessibility scores
  • +
  • Confirm appropriate ARIA (Accessible Rich Internet Applications) roles and labels
  • +
  • Test keyboard navigation
  • +
  • Test with NVDA screen reader
  • +
+ +Cross-browser testing +
    +
  • Test on the latest versions of Chrome, Firefox, Safari, and Edge
  • +
  • Use Chrome device mode to simulate mobile environments
  • +
  • Confirm consistent appearance and behaviour across browsers
  • +
+ +Bug testing +

When a bug is fixed:

+
    +
  1. Reproduce the issue using the main branch.
  2. +
  3. Verify the fix in the pull request branch.
  4. +
  5. Retest the component across all relevant areas.
  6. +
+

Confirm the issue no longer occurs.

+Reporting +
    +
  • Document updated test results, findings, and screenshots in the pull request comments
  • +
  • Log newly discovered issues in GitHub
  • +
+ diff --git a/docs/src/content/get-started/roadmap.mdx b/docs/src/content/get-started/roadmap.mdx new file mode 100644 index 0000000000..0672ebdd37 --- /dev/null +++ b/docs/src/content/get-started/roadmap.mdx @@ -0,0 +1,127 @@ +--- +id: roadmap +title: Roadmap +description: High-level roadmap for the design system team's 2026-27 fiscal year +section: intro +order: 4 +status: published +--- + +Roadmap +A high-level summary of the work the design system team plans to focus on in the 2026-27 Fiscal Year. + +The roadmap is subject to change as we gather new information. We will communicate updates to ensure product teams can align and plan their work accordingly. + +For more details on our priorities and day-to-day activities, see our design system backlog. + + + +

Now

+Focus: Drive DS 2.0 adoption momentum, protect post-launch stability, and prove DS 2.0 helps teams move faster through prescriptive guidance and examples. + +

DS 2.0 adoption and satisfaction measurement

+Objective: Establish reliable DS 2.0 adoption tracking and reporting, and pair it with satisfaction signals from designers, developers, and end users to understand whether DS 2.0 is improving service outcomes as teams upgrade. +Benefit: Enables accurate progress reporting and provides evidence that DS 2.0 is improving usability, accessibility, and experience quality, not only adoption. +Examples: +
    +
  • Create a mechanism to reliably collect and report adoption rate
  • +
  • Track upgrade progress against the adoption schedule
  • +
  • Capture qualitative signals from teams (developer and designer feedback themes)
  • +
  • Capture end-user feedback where available (citizen or worker satisfaction, accessibility and usability feedback)
  • +
+ +

Product acceleration enablement

+Objective: Provide prescriptive guidance and resources that help teams get to screens, prototypes, and working experiences faster using DS 2.0. +Benefit: Reduces time to first screens and improves consistency by helping teams start from proven patterns instead of building from scratch. +Examples: +
    +
  • Create resources that show how to quickly prototype with DS 2.0 components and examples
  • +
  • Provide contextual starting points for teams using Public form and Workspace templates
  • +
  • Pilot DS 2.0 with teams to generate strong examples to share
  • +
  • Create and publish migration success stories
  • +
+ +

Design system MCP

+Objective: Stand up the design system Model Context Protocol (MCP) capability so AI tools and platforms can reliably access design system guidance, components, patterns, and standards. +Benefit: Helps teams generate more consistent, standards-aligned front-ends by making trusted design system context available directly in AI-assisted workflows. +Examples: +
    +
  • Define the initial MCP scope and supported design system resources
  • +
  • Stand up the MCP server and validate the hosting and maintenance approach
  • +
  • Test the MCP use in real product workflows and capture gaps to address
  • +
  • Document recommended workflows for teams
  • +
+ +

Vue support decision

+Objective: Explore and define the minimum work required to confidently state DS 2.0 officially supports Vue, including scope, constraints, and support model. +Benefit: Prevents unclear commitments and reduces strategic risk by enabling an informed investment decision aligned to organizational needs. +Examples: +
    +
  • Define what "official Vue support" means
  • +
  • Outline the minimum supportable scope
  • +
  • Identify implications for documentation, maintenance, testing, and support
  • +
+ + + +

Next

+Focus: Improve the core Public form and Workspace experience, mature reusable patterns and examples, reduce adoption friction through better packaging, and execute on the chosen Vue direction. + +

Public form and Workspace capability improvements

+Objective: Enhance key Public form and Workspace capabilities based on adoption needs and workflow requirements. +Benefit: Improves feature sets and reduces the need for custom one-off solutions by making common workflows easier to implement with DS 2.0. +Example: +
    +
  • Build the review, revise, resubmit feature
  • +
+ +

Examples and pattern maturity

+Objective: Expand and refine examples and position them as adaptable reusable patterns that teams can apply with confidence. +Benefit: Improves self-serve success and product consistency, reducing implementation variance and support demand over time. +Examples: +
    +
  • Continue expanding and refining examples
  • +
  • Show how components and examples combine into larger contexts and workflows
  • +
+ +

Library packaging and tech stack upgrades

+Objective: Reduce friction in how design system assets are bundled and adopted across libraries and update important tech stacks. +Benefit: Lowers setup and upgrade complexity, and keeps the design system up to date with the latest supported versions. +Examples: +
    +
  • Improve how code libraries are bundled together (React, web components, tokens)
  • +
  • Update to Svelte 5
  • +
+ +

Vue follow-through

+Objective: Based on Vue discovery, either implement formal Vue support or clearly position Angular and React as the recommended approach for teams using AI-assisted workflows. +Benefit: Provides clear direction to product teams and reduces uncertainty, enabling progress on a supported path while keeping support sustainable for the design system team. +Examples: +
    +
  • Publish Vue support guidance and expectations
  • +
  • Implement agreed scope if approved
  • +
  • Publish recommended alternatives if Vue support is not pursued
  • +
+ + + +

Later

+Focus: Support DS 2.0 version updates and improve documentation and communications quality to support scaling and sustainability. + +

Documentation and communications improvements

+Objective: Improve how teams access and understand design system guidance, and communicate design system value areas like accessibility more clearly. +Benefit: Increases trust, improves reuse, and supports self-serve adoption by making guidance easier to consume and share. +Examples: +
    +
  • Add markdown file download to website documentation
  • +
  • Articulate accessibility work more clearly (what is covered and how it supports teams)
  • +
+ +

Targeted capacity support for DS 2.0 version updates

+Objective: Provide targeted design system team capacity to help remaining DS 1.x product teams complete the DS 2.0 version update. +Benefit: Accelerates adoption progress and unblocks teams facing more difficult migrations, supporting adoption targets while keeping support sustainable through a focus on teams most in need. +Example: + +
    +
  • Focus migration support on late adopters facing systemic barriers to upgrading
  • +
diff --git a/docs/src/content/productTypes/public-form/index.mdx b/docs/src/content/productTypes/public-form/index.mdx new file mode 100644 index 0000000000..d74d27da0b --- /dev/null +++ b/docs/src/content/productTypes/public-form/index.mdx @@ -0,0 +1,166 @@ +--- +id: public-form +title: Public form +summary: For citizen-facing services where users apply for a benefit, request a service, or submit information. Designed around simplicity and low cognitive load, with plain-language questions, focused pages that ask one thing at a time, save-and-resume, and a clear confirmation of what happens next.
The reference example is a starting point to expand on, not a rigid template. Adapt it to fit each service's context. +heroImage: /images/examples/my-applications-page.png +demoUrl: https://digital-service-demo-v2.netlify.app/ +tags: + - form + - public + - citizen + - pattern +components: [] +status: published +--- + +View demo + +import PreviewContainer from "../../../components/PreviewContainer.astro"; + +Primary user: Citizens applying for a service, benefit, permit, or status update. + +## Pages + +A public form is built from a small set of page types. Combine and adapt them to fit the work the service supports. + +### Start page + +The starting point for a citizen to begin your form from within your service or from Alberta.ca. + + + +### Task list page (optional) + +Outline the entire process for the user and help them through it by breaking the experience into individual tasks. Use it for longer or multi-section forms. + + + +### Question page + +Ask a user a question, or a small set of closely related questions. The most common page in a public form. Several variants cover progress indicators, section titles, background context, expandable help, and grouped fields. + + + +### Review page + +Let users check their answers before submitting information to the service. Group answers by section and let the user jump back to any answer they want to change. + + + +### Result page + +Confirm to users that they have completed a form, application, or task, and tell them what to do next. + + + +--- + +## Form structure + +Use the public form structure focused on content. Asking the right questions in the right shape keeps the interaction as simple as possible. + +### Start with one idea per page + +Split the form across multiple pages with each page containing just one idea. For example: + +- one decision they have to make +- one question they have to answer +- one piece of information you are telling a user + +Starting with one thing per page helps users to: + +- understand what you are asking them to do +- focus on a specific question and its answer +- find their way through an unfamiliar process +- use the service on a mobile device +- recover easily from form errors + +It also helps the service to: + +- handle branching questions and loops +- design for mobile use +- save a user's answers automatically as they go +- capture analytics about each question + +### Combine questions when helpful + +Asking a question does not necessarily mean you should use one form field. Asking a user for their address is best captured all on the same page with multiple fields. See the [grouped fields variant on the question page](/examples/question-page#group-related-questions-on-one-page). + +--- + +## When to use + +Use the public form pattern when: + +- The service is for citizens, not internal staff +- Users may complete the form infrequently and need plain-language guidance +- The form has more than a handful of questions and benefits from being split across pages +- Branching, conditional logic, or save-and-resume matters + +--- + +## Accessibility + +Structuring your form with one idea per page simplifies the experience and makes it more accessible. + +1. **Reduced cognitive load.** Presenting only one idea at a time reduces cognitive load on the user. This is particularly beneficial for users with cognitive impairments who might find it difficult to process and respond to multiple questions at once. +2. **Improved navigation for a screen reader.** This simplified approach efficiently guides the user through the form based on each answer and makes it easier to navigate with screen readers or other assistive technology. +3. **Better error handling.** With smaller sets of questions validated at a time, errors can be identified and addressed in context. This makes it less confusing and less overwhelming, particularly for users with cognitive impairments and those using assistive technologies. +4. **Progressive disclosure.** One idea per page allows the user to focus on the current task and move through information slowly. This is especially helpful for users who are easily distracted or overwhelmed by too much information. + +--- + +## Adding complexity + +Start by making sure the content and questions you are asking the user are as simple as possible. + +As the complexity of your form grows, consider: + +- adding simple [progress indicators on a question page](/examples/question-page#show-a-progress-indicator) to communicate progress +- breaking the form into sections on a [task list page](/examples/task-list-page) + +--- + +## Form stepper + +Avoid using a traditional horizontal form stepper on every form. Research has shown that horizontal steppers shown on every page can distract and confuse some users, take up too much space, and make it hard to handle branching and conditional sections of a form. + +As the complexity of your form grows, consider: + +- adding simple text progress indicators to communicate progress +- following the one idea per page approach, and breaking the form into sections as needed using a task list page diff --git a/docs/src/content/productTypes/workspace/index.mdx b/docs/src/content/productTypes/workspace/index.mdx new file mode 100644 index 0000000000..d3b5d25f72 --- /dev/null +++ b/docs/src/content/productTypes/workspace/index.mdx @@ -0,0 +1,262 @@ +--- +id: workspace +title: Workspace +summary: The workspace is for productivity-focused services used by service delivery staff as a daily tool to review information, manage records, and complete tasks. The design prioritizes productivity, efficiency, and accuracy so staff can move through their work quickly while ensuring the best outcome for citizens and government.
Workspaces should be adapted to fit each service's context and user needs. The reference example is a starting point to expand on, not a rigid template. +heroImage: /thumbnails/workspace-preview.png +demoUrl: https://digital-service-demo-v2.netlify.app/workspace +sourceUrl: https://github.com/GovAlta/goa-workspace-playground +tags: + - workspace + - worker + - service + - case-management + - dashboard + - pattern +components: + - work-side-menu + - table + - badge + - tabs + - container + - accordion + - drawer + - button + - block +status: published +--- + +View demo + +import LinkCard from "../../../components/LinkCard.astro"; +import PreviewContainer from "../../../components/PreviewContainer.astro"; + +
+ + +
+ +Primary user: Service delivery staff + +## Pages + +Combine and adapt these to fit the work your service supports. + +### Dashboard + +The landing view of a workspace, showing staff their counts, trends, and assigned work. + + + +### Index page + +The page where staff scan and pick records to work on, with filters, search, and tabs. + + + +### Case detail + +A single-record view for reviewing and acting on one case. + + + +--- + +## Patterns + +Patterns that show up across multiple workspace pages. + +### Data views + +Workers need different ways to view, scan, and act on records depending on the task. Choose the data view that best supports the task. + +- **Table view.** Dense, scannable rows with sortable columns. Best for users who need to compare fields across many records at once. +- **Card view.** Each record as a card showing key details grouped into sections. Useful when records have more complex data that doesn't fit neatly into columns. +- **Expandable list view.** Compact rows that expand inline to reveal detail. A middle ground between the density of a table and the richness of cards. + +Any view can be combined with grouping (for example, group by priority or status) to organize records into collapsible sections. Users can also search, filter by status using [tabs](/components/tabs), sort with multi-level sorting, and manage active filters with [filter chips](/components/filter-chip). + + + + Table view with sortable columns + + + Card view of case files + + + Expandable list view with grouping + + + +### Sidebar navigation + +Use the [work side menu](/components/work-side-menu) as the primary navigation for a workspace. + +Keep top-level navigation focused on the main areas of work. When a user opens a record or case, switch to contextual navigation that supports that task. This puts the user into a focused mode with relevant navigation items (like sections of an application, comments, reminders) and a back link to return to the main view. The sidebar can adapt to what the user is doing, it doesn't have to show everything at once. + +
+
+

+ Main workspace navigation +

+ Workspace main sidebar navigation with Dashboard and Applications items +
+
+

+ Contextual case navigation +

+ Workspace contextual sidebar showing case-specific navigation items +
+
+ +### Sticky action bar + +A scroll-aware header that pins to the top of the content area as the user scrolls. Use it to keep the most important tools visible. + +Set the content for each page based on the task: + +- On a cases list page, keep tools such as search and key actions visible. +- On a detail page, keep the case name and key actions visible. + +Do not pin everything. Keep only the information and actions people need to continue their work without losing context. + +Workspace sticky action bar + +### Push drawer + +Use a [push drawer](/components/push-drawer) for focused work that should happen without leaving the current page. + +This works well for actions such as: + +- approving or denying a record +- requesting more information +- completing a short decision form +- reviewing supporting details while taking action + +Use it when users need to keep the main record in view while completing the task. + +Workspace push drawer + +--- + +## Components built for workspace + +Workspace patterns are supported by component features designed for denser, more productive interfaces: + +- **Compact inputs.** Every input component now has a `compact` variant that reduces height and spacing. This lets you build tighter forms and toolbars without sacrificing usability. +- **Compact badges and notifications.** [Badges](/components/badge) and [notification banners](/components/notification) also have compact sizing to fit within dense data views and action bars. +- **Badge variants.** [Badges](/components/badge) now include `strong` and `subtle` emphasis options, giving you control over visual weight depending on context. +- **Data grid.** The [data grid](/components/data-grid) works with the table component to support accessible, keyboard-navigable data views. Use them together when the user needs to move through records efficiently without relying on a mouse. +- **Segmented tabs.** A new [tab](/components/tab) variant that works as a segmented toggle for switching between views or modes within a workspace, rather than navigating between pages. +- **Enhanced filter chips.** [Filter chips](/components/filter-chip) now support secondary text and secondary icons, making them more useful for richer filtering in workspace data views. + +--- + +## Keyboard-accessible data views + +Workspace data views use the [data grid](/components/data-grid) to make table and card layouts fully keyboard navigable. Users can use arrow keys to move between cells and rows, making it possible to scan and act on records without a mouse. This is especially important in workspace contexts where staff are processing high volumes of cases and keyboard navigation is significantly faster than clicking. For assistive technology users, screen readers announce cell content and position as the user navigates. + +--- + +## When to use + +Use the workspace when your service needs to support regular, task-based work, such as: + +- Reviewing and processing submissions +- Managing case files, applications, or requests +- Moving between dashboards, lists, and detail views +- Taking actions such as approve, deny, assign, or request more information + +## When not to use + +- Citizen-facing services. Use the [public form](/examples/public-form) pattern instead. +- Content-only pages that do not involve case management. +- Simple internal tools that do not need structured case processing. + +--- + +## Get started + +Use one of the workspace templates as a starting point for your service. Each template includes the sidebar navigation, dashboard, data views, and case detail patterns described above. + +
+ + +
+ +--- + +## Considerations + +- The reference demo is a spike. Component customizations have not gone through the production pipeline yet. +- There should be significant variability within a workspace to meet each service's specific context and user needs. +- The demo is a starting point to expand on and adapt, not a rigid template to copy exactly. +- Desktop uses a card container pattern for the main content area. This is removed on mobile for space. diff --git a/docs/src/data/configurations/accordion.ts b/docs/src/data/configurations/accordion.ts index 2ce87e20f7..79a8d21b3e 100644 --- a/docs/src/data/configurations/accordion.ts +++ b/docs/src/data/configurations/accordion.ts @@ -144,6 +144,78 @@ export const accordionConfigurations: ComponentConfigurations = { Applications are typically processed within 10 business days. +`, + }, + }, + { + id: "filled", + name: "Filled accordion", + description: "Single accordion with filled type", + code: { + react: ` + You will need to provide proof of identity, proof of address, + and any relevant supporting documentation. +`, + angular: ` + You will need to provide proof of identity, proof of address, + and any relevant supporting documentation. +`, + webComponents: ` + You will need to provide proof of identity, proof of address, + and any relevant supporting documentation. +`, + }, + }, + { + id: "actions", + name: "Accordion with actions", + description: "Accordion with actions slot content", + code: { + react: ` + + + View all + + + } +> + + This example mixes badges and controls inside the actions slot. + +`, + angular: ` + + This example mixes badges and controls inside the actions slot. + + + + +
+ + View all +
+
`, + webComponents: ` + + This example mixes badges and controls inside the actions slot. + +
+
+ + View all +
+
`, }, }, diff --git a/docs/src/data/configurations/index.ts b/docs/src/data/configurations/index.ts index d01d86eaa0..cbfbe46429 100644 --- a/docs/src/data/configurations/index.ts +++ b/docs/src/data/configurations/index.ts @@ -54,6 +54,7 @@ export { sideMenuConfigurations } from "./side-menu"; export { sideMenuGroupConfigurations } from "./side-menu-group"; export { sideMenuHeadingConfigurations } from "./side-menu-heading"; export { workSideMenuConfigurations } from "./work-side-menu"; +export { workSideNotificationPanelConfigurations } from "./work-side-notification-panel"; export { menuButtonConfigurations } from "./menu-button"; export { appHeaderConfigurations } from "./app-header"; export { appHeaderMenuConfigurations } from "./app-header-menu"; @@ -122,6 +123,7 @@ import { sideMenuConfigurations } from "./side-menu"; import { sideMenuGroupConfigurations } from "./side-menu-group"; import { sideMenuHeadingConfigurations } from "./side-menu-heading"; import { workSideMenuConfigurations } from "./work-side-menu"; +import { workSideNotificationPanelConfigurations } from "./work-side-notification-panel"; import { menuButtonConfigurations } from "./menu-button"; import { appHeaderConfigurations } from "./app-header"; import { appHeaderMenuConfigurations } from "./app-header-menu"; @@ -196,6 +198,7 @@ export const configurationRegistry: ConfigurationRegistry = { "side-menu-group": sideMenuGroupConfigurations, "side-menu-heading": sideMenuHeadingConfigurations, "work-side-menu": workSideMenuConfigurations, + "work-side-notification-panel": workSideNotificationPanelConfigurations, "menu-button": menuButtonConfigurations, "app-header": appHeaderConfigurations, "app-header-menu": appHeaderMenuConfigurations, diff --git a/docs/src/data/configurations/push-drawer.ts b/docs/src/data/configurations/push-drawer.ts index f0d2a3ffb4..923e112b17 100644 --- a/docs/src/data/configurations/push-drawer.ts +++ b/docs/src/data/configurations/push-drawer.ts @@ -51,6 +51,7 @@ export const pushDrawerConfigurations: ComponentConfigurations = { componentSlug: "push-drawer", componentName: "Push Drawer", defaultConfigurationId: "basic", + previewStyle: "padding: 0;", configurations: [ { diff --git a/docs/src/data/configurations/shared/shared-previews.ts b/docs/src/data/configurations/shared/shared-previews.ts new file mode 100644 index 0000000000..7894d697e9 --- /dev/null +++ b/docs/src/data/configurations/shared/shared-previews.ts @@ -0,0 +1,22 @@ +/** + * Shared preview style/wrapper templates for ConfigurationPreview. + * + * Use these when a component is meant to be seen inside a larger product layout + * (e.g. work-side-menu and notification panel sit next to a workspace area). + * + * - previewStyle: CSS applied to the preview container (replaces inline cssText). + * - previewWrapper: HTML around the component. `{{slot}}` is replaced with the + * component code at render time. Only used in the preview, never in the code + * snippet shown to users. + */ + +export const workspacePreviewStyle = + "background: var(--goa-color-greyscale-50, #f8f8f8); padding: 0; display: flex; min-height: 500px;"; + +export const workspacePreviewWrapper = `
{{slot}}
+
+
+

Dashboard

+

Welcome back.

+
+
`; diff --git a/docs/src/data/configurations/temporary-notification.ts b/docs/src/data/configurations/temporary-notification.ts index 5c1bc5789e..23b64478c5 100644 --- a/docs/src/data/configurations/temporary-notification.ts +++ b/docs/src/data/configurations/temporary-notification.ts @@ -108,29 +108,40 @@ export class SomeOtherComponent { { id: "with-progress", name: "Progress and indeterminate", - description: - "Notifications for loading states (note: progress and indeterminate types may have rendering issues)", + description: "Notifications for loading states", code: { react: ` { - const uuid = TemporaryNotification.show("Uploading file...", { type: "progress" }); - TemporaryNotification.setProgress(uuid, 65); + const uuid = TemporaryNotification.show("Uploading file...", { type: "progress", duration: "long" }); + // Simulate progress; in real usage, drive this from your operation's progress events. + let progress = 0; + const interval = setInterval(() => { + progress = Math.min(progress + 10, 100); + TemporaryNotification.setProgress(uuid, progress); + if (progress >= 100) clearInterval(interval); + }, 500); }} mb="xs">Progress { - TemporaryNotification.show("Processing your request...", { type: "indeterminate" }); + TemporaryNotification.show("Processing your request...", { type: "indeterminate", duration: "long" }); }}>Indeterminate`, angular: { ts: `import { TemporaryNotification } from "@abgov/ui-components-common"; export class SomeOtherComponent { showProgress() { - const uuid = TemporaryNotification.show("Uploading file...", { type: "progress" }); - TemporaryNotification.setProgress(uuid, 65); + const uuid = TemporaryNotification.show("Uploading file...", { type: "progress", duration: "long" }); + // Simulate progress; in real usage, drive this from your operation's progress events. + let progress = 0; + const interval = setInterval(() => { + progress = Math.min(progress + 10, 100); + TemporaryNotification.setProgress(uuid, progress); + if (progress >= 100) clearInterval(interval); + }, 500); } showIndeterminate() { - TemporaryNotification.show("Processing your request...", { type: "indeterminate" }); + TemporaryNotification.show("Processing your request...", { type: "indeterminate", duration: "long" }); } }`, template: ` @@ -145,15 +156,86 @@ export class SomeOtherComponent { `, + }, + }, + { + id: "with-action", + name: "Notification with action", + description: "Notification with a clickable action button (e.g., Undo)", + code: { + react: ` + + { + TemporaryNotification.show("Item moved to trash", { + type: "basic", + duration: "long", + actionText: "Undo", + action: () => { + console.log("Undo clicked"); + }, + }); +}}>Show notification`, + angular: { + ts: `import { TemporaryNotification } from "@abgov/ui-components-common"; + +export class SomeOtherComponent { + showWithAction() { + TemporaryNotification.show("Item moved to trash", { + type: "basic", + duration: "long", + actionText: "Undo", + action: () => { + console.log("Undo clicked"); + }, + }); + } +}`, + template: ` + +Show notification`, + }, + webComponents: ` + +Show notification + +`, diff --git a/docs/src/data/configurations/types.ts b/docs/src/data/configurations/types.ts index c73938b0e7..3bd0e0a7b9 100644 --- a/docs/src/data/configurations/types.ts +++ b/docs/src/data/configurations/types.ts @@ -94,6 +94,13 @@ export interface ComponentConfigurations { /** Default configuration ID to show on page load */ defaultConfigurationId: string; + /** Optional inline CSS for the preview container (e.g. background color for workspace context) */ + previewStyle?: string; + + /** Optional HTML that wraps each config's webComponents code in the preview only (not shown in code snippet). + * Use {{slot}} as placeholder for the component code. */ + previewWrapper?: string; + /** All available configurations */ configurations: ComponentConfiguration[]; } diff --git a/docs/src/data/configurations/work-side-menu.ts b/docs/src/data/configurations/work-side-menu.ts index bfb35371e1..bae643cbef 100644 --- a/docs/src/data/configurations/work-side-menu.ts +++ b/docs/src/data/configurations/work-side-menu.ts @@ -5,11 +5,14 @@ */ import type { ComponentConfigurations } from "./types"; +import { workspacePreviewStyle, workspacePreviewWrapper } from "./shared/shared-previews"; export const workSideMenuConfigurations: ComponentConfigurations = { componentSlug: "work-side-menu", componentName: "Work side menu", defaultConfigurationId: "basic", + previewStyle: workspacePreviewStyle, + previewWrapper: workspacePreviewWrapper, configurations: [ { @@ -49,7 +52,7 @@ export const workSideMenuConfigurations: ComponentConfigurations = { { id: "with-user-profile", name: "With user profile", - description: "Menu showing user name and role", + description: "Menu showing user name and role with an account menu", code: { react: ` } + accountContent={ + <> + + + + + } />`, - angular: ` - - - - -`, + angular: ` + + + + + + + + + + +`, webComponents: ` - - + + + `, }, }, diff --git a/docs/src/data/configurations/work-side-notification-panel.ts b/docs/src/data/configurations/work-side-notification-panel.ts new file mode 100644 index 0000000000..ac467b5420 --- /dev/null +++ b/docs/src/data/configurations/work-side-notification-panel.ts @@ -0,0 +1,784 @@ +/** + * WorkSideNotificationPanel Component Configurations + * + * Notification center panel used within a work side menu item's popover. + */ + +import type { ComponentConfigurations } from "./types"; +import { workspacePreviewStyle, workspacePreviewWrapper } from "./shared/shared-previews"; + +export const workSideNotificationPanelConfigurations: ComponentConfigurations = { + componentSlug: "work-side-notification-panel", + componentName: "Notification panel", + defaultConfigurationId: "basic", + previewStyle: workspacePreviewStyle, + previewWrapper: workspacePreviewWrapper, + + configurations: [ + { + id: "basic", + name: "Basic notification panel", + description: + "Panel with a mix of read and unread notifications in a work side menu", + code: { + react: { + ts: `const initialItems: (GoabWorkSideNotificationItemProps & { id: string })[] = [ + { + id: "1", + title: "New case assigned", + description: "Case #12345 has been assigned to you for review.", + timestamp: "2025-03-15T10:30:00Z", + type: "info", + readStatus: "unread", + priority: "normal", + }, + { + id: "2", + title: "Document uploaded", + description: "A new document was uploaded to Case #12340.", + timestamp: "2025-03-15T09:15:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + { + id: "3", + title: "Case resolved", + description: "Case #12330 has been marked as resolved.", + timestamp: "2025-03-14T16:00:00Z", + type: "success", + readStatus: "read", + priority: "normal", + }, +]; + +const [items, setItems] = useState(initialItems); + +const handleMarkAllRead = () => { + setItems((items) => items.map((item) => ({ ...item, readStatus: "read" }))); +}; + +const handleViewAll = () => { + console.log("view all"); +}; + +const handleClick = (id: string) => { + setItems((items) => + items.map((item) => (item.id === id ? { ...item, readStatus: "read" } : item)), + ); +};`, + jsx: ` navigate(path)} + primaryContent={ + <> + + + + } + secondaryContent={ + + {items.map(({ id, ...item }) => ( + handleClick(id)} + /> + ))} + + } + /> + } +/>`, + }, + angular: { + ts: `interface NotificationItem { + id: string; + title: string; + description: string; + timestamp: string; + type: GoabWorkSideNotificationItemType; + readStatus: GoabWorkSideNotificationReadStatus; + priority: GoabWorkSideNotificationPriority; +} + +export class SomeOtherComponent { + items: NotificationItem[] = [ + { + id: "1", + title: "New case assigned", + description: "Case #12345 has been assigned to you for review.", + timestamp: "2025-03-15T10:30:00Z", + type: "info", + readStatus: "unread", + priority: "normal", + }, + { + id: "2", + title: "Document uploaded", + description: "A new document was uploaded to Case #12340.", + timestamp: "2025-03-15T09:15:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + { + id: "3", + title: "Case resolved", + description: "Case #12330 has been marked as resolved.", + timestamp: "2025-03-14T16:00:00Z", + type: "success", + readStatus: "read", + priority: "normal", + }, + ]; + + handleMarkAllRead() { + this.items = this.items.map((item) => ({ ...item, readStatus: "read" })); + } + + handleViewAll() { + console.log("view all"); + } + + handleClick(id: string) { + this.items = this.items.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ); + } +}`, + template: ` + + + + + + + + + + + + + @for (item of items; track item.id) { + + } + +`, + }, + webComponents: { + html: ` + + + + + + + + + +`, + js: `const panel = container.querySelector("goa-work-side-notification-panel"); +const items = container.querySelectorAll("goa-work-side-notification-item"); + +items.forEach((item) => { + item.addEventListener("_click", () => { + item.setAttribute("read-status", "read"); + }); +}); + +panel.addEventListener("_markAllRead", () => { + items.forEach((item) => item.setAttribute("read-status", "read")); +}); + +panel.addEventListener("_viewAll", () => { + console.log("view all"); +});`, + }, + }, + }, + { + id: "urgent-notifications", + name: "With urgent notifications", + description: "Menu with urgent priority notifications in the panel", + code: { + react: { + ts: `const initialItems: (GoabWorkSideNotificationItemProps & { id: string })[] = [ + { + id: "1", + title: "System maintenance", + description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.", + timestamp: "2025-03-15T14:00:00Z", + type: "critical", + readStatus: "unread", + priority: "urgent", + }, + { + id: "2", + title: "Deadline approaching", + description: "Case #12345 response is due in 2 hours.", + timestamp: "2025-03-15T12:00:00Z", + type: "warning", + readStatus: "unread", + priority: "urgent", + }, + { + id: "3", + title: "New comment on case", + description: "A team member commented on Case #12340.", + timestamp: "2025-03-15T11:00:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, +]; + +const [items, setItems] = useState(initialItems); + +const handleMarkAllRead = () => { + setItems((items) => items.map((item) => ({ ...item, readStatus: "read" }))); +}; + +const handleViewAll = () => { + console.log("view all"); +}; + +const handleClick = (id: string) => { + setItems((items) => + items.map((item) => (item.id === id ? { ...item, readStatus: "read" } : item)), + ); +};`, + jsx: ` navigate(path)} + primaryContent={ + <> + + + + } + secondaryContent={ + + {items.map(({ id, ...item }) => ( + handleClick(id)} + /> + ))} + + } + /> + } +/>`, + }, + angular: { + ts: `interface NotificationItem { + id: string; + title: string; + description: string; + timestamp: string; + type: GoabWorkSideNotificationItemType; + readStatus: GoabWorkSideNotificationReadStatus; + priority: GoabWorkSideNotificationPriority; +} + +export class SomeOtherComponent { + items: NotificationItem[] = [ + { + id: "1", + title: "System maintenance", + description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.", + timestamp: "2025-03-15T14:00:00Z", + type: "critical", + readStatus: "unread", + priority: "urgent", + }, + { + id: "2", + title: "Deadline approaching", + description: "Case #12345 response is due in 2 hours.", + timestamp: "2025-03-15T12:00:00Z", + type: "warning", + readStatus: "unread", + priority: "urgent", + }, + { + id: "3", + title: "New comment on case", + description: "A team member commented on Case #12340.", + timestamp: "2025-03-15T11:00:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + ]; + + handleMarkAllRead() { + this.items = this.items.map((item) => ({ ...item, readStatus: "read" })); + } + + handleViewAll() { + console.log("view all"); + } + + handleClick(id: string) { + this.items = this.items.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ); + } +}`, + template: ` + + + + + + + + + + + + + @for (item of items; track item.id) { + + } + +`, + }, + webComponents: { + html: ` + + + + + + + + + +`, + js: `const panel = container.querySelector("goa-work-side-notification-panel"); +const items = container.querySelectorAll("goa-work-side-notification-item"); + +items.forEach((item) => { + item.addEventListener("_click", () => { + item.setAttribute("read-status", "read"); + }); +}); + +panel.addEventListener("_markAllRead", () => { + items.forEach((item) => item.setAttribute("read-status", "read")); +}); + +panel.addEventListener("_viewAll", () => { + console.log("view all"); +});`, + }, + }, + }, + { + id: "notification-types", + name: "Notification type badges", + description: "All notification item type variants with their badge icons", + code: { + react: { + ts: `const initialItems: (GoabWorkSideNotificationItemProps & { id: string })[] = [ + { + id: "1", + title: "New comment on case", + description: "A team member commented on Case #12340.", + timestamp: "2025-03-15T10:00:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + { + id: "2", + title: "Case #12345 assigned", + description: "Case #12345 has been assigned to you for review.", + timestamp: "2025-03-15T09:00:00Z", + type: "info", + readStatus: "unread", + priority: "normal", + }, + { + id: "3", + title: "Case resolved", + description: "Case #12330 has been marked as resolved.", + timestamp: "2025-03-15T08:00:00Z", + type: "success", + readStatus: "unread", + priority: "normal", + }, + { + id: "4", + title: "Deadline approaching", + description: "Case #12345 response is due in 2 hours.", + timestamp: "2025-03-15T07:00:00Z", + type: "warning", + readStatus: "unread", + priority: "normal", + }, + { + id: "5", + title: "System maintenance", + description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.", + timestamp: "2025-03-15T06:00:00Z", + type: "critical", + readStatus: "unread", + priority: "normal", + }, +]; + +const [items, setItems] = useState(initialItems); + +const handleMarkAllRead = () => { + setItems((items) => items.map((item) => ({ ...item, readStatus: "read" }))); +}; + +const handleViewAll = () => { + console.log("view all"); +}; + +const handleClick = (id: string) => { + setItems((items) => + items.map((item) => (item.id === id ? { ...item, readStatus: "read" } : item)), + ); +};`, + jsx: ` navigate(path)} + primaryContent={ + + } + secondaryContent={ + + {items.map(({ id, ...item }) => ( + handleClick(id)} + /> + ))} + + } + /> + } +/>`, + }, + angular: { + ts: `interface NotificationItem { + id: string; + title: string; + description: string; + timestamp: string; + type: GoabWorkSideNotificationItemType; + readStatus: GoabWorkSideNotificationReadStatus; + priority: GoabWorkSideNotificationPriority; +} + +export class SomeOtherComponent { + items: NotificationItem[] = [ + { + id: "1", + title: "New comment on case", + description: "A team member commented on Case #12340.", + timestamp: "2025-03-15T10:00:00Z", + type: "default", + readStatus: "unread", + priority: "normal", + }, + { + id: "2", + title: "Case #12345 assigned", + description: "Case #12345 has been assigned to you for review.", + timestamp: "2025-03-15T09:00:00Z", + type: "info", + readStatus: "unread", + priority: "normal", + }, + { + id: "3", + title: "Case resolved", + description: "Case #12330 has been marked as resolved.", + timestamp: "2025-03-15T08:00:00Z", + type: "success", + readStatus: "unread", + priority: "normal", + }, + { + id: "4", + title: "Deadline approaching", + description: "Case #12345 response is due in 2 hours.", + timestamp: "2025-03-15T07:00:00Z", + type: "warning", + readStatus: "unread", + priority: "normal", + }, + { + id: "5", + title: "System maintenance", + description: "Scheduled maintenance tonight at 11 PM. All services will be unavailable.", + timestamp: "2025-03-15T06:00:00Z", + type: "critical", + readStatus: "unread", + priority: "normal", + }, + ]; + + handleMarkAllRead() { + this.items = this.items.map((item) => ({ ...item, readStatus: "read" })); + } + + handleViewAll() { + console.log("view all"); + } + + handleClick(id: string) { + this.items = this.items.map((item) => + item.id === id ? { ...item, readStatus: "read" } : item, + ); + } +}`, + template: ` + + + + + + + + + + + + @for (item of items; track item.id) { + + } + +`, + }, + webComponents: { + html: ` + + + + + + + + + + +`, + js: `const panel = container.querySelector("goa-work-side-notification-panel"); +const items = container.querySelectorAll("goa-work-side-notification-item"); + +items.forEach((item) => { + item.addEventListener("_click", () => { + item.setAttribute("read-status", "read"); + }); +}); + +panel.addEventListener("_markAllRead", () => { + items.forEach((item) => item.setAttribute("read-status", "read")); +}); + +panel.addEventListener("_viewAll", () => { + console.log("view all"); +});`, + }, + }, + }, + ], +}; diff --git a/docs/src/hooks/index.ts b/docs/src/hooks/index.ts index 652c65f682..e61376a796 100644 --- a/docs/src/hooks/index.ts +++ b/docs/src/hooks/index.ts @@ -5,3 +5,4 @@ export { useTwoLevelSort, type SortConfig, type SortLevel } from './useTwoLevelSort'; export { useCompactToolbar, useMobile, COMPACT_TOOLBAR_BREAKPOINT, MOBILE_BREAKPOINT } from './useCompactToolbar'; export { useViewSettings, type ViewSettings, type LayoutType, type GroupByField } from './useViewSettings'; +export { useIsDarkMode } from './useIsDarkMode'; diff --git a/docs/src/hooks/useIsDarkMode.ts b/docs/src/hooks/useIsDarkMode.ts new file mode 100644 index 0000000000..24afeb84cd --- /dev/null +++ b/docs/src/hooks/useIsDarkMode.ts @@ -0,0 +1,42 @@ +/** + * useIsDarkMode.ts + * + * Watches the active theme via the `data-theme` attribute on . + * Returns true when in dark mode. Reacts to toggle changes via MutationObserver. + * + * Why read from the DOM attribute instead of localStorage: + * - The pre-paint script in BaseLayout.astro sets `data-theme` from + * localStorage > prefers-color-scheme > "light", so the attribute is + * the source of truth for what's currently rendered. + * - localStorage has no in-tab change event; MutationObserver on the + * attribute is the cleanest way to react to toggle in other islands. + * - localStorage may be blocked (private mode, sandboxed iframe); the + * DOM attribute is always set. + * + * Astro islands cannot share React context, so the DOM attribute is the + * cross-island sync channel for theme. + */ + +import { useEffect, useState } from "react"; + +export function useIsDarkMode(): boolean { + const [isDark, setIsDark] = useState( + () => + typeof document !== "undefined" && + document.documentElement.getAttribute("data-theme") === "dark", + ); + + useEffect(() => { + if (typeof document === "undefined") return; + const observer = new MutationObserver(() => { + setIsDark(document.documentElement.getAttribute("data-theme") === "dark"); + }); + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ["data-theme"], + }); + return () => observer.disconnect(); + }, []); + + return isDark; +} diff --git a/docs/src/layouts/BaseLayout.astro b/docs/src/layouts/BaseLayout.astro index b9f9d3fa4c..0f9905158d 100644 --- a/docs/src/layouts/BaseLayout.astro +++ b/docs/src/layouts/BaseLayout.astro @@ -2,6 +2,7 @@ // 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 search styles eagerly so inline search inputs don't flash unstyled import '../components/search/search.css'; @@ -26,6 +27,24 @@ const ogUrl = new URL(withBase(Astro.url.pathname), Astro.site).href; + + + + + + + +
+ + + {backLabel} + + +
+ {reactSourceUrl && ( + + + + )} + {angularSourceUrl && ( + + + + )} +
+
+ +
+ +
+ + + + diff --git a/docs/src/layouts/TokensLayout.astro b/docs/src/layouts/TokensLayout.astro index 6549a769aa..c7e73a8e36 100644 --- a/docs/src/layouts/TokensLayout.astro +++ b/docs/src/layouts/TokensLayout.astro @@ -16,6 +16,7 @@ import Breadcrumbs from '../components/Breadcrumbs.astro'; import { SiteNav } from '../components/SiteNav'; import { MobileHeader } from '../components/MobileHeader'; import { getNavCategories } from '../lib/nav-categories'; +import { getGetStartedNav } from '../lib/get-started-nav'; interface Props { title: string; @@ -24,6 +25,7 @@ interface Props { const { title, description } = Astro.props; const navCategories = await getNavCategories(); +const getStartedNav = await getGetStartedNav(); --- @@ -36,6 +38,7 @@ const navCategories = await getNavCategories(); client:only="react" initialSection="tokens" categories={navCategories} + getStartedNav={getStartedNav} /> diff --git a/docs/src/lib/base-url.ts b/docs/src/lib/base-url.ts index 1ea988dbab..47e91e8df0 100644 --- a/docs/src/lib/base-url.ts +++ b/docs/src/lib/base-url.ts @@ -3,6 +3,8 @@ export const BASE_URL = import.meta.env.BASE_URL; export function withBase(path: string): string { if (!path) return BASE_URL; if (path.startsWith("http://") || path.startsWith("https://")) return path; + // Idempotent: skip if path is already prefixed with BASE_URL. + if (BASE_URL !== "/" && path.startsWith(BASE_URL)) return path; const clean = path.startsWith("/") ? path.slice(1) : path; return `${BASE_URL}${clean}`; } diff --git a/docs/src/lib/content-queries.ts b/docs/src/lib/content-queries.ts index 2be5abcf8e..c3a8ac8fdf 100644 --- a/docs/src/lib/content-queries.ts +++ b/docs/src/lib/content-queries.ts @@ -9,6 +9,7 @@ export interface PropDefinition { required: boolean; default: string | null; description: string; + deprecated?: boolean; } export interface EventDefinition { @@ -20,24 +21,34 @@ export interface EventDefinition { export interface SlotDefinition { name: string; + type?: string; description: string; + required?: boolean; +} + +export interface FrameworkApiData { + props: PropDefinition[]; + events: EventDefinition[]; + slots: SlotDefinition[]; +} + +export interface FrameworkApiMap { + react: FrameworkApiData; + angular: FrameworkApiData; + webComponents: FrameworkApiData; } export interface SubComponentApi { name: string; webComponentTag: string; description: string; - props: PropDefinition[]; - events: EventDefinition[]; - slots: SlotDefinition[]; + frameworks: FrameworkApiMap; } export interface ComponentApi { componentSlug: string; extractedFrom: string; - props: PropDefinition[]; - events: EventDefinition[]; - slots: SlotDefinition[]; + frameworks: FrameworkApiMap; subComponents?: SubComponentApi[]; } @@ -89,7 +100,9 @@ export async function getExamplesForComponent( ): Promise[]> { const allExamples = await getCollection("examples"); - return allExamples.filter((example) => example.data.components.includes(componentSlug)); + return allExamples.filter( + (example) => !example.data.hidden && example.data.components.includes(componentSlug), + ); } /** @@ -165,7 +178,7 @@ export async function getContentByTag(tag: string) { return { components: components.filter((c) => c.data.tags?.includes(tag)), guidance: guidance.filter((g) => g.data.tags?.includes(tag)), - examples: examples.filter((e) => e.data.tags?.includes(tag)), + examples: examples.filter((e) => !e.data.hidden && e.data.tags?.includes(tag)), }; } diff --git a/docs/src/lib/example-size.ts b/docs/src/lib/example-size.ts new file mode 100644 index 0000000000..133656c6d3 --- /dev/null +++ b/docs/src/lib/example-size.ts @@ -0,0 +1,13 @@ +/** + * Page-scale entries (page, task, product) render a PreviewContainer + * card linking to the entry's docs page rather than an inline sandbox, + * because their composition usually depends on app shell, mock data, or + * external sources that don't render usefully inline. Section and + * interaction snippets render inline with a sandbox plus framework code + * tabs. + */ +const PAGE_SCALES = ["page", "task", "product"] as const; + +export function isPageScale(size: string): boolean { + return (PAGE_SCALES as readonly string[]).includes(size); +} diff --git a/docs/src/lib/get-started-nav.ts b/docs/src/lib/get-started-nav.ts new file mode 100644 index 0000000000..d73df4cb40 --- /dev/null +++ b/docs/src/lib/get-started-nav.ts @@ -0,0 +1,77 @@ +/** + * get-started-nav.ts + * + * Builds the Get Started submenu structure from the content collection. + * Used by layouts to pass nav data to SiteNav -> GetStartedSubMenu. + * + * Section convention: + * - "intro" => top-level pages above grouped sections + * - "designers" => Designers group + * - "developers" => Developers group + * - "appendix" => top-level pages below grouped sections + */ + +import { getCollection } from "astro:content"; + +export interface GetStartedNavItem { + label: string; + url: string; +} + +export interface GetStartedNavGroup { + name: string; + slug: string; + pages: GetStartedNavItem[]; +} + +export interface GetStartedNav { + topPages: GetStartedNavItem[]; + groups: GetStartedNavGroup[]; + bottomPages: GetStartedNavItem[]; +} + +/** Display metadata for the grouped sections (not stored in content collection) */ +const GROUP_META: Record = { + designers: { name: "Designers" }, + developers: { name: "Developers" }, +}; + +/** Canonical display order for grouped sections in the submenu */ +const GROUP_ORDER = ["designers", "developers"]; + +function entryToItem(entry: { + slug: string; + data: { title: string; navLabel?: string }; +}): GetStartedNavItem { + return { + label: entry.data.navLabel ?? entry.data.title, + url: entry.slug === "index" ? "/get-started" : `/get-started/${entry.slug}`, + }; +} + +function bySection( + entries: Awaited>>, + section: string, +): typeof entries { + return entries + .filter((e) => e.data.section === section) + .sort((a, b) => a.data.order - b.data.order); +} + +export async function getGetStartedNav(): Promise { + const entries = await getCollection("get-started"); + const published = entries.filter((e) => e.data.status !== "deprecated"); + + const topPages = bySection(published, "intro").map(entryToItem); + const bottomPages = bySection(published, "appendix").map(entryToItem); + + const groups = GROUP_ORDER.filter((slug) => + published.some((e) => e.data.section === slug), + ).map((slug) => ({ + name: GROUP_META[slug].name, + slug, + pages: bySection(published, slug).map(entryToItem), + })); + + return { topPages, groups, bottomPages }; +} diff --git a/docs/src/lib/tokens.ts b/docs/src/lib/tokens.ts index e36d74171b..ce244064dd 100644 --- a/docs/src/lib/tokens.ts +++ b/docs/src/lib/tokens.ts @@ -29,6 +29,10 @@ export interface FlatToken { isColor: boolean; /** Description if available */ description?: string; + /** Dark mode "as defined" value (only set if token is themed). */ + darkValue?: string; + /** Dark mode resolved value (only set if token is themed). */ + darkResolvedValue?: string; } /** @@ -98,15 +102,35 @@ function boxShadowToCss(shadow: { } /** - * Format a token value for display + * Check if a value is a themed value (has `light` and `dark` keys). + * These are emitted by Style Dictionary for tokens that flip between modes. + * The inner values may be strings (e.g. colors) or objects (e.g. box shadows). */ -function formatValue(value: string | number | object): string { +function isThemedValue(value: unknown): value is { light: unknown; dark: unknown } { + return ( + typeof value === "object" && + value !== null && + "light" in value && + "dark" in value + ); +} + +/** + * Format a token value for display. For themed `{ light, dark }` values, + * returns the light variant (recursively formatted, so themed box-shadow + * objects, themed strings, etc. all flatten correctly). + */ +function formatValue(value: unknown): string { if (typeof value === "string") { return value; } if (typeof value === "number") { return String(value); } + // Themed value: recurse on the light variant + if (isThemedValue(value)) { + return formatValue(value.light); + } // Convert box-shadow objects to CSS syntax if (isBoxShadowObject(value)) { return boxShadowToCss(value); @@ -213,7 +237,10 @@ function flattenTokensRecursive( const tokenPath = currentPath.slice(1).join("/"); const tokenType = value.type || "unknown"; - // Keep original value, resolve for preview + // Detect themed { light, dark } shape, split into separate light + dark fields. + const themed = isThemedValue(value.value) ? value.value : null; + + // Keep original value, resolve for preview (light by default for themed values) const rawValue = formatValue(value.value); let resolvedValue: string; @@ -226,6 +253,18 @@ function flattenTokensRecursive( typeof rawValue === "string" ? resolveTokenReference(rawValue, rootTokens) : rawValue; } + // Resolve dark variant if the value is themed + let darkValue: string | undefined; + let darkResolvedValue: string | undefined; + if (themed) { + // Themed inner value may be a string, box-shadow object, etc. + // Formatting recursively lets it produce a CSS string for any shape. + darkValue = formatValue(themed.dark); + darkResolvedValue = isTokenReference(darkValue) + ? resolveTokenReference(darkValue, rootTokens) + : darkValue; + } + const isColor = tokenType === "color" || (typeof resolvedValue === "string" && resolvedValue.startsWith("#")); @@ -239,6 +278,8 @@ function flattenTokensRecursive( type: tokenType, isColor, description: value.description, + darkValue, + darkResolvedValue, }); } else if (typeof value === "object" && value !== null) { // Recurse into nested object diff --git a/docs/src/pages/components/[slug].astro b/docs/src/pages/components/[slug].astro index 5929614b2c..3c3b3641dc 100644 --- a/docs/src/pages/components/[slug].astro +++ b/docs/src/pages/components/[slug].astro @@ -112,13 +112,13 @@ const v1DocsUrl = `https://v1.design.alberta.ca/components/${slug}`; {api ? ( <> - + {api.subComponents && api.subComponents.length > 0 && ( api.subComponents.map((sub) => (

{sub.name}

{sub.description}

- +
)) )} @@ -130,7 +130,12 @@ const v1DocsUrl = `https://v1.design.alberta.ca/components/${slug}`; )} {subcomponents.map((sub) => (
- +
))}
diff --git a/docs/src/pages/examples/[family]/[page]/index.astro b/docs/src/pages/examples/[family]/[page]/index.astro new file mode 100644 index 0000000000..a5da1c88d6 --- /dev/null +++ b/docs/src/pages/examples/[family]/[page]/index.astro @@ -0,0 +1,134 @@ +--- +/** + * Template Detail Page + * + * Deep dive for a single template or sub-pattern. + * Hero with preview image plus a thin action bar (Live preview, Source, StackBlitz), + * followed by MDX body (when to use, considerations, components used, etc.). + * No framework code tabs at this scale. Source link goes to GitHub. + */ +import { getCollection, render } from 'astro:content'; +import ExamplesPageLayout from '../../../../layouts/ExamplesPageLayout.astro'; +import Breadcrumbs from '../../../../components/Breadcrumbs.astro'; +import PreviewContainer from '../../../../components/PreviewContainer.astro'; + +export async function getStaticPaths() { + const examples = await getCollection('examples'); + // Nested page-scale entries whose slug is "/". Today's + // set: workspace/dashboard, workspace/index-page, workspace/case-detail. + const nested = examples.filter((e) => e.slug.includes('/') && e.data.size === 'page'); + return nested.map((entry) => { + const [family, page] = entry.slug.split('/'); + return { + params: { family, page }, + props: { entry }, + }; + }); +} + +const { entry } = Astro.props; +const { Content } = await render(entry); +const { data } = entry; +const { family, page } = Astro.params; +// data is narrowed to the page-shape by the getStaticPaths filter +const pageData = data as Extract; + +// Emit a Live preview URL so the action bar renders consistently with +// the family overview. Whether the preview iframes an external demo +// (workspace) or renders locally (page-scale templates) is decided +// by the preview route itself. +const internalPreviewUrl = `/examples/${family}/${page}/preview`; +--- + + +
+ +
+
+ + {pageData.frameworks?.map((f: string) => ( + + ))} +
+

{data.title}

+ {data.description &&

} +

+ + + +
+ +
+
+
+ + diff --git a/docs/src/pages/examples/[family]/[page]/preview.astro b/docs/src/pages/examples/[family]/[page]/preview.astro new file mode 100644 index 0000000000..4933cfec2d --- /dev/null +++ b/docs/src/pages/examples/[family]/[page]/preview.astro @@ -0,0 +1,61 @@ +--- +/** + * Template Live Preview + * + * Standalone full-viewport preview of a template. Iframes the template's + * configured previewUrl (typically the workspace demo app) and wraps it + * with a minimal top bar so users can navigate back to the docs. This is + * the "isolated preview" distinct from the full working demo linked via + * the "View demo" CTA in the walkthrough. + */ +import { getCollection } from 'astro:content'; +import PreviewLayout from "../../../../layouts/PreviewLayout.astro"; + +export async function getStaticPaths() { + const examples = await getCollection('examples'); + // Nested examples with a previewUrl: the page-detail route wires the + // Live preview button here, and this route iframes the externally-hosted demo. + const nested = examples.filter( + (e) => e.slug.includes('/') && e.data.size === 'page' && e.data.previewUrl, + ); + return nested.map((entry) => { + const [family, page] = entry.slug.split('/'); + return { + params: { family, page }, + props: { entry }, + }; + }); +} + +const { entry } = Astro.props; +const { data } = entry; +const { family, page } = Astro.params; +const backUrl = `/examples/${family}/${page}`; +const backLabel = `Back to ${data.title}`; +const pageData = data as Extract; +--- + + + + + + diff --git a/docs/src/pages/examples/[family]/index.astro b/docs/src/pages/examples/[family]/index.astro new file mode 100644 index 0000000000..c7d45a0b16 --- /dev/null +++ b/docs/src/pages/examples/[family]/index.astro @@ -0,0 +1,150 @@ +--- +/** + * Service Type Overview Page + * + * Landing page for a service type. Renders the MDX body of the matching + * entry in the `productTypes` collection (workspace, public-form). Follows + * the flexible-doc-page pattern: prose walkthrough with inline demo CTAs, + * images, and links to nested example pages. + */ +import { getCollection, render } from 'astro:content'; +import ExamplesPageLayout from '../../../layouts/ExamplesPageLayout.astro'; +import Breadcrumbs from '../../../components/Breadcrumbs.astro'; +import { TableOfContents } from '../../../components/TableOfContents'; + +export async function getStaticPaths() { + const productTypes = await getCollection('productTypes'); + return productTypes.map((entry) => ({ + params: { family: entry.data.id }, + props: { entry }, + })); +} + +const { entry } = Astro.props; +const { Content } = await render(entry); +const { data } = entry; + +// Family overview cover shows the whole demo app, not a single-page preview, +// so no Live preview button. View demo alone covers the CTA. +--- + + +
+ +
+
+
+

{data.title}

+ {data.summary &&

} +

+ +
+ +
+
+
+ + diff --git a/docs/src/pages/examples/[family]/preview.astro b/docs/src/pages/examples/[family]/preview.astro new file mode 100644 index 0000000000..73c3a161d2 --- /dev/null +++ b/docs/src/pages/examples/[family]/preview.astro @@ -0,0 +1,48 @@ +--- +/** + * Family Live Preview + * + * Standalone full-viewport preview of a template family's main demo route. + * Same chrome as [page]/preview.astro so the family overview's "Live preview" + * button lands on the same shape as the detail pages' buttons. + */ +import { getCollection } from 'astro:content'; +import PreviewLayout from "../../../layouts/PreviewLayout.astro"; + +export async function getStaticPaths() { + const productTypes = await getCollection('productTypes'); + const withDemo = productTypes.filter((entry) => entry.data.demoUrl); + return withDemo.map((entry) => ({ + params: { family: entry.data.id }, + props: { entry }, + })); +} + +const { entry } = Astro.props; +const { data } = entry; +const backUrl = `/examples/${data.id}`; +const backLabel = `Back to ${data.title}`; +--- + + + + + + diff --git a/docs/src/pages/examples/[slug].astro b/docs/src/pages/examples/[slug].astro index 930c953abf..65618d4881 100644 --- a/docs/src/pages/examples/[slug].astro +++ b/docs/src/pages/examples/[slug].astro @@ -13,17 +13,21 @@ import { getCollection, render } from 'astro:content'; import ExamplesPageLayout from '../../layouts/ExamplesPageLayout.astro'; import Breadcrumbs from '../../components/Breadcrumbs.astro'; import ExampleDisplay from '../../components/ExampleDisplay.astro'; +import PreviewContainer from '../../components/PreviewContainer.astro'; import { TableOfContents } from '../../components/TableOfContents'; import { getExampleCode } from '../../lib/example-code'; +import { isPageScale } from '../../lib/example-size'; - -// Generate static paths for all examples +// Generate static paths for flat examples only. Nested entries +// (workspace/dashboard, etc) are handled by [family]/[page]/index.astro. export async function getStaticPaths() { const examples = await getCollection('examples'); - return examples.map((example) => ({ - params: { slug: example.slug }, - props: { example }, - })); + return examples + .filter((example) => !example.slug.includes('/') && !example.data.hidden) + .map((example) => ({ + params: { slug: example.slug }, + props: { example }, + })); } const { example } = Astro.props; @@ -37,37 +41,48 @@ const { Content } = await render(example); const code = await getExampleCode(example.slug); const hasCode = !!(code.react || code.angular || code.webComponents); +// Page-and-larger entries render with a PreviewContainer at the top instead +// of framework code tabs, mirroring the workspace page detail shape. The +// framework files still exist on disk and are linked via GitHub. +// Section-sized entries keep the sandbox + framework tabs treatment. +const pageScale = isPageScale(data.size); +const showCodeTabs = !pageScale && hasCode; +const useTopPreview = pageScale && data.previewImage && !data.hideHero; +const githubBlobBase = 'https://github.com/GovAlta/ui-components/blob/dev/docs/src/content/examples'; +const githubTreeBase = 'https://github.com/GovAlta/ui-components/tree/dev/docs/src/content/examples'; +type WithSourceUrls = { reactSourceUrl?: string; angularSourceUrl?: string; previewUrl?: string }; +const pageData = data as typeof data & WithSourceUrls; +const reactSourceUrl = + pageData.reactSourceUrl ?? (code.react ? `${githubBlobBase}/${slug}/react.tsx` : undefined); +const angularSourceUrl = + pageData.angularSourceUrl ?? (code.angular ? `${githubTreeBase}/${slug}` : undefined); +// /examples/[slug]/preview.astro auto-generates a Live preview route for +// every flat-slug page-scale entry with a sibling react.tsx. So if this +// entry has React code, link the PreviewContainer image to its preview. +const previewUrl = + pageData.previewUrl ?? (pageScale && code.react ? `/examples/${slug}/preview` : undefined); + // Get related examples if defined let relatedExamples: typeof example[] = []; if (data.relatedExamples?.length) { const allExamples = await getCollection('examples'); relatedExamples = allExamples.filter(e => + !e.data.hidden && data.relatedExamples?.includes(e.data.id) ); } -// Format category for display -function formatCategory(category: string): string { - return category +// Format size for display ("page" -> "Page", "component" -> "Component", "digital-service" -> "Digital service") +function formatSize(size: string): string { + return size .split('-') - .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .map((word, i) => (i === 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word)) .join(' '); } -// Format scale for display -function formatScale(scale: string): string { - return scale.charAt(0).toUpperCase() + scale.slice(1); -} - -// Format user type for display -function formatUserType(userType: string): string { - if (userType === 'both') return 'Citizen & Worker'; - return userType.charAt(0).toUpperCase() + userType.slice(1); -} - -// Format component name to sentence case (e.g., "form-item" → "Form item") -function formatComponentName(component: string): string { - return component +// Format service type for display ("public-form" -> "Public form") +function formatProductType(productType: string): string { + return productType .split('-') .map((word, i) => i === 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word) .join(' '); @@ -82,37 +97,56 @@ const v1DocsUrl = `https://v1.design.alberta.ca/examples/${slug}`; currentSlug={slug} >
- + {/* Only page-scale entries (Dashboard, Start page, etc.) are members of + a product-type overview's Pages section. Section-scale snippets carry + a productType for filtering and badges only, so they should not show + the family crumb. */} +
- {data.categories.map((cat: string) => ( - - ))} - - + + {data.productType && ( + + )}
- - {hasCode ? ( + + {showCodeTabs ? (
- ) : data.previewImage ? ( + ) : useTopPreview ? ( +
+

{data.title}

+ {data.description && ( +

+ )} + +

+ ) : (

{data.title}

{data.description && (

)} -

- {`${data.title} -
- ) : null} + )} - {!hasCode ? ( + {!showCodeTabs ? (
@@ -129,6 +163,8 @@ const v1DocsUrl = `https://v1.design.alberta.ca/examples/${slug}`;
)} + {/* end of code-tabs vs TOC switch */} + {relatedExamples.length > 0 && (
@@ -214,10 +250,11 @@ const v1DocsUrl = `https://v1.design.alberta.ca/examples/${slug}`; margin-bottom: var(--goa-space-2xl, 2.5rem); } + /* Use goa-text typography tokens so MDX headings match the design system's + heading scale without authors having to wrap each heading in . */ .example-content :global(h2) { - font-size: 1.25rem; - font-weight: 600; - margin: var(--goa-space-xl, 2rem) 0 var(--goa-space-m, 1rem); + font: var(--goa-typography-heading-m); + margin: var(--goa-space-2xl, 2.5rem) 0 var(--goa-space-m, 1rem); color: var(--goa-color-text-default, #333); } @@ -225,6 +262,12 @@ const v1DocsUrl = `https://v1.design.alberta.ca/examples/${slug}`; margin-top: 0; } + .example-content :global(h3) { + font: var(--goa-typography-heading-s); + margin: var(--goa-space-2xl, 2.5rem) 0 var(--goa-space-s, 0.5rem); + color: var(--goa-color-text-default, #333); + } + .example-content :global(p) { margin-bottom: var(--goa-space-m, 1rem); max-width: 65ch; diff --git a/docs/src/pages/examples/[slug]/preview.astro b/docs/src/pages/examples/[slug]/preview.astro new file mode 100644 index 0000000000..7098c794a8 --- /dev/null +++ b/docs/src/pages/examples/[slug]/preview.astro @@ -0,0 +1,87 @@ +--- +/** + * Generic preview route for flat-slug page-scale examples. + * + * Renders the page's React component full-screen wrapped in PreviewLayout. + * Astro hydration needs static imports so it can ship the right JS bundle + * to the client, hence the SLUG_TO_COMPONENT map below. Adding a new + * page-scale entry means one import + one map entry here. + * + * Workspace pages (nested slugs) use [family]/[page]/preview.astro which + * iframes an external demo. Error-page variants and question-page variants + * have their own routes. + */ +import { getCollection } from "astro:content"; +import PreviewLayout from "../../../layouts/PreviewLayout.astro"; +import { StartPage } from "../../../content/examples/start-page/react"; +import { TaskListPage } from "../../../content/examples/task-list-page/react"; +import { ReviewPage } from "../../../content/examples/review-page/react"; +import { ResultPage } from "../../../content/examples/result-page/react"; +import { BasicPageLayout } from "../../../content/examples/basic-page-layout/react"; + +export async function getStaticPaths() { + // Inline list — Astro's getStaticPaths runs in an isolated module context + // and cannot see frontmatter top-level constants like SLUG_TO_COMPONENT. + // Keep this list in sync with the SLUG_TO_COMPONENT map above when adding + // page-scale entries that need a preview route. + const slugsWithPreview = new Set([ + "start-page", + "task-list-page", + "review-page", + "result-page", + "basic-page-layout", + ]); + const examples = await getCollection("examples"); + return examples + .filter( + (e) => + !e.slug.includes("/") && + e.data.size !== "section" && + slugsWithPreview.has(e.slug), + ) + .map((entry) => ({ + params: { slug: entry.slug }, + props: { entry }, + })); +} + +const { entry } = Astro.props; +const { slug } = Astro.params; +const { data } = entry; +const fullWidth = data.previewFullWidth === true; + +const githubBlob = `https://github.com/GovAlta/ui-components/blob/dev/docs/src/content/examples/${slug}/react.tsx`; +const githubFolder = `https://github.com/GovAlta/ui-components/tree/dev/docs/src/content/examples/${slug}`; +--- + + +
+ {/* Each branch is its own statically-imported JSX element so Astro + can wire up client:load hydration. Add a new branch when adding + a page-scale entry that needs a preview route. */} + {slug === "start-page" && } + {slug === "task-list-page" && } + {slug === "review-page" && } + {slug === "result-page" && } + {slug === "basic-page-layout" && } +
+
+ + diff --git a/docs/src/pages/examples/error-pages/401/preview.astro b/docs/src/pages/examples/error-pages/401/preview.astro new file mode 100644 index 0000000000..6c2dc91688 --- /dev/null +++ b/docs/src/pages/examples/error-pages/401/preview.astro @@ -0,0 +1,76 @@ +--- +/** + * Error pages: 401 live preview + * + * Render-local preview. Composition mirrors + * content/examples/error-pages/401/web-components.html so the rendered + * preview is visually identical to the source a consumer would paste. + */ +import PreviewLayout from "../../../../layouts/PreviewLayout.astro"; +import { withBase } from "@/lib/base-url"; + +const homeUrl = withBase("/"); +--- + + + +
+ + +
+ +
+ Error 401 + +
+ + + Restricted access + + We cannot provide access to this page without valid credentials. Please sign in or + contact support at + + cs.licensingsupport@gov.ab.ca + + to request access. + + + + + Go to home page + +
+
+
+
+ + diff --git a/docs/src/pages/examples/error-pages/404/preview.astro b/docs/src/pages/examples/error-pages/404/preview.astro new file mode 100644 index 0000000000..05343bdff1 --- /dev/null +++ b/docs/src/pages/examples/error-pages/404/preview.astro @@ -0,0 +1,71 @@ +--- +/** + * Error pages: 404 live preview + * + * Render-local preview. Composition mirrors + * content/examples/error-pages/404/web-components.html so the rendered + * preview is visually identical to the source a consumer would paste. + */ +import PreviewLayout from "../../../../layouts/PreviewLayout.astro"; +import { withBase } from "@/lib/base-url"; + +const homeUrl = withBase("/"); +--- + + + +
+ + +
+ +
+ Error 404 + +
+ + + Page not found + + The page you're looking for doesn't exist or has been moved. + + + + + Go to home page + +
+
+
+
+ + diff --git a/docs/src/pages/examples/error-pages/500/preview.astro b/docs/src/pages/examples/error-pages/500/preview.astro new file mode 100644 index 0000000000..9f8eb71b6a --- /dev/null +++ b/docs/src/pages/examples/error-pages/500/preview.astro @@ -0,0 +1,72 @@ +--- +/** + * Error pages: 500 live preview + * + * Render-local preview. Composition mirrors + * content/examples/error-pages/500/web-components.html so the rendered + * preview is visually identical to the source a consumer would paste. + */ +import PreviewLayout from "../../../../layouts/PreviewLayout.astro"; +import { withBase } from "@/lib/base-url"; + +const homeUrl = withBase("/"); +--- + + + +
+ + +
+ +
+ Error 500 + +
+ + + We are experiencing a problem + + We cannot load this page right now. Please try again in a few minutes. We apologize + for the inconvenience. + + + + + Go to home page + +
+
+
+
+ + diff --git a/docs/src/pages/examples/index.astro b/docs/src/pages/examples/index.astro index 75692da9e2..990a81abef 100644 --- a/docs/src/pages/examples/index.astro +++ b/docs/src/pages/examples/index.astro @@ -16,21 +16,43 @@ import Breadcrumbs from '../../components/Breadcrumbs.astro'; import { ExamplesGrid } from '../../components/ExamplesGrid'; -// Get all examples +// Pull both collections so the grid can surface product-type overviews +// alongside their member examples. Synthesizing the productTypes entries +// at render time avoids the stub-MDX duplication we used to have in the +// examples collection. const allExamples = await getCollection('examples'); +const allProductTypes = await getCollection('productTypes'); + +// Transform examples to the shape ExamplesGrid expects, excluding hidden entries. +const exampleEntries = allExamples + .filter((example) => !example.data.hidden) + .map(example => ({ + slug: example.slug, + data: example.data, + body: example.data.description || example.body, + })); + +// Synthesize a size:product card per productType. The slug matches the +// /examples/[productType]/ route the [family] page handler already serves. +const productTypeEntries = allProductTypes.map(productType => ({ + slug: productType.slug, + data: { + id: productType.data.id, + title: productType.data.title, + description: productType.data.summary.replace(/<[^>]+>/g, ''), + size: 'product' as const, + components: productType.data.components ?? [], + tags: productType.data.tags ?? [], + status: productType.data.status, + previewImage: productType.data.heroImage, + }, + body: productType.data.summary, +})); -// Sort by title (default) -const sortedExamples = allExamples.sort((a, b) => +const examples = [...exampleEntries, ...productTypeEntries].sort((a, b) => a.data.title.localeCompare(b.data.title) ); -// Transform to the shape ExamplesGrid expects -const examples = sortedExamples.map(example => ({ - slug: example.slug, - data: example.data, - body: example.data.description || example.body, -})); - --- ({ For citizens submitting applications and requests -
-
-
- Digital service - How workspace and public form connect end-to-end - -
-
diff --git a/docs/src/pages/examples/question-page/variants/background-radio/preview.astro b/docs/src/pages/examples/question-page/variants/background-radio/preview.astro new file mode 100644 index 0000000000..c93a5abb56 --- /dev/null +++ b/docs/src/pages/examples/question-page/variants/background-radio/preview.astro @@ -0,0 +1,24 @@ +--- +import PreviewLayout from "../../../../../layouts/PreviewLayout.astro"; +import { GiveBackgroundInformationBeforeAskingAQuestion } from "../../../../../content/examples/question-page/variants/background-radio/react"; +--- + + +
+ +
+
+ + diff --git a/docs/src/pages/examples/question-page/variants/grouped/preview.astro b/docs/src/pages/examples/question-page/variants/grouped/preview.astro new file mode 100644 index 0000000000..79eb3f4bbd --- /dev/null +++ b/docs/src/pages/examples/question-page/variants/grouped/preview.astro @@ -0,0 +1,24 @@ +--- +import PreviewLayout from "../../../../../layouts/PreviewLayout.astro"; +import { GroupRelatedQuestionsTogetherOnAQuestionPage } from "../../../../../content/examples/question-page/variants/grouped/react"; +--- + + +
+ +
+
+ + diff --git a/docs/src/pages/examples/question-page/variants/help-details/preview.astro b/docs/src/pages/examples/question-page/variants/help-details/preview.astro new file mode 100644 index 0000000000..18ffa1be51 --- /dev/null +++ b/docs/src/pages/examples/question-page/variants/help-details/preview.astro @@ -0,0 +1,24 @@ +--- +import PreviewLayout from "../../../../../layouts/PreviewLayout.astro"; +import { ShowMoreInformationToHelpAnswerAQuestion } from "../../../../../content/examples/question-page/variants/help-details/react"; +--- + + +
+ +
+
+ + diff --git a/docs/src/pages/examples/question-page/variants/one-question/preview.astro b/docs/src/pages/examples/question-page/variants/one-question/preview.astro new file mode 100644 index 0000000000..218f2534c3 --- /dev/null +++ b/docs/src/pages/examples/question-page/variants/one-question/preview.astro @@ -0,0 +1,24 @@ +--- +import PreviewLayout from "../../../../../layouts/PreviewLayout.astro"; +import { QuestionPage } from "../../../../../content/examples/question-page/variants/one-question/react"; +--- + + +
+ +
+
+ + diff --git a/docs/src/pages/examples/question-page/variants/progress-indicator/preview.astro b/docs/src/pages/examples/question-page/variants/progress-indicator/preview.astro new file mode 100644 index 0000000000..6761fdbc0f --- /dev/null +++ b/docs/src/pages/examples/question-page/variants/progress-indicator/preview.astro @@ -0,0 +1,24 @@ +--- +import PreviewLayout from "../../../../../layouts/PreviewLayout.astro"; +import { ShowASimpleProgressIndicatorOnAQuestionPage } from "../../../../../content/examples/question-page/variants/progress-indicator/react"; +--- + + +
+ +
+
+ + diff --git a/docs/src/pages/examples/question-page/variants/section-title/preview.astro b/docs/src/pages/examples/question-page/variants/section-title/preview.astro new file mode 100644 index 0000000000..50e13f7d3e --- /dev/null +++ b/docs/src/pages/examples/question-page/variants/section-title/preview.astro @@ -0,0 +1,24 @@ +--- +import PreviewLayout from "../../../../../layouts/PreviewLayout.astro"; +import { ShowASectionTitleOnAQuestionPage } from "../../../../../content/examples/question-page/variants/section-title/react"; +--- + + +
+ +
+
+ + diff --git a/docs/src/pages/foundations/content-guidelines/error-messages.astro b/docs/src/pages/foundations/content-guidelines/error-messages.astro index d9a2e26e76..ad5f35f8f4 100644 --- a/docs/src/pages/foundations/content-guidelines/error-messages.astro +++ b/docs/src/pages/foundations/content-guidelines/error-messages.astro @@ -525,27 +525,27 @@ const formatPatterns: PatternGroup[] = [ } :global(.explicit-example span.green) { - background-color: #cde9b9; + background-color: var(--goa-color-extended-pasture-border); } :global(.explicit-example span.blue) { - background-color: #bcdae7; + background-color: var(--goa-color-extended-sky-border); } :global(.explicit-example span.yellow) { - background-color: #fadfb1; + background-color: var(--goa-color-extended-prairie-border); } :global(.explicit-example span.greenUnder) { - text-decoration: underline solid #cde9b9 3px; + text-decoration: underline solid var(--goa-color-extended-pasture-border) 3px; } :global(.explicit-example span.blueUnder) { - text-decoration: underline solid #bcdae7 3px; + text-decoration: underline solid var(--goa-color-extended-sky-border) 3px; } :global(.explicit-example span.yellowUnder) { - text-decoration: underline solid #fadfb1 3px; + text-decoration: underline solid var(--goa-color-extended-prairie-border) 3px; } @media (min-width: 768px) { diff --git a/docs/src/pages/get-started/[...slug].astro b/docs/src/pages/get-started/[...slug].astro new file mode 100644 index 0000000000..263038105d --- /dev/null +++ b/docs/src/pages/get-started/[...slug].astro @@ -0,0 +1,25 @@ +--- +import { getCollection, render } from "astro:content"; +import DocumentationPageLayout from "../../layouts/DocumentationPageLayout.astro"; + +export async function getStaticPaths() { + const entries = await getCollection("get-started"); + return entries.map((entry) => ({ + // The "index" entry maps to the collection root URL (/get-started). + // Astro's [...slug] rest route accepts undefined for the parent path. + params: { slug: entry.slug === "index" ? undefined : entry.slug }, + props: { entry }, + })); +} + +const { entry } = Astro.props; +const { Content } = await render(entry); +--- + + + + diff --git a/docs/src/pages/get-started/automated-accessibility.astro b/docs/src/pages/get-started/automated-accessibility.astro deleted file mode 100644 index 061b16c880..0000000000 --- a/docs/src/pages/get-started/automated-accessibility.astro +++ /dev/null @@ -1,92 +0,0 @@ ---- -/** - * Get Started - Automated Accessibility - * - * Guidance on combining automated and manual accessibility testing. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro'; ---- - - - Automated accessibility - - Automated accessibility testing tools help you identify potential accessibility issues. Use them as a starting point. - - -

- However, these tools are not a complete solution. They can produce: -

-
    -
  • False positives – flagging issues that are not actual problems
  • -
  • False negatives – missing real accessibility barriers
  • -
-

- To ensure your digital product is accessible, combine automated testing with manual testing and apply - human judgment. -

- Why automated tools alone are not enough - - False positives -

- Automated tools may flag elements as non-compliant even when they work correctly for users. For - example, a tool may report that an input is "missing an id" even though it is correctly associated with a - label using a valid method, such as wrapping the input inside a <label> element. -

- - False negatives -

- Automated tools cannot detect nuanced or context-specific issues. For example, all interactive - elements may be tabbable, but the order jumps around the page. Tools often don't judge whether the - tab order is logical for completing the task. -

- - Real user experience -

- Accessibility ensures real people can use a product effectively. Automated tools cannot fully simulate - how users interact with your product. -

- Steps for effective accessibility testing - -
    -
  1. - Run automated tools to get an initial assessment. -
  2. -
  3. - Manually verify flagged issues and review the element's intent and context. -
  4. -
  5. - Do additional manual testing for issues automated tools cannot detect: -
      -
    • Test with a screen reader, such as VoiceOver (macOS) or NVDA (Windows)
    • -
    • Test keyboard navigation by checking focus visibility and order
    • -
    -
  6. -
  7. - Report findings -
      -
    • Record what you tested, what failed, and how to reproduce it
    • -
    • If the issue relates to a design system component, submit it using the design system bug report form
    • -
    -
  8. -
- Why this process matters -

- Automated tools provide helpful insight. Relying only on automation can result in: -

-
    -
  • Time spent fixing issues that are not real barriers
  • -
  • Missed opportunities to address genuine accessibility issues
  • -
  • A false sense of compliance without meaningful usability improvements
  • -
-

- Combine automated and manual testing to identify real barriers. This approach improves accessibility - and overall product quality. -

- -
diff --git a/docs/src/pages/get-started/component-lifecycle.astro b/docs/src/pages/get-started/component-lifecycle.astro deleted file mode 100644 index 42b0df0f4a..0000000000 --- a/docs/src/pages/get-started/component-lifecycle.astro +++ /dev/null @@ -1,67 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Component Lifecycle - * - * Defines the stages each Design System component moves through. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro'; ---- - - - Component lifecycle - - The component lifecycle defines the stages each Design System component moves through, from - Experimental to Production to Legacy. - - -

- To request a new component or propose an enhancement, follow the - design contribution process. -

- Experimental -

- Experimental components are new or significantly updated. They are available for testing and feedback - before public release. -

- - Characteristics -
    -
  • Feedback is gathered from selected teams
  • -
  • May be unstable or include breaking changes
  • -
  • Limited documentation
  • -
- Production -

- Production components are stable and ready for broader adoption. -

- - Characteristics -
    -
  • Fully documented, including design guidelines, properties, and examples
  • -
  • Meet accessibility and design system standards
  • -
  • Optimized for mobile use
  • -
  • Actively maintained with updates and bug fixes
  • -
  • Publicly available documentation
  • -
- Legacy -

- Legacy components are older components maintained primarily to support older implementations. If - possible, transition to production is recommended. -

- - Characteristics -
    -
  • No active maintenance or updates
  • -
  • Critical issues may remain unresolved
  • -
  • Recommended alternative clearly identified
  • -
  • Marked as "Legacy" in official documentation
  • -
- -
diff --git a/docs/src/pages/get-started/contribute.astro b/docs/src/pages/get-started/contribute.astro deleted file mode 100644 index 7a2ea6d675..0000000000 --- a/docs/src/pages/get-started/contribute.astro +++ /dev/null @@ -1,188 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Contribute - * - * How to contribute to the Design System (design and code). - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro'; ---- - - - Contribute - - The Design System is a shared resource used and improved by service teams. All roles are encouraged - to contribute. - - -

- Start by using existing Design System components and patterns. If a component or pattern does not - meet your needs, follow the contribution process below. -

- Design contribution process -

- If a required component or example does not exist in production, - contact the Design System team. We will review the request together and determine next steps. -

- - 1. Contact the team -

- Book a design system drop-in hours session. -

-

Be prepared to:

-
    -
  • Describe the component or pattern and its purpose
  • -
  • Explain your user needs and service goals
  • -
  • Share iterations explored with and without the Design System
  • -
- - - There are open contribution files in Figma for every component and pattern in the design system, - including unpublished ideas and experiments. - - - 2. Contribution criteria -

A proposed component or pattern must meet the following criteria.

- - Proposal criteria -

Useful

-

- Evidence shows it supports multiple teams or services. Provide screenshots or links to demonstrate usage. -

- -

Unique

-

- It does not duplicate an existing component or pattern. If replacing an existing component, provide - evidence that the new approach improves usability or accessibility. -

- - Publication standards -

To be published, the solution must be:

- -

Usable

-

- Improves clarity, usability, and accessibility for users. Is informed by research and addresses a - validated user need. -

- -

Universal

-

- Inclusive and accessible. Meets or exceeds accessibility standards. - WCAG 2.2 AA is the minimum requirement. -

- - 3. Backlog and collaboration -

- If approved, the item is added to the - Design System's backlog. -

-

- When development begins, the Design System team will collaborate with you to confirm detailed requirements. -

- Code contribution process -

- The Design System supports multiple development frameworks through Web Components. Contributing full - components can be complex. Smaller contributions are encouraged. -

- - Recommended contribution types -
    -
  • Bug fixes
  • -
  • Documentation updates
  • -
  • Enhancements to existing components
  • -
-

- Start by contacting the team in the #design-system-support Slack channel. -

-

- Select an issue tagged ready-for-contribution from the - backlog. - Confirm which issue you will work on. -

- - - Since the repository is public, use a personal GitHub account instead of your Enterprise Managed User (EMU) account. - - - Set up your contribution environment -
    -
  1. Clone the ui-components repository.
  2. -
  3. Open the repository in your IDE.
  4. -
  5. Create a branch named: contributions/story-number
  6. -
  7. - Run the following commands: -
    npm i
    -npm run build
    -
  8. -
  9. - The playgrounds for local testing are located in: -
    /apps/dev/angular
    -/apps/dev/react
    -
  10. -
- - Run playground environments -

Angular

-
npm run dev:watch
-npm run serve:dev:angular
- -

React

-
npm run dev:watch
-npm run serve:dev:react
- - Repository structure - -

React wrappers

-

/libs/react-components/src/lib

-

Each folder represents a single component with its associated unit tests and wrapper code.

- -

Angular wrappers

-

/libs/angular-components/src/lib/components

-

Each folder represents a single component with its associated unit tests and wrapper code.

- -

Web Components

-

/libs/web-components/src/components

-
    -
  • Unit tests as *.spec.ts
  • -
  • Component code as *.svelte
  • -
- - Testing requirements -
    -
  • Write all unit tests in Svelte.
  • -
  • If updating React or Angular wrappers, write unit tests in those respective frameworks.
  • -
  • - Add browser testing using Jest for React wrappers and Svelte components when appropriate. - These can be found in: libs/react-components/specs -
  • -
  • Manually test components in both React and Angular.
  • -
  • - Create test files that others can use to manually test the PR. These can be created in: -
    /apps/prs/angular
    -/apps/prs/react
    -
  • -
  • Follow the conventions already used in those files to create your test files.
  • -
-

A Design System developer will also manually test the pull request.

- - Submit your contribution -

Use the following commit message format:

- -

Bug fix

-
fix(#storyNumber): short description (7 words max)
- -

Feature request

-
feat(#storyNumber): short description (7 words max)
- -
    -
  • Create a pull request from your branch to the dev branch.
  • -
  • Notify the design system team of the PR.
  • -
- -
diff --git a/docs/src/pages/get-started/designers.astro b/docs/src/pages/get-started/designers.astro deleted file mode 100644 index 2d8a3b163d..0000000000 --- a/docs/src/pages/get-started/designers.astro +++ /dev/null @@ -1,94 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Designers Overview - * - * Overview of design system resources for designers. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro'; ---- - - - Overview - - As a designer, you use the design system through Figma. - -

In Figma, you can access:

- - - -

- The design system library in Figma aligns with coded components used by developers. Start with - design system components for common parts of your service. This helps developers use the matching - coded components and reduces custom work. -

-

- Start with the design system. Validate your design through user testing. If usability issues arise, - or the problem cannot be solved within the system, consider creating a custom solution. -

- Design with development in mind -

- When selecting components, prioritize those with a "goa-" prefix, such as - goa-input. These components exist in both design and development. Using them reduces - the need for custom development. -

-

Choose shared components whenever possible to maintain consistency and efficiency.

- - Design tokens -

Design system components in Figma and code are built using design tokens.

-

- Use tokens to communicate design decisions clearly. Developers can reference the same tokens in code. -

-

Instead of sharing hex values or pixel adjustments, reference semantic tokens.

-

For example:

-
    -
  • Colour: --goa-color-info-default
  • -
  • Spacing: --goa-spacing-m
  • -
-

Using tokens reduces back-and-forth and keeps design and development aligned.

- - Components -

All design system components are available in Figma and in code.

-

- These components are designed to meet - WCAG 2.2 accessibility standards. -

-

Avoid detaching components. Instead:

-
    -
  • Use variants
  • -
  • Show or hide layers within the component
  • -
-

- Use #figma for Figma-related issues, including library updates, missing components, - broken instances, or component behaviour in Figma. -

-

- Use #design-system-support for design system guidance, component usage questions, - standards, and implementation support. -

-

Keep your components up to date. Figma will notify you when library updates are available.

- - Figma file templates and helper components -

Each digital service project folder includes a starter Figma template.

-

Use this template to:

-
    -
  • Organize your design file
  • -
  • Support developer handoff
  • -
  • Help team members navigate files
  • -
-

- Helper components are also available. Use them to clearly communicate intent when sharing designs - with developers and other team members. -

- -
diff --git a/docs/src/pages/get-started/designers/designing-with-ds.astro b/docs/src/pages/get-started/designers/designing-with-ds.astro deleted file mode 100644 index a875429941..0000000000 --- a/docs/src/pages/get-started/designers/designing-with-ds.astro +++ /dev/null @@ -1,81 +0,0 @@ ---- -/** - * Get Started - Designers - Designing with Design System 2.0 - * - * How to start new designs and update existing projects to DS 2.0. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../../layouts/DocumentationPageLayout.astro'; ---- - - - Designing with Design System 2.0 - - What's new in DS 2.0 and how to start using it in your designs. - -

- The Digital Design and Delivery (DDD) Design System has evolved to better support how service teams - design and build digital government services. Design System 2.0 includes an updated design - language, new tokens, refreshed components, and ready-to-use templates. -

- Starting a new design -

- Use DS 2.0 templates as your starting point. Templates package layout, navigation, spacing, and - example content that you can adapt to your service. Some templates are built for specific service types - (for example, public-facing forms and workspace applications), and others are more general-purpose - starting points you can use across many kinds of pages and flows. -

- - Starting from an existing design - - Library swap -

- Use a library swap if - your goal is to convert most of the file to DS 2.0 in one pass. -

-
    -
  • Make a copy of your file before you start.
  • -
  • Expect mixed results. Some screens may need cleanup after the swap.
  • -
- - Manual rebuild -

Use a manual rebuild if you need more control.

-
    -
  • Rebuild your highest value screens first.
  • -
  • Consider using DS 2.0 templates as a base to speed things up.
  • -
- Update an existing project to the new design library - - Approach 1: Developer-first -

Use this approach in most cases.

-
    -
  1. A developer creates a new branch and completes the upgrade steps.
  2. -
  3. The team runs the upgraded application to see what changed.
  4. -
  5. Designers review the upgraded screens and identify what needs design updates.
  6. -
-

When reviewing the upgraded branch, watch for:

-
    -
  • Spacing and layout rhythm
  • -
  • Typography scale and weight usage
  • -
  • Dense or constrained screens (these often have the highest risk during an update)
  • -
- - Approach 2: Design-first -

Use this approach when you want design work to move ahead of development work.

-
    -
  1. Identify custom elements that support your users' needs.
  2. -
  3. Create an inventory and prioritize items by importance and effort.
  4. -
  5. Redesign the highest priority items using the visual design values in the Styles library.
  6. -
- - - In most cases, start with the developer-first approach. It helps you quickly see what changed in your - real product, so you can focus design effort where it matters most. - - -
diff --git a/docs/src/pages/get-started/designers/ux-guidelines.astro b/docs/src/pages/get-started/designers/ux-guidelines.astro deleted file mode 100644 index b44c9c82e5..0000000000 --- a/docs/src/pages/get-started/designers/ux-guidelines.astro +++ /dev/null @@ -1,55 +0,0 @@ ---- -/** - * Get Started - Designers - User Experience Guidelines - * - * UX guidelines for Government of Alberta digital products. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../../layouts/DocumentationPageLayout.astro'; ---- - - - User experience guidelines - - Digital products built for the Government of Alberta should comply with these guidelines to ensure a - quality user experience for Albertans. - - -
    -
  • User-centered: Designed with a clear understanding of users, their goals, tasks, environments, and context of use, using user-centered design methods.
  • -
  • Usable: Interfaces will be easy to use, enabling users to find the information they need and complete tasks successfully.
  • -
  • Accessible: Digital products will be inclusive, ensuring usability for everyone, regardless of physical or cognitive ability.
  • -
  • Trustworthy: Experiences will feel familiar and recognizable as a Government of Alberta product, ensuring users' security and privacy.
  • -
  • Modern: Digital experiences will meet present-day user expectations and preferences for aesthetics and interaction.
  • -
- -

- For more details on the process of assessing compliance to each guideline, refer to our - User Experience Guidelines and Design System Checklist. -

- Usability testing -

- Usability testing is our preferred method to understand user needs as they relate to each guideline. -

-

Suitable usability testing includes:

-
    -
  • Diverse user group: Real users from different demographic, behavioural backgrounds, and geographical regions within Alberta that will experience the problem or benefit of the product.
  • -
  • Inclusive testing: Users with various physical and/or cognitive abilities, literacy levels, and tech savviness.
  • -
  • Device variety: A diverse range of devices that reflect users' preferred choice when interacting with government services.
  • -
  • Tasks: Activities that cover tasks and service process from end-to-end.
  • -
-

- Frequent usability testing should be conducted to maintain product usability, effectiveness and - alignment to the user needs as they evolve over time. -

-

- For guidance on the process of usability testing, refer to our - Understanding Usability documentation. -

- -
diff --git a/docs/src/pages/get-started/developers.astro b/docs/src/pages/get-started/developers.astro deleted file mode 100644 index b34d1c3712..0000000000 --- a/docs/src/pages/get-started/developers.astro +++ /dev/null @@ -1,104 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Developers Overview - * - * Overview of design system resources for developers. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro'; ---- - - - Overview - - As a developer, you use the Design System through tokens, components, examples, and templates. - - -

- The DDD Design System is built using Web Components. Web Components are framework-agnostic. - You can use them with Angular, React, or other front-end frameworks. -

-

The Design System includes:

- -

- Designers use equivalent resources in Figma. When they design with Design System components, you - can build with the matching coded components. This reduces custom development and rework. -

-

- All Design System components are designed and built to meet - WCAG 2.2 accessibility standards. -

- 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. -

-

- Designers reference the same tokens in their tools. This keeps design and development aligned during handoff. -

- - Components -

Components are reusable user interface elements built for use across services.

-

You can:

-
    -
  • Use components individually
  • -
  • Combine them into patterns
  • -
  • Apply them in different contexts
  • -
-

Components are available:

- -

- Refer to the Design System technologies documentation - for implementation details. -

- - Examples -

- Examples are multiple components assembled in realistic service contexts. They help you understand - how to apply Design System guidance in a working interface. -

-

You can use examples to:

-
    -
  • Understand how components work together
  • -
  • Use them as a starting point for building parts of your interface
  • -
  • Use proven approaches to meet user needs
  • -
-

- Examples help you build with more consistency and less rework. Use them to guide implementation, - then adjust them to meet the needs of your product. -

- - Templates -

- Templates are opinionated starting points for common service types. They package layout, navigation, - spacing, and example content so you can start with a proven structure instead of building from scratch. -

-

You can use templates to:

-
    -
  • Start a new product with a proven structure
  • -
  • Learn how components work together in a real layout
  • -
  • Adapt a proven starting point to fit your service needs
  • -
-

- Templates help teams move faster, reduce rework, and stay aligned with Design System guidance. -

- -
diff --git a/docs/src/pages/get-started/developers/browsers.astro b/docs/src/pages/get-started/developers/browsers.astro deleted file mode 100644 index 3ced88e5fc..0000000000 --- a/docs/src/pages/get-started/developers/browsers.astro +++ /dev/null @@ -1,87 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Developers - Supported browsers - * - * Browser and OS support matrix for Design System components. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../../layouts/DocumentationPageLayout.astro'; ---- - - - Supported browsers - - Design System components are tested across supported browsers and devices. - - -

- We support the latest version of each browser listed on this page. Support applies to the browser and - operating system combinations shown in the table below. On mobile, support is limited to the browser - and operating system combinations listed for Android and iOS. -

- - Browser and operating system support - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BrowserWindowsMac OSAndroidiOS
Google ChromeYesYesYesYes
Microsoft EdgeYesYes
Mozilla FirefoxYesYesYes
Apple SafariN/AYesN/AYes
-
- - Representative mobile OS used in testing -
    -
  • Android OS: 10+
  • -
  • iOS: 15+
  • -
- Testing guidance -

- Use supported browsers and operating system versions when developing and testing services. If you - encounter a browser-specific issue, follow the - Verify a bug process. -

- -
diff --git a/docs/src/pages/get-started/developers/bug.astro b/docs/src/pages/get-started/developers/bug.astro deleted file mode 100644 index ffabd0fc5e..0000000000 --- a/docs/src/pages/get-started/developers/bug.astro +++ /dev/null @@ -1,65 +0,0 @@ ---- -/** - * Get Started - Developers - Verify a bug - * - * Process for verifying and reporting Design System component issues. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../../layouts/DocumentationPageLayout.astro'; ---- - - - Verify a bug - - Follow this process when you encounter an issue with a Design System component. - - -

- These steps help confirm whether the issue is caused by the Design System, your product setup, or - custom code. This process applies to Angular and React implementations. -

- - 1. Check versions -

Confirm you are using the latest version of:

-
    -
  • Web Components
  • -
  • Angular or React
  • -
-

- If you are not using the latest version, upgrade and retest. If the issue remains, continue to the next step. -

- - 2. Test with product templates -

Use the official Angular or React product templates to isolate the issue.

- -

This helps determine whether the issue exists outside your project configuration.

- - 3. Recreate the issue -

Create a minimal test environment.

-
    -
  • Use only the code required for the example to function
  • -
  • Include only the component experiencing the issue
  • -
  • Remove unrelated dependencies or custom logic
  • -
-

Confirm whether the issue can be replicated.

- - 4. Share and report -

If you can reproduce the issue:

-
    -
  • Share the template application link in the #design-system-support Slack channel
  • -
  • Provide a link to your repository so the team can review and replicate the issue
  • -
-

- Following these steps will help to ensure efficient investigation and quicker resolution of - design system component issues. -

- -
diff --git a/docs/src/pages/get-started/developers/setup.astro b/docs/src/pages/get-started/developers/setup.astro deleted file mode 100644 index 326b964dfe..0000000000 --- a/docs/src/pages/get-started/developers/setup.astro +++ /dev/null @@ -1,141 +0,0 @@ ---- -/** - * Get Started - Developers - Setup - * - * Setup instructions for Angular, React, and Web Components. - * Based on the current website content with DS 2.0 token updates. - */ -import DocumentationPageLayout from "../../../layouts/DocumentationPageLayout.astro"; -import DropInCallout from "../../../components/DropInCallout.astro"; ---- - - - Developer setup - - Set up the Government of Alberta Design System in Angular, React, or directly with Web - Components. - - -

Angular UI components

- - Supported versions: 18, 19, 20, 21 - - - This is the web component library and utilizes Angular's web component - integration. - - -

1. Add dependencies

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

2. Link ionicons in app/index.html

- - Add the following in the head element: - -
<script type="module" src="https://cdn.jsdelivr.net/npm/ionicons@latest/dist/ionicons/ionicons.esm.js"></script>
-<script nomodule src="https://cdn.jsdelivr.net/npm/ionicons@latest/dist/ionicons/ionicons.js"></script>
- -

3. Update src/app/app.module.ts

- - Update src/app/app.module.ts as per the four steps below: - -
// 1. Import the CUSTOM_ELEMENTS_SCHEMA
-import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
-
-// 2. Import the libs
-import "@abgov/web-components";
-import { AngularComponentsModule } from "@abgov/angular-components";
-
-@NgModule({
-	declarations: [AppComponent],
-	imports: [
-		// 3. Add the needed imports
-		BrowserModule,
-		AngularComponentsModule,
-	],
-	providers: [],
-	bootstrap: [AppComponent],
-	// 4. Add the CUSTOM_ELEMENTS_SCHEMA to the NgModule
-	schemas: [CUSTOM_ELEMENTS_SCHEMA],
-	})
-export class AppModule {}
- -

4. Add the styles link in src/styles.css

-
@import "@abgov/web-components/index.css";
-@import "@abgov/design-tokens/dist/tokens.css";
- - - -

React UI components

- - Supported versions: 17, 18, 19 - - - This library contains React components which wrap the Government of Alberta Web - Components. - - -

1. Add dependencies

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

2. Link ionicons in app/index.html

- - Add the following to the head element: - -
<script type="module" src="https://cdn.jsdelivr.net/npm/ionicons@latest/dist/ionicons/ionicons.esm.js"></script>
-<script nomodule src="https://cdn.jsdelivr.net/npm/ionicons@latest/dist/ionicons/ionicons.js"></script>
- -

3. Import the web components in src/main.tsx

-
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";
- - - -

Web components

- - This library contains web components from the Government of Alberta. - - -

1. Add dependencies

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

2. Link ionicons in index.html

- - Add the following in the head element: - -
<script type="module" src="https://cdn.jsdelivr.net/npm/ionicons@latest/dist/ionicons/ionicons.esm.js"></script>
-<script nomodule src="https://cdn.jsdelivr.net/npm/ionicons@latest/dist/ionicons/ionicons.js"></script>
- -

3. Import the web components into src/main.js

-
import "@abgov/web-components";
- -

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: - -
@import "@abgov/web-components/index.css";
-@import "@abgov/design-tokens/dist/tokens.css";
- - - - -
diff --git a/docs/src/pages/get-started/developers/technologies.astro b/docs/src/pages/get-started/developers/technologies.astro deleted file mode 100644 index 272d9a8a12..0000000000 --- a/docs/src/pages/get-started/developers/technologies.astro +++ /dev/null @@ -1,111 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Developers - Technologies - * - * Overview of Design System technologies: Web Components, Svelte, Angular, React. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../../layouts/DocumentationPageLayout.astro'; ---- - - - Technologies - - An overview of the technologies used in the Design System. - - - How the technologies fit together -

- The Design System is built on Web Components. Most component functionality lives in the core Web - Components layer. Angular and React wrappers sit on top of that layer to make the components easier - to use in those frameworks. -

-

- We use Svelte to author the components that are compiled to custom elements. You can use the Design - System through the core Web Components or through Angular and React wrappers. -

- Diagram showing the technology layers: Svelte compiles to Web Components, which are wrapped by Angular and React - Web Components -

- Web Components - are a set of standard web technologies that allow you to create reusable custom elements. Each component - includes its own structure, styling, and behaviour. This keeps it independent from the rest of your code. -

-

- In the Design System, Web Components are the core library. They are framework-agnostic, so teams - can use them in different front-end environments. -

- - Benefits of using Web Components -
    -
  • Reuse: Build once and use across pages, applications, and frameworks
  • -
  • Browser support: Work in modern browsers without additional libraries
  • -
  • Maintenance: Modular and self-contained structure simplifies updates
  • -
  • Encapsulation: Structure, style, and behaviour remain isolated from other page elements
  • -
  • Reliability: Code is not spread across HTML and JS files, thereby avoiding inconsistencies
  • -
  • Flexibility: Use inline, import, or compile components as needed
  • -
  • Composability: Combine components or integrate them with other components
  • -
- - - Do not use Web Components directly unless there is a specific reason to do so. Using wrappers provides - type checking and developer helpers that are not available when working with the core Web Components alone. - - Svelte -

- Svelte is the framework used to generate the - Design System Web Components. Svelte combines JavaScript (logic), HTML (structure), and CSS (style) - within a single file. It compiles these into efficient, reusable components. -

- Why Svelte -

We use Svelte to:

-
    -
  • Build reusable Web Components
  • -
  • Keep component logic, structure, and styling together
  • -
  • Support integration with multiple front-end frameworks
  • -
- Angular - - - Supported versions: 18, 19, 20, 21 - - -

- Angular is a TypeScript-based framework for building - web applications. The Design System supports Angular through Angular wrappers around the core Web Components. -

- - How Web Components and Angular work together -

Angular wrappers are created around the Web Components. These wrappers:

-
    -
  • Manage component properties and events
  • -
  • Support form binding (Reactive and Template-driven)
  • -
  • Allow integration within Angular applications
  • -
-

The Angular application interacts with the wrapper, which renders the underlying Web Component.

- React - - - Supported versions: 17, 18, 19 - - -

- React is an open-source JavaScript library used to - build user interfaces from reusable components. -

- - How Web Components and React work together -

React wrappers are created around the Web Components. These wrappers:

-
    -
  • Manage properties and events
  • -
  • Enable integration within React applications
  • -
-

The React application interacts with the wrapper, which renders the underlying Web Component.

- -
diff --git a/docs/src/pages/get-started/index.astro b/docs/src/pages/get-started/index.astro deleted file mode 100644 index 1b92e400aa..0000000000 --- a/docs/src/pages/get-started/index.astro +++ /dev/null @@ -1,108 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Landing Page - * - * Overview of the design system and how to use it in your service. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro'; ---- - - - Start with the design system - - Start with the design system to build on the research and experience of other service teams. - This helps you avoid repeating work that has already been done. - - - - The design system gives you a strong foundation for common service needs. It allows your team - to focus on the specific challenges of your product. - Build on it. Do not start from scratch. - - - Design system by role - - - - Why start with the design system? - - Streamline collaboration -

- Designers and developers work from shared components and guidance. This reduces rework and misalignment. -

- - Improve accessibility -

Accessibility is built into both the design and coded components.

- - Reduce testing effort -

Components are tested across devices, browsers, and service contexts.

- - Maintain consistency -

- Components align with the broader system to create a cohesive user experience across government services. -

- - Spend more time on high-value work -

Using existing components saves time. You can focus on work that improves service quality, including:

-
    -
  • Usability testing
  • -
  • User research
  • -
  • Content design
  • -
  • Accessibility reviews
  • -
  • Design quality checks
  • -
  • Low-fidelity prototyping and testing
  • -
-

This leads to better outcomes for users.

- How to use the design system in your service -

Follow these steps when designing and building your service.

- - Use system components first -

Start with existing components and patterns. These meet most user needs.

- - Identify gaps through user testing -

Test your service with users. Identify needs that are not covered by current components.

- - Before you design something new -

- Check what's already available and what's in progress. The team can point you to existing components, - solutions other teams have built, and planned work that may meet your need. -

- - Design and test new solutions when you need them -

- If you still have a gap, design a new solution and test it with users. Move forward only when - testing shows clear user value. -

- - Share what you learn -

- Share your findings with the design system team. Your solution may become part of the design system. -

- - - Do not create custom components without a clear user need. - Unnecessary customization: -
    -
  • Increases maintenance effort
  • -
  • Slows delivery
  • -
  • Reduces consistency
  • -
- Always confirm the need through research and testing. -
- - - View the design system governance process - - -
diff --git a/docs/src/pages/get-started/migration-guide.astro b/docs/src/pages/get-started/migration-guide.astro deleted file mode 100644 index b43c6678e3..0000000000 --- a/docs/src/pages/get-started/migration-guide.astro +++ /dev/null @@ -1,232 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Developers - Migration guide - * - * Migration pathways and guidance for moving products from DS 1.x to DS 2.0. - * Content adapted from Confluence. - */ -import DocumentationPageLayout from "../../layouts/DocumentationPageLayout.astro"; ---- - - - Migration guide - - Design System 2.0 (DS 2.0) becomes the Government of Alberta standard in March 2026. - New products starting after launch should use DS 2.0. Existing active products should - plan their move to DS 2.0 during the recommended migration window, which runs from - March 2026 to September 2026. - - - - -

Migration pathways

- - The right migration path depends on your product's context, including team - funding and capacity, other delivery obligations, product lifecycle, and the effort - required to update. The three pathways are standard migration, late migration, and no - migration. - - -

Starting a new product

- - If your product starts after March 2026, start with DS 2.0. Migration pathways apply - to existing products moving from DS 1.x to DS 2.0. - - -

Compare the pathways

-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
PathwayUse it whenRecommendation
- Standard migration - - - Your product has an active funded team and can migrate by September 2026 - - - Recommended default -
- Late migration - - - Your team cannot meet the standard window because of delivery timelines, - dependencies, or capacity constraints - - - Only when necessary -
- No migration - - - Your product does not have an active funded team and/or is not in a - position to upgrade - - - Only in specific cases -
-
-
- -

- Standard migration - -

- - Standard migration is the default pathway for active products. - - - Choose this path if your product has an active funded team and can schedule migration - work between March 2026 and September 2026. This is the recommended path for most - teams because it keeps your product aligned with the current standard and gives you - the best support. - - Use this pathway when: - -
    -
  • your product is actively maintained
  • -
  • your team can reserve time to migrate by September 2026
  • -
  • you want access to the latest templates, components, tokens, and guidance
  • -
-
- - Plan for work across the product team. Typical upgrade tasks include the library - updates, adjusting spacing and typography, and updating custom code to align with the - DS 2.0 visual design. This is a significant update and will usually involve design, - development, and testing. - - -

Late migration

- - Late migration is a last-resort pathway for active products. - - - Choose this path only when delivery deadlines, dependencies, or capacity constraints - make the standard migration window unrealistic. This path gives your team more time, - but it also increases risk and reduces your ongoing support. - - Use this pathway when: - -
    -
  • a major delivery deadline blocks migration work
  • -
  • critical dependencies prevent the upgrade during the standard window
  • -
  • capacity or funding makes the standard window unrealistic
  • -
-
- - Delaying migration means your product will wait longer to benefit from DS 2.0 - improvements. Over time, unresolved issues will accumulate and your product will be - inconsistent with the new standard for longer. - - -

No migration

- - No migration is an opt-out pathway for specific situations. - - - Choose this path only when your product does not have an active funded team and/or is - not in a position to upgrade. In these cases, the product may remain on DS 1.x. - - - Teams on this path should understand that the product will not receive DS 2.0 - improvements and will not align with the current standard. Support for DS 1.x is - limited from March to September and ends after September 2026. - - - - -

What changes after launch

- - After the DS 2.0 launch in March 2026: - - -
    -
  • New products should use DS 2.0
  • -
  • Active products should aim to migrate by September 2026
  • -
  • - After launch, web components will move to version 2.x. Although this is a major - version update, it does not include breaking changes. -
  • -
  • - Angular 4.x and React 6.x receive limited fixes or features from March to - September -
  • -
  • Support for DS 1.0 ends after September 2026
  • -
  • Web components will update to a new major version after September 2026
  • -
-
- -

How to choose a pathway

- - Use these questions to guide your decision: - - -
    -
  • Is this a new product starting after March 2026?
  • -
  • Does the product have an active funded team?
  • -
  • Can the team schedule migration work before September 2026?
  • -
  • - Are there delivery deadlines or dependencies that block the standard window? -
  • -
  • - Is the team prepared to accept reduced support and higher maintenance risk if - migration is delayed? -
  • -
-
- - - - Review the setup steps for developers - -
diff --git a/docs/src/pages/get-started/out-of-support.astro b/docs/src/pages/get-started/out-of-support.astro deleted file mode 100644 index 3944d67e3a..0000000000 --- a/docs/src/pages/get-started/out-of-support.astro +++ /dev/null @@ -1,54 +0,0 @@ ---- -import { withBase } from '@/lib/base-url'; -/** - * Get Started - Out of Support Versions - * - * Information about unsupported Design System versions. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro'; ---- - - - Out-of-support versions - - With the launch of the new Design System, support for Angular v4 and lower, and React v6 and lower - is significantly reduced. - - - What this means - - Fewer fixes or patches -

Bug fixes and security updates are no longer prioritized for these versions.

- - No new features -

All new features and enhancements are released only in the current major version.

- - Use at your own risk -

Existing projects may continue to run. However:

-
    -
  • Compatibility with new browsers or operating systems is not guaranteed
  • -
  • Compatibility with future framework updates is not guaranteed
  • -
  • Issues discovered in these versions will not be resolved
  • -
- - - Projects using Angular v4 and lower, and React v6 and lower will continue to function. - New issues or defects identified in these versions may not be fixed. - - What to do next -

- Upgrade to the latest supported version. Refer to the - version update guide. -

-

- If you need support planning your upgrade, - book time in drop-in hours. -

- -
diff --git a/docs/src/pages/get-started/qa-testing.astro b/docs/src/pages/get-started/qa-testing.astro deleted file mode 100644 index 146cb12778..0000000000 --- a/docs/src/pages/get-started/qa-testing.astro +++ /dev/null @@ -1,77 +0,0 @@ ---- -/** - * Get Started - QA Testing - * - * Testing process for Design System components. - * Content from Confluence (Brief 87). - */ -import DropInCallout from '../../components/DropInCallout.astro'; -import DocumentationPageLayout from '../../layouts/DocumentationPageLayout.astro'; ---- - - - QA testing - - This page outlines the testing process for the Design System. The process ensures components - function correctly and integrate within products. - - - Testing objectives -

QA testing ensures that:

-
    -
  • Coded components match the design specifications
  • -
  • Components work in both React and Angular implementations
  • -
  • Components are responsive across screen sizes
  • -
  • Components meet accessibility requirements
  • -
  • Mobile behaviour is validated
  • -
  • Documentation on the Design System website is accurate
  • -
- Test cases - - Component testing -
    -
  • Confirm the rendered component matches design and styling guidelines
  • -
  • Confirm configured properties display correctly
  • -
  • Confirm the expected event triggers when interacting with the component
  • -
- - Responsiveness testing -
    -
  • Test components on mobile, tablet, and desktop screen sizes
  • -
  • Use browser developer tools to simulate devices
  • -
- - Accessibility testing -
    -
  • Run Lighthouse audits to review accessibility scores
  • -
  • Confirm appropriate ARIA (Accessible Rich Internet Applications) roles and labels
  • -
  • Test keyboard navigation
  • -
  • Test with NVDA screen reader
  • -
- - Cross-browser testing -
    -
  • Test on the latest versions of Chrome, Firefox, Safari, and Edge
  • -
  • Use Chrome device mode to simulate mobile environments
  • -
  • Confirm consistent appearance and behaviour across browsers
  • -
- - Bug testing -

When a bug is fixed:

-
    -
  1. Reproduce the issue using the main branch.
  2. -
  3. Verify the fix in the pull request branch.
  4. -
  5. Retest the component across all relevant areas.
  6. -
-

Confirm the issue no longer occurs.

- Reporting -
    -
  • Document updated test results, findings, and screenshots in the pull request comments
  • -
  • Log newly discovered issues in GitHub
  • -
- -
diff --git a/docs/src/pages/get-started/roadmap.astro b/docs/src/pages/get-started/roadmap.astro deleted file mode 100644 index 070656eab6..0000000000 --- a/docs/src/pages/get-started/roadmap.astro +++ /dev/null @@ -1,347 +0,0 @@ ---- -/** - * Get Started - Roadmap - * - * High-level roadmap for the design system team's 2026-27 fiscal year. - * Content adapted from Confluence. - */ -import DocumentationPageLayout from "../../layouts/DocumentationPageLayout.astro"; ---- - - - Roadmap - - A high-level summary of the work the design system team plans to focus on in the - 2026-27 Fiscal Year. - - - - The roadmap is subject to change as we gather new information. We will communicate - updates to ensure product teams can align and plan their work accordingly. - - - - For more details on our priorities and day-to-day activities, see our - - design system backlog. - - - - - -

Now

- - Focus: Drive DS 2.0 adoption momentum, protect post-launch stability, and - prove DS 2.0 helps teams move faster through prescriptive guidance and examples. - - -

DS 2.0 adoption and satisfaction measurement

- - Objective: Establish reliable DS 2.0 adoption tracking and reporting, and - pair it with satisfaction signals from designers, developers, and end users to understand - whether DS 2.0 is improving service outcomes as teams upgrade. - - - Benefit: Enables accurate progress reporting and provides evidence that - DS 2.0 is improving usability, accessibility, and experience quality, not only adoption. - - - Examples: - -
    -
  • - Create a mechanism to reliably collect and report adoption rate -
  • -
  • - Track upgrade progress against the adoption schedule -
  • -
  • - Capture qualitative signals from teams (developer and designer feedback themes) -
  • -
  • - Capture end-user feedback where available (citizen or worker satisfaction, - accessibility and usability feedback) -
  • -
- -

Product acceleration enablement

- - Objective: Provide prescriptive guidance and resources that help teams - get to screens, prototypes, and working experiences faster using DS 2.0. - - - Benefit: Reduces time to first screens and improves consistency by helping - teams start from proven patterns instead of building from scratch. - - - Examples: - -
    -
  • - Create resources that show how to quickly prototype with DS 2.0 components and - examples -
  • -
  • - Provide contextual starting points for teams using Public form and Workspace - templates -
  • -
  • - Pilot DS 2.0 with teams to generate strong examples to share -
  • -
  • - Create and publish migration success stories -
  • -
- -

Design system MCP

- - Objective: Stand up the design system Model Context Protocol (MCP) capability - so AI tools and platforms can reliably access design system guidance, components, patterns, - and standards. - - - Benefit: Helps teams generate more consistent, standards-aligned front-ends - by making trusted design system context available directly in AI-assisted workflows. - - - Examples: - -
    -
  • - Define the initial MCP scope and supported design system resources -
  • -
  • - Stand up the MCP server and validate the hosting and maintenance approach -
  • -
  • - Test the MCP use in real product workflows and capture gaps to address -
  • -
  • - Document recommended workflows for teams -
  • -
- -

Vue support decision

- - Objective: Explore and define the minimum work required to confidently - state DS 2.0 officially supports Vue, including scope, constraints, and support model. - - - Benefit: Prevents unclear commitments and reduces strategic risk by enabling - an informed investment decision aligned to organizational needs. - - - Examples: - -
    -
  • - Define what "official Vue support" means -
  • -
  • - Outline the minimum supportable scope -
  • -
  • - Identify implications for documentation, maintenance, testing, and support -
  • -
- - - -

Next

- - Focus: Improve the core Public form and Workspace experience, mature reusable - patterns and examples, reduce adoption friction through better packaging, and execute on - the chosen Vue direction. - - -

Public form and Workspace capability improvements

- - Objective: Enhance key Public form and Workspace capabilities based on - adoption needs and workflow requirements. - - - Benefit: Improves feature sets and reduces the need for custom one-off - solutions by making common workflows easier to implement with DS 2.0. - - - Example: - -
    -
  • - Build the review, revise, resubmit feature -
  • -
- -

Examples and pattern maturity

- - Objective: Expand and refine examples and position them as adaptable reusable - patterns that teams can apply with confidence. - - - Benefit: Improves self-serve success and product consistency, reducing - implementation variance and support demand over time. - - - Examples: - -
    -
  • - Continue expanding and refining examples -
  • -
  • - Show how components and examples combine into larger contexts and workflows -
  • -
- -

Library packaging and tech stack upgrades

- - Objective: Reduce friction in how design system assets are bundled and - adopted across libraries and update important tech stacks. - - - Benefit: Lowers setup and upgrade complexity, and keeps the design system - up to date with the latest supported versions. - - - Examples: - -
    -
  • - Improve how code libraries are bundled together (React, web components, tokens) -
  • -
  • - Update to Svelte 5 -
  • -
- -

Vue follow-through

- - Objective: Based on Vue discovery, either implement formal Vue support - or clearly position Angular and React as the recommended approach for teams using AI-assisted - workflows. - - - Benefit: Provides clear direction to product teams and reduces uncertainty, - enabling progress on a supported path while keeping support sustainable for the design system - team. - - - Examples: - -
    -
  • - Publish Vue support guidance and expectations -
  • -
  • - Implement agreed scope if approved -
  • -
  • - Publish recommended alternatives if Vue support is not pursued -
  • -
- - - -

Later

- - Focus: Support DS 2.0 version updates and improve documentation and communications - quality to support scaling and sustainability. - - -

Documentation and communications improvements

- - Objective: Improve how teams access and understand design system guidance, - and communicate design system value areas like accessibility more clearly. - - - Benefit: Increases trust, improves reuse, and supports self-serve adoption - by making guidance easier to consume and share. - - - Examples: - -
    -
  • - Add markdown file download to website documentation -
  • -
  • - Articulate accessibility work more clearly (what is covered and how it supports - teams) -
  • -
- -

Targeted capacity support for DS 2.0 version updates

- - Objective: Provide targeted design system team capacity to help remaining - DS 1.x product teams complete the DS 2.0 version update. - - - Benefit: Accelerates adoption progress and unblocks teams facing more difficult - migrations, supporting adoption targets while keeping support sustainable through a focus - on teams most in need. - - - Example: - - -
    -
  • - Focus migration support on late adopters facing systemic barriers to upgrading -
  • -
-
diff --git a/docs/src/pages/index.astro b/docs/src/pages/index.astro index 1c720ba5a7..d925a33b14 100644 --- a/docs/src/pages/index.astro +++ b/docs/src/pages/index.astro @@ -76,26 +76,6 @@ import CardLite from '../components/CardLite.astro'; /> - -

Research tools

-

- Conduct research with your users to validate your design decisions. Test your assumptions, gather insights, and ensure your service meets real user needs. -

-
- - - -
-

Understand your service

@@ -103,24 +83,44 @@ import CardLite from '../components/CardLite.astro';

+ + +

Research tools

+

+ Conduct research with your users to validate your design decisions. Test your assumptions, gather insights, and ensure your service meets real user needs. +

+
+ + + +
@@ -138,6 +138,12 @@ import CardLite from '../components/CardLite.astro'; padding: var(--goa-space-2xl) var(--goa-space-2xl); } + :root[data-theme="dark"] .ds-hero-banner { + background: transparent url('/images/home/hero-banner-gradient-dark.svg') + center center no-repeat; + background-size: cover; + } + .hero-content { display: flex; gap: var(--goa-space-2xl); @@ -204,6 +210,14 @@ import CardLite from '../components/CardLite.astro'; outline-offset: 2px; } + :root[data-theme="dark"] .hero-search-trigger { + background: rgba(38, 38, 38, 0.85); + } + + :root[data-theme="dark"] .hero-search-trigger:hover { + background: rgba(38, 38, 38, 0.95); + } + .hero-search-icon { flex-shrink: 0; color: var(--goa-color-text-secondary); @@ -311,6 +325,24 @@ import CardLite from '../components/CardLite.astro'; grid-template-columns: repeat(3, 1fr); } + /* "Understand your service" thumbnails are smaller than card width; + constrain to a uniform 240×112 frame, illustration left-aligned within. */ + .card-grid.three-col :global(.card-image) { + width: 100%; + max-width: 240px; + aspect-ratio: 240 / 112; + display: flex; + align-items: center; + justify-content: flex-start; + } + + .card-grid.three-col :global(.card-image img) { + max-width: 100%; + max-height: 100%; + width: auto; + height: auto; + } + /* Tablet breakpoint - 1199px */ @media screen and (max-width: 1199px) { .ds-hero-banner { diff --git a/docs/src/pages/search.astro b/docs/src/pages/search.astro index 8e52c4b6c2..6ec5447dd2 100644 --- a/docs/src/pages/search.astro +++ b/docs/src/pages/search.astro @@ -12,11 +12,13 @@ import { SiteNav } from '../components/SiteNav'; import { MobileHeader } from '../components/MobileHeader'; import { SearchPage } from '../components/search'; import { getNavCategories } from '../lib/nav-categories'; +import { getGetStartedNav } from '../lib/get-started-nav'; // Get query from URL parameters const url = new URL(Astro.request.url); const initialQuery = url.searchParams.get('q') || ''; const navCategories = await getNavCategories(); +const getStartedNav = await getGetStartedNav(); --- @@ -28,6 +30,7 @@ const navCategories = await getNavCategories(); client:only="react" initialSection="components" categories={navCategories} + getStartedNav={getStartedNav} /> diff --git a/docs/src/scripts/aliases-to-redirects.mjs b/docs/src/scripts/aliases-to-redirects.mjs new file mode 100644 index 0000000000..b8cb3254f2 --- /dev/null +++ b/docs/src/scripts/aliases-to-redirects.mjs @@ -0,0 +1,114 @@ +/** + * Build a redirects map from `aliases` frontmatter on entries in the + * examples and productTypes content collections. + * + * Each alias on an entry becomes a redirect from `/examples/${alias}` to + * the entry's canonical URL. Both collections route under `/examples/`, + * so product-type aliases (none today, but supported) also redirect there + * via the [family] route. + * + * Imported from astro.config.mjs at config-load time. Sync fs reads keep + * the function callable before the content collection pipeline runs. + */ + +import { readdirSync, readFileSync, statSync } from "node:fs"; +import { join, dirname, relative } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const DOCS_ROOT = join(__dirname, "../.."); + +const COLLECTION_ROOTS = [ + join(DOCS_ROOT, "src/content/examples"), + join(DOCS_ROOT, "src/content/productTypes"), +]; + +/** + * Minimal YAML frontmatter parser. Mirrors the parser in + * build-search-index.ts. Only handles the subset our content uses: + * scalar values and list-of-strings for `aliases`. + */ +function parseFrontmatter(content) { + const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/); + if (!match) return {}; + + const result = {}; + let currentKey = null; + let currentArray = null; + + for (const line of match[1].split("\n")) { + const arrayItem = line.match(/^\s+-\s+(.*)/); + if (arrayItem && currentArray) { + currentArray.push(arrayItem[1].trim()); + continue; + } + + const kv = line.match(/^(\w+):\s*(.*)/); + if (!kv) continue; + + if (currentKey && currentArray) { + result[currentKey] = currentArray; + } + currentKey = kv[1]; + const value = kv[2].trim(); + if (value === "" || value === "|") { + currentArray = []; + } else { + currentArray = null; + result[currentKey] = value.replace(/^["']|["']$/g, ""); + } + } + + if (currentKey && currentArray) { + result[currentKey] = currentArray; + } + return result; +} + +/** + * Recursively find every `index.mdx` under a collection root, including + * nested entries like `examples/workspace/dashboard/index.mdx`. + */ +function findIndexMdx(dir) { + const out = []; + for (const entry of readdirSync(dir)) { + const path = join(dir, entry); + if (!statSync(path).isDirectory()) continue; + const indexPath = join(path, "index.mdx"); + try { + if (statSync(indexPath).isFile()) out.push(indexPath); + } catch { + // No index.mdx in this directory; keep recursing. + } + out.push(...findIndexMdx(path)); + } + return out; +} + +export function buildAliasRedirects() { + const redirects = {}; + + for (const root of COLLECTION_ROOTS) { + try { + statSync(root); + } catch { + continue; + } + + for (const file of findIndexMdx(root)) { + const fm = parseFrontmatter(readFileSync(file, "utf-8")); + if (!Array.isArray(fm.aliases) || fm.aliases.length === 0) continue; + + const slug = relative(root, dirname(file)); + const target = `/examples/${slug}`; + + for (const alias of fm.aliases) { + const from = `/examples/${alias}`; + if (from === target) continue; + redirects[from] = target; + } + } + } + + return redirects; +} diff --git a/docs/src/scripts/build-search-index.ts b/docs/src/scripts/build-search-index.ts index 3b2258ff69..e6c4137fa8 100644 --- a/docs/src/scripts/build-search-index.ts +++ b/docs/src/scripts/build-search-index.ts @@ -8,7 +8,7 @@ */ import { readFileSync, writeFileSync, readdirSync, statSync, existsSync, mkdirSync } from 'node:fs'; -import { join, basename, dirname } from 'node:path'; +import { join, basename, dirname, relative, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; // Get directory paths relative to this script @@ -20,6 +20,8 @@ const ROOT = join(__dirname, '../..'); // Content directories const COMPONENTS_DIR = join(ROOT, 'src/content/components'); const EXAMPLES_DIR = join(ROOT, 'src/content/examples'); +const GET_STARTED_DIR = join(ROOT, 'src/content/get-started'); +const PRODUCT_TYPES_DIR = join(ROOT, 'src/content/productTypes'); const OUTPUT_FILE = join(ROOT, 'public/search-index.json'); // ============================================================================ @@ -43,15 +45,26 @@ interface ExampleEntry { title: string; description?: string; status: string; - categories: string[]; + size: string; // "interaction" | "section" | "page" | "task" | "product" + productType?: string; // "workspace" | "public-form" tags: string[]; - components: string[]; // What components this example uses - scale: string; - userType: string; + components: string[]; // What components this example uses + aliases: string[]; // Secondary slugs that surface this entry in search slug: string; } -type SearchEntry = ComponentEntry | ExampleEntry; +interface PageEntry { + type: 'page'; + id: string; + title: string; + description?: string; + status: string; + category: string; // High-level grouping for filter UI ("get started") + tags: string[]; // Synthesized from section so queries like "developer setup" hit + slug: string; // URL path without leading slash (e.g. "get-started/developers/setup") +} + +type SearchEntry = ComponentEntry | ExampleEntry | PageEntry; // ============================================================================ // Frontmatter Parsing @@ -155,6 +168,20 @@ function extractFirstParagraph(body: string): string | undefined { return paragraph || undefined; } +function isHidden(frontmatter: Record): boolean { + return String(frontmatter.hidden ?? '').toLowerCase() === 'true'; +} + +function normalizeDescription(value: string | undefined): string | undefined { + if (!value) return undefined; + + const withoutHtml = value.replace(/<[^>]+>/g, ' '); + const withoutMarkdownLinks = withoutHtml.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1'); + const normalized = withoutMarkdownLinks.replace(/\s+/g, ' ').trim(); + + return normalized || undefined; +} + // ============================================================================ // File Processing // ============================================================================ @@ -170,7 +197,7 @@ function processComponent(filePath: string): ComponentEntry | null { const id = basename(filePath, '.mdx'); // Skip hidden components - if (frontmatter.hidden === true || frontmatter.hidden === 'true') { + if (isHidden(frontmatter)) { return null; } @@ -178,7 +205,9 @@ function processComponent(filePath: string): ComponentEntry | null { type: 'component', id, name: String(frontmatter.name || id), - description: frontmatter.description ? String(frontmatter.description) : undefined, + description: normalizeDescription( + frontmatter.description ? String(frontmatter.description) : undefined, + ), status: String(frontmatter.status || 'stable'), category: String(frontmatter.category || 'utilities'), tags: Array.isArray(frontmatter.tags) ? frontmatter.tags.map(String) : [], @@ -193,15 +222,27 @@ function processComponent(filePath: string): ComponentEntry | null { /** * Process an example MDX file into a search entry. * Examples live in subdirectories: examples/[name]/index.mdx + * or nested: examples/[family]/[page]/index.mdx + * + * The slug is derived from the path relative to EXAMPLES_DIR so that nested + * entries (workspace/dashboard, etc.) get path-shaped slugs matching Astro's + * content-collection routing. Frontmatter `id` is kept for stable cross- + * references but no longer drives the URL. */ function processExample(filePath: string): ExampleEntry | null { try { const content = readFileSync(filePath, 'utf-8'); const { frontmatter, body } = parseFrontmatter(content); - // Get ID from directory name - const dirName = basename(dirname(filePath)); - const id = String(frontmatter.id || dirName); + // Skip hidden examples + if (isHidden(frontmatter)) { + return null; + } + + // Slug = path within EXAMPLES_DIR (e.g., "workspace/dashboard", "start-page"). + // Use forward slashes on every OS so URLs are consistent. + const slug = relative(EXAMPLES_DIR, dirname(filePath)).split(sep).join('/'); + const id = String(frontmatter.id || basename(dirname(filePath))); // Extract description from body if not in frontmatter const description = frontmatter.description @@ -212,18 +253,20 @@ function processExample(filePath: string): ExampleEntry | null { type: 'example', id, title: String(frontmatter.title || id), - description, + description: normalizeDescription(description), status: String(frontmatter.status || 'published'), - categories: Array.isArray(frontmatter.categories) - ? frontmatter.categories.map(String) - : [], + size: String(frontmatter.size || 'section'), + productType: frontmatter.productType + ? String(frontmatter.productType) + : undefined, tags: Array.isArray(frontmatter.tags) ? frontmatter.tags.map(String) : [], components: Array.isArray(frontmatter.components) ? frontmatter.components.map(String) : [], - scale: String(frontmatter.scale || 'interaction'), - userType: String(frontmatter.userType || 'both'), - slug: String(frontmatter.slug || id), + aliases: Array.isArray(frontmatter.aliases) + ? frontmatter.aliases.map(String) + : [], + slug, }; } catch (error) { console.error(`Error processing example ${filePath}:`, error); @@ -231,6 +274,110 @@ function processExample(filePath: string): ExampleEntry | null { } } +/** + * Synthesize search tags from a Get Started section. + * Includes the singular form so a query like "developer setup" matches + * a page whose section is "developers". + */ +function tagsForSection(section: string): string[] { + const singular: Record = { + designers: 'designer', + developers: 'developer', + }; + const tags = [section]; + if (singular[section]) tags.push(singular[section]); + return tags; +} + +/** + * Process a Get Started MDX file into a search entry. + * The collection root holds the index page; nested folders are URL segments. + */ +function processGetStartedPage(filePath: string): PageEntry | null { + try { + const content = readFileSync(filePath, 'utf-8'); + const { frontmatter } = parseFrontmatter(content); + + // Derive ID from path relative to the collection root, minus the extension. + // e.g. "developers/setup.mdx" -> "developers/setup" + // Normalize backslashes to forward slashes so Windows-built indexes still produce valid URLs. + const relPath = filePath + .slice(GET_STARTED_DIR.length + 1) + .replace(/\.mdx$/, '') + .replace(/\\/g, '/'); + + // The index entry lives at /get-started, every other entry under /get-started/. + const slug = relPath === 'index' ? 'get-started' : `get-started/${relPath}`; + + const section = String(frontmatter.section || ''); + + return { + type: 'page', + id: String(frontmatter.id || relPath), + title: String(frontmatter.title || relPath), + description: frontmatter.description ? String(frontmatter.description) : undefined, + status: String(frontmatter.status || 'published'), + category: 'get started', + tags: section ? tagsForSection(section) : [], + slug, + }; + } catch (error) { + console.error(`Error processing get-started page ${filePath}:`, error); + return null; + } +} + +/** + * Process a productType MDX file into a search entry. + * + * ProductTypes are the "starting points" for each kind of digital service + * (workspace, public-form). Their overview pages live at /examples/[slug]/ + * via the [family]/index.astro route, so we synthesize them into the same + * search shape as page-scale examples with size="product". This replaces + * the hand-authored stub entries that previously lived in examples/. + */ +function processProductType(filePath: string): ExampleEntry | null { + try { + const content = readFileSync(filePath, 'utf-8'); + const { frontmatter, body } = parseFrontmatter(content); + + const slug = relative(PRODUCT_TYPES_DIR, dirname(filePath)) + .split(sep) + .join('/'); + const id = String(frontmatter.id || slug); + + // Summary may contain inline HTML formatting (br, span) for the overview + // page. Take the prose before the first tag — enough for search results, + // which truncate to ~80 chars anyway, and safer than regex-stripping. + const description = frontmatter.summary + ? String(frontmatter.summary).split('<')[0].trim() + : frontmatter.description + ? String(frontmatter.description) + : extractFirstParagraph(body); + + return { + type: 'example', + id, + title: String(frontmatter.title || id), + description, + status: String(frontmatter.status || 'published'), + size: 'product', + productType: undefined, + tags: Array.isArray(frontmatter.tags) ? frontmatter.tags.map(String) : [], + components: Array.isArray(frontmatter.components) + ? frontmatter.components.map(String) + : [], + aliases: Array.isArray(frontmatter.aliases) + ? frontmatter.aliases.map(String) + : [], + slug, + }; + } catch (error) { + console.error(`Error processing productType ${filePath}:`, error); + return null; + } +} + /** * Recursively find all MDX files in a directory. */ @@ -288,6 +435,32 @@ function main() { } console.log(` Found ${exampleFiles.length} files, indexed ${entries.length - exampleCount} examples`); + // Process Get Started pages + console.log('Processing get-started pages...'); + const getStartedFiles = findMdxFiles(GET_STARTED_DIR); + const getStartedCount = entries.length; + for (const file of getStartedFiles) { + const entry = processGetStartedPage(file); + if (entry) { + entries.push(entry); + } + } + console.log(` Found ${getStartedFiles.length} files, indexed ${entries.length - getStartedCount} pages`); + + // Process productTypes (workspace, public-form, etc.) — surfaced as + // size:product overview entries so the same Cmd-K query that finds a + // page-scale entry also finds the introductory page for its product type. + console.log('Processing productTypes...'); + const productTypeFiles = findMdxFiles(PRODUCT_TYPES_DIR); + const productTypeCountBefore = entries.length; + for (const file of productTypeFiles) { + const entry = processProductType(file); + if (entry) { + entries.push(entry); + } + } + console.log(` Found ${productTypeFiles.length} files, indexed ${entries.length - productTypeCountBefore} productTypes`); + // Ensure public directory exists const publicDir = dirname(OUTPUT_FILE); if (!existsSync(publicDir)) { diff --git a/docs/src/scripts/extract-api.ts b/docs/src/scripts/extract-api.ts index 2c7f7cadee..6eb01bdedc 100644 --- a/docs/src/scripts/extract-api.ts +++ b/docs/src/scripts/extract-api.ts @@ -15,6 +15,7 @@ import * as fs from "fs"; import * as path from "path"; import { fileURLToPath } from "url"; +import * as ts from "typescript"; // ============================================================================= // Configuration @@ -31,6 +32,10 @@ const UI_COMPONENTS_PATH = path.join( "libs/web-components/src/components", ); const OUTPUT_PATH = path.join(WORKSPACE_ROOT, "docs/generated/component-apis"); +const DOCS_COMPONENT_CONTENT_PATH = path.join( + WORKSPACE_ROOT, + "docs/src/content/components", +); // ============================================================================= // Output Types (matching content model spec) @@ -51,20 +56,36 @@ interface ExtractedEvent { name: string; type: string; description: string; // Empty - filled by human content - frameworks: ("react" | "angular" | "web-component")[]; + frameworks: ("react" | "angular" | "webComponents")[]; } interface ExtractedSlot { name: string; + type?: string; description: string; // Empty - filled by human content + required?: boolean; } interface ExtractedComponentAPI { componentSlug: string; extractedFrom: string; - props: ExtractedProp[]; - events: ExtractedEvent[]; - slots: ExtractedSlot[]; + frameworks: { + react: { + props: ExtractedProp[]; + events: ExtractedEvent[]; + slots: ExtractedSlot[]; + }; + angular: { + props: ExtractedProp[]; + events: ExtractedEvent[]; + slots: ExtractedSlot[]; + }; + webComponents: { + props: ExtractedProp[]; + events: ExtractedEvent[]; + slots: ExtractedSlot[]; + }; + }; } // ============================================================================= @@ -90,6 +111,119 @@ interface ParsedPropRaw { deprecated: boolean; } +interface WrapperExtraction { + found: boolean; + props: ExtractedProp[]; + events: ExtractedEvent[]; + slotDescriptions: Record; + slotNameAliases: Record; + slotRequired: Record; +} + +const INTERNAL_PROP_NAMES = new Set(["publicformsummaryorder", "filterablecontext", "version"]); +const INTERNAL_SLOT_NAMES = new Set(["version"]); +const INTERNAL_EVENT_NAMES = new Set(["_revealChange", "_update"]); + +const DOCS_EXCLUDED_COMPONENTS = new Set(["focus-trap", "form-stepper", "scrollable"]); +const DOCS_FORCED_COMPONENTS = new Set(["table-sort-header"]); +const WRAPPER_COMPONENT_ALIASES: Record = { + "temporary-notification": "temporary-notification-ctrl", +}; +const WEB_COMPONENT_INTERNAL_EVENT_OVERRIDES: Record> = { + "work-side-menu-group": new Set(["_hoverItem"]), + "work-side-menu-item": new Set([ + "_blurItem", + "_desktopPopoverClose", + "_desktopPopoverOpen", + "_hoverItem", + "_itemCurrent", + "_mobilePopoverClose", + "_mobilePopoverOpen", + "_mountItem", + "_navigate", + ]), +}; +const WEB_COMPONENT_EVENT_TYPE_OVERRIDES: Record> = { + dropdown: { + _change: "CustomEvent<{ name?: string; value?: string; event: Event }>", + }, + "file-upload-input": { + _selectFile: "CustomEvent<{ file: File; event: Event }>", + }, +}; +const SLOT_TYPE_OVERRIDES: Record< + string, + Partial>> +> = { + footer: { + react: { + nav: "GoabAppFooterNavSection", + meta: "GoabAppFooterMetaSection", + }, + angular: { + nav: "GoabAppFooterNavSection", + meta: "GoabAppFooterMetaSection", + }, + webComponents: { + nav: "goa-app-footer-nav-section", + meta: "goa-app-footer-meta-section", + }, + }, +}; +const ALLOW_INTERNAL_PROP_BY_COMPONENT: Record> = { + "microsite-header": new Set(["version"]), +}; + +function shouldSkipInternalProp(componentName: string, propName: string): boolean { + const normalizedComponentName = toKebabCase(componentName); + const normalizedName = propName.toLowerCase(); + if (ALLOW_INTERNAL_PROP_BY_COMPONENT[normalizedComponentName]?.has(normalizedName)) { + return false; + } + return INTERNAL_PROP_NAMES.has(normalizedName); +} + +function shouldAllowInternalProp(componentName: string, propName: string): boolean { + const normalizedComponentName = toKebabCase(componentName); + return Boolean( + ALLOW_INTERNAL_PROP_BY_COMPONENT[normalizedComponentName]?.has(propName.toLowerCase()), + ); +} + +function isInternalPropName(propName: string): boolean { + return INTERNAL_PROP_NAMES.has(propName.toLowerCase()); +} + +function isStandardV1V2VersionProp(prop: ExtractedProp | undefined): boolean { + if (!prop || prop.name.toLowerCase() !== "version") return false; + + const values = (prop.values || []).map((value) => String(value).replace(/['"]/g, "").trim()); + if (values.length === 2 && values.includes("1") && values.includes("2")) { + return true; + } + + const normalizedType = String(prop.type || "") + .replace(/['"]/g, "") + .replace(/\s+/g, ""); + + return normalizedType === "1|2"; +} + +function specializeAngularValuePropFromReact( + angularProps: ExtractedProp[], + reactProps: ExtractedProp[], +): void { + const angularValueProp = angularProps.find((prop) => prop.name === "value"); + const reactValueProp = reactProps.find((prop) => prop.name === "value"); + + if (!angularValueProp || !reactValueProp) return; + if (angularValueProp.type !== "unknown | null | undefined") return; + if (!reactValueProp.type || reactValueProp.type === "unknown") return; + + angularValueProp.type = reactValueProp.type; + angularValueProp.values = reactValueProp.values; +} + // ============================================================================= // JSDoc Parser // ============================================================================= @@ -153,11 +287,35 @@ function parseJSDocContent(rawComment: string): { const description = cleaned .replace(/@required\s*/gi, "") .replace(/@internal\s*/gi, "") + .replace(/@deprecated\s*/gi, "") .trim(); return { description, required, internal, deprecated }; } +function parseDescriptionFromJSDoc(rawComment: string | undefined): string { + if (!rawComment) return ""; + const { description } = parseJSDocContent(rawComment); + return description; +} + +function extractDefaultFromDescription(description: string): { + description: string; + defaultValue: string | null; +} { + const defaultMatch = description.match(/@default\s+([^@]+)/i); + const defaultValue = defaultMatch ? defaultMatch[1].trim().replace(/^["']|["']$/g, "") : null; + const cleanDescription = description.replace(/@default\s+([^@]+)/gi, "").trim(); + return { + description: cleanDescription, + defaultValue, + }; +} + +function isReadonlyDescription(description: string): boolean { + return /read[ -]?only\b|set by the component\b/i.test(description); +} + // ============================================================================= // Svelte Parser // ============================================================================= @@ -274,18 +432,11 @@ function extractProps( typeAliases: Map, ): ParsedPropRaw[] { const props: ParsedPropRaw[] = []; + const customElementPropAttributeMap = extractCustomElementPropAttributeMap(content); // Build JSDoc map for descriptions const jsDocMap = buildJSDocMap(content); - // Internal props to skip (used by public forms system, not useful for devs) - const internalProps = new Set([ - "publicformsummaryorder", - "action", - "actionarg", - "actionargs", - ]); - // Match: export let propName: Type = defaultValue; const propMatches = content.matchAll( /export\s+let\s+(\w+)(?:\s*:\s*([^=;]+?))?(?:\s*=\s*([^;]+?))?;/g, @@ -293,16 +444,18 @@ function extractProps( for (const match of propMatches) { const rawName = match[1]; - let type = match[2]?.trim() || "any"; const defaultStr = match[3]?.trim(); + let type = match[2]?.trim() || inferTypeFromDefault(defaultStr); // Skip private props (starting with _) if (rawName.startsWith("_")) continue; - // Skip internal props - if (internalProps.has(rawName.toLowerCase())) continue; + // Keep `version` on Web Component docs; wrappers are filtered later. + if (rawName.toLowerCase() !== "version" && shouldSkipInternalProp(componentName, rawName)) { + continue; + } - const name = toReactPropName(rawName); + const name = customElementPropAttributeMap.get(rawName) || rawName.toLowerCase(); let typeLabel: string | undefined; let values: string[] | undefined; @@ -317,8 +470,8 @@ function extractProps( // Handle special types if (type.includes("GoAIconType") || type.includes("GoaIconType")) { - typeLabel = "GoAIconType"; - type = "GoAIconType"; + typeLabel = "GoabIconType"; + type = "GoabIconType"; } else if (type === "Spacing" || type.includes("Spacing")) { typeLabel = "Spacing"; type = "Spacing"; @@ -382,12 +535,23 @@ function extractProps( // Get JSDoc info from map (description + required flag) const jsDocInfo = jsDocMap.get(rawName); - // Skip @internal props — not for public API docs - if (jsDocInfo?.internal) continue; + // Keep Svelte `version` visible in Web Component docs. + if ( + jsDocInfo?.internal && + rawName.toLowerCase() !== "version" && + !shouldAllowInternalProp(componentName, rawName) + ) { + continue; + } + + // Skip @deprecated props — not for public API docs + if (jsDocInfo?.deprecated) continue; const description = jsDocInfo?.description || ""; - // Use @required from JSDoc if present, otherwise fall back to checking if no default value - const isRequired = jsDocInfo?.required || defaultStr === undefined; + const isReadonly = isReadonlyDescription(description); + // Use @required from JSDoc if present, otherwise fall back to checking if no default value. + // Read-only, component-managed values should not be presented as consumer-required props. + const isRequired = Boolean(jsDocInfo?.required) || (!isReadonly && defaultStr === undefined); props.push({ name, @@ -406,12 +570,28 @@ function extractProps( return props; } +function extractCustomElementPropAttributeMap(content: string): Map { + const map = new Map(); + const optionsTagMatch = content.match(//); + if (!optionsTagMatch) return map; + + const optionsTag = optionsTagMatch[0]; + const propAttributeMatches = optionsTag.matchAll( + /(?:^|\n)\s*(\w+)\s*:\s*\{[^{}]*attribute\s*:\s*["']([^"']+)["'][^{}]*\}/g, + ); + + for (const match of propAttributeMatches) { + const propName = match[1]; + const attributeName = match[2]; + map.set(propName, attributeName); + } + + return map; +} + // Known limitation: only scans the top-level Svelte file, so components that // delegate event dispatching to child Svelte files will have missing events. -// Affected: push-drawer (_close), file-upload-card (_cancel, _delete), -// form (_complete, _continue, _stateChange). -// This will be resolved when #3361 (JSDoc in wrappers) lands and the extractor -// can read events from the React/Angular wrappers instead. +// Events from React/Angular wrappers fill this gap for those frameworks. function extractEvents(content: string): string[] { const eventNames = new Set(); @@ -435,17 +615,6 @@ function extractEvents(content: string): string[] { } } - // Pattern 3: _rootEl?.dispatchEvent(new CustomEvent("_eventName", ...)) - const rootElMatches = content.matchAll( - /_rootEl\??\s*\.?\s*dispatchEvent\s*\(\s*new\s+CustomEvent\s*\(\s*["']([^"']+)["']/g, - ); - for (const match of rootElMatches) { - const eventName = match[1]; - if (!eventName.includes("::")) { - eventNames.add(eventName); - } - } - return Array.from(eventNames); } @@ -463,13 +632,893 @@ function extractSlots(content: string): string[] { } } - // Default slot: or - const hasDefaultSlot = /|>[^<]*<\/slot>)/.test(content); - if (hasDefaultSlot && !seenNames.has("default")) { - slotNames.unshift("default"); + return slotNames; +} + +function parseWrapperPropValues(type: string): string[] | undefined { + if (!type.includes("|")) return undefined; + const values = type + .split("|") + .map((v) => v.trim().replace(/['"]/g, "")) + .filter((v) => v.length > 0 && v !== "undefined" && v !== "null"); + return values.length > 0 ? values : undefined; +} + +function inferTypeFromDefault(defaultValue: string | undefined): string { + if (!defaultValue) return "any"; + + const trimmed = defaultValue.trim(); + if (trimmed === "true" || trimmed === "false") return "boolean"; + if (!isNaN(Number(trimmed))) return "number"; + if (/^["'`]/.test(trimmed)) return "string"; + if (trimmed.startsWith("[")) return "unknown[]"; + if (trimmed.startsWith("{")) return "Record"; + + return "any"; +} + +function normalizeName(value: string): string { + return value.toLowerCase().replace(/[^a-z0-9]/g, ""); +} + +function getMatchingSlotName(propName: string, slotNames: string[]): string | null { + if (propName === "children") { + return "default"; } - return slotNames; + const normalizedPropName = normalizeName(propName); + const directMatch = + slotNames.find((slotName) => normalizeName(slotName) === normalizedPropName) ?? null; + if (directMatch) return directMatch; + + // Common wrapper naming pattern: slot "account" exposed as prop "accountContent". + const contentSuffixMatch = propName.match(/^(.+?)content$/i); + if (contentSuffixMatch?.[1]) { + const baseName = normalizeName(contentSuffixMatch[1]); + return slotNames.find((slotName) => normalizeName(slotName) === baseName) ?? null; + } + + return null; +} + +interface ReactCallbackAliasInfo { + typeParam?: string; + defaultTypeArg?: string; + detailType: string; +} + +interface ReactInterfaceInfo { + name: string; + exported: boolean; + extendsNames: string[]; + declaration: ts.InterfaceDeclaration; +} + +function getTypeReferenceName(typeNode: ts.TypeReferenceNode, sourceFile: ts.SourceFile): string { + const typeName = typeNode.typeName.getText(sourceFile); + return typeName.split(".").pop() || typeName; +} + +function createTsSourceFile(filePath: string, content: string): ts.SourceFile { + const scriptKind = filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS; + return ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, scriptKind); +} + +function getNodeDecorators(node: ts.Node): readonly ts.Decorator[] { + if (typeof ts.canHaveDecorators === "function" && ts.canHaveDecorators(node)) { + return ts.getDecorators(node) ?? []; + } + + const legacyDecorators = (node as { decorators?: readonly ts.Decorator[] }).decorators; + return legacyDecorators ?? []; +} + +function getDecoratorCall(node: ts.Node, decoratorName: string): ts.CallExpression | null { + for (const decorator of getNodeDecorators(node)) { + const expression = decorator.expression; + if (ts.isCallExpression(expression) && ts.isIdentifier(expression.expression)) { + if (expression.expression.text === decoratorName) { + return expression; + } + } + + if (ts.isIdentifier(expression) && expression.text === decoratorName) { + return null; + } + } + + return null; +} + +function isAngularInputRequired(inputDecoratorCall: ts.CallExpression | null): boolean { + if (!inputDecoratorCall || inputDecoratorCall.arguments.length === 0) return false; + + const firstArg = inputDecoratorCall.arguments[0]; + if (!firstArg || !ts.isObjectLiteralExpression(firstArg)) return false; + + const requiredProp = firstArg.properties.find((prop) => { + if (!ts.isPropertyAssignment(prop)) return false; + if (ts.isIdentifier(prop.name)) return prop.name.text === "required"; + if (ts.isStringLiteral(prop.name)) return prop.name.text === "required"; + return false; + }); + + if (!requiredProp || !ts.isPropertyAssignment(requiredProp)) return false; + + return requiredProp.initializer.kind === ts.SyntaxKind.TrueKeyword; +} + +function hasDecorator(node: ts.Node, decoratorName: string): boolean { + for (const decorator of getNodeDecorators(node)) { + const expression = decorator.expression; + if (ts.isCallExpression(expression) && ts.isIdentifier(expression.expression)) { + if (expression.expression.text === decoratorName) { + return true; + } + } + + if (ts.isIdentifier(expression) && expression.text === decoratorName) { + return true; + } + } + + return false; +} + +function parseReactInterfaces(content: string, filePath: string): Map { + const interfaces = new Map(); + const sourceFile = createTsSourceFile(filePath, content); + + for (const statement of sourceFile.statements) { + if (!ts.isInterfaceDeclaration(statement)) continue; + + const name = statement.name.text; + const exported = statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) ?? false; + const extendsNames = + statement.heritageClauses + ?.filter((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword) + .flatMap((clause) => + clause.types + .map((typeNode) => typeNode.expression.getText(sourceFile)) + .map((value) => value.split(".").pop() || value) + .filter(Boolean), + ) ?? []; + + interfaces.set(name, { + name, + exported, + extendsNames, + declaration: statement, + }); + } + + return interfaces; +} + +function resolvePrimaryReactPropsInterface( + componentName: string, + interfaces: Map, +): string | null { + const componentPart = capitalize(toCamelCase(componentName)); + const candidates = [`Goab${componentPart}Props`, `GoA${componentPart}Props`]; + + for (const name of candidates) { + const match = interfaces.get(name); + if (match?.exported) return name; + } + + for (const name of candidates) { + if (interfaces.has(name)) return name; + } + + for (const info of interfaces.values()) { + if (info.exported && /^(?:Goab|GoA)\w+Props$/.test(info.name)) { + return info.name; + } + } + + for (const info of interfaces.values()) { + if (/^(?:Goab|GoA)\w+Props$/.test(info.name)) { + return info.name; + } + } + + return null; +} + +function collectReactInterfaceMembers( + interfaceName: string, + interfaces: Map, + sourceFile: ts.SourceFile, + visited: Set = new Set(), +): ts.TypeElement[] { + if (visited.has(interfaceName)) return []; + visited.add(interfaceName); + + const info = interfaces.get(interfaceName); + if (!info) return []; + + const inheritedMembers = info.extendsNames.flatMap((baseName) => + collectReactInterfaceMembers(baseName, interfaces, sourceFile, visited), + ); + + return [...inheritedMembers, ...info.declaration.members]; +} + +function getFunctionLikeFirstParameterType( + fn: ts.FunctionDeclaration | ts.ArrowFunction | ts.FunctionExpression, +): ts.TypeNode | null { + return fn.parameters[0]?.type ?? null; +} + +function resolvePrimaryReactComponentParameterType( + componentName: string, + sourceFile: ts.SourceFile, +): ts.TypeNode | null { + const componentPart = capitalize(toCamelCase(componentName)); + const candidates = [`Goab${componentPart}`, `GoA${componentPart}`]; + + for (const statement of sourceFile.statements) { + if ( + ts.isFunctionDeclaration(statement) && + statement.name && + candidates.includes(statement.name.text) && + statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) + ) { + return getFunctionLikeFirstParameterType(statement); + } + + if ( + ts.isVariableStatement(statement) && + statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) + ) { + for (const declaration of statement.declarationList.declarations) { + if (!ts.isIdentifier(declaration.name) || !candidates.includes(declaration.name.text)) continue; + if (!declaration.initializer) continue; + + if (ts.isArrowFunction(declaration.initializer) || ts.isFunctionExpression(declaration.initializer)) { + return getFunctionLikeFirstParameterType(declaration.initializer); + } + } + } + } + + return null; +} + +function collectReactTypeNodeMembers( + typeNode: ts.TypeNode | null, + interfaces: Map, + sourceFile: ts.SourceFile, + visitedTypeRefs: Set = new Set(), +): ts.TypeElement[] { + if (!typeNode) return []; + + if (ts.isParenthesizedTypeNode(typeNode)) { + return collectReactTypeNodeMembers(typeNode.type, interfaces, sourceFile, visitedTypeRefs); + } + + if (ts.isIntersectionTypeNode(typeNode)) { + return typeNode.types.flatMap((memberType) => + collectReactTypeNodeMembers(memberType, interfaces, sourceFile, visitedTypeRefs), + ); + } + + if (ts.isTypeLiteralNode(typeNode)) { + return [...typeNode.members]; + } + + if (ts.isTypeReferenceNode(typeNode)) { + const typeName = getTypeReferenceName(typeNode, sourceFile); + if (visitedTypeRefs.has(typeName)) return []; + visitedTypeRefs.add(typeName); + return collectReactInterfaceMembers(typeName, interfaces, sourceFile); + } + + return []; +} + +function hasReactMarginsInHierarchy( + interfaceName: string, + interfaces: Map, + visited: Set = new Set(), +): boolean { + if (visited.has(interfaceName)) return false; + visited.add(interfaceName); + + const info = interfaces.get(interfaceName); + if (!info) return false; + + if (info.extendsNames.includes("Margins")) { + return true; + } + + return info.extendsNames.some((baseName) => + hasReactMarginsInHierarchy(baseName, interfaces, visited), + ); +} + +function extractReactCallbackAliases(sourceFile: ts.SourceFile): Map { + const aliases = new Map(); + for (const statement of sourceFile.statements) { + if (!ts.isTypeAliasDeclaration(statement)) continue; + if (!ts.isFunctionTypeNode(statement.type)) continue; + + const aliasName = statement.name.text; + const typeParam = statement.typeParameters?.[0]?.name.text; + const defaultTypeArg = statement.typeParameters?.[0]?.default?.getText(sourceFile)?.trim(); + const detailType = cleanType( + statement.type.parameters[0]?.type?.getText(sourceFile)?.trim() || "unknown", + ); + + aliases.set(aliasName, { + typeParam, + defaultTypeArg, + detailType, + }); + } + + return aliases; +} + +function parseGenericAliasUsage(type: string): { alias: string; typeArg?: string } { + const aliasMatch = type.match(/^([A-Za-z_]\w*)(?:<\s*([^>]+)\s*>)?$/); + if (!aliasMatch) { + return { alias: type }; + } + + return { + alias: aliasMatch[1], + typeArg: aliasMatch[2]?.trim(), + }; +} + +function resolveReactCallbackEventType( + callbackType: string, + callbackAliases: Map, +): string { + if (callbackType.includes("=>")) { + return callbackType; + } + + const { alias, typeArg } = parseGenericAliasUsage(callbackType); + const aliasInfo = callbackAliases.get(alias); + if (!aliasInfo) { + return callbackType; + } + + const toFunctionSignature = (detailType: string) => `(detail: ${detailType}) => void`; + + if (!aliasInfo.typeParam) { + return toFunctionSignature(aliasInfo.detailType); + } + + const resolvedTypeArg = typeArg || aliasInfo.defaultTypeArg; + if (!resolvedTypeArg) { + return toFunctionSignature(aliasInfo.detailType); + } + + const typeParamPattern = new RegExp(`\\b${aliasInfo.typeParam}\\b`, "g"); + let resolvedDetailType = aliasInfo.detailType.replace(typeParamPattern, resolvedTypeArg); + + // Keep docs concise when the generic argument matches the alias default. + if (aliasInfo.defaultTypeArg && resolvedTypeArg === aliasInfo.defaultTypeArg) { + const defaultGenericPattern = new RegExp(`\\<\\s*${escapeRegExp(resolvedTypeArg)}\\s*\\>`, "g"); + resolvedDetailType = resolvedDetailType.replace(defaultGenericPattern, ""); + } + + return toFunctionSignature(resolvedDetailType); +} + +function isReactCallbackAliasType( + type: string, + callbackAliases: Map, +): boolean { + if (type.includes("=>")) { + return true; + } + + const { alias } = parseGenericAliasUsage(type); + return callbackAliases.has(alias); +} + +function isFunctionType(type: string): boolean { + return /^\(\s*[^)]*\)\s*=>\s*.+$/.test(type.trim()); +} + +function isSlotCarrierType(type: string): boolean { + return /React(?:\.[A-Za-z]+)?(?:Node|Element)(?:<.+?>)?|JSX\.Element|TemplateRef\s*<.+?>/.test(type); +} + +function isPureSlotCarrierType(type: string): boolean { + const members = type + .split("|") + .map((part) => part.trim()) + .filter((part) => part.length > 0 && part !== "null" && part !== "undefined"); + + if (members.length === 0) return false; + return members.every((part) => isSlotCarrierType(part)); +} + +function toEventCallbackType(type: string): string { + if (type === "void") { + return "() => void"; + } + return `(event: ${type}) => void`; +} + +function dedupeByName(items: T[]): T[] { + const seen = new Set(); + return items.filter((item) => { + if (seen.has(item.name)) return false; + seen.add(item.name); + return true; + }); +} + +function createEmptyWrapperExtraction(found: boolean = false): WrapperExtraction { + return { + found, + props: [], + events: [], + slotDescriptions: {}, + slotNameAliases: {}, + slotRequired: {}, + }; +} + +function findImmediateJsDocBefore(content: string, markerIndex: number): string | undefined { + const beforeMarker = content.slice(0, markerIndex); + const start = beforeMarker.lastIndexOf("/**"); + if (start === -1) return undefined; + + const end = beforeMarker.indexOf("*/", start + 3); + if (end === -1) return undefined; + + const tail = beforeMarker.slice(end + 2); + if (!/^\s*$/.test(tail)) return undefined; + + return beforeMarker.slice(start + 3, end); +} + +function extractAngularBaseComponentProps(): Map { + const baseFile = path.join( + WORKSPACE_ROOT, + "libs/angular-components/src/lib/components/base.component.ts", + ); + + if (!fs.existsSync(baseFile)) return new Map(); + + const content = fs.readFileSync(baseFile, "utf-8"); + const sourceFile = createTsSourceFile(baseFile, content); + const props = new Map(); + + const classDecls = sourceFile.statements.filter( + (node): node is ts.ClassDeclaration => ts.isClassDeclaration(node), + ); + + for (const classDecl of classDecls) { + for (const member of classDecl.members) { + if (!ts.isPropertyDeclaration(member)) continue; + if (!hasDecorator(member, "Input")) continue; + if (!member.name || !ts.isIdentifier(member.name)) continue; + + const rawComment = findImmediateJsDocBefore(content, member.getStart(sourceFile)); + const propName = member.name.text; + const inputDecorator = getDecoratorCall(member, "Input"); + const rawDefault = member.initializer?.getText(sourceFile)?.trim(); + const rawType = cleanType(member.type?.getText(sourceFile)?.trim() || inferTypeFromDefault(rawDefault)); + const fullDescription = parseDescriptionFromJSDoc(rawComment); + const { description, defaultValue: descriptionDefault } = extractDefaultFromDescription(fullDescription); + const defaultValue = descriptionDefault ?? parseDefaultValue(rawDefault); + + props.set(propName, { + name: propName, + type: rawType, + values: parseWrapperPropValues(rawType), + required: isAngularInputRequired(inputDecorator), + default: defaultValue, + description, + }); + } + } + + return props; +} + +function findFirstFileByName(root: string, targetName: string): string | null { + if (!fs.existsSync(root)) return null; + const stack = [root]; + + while (stack.length > 0) { + const current = stack.pop(); + if (!current) continue; + const entries = fs.readdirSync(current, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(current, entry.name); + if (entry.isDirectory()) { + stack.push(fullPath); + } else if (entry.isFile() && entry.name === targetName) { + return fullPath; + } + } + } + + return null; +} + +function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +function findFirstFileContaining( + root: string, + extensions: string[], + searchText: string, +): string | null { + if (!fs.existsSync(root)) return null; + const stack = [root]; + const searchPattern = new RegExp( + `(?:<\\s*${escapeRegExp(searchText)}(?=[\\s>/])|["']${escapeRegExp(searchText)}["'])`, + ); + + while (stack.length > 0) { + const current = stack.pop(); + if (!current) continue; + const entries = fs.readdirSync(current, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(current, entry.name); + if (entry.isDirectory()) { + stack.push(fullPath); + } else if ( + entry.isFile() && + extensions.some((ext) => entry.name.endsWith(ext)) && + !entry.name.includes(".spec.") + ) { + const content = fs.readFileSync(fullPath, "utf-8"); + if (searchPattern.test(content)) { + return fullPath; + } + } + } + } + + return null; +} + +function findFirstFileMatchingPattern( + root: string, + extensions: string[], + pattern: RegExp, +): string | null { + if (!fs.existsSync(root)) return null; + const stack = [root]; + + while (stack.length > 0) { + const current = stack.pop(); + if (!current) continue; + const entries = fs.readdirSync(current, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(current, entry.name); + if (entry.isDirectory()) { + stack.push(fullPath); + } else if ( + entry.isFile() && + extensions.some((ext) => entry.name.endsWith(ext)) && + !entry.name.includes(".spec.") + ) { + const content = fs.readFileSync(fullPath, "utf-8"); + if (pattern.test(content)) { + return fullPath; + } + } + } + } + + return null; +} + +function extractReactWrapperApi( + componentName: string, + tagName: string, + slotNames: string[], + wrapperComponentName: string = componentName, +): WrapperExtraction { + const reactRoot = path.join(WORKSPACE_ROOT, "libs/react-components/src/lib"); + const reactFileNameCandidates = [ + `${wrapperComponentName}.tsx`, + `${wrapperComponentName.replace(/-/g, "")}.tsx`, + ]; + const reactTagPattern = new RegExp(`<\\s*${escapeRegExp(tagName)}(?=[\\s>/])`); + + const reactFile = + reactFileNameCandidates.map((name) => findFirstFileByName(reactRoot, name)).find(Boolean) ?? + findFirstFileMatchingPattern(reactRoot, [".tsx"], reactTagPattern) ?? + findFirstFileContaining(reactRoot, [".tsx"], tagName); + + if (!reactFile) return createEmptyWrapperExtraction(); + + const content = fs.readFileSync(reactFile, "utf-8"); + const sourceFile = createTsSourceFile(reactFile, content); + const interfaces = parseReactInterfaces(content, reactFile); + const primaryInterfaceName = resolvePrimaryReactPropsInterface(wrapperComponentName, interfaces); + if (!primaryInterfaceName) return createEmptyWrapperExtraction(true); + + const interfaceMembers = collectReactInterfaceMembers(primaryInterfaceName, interfaces, sourceFile); + const componentParameterType = resolvePrimaryReactComponentParameterType( + wrapperComponentName, + sourceFile, + ); + const componentParameterMembers = collectReactTypeNodeMembers( + componentParameterType, + interfaces, + sourceFile, + new Set([primaryInterfaceName]), + ); + const reactMembers = [...interfaceMembers, ...componentParameterMembers]; + const callbackAliases = extractReactCallbackAliases(sourceFile); + + const props: ExtractedProp[] = []; + const events: ExtractedEvent[] = []; + const slotDescriptions: Record = {}; + const slotNameAliases: Record = {}; + const slotRequired: Record = {}; + + for (const member of reactMembers) { + if (!ts.isPropertySignature(member)) continue; + if (!member.name || !ts.isIdentifier(member.name)) continue; + + const rawComment = findImmediateJsDocBefore(content, member.getStart(sourceFile)); + const propName = member.name.text; + const optional = Boolean(member.questionToken); + const rawType = cleanType(member.type?.getText(sourceFile)?.trim() || "any"); + const { internal, deprecated } = parseJSDocContent(rawComment || ""); + + // Skip @deprecated props and internal-only props — not for public API docs + if (deprecated || (internal && !shouldAllowInternalProp(componentName, propName))) continue; + + const fullDescription = parseDescriptionFromJSDoc(rawComment); + const { description, defaultValue } = extractDefaultFromDescription(fullDescription); + const isReadonly = isReadonlyDescription(description); + const isRequired = !optional && !isReadonly; + + if (shouldSkipInternalProp(componentName, propName)) continue; + + const values = parseWrapperPropValues(rawType); + const slotName = getMatchingSlotName(propName, slotNames); + + if (slotName && isSlotCarrierType(rawType)) { + if (description) { + slotDescriptions[slotName] = description; + } + slotNameAliases[slotName] = propName; + slotRequired[slotName] = Boolean(slotRequired[slotName]) || isRequired; + if (isPureSlotCarrierType(rawType)) { + continue; + } + } + + if ( + propName.startsWith("on") && + (isReactCallbackAliasType(rawType, callbackAliases) || isFunctionType(rawType)) + ) { + events.push({ + name: propName, + type: isReactCallbackAliasType(rawType, callbackAliases) + ? resolveReactCallbackEventType(rawType, callbackAliases) + : rawType, + description, + frameworks: ["react"], + }); + continue; + } + + props.push({ + name: propName, + type: rawType, + values, + required: isRequired, + default: defaultValue, + description, + }); + } + + // Inject inherited margin props when the interface extends Margins + if (hasReactMarginsInHierarchy(primaryInterfaceName, interfaces)) { + const existingNames = new Set(props.map((p) => p.name)); + const marginProps: ExtractedProp[] = ["mt", "mr", "mb", "ml"] + .filter((name) => !existingNames.has(name)) + .map((name) => ({ + name, + type: "Spacing", + required: false, + default: null, + description: "", + })); + props.push(...marginProps); + } + + const dedupedProps = dedupeByName(props).sort((a, b) => a.name.localeCompare(b.name)); + const dedupedEvents = dedupeByName(events).sort((a, b) => a.name.localeCompare(b.name)); + + return { + found: true, + props: dedupedProps, + events: dedupedEvents, + slotDescriptions, + slotNameAliases, + slotRequired, + }; +} + +function extractAngularWrapperApi( + componentName: string, + tagName: string, + slotNames: string[], + wrapperComponentName: string = componentName, +): WrapperExtraction { + const angularRoot = path.join(WORKSPACE_ROOT, "libs/angular-components/src/lib/components"); + const angularSelector = tagName.replace(/^goa-/, "goab-"); + const angularFileNameCandidates = [ + `${wrapperComponentName}.ts`, + `${wrapperComponentName.replace(/-/g, "")}.ts`, + ]; + const angularSelectorPattern = new RegExp(`selector\\s*:\\s*["']${escapeRegExp(angularSelector)}["']`); + const angularTagPattern = new RegExp(`<\\s*${escapeRegExp(tagName)}(?=[\\s>/])`); + + const angularFile = + angularFileNameCandidates + .map((name) => findFirstFileByName(angularRoot, name)) + .find(Boolean) ?? + findFirstFileMatchingPattern(angularRoot, [".ts"], angularSelectorPattern) ?? + findFirstFileMatchingPattern(angularRoot, [".ts"], angularTagPattern) ?? + findFirstFileContaining(angularRoot, [".ts"], tagName); + + if (!angularFile) return createEmptyWrapperExtraction(); + + const content = fs.readFileSync(angularFile, "utf-8"); + const sourceFile = createTsSourceFile(angularFile, content); + + const props: ExtractedProp[] = []; + const events: ExtractedEvent[] = []; + const slotDescriptions: Record = {}; + const slotNameAliases: Record = {}; + const slotRequired: Record = {}; + + const classDecl = sourceFile.statements.find( + (node): node is ts.ClassDeclaration => ts.isClassDeclaration(node) && hasDecorator(node, "Component"), + ); + + if (!classDecl) return createEmptyWrapperExtraction(true); + + for (const member of classDecl.members) { + if (!ts.isPropertyDeclaration(member)) continue; + if (!member.name || !ts.isIdentifier(member.name)) continue; + + const inputDecorator = getDecoratorCall(member, "Input"); + if (!inputDecorator && !hasDecorator(member, "Input")) continue; + + const rawComment = findImmediateJsDocBefore(content, member.getStart(sourceFile)); + const { internal, deprecated } = parseJSDocContent(rawComment || ""); + const propName = member.name.text; + const rawDefault = member.initializer?.getText(sourceFile)?.trim(); + const rawType = cleanType(member.type?.getText(sourceFile)?.trim() || inferTypeFromDefault(rawDefault)); + + const fullDescription = parseDescriptionFromJSDoc(rawComment); + const { description, defaultValue: descriptionDefault } = extractDefaultFromDescription(fullDescription); + const isReadonly = isReadonlyDescription(description); + const required = !isReadonly && isAngularInputRequired(inputDecorator); + + // Skip @deprecated props and internal-only props — not for public API docs + if (deprecated || (internal && !shouldAllowInternalProp(componentName, propName))) continue; + + if (shouldSkipInternalProp(componentName, propName)) continue; + + const values = parseWrapperPropValues(rawType); + const slotName = getMatchingSlotName(propName, slotNames); + + if (slotName && isSlotCarrierType(rawType)) { + if (description) { + slotDescriptions[slotName] = description; + } + slotNameAliases[slotName] = propName; + slotRequired[slotName] = Boolean(slotRequired[slotName]) || required; + if (isPureSlotCarrierType(rawType)) { + continue; + } + } + + const defaultValue = descriptionDefault ?? parseDefaultValue(rawDefault); + + props.push({ + name: propName, + type: rawType, + values, + required, + default: defaultValue, + description, + }); + } + + for (const member of classDecl.members) { + if (!ts.isPropertyDeclaration(member)) continue; + if (!member.name || !ts.isIdentifier(member.name)) continue; + const outputDecorator = getDecoratorCall(member, "Output"); + if (!outputDecorator && !hasDecorator(member, "Output")) continue; + + const rawComment = findImmediateJsDocBefore(content, member.getStart(sourceFile)); + const { deprecated: eventDeprecated } = parseJSDocContent(rawComment || ""); + if (eventDeprecated) continue; + + const eventName = member.name.text; + let eventType = "void"; + + if (member.type && ts.isTypeReferenceNode(member.type)) { + const typeName = member.type.typeName.getText(sourceFile); + if (typeName.endsWith("EventEmitter")) { + eventType = member.type.typeArguments?.[0]?.getText(sourceFile)?.trim() || "void"; + } + } + + if ( + (eventType === "void" || eventType === "CustomEvent") && + member.initializer && + ts.isNewExpression(member.initializer) + ) { + const expr = member.initializer; + const ctorName = expr.expression.getText(sourceFile); + if (ctorName.endsWith("EventEmitter")) { + eventType = expr.typeArguments?.[0]?.getText(sourceFile)?.trim() || "void"; + } + } + + const description = parseDescriptionFromJSDoc(rawComment); + + events.push({ + name: eventName, + type: toEventCallbackType(eventType), + description, + frameworks: ["angular"], + }); + } + + // Inject inherited props when the class extends common Angular base wrappers. + const extendsName = classDecl.heritageClauses + ?.find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword) + ?.types?.[0] + ?.expression + ?.getText(sourceFile); + + if (extendsName && (extendsName === "GoabBaseComponent" || extendsName === "GoabControlValueAccessor")) { + const existingNames = new Set(props.map((p) => p.name)); + const baseComponentProps = extractAngularBaseComponentProps(); + const inheritedPropNames = + extendsName === "GoabControlValueAccessor" + ? ["id", "disabled", "error", "value", "mt", "mr", "mb", "ml", "testId"] + : ["mt", "mr", "mb", "ml", "testId"]; + + const baseProps = inheritedPropNames + .map((name) => baseComponentProps.get(name)) + .filter((prop): prop is ExtractedProp => Boolean(prop)) + .filter((prop) => !existingNames.has(prop.name)); + + props.push(...baseProps); + } + + const dedupedProps = dedupeByName(props).sort((a, b) => a.name.localeCompare(b.name)); + const dedupedEvents = dedupeByName(events).sort((a, b) => a.name.localeCompare(b.name)); + + return { + found: true, + props: dedupedProps, + events: dedupedEvents, + slotDescriptions, + slotNameAliases, + slotRequired, + }; } // ============================================================================= @@ -502,37 +1551,284 @@ function generateTypeLabel( // Event Transformation // ============================================================================= -function transformEvents(rawEventNames: string[]): ExtractedEvent[] { - const events: ExtractedEvent[] = []; +function inferDetailPropertyType(key: string, expression: string): string { + const expr = expression.trim(); + const lowerKey = key.toLowerCase(); + + if (lowerKey === "name") return "string"; + if (lowerKey === "label") return "string"; + if (lowerKey === "labels") return "string[]"; + if (lowerKey === "sortby") return "string"; + if (lowerKey === "sortdir") return "number"; + if (lowerKey === "sorts") return '{ column: string; direction: "asc" | "desc" }[]'; + if (lowerKey === "tab") return "number"; + if (lowerKey === "page") return "number"; + if (lowerKey === "url") return "string"; + if (lowerKey === "values") return "string[]"; + + if (lowerKey === "value") { + if (/newselectedvalues|array\.from\s*\(/i.test(expr)) return "string[]"; + if (/_date\.date/.test(expr)) return "Date | string | null"; + if (/\binput\.value\b/.test(expr)) return "string"; + if (/\.value\b/.test(expr) && !/\bdetail\.value\b/.test(expr)) return "string"; + if (/\boutput\b/.test(expr)) return "string"; + if (/^newvalue$/i.test(expr)) return "string"; + if (/^_?value$/.test(expr)) return "string"; + if (/detail\.value/.test(expr)) return "string | unknown[]"; + } - for (const rawName of rawEventNames) { - // Skip internal events - if (rawName.includes("::") || rawName.includes(":")) continue; + if (lowerKey === "valuestr") return "string"; + if (lowerKey === "key") { + if (/\.key\b/.test(expr)) return "string"; + } + if (lowerKey === "action") { + if (/\.action\b/.test(expr)) return "string"; + } + if (lowerKey === "size") { + if (/\.size\b/.test(expr)) return '"normal" | "compact"'; + } - // Raw event name (e.g., "_click") -> base name (e.g., "click") - const baseName = rawName.replace(/^_/, ""); + if (expr === "true" || expr === "false") return "boolean"; + if (/^[-+]?\d+(\.\d+)?$/.test(expr)) return "number"; + if (/^["'`].*["'`]$/.test(expr)) return "string"; + if (/^\{[\s\S]*\}$/.test(expr)) return "Record"; + if (/^\[[\s\S]*\]$/.test(expr)) return "unknown[]"; + if (/\b(open|checked|disabled|selected|expanded|collapsed|visible|active)\b/i.test(expr)) { + return "boolean"; + } + if (/(open|checked|disabled|selected|expanded|collapsed|visible|active)/.test(lowerKey)) { + return "boolean"; + } + if (/\b(event|e)\b/.test(expr)) return "Event"; - // React event name: onClick, onChange, etc. - const reactName = `on${capitalize(baseName)}`; + return "unknown"; +} - // Add React event - events.push({ - name: reactName, - type: "(event: Event) => void", - description: "", - frameworks: ["react"], - }); +function inferDetailPropertyOptional(key: string, expression: string): boolean { + const expr = expression.trim(); + const lowerKey = key.toLowerCase(); - // Add Angular event (uses the raw name with underscore) - events.push({ - name: rawName, - type: "CustomEvent", - description: "", - frameworks: ["angular"], - }); + if ( + (lowerKey === "action" || lowerKey === "size") && + /\baction\.(action|size)\b/.test(expr) + ) { + return true; } - return events; + return false; +} + +function buildCustomEventTypeFromDetail(detailObjectLiteral: string): string { + const objectBody = detailObjectLiteral.replace(/^\{\s*|\s*\}$/g, ""); + if (!objectBody) return "CustomEvent"; + + const parsedMembers = objectBody + .split(",") + .map((part) => part.trim()) + .filter(Boolean) + .map((part) => { + const keyValueMatch = part.match(/^([A-Za-z_$][\w$]*)\s*:\s*([\s\S]+)$/); + if (keyValueMatch) { + const key = keyValueMatch[1]; + const value = keyValueMatch[2].trim(); + return { + key, + type: inferDetailPropertyType(key, value), + optional: inferDetailPropertyOptional(key, value), + }; + } + + const shorthandMatch = part.match(/^([A-Za-z_$][\w$]*)$/); + if (shorthandMatch) { + const key = shorthandMatch[1]; + return { key, type: inferDetailPropertyType(key, key), optional: false }; + } + + return null; + }) + .filter((member): member is { key: string; type: string; optional: boolean } => + Boolean(member), + ); + + if (!parsedMembers.length) return "CustomEvent>"; + + // Cross-field heuristics for common patterns in component events. + const hasLabels = parsedMembers.some((m) => m.key.toLowerCase() === "labels"); + const hasValueStr = parsedMembers.some((m) => m.key.toLowerCase() === "valuestr"); + + const members = parsedMembers.map((member) => { + if (member.key.toLowerCase() === "value") { + if (hasLabels) { + return `${member.key}${member.optional ? "?" : ""}: string[]`; + } + if (hasValueStr) { + return `${member.key}${member.optional ? "?" : ""}: Date | string | null`; + } + } + return `${member.key}${member.optional ? "?" : ""}: ${member.type}`; + }); + + return `CustomEvent<{ ${members.join("; ")} }>`; +} + +function scoreCustomEventType(eventType: string): number { + if (eventType === "CustomEvent" || eventType === "CustomEvent>" || eventType === "CustomEvent") { + return 0; + } + + const detailMatch = eventType.match(/CustomEvent<\{([\s\S]*)\}>/); + if (!detailMatch?.[1]) return 0; + + const body = detailMatch[1]; + const keyCount = body.split(";").filter((part) => part.trim().length > 0).length; + const unknownCount = (body.match(/\bunknown\b/g) || []).length; + + return keyCount * 10 - unknownCount * 6; +} + +function splitTopLevelArgs(argsSource: string): string[] { + const parts: string[] = []; + let current = ""; + let parenDepth = 0; + let braceDepth = 0; + let bracketDepth = 0; + let inString = false; + let stringQuote = ""; + + for (let i = 0; i < argsSource.length; i++) { + const ch = argsSource[i]; + const prev = i > 0 ? argsSource[i - 1] : ""; + + if (inString) { + current += ch; + if (ch === stringQuote && prev !== "\\") { + inString = false; + stringQuote = ""; + } + continue; + } + + if (ch === '"' || ch === "'" || ch === "`") { + inString = true; + stringQuote = ch; + current += ch; + continue; + } + + if (ch === "(") parenDepth++; + else if (ch === ")") parenDepth--; + else if (ch === "{") braceDepth++; + else if (ch === "}") braceDepth--; + else if (ch === "[") bracketDepth++; + else if (ch === "]") bracketDepth--; + + if (ch === "," && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) { + parts.push(current.trim()); + current = ""; + continue; + } + + current += ch; + } + + if (current.trim().length > 0) { + parts.push(current.trim()); + } + + return parts; +} + +function getCustomEventType(eventName: string, content: string): string { + const escapedName = escapeRegExp(eventName); + const eventPattern = new RegExp( + `new\\s+CustomEvent\\s*\\(\\s*["']${escapedName}["']\\s*,\\s*\\{([\\s\\S]*?)\\}\\s*\\)`, + "g", + ); + + const dispatchCallStartPattern = /dispatch(?:<[^>]+>)?\s*\(/g; + + const detailLiterals: string[] = []; + + for (const match of content.matchAll(eventPattern)) { + const eventOptions = match[1]; + const detailMatch = eventOptions.match(/detail\s*:\s*(\{[\s\S]*?\})/); + if (detailMatch?.[1]) { + detailLiterals.push(detailMatch[1]); + } + } + + for (const match of content.matchAll(dispatchCallStartPattern)) { + const startIndex = match.index ?? -1; + if (startIndex < 0) continue; + + const openParenIndex = startIndex + match[0].length - 1; + let depth = 0; + let endIndex = -1; + + for (let i = openParenIndex; i < content.length; i++) { + const ch = content[i]; + if (ch === "(") depth++; + if (ch === ")") { + depth--; + if (depth === 0) { + endIndex = i; + break; + } + } + } + + if (endIndex === -1) continue; + + const callArgsSource = content.slice(openParenIndex + 1, endIndex); + const args = splitTopLevelArgs(callArgsSource); + if (args.length < 3) continue; + + const eventArg = args[1].trim(); + const eventMatch = eventArg.match(/^["']([^"']+)["']$/); + if (!eventMatch || eventMatch[1] !== eventName) continue; + + const detailLiteral = args[2].trim(); + if (detailLiteral.startsWith("{") && detailLiteral.endsWith("}")) { + detailLiterals.push(detailLiteral); + } + } + + let bestEventType = "CustomEvent>"; + let bestScore = -1; + + for (const literal of detailLiterals) { + const typed = buildCustomEventTypeFromDetail(literal); + const score = scoreCustomEventType(typed); + if (score > bestScore) { + bestScore = score; + bestEventType = typed; + } + } + + if (detailLiterals.length > 0) { + return bestEventType; + } + + return "CustomEvent"; +} + +function transformWebComponentEvents( + componentName: string, + rawEventNames: string[], + content: string, +): ExtractedEvent[] { + const internalOverrides = WEB_COMPONENT_INTERNAL_EVENT_OVERRIDES[componentName] || new Set(); + const typeOverrides = WEB_COMPONENT_EVENT_TYPE_OVERRIDES[componentName] || {}; + + return rawEventNames + .filter((rawName) => !INTERNAL_EVENT_NAMES.has(rawName) && !internalOverrides.has(rawName)) + .filter((rawName) => !rawName.includes("::") && !rawName.includes(":")) + .map((rawName) => ({ + name: rawName, + type: typeOverrides[rawName] || getCustomEventType(rawName, content), + description: "", + frameworks: ["webComponents"], + })); } // ============================================================================= @@ -611,30 +1907,88 @@ function parseDefaultValue(str: string | undefined): string | null { return str; } +function getAllComponentNames(): string[] { + const componentNames = new Set(); + const documentedComponentSlugs = new Set( + fs + .readdirSync(DOCS_COMPONENT_CONTENT_PATH, { withFileTypes: true }) + .filter((entry) => entry.isFile() && entry.name.endsWith(".mdx")) + .map((entry) => entry.name.replace(/\.mdx$/, "")), + ); + const stack = [UI_COMPONENTS_PATH]; + + while (stack.length > 0) { + const current = stack.pop(); + if (!current) continue; + + const entries = fs.readdirSync(current, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(current, entry.name); + + if (entry.isDirectory()) { + stack.push(fullPath); + } else if ( + entry.isFile() && + entry.name.endsWith(".svelte") && + !entry.name.includes(".test.") + ) { + const content = fs.readFileSync(fullPath, "utf-8"); + const slug = toKebabCase(path.basename(entry.name, ".svelte")); + if ( + extractTagName(content) && + documentedComponentSlugs.has(slug) && + !DOCS_EXCLUDED_COMPONENTS.has(slug) + ) { + componentNames.add(slug); + } + } + } + } + + for (const forcedComponent of DOCS_FORCED_COMPONENTS) { + componentNames.add(forcedComponent); + } + + return Array.from(componentNames).sort((a, b) => a.localeCompare(b)); +} + +function removeStaleApiFiles(validComponentNames: string[]): void { + if (!fs.existsSync(OUTPUT_PATH)) return; + + const validFiles = new Set(validComponentNames.map((name) => `${name}.json`)); + const entries = fs.readdirSync(OUTPUT_PATH, { withFileTypes: true }); + + for (const entry of entries) { + if (entry.isFile() && entry.name.endsWith(".json") && !validFiles.has(entry.name)) { + fs.unlinkSync(path.join(OUTPUT_PATH, entry.name)); + console.log(` Removed stale file: ${entry.name}`); + } + } +} + // ============================================================================= // Main Extraction // ============================================================================= function extractComponentAPI(componentName: string): ExtractedComponentAPI | null { const componentPath = path.join(UI_COMPONENTS_PATH, componentName); - if (!fs.existsSync(componentPath) || !fs.statSync(componentPath).isDirectory()) { - console.error(`Component directory not found: ${componentName}`); - return null; - } - // Find the main Svelte file + // Find the Svelte file by the component's public name first, then fall back + // to any .svelte file inside a matching directory. const svelteFileName = `${capitalize(toCamelCase(componentName))}.svelte`; - let svelteFilePath = path.join(componentPath, svelteFileName); + let svelteFilePath = findFirstFileByName(UI_COMPONENTS_PATH, svelteFileName); - if (!fs.existsSync(svelteFilePath)) { - // Try to find any .svelte file + if (!svelteFilePath && fs.existsSync(componentPath) && fs.statSync(componentPath).isDirectory()) { const files = fs.readdirSync(componentPath); const svelteFile = files.find((f) => f.endsWith(".svelte")); - if (!svelteFile) { - console.error(`No Svelte file found in: ${componentName}`); - return null; + if (svelteFile) { + svelteFilePath = path.join(componentPath, svelteFile); } - svelteFilePath = path.join(componentPath, svelteFile); + } + + if (!svelteFilePath) { + console.error(`No Svelte file found for: ${componentName}`); + return null; } const content = fs.readFileSync(svelteFilePath, "utf-8"); @@ -650,11 +2004,49 @@ function extractComponentAPI(componentName: string): ExtractedComponentAPI | nul const typeAliases = extractTypeAliases(content); const validators = extractValidators(content); const rawProps = extractProps(content, validators, componentName, typeAliases); - const rawEventNames = extractEvents(content); + let eventContent = content; + let rawEventNames = extractEvents(content); + const explicitEventsByComponent: Record> = { + "file-upload-card": new Set(["_cancel", "_delete"]), + }; + const explicitEvents = explicitEventsByComponent[componentName]; + if (explicitEvents) { + rawEventNames = Array.from(new Set([...rawEventNames, ...explicitEvents])); + } + const companionEventsByComponent: Record> = { + "work-side-menu": new Set(["_navigate"]), + "push-drawer": new Set(["_close"]), + }; + const companionEvents = companionEventsByComponent[componentName]; + + if (companionEvents) { + const componentDir = path.dirname(svelteFilePath); + const siblingFiles = fs + .readdirSync(componentDir) + .filter((name) => name.endsWith(".svelte") && path.join(componentDir, name) !== svelteFilePath); + + for (const siblingFile of siblingFiles) { + const siblingPath = path.join(componentDir, siblingFile); + const siblingContent = fs.readFileSync(siblingPath, "utf-8"); + const siblingEventNames = extractEvents(siblingContent).filter((eventName) => companionEvents.has(eventName)); + if (siblingEventNames.length > 0) { + rawEventNames = [...rawEventNames, ...siblingEventNames]; + eventContent += `\n${siblingContent}`; + } + } + + rawEventNames = Array.from(new Set(rawEventNames)); + } const slotNames = extractSlots(content); + const wrapperComponentName = WRAPPER_COMPONENT_ALIASES[componentName] ?? componentName; + const reactWrapper = extractReactWrapperApi(componentName, tagName, slotNames, wrapperComponentName); + const angularWrapper = extractAngularWrapperApi(componentName, tagName, slotNames, wrapperComponentName); + + // Default slot content is implied by usage examples and is intentionally omitted + // from the API docs to reduce noise. // Transform to output format - const props: ExtractedProp[] = rawProps.map((p) => ({ + let webComponentProps: ExtractedProp[] = rawProps.map((p) => ({ name: p.name, type: p.type, typeLabel: p.typeLabel, @@ -665,12 +2057,90 @@ function extractComponentAPI(componentName: string): ExtractedComponentAPI | nul ...(p.deprecated && { deprecated: true }), })); - const events = transformEvents(rawEventNames); + let webComponentEvents = transformWebComponentEvents(componentName, rawEventNames, eventContent); + if (componentName === "side-menu-group") { + webComponentEvents = webComponentEvents.filter((event) => event.name !== "_open"); + } + const slotDescriptions = { + ...angularWrapper.slotDescriptions, + ...reactWrapper.slotDescriptions, + }; + const slotNameAliases = { + ...angularWrapper.slotNameAliases, + ...reactWrapper.slotNameAliases, + }; + const slotRequired = { + ...angularWrapper.slotRequired, + ...reactWrapper.slotRequired, + }; - const slots: ExtractedSlot[] = slotNames.map((name) => ({ - name, - description: "", // Filled by human content - })); + const hasWrapperSlotEvidence = (name: string): boolean => + Boolean(slotNameAliases[name] || slotDescriptions[name]) || + Object.prototype.hasOwnProperty.call(slotRequired, name); + + const createSlots = ( + framework: "react" | "angular" | "webComponents", + type?: string, + useAliasNames: boolean = true, + ): ExtractedSlot[] => + slotNames + .filter( + (name) => + !INTERNAL_SLOT_NAMES.has(name.toLowerCase()) && + !(name === "content" && !slotNameAliases[name] && !slotDescriptions[name]), + ) + .map((name) => { + const rawDescription = slotDescriptions[name] || ""; + const description = + framework === "angular" + ? rawDescription.replace(/ReactNode/g, "ngTemplate") + : rawDescription; + return { + name: useAliasNames ? slotNameAliases[name] || name : name, + type: + SLOT_TYPE_OVERRIDES[componentName]?.[framework]?.[name] || + (type && hasWrapperSlotEvidence(name) ? type : undefined), + description, + required: slotRequired[name] || false, + }; + }); + + const reactSlots = createSlots("react", "ReactNode", true); + const angularSlots = createSlots("angular", "TemplateRef", true); + const webComponentSlots = createSlots("webComponents", undefined, false); + + let reactProps: ExtractedProp[] = reactWrapper.found ? [...reactWrapper.props] : []; + let angularProps: ExtractedProp[] = angularWrapper.found ? [...angularWrapper.props] : []; + + specializeAngularValuePropFromReact(angularProps, reactProps); + + const webComponentVersionProp = webComponentProps.find( + (prop) => prop.name.toLowerCase() === "version", + ); + const hideVersionOutsideWeb = isStandardV1V2VersionProp(webComponentVersionProp); + + reactProps = reactProps.filter( + (prop) => + !shouldSkipInternalProp(componentName, prop.name) && + !(hideVersionOutsideWeb && prop.name.toLowerCase() === "version"), + ); + angularProps = angularProps.filter( + (prop) => + !shouldSkipInternalProp(componentName, prop.name) && + !(hideVersionOutsideWeb && prop.name.toLowerCase() === "version"), + ); + webComponentProps = webComponentProps.filter( + (prop) => prop.name.toLowerCase() === "version" || !shouldSkipInternalProp(componentName, prop.name), + ); + + reactProps = dedupeByName(reactProps).sort((a, b) => a.name.localeCompare(b.name)); + angularProps = dedupeByName(angularProps).sort((a, b) => a.name.localeCompare(b.name)); + + webComponentProps.sort((a, b) => a.name.localeCompare(b.name)); + webComponentEvents.sort((a, b) => a.name.localeCompare(b.name)); + reactSlots.sort((a, b) => a.name.localeCompare(b.name)); + angularSlots.sort((a, b) => a.name.localeCompare(b.name)); + webComponentSlots.sort((a, b) => a.name.localeCompare(b.name)); // Relative path from workspace root const relativePath = path.relative(WORKSPACE_ROOT, svelteFilePath); @@ -678,9 +2148,83 @@ function extractComponentAPI(componentName: string): ExtractedComponentAPI | nul return { componentSlug: toKebabCase(componentName), extractedFrom: relativePath, - props, - events, - slots, + frameworks: { + react: { + props: reactWrapper.found ? reactProps : [], + events: reactWrapper.found ? reactWrapper.events : [], + slots: reactWrapper.found ? reactSlots : [], + }, + angular: { + props: angularWrapper.found ? angularProps : [], + events: angularWrapper.found ? angularWrapper.events : [], + slots: angularWrapper.found ? angularSlots : [], + }, + webComponents: { + props: webComponentProps, + events: webComponentEvents, + slots: webComponentSlots, + }, + }, + }; +} + +function mergeItemArray( + next: T[], + existing: T[], + context: string, +): T[] { + const existingByName = new Map(existing.map((item) => [item.name, item])); + const nextNames = new Set(next.map((item) => item.name)); + + // Backfill non-empty descriptions from existing into new items that have empty ones + const merged: T[] = next.map((item) => { + const existingItem = existingByName.get(item.name); + if (existingItem && !item.description && existingItem.description) { + return { ...item, description: existingItem.description }; + } + return item; + }); + + // Preserve items from existing that are absent in the new extraction + // (but skip deprecated entries — they are intentionally excluded) + for (const existingItem of existing) { + if (!nextNames.has(existingItem.name)) { + if ((existingItem as Record).deprecated) continue; + console.warn( + ` Preserved manually-added entry "${existingItem.name}" in ${context} (not found in extraction — check source)`, + ); + merged.push(existingItem); + } + } + + return merged.sort((a, b) => a.name.localeCompare(b.name)); +} + +function mergeWithExisting( + next: ExtractedComponentAPI, + existing: ExtractedComponentAPI, +): ExtractedComponentAPI { + const fw = next.frameworks; + const ex = existing.frameworks; + return { + ...next, + frameworks: { + react: { + props: mergeItemArray(fw.react.props, ex.react.props, `${next.componentSlug}.json [react props]`), + events: mergeItemArray(fw.react.events, ex.react.events, `${next.componentSlug}.json [react events]`), + slots: mergeItemArray(fw.react.slots, ex.react.slots, `${next.componentSlug}.json [react slots]`), + }, + angular: { + props: mergeItemArray(fw.angular.props, ex.angular.props, `${next.componentSlug}.json [angular props]`), + events: mergeItemArray(fw.angular.events, ex.angular.events, `${next.componentSlug}.json [angular events]`), + slots: mergeItemArray(fw.angular.slots, ex.angular.slots, `${next.componentSlug}.json [angular slots]`), + }, + webComponents: { + props: mergeItemArray(fw.webComponents.props, ex.webComponents.props, `${next.componentSlug}.json [webComponents props]`), + events: mergeItemArray(fw.webComponents.events, ex.webComponents.events, `${next.componentSlug}.json [webComponents events]`), + slots: mergeItemArray(fw.webComponents.slots, ex.webComponents.slots, `${next.componentSlug}.json [webComponents slots]`), + }, + }, }; } @@ -691,7 +2235,20 @@ function saveComponentAPI(api: ExtractedComponentAPI): void { } const filePath = path.join(OUTPUT_PATH, `${api.componentSlug}.json`); - fs.writeFileSync(filePath, JSON.stringify(api, null, 2)); + + // Merge with existing file to preserve manually-added entries that the extractor + // cannot see (e.g. props defined in function-level intersections, or wrapper gaps). + let merged = api; + if (fs.existsSync(filePath)) { + try { + const existing = JSON.parse(fs.readFileSync(filePath, "utf-8")) as ExtractedComponentAPI; + merged = mergeWithExisting(api, existing); + } catch { + // Malformed existing file — overwrite with fresh extraction + } + } + + fs.writeFileSync(filePath, JSON.stringify(merged, null, 2)); console.log(` Created: ${filePath}`); } @@ -715,11 +2272,8 @@ function main() { let componentNames: string[]; if (args.includes("--all")) { - // Get all component directories - componentNames = fs.readdirSync(UI_COMPONENTS_PATH).filter((name) => { - const componentPath = path.join(UI_COMPONENTS_PATH, name); - return fs.statSync(componentPath).isDirectory(); - }); + componentNames = getAllComponentNames(); + removeStaleApiFiles(componentNames); } else { componentNames = args; } diff --git a/libs/angular-components/src/index.ts b/libs/angular-components/src/index.ts index 55aebfe4b6..10e50c69ad 100644 --- a/libs/angular-components/src/index.ts +++ b/libs/angular-components/src/index.ts @@ -1,3 +1,4 @@ export * from "./lib/angular-components.module"; export * from "./lib/components"; +export * from "./lib/theme/theme.service"; export * from "@abgov/ui-components-common"; diff --git a/libs/angular-components/src/lib/components/accordion/accordion.spec.ts b/libs/angular-components/src/lib/components/accordion/accordion.spec.ts index d91a1205e1..0425266ea4 100644 --- a/libs/angular-components/src/lib/components/accordion/accordion.spec.ts +++ b/libs/angular-components/src/lib/components/accordion/accordion.spec.ts @@ -5,6 +5,7 @@ import { By } from "@angular/platform-browser"; import { GoabAccordionHeadingSize, GoabAccordionIconPosition, + GoabAccordionHeadingType, } from "@abgov/ui-components-common"; @Component({ @@ -17,6 +18,7 @@ import { [headingSize]="headingSize" [headingContent]="headingContent" [iconPosition]="iconPosition" + [headingType]="headingType" maxWidth="480px" > test content @@ -29,8 +31,21 @@ class TestAccordionComponent { open?: boolean; headingSize?: GoabAccordionHeadingSize; iconPosition?: GoabAccordionIconPosition; + headingType?: GoabAccordionHeadingType; } +@Component({ + standalone: true, + imports: [GoabAccordion], + template: ` + + test content + This is the actions content + + `, +}) +class TestAccordionWithActionsComponent {} + describe("GoabAccordion", () => { let fixture: ComponentFixture; let component: TestAccordionComponent; @@ -48,6 +63,7 @@ describe("GoabAccordion", () => { component.open = true; component.headingSize = "large" as GoabAccordionHeadingSize; component.iconPosition = "right" as GoabAccordionIconPosition; + component.headingType = "filled" as GoabAccordionHeadingType; fixture.detectChanges(); tick(); @@ -64,7 +80,33 @@ describe("GoabAccordion", () => { expect(accordionElement.getAttribute("headingsize")).toBe("large"); expect(accordionElement.getAttribute("maxwidth")).toBe("480px"); expect(accordionElement.getAttribute("iconposition")).toBe("right"); + expect(accordionElement.getAttribute("heading-type")).toBe("filled"); const headingContent = accordionElement.querySelector("[slot='headingcontent']"); expect(headingContent.textContent).toContain("This is the headingcontent"); }); }); + +describe("GoabAccordion actions slot", () => { + let fixture: ComponentFixture; + + beforeEach(fakeAsync(() => { + TestBed.configureTestingModule({ + imports: [GoabAccordion, TestAccordionWithActionsComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }).compileComponents(); + + fixture = TestBed.createComponent(TestAccordionWithActionsComponent); + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + })); + + it("should render the actions slot content", () => { + const accordionElement = fixture.debugElement.query( + By.css("goa-accordion"), + ).nativeElement; + const actionsSlot = accordionElement.querySelector("[slot='actions']"); + expect(actionsSlot).toBeTruthy(); + expect(actionsSlot.textContent).toContain("This is the actions content"); + }); +}); diff --git a/libs/angular-components/src/lib/components/accordion/accordion.ts b/libs/angular-components/src/lib/components/accordion/accordion.ts index d8d80f3202..1d93b78da5 100644 --- a/libs/angular-components/src/lib/components/accordion/accordion.ts +++ b/libs/angular-components/src/lib/components/accordion/accordion.ts @@ -1,6 +1,7 @@ import { GoabAccordionHeadingSize, GoabAccordionIconPosition, + GoabAccordionHeadingType, } from "@abgov/ui-components-common"; import { CUSTOM_ELEMENTS_SCHEMA, @@ -28,9 +29,11 @@ import { GoabBaseComponent } from "../base.component"; [attr.secondarytext]="secondaryText" [attr.open]="open" [attr.headingsize]="headingSize" + [attr.heading-type]="headingType" [attr.maxwidth]="maxWidth" [attr.testid]="testId" [attr.iconposition]="iconPosition" + [attr.heading-type]="headingType" [attr.mt]="mt" [attr.mb]="mb" [attr.ml]="ml" @@ -40,6 +43,11 @@ import { GoabBaseComponent } from "../base.component";
+ @if (actions) { +
+ +
+ } } @@ -60,10 +68,14 @@ export class GoabAccordion extends GoabBaseComponent implements OnInit { @Input() headingSize?: GoabAccordionHeadingSize; /** Sets the heading content template reference. */ @Input() headingContent!: TemplateRef; + /** Sets the actions content template reference, rendered right-aligned in the heading before the expand/collapse icon. */ + @Input() actions?: TemplateRef; /** Sets the maximum width of the accordion. */ @Input() maxWidth?: string; /** Sets the position of the expand/collapse icon. */ @Input() iconPosition?: GoabAccordionIconPosition; + /** Sets the accordion style variant. */ + @Input() headingType?: GoabAccordionHeadingType; /** Emits when the accordion opens or closes. Emits the new open state as a boolean. */ @Output() onChange = new EventEmitter(); diff --git a/libs/angular-components/src/lib/components/chip/chip.ts b/libs/angular-components/src/lib/components/chip/chip.ts index 615c0411a8..99f4d97070 100644 --- a/libs/angular-components/src/lib/components/chip/chip.ts +++ b/libs/angular-components/src/lib/components/chip/chip.ts @@ -56,17 +56,17 @@ export class GoabChip extends GoabBaseComponent implements OnInit { }, 0); } - /** @deprecated Use GoAFilterChip instead. Icon displayed at the start of the chip. */ + /** @deprecated Use GoabFilterChip (goab-filter-chip) instead. Icon displayed at the start of the chip. */ @Input() leadingIcon?: GoabIconType | null; - /** @deprecated Use GoAFilterChip instead. Shows an error state on the chip. */ + /** @deprecated Use GoabFilterChip (goab-filter-chip) instead. Shows an error state on the chip. */ @Input({ transform: booleanAttribute }) error?: boolean; - /** @deprecated Use GoAFilterChip instead. When true, shows a delete icon and makes chip clickable. */ + /** @deprecated Use GoabFilterChip (goab-filter-chip) instead. When true, shows a delete icon and makes chip clickable. */ @Input({ transform: booleanAttribute }) deletable?: boolean; - /** @deprecated Use GoAFilterChip instead. The text content displayed in the chip. */ + /** @deprecated Use GoabFilterChip (goab-filter-chip) instead. The text content displayed in the chip. */ @Input() content?: string = ""; - /** @deprecated Use GoAFilterChip instead. The chip variant style. */ + /** @deprecated Use GoabFilterChip (goab-filter-chip) instead. The chip variant style. */ @Input() variant?: GoabChipVariant; - /** @deprecated Use GoAFilterChip instead. The icon theme - outline or filled. */ + /** @deprecated Use GoabFilterChip (goab-filter-chip) instead. The icon theme - outline or filled. */ @Input() iconTheme?: GoabChipTheme; /** Emits when the chip is clicked. */ diff --git a/libs/angular-components/src/lib/components/drawer/drawer.ts b/libs/angular-components/src/lib/components/drawer/drawer.ts index 29ff92aff0..c6f5ae6541 100644 --- a/libs/angular-components/src/lib/components/drawer/drawer.ts +++ b/libs/angular-components/src/lib/components/drawer/drawer.ts @@ -25,7 +25,7 @@ import { GoabDrawerPosition, GoabDrawerSize } from "@abgov/ui-components-common" [attr.maxsize]="maxSize" [attr.testid]="testId" [attr.version]="version" - (_close)="_onClose()" + (_close)="_onClose($event)" >
@@ -70,7 +70,8 @@ export class GoabDrawer implements OnInit { }, 0); } - _onClose() { + _onClose(event: Event) { + if (event.target !== event.currentTarget) return; this.onClose.emit(); } diff --git a/libs/angular-components/src/lib/components/dropdown/dropdown.ts b/libs/angular-components/src/lib/components/dropdown/dropdown.ts index 92f6a25625..3306dcc334 100644 --- a/libs/angular-components/src/lib/components/dropdown/dropdown.ts +++ b/libs/angular-components/src/lib/components/dropdown/dropdown.ts @@ -83,7 +83,7 @@ export class GoabDropdown extends GoabControlValueAccessor implements OnInit { @Input() leadingIcon?: GoabIconType; /** Maximum height of the dropdown menu. Non-native only. */ @Input() maxHeight?: string; - /** When true, allows multiple items to be selected. Not currently exposed. */ + /** When true, allows multiple items to be selected. @internal */ @Input({ transform: booleanAttribute }) multiselect?: boolean; /** When true will render the native select HTML element. */ @Input({ transform: booleanAttribute }) native?: boolean; diff --git a/libs/angular-components/src/lib/components/header-menu/header-menu.ts b/libs/angular-components/src/lib/components/header-menu/header-menu.ts index a89deb5324..d0e00a86db 100644 --- a/libs/angular-components/src/lib/components/header-menu/header-menu.ts +++ b/libs/angular-components/src/lib/components/header-menu/header-menu.ts @@ -9,8 +9,6 @@ import { inject, } from "@angular/core"; -import { GoabBaseComponent } from "../base.component"; - @Component({ standalone: true, selector: "goab-app-header-menu", @@ -26,13 +24,15 @@ import { GoabBaseComponent } from "../base.component"; schemas: [CUSTOM_ELEMENTS_SCHEMA], }) /** Menu items within the app header. */ -export class GoabAppHeaderMenu extends GoabBaseComponent implements OnInit { +export class GoabAppHeaderMenu implements OnInit { private cdr = inject(ChangeDetectorRef); /** Icon displayed before the heading text. */ @Input() leadingIcon?: GoabIconType; /** The menu heading text displayed as the dropdown trigger. */ @Input() heading?: string; + /** Sets a data-testid attribute for automated testing. */ + @Input() testId?: string; /** Sets the slot name for the component. */ @Input() slotName?: string; diff --git a/libs/angular-components/src/lib/components/header/header.ts b/libs/angular-components/src/lib/components/header/header.ts index a04e04b9d4..94f9bfae93 100644 --- a/libs/angular-components/src/lib/components/header/header.ts +++ b/libs/angular-components/src/lib/components/header/header.ts @@ -10,8 +10,6 @@ import { inject, } from "@angular/core"; -import { GoabBaseComponent } from "../base.component"; - @Component({ standalone: true, selector: "goab-app-header", @@ -33,7 +31,7 @@ import { GoabBaseComponent } from "../base.component"; schemas: [CUSTOM_ELEMENTS_SCHEMA], }) /** Provide structure to help users find their way around the service. */ -export class GoabAppHeader extends GoabBaseComponent implements OnInit { +export class GoabAppHeader implements OnInit { private cdr = inject(ChangeDetectorRef); /** Sets the URL to link from the alberta.ca logo. A full url is required. */ @@ -46,6 +44,8 @@ export class GoabAppHeader extends GoabBaseComponent implements OnInit { @Input() maxContentWidth?: string; /** Sets the breakpoint in px for the full menu to display. */ @Input({ transform: numberAttribute }) fullMenuBreakpoint?: number; + /** Sets a data-testid attribute for automated testing. */ + @Input() testId?: string; isReady = false; version = "2"; diff --git a/libs/angular-components/src/lib/components/hero-banner/hero-banner.ts b/libs/angular-components/src/lib/components/hero-banner/hero-banner.ts index c4d6dcb83f..92ce6d5abc 100644 --- a/libs/angular-components/src/lib/components/hero-banner/hero-banner.ts +++ b/libs/angular-components/src/lib/components/hero-banner/hero-banner.ts @@ -52,8 +52,8 @@ export class GoabHeroBanner implements OnInit { @Input() backgroundColor?: string; /** Text color within the hero banner. */ @Input() textColor?: string; - /** Angular template reference for the actions slot content. */ - @Input() actions!: TemplateRef; + /** Content rendered in the actions slot. */ + @Input() actions?: TemplateRef; ngOnInit(): void { setTimeout(() => { diff --git a/libs/angular-components/src/lib/components/microsite-header/microsite-header.ts b/libs/angular-components/src/lib/components/microsite-header/microsite-header.ts index ce0dbc6f73..5fe6393368 100644 --- a/libs/angular-components/src/lib/components/microsite-header/microsite-header.ts +++ b/libs/angular-components/src/lib/components/microsite-header/microsite-header.ts @@ -65,7 +65,7 @@ export class GoabMicrositeHeader implements OnInit { } /** Emits when the feedback link is clicked. */ - @Output() onFeedbackClick = new EventEmitter(); + @Output() onFeedbackClick = new EventEmitter(); getVersionAsString(): string { return typeof this.version === "string" ? this.version : ""; diff --git a/libs/angular-components/src/lib/components/modal/modal.ts b/libs/angular-components/src/lib/components/modal/modal.ts index 6b5906f782..0562ad7391 100644 --- a/libs/angular-components/src/lib/components/modal/modal.ts +++ b/libs/angular-components/src/lib/components/modal/modal.ts @@ -32,7 +32,7 @@ import { NgTemplateOutlet } from "@angular/common"; [attr.closable]="closable" [attr.transition]="transition" [attr.heading]="getHeadingAsString()" - (_close)="_onClose()" + (_close)="_onClose($event)" >
@if (this.heading !== "" && getHeadingAsTemplate() !== null) { @@ -91,7 +91,7 @@ export class GoabModal implements OnInit { @Input() actions!: TemplateRef; /** Emits when the modal is closed. */ - @Output() onClose = new EventEmitter(); + @Output() onClose = new EventEmitter(); getHeadingAsString(): string { return this.heading instanceof TemplateRef ? "" : this.heading; @@ -102,7 +102,8 @@ export class GoabModal implements OnInit { return this.heading instanceof TemplateRef ? this.heading : null; } - _onClose() { + _onClose(event: Event) { + if (event.target !== event.currentTarget) return; this.onClose.emit(); } } diff --git a/libs/angular-components/src/lib/components/push-drawer/push-drawer.ts b/libs/angular-components/src/lib/components/push-drawer/push-drawer.ts index 1adaeb09cf..db5ab60a4f 100644 --- a/libs/angular-components/src/lib/components/push-drawer/push-drawer.ts +++ b/libs/angular-components/src/lib/components/push-drawer/push-drawer.ts @@ -23,7 +23,7 @@ import { [attr.testid]="testId" [attr.width]="width" [attr.version]="version" - (_close)="_onClose()" + (_close)="_onClose($event)" >
@@ -55,7 +55,7 @@ export class GoabPushDrawer implements OnInit { /** Sets the template reference for the actions slot content. */ @Input() actions!: TemplateRef; /** Emits when the push drawer closes. */ - @Output() onClose = new EventEmitter(); + @Output() onClose = new EventEmitter(); isReady = false; @@ -66,7 +66,8 @@ export class GoabPushDrawer implements OnInit { }, 0); } - _onClose() { + _onClose(event: Event) { + if (event.target !== event.currentTarget) return; this.onClose.emit(); } diff --git a/libs/angular-components/src/lib/components/radio-group/radio-group.ts b/libs/angular-components/src/lib/components/radio-group/radio-group.ts index d22518a691..1d25bf8ab5 100644 --- a/libs/angular-components/src/lib/components/radio-group/radio-group.ts +++ b/libs/angular-components/src/lib/components/radio-group/radio-group.ts @@ -63,6 +63,8 @@ export class GoabRadioGroup extends GoabControlValueAccessor implements OnInit { version = "2"; /** The name for the radio group. Used for accessibility and change events. */ @Input() name?: string; + /** The currently selected value in the radio group. */ + @Input() override value?: string; /** Sets the layout direction. 'vertical' stacks items, 'horizontal' places them in a row. */ @Input() orientation?: GoabRadioGroupOrientation; /** Defines how the radio group will be announced by screen readers. */ diff --git a/libs/angular-components/src/lib/components/radio-item/radio-item.ts b/libs/angular-components/src/lib/components/radio-item/radio-item.ts index 1a88274803..cbccd7c354 100644 --- a/libs/angular-components/src/lib/components/radio-item/radio-item.ts +++ b/libs/angular-components/src/lib/components/radio-item/radio-item.ts @@ -69,7 +69,7 @@ export class GoabRadioItem extends GoabBaseComponent implements OnInit { @Input() revealAriaLabel?: string; /** Disables this radio option. Also disabled if the parent RadioGroup is disabled. */ @Input({ transform: booleanAttribute }) disabled?: boolean; - /** Sets this radio option as checked/selected. */ + /** @internal Sets this radio option as checked/selected. */ @Input({ transform: booleanAttribute }) checked?: boolean; /** Shows an error state on this radio option. */ @Input({ transform: booleanAttribute }) error?: boolean; diff --git a/libs/angular-components/src/lib/components/table-sort-header/table-sort-header.ts b/libs/angular-components/src/lib/components/table-sort-header/table-sort-header.ts index 7ebffb98e5..16e99b20ae 100644 --- a/libs/angular-components/src/lib/components/table-sort-header/table-sort-header.ts +++ b/libs/angular-components/src/lib/components/table-sort-header/table-sort-header.ts @@ -17,6 +17,7 @@ import { [attr.name]="name" [attr.direction]="direction" [attr.sort-order]="sortOrder" + [attr.version]="version" > @@ -30,6 +31,7 @@ export class GoabTableSortHeader implements OnInit { private cdr = inject(ChangeDetectorRef); isReady = false; + version = "2"; /** Column name identifier for sorting. */ @Input() name?: string; /** Sets the sort direction indicator. @default "none" */ diff --git a/libs/angular-components/src/lib/components/work-side-menu-item/work-side-menu-item.spec.ts b/libs/angular-components/src/lib/components/work-side-menu-item/work-side-menu-item.spec.ts index 5fb94132d6..e25a3fdd47 100644 --- a/libs/angular-components/src/lib/components/work-side-menu-item/work-side-menu-item.spec.ts +++ b/libs/angular-components/src/lib/components/work-side-menu-item/work-side-menu-item.spec.ts @@ -51,6 +51,26 @@ class TestWorkSideMenuItemWithPopoverComponent { url = "/popover"; } +@Component({ + standalone: true, + imports: [GoabWorkSideMenuItem], + template: ` + + + +
2
+
+ `, +}) +class TestWorkSideMenuItemWithTrailingContentComponent { + label = "Trailing item"; + url = "/trailing"; +} + describe("GoabWorkSideMenuItem", () => { it("should render and set the props correctly", fakeAsync(() => { TestBed.configureTestingModule({ @@ -96,4 +116,26 @@ describe("GoabWorkSideMenuItem", () => { expect(popoverContent).toBeTruthy(); expect(popoverContent.nativeElement.textContent).toBe("Popover content here"); })); + + it("should render trailing content into the trailingContent slot", fakeAsync(() => { + TestBed.configureTestingModule({ + imports: [TestWorkSideMenuItemWithTrailingContentComponent], + }).compileComponents(); + + const fixture = TestBed.createComponent(TestWorkSideMenuItemWithTrailingContentComponent); + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + + const slotDiv = fixture.debugElement.query( + By.css('[slot="trailingContent"]'), + ); + expect(slotDiv).toBeTruthy(); + + const trailingContent = fixture.debugElement.query( + By.css(".trailing-test-content"), + ); + expect(trailingContent).toBeTruthy(); + expect(trailingContent.nativeElement.textContent).toBe("2"); + })); }); diff --git a/libs/angular-components/src/lib/components/work-side-menu-item/work-side-menu-item.ts b/libs/angular-components/src/lib/components/work-side-menu-item/work-side-menu-item.ts index 527530fe87..493ddcd709 100644 --- a/libs/angular-components/src/lib/components/work-side-menu-item/work-side-menu-item.ts +++ b/libs/angular-components/src/lib/components/work-side-menu-item/work-side-menu-item.ts @@ -31,6 +31,11 @@ import { NgTemplateOutlet } from "@angular/common";
} + @if (trailingContent) { +
+ +
+ } } @@ -45,7 +50,7 @@ export class GoabWorkSideMenuItem implements OnInit { @Input({ required: true }) label!: string; /** The URL the menu item links to. Optional — when absent, renders as a button instead of a link. */ @Input() url?: string; - /** Badge text displayed alongside the menu item (e.g., notification count). */ + /** @deprecated Use trailingContent instead. Badge text displayed alongside the menu item (e.g., notification count). */ @Input() badge?: string; /** When true, indicates this is the currently active menu item. */ @Input() current?: boolean; @@ -55,10 +60,12 @@ export class GoabWorkSideMenuItem implements OnInit { @Input() icon?: string; /** Sets a data-testid attribute for automated testing. */ @Input() testId?: string; - /** Sets the visual style of the badge. Use "emergency" for urgent items, "success" for positive status. @default "normal" */ + /** @deprecated Use trailingContent instead. Sets the visual style of the badge. Use "emergency" for urgent items, "success" for positive status. @default "normal" */ @Input() type?: GoabWorkSideMenuItemType = "normal"; /** Template reference for the popover content slot. */ @Input() popoverContent!: TemplateRef; + /** Template reference for the trailing content slot. */ + @Input() trailingContent!: TemplateRef; isReady = false; diff --git a/libs/angular-components/src/lib/components/work-side-menu/work-side-menu.ts b/libs/angular-components/src/lib/components/work-side-menu/work-side-menu.ts index ac1bce228e..7218e747ea 100644 --- a/libs/angular-components/src/lib/components/work-side-menu/work-side-menu.ts +++ b/libs/angular-components/src/lib/components/work-side-menu/work-side-menu.ts @@ -64,7 +64,7 @@ export class GoabWorkSideMenu implements OnInit { /** Template reference for the account slot content. */ @Input() accountContent!: TemplateRef; /** Emits when the side menu is toggled open or closed. */ - @Output() onToggle = new EventEmitter(); + @Output() onToggle = new EventEmitter(); /** Emits when a navigation link is clicked. Emits the URL as a string. */ @Output() onNavigate = new EventEmitter(); diff --git a/libs/angular-components/src/lib/theme/theme.service.spec.ts b/libs/angular-components/src/lib/theme/theme.service.spec.ts new file mode 100644 index 0000000000..f64c406512 --- /dev/null +++ b/libs/angular-components/src/lib/theme/theme.service.spec.ts @@ -0,0 +1,202 @@ +import { ApplicationRef } from "@angular/core"; +import { TestBed } from "@angular/core/testing"; +import { GoabThemeService } from "./theme.service"; + +const STORAGE_KEY = "goab-theme"; +const ATTRIBUTE = "data-theme"; + +function mockMatchMedia(prefersDark: boolean) { + Object.defineProperty(window, "matchMedia", { + writable: true, + value: jest.fn().mockImplementation((query: string) => ({ + matches: query === "(prefers-color-scheme: dark)" ? prefersDark : false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); +} + +function flushEffects() { + TestBed.inject(ApplicationRef).tick(); +} + +describe("GoabThemeService", () => { + beforeEach(() => { + localStorage.clear(); + document.documentElement.removeAttribute(ATTRIBUTE); + mockMatchMedia(false); + TestBed.resetTestingModule(); + TestBed.configureTestingModule({}); + }); + + describe("initial mode resolution", () => { + it("defaults to 'light' when localStorage, attribute, and system preference are absent", () => { + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("light"); + }); + + it("reads 'dark' from localStorage when present", () => { + localStorage.setItem(STORAGE_KEY, "dark"); + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("dark"); + }); + + it("reads 'light' from localStorage when present", () => { + localStorage.setItem(STORAGE_KEY, "light"); + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("light"); + }); + + it("ignores invalid localStorage values and falls through to next source", () => { + localStorage.setItem(STORAGE_KEY, "purple"); + document.documentElement.setAttribute(ATTRIBUTE, "dark"); + + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("dark"); + }); + + it("reads 'dark' from data-theme attribute when localStorage is empty", () => { + document.documentElement.setAttribute(ATTRIBUTE, "dark"); + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("dark"); + }); + + it("reads 'dark' from prefers-color-scheme when localStorage and attribute are absent", () => { + mockMatchMedia(true); + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("dark"); + }); + + it("prefers localStorage over data-theme attribute", () => { + localStorage.setItem(STORAGE_KEY, "light"); + document.documentElement.setAttribute(ATTRIBUTE, "dark"); + + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("light"); + }); + + it("prefers data-theme attribute over prefers-color-scheme", () => { + mockMatchMedia(true); + document.documentElement.setAttribute(ATTRIBUTE, "light"); + + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("light"); + }); + }); + + describe("setMode", () => { + it("updates the mode signal", () => { + const service = TestBed.inject(GoabThemeService); + service.setMode("dark"); + expect(service.mode()).toBe("dark"); + }); + + it("syncs the data-theme attribute on ", () => { + const service = TestBed.inject(GoabThemeService); + service.setMode("dark"); + flushEffects(); + expect(document.documentElement.getAttribute(ATTRIBUTE)).toBe("dark"); + + service.setMode("light"); + flushEffects(); + expect(document.documentElement.getAttribute(ATTRIBUTE)).toBe("light"); + }); + + it("persists the mode to localStorage", () => { + const service = TestBed.inject(GoabThemeService); + service.setMode("dark"); + flushEffects(); + expect(localStorage.getItem(STORAGE_KEY)).toBe("dark"); + }); + }); + + describe("toggle", () => { + it("flips light to dark", () => { + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("light"); + + service.toggle(); + expect(service.mode()).toBe("dark"); + }); + + it("flips dark to light", () => { + localStorage.setItem(STORAGE_KEY, "dark"); + const service = TestBed.inject(GoabThemeService); + expect(service.mode()).toBe("dark"); + + service.toggle(); + expect(service.mode()).toBe("light"); + }); + + it("flips back and forth across multiple calls", () => { + const service = TestBed.inject(GoabThemeService); + + service.toggle(); + expect(service.mode()).toBe("dark"); + + service.toggle(); + expect(service.mode()).toBe("light"); + + service.toggle(); + expect(service.mode()).toBe("dark"); + }); + + it("syncs attribute and localStorage on toggle", () => { + const service = TestBed.inject(GoabThemeService); + + service.toggle(); + flushEffects(); + expect(document.documentElement.getAttribute(ATTRIBUTE)).toBe("dark"); + expect(localStorage.getItem(STORAGE_KEY)).toBe("dark"); + }); + }); + + describe("localStorage failures", () => { + it("does not throw when localStorage.setItem is blocked", () => { + const setItemSpy = jest + .spyOn(Storage.prototype, "setItem") + .mockImplementation(() => { + throw new Error("QuotaExceededError"); + }); + + const service = TestBed.inject(GoabThemeService); + + expect(() => { + service.setMode("dark"); + flushEffects(); + }).not.toThrow(); + + // Attribute should still update even if storage fails + expect(document.documentElement.getAttribute(ATTRIBUTE)).toBe("dark"); + + setItemSpy.mockRestore(); + }); + + it("does not throw when localStorage.getItem is blocked at construction", () => { + const getItemSpy = jest + .spyOn(Storage.prototype, "getItem") + .mockImplementation(() => { + throw new Error("SecurityError"); + }); + + expect(() => TestBed.inject(GoabThemeService)).not.toThrow(); + + getItemSpy.mockRestore(); + }); + }); + + describe("readonly mode signal", () => { + it("exposes mode as a read-only signal (no .set/.update)", () => { + const service = TestBed.inject(GoabThemeService); + const modeSignal = service.mode as unknown as Record; + + expect(typeof modeSignal["set"]).toBe("undefined"); + expect(typeof modeSignal["update"]).toBe("undefined"); + }); + }); +}); diff --git a/libs/angular-components/src/lib/theme/theme.service.ts b/libs/angular-components/src/lib/theme/theme.service.ts new file mode 100644 index 0000000000..efe89b44a5 --- /dev/null +++ b/libs/angular-components/src/lib/theme/theme.service.ts @@ -0,0 +1,52 @@ +import { Injectable, effect, signal, type Signal } from "@angular/core"; +import type { GoabThemeMode } from "@abgov/ui-components-common"; + +const STORAGE_KEY = "goab-theme"; +const ATTRIBUTE = "data-theme"; + +@Injectable({ providedIn: "root" }) +export class GoabThemeService { + private readonly _mode = signal(this.readInitialMode()); + + /** Read-only signal for consumers. Use in templates: theme.mode() === 'dark'. */ + readonly mode: Signal = this._mode.asReadonly(); + + constructor() { + effect(() => { + const current = this._mode(); + if (typeof document === "undefined") return; + document.documentElement.setAttribute(ATTRIBUTE, current); + try { + window.localStorage.setItem(STORAGE_KEY, current); + } catch { + // localStorage blocked: fail silently. + } + }); + } + + setMode(next: GoabThemeMode): void { + this._mode.set(next); + } + + toggle(): void { + this._mode.update((prev) => (prev === "light" ? "dark" : "light")); + } + + private readInitialMode(): GoabThemeMode { + if (typeof window === "undefined") return "light"; + + try { + const stored = window.localStorage.getItem(STORAGE_KEY); + if (stored === "light" || stored === "dark") return stored; + } catch { + // fall through + } + + const fromAttribute = document.documentElement.getAttribute(ATTRIBUTE); + if (fromAttribute === "light" || fromAttribute === "dark") return fromAttribute; + + if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark"; + + return "light"; + } +} diff --git a/libs/common/src/lib/common.ts b/libs/common/src/lib/common.ts index 6e104f1ad8..942333f31d 100644 --- a/libs/common/src/lib/common.ts +++ b/libs/common/src/lib/common.ts @@ -265,6 +265,7 @@ export type GoabButtonGroupGap = "relaxed" | "compact"; // Accordion export type GoabAccordionHeadingSize = "small" | "medium"; export type GoabAccordionIconPosition = "left" | "right"; +export type GoabAccordionHeadingType = "normal" | "filled"; // Tooltip @@ -1337,6 +1338,7 @@ export type GoabDrawerSizeUnit = "px" | "rem" | "ch" | "vh" | "vw" | "%"; export type GoabDrawerSize = `${number}${GoabDrawerSizeUnit}` | undefined; // Work side menu +/** @deprecated Use trailingContent with explicit badge components for indicator styling. */ export type GoabWorkSideMenuItemType = "normal" | "emergency" | "success"; // Work side notification @@ -1378,3 +1380,5 @@ export type GoabRadioGroupSize = "default" | "compact"; export type GoabInputSize = "default" | "compact"; export type GoabTextAreaSize = "default" | "compact"; + +export type GoabThemeMode = "light" | "dark"; diff --git a/libs/react-components/specs/accordion.browser.spec.tsx b/libs/react-components/specs/accordion.browser.spec.tsx index a76495971b..135df672be 100644 --- a/libs/react-components/specs/accordion.browser.spec.tsx +++ b/libs/react-components/specs/accordion.browser.spec.tsx @@ -119,6 +119,59 @@ describe("Accordion", () => { }); }); + it("should not expand the accordion when a button in the actions slot is clicked", async () => { + const accordionChangeSpy = vi.fn(); + + const Component = () => { + return ( + Action + } + onChange={accordionChangeSpy} + > + Accordion content + + ); + }; + + const result = render(); + const button = result.getByTestId("actions-button"); + await userEvent.click(button); + + await vi.waitFor(() => { + expect(accordionChangeSpy).not.toHaveBeenCalled(); + }); + }); + + it("should fire the actions button onClick when the actions button is clicked", async () => { + const handleClick = vi.fn(); + + const Component = () => { + return ( + Action + } + > + Accordion content + + ); + }; + + const result = render(); + const button = result.getByTestId("actions-button"); + await userEvent.click(button); + + await vi.waitFor(() => { + expect(handleClick).toHaveBeenCalled(); + }); + }); + it("should set the open attribute on the details element", async () => { const Component = () => { const [open, setOpen] = useState(false); diff --git a/libs/react-components/specs/datagrid.browser.spec.tsx b/libs/react-components/specs/datagrid.browser.spec.tsx index 805ecf4e5f..1c876d1c83 100644 --- a/libs/react-components/specs/datagrid.browser.spec.tsx +++ b/libs/react-components/specs/datagrid.browser.spec.tsx @@ -315,37 +315,38 @@ describe("DataGrid", () => { await userEvent.keyboard("{ArrowDown}"); await new Promise(resolve => setTimeout(resolve, 100)); - // Verify td data-testid="cell-1-idNumber" has style outline:3px solid var(--goa-color-interactive-focus) + // Verify td data-testid="cell-1-idNumber" carries the [data-focused] attribute const cell1IdNumber = result.container.querySelector('[data-testid="cell-1-idNumber"]') as HTMLElement; expect(cell1IdNumber).toBeTruthy(); - expect(cell1IdNumber.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell1IdNumber.hasAttribute('data-focused')).toBe(true); // Press Arrow Right await userEvent.keyboard("{ArrowRight}"); await new Promise(resolve => setTimeout(resolve, 100)); - // Verify td data-testid="cell-1-dateStarted" has style outline:3px solid var(--goa-color-interactive-focus) + // Verify td data-testid="cell-1-dateStarted" carries the [data-focused] attribute const cell1DateStarted = result.container.querySelector('[data-testid="cell-1-dateStarted"]') as HTMLElement; - expect(cell1DateStarted?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell1DateStarted?.hasAttribute('data-focused')).toBe(true); - // verify td data-testid="cell-1-idNumber" has no more style defined on line 129 (no focus) - expect(cell1IdNumber?.style.outline).toBe(''); + // verify td data-testid="cell-1-idNumber" no longer carries [data-focused]. + // The attribute is removed when nav moves away. Table CSS owns the visual. + expect(cell1IdNumber?.hasAttribute('data-focused')).toBe(false); // Press Arrow Right await userEvent.keyboard("{ArrowRight}"); await new Promise(resolve => setTimeout(resolve, 100)); - // Verify td data-testid="cell-1-dateSubmitted" has inline style outline 3px... + // Verify td data-testid="cell-1-dateSubmitted" carries the [data-focused] attribute const cell1DateSubmitted = result.container.querySelector('[data-testid="cell-1-dateSubmitted"]') as HTMLElement; - expect(cell1DateSubmitted?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell1DateSubmitted?.hasAttribute('data-focused')).toBe(true); // Press Arrow Right await userEvent.keyboard("{ArrowRight}"); await new Promise(resolve => setTimeout(resolve, 100)); - // Verify td data-testid="cell-1-status" has inline style outline + // Verify td data-testid="cell-1-status" carries the [data-focused] attribute const cell1Status = result.container.querySelector('[data-testid="cell-1-status"]') as HTMLElement; - expect(cell1Status?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell1Status?.hasAttribute('data-focused')).toBe(true); // Press Arrow Right to move to Actions column (last cell with buttons) await userEvent.keyboard("{ArrowRight}"); @@ -433,13 +434,13 @@ describe("DataGrid", () => { statusCells.forEach(cell => { const htmlCell = cell as HTMLElement; - if (htmlCell.style.outline?.includes('3px solid')) { + if (htmlCell.hasAttribute('data-focused')) { focusedStatusCell = htmlCell; } }); expect(focusedStatusCell).toBeTruthy(); - expect(focusedStatusCell?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(focusedStatusCell?.hasAttribute('data-focused')).toBe(true); // Press arrow right to move to Actions column await userEvent.keyboard("{ArrowRight}"); @@ -461,7 +462,7 @@ describe("DataGrid", () => { // Verify a status cell is still highlighted after deletion const remainingStatusCell = result.container.querySelector('td[data-testid*="-status"]') as HTMLElement; expect(remainingStatusCell).toBeTruthy(); - expect(remainingStatusCell?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(remainingStatusCell?.hasAttribute('data-focused')).toBe(true); }); it("Using with Container - should navigate with arrow keys", async() => { @@ -470,42 +471,45 @@ describe("DataGrid", () => { // Wait for components to fully render await new Promise(resolve => setTimeout(resolve, 500)); - // Click on to establish focus position. + // Per issue #3605, mouse click does NOT apply the focus ring — only keyboard + // navigation does. The cell carries no [data-focused] attribute on click. const cell1 = result.container.querySelector('[data-grid="cell-1"]') as HTMLElement; await userEvent.click(cell1); await new Promise(resolve => setTimeout(resolve, 100)); + expect(cell1?.hasAttribute('data-focused')).toBe(false); - // Verify that it is highlighted style: outline: 3px... - expect(cell1?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); - // Press Arrow Right + // Arrow Right is keyboard input — ring applies on the next cell. await userEvent.keyboard("{ArrowRight}"); await new Promise(resolve => setTimeout(resolve, 100)); // Verify goa-block data-grid="cell-2" highlighted const cell2 = result.container.querySelector('[data-grid="cell-2"]') as HTMLElement; - expect(cell2?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell2?.hasAttribute('data-focused')).toBe(true); - // verify that data-grid="cell-1" no more highlighted - expect(cell1?.style.outline).toBe(''); + // verify that data-grid="cell-1" no longer carries [data-focused]. + expect(cell1?.hasAttribute('data-focused')).toBe(false); // Arrow Right await userEvent.keyboard("{ArrowRight}"); await new Promise(resolve => setTimeout(resolve, 100)); // Press Enter await userEvent.keyboard("{Enter}"); - await new Promise(resolve => setTimeout(resolve, 100)); - // We will have a
{{message}}
which will update message when we press Open button => "Open user 1" for example - // Verify the message to test if Open is triggered - const openMessage = result.container.querySelector('[data-testid="open-user"]') as HTMLElement; - expect(openMessage?.textContent).toBe("Open user 1"); + // Wait for the Open handler to fire and React to render the message div. + // Enter activates the focused button via setTimeout(0) inside DataGrid.focusCell; + // a fixed sleep races the macrotask queue under CI load, so poll the assertion. + await vi.waitFor(() => { + const openMessage = result.container.querySelector('[data-testid="open-user"]') as HTMLElement; + expect(openMessage?.textContent).toBe("Open user 1"); + }); // Arrow Right await userEvent.keyboard("{ArrowRight}"); await new Promise(resolve => setTimeout(resolve, 100)); // Verify data-grid="cell-4" highlighted const cell4 = result.container.querySelector('[data-grid="cell-4"]') as HTMLElement; - expect(cell4?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell4?.hasAttribute('data-focused')).toBe(true); // Arrow Right await userEvent.keyboard("{ArrowRight}"); @@ -513,7 +517,7 @@ describe("DataGrid", () => { // Verify data-grid="cell-5" highlighted const cell5 = result.container.querySelector('[data-grid="cell-5"]') as HTMLElement; - expect(cell5?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell5?.hasAttribute('data-focused')).toBe(true); // Arrow Right await userEvent.keyboard("{ArrowRight}"); @@ -521,7 +525,7 @@ describe("DataGrid", () => { // Verify data-grid="cell-6" highlighted const cell6 = result.container.querySelector('[data-grid="cell-6"]') as HTMLElement; - expect(cell6?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell6?.hasAttribute('data-focused')).toBe(true); // Arrow Right await userEvent.keyboard("{ArrowRight}"); @@ -529,7 +533,7 @@ describe("DataGrid", () => { // Verify data-grid="cell-7" highlighted const cell7 = result.container.querySelector('[data-grid="cell-7"]') as HTMLElement; - expect(cell7?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell7?.hasAttribute('data-focused')).toBe(true); // Arrow Right await userEvent.keyboard("{ArrowRight}"); @@ -537,7 +541,7 @@ describe("DataGrid", () => { // Verify data-grid="cell-8" highlighted const cell8 = result.container.querySelector('[data-grid="cell-8"]') as HTMLElement; - expect(cell8?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(cell8?.hasAttribute('data-focused')).toBe(true); // Arrow right await userEvent.keyboard("{ArrowRight}"); await new Promise(resolve => setTimeout(resolve, 100)); @@ -552,11 +556,12 @@ describe("DataGrid", () => { // Press Enter await userEvent.keyboard("{Enter}"); - await new Promise(resolve => setTimeout(resolve, 100)); - // Verify div data-testid="approver-1" has text content = John Doe - const approver1 = result.container.querySelector('[data-testid="approver-1"]') as HTMLElement; - expect(approver1?.textContent).toBe("John Doe"); + // Wait for the dropdown selection to flow through to the rendered approver text. + await vi.waitFor(() => { + const approver1 = result.container.querySelector('[data-testid="approver-1"]') as HTMLElement; + expect(approver1?.textContent).toBe("John Doe"); + }); }) it("Using with Container (Layout mode) - arrow right from last cell wraps to next row", async () => { @@ -703,21 +708,20 @@ describe("DataGrid", () => { const initialRows = result.container.querySelectorAll('[data-grid="row"]'); expect(initialRows.length).toBe(2); - // Click on the first row's name cell to establish focus + // Click on the first row's name cell to establish focus position. + // Per issue #3605, mouse click establishes focus but does NOT apply the + // cell outline — the outline only shows for keyboard-driven focus. const firstRowName = result.container.querySelector('[data-testid="name-1"]') as HTMLElement; await userEvent.click(firstRowName); await new Promise(resolve => setTimeout(resolve, 100)); - // Verify first row name is highlighted - expect(firstRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); - - // Navigate to the second row using Arrow Down + // Navigate to the second row using Arrow Down — keyboard nav applies the outline. await userEvent.keyboard("{ArrowDown}"); await new Promise(resolve => setTimeout(resolve, 100)); // Verify second row name is highlighted const secondRowName = result.container.querySelector('[data-testid="name-2"]') as HTMLElement; - expect(secondRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(secondRowName?.hasAttribute('data-focused')).toBe(true); // Add new rows by clicking the button const addRowsBtn = result.container.querySelector('[data-testid="add-rows-btn"]') as HTMLElement; @@ -731,20 +735,17 @@ describe("DataGrid", () => { const updatedRows = result.container.querySelectorAll('[data-grid="row"]'); expect(updatedRows.length).toBe(4); - // Click on first row's name to re-establish focus + // Click on first row's name to re-establish focus position (no outline per #3605). await userEvent.click(firstRowName); await new Promise(resolve => setTimeout(resolve, 100)); - // Verify first row name is highlighted after re-click - expect(firstRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); - - // Navigate down through all rows including newly added ones + // Navigate down through all rows including newly added ones — keyboard applies outline. // Row 1 -> Row 2 await userEvent.keyboard("{ArrowDown}"); await new Promise(resolve => setTimeout(resolve, 100)); // Verify second row name is highlighted - expect(secondRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(secondRowName?.hasAttribute('data-focused')).toBe(true); // Row 2 -> Row 3 (newly added) await userEvent.keyboard("{ArrowDown}"); @@ -754,7 +755,7 @@ describe("DataGrid", () => { const thirdRowName = result.container.querySelector('[data-testid="name-3"]') as HTMLElement; expect(thirdRowName).toBeTruthy(); expect(thirdRowName?.textContent).toBe("New User 3"); - expect(thirdRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(thirdRowName?.hasAttribute('data-focused')).toBe(true); // Row 3 -> Row 4 (newly added) await userEvent.keyboard("{ArrowDown}"); @@ -764,20 +765,20 @@ describe("DataGrid", () => { const fourthRowName = result.container.querySelector('[data-testid="name-4"]') as HTMLElement; expect(fourthRowName).toBeTruthy(); expect(fourthRowName?.textContent).toBe("New User 4"); - expect(fourthRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(fourthRowName?.hasAttribute('data-focused')).toBe(true); // Navigate back up to verify bidirectional navigation works await userEvent.keyboard("{ArrowUp}"); // Row 4 -> Row 3 await new Promise(resolve => setTimeout(resolve, 100)); - expect(thirdRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(thirdRowName?.hasAttribute('data-focused')).toBe(true); await userEvent.keyboard("{ArrowUp}"); // Row 3 -> Row 2 await new Promise(resolve => setTimeout(resolve, 100)); - expect(secondRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(secondRowName?.hasAttribute('data-focused')).toBe(true); await userEvent.keyboard("{ArrowUp}"); // Row 2 -> Row 1 await new Promise(resolve => setTimeout(resolve, 100)); - expect(firstRowName?.style.outline).toContain('3px solid var(--goa-color-interactive-focus)'); + expect(firstRowName?.hasAttribute('data-focused')).toBe(true); }); }); diff --git a/libs/react-components/specs/link.browser.spec.tsx b/libs/react-components/specs/link.browser.spec.tsx index 621b0ebf76..64e2217dd3 100644 --- a/libs/react-components/specs/link.browser.spec.tsx +++ b/libs/react-components/specs/link.browser.spec.tsx @@ -2,6 +2,7 @@ import { render } from "vitest-browser-react"; import { GoabLink } from "../src"; import { expect, describe, it, vi } from "vitest"; +import { userEvent } from "@vitest/browser/context"; describe("Link", () => { it("should trigger the action with an arg", async () => { @@ -118,4 +119,48 @@ describe("Link", () => { expect(spy).toHaveBeenCalled(); }); }); + + it("should apply the focus ring on keyboard focus but not on mouse click (#3605)", async () => { + const Component = () => { + return ( +
+ + + Download file + + +
+ ); + }; + + const result = render(); + const anchor = result.getByTestId("anchor"); + const before = result.getByTestId("before"); + + // Wait for the custom element to upgrade so .shadowRoot is real. + // The .keyboard-focused class lives on a shadow-DOM element. + const linkDiv = await vi.waitFor(() => { + const host = result.container.querySelector("goa-link") as HTMLElement | null; + const el = host?.shadowRoot?.querySelector(".link") as HTMLElement | null; + expect(el).toBeTruthy(); + return el!; + }); + + // Mouse click on the anchor: pointer modality, no ring on the container. + await anchor.click(); + expect(linkDiv.classList.contains("keyboard-focused")).toBe(false); + + // Tab from the prior button into the link: keyboard modality, ring on the container. + await before.element().focus(); + await userEvent.keyboard("{Tab}"); + await vi.waitFor(() => { + expect(linkDiv.classList.contains("keyboard-focused")).toBe(true); + }); + + // Tab onward: focus leaves the link, class clears. + await userEvent.keyboard("{Tab}"); + await vi.waitFor(() => { + expect(linkDiv.classList.contains("keyboard-focused")).toBe(false); + }); + }); }) diff --git a/libs/react-components/specs/popover.browser.spec.tsx b/libs/react-components/specs/popover.browser.spec.tsx index 7db4ad54f2..83941ab205 100644 --- a/libs/react-components/specs/popover.browser.spec.tsx +++ b/libs/react-components/specs/popover.browser.spec.tsx @@ -202,6 +202,69 @@ describe("Popover", () => { expect(aboveWidth!).toBe(belowWidth!); }); + it("should not close parent popover when child popover closes", async () => { + const Component = () => { + return ( + + Open parent + + } + > +

Parent content

+ + Open child + + } + > +

Child content

+ + Close child + +
+
+ ); + }; + + const result = render(); + const parentTarget = result.getByTestId("parent-target"); + const childTarget = result.getByTestId("child-target"); + const parentContent = result.getByTestId("parent-content"); + const childContent = result.getByTestId("child-content"); + const childClose = result.getByTestId("child-close"); + + // Open parent popover + await parentTarget.click(); + await vi.waitFor(() => { + expect(parentContent).toBeVisible(); + }); + + // Open child popover + await childTarget.click(); + await vi.waitFor(() => { + expect(childContent).toBeVisible(); + }); + + // Close child popover using close button + await childClose.click(); + + // Parent popover should still be open + await vi.waitFor(() => { + expect(childContent).not.toBeVisible(); + expect(parentContent).toBeVisible(); + }); + }); + it("should align popover to the right edge of the target when there is not enough space on the right", async () => { const Component = () => { return ( diff --git a/libs/react-components/specs/temporary-notification-ctrl.browser.spec.tsx b/libs/react-components/specs/temporary-notification-ctrl.browser.spec.tsx index 461731dd7f..713784325d 100644 --- a/libs/react-components/specs/temporary-notification-ctrl.browser.spec.tsx +++ b/libs/react-components/specs/temporary-notification-ctrl.browser.spec.tsx @@ -289,18 +289,15 @@ describe("Temporary Notification Controller", () => { }); }); - it("should handle progress updates", async function() { + it("should handle progress updates", async () => { const Component = () => { return ( - + ); }; const result = render(); - const progressIndicator = result.getByTestId("progress"); + const progressIndicator = result.getByTestId("some-notification"); setTimeout(() => { const uuid = sendTemporaryNotification("some message", { @@ -308,10 +305,12 @@ describe("Temporary Notification Controller", () => { type: "progress", }); sendProgress(uuid, 10); - }, 0) + }, 0); await vi.waitFor(() => { - expect(progressIndicator.element().getAttribute("value")).toBe("10"); + const el = progressIndicator.element().querySelector("goa-linear-progress"); + expect(el).not.toBeNull(); + expect(el?.getAttribute("progress")).toBe("10"); }); }); }); diff --git a/libs/react-components/specs/work-side-menu.browser.spec.tsx b/libs/react-components/specs/work-side-menu.browser.spec.tsx index 5870928da1..31a605f5c9 100644 --- a/libs/react-components/specs/work-side-menu.browser.spec.tsx +++ b/libs/react-components/specs/work-side-menu.browser.spec.tsx @@ -1,6 +1,6 @@ import { render } from "vitest-browser-react"; import { useState } from "react"; -import { GoabButton } from "../src"; +import { GoabBadge, GoabButton } from "../src"; import { GoabWorkSideMenu, GoabWorkSideMenuItem, GoabWorkSideMenuGroup } from "../src"; import { expect, describe, it, vi } from "vitest"; import { page } from "@vitest/browser/context"; @@ -22,6 +22,7 @@ describe("WorkSideMenu", () => { url="#item1" label="Item 1" testId="primary-menu-item" + trailingContent={
Trailing
} /> } secondaryContent={ @@ -51,12 +52,16 @@ describe("WorkSideMenu", () => { const primarySlot = result.baseElement.querySelector("[slot='primary']"); const primaryMenuItem = result.getByTestId("primary-menu-item"); const primaryLink = primaryMenuItem.element().querySelector("a"); + const primaryTrailing = result.getByTestId("trailing-content"); expect(primarySlot).toBeTruthy(); expect(primaryLink?.getAttribute("href")).toBe("#item1"); expect(primaryLink?.textContent).toContain("Item 1"); expect(primaryLink?.role).toBe("menuitem"); + expect(primaryTrailing).toBeTruthy(); + expect(primaryTrailing.element().textContent).toBe("Trailing"); + const secondarySlot = result.baseElement.querySelector("[slot='secondary']"); const secondaryMenuItem = result.getByTestId("secondary-menu-item"); const secondaryLink = secondaryMenuItem.element().querySelector("a"); diff --git a/libs/react-components/src/index.ts b/libs/react-components/src/index.ts index f51ac6b0b9..9131e5d6a3 100644 --- a/libs/react-components/src/index.ts +++ b/libs/react-components/src/index.ts @@ -80,3 +80,4 @@ export * from "./lib/work-side-menu-group/work-side-menu-group"; export * from "./lib/work-side-menu-item/work-side-menu-item"; export * from "./lib/work-side-notification-item/work-side-notification-item"; export * from "./lib/work-side-notification-panel/work-side-notification-panel"; +export * from "./lib/theme/theme-context"; diff --git a/libs/react-components/src/lib/accordion/accordion.spec.tsx b/libs/react-components/src/lib/accordion/accordion.spec.tsx index 2331e6bfe2..6cf5f3586a 100644 --- a/libs/react-components/src/lib/accordion/accordion.spec.tsx +++ b/libs/react-components/src/lib/accordion/accordion.spec.tsx @@ -1,5 +1,6 @@ import { render } from "@testing-library/react"; import { GoabBadge } from "../badge/badge"; +import { GoabButton } from "../button/button"; import { GoabAccordion } from "./accordion"; @@ -20,6 +21,7 @@ describe("Accordion", () => { heading="The heading" secondaryText="Secondary Text" open + headingType="filled" headingContent={} maxWidth="480px" > @@ -30,17 +32,26 @@ describe("Accordion", () => { const headingContent = el?.querySelector("[slot='headingcontent']"); expect(el?.getAttribute("secondarytext")).toBe("Secondary Text"); expect(el?.getAttribute("open")).toBe("true"); + expect(el?.getAttribute("heading-type")).toBe("filled"); const badge = headingContent?.querySelector("goa-badge"); expect(badge?.getAttribute("content")).toBe("test-badge"); expect(el?.getAttribute("maxwidth")).toBe("480px"); }); + it("should render the actions slot", () => { + const { baseElement } = render( + Action}> + Content + , + ); + const el = baseElement.querySelector("goa-accordion"); + const actions = el?.querySelector("[slot='actions']"); + expect(actions).toBeTruthy(); + }); + it("should pass data-grid attributes", () => { const { baseElement } = render( - + Content , ); diff --git a/libs/react-components/src/lib/accordion/accordion.tsx b/libs/react-components/src/lib/accordion/accordion.tsx index a577a18a35..986ace64b5 100644 --- a/libs/react-components/src/lib/accordion/accordion.tsx +++ b/libs/react-components/src/lib/accordion/accordion.tsx @@ -3,6 +3,7 @@ import { ReactNode, useEffect, useRef, type JSX } from "react"; import type { GoabAccordionHeadingSize, GoabAccordionIconPosition, + GoabAccordionHeadingType, Margins, DataAttributes, } from "@abgov/ui-components-common"; @@ -17,6 +18,7 @@ interface WCProps extends Margins { maxwidth?: string; testid?: string; iconposition?: GoabAccordionIconPosition; + headingType?: GoabAccordionHeadingType; } declare module "react" { @@ -42,12 +44,16 @@ export interface GoabAccordionProps extends Margins, DataAttributes { secondaryText?: string; /** Sets content rendered within the accordion heading, alongside the heading text. */ headingContent?: ReactNode; + /** Sets content rendered in the accordion heading, right-aligned before the expand/collapse icon. */ + actions?: ReactNode; /** Sets the maximum width of the accordion. @default "none" */ maxWidth?: string; /** Sets a data-testid attribute for automated testing. */ testId?: string; /** Sets the position of the expand/collapse icon. @default "left" */ iconPosition?: GoabAccordionIconPosition; + /** Sets the accordion style variant. @default "normal" */ + headingType?: GoabAccordionHeadingType; /** Callback fired when the accordion is opened or closed. Receives the new open state as a boolean. */ onChange?: (open: boolean) => void; /** Content rendered inside the accordion body. */ @@ -59,6 +65,8 @@ export function GoabAccordion({ open, onChange, headingContent, + headingType, + actions, children, ...rest }: GoabAccordionProps): JSX.Element { @@ -81,8 +89,14 @@ export function GoabAccordion({ }, [onChange]); return ( - + {headingContent &&
{headingContent}
} + {actions &&
{actions}
} {children}
); diff --git a/libs/react-components/src/lib/chip/chip.tsx b/libs/react-components/src/lib/chip/chip.tsx index e02c58b08b..2ad7a678b7 100644 --- a/libs/react-components/src/lib/chip/chip.tsx +++ b/libs/react-components/src/lib/chip/chip.tsx @@ -30,19 +30,19 @@ declare module "react" { } export interface GoabChipProps extends Margins, DataAttributes { - /** @required @deprecated Use GoAFilterChip instead. The text content displayed in the chip. */ + /** @required @deprecated Use GoabFilterChip instead. The text content displayed in the chip. */ content: string; - /** @deprecated Use GoAFilterChip instead. When true, shows a delete icon and makes chip clickable. */ + /** @deprecated Use GoabFilterChip instead. When true, shows a delete icon and makes chip clickable. */ deletable?: boolean; - /** @deprecated Use GoAFilterChip instead. Icon displayed at the start of the chip. */ + /** @deprecated Use GoabFilterChip instead. Icon displayed at the start of the chip. */ leadingIcon?: string; - /** @deprecated Use GoAFilterChip instead. The icon theme - outline or filled. */ + /** @deprecated Use GoabFilterChip instead. The icon theme - outline or filled. */ iconTheme?: GoabChipTheme; - /** @deprecated Use GoAFilterChip instead. Shows an error state on the chip. */ + /** @deprecated Use GoabFilterChip instead. Shows an error state on the chip. */ error?: boolean; - /** @deprecated Use GoAFilterChip instead. The chip variant style. */ + /** @deprecated Use GoabFilterChip instead. The chip variant style. */ variant?: GoabChipVariant; - /** @deprecated Use GoAFilterChip instead. Sets a data-testid attribute for automated testing. */ + /** @deprecated Use GoabFilterChip instead. Sets a data-testid attribute for automated testing. */ testId?: string; /** Callback fired when the chip is clicked or deleted. */ onClick?: () => void; diff --git a/libs/react-components/src/lib/container/container.tsx b/libs/react-components/src/lib/container/container.tsx index f630646802..5645aff2d0 100644 --- a/libs/react-components/src/lib/container/container.tsx +++ b/libs/react-components/src/lib/container/container.tsx @@ -46,9 +46,9 @@ export interface GoabContainerProps extends Margins, DataAttributes { maxHeight?: string; /** Sets a data-testid attribute for automated testing. */ testId?: string; - /** Content rendered in the container's title/heading area. */ + /** @deprecated Use title instead. Alias for the title prop. */ heading?: ReactNode; - /** @deprecated Use heading instead. Alias for the heading prop. */ + /** Content rendered in the container's title/heading area. */ title?: ReactNode; /** Content rendered in the container's actions area, typically buttons or controls. */ actions?: ReactNode; diff --git a/libs/react-components/src/lib/drawer/drawer.tsx b/libs/react-components/src/lib/drawer/drawer.tsx index c1eda6568d..9c0fca7e34 100644 --- a/libs/react-components/src/lib/drawer/drawer.tsx +++ b/libs/react-components/src/lib/drawer/drawer.tsx @@ -56,9 +56,16 @@ export function GoabDrawer({ if (!el?.current || !onClose) { return; } - el.current?.addEventListener("_close", onClose); + const current = el.current; + const listener = (e: Event) => { + if (e.target !== current) { + return; + } + onClose(); + }; + current.addEventListener("_close", listener); return () => { - el.current?.removeEventListener("_close", onClose); + current.removeEventListener("_close", listener); }; }, [el, onClose]); diff --git a/libs/react-components/src/lib/dropdown/dropdown.tsx b/libs/react-components/src/lib/dropdown/dropdown.tsx index efe4819456..ced71d24a2 100644 --- a/libs/react-components/src/lib/dropdown/dropdown.tsx +++ b/libs/react-components/src/lib/dropdown/dropdown.tsx @@ -69,7 +69,7 @@ export interface GoabDropdownProps extends Margins, DataAttributes { leadingIcon?: GoabIconType; /** Maximum height of the dropdown menu. Non-native only. @default "276px" */ maxHeight?: string; - /** When true, allows multiple items to be selected. */ + /** When true, allows multiple items to be selected. @internal */ multiselect?: boolean; /** When true, renders the native select HTML element. */ native?: boolean; diff --git a/libs/react-components/src/lib/hero-banner/hero-banner.tsx b/libs/react-components/src/lib/hero-banner/hero-banner.tsx index ee721a39a1..3347746c72 100644 --- a/libs/react-components/src/lib/hero-banner/hero-banner.tsx +++ b/libs/react-components/src/lib/hero-banner/hero-banner.tsx @@ -29,6 +29,8 @@ export interface GoabHeroBannerProps { testId?: string; /** Content rendered inside the hero banner body. */ children?: React.ReactNode; + /** Content rendered in the actions slot. */ + actions?: React.ReactNode; /** Maximum width of the content area. @default "100%" */ maxContentWidth?: string; /** Hero Banner background color when no background image is provided. @default "#f8f8f8" */ @@ -46,6 +48,7 @@ export function GoabHeroBanner({ backgroundColor, textColor, children, + actions, testId, }: GoabHeroBannerProps): JSX.Element { return ( @@ -59,6 +62,7 @@ export function GoabHeroBanner({ testid={testId} > {children} + {actions &&
{actions}
} ); } diff --git a/libs/react-components/src/lib/input/input.tsx b/libs/react-components/src/lib/input/input.tsx index 7e508a7285..d134194289 100644 --- a/libs/react-components/src/lib/input/input.tsx +++ b/libs/react-components/src/lib/input/input.tsx @@ -179,7 +179,10 @@ export function GoabInput({ onBlur, onKeyPress, ...rest -}: GoabInputProps & { type?: GoabInputType }): JSX.Element { +}: GoabInputProps & { + /** Sets the type of the input field. @default "text" */ + type?: GoabInputType; +}): JSX.Element { const ref = useRef(null); const _props = transformProps( diff --git a/libs/react-components/src/lib/microsite-header/microsite-header.tsx b/libs/react-components/src/lib/microsite-header/microsite-header.tsx index 4132b6b9ce..106c6adfdf 100644 --- a/libs/react-components/src/lib/microsite-header/microsite-header.tsx +++ b/libs/react-components/src/lib/microsite-header/microsite-header.tsx @@ -26,7 +26,7 @@ interface WCProps { export interface GoabHeaderProps { /** @required The service type which determines the badge style. "live" shows official government site text, "alpha" and "beta" show development stage badges. */ type: GoabServiceLevel; - /** App or service version displayed on the right side of the header. Accepts a string or custom ReactNode for rich content. */ + /** App or service version displayed on the right side of the header. */ version?: string | React.ReactNode; /** URL to a feedback page displayed when provided. */ feedbackUrl?: string; diff --git a/libs/react-components/src/lib/modal/modal.tsx b/libs/react-components/src/lib/modal/modal.tsx index 38604c5d83..4b97f47b13 100644 --- a/libs/react-components/src/lib/modal/modal.tsx +++ b/libs/react-components/src/lib/modal/modal.tsx @@ -76,7 +76,10 @@ export function GoabModal({ return; } const current = el.current; - const listener = () => { + const listener = (e: Event) => { + if (e.target !== current) { + return; + } onClose?.(); }; diff --git a/libs/react-components/src/lib/push-drawer/push-drawer.tsx b/libs/react-components/src/lib/push-drawer/push-drawer.tsx index 681add6e08..ec3d4e7b96 100644 --- a/libs/react-components/src/lib/push-drawer/push-drawer.tsx +++ b/libs/react-components/src/lib/push-drawer/push-drawer.tsx @@ -51,9 +51,16 @@ export function GoabPushDrawer({ if (!el?.current || !onClose) { return; } - el.current?.addEventListener("_close", onClose); + const current = el.current; + const listener = (e: Event) => { + if (e.target !== current) { + return; + } + onClose(); + }; + current.addEventListener("_close", listener); return () => { - el.current?.removeEventListener("_close", onClose); + current.removeEventListener("_close", listener); }; }, [el, onClose]); diff --git a/libs/react-components/src/lib/radio-group/radio.tsx b/libs/react-components/src/lib/radio-group/radio.tsx index 9f100e6dc6..11b836f635 100644 --- a/libs/react-components/src/lib/radio-group/radio.tsx +++ b/libs/react-components/src/lib/radio-group/radio.tsx @@ -44,7 +44,7 @@ export interface GoabRadioItemProps extends Margins { maxWidth?: string; /** Disables this radio option. Also disabled if the parent RadioGroup is disabled. */ disabled?: boolean; - /** Sets this radio option as checked/selected. */ + /** @internal Sets this radio option as checked/selected. */ checked?: boolean; /** Shows an error state on this radio option. */ error?: boolean; diff --git a/libs/react-components/src/lib/tab/tab.tsx b/libs/react-components/src/lib/tab/tab.tsx index 919289ed83..0064fb1643 100644 --- a/libs/react-components/src/lib/tab/tab.tsx +++ b/libs/react-components/src/lib/tab/tab.tsx @@ -1,7 +1,7 @@ import type { JSX } from "react"; interface WCProps { - heading?: React.ReactNode; + heading?: string | React.ReactNode; disabled?: string; slug?: string; } @@ -17,7 +17,7 @@ declare module "react" { export interface GoabTabItemProps { /** The text label for this tab. Can also pass React nodes for custom heading content. */ - heading?: React.ReactNode; + heading?: string | React.ReactNode; /** When true, disables the tab so it cannot be selected. */ disabled?: boolean; /** Content rendered inside the tab panel. */ diff --git a/libs/react-components/src/lib/table/table-sort-header.tsx b/libs/react-components/src/lib/table/table-sort-header.tsx index 0995dc319b..6be764bbe1 100644 --- a/libs/react-components/src/lib/table/table-sort-header.tsx +++ b/libs/react-components/src/lib/table/table-sort-header.tsx @@ -10,6 +10,7 @@ interface WCProps { name?: string; direction?: GoabTableSortDirection; "sort-order"?: GoabTableSortOrder; + version?: "1" | "2"; } declare module "react" { @@ -46,6 +47,7 @@ export function GoabTableSortHeader({ name={name} direction={direction} sort-order={sortOrder} + version="2" {...rest} > {children} diff --git a/libs/react-components/src/lib/table/table.tsx b/libs/react-components/src/lib/table/table.tsx index c07dc6bc17..b654243402 100644 --- a/libs/react-components/src/lib/table/table.tsx +++ b/libs/react-components/src/lib/table/table.tsx @@ -10,7 +10,6 @@ import { ReactNode, useEffect, useRef } from "react"; interface WCProps extends Margins { ref?: React.RefObject; width?: string; - stickyheader?: string; variant?: GoabTableVariant; "sort-mode"?: GoabTableSortMode; testid?: string; @@ -37,7 +36,7 @@ export interface GoabTableProps extends Margins { onMultiSort?: (detail: GoabTableOnMultiSortDetail) => void; /** Sort mode: "single" allows one column, "multi" allows up to 2 columns. @default "single" */ sortMode?: GoabTableSortMode; - // stickyHeader?: boolean; TODO: enable this later + // stickyHeader intentionally not exposed in wrapper yet. /** A relaxed variant of the table with more vertical padding for the cells. @default "normal" */ variant?: GoabTableVariant; /** When true, alternates row background colors for improved readability. */ diff --git a/libs/react-components/src/lib/theme/theme-context.spec.tsx b/libs/react-components/src/lib/theme/theme-context.spec.tsx new file mode 100644 index 0000000000..9eec8e998e --- /dev/null +++ b/libs/react-components/src/lib/theme/theme-context.spec.tsx @@ -0,0 +1,215 @@ +import { act, renderHook } from "@testing-library/react"; +import { type ReactNode } from "react"; + +import { GoabThemeProvider, useTheme } from "./theme-context"; + +const STORAGE_KEY = "goab-theme"; +const ATTRIBUTE = "data-theme"; + +function mockMatchMedia(prefersDark: boolean) { + Object.defineProperty(window, "matchMedia", { + writable: true, + value: vi.fn().mockImplementation((query: string) => ({ + matches: query === "(prefers-color-scheme: dark)" ? prefersDark : false, + media: query, + onchange: null, + addListener: vi.fn(), + removeListener: vi.fn(), + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn(), + })), + }); +} + +function wrapper(props: { children: ReactNode }) { + return {props.children}; +} + +describe("GoabThemeProvider / useTheme", () => { + beforeEach(() => { + localStorage.clear(); + document.documentElement.removeAttribute(ATTRIBUTE); + mockMatchMedia(false); + }); + + describe("initial mode resolution", () => { + it("defaults to 'light' when localStorage, attribute, and system preference are absent", () => { + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("light"); + }); + + it("reads 'dark' from localStorage when present", () => { + localStorage.setItem(STORAGE_KEY, "dark"); + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("dark"); + }); + + it("reads 'light' from localStorage when present", () => { + localStorage.setItem(STORAGE_KEY, "light"); + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("light"); + }); + + it("ignores invalid localStorage values and falls through to next source", () => { + localStorage.setItem(STORAGE_KEY, "purple"); + document.documentElement.setAttribute(ATTRIBUTE, "dark"); + + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("dark"); + }); + + it("reads 'dark' from data-theme attribute when localStorage is empty", () => { + document.documentElement.setAttribute(ATTRIBUTE, "dark"); + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("dark"); + }); + + it("reads 'dark' from prefers-color-scheme when localStorage and attribute are absent", () => { + mockMatchMedia(true); + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("dark"); + }); + + it("prefers localStorage over data-theme attribute", () => { + localStorage.setItem(STORAGE_KEY, "light"); + document.documentElement.setAttribute(ATTRIBUTE, "dark"); + + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("light"); + }); + + it("prefers data-theme attribute over prefers-color-scheme", () => { + mockMatchMedia(true); + document.documentElement.setAttribute(ATTRIBUTE, "light"); + + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("light"); + }); + + it("respects defaultMode prop when no other source is set", () => { + const customWrapper = (props: { children: ReactNode }) => ( + {props.children} + ); + const { result } = renderHook(() => useTheme(), { wrapper: customWrapper }); + expect(result.current.mode).toBe("dark"); + }); + }); + + describe("setMode", () => { + it("updates the mode value", () => { + const { result } = renderHook(() => useTheme(), { wrapper }); + + act(() => result.current.setMode("dark")); + expect(result.current.mode).toBe("dark"); + }); + + it("syncs the data-theme attribute on ", () => { + const { result } = renderHook(() => useTheme(), { wrapper }); + + act(() => result.current.setMode("dark")); + expect(document.documentElement.getAttribute(ATTRIBUTE)).toBe("dark"); + + act(() => result.current.setMode("light")); + expect(document.documentElement.getAttribute(ATTRIBUTE)).toBe("light"); + }); + + it("persists the mode to localStorage", () => { + const { result } = renderHook(() => useTheme(), { wrapper }); + + act(() => result.current.setMode("dark")); + expect(localStorage.getItem(STORAGE_KEY)).toBe("dark"); + }); + }); + + describe("toggle", () => { + it("flips light to dark", () => { + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("light"); + + act(() => result.current.toggle()); + expect(result.current.mode).toBe("dark"); + }); + + it("flips dark to light", () => { + localStorage.setItem(STORAGE_KEY, "dark"); + const { result } = renderHook(() => useTheme(), { wrapper }); + expect(result.current.mode).toBe("dark"); + + act(() => result.current.toggle()); + expect(result.current.mode).toBe("light"); + }); + + it("flips back and forth across multiple calls", () => { + const { result } = renderHook(() => useTheme(), { wrapper }); + + act(() => result.current.toggle()); + expect(result.current.mode).toBe("dark"); + + act(() => result.current.toggle()); + expect(result.current.mode).toBe("light"); + + act(() => result.current.toggle()); + expect(result.current.mode).toBe("dark"); + }); + + it("syncs attribute and localStorage on toggle", () => { + const { result } = renderHook(() => useTheme(), { wrapper }); + + act(() => result.current.toggle()); + expect(document.documentElement.getAttribute(ATTRIBUTE)).toBe("dark"); + expect(localStorage.getItem(STORAGE_KEY)).toBe("dark"); + }); + + it("returns a stable toggle reference across renders", () => { + const { result, rerender } = renderHook(() => useTheme(), { wrapper }); + const firstToggle = result.current.toggle; + + rerender(); + expect(result.current.toggle).toBe(firstToggle); + }); + }); + + describe("useTheme outside provider", () => { + it("throws a descriptive error when used without GoabThemeProvider", () => { + // Suppress React's expected error log for this test + const noop = () => undefined; + const errorSpy = vi.spyOn(console, "error").mockImplementation(noop); + + expect(() => renderHook(() => useTheme())).toThrow( + "useTheme must be used within a GoabThemeProvider", + ); + + errorSpy.mockRestore(); + }); + }); + + describe("localStorage failures", () => { + it("does not throw when localStorage.setItem is blocked", () => { + const setItemSpy = vi + .spyOn(Storage.prototype, "setItem") + .mockImplementation(() => { + throw new Error("QuotaExceededError"); + }); + + const { result } = renderHook(() => useTheme(), { wrapper }); + + expect(() => act(() => result.current.setMode("dark"))).not.toThrow(); + expect(document.documentElement.getAttribute(ATTRIBUTE)).toBe("dark"); + + setItemSpy.mockRestore(); + }); + + it("does not throw when localStorage.getItem is blocked at construction", () => { + const getItemSpy = vi + .spyOn(Storage.prototype, "getItem") + .mockImplementation(() => { + throw new Error("SecurityError"); + }); + + expect(() => renderHook(() => useTheme(), { wrapper })).not.toThrow(); + + getItemSpy.mockRestore(); + }); + }); +}); diff --git a/libs/react-components/src/lib/theme/theme-context.tsx b/libs/react-components/src/lib/theme/theme-context.tsx new file mode 100644 index 0000000000..2f02c14d1e --- /dev/null +++ b/libs/react-components/src/lib/theme/theme-context.tsx @@ -0,0 +1,87 @@ +import { + createContext, + useCallback, + useContext, + useEffect, + useState, + type ReactNode, +} from "react"; +import type { GoabThemeMode } from "@abgov/ui-components-common"; + +interface GoabThemeContextValue { + mode: GoabThemeMode; + setMode: (mode: GoabThemeMode) => void; + toggle: () => void; +} + +const STORAGE_KEY = "goab-theme"; +const ATTRIBUTE = "data-theme"; + +const GoabThemeContext = createContext(null); + +function readInitialMode(defaultMode: GoabThemeMode): GoabThemeMode { + if (typeof window === "undefined") return defaultMode; + + // Priority: localStorage > existing data-theme > system preference > defaultMode. + // Reading the attribute allows a blocking
diff --git a/libs/web-components/src/components/menu-button/MenuButton.svelte b/libs/web-components/src/components/menu-button/MenuButton.svelte index 9af6007abb..e77f2634f1 100644 --- a/libs/web-components/src/components/menu-button/MenuButton.svelte +++ b/libs/web-components/src/components/menu-button/MenuButton.svelte @@ -139,7 +139,7 @@ } function onAction(action: MenuActionProps) { - dispatch(_rootEl, "_action", action, { bubbles: true }); + dispatch(_rootEl, "_action", { action: action.action, size: action.size }, { bubbles: true }); close(); _buttonIndex = 0; } diff --git a/libs/web-components/src/components/microsite-header/MicrositeHeader.svelte b/libs/web-components/src/components/microsite-header/MicrositeHeader.svelte index fe03dfbd97..ff19af50d9 100644 --- a/libs/web-components/src/components/microsite-header/MicrositeHeader.svelte +++ b/libs/web-components/src/components/microsite-header/MicrositeHeader.svelte @@ -161,7 +161,7 @@ color: var(--goa-microsite-header-color-links-hover); } - a:focus { + a:focus-visible { outline: var(--goa-microsite-header-link-focus-border); } diff --git a/libs/web-components/src/components/notification/Notification.svelte b/libs/web-components/src/components/notification/Notification.svelte index 28c0caf94e..efe9adb63c 100644 --- a/libs/web-components/src/components/notification/Notification.svelte +++ b/libs/web-components/src/components/notification/Notification.svelte @@ -191,11 +191,11 @@ color: unset !important; outline: unset !important; } - :global(::slotted(a:focus)) { + :global(::slotted(a:focus-visible)) { outline: auto !important; border-radius: var(--goa-border-radius-xs); } - .notification.important :global(::slotted(a:focus)) { + .notification.important :global(::slotted(a:focus-visible)) { outline: unset !important; box-shadow: 0 0 0 3px var(--goa-color-greyscale-black); border-radius: var(--goa-border-radius-xs); @@ -423,27 +423,27 @@ } /* V2 link focus states */ - .v2 .notification.important.high :global(::slotted(a:focus)) { + .v2 .notification.important.high :global(::slotted(a:focus-visible)) { box-shadow: var(--goa-notification-banner-important-high-focus-border); } - .v2 .notification.important.low :global(::slotted(a:focus)) { + .v2 .notification.important.low :global(::slotted(a:focus-visible)) { box-shadow: var(--goa-notification-banner-important-low-focus-border); } - .v2 .notification.information.high :global(::slotted(a:focus)) { + .v2 .notification.information.high :global(::slotted(a:focus-visible)) { box-shadow: var(--goa-notification-banner-information-high-focus-border); } - .v2 .notification.information.low :global(::slotted(a:focus)) { + .v2 .notification.information.low :global(::slotted(a:focus-visible)) { box-shadow: var(--goa-notification-banner-information-low-focus-border); } - .v2 .notification.emergency.high :global(::slotted(a:focus)) { + .v2 .notification.emergency.high :global(::slotted(a:focus-visible)) { box-shadow: var(--goa-notification-banner-emergency-high-focus-border); } - .v2 .notification.emergency.low :global(::slotted(a:focus)) { + .v2 .notification.emergency.low :global(::slotted(a:focus-visible)) { box-shadow: var(--goa-notification-banner-emergency-low-focus-border); } diff --git a/libs/web-components/src/components/popover/Popover.svelte b/libs/web-components/src/components/popover/Popover.svelte index 0b9fa6d436..362349ec6a 100644 --- a/libs/web-components/src/components/popover/Popover.svelte +++ b/libs/web-components/src/components/popover/Popover.svelte @@ -54,13 +54,13 @@ /** Disables the popover interaction. Used by parent components like Dropdown. */ export let disabled: string = "false"; /** Additional vertical offset added to the popover's position. */ - export let voffset = ""; + export let voffset: string = ""; /** Additional horizontal offset added to the popover's position. */ - export let hoffset = ""; + export let hoffset: string = ""; /** Width of the focus outline border. */ - export let focusborderwidth = "var(--goa-border-width-l)"; + export let focusborderwidth: string = "var(--goa-border-width-l)"; /** Border radius of the popover window. */ - export let borderradius = "var(--goa-border-radius-m)"; + export let borderradius: string = "var(--goa-border-radius-m)"; /** Indicates the popover is used within a filterable context like a combobox. */ export let filterablecontext: string = "false"; @@ -200,6 +200,44 @@ } } + function isInPopoverComposedTree(node: EventTarget | null): boolean { + if (!_popoverEl || !(node instanceof Node)) { + return false; + } + + if (_popoverEl.contains(node)) { + return true; + } + + // Walk across slot and shadow boundaries to detect nested/slotted descendants. + let current: Node | null = node; + while (current) { + if (current === _popoverEl) { + return true; + } + + if (current instanceof Element && current.assignedSlot) { + current = current.assignedSlot; + continue; + } + + if (current.parentNode) { + current = current.parentNode; + continue; + } + + const rootNode = current.getRootNode?.(); + if (rootNode instanceof ShadowRoot) { + current = rootNode.host; + continue; + } + + current = null; + } + + return false; + } + // When one popover is opened it dispatches a `goa:closePopover` to the document.body element, so adding a listener // here will allow any other popover that is currently open to be closed function addGlobalCloseListener() { @@ -213,7 +251,10 @@ // the popover that is being opened will, at that time have the an open state, so we need to prevent // that one that is being opened be immediately closed. if (target !== _targetEl) { - closePopover(); + // Don't close if the target is a child popover (descendant of this popover's content) + if (target && !isInPopoverComposedTree(target)) { + closePopover(); + } } }); } @@ -404,7 +445,7 @@ class:use-anchor-based-positioning={!_needsManualPositioning} class:align-right={_alignment === "right"} style={styles( - style("width", position !== "right" ? width : undefined), + position !== "right" && style("width", width), style("min-width", minwidth), style( "max-width", diff --git a/libs/web-components/src/components/push-drawer/PushDrawerInternal.svelte b/libs/web-components/src/components/push-drawer/PushDrawerInternal.svelte index 5efc55ea69..192bfa1e9e 100644 --- a/libs/web-components/src/components/push-drawer/PushDrawerInternal.svelte +++ b/libs/web-components/src/components/push-drawer/PushDrawerInternal.svelte @@ -24,6 +24,7 @@ export let open: boolean = false; export let heading: string = ""; export let width: string = "492px"; + /** @internal Design system version for styling. */ export let version: VersionType = "1"; let _contentEl: HTMLElement | null = null; diff --git a/libs/web-components/src/components/radio-item/RadioItem.svelte b/libs/web-components/src/components/radio-item/RadioItem.svelte index bbf00546a5..678d8705a2 100644 --- a/libs/web-components/src/components/radio-item/RadioItem.svelte +++ b/libs/web-components/src/components/radio-item/RadioItem.svelte @@ -66,7 +66,7 @@ export let disabled: string = "false"; /** Shows an error state on this radio option. */ export let error: string = "false"; - /** Sets this radio option as checked/selected. */ + /** @internal Sets this radio option as checked/selected. */ export let checked: string = "false"; /** Defines how this option will be announced by screen readers. */ export let arialabel: string = ""; @@ -209,7 +209,7 @@ checked = fromBoolean(data.checked); description = data.description; name = data.name; - revealarialabel = data.revealAriaLabel; + revealarialabel = data.revealAriaLabel || ""; _version = data.version || "1"; _compact = data.compact || false; }); diff --git a/libs/web-components/src/components/side-menu-group/SideMenuGroup.svelte b/libs/web-components/src/components/side-menu-group/SideMenuGroup.svelte index ef495212c3..7002ab82d5 100644 --- a/libs/web-components/src/components/side-menu-group/SideMenuGroup.svelte +++ b/libs/web-components/src/components/side-menu-group/SideMenuGroup.svelte @@ -138,7 +138,7 @@ ${calculateMargin(mt, mr, mb, ml)}; `} > - + {#if icon}
{#if version === "2"} diff --git a/libs/web-components/src/components/table/Table.svelte b/libs/web-components/src/components/table/Table.svelte index e9e0e714aa..c185459427 100644 --- a/libs/web-components/src/components/table/Table.svelte +++ b/libs/web-components/src/components/table/Table.svelte @@ -42,7 +42,7 @@ /** Width of the table. By default it will fit the enclosed content. */ export let width: string = ""; - /** When true, the table header sticks to the top when scrolling. */ + /** @internal When true, the table header sticks to the top when scrolling. */ export let stickyheader: string = "false"; /** When true, alternates row background colors for improved readability. */ export let striped: string = "false"; diff --git a/libs/web-components/src/components/table/TableSortHeader.svelte b/libs/web-components/src/components/table/TableSortHeader.svelte index d8813366c4..1f06307101 100644 --- a/libs/web-components/src/components/table/TableSortHeader.svelte +++ b/libs/web-components/src/components/table/TableSortHeader.svelte @@ -49,16 +49,18 @@ class:sorted={direction !== "none"} class:v2={version === "2"} > - - - {sortOrder} - {#if direction === "desc"} - - {:else if direction === "asc"} - - {:else} - - {/if} + + + + {sortOrder} + {#if direction === "desc"} + + {:else if direction === "asc"} + + {:else} + + {/if} + @@ -85,11 +87,21 @@ var(--goa-space-s) var(--goa-space-m) var(--goa-space-xs) ); justify-content: var(--header-text-align, flex-start); - gap: var(--goa-table-sort-header-gap, var(--goa-space-2xs)); align-items: flex-end; text-align: var(--header-align, left); } + /* Inline-flex wrapper around label + sort icon. Sizes to its content so the + focus ring wraps just the visible button content, not the whole cell. + The padding adds breathing room between the content and the focus ring. */ + .content { + display: inline-flex; + align-items: flex-end; + gap: var(--goa-table-sort-header-gap, var(--goa-space-2xs)); + padding: var(--goa-space-3xs); + border-radius: var(--goa-border-radius-m); + } + /* Hover state - no background change, only text color */ button:hover { color: var( @@ -102,17 +114,12 @@ outline: none; } - /* V1: Focus ring on whole button */ - button:focus-visible { + /* Focus ring on the content wrapper (label + sort icon) */ + button:focus-visible .content { box-shadow: 0 0 0 var(--goa-border-width-l) var(--goa-color-interactive-focus); } - /* V2: No focus ring on button, focus ring goes on icon instead */ - button.v2:focus-visible { - box-shadow: none; - } - /* Icon wrapper - contains the sort icon */ .icon-wrapper { display: inline-flex; @@ -121,15 +128,6 @@ border-radius: var(--goa-border-radius-m); } - /* V2: Focus ring on icon when button is focused */ - button.v2:focus-visible .icon-wrapper { - box-shadow: 0 0 0 var(--goa-icon-button-focus-border-width, 2px) - var( - --goa-icon-button-focus-border-color, - var(--goa-color-interactive-focus) - ); - } - /* Active sort icon */ button.sorted goa-icon { color: var(--goa-color-interactive-default); diff --git a/libs/web-components/src/components/tabs/Tabs.svelte b/libs/web-components/src/components/tabs/Tabs.svelte index 470cece631..6dba4e53d6 100644 --- a/libs/web-components/src/components/tabs/Tabs.svelte +++ b/libs/web-components/src/components/tabs/Tabs.svelte @@ -342,8 +342,7 @@ let currentLocation = ""; // send message to each tab to set visibility within - // @ts-expect-error - [..._tabsEl.querySelectorAll("[role=tab]")].map((el, index) => { + [..._tabsEl.querySelectorAll("[role=tab]")].map((el, index) => { const isCurrent = index + 1 === +_currentTab; // currentTab is 1-based el.setAttribute("aria-selected", fromBoolean(isCurrent)); diff --git a/libs/web-components/src/components/temporary-notification/TemporaryNotification.spec.ts b/libs/web-components/src/components/temporary-notification/TemporaryNotification.spec.ts index 307abaacc4..a5cfa5d1de 100644 --- a/libs/web-components/src/components/temporary-notification/TemporaryNotification.spec.ts +++ b/libs/web-components/src/components/temporary-notification/TemporaryNotification.spec.ts @@ -6,7 +6,7 @@ describe("GoATemporaryNotification", () => { it("should render", async () => { const { findByTestId } = render(GoATemporaryNotification, { testid: "notification-test", - message: "Test notification" + message: "Test notification", }); const notification = await findByTestId("notification-test"); @@ -15,25 +15,27 @@ describe("GoATemporaryNotification", () => { }); describe("types", () => { - ["basic", "success", "failure", "indeterminate", "progress"].forEach((type) => { - it(`should render ${type} type`, async () => { - const { findByTestId } = render(GoATemporaryNotification, { - testid: "notification-test", - message: "Test notification", - type + ["basic", "success", "failure", "indeterminate", "progress"].forEach( + (type) => { + it(`should render ${type} type`, async () => { + const { findByTestId } = render(GoATemporaryNotification, { + testid: "notification-test", + message: "Test notification", + type, + }); + const notification = await findByTestId("notification-test"); + + expect(notification).toBeTruthy(); + expect(notification.className).toContain(type); }); - const notification = await findByTestId("notification-test"); - - expect(notification).toBeTruthy(); - expect(notification.className).toContain(type); - }); - }); + }, + ); it("should render success type with checkmark icon", async () => { const { container } = render(GoATemporaryNotification, { testid: "notification-test", message: "Success notification", - type: "success" + type: "success", }); const icon = container.querySelector("goa-icon"); @@ -45,7 +47,7 @@ describe("GoATemporaryNotification", () => { const { container } = render(GoATemporaryNotification, { testid: "notification-test", message: "Failure notification", - type: "failure" + type: "failure", }); const icon = container.querySelector("goa-icon"); @@ -58,25 +60,30 @@ describe("GoATemporaryNotification", () => { testid: "notification-test", message: "Progress notification", type: "progress", - progress: 50 + progress: 50, }); - const progressBar = container.querySelector("progress"); + const progressBar = container.querySelector("goa-linear-progress"); expect(progressBar).toBeTruthy(); - expect(progressBar?.getAttribute("value")).toBe("50"); - expect(progressBar?.getAttribute("max")).toBe("100"); + expect(progressBar?.getAttribute("progress")).toBe("50"); + expect(progressBar?.getAttribute("aria-label")).toBe( + "Progress notification", + ); }); it("should render indeterminate type with indeterminate progress bar", async () => { const { container } = render(GoATemporaryNotification, { testid: "notification-test", message: "Indeterminate notification", - type: "indeterminate" + type: "indeterminate", }); - const progressBar = container.querySelector("progress"); + const progressBar = container.querySelector("goa-linear-progress"); expect(progressBar).toBeTruthy(); - expect(progressBar?.hasAttribute("value")).toBe(false); + expect(progressBar?.hasAttribute("progress")).toBe(false); + expect(progressBar?.getAttribute("aria-label")).toBe( + "Indeterminate notification", + ); }); }); @@ -84,7 +91,7 @@ describe("GoATemporaryNotification", () => { it("should be visible by default", async () => { const { findByTestId } = render(GoATemporaryNotification, { testid: "notification-test", - message: "Test notification" + message: "Test notification", }); const notification = await findByTestId("notification-test"); @@ -96,7 +103,7 @@ describe("GoATemporaryNotification", () => { const { findByTestId } = render(GoATemporaryNotification, { testid: "notification-test", message: "Test notification", - visible: false + visible: false, }); const notification = await findByTestId("notification-test"); @@ -109,7 +116,7 @@ describe("GoATemporaryNotification", () => { it("should use down animation by default", async () => { const { findByTestId } = render(GoATemporaryNotification, { testid: "notification-test", - message: "Test notification" + message: "Test notification", }); const notification = await findByTestId("notification-test"); @@ -121,7 +128,7 @@ describe("GoATemporaryNotification", () => { const { findByTestId } = render(GoATemporaryNotification, { testid: "notification-test", message: "Test notification", - animationDirection: "up" + animationDirection: "up", }); const notification = await findByTestId("notification-test"); @@ -135,10 +142,10 @@ describe("GoATemporaryNotification", () => { const { container } = render(GoATemporaryNotification, { testid: "notification-test", message: "Test notification", - actionText: "Undo" + actionText: "Undo", }); - const actionButton = container.querySelector("goa-link-button"); + const actionButton = container.querySelector("goa-button"); expect(actionButton).toBeTruthy(); expect(actionButton?.textContent?.trim()).toBe("Undo"); }); @@ -146,10 +153,10 @@ describe("GoATemporaryNotification", () => { it("should not render action button when actionText is not provided", async () => { const { container } = render(GoATemporaryNotification, { testid: "notification-test", - message: "Test notification" + message: "Test notification", }); - const actionButton = container.querySelector("goa-link-button"); + const actionButton = container.querySelector("goa-button"); expect(actionButton).toBeFalsy(); }); }); @@ -160,16 +167,15 @@ describe("GoATemporaryNotification", () => { testid: "notification-test", message: "Progress notification", type: "progress", - progress: 25 + progress: 25, }); - let progressBar = container.querySelector("progress"); - expect(progressBar?.getAttribute("value")).toBe("25"); + const progressBar = container.querySelector("goa-linear-progress"); + expect(progressBar?.getAttribute("progress")).toBe("25"); // Test updating progress await rerender({ progress: 75 }); - progressBar = container.querySelector("progress"); - expect(progressBar?.getAttribute("value")).toBe("75"); + expect(progressBar?.getAttribute("progress")).toBe("75"); }); }); }); diff --git a/libs/web-components/src/components/temporary-notification/TemporaryNotification.svelte b/libs/web-components/src/components/temporary-notification/TemporaryNotification.svelte index e7eaca1a62..be1436fb93 100644 --- a/libs/web-components/src/components/temporary-notification/TemporaryNotification.svelte +++ b/libs/web-components/src/components/temporary-notification/TemporaryNotification.svelte @@ -14,8 +14,6 @@ />
{#if type === "success"} - + {/if} {#if type === "failure"} - + {/if} {message} -
- {#if actionText} -
- - {actionText} - -
- {/if} + {#if actionText} +
+ + {actionText} + +
+ {/if} +
{#if type === "progress"} - + {:else if type === "indeterminate"} - + {/if}
diff --git a/libs/web-components/src/components/temporary-notification/TemporaryNotificationCtrl.svelte b/libs/web-components/src/components/temporary-notification/TemporaryNotificationCtrl.svelte index 5d63f8b7c4..fee9e12954 100644 --- a/libs/web-components/src/components/temporary-notification/TemporaryNotificationCtrl.svelte +++ b/libs/web-components/src/components/temporary-notification/TemporaryNotificationCtrl.svelte @@ -1,28 +1,35 @@ -
| undefined; + let _hideTooltipTimeout: ReturnType | undefined; // Use a unique id for each tooltip instance. // So screen readers can identify the tooltip instance when @@ -143,6 +143,16 @@ }, 500); }; + // Mouse click also fires on:focus on a tabindex=0 element, but we only want + // to reveal the tooltip on keyboard-driven focus so JS state stays aligned + // with the CSS :focus-visible rule that drives opacity. + function handleFocus(e: FocusEvent) { + const target = e.currentTarget as HTMLElement | null; + if (!target?.matches?.(":focus-visible")) return; + clearTimeout(_hideTooltipTimeout); + showTooltip(); + } + async function checkAndAdjustPosition() { // angular needs time to render the _tooltipEl await tick(); @@ -227,10 +237,7 @@ showTooltip(); }} on:mouseleave={hideTooltip} - on:focus={() => { - clearTimeout(_hideTooltipTimeout); - showTooltip(); - }} + on:focus={handleFocus} on:blur={hideTooltip} data-testid={testid} role="tooltip" @@ -315,7 +322,7 @@ } .tooltip:hover .tooltip-text, - .tooltip:focus .tooltip-text { + .tooltip:focus-visible .tooltip-text { opacity: 1; } diff --git a/libs/web-components/src/components/work-side-menu/WorkSideMenu.svelte b/libs/web-components/src/components/work-side-menu/WorkSideMenu.svelte index 4aabdd4c56..a08757c4e7 100644 --- a/libs/web-components/src/components/work-side-menu/WorkSideMenu.svelte +++ b/libs/web-components/src/components/work-side-menu/WorkSideMenu.svelte @@ -32,7 +32,7 @@ // optional /** Controls whether the side menu is expanded or collapsed. */ - export let open = false; + export let open: boolean = false; /** Sets a data-testid attribute for automated testing. */ export let testid: string = ""; /** User's name displayed in the profile section. */ @@ -55,10 +55,10 @@ let _menuEl: HTMLElement; let _menuLinks: HTMLElement[] = []; - let _containerEl: HTMLElement; + let _containerEl: HTMLElement | undefined; let _rootEl: HTMLElement; let _scrollEl: HTMLElement; - let _toggleButtonEl: HTMLElement; + let _toggleButtonEl: HTMLElement | undefined; let _tooltipEl: HTMLElement; let _tooltipLabel: string = ""; @@ -71,7 +71,7 @@ let _resizeObserver: ResizeObserver | null = null; const _logo = - "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' fill='none'%3E%3Crect width='31.695' height='31.688' x='.028' fill='%2300B6ED' rx='4'/%3E%3Cg clip-path='url(%23a)'%3E%3Cmask id='b' width='47' height='39' x='-11' y='-2' maskUnits='userSpaceOnUse' style='mask-type:alpha'%3E%3Cpath fill='%23545860' d='M22.017 31.103a63.47 63.47 0 0 1-7.22-3.164 52.41 52.41 0 0 0 6.195-2.724 43.148 43.148 0 0 0 1.023 5.89m13.27-24.392c-1.034-.13-.497.348-.785 1.7-1.246 5.832-6.05 10.035-10.873 12.855-.506-6.678-.3-14.093.967-18.636 1.069-3.836 2.34-3.132.763-3.938-1.66-.848-3.44.273-4.882 3.13C19.033 4.68 12.393 20.19 1.78 30.664c-5.43 5.36-10.34 2.6-11.323 1.775-.8-.67-1.096.365-.103 1.426 4.39 4.7 10.805 2.003 13.141-.314 6.455-6.405 13.96-20.193 16.996-26.044a89.89 89.89 0 0 0 .243 15.294 44.69 44.69 0 0 1-7.619 2.885c-1.504.391-2.435 1-2.462 1.691-.03.758.98 1.397 2.44 2.085 2.6 1.226 10.216 4.798 12.093 5.878 1.606.925 2.39.204 2.866-.796.622-1.302-1.083-2.054-2.735-2.545a50.47 50.47 0 0 1-1.48-8.385c3.87-2.365 7.682-5.52 9.88-9.452a18.004 18.004 0 0 0 1.568-4.365c.23-.934.293-1.9.186-2.855 0 0-.03-.209-.186-.229'/%3E%3C/mask%3E%3Cg mask='url(%23b)'%3E%3Crect width='31.695' height='31.695' x='.028' fill='%23fff' rx='3.048'/%3E%3C/g%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='a'%3E%3Crect width='32' height='31.992' y='.008' fill='%23fff' rx='4'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E"; + "data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSczMicgaGVpZ2h0PSczMicgZmlsbD0nbm9uZSc+PHJlY3Qgd2lkdGg9JzMxLjY5NScgaGVpZ2h0PSczMS42ODgnIHg9Jy4wMjgnIGZpbGw9JyMwMEI2RUQnIHJ4PSc0Jy8+PGcgY2xpcC1wYXRoPSd1cmwoI2EpJz48bWFzayBpZD0nYicgd2lkdGg9JzQ3JyBoZWlnaHQ9JzM5JyB4PSctMTEnIHk9Jy0yJyBtYXNrVW5pdHM9J3VzZXJTcGFjZU9uVXNlJyBzdHlsZT0nbWFzay10eXBlOmFscGhhJz48cGF0aCBmaWxsPScjNTQ1ODYwJyBkPSdNMjIuMDE3IDMxLjEwM2E2My40NyA2My40NyAwIDAgMS03LjIyLTMuMTY0IDUyLjQxIDUyLjQxIDAgMCAwIDYuMTk1LTIuNzI0IDQzLjE0OCA0My4xNDggMCAwIDAgMS4wMjMgNS44OW0xMy4yNy0yNC4zOTJjLTEuMDM0LS4xMy0uNDk3LjM0OC0uNzg1IDEuNy0xLjI0NiA1LjgzMi02LjA1IDEwLjAzNS0xMC44NzMgMTIuODU1LS41MDYtNi42NzgtLjMtMTQuMDkzLjk2Ny0xOC42MzYgMS4wNjktMy44MzYgMi4zNC0zLjEzMi43NjMtMy45MzgtMS42Ni0uODQ4LTMuNDQuMjczLTQuODgyIDMuMTNDMTkuMDMzIDQuNjggMTIuMzkzIDIwLjE5IDEuNzggMzAuNjY0Yy01LjQzIDUuMzYtMTAuMzQgMi42LTExLjMyMyAxLjc3NS0uOC0uNjctMS4wOTYuMzY1LS4xMDMgMS40MjYgNC4zOSA0LjcgMTAuODA1IDIuMDAzIDEzLjE0MS0uMzE0IDYuNDU1LTYuNDA1IDEzLjk2LTIwLjE5MyAxNi45OTYtMjYuMDQ0YTg5Ljg5IDg5Ljg5IDAgMCAwIC4yNDMgMTUuMjk0IDQ0LjY5IDQ0LjY5IDAgMCAxLTcuNjE5IDIuODg1Yy0xLjUwNC4zOTEtMi40MzUgMS0yLjQ2MiAxLjY5MS0uMDMuNzU4Ljk4IDEuMzk3IDIuNDQgMi4wODUgMi42IDEuMjI2IDEwLjIxNiA0Ljc5OCAxMi4wOTMgNS44NzggMS42MDYuOTI1IDIuMzkuMjA0IDIuODY2LS43OTYuNjIyLTEuMzAyLTEuMDgzLTIuMDU0LTIuNzM1LTIuNTQ1YTUwLjQ3IDUwLjQ3IDAgMCAxLTEuNDgtOC4zODVjMy44Ny0yLjM2NSA3LjY4Mi01LjUyIDkuODgtOS40NTJhMTguMDA0IDE4LjAwNCAwIDAgMCAxLjU2OC00LjM2NWMuMjMtLjkzNC4yOTMtMS45LjE4Ni0yLjg1NSAwIDAtLjAzLS4yMDktLjE4Ni0uMjI5Jy8+PC9tYXNrPjxnIG1hc2s9J3VybCgjYiknPjxyZWN0IHdpZHRoPSczMS42OTUnIGhlaWdodD0nMzEuNjk1JyB4PScuMDI4JyBmaWxsPScjZmZmJyByeD0nMy4wNDgnLz48L2c+PC9nPjxkZWZzPjxjbGlwUGF0aCBpZD0nYSc+PHJlY3Qgd2lkdGg9JzMyJyBoZWlnaHQ9JzMxLjk5MicgeT0nLjAwOCcgZmlsbD0nI2ZmZicgcng9JzQnLz48L2NsaXBQYXRoPjwvZGVmcz48L3N2Zz4="; // ***** // Hooks @@ -198,6 +198,7 @@ } function setTooltipPos(label: string, el: HTMLElement) { + if (!_containerEl || !_tooltipEl) return; const rect = el?.getBoundingClientRect(); const containerRect = _containerEl.getBoundingClientRect(); const top = rect.top - containerRect.top + rect.height / 2; @@ -218,7 +219,7 @@ } function handleToggleHover() { - if (open) return; + if (open || !_toggleButtonEl) return; setTooltipPos("Expand menu", _toggleButtonEl); showTooltip(); @@ -378,12 +379,12 @@
{#if url} - + {heading} {:else}
- + {heading}
{/if} @@ -477,6 +478,13 @@